From f00318777763b7c3202716e5da752f2602f12c89 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Sat, 9 Sep 2017 21:21:26 +0200 Subject: [PATCH 001/120] Initial update to changelog for the v1.1 release --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee7240aa..a94cccf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,29 @@ For reference, the possible headings are: * **Notes** +## [1.1] - 2017-09-?????? +Tag name: v1.1.0 + +### Added +* Support for server-side plugins that can add support for alternate event consumers (other than the WebSocket API). [Pull request #1707](https://github.com/bigchaindb/bigchaindb/pull/1707) +* New configuration settings to set the *advertised* wsserver scheme, host and port. (The *advertised* ones are the ones that external users use to connect to the WebSocket API.) [Pull request #1703](https://github.com/bigchaindb/bigchaindb/pull/1703) +* Support for secure (TLS) WebSocket connections. [Pull request #1619](https://github.com/bigchaindb/bigchaindb/pull/1619) +* A new page of documentation about the contents of a condition (inside a transaction). [Pull request #1668](https://github.com/bigchaindb/bigchaindb/pull/1668) + +### Changed +* We updated our definition of the **public API** (at the top of this document). [Pull request #1700](https://github.com/bigchaindb/bigchaindb/pull/1700) +* The HTTP API Logger now logs the request path and method as well. [Pull request #1644](https://github.com/bigchaindb/bigchaindb/pull/1644) + +### External Contributors +* @carchrae - [Pull request #1731](https://github.com/bigchaindb/bigchaindb/pull/1731) +* @ivanbakel - [Pull request #1706](https://github.com/bigchaindb/bigchaindb/pull/1706) +* @ketanbhatt - Pull requests [#1643](https://github.com/bigchaindb/bigchaindb/pull/1643) and [#1644](https://github.com/bigchaindb/bigchaindb/pull/1644) + +### Notes +* Many improvements to our production deployment template (which uses Kubernetes). +* The production deployment template for the multi-node case was out of date. We updated that and verified it. [Pull request #1713](https://github.com/bigchaindb/bigchaindb/pull/1713) + + ## [1.0.1] - 2017-07-13 Tag name: v1.0.1 From 3b40dcc197a35a14090e4fb70fbf88281f3253eb Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 12 Sep 2017 22:12:12 +0200 Subject: [PATCH 002/120] Added link to new Java driver in the docs --- docs/server/source/drivers-clients/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/server/source/drivers-clients/index.rst b/docs/server/source/drivers-clients/index.rst index 382e68b6..45b0029a 100644 --- a/docs/server/source/drivers-clients/index.rst +++ b/docs/server/source/drivers-clients/index.rst @@ -23,6 +23,7 @@ Community-Driven Libraries and Tools * `Haskell transaction builder `_ * `Go driver `_ -* `Java driver `_ +* `Java driver (newer, working) `_ +* `Java driver (old, not working) `_ * `Ruby driver `_ * `Ruby library for preparing/signing transactions and submitting them or querying a BigchainDB/IPDB node (MIT licensed) `_ From f2e1b4ac80662f90e905e966a8262488def110c2 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Thu, 14 Sep 2017 14:00:13 +0200 Subject: [PATCH 003/120] Automation for single node deployment for quickstart - Change consists of two deployment models: - Using Vagrant(single node, with/without docker) - Using Ansible(single node, with/without docker) - Updated quickstart documentation. - Some WIP comments, which will be addressed later. Depending on the requirements. --- README.md | 2 + docs/server/source/appendices/index.rst | 2 + .../source/appendices/run-with-ansible.md | 73 ++++++++++ .../source/appendices/run-with-vagrant.md | 137 ++++++++++++++++++ docs/server/source/quickstart.md | 8 +- pkg/Vagrantfile | 56 +++++++ pkg/ansible/quickstart.yml | 10 ++ .../roles/bigchaindb-driver/defaults/main.yml | 25 ++++ .../roles/bigchaindb-driver/tasks/centos.yml | 12 ++ .../roles/bigchaindb-driver/tasks/common.yml | 14 ++ .../roles/bigchaindb-driver/tasks/debian.yml | 8 + .../roles/bigchaindb-driver/tasks/fedora.yml | 7 + .../roles/bigchaindb-driver/tasks/main.yml | 12 ++ .../roles/bigchaindb/defaults/main.yml | 46 ++++++ pkg/ansible/roles/bigchaindb/tasks/centos.yml | 16 ++ pkg/ansible/roles/bigchaindb/tasks/common.yml | 36 +++++ pkg/ansible/roles/bigchaindb/tasks/debian.yml | 8 + pkg/ansible/roles/bigchaindb/tasks/fedora.yml | 7 + pkg/ansible/roles/bigchaindb/tasks/main.yml | 16 ++ .../roles/bigchaindb/tasks/with_docker.yml | 25 ++++ .../roles/docker-compose/defaults/main.yml | 7 + .../roles/docker-compose/tasks/main.yml | 9 ++ pkg/ansible/roles/docker/defaults/main.yml | 18 +++ pkg/ansible/roles/docker/tasks/centos.yml | 42 ++++++ pkg/ansible/roles/docker/tasks/debian.yml | 52 +++++++ pkg/ansible/roles/docker/tasks/fedora.yml | 34 +++++ pkg/ansible/roles/docker/tasks/main.yml | 40 +++++ pkg/ansible/roles/mongodb/defaults/main.yml | 34 +++++ pkg/ansible/roles/mongodb/tasks/centos.yml | 18 +++ pkg/ansible/roles/mongodb/tasks/common.yml | 10 ++ pkg/ansible/roles/mongodb/tasks/debian.yml | 21 +++ pkg/ansible/roles/mongodb/tasks/fedora.yml | 17 +++ pkg/ansible/roles/mongodb/tasks/main.yml | 31 ++++ .../roles/mongodb/tasks/with_docker.yml | 20 +++ pkg/config/bdb-config.yaml | 12 ++ pkg/scripts/bootstrap.sh | 62 ++++++++ pkg/scripts/bootstrap_constants.sh | 7 + pkg/scripts/bootstrap_helper.sh | 89 ++++++++++++ 38 files changed, 1042 insertions(+), 1 deletion(-) create mode 100644 docs/server/source/appendices/run-with-ansible.md create mode 100644 docs/server/source/appendices/run-with-vagrant.md create mode 100644 pkg/Vagrantfile create mode 100644 pkg/ansible/quickstart.yml create mode 100644 pkg/ansible/roles/bigchaindb-driver/defaults/main.yml create mode 100644 pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml create mode 100644 pkg/ansible/roles/bigchaindb-driver/tasks/common.yml create mode 100644 pkg/ansible/roles/bigchaindb-driver/tasks/debian.yml create mode 100644 pkg/ansible/roles/bigchaindb-driver/tasks/fedora.yml create mode 100644 pkg/ansible/roles/bigchaindb-driver/tasks/main.yml create mode 100644 pkg/ansible/roles/bigchaindb/defaults/main.yml create mode 100644 pkg/ansible/roles/bigchaindb/tasks/centos.yml create mode 100644 pkg/ansible/roles/bigchaindb/tasks/common.yml create mode 100644 pkg/ansible/roles/bigchaindb/tasks/debian.yml create mode 100644 pkg/ansible/roles/bigchaindb/tasks/fedora.yml create mode 100644 pkg/ansible/roles/bigchaindb/tasks/main.yml create mode 100644 pkg/ansible/roles/bigchaindb/tasks/with_docker.yml create mode 100644 pkg/ansible/roles/docker-compose/defaults/main.yml create mode 100644 pkg/ansible/roles/docker-compose/tasks/main.yml create mode 100644 pkg/ansible/roles/docker/defaults/main.yml create mode 100644 pkg/ansible/roles/docker/tasks/centos.yml create mode 100644 pkg/ansible/roles/docker/tasks/debian.yml create mode 100644 pkg/ansible/roles/docker/tasks/fedora.yml create mode 100644 pkg/ansible/roles/docker/tasks/main.yml create mode 100644 pkg/ansible/roles/mongodb/defaults/main.yml create mode 100644 pkg/ansible/roles/mongodb/tasks/centos.yml create mode 100644 pkg/ansible/roles/mongodb/tasks/common.yml create mode 100644 pkg/ansible/roles/mongodb/tasks/debian.yml create mode 100644 pkg/ansible/roles/mongodb/tasks/fedora.yml create mode 100644 pkg/ansible/roles/mongodb/tasks/main.yml create mode 100644 pkg/ansible/roles/mongodb/tasks/with_docker.yml create mode 100644 pkg/config/bdb-config.yaml create mode 100755 pkg/scripts/bootstrap.sh create mode 100755 pkg/scripts/bootstrap_constants.sh create mode 100755 pkg/scripts/bootstrap_helper.sh diff --git a/README.md b/README.md index 118d6f85..c04a6466 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ BigchainDB is a scalable blockchain database. [The whitepaper](https://www.bigch ### [Quickstart](https://docs.bigchaindb.com/projects/server/en/latest/quickstart.html) ### [Set Up & Run a Dev/Test Node](https://docs.bigchaindb.com/projects/server/en/latest/dev-and-test/setup-run-node.html) ### [Run BigchainDB Server with Docker](https://docs.bigchaindb.com/projects/server/en/latest/appendices/run-with-docker.html) +### [Run BigchainDB Server with Vagrant](https://docs.bigchaindb.com/projects/server/en/latest/appendices/run-with-vagrant.html) +### [Run BigchainDB Server with Ansible](https://docs.bigchaindb.com/projects/server/en/latest/appendices/run-with-ansible.html) ## Links for Everyone diff --git a/docs/server/source/appendices/index.rst b/docs/server/source/appendices/index.rst index 864b32e4..7bee77df 100755 --- a/docs/server/source/appendices/index.rst +++ b/docs/server/source/appendices/index.rst @@ -27,3 +27,5 @@ Appendices rethinkdb-backup licenses install-with-lxd + run-with-vagrant + run-with-ansible \ No newline at end of file diff --git a/docs/server/source/appendices/run-with-ansible.md b/docs/server/source/appendices/run-with-ansible.md new file mode 100644 index 00000000..e4b4a54a --- /dev/null +++ b/docs/server/source/appendices/run-with-ansible.md @@ -0,0 +1,73 @@ +# Run BigchainDB with Ansible + +**NOT for Production Use** + +You can use the following instructions to deploy a BigchainDB node for +dev/test using Ansible. Ansible will setup a BigchainDB node along with +[Docker](https://www.docker.com/), [Docker Compose](https://docs.docker.com/compose/), +[MongoDB](https://www.mongodb.com/), [BigchainDB Python driver](https://docs.bigchaindb.com/projects/py-driver/en/latest/). + +Currently, this workflow is only supported for the following distributions: +- Ubuntu >= 16.04 +- CentOS >= 7 +- Fedora >= 24 + +## Clone the BigchainDB repository | Ansible +```text +$ git clone https://github.com/bigchaindb/bigchaindb.git +``` + +## Install dependencies | Ansible +- [Ansible](http://docs.ansible.com/ansible/latest/intro_installation.html) + +You can also install `ansible` and other dependecies, if any, using the `boostrap.sh` script +inside the BigchainDB repository. +Navigate to `bigchaindb/pkg/scripts` and run the `bootstrap.sh` script to install the dependecies +for your OS. The script also checks if the OS you are running is compatible with the +supported versions. + +```text +$ cd bigchaindb/pkg/scripts/ +$ sudo ./bootstrap.sh +``` + +### Local Setup | Ansible +You can safely run the `quickstart` playbook now and everything will be taken care of by `ansible` on your host. `quickstart` playbook only supports deployment on your dev/local host. To run the playbook please navigate to the ansible directory inside the BigchainDB repository and run the `quickstart` playbook. + +```text +$ cd bigchaindb/pkg/ansible/ + +# All the services will be deployed as processes +$ sudo ansible-playbook quickstart.yml -c local + +OR + +# To deploy all services inside docker containers +$ sudo ansible-playbook quickstart.yml --extra-vars "with_docker=true" -c local +``` + +After successfull execution of the playbook, you can verify that BigchainDB docker/process is running. + +Verify BigchainDB process: +```text +$ ps -ef | grep bigchaindb +``` + +OR + +Verify BigchainDB Docker: +```text +$ docker ps | grep bigchaindb +``` + +The playbook also installs the BigchainDB python driver, so can instantly make transactions and verify the functionality. The `bdb_root_url` can be be one of the following: +```text +# BigchainDB is running as a process +bdb_root_url = http://:9984 + +OR + +# BigchainDB is running inside a docker container +bdb_root_url = http://: +``` +For more details on `how to make a transaction?` Please refer to [Basic Usage Examples](https://docs.bigchaindb.com/projects/py-driver/en/latest/connect.html). diff --git a/docs/server/source/appendices/run-with-vagrant.md b/docs/server/source/appendices/run-with-vagrant.md new file mode 100644 index 00000000..c3c11e0e --- /dev/null +++ b/docs/server/source/appendices/run-with-vagrant.md @@ -0,0 +1,137 @@ +# Run BigchainDB with Vagrant + +**NOT for Production Use** + +You can use the following instructions to deploy a BigchainDB node +for dev/test using Vagrant. Vagrant will setup a BigchainDB node with +all the dependencies along with MongoDB, BigchainDB Python driver. You +can also tweak the following configurations for the BigchainDB node. +- Vagrant Box + - Currently, we support the following boxes: + - `ubuntu/xenial64 # >=16.04` + - `centos/7 # >=7` + - `fedora/24 # >=24` + - **NOTE** : You can choose any other vagrant box of your choice but these are + the minimum versioning requirements. +- Resources and specs for your box. + - RAM + - VCPUs + - Network Type + - Currently, only `private_network` is supported. + - IP Address +- Setup type + - `quickstart` +- Deploy node with Docker + - Deploy all the services in Docker containers or as processes. +- Upstart Script +- Vagrant Provider + - Virtualbox + - VMware + +## Install dependencies | Vagrant +1. [VirtualBox](https://www.virtualbox.org/wiki/Downloads) >= 5.0.0 +2. [Vagrant](https://www.vagrantup.com/downloads.html) >= 1.16.0 + +## Clone the BigchainDB repository | Vagrant +```text +$ git clone https://github.com/bigchaindb/bigchaindb.git +``` + +## Configuration | Vagrant +Navigate to `bigchaindb/pkg/config/` inside the repository. +```text +$ cd bigchaindb/pkg/config/ +``` + +Edit the `bdb-config.yaml` as per your requirements. Sample `bdb-config.yaml`: + +```text +--- +- name: "bdb-node-01" + box: + name: "ubuntu/xenial64" + ram: "2048" + vcpus: "2" + setup_type: "quickstart" + deploy_docker: false + network: + ip: "10.20.30.40" + type: "private_network" + upstart: "/bigchaindb/scripts/bootstrap.sh" +``` + +**Note**: You can spawn multiple instances as well using `bdb-config.yaml`. Here is a sample `bdb-config.yaml`: +```text +--- +- name: "bdb-node-01" + box: + name: "ubuntu/xenial64" + ram: "2048" + vcpus: "2" + setup_type: "quickstart" + deploy_docker: false + network: + ip: "10.20.30.40" + type: "private_network" + upstart: "/bigchaindb/scripts/bootstrap.sh" +- name: "bdb-node-02" + box: + name: "ubuntu/xenial64" + ram: "4096" + vcpus: "3" + setup_type: "quickstart" + deploy_docker: false + network: + ip: "10.20.30.50" + type: "private_network" + upstart: "/bigchaindb/scripts/bootstrap.sh" +``` + + +## Local Setup | Vagrant +To bring up the BigchainDB node, run the following command: + +```text +$ vagrant up +``` + +*Note*: There are some vagrant plugins required for the installation, user will be prompted to install them if they are not present. Instructions to install the plugins can be extracted from the message. + +```text +$ vagrant plugin install +``` + +After successfull execution of Vagrant, you can log in to your fresh BigchainDB node. + +```text +$ vagrant ssh +``` + +## Make your first transaction +Once you are inside the BigchainDB node, you can verify that BigchainDB docker/process is running. + +Verify BigchainDB process: +```text +$ ps -ef | grep bigchaindb +``` + +OR + +Verify BigchainDB Docker: +```text +$ docker ps | grep bigchaindb +``` + +BigchainDB python driver is pre-installed in the instance, so you can instantly make transactions and verify the functionality. The `bdb_root_url` can be one of the following: +```text +# BigchainDB is running as a process +bdb_root_url = http://:9984 + +OR + +# BigchainDB is running inside a docker container +bdb_root_url = http://: +``` +For more details on *how to make a transaction?* Please refer to [Basic Usage Examples](https://docs.bigchaindb.com/projects/py-driver/en/latest/connect.html). + +*Note*: If you want to make transactions remotely, you need to install the `bigchaindb-driver`. For detailed instructions on how to install the driver and make your first transaction. Please refer to [Quickstart/Installation](https://docs.bigchaindb.com/projects/py-driver/en/latest/quickstart.html) of BigchainDB driver. \ No newline at end of file diff --git a/docs/server/source/quickstart.md b/docs/server/source/quickstart.md index 62a31fb9..ba755a7a 100644 --- a/docs/server/source/quickstart.md +++ b/docs/server/source/quickstart.md @@ -1,6 +1,12 @@ # Quickstart -This page has instructions to set up a single stand-alone BigchainDB node for learning or experimenting. Instructions for other cases are [elsewhere](introduction.html). We will assume you're using Ubuntu 16.04 or similar. If you're not using Linux, then you might try [running BigchainDB with Docker](appendices/run-with-docker.html). +This page has instructions to set up a single stand-alone BigchainDB node manually for learning or experimenting. Instructions for other cases are [elsewhere](introduction.html). You might try one of the following deployment methods +as well, depending on your choice: +- [BigchainDB with Docker](appendices/run-with-docker.html). +- [BigchainDB with Vagrant](appendices/run-with-vagrant.html). +- [BigchainDB with Ansible](appendices/run-with-ansible.html). + +For manual installation, We will assume you're using Ubuntu 16.04 or similar. A. Install MongoDB as the database backend. (There are other options but you can ignore them for now.) diff --git a/pkg/Vagrantfile b/pkg/Vagrantfile new file mode 100644 index 00000000..e998b4af --- /dev/null +++ b/pkg/Vagrantfile @@ -0,0 +1,56 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Required modules +require 'yaml' + +# Minimum Requirements +Vagrant.require_version '>= 1.6.0' +VAGRANTFILE_API_VERSION = '2' + +# Configuration files +CONFIGURATION_FILE = 'config/bdb-config.yaml' + +# Validate if all the required plugins are present +required_plugins = ["vagrant-cachier"] +required_plugins.each do |plugin| + if not Vagrant.has_plugin?(plugin) + raise "Required vagrant plugin #{plugin} not found. Please run `vagrant plugin install #{plugin}`" + end +end + +# Read configuration file(s) +instances_config = YAML.load_file(File.join(File.dirname(__FILE__), CONFIGURATION_FILE)) + +#TODO: (muawiakh) Add support for Docker, AWS, Azure +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + instances_config.each do |instance| + config.vm.define instance['name'] do |bdb| + # Workaround until vagrant cachier plugin supports dnf + if !(instance["box"]["name"].include? "fedora") + if Vagrant.has_plugin?("vagrant-cachier") + config.cache.scope = :box + end + end + bdb.vm.hostname = instance["name"] + bdb.vm.network instance["network"]["type"], ip: instance["network"]["ip"] + bdb.vm.box = instance["box"]["name"] + bdb.vm.synced_folder ".", "/bigchaindb" + bdb.vm.provision :shell, inline: "cd /bigchaindb/scripts;/bin/bash #{instance["upstart"]}" + if instance["setup_type"] == "quickstart" + bdb.vm.provision :shell, inline: "PYTHONBUFFERED=1 ansible-playbook \ + /bigchaindb/ansible/quickstart.yml --extra-vars \"with_docker=#{instance["deploy_docker"]}\" -c local" + end + + bdb.vm.provider 'vmware_fusion' do |vmwf, override| + vmwf.vmx['memsize'] = instance["ram"] + vmwf.vmx['numvcpus'] = instance['vcpus'] + end + + bdb.vm.provider 'virtualbox' do |vb, override| + vb.memory = instance["ram"] + vb.cpus = instance['vcpus'] + end + end + end +end \ No newline at end of file diff --git a/pkg/ansible/quickstart.yml b/pkg/ansible/quickstart.yml new file mode 100644 index 00000000..aa0f8c49 --- /dev/null +++ b/pkg/ansible/quickstart.yml @@ -0,0 +1,10 @@ +- hosts: localhost + remote_user: vagrant + vars: + with_docker: "{{ deploy_docker | default(false) }}" + roles: + - { role: docker, when: with_docker|bool } + - { role: docker-compose, when: with_docker|bool } + - mongodb + - bigchaindb + - bigchaindb-driver \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb-driver/defaults/main.yml b/pkg/ansible/roles/bigchaindb-driver/defaults/main.yml new file mode 100644 index 00000000..bf1297bf --- /dev/null +++ b/pkg/ansible/roles/bigchaindb-driver/defaults/main.yml @@ -0,0 +1,25 @@ +--- +dependencies_deb: + - python3-dev + - libffi-dev + - libssl-dev + - python3-pip + +dependencies_yum: + - gcc-c++ + - "@Development Tools" + - python34-devel + - libffi-devel + - openssl-devel + - python34-setuptools + +dependencies_dnf: + - gcc-c++ + - redhat-rpm-config + - "@Development Tools" + - python3-devel + - libffi-devel + - openssl-devel + +python_pip_upgrade: true +python_setuptools_upgrade: true \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml b/pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml new file mode 100644 index 00000000..e6014e4b --- /dev/null +++ b/pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml @@ -0,0 +1,12 @@ +--- +- name: Install dependencies + yum: + name: "{{ item }}" + state: present + update_cache: yes + with_items: "{{ dependencies_yum }}" + tags: [bigchaindb-driver] + +- name: Install pip + shell: "easy_install-3.4 pip" + tags: [bigchaindb-driver] \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/common.yml b/pkg/ansible/roles/bigchaindb-driver/tasks/common.yml new file mode 100644 index 00000000..55641bb4 --- /dev/null +++ b/pkg/ansible/roles/bigchaindb-driver/tasks/common.yml @@ -0,0 +1,14 @@ +--- +- name: Upgrade pip + shell: "pip3 install --upgrade pip" + when: python_pip_upgrade + tags: [bigchaindb-driver] + +- name: Upgade setuptools + shell: "pip3 install --upgrade setuptools" + when: python_setuptools_upgrade + tags: [bigchaindb-driver] + +- name: Install BigchainDB Driver + shell: "pip3 install bigchaindb-driver" + tags: [bigchaindb-driver] \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/debian.yml b/pkg/ansible/roles/bigchaindb-driver/tasks/debian.yml new file mode 100644 index 00000000..e00a7061 --- /dev/null +++ b/pkg/ansible/roles/bigchaindb-driver/tasks/debian.yml @@ -0,0 +1,8 @@ +--- +- name: Install dependencies + apt: + name: "{{ item }}" + state: present + update_cache: yes + with_items: "{{ dependencies_deb }}" + tags: [bigchaindb] diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/fedora.yml b/pkg/ansible/roles/bigchaindb-driver/tasks/fedora.yml new file mode 100644 index 00000000..bd8b701a --- /dev/null +++ b/pkg/ansible/roles/bigchaindb-driver/tasks/fedora.yml @@ -0,0 +1,7 @@ +--- +- name: Install dependencies + dnf: + name: "{{ item }}" + state: present + with_items: "{{ dependencies_dnf }}" + tags: [bigchaindb-driver] \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/main.yml b/pkg/ansible/roles/bigchaindb-driver/tasks/main.yml new file mode 100644 index 00000000..f743ff1c --- /dev/null +++ b/pkg/ansible/roles/bigchaindb-driver/tasks/main.yml @@ -0,0 +1,12 @@ +--- + +- include: debian.yml + when: distribution_name == "debian" or distribution_name == "ubuntu" + +- include: centos.yml + when: distribution_name == "centos" or distribution_name == "red hat enterprise linux" + +- include: fedora.yml + when: distribution_name == "fedora" + +- include: common.yml \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/defaults/main.yml b/pkg/ansible/roles/bigchaindb/defaults/main.yml new file mode 100644 index 00000000..3b75ae42 --- /dev/null +++ b/pkg/ansible/roles/bigchaindb/defaults/main.yml @@ -0,0 +1,46 @@ +--- +dependencies_deb: + - g++ + - python3-dev + - libffi-dev + - build-essential + - libssl-dev + - python3-pip + +dependencies_yum: + - gcc-c++ + - "@Development Tools" + - python34-devel + - libffi-devel + - openssl-devel + - python34-setuptools + +dependencies_dnf: + - gcc-c++ + - redhat-rpm-config + - "@Development Tools" + - python3-devel + - libffi-devel + - openssl-devel + +python_pip_upgrade: true +python_setuptools_upgrade: true + +directories: + - /data + +backend_db: mongodb #[rethinkdb, mongodb] + +bigchaindb_server_bind: "0.0.0.0:9984" +bigchaindb_database_host: "172.17.0.1" +bigchaindb_log_file: "{{ ansible_env.HOME }}/bigchaindb.log" + +# Docker configuration +backend_db_image: "mongo:3.4.1" +backend_db_name: "mongodb" +bigchaindb_image_name: "bigchaindb/bigchaindb" +bigchaindb_docker_name: "bigchaindb" +bigchaindb_docker_published_ports: + - 59984:9984 +bigchaindb_docker_volumes: + - "{{ ansible_env.HOME }}/bigchaindb_docker:/data" diff --git a/pkg/ansible/roles/bigchaindb/tasks/centos.yml b/pkg/ansible/roles/bigchaindb/tasks/centos.yml new file mode 100644 index 00000000..e8ca5cd8 --- /dev/null +++ b/pkg/ansible/roles/bigchaindb/tasks/centos.yml @@ -0,0 +1,16 @@ +--- +- name: Creating directories | CentOS + file: + path: "{{ item }}" + state: directory + mode: 0700 + with_items: "{{ directories }}" + tags: [bigchaindb] + +- name: Install dependencies | CentOS + yum: + name: "{{ item }}" + state: present + update_cache: yes + with_items: "{{ dependencies_yum }}" + tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/tasks/common.yml b/pkg/ansible/roles/bigchaindb/tasks/common.yml new file mode 100644 index 00000000..c88882be --- /dev/null +++ b/pkg/ansible/roles/bigchaindb/tasks/common.yml @@ -0,0 +1,36 @@ +--- +- name: Upgrade pip + shell: "pip3 install --upgrade pip" + when: python_pip_upgrade + tags: [bigchaindb] + +- name: Upgade setuptools + shell: "pip3 install --upgrade setuptools" + when: python_setuptools_upgrade + tags: [bigchaindb] + +- name: Install BigchainDB + shell: "pip3 install bigchaindb" + tags: [bigchaindb] + +- name: Configure BigchainDB + shell: "bigchaindb -y configure {{ backend_db }}" + environment: + BIGCHAINDB_SERVER_BIND: "{{ bigchaindb_server_bind }}" + tags: [bigchaindb] + +- name: MongoDB Process Check + shell: pgrep mongod | wc -l + register: mdb_pchk + tags: [bigchaindb] + +- name: BigchainDB Process Check + shell: pgrep bigchaindb | wc -l + register: bdb_pchk + tags: [bigchaindb] + +- name: Start BigchainDB + become: yes + shell: "bigchaindb start > {{ bigchaindb_log_file }} 2>&1 &" + when: mdb_pchk.stdout| int >= 1 and bdb_pchk.stdout| int == 0 + tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/tasks/debian.yml b/pkg/ansible/roles/bigchaindb/tasks/debian.yml new file mode 100644 index 00000000..0686848a --- /dev/null +++ b/pkg/ansible/roles/bigchaindb/tasks/debian.yml @@ -0,0 +1,8 @@ +--- +- name: Install dependencies + apt: + name: "{{ item }}" + state: present + update_cache: yes + with_items: "{{ dependencies_deb }}" + tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/tasks/fedora.yml b/pkg/ansible/roles/bigchaindb/tasks/fedora.yml new file mode 100644 index 00000000..4f542d3c --- /dev/null +++ b/pkg/ansible/roles/bigchaindb/tasks/fedora.yml @@ -0,0 +1,7 @@ +--- +- name: Install dependencies + dnf: + name: "{{ item }}" + state: present + with_items: "{{ dependencies_dnf }}" + tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/tasks/main.yml b/pkg/ansible/roles/bigchaindb/tasks/main.yml new file mode 100644 index 00000000..532c4ae6 --- /dev/null +++ b/pkg/ansible/roles/bigchaindb/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- include: with_docker.yml + when: with_docker|bool + tags: [bigchaindb] + +- include: debian.yml + when: not with_docker|bool and (distribution_name == "debian" or distribution_name == "ubuntu") + +- include: centos.yml + when: not with_docker|bool and (distribution_name == "centos" or distribution_name == "red hat enterprise linux") + +- include: fedora.yml + when: not with_docker|bool and (distribution_name == "fedora") + +- include: common.yml + when: not with_docker|bool \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/tasks/with_docker.yml b/pkg/ansible/roles/bigchaindb/tasks/with_docker.yml new file mode 100644 index 00000000..bf832711 --- /dev/null +++ b/pkg/ansible/roles/bigchaindb/tasks/with_docker.yml @@ -0,0 +1,25 @@ +--- +- name: Configuring BigchainDB Docker + docker_container: + name: "{{ bigchaindb_docker_name }}" + image: "{{ bigchaindb_image_name }}" + volumes: "{{ bigchaindb_docker_volumes }}" + pull: false + env: + BIGCHAINDB_SERVER_BIND: "{{ bigchaindb_server_bind }}" + BIGCHAINDB_DATABASE_HOST: "{{ bigchaindb_database_host }}" + entrypoint: "bigchaindb -y configure mongodb" + register: result + tags: [bigchaindb] + +- name: Start BigchainDB Docker + docker_container: + name: "{{ bigchaindb_docker_name }}" + image: "{{ bigchaindb_image_name }}" + published_ports: "{{ bigchaindb_docker_published_ports }}" + restart_policy: always + volumes: "{{ bigchaindb_docker_volumes }}" + state: started + pull: false + when: result|succeeded + tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/ansible/roles/docker-compose/defaults/main.yml b/pkg/ansible/roles/docker-compose/defaults/main.yml new file mode 100644 index 00000000..e50ee45c --- /dev/null +++ b/pkg/ansible/roles/docker-compose/defaults/main.yml @@ -0,0 +1,7 @@ +--- +# TODO: (muawiakh) Install docker-compose using pip +# docker_compose_pip_install: false #[true, false] +docker_compose_install: true #[true, false] +docker_compose_version: "1.15.0" +docker_compose_binary: /usr/local/bin/docker-compose +docker_compose_base_url: "https://github.com/docker/compose/releases/download/" \ No newline at end of file diff --git a/pkg/ansible/roles/docker-compose/tasks/main.yml b/pkg/ansible/roles/docker-compose/tasks/main.yml new file mode 100644 index 00000000..2862061e --- /dev/null +++ b/pkg/ansible/roles/docker-compose/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: Get docker-compose + become: yes + get_url: + url: "{{ docker_compose_base_url }}{{ docker_compose_version }}/docker-compose-{{ ansible_system }}-{{ ansible_machine}}" + dest: "{{docker_compose_binary}}" + mode: 0755 + when: docker_compose_install + tags: [docker-compose] \ No newline at end of file diff --git a/pkg/ansible/roles/docker/defaults/main.yml b/pkg/ansible/roles/docker/defaults/main.yml new file mode 100644 index 00000000..b1eda858 --- /dev/null +++ b/pkg/ansible/roles/docker/defaults/main.yml @@ -0,0 +1,18 @@ +--- +uninstall_old_version: false #[true, false] +docker_edition: 'ce' #[ce, ee] Currently, onlt CE is supported +docker_pkg: "docker-{{ docker_edition }}" #[docker-ce, docker-ee] +docker_update_channel: "stable" #[stable, edge] + +# Host configuration +distribution_name: "{{ ansible_distribution|lower }}" +distribution_codename: "{{ ansible_distribution_release|lower }}" +distribution_major: "{{ ansible_distribution_major_version }}" +server_arch: "amd64" #[amd64, armhf, s390x] + +# Docker Repositories +docker_apt_repo: "deb [arch={{ server_arch }}] https://download.docker.com/linux/{{ distribution_name }} {{ distribution_codename }} {{ docker_update_channel }}" +apt_key_fingerprint: "9DC858229FC7DD38854AE2D88D81803C0EBFCD88" +apt_key_url: "https://download.docker.com/linux/{{ distribution_name }}/gpg" +docker_yum_repo: "https://download.docker.com/linux/{{ distribution_name }}/{{ distribution_major }}/$basearch/{{ docker_update_channel }}" +docker_dnf_repo: "https://download.docker.com/linux/{{ distribution_name }}/{{ docker_pkg }}.repo" \ No newline at end of file diff --git a/pkg/ansible/roles/docker/tasks/centos.yml b/pkg/ansible/roles/docker/tasks/centos.yml new file mode 100644 index 00000000..62d40d53 --- /dev/null +++ b/pkg/ansible/roles/docker/tasks/centos.yml @@ -0,0 +1,42 @@ +--- +- name: Uninstall older versions of Docker | CentOS + yum: + name: "{{ item }}" + state: absent + with_items: + - docker + - docker-common + - docker-engine + - docker-selinux + when: uninstall_old_version + tags: [docker] + +- name: Setup Pre-reqs | CentOS + yum: + name: "{{ item }}" + state: present + update_cache: yes + with_items: + - yum-utils + - device-mapper-persistent-data + - lvm2 + - python-pip + tags: [docker] + +- name: Add Docker Repo | CentOS + yum_repository: + name: "{{ docker_pkg }}" + gpgcheck: yes + gpgkey: https://download.docker.com/linux/centos/gpg + baseurl: "{{ docker_yum_repo }}" + file: "{{ docker_pkg }}" + description: "Docker Repo" + enabled: yes + tags: [docker] + +- name: Install Docker | CentOS + yum: + name: "{{ docker_pkg }}" + state: present + update_cache: yes + tags: [docker] \ No newline at end of file diff --git a/pkg/ansible/roles/docker/tasks/debian.yml b/pkg/ansible/roles/docker/tasks/debian.yml new file mode 100644 index 00000000..483b7ac4 --- /dev/null +++ b/pkg/ansible/roles/docker/tasks/debian.yml @@ -0,0 +1,52 @@ +--- +- name: Uninstall older versions of Docker | Debian + apt: + name: "{{ item }}" + state: absent + with_items: + - docker + - docker-engine + - docker.io + when: uninstall_old_version + tags: [docker] + +- name: Install dependencies | Debian + apt: + name: "{{ item }}" + state: present + with_items: + - apt-transport-https + - ca-certificates + - curl + - software-properties-common + - python-pip + tags: [docker] + +- name: Add APT Key | Debian + apt_key: + url: "{{ apt_key_url }}" + id: "{{ apt_key_fingerprint }}" + state: present + register: add_repository_key + ignore_errors: true + tags: [docker] + +- name: Use curl if apt_key fails | Debian + shell: "curl -sSl {{ apt_key_url }} | sudo apt-key add -" + args: + warn: no + when: add_repository_key|failed + tags: [docker] + +- name: Add Docker repo and update cache | Debian + apt_repository: + repo: "{{ docker_apt_repo }}" + update_cache: yes + state: present + tags: [docker] + +- name: Install Docker | Debian + apt: + name: "{{ docker_pkg }}" + state: present + tags: [docker] \ No newline at end of file diff --git a/pkg/ansible/roles/docker/tasks/fedora.yml b/pkg/ansible/roles/docker/tasks/fedora.yml new file mode 100644 index 00000000..93d82b20 --- /dev/null +++ b/pkg/ansible/roles/docker/tasks/fedora.yml @@ -0,0 +1,34 @@ +--- +- name: Uninstall older versions of Docker | Fedora + dnf: + name: "{{ item }}" + state: absent + with_items: + - docker-engine-selinux + - docker-common + - docker-engine + - docker-selinux + when: uninstall_old_version + tags: [docker] + +- name: Setup Pre-reqs | Fedora + dnf: + name: "{{ item }}" + state: present + with_items: + - dnf-plugins-core + tags: [docker] + +- name: Add Docker repo | Fedora + shell: "dnf config-manager --add-repo {{ docker_dnf_repo }}" + tags: [docker] + +- name: Update Cache | Fedora + shell: "dnf makecache fast" + tags: [docker] + +- name: Install Docker | Fedora + dnf: + name: "{{ docker_pkg }}" + state: present + tags: [docker] \ No newline at end of file diff --git a/pkg/ansible/roles/docker/tasks/main.yml b/pkg/ansible/roles/docker/tasks/main.yml new file mode 100644 index 00000000..66d36489 --- /dev/null +++ b/pkg/ansible/roles/docker/tasks/main.yml @@ -0,0 +1,40 @@ +--- +- include: debian.yml + when: distribution_name == "debian" or distribution_name == "ubuntu" + +- include: centos.yml + when: distribution_name == "centos" or distribution_name == "red hat enterprise linux" + +- include: fedora.yml + when: distribution_name == "fedora" + +- name: Create Docker group + group: + name: docker + state: present + register: group_result + tags: [docker] + +- name: Add USER to docker group + user: + append: yes + name: "{{ item }}" + state: present + group: docker + with_items: + - vagrant + - "{{ distribution_name }}" + tags: [docker] + +- name: Start docker service + systemd: + name: docker + enabled: yes + state: started + tags: [docker] + +- name: Install docker-py + pip: + name: docker-py + state: present + tags: [docker] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/defaults/main.yml b/pkg/ansible/roles/mongodb/defaults/main.yml new file mode 100644 index 00000000..ea4656df --- /dev/null +++ b/pkg/ansible/roles/mongodb/defaults/main.yml @@ -0,0 +1,34 @@ +--- +mongodb_version: "3.4" +mongodb_package: "mongodb-org" +apt_key_fingerprint: "0C49F3730359A14518585931BC711F9BA15703C6" +apt_keyserver: "keyserver.ubuntu.com" +distribution_name: "{{ansible_distribution|lower }}" +distribution_codename: "{{ ansible_distribution_release|lower }}" +distribution_major: "{{ ansible_distribution_major_version }}" +server_arch: "amd64,arm64" + +# MongoDB Repos +mongodb_apt_repo: "deb [arch={{ server_arch }}] http://repo.mongodb.org/apt/{{ distribution_name }} {{ distribution_codename }}/{{ mongodb_package }}/{{ mongodb_version }} {{'main' if ansible_distribution == 'debian' else 'multiverse'}}" +mongodb_yum_base_url: "https://repo.mongodb.org/yum/{{ ansible_os_family|lower }}/$releasever/{{ mongodb_package }}/{{ mongodb_version }}/{{ ansible_architecture }}" +mongodb_dnf_base_url: "https://repo.mongodb.org/yum/{{ ansible_os_family|lower }}/7/{{ mongodb_package }}/{{ mongodb_version }}/{{ ansible_architecture }}" + +# MongoDB running config +mongodb_storage_path: /data/db +mongodb_log_path: /var/log/mongodb +mongodb_config_path: /data/configdb +se_linux: "TODO: (muawiakh)" +directories: + - "{{ mongodb_storage_path }}" + - "{{ mongodb_log_path }}" + - "{{ mongodb_config_path }}" + +# Docker configuration +mongodb_default_port: 27017 +mongodb_docker_image: "mongo:3.4.1" +mongodb_docker_name: "mongodb" +mongodb_docker_published_ports: + - 172.17.0.1:27017:27017 +mongodb_docker_volumes: + - "/tmp/mongodb_docker/db:{{ mongodb_storage_path }}" + - "/tmp/mongodb_docker/configdb:{{ mongodb_config_path }}" \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/centos.yml b/pkg/ansible/roles/mongodb/tasks/centos.yml new file mode 100644 index 00000000..e3340100 --- /dev/null +++ b/pkg/ansible/roles/mongodb/tasks/centos.yml @@ -0,0 +1,18 @@ +--- +- name: Add MongoDB Repo | CentOS + yum_repository: + name: "{{ mongodb_package }}" + gpgcheck: yes + gpgkey: https://www.mongodb.org/static/pgp/server-{{ mongodb_version }}.asc + baseurl: "{{ mongodb_yum_base_url }}" + file: "{{ mongodb_package }}" + description: "MongoDB Repo" + enabled: yes + tags: [mongodb] + +- name: Install MongoDB | CentOS + yum: + name: "{{ mongodb_package }}" + state: present + update_cache: yes + tags: [mongodb] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/common.yml b/pkg/ansible/roles/mongodb/tasks/common.yml new file mode 100644 index 00000000..41c6de1d --- /dev/null +++ b/pkg/ansible/roles/mongodb/tasks/common.yml @@ -0,0 +1,10 @@ +--- +- name: MongoDB Process Check + shell: pgrep mongod | wc -l + register: command_result + tags: [mongodb] + +- name: Run MongoDB + shell: "mongod --replSet=bigchain-rs --logpath {{ mongodb_log_path }}/mongod.log &" + when: command_result.stdout| int != 1 + tags: [mongodb] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/debian.yml b/pkg/ansible/roles/mongodb/tasks/debian.yml new file mode 100644 index 00000000..c2b0349b --- /dev/null +++ b/pkg/ansible/roles/mongodb/tasks/debian.yml @@ -0,0 +1,21 @@ +--- +- name: Add APT Key | Debian + apt_key: + keyserver: "{{ apt_keyserver }}" + id: "{{ apt_key_fingerprint }}" + state: present + ignore_errors: true + tags: [mongodb] + +- name: Add MongoDB repo and update cache | Debian + apt_repository: + repo: "{{ mongodb_apt_repo }}" + update_cache: yes + state: present + tags: [mongodb] + +- name: Install MongoDB | Debian + apt: + name: "{{ mongodb_package }}" + state: present + tags: [mongodb] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/fedora.yml b/pkg/ansible/roles/mongodb/tasks/fedora.yml new file mode 100644 index 00000000..fb83357f --- /dev/null +++ b/pkg/ansible/roles/mongodb/tasks/fedora.yml @@ -0,0 +1,17 @@ +--- +- name: Add MongoDB Repo | Fedora + yum_repository: + name: "{{ mongodb_package }}" + gpgcheck: yes + gpgkey: https://www.mongodb.org/static/pgp/server-{{ mongodb_version }}.asc + baseurl: "{{ mongodb_dnf_base_url }}" + file: "{{ mongodb_package }}" + description: "MongoDB Repo" + enabled: yes + tags: [mongodb] + +- name: Install MongoDB | Fedora + dnf: + name: "{{ mongodb_package }}" + state: present + tags: [mongodb] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/main.yml b/pkg/ansible/roles/mongodb/tasks/main.yml new file mode 100644 index 00000000..451b81b9 --- /dev/null +++ b/pkg/ansible/roles/mongodb/tasks/main.yml @@ -0,0 +1,31 @@ +--- +- name: Creating directories + file: + path: "{{ item }}" + state: directory + mode: 0700 + with_items: "{{ directories }}" + tags: [mongodb] + +- include: with_docker.yml + when: with_docker|bool + +- name: Verify logfiles exist | Debian + file: + path: "{{ mongodb_log_path }}/mongod.log" + state: touch + mode: 0755 + when: not with_docker|bool + tags: [mongodb] + +- include: debian.yml + when: not with_docker|bool and (distribution_name == "debian" or distribution_name == "ubuntu") + +- include: centos.yml + when: not with_docker|bool and (distribution_name == "centos" or distribution_name == "red hat enterprise linux") + +- include: fedora.yml + when: not with_docker|bool and (distribution_name == "fedora") + +- include: common.yml + when: not with_docker|bool \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/with_docker.yml b/pkg/ansible/roles/mongodb/tasks/with_docker.yml new file mode 100644 index 00000000..ff3a24a5 --- /dev/null +++ b/pkg/ansible/roles/mongodb/tasks/with_docker.yml @@ -0,0 +1,20 @@ +--- +- name: Check Docker Service + systemd: + name: docker + enabled: yes + state: started + tags: [docker] + +- name: Running MongoDB Docker + docker_container: + name: "{{ mongodb_docker_name }}" + image: "{{ mongodb_docker_image }}" + detach: True + published_ports: "{{ mongodb_docker_published_ports }}" + restart_policy: always + volumes: "{{ mongodb_docker_volumes }}" + state: started + pull: false + entrypoint: /entrypoint.sh --replSet=bigchain-rs + tags: [mongodb] \ No newline at end of file diff --git a/pkg/config/bdb-config.yaml b/pkg/config/bdb-config.yaml new file mode 100644 index 00000000..de9d1fce --- /dev/null +++ b/pkg/config/bdb-config.yaml @@ -0,0 +1,12 @@ +--- +- name: "bdb-node-01" # Instance name + box: + name: "ubuntu/xenial64" # Box name + ram: "2048" + vcpus: "2" + setup_type: "quickstart" # Currently, only quickstart is supported. + deploy_docker: true # [true, false] + network: + ip: "10.20.30.50" + type: "private_network" # Currently, only private network is supported. + upstart: "/bigchaindb/scripts/bootstrap.sh" # Path to upstart script diff --git a/pkg/scripts/bootstrap.sh b/pkg/scripts/bootstrap.sh new file mode 100755 index 00000000..9fcf5612 --- /dev/null +++ b/pkg/scripts/bootstrap.sh @@ -0,0 +1,62 @@ +#!/bin/bash +set -e + +. ./bootstrap_constants.sh +. ./bootstrap_helper.sh + +# OS ID(ubuntu, centos, fedora) +OS="" +# OS Version(16.04, 7, 24) +VER="" + +# Parsing arguments +while [[ $# -gt 1 ]]; do + arg="$1" + case $arg in + --os) + OS="$2" + shift + ;; + --os-version) + VER="$2" + shift + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac + shift +done + +validate_os_configuration(){ + valid_os=1 + if [ -f $1 ]; then + . $1 + OS=$ID + VER=$VERSION_ID + elif type lsb_release >/dev/null 2>&1; then + OS=$(lsb_release -si) + VER=$(lsb_release -sr) + else + echo "Cannot find $OS_CONF. Pass arguments to your OS configurations: NAME, VERSION_ID. + Supported OS(s) are: [ ${SUPPORTED_OS[*]} ]." + exit 1 + fi + for os in "${SUPPORTED_OS[@]}"; do + if [[ $os = $2 ]]; then + valid_os=true + break + fi + done +} + +validate_os_configuration $OS_CONF $OS $VER +echo "Operation Sytem: $OS" +echo "Version: $VER" +install_deps=$(validate_os_version_and_deps true $OS $VER) +if [[ $install_deps -eq 1 ]]; then + install_dependencies $OS +else + echo "Dependencies already installed:[ ${OS_DEPENDENCIES[*]} ]" +fi \ No newline at end of file diff --git a/pkg/scripts/bootstrap_constants.sh b/pkg/scripts/bootstrap_constants.sh new file mode 100755 index 00000000..67a6d7ef --- /dev/null +++ b/pkg/scripts/bootstrap_constants.sh @@ -0,0 +1,7 @@ +#!/bin/bash +OS_CONF=/etc/os-release +declare -a SUPPORTED_OS=('ubuntu' 'centos' 'fedora') +declare -a OS_DEPENDENCIES=('ansible') +MINIMUM_UBUNTU_VERSION=16.04 +MINIUMUM_CENTOS_VERSION=7 +MINIMIUM_FEDORA_VERSION=24 \ No newline at end of file diff --git a/pkg/scripts/bootstrap_helper.sh b/pkg/scripts/bootstrap_helper.sh new file mode 100755 index 00000000..9d4633ea --- /dev/null +++ b/pkg/scripts/bootstrap_helper.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +. ./bootstrap_constants.sh + +validate_os_version_and_deps(){ + if $1; then + case $2 in + ubuntu) + apt-get install bc -y > /dev/null 2>&1 + if [[ ($(echo $3 | bc) > $MINIMUM_UBUNTU_VERSION) + || ($(echo $3 | bc) == $MINIMUM_UBUNTU_VERSION)]]; then + dpkg -s "${OS_DEPENDENCIES[@]}" > /dev/null 2>&1 + echo $? + else + echo "Supported $2 Versions: >= $MINIMUM_UBUNTU_VERSION" + exit 1 + fi + ;; + centos) + yum install bc -y > /dev/null 2>&1 + if [[ ($(echo $3 | bc) > $MINIMUM_CENTOS_VERSION) + || ($(echo $3 | bc) == $MINIMUM_CENTOS_VERSION) ]]; then + rpm -q "${OS_DEPENDENCIES[@]}" > /dev/null 2>&1 + echo $? + else + echo "Supported $2 Versions: >= $MINIMUM_CENTOS_VERSION" + exit 1 + fi + ;; + fedora) + dnf install bc -y > /dev/null 2>&1 + if [[ ($(echo $3 | bc) > $MINIMUM_FEDORA_VERSION) + || ($(echo $3 | bc) == $MINIMUM_FEDORA_VERSION) ]]; then + rpm -q "${OS_DEPENDENCIES[@]}" > /dev/null 2>&1 + echo $? + else + echo "Supported $2 Versions: >= $MINIMUM_FEDORA_VERSION" + exit 1 + fi + ;; + *) + echo "Supported OS(s) are: [ ${SUPPORTED_OS[*]} ]." + exit 1 + ;; + esac + else + echo "Supported OS(s) are: [ ${SUPPORTED_OS[*]} ]." + exit 1 + fi +} + +install_dependencies() { + case $1 in + ubuntu) + install_deps_deb + ;; + centos) + install_deps_centos + ;; + fedora) + install_deps_fedora + ;; + *) + echo "Supported OS(s) are: [ ${SUPPORTED_OS[*]} ]." + exit 1 + ;; + esac +} + +#TODO: muawiakh(Currently only ansible is required. Make it generic for +# multiple dependencies) +install_deps_deb() { + echo "Installing Dependencies..." + apt-get install -y software-properties-common + apt-add-repository ppa:ansible/ansible + apt-get update + apt-get install -y --force-yes ansible +} +install_deps_centos() { + echo "Installing Dependencies..." + yum install epel-release -y + yum install ansible -y +} +install_deps_fedora() { + echo "Installing Dependencies..." + export LC_ALL=C + dnf makecache + dnf -y install ansible python2-dnf +} \ No newline at end of file From 3cbdc15e91a96ad33e97726f82908f133d834022 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Thu, 14 Sep 2017 17:29:23 +0200 Subject: [PATCH 004/120] Only list the new Java driver in the docs --- docs/server/source/drivers-clients/index.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/server/source/drivers-clients/index.rst b/docs/server/source/drivers-clients/index.rst index 45b0029a..407fe688 100644 --- a/docs/server/source/drivers-clients/index.rst +++ b/docs/server/source/drivers-clients/index.rst @@ -23,7 +23,6 @@ Community-Driven Libraries and Tools * `Haskell transaction builder `_ * `Go driver `_ -* `Java driver (newer, working) `_ -* `Java driver (old, not working) `_ +* `Java driver `_ * `Ruby driver `_ * `Ruby library for preparing/signing transactions and submitting them or querying a BigchainDB/IPDB node (MIT licensed) `_ From 4235618522f0d4524f57233b6e02dec2f6c985ef Mon Sep 17 00:00:00 2001 From: muawiakh Date: Mon, 18 Sep 2017 15:59:49 +0200 Subject: [PATCH 005/120] Addressing comments - support public_network for vagrant box - using python3-5 for centos based installations - Revisiting docs. - More changes will be incorporated in another PR. - Parameterize MongoDB host mount path for docker deployments --- docs/server/source/introduction.md | 1 - docs/server/source/quickstart.md | 8 +------- pkg/Vagrantfile | 10 ++++++++-- pkg/ansible/roles/bigchaindb-driver/defaults/main.yml | 5 +++-- pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml | 4 ++-- pkg/ansible/roles/bigchaindb/defaults/main.yml | 5 +++-- pkg/ansible/roles/bigchaindb/tasks/centos.yml | 6 +++++- pkg/ansible/roles/mongodb/defaults/main.yml | 10 ++++++---- pkg/config/bdb-config.yaml | 4 +++- pkg/scripts/bootstrap_helper.sh | 1 + 10 files changed, 32 insertions(+), 22 deletions(-) diff --git a/docs/server/source/introduction.md b/docs/server/source/introduction.md index 58d7de16..5c48a8fe 100644 --- a/docs/server/source/introduction.md +++ b/docs/server/source/introduction.md @@ -22,7 +22,6 @@ Note that there are a few kinds of nodes: There are some old RethinkDB-based deployment instructions as well: * [Deploy a bare-bones RethinkDB-based node on Azure](appendices/azure-quickstart-template.html) -* [Deploy a bare-bones RethinkDB-based node on any Ubuntu machine with Ansible](appendices/template-ansible.html) * [Deploy a RethinkDB-based testing cluster on AWS](appendices/aws-testing-cluster.html) Instructions for setting up a client will be provided once there's a public test net. diff --git a/docs/server/source/quickstart.md b/docs/server/source/quickstart.md index ba755a7a..62a31fb9 100644 --- a/docs/server/source/quickstart.md +++ b/docs/server/source/quickstart.md @@ -1,12 +1,6 @@ # Quickstart -This page has instructions to set up a single stand-alone BigchainDB node manually for learning or experimenting. Instructions for other cases are [elsewhere](introduction.html). You might try one of the following deployment methods -as well, depending on your choice: -- [BigchainDB with Docker](appendices/run-with-docker.html). -- [BigchainDB with Vagrant](appendices/run-with-vagrant.html). -- [BigchainDB with Ansible](appendices/run-with-ansible.html). - -For manual installation, We will assume you're using Ubuntu 16.04 or similar. +This page has instructions to set up a single stand-alone BigchainDB node for learning or experimenting. Instructions for other cases are [elsewhere](introduction.html). We will assume you're using Ubuntu 16.04 or similar. If you're not using Linux, then you might try [running BigchainDB with Docker](appendices/run-with-docker.html). A. Install MongoDB as the database backend. (There are other options but you can ignore them for now.) diff --git a/pkg/Vagrantfile b/pkg/Vagrantfile index e998b4af..b8720016 100644 --- a/pkg/Vagrantfile +++ b/pkg/Vagrantfile @@ -33,7 +33,13 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| end end bdb.vm.hostname = instance["name"] - bdb.vm.network instance["network"]["type"], ip: instance["network"]["ip"] + if instance["network"]["type"] == "private_network" + bdb.vm.network instance["network"]["type"], ip: instance["network"]["ip"] + elsif instance["network"]["type"] == "public_network" + bdb.vm.network instance["network"]["type"], use_dhcp_assigned_default_route: true, bridge: instance["network"]["bridge"] + else + raise "Invalid network type: Please specify one of the following: [private_network, public_network]" + end bdb.vm.box = instance["box"]["name"] bdb.vm.synced_folder ".", "/bigchaindb" bdb.vm.provision :shell, inline: "cd /bigchaindb/scripts;/bin/bash #{instance["upstart"]}" @@ -53,4 +59,4 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| end end end -end \ No newline at end of file +end diff --git a/pkg/ansible/roles/bigchaindb-driver/defaults/main.yml b/pkg/ansible/roles/bigchaindb-driver/defaults/main.yml index bf1297bf..63485cce 100644 --- a/pkg/ansible/roles/bigchaindb-driver/defaults/main.yml +++ b/pkg/ansible/roles/bigchaindb-driver/defaults/main.yml @@ -8,10 +8,10 @@ dependencies_deb: dependencies_yum: - gcc-c++ - "@Development Tools" - - python34-devel + - python35u-devel - libffi-devel - openssl-devel - - python34-setuptools + - python35u-setuptools dependencies_dnf: - gcc-c++ @@ -20,6 +20,7 @@ dependencies_dnf: - python3-devel - libffi-devel - openssl-devel + - python3-pip python_pip_upgrade: true python_setuptools_upgrade: true \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml b/pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml index e6014e4b..0eb69356 100644 --- a/pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml +++ b/pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml @@ -6,7 +6,7 @@ update_cache: yes with_items: "{{ dependencies_yum }}" tags: [bigchaindb-driver] - + - name: Install pip - shell: "easy_install-3.4 pip" + shell: "easy_install-3.5 pip" tags: [bigchaindb-driver] \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/defaults/main.yml b/pkg/ansible/roles/bigchaindb/defaults/main.yml index 3b75ae42..83058813 100644 --- a/pkg/ansible/roles/bigchaindb/defaults/main.yml +++ b/pkg/ansible/roles/bigchaindb/defaults/main.yml @@ -10,10 +10,10 @@ dependencies_deb: dependencies_yum: - gcc-c++ - "@Development Tools" - - python34-devel + - python35u-devel - libffi-devel - openssl-devel - - python34-setuptools + - python35u-setuptools dependencies_dnf: - gcc-c++ @@ -22,6 +22,7 @@ dependencies_dnf: - python3-devel - libffi-devel - openssl-devel + - python3-pip python_pip_upgrade: true python_setuptools_upgrade: true diff --git a/pkg/ansible/roles/bigchaindb/tasks/centos.yml b/pkg/ansible/roles/bigchaindb/tasks/centos.yml index e8ca5cd8..912d0f74 100644 --- a/pkg/ansible/roles/bigchaindb/tasks/centos.yml +++ b/pkg/ansible/roles/bigchaindb/tasks/centos.yml @@ -13,4 +13,8 @@ state: present update_cache: yes with_items: "{{ dependencies_yum }}" - tags: [bigchaindb] \ No newline at end of file + tags: [bigchaindb] + +- name: Install pip + shell: "easy_install-3.5 pip" + tags: [bigchaindb-driver] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/defaults/main.yml b/pkg/ansible/roles/mongodb/defaults/main.yml index ea4656df..950b4a18 100644 --- a/pkg/ansible/roles/mongodb/defaults/main.yml +++ b/pkg/ansible/roles/mongodb/defaults/main.yml @@ -14,7 +14,7 @@ mongodb_yum_base_url: "https://repo.mongodb.org/yum/{{ ansible_os_family|lower } mongodb_dnf_base_url: "https://repo.mongodb.org/yum/{{ ansible_os_family|lower }}/7/{{ mongodb_package }}/{{ mongodb_version }}/{{ ansible_architecture }}" # MongoDB running config -mongodb_storage_path: /data/db +mongodb_storage_path: /data/db/main mongodb_log_path: /var/log/mongodb mongodb_config_path: /data/configdb se_linux: "TODO: (muawiakh)" @@ -25,10 +25,12 @@ directories: # Docker configuration mongodb_default_port: 27017 -mongodb_docker_image: "mongo:3.4.1" +mongodb_docker_image: "mongo:3.4.4" mongodb_docker_name: "mongodb" mongodb_docker_published_ports: - 172.17.0.1:27017:27017 +mongodb_host_mount_dir_db: /tmp/mongodb_docker/db +mongodb_host_mount_dir_config: /tmp/mongodb_docker/configdb mongodb_docker_volumes: - - "/tmp/mongodb_docker/db:{{ mongodb_storage_path }}" - - "/tmp/mongodb_docker/configdb:{{ mongodb_config_path }}" \ No newline at end of file + - "{{ mongodb_host_mount_dir_db }}:{{ mongodb_storage_path }}" + - "{{ mongodb_host_mount_dir_config }}:{{ mongodb_config_path }}" \ No newline at end of file diff --git a/pkg/config/bdb-config.yaml b/pkg/config/bdb-config.yaml index de9d1fce..86acac56 100644 --- a/pkg/config/bdb-config.yaml +++ b/pkg/config/bdb-config.yaml @@ -8,5 +8,7 @@ deploy_docker: true # [true, false] network: ip: "10.20.30.50" - type: "private_network" # Currently, only private network is supported. + type: "private_network" + # Active network interface on host, Only required for public network e.g "en0: Wi-Fi (AirPort)" + bridge: "" upstart: "/bigchaindb/scripts/bootstrap.sh" # Path to upstart script diff --git a/pkg/scripts/bootstrap_helper.sh b/pkg/scripts/bootstrap_helper.sh index 9d4633ea..2c8abd32 100755 --- a/pkg/scripts/bootstrap_helper.sh +++ b/pkg/scripts/bootstrap_helper.sh @@ -79,6 +79,7 @@ install_deps_deb() { install_deps_centos() { echo "Installing Dependencies..." yum install epel-release -y + yum install -y https://centos7.iuscommunity.org/ius-release.rpm yum install ansible -y } install_deps_fedora() { From a72f971ed20c404b4c1c15e4ee1524f33570adf2 Mon Sep 17 00:00:00 2001 From: "krish7919 (Krish)" Date: Thu, 21 Sep 2017 12:37:26 +0200 Subject: [PATCH 006/120] Documenting the use of ConfigMap and Secret in deployment --- .../node-on-kubernetes.rst | 97 ++++++++++++++++++- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/docs/server/source/production-deployment-template/node-on-kubernetes.rst b/docs/server/source/production-deployment-template/node-on-kubernetes.rst index d415e44a..c9272b6e 100644 --- a/docs/server/source/production-deployment-template/node-on-kubernetes.rst +++ b/docs/server/source/production-deployment-template/node-on-kubernetes.rst @@ -322,6 +322,18 @@ Step 9.1: Vanilla NGINX ``cluster-health-check-port``. Set them to the values specified in the ConfigMap. + * The configuration uses the following values set in the ConfigMap: + + - ``cluster-frontend-port`` + - ``cluster-health-check-port`` + - ``cluster-dns-server-ip`` + - ``mongodb-frontend-port`` + - ``ngx-mdb-instance-name`` + - ``mongodb-backend-port`` + - ``ngx-bdb-instance-name`` + - ``bigchaindb-api-port`` + - ``bigchaindb-ws-port`` + * Start the Kubernetes Deployment: .. code:: bash @@ -346,6 +358,25 @@ Step 9.2: NGINX with HTTPS ``cluster-health-check-port``. Set them to the values specified in the ConfigMap. + * The configuration uses the following values set in the ConfigMap: + + - ``cluster-frontend-port`` + - ``cluster-health-check-port`` + - ``cluster-fqdn`` + - ``cluster-dns-server-ip`` + - ``mongodb-frontend-port`` + - ``ngx-mdb-instance-name`` + - ``mongodb-backend-port`` + - ``openresty-backend-port`` + - ``ngx-openresty-instance-name`` + - ``ngx-bdb-instance-name`` + - ``bigchaindb-api-port`` + - ``bigchaindb-ws-port`` + + * The configuration uses the following values set in the Secret: + + - ``https-certs`` + * Start the Kubernetes Deployment: .. code:: bash @@ -500,6 +531,17 @@ Step 12: Start a Kubernetes StatefulSet for MongoDB backend port. Set it to the value specified for ``mongodb-backend-port`` in the ConfigMap. + * The configuration uses the following values set in the ConfigMap: + + - ``mdb-instance-name`` + - ``mongodb-replicaset-name`` + - ``mongodb-backend-port`` + + * The configuration uses the following values set in the Secret: + + - ``mdb-certs`` + - ``ca-auth`` + * Create the MongoDB StatefulSet using: .. code:: bash @@ -661,6 +703,12 @@ Step 14: Start a Kubernetes Deployment for MongoDB Monitoring Agent ``mdb-mon-instance-name`` is ``mdb-mon-instance-0``, set the fields to the value ``mdb-mon-instance-0-dep``. + * The configuration uses the following values set in the Secret: + + - ``mdb-mon-certs`` + - ``ca-auth`` + - ``cloud-manager-credentials`` + * Start the Kubernetes Deployment using: .. code:: bash @@ -682,6 +730,12 @@ Step 15: Start a Kubernetes Deployment for MongoDB Backup Agent ``mdb-bak-instance-name`` is ``mdb-bak-instance-0``, set the fields to the value ``mdb-bak-instance-0-dep``. + * The configuration uses the following values set in the Secret: + + - ``mdb-bak-certs`` + - ``ca-auth`` + - ``cloud-manager-credentials`` + * Start the Kubernetes Deployment using: .. code:: bash @@ -714,10 +768,34 @@ Step 16: Start a Kubernetes Deployment for BigchainDB richer monitoring and probing becomes available in BigchainDB, we will tweak the ``livenessProbe`` and ``readinessProbe`` parameters. - * Set the ports to be exposed from the pod in the - ``spec.containers[0].ports`` section. We currently expose 2 ports - - ``bigchaindb-api-port`` and ``bigchaindb-ws-port``. Set them to the - values specified in the ConfigMap. + * Set the ports to be exposed from the pod in the + ``spec.containers[0].ports`` section. We currently expose 2 ports - + ``bigchaindb-api-port`` and ``bigchaindb-ws-port``. Set them to the + values specified in the ConfigMap. + + * The configuration uses the following values set in the ConfigMap: + + - ``mdb-instance-name`` + - ``mongodb-backend-port`` + - ``mongodb-replicaset-name`` + - ``bigchaindb-database-name`` + - ``bigchaindb-server-bind`` + - ``bigchaindb-ws-interface`` + - ``cluster-fqdn`` + - ``bigchaindb-ws-port`` + - ``cluster-frontend-port`` + - ``bigchaindb-wsserver-advertised-scheme`` + - ``bdb-public-key`` + - ``bigchaindb-backlog-reassign-delay`` + - ``bigchaindb-database-maxtries`` + - ``bigchaindb-database-connection-timeout`` + - ``bigchaindb-log-level`` + - ``bdb-user`` + + * The configuration uses the following values set in the Secret: + + - ``bdb-certs`` + - ``ca-auth`` * Create the BigchainDB Deployment using: @@ -747,6 +825,17 @@ Step 17: Start a Kubernetes Deployment for OpenResty which OpenResty is listening for requests, ``openresty-backend-port`` in the above ConfigMap. + * The configuration uses the following values set in the Secret: + + - ``threescale-credentials`` + + * The configuration uses the following values set in the ConfigMap: + + - ``cluster-dns-server-ip`` + - ``openresty-backend-port`` + - ``ngx-bdb-instance-name`` + - ``bigchaindb-api-port`` + * Create the OpenResty Deployment using: .. code:: bash From 8160190f3abb6f422306865c104e1868bd4efbb0 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Mon, 25 Sep 2017 15:12:54 +0200 Subject: [PATCH 007/120] Added notes about new Java driver & Ruby library in CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a94cccf7..bb4ddb34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,9 @@ Tag name: v1.1.0 * @ketanbhatt - Pull requests [#1643](https://github.com/bigchaindb/bigchaindb/pull/1643) and [#1644](https://github.com/bigchaindb/bigchaindb/pull/1644) ### Notes +* New drivers & tools from our community: + * [Java driver](https://github.com/authenteq/java-bigchaindb-driver), by [Authenteq](https://authenteq.com/) + * [Ruby library](https://rubygems.org/gems/bigchaindb), by @nileshtrivedi * Many improvements to our production deployment template (which uses Kubernetes). * The production deployment template for the multi-node case was out of date. We updated that and verified it. [Pull request #1713](https://github.com/bigchaindb/bigchaindb/pull/1713) From 2cbf6b6a5c0bfd48b8133e1dbae8775482e3d1ad Mon Sep 17 00:00:00 2001 From: Muawia Khan Date: Wed, 16 Aug 2017 14:04:43 +0200 Subject: [PATCH 008/120] [WIP]: Move the bigchaindb/nginx_3scale repo under bigchaindb/bigchaindb - All files moved to k8s/nginx-3scale with directory structure consistent with k8s/nginx-http(s) - Top level LICENCES.md updated - Renaming entry point script to nginx_openresty_entrypoint.bash --- LICENSES.md | 1 + k8s/nginx-openresty/LICENSE.md | 77 ++++ k8s/nginx-openresty/container/Dockerfile | 15 + k8s/nginx-openresty/container/README.md | 96 ++++ .../container/docker_build_and_push.bash | 5 + .../container/nginx.conf.template | 197 +++++++++ .../container/nginx.lua.template | 416 ++++++++++++++++++ .../container/nginx_openresty_entrypoint.bash | 58 +++ 8 files changed, 865 insertions(+) create mode 100644 k8s/nginx-openresty/LICENSE.md create mode 100644 k8s/nginx-openresty/container/Dockerfile create mode 100644 k8s/nginx-openresty/container/README.md create mode 100755 k8s/nginx-openresty/container/docker_build_and_push.bash create mode 100644 k8s/nginx-openresty/container/nginx.conf.template create mode 100644 k8s/nginx-openresty/container/nginx.lua.template create mode 100755 k8s/nginx-openresty/container/nginx_openresty_entrypoint.bash diff --git a/LICENSES.md b/LICENSES.md index 82d62018..1e498b3c 100644 --- a/LICENSES.md +++ b/LICENSES.md @@ -4,6 +4,7 @@ For all code in this repository, BigchainDB GmbH ("We") either: 1. owns the copyright, or 2. owns the right to sublicense it (because all external contributors must agree to a Contributor License Agreement). +3. The licensing of things in the k8s/nginx-openresty/ directory is described by a separate LICENSE.md file in that directory. Therefore We can choose how to license all the code in this repository. We can license it to Joe Xname under one license and Company Yname under a different license. diff --git a/k8s/nginx-openresty/LICENSE.md b/k8s/nginx-openresty/LICENSE.md new file mode 100644 index 00000000..ed4710c4 --- /dev/null +++ b/k8s/nginx-openresty/LICENSE.md @@ -0,0 +1,77 @@ +# Licenses on the Software in This Git Repository + +This Git repository can be found at +[https://github.com/bigchaindb/nginx_3scale](https://github.com/bigchaindb/nginx_3scale) + +All code in this repository is copyright 2016-2017 BigchainDB GmbH, +except for the configuration files obtained from 3scale (NGINX configuration +file and NGINX Lua script). + +`nginx.conf.template` and `nginx.lua.template` are based on files we got from +3scale (by going to the 3scale admin site - API - Integration - Download +the NGINX Config files). + +The original files (from 3scale) were licensed under an MIT License, +the text of which can be found below. + +The derived files (`nginx.conf.template` and `nginx.lua.template`), along with +the other files in this repository, are also licensed under an MIT License, +the text of which can be found below. + + +# Documentation Licenses + +The documentation is licensed under a Creative Commons Attribution-ShareAlike +4.0 International license, the full text of which can be found at +[http://creativecommons.org/licenses/by-sa/4.0/legalcode](http://creativecommons.org/licenses/by-sa/4.0/legalcode). + + +
+ +The MIT License + +Copyright (c) 2016-2017 BigchainDB GmbH. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +
+ +The MIT License + +Copyright (c) 2007-2016 3scale Networks S.L. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/k8s/nginx-openresty/container/Dockerfile b/k8s/nginx-openresty/container/Dockerfile new file mode 100644 index 00000000..8e5b7e2e --- /dev/null +++ b/k8s/nginx-openresty/container/Dockerfile @@ -0,0 +1,15 @@ +FROM openresty/openresty:xenial +LABEL maintainer "dev@bigchaindb.com" +WORKDIR / +RUN apt-get update \ + && apt-get -y upgrade \ + && apt-get autoremove \ + && apt-get clean +COPY nginx.conf.template /usr/local/openresty/nginx/conf/nginx.conf +COPY nginx.lua.template /usr/local/openresty/nginx/conf/nginx.lua +COPY nginx_entrypoint.bash / +# The following ports are the values we use to run the NGINX+3scale container. +# 80 for http, 8080 for the 3scale api, 8888 for health-check, 27017 for +# MongoDB +EXPOSE 80 8080 8888 27017 +ENTRYPOINT ["/nginx_openresty_entrypoint.bash"] diff --git a/k8s/nginx-openresty/container/README.md b/k8s/nginx-openresty/container/README.md new file mode 100644 index 00000000..c75fa206 --- /dev/null +++ b/k8s/nginx-openresty/container/README.md @@ -0,0 +1,96 @@ +# nginx_3scale agent +nginx_3scale agent is a module that is responsible for providing authentication, +authorization and metering of BigchainDB API users, by communicating with 3scale. +We use the openresty for this, which is nginx bundled with lua libraries. +More information at their [website](openresty.org/en) + +It validates the tokens sent by users in HTTP headers. +The user tokens map directly to the Application Plan specified in 3scale. + +## Build and Push the Latest Container +Use the `docker_build_and_push.bash` script to build the latest docker image +and upload it to Docker Hub. +Ensure that the image tag is updated to a new version number to properly +reflect any changes made to the container. + + +## Working + +* We define a [lua module](./nginx.lua.template) and + custom hooks (lua functions to be executed at certain phases of the nginx + request processing lifecycle) to authenticate an API request. + +* Download the template available from 3scale which pre-defines all the + rules defined using the 3scale UI for monitoring, and the basic nginx + configuration. + +* We heavily modify these templates to add our custom functionality. + +* The nginx_3scale image reads the environment variables and accordingly + creates the nginx.conf and nginx.lua files from the templates. + +* Every request calls the `_M.access()` function. This function extracts the + `app_id` and `app_key` from the HTTP request headers and forwards it to + 3scale to see if a request is allowed to be forwarded to the BigchainDB + backend. The request also contains the + various parameters that one would like to set access policies on. If the + `app_id` and `app_key` is successful, the access rules for the parameters + passed with the request are checked to see if the request can pass through. + For example, we can send a parameter, say `request_body_size`, to the 3scale + auth API. If we have defined a rule in the 3scale dashboard to drop + `request_body_size` above a certain threshold, the authorization will fail + even if the `app_id` and `app_key` are valid. + +* A successful response from the auth API causes the request to be proxied to + the backend. After a backend response, the `_M.post_action_content` hook is + called. We calculate details about all the metrics we are interested in and + form a payload for the 3scale reporting API. This ensures that we update + parameters of every metric defined in the 3scale UI after every request. + +* Note: We do not cache the keys in nginx so that we can validate every request + with 3scale and apply plan rules immediately. We can add auth caching to + improve performance, and in case we move to a fully post-paid billing model. + +* Refer to the references made in the [lua module](./nginx.lua.template) for + more details about how nginx+lua+3scale works + +* For HTTPS support, we also need to add the signed certificate and the + corresponding private key to the folder + `/usr/local/openresty/nginx/conf/ssl/`. Name the pem-encoded certificate as + `cert.pem` and the private key as `cert.key`. + + +## Deployment terminology +We currently use the terms `frontend`, `backend`, `upstream` in our code and +configuration. This diagram should help understand the various terms. + +The final goal is to have a deployment that looks like this: + +``` + +------------+ +------------+ + | | | | ++-----------------------------+----+ N | +---------------------+------+ | +| BigchainDB Frontend Port | G | | BigchainDB Backend Port | | +| | I | | | | +|[port number exposed globally | N | +--------> |[port where BDB instance | | +| for backend BDB cluster services]| X | | | listens/waits for requests]| | ++-----------------------------+----+ | | +---------------------+------+ | + | G | | | | ++-----------------------------+----+ A | | | BigchainDB | +| Health Check Port | T | | | Backend | +| | E | | | Host | +| [port number exposed to the LB | W | | +------------+ +| for health checks] | A | | ++-----------------------------+----+ Y | | +------------+ + | | | | MongoDB | + | +--+------------------+-------+ | Backend | ++-----------------------------+----+ | Upstream API Port | | Host | +| MongoDB Frontend Port | | | | | +| | |[internal port where we can | +--------------------+--------+ | +| [port number for MongoDB | |access backend BDB cluster | | MongoDB Backend Port | | +| instances to communicate | +--+--------------------------+ | | | +| with each other +-------+----------------------------->|[port where MongoDB instance | | ++-----------------------------+----+ | | listens/waits for requests] | | + | | +--------------------+--------+ | + +------------+ +------------+ +``` diff --git a/k8s/nginx-openresty/container/docker_build_and_push.bash b/k8s/nginx-openresty/container/docker_build_and_push.bash new file mode 100755 index 00000000..4f02ae19 --- /dev/null +++ b/k8s/nginx-openresty/container/docker_build_and_push.bash @@ -0,0 +1,5 @@ +#!/bin/bash + +docker build -t bigchaindb/nginx_3scale:3.0 . + +docker push bigchaindb/nginx_3scale:3.0 diff --git a/k8s/nginx-openresty/container/nginx.conf.template b/k8s/nginx-openresty/container/nginx.conf.template new file mode 100644 index 00000000..9a4e56bc --- /dev/null +++ b/k8s/nginx-openresty/container/nginx.conf.template @@ -0,0 +1,197 @@ +worker_processes 2; +daemon off; +user nobody nogroup; +pid /tmp/nginx.pid; +error_log /usr/local/openresty/nginx/logs/error.log; +env THREESCALE_DEPLOYMENT_ENV; + +events { + worker_connections 256; + accept_mutex on; + use epoll; +} + +http { + lua_shared_dict api_keys 10m; + server_names_hash_bucket_size 128; + lua_package_path ";;$prefix/?.lua;$prefix/conf/?.lua"; + init_by_lua 'math.randomseed(ngx.time()) ; cjson = require("cjson")'; + access_log /usr/local/openresty/nginx/logs/access.log combined buffer=16k flush=5s; + + # allow 10 req/sec from the same IP address, and store the counters in a + # `zone` or shared memory location tagged as 'one'. + limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s; + # enable logging when requests are being throttled + limit_req_log_level notice; + + # the http status code to return to the client; 429 is for TooManyRequests, + # ref. RFC 6585 + limit_req_status 429; + + resolver DNS_SERVER valid=30s ipv6=off; + + map $remote_addr $bdb_backend { + default BIGCHAINDB_BACKEND_HOST; + } + + upstream backend_SERVICE_ID { + server localhost:9999 max_fails=5 fail_timeout=30; + } + + # Our frontend API server that accepts requests from the external world and + # takes care of authentication and authorization. If auth is successful, it + # forwards the request to the backend_SERVICE_ID upstream where a consortium + # can run a BDB cluster. + server { + lua_code_cache on; + listen OPENRESTY_FRONTEND_PORT; + keepalive_timeout 60s; + + underscores_in_headers on; + set_by_lua $deployment 'return os.getenv("THREESCALE_DEPLOYMENT_ENV")'; + set $threescale_backend "https://su1.3scale.net"; + #set $threescale_backend "http://su1.3scale.net"; + #set $threescale_backend "https://su1.3scale.net:443"; + #set $threescale_backend "https://echo-api.3scale.net"; + + # `slowloris` attack mitigation settings + client_body_timeout 10s; + client_header_timeout 10s; + + location = /out_of_band_authrep_action { + internal; + proxy_pass_request_headers off; + set $service_token "SERVICE_TOKEN"; + content_by_lua "require('nginx').post_action_content()"; + } + + # 3scale auth api that takes the auth credentials and metrics as input, + # and returns 200 OK if both the credentials match and the user has not + # exceeded the limits in his application plan. + location = /threescale_auth { + internal; + set $service_token "SERVICE_TOKEN"; + proxy_pass $threescale_backend/transactions/authorize.xml?service_token=$service_token&service_id=$service_id&$usage&$credentials&log%5Bcode%5D=$arg_code&log%5Brequest%5D=$arg_req&log%5Bresponse%5D=$arg_resp; + proxy_set_header Host "su1.3scale.net"; + #proxy_set_header Host "echo-api.3scale.net"; + proxy_set_header X-3scale-User-Agent "nginx$deployment"; + proxy_set_header X-3scale-Version "THREESCALE_VERSION_HEADER"; + } + + # 3scale reporting api that takes the metrics data and persists the metrics + # in the 3scale backend. + location = /threescale_report { + internal; + set $service_token "SERVICE_TOKEN"; + proxy_pass $threescale_backend/transactions.xml; + proxy_set_header Host "su1.3scale.net"; + #proxy_set_header Host "echo-api.3scale.net"; + # We have a bug in lua-nginx module that does not set + # Content-Type from lua script + proxy_pass_request_headers off; + proxy_set_header Content-Type "application/x-www-form-urlencoded"; + proxy_set_header X-3scale-User-Agent "nginx$deployment"; + proxy_set_header X-3scale-Version "THREESCALE_VERSION_HEADER"; + } + + location / { + proxy_ignore_client_abort on; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-3scale-proxy-secret-token $secret_token; + + # limit requests from the same client, allow `burst` to 20 r/s, + # `nodelay` or drop connection immediately in case it exceeds this + # threshold. + limit_req zone=one burst=20 nodelay; + + # We do not need the GET handling here as it's done in the other NGINX + # module + #if ($request_method = GET ) { + # proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT; + #} + + if ($request_method = POST ) { + set $service_token null; + set $cached_key null; + set $credentials null; + set $usage null; + set $service_id SERVICE_ID; + set $proxy_pass null; + set $secret_token null; + set $resp_body null; + set $resp_headers null; + access_by_lua "require('nginx').access()"; + body_filter_by_lua 'ngx.ctx.buffered = (ngx.ctx.buffered or "") .. string.sub(ngx.arg[1], 1, 1000) + if ngx.arg[2] then ngx.var.resp_body = ngx.ctx.buffered end'; + header_filter_by_lua 'ngx.var.resp_headers = cjson.encode(ngx.resp.get_headers())'; + + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; + add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; + + proxy_pass $proxy_pass ; + post_action /out_of_band_authrep_action; + } + + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,app_key,app_id'; + add_header 'Access-Control-Max-Age' 43200; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + } + } + + # Our backend server block that accepts requests from the nginx proxy and + # forwards it to instances of BDB cluster. We currently run only a single + # instance. + server { + sendfile on; + + listen 9999; + + # max client request body size: avg transaction size + client_max_body_size 15k; + + # keepalive connection settings + keepalive_timeout 60s; + + # `slowloris` attack mitigation settings + client_body_timeout 10s; + client_header_timeout 10s; + + if ( $http_x_3scale_proxy_secret_token != "THREESCALE_RESPONSE_SECRET_TOKEN" ) { + return 403; + } + + location / { + try_files $uri @proxy_to_app; + } + + location @proxy_to_app { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # enable the following line if and only if you use HTTPS + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + + # we don't want nginx trying to do something clever with + # redirects, we set the Host: header above already. + proxy_redirect off; + proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT; + + # limit requests from the same client, allow `burst` to 20 r/s on avg, + # `nodelay` or drop connection immediately in case it exceeds this + # threshold. + limit_req zone=one burst=20 nodelay; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/local/openresty/nginx/html/50x.html; + } + } +} diff --git a/k8s/nginx-openresty/container/nginx.lua.template b/k8s/nginx-openresty/container/nginx.lua.template new file mode 100644 index 00000000..64baeaa1 --- /dev/null +++ b/k8s/nginx-openresty/container/nginx.lua.template @@ -0,0 +1,416 @@ +-- -*- mode: lua; -*- +-- Generated on: 2017-04-10 14:41:18 +0000 -- +-- Version: +-- Error Messages per service + +-- Ref: https://github.com/openresty/lua-nginx-module +-- Ref: https://ipdbtestnet-admin.3scale.net/p/admin/api_docs +-- Ref: http://nginx.org/en/docs/debugging_log.html + +local custom_config = false + +local _M = { + ['services'] = { + ['SERVICE_ID'] = { + error_auth_failed = 'Authentication failed', + error_auth_missing = 'Authentication parameters missing', + auth_failed_headers = 'text/plain; charset=us-ascii', + auth_missing_headers = 'text/plain; charset=us-ascii', + error_no_match = 'No Mapping Rule matched', + no_match_headers = 'text/plain; charset=us-ascii', + no_match_status = 404, + auth_failed_status = 403, + auth_missing_status = 403, + secret_token = 'THREESCALE_RESPONSE_SECRET_TOKEN', + get_credentials = function(service, params) + return ( + (params.app_id and params.app_key) + ) or error_no_credentials(service) + end, + extract_usage = function (service, request) + local method, url = unpack(string.split(request," ")) + local path, querystring = unpack(string.split(url, "?")) + local usage_t = {} + local matched_rules = {} + + local args = get_auth_params(nil, method) + + for i,r in ipairs(service.rules) do + check_rule({path=path, method=method, args=args}, r, usage_t, matched_rules) + end + + -- if there was no match, usage is set to nil and it will respond a 404, this behavior can be changed + return usage_t, table.concat(matched_rules, ", ") + end, + rules = { + { + method = 'POST', + pattern = '/api/{version}/transactions$', + parameters = { 'version' }, + querystring_params = function(args) + return true + end, + system_name = 'hits', + delta = 1 + }, + { + method = 'POST', + pattern = '/api/{version}/transactions$', + parameters = { 'version' }, + querystring_params = function(args) + return true + end, + system_name = 'request_body_size', + delta = 1 + }, + { + method = 'POST', + pattern = '/api/{version}/transactions$', + parameters = { 'version' }, + querystring_params = function(args) + return true + end, + system_name = 'response_body_size', + delta = 1 + }, + { + method = 'POST', + pattern = '/api/{version}/transactions$', + parameters = { 'version' }, + querystring_params = function(args) + return true + end, + system_name = 'post_transactions', + delta = 1 + }, + { + method = 'POST', + pattern = '/api/{version}/transactions$', + parameters = { 'version' }, + querystring_params = function(args) + return true + end, + system_name = 'total_body_size', + delta = 1 + }, + } +}, + } +} + +-- Error Codes +function error_no_credentials(service) + ngx.status = service.auth_missing_status + ngx.header.content_type = service.auth_missing_headers + ngx.print(service.error_auth_missing) + ngx.exit(ngx.HTTP_OK) +end + +function error_authorization_failed(service) + ngx.status = service.auth_failed_status + ngx.header.content_type = service.auth_failed_headers + ngx.print(service.error_auth_failed) + ngx.exit(ngx.HTTP_OK) +end + +function error_no_match(service) + ngx.status = service.no_match_status + ngx.header.content_type = service.no_match_headers + ngx.print(service.error_no_match) + ngx.exit(ngx.HTTP_OK) +end +-- End Error Codes + +-- Aux function to split a string + +function string:split(delimiter) + local result = { } + local from = 1 + local delim_from, delim_to = string.find( self, delimiter, from ) + if delim_from == nil then return {self} end + while delim_from do + table.insert( result, string.sub( self, from , delim_from-1 ) ) + from = delim_to + 1 + delim_from, delim_to = string.find( self, delimiter, from ) + end + table.insert( result, string.sub( self, from ) ) + return result +end + +function first_values(a) + r = {} + for k,v in pairs(a) do + if type(v) == "table" then + r[k] = v[1] + else + r[k] = v + end + end + return r +end + +function set_or_inc(t, name, delta) + return (t[name] or 0) + delta +end + +function build_querystring_formatter(fmt) + return function (query) + local function kvmap(f, t) + local res = {} + for k, v in pairs(t) do + table.insert(res, f(k, v)) + end + return res + end + + return table.concat(kvmap(function(k,v) return string.format(fmt, k, v) end, query or {}), "&") + end +end + +local build_querystring = build_querystring_formatter("usage[%s]=%s") +local build_query = build_querystring_formatter("%s=%s") + +function regexpify(path) + return path:gsub('?.*', ''):gsub("{.-}", '([\\w_.-]+)'):gsub("%.", "\\.") +end + +function check_rule(req, rule, usage_t, matched_rules) + local param = {} + local p = regexpify(rule.pattern) + local m = ngx.re.match(req.path, + string.format("^%s",p)) + if m and req.method == rule.method then + local args = req.args + if rule.querystring_params(args) then -- may return an empty table + -- when no querystringparams + -- in the rule. it's fine + for i,p in ipairs(rule.parameters) do + param[p] = m[i] + end + + table.insert(matched_rules, rule.pattern) + usage_t[rule.system_name] = set_or_inc(usage_t, rule.system_name, rule.delta) + end + end +end + +--[[ + Authorization logic + NOTE: We do not use any of the authorization logic defined in the template. + We use custom authentication and authorization logic defined in the + custom_app_id_authorize() function. +]]-- + +function get_auth_params(where, method) + local params = {} + if where == "headers" then + params = ngx.req.get_headers() + elseif method == "GET" then + params = ngx.req.get_uri_args() + else + ngx.req.read_body() + params = ngx.req.get_post_args() + end + return first_values(params) +end + +function get_debug_value() + local h = ngx.req.get_headers() + if h["X-3scale-debug"] == 'SERVICE_TOKEN' then + return true + else + return false + end +end + +function _M.authorize(auth_strat, params, service) + if auth_strat == 'oauth' then + oauth(params, service) + else + authrep(params, service) + end +end + +function oauth(params, service) + ngx.var.cached_key = ngx.var.cached_key .. ":" .. ngx.var.usage + local access_tokens = ngx.shared.api_keys + local is_known = access_tokens:get(ngx.var.cached_key) + + if is_known ~= 200 then + local res = ngx.location.capture("/threescale_oauth_authrep", { share_all_vars = true }) + + -- IN HERE YOU DEFINE THE ERROR IF CREDENTIALS ARE PASSED, BUT THEY ARE NOT VALID + if res.status ~= 200 then + access_tokens:delete(ngx.var.cached_key) + ngx.status = res.status + ngx.header.content_type = "application/json" + ngx.var.cached_key = nil + error_authorization_failed(service) + else + access_tokens:set(ngx.var.cached_key,200) + end + + ngx.var.cached_key = nil + end +end + +function authrep(params, service) + ngx.var.cached_key = ngx.var.cached_key .. ":" .. ngx.var.usage + local api_keys = ngx.shared.api_keys + local is_known = api_keys:get(ngx.var.cached_key) + + if is_known ~= 200 then + local res = ngx.location.capture("/threescale_authrep", { share_all_vars = true }) + + -- IN HERE YOU DEFINE THE ERROR IF CREDENTIALS ARE PASSED, BUT THEY ARE NOT VALID + if res.status ~= 200 then + -- remove the key, if it's not 200 let's go the slow route, to 3scale's backend + api_keys:delete(ngx.var.cached_key) + ngx.status = res.status + ngx.header.content_type = "application/json" + ngx.var.cached_key = nil + error_authorization_failed(service) + else + api_keys:set(ngx.var.cached_key,200) + end + ngx.var.cached_key = nil + end +end + +function _M.access() + local params = {} + local host = ngx.req.get_headers()["Host"] + local auth_strat = "" + local service = {} + local usage = {} + local matched_patterns = '' + + if ngx.status == 403 then + ngx.say("Throttling due to too many requests") + ngx.exit(403) + end + + if ngx.var.service_id == 'SERVICE_ID' then + local parameters = get_auth_params("headers", string.split(ngx.var.request, " ")[1] ) + service = _M.services['SERVICE_ID'] -- + ngx.var.secret_token = service.secret_token + params.app_id = parameters["app_id"] + params.app_key = parameters["app_key"] -- or "" -- Uncoment the first part if you want to allow not passing app_key + service.get_credentials(service, params) + ngx.var.cached_key = "SERVICE_ID" .. ":" .. params.app_id ..":".. params.app_key + auth_strat = "2" + ngx.var.service_id = "SERVICE_ID" + ngx.var.proxy_pass = "http://backend_SERVICE_ID" + usage, matched_patterns = service:extract_usage(ngx.var.request) + end + + usage['post_transactions'] = 0 + usage['request_body_size'] = 0 + usage['total_body_size'] = 0 + usage['response_body_size'] = 0 + ngx.var.credentials = build_query(params) + ngx.var.usage = build_querystring(usage) + + -- WHAT TO DO IF NO USAGE CAN BE DERIVED FROM THE REQUEST. + if ngx.var.usage == '' then + ngx.header["X-3scale-matched-rules"] = '' + error_no_match(service) + end + + if get_debug_value() then + ngx.header["X-3scale-matched-rules"] = matched_patterns + ngx.header["X-3scale-credentials"] = ngx.var.credentials + ngx.header["X-3scale-usage"] = ngx.var.usage + ngx.header["X-3scale-hostname"] = ngx.var.hostname + end + _M.custom_app_id_authorize(params, service) +end + +function _M.custom_app_id_authorize(params, service) + ngx.var.cached_key = ngx.var.cached_key .. ":" .. ngx.var.usage + local api_keys = ngx.shared.api_keys + local res = ngx.location.capture("/threescale_auth", { share_all_vars = true }) + if res.status ~= 200 then + ngx.status = res.status + ngx.header.content_type = "application/json" + ngx.var.cached_key = nil + error_authorization_failed(service) + end + ngx.var.cached_key = nil +end + +function _M.post_action_content() + local report_data = {} + + -- increment POST count + report_data['post_transactions'] = 1 + + -- NOTE: When we are querying for the length of the request here, we already + -- have the complete request data with us and hence can just use the len() + -- function to get the size of the payload in bytes. + -- However, we might not have a complete response from the backend at this + -- stage (esp. if it's a large response size). So, we decipher the payload + -- size by peeking into the content length header of the response. + -- Otherwise, nginx will have to buffer every response and then calculate + -- response payload size. + + -- req data size + local req_data = ngx.req.get_body_data() + if req_data then + report_data['request_body_size'] = req_data:len() + else + report_data['request_body_size'] = 0 + end + + -- res data size + local all_headers = cjson.decode(ngx.var.resp_headers) + local variable_header = "content-length" --<-- case sensitive + if all_headers[variable_header] then + report_data['response_body_size'] = all_headers[variable_header] + else + report_data['response_body_size'] = 0 + end + + -- total data size + report_data['total_body_size'] = report_data['request_body_size'] + report_data['response_body_size'] + + -- get the app_id + local app_id = "" + local credentials = ngx.var.credentials:split("&") + for i in pairs(credentials) do + if credentials[i]:match('app_id') then + local temp = credentials[i]:split("=") + app_id = temp[2] + end + end + + -- form the payload to report to 3scale + local report = {} + report['service_id'] = ngx.var.service_id + report['service_token'] = ngx.var.service_token + report['transactions[0][app_id]'] = app_id + report['transactions[0][usage][post_transactions]'] = report_data['post_transactions'] + report['transactions[0][usage][request_body_size]'] = report_data['request_body_size'] + report['transactions[0][usage][response_body_size]'] = report_data['response_body_size'] + report['transactions[0][usage][total_body_size]'] = report_data['total_body_size'] + local res1 = ngx.location.capture("/threescale_report", {method = ngx.HTTP_POST, body = ngx.encode_args(report), share_all_vars = true }) + --ngx.log(0, ngx.encode_args(report)) + ngx.log(0, "Status: "..res1.status) + ngx.log(0, "Body: "..res1.body) + --if res1.status ~= 200 then + -- local api_keys = ngx.shared.api_keys + -- api_keys:delete(cached_key) + --end + ngx.exit(ngx.HTTP_OK) +end + +if custom_config then + local ok, c = pcall(function() return require(custom_config) end) + if ok and type(c) == 'table' and type(c.setup) == 'function' then + c.setup(_M) + end +end + +return _M + +-- END OF SCRIPT diff --git a/k8s/nginx-openresty/container/nginx_openresty_entrypoint.bash b/k8s/nginx-openresty/container/nginx_openresty_entrypoint.bash new file mode 100755 index 00000000..baad9a47 --- /dev/null +++ b/k8s/nginx-openresty/container/nginx_openresty_entrypoint.bash @@ -0,0 +1,58 @@ +#!/bin/bash +set -euo pipefail + +# Openresty vars +dns_server=`printenv DNS_SERVER` +openresty_frontend_port=`printenv OPENRESTY_FRONTEND_PORT` + + +# BigchainDB vars +bdb_backend_host=`printenv BIGCHAINDB_BACKEND_HOST` +bdb_api_port=`printenv BIGCHAINDB_API_PORT` + + +# Read the 3scale credentials from the mountpoint +# Should be mounted at the following directory +THREESCALE_CREDENTIALS_DIR=/usr/local/openresty/nginx/conf/threescale + +threescale_secret_token=`cat ${THREESCALE_CREDENTIALS_DIR}/secret-token` +threescale_service_id=`cat ${THREESCALE_CREDENTIALS_DIR}/service-id` +threescale_version_header=`cat ${THREESCALE_CREDENTIALS_DIR}/version-header` +threescale_service_token=`cat ${THREESCALE_CREDENTIALS_DIR}/service-token` + + +# sanity checks TODO(Krish): hardening +if [[ -z "${dns_server}" || \ + -z "${openresty_frontend_port}" || \ + -z "${bdb_backend_host}" || \ + -z "${bdb_api_port}" || \ + -z "${threescale_secret_token}" || \ + -z "${threescale_service_id}" || \ + -z "${threescale_version_header}" || \ + -z "${threescale_service_token}" ]]; then + echo "Invalid environment settings detected. Exiting!" + exit 1 +fi + +NGINX_LUA_FILE=/usr/local/openresty/nginx/conf/nginx.lua +NGINX_CONF_FILE=/usr/local/openresty/nginx/conf/nginx.conf + +# configure the nginx.lua file with env variables +sed -i "s|SERVICE_ID|${threescale_service_id}|g" ${NGINX_LUA_FILE} +sed -i "s|THREESCALE_RESPONSE_SECRET_TOKEN|${threescale_secret_token}|g" ${NGINX_LUA_FILE} +sed -i "s|SERVICE_TOKEN|${threescale_service_token}|g" ${NGINX_LUA_FILE} + +# configure the nginx.conf file with env variables +sed -i "s|DNS_SERVER|${dns_server}|g" ${NGINX_CONF_FILE} +sed -i "s|OPENRESTY_FRONTEND_PORT|${openresty_frontend_port}|g" ${NGINX_CONF_FILE} +sed -i "s|BIGCHAINDB_BACKEND_HOST|${bdb_backend_host}|g" ${NGINX_CONF_FILE} +sed -i "s|BIGCHAINDB_API_PORT|${bdb_api_port}|g" ${NGINX_CONF_FILE} +sed -i "s|THREESCALE_RESPONSE_SECRET_TOKEN|${threescale_secret_token}|g" $NGINX_CONF_FILE +sed -i "s|SERVICE_ID|${threescale_service_id}|g" $NGINX_CONF_FILE +sed -i "s|THREESCALE_VERSION_HEADER|${threescale_version_header}|g" $NGINX_CONF_FILE +sed -i "s|SERVICE_TOKEN|${threescale_service_token}|g" $NGINX_CONF_FILE + + +# start nginx +echo "INFO: starting nginx..." +exec /usr/local/openresty/nginx/sbin/nginx -c ${NGINX_CONF_FILE} From a1fe3d27ce7cc73c0d490484facae3163947dab6 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Thu, 31 Aug 2017 16:55:45 +0200 Subject: [PATCH 009/120] Edited two LICENSES.md files --- LICENSES.md | 15 +++++++++------ k8s/nginx-openresty/LICENSE.md | 11 ++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/LICENSES.md b/LICENSES.md index 1e498b3c..a62ca81e 100644 --- a/LICENSES.md +++ b/LICENSES.md @@ -1,24 +1,27 @@ # Code Licenses -For all code in this repository, BigchainDB GmbH ("We") either: +Except as noted in the **Exceptions** section below, for all code in this repository, BigchainDB GmbH ("We") either: 1. owns the copyright, or -2. owns the right to sublicense it (because all external contributors must agree to a Contributor License Agreement). -3. The licensing of things in the k8s/nginx-openresty/ directory is described by a separate LICENSE.md file in that directory. +2. owns the right to sublicense it under any license (because all external contributors must agree to a Contributor License Agreement). -Therefore We can choose how to license all the code in this repository. We can license it to Joe Xname under one license and Company Yname under a different license. +Therefore We can choose how to license all the code in this repository (except for the Exceptions). We can license it to Joe Xname under one license and Company Yname under a different license. The two general options are: 1. You can get it under a commercial license for a fee. We can negotiate the terms of that license. It's not like we have some standard take-it-or-leave it commercial license. If you want to modify it and keep your modifications private, then that's certainly possible. Just ask. 2. You can get it under the AGPLv3 license for free. You don't even have to ask us. That's because all code in _this_ repository is licensed under the GNU Affero General Public License version 3 (AGPLv3), the full text of which can be found at [http://www.gnu.org/licenses/agpl.html](http://www.gnu.org/licenses/agpl.html). -If you don't like the AGPL license, then just ignore it. It doesn't affect any other license. +If you don't like the AGPL license, then contact us to get a different license. -All short code snippets embedded in the official BigchainDB _documentation_ are also licensed under the Apache License, Version 2.0, the full text of which can be found at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0). +All short code snippets embedded in the official BigchainDB _documentation_ are licensed under the Apache License, Version 2.0, the full text of which can be found at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0). For the licenses on all other BigchainDB-related code, see the LICENSE file in the associated repository. # Documentation Licenses The official BigchainDB documentation, _except for the short code snippets embedded within it_, is licensed under a Creative Commons Attribution-ShareAlike 4.0 International license, the full text of which can be found at [http://creativecommons.org/licenses/by-sa/4.0/legalcode](http://creativecommons.org/licenses/by-sa/4.0/legalcode). + +# Exceptions + +The contents of the `k8s/nginx-openresty/` directory are licensed as described in the `LICENSE.md` file in that directory. diff --git a/k8s/nginx-openresty/LICENSE.md b/k8s/nginx-openresty/LICENSE.md index ed4710c4..7451bedf 100644 --- a/k8s/nginx-openresty/LICENSE.md +++ b/k8s/nginx-openresty/LICENSE.md @@ -1,9 +1,6 @@ -# Licenses on the Software in This Git Repository +# Licenses on the Stuff in this Directory -This Git repository can be found at -[https://github.com/bigchaindb/nginx_3scale](https://github.com/bigchaindb/nginx_3scale) - -All code in this repository is copyright 2016-2017 BigchainDB GmbH, +All _code_ in this directory is copyright BigchainDB GmbH, except for the configuration files obtained from 3scale (NGINX configuration file and NGINX Lua script). @@ -15,13 +12,13 @@ The original files (from 3scale) were licensed under an MIT License, the text of which can be found below. The derived files (`nginx.conf.template` and `nginx.lua.template`), along with -the other files in this repository, are also licensed under an MIT License, +the other files in this directory, are _also_ licensed under an MIT License, the text of which can be found below. # Documentation Licenses -The documentation is licensed under a Creative Commons Attribution-ShareAlike +The documentation in this directory is licensed under a Creative Commons Attribution-ShareAlike 4.0 International license, the full text of which can be found at [http://creativecommons.org/licenses/by-sa/4.0/legalcode](http://creativecommons.org/licenses/by-sa/4.0/legalcode). From 598d925dd4eee1d43ed193979ffd355111f73f35 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Mon, 25 Sep 2017 16:14:00 +0200 Subject: [PATCH 010/120] Addressing comments - Update README.md to remove old deployment model. - Update version number of nginx_3scale. --- k8s/nginx-openresty/container/README.md | 36 ------------------- .../container/docker_build_and_push.bash | 4 +-- 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/k8s/nginx-openresty/container/README.md b/k8s/nginx-openresty/container/README.md index c75fa206..47b37103 100644 --- a/k8s/nginx-openresty/container/README.md +++ b/k8s/nginx-openresty/container/README.md @@ -58,39 +58,3 @@ reflect any changes made to the container. corresponding private key to the folder `/usr/local/openresty/nginx/conf/ssl/`. Name the pem-encoded certificate as `cert.pem` and the private key as `cert.key`. - - -## Deployment terminology -We currently use the terms `frontend`, `backend`, `upstream` in our code and -configuration. This diagram should help understand the various terms. - -The final goal is to have a deployment that looks like this: - -``` - +------------+ +------------+ - | | | | -+-----------------------------+----+ N | +---------------------+------+ | -| BigchainDB Frontend Port | G | | BigchainDB Backend Port | | -| | I | | | | -|[port number exposed globally | N | +--------> |[port where BDB instance | | -| for backend BDB cluster services]| X | | | listens/waits for requests]| | -+-----------------------------+----+ | | +---------------------+------+ | - | G | | | | -+-----------------------------+----+ A | | | BigchainDB | -| Health Check Port | T | | | Backend | -| | E | | | Host | -| [port number exposed to the LB | W | | +------------+ -| for health checks] | A | | -+-----------------------------+----+ Y | | +------------+ - | | | | MongoDB | - | +--+------------------+-------+ | Backend | -+-----------------------------+----+ | Upstream API Port | | Host | -| MongoDB Frontend Port | | | | | -| | |[internal port where we can | +--------------------+--------+ | -| [port number for MongoDB | |access backend BDB cluster | | MongoDB Backend Port | | -| instances to communicate | +--+--------------------------+ | | | -| with each other +-------+----------------------------->|[port where MongoDB instance | | -+-----------------------------+----+ | | listens/waits for requests] | | - | | +--------------------+--------+ | - +------------+ +------------+ -``` diff --git a/k8s/nginx-openresty/container/docker_build_and_push.bash b/k8s/nginx-openresty/container/docker_build_and_push.bash index 4f02ae19..21d203cc 100755 --- a/k8s/nginx-openresty/container/docker_build_and_push.bash +++ b/k8s/nginx-openresty/container/docker_build_and_push.bash @@ -1,5 +1,5 @@ #!/bin/bash -docker build -t bigchaindb/nginx_3scale:3.0 . +docker build -t bigchaindb/nginx_3scale:3.1 . -docker push bigchaindb/nginx_3scale:3.0 +docker push bigchaindb/nginx_3scale:3.1 From 13379446a757e643185cebd355313efd275dca33 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 26 Sep 2017 10:02:34 +0200 Subject: [PATCH 011/120] Set the date of the v1.1 release in CHANGELOG.md I should have done this in PR #1744 but I forgot. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb4ddb34..7622b2c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ For reference, the possible headings are: * **Notes** -## [1.1] - 2017-09-?????? +## [1.1] - 2017-09-26 Tag name: v1.1.0 ### Added From cdfc0a30586a557ca773697aa7f163dfbbfb9a51 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 26 Sep 2017 10:09:25 +0200 Subject: [PATCH 012/120] Update BDB Docker image version for k8s Part of the BigchainDB release process --- k8s/bigchaindb/bigchaindb-dep.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/k8s/bigchaindb/bigchaindb-dep.yaml b/k8s/bigchaindb/bigchaindb-dep.yaml index 26a47ca2..6c4ca88c 100644 --- a/k8s/bigchaindb/bigchaindb-dep.yaml +++ b/k8s/bigchaindb/bigchaindb-dep.yaml @@ -12,7 +12,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: bigchaindb - image: bigchaindb/bigchaindb:1.0.1 + image: bigchaindb/bigchaindb:1.1.0 imagePullPolicy: IfNotPresent args: - start @@ -158,4 +158,4 @@ spec: - name: ca-auth secret: secretName: ca-auth - defaultMode: 0400 \ No newline at end of file + defaultMode: 0400 From d852209c4eed1fb0fbbfa8e75093ae020f85a08d Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 26 Sep 2017 10:27:05 +0200 Subject: [PATCH 013/120] Updated BDB image version in the k8s YAML of k8s/dev-setup/ --- k8s/dev-setup/bigchaindb.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/dev-setup/bigchaindb.yaml b/k8s/dev-setup/bigchaindb.yaml index 1186738e..e6c39775 100644 --- a/k8s/dev-setup/bigchaindb.yaml +++ b/k8s/dev-setup/bigchaindb.yaml @@ -34,7 +34,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: bigchaindb - image: bigchaindb/bigchaindb:1.0.0 + image: bigchaindb/bigchaindb:1.1.0 imagePullPolicy: Always args: - start From 6648b3473c3958930b537788b0bb921e799120df Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 26 Sep 2017 11:39:47 +0200 Subject: [PATCH 014/120] Update version.py version to 1.2.0.dev for docs --- bigchaindb/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bigchaindb/version.py b/bigchaindb/version.py index e20993d7..7c0b19ea 100644 --- a/bigchaindb/version.py +++ b/bigchaindb/version.py @@ -1,2 +1,2 @@ -__version__ = '1.1.0.dev' -__short_version__ = '1.1.dev' +__version__ = '1.2.0.dev' +__short_version__ = '1.2.dev' From 4371a2ce4b6e76ed322520ef3070074e10dc8591 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Tue, 26 Sep 2017 14:19:55 +0200 Subject: [PATCH 015/120] Update nginx config for well being - turned off server tokens so the server does not leak nginx information on errors and header - Added header to turn off cross site scripting - use stable release of nginx instead of mainline - limit available methods - update response code --- k8s/nginx-http/container/Dockerfile | 2 +- k8s/nginx-http/container/nginx.conf.template | 20 ++++++++++++----- k8s/nginx-https/container/Dockerfile | 2 +- .../container/docker_build_and_push.bash | 4 ++-- k8s/nginx-https/container/nginx.conf.template | 22 ++++++++++++++----- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/k8s/nginx-http/container/Dockerfile b/k8s/nginx-http/container/Dockerfile index c6b0ccd4..e35dd5e0 100644 --- a/k8s/nginx-http/container/Dockerfile +++ b/k8s/nginx-http/container/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.13.1 +FROM nginx:stable LABEL maintainer "dev@bigchaindb.com" WORKDIR / RUN apt-get update \ diff --git a/k8s/nginx-http/container/nginx.conf.template b/k8s/nginx-http/container/nginx.conf.template index 35d121eb..aac1ebba 100644 --- a/k8s/nginx-http/container/nginx.conf.template +++ b/k8s/nginx-http/container/nginx.conf.template @@ -45,6 +45,12 @@ http { keepalive_timeout 60s; + # Do not expose nginx data/version number in error response and header + server_tokens off; + + # To prevent cross-site scripting + add_header X-XSS-Protection "1; mode=block"; + # The following map blocks enable lazy-binding to the backend at runtime, # rather than binding as soon as NGINX starts. map $remote_addr $bdb_backend { @@ -54,7 +60,6 @@ http { # Frontend server for the external clients server { listen CLUSTER_FRONTEND_PORT; - underscores_in_headers on; # Forward websockets to backend BDB at 9985. @@ -75,6 +80,10 @@ http { # max client request body size: avg transaction size. client_max_body_size 15k; + if ($request_method !~ ^(GET|OPTIONS|POST)$) { + return 444; + } + # No auth for GETs, forward directly to BDB. if ($request_method = GET) { proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT; @@ -82,11 +91,10 @@ http { # POST requests get forwarded to OpenResty instance. Enable CORS too. if ($request_method = POST ) { - add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; - + proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT; } @@ -130,10 +138,10 @@ stream { # Enable logging when connections are being throttled. limit_conn_log_level notice; - + # Allow 16 connections from the same IP address. limit_conn two 16; - + # DNS resolver to use for all the backend names specified in this configuration. resolver DNS_SERVER valid=30s ipv6=off; @@ -142,7 +150,7 @@ stream { map $remote_addr $mdb_backend { default MONGODB_BACKEND_HOST; } - + # Frontend server to forward connections to MDB instance. server { listen MONGODB_FRONTEND_PORT so_keepalive=10m:1m:5; diff --git a/k8s/nginx-https/container/Dockerfile b/k8s/nginx-https/container/Dockerfile index 98ec0cfd..3bd6b607 100644 --- a/k8s/nginx-https/container/Dockerfile +++ b/k8s/nginx-https/container/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.13.1 +FROM nginx:stable LABEL maintainer "dev@bigchaindb.com" WORKDIR / RUN apt-get update \ diff --git a/k8s/nginx-https/container/docker_build_and_push.bash b/k8s/nginx-https/container/docker_build_and_push.bash index 3ae71ff9..76494bcb 100755 --- a/k8s/nginx-https/container/docker_build_and_push.bash +++ b/k8s/nginx-https/container/docker_build_and_push.bash @@ -1,5 +1,5 @@ #!/bin/bash -docker build -t bigchaindb/nginx_https:1.0 . +docker build -t bigchaindb/nginx_https:1.1 . -docker push bigchaindb/nginx_https:1.0 +docker push bigchaindb/nginx_https:1.1 diff --git a/k8s/nginx-https/container/nginx.conf.template b/k8s/nginx-https/container/nginx.conf.template index 8a85c894..90e271a4 100644 --- a/k8s/nginx-https/container/nginx.conf.template +++ b/k8s/nginx-https/container/nginx.conf.template @@ -42,6 +42,12 @@ http { client_body_timeout 10s; client_header_timeout 10s; + # Do not expose nginx data/version number in error response and header + server_tokens off; + + # To prevent cross-site scripting + add_header X-XSS-Protection "1; mode=block"; + # DNS resolver to use for all the backend names specified in this configuration. resolver DNS_SERVER valid=30s ipv6=off; @@ -59,11 +65,13 @@ http { # Frontend server for the external clients; acts as HTTPS termination point. server { listen CLUSTER_FRONTEND_PORT ssl; + add_header X-XSS-Protection "1; mode=block"; server_name "CLUSTER_FQDN"; - ssl_certificate /etc/nginx/ssl/cert.pem; - ssl_certificate_key /etc/nginx/ssl/cert.key; - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers HIGH:!aNULL:!MD5; + + ssl_certificate /etc/nginx/ssl/cert.pem; + ssl_certificate_key /etc/nginx/ssl/cert.key; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers HIGH:!aNULL:!MD5; underscores_in_headers on; @@ -89,6 +97,10 @@ http { # max client request body size: avg transaction size. client_max_body_size 15k; + if ($request_method !~ ^(GET|OPTIONS|POST)$) { + return 444; + } + # No auth for GETs, forward directly to BDB. if ($request_method = GET) { proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT; @@ -135,7 +147,7 @@ http { location / { add_header Upgrade "TLS/1.2, HTTP/1.1" always; default_type text/plain; - return 426 'Consider using the HTTPS protocol next time!'; + return 301 'Consider using the HTTPS protocol next time!'; } } } From dbddc7c85cb9dad08d2f6a008e8bfbeb716075f0 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Tue, 26 Sep 2017 15:31:37 +0200 Subject: [PATCH 016/120] Addressing comments --- k8s/nginx-http/container/docker_build_and_push.bash | 4 ++-- k8s/nginx-http/container/nginx.conf.template | 10 ++++++---- k8s/nginx-https/container/nginx.conf.template | 11 ++++++----- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/k8s/nginx-http/container/docker_build_and_push.bash b/k8s/nginx-http/container/docker_build_and_push.bash index d4b70555..5011eb2d 100755 --- a/k8s/nginx-http/container/docker_build_and_push.bash +++ b/k8s/nginx-http/container/docker_build_and_push.bash @@ -1,5 +1,5 @@ #!/bin/bash -docker build -t bigchaindb/nginx_http:1.0 . +docker build -t bigchaindb/nginx_http:1.1 . -docker push bigchaindb/nginx_http:1.0 +docker push bigchaindb/nginx_http:1.1 diff --git a/k8s/nginx-http/container/nginx.conf.template b/k8s/nginx-http/container/nginx.conf.template index aac1ebba..bc8b8245 100644 --- a/k8s/nginx-http/container/nginx.conf.template +++ b/k8s/nginx-http/container/nginx.conf.template @@ -80,10 +80,6 @@ http { # max client request body size: avg transaction size. client_max_body_size 15k; - if ($request_method !~ ^(GET|OPTIONS|POST)$) { - return 444; - } - # No auth for GETs, forward directly to BDB. if ($request_method = GET) { proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT; @@ -91,6 +87,7 @@ http { # POST requests get forwarded to OpenResty instance. Enable CORS too. if ($request_method = POST ) { + add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; @@ -108,6 +105,11 @@ http { add_header 'Content-Length' 0; return 204; } + + # Only return this reponse if request_method is neither POST|GET|OPTIONS + if ($request_method !~ ^(GET|OPTIONS|POST)$) { + return 444; + } } } diff --git a/k8s/nginx-https/container/nginx.conf.template b/k8s/nginx-https/container/nginx.conf.template index 90e271a4..50257205 100644 --- a/k8s/nginx-https/container/nginx.conf.template +++ b/k8s/nginx-https/container/nginx.conf.template @@ -97,10 +97,6 @@ http { # max client request body size: avg transaction size. client_max_body_size 15k; - if ($request_method !~ ^(GET|OPTIONS|POST)$) { - return 444; - } - # No auth for GETs, forward directly to BDB. if ($request_method = GET) { proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT; @@ -126,6 +122,11 @@ http { add_header 'Content-Length' 0; return 204; } + + # Only return this reponse if request_method is neither POST|GET|OPTIONS + if ($request_method !~ ^(GET|OPTIONS|POST)$) { + return 444; + } } } @@ -147,7 +148,7 @@ http { location / { add_header Upgrade "TLS/1.2, HTTP/1.1" always; default_type text/plain; - return 301 'Consider using the HTTPS protocol next time!'; + return 426 'Consider using the HTTPS protocol next time!'; } } } From 9ab6785920c30fdbffa27f8be20dd4273552ca45 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Tue, 26 Sep 2017 16:01:14 +0200 Subject: [PATCH 017/120] Some more comments --- k8s/nginx-https/container/nginx.conf.template | 1 - 1 file changed, 1 deletion(-) diff --git a/k8s/nginx-https/container/nginx.conf.template b/k8s/nginx-https/container/nginx.conf.template index 50257205..3ffb4cce 100644 --- a/k8s/nginx-https/container/nginx.conf.template +++ b/k8s/nginx-https/container/nginx.conf.template @@ -65,7 +65,6 @@ http { # Frontend server for the external clients; acts as HTTPS termination point. server { listen CLUSTER_FRONTEND_PORT ssl; - add_header X-XSS-Protection "1; mode=block"; server_name "CLUSTER_FQDN"; ssl_certificate /etc/nginx/ssl/cert.pem; From 93ab1bc38a87e3119396173e2e4f16e4f0734ec5 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Tue, 26 Sep 2017 17:08:15 +0200 Subject: [PATCH 018/120] Add template for issue reporting for BigchainDB and IPDB --- .github/issue_template.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/issue_template.md diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 00000000..743d00cd --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,25 @@ +* BigchainDB version: +* Operating System: +* Deployment Type: `[Docker|Host|IPDB|Other]` + * If you are using IPDB, please specify your network type `[test, prod]` + and the `bdb_url(BigchainDB URL)` you are using. + * For every other type of deployment, please specify the documentation/instructions + you are following. +* BigchainDB driver: `[yes|no]` + * If using a driver please specify, driver type `[python|js|java]` + and version. + +### Description + +Describe what you were trying to get done. +Tell us what happened, what went wrong, and what you expected to happen. + +### Steps to Reproduce +If you have the precise steps to reproduce, please specify. If you can reproduce +ocassionaly, please provide addition information e.g. screenshots, commands, logs etc. + +### What I Did + +``` +Paste the command(s) you ran and the output. +If there was a crash, please include the traceback/error message here. \ No newline at end of file From 94fb27be6cc185bad7a742269ff170b795b04220 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Tue, 26 Sep 2017 17:24:18 +0200 Subject: [PATCH 019/120] Fix typos --- .github/issue_template.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/issue_template.md b/.github/issue_template.md index 743d00cd..1446da07 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -16,10 +16,11 @@ Tell us what happened, what went wrong, and what you expected to happen. ### Steps to Reproduce If you have the precise steps to reproduce, please specify. If you can reproduce -ocassionaly, please provide addition information e.g. screenshots, commands, logs etc. +ocassionally, please provide additional information; e.g. screenshots, commands, logs, etc. ### What I Did ``` Paste the command(s) you ran and the output. -If there was a crash, please include the traceback/error message here. \ No newline at end of file +If there was a crash, please include the traceback/error message here. +``` \ No newline at end of file From 99156e6a4cfab5f2ab4338d5d86bc14eaa902123 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Wed, 27 Sep 2017 13:50:20 +0200 Subject: [PATCH 020/120] Minor revisions to RELEASE_PROCESS.md following the release of v1.1 --- RELEASE_PROCESS.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/RELEASE_PROCESS.md b/RELEASE_PROCESS.md index ad54f164..776eecba 100644 --- a/RELEASE_PROCESS.md +++ b/RELEASE_PROCESS.md @@ -16,13 +16,13 @@ except release candidates are labelled like A minor release is preceeded by a feature freeze and created from the 'master' branch. This is a summary of the steps we go through to release a new minor version of BigchainDB Server. 1. Update the `CHANGELOG.md` file in master -1. In `k8s/bigchaindb/bigchaindb-dep.yaml`, find the line of the form `image: bigchaindb/bigchaindb:0.8.1` and change the version number to the new version number, e.g. `0.9.0`. (This is the Docker image that Kubernetes should pull from Docker Hub.) Commit that change to master +1. In `k8s/bigchaindb/bigchaindb-dep.yaml` AND in `k8s/dev-setup/bigchaindb.yaml`, find the line of the form `image: bigchaindb/bigchaindb:0.8.1` and change the version number to the new version number, e.g. `0.9.0`. (This is the Docker image that Kubernetes should pull from Docker Hub.) Commit that change to master 1. Create and checkout a new branch for the minor release, named after the minor version, without a preceeding 'v', e.g. `git checkout -b 0.9` (*not* 0.9.0, this new branch will be for e.g. 0.9.0, 0.9.1, 0.9.2, etc. each of which will be identified by a tagged commit) 1. Push the new branch to GitHub, e.g. `git push origin 0.9` 1. Create and checkout a new branch off of the 0.9 branch. Let's call it branch T for now 1. In `bigchaindb/version.py`, update `__version__` and `__short_version__`, e.g. to `0.9` and `0.9.0` (with no `.dev` on the end) 1. Commit those changes, push the new branch T to GitHub, and use the pushed branch T to create a new pull request merging the T branch into the 0.9 branch. -1. Wait for all the tests to pass! +1. Wait for all the tests to pass! Then merge T into 0.9. 1. Follow steps outlined in [Common Steps](#common-steps) 1. In 'master' branch, Edit `bigchaindb/version.py`, increment the minor version to the next planned release, e.g. `0.10.0.dev`. (Exception: If you just released `X.Y.Zrc1` then increment the minor version to `X.Y.Zrc2`.) This step is so people reading the latest docs will know that they're for the latest (master branch) version of BigchainDB Server, not the docs at the time of the most recent release (which are also available). 1. Go to [Docker Hub](https://hub.docker.com/), sign in, go to bigchaindb/bigchaindb, go to Settings - Build Settings, and under the build with Docker Tag Name equal to `latest`, change the Name to the number of the new release, e.g. `0.9` @@ -38,7 +38,7 @@ A patch release is similar to a minor release, but piggybacks on an existing min 1. Update the `CHANGELOG.md` file 1. Increment the patch version in `bigchaindb/version.py`, e.g. `0.9.1` 1. Commit that change -1. In `k8s/bigchaindb/bigchaindb-dep.yaml`, find the line of the form `image: bigchaindb/bigchaindb:0.9.0` and change the version number to the new version number, e.g. `0.9.1`. (This is the Docker image that Kubernetes should pull from Docker Hub.) +1. In `k8s/bigchaindb/bigchaindb-dep.yaml` AND in `k8s/dev-setup/bigchaindb.yaml`, find the line of the form `image: bigchaindb/bigchaindb:0.9.0` and change the version number to the new version number, e.g. `0.9.1`. (This is the Docker image that Kubernetes should pull from Docker Hub.) 1. Commit that change 1. Push the updated minor release branch to GitHub 1. Follow steps outlined in [Common Steps](#common-steps) @@ -59,8 +59,7 @@ These steps are common between minor and patch releases: 1. Make sure your local Git is in the same state as the release: e.g. `git fetch ` and `git checkout v0.9.1` 1. Make sure you have a `~/.pypirc` file containing credentials for PyPI 1. Do a `make release` to build and publish the new `bigchaindb` package on PyPI -1. [Login to readthedocs.org](https://readthedocs.org/accounts/login/) - as a maintainer of the BigchainDB Server docs, and: +1. [Login to readthedocs.org](https://readthedocs.org/accounts/login/) and go to the **BigchainDB Server** project (*not* **BigchainDB**), then: - Go to Admin --> Advanced Settings and make sure that "Default branch:" (i.e. what "latest" points to) is set to the new release's tag, e.g. `v0.9.1`. From 7abdca205a2d71d0684ad7b1c27b3527466b9394 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Mon, 25 Sep 2017 16:44:39 +0200 Subject: [PATCH 021/120] Adjust resource for MongoDB Stateful Set - Currently, MongoDB container crashed because of resource constaints i.e. out of memory exception. This change updates the resources and provides data on how the configure/calculate them(if not following the guide). - Also, add the ability to specify the storage engine(WiredTiger) cache size for MongoDB, this configuration also helps with keeping the resources constrained for MongoDB containers. - Minor changes in some other documents as well. --- .../client-tls-certificate.rst | 2 +- .../node-on-kubernetes.rst | 13 +++++++++++++ .../container/docker_build_and_push.bash | 4 ++-- k8s/mongodb/container/mongod.conf.template | 2 +- k8s/mongodb/container/mongod_entrypoint.bash | 18 +++++++++++++++++- k8s/mongodb/mongo-ss.yaml | 8 +++++++- 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/docs/server/source/production-deployment-template/client-tls-certificate.rst b/docs/server/source/production-deployment-template/client-tls-certificate.rst index 80483b83..d0a67006 100644 --- a/docs/server/source/production-deployment-template/client-tls-certificate.rst +++ b/docs/server/source/production-deployment-template/client-tls-certificate.rst @@ -92,7 +92,7 @@ consolidated file containing both the public and private keys. .. code:: bash - cat /path/to/mdb-instance-0.crt /path/to/mdb-instance-0.key > mdb-instance-0.pem + cat /path/to/bdb-instance-0.crt /path/to/bdb-instance-0.key > bdb-instance-0.pem OR diff --git a/docs/server/source/production-deployment-template/node-on-kubernetes.rst b/docs/server/source/production-deployment-template/node-on-kubernetes.rst index c9272b6e..fc774f3d 100644 --- a/docs/server/source/production-deployment-template/node-on-kubernetes.rst +++ b/docs/server/source/production-deployment-template/node-on-kubernetes.rst @@ -542,6 +542,19 @@ Step 12: Start a Kubernetes StatefulSet for MongoDB - ``mdb-certs`` - ``ca-auth`` + * **Optional**: You can also change the value for ``STORAGE_ENGINE_CACHE_SIZE``, for more information + regarding this configuration, please consult the `MongoDB Official + Documentation `_. + + * **Optional**: If you are not using the **Standard_D2_v2** virtual machines for Kubernetes agents as per the guide, + please update the ``resources`` for ``mongo-ss``. We suggest allocating ``memory`` using the following scheme + for a MongoDB StatefulSet: + + .. code:: bash + + memory = (Total_Memory_Agent_VM_GB - 2GB) + STORAGE_ENGINE_CACHE_SIZE = memory / 2 + * Create the MongoDB StatefulSet using: .. code:: bash diff --git a/k8s/mongodb/container/docker_build_and_push.bash b/k8s/mongodb/container/docker_build_and_push.bash index ce861040..680fab22 100755 --- a/k8s/mongodb/container/docker_build_and_push.bash +++ b/k8s/mongodb/container/docker_build_and_push.bash @@ -1,5 +1,5 @@ #!/bin/bash -docker build -t bigchaindb/mongodb:3.1 . +docker build -t bigchaindb/mongodb:3.2 . -docker push bigchaindb/mongodb:3.1 +docker push bigchaindb/mongodb:3.2 diff --git a/k8s/mongodb/container/mongod.conf.template b/k8s/mongodb/container/mongod.conf.template index 2ad36344..d8ae1bce 100644 --- a/k8s/mongodb/container/mongod.conf.template +++ b/k8s/mongodb/container/mongod.conf.template @@ -86,6 +86,7 @@ storage: wiredTiger: engineConfig: journalCompressor: snappy + configString: cache_size=STORAGE_ENGINE_CACHE_SIZE collectionConfig: blockCompressor: snappy indexConfig: @@ -98,4 +99,3 @@ operationProfiling: replication: replSetName: REPLICA_SET_NAME enableMajorityReadConcern: true - diff --git a/k8s/mongodb/container/mongod_entrypoint.bash b/k8s/mongodb/container/mongod_entrypoint.bash index c9f7b027..3eb18979 100755 --- a/k8s/mongodb/container/mongod_entrypoint.bash +++ b/k8s/mongodb/container/mongod_entrypoint.bash @@ -46,6 +46,10 @@ while [[ $# -gt 1 ]]; do MONGODB_IP="$2" shift ;; + --storage-engine-cache-size) + STORAGE_ENGINE_CACHE_SIZE="$2" + shift + ;; *) echo "Unknown option: $1" exit 1 @@ -61,7 +65,8 @@ if [[ -z "${REPLICA_SET_NAME:?REPLICA_SET_NAME not specified. Exiting!}" || \ -z "${MONGODB_IP:?MONGODB_IP not specified. Exiting!}" || \ -z "${MONGODB_KEY_FILE_PATH:?MONGODB_KEY_FILE_PATH not specified. Exiting!}" || \ -z "${MONGODB_CA_FILE_PATH:?MONGODB_CA_FILE_PATH not specified. Exiting!}" || \ - -z "${MONGODB_CRL_FILE_PATH:?MONGODB_CRL_FILE_PATH not specified. Exiting!}" ]] ; then + -z "${MONGODB_CRL_FILE_PATH:?MONGODB_CRL_FILE_PATH not specified. Exiting!}" || + -z "${STORAGE_ENGINE_CACHE_SIZE:=''}" ]] ; then #-z "${MONGODB_KEY_FILE_PASSWORD:?MongoDB Key File Password not specified. Exiting!}" || \ exit 1 else @@ -72,6 +77,7 @@ else echo MONGODB_KEY_FILE_PATH="$MONGODB_KEY_FILE_PATH" echo MONGODB_CA_FILE_PATH="$MONGODB_CA_FILE_PATH" echo MONGODB_CRL_FILE_PATH="$MONGODB_CRL_FILE_PATH" + echo STORAGE_ENGINE_CACHE_SIZE="$STORAGE_ENGINE_CACHE_SIZE" fi MONGODB_CONF_FILE_PATH=/etc/mongod.conf @@ -84,6 +90,16 @@ sed -i "s|MONGODB_KEY_FILE_PATH|${MONGODB_KEY_FILE_PATH}|g" ${MONGODB_CONF_FILE_ sed -i "s|MONGODB_CA_FILE_PATH|${MONGODB_CA_FILE_PATH}|g" ${MONGODB_CONF_FILE_PATH} sed -i "s|MONGODB_CRL_FILE_PATH|${MONGODB_CRL_FILE_PATH}|g" ${MONGODB_CONF_FILE_PATH} sed -i "s|REPLICA_SET_NAME|${REPLICA_SET_NAME}|g" ${MONGODB_CONF_FILE_PATH} +if [ ! -z "$STORAGE_ENGINE_CACHE_SIZE" ]; then + if [[ "$STORAGE_ENGINE_CACHE_SIZE" =~ ^[0-9]+\.?(G|M|T)B$ ]]; then + sed -i.bk "s|STORAGE_ENGINE_CACHE_SIZE|${STORAGE_ENGINE_CACHE_SIZE}|g" ${MONGODB_CONF_FILE_PATH} + else + echo "Invalid Value for storage engine cache size $STORAGE_ENGINE_CACHE_SIZE" + exit 1 + fi +else + sed -i.bk "/cacheSizeGB/d" ${MONGODB_CONF_FILE_PATH} +fi # add the hostname and ip to hosts file echo "${MONGODB_IP} ${MONGODB_FQDN}" >> $HOSTS_FILE_PATH diff --git a/k8s/mongodb/mongo-ss.yaml b/k8s/mongodb/mongo-ss.yaml index 4bc3cfa2..8c9c2739 100644 --- a/k8s/mongodb/mongo-ss.yaml +++ b/k8s/mongodb/mongo-ss.yaml @@ -43,6 +43,10 @@ spec: configMapKeyRef: name: vars key: mongodb-backend-port + # Optional: Optimize storage engine(wired tiger) + # cache size. e.g. (2048MB, 2GB, 1TB) + - name: STORAGE_ENGINE_CACHE_SIZE + value: "" args: - --mongodb-port - $(MONGODB_PORT) @@ -58,6 +62,8 @@ spec: - $(MONGODB_FQDN) - --mongodb-ip - $(MONGODB_POD_IP) + - --storage-engine-cache-size + - $(STORAGE_ENGINE_CACHE_SIZE) securityContext: capabilities: add: @@ -80,7 +86,7 @@ spec: resources: limits: cpu: 200m - memory: 3.5G + memory: 5G livenessProbe: tcpSocket: port: mdb-api-port From 8b1fd605e2f335e356051faa39a5c069d7348736 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Mon, 25 Sep 2017 17:44:35 +0200 Subject: [PATCH 022/120] Address some bugs - Pushed the wrong codebase in the previous commit --- k8s/mongodb/container/mongod_entrypoint.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/k8s/mongodb/container/mongod_entrypoint.bash b/k8s/mongodb/container/mongod_entrypoint.bash index 3eb18979..213f9989 100755 --- a/k8s/mongodb/container/mongod_entrypoint.bash +++ b/k8s/mongodb/container/mongod_entrypoint.bash @@ -65,7 +65,7 @@ if [[ -z "${REPLICA_SET_NAME:?REPLICA_SET_NAME not specified. Exiting!}" || \ -z "${MONGODB_IP:?MONGODB_IP not specified. Exiting!}" || \ -z "${MONGODB_KEY_FILE_PATH:?MONGODB_KEY_FILE_PATH not specified. Exiting!}" || \ -z "${MONGODB_CA_FILE_PATH:?MONGODB_CA_FILE_PATH not specified. Exiting!}" || \ - -z "${MONGODB_CRL_FILE_PATH:?MONGODB_CRL_FILE_PATH not specified. Exiting!}" || + -z "${MONGODB_CRL_FILE_PATH:?MONGODB_CRL_FILE_PATH not specified. Exiting!}" || \ -z "${STORAGE_ENGINE_CACHE_SIZE:=''}" ]] ; then #-z "${MONGODB_KEY_FILE_PASSWORD:?MongoDB Key File Password not specified. Exiting!}" || \ exit 1 @@ -91,14 +91,14 @@ sed -i "s|MONGODB_CA_FILE_PATH|${MONGODB_CA_FILE_PATH}|g" ${MONGODB_CONF_FILE_PA sed -i "s|MONGODB_CRL_FILE_PATH|${MONGODB_CRL_FILE_PATH}|g" ${MONGODB_CONF_FILE_PATH} sed -i "s|REPLICA_SET_NAME|${REPLICA_SET_NAME}|g" ${MONGODB_CONF_FILE_PATH} if [ ! -z "$STORAGE_ENGINE_CACHE_SIZE" ]; then - if [[ "$STORAGE_ENGINE_CACHE_SIZE" =~ ^[0-9]+\.?(G|M|T)B$ ]]; then + if [[ "$STORAGE_ENGINE_CACHE_SIZE" =~ ^[0-9]+(G|M|T)B$ ]]; then sed -i.bk "s|STORAGE_ENGINE_CACHE_SIZE|${STORAGE_ENGINE_CACHE_SIZE}|g" ${MONGODB_CONF_FILE_PATH} else echo "Invalid Value for storage engine cache size $STORAGE_ENGINE_CACHE_SIZE" exit 1 fi else - sed -i.bk "/cacheSizeGB/d" ${MONGODB_CONF_FILE_PATH} + sed -i.bk "/cache_size=/d" ${MONGODB_CONF_FILE_PATH} fi # add the hostname and ip to hosts file From 1e53f13be39024c9bc7b9d7a156818343b630c95 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Wed, 27 Sep 2017 14:40:12 +0200 Subject: [PATCH 023/120] Use config map for storage engine cache size --- .../production-deployment-template/node-on-kubernetes.rst | 2 +- k8s/configuration/config-map.yaml | 5 +++++ k8s/mongodb/mongo-ss.yaml | 7 ++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/server/source/production-deployment-template/node-on-kubernetes.rst b/docs/server/source/production-deployment-template/node-on-kubernetes.rst index fc774f3d..d9b1437b 100644 --- a/docs/server/source/production-deployment-template/node-on-kubernetes.rst +++ b/docs/server/source/production-deployment-template/node-on-kubernetes.rst @@ -542,7 +542,7 @@ Step 12: Start a Kubernetes StatefulSet for MongoDB - ``mdb-certs`` - ``ca-auth`` - * **Optional**: You can also change the value for ``STORAGE_ENGINE_CACHE_SIZE``, for more information + * **Optional**: You can change the value for ``STORAGE_ENGINE_CACHE_SIZE`` in the ConfigMap ``storage-engine-cache-size``, for more information regarding this configuration, please consult the `MongoDB Official Documentation `_. diff --git a/k8s/configuration/config-map.yaml b/k8s/configuration/config-map.yaml index 8c30565f..fafe365c 100644 --- a/k8s/configuration/config-map.yaml +++ b/k8s/configuration/config-map.yaml @@ -99,6 +99,11 @@ data: # WebSocket API in BigchainDB; can be 'ws' or 'wss' (default). bigchaindb-wsserver-advertised-scheme: "wss" + # Optional: Optimize storage engine(wired tiger) + # cache size. e.g. (2048MB, 2GB, 1TB), otherwise + # it will use the default cache size; i.e. max((50% RAM - 1GB), 256MB) + storage-engine-cache-size: "" + --- apiVersion: v1 kind: ConfigMap diff --git a/k8s/mongodb/mongo-ss.yaml b/k8s/mongodb/mongo-ss.yaml index 8c9c2739..358587bf 100644 --- a/k8s/mongodb/mongo-ss.yaml +++ b/k8s/mongodb/mongo-ss.yaml @@ -43,10 +43,11 @@ spec: configMapKeyRef: name: vars key: mongodb-backend-port - # Optional: Optimize storage engine(wired tiger) - # cache size. e.g. (2048MB, 2GB, 1TB) - name: STORAGE_ENGINE_CACHE_SIZE - value: "" + valueFrom: + configMapKeyRef: + name: vars + key: storage-engine-cache-size args: - --mongodb-port - $(MONGODB_PORT) From 3d2daa3119ba2745e3c30b27f6641a64b393b09b Mon Sep 17 00:00:00 2001 From: muawiakh Date: Thu, 28 Sep 2017 10:40:05 +0200 Subject: [PATCH 024/120] Update nginx-http(s) and mongodb deployments files to use latest versions --- k8s/mongodb/mongo-ss.yaml | 2 +- k8s/nginx-http/nginx-http-dep.yaml | 2 +- k8s/nginx-https/nginx-https-dep.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/k8s/mongodb/mongo-ss.yaml b/k8s/mongodb/mongo-ss.yaml index 358587bf..1243da26 100644 --- a/k8s/mongodb/mongo-ss.yaml +++ b/k8s/mongodb/mongo-ss.yaml @@ -21,7 +21,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: mongodb - image: bigchaindb/mongodb:3.1 + image: bigchaindb/mongodb:3.2 imagePullPolicy: IfNotPresent env: - name: MONGODB_FQDN diff --git a/k8s/nginx-http/nginx-http-dep.yaml b/k8s/nginx-http/nginx-http-dep.yaml index ad97bcdf..5a9359f5 100644 --- a/k8s/nginx-http/nginx-http-dep.yaml +++ b/k8s/nginx-http/nginx-http-dep.yaml @@ -12,7 +12,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: nginx - image: bigchaindb/nginx_http:1.0 + image: bigchaindb/nginx_http:1.1 imagePullPolicy: IfNotPresent env: - name: CLUSTER_FRONTEND_PORT diff --git a/k8s/nginx-https/nginx-https-dep.yaml b/k8s/nginx-https/nginx-https-dep.yaml index 57218424..79dfe040 100644 --- a/k8s/nginx-https/nginx-https-dep.yaml +++ b/k8s/nginx-https/nginx-https-dep.yaml @@ -12,7 +12,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: nginx - image: bigchaindb/nginx_https:1.0 + image: bigchaindb/nginx_https:1.1 imagePullPolicy: IfNotPresent env: - name: CLUSTER_FRONTEND_PORT From 99f599688158c142e24c98170ac8a74cba775524 Mon Sep 17 00:00:00 2001 From: "krish7919 (Krish)" Date: Thu, 28 Sep 2017 13:58:08 +0200 Subject: [PATCH 025/120] Sanity check for input values --- .../container/nginx_openresty_entrypoint.bash | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/k8s/nginx-openresty/container/nginx_openresty_entrypoint.bash b/k8s/nginx-openresty/container/nginx_openresty_entrypoint.bash index baad9a47..9a50fc20 100755 --- a/k8s/nginx-openresty/container/nginx_openresty_entrypoint.bash +++ b/k8s/nginx-openresty/container/nginx_openresty_entrypoint.bash @@ -21,15 +21,14 @@ threescale_version_header=`cat ${THREESCALE_CREDENTIALS_DIR}/version-header` threescale_service_token=`cat ${THREESCALE_CREDENTIALS_DIR}/service-token` -# sanity checks TODO(Krish): hardening -if [[ -z "${dns_server}" || \ - -z "${openresty_frontend_port}" || \ - -z "${bdb_backend_host}" || \ - -z "${bdb_api_port}" || \ - -z "${threescale_secret_token}" || \ - -z "${threescale_service_id}" || \ - -z "${threescale_version_header}" || \ - -z "${threescale_service_token}" ]]; then +if [[ -z "${dns_server:?DNS_SERVER not specified. Exiting!}" || \ + -z "${openresty_frontend_port:?OPENRESTY_FRONTEND_PORT not specified. Exiting!}" || \ + -z "${bdb_backend_host:?BIGCHAINDB_BACKEND_HOST not specified. Exiting!}" || \ + -z "${bdb_api_port:?BIGCHAINDB_API_PORT not specified. Exiting!}" || \ + -z "${threescale_secret_token:?3scale secret token not specified. Exiting!}" || \ + -z "${threescale_service_id:?3scale service id not specified. Exiting!}" || \ + -z "${threescale_version_header:?3scale version header not specified. Exiting!}" || \ + -z "${threescale_service_token:?3scale service token not specified. Exiting!}" ]]; then echo "Invalid environment settings detected. Exiting!" exit 1 fi From 4ee5b4cfbcde61ab592ccc6bd48bc6dd6cfe948d Mon Sep 17 00:00:00 2001 From: "krish7919 (Krish)" Date: Thu, 28 Sep 2017 13:45:03 +0200 Subject: [PATCH 026/120] Bugfix in nginx-openresty Dockerfile --- k8s/nginx-openresty/container/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/nginx-openresty/container/Dockerfile b/k8s/nginx-openresty/container/Dockerfile index 8e5b7e2e..da3bfc40 100644 --- a/k8s/nginx-openresty/container/Dockerfile +++ b/k8s/nginx-openresty/container/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get update \ && apt-get clean COPY nginx.conf.template /usr/local/openresty/nginx/conf/nginx.conf COPY nginx.lua.template /usr/local/openresty/nginx/conf/nginx.lua -COPY nginx_entrypoint.bash / +COPY nginx_openresty_entrypoint.bash / # The following ports are the values we use to run the NGINX+3scale container. # 80 for http, 8080 for the 3scale api, 8888 for health-check, 27017 for # MongoDB From 1761e94840541acc263126a53cf06fb298e3821f Mon Sep 17 00:00:00 2001 From: "krish7919 (Krish)" Date: Mon, 25 Sep 2017 17:31:22 +0200 Subject: [PATCH 027/120] Adding high level arch description --- docs/server/source/_static/arch.svg | 2 + .../architecture.rst | 69 +++++++++++++++++++ .../production-deployment-template/index.rst | 1 + 3 files changed, 72 insertions(+) create mode 100644 docs/server/source/_static/arch.svg create mode 100644 docs/server/source/production-deployment-template/architecture.rst diff --git a/docs/server/source/_static/arch.svg b/docs/server/source/_static/arch.svg new file mode 100644 index 00000000..0f0655a0 --- /dev/null +++ b/docs/server/source/_static/arch.svg @@ -0,0 +1,2 @@ + +
NGINX Service
NGINX Service
NGINX Deployment
NGINX Deployment
Rate
Limiting
Logic
[Not supported by viewer]
HTTPs
Termination

[Not supported by viewer]
Analyze
Request
[Not supported by viewer]
443
443
OpenResty
Service
[Not supported by viewer]
OpenResty
Deployment
[Not supported by viewer]
POST
POST
Auth
Logic
[Not supported by viewer]
3Scale
3Scale
BigchainDB
Service
[Not supported by viewer]
BigchainDB
Deployment
[Not supported by viewer]
GET
GET
Rate
Limiting
Logic
[Not supported by viewer]
27017
27017
MongoDB
Service
[Not supported by viewer]
MongoDB
StatefulSet
[Not supported by viewer]
MongoDB Monitoring
Agent
Deployment
[Not supported by viewer]
MongoDB
backup
Agent
Deployment
[Not supported by viewer]
MongoDB
Cloud
Manager
[Not supported by viewer]
BigchainDB API
BigchainDB API
MongoDB Cluster
Communication
MongoDB Cluster<div>Communication</div>
IPDB Node
IPDB Node
\ No newline at end of file diff --git a/docs/server/source/production-deployment-template/architecture.rst b/docs/server/source/production-deployment-template/architecture.rst new file mode 100644 index 00000000..62b850fd --- /dev/null +++ b/docs/server/source/production-deployment-template/architecture.rst @@ -0,0 +1,69 @@ +Architecture of an IPDB Node +============================ + +An IPDB Production deployment is hosted on a Kubernetes cluster and includes: + +* NGINX, OpenResty, BigchainDB and MongoDB + `Kubernetes Services `_. +* NGINX, OpenResty, BigchainDB, Monitoring Agent and Backup Agent + `Kubernetes Deployments `_. +* MongoDB `Kubernetes StatefulSet `_. +* External systems like `3scale `_, + `MongoDB Cloud Manager `_ and the + `Azure Operations Management Suite + `_. + +.. image:: ../_static/arch.svg + + +We describe the role of each of these modules here. + +NGINX +----- + +We use an NGINX as HTTP proxy on port 443 at the cloud entrypoint for: + +#. Rate Limiting: We configure NGINX to allow only a certain number of requests + (configurable) which prevents DoS attacks. + +#. HTTPS Termination: The HTTPS connection does not carry through all the way + to BigchainDB and terminates at NGINX for now. + +#. Request Routing: For HTTPS connections on port 443 (or the configured BigchainDB public api port), + the connection is proxied to: + + #. OpenResty Service if it is a POST request. + #. BigchainDB Service if it is a GET request. + + +We use an NGINX TCP proxy on port 27017 at the cloud entrypoint for: + +#. Rate Limiting: We configure NGINX to allow only a certain number of requests + (configurable) which prevents DoS attacks. + +#. Request Routing: For connections on port 27017 (or the configured MongoDB + public api port), the connection is proxied to the MongoDB Service. + + +OpenResty +--------- + +We use `OpenResty `_ to perform authorization checks +with 3scale using the ``app_id`` and ``app_key`` headers in the HTTP request. + +OpenResty is NGINX plus a bunch of other +`components `_. We primarily depend +on the LuaJIT compiler to execute the functions to authenticate the ``app_id`` +and ``app_key`` with the 3scale backend. + + +MongoDB +------- + +We use MongoDB as the backend database for BigchainDB. +In a multi-node deployment, MongoDB members communicate with each other via the +public port exposed by the NGINX Service. + +We achieve security by avoiding DoS attacks at the NGINX proxy layer and by +ensuring that MongoDB has TLS enabled for all its connections. + diff --git a/docs/server/source/production-deployment-template/index.rst b/docs/server/source/production-deployment-template/index.rst index 8852dd2c..9dbb4f11 100644 --- a/docs/server/source/production-deployment-template/index.rst +++ b/docs/server/source/production-deployment-template/index.rst @@ -28,3 +28,4 @@ Feel free change things to suit your needs or preferences. add-node-on-kubernetes restore-from-mongodb-cloud-manager tectonic-azure + architecture From cebea3e1b8b984c6dbfa13dfaa0bc09fed5b8d7a Mon Sep 17 00:00:00 2001 From: "krish7919 (Krish)" Date: Tue, 26 Sep 2017 12:16:34 +0200 Subject: [PATCH 028/120] Update image and address comments --- docs/server/source/_static/arch.jpg | Bin 0 -> 53244 bytes docs/server/source/_static/arch.svg | 2 -- .../architecture.rst | 11 ++++++----- 3 files changed, 6 insertions(+), 7 deletions(-) create mode 100644 docs/server/source/_static/arch.jpg delete mode 100644 docs/server/source/_static/arch.svg diff --git a/docs/server/source/_static/arch.jpg b/docs/server/source/_static/arch.jpg new file mode 100644 index 0000000000000000000000000000000000000000..570d63c14af15db0cd9dff5e3e4f09cad28f1d5b GIT binary patch literal 53244 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

~^7&+RSnR-YXMJnXKZ0JJ2<(=|3ing#PU>yz*gp zGw~rS#KBU_JVr+8!W&X0j5d}!N3KwxUWG3m-$vB9LURzq4hLo4lK1I8j&5{p-;#MzJui{t>4nn*Qz`cp>cSpG40;vYz~}iT?%kPGNQc literal 0 HcmV?d00001 diff --git a/docs/server/source/_static/arch.svg b/docs/server/source/_static/arch.svg deleted file mode 100644 index 0f0655a0..00000000 --- a/docs/server/source/_static/arch.svg +++ /dev/null @@ -1,2 +0,0 @@ - -
NGINX Service
NGINX Service
NGINX Deployment
NGINX Deployment
Rate
Limiting
Logic
[Not supported by viewer]
HTTPs
Termination

[Not supported by viewer]
Analyze
Request
[Not supported by viewer]
443
443
OpenResty
Service
[Not supported by viewer]
OpenResty
Deployment
[Not supported by viewer]
POST
POST
Auth
Logic
[Not supported by viewer]
3Scale
3Scale
BigchainDB
Service
[Not supported by viewer]
BigchainDB
Deployment
[Not supported by viewer]
GET
GET
Rate
Limiting
Logic
[Not supported by viewer]
27017
27017
MongoDB
Service
[Not supported by viewer]
MongoDB
StatefulSet
[Not supported by viewer]
MongoDB Monitoring
Agent
Deployment
[Not supported by viewer]
MongoDB
backup
Agent
Deployment
[Not supported by viewer]
MongoDB
Cloud
Manager
[Not supported by viewer]
BigchainDB API
BigchainDB API
MongoDB Cluster
Communication
MongoDB Cluster<div>Communication</div>
IPDB Node
IPDB Node
\ No newline at end of file diff --git a/docs/server/source/production-deployment-template/architecture.rst b/docs/server/source/production-deployment-template/architecture.rst index 62b850fd..98d90184 100644 --- a/docs/server/source/production-deployment-template/architecture.rst +++ b/docs/server/source/production-deployment-template/architecture.rst @@ -8,20 +8,20 @@ An IPDB Production deployment is hosted on a Kubernetes cluster and includes: * NGINX, OpenResty, BigchainDB, Monitoring Agent and Backup Agent `Kubernetes Deployments `_. * MongoDB `Kubernetes StatefulSet `_. -* External systems like `3scale `_, +* Third party systems like `3scale `_, `MongoDB Cloud Manager `_ and the `Azure Operations Management Suite `_. -.. image:: ../_static/arch.svg +.. image:: ../_static/arch.jpg -We describe the role of each of these modules here. NGINX ----- -We use an NGINX as HTTP proxy on port 443 at the cloud entrypoint for: +We use an NGINX as HTTP proxy on port 443 (configurable) at the cloud +entrypoint for: #. Rate Limiting: We configure NGINX to allow only a certain number of requests (configurable) which prevents DoS attacks. @@ -36,7 +36,8 @@ We use an NGINX as HTTP proxy on port 443 at the cloud entrypoint for: #. BigchainDB Service if it is a GET request. -We use an NGINX TCP proxy on port 27017 at the cloud entrypoint for: +We use an NGINX TCP proxy on port 27017 (configurable) at the cloud +entrypoint for: #. Rate Limiting: We configure NGINX to allow only a certain number of requests (configurable) which prevents DoS attacks. From 751da63e38a524a9454d8d322bd4a5eb8226bb75 Mon Sep 17 00:00:00 2001 From: "krish7919 (Krish)" Date: Thu, 28 Sep 2017 11:16:50 +0200 Subject: [PATCH 029/120] Address comments --- .../source/production-deployment-template/architecture.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/server/source/production-deployment-template/architecture.rst b/docs/server/source/production-deployment-template/architecture.rst index 98d90184..beb03d7e 100644 --- a/docs/server/source/production-deployment-template/architecture.rst +++ b/docs/server/source/production-deployment-template/architecture.rst @@ -8,13 +8,18 @@ An IPDB Production deployment is hosted on a Kubernetes cluster and includes: * NGINX, OpenResty, BigchainDB, Monitoring Agent and Backup Agent `Kubernetes Deployments `_. * MongoDB `Kubernetes StatefulSet `_. -* Third party systems like `3scale `_, +* Third party services like `3scale `_, `MongoDB Cloud Manager `_ and the `Azure Operations Management Suite `_. .. image:: ../_static/arch.jpg +.. note:: + The arrows in the diagram represent the client-server communication. For + example, A-->B implies that A initiates the connection to B. + It does not represent the flow of data; the communication channel is always + fully duplex. NGINX From 9609efbb5e59284951957318ba541ba43db57034 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Thu, 28 Sep 2017 15:14:38 +0200 Subject: [PATCH 030/120] Update mongodb monitoring agent --- k8s/mongodb-backup-agent/container/docker_build_and_push.bash | 4 ++-- k8s/mongodb-backup-agent/mongo-backup-dep.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/k8s/mongodb-backup-agent/container/docker_build_and_push.bash b/k8s/mongodb-backup-agent/container/docker_build_and_push.bash index fd1d6420..91a0b22c 100755 --- a/k8s/mongodb-backup-agent/container/docker_build_and_push.bash +++ b/k8s/mongodb-backup-agent/container/docker_build_and_push.bash @@ -1,5 +1,5 @@ #!/bin/bash -docker build -t bigchaindb/mongodb-backup-agent:3.4 . +docker build -t bigchaindb/mongodb-backup-agent:3.5 . -docker push bigchaindb/mongodb-backup-agent:3.4 +docker push bigchaindb/mongodb-backup-agent:3.5 diff --git a/k8s/mongodb-backup-agent/mongo-backup-dep.yaml b/k8s/mongodb-backup-agent/mongo-backup-dep.yaml index d00194ed..4aeb66bf 100644 --- a/k8s/mongodb-backup-agent/mongo-backup-dep.yaml +++ b/k8s/mongodb-backup-agent/mongo-backup-dep.yaml @@ -24,7 +24,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: mdb-backup - image: bigchaindb/mongodb-backup-agent:3.4 + image: bigchaindb/mongodb-backup-agent:3.5 imagePullPolicy: IfNotPresent env: - name: MMS_API_KEYFILE_PATH From df2bd1043011fe096040899b443d6767fa92ff6c Mon Sep 17 00:00:00 2001 From: "krish7919 (Krish)" Date: Thu, 21 Sep 2017 11:15:07 +0200 Subject: [PATCH 031/120] Add troubleshooting doc --- .../production-deployment-template/index.rst | 1 + .../troubleshoot.rst | 70 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 docs/server/source/production-deployment-template/troubleshoot.rst diff --git a/docs/server/source/production-deployment-template/index.rst b/docs/server/source/production-deployment-template/index.rst index 9dbb4f11..aa966677 100644 --- a/docs/server/source/production-deployment-template/index.rst +++ b/docs/server/source/production-deployment-template/index.rst @@ -28,4 +28,5 @@ Feel free change things to suit your needs or preferences. add-node-on-kubernetes restore-from-mongodb-cloud-manager tectonic-azure + troubleshoot architecture diff --git a/docs/server/source/production-deployment-template/troubleshoot.rst b/docs/server/source/production-deployment-template/troubleshoot.rst new file mode 100644 index 00000000..9a46d64d --- /dev/null +++ b/docs/server/source/production-deployment-template/troubleshoot.rst @@ -0,0 +1,70 @@ +Cluster Troubleshooting +======================= + +This page describes some basic issues we have faced while deploying and +operating the cluster. + +1. MongoDB Restarts +------------------- + +We define the following in the ``mongo-ss.yaml`` file: + +.. code:: bash + + resources: + limits: + cpu: 200m + memory: 3.5G + +So, when the MongoDB cache occupies a memory greater than 3.5GB, it is +terminated by the ``kubelet``. +This can usually be verified by logging in to the worker node running MongoDB +container and looking at the syslog (the ``journalctl`` command should usually +work). It should show an error message as: + +TODO: paste the error message the next time this error happens! + + +2. 502 Bad Gateway Error on Runscope Tests +------------------------------------------ + +It means that NGINX could not find the appropriate backed to forward the +requests to. This typically happens when MongoDB goes down (as described above) +and BigchainDB, after trying for ``BIGCHAINDB_DATABASE_MAXTRIES`` times, gives +up. The Kubernetes BigchainDB Deployment then restarts the BigchainDB pod. + + +3. Service Unreachable +---------------------- + +Communication between Kubernetes Services and Deployments fail in +v1.6.6 and before due to a trivial key lookup error for non-existent services +in the ``kubelet``. +This error can be reproduced by restarting any public facing (that is, services +using the cloud load balancer) Kubernetes services, and watching the +``kube-proxy`` failure in its logs. +The solution to this problem is to restart ``kube-proxy`` on the affected +worker/agent node. Login to the worker node and run: + +.. code:: bash + + docker stop `docker ps | grep k8s_kube-proxy | cut -d" " -f1` + + docker logs -f `docker ps | grep k8s_kube-proxy | cut -d" " -f1` + +This issue is fixed in Kubernetes v1.7. + + +4. Single Disk Attached to Multiple Mountpoints in a Container +-------------------------------------------------------------- + +This is currently the issue faced in one of the clusters and being debugged by +the support team at Microsoft. + +An issue has been logged `here +`_. + +This is apparently fixed in Kubernetes v1.7.2 which include a new disk driver, +but is yet to tested by us. + + From cba933a59243d35c10337a95e67dccd0bdce11a7 Mon Sep 17 00:00:00 2001 From: "krish7919 (Krish)" Date: Wed, 27 Sep 2017 11:17:13 +0200 Subject: [PATCH 032/120] Elaborate on 502 gateway error --- .../production-deployment-template/troubleshoot.rst | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/server/source/production-deployment-template/troubleshoot.rst b/docs/server/source/production-deployment-template/troubleshoot.rst index 9a46d64d..42ce2b9c 100644 --- a/docs/server/source/production-deployment-template/troubleshoot.rst +++ b/docs/server/source/production-deployment-template/troubleshoot.rst @@ -29,9 +29,16 @@ TODO: paste the error message the next time this error happens! ------------------------------------------ It means that NGINX could not find the appropriate backed to forward the -requests to. This typically happens when MongoDB goes down (as described above) -and BigchainDB, after trying for ``BIGCHAINDB_DATABASE_MAXTRIES`` times, gives -up. The Kubernetes BigchainDB Deployment then restarts the BigchainDB pod. +requests to. This typically happens when: + +#. MongoDB goes down (as described above) and BigchainDB, after trying for + ``BIGCHAINDB_DATABASE_MAXTRIES`` times, gives up. The Kubernetes BigchainDB + Deployment then restarts the BigchainDB pod. + +#. BigchainDB crashes for some reason. We have seen this happen when updating + BigchainDB from one version to the next. This usually means the older + connections to the service gets disconnected; retrying the request one more + time, forwards the connection to the new instance and succeed. 3. Service Unreachable From c211ef156aed2171a0d8b1111a0edcec0e01217e Mon Sep 17 00:00:00 2001 From: "krish7919 (Krish)" Date: Thu, 28 Sep 2017 11:02:47 +0200 Subject: [PATCH 033/120] Address comments --- .../troubleshoot.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/server/source/production-deployment-template/troubleshoot.rst b/docs/server/source/production-deployment-template/troubleshoot.rst index 42ce2b9c..004fecf9 100644 --- a/docs/server/source/production-deployment-template/troubleshoot.rst +++ b/docs/server/source/production-deployment-template/troubleshoot.rst @@ -14,16 +14,16 @@ We define the following in the ``mongo-ss.yaml`` file: resources: limits: cpu: 200m - memory: 3.5G + memory: 5G -So, when the MongoDB cache occupies a memory greater than 3.5GB, it is +When the MongoDB cache occupies a memory greater than 5GB, it is terminated by the ``kubelet``. This can usually be verified by logging in to the worker node running MongoDB container and looking at the syslog (the ``journalctl`` command should usually -work). It should show an error message as: - -TODO: paste the error message the next time this error happens! +work). +This issue is resolved in +`PR #1757 `_. 2. 502 Bad Gateway Error on Runscope Tests ------------------------------------------ @@ -59,7 +59,8 @@ worker/agent node. Login to the worker node and run: docker logs -f `docker ps | grep k8s_kube-proxy | cut -d" " -f1` -This issue is fixed in Kubernetes v1.7. +`This issue `_ is +`fixed in Kubernetes v1.7 `_. 4. Single Disk Attached to Multiple Mountpoints in a Container @@ -68,10 +69,9 @@ This issue is fixed in Kubernetes v1.7. This is currently the issue faced in one of the clusters and being debugged by the support team at Microsoft. -An issue has been logged `here -`_. +The issue was first seen on August 29, 2017 on the Test Network and has been +logged in the `Azure/acs-engine repo on GitHub `_. This is apparently fixed in Kubernetes v1.7.2 which include a new disk driver, but is yet to tested by us. - From 1b9dcb9ffa431522e78026dd9101caf5c84876cb Mon Sep 17 00:00:00 2001 From: Shahbaz Nazir Date: Fri, 29 Sep 2017 09:56:58 +0200 Subject: [PATCH 034/120] Change Group ID to Project ID for cloud manager config (#1772) MongoDB cloud manager UI has been updated and they have changed Group ID to Project ID and merged Settings -> Group Settings into one consolidated panel Settings This PR updates the k8s docs accordingly --- .../production-deployment-template/cloud-manager.rst | 2 +- .../source/production-deployment-template/workflow.rst | 8 ++++---- k8s/configuration/secret.yaml | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/server/source/production-deployment-template/cloud-manager.rst b/docs/server/source/production-deployment-template/cloud-manager.rst index 0a1030a3..c407ceb1 100644 --- a/docs/server/source/production-deployment-template/cloud-manager.rst +++ b/docs/server/source/production-deployment-template/cloud-manager.rst @@ -16,7 +16,7 @@ Configure MongoDB Cloud Manager for Monitoring * Select the group from the dropdown box on the page. - * Go to Settings, Group Settings and add a ``Preferred Hostnames`` entry as + * Go to Settings and add a ``Preferred Hostnames`` entry as a regexp based on the ``mdb-instance-name`` of the nodes in your cluster. It may take up to 5 mins till this setting takes effect. You may refresh the browser window and verify whether the changes have diff --git a/docs/server/source/production-deployment-template/workflow.rst b/docs/server/source/production-deployment-template/workflow.rst index 8b806bcd..aff8d5f9 100644 --- a/docs/server/source/production-deployment-template/workflow.rst +++ b/docs/server/source/production-deployment-template/workflow.rst @@ -110,13 +110,13 @@ secret token, service ID, version header and API service token. ☐ If the cluster uses MongoDB Cloud Manager for monitoring and backup, -you must ask the managing organization for the ``Group ID`` and the +you must ask the managing organization for the ``Project ID`` and the ``Agent API Key``. -(Each Cloud Manager "group" has its own ``Group ID``. A ``Group ID`` can +(Each Cloud Manager "Project" has its own ``Project ID``. A ``Project ID`` can contain a number of ``Agent API Key`` s. It can be found under -**Settings - Group Settings**. It was recently added to the Cloud Manager to +**Settings**. It was recently added to the Cloud Manager to allow easier periodic rotation of the ``Agent API Key`` with a constant -``Group ID``) +``Project ID``) ☐ :doc:`Deploy a Kubernetes cluster on Azure `. diff --git a/k8s/configuration/secret.yaml b/k8s/configuration/secret.yaml index d7a83135..ad3ca7d7 100644 --- a/k8s/configuration/secret.yaml +++ b/k8s/configuration/secret.yaml @@ -14,9 +14,9 @@ metadata: namespace: default type: Opaque data: - # Base64-encoded Group ID - # Group ID used by MongoDB deployment - group-id: "" + # Base64-encoded Project ID + # Project ID used by MongoDB deployment + group-id: "" # Base64-encoded MongoDB Agent API Key for the group agent-api-key: "" --- From 44b6376f05cde37cdb10df31b4c7a9f8eea65e1e Mon Sep 17 00:00:00 2001 From: Krish Date: Fri, 29 Sep 2017 11:01:45 +0200 Subject: [PATCH 035/120] Add Preferred Hostname Troubleshooting steps (#1773) --- .../troubleshoot.rst | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/server/source/production-deployment-template/troubleshoot.rst b/docs/server/source/production-deployment-template/troubleshoot.rst index 004fecf9..9099a60e 100644 --- a/docs/server/source/production-deployment-template/troubleshoot.rst +++ b/docs/server/source/production-deployment-template/troubleshoot.rst @@ -75,3 +75,32 @@ logged in the `Azure/acs-engine repo on GitHub `. From a9625e0e6263778fc9198ee1f4172892031df86b Mon Sep 17 00:00:00 2001 From: muawiakh Date: Mon, 2 Oct 2017 15:20:41 +0200 Subject: [PATCH 036/120] Refactor installation docs for bigchaindb node - Restructure docs for introduction page. - Add vagrant and ansible deployment menthod to the list --- docs/server/source/dev-and-test/index.rst | 3 + .../source/dev-and-test/setup-bdb-cloud9.md | 5 + .../source/dev-and-test/setup-bdb-docker.md | 114 +++++++++++ .../source/dev-and-test/setup-bdb-host.md | 58 ++++++ .../source/dev-and-test/setup-run-node.md | 188 +----------------- docs/server/source/introduction.md | 4 +- 6 files changed, 189 insertions(+), 183 deletions(-) create mode 100644 docs/server/source/dev-and-test/setup-bdb-cloud9.md create mode 100644 docs/server/source/dev-and-test/setup-bdb-docker.md create mode 100644 docs/server/source/dev-and-test/setup-bdb-host.md diff --git a/docs/server/source/dev-and-test/index.rst b/docs/server/source/dev-and-test/index.rst index f79c20a5..a033c130 100644 --- a/docs/server/source/dev-and-test/index.rst +++ b/docs/server/source/dev-and-test/index.rst @@ -6,3 +6,6 @@ Develop & Test BigchainDB Server setup-run-node running-all-tests + setup-bdb-host + setup-bdb-docker + setup-bdb-cloud9 diff --git a/docs/server/source/dev-and-test/setup-bdb-cloud9.md b/docs/server/source/dev-and-test/setup-bdb-cloud9.md new file mode 100644 index 00000000..cc0488e4 --- /dev/null +++ b/docs/server/source/dev-and-test/setup-bdb-cloud9.md @@ -0,0 +1,5 @@ +## Set up BigchainDB node on Cloud9 + +Ian Worrall of [Encrypted Labs](http://www.encryptedlabs.com/) wrote a document (PDF) explaining how to set up a BigchainDB (Server) dev machine on Cloud9: + +[Download that document from GitHub](https://raw.githubusercontent.com/bigchaindb/bigchaindb/master/docs/server/source/_static/cloud9.pdf) \ No newline at end of file diff --git a/docs/server/source/dev-and-test/setup-bdb-docker.md b/docs/server/source/dev-and-test/setup-bdb-docker.md new file mode 100644 index 00000000..b7d0f265 --- /dev/null +++ b/docs/server/source/dev-and-test/setup-bdb-docker.md @@ -0,0 +1,114 @@ +## Set up BigchainDB node using Docker + +You need to have recent versions of [Docker](https://docs.docker.com/engine/installation/) +and (Docker) [Compose](https://docs.docker.com/compose/install/). + +Build the images: + +```bash +docker-compose build +``` + +### Docker with RethinkDB + +**Note**: If you're upgrading BigchainDB and have previously already built the images, you may need +to rebuild them after the upgrade to install any new dependencies. + +Start RethinkDB: + +```bash +docker-compose -f docker-compose.rdb.yml up -d rdb +``` + +The RethinkDB web interface should be accessible at http://localhost:58080/. +Depending on which platform, and/or how you are running docker, you may need +to change `localhost` for the `ip` of the machine that is running docker. As a +dummy example, if the `ip` of that machine was `0.0.0.0`, you would access the +web interface at: http://0.0.0.0:58080/. + +Start a BigchainDB node: + +```bash +docker-compose -f docker-compose.rdb.yml up -d bdb-rdb +``` + +You can monitor the logs: + +```bash +docker-compose -f docker-compose.rdb.yml logs -f bdb-rdb +``` + +If you wish to run the tests: + +```bash +docker-compose -f docker-compose.rdb.yml run --rm bdb-rdb pytest -v -n auto +``` + +### Docker with MongoDB + +Start MongoDB: + +```bash +docker-compose up -d mdb +``` + +MongoDB should now be up and running. You can check the port binding for the +MongoDB driver port using: +```bash +$ docker-compose port mdb 27017 +``` + +Start a BigchainDB node: + +```bash +docker-compose up -d bdb +``` + +You can monitor the logs: + +```bash +docker-compose logs -f bdb +``` + +If you wish to run the tests: + +```bash +docker-compose run --rm bdb py.test -v --database-backend=mongodb +``` + +### Accessing the HTTP API + +You can do quick check to make sure that the BigchainDB server API is operational: + +```bash +curl $(docker-compose port bdb 9984) +``` + +The result should be a JSON object (inside braces like { }) +containing the name of the software ("BigchainDB"), +the version of BigchainDB, the node's public key, and other information. + +How does the above curl command work? Inside the Docker container, BigchainDB +exposes the HTTP API on port `9984`. First we get the public port where that +port is bound: + +```bash +docker-compose port bdb 9984 +``` + +The port binding will change whenever you stop/restart the `bdb` service. You +should get an output similar to: + +```bash +0.0.0.0:32772 +``` + +but with a port different from `32772`. + + +Knowing the public port we can now perform a simple `GET` operation against the +root: + +```bash +curl 0.0.0.0:32772 +``` diff --git a/docs/server/source/dev-and-test/setup-bdb-host.md b/docs/server/source/dev-and-test/setup-bdb-host.md new file mode 100644 index 00000000..6db2eea6 --- /dev/null +++ b/docs/server/source/dev-and-test/setup-bdb-host.md @@ -0,0 +1,58 @@ +#### Set up BigchainDB node on Local Dev Machine + +### With RethinkDB + +Create a default BigchainDB config file (in `$HOME/.bigchaindb`): +```text +$ bigchaindb -y configure rethinkdb +``` + +Note: [The BigchainDB CLI](../server-reference/bigchaindb-cli.html) and the [BigchainDB Configuration Settings](../server-reference/configuration.html) are documented elsewhere. (Click the links.) + +Start RethinkDB using: +```text +$ rethinkdb +``` + +You can verify that RethinkDB is running by opening the RethinkDB web interface in your web browser. It should be at http://localhost:8080/ + + + +To run BigchainDB Server, do: +```text +$ bigchaindb start +``` + +You can [run all the unit tests](running-unit-tests.html) to test your installation. + +The BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md) has more details about how to contribute. + + +### With MongoDB + +Create a default BigchainDB config file (in `$HOME/.bigchaindb`): +```text +$ bigchaindb -y configure mongodb +``` + +Note: [The BigchainDB CLI](../server-reference/bigchaindb-cli.html) and the [BigchainDB Configuration Settings](../server-reference/configuration.html) are documented elsewhere. (Click the links.) + +Start MongoDB __3.4+__ using: +```text +$ mongod --replSet=bigchain-rs +``` + +You can verify that MongoDB is running correctly by checking the output of the +previous command for the line: +```text +waiting for connections on port 27017 +``` + +To run BigchainDB Server, do: +```text +$ bigchaindb start +``` + +You can [run all the unit tests](running-unit-tests.html) to test your installation. + +The BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md) has more details about how to contribute. \ No newline at end of file diff --git a/docs/server/source/dev-and-test/setup-run-node.md b/docs/server/source/dev-and-test/setup-run-node.md index b9271cf8..49b0ebf7 100644 --- a/docs/server/source/dev-and-test/setup-run-node.md +++ b/docs/server/source/dev-and-test/setup-run-node.md @@ -2,188 +2,14 @@ This page explains how to set up a minimal local BigchainDB node for development and testing purposes. -The BigchainDB core dev team develops BigchainDB on recent Ubuntu and Fedora distributions, so we recommend you use one of those. BigchainDB Server doesn't work on Windows and Mac OS X (unless you use a VM or containers). - - -## Option A: Using a Local Dev Machine +The BigchainDB core dev team develops BigchainDB on recent CentOS Fedora and Ubuntu distributions, so we recommend you use one of those. BigchainDB Server doesn't work on Windows and Mac OS X (unless you use a VM or containers). Read through the BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md). It outlines the steps to setup a machine for developing and testing BigchainDB. -### With RethinkDB +You can set up a stand-alone BigchainDB node using one of the following guides: -Create a default BigchainDB config file (in `$HOME/.bigchaindb`): -```text -$ bigchaindb -y configure rethinkdb -``` - -Note: [The BigchainDB CLI](../server-reference/bigchaindb-cli.html) and the [BigchainDB Configuration Settings](../server-reference/configuration.html) are documented elsewhere. (Click the links.) - -Start RethinkDB using: -```text -$ rethinkdb -``` - -You can verify that RethinkDB is running by opening the RethinkDB web interface in your web browser. It should be at http://localhost:8080/ - - - -To run BigchainDB Server, do: -```text -$ bigchaindb start -``` - -You can [run all the unit tests](running-unit-tests.html) to test your installation. - -The BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md) has more details about how to contribute. - - -### With MongoDB - -Create a default BigchainDB config file (in `$HOME/.bigchaindb`): -```text -$ bigchaindb -y configure mongodb -``` - -Note: [The BigchainDB CLI](../server-reference/bigchaindb-cli.html) and the [BigchainDB Configuration Settings](../server-reference/configuration.html) are documented elsewhere. (Click the links.) - -Start MongoDB __3.4+__ using: -```text -$ mongod --replSet=bigchain-rs -``` - -You can verify that MongoDB is running correctly by checking the output of the -previous command for the line: -```text -waiting for connections on port 27017 -``` - -To run BigchainDB Server, do: -```text -$ bigchaindb start -``` - -You can [run all the unit tests](running-unit-tests.html) to test your installation. - -The BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md) has more details about how to contribute. - - -## Option B: Using a Local Dev Machine and Docker - -You need to have recent versions of [Docker Engine](https://docs.docker.com/engine/installation/) -and (Docker) [Compose](https://docs.docker.com/compose/install/). - -Build the images: - -```bash -docker-compose build -``` - -### Docker with RethinkDB - -**Note**: If you're upgrading BigchainDB and have previously already built the images, you may need -to rebuild them after the upgrade to install any new dependencies. - -Start RethinkDB: - -```bash -docker-compose -f docker-compose.rdb.yml up -d rdb -``` - -The RethinkDB web interface should be accessible at http://localhost:58080/. -Depending on which platform, and/or how you are running docker, you may need -to change `localhost` for the `ip` of the machine that is running docker. As a -dummy example, if the `ip` of that machine was `0.0.0.0`, you would access the -web interface at: http://0.0.0.0:58080/. - -Start a BigchainDB node: - -```bash -docker-compose -f docker-compose.rdb.yml up -d bdb-rdb -``` - -You can monitor the logs: - -```bash -docker-compose -f docker-compose.rdb.yml logs -f bdb-rdb -``` - -If you wish to run the tests: - -```bash -docker-compose -f docker-compose.rdb.yml run --rm bdb-rdb pytest -v -n auto -``` - -### Docker with MongoDB - -Start MongoDB: - -```bash -docker-compose up -d mdb -``` - -MongoDB should now be up and running. You can check the port binding for the -MongoDB driver port using: -```bash -$ docker-compose port mdb 27017 -``` - -Start a BigchainDB node: - -```bash -docker-compose up -d bdb -``` - -You can monitor the logs: - -```bash -docker-compose logs -f bdb -``` - -If you wish to run the tests: - -```bash -docker-compose run --rm bdb py.test -v --database-backend=mongodb -``` - -### Accessing the HTTP API - -You can do quick check to make sure that the BigchainDB server API is operational: - -```bash -curl $(docker-compose port bdb 9984) -``` - -The result should be a JSON object (inside braces like { }) -containing the name of the software ("BigchainDB"), -the version of BigchainDB, the node's public key, and other information. - -How does the above curl command work? Inside the Docker container, BigchainDB -exposes the HTTP API on port `9984`. First we get the public port where that -port is bound: - -```bash -docker-compose port bdb 9984 -``` - -The port binding will change whenever you stop/restart the `bdb` service. You -should get an output similar to: - -```bash -0.0.0.0:32772 -``` - -but with a port different from `32772`. - - -Knowing the public port we can now perform a simple `GET` operation against the -root: - -```bash -curl 0.0.0.0:32772 -``` - -## Option C: Using a Dev Machine on Cloud9 - -Ian Worrall of [Encrypted Labs](http://www.encryptedlabs.com/) wrote a document (PDF) explaining how to set up a BigchainDB (Server) dev machine on Cloud9: - -[Download that document from GitHub](https://raw.githubusercontent.com/bigchaindb/bigchaindb/master/docs/server/source/_static/cloud9.pdf) +- [Using a Local Dev Machine](setup-bdb-host.html) +- [Using a Local Dev Machine and Docker](setup-bdb-docker.html) +- [Using Vagrant](../appendices/run-with-vagrant.html) +- [Using Ansible](../appendices/run-with-ansible.html) +- [Using a Dev Machine on Cloud9](setup-bdb-cloud9.html) diff --git a/docs/server/source/introduction.md b/docs/server/source/introduction.md index 5c48a8fe..e92e9e0d 100644 --- a/docs/server/source/introduction.md +++ b/docs/server/source/introduction.md @@ -15,8 +15,8 @@ Note that there are a few kinds of nodes: ## Setup Instructions for Various Cases -* [Set up a local stand-alone BigchainDB node for learning and experimenting: Quickstart](quickstart.html) -* [Set up and run a local dev/test node for developing and testing BigchainDB Server](dev-and-test/setup-run-node.html) +* [Quickstart](quickstart.html) +* [Set up a local BigchainDB node for development, experimenting and testing](dev-and-test/setup-run-node.html) * [Set up and run a BigchainDB cluster](clusters.html) There are some old RethinkDB-based deployment instructions as well: From f1ba93547678fcccd3e7354a2a386a1d0f6bb75c Mon Sep 17 00:00:00 2001 From: muawiakh Date: Wed, 4 Oct 2017 11:21:34 +0200 Subject: [PATCH 037/120] [refactor docs]: Remove cloud9 deployment guide - Remove deprecated guides - Address comments --- docs/server/source/dev-and-test/index.rst | 5 +- .../source/dev-and-test/setup-bdb-cloud9.md | 5 -- .../source/dev-and-test/setup-bdb-docker.md | 68 +++++++++---------- .../source/dev-and-test/setup-bdb-host.md | 58 ++++++++-------- .../source/dev-and-test/setup-run-node.md | 5 +- 5 files changed, 67 insertions(+), 74 deletions(-) delete mode 100644 docs/server/source/dev-and-test/setup-bdb-cloud9.md diff --git a/docs/server/source/dev-and-test/index.rst b/docs/server/source/dev-and-test/index.rst index a033c130..ff6e3ccf 100644 --- a/docs/server/source/dev-and-test/index.rst +++ b/docs/server/source/dev-and-test/index.rst @@ -5,7 +5,8 @@ Develop & Test BigchainDB Server :maxdepth: 1 setup-run-node - running-all-tests setup-bdb-host setup-bdb-docker - setup-bdb-cloud9 + ../appendices/run-with-vagrant + ../appendices/run-with-ansible + running-all-tests diff --git a/docs/server/source/dev-and-test/setup-bdb-cloud9.md b/docs/server/source/dev-and-test/setup-bdb-cloud9.md deleted file mode 100644 index cc0488e4..00000000 --- a/docs/server/source/dev-and-test/setup-bdb-cloud9.md +++ /dev/null @@ -1,5 +0,0 @@ -## Set up BigchainDB node on Cloud9 - -Ian Worrall of [Encrypted Labs](http://www.encryptedlabs.com/) wrote a document (PDF) explaining how to set up a BigchainDB (Server) dev machine on Cloud9: - -[Download that document from GitHub](https://raw.githubusercontent.com/bigchaindb/bigchaindb/master/docs/server/source/_static/cloud9.pdf) \ No newline at end of file diff --git a/docs/server/source/dev-and-test/setup-bdb-docker.md b/docs/server/source/dev-and-test/setup-bdb-docker.md index b7d0f265..a0a50dfd 100644 --- a/docs/server/source/dev-and-test/setup-bdb-docker.md +++ b/docs/server/source/dev-and-test/setup-bdb-docker.md @@ -1,4 +1,4 @@ -## Set up BigchainDB node using Docker +# Set Up BigchainDB Node Using Docker You need to have recent versions of [Docker](https://docs.docker.com/engine/installation/) and (Docker) [Compose](https://docs.docker.com/compose/install/). @@ -8,8 +8,38 @@ Build the images: ```bash docker-compose build ``` +## Docker with MongoDB -### Docker with RethinkDB +Start MongoDB: + +```bash +docker-compose up -d mdb +``` + +MongoDB should now be up and running. You can check the port binding for the +MongoDB driver port using: +```bash +$ docker-compose port mdb 27017 +``` + +Start a BigchainDB node: + +```bash +docker-compose up -d bdb +``` + +You can monitor the logs: + +```bash +docker-compose logs -f bdb +``` + +If you wish to run the tests: + +```bash +docker-compose run --rm bdb py.test -v --database-backend=mongodb +``` +## Docker with RethinkDB **Note**: If you're upgrading BigchainDB and have previously already built the images, you may need to rebuild them after the upgrade to install any new dependencies. @@ -44,39 +74,7 @@ If you wish to run the tests: docker-compose -f docker-compose.rdb.yml run --rm bdb-rdb pytest -v -n auto ``` -### Docker with MongoDB - -Start MongoDB: - -```bash -docker-compose up -d mdb -``` - -MongoDB should now be up and running. You can check the port binding for the -MongoDB driver port using: -```bash -$ docker-compose port mdb 27017 -``` - -Start a BigchainDB node: - -```bash -docker-compose up -d bdb -``` - -You can monitor the logs: - -```bash -docker-compose logs -f bdb -``` - -If you wish to run the tests: - -```bash -docker-compose run --rm bdb py.test -v --database-backend=mongodb -``` - -### Accessing the HTTP API +## Accessing the HTTP API You can do quick check to make sure that the BigchainDB server API is operational: diff --git a/docs/server/source/dev-and-test/setup-bdb-host.md b/docs/server/source/dev-and-test/setup-bdb-host.md index 6db2eea6..e74cedd4 100644 --- a/docs/server/source/dev-and-test/setup-bdb-host.md +++ b/docs/server/source/dev-and-test/setup-bdb-host.md @@ -1,34 +1,6 @@ -#### Set up BigchainDB node on Local Dev Machine +# Set Up BigchainDB Node on Local Dev Machine -### With RethinkDB - -Create a default BigchainDB config file (in `$HOME/.bigchaindb`): -```text -$ bigchaindb -y configure rethinkdb -``` - -Note: [The BigchainDB CLI](../server-reference/bigchaindb-cli.html) and the [BigchainDB Configuration Settings](../server-reference/configuration.html) are documented elsewhere. (Click the links.) - -Start RethinkDB using: -```text -$ rethinkdb -``` - -You can verify that RethinkDB is running by opening the RethinkDB web interface in your web browser. It should be at http://localhost:8080/ - - - -To run BigchainDB Server, do: -```text -$ bigchaindb start -``` - -You can [run all the unit tests](running-unit-tests.html) to test your installation. - -The BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md) has more details about how to contribute. - - -### With MongoDB +## With MongoDB Create a default BigchainDB config file (in `$HOME/.bigchaindb`): ```text @@ -55,4 +27,30 @@ $ bigchaindb start You can [run all the unit tests](running-unit-tests.html) to test your installation. +The BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md) has more details about how to contribute. +## With RethinkDB + +Create a default BigchainDB config file (in `$HOME/.bigchaindb`): +```text +$ bigchaindb -y configure rethinkdb +``` + +Note: [The BigchainDB CLI](../server-reference/bigchaindb-cli.html) and the [BigchainDB Configuration Settings](../server-reference/configuration.html) are documented elsewhere. (Click the links.) + +Start RethinkDB using: +```text +$ rethinkdb +``` + +You can verify that RethinkDB is running by opening the RethinkDB web interface in your web browser. It should be at http://localhost:8080/ + + + +To run BigchainDB Server, do: +```text +$ bigchaindb start +``` + +You can [run all the unit tests](running-all-tests.html) to test your installation. + The BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md) has more details about how to contribute. \ No newline at end of file diff --git a/docs/server/source/dev-and-test/setup-run-node.md b/docs/server/source/dev-and-test/setup-run-node.md index 49b0ebf7..0597adb6 100644 --- a/docs/server/source/dev-and-test/setup-run-node.md +++ b/docs/server/source/dev-and-test/setup-run-node.md @@ -2,7 +2,7 @@ This page explains how to set up a minimal local BigchainDB node for development and testing purposes. -The BigchainDB core dev team develops BigchainDB on recent CentOS Fedora and Ubuntu distributions, so we recommend you use one of those. BigchainDB Server doesn't work on Windows and Mac OS X (unless you use a VM or containers). +The BigchainDB core dev team develops BigchainDB on recent Ubuntu, Fedora and CentOS distributions, so we recommend you use one of those. BigchainDB Server doesn't work on Windows and Mac OS X (unless you use a VM or containers). Read through the BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md). It outlines the steps to setup a machine for developing and testing BigchainDB. @@ -12,4 +12,5 @@ You can set up a stand-alone BigchainDB node using one of the following guides: - [Using a Local Dev Machine and Docker](setup-bdb-docker.html) - [Using Vagrant](../appendices/run-with-vagrant.html) - [Using Ansible](../appendices/run-with-ansible.html) -- [Using a Dev Machine on Cloud9](setup-bdb-cloud9.html) + +You can [run all the unit tests](running-all-tests.html) to test your installation. From 8390cab59acf5a1debe91ead96f60ddcd0f4c2bb Mon Sep 17 00:00:00 2001 From: muawiakh Date: Wed, 4 Oct 2017 11:51:22 +0200 Subject: [PATCH 038/120] Remove cloud9 pdf --- docs/server/source/_static/cloud9.pdf | Bin 885538 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/server/source/_static/cloud9.pdf diff --git a/docs/server/source/_static/cloud9.pdf b/docs/server/source/_static/cloud9.pdf deleted file mode 100644 index 22c6891e8a22bb9759d01cd6241cb951d8af680d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 885538 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%0Al<+c`sAyksrX_yYd<@% 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

U*dhtbd@~ zeCg)lMoxe?FvNbH9ozHnz1}#H(|xk84Q2hQ_xbya`XfozO2qqShp(U1m`v<<)L;0# z5B#=M3emrr@Nq7Em|#Ac7veD4>4f_B`U-#yje!s@x0)=D+4;d`e<4&gGgNhQ9C%4u zF|(O=iokRAfGn-KCuVFg+#>juZ_dCUsy?Yre}03Nr7}D}=yLMv+pxA#_C7KJcPWi(W!b4NOK>Qa$F_X16(p?qD(Bu_;&J z5n@n0iWpa!IjZ(CCT8bnX`o3PhT1z<13zpK4(!7ffU~85!ze;Pg&ez-H?ukT?r`3~ z@)f8>Cw(R04BqP=VxpL==5>tgXDpnm4Sj~{{T16ts^0av&H?;H9*b?a1ORd+bs@?x<(B3@c5-%E}4 zJe+-X7Gqi(6;lF(GQzs$LX@ubCa>Oj|_4-)T82rc@^^U z98^dn6NT@j%mqDii z6z$KqzLZb}A}D`Wdt^>%*;C<<*G;s6Y=;0}f(Tw{Zo&N3^C1=Q{se%W+>XbM6o@of zpL&(PZE#1L#3*E@BnY4Qtj;!VyE@QV+cMONhChduN?&(M!mdee19%`6N{udn+J)J3 z8?!Q4SU*4)M%De&gyn~|UfaZGQd-I>Hfll0%1-L7Vrvxl@O`Ea#mig^QtE|{gtaFX zgC`f%gcf?Z0v8FLmApsJ!FMd-q8vZ$E{)?DFqaIMIBGkU8dek@t5;w2$Tk zIcgX~0^1;f;>_yKmRtNW-%pgW2=Qh2_4J49J;fk{|A>_V{|+PQW0;A4$U+o^+qenD zq*q-%KBHbR%=k|m(aY4fz+cR(36QWF=*5 z@L-k-{SEw^nGGMxm6g6e(<-aIX2<~VoG-u=Pxf+t%~;@ha8+Sea%LUKP^96jYUD{az= ztDotrv??FrD;p=4$wIGx%FD+gH|L*TtSlpmEE!Y{O48(J#;p>=V-QRGk!;8;*nUw$s1c3jJh zaXnkYmMf;@*=xZ}d|~s6-9oqKQ?kzzoSg;UOPNS$rbh{k&E9VCk?Czt+su#>ZZy)j z%;Zdo>#807>yc4=Lq&pf_|Jwt?+w38(J}>2UEZsZ7;U^Vpr)|YHLvLsdX6fNLzOZzAf3WY{E zp3_;cgamwNfkA#Qyt@gcNQs}!dx$Xl*#p1oGbBJ3G0LH)o}bj}7il`wQBqRc82#Lz zz|s5yysyvhg=4YP$u{^|im%bGcl{QU50FBhd^}3YPXZqdd_X7b>3CYM0bzlWcKk#p z!h)x)w;zB%L^2>jT2EEF&so)y(gr6zv#G?{t9jL;xg*(uiGZnq-f@4=U zAFEz;p1MeqVjC1h+xHJO;Ng`$L*-XpGSd~c_5V9e@>oYP#~JG$P- zzK=x3>r+1DwRRAk5goucggyq4ZL5B6-+KZWN(u@!=j-|QVfVf@kvbNqUJ15`5Nwof zz^^s}Ocf-}3*wwLdu>lj40~UqTGIKxJ_74zWqDZ)^*TW@xf`|iJ)2YWaSB3sz(QLv?JmN%5+EYj91G8kac@!`rsfYH z12om|?+t@UgaxV1soVTiwjNQITT{nN#L3WQ3b`0P`y9Y>q%n6bxY?-#q+X_VcpNX#zW4`WaW9(DMeC-+K}ye7K|D&UG{_zlqcQsqqfC2+JM#BMLte6; za;$)D1*qe|yPv{G_W=!-vqKC1LXX*ifWg~&yfvY$tn8alxs9Aq>Hcx|aP2#BE6T4V zw*$X0!AFEw$<<}JPOjjC>@_JlpLChb%$_lnuc+ zWa=FgAE{tvF+j145%m?s9~{`ZLn61N*bi)FC<6zA4I~XR`h5FL-iIl56@cXBdg(qT z+cS8dSi4yfqZvTGg6HrEbmU`5S@Y1=QyT77=YU5*C}J!CyGgN* zpEvC{GLSCVKupBFnj!zA}9&o>OPX+8N&|)G@8MjsL z{}OuKMIWniu*z5Z%z|fxB34)c(%~@~BKb6d zoa}%bSDm;@9By6^tadFj#Sp}dM;>=DQ`Ir%vxOUsLf=&0$9ab(km7-ODja81^#Rw( z^tmyY;Mqu1(Ac;0u)Hr|cTAHNTP(Bz4kx+U7ZnNn|28+fw{Za5hSsQ7{O z`Ob5yg%q}W2?bho5jNPO+T)*4(nv|W&iM>{k5m=YlB}D&Wj;36wB@yA-)D-!H!&ol z0^m{nUx+I{f{{i?q`cpI%oswWA0WlRWLq1+=X^hQ&_D~<63&MZhMem8YHra(MIoRT zB;FmCm;M+P#ct*gb?lT<3Fg`MTp^Q#Rh zHhe~WV9rFjG9oc}L<5T~*??;{X7>)23UnkD)-)vxWnL9kZZgd%zkAuRb?}{5=w0JL0Dg3f0vTNhq2Zz@G#}% zLWBhi_z-jHO8;u31&ZyYd|EnKWPT$1VR$5QdN)r6HsCdxi5tq3zso5-qyvQGe2YJm zQ6HD^O}hVt?+QJSo;74o*g zib^6W24(^rWiTEK4HHvjq#UzLnBJcWenP~w|bS!QKFv%!6HP93eR>p39I2VwF zPgqSFCjBLC2U7SiGyRs)P5iFfo|wg^0qFq9xu49p@pMoaM)fErg&&!P_kf3wnGyg1 z+&;(y(hbVqPxu_};-!69Yvgu1PPyFQ-yFH0p>%2BZj+V&dg2yph zsL2WU&>_Vave?q*dUgKVjC|?pWX7mekAW{_moM@4q(1Er%4BB@aBBE5>-(RJi;DsW zh)5L)_jLmV4_)>+Dxx-qA&@U~_Py(dfXDA7jO@RghG9Py0A`>;wGM5uW_i#^N3; zF_Qjndps7$>&DZ@U*JIjFUh9Y7W750{lyB?r&brT<6pUuPIf%YJ0%8g(>T`mcx$b# zt+9xb_pnIT89xaN40ut=yy)Xfj0nZ&@SL+;9Y|HVKfd{*f4m>zeK-sBaRl6c4(QxCy`%$PDvu=NV2=6A?x>X*2H(uVSA^=$ zX;zrO2KAR(x#^Y`Ii3tTef>wsq2*4FDOjPmKe_yOmYU}IGaf%!iZe=Td}smW_UuBA zpKVH$*wBlPyc!+DBqdb?ea$G#%F1V4FUG#;`3Wd68U4_zcTL2)6x^fV0)J9ed^9LtOdW-!r_a9zAh(9s^uA%|Mtp4R^4baa+ejGkD?SBH&EC=H zoA>TkfmI3K4c8V*7wPe6MLL<)~27(F3D`{*jf4pbDpH4;;fXaoT~??(%8OLh54 z3hNj7b95J5OIiLevqMG?Q}(=Z-`kF=?Af!J6+q z)|P1@2;cYhy3ooFbN9RYpa$_+dt9yG5WM`XO|1Miwm3-@i+*2*NEAc@yiJQ7gw9*_ zTSVfW>tNty8p96vyXp1j=D&G^EzE)9+c{LFxAa4Ji?&q^XNi~5O8jmqO0pb^ySXo+ z+vOLJq>p*60GD{%pQm{{c~DnFZob@utAKP7Xc^{VM4KCs3Dx~ruNssB66f}7QwHzP z8u?{YaTv$hd)Y z=g24r@HYkb+$mX#b2H zJVnYi+&xst<+xEY0hc|4hU{PQaBc`N4(+7EA?A;!etdiL-Q9%Xh4om4g&rS?8M+s6 z*+^29OFeN+0E{8u2mTPB-JD22Da^m0`(!dxJjRorg9WKBN`o5c2S>E?KL7DvV49in zVGdL7TdnjVzoC){f&dSNTJrU)v7rdJ-yj2-hrl|2wh!^U2mw%Eiw>*i<^6qe`+bIL z(~2DmiG?^DA( zijIkC&orH?0+ZFT%72JgwSRebu(&x{$wWR=X@zjLy4u(oNeQ%_?|=?VL~0+-x2XQw z5rln(yQ$|rO#LYc_ggwE-+ZS?l4{8%-UD;AC#Em!e!d#Kr%ey(amGdN*%{B&aSO&_mAIl^gJ_qT^i*?^CME$7 zgYp0{>cto&5H^#sS-P%^y_O)_9V;2+|LjVzu;utrDGYgW%ONc`R=uBC;IG}uQA!QU z?%Hhd7ks!nKS~evJevJ*9}{R?h2wBwa(Snd^j~ev*}Z-I1RU~%bM47_)rzeRP2oh@ z9K+6am<4ond#w*sa$ieHp`1Mz)AbgR6i2;xpb+r)@)+64%3T4HtkJ`% zI+u9?7 zDnk_%`Kqy(d~-?p3B6qbE14Q7JhOd3!6S3u1c}K|d z0aB2c2gG&C0D-BpUTcz~2Mxe}rGRXQUy(5J>2tsw97703c=P5BwQKgKOn{0L$R$-N z$I^vSg;6nHYZ7NQ17ym_#LU!`F1}Oes2Lu}(Gz5oo%cnf$&c5*{~C#KC?vCQIQp|; z2hieTeox^g_NAA@6SoqH3TDm>XLm-74)*NUvj-lOX7d=%H% zd%pltR8}~}j{twa%~ZmY;N-MWvy95K%=0r5RE=?|jDSq%itvrZdIC zNe;<9BR``}@gJ)A&tL#^6yp34cg_Shgkv`9g%-!NEA5+e?Cc!h9^8Z+hiW5E?p)d| zi;u%o*qT6 zBWQm=pAaP)$Qci@we07>f&=+5Srf-H$Q%QlV=D6;oYL(~#gzCKXvnJ-gMVw9p_dzD z!G?dF0&%3ji+>-7J2o=%JBS7m5fL4Bz{Fz8S)H!{H~gy-{}aT3p3tvgll>}z#S1JU zSD+IHndrgkLa1~cBl-TbK1J!?iT*^+n8d_dN{NPh=fHE4xtBp?-C&dOl#k3p#Qxk0 z1V#@bve}MubM#~E#OHc#K-P5*DAS#>FQgh}v)15F=w5a^)7}Sep0H~`a~erz(!#Hj zE$sAGVC#-}1JAHd-) zU+aw>92_dDC)cLq%5Q+Oc$MFJ1{h-Z;nGKQfK0Bhzy100d~2dSJOF@uEn+zBT0qsn zX|t|?|1cw|W1RhQY>=RXkp?*__lW9WxdtEHB;4eKK7w{(>)8em5FnU^rO=+w&D>m{ z1U#ah94Be1Win%PEIuDi_T$GK@G{Qd_)(;+pin^|5{x_8o6WN)8c87;&-$5%9B%TW z8I^ao;z?MnsaY*k;ZShRPujms73K&>g7|_i^+8}@AW(YRjc^{=9?mWkIGq74Iy z7cNv1JON5&skn^d?u{pAHH}sr$REn%S>MlVbbvVQ3aU!>#;>pX@{8&Mtjq!*KV#TQ zTTOf^M>L;k@e!6`1n%$M$4rUFKVb1@>t|_25YO3SWCB}bS7T5R5}fR!dO|)VuDqx( z*Y%x)>W$6Plv}NaoDIUDvg46y=uAOWVIW;mPhpcqROtti$__`gIG+$&Dk{Eom)%AL zTIIrwOq|EKydX!oht88zQ2GJ&p6~;pjIJN_0xI5zXR65}QW?xet1OEU+yM)KAK^J7 zzaJ|%(;hX!>-EE?9p7aU{ElwX1Q2cBi%ljJm^oWZ%O9z)eC?rHIq4*>PEznD>kyR8 zOA5(PCet->;uW#Fi#B2+9)7}YiVwmRF#nTLHiVlIlh!&OorCh6!>0}~8aPP)4f1;HT#SgK2J>VV#qXc`8GrmEl1LOn@@H{}s4Mj3y zjgg!un|?|h5-Ew8fNlVoH~u#L)WLp(UZB2QvCWtVxsvE&DTrMZ6WdeOYmA3FAfc0d zFeS`Ek%U(S!Bx(Mk^lU+4+0oK`;g!W7*Z`c2H z(CS1Gr>kc<&=qaf6d+V;vfGM6VG2~dgS>zO%woc>UscP4H?Y3EFEY`eJBD?5 zKg4!DU!!cHnCR9wFnF!bJZ}F&_xoprFBtR7>vUw}3t;@6A+kq+D){RW5W&8qaA|Od z!RPlgC>D>Q8%r(JsB9uB{hlo?T-U8})K^ox*|pU-leo!KpRo~&jpnk`L%mkIDi?~| z`e?*1+!78BD^-d66ktENx*dE^EsUQp1o$^of?m7E*Udh!c{8cHT0Fj=2BuA^5c}Ct z(Pcp?Eb>{&^W}K6Gz9*iU-X3gGT1HV;b^amQ7!55@SF5sWqw+qDJK5p#SjEx-eBwG zV^t#6b=DV6-_vM){ph0@afpkIBbv;Ezg;-^o%p_hk}XcjF0X!aBxoYwK3`487asep zUXEC9Ud-w94C!^jyJn?UF*XHa8pg$R%xJ$C6W?s?PCBu*;_V@WKi)W6^uK9UE*$aW z7f1UE9;!o5jMa7S(FWvG;5`f@7$QG#_SISJN?1<^Giv~_x#7G(09g-^ogv^L6&Ukv zzeG(tjee@?34@+3Z>rBh9QUI@_0^ZfRJ3$9;!yN3aUoPWJOYnUD#6s}qRDJ#kbF)H z=1i&rz@#zA{xv7i`N{dn2WPRO(ZnNy|75f+_zAk5R265_W2#jGGPw>NTh824M&u}% z()K3q#UxHR-oX6QLPGsGV&(*=ac>Iy6Dih&#^%w^g^-kC2JHQHDKaVKaLYD4V}J(3 z8@9NcfZUI90~tL+KZQ~19&03Vt3!Mf`p#IQJkHloK*w<#8Udg_`H7CbZ}JKC3W~S4 zw-BU?Ne{a@!ViPXauIPl=#-AcuftzM_iPSOK)spfG`Xp=zQbOo?^jzuAH?2gng=N9 zkWrzsjWaOYBv>K!R1c9U`RSI|sEtT50tcLqgAf=0u0OyCM>=e~dn zU_Cc`fC2|j(v?IAiR6i_vlMY(4S^L7?NksMb35H|u8&1$&;5Y0Vf-m<#+N>uo15mL zui)bao#z-^qC=e9%16iDnKg)I;4O<^Ki9a%lClH-sa#eP+5>$1I-=i>QJ@BzjmULPpPQ!n@$0comcGNzer!5Zm#F9)7Zp=ipWmf{0P*rvcGmbZy@sJ&!-$3s|DC*E(#>^f93 zGxGNDhxZ|xHLeXq=i)(Elv88hp zvB4eD_7zS4F{A!6T7ZwSUzY?Xz+&DE4Zh9#dp=>9J;GNc02e8&7$74hIH2rLF~d@Qhlk z@FSp^?{*%DSP&~(HO&*I^vX=9)_Dwgh@|Bb*gSBUDJu~OUrE1MArr%(7}SY|NTl`2 zDgIpqaY+&J&A`_HRRm368hy=f6A-W*?C--Cekz~l4TW?Q)tUorLj9Vr7rheHXH)`Y zpUG0&g>$PNhrCSj0{)Xd@wos?+iwe4e+STlP%z#RDAy!@^~5)c z%VFrfsP*#J*sK(2)AIok4pG;-`~=SS6#x+iy;kc$&N++SMLP$)&B(|Iek4CM70rD_ zNux_1l~nOG`1L$5eI~} zI<7wb@EUY0A)r{^<8Es4c6lGkN_FyZ6qmt+SGq&TnS(QawNR{5Xj;Pjl{l4t?I>wpV@%4A5k8%()o0Xl>nU-ZfPa0(31-^yAKKiazx1K$MXC#*W;8UTYb ztG@zd|5woVw|YeMe$H0ngTTvm{wM;W1`wLB0iMNz3|e-~zQpO0XHcv*0%Fk(@JR1Q z3mR?5bLF#v91=7terdKu6qx}42Af&mx>S<)@#ffNVM_+XEyXPq;g}x&R%MvQT$@ zz5#On7mjG^srAEJv5bk^&3>X^p4tc)@B%3k;0gr9LvWt!0^(1k$?a-G8-QM<2L-An z83+W%0e?c$FGul#3>3&5YoPI7d;7sAO8}X5p^%@w463fi1Zd8R2$<4Si7Gefehf!X z`#{!vaFsv$fvyYaPAgeO<@RIcT0$LYAdQ0evG1Sv4^U{SeY^?dh;}mpDlS~^juDV? z%0FeRIwJBM)Ly41rI9?5Jxk(t`ow;ne{UZur0Qjx(J6IaNwn)BKMTY|ar}J(!N1Ga zkB`VRWdYhOF^1@!X%4R7>I)Y6CI5rg)2QqGT0 z++;Iw8PQgxVUrS6uIvNUQAxG|DvCUula3H>4+7ucuN;xPxC=y%Xfw(h zqLSL;sQ=q2e&zRL@niV+l7*a!IveuXu!K7j8vP-|Uihhgm6-7a-A@3@@BWS)##@n+ z8&N{zxyABgp$@m-0VO=%EEl4vAE2IyY+r4=0GM|CRokGK)DGakVp+oN7lTp|q!ZX1 z(_TiK?+e&ohu7!aRYL!>Z=q2fh*Lam5;);GfS+)9j5L4uO*Hb?!r&{WDS&=(=YYcn z2F&@GD_GZ%J^2)+K{O5f4+k^=%gpZxYXoy3_ z<1-^icq%A#HrxC$7SU=KHF-P2{l;D#92{`mz;gKT_rlGBZPW~NsOAXzT+MR$p ze~#FYZXjLAyGEA1|0jj8isN%Qi^cC#PJUS?d%WF;ZKKFysn=EZ^WT<<2-+GOr*}w4Wd07E2IF&9RZ z?Fx)iJ;hL#;E{S+YgB4=`lX9uyBg**7bP>pUAM@oj zM#5^Y17}E40u}mp@%=;k6;#JmP6c1J`}P34Qd2khleR)F2gWyQkr5RYg^x)1`&!*y zP`_FW?B*V3fEF6bh=K0(VNEvaU|PFYtpC)19vM*NYyRUr_`+!Zs^x!hF2k>{P*#jn z(C9U*$V6kGzWO1*K%<(HoAjUc1bX^whPBN({#Psu`M8Igo}TgwpeQ1(AW79FM-rum z@mJUcG{}8>nXkM}oC`GLqIuWOhPi+g2t%Q zbpgGCzduG5Dply~2#_#rw%e0l{#hBG_gloT;A0lR;&wDY2;si^5mjG3&$wQ+a^4mC zLs>zq+G~Sqq_Ci%MNCCatt(S#*vlIE2x*%r6Alfm{RcU*)BnZIhtPp}_r&%<9envS z(GDBSH9>XId-)|{+U~BRX(5b1Sd^dDTJh`V7oZ&mFm9mwoHu>(hjUV| zwtaTR1O5##-dg}_OJFqU0#HVe2)pCqYW>ZX**r-5Hij}E#?@b+zni90Db@k;J!*H# zZf5Toh&TY8?F>AmKTu4{bpVJ-Yz|--l!A?t4V(*InzT?Y)t@Z_sL+3`5$M zN)ZWG%ZQbw7;OqqoJr6oC7Mb_^1u`ppb^_N)PM8BM6jY_L@MpAw5|Ui@Ss-2(;;#C z-Xv~L&;ng2H2RwEatH+wcR}!1b5*RF}{? z6jvBE1j2m|I)H`DzMkZAdd>T|3%7l&di9qP`QYT-|5@o!IBwFd^q?jJHCn^<-EwP0 zK(!xF!H1on)C7i)i^en!Y-1bku~kuregFWyX#&&VSKAmYSbze^&!Vc}0L8#v64T7s zGl2AAnkE3uqrzh0(&6D)3xy{ng9m`JH-K&gau8dfzQMxL+k5W`ur%i@)3+rnPLBY*%)qY?HNzj@lpk)!8ja9jaO9wg=4ztXG@Nz2rk0%>&__isjrG z&;q1FK{_x*`8UOPA}r^c;1fiq9K!^Z9s;~|6bHXDX2}ERfhYofJ}d!u1)!PxDv74P zpeC_fc$R+vod-oKUz%Eu)}fokGB3mLFDDNUqoDS%&#j-etYI<}-h2PEs`_H_VUZ+P zC}fklwqoVmJnfISEh(Q7KgV<&^G|Z_VQ-C>Q2OwaJ(({AN|o5%0hjkbzcrRK@uAYG zee*jYr5Z&-;u3)pN(BK=Sr?7(3!~24y|sY>HqD3(M6CvbO^AEuy%ST&<)1c!ko6zf@1Q~M^PgP-x0OT;n1d5CTbd|&Fp(m zfc~k~x+zTrB_i9M>8T8&yBx61E{Ybu?sjb-<;eyAV|!4*|Mo9VBHXK^K2ls?0h2|y zTo3?Uospp->m;dMmi|sqeiVP6&)=D3#BYAKR=oqeC+F6a$ zjkwUk={zV+piE(bCj8qGI1c4k0`e=39HxNc@oT^_J;UbRQTFubH>g zNqD3!?>-My?5l<5@cbP-JH>&SE9DuPn4Y8a9FOS*V$;*n(QN|>6>xfEDs73B8X5=3 ziv*9f3M<<_#yAPv{0)GK(810PCq!zgseMXL?pG%PSU`{*QiL|R0`GpOoO*D+{u=cN z=xF%8Bn28S;P9tbLUbPVpb$=SkhXwq$aRNO4;f@oUw$YU{bf`bGYpUov6@bfbrCXd z4uHc|040O5H0&Q%4oCTRdb<}QeXRCIgWL)Azv;j-8;go|2H`S+ z3}WTiBv#uwa(sN7X7N$1Hn;5Wt;S5}f#?|`4zvyc0!WGUZS{JlUbblONJ;)u;NZAz zYh1yls!j2qvy}drFw7nn9gZMo+WA1z#8V0)1u+@Q=mceDViY1s4>4!r*LDSh^Z%#* z2^@R`CB)v36?;Ukf@5M>fGfMHudQ~fOjEmi=UO;1O@^lA1NOs!o`8teym&2Y|F3#B zavX^rJwIMj4ZK(s#KM5rgyYA4^oT4rsSYV{Hh4hpJMSElk=5g7PN%lw zniNrePeN3r5Bu-!-0yg(!1f}~g0nO48x9Ni2&ntK> z@$Zd@_;euP`y~lXCdxjavJR%vUP`Yq9rdkeRJkNo*q2H1X@OVX+Tw;LCStSgl%o_9|tXN35)N@Xok|BQkaw)biZdTIxt_}FIT?G&e`+h({+9(3fZ zwoXdletn8mN@09_Pd$L0!H}V8D6rW@|Bc%x!u!f2TQ8U0bYQW9bA^oFyjcSXQg7&o{Pkn}{p=g2uKerX+VJ1w)hU2Yb%}pb zaWd@$4!XGlsLi7*9gF5TCL@UbtVgb$66MI2UT<7$lDO8h(V2<+zrU=FOlE7Li^&cw z2H;mzdQ2uO_JHiBb++ze`vRnT-6zAr;L5H@>pqgAA%E}0-xnexY5uY)wwqh=so@~7 z>Je~nDyphymk0gON(Zp#th_9hd8UMprWuuP4j&CQHUn;l>j&GLsJWLf5DJn-K(9kD zxW3q#0hu!3PzNtXD!_HRJQ?*y4j)~EHp6bOqXLilj>-5ehJr#ocfvQ~Zu8IV8a$<% z&D)tHGVoYt-39O4Yn_R=2jCfM6wg0ai(25BtnJL7YwPQ~eSA4g#I1?pMy7tQ5+I}o z+Ti`2%>H4{{K)m=VO{Q!tB!n&mO<*?_X=3nBEw36p zZHYv`+fm9wmnCT^mz;CG@d39DSYm+zYZWuJMQsGy*`&Ys*Q)$43%Z?5*#WqZwyJ3; z6cu9pYY&~^wmVOg7w!9(Mq>QCED)`qq5Uk+^_tJV2N1jC`5Ct;9{HUDsl18m5Y42G z?tHF=?cv)cr-`U=QL!&Eh~x@PuoQQ!XXAvu_cf~~;_mH7;B@aZpV)zhNmnp{_?_J9 zJk!ueq#IH2i;AkvvA>_iy@3nXW@=LZ8l1uiQc@rfTLCnB&Hjz_FK6?A+rP#$Stwdy zO>lqw*PN<)bJwiED+EV4-I^2e8#=J(7sKJL_m@*l`R+BJ6nn1zjBg$8Q*}MSo&f<0 z4P2Fn|M-_5aq-E*d|JKfE2@9Cp}{Zzg5~C54#XYM{)f4t|MyMHRr2kdHAt-YB`&^H zY1-Nl6BSj-lv4b5EqqDPDFhW;06h}WPF9|k<$_ssFjV-F9j&bSP(As#eTWD>azAUt zKCNT7-zxn9&Nrw$T=43idwak)l_dT6$U)9wB)iNG{r4mWsi#zCPXN^56)Lxav;Xc) z=D&8Fj4R3c-kC4h=|ul~3=OAnFE3ba%-adlqe*X6OHV}km@mWcq0G$vxZ)U;mVkY}^ z;t+shSD;DdA6NWF$a%FoLitr_$`$7C=L4Vwbm6ZgIc)>HKsX)seR zCsWUExN57o6RASqQ0~8#7_@%;ds%q2K9G2Sw|Nn?pQ=U8%+7t?OG$5S66itegUCx}MGViT{pD z1BrZAMs}bO1M3@Lt--BkQI*S|-a%YX=fDv`sb}Hl;JW`cECX{aH?FU*gTAEr9aSsE zDF~aKQaoY@ZQO6yLc~WD-SCNm?(zh9^|5-l8_W)^_EnOa)OJNU9t`>&22bJ=4)RL#}Bu zC0){I%rIpe#^qaoir7N~2Dd+(9?Da-mK7gBj~-1KxCfdX0w@M&2ooNSU!lVvdZ9mm zCivS5VU-P^Ld^DO0I>?%uS*=)fYMa0-t`JZuDqB$ruE|<`TX>S?)(s)XSbFMONHhK zhA4zQmms-TqJN}~`}DjK=sy+d6^(|saI@r5g`<_ZiJahnZzVnoXrPXT>UY`R|5Uh? z8e~z1F2OXy8uPiPPiMI|iseQTFS!ZjwE+5Kb88LK$FV=V9%&;u1KME+w8^BwJgsU1 z|9Q~@)d-!YHUZvD!X@KHt|_6#&!@Y_`)@r?wIqK(8v~=qTSB%t4!iBihx9e(U`0q? zW4P??07@;e{)Mcan~l~K&sPP}MfQD~aK5p7zen4E2$$!g;jj!nPcW2_zK&hx5+yFW zUWu8j(3Fthk<1>>;iHa>iT`gOq>}=oVjz!9IVv+b#!Oj_7#Cle@a-UoJXYW9sK`w5 zq%h+QC@qb+dm7~5KA``@5692Wfv>V(MX2I-U>Rr_XZ<}4K2O-eiH72oD(*(}P#y98 zw{ZN{aJRcf063?|E-9wcWG$oLyN*9mU1bg{QBYs{R#<$gr9e3>6Y$N>28n~kd%}(5CQ210VxrY6hu-G0TIr` zTYc{LeedV{&iQlxoQFSb7JIEVV~jD!nDZLf2(yy;_iMz@P8#L%WV|1)DV86W{L_;u z(qEnYq!cnylx#Nd^leHnU_z$N7koA{87PR4KMtS@t?Jf zg#E8c`EE@wHv4>}rcq(`#h-tk|98r*fjoUEt`1t+jvRkiMDB*Z{XQEF#Mj& zEyZ8`42I>ryS1+GhVO6wdn&{BAb;uC9e?eSK)b+9@8g1kKaH*X)lE-&yQguXZRr?) z1{S#RzpRfDZ?7Z zpYivQlRf-3AG8+F$~<6!nX*JXf0Wje>i3=WaynvBZ7Q6w6S?2EnaA|^=q%PM1#W&} z+t`|?{H@WQ4Zjqc)_@7i?)eudmb50#KRr4AWh(ESPtva9Y|P-5+Q0tOmD`xVmRtMY zm=5+p!DI9Vso#&4zWI9v`)617uRH&Z=lV;0t|muUlD@FTu!zzBd92j0etskDT3mwF zdnL3S{jm~0%)j*OWrE2#`$$cG>Hf~2#(MsmlN3tU8g zGcLj5GgyiX5(9q^4ypH(PHXFFPyO>rd|1PM8AxP#);@ z2Yx;gVctJi1%6!>7l(4I*||CRI6?&k!8IKyw_c!!9hBQh)7r_-#s|u+>uc@v^NO;o zl>_*P;cZ*+Wnms+D7TW`Z3jmmD6fzxlv~c-#obHS!^*}ElUv@-@3xJdqL)=5lv~-& z$Ii>c-Nnks4(j9O3mzbQ+s9kW&P&eS)x+J*&dmoZ0_9e??E=0AeqVo2-pPc!7Ge-Qg?VZIi7 zK>@)(LND|WLNEM(AoRR^JUoA-o?j4r{=X*m)a(Bd`u`~We~jIKEdGDA;6GaMA1(N| zTF^PtiQs^rP5Tcn!Szyq?Go^c2nzi12}J*=PXHG7pN{bVpHuqOK-K+?G+xJkJ=x(l zMcP=0EAlGBE+P)GQkIBTsumH11u?zz%E7OlUt{fwZ>kpV%Yp&n58{6L*liKmISS0HNelvW2dF4~(nxgYr!I+Y=(Wqwx zM|NK;*$w-s?#Qy}I})w5AMxlDFDUIKd?Nwv3~GTjXw3Me`;E9{i7Y{-^}aMyo$Q!o ze8*f(WLrq(xgKOQdwr}iCP!1DRSRQ1nOAM}=6bQ>yrKRqN~+BXw#<139g-)7A)j^= zlsq@|2VLL^YZReQ^BcVUw}dzjgO|Acl!-&t6{0d3`Pw)xqh{92q*1(goQ1exbgp!o z3|s4Ujr>njcttEN5O^DGQ6o<{;9Y6fJUSj|gW=os44Ij0jk|5@f=H9GSNN^M9+NBV ztw+>xx*xP%3NY1OmIuWMV)h-gj8+l6Dq{C|I!%*h^i-Z3s?i{^p|32TNu~F-m&*2X z@=M%0YYX4|-dj!U!tJ?s!nag2v2bDlYp^&meHy~(bwu$MKQ4f-Ey;^8Cl<5$3ZGy{JJC1R~nsqeC8^UwpmUefGLZ zXTDo(W?S|>YpFUX)eyl~^DL(fdsKr9Q5uH1IMNp~Iwnu?T?B^Vg~`s-hqo+h3BE0T z;X$|*8C?G?d&!MUU7Y?urS_*V{&ZwTh5rbx$lrwauW(K4XKbcr<#ioUU59)ikkhgA zcK7wNvGaxs^8R&2&K*Q!Za&^nforh`Us1QSy=^7y9)Nl4TIPj#`Jlq0d}i07*RSyL z=bhKDzYY|&yxeVc?R=oOz(;un5GmRPfB^AlTqyhNx7@Ga%22bvd&ki0+vU7@p+DVi zOi4))>VdZWysW1u0OkFwf!Ei62cFk=D7y+n1+PO@&{SntA*dkV&(Gj%e{11CgtCJF zC!s7akHEiTSz#d%js7iW#r!K~{gw;GOifWC5^O-8|>g^@bivxO`Zx2;F z8J7t>Fj^p{NL+~7q5u4+?fp)Rt5%2mOatFx)&KOBSXM-Tm^J3`kSUTVgU7s8(vQu* zKeXsX34wWa-X^6+V)tuS>;HV$Oont?K`b(k2&hVP570HdmH?nF|5r}WA)N?H2)IQh zc|0dO|E+y}8Pb#au^|8aiaX@&h9CX6S2~};8R>@MZWaO=0!B0@o{rl39kc&-mwuKs zetv8O&P|9n{;f&sn1x+|b*FYZ$P+#CQ4D+WC_d z)GUNLh$A9@6mnVi&fojm$*6S?g9zZc&{j~JRH57$EwtJ{Jk>E`sJ!OG&}iDOF43Z; ztYhobzVyhREI2>B>AQXTNi*bfjrL0KRd56{t~iU@7=_!kqZE$N-pl<kNVVi zZWTj_nD`Wlb4%8qQa2IF`iRaSF#MUYj3x-?raYC;M3+%SpmB=E4nZnJ8t0UCBTV>KUjyWC7@lZ@InLSdQ?1dz8Deu1`%oBk^R2HZT8s4AZ9T74^MY+7roR z&6hi^pX+=nglsoIcPep)NK_s^q zSb+{wlsD{R?DjYGYI?+jX5=IhtS>s>CBE-8=NubzV_mNF#58LM9CXDPgt>ZI!EY_~ zC#9Iax_o?%8^3O^z8Od#^Co@w>gsF1(f-oh22*m`NB#Gg>aQJn+??UB&P!+agN~Z7 zKE!d(6Bfe_v?I(3y=>2PH`9D^Zz|lmnbn8Ru*mL`Ka8Hz3C>wfYu;}rG97x@(R9e~?G3@n$-SpeBbpd1{LOL3w135FhGi|y( zT;Eo>2e~VS*E7$BrQTc4ucDR;=T$VQelW(yU0R|tO_4CctrR|JsnOIlBBHOYd}KT0iD4#8ZP?`^aJD3=dFuTt*g=DvFMV>hw=+me_DUECW1 zmwBE?FEd1H#9+u`8%6B)r63KD!TSdQb?LT)1Mj&P^s9j8QV+%c@(g4b0)7(zMP89~ z;Ya%QrkuCTr%DxHgU3qgC|wM+Ro4g~3% zE(quh92ji!9&UNefOKi7?$V<{|`T0B3Ki-O>?rXyCsUc z_4S$=y&=hSwoO^Nx4Mm+1Ikp3@CZCuNMx&rvI3U^#{fP7Cm52x(d)z=N!VpdHBjfa zbb+*pCIn3u+Y{OHf9EP(yLeyY=BFwl?INGIX=~KYZQBU;conSDbok zeBd)K`F#iQF-QfIR3vgEYT-A2#(G{((s|4__8}C}PNNr`|Jze_oGcIoUK2q!4CWyE zWPd3cfEj0TThx_(uKP@=%+_mTJ`<%OKd2T_qnJmlef31OyX-wz%R)YSLj9ZXGVs}U z?=U!tKx!~@fu?Om@SVLE!raZ4lzK1v`Nu^*gDk6|yn;6ofVo5JWPYvb5eZ9^`-fol z2ZcsO-D^aY@t_){*`*$wF+cF*Tjl~Eui5FfWal7&U2{-pJ5&-c1ydRmvJt7@@NFsS zAYCPYWwn76R(6iupi?M1K)IUQFrI9X$9vy$Aj;bQR#X3kAXLbCYMdw#ScF`aPw!v8 zc76VSJSB8Ni2#D}jMUe2T62!Anq(_?|2|;4JvQ##l0{6`npjsqq&7yF)gT{u3F~=d|eCxJx zK`a0`3@td^fx+;w;(%mE2q&LSPd&V98*zKNJKp`&k;mffiw*$mW_*jLM3wD#Ua)t| z)&Edq$gP%U=Jz&JwrC|OVq(uOYteUZ_n{Zxt*FzRzB*sO#8pIN`)hiCAvF*Fm=>Tz zf4@rKK{7$4tpB~Av!hGGS$uvhGOkqhWu@?l5NTZqLx#d5LPXV`Sd?-6PXkk?)inmap(srm-KWI<(@07`P#Hg1juz_R@h`#1-Y$UDvefY91q z^9t}S0^I5~2=mQz_Yh)hgC79b`0@3_E0C(7gO2tPEYdH4{l>$-r3BzPr-1G<=Btvn zUL+ed?i8fc-UXJ*cIC+oK;8_AQQsipD8i$m1B@~Yh-eLvSN8@6s_zqqq45F&I)L`v zf4SfB0hrHBLvwNh!*zLS-RF0`5%YKwMDcxNxVqS@4C}jSac?^fWfn-wai4F%XZ2(n%dc;%_G5;@>YB%IzBGHuezrm+4!jVMuQjtAiVd#thiy?TKCZ@aP#o%0klPZ`BYO5Ye)V|`o`!t> z9C@g)TQ^wQ3;_^G?M)i4c6!jb=%%guSeYS~a~Xi}-ka4MN7N#!$uorn5Rq>d1lShn z9)29(0jSjlsukO5u9rI{Hri!gDr{y7)p#nYgr4hZifn~q^-8vOo%A(Khz)udGL8H* zWFq(vo7ya%yZr!kiB^>(aSfc>d81Q50IICw^hw|q_YMEuyqgF|$8TOQi{uc>ARHCq zN;Hze;&S!t6Ibr-F8D4aE#bwxNKsR0)9t`Xtee(M&l}_f_myA3TwSLyU%Tej@*3PzZ>i= z)kdTd-wf665{jJZE~d9W*w>Ie(}RDp5EXf*y!nN`(@#0@qAS0{(jsn`0SDeNt=5*0 z-X{AjUf%td5Jv#4(|&B+<}8E5)@9o9yCn3TbcO=S1uJ?j$*@|sK~_}AiWQ|oZ}TM9 z2F;z+1uX^AncWVt7!As9gq2=@7z6tru)48?o;!`|988LDJYYtsWxnW<7A@)|jf<&P ztv7Ubv7=C}8A(=ESCsmJ?p<4jXxHZ+t)F!fkckmS&$A8QM2PI)WzLmk3>CF{fsTO6 zBUe;Hz=t26H3)GvvOny>SIyi=cCOz&9HdX73S6JGX8MdE&!W|wV7(~rj_7BwI2cB;g!l*n7u@-UhP9wjF>l~R3^-R+a&7cVqaEUWQ0_$kL1 zn=V}RwB0aT*1h0XId~7c^k`XLgd>s=f56oC z1+wr;CvvVu(*-xi2~^2037t|><95lX^p2*EPl-P?SHa3MV(tnsleMD&z4dM9?futg z){?&aOVs|-$`1LS3Ls}ZQ2r_4?Tgk_T2Z9(8l)3m^gzCWU#gI_+KHOs1|g)S6O5`lPdt9zQ(TtV^poUb2V8yz(Ysz&d}5| zDji^?9{?O#&gn|ezV;|!LvyhO1OfUCts^jE9%dx|;H5UwK=&X}mIL;2JlI+3^=C2_ z>$m*Q;#2^Wx%TAE<;g)$O6->pSC{^S4f+H5!6Tf{;{Xqi`7F*2z4`oDR8mtyWmgZY zZ+y(wi?a&q8qL$FVYy+V41#f$ANoEf}B7L z0D9!^0EFNbg+b>RMAeaCdS}Qo+nwV4S36UPP=0UaOn+y<|$VLxx% zdb%p_zH&E zKL>#S5BI*Awb-rb9jYAyW)e7Koq2m6H6xBnTGX1{4k5_nzglSVq*p1FVA?CuJXw13 z2}1-Qozr#=a7SAEA;f^3M7X1pd6fu0wV1i@H8>BDVhm@nf^H2c>P|6cmnHMFCRTJd zve>7_&;-T4jVbVtqo~2PxCHjQK+u^)mw+)QlZn6{a}A1ZPxnzb5|KxmZOm2}k9qpM zU=TPoNAc_n8u=n=Pr)K4w&?R_ENfWm{L{iyb~_ytIHRdYSCk_LLrQfQ#{l>BP@PH( zFk^yb7)jf~0zCN~)=L{8Z}Zu4(|11Hqvt^-!nhKkVo)o%iG6Q`{;(EH3X~FY+4ES= zyoJy_bY4U)F+6TBcUji0A)dR~&$r7ctse2JNsah}- zr5gby60Z0G!p*R@#GrE%+q7VYCfK4^s@G^vBh`j1|7gDG{V}o3)M*Llx!9|CiaVz( ziaZuP-w+!-2ZJsGZjz=I25sNYx9|N#k6M!ge_Te9Y0RyA4YjSKUD4GLO|oF%<2RhN z&cVzTb9&Y)VgPd>&JoiP+ZAZ*QVZ&*r~;+IheqN=00DzcUlghNAp6V?{rs(&0K6To zYZg%97S{WXnnqQpC~Y@o7#`NzrZbv9AiBl?oB6*-spM+iDglbP51jNICJSyuqR)y^l5Ti+M=6e?p^mi7R zw)&92R26Z&&nz{#mtKp{gw%TqfVn)k(gb|AK&{-%1hf}Mk8U-teg&nj!?AI^M)SVn zX>afYJ_I zJgbQ?Y%OB$P1(>PFh0?0+=AH5;oo#q*|>3*J)6UOU$Rj>rx$#(cmQqSBzMjTt%+jq z+7=MFJ4AIWs;+CrX?90kYjYna zm40%Z^-^gTqUQG#>Wl<)1jAG7!T3avsQ2j@eIr~iT>$()pabg!Fx0FrAGo@*)9on2 z*t>UEVubrAqp?xB2P@3zHv4cLb}8luCyg{-*kG@!Q29>tN|T~t1_e2QvJFZphp{Hk z?_1Rm-=#lQP#~d4`cXxjET=?rj-M(+^@xNsKZ6jFB3JB``ra`w{?Qlrknfa-J6l7f zv1K2FdqdGyZkJEvj93iZKfovRxhog9reF#vt~l6{W2pUd;=2>N)+#MtNm_`@6o1lH z6~UiqptYLu-I_ogd|Qg-1v7GL4)9|!3T{-y)w4i?Q{E7>gMXB7&>DrM8?PBf@CnX1 zbyKP7u+&fGV{ejvdv@B5(sUCa5IkF3^t0LR z)AXe9tBM%sY>@FYw1Z`;_M!JQq^IYcfy-h$5tBywdo%h4 z^AjJ52-}~9oJA*RX6Ye}^OhS~?Jc#7jVAEA*jRSneQdDIW}=FZ;k@F@< zp2_HOj)SO5k%G#bjtZ~F?$=J{kS7Mgu&~-Jwvp)T)TUq;1isjVzIC=$x8^2S0SH^T zu2N5cB9mXEeVyL=D8WXi;WGzs=0);iQnHT*ND&!rxmu7rJ6IIPo8twawvO!w=+c5m z!)}SgeQ`nB}$5Gnf>_wZ9vA7Fp^;rZN5{c^VA`xJO4&LI!U&NT&=kdx&KLJXg<1- z2uIor*1&tGE{|2k;% zp3`(~tVMuToukoy(+*~i{_E;kMo%J@<7|ti1sFySVc3lJZE@9AHVAWf?BkmxuQOFX zi|ji=tUB{!&&TR9)^hp$cExlx9jO>6XTU;|qzI0K!y!HH1AzXb$fi8sl%J{pdU#PX`glDXi`_`rCh<62M_?v`nCKTt>!C{5V~s z6KK0T$AT+X%ln9ab1Sxs&q^={;c=<-j#KQ{H=fXRBlJF;UZe^?-6$e+DP3nk zg$G_aZAV18HFT1D`o{(vVXd!iLU#07)uu; zrV4%|BIILo-eayO?cVQFckqkY*9GPGTsQ@t^v()gTDl9Y-F_Oi@KK2cF?nNL8jbs`-HGwh<5-Cd`J5I;@Fm*x%Hkjk`V z{abC_qA8dLBqDTei|>Uo^Apj$z$;UIP+k z#Ky#RM_PO}db!yW#h8G-|6;(KMwGD+t!3VNxePMkrI6evvJCiwv}1l$0J9LUfuzLu2pMhq@i~yUbSYm z+w?|!e9Z{(1nww=ie?deTxP(xHSld^G*d7PfzpV<%Ja}KaFA1hi9qbf@hkk!jE!E^ zJpwfYD>`WkvSwYm_M9;*9oUMRY9``52vWrM+inDJiCoBsPL{ygDaNhH_{ZrrDKLn>&|6y@v# zo-hnTadZ<%xWJ~SaQ2rb%D@ov&xJN6Ec)ic%Um%ffZmYGAi;tN?fw(*M&K5H@$&{- zByO#rn3|gBLj5~cm4i0ODOlp9Rw4E2cMDHZ#Snmex33YKhW^@A^h|4`6$>M9T~yTzt6ie@5wZs z4QI2wg}kC6kDrfT-4p(FPIz8!)O2CY2PP7x<)6~Njg@Qh5g#k~EL4snhI3(09?QZW ziEgeAnTCCY@1QZYL)t14^HL7-9)jz_(jcx{{{tkyj`~jroNZLitpu)x@;t--7%7V1 zP(8kp4F3i~LOI208S%CvcOpvGLD(99LXx{>%l!(8b*@|I&=7bz`7l;^^8sa(X;T&H$FYl*kdV{50TcS z>~CW|1lvB(fsdKtF{R9Wh|T!SdT0cZc_(C?9=LClFZWv6{i-fQB9}7zGok4w^XY>t z@>F13xXmccBI3LB*}}b|n@y)0@}oG_NaRK;9zHu0`lSry??+ANZ<~VD;@c6ZRVm)E zDL@|1lHO;FRs8DFE60JUhp<5MEP4`biXDRr4YOHoQtsg0G(~$=QF^>?*qWItDhC&8 zb&heBRgZ)br6Iuyr+#VHThd^#$wvIP?JR16-V$abOs=bY*fxT}yJ(+OVQbEFQGJ&g zb`R5YU&$A2^{pLo_e=F%Gh5#c!{Z}+WYq1uZ_Y7trRiY)!uj0d{SPU{hr0f!d~hMM zcF%pn*H8B}65Q&g3McD0d>3b>_PiazS=j_NN_rq%@*%<&eXtn9mp-JN#e^&)Nx`A3mc;yj<(|e%ouBY8m|P(;Gt$ z&wyw}7u?7QZ_oYqZ{_#u)|5BK(1lP=ry0g%NH;=t=Wq6l(GHh#edlc<>ke=@M#?by z5qseh-4{0uc4n;))+A%2HJKa5yAN!4EKhJL1e6Z5 z&HTteFm}FQz9un05|nx-t7I*KNXe=rdG#ELk66~MY&AuT!rhx}L*KBxX_5S~!Li$_mLtiJ6AZcT+(1ZM7 zqZ37R`Kc7(lZtI*=*F#=D_zoBwq3NW- z@zBzPM^~DV{Z(>GD#cgyKR!_^fYPitK1zs{^NCp!0*%w!32{+sMc9{CR=Xt{K&Lc(Q*$^2X@}3 zOktwuFcPQW1sDq7cQB_}2@vhiVbs^VRt{v0JPH_8tI#O0@&{byi-0MEyghM`SmxW_TvK%lUs(cJ1~^>1Bjc*a_s|jDZ&Z?r z$l#-)pP7@8lWXlr8DPR$Jh7LPE;m+3*}QAE$94wdJ=mF%-f`H9bT#-U4Pky|3~mz2 zf)g*TqV>1cjrT3vZHt1#Ya<>jH|sUxox?NyAkHoYc(r{+dYINH+$N>|5{XrLo*UCH zzHQ0_-Ijun6`Pum>7>F9+l?+#bS=S-?ExvUJAPDry2g$Px-E{-M_H%G8pd`Q zp|A$M=H*(6a?im5j%}V!p9s7h`3524E0EM)3XikhTPszwKe<2L&DWest~6okeEY=% zy-^cC+8p6V?H)EFq0e*am9g}+dRDw7osL5kDYUi%m=`DSUNzd&r?pifx*wc@-Bcrj zd_v>>XQZPR^E6~H%P$87zq$qbeIt=Lm6}hDdi5&*ot4-|%i}9zn)c$QUGJ-@+8#tS zdG9DjBGJTlP>87-jX&f#+c+Y(inuQ|;pyS1UVmv3fpRzE3Ta&J7Jjf#Z7VE1J$}Fg zb9V*Zoho=)e^$x%BmL&+Tc!A3a7F{U@jY!2LfgpJXxQl6{KW$R4+L&|-Nn(i9V1rg z=MMAd>P{4sKdmfH9v^028%zvA_v&GF#&|*R3A^dPm(C?hLe!YM#vWPQGB&2ET&_Sd zl1}s)VI_1U6tkvdH5cXns7zjfcTR?JQdit^FbLA++`|=B!#P+DZmh^pWKq0L>^!x# z2Rz6L^Xf}r`@h;HA*i2P59yg+`t(+1!B=Y*uf^;>9hc~M29Jf?ZL&U(ICTx>pAq)% zhfEZI7nJmS$W$SC^StZ_E*IT>cjnZ`!d(Cm0L&9O$ndSVr+dmE_TBWZJ6fq>Ou(7{ zHN(Wmr(Fc@k~rb60tblLXZVm_A!UppyaO#LbNEc+D9TlJZqwbUOn;JNnD>mzfvH#t zq*D{_Y|SXLE(+h5`U68D(nX@GUmY~%bzb!RYz@yVHN7hq{(AoKsx9DQ_>t;P>z*{H z^#=50HgSS#>cI;b`CD8?)NP`16 zLvWPpF`G?FdzvWvZVz7RvsqW-p#j<46S*{mkyJG|+9)HehdwO0vlaOHzo40RS_oM3 z3B%L^$_IbMQjY|2qqucp4Zigp$nf6#jX}A_K3P^|OUo3Xm&FJU8j3k>|A^J$@hphx zRz}DV&7z)+Sibe<();g7DXlvUp@dzE+n5XH<`I2->#AaxcGKOtAH;%&ERiF(*wawp zrKJDm4S#`yy5jKeb8sJhsKt?Lr^Na-_Ms`zyR|#Y*WFx;Zw&ToSlh?5g<}`7pv9YV=NTX zV#ukzC`s@AbmIVP!e5OMXQt z;vE)z7RyreK#tYw!W$nUM&2Zc>>OoRJv2aM9Vdz9MGT@&=6e;(P`RQ)#&lIH7;%;_ z!vQ;=dgd47mMJw+LoW7#%oG_`)Hy6x(H4>!$O?b*>v6jvy7uu;LJ`j3a?|UCB67T^ zGu9pAX%y+!5sFU){3J=O1``R6XjJ;{+nOU-aV0RjT%xBLxQO6B^3I^nfbEzn=Wwxi zF1N^{OQLF%){(o2wAh1+5fdBNPltBx5O%u_Wh5mX)1t;YYd?oO&$$WR%dQd!fgWU!S9466NZ^UDCvzXr>DSnrhTGhwT`_h(|(bBkIUa z6V4MOAl=F&8(>@ne>NP$2{re43-$svC_`V9A;nbOixk^d+$)<~j$t&y3Why2<<(p1 zaL5E*gGo*YWFRD^a}+8KYx@p&o24j>(vzkv!q-e+)TV}V4G?=B@RDI7-frngf9Au< z#`$xQ5>e)`u+ZkP-1sBk*mdN|oXSM&JYH0PNnjw3jLr8TDsXzMl#4MAQC)NK5GmF$ zEW;j;*nQX#QNP%D3s04E*b#OuF7RI#`Vy7-asjAYYqrZA)t)R$$%jyxyUlJv7zj*opg*dk|Ns-sI*)f%v_BTAQ)NkSnTssE@+ z#BdN#yQP)^&8o-KjsUuBgNLDn&g!~x&KB@|`f25B5iD#}I13s!$s0OJv6m#75YvQK zPPV6=)KBpg`O7L6r?IWQqEh11K583%ln~I0t|)A9&z#h|ztx9TWg8i)=fx@pfz7_( zQf923BJ!&6Kf>44LGz^(pu!-c>5Ic5cU zq`>24ZB>=k+hS5!560>l_DT%zvdNvVYOiH8cjwLNNlGY{4Kvj9eQ`W4leI}1-T+b+ z$%q`ih8d8yP{E9F9F{7|$wq`oa6$;g(LT8>$IA{H;r-VXH< zxqPrLXBivJP}3pP#LAYAy`a-gDq*fwbX*s#WYH#I4NAi|(4O$Xcnyj52g8MwzJ|#F z#r&-x_w!iq`DGC;+Owej)DQ~7rtElk{+vm!p3H%X%S~<4EUd%G@?IztR8{jZUi;R( zGDBS9#-txHC(~#RPoIh3227z2a%kQ8!pm6nr>#qk&JapP_4`YDug!&9!mwoa*k}Pp z$wZ!vH{Me%L4}uZ&*JCI_=!yNLam9iUKO=rddHxSe^mmsU3?2pY*wpq)O$*$FQlJ} z7{*T8F>;93rAGWTckp}tlPnX|U?32+l_-D_9fL-My?lq&H;pxaWGaF`szs4FU8jW9 zYqP0pj6WnINP*NlPcQHhKQ(RY7#$Ijm?da9GE}v+FmVEpDO0I?UbW+G034 zO<<+xiBI{3zZOyIbZ~f1Zp(e!r)6weNN&;v)x}q@QGG(m+$tG0x= zA7B4Mt~iXS&BNvMR;9pM8v+~h@aK#dz(bN#;Pd3%HX&m0*eHjq*EBdwn}@{@`Y2aD zI8Kp>1`gbzQlZMz6zRkyU3}*&vtD}w!il$7Na2lM+Bk>f#MVB>bch4QN(a2Lc&7YH z1+Dg}5L2+&csxLSH?+%+8vd?C3CjA?>|^Ur$TVLHPtW}HL2vxpRO#eFWdYKLAX2Li zZ$>GHIDxVe?{Im;Y9?HW;A?u>lwR`8U@5RrUZ!tj4|oSX5OC|rrNgi1w~l<#-sAhQ ztF}7YV3)i$WK6oe_?|`%t8z9E1|q2y48w!e@Y7b4Fa`Skv;>56(+tdnL`03Usvs7@ z@7}o1#Vc&`C~Vy1aqD&LW&U*xFhUBL*I#|W6LOh2Ba?@2aZ&P72-ek`CQvXCd2ntw z^DBA$lrQAr2{m+M1LC)aEZDs$_5zIr2GWnvqXz5g@TMv~HlorIstih-Dj|N0wYGhg z{_=7JX{J`@u!>iQZl$d6C=%c0E#sov*Rj3JOH0wsYx1h=Op)%B5Uxv4pLsI(ffZjo zyQ5a68Lgm3%l);{nfaH1U=P*GhgO>Nbqk62GweM~qgqs|(Nw#a0z7WKi7eB0{60Ln zcLXIsK%IH=F04j?%-IKtc%odbD~IjLzI5j*-5NdxZzpwA+* zD$%I3yf@bg5UN{l80Jr2!^H5&Y$D-YB;%kK4*?i)cticxmi))A?ypdlBI#$9BW&fQ zY!g^METk%O0*hng%(Z$O*b+BZKXH3`k|trU;P9rI4wp|I$GRDkq>rLA*P4>ppfI%{ z;#Zvmq!>@#>WGRt0r~CVVmso8?7mue>i`q&SFnk5ja%4$+7{H{VXBX2sO(9Ms2`rP zEc%g5O~s&^G$Z=1ffd%rgcE9fL**eh83e^@)YoU@B5DpM5^_Pw>~p)z%t+M`+9-!q z3`07Ra@@G}k`ZWSct_C3T!(A;DyZqF?5>4Fx`EdtFXg{yI-|q@>3e<-GcA9i`aZu# z?ZyiqTSnV%+(Dv;y?7G^2#1!5FK?T{s~v_0?e0Bp*n_6Z>I`jgtFV+h>5)XaYT;od zsc3i*DOO(s`nE*&09|j6Xla%j0OJ9LZr#D*`Zs`r1aN*HP%DH{HLDVSTbW4SAkzzu z+dU8PJjs<-$c2pFpP?!fa5lvEpSl1dB?<8C_9v2;7%F_FsA?fQy_|5^mC2OTfj6l@ z{tSq*L@Y}S(fC3HAhmt;jW%!{f4@t`4h6CF(MgfSU&HdKUac78b#X^YL{4`hC|3fA zqVe=fA8I=TEUF06l#qoIfMHY}-E z3Cqel(#jEmIIUN!!xW<{QOPb$fw59xFBM-dv}DlkP~60*TswTS63;VpnI&28u?)4M z0ogXFJ;4%@M(zY^khGi-GHU?bN0o`0h%uc`oQA&APVd2>nZzIgB++%LO|%}=eS^*c zjNIe7S~UG-06=Bm?h-MLdz90n5?_N}NpKhPdiKGKfg(|SQ4jq)K|IfE)4TO`Oc~La zm1erV^T{^>jh@^C^<2IUKxrnYZNry#BZ@@vxoX1A1%Cr$xOC<+eL%8}#be{@&Cl7eopVm7y*E)*DqPRm^ zZ1G^c5-_>9C5|S?j}a6IjOFFT12a`;tB7R@NR`>*#WD=?R`rwPqjCrm??V(l%bZZ3 zdS>1-aJk7tFpx;z1Jy5;HGXW=7)~7zN{R6=`ARD_S<57nyMEoCDFfuSCqU$wUfPy3 z7+?&RFwByt7Tdyodv&2USAc=fAVrJ&)_tPEJY))Fi|8349mOOH6n9Y6GTi91`;!fT zHiAYIRHB!c(ex4rZ5785y>Og_d5z_Z>J~UkoB|%jNR*}~ncV;uJ+y}{8rKz}0olEp zn+MA4)zlJ#Uj03qNV!InHOG{nqEjp6C486Q(QX>=DFCofeLt=W9eze+wT!*JWpS1w z-=trxEwZ;t}Rt2nw2?`0kYlNTU~O`%FZ(z-9!B!J?2>soqpnD=p@PT|PiB z8Jldbi*kdtciCAk(cT^^9leS&BrA4UX^>C4{NuWQwy-)@P6Y_@8K%XSJ)h8%n~8!- zk)$AhN{jK7g&9eF!U$q5T|L;5?%W1S63dC@42zWEW~vZrELHr zDjzJ&Xw>*T6-04ah1>_Op$T+D$TmBK5qqGT5&J4;kXb*mc%{RQ=?G6-{c*kEXDnE6 zFgG&owf6CJZ*Y>EP@h0k1|gzKl8cP&Uj@Ub`brB-==v>@+rPw{m&-_p;$YKa=yLm; zO_y*i>X%L?gr5FQND{^PTOGAo*b`ytEo7lPx_F%#>9ssx&1g|70SK);coSs}y1zm?qn5Li5%i(Z)XhzmbLMNSMN;UBnx<3UtY(2vvH)t4AfFr{86EQk>F^5{3zP}nDrP1n zeb;molM$Dciemh*p!^3Jhofq2Ie!((#wdc!7y*WaDaLjHmDdpKtS6k?C}n+1W)PF% zr$G?76Vb0Sr(9LNOQ6BRE{eb9gzi%upj~X4$$*4_OB%s2oK_Voi<;Ubr!|;}vn!t( z_2mWMQ-K>P8PKhgD{_?#EFXOiP%g#va4=I8HI73Iw?9okk9Cuc1T1El7nPrf!iO9z zq0lXY(EfB=61E%d3er|HWRmIc)6sR4X}XA`Dm^~=tp@6Gvc-6Wmx|~-#dd0GBFUAG z9i$^b^ zBs$^2dna9<()iI@+87bd3-p7^Z!*0R@>WeS>6t8sI)<9?RTcftM16HN{FcAg1S)T= z1r113Iw_VxSY<0&F``sZt`ZfZV{CSSo#~L6^mHc{Up_h)k}UP1EVaLvm1A1(cs3>? zGNuQqM$smLDKVE9ZnfVgrYJNLf=E@haNOLgFb~C&j8c#jQ_-X#F0---vxVy6GqG-h zbBibf_>TqWdPF5I0S4Y3`c!R23Es-s?Ag9vo!!$xAfPGL_)(+D$XikDG6g?wV9KNs z$hECu8tX4aOc4F0!RUoiw>;p|Rx50G1&oK{I@R&YCp655R0ey^;BL$6{irnsc&g>d z?yEg(YCbV-AVKwSU>7GhPTD;5El7H+hQmg?!2>11Cz#+m^~{2Hc3P=ERI5@$~x6 zS_$k)=%?$$8JSpju!_};hia|ERA2Zcr%A{&6d6Z@L+nA746@BZ6*==lq$-uEywGkD zoEB!&QR8`gk8*v%6Dn6c;E3aS@H)gH+6&N3ViaD+uFqvczs(6MvTpmhUE*5G4009=~}d=lr?i1 zq=TB`Km5CKCMmRWLd6^DM)yFu&C$;XDO;V0>@ItTB`u;Pmmu4pg=od+g*LTrM~MSx z>vc*pG$Hj>r*qWfywc$_RgP)Sw?4s0TPlkXsk~U*ZK_G&%JdDZQB`QVkwiwLQ!zD~!}w7i&)tOLuGejOB~^Z| zsX@+&x*$$=!)QOpUg9tnhx~;{@HC9MWG?n|QfVY)Us@}aTHk2AH@`fmo`;Zo{Xz$mFN>BCJc7y`0av6#5*8Sq(^^tg?1) zQ;D>G8Y?>^F}fjv*Wru5v{UV9rufCca`!Qsw5>dya8M+FfJq`!e68+egpaU6F5KEq z`_aUBG5&pn&X`8ymr%Br=g-oYD^C>rq03qoTf~R#gYgJnU!;NeWW1Y<8h@uUO_tNCeVT~qMrmZ9y7Cz&{( z8rLixN#%_#dow4Dk*p(m&xmfyC=xfp5SX(tv>0yKZkc!6Q}R%?OiW3W@-$#undIp+ zb;(KV5GS)k`iNhlrIC>u*P?xOJg?3efVNHUOA}q9AT)0&r3dMW3qTwx{O!H%7+lEX zv_&{%Ug(AQ9mUqFNv`WCWGWa%G5=D}n#HE3$rx5f<4GN^yhomo&t%_4CF-{8R~su> zv23tfdg2Q)hw~WbL>6db1mVKgRS0R>ad{F))A&h8mCSNh1_V_6V7ZfeEkRm`wa>Jf zco#b6&XyX`hRTsJ%ES)j@)W`ZbR`CFMT+Nf+XVJyM#{CzD)D*}4_D`y{^eyVeCZ^x zto%F^VU^>ys;vQGH;Ys^fa-Gb%#t2%%UE_o_tfpWLG;(j;!r@+qQOGM^`^ zOrFR3zP2C`%O8l=T@qbh$+OsnyxtC?;Nrj^>?P)veOWZ9=DIwo@IZsZBiv+A?{*W5 z$Q?EFUCGpVmFETM2N(u%0-Ob+V!BT?&Us^di;EXp2>3}}+Z5m7Nv_RjS1v-eLrI+y zvVVJm=!l41-M6QQMo!9$$1Y8#vKASd`e-L8GADFUeyBi|QTjC_g>`IpVTCPCTnc}D zf?TPxifI=aC&7_ZEr!aMG}fr6uOquzp$f1y{+i$9s5w&W;Xcpq3eL;g~Xhrg8 zf*C~yznHLg-9QrrE15U-3TzS#VTm+}3F0+BgPGA08VZ8CZ1*WKEE%Lt7-c-oaH^1=ADb>xYqR~(~JvD8Ur!rkSX!l|kO z7|2(Y_6|j8#iqH4CeOMdVWpn_h8r85^(}2t?KZ2y)Peak>=YGSR>isk#reToG-3_c zP!gZS@0?qNv8dwm&kfHcGBWrNG4zaauM`h1fty^i#;ko{x*|X%mLxh^io9Z0NC$ej zIa%Rzs1mhxfu|1bR5*}C#_~fFUSl+pFPt<=gj73uo>0d&GH_&al6x^nKiau{v<|zs42|)q(hSU&v{b5kZlD)QKTUSR6YVn?iEU=}edy z_Y|PF5L-{sIU_8rA1EQACI);Ng~rVPeMD8t&=Z1 zfVY;iHdS(jR}40n*JI=Ng5wyyx*OB@KEAa42_de0x`jccE97d|4W(4nadDQzg$DBI zz`OXa&~}y^RDdl58x=}y6(Cw~C=WuA_bl^@BS)m;L9yo$LmQe(ah55_mg(w}!0W8Gm|2Rx&?b-2K9647|AL*7`{I zcNbD+dSAa$-}b7Eu~1!XNMLJ1cAX>;r&FvPRa*ATEk%umTP9mLR;q4l+S@A;f;aQM zM<%$bMa7~H1S`l~Ob66Ri5({mRlu9Ps3Cf}=T31uR6bk7FR`N8@vA^(i@tkXTxOE; zYabu&@TDJX@n}5kaIe1RDgIJl_Y=-WA?UufB-6yOI2-M&$D&zo*r>^)w0Fz(pRy4SDMNngMB>E`d5wU<; zW7PxkmMM$LXYsyO*!gZV!RaB?Zz(<);BPM$5tx=G(eftD&BV2h*}iJ&t+H z9lv<>(0XN}hN0)i3>c$z%=f6jzuDUri18!ivf7q)BN@YROz|=y=HbRna6$ZoGLVUIX0>(Pr>*sCj=YiG2 zB2LBqC@J&7&e7ObE79AN#qNvuy&Uv@$*~c^j43{GXb2-oUtIFCZuzwz_1LP`#F60m z8rxDjj7(MT=iBfRED>Y3vcIgXpgk^WBrptSBf5xdu{%k(xi;vhSLosNt&9ly-%0Zs z-0iXU$|)x3vD=AV9w>W1K1_dMru^=GUO($Y2!G_wsl|G~Ibfz6nR9A-F)r4i@+u7G zI3^Zfq1y>BhPV~ba}q(^5-IZypKKi8_$=)zp)PEy;0#f#ObA@Kle!|OO z9o^C_{E}D{>lFgyL8q_XtJ;use2<340`xltW=o{I$m3kV!ZTvrRp5P0YmqhOg#plf zb|uyrr9ZF;0~S+TFiTzX!1>#YVFc0`NBd?KM_i}`Y$BPtxy8k42o4=`dkbP+xb<9= zEuIZ}f~brN{EjnwXxkh0?ir-BIOAs2dx@2jj6|Z>jp1lZ9w?*99a?v2?Vnc-%6^eB zHv4x;lnawp7MC|AWz?|!_zxBhS@}7SD*qwFkacj5J@7ty??xZTX&P}7kDZRn~Q#>5rbAm1go!N zwCKe%52{p6Q2Y@cjeO&)wjul?47^qJ5K@ zC^uH(&_OGPggaRwp;oTvVMtWE>3_26X3j0L{AcksDMS9$zy|&rcvY++c#k&IjShkc zt~gvEm_6tcQ^9w*&N9T(3HDndHzd-ed)&Xflh%V1cZTjUEkI_I0KWLvSK<(f73y${ zU8lt}1B&j5+aw>uvFp;wAIvQZ1cX%Qj?ElA=^Q-Yw6O)KTDW8A8Ml~5O^l)FqRL{A z#^jXA5MCOSO{8bDV~o%S5dXu?!_8*9uhm5M+Z{Ld>?H3dlRTu&kp_M>(2rh%l$E!l zUQopWodODdEyOY#)*tNw<=8Yg7~B?{4vg8Pw`;ZT&r$_R&$zMG4U{R~8nzcYK#4Yo zz5Csa5g+UwoF=>D{yW&1@2OSSr@QB%ui4+8bzF~_s+a#pH8?ZIK!!C;KTXE_75%jh zSAXm1>Nc((Gt95gJ8T`2^9@DA0FdPP5w%S6u-bT{ROu%?h6TZuhjgy_5M_9EB#l#* zu5JLL1v(4DZ8{9Yl;6V$II0_>vC~m?Xt)KIP*G$J2SlDT`zG1R-{MsNFt%8~;`<0Q zqwt9r|9_-xYn>;YgHNAt;d)$Phfm+EnyRA2IjEL)jWMA1Wd}@@9c>|)&_s70r<~#+ zc(-_);ep7VYR7WH+SbU7YQp>KK_?k0EMEQ{&c_p20!kAdes4BgxUJ&d{d zc4lB@{V~84`8(8S8w%XpWCyYxE#V}=822QdjZ~5>G)yhld&s2KRgi$n_$C6I;tPMO zac`*%M>HfEdWDnO_jYz7sv?7#_a6^4AiRW!x@mx9g?EU#urV;+pM#iH+>P}2)Wnv3 zd#@I=0l4?~zn-!$_0k?LVUDQd{oqr9eJO*vpq)s5-y%?p;1$><1+2J_w}q+K2#~&S zmAh2x9Nkhjd%E@sfTs1(`-P3`paCT?A3iE4wquDVH02-$){rW@ORtr`ma-W z6m7z_%SA2#xVBE)G2x=gVV2wiB>o!tpR~Pjn5AZ_8A^2&t`yEe=4E|L4wfKewoepP zNsvpXi2sW+6dY>V{D%8nzZoxykbr%&ynvB1dR``8LH`zcIwbO~D6giCBp6v#G?Im2 zPBswJ;EC+n?*rfQy}kUweVEYy!#z-_6E&Ym1y#kjQD3L+%|E*?k9Ym!-yb&bKA*g) zUVFMVrK22YTT5^6ccB`2S)3{3>?hi)`W z5ynrrfhQuQ3S%+1u&gPy(IZ#wpMV2r%gGUHL=HfbxKnoqig=-wyh-giRcCA89ZT)E zZ&^4_9lsbUIMyNc<9;YIT%o2P(cXrZN#DEo>d|ZGe*Dz}zWfbdmoI1My2qqnB8z29yx=RHAxmxoGEkO}r` zfPmJQa;ZO$f6`!@kB{>+FJLYG9ajx~0|bMs`~>rrfej89yEY?cYc-5l#EYIStXAbc zc68)Wv=z{7K_1TM`TZous3~UsS`9x3^Nl!u3}Z>T;wKqpUSwvHF6PIqhm-d$NVuZ69y-H~iUZGZ|?CB}8B>2L5HNEl8;buwh$B%um7hH#3FV>8o=H5Qb z`%;SC|M*nu;#qi>73nW*z~{HP~N9Ix2EXj$DGyhjE8IQKgCah z;|bs2y=s|x_h=_4?Hv%eqG(fG@EN)Xv$aDgO?0?T?}|9hyR6o+hFX)NKl?yi+EMSa z7sKcB%JzO++e~LN%kzD;$se|-=vJmrA#LDwHN)n;bv(_{L-GaTgM`n*4L9~pwDQ#y zL+wRKMX~|w*b1c~vCP;`qGva)K}88~i9r#7`7Yl3372xHUMg_qx>Jms%#vz3WR=B5 z1astX4AU7KS|R&GRED>?JJ`q=Pll7Ff(HTR>)rY%W8ZFIBTJr1lyWuve3@HPm(N`B z%kC${tz$2NsSBPwyuVyGSRq91-lcgd|-4%WMXMd}%Y-aksq0Eq;_RQ-Sx}>}8=O|m1a%`(%H9vzb3aPfQ!(2qU zaS`K9c*}w54-c1i(z*+pyzTdsK{+2@?kC-+1r~jl#SD%e9m6^ho*J2W+@2m6sLhhI z{SkN7T6sOYr6t{SKav1e$Pb(@evST)cBRectlKc$`~Z7?`W89v(85Oa%-tBMqb-5 zs?Pc_nqPG%5H75s#;vUgXO{g_6fw)ma6rLVdTY-rr#~G$Z@rIStm_Zy2g;JOz0P!# zUHYEbZ}9z*2dB9bd(EKbFe`Wd(@RS~RGc z`0kfTy#?bZ(4M&pdj}CG;}pOG*bBP#{ic!>@|9IR+?-G2x?8{{E>}AB-N3umsP5H} zoy^7UrW1f(088~!DBQIxSoWahiFvtGE7mrUVr``zVu=lWaFzr*BrT5A~) z8XsS7c1Rf>I+pG8fDjvbUqtlYViQpLH$3SwcdS0`>dSa7j}!$U+h^JZf{ z<1Lp+J?MntE?+VPd~kP2p!wyPV%atD>ad7BUMX8J4(ox=EN0C2p0jGCc71N|_7lMN zo5k#*$Ym<;G$inS^UjoL&Mk4QfsEFlY=Qej6~?J4+z^{7?k4MO(1w~pT`nu|y?Rcy-phD(6(AOE7=|v~ zlu4$ILlvyFF~Fi#F6iE5Y=OJ2doujaipyKZs>Sio3hUeQSY9`9RvpY0vqI(BBFye; zgz&{`H5liD8QCL+Zuqmjwo#I~xZE%XyPQ}E!6yAYVduNvPc`&yJMsB96x@MPsO9+n z{M`U(;(5fUQ|*nSZUaQK+(;(5?B8rlT`w;tjzo}|vCR(5UCt0Z49|ef4y)j@Ra6?& zWOETx%!K86ojFV4R2YlWf4v6ghFTLzn!c?g@DuUfm-^Gx@%u3M;5nXUB5q&t$lVt~ zj}flX3@XTs>=2^xi@B1^7gl31o)u0}TFjYc14{J0M}jO4C7)qh*-mO8GFc%FF8p!P z&o-(r9k40*BRDyoe$~(hfIY4xl*<12sqIAoLhu?Z+^NJp?CRN$n za7U=w&0{3#3&ujjT=UX~0KmEWfB%vP4vO!w$#SLSSK27G=NT1JP=3aD3r!sw@ zT<`Bf#zYra*@{MUwz1=Ec!k=4`5?e`xSmEX0j?y=H=~LM&B!SW9hu05gK+G>jEgzw zxTM1?fr{<})Ajs;C8x|-f}Tv?SHPqqS|cD33-@g-Jv{xJ4FnmjS45n12+I|t2)IQ& z6W$0~pIVReHM>X%>Z=Sz1_Zjk|8wEQ-?aF-US&0?r&lf1*?{yv>tVl#7zRx~H?F++ z-fBMt!Z#)K#6M5{ycm{^O|p35VK%%JX4ul5uEUF0WDU|+0pcq{jo}9=MDwM>9!&kQ zS|&YR-_)IeHEyF zxTXH-JFgI9wGZN$6(?T2O6%#xXYcP1&>%p5ie^Bl#Fufi!Dy7kVj%>XP{Y0lUt4MJ ziAT?mOHMVPt1M4gOZ{s*%WnDr^A(mf?8Ru5RXP88r;+O|N?t!g%j)F_0?2hHv6LD@ zw7r}TXVVokle+P^w^Py=z~GKBQeg#F12wg7UBo}iWW@NWlSw5>Zxz|3w6a!wIcqD@ zaQ(7x2;G1w^P*kq4O(ERA8Ol&quS(u^JPg_dqd{U3(r&C-bdcKXKPa|MtQ*uZh&jx9qF-b=WN3~VIF1mC_PIuZ~Xe#?JlG$s}O|-#4rnz}nMa;-oZ=@*#afV#Gk19FgaIw6o zu5)MIw;djCE&v!J6M~HUWc@Yvy*^%DOyF0$5u=HA3OReIQXJ0FN#SIWdj2teq4Hb) z7Y(LBU8~c=AZW?#r^JauhHay|K<+B+}l1LRI3`(m=q=!g)My1HQ!LP@Ii z^hxVe6tme8ihW*;&9Jb&gzs8`UB$zE`rj{pjJr7|y`i%sh>)^3A~F+;e5d>&|D`22 zLCc+V)va1%TcKl=mToxoSG@XkovmUP#X`^&IOt#Y`DAbGrsr z6d`MpBH^G{)AuK0?kM-YC_eJ+W~;mipJ|cCz9Lyqdrkij%{uv4%$a{_Ic1U4j@k*7esHPOSj z#<^WixHW|(gaoKW)vfbNO^u`!V`!LzC)XI5`E5`Sr_8uFW);hM7L9hK6;g#U(wB$K zFyx7>?AOXRlGa%I5#U2~8xLNI;d6TW4Z68iKVcb1z8;yZu^O;Oel)H9Z1HD+rhoB4 zcWAqrx(|6lyaB>X?bm9g#E`lpvKCQIZM*5Dn5cEqlJYuOjU*NPh4`BqA*;w6A-Te& zJ2ZW25IEe8%c`2|zYx|)-gT+w)i8e><=*UrD+iSsEkr~}sRR^PYTyXt5rJ_CE)W#I znJAe%A%`<3FNfaPxiQw{;0U_o&8&Xy`1M$8S*ZKZpsMf=?`gh0u2zY|X-M+t0F5AI z^bM0Rs|hq)&~qr?c{AZ{$ZAXY=%ZT=;}H~AyO|T#b`lsOyqKmm!&#Ivzl@rdM&mw= zgTxPwM?ZGZkWCUG$Mrrt?`+nbzoh(eX_%0h6O+(6v31jje1%l7oMz`2v?}kWx^(?}>R$kTj-%}q)(Xc_ zh9N$kuf2;h)nu89D;35~L=KaF3$uibsR$~%8C6)GW`93Mln%ZjPi>G@p1QS#`O60?L^LLl}EQ-lNQ zC9Pql$VP%Tr?7$c0{esk*U@OO{vxO2&M=r8!@`Xd%g+{DG`?)9t`l%%!bJkFKoN7NuPAQK zU{wtrnL`>YWW67FXsB$M5g9?(&FL75+$sHE z-`}gpl&L;tt)e|chaDpaTH6(Cd(C;B*@$`nFb|Jlup*>gDC97aNTWoY2wVZG)MLu2 zTcymZd!M!EjTo@zQQt=Kr^7XZmFo$S;S1LE0S+n?PP9VCyx0{)*#}75j}NKLb!r1f z??SUYnf_&)qF0%0>L(4t1TY&jCHPbLZ809Zyno_%JruIni1vwwTlWc~+43`E_GBnB z>TJ$e;GJ^Ma{Znh$hBtPdc4ozO%U*lm&htfm5@L!mKklu| zy2diX*VQV-S>#=6m}PUqZi=zuqyagc@bB3X!L;gj0-yL9O@9`?YN0^BZ5&m&f_!m% z7gmb2z=aPp{TqMc*sh{Wa%Y*r6}%EL74F*lN?Nnr_Dx5rFDdYZxC{Hb!1~oQc;!)p zFzQ-He)(c$G#DwwZ6fzsb=t67vEAwu{bk41&bWv_Y^XeO5@4q9&g2R^CoNhveACUR z(oQ}p?U{|6IdMl3h2ObK(>a|~av;Q@V>h&qOt*RMB1RgOO8l-oV6Kb9V{n30<0W05 zr9?v8pIGYG4jNjO=t2qgCq9JJ3}Bg|J|-StH>Q~|zVI9#Oa{P;g z?lK)H`KzD}rWIDa`F;lIKstO$<*!3=<98NaWWwo-Lqvau70Gq4ooBP47?`%%Z<2}* zpBUhNde%l9wB9$X79)Zt-sjeD{x4ULu~&}}S@Ygpf&HVQEocKxe-4~2=^H6tvo%zdS;?W6BkG*yRLNN$shnq#SpM@z6JN1Q;I_k#&I1$9i zS(~CTnA$;H(2-kv<{tBlT#A~@WW;-lvq1EZH-n@2#~B#^P(Bn?TZwO;vCP_2F zN!WP%<5APoHpfbGr%-ZHyRcc^&KQDvNZEd12J*$i=u@S$i4J};%&r#G1g0p9^e*p= zhy4{JohVe>t|S<)UV}5)kk}jVS5HP@;=J$! z8DC1uS+TxF7PqJxFJ=sbNN9GG2HIePmNX^;HZ~Hm+4`2-!`ia#-|tTSv+p;2BD_*w zmlNO}KS3x{bAYWbgZ#-Xcz@BvXbo+k)HG^S=m9JJ;Top4)%D~_Miw<~b75ZDxc;in z3Vsus_(G+OdDh5JdgS^TUDYwC$KFuXCfm=1D(L?T#cRZwn-tv~CI z0sQ9Vvj~d3|C*dc9BY?lUr^S#g0C$kL+;cUu3uP|u->1b-bNIaoNy>6pG z#jLKG$z(*?FWe%=HWML&jyqF}*o2Iva9e(l92X+Xb-Y6L@(j~;zpDFhBmpWZ%J$S@ z9%kG-(9%E>fJlDg`j_JIg>#58nS>)MfcxxZlC92hS)|A6zUacE4 zIO#gZck`%fDwIDB`zHqPK4%%XvH$L|kK;*h7qX8t`4xgt(O&?vJ^r{lLS<|{&0kC) zWv<_ngvGMJRlRU1e8&d`6x_=Udf;cVugS*3xYszTZely5so4AA6JxP8n{nW#m5)vP z;?Zh<31p-M59A3D;-ua5NdXL|!ak=Ia&K>>Adkcm!1d7O#0ufNW#mhr)q|AZ@Epf* z)K{Bk$jO-0%2&unkqhFoj+g0L){dk6TecBdyQ$}g?LY#gZ*hZo?`yVUs(`&fs1xNF zHteQ>Rm$*6v?@G$7mXbNPNc7`*q4IX3|W`#9%_r~`qE({NpgoeK~Q>}Xr);m@0rJK zmNFK%(?K%8F58tnR>oQbgM#<3ednfI2}na#I(2s6EhQCd@ob|!VE543xJ)B@J{t$= z*bW$)zxzAK?opr?b(xm~uy};I0wmBCP4>|b}xKz&0}vp4oH#8~MkSdgZHlYKK8^p_44iU@N1!*X_1 z{T;U?gW2owg9L;7Q%3Zm(`oh&`i2H?xR40?KqHt!6Qf|a+im^Zjwr`|;9OmBT)8>t zLVTy25xTOulOGR0+Hy2d!=!OQz~)x|P_`LtvXKMhrx=o(P3rzdBffN>dQ(^67;J4& zV1S>ZATBE7hzFri=i$l>9)i{I;vg$uZ6+Zs;JAuj3ul60yDQ)cyq@_Mb~8#Z-0Wz_ zRZ-~-M<#!6aHYZn^F!6(FKw3O<)}cda{i?~8^c6}n+nvB<(#O?k93MZKP;PYMIwv_ zDO11WP|BtAXQfCvYYubeLb!lqy~yX-Lfj_oAx1^VuSjOD!=9PFjG{1y6ec32VF01k z7fGnNk-~X4IEf)C0wl-k7QwQUK7@4AVox|8T_v6Aea-DQ>9q)*1s z@Sm!Ul6sk6RFc}*(L(^E<*><5M2t&NkPuHEgz{AUY-pGm!&zfZ$esHwBiG8Qz5kL; zA;A~y{=9VZ{I4D)BttEj6w-%TLe%_2x5WM~!i?l6{ovNstXjoB049?uFIct+8a zZykM!>`X*l9xiqZJLJeOo_IHEkT+}$btz%oOjMz!91m~d_{@TkvrSb&5$uz zTYQG+`oe+S0r}t^d?BbCy`6N^J5VQ(C(Bbk!;ylL#6M~iCwFpGDgD0RjVbi0eX!Z; z=4>#ZIT^@Cb(<~QWzXc$y?s!b?r2>r>rlt_3ZA;84TNxjh!7(amd`V2nT;1!UQ~C} z*E6pjD_Ea&xyHqpd(uE^LPFKtR&UF3AlebgfCWr%|3`H2i{{O@fWyxmt}k(*%oTHz0<8xce`LWpjBaz_4zZ3wrh2EeWh&p7gDGwr~ih0-9S-^^s9Z zH;7{fohaB3(D}7SypbQwjz@3rRCO^szkPOyGdI9e0j`+iz(SW!O@RIg*wlN=0kTa| zCDxqxFKeUerBmht_XwT!RPj>~s((jOA=3;uU?Qk?X15%!H$0SGzO~!cT|S`Q3a5si z>o!s4eql*F8hRDbXW!kyiZBa@uYHn57%M$uEl4`Sqpn@sG-XPkjgR zlP0Dfq{xoe0JQ)~^xF?;U2pNrt-o(o*R|tHQq<~I!`{5ij&VMa1?h2*S=0r5ptcwc|L|Eph)TP31NCu9>tTaJf!BmIaDp!2i~+=r2bDE<>h!Y zoss(Zra-m5vQb~X>i>P>O_VNt?1^jYC8N(xYA?1HaA!hB;Vn+O6pdrkXWR)akRhT$ zc5lXNIseSD7*#|vm}v1=h3``fla###X{BHpuX{A;D)04|%J(udA!>kHmxdaQ=kD;u zuv8_M^k&@+uk7eqTs&d%nxJ9ksYJRAtv;}ruWXI0&fyxJX?+B6iQ8=%V z0jAem^hp3okSZ%VB?M!J4$&|Bt&8(K_>9g>-)10l>es0%@H)ipWemibg)+R;Kc_Pp zUCud^+##}GIX>4snZV{s%dvW!BhmO4cfT~;(BliL)Ynn5z-G+tHv92R8A^3j zz?ERHSYdU1P2VzNBrRp$wGU-GDW*Y0)@f-}Io$5nZ#JtTU^7Cm+zVbE%6=536%_bZ&14u2g7X=25}>CQU6W}Q-A1vf|7gPAfVFXby+y+8WW?dO;!Tw# z%)|Oo$;{@;#|EDn;m7!tX+JVFjz|s9YbADe>`{|3vR_JsJZS3>XE~5w1H-r(vswRAJx*5-p%E#bceo1kDI9pbzt)}}8 zC(_u^v95XPprzpZ3_e*iJydGbcY8BQB4NVye9(lRGU)@u*8D9m%bW43Fa<7Y1vXX# zMM^CeL|N-U1=@+kWoAfDEvK?N|8*u1Z(+$6`sCbOw^j$0!m*@Q4k(tXW1{_*PQ7x7 zn^Ll2#(^JpxdWlB@%?itH15Qj_J>mp6oZv$(a*Vfy2EFDkx67a*J0O7J-jgh@}wBK zBTYwqM<^-bO&;~T_NmkGwM%}^c`YF{q#^LD4>D*eHOM4Xyi~QbjJi)rJr`eel}D2p zurZzWxdHp@Fzky;8GpV0x0O(3#1aL?k@t zpbyia-p4`g^;!7{;ACW1SrcWds_|Vv)3f*1on+9jAByR%3l;8b9_A7LX33W-L&wI6 zIg5mvQQNcci9#+Mx!yW-#%}HK+p=H!Z1>o6Wdpu`@OaZC)?7fxK}zK9hETR7fUsep zrIv9+rwjPCfz@P@wE`%)4$Nfn;#+w;+LnzAV_dumOHN4t8A?>i%#WUZNl%zy9)V7+ zmoC^hZ7Rg&w2i)XoAy0l)b00&-m#H){rBDBFu+cUdOS`S!1OK zSt%EyylC8-wV6g8C@?q-0bMo<*4cJ{vM=S6>S*=B-N)0t)69L@qidM1)U+)7N49BI z{Je|i%lBHmU6<0|QrR^!5sagdqR4aoo9*I9sXzt&?afe{>gS~Y)9vCNwkTFpp4k`M zvqJfym_f(9ej)T0-myKeGH4`qo$ZHYto(>a&xV{}Xsi1hqx2XjGYA`|v(Zfg(II5% z;ndHLz^eqlU{rPxVa zfP8Yi29xj+e&JR^A;jR)R!!to|EJc?k?F*4);8~3ExgMdVxLE_TSfjFozP%%5K|V* zuoULd9;^JrH5xdRflJwlGR!cvaD<@z5-cjr5L9=3q?88ZVeeX6s$}Ktl*AO;gwb#% z4>N;$NDPPtM-_WoQO}J5SLVf)XJOj*gR+mLJ3vYbB6Uj3;5*QT8R1xa)7E}rZ7(TX zv3lK^kQ-^|kS=zT3HQz}o^rHc%d;ic7t;N5xWd?DSHGLHrI|R*R8uu%qz0vsA$HAZ z>`ozxv8Z-W2aq|7V|N7}OKvN4PR;aUpr4uB2 z31r?c|D7=W_;lQUFzu;WyZ`sqW!&S$bGP>&ycIr2Jmx7PTpv zmsh|Y~+ zzVxQr$6$MSco_cg&k*eNoq~~_d8S=5oF!_Ul&0`Y$`ZQS94#e(Ri~=Y|A?#;sn8$jjyYcKH2V z?P@4Ek8-z=J$I!Y`om3BTBbXZLDjyZGcjmHtny)GKENfHK`A-2HS}cH$UkFx81=;W zDL2GKZ;ZuWsCOfm%~R}*hxq8}o`MV?o`vV!faebjE40i0`}@rQ##(x|sJeFo|`yEXrT+6({Zvg^O| zrqE&%f*v9v%o~rMh#E#~>uS?f}hzMNm^VW}uduvSx{3o9c^F`u*ykUk-WYEp& zLvUiVjZrK#LD<U=Mn#1NxX2Cjvt6pvh*jS0g--nB2IhZ}2 zk7-Bvh%P}k7KS_G^1(T5vR7*-l6nDGga28^*9ws|nC@Y>tiy}$YNDyI`gyk!OKht| z-OFDhbF;%g#4tK@Ny!`vzx&iHhKT1iSgCVo`q9}}f(QUHOkXofKxcTaGG(P>oUBTe zUYh>C&i;x0Ojw9(=7h;Gl-a_xqUKqEuz`e`P?u|QH8tDKThs7?hzrlPTTyb#m38Ke zb80#j%pIM@*}4yk9?q2o^g8AIC2;g5AwPTnMCGiS&X}p!=gfPPt{*+a^Kw4Gb^Stk zw{!vJn2qa;Ho?L0w7^3=HoZ$nL_upVgGWIs6Tbzd4f>S~qoOUzHOh=@%dBuZ8IDJe zz?~2}uu8fA-JbGMMUkuvMgpp?L2DuP648RJ%L`eVOukH9nauZVY@gYr{R6BlK!$V} z{5Q@%Ai~=yQ1^}d8Wkx+_UZsDi1Q>PUB5`~?Rr46+g_5oG|y{Sd2|vL;^PX4becR0 zmZyr1{M>8E5fES(Zt8w5o{ef7l>I9BP0MF5tfP;e0Ww`|Xi`plloc;AzF95{ua>eX zVzHFzx&?;_yMSBqJdDIiQYgv|B(Wffid40x1M^9NDJn1Qgu6cl`r-sZ4emljs5N$3 zEn}@llV$?Nd#+7Uypvc>BkGX zVZl>Mg;{oS))D)7(#AqolRXy&9Tblpp#zQSg>gsRV8Wf@I5uF=9Y;SUuG7Z}8HeIB zEc-G5a&}#UE|;7PXG0}XNbhP`uC94YRRDJ+il(j_BK)Yh!ZQ&@o_vq?>RU?o`;AkE znuKiBT?*Em5$HA1Q1wC{F=~J(4$9fm#i|BbEtd&YyoxSL^)SlH72Mh_N9hxhibt5o z6fuS8@4914hqnJ&CyMG~vi66V1LVjY@?lfWkAKu*2jyB)HlTrXE}m<%9-wS0E-+|& z-dnq0yk8yxiKI6Bk?j_{zx4NIWjd3dvYkLF^opMZ-6!M)BpE$*{jJzEQml{r3l zE=>QA=gL231>>|90HO%nq+4|(IcGl}JN}RU<`WHLt=-8jyS@?ND|0o(u3KR95&V-I zPF|3HdDtj&Q~M;$Yp=&icI(|y{BwaFOF*Z+`SF|B&^HQhvf_#<)J1)}++^JvV+I6b5d8?N58BZ(0sW@FoC#&4 zN7etgxs0Mjm=mEVT-V~&U3~@kfa^aJwC%PU9n7D!vpR(oq0-2o^t>$#qLI=7W~BF zc)oAk;PL7hDS*PBSN|h~ehqVc*Kt=P_H(g|``PLP$A7FeAOG;9%P!mGNY-xI>QhdW z7UbU!>-VyAuIg!qDxYHI8EELYB12k?-g8GtXrfC7=MMa(U`g0qrb+XVrpTn~&HUV1 z?}>!eW~(r5cdW!Q%(Wx+j>;-h@g!DCOsdrWTQ9q4B4f+Di`p1oUGT!rFCvxe@@qG} zaSKf(%EE=NZFYTyXAQ_&Y&T;AC`FCrn)&)?V$P12QPul}sd%jXQhiWRu9%!@3jGJ7 zf)fsmBp+cT%3nXJ!`ujgN*P?nbAVkULZd5Epyhk6em^mOpP{_>4%zqtBWCTtcHzW! z7&i&OzURossi-yNwyKr!i@&sg<<-Dt@-Pc+s)kE_`C5I+av|AM?#GXC47@X1{NI+Y z{uD&Mz?$b;<=-!;T`JmjSzZ=c@Ea_Q`!cmOxtBFSaP6}^;u7AbFBN6zo}^$N88M8* zM}{IRX3s*7;7Pa1;e#2c~#4*@_ zqC|!GFaqSJ=(4cL7TA_`&qTW<5=?bNw_mcDbY*%Y^!8C*3L`Q9k+UjVYRz-rQ)wg?<9M&7B0R7Jsj1TrjEh|(C0>= zMiWZ0PW0`)dSFC#ar|;mMNNd2@&qR^q`iLivFv6Wh(eMOQyi3kDd1;lDTc32J4P3r zk!^%>hFU|3a+AvCiNKnwo{*21O-;;YY_}g16Zk90)I24W7k)`_KrLss^6? zIY!D4XhAvK)5TNoN5Q74rdP8IIz4%7->hM6Z^9M2eL6c;qF2t58UfRV*aJ`S)F(tO zCw8b67;mbn1>>_WAqR>*EErQUyT`Gt|9vwT)sC7mJZZM=2CpQfwT6aW-yBt*G$Ugk zrCwODi8mD`wf|Wa6Sk%>rk%ibyf8(`w&PK#M%hF(Y%{mj(M9P;k;xAA4A+zyg6ani zyWL(aji9XzI!%lq581PQGE|~jA%zdav^nS#FJ6jFKR=Z~!JrqUPZ}QE)a0f@=#UE9 zc`eE*=~QCKX`$!bbbbm{+4{L#qQ}ARiO_Ky5dDw%UH@pEAu=VjPS#?HoN|j~1+obe zmQt5>ZU}!aJ{84kMiaJknJCResPnp~ad&bT28t!LDQ%_mEGj6B%^bJ+ZH%sf`&Oc(mdRfh&yY=qMmZ z%+<^><(Bibyd+gM#7A9-14JC_iXJIzF^9xCMgJ!#=K$J41HJT80e&6LUo^+ijC>Ll zGnad=fuYIbT zPJ#e**`?wZo3XV=t-yZpg+J`FKzyqR+1|sNrBFRKgX`Zp5I$I8g#A>(>7usb5y|a7 zmus;-L|qDba)2YXab^?@6z#@@PHG-+J}Y|j{XnY;brflYnhCVJZU zqs=hm#bZuty&2^=rmu7G4;!Hqoc$^UVZ#>@fzfTlQl`G=`z_b%U< znu}MSS*Wfh?tZc8FY=+Ebm3D#d^Lalcb%?8-a|6N3Pif!s%#Ui_jx9(d1 z$yS(XVs4j;#@;_U>$%KDt&l&7S2!jyps80qPGQ=J`pdY^G}DAbo1v{{lIZ>w4?}vG zLG9?)zHVI|{d!dCzeR@yO4W6U|FNwAHTM5@xPa2bxK$CWSc@@=BDGK1yv67V?~Huj zbm6!v*GrGq`-~HfNHs5HO4-%}6dDbigr$Ww0JrcY`CVcwQIP}}LsAv0`tQE=B1y_2 zE&NX*%@Ul!#3dlFi|n)sY0PZ6jkqoR#$^(<_{aMyqQT85FAI;K1}+I{sBkziQ$?Ai zP!3_+r_8-5{M%!!^fE+OEHUneQa0zHuD99ELH>+3!&$e~`5fFhSpT>Bisjzdf zDr)oS3lSj2FM?zt&9O1$WgSh--8i$v65Db@z@lE7EeUnBn#DBML*X-JY;n1|=j_+-L*0~ax8Z40@OF$#c6oT1% zqvDAoj^io>T?v$sa0Uw~1lcIHe0v3`B4v@D~p&^Bq5#RX~r zGUY$(=C>km2tYo}tt-k^#)7Pqh#WSPP{{2GZ=KRaien@-?SbO-e+FlryCpDpqZQp4 zIa2Q=@0wZ&n6d80-9s%DLLCN)wV}4c0<-zhjqvwt0Q=VgRy6$?vT$7b0l`=S@+bkH zK7$AWTWy=rfm#BqQ4C80Q-L&#SQ@>||38-KOL(yhr&S>=!qP=A3z?B|1d1g7_cLAz z{okP6hd)oXPv5?qN@E2){R(=zqvtcmc|41JwSt^RuBN;{_;otP2zf|jM52xNML3hh*?o?YQf@;2(WN!?0zSZmm zT^*XDX5Qps2Y>yNSBhPl`p+b#XcGU^@^9@5VpM{l^iwer7JBCIZ)Jp*qN`av;s3r! zkQRIU0mm=;vcQ6RU|q3idXBooibN$CFN`nb;r+*pXQc_&YVfKlTvg@3_5I z3r$9ruP2Q#2Xwj)@&A8>y>(PoQTHxB(HJEWxq1Zj}2Lx(gX zC=HTIBO&!|eBa-_-#5N7?)}H%M%;U?HP@Q!na?xVn$fM9$1eb9fb0_h4ZOR;^56w6 z-nerld!ijFoJn>Pkim(IRWb3T_L>Mee9RF<4;%AusKF9+oK?_Kno~GZY$+yU{W>5* zm0RF(MJTXS8PlGT95o6e3JmeS5;k|rDUrT{RjF;_Gn4x6Mek~W0on}QD<=smXBK_c zT@$(@kSqt>J+Nk_SZ=7PcR+dkismQb8|i;L5Elk3$3KA5`-zxd!#<9m3txsbW{-%_ z)qBYMT=>Ve39Qbu4Z<=iwK(3#6+T}|Tr`;nqVI}Qt*oH8sU4UHPHPsnX__Tj>gET$ zfU|mM)sP(C^BW~9w92&HkD07T9JZ`a60=iFJ4_NlUmzi(8k^ljoSpKck0uLBCU|_| zhA$3)=ubJpqRfHJA|jzlrB@vl0`)i8n(yv6@kiMA^4^@W6SX9wjj=)mez)%DvOXbD zX}nad2uvhZaBojJ%pjFDuzM>iZBD=Q8HP$=E;4q?gpx!Y)?d{f%6N?^`~#6_s%bQq zV>uq^vv8-7opZkzHbVcd=n zyLL{R5Kg-&;N+{m8XYM%D|A^N2ylC%eL_Nt?TrltRp?bQ;ij8vQz@_+{z+~2lI0}& zW5e9}x!t5*({9~T&lO4Au8UwLg3i(+Y60cPXiiOTNhm;KYY_Pe$OogfKbYbaQ0{%Y zG-N1+ur2o7>kDKmN6HaZXdh5|mt%7`AgXpTeyAc6I*8uF*}-7n{0aaSXQW?-zeIuq z+gJ);y!4CjvSv1fM1P1QIxC1gkiI~?jQ%xHXI7=@7yf2`Zt-(iydS&nl_^u!F{0A0 zuG71WEDf2UV3NYl$dnpQ#y?q|1K9I*?9qg}9LrYX0@mFh>ooO-W4=Y@U6mfnG{PkP z+pUiXC$L!we$29S9(~czEQY`)J`Nr0C)eREIw%RlCfu0bLH$mH!0c{Y*hJn;F-?=h zGPQ<1+Rij6IhqU|Qc|{*d?&q2qnV0PWp!W0f9NC@lSH7Q_e7En1}>`ot-dN9=Dkfg zPv^q;0O_eDqpAV^9E2Z~XN$+4l^rSNkN@V?dbXT!q*)BZ&Ja5C9u@@a$BJik8r7VF z<>YA|kf&*Ax=x;Okv6A@=VWm7p&m|`F`;t%^h9w+r2G|4SzW_tNA2Os`8rQDOSHp! zb;%d3%h6`}f=B>Nx*ID$<9=Hh#`nfQ?DXiAM%BtSem<0G7EgvDG$d0u{34bpe?j5f zmF>-WlnydnJEO7Lx*bG>JXMA;?yl&zzelt}+mXRrXOivT`cj^my`6d4)g}rG3t`$` za1$J{{my(MQF1>QmerLYGq_!kr&eU`8}c(uvl{v3>lH2B@?oLHz7r&@(5>+`Z!6Hz zg{%Owk~x@=OpDPwy>oz(>^9p+2a$Ad3;EMT)ehUJd7qLF4-OfF_aYG*@8GWeQE;zZ zp{Aa|&YS0Jr)hr70@sOU6t!Px0FGyEL2nJ5)Smh4#5xFsa}#BUwG zd%%aChm=1O_z(?w)n9!@eRp!~Dz2=Fm8pShxp5$J%?!(C?yy^+=}oL;V&UijL{YL@ z$r8rWfYE>+x}zQvIYQMnLldpp5kIHBL?Yg3F<`DtbF|l7V|p{IK*gV%{CR5Fr!JOv zz3E>EvDF2ABkIMgUNb}l{bjUKmt#OX;styk zP-Ssy=<>h7Wg@N`3R`#T&J<9h7p>)-1PAZy_GP+-wksHM1@oQH7$oIs6gkh5plD6j zU%IgRS>@gvmT83Mp+MvsMRfL2#9qd7zV0)6OPW=~5#^%}5d$IO59CXEwoi`-#z;!nX_j{yfhjBT|R8damCtw*zA-2!gHAEBM3LtWz$O3&j;^jcE z`xaHqk3-DtHasHg%eLY3>-(Uj>Km$~JECV!t!~8dBrWA>Qu^TD1KoMbg zSam(9Q$ytago(7f^eS1GfdRI%NB3jPTRTd7kR#$;ZMN)(;%gQ>EmbzS92I^s-ezk( zzW+B6wIdO>_=i4&Y~;-oUlkNukP5?b@+gVlgnFYbEziF73*& zoDJ`OQ>-wt2 z$9seH;T1|QJEBd0qHN@feU8aW)jW0Qmo{O*GM`TXcR4mkGaEszN7>cSVdcu%t=2QL=>eu$l zeWv7VtY#?x0)~WQx$Vn}#~@*ruo~kSo89~ro%Y1oV}JLyBpUwZdj*C6!b2tHY55#l z+e!HI{~}PvIdBAI)chq%o(4}7yf~Iwvj6Z0#d^jHtEOfq1K!PWp$Ex=ykFQD z7|2o->603`m)XZeN$FRuA-(f&h+uM~bc#`2Gl{4)q~DPh0bq5$Zi3M%`Gt`I&_-OG z4uwcWz*tV0I*QI&_PNeTDdIBDDB9wKAQgNv&&&@}g!&s=xk?Ag#-+cz_i(-2Va%N~ zx?`=nhZhOG0oj(~w6ag@E`c+Y|6LEvNDK>H+`XT3;8o|Ddgucx7gWBtJAeNA-b2x( zB&^`QhNLX#q0H;&RMXD|u!8M&_N#8=)`KX69gk6!K35u1$(tBSB9>J(KS-p{8CP5< zoXkodW~FRRPC46jLryCIlK90x1q{9*;AQ`T7dC8x%N$NXXz4qpRWvraZBP_PW-Rbm zsY|rRUtyn|WM|PuLKY=bv~Nh2Ieu`-@3t8oQ=EvXRGHq%8+i8oB?uKF-A!}#{sxB_ zDivIIP?)LMvzW;2y|~-zpl28*(B+;iQ44w0378XPjc=<7f%%!3(d>o7?v5LrsmV;; zQ%P0+cP8;KC;l+jgy$-UpN3=Z2mie3M%&+pQh$3ERD`d;8=ud#d=7$fc?Sg{N8E&W zLcU}#z4MaWjMcrE5AE!dz&q3ef*0B}Aa*uX8hZiuEiqT6-kyg()LtVV*KdfYzIP;N zo*=FM(8zcRC7du1WiYp8s+_J&b29V_=cMmVWr@E{iq`9yeH zKi&R@SU?df114B!y&O?`+M3YG5h24ktzL5fx0tfJfahGG@$_jv0drTS?*XcgP*)(( zmf4UhW}6zFy8D#QmG7r|($J-LW}FbL=zv@_Zp#W%R;zbERGru{N?Rv=I;QPhZHfrh zbh=--T#}L=0GuinFVv;dOKeaK_;vUHP>U}N4G{vp1&v1_X{b%h20wc7`-%^rVI%+A zkWvK^$PYfIEh^^z`HY zLjR)N^~rIZ<6s^@5S)TQ03P;&BaV~->;Qa6!z#QbfgD7Y_b8?SO?gBZBF7MvB9I=h*;_3`}H~-j8;b$=AMz zGK&$HG9fcW`)xgp6Uy(KxqghvM`OW?0D#Z1&B8H2gLD|XhkhNgNb7r6ks+tM&PuX` zx&5}26SAeVVS?si$AZDYgn@GVeQAl2Bmo;zT+f%XYwxNIO&y&~5|)4Tj3*j?Uut2= zok;vkF90k#ss3m=q6e=;<7zF9#ZzvV1CZlBUP#_bJ=hn|bV`HL~ zmh}b`-H1?xbjDebmz%w!+31IkI2f;@FPUSxhAo1h8FYwn>4A{fM@LR8xxeWfFh)J} zvZ-9Ex%pl`(>Wz6Erhr)Uo8$B7nVX->TDM=UtiCIT()@BjG&;IPpaXuE)CV#RH;J$8$k5eZNnR*`sHGPPZ+y7oHF8+t{PBnA6GIxPH;T!w;HtC- z(Q{-R8MyFgR*$_NYaH&Ea=VpSkCj8u)cWs1<;dzS)wRlHuY`uaNRBfwW-w-UT%y=E zdAy@T3~-{Gse)ahN?ZO&F+$?CMOF_Bp3v_tOW~^OuXx0>F`J_SE@gd37-%2eW{Bu| z>;s|`>kY+H8|~lIr%?7Dh1VTvUN_a|kxDzNL+)TgkkL+AK3$zZN^UWX9CpnhzY43a z$PE8kF0!9)FOHU;@K;y4>MJ#{tvcX2=q2N#Q;ilUmm12v09+fGus*>!Tnamq%;K4^ zdSwK)_)P>1B|z_V=zb`?tZununU1H`i+3zp5>lzSGeThttvYeK=HX>W%(|u?q3jR5>&*joAmbOVmpADmgdJ_U`^`{*Mv*b>i9BU2P2-4MY z-4)AA+pEj}!#W4azq~6)Vwzt-=(PsG7oO|14_%=V4ssXv&yB9xZqE=B~+@x27E~og`{dPjW0G!DG zm(gliB&Il^x$5~<*OeH#FEf^jt?fluK>G=?P}KGGLjY$KlJu$01@@8DCQURCd8#ea z@j6x+HYy12DTyLu=m;9_Fk~zllZs5Tj~f4|FND>3tJF1S z+mE4hvic)R9c~5vs%_K!d;0uz`fO%e6^8yb^sOr#f?ApuoD7@;)B)*rZ5a1v(n&8V zLE&t6?B6US*IWWh94;J99BLevrF+M1pP`-Oq2mdy(+W(PRw$KmPkg2J;rJ`o=?@by z%4R>nA7Xw$Pc%d!B|jZemJ?t;Xp7zUW4goUO8>r9|FOEakK5W2oSpsw_zHJK(l>G9 zGg;q_WK^|-1Q;B|nS@j-Q99eYUw6R0LsuSwMFVf{G31>fm5>W^t7Ya0`GiJ3IMH#rJJ$(ZF+E^k#W@>hHr1c>F~RJoSz z(aT`m-rO9wpV5LN`!69sl)9VEvVo)e1{T1-Wxqk8UiCKF}DjM{KUQ zg4=0{&zKi`q<$kHVqm!=Ac`xOvklPe(1L|TV|jb-1fpC5Fi+Ya9H2t3p#1d*?oE}` zev>S*^jLqeCpmk)%&IC{z3^K;ldY4=cZU%ja4scdU00bG2Q(E;oWbl72jEP(?k3?y~4@R`$F5&Rj;$z^=5_Bh?IP;;t9XD;o#|}`V**Kw^)36|7g=*BMWZ$;^**;9$khK)UG7W+xLp{sk+sJMFqP6rEy;P)L0K!b&XT0d+7 zuay%!ab^Nu+xn~R!4gubem_1Wtgo*e1h zm5;D`pVPPb=qhLrk9JY=6E>^Y7QNNdEpWKiy)E8l3oL5hZcUiQr9kl2zDe6ua}v{>UzvMjZI}f>U%%o z5eC}GpXr)8(G)&rHm8YNG#OGIUtmB%GbBNGtq{WSY&`2)GS0Z={;*~hm1zd&`~WYc zm2|}Ji1)oJDynen73-@ltw3)EuF=CCANWd6X>1MHw>QXt6N`T{`%!X% zZVkU4o5eN?*uq#oK#V5($s*-HaT^S>H;++UF3C=1weWpxVEHv`;-pG^R`=%?ct-d8 zBKYQG9*#m}$sfPt;NWc^*tb#IWwFmPO>*K7YLl4IH74T43QTP}s>;=g6551zudt7T z1Oc00adP~qmJo$b!wDSvnK8Dw-5I8A7>lO4qEm81TM>k#T*as1 z2DK4A_=YITxnHmKK`i9GgKzW~pH}XV4adKi-aF_JpH08{w6BG3u)wALF`Xyz!HF#4i)(OGMF=+0p4!I`2t97wawJ=&~>6&Zc-dsD_2cC(~zWE$ua5Mj#|L9{Vja^ZHb%u{$ ziNAtIRT`T|PI;i6f^n_ibvS1tONY;j`QX*MCWPy|vhUYV$qiMbZ<;hj)HQGg5=UWMNJNR_@Y=ba*HsP?E-+FX8v*~cXXK7% zBaGG)rU{NUO{2||{vOp>{o7Hw}*R{MPNO+`H4{SjpZoX2i0Pl61}2 z6bt|%aogwjK-+&b0?*u=CWnVE&UXLW?uDe-gVuNNx1Iu95xe5wRqr~yIb6U1TQB^u z&fF-HGE4ZZG|3v_ck-?mhd-8SKmAQAF1*dxbcA`}qs%3yTL#>_fHZqQK_;2*M?1HvWY z(z`kkZ(rdCm7zf&{^+cB94OW@NjzUms&7GLX~9N(%s$l;0#V1hA#Ns4fa9rC@~xI| zfOaiztStVJhd@f}<}OSlS2y*D+Fti`rGS+2XCKlv@7;jIkA+avzaV>r4)H0lViVR2 zX$KT9`bXM@r@NjVyk^0MLrYZ{@=1z&@1&w?A+)r+vbYIY_h<%q23DE(9X=2L%k00% z8#*33dNe~hykkp;y&+IWvZO2DLtVSUfX;K1D1r%Oj0@vRaru`omc4$ZBOe6w%!pJ& zfQ`k7o5H7&0cgEty_-fp(E3U)-$n+Y^~=9j=J)>1&fw+l?e_O)z3`7biF{ONtca8_ z#W0n=d@7SdCk|Z5cUNX=*~X#qv=qWu;#KyDlog%_ey_5*OM4TJ^5026oTr48q4?Fh zaBMk`O7JwSX)V{k{R0#*=sc)to(|Y$GP~Pl3-Pb1F?;^I^rFd`J!}*7ZR6FqAAPDG zfsZrrLU(S1iMhya6+H{XG_PcPxv}>wiVa>gOl1k0On6q|t2H5}1(zmG7?wh1{oyM9 zw3h+P>Q=;J)pXtURVb(jZOt@dfSy`r=vf{68LsP#xy&W(3BE@PqdPlWYO|S6jzlO- zDy46o;_BR>1yy=%-@`5&Q1|@1R^dfv-}8N6h;R!Kl&3g$QEoW3tcpLok&nT7O zbQ>9#;fZ6Z2l)L-C?hE2uQ}%tdE*gdDIOYjd=R)$LApP%2AlOadxqcw@xT10IJ(we z+g}uxBu@(0pNMBLGXmwPjC~yE>FkLcPmk?7?YT@R?|mFL6WcY=d++{DPp$W7MM(Rv zLZQR{$K~;^jYrq_&@ZOfO-^+kz?~7(XXm7+exq+c(M{nynKv=~&OyJOdD!e37xiL8nAV|TiU20h}?P`xGykFgaDLKZKfy^{O0vrB$IH>6j`b!rd z_Qjs>u2dKK{c~ZwN)_#__!ZRcQWumgShq5OoBQHD-v%T&A zAOlo(`n4@OL2cRimbdfGBf9>d-p6CNrC;knmqu&Olp)Cm-cCjyT4;WofrEu&=W%K^ zwXRwXgWtq6q%)!UeG-wvOh={?tFD6L_@R-%*(lzHcW9~8un8fvkXg@ahtCV%N~=mR zG;m{o4Ju0w+lNh+^%I9wPr6oBe3~WHuTy)4qKx^fvGwd>rXTObx~i zTpl!rxqmzjnQ>eO#@^p^km{RC`0+O=yw-9*I)A4*dm6%94#3e^K03cStRQrUHvxR- z=N=Z5TNRGYu+v=}u8eKrnT9tR%M{TO)R5AH*wiID*BfPxr2PbSnu&UkUJxvtxYV*5 zljTOFTv`R9F86J{0t|9fv?m=>7221GT!a)_@Vg2n)=(CfH-ECN=;R^mcWakq&ryB( zH@^Me`($%J*YDSF1lNlme$qYPj*5{jYyhHsdpM4oaGLQBC8qxvs_7Z5D1TIA>zkwQdNuV(;BFzOM$|4w6rMV4tal{9O>c8&?zELQy+QV+@Lt`19JW`#g6h z$hKg|d)yL6?Nh_Rq;8dt-_m8_O*aDF`Y5`>u%!h?QNk;iGkxD$U`8+c7_m&XV3v&yrt3?>Z)21x?De<-r(>s(`Z zgoT%HRg70at>t;?Ou)D11|!9uA3MsIXz$*Y+6nIv@!JJ)7I++XZ)>Ck;HE4;3+xx{ zFxht6$GdNm18#(nqLX>xV+F4wr8Uh1<9tfP2K{JXRS@el{nIGPt2Fbxr8YL>!u@iY{lT(9HWu^1%>0MO* zV=fP%%rrJX_|iUU)g zwkqKqw#wqS^MXe!1cef&BxHxvaauTlX>%GG22tn=HkIxulIxQyRas8d9jmEPXD`v; z-`*C(5tsHLz}baWu2_42aYQ{D2t|nig8i^j)q`2&k95f^aen?n1KR$ILuO&vm)S7^ zSg2^$z$LZJpjADf`dfKhfQ#y#jUI@7y%u)Wi=L+xm!kJwXlN(kEJlNWyCvWMG@H2> z+WHXEMIKmOA9qZYg25py9+W&02}v&_(*>uDiOfbV1qkisP zA4uwjFZK~-^4D^XIW(No$$T+8E(J!F|Kn#a|8*cMm(%)h*X6X3g7q0;hta1Ij6>0W z+*Vw;);o^0I~C~z_=ur-{VxM!3b~Ek&M6z@8PNC0Ss#I)5a%`*7@S#Qqov0pP(f6< z-}KT#D+tdh;?x7T5Z8zks382}$jILMLc{4CCO-I3wB9&<^U4dlb*o(@40w$)5Hl7B zLVH`+vdrb65Z2CHN~@{d9CW0UzYPVKz0By&@h~x`-pPB@y4iI2>cf^^hMT-r$U(9*CkGA^_x-xqd%Uq}x z*7EHyU|a&ERJ;z8FRoL*vLGv zJ-)EC6-SyqU1S^5#+>`1u@N5v7SngGbbMzfkVS_oce{AYM;m^pOh788^o3%Z51qsq z>9C?kNbSY7Z3PM#7R$8kpWx@?xD@U4D!f9b%()UVn;>06M{L%%x>tr&%H+*5=IW^I zk_@rTGL!LNO1tFJ)gYds5wcsHbt4-*OaQc$tO8^b1BAAR(0~`;1!0xhz5^5UzR){o{C=Nw3yO31dE=II557C0zDwsZ_bX$x zye^Vv7Ys)MxfX3k4&{os4a2d$3@9o4xE%K^HMp6|y7Yi2ZY3>}y?4Fq5qT>Q7Png? zcukg`T-trn%qJMCH=mlzDUR;|o9W8U?dxt*2x~Cx`+U*j#$lH>2#hId-{ax)T}9vD z6{Y9V=ZpU5l1DhWrxBwr^^h=yW~FJLj+kT$s_!@Elysi{z;}miH+p)#EdG^)Mcmu#}vnV~T=R#kl zxJ<}$zy_OUrsORGb9FhTWc$J3CuJUleJ9p|f6H8SM&?rXI$Z2emD(NZ7Fy*)Qo>-v zC9ubTyBYDI==Ig5yXT;zA9Y<|Bi8?%i8-o*B9n7-r-H{3iEqBWFy=p++b|=6Eg?8* zACC7?-v;mI5v`!HQbQ!{1+k8d>>v}xSk+9gdEbg+u=yRvHKI35kZP{3!#}K5mHiz_ z2cM1neeztbd^fsTB*cwv#8}&5=+n&M85yP z7UI<(@?6CBaQbvP{2X>~)^{xSa4hir%dYMjh#WB9qdZ)F6!W&UsyR@y@GQ6@@zr+_y!}{Lzemo768xHnt9kEOqD-}!E{oE55T z_cqxktr#M`Hk^R-ZtErB3;f~m(E^WOflDn0S2Fsk$#=b(|I*8whC4!fUeq_e%rsfjxJF2MR0=t`y& zulNq!<}1NpQaC+X#?KW>F!rrELZCe#85TRBUngNNPdzip*sU0EXVKW%!lkB2={x1B zXyqXXPS+T&cZ+J%4+n=KH=WOqZqrXG&!_$&j{}%R*N;ZM3Bt<{mR7|mWp^0Ly-Pc> z&JViSVjsm#Xo(RS;GJpICpK+_M?7d@Yx%mj&~@!-AtEc7|kyS8+`@e5}_%f+;W&ROG2?wBds@KO5AQ<`_h z=OT3N>YD`p8Jt1AJe^J3FMKnvpzM=r8L#d*sj7)QLQD*=PkcQiJu+VTZ?o;RQVC6B zH&@Okulss-)_CjkdDKlV(rMS4RQG1F{;dx2+wga_M)vx?cwSF;`^`3?=vL$Wnu+)` zeNgo(CE@65x>X387030w65BhxzUiCGqGytD1lGJpDh@UqO8J+vxD~plUlxHK-Tl@S zW65Ghde0DnF737*jjsz@fZwj-tY5t+#ml?dpwC=z2G<=h0vimropd8bl{))C{)oH? zPNG0bxeY;fZQnxdO>DJH!~g{6_U%_qem>mt<$X6jr!xOG;v>)dV4-%I7h0CLvhMtv zamOdZ|Kx40`8Rc6oX(jZE4wg=rW2JE$D-AvhEEFRJQoI7hON+ZKw z4}}_OT`}`{8~A}!P?OAz5C-FCVWn*FojSHY58_4KK<{7)l9qM}6|^mWyDQF?Z|?e- zc^ZYl(M~(Kpb!pHjPHItiydcyq??(mCamp2zc-cqR_nEYT?Y6FryNM%EcQTy^_#oh z?9mUPzDN>Tnci6pqCJErZ@Bz^C8|9GW=D5barDm$@YC@LXYEO;an(zdu5xHLT+{nx zfjHF2BM-6Y=>fsfTve%pnD{}T%Gl$K4yE{APlPK1;Bt%M-+OkP= z!)=7q>1K`Q!(mVK{RmAg&ThSr?;j(#-i&e@cC{)m zFTqU+@3^{%0YTeh`#-?K&rB&oe5MAPd*r@Cvs5hPoZYaUa}fa|xJJsiRsf*dzU{1h zU6+TTz3ae)ShLsl06cU3oDhUU*&vl8bRUD{T=-m!kkx*Sff_^Eh=97KtVGwwlz$1W z6l6XNCvMgg$V2F8puzbHkSZ#`jS(*649-YG!TEUwh}|kZ9T6@HaO?f58+o*C3PY2~ zMARVw*<4LXlg{^qRGIc{>Wr!F5dT>`Qxe75)O?xT%wnnZg#1$$q2eKGel*--Ee%Xi zK$GW$(u6Xk)t3Lat(51hm8rKIdAc8A+*I^VY^4Bkr+K68!(y5=*6W$XRP;iVYBPsb z(+gP1fS=lgGXxB#jeCkZygQhN(0zNvnJV?KT-ExuD-{+XQXL9JMQnm z$EyOmklfhNTsy|#Y}fTxh`123oAj~0xmF%-{d?U;c(mNhvNp|Vf1lbrgYh7@q4?ky z>Bb9#Mhl$0JxF1uxk&e%A;f3Nuc5Mh|55Fx=yb{3aO(2GAb8`Q=M%XsSQPU!Op(xg zf^yZzSHLMo=5lXZFvu3al`l2bzq4vz!T)X#P!{|rsVzUmh`%b*(*FUKb)rD``_RP} zr3R<^df6CV8r#D8B?!s9?Mm6wBWUx@N2Wwc3qt>`qDD7` zdp%ACmnPg`1h+bl5J{ec`r8J7GwH!4VMwISUR!~N9vetI(5k{s<5AaE5<+{1!vwU8 zsg~zV67-+AS+)&xfM~jYaH6!e5W0ZKs|S#|UqQKp0yOM(AtsT`-H0B6boweV6AqBw zn(q=p)+QII2)tS#UV-p+NHa>l){o9?vrJtiBji=5P%`S(fa$;u747W-%KytZu+T2; zeyjMAfIU-;gI7gUQ!CfClq>KaCaT40m=0l5J`dm<5Kt3d#?BAq#refh^cI5ZqS7?K zU#GL(%65z+@&6y+?}E+2B}psKi$PasYOz{}1|%4$hMjl&QH6NI#C5c>d@@3z0iUI4 zUSL$ar;sAihZ}ufW3)wIm%@$*R)O)o+W4Hfs)YmM|0v|RqUiiC=3YEl3Pat<0;Rj} zMvv2ou`c2AaY1@0UB97g@IYz-tjcdrP(E0l60~AU-UXx=&@pj0gp2D6!)mwRKN0_* zTMSU>8cU!%-^ghm)st(AP?S#{II3Fk!ojQSa({kPq1nJioMHLtjGvxwH1G<=qLsEb zQnh9gzD8vh39{By`Z6u^kg#kY3PBb}1h~Y#A0dj#h@P*M{+AeDeg-K1aQW2$-;_f{ zxg;L&$D`}KyRnBOs3$uS+LyOb55Hk{ITH z=jT~tzej_LO+>Qv(@-Zgw^--r~dhc_-Fm0JDI6Pc(f}R zOWOxfk3gx(qQdd5bS2h1K;#f^wx=1x47nYANkGuOIC>v&XiIcf;xjd`l8n4%CwBi` zV|)^{!9x(B{g()*el_&8>$G>gq8kAts3sSM-JuRi+w(t+_Do#v{gnlRM^|Go8+0AB zEnGq}A|(8YjGmk`2jMH@Zc%v!y<(s%jmqW>kdP3-rUO$+1LLyKg2$>u4~uh^K?A?rI17pBxZt7yfBwfg)~X`mFdWItV-ktfku)ifBGhiqsA4r7JRcd<3H{7)N9HX zw1r9}YE{1GzyChu>9T0_7XNZCT+apu^Pjix;Th(YmJ%uie9{*uVJo$<35oFDc zM;|5v1x_{PlZ60>1+qiQ$9tAq-xz@0Rk$||*w-m9Vd0RF+hO4-D&~E^Bb@;hKdJAk z$5GWs>o=qgKSjHESXEa)zkW3CV4(*h?CE=cc5sKt{J1Vpu zb}DlGc_H&S9F>)SD-wsln*;yPW)1?z!{%g4m{i^`4*J?!?3cycftj-eaixpaE4-c0 z-6S8E$P>*Gialo)DHjfitEy2ZpQI36u93(Cj)Qp>mApCSJPq{(=+%^vhn*erXTOm@ zfJAfRuK;hNF!?ZPC;HDuUjPaQ;JN3LfohPwQV$~ouoka#W5-^E3+QdUoajXw35GwQ zw*(xwEJa%Y_tOAH;m#BMBlm|1%pS_n(IXq; zND~4XY>cIXlXLDT(vhv%uk{jDcu%UcZ|cirZhH7Zy_b4K{Ze86S`bWu1K>Zy$e|y$}E{8^c)bzni|49;1+` z!{H2>%W<3Mg<70$z_AUhUCigwBE2n)+xC3<)!@4?X12)eRP0(qW2N}4Z&KH|=t){L zw+GM1>;0#k&c<)|nd-Z-%a&jX1j!_T(}-+LC>wy}QS&0q6ty70@1^B#zpD@0jiW0Z zQ?ep(J8w9qUjF%9I~$rCblwT5OH3F^EOZdZZlcRQBtQ&BASP9AQ6Jc{VGAUxI|ZnI z!4DKcoL~A>AFmEqHlBRwJvR3X16fbY6Dap&wq6rS?D&1agKI;%gqn}+7lrhuY}}6U zAuIWzRz#iR2`m)Q8=BYk3x@?ehMErkhiv|z#2>g@PgHC2vk0a@_}_}i6kfLFq=6^whZ|**S6hVJtr_>3vKnr?6$pxphQ*6t&8omfgno)Y2 zv-TKCu(GNU*$vKm8Fva7$}&LN4MAbr6E$8iuzNqubUyt%9lG%+I}C`oS0;nsA>2 zu5U`(vIlr3DI7bJJ7AENt@hDRBD4017uSHMgUH58EEHoKhWef_{Oq$bPP+js$SY)h z02k_r$7b`JOF74AtIuz_b>5X8a9ks7bA9ccx`09ur`NrW$K1^RI-PywLcV(WTw95O ze7fPV{#W3HRw1^Q*e^Ol!pE`hhm4{JctyJ4Z>E;>eP;uxyJBA9u4XEJvt&(wR{@GR zJ-Ztob}zu1R$U_FXPGg@e(nOSm&?YxGf|$dV85gq~>Gd7H6a~Po?qONf;=^UyBuhNw;Cn{uH+-8Fv1|ETB8w{gq&ypHI`U=e>JbMy3YkK$zo8hEGO#3Q* zOX_R}o(`s&ay>;T#eLAyt?Rh8wJu^{Yvk55O)mTeZ%BJUQH>A6!O~e%StLqE=W#ei zt4--7b+-jx(;gRw!p=qxe7L41Fe`mScl;bd%qvp-7T2HjZ{RkGpW}xot6CR@{VRVZ z!M|31tlLBYE?7%9=ReE2+EIHMb8iWgP1$l-#yG}M!yUy+$*Ip$`xWHJBTrB8*&ZuXa+MZ* znKzj3$wYRCdpbc45wu|dHDenl1!Y~z3x_-Breq*1{{`kb^(7cT_Aq@zB4w)mueFIT z)ZFGN!G&;eh6}p_@76ssf@7uE(9e1K@>X2Ud_?x)ZodeVFWr)zq*EMQSk~QE?+Z1o zTKJR@tLaVWQt(*>Ia(e(MqL<+Wy9nDwxm?G6%NAq8BvYI*7AE)LNjN0v`#4vs<_+v z>|R`WWpwu)k1$jd_V65i^84k{&I1-T68;?5I>8&`Xw3UHTo$rc%9%abY94bE=4$dc zLv4MJE_)j<8ndgKJ6Vo)xG5ohmME!Oi}EjLGVsrxm95b15BPf$#vGLxo_l3tZsD%g zGfI%+t!4~Pb9?}7j>yS+ zejBFGxu`9AnLES(`TI0`rxjOtaqJ}I2o}qvZD9gBc{?3$!%Edj4~aWNMdd(NpxF1J zd!o)Np$DksY2$B_*z2gm^)dx@i8xfcTkHRfiSO7|l45aLrwoydQGz)z_^jB?!iPIe zm7)42C{?-vbGQy4hs2sBa%UNP4@raWYpY)nai?`W>MKFAXk8 z9B{~&o-H|EWsC_!71^78m_jQpsRWON2a3{Wy z*qIpc#owXhcH$j>nfO~XY9G}Hw9!d5PKirU*4*597CZ+8kGTOOS61%Yx)%QlE*s8ZYxA z1}UrN5;WJ$s)0P%;&C|9`L!zw4&eIl#KD+c;q6PK)&r8VR;0q_dhkAuWP>ig0(`T+ zw)OU)YcN`Mp&hkGf<*!v^CBXmxwH4>ZNpFRKZ|-s*_Rr$;2_rc2mQb^>bY3zZ2&8? zIt6g|4=)xgY;F?gP#~_Pz{p7@AB1J^(h=mWD&xou09K2z+oMNCk{qj93FgjUz=$U_ z!thg1}G5JsLZ;!UC?L*=_3_Vd{lvyQCn^qEB1*-7nL z_+#{Xj&zQ7sYD~oS^8om#k6CZ-s_Io%03OmM?Q;!Gbhz2-;luWL)k&EvZ3++Y}d}2 z`V}yq=y!8QYWWX$SMiPX`?5JD(A&=3sge+nH#H6olwXn=F;abPusKe?!&x@G!u>MN z!P|~7f@aWWtqPv8<<>b6V$OQUk-i`gsZ93Aadt0=a6{kL>S{Rhm&G>wZcb^<9g*tr zV#qT{UrWg=g)jwpORn(PJpBZ5+vHdZARm-FQXr2-K=pOX7y{t78$8&QlVQ`g0~C9+IbLaD6^==x z-*463z&*94d6p1!tiP8uSQ7!$4319OmGb+%Uja(+Y-hGz)CXxd?o{DZSv->W$<;Ud z4~3^Fz$b_?&w}q3#4Gexc}NiP2^HXFxajQ7j!1P zeo2v?D(YlQu-?G^S5UCTGdALDY#>vS{S8rxCk?$39_%U{$YAG4(o5c>%j0b@mD{DW zPBw0=HsN|Q4XRWH`ztjjC=(qs<6s@jACAq7BwkxY4n3DZ;I0G@2EUF!L5j3Zvtzj`)-Nc+7quy4hoVr;uEf-ejuwg^e7Y~>VxeUH*~U1px-}d0x0W(w{w;Bu&hVw)~DPm|m@0oF_kdhSB ze=4~K&BMCJxYO0D0*LIhO2Dt0>oRi9&E!2Tt==;1GAxb3+I@$=00zKNhr-7j<@xV3 z>ydFI{~w0BHbx(gkvcs@c3cd(UIH#35J&wpn^A`4rx1S&|p~XSCV5qOHz=g znfC@y^dFGSQfA^L09DdZ-sj4CdVp|i0>p{C+fQ2-ISq}KP}7qanLy&g?3rpuZ<%34 z`a^HKMUWuFV4I`E1>eeQu-9=7tib zyYrkdBh%bM1rf4rUkHDvVYH4KAW zI{NQlgdVN>uibxy6^8zjB<}OJx@CUdyw5$%9BGw(hqgNMqG)BQw=BE@e9-O9dNM&;HBtVZQX`u=j@R)rJY^xN8-&U9#v;9O1@FdGO4!UxyOf=U<_ zQ{tIYW6|+1tMgfvH{K)g)*nuV^Si z6C`YSv3#e)1BGwQfsC$u->%rD;RHUgNym(sX#%*uVan!NhvFolym~X8uB25E_!r>Y z#7Ooc^1C|miTG@5W%%~f^T^-x`z0&1M)FsXHK5N)70B>TaWK@>?0=jc9IKjvM8fZsR!=nD94iL1E zl6qUX(SiJ>hh&h%RF&-ii|!w}{+bviXbuM+%D7SQK*y-OImxF-i%19zoQRm0M$HD# zT{7^cZ;k*4if~=;+56EMpiP&HjD?cvf0)kzQzv5PPOKrl!zlc{f6qHgw>LJO-+hlj ztjc})xX!QpH!>I%0$2Lpe$CNOlM**N5yn@#2X^ScFht)aofSprGGWKYp$Ww1w}=jW*=PWqGEUtNy?VOc#& zSU5c*`WG47lMuk_d%Qa;{TY;h1wcmE0MQ(VcPKBUFvaq2`&WO!FXcL8jVKWYtp@;H zbv9XHApe5Xd{|~U6hHJ2W(V=E5q4lO;hW||E6aG5&}xBoFZPlKb&SGnlONO+6r@Yq zD)ONW0bSF>Y>)ssn)kuF?2zpTEd(H2Uja1!tgf10Xhzqs;DyR#4gF0Xjg5%6>>5?A z;QH_O1@O9;FFg^iMSz=8g3{!#OpsOfir`V8-9d+!$dfRswQ5d zHfdf6FMO2;bBQUMpst3xpnde4oydb-0NySkE6{iVfm0d#q|#C(YVx6dOXTRwgfBbD zvp=7BP$B(j$Os)?D3lov;|ADbn<(H!H-O-fLzK6f1Z_jEoFCU2O=@UI$J4{n6EIjv z&hI>5)U87F3Bb=l$tG( zdVKC+k3N#6?pNP%a<8Sxb8n|h*$>m6Wis);K!nCf$qiimJRU6RAwzldbXr8TkTqma zKrc9fJ2Tsfj91qIS|S7yBf?gN`{IyGV;|_Jwe|Qbqb^I`svWi{pm=aLEJO0B+eoEm z-`Mu}1knab5=Z|?QWed3T=hCl${l-#-Iw%WJzz6|Ktl!)3@Uu)dj9cPi%Ip{68b~s z=MBV?RGuXc?%_Tc6-MYjJqQHCrwMWEPQ!{uw^Oz?9WPtn{#UqRED~NAh)p#M&gC0! z>pBabjq&K#EGHnCUE)w&wG2^FJ%(j>LJ>eP$*fwGBsG0PJzH=T*PtqXfSN6KSr>PL zKVnCDtQ7hTUwa$@Xt^A*bd^NPb3B7`4)lS|M-3r|h`9PW<1dHz+$cE!o#=%SuAWsR z(x>+VH-=$x(pb%TS+U#6xcGzTFaq8=B+di==QR-LQnrpT8y7kfj>XIdLJ6uKy*NND z;i`XAnq*{x_b$VYPCq&oHxvPtf}?etI$A6JF3RwnI#eLFGNKcZ2YC-mlK181Jsmkr}OS`&A9|->~n#~ic@`V1H?zl?y6UIR)dG|2#%s5SEtn~*z=SGVhGF96JuGZ6jfaB<*DNTBn(qIfCX z>kKE`Uk0w|an}^RU@(aLo}7?1Wb;|#<#Xiy2aTNOIc!KlzE99~jUe;k4}F2h;+|nx zW3vJ%$5LZOAfG4<#vVIRgs1YEdzi|TfPE$h4PU^Tc{xtX!P7@x&O!L4#|H^!`U4D) z*d>>n4_QD-n|~qOE876nG^;Gz+m`IKpXpu5b0vuU)!ihQzxe%+D5CSYS{CwP0`N*x zm@`mbS=adEB9M=Fiw@3HH5{x0LX&C$#~)-GH^4DJJ|(2lqYd5zL`_if1az*!Y%)U8 zerU7=`Ez2%hNf;%SWe*JO4&1?TI^v*l?w!$4^?5Ri^us|oM!lSyYKaa%P5;iFkrWX zzSP;OUkOX8@FL#YuYxJC+U&b`Eu#L zXD;rb-2O%C2+2Tv4kw$*k}!APUs+n9PCY%U&re-TDwG02q7$2PEagd5MEdzXa7L;C z=Xo@1K!)V|61%ac5TBkf2`Q5Sn%&;skv#}XMx9gp_x~E7l_Ea(YZRE?Edcqs2Pe*$ zp{Q)k$Ou^Lb-s5OC{b?`v6=Ooes_YgS~&wlOYo$-_990VbhuaFU*DIC99Xv+wA0B; zsQDeb=F$*ca)oLVa(dwBEyGFvMxY2SlJECR7WXe!#n6PSjDT7DRx88a>vxZ`7ubDG zO1mx&RC+8m0mNc+!XG^n>EUovar{~YM%OVyKjGWWg}jAT z(TTF&7zorC- z+x1ZawFTaPs4d_b(jPLH&grYBC(-L)=wZVoqFIJ?H%Nf$;)*csNDY99vM@JCZ2_Ly zv+$5;2ZJSudRVUY=`^itd3P=)J~{wh_&%F{n6g0dFo=Zt=($m=IweQlj`y8#K@A~5$ z(|VUf^<+cH&&f&JVb(A`x`J#^3$dn(%eO~9TSCf7b(*idtSk|E-Lf_Qj0yeLMEBT@iLJ+pIG zL}f++GK0=aK5kdY5F*NbF^4Y-Ar5u7)kST0S+DCj8k`5s%!tV>je{pD2cSt`GdFy8 zckG`QbwV#3nw}U!v1eSyKnFt`fxOlMGgSQJ=(Rx}=H#ck&n+D;hlH&{l&*iujt~6c zIqNeNKu+?QXz`+NqIRP(K;}*1vh1pSfiR)bZKTXRL`#JlR+wZ3BYh2|iMBFEMR25B z%g*u6G~hNwFls0doPu%s=&Up4;w3f4RhoTwvo5GV{!2u+ATt#fVQkYWehJ%N>vceD zR>bc=8OAcfJVH5TCYA6zH1ER1AbRnTCN6=~S(P3hA{X3{Zj@Dz_kiOi4G8QqmhBMG zzQAX&oAjlkC+EqFKZ`p6ta?Zuo?e+S?gKQi&P7^wh?wcLA@@Vd$0r$Vu8Doi-B%O&zA9x$!z&U(_L(8(ptlY-Xa;!B>0s>r${#<{)FWL=oQ_T7P+tc~M(zLIE zs!_+U=^&)A5_YC?H_$+yr0@&{xm;2a>RNh4rFh9^mxQ|2^KiNVT`{gEXNo||z$(>a zy8-5V%82E6FvaU=QZxpY`zLb!uw3&)-3B^}tSX_*_=K7sD&dx)Fwb&Fel3{!4CC1# zS`%Tz%?~1IG7h}PeE-}$R{_1KHkSgnu^R}=$N3yf^hVIZz>6pn<->lF+J(4d^jywj<(ItkQyV! z-AR&kgay_B9fF_38<7-mRzRNZ2Tk+wNi8daWF7RS<)cjdWOtzx?l>@~w zb;A?=F{;4KYT9lo(!jOFE7JsB^P*1^!+orI0ZCAK6A)1-2A1!7{ zV*pAxsYkHjCZvgQR_GF!TGF~?V5(H=H~SIJ6pw$*h>2l1^|YMegduGLi9P&8TRPKV zVSP4BVJj%|Rnsgxfk56LOYFJ;Dr)BzgrL;3?g=SuAP;h0a>)qK5!}D#U4%WSi#;Za zKt34?lV46TKyKo{CRPS2R_Rmpm2YMEPJgs6OU6d4;~WKV|HQjn8%r50ayV$bl%f9d z=!$n@V+4^fZHGXi1<>F5#K~25MJfk+Fhe`a)OIhbDQ(aLGP00(_0L-95f?rV342q9 z_qJ}6r5rU^$XuXBr}D=j=u|sx%JK&Mj4UWj;d~SzUsC)zX2J@;-w0F^FuT=>mvYMc zknh!p&Id1&`sIl>NDuJbdl2BcS@7alb8HEIWl(qFmYj3M{)dDS?i*}cx!_}XlJ6d; zNwUFC`(Hm~H)Zr5ugoKrJ2mCAy@hI+PRI|u1dFQ-;#y+_+X_#f-C&}{t+0{3OORre zj85}3o(M{qZ!$qL=8gL&|BfxMVUXLS7GX0VOjqwaW3f;L!w48B^i$+ufQI_HxZY+S zHV}PXk!{Fth5_m9zJyh#ea~@_Bu-ln=qY4Jvb@h1WpJIYk7<4sGrJ$ z!iRHXmSW7g-bAfo{5v_SNmP7oq!c+UYk#h;)s_Ow?KetJ1)3ic+N&Ly+gC|a(L@Ei zP8c4TeoOG1Y+Hf35wx&r=Jz8ms3av-P?U;5loC$EcT#Ynp#!rzt?S*0nw%D_shF=b z=&2*RAGsXq5d@R}a71FhdiLqVY&GIbamEi|hfej7*C&L3raxa^_F($OhhvWnXr;Ky|KX~W(VCfycL)LS?Ilf*MWVS`TF`zi}3-wk_1Q}BWksk zi=k=dK7orxMqiI&)GW}M`-U2Y!L)AdfdTUGJr%`zTb7;PHx@BNLU@BowMQfQtQUMgPKm}AtU8mmL0aZ{0Fio6m_JV1akC%|}{T zuJBLSEfFWZoJ8=uvut|>VEtIb<9S&noCJ6O6*QyeLJ$UV9X|->-~<2Who8$4e+Ug! z-mDT?`51l$nfV85HwdA0X0y6lpA#u@5-e$8H?vAzs}bqC5{c>jQf#s z%+o2Di2PAJYvdKtBqa~M_op?ZRNLZ336GCV`{9Vun-OW-Oykx#YQ|-R!fyvxvE|_@ z;DM@Q1~Shf4zpep%6Z!=P2lcW_ZGc1^EiSEtIe^x{6rm;*qA!Dgj&;=wQy={gnj~m z0Gn#rOeFF!>f~!_gWQeI@!hmR+Q%1sMh~22M86FjbjH?&t=29@sv}^UH|x5|bvWpx zh6<-j`6XQ8_L zF5hC4bB+I_(W!H-fG@$`C(}tB)6=NQQq+T4YA>|OTjwyK{Gx#WT0Po25&2u9IYl)B zeWcR)PC5u(jd$<}sqa{pDj{X8vR83(Y^=aka@;H&9F-~NM=(kWaew`_gjQf6-7bym zhmx^P%kLv2?YbA|n2`Ac zI4=9QoSey_dI_v8Ncqgvisduk3>5Gs*;o{0B_Ms$s{dvV2j6krkj_x7md+UhfT@+6)?qUIimW{ z0(iTq9Xi94W{FiE!^#18TvF5V`4Iq*H-#oWtyok3JB83Xtgo9BCN-o3vmPbLlk;Q-5kA3O zsuL>H-SH=w^C7~n%nX&&c^*~=1KazmI0dvy4F?2$oINfxvKYPtY6Tod0V8LR=Z*<4 z(r=+WL;it@XLw;nz|kAri(aefvmiSxvkVB3P=2Mrc!sZdRtCMdjNCPqXKx9ykLB&Z zDFF%V?e4Hbhs&nc+8)9c)Va|V*tq{Cs>v$?L^WY%StD-5K!0AwWse8v&4ph zS{Qr7p=6Y1dgUai-NS~8_&y5$FebD(%~AoPSjwe)K0l~{sM0l7@<-OvAAqOcwT|<# z=|6`qNS<$tGRuu+cURe_5r*ru&fd)t-EBTh2|jp*QWrTwu#|YPvFimB2$%IJR$dr% zw#cvv7fa@J7N}VN2yHlbCbaMzzTni^RVeu-*-)0&%FkqT=r;i|nY60Ob-qu)7Y0rD zPP!l~fBH0- z?HO$I%2M43ACbtF=pl+PM$BF|0`Ztky|tUpVjCb-_GwqiLj74hWD~P>ms$#V$tGZo z+8-r)&xn8utwv&D2}Mgi;IK3)zRCjWB;oxC2kxwr1nh_AVY^pK)_aD2ul3%#hQNw1 z8^WDau2{T}Twf?>NebVXGj-7m1X|J$oH|PxeYV=^yNoQYJiu3Yj3P!~Xn{E_;UUcP z>M)@qZXO96d#3FdRIjI|9aW<~k^I=|-Vw;^IYx8K3gvJPuVKjBSA6onT(X}}EL8a6 z^QpC>bi2YYwmQ=<*ekTNY|`|6nKnWSrHr5M4SgwmGAuUjJK7Ieln8T$G77M?RM^{( zCB6=>-utt*16mF-J9I`*nLO!!rqBgDPxqyzDUerO6=OF!5&LfU9DKO}VEGAd zM)XidD~U<5?;1%MyhStM3PRxkQ|(FO3e5WJu!;eUM z-_*9*h!q>a%ye6qC2G!>miGTP*yxF+Ii5|@8S06*6dPgzh?8e^yaC48ofU$gx zj*Cy0kj+3x59nrhSFzoCQU)XONKs3<&5D~Fmv64-KLm7r(etd&Bc2xeJhf){8Tk$C z@@E{AT5Y|xS5~tm#;h-oFk(uLEvOHD?~6BJu!iaOK}N6Mw75TagskneFbL=f(lvHs zuL$*b>Q!7xa(Hjg3S#Px*1#umPobT<_a1FG(NoPN%*~f^=lCe%Nkm$QesI0y$78<} zvEd6@2Qk%ZZH(Z%Io?dl@DHG}PyVC%p&u%7j!i_wzkQmPj&S%`oRUC;KhqsN8-u93ZcnK(KmLkV|nDw&EX`wI9X_eaL% z#sm3tIR8LAgRv;QV_09NYS#| z_8-b{ebm&VOX-T|Jff5 z3}}oDTO3_S%I?vjw7GKlc57iaP8{q2UyDE?vxTE_3X>dPXg~YK)J%BzUTjl888$Fc zFm4)YKkZQiqxWqQw!7SOH=du^QaQDSw@~f|zci|R)tmn>qC@XS%%ETRrw67j|R_OpuHUr@kMDfOCwpay1FK`@6-;Q*Y2j zHfvD7uaV5j7=8@?E}xWQ(^ARm2jJN**w+B4eLg8m5ono8c|7u}TXB|wWy_2No)~B@ zlzNZ>0(`2jHm7DufTqwc%t4aD#XsGbyu~ma!;UkHm|i^n8X<+brx=fu*qIV)OvU7t zg+wpy=F?X&>K^~dLLl|nMNxHxF!WrLV3n)A>2E)uQsjTm)8%*EgG6D00-MVV-yY&S zRj<-10hOSHT;`i9@TCrm)jiT=X$b}1<8LcF~LK9N1s)zdu#9R1a+X}=iv@t?L+pZ@r+#qg;a zJ9a%Zl?EkCP$I(zQewdeiDMzdN-VF)fOgSf{D9QS#r^KwX2P<|2Tt!rzs=L#s}Q~0 zgwI1xS0>Df)Rvl!@8}kzlT3JGg8!;BcM;okhS4AAYedgFTLx=3qiT-;hB*d=QLyq$ zal_dEdilRvA~%7j>;STYQS(jZe=Q|ErCe9r-;jAQY+rsD~){4u@?8=}S1}g(+UalTl z0gQ^o74}N*awgrzNIPqs1ObrO9dsnpwq z9FM?UxCmGtmZ+R^aUaU%j|iB0n0su?#Z1am{gXcvyHyoXda?X${Y@O=r}ZtZONmRE zPCrpIH~><~T`k^SxV984q368s5_C#htQ=OU_aV&GZF=pK9EK&>q{X5xvWF?iocB|} zVG`#AA)$|jlKmv1uvQ%^TET%;=XC4tW^IyYEi8+az-A2R5j$3QB0z5`#-H}OJpbv9fELj1?wQWBp+w0x z#^QM-$HBh*>to;5*8ly_!e|Cej@TDpGG+Fu$DOMcYFWJmPZRpBnwc-tKecn`AFW>a zZP9RADNbDGDTlo@OZhNkMn|6qsniNCA0$cNh7?3sc!Ex!Zb4wJf`l{87nr8$_nQOT)VFVg`pqqKJ=#VP7(X2D!gH+&cEn9IuVp`H)Bj zb){W&R@ePDigX`5|DHO~L=(WSXw)KIaSk=51?DK{@|uSe?#@Vyi(R-(Y)_!%xc2)Z zPEPT{Fxl~fR|zaC;{`cveP+Ei;sJD)h;hhy$BE94?Y`t%#gNdq{vN+aOla2$NlQOu5xL-ZT$7~$pBBiLgu+z!%m(kigf-zf)>QFX=L)c*F8-M2*N7VF zwvGsSGOf_EWBgV8IkG;JfA}D5s+m~>>s^p>STZY(#}~)c${@|b6j^v#1qw9*L|2R9 z3@XdeETUeb7WQakHFxdL&yQAma*2u#spHrxj(C0adkSad$~i-Wjt`dyj6NRLN_en$ zJn2kzS4B@6s&bf?(aXq2xz+x(r>lU@1f$ZdeO&`;;XIElV6Id&j8SD7V>KODI8Ay@ zhxI+bnV%%CuXY+H3NEqF)vWg^CFR~;LvvP#t*=5rLi?h2JIFyg`k^rG#cxxv{`3U% zpr$W<1u=t9Pzpc43h7HCZ6LiCWqEL#KdiYXg>w(HP9SKFYRe5X9+))v8wQ?ud&9cC zm5!bl9`EhZ3EsApxrmqa+{4PoBSAL;Ipvd)ZfIDlzKT#7f|5vWzPn4F3swr!<9~-Qy`K2BH+Uvd?;>76`3byo!w?xck zBKGO*mom!dZE-Tif=k)R+}+C7nHg!e(Elp`sQ)Dm6>0>Ae$X0JjIMi#4v@~&z&_(p zdnXxf{HsYPF+~osB2fIF^_Ub+AZjyG-IP+>@>7rxO%@DkFHx_wYz zU#=FPBstTmCHF9Iv4lyC7m(u$L`4G2*|U4F*mvik3z;44j$639>%HPNAFH7T*J9+o zI@`HW^dWsmw63OaNKq9=!qS$}Sv4;B-!iDQx3~~{iFUQv6t6Y;;rarCR|B(&27!Vz9DWC3RSnB^ zW^UbzFDsbQDn7@o=!GVY$(mh+=1PkpR=?JCl#iR4VqGM8e^{ej()DqfFQ*>;egu^_ zfKSKVz|&xz5I5|3-VxGJX=iPq<~;8NE7~gsoOBo=B&!F(p=_lF`#(A0E>GJQ-+Wp7 zfNW6q_G_J9g!TEzSJR&kReC8iR50v)UH6R=&D2PFKQ{{vEaX2Y;qk*)%!I$`urNpo znc$k0MWQhSV?UelJ?ci1Ynx>6ndNu^T+GJdA7LGr_v5;s*-OaDq9X-3f&S{A+boIh z+y-G5T1ICG#;T#3!s7|(#xZ_eE~OoW+8)^WW+zU0JQVy4Sc3P14KMxtb!y!H#i$ux zrQa45`nh&2u+HFgaF<)I7G<~vI}AFYOSe^V0n-~l{6$1N>u+aE5n7A@Q}%V7RpdNa z@}o=Ff*Jfjbr;%=39&Lub}Y~SIQn8Wr~#B--(^;N0oibM?mIA6Xg&nuGZpc3+`o>Zy&(>PYk4rl5H*L5<&tiweMoG_pw*e>AB zv08FWVC{_><)+z@9%7NJ=KmrXM`M1IQF8G*sljTzVDBWpVf!IV+M30iBHL-H!^1K| zJ)Ymyf*x^Ro%izAa69jz7-FDf?(_1Y!Bw`hDw?m7=cww;{`b$&gQG7IW;5yV710$! zv3Y{1u3(qT;hV_1ga$^+^~eT;OjnENvmx=stFS09t%cn&N=%{-Ha&6T8bNi)7#q84 ztf$4`oZrEulV>-SO!DCRXR0^sr7CDp56)$A=!b7?|1gX0%z|?5uJIbQVXS3$O+c=JT$9jcRInNG6<2JsxdMyjYpiV+G+Iub4c6bK7||~rub?N# zJx8_q{fDpNRrdf{q3KId;USt}YaS^3 z`;Vh>+b{kwA03A<49lyA^MJ})ylkvzT)F4-r2J6{r@6ZSTw4BpgXxxx0TmJK-T|4?dgCTI z*MpDUX74nRMk!*4XwI~ip=&!=ALoj-h$LSmGjis*j7#v_J9FKM(;BPjL+68gQr);= zQD10{>^>`h!zla+At!1S>~mlK&*kX3ombCyzYie3Po0TWqumMEE*75G!GOUmFxKJ1 zEZ@^M39IvJDH_yTC0P!2pQV6!>r(HzbdU>2&NM-o(=0u zNnw=#R|B#zFw*ew*TRz3B!@`L2T8MOs8-&`PiW<0>HY|1?{o&79!+@l9#?~_D$W1k zLI|0oelJGxRgPZnl+0OrUdx8@JT8WZ%dU8gh$8;ay^az&0J!oqo)7^WS!y8WY5Tpe z<=V+!f4ay5siP4+#H*0!0B}S!lv6igan%GhB&sqzLnPT|8s*A@F)qS(d{~@55fk#ld@1EIH)Zk2eGcIotWQD67`B*Ex>Z!EasBGQ@J3gVhzWdk<=A@&rlxHlqK$DFU#Rup~L|EpoeW{$cPj zhgi0hgCyCx;*XS4lxB8H@k!$pn^$qn;uBUgNw_ZxR}A19hvB^%1dJ~YTudGX9i*gU zOa9xm@BmD(MRZ#9?e5IY)6dmIr^6M!?+l~sw4AF~fua_5f^Vsb|D=pq0WNx|jumCQ znW0wJ{0Ra5D*GqFgtBq-ZFsnc6h_9r#q(A9-=huyX?hBPQ9WBPoK;Ka*(UJWW;+9R z$`&X+CW}U>^u@2hT8VDj;Wi(C(HQ4zjx%Mi7JtNNmdr9@Rw0~nYHAl=g#YxDF!eK{ zG!dW4b~HY(Pb_{^hlemr(FpDCUar5wJai&)$tdM46# zOUL>5{nicE!U~yOfTD}Ih1&~1ylbX`-q_;K+D1r#6ZmQV*B=`1m}@c|EPXUFFH4LX zws8ZgBOAV9tLQQmemydEEM%BGQ97+tN z?3*N(Vn|@!18tfdr)&Q2{tl+hH5>jmfkG0}o`dXl-2T=<45w@>miE|VSnbr&WbiX8 zVa3HyI4+*b>7iQd*G-Y#zjwOqdxLx}S=`L^g~=!&C*h>rbKm}JBsGTf_r({_CEuN1 zp5TY7V-}m}O@a$Qg9fYgn@gUuzsS@&7%8hBH*T*5%VNd*)Y;H-8*CQ-a2fZt~o=MLv$C^>^+ zEC0SvGI3=p-f5J~^RDQGj%aYbw|7hTpfp`BaX`-gGIrfEX~P~_OEz6Z!y5C}a_f3; zG4c?r>n)^dkcygGR{cLGU^fkbDkC#;<*I|{^xz^j|6IBgMMk!5|LUY#QVC^skPH6y zDS%VP;YGvpD?*vA&=s@(@X7~G1VR7>)O!0dxCK|N$xl~z;dA&kkVobT;Dev|UJUyH zX?`A8C>~d$fN~mu$mGKRuG!z#KU!w_ncMtBRqWx)|LH23vFCE=UyFe(d|;gDZTJw@ zlF!*M0Nggm+t3Um@jmtM}l(wbgX*SRXti!RDw?UC^dRiBEC>TdJgX=o^HgR+136w ztj}z@P9PuDGr+YP<$XHB@cxb88p$927Si9W_$lkwBrDX$I}C* zp~uRAw$Z~tm427^)5F!GAYujoC+g*DCJ7_&FSf@o;2r^FvJ*&A@^s4abo!jUTTpq) z@6Mk6_E$vvMEZ07Yzn{Y6<@b{&$GLG@_eN|$K$E;xoS9-4a`4x%fW4!>FVE(&c$kL zE&zEB&Q-yY(z2)s8#Q#mlF+5W3XIGn_1pWRa%vam)a}|^+2>fqMs1b2-!B6z<8eb7 zsa$E6&_)xfuyO=hv>bGhBG_{MLFXmc+B1mh=FnQ-iUK(S;93ogdmtCpCB@STMb}yO zQH#RO?Ox5<3{UzDL`i00ORi-)E3k(hZjtVZ!Ri7?@WkE1g?<7k0LV`UD!(x>-V_o4 zv*BDtfC%b=Q&3E1VCijsB&b&fVR=h%6tBo}&RODS%l~l;NH%k(l(eTI@$zve_i^WB zh+^xjU-tEp-&NbQEoyK)C%6_QHX=uI>buqv58Ah?o9sQF{uJJAR8!&S06go*S9s3H zvzOxgHDeUzNZikPi>fO-__pA#^@zH$6Tu5IG8u$CqAfjx!)4C2uy z>^~g1dVuXG9XS3vb!Ul2(ugJaGZ;t?*{idz!PUtgj zInma)2xKW#cRA57)V&Qb+s+Dh=O%!80I0mXFt~e^qwDst?WnFx4)JrJ|6SKp^J8s! zEM-7#o5|^d>x8oeS2U7eUSZ}!TU$xE2apUlAKqR0)DN~3kTbb%#b|RJtOF^gF1;@N zygHwn9z>{#zGFQ7^1tDDFxDh<{&jTntN{5#`Mbvl+O@!B&L`CIe1?NiA67Sliz59 z<__7tMR<%LbaKvK7PFXDC!F+Kg>kdq{4}wA1ckY=W3q$0KBPzMxF$ z6hC4K{uq!vVYhYD|Fn*O$(N9xNZ+^QJheupInH@K7X_%>Qs~!J!FN+a$Og~qqv@jM z`(TQDPUR4{4yNeltP z5e7#D36@xG)2dp3k4cz(u)uP9mXnp?Wp(o%QN=A6)O#4&rzhpK@d4^ef23tFOnI{~ z@&uFunA);uq%Ok!(sN+6kFkk5jC%u=SLu15`a36LnaOUmsaqo%HR(D+ILB9VJ{dT3p?7Y&X<;k;@O}W9-?2Q`MZY;-B&w|n zhh7G9eEh)Wv&qt_E_J+~iOxjEFdTn*t{V>X^qlCrEA9cxvo+x1RM3=ZCH&-*Z91nu z&a=miAUc@n$rlNUCMs?ds>FsYuOFUH?6`lDI z(ddkDljA7{+@f$QxfSA(N$#5{=ySl@qqC5W2lD+4em1=-+7MbCQ+w3KPHC;HsW$#k9HqjCZXRS zL}93;n;o{=C_}>4d%;XU&s$rq=lO<85s+w9NT9o`GvCVx#rut-YXz zRCky$B@p{=1g?+Liz7*ILd8b)X8b>qRw&Mt+n@Mr1D7!UmHQw+41H6^UoWxhqRZ<} zGDe!HgGiRaDye5dCn}I0&p`=keN|;nonl7vLpFX|ew*?uRbN!)Z=R}|iEa4Np5rlK z9xdaw1u@GjB3jnYkNts&R9iZ0*VLhRBpQ=!wVa`CEaV@iHmAL;Nx5^Z$Elzo2Hx=r z<%T);)gw#SeS}g4p)I=!_G3-1>76DXsVXc)snAdF#N&LoaI2EYc;&%RsvOr3n#oxq zU*Ibd(AuJr#G_ZDoQ8f?%}O~=w;}mNP%7m#!FrBkR7Z%705h48uQ435+aYM`3>6cvN<*sZ=pGRq_GWwU-X(wj-J=pmSKjl;N zCilC1xNvLcQZr)L`JHUw)m}b@(m-|E$Ko0<7mr=lg6wjnN7q}`E0n7#Q|e^CQ`KEJ z5*DTH?Z$iS-L49u8dl+R${w&{#8URD+Vfp!SfKGkPng)u)1@vk9;Ny{kG)3eBcw8 zG{F%^^{t=X<8kpN-B(R>QWQ--ER|CRzkPBuP1`J7cCwKp_=cx(#j!Iioiy<SVm(HCdVXL#Q(PZpHvsC+n;GY9=$X@RsNJRMs)w z`amZxA~Wc?_Agn z83s4vsw$i3?J3$P|ExU-kDL7lVO)Xu6snt+9O0che{Q~%p{5o;ni|i+hLm=~esp|n zksTkAo;qxS5a1Iuj0x51cxXT};W?@iX95P9Uz)nl*eiZRGVv`@201?%-+D{7`) z%laHd`EkOJ2zB*%-`RZp$h|yq?leIi6#7t!fm4{p{_#_*fJ!2(Eu^Q+biYpAVG^13 zK`w4fh8Xq(*V3$5l7MEK6nsv}H%iak%(gdDpBpIXObVU6T`ylk$l2k&2&pTp(}diy zV9cFz{e`=oz1j*h`|cr-kP8~iC3()}@ferQI!i}hPY$$+PgKri{el^Ue{Tw5B}i|;qh#68wD5`2|KLq>s_8jea^hy=?ag0nPz z`kZGM*c}*|HIl>uvNW%Thk%AMY=bs0)ikQjg*22N=Qf}U5e738|fB7LO_s^ z4n?{|T0%lPMY@}JZQz{aK3DH^-}}E`0DgO|x#pT{%rV9s|5zU#XwIYX_2~`KXjDG> z`+VOHV_ML#dukO;zIx!47|WzqHy=0_3>`8(tieG=R^glzoLmUdE>C+Y5(DGkBF^t_ zuU7RXu$UGYgW2Es@Z6O1FeWcrtK#19&xT@H7`EnUOIZ4se*E=Mq}Dn#cO$0j*Q8|w zspzb=B@2>i78Y-0O8+CJ#6xjGd(Ib>i(< zLR%`MMX+QEvKva+3AiJK&Eb3s-}}1=%L1?x33wuyE0Y=cqi;&cO4xADjsgk6+gkN~ z5x#Fup4@h+&8wW1TZi|my_P<4*V?b|El+e%FIs0wNs7|+Ls9l>_6FtiS~s9xE%@HV z5LTUs2a|p3rjIZS!HWHnsp8t&Yb;A_JKKA= zMZVR_aqe%vv-kMG-ZThmwAXs?OKt8=X-bYya5+QQhWlj{%L$X^`(G1SDe;w;w~4#D z`iy@8oRfg&P-o2%>{v#Q!pf}LAnZHa_viz|xMTIVHMHDA=dorP9Nq^I_=&bl>VG?= z5hpv;<6ot<$Mo*oihXlp5PzPq{~dis*zw1w3I>8 zim9>*RQ*xgG@vTU*%96nA>AqT(5-P!3N7cWs;srs&*r#~d>9^~C=Xf(-zu=#zrea( zxJNkFevN$Gpsg|hYmT`~-thTpz}Ga%=OyVdxmzEM&kft#^O8cSs;y#&sp-B)lG4ga z+6NC(W~B7+2<%ukCE+U%p9DBz7xvX3c;@^Sf{A z3v$a@>T;x;OnAoisvfHt9LUGgm=92b#d7&3SDoYhZrfz-KrW$}w3ax?@0HI_>ABUK z^YuQ2Jb8?t)~w>)rg!OC-Be!NvoKC2`cZ!!_a7GcEJ~D*nk!vL`1mxD;gS`}lo|@dJJm zSopL7Wzj-PmRhDh`GMMzfqhv{$EaDLGDOr#w?yb@P*rl((&?HPH<<%_>!YfJUW=SNeAX%%p&D2)CJ#Sh(BLDkgO~M-=Cquk@5NLhk{%FW!E3>8V4c zGDNMT*qp+btdKfAl6n2mzW+j<8^1O#L!zI-N4>$?7>p}e*{6Jg1uW;`N0O_3oZD24 zK@T!-Op|CO`#V!i*SxDyk-k26p_2d?`<~$bP2zkLrLWi&XaOU_woS=IAy^n>ay#Qw zd={~oyV&E0(jvkpoAnIRLU>v!Q{ap)mV;w z@H`=PgX2r0s+%@%2=VUKeGgf^;vvK3dt5hvq)%J>ftc!wTc!7>+jS3X-VNY?An{;F zeP=LmO_E%&jjvXb+N<~Qv))DrDl!NpG#>|ZvxDtfJUg)g|Rpl2WT z6>kV&8b(hgO@upGgC;M4A&*48cFs8;1I=UO~CM4D#-f{G1>tPqKp3ut2 zWi-miEW1l9dr@*NsWM>>t|CIAY7B&@MKd8JKV*gk3LxuD$ial-oE7 zEzydY8y0$AJ?}?&phnKj4=?{uNsSKW5Vb(qY!j%YXGbeGz~k_petuhmYqk^pcHzu@ z6+JU5+#N5v^6%8bY#);~AqFRHGA6~%FZXzqg*l{Zf?vS=pAweB99VZa1c}ek!m}%c z?5vrjlH-gy`kqR0inCfwm3j7V?fCW$@BHnlMY0xArlaDw$t1&Ms0rOQO`TqPLEGtM zAN6a=Ay1C#eJFnjh0hQP3aK}kj~w0Y-2&qt5m0UIvp!I0{jlp>6GP2AdbrN?hpUdN z0iN5b=uV?PDz9ZxDP@oSS!)W~BzME^Jg>=v=>PAU~uA>DE zw8u7ZKg4nC39j4S7Sv>k3-5emGJRNby+u@yE$3p6r*M3fSdI0ejX;K?`%|yV`d_Fg z5516vq$Mr**?LqEmL?o>+Cr$0Q^#1-b_>D^5mt?j-zGFA+56zf_{o5GVky=5V@|Mu zVDb_P)5*_0EQ_y3J!nC~t02Qr%?+eJAne`u^S!C*o79*Qzp6_l{exu5a&!FJU=v6b=Zo(KbQ*9;Tmd6##&XlsaQD}a11G$ zzZB&Qx^$zNN*Rh$kv~FV12)QUv(IAjyip**&;`9!yK_%smJYwAhS6^+zioNIBBXQqN>!-npxl+427FjrZ)Q}=qpP4zP1+OH5grwqDh`N*{l~XbcV*h*zbdx4rx0GXtU~S zaPVS)mQqIlxcuu1jCX<4;vpvy#J*zqc{j9XSl(LE{vSOeG|wI{K&%N1^4Qs`m^@gAcflYxkHYU*(Xq04ur z2eDU`au&J@O;z01v@Y6vibY5l9b}Es9{HXam@q)4XMd8W%XtsPkO}bksitmZJ;z5u z?bPtbZGV95V)9s`KJx{Pe^X51=~*-9oVGnof7&aLxd~dvG89bE=@a>J`8@MEv-azm z%)RJekKJ&bmD$}hU)>{yG%4`J(3n_Vbz=5#Gg1?tnX&u*a^^@%j_8UuhUG>Wg%-X% zJp67n#%X;`l^~r(AyWL?ON_*pxvN~pggJFq9ST<|JEpOSUJk~uX?kd71>(B`T9-X{grFCR_ z9p=5M@>g(n9zIT4>X9$%1Vd+@@lS1#W|vV${VQGv;PHAfN$<0b5&14%Ck`qfP4&H? z!TOo88$%&w4=D=m`2>1qPxjlHUf(6rEh~SiF%G?2XEc;fAt06!|MK90tS1tQIoEtr z#J$-fl|D@)Xo&FFNG*gkY4rCE(jMueyFT#1RkpY$?I=);6Ywz-bY@qo$b_7;O?|CG zQj&H}l@#v2`-P9e3qF|@;fTRM84wdNeML~Lbutg=4sXbCUeq*_R_j|a$MFg2gPz=@ zCDa9+4Dtui@mo5|HuiEJws;N0dy9LMl>v}P!jh6y&S@+a2)VEw}cDkW8zwHO?7GBtC0b1NtfLT|HYAb z>#9BLe{+Fc>5$TW)NWlXdjNrx3JldY>E;AC>}*Z?kS-mmqL42b%c!kV-u*Cp$aC40 zD+(s)yPS{xxRal-yK<{)SawTqFix>#=`Nbi8hrc?+}jUshjtRn^y`|?VSUF$QIv%- zZ9ct9-3{lfSe1Sfw6-=ynrl|Qq#KG$`aHQX`AZ{n!zLSQ>4Bz`J_OF&xbZ_wLZdzZ zMXk3@{#8{jze*u4-^yIrcysdZn-zn!G}B+VQH-!04|$%6(KfOL2B)tS7Lz}~)AYMn zpH)CBWSx{#<#0T{+Ik3cNo2&f>7E+Px9d+PM$_ZrQ57hp zy4m)bU%BUpP}=i<{emDQMq5pI6-nS#c}Q_FJezX2a2c~< zn10oQdellJRar#YYKis-`$Z3C?ws#O7(T+|aV4!kX;=dbyj#sm$Zd)E0}RzMIZ3^n zbD&U;(C!?}^ZM@ezgVU5kSbUv5<0X_$AQ# z=JL+W(iA%`6YfkSV_g`p)FPLIreTh1&G%I3;T70BED~a|NP3=JruvqP-8N)HJb z+Gw(hF#$vKaLY={9yazKOLK}4@}!wA`23Y}R-=upVOelMlN(&_aT%K9v8q-ciuK@s z0?M|#VyI4eD6d{58<9N1st4LH66&;O8f9cB7lz@_a<+s5riBmiVxy%b8wx_g42cjf z6HF97`g8sa)`^BV&tJ-}l{9ROKo!=c5*OXjfw68);a)>xCLFg{MO{7_iL09=PeSm2 ze$zKDOHYH{jDpcs0{X?&(ax9-0oAdo=mF;e_0aTIz=esl9eGGSU1ndd>HxtdG$7{Bo!Wk#Nq}sc{%Q15VI=NGQ zas<3HTM`!(5V(M=tMq5F^N!uGlFynCIa3hFFcCepl)@P6#aDEGnT{JP$$zW9`Zs-m z0nnUFzmwz%Y|ro$(HfWvg?^)97j6lc;~A{&Fd4ui#Ciz=r?A9UZ89Z3ciIh!TD*^t zwHUyE^k4^9^gjZyE{8J#*g)V{!Cg(9WPG(}cEjBgmvKm-G8<+Cx&6E)(hnwO)By@G zEZlKdlHg)P9ef58a67bipmAO-aFd#ZUn3bJTbE}quQEWjUAI(GCw!;i7dEN73_yB`S9!xE-0<-0+j`x4!rvO4u&(EEAqF{u`?n@%5 zmpb-n;_mTIwYynS zn#qU_F23Ht+3%)kQhaYor%$e8Fr^egB`e9#TVexmN}>iTrBv0`Ze&lvuy|0uj)S2xIt07$CAY5J zilMnU`|xFPz~;BO0mx|GEQ|KHTz!OlMCdL&n~c|kN6%f##2?V3)7}mZnzivyE2q~O zl(TWr!`b?k_QGp97rkW?L)+QB-M&Do8Nb)2&RwLoSqxcJwHtWcsa`xs2fc+}J6)IF zeLQ5ICkzZ)t7vNpD&hPRu4E~+>}%DB*E?@?*Qb}NhN`(Q0)v@5Qnii8YR=DVvYeO7Cf2*WHMdH{+}5FU4rf z-MJ*4{)7;+2FOkkGSLn*DWt`y1~hxCi$$H+k!ua);I^?226d=Sw!Y$n`IoY4pcn>#e^sQYe7cXh(n)qDA(Hce( z-;zY4F;lk?M3Gg@Um(f->KzQep_^e^)?3{#hTtJa1L9#OWUwKEPU6DrfB)=Gh5Js& zC9F1X;y1gvFE2v4B3vvCRE3p^aa7nuh@{w06eTqtORZnP~<`LdnF>sfII2aI0>%360iKEz3peF$P`z^)Z(P? zpc4BecGrK+uxo)8u)mU#{QkU)`Jasde^XZno{d4l#im7L^-gC02;||)?qoDN&$#+V z>#Gw#HpfpS>rS2swCYMcM^0CX8u1yqPdZR!t&&N%syjf>)QY7&`GX#+KgIynB=~ig z%df(d>IN=(2X3HUxT!(w8?IMAV?5TeAG1;N+duSx2k{}tet|2A-19C=ZZYut)S4!_ujn7zeEof$^jIttbV@Lz}mjmVO?0fGk6i|9XxPV zscGvk%ev}l=AZdQX5j<#4SYXm@kSM4HfLdh9MuNJ!Y?j9(#}C~3KHG1c{s>U*&mdhv8tphlQIC7cjqW}C4YzJ6w8%hO?1|gH=l0Gc)KV@C{#4K4 zBy{hg(rb-f#5f%=SOxwN+FxM~R+kQIF|cM9daD#@Pig(j4(@h;E{!m=%0o_Sro$Kt zC7E|5Qhi?NU78+s7^=mgGAZ(g4Ods?acvg#mJRUgTU07Z2N0KQD9l3mUx5HlFdz}P zBm|mBWT|iJ3OS4}_umZaqjrorMohG zKgf2p+$9^dFfCCK?&WPMa2`PMO6yZ5G4%Qo*`C;L>_c9RY@JCAqYMqeQ`nxm z82fZN|61Dt((}U2cKaR8l9t24z_S3XK4d>bZSSwui{n}3@0V)#Ui+0V1!D+`Uv6_F zdF@r0kA1uxEb#n-$`>NDC(@FO&XRx8MbB$hd-w`)y|f9RxJrJ#1iaL)Z^v0aP8Vhr z3qMiiGw4SObzhq(Ela~zx=z@0-SajJh3ezynGMOs5(j0d>GKMV94Z zovbTI_|Qt_A3y$95)yW(bkQKc#IB^D?#l)HNDb5hOU-wJFqXC}a%MN6e~M5KN^oE2 z(!Ek9IvIC#7R{9u@gBa0J2v*nt8I!gyF;~dJj*S*F6iAX8(Pq35?Ra4mu4j;sJxVK z{8Okio#1baWdReS^B;Y7vhuHi!-{2{0f_Fqd$?7VEY>WTDjwEXGbx%Z>ejjCg^R?Z z!yDHzm*zyHyySE$_=t+aTD&_ zeQkfAq%=JUR{k?t{#UBMS4|bxcON)E{ac%(&gi{}DJ3d5&b`M*4RI*MwQZ$u*)`P1 zEvmQ2PvmTOv_xkV30oKau6rT{ftVAX`XTb)9ex&rvA8kW!TyKev^-bL5K5T)n%b zp0!dU*X))S-O@@~zD(b`e->WpoQkL%0Z&;p@}@yq&OLBUt1$n)p!R51Vv@bWcI9i) zxPw<#`c}RS2lh$)Xz4NRx;|~>6xsPLiyKQ-k8ds`8ZVb(X59#_RE1$$v`I-bHqqqD z(PY2nGLig+ur|r>uD#6AU(<^2L-?OgF!&5Y-^BAB{z68~=iP``9w$?0h*h^!N;JyT zJDO5r`CL)YCX3Na0bcb(T1KoyFB$}uoiJVD8e%>@tuF6@Xf6CX;wboRgzB@ug*tTr zd*`L#zKf)6LuMBY#`l)#vislQbN-_rs-I~$SM6h#5d6;DBMxStK$k_#h#>O`N%0It&IVkbY55Mc?7aSfnCXYr9 z-2IF+qMhzhaLE4j)q@qw`7>+bx-0d=?U9!C(*@D&Q6`=-oK0$_g><%Y)d%{ki@9%! zKi>3no6OJ>Y{l#o>&w&k%7tW| z!uLY*<%d)TKTT#^Ij;?yydpb+NdPX3vg+L4oUu%SWmO;;tQ}2 z0O#@30+&JSh6*O(sfy@rbKWO2RwyA>&X*I*Oxn;aWN-8gCTUUMblY7O4zrj-fLDDM zgjCQF3_2jxx;NnU9*-talhr2x*t$JM1@*$4FKw84*HN;p|60Et(l|be2P%7cPB+DXUh*O-wXWISO&jbpu-)e|982-l^qW4@D zL)tk~_0=|yKe?u**r<(W(V$gb@=Qv(bVY&0VhdlzNjfM`>!EEU$~{4P z4CnM496o-PkS6`4k(4!_AlSf$!{<_jV14g-wn@O#$bA&wlSKjUW%OWA@k5Dw+cma} zHR`A{sP9kBjGnPvK#M~6`|{=n>>gCTAGxh@9FEnP;|}{EZhHXui~5Aqk#O%KJ@2q@ zMB<=Z*1BYjvh_V2jfQ|+_E^5{r7E&P$*2>Zkze#a887=6RfwA4QJK72{)$E8dyBw~ zDUe%*XbP7Q5`j70SuGr6q_o^R+^k7r&TMsa-<#o%%=xc7=eDTKPE3+BlL2bQ$ zCu4U!S%(J5Pir=x-y&|g_xZVGtWT$(i2283$hWg-NP#PyF)(~+k-DXmxpkN@Cxp{E z^DE6}XUE#N3gQuZw+g65Fep);H(Bccaz7KI*-3(`2bpQs_65DBxmdx%@G*zP{U@YH zLwpUxEn$s#rujFC37bCWoR20Fa-hvw+rhdL}2$j5nV$uWER@b*T3OL zf*OT8#B4!K(^t!Ce%%WQD4o;sIo#-DMvV^FDbOqNo)qMK<%Q}u*VD)2qx|x^D94BI z+J6oO{qfW1Kxx^SzcahUjP%^tv#n^nTXkyF1-T>Kwq4MqSnOrCoJ4%Kr~3t&mnVI}C4xrhE6>?Rmi-cc@p7a;|Pz@Y)qNcjIo zV7^q}^d==*;c5bSn3(nRiwH9bAZTRNj2YiP*uFcDs zlSzCi^@KfE4h~jex(Ipl`bqptgr7|f2da^|;DB-u2Yxk!wf~%gNVSk34^hSVp7%uj z+#5DHY+`iG1f88L71apt*~7veDwJ~WT4pc&QkMl9wu=t@hCRRRITp${arhaa^<#$% zJuQIHQ&2dl^ggpSlCdCN_1zxkf5W8 zzj^n9vt$q>?eI$#0+q&F#DSfX_X9^p3I&`sCDGQbUTqDkJSK(|OihHz|2v;j0-iA$ zkRpSg)Vyo>vG|kIPtmp4_rahi@v?6Nermf zWOlb(u6xBgIQ?;1;WZC;{TnUAp@Bk^Am$0a_Tlv9EF=rtWndbETpj3Uk<|Er`q?mf z$tUghD{GZXXp}dFwo1|c%<9}!H4Nh7|G2JXIh1yvswk^D&j>mLRmwWVoJCu?3$lqr z^k(0~o!;LG_MXsIe4;|osvU}-P0SUQbDcJ&o5o}`>)wuApk>!!yA zk23Cm@pE266cdu%l8=PHc~}M^cbMo-8P_J4o_fM~aYH8srg*s!4uT*Y0SSX2gXW1P z5hb3&+_YE2<~4I%u)hg8i^-OknNAF1<)X_&S#eO+RMhjcV1x;S5~2snmOq64lmh?~ zgVvP8khNz z;jS!TIEgz{1i2b%s+$sED^6GUwZFV^%CT8uH?51pZ79A=_cg#zMVA5|+ll3fZ*418jE;aue1y^ZA4Y&igl#%7!k!JnNrxL%SJn;s2!`#{08%2RqtOz zqm_~T1c2m-yx z?z+X1KY1%A#aWbV9QNNMCZP;as_9tC26&Ur7^t{D%q2R5LE7K0iPHg$edel;<4p9! z_qNYCR}24I-_ymWqViPw6jFR*8wj5T$ZelOUjxi3l9z4l1`n)0xvo0)WbRNfu10lW zm0vh%?vj=aN{H1_`}($+o$HwiZm#s)*0V@kLNbSbiiSZcTkG%XK2)El?{* z{=n9DaRBO2Y7H2SCDCE>T}I;mpPM|OE&I5mVq-g8Isj|Woyei*=gs!G$y#j<9o#y%}J|n*ig!)%Zw^;*QIy)`TEMOF!)_KUE1)Gk?xl~=W#i+fqID1%J zIB_>|dOj9o`jqtx6d*JGLtkSPFfFDhz1%qH7U`GzmOGIOM0$F-DNe&#=_$Di^zA= zXraL^EslgJTBL2la2Q505 zg1k7dQp}U;VFGCXN z?oc%r8bjZ;EBOC{f8>R^(kU`2N&@{)R;L1B{M?U}ekJJA*`WO!{i&YClGbl+!^+-w zwe;*N(3l?kfr^szK%P}X7A@zP7tQWBjHQY4+xQ4|fH6EZ)|7Q}8s1(PcMyzgGkmcW zS!9cM3IPS>M_`^qKmsVI5Ky&nitVl(!)o4AwhY6<54U8 zf2^?We9+l-IcHvN5TvBBsx@GJtY?lAo)YuPwb`z!Anx;jY}jr0*0XZpvx*0bS}uOi5m#D@>I;M}L)$YVn0i zklrIyF`Xw-vB676jXJD+--IryGe>DM4*+=uUV@J zns;6B;(SG!lhTY|5S)>;Y=_3?9*hF_x~9KqEZIPhAH;}&SK3g3-|ypc034{TXAlBgX7hodLrQC+lAIPQiPX5fr)HhOFYRs2oUcCS9MNF*jvYo5nE8*U#<|?V zP2doadH4nMd4qm7MbHliT&KhfjSsmsT&G{ddc6O&#LZ&k%#sb{elAp__>r;01lI}X z^3q>Nu1;m&L@{FG`Rv{yerd_x{v$Eh0z}xhDplagaoxTC(r~MLmJx9<11jE^5XuB*3VZo`hKEBhqmRqq#$XWYb*KXa0vo6mP+x3klf zeen|ZhZV(A1CC$c*(gx!aKpE?g|myDJU&%2iw`)7e&7Ly(K$_>`W_MD!#=rnsRCpO zRHCoLK|0#0$z}8$F)DzApFoxK4xvKi$N0YjgQ%uH-zGsgzATWl;= z`t?q@D|FAsIn$>bMGx-p{Qlw(UFTF=5p&@;Iz0ImSFeLx;P-KmKf{en{+4}kG`1|# zyMbogiaAIBXBn0AeJ9LnXP>_uF>X}X+?qDg#;fQXdfR_n_K+3FIrUiu1k%iZJwgiM znBF-Hu0kI$U%)DYIhEC;Mo`H^+=(sX@IJ=_F9)ym{Q>T`W_uaN10^rK=5y74nwb;s z|L8EC(Ro_~Ad#o}ZxQ34?6mT&=bQkw(GVaSPaXnuu0x%~P$G$w^rt!6pMG!-1FDVc zaQ*1b>SWqnJ=~cg3~0>#8@wXXw=5_@kRfs8@KhW4piUG>L9g`|8;0hGP`Cm=F%uMn=R)R$RWQ8)l)i9eGKra z5-$ZNU9V}Rhci(UFGD4^(5v}ctMX+%4&57$uNjfUrOr|&&ums0-Xt?rL{r-h+LA1R z?P&@RXG5s@@0~uYBhQ7r`YX-Dv6zvJdudz`G^UXP+ILcaGGU!WG~#BGB}AFw9oDnD z%VAiE6x~@e`UcnWZe1X=ONabvLDQPsXXGjbqs7cAdDyp%qt6NoZL z8igtxSw{n5Xldp(>XT3@P;8v!zTc~VDzhYkh<}PVard>Eisc7zvMu@HcN5$ZIAZ}5%vj7n>q$%77lCfn?>f$ zWR85}u`EUL@!EU|*%-*Dh8}>3|2_i1TVbLt--I-dx0H<{_0F#RhTXf0D@el$f_P)9 zH7jpuhm8xAF-PpA+4CM2$-1mus+Go9sI>GLn) z5=)&IDOX7Vyzqz9UpS)#H}M)Vej!~Nt!(Rzw=0Cf)#X+!))}9l6-iypo<8lq`1IYy z9mr!nB;ZD?N(}MhcAhs*%3^;FDy-ip)c*_#3SwYTM|ff;z#AC<8FA$gsR{t${M>Tg z^IDDv;~QxpzAg!!v`2+JzFby-+_2Rq*= zDU$Hkj#b{zxR)a9c#9oyjDElS{}FHHcbWCS!` z@SQk_mkV=DFzg%5B7M}C_uwU0UxKd(WboEIJYuEXQo9->iA~O8RFxHY!T0;`^eO8B z)XhT|jIq&3aPwWMDI-?KGvL(&Zn=r-$zML}?|E-;(8|^_gPA8yEBZoA?cXZj2`W=D z2{oai$p^9ULno(oEYUDc)X*&eH2uuXneUr|d_i08n%N_c==*2IIzcY)=3*d&Zk0jT4xWI!4k7 zmlYvx7Un~5qR~6H%?XaHdF;owld$wPX#{u3rSM~VdK%}7`x)J@ixMhG(NhKr zwm()U=F7o&N29){lEBX=T>XV_%>C~>`D^s~d=!J5<%VX>5U5aEbY{Dq>a9@co2}Ge zAA=Y*_*aI)6d%U`Vk-lGN`M>Wu4^B?|5T|a9F-^}kHIcs1-He`74X(2wzGB980^Zr z&tWaCt9j$rv4K#@^B)0kzXDzStVnknQp?>2as1#k#46x|CnX_djtu@#)zHoI-han* zy(*1){KR2D7Y{|_aj~{Zy2qohXDX}L{Fa`U1Q?nhyU)N67);6F#xX*z>V4W+`_EY` z_)kq3gAx8R7>#*K+xs}-hBPV?;QG$vZwy1M^SUm-I~QntQ#A}+Fz~sVcR%lbCfj$N zXx~x=zIG8DyyNbPAa_3KWUpGVC<1OlcUGIB>9Pw_!NU>1gp7 zhe;!uDTpg3m+kYTf9b5gb*ziuP`qJAN^mmK3`#+>oF)X)wGH9FVT=D?(uy|~#T`VE z#HF*>6}g=&;V4JvLu#>cJ-F*KTx6936Qes9S!H3IiL5TgbWA+_kg5Kq%FK>oMKXaR zYYm}$MTHKY?2<(@fC|{QhxKWMO5;W{-F~jm?DirSj+^)8Z_Ye#FJ405a=2JBj~}nN z9fS%gts6WDsg;4Ns>VC-Hrx*ho<Q|@dnC(Qk`vA?&??I-JdVZgv@(*&ZDm$%qVw~Sw z-!>=)3nGLn>-horADQ2Zsq1F4X?V~7GJA{vOF_60Vr30KtYm0=j1pFE_Xg;uwI5A;+M$cvmzX*3C?zbv6YPn@JusFSR5kL9BLKQG>>%@|X1W2L^t`1NB0Nphr zi5trZKR@;Vg0ez2GjN**p;BXk@7Mp<12-W2U%Rh&4x|8XasBknws%|op1J89#aJQ&Hwi79gt0RSt9!&Lu!ITVe& zeb603 zQvHn_15W*Gn*%h3eh>Y=vLh|OHwFc>LtouwSx#kc_AY`4QHTG5^FwlpYchpYagy;kRK zp@2tDFYzN6o%*ZQA&2x=a}? zQuh!KONG!{KZF4qh6-dLI!W%wdnK@4AOvcw;`hOVD}joMe-Q#{gcb}SgypFM>Q^8| zySnHQ$?=p_!hE$Kg|wNCMCt>%~P1o_%e{GC}QBVZ1T z1@Z5L|Etl)*Sa8JyXZz`tZ2yL$D)vyehV{37fjpUY6r)qK*Z1)Ps$)EpFsIi*@F zCOzD>YzAY%dL@h9IsPc>;?0h`J_fT9u-(lJ(Mq?ZeeR^apcN$s=*wt_g?AZnm(nB( z3&gxHM0J*<49(KNAFSJz3t)?lsB@~Vnq)t5szRFk{9%@w=d;e~O+d*$AV#(D} z@aFBm%}fhOZ!~&Tmmn>8NEw$=3r7|HW(L;?_^*Fye+;l$cZr!T#{z1Ms%hL0*W{`% zIL{0OBKA3m&e@$YoIp1r|JCsCX;^S`OetAHg?wdN=O$(LlTF+T)%%2%#O7L-c(+7H zZss~Hw0MC3_D$P)Db6@?4_Lc4dCd81AH4oa0@>AZ+k2d7zOEIZF#jaH7@;TD@gFIy z9!b*C0&`(?W;zFpA8?o5l^*_&z;dj!toq3EIIJPgGd2q$bt`bdrHyn=;Oa6QYMij2 zURphDnTu@>Gtws&a_4l}$Wg|AnK0HSvo9eYMPpigHOKj+-MdObVeIn?6808e&N08Dd^Hyf9o)(Q`XxFI*Cb?pKB zXjJ#}bxW)wseR$SPXy>f7}mxs%RrAMIGYIcSX0(b1$S_197VvN7}$L$a~P4|ar0>a zKAePf4Ri71H@2aTyD-??ZqVlxgx1UVz?x;~EfP!DcHkiwY5GlO2Xk$Erit;6h-pw1 z$xX3{jlKDgd@VYKFOiA8BQc2*ga>60~Vy9Hca7^hNN;zLwW?KA<15lIin%<_x>fop$e=)4S-d^SxA`wu#o!CSxDE+S($-9c?fq> zA_u#e3_2EN536aiR~NUmT2n6vIoGz-4uHoxVT*|R8*MZ@Qphl_dJG3aSwF*(o8+jr z0uL+lZQWU$jS*P~0pVTI@KyJO_tyvRYl&GBJ-45*=|vA&R61oL;op`guay&Gkd*u` zXo@Jquwg@~2!vUJ`4xUrntzdy2!0_UX&_fiiI(o@zr+8y5~M+sXB4?B!s-=FmFP5t zB5`Aa|7vbQjy&9gK-zExA;IrJR|(HGQ$4%B^n5!a31#)$>HAq8ak&aA57&$F?@xL5 zy2=BipinQrVQIAxCtS5kSc*~P7FO^!8TX3c8-qrmAN$i6yHNfV@hH2BsffI4*H8NS zOT(kfWZ$b)3H#j=sJT&IY;fZjSAV0(59X>N#bn&_CdobXRSV4`98QisH=LSk_Rie?<(t^W4(%Yc!5D@jSZm3_@wkx_Z{QuCb{s|Ch(UKRuD? zOO$KP?XC?+hb({PqNxCH+CO~gFzz1XC+e@ulXagl0bQn$OYNxc#1tCj6{(B2IG8Sp ze7x|9UrQ;|+72D9F2}MlkwMwts&U?!2`kz9Pp4|Y2v}ywcF#+k0Z&B&XTa09GvFyC znMASa=j_9UC~Ofu@yNB_-OHmRX;r${9H?r$Gh3Q~7UOrvYCucUg4-~z$bQR≀rj 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 z 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

nJL=GBEdzz>RSm&N?LzgO2UdcPPitw-S~Jq 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%0DnMx+ah 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%0A1Fb2cU zv@6~5G2GXmDUj&+ycc<0kAEv-HsIpR>I~mqzZ#GJx@qxDvfCJcq;#M?zT!ZlS%dd8 zL4?A42yPWAF?@&F-DN>6OC3XC{fU+60|5%B0hhU~C80&Q?ENps>LN{}i`oC?*|BER zaWTir5J_?WuJA9}rYfAvG&~hr7q$5Mmby#;tR*)THV@_rBe{-;4TQ5aodN_Fh?zNW2RmGkdBut<`KCkD8QWIO#* z2nbwM102ZWapbbNUSrtoNCkRh$s9_QX~$4PP+f?iRMWSHA-V8TAs8s?)4$QIr!(Ty zAMp2gIK1BvUx^Jh2>jOi0FKN`-rmdWjGvjyx+MOW{;k1qUV=OqNDBsf*l|97Y%Y0% z3Wlv66M_3O*G1e-CVO^7Otypm4Ze-yxB-a!zGqcgPN+ccZ$54D^oAN`nH;p7S+HA7 zKO7UY-!yUSqNe_6SZEXRi)n5yVj2zD=MmXr)nwhqLMu=JHjjk$V_6yd@lf}Dme<5t z#ZGYoA2i7*ih;1egB&FS0M6FYVAOi}qtjw*qP3vFeJ-WMTwX*|UF7>;IvrT?SdV8; z_&C6mdLPp9z`gK1p)#-+0Qk36kw9&jgdU5rgCsyNg~8H%ZiQMV&E(;s;3w$U$7{&0A(O*i% znS?&bj7nI#>|gUVf!r=P2IL2_%G?w~5_0P(eu!1Xv2|B7vY06zJ*!b71t#jMl8@{T=c3+hW>?yp|2%Vi@k8A&JIeh%d-b= zzORul=?Fjl>^6<-c~8^sN_a+dwS(KCNO%U&18uJVYOR!3wY*$W_cbnl;g^DW?eWTe zXVgOMbQou`yPFzdXwhhG^;7Acd)&F-vtllack0;tzkkUy+yTo;_=2lrct8bF@FBo_ zMF7>?yv0?}mhoYnrdf2}B93gsB?gDSPucd$ai}*jE(${d6E`+{NHCxPRrH8Nr(^xC<%UMXP6E~( zP#eKhQ=?NNs12Z@SxH~ZHTEsKzU)mTc`G~!$_oB}p&ZfKZKYIUpzoS*T0tOIYNdoo zLHhyZi8=CmFUB&IVwCtWM1V0Q-06Z5U_9F134IDMhR$vptxf>70rbf!>0~gu0mSgk zB|brV-b2s?Au_g#*%iMjTV}Hc1jTw<99P@Hft zxR52r8rEP4{)%V+yJ50u zbN9l6#*+=~Ks)XPx9K_0C(AZ(!ZXXu&AAR~!ZUydwRuY+z}TEJOVEVNR%KGRh}bVX zKEaP5KTv?*<-N7t6Mr6a!l1XpsSAVc&fB_LiFN=(!KO81%#3GmfJo+2C%Zwqw>+H^ zW6Dd*4@74tz?#xT^wJ{|u*S6faQJ+JNune$_0~~QcKyFF!@y8O*U;VFEgedWbayu*EhQ}>DBY=aHw@hf zD2<48hmwMLuDS2$_q^wv_g(KFvzT?Q#on{`_uBP|?^YJo3XefY3CNPO<%skMt;$+0 zJ(r$)I<{}|Z7OhL2jKK3ur0osOJn+et$Y@)4=r!j3mTEM;46zH^ImI+>pA^ z@7wq3iX)m^PKciDl{JMmFUXLe8@)2e%!lL%*Y%JC9HrG6272ZtIT29-x2EE^=$O^8 zqf?wE?tC$ouM1e`d)gMYl4Yq@qDXy;MXzFR<@yG*%;3_0QKcNE>5C(-nvc@D9B6@} zBmVEA9f~7j(aDHR`}{$x@qH(rKl96oW6RoA^a)O@D_&lhH<`C!j4~C}q2DYqgfckA zr-yIkTfTYa@4|Y6v#?mF<0Y8vt&`PfzfyE{zO4-bbmr@FCwuO{6gFEBxyK6pw^PAe9A^4$%#v3hzW7%qchY*$ zHl?%u>Oc8vh!i6AYoI#{NfC+Lfq`gPYa`irx5WVl6aW zCz)n45~};N#-;kxF>^9Hi~a<>1)WV$)=dfR$a%?n>@Q%g0Z?Lh;O3yelG7_+(}q5) zCuE^f`)%xB`U7}P&~;;euE8~M_J5d73K8UUW{b@Ske-m+0UGYogK8(A3y7p1PvZap zMyGrJjw_k`Mihnu0JNGnSH8ykMmH7tr4;9XZoc={vAIWqzZZAxPJFQQmkCz-C$|41 zC2)){Q~XCupd1=`ql6Ym)vkonNBdQzbzKz)r8J1tY&;h=K3VbEIS;2el2$hWSOtyB zQ~!L}ll~h@)xk7$(c!b%V@47p_%I^<=xJWMkmV1oJ6x@6Kl_1``I2>#;s63R8-9jB zUYa=uJGS4cuHO!eBu>2ZT5&8#Z18e2n$reJfpdDgdC1-Kto2Vyq;_y?+{v!NGu7Lp)YnSi@b% zPK}$4swr-TI)D!%ISUr>&+*%gMKDaBLOieUCOoG{D7_~!Yq%z*#Ni#M?R$B_%S$93 z3sQ&nv5=sn>Q<|!v*5G9i|)_<)80h40I1KjvC}q0z4M)P6^hnV8?ZZ+1B6=rpHSa~ z`tMPS3i6-oK5-@W0zl_IzhXi{O)3_jHP{`c|bmpIAY&-C7)gVOYdqdy4t zihh(w`X!JJjvpR~z^37;fca0kiT~p5DBv0E#gd+&)$||NsR6ht1PzAxIHqNZc_R-D zF4Fx$91$8>*o#Ep7yls6`M!0vrvV^MMI+7hzG%$jNl;drDQApH!@A%d4s*-?fJtlW z2%+H)lGF)9`&`9n>emk!K9^|Hw|z@)1yM^984iq1iCj_#Pc{1)r=Q%rT&EdZGLv5q z1}w$cAJZNZ=AB2jcAvN+D3|K!(ibFaykZT!E`xSw8;iY)>OR7cuT5`n^A}-QoIMt-SzVjk*V26sI<1O@32*_WJKV$=^QQkn?cT zE~GGj8weeW#A(}>gW&a+9qwMT#w|U7Y}r2UiB-yb7k zk(kyBTdWys{)4SZ=*yIMGto~J@U!4L7vfz+f?mj|u2w4)+TaUxg9~7SL)Eo(zs>og zDV@u_&s?4nTRY&dDzgjF%So;P7W$pGNOmCNPHNqaAr?4UXW$vxK5yI2a)y6~VOW3C zW!8&~?H^cEcrDg$F?=pC1E+|rXPzr`3AYx=;BM#i$A=r~0uW9D3aAcr7+pBTOF~0& z-4u{~otpo^h*rug(DS_SNp%?6hxXV2K&j^or501*O@3<~*(qxC$Tw@$AMT`AG|tul~V zDSiG<;MAiKL3hIXk%Ub|u5mvDZ=I{nkFd-q9=#@bko%_oukfElZ#M~HPbS;HN(YLz z&ee!^D}aZ2W|P|ZKd960|3~w+M-o3G39Sz8Em7o) zdNa}ySCO*cNq68fwPo)<`+UA_TWSK?YfROsZ@=p<(ZGX{IRN{*ed z05C6e97s7KNfrBc7&J`=VQV9H-|F@&)iWJyqnNwTQuStTyF4ToRwM3k0CjnkBxC>B z8<(Gp9x@lczTy_Y!m;J(=qjR#xH+oa^|Kf%nLnhu%A^a<4{hJbYsOd!(&b?ExYA*xDE6NXs!<5B;xR5;Fw_)LcoywJC~F>4+`oH zyGCn^j|pu?@9MtV@HVg{q}*i9K$f$kHVg=#V$QMJOwowUyH=Vsx6kp6QXkBnPY^W} zJb9^gz(9S09>I)B{`yUm_B@2pfM>C=hn6|)8^4anjnxl_8Tu$?5(ekwQ--kWRZAGg zDxRglU?Hc$7$I=7VUP{wsA;pZ`ooxr9cU!wioFqp3Xg;-)cf~sa&>Aep}{OUyZI@H z&(`%aE<=Rskia+qFkm64UoB3;6+r`}+VVGh^p0X{34e3&ZnO@0Uf^O3&Kaw}Jzvz3cZPi6hF0=)a5JFMdk9FYU5NWzRS(9;|^iX-;Z+VPfuk#-n%KrXf_oNd&j}fOP zj47Psjr|3o8rCkzVv7ZQm(ls^vn0=7u>m4{N0$yp{whekMpukC%2r}&;CH6exWjCI zwVvPewMry9kmd`~f#zwLp;{Y4PGQ>9qCqLa_KnhaHxtU?TQim=l_Q@w&+@?;E^6>W zNbB~k$ol9*;5b`(TOoYb#0sTJN{cpFB+n^xVR-@6?R}g|e(sgl4}}v)Y%*%(T$ZcP zxLyEgx#aO0z8t{|2!H1PGlXf2z?9#B)BpA^j(k!FmV&h8n#N8WzWxES(f6qJL2YUaI9YF^He?({=)xc=+K&UHmAlQIFg zb&3wfEkKy=W!QqlOTh%oPmoUV_!SJ%ExaXo41`aSq<57IjTpnBf8zRxB2fz4f5jBX zpwfGx&4%eDl_p2}7M6G8v%t2_qZHd(XZxBKEkzo?$&Xk$0+F5hVS+BF(S#Y^ApF_F z1HTS2gIa;Rh=Q&0oXGUVJ^0O==dg%E$oQ;f>f_sU$5?4xIDnQiou6ytGpcTg#}EwMxRHD7vNrfx-oBIe!|CV>NP6S zOU3ro*?6`|{jU>`Fm!SpI-2-BhDvzXM4eH>4&GtSnw?n0da@vRWRs(&6h-U=TPsk{ zPmAX*auD*+#@r|q6Z%)f9xca4Yw2!qjphKyAo4vIK5I$djW7(;Gx97-&E__te$4AX zviOwG`yDB$W;{>UoUp;F@lRg^tN)1{vRxpCDtIY=ozEh)TN~*WPh$eP$^||K2KFbvouHH} zk3IU_fHu~CdNDTb$U&ol6hEB?nRn+^8a@{8bA}1{;SSVcGF%Udr_{IJbN;eDd$#_B zD#H@*`XMNJVXkegOtaHi5u7qYikrOe+H)35HE`di_TvcUjnLX=6~jbi@%iSPM662V zza552!bg{2x!2-;1iL=p7>2~8)r`rgpo0EzW&PXCOCfL%n(Ua1SMz+4H$k)1oR~Q| z5;YWlsHcFYrm3AwhTVC^R~3+zqQDl#Wv@_=f*$ex;9KYq}~1$F6O`ks+SkK;Ggil*5jDL=^Aq?~$9>0sqOC1~yf} zjTwwz4DoT{t{QSy!)?kv72z;S2u!nCRD?6X-oiDg-NFYxXC-l!Em7A507vRGbaW`@ zJA(v-NufEy;>m=A{rGJAj&=eAoYiz^_j5>YQ;2gg4iR>r)|)9sKkBgD=&04sS_+56 z_?CZd^G_$A6F}R-{}POzYx?nggFh17XDpq+%4av=I%q*%jZ;8F;^nLM#?zKG<>a@& zdS4j*imB$NZ5p2M3{CjG*nRr)q=sfXOp!&JSx%ZLx-pk@SWm&CpB%Y=bc|@=#n4j% zobPf424tL~Q`!mHaOD)0kB;tx_V|;w1w3Z?>-aWakr8ZBMA_N5;!9xa1YPuNrRBB3 z##ucjG$$9cR~?~>j6@Um%sKFAnLX>#zBnrv$9kRwI&HjoTdw#Dfb)y9USASmVXffm z(ZNCt$_pke61fU~JPVhXUk(fDdhH9*9lq})nev5)N^$bj3Y7CF1OH_fIhL;8B&#OK zgYE7urHZ1@dHf5Txtz@)Yr_U#YWn%W#>1~3$zLW9dr+MmyAH5^l~`C$ok1@u1klwWowPrI6%yE4y6%g%8rRSA^6O&GcBNJejd_eq49WgxjL#tv5o8AVD zP@}tFtO^dY5IorA%mT+cIam=mBn!x(Iy@ADUU4Ncm5%Z3Ny zF(NPSWTLs9J#HIT_c|v!@o5{E&>7b&4lijo83xS8(8nbbhiIhZo zx!`d7LSppo%^(S$gcCGkP_hG7D-w}H{dt`ZQVcz6Z=Z)!B}vXM>##a4EcQdzt&)wW z7kKh1hl!j247Yn+yf=&O=8;x1uHuD27Xzw)FuSE&L$zxgkDZ&`9q0YIKZ9wkrC*av zfmt2s=!DW2RnnpYPQWXfE9c{Jy=<@S1Lt$^H<+te3pX4tyK2&tnpHvn1EWg7_oW$D zwja?`ZYDgsn6T2Tz{AzftRo7w#XF{CP!@jj6iHCY2MG+~N0y-92Ce`Utb>8|UQl8| zD3vdlS#~O!Bq6b(92R31@^R1ae@=Q|zcL_fnkl< zGhK|z*+CMWwbFKOIQ)DXHYk{;Yj~@9Q#|X}Q3sBHKnFTZR0S<`Bj*csP4pZRGzLrV z-lZf-(DTJyyqJJuO>S(VesDI(5fKl~*YPdDfuQG^Kk(Ky35#b4%PMycvQhf>A9>MH zFih-+QgLha;g<_Ep6f(g$`MXQtpLZgruV=x?H}zTG=v+yQ`+!_c9UPH{I|)CUqdHN zOjfl>>nepvAq17YOp4(Ov5)l}4xWnGcFu%%t;pGC&ak{sMgU*n{Q9E7XCdQlB7<{I zPdZT)V=c{(VY9e8T|T$O?ucMr{?5W!_rcCD%3$o|xtb8Qz+BJ1Wn>q%Q~EvTG-=@k zz0^x8DGIhpQrGW_;wY-}Ca&Wd)D#$30_P(+jXJ|u@T4yp2AG-ke?3XQ8{&OU_#&_q zN^VdB(j+1-wo-S@Dm1bI4l=-&HH%F{;9K8neMf)2)WbDxaBmW@{tc!GRfh~qJUq0i z^HP5ENZjO*TYM+m+8`0ytzLz>mA_BG!mpWK5Rq9nYaj^$b!3P#Buov{ zgYSy-7_Un~onRQ$MXB^s$fKUX_96!~5jla{*9=>$VH9-oUgHQ=ZlW)=pe7d?wWU9Z z(?4Uf*$8jcdyc8}@dLBI#wj9S6vZoJ^N;%$=HId=KY|47vb?`Uy~OSb|AOyHVl}Yt z)?S+m2~zoOk184x|CpRL>NG1u?vd5^+ldw-t2TslUVk7F3zUYgX-w6e$j@-6H_Qi; zGSFfahVjeXNHV4WRr~1Uub}dO$?~mI05asin5VoDn8ZRXZ{(t-?|Z8FSEbfZKLt11 zUx}b8iWc^f^;U~pi@g#$t?w7ykYZLF+-krY7%|wT0sW`J*HJe%|0`Z6ai4--2H5G^Hgb z7{9ICz5X6sS0<47SXTX}sDl(QxkmxzPw%O`BXu>xn86@e2RZ%IBhNO83#Tw?E2 zCmxmcj`9t}%S{}!)HY=v=*#oNOT}kiM1TeB3E~m)ETD@B8w1qv;U}kzug?ejB_@fp z;>WOz)eoo@Pnx5EU1H~kukp4YZY1_aJer>BpAs2)k9r;p@tbkYZ>5D6E$pJQ_kCog zqf8v9KpG7;pr2#jm%)_Ffd(gPxEnet3IencJynVoWiH^$Ni*bwxUkh z+kp7_(?ob>0YCxj?!QU?5Mv0TKv#7q^Zym^OqEb^b^8Q20j2;PZ+OCbA68zS~? zIE_(EP5=WEJN~&0w+5&v;)vJT-~)tSyrN(Q{6I{5gKn6{jdSA`cfR@@+3NtaKWUVW zmL=G{?Hl=uUXf|2R5R#!?4>z;9Q9#sYLi;A>TM_S@15{M5F4J}Xs&7)HeLll5ZPwh zwn&fyK@lVsvSXT<1Nx~!F#lv4;V<;ow$^JP0$N0?K@F_7GP7m?okItH8}K2Ph-X%! zX)ibOA_^j~C|<DJIXT?vql-^<3NNc9nPU zo5&6D!FiU{)lFP)pZ*U&vBpeIJ*A-JeP8_-0OIGtxRNp-$>h%n0YU;mR^|N?CI4!?)ei*vS3d8pa!~CT{dJICeTX) zE(`Yov=m{y-{&5Iu0=6A*&Batm(AhsM^cYGd#{Ob%i<1IG4;*m#jtJhPfG@@xpmqV zN=B99gD?7fGxmWx&VttgAa5q18vvjSzv&8R6equxW}BE0!#=6M)h1fDo-!V4$!K@v zfk1KY0OEk(_%7YVYYb3P4#!HC=lZUQ^xjRy8hSr2D=hH zwK79=huf5OQf(B5)HWTi;nH`8UCp1fl#O@PL#ZcX00Iv)jQq6}w)trU69m-M~@$as8%8MDJ(KIz@ub zRFeOswGmCovTb^1$h6p=mTO&#AK*tgC*6M9yO$R@jL0<4n|Y#G@1dn&> zZf4HfhYvjLkSZ8Qs+D6^-wz_UAp}MA>MApobVyA}%?GC$$xZOQ5QY9Fs?ZP87QHA3 zCNtZR|ETc^sU+{0KikQ4Z=mvcBoNY8Wu;J>ul$Pydz8NlMO4g< z-41{_oY=1-He#Rl+_!Ipm@eI7WAsdHEF#527MMm6x_=nnvB`|M`UnXmiJ6`NsxsD{ zF6N6JcYZ5F=6C*I)jzjOTG3Bb1+<)W3p~D#1N0gM7b3a-a?#YaJQc@E3}8VJ=krEn z4?wP;c@MB+(S?8wKsqaQ6Uc=pobnR94`klG`9En8?bWMA^S=O%k)wRrwGobme*O`` zr#2E{jEpv4af7g+9u4$iEf;@z+sB379B_Bb9 z%wf9r?PAGkR-Gd(IVaQr{V}MVMoxsFNz~{m)?TPeRUoHh;Vud-n*92t-+dUX8B}B# zV;QhMkIR%epSEcC-DN8VM0H7ZO?C~Qq-cHmkWkD+hUKmTlqiJ z%7e}$Xc9_4krZhP-pBgdHp95;F{md;etnjvDSp5EIG5g&W=YNb8?Zgx0w2)`WL0?r zm;*W1U`zgaBum#OaqaEz#a?RLh|nK^R+%S>F#1qo8P?dk=B4@-UY|SzF5;gRpiJ(w zU3C;vzEEe<>kFNA%|H{x`H(8??l(X|ebY8#sbYS=vM6^4&`qD=bD}mb5RRc;25}h0 zN$}0L=uYdGi<8P79p z4`G3D<}kc@)qXKdLASCWs=kgO51}9kXJR`3C;U@wjDuA9c|0s$3!}mjK4BcZW_7S* z40=YV=Q9&L$#5qlV2FrJhSIZ-nCeiPSb8ReDO26kiqAw{{7UOjPsCkRr(ph}=x7DS zSlLHfEjs`%cWw_R)gqKr!i3@c{m4r=f+J2QPaCI6$m6t5jZAC_pG=Y(KK-zRC3E_B z!9a0(hYaA;L3#51CtSND==c$@GgwKhz4hNcOJhYcCzr%K_wcCr{Fb-y#T+S*pwIwA zHjgb+Puc-i3{FkkCMHDN1vMPgkCGNoX&ga=D4|(S>*|}9uG(`V)xfkQLpH!Pv@aIL zc%4McFRuX>ghl!eLkg=ucD&w6CQ$%29s|mR{1#w_A{0Xrj-c&1l$Sq8H^F?!EuOoX z_WiNK4mG)GRJ1q-Wh%RE5@%h%0J8{aG0gjRJajqP@aO9H$Cmk@&%Z*XYVgjZw&Vy( zY~!}ci7a=m+=)mP2yZDj69N8K{v4jvgbs;%xE+!1IpRlEY&nrrG>QJb&`HkwCo$Fv z2{C{2F@mJ+pm7#!mM_#?ndfG!+-7G1#zQ8ctF_;HK94iY?%KN3={xyEiK0%71pF=o zz+o%?akSBXsEUW;C3JB=`ep|n34 zuEPW~Q=zCxy%-JD#+9Gjx8QkJ&^yNx{fUmm0uGRR=AO?6qtwFH7NP>j;q~+h=Pzpm zseU~{aptLZnduC0_dAbFV>(9FxA;L$jFrR~&fSI!oT{Zf46B&ly)mX}61C2V#Mg*G z>0)jM-Q`_X*$3|mg_b@Z)pRB*Q$BIl(tZF)FvVk*a9;}s z!QuRkfo0`nY(^#VtE0c)(gm?b--2UTAdwHDzF!PWtR9M-Xi~_=3RfL%P3W}nf?%qh zA6(-%1T)09uKd65Apv{7LUdkSAgUvJv%3QRs{0*^y_ee2NH3GPlPWP?lwy{K8lw-~|_pP*Eo+-!KRYb@q7 z>HN|AuVX}m8ZgDY^vQS0~Ldgc3L>rXzQ4)hd(x9xjk+=G^sEmG{Qe0UL)OtCT} z5OpMC&gyP@Sc!0o(R zND~tu5NFa{2nMg?dd&OhzJ6%)KShBFF)7y(5!fvfkte7Tg=n4(n|pw%{Y@o&AG74m z(bY%ew`eNfQxvWDtDn9tf=+Od1%L9=J2b`Z0;kfX&_Q-5Hbw4G!hYI*PU?0^2L(() zm$hIv=Srd5_$p;BtZ}lWk77osbi7-v9#3Yak|Nq*bcTB){Rp4M@bLhnBB!R-F)IA} z#!SWihg4DjZiBRSCZ7i8h_d6GyU_-K!Ga`JOt6*xxgsuOciI&t`~>T5eh3@;NV8Au zvcYF3MZMbo(&|mlI1+vzrFyHP2RTwp#fQv^R*M7T%l!s{`Gy^Q$)^=z07V+ew}IeC zB0ksSapHl&&**rms4BB08^CW2J8lsaS7W{daO*kBv=Q@>B8(!+$>gr)Rrf@7)57}j zY#(AHTM?%nk#oU{|7&HiP+YqOU>tr4vFvnc2k&Nb$~rF*I#b8g`zLV#vTuKjFv62C zcXqT1euG+|=;G4e47YtZVa?2>8J$Z+yeasa^56-#1}QicgRnp>WHL*75U_8FAPEFstRpdwTR{-)8J$Ol z3~H#j@6N&itvKzqu3q_I~KvF%RUvOblhb_cY%ENg|(TcX%G@u{G}dr=#*S(GMxLlVMP4Vi-0w) z;U5!9gyrH0!HRvhT!%NwbmMZoDb1-CME1j$6Yshqamq!5p)@n|(@BKIU`&lF zJa-7a)y34)^6K`NKZCvIW1fUi!inBQcD><Rip)}ZvQ*8^e zvwefIDgOztoAIC`41Gi9Rvdz5qqN%uMMq-*l4z%MHj|#cwSA7Krh(61PJKN7iCGD) zhUDkwt-(?Zn-PXRG?iEGjztdn`uW{D%ad6rXTV!V&4R8qgEMc(*kAc^y<+{_f4 zAuZXNinuEuYC^Pu1cs6)2GJWA@OS==@76xN#c~RpIT%paDR6n1y!RQBaGDHvtzE7^ z&41=$*i5*tbD+v-oSs6KsH+CQf)6}w&JT4G<6l~2S@~mZ)H7~cKntUnyyjvRn6;mA zHv#nJdW_bJbSIwrszO1Z1HP3-QAv}$kf`x;OzesxQkiKn_>& zH=Et{BADb-Jk9IN>P@62%Oll;~5 z(;s3~q4-ow0so2NLY?lbrnfIa5#@B-al;eOB>s{_tRBd&^iN}e3jR-@4KJ(MD=*ua zQOneG+c#Tfm@nrv7pq_7o+0a$HjDtv6N( z-ly+*c1?rjNL;`M>pcH*LlB(dpg6nrY?O!Xhw4Xc=T}1*kWV{n%rz9=R$G(#>kSrN zsz=tDoV*&$=8X83r&8i7`IJ)h!0fwQE^W|etqxw?KBQNU-ABK{se6iyA_qnf2@C5s zqQqeV@nZZYrF(U?4yWr%odsPm3z8B)_qFmtstH}533Vr|8`fhHhW} z>Q9M$@Z&7QpJygYN?uFa%7?|LjmLf^f&RzkW1aj}D+0M8u`Qx5V;_kRR+wOtK$A^F z>v5d?UTqggL-ssg=Jsz)VlQBx_B_u^ndZlbcJWO9I5!4tYO~8DK1$f%?fA3KSp=tE zd6%@N7Pw4$3O@V7d5CZ1mc~ zd7f}8#6=&t){d0Va4;lOVj@VH$JqIN~-P?#`SRVT)C+Hxq(b^{Ve|wysWc$3+^R( z_`pK`&jw3bu8Wmp00xEQ9=-h@h{6gSpFOrV+wh|Vt*U2a9zn4NJh?AgvcI74UNyYyR0KSt6952o)fVR(=uUIS4}Ct-05 zws)WWF59*S_d`vBNa;PJq!<1eHLFoD^UZ2Tpa2s=7!qR+vQy=o-QW~L345qGlE2{` zOCnXnFdq7@<0kgXO4P_dKgUJrtk{KiJTxiAS zOEye3D-+byMI9xgTA_5mFcUE5gx6j}%mXhEv-r#;`u5wMazm=;vxZwHf-(!D!8~kg zl&p;XZ(|i5h^Evg#XAOLiRlN97in6D+*Fa+y_N|X4PcF~-s8ZLU(3Dudjm}9r09G7 z{OFLFb;!jML8l(-ucc#_6?!3*DNd&w8&W5e0QA46rEZ7vccuIfFfBA!!R zw>^h+DSxvP^SM#jt)JDf5%6?D`chRmF z2Ixz#0qG5JAL(3DL=C0HlIM6^-d))wj9J)+C>b73_yaF16WzK@w!m~KyH;4QQ8*XE z3xk`SU!c>ao~CzI#IK=l_%5C}k~)(DQh&U;`6=H{j1qXlQ@@LtK!q0sw!%Z0>X$ea z3MF4R|8e+`0`Pj7e^u3sB`#GI&g{s@hjFsk%k0#tGGMIi?B}Z=!vrw*}#p^==Uw*%8k1Iw(^i*H4Qpl>Cx&XEv7_^OAh;w+onI{3*Z-G=)D?1 znmwh}5@7q8oITsep3Rqil~ZnYmi^`6I78ms$of61S(l5L2$$L3@+KvKw@WJ9auxcI*Y93s+r(@au*0GdL}?~LNnLR*qoX~lXhdx4>|Va6&$Mc0?^P~nyGm17Vs&Htw38B0^8#v{{&ZO1vn?}tEJ72WTDaHZ$Nq? zwgCo9IVCh_t0A^s8w3Pz$dlQ@jNmL%6QA+1Ap8#vX8bRyfE+FVn>S|=y)33%agjs} z;M0md4Pty9bFl_-T#I!-HDuGakUpfwThw{>DWyE=UX`WoCRr2nEIAiq^_y8o$szi@ zZ$YIdYMb*3=&`a-%mNFt0L*_hqsq1gB((==>Z;pSbpZ?mkg+Iijn>I4(4iZB%`EH> zPE>7j59cFA_Bpz&1ClI#I^fZnRCFi?qsvGAq?X8MAzg`33eIJE^SA1)L=y12cl{{~ zZ3Ju_UpP-}*2fVI+393O%_#+F48xVNuK5LEy0+Q^PJpEwXKwS|_uxVLLzT#VzH1YY zPEXmeqy7-|e!~42@__B$FF9Ub@t?>XQ^GaLGuD0&q1`W*-za-r-Ek=5L9nG5hOwA?_NzT}HnD{CJdrH1@hfm`PL;D@4FjO1=5}L;6XpBl0tRB0Wn} zZxn?W&doZo2R0593Tx#|iKWhqtVm&5;PeO9pklqIpWNf)WPZKs*Vd(>k=E zk_WD1$M}xzo_->K9JmNRX?2b>u{nDN+3z-z`K0-Vf9+$B*h46Pid#b&8?sBBdV(7+ zE{~-$)$yW*x-bQOvh$ayP^O?>yiug}+RqHjE-^BYbHtM*Jl2;pV!$O7hAYsIQC#xn zmg`H#J14nC5|*=mJ(J&2mabpnmHc@Ii3|8C&-=HX=fPgbh1~pY0%)MMv0OY_#ohy_6@> z%Q~I`LH``|Fq3Qz6l3-iEJQ4RK4nZI1S$=pUwZDy1GK0vk?vLh@oHz!Ugyj8b&S8~ zv~{66)(E-Q%|^oC_1wfK!ftWQ8=hG6OhEQ&xt zQt8tJ0>glwG7Ew}-7G=3LCPm;|JwNzJx$zTBso5RAQK3-?e3-GVne{~gF};YXvxhd z@RyqB#ImR=S6nAYdf~EMH*a#i?E2V=etf*Gh~SWxN$q398*M%y+9*AIuS^RDQZ+%w zHi!^qBX_;%?gz?FcA2OthZ>Shkt=muuX9_oWP0yS*9#A%Ot!`%mG-GzVYq87n94RS zqgC#gk3Kh|4K0;~1q1{ImR0l`q_D)-oNuVzlq&!Y&_T{P)F%Ogz!CpCK$;2Yt8x_H z`C3}!Qk(_8?G#>`t{X2G9nUWOsdzMWwNTMoaF zgmA5*Di-qrclq@ZQ)V9gzC_<%@d^wR;K8kRmLFy0vW%xp(< zU0PQUdVJQFug-IlbV>G3a#v|2p9%8ch1Clr(GIZGdoC1wMEb?~XpV8@$z9O8#w^S3 z;&fy))n8MeDBkvbfd3D7xJ-?DJUm0Gh6woa`j~f@o#?=qf1aQNtteU3vPu|EQjV(X z#R56rFZfGHzGnOt!A_Uy7_ijvir%p9?b+|4OB_4#-!+uSiJSe9kE2!-m}o9>9fZnx zoE`M?{JGpwh&p65qiRqPbs%3|w!;v008e}q;iZQK+MC2t$IOhBE0X~%UBN05HO^K= z7x%GB@Th@QT)t^qHC5$L-&g8UZ;F(!`+x0S=o3E(D=zt<3B0QNb&-LSj)(-)teUX| z5N^M{__(b68ilNb(V-3+LzWvky&)1QiQFAEW#lmzS^f`~vX8e`8>_{s~pJ^(nBocC`hgK=uiysxi9!z{fxdjE^rG&cC4Zua`)NxUkfK|c2La0YxVmysbSn&_9f1fB~nX( zJ!9`UsBT^V3HvOLjuJ+ThY~J>hmI^ui*B-tE)z@#xBr~?o`A+~)bEgv9>X`u#ittz zYkoobnV>89cC2yzk(SWm!~NfD74qxwu#qtwLfTZvcfsBcAZhW@Ok`*6I9Ww|JQr7& z@{bsBP^N%=9vc0+>?py1Yx$?j8cP(~Zu{w+A2?ztfmHIRkzLwuG+hTbtI?fD-4*y( zw*C^qV@tYBFQaM7rN+-OQrE5bYvc4p<}q8E%__T{wRA6Ursm5(Row3aywyT_>$-S3 zw#kxv*9F9R8$1n|xlEHF8gD(lD;%!OF1QvxtQff;t^xTIzkDj{b?L{Vn*wbaURmdJ!1I{Sy(hDW z#h@u?M&`Wiy@ZcueV@P+F5e6hcGDoi2r?Jx=$Er`FVU?s(#d|#V7R5sU$@ZmO2pMr z!VtBx(!s=2kdJAkgGNu?yt8hs!fvWevFh7)274!!*omLZ(Yl6&JHRn^0eyG^Dsp zMcopHr21}=&*s_A`nx^XU%o3h>rWtm8b;Ue17^@|!UZ$DZrPdS^geg|#SR!z;vBML z^OTivF;XDrJ=htz$BAO%NCthdc<;HRViDY6ooqzeNomVT`E3QtCCt?yk#n}=XH;T2 z=)q@27@>orT04jQNqtkw+TvVfxQY60pEZ8=48`H~q5Q|}F?It!mEUj&h7tUCo~T4( z5Gq_T^Dz0p6NWxXHKIfAnn5pXNMJv5?z5$o>!n}l*OYhGyn7s)@AJ4;11K5M zs5Q%f>n{WgY_S_qnSAtqx$B3KI+oe@W!L80bQ8y(=Ccc*y=H%slgx zp$RrUH43^b?3flqOSG>TgwDS-l&;J(WOKTB@g{bQB%8YUU*2D8U#<367r;0 zhK(S})gi}QzIgcui=Rv%Cn*Gd7v_R1&o2i@k@4yw*Q64Q-{s7z^qz+18aM0S>dF@g ze3siX+AaD+=-&G*l+Je36FF8SU6m(|pJNyGvhnl+{Djy=2W8-zqrpl0@M`hp6n~oe z!1L^9dVNlmxF@j5wok=uBedl)IkjFSJM?J+VD#-tyy=bRxtG&WF#%oz0}XGx0&(7J zhRQMe)5536mR6%ElGZZuePb)}{Eu#euN^@ykHhRsXr&86@LRY0ld2Qw=iU8Rjq_JL zhNv8XuLv2qel1Ve%MSMW!-?SPNsglT(Ad0KPNCn6Y3L8=TgChg0hzAu>ACSiw=GQm zUDOJw#Je$TeMi36#2g?$R@-_vTnGOKM;?-czG06i$P}}DV~mDEIYTDA5${9mrrVHF zaEmA-Uizeg_~D!N5mZ%3g@1R}@;Gpm<`h|zs56-JDE zFT2r9%S!twtAiZ>pp{;&#NB zxW7N_9CG47lX4U#h%AGH!Zank`KfCNqbBnL*k>&EQjnJ1e8+etnM(krnkc1^ki-VQ zO-i-nVr=@tcuR#*G24ezm(k)^0efSI1dg;0ea|SJIBiXKV3T)o5%h?bDZu;SWc>fO zku{HO+9O;*KCG-y7ZPC~xM7N9jC)u2F_jyzgEdkc27jw}xy+NFLlUmA?c&5)?WG1p zlKmcYZ7IQxLT(944FqErJLjWqhsw%{eZH8;almi{da!UhPNq*b<)88H#z)y-+pnnE zzgnKt>qD|fMuNk=kmuAf`$FdRhmR>iQiJC+{RT$-g{TSh+3FL6uqc|O*Jf+_4=&7= z#A=}&24Z&nz-=A;1Tcu0`3~ne(^EW3f;{1R?;-qTlUy=_EvDkwGSA4!G3YBdZ;~q% zf)FO0RBHuUI(-_A#x!IitiC!QY)zq;?8CL{yo!HfoXu^Fl#49CGNr>^vkd=~56ce7kt` z7-IO~^g4J1te;*f>V3|-zvK6Qc;_A8bZ_h67v;Kr_jZ02eavC20iQ8Kcd2TDHT6)( z=25CmS3ALCsQ_{W45HsM<843fG!pwj(f^JdI{iJ5sB?}{S?mZ8?LyI=%)-;LSCSN6 z!svHr5508jy?-{|EsCQPzP9>3=AYqzpc|!6FnkD}XHiQ!>Ac>2(lQfp1I(0_o-cSA zqv}P-OkFGRHVCTVmXf~Vy3_i=gg-fR`qk5FG82Sn&}LB=iD-oY<=@E}+#IDVF^}Jt zU+v1ukU_i`jm*Oqs!}Ivj$HwLKlYSoPQq#|2xTOlk2+dBo!=f6Vx|Dgr>zMe#0#pS z$t)(Y&54Q3xy5ANrq4^oxP-DD$AHtvZa;frfzdmj8TQ@HK_q2G%;%5ci~h6L0>4|I zV5zm>=jcm`A=%{CE4+F1c_%7zjuA{MXhNu;-z9x%252|*{a-1PIx4tLyNq%xb1XsdBcUjm6l@5RbR z7HVgqU5BI*NdJqpzYMGL-MYqMdV#b^cZ+m)2?)|icZ+l{8WxR&2ui0Qjndr>f*{@9 z-Ch3+-M_u%e(wDo@A16fIQVd_Gv}P=m}ATtoKX?ZydF;i6OeW5l<548r_%F)z@hYo zte}SsfH!R6xWpR*YNJuO=j0{2D1C>zt~bO%FZX4EOvjy7W$2T zVQwRGl30w%Nk`B{I)rg+Z)8z0qCu)IK7O$F3o@54S#;6nKKm1 z2^V-Cc`Zk9Q!UypQ{tDdXeKhQlDy{k^E3U3tx;+tFqbRLYAfkA!9W)w-f+4k=o3~P z);G)?c4sdraM_nFA-IxuU1m*>j$5HiwrKG)IBbR(ZUl(%doV7jWd6KT{+UyCHYVic zrI)_vp+x)vidZafZwY`QkZ%p|6(5es(64BjJ2C#6Xgn6lu?;ve1((@O>$@+w_=8y=W1+)=kvS6WkD9Owk zL5RKNkJnM?1QFJivny%ePA{r5(Y^=6l3(M&{j~{Dz%xF*ogD?gA4N5m(Re?gDoG)8 zd&nEbX5UzSpR&jHrAUH7YGEGNtIGATzWO3`@FzJfgOX?dXPQ{T){I+ZlG1-KakI0Z zNS?o2(9Z5je=XtRS*1YI^zyDW_L$QbFS;J#4T7f6b5y8c7xz|bP+~~#ERppK&PxbU zdTtyV$z59{?bZSxFHULFqhpwbwubMJ^J}*%+^~1Zc1(M1H=^8SO5c{R9ImgO2!(|{ z>@$-4*Yiv}o_Nu89O!;D#Vr!e6bkLm9wTHW5U=cCv&De>js-mWn?ud;j--+ZmAck! zr|VNplH)g=ZUu^X-<`}6TAO_`sV!UmHy(+yD#BYQ%C6#+lc=jqK0!^Nf%g5AF?k*S z->ay&l|FFv%tP|y3>QBGPB})ItWB=v=oCZKi=S*KQj)c5@mS`t zTqvVeb9H{mKy!%y=WzacPtyVrRJ>VtM=beb-QsSk7mw$@d-^R{E-Gv%1@9J*VGj}e zN3JH6j>^|DyfLE#3o&r?8+GQOVTsliQAX$<%vUH91S;()==mL$KNRx+58z$$jeb zg@XDLZh;oB=NCIEmxr=77c^}Y!!T5~#DQYiP_91_&7*@ejszTTK2g1104&6+B%EVn z&ta~O9c^2e%oK#7YEUPZ+9^3j7?J0a5`g_6KNq_`7vMnC6n51>=8g_JeIt0T)2+YG((wU@`#O^f>aQcY@UL;k z@}4Jc4W0R`Ls1RAv1tXs<6n1Cedzh(bMm;R-E;3vTDTf}p@;e7H(6efsjcC7<$EG2-dr;_*fkT3pvJI24bYj>QDd{OWo$=z%)Pi|_( zzY9OWd{gRFo4*nwDiXO9xITT2tP0;GhsibD0vw>b=SWb0ZFRLCfI34_uh|ldRgOTS zoNeQ(hH>k4e-0seZpX^uO0yoEXW$@}j2q_5r5S698S;Y_Vl5M70~_Sg(a2VrSYE?Y90+~ zmL&CRH@(@J9PdwdyCc0@1l<@GzyFj`U>_NM%!=79=_8vC#^+K6YG+UK9~ZwvmEvqq z`q}@zs&zVSqW6sa9>b%y&0yCkDjzyB$)x+k$;s5QL}gndyzr=IZYu!&JtJ&I?LO=nDX-HB zUu~|-kJBdsA$u5a1k(KVf`4y#Nd!2;5Grmu_s4sGGoeGQDx~Oe3PhGd*C2A-uucez z*w+T60h)@+>MP!i^7sjaTljNl??W3~X5Md}!}MkyLWjP^`E63&={ehiwH=?_vua;a zDF0ZqsP`D|E|}E&;vmP)56q-(I!o(48F~!u$&n9hUiSHdMXb}mm?9h0T;kF^9h@dm z@Ogt+zW4T?HCQw!9(!|cBv=$j7%N5DVzTo>W5R-L$oSP)g9lko6)^rhQdnep)6y$lf9_!BF9zC!@P{=uZ?x;a^97KMWI&A2=4Yn3_W zaOB;LKUKLsN8s4vzz-C}YWdk$6i%4%cAI_`&zAhIH zVloM(#+kSUXen?)?aos(#nL~9& zD{BYxpc++>)KU~Wk@RZLvzZOQuC(~}uiM;nuKwCMfWk=U_32h3htzu<60Z}beu)ql zD>hzFK0ZyC8O#h$XrMR}|0H~Ee75M6?1zW0IFxNu_Cw2D$T?^?I~_pHF)8dL+90ny zVmPK$W_VR0O1rmbIL!%pR1oh;m$SfEYN_iclJ5fEeL#3TqwMB4E2)FJqNm#&=iuOF&Mf z;dq<8TN6LTAH}msm2Gc=_U!NnxkRkfVEDfWl8HA4!*h=*ib9ML;8v7hhG#GMQvq((MgO9^ddJ8Se-(ZJXj+Mc&O?T; zQT^*$wC#DwqH!Q4^yjR6nTv4JUxMc|%5k<%&spJ=iS-Qizas@nnimnWOIG&uzZAyH z*n!DY)89t$*Dbtm&!Mxn@W)Ph2{9CBl4LVMDx1;PUfZcH+Y5B#XJlV{jpXmGSu8mx zbkad%GD=k36|eR~Sa8-RiAt0IU0xD3)4Lp(!52qe!A8xcTaZhb9!7u1wKl#&v}|1;SD-UT|8$n1=;fJ$hP{CUt ziqVaamA6!aKk6g5x_Mu>{4sB?Hrb#vfsKS&;sXfa?iNiL|N5b3E-5W}mAeBSE+lbFPY z!#;McGW<|c{QI*Rg*MpX<&{Fx)=rue2-J%)0r)H(x@u$-yeCmCKN;pOcEt&htC;5lzyJ;v+mK?kuJR35H>{yi2Y0ac$Vc5+-u< zRLFz9V4-vbqAC>%xjr=4I=DuxQ!w*5T=w=JQRt8PWx}eQau7#S`RfUaWKTP6u8K+K zSiKQ`QtD1%ueHa*pX1=))hdJ@T50qczDmr57e3F(L*!f?F~g%}OWsMdab2CVzVrE4M zrLZQTbCcjjd&eCH1~gnLVy^HW$gn}ld|7u(#q$%bgHox} z#VN6%ef99fUC0+pub!vaYA)m0-rUvsE|lzBqlbv*;#*(WKTFPJq9I%`Cd!?lCsJr>v!h0?jIgS}});T0l11a(gu~j@Jr9h|>^YSBr2YIBugyUa=4a9dCeQS-`k`K$3 zg%!w1iV(EK{j-H~ADO7lg_RffeVJ=aO)xZoH_Ew#zE#LN9;~?G82U$>3{N-f?m# zVSk0tOJ??YjNyeU&vOj{i=FSToa=mo$&OZVSKmM!CoKI9-&$BIHx3f9h;>H}yK|ap zMpxT%cKX|b$JFNdKPr`--Sn+zt$eY(XnM_uE~A?^-Gbgv&)=Q=Agm^C7ni? zl>7zRj%kQCP6kzh{^m#lM1Q+hzqa`Vw0?o)Y&_R&7ozqZ`t1kj+^iZbBB)o| z{YfI3rQy8_tp(I#MvoN(tt0MEZMZ|A-$%!xwP@%pDh-^Uqxw|5$Bx82PRTeA<2%5Ftat``M3&4a7tto-dtW8>F6rO`9~c`}N0Sog;S52l~A)e7TW# z911u!%QLtB9tU5F*DSX2py&;lZH%d8N%9r#%nOx4-XgLbJPw`+ZL~Oe2;Sh6H{a|v z*Zuk%CXa|n*te&?YQ7pTx8W?cVZkfj!z$XMW!X@2hB{u+0QfK1@Skg?n%j4=a;op zui{ie9lZEG>}ligN1?H|OYmt#zO+b)?tUmE>Qy1O(~BN%)gr%VICVmu)Ixq9&U?c# zxY(ef1cG};`nEWww2pFAly^IigfFl>sqEbPz|LvgFr@ISmn%r=6~g%Y4ockhA0|wn zNt{JA1aCRL){gCRIFlAsVWW&Bw}aa4F|;RBtbPaJ-*Mo!Mn~Z1rPqYe&$Z(Xap7#b z>_27AI9Yt4OF&*k$sDPfzO!ztHY(b&NAuutGEYT_3E)-`o?`_FKujjYN z_{q~9(PdLQLVgZCyOiDTpRnWlzN1X-z~f4+J|hMMPPgWB(m2pP*pc)Q-sdfz3oms9 zF=6OEJt&=qgwrPO}(?PmW$Z6II1mev)*i$ zR!HBnv3$f=cH-19h(Wco{L}iGr4b$gbu|?Et`B3L-%y{ic$)ZKD$d|GT{}qyg$mM3 zC)?nSeR{!i@BfD2YqxOSM&(i#U5e=_bdL=DC5O7}^~oo`625dydFf<69?D5fPzc}n z882puEZ_t{1gaK`0zF6{-MB4%{lBHi5|0#Muq-Nr)n7u5>4vZh$lCHz!b*(yV4AHM zX6P{z&9z*8l_nnfq?LvC3;wh`+N&m29i$V4qD*Y}yk;{n@6C&4o)A^L-|=emXkhb+ zB_k$cAK5_&rVpOCA!eQ9WKjhb!d7d|hzm4NmSYw@&d-#ywsD=JvSOjdC6t}l6Q6{2 zwC+`iovsFLnCz+jz;6P6&XTVYqktn`9DaYM?zTtJ!gxrU0PEdNr9N%$Z2j(sVRZ8< z%9*w|-4E&6-_EV&BvX=%#lN`@;l}VHP-17wUdX+*`W$gO!F$8=%4#VfLV-qROffCq#C7!obE1TvYXw>UWvIS zmiLwI)8^nEqpM}phzbAbp3kCGRB3VrDnJtX6z!iR@^x#rpw?Fqp|PfOv&Pb|Sk$qU z%eJ)fdOiq~R@PgJt)2{vP=&Fs-HkBNv+Yd+G@RHxKFDoiB<-k$p#>z8l~x(F!Dl@`OPq(6KAEkK4vMZ1B@s?*ye_TgTUaq}nn{OROthJhA|_+C3c!!0TQemEl|1=? z`8(LC#aO7d`;pde&WM;K@^@G-pGX|LnE;7du zxPiZ(twalIhp8K8RyNrX`l%<#V^}6kg;#mAYn$9PS@dBp-fY&kIrytlZ^k+$64MN_^ zSFZFFjn~@FusX~IXcv&r37%tiZ{71F!%MncjlV7$8elXp34)A&^t|t7)v;y$%xA#E zx>IwkpgeNq%RQAhO@`vY#oMIXB>#4?@Doa=9~Poa2Lv6OfmRWOXt?b_lG&mRcKOPe zuK9t^eX)7P(F6;xwTYt8Amfc&%;&6b#FDtF+8iKuOX1j+x&tr>u;E#Rn{}wXud|(>R>G% zTRC8^Xf1T$MnIk~7`0@@2EMU+aTJf?%~ex666kNq(O~CB9Yl|;F2=-^oHbc^ZA;Tr z0SPU3(hlO>6lMbve4(S*L{o$OTDa<8C7E=%h$X%XEZ$^G=}o;V3BxN+qL-jY8ZfRK z9UAsIi6L={La+LMaj|$q57;FXs8&XCqfnKFMdOY(sB{WaQc~z7jtvetXwNGJx|<|jENacvXUX9Vi5)Bjgh%x(Muv;pn0(vDN~5u3 z^N@Jp*HK#ARPBWs*v3>%U&Jd650+jvg704P+RaHN2xN&nP!R-ul6%T^Kllzi2EpAO zSqvcH(6ClkR`Wp}^EKmpTlgS0r7>@%67kHO*Dt1_mSz1 zI*3S6l_+0B4Vx6TcMx;zJr-@yvr?ZQ*eQx_^2X+*uzl;p4h}tSQA+vH{pCU!mwE5y z!Qct{E&}a)rm%RADCggCS}P4IdufqmeZ@zn!h2sr3e@BR9fZ{=<9Fz5}6 zTPfVIo)=hzO{}Zy<%K^5J((P*=q>RU%GF{>68rr&L*@Ak8+6(0i~3od?1l*flI|A`BAg{DxCY9?70)X|oK;IW$G9d)VF}kL z4=~LA3pL&CdP)6paMVHG+0W%%3umG^tuQX%W2Bd-vKI|qp%L}J=zHrc z5{$tGHbhilr4r$(*!U)F=t9E|vqZSIg{li)E+nz@#jYZ>6Cb;i46%xU6+RVxFqVt@ z`Bs4`OX1r|PFqw>X#(fr^fl&u3Iw*U+F+OBxp!P7g~_FbTdt5qv3L)m;mC9=iUj8G zuBcQ=3vo?rmTJ+G@6u`iA4wBoR8lWEw$V)%u zm)MA&;_Olkcg9K>KSR?0ScNN-4RtoZt`ZR%6@ zzP6mnvw4-}Aq-Q7;7K1AhcluCG+AI8)3GBGtg^mMUPw2xv?$nGNF;L3Li^s+&@2B} zI&*>G)$de~Q0N1iKAm}fwt6WAmAu-;TS0xc0e?|%yAG|NaE|M-+$@xSxRmGJWGx*ULd*!viS^lw607J3z$Vln-&L&v)xTg z&vfIdxEKEE%agq5XalE}{R#iB{%JZV#x_&c>P)KAoen+B|%SQMYA2AAdmyu5Q7!dk7@Kq!I-%mcEkzS zodQ#?djFX*uD}Mnx4N9(YX@JzI$!%R;28DI0Zj}ZL6igv+i_#58cq${_f>IA8#9e1S3{I3 z_sfTI$Y_lnD!PgUfIW=DksJFa>Jm_aI@M_D@&kv>rFfi@r{}Lz2drxF?^T_tz91t_ zl>JSf?HTSk36sr%5e0ZTc>atrLkgc%nB&>A5Q>GzS{0xU3mF~c@?MR!IJ7Y`KKj-U zCy@UGa>uXzDMs4?_aifVOGBZ-m*k{w{v2**L_x^v18c-(*}`TNwe=6h>m+5)D1QFDGky@la{FVw?> z4CKFa#!09t=J41G6JW}+%GU@EMm)uBlV>ePFEeAYOFTM`l|UYXexGz6-BJf2*}YNj z!}!3&Xecop0W1NV?s%!pUa6mZ~2*ZAL(wDvsSc~&@@ErSo_y~(Q+ zKwAFSow>_|>sAcN;Ts2EnyuBm>)3LkC|zKs<&Ci%UY0bJHp@gs#0doFCk+hMmO;s2 zY|vlB#DF^^1a6~5exylv>Gs{s9W;8Ju5D!1u(==uoO+H6&QM#W@@pYDJ)42-EUKWE zmw2kL?pgdHP3lB?+HaKy2PIml9kHG%32qrQ1>2QA-gK1T_q=BIb<;_38@PFzzeIT9 zAZ3XA4t;&R^FWj`nIRwB67yGEV)jOh^><%9m#@jsF4G4m-cHNiO=?B@@c*~rDlXv% zp_m1|=#2$PeA7R32A$1?5vtBh3eKZexXIIHSro=p2q~wJCEm`BgX(%{7>hMRMXw9r zr&Z!O7tf3FOg_4s3_-uo)BiJ1!x#bO(K&`Z_|c&c1H@lYY65K^B?0Lg zAD0hsJgJu3#dEgT-F}K@p3lAGPof%5VI;kE{S1r8z@uyY9Q0!nHStRZ|L9KQlNKh; zl4`z-gEsWZx-zqYJD&eRM&f~oQIrm$K5?LP`@iu=R7?Hlv35wa5T6tjf9HjvC=4tE z|9J5Odc1RD5I|W6_JAT+JwWc)>u{-K-UR7y1C0oiBLXFjR1%=aM2#U$+{eCR)cf&Z z_5eI7MAYaa_{+O4yIbN+KHM7x$K@+hp#94)Z=vm!qO^=P!dk>2awYEvcNeYUcL0n+ zKdPP9HI)2g{-gB~U3dzY9`~_NA{+hT>n7&xUkNHvQi4>C0c-0Lx)&g^eBiWB;e39r zl66asiby$PfGWrpXf3ciA;oO%h*}xMI*Qhg@!nC>8B*F?*g~DjOZeyqa>StAk$QC0 z9)>Re72PJMOcTz-V3%@LFSN?#?Obl7k1k9(oJO(g^K9Rou8V$$PmK9c$y`Rw;^IWl z5w#t0t+3FMog=z5)QAr>CO3s{M$jIwPXVF`8vud<#|CR{F~)?>g?1&P7Vu$_yH)a= zt#DW2&CRq*3@qRC;2clyDtj*7IlzW^tbi&r>%iU#I0 z0_7;}3@B6u19q_r(@!_#3p}{ptHqpAaN_P1m;T6PaBHF${BK+NfQ2@a7gs-!jVKLC z^aKscuuflfRJBhRNMb4DK7aCJlr?)5GAuzWpfB-@yKa)V$)Pzuv@6}TF8v+H)ZAfQ zjlUP+O%LrO2MOUJ3oeD%2L&1Ldlh|NxG^_SWkTvD5{2-=tG22<`BYst}?ZZ;8;g|N+%&WvzlGekJ zMa4Q`RX(!~K8rN*R-`@x*FG0Jlcz$iJk&*tpKFl~eqCA_`g#hD1jnWLtW}CT6Yb3U zfHv(>%!LgHJYRsANFEI-n5%3K$u>BNTen$XPWBfd(6Jt(Ar<(Kx(o%z-Go_SeojC4 z#f5cf@g~|U;==HTKj`H@rhSJHCaeJVIjhe$UTGFWc%esKeM;lPu0^c;f_BwEk}|1~ z1`_3%x$Q&ex0LE{QJvnHQh?N`#YS2hQSVl;9(gmrX0DMI6tS~@0R}DDH>ihi%gVOD z9h^~|m3nmxx2Nv0Xw+$ZwP;?Z!7rs0Y&i3b+AV(DqTq~^e*pC~HQ%qS%C7P3GsRn+ zkoSBV_#Tree;@q`?uW@212$cUfdIA@CF+buAZcWZz?O8*CY>MWYHNGZ8pevfq+2%q zHsyv?Aetivs{N$NpIJPm{kJa6`hhhuty~;xhjW8 z#7A0wO!U6}Ur%hxN3oJ%+OVtJOaG+Zi!Z~yN8sszk^<>Yd|w(7cQ!fxch8PVxwY9; zoUHS)tt>hE=Q#{-_h`VJ68uV_Yp#n=3XeYf~a5TN--NXOmlw9bW%*EDCMMEqfLp1Vgfy?{2!tYmj+I}e-|p!wJJ zS+!2RE9U+6ev?lZv5UY_H)W*Y8D1yQd(LB*7=AMI?<)$8si8yM9BhVHDofb9GsIoh zJG~p#<-sBq&N-hX9gVjFk%Wo-Sr73Z6VyXuujdqj$Qd?2q&OxGzFEe85xCAoi-&n0 z9m(-fsB_Q2b-@>efkq$P39P{_(CBW<6X-&R@r)k&@!hC?ivj#>cZMz?XneC8WnSfR z3V8nC$Ugs$x)FNYc@9n|1jqkV1qF-`cVbgH6qk>2Osr3g);QF1-ELJ`rFzo2B(bdI zK2So^5vWAE1@yY}aIJo)6?zMBkRk@8Xj_0Hp}o=~j}Ogv{D(U^w7k?ukK(pO+Spyb z1eoK0qt|T{S%;<=NIm;2O?i+PjB7=6(+hLVG&Enuq< zp;OJeg-T$x*D7!NUF)po@uA(kXqx88z|Wt zzEe&zps=={AAwHrIxWzruA&4TJT&lo=n41iq0^lkpp*?a9D~%r&Z`NPswMw(MSoju zbxz>s1Nj05nYiG(G0NLL6;IcE{kl&F$FHQjO{concPm+T0ZG`zFhP6jn{{|Aoz{UV ziZRuWF^%bTTc+oz2L=;lmN-~yWWQSV@?cAskVCpHW;cLJduE-_Sl#vr$= zce*kEW4ho!-UlFFhk++iZJA@`bA)2sUp+~P%v+sfVUYwGyz?|t;u;g zHv!9Mq{`)~H;G@y?s8#EYXKfi517y0jjOP+d*h+&o-%^>@TLrN!wIm!SJNQRBD#D- zE&9h!zaju|E57ATW6D7~GuoKs!!!mS^d}ikyOm7=^K)PJyvlxR#*>H&uCE#5 zYrj(v(+uPU^jD?`qL~6g5m-dKJ=8E~lEer82=#K!gm4x0K!IrBFZHB{Qo;f@?YLME zRf8RpGm%qWmyohiT*Z95B3xguY7yK|#yvWBbbprL^V#+slWmpc{;tcAHwhA;i{Qzr zY$s`eN-LU#{+}?@I)FuNLTQu?!r(ILXxNwb5P}BbgAL#R9f^$NJy`VLDATS>>WcYJ zy>M2U^_<>UUD%8dEq(9}!_IPsfC{VcnyFm!y~(MUelq7fODcb8t7>F`Po2ZeGu=wY zH)BfB^kSrildHar|Ix7_dti=yoY!$-eo@ z1DxAfse)cJYD<5vOSvKf6J8NSs#)*?DA>Ch$v5%Ngofu)>~#LG7{>wXNOr=;)#DWL zTU`0FZ+ThqYczrhL5GkQ+xpRK`HCWgj^^d57Zb+F-(JNSja(zbDROTaoVW1{KEkK0 z0-Bc|IB#tUntX>OjqthbV4}8yIt+6hF5J~!+v)5=Z$5vBoY2{*@-guW*Lz4=&Qt)( zs272>gaPJ*kgC;R4sUxZu0*sc>eO?j%kO~NB5sg4EP+B z!k&*LyGdxhZY25Ym_Y;e9FtPcZT~J|0kh!HrEuyQMz%V&2jDj70 zLwC#Z`qb}I*+S$s0zBejfaXdf7iR_I@wWbzKTX!ECCjZ`oK)A^ z4ZXqozxG|A{&;usb?O786y2PpQ5DRc{s1UN>T3kRk;(G1I9!v*%i%6-7WmIlhCX{X zX8MyYf|h5?U_Fzc`0>sM0doct6|7*dc=F|QIXwU@<6qc4<%8|hH&@i{oqKHz?0gy4 z9TUtI_ve>8vy}9uY5<~i;qXR1k^-j3KzB?Dl!W>d=n?VPW!)kA6Wa@z_5<-zu@lfL z{4DFrm|$0RH5!Gdw`i6gZFH9Iwy=%^ukrKf8B%k6KiPwliT%Hg5ICD+UmEiEzPY)b zR=V-u%y?Wpbq)~>sw{)*xbbk`RiapmAa6^gW6_qj{0=>!q7z;>rj`B=nDoDm?{~-* z^x~NIyc6PUn^e`?w_8>8x_C8RE{{#Ll{u|Qo!ou!0INr3TTb_A;iG(Ot_@?N=_jyN z?9YcIdEAnM_UQ0%i5nnqrDN_pqfAnmpV_$bZ~4pbx=?Ld4}09<7~&?-7No`>wK#kD zNi7;Epl z^IHj={(!AfBS;zGuCx`feCAuJl4fA65vSK&3Gc5vErt8+8(I?L$6SA1^t}_@M^6Ou z2m47e3h?qKoqfXBA;G=h^Q2;|55Roif&&+}PWoT!Pk^V&EXt6mK@8NaC^)UTFY&l6 zxq2%xx#b$e{AAW>awSf4{ZYH#wmzCVIO1Q{Ba3|Kz|5TM49(Sp_Ke;Zl_Qn8hZcka zn1`MWt&-R*s&9PFifrY#Jg$N@lU`lHdJLx4mW4>bK|fuP_jzP62q^%o33(b>SZBY6 z9Tc8(xWC8^A4E#lc%pW*R6pyf#Rlk(R*=AXK~a~a-EhYyauuwl4gLmeUS7pXRzomh zS$O3GiLMgC*qLZtL`g{Kj~+Dt^5lgY8-;b4``?i(d#7Va3dt|0;-YV0dm#GKw$TW6 z{DO<7~kmBF-;u)yn&|#fO?Mp7&vG|KH!Xy)?j|i6XNmPb^>cGkPFJpw&I7AU6 zF?Xcgnz*q}s``Yom3g(w8QecTeS0H6H60GsBef=nBuugjg@Eimj&~a5*S|-qML$hq z{mn#Tq~$xvW@(mV-#zBD6eykaXoh`a=n{Kfje0j?Rzr{^B(~c zPEokPKLNF4J`4LcSRVd!}%uctY`!tIm+=r2GfCd2vjvZx%1g0eW~~z zj-bpTm>`+ObDrQGQZX4w1%QOQPNXYyVeF-_zaFdM$bmvDZq+jq^N+7}yKLZ|HP6A+uL}|M% z@f{8wTfzTJ(W3WWG5LruMDlIT^{bwuSky4@jPNLny#9pl`T}@lkNflAJ_1jzLjE8F zu@YrLO8fCuGDlyw*ZWflD|#+jM>|(y03?WXLog2v&szW9fD*1wQ5qSp_%ldMVb{v1 zghBzwnui068*8EQ=sL9? ztHODeCEZ%e{2z*>9Z#p6wnsPUC&ok&U%Vkuib((HR7lZG%GrLi!>ul0j%mZxlW155@+HD;U;nN|Bv5Z}K-n+!j?mmC^h54{@#zopq2y~hXY=b8dZ?%7 zblir({=42ut$|c2Y;(fcO!mb~4G8B~A)CZ~PVrQh1@T{Z7Yyw|mdxQ!|EEh@aF<*t zoA*2$*uOi9&~G@}>`;jG@Aw@*{lAKomQlLf;r@1@3?a<}{b{$m_gBJ4=QoxL#5t24 zqtKt@n*jIn2KLohgDxOPH~@3X&>no#=F)xM(L5ifMb)ksnJ2w}dcju~MPG)%m&X$1ncD>)-*T?NaanR?)@dBv!6oZ z?_3T7b3a`ys=_CA*y^_fYCA9o%_HrxfhL@d$BC^X$j9w`zwB-xqHDKpoMv_#BPr~&xQxC&t^dafbbpy> z`y_FDchm9{eDiD5)UD3C6(}~e94>-ICYX>-%n^DSnZ$_yqLvG&H^fP>Zkt%_?SfU8 zn30m}fB7YT=+VV6#jL)V>}aaKKK}(@bbCad%Fuc-xINJ40wfF|i~}qt@s%comGy*k z^2~}(d=+)94cUqZxIMvVWgG3b?q0L)$jDI*QEDX?a@NujCK04P29|}pKsw0#c{ax* zQ>h8(eRxLr9EODcCCz~v+nMRSoZiEHe$)6p0PX8pLsg_`6GQ2FBMApg0vT!_oJY8M z*3IznZsmIpJJN!YpHFeil_Rj)V5Jbmi5d8(hP57r!~!q?T@W1?v$GI-3xXeT`2yIY z3lbQT(5;aWX$fs>7~?2O`OGPN6YW8-=~v3!v2U-QjLFxpM| zg|sjtoboq3LMMclv5yF`r6lXbTDn}CA(Cnfk$mx_p>(J)|GqQLbeIb`PYFG@8Dd5_Zg-d_#o)OP9$&zOlH~I02~O)$a8~_c$SUaF;uMG(2;N? zNp8@$g&y@!-?~~tppsf4yXq#Rr7c?H3}SA8jxr*X!Q(f(5AoqQcW7bubzMPQ+w)2H zCtKb$HOqxJtr=G_E6Aii2g{E4JZWu9j-b+ayRCHd*tcA`JP~Tt5xA*u zm6{E{gduf%Bd%CN_|3)~dgt~3fSfYX)`E?s|BB-52;kz`L1P3EU08z_1mq33k4Y}tu1b3fG%l~;<Mp4eCC1Pn zMYSUah#7_ne-lcqLYt3^gi-PDKJj}eo%&pl`OK7GRp8zaX%9em=+9nX6YfsMj*YcosShsOP1XDj(RNegJ-X2C&TvG&zDJ8f{RNq#=jLM5#Jll7nT1#; zbeC_ESF?Gp%R`D5yYj6AgmmO_=A>y=)2-!kTewCFmKYw=DY(V+NPjL93=RDwoN@+kqK4vO?}Hr{6F5#lGTq zaq_9bIqt>wIRDU}(o8Md8<((y6Rdx|+B?0yVZwOa30-q|*79l;_aU=%`TW7D z+eFSy$E{OB+r^TukHk)7;w~I>@S{~wD2=X)!<5VU_sXA)n9o-K?~KYHSQb&R_) z*fdRYKi%*Y@p+tZ!?sIzge}t)VnD~Juaz6ISdiZvxM{2ZhK8M7{ey;SP0>V}ut4No zeC5LTsIqU(wJjJ4=Kn#Ljrv%W?e1^S#~0jAN7b7E@okA4&@t@LF3P)+^E^!dX6Z-4 z6IBU+%oyswyiuLx!oc1|)yG9plg~M{j?2wlrQ^kx*nP@}yPN*|R&HfOs|HZE2^#QF6Lw)ttVle4TNLJT2-qD8b zXZ$COVPg|dZPOgQS0I}$)0!J`6$wt6hxd1AFO4tUL-OX;_MDM;KSCLQTa+Bjm+q)m zzB*SV{z$S}bfJs%RwE!b_$N>>P{6o2uJgea z>MJ5S5Mo2vr}3%mIloCWU~W7)&>tFX15(9>(CD~^$5phS5O0LodJdj+W?xtQ&a(c1 zt~vh?tcU&o1FYu)pxTp18PINgZ$HXE$gCsMfKJ=1{PUM+N&1&R)PX*Mg13DHEH2F` zF9SP%`^{0Q|SZWYgT%5x=o=F5r8)&vWA2=N8kJeRe>-46 zWLJvVYKyE8};zAA^2xbl#7JPI}`egdv|mB4Ql zGuR}#1yv3-^pXdgt-3DuWW?#)6ipw0#Cy>Um8$A-&;n9L{f(Aqsr{XkvFpGTdDc9N zi5MO0k#_eqsjw;zZ^)ks?f$tVQh=?H$94`b^QB?lF12IzDwfZ;Z2)SVs{cT)ytV6& z(#;-*unl0sZ-`Q+xz+UDztTSwxN~TsF2chaTLw+GzP%?j`pji~YA88@D_FTdmEypC zZnn4ZAicK5IzSL*428)?cdZWL4b--6I1R)N;$=f)ZLCKuX(oIkVA(G7A~;xI;PGM} zh+yiZ1c%8Q6Fcj(^x#7u4eQq*To&E)A6*V^tFKkQ(ARKUN(<2b9np4nbXB=OJn@ed zZ#Quh`=Ze*Wn4zPoC?-(E7CuJsVUKN!-TzxOyY^pa3KYS?M2zdnyb zN}~BgJD^4lRl#afonvx7PYN;Ev>MXQ`hsDnEPPqa+sUyu;FlvATTYiL7g#JR@*c*D zFC&oYiB-OIrc zz3u*dMZ?^eFhqQC=AHt*#+*>}-E{veYl>*|B(^9n^lexS*;#uo<_x82U`4pux8dTF zKrRq45GByCC?Wq}%YjUB@GGH?e43vgi2)ObKP}t-sz=O0ts9tprtv4>s!&X0EIGeSe&Y<--v`bR2mOktphp;=2 znrnGYFpLk^jwsQo2(Vt*Y|8$oYGh$l-zOxIPZSokEMr_enH%Bxa8kX~Cb6&Ydfp^( zA^G(-rb}obab9hjBf|NR_O6wJK<7`2myN0>wQmyNHaN`#T|Wb@r0ZAe+`;%TyVd!P zhg8x+Zi3$%=zfCdAPb=kb+fb^aAr1t;X6EdCD1m4-OXS3fQK5Uk3gh2K{OW}6zsEi z@4vZ^sj^8Iu`E#OG#MP$c%FHk$l-c&%-nb>7T$EZwl36A-5e*Dx`rGEF$Kb*==)dE z=uH>V9B z_;^;8;2Cfn3Qb7!Ev2TI8IF4uD*VII*LlOWE-Ny9JnriDC z|Nf(#3NBp|HXp;o%Zad zAgfzT3d{bPx(1zO&QH%pL_%{P2)a91TD3X7w!@4>Kg1Z6rlgk;P!mrIt9Q3cWM-h~ zVa)aC4PtPNH3s<3VmmprhRb>CF+CMS8=j3NUdx)1WeA~hG+5z=y6(`^I4I!%kF~dO ztMc2rhUtxfgi1<-q;z+Kf^eC;JuAJL~R4@%y1vThzsf;c)+*tby$&<{+8GYiVX?ZI|4rO<%RQ zA29NwKCBzXM`n!-%lUXd`isf0BzX|s^sJ2asVk_i{_!OR97S})z8fDW6QI7P3^r?1 z{}fpch7#%OKQTD_P_8G_3<_yy*Pw=2gs{cSgX~4W|9w6CAi4qGC7w<{ty58FYxjD~ zClvV&SS)ibk|-{wtUW>-LeE2+^hg911D>_M)#l4imPtR&(s4ek&}q z$hW>-MeD`-!_9Wn?SH4Y3W&r=#NCK+hArjNbA8vrwVq)d(OEY`;~togte+7<^1@XJ zNnIc$fY-a$7rCuehoh;R;&tJ=oWX!m4x4>#AlDXUMMRdXbp z)snD?t)x|cEpi|+!TjtT6zQG+^@zf>xOV61vzuVRR?p!qbM{G=4olA$6lD=;os9S@;0D5cg}$sHMfU)z&=>^BQ7;4kWzREV)5(FlUpYmhaPnyv=?2Fp z-QkJ&B+qsc2Z1`w8+}xS&oN>@;P?hF!dOZr=J+aE_Vf|}5aY!Bz2)WZ`8fySX5b}~U`0N!W`li>1d_L*Z7uTM=Wy9@yA zNF_9A)d0QR|EN(zKS1diBGIl&NuzZndvz088G^aurn9GRXmt#^EuC*hd|QiX@UakO z>yC&yZwuDX?6o<+CIkJAGp8QF?;S4-Xh}_Oe1UI_D^7|$_c+w~HuoL*w+J=2Vv-u= zCK|Rdq$EAtR~lrz`1fkz-`;_*nFInIIM3kFUX+8F& zx^p%LWw{8;Mj~5Iya#4JjkF?gD}xRJ4Vt};LcB7d60hSz-1%0V?c7FqgHoB z5#exMYYi?aiF&b%^r>+V2X=uug!AT(j@|Kdc6t`q3FI^~XH%L`GeX1CDW^Yk2RwEU zPm5Q@W2%rbsk@4F$wm6yvZvw!qLTB2VH^S@olgKgRR}j{uh*+rf1@vAUL2^pZFTN8 zhHZ*B4mK6l8^HRBJ@ov!)vY;15S$3#h;EOk$<9E$cWL6acj5{uKS)Qz zw0&jp*1rG2fx5ruRYEa9zs7O74^-q6@(bW?V-RoDg9Y_O06h zY`st92A5%zg2K2tS3kdc{rA5S_Ohn+!8z;^lNi0Q@}z|hu`%4(Poz8}C|}~xjtC&q z{^FURO+#<=Z@OKNo#|@%_yi(F%U9Z_j0)G@vr%TM=&kXH?83#!8RdddQqGJ=!@VbW zx?KeW_U*rlP(XAI+@8bGjV?AH9H*UbDzd0n&eI0owm@R9FVgK_=GVCtAFzNn&FIzv z?7AsLuMH@WUwjTwMH}A|t(V^iY7+3k_hI-TA4&UQpM;1{@!S9%I`dW1ihpG^RB&f8hGznepEZ+mnlC$}Zzi-F54*CGUtPyf21D#x zA|3$4+ngDrhUQnK*ggg8`ja@8x_6CT3MP__v}ItgZ9j6UO^J=@Li?EL441=mD+RXv z(!`sG#nkYu;6M1$Vc}Pr()^X%k~SHf++Li`kU8MujQG4q2G7BJWDJ+@ns?f%9*{_R zNl@OptvRY#M3{dW=lk=U%@?m2B=PRjOGI?IT*;Mk& zb=&UMgF{3Xz0II}83qB*%aFON)iQfMsdM*ZFYISKZu&a`F|lB)jKu#v)1+&(W%Ret zV3x%Eu}($pg{R9JgnwwbBiU`ah)}T3xMdVG@f}!Ct8DX%$n#=<&T~z6Jm;K9MO*bc z`sPj*zLn_wx*Xvv-eS)i<1vkeZLuw*%W%&?z8Sq@hmsc~ULDfRh7v9=+vlWHdUsD> zC@nyf^D4s|TQ9h6Q;T&!M}KT@^P}X;-x)UN$0jN38+6j^^GnFgLRwB1;c7B>m;tt` zz=}C?$3~w1Fxl2vHyW+#UTORP1DfhNkKMlzAcFG~szmR_ZqpAZ!Vs6wp8Q)jrhIFy zaNidO>6}9kTYqSPUH%^mqCd6UeEGv+6dJ=3x-M+a8YF`jzLP_~m+JE;pAQ<`6d$;e zQPOJt_rz7y!-3(ydexdxV9;*%^0Iwvldl$Ep@>m>2(Et*Bkx%&tIPnXg#SW7eR4we zLjQM|X&MQJs)4fi60h2#Pncg>jG3dTwZI+|{3S_|`n)nb3CPXLckA6zE{r1TPmfbD zI^j%pDaH+6(XJ#XSyf7Z^}c+aVfCphCDAMahft827(9>1sa=ZvXNU%pCfC|**d&G; z3w_EnZN+4Xi+F2~ouS9>m|!Et$yOj}K)c~E189y0O$5aoP@R?wL)7lq8P%t#qs-31 zuZlpG68_Wqq=OFPf&!#zq*?5jZG*usYw6zsWkKtHa`d0_&gP_awk1C>yA7j4ul{_H$+<5EYITVY?9wH!v>PlD!R0;nL ziFI=I`i0A%IU5OtYV`Hzp63_{jk*%Ig{J&$&iT(U;bOIb!Y<ItcjA~jj&iY zeKdpE_SpaA@FD3f?OOf+Yq_+)ZX~rD-suX$4acm- z5Gj$I3Z4f7)?fWJGu_>0t&oSbb9Dmw3WT<(?X{cQpIznC>1!!lgj75{@L~Bj2!-bV zu=LGFvouJrUwF7#+0l-C;SWgOhrxLn91Ae_9;ds60}Ph{f+Y7vR5Hhr(!3e8;3H3P8rSU1CUL%hi31^ z^TmoIW`<@>n&c?PL(Qd3{nh0`sxt!-et#+tK*fGOmh8U<>EXC(6?Z0FTS(j7t9{jG z^AwzNXgt1eGv)RpJlK_%)Nm5cBCImZ^i1;I&!8Rhs}odv)fnA7#WQ-i8lfZldGQWX2-$+O1k~UTw>|>7~msT#6tx*zIx5T}@|U3ru9Mm=ikz*NXvc^E8gi1hhzRwpj1Vfrv0|3zIa0~{_OXc5hHe!HT|O+C~nO-yzql!(?o>nYN+ zr!{t!BSy%H(?z* z^qgl{iuOXLev1%Mbyl@Xgc*!cc9YA(8ETF3ylP*drRKbq8GbkW?6UAH|HM-0JW7` zbzr-@Ep^<%>dyiH3di`o0s=Xit)B@6b01zStX;k3Z#sW;O&K=iF5~F-ZnNJRzoR2O z>T5|N`?sY~0!nrQTMTS(L711{;E)zcNxniYzQKT9B!v#05PpFO7ujbWT4|QAuVuzi zpjDw{UR0SR#$?vb)RAyFqG{e}-BTmlHed<=&Wva<#f2*GAPO$M+Q$p0If^Tw2=z#lP{3i@ebRaOIt5t z@u-5fQE-t8qQE6Oj{vG<6Tcyl`@1$ua<2&{@raOJk*1_*oj#6C;S*h2;xW9vWfxI$ zFjM5zds;U_})ENX-y={HKOW;@%DIt{f67gG6M{tiz8Crevp;jH(Xy0Pr-gu_Au@HR_1C~9J96KT^{88 zE{6h~A(nWkis2CH?1D+~Q(G^ZHjo@&=?Mu@dyKpRHg*h&i6tqEL<}i#WjZv?z+Im1 zuJNw`F795S$Mpw4XutTa`=m>Rl^Whk8EmUDIC7p_zN;a*oq>O*znr*u_xnsX>4^!%!eC7YwFNMg2C1avJz&i0vRKNBk7js!QEk)V-RIdA9cbz2OUYjD`vO$s;FM z^h+@6x&^ifc{0E5x-eOSg#vAEh5|R8y%$NBT)TWdX@RK@7Q;jtG{6PXG26=n5Emo3zVHY_wO6=|Mmds<)=pF^ z)=z7t1_cFn>Ww~I_!NH+coi@fcSk(r_kp(j02QWip67bQFx>oJw$J(}w04n@eIe>3?mOvtWZ*@T zAr9++LUViK^$UbbuFk+w#SR4z^ijGd6C(9_FY6SC*STs_> z1J5Jpw(yT326kF-QK9fhVouVEKXl%n=k9sSVgCC-Sct$?r6AfjwTVsHSd7`f0Jf@w zf5I(Bk3UQQ4Xq?BlXkKwlX{TiguY7j^g-XSTyz4Vj^}Mhhy0 z4{kYZyBdKGJ?2#&@OX(3gqZ%KnR!{B#-hzQl8P=5;fMdgFzT>^Or9@vx1(e8pN&I- zxJRrw42{M%L$QS0&3HE_T!BaHcH99%)wDFI!Ed6nXlG?w5L(ByU^8GXI-#kb*u#d^ z#FmQDKxIWzrI3({BMDDP?k)vUBkdK-tM22dfPCYQcLM*Mfdj<7N36rp45Aw65hxZ= zce8`Tp}Uy;d?O7rYrZNSP{zH2$m zKwM<(cCyG>_R?o2^zAnDNt>ifUs|g0wZBPo-nyTtQ6%p}l83sxZv335GDHSzp|Fv* zr$R(sV_e2W;FR|ypoyEoCHIuxaPabA;-LeE3!4xvTT~Ga&n9Bpj$OVs8`V!Zu<v>>LhzR)^lDpp4-U~*vr^Cmv3Pu zhvjLJSKCYOy@l0fO5I|8brOi}4^d zu9Te+74G4eC%I`dG-!nE4;dv=Ul6Dhw5n{-8f2-eI`@Dsobakc|ndx zS2_v~oT%XwtLRJYQY4QI(tIw#Jl|*C#vFRTPdf^OMxqU*VRd=j@?}YqB{|-X#(JLOyB+WtK<^CFgLSCa<$e=)YVsVz! zD~?Go*b=2|Bkmu9Pc4@J9Noaacy*2qZSH>gE{ON~OQuqGYLm~6PXxvf**e`S4Irn7 zyHV$^wU90Fh&Ey1u%)#st;QPA z3jf3_VZ|QBYVG#bfDQrqc49!|oTa)ktatB-5RV9|Flt+2;q#!w z!}O?IvyGVphZVmPshD9}7%?wV;~t`1-fs~%B&WtKQyI!sirCsG!;KE9SFhyW|cZ6 zoVX6?cp8yh*Ah)!!{**MH%xh#nF*?^pw~!mS`hc&T`r{Ei?gLbHoH7l?T#{O^w>4b zJp*I?!Jr^tbD@DGHKgmY1D7bC$w#%^)+gA@UCZBXpd(@OQLjQ+{yB@c`6_fh)%mAO z5284mBc*D%KukX?P%i=K>-LpTh80hB+5~XX?CEvxJ@?O7z%bSS)HEfw+qUdmzB%eY zp#4f)46F?oE9GzZSfdipdK z`^&xAA{|Bl6Wt`QqZyEE^+a|33>)>f2!Y^7W2WUVrm>F?elBd=2ahD8f~Q^&vBjyz zMh>dN2x;};JR3&xDJ6NR^rJ!Bk;?NVPpAVlGAPg=_ye2H@5 zB>{9t*h8OBNYs(PvLAzjmV6IA)z_Jy;aAB6mw0^^O2h@v~q zIyNZ_5+%4A_k!d7&);Uo3zx@u^^SPIEDd9fYPKYfM+kuJJ!NJ`Li!SXUjoG{LG?SGMnM z%+9;He4D97!o?=L1{OTxP<(Q&XOGV3o>jVI!jT+yX+eNiV;c-d6UN?b;dUwtiABY2hQ?eHgF zO`&+Z$(Odbu>pyGAp_X#vqyrd>I<2kU%8t8#^S={PqGUFr8*l^s){Y*g{MJJNU(>J zk}GLN%3>^lZU^>2z6^D2xpx>ICp7xW%D~Be^v;*%+gE5plxK#0Sj}P}z3^tRE*PbJ z==ZK4e}lLj9LYw%15hY7)(0_ps^9n(1bXc@alRR^-=+VYEYH<7!q>pLgcb=eTX>eY zy9T?8%;S*WhDmP`D30-bXqUoM!q{(ISI$s*k){qu%gnnHih$Auw=$re@iq0+h|r~y zUCy5<^$^{pfl94a=!sinZ3h;x3EgEQf!k-#c>JyXWL;Nyl&h3zpy}g&BI}~sRE?Y{3u4%K_KWHCv4Yrg7M zh^k8~o-qg@#}m;c+a)*(B@5-;>!zqY1;4+75g%^$qNgzxwc&E!)6yZQwF8TQ&p!NW z`tx+Rb*%^-5SR3S0+)AT<$`2VOYag*VuQ15qysLxJ&FpwNn)n$178uY4QG^8O-XVU zA_H8y_r$nQ`Ze`aTsVI+3nivLBEVzrDnR8kBdt=KI`PM_0V?9T3NcRm5X#95h4b+gFf zJ))Z{z!xDiB!>p8k4TM{O17KG9cU2Paat$-_`NT1C}3pkYlu!f`VHNn+6-TB`Gb(Br%!m+a zY`lf$%(X4s=k~&U5%#TM-KTCkyl}rW@e~4R6(D`hCuVJRvcQmKZ3}y4a#1vLvh=D5 zvjl$e4g^x`#+6BWuCDGSQe{U}SD(4Aj>nnB@g#6LZzGeA3u>f8?X;K*`&op5J`Ih-(RSL0=>g22yb)R{JN3H*&>3-nA_isC;$lYPVd|@ z0W%J}8bXn14TQ@iCs&%#`IGk}S%eR6!X&KearoMlYKYl{4?IbghsR_6@DN>}DS2$O zQ5o$`3K2aX=ejRS^U+|EwQt}S`OX(e(psUtvoHrlk~CRIGh_%gmOJ7?Qztw0?h;pQ zdhNN9TA-MuKpU~ibmfH`oz ztaTYP8D6>hSgU4D1L;TkGnk^#6?Le9M=gc3oDD z&xm-=`#*cq229WISsUw+(7u=LajRU%5SRt~QGrLm}Xiyba3Lf^q)KtunjG zUr6q4(*Nm0Qx`{=aGj^i-lr1r>P$p|G3=0YY<{<;YgKF4e9Zzsalt3V4~x&c%L4b- zk!u6p*2gUsHRcxYu7#XzhaI3&9$xn37QwQ`I&JrtH)t*KRmUEslc9Ggm_K6OTug|n z1Z5CKoV+HRrZ4B`^?(jNnjWc-c2X_#8YQiimwguNZY`ZLepah5$(~n^SH=IkB_uG#V zMoL65Yh{=B>beB0nh008x4z5ZrVX_^b3J0oF(RCg{Uti$It=ecxjCF2w4RAyPJ#7) ziI_*ihLRGG<4Fo?5WSbJj8P{IQoHs{Jbrhz(#D6%bpByDt=tbTrZQ_+%6^H4Newx! zG(qn6r_kSmNS9lyn9a5pNfG2t@s-Eg#1ybv)p&IEc5Zp4oAb2^j*(_qG+rptZYH~C zfQ)bh+|ag`I>OSiS@&g2oei*9?4cIXM`p^;J(x8QH3L@WeY`(aivh5_$tBCQBTaP@F2Y)%yn? z&VyYX2U73ixi_}sP6wYr7hh&xkfb=BAmUG?UBJ=$^SwN1Au*CGJ~3m3kt9Hkc+e^j z>c(>wrEqLAc9PmZ}h-RUwyq7{FM7-#S znNL-Hr$B_=M@IIRY=z4_Ot>rgk{Zi65qo~o=GajRsIY!|T+<~6AZ+ZezO>dp&l}r9$sffpeQ{TMeqZP7_}){VYEGAYVb_Mthjgbg z*x`I{7v~KJ*qj~sZu*wb0|FoyZK_Gh%KN(xp1z;!WoJ0p=8JZ37@`TCclL8Kvb1@Q z=XS3>5jpo4OLCyMdx-=NREKBW&k9c%V|za|kq1WwfRi0d-Y$VNq+*Gi03PMX!*qXv zv0)e7I=;Z`z*bNO10^Iwn)ACLp6>W{m!sW=$Q|36tv| zzLXTftEUzGT)dOes~tOYN3c^W0DcSYl$#~9OwkzX&6>5y?b5_L;jc~aiy zGAZBLHj`SyNxI&9sv6H6?v@VCE zSkSZ)3%D*m<5qe*5B4g2_f%LWR|j%27JwQPi~x{Mv&h)=oqf5`=Ae9H!_N=zuQYL8 zE<~GpK7eU?c705XMmQ}gYuC}N6$Y7a$p}+FNC@PK_B>fXOOMJPJV;x9^}4=yYq9yT^ica2@$SK-Y>R>Sh5y6 z;(8wpkGB3of2r)8#i=aRj^f?>>gvN!Qm&n|L^ix!()g(a>lGpleR$JOD{OEIZl(VP zsB*a&Iox7DK1NC7A{3&2meN!^nlxWA3e+U`N78*ho+XpW?X;Jo1lz|Z#%AF@%H{hz z6Spb2g;_Y3YQA7o&{|!`fNbgU`;TI1lOapq@2(;7M0MPwQJ=7%87~hgu2hTkjAgJT z`+rCNa*Q+bQMNUVMVjh@9r(k=i&(d1+yIjBTwP*s3V*4Vl`QJ4cJCU)=M@A z@W*fX(drTS{n|`sCSE|@_jM8Bu&#j$whG|LhzE-Ap-A0x#OX&IR}Gc>Cx%17p1e8x z5%X;gNk%2w_~t!q+hz~4iC>A|HiM)}F+I8@9kGb@YekMdURy8|)|2)~ps+XaI&vJp z!+g4cch!Oar4RTTnbf3Rn|&d*)ZdLnInq%VgiRI3t48t)4jLw9mXtyvgozFk`B2a6bAA=vN62|0JDg}g z=uyf&_5=eG1?$a<)wYw<3R88nbSV$83 zuZniycXz=~OeIKc%tvftPyYrC)!~BXW70?tE9NKvRTuYw3iI0{%gg9b?-7hzP0T=M z)LA1!vbN)8$p#( z#m#&6V}ct{Pu~e5iOn>n?_^j+AT{NXBbfvSM)=5m8@vP){7`;8tjzmA6LnaaKp4cs z9v-XDY~$~fpG+S34XRl#tbNEl3aIJ%49pY<+0=FyZ6Z((JAAL9+rG=$iN{CixQn05EFRwr!sz&=T}iIgP~75XZ<=u$!n0ov#R$Oj%93=_R=ai8v^8N3d>kDjE)(hz7b!;NO2DFAJjBjRa~g zW4)1pMq7JyIA;nG8IM~It@bmQJo{qAGN|J_Q=3D!!9^ z=}x?rv;2W!l3G&93M`PcW68OnUCM#zP}H7(;rr;)Ri_2`etVp3O{m9P3~SN7(jH97 zyuhr_%1b5A<-v&d)3uC_^oII&q}v(g8}gLa%}Ac;aO_Vd1`osA`NY0SMA|sy+hU(< zBR{QfF674ugGbfrQ{;rbu^FTu$23#>rKwX0G_#(W#@I5x27ma;Li@70>q3;O&2JpuHbT}WxRcc(8M?irgWk%xoagD47->85wik~vljJ1}VcMn~?)_@ajb0j=} zi40T8r>^~Yuc%01;t`8V`8ZvdB=d<(dD5&={$?-^b~60zF+009QLnEcK%Yo<8)J#6 z}Ie0Q~?r7lHL}^a~N% z4tn}&NIwi>jTa89u+%FocbgpopK~{xo$g&M_aAb$8{Ryqo$WKA3BM3bv0K7}79c#j z(wK<5(M=Qm*22~6f!>@Qgf9l^1>>rYk9G4XX%u8ru7z$SV#(Q_K{4&)@}XB?=*;A% zl%I`Y0g;9Fg5YiCeYn?jgsaL#-03+MqvKonLaJZYko}AzSleS$&Bya9IDV+iYoN{& zz+NK4DY5CoJCqUL1B)V9t`_YSNwU-x40#&yzOZcJgL@_5`nD3soQIjszXmZH${zMs zA0vRP!19_QgQI!tJy85p@#9zD&d0tqdP>p!3g5V8*n7^RwOIavtnap1rDstjVI2Nj5_YbRyGkr@I670IOYLS_kVNc6-jAs{@$Z^IT1q?RSL@ z*0Y3`%Dl;=oAJSUW3zeBib=QEH3sHowv z=zD=8sfV7EYd-ir@E-}NUII+VzEWIJD2lEem6+l{D zAe-{~G{%~q)adsv zN##0&f?^S=Kd1p8`IsJXN~7sk_kHdDjp;U9y66#+<{&U=IGAq@^JJm@?1a!SyR zRHXuWx*O}rddTItP&uYPwhw!M#SXT$R>Vpi@nkzK0KQ)nLM`2?(0{ol|| z(0@;|0DQkH=u?(SueOxG^XE}Lb$zysU~KUcmKR5|Gl|Y87`27iccd9=t+CedehSWR z-2Q6$+Z`A}~FcA*?_dg)6;dV^h`JB;*FDOgv`KWloxizF_E zcQP-Ub-0upXH~VS{+KWPv&5>xSH zMoGmp@`*cNgz1CfL*K1Df>r^U-)J4~-S7D4{!o1|K7Dh}XP1Xcp7Wiu4?MP(ean2R zGXtRt8NOiZLcWmwV)ch!I|8T!9eBFIiT@Fl@x@zqOAOZ|7&m^PgvLx)Fal@xE7Jztw^8+bv}38Et`d4Yv4oAw+KLI&<=RFhiUu( z;PN*ut0J?C533}ztY?$HY5~@WzA?z^SsR)y^KvpSgd$Y2k3NiaycU-td4T}W8jF)n z*jxHa&Ny2%!2i{|JXp_}`$7cA8y=l=?@9&{l4MZXr&tNV11`?EvaBoBnTLk9-FW{k zXO_Qk`cs7cAFij^9`24EZsE^!KRfpsh`7&>E}+slxZfqh zfj8WN9d*MOWh*dWe~(ss#6WHZBOk}9TorSRTO=nU1IJkac+Rkb`*mN@XNh~&vTiV< zjWkAd(q`~#mm&bmgcWJVm2&TO?(@8C^GH$(Rg=9190ByLw;StwtqYPIqXYg3JQunt zJ1Wo0_DEj;cW^u{;`ot-rP!Dq+B-GTCS0w89sSV}IR!Wx(x>tCx5o5+6Kk)*elDb& z{v*vU9&Nm4_t&0=D3Exh9!79B7hXJ4GKb zt~VSQgu!pgxSZc+6B`?B;;K&-B-fGVub>Q& zSH_)BHthKPsVY%U0Qyr2zj+%uPnPe|6;ar%CZkJGj-8O1-!eorH@k%40UP>>WcJmh zx!jNW3g6Z5W%qO3gxLK7NGy=QL0S^_fvc2nF)WFj6H8|%vhI{2{DFZOKP$`!;L-u4 zVE+q7t(W`heE|H}bcHw#$iK#KHqc~x)QoobYXgl1uy!>fJD~O#lzy!wSB6le*&+~V z({@}Q0dDvrUw&G>KwOvexMf4i=Ex)SE40N%svI4FGos+ez5ny^$WJ^!aB1bgjd-@I z#nE)apw)0YB5y(9nHtetWP;$t=ODp5Wg_=q9_=Pf2mCNLAcGo%C&(#qCwA&de@SG!)8@KQ4K>85El&>O-m?CJH zB6P=}pb7v$yz4mdMQ`zsm=|u@89_+tP2d!+eT(~okP+sPIHfZFdS#}OL$=u9W7FvE z7=Ke$r#(}?gJCaR%Us8!5%P)<8_(Qkkw{v?6kqB?GLQq9VO@kOSgCTU=mIJLHPU9; z$Zw!Gp8&>~V^$w?UgH$fJQ*?#+aQB@bVnUMl?AAyM?F|8?TVfa-xsL2{Q&YPI@y9v zo`DXW&=^!4)jdS7G4t%Wpym=P>o<9n#tc^=ZMd4PU>G=tS~!I7Sa!b$RdBpHW<4?O z_pbRozqJ_HjHx1d0}TjIZ~3+kZB*d3F^>4w_NYqU{;@6bz4Mk6%)SO~Hk=^_BQHOB zng=O&qJL7a`N+r6`u4>Nb106Z|CH@b#OO}PiEDBofmzQ(VwWYEeCXQ?`cCMNLniMf_PrV%k2H z0J_tWWZ^NfOD4|xu*8Bfa?c|a(&H$;5pd@__Xrol%U?2oNv6)eB&QFk$^e&Zx5^!N zUo=$+&i8i($brxZuP4+$j{4$5{mNzXhc=pPkoQMTol!5Bwj*h_Ow;ao1+y=bV@a{d2M2+(V=a2+K7i4GIk#Yr_*d`~Y8DxG zBb)|qPRE_;+K>>(920Gw2DkHH%x_HM#!l7!H^qp0DFb~Aw1~75u8uD7x2K~iNCOZ& z-)sJ}Skylw)-*I*qB5r)3r}%mI3x9V}eqAS@!nIVg_k;f-Jh5qFjQw);cz`Fst#eHlr zq)N!fs7StH%U&lz@*=?CAXI#)PbJiDS7-YM9id&$2g_Y#5}_aA&-#A@RqJTbNh*Ha z^Ic-sYzy7uDgWF^lp6ki3;~tF+pP=f8$l;|ra|Q&>K~H{AjBgGzh`}i35AWBqZ|-} z!wW}+8Gxgw>PV}LrUMv5?X_xZ4kr+f16H!=7cY7b*ZSsc`}ho?fxGVh{9cH7aS)`S zI&BJhN^_QBnB3kOe{~V4{OKZCFqMhVu1(6KnM@w^Vid-FE<%{mqQdJOO)mK}*Sl1Y zwE~t&bP>OSd%W6qt*oT}`eaJSZU6mhS118bRn-gjF}&-mHG#ggRZ+?Kf1xpvysc+W z1G0T7W$?FXQV)S-BYfGiJLTw*p502b-frU&TvZ|oD1tCiW{vTIL))bJj~PsBv^Uz> z4g4g~lA!V847uTlycp@OpMw7dOJ{#5#I=9db^uI%mTa;I-#5Tq6AW}%zH#dQ1U$A@ z|C@bG{@6oGbYGA&!tjyo6}?#D3X%>0i5QN^FC@^HadT%T=pBfJVYr@hR(p*h zWYCWrofZbOa?JS#k=9D-gMWAg={ejyB~F)DL_h@4b_Be5S%BMAdi&xfx0`)`!qWg$ z0vF)1tG#KUjSYB?Ne&|qA)jE~YUNF_<$X#foM+nL89^*etz*^TOIQ z!+%%EINmqtRn8r%a-d{46|I#i9g$uOIKN+)Y_M2afILH7W$?1d7{Iz~m`8=w`p|0jZR@))wzT3S5cCLkU1-Q33Z)`lepxX?25#mPR#46;)JB;VeLDSO3o{*cF zT1SDsCRpCj>oKa@1K4m{Hb?97pHOxhAs+M`ixiliZ~s&lE5tScKb7qZP*p};J=K_G zP`9NSmOs8>t=vkTGcFhMiZ%Xv^qS*TYO8bO}wL(Y8d%!CR=xqy`c zbwR_z9ZtFbkG;2!s&eht#_5u7q!x{Icb9;4cOxK3gVH4p0s_)4-HkL75)u*;N+YoV zr9+ADSs;76&%596oZmU;8^3?HV>p0k#hvrM=e*{e*TgOt>DPLb8ox={BrrA&eVfeY z%MJ0={hrNs6w&EL?2w0UKYKo9r0?WRHFjqcr?0+gw*I+^4~1o;YX7cz1t_AN`a!!y zsx^al9Mg;L6`KA&1>$7eNBK~J0VB;xxvyQ_1<>pCxW(OxDu}~xO@E7nZbwSLTEYcG z04}3N`=;Z1iT@e2t>;rKq;t1j^&dhaiGYiG?s~Yq&>4Y>jqc`pW6#n>)y+pK(gn=R zjE1G%aVGJlN3|qR@^E4Oa1(*DoOM62YdFbwB=L3$-YngUlkUgF|oZAzR zN~CObu^7hWnt`Ug10c9ljH3y<WXazj6l9T1zAp_RSKRk9BLh8G+tDkoBxrKofP zHrk1NZc4@RDj`C*)JDBT_T(%Mb+FHUN|<v>)Wx{i@u^D&mR8Lu72Xffqj1TeBYsk;2Ra%R;K#kiRH2Q|`yCXg~MUC6yy zT)-RBdH$W{&VNS80rMp$N?>VWjpEt3&*#Sw1bL}Db{Vo)DaU)50vaP1A_ov{rpwXt z+LBu%Cfkr$l2EtUA~zef;MN{WSy)UwHn3C0jh@B^u)Z{(XF?=*%j-kcSqn)$p04{I zlD>#U4ICaoIZz;$96&H7eED13?5mq6#C?cun`sZhYHB~^K}DrRc`x+DRe0V6$j?r1 zqvx}P+Cl1p>XWXO)!sSt0oyeQuw5ld_mt{90!hu`1jHep5OTm1Vm62Q_^HzjtAlo= z!9tMu`#IB0~GGuP|>X6O6fR4 zhkj0PsXmWHFCQRTUqtCq#a@Q4^&@R%T2(F zzUF7{;95}f18wMGVUCVUN7LVL^HyYsdtb-7z(eCP!&oz-RSdgQ+YD3J zD4_G%AqCO?4o77F6Srp3ny-)Qg!!LArX~UBTMTz|^9dh-rpK26Xu6CUhV0A@vbYeh z%)Tc#FUWBLPVVf4r5?ryrTaG3c z2=)y2CyuXtv~BPD6yiXH^9v!>E*wrn<$v2K^&*)E`f~rInYfwe?NP+K)Y+84q+to1 znNFSQTiv=dlmK{-LQXD$|-#o$qda zK?htAUnxL&-N>2=R4q*LO;^;vDU3Nf1#Q<`q@jmEESkpgMi^g`fhQe^>>gFqzEg** zLjFic?XLFfpT_!MLN9~1`9|mK?k<`{Nr;zR6%pbkA3Xj-YGiYB3A_ga1a?^yhy<8r znDgis7S=92M#wo>MMjN;k@E}$6JnSXL)*W$B$`{lh@uuVEcG1F(;6T|llLtRO1vs) zI=tIXucQ9F$7mY2*FTZmo}I5r{Dp8DNB|8=Vq1D{UucjWnyaQS)V9o2^{}RWhf+Cc_=JWbJodx0U$w{^Fi;uELt3yfp>?*TVWEU8VqU z%58gPcrb{Wi{Sz@E;}dn_v;b8=6}I3>;R{IjkOIl`trEX-bre%t<6&Uf(qzWWkFiQ z8o&T!HQ$|UkRWvxR=kG#N?bE+z%IcCgsYl=qEBjYI`Er6isl!(%iuQWW9S1}hW`=X zICb6p9PW>G2!)!)%|UN!xAstMrlHzvS-j0zUtT#jY=Z<;0W9+CK?-Rw;$@k_>?m5r z^ggxmbx2oeUFzQ{GKOq9RY=pql+k$OQix^iVh(Nh!dgDv>jnbXDyA8HEEGX$y?tyhG z;2r5HR5rc#Jg!3FI$8NK_w!}*NuDq+_v+f~+dq!aRxv!W8-5-LIN{iq=MnGj$I`&N zYfN*i>gQYG8wCrXKABVIu()WBCs8dXLoGE3?+Mi_DPlt@LvIi<%(%*CFLv&rrPEJ2Kg5&@A*4q>fIi z`msY%Vi=Ik`AP%8GtHKq=C8s+BMndAf41Rb#Sbi<5FnoK*2<$i$9(SOg{~?8o^1vx zPky&j3v=&bFSx-Hokl>NeD-3kx}MRDdW|z~{&i$!yLV+*m3aToHL< z?&wJ_s9z~}wMirert>P9iUWdbj)hM0Or2#BcoNNGvxN7tNlUEVst^|GFh2h3y%_J^ z^_3<%{}ZTbJ-5&%dbN1n_!os=OI+5clCag-1n{8Aq%OOto@uwbNlon=@w7(W2 z{ZyDn2Bl@+Kmn>2;!xIt{oU{Z)y8qBUa}}i5W`ROXI7N(?D3nAN*_l>t}j^aFB~SH z6n?F`%=5d>Q)n+vm3?>3>UYVzdk<$e0M_`Y%Yo>R;WU<~c56_D_xZsmIf~`B8)lF# zX41=y`nF&=xXAo)E3I*Yh*<&7aB+zTk?5mm&MwJ#isS36{+Nf(P(f&gCxjlMf$7V1 zXn5R3W*cfq?t>_$LBEIY=}5w%cU-Um<$dF_tar?#go|6E&QofWy#<-IKU@(5C6WZ6 z*_Y71+7mq@zsAY%Sb6O*jE!{mfCl01{(cH)sC_e0i(#P!9$GEU`TddDtB@~m1!Nn9 z5-GZ0_jV)eqdSZ;UdPu>a1r|+zwoIog~Sd=s%7Jf=P>NJMEfI6y-Nvtw?xIC-DWl! zJ0&uu8ako?`ks6=d>673GC) zASLJL83_FVBq&SD(^Vj&n|cP%w(`Li-9 zF1W8f-7QT1VJQ^oNs{JRKU+Bfp#)L2dk*5ZRGHwj#HjI*NZ6J0Xitr8!8ny z!s5XvFiMoOsnAT3OF8)YT8R27MHP2UHYVkmkko;oRaVhC-?UD%WCfZF<{qzC-O9t+ zBWpyya1slwYy*dQLYhblJkunPy=*wgPi_P#5HxDhKQIc}o&=nQ%&GXLp`+6>Z{cK* zjKE?&B9HQsIK(uJ^Q&2D2q(vN2sNzJKL*P^=kRr#>iRmAv>34qWHsp9rM`XrO9_Rh za#TdxBjcLvV*U05diuOh)NC_#{Bac@&%mOHGhBp7V!qX$MRCa}SO?{WM&g11TSbMeH#mcg=-Sz`}miaV&W)H1ne;8n4vT^5eg{ z4V>t3M&<5y4q*WPFME37`V^z@8;o_av!b-)&a;Ow;uCv524DRE@@NueST|eH;Ujc<+Ew=cGFtkQXbu4p#%6cNTW^ESLAsE~L4O>T zI^C<^{Kuh4Uz``e=b`)V`CXCk3V8q#YOk*kZ2f$fMmySzQC0T>DzAIh7uyn-&;?%) zLBB#c#JtiVFX8a(Wu|OEpSlUM{x1X&JLGe%F z^n37o>tB}l(htf#0@0rsML~!iC+~+tuU!}NTYaG1hbJQD77f0jt~1-ryDQlFkr|G` znU=@^7mn_Uh2*`$)Ty3Nm!ns!qWiO+nFFYbsC2tG;1|Bj%Xo0^Zk|4r)Enuy$lDQ( zl0R)ZjEk}N-BV>HcQRyo?0Q2u3tak*(C<&b z`>iy5rcJ35jz>Z|f8%0~kpGwLD&2GvZ1ks(J8&1!d0CtNm01+V1k%!Lws;= zXv|TCIh?NH{&bQOPURsvEm}Ps3u836(@zMSZKau3(F`TnhoEvft)Gt$Ltn~ z4B3z8FAv=30vjLI!UeDnI~PT(pEr2bFR?HZ~kHrSm3-7}nxSQj%9x z%RDZ`9yRtH18u%Q2U-#sf8b=tLj$eu-Fbsg2D;^xcf!dXiH>c zopmW)OfiJ0Sx#a7h_IPIAQhFZ$xF;MR#uUvs)}eFl zr=ZK4f+^@C`~2A?-?(9CNzC0DX2$c1{^glPvcdr;6XbS2Qr|6kt*`meDD>iklHt}UlmLoFVY>`N>H|I-&vd1`yI5c#VzD;X*Bj1D=>om_vqdQ)8e3Q&q z-{dEo7Z>wK7$-!R&#}{u)P&svO{rnw<;NtHkEm<(MU=q0c74oysLRoGef1NARG`OB z_sn+OSo+$XIjS7k75AvB9HmDEBpcaa?r9&D-9G4@%5Xbs)pvu^1mH#S^5u_HiPBEK zzSJ~(>W%sf73pm5#jk*fUnY{UjmTx3*B^|p%4P_abX8P}YoyDaE5)^Jth1gvF9x*Z zesN+`FwFi|{*AzKc`?0$;eK;)+`k_zERqZ04Y!H3+x|f^+jijo1JU^_LPv#OBUJ3hB2h~(-ZvzKi)n3v&ygPN~#var{|D_T9 z_dw$+=SB2qGk>^d*R2d?fRV+2diX zy!RZF$(qaYpwF?eh(6U35$NMeuh#bf;8i1Q()+vn6v9-QD4C7n2E`7ccPKDa>IXc$ z)681W1d1HY6{jtX4CUpGC&e#|$sBufu%Ez-&&DDQc0w3v@Zez}jOIWrPzUM8Xx8;+ zUQDWVt6-2-Q9E!B3@33|K~+A^<7ynxu8oTgHMYEX)74?v@EoY0p%9$&kW*2MsGyK> za~&Gm@M7EeTEGbhIFKN(Dr(k=vDc|=+Bufk>MEsaViGn1nD!{F{}!58-Gn9pA^$C3%U?*O$cmy}Dy zmH>?zlg|%eZWRJ}ff=bWUn7&EoDR@stp%@MAg!&<;_gL}q*ilns$_Uydg$FJ?z63I zTh~qMaB~?Uzy9>rzcc`=W;CvT2eLp<^u~qmWBOjd)`Ftq| zgHl+Hl!VU_bnO_GfB(R=ajZV5b5a`Dnl!W?b|HfqEjXT)m409OaIYI9i{IsOf0*SW zFm5q+yez*fkCV=1A8SOR?vTe!I0C+iuioyXeYIr-7QWLo^L%x&x!8}^$oKp!;L_FT zFo|Dez5Wz1P}Whk3mLEJukm6EKNd}-;Js*`?5MK!@m$$`Q=Vqs-dcv~<%=>ozy;Ju zb}3@eP5ofZ2m`m2lc4BEl^qrQ2eRMi8?C$WmF{aWfsu7d&|_3+AOkZ?h%mjeCuByl zG1b(@g&q4zpkJT{B7_dMFowgwwyCo90A)B|!2eT?LKbwXnd`lI4NUB2fUo!^e4x~0 zz-P_g&8x#FOV{cIUR*&Xd|9oqNysgVvI8A$lLAtJ7kY$f%S6=N1HBwhzl6yq3=9^0 zF~C~pc<3-cDT?!f+=s@+-IUt(svI_2*U$8GPF}9xHhu_;)oQly_DvqufABP90-lB; z-(2gXaf@C|5^`Fv2WC`JibEv0rtzU|l-qVMk|=+98u}~6CahHv0dpPO78-?Cf$M74 zD(ma~@ZOa1C0KiS`$v;=3{DgfDX^3Unu4BYuC*&fb!b1Q#j75O1^XKdq0c^^Umx26 zkL^@sr=dtlycdPGigw;9Vz#(1YWDMF_YqwZv6Bo7MyLZ5VslRbBT@2e4?es-CekKg zTl4)yv+nnJoLXUZST^w`S-|h$-lHhL?K8Qo3(kFjeDxck@yPWSqh1B>CFwn6K%GAJQTux!O@ zlbzeI@-;!RYA&~VO8m;7D_YkA7V3M)^;IMRD^F0h_^W(n7Edc=|BhGmNbsF{(iCTO zkKAJ2K4MuT79;y!s*%Pbo_F?rl>u&f-fKNw%QG2m$SxO#2hxh=xti9`r?idpQIdGy z)Ow)l2!z@JW0x}7VSOyPq-&cDIo0e?;bOk?Ra$Q#;sbk|i)L;k#&2892AqZb7_0Fu z1vFb{YzNZCxxMeug?=NOD{`LScCwzLbIn#6Y_sXrryDGnV^Md;xktmx!_f>5?|X7% zJkj8^opkx?a#8^Pd1LpdW~k5u^++|m>QRQlf`yvtjC*kXK{+pWW+|KMUWx;xeizU- z_tggwVx5?w33;gKo~}V9b*(;R6{BeKjfwWd)mmUb(1M4_u1Vj2c`&N;ut0V4hmHh? z3fDTxfhpZsG@2te9Ge`n44W-n=SxR>dA6$j6`c|aa+Y6%{lQKP?eH3X%!tDk)M*hk zxgUI7mX?kYfB3$`&7A&g7V=d#P_|k4{8>OP34QS6D!=ViYm-q7L#-o+jBFh!0S0vN zuQUAIQ=+3D-s4+FBi*Ay)!0H+p}C%gYRUU>k(JXh;Mjv}Aj~oX3W$ccF2DccHXI%^ zoIy2P?Ul+98006G+DAPL)oIw`4(-KhSAtemhO6EaM5|*x7Gl%{l(()r+)vw!Xs)`* zVqn6#I7sRs846z@|7p&S&sNv1lub-LNsVMM*Y!?5Bxmld&{Po-_3%4Wy-wUf@-p#I z0E?6Lc_csb^H28+sx3C*V2t%y7!QDfVw*z-8jlGKbOe2WHLF7}mi)?*YxPopS_;<7 zce4hNVYptHvEmiS8zJt>%6YC%SVPF&BnPlnN#+0{b8ft@kDRyghQs$t-2`w#rMZC+ zeE8BzSE<_w{165b=Ndi0L)D$Vwt?AwJ5s_~C`o+p6tZDLJ6eWQTocS}N?))p(z--a zwQTmt#N4I`nTQa6tTz6B5?5Bto5Fp^;14=`u^55@_V`H1q`a=6COF(P(3cm;h4i{L zU9|o~qO{iosD_kd7m@t;_E5>1s?&AfPa8136lOdILWgR^Mw@jH={l;0A;)vIC=OHo z9uhq0-DqC&@iaxwp#y3EhadMoqZ^J0Tz|50=N^y~bPc*J-!>p+8-LSNwZa~vP+a6p z3XAhS3Am#(K4XjjGHvVWBTc_ssOY9dsN>ri=oc`RkUm_jt{_{z}_5Z~BD z#i7}gFD>t-UyLf^Cb)<+|HvR7Ji9bqt%sL|^<7JwtvU~tb?elFay4TDU7Nk*ecp#v z%tt;F!AbYBj}p;$2HCY%%vvIp-v2spZsv><314X~kkf3r{pUCHXx}BBXg3F&v0}q@ z!U?q#rq1`Cd^6o&#oj03Dh}3WCYxMjd_|3d+AmAv_DeOMNf){*C;rI^eQh!0mv0XJ6OS};ac0}a?^2UDAc#XJ>3n-cw zb(0LrCB0K;p}{VVsZOvjJp?im9E&I%!?2Xh1|K%aYeueVA)fQvLI)9Fr`7X)fL|%_ z`>_7tGW`j$%S+N%R!rwQoh9TiqwN`7<3S1%ybpTB5T0+Ghw7-JwglQcpT+wt_m$OI zZIA6YnJ4c}&VJS9<@clQsER+ds`+H`LEdXU#SO5E@(7x&tKuQoDmW|LBRef!G}GFg zXB_M}pRP3Y4mbUIIXbN$FA%cvhuP|nMffY15H%0qg%%RpsLvGmMx+|U#%eWIq`&iJ zKLbL?il#7vCRtZRz(X(1t_seC`??Wvr&O4LFEU7c*!x-EZ@RLK3HGh>9l}`)zh99F zgBwNq&`lg&DmA)W$-|33R9UI|2f$0jbE&HTv0lD)j3WKx6qx0)A(}LHZ!H}pXMvJ1 zO=|{{vq1du2avO{c2xWRFAb>Nx_fJqYb(0rfS8cV2cB-MP#cHwZKXEo;c?Mj6dGAR z!-tX1s@UgL1+O?|5i}`iYgK8XC9pJ~bWC++)3yu#8GQy=3~Z198E7GXkqIIWX#v9+ zib3WeALUj* z)1YYtjNN@o$uO7*9*ED6&GKsYPX;>3$f+TY2mxi0NQ%`B9Pbu^uM4~mh2?zL#`AC) zw$MlF64_&?ONSR2$o|I8+3P3y-7{|=WC~BE%~I2ABnhXL&}W*I22m(_pZ5M`iEg0K z)C&S+wt?6OQ~xd>V9P?~N6jjxnQ|0YpbWKcj$VYejs}xj?ug1KkVaD5R9C{eRni~e zAB1f`77_#&CJXp}ZvA@Q{};brJz35Lbr-~n#|>;d$=CZk(_-VuI5ybmM6bEtio#px9eE zAt_0CXPFe#<1>u3-{gXHr5CKBWTWsB6rqb$Cj=HuW8CW?w>E^Mb5#5jhzd`){ zjWTouuJ7}Bf00fb$Vz4RFa!BjsG9iteMTq_+I}d81iSB-jzruWjN&gS;r<{CI+p$q zWI<`O&6?s4@xj#uZy*wkvb$3jmzFVhSFA!ag zf3E$E^!G6UB8&#TNkd(G&uP!21mb=8?}p}YYLRC5s<>a=^Mp5@n`{{UU7nZjWBRK} zFy$o0e)xrrP1n7}bh8rySl|Tmg2S`7iNCCasPtItG9(3XM#jm{_hr#ds+K3oBq7u~ zu^|!nHL6`6zzJGPH-i2BxUY5z=K%oWtONS7eo~EaU(FRI=xIV~YNS%no zPFERIFXrR-WN)k*{1jh1-^V5GbKJvvD69t0b5cF`wZTEQE<4P|yY9 z+?34zh%dfb4uOY2%@09Ir3O@FW56HrIkfxX1m3Rp1g;H^7oChRDi7Klq+m~R3T

JBtEO)m?n1(6wjoK09zhF!u;bM^KW|~7S4q=uoG@Y7hJ2=VS)T^Q= z$y~1sZ{GGO$-R7lhD4?Di*rBzpjk^939y%aB2{~ zMbLQO#1;u{SA~w3;@g&$-L4P!rl#qrA>=U)xDm|(bY`xj&T-6Y(0qwf&}dlfYM6rs z6!dgtJYWX0Zh&)8cjFJv!JF%&Tk2-)=tuUU`~BbLWX z`drLf7+ICk&d9NwZIc0EKCk7mEc}bw<;{)d*^2V3*^0*a^6tg&S+xHBtg1r@C#tPa z*uXT0?s49m0+r8;>IY=zr)n@kHY(~q@7%=WaHXWr5&`y>p4fl@YbHL;M`U(BD}5-& zx?CSpwvF!MJ#WYaU1M(6$pB{^{0SC4sEB}J0moq!e~NtzCOmNG390%IfAzHVJ?{sB ze5jm!9sfeW@~tp~^UwSM;J8D@4k&=I{fjr;(;P`l%K1BHe7^IsYR@VEZm{K`ZX}eO z4p}+8)H?VjEX_x7kezf1e>ggzIE@%Q`|Ij^-K@R^`vzYz%bZ9vyqJ_;LRwYDbHTa} z+QUQ!EQi8yuAYT(i*7CNerPv`y73&P8f`o`HIKb28-IQjY48|0`=`xD)L+izpxd>_ zrwe@{nKlc=8FUXvvMj~l!vU!33hkN|{r0Tkb9D98FJC<*VgpKA(0`#nWwpS&keAkR z0etR3>2JR!{4S$nr$}#rawUf;02Er{pXzox^x5X#0?RNqTszlL4v#$h-b2;!7c)b7 z6%h+Vd7o48_#2*p=rr#;n;3BDkh+TQrr&w(Z(_YnVv)F}{+Gz=+4@tqmHuV%VRe9H zD<%ABXwwkcZEB&=NpN(d_A}lw65^-5?agUW`ogMlo-n%@2cpf?#Sfsv!bg9{^1~Vh zHht&#^M0R#P7s!?8)%M6UT7e8f35dAx?f^?cCV*hf5E8jKp|xcMI-C*y2eHWELOga z9;kP(^BWdSVpFH}%-07pW^wNa|T$+{L;BN7co82*5u9n4&9`q8m~=LHbR&E{p>~8$mqAc!fT(j2F8HUa=RJ z0SnQ%DgMW&aq4N;#T%##zPmF($dh3WI5QGn#wQAs9fIJo{6m+6KNI zh|%pC_IIJ%mAFy}jCgTXmr)<|2h`pP>q?E>7Fvt^M0p`)~;oFns<@hGse+l3Is3)me(u|_wJ>w}*szuKO zsW!)HHIm8i67nc&CUkgNS0gB5!DAz1+Srd&nN-EhvBt_q=87%CSQDJCo4*DGe}82Y zHq8px1Ir|a3b^IbB*%DJmWgGvGYVB+kRGuH`F3}8b>yCFf9OEHvfN`0@*`q^D{u}$ z*sbIPsN>hG9*;}~DM%O2p7wl})93x@?V(F?a-@|Z2e8NczN7@mHf*K+p@b4@itXWW zNxO3NG~$G22sc5fCt`^E_^=z=^`=Q3d-98;h~DK}g!#hW zrASMI8iS_~P&&dpWn8&DSB&t|gWq;?X~Dd>%wA7?TzSHDFH`s@nXrYH`Q*q-S6{a% zP~rtuoSkon=ddn1-}fkOsPZa8@dgQ$vJSD}VImH! zSPP{g*67BE?@NXvdJYe3$d7e*NcBq**v`+!CdM^+B7i`3ig(InLJ?)Pn&xyOrHt9t ztn3#_Q&YKK@U&GSep>DjEsldAK^w)Y);lw^AtP8jXsE2Z3;jFT@Yfj%Z@F}zz}3~578 zsWwG@Ibh9qWPCX(R+YD**HP4D?Xr}BJrGk1Ai=TwPonBo8J;X1NQE#I?!Xu;?oJ}s z=e7ySvrx}7QaF?eRdV6nY#cx7OM-`f?5p1$+)8@>*gOpfLzo?Oi6>YX%8${ZSAW8{ zI;s|vVPRu&-V)_2dd#>K#I;=o$Ohgbt^%iz5QKWHBPmZyu#@}b4+DfJg4#9`JA&A0 z2EF^q$$>S~p1l2fNmK20Z6~}4epnCksN~{QEWP@UJj`hS6 zv|G-$4a$+iT6?EmBr}ke-{wI}a)^6sc_o%G_nJSFl6rM8z1YT~#jae!%`{qiQLr{W zwkUoXvbizTp?!sSY)o>=cb3%EfhqyIev)jQ5(zLaom*nYhx#EPZ(Mr_RLuOaCH9Db z`UsaNW`~9W(0=H__v`f(B^>f|jOP*Rm6d9PWrnAe=A0^}!iR*nxS9F}4@6{;PZQrB+P|1)v@WuKnBEp@ZOGS@hOBwfH1!?ZHgWHSCKs+g=1Rs?g2C zDMa)b>`bel@*m)oJV^B|hq1sLHa+>VDzd&Y)^@+UN9SvLaiL|3d8W4i(sz(CeuJl3 zg3CRUz8Cx7HM^k2ExX?P`nZWe=oR-`cYZSe>2RgO;*YCAqhjLpX<7`b}E)nu>8AZ zbi8F)nQ)XRE@5!7@`}T<6o=ZMSINCIBBD&ewwKzz$c!FA7;>+Sx>*+BYb)vf$d0Un z2eL(Jex1BG^XH3U3JIUTCU5SVcSW(Zw{UTFwlsYT`OU%X2?`$4gp+!BRV%F^A&-14EbsRxKv&feA1+0nty z)YTH?>g)!5gM^K%i;AVQq{CB32YX98M+*Ltf`6poA1U}p3jUFTf280a zDfmYU{*i+J=TZ;@3%iJvgz+~fvYm*QzW&0HZ$1fW9s(AtI6IiDTe^bufnTL$0JPZhxhu%<_q!Mbd7GpQI|za?s{!8w zpt?YtH;*+mxIpYTGmip1|Fa25Z|_?8b1*J{b`JE{&H-q%+bwYX$i~72=*;clI3Q@Z z8i?~otw7(%Hqv z!5+lQ&cgNE7fnsRe>*N#X?p+|x3LF0q-bic=J3?i{?8{eHqI`tlGebdIXM7K z-}JXXZXkQeEb*{$p!{XXcisWWlHK;~uPxv9M9K6i0NekYp4ypO0W$+M3HhYN%|2r0 z=H>%2bMkV7c-i>?R{xck`blWr_$d()+eu$O{*>rzw-oH^h z`G2XMw~h~X5GNNe(C&YB63lB~`l)}#6Fv3)9^antVKXtu(@OoxBp)p?H#Z}yt}a;5 zG7+qxQWso@n~$4wR#P!PFoxAR_#&)-l3&VlMB4KH)2-$Q>Y-5-uIe8jd``&uz>jNz zrzHIL!Nt->t*A+hvh&D!rc37G>$FiH`}eObhb{8$Vc^&6xtVDXYrYWxRS#aHD`OWf z$h=9aXUbfB-Ls{POeW~Jyvr#`GQ9rYi>!&cPZUnrNylgu z#rHmMM9-9GAve@<&-1*>TEN@Uot*r{WKi)TSRw+yk#(1i!cr^cx!hq`2R^ktQCeL_ z0S~33g<+!_`@9tX_<%Tu3VvL(jCZ1rqL=)BHQnl4-WgV58FTgFVL`zII+_>4qofRH zPo^Fy9v2!hv)L#RS{Ta{$Ix<|_|`w+(?3p&!+t%HL{>PtLU3%)yfJ(1qR|Vu;d9|~ z<}IvQ%;IVlQ)%GET~ceh-?-0F-%opBCGvB?RdacQqxg}l)&cTxHb>6Z<5sQ-#zebZ zId;p)tvrQUwqrK#=Hibq6bPJ3Zp+lGjD0FZR}+yqhGz$7_m62-hoD!_s$&J(5#F~% zn;S=|zn9>{XKN=69gTTiG8*bwhkO0lyYEb!NW^V9OO+%JJBICLPv|K^NVIan>T0*? zu@i1+_Zi~q*h71_u>Cki22 zs;!q=FFn)tKh2>YYoT9#2^LK>SLrn2KjA!SOQ|?vUr=~&)JIO_MX6M8g?kknIUmKF zJ5xVb=+5pt`n>I4CA*R3#mj0J^#ae}eU8<}s6{pe>IMIM9SymD4=ce|JDX{F?nh=1 z8$V8OtNXZ&5wLmsJP+SD!`;tBIfhyFFdfBM*2cCKTz$)yiMC2aY^HlgvucB${*IMU zncX)t_-PbfR#h?G(B2EQ7{C$#KC)^m{C&gOl)2%|%KK5m7!KdT=WEN}$FhVNqH8J` z8>tQO~Ox+RIUZOWUqOG<>mCm1o z!5jv?)+Qg!3}%Bp`<@vj4>U;}mNF71o#s{`B~7gt57Fki>%A@+?v4TraR;#*jvcW* zftxzY6~NHUElQ2DNmSxyzBjSr35tEJp*5qKkCW(>0jCLPSMu&%8o~dJxx{U z1nI`vEJfYartyT9D>{A2^y}g9d>v5vl!@!65_%P>WB2^z8V*{PVz$HUXwVB824v)N zzZ9toEfhu&t@gUKVr*=E1q;bwts3<433|Ux9Mq0>*`c>cf7)1DOJo#d?9sBcZ*E80 zC%eub^)X77UX-_{lojEU*y-CNEqH@B*D(EB<)JP-WfIH z%XhJ&A$irc{DO*Kuw}Sp$9*Qgw$`$MF%7R_ZHL3sJ!PvuVfHC+nN1b#xAFlQ1S&%T zIjc8cDW?K(L!>422?yb2T?hkNP})dRakJ0G(XE}BTb;|bF0NfZUO#6%*o>NBIc!nX zrxS8|88$Kh!`VYV%gD)7*V}c1wPJT%%Z4?)RdWQt#TuS;YJ9(hNB52IEHPJW?rzTT z`ZqF?T+7WopCbWM%&k~=WQ)p%nAW+UudJq0NCbYsw=vb>Tp~R&ujiS|6=uc~d{9w8 z;cVC>@`&;~&q;(k?>zIi$ehG3C7pl{#c{{O&o5?@T>5KC)`gSZ2WQ+~9}%{i zq~;2gKkD~56iR)TN~^=;l6{2s>LLGxICl}jqsiTI=#K_-We8J!Jwh)qN=ADmxaP1M zo77P9BYSolp7_j3`OxmhUuL-CRdf&YWtVfIMC&^xd%8+c&C7aCX7@@9KM0;QxA|z# zdw+Q9!AF5(ph)pkV$#>iE>03v+6Q^nZt|qn(aABR&qY(D{1nKj zCz3%ckQdG9`&t)Ame{m0Xc0E&lw;vgs8rAM);f);Loc#OVKP00M=nbu?HK=Qy@r=T z!R$+hR3?6zQe~U`219T`0*hV=Lbw!(@{vS@G||Cn0d@>k!Oth%)t!mrqqY>49c#p6 ztFrq&MIx^~TIfWC49K~@FyN}^neFBGp&BoDT|XAuWGybm@LZYGozkQ-EhR3Mn#D{& zJ&-G+F|6Nw6)~55Fi_aQzMe7-4(Fo`{)+X`<*o6EAB~#?IB3**PB^EDr^mPg`e52k1F+{RL%mWT~-g zDRefY-5yeY3p-*DT;lJAL?(-=C;HVQ;$JZi>?kZ{P+2BT`q*;}m? z7QdEnqv%NQE1tSYqE*@quWf6!?ti<;@Wn+&l1u4zD}f5*!)UE~=>=~!Yr8BDmZT)i z;p5iVC0d&ZiS0Gl{Zh_5qQH;yS*6N}4L47HG=aCc-{Q%gxq97KHnE31!kIh+G0_$& zuCLbgL&Ha7Uy#y{uQg?reR$PWYz1dEJ*`b({IS*Aw8c;B@WS$5+G|W7v`y=$gnwg@ z+*w&19Q^!$Xj=ar^;bqkSzS?vQ4-J%&75tRB^>N5Zq>QpwclHnomIm@)86JLGKBwE zsLF3TFXwMMFCU;S{-N`7ad3jT00o+xlNSZ}58?t;QpisZE*=mUFBgb|g9pUT!w%x% zWCNZ9uW|6-yass>Hyh+X@OfU~KM)_o$;}PoW9Nh@jKFts+`P`o#slJH=K*o>+`gZa zpC9->$onDR2eb!#mJ=|lZrTL&OfH}u$a^8rxBzvP7qC+y?eIWe1Ns9*>43Pn`GNib z&w!tQ(bw;Q)!)K)faV|??|-Vk8paPl`7DMjbLttPTM(IDZDmIXf}^2WlJ+b5j2N3A zht=~c_G|EB`$mhi+U5$Oi1B=imrUw~<#qG-mf5eOg*hT`X6p?X6}C7G3I*Pp3%L0- z=(QA-Zg|yPgI%~E^ACr9wp7~iSwyd(=h!$ft}|HQS|@Ag>1Ox&=qFl0t7z!wjNxa5 zelof&@bdds`j6T3GA6@#z1Kgrq8CeDoZr@qd?N8GFUxzCR=Gm4z#j zbCQHJQ~84Z3_lAuD@@F-@Js>j`#Fu4l*wZKN*q#8kq%D4f>t#JjOJ&0tbmf?FW3P^ z3;wNpBG!5S>Ddgy{^_08rD5qNmZg*g3XX-vFwTJsGFal`l}}&TvMoky<7s!b3kdM= ziu84ICx8ER(#y@%&O=?%<((33WB^Y*z`MlIx~PLUU3ErQEMovKS#sYAPpHgDX?khq zSdC9KD3O~p^eLM~epu;}DXCYFCgyQ7RmI8`0#!v|wCjB=|ZU-QzJ$D6eab4Dyg`ytEvf5x$49pB0FT82KzThh$9`v@7B8_I)ccq&0k1p`11C zK_bI!asl5i43qvh;(Lc30Q>F_>4gZ{zgn+CmTkiWv-*x7y|L3h?5FE0=@_n(SWhVHXi+>ONVe8Lm+@m8J(AC!~?`JayP z*9J7bn5SW?3ahJP!q!=bL*YSqBtf4JkHE-}OqB7mCe~6vA>GxA*x(gv`{DUTC^OOG zY>h>R|5n?yFlS37_4Hf&63_O^4s_P*g`Y;s-{)$f<0zj|@dYZ_5q}N{6a9eF-L9x! zOB}gz9RzyaFo0&heQ%?mnXop#N`>#?1e+&qqvChQOxDo-@yV0$6}KHzKI4w3cEBj}C%o^}OC^qmfuw@x2gKXc47MU- z3Tpc+Lw-%$Xr>2;d7|IiJ-Gce+zkbwP6wCJg2{y*3a4~LfR47(v>iy|3<(xBTItb| zC7{>*B0xQc{i?YLTXaNg^jCs>?Jr4a6lLkw1JC(B=r7Mip<*gJE?SxHhROU`gY3UQAVDP&isq&lcyi?7drBXn5@{XG(iB1lgB zA=10RAB~-Fal(VhCc}uUDfD{6k}+Yw1W~}5A!5{k1ez)y3L%9jP-ykQk4nd4z6%JI zUe@I|li>=3L8e0Q!B|HFeGS9j57Z>=LHrcwpJ=V>H_^{^AW$N$|B-6*lnquZxcohf z8TpFM1=a;DrR*0;1FHBnrgQUfr5f=Amc;B&>Knzp`HJH|^OG#_XPb7s>RuVii*_w3 z2y+gRm>XI6_Nm!1|I|HE^a#CRatzyR*|&WIb5;;5|At@-)@e$q{`n>@p|l*ey*BR9 zna`{SgKnthxJcupfNTnYTs1?p_KnSAS2Pa@*FZZI#pK zqIN{KC%j=qsJ^z3@G1I+RwKe$CGl!TeJFW}UAW`$Nl7B<^;w3&vyp&>iDq*fL$PgE zI@+Pj0GelL??d#)83blK;4kYtSo-%jn5utVJd8VON)fdW;|fAN9=!}Ok>j0#-Us8t zw-s{FG8Ji1?$H(LsI(hdA#xLFC{{JSSO;tG+VEejQ^5{pT{L#j9#b*n>jmP}Nfbo6 z+gopEkUofEZmDg2YHp>VRI9e~YT)TOp^%dO-p)^}Oo=#$ipd#o{OBpG`p^$$f;$z9 zhevA_Rs|d*Vkwh^2&4FQr-oyh2;N#_r0!|o`lVBUd;>f99=To7<-^?dQECR>6d@_s=#0WZu$W?&3;qWq@Dh zdTGZL7Ka61`5F(hAiDRx&|HZU zwzfF09P9I+Cu8Gm%}`~>M!vwJ8@!BqK&`Ty?v?aB@CbA)UD8OzpQhf@^=QJxPW5^H zQlo?r3ZtALwDRB@hsRWN_t3PEfTm{K*Pg+H`~?gy0dbs7(P9NXy~QT`iS-XSC#f-Do`i%s{RKmYB#^@d8@El19%f}^z!Sz z`Z>WT!gLYak|K&DxMEmW9HBbQLof_uGMO+%Bf(md;42ZoahB6D20h9E(Us$I1@C)0 zo`ef94<30xqCmfQRYu^3o&^2&U{sLG*-PFV&l4NJUvNkK-aU6AUC;U9>&FVQ6kT5H z_Lu~+XlnZ2h1t}i;KTEIl0wAt#OHV_A6^pGxqpd0KwdVc{y&|)1z1(x);27uA|)l= z-E3eJ(jC&>-6%_249Y;d(Cw<(_|B7Wwjf14b}~iXLti|7hmF>&W-+-QlDsYF z+uKLkd?s$`c+Th8TbX`K-KeXZe5pxGUT<>S%*(~Xf^6zugRUW2q8ekU^yB~&#CU;d zM%)s`E3s6ktMmrGP}oO088-dhR%L9PYc5VtFTwS2zxJJ*+Tr3}4psc z!wEy_0k8eKg-)ZZwbb$lB%Qg-p*IFwchx0zT=f;L>*WQ|#qSerk8De1m4kQ=TBX=l z47%1#do&PR>@F0?N-c@K$+HC~m^;7S60BRbwBxz&iB>7!9@UvR&m5tW#Uf`!c2f#2 z&W(oE(;_jwD=2Zw75nsx(j+mPMqnU|1`JJP8kRsY<(yR`(- z_k&nKPHE)>Wlz?#-VY9n@?7`qnvzGO7r57(LMI2`ri=rg2+8Nd);agMgQi^$FE?Cl znjJ@r(8tDnIPrw_*~v_jT;@&b7m%lWuV-Y+4?}YECWu2QySUWj5wMQD?h)ZA~Pg%2)5)4p~loF#^-_TC$Zw z7k+`1a7&oz7@BdNVI0OV@5ef10*Z+xKdSplLMo+M>@QKg-SpAeUiRg1(xkUaSjNR~ zy6u#)@9EsqqFz@;yW|P-H%I=&C@9-eb$#DyG%S)5LmCezNpC$1XwOI4>N1vzB6%xP z0gTnXRZUrSoF9BTGy+?R8^~hp}3-(|Pv?BXcikZi?}^IdYAEk)7g18W(uBEh(tma_k>iLHyJbrYD~&hWIj zC)Q4x#c<;D_x4ZD&-@l3l*m@J#$GXb6^W?wu{!d1lW}ED;xeiSz7%u2{aP%h<6iRA z(%2bVip3(-z2z;=p1Il1vo~BHX+JM31|}=yyHHzNY+Plrg_^@eQIY0JYem>ow-n~our5dHT871F+zgfiH-()8xD3r6`7Vy? z`9c=<;o<-&25ADHp|nxKO^ z^(CR8hqqvGKbpKm**an~HTa^9!N^obAA`M45UAQdl-a>NZ>Bp-8x z_ytFV8zD#-rU~;eOoS1sZu2rJ?r|i~c6;*A(%$BU#jjx!#jBL1S|@X~RWw>3+G{wa z&S82H=+uIj@R{|t!%bbk?TRE$XXdd;qi(Il!R7F4Ro~A)HP+@{n6BA6O|GJ=PM^z4 z^2X2qg!46LgNLYC@{W90m_Y>MsNq?UB>D@XFjFH)_qeEW6bUOkELu-ycV+LFY3H;S zQf^$&ajFGN$n?yb3Y?9D+vqZ*UUs>I>l3nbih#~)#Qjq3~yg=8sn6F!}DdKhv##4OcTod1bLWvU*tfkup z0W88BzSa*&W_qYACpYL(kzEb#qqfDvsbFrWd)o$?QFDbco%12u=PFXXZ6-5`Y~7P1 z4J5dO0gG7+mma=Z+7#w;dsiy3oGs|u!+cE@9VKN4g}gRSreruGG&gIU@3gqgOC8UL z5&h5LJ_T00GEp5^X)8?Bn3#=Ed?a2k?I%MBxKlk#TIODwb>0&5ONc)qaD-3lh>u9{ zG@wk>!45Xaoz^l|A)A2BFfH-*K23zci+S+@gOL9T!^d`kDs(H~ohcZ;>Gec4i;i_E zRkgB$@mB<+afDec;HCLbyL=UcN+76YoBe^WbIB*8iOLwA{DL0C8(ZX`Q|d<+`66RH zWSKc_)(gb6X$ZY_VZZP;wh5K6nC}IM7F&o0SZo%p-4G>Y1}Kl4HWw6UR~KM+V8RGB z`?SG>1iRv>6?m_yI}>^uwZY^;7#k=VrjlC#PPVBkeS5q4%FO=gf;HM-X3q-KMmRipG_}3XXF>YWC-%hhXJfqMT*frzx@IViM;= zjSkthnvr*JH>XJOBt$3MBNL8a{x~EPv_hPOb!-uBWmWj(%9w=)x}Mq`*+3!65v6WKdZzV*kfza3csqRnRks7YNCck}kkB`;ClqlZ~vZp07GJ4aX zN4hs~>9{nvMAlNfw2|x{DEJfMn>v-xIvP#<6?M~kx#5Qam6^8OwvoU&_xzh%312w^ zs`^i7asAfHNl?b_4MV%sHmYjNA8RSP%uglqmh?V0IK(X#sw6FPiWUy-(%PsJ3DxQy zaGt}g!Q@JW?RFe^dQRv_WF>jN%|?%nj&iAFV8mua>t1wrXs9#So2baGXRLz^@zVK{ zB7LJ?qpo5suYe*VaKI302Epa=^9FW|0NrjI>GQ#t7TGagN<%eIM-vLN9Lg5a6)WY! z_@fz{&>{Ie79HZE?p8P-DRsx{Hc##(P0>zFv;pnWWH*bhOmN9OG+`!#(g~USN^Aw%4 znJ^FYu=ckhWsa(%E@gi7xeXRN7Syy3ziMV;4$mM)H_hVKA8Vpw`x$p~$%N)_pa-9}iN#lg zqYLdzfuV?1%Qk)iG~1*w2;TJh8SJ5?C+z z0J?!3P0}JCyx)2c4W@wF2_ZD)f0BR>jojtaGk~VR<=awNsCEZ^N8AS`;=Jb1EhGJ6 z7c^m@1BtiXB(j_9Fvt~Cib?iFFd}|cDy)~etkLKbkKfPA~deeaE&rv zEDDET~dh#{*#jDf#%ae?V+LINPQ<~FxI1@1D5T{xl zBQ=j_gnbrVr2J0NGyf7U>i7cc<(I{17}SDU=6a>D^LS5^WpW_4>t5V6`_HZK^sKH1 z^h9R`te4>ICRUgg2D&rdZC%PA7YHm(W2Dll&=MAE9jOd^8|B$(Aeu}B=Qx+iIw!)-;Q}fle2Z(yzHq!N${FJ4{Sp2lJ*tE2Y z7*0yi#hS(ot~#c7RRik1MCM5elkM6jTBC-XCZ$Fwoy!nov%_qrUnq1bL@3HAqTx`2 zr5CJ0csodDGAMRXXT7&vd!0gC1xr!>y?$Xojg8j)r}a6Fwy*HqE~)aid{*#;(?t+r@BdPjM?z{H;)3^Oql=<|@npop zM(YDKu^(EWmVk^_Q%Jg-)CiS#R9y2A5=2>GmMO0&_DYIa(F;}hbu{nzTx1>&n@Uxm z2rdWm5%J7#$)ghJ-bRc!C!_G-TIg76)i{!Pk+#lP%n}uSx*Cm3yRUd4f-+Dsn=RM` ziv@Xdd=`0-5m#GRbU=_%qHgZJv4}aP z^J@d``a2n`rWr(+)TwXeO*8H42K2t2nP9iYp2=b;ytA7~Ppd7|FM1H+;m>XaR?ygi z0C(GL{ELW6rh8^eU{UTi^oMy1tv)6q`7wTFv=!56SqUaP7}0)&F`p`|!k;l?4p?>sd9^ zf2J+{!&mt~F|GJzWJKOb)9~Aw=~+rC{_9Ec-;cN9m;fTtFCgV_mzEh>iU>tma?Fe>`mdA12p-BO7T&Ntt&s!uwzF_$N$s>zYjW$mYWvju9lE zKZz)V79_#xRogg^2Ry#D`c?`qf+_kf?k5!}37730pfHjkufi-Assu6LB9b<~xLg_d zVUet1i4wD_r}KiITk2&E#*^c;=-LfD=}4Z4OWE3)eWs_$tEaAb$skKAkJa~ze9sL& zuXnAdTe(%fcyGD=>0$xNh?n_n>+&lqB!zzVP4Gr`FRNPM?0A>}jnV0MW9XRs8BXuF zoT-T;+v*ZOG=8?Fg#eF+qZbmG3(TBN`7ONpTzHj2iV#iD5UjmzQU6mr|J9@*5c9vA z`B#hlRfGSHp7uxcK87O*HR!-#RsfCwu@Zt90dU|K90B*g5z`o1{|QF`VBOzv1R?vw zm;Z(%-WcgUkn-Rjy2HOoYK#De@NbgZuk3zTck&FSmFo!HTY10Jdx*)Y(Fm&qBtY33|6o_Ck`01`mJs{?5obf(c z&X8ZjTUmyT*pnana-6*0T4Fnts(x!E*vk#c*Ih|J#;}uwQZZd2j6aJx7|ZWt z5UoDfH9G23b33%@Y#e}@aE9vr1y@h=}@S-ub|jS?c;=ZOXA-m6X{gZeKScr>SYW!Pu+yDuzAfUi+e(U_Whm06IIK;-J!-0N;3x=8N)|8hbps#wbB-ehnxW?Z@ zblbUFG{wbXrz@dRp)(5=%U%Jd3Ou$48VCjI~1FFXgba@s4w*x)A0fOxVj{WdI z7)bvYUJjIq8F;g@0PhEkn;9TmvIBO&{{Y4f#|q>DX8#wC4t~JnK>#++3gG6z_sjrv z_<)1|(gp5?9pEdo09f6xYk&X%27?IMAIb;tdx7%6u`&VavjAxUX@GxW{_FtO4wMhT z`ybxS4{1K+3)ub>Q~y`3{?&Z{9(n(-sCwLBL<%3W@Wne}28z&Vob5Vp6aj20mY7$r zl+rv;1m^`pAoQA#mbVs;4N->I2(^lfo2JTiKnGBBL?1FfYKe{k0K zScMzvk~Z`e1Xg`UwYVCw9prrHSRD zv!DCcZFWB8r(?2bfju_HR&^r)w^c198eh+)#%ieTte2B4G1Q9|-x=LDOZAVvM89gu zbJ`y_GM{5%>!dP@zi>ReRyQ%*=JCsJQ^Ad}DH7IJ>A1n%Ev1Gdb!l6YND$)_>Gy^{ zbR{N12`VR>5#z%rV-w@6i_rkSo)zOE^4X3x^o2Hz;Ua`E>!(ABs%hHA;Rn=9ZJCZCCtg^~YCe{p>OXoi`ehb_0J);Zjdpj=KjiD|< z5a$e=p`it{@GN1R1=1Q?%WR(u-u#Ro${M;~ITXi9vC0jx;iZ@c99ui?ThgF45m}lx z2)6fzSQ~nTj*5W6jf4p9bMtSM`qELQW-Fbaqm?)HqDnhIXMux2xOahVPl031E?*KG zAR7+28^XWGH%xGb9e2}(9}{`WiZu;3?I$$|x{%w37U>~mr!Wp=62j>g@eK*%|5$;j zWQYc7_LCX5jt?|cs?H4SGdZ*I499=;Tbi%&$7o?Jn0rZK#hc@&IHi`7dJ)UYI7Q-j z%uv2U_c(C}$cv7L&I;~nCgo&J$lrU$r6!SfevYK}h`+$}dJ^TXDDt1?sK4NSFv~yI z(*G~`{vUJGe^^T&crgI9&-NFz4+3lbuWRZ51==TM0ml8`Yw7>2pK$*L+GqL$+W#ea zJc|G2YVcQt8z#W@00hhq{~gYqP4Ze4_~dOjOvDG=o-dgx^x z3qNvkK7Zq3Z?ZYmVt==#<9Y9N{(ZJBdL?-8xe)TiYjS7QA|%!q1us(S3FhKjMMqJE z46O%y`Vn^A_3=mIHFOC*WD+_#8jN~deLvj1d{5{*?<{4KoY;y8d9!+nj!QZw0wA&ll$AbFjQ2v3vGua< z!A>k~M=I<*c}~b|9dDE7M4O-WViprhGu=Fg97gT@?0aUb`Q88tH)WMFz<>l7>Zlot zJw5?~-;^)axxFQFn>5TX(6$5h)l1@AA)-~X_kJn1$WFu=&yZdH&^?uegn}66N1R8THxXt_*8h zGJ~0Ce%Z`Y=}*z`y^Zg*st=qN+jclS(pv?2^D?G*bMDjH^|nC^qzNI3U0YooMKae} zw0#!ew!V>;#>$>&*JI)xdHX6kpmKkf9;3)d%!ycIC&4-DEea89s46XG;a7?ag!06T z$EK+$mB_4;XY*f4+=+(vKNLTmzQx>?s+t_*TbIRJuLGVSC1j;47k%V0RIMdfByfHk zWbm@neykYdKIHrNJ008XK|?2TE{0D-f#H3lcVM?+_~;*TeZ85mY%xyA6ghGUG;4csxO|LfHTr;rY1~ojL{h~i4FgHMS>5a+9-F?qwDW=fTMQXSb=0cIR=(u$)vzo2 z`gb`pvkH8TyUD>asQ9{c*)7(eHbYb4H39uC2q{ldT*+npcrbpT!Q&r9AUP>Z7Kiwx zp{dnWbrijU-gS#@E5$3ipqv^hhWHrQ@6S7q-GiXc=NHykGdZYmY{=xQ+Nyd?o`YkU zn!sF^g}L;#=0I#_%!_lPWp{+FqGSm?y}E)WbYiZpGWUAowS$|WQunEqMdQVJ;vNTj zXsgjj2~GprHO$+dUL6nJyB}|3*+#QszsHPGy@<{hyXhww!oON_9A3?4q-o^0OL8{x zc1BSJ&OUL3*=itr$H{y;%&RSX7quq8y^7Q}cW-%BE-J%wx3Qn&ZeG|#(0V)U!@?Ut zaC>w+Z6ZUP@d|b3{)sXobEaBS7Gdo%&2ol%qs$N-RaC1`b&bRz#o=cKxfB<=QO2XZ zj~fbHrcdZTJ0b}mtD`Scagg$G(=l*_#RzW1TfJ|ml5~P9h&#%LTA%6m=U{n;CR9bE z$*DKpP&M!#R?klQc`U6I0Aea zuI0O+Fak`ps*j#t6RyK(N}im-Jy%f8}ZD0mTg}T^_G%u{-vZ zRf~bTC$B(*ME8rcbrzr1&@W0j0t9rGn(2@)E<;-aP8F;8oE&s`m5H~7!$oSujh{%j zI>)tS7~AbMWHppmfDukStSF5bO4qu^~Dj$D#R+7vxN!Mh5b(>)?;LftEqNbm| zLGx{5k0QkFJ}dE>=aStU{DnLuN&7PBF6swAe4KEpuwkZrRCAZY7XtdW^`G`8%REzc zw+lC0Be#P)=O!c;2Xieq<&Kp{UscYB7Fxg(i&s-u6f+1qmwP|Aw(xb>fYHlab>d#& z25aM?caokc?TD0qMSl+E9nA|7%=z|NMpZJ6|1(Nqh99uo6jFeHt4ko^jpbM5ll@$( z3irK;_)3$#01CK+rUDatQRGD?*TWGvvh-NQ(&TEE2m3m8a zLTaPtxTQ{IJq3y>R>hBmS0dpz4$U!^d)2H7i+8s34xvw3URbIzn)byUulDdAZ*e3; zjAG@M;m=LYHGis~E*z{lq>{U%+ZJFeUoc-)HOi|fN74}5>JT->Hk^*{#Jz?aq8iov zV)BzaG+zUWi*c;kqG2Q(mTT3~$b)&XghJgn4@$$?8jG@I-t9*B&epkQXdF#{Dz&lD zD!Z<#VnMsne162LWT4Mt`rUJVjEZIKV?Mv$s~iYtB^@;-87*-&ecSx{`^GGRmSK_- z;SySY%oX?s&2GA^f%NO~ssJVCBsXrcd#xxRUcsLz+ZRTTNH34s}&VJ4;NpDg#F6&JNrg znj{&6mS{IB`5`sjc>AMCX5?|{Qe)uTeg+agjCFMkT*5aCg7I~LgyP)+J zq*XF)5Sgu_bH}7r@ZLhiB=B8?ZGq*)Ggov&B#u~BQY_1Md1W;!2wU=LM=Nnu;;i~rY?3m!4A=1#2R8v?1R5Z6H%j>$}+wzErXMPFfPwW$7Ta#jQkF&^avWvLK!Sl(OMOD!R`(D6F6`1AW-=T-0l+9i8IsNI5;%^;GId!)= z?z-;I4REk?n-k=}-4?H2?~w4}Gr>-}jg>?p=#cS><-LI5B@BF>h)2lKZCiJZP9hxZ zY+Y)a&cU0!ysWH;t|~FUOLA6Xfuy-*kz81TWj-{ct8?WzMs99JlsM_IvGbFy)umxX z_d>(5N-4zUo!oLgJputiKhow?msyx*4W!A1!F_K_`m~DNlhM2wSjG`7dPp?wwdmq6 zEvefqYeJPLx5+yifjM~!^%Z;EOI=vpNnRcP(+oANkoDf~!>s}N5kYi=rBI84i@h1C za~B=KBj?HzX=jQ3PAe0WmJ0Kg;h*cLQ8H~IDY=julaQ32MA73M(XAppb2SSP{y-d0 z1;^pQqc6$x?cnR;a!po=SZ9%%5RtSN2g^jwUKV%l8S{mV&CT(3$BXSRJ^?@c2yWkX z)vv9{E*P@CSIRw=uPucOMOUx3Br`TMspD=a&v##~6;Fm*gcj zRIN$!%1>B;GthK7)k4LEu~-~Yh}jaDKN&>Gep0!huE4+)zo$mxd`k4vE3MtzqtnsH z=yk$V_4nBLOm4H;2GF&-bbA$PYeG%9rz7`>`l{Z@tdVb)GA&pp+C7_R?2;7ahegRwVhNiA%e4piL5Vu{dd9t1MUcJ~T^jO=*vHU=y*8>? zd#6#ba*A=`sNHG83E>tJ3FvCdWqbE!Y{ux)noar!9X{tUTAod!n#NQIh+S0Z z-z+f8B=@zoP|UIEF35@pE$iZ85cWE=f)frpef=R16?pKM_sb4KBCL-U=_Jd`ta4p6 z^k~h^tsT)RK9-I^m7E4l(Vb@>ahN!CK*^ z1qL>!%^vpas&SLS5T9}93ab|prPApG5wzXD=voLV*6Gkzt#9=r_Dwd>E-37|pW zHe2XYH)W0=v;F=2+Ex71TWrtOTaNMU3Y62}@{tSB`*^A5Mj71i=#Hq>A$%5}W0&w> zMWCR(jYC8sLgibWvTqwLctoA~Z~b!O zFy=ft&oT&nFeMP)y_~%DnQA%D-ZT~0NQcL+0+m#JEWb~0HBR_(amFfoq|$iLd+i1z z$2a7L`&`%Nj7Rolc|i8dO|3h@eDz++YZ{Al?S&Ux#gY+SbxS~-@QAM0Eg8+vHE&cn zd){n>B;<_l`<&RZk2>L{6jSLqm%3k7_9q|L_UewD3~-!+hg|b`@0+ia?^=0zo4|9^ z3ur^TjEwE3c4C^AM$TTVlXPD*67z0dMRUK~TIkmdNZ*~$9pWFdTn<7>5byQuEWh{8 zye`B*{6?mqA5Ve5yzJQ-;Knhnp1sgwp6l63yZOZ}^L%MkUIU_C2SY`n-54y)=&|Gv zhiS?sLSOezO$8cNh127v(Nxsk1i!o$JB|2)gRPh=HZS@ew=(J%6Rjf5;?VDXC}p=~ z-z6uQo?VW|eUk%#ZrK)9;7rB$zGh2RlY(e8N6p>nEVCgr=1`KD$sk`@d#iBCy%&uv zEW~4RvvhFpKjW;^l*GswLg>j=M5xpWp9ZNEL8n0#?&w?wxj_|P5g5u(;uu*(o}nSt zze-VJ8Hqc_2`oODlfaA4Z=L!n75(*dw9iV_TvD*$6JBcNBNZp~Z>-&K#`1lpN|K3l z%RO$6KQ8Gr!*YWZk@2(x(F)=H2XpYfJoO7(^{YzwNIt-0x6BgG!Kcm|CqQ+NhzU>b zjg}B}U9M|f%9ua>iFwM#c$aJ8wq}yXZKRHklDj~z{M7uZ%~8)@<2}VX<=I6C6?fSE6$7)uFH+Z?&FG# zLd%YuF)QQVbrQ9T3T)wLZuqMI7A7+?^UF3UFUA8gRAb|dM@{Cq?MdVc55(}EqNys$ z^Jm#_D38tja7)WG-68jP5{4`?ljinr)OG(myKxN5! z_r4~fa6Z;#BJ)sga$U?KFpde*d7uCuA-!|$RFdnOL-?m33aKu3Tx6j$)iEBN1iBMV z9LAVOs$82GtD`z{jQgvZOg6js*a=U{SrT!_xE^Pj1O^LEp53cWHuD_S^fk zshAxgNgXmqXNA@xTXFpQS3|7UL>PdU`xa>Fq$QAww#18F)9oR(01qw3-jg zA;p6-jYGM=K^>cZlx)S0`U?vVNAW(PhP?Sj2-<5J%&22xn`e!So;jbRNUw2du3JVj z`>02;g+vS{qgiWm1=h(+B7Byjz*q%K(Npl-tfp{m8N+yZAlSHUv$T)o2JA(F{q z&{;&?OjYPf=$m*?xBEkcUvs)}2DSEiMvJJnjgMfN6Pn9U|4YrJuvKHj& zWAr3@ic;b5nJQAyf?8Z*DOejZ&11Vt&t=Ok|I_hBG3h68EfMk zaE4IzBy?H)BDt8Y*`@)Vq78dlsZpfq8RXIDLNc*qjBkk4T?^sMv1iqxM$f3b#H~YT z>E7A~NECEY$(Ss1+(>}apPJA0n-sE7J!!EEQ!aAS${!W)CX-X6X%D>RR9weAo(P&p zMQl{4HNL*k^>nL2HG?u`b7q{^Ovso=$t1i zBPRLJec6`@C1Qd+4UyxWA+?=9A3iN1491BM?BiuF&}DeSU-e}&j`mZ!Ev{bZ;5PnM z#vb`}nVwkMAo;8jLNRWklbbp0fY|ox2Rdn}?l&#PVXY_SpmP~)xnaKQpxM(+_qNmz zS2G!HwOH6wPncl2mi3Yjp^}iQ3gQ^r}upm`KxQII4B zsf+`WlRJBcLuGWA?((O>faHe#&V|7g(nd#MHy>m+4C+;?dX*`L1M=&lPfrQnWV~X* z5a%{=;5%AFrE^Pgo!vpFgBA0{1@)9Dn4&te?cXte+r3S4i-Vw~FG$>ZSsl!Y*d>m# z;fWDHW>P7j7pvIn(yjUyGi}J6`f7BRX1g{2#^9aXkghj3VOIwMCQ@}OCTSgVb=RwB z0zHjU%E1oNq*F!pq_V;oiBg!=neIs4or-zH=zM~oAl6Ki{gRRHtn#;mKxBk2M7Q1x z2i9{7=w;8bj>$)?u|DZJdb%84`nB1(NI^g|Vvjtr!j62YX%pP^v9>QqUfevYvB!c9 zgRQK*Kjmv~Tw1JJ8dQn;wg6tI895#CAQj*`7ha^qOsb+*FAhE&^5zv`9YApGm+*E?9%iZ>{O~5J26pF%~C2-t6HF zeT?rgu3?9VH=@EfrDplT;vHPq;4HJ8cu~sH*CXormoK zH9d?X1-aQtMrpg)tEy`v%Xy+>sp;)gxpS?gL>c?F03L0zSD=KKW5jHd_C*t%*di`{ z5r3pG;fX22C3=v>?EQ)(CALP-4Xz|!%hRw~%pBvh9j^;JeT!5am^~0r!j}pae+q=40gm08?)5xIr z5;bS*2?o_#pC&if7Er8hj>I-;7Yt--eWvZT!W&ru<1Au?CMbqyaI?o}ENksui2iKe z0P{CyGs8elhy3XL9!z3_zkCuwnCB#784$KY`z7Q8Qa@MRaUg48Lz-=%QtR9C)af0m zCcF4gWE&;b+~p0CZA<;-oEetUu*qFljGY>R?qV$~I-I%Ns}e*<0tgU?av7?zdYzN- z{x-Wg$*VZjfV7a-5USFytsYQPzELUgOlA&lFOXXCGpRxpX7HxQD;y zaaCph*sCe;Kip5QaSYkQD2US==xH1`Vmv?AfByxuX62nC?iB_}(~E^CSOL}9;;!EE z(@{v#O&)sRB4?WuSU$qmD>=>6s*^%McaYPTG2X8~Ih!}6Gwl^wxlH?F)+yYF+dFY* z7TsQyMBhXN1Ag(jHOav?>|np)uK)Yl{8Ji;*&hKg((yB&9M$#??p$)coC@_w_iNlV z6`?9rm_)?i!Ze0BYkgG`Tx$Ea*JLi7qEztmd(5*G{!F7atNCWG%JQ+C%0SANQ5tVV zn4Ez`tYZCRjG=mn%u~p15vKj|&YCsN^N@7oshA#_y4R@|P>R_vde-hpBKJoQZRov? zF_UUJ=NM(duI9Pk#q9N-H+VVG<5tUGC+_`!ACAoVcV-D05F&tts!m_I-8u zx;9VRDvC66(Q=0Aa_q*fxd_#Z2o3!0hPxl%yMh}V@84|5f0gE6&i;>!`A5Jv zfLO-_1hk+7Vu1jhIv~^rJBaOn{!8x!Qy+nw0hxzm|ei z_-Zl>AKwN!&Kr44+5m5dS7y(m{B(nbAfM$XbSFWEx=_(cnMriZn@9JcQ`yV)}Q`tSqC)=>YNuw-#mz%%&w_7)~H zKBCvyX4c6~4wbxF1=CL&WgHiq=lquFh&eauRJGH-OgM|(m`Y9U5BNnOn%R`R6ckV) z$!)34cluG~myRC|HfrzqB<^*sJhoU{ok-T(D?auUX{fv`MmZuZ>a$M$M^7dtL-=?n z-No!;!)6q(keO?0xOYc6p8*P1&eO@sHF$7Ut{a#U9eQlEA zuwFUuFb;E25J%*ztJ<*!yvSr?52Fubyoh9?52I{iDf)S1ya>Hy?jpGOTm40&sd8HU zX|cAX=9bWA{n;qn(sOH@MXo4aleqkR$M@LcbjXlmp7yDz-c(TChb+j{#kP@NM7I&@ zkb6lVbW1jf?#`urY1B^qQPxcu@hX}qo&8!iG-ykBKl-LUtM{3&el><~hF*g$8@>xReK{z-m?*847IiNaQGjlg8c&5eL$=B-ptn3`mHJ72Ko z#95Z+p1FD}KbY(=jeLQ~)13f|W#G*`mbIY}$;_}iymJ3-8rmqen{t*^mGDQD$lzhO zurDJ=67TTVyNtO-OijM3?@yR#j8sG;9OGBYAv_OXR}F2qQ%{ISik5Vpk~I8jb?-(i z5Pe!IW4dof2aA*)QF2en?Wo!}RSzb?*O(XJ^1d6N0TP`yri0Zn%D}e6R}&r~Gl~AT zq0;wZ!y}2PmZKpuIUb=SPH-c!e`lj*gT;-IUqJ^r)U;FaPfWe-E)D)j~Za*wcY`X9JffxsJ*|Vw1qX~;lT2=M4O}PT)tpcSl zbJxW=G7^}{O;S?vDIJ|B+?04Xm^qFEuZX`maHz@AOzV`ch1gT1 zpAK;@ZJu{t^G?l)3Wckd(&w~&gEyI5We-TS%L)Z(oG&_^g`Jd9fmei?78KRx(ayN#vVbc6w^@*nVS>oOI>> zONPM^Yvx+u$2qS5Zj50?dxk9>$rY#gzv*c&bIe3$>a#VNXHq4ujNX9Ou%4 z$I89&SLhSdHcC+^*3X`E`H6VQ5j(HrnY1jCpNvhIjfI;_>q|4vQgw2gaJvl-LFcAX z(TtCN@&?taY;{=F6@AYb2|p?3$(dN_E_4_vI@yhRJ(^bL#F@zQrEqSMgh|`6;be;E z!qhon$T(+c9l#FawW=%-x^)S+-@c~LLASeIN*ZY`0b!(~923AlwX-jm`>7qt8!)bV zZRgcoQo^!v%(0qeZ$D&M(4{%6R&bYiqG&BGZq`SjlAhgRIF}tFz$A^(|LoXg7^Equ zSN^VMGp=iu9-$?3a(%U7*E}SL@r3L~kGVv1fr`V^YwWfosTi4zRTSPAidZXgogslU zWKcj&&ufyPr3AFga6U6s9@p_TB!?P%Bo?J0VDm+RKV+ruS7)VCxWHbqbZc;=L-diU zDrg~Nh>%XoRfUw2uAqy6`KP3yffs5gXp|?Ox`N7TzS>4kf}3pG#E`RP#|K#Xb}M#u?*=Yc+$3R?Z3?8^CUf_#rsE zAtX)$WL5>qW6=j^2$MVVG0m_d?S{CB1$o2~kH6L|-embsMekn6=ay|V0reQ>q6nsH z?+se0h~t)sN^P~$QZN1~LVn|lGF5~V(cw{lXXgsH=jG*UR*M_7o8eP8=whwyLble3 zi8LH;tVAC54Sd6DnwnxZhd>%{>uvNmOl?w9_KAeU?zi0Y_X}UNNvsD6mbR{!4oWqy z>+8U!E(ZlP*iPGngBs2(EHx4z>;t*{@4tV%n{uF>Z9`GnNZ^KK4(V8>S|w6Q zoEcGTcybSMN<(=5pLT)&c2{6zW%>6m5MVw3Ya2)j?9>Ql6bMy;{SZCy$4V&YsAuQk zMhJvV{uO`O#ewQ?tG_7altP>!MkX*L2Z#;$WMc-YGcr;De}Aj~W0wiUVK#I$0FKOK z`jsoNPZR{s{c`}~5(_UyfB4uOvo8a$gNG^6p#&Cca1QQz^;0^IVFCgR? zD?t7>Cj2F1X9sZr6zpH$5nBIC#>mJF6!Lc&JD8CP2v_zf7=3k#7DM3 zdQ1Q*^LITa4(10!=kK<^u6~oT1B7ybn*N*Y*To}Sb~YwPz&+_Pb-xc8|Zym;i?TV?AIW{ztt4dJmzZe@hRjJ@!9rnb{vgQ~j<7W_?`u zKx421VdEa@0dbWd*ULlSdQ=CDKs^KW+uv;gy@$xzzvT;J1Od^Uf0qHl@&F3{Z!#uk z4loe<`8OFOh>_)wIsj~ecwoQjF|j-tKb8TJ^d9xAhdhALdVkmgZV8WM?BK`u!NkJ) zNBMx81p{sok8Rli*Mi5ghhWve%h=gj{>TH6u{|mu2*mW@0`Z&egY5DBf&lNQ2dAfp z*I#4iLH2kYfj}(GK!CJIdaR7>f8+sF>K|ocWdy<#KDK3gtOxjjus`k_%`~q_(Fp_@HgOwHNyN~Jx&;vav}guMS}9uKm|eFF?Q-aN#W|4omLk&*pT zJp+2o4@=BrJ-`+1v5e{Aq<}|y%z%r}Z!$J!FzCUN>7RNJG9WDGZ!&gZ!~o$qAIaDm zAKx20D+l-?9_T;Qd$0vUdOnh|1K|fB%Q%3A<_{Sg;Cl4P_Rlo{Xb;9e$_GTFf83t| zJ=Vu<1jznF`vU9W})`_ zJkA&B2S7N|-)#ZChr<&dUVn`vz!v;?3_h&2tbgbM9%z50$He+@Uc>L{0W;g=mbeG3{9N5$RvGzR39?_X92Ns=<&e)ca?uVy0doxHjuxzY(OeNOTdwl3CoDU{U5Br;H>}v From 22af5c8383c149298d8444eeedb66f64d29bf0df Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 10 Oct 2017 09:29:25 +0200 Subject: [PATCH 039/120] Quickstart: BigchainDB Root URL from text-> URL In the Quickstart page of the docs, the BigchainDB Root URL (http://127.0.0.1:9984/) was being formatted as text (with a $ in front) rather than as an URL. I changed it to format like a clickable (linked) URL. --- docs/server/source/quickstart.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/server/source/quickstart.md b/docs/server/source/quickstart.md index 62a31fb9..4737d5ad 100644 --- a/docs/server/source/quickstart.md +++ b/docs/server/source/quickstart.md @@ -58,9 +58,8 @@ $ bigchaindb start ``` J. Verify BigchainDB Server setup by visiting the BigchainDB Root URL in your browser: -```text -$ http://127.0.0.1:9984/ -``` + +http://127.0.0.1:9984/ A correctly installed installation will show you a JSON object with information about the API, docs, version and your public key. From bb9e26c6943e413cde78f0cc194cadfbe19630e1 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 10 Oct 2017 09:43:53 +0200 Subject: [PATCH 040/120] Markdown-link http://127.0.0.1:9984/ in Quickstart --- docs/server/source/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/server/source/quickstart.md b/docs/server/source/quickstart.md index 4737d5ad..63ab8643 100644 --- a/docs/server/source/quickstart.md +++ b/docs/server/source/quickstart.md @@ -59,7 +59,7 @@ $ bigchaindb start J. Verify BigchainDB Server setup by visiting the BigchainDB Root URL in your browser: -http://127.0.0.1:9984/ +[http://127.0.0.1:9984/](http://127.0.0.1:9984/) A correctly installed installation will show you a JSON object with information about the API, docs, version and your public key. From 8385b7d4efec7b0293d004456bd1e268aaad4251 Mon Sep 17 00:00:00 2001 From: Michiel Mulders Date: Thu, 12 Oct 2017 17:23:27 +0200 Subject: [PATCH 041/120] Added Link To JavaScript Driver Docs --- docs/root/source/index.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/root/source/index.rst b/docs/root/source/index.rst index 1dd71003..455cae0c 100644 --- a/docs/root/source/index.rst +++ b/docs/root/source/index.rst @@ -58,6 +58,9 @@ At a high level, one can communicate with a BigchainDB cluster (set of nodes) us + From 0a8bf89bc67f9278ec5de32a1e16a4be4b545292 Mon Sep 17 00:00:00 2001 From: Shahbaz Nazir Date: Fri, 13 Oct 2017 23:26:13 +0200 Subject: [PATCH 042/120] Add workflow to retain Azure storage disks on PVC or PV delete (#1782) --- .../node-on-kubernetes.rst | 25 ++++++++++- .../troubleshoot.rst | 33 +++++++++++++++ k8s/mongodb/mongo-pv.yaml | 41 +++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 k8s/mongodb/mongo-pv.yaml diff --git a/docs/server/source/production-deployment-template/node-on-kubernetes.rst b/docs/server/source/production-deployment-template/node-on-kubernetes.rst index d9b1437b..371ecc36 100644 --- a/docs/server/source/production-deployment-template/node-on-kubernetes.rst +++ b/docs/server/source/production-deployment-template/node-on-kubernetes.rst @@ -414,8 +414,8 @@ First, you need an Azure storage account. If you deployed your Kubernetes cluster on Azure using the Azure CLI 2.0 (as per :doc:`our template `), -then the `az acs create` command already created two -storage accounts in the same location and resource group +then the `az acs create` command already created a +storage account in the same location and resource group as your Kubernetes cluster. Both should have the same "storage account SKU": ``Standard_LRS``. Standard storage is lower-cost and lower-performance. @@ -488,6 +488,27 @@ You can check its status using: ``kubectl get pvc -w`` Initially, the status of persistent volume claims might be "Pending" but it should become "Bound" fairly quickly. +.. Note:: + The default Reclaim Policy for dynamically created persistent volumes is ``Delete`` + which means the PV and its associated Azure storage resource will be automatically + deleted on deletion of PVC or PV. In order to prevent this from happening do + the following steps to change default reclaim policy of dyanmically created PVs + from ``Delete`` to ``Retain`` + + * Run the following command to list existing PVs + + .. Code:: bash + + $ kubectl --context k8s-bdb-test-cluster-0 get pv + + * Run the following command to update a PV's reclaim policy to + + .. Code:: bash + + $ kubectl --context k8s-bdb-test-cluster-0 patch pv -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' + + For notes on recreating a private volume form a released Azure disk resource consult + :ref:`the page about cluster troubleshooting `. Step 12: Start a Kubernetes StatefulSet for MongoDB --------------------------------------------------- diff --git a/docs/server/source/production-deployment-template/troubleshoot.rst b/docs/server/source/production-deployment-template/troubleshoot.rst index 9099a60e..72e073e0 100644 --- a/docs/server/source/production-deployment-template/troubleshoot.rst +++ b/docs/server/source/production-deployment-template/troubleshoot.rst @@ -104,3 +104,36 @@ MongoDB instance correctly. More information about this configuration is provided in :doc:`this document `. + +6. Create a Persistent Volume from existing Azure disk storage Resource +--------------------------------------------------------------------------- +When deleting a k8s cluster, all dynamically-created PVs are deleted, along with the +underlying Azure storage disks (so those can't be used in a new cluster). resources +are also deleted thus cannot be used in a new cluster. This workflow will preserve +the Azure storage disks while deleting the k8s cluster and re-use the same disks on a new +cluster for MongoDB persistent storage without losing any data. + +The template to create two PVs for MongoDB Stateful Set (One for MongoDB data store and +the other for MongoDB config store) is located at ``mongodb/mongo-pv.yaml``. + +You need to configure ``diskName`` and ``diskURI`` in ``mongodb/mongo-pv.yaml`` file. You can get +these values by logging into your Azure portal and going to ``Resource Groups`` and click on your +relevant resource group. From the list of resources click on the storage account resource and +click the container (usually named as ``vhds``) that contains storage disk blobs that are available +for PVs. Click on the storage disk file that you wish to use for your PV and you will be able to +see ``NAME`` and ``URL`` parameters which you can use for ``diskName`` and ``diskURI`` values in +your template respectively and run the following command to create PVs: + +.. code:: bash + + $ kubectl --context apply -f mongodb/mongo-pv.yaml + +.. note:: + + Please make sure the storage disks you are using are not already being used by any + other PVs. To check the existing PVs in your cluster, run the following command + to get PVs and Storage disk file mapping. + + .. code:: bash + + $ kubectl --context get pv --output yaml diff --git a/k8s/mongodb/mongo-pv.yaml b/k8s/mongodb/mongo-pv.yaml new file mode 100644 index 00000000..15b90213 --- /dev/null +++ b/k8s/mongodb/mongo-pv.yaml @@ -0,0 +1,41 @@ +############################################################# +# This YAML section desribes a k8s PV for mongodb dbPath # +############################################################# +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-mongo-db +spec: + accessModes: + - ReadWriteOnce + azureDisk: + cachingMode: None + diskName: + diskURI: + fsType: ext4 + readOnly: false + capacity: + storage: 50Gi + persistentVolumeReclaimPolicy: Retain + storageClassName: slow-db +--- +############################################################# +# This YAML section desribes a k8s PV for mongodb configDB # +############################################################# +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-mongdo-configdb +spec: + accessModes: + - ReadWriteOnce + azureDisk: + cachingMode: None + diskName: + diskURI: + fsType: ext4 + readOnly: false + capacity: + storage: 2Gi + persistentVolumeReclaimPolicy: Retain + storageClassName: slow-configdb From ee6f0fa7ddd446c721a516933a147cc20182060b Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Sun, 15 Oct 2017 13:52:54 +0200 Subject: [PATCH 043/120] Refactored the docs on dev/test node setup --- .../server/source/appendices/rethinkdb-backup.md | 4 +--- .../server/source/appendices/run-with-ansible.md | 12 ++++++++++-- .../server/source/appendices/run-with-vagrant.md | 11 ++++++++--- docs/server/source/dev-and-test/index.rst | 11 ++++++----- .../server/source/dev-and-test/setup-bdb-host.md | 13 +++++++++---- .../server/source/dev-and-test/setup-run-node.md | 16 ---------------- docs/server/source/introduction.md | 2 +- 7 files changed, 35 insertions(+), 34 deletions(-) delete mode 100644 docs/server/source/dev-and-test/setup-run-node.md diff --git a/docs/server/source/appendices/rethinkdb-backup.md b/docs/server/source/appendices/rethinkdb-backup.md index 732323ed..dc33231e 100644 --- a/docs/server/source/appendices/rethinkdb-backup.md +++ b/docs/server/source/appendices/rethinkdb-backup.md @@ -22,8 +22,6 @@ That's just one possible way of setting up the file system so as to provide extr Another way to get similar reliability would be to mount the RethinkDB data directory on an [Amazon EBS](https://aws.amazon.com/ebs/) volume. Each Amazon EBS volume is, "automatically replicated within its Availability Zone to protect you from component failure, offering high availability and durability." -See [the section on setting up storage for RethinkDB](../dev-and-test/setup-run-node.html#set-up-storage-for-rethinkdb-data) for more details. - As with shard replication, live file-system replication protects against many failure modes, but it doesn't protect against them all. You should still consider having normal, "cold" backups. @@ -108,7 +106,7 @@ Considerations for BigchainDB: Although it's not advertised as such, RethinkDB's built-in replication feature is similar to continous backup, except the "backup" (i.e. the set of replica shards) is spread across all the nodes. One could take that idea a bit farther by creating a set of backup-only servers with one full backup: -* Give all the original BigchainDB nodes (RethinkDB nodes) the server tag `original`. This is the default if you used the RethinkDB config file suggested in the section titled [Configure RethinkDB Server](../dev-and-test/setup-run-node.html#configure-rethinkdb-server). +* Give all the original BigchainDB nodes (RethinkDB nodes) the server tag `original`. * Set up a group of servers running RethinkDB only, and give them the server tag `backup`. The `backup` servers could be geographically separated from all the `original` nodes (or not; it's up to the consortium to decide). * Clients shouldn't be able to read from or write to servers in the `backup` set. * Send a RethinkDB reconfigure command to the RethinkDB cluster to make it so that the `original` set has the same number of replicas as before (or maybe one less), and the `backup` set has one replica. Also, make sure the `primary_replica_tag='original'` so that all primary shards live on the `original` nodes. diff --git a/docs/server/source/appendices/run-with-ansible.md b/docs/server/source/appendices/run-with-ansible.md index e4b4a54a..70e4b595 100644 --- a/docs/server/source/appendices/run-with-ansible.md +++ b/docs/server/source/appendices/run-with-ansible.md @@ -60,7 +60,14 @@ Verify BigchainDB Docker: $ docker ps | grep bigchaindb ``` -The playbook also installs the BigchainDB python driver, so can instantly make transactions and verify the functionality. The `bdb_root_url` can be be one of the following: +The playbook also installs the BigchainDB Python Driver, +so you can use it to make transactions +and verify the functionality of your BigchainDB node. +See the [BigchainDB Python Driver documentation](https://docs.bigchaindb.com/projects/py-driver/en/latest/index.html) +for details on how to use it. + + +Note 1: The `bdb_root_url` can be be one of the following: ```text # BigchainDB is running as a process bdb_root_url = http://:9984 @@ -70,4 +77,5 @@ OR # BigchainDB is running inside a docker container bdb_root_url = http://: ``` -For more details on `how to make a transaction?` Please refer to [Basic Usage Examples](https://docs.bigchaindb.com/projects/py-driver/en/latest/connect.html). + +Note 2: BigchainDB has [other drivers as well](../drivers-clients/index.html). diff --git a/docs/server/source/appendices/run-with-vagrant.md b/docs/server/source/appendices/run-with-vagrant.md index c3c11e0e..c396017a 100644 --- a/docs/server/source/appendices/run-with-vagrant.md +++ b/docs/server/source/appendices/run-with-vagrant.md @@ -122,7 +122,13 @@ Verify BigchainDB Docker: $ docker ps | grep bigchaindb ``` -BigchainDB python driver is pre-installed in the instance, so you can instantly make transactions and verify the functionality. The `bdb_root_url` can be one of the following: +The BigchainDB Python Driver is pre-installed in the instance, +so you can use it to make transactions +and verify the functionality of your BigchainDB node. +See the [BigchainDB Python Driver documentation](https://docs.bigchaindb.com/projects/py-driver/en/latest/index.html) +for details on how to use it. + +Note 1: The `bdb_root_url` can be one of the following: ```text # BigchainDB is running as a process bdb_root_url = http://:9984 @@ -132,6 +138,5 @@ OR # BigchainDB is running inside a docker container bdb_root_url = http://: ``` -For more details on *how to make a transaction?* Please refer to [Basic Usage Examples](https://docs.bigchaindb.com/projects/py-driver/en/latest/connect.html). -*Note*: If you want to make transactions remotely, you need to install the `bigchaindb-driver`. For detailed instructions on how to install the driver and make your first transaction. Please refer to [Quickstart/Installation](https://docs.bigchaindb.com/projects/py-driver/en/latest/quickstart.html) of BigchainDB driver. \ No newline at end of file +Note 2: BigchainDB has [other drivers as well](../drivers-clients/index.html). diff --git a/docs/server/source/dev-and-test/index.rst b/docs/server/source/dev-and-test/index.rst index ff6e3ccf..bcde6e87 100644 --- a/docs/server/source/dev-and-test/index.rst +++ b/docs/server/source/dev-and-test/index.rst @@ -1,12 +1,13 @@ Develop & Test BigchainDB Server ================================ +This section outlines some ways that you could set up a minimal BigchainDB node for development and testing purposes. For additional guidance on how you could help develop BigchainDB, see the `CONTRIBUTING.md file on GitHub `_. + .. toctree:: :maxdepth: 1 - setup-run-node - setup-bdb-host - setup-bdb-docker - ../appendices/run-with-vagrant - ../appendices/run-with-ansible + Using a Local Dev Machine + Using a Local Dev Machine and Docker + Using Vagrant <../appendices/run-with-vagrant> + Using Ansible <../appendices/run-with-ansible> running-all-tests diff --git a/docs/server/source/dev-and-test/setup-bdb-host.md b/docs/server/source/dev-and-test/setup-bdb-host.md index e74cedd4..cdee3c0b 100644 --- a/docs/server/source/dev-and-test/setup-bdb-host.md +++ b/docs/server/source/dev-and-test/setup-bdb-host.md @@ -1,7 +1,12 @@ # Set Up BigchainDB Node on Local Dev Machine +The BigchainDB core dev team develops BigchainDB on recent Ubuntu, Fedora and CentOS distributions, so we recommend you use one of those. BigchainDB Server doesn't work on Windows or macOS (unless you use a VM or containers). + + ## With MongoDB +First read the BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md). It outlines the steps to set up a machine for developing and testing BigchainDB. + Create a default BigchainDB config file (in `$HOME/.bigchaindb`): ```text $ bigchaindb -y configure mongodb @@ -25,11 +30,13 @@ To run BigchainDB Server, do: $ bigchaindb start ``` -You can [run all the unit tests](running-unit-tests.html) to test your installation. +You can [run all the unit tests](running-all-tests.html) to test your installation. + -The BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md) has more details about how to contribute. ## With RethinkDB +First read the BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md). It outlines the steps to set up a machine for developing and testing BigchainDB. + Create a default BigchainDB config file (in `$HOME/.bigchaindb`): ```text $ bigchaindb -y configure rethinkdb @@ -52,5 +59,3 @@ $ bigchaindb start ``` You can [run all the unit tests](running-all-tests.html) to test your installation. - -The BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md) has more details about how to contribute. \ No newline at end of file diff --git a/docs/server/source/dev-and-test/setup-run-node.md b/docs/server/source/dev-and-test/setup-run-node.md deleted file mode 100644 index 0597adb6..00000000 --- a/docs/server/source/dev-and-test/setup-run-node.md +++ /dev/null @@ -1,16 +0,0 @@ -# Set Up & Run a Dev/Test Node - -This page explains how to set up a minimal local BigchainDB node for development and testing purposes. - -The BigchainDB core dev team develops BigchainDB on recent Ubuntu, Fedora and CentOS distributions, so we recommend you use one of those. BigchainDB Server doesn't work on Windows and Mac OS X (unless you use a VM or containers). - -Read through the BigchainDB [CONTRIBUTING.md file](https://github.com/bigchaindb/bigchaindb/blob/master/CONTRIBUTING.md). It outlines the steps to setup a machine for developing and testing BigchainDB. - -You can set up a stand-alone BigchainDB node using one of the following guides: - -- [Using a Local Dev Machine](setup-bdb-host.html) -- [Using a Local Dev Machine and Docker](setup-bdb-docker.html) -- [Using Vagrant](../appendices/run-with-vagrant.html) -- [Using Ansible](../appendices/run-with-ansible.html) - -You can [run all the unit tests](running-all-tests.html) to test your installation. diff --git a/docs/server/source/introduction.md b/docs/server/source/introduction.md index e92e9e0d..1ef47922 100644 --- a/docs/server/source/introduction.md +++ b/docs/server/source/introduction.md @@ -16,7 +16,7 @@ Note that there are a few kinds of nodes: ## Setup Instructions for Various Cases * [Quickstart](quickstart.html) -* [Set up a local BigchainDB node for development, experimenting and testing](dev-and-test/setup-run-node.html) +* [Set up a local BigchainDB node for development, experimenting and testing](dev-and-test/index.html) * [Set up and run a BigchainDB cluster](clusters.html) There are some old RethinkDB-based deployment instructions as well: From fba6e1b30bc98065b4921264ff4164e9de28f437 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Wed, 18 Oct 2017 15:38:46 +0200 Subject: [PATCH 044/120] New root docs page about permissions in BigchainDB --- docs/root/source/conf.py | 4 +- docs/root/source/index.rst | 1 + docs/root/source/permissions.rst | 74 ++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 docs/root/source/permissions.rst diff --git a/docs/root/source/conf.py b/docs/root/source/conf.py index 0d799fed..990fa3ce 100644 --- a/docs/root/source/conf.py +++ b/docs/root/source/conf.py @@ -34,7 +34,9 @@ from recommonmark.parser import CommonMarkParser # ones. import sphinx_rtd_theme -extensions = [] +extensions = [ + 'sphinx.ext.autosectionlabel', +] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/root/source/index.rst b/docs/root/source/index.rst index 455cae0c..71fdd022 100644 --- a/docs/root/source/index.rst +++ b/docs/root/source/index.rst @@ -88,5 +88,6 @@ More About BigchainDB assets smart-contracts transaction-concepts + permissions timestamps Data Models diff --git a/docs/root/source/permissions.rst b/docs/root/source/permissions.rst new file mode 100644 index 00000000..d5972ac0 --- /dev/null +++ b/docs/root/source/permissions.rst @@ -0,0 +1,74 @@ +Permissions in BigchainDB +------------------------- + +BigchainDB lets users control what other users can do, to some extent. That ability resembles "permissions" in the \*nix world, "privileges" in the SQL world, and "access control" in the security world. + + +Permission to Spend/Transfer an Output +====================================== + +In BigchainDB, every output has an associated condition (crypto-condition). + +To spend/transfer an unspent output, a user (or group of users) must fulfill the condition. Another way to say that is that only certain users have permission to spend the output. The simplest condition is of the form, "Only someone with the private key corresponding to this public key can spend this output." Much more elaborate conditions are possible, e.g. "To spend this output, …" + +- "…anyone in the Accounting Group can sign." +- "…three of these four people must sign." +- "…either Bob must sign, or both Tom and Sylvia must sign." + +For details, see `the documentation about conditions in BigchainDB `_. + +Once an output has been spent, it can't be spent again: *nobody* has permission to do that. That is, BigchainDB doesn't permit anyone to "double spend" an output. + + +Write Permissions +================= + +When someone builds a TRANSFER transaction, they can put an arbitrary JSON object in the ``metadata`` field (within reason; real BigchainDB networks put a limit on the size of transactions). That is, they can write just about anything they want in a TRANSFER transaction. + +Does that mean there are no "write permissions" in BigchainDB? Not at all! + +A TRANSFER transaction will only be valid (allowed) if its inputs fulfill some previous outputs. The conditions on those outputs will control who can build valid TRANSFER transactions. In other words, one can interpret the condition on an output as giving "write permissions" to certain users to write something into the history of the associated asset. + +As a concrete example, you could use BigchainDB to write a public journal where only you have write permissions. Here's how: First you'd build a CREATE transaction with the ``asset.data`` being something like ``{"title": "The Journal of John Doe"}``, with one output. That output would have an amount 1 and a condition that only you (who has your private key) can spend that output. +Each time you want to append something to your journal, you'd build a new TRANSFER transaction with your latest entry in the ``metadata`` field, e.g. + +.. code-block:: json + + {"timestamp": "1508319582", + "entry": "I visited Marmot Lake with Jane."} + +The TRANSFER transaction would have one output. That output would have an amount 1 and a condition that only you (who has your private key) can spend that output. And so on. Only you would be able to append to the history of that asset (your journal). + +The same technique could be used for scientific notebooks, supply-chain records, government meeting minutes, and so on. + +You could do more elaborate things too. As one example, each time someone writes a TRANSFER transaction, they give *someone else* permission to spend it, setting up a sort of writers-relay or chain letter. + +.. note:: + + Anyone can write any JSON (again, within reason) in the ``asset.data`` field of a CREATE transaction. They don't need permission. + + +Read Permissions +================ + +All the data stored in a BigchainDB network can be read by anyone with access to that network. One *can* store encrypted data, but if the decryption key ever leaks out, then the encrypted data can be read, decrypted, and leak out too. (Deleting the encrypted data is :doc:`not an option `.) + +The permission to read some specific information (e.g. a music file) can be thought of as an *asset*. (In many countries, that permission or "right" is a kind of intellectual property.) +BigchainDB can be used to register that asset and transfer it from owner to owner. +Today, BigchainDB does not have a way to restrict read access of data stored in a BigchainDB network, but many third-party services do offer that (e.g. Google Docs, Dropbox). +In principle, a third party service could ask a BigchainDB network to determine if a particular user has permission to read some particular data. Indeed they could use BigchainDB to keep track of *all* the rights a user has for some data (not just the right to read it). +That third party could also use BigchainDB to store audit logs, i.e. records of every read, write or other operation on stored data. + +BigchainDB can be used in other ways to help parties exchange private data: + +- It can be used to publicly disclose the *availability* of some private data (stored elsewhere). For example, there might be a description of the data and a price. +- It can be used to record the TLS handshakes which two parties sent to each other to establish an encrypted and authenticated TLS connection, which they could use to exchange private data with each other. (The stored handshake information wouldn't be enough, by itself, to decrypt the data.) It would be a "proof of TLS handshake." +- See the BigchainDB `Privacy Protocols repository `_ for more techniques. + + +Role-Based Access Control (RBAC) +================================ + +In September 2017, we published a `blog post about how one can define an RBAC sub-system on top of BigchainDB `_. +At the time of writing (October 2017), doing so required the use of a plugin, so it's not possible using standard BigchainDB (which is what's available on `IPDB `_). That may change in the future. +If you're interested, `contact BigchainDB `_. From 788f2f7277f871df9c165ca7464260185a5fb895 Mon Sep 17 00:00:00 2001 From: Sylvain Bellemare Date: Fri, 20 Oct 2017 11:00:38 +0200 Subject: [PATCH 045/120] Remove dev related mount of cryptoconditions --- docker-compose.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 81be1c69..cd6aa2aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: ports: - "27017" command: mongod --replSet=bigchain-rs - + bdb: build: context: . @@ -22,7 +22,6 @@ services: - ./setup.cfg:/usr/src/app/setup.cfg - ./pytest.ini:/usr/src/app/pytest.ini - ./tox.ini:/usr/src/app/tox.ini - - ../cryptoconditions:/usr/src/app/cryptoconditions environment: BIGCHAINDB_DATABASE_BACKEND: mongodb BIGCHAINDB_DATABASE_HOST: mdb From 0c0d3049f25a983beea2a8f49caf59b8ed777be8 Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 23 Oct 2017 09:17:58 +0530 Subject: [PATCH 046/120] Provide log server port as config paramter --- bigchaindb/__init__.py | 1 + bigchaindb/log/configs.py | 3 ++- bigchaindb/log/loggers.py | 5 ++++- bigchaindb/log/setup.py | 21 +++++++++++++++++---- bigchaindb/processes.py | 3 ++- bigchaindb/web/server.py | 8 +++++++- tests/log/test_loggers.py | 6 +++--- tests/log/test_setup.py | 2 +- tests/test_config_utils.py | 1 + 9 files changed, 38 insertions(+), 12 deletions(-) diff --git a/bigchaindb/__init__.py b/bigchaindb/__init__.py index 4fa1df02..c751469f 100644 --- a/bigchaindb/__init__.py +++ b/bigchaindb/__init__.py @@ -97,6 +97,7 @@ config = { 'fmt_console': log_config['formatters']['console']['format'], 'fmt_logfile': log_config['formatters']['file']['format'], 'granular_levels': {}, + 'port': log_config['root']['port'] }, 'graphite': { 'host': os.environ.get('BIGCHAINDB_GRAPHITE_HOST', 'localhost'), diff --git a/bigchaindb/log/configs.py b/bigchaindb/log/configs.py index 034256a4..687d49d1 100644 --- a/bigchaindb/log/configs.py +++ b/bigchaindb/log/configs.py @@ -62,6 +62,7 @@ SUBSCRIBER_LOGGING_CONFIG = { 'loggers': {}, 'root': { 'level': logging.DEBUG, - 'handlers': ['console', 'file', 'errors'] + 'handlers': ['console', 'file', 'errors'], + 'port': 9020 }, } diff --git a/bigchaindb/log/loggers.py b/bigchaindb/log/loggers.py index f8c18320..156a4c41 100644 --- a/bigchaindb/log/loggers.py +++ b/bigchaindb/log/loggers.py @@ -22,11 +22,14 @@ class HttpServerLogger(Logger): object. *Ignored*. """ + log_cfg = self.cfg.env_orig.get('custom_log_config', {}) + self.log_port = log_cfg.get('port', DEFAULT_SOCKET_LOGGING_PORT) + self._set_socklog_handler(self.error_log) self._set_socklog_handler(self.access_log) def _set_socklog_handler(self, log): socket_handler = logging.handlers.SocketHandler( - DEFAULT_SOCKET_LOGGING_HOST, DEFAULT_SOCKET_LOGGING_PORT) + DEFAULT_SOCKET_LOGGING_HOST, self.log_port) socket_handler._gunicorn = True log.addHandler(socket_handler) diff --git a/bigchaindb/log/setup.py b/bigchaindb/log/setup.py index b6b45b00..b6e45ef1 100644 --- a/bigchaindb/log/setup.py +++ b/bigchaindb/log/setup.py @@ -25,17 +25,29 @@ def _normalize_log_level(level): raise ConfigurationError('Log level must be a string!') from exc -def setup_pub_logger(): +def setup_pub_logger(logging_port=None): + if logging_port is None: + logging_port = DEFAULT_SOCKET_LOGGING_PORT + dictConfig(PUBLISHER_LOGGING_CONFIG) socket_handler = logging.handlers.SocketHandler( - DEFAULT_SOCKET_LOGGING_HOST, DEFAULT_SOCKET_LOGGING_PORT) + DEFAULT_SOCKET_LOGGING_HOST, logging_port) socket_handler.setLevel(logging.DEBUG) logger = logging.getLogger() logger.addHandler(socket_handler) def setup_sub_logger(*, user_log_config=None): - server = LogRecordSocketServer() + kwargs = {} + logging_port = None + + if user_log_config is not None: + logging_port = user_log_config.get('port') + + if logging_port is not None: + kwargs['port'] = logging_port + + server = LogRecordSocketServer(**kwargs) with server: server_proc = Process( target=server.serve_forever, @@ -45,7 +57,8 @@ def setup_sub_logger(*, user_log_config=None): def setup_logging(*, user_log_config=None): - setup_pub_logger() + port = user_log_config.get('port') if user_log_config is not None else None + setup_pub_logger(logging_port=port) setup_sub_logger(user_log_config=user_log_config) diff --git a/bigchaindb/processes.py b/bigchaindb/processes.py index 550342e5..f93cd5ce 100644 --- a/bigchaindb/processes.py +++ b/bigchaindb/processes.py @@ -63,7 +63,8 @@ def start(): election.start(events_queue=exchange.get_publisher_queue()) # start the web api - app_server = server.create_server(bigchaindb.config['server']) + app_server = server.create_server(settings=bigchaindb.config['server'], + log_config=bigchaindb.config['log']) p_webapi = mp.Process(name='webapi', target=app_server.run) p_webapi.start() diff --git a/bigchaindb/web/server.py b/bigchaindb/web/server.py index 91892807..a776afd4 100644 --- a/bigchaindb/web/server.py +++ b/bigchaindb/web/server.py @@ -37,6 +37,11 @@ class StandaloneApplication(gunicorn.app.base.BaseApplication): super().__init__() def load_config(self): + # find a better way to pass this such that + # the custom logger class can access it. + custom_log_config = self.options.get('custom_log_config') + self.cfg.env_orig['custom_log_config'] = custom_log_config + config = dict((key, value) for key, value in self.options.items() if key in self.cfg.settings and value is not None) @@ -74,7 +79,7 @@ def create_app(*, debug=False, threads=1): return app -def create_server(settings): +def create_server(settings, log_config=None): """Wrap and return an application ready to be run. Args: @@ -97,6 +102,7 @@ def create_server(settings): settings['threads'] = 1 settings['logger_class'] = 'bigchaindb.log.loggers.HttpServerLogger' + settings['custom_log_config'] = log_config app = create_app(debug=settings.get('debug', False), threads=settings['threads']) standalone = StandaloneApplication(app, options=settings) diff --git a/tests/log/test_loggers.py b/tests/log/test_loggers.py index 795de046..83a32252 100644 --- a/tests/log/test_loggers.py +++ b/tests/log/test_loggers.py @@ -7,9 +7,9 @@ class TestHttpServerLogger: from bigchaindb.log.configs import ( DEFAULT_SOCKET_LOGGING_ADDR as expected_socket_address) from bigchaindb.log.loggers import HttpServerLogger - mocked_config = mocker.patch( - 'gunicorn.config.Config', autospec=True, spec_set=True) - logger = HttpServerLogger(mocked_config.return_value) + from gunicorn import config + logger_config = config.Config() + logger = HttpServerLogger(logger_config) assert len(logger.access_log.handlers) == 1 assert len(logger.error_log.handlers) == 1 assert isinstance(logger.access_log.handlers[0], SocketHandler) diff --git a/tests/log/test_setup.py b/tests/log/test_setup.py index 0e608d26..063fb16f 100644 --- a/tests/log/test_setup.py +++ b/tests/log/test_setup.py @@ -70,7 +70,7 @@ def log_record_bytes(log_record_dict): def test_setup_logging(mocked_setup_pub_logger, mocked_setup_sub_logger): from bigchaindb.log.setup import setup_logging setup_logging() - mocked_setup_pub_logger.assert_called_once_with() + mocked_setup_pub_logger.assert_called_once_with(logging_port=None) mocked_setup_sub_logger.assert_called_once_with(user_log_config=None) diff --git a/tests/test_config_utils.py b/tests/test_config_utils.py index 3caa7777..8e71bc21 100644 --- a/tests/test_config_utils.py +++ b/tests/test_config_utils.py @@ -302,6 +302,7 @@ def test_autoconfigure_read_both_from_file_and_env(monkeypatch, request, certs_d 'fmt_console': log_config['formatters']['console']['format'], 'fmt_logfile': log_config['formatters']['file']['format'], 'granular_levels': {}, + 'port': 9020 }, 'graphite': {'host': 'localhost'}, } From 01390a8cc0ae6e25dcf294cd72d228b44b5e33a7 Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 23 Oct 2017 10:20:56 +0530 Subject: [PATCH 047/120] Fix code coverage --- tests/log/test_setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/log/test_setup.py b/tests/log/test_setup.py index 063fb16f..a02bd4c2 100644 --- a/tests/log/test_setup.py +++ b/tests/log/test_setup.py @@ -112,11 +112,12 @@ def test_setup_sub_logger_with_config(mocked_socket_server, mocked_process): 'granular_levels': { 'bigchaindb.core': 'debug', }, + 'port': 9020 } root_logger = getLogger() setup_sub_logger(user_log_config=user_log_config) assert root_logger.level == logging.NOTSET - mocked_socket_server.assert_called_once_with() + mocked_socket_server.assert_called_once_with(port=9020) mocked_process.assert_called_once_with( target=mocked_socket_server.return_value.serve_forever, kwargs={'log_config': user_log_config}, From 6f5eef97a7e000502434522a9401b8b39b4c583b Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 23 Oct 2017 14:31:12 +0530 Subject: [PATCH 048/120] Updated server configuration docs --- .../source/server-reference/configuration.md | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/server/source/server-reference/configuration.md b/docs/server/source/server-reference/configuration.md index c4b3f0ef..3d309df4 100644 --- a/docs/server/source/server-reference/configuration.md +++ b/docs/server/source/server-reference/configuration.md @@ -319,7 +319,8 @@ holding the logging configuration. "granular_levels": { "bichaindb.backend": "info", "bichaindb.core": "info" - } + }, + "port": 7070 } ``` @@ -336,7 +337,8 @@ holding the logging configuration. "datefmt_logfile": "%Y-%m-%d %H:%M:%S", "fmt_logfile": "[%(asctime)s] [%(levelname)s] (%(name)s) %(message)s (%(processName)-10s - pid: %(process)d)", "fmt_console": "[%(asctime)s] [%(levelname)s] (%(name)s) %(message)s (%(processName)-10s - pid: %(process)d)", - "granular_levels": {} + "granular_levels": {}, + "port": 9020 } ``` @@ -533,6 +535,22 @@ logging of the `core.py` module to be more verbose, you would set the **Defaults to**: `"{}"` +### log.port +The port number at which the logging server should listen. + +**Example**: + +``` +{ + "log": { + "port": 7070 + } +} +``` + +**Defaults to**: `9020` + + ## graphite.host The host name or IP address of a server listening for statsd events on UDP From dc00e16fda2c3960611c29af48b18121d1ad90bc Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 23 Oct 2017 16:00:09 +0530 Subject: [PATCH 049/120] Apply "log" environment variables to config --- bigchaindb/commands/utils.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/bigchaindb/commands/utils.py b/bigchaindb/commands/utils.py index d6840d68..11d97395 100644 --- a/bigchaindb/commands/utils.py +++ b/bigchaindb/commands/utils.py @@ -34,16 +34,18 @@ def configure_bigchaindb(command): """ @functools.wraps(command) def configure(args): + config_from_cmdline = None try: - config_from_cmdline = { - 'log': { - 'level_console': args.log_level, - 'level_logfile': args.log_level, - }, - 'server': {'loglevel': args.log_level}, - } + if args.log_level is not None: + config_from_cmdline = { + 'log': { + 'level_console': args.log_level, + 'level_logfile': args.log_level, + }, + 'server': {'loglevel': args.log_level}, + } except AttributeError: - config_from_cmdline = None + pass bigchaindb.config_utils.autoconfigure( filename=args.config, config=config_from_cmdline, force=True) command(args) @@ -238,10 +240,11 @@ base_parser.add_argument('-c', '--config', help='Specify the location of the configuration file ' '(use "-" for stdout)') +# NOTE: this flag should not have any default value because that will override +# the environment variables provided to configure the logger. base_parser.add_argument('-l', '--log-level', type=str.upper, # convert to uppercase for comparison to choices choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], - default='INFO', help='Log level') base_parser.add_argument('-y', '--yes', '--yes-please', From 50eb8571332bfbfa4288952e7cfce99cc695a252 Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 23 Oct 2017 18:06:11 +0530 Subject: [PATCH 050/120] Fix flake8 ambiguous variable "l" issue --- tests/test_utils.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index fbf5d65d..9620d0f9 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -142,9 +142,9 @@ def test_is_genesis_block_returns_true_if_genesis(b): def test_lazy_execution(): from bigchaindb.utils import Lazy - l = Lazy() - l.split(',')[1].split(' ').pop(1).strip() - result = l.run('Like humans, cats tend to favor one paw over another') + lz = Lazy() + lz.split(',')[1].split(' ').pop(1).strip() + result = lz.run('Like humans, cats tend to favor one paw over another') assert result == 'cats' class Cat: @@ -153,7 +153,7 @@ def test_lazy_execution(): cat = Cat('Shmui') - l = Lazy() - l.name.upper() - result = l.run(cat) + lz = Lazy() + lz.name.upper() + result = lz.run(cat) assert result == 'SHMUI' From 020d463e8d740d0b981a76ec831fe7d1cd296d70 Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 23 Oct 2017 21:08:44 +0530 Subject: [PATCH 051/120] Modified log port config checks. --- bigchaindb/log/configs.py | 2 +- bigchaindb/log/setup.py | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/bigchaindb/log/configs.py b/bigchaindb/log/configs.py index 687d49d1..6746edf9 100644 --- a/bigchaindb/log/configs.py +++ b/bigchaindb/log/configs.py @@ -63,6 +63,6 @@ SUBSCRIBER_LOGGING_CONFIG = { 'root': { 'level': logging.DEBUG, 'handlers': ['console', 'file', 'errors'], - 'port': 9020 + 'port': DEFAULT_SOCKET_LOGGING_PORT }, } diff --git a/bigchaindb/log/setup.py b/bigchaindb/log/setup.py index b6e45ef1..61ada66f 100644 --- a/bigchaindb/log/setup.py +++ b/bigchaindb/log/setup.py @@ -26,8 +26,7 @@ def _normalize_log_level(level): def setup_pub_logger(logging_port=None): - if logging_port is None: - logging_port = DEFAULT_SOCKET_LOGGING_PORT + logging_port = logging_port or DEFAULT_SOCKET_LOGGING_PORT dictConfig(PUBLISHER_LOGGING_CONFIG) socket_handler = logging.handlers.SocketHandler( @@ -39,13 +38,10 @@ def setup_pub_logger(logging_port=None): def setup_sub_logger(*, user_log_config=None): kwargs = {} - logging_port = None + log_port = user_log_config.get('port') if user_log_config is not None else None - if user_log_config is not None: - logging_port = user_log_config.get('port') - - if logging_port is not None: - kwargs['port'] = logging_port + if log_port is not None: + kwargs['port'] = log_port server = LogRecordSocketServer(**kwargs) with server: From fa345e54419581cf12435715d31fb4deb15cf181 Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 23 Oct 2017 21:52:30 +0530 Subject: [PATCH 052/120] Updated server configuration docs. --- docs/server/source/server-reference/configuration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/server/source/server-reference/configuration.md b/docs/server/source/server-reference/configuration.md index 3d309df4..b7c5526e 100644 --- a/docs/server/source/server-reference/configuration.md +++ b/docs/server/source/server-reference/configuration.md @@ -39,6 +39,7 @@ For convenience, here's a list of all the relevant environment variables (docume `BIGCHAINDB_LOG_FMT_CONSOLE`
`BIGCHAINDB_LOG_FMT_LOGFILE`
`BIGCHAINDB_LOG_GRANULAR_LEVELS`
+`BIGCHAINDB_LOG_PORT`
`BIGCHAINDB_DATABASE_SSL`
`BIGCHAINDB_DATABASE_LOGIN`
`BIGCHAINDB_DATABASE_PASSWORD`
@@ -532,7 +533,7 @@ logging of the `core.py` module to be more verbose, you would set the } ``` -**Defaults to**: `"{}"` +**Defaults to**: `{}` ### log.port From 5954d6360a4f8e4673fbf1dcc42f493537a2022c Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 24 Oct 2017 16:59:10 +0530 Subject: [PATCH 053/120] Added cmd flag --init to start command --- bigchaindb/commands/bigchaindb.py | 9 ++++++++- docker-compose.benchmark.yml | 2 +- docker-compose.rdb.yml | 2 +- docker-compose.yml | 2 +- tests/commands/conftest.py | 1 + tests/commands/test_commands.py | 9 ++++++--- 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/bigchaindb/commands/bigchaindb.py b/bigchaindb/commands/bigchaindb.py index 146dab91..9705065c 100644 --- a/bigchaindb/commands/bigchaindb.py +++ b/bigchaindb/commands/bigchaindb.py @@ -196,7 +196,9 @@ def run_start(args): logger.info('RethinkDB started with PID %s' % proc.pid) try: - _run_init() + if args.initialize_database: + logger.info('Initializing database') + _run_init() except DatabaseAlreadyExists: pass except KeypairNotFoundException: @@ -300,6 +302,11 @@ def create_parser(): action='store_true', help='Run RethinkDB on start') + start_parser.add_argument('--init', + dest='initialize_database', + action='store_true', + help='Force initialize database') + # parser for configuring the number of shards sharding_parser = subparsers.add_parser('set-shards', help='Configure number of shards') diff --git a/docker-compose.benchmark.yml b/docker-compose.benchmark.yml index c7319040..2a2aacc2 100644 --- a/docker-compose.benchmark.yml +++ b/docker-compose.benchmark.yml @@ -25,7 +25,7 @@ services: BIGCHAINDB_GRAPHITE_HOST: graphite ports: - "9984" - command: bigchaindb start + command: bigchaindb start --init graphite: image: hopsoft/graphite-statsd diff --git a/docker-compose.rdb.yml b/docker-compose.rdb.yml index 15f91675..e02aa444 100644 --- a/docker-compose.rdb.yml +++ b/docker-compose.rdb.yml @@ -45,4 +45,4 @@ services: BIGCHAINDB_SERVER_BIND: 0.0.0.0:9984 ports: - "9984" - command: bigchaindb start + command: bigchaindb start --init diff --git a/docker-compose.yml b/docker-compose.yml index cd6aa2aa..8f774106 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,4 +30,4 @@ services: BIGCHAINDB_WSSERVER_HOST: 0.0.0.0 ports: - "9984" - command: bigchaindb start + command: bigchaindb start --init diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py index 4a60c0cc..1aef2d30 100644 --- a/tests/commands/conftest.py +++ b/tests/commands/conftest.py @@ -49,6 +49,7 @@ def run_start_args(request): config=param.get('config'), start_rethinkdb=param.get('start_rethinkdb', False), allow_temp_keypair=param.get('allow_temp_keypair', False), + initialize_database=param.get('initialize_database', True), ) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index b50a2a67..15aa9302 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -39,7 +39,8 @@ def test_bigchain_run_start(mock_run_configure, mocked_setup_logging): from bigchaindb import config from bigchaindb.commands.bigchaindb import run_start - args = Namespace(start_rethinkdb=False, allow_temp_keypair=False, config=None, yes=True) + args = Namespace(start_rethinkdb=False, allow_temp_keypair=False, config=None, yes=True, + initialize_database=True) run_start(args) mocked_setup_logging.assert_called_once_with(user_log_config=config['log']) @@ -288,7 +289,8 @@ def test_allow_temp_keypair_generates_one_on_the_fly( bigchaindb.config['keypair'] = {'private': None, 'public': None} - args = Namespace(allow_temp_keypair=True, start_rethinkdb=False, config=None, yes=True) + args = Namespace(allow_temp_keypair=True, start_rethinkdb=False, config=None, yes=True, + initialize_database=True) run_start(args) mocked_setup_logging.assert_called_once_with( @@ -314,7 +316,8 @@ def test_allow_temp_keypair_doesnt_override_if_keypair_found(mock_gen_keypair, assert isinstance(original_public_key, str) assert isinstance(original_private_key, str) - args = Namespace(allow_temp_keypair=True, start_rethinkdb=False, config=None, yes=True) + args = Namespace(allow_temp_keypair=True, start_rethinkdb=False, config=None, yes=True, + initialize_database=True) run_start(args) mocked_setup_logging.assert_called_once_with( From 199473178fe1e9cf0e6ec8ad67c1b805003349b9 Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 24 Oct 2017 18:03:57 +0530 Subject: [PATCH 054/120] Fix rethinkdb tests --- tests/commands/rethinkdb/test_commands.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/commands/rethinkdb/test_commands.py b/tests/commands/rethinkdb/test_commands.py index e40b3ff2..29a84972 100644 --- a/tests/commands/rethinkdb/test_commands.py +++ b/tests/commands/rethinkdb/test_commands.py @@ -13,7 +13,8 @@ def test_bigchain_run_start_with_rethinkdb(mock_start_rethinkdb, mocked_setup_logging): from bigchaindb import config from bigchaindb.commands.bigchaindb import run_start - args = Namespace(start_rethinkdb=True, allow_temp_keypair=False, config=None, yes=True) + args = Namespace(start_rethinkdb=True, allow_temp_keypair=False, config=None, yes=True, + initialize_database=True) run_start(args) mock_start_rethinkdb.assert_called_with() From cf19a8cb93ed0c1429c5f813c51a369e4aa4de90 Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 24 Oct 2017 18:29:31 +0530 Subject: [PATCH 055/120] Updated docs --- docs/server/source/appendices/azure-quickstart-template.md | 2 +- docs/server/source/dev-and-test/setup-bdb-host.md | 4 ++-- docs/server/source/quickstart.md | 2 +- docs/server/source/server-reference/bigchaindb-cli.md | 4 +--- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/server/source/appendices/azure-quickstart-template.md b/docs/server/source/appendices/azure-quickstart-template.md index 59f52fd3..13cda281 100644 --- a/docs/server/source/appendices/azure-quickstart-template.md +++ b/docs/server/source/appendices/azure-quickstart-template.md @@ -33,7 +33,7 @@ API Server bind? (default `localhost:9984`): 0.0.0.0:9984 Finally, run BigchainDB Server by doing: ```text -bigchaindb start +bigchaindb start --init ``` BigchainDB Server should now be running on the Azure virtual machine. diff --git a/docs/server/source/dev-and-test/setup-bdb-host.md b/docs/server/source/dev-and-test/setup-bdb-host.md index cdee3c0b..5feb8c42 100644 --- a/docs/server/source/dev-and-test/setup-bdb-host.md +++ b/docs/server/source/dev-and-test/setup-bdb-host.md @@ -27,7 +27,7 @@ waiting for connections on port 27017 To run BigchainDB Server, do: ```text -$ bigchaindb start +$ bigchaindb start --init ``` You can [run all the unit tests](running-all-tests.html) to test your installation. @@ -55,7 +55,7 @@ You can verify that RethinkDB is running by opening the RethinkDB web interface To run BigchainDB Server, do: ```text -$ bigchaindb start +$ bigchaindb start --init ``` You can [run all the unit tests](running-all-tests.html) to test your installation. diff --git a/docs/server/source/quickstart.md b/docs/server/source/quickstart.md index 63ab8643..2375fd5f 100644 --- a/docs/server/source/quickstart.md +++ b/docs/server/source/quickstart.md @@ -54,7 +54,7 @@ $ bigchaindb -y configure mongodb I. Run BigchainDB Server: ```text -$ bigchaindb start +$ bigchaindb start --init ``` J. Verify BigchainDB Server setup by visiting the BigchainDB Root URL in your browser: diff --git a/docs/server/source/server-reference/bigchaindb-cli.md b/docs/server/source/server-reference/bigchaindb-cli.md index 05f321f9..fddfd3f5 100644 --- a/docs/server/source/server-reference/bigchaindb-cli.md +++ b/docs/server/source/server-reference/bigchaindb-cli.md @@ -51,8 +51,6 @@ all database tables/collections, various backend database indexes, and the genesis block. -Note: The `bigchaindb start` command (see below) always starts by trying a `bigchaindb init` first. If it sees that the backend database already exists, then it doesn't re-initialize the database. One doesn't have to do `bigchaindb init` before `bigchaindb start`. `bigchaindb init` is useful if you only want to initialize (but not start). - ## bigchaindb drop @@ -63,7 +61,7 @@ If you want to force-drop the database (i.e. skipping the yes/no prompt), then u ## bigchaindb start -Start BigchainDB. It always begins by trying a `bigchaindb init` first. See the note in the documentation for `bigchaindb init`. +Start BigchainDB assuming that the database has already been initialized using `bigchaindb init`. If that is not the case then passing the flag `--init` will initialize the database and start BigchainDB. You can also use the `--dev-start-rethinkdb` command line option to automatically start rethinkdb with bigchaindb if rethinkdb is not already running, e.g. `bigchaindb --dev-start-rethinkdb start`. Note that this will also shutdown rethinkdb when the bigchaindb process stops. The option `--dev-allow-temp-keypair` will generate a keypair on the fly if no keypair is found, this is useful when you want to run a temporary instance of BigchainDB in a Docker container, for example. From 25716261e0c9609a014cc76d5c1462d77c30897b Mon Sep 17 00:00:00 2001 From: kansi Date: Wed, 25 Oct 2017 13:47:02 +0530 Subject: [PATCH 056/120] Updated keep-alive section --- .../source/events/websocket-event-stream-api.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/server/source/events/websocket-event-stream-api.rst b/docs/server/source/events/websocket-event-stream-api.rst index 0000107b..7eb3f3f5 100644 --- a/docs/server/source/events/websocket-event-stream-api.rst +++ b/docs/server/source/events/websocket-event-stream-api.rst @@ -40,11 +40,14 @@ response contains a ``streams`` property: Connection Keep-Alive --------------------- -The Event Stream API initially does not provide any mechanisms for connection -keep-alive other than enabling TCP keepalive on each open WebSocket connection. -In the future, we may add additional functionality to handle ping/pong frames -or payloads designed for keep-alive. +The Event Stream API supports Ping/Pong frames as descibed in +`RFC 6455 `_. +.. note:: + + It might not be possible to send PING/PONG frames via web browsers because + of non availability of Javascript API on different browsers to achieve the + same. Streams ------- From ddfce61b79895c63c84ace2e8861e1a59c63ed67 Mon Sep 17 00:00:00 2001 From: kansi Date: Fri, 27 Oct 2017 15:05:43 +0530 Subject: [PATCH 057/120] Added secondary index for "id" in bigchain collection. --- bigchaindb/backend/mongodb/schema.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bigchaindb/backend/mongodb/schema.py b/bigchaindb/backend/mongodb/schema.py index e398560f..00616dcb 100644 --- a/bigchaindb/backend/mongodb/schema.py +++ b/bigchaindb/backend/mongodb/schema.py @@ -50,6 +50,11 @@ def drop_database(conn, dbname): def create_bigchain_secondary_index(conn, dbname): logger.info('Create `bigchain` secondary index.') + # secondary index on block id which is should be unique + conn.conn[dbname]['bigchain'].create_index('id', + name='block_id', + unique=True) + # to order blocks by timestamp conn.conn[dbname]['bigchain'].create_index([('block.timestamp', ASCENDING)], From 97e1a13c7f02791b8fbfa3b2190bbac43070f466 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Fri, 27 Oct 2017 11:51:02 +0200 Subject: [PATCH 058/120] Updated docs/server/requirements.txt The `requirements.txt` file in `docs/server` didn't have all the Python packages needed to build the BigchainDB Server docs. I fixed that. --- docs/server/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/server/requirements.txt b/docs/server/requirements.txt index 4321f44b..5ca634a4 100644 --- a/docs/server/requirements.txt +++ b/docs/server/requirements.txt @@ -3,3 +3,5 @@ recommonmark>=0.4.0 sphinx-rtd-theme>=0.1.9 sphinxcontrib-napoleon>=0.4.4 sphinxcontrib-httpdomain>=1.5.0 +pyyaml +bigchaindb From 421c67c62149b28b8de137c3ed46659c743df4dd Mon Sep 17 00:00:00 2001 From: kansi Date: Fri, 27 Oct 2017 15:31:44 +0530 Subject: [PATCH 059/120] Fixed mongodb tests --- bigchaindb/backend/mongodb/schema.py | 3 +-- tests/backend/mongodb/test_schema.py | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bigchaindb/backend/mongodb/schema.py b/bigchaindb/backend/mongodb/schema.py index 00616dcb..01eac29c 100644 --- a/bigchaindb/backend/mongodb/schema.py +++ b/bigchaindb/backend/mongodb/schema.py @@ -52,8 +52,7 @@ def create_bigchain_secondary_index(conn, dbname): # secondary index on block id which is should be unique conn.conn[dbname]['bigchain'].create_index('id', - name='block_id', - unique=True) + name='block_id') # to order blocks by timestamp conn.conn[dbname]['bigchain'].create_index([('block.timestamp', diff --git a/tests/backend/mongodb/test_schema.py b/tests/backend/mongodb/test_schema.py index e11dbfe8..1a244b1b 100644 --- a/tests/backend/mongodb/test_schema.py +++ b/tests/backend/mongodb/test_schema.py @@ -22,8 +22,8 @@ def test_init_creates_db_tables_and_indexes(): 'votes'] indexes = conn.conn[dbname]['bigchain'].index_information().keys() - assert sorted(indexes) == ['_id_', 'asset_id', 'block_timestamp', 'inputs', - 'outputs', 'transaction_id'] + assert sorted(indexes) == ['_id_', 'asset_id', 'block_id', 'block_timestamp', + 'inputs', 'outputs', 'transaction_id'] indexes = conn.conn[dbname]['backlog'].index_information().keys() assert sorted(indexes) == ['_id_', 'assignee__transaction_timestamp', @@ -86,8 +86,8 @@ def test_create_secondary_indexes(): # Bigchain table indexes = conn.conn[dbname]['bigchain'].index_information().keys() - assert sorted(indexes) == ['_id_', 'asset_id', 'block_timestamp', 'inputs', - 'outputs', 'transaction_id'] + assert sorted(indexes) == ['_id_', 'asset_id', 'block_id', 'block_timestamp', + 'inputs', 'outputs', 'transaction_id'] # Backlog table indexes = conn.conn[dbname]['backlog'].index_information().keys() From 722658421580c36ac32d6a7bd9e3537ed96a9bb6 Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 31 Oct 2017 10:12:16 +0530 Subject: [PATCH 060/120] Api fix for asset language --- bigchaindb/backend/schema.py | 22 ++++++++++++++++++ bigchaindb/models.py | 2 ++ tests/web/test_transactions.py | 41 ++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/bigchaindb/backend/schema.py b/bigchaindb/backend/schema.py index f6ce466f..8b85c068 100644 --- a/bigchaindb/backend/schema.py +++ b/bigchaindb/backend/schema.py @@ -16,10 +16,14 @@ import logging import bigchaindb from bigchaindb.backend.connection import connect +from bigchaindb.common.exceptions import ValidationError logger = logging.getLogger(__name__) TABLES = ('bigchain', 'backlog', 'votes', 'assets') +VALID_LANGUAGES = ('danish' 'dutch' 'english' 'finnish' 'french' 'german' + 'hungarian' 'italian' 'norwegian' 'portuguese' 'romanian' + 'russian' 'spanish' 'swedish' 'turkish') @singledispatch @@ -99,3 +103,21 @@ def init_database(connection=None, dbname=None): create_database(connection, dbname) create_tables(connection, dbname) create_indexes(connection, dbname) + + +def validate_if_exists_asset_language(tx_body): + data = tx_body['asset'].get('data', {}) + + if data and 'language' in data: + + language = data.get('language') + backend = bigchaindb.config['database']['backend'] + + if backend == 'mongodb' and language not in VALID_LANGUAGES: + error_str = ('MongoDB does not support text search for the ' + 'language "{}". If you do not understand this error ' + 'message then please rename key/field "language" to ' + 'something else like "lang".').format(language) + raise ValidationError(error_str) from ValueError() + + return diff --git a/bigchaindb/models.py b/bigchaindb/models.py index c8ad9dd3..d88d239e 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -10,6 +10,7 @@ from bigchaindb.common.exceptions import (InvalidHash, InvalidSignature, from bigchaindb.common.transaction import Transaction from bigchaindb.common.utils import gen_timestamp, serialize from bigchaindb.common.schema import validate_transaction_schema +from bigchaindb.backend.schema import validate_if_exists_asset_language class Transaction(Transaction): @@ -84,6 +85,7 @@ class Transaction(Transaction): @classmethod def from_dict(cls, tx_body): validate_transaction_schema(tx_body) + validate_if_exists_asset_language(tx_body) return super().from_dict(tx_body) @classmethod diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index acea8c2c..8b4d31bf 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -47,6 +47,47 @@ def test_post_create_transaction_endpoint(b, client): assert res.json['outputs'][0]['public_keys'][0] == user_pub +@pytest.mark.parametrize("language,expected_status_code", [ + ('danish', 202), + ('dutch', 202), + ('english', 202), + ('finnish', 202), + ('french', 202), + ('german', 202), + ('hungarian', 202), + ('italian', 202), + ('norwegian', 202), + ('portuguese', 202), + ('romanian', 202), + ('russian', 202), + ('spanish', 202), + ('swedish', 202), + ('turkish', 202), + ('any', 400), +]) +@pytest.mark.language +@pytest.mark.bdb +def test_post_create_transaction_with_language(b, client, language, expected_status_code): + from bigchaindb.models import Transaction + from bigchaindb.backend.mongodb.connection import MongoDBConnection + + if isinstance(b.connection, MongoDBConnection): + user_priv, user_pub = crypto.generate_key_pair() + + tx = Transaction.create([user_pub], [([user_pub], 1)], + asset={'language': language}) + tx = tx.sign([user_priv]) + res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict())) + assert res.status_code == expected_status_code + if res.status_code == 400: + expected_error_message = ( + "Invalid transaction (ValidationError): MongoDB does not support " + "text search for the language \"{}\". If you do not understand this " + "error message then please rename key/field \"language\" to something " + "else like \"lang\".").format(language) + assert res.json['message'] == expected_error_message + + @patch('bigchaindb.web.views.base.logger') def test_post_create_transaction_with_invalid_id(mock_logger, b, client): from bigchaindb.common.exceptions import InvalidHash From 1de5375962306b1ce04c553eb38ad5237839959f Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 31 Oct 2017 15:16:59 +0530 Subject: [PATCH 061/120] Validate asset data keys --- bigchaindb/common/utils.py | 19 ++++++++++++++++++- bigchaindb/models.py | 4 +++- tests/web/test_transactions.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/bigchaindb/common/utils.py b/bigchaindb/common/utils.py index f6f671db..fd9386e1 100644 --- a/bigchaindb/common/utils.py +++ b/bigchaindb/common/utils.py @@ -1,7 +1,10 @@ import time - +import re import rapidjson +import bigchaindb +from bigchaindb.common.exceptions import ValidationError + def gen_timestamp(): """The Unix time, rounded to the nearest second. @@ -46,3 +49,17 @@ def deserialize(data): string. """ return rapidjson.loads(data) + + +def validate_asset_data_keys(tx_body): + backend = bigchaindb.config['database']['backend'] + + if backend == 'mongodb': + data = tx_body['asset'].get('data', {}) + keys = data.keys() if data else [] + for key in keys: + if re.search(r'^[$]|\.', key): + error_str = ('Invalid key name "{}" in asset object. The ' + 'key name cannot contain characters ' + '"." and "$"').format(key) + raise ValidationError(error_str) from ValueError() diff --git a/bigchaindb/models.py b/bigchaindb/models.py index c8ad9dd3..9704372d 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -8,7 +8,8 @@ from bigchaindb.common.exceptions import (InvalidHash, InvalidSignature, SybilError, DuplicateTransaction) from bigchaindb.common.transaction import Transaction -from bigchaindb.common.utils import gen_timestamp, serialize +from bigchaindb.common.utils import (gen_timestamp, serialize, + validate_asset_data_keys) from bigchaindb.common.schema import validate_transaction_schema @@ -84,6 +85,7 @@ class Transaction(Transaction): @classmethod def from_dict(cls, tx_body): validate_transaction_schema(tx_body) + validate_asset_data_keys(tx_body) return super().from_dict(tx_body) @classmethod diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index acea8c2c..4c2a6ed9 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -47,6 +47,34 @@ def test_post_create_transaction_endpoint(b, client): assert res.json['outputs'][0]['public_keys'][0] == user_pub +@pytest.mark.parametrize("key,expected_status_code", [ + ('bad.key', 400), + ('$bad.key', 400), + ('$badkey', 400), + ('good_key', 202) +]) +@pytest.mark.assetkey +@pytest.mark.bdb +def test_post_create_transaction_with_invalid_asset_key(b, client, key, expected_status_code): + from bigchaindb.models import Transaction + from bigchaindb.backend.mongodb.connection import MongoDBConnection + user_priv, user_pub = crypto.generate_key_pair() + + if isinstance(b.connection, MongoDBConnection): + tx = Transaction.create([user_pub], [([user_pub], 1)], + asset={key: 'random_value'}) + tx = tx.sign([user_priv]) + res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict())) + + assert res.status_code == expected_status_code + if res.status_code == 400: + expected_error_message = ( + 'Invalid transaction (ValidationError): Invalid key name "{}" ' + 'in asset object. The key name cannot contain characters ' + '"." and "$"').format(key) + assert res.json['message'] == expected_error_message + + @patch('bigchaindb.web.views.base.logger') def test_post_create_transaction_with_invalid_id(mock_logger, b, client): from bigchaindb.common.exceptions import InvalidHash From cd636101a7c03e433c27a26d1749e87a37dbec55 Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 31 Oct 2017 16:54:47 +0530 Subject: [PATCH 062/120] Support abbreviated values for "language" --- bigchaindb/backend/schema.py | 12 +++++++----- tests/web/test_transactions.py | 24 ++++++++---------------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/bigchaindb/backend/schema.py b/bigchaindb/backend/schema.py index 8b85c068..3b7413a2 100644 --- a/bigchaindb/backend/schema.py +++ b/bigchaindb/backend/schema.py @@ -21,9 +21,11 @@ from bigchaindb.common.exceptions import ValidationError logger = logging.getLogger(__name__) TABLES = ('bigchain', 'backlog', 'votes', 'assets') -VALID_LANGUAGES = ('danish' 'dutch' 'english' 'finnish' 'french' 'german' - 'hungarian' 'italian' 'norwegian' 'portuguese' 'romanian' - 'russian' 'spanish' 'swedish' 'turkish') +VALID_LANGUAGES = ('danish', 'dutch', 'english', 'finnish', 'french', 'german', + 'hungarian', 'italian', 'norwegian', 'portuguese', 'romanian', + 'russian', 'spanish', 'swedish', 'turkish', + 'da', 'nl', 'en', 'fi', 'fr', 'de', 'hu', 'it', 'nb', 'pt', + 'ro', 'ru', 'es', 'sv', 'tr') @singledispatch @@ -108,12 +110,12 @@ def init_database(connection=None, dbname=None): def validate_if_exists_asset_language(tx_body): data = tx_body['asset'].get('data', {}) - if data and 'language' in data: + if data and ('language' in data): language = data.get('language') backend = bigchaindb.config['database']['backend'] - if backend == 'mongodb' and language not in VALID_LANGUAGES: + if (backend == 'mongodb') and (language not in VALID_LANGUAGES): error_str = ('MongoDB does not support text search for the ' 'language "{}". If you do not understand this error ' 'message then please rename key/field "language" to ' diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index 8b4d31bf..f33c47b1 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -48,22 +48,14 @@ def test_post_create_transaction_endpoint(b, client): @pytest.mark.parametrize("language,expected_status_code", [ - ('danish', 202), - ('dutch', 202), - ('english', 202), - ('finnish', 202), - ('french', 202), - ('german', 202), - ('hungarian', 202), - ('italian', 202), - ('norwegian', 202), - ('portuguese', 202), - ('romanian', 202), - ('russian', 202), - ('spanish', 202), - ('swedish', 202), - ('turkish', 202), - ('any', 400), + ('danish', 202), ('dutch', 202), ('english', 202), ('finnish', 202), + ('french', 202), ('german', 202), ('hungarian', 202), ('italian', 202), + ('norwegian', 202), ('portuguese', 202), ('romanian', 202), + ('russian', 202), ('spanish', 202), ('swedish', 202), ('turkish', 202), + ('da', 202), ('nl', 202), ('en', 202), ('fi', 202), ('fr', 202), + ('de', 202), ('hu', 202), ('it', 202), ('nb', 202), ('pt', 202), + ('ro', 202), ('ru', 202), ('es', 202), ('sv', 202), ('tr', 202), + ('any', 400) ]) @pytest.mark.language @pytest.mark.bdb From f3da30aea082347a8ae72d1b8ddd97e0def5d37d Mon Sep 17 00:00:00 2001 From: kansi Date: Wed, 1 Nov 2017 17:26:16 +0530 Subject: [PATCH 063/120] Validate nested keys for asset.data and metadata --- bigchaindb/common/utils.py | 28 +++++++++++++++++++--------- bigchaindb/models.py | 5 +++-- tests/web/test_transactions.py | 29 ++++++++++++++++++----------- 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/bigchaindb/common/utils.py b/bigchaindb/common/utils.py index fd9386e1..35163f14 100644 --- a/bigchaindb/common/utils.py +++ b/bigchaindb/common/utils.py @@ -51,15 +51,25 @@ def deserialize(data): return rapidjson.loads(data) -def validate_asset_data_keys(tx_body): +def validate_txn_obj(obj_name, obj, key, validation_fun): backend = bigchaindb.config['database']['backend'] if backend == 'mongodb': - data = tx_body['asset'].get('data', {}) - keys = data.keys() if data else [] - for key in keys: - if re.search(r'^[$]|\.', key): - error_str = ('Invalid key name "{}" in asset object. The ' - 'key name cannot contain characters ' - '"." and "$"').format(key) - raise ValidationError(error_str) from ValueError() + data = obj.get(key, {}) or {} + validate_all_keys(obj_name, data, validation_fun) + + +def validate_all_keys(obj_name, obj, validation_fun): + for key, value in obj.items(): + validation_fun(obj_name, key) + if type(value) is dict: + validate_all_keys(obj_name, value, validation_fun) + return + + +def validate_key(obj_name, key): + if re.search(r'^[$]|\.|\x00', key): + error_str = ('Invalid key name "{}" in {} object. The ' + 'key name cannot contain characters ' + '".", "$" or null characters').format(key, obj_name) + raise ValidationError(error_str) from ValueError() diff --git a/bigchaindb/models.py b/bigchaindb/models.py index 9704372d..1ecd964e 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -9,7 +9,7 @@ from bigchaindb.common.exceptions import (InvalidHash, InvalidSignature, DuplicateTransaction) from bigchaindb.common.transaction import Transaction from bigchaindb.common.utils import (gen_timestamp, serialize, - validate_asset_data_keys) + validate_txn_obj, validate_key) from bigchaindb.common.schema import validate_transaction_schema @@ -85,7 +85,8 @@ class Transaction(Transaction): @classmethod def from_dict(cls, tx_body): validate_transaction_schema(tx_body) - validate_asset_data_keys(tx_body) + validate_txn_obj('asset', tx_body['asset'], 'data', validate_key) + validate_txn_obj('metadata', tx_body, 'metadata', validate_key) return super().from_dict(tx_body) @classmethod diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index 4c2a6ed9..e5034697 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -47,22 +47,29 @@ def test_post_create_transaction_endpoint(b, client): assert res.json['outputs'][0]['public_keys'][0] == user_pub -@pytest.mark.parametrize("key,expected_status_code", [ - ('bad.key', 400), - ('$bad.key', 400), - ('$badkey', 400), - ('good_key', 202) +@pytest.mark.parametrize("field", ['asset', 'metadata']) +@pytest.mark.parametrize("value,err_key,expected_status_code", [ + ({'bad.key': 'v'}, 'bad.key', 400), + ({'$bad.key': 'v'}, '$bad.key', 400), + ({'$badkey': 'v'}, '$badkey', 400), + ({'bad\x00key': 'v'}, 'bad\x00key', 400), + ({'good_key': {'bad.key': 'v'}}, 'bad.key', 400), + ({'good_key': 'v'}, 'good_key', 202) ]) -@pytest.mark.assetkey @pytest.mark.bdb -def test_post_create_transaction_with_invalid_asset_key(b, client, key, expected_status_code): +def test_post_create_transaction_with_invalid_key(b, client, field, value, + err_key, expected_status_code): from bigchaindb.models import Transaction from bigchaindb.backend.mongodb.connection import MongoDBConnection user_priv, user_pub = crypto.generate_key_pair() if isinstance(b.connection, MongoDBConnection): - tx = Transaction.create([user_pub], [([user_pub], 1)], - asset={key: 'random_value'}) + if field == 'asset': + tx = Transaction.create([user_pub], [([user_pub], 1)], + asset=value) + elif field == 'metadata': + tx = Transaction.create([user_pub], [([user_pub], 1)], + metadata=value) tx = tx.sign([user_priv]) res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict())) @@ -70,8 +77,8 @@ def test_post_create_transaction_with_invalid_asset_key(b, client, key, expected if res.status_code == 400: expected_error_message = ( 'Invalid transaction (ValidationError): Invalid key name "{}" ' - 'in asset object. The key name cannot contain characters ' - '"." and "$"').format(key) + 'in {} object. The key name cannot contain characters ' + '".", "$" or null characters').format(err_key, field) assert res.json['message'] == expected_error_message From 263e9a25f66cd883095d237bedd84c69337d614a Mon Sep 17 00:00:00 2001 From: kansi Date: Wed, 1 Nov 2017 21:23:06 +0530 Subject: [PATCH 064/120] Unique index for bigchain collection, fixed test case --- bigchaindb/backend/mongodb/schema.py | 5 +++-- tests/backend/mongodb/test_queries.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bigchaindb/backend/mongodb/schema.py b/bigchaindb/backend/mongodb/schema.py index 01eac29c..572acff9 100644 --- a/bigchaindb/backend/mongodb/schema.py +++ b/bigchaindb/backend/mongodb/schema.py @@ -50,9 +50,10 @@ def drop_database(conn, dbname): def create_bigchain_secondary_index(conn, dbname): logger.info('Create `bigchain` secondary index.') - # secondary index on block id which is should be unique + # secondary index on block id which should be unique conn.conn[dbname]['bigchain'].create_index('id', - name='block_id') + name='block_id', + unique=True) # to order blocks by timestamp conn.conn[dbname]['bigchain'].create_index([('block.timestamp', diff --git a/tests/backend/mongodb/test_queries.py b/tests/backend/mongodb/test_queries.py index 0fd7229a..3ea7db28 100644 --- a/tests/backend/mongodb/test_queries.py +++ b/tests/backend/mongodb/test_queries.py @@ -299,12 +299,13 @@ def test_count_blocks(signed_create_tx): from bigchaindb.models import Block conn = connect() + assert query.count_blocks(conn) == 0 + # create and insert some blocks block = Block(transactions=[signed_create_tx]) conn.db.bigchain.insert_one(block.to_dict()) - conn.db.bigchain.insert_one(block.to_dict()) - assert query.count_blocks(conn) == 2 + assert query.count_blocks(conn) == 1 def test_count_backlog(signed_create_tx): From 8fdf8f6ca6cfdc3c20ac863c1b205dcfe365894e Mon Sep 17 00:00:00 2001 From: kansi Date: Thu, 2 Nov 2017 18:02:11 +0530 Subject: [PATCH 065/120] Added docstrings --- bigchaindb/common/utils.py | 43 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/bigchaindb/common/utils.py b/bigchaindb/common/utils.py index 35163f14..e472f380 100644 --- a/bigchaindb/common/utils.py +++ b/bigchaindb/common/utils.py @@ -52,6 +52,22 @@ def deserialize(data): def validate_txn_obj(obj_name, obj, key, validation_fun): + """Validates value associated to `key` in `obj` by applying + `validation_fun`. + + Args: + obj_name (str): name for `obj` being validated. + obj (dict): dictonary object. + key (str): key to be validated in `obj`. + validation_fun (function): function used to validate the value + of `key`. + + Returns: + None: indicates validation successfull + + Raises: + ValidationError: `validation_fun` will raise this error on failure + """ backend = bigchaindb.config['database']['backend'] if backend == 'mongodb': @@ -60,6 +76,20 @@ def validate_txn_obj(obj_name, obj, key, validation_fun): def validate_all_keys(obj_name, obj, validation_fun): + """Validates all (nested) keys in `obj` by using `validation_fun` + + Args: + obj_name (str): name for `obj` being validated. + obj (dict): dictonary object. + validation_fun (function): function used to validate the value + of `key`. + + Returns: + None: indicates validation successfull + + Raises: + ValidationError: `validation_fun` will raise this error on failure + """ for key, value in obj.items(): validation_fun(obj_name, key) if type(value) is dict: @@ -68,6 +98,19 @@ def validate_all_keys(obj_name, obj, validation_fun): def validate_key(obj_name, key): + """Check if `key` contains ".", "$" or null characters + https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names + + Args: + obj_name (str): object name to use when raising exception + key (str): key to validated + + Returns: + None: indicates validation successfull + + Raises: + ValidationError: raise execption incase of regex match. + """ if re.search(r'^[$]|\.|\x00', key): error_str = ('Invalid key name "{}" in {} object. The ' 'key name cannot contain characters ' From 99aa38b21742ef412bf591f81e6f8c8763db68bb Mon Sep 17 00:00:00 2001 From: kansi Date: Fri, 3 Nov 2017 11:38:38 +0530 Subject: [PATCH 066/120] Added "none" to language whitelist --- bigchaindb/backend/schema.py | 49 +++++++++++++----- bigchaindb/common/utils.py | 96 +++++++++++++++++++++++++++++++++++- 2 files changed, 131 insertions(+), 14 deletions(-) diff --git a/bigchaindb/backend/schema.py b/bigchaindb/backend/schema.py index 3b7413a2..07fe4210 100644 --- a/bigchaindb/backend/schema.py +++ b/bigchaindb/backend/schema.py @@ -17,13 +17,14 @@ import logging import bigchaindb from bigchaindb.backend.connection import connect from bigchaindb.common.exceptions import ValidationError +from bigchaindb.common.utils import validate_all_value_for_key logger = logging.getLogger(__name__) TABLES = ('bigchain', 'backlog', 'votes', 'assets') VALID_LANGUAGES = ('danish', 'dutch', 'english', 'finnish', 'french', 'german', 'hungarian', 'italian', 'norwegian', 'portuguese', 'romanian', - 'russian', 'spanish', 'swedish', 'turkish', + 'russian', 'spanish', 'swedish', 'turkish', 'none', 'da', 'nl', 'en', 'fi', 'fr', 'de', 'hu', 'it', 'nb', 'pt', 'ro', 'ru', 'es', 'sv', 'tr') @@ -107,19 +108,41 @@ def init_database(connection=None, dbname=None): create_indexes(connection, dbname) -def validate_if_exists_asset_language(tx_body): - data = tx_body['asset'].get('data', {}) +def validate_if_exists_language(obj, key): + """Validate all nested "language" key in `obj`. - if data and ('language' in data): + Args: + obj (dict): dictonary whose "language" key is to be validated. - language = data.get('language') - backend = bigchaindb.config['database']['backend'] + Returns: + None: validation successfull - if (backend == 'mongodb') and (language not in VALID_LANGUAGES): - error_str = ('MongoDB does not support text search for the ' - 'language "{}". If you do not understand this error ' - 'message then please rename key/field "language" to ' - 'something else like "lang".').format(language) - raise ValidationError(error_str) from ValueError() + Raises: + ValidationError: raises execption incase language is not valid. + """ + backend = bigchaindb.config['database']['backend'] - return + if backend == 'mongodb': + data = obj.get(key, {}) or {} + validate_all_value_for_key(data, 'language', validate_language) + + +def validate_language(value): + """Check if `value` is a valid language + https://docs.mongodb.com/manual/reference/text-search-languages/ + + Args: + value (str): language to validated + + Returns: + None: validation successfull + + Raises: + ValidationError: raises execption incase language is not valid. + """ + if value not in VALID_LANGUAGES: + error_str = ('MongoDB does not support text search for the ' + 'language "{}". If you do not understand this error ' + 'message then please rename key/field "language" to ' + 'something else like "lang".').format(value) + raise ValidationError(error_str) from ValueError() diff --git a/bigchaindb/common/utils.py b/bigchaindb/common/utils.py index f6f671db..00621b2e 100644 --- a/bigchaindb/common/utils.py +++ b/bigchaindb/common/utils.py @@ -1,7 +1,10 @@ import time - +import re import rapidjson +import bigchaindb +from bigchaindb.common.exceptions import ValidationError + def gen_timestamp(): """The Unix time, rounded to the nearest second. @@ -46,3 +49,94 @@ def deserialize(data): string. """ return rapidjson.loads(data) + + +def validate_txn_obj(obj_name, obj, key, validation_fun): + """Validates value associated to `key` in `obj` by applying + `validation_fun`. + + Args: + obj_name (str): name for `obj` being validated. + obj (dict): dictonary object. + key (str): key to be validated in `obj`. + validation_fun (function): function used to validate the value + of `key`. + + Returns: + None: indicates validation successfull + + Raises: + ValidationError: `validation_fun` will raise this error on failure + """ + backend = bigchaindb.config['database']['backend'] + + if backend == 'mongodb': + data = obj.get(key, {}) or {} + validate_all_keys(obj_name, data, validation_fun) + + +def validate_all_keys(obj_name, obj, validation_fun): + """Validates all (nested) keys in `obj` by using `validation_fun` + + Args: + obj_name (str): name for `obj` being validated. + obj (dict): dictonary object. + validation_fun (function): function used to validate the value + of `key`. + + Returns: + None: indicates validation successfull + + Raises: + ValidationError: `validation_fun` will raise this error on failure + """ + for key, value in obj.items(): + validation_fun(obj_name, key) + if type(value) is dict: + validate_all_keys(obj_name, value, validation_fun) + return + + +def validate_all_value_for_key(obj, key, validation_fun): + """Validates value for all (nested) occurences of `key` in `obj` + using `validation_fun` + + Args: + obj (dict): dictonary object. + key (str): key whose value is to be validated. + validation_fun (function): function used to validate the value + of `key`. + + Returns: + None: indicates validation successfull + + Raises: + ValidationError: `validation_fun` will raise this error on failure + """ + for vkey, value in obj.items(): + if vkey == key: + validation_fun(value) + elif type(value) is dict: + validate_all_value_for_key(value, key, validation_fun) + return + + +def validate_key(obj_name, key): + """Check if `key` contains ".", "$" or null characters + https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names + + Args: + obj_name (str): object name to use when raising exception + key (str): key to validated + + Returns: + None: indicates validation successfull + + Raises: + ValidationError: raise execption incase of regex match. + """ + if re.search(r'^[$]|\.|\x00', key): + error_str = ('Invalid key name "{}" in {} object. The ' + 'key name cannot contain characters ' + '".", "$" or null characters').format(key, obj_name) + raise ValidationError(error_str) from ValueError() From 3b33cdb111fb1f749b5e1e2971970fd89da5362d Mon Sep 17 00:00:00 2001 From: Trent McConaghy Date: Fri, 3 Nov 2017 13:48:08 +0100 Subject: [PATCH 067/120] Update bft.md --- docs/root/source/bft.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/root/source/bft.md b/docs/root/source/bft.md index 1f1a9bab..fce8ca3d 100644 --- a/docs/root/source/bft.md +++ b/docs/root/source/bft.md @@ -1,6 +1,8 @@ # BigchainDB and Byzantine Fault Tolerance -While BigchainDB is not currently [Byzantine fault tolerant (BFT)](https://en.wikipedia.org/wiki/Byzantine_fault_tolerance), we plan to offer it as an option. -We anticipate that turning it on will cause a severe dropoff in performance. See [Issue #293](https://github.com/bigchaindb/bigchaindb/issues/293). +While BigchainDB is not currently [Byzantine fault tolerant (BFT)](https://en.wikipedia.org/wiki/Byzantine_fault_tolerance), we plan to offer it as an option. +Update Nov 2017: we're actively working on this, the next release or two will likely have support. More details to come in blog form and github issues + +Related issue: [Issue #293](https://github.com/bigchaindb/bigchaindb/issues/293). We anticipate that turning on BFT will cause a dropoff in performance (for a gain in security). In the meantime, there are practical things that one can do to increase security (e.g. firewalls, key management, and access controls). From a29fd7e84f61f6df299faf4d955596edb090a8e7 Mon Sep 17 00:00:00 2001 From: kansi Date: Fri, 3 Nov 2017 18:37:19 +0530 Subject: [PATCH 068/120] Fix variable type check and docstrings --- bigchaindb/backend/schema.py | 8 ++++---- bigchaindb/common/utils.py | 11 +++-------- bigchaindb/models.py | 4 ++-- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/bigchaindb/backend/schema.py b/bigchaindb/backend/schema.py index 07fe4210..fcad33a6 100644 --- a/bigchaindb/backend/schema.py +++ b/bigchaindb/backend/schema.py @@ -108,14 +108,14 @@ def init_database(connection=None, dbname=None): create_indexes(connection, dbname) -def validate_if_exists_language(obj, key): +def validate_language_key(obj, key): """Validate all nested "language" key in `obj`. Args: obj (dict): dictonary whose "language" key is to be validated. Returns: - None: validation successfull + None: validation successful Raises: ValidationError: raises execption incase language is not valid. @@ -135,7 +135,7 @@ def validate_language(value): value (str): language to validated Returns: - None: validation successfull + None: validation successful Raises: ValidationError: raises execption incase language is not valid. @@ -145,4 +145,4 @@ def validate_language(value): 'language "{}". If you do not understand this error ' 'message then please rename key/field "language" to ' 'something else like "lang".').format(value) - raise ValidationError(error_str) from ValueError() + raise ValidationError(error_str) diff --git a/bigchaindb/common/utils.py b/bigchaindb/common/utils.py index 00621b2e..b21f41d6 100644 --- a/bigchaindb/common/utils.py +++ b/bigchaindb/common/utils.py @@ -92,9 +92,8 @@ def validate_all_keys(obj_name, obj, validation_fun): """ for key, value in obj.items(): validation_fun(obj_name, key) - if type(value) is dict: + if isinstance(value, dict): validate_all_keys(obj_name, value, validation_fun) - return def validate_all_value_for_key(obj, key, validation_fun): @@ -107,18 +106,14 @@ def validate_all_value_for_key(obj, key, validation_fun): validation_fun (function): function used to validate the value of `key`. - Returns: - None: indicates validation successfull - Raises: ValidationError: `validation_fun` will raise this error on failure """ for vkey, value in obj.items(): if vkey == key: validation_fun(value) - elif type(value) is dict: + elif isinstance(value, dict): validate_all_value_for_key(value, key, validation_fun) - return def validate_key(obj_name, key): @@ -139,4 +134,4 @@ def validate_key(obj_name, key): error_str = ('Invalid key name "{}" in {} object. The ' 'key name cannot contain characters ' '".", "$" or null characters').format(key, obj_name) - raise ValidationError(error_str) from ValueError() + raise ValidationError(error_str) diff --git a/bigchaindb/models.py b/bigchaindb/models.py index 152a8bcd..8e7a6bde 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -11,7 +11,7 @@ from bigchaindb.common.transaction import Transaction from bigchaindb.common.utils import (gen_timestamp, serialize, validate_txn_obj, validate_key) from bigchaindb.common.schema import validate_transaction_schema -from bigchaindb.backend.schema import validate_if_exists_language +from bigchaindb.backend.schema import validate_language_key class Transaction(Transaction): @@ -88,7 +88,7 @@ class Transaction(Transaction): validate_transaction_schema(tx_body) validate_txn_obj('asset', tx_body['asset'], 'data', validate_key) validate_txn_obj('metadata', tx_body, 'metadata', validate_key) - validate_if_exists_language(tx_body['asset'], 'data') + validate_language_key(tx_body['asset'], 'data') return super().from_dict(tx_body) @classmethod From e2c2c4b097e3e77fb35c8af44b1c5052229df0b7 Mon Sep 17 00:00:00 2001 From: kansi Date: Fri, 3 Nov 2017 19:15:32 +0530 Subject: [PATCH 069/120] Fix spell errors. --- bigchaindb/backend/schema.py | 12 ++++++------ bigchaindb/common/utils.py | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/bigchaindb/backend/schema.py b/bigchaindb/backend/schema.py index fcad33a6..0e2815db 100644 --- a/bigchaindb/backend/schema.py +++ b/bigchaindb/backend/schema.py @@ -17,7 +17,7 @@ import logging import bigchaindb from bigchaindb.backend.connection import connect from bigchaindb.common.exceptions import ValidationError -from bigchaindb.common.utils import validate_all_value_for_key +from bigchaindb.common.utils import validate_all_values_for_key logger = logging.getLogger(__name__) @@ -112,23 +112,23 @@ def validate_language_key(obj, key): """Validate all nested "language" key in `obj`. Args: - obj (dict): dictonary whose "language" key is to be validated. + obj (dict): dictionary whose "language" key is to be validated. Returns: None: validation successful Raises: - ValidationError: raises execption incase language is not valid. + ValidationError: will raise exception in case language is not valid. """ backend = bigchaindb.config['database']['backend'] if backend == 'mongodb': data = obj.get(key, {}) or {} - validate_all_value_for_key(data, 'language', validate_language) + validate_all_values_for_key(data, 'language', validate_language) def validate_language(value): - """Check if `value` is a valid language + """Check if `value` is a valid language. https://docs.mongodb.com/manual/reference/text-search-languages/ Args: @@ -138,7 +138,7 @@ def validate_language(value): None: validation successful Raises: - ValidationError: raises execption incase language is not valid. + ValidationError: will raise exception in case language is not valid. """ if value not in VALID_LANGUAGES: error_str = ('MongoDB does not support text search for the ' diff --git a/bigchaindb/common/utils.py b/bigchaindb/common/utils.py index b21f41d6..b1aa5c12 100644 --- a/bigchaindb/common/utils.py +++ b/bigchaindb/common/utils.py @@ -52,21 +52,20 @@ def deserialize(data): def validate_txn_obj(obj_name, obj, key, validation_fun): - """Validates value associated to `key` in `obj` by applying - `validation_fun`. + """Validate value of `key` in `obj` using `validation_fun`. Args: obj_name (str): name for `obj` being validated. - obj (dict): dictonary object. + obj (dict): dictionary object. key (str): key to be validated in `obj`. validation_fun (function): function used to validate the value of `key`. Returns: - None: indicates validation successfull + None: indicates validation successful Raises: - ValidationError: `validation_fun` will raise this error on failure + ValidationError: `validation_fun` will raise exception on failure """ backend = bigchaindb.config['database']['backend'] @@ -76,16 +75,16 @@ def validate_txn_obj(obj_name, obj, key, validation_fun): def validate_all_keys(obj_name, obj, validation_fun): - """Validates all (nested) keys in `obj` by using `validation_fun` + """Validate all (nested) keys in `obj` by using `validation_fun`. Args: obj_name (str): name for `obj` being validated. - obj (dict): dictonary object. + obj (dict): dictionary object. validation_fun (function): function used to validate the value of `key`. Returns: - None: indicates validation successfull + None: indicates validation successful Raises: ValidationError: `validation_fun` will raise this error on failure @@ -96,12 +95,12 @@ def validate_all_keys(obj_name, obj, validation_fun): validate_all_keys(obj_name, value, validation_fun) -def validate_all_value_for_key(obj, key, validation_fun): - """Validates value for all (nested) occurences of `key` in `obj` - using `validation_fun` +def validate_all_values_for_key(obj, key, validation_fun): + """Validate value for all (nested) occurrence of `key` in `obj` + using `validation_fun`. Args: - obj (dict): dictonary object. + obj (dict): dictionary object. key (str): key whose value is to be validated. validation_fun (function): function used to validate the value of `key`. @@ -113,11 +112,12 @@ def validate_all_value_for_key(obj, key, validation_fun): if vkey == key: validation_fun(value) elif isinstance(value, dict): - validate_all_value_for_key(value, key, validation_fun) + validate_all_values_for_key(value, key, validation_fun) def validate_key(obj_name, key): - """Check if `key` contains ".", "$" or null characters + """Check if `key` contains ".", "$" or null characters. + https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names Args: @@ -125,10 +125,10 @@ def validate_key(obj_name, key): key (str): key to validated Returns: - None: indicates validation successfull + None: validation successful Raises: - ValidationError: raise execption incase of regex match. + ValidationError: will raise exception in case of regex match. """ if re.search(r'^[$]|\.|\x00', key): error_str = ('Invalid key name "{}" in {} object. The ' From 7941922ac04ea7173f9fcdd2dcdf3e08458c6ab0 Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 6 Nov 2017 10:43:54 +0530 Subject: [PATCH 070/120] Added type validation for data --- bigchaindb/backend/schema.py | 5 +++-- bigchaindb/common/utils.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bigchaindb/backend/schema.py b/bigchaindb/backend/schema.py index 0e2815db..4f2ebd6c 100644 --- a/bigchaindb/backend/schema.py +++ b/bigchaindb/backend/schema.py @@ -123,8 +123,9 @@ def validate_language_key(obj, key): backend = bigchaindb.config['database']['backend'] if backend == 'mongodb': - data = obj.get(key, {}) or {} - validate_all_values_for_key(data, 'language', validate_language) + data = obj.get(key, {}) + if isinstance(data, dict): + validate_all_values_for_key(data, 'language', validate_language) def validate_language(value): diff --git a/bigchaindb/common/utils.py b/bigchaindb/common/utils.py index b1aa5c12..9ad448f5 100644 --- a/bigchaindb/common/utils.py +++ b/bigchaindb/common/utils.py @@ -70,8 +70,9 @@ def validate_txn_obj(obj_name, obj, key, validation_fun): backend = bigchaindb.config['database']['backend'] if backend == 'mongodb': - data = obj.get(key, {}) or {} - validate_all_keys(obj_name, data, validation_fun) + data = obj.get(key, {}) + if isinstance(data, dict): + validate_all_keys(obj_name, data, validation_fun) def validate_all_keys(obj_name, obj, validation_fun): From 3cbec5a864f004b5e35d2c6b45acb7bcecb059dd Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 6 Nov 2017 12:06:01 +0530 Subject: [PATCH 071/120] Updated metadata and asset model docs --- docs/server/source/data-models/asset-model.md | 8 ++++++++ docs/server/source/data-models/transaction-model.rst | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/docs/server/source/data-models/asset-model.md b/docs/server/source/data-models/asset-model.md index eefa81bb..2d7ac1e8 100644 --- a/docs/server/source/data-models/asset-model.md +++ b/docs/server/source/data-models/asset-model.md @@ -18,3 +18,11 @@ In a `TRANSFER` transaction, the `"asset"` must contain exactly one key-value pa "id": "38100137cea87fb9bd751e2372abb2c73e7d5bcf39d940a5516a324d9c7fb88d" } ``` + + +.. note:: + + When using MongoDB for storage certain restriction apply to all (including nested) keys of `"data"` JSON document i.e. valid keys should **not** begin with ``$`` character and cannot contain ``.`` or null character (Unicode code point 0000). Furthermore, the key `"language"` (at any level in the hierarchy) in `"data"` JSON document is a spcial key and used for specifying text search language. Its value must be one of the allowed values, see `Text search languages `_ . It must be noted that only the languages supported by MongoDB community edition are allowed. + + + diff --git a/docs/server/source/data-models/transaction-model.rst b/docs/server/source/data-models/transaction-model.rst index 38e523bd..2b28b592 100644 --- a/docs/server/source/data-models/transaction-model.rst +++ b/docs/server/source/data-models/transaction-model.rst @@ -46,6 +46,10 @@ Here's some explanation of the contents: - **metadata**: User-provided transaction metadata. It can be any valid JSON document, or ``null``. + **NOTE** when using MongoDB for storage certain restriction apply to all + (including nested) keys of ``"metadata"`` JSON document i.e. valid keys + should **not** begin with ``$`` character and cannot contain ``.`` or + null character (Unicode code point 0000). **How the transaction ID is computed.** 1) Build a Python dictionary containing ``version``, ``inputs``, ``outputs``, ``operation``, ``asset``, ``metadata`` and their values, From c616145a66e3407fa3f12bc52560cc607548041a Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Mon, 6 Nov 2017 12:12:16 +0100 Subject: [PATCH 072/120] pyyaml>=3.12 in docs/server/requirements.txt --- docs/server/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/server/requirements.txt b/docs/server/requirements.txt index 5ca634a4..cd06eab9 100644 --- a/docs/server/requirements.txt +++ b/docs/server/requirements.txt @@ -3,5 +3,5 @@ recommonmark>=0.4.0 sphinx-rtd-theme>=0.1.9 sphinxcontrib-napoleon>=0.4.4 sphinxcontrib-httpdomain>=1.5.0 -pyyaml +pyyaml>=3.12 bigchaindb From 636c28d31177121d382859ad27b35935a9d92e16 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Mon, 6 Nov 2017 14:22:17 +0100 Subject: [PATCH 073/120] Edited changes to the docs about the asset model --- docs/server/source/data-models/asset-model.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/server/source/data-models/asset-model.md b/docs/server/source/data-models/asset-model.md index 2d7ac1e8..054a4083 100644 --- a/docs/server/source/data-models/asset-model.md +++ b/docs/server/source/data-models/asset-model.md @@ -2,6 +2,8 @@ To avoid redundant data in transactions, the asset model is different for `CREATE` and `TRANSFER` transactions. +## In CREATE Transactions + In a `CREATE` transaction, the `"asset"` must contain exactly one key-value pair. The key must be `"data"` and the value can be any valid JSON document, or `null`. For example: ```json { @@ -12,17 +14,18 @@ In a `CREATE` transaction, the `"asset"` must contain exactly one key-value pair } ``` +When using MongoDB for storage, certain restriction apply to all (including nested) keys of the `"data"` JSON document: + +* Keys (i.e. key names, not values) must **not** begin with the `$` character. +* Keys must not contain `.` or the null character (Unicode code point 0000). +* The key `"language"` (at any level in the hierarchy) is a special key and used for specifying text search language. Its value must be one of the allowed values; see the valid [Text Search Languages](https://docs.mongodb.com/manual/reference/text-search-languages/) in the MongoDB Docs. In BigchainDB, only the languages supported by _MongoDB community edition_ are allowed. + + +## In TRANSFER Transactions + In a `TRANSFER` transaction, the `"asset"` must contain exactly one key-value pair. They key must be `"id"` and the value must contain a transaction ID (i.e. a SHA3-256 hash: the ID of the `CREATE` transaction which created the asset, which also serves as the asset ID). For example: ```json { "id": "38100137cea87fb9bd751e2372abb2c73e7d5bcf39d940a5516a324d9c7fb88d" } ``` - - -.. note:: - - When using MongoDB for storage certain restriction apply to all (including nested) keys of `"data"` JSON document i.e. valid keys should **not** begin with ``$`` character and cannot contain ``.`` or null character (Unicode code point 0000). Furthermore, the key `"language"` (at any level in the hierarchy) in `"data"` JSON document is a spcial key and used for specifying text search language. Its value must be one of the allowed values, see `Text search languages `_ . It must be noted that only the languages supported by MongoDB community edition are allowed. - - - From cae883e9cbca276f491fbf0412b3997be3b74e5b Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Mon, 6 Nov 2017 14:30:01 +0100 Subject: [PATCH 074/120] Edited the changes to transaction model docs --- docs/server/source/data-models/transaction-model.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/server/source/data-models/transaction-model.rst b/docs/server/source/data-models/transaction-model.rst index 2b28b592..b4f2a4f1 100644 --- a/docs/server/source/data-models/transaction-model.rst +++ b/docs/server/source/data-models/transaction-model.rst @@ -46,10 +46,10 @@ Here's some explanation of the contents: - **metadata**: User-provided transaction metadata. It can be any valid JSON document, or ``null``. - **NOTE** when using MongoDB for storage certain restriction apply to all - (including nested) keys of ``"metadata"`` JSON document i.e. valid keys - should **not** begin with ``$`` character and cannot contain ``.`` or - null character (Unicode code point 0000). + **NOTE:** When using MongoDB for storage, certain restriction apply + to all (including nested) keys of the ``"data"`` JSON document: + 1) keys (i.e. key names, not values) must **not** begin with the ``$`` character, and + 2) keys must not contain ``.`` or the null character (Unicode code point 0000). **How the transaction ID is computed.** 1) Build a Python dictionary containing ``version``, ``inputs``, ``outputs``, ``operation``, ``asset``, ``metadata`` and their values, From d9d058522856ae450d31f6a637336a348b239e7e Mon Sep 17 00:00:00 2001 From: kansi Date: Mon, 6 Nov 2017 20:20:06 +0530 Subject: [PATCH 075/120] Added metadata table for mongodb --- bigchaindb/backend/mongodb/query.py | 18 ++++++ bigchaindb/backend/mongodb/schema.py | 17 +++++- bigchaindb/backend/query.py | 27 +++++++++ bigchaindb/backend/rethinkdb/query.py | 14 +++++ bigchaindb/backend/rethinkdb/schema.py | 2 +- bigchaindb/backend/schema.py | 2 +- bigchaindb/core.py | 33 ++++++++++ bigchaindb/models.py | 84 +++++++++++++++++++++++++- tests/backend/mongodb/test_queries.py | 1 + tests/backend/mongodb/test_schema.py | 4 +- tests/backend/test_generics.py | 2 + tests/integration/test_integration.py | 4 +- 12 files changed, 201 insertions(+), 7 deletions(-) diff --git a/bigchaindb/backend/mongodb/query.py b/bigchaindb/backend/mongodb/query.py index 673f643f..73dfbd0c 100644 --- a/bigchaindb/backend/mongodb/query.py +++ b/bigchaindb/backend/mongodb/query.py @@ -265,6 +265,16 @@ def write_assets(conn, assets): return +@register_query(MongoDBConnection) +def write_metadata(conn, metadata): + try: + return conn.run( + conn.collection('metadata') + .insert_many(metadata, ordered=False)) + except OperationError: + return + + @register_query(MongoDBConnection) def get_assets(conn, asset_ids): return conn.run( @@ -273,6 +283,14 @@ def get_assets(conn, asset_ids): projection={'_id': False})) +@register_query(MongoDBConnection) +def get_metadata(conn, txn_ids): + return conn.run( + conn.collection('metadata') + .find({'id': {'$in': txn_ids}}, + projection={'_id': False})) + + @register_query(MongoDBConnection) def count_blocks(conn): return conn.run( diff --git a/bigchaindb/backend/mongodb/schema.py b/bigchaindb/backend/mongodb/schema.py index 572acff9..e55d01a8 100644 --- a/bigchaindb/backend/mongodb/schema.py +++ b/bigchaindb/backend/mongodb/schema.py @@ -27,7 +27,7 @@ def create_database(conn, dbname): @register_schema(MongoDBConnection) def create_tables(conn, dbname): - for table_name in ['bigchain', 'backlog', 'votes', 'assets']: + for table_name in ['bigchain', 'backlog', 'votes', 'assets', 'metadata']: logger.info('Create `%s` table.', table_name) # create the table # TODO: read and write concerns can be declared here @@ -40,6 +40,7 @@ def create_indexes(conn, dbname): create_backlog_secondary_index(conn, dbname) create_votes_secondary_index(conn, dbname) create_assets_secondary_index(conn, dbname) + create_metadata_secondary_index(conn, dbname) @register_schema(MongoDBConnection) @@ -121,3 +122,17 @@ def create_assets_secondary_index(conn, dbname): # full text search index conn.conn[dbname]['assets'].create_index([('$**', TEXT)], name='text') + + +def create_metadata_secondary_index(conn, dbname): + logger.info('Create `metadata` secondary index.') + + # unique index on the id of the metadata. + # the id is the txid of the transaction for which the metadata + # was specified + conn.conn[dbname]['metadata'].create_index('id', + name='transaction_id', + unique=True) + + # full text search index + conn.conn[dbname]['metadata'].create_index([('$**', TEXT)], name='text') diff --git a/bigchaindb/backend/query.py b/bigchaindb/backend/query.py index 0528da3b..dc70e0b4 100644 --- a/bigchaindb/backend/query.py +++ b/bigchaindb/backend/query.py @@ -254,6 +254,19 @@ def write_assets(connection, assets): raise NotImplementedError +@singledispatch +def write_metadata(connection, metadata): + """Write a list of metadata to the metadata table. + + Args: + metadata (list): a list of metadata to write. + + Returns: + The database response. + """ + raise NotImplementedError + + @singledispatch def get_assets(connection, asset_ids): """Get a list of assets from the assets table. @@ -268,6 +281,20 @@ def get_assets(connection, asset_ids): raise NotImplementedError +@singledispatch +def get_metadata(connection, txn_ids): + """Get a list of metadata from the metadata table. + + Args: + txn_ids (list): a list of ids for the metadata to be retrieved from + the database. + + Returns: + metadata (list): the list of returned metadata. + """ + raise NotImplementedError + + @singledispatch def count_blocks(connection): """Count the number of blocks in the bigchain table. diff --git a/bigchaindb/backend/rethinkdb/query.py b/bigchaindb/backend/rethinkdb/query.py index cac9cc94..6a572d0c 100644 --- a/bigchaindb/backend/rethinkdb/query.py +++ b/bigchaindb/backend/rethinkdb/query.py @@ -173,6 +173,13 @@ def write_assets(connection, assets): .insert(assets, durability=WRITE_DURABILITY)) +@register_query(RethinkDBConnection) +def write_metadata(connection, metadata): + return connection.run( + r.table('metadata') + .insert(metadata, durability=WRITE_DURABILITY)) + + @register_query(RethinkDBConnection) def get_assets(connection, asset_ids): return connection.run( @@ -180,6 +187,13 @@ def get_assets(connection, asset_ids): .get_all(*asset_ids)) +@register_query(RethinkDBConnection) +def get_metadata(connection, txn_ids): + return connection.run( + r.table('metadata', read_mode=READ_MODE) + .get_all(*txn_ids)) + + @register_query(RethinkDBConnection) def count_blocks(connection): return connection.run( diff --git a/bigchaindb/backend/rethinkdb/schema.py b/bigchaindb/backend/rethinkdb/schema.py index ea6f4e25..04534857 100644 --- a/bigchaindb/backend/rethinkdb/schema.py +++ b/bigchaindb/backend/rethinkdb/schema.py @@ -23,7 +23,7 @@ def create_database(connection, dbname): @register_schema(RethinkDBConnection) def create_tables(connection, dbname): - for table_name in ['bigchain', 'backlog', 'votes', 'assets']: + for table_name in ['bigchain', 'backlog', 'votes', 'assets', 'metadata']: logger.info('Create `%s` table.', table_name) connection.run(r.db(dbname).table_create(table_name)) diff --git a/bigchaindb/backend/schema.py b/bigchaindb/backend/schema.py index f6ce466f..8192f6cb 100644 --- a/bigchaindb/backend/schema.py +++ b/bigchaindb/backend/schema.py @@ -19,7 +19,7 @@ from bigchaindb.backend.connection import connect logger = logging.getLogger(__name__) -TABLES = ('bigchain', 'backlog', 'votes', 'assets') +TABLES = ('bigchain', 'backlog', 'votes', 'assets', 'metadata') @singledispatch diff --git a/bigchaindb/core.py b/bigchaindb/core.py index af9a9f36..49ae59b2 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -190,10 +190,15 @@ class Bigchain(object): # get the asset ids from the block if block_dict: asset_ids = Block.get_asset_ids(block_dict) + txn_ids = Block.get_txn_ids(block_dict) # get the assets from the database assets = self.get_assets(asset_ids) + # get the metadata from the database + metadata = self.get_metadata(txn_ids) # add the assets to the block transactions block_dict = Block.couple_assets(block_dict, assets) + # add the metadata to the block transactions + block_dict = Block.couple_metadata(block_dict, metadata) status = None if include_status: @@ -508,10 +513,15 @@ class Bigchain(object): # Decouple assets from block assets, block_dict = block.decouple_assets() + metadatas, block_dict = block.decouple_metadata(block_dict) + # write the assets if assets: self.write_assets(assets) + if metadatas: + self.write_metadata(metadatas) + # write the block return backend.query.write_block(self.connection, block_dict) @@ -622,6 +632,19 @@ class Bigchain(object): """ return backend.query.get_assets(self.connection, asset_ids) + def get_metadata(self, txn_ids): + """ + Return a list of metadata that match the transaction ids (txn_ids) + + Args: + txn_ids (:obj:`list` of :obj:`str`): A list of txn_ids to + retrieve from the database. + + Returns: + list: The list of metadata returned from the database. + """ + return backend.query.get_metadata(self.connection, txn_ids) + def write_assets(self, assets): """ Writes a list of assets into the database. @@ -632,6 +655,16 @@ class Bigchain(object): """ return backend.query.write_assets(self.connection, assets) + def write_metadata(self, metadata): + """ + Writes a list of metadata into the database. + + Args: + metadata (:obj:`list` of :obj:`dict`): A list of metadata to write to + the database. + """ + return backend.query.write_metadata(self.connection, metadata) + def text_search(self, search, *, limit=0): """ Return an iterator of assets that match the text search diff --git a/bigchaindb/models.py b/bigchaindb/models.py index 1ecd964e..981f7379 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -47,7 +47,9 @@ class Transaction(Transaction): 'input `{}` does not exist in a valid block'.format( input_txid)) + print(input_txid, self.id) spent = bigchain.get_spent(input_txid, input_.fulfills.output) + print(spent) if spent and spent.id != self.id: raise DoubleSpend('input `{}` was already spent' .format(input_txid)) @@ -112,6 +114,13 @@ class Transaction(Transaction): del asset['id'] tx_dict.update({'asset': asset}) + # get metadata of the transaction + metadata = list(bigchain.get_metadata([tx_dict['id']])) + if metadata: + metadata = metadata[0] + del metadata['id'] + tx_dict.update({'metadata': metadata}) + return cls.from_dict(tx_dict) @@ -350,11 +359,15 @@ class Block(object): """ asset_ids = cls.get_asset_ids(block_dict) assets = bigchain.get_assets(asset_ids) + txn_ids = cls.get_txn_ids(block_dict) + metadata = bigchain.get_metadata(txn_ids) + # reconstruct block block_dict = cls.couple_assets(block_dict, assets) + block_dict = cls.couple_metadata(block_dict, metadata) kwargs = from_dict_kwargs or {} return cls.from_dict(block_dict, **kwargs) - def decouple_assets(self): + def decouple_assets(self, block_dict=None): """ Extracts the assets from the ``CREATE`` transactions in the block. @@ -363,6 +376,9 @@ class Block(object): the block being the dict of the block with no assets in the CREATE transactions. """ + if block_dict is None: + block_dict = deepcopy(self.to_dict()) + block_dict = deepcopy(self.to_dict()) assets = [] for transaction in block_dict['block']['transactions']: @@ -374,6 +390,28 @@ class Block(object): return (assets, block_dict) + def decouple_metadata(self, block_dict=None): + """ + Extracts the metadata from transactions in the block. + + Returns: + tuple: (metadatas, block) with the metadatas being a list of dict/null and + the block being the dict of the block with no metadata in any transaction. + """ + if block_dict is None: + block_dict = deepcopy(self.to_dict()) + + metadatas = [] + for transaction in block_dict['block']['transactions']: + metadata = transaction.pop('metadata') + if isinstance(metadata, dict): + metadata.update({'id': transaction['id']}) + metadatas.append(metadata) + else: + transaction.update({'metadata': metadata}) + + return (metadatas, block_dict) + @staticmethod def couple_assets(block_dict, assets): """ @@ -399,6 +437,31 @@ class Block(object): transaction.update({'asset': assets.get(transaction['id'])}) return block_dict + @staticmethod + def couple_metadata(block_dict, metadatal): + """ + Given a block_dict with no metadata (as returned from a database call) + and a list of metadata, reconstruct the original block by putting the + metadata of each transaction back into its original transaction. + + Args: + block_dict (:obj:`dict`): The block dict as returned from a + database call. + metadata (:obj:`list` of :obj:`dict`): A list of metadata returned from + a database call. + + Returns: + dict: The dict of the reconstructed block. + """ + # create a dict with {'': metadata} + metadatal = {m.pop('id'): m for m in metadatal} + # add the metadata to their corresponding transactions + for transaction in block_dict['block']['transactions']: + metadata = metadatal.get(transaction['id']) + if metadata: + transaction.update({'metadata': metadata}) + return block_dict + @staticmethod def get_asset_ids(block_dict): """ @@ -422,6 +485,25 @@ class Block(object): return asset_ids + @staticmethod + def get_txn_ids(block_dict): + """ + Given a block_dict return all the transaction ids. + + Args: + block_dict (:obj:`dict`): The block dict as returned from a + database call. + + Returns: + list: The list of txn_ids in the block. + + """ + txn_ids = [] + for transaction in block_dict['block']['transactions']: + txn_ids.append(transaction['id']) + + return txn_ids + def to_str(self): return serialize(self.to_dict()) diff --git a/tests/backend/mongodb/test_queries.py b/tests/backend/mongodb/test_queries.py index 3ea7db28..6e4222f4 100644 --- a/tests/backend/mongodb/test_queries.py +++ b/tests/backend/mongodb/test_queries.py @@ -353,6 +353,7 @@ def test_get_genesis_block(genesis_block): conn = connect() assets, genesis_block_dict = genesis_block.decouple_assets() + metadata, genesis_block_dict = genesis_block.decouple_metadata(genesis_block_dict) assert query.get_genesis_block(conn) == genesis_block_dict diff --git a/tests/backend/mongodb/test_schema.py b/tests/backend/mongodb/test_schema.py index 1a244b1b..471cc583 100644 --- a/tests/backend/mongodb/test_schema.py +++ b/tests/backend/mongodb/test_schema.py @@ -19,7 +19,7 @@ def test_init_creates_db_tables_and_indexes(): collection_names = conn.conn[dbname].collection_names() assert sorted(collection_names) == ['assets', 'backlog', 'bigchain', - 'votes'] + 'metadata', 'votes'] indexes = conn.conn[dbname]['bigchain'].index_information().keys() assert sorted(indexes) == ['_id_', 'asset_id', 'block_id', 'block_timestamp', @@ -67,7 +67,7 @@ def test_create_tables(): collection_names = conn.conn[dbname].collection_names() assert sorted(collection_names) == ['assets', 'backlog', 'bigchain', - 'votes'] + 'metadata', 'votes'] def test_create_secondary_indexes(): diff --git a/tests/backend/test_generics.py b/tests/backend/test_generics.py index 18d4df3e..01f28675 100644 --- a/tests/backend/test_generics.py +++ b/tests/backend/test_generics.py @@ -40,6 +40,8 @@ def test_schema(schema_func_name, args_qty): ('get_spending_transactions', 1), ('write_assets', 1), ('get_assets', 1), + ('write_metadata', 1), + ('get_metadata', 1), )) def test_query(query_func_name, args_qty): from bigchaindb.backend import query diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 2bf0ebcd..836c5970 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -25,6 +25,7 @@ def test_double_create(b, user_pk): assert count_blocks(b.connection) == 2 +@pytest.mark.dspend @pytest.mark.usefixtures('inputs') def test_get_owned_ids_works_after_double_spend(b, user_pk, user_sk): """ Test for #633 https://github.com/bigchaindb/bigchaindb/issues/633 """ @@ -37,9 +38,10 @@ def test_get_owned_ids_works_after_double_spend(b, user_pk, user_sk): input_valid.id, {'1': 1}).sign([user_sk]) + print(tx_valid) # write the valid tx and wait for voting/block to catch up b.write_transaction(tx_valid) - time.sleep(2) + time.sleep(5) # doesn't throw an exception b.get_owned_ids(user_pk) From 94ce03cbec08ae9d45656990d1d7e6c3e6e05bd0 Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 7 Nov 2017 10:50:07 +0530 Subject: [PATCH 076/120] Decouple metadata from transaction --- bigchaindb/core.py | 7 ++++++ bigchaindb/models.py | 30 ++++++++++++++++---------- tests/backend/mongodb/test_queries.py | 3 ++- tests/backend/rethinkdb/test_schema.py | 3 ++- tests/integration/test_integration.py | 1 - 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 49ae59b2..555b7ebe 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -395,6 +395,13 @@ class Bigchain(object): ' with the chain'.format(txid)) # if its not and invalid transaction if status is not None: + if 'metadata' not in transaction: + metadata = list(self.get_metadata([transaction['id']])) + metadata = metadata[0] if metadata else None + if metadata: + metadata.pop('id', None) + transaction.update({'metadata': metadata}) + non_invalid_transactions.append(transaction) if non_invalid_transactions: diff --git a/bigchaindb/models.py b/bigchaindb/models.py index 981f7379..a1dde131 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -5,7 +5,7 @@ from bigchaindb.common.exceptions import (InvalidHash, InvalidSignature, DoubleSpend, InputDoesNotExist, TransactionNotInValidBlock, AssetIdMismatch, AmountError, - SybilError, + SybilError, ValidationError, DuplicateTransaction) from bigchaindb.common.transaction import Transaction from bigchaindb.common.utils import (gen_timestamp, serialize, @@ -47,9 +47,7 @@ class Transaction(Transaction): 'input `{}` does not exist in a valid block'.format( input_txid)) - print(input_txid, self.id) spent = bigchain.get_spent(input_txid, input_.fulfills.output) - print(spent) if spent and spent.id != self.id: raise DoubleSpend('input `{}` was already spent' .format(input_txid)) @@ -116,9 +114,11 @@ class Transaction(Transaction): # get metadata of the transaction metadata = list(bigchain.get_metadata([tx_dict['id']])) - if metadata: - metadata = metadata[0] - del metadata['id'] + if 'metadata' not in tx_dict: + metadata = metadata[0] if metadata else None + if metadata: + metadata.pop('id', None) + tx_dict.update({'metadata': metadata}) return cls.from_dict(tx_dict) @@ -407,8 +407,8 @@ class Block(object): if isinstance(metadata, dict): metadata.update({'id': transaction['id']}) metadatas.append(metadata) - else: - transaction.update({'metadata': metadata}) + elif metadata: + raise ValidationError('Invalid value for metadata') return (metadatas, block_dict) @@ -444,6 +444,10 @@ class Block(object): and a list of metadata, reconstruct the original block by putting the metadata of each transaction back into its original transaction. + NOTE: Till a transaction gets accepted the `metadata` of the transaction + is not moved outside of the transaction. So, if a transaction is found to + have metadata then it should not be overridden. + Args: block_dict (:obj:`dict`): The block dict as returned from a database call. @@ -457,9 +461,13 @@ class Block(object): metadatal = {m.pop('id'): m for m in metadatal} # add the metadata to their corresponding transactions for transaction in block_dict['block']['transactions']: - metadata = metadatal.get(transaction['id']) - if metadata: - transaction.update({'metadata': metadata}) + if 'metadata' not in transaction: + metadata = metadatal.get(transaction['id']) + if metadata: + metadata.pop('id', None) + transaction.update({'metadata': metadata}) + else: + transaction.update({'metadata': None}) return block_dict @staticmethod diff --git a/tests/backend/mongodb/test_queries.py b/tests/backend/mongodb/test_queries.py index 6e4222f4..fea2c7c4 100644 --- a/tests/backend/mongodb/test_queries.py +++ b/tests/backend/mongodb/test_queries.py @@ -421,7 +421,8 @@ def test_get_new_blocks_feed(b, create_tx): ts = str(random.random()) block = Block(transactions=[create_tx], timestamp=ts) b.write_block(block) - return block.decouple_assets()[1] + block_dict = block.decouple_assets()[1] + return block.decouple_metadata(block_dict)[1] create_block() b1 = create_block() diff --git a/tests/backend/rethinkdb/test_schema.py b/tests/backend/rethinkdb/test_schema.py index 6f77b672..e56dfd21 100644 --- a/tests/backend/rethinkdb/test_schema.py +++ b/tests/backend/rethinkdb/test_schema.py @@ -64,7 +64,8 @@ def test_create_tables(): assert conn.run(r.db(dbname).table_list().contains('backlog')) is True assert conn.run(r.db(dbname).table_list().contains('votes')) is True assert conn.run(r.db(dbname).table_list().contains('assets')) is True - assert len(conn.run(r.db(dbname).table_list())) == 4 + assert conn.run(r.db(dbname).table_list().contains('metadata')) is True + assert len(conn.run(r.db(dbname).table_list())) == 5 @pytest.mark.bdb diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 836c5970..c6eb355a 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -38,7 +38,6 @@ def test_get_owned_ids_works_after_double_spend(b, user_pk, user_sk): input_valid.id, {'1': 1}).sign([user_sk]) - print(tx_valid) # write the valid tx and wait for voting/block to catch up b.write_transaction(tx_valid) time.sleep(5) From 714c1782ace8066200bb97a6463658d58a25178a Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 7 Nov 2017 12:20:51 +0530 Subject: [PATCH 077/120] Support for metadata search api and its testing suite --- bigchaindb/backend/mongodb/query.py | 9 ++- bigchaindb/backend/query.py | 2 +- bigchaindb/core.py | 14 +++-- bigchaindb/web/routes.py | 2 + bigchaindb/web/views/metadata.py | 50 +++++++++++++++ tests/backend/mongodb/test_queries.py | 27 +++++---- tests/web/test_metadata.py | 87 +++++++++++++++++++++++++++ 7 files changed, 169 insertions(+), 22 deletions(-) create mode 100644 bigchaindb/web/views/metadata.py create mode 100644 tests/web/test_metadata.py diff --git a/bigchaindb/backend/mongodb/query.py b/bigchaindb/backend/mongodb/query.py index 73dfbd0c..e59c0311 100644 --- a/bigchaindb/backend/mongodb/query.py +++ b/bigchaindb/backend/mongodb/query.py @@ -366,9 +366,12 @@ def get_new_blocks_feed(conn, start_block_id): @register_query(MongoDBConnection) def text_search(conn, search, *, language='english', case_sensitive=False, - diacritic_sensitive=False, text_score=False, limit=0): + diacritic_sensitive=False, text_score=False, limit=0, table=None): + if table is None: + table = 'assets' + cursor = conn.run( - conn.collection('assets') + conn.collection(table) .find({'$text': { '$search': search, '$language': language, @@ -381,7 +384,7 @@ def text_search(conn, search, *, language='english', case_sensitive=False, if text_score: return cursor - return (_remove_text_score(asset) for asset in cursor) + return (_remove_text_score(obj) for obj in cursor) def _remove_text_score(asset): diff --git a/bigchaindb/backend/query.py b/bigchaindb/backend/query.py index dc70e0b4..7c0318ce 100644 --- a/bigchaindb/backend/query.py +++ b/bigchaindb/backend/query.py @@ -387,7 +387,7 @@ def get_new_blocks_feed(connection, start_block_id): @singledispatch def text_search(conn, search, *, language='english', case_sensitive=False, - diacritic_sensitive=False, text_score=False, limit=0): + diacritic_sensitive=False, text_score=False, limit=0, table=None): """Return all the assets that match the text search. The results are sorted by text score. diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 555b7ebe..78779d42 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -672,7 +672,7 @@ class Bigchain(object): """ return backend.query.write_metadata(self.connection, metadata) - def text_search(self, search, *, limit=0): + def text_search(self, search, *, limit=0, table=None): """ Return an iterator of assets that match the text search @@ -683,12 +683,16 @@ class Bigchain(object): Returns: iter: An iterator of assets that match the text search. """ - assets = backend.query.text_search(self.connection, search, limit=limit) + if table is None: + table = 'assets' + + objects = backend.query.text_search(self.connection, search, limit=limit, + table=table) # TODO: This is not efficient. There may be a more efficient way to # query by storing block ids with the assets and using fastquery. # See https://github.com/bigchaindb/bigchaindb/issues/1496 - for asset in assets: - tx, status = self.get_transaction(asset['id'], True) + for obj in objects: + tx, status = self.get_transaction(obj['id'], True) if status == self.TX_VALID: - yield asset + yield obj diff --git a/bigchaindb/web/routes.py b/bigchaindb/web/routes.py index d1fa6d26..e74c58cd 100644 --- a/bigchaindb/web/routes.py +++ b/bigchaindb/web/routes.py @@ -2,6 +2,7 @@ from flask_restful import Api from bigchaindb.web.views import ( assets, + metadata, blocks, info, statuses, @@ -27,6 +28,7 @@ def r(*args, **kwargs): ROUTES_API_V1 = [ r('/', info.ApiV1Index), r('assets/', assets.AssetListApi), + r('metadata/', metadata.MetadataApi), r('blocks/', blocks.BlockApi), r('blocks/', blocks.BlockListApi), r('statuses/', statuses.StatusApi), diff --git a/bigchaindb/web/views/metadata.py b/bigchaindb/web/views/metadata.py new file mode 100644 index 00000000..1879fabe --- /dev/null +++ b/bigchaindb/web/views/metadata.py @@ -0,0 +1,50 @@ +"""This module provides the blueprint for some basic API endpoints. + +For more information please refer to the documentation: http://bigchaindb.com/http-api +""" +import logging + +from flask_restful import reqparse, Resource +from flask import current_app + +from bigchaindb.backend.exceptions import OperationError +from bigchaindb.web.views.base import make_error + +logger = logging.getLogger(__name__) + + +class MetadataApi(Resource): + def get(self): + """API endpoint to perform a text search on transaction metadata. + + Args: + search (str): Text search string to query the text index + limit (int, optional): Limit the number of returned documents. + + Return: + A list of metadata that match the query. + """ + parser = reqparse.RequestParser() + parser.add_argument('search', type=str, required=True) + parser.add_argument('limit', type=int) + args = parser.parse_args() + + if not args['search']: + return make_error(400, 'text_search cannot be empty') + if not args['limit']: + del args['limit'] + + pool = current_app.config['bigchain_pool'] + + with pool() as bigchain: + args['table'] = 'metadata' + metadata = bigchain.text_search(**args) + + try: + # This only works with MongoDB as the backend + return list(metadata) + except OperationError as e: + return make_error( + 400, + '({}): {}'.format(type(e).__name__, e) + ) diff --git a/tests/backend/mongodb/test_queries.py b/tests/backend/mongodb/test_queries.py index fea2c7c4..113f4249 100644 --- a/tests/backend/mongodb/test_queries.py +++ b/tests/backend/mongodb/test_queries.py @@ -529,13 +529,14 @@ def test_get_assets(): assert list(cursor.sort('id', pymongo.ASCENDING)) == assets[::2] -def test_text_search(): +@pytest.mark.parametrize("table", ['assets', 'metadata']) +def test_text_search(table): from bigchaindb.backend import connect, query conn = connect() # Example data and tests cases taken from the mongodb documentation # https://docs.mongodb.com/manual/reference/operator/query/text/ - assets = [ + objects = [ {'id': 1, 'subject': 'coffee', 'author': 'xyz', 'views': 50}, {'id': 2, 'subject': 'Coffee Shopping', 'author': 'efg', 'views': 5}, {'id': 3, 'subject': 'Baking a cake', 'author': 'abc', 'views': 90}, @@ -547,17 +548,17 @@ def test_text_search(): ] # insert the assets - conn.db.assets.insert_many(deepcopy(assets), ordered=False) + conn.db[table].insert_many(deepcopy(objects), ordered=False) # test search single word - assert list(query.text_search(conn, 'coffee')) == [ + assert list(query.text_search(conn, 'coffee', table=table)) == [ {'id': 1, 'subject': 'coffee', 'author': 'xyz', 'views': 50}, {'id': 2, 'subject': 'Coffee Shopping', 'author': 'efg', 'views': 5}, {'id': 7, 'subject': 'coffee and cream', 'author': 'efg', 'views': 10}, ] # match any of the search terms - assert list(query.text_search(conn, 'bake coffee cake')) == [ + assert list(query.text_search(conn, 'bake coffee cake', table=table)) == [ {'author': 'abc', 'id': 3, 'subject': 'Baking a cake', 'views': 90}, {'author': 'xyz', 'id': 1, 'subject': 'coffee', 'views': 50}, {'author': 'xyz', 'id': 4, 'subject': 'baking', 'views': 100}, @@ -566,48 +567,48 @@ def test_text_search(): ] # search for a phrase - assert list(query.text_search(conn, '\"coffee shop\"')) == [ + assert list(query.text_search(conn, '\"coffee shop\"', table=table)) == [ {'id': 2, 'subject': 'Coffee Shopping', 'author': 'efg', 'views': 5}, ] # exclude documents that contain a term - assert list(query.text_search(conn, 'coffee -shop')) == [ + assert list(query.text_search(conn, 'coffee -shop', table=table)) == [ {'id': 1, 'subject': 'coffee', 'author': 'xyz', 'views': 50}, {'id': 7, 'subject': 'coffee and cream', 'author': 'efg', 'views': 10}, ] # search different language - assert list(query.text_search(conn, 'leche', language='es')) == [ + assert list(query.text_search(conn, 'leche', language='es', table=table)) == [ {'id': 5, 'subject': 'Café Con Leche', 'author': 'abc', 'views': 200}, {'id': 8, 'subject': 'Cafe con Leche', 'author': 'xyz', 'views': 10} ] # case and diacritic insensitive search - assert list(query.text_search(conn, 'сы́рники CAFÉS')) == [ + assert list(query.text_search(conn, 'сы́рники CAFÉS', table=table)) == [ {'id': 6, 'subject': 'Сырники', 'author': 'jkl', 'views': 80}, {'id': 5, 'subject': 'Café Con Leche', 'author': 'abc', 'views': 200}, {'id': 8, 'subject': 'Cafe con Leche', 'author': 'xyz', 'views': 10} ] # case sensitive search - assert list(query.text_search(conn, 'Coffee', case_sensitive=True)) == [ + assert list(query.text_search(conn, 'Coffee', case_sensitive=True, table=table)) == [ {'id': 2, 'subject': 'Coffee Shopping', 'author': 'efg', 'views': 5}, ] # diacritic sensitive search - assert list(query.text_search(conn, 'CAFÉ', diacritic_sensitive=True)) == [ + assert list(query.text_search(conn, 'CAFÉ', diacritic_sensitive=True, table=table)) == [ {'id': 5, 'subject': 'Café Con Leche', 'author': 'abc', 'views': 200}, ] # return text score - assert list(query.text_search(conn, 'coffee', text_score=True)) == [ + assert list(query.text_search(conn, 'coffee', text_score=True, table=table)) == [ {'id': 1, 'subject': 'coffee', 'author': 'xyz', 'views': 50, 'score': 1.0}, {'id': 2, 'subject': 'Coffee Shopping', 'author': 'efg', 'views': 5, 'score': 0.75}, {'id': 7, 'subject': 'coffee and cream', 'author': 'efg', 'views': 10, 'score': 0.75}, ] # limit search result - assert list(query.text_search(conn, 'coffee', limit=2)) == [ + assert list(query.text_search(conn, 'coffee', limit=2, table=table)) == [ {'id': 1, 'subject': 'coffee', 'author': 'xyz', 'views': 50}, {'id': 2, 'subject': 'Coffee Shopping', 'author': 'efg', 'views': 5}, ] diff --git a/tests/web/test_metadata.py b/tests/web/test_metadata.py new file mode 100644 index 00000000..fa551f3e --- /dev/null +++ b/tests/web/test_metadata.py @@ -0,0 +1,87 @@ +import pytest + +METADATA_ENDPOINT = '/api/v1/metadata/' + + +def test_get_metadata_with_empty_text_search(client): + res = client.get(METADATA_ENDPOINT + '?search=') + assert res.json == {'status': 400, + 'message': 'text_search cannot be empty'} + assert res.status_code == 400 + + +def test_get_metadata_with_missing_text_search(client): + res = client.get(METADATA_ENDPOINT) + assert res.status_code == 400 + + +@pytest.mark.genesis +def test_get_metadata(client, b): + from bigchaindb.models import Transaction + from bigchaindb.backend.mongodb.connection import MongoDBConnection + + if isinstance(b.connection, MongoDBConnection): + # test returns empty list when no assets are found + res = client.get(METADATA_ENDPOINT + '?search=abc') + assert res.json == [] + assert res.status_code == 200 + + # create asset + asset = {'msg': 'abc'} + metadata = {'key': 'my_meta'} + tx = Transaction.create([b.me], [([b.me], 1)], metadata=metadata, + asset=asset).sign([b.me_private]) + # create block + block = b.create_block([tx]) + b.write_block(block) + # vote valid + vote = b.vote(block.id, b.get_last_voted_block().id, True) + b.write_vote(vote) + + # test that metadata is returned + res = client.get(METADATA_ENDPOINT + '?search=my_meta') + assert res.status_code == 200 + assert len(res.json) == 1 + assert res.json[0] == { + 'key': 'my_meta', + 'id': tx.id + } + else: + # test that the correct error is returned if not running MongoDB + res = client.get(METADATA_ENDPOINT + '?search=my_meta') + assert res.status_code == 400 + assert res.json['message'].startswith('(OperationError)') + + +@pytest.mark.genesis +def test_get_metadata_limit(client, b): + from bigchaindb.models import Transaction + from bigchaindb.backend.mongodb.connection import MongoDBConnection + + if isinstance(b.connection, MongoDBConnection): + # create two assets + asset1 = {'msg': 'abc 1'} + meta1 = {'key': 'meta 1'} + tx1 = Transaction.create([b.me], [([b.me], 1)], metadata=meta1, + asset=asset1).sign([b.me_private]) + + asset2 = {'msg': 'abc 2'} + meta2 = {'key': 'meta 2'} + tx2 = Transaction.create([b.me], [([b.me], 1)], metadata=meta2, + asset=asset2).sign([b.me_private]) + # create block + block = b.create_block([tx1, tx2]) + b.write_block(block) + # vote valid + vote = b.vote(block.id, b.get_last_voted_block().id, True) + b.write_vote(vote) + + # test that both assets are returned without limit + res = client.get(METADATA_ENDPOINT + '?search=meta') + assert res.status_code == 200 + assert len(res.json) == 2 + + # test that only one asset is returned when using limit=1 + res = client.get(METADATA_ENDPOINT + '?search=meta&limit=1') + assert res.status_code == 200 + assert len(res.json) == 1 From d55004601c6a1e6e8444b73f9ee1f1b3d70dd61e Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 7 Nov 2017 10:17:21 +0100 Subject: [PATCH 078/120] Fix command to run RethinkDB in bg w/ docker-compose --- tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/README.md b/tests/README.md index 252fcda4..9fc9b9d5 100644 --- a/tests/README.md +++ b/tests/README.md @@ -105,7 +105,7 @@ $ docker-compose build First, start `RethinkDB` in the background: ```text -$ docker-compose up -d rdb +$ docker-compose -f docker-compose.rdb.yml up -d rdb ``` then run the tests using: From 6cab2f26e92317f16b97174cb72c6b8e4c5838dd Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 7 Nov 2017 10:20:41 +0100 Subject: [PATCH 079/120] Fix command to run tests w/ docker-compose & bdb-rdb --- tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/README.md b/tests/README.md index 9fc9b9d5..e3c9133c 100644 --- a/tests/README.md +++ b/tests/README.md @@ -111,7 +111,7 @@ $ docker-compose -f docker-compose.rdb.yml up -d rdb then run the tests using: ```text -$ docker-compose run --rm bdb-rdb py.test -v +$ docker-compose -f docker-compose.rdb.yml run --rm bdb-rdb py.test -v ``` to rebuild all the images (usually you only need to rebuild the `bdb` and From 220465f7016bd2b71fb14f0e428a84ef418596c7 Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 7 Nov 2017 14:55:05 +0530 Subject: [PATCH 080/120] Added "--no-init" flag for "bigchaindb start" command --- bigchaindb/commands/bigchaindb.py | 9 +++++---- .../source/appendices/azure-quickstart-template.md | 2 +- docs/server/source/dev-and-test/setup-bdb-host.md | 4 ++-- docs/server/source/quickstart.md | 2 +- docs/server/source/server-reference/bigchaindb-cli.md | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/bigchaindb/commands/bigchaindb.py b/bigchaindb/commands/bigchaindb.py index 9705065c..6320d279 100644 --- a/bigchaindb/commands/bigchaindb.py +++ b/bigchaindb/commands/bigchaindb.py @@ -196,7 +196,7 @@ def run_start(args): logger.info('RethinkDB started with PID %s' % proc.pid) try: - if args.initialize_database: + if not args.skip_initialize_database: logger.info('Initializing database') _run_init() except DatabaseAlreadyExists: @@ -302,10 +302,11 @@ def create_parser(): action='store_true', help='Run RethinkDB on start') - start_parser.add_argument('--init', - dest='initialize_database', + start_parser.add_argument('--no-init', + dest='skip_initialize_database', + default=False, action='store_true', - help='Force initialize database') + help='Skip database initialization') # parser for configuring the number of shards sharding_parser = subparsers.add_parser('set-shards', diff --git a/docs/server/source/appendices/azure-quickstart-template.md b/docs/server/source/appendices/azure-quickstart-template.md index 13cda281..59f52fd3 100644 --- a/docs/server/source/appendices/azure-quickstart-template.md +++ b/docs/server/source/appendices/azure-quickstart-template.md @@ -33,7 +33,7 @@ API Server bind? (default `localhost:9984`): 0.0.0.0:9984 Finally, run BigchainDB Server by doing: ```text -bigchaindb start --init +bigchaindb start ``` BigchainDB Server should now be running on the Azure virtual machine. diff --git a/docs/server/source/dev-and-test/setup-bdb-host.md b/docs/server/source/dev-and-test/setup-bdb-host.md index 5feb8c42..cdee3c0b 100644 --- a/docs/server/source/dev-and-test/setup-bdb-host.md +++ b/docs/server/source/dev-and-test/setup-bdb-host.md @@ -27,7 +27,7 @@ waiting for connections on port 27017 To run BigchainDB Server, do: ```text -$ bigchaindb start --init +$ bigchaindb start ``` You can [run all the unit tests](running-all-tests.html) to test your installation. @@ -55,7 +55,7 @@ You can verify that RethinkDB is running by opening the RethinkDB web interface To run BigchainDB Server, do: ```text -$ bigchaindb start --init +$ bigchaindb start ``` You can [run all the unit tests](running-all-tests.html) to test your installation. diff --git a/docs/server/source/quickstart.md b/docs/server/source/quickstart.md index 2375fd5f..63ab8643 100644 --- a/docs/server/source/quickstart.md +++ b/docs/server/source/quickstart.md @@ -54,7 +54,7 @@ $ bigchaindb -y configure mongodb I. Run BigchainDB Server: ```text -$ bigchaindb start --init +$ bigchaindb start ``` J. Verify BigchainDB Server setup by visiting the BigchainDB Root URL in your browser: diff --git a/docs/server/source/server-reference/bigchaindb-cli.md b/docs/server/source/server-reference/bigchaindb-cli.md index fddfd3f5..790cb453 100644 --- a/docs/server/source/server-reference/bigchaindb-cli.md +++ b/docs/server/source/server-reference/bigchaindb-cli.md @@ -61,7 +61,7 @@ If you want to force-drop the database (i.e. skipping the yes/no prompt), then u ## bigchaindb start -Start BigchainDB assuming that the database has already been initialized using `bigchaindb init`. If that is not the case then passing the flag `--init` will initialize the database and start BigchainDB. +Start BigchainDB. It always begins by trying a `bigchaindb init` first. See the note in the documentation for `bigchaindb init`. The database initialization step is optional and can be skipped by passing the `--no-init` flag i.e. `bigchaindb start --no-init`. You can also use the `--dev-start-rethinkdb` command line option to automatically start rethinkdb with bigchaindb if rethinkdb is not already running, e.g. `bigchaindb --dev-start-rethinkdb start`. Note that this will also shutdown rethinkdb when the bigchaindb process stops. The option `--dev-allow-temp-keypair` will generate a keypair on the fly if no keypair is found, this is useful when you want to run a temporary instance of BigchainDB in a Docker container, for example. From 8aba802425bd9383ac15af32e2278fd649362c05 Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 7 Nov 2017 15:41:55 +0530 Subject: [PATCH 081/120] Fix tests --- tests/commands/conftest.py | 2 +- tests/commands/rethinkdb/test_commands.py | 2 +- tests/commands/test_commands.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py index 1aef2d30..46f8a8f6 100644 --- a/tests/commands/conftest.py +++ b/tests/commands/conftest.py @@ -49,7 +49,7 @@ def run_start_args(request): config=param.get('config'), start_rethinkdb=param.get('start_rethinkdb', False), allow_temp_keypair=param.get('allow_temp_keypair', False), - initialize_database=param.get('initialize_database', True), + skip_initialize_database=param.get('skip_initialize_database', False), ) diff --git a/tests/commands/rethinkdb/test_commands.py b/tests/commands/rethinkdb/test_commands.py index 29a84972..c8990582 100644 --- a/tests/commands/rethinkdb/test_commands.py +++ b/tests/commands/rethinkdb/test_commands.py @@ -14,7 +14,7 @@ def test_bigchain_run_start_with_rethinkdb(mock_start_rethinkdb, from bigchaindb import config from bigchaindb.commands.bigchaindb import run_start args = Namespace(start_rethinkdb=True, allow_temp_keypair=False, config=None, yes=True, - initialize_database=True) + skip_initialize_database=False) run_start(args) mock_start_rethinkdb.assert_called_with() diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 15aa9302..423e4614 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -40,7 +40,7 @@ def test_bigchain_run_start(mock_run_configure, from bigchaindb import config from bigchaindb.commands.bigchaindb import run_start args = Namespace(start_rethinkdb=False, allow_temp_keypair=False, config=None, yes=True, - initialize_database=True) + skip_initialize_database=False) run_start(args) mocked_setup_logging.assert_called_once_with(user_log_config=config['log']) @@ -290,7 +290,7 @@ def test_allow_temp_keypair_generates_one_on_the_fly( bigchaindb.config['keypair'] = {'private': None, 'public': None} args = Namespace(allow_temp_keypair=True, start_rethinkdb=False, config=None, yes=True, - initialize_database=True) + skip_initialize_database=False) run_start(args) mocked_setup_logging.assert_called_once_with( @@ -317,7 +317,7 @@ def test_allow_temp_keypair_doesnt_override_if_keypair_found(mock_gen_keypair, assert isinstance(original_private_key, str) args = Namespace(allow_temp_keypair=True, start_rethinkdb=False, config=None, yes=True, - initialize_database=True) + skip_initialize_database=False) run_start(args) mocked_setup_logging.assert_called_once_with( From 1266c43ff87366ee7b3fb1f8a668feeae537a75e Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 7 Nov 2017 18:44:51 +0530 Subject: [PATCH 082/120] Fix docker files --- docker-compose.benchmark.yml | 2 +- docker-compose.rdb.yml | 2 +- docker-compose.yml | 2 +- tests/integration/test_integration.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docker-compose.benchmark.yml b/docker-compose.benchmark.yml index 2a2aacc2..c7319040 100644 --- a/docker-compose.benchmark.yml +++ b/docker-compose.benchmark.yml @@ -25,7 +25,7 @@ services: BIGCHAINDB_GRAPHITE_HOST: graphite ports: - "9984" - command: bigchaindb start --init + command: bigchaindb start graphite: image: hopsoft/graphite-statsd diff --git a/docker-compose.rdb.yml b/docker-compose.rdb.yml index e02aa444..15f91675 100644 --- a/docker-compose.rdb.yml +++ b/docker-compose.rdb.yml @@ -45,4 +45,4 @@ services: BIGCHAINDB_SERVER_BIND: 0.0.0.0:9984 ports: - "9984" - command: bigchaindb start --init + command: bigchaindb start diff --git a/docker-compose.yml b/docker-compose.yml index 8f774106..cd6aa2aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,4 +30,4 @@ services: BIGCHAINDB_WSSERVER_HOST: 0.0.0.0 ports: - "9984" - command: bigchaindb start --init + command: bigchaindb start diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 2bf0ebcd..21b783e6 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -12,9 +12,9 @@ def test_double_create(b, user_pk): metadata={'test': 'test'}).sign([b.me_private]) b.write_transaction(tx) - time.sleep(2) + time.sleep(5) b.write_transaction(tx) - time.sleep(2) + time.sleep(5) tx_returned = b.get_transaction(tx.id) # test that the tx can be queried From e725c23691a69d3e6ebdd35fa9f0c69320474509 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 7 Nov 2017 14:24:33 +0100 Subject: [PATCH 083/120] Added note about 'make clean-pyc' --- tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/README.md b/tests/README.md index e3c9133c..146d3bc6 100644 --- a/tests/README.md +++ b/tests/README.md @@ -115,7 +115,7 @@ $ docker-compose -f docker-compose.rdb.yml run --rm bdb-rdb py.test -v ``` to rebuild all the images (usually you only need to rebuild the `bdb` and - `bdb-rdb` images). + `bdb-rdb` images). If that fails, then do `make clean-pyc` and try again. ## Automated Testing of All Pull Requests From 5ce2eb1f971086868f1cc4869db23affd1487ac8 Mon Sep 17 00:00:00 2001 From: Vanshdeep Singh Date: Thu, 9 Nov 2017 00:11:17 +0530 Subject: [PATCH 084/120] Bypass CI issues for rethinkdb (#1821) Add custom marker to skip some travis/rdb tests --- tests/conftest.py | 9 +++++++++ tests/integration/test_federation.py | 3 +++ tests/integration/test_integration.py | 1 + 3 files changed, 13 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index b930e4ec..4b5c7946 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,6 +25,15 @@ USER_PRIVATE_KEY = '8eJ8q9ZQpReWyQT5aFCiwtZ5wDZC4eDnCen88p3tQ6ie' USER_PUBLIC_KEY = 'JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE' +def pytest_runtest_setup(item): + if isinstance(item, item.Function): + if item.get_marker('skip_travis_rdb'): + if (os.getenv('TRAVIS_CI') == 'true' and + os.getenv('BIGCHAINDB_DATABASE_BACKEND') == 'rethinkdb'): + pytest.skip( + 'Skip test during Travis CI build when using rethinkdb') + + def pytest_addoption(parser): from bigchaindb.backend.connection import BACKENDS diff --git a/tests/integration/test_federation.py b/tests/integration/test_federation.py index 598412ff..22e2e8da 100644 --- a/tests/integration/test_federation.py +++ b/tests/integration/test_federation.py @@ -97,6 +97,7 @@ def process_vote(steps, result=None): @pytest.mark.bdb @pytest.mark.genesis +@pytest.mark.skip_travis_rdb def test_elect_valid(federation_3): [bx, (s0, s1, s2)] = federation_3 tx = input_single_create(bx[0]) @@ -115,6 +116,7 @@ def test_elect_valid(federation_3): @pytest.mark.bdb +@pytest.mark.skip_travis_rdb @pytest.mark.genesis def test_elect_invalid(federation_3): [bx, (s0, s1, s2)] = federation_3 @@ -135,6 +137,7 @@ def test_elect_invalid(federation_3): @pytest.mark.bdb @pytest.mark.genesis +@pytest.mark.skip_travis_rdb def test_elect_sybill(federation_3): [bx, (s0, s1, s2)] = federation_3 tx = input_single_create(bx[0]) diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 2bf0ebcd..50734fee 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -5,6 +5,7 @@ import pytest pytestmark = [pytest.mark.bdb, pytest.mark.usefixtures('processes')] +@pytest.mark.skip_travis_rdb def test_double_create(b, user_pk): from bigchaindb.models import Transaction from bigchaindb.backend.query import count_blocks From c4e0a8e1db16dee8857568db396f26cf84229fc8 Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 19 Oct 2017 12:19:43 +0200 Subject: [PATCH 085/120] Handle WS CLOSE properly --- bigchaindb/web/websocket_server.py | 34 ++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/bigchaindb/web/websocket_server.py b/bigchaindb/web/websocket_server.py index bcf14f35..effc153c 100644 --- a/bigchaindb/web/websocket_server.py +++ b/bigchaindb/web/websocket_server.py @@ -70,6 +70,15 @@ class Dispatcher: self.subscribers[uuid] = websocket + def unsubscribe(self, uuid): + """Remove a websocket from the list of subscribers. + + Args: + uuid (str): a unique identifier for the websocket. + """ + + del self.subscribers[uuid] + @asyncio.coroutine def publish(self): """Publish new events to the subscribers.""" @@ -115,11 +124,16 @@ def websocket_handler(request): msg = yield from websocket.receive() except RuntimeError as e: logger.debug('Websocket exception: %s', str(e)) - return websocket - - if msg.type == aiohttp.WSMsgType.ERROR: + break + if msg.type == aiohttp.WSMsgType.CLOSED: + logger.debug('Websocket closed') + break + elif msg.type == aiohttp.WSMsgType.ERROR: logger.debug('Websocket exception: %s', websocket.exception()) - return websocket + break + + request.app['dispatcher'].unsubscribe(uuid) + return websocket def init_app(event_source, *, loop=None): @@ -157,3 +171,15 @@ def start(sync_event_source, loop=None): aiohttp.web.run_app(app, host=config['wsserver']['host'], port=config['wsserver']['port']) + + +if __name__ == '__main__': + def meow(queue): + while True: + yield from asyncio.sleep(1) + yield from queue.put('meow') + loop = asyncio.get_event_loop() + event_source = asyncio.Queue(loop=loop) + # loop.create_task(meow(event_source)) + app = init_app(event_source, loop=loop) + aiohttp.web.run_app(app) From 832ecb5e638c2fd0a7e7b520ae8726aa254113b3 Mon Sep 17 00:00:00 2001 From: kansi Date: Thu, 9 Nov 2017 19:17:23 +0530 Subject: [PATCH 086/120] Handle metadata table during test setup/tear down --- tests/backend/mongodb/test_schema.py | 3 +++ tests/utils.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tests/backend/mongodb/test_schema.py b/tests/backend/mongodb/test_schema.py index 471cc583..f1a2f428 100644 --- a/tests/backend/mongodb/test_schema.py +++ b/tests/backend/mongodb/test_schema.py @@ -35,6 +35,9 @@ def test_init_creates_db_tables_and_indexes(): indexes = conn.conn[dbname]['assets'].index_information().keys() assert sorted(indexes) == ['_id_', 'asset_id', 'text'] + indexes = conn.conn[dbname]['metadata'].index_information().keys() + assert sorted(indexes) == ['_id_', 'text', 'transaction_id'] + def test_init_database_fails_if_db_exists(): import bigchaindb diff --git a/tests/utils.py b/tests/utils.py index 9af72a5d..5b3b5242 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -33,6 +33,7 @@ def flush_rethink_db(connection, dbname): connection.run(r.db(dbname).table('backlog').delete()) connection.run(r.db(dbname).table('votes').delete()) connection.run(r.db(dbname).table('assets').delete()) + connection.run(r.db(dbname).table('metadata').delete()) except r.ReqlOpFailedError: pass @@ -43,6 +44,7 @@ def flush_mongo_db(connection, dbname): connection.conn[dbname].backlog.delete_many({}) connection.conn[dbname].votes.delete_many({}) connection.conn[dbname].assets.delete_many({}) + connection.conn[dbname].metadata.delete_many({}) @singledispatch From e242345327f7094002f38179a3b04449883e8fe8 Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 9 Nov 2017 15:59:02 +0100 Subject: [PATCH 087/120] Remove sample code --- bigchaindb/web/websocket_server.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/bigchaindb/web/websocket_server.py b/bigchaindb/web/websocket_server.py index effc153c..930ebc94 100644 --- a/bigchaindb/web/websocket_server.py +++ b/bigchaindb/web/websocket_server.py @@ -171,15 +171,3 @@ def start(sync_event_source, loop=None): aiohttp.web.run_app(app, host=config['wsserver']['host'], port=config['wsserver']['port']) - - -if __name__ == '__main__': - def meow(queue): - while True: - yield from asyncio.sleep(1) - yield from queue.put('meow') - loop = asyncio.get_event_loop() - event_source = asyncio.Queue(loop=loop) - # loop.create_task(meow(event_source)) - app = init_app(event_source, loop=loop) - aiohttp.web.run_app(app) From cfa63ae9af7b826ecf7da72eee953f2e1a833c5b Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Mon, 13 Nov 2017 13:38:00 +0100 Subject: [PATCH 088/120] Updated the changelog for the v1.2 release --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7622b2c2..feef1748 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,26 @@ For reference, the possible headings are: * **External Contributors** to list contributors outside of BigchainDB GmbH. * **Notes** +## [1.2] - 2017-11-13 +Tag name: v1.2.0 + +### Added +* New and improved installation setup docs and code. Pull requests [#1775](https://github.com/bigchaindb/bigchaindb/pull/1775) and [#1785](https://github.com/bigchaindb/bigchaindb/pull/1785) +* New BigchainDB configuration setting to set the port number of the log server: `log.port`. [Pull request #1796](https://github.com/bigchaindb/bigchaindb/pull/1796) +* New secondary index on `id` in the bigchain table. That will make some queries execute faster. [Pull request #1803](https://github.com/bigchaindb/bigchaindb/pull/1803) +* When using MongoDB, there are some restrictions on allowed names for keys (JSON keys). Those restrictions were always there but now BigchainDB checks key names explicitly, rather than leaving that to MongoDB. Pull requests [#1807](https://github.com/bigchaindb/bigchaindb/pull/1807) and [#1811](https://github.com/bigchaindb/bigchaindb/pull/1811) +* When using MongoDB, there are some restrictions on the allowed values of "language" (if that key is used in the values of `metadata` or `asset.data`). Those restrictions were always there but now BigchainDB checks the values explicitly, rather than leaving that to MongoDB. Pull requests [#1806](https://github.com/bigchaindb/bigchaindb/pull/1806) and [#1811](https://github.com/bigchaindb/bigchaindb/pull/1811) +* There's a new page in the root docs about permissions in BigchainDB. [Pull request #1788](https://github.com/bigchaindb/bigchaindb/pull/1788) +* There's a new option in the `bigchaindb start` command: `bigchaindb start --no-init` will avoid doing `bigchaindb init` if it wasn't done already. [Pull request #1814](https://github.com/bigchaindb/bigchaindb/pull/1814) + +### Fixed +* Fixed a bug where setting the log level in a BigchainDB config file didn't have any effect. It does now. [Pull request #1797](https://github.com/bigchaindb/bigchaindb/pull/1797) +* The docs were wrong about there being no Ping/Pong support in the Events API. There is, so the docs were fixed. [Pull request #1799](https://github.com/bigchaindb/bigchaindb/pull/1799) +* Fixed an issue with closing WebSocket connections properly. [Pull request #1819](https://github.com/bigchaindb/bigchaindb/pull/1819) + +### Notes +* Many changes were made to the Kubernetes-based production deployment template and code. + ## [1.1] - 2017-09-26 Tag name: v1.1.0 From 67c8c6a1cbccebba09912c98cd9f1ab12b71147d Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Mon, 13 Nov 2017 13:54:13 +0100 Subject: [PATCH 089/120] Updated Docker image version to 1.2.0 in k8s YAML files --- k8s/bigchaindb/bigchaindb-dep.yaml | 2 +- k8s/dev-setup/bigchaindb.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/k8s/bigchaindb/bigchaindb-dep.yaml b/k8s/bigchaindb/bigchaindb-dep.yaml index 6c4ca88c..5e23f4c0 100644 --- a/k8s/bigchaindb/bigchaindb-dep.yaml +++ b/k8s/bigchaindb/bigchaindb-dep.yaml @@ -12,7 +12,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: bigchaindb - image: bigchaindb/bigchaindb:1.1.0 + image: bigchaindb/bigchaindb:1.2.0 imagePullPolicy: IfNotPresent args: - start diff --git a/k8s/dev-setup/bigchaindb.yaml b/k8s/dev-setup/bigchaindb.yaml index e6c39775..e9980a96 100644 --- a/k8s/dev-setup/bigchaindb.yaml +++ b/k8s/dev-setup/bigchaindb.yaml @@ -34,7 +34,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: bigchaindb - image: bigchaindb/bigchaindb:1.1.0 + image: bigchaindb/bigchaindb:1.2.0 imagePullPolicy: Always args: - start From 9bed27b98f3c7c4f0c147756d6df3b66242c458a Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Mon, 13 Nov 2017 14:53:25 +0100 Subject: [PATCH 090/120] Updated to 1.3.0.dev in version.py --- bigchaindb/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bigchaindb/version.py b/bigchaindb/version.py index 7c0b19ea..4937b037 100644 --- a/bigchaindb/version.py +++ b/bigchaindb/version.py @@ -1,2 +1,2 @@ -__version__ = '1.2.0.dev' -__short_version__ = '1.2.dev' +__version__ = '1.3.0.dev' +__short_version__ = '1.3.dev' From f0d4417d021d176a9caa8b51642bb5869ea1445b Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Mon, 13 Nov 2017 17:28:06 +0100 Subject: [PATCH 091/120] Removed auto-generation of tx/vote schema documentation --- bigchaindb/common/schema/README.md | 11 +- docs/server/generate_schema_documentation.py | 241 ------------------ docs/server/source/conf.py | 1 - .../source/data-models/inputs-outputs.rst | 2 - .../source/data-models/transaction-model.rst | 4 +- docs/server/source/index.rst | 2 - 6 files changed, 7 insertions(+), 254 deletions(-) delete mode 100644 docs/server/generate_schema_documentation.py diff --git a/bigchaindb/common/schema/README.md b/bigchaindb/common/schema/README.md index 3c8451b0..4b2cf873 100644 --- a/bigchaindb/common/schema/README.md +++ b/bigchaindb/common/schema/README.md @@ -3,11 +3,12 @@ This directory contains the schemas for the different JSON documents BigchainDB uses. The aim is to provide: - - a strict definition/documentation of the data structures used in BigchainDB - - a language independent tool to validate the structure of incoming/outcoming - data (there are several ready to use - [implementations](http://json-schema.org/implementations.html) written in - different languages) + +- a strict definition of the data structures used in BigchainDB +- a language independent tool to validate the structure of incoming/outcoming + data (there are several ready to use + [implementations](http://json-schema.org/implementations.html) written in + different languages) ## Learn about JSON Schema diff --git a/docs/server/generate_schema_documentation.py b/docs/server/generate_schema_documentation.py deleted file mode 100644 index c94fe3a9..00000000 --- a/docs/server/generate_schema_documentation.py +++ /dev/null @@ -1,241 +0,0 @@ -""" Script to render transaction schema into .rst document """ - -from collections import OrderedDict -import os.path - -import yaml - -from bigchaindb.common.schema import TX_SCHEMA_PATH, VOTE_SCHEMA_PATH - - -TPL_PROP = """\ -%(title)s -%(underline)s - -**type:** %(type)s - -%(description)s -""" - - -TPL_STYLES = """ -.. raw:: html - - -""" - - -TPL_TRANSACTION = TPL_STYLES + """\ -.. This file was auto generated by %(file)s - -================== -Transaction Schema -================== - -* `Transaction`_ - -* Input_ - -* Output_ - -* Asset_ - -* Metadata_ - - -Transaction ------------ - -%(transaction)s - -Input ------ - -%(input)s - -Output ------- - -%(output)s - -Asset ------ - -%(asset)s - -Metadata --------- - -%(metadata)s -""" - - -def generate_transaction_docs(): - schema = load_schema(TX_SCHEMA_PATH) - defs = schema['definitions'] - - doc = TPL_TRANSACTION % { - 'transaction': render_section('Transaction', schema), - 'output': render_section('Output', defs['output']), - 'input': render_section('Input', defs['input']), - 'asset': render_section('Asset', defs['asset']), - 'metadata': render_section('Metadata', defs['metadata']['anyOf'][0]), - 'container': 'transaction-schema', - 'file': os.path.basename(__file__), - } - - write_schema_doc('transaction', doc) - - -TPL_VOTE = TPL_STYLES + """\ -.. This file was auto generated by %(file)s - -=========== -Vote Schema -=========== - -Vote ----- - -%(vote)s - -Vote Details ------------- - -%(vote_details)s - -""" - - -def generate_vote_docs(): - schema = load_schema(VOTE_SCHEMA_PATH) - - doc = TPL_VOTE % { - 'vote': render_section('Vote', schema), - 'vote_details': render_section('Vote', schema['properties']['vote']), - 'container': 'vote-schema', - 'file': os.path.basename(__file__), - } - - write_schema_doc('vote', doc) - - -def ordered_load_yaml(path): - """ Custom YAML loader to preserve key order """ - class OrderedLoader(yaml.SafeLoader): - pass - - def construct_mapping(loader, node): - loader.flatten_mapping(node) - return OrderedDict(loader.construct_pairs(node)) - OrderedLoader.add_constructor( - yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, - construct_mapping) - with open(path) as handle: - return yaml.load(handle, OrderedLoader) - - -def load_schema(path): - global DEFS - schema = ordered_load_yaml(path) - DEFS = schema['definitions'] - return schema - - -def write_schema_doc(name, doc): - # Check base path exists - base_path = os.path.join(os.path.dirname(__file__), 'source/schema') - if not os.path.exists(base_path): - os.makedirs(base_path) - # Write doc - path = os.path.join(base_path, '%s.rst' % name) - with open(path, 'w') as handle: - handle.write(doc) - - -def render_section(section_name, obj): - """ Render a domain object and it's properties """ - out = [obj['description']] - for name, prop in obj.get('properties', {}).items(): - try: - title = '%s.%s' % (section_name, name) - out += [TPL_PROP % { - 'title': title, - 'underline': '^' * len(title), - 'description': property_description(prop), - 'type': property_type(prop), - }] - except Exception as exc: - raise ValueError('Error rendering property: %s' % name, exc) - return '\n\n'.join(out + ['']) - - -def property_description(prop): - """ Get description of property """ - if 'description' in prop: - return prop['description'] - if '$ref' in prop: - return property_description(resolve_ref(prop['$ref'])) - if 'anyOf' in prop: - return property_description(prop['anyOf'][0]) - raise KeyError('description') - - -def property_type(prop): - """ Resolve a string representing the type of a property """ - if 'type' in prop: - if prop['type'] == 'array': - return 'array (%s)' % property_type(prop['items']) - return prop['type'] - if 'anyOf' in prop: - return ' or '.join(property_type(p) for p in prop['anyOf']) - if '$ref' in prop: - return property_type(resolve_ref(prop['$ref'])) - raise ValueError('Could not resolve property type') - - -DEFINITION_BASE_PATH = '#/definitions/' - - -def resolve_ref(ref): - """ Resolve definition reference """ - assert ref.startswith(DEFINITION_BASE_PATH) - return DEFS[ref[len(DEFINITION_BASE_PATH):]] - - -def main(): - """ Main function """ - generate_transaction_docs() - generate_vote_docs() - - -def setup(*_): - """ Fool sphinx into think it's an extension muahaha """ - main() - - -if __name__ == '__main__': - main() diff --git a/docs/server/source/conf.py b/docs/server/source/conf.py index 756a8d13..e272baf4 100644 --- a/docs/server/source/conf.py +++ b/docs/server/source/conf.py @@ -51,7 +51,6 @@ extensions = [ 'sphinx.ext.autosectionlabel', # Below are actually build steps made to look like sphinx extensions. # It was the easiest way to get it running with ReadTheDocs. - 'generate_schema_documentation', 'generate_http_server_api_documentation', ] diff --git a/docs/server/source/data-models/inputs-outputs.rst b/docs/server/source/data-models/inputs-outputs.rst index 4e246bfe..52214421 100644 --- a/docs/server/source/data-models/inputs-outputs.rst +++ b/docs/server/source/data-models/inputs-outputs.rst @@ -26,7 +26,6 @@ An input has the following structure: You can think of the ``fulfills`` object as a pointer to an output on another transaction: the output that this input is spending/transferring. A CREATE transaction should have exactly one input. That input can contain one or more ``owners_before``, a ``fulfillment`` (with one signature from each of the owners-before), and the value of ``fulfills`` should be ``null``). A TRANSFER transaction should have at least one input, and the value of ``fulfills`` should not be ``null``. -See the reference on :ref:`inputs ` for more description about the meaning of each field. The ``fulfillment`` string fulfills the condition in the output that is being spent (transferred). To calculate it: @@ -62,7 +61,6 @@ An output has the following structure: The :ref:`page about conditions ` explains the contents of a ``condition``. The list of ``public_keys`` is always the "owners" of the asset at the time the transaction completed, but before the next transaction started. -See the reference on :ref:`outputs ` for more description about the meaning of each field. Note that ``amount`` must be a string (e.g. ``"7"``). In a TRANSFER transaction, the sum of the output amounts must be the same as the sum of the outputs that it transfers (i.e. the sum of the input amounts). For example, if a TRANSFER transaction has two outputs, one with ``"amount": "2"`` and one with ``"amount": "3"``, then the sum of the outputs is 5 and so the sum of the outputs-being-transferred must also be 5. diff --git a/docs/server/source/data-models/transaction-model.rst b/docs/server/source/data-models/transaction-model.rst index b4f2a4f1..4c2e2a0f 100644 --- a/docs/server/source/data-models/transaction-model.rst +++ b/docs/server/source/data-models/transaction-model.rst @@ -19,20 +19,18 @@ Here's some explanation of the contents: - **id**: The ID of the transaction and also the hash of the transaction (loosely speaking). See below for an explanation of how it's computed. It's also the database primary key. -- **version**: The version-number of :ref:`the transaction schema `. As of BigchainDB Server 1.0.0, the only allowed value is ``"1.0"``. +- **version**: The version-number of the transaction schema. As of BigchainDB Server 1.0.0, the only allowed value is ``"1.0"``. - **inputs**: List of inputs. Each input spends/transfers a previous output by satisfying/fulfilling the crypto-conditions on that output. A CREATE transaction should have exactly one input. A TRANSFER transaction should have at least one input (i.e. ≥1). - For more details, see the subsection about :ref:`inputs `. - **outputs**: List of outputs. Each output indicates the crypto-conditions which must be satisfied by anyone wishing to spend/transfer that output. It also indicates the number of shares of the asset tied to that output. - For more details, see the subsection about :ref:`outputs `. - **operation**: A string indicating what kind of transaction this is, and how it should be validated. diff --git a/docs/server/source/index.rst b/docs/server/source/index.rst index ec6efef0..42c7e4be 100644 --- a/docs/server/source/index.rst +++ b/docs/server/source/index.rst @@ -16,7 +16,5 @@ BigchainDB Server Documentation events/index drivers-clients/index data-models/index - schema/transaction - schema/vote release-notes appendices/index From 4eca26782caac8c9f95b0ef4abd58f4a56f0c013 Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 14 Nov 2017 00:13:06 +0530 Subject: [PATCH 092/120] Change metadata model, fix tests and update docs --- bigchaindb/backend/mongodb/query.py | 5 +- bigchaindb/core.py | 17 +-- bigchaindb/models.py | 25 ++-- docs/server/source/http-client-server-api.rst | 112 ++++++++++++++++++ tests/pipelines/test_vote.py | 13 ++ tests/web/test_metadata.py | 2 +- 6 files changed, 140 insertions(+), 34 deletions(-) diff --git a/bigchaindb/backend/mongodb/query.py b/bigchaindb/backend/mongodb/query.py index e59c0311..2abd770d 100644 --- a/bigchaindb/backend/mongodb/query.py +++ b/bigchaindb/backend/mongodb/query.py @@ -366,10 +366,7 @@ def get_new_blocks_feed(conn, start_block_id): @register_query(MongoDBConnection) def text_search(conn, search, *, language='english', case_sensitive=False, - diacritic_sensitive=False, text_score=False, limit=0, table=None): - if table is None: - table = 'assets' - + diacritic_sensitive=False, text_score=False, limit=0, table='assets'): cursor = conn.run( conn.collection(table) .find({'$text': { diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 78779d42..f5ae567f 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -384,8 +384,8 @@ class Bigchain(object): for transaction in transactions: # ignore transactions in invalid blocks # FIXME: Isn't there a faster solution than doing I/O again? - _, status = self.get_transaction(transaction['id'], - include_status=True) + txn, status = self.get_transaction(transaction['id'], + include_status=True) if status == self.TX_VALID: num_valid_transactions += 1 # `txid` can only have been spent in at most on valid block. @@ -395,13 +395,7 @@ class Bigchain(object): ' with the chain'.format(txid)) # if its not and invalid transaction if status is not None: - if 'metadata' not in transaction: - metadata = list(self.get_metadata([transaction['id']])) - metadata = metadata[0] if metadata else None - if metadata: - metadata.pop('id', None) - transaction.update({'metadata': metadata}) - + transaction.update({'metadata': txn.metadata}) non_invalid_transactions.append(transaction) if non_invalid_transactions: @@ -672,7 +666,7 @@ class Bigchain(object): """ return backend.query.write_metadata(self.connection, metadata) - def text_search(self, search, *, limit=0, table=None): + def text_search(self, search, *, limit=0, table='assets'): """ Return an iterator of assets that match the text search @@ -683,9 +677,6 @@ class Bigchain(object): Returns: iter: An iterator of assets that match the text search. """ - if table is None: - table = 'assets' - objects = backend.query.text_search(self.connection, search, limit=limit, table=table) diff --git a/bigchaindb/models.py b/bigchaindb/models.py index 7660b224..4eeb846d 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -5,8 +5,7 @@ from bigchaindb.common.exceptions import (InvalidHash, InvalidSignature, DoubleSpend, InputDoesNotExist, TransactionNotInValidBlock, AssetIdMismatch, AmountError, - SybilError, ValidationError, - DuplicateTransaction) + SybilError, DuplicateTransaction) from bigchaindb.common.transaction import Transaction from bigchaindb.common.utils import (gen_timestamp, serialize, validate_txn_obj, validate_key) @@ -119,7 +118,7 @@ class Transaction(Transaction): if 'metadata' not in tx_dict: metadata = metadata[0] if metadata else None if metadata: - metadata.pop('id', None) + metadata = metadata.get('metadata') tx_dict.update({'metadata': metadata}) @@ -406,11 +405,10 @@ class Block(object): metadatas = [] for transaction in block_dict['block']['transactions']: metadata = transaction.pop('metadata') - if isinstance(metadata, dict): - metadata.update({'id': transaction['id']}) - metadatas.append(metadata) - elif metadata: - raise ValidationError('Invalid value for metadata') + if metadata: + metadata_new = {'id': transaction['id'], + 'metadata': metadata} + metadatas.append(metadata_new) return (metadatas, block_dict) @@ -460,16 +458,11 @@ class Block(object): dict: The dict of the reconstructed block. """ # create a dict with {'': metadata} - metadatal = {m.pop('id'): m for m in metadatal} + metadatal = {m.pop('id'): m.pop('metadata') for m in metadatal} # add the metadata to their corresponding transactions for transaction in block_dict['block']['transactions']: - if 'metadata' not in transaction: - metadata = metadatal.get(transaction['id']) - if metadata: - metadata.pop('id', None) - transaction.update({'metadata': metadata}) - else: - transaction.update({'metadata': None}) + metadata = metadatal.get(transaction['id'], None) + transaction.update({'metadata': metadata}) return block_dict @staticmethod diff --git a/docs/server/source/http-client-server-api.rst b/docs/server/source/http-client-server-api.rst index 618903a8..58ec5617 100644 --- a/docs/server/source/http-client-server-api.rst +++ b/docs/server/source/http-client-server-api.rst @@ -452,6 +452,118 @@ Assets text search. +Transaction Metadata +-------------------------------- + +.. http:get:: /api/v1/metadata + + Return all the metadata that match a given text search. + + :query string text search: Text search string to query. + :query int limit: (Optional) Limit the number of returned metadata objects. Defaults + to ``0`` meaning return all matching objects. + + .. note:: + + Currently this enpoint is only supported if the server is running + MongoDB as the backend. + +.. http:get:: /api/v1/metadata/?search={text_search} + + Return all metadata that match a given text search. The ``id`` of the metadata + is the same ``id`` of the transaction where it was defined. + + If no metadata match the text search it returns an empty list. + + If the text string is empty or the server does not support text search, + a ``400`` is returned. + + The results are sorted by text score. + For more information about the behavior of text search see `MongoDB text + search behavior `_ + + **Example request**: + + .. sourcecode:: http + + GET /api/v1/metadata/?search=bigchaindb HTTP/1.1 + Host: example.com + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-type: application/json + + [ + { + "metadata": {"metakey1": "Hello BigchainDB 1!"}, + "id": "51ce82a14ca274d43e4992bbce41f6fdeb755f846e48e710a3bbb3b0cf8e4204" + }, + { + "metadata": {"metakey2": "Hello BigchainDB 2!"}, + "id": "b4e9005fa494d20e503d916fa87b74fe61c079afccd6e084260674159795ee31" + }, + { + "metadata": {"metakey3": "Hello BigchainDB 3!"}, + "id": "fa6bcb6a8fdea3dc2a860fcdc0e0c63c9cf5b25da8b02a4db4fb6a2d36d27791" + } + ] + + :resheader Content-Type: ``application/json`` + + :statuscode 200: The query was executed successfully. + :statuscode 400: The query was not executed successfully. Returned if the + text string is empty or the server does not support + text search. + +.. http:get:: /api/v1/metadata/?search={text_search}&limit={n_documents} + + Return at most ``n`` metadata objects that match a given text search. + + If no metadata match the text search it returns an empty list. + + If the text string is empty or the server does not support text search, + a ``400`` is returned. + + The results are sorted by text score. + For more information about the behavior of text search see `MongoDB text + search behavior `_ + + **Example request**: + + .. sourcecode:: http + + GET /api/v1/metadata/?search=bigchaindb&limit=2 HTTP/1.1 + Host: example.com + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-type: application/json + + [ + { + "metadata": {"msg": "Hello BigchainDB 1!"}, + "id": "51ce82a14ca274d43e4992bbce41f6fdeb755f846e48e710a3bbb3b0cf8e4204" + }, + { + "metadata": {"msg": "Hello BigchainDB 2!"}, + "id": "b4e9005fa494d20e503d916fa87b74fe61c079afccd6e084260674159795ee31" + }, + ] + + :resheader Content-Type: ``application/json`` + + :statuscode 200: The query was executed successfully. + :statuscode 400: The query was not executed successfully. Returned if the + text string is empty or the server does not support + text search. + + Advanced Usage -------------------------------- diff --git a/tests/pipelines/test_vote.py b/tests/pipelines/test_vote.py index 21bbc0bf..701434fd 100644 --- a/tests/pipelines/test_vote.py +++ b/tests/pipelines/test_vote.py @@ -29,6 +29,16 @@ def decouple_assets(b, block): return block_dict +def decouple_metadata(b, block, block_dict): + # the block comming from the database does not contain the metadata + # so we need to pass the block without the metadata and store the metadata + # so that the voting pipeline can reconstruct it + metadata, block_dict = block.decouple_metadata(block_dict) + if metadata: + b.write_metadata(metadata) + return block_dict + + DUMMY_SHA3 = '0123456789abcdef' * 4 @@ -89,6 +99,7 @@ def test_vote_validate_block(b): tx = dummy_tx(b) block = b.create_block([tx]) block_dict = decouple_assets(b, block) + block_dict = decouple_metadata(b, block, block_dict) vote_obj = vote.Vote() validation = vote_obj.validate_block(block_dict) @@ -230,6 +241,7 @@ def test_valid_block_voting_multiprocessing(b, genesis_block, monkeypatch): block = dummy_block(b) block_dict = decouple_assets(b, block) + block_dict = decouple_metadata(b, block, block_dict) inpipe.put(block_dict) vote_pipeline.start() @@ -268,6 +280,7 @@ def test_valid_block_voting_with_create_transaction(b, monkeypatch.setattr('time.time', lambda: 1111111111) block = b.create_block([tx]) block_dict = decouple_assets(b, block) + block_dict = decouple_metadata(b, block, block_dict) inpipe = Pipe() outpipe = Pipe() diff --git a/tests/web/test_metadata.py b/tests/web/test_metadata.py index fa551f3e..22c025ae 100644 --- a/tests/web/test_metadata.py +++ b/tests/web/test_metadata.py @@ -43,7 +43,7 @@ def test_get_metadata(client, b): assert res.status_code == 200 assert len(res.json) == 1 assert res.json[0] == { - 'key': 'my_meta', + 'metadata': {'key': 'my_meta'}, 'id': tx.id } else: From 053b9546240e3ed3bb909581f1dd476d75943d02 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 14 Nov 2017 10:20:10 +0100 Subject: [PATCH 093/120] Removed docs/server/source/schema from .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 20d71296..c58d0db8 100644 --- a/.gitignore +++ b/.gitignore @@ -77,7 +77,6 @@ ntools/one-m/ansible/hosts ntools/one-m/ansible/ansible.cfg # Just in time documentation -docs/server/source/schema docs/server/source/http-samples # Terraform state files From 6291afd0f7e3075f05469029fee177db9a78690e Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 14 Nov 2017 14:05:02 +0100 Subject: [PATCH 094/120] rm all 'description' keys & values from YAML files --- bigchaindb/common/schema/transaction.yaml | 85 ------------------- .../common/schema/transaction_transfer.yaml | 2 - bigchaindb/common/schema/vote.yaml | 29 ------- 3 files changed, 116 deletions(-) diff --git a/bigchaindb/common/schema/transaction.yaml b/bigchaindb/common/schema/transaction.yaml index fbab5eb1..33f6a1f8 100644 --- a/bigchaindb/common/schema/transaction.yaml +++ b/bigchaindb/common/schema/transaction.yaml @@ -4,8 +4,6 @@ id: "http://www.bigchaindb.com/schema/transaction.json" type: object additionalProperties: false title: Transaction Schema -description: | - A transaction represents the creation or transfer of assets in BigchainDB. required: - id - inputs @@ -17,48 +15,24 @@ required: properties: id: "$ref": "#/definitions/sha3_hexdigest" - description: | - A sha3 digest of the transaction. The ID is calculated by removing all - derived hashes and signatures from the transaction, serializing it to - JSON with keys in sorted order and then hashing the resulting string - with sha3. operation: "$ref": "#/definitions/operation" asset: "$ref": "#/definitions/asset" - description: | - Description of the asset being transacted. - - See: `Asset`_. inputs: type: array title: "Transaction inputs" - description: | - Array of the inputs of a transaction. - - See: Input_. items: "$ref": "#/definitions/input" outputs: type: array - description: | - Array of outputs provided by this transaction. - - See: Output_. items: "$ref": "#/definitions/output" metadata: "$ref": "#/definitions/metadata" - description: | - User provided transaction metadata. This field may be ``null`` or may - contain an id and an object with freeform metadata. - - See: `Metadata`_. version: type: string pattern: "^1\\.0$" - description: | - BigchainDB transaction schema version. definitions: offset: type: integer @@ -78,53 +52,25 @@ definitions: uuid4: pattern: "[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}" type: string - description: | - A `UUID `_ - of type 4 (random). operation: type: string - description: | - Type of the transaction: - - A ``CREATE`` transaction creates an asset in BigchainDB. This - transaction has outputs but no inputs, so a dummy input is created. - - A ``TRANSFER`` transaction transfers ownership of an asset, by providing - an input that meets the conditions of an earlier transaction's outputs. - - A ``GENESIS`` transaction is a special case transaction used as the - sole member of the first block in a BigchainDB ledger. enum: - CREATE - TRANSFER - GENESIS asset: type: object - description: | - Description of the asset being transacted. In the case of a ``TRANSFER`` - transaction, this field contains only the ID of asset. In the case - of a ``CREATE`` transaction, this field contains only the user-defined - payload. additionalProperties: false properties: id: "$ref": "#/definitions/sha3_hexdigest" - description: | - ID of the transaction that created the asset. data: - description: | - User provided metadata associated with the asset. May also be ``null``. anyOf: - type: object additionalProperties: true - type: 'null' output: type: object - description: | - A transaction output. Describes the quantity of an asset and the - requirements that must be met to spend the output. - - See also: Input_. additionalProperties: false required: - amount @@ -134,15 +80,7 @@ definitions: amount: type: string pattern: "^[0-9]{1,20}$" - description: | - Integral amount of the asset represented by this output. - In the case of a non divisible asset, this will always be 1. condition: - description: | - Describes the condition that needs to be met to spend the output. Has the properties: - - - **details**: Details of the condition. - - **uri**: Condition encoded as an ASCII string. type: object additionalProperties: false required: @@ -158,13 +96,8 @@ definitions: subtypes=ed25519-sha-256(&)?){2,3}$" public_keys: "$ref": "#/definitions/public_keys" - description: | - List of public keys associated with the conditions on an output. input: type: "object" - description: - An input spends a previous output, by providing one or more fulfillments - that fulfill the conditions of the previous output. additionalProperties: false required: - owners_before @@ -172,13 +105,7 @@ definitions: properties: owners_before: "$ref": "#/definitions/public_keys" - description: | - List of public keys of the previous owners of the asset. fulfillment: - description: | - Fulfillment of an `Output.condition`_, or, put a different way, a payload - that satisfies the condition of a previous output to prove that the - creator(s) of this transaction have control over the listed asset. anyOf: - type: string pattern: "^[a-zA-Z0-9_-]*$" @@ -186,8 +113,6 @@ definitions: fulfills: anyOf: - type: 'object' - description: | - Reference to the output that is being spent. additionalProperties: false required: - output_index @@ -195,26 +120,16 @@ definitions: properties: output_index: "$ref": "#/definitions/offset" - description: | - Index of the output containing the condition being fulfilled transaction_id: "$ref": "#/definitions/sha3_hexdigest" - description: | - Transaction ID containing the output to spend - type: 'null' metadata: anyOf: - type: object - description: | - User provided transaction metadata. This field may be ``null`` or may - contain an non empty object with freeform metadata. additionalProperties: true minProperties: 1 - type: 'null' condition_details: - description: | - Details needed to reconstruct the condition associated with an output. - Currently, BigchainDB only supports ed25519 and threshold condition types. anyOf: - type: object additionalProperties: false diff --git a/bigchaindb/common/schema/transaction_transfer.yaml b/bigchaindb/common/schema/transaction_transfer.yaml index b8b79696..538ec5e6 100644 --- a/bigchaindb/common/schema/transaction_transfer.yaml +++ b/bigchaindb/common/schema/transaction_transfer.yaml @@ -10,8 +10,6 @@ properties: properties: id: "$ref": "#/definitions/sha3_hexdigest" - description: | - ID of the transaction that created the asset. required: - id inputs: diff --git a/bigchaindb/common/schema/vote.yaml b/bigchaindb/common/schema/vote.yaml index 49e5ae98..8f16562f 100644 --- a/bigchaindb/common/schema/vote.yaml +++ b/bigchaindb/common/schema/vote.yaml @@ -4,13 +4,6 @@ id: "http://www.bigchaindb.com/schema/vote.json" type: object additionalProperties: false title: Vote Schema -description: | - A Vote is an endorsement of a Block (identified by a hash) by - a node (identified by a public key). - - The outer Vote object contains the details of the vote being made - as well as the signature and identifying information of the node - passing the vote. required: - node_pubkey - signature @@ -19,18 +12,12 @@ properties: node_pubkey: type: "string" pattern: "[1-9a-zA-Z^OIl]{43,44}" - description: | - Ed25519 public key identifying the voting node. signature: type: "string" pattern: "[1-9a-zA-Z^OIl]{86,88}" - description: - Ed25519 signature of the `Vote Details`_ object. vote: type: "object" additionalProperties: false - description: | - `Vote Details`_ to be signed. required: - invalid_reason - is_block_valid @@ -40,33 +27,17 @@ properties: properties: previous_block: "$ref": "#/definitions/sha3_hexdigest" - description: | - ID (SHA3 hash) of the block that precedes the block being voted on. - The notion of a "previous" block is subject to vote. voting_for_block: "$ref": "#/definitions/sha3_hexdigest" - description: | - ID (SHA3 hash) of the block being voted on. is_block_valid: type: "boolean" - description: | - This field is ``true`` if the block was deemed valid by the node. invalid_reason: anyOf: - type: "string" - description: | - Reason the block is voted invalid, or ``null``. - - .. container:: notice - - **Note**: The invalid_reason was not being used and may be dropped in a future version of BigchainDB. See Issue `#217 `_ on GitHub. - type: "null" timestamp: type: "string" pattern: "[0-9]{10}" - description: | - Unix timestamp that the vote was created by the node, according - to the system time of the node. definitions: sha3_hexdigest: pattern: "[0-9a-f]{64}" From e86fa1f1bbf42088ced8a87a45f5d67a9e4709ee Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 14 Nov 2017 14:05:53 +0100 Subject: [PATCH 095/120] Removed drop_schema_description() & its test --- bigchaindb/common/schema/__init__.py | 13 -------- tests/common/test_schema.py | 45 +--------------------------- 2 files changed, 1 insertion(+), 57 deletions(-) diff --git a/bigchaindb/common/schema/__init__.py b/bigchaindb/common/schema/__init__.py index fc048e0b..b2e8129a 100644 --- a/bigchaindb/common/schema/__init__.py +++ b/bigchaindb/common/schema/__init__.py @@ -13,24 +13,11 @@ from bigchaindb.common.exceptions import SchemaValidationError logger = logging.getLogger(__name__) -def drop_schema_descriptions(node): - """ Drop descriptions from schema, since they clutter log output """ - if 'description' in node: - del node['description'] - for n in node.get('properties', {}).values(): - drop_schema_descriptions(n) - for n in node.get('definitions', {}).values(): - drop_schema_descriptions(n) - for n in node.get('anyOf', []): - drop_schema_descriptions(n) - - def _load_schema(name): """ Load a schema from disk """ path = os.path.join(os.path.dirname(__file__), name + '.yaml') with open(path) as handle: schema = yaml.safe_load(handle) - drop_schema_descriptions(schema) fast_schema = rapidjson_schema.loads(rapidjson.dumps(schema)) return path, (schema, fast_schema) diff --git a/tests/common/test_schema.py b/tests/common/test_schema.py index e80ad0e2..8c064696 100644 --- a/tests/common/test_schema.py +++ b/tests/common/test_schema.py @@ -11,7 +11,7 @@ from pytest import raises from bigchaindb.common.exceptions import SchemaValidationError from bigchaindb.common.schema import ( - TX_SCHEMA_COMMON, VOTE_SCHEMA, drop_schema_descriptions, + TX_SCHEMA_COMMON, VOTE_SCHEMA, validate_transaction_schema, validate_vote_schema) SUPPORTED_CRYPTOCONDITION_TYPES = ('threshold-sha-256', 'ed25519-sha-256') @@ -46,49 +46,6 @@ def test_vote_schema_additionalproperties(): _test_additionalproperties(VOTE_SCHEMA) -def test_drop_descriptions(): - node = { - 'description': 'abc', - 'properties': { - 'description': { - 'description': ('The property named "description" should stay' - 'but description meta field goes'), - }, - 'properties': { - 'description': 'this must go' - }, - 'any': { - 'anyOf': [ - { - 'description': 'must go' - } - ] - } - }, - 'definitions': { - 'wat': { - 'description': 'go' - } - } - } - expected = { - 'properties': { - 'description': {}, - 'properties': {}, - 'any': { - 'anyOf': [ - {} - ] - } - }, - 'definitions': { - 'wat': {}, - } - } - drop_schema_descriptions(node) - assert node == expected - - ################################################################################ # Test call transaction schema From 860d247aa44be23fdae95deefcdd841c65b8057b Mon Sep 17 00:00:00 2001 From: kansi Date: Tue, 14 Nov 2017 19:23:22 +0530 Subject: [PATCH 096/120] Fixed decouple assets --- bigchaindb/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bigchaindb/models.py b/bigchaindb/models.py index 4eeb846d..5f602299 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -380,7 +380,6 @@ class Block(object): if block_dict is None: block_dict = deepcopy(self.to_dict()) - block_dict = deepcopy(self.to_dict()) assets = [] for transaction in block_dict['block']['transactions']: if transaction['operation'] in [Transaction.CREATE, From 31a0bc846b3eebb04bace2a90357e14e64e61d56 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 14 Nov 2017 15:51:36 +0100 Subject: [PATCH 097/120] Updated docs about blocks and votes --- docs/server/source/appendices/index.rst | 3 +- docs/server/source/appendices/vote-yaml.rst | 16 +++ .../server/source/data-models/block-model.rst | 92 ++++++++++--- docs/server/source/data-models/vote-model.md | 27 ---- docs/server/source/data-models/vote-model.rst | 121 ++++++++++++++++++ docs/server/source/glossary.rst | 19 +++ docs/server/source/index.rst | 1 + 7 files changed, 232 insertions(+), 47 deletions(-) create mode 100644 docs/server/source/appendices/vote-yaml.rst delete mode 100644 docs/server/source/data-models/vote-model.md create mode 100644 docs/server/source/data-models/vote-model.rst create mode 100644 docs/server/source/glossary.rst diff --git a/docs/server/source/appendices/index.rst b/docs/server/source/appendices/index.rst index 7bee77df..5a28199e 100755 --- a/docs/server/source/appendices/index.rst +++ b/docs/server/source/appendices/index.rst @@ -28,4 +28,5 @@ Appendices licenses install-with-lxd run-with-vagrant - run-with-ansible \ No newline at end of file + run-with-ansible + vote-yaml diff --git a/docs/server/source/appendices/vote-yaml.rst b/docs/server/source/appendices/vote-yaml.rst new file mode 100644 index 00000000..ad05d8ba --- /dev/null +++ b/docs/server/source/appendices/vote-yaml.rst @@ -0,0 +1,16 @@ +The vote.yaml File +================== + +BigchainDB checks all :ref:`votes ` +(JSON documents) against a formal schema +defined in a JSON Schema file named vote.yaml. +The contents of that file are copied below. +To understand those contents +(i.e. JSON Schema), check out +`"Understanding JSON Schema" +`_ +by Michael Droettboom or +`json-schema.org `_. + +.. literalinclude:: ../../../../bigchaindb/common/schema/vote.yaml + :language: yaml diff --git a/docs/server/source/data-models/block-model.rst b/docs/server/source/data-models/block-model.rst index 8b184261..36b7204e 100644 --- a/docs/server/source/data-models/block-model.rst +++ b/docs/server/source/data-models/block-model.rst @@ -1,36 +1,90 @@ The Block Model =============== -A block has the following structure: +A block is a JSON object with a particular schema, +as outlined in this page. +A block must contain the following JSON keys +(also called names or fields): .. code-block:: json { - "id": "", + "id": "", "block": { - "timestamp": "", - "transactions": [""], - "node_pubkey": "", - "voters": [""] + "timestamp": "", + "transactions": [""], + "node_pubkey": "", + "voters": [""] }, - "signature": "" + "signature": "" } -- ``id``: The :ref:`hash ` of the serialized inner ``block`` (i.e. the ``timestamp``, ``transactions``, ``node_pubkey``, and ``voters``). It's used as a unique index in the database backend (e.g. RethinkDB or MongoDB). +The JSON Keys in a Block +------------------------ -- ``block``: - - ``timestamp``: The Unix time when the block was created. It's provided by the node that created the block. - - ``transactions``: A list of the transactions included in the block. - - ``node_pubkey``: The public key of the node that created the block. - - ``voters``: A list of the public keys of all cluster nodes at the time the block was created. - It's the list of nodes which can cast a vote on this block. - This list can change from block to block, as nodes join and leave the cluster. +**id** -- ``signature``: :ref:`Cryptographic signature ` of the block by the node that created the block (i.e. the node with public key ``node_pubkey``). To generate the signature, the node signs the serialized inner ``block`` (the same thing that was hashed to determine the ``id``) using the private key corresponding to ``node_pubkey``. +The transaction ID and also the SHA3-256 hash +of the inner ``block`` object, loosely speaking. +It's a string. +To compute it, 1) construct an :term:`associative array` ``d`` containing +``block.timestamp``, ``block.transactions``, ``block.node_pubkey``, +``block.voters``, and their values. 2) compute ``id = hash_of_aa(d)``. +There's pseudocode for the ``hash_of_aa()`` function +in the `IPDB Protocol documentation page about cryptographic hashes +`_. +The result (``id``) is a string: the block ID. +An example is ``"b60adf655932bf47ef58c0bfb2dd276d4795b94346b36cbb477e10d7eb02cea8"`` -Working with Blocks -------------------- +**block.timestamp** -There's a **Block** class for creating and working with Block objects; look in `/bigchaindb/models.py `_. (The link is to the latest version on the master branch on GitHub.) +The `Unix time `_ +when the block was created, according to the node which created it. +It's a string representation of an integer. +An example is ``"1507294217"``. + + +**block.transactions** + +A list of the :ref:`transactions ` included in the block. +(Each transaction is a JSON object.) + + +**block.node_pubkey** + +The public key of the node that created the block. +It's a string. +See the `IPDB Protocol documentation page about cryptographic keys & signatures +`_. + + +**block.voters** + +A list of the public keys of all cluster nodes at the time the block was created. +It's a list of strings. +This list can change from block to block, as nodes join and leave the cluster. + + +**signature** + +The cryptographic signature of the inner ``block`` +by the node that created the block +(i.e. the node with public key ``node_pubkey``). +To compute that: + +#. Construct an :term:`associative array` ``d`` containing the contents + of the inner ``block`` + (i.e. ``block.timestamp``, ``block.transactions``, ``block.node_pubkey``, + ``block.voters``, and their values). +#. Compute ``signature = sig_of_aa(d, private_key)``, + where ``private_key`` is the node's private key + (i.e. ``node_pubkey`` and ``private_key`` are a key pair). There's pseudocode + for the ``sig_of_aa()`` function + on `the IPDB Protocol documentation page about cryptographic keys and signatures + `_. + +.. note:: + + The ``d_bytes`` computed when computing the block ID will be the *same* as the ``d_bytes`` computed when computing the block signature. This can be used to avoid redundant calculations. diff --git a/docs/server/source/data-models/vote-model.md b/docs/server/source/data-models/vote-model.md deleted file mode 100644 index daa66a94..00000000 --- a/docs/server/source/data-models/vote-model.md +++ /dev/null @@ -1,27 +0,0 @@ -# The Vote Model - -A vote has the following structure: - -```json -{ - "node_pubkey": "", - "vote": { - "voting_for_block": "", - "previous_block": "", - "is_block_valid": "", - "invalid_reason": null, - "timestamp": "" - }, - "signature": "" -} -``` - -**Notes** - -* Votes have no ID (or `"id"`), as far as users are concerned. (The backend database uses one internally, but it's of no concern to users and it's never reported to them via BigchainDB APIs.) - -* At the time of writing, the value of `"invalid_reason"` was always `null`. In other words, it wasn't being used. It may be used or dropped in a future version of BigchainDB. See [Issue #217](https://github.com/bigchaindb/bigchaindb/issues/217) on GitHub. - -* For more information about the vote `"timestamp"`, see [the page about timestamps in BigchainDB](https://docs.bigchaindb.com/en/latest/timestamps.html). - -* For more information about how the `"signature"` is calculated, see [the page about cryptography in BigchainDB](../appendices/cryptography.html). diff --git a/docs/server/source/data-models/vote-model.rst b/docs/server/source/data-models/vote-model.rst new file mode 100644 index 00000000..027c4875 --- /dev/null +++ b/docs/server/source/data-models/vote-model.rst @@ -0,0 +1,121 @@ +The Vote Model +============== + +A vote is a JSON object with a particular schema, +as outlined in this page. +A vote must contain the following JSON keys +(also called names or fields): + +.. code-block:: json + + { + "node_pubkey": "", + "vote": { + "voting_for_block": "", + "previous_block": "", + "is_block_valid": "", + "invalid_reason": null, + "timestamp": "" + }, + "signature": "" + } + +.. note:: + + Votes have no ID (or ``"id"``), as far as users are concerned. + The backend database may use one internally, + but it's of no concern to users and it's never reported to them via APIs. + + +The JSON Keys in a Vote +----------------------- + +**node_pubkey** + +The public key of the node which cast this vote. +It's a string. +For more information about public keys, +see the `IPDB Protocol documentation page about cryptographic keys and signatures +`_. + + +**vote.voting_for_block** + +The block ID that this vote is for. +It's a string. +For more information about block IDs, +see the page about :ref:`blocks `. + + +**vote.previous_block** + +The block ID of the block "before" the block that this vote is for, +according to the node which cast this vote. +It's a string. +(It's possible for different nodes to see different block orders.) +For more information about block IDs, +see the page about :ref:`blocks `. + + +**vote.is_block_valid** + +``true`` if the node which cast this vote considered the block in question to be valid, +and ``false`` otherwise. +Note that it's a *boolean* (i.e. ``true`` or ``false``), not a string. + + +**vote.invalid_reason** + +Always ``null``, that is, it's not being used. +It may be used or dropped in a future version. +See `bigchaindb/bigchaindb issue #217 +`_ on GitHub. + + +**vote.timestamp** + +The `Unix time `_ +when the vote was created, according to the node which created it. +It's a string representation of an integer. + + +**signature** + +The cryptographic signature of the inner ``vote`` +by the node that created the vote +(i.e. the node with public key ``node_pubkey``). +To compute that: + +#. Construct an :term:`associative array` ``d`` containing the contents of the inner ``vote`` + (i.e. ``vote.voting_for_block``, ``vote.previous_block``, ``vote.is_block_valid``, + ``vote.invalid_reason``, ``vote.timestamp``, and their values). +#. Compute ``signature = sig_of_aa(d, private_key)``, where ``private_key`` + is the node's private key (i.e. ``node_pubkey`` and ``private_key`` are a key pair). + There's pseudocode for the ``sig_of_aa()`` function + on `the IPDB Protocol documentation page about cryptographic keys and signatures + `_. + + +The Vote Schema +--------------- + +BigchainDB checks all votes (JSON documents) against a formal schema +defined in a JSON Schema file named :ref:`vote.yaml `. + + +An Example Vote +--------------- + +.. code-block:: json + + { + "node_pubkey": "3ZCsVWPAhPTqHx9wZVxp9Se54pcNeeM5mQvnozDWyDR9", + "vote": { + "voting_for_block": "11c3a3fcc9efa4fc4332a0849fc39b58e403ff37794a7d1fdfb9e7703a94a274", + "previous_block": "3dd1441018b782a50607dc4c7f83a0f0a23eb257f4b6a8d99330dfff41271e0d", + "is_block_valid": true, + "invalid_reason": null, + "timestamp": "1509977988" + }, + "signature": "3tW2EBVgxaZTE6nixVd9QEQf1vUxqPmQaNAMdCHc7zHik5KEosdkwScGYt4VhiHDTB6BCxTUzmqu3P7oP93tRWfj" + } diff --git a/docs/server/source/glossary.rst b/docs/server/source/glossary.rst new file mode 100644 index 00000000..8fc03ac2 --- /dev/null +++ b/docs/server/source/glossary.rst @@ -0,0 +1,19 @@ +Glossary +======== + +.. glossary:: + :sorted: + + associative array + A collection of key/value (or name/value) pairs + such that each possible key appears at most once + in the collection. + In JavaScript (and JSON), all objects behave as associative arrays + with string-valued keys. + In Python and .NET, associative arrays are called *dictionaries*. + In Java and Go, they are called *maps*. + In Ruby, they are called *hashes*. + See also: Wikipedia's articles for + `Associative array `_ + and + `Comparison of programming languages (associative array) `_ diff --git a/docs/server/source/index.rst b/docs/server/source/index.rst index 42c7e4be..65bd8774 100644 --- a/docs/server/source/index.rst +++ b/docs/server/source/index.rst @@ -17,4 +17,5 @@ BigchainDB Server Documentation drivers-clients/index data-models/index release-notes + glossary appendices/index From b3ccb09e0179f7937d8cbc5498e04de016238350 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Wed, 15 Nov 2017 11:17:41 +0100 Subject: [PATCH 098/120] Changed title of the page about vote.yaml --- docs/server/source/appendices/vote-yaml.rst | 8 ++++++-- docs/server/source/data-models/vote-model.rst | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/server/source/appendices/vote-yaml.rst b/docs/server/source/appendices/vote-yaml.rst index ad05d8ba..6613827e 100644 --- a/docs/server/source/appendices/vote-yaml.rst +++ b/docs/server/source/appendices/vote-yaml.rst @@ -1,5 +1,5 @@ -The vote.yaml File -================== +The Vote Schema File +==================== BigchainDB checks all :ref:`votes ` (JSON documents) against a formal schema @@ -12,5 +12,9 @@ To understand those contents by Michael Droettboom or `json-schema.org `_. + +vote.yaml +--------- + .. literalinclude:: ../../../../bigchaindb/common/schema/vote.yaml :language: yaml diff --git a/docs/server/source/data-models/vote-model.rst b/docs/server/source/data-models/vote-model.rst index 027c4875..45db9680 100644 --- a/docs/server/source/data-models/vote-model.rst +++ b/docs/server/source/data-models/vote-model.rst @@ -100,7 +100,7 @@ The Vote Schema --------------- BigchainDB checks all votes (JSON documents) against a formal schema -defined in a JSON Schema file named :ref:`vote.yaml `. +defined in a :ref:`JSON Schema file named vote.yaml `. An Example Vote From c6c89bfcbaebf7942bf8b4e922b57f538759c2b3 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Wed, 15 Nov 2017 11:18:07 +0100 Subject: [PATCH 099/120] Added page about the transaction schema files --- docs/server/source/appendices/index.rst | 1 + .../source/appendices/tx-yaml-files.rst | 37 +++++++++++++++++++ .../source/data-models/transaction-model.rst | 10 +++++ 3 files changed, 48 insertions(+) create mode 100644 docs/server/source/appendices/tx-yaml-files.rst diff --git a/docs/server/source/appendices/index.rst b/docs/server/source/appendices/index.rst index 5a28199e..45337e44 100755 --- a/docs/server/source/appendices/index.rst +++ b/docs/server/source/appendices/index.rst @@ -29,4 +29,5 @@ Appendices install-with-lxd run-with-vagrant run-with-ansible + tx-yaml-files vote-yaml diff --git a/docs/server/source/appendices/tx-yaml-files.rst b/docs/server/source/appendices/tx-yaml-files.rst new file mode 100644 index 00000000..f9a51685 --- /dev/null +++ b/docs/server/source/appendices/tx-yaml-files.rst @@ -0,0 +1,37 @@ +The Transaction Schema Files +============================ + +BigchainDB checks all :ref:`transactions ` +(JSON documents) against a formal schema +defined in some JSON Schema files named +transaction.yaml, +transaction_create.yaml and +transaction_transfer.yaml. +The contents of those files are copied below. +To understand those contents +(i.e. JSON Schema), check out +`"Understanding JSON Schema" +`_ +by Michael Droettboom or +`json-schema.org `_. + + +transaction.yaml +---------------- + +.. literalinclude:: ../../../../bigchaindb/common/schema/transaction.yaml + :language: yaml + + +transaction_create.yaml +----------------------- + +.. literalinclude:: ../../../../bigchaindb/common/schema/transaction_create.yaml + :language: yaml + + +transaction_transfer.yaml +------------------------- + +.. literalinclude:: ../../../../bigchaindb/common/schema/transaction_transfer.yaml + :language: yaml diff --git a/docs/server/source/data-models/transaction-model.rst b/docs/server/source/data-models/transaction-model.rst index 4c2e2a0f..631399e2 100644 --- a/docs/server/source/data-models/transaction-model.rst +++ b/docs/server/source/data-models/transaction-model.rst @@ -62,3 +62,13 @@ There are example BigchainDB transactions in :ref:`the HTTP API documentation ` and `the Python Driver documentation `_. + + +The Transaction Schema +---------------------- + +BigchainDB checks all transactions (JSON documents) +against a formal schema defined in :ref:`some JSON Schema files named +transaction.yaml, +transaction_create.yaml and +transaction_transfer.yaml `. From 67c4b8ee3f456ad4e728a5f24c4c605eeeff2e6e Mon Sep 17 00:00:00 2001 From: kansi Date: Wed, 15 Nov 2017 16:31:46 +0530 Subject: [PATCH 100/120] Fix "Set Up & Run a Dev/Test Node" link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c04a6466..7bcde402 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ BigchainDB is a scalable blockchain database. [The whitepaper](https://www.bigch ## Get Started with BigchainDB Server ### [Quickstart](https://docs.bigchaindb.com/projects/server/en/latest/quickstart.html) -### [Set Up & Run a Dev/Test Node](https://docs.bigchaindb.com/projects/server/en/latest/dev-and-test/setup-run-node.html) +### [Set Up & Run a Dev/Test Node](https://docs.bigchaindb.com/projects/server/en/latest/dev-and-test/index.html) ### [Run BigchainDB Server with Docker](https://docs.bigchaindb.com/projects/server/en/latest/appendices/run-with-docker.html) ### [Run BigchainDB Server with Vagrant](https://docs.bigchaindb.com/projects/server/en/latest/appendices/run-with-vagrant.html) ### [Run BigchainDB Server with Ansible](https://docs.bigchaindb.com/projects/server/en/latest/appendices/run-with-ansible.html) From 18fed8b1d0646c6f45002ad8457303426b122f0c Mon Sep 17 00:00:00 2001 From: muawiakh Date: Tue, 14 Nov 2017 13:11:44 +0100 Subject: [PATCH 101/120] [Workaround]: Travis failures - Marking test_double_create as serial - If this works, we don't need to skip the tests - Finger crossed. --- .ci/travis_script.sh | 7 +++++-- tests/integration/test_federation.py | 2 +- tests/integration/test_integration.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.ci/travis_script.sh b/.ci/travis_script.sh index cc1061fe..97cfc977 100755 --- a/.ci/travis_script.sh +++ b/.ci/travis_script.sh @@ -7,11 +7,14 @@ if [[ -n ${TOXENV} ]]; then elif [[ "${BIGCHAINDB_DATABASE_BACKEND}" == mongodb && \ -z "${BIGCHAINDB_DATABASE_SSL}" ]]; then # Run the full suite of tests for MongoDB over an unsecure connection - pytest -sv --database-backend=mongodb --cov=bigchaindb + pytest -sv --database-backend=mongodb -m "serial" + pytest -sv --database-backend=mongodb --cov=bigchaindb -m "not serial" elif [[ "${BIGCHAINDB_DATABASE_BACKEND}" == mongodb && \ "${BIGCHAINDB_DATABASE_SSL}" == true ]]; then # Run a sub-set of tests over SSL; those marked as 'pytest.mark.bdb_ssl'. pytest -sv --database-backend=mongodb-ssl --cov=bigchaindb -m bdb_ssl else - pytest -sv -n auto --cov=bigchaindb + # Run the full suite of tests for RethinkDB (the default backend when testing) + pytest -sv -m "serial" + pytest -sv --cov=bigchaindb -m "not serial" fi diff --git a/tests/integration/test_federation.py b/tests/integration/test_federation.py index 22e2e8da..05d8f32e 100644 --- a/tests/integration/test_federation.py +++ b/tests/integration/test_federation.py @@ -116,8 +116,8 @@ def test_elect_valid(federation_3): @pytest.mark.bdb -@pytest.mark.skip_travis_rdb @pytest.mark.genesis +@pytest.mark.skip_travis_rdb def test_elect_invalid(federation_3): [bx, (s0, s1, s2)] = federation_3 tx = input_single_create(bx[0]) diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index ba097400..89fc8cbc 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -5,7 +5,7 @@ import pytest pytestmark = [pytest.mark.bdb, pytest.mark.usefixtures('processes')] -@pytest.mark.skip_travis_rdb +@pytest.mark.serial def test_double_create(b, user_pk): from bigchaindb.models import Transaction from bigchaindb.backend.query import count_blocks From 7906edcebf8ef1edaee7b4169d16e0ecba3c8544 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Thu, 9 Nov 2017 15:33:59 +0100 Subject: [PATCH 102/120] Update quickstart guide for 'docker for mac' users --- .../source/appendices/run-with-docker.md | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/server/source/appendices/run-with-docker.md b/docs/server/source/appendices/run-with-docker.md index d80f58b1..8fd00e78 100644 --- a/docs/server/source/appendices/run-with-docker.md +++ b/docs/server/source/appendices/run-with-docker.md @@ -30,6 +30,17 @@ docker run \ -y configure \ [mongodb|rethinkdb] +# For Docker for Mac users +docker run \ + --interactive \ + --rm \ + --tty \ + --volume $HOME/bigchaindb_docker:/data \ + --env BIGCHAINDB_DATABASE_HOST=172.17.0.1 \ + bigchaindb/bigchaindb \ + -y configure \ + [mongodb|rethinkdb] + Generating keypair Configuration written to /data/.bigchaindb Ready to go! @@ -78,6 +89,16 @@ docker run \ --restart=always \ --volume $HOME/bigchaindb_docker:/data \ rethinkdb:2.3 + +# For Docker for Mac users +docker run \ + --detach \ + --name=rethinkdb \ + --publish=28015:28015 \ + --publish=58080:8080 \ + --restart=always \ + --volume $HOME/bigchaindb_docker:/data \ + rethinkdb:2.3 ``` @@ -106,7 +127,17 @@ docker run \ --restart=always \ --volume=$HOME/mongodb_docker/db:/data/db \ --volume=$HOME/mongodb_docker/configdb:/data/configdb \ - mongo:3.4.1 --replSet=bigchain-rs + mongo:3.4.9 --replSet=bigchain-rs + +# For Docker for Mac users +docker run \ + --detach \ + --name=mongodb \ + --publish=27017:27017 \ + --restart=always \ + --volume=$HOME/mongodb_docker/db:/data/db \ + --volume=$HOME/mongodb_docker/configdb:/data/configdb \ + mongo:3.4.9 --replSet=bigchain-rs ``` ### Run BigchainDB From 47f872df0f187efb161b4d4778a73e815eeb6199 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Thu, 9 Nov 2017 16:19:24 +0100 Subject: [PATCH 103/120] Integrate some other changes --- docs/server/source/appendices/docker-on-mac.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/server/source/appendices/docker-on-mac.md b/docs/server/source/appendices/docker-on-mac.md index 7f87540f..60144fe2 100644 --- a/docs/server/source/appendices/docker-on-mac.md +++ b/docs/server/source/appendices/docker-on-mac.md @@ -35,7 +35,7 @@ Install Docker for Mac. Pull the bigchaindb and other required docker images from docker hub. ```text -docker pull bigchaindb/bigchaindb:master +docker pull bigchaindb/bigchaindb:latest docker pull [rethinkdb:2.3|mongo:3.4.1] ``` @@ -44,7 +44,7 @@ docker pull [rethinkdb:2.3|mongo:3.4.1] docker run \ --rm \ --volume $HOME/bigchaindb_docker:/data \ - bigchaindb/bigchaindb:master \ + bigchaindb/bigchaindb \ -y configure \ [mongodb|rethinkdb] ``` @@ -93,6 +93,7 @@ docker run \ docker run \ --name=bigchaindb \ --publish=9984:9984 \ + --publish=9985:9985 \ --restart=always \ --volume=$HOME/bigchaindb_docker:/data \ bigchaindb/bigchaindb \ From b4ca4959673fe1da80307739e741f426f155f54b Mon Sep 17 00:00:00 2001 From: muawiakh Date: Thu, 16 Nov 2017 12:14:11 +0100 Subject: [PATCH 104/120] Remove redundant redirections to different docker installation pages(s) - All the instructions are common now - Remove redundant files - address comments --- .../server/source/appendices/docker-on-mac.md | 102 ---------------- docs/server/source/appendices/index.rst | 3 +- .../source/appendices/run-with-docker.md | 47 ++------ docs/server/source/dev-and-test/index.rst | 4 +- .../source/dev-and-test/setup-bdb-docker.md | 112 ------------------ docs/server/source/quickstart.md | 2 +- 6 files changed, 11 insertions(+), 259 deletions(-) delete mode 100644 docs/server/source/appendices/docker-on-mac.md delete mode 100644 docs/server/source/dev-and-test/setup-bdb-docker.md diff --git a/docs/server/source/appendices/docker-on-mac.md b/docs/server/source/appendices/docker-on-mac.md deleted file mode 100644 index 60144fe2..00000000 --- a/docs/server/source/appendices/docker-on-mac.md +++ /dev/null @@ -1,102 +0,0 @@ -# Run BigchainDB with Docker On Mac - -**NOT for Production Use** - -Those developing on Mac can follow this document to run BigchainDB in docker -containers for a quick dev setup. -Running BigchainDB on Mac (Docker or otherwise) is not officially supported. - -Support is very much limited as there are certain things that work differently -in Docker for Mac than Docker for other platforms. -Also, we do not use mac for our development and testing. :) - -This page may not be up to date with various settings and docker updates at -all the times. - -These steps work as of this writing (2017.Mar.09) and might break in the -future with updates to Docker for mac. -Community contribution to make BigchainDB run on Docker for Mac will always be -welcome. - - -## Prerequisite - -Install Docker for Mac. - -## (Optional) For a clean start - -1. Stop all BigchainDB and RethinkDB/MongoDB containers. -2. Delete all BigchainDB docker images. -3. Delete the ~/bigchaindb_docker folder. - - -## Pull the images - -Pull the bigchaindb and other required docker images from docker hub. - -```text -docker pull bigchaindb/bigchaindb:latest -docker pull [rethinkdb:2.3|mongo:3.4.1] -``` - -## Create the BigchainDB configuration file on Mac -```text -docker run \ - --rm \ - --volume $HOME/bigchaindb_docker:/data \ - bigchaindb/bigchaindb \ - -y configure \ - [mongodb|rethinkdb] -``` - -To ensure that BigchainDB connects to the backend database bound to the virtual -interface `172.17.0.1`, you must edit the BigchainDB configuration file -(`~/bigchaindb_docker/.bigchaindb`) and change database.host from `localhost` -to `172.17.0.1`. - - -## Run the backend database on Mac - -From v0.9 onwards, you can run RethinkDB or MongoDB. - -We use the virtual interface created by the Docker daemon to allow -communication between the BigchainDB and database containers. -It has an IP address of 172.17.0.1 by default. - -You can also use docker host networking or bind to your primary (eth) -interface, if needed. - -### For RethinkDB backend -```text -docker run \ - --name=rethinkdb \ - --publish=28015:28015 \ - --publish=8080:8080 \ - --restart=always \ - --volume $HOME/bigchaindb_docker:/data \ - rethinkdb:2.3 -``` - -### For MongoDB backend -```text -docker run \ - --name=mongodb \ - --publish=27017:27017 \ - --restart=always \ - --volume=$HOME/bigchaindb_docker/db:/data/db \ - --volume=$HOME/bigchaindb_docker/configdb:/data/configdb \ - mongo:3.4.1 --replSet=bigchain-rs -``` - -### Run BigchainDB on Mac -```text -docker run \ - --name=bigchaindb \ - --publish=9984:9984 \ - --publish=9985:9985 \ - --restart=always \ - --volume=$HOME/bigchaindb_docker:/data \ - bigchaindb/bigchaindb \ - start -``` - diff --git a/docs/server/source/appendices/index.rst b/docs/server/source/appendices/index.rst index 7bee77df..088ff7db 100755 --- a/docs/server/source/appendices/index.rst +++ b/docs/server/source/appendices/index.rst @@ -10,7 +10,6 @@ Appendices install-os-level-deps install-latest-pip run-with-docker - docker-on-mac json-serialization cryptography the-Bigchain-class @@ -28,4 +27,4 @@ Appendices licenses install-with-lxd run-with-vagrant - run-with-ansible \ No newline at end of file + run-with-ansible diff --git a/docs/server/source/appendices/run-with-docker.md b/docs/server/source/appendices/run-with-docker.md index 8fd00e78..b75c9300 100644 --- a/docs/server/source/appendices/run-with-docker.md +++ b/docs/server/source/appendices/run-with-docker.md @@ -6,9 +6,12 @@ For those who like using Docker and wish to experiment with BigchainDB in non-production environments, we currently maintain a Docker image and a `Dockerfile` that can be used to build an image for `bigchaindb`. +## Prerequisite(s) +- [Docker](https://docs.docker.com/engine/installation/) + ## Pull and Run the Image from Docker Hub -Assuming you have Docker installed, you would proceed as follows. +With Docker installed, you can proceed as follows. In a terminal shell, pull the latest version of the BigchainDB Docker image using: ```text @@ -21,16 +24,6 @@ the `-y` option to accept all the default values. The configuration file will be stored in a file on your host machine at `~/bigchaindb_docker/.bigchaindb`: ```text -docker run \ - --interactive \ - --rm \ - --tty \ - --volume $HOME/bigchaindb_docker:/data \ - bigchaindb/bigchaindb \ - -y configure \ - [mongodb|rethinkdb] - -# For Docker for Mac users docker run \ --interactive \ --rm \ @@ -57,40 +50,24 @@ Let's analyze that command: this allows us to have the data persisted on the host machine, you can read more in the [official Docker documentation](https://docs.docker.com/engine/tutorials/dockervolumes) +* `--env BIGCHAINDB_DATABASE_HOST=172.17.0.1`, `172.17.0.1` is the default `docker0` bridge +IP address, for fresh Docker installations. It is used for the communication between BigchainDB and database +containers. * `bigchaindb/bigchaindb` the image to use. All the options after the container name are passed on to the entrypoint inside the container. * `-y configure` execute the `configure` sub-command (of the `bigchaindb` command) inside the container, with the `-y` option to automatically use all the default config values * `mongodb` or `rethinkdb` specifies the database backend to use with bigchaindb -To ensure that BigchainDB connects to the backend database bound to the virtual -interface `172.17.0.1`, you must edit the BigchainDB configuration file -(`~/bigchaindb_docker/.bigchaindb`) and change database.host from `localhost` -to `172.17.0.1`. - ### Run the backend database From v0.9 onwards, you can run either RethinkDB or MongoDB. -We use the virtual interface created by the Docker daemon to allow -communication between the BigchainDB and database containers. -It has an IP address of 172.17.0.1 by default. - You can also use docker host networking or bind to your primary (eth) interface, if needed. #### For RethinkDB ```text -docker run \ - --detach \ - --name=rethinkdb \ - --publish=172.17.0.1:28015:28015 \ - --publish=172.17.0.1:58080:8080 \ - --restart=always \ - --volume $HOME/bigchaindb_docker:/data \ - rethinkdb:2.3 - -# For Docker for Mac users docker run \ --detach \ --name=rethinkdb \ @@ -120,16 +97,6 @@ group. ```text -docker run \ - --detach \ - --name=mongodb \ - --publish=172.17.0.1:27017:27017 \ - --restart=always \ - --volume=$HOME/mongodb_docker/db:/data/db \ - --volume=$HOME/mongodb_docker/configdb:/data/configdb \ - mongo:3.4.9 --replSet=bigchain-rs - -# For Docker for Mac users docker run \ --detach \ --name=mongodb \ diff --git a/docs/server/source/dev-and-test/index.rst b/docs/server/source/dev-and-test/index.rst index bcde6e87..b9ddaf58 100644 --- a/docs/server/source/dev-and-test/index.rst +++ b/docs/server/source/dev-and-test/index.rst @@ -7,7 +7,7 @@ This section outlines some ways that you could set up a minimal BigchainDB node :maxdepth: 1 Using a Local Dev Machine - Using a Local Dev Machine and Docker + Using a Local Dev Machine and Docker <../appendices/run-with-docker> Using Vagrant <../appendices/run-with-vagrant> Using Ansible <../appendices/run-with-ansible> - running-all-tests + running-all-tests \ No newline at end of file diff --git a/docs/server/source/dev-and-test/setup-bdb-docker.md b/docs/server/source/dev-and-test/setup-bdb-docker.md deleted file mode 100644 index a0a50dfd..00000000 --- a/docs/server/source/dev-and-test/setup-bdb-docker.md +++ /dev/null @@ -1,112 +0,0 @@ -# Set Up BigchainDB Node Using Docker - -You need to have recent versions of [Docker](https://docs.docker.com/engine/installation/) -and (Docker) [Compose](https://docs.docker.com/compose/install/). - -Build the images: - -```bash -docker-compose build -``` -## Docker with MongoDB - -Start MongoDB: - -```bash -docker-compose up -d mdb -``` - -MongoDB should now be up and running. You can check the port binding for the -MongoDB driver port using: -```bash -$ docker-compose port mdb 27017 -``` - -Start a BigchainDB node: - -```bash -docker-compose up -d bdb -``` - -You can monitor the logs: - -```bash -docker-compose logs -f bdb -``` - -If you wish to run the tests: - -```bash -docker-compose run --rm bdb py.test -v --database-backend=mongodb -``` -## Docker with RethinkDB - -**Note**: If you're upgrading BigchainDB and have previously already built the images, you may need -to rebuild them after the upgrade to install any new dependencies. - -Start RethinkDB: - -```bash -docker-compose -f docker-compose.rdb.yml up -d rdb -``` - -The RethinkDB web interface should be accessible at http://localhost:58080/. -Depending on which platform, and/or how you are running docker, you may need -to change `localhost` for the `ip` of the machine that is running docker. As a -dummy example, if the `ip` of that machine was `0.0.0.0`, you would access the -web interface at: http://0.0.0.0:58080/. - -Start a BigchainDB node: - -```bash -docker-compose -f docker-compose.rdb.yml up -d bdb-rdb -``` - -You can monitor the logs: - -```bash -docker-compose -f docker-compose.rdb.yml logs -f bdb-rdb -``` - -If you wish to run the tests: - -```bash -docker-compose -f docker-compose.rdb.yml run --rm bdb-rdb pytest -v -n auto -``` - -## Accessing the HTTP API - -You can do quick check to make sure that the BigchainDB server API is operational: - -```bash -curl $(docker-compose port bdb 9984) -``` - -The result should be a JSON object (inside braces like { }) -containing the name of the software ("BigchainDB"), -the version of BigchainDB, the node's public key, and other information. - -How does the above curl command work? Inside the Docker container, BigchainDB -exposes the HTTP API on port `9984`. First we get the public port where that -port is bound: - -```bash -docker-compose port bdb 9984 -``` - -The port binding will change whenever you stop/restart the `bdb` service. You -should get an output similar to: - -```bash -0.0.0.0:32772 -``` - -but with a port different from `32772`. - - -Knowing the public port we can now perform a simple `GET` operation against the -root: - -```bash -curl 0.0.0.0:32772 -``` diff --git a/docs/server/source/quickstart.md b/docs/server/source/quickstart.md index 63ab8643..e066a046 100644 --- a/docs/server/source/quickstart.md +++ b/docs/server/source/quickstart.md @@ -1,6 +1,6 @@ # Quickstart -This page has instructions to set up a single stand-alone BigchainDB node for learning or experimenting. Instructions for other cases are [elsewhere](introduction.html). We will assume you're using Ubuntu 16.04 or similar. If you're not using Linux, then you might try [running BigchainDB with Docker](appendices/run-with-docker.html). +This page has instructions to set up a single stand-alone BigchainDB node for learning or experimenting. Instructions for other cases are [elsewhere](introduction.html). We will assume you're using Ubuntu 16.04 or similar. You can also try, [running BigchainDB with Docker](appendices/run-with-docker.html). A. Install MongoDB as the database backend. (There are other options but you can ignore them for now.) From 1eb8764e4a33c0d66b9185d5b540c1cb99908211 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Thu, 9 Nov 2017 14:50:29 +0100 Subject: [PATCH 105/120] Update deployment with tectonic documentation - Add details about CA configuration - Update storage class template --- .../node-on-kubernetes.rst | 22 ++++++++----------- .../tectonic-azure.rst | 16 +++++++++++++- .../template-kubernetes-azure.rst | 15 +++++++++++++ k8s/mongodb/mongo-sc.yaml | 12 ++++++++-- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/docs/server/source/production-deployment-template/node-on-kubernetes.rst b/docs/server/source/production-deployment-template/node-on-kubernetes.rst index 371ecc36..492d15c6 100644 --- a/docs/server/source/production-deployment-template/node-on-kubernetes.rst +++ b/docs/server/source/production-deployment-template/node-on-kubernetes.rst @@ -424,13 +424,14 @@ LRS means locally-redundant storage: three replicas in the same data center. Premium storage is higher-cost and higher-performance. It uses solid state drives (SSD). -At the time of writing, -when we created a storage account with SKU ``Premium_LRS`` -and tried to use that, -the PersistentVolumeClaim would get stuck in a "Pending" state. +You can create a `storage account `_ +for Premium storage and associate it with your Azure resource group. For future reference, the command to create a storage account is `az storage account create `_. +.. Note:: + Please refer to `Azure documentation `_ + for the list of VMs that are supported by Premium Storage. The Kubernetes template for configuration of Storage Class is located in the file ``mongodb/mongo-sc.yaml``. @@ -438,6 +439,10 @@ file ``mongodb/mongo-sc.yaml``. You may have to update the ``parameters.location`` field in the file to specify the location you are using in Azure. +If you want to use a custom storage account with the Storage Class, you +can also update `parameters.storageAccount` and provide the Azure storage +account name. + Create the required storage classes using: .. code:: bash @@ -447,15 +452,6 @@ Create the required storage classes using: You can check if it worked using ``kubectl get storageclasses``. -**Azure.** Note that there is no line of the form -``storageAccount: `` -under ``parameters:``. When we included one -and then created a PersistentVolumeClaim based on it, -the PersistentVolumeClaim would get stuck -in a "Pending" state. -Kubernetes just looks for a storageAccount -with the specified skuName and location. - Step 11: Create Kubernetes Persistent Volume Claims --------------------------------------------------- diff --git a/docs/server/source/production-deployment-template/tectonic-azure.rst b/docs/server/source/production-deployment-template/tectonic-azure.rst index c59dc241..3803751e 100644 --- a/docs/server/source/production-deployment-template/tectonic-azure.rst +++ b/docs/server/source/production-deployment-template/tectonic-azure.rst @@ -47,7 +47,9 @@ when following the steps above: ``tectonic-cluster-CLUSTER``. #. Set the ``tectonic_base_domain`` to ``""`` if you want to use Azure managed - DNS. You will be assigned a ``cloudapp.azure.com`` sub-domain by default. + DNS. You will be assigned a ``cloudapp.azure.com`` sub-domain by default and + you can skip the ``Configuring Azure DNS`` section from the Tectonic installation + guide. #. Set the ``tectonic_cl_channel`` to ``"stable"`` unless you want to experiment or test with the latest release. @@ -76,6 +78,14 @@ when following the steps above: #. Set the ``tectonic_azure_ssh_key`` to the path of the public key created in the previous step. +#. We recommend setting up or using a CA(Certificate Authority) to generate Tectonic + Console's server certificate(s) and adding it to your trusted authorities on the client side, + accessing the Tectonic Console i.e. Browser. If you already have a CA(self-signed or otherwise), + Set the ``tectonic_ca_cert`` and ``tectonic_ca_key`` configurations with the content + of PEM-encoded certificate and key files, respectively. For more information about, how to set + up a self-signed CA, Please refer to + :doc:`How to Set up self-signed CA `. + #. Note that the ``tectonic_azure_client_secret`` is the same as the ``ARM_CLIENT_SECRET``. @@ -85,6 +95,10 @@ when following the steps above: ``test-cluster`` and specified the datacenter as ``westeurope``, the Tectonic console will be available at ``test-cluster.westeurope.cloudapp.azure.com``. +#. Note that, if you do not specify ``tectonic_ca_cert``, a CA certificate will + be generated automatically and you will encounter the untrusted certificate + message on your client(Browser), when accessing the Tectonic Console. + Step 4: Configure kubectl ------------------------- diff --git a/docs/server/source/production-deployment-template/template-kubernetes-azure.rst b/docs/server/source/production-deployment-template/template-kubernetes-azure.rst index a916012f..7312ba36 100644 --- a/docs/server/source/production-deployment-template/template-kubernetes-azure.rst +++ b/docs/server/source/production-deployment-template/template-kubernetes-azure.rst @@ -105,6 +105,21 @@ Finally, you can deploy an ACS using something like: --orchestrator-type kubernetes \ --debug --output json +.. Note:: + Please refer to `Azure documentation `_ + for a comprehensive list of options available for `az acs create`. + Please tune the following parameters as per your requirement: + + * Master count. + + * Agent count. + + * Agent VM size. + + * **Optional**: Master storage profile. + + * **Optional**: Agent storage profile. + There are more options. For help understanding all the options, use the built-in help: diff --git a/k8s/mongodb/mongo-sc.yaml b/k8s/mongodb/mongo-sc.yaml index 2f291ffe..9be5ed05 100644 --- a/k8s/mongodb/mongo-sc.yaml +++ b/k8s/mongodb/mongo-sc.yaml @@ -7,8 +7,12 @@ metadata: name: slow-db provisioner: kubernetes.io/azure-disk parameters: - skuName: Standard_LRS + skuName: Standard_LRS #[Standard_LRS, Premium_LRS] location: westeurope + # If you have created a different storage account e.g. for Premium Storage + #storageAccount: + # Use Managed Disk(s) with VMs using Managed Disks(Only used for Tectonic deployment) + #kind: Managed --- ###################################################################### # This YAML section desribes a StorageClass for the mongodb configDB # @@ -19,5 +23,9 @@ metadata: name: slow-configdb provisioner: kubernetes.io/azure-disk parameters: - skuName: Standard_LRS + skuName: Standard_LRS #[Standard_LRS, Premium_LRS] location: westeurope + # If you have created a different storage account e.g. for Premium Storage + #storageAccount: + # Use Managed Disk(s) with VMs using Managed Disks(Only used for Tectonic deployment) + #kind: Managed From 977a6426fece72e788a40e99c3b07f8acb86c3e8 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Fri, 10 Nov 2017 12:53:51 +0100 Subject: [PATCH 106/120] Make premium_lrs default --- k8s/mongodb/mongo-sc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/k8s/mongodb/mongo-sc.yaml b/k8s/mongodb/mongo-sc.yaml index 9be5ed05..2b155d54 100644 --- a/k8s/mongodb/mongo-sc.yaml +++ b/k8s/mongodb/mongo-sc.yaml @@ -7,7 +7,7 @@ metadata: name: slow-db provisioner: kubernetes.io/azure-disk parameters: - skuName: Standard_LRS #[Standard_LRS, Premium_LRS] + skuName: Premium_LRS #[Premium_LRS, Standard_LRS] location: westeurope # If you have created a different storage account e.g. for Premium Storage #storageAccount: @@ -23,7 +23,7 @@ metadata: name: slow-configdb provisioner: kubernetes.io/azure-disk parameters: - skuName: Standard_LRS #[Standard_LRS, Premium_LRS] + skuName: Premium_LRS #[Premium_LRS, Standard_LRS] location: westeurope # If you have created a different storage account e.g. for Premium Storage #storageAccount: From 241af47a32c0719d7e05d40360e9768609703b93 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Wed, 18 Oct 2017 17:59:08 +0200 Subject: [PATCH 107/120] Automation of multi node BigchainDB deployment for dev/test - Setup single/multi node BigchainDB cluster using - Vagrant - Ansible - Updated documentation --- .../source/appendices/run-with-ansible.md | 109 +++++++++++++--- .../source/appendices/run-with-vagrant.md | 120 +++++++++++------- pkg/Vagrantfile | 62 +++++++-- pkg/ansible/quickstart.yml | 10 -- pkg/ansible/roles/bigchaindb/tasks/main.yml | 16 --- .../roles/bigchaindb/tasks/with_docker.yml | 25 ---- pkg/ansible/roles/mongodb/tasks/common.yml | 10 -- pkg/ansible/roles/mongodb/tasks/main.yml | 31 ----- .../roles/mongodb/tasks/with_docker.yml | 20 --- pkg/config/bdb-config.yaml | 14 -- pkg/configuration/bdb-deploy.yml | 12 ++ pkg/configuration/group_vars/all | 5 + pkg/configuration/host_vars/bdb-node-01 | 5 + pkg/configuration/hosts/all | 8 ++ pkg/configuration/multi_node.yml | 5 + pkg/configuration/pre_req.yml | 8 ++ .../roles/bigchaindb-driver/defaults/main.yml | 7 +- .../roles/bigchaindb-driver/tasks/centos.yml | 0 .../roles/bigchaindb-driver/tasks/common.yml | 0 .../roles/bigchaindb-driver/tasks/debian.yml | 0 .../roles/bigchaindb-driver/tasks/fedora.yml | 0 .../roles/bigchaindb-driver/tasks/main.yml | 8 +- .../roles/bigchaindb/defaults/main.yml | 19 +-- .../roles/bigchaindb/tasks/centos.yml | 0 .../roles/bigchaindb/tasks/common.yml | 27 +++- .../roles/bigchaindb/tasks/debian.yml | 0 .../roles/bigchaindb/tasks/deploy_docker.yml | 51 ++++++++ .../roles/bigchaindb/tasks/fedora.yml | 0 .../roles/bigchaindb/tasks/main.yml | 20 +++ .../roles/docker-compose/defaults/main.yml | 0 .../roles/docker-compose/tasks/main.yml | 0 .../roles/docker/defaults/main.yml | 0 .../roles/docker/tasks/centos.yml | 0 .../roles/docker/tasks/debian.yml | 0 .../roles/docker/tasks/fedora.yml | 0 .../roles/docker/tasks/main.yml | 6 +- .../roles/key-exchange/defaults/main.yml | 13 ++ .../roles/key-exchange/tasks/main.yml | 8 ++ .../tasks/pub_key_exchange_docker.yml | 31 +++++ .../tasks/pub_key_exchange_host.yml | 28 ++++ .../templates/exchange_keyring_docker.j2 | 18 +++ .../templates/exchange_keyring_host.j2 | 21 +++ .../roles/mongodb/defaults/main.yml | 27 ++-- .../roles/mongodb/files/mongod.conf | 101 +++++++++++++++ .../roles/mongodb/tasks/centos.yml | 7 + .../roles/mongodb/tasks/common.yml | 25 ++++ .../roles/mongodb/tasks/debian.yml | 7 +- .../roles/mongodb/tasks/deploy_docker.yml | 48 +++++++ .../roles/mongodb/tasks/fedora.yml | 4 +- .../roles/mongodb/tasks/initiate_repl_set.yml | 6 + .../tasks/initiate_repl_set_docker.yml | 13 ++ .../mongodb/tasks/initiate_repl_set_host.yml | 20 +++ .../roles/mongodb/tasks/main.yml | 31 +++++ .../mongodb/templates/replSet_init_docker.j2 | 30 +++++ .../mongodb/templates/replSet_init_host.j2 | 7 + pkg/configuration/vars/bdb-config.yml | 13 ++ pkg/scripts/bootstrap_helper.sh | 14 +- 57 files changed, 830 insertions(+), 240 deletions(-) delete mode 100644 pkg/ansible/quickstart.yml delete mode 100644 pkg/ansible/roles/bigchaindb/tasks/main.yml delete mode 100644 pkg/ansible/roles/bigchaindb/tasks/with_docker.yml delete mode 100644 pkg/ansible/roles/mongodb/tasks/common.yml delete mode 100644 pkg/ansible/roles/mongodb/tasks/main.yml delete mode 100644 pkg/ansible/roles/mongodb/tasks/with_docker.yml delete mode 100644 pkg/config/bdb-config.yaml create mode 100644 pkg/configuration/bdb-deploy.yml create mode 100644 pkg/configuration/group_vars/all create mode 100644 pkg/configuration/host_vars/bdb-node-01 create mode 100644 pkg/configuration/hosts/all create mode 100644 pkg/configuration/multi_node.yml create mode 100644 pkg/configuration/pre_req.yml rename pkg/{ansible => configuration}/roles/bigchaindb-driver/defaults/main.yml (62%) rename pkg/{ansible => configuration}/roles/bigchaindb-driver/tasks/centos.yml (100%) rename pkg/{ansible => configuration}/roles/bigchaindb-driver/tasks/common.yml (100%) rename pkg/{ansible => configuration}/roles/bigchaindb-driver/tasks/debian.yml (100%) rename pkg/{ansible => configuration}/roles/bigchaindb-driver/tasks/fedora.yml (100%) rename pkg/{ansible => configuration}/roles/bigchaindb-driver/tasks/main.yml (65%) rename pkg/{ansible => configuration}/roles/bigchaindb/defaults/main.yml (60%) rename pkg/{ansible => configuration}/roles/bigchaindb/tasks/centos.yml (100%) rename pkg/{ansible => configuration}/roles/bigchaindb/tasks/common.yml (53%) rename pkg/{ansible => configuration}/roles/bigchaindb/tasks/debian.yml (100%) create mode 100644 pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml rename pkg/{ansible => configuration}/roles/bigchaindb/tasks/fedora.yml (100%) create mode 100644 pkg/configuration/roles/bigchaindb/tasks/main.yml rename pkg/{ansible => configuration}/roles/docker-compose/defaults/main.yml (100%) rename pkg/{ansible => configuration}/roles/docker-compose/tasks/main.yml (100%) rename pkg/{ansible => configuration}/roles/docker/defaults/main.yml (100%) rename pkg/{ansible => configuration}/roles/docker/tasks/centos.yml (100%) rename pkg/{ansible => configuration}/roles/docker/tasks/debian.yml (100%) rename pkg/{ansible => configuration}/roles/docker/tasks/fedora.yml (100%) rename pkg/{ansible => configuration}/roles/docker/tasks/main.yml (89%) create mode 100644 pkg/configuration/roles/key-exchange/defaults/main.yml create mode 100644 pkg/configuration/roles/key-exchange/tasks/main.yml create mode 100644 pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml create mode 100644 pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_host.yml create mode 100644 pkg/configuration/roles/key-exchange/templates/exchange_keyring_docker.j2 create mode 100644 pkg/configuration/roles/key-exchange/templates/exchange_keyring_host.j2 rename pkg/{ansible => configuration}/roles/mongodb/defaults/main.yml (70%) create mode 100644 pkg/configuration/roles/mongodb/files/mongod.conf rename pkg/{ansible => configuration}/roles/mongodb/tasks/centos.yml (79%) create mode 100644 pkg/configuration/roles/mongodb/tasks/common.yml rename pkg/{ansible => configuration}/roles/mongodb/tasks/debian.yml (81%) create mode 100644 pkg/configuration/roles/mongodb/tasks/deploy_docker.yml rename pkg/{ansible => configuration}/roles/mongodb/tasks/fedora.yml (85%) create mode 100644 pkg/configuration/roles/mongodb/tasks/initiate_repl_set.yml create mode 100644 pkg/configuration/roles/mongodb/tasks/initiate_repl_set_docker.yml create mode 100644 pkg/configuration/roles/mongodb/tasks/initiate_repl_set_host.yml create mode 100644 pkg/configuration/roles/mongodb/tasks/main.yml create mode 100644 pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 create mode 100644 pkg/configuration/roles/mongodb/templates/replSet_init_host.j2 create mode 100644 pkg/configuration/vars/bdb-config.yml diff --git a/docs/server/source/appendices/run-with-ansible.md b/docs/server/source/appendices/run-with-ansible.md index 70e4b595..b3bcdfba 100644 --- a/docs/server/source/appendices/run-with-ansible.md +++ b/docs/server/source/appendices/run-with-ansible.md @@ -2,8 +2,8 @@ **NOT for Production Use** -You can use the following instructions to deploy a BigchainDB node for -dev/test using Ansible. Ansible will setup a BigchainDB node along with +You can use the following instructions to deploy a single or multi node +BigchainDB setup for dev/test using Ansible. Ansible will setup BigchainDB node(s) along with [Docker](https://www.docker.com/), [Docker Compose](https://docs.docker.com/compose/), [MongoDB](https://www.mongodb.com/), [BigchainDB Python driver](https://docs.bigchaindb.com/projects/py-driver/en/latest/). @@ -26,36 +26,113 @@ Navigate to `bigchaindb/pkg/scripts` and run the `bootstrap.sh` script to instal for your OS. The script also checks if the OS you are running is compatible with the supported versions. +**Note**: `bootstrap.sh` only supports Ubuntu >= 16.04, CentOS >= 7 and Fedora >=24. + ```text $ cd bigchaindb/pkg/scripts/ $ sudo ./bootstrap.sh ``` -### Local Setup | Ansible -You can safely run the `quickstart` playbook now and everything will be taken care of by `ansible` on your host. `quickstart` playbook only supports deployment on your dev/local host. To run the playbook please navigate to the ansible directory inside the BigchainDB repository and run the `quickstart` playbook. +### BigchainDB Setup Configuration(s) | Ansible +#### Local Setup | Ansible +You can run the Ansible playbook `bdb-deploy.yml` on your local dev machine and set up the BigchainDB node where +BigchainDB can be run as a process or inside a Docker container(s) depending on your configuratin. +Before, running the playbook locally, you need to update the `hosts` and `bdb-config.yml` configuration, which will notify Ansible that we need to run the play locally. + +##### Update Hosts | Local +Navigate to `bigchaindb/pkg/configuration/hosts` inside the BigchainDB repository. ```text -$ cd bigchaindb/pkg/ansible/ - -# All the services will be deployed as processes -$ sudo ansible-playbook quickstart.yml -c local - -OR - -# To deploy all services inside docker containers -$ sudo ansible-playbook quickstart.yml --extra-vars "with_docker=true" -c local +$ cd bigchaindb/pkg/configuration/hosts ``` -After successfull execution of the playbook, you can verify that BigchainDB docker/process is running. +Edit `all` configuration file: +```text +# Delete any existing configuration in this file and insert +localhost ansible_connection=local +``` +##### Update Configuration | Local +Navigate to `bigchaindb/pkg/configuration/vars` inside the BigchainDB repository. +```text +$ cd bigchaindb/pkg/configuration/vars/bdb-config.yml +``` -Verify BigchainDB process: +Edit `bdb-config.yml` configuration file as per your requirements, sample configuration file(s): +```text +--- +deploy_docker: false #[true, false] +docker_replset_size: 1 # Only needed if `deploy_docker` is true +bdb_hosts: + - name: "" +``` +**Note**: You can also orchestrate a multi-node BigchainDB cluster on a local dev host using Docker containers. +Here is a sample `bdb-config.yml` +```text +--- +deploy_docker: true #[true, false] +docker_replset_size: 3 +bdb_hosts: + - name: "" +``` + +#### Remote Setup | Ansible +You can also run the Ansible playbook `bdb-deploy.yml` on remote machine(s) and set up the BigchainDB node where +BigchainDB can be run as a process or inside a Docker container(s) depending on your configuration. + +Before, running the playbook on a remote host, you need to update the `hosts` and `bdb-config.yml` configuration, which will notify Ansible that we need to run the play on a remote host. + +##### Update Hosts | Remote +Navigate to `bigchaindb/pkg/configuration/hosts` inside the BigchainDB repository. +```text +$ cd bigchaindb/pkg/configuration/hosts +``` + +Edit `all` configuration file: +```text +# Delete any existing configuration in this file and insert + ansible_ssh_user= ansible_sudo_pass= +``` + +**Note 1**: You can multiple hosts to `all` configuration file. Root password is needed because ansible +will run some tasks that require root permissions. + +**Note 2**: You can also use other methods to get inside the remote machines instead of password based SSH. For other methods +please consult [Ansible Documentation](http://docs.ansible.com/ansible/latest/intro_getting_started.html). + +##### Update Configuration | Remote +Navigate to `bigchaindb/pkg/configuration/vars` inside the BigchainDB repository. +```text +$ cd bigchaindb/pkg/configuration/vars/bdb-config.yml +``` + +Edit `bdb-config.yml` configuration file as per your requirements, sample configuration file(s): +```text +--- +deploy_docker: false #[true, false] +docker_replset_size: 1 # Only needed if `deploy_docker` is true +bdb_hosts: + - name: "" +``` + +### BigchainDB Setup | Ansible +Now, You can safely run the `bdb-deploy.yml` playbook and everything will be taken care of by `Ansible`. To run the playbook please navigate to the `bigchaindb/pkg/configuration` directory inside the BigchainDB repository and run the `bdb-deploy.yml` playbook. + +```text +$ cd bigchaindb/pkg/configuration/ + +$ sudo ansible-playbook bdb-deploy.yml -i /bigchaindb/configuration/hosts/all +``` + +After successfull execution of the playbook, you can verify that BigchainDB docker(s)/process(es) is(are) running. + +Verify BigchainDB process(es): ```text $ ps -ef | grep bigchaindb ``` OR -Verify BigchainDB Docker: +Verify BigchainDB Docker(s): ```text $ docker ps | grep bigchaindb ``` diff --git a/docs/server/source/appendices/run-with-vagrant.md b/docs/server/source/appendices/run-with-vagrant.md index c396017a..e70dd715 100644 --- a/docs/server/source/appendices/run-with-vagrant.md +++ b/docs/server/source/appendices/run-with-vagrant.md @@ -2,10 +2,10 @@ **NOT for Production Use** -You can use the following instructions to deploy a BigchainDB node -for dev/test using Vagrant. Vagrant will setup a BigchainDB node with -all the dependencies along with MongoDB, BigchainDB Python driver. You -can also tweak the following configurations for the BigchainDB node. +You can use the following instructions to deploy a single or multi node +BigchainDB setup for dev/test using Vagrant. Vagrant will set up the BigchainDB node(s) +with all the dependencies along with MongoDB and BigchainDB Python driver. You +can also tweak the following configurations for the BigchainDB node(s). - Vagrant Box - Currently, we support the following boxes: - `ubuntu/xenial64 # >=16.04` @@ -19,10 +19,11 @@ can also tweak the following configurations for the BigchainDB node. - Network Type - Currently, only `private_network` is supported. - IP Address -- Setup type - - `quickstart` - Deploy node with Docker - Deploy all the services in Docker containers or as processes. +- Size of Replica Set(Number of cluster member) + - If you want to deploy the services inside Docker containers, you + can specify number of member(s) in the MongoDB/BigchainDB cluster. - Upstart Script - Vagrant Provider - Virtualbox @@ -38,64 +39,84 @@ $ git clone https://github.com/bigchaindb/bigchaindb.git ``` ## Configuration | Vagrant -Navigate to `bigchaindb/pkg/config/` inside the repository. +Navigate to `bigchaindb/pkg/config/` inside the BigchainDB repository. ```text $ cd bigchaindb/pkg/config/ ``` -Edit the `bdb-config.yaml` as per your requirements. Sample `bdb-config.yaml`: +Edit `bdb-config.yml` as per your requirements. Sample `bdb-config.yml`: ```text --- -- name: "bdb-node-01" - box: - name: "ubuntu/xenial64" - ram: "2048" - vcpus: "2" - setup_type: "quickstart" - deploy_docker: false - network: - ip: "10.20.30.40" - type: "private_network" - upstart: "/bigchaindb/scripts/bootstrap.sh" +deploy_docker: false #[true, false] +docker_replset_size: 1 +upstart: "/bigchaindb/scripts/bootstrap.sh" +bdb_hosts: + - name: "bdb-node-01" + box: + name: "ubuntu/xenial64" + ram: "2048" + vcpus: "2" + network: + ip: "10.20.30.40" + type: "private_network" ``` -**Note**: You can spawn multiple instances as well using `bdb-config.yaml`. Here is a sample `bdb-config.yaml`: +**Note**: You can spawn multiple instances to orchestrate a multi-node BigchainDB cluster. +Here is a sample `bdb-config.yml`: ```text --- -- name: "bdb-node-01" - box: - name: "ubuntu/xenial64" - ram: "2048" - vcpus: "2" - setup_type: "quickstart" - deploy_docker: false - network: - ip: "10.20.30.40" - type: "private_network" - upstart: "/bigchaindb/scripts/bootstrap.sh" -- name: "bdb-node-02" - box: - name: "ubuntu/xenial64" - ram: "4096" - vcpus: "3" - setup_type: "quickstart" - deploy_docker: false - network: - ip: "10.20.30.50" - type: "private_network" - upstart: "/bigchaindb/scripts/bootstrap.sh" +deploy_docker: false #[true, false] +docker_replset_size: 1 +upstart: "/bigchaindb/scripts/bootstrap.sh" +bdb_hosts: + - name: "bdb-node-01" + box: + name: "ubuntu/xenial64" + ram: "2048" + vcpus: "2" + network: + ip: "10.20.30.40" + type: "private_network" + - name: "bdb-node-02" + box: + name: "ubuntu/xenial64" + ram: "2048" + vcpus: "2" + network: + ip: "10.20.30.50" + type: "private_network" ``` +**Note**: You can also orchestrate a multi-node BigchainDB cluster on a single dev host using Docker containers. +Here is a sample `bdb-config.yml` +```text +--- +deploy_docker: true #[true, false] +docker_replset_size: 3 +upstart: "/bigchaindb/scripts/bootstrap.sh" +bdb_hosts: + - name: "bdb-node-01" + box: + name: "ubuntu/xenial64" + ram: "8192" + vcpus: "4" + network: + ip: "10.20.30.40" + type: "private_network" +``` +The above mentioned configuration will deploy a 3 node BigchainDB cluster with Docker containers +on your specified host. - -## Local Setup | Vagrant -To bring up the BigchainDB node, run the following command: +## BigchainDB Setup | Vagrant +To bring up the BigchainDB node(s), run the following command: ```text $ vagrant up ``` -*Note*: There are some vagrant plugins required for the installation, user will be prompted to install them if they are not present. Instructions to install the plugins can be extracted from the message. +**Note**: There are some vagrant plugins required for the installation, +user will be prompted to install them if they are not present. Instructions +to install the plugins can be extracted from the message. ```text $ vagrant plugin install @@ -108,16 +129,17 @@ $ vagrant ssh ``` ## Make your first transaction -Once you are inside the BigchainDB node, you can verify that BigchainDB docker/process is running. +Once you are inside the BigchainDB node, you can verify that BigchainDB +docker(s)/process(es) is(are) running. -Verify BigchainDB process: +Verify BigchainDB process(es): ```text $ ps -ef | grep bigchaindb ``` OR -Verify BigchainDB Docker: +Verify BigchainDB Docker(s): ```text $ docker ps | grep bigchaindb ``` diff --git a/pkg/Vagrantfile b/pkg/Vagrantfile index b8720016..8bfebe94 100644 --- a/pkg/Vagrantfile +++ b/pkg/Vagrantfile @@ -9,10 +9,12 @@ Vagrant.require_version '>= 1.6.0' VAGRANTFILE_API_VERSION = '2' # Configuration files -CONFIGURATION_FILE = 'config/bdb-config.yaml' +CONFIGURATION_FILE = 'configuration/vars/bdb-config.yml' +HOSTS_FILE = 'configuration/hosts/all' +HOST_VARS_PATH = 'configuration/host_vars' # Validate if all the required plugins are present -required_plugins = ["vagrant-cachier"] +required_plugins = ["vagrant-cachier", "vagrant-vbguest", "vagrant-hosts"] required_plugins.each do |plugin| if not Vagrant.has_plugin?(plugin) raise "Required vagrant plugin #{plugin} not found. Please run `vagrant plugin install #{plugin}`" @@ -21,10 +23,22 @@ end # Read configuration file(s) instances_config = YAML.load_file(File.join(File.dirname(__FILE__), CONFIGURATION_FILE)) - -#TODO: (muawiakh) Add support for Docker, AWS, Azure +hosts_config = File.open(HOSTS_FILE, 'w+') +# TODO: (muawiakh) Add support for Docker, AWS, Azure Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - instances_config.each do |instance| + instances_config["bdb_hosts"].each do |instance| + # Workaround till canonical fixes https://bugs.launchpad.net/cloud-images/+bug/1569237 + # using -u ubuntu as remote user, conventionally vagrant boxes use `vagrant` user + if instance["box"]["name"] == "ubuntu/xenial64" + hosts_config.puts("#{instance["name"]} ansible_user=ubuntu") + if Vagrant.has_plugin?("vagrant-vbguest") + config.vbguest.auto_update = false + config.vbguest.no_install = true + config.vbguest.no_remote = true + end + else + hosts_config.puts("#{instance["name"]} ansible_user=vagrant") + end config.vm.define instance['name'] do |bdb| # Workaround until vagrant cachier plugin supports dnf if !(instance["box"]["name"].include? "fedora") @@ -40,14 +54,12 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| else raise "Invalid network type: Please specify one of the following: [private_network, public_network]" end + bdb.vm.provision :hosts, :sync_hosts => true bdb.vm.box = instance["box"]["name"] bdb.vm.synced_folder ".", "/bigchaindb" - bdb.vm.provision :shell, inline: "cd /bigchaindb/scripts;/bin/bash #{instance["upstart"]}" - if instance["setup_type"] == "quickstart" - bdb.vm.provision :shell, inline: "PYTHONBUFFERED=1 ansible-playbook \ - /bigchaindb/ansible/quickstart.yml --extra-vars \"with_docker=#{instance["deploy_docker"]}\" -c local" - end - + File.open("#{HOST_VARS_PATH}/#{instance["name"]}", "w+") {|f| \ + f.write("ansible_ssh_private_key_file: /bigchaindb/.vagrant/machines/#{instance["name"]}/virtualbox/private_key") } + bdb.vm.provision :shell, inline: "cd /bigchaindb/scripts;/bin/bash #{instances_config["upstart"]}" bdb.vm.provider 'vmware_fusion' do |vmwf, override| vmwf.vmx['memsize'] = instance["ram"] vmwf.vmx['numvcpus'] = instance['vcpus'] @@ -59,4 +71,32 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| end end end + hosts_config.close + config.vm.define "config-node" do |bdb| + bdb.vm.box = "ubuntu/xenial64" + bdb.vm.hostname = "config-node" + bdb.vm.provision :hosts, :sync_hosts => true + bdb.vm.synced_folder ".", "/bigchaindb" + bdb.vm.network "private_network", ip: "192.168.100.200" + bdb.vm.provision :shell, inline: "cd /bigchaindb/scripts;/bin/bash #{instances_config["upstart"]}" + bdb.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /bigchaindb/configuration/bdb-deploy.yml \ + -c /bigchaindb/configuration/hosts/all" + bdb.vm.provider "virtualbox" do |vb| + vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] + vb.memory = 2048 + vb.cpus = 2 + end + bdb.vm.provider 'vmware_fusion' do |vmwf| + vmwf.vmx['memsize'] = 2048 + vmwf.vmx['numvcpus'] = 2 + end + if Vagrant.has_plugin?("vagrant-vbguest") + config.vbguest.auto_update = false + config.vbguest.no_install = true + config.vbguest.no_remote = true + end + if Vagrant.has_plugin?("vagrant-cachier") + config.cache.scope = :box + end + end end diff --git a/pkg/ansible/quickstart.yml b/pkg/ansible/quickstart.yml deleted file mode 100644 index aa0f8c49..00000000 --- a/pkg/ansible/quickstart.yml +++ /dev/null @@ -1,10 +0,0 @@ -- hosts: localhost - remote_user: vagrant - vars: - with_docker: "{{ deploy_docker | default(false) }}" - roles: - - { role: docker, when: with_docker|bool } - - { role: docker-compose, when: with_docker|bool } - - mongodb - - bigchaindb - - bigchaindb-driver \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/tasks/main.yml b/pkg/ansible/roles/bigchaindb/tasks/main.yml deleted file mode 100644 index 532c4ae6..00000000 --- a/pkg/ansible/roles/bigchaindb/tasks/main.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -- include: with_docker.yml - when: with_docker|bool - tags: [bigchaindb] - -- include: debian.yml - when: not with_docker|bool and (distribution_name == "debian" or distribution_name == "ubuntu") - -- include: centos.yml - when: not with_docker|bool and (distribution_name == "centos" or distribution_name == "red hat enterprise linux") - -- include: fedora.yml - when: not with_docker|bool and (distribution_name == "fedora") - -- include: common.yml - when: not with_docker|bool \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/tasks/with_docker.yml b/pkg/ansible/roles/bigchaindb/tasks/with_docker.yml deleted file mode 100644 index bf832711..00000000 --- a/pkg/ansible/roles/bigchaindb/tasks/with_docker.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -- name: Configuring BigchainDB Docker - docker_container: - name: "{{ bigchaindb_docker_name }}" - image: "{{ bigchaindb_image_name }}" - volumes: "{{ bigchaindb_docker_volumes }}" - pull: false - env: - BIGCHAINDB_SERVER_BIND: "{{ bigchaindb_server_bind }}" - BIGCHAINDB_DATABASE_HOST: "{{ bigchaindb_database_host }}" - entrypoint: "bigchaindb -y configure mongodb" - register: result - tags: [bigchaindb] - -- name: Start BigchainDB Docker - docker_container: - name: "{{ bigchaindb_docker_name }}" - image: "{{ bigchaindb_image_name }}" - published_ports: "{{ bigchaindb_docker_published_ports }}" - restart_policy: always - volumes: "{{ bigchaindb_docker_volumes }}" - state: started - pull: false - when: result|succeeded - tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/common.yml b/pkg/ansible/roles/mongodb/tasks/common.yml deleted file mode 100644 index 41c6de1d..00000000 --- a/pkg/ansible/roles/mongodb/tasks/common.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -- name: MongoDB Process Check - shell: pgrep mongod | wc -l - register: command_result - tags: [mongodb] - -- name: Run MongoDB - shell: "mongod --replSet=bigchain-rs --logpath {{ mongodb_log_path }}/mongod.log &" - when: command_result.stdout| int != 1 - tags: [mongodb] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/main.yml b/pkg/ansible/roles/mongodb/tasks/main.yml deleted file mode 100644 index 451b81b9..00000000 --- a/pkg/ansible/roles/mongodb/tasks/main.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- -- name: Creating directories - file: - path: "{{ item }}" - state: directory - mode: 0700 - with_items: "{{ directories }}" - tags: [mongodb] - -- include: with_docker.yml - when: with_docker|bool - -- name: Verify logfiles exist | Debian - file: - path: "{{ mongodb_log_path }}/mongod.log" - state: touch - mode: 0755 - when: not with_docker|bool - tags: [mongodb] - -- include: debian.yml - when: not with_docker|bool and (distribution_name == "debian" or distribution_name == "ubuntu") - -- include: centos.yml - when: not with_docker|bool and (distribution_name == "centos" or distribution_name == "red hat enterprise linux") - -- include: fedora.yml - when: not with_docker|bool and (distribution_name == "fedora") - -- include: common.yml - when: not with_docker|bool \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/with_docker.yml b/pkg/ansible/roles/mongodb/tasks/with_docker.yml deleted file mode 100644 index ff3a24a5..00000000 --- a/pkg/ansible/roles/mongodb/tasks/with_docker.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -- name: Check Docker Service - systemd: - name: docker - enabled: yes - state: started - tags: [docker] - -- name: Running MongoDB Docker - docker_container: - name: "{{ mongodb_docker_name }}" - image: "{{ mongodb_docker_image }}" - detach: True - published_ports: "{{ mongodb_docker_published_ports }}" - restart_policy: always - volumes: "{{ mongodb_docker_volumes }}" - state: started - pull: false - entrypoint: /entrypoint.sh --replSet=bigchain-rs - tags: [mongodb] \ No newline at end of file diff --git a/pkg/config/bdb-config.yaml b/pkg/config/bdb-config.yaml deleted file mode 100644 index 86acac56..00000000 --- a/pkg/config/bdb-config.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -- name: "bdb-node-01" # Instance name - box: - name: "ubuntu/xenial64" # Box name - ram: "2048" - vcpus: "2" - setup_type: "quickstart" # Currently, only quickstart is supported. - deploy_docker: true # [true, false] - network: - ip: "10.20.30.50" - type: "private_network" - # Active network interface on host, Only required for public network e.g "en0: Wi-Fi (AirPort)" - bridge: "" - upstart: "/bigchaindb/scripts/bootstrap.sh" # Path to upstart script diff --git a/pkg/configuration/bdb-deploy.yml b/pkg/configuration/bdb-deploy.yml new file mode 100644 index 00000000..9bd93d98 --- /dev/null +++ b/pkg/configuration/bdb-deploy.yml @@ -0,0 +1,12 @@ +- import_playbook: pre_req.yml + +- hosts: all + vars_files: + - vars/bdb-config.yml + serial: 1 + roles: + - bigchaindb + - bigchaindb-driver + +- import_playbook: multi_node.yml + when: (bdb_hosts|length > 1) or docker_replset_size|int > 1 \ No newline at end of file diff --git a/pkg/configuration/group_vars/all b/pkg/configuration/group_vars/all new file mode 100644 index 00000000..f530443e --- /dev/null +++ b/pkg/configuration/group_vars/all @@ -0,0 +1,5 @@ +--- +ansible_connection: ssh +ansible_ssh_port: 22 +ansible_become: yes +ansible_ssh_common_args: '-o StrictHostKeyChecking=no' \ No newline at end of file diff --git a/pkg/configuration/host_vars/bdb-node-01 b/pkg/configuration/host_vars/bdb-node-01 new file mode 100644 index 00000000..e20d655a --- /dev/null +++ b/pkg/configuration/host_vars/bdb-node-01 @@ -0,0 +1,5 @@ +# Place holder file for users, running Ansible playbooks manually. Otherwise Vagrant +# populates this dynamically. + +# Only needed for logging into remote hosts and adding host specific variables e.g. +#ansible_ssh_private_key_file: "/path/to/private/key" \ No newline at end of file diff --git a/pkg/configuration/hosts/all b/pkg/configuration/hosts/all new file mode 100644 index 00000000..1f7800f2 --- /dev/null +++ b/pkg/configuration/hosts/all @@ -0,0 +1,8 @@ +# Place holder file for users, running Ansible playbooks manually. Otherwise Vagrant +# populates this dynamically. + +# For local host +#localhost ansible_connection=local + +# For remote host(s) +# ansible_ssh_user= ansible_sudo_pass= \ No newline at end of file diff --git a/pkg/configuration/multi_node.yml b/pkg/configuration/multi_node.yml new file mode 100644 index 00000000..aa293ad9 --- /dev/null +++ b/pkg/configuration/multi_node.yml @@ -0,0 +1,5 @@ +- hosts: all + vars_files: + - vars/bdb-config.yml + roles: + - key-exchange \ No newline at end of file diff --git a/pkg/configuration/pre_req.yml b/pkg/configuration/pre_req.yml new file mode 100644 index 00000000..b7e54581 --- /dev/null +++ b/pkg/configuration/pre_req.yml @@ -0,0 +1,8 @@ +- hosts: all + vars_files: + - vars/bdb-config.yml + serial: 1 + roles: + - { role: docker, when: deploy_docker|bool } + - { role: docker-compose, when: deploy_docker|bool } + - mongodb \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb-driver/defaults/main.yml b/pkg/configuration/roles/bigchaindb-driver/defaults/main.yml similarity index 62% rename from pkg/ansible/roles/bigchaindb-driver/defaults/main.yml rename to pkg/configuration/roles/bigchaindb-driver/defaults/main.yml index 63485cce..28c99323 100644 --- a/pkg/ansible/roles/bigchaindb-driver/defaults/main.yml +++ b/pkg/configuration/roles/bigchaindb-driver/defaults/main.yml @@ -23,4 +23,9 @@ dependencies_dnf: - python3-pip python_pip_upgrade: true -python_setuptools_upgrade: true \ No newline at end of file +python_setuptools_upgrade: true + +# Host configuration +distribution_name: "{{ ansible_distribution|lower }}" +distribution_codename: "{{ ansible_distribution_release|lower }}" +distribution_major: "{{ ansible_distribution_major_version }}" \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml b/pkg/configuration/roles/bigchaindb-driver/tasks/centos.yml similarity index 100% rename from pkg/ansible/roles/bigchaindb-driver/tasks/centos.yml rename to pkg/configuration/roles/bigchaindb-driver/tasks/centos.yml diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/common.yml b/pkg/configuration/roles/bigchaindb-driver/tasks/common.yml similarity index 100% rename from pkg/ansible/roles/bigchaindb-driver/tasks/common.yml rename to pkg/configuration/roles/bigchaindb-driver/tasks/common.yml diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/debian.yml b/pkg/configuration/roles/bigchaindb-driver/tasks/debian.yml similarity index 100% rename from pkg/ansible/roles/bigchaindb-driver/tasks/debian.yml rename to pkg/configuration/roles/bigchaindb-driver/tasks/debian.yml diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/fedora.yml b/pkg/configuration/roles/bigchaindb-driver/tasks/fedora.yml similarity index 100% rename from pkg/ansible/roles/bigchaindb-driver/tasks/fedora.yml rename to pkg/configuration/roles/bigchaindb-driver/tasks/fedora.yml diff --git a/pkg/ansible/roles/bigchaindb-driver/tasks/main.yml b/pkg/configuration/roles/bigchaindb-driver/tasks/main.yml similarity index 65% rename from pkg/ansible/roles/bigchaindb-driver/tasks/main.yml rename to pkg/configuration/roles/bigchaindb-driver/tasks/main.yml index f743ff1c..f70ef304 100644 --- a/pkg/ansible/roles/bigchaindb-driver/tasks/main.yml +++ b/pkg/configuration/roles/bigchaindb-driver/tasks/main.yml @@ -1,12 +1,12 @@ --- -- include: debian.yml +- import_tasks: debian.yml when: distribution_name == "debian" or distribution_name == "ubuntu" -- include: centos.yml +- import_tasks: centos.yml when: distribution_name == "centos" or distribution_name == "red hat enterprise linux" -- include: fedora.yml +- import_tasks: fedora.yml when: distribution_name == "fedora" -- include: common.yml \ No newline at end of file +- import_tasks: common.yml \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/defaults/main.yml b/pkg/configuration/roles/bigchaindb/defaults/main.yml similarity index 60% rename from pkg/ansible/roles/bigchaindb/defaults/main.yml rename to pkg/configuration/roles/bigchaindb/defaults/main.yml index 83058813..746cc8e6 100644 --- a/pkg/ansible/roles/bigchaindb/defaults/main.yml +++ b/pkg/configuration/roles/bigchaindb/defaults/main.yml @@ -27,21 +27,24 @@ dependencies_dnf: python_pip_upgrade: true python_setuptools_upgrade: true +# Host configuration +distribution_name: "{{ ansible_distribution|lower }}" +distribution_codename: "{{ ansible_distribution_release|lower }}" +distribution_major: "{{ ansible_distribution_major_version }}" + directories: - /data -backend_db: mongodb #[rethinkdb, mongodb] +backend_db: mongodb #[mongodb] +bigchaindb_config_path: /data/.bigchaindb bigchaindb_server_bind: "0.0.0.0:9984" -bigchaindb_database_host: "172.17.0.1" bigchaindb_log_file: "{{ ansible_env.HOME }}/bigchaindb.log" # Docker configuration -backend_db_image: "mongo:3.4.1" -backend_db_name: "mongodb" bigchaindb_image_name: "bigchaindb/bigchaindb" bigchaindb_docker_name: "bigchaindb" -bigchaindb_docker_published_ports: - - 59984:9984 -bigchaindb_docker_volumes: - - "{{ ansible_env.HOME }}/bigchaindb_docker:/data" +bigchaindb_default_port: 9984 +bigchandb_host_port: 59984 +bigchaindb_host_mount_dir: "{{ ansible_env.HOME }}/bigchaindb_docker" +bdb_docker_net_name: "bdb_network" diff --git a/pkg/ansible/roles/bigchaindb/tasks/centos.yml b/pkg/configuration/roles/bigchaindb/tasks/centos.yml similarity index 100% rename from pkg/ansible/roles/bigchaindb/tasks/centos.yml rename to pkg/configuration/roles/bigchaindb/tasks/centos.yml diff --git a/pkg/ansible/roles/bigchaindb/tasks/common.yml b/pkg/configuration/roles/bigchaindb/tasks/common.yml similarity index 53% rename from pkg/ansible/roles/bigchaindb/tasks/common.yml rename to pkg/configuration/roles/bigchaindb/tasks/common.yml index c88882be..d29cc3ef 100644 --- a/pkg/ansible/roles/bigchaindb/tasks/common.yml +++ b/pkg/configuration/roles/bigchaindb/tasks/common.yml @@ -13,10 +13,18 @@ shell: "pip3 install bigchaindb" tags: [bigchaindb] +- name: Check if BigchainDB node is already configured + stat: + path: "{{ bigchaindb_config_path }}" + register: stat_result + - name: Configure BigchainDB shell: "bigchaindb -y configure {{ backend_db }}" environment: BIGCHAINDB_SERVER_BIND: "{{ bigchaindb_server_bind }}" + BIGCHAINDB_CONFIG_PATH: "{{ bigchaindb_config_path }}" + BIGCHAINDB_DATABASE_HOST: "{{ ansible_hostname }}" + when: stat_result.stat.exists == False tags: [bigchaindb] - name: MongoDB Process Check @@ -30,7 +38,22 @@ tags: [bigchaindb] - name: Start BigchainDB - become: yes shell: "bigchaindb start > {{ bigchaindb_log_file }} 2>&1 &" + environment: + BIGCHAINDB_CONFIG_PATH: "{{ bigchaindb_config_path }}" when: mdb_pchk.stdout| int >= 1 and bdb_pchk.stdout| int == 0 - tags: [bigchaindb] \ No newline at end of file + async: 10 + poll: 0 + tags: [bigchaindb] + +- name: Get BigchainDB node public key + shell: "cat {{ bigchaindb_config_path }}" + register: bdb_node_config + tags: [bigchaindb] + +- name: Set Facts BigchainDB + set_fact: + pub_key="{{ ( bdb_node_config.stdout|from_json).keypair.public }}" + hostname="{{ ansible_hostname }}" + bdb_config="{{ bigchaindb_config_path }}" + tags: [bigchaindb] diff --git a/pkg/ansible/roles/bigchaindb/tasks/debian.yml b/pkg/configuration/roles/bigchaindb/tasks/debian.yml similarity index 100% rename from pkg/ansible/roles/bigchaindb/tasks/debian.yml rename to pkg/configuration/roles/bigchaindb/tasks/debian.yml diff --git a/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml b/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml new file mode 100644 index 00000000..82ca060e --- /dev/null +++ b/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml @@ -0,0 +1,51 @@ +--- +- name: Check if BigchainDB Dockers are already configured + stat: + path: "{{ bigchaindb_host_mount_dir }}{{ item|string }}/.bigchaindb" + with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + register: stat_result + +- name: Configuring BigchainDB Docker + docker_container: + name: "{{ bigchaindb_docker_name }}{{ item }}" + hostname: "{{ bigchaindb_docker_name }}{{ item }}" + image: "{{ bigchaindb_image_name }}" + volumes: + - "{{ bigchaindb_host_mount_dir }}{{ item|string }}:/data" + env: + BIGCHAINDB_SERVER_BIND: "{{ bigchaindb_server_bind }}" + BIGCHAINDB_DATABASE_HOST: "{{ hostvars[ansible_hostname]['mongodb' + item|string] }}" + entrypoint: "bigchaindb -y configure mongodb" + networks: + - name: "{{ bdb_docker_net_name }}" + when: stat_result.results[item|int].stat.exists == False + with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + tags: [bigchaindb] + +- name: Start BigchainDB Docker + docker_container: + name: "{{ bigchaindb_docker_name }}{{ item }}" + image: "{{ bigchaindb_image_name }}" + detach: true + published_ports: + - "{{ bigchandb_host_port|int + item|int }}:{{ bigchaindb_default_port }}" + restart_policy: always + volumes: + - "{{ bigchaindb_host_mount_dir }}{{ item|string }}:/data" + networks: + - name: "{{ bdb_docker_net_name }}" + state: started + with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + tags: [bigchaindb] + +- name: Get BigchainDB node public key + shell: "cat {{ bigchaindb_host_mount_dir + item|string }}/.bigchaindb" + register: bdb_node_config + with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + tags: [bigchaindb] + +- name: Set facts for BigchainDB containers + set_fact: + pub_key_{{ bigchaindb_docker_name }}{{ item }}="{{ (bdb_node_config.results[item|int].stdout|from_json).keypair.public }}" + with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + tags: [mongodb] \ No newline at end of file diff --git a/pkg/ansible/roles/bigchaindb/tasks/fedora.yml b/pkg/configuration/roles/bigchaindb/tasks/fedora.yml similarity index 100% rename from pkg/ansible/roles/bigchaindb/tasks/fedora.yml rename to pkg/configuration/roles/bigchaindb/tasks/fedora.yml diff --git a/pkg/configuration/roles/bigchaindb/tasks/main.yml b/pkg/configuration/roles/bigchaindb/tasks/main.yml new file mode 100644 index 00000000..207bee93 --- /dev/null +++ b/pkg/configuration/roles/bigchaindb/tasks/main.yml @@ -0,0 +1,20 @@ +--- +- import_tasks: deploy_docker.yml + when: deploy_docker|bool + tags: [bigchaindb] + +- import_tasks: debian.yml + when: not deploy_docker|bool and (distribution_name == "debian" or distribution_name == "ubuntu") + tags: [bigchaindb] + +- import_tasks: centos.yml + when: not deploy_docker|bool and (distribution_name == "centos" or distribution_name == "red hat enterprise linux") + tags: [bigchaindb] + +- import_tasks: fedora.yml + when: not deploy_docker|bool and (distribution_name == "fedora") + tags: [bigchaindb] + +- import_tasks: common.yml + when: not deploy_docker|bool + tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/ansible/roles/docker-compose/defaults/main.yml b/pkg/configuration/roles/docker-compose/defaults/main.yml similarity index 100% rename from pkg/ansible/roles/docker-compose/defaults/main.yml rename to pkg/configuration/roles/docker-compose/defaults/main.yml diff --git a/pkg/ansible/roles/docker-compose/tasks/main.yml b/pkg/configuration/roles/docker-compose/tasks/main.yml similarity index 100% rename from pkg/ansible/roles/docker-compose/tasks/main.yml rename to pkg/configuration/roles/docker-compose/tasks/main.yml diff --git a/pkg/ansible/roles/docker/defaults/main.yml b/pkg/configuration/roles/docker/defaults/main.yml similarity index 100% rename from pkg/ansible/roles/docker/defaults/main.yml rename to pkg/configuration/roles/docker/defaults/main.yml diff --git a/pkg/ansible/roles/docker/tasks/centos.yml b/pkg/configuration/roles/docker/tasks/centos.yml similarity index 100% rename from pkg/ansible/roles/docker/tasks/centos.yml rename to pkg/configuration/roles/docker/tasks/centos.yml diff --git a/pkg/ansible/roles/docker/tasks/debian.yml b/pkg/configuration/roles/docker/tasks/debian.yml similarity index 100% rename from pkg/ansible/roles/docker/tasks/debian.yml rename to pkg/configuration/roles/docker/tasks/debian.yml diff --git a/pkg/ansible/roles/docker/tasks/fedora.yml b/pkg/configuration/roles/docker/tasks/fedora.yml similarity index 100% rename from pkg/ansible/roles/docker/tasks/fedora.yml rename to pkg/configuration/roles/docker/tasks/fedora.yml diff --git a/pkg/ansible/roles/docker/tasks/main.yml b/pkg/configuration/roles/docker/tasks/main.yml similarity index 89% rename from pkg/ansible/roles/docker/tasks/main.yml rename to pkg/configuration/roles/docker/tasks/main.yml index 66d36489..5676e153 100644 --- a/pkg/ansible/roles/docker/tasks/main.yml +++ b/pkg/configuration/roles/docker/tasks/main.yml @@ -1,11 +1,11 @@ --- -- include: debian.yml +- import_tasks: debian.yml when: distribution_name == "debian" or distribution_name == "ubuntu" -- include: centos.yml +- import_tasks: centos.yml when: distribution_name == "centos" or distribution_name == "red hat enterprise linux" -- include: fedora.yml +- import_tasks: fedora.yml when: distribution_name == "fedora" - name: Create Docker group diff --git a/pkg/configuration/roles/key-exchange/defaults/main.yml b/pkg/configuration/roles/key-exchange/defaults/main.yml new file mode 100644 index 00000000..3bc2d64a --- /dev/null +++ b/pkg/configuration/roles/key-exchange/defaults/main.yml @@ -0,0 +1,13 @@ +keyring_script_host: /tmp/keyring.py +bigchaindb_log_file_host: "{{ ansible_env.HOME }}/bigchaindb.log" +bigchaindb_config_path_host: /data/.bigchaindb + +# Docker configuration +keyring_script_docker: "{{ ansible_env.HOME }}/config/keyring.py" +bigchaindb_config_path_docker: "{{ ansible_env.HOME }}/bigchaindb_docker" +bigchaindb_docker_name: bigchaindb +bigchaindb_default_port: 9984 +bigchandb_host_port: 59984 +bigchaindb_host_mount_dir: "{{ ansible_env.HOME }}/bigchaindb_docker" +bigchaindb_image_name: "bigchaindb/bigchaindb" +bdb_docker_net_name: "bdb_network" \ No newline at end of file diff --git a/pkg/configuration/roles/key-exchange/tasks/main.yml b/pkg/configuration/roles/key-exchange/tasks/main.yml new file mode 100644 index 00000000..031bf16b --- /dev/null +++ b/pkg/configuration/roles/key-exchange/tasks/main.yml @@ -0,0 +1,8 @@ +--- +- include_tasks: pub_key_exchange_host.yml + when: not deploy_docker|bool + tags: [bigchaindb] + +- include_tasks: pub_key_exchange_docker.yml + when: deploy_docker|bool + tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml b/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml new file mode 100644 index 00000000..87772617 --- /dev/null +++ b/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml @@ -0,0 +1,31 @@ +--- +- name: Creating files for key exchange + template: src=exchange_keyring_docker.j2 dest="{{ keyring_script_docker }}" + tags: [keyex] + +- name: Setting permissions + file: + path: "{{ keyring_script_docker }}" + mode: "0777" + tags: [keyex] + +- name: Update Keyring Configuration + shell: "python {{ keyring_script_docker }}" + tags: [keyex] + +- name: Restart BigchainDB Docker after keyring update + docker_container: + name: "{{ bigchaindb_docker_name }}{{ item }}" + image: "{{ bigchaindb_image_name }}" + detach: true + published_ports: + - "{{ bigchandb_host_port|int + item|int }}:{{ bigchaindb_default_port }}" + restart_policy: always + volumes: + - "{{ bigchaindb_host_mount_dir }}{{ item|string }}:/data" + state: started + restart: true + networks: + - name: "{{ bdb_docker_net_name }}" + with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_host.yml b/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_host.yml new file mode 100644 index 00000000..f3d5c4d6 --- /dev/null +++ b/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_host.yml @@ -0,0 +1,28 @@ +--- +- name: Creating files for key exchange + template: src=exchange_keyring_host.j2 dest="{{ keyring_script_host }}" + tags: [keyex] + +- name: Setting permissions + file: + path: "{{ keyring_script_host }}" + mode: "0777" + tags: [keyex] + +- name: Update Keyring Configuration + shell: "python {{ keyring_script_host }}" + tags: [keyex] + +- name: Stop BigchainDB + shell: pkill bigchaindb + register: bdb_stop + tags: [keyex] + +- name: Start BigchainDB + shell: "bigchaindb start > {{ bigchaindb_log_file_host }} 2>&1 &" + environment: + BIGCHAINDB_CONFIG_PATH: "{{ bigchaindb_config_path_host }}" + async: 10 + poll: 0 + when: bdb_stop|succeeded + tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/configuration/roles/key-exchange/templates/exchange_keyring_docker.j2 b/pkg/configuration/roles/key-exchange/templates/exchange_keyring_docker.j2 new file mode 100644 index 00000000..04c30716 --- /dev/null +++ b/pkg/configuration/roles/key-exchange/templates/exchange_keyring_docker.j2 @@ -0,0 +1,18 @@ +#!/usr/bin/python +import json +{% set keyring = {} %} +{% for docker in range(0, docker_replset_size|int, 1) %} + {{- keyring.update({'pub_key_' + bigchaindb_docker_name + docker|string: hostvars[ansible_hostname]['pub_key_' + bigchaindb_docker_name + docker|string]}) -}} +{%- endfor -%} +{% for docker in range(0, docker_replset_size|int, 1) %} +keyring = {{ keyring }} +keyring.pop('{{ 'pub_key_' + bigchaindb_docker_name + docker|string }}', None) +with open('{{ bigchaindb_config_path_docker + docker|string }}/.bigchaindb', 'r+') as f: + data = json.load(f) + del data['keyring'][:] + for key, value in keyring.iteritems(): + data['keyring'].append(value) + f.seek(0) + json.dump(data, f, indent=4) + f.truncate() +{% endfor %} \ No newline at end of file diff --git a/pkg/configuration/roles/key-exchange/templates/exchange_keyring_host.j2 b/pkg/configuration/roles/key-exchange/templates/exchange_keyring_host.j2 new file mode 100644 index 00000000..f02a208c --- /dev/null +++ b/pkg/configuration/roles/key-exchange/templates/exchange_keyring_host.j2 @@ -0,0 +1,21 @@ +{%- set keyring = [] -%} +{%- set bdb_config_path = {'path': ''} -%} +{%- for host in bdb_hosts -%} + {%- if host["name"] != ansible_hostname -%} + {{- keyring.append(hostvars[host["name"]]["pub_key"]) -}} + {%- else -%} + {%- if bdb_config_path.update({'path': hostvars[host["name"]]["bdb_config"]}) -%} + {%- endif -%} + {%- endif -%} +{%- endfor -%} +{%- if keyring|length != 0 -%} +#!/usr/bin/python +import json +with open('{{ bdb_config_path['path'] }}', 'r+') as f: + data = json.load(f) + del data['keyring'][:] + data['keyring'] = {{ keyring }} + f.seek(0) + json.dump(data, f, indent=4) + f.truncate() +{%- endif -%} \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/defaults/main.yml b/pkg/configuration/roles/mongodb/defaults/main.yml similarity index 70% rename from pkg/ansible/roles/mongodb/defaults/main.yml rename to pkg/configuration/roles/mongodb/defaults/main.yml index 950b4a18..1e4bfcf5 100644 --- a/pkg/ansible/roles/mongodb/defaults/main.yml +++ b/pkg/configuration/roles/mongodb/defaults/main.yml @@ -17,20 +17,27 @@ mongodb_dnf_base_url: "https://repo.mongodb.org/yum/{{ ansible_os_family|lower } mongodb_storage_path: /data/db/main mongodb_log_path: /var/log/mongodb mongodb_config_path: /data/configdb -se_linux: "TODO: (muawiakh)" directories: - "{{ mongodb_storage_path }}" - "{{ mongodb_log_path }}" - "{{ mongodb_config_path }}" +mongodb_conf_file: /etc/mongod.conf +mongodb_conf_files: [ + { src: "mongod.conf", dest: "{{ mongodb_conf_file }}"} +] +mongodb_port: 27017 +mongodb_admin_user: "adminUser" +mongodb_admin_password: "superstrongpassword" + +replica_set_name: bigchain-rs + +bdb_docker_net_name: "bdb_network" +bdb_docker_default_subnet: "172.18.0.0/16" +bdb_docker_default_gw: "172.18.0.1" + # Docker configuration -mongodb_default_port: 27017 -mongodb_docker_image: "mongo:3.4.4" +mongodb_docker_image: "mongo:3.4.9" mongodb_docker_name: "mongodb" -mongodb_docker_published_ports: - - 172.17.0.1:27017:27017 -mongodb_host_mount_dir_db: /tmp/mongodb_docker/db -mongodb_host_mount_dir_config: /tmp/mongodb_docker/configdb -mongodb_docker_volumes: - - "{{ mongodb_host_mount_dir_db }}:{{ mongodb_storage_path }}" - - "{{ mongodb_host_mount_dir_config }}:{{ mongodb_config_path }}" \ No newline at end of file +mongodb_host_mount_dir: "{{ ansible_env.HOME }}/mongodb_docker" +mongodb_host_config: "{{ ansible_env.HOME }}/config" \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/files/mongod.conf b/pkg/configuration/roles/mongodb/files/mongod.conf new file mode 100644 index 00000000..ed961801 --- /dev/null +++ b/pkg/configuration/roles/mongodb/files/mongod.conf @@ -0,0 +1,101 @@ +# mongod.conf + +# for documentation of all options, see: +# http://docs.mongodb.org/manual/reference/configuration-options/ + +# where to write logging data. +systemLog: + verbosity: 0 + # traceAllExceptions: true + timeStampFormat: iso8601-utc + component: + accessControl: + verbosity: 0 + command: + verbosity: 0 + control: + verbosity: 0 + ftdc: + verbosity: 0 + geo: + verbosity: 0 + index: + verbosity: 0 + network: + verbosity: 0 + query: + verbosity: 0 + replication: + verbosity: 0 + sharding: + verbosity: 0 + storage: + verbosity: 0 + journal: + verbosity: 0 + write: + verbosity: 0 + +processManagement: + fork: false + pidFilePath: /tmp/mongod.pid + +net: + port: 27017 + bindIp: 0.0.0.0 + maxIncomingConnections: 8192 + wireObjectCheck: false + unixDomainSocket: + enabled: false + pathPrefix: /tmp + filePermissions: 0700 + http: + enabled: false + compression: + compressors: snappy +# ssl: +# mode: requireSSL +# PEMKeyFile: MONGODB_KEY_FILE_PATH +# PEMKeyPassword: MONGODB_KEY_FILE_PASSWORD +# CAFile: MONGODB_CA_FILE_PATH +# CRLFile: MONGODB_CRL_FILE_PATH + +# allowConnectionsWithoutCertificates: false +# allowInvalidHostnames: false +# weakCertificateValidation: false +# allowInvalidCertificates: false + +#security: +# authorization: enabled +# clusterAuthMode: x509 + +#setParameter: +# enableLocalhostAuthBypass: true +# #notablescan: 1 +# logUserIds: 1 +# authenticationMechanisms: MONGODB-X509,SCRAM-SHA-1 + +storage: + dbPath: /data/db/main + indexBuildRetry: true + journal: + enabled: true + commitIntervalMs: 100 + directoryPerDB: true + engine: wiredTiger + wiredTiger: + engineConfig: + journalCompressor: snappy +# configString: cache_size=STORAGE_ENGINE_CACHE_SIZE + collectionConfig: + blockCompressor: snappy + indexConfig: + prefixCompression: true # TODO false may affect performance? + +operationProfiling: + mode: slowOp + slowOpThresholdMs: 100 + +replication: + replSetName: bigchain-rs + enableMajorityReadConcern: true diff --git a/pkg/ansible/roles/mongodb/tasks/centos.yml b/pkg/configuration/roles/mongodb/tasks/centos.yml similarity index 79% rename from pkg/ansible/roles/mongodb/tasks/centos.yml rename to pkg/configuration/roles/mongodb/tasks/centos.yml index e3340100..62e8faa0 100644 --- a/pkg/ansible/roles/mongodb/tasks/centos.yml +++ b/pkg/configuration/roles/mongodb/tasks/centos.yml @@ -15,4 +15,11 @@ name: "{{ mongodb_package }}" state: present update_cache: yes + tags: [mongodb] + +- name: Install pip | CentOS + yum: + name: python-pip + state: present + update_cache: yes tags: [mongodb] \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/tasks/common.yml b/pkg/configuration/roles/mongodb/tasks/common.yml new file mode 100644 index 00000000..40369191 --- /dev/null +++ b/pkg/configuration/roles/mongodb/tasks/common.yml @@ -0,0 +1,25 @@ +--- +- name: MongoDB config files are copied + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: "{{ mongodb_conf_files }}" + tags: [mongodb] + +- name: MongoDB Process Check + shell: pgrep mongod | wc -l + register: command_result + tags: [mongodb] + +- name: Install pymongo + pip: + name: pymongo + state: present + tags: [mongodb] + +- name: Run MongoDB + shell: "mongod --config {{ mongodb_conf_file }} 2>&1 &" + when: command_result.stdout| int != 1 + async: 5 + poll: 0 + tags: [mongodb] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/debian.yml b/pkg/configuration/roles/mongodb/tasks/debian.yml similarity index 81% rename from pkg/ansible/roles/mongodb/tasks/debian.yml rename to pkg/configuration/roles/mongodb/tasks/debian.yml index c2b0349b..aac606fa 100644 --- a/pkg/ansible/roles/mongodb/tasks/debian.yml +++ b/pkg/configuration/roles/mongodb/tasks/debian.yml @@ -3,8 +3,6 @@ apt_key: keyserver: "{{ apt_keyserver }}" id: "{{ apt_key_fingerprint }}" - state: present - ignore_errors: true tags: [mongodb] - name: Add MongoDB repo and update cache | Debian @@ -16,6 +14,9 @@ - name: Install MongoDB | Debian apt: - name: "{{ mongodb_package }}" + name: "{{ item }}" state: present + with_items: + - "{{ mongodb_package }}" + - python-pip tags: [mongodb] \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml b/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml new file mode 100644 index 00000000..52ec3fde --- /dev/null +++ b/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml @@ -0,0 +1,48 @@ +--- +- name: Check Docker Service + systemd: + name: docker + enabled: yes + state: started + tags: [mongodb] + +- name: Creating BDB Docker network + docker_network: + name: "{{ bdb_docker_net_name }}" + ipam_options: + subnet: "{{ bdb_docker_default_subnet }}" + driver_options: + com.docker.network.bridge.enable_icc": "true" + com.docker.network.bridge.enable_ip_masquerade": "true" + com.docker.network.bridge.host_binding_ipv4": "0.0.0.0" + com.docker.network.driver.mtu: "1500" + state: present + tags: [mongodb] + +- name: Running MongoDB Docker + docker_container: + name: "{{ mongodb_docker_name }}{{ item }}" + hostname: "{{ mongodb_docker_name }}{{ item }}" + image: "{{ mongodb_docker_image }}" + detach: true + published_ports: + - "{{ bdb_docker_default_gw }}:{{ (mongodb_port|int + item|int)|string }}:{{ mongodb_port }}" + restart_policy: always + volumes: + - "{{ mongodb_host_mount_dir }}{{ item|string }}/db:{{ mongodb_storage_path }}" + - "{{ mongodb_host_mount_dir }}{{ item|string }}/configdb:{{ mongodb_config_path }}" + - "{{ mongodb_host_config }}:/bdb_config" + state: started + keep_volumes: true + entrypoint: /entrypoint.sh --replSet=bigchain-rs + networks: + - name: "{{ bdb_docker_net_name }}" + register: mongo_container_info + with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + tags: [mongodb] + +- name: Set facts for MongoDB containers + set_fact: + mongodb{{ item }}={{ mongo_container_info.results[item|int].ansible_facts.docker_container.NetworkSettings.IPAddress }} + with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + tags: [mongodb] \ No newline at end of file diff --git a/pkg/ansible/roles/mongodb/tasks/fedora.yml b/pkg/configuration/roles/mongodb/tasks/fedora.yml similarity index 85% rename from pkg/ansible/roles/mongodb/tasks/fedora.yml rename to pkg/configuration/roles/mongodb/tasks/fedora.yml index fb83357f..c2f61110 100644 --- a/pkg/ansible/roles/mongodb/tasks/fedora.yml +++ b/pkg/configuration/roles/mongodb/tasks/fedora.yml @@ -12,6 +12,8 @@ - name: Install MongoDB | Fedora dnf: - name: "{{ mongodb_package }}" + name: "{{ item }}" state: present + with_items: + - "{{ mongodb_package }}" tags: [mongodb] \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/tasks/initiate_repl_set.yml b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set.yml new file mode 100644 index 00000000..2fed72d7 --- /dev/null +++ b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set.yml @@ -0,0 +1,6 @@ +--- +- import_tasks: initiate_repl_set_host.yml + when: (ansible_hostname == bdb_hosts[bdb_hosts|length-1]['name']) and not deploy_docker|bool + +- import_tasks: initiate_repl_set_docker.yml + when: deploy_docker|bool \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_docker.yml b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_docker.yml new file mode 100644 index 00000000..af5b89ca --- /dev/null +++ b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_docker.yml @@ -0,0 +1,13 @@ +--- +- name: Creating files to initialize MongoDB Replica Set | Docker + template: src=replSet_init_docker.j2 dest="{{ mongodb_host_config }}/replSet_init.js" + tags: [mongodb] + +- name: Initializing Replica Set and Adding AdminUser | Docker + run_once: true + shell: + cmd: + "docker exec {{ mongodb_docker_name }}{{ docker_replset_size|int - 1 }} bash -l -c + '/usr/bin/mongo --host {{ mongodb_docker_name }}{{ docker_replset_size|int - 1 }} + --port {{ mongodb_port }} < /bdb_config/replSet_init.js'" + tags: [mongodb] \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_host.yml b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_host.yml new file mode 100644 index 00000000..8d398bcb --- /dev/null +++ b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_host.yml @@ -0,0 +1,20 @@ +--- +- name: Creating files to initialize MongoDB Replica Set + template: src=replSet_init_host.j2 dest=/tmp/replSet_init.js + tags: [mongodb] + +- name: Initializing Replica Set + shell: "/usr/bin/mongo --host {{ ansible_hostname }} --port {{ mongodb_port }} < /tmp/replSet_init.js" + tags: [mongodb] + +- name: Adding AdminUser to MongoDB + run_once: true + mongodb_user: + database: admin + login_host: "{{ ansible_hostname }}" + login_port: "{{ mongodb_port }}" + name: "{{ mongodb_admin_user }}" + password: "{{ mongodb_admin_password }}" + roles: readWriteAnyDatabase,clusterManager + state: present + tags: [mongodb] \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/tasks/main.yml b/pkg/configuration/roles/mongodb/tasks/main.yml new file mode 100644 index 00000000..6576d4c2 --- /dev/null +++ b/pkg/configuration/roles/mongodb/tasks/main.yml @@ -0,0 +1,31 @@ +--- +- name: Creating directories + file: + path: "{{ item }}" + state: directory + mode: 0700 + with_items: "{{ directories }}" + when: not deploy_docker|bool + tags: [mongodb] + +- import_tasks: deploy_docker.yml + when: deploy_docker|bool + tags: [mongodb] + +- import_tasks: debian.yml + when: not deploy_docker|bool and (distribution_name == "debian" or distribution_name == "ubuntu") + tags: [mongodb] + +- import_tasks: centos.yml + when: not deploy_docker|bool and (distribution_name == "centos" or distribution_name == "red hat enterprise linux") + tags: [mongodb] + +- import_tasks: fedora.yml + when: not deploy_docker|bool and (distribution_name == "fedora") + tags: [mongodb] + +- import_tasks: common.yml + when: not deploy_docker|bool + tags: [mongodb] + +- import_tasks: initiate_repl_set.yml \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 b/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 new file mode 100644 index 00000000..a0121b19 --- /dev/null +++ b/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 @@ -0,0 +1,30 @@ +rs.initiate({ + "_id": "{{ replica_set_name }}", + "members": [ + { + "_id": 0, + "host": "{{ mongodb_docker_name }}{{ docker_replset_size|int - 1 }}:{{ mongodb_port }}" + } + ] +}); +sleep(5000); +{% for docker in range(0, docker_replset_size|int, 1) %} +{%- if docker != (docker_replset_size|int - 1) -%} +rs.add("{{ mongodb_docker_name }}{{ docker }}:{{ mongodb_port }}"); +{% endif %} +{%- endfor -%} +use admin; +db.createUser(db.createUser({ + "user": "{{ mongodb_admin_user }}", + "pwd": "{{ mongodb_admin_password }}", + "roles": [ + { + "role": "userAdminAnyDatabase", + "db": "admin" + }, + { + "role": "clusterManager", + "db": "admin" + } + ] +}); \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/templates/replSet_init_host.j2 b/pkg/configuration/roles/mongodb/templates/replSet_init_host.j2 new file mode 100644 index 00000000..42bca2a3 --- /dev/null +++ b/pkg/configuration/roles/mongodb/templates/replSet_init_host.j2 @@ -0,0 +1,7 @@ +rs.initiate( { _id : "{{ replica_set_name }}", members: [ { _id : 0, host :"{{ bdb_hosts[bdb_hosts|length-1]['name'] }}:{{ mongodb_port }}" } ] } ) +sleep(5000); +{% for host in bdb_hosts %} +{%- if ansible_hostname != host["name"] -%} +rs.add("{{ host["name"] }}:{{ mongodb_port }}"); +{% endif %} +{%- endfor -%} \ No newline at end of file diff --git a/pkg/configuration/vars/bdb-config.yml b/pkg/configuration/vars/bdb-config.yml new file mode 100644 index 00000000..952738b2 --- /dev/null +++ b/pkg/configuration/vars/bdb-config.yml @@ -0,0 +1,13 @@ +--- +deploy_docker: false #[true, false] +docker_replset_size: 1 +upstart: "/bigchaindb/scripts/bootstrap.sh" +bdb_hosts: + - name: "config-node" + box: + name: "ubuntu/xenial64" + ram: "2048" + vcpus: "2" + network: + ip: "10.20.30.40" + type: "private_network" \ No newline at end of file diff --git a/pkg/scripts/bootstrap_helper.sh b/pkg/scripts/bootstrap_helper.sh index 2c8abd32..8afb4d7e 100755 --- a/pkg/scripts/bootstrap_helper.sh +++ b/pkg/scripts/bootstrap_helper.sh @@ -28,7 +28,7 @@ validate_os_version_and_deps(){ fi ;; fedora) - dnf install bc -y > /dev/null 2>&1 + dnf install bc python2-dnf libselinux-python -y > /dev/null 2>&1 if [[ ($(echo $3 | bc) > $MINIMUM_FEDORA_VERSION) || ($(echo $3 | bc) == $MINIMUM_FEDORA_VERSION) ]]; then rpm -q "${OS_DEPENDENCIES[@]}" > /dev/null 2>&1 @@ -71,20 +71,22 @@ install_dependencies() { # multiple dependencies) install_deps_deb() { echo "Installing Dependencies..." + apt-get update -y apt-get install -y software-properties-common apt-add-repository ppa:ansible/ansible - apt-get update - apt-get install -y --force-yes ansible + apt-get update -y + apt-get install -y "${OS_DEPENDENCIES[@]}" } install_deps_centos() { echo "Installing Dependencies..." yum install epel-release -y yum install -y https://centos7.iuscommunity.org/ius-release.rpm - yum install ansible -y + yum install "${OS_DEPENDENCIES[@]}" -y } install_deps_fedora() { echo "Installing Dependencies..." export LC_ALL=C dnf makecache - dnf -y install ansible python2-dnf -} \ No newline at end of file + echo "${OS_DEPENDENCIES[@]}" + dnf -y install "${OS_DEPENDENCIES[@]}" +} From 0f68c41b890dd62973cc347b42d2476a1ece2fd5 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Fri, 27 Oct 2017 17:54:19 +0200 Subject: [PATCH 108/120] Addressing comments and updating some documentation --- .../source/appendices/run-with-ansible.md | 19 +++++++++------ .../source/appendices/run-with-vagrant.md | 17 ++++++++----- pkg/Vagrantfile | 15 ++++++------ pkg/configuration/bdb-deploy.yml | 2 +- pkg/configuration/host_vars/bdb-node-01 | 2 +- pkg/configuration/hosts/all | 4 ++-- .../roles/bigchaindb/tasks/deploy_docker.yml | 10 ++++---- .../tasks/pub_key_exchange_docker.yml | 2 +- .../templates/exchange_keyring_docker.j2 | 4 ++-- .../roles/mongodb/tasks/deploy_docker.yml | 4 ++-- .../tasks/initiate_repl_set_docker.yml | 4 ++-- .../mongodb/templates/replSet_init_docker.j2 | 6 ++--- pkg/configuration/vars/bdb-config.yml | 24 +++++++++++++++---- 13 files changed, 70 insertions(+), 43 deletions(-) diff --git a/docs/server/source/appendices/run-with-ansible.md b/docs/server/source/appendices/run-with-ansible.md index b3bcdfba..9917841b 100644 --- a/docs/server/source/appendices/run-with-ansible.md +++ b/docs/server/source/appendices/run-with-ansible.md @@ -12,6 +12,10 @@ Currently, this workflow is only supported for the following distributions: - CentOS >= 7 - Fedora >= 24 +## Minimum Requirements +Minimum resource requirements for a single node BigchainDB dev setup. **The more the better**: +- Memory >= 512MB +- VCPUs >= 1 ## Clone the BigchainDB repository | Ansible ```text $ git clone https://github.com/bigchaindb/bigchaindb.git @@ -49,7 +53,8 @@ $ cd bigchaindb/pkg/configuration/hosts Edit `all` configuration file: ```text # Delete any existing configuration in this file and insert -localhost ansible_connection=local +# Hostname of dev machine + ansible_connection=local ``` ##### Update Configuration | Local Navigate to `bigchaindb/pkg/configuration/vars` inside the BigchainDB repository. @@ -61,16 +66,16 @@ Edit `bdb-config.yml` configuration file as per your requirements, sample config ```text --- deploy_docker: false #[true, false] -docker_replset_size: 1 # Only needed if `deploy_docker` is true +docker_cluster_size: 1 # Only needed if `deploy_docker` is true bdb_hosts: - - name: "" + - name: "HOSTNAME>" # Hostname of dev machine ``` **Note**: You can also orchestrate a multi-node BigchainDB cluster on a local dev host using Docker containers. Here is a sample `bdb-config.yml` ```text --- deploy_docker: true #[true, false] -docker_replset_size: 3 +docker_cluster_size: 3 bdb_hosts: - name: "" ``` @@ -109,7 +114,7 @@ Edit `bdb-config.yml` configuration file as per your requirements, sample config ```text --- deploy_docker: false #[true, false] -docker_replset_size: 1 # Only needed if `deploy_docker` is true +docker_cluster_size: 1 # Only needed if `deploy_docker` is true bdb_hosts: - name: "" ``` @@ -120,7 +125,7 @@ Now, You can safely run the `bdb-deploy.yml` playbook and everything will be tak ```text $ cd bigchaindb/pkg/configuration/ -$ sudo ansible-playbook bdb-deploy.yml -i /bigchaindb/configuration/hosts/all +$ sudo ansible-playbook bdb-deploy.yml -i hosts/all ``` After successfull execution of the playbook, you can verify that BigchainDB docker(s)/process(es) is(are) running. @@ -137,7 +142,7 @@ Verify BigchainDB Docker(s): $ docker ps | grep bigchaindb ``` -The playbook also installs the BigchainDB Python Driver, +The playbook also installs the BigchainDB Python Driver, so you can use it to make transactions and verify the functionality of your BigchainDB node. See the [BigchainDB Python Driver documentation](https://docs.bigchaindb.com/projects/py-driver/en/latest/index.html) diff --git a/docs/server/source/appendices/run-with-vagrant.md b/docs/server/source/appendices/run-with-vagrant.md index e70dd715..4c61ad9c 100644 --- a/docs/server/source/appendices/run-with-vagrant.md +++ b/docs/server/source/appendices/run-with-vagrant.md @@ -29,6 +29,11 @@ can also tweak the following configurations for the BigchainDB node(s). - Virtualbox - VMware +## Minimum Requirements +Minimum resource requirements for a single node BigchainDB dev setup. **The more the better**: +- Memory >= 512MB +- VCPUs >= 1 + ## Install dependencies | Vagrant 1. [VirtualBox](https://www.virtualbox.org/wiki/Downloads) >= 5.0.0 2. [Vagrant](https://www.vagrantup.com/downloads.html) >= 1.16.0 @@ -39,9 +44,9 @@ $ git clone https://github.com/bigchaindb/bigchaindb.git ``` ## Configuration | Vagrant -Navigate to `bigchaindb/pkg/config/` inside the BigchainDB repository. +Navigate to `bigchaindb/pkg/configuration/vars/` inside the BigchainDB repository. ```text -$ cd bigchaindb/pkg/config/ +$ cd bigchaindb/pkg/configuration/vars/ ``` Edit `bdb-config.yml` as per your requirements. Sample `bdb-config.yml`: @@ -49,7 +54,7 @@ Edit `bdb-config.yml` as per your requirements. Sample `bdb-config.yml`: ```text --- deploy_docker: false #[true, false] -docker_replset_size: 1 +docker_cluster_size: 1 upstart: "/bigchaindb/scripts/bootstrap.sh" bdb_hosts: - name: "bdb-node-01" @@ -67,7 +72,7 @@ Here is a sample `bdb-config.yml`: ```text --- deploy_docker: false #[true, false] -docker_replset_size: 1 +docker_cluster_size: 1 upstart: "/bigchaindb/scripts/bootstrap.sh" bdb_hosts: - name: "bdb-node-01" @@ -92,7 +97,7 @@ Here is a sample `bdb-config.yml` ```text --- deploy_docker: true #[true, false] -docker_replset_size: 3 +docker_cluster_size: 3 upstart: "/bigchaindb/scripts/bootstrap.sh" bdb_hosts: - name: "bdb-node-01" @@ -115,7 +120,7 @@ $ vagrant up ``` **Note**: There are some vagrant plugins required for the installation, -user will be prompted to install them if they are not present. Instructions +user will be prompted to install them if they are not present. Instructions to install the plugins can be extracted from the message. ```text diff --git a/pkg/Vagrantfile b/pkg/Vagrantfile index 8bfebe94..4031df07 100644 --- a/pkg/Vagrantfile +++ b/pkg/Vagrantfile @@ -31,11 +31,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # using -u ubuntu as remote user, conventionally vagrant boxes use `vagrant` user if instance["box"]["name"] == "ubuntu/xenial64" hosts_config.puts("#{instance["name"]} ansible_user=ubuntu") - if Vagrant.has_plugin?("vagrant-vbguest") - config.vbguest.auto_update = false - config.vbguest.no_install = true - config.vbguest.no_remote = true - end else hosts_config.puts("#{instance["name"]} ansible_user=vagrant") end @@ -43,7 +38,13 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # Workaround until vagrant cachier plugin supports dnf if !(instance["box"]["name"].include? "fedora") if Vagrant.has_plugin?("vagrant-cachier") - config.cache.scope = :box + bdb.cache.scope = :box + end + elsif instance["box"]["name"] == "ubuntu/xenial64" + if Vagrant.has_plugin?("vagrant-vbguest") + bdb.vbguest.auto_update = false + bdb.vbguest.no_install = true + bdb.vbguest.no_remote = true end end bdb.vm.hostname = instance["name"] @@ -80,7 +81,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| bdb.vm.network "private_network", ip: "192.168.100.200" bdb.vm.provision :shell, inline: "cd /bigchaindb/scripts;/bin/bash #{instances_config["upstart"]}" bdb.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /bigchaindb/configuration/bdb-deploy.yml \ - -c /bigchaindb/configuration/hosts/all" + -i /bigchaindb/configuration/hosts/all" bdb.vm.provider "virtualbox" do |vb| vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] vb.memory = 2048 diff --git a/pkg/configuration/bdb-deploy.yml b/pkg/configuration/bdb-deploy.yml index 9bd93d98..5c4b5786 100644 --- a/pkg/configuration/bdb-deploy.yml +++ b/pkg/configuration/bdb-deploy.yml @@ -9,4 +9,4 @@ - bigchaindb-driver - import_playbook: multi_node.yml - when: (bdb_hosts|length > 1) or docker_replset_size|int > 1 \ No newline at end of file + when: (bdb_hosts|length > 1) or docker_cluster_size|int > 1 \ No newline at end of file diff --git a/pkg/configuration/host_vars/bdb-node-01 b/pkg/configuration/host_vars/bdb-node-01 index e20d655a..fef41e4a 100644 --- a/pkg/configuration/host_vars/bdb-node-01 +++ b/pkg/configuration/host_vars/bdb-node-01 @@ -2,4 +2,4 @@ # populates this dynamically. # Only needed for logging into remote hosts and adding host specific variables e.g. -#ansible_ssh_private_key_file: "/path/to/private/key" \ No newline at end of file +#ansible_ssh_private_key_file: "/path/to/private/key" diff --git a/pkg/configuration/hosts/all b/pkg/configuration/hosts/all index 1f7800f2..f84cc374 100644 --- a/pkg/configuration/hosts/all +++ b/pkg/configuration/hosts/all @@ -2,7 +2,7 @@ # populates this dynamically. # For local host -#localhost ansible_connection=local +# ansible_connection=local # For remote host(s) -# ansible_ssh_user= ansible_sudo_pass= \ No newline at end of file +# ansible_ssh_user= ansible_sudo_pass= diff --git a/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml b/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml index 82ca060e..e8ebbb63 100644 --- a/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml +++ b/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml @@ -2,7 +2,7 @@ - name: Check if BigchainDB Dockers are already configured stat: path: "{{ bigchaindb_host_mount_dir }}{{ item|string }}/.bigchaindb" - with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 register: stat_result - name: Configuring BigchainDB Docker @@ -19,7 +19,7 @@ networks: - name: "{{ bdb_docker_net_name }}" when: stat_result.results[item|int].stat.exists == False - with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [bigchaindb] - name: Start BigchainDB Docker @@ -35,17 +35,17 @@ networks: - name: "{{ bdb_docker_net_name }}" state: started - with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [bigchaindb] - name: Get BigchainDB node public key shell: "cat {{ bigchaindb_host_mount_dir + item|string }}/.bigchaindb" register: bdb_node_config - with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [bigchaindb] - name: Set facts for BigchainDB containers set_fact: pub_key_{{ bigchaindb_docker_name }}{{ item }}="{{ (bdb_node_config.results[item|int].stdout|from_json).keypair.public }}" - with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [mongodb] \ No newline at end of file diff --git a/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml b/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml index 87772617..bd5be749 100644 --- a/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml +++ b/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml @@ -27,5 +27,5 @@ restart: true networks: - name: "{{ bdb_docker_net_name }}" - with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [bigchaindb] \ No newline at end of file diff --git a/pkg/configuration/roles/key-exchange/templates/exchange_keyring_docker.j2 b/pkg/configuration/roles/key-exchange/templates/exchange_keyring_docker.j2 index 04c30716..31aed4fb 100644 --- a/pkg/configuration/roles/key-exchange/templates/exchange_keyring_docker.j2 +++ b/pkg/configuration/roles/key-exchange/templates/exchange_keyring_docker.j2 @@ -1,10 +1,10 @@ #!/usr/bin/python import json {% set keyring = {} %} -{% for docker in range(0, docker_replset_size|int, 1) %} +{% for docker in range(0, docker_cluster_size|int, 1) %} {{- keyring.update({'pub_key_' + bigchaindb_docker_name + docker|string: hostvars[ansible_hostname]['pub_key_' + bigchaindb_docker_name + docker|string]}) -}} {%- endfor -%} -{% for docker in range(0, docker_replset_size|int, 1) %} +{% for docker in range(0, docker_cluster_size|int, 1) %} keyring = {{ keyring }} keyring.pop('{{ 'pub_key_' + bigchaindb_docker_name + docker|string }}', None) with open('{{ bigchaindb_config_path_docker + docker|string }}/.bigchaindb', 'r+') as f: diff --git a/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml b/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml index 52ec3fde..295f2105 100644 --- a/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml +++ b/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml @@ -38,11 +38,11 @@ networks: - name: "{{ bdb_docker_net_name }}" register: mongo_container_info - with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [mongodb] - name: Set facts for MongoDB containers set_fact: mongodb{{ item }}={{ mongo_container_info.results[item|int].ansible_facts.docker_container.NetworkSettings.IPAddress }} - with_sequence: start=0 end="{{ docker_replset_size|int - 1 }}" stride=1 + with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [mongodb] \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_docker.yml b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_docker.yml index af5b89ca..5cd341fa 100644 --- a/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_docker.yml +++ b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set_docker.yml @@ -7,7 +7,7 @@ run_once: true shell: cmd: - "docker exec {{ mongodb_docker_name }}{{ docker_replset_size|int - 1 }} bash -l -c - '/usr/bin/mongo --host {{ mongodb_docker_name }}{{ docker_replset_size|int - 1 }} + "docker exec {{ mongodb_docker_name }}{{ docker_cluster_size|int - 1 }} bash -l -c + '/usr/bin/mongo --host {{ mongodb_docker_name }}{{ docker_cluster_size|int - 1 }} --port {{ mongodb_port }} < /bdb_config/replSet_init.js'" tags: [mongodb] \ No newline at end of file diff --git a/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 b/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 index a0121b19..e1764993 100644 --- a/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 +++ b/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 @@ -3,13 +3,13 @@ rs.initiate({ "members": [ { "_id": 0, - "host": "{{ mongodb_docker_name }}{{ docker_replset_size|int - 1 }}:{{ mongodb_port }}" + "host": "{{ mongodb_docker_name }}{{ docker_cluster_size|int - 1 }}:{{ mongodb_port }}" } ] }); sleep(5000); -{% for docker in range(0, docker_replset_size|int, 1) %} -{%- if docker != (docker_replset_size|int - 1) -%} +{% for docker in range(0, docker_cluster_size|int, 1) %} +{%- if docker != (docker_cluster_size|int - 1) -%} rs.add("{{ mongodb_docker_name }}{{ docker }}:{{ mongodb_port }}"); {% endif %} {%- endfor -%} diff --git a/pkg/configuration/vars/bdb-config.yml b/pkg/configuration/vars/bdb-config.yml index 952738b2..6dc79b30 100644 --- a/pkg/configuration/vars/bdb-config.yml +++ b/pkg/configuration/vars/bdb-config.yml @@ -1,13 +1,29 @@ --- deploy_docker: false #[true, false] -docker_replset_size: 1 +docker_cluster_size: 1 upstart: "/bigchaindb/scripts/bootstrap.sh" bdb_hosts: - - name: "config-node" + - name: "bdb-node-01" box: name: "ubuntu/xenial64" ram: "2048" - vcpus: "2" + vcpus: "1" + network: + ip: "10.20.30.20" + type: "private_network" + - name: "bdb-node-02" + box: + name: "centos/7" + ram: "2048" + vcpus: "1" + network: + ip: "10.20.30.30" + type: "private_network" + - name: "bdb-node-03" + box: + name: "bento/fedora-24" + ram: "2048" + vcpus: "1" network: ip: "10.20.30.40" - type: "private_network" \ No newline at end of file + type: "private_network" From 20147562f6ec6bb9925f79b4139060b36f20dd97 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Fri, 27 Oct 2017 20:25:19 +0200 Subject: [PATCH 109/120] Fix docs build issue --- docs/server/source/appendices/run-with-ansible.md | 2 +- docs/server/source/appendices/run-with-vagrant.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/server/source/appendices/run-with-ansible.md b/docs/server/source/appendices/run-with-ansible.md index 9917841b..43b6559b 100644 --- a/docs/server/source/appendices/run-with-ansible.md +++ b/docs/server/source/appendices/run-with-ansible.md @@ -12,7 +12,7 @@ Currently, this workflow is only supported for the following distributions: - CentOS >= 7 - Fedora >= 24 -## Minimum Requirements +## Minimum Requirements | Ansible Minimum resource requirements for a single node BigchainDB dev setup. **The more the better**: - Memory >= 512MB - VCPUs >= 1 diff --git a/docs/server/source/appendices/run-with-vagrant.md b/docs/server/source/appendices/run-with-vagrant.md index 4c61ad9c..aab7f39f 100644 --- a/docs/server/source/appendices/run-with-vagrant.md +++ b/docs/server/source/appendices/run-with-vagrant.md @@ -29,7 +29,7 @@ can also tweak the following configurations for the BigchainDB node(s). - Virtualbox - VMware -## Minimum Requirements +## Minimum Requirements | Vagrant Minimum resource requirements for a single node BigchainDB dev setup. **The more the better**: - Memory >= 512MB - VCPUs >= 1 From b2b644db3d1c9280e2b594ea8418cd7a405e41c4 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Fri, 27 Oct 2017 20:29:13 +0200 Subject: [PATCH 110/120] Fix minor docs comments --- docs/server/source/appendices/run-with-ansible.md | 2 +- docs/server/source/appendices/run-with-vagrant.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/server/source/appendices/run-with-ansible.md b/docs/server/source/appendices/run-with-ansible.md index 43b6559b..fdadb28e 100644 --- a/docs/server/source/appendices/run-with-ansible.md +++ b/docs/server/source/appendices/run-with-ansible.md @@ -68,7 +68,7 @@ Edit `bdb-config.yml` configuration file as per your requirements, sample config deploy_docker: false #[true, false] docker_cluster_size: 1 # Only needed if `deploy_docker` is true bdb_hosts: - - name: "HOSTNAME>" # Hostname of dev machine + - name: "" # Hostname of dev machine ``` **Note**: You can also orchestrate a multi-node BigchainDB cluster on a local dev host using Docker containers. Here is a sample `bdb-config.yml` diff --git a/docs/server/source/appendices/run-with-vagrant.md b/docs/server/source/appendices/run-with-vagrant.md index aab7f39f..8f56328f 100644 --- a/docs/server/source/appendices/run-with-vagrant.md +++ b/docs/server/source/appendices/run-with-vagrant.md @@ -21,9 +21,9 @@ can also tweak the following configurations for the BigchainDB node(s). - IP Address - Deploy node with Docker - Deploy all the services in Docker containers or as processes. -- Size of Replica Set(Number of cluster member) +- Number of BigchainDB nodes - If you want to deploy the services inside Docker containers, you - can specify number of member(s) in the MongoDB/BigchainDB cluster. + can specify number of member(s) in the BigchainDB cluster. - Upstart Script - Vagrant Provider - Virtualbox From b96a754f9a75858ca451ff8e10c4deced0269546 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Sat, 28 Oct 2017 01:02:18 +0200 Subject: [PATCH 111/120] Update bdb-config --- pkg/configuration/vars/bdb-config.yml | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/pkg/configuration/vars/bdb-config.yml b/pkg/configuration/vars/bdb-config.yml index 6dc79b30..f34cd7c7 100644 --- a/pkg/configuration/vars/bdb-config.yml +++ b/pkg/configuration/vars/bdb-config.yml @@ -7,23 +7,7 @@ bdb_hosts: box: name: "ubuntu/xenial64" ram: "2048" - vcpus: "1" + vcpus: "2" network: ip: "10.20.30.20" type: "private_network" - - name: "bdb-node-02" - box: - name: "centos/7" - ram: "2048" - vcpus: "1" - network: - ip: "10.20.30.30" - type: "private_network" - - name: "bdb-node-03" - box: - name: "bento/fedora-24" - ram: "2048" - vcpus: "1" - network: - ip: "10.20.30.40" - type: "private_network" From 0ee0d88da1ac6e493fe13297358eb673d04cac9f Mon Sep 17 00:00:00 2001 From: muawiakh Date: Sat, 28 Oct 2017 01:33:32 +0200 Subject: [PATCH 112/120] Fix flake8 failure --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 9620d0f9..a329c595 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -156,4 +156,4 @@ def test_lazy_execution(): lz = Lazy() lz.name.upper() result = lz.run(cat) - assert result == 'SHMUI' + assert result == 'SHMUI' \ No newline at end of file From c285487dfb71f61eb02e6564368c120cb3e62933 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Sat, 28 Oct 2017 01:41:42 +0200 Subject: [PATCH 113/120] Revert "Fix flake8 failure" This reverts commit 5c6e7419a7fa827f1291be3ecbeda895e3a46b58. --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index a329c595..9620d0f9 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -156,4 +156,4 @@ def test_lazy_execution(): lz = Lazy() lz.name.upper() result = lz.run(cat) - assert result == 'SHMUI' \ No newline at end of file + assert result == 'SHMUI' From 2df08430cde169569e344f8bbf1571f77f0125b5 Mon Sep 17 00:00:00 2001 From: muawiakh Date: Mon, 13 Nov 2017 14:31:42 +0100 Subject: [PATCH 114/120] Remove docker network creation and use default docker bridge --- pkg/configuration/bdb-deploy.yml | 2 +- .../roles/bigchaindb/defaults/main.yml | 3 ++- .../roles/bigchaindb/tasks/deploy_docker.yml | 7 ++----- .../roles/bigchaindb/tasks/main.yml | 2 +- .../roles/key-exchange/defaults/main.yml | 1 - .../tasks/pub_key_exchange_docker.yml | 4 +--- .../roles/mongodb/defaults/main.yml | 6 +----- .../roles/mongodb/tasks/deploy_docker.yml | 19 ++----------------- .../roles/mongodb/tasks/initiate_repl_set.yml | 2 +- .../roles/mongodb/tasks/main.yml | 2 +- .../mongodb/templates/replSet_init_docker.j2 | 6 +++--- 11 files changed, 15 insertions(+), 39 deletions(-) diff --git a/pkg/configuration/bdb-deploy.yml b/pkg/configuration/bdb-deploy.yml index 5c4b5786..8dd8c7ea 100644 --- a/pkg/configuration/bdb-deploy.yml +++ b/pkg/configuration/bdb-deploy.yml @@ -9,4 +9,4 @@ - bigchaindb-driver - import_playbook: multi_node.yml - when: (bdb_hosts|length > 1) or docker_cluster_size|int > 1 \ No newline at end of file + when: (bdb_hosts|length > 1) or docker_cluster_size|int > 1 diff --git a/pkg/configuration/roles/bigchaindb/defaults/main.yml b/pkg/configuration/roles/bigchaindb/defaults/main.yml index 746cc8e6..594deb20 100644 --- a/pkg/configuration/roles/bigchaindb/defaults/main.yml +++ b/pkg/configuration/roles/bigchaindb/defaults/main.yml @@ -47,4 +47,5 @@ bigchaindb_docker_name: "bigchaindb" bigchaindb_default_port: 9984 bigchandb_host_port: 59984 bigchaindb_host_mount_dir: "{{ ansible_env.HOME }}/bigchaindb_docker" -bdb_docker_net_name: "bdb_network" +# Default IP of docker0 bridge +bigchaindb_default_host: "172.17.0.1" diff --git a/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml b/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml index e8ebbb63..98fd90d5 100644 --- a/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml +++ b/pkg/configuration/roles/bigchaindb/tasks/deploy_docker.yml @@ -4,6 +4,7 @@ path: "{{ bigchaindb_host_mount_dir }}{{ item|string }}/.bigchaindb" with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 register: stat_result + tags: [bigchaindb] - name: Configuring BigchainDB Docker docker_container: @@ -16,8 +17,6 @@ BIGCHAINDB_SERVER_BIND: "{{ bigchaindb_server_bind }}" BIGCHAINDB_DATABASE_HOST: "{{ hostvars[ansible_hostname]['mongodb' + item|string] }}" entrypoint: "bigchaindb -y configure mongodb" - networks: - - name: "{{ bdb_docker_net_name }}" when: stat_result.results[item|int].stat.exists == False with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [bigchaindb] @@ -32,8 +31,6 @@ restart_policy: always volumes: - "{{ bigchaindb_host_mount_dir }}{{ item|string }}:/data" - networks: - - name: "{{ bdb_docker_net_name }}" state: started with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [bigchaindb] @@ -48,4 +45,4 @@ set_fact: pub_key_{{ bigchaindb_docker_name }}{{ item }}="{{ (bdb_node_config.results[item|int].stdout|from_json).keypair.public }}" with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 - tags: [mongodb] \ No newline at end of file + tags: [bigchaindb] diff --git a/pkg/configuration/roles/bigchaindb/tasks/main.yml b/pkg/configuration/roles/bigchaindb/tasks/main.yml index 207bee93..3b1de267 100644 --- a/pkg/configuration/roles/bigchaindb/tasks/main.yml +++ b/pkg/configuration/roles/bigchaindb/tasks/main.yml @@ -17,4 +17,4 @@ - import_tasks: common.yml when: not deploy_docker|bool - tags: [bigchaindb] \ No newline at end of file + tags: [bigchaindb] diff --git a/pkg/configuration/roles/key-exchange/defaults/main.yml b/pkg/configuration/roles/key-exchange/defaults/main.yml index 3bc2d64a..6bfe9035 100644 --- a/pkg/configuration/roles/key-exchange/defaults/main.yml +++ b/pkg/configuration/roles/key-exchange/defaults/main.yml @@ -10,4 +10,3 @@ bigchaindb_default_port: 9984 bigchandb_host_port: 59984 bigchaindb_host_mount_dir: "{{ ansible_env.HOME }}/bigchaindb_docker" bigchaindb_image_name: "bigchaindb/bigchaindb" -bdb_docker_net_name: "bdb_network" \ No newline at end of file diff --git a/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml b/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml index bd5be749..eaf0eb14 100644 --- a/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml +++ b/pkg/configuration/roles/key-exchange/tasks/pub_key_exchange_docker.yml @@ -25,7 +25,5 @@ - "{{ bigchaindb_host_mount_dir }}{{ item|string }}:/data" state: started restart: true - networks: - - name: "{{ bdb_docker_net_name }}" with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 - tags: [bigchaindb] \ No newline at end of file + tags: [keyex] diff --git a/pkg/configuration/roles/mongodb/defaults/main.yml b/pkg/configuration/roles/mongodb/defaults/main.yml index 1e4bfcf5..7088a61b 100644 --- a/pkg/configuration/roles/mongodb/defaults/main.yml +++ b/pkg/configuration/roles/mongodb/defaults/main.yml @@ -32,12 +32,8 @@ mongodb_admin_password: "superstrongpassword" replica_set_name: bigchain-rs -bdb_docker_net_name: "bdb_network" -bdb_docker_default_subnet: "172.18.0.0/16" -bdb_docker_default_gw: "172.18.0.1" - # Docker configuration mongodb_docker_image: "mongo:3.4.9" mongodb_docker_name: "mongodb" mongodb_host_mount_dir: "{{ ansible_env.HOME }}/mongodb_docker" -mongodb_host_config: "{{ ansible_env.HOME }}/config" \ No newline at end of file +mongodb_host_config: "{{ ansible_env.HOME }}/config" diff --git a/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml b/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml index 295f2105..ecadea49 100644 --- a/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml +++ b/pkg/configuration/roles/mongodb/tasks/deploy_docker.yml @@ -6,19 +6,6 @@ state: started tags: [mongodb] -- name: Creating BDB Docker network - docker_network: - name: "{{ bdb_docker_net_name }}" - ipam_options: - subnet: "{{ bdb_docker_default_subnet }}" - driver_options: - com.docker.network.bridge.enable_icc": "true" - com.docker.network.bridge.enable_ip_masquerade": "true" - com.docker.network.bridge.host_binding_ipv4": "0.0.0.0" - com.docker.network.driver.mtu: "1500" - state: present - tags: [mongodb] - - name: Running MongoDB Docker docker_container: name: "{{ mongodb_docker_name }}{{ item }}" @@ -26,7 +13,7 @@ image: "{{ mongodb_docker_image }}" detach: true published_ports: - - "{{ bdb_docker_default_gw }}:{{ (mongodb_port|int + item|int)|string }}:{{ mongodb_port }}" + - "{{ (mongodb_port|int + item|int)|string }}:{{ mongodb_port }}" restart_policy: always volumes: - "{{ mongodb_host_mount_dir }}{{ item|string }}/db:{{ mongodb_storage_path }}" @@ -35,8 +22,6 @@ state: started keep_volumes: true entrypoint: /entrypoint.sh --replSet=bigchain-rs - networks: - - name: "{{ bdb_docker_net_name }}" register: mongo_container_info with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 tags: [mongodb] @@ -45,4 +30,4 @@ set_fact: mongodb{{ item }}={{ mongo_container_info.results[item|int].ansible_facts.docker_container.NetworkSettings.IPAddress }} with_sequence: start=0 end="{{ docker_cluster_size|int - 1 }}" stride=1 - tags: [mongodb] \ No newline at end of file + tags: [mongodb] diff --git a/pkg/configuration/roles/mongodb/tasks/initiate_repl_set.yml b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set.yml index 2fed72d7..ecbdc625 100644 --- a/pkg/configuration/roles/mongodb/tasks/initiate_repl_set.yml +++ b/pkg/configuration/roles/mongodb/tasks/initiate_repl_set.yml @@ -3,4 +3,4 @@ when: (ansible_hostname == bdb_hosts[bdb_hosts|length-1]['name']) and not deploy_docker|bool - import_tasks: initiate_repl_set_docker.yml - when: deploy_docker|bool \ No newline at end of file + when: deploy_docker|bool and docker_cluster_size|int > 1 diff --git a/pkg/configuration/roles/mongodb/tasks/main.yml b/pkg/configuration/roles/mongodb/tasks/main.yml index 6576d4c2..8daeffc6 100644 --- a/pkg/configuration/roles/mongodb/tasks/main.yml +++ b/pkg/configuration/roles/mongodb/tasks/main.yml @@ -28,4 +28,4 @@ when: not deploy_docker|bool tags: [mongodb] -- import_tasks: initiate_repl_set.yml \ No newline at end of file +- import_tasks: initiate_repl_set.yml diff --git a/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 b/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 index e1764993..ed8c8fa4 100644 --- a/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 +++ b/pkg/configuration/roles/mongodb/templates/replSet_init_docker.j2 @@ -3,14 +3,14 @@ rs.initiate({ "members": [ { "_id": 0, - "host": "{{ mongodb_docker_name }}{{ docker_cluster_size|int - 1 }}:{{ mongodb_port }}" + "host": "{{ hostvars[ansible_hostname][mongodb_docker_name + (docker_cluster_size|int - 1)|string] }}:{{ mongodb_port }}" } ] }); sleep(5000); {% for docker in range(0, docker_cluster_size|int, 1) %} {%- if docker != (docker_cluster_size|int - 1) -%} -rs.add("{{ mongodb_docker_name }}{{ docker }}:{{ mongodb_port }}"); +rs.add("{{ hostvars[ansible_hostname][mongodb_docker_name + docker|string] }}:{{ mongodb_port }}"); {% endif %} {%- endfor -%} use admin; @@ -27,4 +27,4 @@ db.createUser(db.createUser({ "db": "admin" } ] -}); \ No newline at end of file +}); From cd9859185197316f93b41e13033ff018a915aa5e Mon Sep 17 00:00:00 2001 From: muawiakh Date: Tue, 14 Nov 2017 12:08:33 +0100 Subject: [PATCH 115/120] Address comments on docs and some typos --- .../source/appendices/run-with-ansible.md | 92 ++++++++++--------- .../source/appendices/run-with-vagrant.md | 19 ++-- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/docs/server/source/appendices/run-with-ansible.md b/docs/server/source/appendices/run-with-ansible.md index fdadb28e..b1ec6769 100644 --- a/docs/server/source/appendices/run-with-ansible.md +++ b/docs/server/source/appendices/run-with-ansible.md @@ -24,7 +24,7 @@ $ git clone https://github.com/bigchaindb/bigchaindb.git ## Install dependencies | Ansible - [Ansible](http://docs.ansible.com/ansible/latest/intro_installation.html) -You can also install `ansible` and other dependecies, if any, using the `boostrap.sh` script +You can also install `ansible` and other dependencies, if any, using the `boostrap.sh` script inside the BigchainDB repository. Navigate to `bigchaindb/pkg/scripts` and run the `bootstrap.sh` script to install the dependecies for your OS. The script also checks if the OS you are running is compatible with the @@ -40,7 +40,7 @@ $ sudo ./bootstrap.sh ### BigchainDB Setup Configuration(s) | Ansible #### Local Setup | Ansible You can run the Ansible playbook `bdb-deploy.yml` on your local dev machine and set up the BigchainDB node where -BigchainDB can be run as a process or inside a Docker container(s) depending on your configuratin. +BigchainDB can be run as a process or inside a Docker container(s) depending on your configuration. Before, running the playbook locally, you need to update the `hosts` and `bdb-config.yml` configuration, which will notify Ansible that we need to run the play locally. @@ -80,45 +80,6 @@ bdb_hosts: - name: "" ``` -#### Remote Setup | Ansible -You can also run the Ansible playbook `bdb-deploy.yml` on remote machine(s) and set up the BigchainDB node where -BigchainDB can be run as a process or inside a Docker container(s) depending on your configuration. - -Before, running the playbook on a remote host, you need to update the `hosts` and `bdb-config.yml` configuration, which will notify Ansible that we need to run the play on a remote host. - -##### Update Hosts | Remote -Navigate to `bigchaindb/pkg/configuration/hosts` inside the BigchainDB repository. -```text -$ cd bigchaindb/pkg/configuration/hosts -``` - -Edit `all` configuration file: -```text -# Delete any existing configuration in this file and insert - ansible_ssh_user= ansible_sudo_pass= -``` - -**Note 1**: You can multiple hosts to `all` configuration file. Root password is needed because ansible -will run some tasks that require root permissions. - -**Note 2**: You can also use other methods to get inside the remote machines instead of password based SSH. For other methods -please consult [Ansible Documentation](http://docs.ansible.com/ansible/latest/intro_getting_started.html). - -##### Update Configuration | Remote -Navigate to `bigchaindb/pkg/configuration/vars` inside the BigchainDB repository. -```text -$ cd bigchaindb/pkg/configuration/vars/bdb-config.yml -``` - -Edit `bdb-config.yml` configuration file as per your requirements, sample configuration file(s): -```text ---- -deploy_docker: false #[true, false] -docker_cluster_size: 1 # Only needed if `deploy_docker` is true -bdb_hosts: - - name: "" -``` - ### BigchainDB Setup | Ansible Now, You can safely run the `bdb-deploy.yml` playbook and everything will be taken care of by `Ansible`. To run the playbook please navigate to the `bigchaindb/pkg/configuration` directory inside the BigchainDB repository and run the `bdb-deploy.yml` playbook. @@ -128,7 +89,7 @@ $ cd bigchaindb/pkg/configuration/ $ sudo ansible-playbook bdb-deploy.yml -i hosts/all ``` -After successfull execution of the playbook, you can verify that BigchainDB docker(s)/process(es) is(are) running. +After successful execution of the playbook, you can verify that BigchainDB docker(s)/process(es) is(are) running. Verify BigchainDB process(es): ```text @@ -149,7 +110,7 @@ See the [BigchainDB Python Driver documentation](https://docs.bigchaindb.com/pro for details on how to use it. -Note 1: The `bdb_root_url` can be be one of the following: +**Note**: The `bdb_root_url` can be be one of the following: ```text # BigchainDB is running as a process bdb_root_url = http://:9984 @@ -160,4 +121,47 @@ OR bdb_root_url = http://: ``` -Note 2: BigchainDB has [other drivers as well](../drivers-clients/index.html). +**Note**: BigchainDB has [other drivers as well](../drivers-clients/index.html). + +### Experimental: Running Ansible a Remote Dev/Host +#### Remote Setup | Ansible +You can also run the Ansible playbook `bdb-deploy.yml` on remote machine(s) and set up the BigchainDB node where +BigchainDB can run as a process or inside a Docker container(s) depending on your configuration. + +Before, running the playbook on a remote host, you need to update the `hosts` and `bdb-config.yml` configuration, which will notify Ansible that we need to +run the play on a remote host. + +##### Update Hosts | Remote +Navigate to `bigchaindb/pkg/configuration/hosts` inside the BigchainDB repository. +```text +$ cd bigchaindb/pkg/configuration/hosts +``` + +Edit `all` configuration file: +```text +# Delete any existing configuration in this file and insert + ansible_ssh_user= ansible_sudo_pass= +``` + +**Note**: You can add multiple hosts to the `all` configuration file. Root password is needed because ansible +will run some tasks that require root permissions. + +**Note**: You can also use other methods to get inside the remote machines instead of password based SSH. For other methods +please consult [Ansible Documentation](http://docs.ansible.com/ansible/latest/intro_getting_started.html). + +##### Update Configuration | Remote +Navigate to `bigchaindb/pkg/configuration/vars` inside the BigchainDB repository. +```text +$ cd bigchaindb/pkg/configuration/vars/bdb-config.yml +``` + +Edit `bdb-config.yml` configuration file as per your requirements, sample configuration file(s): +```text +--- +deploy_docker: false #[true, false] +docker_cluster_size: 1 # Only needed if `deploy_docker` is true +bdb_hosts: + - name: "" +``` + +After, the configuration of remote hosts, [run the Ansible playbook and verify your deployment](#bigchaindb-setup-ansible). diff --git a/docs/server/source/appendices/run-with-vagrant.md b/docs/server/source/appendices/run-with-vagrant.md index 8f56328f..8bde0a38 100644 --- a/docs/server/source/appendices/run-with-vagrant.md +++ b/docs/server/source/appendices/run-with-vagrant.md @@ -113,21 +113,22 @@ The above mentioned configuration will deploy a 3 node BigchainDB cluster with D on your specified host. ## BigchainDB Setup | Vagrant + +**Note**: There are some vagrant plugins required for the installation, +user will be prompted to install them if they are not present. To install +the required plugins, run the following command: + +```text +$ vagrant plugin install vagrant-cachier vagrant-vbguest vagrant-hosts +``` + To bring up the BigchainDB node(s), run the following command: ```text $ vagrant up ``` -**Note**: There are some vagrant plugins required for the installation, -user will be prompted to install them if they are not present. Instructions -to install the plugins can be extracted from the message. - -```text -$ vagrant plugin install -``` - -After successfull execution of Vagrant, you can log in to your fresh BigchainDB node. +After successful execution of Vagrant, you can log in to your fresh BigchainDB node. ```text $ vagrant ssh From bc4f8fcab58b5863d2b78be2b04b104ad9e244eb Mon Sep 17 00:00:00 2001 From: Shahbaz Nazir Date: Fri, 17 Nov 2017 20:35:57 +0100 Subject: [PATCH 116/120] Fix getstarted undefined referrer issue with IPDB (#1866) Skip Referer check on preflight request (OPTIONS) and set Referrer-Policy to origin-when-cross-origin in response to OPTIONS request. Once Referrer-Policy is set on the subsequent POST request referrer is set by the browser to expected value. --- .../container/docker_build_and_push.bash | 4 ++-- .../container/nginx.conf.template | 13 +++++++------ .../nginx-https-web-proxy-conf.yaml | 5 +++++ .../nginx-https-web-proxy-dep.yaml | 5 +++++ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/k8s/nginx-https-web-proxy/container/docker_build_and_push.bash b/k8s/nginx-https-web-proxy/container/docker_build_and_push.bash index 69bfd56f..e84e2563 100755 --- a/k8s/nginx-https-web-proxy/container/docker_build_and_push.bash +++ b/k8s/nginx-https-web-proxy/container/docker_build_and_push.bash @@ -1,5 +1,5 @@ #!/bin/bash -docker build -t bigchaindb/nginx-https-web-proxy:0.10 . +docker build -t bigchaindb/nginx-https-web-proxy:0.12 . -docker push bigchaindb/nginx-https-web-proxy:0.10 +docker push bigchaindb/nginx-https-web-proxy:0.12 diff --git a/k8s/nginx-https-web-proxy/container/nginx.conf.template b/k8s/nginx-https-web-proxy/container/nginx.conf.template index 421d7fc0..c379dc8e 100644 --- a/k8s/nginx-https-web-proxy/container/nginx.conf.template +++ b/k8s/nginx-https-web-proxy/container/nginx.conf.template @@ -90,12 +90,6 @@ http { end } - # check if the request originated from the required web page - # use referer header. - if ($http_referer !~ "PROXY_EXPECTED_REFERER_HEADER" ) { - return 403 'Unknown referer'; - } - # check if the request has the expected origin header if ($http_origin !~ "PROXY_EXPECTED_ORIGIN_HEADER" ) { return 403 'Unknown origin'; @@ -108,9 +102,16 @@ http { add_header 'Access-Control-Max-Age' 43200; add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; + add_header 'Referrer-Policy' "PROXY_REFERRER_POLICY"; return 204; } + # check if the request originated from the required web page + # use referer header. + if ($http_referer !~ "PROXY_EXPECTED_REFERER_HEADER" ) { + return 403 'Unknown referer'; + } + # No auth for GETs, forward directly to BDB. if ($request_method = GET) { proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT; diff --git a/k8s/nginx-https-web-proxy/nginx-https-web-proxy-conf.yaml b/k8s/nginx-https-web-proxy/nginx-https-web-proxy-conf.yaml index b9dbc541..0a255d89 100644 --- a/k8s/nginx-https-web-proxy/nginx-https-web-proxy-conf.yaml +++ b/k8s/nginx-https-web-proxy/nginx-https-web-proxy-conf.yaml @@ -49,6 +49,11 @@ data: # are available to external clients. proxy-frontend-port: "4443" + # proxy-referrer-policy defines the expected behaviour from + # browser while setting the referer header in the HTTP requests to the + # proxy service. + proxy-referrer-policy: "origin-when-cross-origin" + # expected-http-referer is the expected regex expression of the Referer # header in the HTTP requests to the proxy. # The default below accepts the referrer value to be *.bigchaindb.com diff --git a/k8s/nginx-https-web-proxy/nginx-https-web-proxy-dep.yaml b/k8s/nginx-https-web-proxy/nginx-https-web-proxy-dep.yaml index 6ada9347..e92aba7d 100644 --- a/k8s/nginx-https-web-proxy/nginx-https-web-proxy-dep.yaml +++ b/k8s/nginx-https-web-proxy/nginx-https-web-proxy-dep.yaml @@ -25,6 +25,11 @@ spec: configMapKeyRef: name: proxy-vars key: proxy-frontend-port + - name: PROXY_REFERRER_POLICY + valueFrom: + configMapKeyRef: + name: proxy-vars + key: proxy-referrer-policy - name: PROXY_EXPECTED_REFERER_HEADER valueFrom: configMapKeyRef: From 6c1017510b8b8a152c741ab30e9a27e3b5128033 Mon Sep 17 00:00:00 2001 From: Shahbaz Nazir Date: Mon, 20 Nov 2017 14:08:57 +0100 Subject: [PATCH 117/120] Add standard template for creating PRs (#1776) * Add standard template for creating PRs Adding a standard template for creating Pull requests for improved code QA and delegating dependencies whenever applicable Signed-off-by: Shahbaz Nazir * Update developer docs with PR instructions Signed-off-by: Shahbaz Nazir * Addressing review comments for PR template Signed-off-by: Shahbaz Nazir --- .github/pull_request_template.md | 34 ++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 14 +++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..31636a13 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,34 @@ +## Description +A few sentences describing the overall goals of the pull request's commits. + +## Issues This PR Fixes +Fixes #NNNN +Fixes #NNNN + +## Related PRs +List related PRs against other branches e.g. for backporting features/bugfixes +to previous release branches: + +Repo/Branch | PR +------ | ------ +some_other_PR | [link]() + + +## Todos +- [ ] Tested and working on development environment +- [ ] Unit tests (if appropriate) +- [ ] Added/Updated all related documentation. Add [link]() if different from this PR +- [ ] DevOps Support needed e.g. create Runscope API test if new endpoint added or + update deployment docs. Create a ticket and add [link]() + +## Deployment Notes +Notes about how to deploy this work. For example, running a migration against the production DB. + +## How to QA +Outline the steps to test or reproduce the PR here. + +## Impacted Areas in Application +List general components of the application that this PR will affect: +- Scale +- Performance +- Security etc. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1b8fc9c9..145efe95 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -145,6 +145,20 @@ Once you accept and submit the CLA, we'll email you with further instructions. ( Someone will then merge your branch or suggest changes. If we suggest changes, you won't have to open a new pull request, you can just push new code to the same branch (on `origin`) as you did before creating the pull request. +### Pull Request Guidelines + +Before you submit a pull request, check that it meets these guidelines: + +1. The pull request should include tests. +2. If the pull request adds functionality, the docs should be updated. Put + your new functionality into a function with a docstring, and add the + feature to the list in README.rst. +3. The pull request should work for Python 3.5, and pass the flake8 check. + Check https://travis-ci.org/bigchaindb/bigchaindb-driver/pull_requests + and make sure that the tests pass for all supported Python versions. +4. Follow the pull request template while creating new PRs, the template will + be visible to you when you create a new pull request. + ### Tip: Upgrading All BigchainDB Dependencies Over time, your versions of the Python packages used by BigchainDB will get out of date. You can upgrade them using: From 9d9310d8e50f2dd9d24aa28b7fa462fb95949b8a Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 21 Nov 2017 18:41:44 +0100 Subject: [PATCH 118/120] Updated CHANGELOG.md for the v1.3 release --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index feef1748..65086567 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,16 @@ For reference, the possible headings are: * **External Contributors** to list contributors outside of BigchainDB GmbH. * **Notes** +## [1.3] - 2017-11-21 +Tag name: v1.3.0 + +### Added +* Metadata full-text search. [Pull request #1812](https://github.com/bigchaindb/bigchaindb/pull/1812) + +### Notes +* Improved documentation about blocks and votes. [Pull request #1855](https://github.com/bigchaindb/bigchaindb/pull/1855) + + ## [1.2] - 2017-11-13 Tag name: v1.2.0 From 61747b138d3854daef427452b3a6e7123993b250 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 21 Nov 2017 18:58:41 +0100 Subject: [PATCH 119/120] Updated Docker image to 1.3.0 in k8s YAML files --- k8s/bigchaindb/bigchaindb-dep.yaml | 2 +- k8s/dev-setup/bigchaindb.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/k8s/bigchaindb/bigchaindb-dep.yaml b/k8s/bigchaindb/bigchaindb-dep.yaml index 5e23f4c0..ed79b122 100644 --- a/k8s/bigchaindb/bigchaindb-dep.yaml +++ b/k8s/bigchaindb/bigchaindb-dep.yaml @@ -12,7 +12,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: bigchaindb - image: bigchaindb/bigchaindb:1.2.0 + image: bigchaindb/bigchaindb:1.3.0 imagePullPolicy: IfNotPresent args: - start diff --git a/k8s/dev-setup/bigchaindb.yaml b/k8s/dev-setup/bigchaindb.yaml index e9980a96..48a0db2b 100644 --- a/k8s/dev-setup/bigchaindb.yaml +++ b/k8s/dev-setup/bigchaindb.yaml @@ -34,7 +34,7 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: bigchaindb - image: bigchaindb/bigchaindb:1.2.0 + image: bigchaindb/bigchaindb:1.3.0 imagePullPolicy: Always args: - start From b2ff0a454493f6b6986835805ee70d6497bcbb15 Mon Sep 17 00:00:00 2001 From: Troy McConaghy Date: Tue, 21 Nov 2017 19:05:48 +0100 Subject: [PATCH 120/120] Updated to 1.3.0 in version.py --- bigchaindb/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bigchaindb/version.py b/bigchaindb/version.py index 4937b037..919193d2 100644 --- a/bigchaindb/version.py +++ b/bigchaindb/version.py @@ -1,2 +1,2 @@ -__version__ = '1.3.0.dev' -__short_version__ = '1.3.dev' +__version__ = '1.3.0' +__short_version__ = '1.3'