[
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--\r\nDo you have a broad question? Are you suggesting a feature, e.g. a new VPN\r\nservice or cloud provider? If so, please create a new issue in the Streisand\r\nDiscussions repository instead:\r\nhttps://github.com/StreisandEffect/streisand-discussions/issues/ \r\n-->\r\n\r\n### Expected behavior:\r\n\r\n### Actual Behavior:\r\n\r\n### Steps to Reproduce:\r\n1. \r\n\r\n<!--\r\nIf you have a `streisand-diagnostics.md` file in your Streisand directory please\r\npaste its contents below. \r\n-->\r\n\r\n[ contents of `streisand-diagnostics.md` here ]\r\n\r\n<!--\r\nIf you *do not* have a `streisand-diagnostics.md` file to share, please answer \r\nthe following questions below manually\r\n-->\r\n### Additional Details:\r\n#### *Log output from Ansible or other relevant services (link to Gist for longer output):*\r\n##### *Target Cloud Provider:*\r\n##### *Operating System of target host:*\r\n##### *Operating System of client:*\r\n##### *Version of Ansible, using `ansible --version` :*\r\n##### *Output from `git rev-parse HEAD` in your Streisand directory :*\r\n"
  },
  {
    "path": ".github/workflows/streisand.yml",
    "content": "---\nname: Streisand\non: [push, pull_request]\n\njobs:\n  deps:\n    name: Dependencies\n    runs-on: ubuntu-16.04\n    env:\n      ANSIBLE_CONFIG: tests/ansible.cfg\n      ANSIBLE_NOCOWS: true\n      #ANSIBLE_VERBOSITY: 5\n      DEBIAN_FRONTEND: noninteractive\n    strategy:\n      #max-parallel: 5\n      fail-fast: false\n      matrix:\n        # 3.5 for older distro's like xenial, and 3.8 to test the latest python\n        python-version: [3.5, 3.8]\n        # Test ansible 2.8 and \"latest\"\n        ansible-version: [\">=2.8,<2.9\", \">=2.9\"]\n        env_vars:\n          - {RUN: \"shellcheck yamlcheck syntax ci\", SITE: \"global_vars/default-site.yml\"}\n          - {RUN: \"ci\", SITE: \"tests/site_vars/openconnect.yml\"}\n          - {RUN: \"ci\", SITE: \"tests/site_vars/openvpn.yml\"}\n          - {RUN: \"ci\", SITE: \"tests/site_vars/shadowsocks.yml\"}\n          - {RUN: \"ci\", SITE: \"tests/site_vars/ssh.yml\"}\n          - {RUN: \"ci\", SITE: \"random\"}\n    steps:\n        # Removing dotnetdev.list, and microsoft-prod.list for now, as they seem to constantly have issues\n        # with multiple github issues being opened in response. Removing shellcheck so we can install\n        # a newer version from snap.\n      - name: Remove apt lists and packages we dont need\n        run: |\n          sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list\n          sudo rm -rf /var/lib/apt/lists/*\n          sudo apt-get clean\n          sudo apt-get update -qq\n          sudo apt-get purge -yqq shellcheck\n          sudo dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\\.[0-9]+\\.[0-9]+' | grep -v $(uname -r | cut -d- -f-2) | xargs sudo apt-get -yqq purge\n          sudo apt-get --purge autoremove -yqq\n      - name: Update Yarn Debian key\n        run: |\n          curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -\n      - name: Install additonal deps\n        run: |\n          sudo apt-get install ca-certificates\n          sudo snap install --channel=edge shellcheck\n      - uses: actions/checkout@v1\n        with:\n          fetch-depth: 1\n      - name: Set up Python ${{ matrix.python-version }}\n        uses: actions/setup-python@v1\n        with:\n          fetch-depth: 1\n          python-version: ${{ matrix.python-version }}\n      - name: Install additional pip dependencies\n        run: |\n          python -m pip install --upgrade pip\n          pip install \"ansible${{ matrix.ansible-version }}\"\n          pip install urllib3 yamllint\n          ansible --version\n      - name: Run tests\n        env: ${{ matrix.env_vars }}\n        run: ./tests/tests.sh\n"
  },
  {
    "path": ".gitignore",
    "content": "generated-docs\n*.retry\n*.pyc\n*~\n*.swp\n*.tmp\n*.temp\n.DS_Store\n.vagrant/\nubuntu-xenial-16.04-cloudimg-console.log\n\n# Ignore changes to the existing server inventory to allow users to modify it\ninventories/inventory-existing\n\n# Ignore the Streisand diagnostics file we generate each run\nstreisand-diagnostics.md\n\n# We recommend people use a Python virtualenv, and document this as\n# the location.\nvenv/\n"
  },
  {
    "path": "Advanced installation.md",
    "content": "# Advanced installation\n\n### Running Streisand to Provision Localhost ###\n\nIf you can't run Streisand in the normal manner (running from your client home machine/laptop to configure a remote server) Streisand supports a local provisioning mode for **machines running Ubuntu 16.04**. After following the basic instructions, choose \"Localhost (Advanced)\" from the menu after running `./streisand`.\n\n**Note:** Running Streisand against localhost can be a destructive action! You will be potentially overwriting configuration files and must be certain that you are affecting the correct machine.\n\n**Note:** The machine must be running Ubuntu 16.04.\n\n**Note:** If you have an external firewall available, see the `generated-docs` directory for a `-firewall-information.html` document with information on which ports need to be opened.\n\n### Running Streisand on Other Providers ###\n\nYou can also run Streisand on a new Ubuntu 16.04 server. Dedicated hardware? Great! Esoteric cloud provider? Awesome! To do so, simply choose \"Existing Server (Advanced)\" from the menu after running `./streisand` and provide the IP address of the existing server when prompted.\n\nThe server must be accessible using the `$HOME/.ssh/id_rsa` SSH Key, and **root** is used as the connecting user by default. If your provider requires you to SSH with a different user than root (e.g. `ubuntu`) specify the `ANSIBLE_SSH_USER` environmental variable (e.g. `ANSIBLE_SSH_USER=ubuntu`) when you run `./streisand`.\n\n**Note:** Running Streisand against an existing server can be a destructive action! You will be potentially overwriting configuration files and must be certain that you are affecting the correct machine.\n\n**Note:** The machine must be running Ubuntu 16.04.\n\n**Note:** If you have an external firewall available, see the `generated-docs` directory for a `-firewall-information.html` document with information on which ports need to be opened.\n\n### Noninteractive Deployment ###\n\nAlternative scripts and configuration file examples are provided for\nnoninteractive deployment, in which all of the required information is passed\non the command line or in a configuration file.\n\nExample configuration files are found under `global_vars/noninteractive`. Copy\nand edit the desired parameters, such as providing API tokens and other choices,\nand then run the appropriate script.\n\nTo deploy a new Streisand server:\n\n      deploy/streisand-new-cloud-server.sh \\\n        --provider digitalocean \\\n        --site-config global_vars/noninteractive/digitalocean-site.yml\n\nTo run the Streisand provisioning on the local machine:\n\n      deploy/streisand-local.sh \\\n        --site-config global_vars/noninteractive/local-site.yml\n\nTo run the Streisand provisioning against an existing server:\n\n      deploy/streisand-existing-cloud-server.sh \\\n        --ip-address 10.10.10.10 \\\n        --ssh-user root \\\n        --site-config global_vars/noninteractive/digitalocean-site.yml\n\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## Contributing Issues and Bug Reports\r\n\r\nThanks for your interest in helping improve Streisand! This documentation page\r\nhas some helpful tips and things to keep in mind to make your\r\ncontributions to Streisand as great as they can be.\r\n\r\n### Keep it Positive/Empathetic\r\n\r\nEncountering bugs is a frustrating experience! Missing features speak to\r\nunaddressed needs. We understand that and want to help.\r\n\r\nPlease also remember that Streisand is 100% a volunteer effort. Nobody is paid\r\nto work on Streisand, and nobody does it as their full time job.\r\n\r\nWhere possible try to keep discussion tone positive and remember that the folks\r\nworking on Streisand fit it into their spare time between other real life\r\ncommitments (family, vacation, jobs, hobbies, relaxation!).\r\n\r\n### Which Repository?\r\n\r\nIf your issue is a question or you need help with setting up / configuring Streisand, then please ask on the [streisand-discussions](https://github.com/StreisandEffect/streisand-discussions/) Github repository. \r\n\r\nSimilarly, if you are requesting a new feature we prefer it be done on the [streisand-discussions](https://github.com/StreisandEffect/streisand-discussions) Github repository.\r\n\r\n### Before Submitting an Issue\r\n\r\nBefore submitting new issues please do a search in [open issues](https://github.com/StreisandEffect/streisand/issues) to see if the issue or refinement you have in mind has already been suggested. For features/questions search [the streisand-discussions open issues](https://github.com/StreisandEffect/streisand-discussions/issues).\r\n\r\nIf you find your issue already exists, feel free to add constructive comments such as new information, additional insights on how to reproduce, etc. If you're only interested in sharing that the feature is important to you, or that the bug affects you then add a [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Using reactions in place of a \"+1\" or \"me too!\" comments helps keeps the conversation clear and concise.\r\n\r\n👍 - upvote\r\n\r\n👎 - downvote\r\n\r\nIf you cannot find an existing issue that describes your bug or feature, submit a new issue using the guidelines below.\r\n\r\n## Writing Good Bug Reports and Feature Requests\r\n\r\nDescribe a single problem or feature request per issue. Do not include multiple bugs or feature requests in the same issue.\r\nThe more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix. \r\n#Take advantage of Github Markdown styling to make your issue easier to read. For example, Wrap single line code statements or logs in single backticks: \\` code here \\`. Wrap multi-line in triple backticks: \\``` multi-line code here \\```. \r\n\r\n#### Streisand Diagnostics File\r\n\r\nStreisand automatically creates a markdown file in the project directory called\r\n`streisand-diagnostics.md`. Every time you run Streisand this file is populated\r\nwith some basic diagnostic information about your system & Streisand options\r\nthat are enabled.\r\n\r\nSharing the contents of this file in new issues is a great way to answer a lot\r\nof required questions without having to do any work besides copy & pasting!\r\n\r\n#### What Other Information to Include in Your Issue\r\n\r\nPlease try your best to answer all of the questions in [the Streisand Issue template](https://github.com/StreisandEffect/streisand/blob/master/.github/ISSUE_TEMPLATE.md). Answering these questions help us skip a lot of \"Github telephone tag\" that takes up time that could be used fixing the bug.\r\n\r\nWhen describing your issue focus on:\r\n\r\n* Reproducible steps (1... 2... 3...) and what you expected versus what you actually saw.\r\n* Log output from Ansible or other relevant services, ideally linking to a Gist for longer log output.\r\n* Information about your system (OS, version, etc)\r\n* Information about the target Streisand server (cloud provider, etc)\r\n\r\nDon't feel bad if we can't reproduce the issue and ask for more information.\r\nIt's impossible to know what questions will be most relevant for every potential\r\nbug!\r\n\r\n#### Why Was My Issue Closed???\r\n\r\nIssues are generally closed for one of three reasons:\r\n\r\n1. There wasn't enough information or nobody has been replying to questions\r\n   asked.\r\n2. The issue was created on the wrong repository and should have been created as\r\n   a [streisand-discussions](https://github.com/StreisandEffect/streisand-discussions)\r\n   issue or vice-versa.\r\n3. After discussion and evaluation it was determined the problem was fixed or\r\n   wasn't appropriate for Streisand\r\n\r\nWe try very hard to keep the issue list clean. Don't feel bad if your issue\r\nwas closed, it can always be reopened if there are disagreements to discuss\r\nor the situation has changed.\r\n\r\n## Contributing Fixes\r\n\r\nIf you are interested in fixing issues and contributing directly to the code\r\nbase please feel free to submit a PR. We're excited to help! If there is an\r\nexisting issue for the problem you are interested in fixing please leave a quick\r\ncomment indicating that you'd like to start working on a solution. That way we\r\ncan avoid duplicating work. Similarly, talking about how you plan to implement\r\na fix or a new feature ahead of starting gives folks a chance to give early\r\ndesign input which will save time later during code review!\r\n\r\n#### CI Testing\r\n\r\nStreisand uses [Travis CI](https://travis-ci.org/jlund/streisand) for continuous\r\nintegration testing. Make sure to read\r\n[testing.md](https://github.com/StreisandEffect/streisand/blob/master/documentation/testing.md)\r\nwhere we describe the tests that are run, how to work around breakages for\r\nfeatures unsupported by LXC, and tips for developing on localhost with Vagrant.\r\nAll PRs will have to pass CI to be merged. Feel free to submit a PR with broken\r\nCI if you need help getting the tests to pass.\r\n\r\n#### Code Reviews\r\n\r\nAll PRs need at least one approved code review from a maintainer in order to be\r\nmerged. Maintainers may not review their own pull requests.\r\n\r\nStreisand is a volunteer effort. Please allow at least 7 days to pass before\r\nfollowing up on missing reviews. If more than 7 days have elapsed and you are\r\nstill waiting on a review or a reply from a maintainer please leave a friendly\r\n\"bump\" message and \"@ mention\" their username.\r\n\r\n#### Modularity\r\n\r\nWe've recently begun working on modularizing Streisand so that installations can\r\nbe customized to include/not include certain VPN services. Additions to\r\nStreisand should endeavour to fit into this model. We describe the philosophy\r\nand design patterns used in this approach in\r\n[modular_roles.md](https://github.com/StreisandEffect/streisand/blob/master/documentation/modular_roles.md)\r\n\r\n"
  },
  {
    "path": "Features.md",
    "content": "# Features\n\n* A single command sets up a brand new Ubuntu 16.04 server running a [wide variety of anti-censorship software](#services-provided) that can completely mask and encrypt all of your Internet traffic.\n* Streisand natively supports the creation of new servers at [Amazon EC2](https://aws.amazon.com/ec2/), [Azure](https://azure.microsoft.com), [DigitalOcean](https://www.digitalocean.com/), [Google Compute Engine](https://cloud.google.com/compute/), [Linode](https://www.linode.com/), and [Rackspace](https://www.rackspace.com/)&mdash;with more providers coming soon! It also runs on any Ubuntu 16.04 server regardless of provider, and **hundreds** of instances can be configured simultaneously using this method.\n* The process is completely automated and only takes about ten minutes, which is pretty awesome when you consider that it would require the average system administrator several days of frustration to set up even a small subset of what Streisand offers in its out-of-the-box configuration.\n* Once your Streisand server is running, you can give the custom connection instructions to friends, family members, and fellow activists. The connection instructions contain an embedded copy of the server's unique SSL certificate, so you only have to send them a single file.\n* Each server is entirely self-contained and comes with absolutely everything that users need to get started, including cryptographically verified mirrors of all common clients. This renders any attempted censorship of default download locations completely ineffective.\n* But wait, there's more...\n\nMore Features\n-------------\n* Nginx powers a password-protected and encrypted Gateway that serves as the starting point for new users. The Gateway is accessible over SSL, or as a Tor [hidden service](https://www.torproject.org/docs/hidden-services.html.en).\n  * Beautiful, custom, step-by-step client configuration instructions are generated for each new server that Streisand creates. Users can quickly access these instructions through any web browser. The instructions are responsive and look fantastic on mobile phones.\n  * The integrity of mirrored software is ensured using SHA-256 checksums, or by verifying GPG signatures if the project provides them. This protects users from downloading corrupted files.\n  * All ancillary files, such as OpenVPN configuration profiles, are also available via the Gateway.\n  * Current Tor users can take advantage of the additional services Streisand sets up in order to transfer large files or to handle other traffic (e.g. BitTorrent) that isn't appropriate for the Tor network.\n  * A unique password, SSL certificate, and SSL private key are generated for each Streisand Gateway. The Gateway instructions and certificate are transferred via SSH at the conclusion of Streisand's execution.\n* Distinct services and multiple daemons provide an enormous amount of flexibility. If one connection method gets blocked there are numerous options available, most of which are resistant to Deep Packet Inspection.\n  * All of the connection methods (including direct OpenVPN connections) are effective against the type of blocking Turkey has been experimenting with.\n  * OpenConnect/AnyConnect, OpenSSH, OpenVPN (wrapped in stunnel), Shadowsocks, Tor (with obfsproxy and the obfs4 pluggable transport), and WireGuard are all currently effective against China's Great Firewall.\n* Every task has been thoroughly documented and given a detailed description. Streisand is simultaneously the most complete HOWTO in existence for the setup of all of the software it installs, and also the antidote for ever having to do any of this by hand again.\n* All software runs on ports that have been deliberately chosen to make simplistic port blocking unrealistic without causing massive collateral damage. OpenVPN, for example, does not run on its default port of 1194, but instead uses port 636, the standard port for LDAP/SSL connections that are beloved by companies worldwide.\n"
  },
  {
    "path": "Installation.md",
    "content": "# Installation\n\nPlease read all installation instructions **carefully** before proceeding.\n\nIf you're an expert, and installing on a cloud provider Streisand doesn't support, make sure to read [the advanced installation instructions](Advanced%20installation.md).\n\n## Important: definitions ##\nStreisand is based on [Ansible](https://www.ansible.com/), an automation tool that is typically used to provision and configure files and packages on remote servers. Streisand automatically sets up **another server** with the VPN packages and configuration. We call the machine that sets up the Streisand server the *builder*. Think of the builder as \"a place to stand.\"\n\n* If you don't have a suitable builder machine, you could set up another cloud server to use as your builder. That means you'd have two cloud servers at the end — the builder, and your fresh new Streisand *server*.  When you're done with the builder, make sure you download the *builder's* `streisand` directory — very important to keep the contents of that directory! — you could delete the *builder* cloud server.)\n\n* Although it's not recommended, sometimes you can use a fresh server as both the builder and the server. See the [the advanced installation instructions](Advanced%20installation.md).\n\n## Prerequisites ##\n\nThe Streisand builder requires a Linux, macOS, or BSD system.\n\n* Using native Windows as a builder is not supported, but Ubuntu on the [Windows Subsystem For Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/faq) should work. ([Ubuntu install link on Microsoft Store](https://www.microsoft.com/en-us/p/ubuntu-1804-lts/9n9tngvndl3q))\n\nComplete all of these tasks on your local machine. All of the commands should be run inside a command-line session.\n\n### SSH key\n\nMake sure an SSH public key is present in `~/.ssh/id_rsa.pub`.\n\n  * SSH keys are a more secure alternative to passwords that allow you to prove your identity to a server or service built on public key cryptography. The public key is something that you can give to others, whereas the private key should be kept secret (like a password).\n\nTo check if you already have an SSH public key, enter the following command at a command prompt:\n\n```\nls ~/.ssh\n```\n\nIf you see an `id_rsa.pub` file, then you have an SSH public key. If you do not have an SSH key pair, you can generate one by using this command and following the defaults:\n\n```\nssh-keygen\n```\n\nIf you'd like to use an SSH key with a different name or from a non-standard location, please enter *yes* when asked if you'd like to customize your instance during installation.\n\n  * **Please note**: You will need these keys to access your Streisand instance over SSH. Please keep `~/.ssh/id_rsa` and `~/.ssh/id_rsa.pub` for the lifetime of the Streisand server.\n\n\n## Bootstrap ##\n\nInstall the bootstrap packages: Git, and Python 3.5 or later. Some environments need additional packages.\n\nHere's how to set up these packages:\n\n* On Debian and Ubuntu:\n\n```\nsudo apt-get install git python3 python3-venv\n```\n\n* On Fedora 30, some additional packages are needed later:\n\n```\ndnf install git python3 gcc python3-devel python3-crypto \\\n     python3-pycurl libcurl-devel\n\n```\n\n* On CentOS 7, `python36` is available from the EPEL repository; some additional packages are needed later:\n\n```\nsudo yum -y update && sudo yum install -y epel-release\nsudo yum -y update && sudo yum install -y \\\n    git gcc python36-devel python36-crypto python36-pycurl \\\n    libcurl-devel\n```\n\n* On macOS, `git` is part of the Developer Tools, and it will be installed the first time you run it. Python 3.5 or later is required. Either use [Homebrew](https://brew.sh/) and run `brew install python3`, or see [the Python.org Mac download site](https://www.python.org/downloads/mac-osx/); the package you want to download is the \"macOS 64-bit installer\".\n\n## Execution ##\n\n1. Clone the Streisand repository and enter the directory.\n\n        git clone https://github.com/StreisandEffect/streisand.git && cd streisand\n\n1. Run the installer for Ansible and its dependencies. The installer will detect missing packages, and print the commands needed to install them. (Ignore the Python 2.7 `DEPRECATION` warning; ignore the warning from python-novaclient that pbr 5.1.3 is incompatible.)\n\n       ./util/venv-dependencies.sh ./venv\n\n1. Activate the Ansible packages that were installed.\n\n        source ./venv/bin/activate\n\n1. Execute the Streisand script.\n\n        ./streisand\n\n1. Follow the prompts to choose your provider, the physical region for the server, and its name. You will also be asked to enter API information.\n1. Once login information and API keys are entered, Streisand will begin spinning up a new remote server.\n1. Wait for the setup to complete (this usually takes around ten minutes) and look for the corresponding files in the `generated-docs` folder in the Streisand repository directory. The HTML file will explain how to connect to the Gateway over SSL, or via the Tor hidden service. All instructions, files, mirrored clients, and keys for the new server can then be found on the Gateway. You are all done!\n\n## Keep the results!\n\nYou should keep a copy of the `generated-docs` directory for the life of the server.\n\nRemember to save your `~/.ssh/id_rsa` and `~/.ssh/id_rsa.pub` SSH keys too. You'll need them in case you want to troubleshoot or perform maintenance on your server later.\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright 2014-2017 Joshua Lund\n\nOpenVPN role courtesy of Sovereign (https://github.com/al3x/sovereign)\nCopyright 2013-2014 Luke Cyca, Ben Ford, Greg Karékinian, Joshua Lund,\nand Alex Payne.\n\nL2TP/IPsec configuration files courtesy of Lin Song\n(https://github.com/hwdsl2/setup-ipsec-vpn).\nCopyright 2014-2017 Lin Song, and based on the work of\nThomas Sarlandie (Copyright 2012).\nModifications to the L2TP/IPsec configuration files are licensed\nunder CC Attribution-ShareAlike 3.0 Unported\n(http://creativecommons.org/licenses/by-sa/3.0/).\n\nCloudflared DNS-over-HTTPS role courtesy of Steven Foerster\n(https://github.com/sfoerster/ansible-cloudflared).\nCopyright 2019 Steven Foerster, and based on the work of\nBen Dews (Copyright 2018).\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\n\n                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "README-chs.md",
    "content": "<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/jlund/streisand/master/logo.jpg\" alt=\"Automate the effect\"/>\n</p>\n\n- - -\n[English](README.md), [Français](README-fr.md), [简体中文](README-chs.md), [Русский](README-ru.md) | [Mirror](https://gitlab.com/alimakki/streisand)\n- - -\n\n[![Build Status](https://github.com/StreisandEffect/streisand/workflows/Streisand/badge.svg)](https://github.com/StreisandEffect/streisand/actions)\n[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/espadrine.svg?style=social&label=Follow%20%40StreisandVPN)](https://twitter.com/StreisandVPN)\n\nStreisand\n=========\n\n**欲盖弥彰的[Streisand效应](https://zh.wikipedia.org/wiki/%E5%8F%B2%E7%BF%A0%E7%8F%8A%E6%95%88%E5%BA%94).**\n\n互联网对我们并不公平。ISP、通信、政治家，他们串通一气封锁那些我们感兴趣和关注的网站和信息。或许是时候*打破枷锁*，来场正面较量了。\n\nStreisand介绍\n---------------------\n* 只需要一个简单的脚本，就能在全新的 Ubuntu 16.04 服务器上运行[多个不同的科学上网工具](#提供的服务)，它们能够让你匿名并且加密所有的网络流量。\n* Streisand 原生支持多个 VPS 供应商，其中包括[亚马逊EC2](https://aws.amazon.com/ec2/)，[微软云服务](https://azure.microsoft.com)，[DigitalOcean](https://www.digitalocean.com/)，[Google云计算](https://cloud.google.com/compute/)，[Linode](https://www.linode.com/)和[Rackspace](https://www.rackspace.com/)；随着软件的开发还将支持更多云和VPS——只要运行的是 Ubuntu 16.04 ，不论提供商是谁还是有**成百个**实例都能用这个方法部署。\n* 整个部署过程顺利的话大概在10分钟左右搞定。试想一个没有系统管理能力的人可能要花数天来完成其中一项工作，而我们用 Streisand 让你获得获得开箱既得的畅快体验。\n* 一旦部署完成，你可以将使用指南发送给你的朋友，家人和你觉得对你重要的人**（译者注：原文是社会活动家）**。在这个指南中包含唯一的一个 SSL 证书，这也意味着你发送给他们的只是一个简单的文件而已。\n* 部署好网关中包含了用户需要的一切内容，例如设置向导，所支持操作系统需要的客户端。即使无法下载到官方客户端的朋友都可以在网关中的镜像里下载到需要的最新版本客户端。\n* 这才是开始，来来来，看看后面更精彩...\n\n更多特性\n-------------\n* 新用户登录时，使用 Nginx 提供密码保护和网关加密。加密网关通过 SSL 证书，或者通过 [Tor](https://www.torproject.org/docs/hidden-services.html.en)隐藏服务进行加密。\n  * 网关将自动生成客户端配置说明，架设在轻量级的 http 服务器 Nginx 上。而您可以用电脑或是手机的浏览器轻松阅读，只需按部就班就能轻松配置客户端了。\n  * 所有科学上网需要的客户端软件都进行了 SHA-256 检查，并且通过 GPG 进行了签名认证。确保那些无法通过官方渠道下载客户端的用户同样能够从镜像放心下载。\n  * 所有客户端需要的额外文件，比如：OpenVPN 的配置文件，都可以通过网关下载到。\n  * 目前 Tor 用户可以借助 Streisand 所提供的优秀特性传输大文件或者控制 Tor 服务其他流量（比如BT，传统的 Tor 并不适合进行BT这样的数据传输）。\n  * 网关会自动生成一个唯一的密码、一个 SSL 证书和一个 SSL 私钥。在Streisand部署后，网关说明和证书都通过 SSH 进行传输。\n  * 不同的服务和多个守护进程带来了巨大的灵活性。如果其中一个连接方式遭到封锁，还有其他方式可以尝试使用。它们大多数都能够避免深度包检测。\n  * OpenConnect/AnyConnect, OpenSSH（没有测试）, OpenVPN (stunnel加持的), Shadowsocks, and Tor (obfs4进行混淆传输)都可以在中国使用\n* 每一个科学上网工具都提供了文档和详细的描述。 Streisand 或许是迄今为止最为全面的指南，帮助你安装和配置客户端。在必要的时候也能够再次通过手动完成任何相关操作。\n* 为了避免科学上网工具被大面积破坏，端口在设计上也是有讲究的。比方说 OpenVPN ，并没有运行在默认的1194端口，而是636端口，这个是很多跨国公司使用的标准 LDAP/SSL 连接端口。\n\n<a name=\"提供的服务\"></a>\n提供的服务\n-----------------\n\n* [OpenSSH](https://www.openssh.com/)\n  * 支持 Windows 和 Android 的 SSH 隧道， 并且需要使用 PuTTY 将默认的密钥对导出成 .ppk 的格式；\n  * [Tinyproxy](https://banu.com/tinyproxy/) 默认安装并绑定到主机，它作为一个 http(s) 代理提供给那些原生不支持 SOCKS 代理的软件通过 SSH 隧道访问网络，比如说 Android 上的鸟嘀咕。\n  * 针对 [sshuttle](https://github.com/sshuttle/sshuttle) 的一个无特权转发用户和产生的 SSH 密钥对，同样也兼容 SOCKS；\n* [OpenConnect](https://ocserv.gitlab.io/www/index.html) / [Cisco AnyConnect](https://www.cisco.com/c/en/us/products/security/anyconnect-secure-mobility-client/index.html)\n  * oepnConnect (ocserv) 是一个非常强劲、轻巧的 VPN 服务器，并且完全兼容思科的 AnyConnect 客户端；\n  * 其中包涵了很多顶级的标准[协议](https://ocserv.gitlab.io/www/technical.html)，比如：HTTP, TLS 和 DTLS， 当然还有很多被跨国公司广泛使用的且流行的技术；\n   * 这就意味着 OpenConnect 非常易用且高速，而且经得住审查的考验，几乎从未被封锁。\n* [OpenVPN](https://openvpn.net/index.php/open-source.html)\n  * 从自带的 .ovpn 配置文件生成一个简单的客户端配置文件；\n  * 同时支持 TCP 和 UDP 连接；\n  * 客户端的 DNS 解析由 [Dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) 负责，避免 DNS 泄露；\n  * 启用 TLS 认证，有助于防止主动探测攻击。错误的 HMAC 流量并不会被轻易丢弃。\n* [Shadowsocks](https://shadowsocks.org/en/index.html)\n  * 安装的是高性能的 libev 版本，这个版本能够处理数以千计的并发连接；\n  * Android 和 iOS 只需要扫描一个二维码就能完成自动配置。DNS 可以设置为 8.8.8.8，或者将配置一一复制粘贴到客户端上；\n  * 采用 ChaCha20 和 Poly1305 对 [AEAD](https://shadowsocks.org/en/spec/AEAD-Ciphers.html) 进行加密，增强了安全性并提升了穿透性；\n  * 使用 [simple-obfs](https://github.com/shadowsocks/simple-obfs) 插件提供流量混淆以便于从审查的网络中脱逃（尤其是QOS节流中）。\n* [sslh](https://www.rutschle.net/tech/sslh/README.html)\n  * sslh 是一个协议解复用器（这个我不了解，如果有更好的翻译请request），在一个高度限制的网络环境下（只能访问 http 端口的网络为例），它作为一种备选方案，仍然可以通过 OpenSSH 和 OpenVPN 进行连接，因为通过 sslh 让二者共享了 443 端口。\n* [Stunnel](https://www.stunnel.org/index.html)\n  * 监听并且将 OpenVPN 的流量进行封装，让 OpenVPN 的流量伪装成标注的 SSL 流量，从而可以让 OpenVPN 客户端成功通过隧道进行连接，躲避深度包检测。\n  * 通过隧道连接的 OpenVPN 的配置文件和直接连接 OpenVPN 的配置文件是一起生成的，详细的说明也一同生成。\n  * stunnel 证书和密钥是 PKCS #12 格式，SSL 隧道程序能够很好的兼容，尤其 [OpenVPN Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn) 版本也能够通过 [SSLDroid](https://play.google.com/store/apps/details?id=hu.blint.ssldroid) 传输。在中国的移动设备上使用 OpenVPN 成为可能*（据译者所知，大陆 OpenVPN 以前完全阵亡）*。\n* [Tor](https://www.torproject.org/)\n  * 桥接的名字是随即生成的；\n  * [Obfsproxy](https://www.torproject.org/projects/obfsproxy.html.en) 默认安装并且配置支持 obfs4 传输；\n  * Android 手机使用 [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android) 扫描二维码即可获取桥接信息并完成自动配置。\n* [UFW](https://wiki.ubuntu.com/UncomplicatedFirewall)\n  * 防火墙根据不同的服务完全配置好，任何未经授权的流量都将被阻止。\n* [系统无人值守安全更新](https://help.ubuntu.com/community/AutomaticSecurityUpdates)\n  * Streisand 所在的服务器自动配置成无人值守更新，自动更新级别为*安全更新*。\n* [WireGuard](https://www.wireguard.com/)\n  * Linux 用户可以使用下一代更加简化，基于内核的黑科技 VPN ，速度快，而且使用了很多之前 VPN 所没有加密类型。\n\n安装\n------------\n在你搞事情之前，认真阅读\n\n### 重要说明 ###\nStreisand 基于 [Ansible](https://www.ansible.com/) ，它可以在远程服务器完成自动配置、打包等工作，Streisand 是将远程服务器自动配置成为多个 VPN 服务及科学上网的工具。\n\nStreisand 运行在**你自己的计算机上时（或者你电脑的虚拟机上时）**，它将把网关部署到你 VPS 提供商的**另一个服务器**上（通过你自己的API自动生成）。另外，如果 Streisand 运行在 VPS 上，它将会把网关部署到**另一个 VPS 上**，所以说原先你运行 Streisand 的那个 VPS 就多余了，记得部署完成并获得文档后把它删掉，而部署出来的那个 VPS 你是无法使用 SSH 连接进去的，除非你有公钥（当然这是不可能的，因为整个配置过程都没有提供公钥给你下载或者你想办法把它搞出来）。\n\n在某些情况下，你可能需要运行 Streisand/Ansible 在 VPS 上并将其自身配置为 Streisand 服务器，这种模式适合当你无法在你自己的计算机上运行和安装 Streisand/Ansible 时，或本地与 VPS 之间的 SSH 连接不稳定时。\n\n### 准备工作 ###\n在本地计算机完成以下所有步骤（也可以在 VPS 上运行）。\n\n* Streisand 运行在 BSD，Linux，或者 macOS 上，Windows 上是无法运行的。所有的指令都需要在终端下运行。\n* 需要 Python 2.7 ，一般在 macOS 、Linux 及 BSD 系统上都是标配，如果你使用的发行版标配是 Python 3，你需要安装 Python 2.7 来运行 Streisand。\n* 确定你的 SSH key 储存在 ~/.ssh/id\\_rsa.pub 。\n  * 如果不曾有过 SSH key，你需要用下面的命令生成一个：\n\n        ssh-keygen\n* 安装 Git 。\n  * 基于 Debian 和 Ubuntu 的 Linux 发行版\n\n        sudo apt install git\n  * 在 Fedora\n\n        sudo dnf install git\n  * 在 macOS 上 （需要通过 [Homebrew](https://brew.sh/) 进行安装）\n\n        brew install git\n* 利用 Python 安装 [pip](https://pip.pypa.io/en/latest/) 包管理\n  * 基于 Debian 和 Ubuntu 的 Linux 发行版\n\n        sudo apt install python-paramiko python-pip python-pycurl python-dev build-essential\n  * 在 Fedora\n\n        sudo dnf install python-pip\n  * 在 macOS 上\n\n        sudo easy_install pip\n        sudo pip install pycurl\n\n* 安装 [Ansible](https://www.ansible.com/) 。\n  * 在 macOS 上\n\n        brew install ansible\n  * 在 Linux 和 其他 BSD 上\n\n        sudo pip install ansible markupsafe\n* 以下使用 pip 安装的 Python 库根据你所使用的 VPS 供应商不同而不同。如果你准备将目前使用的 VPS 变成网关，可以跳过此步。\n  * 亚马逊 EC2\n\n        sudo pip install boto boto3\n  * 微软云服务\n\n        sudo pip install ansible[azure]\n  * Google\n\n        sudo pip install \"apache-libcloud>=1.17.0\"\n  * Linode\n\n        sudo pip install linode-api4\n  * Rackspace 云\n\n        sudo pip install pyrax\n  * **特别需要注意的是如果你使用 Python** 是通过 Homebrew 安装的，还需要运行以下命令来确定找到必要的库文件\n\n        mkdir -p ~/Library/Python/2.7/lib/python/site-packages\n        echo '/usr/local/lib/python2.7/site-packages' > ~/Library/Python/2.7/lib/python/site-packages/homebrew.pth\n\n### 执行 ###\n1. 从 Streisand 抓取源码\n\n        git clone https://github.com/StreisandEffect/streisand.git && cd streisand\n2. 执行 Streisand 脚本。\n\n        ./streisand\n3. 根据实际情况从弹出的问题中填写或选择选项，比如服务器的物理位置，它的名字。还有最重要的是 API 信息（可以从问题提示中找到如何提供 API 信息）。\n4. 一旦登录信息和 API key 正确无误完成，Streisand 就开始安装到另一个 VPS 上了（或者把你目前的 VPS 变成网关）。\n5. 整个配置完成大概需要10分钟左右的样子，完成后，在 Streisand 目录下会生成一个 'generated-docs' 文件夹，里面储存了4个 html 文件，其中包含了网关的 SSL 证书和如何连接的详细说明。当你使用这些方法连接上网关以后，网关里详细描述了设置客户端的方法、需要额外下载的文件，客户端镜像，密钥，只要耐心配置客户端就一切搞定了。\n\n**译者注：到这里官方英文配置就告一段落了。译者在自己配置的过程中还遇到一些小麻烦，需要各位朋友注意。**\n* 从本地用 Streisand 安装到网关的模式，如果能用这种模式最好，就不要选择其他的模式了，因为这样他生成的 generated-docs 就在本地，你用浏览器打开就能直接下载到证书文件，不折腾。\n* 在 VPS 上用 Streisand 安装到新的 VPS 模式还有后面介绍的将正在运行的 VPS 转变为网关这种模式，你会发现你很难在 VPS 上阅读 generated-docs 文件夹中的4个 html 文档，这个时候有几种方法可选：\n  * 使用 sftp 下载文件；\n  * 在目前的 VPS 上安装一个 apache2 ，然后 cp -r generated-doc /var/www/html/ ，然后从浏览器输入 VPS 的地址直接浏览并下载密钥（严格地说，这不安全，因为不是 https 连接，如果截获了数据便可以知道如何登录你科学上网的那个网关了。**如果是使用转化那个模式，就不要用这种方法了**）。\n  * 在 VPS 上使用 scp 将 generated-docs 目录全部推送到你本地暴露在公网下的 Linux, Unix 或者 macOS 里，或者另一个 VPS 里也可以。命令大概是 scp -r generated-docs user@×××.×××.×××.×××:/home/user/\n\n### 将正在使用中的 VPS 变成 Streisand 服务器 （高级使用） ###\n\n如果你本地使用的计算机无法运行 Streisand ，你可以将正在运行的 VPS 转变为网关。只需要在 VPS 上运行 ./streisand 并在菜单中选择 \"Localhost (Advanced)\" 就可以了。\n\n**但是需要注意的是**这个操作是无法挽回的，它将把你正在使用的 VPS 完全转变为网关后，之前如果你在上面搭建博客或者用于测试某些软件，那完成这个操作后，它们将不复存在。\n\n### 在其他的 VPS 供应商上运行 （高级使用）###\n\n你同样可以将 Streisand 运行在其他 VPS 供应商（提供更好的硬件也没问题，奇葩的 VPS 供应商也行）的 16.04 Ubuntu 上，只需要你在运行 ./streisand 的时候选择菜单中的 \"Existing Server (Advanced)\" 就可以。你需要提供这个 VPS 的 IP 地址。\n\n这个 VPS 必须使用 `$HOME/.ssh/id_rsa` 来储存 SSH key，并且可以使用 **root** 作为默认用户登录 VPS，如果提供商没有给你 root 用户作为默认用户登录，而是别的用户名，比如：`ubuntu` ，那么在运行 `./streisand` 之前需要额外配置 `ANSIBLE_SSH_USER` 环境变量，比如修改为：`ANSIBLE_SSH_USER=ubuntu` 。\n\n### 非交互式部署 （高级使用）###\n\n如果你想做非交互式部署, 你可以在 `global_vars/noninteractive`找到配置文件和脚本文件。你需要在配置文件或命令行录入必要信息。\n\n将 Streisand 在 VPS 供应商上运行:\n\n      deploy/streisand-new-cloud-server.sh \\\n        --provider digitalocean \\\n        --site-config global_vars/noninteractive/digitalocean-site.yml\n\n将 Streisand 在正在使用中的服务器上运行:\n\n      deploy/streisand-local.sh \\\n        --site-config global_vars/noninteractive/local-site.yml\n\n将 Streisand 在已现有的服务器上运行 :\n\n      deploy/streisand-existing-cloud-server.sh \\\n        --ip-address 10.10.10.10 \\\n        --ssh-user root \\\n        --site-config global_vars/noninteractive/digitalocean-site.yml\n\n未来特性\n-----------------\n* 更简便的设置\n\n如果你对 Streisand 有任何期待和想法，或者你找到 BUG ，请联系我们并且发 [Issue Tracker](https://github.com/StreisandEffect/streisand/issues) 。\n\n核心的贡献者们\n----------------\n* Jay Carlson (@nopdotcom)\n* Nick Clarke (@nickolasclarke)\n* Joshua Lund (@jlund)\n* Ali Makki (@alimakki)\n* Daniel McCarney (@cpu)\n* Corban Raun (@CorbanR)\n\n相关知识\n----------------\n[Jason A. Donenfeld](https://www.zx2c4.com/) 凭借他的智慧和果敢重新设计一个现代的 VPN，就像我们看到的 [WireGuard](https://www.wireguard.com/) 。他非常耐心和认真的给予帮助并提供了优质的反馈，在此，向他表示我由衷的感谢。\n\n对 [Trevor Smith](https://github.com/trevorsmith) 在项目上的付出，简直无法形容，非常感谢他，正是他提出了网关的提案，提供了数不胜数反馈，在公布前灵机一动，创建了 html 模板，让现在的**一切看上去那么屌**。\n\n非常感谢 [Paul Wouters](https://nohats.ca/) 的 [The Libreswan Project](https://libreswan.org/) ，正是他的耐心调试和设置，才让 L2TP/IPsec 工作的那么好。\n\n另外，[Joshua Lund](https://github.com/jlund)开始这个项目工作的时候，他差不多把 [Starcadian's](https://www.starcadian.com/) 的 'Sunset Blood' 听了300遍（译者：这张专辑节奏感不错）。\n"
  },
  {
    "path": "README-fr.md",
    "content": "<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/jlund/streisand/master/logo.jpg\" alt=\"Automate the effect\"/> \n</p>\n\n- - -\n[English](README.md), [Français](README-fr.md), [简体中文](README-chs.md), [Русский](README-ru.md) | [Miroir](https://gitlab.com/alimakki/streisand)\n- - -\n\n[![Build Status](https://github.com/StreisandEffect/streisand/workflows/Streisand/badge.svg)](https://github.com/StreisandEffect/streisand/actions)\n[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/espadrine.svg?style=social&label=Follow%20%40StreisandVPN)](https://twitter.com/StreisandVPN)\n\nStreisand\n=========\n\n**Silence la censure. Automatiser [l'effet](https://fr.wikipedia.org/wiki/Effet_Streisand).**\n\nL'Internet peut être un peu injuste. Il est trop facile pour les fournisseurs de services Internet, les télécoms, les politiciens et les entreprises de bloquer l'accès aux sites et aux informations qui vous intéressent. Mais briser ces restrictions est *difficile*. Ou est-ce?\n\nPrésentation de Streisand\n-------------------------\n* Une seule commande configure un tout nouveau serveur Ubuntu 16.04 exécutant une [grande variété de logiciels anti-censure](#services-provided) qui peuvent masquer et chiffrer totalement votre trafic Internet.\n* Streisand supporte nativement la création de nouveaux serveurs chez [Amazon EC2](https://aws.amazon.com/ec2/), [Azure](https://azure.microsoft.com/fr-fr/), [DigitalOcean](https://www.digitalocean.com/), [Google Compute Engine](Https://cloud.google.com/compute/), [Linode](https://www.linode.com/) et [Rackspace](https://www.rackspace.com/)&mdash; et plus de fournisseurs à venir! Il fonctionne également sur n'importe quel serveur Ubuntu 16.04 quel que soit le fournisseur, et des **centaines** d'instances peuvent être configurés simultanément en utilisant cette méthode.\n* Le processus est entièrement automatisé et ne prend que quelques dizaines de minutes, ce qui est assez remarquable si vous considérez qu'il faudrait un administrateur système au moins plusieurs jours de contrainte pour mettre en place un petit sous-ensemble de ce que Streisand offre dans sa configuration.\n* Une fois que votre serveur Streisand est en cours d'exécution, vous pouvez donner les instructions de connexion personnalisée à vos amis, membres de la famille et activistes. Les instructions de connexion contiennent une copie intégrée du certificat SSL unique du serveur, il vous suffit de leur envoyer un seul fichier.\n* Chaque serveur est entièrement autonome et comprend tout ce dont les utilisateurs ont besoin pour démarrer, y compris les miroirs cryptographiquement vérifiés de tous les clients communs. Cela rend toute tentative de censure des emplacements de téléchargement par défaut complètement inefficace.\n* Mais attendez, il y a plus..\n\nPlus de fonctionnalités\n-----------------------\n* Nginx alimente la passerelle protégée par mot de passe et chiffrée qui sert de point de départ pour les nouveaux utilisateurs. La passerelle est accessible via SSL, ou comme [service caché](https://www.torproject.org/docs/hidden-services.html.en) Tor.\n  * Instructions belles, personnalisées, et étape par étape, les configurations du client sont générées pour chaque nouveau serveur que Streisand crée. Les utilisateurs peuvent accéder rapidement à ces instructions via n'importe quel navigateur Web. Les instructions sont réactives et fantastiques sur les téléphones mobiles.\n  * L'intégrité du logiciel mis en miroir est assurée en utilisant les sommes de contrôle SHA-256 ou en vérifiant les signatures GPG si le projet les fournit. Cela protège les utilisateurs contre le téléchargement de fichiers corrompus.\n  * Tous les fichiers auxiliaires, tels que les profils de configuration OpenVPN, sont également disponibles via la passerelle.\n  * Les utilisateurs actuels de Tor peuvent profiter des services supplémentaires que Streisand met en place pour transférer des fichiers volumineux ou pour traiter d'autres types de trafic (par exemple BitTorrent) qui ne sont pas appropriés pour le réseau Tor.\n  * Un mot de passe unique, un certificat SSL et une clé privée SSL sont générés pour chaque passerelle Streisand. Les instructions de la passerelle et le certificat sont transférés via SSH à la fin de l'exécution de Streisand.\n* Des services distincts et des daemons multiples offrent une énorme flexibilité. Si une méthode de connexion est bloquée, il existe de nombreuses options disponibles, dont la plupart sont résistantes à l'inspection des paquets en profondeur.\n  * Toutes les méthodes de connexion (y compris les connexions directes OpenVPN) sont efficaces contre le type de blocage avec lequel la Turquie a expérimenté.\n  * OpenConnect/AnyConnect, OpenSSH, OpenVPN (enveloppé dans stunnel), Shadowsocks, Tor (avec obfsproxy et obfs4 transports enfichables), et WireGuard sont tous actuellement efficace contre le grand pare-feu de la Chine.\n* Chaque tâche a été bien documentée et a donné une description détaillée. Streisand est simultanément le HOWTO le plus complet en existance pour l'installation de tous les logiciels qu'il installe, et aussi l'antidote pour avoir à faire jamais tout cela à la main de nouveau.\n* Tous les logiciels fonctionnent sur des ports qui ont été délibérément choisis pour rendre le blocage de ports simpliste irréaliste sans causer de dommages collatéraux massifs. OpenVPN, par exemple, ne fonctionne pas sur le port défaut de 1194, mais utilise le port standard 636 pour les connexions LDAP/SSL qui sont aimés par des entreprises du monde entier.\n\n<a name=\"services-provided\"></a>\nServices fournis\n----------------\n\n* [OpenSSH](https://www.openssh.com/)\n  * Les tunnels Windows et Android SSH sont également pris en charge et une copie des clés sont exportée dans le format .ppk que PuTTY requiert.\n  * [Tinyproxy](https://banu.com/tinyproxy/) est installé et lié à localhost. Il peut être accédé sur un tunnel SSH par des programmes qui ne prennent pas en charge nativement SOCKS et qui nécessitent un proxy HTTP, comme Twitter pour Android.\n  * Un utilisateur de transfert non privilégié et une paire paire de clés asymétriques SSH sont générés pour les fonctionnalités [sshuttle](https://github.com/sshuttle/sshuttle) et SOCKS.\n* [OpenConnect](https://ocserv.gitlab.io/www/index.html)/[Cisco AnyConnect](https://www.cisco.com/c/en/us/products/security/anyconnect-secure-mobility-client/index.html)\n  * OpenConnect (ocserv) est un serveur VPN extrêmement performant et léger qui offre également une compatibilité totale avec les clients officiels Cisco AnyConnect.\n  * Le [protocole](https://ocserv.gitlab.io/www/technical.html) est bâti sur des standards comme HTTP, TLS et DTLS, et c'est l'une des technologies VPN les plus populaires et largement utilisées parmi des grands entreprises multi-nationales.\n    * Cela signifie qu'en plus de sa facilité d'utilisation et de sa rapidité, OpenConnect est également très résistant à la censure et presque jamais bloqué.\n* [OpenVPN](https://openvpn.net/index.php/open-source.html)\n  * Des profils autonome \"unifiés\" .ovpn sont générés pour une configuration de client facile en utilisant un seul fichier.\n  * Les connexions TCP et UDP sont prises en charge.\n  * La résolution DNS du client est gérée via [Dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) pour empêcher les fuites DNS.\n  * L'authentification TLS est activée, ce qui permet de vous protéger contre les attaques actives. Le trafic qui n'a pas de HMAC approprié est simplement abandonné.\n* [Shadowsocks](https://shadowsocks.org/en/index.html)\n  * La [variante libev](https://github.com/shadowsocks/shadowsocks-libev) haute performance est installée. Cette version est capable de gérer des milliers de connexions simultanées.\n  * Un code QR est généré qui peut être utilisé pour configurer automatiquement les clients Android et iOS en prenant simplement une photo. Vous pouvez étiqueter \"8.8.8.8\" sur ce mur de béton, ou vous pouvez coller les instructions de Shadowsocks et quelques codes QR à la place!\n  * [AEAD](https://shadowsocks.org/fr/spec/AEAD-Ciphers.html) est activé avec ChaCha20 et Poly1305 pour un contournement plus efficace du GFW.\n  * Le plugin [simple-obfs](https://github.com/shadowsocks/simple-obfs) est installé afin de fournir une techique d'évasion du votre trafic sur des réseaux hostiles (en particulier ceux qui appliquent la limitation de la qualité de service (QOS)).\n* [sslh](https://www.rutschle.net/tech/sslh/README.html)\n  * Sslh est un démultiplexeur de protocole qui permet à Nginx, OpenSSH et OpenVPN de partager le port 443. Cela fournit une autre option de connexion et signifie que vous pouvez toujours acheminer le trafic via OpenSSH et OpenVPN même si vous êtes sur un réseau restrictif qui bloque tout accès à des ports non HTTP.\n* [Stunnel](https://www.stunnel.org/index.html)\n  * Écoute et enveloppe les connexions OpenVPN. Cela les fait ressembler au trafic SSL standard et permet aux clients OpenVPN d'établir avec succès des tunnels même en présence d'une inspection approfondie des paquets.\n  * Des profils unifiés pour les connexions OpenVPN enveloppées de stunnel sont générés à côté des profils de connexion directe. Des instructions détaillées sont également générées.\n  * Le certificat stunnel et la clé sont exportés au format PKCS # 12 afin qu'ils soient compatibles avec d'autres applications de tunneling SSL. Notamment, cela permet à [OpenVPN pour Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn&hl=fr) de tunneliser son trafic via [SSLDroid](https://play.google .com / store / apps / details? Id = hu.blint.ssldroid). OpenVPN en Chine sur un appareil mobile? Oui!\n* [Tor](https://www.torproject.org/)\n  * Un [pont relais](https://www.torproject.org/docs/bridges) est mis en place avec un surnom aléatoire.\n  * [Obfsproxy](https://www.torproject.org/projects/obfsproxy.html.en) est installé et configuré avec le support pour le transport enfichable obfs4.\n  * Un code BridgeQR est généré et peut être utilisé pour configurer automatiquement [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android&hl=fr) pour Android.\n* [UFW](https://wiki.ubuntu.com/UncomplicatedFirewall)\n  * Les règles de pare-feu sont configurées pour chaque service et tout trafic qui est envoyé vers un port non autorisé sera bloqué.\n* [unattended-upgrades](https://help.ubuntu.com/community/AutomaticSecurityUpdates)\n  * Votre serveur Streisand est configuré pour installer automatiquement de nouvelles mises à jour de sécurité.\n* [WireGuard](https://www.wireguard.com/)\n  * Les utilisateurs Linux peuvent profiter d'un VPN de nouvelle génération qui est simple mais à la même fois moderne, basé dans le noyau, et utilise des principes cryptographiques modernes que toutes les autres solutions VPN ne fournissent pas.\n\nInstallation\n------------\nVeuillez lire *attentivement* toutes les instructions d'installation avant de poursuivre.\n\n### Clarification importante ###\nStreisand est basé sur [Ansible](https://www.ansible.com/), un outil d'automatisation qui est généralement utilisé pour fournir et configurer des fichiers et des paquets sur des serveurs distants. Cela signifie que lorsque vous exécutez Streisand, il configure automatiquement **un autre serveur distant** avec les paquets VPN et ses configurations.\n\nStreisand va déployer **un autre serveur** sur votre fournisseur d'hébergement choisi lorsque vous exécutez **sur votre ordinateur local** (par exemple, votre ordinateur portable). Habituellement, vous **n'utilisez pas Streisand sur le serveur distant** car, par défaut, cela entraînerait le déploiement d'un autre serveur à partir de votre serveur et rendrait le premier serveur redondant (Ouf!).\n\nDans certains cas, les utilisateurs avancés peuvent opter pour le mode de provisionnement local pour que le système fonctionne avec Streisand/Ansible se configure comme un serveur Streisand. Il s'agit d'un mode de configuration mieux réservé quand ce n'est pas possible d'installer Ansible sur votre ordinateur local ou lorsque votre connexion à un fournisseur de cloud est peu fiable pour les connexions SSH requis par Ansible.\n\n### Prérequis ###\nEffectuez toutes ces tâches sur votre machine locale.\n\n* Streisand nécessite un système BSD, Linux ou macOS. À partir de maintenant, Windows n'est pas soutenu. Toutes les commandes suivantes doivent être exécutées à l'intérieur d'une session Terminal.\n* Python 2.7 est nécessaire. Cela est standard sur macOS, et est la valeur par défaut sur presque toutes les distributions Linux et BSD. Si votre distribution emploie Python 3 à la place, vous devrez installer la version 2.7 pour que Streisand fonctionne correctement.\n* Assurez-vous qu'une clé publique SSH est présente dans ~/.ssh/id\\_rsa.pub.\n  * Les clés SSH constituent une alternative plus sécurisé aux mots de passe qui vous permettent de prouver votre identité à un serveur ou à un service basé sur la cryptographie à clé publique. Fondamentalement, la clé publique est quelque chose que vous pouvez partager aux autres, alors que la clé privée doit être gardée secrète (comme un mot de passe).\n  * Pour vérifier si vous avez déjà une clé publique SSH, entrez la commande suivante à l'invite de commande.\n\n        ls ~/.ssh\n  * Si vous voyez un fichier id_rsa.pub, vous avez une clé publique SSH.\n  * Si vous n'avez pas de paire de clés SSH, vous pouvez en générer une en utilisant cette commande et en suivant les valeurs par défaut:\n\n        ssh-keygen\n  * Si vous souhaitez utiliser une clé SSH avec un nom différent ou dans un emplacement non standard, veuillez entrer 'oui' lorsqu'on vous demande si vous souhaitez personnaliser votre instance lors de l'installation.\n  * **Notez**: Vous aurez besoin de ces clés pour accéder à votre instance Streisand via SSH. Conservez-les pour la durée de vie de votre serveur Streisand.\n* Installez Git.\n  * Sur Debian et Ubuntu\n\n            sudo apt-get install git\n  * Sur Fedora 27, certains progiciels sont nécessaires plus tard\n\n          sudo dnf install git python2-pip gcc python2-devel python2-crypto python2-pycurl libcurl-devel\n  * Sur CentOS 7, `pip` est disponible dans le dépôt EPEL; certains progiciels supplémentaires sont nécessaires plus tard.\n\n          sudo yum -y update && sudo yum install -y epel-release\n          sudo yum -y update && sudo yum install -y git gcc python-devel python-crypto python-pycurl python-pip libcurl-devel\n  * Sur macOS, `git` fait partie des outils de développement et sera installé la première fois que vous l'exécuterez. S'il n'y a pas déjà une commande `pip` installée, installez-la avec:\n\n         sudo python2.7 -m ensurepip\n\n### Exécution ###\n1. Clonez le répertoire Streisand et entrez dans le répertoire.\n\n        git clone https://github.com/StreisandEffect/streisand.git && cd streisand\n\n2. Exécutez le programme d'installation pour Ansible et ses dépendances.\n\n        ./util/venv-dependencies.sh ./venv\n    * Le programme d'installation détectera les progiciels manquants et imprimera les commandes nécessaires pour les installer.\n\n3. Activez les progciels Ansible installés.\n\n        source ./venv/bin/activate\n      \n4. Exécutez le script Streisand.\n\n        ./streisand\n5. Suivez les instructions pour choisir votre fournisseur, la région physique du serveur, et son nom. Vous serez également invité à entrer les informations de l'API.\n6. Une fois les informations de connexion et les clés d'API saisies, Streisand commencera à faire tourner un nouveau serveur distant.\n5. Attendez que l'installation soit terminée (cela prend habituellement environ dix minutes) et recherchez les fichiers correspondants dans le dossier 'generated-docs' dans le répertoire du dépôt Streisand. Le fichier HTML expliquera comment se connecter à la passerelle via SSL ou via le service caché Tor. Toutes les instructions, les fichiers, les clients en miroir et les clés du nouveau serveur se trouvent alors sur la passerelle. Vous avez fini!\n\n### Installation de Streisand sur localhost (Avancé) ###\n\nSi vous ne pouvez pas exécuter Streisand de la manière normale (à partir de votre ordinateur client/ordinateur portable pour configurer un serveur distant), Streisand prend en charge un mode de provisionnement local. Choisissez simplement \"Localhost (Advanced)\" dans le menu après avoir exécuté `./streisand`.\n\n**Note:** L'installation de Streisand sur localhost peut être une action destructive! Vous pourriez potentiellement écraser des fichiers de configuration; vous devez être certain que vous affectez la machine correcte.\n\n### Exécution de Streisand sur d'autres fournisseurs (Avancé) ###\n\nVous pouvez également exécuter Streisand sur un nouveau serveur Ubuntu 16.04. Serveur dédié? Génial! Fournisseur de cloud ésotérique? Fantastique! Pour ce faire, choisissez simplement `Existing server (Advanced)` dans le menu après avoir exécuté `./streisand` et fournissez l'adresse IP du serveur existant lorsque vous y êtes invité.\n\nLe serveur doit être accessible en utilisant la clé SSH `$HOME/.ssh/id_rsa`, avec **root** comme utilisateur de connexion par défaut. Si votre fournisseur vous demande un utilisateur SSH au lieu de `root` (par exemple, `ubuntu`), spécifiez la variable environnementale `ANSIBLE_SSH_USER` (par exemple `ANSIBLE_SSH_USER=ubuntu`) lorsque vous exécutez `./streisand`.\n\n**Note:** L'installation de Streisand sur localhost peut être une action destructive! Vous pourriez potentiellement écraser des fichiers de configuration; vous devez être certain que vous affectez la machine correcte.\n\n### Déploiement non interactif (Avancé) ###\n\nDes scripts alternatifs et des exemples de fichiers de configuration sont fournis pour les déploiements non interactifs, dans lequel toutes les informations requises sont transmises sur la ligne de commande ou dans un fichier de configuration.\n\nDes exemples de fichiers de configuration se trouvent sous `global_vars/noninteractive`. Copiez et modifiez les paramètres souhaités, tels que la fourniture de jetons d'API et d'autres choix, puis exécutez le script.\n\nPour déployer un nouveau serveur Streisand:\n\n      deploy/streisand-new-cloud-server.sh \\\n        --provider digitalocean \\\n        --site-config global_vars/noninteractive/digitalocean-site.yml\n\nPour exécuter l'approvisionnement Streisand sur la machine locale:\n\n      deploy/streisand-local.sh \\\n        --site-config global_vars/noninteractive/local-site.yml\n\nPour exécuter l'approvisionnement Streisand contre un serveur existant:\n\n      deploy/streisand-existing-cloud-server.sh \\\n        --ip-address 10.10.10.10 \\\n        --ssh-user root \\\n        --site-config global_vars/noninteractive/digitalocean-site.yml\n\nNouvelles fonctionnalités à venir\n---------------------------------\n* Configuration simplifiée.\n\nS'il ya quelque chose que vous pensez que Streisand devrait faire, ou si vous trouviez un bug dans sa documentation ou son exécution, s'il vous plaît déposer un rapport sur le [Issue Tracker](https://github.com/StreisandEffect/streisand/issues).\n\nContributeurs principaux\n------------------------\n* Jay Carlson (@nopdotcom)\n* Nick Clarke (@nickolasclarke)\n* Joshua Lund (@jlund)\n* Ali Makki (@alimakki)\n* Daniel McCarney (@cpu)\n* Corban Raun (@CorbanR)\n\nRemerciements\n-------------\n[Jason A. Donenfeld](https://www.zx2c4.com/) mérite beaucoup de crédit pour être assez courageux à réimaginer ce qu'est un VPN moderne devrait ressembler et pour mettre au monde quelque chose aussi épatant que [WireGuard](https://www.wireguard.com/). Il a nos sincères remerciements pour toute son aide, patience et ses commentaires.\n\n[Corban Raun](https://github.com/CorbanR) à eu la gentillesse de me prêter un ordinateur portable Windows qui m'a permi de tester et d'affiner les instructions pour cette plate-forme, aussi bien qu'il était un grand partisan du projet dès le début.\n\nNous sommes reconnaissants à [Trevor Smith](https://github.com/trevorsmith) pour ses contributions massives au projet. Il a suggéré l'approche passerelle, fourni des tonnes de commentaires inestimable, a fait *tout* pour apparaître mieux, et développé le modèle HTML qui a servi d'inspiration pour faire passer les choses au niveau suivant avant la diffusion publique de Streisand. J'ai également apprécié l'utilisation fréquente de son iPhone tout en testant des clients divers.\n\nUn grand merci à [Paul Wouters](https://nohats.ca/) de [The Libreswan Projet](https://libreswan.org/) à son aide généreuse pour le débogage des configurations d'L2TP/IPsec.\n\nL'album 'Sunset Blood' de [Starcadian](https://starcadian.com/) a été répété environ 300 fois au cours des premiers mois de travail sur le projet au début de 2014.\n"
  },
  {
    "path": "README-ru.md",
    "content": "<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/jlund/streisand/master/logo.jpg\" alt=\"Automate the effect\"/>\n</p>\n\n- - -\n[English](README.md), [Français](README-fr.md), [简体中文](README-chs.md), [Русский](README-ru.md) | [Зеркало](https://gitlab.com/alimakki/streisand)\n- - -\n\n[![Build Status](https://github.com/StreisandEffect/streisand/workflows/Streisand/badge.svg)](https://github.com/StreisandEffect/streisand/actions)\n[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/espadrine.svg?style=social&label=Follow%20%40StreisandVPN)](https://twitter.com/StreisandVPN)\n\nСтрейзанд\n=========\n\n**Заставьте цензуру замолчать. Автоматизируйте [эффект Стрейзанд](https://ru.wikipedia.org/wiki/Эффект_Стрейзанд).**\n\nИнтернет может быть немножечко несправедливым. Провайдерам, телекоммуникационным гигантам, политикам и корпорациям слишком просто блокировать доступ к сайтам и информации, которая важна для вас. Но преодолеть эти ограничения сложно. Или нет?\n\nПредставляем Стрейзанд\n---------------------\n* Одна-единственная команда настраивает с нуля сервер под операционной системой Ubuntu 16.04 с большим набором [ПО для противодействия цензуре](#services-provided), который может полностью скрыть и зашифровать весь ваш трафик.\n* Стрейзанд поддерживает создание новых серверов в [Amazon EC2](https://aws.amazon.com/ec2/), [Azure](https://azure.microsoft.com), [DigitalOcean](https://www.digitalocean.com/), [Google Compute Engine](https://cloud.google.com/compute/), [Linode](https://www.linode.com/), и [Rackspace](https://www.rackspace.com/). В скором времени ожидается поддержка также и других облачных хостеров. Стрейзанд также можно запускать на любом сервере с операционной системой Ubuntu 16.04 вне зависимости от хостера, и **сотни** серверов могут быть одновременно сконфигурированы с применением этого метода.\n* Процесс полностью автоматизирован и занимает примерно десять минут, что довольно круто, учитывая что среднему системному администратору требуется несколько дней возни, для того, чтобы настроить малую часть того, что Стрейзанд предлагает \"из коробки\".\n* После того, как ваш сервер Стрейзанд запущен, вы можете раздать инструкции по подключению друзьям, членам семьи и соратникам. Инструкции по подключению содержат в себе копию SSL-сертификата, уникального для каждого сервера, так что вам нужно послать им всего один файл.\n* Каждый сервер полностью самодостаточен и содержит абсолютно всё, что нужно для того, чтобы начать использовать Стрейзанд, включая криптографически верифицированные копии основного клиентского ПО. Это позволяет обойти попытки подвергнуть цензуре соответствующее ПО.\n* Но это еще не всё...\n\nДополнительные особенности\n-------------\n* Nginx поддерживает защищённый паролем и зашифрованный Портал, который служит отправной точкой для новых пользователей. Портал доступен с ипользованием SSL или через [скрытые сервисы](https://www.torproject.org/docs/hidden-services.html.en) Tor.\n  * Стрейзанд генерирует замечательные, персонализированные пошаговые инструкции по подключению для пользователей. Пользователи могут легко получить доступ к этим инструкциям через любой веб браузер. Инструкции также отлично выглядят на мобильных телефонах.\n  * Неизменность копий программного обеспечения подтверждена с помощью контрольных сумм SHA-256 или с использованием криптографических подписей GPG, если конкретный проект их предоставляет. Это предотвращает загрузку испорченных файлов.\n  * Все дополнительные файлы, такие как конфигурационные профили OpenVPN также доступны через Портал.\n  * Пользователи Tor могут также пользоваться дополнительными сервисами, устанавливаемыми Стрейзанд, для передачи больших файлов или для использования видов трафика (например BitTorrent), для которых Tor изначально не предназначен.\n  * Для каждого шлюза Стрейзанд создается уникальный пароль, SSL-сертификат и приватный ключ SSL. Инструкции и сертификат передаются через SSH в конце выполнения Стрейзанд.\n* Отдельные сервисы и множество демонов предоставляют впечатляющую гибкость. Если один из методов будет заблокирован, множество других остается доступными и большая часть из них устойчива к Deep Packet Inspection (DPI).\n  * Все методы подключения (включая прямые соединения OpenVPN) эффективны против методов блокировки, с которыми экспериментирует Турция.\n  * OpenConnect/AnyConnect, OpenSSH, OpenVPN (завернутый в stunnel), Shadowsocks, Tor (с obfsproxy и подключаемым транспортом obfs4 ) и WireGuard эффективны против Великого Китайского Файрволла.\n* Каждая задача тщательно документирована и снабжена детальным описанием. Стрейзанд одновременно является самым полным HOWTO об установке всего ПО, которое он включается и является страховкой от установки всего этого руками.\n* Всё ПО сознательно использует порты так, чтобы сделать простое блокирование портов невозможным без нанесения блокирующей стороной значительного сопутствующего ущерба. К примеру, OpenVPN использует не порт по умолчанию 1194, а 636, стандартный порт для LDAP/SSL соединений, часто используемый компаниями во всем мире.\n\n<a name=\"services-provided\"></a>\nПредоставляемые сервисы\n-----------------\n\n* [OpenSSH](https://www.openssh.com/)\n  * Создается непривилегированный пользователь и пара ключей для [sshuttle](https://github.com/sshuttle/sshuttle) и SOCKS.\n  * Поддерживаются также SSH-туннели Windows и Android, создается копия пары ключей в .ppk формате для PuTTY\n  * Установлен [Tinyproxy](https://banu.com/tinyproxy/) и подключен к localhost. Программы, которые не поддерживают SOCKS и требуют наличия HTTP proxy, такие как Twitter для Android, могу подключиться к нему через SSH-туннель.\n* [OpenConnect](https://ocserv.gitlab.io/www/index.html) / [Cisco AnyConnect](https://www.cisco.com/c/en/us/products/security/anyconnect-secure-mobility-client/index.html)\n  * OpenConnect (ocserv) - высокопроизводительный и легковесный VPN-сервер полностью совместимый с официальными клиентами Cisco AnyConnect.\n  * Его [протокол](https://ocserv.gitlab.io/www/technical.html) построен на классических стандартах, таких как HTTP, TLS и  DTLS и является одним из самых популярных и широко используемых мультинациональными корпорациями VPN технологий.\n    * Это означает, что кроме своей простоты и скорости, OpenConnect также устойчив к цензуре и практически никогда не блокируется.\n* [OpenVPN](https://openvpn.net/index.php/open-source.html)\n  * Для каждого клиента создаются унифицированные .ovpn профили для простой настройки клиента с использованием только одного файла.\n  * Поддерживаются соединения TCP и UDP.\n  * Определение адресов для клиента исползует [Dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) для предотвращения утечек DNS-запросов.\n   *  Включена TLS Authentication для защиты от зондирующих атак. Трафик не имеющий корректного HMAC будет попросту проигнорирован.\n* [Shadowsocks](https://shadowsocks.org/en/index.html)\n  * Установлен высокопроизводительный [вариант libev](https://github.com/shadowsocks/shadowsocks-libev). Эта версия обрабатывает тысячи одновременных соединений.\n  * Создается QR код который можно использовать для автоматической настройки Android и iOS клиентов. Вы можете написать '8.8.8.8' на бетонной стене, или вы можете наклеить инструкции для Shadowsocks и QR коды на ту же стену.\n  * Включена поддержка [AEAD](https://shadowsocks.org/en/spec/AEAD-Ciphers.html) с ChaCha20 и Poly1305 для усиленной безопасности и уклонения от GFW.\n* [sslh](https://www.rutschle.net/tech/sslh/README.html)\n  * Sslh - демультиплексор протоколов, позволяющий Nginx, OpenSSH и  OpenVPN совместно использовать порт 443. Это предоставляет альтернативный метод подключения и означает, что вы можете перенаправлять трафик через OpenSSH и OpenVPN даже если вы находитесь в сети с очень строгими правилами, которая блокирует все соединения не с HTTP.\n* [Stunnel](https://www.stunnel.org/index.html)\n  * Слушает и упаковывает соединения OpenVPN. Это заставляет их выглядеть как стандартный SSL трафик и позволяет OpenVPN клиентам устанавливать туннели даже в случае использования Deep Packet Inspection.\n  * Создаются как профили для прямых соединений, так и унифицированные профили для соединений OpenVPN через stunnel. И подробные инструкции тоже.\n  * Сертификат stunnel и ключ экспортируются в формате PKCS #12 для совместимости с другими приложениями для туннелирования SSL. В частности , это позволяет [OpenVPN for Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn) туннелировать свой трафик через [SSLDroid](https://play.google.com/store/apps/details?id=hu.blint.ssldroid). OpenVPN в Китае на мобильном устройстве? Да!\n* [Tor](https://www.torproject.org/)\n  * Настроен  [bridge relay](https://www.torproject.org/docs/bridges) со случайно сгенерированным именем.\n  * Установлен [Obfsproxy](https://www.torproject.org/projects/obfsproxy.html.en) и настроен с поддержкой подключаемого транспорта obfs4.\n  * Сгенерирован код BridgeQR для автоматического конфигурирования [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android) для Android.\n* [UFW](https://wiki.ubuntu.com/UncomplicatedFirewall)\n  * Для каждого сервиса настроены правила файрвола, так что любой трафик отправленный на запрещенный порт будет заблокирован.\n* [unattended-upgrades](https://help.ubuntu.com/community/AutomaticSecurityUpdates)\n  * Ваш Стрейзанд сервер настроен для автоматической установки обновлений, связанных с безопасностью.\n* [WireGuard](https://www.wireguard.io/)\n  * Пользователи Linux могут насладиться простым и прекрасным VPN, который также является сказочно быстрым и использует современные криптографические принципы, отсутствующие в других высокоскоростных VPN решениях\n\nУстановка\n------------\nПожалуйста, **внимательно** прочитайте инструкции по установке перед тем, как продолжать.\n\n### Важное разъяснение ###\nСтрейзанд основан на [Ansible](https://www.ansible.com/), инструменте автоматизации, который обычно используется для установки и настройки файлов и пакетов на удалённых серверах. Стрейзанд автоматически создает **новый удалённый сервер** с пакетами и конфигурационными файлами VPN.\n\nКогда вы запустите Стрейзанд **на вашей домашней машине** (например на вашем лэптопе), он создаст и запустит **новый отдельный сервер** у хостера по вашему выбору. Обычно, вам **не надо запускать Стрейзанд на удалённом сервере** , так как по умолчанию это приведет к созданию нового сервера с вашего текущего сервера и первый сервер будет излишним.  (фух!).\n\nПри некоторых обстоятельствах продвинутые пользователи могут воспользоваться локальным методом настройки чтобы настроить сервер Стрейзанд на той же машине, где запущен Стрейзанд/Ansible. Этот способ конфигурации стоит использовать для ситуаций когда вы не можете установить Ansible на вашем домашнем компьютере или когда ваше соединение с облачным хостером слишком ненадежно для работы Ansible.\n\n### Необходимые условия ###\nВыполните все указанные ниже шаги на вашем домашнем компьютере.\n\n* Стрейзанд требует BSD, Linux или macOS. На текущий момент Windows не поддерживается. Все указанные ниже команды должны выполняться в терминале.\n* Требуется наличие Python 2.7. Он присутствует в стандартной поставке macOS и практически во всех Linux и BSD дистрибутивах. Если в вашем дистрибутиве установлен Python 3, вам потребуется также установить Python 2.7 , чтобы  Стрейзанд работал нормально.\n* Убедитесь, что открытый SSH ключ присутствует в файле ~/.ssh/id\\_rsa.pub.\n  * SSH ключи - это более защищенная альтернатива паролям, позволяющая подтвердить вашу личность на сервере или службе, построенной на криптографии с открытым ключом. Открытый ключ вы можете передавать другим, в то время как закрытый ключ должен храниться в тайне (так же как пароль).\n  * Для того, чтобы проверить, есть ли у вас открытый SSH ключ, введите следущую комманду:\n\n        ls ~/.ssh\n  * Если вы видите файл id\\_rsa.pub, значит у вас есть открытый SSH ключ.\n  * Если у вас нет пары SSH ключей, вы можете ее сгенерировать с использованием следующей команды и выбирая значения по умолчанию:\n\n        ssh-keygen\n  * Если вы хотите использовать SSH ключи с другим именем или в другом местоположении, введите 'yes' когда установщик спросит хотите ли вы настроить сервер.\n  * **Обратите внимание**: Эти ключи будут вам нужны для доступа к серверу Стрейзанд по SSH. Пожалуйста, сохраняйте их на протяжении всей жизни сервера.\n* Установите Git.\n  * На Debian и Ubuntu\n\n        sudo apt-get install git\n  * На Fedora\n\n        sudo dnf install git\n  * На macOS (с использованием [Homebrew](https://brew.sh/))\n\n        brew install git\n* Установите  [pip](https://pip.pypa.io/en/latest/) - систему управления пакетами для Python.\n  * На Debian и Ubuntu (также устанавливает зависимости. необходимые для сборки Ansible и работы некоторых других модулей)\n\n        sudo apt-get install python-paramiko python-pip python-pycurl python-dev build-essential\n  * На Fedora\n\n        sudo dnf install python-pip\n  * На macOS\n\n        sudo easy_install pip\n        sudo pip install pycurl\n\n* Установите [Ansible](https://www.ansible.com/).\n  * На macOS (с использованием [Homebrew](http://brew.sh/))\n\n        brew install ansible\n  * На BSD или Linux (с использованием pip)\n\n        sudo pip install ansible markupsafe\n* Установите необходимые библиотеки Python для вашего облачного хостера. Если вы настраиваете локальный или существующий сервер, вы можете пропустить этот шаг.\n  * Amazon EC2\n\n        sudo pip install boto boto3\n  * Azure\n\n        sudo pip install ansible[azure]\n  * Google\n\n        sudo pip install \"apache-libcloud>=1.17.0\"\n\n  * Linode\n\n        sudo pip install linode-api4\n  * Rackspace Cloud\n\n        sudo pip install pyrax\n  * **Важное замечание: если вы используете Python , установленный через  Homebrew** то вы должны также выполнить следующие команды чтобы быть уверенным, что Python сможет найти необходимые библиотеки:\n\n        mkdir -p ~/Library/Python/2.7/lib/python/site-packages\n        echo '/usr/local/lib/python2.7/site-packages' > ~/Library/Python/2.7/lib/python/site-packages/homebrew.pth\n\n### Выполнение ###\n1. Склонируйте репозиторий Стрейзанд и перейдите в директорию\n\n       git clone https://github.com/StreisandEffect/streisand.git && cd streisand\n2. Запустите скрипт Стрейзанд.\n\n       ./streisand\n3. Следуйте инструкциям для выбора вашего хостера, региона, где будет запущен сервер и его имени. Вам также потребуется ввести информацию об API.\n4. После того, как логины и API ключи предоставлены, Стрейзанд начинает создавать новый удалённый сервер.\n5. Подождите, пока установка будет завершена (это обычно занимает примерно десять минут) и вы найдете файл в папке 'generated-docs' в директории репозитория Стрейзанд. HTML файл содержит инструкции как подключиться к шлюзу через SSL или через Tor. Все инструкции, файлы, копии клиентского ПО и ключ для нового сервера расположены на портале. Всё готово!\n\n### Использование Стрейзанд для настройки локального сервера (Для продвинутых) ###\n\nДля случаев, когда вы не можете запустить Стрейзанд как обычно (с вашего домашнего компьютера или лэптопа), с тем, чтобы сконфигурировать удалённый сервер, Стрейзанд поддерживает локальный метод настройки. Просто выберите  \"Localhost (Advanced)\" из меню, после того, как запустили `./streisand`.\n\n**Замечание:** Запуск Стрейзанд для настройки локального сервера может что-нибудь испортить. Возможно, вы перезапишете конфигурационные файлы, поэтому будьте уверены, что вы настраиваете правильный сервер.\n\n### Использование Стрейзанд для других хостеров (Для продвинутых) ###\n\nВы также можете запустить Стрейзанд на любом сервере Ubuntu 16.04. Выделенный сервер? Отлично! Странный облачный хостер? Замечательно! Чтобы это сделать, просто выберите\n\"Existing Server (Advanced)\" из меню после запуска `./streisand` и введите IP адрес существующего сервера , когда скрипт запросит эти данные.\n\nЭтот сервер должен разрешать подключение с SSH-ключом `$HOME/.ssh/id_rsa` и по умолчанию для подключения будет использоваться пользователь **root**. Если ваш хостер требует, чтобы для подключения использовался какой-то другой пользователь (например `ubuntu`), установите переменную среды `ANSIBLE_SSH_USER` (например `ANSIBLE_SSH_USER=ubuntu` ) перед запуском `./streisand`.\n\n**Замечание:** Запуск Стрейзанд для настройки существующего сервера может что-нибудь испортить. Возможно, вы перезапишете конфигурационные файлы, поэтому будьте уверены, что вы настраиваете правильный сервер.\n\nБудущие возможности\n-------------------\n* Более простая установка.\n\nЕсли у вас есть идея, что ещё может делать Стрейзанд или вы нашли баг в документации или коде, пожалуйста, оставьте сообщение в [Issue Tracker](https://github.com/StreisandEffect/streisand/issues).\n\nКлючевые разработчики\n---------------------\n* Jay Carlson (@nopdotcom)\n* Nick Clarke (@nickolasclarke)\n* Joshua Lund (@jlund)\n* Ali Makki (@alimakki)\n* Daniel McCarney (@cpu)\n* Corban Raun (@CorbanR)\n\nБлагодарности\n-------------\n[Jason A. Donenfeld](https://www.zx2c4.com/) заслуживает множество благодарностей за смелое представление о том, как может выглядеть современный VPN и за то, что он создал такую отличную штуку как  [WireGuard](https://www.wireguard.io/). Искреннее спасибо за его терпеливую помощь и отличную обратную связь.\n\nМы благодарны [Trevor Smith](https://github.com/trevorsmith) за его огромный вклад в проект. Он предложил подход с использованием портала, дал множество бесценных комментариев. С его помощью *всё* стало выглядеть лучше, он создал шаблон HTML, который вдохновил меня поднять всё на новый уровень перед официальным запуском.\n\nОгромное спасибо  [Paul Wouters](https://nohats.ca/) из [The Libreswan Project](https://libreswan.org/) за его великодушную помощь в отладке инсталляции  L2TP/IPsec.\n\nАльбом 'Sunset Blood' группы [Starcadian's](https://www.starcadian.com/) был прослушан примерно 300 раз в цикле в течение первых месяцев работы над этим проектом в начале 2014 года.\n"
  },
  {
    "path": "README.md",
    "content": "# Streisand\n\n<p align=\"center\">\n<img src=\"https://raw.githubusercontent.com/jlund/streisand/master/logo.jpg\" alt=\"Automate the effect\"/> \n</p>\n\n- - -\n[English](README.md), [Français](README-fr.md), [简体中文](README-chs.md), [Русский](README-ru.md) | [Mirror](https://gitlab.com/alimakki/streisand)\n- - -\n\n[![Build Status](https://github.com/StreisandEffect/streisand/workflows/Streisand/badge.svg)](https://github.com/StreisandEffect/streisand/actions)\n[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/espadrine.svg?style=social&label=Follow%20%40StreisandVPN)](https://twitter.com/StreisandVPN)\n\nStreisand\n=========\n\n**Silence censorship. Automate the [effect](https://en.wikipedia.org/wiki/Streisand_effect).**\n\nThe Internet can be a little unfair. It's way too easy for ISPs, telecoms, politicians, and corporations to block access to the sites and information that you care about. But breaking through these restrictions is *tough*. Or is it?\n\nIf you have an account with a cloud computing provider, Streisand can set up a new node with many censorship-resistant VPN services nearly automatically. You'll need a little experience with a Unix command-line. (But without Streisand, it could take days for a skilled Unix administrator to configure these services securely!) At the end, you'll have a private website with software and instructions.\n\nHere's what **[a sample Streisand server](http://streisandeffect-demo.s3-website.us-east-2.amazonaws.com/)** looks like.\n\n\nThere's a [list of supported cloud providers](#cloud-providers); experts may be able to use Streisand to install on many other cloud providers.\n\n## VPN services\n\nOne type of tool that people use to avoid network censorship is a Virtual Private Network (VPN). There are many kinds of VPNs.\n\nNot all network censorship is alike; in some places, it changes from day to day. Streisand provides many different VPN services to try. (You don't have to install them all, though.)\n\nSome Streisand services include add-ons for further censorship and throttling resistance:\n\n* [OpenSSH](https://www.openssh.com/)\n    * [Tinyproxy](https://banu.com/tinyproxy/) may be used as an HTTP proxy.\n* [OpenConnect](https://ocserv.gitlab.io/www/index.html) / [Cisco AnyConnect](https://www.cisco.com/c/en/us/products/security/anyconnect-secure-mobility-client/index.html)\n    * This protocol is widely used by multi-national corporations, and might not be blocked.\n* [OpenVPN](https://openvpn.net/index.php/open-source.html)\n    * [Stunnel](https://www.stunnel.org/index.html) add-on available.\n* [Shadowsocks](https://shadowsocks.org/en/index.html), \n    * The [V2ray-plugin](https://github.com/shadowsocks/v2ray-plugin) is installed to provide robust traffic evasion on hostile networks (especially those implementing quality of service (QOS) throttling).\n* A private [Tor](https://www.torproject.org/) bridge relay\n    * [Obfsproxy](https://www.torproject.org/projects/obfsproxy.html.en) with obfs4 available as an add-on.\n* [WireGuard](https://www.wireguard.com/), a modern high-performance protocol.\n\nSee also:\n* A [more technical list of features](Features.md) \n* A [more technical list of services](Services.md)\n\n<a id=\"cloud-providers\"></a>\n## Cloud providers\n* Amazon Web Services (AWS)\n* Microsoft Azure\n* Digital Ocean\n* Google Compute Engine (GCE)\n* Linode\n* Rackspace\n\n\n#### Other providers\nWe recommend using one of the above providers. If you are an expert and can set up a *fresh Ubuntu 16.04 server* elsewhere, there are \"localhost\" and \"existing remote server\" installation methods. For more information, see [the advanced installation instructions](Advanced%20installation.md).\n\n## Installation\n\nYou need command-line access to a Unix system. You can use Linux, BSD, or macOS; on Windows 10, the Windows Subsystem for Linux (WSL) counts as Linux. \n\nOnce you're ready, see the [full installation instructions](Installation.md).\n\n\n## Things we want to do better\n\nAside from a good deal of cleanup, we could really use:\n\n* Easier setup.\n* Faster adoption of new censorship-avoidance tools\n\nWe're looking for help with both.\n\nIf there is something that you think Streisand should do, or if you find a bug in its documentation or execution, please file a report on the [Issue Tracker](https://github.com/StreisandEffect/streisand/issues).\n\nCore Contributors\n----------------\n* Jay Carlson (@nopdotcom)\n* Nick Clarke (@nickolasclarke)\n* Joshua Lund (@jlund)\n* Ali Makki (@alimakki)\n* Daniel McCarney (@cpu)\n* Corban Raun (@CorbanR)\n\nAcknowledgements\n----------------\n[Jason A. Donenfeld](https://www.zx2c4.com/) deserves a lot of credit for being brave enough to reimagine what a modern VPN should look like and for coming up with something as good as [WireGuard](https://www.wireguard.com/). He has our sincere thanks for all of his patient help and high-quality feedback.\n\nWe are grateful to [Trevor Smith](https://github.com/trevorsmith) for his massive contributions. He suggested the Gateway approach, provided tons of invaluable feedback, made *everything* look better, and developed the HTML template that served as the inspiration to take things to the next level before Streisand's public release.\n\nHuge thanks to [Paul Wouters](https://nohats.ca/) of [The Libreswan Project](https://libreswan.org/) for his generous help troubleshooting the L2TP/IPsec setup.\n\n[Starcadian's](https://www.starcadian.com/) 'Sunset Blood' album was played on repeat approximately 300 times during the first few months of work on the project in early 2014.\n"
  },
  {
    "path": "Services.md",
    "content": "# Services\n\nServices Provided\n-----------------\n\n* [OpenSSH](https://www.openssh.com/)\n  * Windows and Android SSH tunnels are also supported, and a copy of the keypair is exported in the `.ppk` format that PuTTY requires.\n  * [Tinyproxy](https://tinyproxy.github.io/) can be installed and bound to localhost. It can be accessed over an SSH tunnel by programs that do not natively support SOCKS and that require an HTTP proxy, such as Twitter for Android.\n  * An unprivileged forwarding user and SSH keypair can be generated for [sshuttle](https://github.com/sshuttle/sshuttle) and SOCKS capabilities.\n* [OpenConnect](https://ocserv.gitlab.io/www/index.html) / [Cisco AnyConnect](https://www.cisco.com/c/en/us/products/security/anyconnect-secure-mobility-client/index.html)\n  * OpenConnect (ocserv) is an extremely high-performance and lightweight VPN server that also features full compatibility with the official Cisco AnyConnect clients.\n  * The [protocol](https://ocserv.gitlab.io/www/technical.html) is built on top of standards like HTTP, TLS, and DTLS, and it's one of the most popular and widely used VPN technologies among large multi-national corporations.\n    * This means that in addition to its ease-of-use and speed, OpenConnect is also highly resistant to censorship and is almost never blocked.\n* [OpenVPN](https://openvpn.net/index.php/open-source.html)\n  * When enabled, self-contained \"unified\" .ovpn profiles are generated for easy client configuration using only a single file.\n  * Both TCP and UDP connections are supported.\n  * Client DNS resolution is handled via [Dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) to prevent DNS leaks.\n  * TLS Authentication is enabled which helps protect against active probing attacks. Traffic that does not have the proper HMAC is simply dropped.\n* [Shadowsocks](https://shadowsocks.org/en/index.html)\n  * When enabled, the high-performance [libev variant](https://github.com/shadowsocks/shadowsocks-libev) is installed. This version is capable of handling thousands of simultaneous connections.\n  * A QR code is generated that can be used to automatically configure the Android and iOS clients by simply taking a picture. You can tag '8.8.8.8' on that concrete wall, or you can glue the Shadowsocks instructions and some QR codes to it instead!\n  * [AEAD](https://shadowsocks.org/en/spec/AEAD-Ciphers.html) support is enabled using ChaCha20 and Poly1305 for enhanced security and improved GFW evasion.\n  * The [v2ray-plugin](https://github.com/shadowsocks/v2ray-plugin) plugin is installed to provide robust traffic evasion on hostile networks (especially those implementing quality of service (QOS) throttling).\n* [sslh](https://www.rutschle.net/tech/sslh/README.html)\n  * Sslh is a protocol demultiplexer that allows Nginx, OpenSSH, and OpenVPN to share port 443. This provides an alternative connection option and means that you can still route traffic via OpenSSH and OpenVPN even if you are on a restrictive network that blocks all access to non-HTTP ports.\n* [Stunnel](https://www.stunnel.org/index.html)\n  * When enabled, listens for and wraps OpenVPN connections. This makes them look like standard SSL traffic and allows OpenVPN clients to successfully establish tunnels even in the presence of Deep Packet Inspection.\n  * Unified profiles for stunnel-wrapped OpenVPN connections are generated alongside the direct connection profiles. Detailed instructions are also generated.\n  * The stunnel certificate and key are exported in PKCS #12 format so they are compatible with other SSL tunneling applications. Notably, this enables [OpenVPN for Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn) to tunnel its traffic through [SSLDroid](https://play.google.com/store/apps/details?id=hu.blint.ssldroid). OpenVPN in China on a mobile device? Yes!\n* [Tor](https://www.torproject.org/)\n  * If chosen by the user a [bridge relay](https://www.torproject.org/docs/bridges) is set up with a random nickname.\n  * [Obfsproxy](https://www.torproject.org/projects/obfsproxy.html.en) is installed and configured with support for the obfs4 pluggable transport.\n  * A BridgeQR code is generated that can be used to automatically configure [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android) for Android.\n* [UFW](https://wiki.ubuntu.com/UncomplicatedFirewall)\n  * Firewall rules are configured for every service, and any traffic that is sent to an unauthorized port will be blocked.\n* [unattended-upgrades](https://help.ubuntu.com/community/AutomaticSecurityUpdates)\n  * Your Streisand server is configured to automatically install new security updates.\n* [WireGuard](https://www.wireguard.com/)\n  * Users can take advantage of this next-gen, simple, kernel-based or user-space-based, state-of-the-art VPN that also happens to be ridiculously fast and uses modern cryptographic principles that all other highspeed VPN solutions lack. It is noticeably more performant and enery-saving, and is highly advantageous in roaming network-to-network environments, like mobile phones. A connection can be made as simply as scanning a QR code, which makes it perfect for sharing with friends and family members. It currently offers an official client for macOS, iOS, Android, Windows, a variety of Linux distibutions, OpenBSD and FreeBSD.\n* [Cloudflared DNS-over-HTTPS](https://developers.cloudflare.com/1.1.1.1/dns-over-https/)\n  * Even when you are visiting a site using HTTPS, by default your DNS query is sent over an unencrypted connection (between the Streisand server and upstream DNS servers). With Streisand's DNS-over-HTTPS service provided by the cloudflared client enabled, your DNS queries are blocked from view by the cloud provider hosting your Streisand server and everyone in between them and the upstream DNS server. The DNS reply from the upstream server is also protected from both view and tampering on its way back to your Streisand server.\n"
  },
  {
    "path": "Vagrantfile",
    "content": "# See documentation/testing.md for instructions on using this Vagrantfile\n#\nVagrant.require_version \">= 1.9.0\"\n\nVagrant.configure(2) do |config|\n\n  config.vm.box = \"ubuntu/xenial64\"\n\n  config.vm.define \"streisand-host\", primary: true do |streisand|\n    streisand.vm.hostname = \"streisand-host\"\n    streisand.vm.network :private_network, ip: \"10.0.0.10\"\n\n    streisand.vm.provision \"ansible\" do |ansible|\n      # NOTE: Uncomment the below line for verbose Ansible output\n      # ansible.verbose = \"v\"\n      ansible.playbook = \"playbooks/vagrant.yml\"\n      ansible.host_vars = {\n        \"streisand-host\" => {\n          \"streisand_ipv4_address\" => \"10.0.0.10\"\n        }\n      }\n      ansible.raw_arguments  = [\n        \"--extra-vars=@global_vars/globals.yml\",\n        \"--extra-vars=@global_vars/default-site.yml\",\n        \"--extra-vars=@global_vars/integration/test-site.yml\"\n      ]\n    end\n  end\n\n  config.vm.define \"streisand-client\" do |client|\n    client.vm.hostname = \"streisand-client\"\n    client.vm.network :private_network, ip: \"10.0.0.11\"\n\n    client.vm.provision \"ansible\" do |ansible|\n      # NOTE: Uncomment the below line for verbose Ansible output\n      # ansible.verbose = \"v\"\n      ansible.playbook = \"playbooks/test-client.yml\"\n      ansible.host_vars = {\n        \"streisand-client\" => {\n          \"streisand_ip\" => \"10.0.0.10\",\n        }\n      }\n    end\n  end\nend\n"
  },
  {
    "path": "Vagrantfile.remotetest",
    "content": "# See documentation/testing.md for instructions on using this Vagrantfile\n#\n# NOTE: You *MUST* replace the \"REMOTE_IP_HERE\" value in the `host_vars` section\n# with the IP address of the Streisand server you wish to test\n#\nVagrant.require_version \">= 1.9.0\"\n\nVagrant.configure(2) do |config|\n\n  config.vm.box = \"ubuntu/xenial64\"\n\n  config.vm.define \"streisand-client\" do |client|\n    client.vm.hostname = \"streisand-client\"\n    client.vm.network :private_network, ip: \"10.0.0.11\"\n\n    client.vm.provision \"ansible\" do |ansible|\n      # NOTE: Uncomment the below line for verbose Ansible output\n      #ansible.verbose = \"v\"\n      ansible.playbook = \"playbooks/test-client.yml\"\n      ansible.host_vars = {\n        \"streisand-client\" => {\n          \"streisand_ip\" => \"REMOTE_IP_HERE\",\n        }\n      }\n    end\n  end\nend\n"
  },
  {
    "path": "ansible.cfg",
    "content": "[defaults]\ninventory = inventories/inventory\nnocows = 1\n\n# This is a convenient setting for a brand-new Streisand server that\n# you are connecting to for the first time. However, this line should be\n# commented out if you are connecting to an existing server where a\n# known_hosts entry has already been created. Host key checking happens\n# by default in Ansible.\nhost_key_checking = False\n\n# Workaround for an Ansible issue with temporary paths:\n# https://github.com/ansible/ansible/issues/21562\nremote_tmp = $HOME/.ansible/tmp\nlocal_tmp = $HOME/.ansible/tmp\n\n# Some providers take a long time to actually begin accepting\n# connections even after the OpenSSH daemon has started.\ntimeout = 100\n\nlibrary=library\n\n[ssh_connection]\n# Enables multiplexing (lets ansible reuse opened SSH connections)\nssh_args = -o ControlMaster=auto -o ControlPersist=60s\npipelining = True\n"
  },
  {
    "path": "deploy/streisand-existing-cloud-server.sh",
    "content": "#!/usr/bin/env bash\n#\n# Provision an existing cloud server.\n#\n# This requires an expanded extra-vars file specific to the provider type that\n# sets all of the values gathered by prompts in the interactive installation.\n# See the contents of global_vars/noninteractive for examples that can be copied\n# and modified.\n#\n# Usage:\n#\n# streisand-existing-cloud-server \\\n#   --ssh-user root \\\n#   --ip-address 10.10.10.10 \\\n#   --site-config path/to/digitalocean-site.yml\n#\n\nset -o errexit\nset -o nounset\n\nDIR=\"$( cd \"$( dirname \"$0\" )\" && pwd)\"\nPROJECT_DIR=\"${DIR}/..\"\n\nexport DEFAULT_SITE_VARS=\"${PROJECT_DIR}/global_vars/default-site.yml\"\nexport GLOBAL_VARS=\"${PROJECT_DIR}/global_vars/globals.yml\"\n\n# Include the check_ansible function from ansible_check.sh.\n# shellcheck source=util/source_validate_and_deploy.sh\nsource \"${PROJECT_DIR}/util/ansible_check.sh\"\ncheck_ansible\n\n# --------------------------------------------------------------------------\n# Reading options.\n# --------------------------------------------------------------------------\n\nfunction usage () {\n  cat <<EOF\nUsage:\n$0 \\\\\n  --ssh-user root \\\\\n  --ip-address 10.10.10.10 \\\\\n  --site-config path/to/site.yml\n\nIf no SSH user is specified, then the root user will be used.\n\nIf no configuration file is specified, then ~/.streisand/site.yml will be used\nif it exists, or global_vars/default-site.yml will be used otherwise.\nEOF\n}\n\nSSH_USER=\"\"\nIP_ADDRESS=\"\"\nSITE_VARS=\"\"\n\nwhile [[ ${#} -gt 0 ]]; do\n  case \"${1}\" in\n    # Required.\n    --ip-address)    IP_ADDRESS=\"${2}\"; shift;;\n\n    # Optional.\n    --site-config)   SITE_VARS=\"${2}\"; shift;;\n    --ssh-user)      SSH_USER=\"${2}\"; shift;;\n\n    # Utility.\n    -h|--help)       usage; exit 0;;\n    --)              break;;\n    -*)              echo \"Unrecognized option ${1}\"; usage; exit 1;;\n  esac\n\n  shift\ndone\n\n# --------------------------------------------------------------------------\n# Fail if required options are not set.\n# --------------------------------------------------------------------------\n\nif [ -z \"${IP_ADDRESS}\" ]; then\n  usage\n  exit 1\nfi\n\n# --------------------------------------------------------------------------\n# Default if no parameter is provided.\n# --------------------------------------------------------------------------\n\nif [ -z \"${SSH_USER}\" ]; then\n  echo \"Defaulting to SSH user: root\"\n  SSH_USER=\"root\"\nfi\n\n# --------------------------------------------------------------------------\n# Sort out the SITE_VARS value based on input and defaults.\n# --------------------------------------------------------------------------\n\n# shellcheck source=util/source_check_and_default_site_vars.sh\nsource \"${PROJECT_DIR}/util/source_check_and_default_site_vars.sh\"\n\n# --------------------------------------------------------------------------\n# Onwards to launch and provision the server.\n# --------------------------------------------------------------------------\n\nexport INVENTORY=\"${PROJECT_DIR}/inventories/inventory-existing\"\n\n# Create an inventory file on the fly.\ncat > \"${INVENTORY}\" <<EOF\n[localhost]\nlocalhost ansible_connection=local ansible_python_interpreter=python\n[streisand-host]\n${IP_ADDRESS} ansible_user=${SSH_USER}\nEOF\n\nexport PLAYBOOK=\"${PROJECT_DIR}/playbooks/existing-server.yml\"\n\n# Run the validation and deployment. This expects the variables set here.\n# shellcheck source=util/source_validate_and_deploy.sh\nsource \"${PROJECT_DIR}/util/source_validate_and_deploy.sh\"\n"
  },
  {
    "path": "deploy/streisand-local.sh",
    "content": "#!/usr/bin/env bash\n#\n# Run a noninteractive Streisand installation on the local machine.\n#\n# This requires an expanded extra-vars file specific to the provider type that\n# sets all of the values gathered by prompts in the interactive installation.\n# See the contents of global_vars/noninteractive for examples that can be copied\n# and modified.\n#\n# Usage:\n#\n# streisand-local --site-config path/to/local-site.yml\n#\n\nset -o errexit\nset -o nounset\n\nDIR=\"$( cd \"$( dirname \"$0\" )\" && pwd)\"\nPROJECT_DIR=\"${DIR}/..\"\n\nexport DEFAULT_SITE_VARS=\"${PROJECT_DIR}/global_vars/default-site.yml\"\nexport GLOBAL_VARS=\"${PROJECT_DIR}/global_vars/globals.yml\"\n\n# Include the check_ansible function from ansible_check.sh.\n# shellcheck source=util/source_validate_and_deploy.sh\nsource \"${PROJECT_DIR}/util/ansible_check.sh\"\ncheck_ansible\n\n# --------------------------------------------------------------------------\n# Reading options.\n# --------------------------------------------------------------------------\n\nfunction usage () {\n  cat <<EOF\nUsage:\n$0 --site-config path/to/site.yml\n\nIf no configuration file is specified, then ~/.streisand/site.yml will be used\nif it exists, or global_vars/default-site.yml will be used otherwise.\nEOF\n}\n\nSITE_VARS=\"\"\n\nwhile [[ ${#} -gt 0 ]]; do\n  case \"${1}\" in\n    # Optional.\n    --site-config)   SITE_VARS=\"${2}\"; shift;;\n\n    # Utility.\n    -h|--help)       usage; exit 0;;\n    --)              break;;\n    -*)              echo \"Unrecognized option ${1}\"; usage; exit 1;;\n  esac\n\n  shift\ndone\n\n# --------------------------------------------------------------------------\n# Sort out the SITE_VARS value based on input and defaults.\n# --------------------------------------------------------------------------\n\n# shellcheck source=util/source_check_and_default_site_vars.sh\nsource \"${PROJECT_DIR}/util/source_check_and_default_site_vars.sh\"\n\n# --------------------------------------------------------------------------\n# Onwards to provision the local machine.\n# --------------------------------------------------------------------------\n\nexport INVENTORY=\"${PROJECT_DIR}/inventories/inventory-local-provision\"\nexport PLAYBOOK=\"${PROJECT_DIR}/playbooks/localhost.yml\"\n\n# Run the validation and deployment. This expects the variables set here.\n# shellcheck source=util/source_validate_and_deploy.sh\nsource \"${PROJECT_DIR}/util/source_validate_and_deploy.sh\"\n"
  },
  {
    "path": "deploy/streisand-new-cloud-server.sh",
    "content": "#!/usr/bin/env bash\n#\n# Run a noninteractive Streisand installation that creates a new cloud server.\n#\n# This requires an expanded extra-vars file specific to the provider type that\n# sets all of the values gathered by prompts in the interactive installation.\n# See the contents of global_vars/noninteractive for examples that can be copied\n# and modified.\n#\n# Usage:\n# streisand-new-cloud-server \\\n#   --provider [amazon|azure|digitalocean|google|linode|rackspace] \\\n#   --site-config path/to/digitalocean-site.yml\n#\n\nset -o errexit\nset -o nounset\n\nDIR=\"$( cd \"$( dirname \"$0\" )\" && pwd)\"\nPROJECT_DIR=\"${DIR}/..\"\n\nVALID_PROVIDERS=\"amazon|azure|digitalocean|google|linode|rackspace\"\nexport DEFAULT_SITE_VARS=\"${PROJECT_DIR}/global_vars/default-site.yml\"\nexport GLOBAL_VARS=\"${PROJECT_DIR}/global_vars/globals.yml\"\n\n# Include the check_ansible function from ansible_check.sh.\n# shellcheck source=util/source_validate_and_deploy.sh\nsource \"${PROJECT_DIR}/util/ansible_check.sh\"\ncheck_ansible\n\n# --------------------------------------------------------------------------\n# Reading options.\n# --------------------------------------------------------------------------\n\nfunction usage () {\n  cat <<EOF\nUsage:\n$0 \\\\\n  --provider [${VALID_PROVIDERS}] \\\\\n  --site-config path/to/site.yml\n\nIf no configuration file is specified, then ~/.streisand/site.yml will be used\nif it exists, or global_vars/default-site.yml will be used otherwise.\nEOF\n}\n\nPROVIDER=\"\"\nSITE_VARS=\"\"\n\nwhile [[ ${#} -gt 0 ]]; do\n  case \"${1}\" in\n    # Required.\n    --provider)      PROVIDER=\"${2}\"; shift;;\n\n    # Optional.\n    --site-config)   SITE_VARS=\"${2}\"; shift;;\n\n    # Utility.\n    -h|--help)       usage; exit 0;;\n    --)              break;;\n    -*)              echo \"Unrecognized option ${1}\"; usage; exit 1;;\n  esac\n\n  shift\ndone\n\n# --------------------------------------------------------------------------\n# Check the provider parameter.\n# --------------------------------------------------------------------------\n\n# Was it passed in at all?\nif [ -z \"${PROVIDER}\" ]; then\n  usage\n  exit 1\nfi\n\n# Check validity of the provider name.\nif [[ ! \"${PROVIDER}\" =~ ${VALID_PROVIDERS} ]]; then\n  echo \"Invalid provider: ${PROVIDER}\"\n  exit 1\nfi\n\n# --------------------------------------------------------------------------\n# Sort out the SITE_VARS value based on input and defaults.\n# --------------------------------------------------------------------------\n\n# shellcheck source=util/source_check_and_default_site_vars.sh\nsource \"${PROJECT_DIR}/util/source_check_and_default_site_vars.sh\"\n\n# --------------------------------------------------------------------------\n# Onwards to launch and provision the server.\n# --------------------------------------------------------------------------\n\nexport INVENTORY=\"${PROJECT_DIR}/inventories/inventory\"\nexport PLAYBOOK=\"${PROJECT_DIR}/playbooks/${PROVIDER}.yml\"\n\n# Run the validation and deployment. This expects the variables set here.\n# shellcheck source=util/source_validate_and_deploy.sh\nsource \"${PROJECT_DIR}/util/source_validate_and_deploy.sh\"\n\n"
  },
  {
    "path": "documentation/AWS-fr.md",
    "content": "Configuration de contrôle d'accès AWS IAM\n=========================================\n\nConfiguration d'accès IAM\n-------------------------\n\n* Connectez-vous à AWS et naviguez jusqu'à le panneau Gestion des identités et des accès (IAM) \n![](screenshots/AWS/IAMPolicy1.png?raw=true)\n\n* Créer un groupe de resources\n![](screenshots/AWS/IAMPolicy2.png?raw=true)\n\n* Entrez un nom et une description pour la groupe de resources, coller le document de ci-dessous, puis créez la resource en cliquant sur le bouton dans le coin inférieur droit.\n![](screenshots/AWS/IAMPolicy3.png?raw=true)\n\n```\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"EC2Policies\",\n            \"Action\": [\n                \"ec2:AllocateAddress\",\n                \"ec2:AssociateAddress\",\n                \"ec2:AuthorizeSecurityGroupIngress\",\n                \"ec2:AuthorizeSecurityGroupEgress\",\n                \"ec2:CreateSecurityGroup\",\n                \"ec2:ImportKeyPair\",\n                \"ec2:CreateTags\",\n                \"ec2:CreateSecurityGroup\",\n                \"ec2:DescribeSecurityGroups\",\n                \"ec2:DescribeAddresses\",\n                \"ec2:DescribeImages\",\n                \"ec2:DescribeInstances\",\n                \"ec2:DescribeKeyPairs\",\n                \"ec2:DescribeSubnets\",\n                \"ec2:RevokeSecurityGroupEgress\",\n                \"ec2:RevokeSecurityGroupIngress\",\n                \"ec2:RunInstances\",\n                \"ec2:DeleteKeyPair\"\n            ],\n            \"Effect\": \"Allow\",\n            \"Resource\": \"*\"\n        },\n        {\n            \"Sid\": \"CloudwatchPolicies\",\n            \"Action\": [\n                \"cloudwatch:DescribeAlarms\",\n                \"cloudwatch:PutMetricAlarm\"\n            ],\n            \"Effect\": \"Allow\",\n            \"Resource\": \"*\"\n        },\n        {\n            \"Sid\": \"IAMPolicies\",\n            \"Action\": [\n                \"iam:CreateServiceLinkedRole\"\n            ],\n            \"Effect\": \"Allow\",\n            \"Resource\": \"*\"\n        }\n    ]\n}\n```\n\n* Vous devriez voir un écran de confirmation semblable au suivant:\n![](screenshots/AWS/IAMPolicy4.png?raw=true)\n\n\nConfiguration de l'utilisateur d'IAM\n-----\n* Naviguez jusqu'à le panneau Gestion des identités et des accès (IAM)\n\n* Ajoutez un utilisateur, selectionnez `Accès par programmation`. Cliquez le bouton `Suivant: Autorisations`\n![](screenshots/AWS/IAMUser1.png?raw=true)\n\n* Définissez les autorisations pour l'utilisateur IAM en attachant le document créée ci-dessus.\n![](screenshots/AWS/IAMUser2.png?raw=true)\n\n* Vérifiez les changements, puis cliquez sur le bouton `Créer un utilisateur`\n![](screenshots/AWS/IAMUser3.png?raw=true)\n\n* Après l'écran de confirmation, téléchargez le fichier `.csv` — vous l'utiliserez lors de la configuration de votre VPN.\n![](screenshots/AWS/IAMUser4.png?raw=true)\n"
  },
  {
    "path": "documentation/AWS.md",
    "content": "AWS IAM role and policy setup\n==========================\n\nIAM Policy Setup\n-----\n\n* Log onto AWS and navigate to the IAM policy panel\n![](screenshots/AWS/IAMPolicy1.png?raw=true)\n\n* Create a IAM Policy\n![](screenshots/AWS/IAMPolicy2.png?raw=true)\n\n* Write a name and description for the policy, paste in the below policy document, then create the policy by clicking the button in the lower right corner.\n![](screenshots/AWS/IAMPolicy3.png?raw=true)\n\n```\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"EC2Policies\",\n            \"Action\": [\n                \"ec2:AllocateAddress\",\n                \"ec2:AssociateAddress\",\n                \"ec2:AuthorizeSecurityGroupIngress\",\n                \"ec2:AuthorizeSecurityGroupEgress\",\n                \"ec2:CreateSecurityGroup\",\n                \"ec2:ImportKeyPair\",\n                \"ec2:CreateTags\",\n                \"ec2:CreateSecurityGroup\",\n                \"ec2:DescribeSecurityGroups\",\n                \"ec2:DescribeAddresses\",\n                \"ec2:DescribeImages\",\n                \"ec2:DescribeInstances\",\n                \"ec2:DescribeKeyPairs\",\n                \"ec2:DescribeSubnets\",\n                \"ec2:RevokeSecurityGroupEgress\",\n                \"ec2:RevokeSecurityGroupIngress\",\n                \"ec2:RunInstances\",\n                \"ec2:DeleteKeyPair\"\n            ],\n            \"Effect\": \"Allow\",\n            \"Resource\": \"*\"\n        },\n        {\n            \"Sid\": \"CloudwatchPolicies\",\n            \"Action\": [\n                \"cloudwatch:DescribeAlarms\",\n                \"cloudwatch:PutMetricAlarm\"\n            ],\n            \"Effect\": \"Allow\",\n            \"Resource\": \"*\"\n        },\n        {\n            \"Sid\": \"IAMPolicies\",\n            \"Action\": [\n                \"iam:CreateServiceLinkedRole\"\n            ],\n            \"Effect\": \"Allow\",\n            \"Resource\": \"*\"\n        }\n    ]\n}\n```\n\n* You should see a confirmation screen similar to the below:\n![](screenshots/AWS/IAMPolicy4.png?raw=true)\n\n\nIAM User Setup\n-----\n* Navigate to the IAM User panel\n\n* Add a user name, select the `programmatic access` access type. Then click the `Next: Permissions` button\n![](screenshots/AWS/IAMUser1.png?raw=true)\n\n* Set the permissions for the IAM User by attaching the policy created above.\n![](screenshots/AWS/IAMUser2.png?raw=true)\n\n* Review the changes, the click the `Create User` button\n![](screenshots/AWS/IAMUser3.png?raw=true)\n\n* After the confirmation screen, download the `.csv` file — you'll use it when setting up your VPN.\n![](screenshots/AWS/IAMUser4.png?raw=true)\n"
  },
  {
    "path": "documentation/AZURE-fr.md",
    "content": "Certification et configuration d'Azure\r\n======================================\r\n\r\n<!--\r\nAlso a best effort at translation @alimakki\r\n-->\r\nInstallation\r\n------------\r\n* Créer une application ( [guide visuel](https://docs.microsoft.com/fr-fr/azure/azure-resource-manager/resource-group-create-service-principal-portal#create-an-active-directory-application) )<br />\r\n\tRechercher **Inscriptions d’applications** dans la barre de recherche et sélectionnez le premier résultat.<br />\r\n\tSélectionnez **Inscriptions d’applications**.<br />\r\n\tRemplissez le formulaire:\r\n\r\n\t\tName: StreisandAuth\r\n\t\tApplication type: Web app / API\r\n\t\tSign-on URL: http://StreisandAuth\r\n\r\n* Assurez que l'application peut créer des instances Azure ( [guide visuel](https://docs.microsoft.com/fr-fr/azure/azure-resource-manager/resource-group-create-service-principal-portal#assign-application-to-role) )<br />\r\n\tRechercher **Abonnements** dans la barre de recherche et sélectionnez le premier résultat.<br />\r\n\tChoisissez l'abonnement souhaité.<br />\r\n\tSélectionnez **Access control (IAM)** à partir du menu nouvellement ouvert.<br />\r\n\tAjouter:\r\n\r\n\t\tRole: Contributor\r\n\t\tSelect: StreisandAuth\r\n\r\nAutorisations\r\n-------------\r\nEmplacement du fichier:\r\n\r\n\t\t~/.azure/credentials\r\n\r\nFormat du fichier ( [source](https://docs.ansible.com/ansible/guide_azure.html#storing-in-a-file) ).\r\n\r\n\t\t[default]\r\n\t\tsubscription_id=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\n\t\tclient_id=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\n\t\tsecret=xxxxxxxxxxxxxxxxx\r\n\t\ttenant=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\n\r\nRemplacez le motif **xxxxx** par les valeurs obtenues en suivant les étapes ci-dessous.\r\n\r\n* Obtenir le **subscription_id**<br />\r\n\tRechercher pour **Subscriptions** à partir du menu nouvellement ouvert.<br />\r\n\tL'ID de l'abonnement sera dans la deuxième colonne du tableau des abonnements.\r\n\r\n* Obtenir le **client_id** ( [guide visuel](https://docs.microsoft.com/fr-fr/azure/azure-resource-manager/resource-group-create-service-principal-portal#get-application-id-and-authentication-key) )<br />\r\n\tRechercher pour **App registrations** à partir du menu nouvellement ouvert.<br />\r\n\tSélectionnez votre application dans la liste: **StreisandAuth**.<br />\r\n\tLe client_id est le [Guid](https://en.wikipedia.org/wiki/Universally_unique_identifier) sous **Application ID**.<br />\r\n\r\n* Obtenir le **secret** ( [guide visuel](https://docs.microsoft.com/fr-fr/azure/azure-resource-manager/resource-group-create-service-principal-portal#get-application-id-and-authentication-key) )<br />\r\n\tRechercher pour **App registrations** à partir du menu nouvellement ouvert.<br />\r\n\tSélectionnez votre application dans la liste: **StreisandAuth**.<br />\r\n\tSélectionnez **Keys** à partir du menu nouvellement ouvert à droite.<br />\r\n\tCréer une nouvelle clé:\r\n\r\n\t\tKey description: streisand\r\n\t\tDuration: Never expires\r\n\tLa clé secrète sera générée après la sauvegarde.\r\n\r\n* Obtenir le **tenant** ( [guide visuel](https://docs.microsoft.com/fr-fr/azure/azure-resource-manager/resource-group-create-service-principal-portal#get-tenant-id) )<br />\r\n\tRechercher pour **Azure Active Directory** à partir du menu nouvellement ouvert.<br />\r\n\tFaites défiler vers le bas et sélectionnez **Properties** à partir du menu nouvellement ouvert à gauche.<br />\r\n\tLe locataire est le Guid sous **Directory ID**.<br />\r\n\r\nProblèmes possibles et dépannage\r\n--------------------------------\r\n* You cannot register an application (Vous ne pouvez pas enregistrer une application)<br />\r\n\tRechercher pour **Azure Active Directory** à partir du menu nouvellement ouvert.<br />\r\n\tDans le menu gauche résultant, sélectionnez \"User settings\".<br />\r\n\tAssurez-vous que **App registrations** sont réglés sur **Yes**.\r\n"
  },
  {
    "path": "documentation/AZURE.md",
    "content": "Azure credential and setup\r\n==========================\r\n\r\n- - -\r\n[English](AZURE.md), [Français](AZURE-fr.md)\r\n- - -\r\n\r\nSetup\r\n-----\r\n* Create an application ( [visual guide](https://docs.microsoft.com/en-in/azure/azure-resource-manager/resource-group-create-service-principal-portal#create-an-active-directory-application) )<br />\r\n\tSearch for **App registrations** in the top search bar and select the first result.<br />\r\n\tSelect **New application registration**.<br />\r\n\tFill in the application form:\r\n\r\n\t\tName: StreisandAuth\r\n\t\tApplication type: Web app / API\r\n\t\tSign-on URL: http://StreisandAuth\r\n\r\n* Ensure that the application can create Azure instances ( [visual guide](https://docs.microsoft.com/en-in/azure/azure-resource-manager/resource-group-create-service-principal-portal#assign-application-to-role) )<br />\r\n\tSearch for **Subscriptions** in the top search bar and select the first result.<br />\r\n\tChoose the desired subscription.<br />\r\n\tSelect **Access control (IAM)** from the newly opened menu.<br />\r\n\tAdd:\r\n\r\n\t\tRole: Contributor\r\n\t\tSelect: StreisandAuth\r\n\r\nCredentials\r\n-----------\r\nFile location:\r\n\r\n\t\t~/.azure/credentials\r\n\r\nFile format ( [source](https://docs.ansible.com/ansible/guide_azure.html#storing-in-a-file) ).\r\n\r\n\t\t[default]\r\n\t\tsubscription_id=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\n\t\tclient_id=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\n\t\tsecret=xxxxxxxxxxxxxxxxx\r\n\t\ttenant=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\n\r\nReplace the **xxxxx** pattern with the values obtained by following the below steps.\r\n\r\n* Get the **subscription_id**<br />\r\n\tSearch for **Subscriptions** in the top search bar and select the first result.<br />\r\n\tThe subscription ID will be in the second column of the subscriptions table.\r\n\r\n* Get the **client_id** ( [visual guide](https://docs.microsoft.com/en-in/azure/azure-resource-manager/resource-group-create-service-principal-portal#get-application-id-and-authentication-key) )<br />\r\n\tSearch for **App registrations** in the top search bar and select the first result.<br />\r\n\tSelect your application from the list: **StreisandAuth**.<br />\r\n\tThe client_id is the [Guid](https://en.wikipedia.org/wiki/Universally_unique_identifier) under **Application ID**.<br />\r\n\r\n* Get the **secret** ( [visual guide](https://docs.microsoft.com/en-in/azure/azure-resource-manager/resource-group-create-service-principal-portal#get-application-id-and-authentication-key) )<br />\r\n\tSearch for **App registrations** in the top search bar and select the first result.<br />\r\n\tSelect your application from the list: **StreisandAuth**.<br />\r\n\tSelect **Certificates & secrets** from the newly opened menu on the left.<br />\r\n\tSelect **New client secret** under **Client secrets**.<br />\r\n\tCreate a new key:\r\n\r\n\t\tKey description: streisand\r\n\t\tDuration: Never expires\r\n\tThe secret key will be generated after saving.\r\n\r\n* Get the **tenant** ( [visual guide](https://docs.microsoft.com/en-in/azure/azure-resource-manager/resource-group-create-service-principal-portal#get-tenant-id) )<br />\r\n\tSearch for **Azure Active Directory** in the top search bar and select the first result.<br />\r\n\tScroll down and select **Properties** from the newly opened left menu.<br />\r\n\tThe tenant is the Guid under **Directory ID**.<br />\r\n\r\nPossible issues and troubleshooting\r\n-----------------------------------\r\n* You cannot register an application<br />\r\n\tSearch for **Azure Active Directory** in the top search bar and select the first result.<br />\r\n\tIn the resulting left menu select \"User settings\".<br />\r\n\tEnsure that **App registrations** is set to **Yes**.\r\n"
  },
  {
    "path": "documentation/SOURCES.md",
    "content": "# Source of packages installed\r\n\r\n## From APT\r\n\r\n- Ubuntu standard repositories\r\n  - [Streisand Common Packages](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/common/vars/main.yml)\r\n  - [`bind`](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/dnsmasq/tasks/main.yml)\r\n  - [`dnsmasq`](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/dnsmasq/tasks/main.yml)\r\n  - [Libreswan Compilation Dependencies](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/l2tp-ipsec/vars/main.yml)\r\n  - [OpenConnect Dependencies](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/openconnect/vars/main.yml)\r\n  - [Shadowsocks Dependencies](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/shadowsocks/vars/main.yml)\r\n  - [`sslh`](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/sslh/tasks/main.yml)\r\n  - [`stunnel4`](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/stunnel/tasks/main.yml)\r\n  - [`tinyproxy`](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/tinyproxy/tasks/main.yml)\r\n  - [`ufw`](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/ufw/tasks/main.yml)\r\n- from 3rd party repositories:\r\n  - [`nginx` (from nginx.org)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/nginx/tasks/main.yml)\r\n  - [`obbfs4proxy` (from deb.torproject.org)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/tor-bridge/tasks/main.yml)\r\n  - [Wireguard Packages (from wireguard PPA)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/wireguard/tasks/install.yml)\r\n  - [Acmetool (from PPA)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/lets-encrypt/tasks/install.yml)\r\n\r\n## Source\r\n- [Libreswan](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/l2tp-ipsec/vars/main.yml)\r\n- [OpenConnect](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/openconnect/vars/main.yml)\r\n- [OpenVPN (from build.openvpn.net)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/openvpn/vars/mirror.yml)\r\n- [Shadowsocks (from github.com/shadowsocks)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/shadowsocks/tasks/main.yml)\r\n- [Shadowsocks Simple-obfs (from github.com/shadowsocks-simpleobfs)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/shadowsocks/tasks/simple-obfs.yml)\r\n\r\n\r\n# Source of all clients mirrored\r\n\r\n- Android\r\n  - [Shadowsocks (from github.com/shadowsocks)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/shadowsocks/vars/mirror.yml)\r\n- Linux\r\n  - [Shadowsocks (from github.com/shadowsocks)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/shadowsocks/vars/mirror.yml)\r\n  - [Tor Browser (from dist.torproject.org)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/tor-bridge/vars/mirror-common.yml)\r\n- macOS\r\n  - [Tunnelblick (from tunnelblick.net)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/openvpn/vars/mirror.yml)\r\n  - [Shadowsocks (from github.com/shadowsocks)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/shadowsocks/vars/mirror.yml)\r\n  - [Tor Browser (from dist.torproject.org)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/tor-bridge/vars/mirror-common.yml)\r\n- Windows\r\n  - [OpenVPN (from build.openvpn.net)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/openvpn/vars/mirror.yml)\r\n  - [Shadowsocks (from github.com/shadowsocks)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/shadowsocks/vars/mirror.yml)\r\n  - [Shuttle (from github.com/sshuttle)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/streisand-mirror/vars/ssh.yml)\r\n  - [Stunnel (from stunnel.org)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/stunnel/vars/mirror.yml)\r\n  - [Putty (from the.earth.li)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/streisand-mirror/vars/ssh.yml)\r\n  - [Tor Browser (from dist.torproject.org)](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/tor-bridge/vars/mirror-common.yml)\r\n"
  },
  {
    "path": "documentation/certificates.md",
    "content": "Streisand PKI\n=============\n\nStreisand includes a role responsible for PKI certificate generation,\nseparated into three heirarchical tasks:\n\n```\nCA/Server\n   \\__ CA Certificate\n     \\__ Server certificate\n    \\__ Client (1..n)\n      \\__ Client PKCS (1..n)\n \n```\n\nCA/Server\n---------\nGuarded by `generate_ca_server: yes`\n\nGenerate a certificate authority, and a server \ncertificate signed by the newly minted certificate authority.\n\nClient\n------\nGenerate client certificates using the CA from `generate_ca_server: yes`. \nThese client certificates can be used by VPN clients to authenticate with \nVPN services on the server.\n\nClient (PKCS#11 format)\n-----------------------\nGuarded by `generate_pkcs: yes`\n\nAlso convert client certificates into PKCS#12 format.\n\nInfrastructure\n--------------\n\nNote: Each VPN service that invokes the certificates role will generate it's own \ndistinct public key infrastructure.\n\nThe overall Streisand PKI infrastructure assumes the following structure:\n\n```\nWeb Root CA: \n   \\__ gateway HTTPS cert (unless Let's Encrypt; see below)\n\nOpenConnect CA: \n   \\__ OpenConnect server cert\n   \\__ OpenConnect client 1\n   \\__ OpenConnect client ...\n   \\__ OpenConnect client n\n\nOpenVPN CA: \n   \\__ OpenVPN server cert\n   \\__ OpenVPN client 1\n   \\__ OpenVPN client ...\n   \\__ OpenVPN client n\n\nISRG X1:\n   \\__ Let's Encrypt Authority X3\n        \\__ streisand.example.com HTTPS cert\n``` \n\nUsage\n-----\n\nThe `certificates` role can be invoked as follows (using OpenVPN as an example, with variables expanded for brevity):\n\n```\n- include_role:\n    name: certificates\n  vars:\n    ca_path:            \"/etc/openvpn\"\n    tls_ca:             \"/etc/openvpn/ca\"\n    tls_client_path:    \"/etc/openvpn\"\n    generate_ca_server: yes \n    generate_client:    yes\n    tls_request_subject:         \"/C=US/ST=California/L=Beverly Hills/O=ACME CORPORATION/OU=Anvil Department\"\n    tls_server_common_name_file: \"/etc/openvpn/openvpn-common-name.txt\"\n    tls_sans:                    # sets the Subject Alternative Name(s) attribute(s)\n      - \"1.2.3.4\"\n      - \"5.6.7.8\"\n```\n\nNote the following flags:\n - `generate_ca_server: yes`\n - `generate_client: yes`\n - `generate_pkcs: yes`\n\n These must be made explicit, as the default value is `no`; certificates should not be generated unless\n they have to be.\n\nThe certificates role makes certain assumptions with regards to default values,\nall of which can be inspected [here](https://github.com/StreisandEffect/streisand/blob/master/playbooks/roles/certificates/defaults/main.yml).\n\n"
  },
  {
    "path": "documentation/localization_howto.md",
    "content": "Localizing Streisand in your language\n=====================================\n\nOne of the most unique aspects of the Streisand project are the\ndetailed and customized instructions that it generates for each\nof the VPN services it provides. The instructions are hosted\non a password protected website allowing them to be easily shared\namong fellow users. This can help in removing ambiguity in how \ncertain services need to be set up and can be easily updated as\nStreisand evolves.\n\nScope\n-----\n\nThe best place to focus localization efforts is on user facing\ncontent, as opposed to developer content.\n\nFor example, documentation that can help a user navigate the particularities of certain\ncloud providers (account setup, permissions, etc...) are good candidates for localization.\n\nOn the other hand, translation of developer oriented texts, such as Ansible \ntask names isn't needed at this time.\n\nLanguage codes\n--------------\n\nFor simplicity, it is preferable to use 2 character language codes (fr -> French, ar -> Arabic),\nas defined by [ISO 631-1](https://en.wikipedia.org/wiki/ISO_639). For certain locales such as\nChinese vs Simplified Chinese, 3 character codes are also acceptable.\n\nFilename conventions\n--------------------\n\nIn order to differentiate a localized file, append the lowercase language code after the\nfilename with a 'dash' symbol (e.x. README-fr.md for a README localized in French).\n\nPoint of reference\n------------------\n\nWhen translating, English should be considered the point of reference to translate *from*.\n\nREADMEs and Documentation\n-------------------------\n\nThe interaction with Streisand for an end user would be first visiting the project README,\nwhere all the necessary steps one would need to set up their computing environment are\ndetailed, as well as a listing of all the VPN services provided by Streisand.\n\nUnlike Streisand's instructions markdown template files, READMEs and documentation are\northogonal to Streisand being able to successfully build. As a consequences, it is possible\nto have READMEs and documentation in more languages than Streisand builds documentation with.\n\nDefining locales\n----------------\n\nIn order to define a locale for Streisand, a new entry defining your language must be\nadded to the `streisand_languages` dict object in the `playbooks/roles/common/vars/main.yml` file,\nwhere the 2 letter code is considered the key, and a list of key-value pairs with additional data\nas its value.\n\nFor example:\n\n```\nstreisand_languages:\n  en:\n    file_suffix: \"\"\n    language_name: \"English\"\n    tor_locale: \"en-US\"\n  fr:\n    file_suffix: \"-fr\"              # appends to the end of a file name\n    language_name: \"Français\"       # name of the language in the language itself\n    tor_locale: \"fr\"                # edge case for Tor          \n```\n\nLocalizing gateway instructions\n-------------------------------\n\nThe following roles contain user instructions that will require translation:\n\n - `playbooks/roles/openconnect/templates`\n  1. `instructions.md.j2`\n  1. `mirror.md.j2`\n\n - `playbooks/roles/openvpn/templates`\n  1. `instructions.md.j2`\n  1. `stunnel-insructions.md.j2`\n  1. `mirror.md.j2`\n\n - `playbooks/roles/shadowsocks/templates`\n  1. `instructions.md.j2`\n  1. `mirror.md.j2`\n\n- `playbooks/roles/ssh-forward/templates`\n  1. `instructions.md.j2`\n  1. `mirror.md.j2`\n\n - `playbooks/roles/streisand-gateway/templates`\n  1. `index.md.j2`\n  1. `instructions.md.j2`\n  1. `firewall.md.j2`\n\n - `playbooks/roles/streisand-mirror/templates`\n  1. `mirror-index.md.j2`\n\n - `playbooks/roles/stunnel/templates`\n  1. `mirror.md.j2`\n\n - `playbooks/roles/tor/templates`\n  1. `instructions.md.j2`\n  1. `mirror.md.j2`\n\n - `playbooks/roles/wireguard/templates`\n  1. `instructions.md.j2`\n\nLanguage selection in generated pages\n-------------------------------------\n\nBy default, Streisand's common header file contains language selection links\n(generated using the `streisand_languages` dict). For most pages the header with\nlanguage selection links will be included automatically. Certain edge cases \ndo exist where a jinja2 code block is explicitly needed with the generated html filename.\n\nThese edge case files maybe all reside with the `streisand-gateway` role:\n\n - `firewall.md.j2`\n - `index.md.j2`\n - `instructions.md.j2`\n\n```\n- - -\n{% for key, value in streisand_languages.items() %}\n  [{{ value.language_name }}]({{ streisand_server_name }}-*generated-html-file-name*{{ value.file_suffix }}.html)&nbsp;\n{% endfor %}\n- - -\n```\n\nThe HTML filename can be recovered by looking at the relevant Ansible task that generates the\ntemplate.\n\nEnd user considerations\n-----------------------\n\nWhile we aim to have as-close-to-the-original-source translations, linguistic differences in\nexpressions should be taken into consideration when it makes sense.\n\nA non-technical example would be a the following\nexpression in English: \"the straw that broke the camel's back\".\nA literal translation into French\nwould give: \"la paille qui a cassé le dos du chameau\", however contextually\na similar expression exists in French: \"C'est la goutte d'eau qui fait déborder le vase\"\n(it's the drop of water that made the vase overflow). Different translations,\nsame meaning. In this case, the latter would be the 'ideal' translation, as it makes more sense\nto a native speaker of that language.\n\nAnother aspect to consider is what language an end-user's device is set to.\nIt is best to have a device nearby set in the same language, where you can see exactly what is\ndisplayed in particular menus and use those same exactly what is displayed.\n\nIt's worth noting that not all software available in app stores or otherwise are localized\nin your language of choice, and many are English only. In this case, it would be sufficient to use\nthe same English texts, and should you choose, adjacent to it between parenthesis a translation of\nthe aforementioned text.\n\nIn the case where you aren't in possession of a particular device, a best-effort\napproach is also acceptable.\n"
  },
  {
    "path": "documentation/modular_roles.md",
    "content": "Modular Roles\n===============\n\nStreisand includes many services in an out-of-box install. This helps make\ncensorship resistance as easy as possible. In a hostile network environment the\nprotocols/services that are blocked can vary & change overnight. With many\nchoices available for connecting through a Streisand instance to clear Internet\nthere is likely always a choice that will work!\n\nFor use cases less focused on censorship resistance this \"kitchen sink of\nservices\" approach has two large downsides: many moving parts & a very large\nexternally facing attack surface.\n\nThe solution: Allowing users to selectively disable Streisand services they\ndon't require, creating custom profiles that suits their needs.\n\nThe challenge: Streisand was initially designed as a monolithic deploy. That is,\nthe Ansible roles responsible for each service inter-depend on one another. To\nenable picking and choosing Streisand services while minimizing spaghetti\ncomplexity it's necessary to eliminate cross-role dependencies.\n\nThis document aims to be a roadmap for converting roles to be stand-alone and\nsuitable for the goal of modularizing included services. As a concrete example\nthis document will discuss the Shadowsocks role, the first role that has been\nconverted to this style.\n\nRough Plan\n----------\n\n**Note**: _This is all subject to change as discussion/experience unfolds!_\n\n1. One role at a time, convert it to be stand alone (e.g. create its own\n   firewall rules, do its own client mirroring, etc).\n2. Add an enable flag variable for the role, default to on (e.g. Streisand by\n   default remains ship-it-all-by-default).\n3. Once all roles are converted, add infrastructure for selecting roles (helper\n   script modifications).\n4. Discuss which roles should be enabled by default to perhaps pare down the\n   base install.\n5. Update this documentation.\n\nImplementation\n--------------\n\nEach service has an enable bool variable defined in `playbooks/group_vars/all` to\ncontrol whether the service is going to be included or not. E.g.\n`streisand_shadowsocks_enabled: yes` would include Shadowsocks when provisioning\na server.\n\nEvery Streisand service has to handle the following responsibilities:\n\n* Installing & setting up server software/configurations.\n* Updating firewall rules/access controls.\n* Generating client connection instructions & config files.\n* Mirroring client software.\n\nFor the purpose of connection instructions & client software each service has\ntwo directories it must create & populate:\n\n* One in `/var/www/streisand/` for connection instructions.\n* One in `var/www/streisand/mirror/` for client mirroring.\n\nBoth directories should contain an `index.html` for the available Streisand\nlanguages.\n\nSince responsibilities between services are similar, the self-contained roles\nshould have roughly the same structure (minimized for brevity):\n\n```\nservice/\n├── meta\n│   └── main.yml\n├── tasks\n│   ├── main.yml\n│   ├── docs.yml\n│   ├── firewall.yml\n│   └── mirror.yml\n└── vars\n    ├── main.yml\n    └── mirror.yml\n```\n\n* `meta/main.yml` is used for declaring dependencies (e.g. on `ufw` for\n  firewall rules). Nothing special there!\n\n* `tasks/main.yml` handles the base responsibilities of installing\n  software/configs etc. and includes the subtask files: `docs.yml`,\n  `firewall.yml` and `mirror.yml`.\n\n* `tasks/docs.yml` handles generating connection instructions for the service\n  under its documentation root.\n\n* `tasks/firewall.yml` handles adding `ufw`/`iptables` rules as required by the\n  service.\n\n* `tasks/mirror.yml` handles downloading client software to the service's mirror\n  root and generating any required client install documentation.\n\n* `vars/main.yml` are the variables required for the service's configuration/etc.\n\n* `vars/mirror.yml` are mirror-specific variables (client software versions,\n   download URLs, expected hashes/signatures, etc)\n\nFor Shadowsocks, initially the `ufw` role was responsible for adding a firewall\nrule for the `shadowsocks-libev` port. This created a cross-role dependency\nwhere if the `shadowsocks` role was disabled the `ufw` role would open a port\nunnecessarily, or reference a variable that didn't exist. \n\nTo remove this cross-dependency the `shadowsocks` role was updated to declare\na meta dependency on the generic firewall role (to ensure the package is\ninstalled and ready) in `meta/main.yml`. Then a `tasks/firewall.yml` subtask\nfile was added that uses `ufw` to add the required rules.\n\nSimilarly, the initial `streisand-mirror` role downloaded all of the\nShadowsocks clients for the mirror using a distinct tasks `.yml` with its own\nvariables `.yml`. This made it fairly easy to move the mirror subtasks from\n`streisand-mirror/tasks/shadowsocks.yml` to\n`shadowsocks/tasks/mirror.yml` and `streisand-mirror/vars/shadowsocks.yml` to\n`shadowsocks/vars/mirror.yml`. Now the `shadowsocks` role can be responsible for\npreparing its own client mirror.\n\nGateway & Mirror Indices\n------------------------------\n\nWhile the Gateway & Mirror documentation can be largely agnostic of which\nservices are included in a given build by outsourcing the management of\nsubfolders of `/var/www/streisand` and `/var/www/streisand/mirror` eventually\na consistent set of docs to navigate must be created based on the included\nservices. This is done by conditionally adding links to the connection\ninstruction & mirror indices of each subservice using the enable bool variables\nin the docs and mirror index files.  This is the one place where the \"if\nspaghetti\" is required in order to stitch things together.\n\nAs a concrete example, consider the `shadowsocks` role. Previously the\n`streisand-gateway` and `streisand-mirror` roles were responsible for all\naspects of the Shadowsocks documentation & mirroring.\n\nNow, the `shadowsocks` role creates a `/var/www/streisand/shadowsocks/`\ndirectory and generates an `index.html` in there with connection instructions.\nSimilarly, the client software is mirrored to\n`/var/www/streisand/mirror/shadowsocks/` and an `index.html` is generated in\nthere to list the available clients & their installation instructions.\n\nThe `playbooks/roles/streisand-gateway/templates/index.md.j2` index template can\nconditionally generate a link to the installation instructions:\n\n```\n{% if streisand_shadowsocks_enabled %}\n* [Shadowsocks](/shadowsocks/)\n{% endif %}\n```\n\nSimilarly, the index can conditionally generate a link to the service client mirror:\n\n```\n{% if streisand_shadowsocks_enabled %}\n* [Shadowsocks](/mirror/shadowsocks/)\n{% endif %}\n```\n\nThe same approach is taken in the mirror index template:\n`playbooks/roles/streisand-mirror/templates/mirror-index.md.j2`.\n\nCommon Daemon Config\n------------------------\n\nSome Streisand services have to modify base daemon configurations in order to\nprovide services like DNS/DHCP to interfaces they create. Where possible we\nshould strive to avoid having centralized \"monolith\" configurations and instead\nuse the \"config.d/\" approach to allow modular configuration of these shared\ndaemons. The [original usecase](https://lists.debian.org/debian-devel/2010/04/msg00352.html)\nfor these directories closely matches the situation Streisand is in:\n\n    Once upon a time, most UNIX software was controlled by a single\n    configuration file per software package, and all the configuration details\n    for that package went into that file.  This worked reasonably well when\n    that file was hand-crafted by the system administrator for local needs.\n\n    When distribution packaging became more and more common, it became clear\n    that we needed better ways of forming such configuration files out of\n    multiple fragments, often provided by multiple independent packages.  Each\n    package that needs to configure some shared service should be able to\n    manage only its configuration without having to edit a shared\n    configuration file used by other packages.\n\n    The most common convention adopted was to permit including a directory\n    full of configuration files, where anything dropped into that directory\n    would become active and part of that configuration.\n\nA concrete example of this common daemon problem is the `dnsmasq` service/role\nand its interactions with the `wireguard` and `openvpn` roles. Prior to\nmodularization the `dnsmasq` role made sure the daemon listened on all required\nintefaces by having one `/etc/dnsmasq.conf` config file generated by the\n`dnsmasq` role's `dnsmasq.conf.j2` template. The template had one\n`listen-address` configuration parameter that listed all of the interface\naddresses in a comma-separated form:\n\n```\nlisten-address=127.0.0.1,{{ dnsmasq_openvpn_tcp_ip }},{{ dnsmasq_openvpn_udp_ip }},{{ dnsmasq_wireguard_ip }}\n```\n\nThis meant that if the `openvpn` or `wireguard` roles were disabled/removed the\ntemplate for the `dnsmasq` config would fail due to the missing variables.\n\nThe approach used to fix this was to have the base `/etc/dnsmasq.conf` file\nspecify only `listen-address=127.0.0.1` and update the `openvpn` and `wireguard`\nroles to write their own `listen-address` fragments from a template to their own\nconfig files in `/etc/dnsmasq.d/`. Now the `dnsmasq` role is decoupled from the\n`openvpn` and `wireguard` roles that can be added/removed at will.\n\n"
  },
  {
    "path": "documentation/testing.md",
    "content": "CI Testing\n==========================\n\nStreisand has a `.travis.yml` file that powers [continuous integration\ntests](https://travis-ci.org/jlund/streisand). It works by installing required\ntest tools (e.g. shellcheck) and an Ansible environment on a Ubuntu Trusty\n(14.04) machine.\n\nThe `test.sh` wrapper script\n--------------------------------\n\nThe `test/test.sh` wrapper script is invoked to perform tests and supports\nan argument for specifying what actions should be taken. The following are\nsupported arguments:\n\n* **\"setup\"** prepares the local environment for running a Streisand\n    [LXC](https://linuxcontainers.org/lxc/introduction/) instance. The instance\n    is managed via [LXD](https://linuxcontainers.org/lxd/).\n\n* **\"syntax\"** checks the Streisand playbooks for Ansible syntax errors.\n\n* **\"run\"** runs the CI tests. It assumes the local environment is already\n    prepared from a previous \"setup\" run.\n\n* **\"ci\"** combines \"setup\" and \"run\".\n\n* **\"full\"** performs the same as \"ci\" but additionally adds verbose output to\n    the Ansible run. This is very verbose but can be useful for diagnosing\n    tricky broken builds.\n\n* By **default** the wrapper will run \"syntax\".\n\nWorking around things that won't work in Travis\n-----------------------------------------------\n\nSome playbooks/tasks can't be run in CI because of limitations imposed by the\ncontainerization or Travis. One example of this is installing a Tor relay. To\nwork around this playbooks/tasks that break in CI can be gated on the\n`streisand_ci` variable, which is `true` only for CI runs. Where possible it's\nbest to minimize the use of this variable for conditional execution because we\nwant as much code to be tested as possible!\n\nKernel Modules\n---------------------\n\nBy design LXC containers share the Linux kernel they use with the host machine.\nThis means playbooks/services that require a kernel module (e.g. Libreswan) must\nbuild the kernel module on the host machine.\n\n\nLocal Testing\n==========================\n\nFor local testing Streisand includes a `Vagrantfile` that creates two virtual\nmachines: `streisand-host` and `streisand-client`.\n\nThe `streisand-host` machine is provisioned with the standard Streisand\nplaybooks and replicates a Streisand server created with a cloud provider, but\nrunning on your local computer.\n\nNote that a throwaway SSH key pair is created in the `streisand-host` virtual\nmachine in the location specified in the Anisible variable\n`streisand_ssh_private_key`. This is not needed to SSH into the virtual machine\nusing `vagrant ssh streisand-host` and is only used by the provisioning process.\n\nThe `streisand-client` machine is provisioned specifically to act as a client of\nthe `streisand-host`. It connects to the `streiand-host`'s HTTPS gateway to\ndownload client configuration files that are used by test scripts to ensure that\nservices work \"end-to-end\".\n\nUsing Vagrant for Local Testing\n-------------------------------\n\n1. [Install Vagrant](https://www.vagrantup.com/docs/installation/)\n2. Clone the Streisand repository and enter the directory.\n\n       git clone https://github.com/StreisandEffect/streisand.git && cd streisand\n3. If this is your first time following these steps, create & start the\n   `streisand-host` and `streisand-client` virtual machines with:\n\n       `vagrant up`\n4. To re-run the Streisand playbooks, the virtual machines can be re-provisioned\n   with:\n\n       `vagrant up --provision`\n\nRemote Testing\n==========================\n\nFor testing an existing Streisand server there is a `Vagrantfile.remotetest`\nVagrantifle. As compared to the stock `Vagrantfile` for local testing the\n`Vagrantfile.remotetest` Vagrantfile does not include a `streisand-host`\nmachine. This remotetest variant is useful to \"smoke test\" an existing\nStreisand server, or to provide end-to-end testing of a cloud provisioner.\n\nUsing Vagrant for Remote Testing (Easy Way)\n--------------------------------------------\n\n1. [Install Vagrant](https://www.vagrantup.com/docs/installation/)\n2. Clone the Streisand repository and enter the directory.\n\n       git clone https://github.com/StreisandEffect/streisand.git && cd streisand\n3. Run the `remote_test.sh` helper script and give it the remote server IP\n   & gateway password when prompted:\n\n       ./tests/remote_test.sh\n\nUsing Vagrant for Remote Testing (Hard Way)\n--------------------------------------------\n1. [Install Vagrant](https://www.vagrantup.com/docs/installation/)\n2. Clone the Streisand repository and enter the directory.\n\n       git clone https://github.com/StreisandEffect/streisand.git && cd streisand\n3. Edit `Vagrantfile.remotetest` and replace the `streisand_ip` host variable\n   with the IP of the remote server.\n4. Create the `generated-docs/gateway-password.txt` file with the gateway\n   password of the Streisand server\n5. If this is your first time following these steps, create & start the\n   `streisand-client` virtual machine with:\n\n       VAGRANT_VAGRANTFILE=Vagrantfile.remotetest vagrant up\n4. To re-run the Streisand playbooks, the virtual machines can be re-provisioned\n   with:\n\n       VAGRANT_VAGRANTFILE=Vagrantfile.remotetest vagrant up --provision\n\nMisc Tricks\n==========================\n\n* Uncomment the lines setting the `ansible.verbose` value in the Vagrantfiles to\n  increase the verbosity of the Ansible playbook runs.\n* Skip the `./tests/remote_test.sh` prompts using `printf`:\n\n       STREISAND_SERVER_IP=XX.XX.XX.XX; STREISAND_PASSWORD='gateway-password-goes-here'; printf \"$STREISAND_SERVER_IP\\n$STREISAND_PASSWORD\\n\" | ./tests/remote_test.sh\n"
  },
  {
    "path": "global_vars/default-site.yml",
    "content": "---\n# Site specific Streisand configuration.\n#\n# This file is mutated by the playbooks/customize.yml tasks when a user chooses\n# to customize which Streisand services are installed.\n\n# The SSH private key that Ansible will use to connect to the Streisand node.\n# The associated public key will be used if required when provisioning cloud\n# nodes for the authorized_keys file.\nstreisand_ssh_private_key: \"~/.ssh/id_rsa\"\n\nvpn_clients: 10\n\nstreisand_ad_blocking_enabled: no\nstreisand_openconnect_enabled: yes\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: yes\nstreisand_shadowsocks_v2ray_enabled: no\nstreisand_ssh_forward_enabled: yes\n# By default sshuttle is disabled because it creates a `sshuttle` user that has\n# full shell privileges on the Streisand host\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: yes\nstreisand_tinyproxy_enabled: yes\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: yes\nstreisand_cloudflared_enabled: no\n"
  },
  {
    "path": "global_vars/globals.yml",
    "content": "---\n\n# If using regular cleartext DNS then dnsmasq will set these upstream DNS servers\nupstream_dns_servers:\n  - 1.1.1.1\n  - 1.0.0.1\n\n# If using DNS-over-HTTPS with cloudflared then the upstream servers and queries can be set in:\n# playbooks/roles/cloudflared/defaults/main.yml\n\nstreisand_client_test: no\n\nstreisand_site_vars: \"{{ lookup('env','HOME') }}/.streisand/site.yml\"\n"
  },
  {
    "path": "global_vars/integration/test-site.yml",
    "content": "---\n# Test site configuration for the end-to-end integration tests.\n\n# Don't ask questions\nstreisand_noninteractive: true\nconfirmation: true\nstreisand_domain_var: \"\"\nstreisand_admin_email_var: \"\"\n\n# Take a few extra steps during server provisioning to make the client tests work\nstreisand_client_test: true\n\n# Only services with corresponding tests are enabled.\nstreisand_ad_blocking_enabled: yes\nstreisand_shadowsocks_enabled: yes\nstreisand_ssh_forward_enabled: yes\nstreisand_openvpn_enabled: yes\nstreisand_wireguard_enabled: yes\nstreisand_openconnect_enabled: yes\nstreisand_tor_enabled: no\nstreisand_stunnel_enabled: yes\nstreisand_tinyproxy_enabled: yes\n# TODO(@cpu): The services below need some manner of integration test written\nstreisand_sshuttle_enabled: no\n"
  },
  {
    "path": "global_vars/noninteractive/amazon-site.yml",
    "content": "---\n# Example site specific configuration for a noninteractive AWS deployment.\n#\n# Copy this and edit it as needed before running streisand-new-cloud-server.\n#\n\nstreisand_noninteractive: true\nconfirmation: true\n\n# The SSH private key that Ansible will use to connect to the Streisand node.\n#\n# This will be added to the AWS console and given the name streisand-ssh.\nstreisand_ssh_private_key: \"~/.ssh/id_rsa\"\n\nvpn_clients: 10\n\nstreisand_ad_blocking_enabled: no\nstreisand_openconnect_enabled: yes\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: yes\nstreisand_ssh_forward_enabled: yes\n# By default sshuttle is disabled because it creates a `sshuttle` user that has\n# full shell privileges on the Streisand host\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: yes\nstreisand_tinyproxy_enabled: yes\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: yes\n\n# The AWS region number.\n#\n# See ./playbooks/amazon.yml for numbering.\n#\n# Note: aws_region_var must be a number in quotes, e.g. \"3\" not 3.\naws_region_var: \"16\"\n\n# The VPC and subnet IDs to use. They can be empty strings to indicate that a\n# VPC will not be used.\naws_vpc_id_var: \"\"\naws_vpc_subnet_id_var: \"\"\n\naws_instance_name: streisand\n\n# The AWS credentials to use.\naws_access_key: \"\"\naws_secret_key: \"\"\n\n# Definitions needed for Let's Encrypt HTTPS (or TLS) certificate setup.\n#\n# If these are both left as empty strings, Let's Encrypt will not be set up and\n# a self-signed certificate will be used instead.\n#\n# The domain to use for Let's Encrypt certificate.\nstreisand_domain_var: \"\"\n# The admin email address for Let's Encrypt certificate registration.\nstreisand_admin_email_var: \"\"\n"
  },
  {
    "path": "global_vars/noninteractive/azure-site.yml",
    "content": "---\n# Example site specific configuration for a noninteractive Azure deployment.\n#\n# Copy this and edit it as needed before running streisand-new-cloud-server.\n#\n# Ensure that you have the azure credentials file set up at ~/.azure/credentials\n#\n\nstreisand_noninteractive: true\nconfirmation: true\n\n# The SSH private key that Ansible will use to connect to the Streisand node.\nstreisand_ssh_private_key: \"~/.ssh/id_rsa\"\n\nvpn_clients: 10\n\nstreisand_ad_blocking_enabled: no\nstreisand_openconnect_enabled: yes\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: yes\nstreisand_ssh_forward_enabled: yes\n# By default sshuttle is disabled because it creates a `sshuttle` user that has\n# full shell privileges on the Streisand host\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: yes\nstreisand_tinyproxy_enabled: yes\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: yes\n\n# The region to deploy into.\n#\n# North America:\n#    1: East US             (Virginia)\n#    2: East US 2           (Virginia)\n#    3: Central US          (Iowa)\n#    4: North Central US    (Illinois)\n#    5: South Central US    (Texas)\n#    6: West Central US     (West Central US)\n#    7: West US             (California)\n#    8: West US 2           (West US 2)\n#    9: US Gov Virginia     (Virginia)\n#   10: US Gov Iowa         (Iowa)\n#   11: US DoD East         (US DoD East)\n#   12: US DoD Central      (US DoD Central)\n#   13: Canada East         (Quebec City)\n#   14: Canada Central      (Toronto)\n#\n# South America:\n#   15: Brazil South        (Sao Paulo State)\n#\n# Asia:\n#   16: Southeast Asia      (Singapore)\n#   17: East Asia           (Hong Kong)\n#   18: China East          (Shanghai)\n#   19: China North         (Beijing)\n#   20: Japan East          (Tokyo, Saitama)\n#   21: Japan West          (Osaka)\n#   22: Korea Central       (Seoul)\n#   23: Korea South         (Busan)\n#   24: Central India       (Pune)\n#   25: West India          (Mumbai)\n#   26: South India         (Chennai)\n#\n# Australia:\n#   27: Australia East      (New South Wales)\n#   28: Australia Southeast (Victoria)\n#\n# Europe:\n#   29: North Europe        (Ireland)\n#   30: West Europe         (Netherlands)\n#   31: Germany Central     (Frankfurt)\n#   32: Germany Northeast   (Magdeburg)\n#   33: UK West             (Cardiff)\n#   34: UK South            (London)\n#\n# Note: azure_region_var must be a number in quotes, e.g. \"1\" not 1.\nazure_region_var: \"1\"\n\nazure_instance_name_var: streisand\n\n# Definitions needed for Let's Encrypt HTTPS (or TLS) certificate setup.\n#\n# If these are both left as empty strings, Let's Encrypt will not be set up and\n# a self-signed certificate will be used instead.\n#\n# The domain to use for Let's Encrypt certificate.\nstreisand_domain_var: \"\"\n# The admin email address for Let's Encrypt certificate registration.\nstreisand_admin_email_var: \"\"\n"
  },
  {
    "path": "global_vars/noninteractive/digitalocean-site.yml",
    "content": "---\n# Example site specific configuration for a noninteractive Digital Ocean\n# deployment.\n#\n# Copy this and edit it as needed before running streisand-new-cloud-server.\n#\n\nstreisand_noninteractive: true\nconfirmation: true\n\n# The SSH private key that Ansible will use to connect to the Streisand node.\n#\n# The corresponding public key must be added to the Digital Ocean control panel\n# and the name given to it referenced below in the do_ssh_name variable.\n# The corresponding public key must be uploaded to Digital Ocean and the name\n# given to it referenced below in the do_ssh_name variable.\nstreisand_ssh_private_key: \"~/.ssh/id_rsa\"\n\nvpn_clients: 10\n\nstreisand_ad_blocking_enabled: no\nstreisand_openconnect_enabled: yes\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: yes\nstreisand_ssh_forward_enabled: yes\n# By default sshuttle is disabled because it creates a `sshuttle` user that has\n# full shell privileges on the Streisand host\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: yes\nstreisand_tinyproxy_enabled: yes\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: yes\n\n# The Digital Ocean region number.\n#\n# 1.  Amsterdam        (Datacenter 2)\n# 2.  Amsterdam        (Datacenter 3)\n# 3.  Bangalore\n# 4.  Frankfurt\n# 5.  London\n# 6.  New York         (Datacenter 1)\n# 7.  New York         (Datacenter 2)\n# 8.  New York         (Datacenter 3)\n# 9.  San Francisco    (Datacenter 1)\n# 10. San Francisco    (Datacenter 2)\n# 11. Singapore\n# 12. Toronto\n#\n# Note: do_region must be a number in quotes, e.g. \"2\" not 2.\ndo_region: \"2\"\n\ndo_server_name: streisand\n\n# Add the Digital Ocean access token here.\ndo_access_token_entry: \"\"\n\n# The name given to the key in the DigitalOcean control panel.\ndo_ssh_name: streisand\n\n# Definitions needed for Let's Encrypt HTTPS (or TLS) certificate setup.\n#\n# If these are both left as empty strings, Let's Encrypt will not be set up and\n# a self-signed certificate will be used instead.\n#\n# The domain to use for Let's Encrypt certificate.\nstreisand_domain_var: \"\"\n# The admin email address for Let's Encrypt certificate registration.\nstreisand_admin_email_var: \"\"\n"
  },
  {
    "path": "global_vars/noninteractive/google-site.yml",
    "content": "---\n# Example site specific configuration for a noninteractive Google Compute Engine\n# deployment.\n#\n# Copy this and edit it as needed before running streisand-new-cloud-server.\n#\n\nstreisand_noninteractive: true\nconfirmation: true\n\n# The SSH private key that Ansible will use to connect to the Streisand node.\nstreisand_ssh_private_key: \"~/.ssh/id_rsa\"\n\nvpn_clients: 10\n\nstreisand_ad_blocking_enabled: no\nstreisand_openconnect_enabled: yes\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: yes\nstreisand_ssh_forward_enabled: yes\n# By default sshuttle is disabled because it creates a `sshuttle` user that has\n# full shell privileges on the Streisand host\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: yes\nstreisand_tinyproxy_enabled: yes\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: yes\n\n# Server location:\n#\n# 1. Central US            \"us-central1-a\"\n# 2. Central US            \"us-central1-b\"\n# 3. Central US            \"us-central1-c\"\n# 4. Central US            \"us-central1-f\"\n# 5. Eastern US            \"us-east4-a\"\n# 6. Eastern US            \"us-east4-b\"\n# 7. Eastern US            \"us-east4-c\"\n# 8. Eastern US            \"us-east1-b\"\n# 9. Eastern US            \"us-east1-c\"\n# 10. Eastern US           \"us-east1-d\"\n# 11. Western US           \"us-west1-a\"\n# 12. Western US           \"us-west1-b\"\n# 13. Western US           \"us-west1-c\"\n# 14. Western Europe       \"europe-west1-b\"\n# 15. Western Europe       \"europe-west1-c\"\n# 16. Western Europe       \"europe-west1-d\"\n# 17. Western Europe       \"europe-west2-a\"\n# 18. Western Europe       \"europe-west2-b\"\n# 19. Western Europe       \"europe-west2-c\"\n# 20. Western Europe       \"europe-west3-a\"\n# 21. Western Europe       \"europe-west3-b\"\n# 22. Western Europe       \"europe-west3-c\"\n# 23. Western Europe       \"europe-west4-a\"\n# 24. Western Europe       \"europe-west4-b\"\n# 25. Western Europe       \"europe-west4-c\"\n# 26. East Asia            \"asia-east1-a\"\n# 27. East Asia            \"asia-east1-b\"\n# 28. East Asia            \"asia-east1-c\"\n# 29. Northeast Asia       \"asia-northeast1-a\"\n# 30. Northeast Asia       \"asia-northeast1-b\"\n# 31. Northeast Asia       \"asia-northeast1-c\"\n# 32. South Asia           \"asia-south1-a\"\n# 33. South Asia           \"asia-south1-b\"\n# 34. South Asia           \"asia-south1-c\"\n# 35. Southeast Asia       \"asia-southeast1-a\"\n# 36. Southeast Asia       \"asia-southeast1-b\"\n# 37. Southeast Australia  \"australia-southeast1-a\"\n# 38. Southeast Australia  \"australia-southeast1-b\"\n# 39. Southeast Australia  \"australia-southeast1-c\"\n#\n\n# Named zones are more robust if you use non-interactive deployments. You can still use\n# the numbered index, however the number can change, whereas the name will stay the same.\n# Keep the idx variable non-empty if you use named zones.\n\ngce_zone_idx: \"do not remove this var if you have defined gce_zone\"\ngce_zone: us-central1-c\n\ngce_server_name: streisand\n\n# The full path of your unique service account credentials file. See:\n# https://docs.ansible.com/ansible/guide_gce.html#credentials\n# https://support.google.com/cloud/answer/6158849?hl=en&ref_topic=6262490#serviceaccounts\ngce_json_file_location: \"\"\n\n# Definitions needed for Let's Encrypt HTTPS (or TLS) certificate setup.\n#\n# If these are both left as empty strings, Let's Encrypt will not be set up and\n# a self-signed certificate will be used instead.\n#\n# The domain to use for Let's Encrypt certificate.\nstreisand_domain_var: \"\"\n# The admin email address for Let's Encrypt certificate registration.\nstreisand_admin_email_var: \"\"\n"
  },
  {
    "path": "global_vars/noninteractive/linode-site.yml",
    "content": "---\n# Example site specific configuration for a noninteractive Linode deployment.\n#\n# Copy this and edit it as needed before running streisand-new-cloud-server.\n#\n\nstreisand_noninteractive: true\nconfirmation: true\n\n# The SSH private key that Ansible will use to connect to the Streisand node.\nstreisand_ssh_private_key: \"~/.ssh/id_rsa\"\n\nvpn_clients: 10\n\nstreisand_ad_blocking_enabled: no\nstreisand_openconnect_enabled: yes\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: yes\nstreisand_ssh_forward_enabled: yes\n# By default sshuttle is disabled because it creates a `sshuttle` user that has\n# full shell privileges on the Streisand host\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: yes\nstreisand_tinyproxy_enabled: yes\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: yes\n\n# Choose the server location.\n# 1. Atlanta\n# 2. Dallas\n# 3. Frankfurt\n# 4. Fremont\n# 5. London\n# 6. Newark\n# 7. Singapore\n# 8. Tokyo\n# 9. Tokyo 2\n#\n# Note: linode_datacenter must be a number in quotes, e.g. \"7\" not 7.\nlinode_datacenter: \"7\"\n\nlinode_server_name: streisand\n\n# Obtain the API key from the Linode Manager console.\nlinode_api_key: \"\"\n\n# Definitions needed for Let's Encrypt HTTPS (or TLS) certificate setup.\n#\n# If these are both left as empty strings, Let's Encrypt will not be set up and\n# a self-signed certificate will be used instead.\n#\n# The domain to use for Let's Encrypt certificate.\nstreisand_domain_var: \"\"\n# The admin email address for Let's Encrypt certificate registration.\nstreisand_admin_email_var: \"\"\n"
  },
  {
    "path": "global_vars/noninteractive/local-site.yml",
    "content": "---\n# Example site specific configuration for a noninteractive local machine\n# deployment.\n#\n# Copy this and edit it as needed before running streisand-local.\n#\n\nstreisand_noninteractive: true\nconfirmation: true\n\n# Change this to the location of a key on the local system.\nstreisand_ssh_private_key: \"~/.ssh/id_rsa\"\n\nvpn_clients: 10\n\nstreisand_ad_blocking_enabled: no\nstreisand_openconnect_enabled: yes\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: yes\nstreisand_ssh_forward_enabled: yes\n# By default sshuttle is disabled because it creates a `sshuttle` user that has\n# full shell privileges on the Streisand host\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: yes\nstreisand_tinyproxy_enabled: yes\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: yes\n\n# Definitions needed for Let's Encrypt HTTPS (or TLS) certificate setup.\n#\n# If these are both left as empty strings, Let's Encrypt will not be set up and\n# a self-signed certificate will be used instead.\n#\n# The domain to use for Let's Encrypt certificate.\nstreisand_domain_var: \"\"\n# The admin email address for Let's Encrypt certificate registration.\nstreisand_admin_email_var: \"\"\n"
  },
  {
    "path": "global_vars/noninteractive/rackspace-site.yml",
    "content": "---\n# Example site specific configuration for a noninteractive Rackspace deployment.\n#\n# Copy this and edit it as needed before running streisand-new-cloud-server.\n#\n\nstreisand_noninteractive: true\nconfirmation: true\n\n# The SSH private key that Ansible will use to connect to the Streisand node.\nstreisand_ssh_private_key: \"~/.ssh/id_rsa\"\n\nvpn_clients: 10\n\nstreisand_ad_blocking_enabled: no\nstreisand_openconnect_enabled: yes\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: yes\nstreisand_ssh_forward_enabled: yes\n# By default sshuttle is disabled because it creates a `sshuttle` user that has\n# full shell privileges on the Streisand host\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: yes\nstreisand_tinyproxy_enabled: yes\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: yes\n\n# Choose the region to deploy into.\n#\n# 1. Chicago\n# 2. Dallas\n# 3. Hong Kong\n# 4. Northern Virginia\n# 5. Sydney\n#\n# Note: rackspace_region must be a number in quotes, e.g. \"1\" not 1.\nrackspace_region: \"1\"\n\nrackspace_server_name: streisand\n\n# Obtain these credentials from the Rackspace Cloud Control Panel.\nrackspace_username: \"\"\nrackspace_api_key: \"\"\n\n# Definitions needed for Let's Encrypt HTTPS (or TLS) certificate setup.\n#\n# If these are both left as empty strings, Let's Encrypt will not be set up and\n# a self-signed certificate will be used instead.\n#\n# The domain to use for Let's Encrypt certificate.\nstreisand_domain_var: \"\"\n# The admin email address for Let's Encrypt certificate registration.\nstreisand_admin_email_var: \"\"\n"
  },
  {
    "path": "inventories/inventory",
    "content": "[localhost]\nlocalhost ansible_connection=local ansible_python_interpreter=python3\n\n# Uncomment the following lines and update the IP address if you would\n# like to use Streisand to configure a server that is already running\n# (e.g. a server at a provider not natively supported by Streisand).\n#\n# Multiple servers can be configured simultaneously if multiple IP\n# addresses are defined.\n#\n# If you already have SSH fingerprints for the hosts you are configuring\n# (e.g. using `ssh-keyscan`) then you should also comment out the\n# 'host_key_checking = False' line in the ansible.cfg file. That setting\n# is only sensible and convenient when connecting to a brand-new host.\n#\n# [streisand-host]\n# 255.255.255.255\n#\n# If the SSH user to be used to login is not \"root\", specify it here with\n# the ansible_user directive. Streisand will sudo automatically. If sudo\n# requires a password, use the --ask-become-pass command line option.\n#\n# [streisand-host]\n# 255.255.255.255 ansible_user=ubuntu\n"
  },
  {
    "path": "inventories/inventory-local-provision",
    "content": "# inventory-local-provision is a pre-built inventory file useful for doing an\n# advanced local install of Streisand where the server running Ansible is the\n# server that will be configured.\n\n# Settings for the provisioning process\n[localhost]\n\n# This must specify the Python interpreter when provisioning, because\n# \"python\" may be in, for example, a virtualenv without python-apt.\nlocalhost ansible_connection=local ansible_python_interpreter=/usr/bin/python\n\n# Settings for the Streisand host that will be provisioned\n[streisand-host]\n# If you need to override the name of the server (e.g. because the system\n# hostname is not the desired server name for documentation/etc) then add a host\n# var named \"streisand_server_name\" with the desired value.\nlocalhost ansible_connection=local streisand_noninteractive=true\n"
  },
  {
    "path": "library/digital_ocean_droplet.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright: Ansible Project\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\n# Origin: @jackivanov's PR#61643 for ansible:\n# https://github.com/ansible/ansible/blob/b8b416d30282d6aef4b3ffb7fcb01a0dd2da9f59/lib/ansible/modules/cloud/digital_ocean/digital_ocean_droplet.py\n\n# This will be removed on fix to upstream\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: digital_ocean_droplet\nshort_description: Create and delete a DigitalOcean droplet\ndescription:\n     - Create and delete a droplet in DigitalOcean and optionally wait for it to be active.\nversion_added: \"2.8\"\nauthor: \"Gurchet Rai (@gurch101)\"\noptions:\n  state:\n    description:\n     - Indicate desired state of the target.\n    default: present\n    choices: ['present', 'absent']\n  id:\n    description:\n     - Numeric, the droplet id you want to operate on.\n    aliases: ['droplet_id']\n  name:\n    description:\n     - String, this is the name of the droplet - must be formatted by hostname rules.\n  unique_name:\n    description:\n     - require unique hostnames.  By default, DigitalOcean allows multiple hosts with the same name.  Setting this to \"yes\" allows only one host\n       per name.  Useful for idempotence.\n    default: False\n    type: bool\n  size:\n    description:\n     - This is the slug of the size you would like the droplet created with.\n    aliases: ['size_id']\n  image:\n    description:\n     - This is the slug of the image you would like the droplet created with.\n    aliases: ['image_id']\n  region:\n    description:\n     - This is the slug of the region you would like your server to be created in.\n    aliases: ['region_id']\n  ssh_keys:\n    description:\n     - array of SSH key (numeric) ID that you would like to be added to the server.\n    required: False\n  private_networking:\n    description:\n     - add an additional, private network interface to droplet for inter-droplet communication.\n    default: False\n    type: bool\n  user_data:\n    description:\n      - opaque blob of data which is made available to the droplet\n    required: False\n  ipv6:\n    description:\n      - enable IPv6 for your droplet.\n    required: False\n    default: False\n    type: bool\n  wait:\n    description:\n     - Wait for the droplet to be active before returning.  If wait is \"no\" an ip_address may not be returned.\n    required: False\n    default: True\n    type: bool\n  wait_timeout:\n    description:\n     - How long before wait gives up, in seconds, when creating a droplet.\n    default: 120\n  backups:\n    description:\n     - indicates whether automated backups should be enabled.\n    required: False\n    default: False\n    type: bool\n  monitoring:\n    description:\n     - indicates whether to install the DigitalOcean agent for monitoring.\n    required: False\n    default: False\n    type: bool\n  tags:\n    description:\n     - List, A list of tag names as strings to apply to the Droplet after it is created. Tag names can either be existing or new tags.\n    required: False\n  volumes:\n    description:\n     - List, A list including the unique string identifier for each Block Storage volume to be attached to the Droplet.\n    required: False\n  oauth_token:\n    description:\n     - DigitalOcean OAuth token. Can be specified in C(DO_API_KEY), C(DO_API_TOKEN), or C(DO_OAUTH_TOKEN) environment variables\n    aliases: ['API_TOKEN']\n    required: True\nrequirements:\n  - \"python >= 2.6\"\n'''\n\n\nEXAMPLES = '''\n- name: create a new droplet\n  digital_ocean_droplet:\n    state: present\n    name: mydroplet\n    oauth_token: XXX\n    size: 2gb\n    region: sfo1\n    image: ubuntu-16-04-x64\n    wait_timeout: 500\n  register: my_droplet\n\n- debug:\n    msg: \"ID is {{ my_droplet.data.droplet.id }}, IP is {{ my_droplet.data.ip_address }}\"\n\n- name: ensure a droplet is present\n  digital_ocean_droplet:\n    state: present\n    id: 123\n    name: mydroplet\n    oauth_token: XXX\n    size: 2gb\n    region: sfo1\n    image: ubuntu-16-04-x64\n    wait_timeout: 500\n'''\n\n\nRETURN = '''\n# Digital Ocean API info https://developers.digitalocean.com/documentation/v2/#droplets\ndata:\n    description: a DigitalOcean Droplet\n    returned: changed\n    type: dict\n    sample: {\n        \"ip_address\": \"104.248.118.172\",\n        \"ipv6_address\": \"2604:a880:400:d1::90a:6001\",\n        \"private_ipv4_address\": \"10.136.122.141\",\n        \"droplet\": {\n            \"id\": 3164494,\n            \"name\": \"example.com\",\n            \"memory\": 512,\n            \"vcpus\": 1,\n            \"disk\": 20,\n            \"locked\": true,\n            \"status\": \"new\",\n            \"kernel\": {\n                \"id\": 2233,\n                \"name\": \"Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic\",\n                \"version\": \"3.13.0-37-generic\"\n            },\n            \"created_at\": \"2014-11-14T16:36:31Z\",\n            \"features\": [\"virtio\"],\n            \"backup_ids\": [],\n            \"snapshot_ids\": [],\n            \"image\": {},\n            \"volume_ids\": [],\n            \"size\": {},\n            \"size_slug\": \"512mb\",\n            \"networks\": {},\n            \"region\": {},\n            \"tags\": [\"web\"]\n        }\n    }\n'''\n\nimport time\nimport json\nfrom ansible.module_utils.basic import AnsibleModule, env_fallback\nfrom ansible.module_utils.digital_ocean import DigitalOceanHelper\n\n\nclass DODroplet(object):\n    def __init__(self, module):\n        self.rest = DigitalOceanHelper(module)\n        self.module = module\n        self.wait = self.module.params.pop('wait', True)\n        self.wait_timeout = self.module.params.pop('wait_timeout', 120)\n        self.unique_name = self.module.params.pop('unique_name', False)\n        # pop the oauth token so we don't include it in the POST data\n        self.module.params.pop('oauth_token')\n\n    def get_by_id(self, droplet_id):\n        if not droplet_id:\n            return None\n        response = self.rest.get('droplets/{0}'.format(droplet_id))\n        json_data = response.json\n        if response.status_code == 200:\n            return json_data\n        return None\n\n    def get_by_name(self, droplet_name):\n        if not droplet_name:\n            return None\n        page = 1\n        while page is not None:\n            response = self.rest.get('droplets?page={0}'.format(page))\n            json_data = response.json\n            if response.status_code == 200:\n                for droplet in json_data['droplets']:\n                    if droplet['name'] == droplet_name:\n                        return {'droplet': droplet}\n                if 'links' in json_data and 'pages' in json_data['links'] and 'next' in json_data['links']['pages']:\n                    page += 1\n                else:\n                    page = None\n        return None\n\n    def get_addresses(self, data):\n        \"\"\"\n         Expose IP addresses as their own property allowing users extend to additional tasks\n        \"\"\"\n        _data = data\n        for k, v in data.items():\n            setattr(self, k, v)\n        networks = _data['droplet']['networks']\n        for network in networks.get('v4', []):\n            if network['type'] == 'public':\n                _data['ip_address'] = network['ip_address']\n            else:\n                _data['private_ipv4_address'] = network['ip_address']\n        for network in networks.get('v6', []):\n            if network['type'] == 'public':\n                _data['ipv6_address'] = network['ip_address']\n            else:\n                _data['private_ipv6_address'] = network['ip_address']\n        return _data\n\n    def get_droplet(self):\n        json_data = self.get_by_id(self.module.params['id'])\n        if not json_data and self.unique_name:\n            json_data = self.get_by_name(self.module.params['name'])\n        return json_data\n\n    def create(self):\n        json_data = self.get_droplet()\n        droplet_data = None\n        if json_data:\n            droplet_data = self.get_addresses(json_data)\n            self.module.exit_json(changed=False, data=droplet_data)\n        if self.module.check_mode:\n            self.module.exit_json(changed=True)\n        data = self.module.params\n        try:\n            del data['id']\n        except KeyError:\n            pass\n        response = self.rest.post('droplets', data=data)\n        json_data = response.json\n        if response.status_code >= 400:\n            self.module.fail_json(changed=False, msg=json_data['message'])\n        if self.wait:\n            json_data = self.ensure_power_on(json_data['droplet']['id'])\n            droplet_data = self.get_addresses(json_data)\n        self.module.exit_json(changed=True, data=droplet_data)\n\n    def delete(self):\n        json_data = self.get_droplet()\n        if json_data:\n            if self.module.check_mode:\n                self.module.exit_json(changed=True)\n            response = self.rest.delete('droplets/{0}'.format(json_data['droplet']['id']))\n            json_data = response.json\n            if response.status_code == 204:\n                self.module.exit_json(changed=True, msg='Droplet deleted')\n            self.module.fail_json(changed=False, msg='Failed to delete droplet')\n        else:\n            self.module.exit_json(changed=False, msg='Droplet not found')\n\n    def ensure_power_on(self, droplet_id):\n        end_time = time.time() + self.wait_timeout\n        while time.time() < end_time:\n            response = self.rest.get('droplets/{0}'.format(droplet_id))\n            json_data = response.json\n            if json_data['droplet']['status'] == 'active':\n                return json_data\n            time.sleep(min(2, end_time - time.time()))\n        self.module.fail_json(msg='Wait for droplet powering on timeout')\n\n\ndef core(module):\n    state = module.params.pop('state')\n    droplet = DODroplet(module)\n    if state == 'present':\n        droplet.create()\n    elif state == 'absent':\n        droplet.delete()\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            state=dict(choices=['present', 'absent'], default='present'),\n            oauth_token=dict(\n                aliases=['API_TOKEN'],\n                no_log=True,\n                fallback=(env_fallback, ['DO_API_TOKEN', 'DO_API_KEY', 'DO_OAUTH_TOKEN'])\n            ),\n            name=dict(type='str'),\n            size=dict(aliases=['size_id']),\n            image=dict(aliases=['image_id']),\n            region=dict(aliases=['region_id']),\n            ssh_keys=dict(type='list'),\n            private_networking=dict(type='bool', default=False),\n            backups=dict(type='bool', default=False),\n            monitoring=dict(type='bool', default=False),\n            id=dict(aliases=['droplet_id'], type='int'),\n            user_data=dict(default=None),\n            ipv6=dict(type='bool', default=False),\n            volumes=dict(type='list'),\n            tags=dict(type='list'),\n            wait=dict(type='bool', default=True),\n            wait_timeout=dict(default=120, type='int'),\n            unique_name=dict(type='bool', default=False),\n        ),\n        required_one_of=(\n            ['id', 'name'],\n        ),\n        required_if=([\n            ('state', 'present', ['name', 'size', 'image', 'region']),\n        ]),\n        supports_check_mode=True,\n    )\n\n    core(module)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "playbooks/amazon.yml",
    "content": "---\n- name: Provision the EC2 Server\n# ==============================\n  hosts: localhost\n  connection: local\n  gather_facts: yes\n\n  vars:\n    # The region dict is generated from ./util/print-aws-regions.py\n    regions:\n      \"1\": \"ap-east-1\"\n      \"2\": \"ap-northeast-1\"\n      \"3\": \"ap-northeast-2\"\n      \"4\": \"ap-northeast-3\"\n      \"5\": \"ap-south-1\"\n      \"6\": \"ap-southeast-1\"\n      \"7\": \"ap-southeast-2\"\n      \"8\": \"ca-central-1\"\n      \"9\": \"eu-central-1\"\n      \"10\": \"eu-north-1\"\n      \"11\": \"eu-west-1\"\n      \"12\": \"eu-west-2\"\n      \"13\": \"eu-west-3\"\n      \"14\": \"sa-east-1\"\n      \"15\": \"us-east-1\"\n      \"16\": \"us-east-2\"\n      \"17\": \"us-west-1\"\n      \"18\": \"us-west-2\"\n\n  # These variable files are included so the ec2-security-group role\n  # knows which ports to open\n  vars_files:\n    - roles/openconnect/defaults/main.yml\n    - roles/openvpn/defaults/main.yml\n    - roles/shadowsocks/defaults/main.yml\n    - roles/ssh/defaults/main.yml\n    - roles/lets-encrypt/vars/main.yml\n    - roles/streisand-gateway/defaults/main.yml\n    - roles/stunnel/defaults/main.yml\n    - roles/tor-bridge/defaults/main.yml\n    - roles/wireguard/defaults/main.yml\n\n  vars_prompt:\n    # The region prompt is generated from ./util/print-aws-regions.py\n    # Don't forget to update the default if it changes.\n    - name: \"aws_region_var\"\n      prompt: |\n        In what region should the server be located?\n           1. ap-east-1       Asia Pacific   (Hong Kong)\n           2. ap-northeast-1  Asia Pacific   (Tokyo)\n           3. ap-northeast-2  Asia Pacific   (Seoul)\n           4. ap-northeast-3  Asia Pacific   (Osaka-Local)\n           5. ap-south-1      Asia Pacific   (Mumbai)\n           6. ap-southeast-1  Asia Pacific   (Singapore)\n           7. ap-southeast-2  Asia Pacific   (Sydney)\n           8. ca-central-1    Canada         (Central)\n           9. eu-central-1    EU             (Frankfurt)\n          10. eu-north-1      EU             (Stockholm)\n          11. eu-west-1       EU             (Ireland)\n          12. eu-west-2       EU             (London)\n          13. eu-west-3       EU             (Paris)\n          14. sa-east-1       South America  (São Paulo)\n          15. us-east-1       US East        (N. Virginia)\n          16. us-east-2       US East        (Ohio)\n          17. us-west-1       US West        (N. California)\n          18. us-west-2       US West        (Oregon)\n        Please choose the number of your region. Press enter for default (#16) region.\n      default: \"16\"\n      private: no\n\n    - name: \"aws_vpc_id_var\"\n      prompt: |\n\n        In which VPC would you like to create the server and security group\n        (e.g. vpc-89d740ee)?\n\n        Press enter to use the default VPC.\n      private: no\n\n    - name: \"aws_vpc_subnet_id_var\"\n      prompt: |\n\n        From which subnet should the server receive an address (e.g. subnet-78d9a232)?\n\n        Press enter to use the default subnet.\n      private: no\n\n    - name: \"aws_instance_name\"\n      prompt: \"\\nWhat should the server be named? Press enter for default (streisand).\\n\"\n      default: \"streisand\"\n      private: no\n\n    - name: \"aws_access_key\"\n      prompt: \"\\n\\nThe following information can be found in the IAM Management Console.\\nhttps://console.aws.amazon.com/iam/home?#security_credential\\n\\nWhat is your AWS Access Key ID?\\n\"\n      private: no\n\n    - name: \"aws_secret_key\"\n      prompt: \"\\nWhat is your AWS Secret Access Key?\\n\"\n      private: no\n\n    - name: \"confirmation\"\n      prompt: \"\\nStreisand will now set up your server. This process usually takes around ten minutes. Press Enter to begin setup...\\n\"\n\n  pre_tasks:\n    - name: Set the AWS Region fact\n      set_fact:\n        aws_region: \"{{ regions[aws_region_var] }}\"\n\n    - name: Set the AWS VPC ID fact\n      set_fact:\n        aws_vpc_id: \"{{ aws_vpc_id_var }}\"\n      when: aws_vpc_id_var != \"\"\n\n    - name: Set the AWS VPC Subnet ID fact\n      set_fact:\n        aws_vpc_subnet_id: \"{{ aws_vpc_subnet_id_var }}\"\n      when: aws_vpc_subnet_id_var != \"\"\n\n  roles:\n    - genesis-amazon\n\n- import_playbook: ssh-setup.yml\n- import_playbook: cloud-status.yml\n- import_playbook: python.yml\n- import_playbook: ec2-metadata-instance.yml\n- import_playbook: streisand.yml\n...\n"
  },
  {
    "path": "playbooks/azure.yml",
    "content": "---\n- name: Provision the Azure Server (Resource Manager mode)\n# ========================================================\n  hosts: localhost\n  connection: local\n  gather_facts: yes\n\n  vars:\n    regions:\n      \"1\": \"eastus\"\n      \"2\": \"eastus2\"\n      \"3\": \"centralus\"\n      \"4\": \"northcentralus\"\n      \"5\": \"southcentralus\"\n      \"6\": \"westcentralus\"\n      \"7\": \"westus\"\n      \"8\": \"westus2\"\n      \"9\": \"usgovvirginia\"\n      \"10\": \"usgoviowa\"\n      \"11\": \"usdodeast\"\n      \"12\": \"usdodcentral\"\n      \"13\": \"canadaeast\"\n      \"14\": \"canadacentral\"\n      \"15\": \"brazilsouth\"\n      \"16\": \"southeastasia\"\n      \"17\": \"eastasia\"\n      \"18\": \"chinaeast\"\n      \"19\": \"chinanorth\"\n      \"20\": \"japaneast\"\n      \"21\": \"japanwest\"\n      \"22\": \"koreacentral\"\n      \"23\": \"koreasouth\"\n      \"24\": \"centralindia\"\n      \"25\": \"westindia\"\n      \"26\": \"southindia\"\n      \"27\": \"australiaeast\"\n      \"28\": \"australiasoutheast\"\n      \"29\": \"australiacentral\"\n      \"30\": \"australiacentral2\"\n      \"31\": \"northeurope\"\n      \"32\": \"westeurope\"\n      \"33\": \"germanycentral\"\n      \"34\": \"germanynortheast\"\n      \"35\": \"ukwest\"\n      \"36\": \"uksouth\"\n      \"37\": \"francecentral\"\n      \"38\": \"francesouth\"\n\n  # These variable files are included so the azure-security-group role\n  # knows which ports to open\n  vars_files:\n    - roles/openconnect/defaults/main.yml\n    - roles/openvpn/defaults/main.yml\n    - roles/shadowsocks/defaults/main.yml\n    - roles/ssh/defaults/main.yml\n    - roles/lets-encrypt/vars/main.yml\n    - roles/streisand-gateway/defaults/main.yml\n    - roles/stunnel/defaults/main.yml\n    - roles/tor-bridge/defaults/main.yml\n    - roles/wireguard/defaults/main.yml\n\n  vars_prompt:\n    - name: \"azure_region_var\"\n      prompt: >\n        What region should the server be located in?\n\n          North America:\n             1: East US             (Virginia)\n             2: East US 2           (Virginia)\n             3: Central US          (Iowa)\n             4: North Central US    (Illinois)\n             5: South Central US    (Texas)\n             6: West Central US     (West Central US)\n             7: West US             (California)\n             8: West US 2           (West US 2)\n             9: US Gov Virginia     (Virginia)\n            10: US Gov Iowa         (Iowa)\n            11: US DoD East         (US DoD East)\n            12: US DoD Central      (US DoD Central)\n            13: Canada East         (Quebec City)\n            14: Canada Central      (Toronto)\n\n          South America:\n            15: Brazil South        (Sao Paulo State)\n\n          Asia:\n            16: Southeast Asia      (Singapore)\n            17: East Asia           (Hong Kong)\n            18: China East          (Shanghai)\n            19: China North         (Beijing)\n            20: Japan East          (Tokyo, Saitama)\n            21: Japan West          (Osaka)\n            22: Korea Central       (Seoul)\n            23: Korea South         (Busan)\n            24: Central India       (Pune)\n            25: West India          (Mumbai)\n            26: South India         (Chennai)\n\n          Australia:\n            27: Australia East      (New South Wales)\n            28: Australia Southeast     (Victoria)\n            29: Austrailia Central       (Canberra)\n            30: Austrailia Central 2    (Canberra)\n\n          Europe:\n            31: North Europe        (Ireland)\n            32: West Europe         (Netherlands)\n            33: Germany Central     (Frankfurt)\n            34: Germany Northeast   (Magdeburg)\n            35: UK West             (Cardiff)\n            36: UK South            (London)\n            37: France Central    (Paris)\n            38: France South      (Marseille)\n\n        Please choose the number of your region: Press enter for default (#1) region.\n      default: \"1\"\n      private: no\n\n    - name: \"azure_instance_name_var\"\n      prompt: \"\\nWhat should the server be named? Press enter for default (streisand).\\n\"\n      default: \"streisand\"\n      private: no\n\n    - name: \"confirmation_credentials\"\n      prompt: \"\\nEnsure that you have the azure credentials file: ~/.azure/credentials \\nDetails on generating this can be found at https://github.com/StreisandEffect/streisand/blob/master/documentation/AZURE.md\"\n\n    - name: \"confirmation\"\n      prompt: \"\\nStreisand will now set up your server: This process usually takes around ten minutes: Press Enter to begin setup...\\n\"\n\n  pre_tasks:\n    - name: Set the Azure Region fact\n      set_fact:\n        azure_region: \"{{ regions[azure_region_var] }}\"\n\n    - name: Set the Azure Instance Name fact\n      set_fact:\n        azure_instance_name: \"{{ azure_instance_name_var | regex_replace('\\\\s', '_') }}\"\n\n  roles:\n    - genesis-azure\n\n- import_playbook: ssh-setup.yml\n- import_playbook: cloud-status.yml\n- import_playbook: streisand.yml\n...\n"
  },
  {
    "path": "playbooks/cloud-status.yml",
    "content": "---\n- name: Checking instance status\n# =========================================\n  hosts: streisand-host\n  gather_facts: no\n\n  remote_user: \"root\"\n  become: true\n\n  tasks:\n    - name: Wait for cloud-init to complete\n      raw: bash -c \"for i in {1..30}; do if [ -f /var/lib/cloud/instance/boot-finished ]; then exit 0; fi; sleep 1; done; exit 1;\"\n      register: result\n      changed_when: False\n      failed_when: result.rc != 0\n...\n"
  },
  {
    "path": "playbooks/customize.yml",
    "content": "---\n- name: Customize enabled Streisand services\n  hosts: localhost\n  gather_facts: no\n\n  vars_prompt:\n    - name: streisand_ssh_private_key\n      prompt: \"Enter the path to your SSH private key, or press enter for default \"\n      default: \"~/.ssh/id_rsa\"\n      private: no\n    - name: vpn_clients\n      prompt: \"How many VPN client profiles should be generated per-service (min: 1 max: 20)? Press enter for default \"\n      default: 10\n      private: no\n    - name: streisand_ad_blocking_enabled\n      prompt: \"Enable DNS-based ad-blocking? Press enter for default \"\n      default: \"no\"\n      private: no\n    - name: streisand_openconnect_enabled\n      prompt: \"Enable OpenConnect? Press enter for default \"\n      default: \"yes\"\n      private: no\n    - name: streisand_openvpn_enabled\n      prompt: \"Enable OpenVPN? Press enter for default \"\n      default: \"yes\"\n      private: no\n    - name: streisand_stunnel_enabled\n      prompt: \"Enable stunnel service (only allowed for OpenVPN)? Press enter for default \"\n      default: \"yes\"\n      private: no\n    - name: streisand_shadowsocks_enabled\n      prompt: \"Enable Shadowsocks? Press enter for default \"\n      default: \"yes\"\n      private: no\n    - name: streisand_shadowsocks_v2ray_enabled\n      prompt: \"Enable v2ray-plugin for Shadowsocks? Press enter for default \"\n      default: \"no\"\n      private: no\n    - name: streisand_ssh_forward_enabled\n      prompt: \"Enable SSH Forward User? (Note: A SOCKS proxy only user will be added, no shell). Press enter for default \"\n      default: \"yes\"\n      private: no\n    - name: streisand_sshuttle_enabled\n      prompt: \"Enable sshuttle? (Note: A full shell access user will be added) Press enter for default \"\n      default: \"no\"\n      private: no\n    - name: streisand_tinyproxy_enabled\n      prompt: \"Enable tinyproxy? Press enter for default \"\n      default: \"yes\"\n      private: no\n    - name: streisand_tor_enabled\n      prompt: \"Enable Tor? Press enter for default \"\n      default: \"no\"\n      private: no\n    - name: streisand_wireguard_enabled\n      prompt: \"Enable WireGuard? Press enter for default \"\n      default: \"yes\"\n      private: no\n    - name: streisand_cloudflared_enabled\n      prompt: \"[BROKEN ON SOME PROVIDERS, including AWS] Enable DNS-over-HTTPS (cloudflared)? Press enter for default \"\n      default: \"no\"\n      private: no\n\n  tasks:\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_ssh_private_key: .*$\"\n        line: \"streisand_ssh_private_key: {{ streisand_ssh_private_key }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^vpn_clients: [\\\\d]+$\"\n        line: \"vpn_clients: {{ vpn_clients }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_ad_blocking_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_ad_blocking_enabled: {{ streisand_ad_blocking_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_openconnect_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_openconnect_enabled: {{ streisand_openconnect_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_openvpn_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_openvpn_enabled: {{ streisand_openvpn_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_shadowsocks_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_shadowsocks_enabled: {{ streisand_shadowsocks_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_shadowsocks_v2ray_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_shadowsocks_v2ray_enabled: {{ streisand_shadowsocks_v2ray_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_ssh_forward_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_ssh_forward_enabled: {{ streisand_ssh_forward_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_sshuttle_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_sshuttle_enabled: {{ streisand_sshuttle_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_stunnel_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_stunnel_enabled: {{ streisand_stunnel_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_tinyproxy_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_tinyproxy_enabled: {{ streisand_tinyproxy_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_tor_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_tor_enabled: {{ streisand_tor_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_wireguard_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_wireguard_enabled: {{ streisand_wireguard_enabled|bool }}\"\n    - lineinfile:\n        path: \"{{ streisand_site_vars }}\"\n        regexp: \"^streisand_cloudflared_enabled: (?:yes|no|True|False)$\"\n        line: \"streisand_cloudflared_enabled: {{ streisand_cloudflared_enabled|bool }}\"\n"
  },
  {
    "path": "playbooks/digitalocean.yml",
    "content": "---\n- name: Provision the DigitalOcean Server\n# =======================================\n  hosts: localhost\n  connection: local\n  gather_facts: yes\n\n  vars:\n    regions:\n      \"1\":  \"ams2\"\n      \"2\":  \"ams3\"\n      \"3\":  \"blr1\"\n      \"4\":  \"fra1\"\n      \"5\":  \"lon1\"\n      \"6\":  \"nyc1\"\n      \"7\":  \"nyc2\"\n      \"8\":  \"nyc3\"\n      \"9\":  \"sfo1\"\n      \"10\": \"sfo2\"\n      \"11\": \"sgp1\"\n      \"12\": \"tor1\"\n\n  vars_prompt:\n    - name: \"do_region\"\n      prompt: >\n        What region should the server be located in?\n          1.  Amsterdam        (Datacenter 2)\n          2.  Amsterdam        (Datacenter 3)\n          3.  Bangalore\n          4.  Frankfurt\n          5.  London\n          6.  New York         (Datacenter 1)\n          7.  New York         (Datacenter 2)\n          8.  New York         (Datacenter 3)\n          9.  San Francisco    (Datacenter 1)\n          10. San Francisco    (Datacenter 2)\n          11. Singapore\n          12. Toronto\n        Please choose the number of your region. Press enter for default (#2) region.\n      default: \"2\"\n      private: no\n\n    - name: \"do_server_name\"\n      prompt: \"\\nWhat should the server be named? Press enter for default (streisand).\\n\"\n      default: \"streisand\"\n      private: no\n\n    - name: \"do_access_token_entry\"\n      prompt: |\n\n          Personal Access Tokens allow Streisand to create a droplet for you.\n          New Personal Access Tokens can be generated in the DigitalOcean control panel.\n          To generate a new token please do the following:\n                * Go to https://cloud.digitalocean.com/settings/applications\n                * Click 'Generate New Token'\n                * Give the token a name (it is arbitrary)\n                * Be sure to select the 'Write' scope as well (this is not optional)\n                * Click 'Generate Token'\n                * Copy the long string that is generated and paste it below.\n          If this field is left blank, the environment variable DO_API_KEY will be used.\n\n          What is your DigitalOcean Personal Access Token?\n      private: no\n\n    - name: \"do_ssh_name\"\n      prompt: \"\\n\\nThe following information can be found on your DigitalOcean control panel.\\nhttps://cloud.digitalocean.com/settings/security\\n\\nWhat is the name of the DigitalOcean SSH key that you would like to use?\\n  * If you have never uploaded an SSH key to DigitalOcean then the default\\n    value will work!\\n  * This key should match your Streisand SSH key file (default: ~/.ssh/id_rsa.pub).\\n\\  * DigitalOcean requires SSH keys to be unique. You cannot upload multiple\\n    keys that have the same value under different names.\\n\\n    If you see an error that says 'SSH Key failed to be created' once the setup\\n    process starts, then this is the problem. You can retry the setup process\\n    using the name of the existing SSH key from the DigitalOcean control panel\\n    that matches the contents of your RSA public key.\\n\"\n      default: \"streisand\"\n      private: no\n\n    - name: \"confirmation\"\n      prompt: \"\\nStreisand will now set up your server. This process usually takes around ten minutes. Press Enter to begin setup...\\n\"\n\n  roles:\n    - genesis-digitalocean\n\n- import_playbook: ssh-setup.yml\n- import_playbook: cloud-status.yml\n- import_playbook: streisand.yml\n...\n"
  },
  {
    "path": "playbooks/ec2-metadata-instance.yml",
    "content": "---\n- name: Drop packets to the Amazon EC2 metadata instance\n  hosts: streisand-host\n  gather_facts: no\n\n  remote_user: \"root\"\n  become: true\n\n  tasks:\n\n    - name: Copy the EC2 metadata instance oneshot unit file\n      copy:\n        src: \"./roles/genesis-amazon/files/aws-metadata-instance.service\"\n        dest: \"/etc/systemd/system/aws-metadata-instance.service\"\n        owner: root\n        group: root\n        mode: 0644\n\n    - name: Enable and reload the EC2 metadata instance\n      systemd:\n        name: aws-metadata-instance.service\n        daemon_reload: yes\n        enabled: yes\n        state: restarted\n"
  },
  {
    "path": "playbooks/existing-server.yml",
    "content": "---\n# existing-server.yml is an advanced provisioning option that doesn't use a genesis\n# role to create a new server and instead applies Streisand to an existing\n# remote server.\n\n- name: Register the genesis role in use\n  hosts: localhost\n  gather_facts: yes\n  tasks:\n    - set_fact:\n        streisand_genesis_role: \"existing-server\"\n\n- include: ssh-setup.yml\n\n- name: Check SSH access to existing server\n  hosts: streisand-host\n  gather_facts: no\n  remote_user: \"{{ lookup('env', 'SSH_USER') }}\"\n  become: true\n  tasks:\n    - block:\n        - raw: whoami\n          args:\n            executable: /bin/bash\n          changed_when: False\n      rescue:\n        - fail:\n            msg: \"Unable to SSH to existing streisand-host.\\nEnsure private key corresponding to \\\"{{ streisand_ssh_private_key }}\\\" is loaded in your SSH key agent.\\nTry using `ssh-keygen -i {{ streisand_ssh_private_key }} to generate your key if it does not exist\\n\"\n\n# Ensure Python is installed on the system\n- import_playbook: python.yml\n\n# Try and detect the remote server's provider & apply required workarounds\n- import_playbook: provider-detect.yml\n\n- name: Prepare the remote server for Streisand\n# =========================================\n  hosts: streisand-host\n  remote_user: \"{{ lookup('env', 'SSH_USER') }}\"\n  become: true\n\n- import_playbook: streisand.yml\n...\n"
  },
  {
    "path": "playbooks/google.yml",
    "content": "---\n- name: Provision the GCE Server\n# =======================================\n  hosts: localhost\n  connection: local\n  gather_facts: yes\n\n  vars:\n    zones:\n      \"1\":  \"us-central1-a\"\n      \"2\":  \"us-central1-b\"\n      \"3\":  \"us-central1-c\"\n      \"4\":  \"us-central1-f\"\n      \"5\":  \"us-east4-a\"\n      \"6\":  \"us-east4-b\"\n      \"7\":  \"us-east4-c\"\n      \"8\":  \"us-east1-b\"\n      \"9\":  \"us-east1-c\"\n      \"10\": \"us-east1-d\"\n      \"11\": \"us-west1-a\"\n      \"12\": \"us-west1-b\"\n      \"13\": \"us-west1-c\"\n      \"14\": \"europe-west1-b\"\n      \"15\": \"europe-west1-c\"\n      \"16\": \"europe-west1-d\"\n      \"17\": \"europe-west2-a\"\n      \"18\": \"europe-west2-b\"\n      \"19\": \"europe-west2-c\"\n      \"20\": \"europe-west3-a\"\n      \"21\": \"europe-west3-b\"\n      \"22\": \"europe-west3-c\"\n      \"23\": \"europe-west4-a\"\n      \"24\": \"europe-west4-b\"\n      \"25\": \"europe-west4-c\"\n      \"26\": \"asia-east1-a\"\n      \"27\": \"asia-east1-b\"\n      \"28\": \"asia-east1-c\"\n      \"29\": \"asia-east2-a\"\n      \"30\": \"asia-east2-b\"\n      \"31\": \"asia-east2-c\"\n      \"32\": \"asia-northeast1-a\"\n      \"33\": \"asia-northeast1-b\"\n      \"34\": \"asia-northeast1-c\"\n      \"35\": \"asia-south1-a\"\n      \"36\": \"asia-south1-b\"\n      \"37\": \"asia-south1-c\"\n      \"38\": \"asia-southeast1-a\"\n      \"39\": \"asia-southeast1-b\"\n      \"40\": \"australia-southeast1-a\"\n      \"41\": \"australia-southeast1-b\"\n      \"42\": \"australia-southeast1-c\"\n      \"43\": \"southamerica-east1-a\"\n      \"44\": \"southamerica-east1-b\"\n      \"45\": \"southamerica-east1-c\"\n\n  # These variable files are included so the gce-network role\n  # knows which ports to open\n  vars_files:\n    - roles/openconnect/defaults/main.yml\n    - roles/openvpn/defaults/main.yml\n    - roles/shadowsocks/defaults/main.yml\n    - roles/ssh/defaults/main.yml\n    - roles/lets-encrypt/vars/main.yml\n    - roles/streisand-gateway/defaults/main.yml\n    - roles/stunnel/defaults/main.yml\n    - roles/tor-bridge/defaults/main.yml\n    - roles/wireguard/defaults/main.yml\n\n  vars_prompt:\n    - name: \"gce_zone_idx\"\n      prompt: >\n        What zone should the server be located in?\n          1. Central US            (Iowa A)\n          2. Central US            (Iowa B)\n          3. Central US            (Iowa C)\n          4. Central US            (Iowa F)\n          5. Eastern US            (Northern Virginia A)\n          6. Eastern US            (Northern Virginia B)\n          7. Eastern US            (Northern Virginia C)\n          8. Eastern US            (South Carolina B)\n          9. Eastern US            (South Carolina C)\n          10. Eastern US           (South Carolina D)\n          11. Western US           (Oregon A)\n          12. Western US           (Oregon B)\n          13. Western US           (Oregon C)\n          14. Western Europe       (Belgium B)\n          15. Western Europe       (Belgium C)\n          16. Western Europe       (Belgium D)\n          17. Western Europe       (London A)\n          18. Western Europe       (London B)\n          19. Western Europe       (London C)\n          20. Western Europe       (Frankfurt A)\n          21. Western Europe       (Frankfurt B)\n          22. Western Europe       (Frankfurt C)\n          23. Western Europe       (Netherlands A)\n          24. Western Europe       (Netherlands B)\n          25. Western Europe       (Netherlands C)\n          26. East Asia            (Taiwan A)\n          27. East Asia            (Taiwan B)\n          28. East Asia            (Taiwan C)\n          29. East Asia            (Hong Kong A)\n          30. East Asia            (Hong Kong B)\n          31. East Asia            (Hong Kong C)\n          32. Northeast Asia       (Tokyo A)\n          33. Northeast Asia       (Tokyo B)\n          34. Northeast Asia       (Tokyo C)\n          35. South Asia           (Mumbai A)\n          36. South Asia           (Mumbai B)\n          37. South Asia           (Mumbai C)\n          38. Southeast Asia       (Singapore A)\n          39. Southeast Asia       (Singapore B)\n          40. Southeast Australia  (Sydney A)\n          41. Southeast Australia  (Sydney B)\n          42. Southeast Australia  (Sydney C)\n          43. South America        (São Paulo A)\n          44. South America        (São Paulo B)\n          45. South America        (São Paulo C)\n        Please choose the number of your zone. Press enter for default (#3) zone.\n      default: \"3\"\n      when: gce_zone is not defined\n      private: no\n\n    - name: \"gce_server_name\"\n      prompt: \"\\nWhat should the server be named? Press enter for default (streisand).\\n\"\n      default: \"streisand\"\n      private: no\n\n    - name: \"gce_json_file_location\"\n      prompt: \"\\n\\nThe full path of your unique service account credentials file. Details on generating this can be found at \\nhttps://docs.ansible.com/ansible/guide_gce.html#credentials\\n and \\nhttps://support.google.com/cloud/answer/6158849?hl=en&ref_topic=6262490#serviceaccounts\\n\"\n      default: \"{{ lookup('env','HOME') }}/streisand.json\"\n      private: no\n\n    - name: \"confirmation\"\n      prompt: \"\\nStreisand will now set up your server. This process usually takes around ten minutes. Press Enter to begin setup...\\n\"\n\n  pre_tasks:\n    - name: Set the Google Compute Engine Zone interactive\n      set_fact:\n        gce_zone: \"{{ zones[gce_zone_idx] }}\"\n      when: gce_zone is not defined\n\n    - name: Register JSON file contents\n      command: cat {{ gce_json_file_location }}\n      register: gce_json_file_contents\n      changed_when: False\n\n    - name: Set JSON file contents fact\n      set_fact:\n        gce_json_contents_fact: \"{{ gce_json_file_contents.stdout | from_json }}\"\n\n    - name: Set the Google Compute Engine Service Account Email\n      set_fact:\n        gce_service_account_email: \"{{ gce_json_contents_fact.client_email }}\"\n\n    - name: Set the Google Compute Engine Project ID\n      set_fact:\n        gce_project_id: \"{{ gce_json_contents_fact.project_id }}\"\n\n  roles:\n    - genesis-google\n\n- import_playbook: ssh-setup.yml\n- import_playbook: cloud-status.yml\n- import_playbook: streisand.yml\n...\n"
  },
  {
    "path": "playbooks/group_vars/all",
    "content": "---\nstreisand_ci: no\nstreisand_noninteractive: no\n"
  },
  {
    "path": "playbooks/lets-encrypt.yml",
    "content": "---\n# lets-encrypt.yml asks questions about Streisand instance domain name, which\n# is used to request TLS certificates from Let's Encrypt. If user fails to\n# answer these questions, lets-encrypt role would not be run, and self-signed\n# certificates are generated and used instead.\n- name: Collect information about the Streisand domain\n# =========================================\n  hosts: streisand-host\n  gather_facts: no\n\n  vars_files:\n    - roles/lets-encrypt/vars/main.yml\n\n  vars_prompt:\n    - name: \"streisand_domain_var\"\n      prompt: |\n        Do you have a fully qualified domain pointed at your Streisand server?\n\n        This is an optional question. If you have a domain that points to your\n        Streisand server, the installation scripts can request a Let's Encrypt\n        HTTPS certificate for you automatically.  If you do not provide one or\n        the request fails, a self-signed certificate will be used instead.\n\n        If you have just created a new cloud server in previous steps now is a\n        good time to point your fully qualified domain to your server's public\n        address. Make sure the fully qualified domain resolves to the correct IP\n        address before proceeding.\n\n        Please type your fully qualified domain below. Press enter to skip.\n      private: no\n\n    - name: \"streisand_admin_email_var\"\n      prompt: |\n        Which email address do you want to use as a contact for the Streisand\n        server's Let's Encrypt certificate?\n\n        This is an optional question. If you supply an email address Let's\n        Encrypt will send you important (but infrequent) notifications about\n        your certificate. These messages include any upcoming certificate\n        expirations, and important changes to the Let's Encrypt service.\n        The email provided will not be used for anything else or shared with the\n        Streisand developers.\n\n        Please type your contact email below. Press enter to skip.\n      private: no\n\n  pre_tasks:\n    - name: Set Streisand domain\n      set_fact:\n        streisand_domain: \"{{ streisand_domain_var }}\"\n      when: streisand_domain_var != \"\"\n\n    - name: Set Streisand admin email\n      set_fact:\n        streisand_admin_email: \"{{ streisand_admin_email_var }}\"\n\n    - name: Enable Let's Encrypt role\n      set_fact:\n        streisand_le_enabled: yes\n      when: streisand_domain_var != \"\"\n\n    - name: Disable Let's Encrypt role\n      set_fact:\n        streisand_le_enabled: no\n        streisand_domain: \"\"\n        streisand_admin_email: \"\"\n        le_ok: False\n      when: streisand_domain_var == \"\"\n...\n"
  },
  {
    "path": "playbooks/linode.yml",
    "content": "---\n- name: Provision the Linode Server\n# =================================\n  hosts: localhost\n  connection: local\n  gather_facts: yes\n\n  vars:\n    regions:\n      \"1\": \"ca-central\"\n      \"2\": \"us-central\"\n      \"3\": \"us-west\"\n      \"4\": \"us-southeast\"\n      \"5\": \"us-east\"\n      \"6\": \"eu-west\"\n      \"7\": \"ap-south\"\n      \"8\": \"eu-central\"\n      \"9\": \"ap-northeast\"\n      \"10\": \"ap-west\"\n      \"11\": \"ap-southeast\"\n\n  vars_prompt:\n    - name: \"linode_datacenter\"\n      prompt: >\n        What region should the server be located in?\n          1. Toronto\n          2. Dallas\n          3. Fremont\n          4. Atlanta\n          5. Newark\n          6. London\n          7. Singapore\n          8. Frankfurt\n          9. Tokyo\n          10. Mumbai\n          11. Sydney\n        Please choose the number of your region. Press enter for default (#7) region.\n      default: \"7\"\n      private: no\n\n    - name: \"linode_server_name\"\n      prompt: \"\\nWhat should the server be named? Press enter for default (streisand).\\n\"\n      default: \"streisand\"\n      private: no\n\n    - name: \"linode_api_token\"\n      prompt: \"\\n\\nThe following information can be found in the Linode Manager:\\nhttps://cloud.linode.com/profile/tokens\\n\\nWhat is your Linode API Token?\\n\"\n      private: no\n\n    - name: \"confirmation\"\n      prompt: \"\\nStreisand will now set up your server. This process usually takes around ten minutes. Press Enter to begin setup...\\n\"\n\n  roles:\n    - genesis-linode\n\n- import_playbook: ssh-setup.yml\n- import_playbook: streisand.yml\n...\n"
  },
  {
    "path": "playbooks/localhost.yml",
    "content": "---\n# localhost.yml is an advanced provisioning option that doesn't use a genesis\n# role to create a new server and instead applies Streisand to the localhost.\n\n# Ensure Python is installed on the system\n- import_playbook: python.yml\n\n# Try and detect localhost's provider & apply required workarounds\n- import_playbook: provider-detect.yml\n\n- name: Prepare the localhost for Streisand\n# =========================================\n  hosts: streisand-host\n  remote_user: \"root\"\n  become: true\n\n  tasks:\n    - set_fact:\n        streisand_genesis_role: \"localhost\"\n\n    # If there's no streisand_ipv4_address set then we try our best using\n    # the interface Ansible thinks is the default.\n    - name: \"Set the Streisand IPv4 address to the Ansible default: interface: {{ ansible_default_ipv4.alias }} address: {{ ansible_default_ipv4.address }}\"\n      set_fact:\n        # The ansible_default_ipv4 address is calculated based on the default\n        # ipv4 route to 8.8.8.8 for the system, and for local provisioning on\n        # _most_ providers, seems to work well for finding the external facing IP.\n        # See `provider-detect.yml` for cases where this approach doesn't work\n        # (e.g. GCE) and workarounds.\n        streisand_ipv4_address: \"{{ ansible_default_ipv4.address }}\"\n      when: streisand_ipv4_address is not defined\n\n- import_playbook: streisand.yml\n...\n"
  },
  {
    "path": "playbooks/provider-detect.yml",
    "content": "---\n# provider-detect.yml is used for the advanced existing/localhost provisioning\n# to try and determine if a given host is from a specific cloud provider. If\n# the cloud provider is detected, some facts/workarounds may be set to aid in\n# provisioning in place of one of the geneiss roles.\n- name: Try to detect Cloud providers for specific overrides\n# =========================================\n  hosts: streisand-host\n\n  remote_user: \"root\"\n  become: true\n\n  tasks:\n    - name: \"Install dmidecode to use for BIOS version detection\"\n      apt:\n        package: dmidecode\n\n    - name: \"Try to determine localhost Cloud provider name from BIOS version\"\n      # Looking into ways to detect EC2/GCE instances without relying on\n      # connections to metadata IPs this solution[0] seemed the most\n      # straightforward & reliable.\n      #   https://serverfault.com/a/775063\n      command: dmidecode -s bios-version\n      register: streisand_localhost_bios_name\n      changed_when: False\n      ignore_errors: True\n\n    - name: \"Set BIOS name fact from dmidecode if possible\"\n      set_fact:\n        streisand_bios_name: \"{{ streisand_localhost_bios_name.stdout }}\"\n      when: streisand_localhost_bios_name.rc == 0\n\n    - name: \"...Otherwise set unknown BIOS fact\"\n      set_fact:\n        streisand_bios_name: \"Unknown\"\n      when: streisand_bios_name is undefined\n\n    # GCE specific work-arounds:\n    #   * None of the interfaces have the external IP bound, so this must be set\n    #     from the Google Platform medatadata service.\n    - block:\n        - name: Warn about manual provisioning of GCE instances\n          pause:\n            prompt: \"You are running Streisand in an advanced mode against an existing GCE instance. Unlike the standard GCE provisioning mode this means Streisand *CAN NOT* open ports on your behalf. You will need to manually create the correct VPC Network and firewall rules. See 'generated-docs/' for the firewall-information.html file at the end of installation for a list of ports to open. The Streisand maintainers are not able to support this configuration. Press [enter] to continue\"\n          when: not streisand_noninteractive\n\n        - name: \"Find the external GCE IP from Google Metadata\"\n          # NOTE: We use the command module and `curl` here because (AFAICT)\n          # there isn't a way to `register` a `get_url` call and it seems\n          # hackier overall to add an intermediate step using a file on disk\n          #\n          # Metadata URL & the required \"Metadata-Flavor\" are explained in the\n          # Google Cloud Platform documentation[0].\n          # [0]: https://cloud.google.com/compute/docs/storing-retrieving-metadata#querying\n          command: curl -H Metadata-Flavor:Google http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip\n          register: streisand_gce_external_ip\n          changed_when: False\n        - name: \"Set the Streiand IPv4 address to the GCE external IP: {{ streisand_gce_external_ip.stdout }}\"\n          set_fact:\n            streisand_ipv4_address: \"{{ streisand_gce_external_ip.stdout }}\"\n      when: \"streisand_bios_name == 'Google'\"\n\n    # Amazon EC2 specific work-arounds:\n    #   * None of the interfaces have the external IP bound, so this must be set\n    #     from the EC2 medatadata service.\n    - block:\n        - name: Warn about manual provisioning of EC2 instances\n          pause:\n            prompt: \"You are running Streisand in an advanced mode against an existing Amazon EC2 instance. Unlike the standard EC2 provisioning mode this means Streisand *CAN NOT* open ports on your behalf. You will need to manually assinging this machine to a security group with the correct firewall rules. See 'generated-docs/' for the firewall-information.html file at the end of installation for a list of ports to open. The Streisand maintainers are not able to support this configuration. Press [enter] to continue\"\n          when: not streisand_noninteractive\n\n            # EC2 Instance Metadata API is explained in the EC2 docs[0].\n            # [0]: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html\n        - name: \"Find the external EC2 IP from Metadata\"\n          command: curl http://169.254.169.254/latest/meta-data/public-ipv4\n          register: streisand_ec2_external_ip\n          changed_when: False\n        - name: \"Set the Streiand IPv4 address to the EC2 external IP: {{ streisand_ec2_external_ip.stdout }}\"\n          set_fact:\n            streisand_ipv4_address: \"{{ streisand_ec2_external_ip.stdout }}\"\n      when: \"'amazon' in streisand_bios_name\"\n...\n"
  },
  {
    "path": "playbooks/python.yml",
    "content": "---\n- name: Prepare the new server for Ansible\n# =========================================\n  hosts: streisand-host\n  gather_facts: no\n\n  remote_user: \"root\"\n  become: true\n\n  tasks:\n    - name: Install Python using a raw SSH command to enable the execution of Ansible modules\n      raw: apt update && apt install python -y\n      args:\n        executable: /bin/bash\n...\n"
  },
  {
    "path": "playbooks/rackspace.yml",
    "content": "---\n- name: Provision the Rackspace Server\n# ====================================\n  hosts: localhost\n  connection: local\n  gather_facts: yes\n\n  vars:\n    regions:\n      \"1\": \"ORD\"\n      \"2\": \"DFW\"\n      \"3\": \"HKG\"\n      \"4\": \"IAD\"\n      \"5\": \"SYD\"\n\n  vars_prompt:\n    - name: \"rackspace_region\"\n      prompt: >\n        What region should the server be located in?\n          1. Chicago\n          2. Dallas\n          3. Hong Kong\n          4. Northern Virginia\n          5. Sydney\n        Please choose the number of your region. Press enter for default (#1) region.\n      default: \"1\"\n      private: no\n\n    - name: \"rackspace_server_name\"\n      prompt: \"\\nWhat should the server be named? Press enter for default (streisand).\\n\"\n      private: no\n      default: \"streisand\"\n\n    - name: \"rackspace_username\"\n      prompt: \"\\nWhat is your Rackspace username?\\n\"\n      private: no\n\n    - name: \"rackspace_api_key\"\n      prompt: \"\\n\\nThe following information can be found in the Rackspace Cloud Control Panel.\\nhttps://mycloud.rackspace.com/\\n\\nWhat is your Rackspace API key?\\n\"\n      private: no\n\n    - name: \"confirmation\"\n      prompt: \"\\nStreisand will now set up your server. This process usually takes around ten minutes. Press Enter to begin setup...\\n\"\n\n  roles:\n    - genesis-rackspace\n\n- import_playbook: ssh-setup.yml\n- import_playbook: cloud-status.yml\n- import_playbook: streisand.yml\n...\n"
  },
  {
    "path": "playbooks/roles/ad-blocking/files/download-blocklists",
    "content": "#!/bin/bash\nset -e\n\n# Now, if there were only some convenient way of storing etags from\n# those fetches.\n\ndownload_if_newer () {\n    filename=\"$1\"\n    url=\"$2\"\n    if [ -e \"$filename\" ]; then\n\tcurl --time-cond \"$filename\" -o \"$filename\" \"$url\"\n    else\n\tcurl -o \"$filename\" \"$url\"\n    fi\n}\n\n\nmkdir -p /var/lib/blocklists\n\ndownload_if_newer /var/lib/blocklists/block-hostnames.txt 'https://raw.githubusercontent.com/notracking/hosts-blocklists/master/hostnames.txt'\n\ndownload_if_newer /var/lib/blocklists/block-domains.txt 'https://raw.githubusercontent.com/notracking/hosts-blocklists/master/domains.txt'\n\ntransform-domain-list </var/lib/blocklists/block-domains.txt >/etc/dnsmasq.d/block-domains.conf\ntransform-host-list </var/lib/blocklists/block-hostnames.txt >/etc/dnsmasq-block-hosts\n\necho \"addn-hosts=/etc/dnsmasq-block-hosts\" >/etc/dnsmasq.d/block-hosts.conf\n\n# Sadly, \"reload\" doesn't work\"\nsystemctl restart dnsmasq.service\n"
  },
  {
    "path": "playbooks/roles/ad-blocking/files/download-blocklists.service",
    "content": "[Unit]\nDescription=Download blocklists\n\n[Service]\nType=oneshot\nExecStart=/usr/local/bin/download-blocklists\n\n"
  },
  {
    "path": "playbooks/roles/ad-blocking/files/download-blocklists.timer",
    "content": "[Timer]\nOnActiveSec=0\nOnBootSec=60\nOnUnitActiveSec=1d\nRandomizedDelaySec=1h\n\n[Install]\nWantedBy=network.target\n"
  },
  {
    "path": "playbooks/roles/ad-blocking/files/transform-domain-list",
    "content": "#!/bin/bash\n\nawk '\nBEGIN { FS=\"/\"; print \"# post-processed by transform-domain-list\" }\n\n/^#/ { print $0; next; }\n\n/^address=\\/.*\\/0\\.0\\.0\\.0$/ { next; }\n\n/^address=\\/.*\\/::$/ {\n    if ($2 !~ /\\./) {\n       print \"### no dot found in domain, skipping: \" $0;\n       next;\n    }\n    print \"address=/\" $2 \"/0.0.0.0\\naddress=/\" $2 \"/::\";\n    next;\n}\n\n{ print \"### ERROR unprocessed line: \" $0; }\n'\n"
  },
  {
    "path": "playbooks/roles/ad-blocking/files/transform-host-list",
    "content": "#!/bin/bash\n\nawk '\nBEGIN { print \"# post-processed by transform-host-list\"; }\n\n/^#/ { print $0; next; }\n\n/^0\\.0\\.0\\.0 / { next; }\n\n/^:: / {\n    if ($2 !~ /\\./) {\n       print \"### no dot found in hostname, skipping: \" $0;\n       next;\n    }\n    print \"0.0.0.0 \" $2 \"\\n:: \" $2;\n    next;\n}\n\n{ print \"### ERROR unprocessed line: \" $0; }\n'\n"
  },
  {
    "path": "playbooks/roles/ad-blocking/tasks/main.yml",
    "content": "- name: \"Install blocklist tools\"\n  copy:\n    src: \"{{ item }}\"\n    dest: /usr/local/bin/\n    mode: '0755'\n  loop:\n    - download-blocklists\n    - transform-domain-list\n    - transform-host-list\n\n- name: \"Install blocklist systemd goo\"\n  copy:\n    src: \"{{ item }}\"\n    dest: /etc/systemd/system/\n    mode: '0644'\n  loop:\n    - download-blocklists.service\n    - download-blocklists.timer\n\n- name: \"Enable the blocklist download service\"\n  systemd:\n    name: download-blocklists.service\n    daemon_reload: true\n    enabled: true\n    state: started\n\n- name: \"Enable and start the blocklist re-download timer\"\n  systemd:\n    name: download-blocklists.timer\n    enabled: true\n    state: started\n"
  },
  {
    "path": "playbooks/roles/azure-security-group/meta/main.yml",
    "content": "---\nallow_duplicates: yes\n"
  },
  {
    "path": "playbooks/roles/azure-security-group/tasks/main.yml",
    "content": "---\n- name: Create Azure resource group\n  azure_rm_resourcegroup:\n    name: \"{{ azure_resource_group_name }}\"\n    location: \"{{ azure_region }}\"\n\n- name: Create Azure virtual network\n  azure_rm_virtualnetwork:\n    resource_group: \"{{ azure_resource_group_name }}\"\n    name: \"{{ azure_resource_group_name }}\"\n    address_prefixes: \"10.10.0.0/16\"\n\n- name: Create Azure subnet\n  azure_rm_subnet:\n    resource_group: \"{{ azure_resource_group_name }}\"\n    name: \"{{ azure_resource_group_name }}\"\n    address_prefix: \"10.10.0.0/24\"\n    virtual_network: \"{{ azure_resource_group_name }}\"\n\n- name: Create Azure public ip\n  azure_rm_publicipaddress:\n    resource_group: \"{{ azure_resource_group_name }}\"\n    allocation_method: Static\n    name: \"{{ azure_resource_group_name }}\"\n\n- name: Open all of the necessary ports across every service in the Azure security group\n  azure_rm_securitygroup:\n    name: \"{{ azure_resource_group_name }}\"\n    resource_group: \"{{ azure_resource_group_name }}\"\n    location: \"{{ azure_region }}\"\n    rules:\n      # Nginx\n      # ---\n      - name: \"AllowNGINX\"\n        destination_port_range: \"{{ nginx_port }}\"\n        protocol: Tcp\n        access: Allow\n        direction: Inbound\n        priority: 101\n      # SSH\n      # ---\n      - name: \"AllowSSHTCP\"\n        destination_port_range: \"{{ ssh_port }}\"\n        protocol: Tcp\n        access: Allow\n        direction: Inbound\n        priority: 108\n      # HTTP (Let's Encrypt)\n      # ---\n      - name: \"AllowHTTP\"\n        destination_port_range: \"{{ le_port }}\"\n        protocol: Tcp\n        access: Allow\n        direction: Inbound\n        priority: 120\n\n# Shadowsocks\n# ---\n- name: Open Shadowsocks ports in the Azure security group\n  azure_rm_securitygroup:\n    name: \"{{ azure_resource_group_name }}\"\n    resource_group: \"{{ azure_resource_group_name }}\"\n    location: \"{{ azure_region }}\"\n    rules:\n      # Shadowsocks TCP\n      # ---\n      - name: \"AllowShadowsocksTCP\"\n        destination_port_range: \"{{ shadowsocks_server_port }}\"\n        protocol: Tcp\n        access: Allow\n        direction: Inbound\n        priority: 106\n      # Shadowsocks UDP\n      # ---\n      - name: \"AllowShadowsocksUDP\"\n        destination_port_range: \"{{ shadowsocks_server_port }}\"\n        protocol: Udp\n        access: Allow\n        direction: Inbound\n        priority: 107\n  when: streisand_shadowsocks_enabled\n\n# WireGuard\n# ---\n- name: Open WireGuard ports in the Azure security group\n  azure_rm_securitygroup:\n    name: \"{{ azure_resource_group_name }}\"\n    resource_group: \"{{ azure_resource_group_name }}\"\n    location: \"{{ azure_region }}\"\n    rules:\n      - name: \"AllowWireguard\"\n        destination_port_range: \"{{ wireguard_port }}\"\n        protocol: Udp\n        access: Allow\n        direction: Inbound\n        priority: 112\n  when: streisand_wireguard_enabled\n\n# OpenConnect (ocserv)\n# ---\n- name: Open the OpenConnect ports in the Azure security group\n  azure_rm_securitygroup:\n    name: \"{{ azure_resource_group_name }}\"\n    resource_group: \"{{ azure_resource_group_name }}\"\n    location: \"{{ azure_region }}\"\n    rules:\n      # OpenConnect TCP\n      # ---\n      - name: \"AllowOCServTCP\"\n        destination_port_range: \"{{ ocserv_port }}\"\n        protocol: Tcp\n        access: Allow\n        direction: Inbound\n        priority: 102\n      # OpenConnect UDP\n      # ---\n      - name: \"AllowOCServUDP\"\n        destination_port_range: \"{{ ocserv_port }}\"\n        protocol: Udp\n        access: Allow\n        direction: Inbound\n        priority: 103\n  when: streisand_openconnect_enabled\n\n# OpenVPN\n# ---\n- name: Open the OpenVPN ports in the Azure security group\n  azure_rm_securitygroup:\n    name: \"{{ azure_resource_group_name }}\"\n    resource_group: \"{{ azure_resource_group_name }}\"\n    location: \"{{ azure_region }}\"\n    rules:\n      # OpenVPN TCP\n      # ---\n      - name: \"AllowOpenVPNTCP\"\n        destination_port_range: \"{{ openvpn_port }}\"\n        protocol: Tcp\n        access: Allow\n        direction: Inbound\n        priority: 104\n      # OpenVPN UDP\n      # ---\n      - name: \"AllowOpenVPNUDP\"\n        destination_port_range: \"{{ openvpn_port_udp }}\"\n        protocol: Udp\n        access: Allow\n        direction: Inbound\n        priority: 105\n  when: streisand_openvpn_enabled\n\n# stunnel\n# ---\n- name: Open the stunnel port in the Azure security group\n  azure_rm_securitygroup:\n    name: \"{{ azure_resource_group_name }}\"\n    resource_group: \"{{ azure_resource_group_name }}\"\n    location: \"{{ azure_region }}\"\n    rules:\n      - name: \"AllowStunnelTCP\"\n        destination_port_range: \"{{ stunnel_remote_port }}\"\n        protocol: Tcp\n        access: Allow\n        direction: Inbound\n        priority: 109\n  when: streisand_openvpn_enabled and streisand_stunnel_enabled\n\n# Tor\n# ---\n- name: Open Tor ports in the Azure security group\n  azure_rm_securitygroup:\n    name: \"{{ azure_resource_group_name }}\"\n    resource_group: \"{{ azure_resource_group_name }}\"\n    location: \"{{ azure_region }}\"\n    rules:\n      # Tor TCP\n      # ---\n      - name: \"AllowTorTCP\"\n        destination_port_range: \"{{ tor_orport }}\"\n        protocol: Tcp\n        access: Allow\n        direction: Inbound\n        priority: 110\n      # Tor obfs4 TCP port\n      # ---\n      - name: \"AllowOBFS4TCP\"\n        destination_port_range: \"{{ tor_obfs4_port }}\"\n        protocol: Tcp\n        access: Allow\n        direction: Inbound\n        priority: 111\n  when: streisand_tor_enabled\n\n- name: Create Azure network interface\n  azure_rm_networkinterface:\n    resource_group: \"{{ azure_resource_group_name }}\"\n    name: \"{{ azure_resource_group_name }}\"\n    virtual_network: \"{{ azure_resource_group_name }}\"\n    subnet: \"{{ azure_resource_group_name }}\"\n    public_ip_name: \"{{ azure_resource_group_name }}\"\n    security_group: \"{{ azure_resource_group_name }}\"\n"
  },
  {
    "path": "playbooks/roles/azure-security-group/vars/main.yml",
    "content": "---\nazure_resource_group_name: \"streisand-{{ azure_instance_name }}\"\n"
  },
  {
    "path": "playbooks/roles/certificates/defaults/main.yml",
    "content": "---\ntls_key_country:  \"US\"\ntls_key_province: \"California\"\ntls_key_city:     \"Beverly Hills\"\ntls_key_org:      \"ACME CORPORATION\"\ntls_key_ou:       \"Anvil Department\"\ntls_days_valid:   \"1825\"\ntls_default_md:   \"sha256\"\ntls_key_size:     \"4096\"\n\n# What type of certificates to be generated\n# must be explicitly set by playbooks that\n# include the certificates role\ngenerate_ca_server: no\ngenerate_client:    no\ngenerate_pkcs:      no\n"
  },
  {
    "path": "playbooks/roles/certificates/tasks/ca-server.yml",
    "content": "---\n- name: \"Generate the private keys for the CA and Server certificates\"\n  command: openssl genrsa -out {{ item }}.key {{ tls_key_size }}\n  args:\n    chdir: \"{{ ca_path }}\"\n    creates: \"{{ item }}.key\"\n  with_items:\n    - ca\n    - server\n\n- name: Set the proper permissions on all the private keys\n  file:\n    path: \"{{ ca_path }}\"\n    recurse: yes\n    state: directory\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Generate CA certificate\n  command: openssl req -nodes -batch -new -x509 -key {{ tls_ca }}.key -days {{ tls_days_valid }} -out {{ tls_ca }}.crt -subj \"{{ tls_request_subject }}/CN=ca-certificate\"\n  args:\n    creates: \"{{ tls_ca }}.crt\"\n\n- name: Generate a random server common name\n  shell: \"{{ streisand_word_gen.long_identifier | trim }} > {{ tls_server_common_name_file }}\"\n  args:\n    creates: \"{{ tls_server_common_name_file }}\"\n\n- name: Set permissions on the TLS server common name file\n  file:\n    path: \"{{ tls_server_common_name_file }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Register the TLS server common name\n  command: cat \"{{ tls_server_common_name_file }}\"\n  register: tls_server_common_name\n  changed_when: False\n\n- name: Generate the OpenSSL configuration that will be used for the server certificate's req and ca commands\n  template:\n    src: openssl.cnf.j2\n    dest: \"{{ ca_path }}/openssl.cnf\"\n\n- name: Seed a blank database file that will be used when generating the Server's certificate\n  file:\n    path: \"{{ ca_path }}/index.txt\"\n    state: touch\n\n- name: Seed a serial file that will be used when generating the Server's certificate\n  copy:\n    content: \"01\"\n    dest: \"{{ ca_path }}/serial\"\n\n- name: Generate CSR for the Server\n  command: openssl req -batch -extensions server -new -key server.key -out server.csr -config {{ ca_path }}/openssl.cnf\n  args:\n    chdir: \"{{ ca_path }}\"\n    creates: server.csr\n\n- name: Generate certificate for the Server\n  command: openssl ca -batch -extensions server -in server.csr -out server.crt -config openssl.cnf\n  args:\n    chdir: \"{{ ca_path }}\"\n    creates: server.crt\n"
  },
  {
    "path": "playbooks/roles/certificates/tasks/client.yml",
    "content": "---\n- name: Create directories for clients\n  file:\n    path: \"{{ tls_client_path }}/{{ client_name.stdout }}\"\n    state: directory\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: Generate the private keys for the client certificates\n  command: openssl genrsa -out client.key {{ tls_key_size }}\n  args:\n    chdir: \"{{ tls_client_path }}/{{ client_name.stdout }}\"\n    creates: client.key\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: Set the proper permissions on all private client keys\n  file:\n    path: \"{{ ca_path }}\"\n    recurse: yes\n    state: directory\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Generate CSRs for the clients\n  command: openssl req -new -extensions client -key client.key -out client.csr -subj \"{{ tls_request_subject }}/CN={{ client_name.stdout }}\" -config {{ ca_path }}/openssl.cnf\n  args:\n    chdir: \"{{ tls_client_path }}/{{ client_name.stdout }}\"\n    creates: client.csr\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: Generate certificates for the clients\n  command: openssl x509 -extensions client -CA {{ tls_ca }}.crt -CAkey {{ tls_ca }}.key -CAcreateserial -req -days {{ tls_days_valid }} -in client.csr -out client.crt -extfile {{ ca_path }}/openssl.cnf\n  args:\n    chdir: \"{{ tls_client_path }}/{{ client_name.stdout }}\"\n    creates: client.crt\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: Authorize certificates via /etc/allowed_vpn_certs\n  template:\n    src: allowed_vpn_certs.j2\n    dest: /etc/allowed_vpn_certs\n    owner: root\n    group: root\n    mode: 0644\n"
  },
  {
    "path": "playbooks/roles/certificates/tasks/main.yml",
    "content": "---\n- import_tasks: ca-server.yml\n  when: generate_ca_server\n\n- import_tasks: client.yml\n  when: generate_client\n\n- import_tasks: pkcs.yml\n  when: generate_pkcs\n"
  },
  {
    "path": "playbooks/roles/certificates/tasks/pkcs.yml",
    "content": "---\n- name: \"Generate a random password that will be used during the PKCS #12 conversion\"\n  shell: \"{{ streisand_word_gen.weak_password | trim }} > {{ tls_client_path }}/{{ client_name.stdout }}/{{ vpn_name }}-{{ client_name.stdout }}-pkcs12-password\"\n  args:\n    creates: \"{{ tls_client_path }}/{{ client_name.stdout }}/{{ vpn_name }}-{{ client_name.stdout }}-pkcs12-password\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: \"Set permissions on the PKCS #12 password file\"\n  file:\n    path: \"{{ tls_client_path }}/{{ client_name.stdout }}/{{ vpn_name }}-{{ client_name.stdout }}-pkcs12-password\"\n    owner: root\n    group: root\n    mode: 0600\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: \"Register the PKCS #12 passwords\"\n  command: cat {{ tls_client_path }}/{{ client_name.stdout }}/{{ vpn_name }}-{{ client_name.stdout }}-pkcs12-password\n  register: \"vpn_client_pkcs12_password_list\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n  changed_when: False\n\n- name: \"Convert the {{ vpn_name }} client keys and certificates into PKCS #12 format\"\n  command: >\n    openssl pkcs12 -export\n    -in {{ tls_client_path }}/{{ vpn_client_password.client_name.stdout }}/client.crt\n    -inkey {{ tls_client_path }}/{{ vpn_client_password.client_name.stdout }}/client.key\n    -name {{ vpn_client_password.client_name.stdout }}\n    -out {{ tls_client_path }}/{{ vpn_client_password.client_name.stdout }}/{{ vpn_client_password.client_name.stdout }}.p12\n    -certfile {{ tls_client_path }}/ca.crt\n    -passout pass:\"{{ vpn_client_password.stdout }}\"\n  args:\n    creates: \"{{ tls_client_path }}/{{ vpn_client_password.client_name.stdout }}/{{ vpn_client_password.client_name.stdout }}.p12\"\n  with_items: \"{{ vpn_client_pkcs12_password_list.results }}\"\n  loop_control:\n    loop_var: \"vpn_client_password\"\n    label: \"{{ vpn_client_password.client_name.item }}\"\n"
  },
  {
    "path": "playbooks/roles/certificates/templates/allowed_vpn_certs.j2",
    "content": "# This file lists all the enabled VPN certificate names. Note that\n# it does not affect WireGuard.\n\n{% for client in vpn_client_names.results -%}\n{{ client.stdout }}\n{% endfor %}\n"
  },
  {
    "path": "playbooks/roles/certificates/templates/openssl.cnf.j2",
    "content": "[ ca ]\ndefault_ca = CA_default\n\n[ CA_default ]\n\ndir = {{ ca_path }}\ncerts = $dir\ncrl_dir = $dir\ndatabase = $dir/index.txt\nnew_certs_dir = $dir\n\ncertificate = {{ tls_ca }}.crt\nserial = $dir/serial\ncrl = $dir/crl.pem\nprivate_key = {{ tls_ca }}.key\nRANDFILE = $dir/.rand\n\ncopy_extensions = copy\n\nx509_extensions = server\n\ndefault_days = {{ tls_days_valid }}\ndefault_crl_days= 30\ndefault_md = {{ tls_default_md }}\npreserve = no\n\npolicy = policy_anything\n\nkeyUsage = cRLSign, keyCertSign\n\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always,issuer:always\n\n[ policy_anything ]\ncountryName = optional\nstateOrProvinceName = optional\nlocalityName = optional\norganizationName = optional\norganizationalUnitName = optional\ncommonName = supplied\nname = optional\nemailAddress = optional\n\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions     = req_ext\n\n[ req_ext ]\nsubjectAltName = @alt_names\n\n[ alt_names ]\n{% for item in tls_sans %}\nIP.{{ loop.index }} = {{ item }}\n{% endfor %}\n\n[ req_distinguished_name ]\ncountryName = Country Name (2 letter code)\ncountryName_default = {{ tls_key_country }}\n\nstateOrProvinceName = State or Province Name (full name)\nstateOrProvinceName_default = {{ tls_key_province }}\n\nlocalityName = Locality Name (eg, city)\nlocalityName_default = {{ tls_key_city }}\n\n0.organizationName = Organization Name (eg, company)\n0.organizationName_default = {{ tls_key_org }}\n\norganizationalUnitName = Organizational Unit Name (eg, section)\norganizationalUnitName_default = {{ tls_key_ou }}\n\ncommonName = Common Name (eg, your name or your server\\'s hostname)\ncommonName_default = {{ tls_server_common_name.stdout }}\n\n[ v3_ca ]\nkeyUsage = digitalSignature, keyEncipherment\n\n[ server ]\nbasicConstraints=CA:FALSE\nnsComment = \"Ansible Generated Server Certificate\"\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid,issuer:always\nextendedKeyUsage=serverAuth\nkeyUsage = digitalSignature, keyEncipherment\nsubjectAltName = @alt_names\n\n[ client ]\nbasicConstraints=CA:FALSE\nnsComment = \"Ansible Generated Client Certificate\"\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid,issuer:always\nextendedKeyUsage=clientAuth\nkeyUsage = digitalSignature\n"
  },
  {
    "path": "playbooks/roles/certificates/vars/main.yml",
    "content": "---\ntls_request_subject: \"/C={{ tls_key_country }}/ST={{ tls_key_province }}/L={{ tls_key_city }}/O={{ tls_key_org }}/OU={{ tls_key_ou }}\"\n"
  },
  {
    "path": "playbooks/roles/cloudflared/defaults/main.yml",
    "content": "---\ncloudflared_base_url: \"https://bin.equinox.io/c/VdrWdbjqyF/\"\n\ncloudflared_amd64_apt: \"cloudflared-stable-linux-amd64.deb\"\ncloudflared_amd64_yum: \"cloudflared-stable-linux-amd64.rpm\"\ncloudflared_amd64_binary: \"cloudflared-stable-linux-amd64.tgz\"\ncloudflared_arm_apt: \"cloudflared-stable-linux-arm.deb\"\ncloudflared_arm_yum: \"cloudflared-stable-linux-arm.rpm\"\ncloudflared_arm_binary: \"cloudflared-stable-linux-arm.tgz\"\n\ncloudflared_allow_firewall: false\ncloudflared_enable_service: true\ncloudflared_upstream1: \"https://1.1.1.1/dns-query\"\ncloudflared_upstream2: \"https://1.0.0.1/dns-query\"\ncloudflared_port: 5053\n\ncloudflared_options: \"proxy-dns --port {{ cloudflared_port }} --upstream {{ cloudflared_upstream1 }} --upstream {{ cloudflared_upstream2 }}\"\n\ncloudflared_bin_location: /usr/local/bin\n"
  },
  {
    "path": "playbooks/roles/cloudflared/files/cloudflared.service",
    "content": "[Unit]\nDescription=cloudflared service\nAfter=syslog.target network-online.target\n\n[Service]\nType=simple\nUser=cloudflared\nEnvironmentFile=/etc/default/cloudflared\nExecStart=/usr/local/bin/cloudflared $CLOUDFLARED_OPTS\nRestart=on-failure\nRestartSec=10\nKillMode=process\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "playbooks/roles/cloudflared/handlers/main.yml",
    "content": "---\n- name: restart cloudflared service\n  systemd:\n    name: cloudflared.service\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/cloudflared/meta/main.yml",
    "content": "---\ndependencies:\n  - { role: dnsmasq }\n  - { role: ip-forwarding }\n"
  },
  {
    "path": "playbooks/roles/cloudflared/tasks/install_binary.yml",
    "content": "---\n- name: build filename of file to be downloaded\n  set_fact:\n    cloudflared_file: \"{{ vars['cloudflared_'+device_arch+'_binary'] }}\"\n\n- name: download correct file for device\n  get_url:\n    url: \"{{ cloudflared_base_url }}{{ cloudflared_file }}\"\n    dest: \"/tmp/{{ cloudflared_file }}\"\n    #checksum: \"{{ cloudflared_file_checksum }}\"\n\n- name: extract cloudflared into /usr/local/bin\n  unarchive:\n    src: \"/tmp/{{ cloudflared_file }}\"\n    dest: \"{{ cloudflared_bin_location }}\"\n    remote_src: yes\n"
  },
  {
    "path": "playbooks/roles/cloudflared/tasks/install_package.yml",
    "content": "---\n- name: build filename of file to be downloaded\n  set_fact:\n    cloudflared_file: \"{{ vars['cloudflared_'+device_arch+'_'+ansible_pkg_mgr] }}\"\n\n- name: download correct file for device\n  get_url:\n    url: \"{{ cloudflared_base_url }}{{ cloudflared_file }}\"\n    dest: \"/tmp/{{ cloudflared_file }}\"\n    #checksum: \"{{ cloudflared_file_checksum }}\"\n\n- name: Install a .deb package\n  apt:\n    deb: \"/tmp/{{ cloudflared_file }}\"\n    state: present\n  register: pkg_mgr_output\n  ignore_errors: true\n  when: ansible_pkg_mgr == 'apt'\n\n- name: Install a .rpm package\n  yum:\n    name: \"/tmp/{{ cloudflared_file }}\"\n    state: present\n  register: pkg_mgr_output\n  ignore_errors: true\n  when: ansible_pkg_mgr == 'yum'\n"
  },
  {
    "path": "playbooks/roles/cloudflared/tasks/main.yml",
    "content": "---\n- stat:\n    path: \"{{ cloudflared_bin_location }}/cloudflared\"\n  register: cloudflared_binary\n\n- set_fact:\n    cloudflared_installed: \"{{ cloudflared_binary.stat.exists | default(false) }}\"\n\n- name: set device architecture and package manager vars\n  set_fact:\n    device_arch: \"{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm' }}\"\n\n- name: install package\n  import_tasks: install_package.yml\n  when: (not cloudflared_installed) and (ansible_pkg_mgr == 'yum' or ansible_pkg_mgr == 'apt') and (ansible_architecture == 'x86_64' or ansible_architecture == 'arm')\n\n- name: install binary\n  import_tasks: install_binary.yml\n  when: (not cloudflared_installed) and ((pkg_mgr_output is undefined or pkg_mgr_output is failed) or ansible_architecture == 'armv7l')\n\n- name: Set network capabilities for cloudflared\n  capabilities:\n    path: \"{{ cloudflared_bin_location }}/cloudflared\"\n    capability: cap_net_bind_service+ep\n    state: present\n  when: cloudflared_port|int < 1024\n\n- command: cloudflared update\n  register: update_command\n  changed_when: update_command.rc == '64'\n\n- name: create cloudflared nologin user\n  become: yes\n  user:\n    name: cloudflared\n    shell: /usr/sbin/nologin\n    system: True\n    create_home: False\n\n- name: set ownership of /usr/local/bin/cloudflared\n  file:\n    path: /usr/local/bin/cloudflared\n    state: file\n    owner: cloudflared\n    group: cloudflared\n\n- name: template config file\n  template:\n    src: cloudflared.j2\n    dest: /etc/default/cloudflared\n    owner: cloudflared\n    group: cloudflared\n  notify: restart cloudflared service\n  tags: systemd\n\n- name: copy systemd service\n  copy:\n    src: cloudflared.service\n    dest: /etc/systemd/system/\n    owner: root\n    group: root\n    mode: 0644\n  notify: restart cloudflared service\n  register: service\n  tags: systemd\n\n- name: enable systemd service\n  service:\n    name: cloudflared\n    enabled: \"{{ cloudflared_enable_service }}\"\n  when: service.changed\n  tags: systemd\n\n- name: Allow port in firewall\n  ufw:\n    rule: allow\n    port: \"{{ cloudflared_port }}\"\n    comment: \"allow cloudflared\"\n  when: cloudflared_allow_firewall\n\n# DNSMASQ\n- name: Remove existing upstream servers in dnsmasq\n  replace:\n    path: /etc/dnsmasq.conf\n    regexp: \"^server=(.*)$\"\n\n- name: Set upstream DNS server to cloudflared proxy\n  lineinfile:\n    path: /etc/dnsmasq.conf\n    state: present\n    line: \"server=127.0.0.1#{{ cloudflared_port }}\"\n  notify: Restart dnsmasq\n"
  },
  {
    "path": "playbooks/roles/cloudflared/templates/cloudflared.j2",
    "content": "# Commandline args for cloudflared\nCLOUDFLARED_OPTS={{ cloudflared_options }}\n"
  },
  {
    "path": "playbooks/roles/cloudflared/vars/main.yml",
    "content": "---\n# Cloudflared variables\n"
  },
  {
    "path": "playbooks/roles/common/files/english.txt",
    "content": "abandon\nability\nable\nabout\nabove\nabsent\nabsorb\nabstract\nabsurd\nabuse\naccess\naccident\naccount\naccuse\nachieve\nacid\nacoustic\nacquire\nacross\nact\naction\nactor\nactress\nactual\nadapt\nadd\naddict\naddress\nadjust\nadmit\nadult\nadvance\nadvice\naerobic\naffair\nafford\nafraid\nagain\nage\nagent\nagree\nahead\naim\nair\nairport\naisle\nalarm\nalbum\nalcohol\nalert\nalien\nall\nalley\nallow\nalmost\nalone\nalpha\nalready\nalso\nalter\nalways\namateur\namazing\namong\namount\namused\nanalyst\nanchor\nancient\nanger\nangle\nangry\nanimal\nankle\nannounce\nannual\nanother\nanswer\nantenna\nantique\nanxiety\nany\napart\napology\nappear\napple\napprove\napril\narch\narctic\narea\narena\nargue\narm\narmed\narmor\narmy\naround\narrange\narrest\narrive\narrow\nart\nartefact\nartist\nartwork\nask\naspect\nassault\nasset\nassist\nassume\nasthma\nathlete\natom\nattack\nattend\nattitude\nattract\nauction\naudit\naugust\naunt\nauthor\nauto\nautumn\naverage\navocado\navoid\nawake\naware\naway\nawesome\nawful\nawkward\naxis\nbaby\nbachelor\nbacon\nbadge\nbag\nbalance\nbalcony\nball\nbamboo\nbanana\nbanner\nbar\nbarely\nbargain\nbarrel\nbase\nbasic\nbasket\nbattle\nbeach\nbean\nbeauty\nbecause\nbecome\nbeef\nbefore\nbegin\nbehave\nbehind\nbelieve\nbelow\nbelt\nbench\nbenefit\nbest\nbetray\nbetter\nbetween\nbeyond\nbicycle\nbid\nbike\nbind\nbiology\nbird\nbirth\nbitter\nblack\nblade\nblame\nblanket\nblast\nbleak\nbless\nblind\nblood\nblossom\nblouse\nblue\nblur\nblush\nboard\nboat\nbody\nboil\nbomb\nbone\nbonus\nbook\nboost\nborder\nboring\nborrow\nboss\nbottom\nbounce\nbox\nboy\nbracket\nbrain\nbrand\nbrass\nbrave\nbread\nbreeze\nbrick\nbridge\nbrief\nbright\nbring\nbrisk\nbroccoli\nbroken\nbronze\nbroom\nbrother\nbrown\nbrush\nbubble\nbuddy\nbudget\nbuffalo\nbuild\nbulb\nbulk\nbullet\nbundle\nbunker\nburden\nburger\nburst\nbus\nbusiness\nbusy\nbutter\nbuyer\nbuzz\ncabbage\ncabin\ncable\ncactus\ncage\ncake\ncall\ncalm\ncamera\ncamp\ncan\ncanal\ncancel\ncandy\ncannon\ncanoe\ncanvas\ncanyon\ncapable\ncapital\ncaptain\ncar\ncarbon\ncard\ncargo\ncarpet\ncarry\ncart\ncase\ncash\ncasino\ncastle\ncasual\ncat\ncatalog\ncatch\ncategory\ncattle\ncaught\ncause\ncaution\ncave\nceiling\ncelery\ncement\ncensus\ncentury\ncereal\ncertain\nchair\nchalk\nchampion\nchange\nchaos\nchapter\ncharge\nchase\nchat\ncheap\ncheck\ncheese\nchef\ncherry\nchest\nchicken\nchief\nchild\nchimney\nchoice\nchoose\nchronic\nchuckle\nchunk\nchurn\ncigar\ncinnamon\ncircle\ncitizen\ncity\ncivil\nclaim\nclap\nclarify\nclaw\nclay\nclean\nclerk\nclever\nclick\nclient\ncliff\nclimb\nclinic\nclip\nclock\nclog\nclose\ncloth\ncloud\nclown\nclub\nclump\ncluster\nclutch\ncoach\ncoast\ncoconut\ncode\ncoffee\ncoil\ncoin\ncollect\ncolor\ncolumn\ncombine\ncome\ncomfort\ncomic\ncommon\ncompany\nconcert\nconduct\nconfirm\ncongress\nconnect\nconsider\ncontrol\nconvince\ncook\ncool\ncopper\ncopy\ncoral\ncore\ncorn\ncorrect\ncost\ncotton\ncouch\ncountry\ncouple\ncourse\ncousin\ncover\ncoyote\ncrack\ncradle\ncraft\ncram\ncrane\ncrash\ncrater\ncrawl\ncrazy\ncream\ncredit\ncreek\ncrew\ncricket\ncrime\ncrisp\ncritic\ncrop\ncross\ncrouch\ncrowd\ncrucial\ncruel\ncruise\ncrumble\ncrunch\ncrush\ncry\ncrystal\ncube\nculture\ncup\ncupboard\ncurious\ncurrent\ncurtain\ncurve\ncushion\ncustom\ncute\ncycle\ndad\ndamage\ndamp\ndance\ndanger\ndaring\ndash\ndaughter\ndawn\nday\ndeal\ndebate\ndebris\ndecade\ndecember\ndecide\ndecline\ndecorate\ndecrease\ndeer\ndefense\ndefine\ndefy\ndegree\ndelay\ndeliver\ndemand\ndemise\ndenial\ndentist\ndeny\ndepart\ndepend\ndeposit\ndepth\ndeputy\nderive\ndescribe\ndesert\ndesign\ndesk\ndespair\ndestroy\ndetail\ndetect\ndevelop\ndevice\ndevote\ndiagram\ndial\ndiamond\ndiary\ndice\ndiesel\ndiet\ndiffer\ndigital\ndignity\ndilemma\ndinner\ndinosaur\ndirect\ndirt\ndisagree\ndiscover\ndisease\ndish\ndismiss\ndisorder\ndisplay\ndistance\ndivert\ndivide\ndivorce\ndizzy\ndoctor\ndocument\ndog\ndoll\ndolphin\ndomain\ndonate\ndonkey\ndonor\ndoor\ndose\ndouble\ndove\ndraft\ndragon\ndrama\ndrastic\ndraw\ndream\ndress\ndrift\ndrill\ndrink\ndrip\ndrive\ndrop\ndrum\ndry\nduck\ndumb\ndune\nduring\ndust\ndutch\nduty\ndwarf\ndynamic\neager\neagle\nearly\nearn\nearth\neasily\neast\neasy\necho\necology\neconomy\nedge\nedit\neducate\neffort\negg\neight\neither\nelbow\nelder\nelectric\nelegant\nelement\nelephant\nelevator\nelite\nelse\nembark\nembody\nembrace\nemerge\nemotion\nemploy\nempower\nempty\nenable\nenact\nend\nendless\nendorse\nenemy\nenergy\nenforce\nengage\nengine\nenhance\nenjoy\nenlist\nenough\nenrich\nenroll\nensure\nenter\nentire\nentry\nenvelope\nepisode\nequal\nequip\nera\nerase\nerode\nerosion\nerror\nerupt\nescape\nessay\nessence\nestate\neternal\nethics\nevidence\nevil\nevoke\nevolve\nexact\nexample\nexcess\nexchange\nexcite\nexclude\nexcuse\nexecute\nexercise\nexhaust\nexhibit\nexile\nexist\nexit\nexotic\nexpand\nexpect\nexpire\nexplain\nexpose\nexpress\nextend\nextra\neye\neyebrow\nfabric\nface\nfaculty\nfade\nfaint\nfaith\nfall\nfalse\nfame\nfamily\nfamous\nfan\nfancy\nfantasy\nfarm\nfashion\nfat\nfatal\nfather\nfatigue\nfault\nfavorite\nfeature\nfebruary\nfederal\nfee\nfeed\nfeel\nfemale\nfence\nfestival\nfetch\nfever\nfew\nfiber\nfiction\nfield\nfigure\nfile\nfilm\nfilter\nfinal\nfind\nfine\nfinger\nfinish\nfire\nfirm\nfirst\nfiscal\nfish\nfit\nfitness\nfix\nflag\nflame\nflash\nflat\nflavor\nflee\nflight\nflip\nfloat\nflock\nfloor\nflower\nfluid\nflush\nfly\nfoam\nfocus\nfog\nfoil\nfold\nfollow\nfood\nfoot\nforce\nforest\nforget\nfork\nfortune\nforum\nforward\nfossil\nfoster\nfound\nfox\nfragile\nframe\nfrequent\nfresh\nfriend\nfringe\nfrog\nfront\nfrost\nfrown\nfrozen\nfruit\nfuel\nfun\nfunny\nfurnace\nfury\nfuture\ngadget\ngain\ngalaxy\ngallery\ngame\ngap\ngarage\ngarbage\ngarden\ngarlic\ngarment\ngas\ngasp\ngate\ngather\ngauge\ngaze\ngeneral\ngenius\ngenre\ngentle\ngenuine\ngesture\nghost\ngiant\ngift\ngiggle\nginger\ngiraffe\ngirl\ngive\nglad\nglance\nglare\nglass\nglide\nglimpse\nglobe\ngloom\nglory\nglove\nglow\nglue\ngoat\ngoddess\ngold\ngood\ngoose\ngorilla\ngospel\ngossip\ngovern\ngown\ngrab\ngrace\ngrain\ngrant\ngrape\ngrass\ngravity\ngreat\ngreen\ngrid\ngrief\ngrit\ngrocery\ngroup\ngrow\ngrunt\nguard\nguess\nguide\nguilt\nguitar\ngun\ngym\nhabit\nhair\nhalf\nhammer\nhamster\nhand\nhappy\nharbor\nhard\nharsh\nharvest\nhat\nhave\nhawk\nhazard\nhead\nhealth\nheart\nheavy\nhedgehog\nheight\nhello\nhelmet\nhelp\nhen\nhero\nhidden\nhigh\nhill\nhint\nhip\nhire\nhistory\nhobby\nhockey\nhold\nhole\nholiday\nhollow\nhome\nhoney\nhood\nhope\nhorn\nhorror\nhorse\nhospital\nhost\nhotel\nhour\nhover\nhub\nhuge\nhuman\nhumble\nhumor\nhundred\nhungry\nhunt\nhurdle\nhurry\nhurt\nhusband\nhybrid\nice\nicon\nidea\nidentify\nidle\nignore\nill\nillegal\nillness\nimage\nimitate\nimmense\nimmune\nimpact\nimpose\nimprove\nimpulse\ninch\ninclude\nincome\nincrease\nindex\nindicate\nindoor\nindustry\ninfant\ninflict\ninform\ninhale\ninherit\ninitial\ninject\ninjury\ninmate\ninner\ninnocent\ninput\ninquiry\ninsane\ninsect\ninside\ninspire\ninstall\nintact\ninterest\ninto\ninvest\ninvite\ninvolve\niron\nisland\nisolate\nissue\nitem\nivory\njacket\njaguar\njar\njazz\njealous\njeans\njelly\njewel\njob\njoin\njoke\njourney\njoy\njudge\njuice\njump\njungle\njunior\njunk\njust\nkangaroo\nkeen\nkeep\nketchup\nkey\nkick\nkid\nkidney\nkind\nkingdom\nkiss\nkit\nkitchen\nkite\nkitten\nkiwi\nknee\nknife\nknock\nknow\nlab\nlabel\nlabor\nladder\nlady\nlake\nlamp\nlanguage\nlaptop\nlarge\nlater\nlatin\nlaugh\nlaundry\nlava\nlaw\nlawn\nlawsuit\nlayer\nlazy\nleader\nleaf\nlearn\nleave\nlecture\nleft\nleg\nlegal\nlegend\nleisure\nlemon\nlend\nlength\nlens\nleopard\nlesson\nletter\nlevel\nliar\nliberty\nlibrary\nlicense\nlife\nlift\nlight\nlike\nlimb\nlimit\nlink\nlion\nliquid\nlist\nlittle\nlive\nlizard\nload\nloan\nlobster\nlocal\nlock\nlogic\nlonely\nlong\nloop\nlottery\nloud\nlounge\nlove\nloyal\nlucky\nluggage\nlumber\nlunar\nlunch\nluxury\nlyrics\nmachine\nmad\nmagic\nmagnet\nmaid\nmail\nmain\nmajor\nmake\nmammal\nman\nmanage\nmandate\nmango\nmansion\nmanual\nmaple\nmarble\nmarch\nmargin\nmarine\nmarket\nmarriage\nmask\nmass\nmaster\nmatch\nmaterial\nmath\nmatrix\nmatter\nmaximum\nmaze\nmeadow\nmean\nmeasure\nmeat\nmechanic\nmedal\nmedia\nmelody\nmelt\nmember\nmemory\nmention\nmenu\nmercy\nmerge\nmerit\nmerry\nmesh\nmessage\nmetal\nmethod\nmiddle\nmidnight\nmilk\nmillion\nmimic\nmind\nminimum\nminor\nminute\nmiracle\nmirror\nmisery\nmiss\nmistake\nmix\nmixed\nmixture\nmobile\nmodel\nmodify\nmom\nmoment\nmonitor\nmonkey\nmonster\nmonth\nmoon\nmoral\nmore\nmorning\nmosquito\nmother\nmotion\nmotor\nmountain\nmouse\nmove\nmovie\nmuch\nmuffin\nmule\nmultiply\nmuscle\nmuseum\nmushroom\nmusic\nmust\nmutual\nmyself\nmystery\nmyth\nnaive\nname\nnapkin\nnarrow\nnasty\nnation\nnature\nnear\nneck\nneed\nnegative\nneglect\nneither\nnephew\nnerve\nnest\nnet\nnetwork\nneutral\nnever\nnews\nnext\nnice\nnight\nnoble\nnoise\nnominee\nnoodle\nnormal\nnorth\nnose\nnotable\nnote\nnothing\nnotice\nnovel\nnow\nnuclear\nnumber\nnurse\nnut\noak\nobey\nobject\noblige\nobscure\nobserve\nobtain\nobvious\noccur\nocean\noctober\nodor\noff\noffer\noffice\noften\noil\nokay\nold\nolive\nolympic\nomit\nonce\none\nonion\nonline\nonly\nopen\nopera\nopinion\noppose\noption\norange\norbit\norchard\norder\nordinary\norgan\norient\noriginal\norphan\nostrich\nother\noutdoor\nouter\noutput\noutside\noval\noven\nover\nown\nowner\noxygen\noyster\nozone\npact\npaddle\npage\npair\npalace\npalm\npanda\npanel\npanic\npanther\npaper\nparade\nparent\npark\nparrot\nparty\npass\npatch\npath\npatient\npatrol\npattern\npause\npave\npayment\npeace\npeanut\npear\npeasant\npelican\npen\npenalty\npencil\npeople\npepper\nperfect\npermit\nperson\npet\nphone\nphoto\nphrase\nphysical\npiano\npicnic\npicture\npiece\npig\npigeon\npill\npilot\npink\npioneer\npipe\npistol\npitch\npizza\nplace\nplanet\nplastic\nplate\nplay\nplease\npledge\npluck\nplug\nplunge\npoem\npoet\npoint\npolar\npole\npolice\npond\npony\npool\npopular\nportion\nposition\npossible\npost\npotato\npottery\npoverty\npowder\npower\npractice\npraise\npredict\nprefer\nprepare\npresent\npretty\nprevent\nprice\npride\nprimary\nprint\npriority\nprison\nprivate\nprize\nproblem\nprocess\nproduce\nprofit\nprogram\nproject\npromote\nproof\nproperty\nprosper\nprotect\nproud\nprovide\npublic\npudding\npull\npulp\npulse\npumpkin\npunch\npupil\npuppy\npurchase\npurity\npurpose\npurse\npush\nput\npuzzle\npyramid\nquality\nquantum\nquarter\nquestion\nquick\nquit\nquiz\nquote\nrabbit\nraccoon\nrace\nrack\nradar\nradio\nrail\nrain\nraise\nrally\nramp\nranch\nrandom\nrange\nrapid\nrare\nrate\nrather\nraven\nraw\nrazor\nready\nreal\nreason\nrebel\nrebuild\nrecall\nreceive\nrecipe\nrecord\nrecycle\nreduce\nreflect\nreform\nrefuse\nregion\nregret\nregular\nreject\nrelax\nrelease\nrelief\nrely\nremain\nremember\nremind\nremove\nrender\nrenew\nrent\nreopen\nrepair\nrepeat\nreplace\nreport\nrequire\nrescue\nresemble\nresist\nresource\nresponse\nresult\nretire\nretreat\nreturn\nreunion\nreveal\nreview\nreward\nrhythm\nrib\nribbon\nrice\nrich\nride\nridge\nrifle\nright\nrigid\nring\nriot\nripple\nrisk\nritual\nrival\nriver\nroad\nroast\nrobot\nrobust\nrocket\nromance\nroof\nrookie\nroom\nrose\nrotate\nrough\nround\nroute\nroyal\nrubber\nrude\nrug\nrule\nrun\nrunway\nrural\nsad\nsaddle\nsadness\nsafe\nsail\nsalad\nsalmon\nsalon\nsalt\nsalute\nsame\nsample\nsand\nsatisfy\nsatoshi\nsauce\nsausage\nsave\nsay\nscale\nscan\nscare\nscatter\nscene\nscheme\nschool\nscience\nscissors\nscorpion\nscout\nscrap\nscreen\nscript\nscrub\nsea\nsearch\nseason\nseat\nsecond\nsecret\nsection\nsecurity\nseed\nseek\nsegment\nselect\nsell\nseminar\nsenior\nsense\nsentence\nseries\nservice\nsession\nsettle\nsetup\nseven\nshadow\nshaft\nshallow\nshare\nshed\nshell\nsheriff\nshield\nshift\nshine\nship\nshiver\nshock\nshoe\nshoot\nshop\nshort\nshoulder\nshove\nshrimp\nshrug\nshuffle\nshy\nsibling\nsick\nside\nsiege\nsight\nsign\nsilent\nsilk\nsilly\nsilver\nsimilar\nsimple\nsince\nsing\nsiren\nsister\nsituate\nsix\nsize\nskate\nsketch\nski\nskill\nskin\nskirt\nskull\nslab\nslam\nsleep\nslender\nslice\nslide\nslight\nslim\nslogan\nslot\nslow\nslush\nsmall\nsmart\nsmile\nsmoke\nsmooth\nsnack\nsnake\nsnap\nsniff\nsnow\nsoap\nsoccer\nsocial\nsock\nsoda\nsoft\nsolar\nsoldier\nsolid\nsolution\nsolve\nsomeone\nsong\nsoon\nsorry\nsort\nsoul\nsound\nsoup\nsource\nsouth\nspace\nspare\nspatial\nspawn\nspeak\nspecial\nspeed\nspell\nspend\nsphere\nspice\nspider\nspike\nspin\nspirit\nsplit\nspoil\nsponsor\nspoon\nsport\nspot\nspray\nspread\nspring\nspy\nsquare\nsqueeze\nsquirrel\nstable\nstadium\nstaff\nstage\nstairs\nstamp\nstand\nstart\nstate\nstay\nsteak\nsteel\nstem\nstep\nstereo\nstick\nstill\nsting\nstock\nstomach\nstone\nstool\nstory\nstove\nstrategy\nstreet\nstrike\nstrong\nstruggle\nstudent\nstuff\nstumble\nstyle\nsubject\nsubmit\nsubway\nsuccess\nsuch\nsudden\nsuffer\nsugar\nsuggest\nsuit\nsummer\nsun\nsunny\nsunset\nsuper\nsupply\nsupreme\nsure\nsurface\nsurge\nsurprise\nsurround\nsurvey\nsuspect\nsustain\nswallow\nswamp\nswap\nswarm\nswear\nsweet\nswift\nswim\nswing\nswitch\nsword\nsymbol\nsymptom\nsyrup\nsystem\ntable\ntackle\ntag\ntail\ntalent\ntalk\ntank\ntape\ntarget\ntask\ntaste\ntattoo\ntaxi\nteach\nteam\ntell\nten\ntenant\ntennis\ntent\nterm\ntest\ntext\nthank\nthat\ntheme\nthen\ntheory\nthere\nthey\nthing\nthis\nthought\nthree\nthrive\nthrow\nthumb\nthunder\nticket\ntide\ntiger\ntilt\ntimber\ntime\ntiny\ntip\ntired\ntissue\ntitle\ntoast\ntobacco\ntoday\ntoddler\ntoe\ntogether\ntoilet\ntoken\ntomato\ntomorrow\ntone\ntongue\ntonight\ntool\ntooth\ntop\ntopic\ntopple\ntorch\ntornado\ntortoise\ntoss\ntotal\ntourist\ntoward\ntower\ntown\ntoy\ntrack\ntrade\ntraffic\ntragic\ntrain\ntransfer\ntrap\ntrash\ntravel\ntray\ntreat\ntree\ntrend\ntrial\ntribe\ntrick\ntrigger\ntrim\ntrip\ntrophy\ntrouble\ntruck\ntrue\ntruly\ntrumpet\ntrust\ntruth\ntry\ntube\ntuition\ntumble\ntuna\ntunnel\nturkey\nturn\nturtle\ntwelve\ntwenty\ntwice\ntwin\ntwist\ntwo\ntype\ntypical\nugly\numbrella\nunable\nunaware\nuncle\nuncover\nunder\nundo\nunfair\nunfold\nunhappy\nuniform\nunique\nunit\nuniverse\nunknown\nunlock\nuntil\nunusual\nunveil\nupdate\nupgrade\nuphold\nupon\nupper\nupset\nurban\nurge\nusage\nuse\nused\nuseful\nuseless\nusual\nutility\nvacant\nvacuum\nvague\nvalid\nvalley\nvalve\nvan\nvanish\nvapor\nvarious\nvast\nvault\nvehicle\nvelvet\nvendor\nventure\nvenue\nverb\nverify\nversion\nvery\nvessel\nveteran\nviable\nvibrant\nvicious\nvictory\nvideo\nview\nvillage\nvintage\nviolin\nvirtual\nvirus\nvisa\nvisit\nvisual\nvital\nvivid\nvocal\nvoice\nvoid\nvolcano\nvolume\nvote\nvoyage\nwage\nwagon\nwait\nwalk\nwall\nwalnut\nwant\nwarfare\nwarm\nwarrior\nwash\nwasp\nwaste\nwater\nwave\nway\nwealth\nweapon\nwear\nweasel\nweather\nweb\nwedding\nweekend\nweird\nwelcome\nwest\nwet\nwhale\nwhat\nwheat\nwheel\nwhen\nwhere\nwhip\nwhisper\nwide\nwidth\nwife\nwild\nwill\nwin\nwindow\nwine\nwing\nwink\nwinner\nwinter\nwire\nwisdom\nwise\nwish\nwitness\nwolf\nwoman\nwonder\nwood\nwool\nword\nwork\nworld\nworry\nworth\nwrap\nwreck\nwrestle\nwrist\nwrite\nwrong\nyard\nyear\nyellow\nyou\nyoung\nyouth\nzebra\nzero\nzone\nzoo\n"
  },
  {
    "path": "playbooks/roles/common/files/footer.html",
    "content": "</body>\n</html>"
  },
  {
    "path": "playbooks/roles/common/files/header.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\" />\n    <meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\" />\n    <meta content=\"IE=edge\" http-equiv=\"X-UA-Compatible\" />\n    <link href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAMFBMVEUAAABYWFhra2tCQkK4uLj09PT///+NjY3p6enR0dHFxcUmJiacnJzd3d2qqqp9fX2xNhOVAAAAl0lEQVR42t2RUQ7EIAhEK6KCYvf+t12Jrdlkxx6g80XgGZjxeKMCUdxPI6c8lHjDlLxU0Jx8IqrZRQCo18vGo6gAGG2dVRp3YEDaPMbMANCdsODlowlh2yVxLpcaMEH1JhIdWO1z9km0h8ANZ1lU79VO/Pr86xIE4rqt+a3AB/vqbsbiRpGDnpcEZ2VypcBbk8H/iY736QuY2AVel91hIQAAAABJRU5ErkJggg==\" rel=\"icon\" />\n    <title>STREISAND</title>\n\n    <style>\n    html {\n      font-size: 100%;\n      -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n      text-rendering: optimizelegibility;\n    }\n\n    body {\n      margin: 1em auto;\n      padding: 1em;\n      line-height: 1.6875;\n      max-width: 44em;\n      font-family: Georgia, Palatino, 'Palatino Linotype', 'Times New Roman', serif;\n      font-size: 16px;\n      background: #fff;\n      color:#333;\n    }\n\n    h1,\n    h2,\n    h3,\n    h4,\n    h5,\n    h6 {\n      font-weight: normal;\n      color: #111;\n      font-family: \"Helvetica Neue\", Helvetica, sans-serif;\n      font-weight: bold;\n      margin: 0;\n      line-height: 1.3;\n    }\n\n    h4,\n    h5,\n    h6 {\n      font-weight: bold;\n    }\n    \n    h1 {\n      font-size: 3.157em;\n\n    }\n\n    h2 {\n      margin-top: 2em;\n      font-size:1.777em;\n    }\n\n    h3 {\n      margin-top: 1.5em;\n      font-size: 1.333em;\n    }\n\n    h4 {\n      font-size:1em;\n    }\n\n    h5 {\n      font-size:0.9em;\n    }\n\n    h6 {\n      font-size:0.8em;\n    }\n\n    h5 + p,\n    h5 + pre {\n      margin-top: 0.25em;\n    }\n\n    ul,\n    ol {\n      margin: 1em 0 2em;\n      padding: 0 0 0 2em;\n    }\n\n    li + li {\n      margin-top: 0.5em;\n    }\n\n    ul + h3,\n    ol + h3 {\n      margin-top: 2em;\n    }\n\n    /*p em:only-child {\n      font-size: 1.333em;\n    }*/\n\n    /*p.lead {\n      margin-top: -0.25em;\n    }*/\n\n    li p:last-child {\n      margin:0;\n    }\n\n    p {\n      margin: 1em 0;\n    }\n\n    a {\n      text-decoration: none;\n      border-bottom: 1px solid #555;\n      color: #333;\n      display: inline-block;\n    }\n\n    a:hover {\n      color: white;\n      border-bottom-color: black;\n      background-color: black;\n      padding: 0 0.5em;\n      margin: 0 -0.5em;\n    }\n\n    a:hover,\n    a:active {\n      outline: 0;\n    }\n\n    ::-moz-selection,\n    a::-moz-selection {\n      background: rgba(0,0,0,0.1);\n      color: black;\n    }\n\n    ::selection,\n    a::selection {\n      background: rgba(0,0,0,0.1);\n      color: black;\n    }\n\n    img {\n      max-width:100%;\n      border: 0;\n      -ms-interpolation-mode: bicubic;\n      vertical-align: middle;\n    }\n\n    b,\n    strong {\n      font-weight: bold;\n    }\n\n    blockquote {\n      color:#666666;\n      margin:0;\n      padding-left: 3em;\n      border-left: 0.5em #EEE solid;\n    }\n\n    hr {\n      display: none;\n    }\n\n    pre,\n    code { \n      color: #000; \n      font-family: Consolas, monaco, monospace;\n      font-size: 0.88em; \n      background-color: #e6e6e6;\n    }\n\n    code {\n      padding: 4px 6px 0;\n      display: inline-block;\n    }\n\n    pre {\n      padding: 4px 6px 0;\n      white-space: pre;\n      overflow-x: auto;\n    }\n\n    pre code {\n      padding: 0;\n      background-color: transparent;\n      font-size: 1em;\n    }\n\n\n    sub,\n    sup {\n      font-size: 75%;\n      line-height: 0;\n      position: relative;\n      vertical-align: baseline;\n    }\n    \n    sup {\n      top: -0.5em;\n    }\n    \n    sub {\n      bottom: -0.25em;\n    }\n\n    .logo {\n      position: relative;\n      display: inline-block;\n      margin: 0 0 0.5em 0 !important;\n      padding: 0.1em 0.5em !important;\n      -webkit-font-smoothing: auto !important;\n      background-color: black;\n      color: white;\n      font-weight: bold;\n      font-family: \"Helvetica Neue\", Helvetica, sans-serif;\n      text-transform: uppercase;\n      font-size: 2em;\n      letter-spacing: 1px;\n      border: 0;\n    }\n\n    .logo:hover {\n      border: 0;\n      background-color: white;\n      color: black;\n    }\n\n    .logo:hover hr {\n      display: inline-block;\n      position: absolute;\n      height: 30%;\n      left: 0.4em;\n      right: 0.4em;\n      top: 9%;\n      border: 0;\n      background-color: black;\n      background-color: rgba(0,0,0,0.9);\n    }\n\n    hr + ul {\n      background-color: #f6f6f6;\n      padding: 1em 2em;\n      margin-top: 1.5em;\n      list-style-type: none;\n    }\n\n    hr + ul a {\n      text-decoration: none;\n    }\n\n    hr + ul li + li {\n      margin-top: 0.25em;\n    }\n\n    hr + ul ul {\n      margin-top: 0.25em;\n      margin-bottom: 1em;\n    }\n\n    a[download] {\n      border: 2px solid #333;\n      color: #333;\n      display: inline-block;\n      padding: 14px 18px;\n      font-family: \"Helvetica Neue\", Helvetica, sans-serif;\n      font-weight: bold;\n      font-size: 15px;\n      line-height: 16px;\n      outline: none;\n      text-align: center;\n      margin: 1em 0;\n      text-transform: uppercase;\n    }\n\n    a[download]:hover {\n      background-color: black;\n      border-color: black;\n      color: white;\n      -webkit-font-smoothing: antialiased;\n    }\n\n    a[download] img {\n      vertical-align: top;\n      margin-right: 0.5em;\n      margin-left: -0.5em;\n    }\n\n    @media (max-width: 479px) {\n      a[download] {\n        display: block;\n      }\n    }\n\n    </style>\n\n    <script>\n      document.addEventListener('click', function (e) {\n        if (e.target.getAttribute('href') === '#download') {\n          e.preventDefault(); document.getElementById('download').click();\n        }\n      });\n    </script>\n  </head>\n  <body>\n    <a href='/' class='logo'>Streisand<hr/></a>\n"
  },
  {
    "path": "playbooks/roles/common/tasks/detect-public-ip.yml",
    "content": "---\n# detect-public-ip.yml will attempt to identify whether the server's public\n# IP address is different from what is visible on the host and, if\n# successfully detected, ask to update the address for documentation and\n# configuration profiles\n- name: \"Install dns module\"\n  apt:\n    package: dnsutils\n\n- name: \"Initialize lookup variable\"\n  set_fact:\n    external_ipv4_address: \"presumed_failed\"\n\n- name: \"Check external IP Address through Google\"\n  command: dig -4 +short myip.opendns.com @resolver1.opendns.com A\n  register: dig_output\n\n- name: \"Set the variable to the value\"\n  set_fact:\n    external_ipv4_address: \"{{ dig_output.stdout | regex_replace('\\\"', '') }}\"\n    when: (dig_output.rc == 0)\n\n# Enter this block only when when the IPs are different and query user for updating\n# to public ip\n- block:\n    - name: \"Initialize the prompt\"\n      set_fact:\n        prompt_external_ip: |\n          We have found another public IP address of your server\n\n          Some cloud providers use load balancers or SDN to make servers externally\n          reachable. It seems\n          - {{ external_ipv4_address }} is publicly visible\n          - {{ streisand_ipv4_address }} is visible on the server\n\n          Type 'yes' to use {{ external_ipv4_address }} for the VPN\n          Hit 'enter' to skip and use {{ streisand_ipv4_address }}.\n\n          Skip with 'enter' if you do not know {{ external_ipv4_address }}\n\n    - name: \"Ask user to update to public IP address\"\n      pause:\n        prompt: \"{{ prompt_external_ip }}\"\n      register: publish_external\n\n    - name: \"Change streisand_ipv4_address to public if requested\"\n      set_fact:\n        streisand_ipv4_address: \"{{ external_ipv4_address }}\"\n      when: ((publish_external.user_input == \"yes\") or (publish_external.user_input == \"Yes\") or (publish_external.user_input == \"YES\") or (publish_external.user_input == \"Y\") or (publish_external.user_input == \"y\"))\n  when: (external_ipv4_address != \"presumed_failed\") and (streisand_ipv4_address != external_ipv4_address)\n...\n"
  },
  {
    "path": "playbooks/roles/common/tasks/main.yml",
    "content": "---\n- name: Warn users if the server's Linux distribution is not Ubuntu 16.04\n  pause:\n    prompt: \"Ubuntu 16.04 is the only officially supported distribution; the setup will probably fail. Press Enter if you still want to continue.\"\n  when: not streisand_noninteractive and (ansible_distribution != \"Ubuntu\" or ansible_distribution_version != \"16.04\")\n\n# Set default variables\n- import_tasks: set-default-variables.yml\n\n- name: Ensure the APT cache is up to date\n  apt:\n    update_cache: yes\n    cache_valid_time: 3600\n\n- name: Install Streisand common packages\n  apt:\n    package: \"{{ streisand_common_packages }}\"\n\n- name: Purge unneeded services\n  apt:\n    package: \"{{ streisand_unneeded_packages }}\"\n    state: \"absent\"\n    purge: yes\n    autoremove: yes\n\n- name: Perform a full system upgrade\n  apt:\n    upgrade: \"safe\"\n\n- name: Copy the English BIP-0039 wordlist\n  copy:\n    src: english.txt\n    dest: /usr/share/dict\n    owner: root\n    group: root\n    mode: 0644\n\n- name: Generate random VPN client names\n  shell: \"{{ streisand_word_gen.identifier_max_len_15 }}\"\n  register: \"vpn_client_names\"\n  with_sequence: count={{ vpn_clients }}\n\n- name: Ensure the Streisand gateway directory exists\n  file:\n    path: \"{{ streisand_gateway_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0750\n    state: directory\n\n- name: Output the random VPN client names to disk for integration tests\n  template:\n    src: \"test-client-inventory.j2\"\n    dest: \"{{ streisand_gateway_location }}/test-client-inventory\"\n  when: streisand_client_test\n\n- name: Copy the HTML header and footer templates that are used during documentation generation\n  copy:\n    src: \"{{ item.src }}\"\n    dest: \"{{ item.dest }}\"\n  with_items:\n    - { src: \"header.html\", dest: \"{{ streisand_header_template }}\" }\n    - { src: \"footer.html\", dest: \"{{ streisand_footer_template }}\" }\n\n- name: Generate the unattended-upgrades templates to enable automatic security updates\n  template:\n    src: \"{{ item.src }}\"\n    dest: \"{{ item.dest }}\"\n    owner: root\n    group: root\n    mode: 0644\n  with_items:\n    - { src: \"20auto-upgrades.j2\",       dest: \"/etc/apt/apt.conf.d/20auto-upgrades\" }\n    - { src: \"50unattended-upgrades.j2\", dest: \"/etc/apt/apt.conf.d/50unattended-upgrades\" }\n\n- name: Apply the custom sysctl values\n  include_role:\n    name: sysctl\n"
  },
  {
    "path": "playbooks/roles/common/tasks/set-default-variables.yml",
    "content": "---\n# Some providers (e.g. Amazon EC2) assign internal 172.x.x.x IP\n# addresses to their virtual machines. It's important to use the real\n# public IP in the instructions Streisand generates, because the\n# internal addresses are not publicly accessible.\n#\n# Some providers (e.g. Amazon EC2 and Linode) do not use the name that\n# is provided in the API call as the server's hostname. It's important\n# to use the friendly name in the instructions rather than an ugly,\n# randomly generated hostname.\n#\n# Each 'genesis' role for the providers that Streisand natively supports\n# sets the streisand_ipv4_address and streisand_server_name variables in\n# an attempt to correct the limitations laid out above. However, it is\n# also necessary to fall back to default sane values if users choose to\n# run Streisand on their own servers or against other cloud providers.\n#\n# These conditionals are here for that very reason :)\n\n- name: Set the streisand_ipv4_address variable to the value provided by a 'genesis' role if one is defined\n  set_fact:\n    streisand_ipv4_address: \"{{ hostvars['127.0.0.1']['streisand_ipv4_address'] }}\"\n  when: hostvars['127.0.0.1']['streisand_ipv4_address'] is defined\n\n- name: Set the streisand_ipv4_address variable to the default value if it doesn't already have one. The default is the value defined in the inventory file, which should be the IP address of the server that is being configured.\n  set_fact:\n    streisand_ipv4_address: \"{{ inventory_hostname }}\"\n  when: streisand_ipv4_address is not defined\n\n- name: Set the streisand_server_name variable to the value provided by a 'genesis' role if one is defined\n  set_fact:\n    streisand_server_name: \"{{ hostvars['127.0.0.1']['streisand_server_name'] }}\"\n  when: hostvars['127.0.0.1']['streisand_server_name'] is defined\n\n- name: Set the streisand_server_name variable to the default value if it doesn't already have one. The default is the value of the hostname retrieved from the server that is being configured.\n  set_fact:\n    streisand_server_name: \"{{ ansible_hostname }}\"\n  when: streisand_server_name is not defined\n\n- import_tasks: detect-public-ip.yml\n  when: (hostvars['127.0.0.1']['streisand_genesis_role'] is defined and ((hostvars['127.0.0.1']['streisand_genesis_role'] == \"localhost\") or (hostvars['127.0.0.1']['streisand_genesis_role'] == \"existing-server\")))\n"
  },
  {
    "path": "playbooks/roles/common/templates/20auto-upgrades.j2",
    "content": "APT::Periodic::Update-Package-Lists \"1\";\nAPT::Periodic::Unattended-Upgrade \"1\";\n"
  },
  {
    "path": "playbooks/roles/common/templates/50unattended-upgrades.j2",
    "content": "// Automatically upgrade packages from these (origin, archive) pairs\nUnattended-Upgrade::Allowed-Origins {\n    // ${distro_id} and ${distro_codename} will be automatically expanded\n    \"${distro_id} stable\";\n    \"${distro_id} ${distro_codename}-security\";\n\n    // Autoupdate Nginx\n    \"nginx:${distro_codename}\";\n\n{% if streisand_openvpn_enabled %}\n    // Autoupdate OpenVPN\n    \"Freight:${distro_codename}\";\n{% endif %}\n\n{% if streisand_shadowsocks_enabled %}\n    // Autoupdate shadowsocks-libev\n    \"LP-PPA-max-c-lv-shadowsocks-libev:${distro_codename}\";\n{% endif %}\n\n{% if streisand_tor_enabled %}\n    // Autoupdate Tor\n    \"TorProject:${distro_codename}\";\n{% endif %}\n\n{% if streisand_wireguard_enabled %}\n    // Autoupdate WireGuard\n    \"LP-PPA-wireguard-wireguard:${distro_codename}\";\n{% endif %}\n};\n\n// List of packages to not update\nUnattended-Upgrade::Package-Blacklist {\n};\n\n// Do automatic removal of new unused dependencies after the upgrade\n// (equivalent to apt-get autoremove)\nUnattended-Upgrade::Remove-Unused-Dependencies \"true\";\n\n// Automatically reboot *WITHOUT CONFIRMATION* if a\n// the file /var/run/reboot-required is found after the upgrade\nUnattended-Upgrade::Automatic-Reboot \"true\";\n\n// If automatic reboot is enabled and needed, reboot at the specific\n// time instead of immediately\n//  Default: \"now\"\nUnattended-Upgrade::Automatic-Reboot-Time \"00:00\";\n\n// Avoid conffile dpkg prompt by *always* leaving the modified configuration in\n// place and putting the new package configuration in a .dpkg-dist file\nDpkg::Options {\n   \"--force-confdef\";\n   \"--force-confold\";\n};\n"
  },
  {
    "path": "playbooks/roles/common/templates/test-client-inventory.j2",
    "content": "{% for client_name in vpn_client_names.results %}\n{{ client_name.stdout }}\n{% endfor %}\n"
  },
  {
    "path": "playbooks/roles/common/vars/main.yml",
    "content": "---\nstreisand_common_packages:\n  # Ensure that Apparmor is installed\n  - apparmor\n  # Enables support for the HTTPS protocol in APT sources\n  - apt-transport-https\n  # Used to perform a system upgrade\n  - aptitude\n  # Used to compile Libreswan and OpenConnect Server (ocserv)\n  - build-essential\n  # Used to perform API requests, including the version check for\n  # the Tor Browser Bundle\n  - curl\n  # Enables automation of programs and scripts that ask for user input\n  - expect\n  # Legacy GPG is required by the Ansible apt_repository task\n  - gnupg\n  # Used to configure firewall rules\n  - iptables\n  # Used for documentation generation\n  - markdown\n  # Ensures the server's clock is set properly\n  - ntp\n  # Required to use the Ansible `expect` module\n  - python-pexpect\n  # Required for the apt_repository module\n  - software-properties-common\n  # Used to generate convenient QR codes for mobile clients in the\n  # Shadowsocks, Tor, and WireGuard roles\n  - qrencode\n  # Used for automatically installing security updates\n  - unattended-upgrades\n  # A UUID generator with an explicit random function.\n  # Used for generating UUIDs for mobileconfig files\n  - uuid\n  # Install git for source code retrieval and use with \"go get\" command\n  - git\n\n# Services that are running by default but not needed by Streisand\nstreisand_unneeded_packages:\n  - lxd\n  - snapd\n\nstreisand_gateway_location: \"/var/www/streisand\"\n\nstreisand_mirror_location: \"{{ streisand_gateway_location }}/mirror\"\n\nstreisand_local_directory: \"generated-docs\"\n\nstreisand_header_template: \"/tmp/header.html\"\nstreisand_footer_template: \"/tmp/footer.html\"\nstreisand_language_selector: \"/tmp/languages.html\"\n\n# By default concurrent executions of `iptables` will fail immediately if unable\n# to acquire a lock. We use the `--wait` argument to instead specify a maximum\n# number of seconds to wait before failing. This allows multiple services to add\n# iptables rules at once. See Issue #950 for longer term ideas on how to make\n# this var not required.\nstreisand_iptables_wait: 120\n\n# Internationalization\nstreisand_languages:\n  en:\n    file_suffix: \"\"\n    language_name: \"English\"\n    tor_locale: \"en-US\"\n  fr:\n    file_suffix: \"-fr\"\n    language_name: \"Français\"\n    tor_locale: \"fr\"\n\nstreisand_shuf: \"shuf --random-source=/dev/urandom\"\n\n# NOTE(@cpu): using the \"folded block scalar\" YAML syntax in the\n# `streisand_word_gen` entries seems to be the best way to both:\n#   a) split up the long command lines\n#   b) use templated variables like {{ striesand_shuf }}.\n# It has the unfortunate downside of leaving a trailing `\\n` in the var content\n# which can cause problems in usage like:\n#  `shell: {{ streisand_word_gen.identifier }} > foo`\n# The work-around/solution is to use:\n#  `shell: {{ streisand_word_gen.identifier | trim }} > foo`\n# If you, clever reader, have a better idea please open a PR! :-)\nstreisand_word_gen:\n  gateway: >\n    {{ streisand_shuf }} -n 6 /usr/share/dict/english.txt |\n    paste -s -d '.' -\n  identifier: >\n    {{ streisand_shuf }} -n 2 /usr/share/dict/english.txt |\n    paste -s -d '-' -\n  identifier_max_len_15: >\n    egrep '^.{1,7}$' /usr/share/dict/english.txt |\n    {{ streisand_shuf }} -n 2 |\n    paste -s -d '-' -\n  # Tor only likes [A-Za-z0-9] for nicknames.\n  #\n  # The BIP words are maximum 8 characters, so we get two safely.\n  #\n  # Tor nicknames should be 19 characters or fewer; cut ours off at 18.\n  #\n  # Caps script from https://www.unix.com/302904939-post2.html\n  tor_nickname: >\n    {{ streisand_shuf }} -n 2 /usr/share/dict/english.txt |\n    awk '{OFS=\"\"; for(j=1;j<=NF;j++){ $j=toupper(substr($j,1,1)) substr($j,2) }}1' |\n    tr -d '\\n' |\n    cut -b 1-18\n  long_identifier: >\n    {{ streisand_shuf }} -n 3 /usr/share/dict/english.txt |\n    paste -s -d '-' -\n  weak_password: >\n    {{ streisand_shuf }} -n 3 /usr/share/dict/english.txt |\n    paste -s -d '.' -\n  psk: >\n    {{ streisand_shuf }} -n 5 /usr/share/dict/english.txt |\n    paste -s -d '.' -\n\n# In online documentation, we recommand a URL for people to check\n# their effective IP address.\n\nstreisand_my_ip_url: https://duckduckgo.com/?q=ip+address\n\n# We used to use Google; it has marginally better usability, but there\n# are reasons not to use it.  If you're reading this, you know enough\n# to make your own decision.\n#\n# streisand_my_ip_url: https://encrypted.google.com/search?hl=en&q=my%20ip%20address\n\n# Ciphersuites recommended from Mozilla's Modern compatibility profile\n# https://wiki.mozilla.org/Security/Server_Side_TLS\nstreisand_tls_ciphers: \"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256\"\n\napt_repository_retries: 10\napt_repository_delay: 20\n"
  },
  {
    "path": "playbooks/roles/diagnostics/tasks/main.yml",
    "content": "---\n- name: \"Determine the git revision of the current Streisand clone\"\n  command: git rev-parse HEAD\n  register: streisand_diagnostics_git_rev\n  changed_when: False\n\n# Credit to https://stackoverflow.com/a/3879077 for this approach\n- name: \"Determine if there are untracked changes in the Streisand clone\"\n  shell: git diff-index --quiet HEAD -- && echo \"no\" || echo \"yes\";\n  register: streisand_diagnostics_git_untracked\n  changed_when: False\n\n- name: \"Produce the diagnostics markdown file to share if there is an error\"\n  template:\n    src: streisand-diagnostics.md.j2\n    dest: ../streisand-diagnostics.md\n"
  },
  {
    "path": "playbooks/roles/diagnostics/templates/streisand-diagnostics.md.j2",
    "content": "<!--\n\nPlease share the contents of this file when you open a new Streisand issue\nhttps://github.com/StreisandEffect/streisand-discussions/issues/ \n\nIt will help the developers reproduce your problem and provide a fix.\n-->\n\n### Ansible Information\n\n{% if 'localhost' in hostvars %}\n{% if 'ansible_version' in hostvars['localhost'] %}\n* Ansible version: {{ hostvars['localhost']['ansible_version']['full'] }}\n{% else %}\n* Ansible version: Unknown\n{% endif %}\n{% if 'ansible_system' in hostvars['localhost'] %}\n* Ansible system: {{ hostvars['localhost']['ansible_system'] }}\n{% else %}\n* Ansible system: Unknown\n{% endif %}\n{% if 'ansible_distribution' in hostvars['localhost'] %}\n* Host OS: {{ hostvars['localhost']['ansible_distribution'] }}\n{% else %}\n* Host OS: Unknown\n{% endif %}\n{% if 'ansible_distribution_version' in hostvars['localhost'] %}\n* Host OS version:  {{ hostvars['localhost']['ansible_distribution_version'] }}\n{% else %}\n* Host OS version: Unknown\n{% endif %}\n{% if 'ansible_python_interpreter' in hostvars['localhost'] %}\n* Python interpreter: {{ hostvars['localhost']['ansible_python_interpreter'] }}\n{% else %}\n* Python interpreter: Unknown\n{% endif %}\n{% if 'ansible_python_version' in hostvars['localhost'] %}\n* Python version: {{ hostvars['localhost']['ansible_python_version'] }}\n{% else %}\n* Python version: Unknown\n{% endif %}\n{% else %}\n* No 'localhost' in hostvars. Ansible information unknown.\n{% endif %}\n\n### Streisand Information\n\n* Streisand Git revision: {{ streisand_diagnostics_git_rev.stdout }}\n* Streisand Git clone has untracked changes: {{ streisand_diagnostics_git_untracked.stdout }}\n* Genesis role: {{ streisand_genesis_role | default(\"None\") }}\n* Custom SSH key: {{ streisand_ssh_private_key != \"~/.ssh/id_rsa\" }}\n\n### Enabled Roles\n\n* Shadowsocks enabled:  {{ streisand_shadowsocks_enabled }}\n* Wireguard enabled: {{ streisand_wireguard_enabled }}\n* OpenVPN enabled: {{ streisand_openvpn_enabled }}\n* stunnel enabled: {{ streisand_stunnel_enabled }}\n* Tor enabled: {{ streisand_tor_enabled }}\n* Openconnect enabled: {{ streisand_openconnect_enabled }}\n* TinyProxy enabled: {{ streisand_tinyproxy_enabled }}\n* SSH forward user enabled: {{ streisand_ssh_forward_enabled }}\n* Configured number of VPN clients: {{ vpn_clients }}\n"
  },
  {
    "path": "playbooks/roles/dnsmasq/handlers/main.yml",
    "content": "---\n- name: Restart dnsmasq\n  systemd:\n    name: dnsmasq.service\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/dnsmasq/tasks/main.yml",
    "content": "---\n- name: Ensure that BIND is not installed in order to avoid conflicts with dnsmasq\n  apt:\n    package: bind9\n    state: absent\n\n- name: Install dnsmasq\n  apt:\n    package: dnsmasq\n\n- name: Generate the dnsmasq configuration file\n  template:\n    src: dnsmasq.conf.j2\n    dest: /etc/dnsmasq.conf\n  notify: Restart dnsmasq\n\n- name: Create the dnsmasq systemd drop-in configuration directory\n  file:\n    path: \"{{ dnsmasq_systemd_service_path }}\"\n    state: directory\n\n- name: Generate the dnsmasq systemd drop-in service file\n  template:\n    src: dnsmasq.service.j2\n    dest: \"{{ dnsmasq_systemd_service_path }}/10-restart-failure.conf\"\n    mode: 0644\n\n- name: Enable the dnsmasq service\n  systemd:\n    daemon_reload: yes\n    name: dnsmasq.service\n    enabled: yes\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/dnsmasq/templates/dnsmasq.conf.j2",
    "content": "# Explicitly listen on localhost. This is required since config fragments in\n# `/etc/dnsmasq.d` may add additional `listen-address` values and the man page\n# says:\n#   Note that if no --interface option is given, but --listen-address is,\n#   dnsmasq will not automatically listen on the loopback interface. To achieve\n#   this, its IP address, 127.0.0.1, must be explicitly given as\n#   a --listen-address option.\nlisten-address=127.0.0.1\n\n# Never forward plain names (without a dot or domain part)\ndomain-needed\n\n# Never forward addresses in the non-routed address spaces.\nbogus-priv\n\n# If you don't want dnsmasq to read /etc/resolv.conf or any other\n# file, getting its servers from this file instead (see below), then\n# uncomment this.\nno-resolv\n\n{% for item in upstream_dns_servers %}\nserver={{ item }}\n{% endfor %}\n"
  },
  {
    "path": "playbooks/roles/dnsmasq/templates/dnsmasq.service.j2",
    "content": "[Service]\nPrivateTmp=true\nRestartSec=5s\nRestart=on-failure\n"
  },
  {
    "path": "playbooks/roles/dnsmasq/vars/main.yml",
    "content": "---\ndnsmasq_systemd_service_path: \"/etc/systemd/system/dnsmasq.service.d\"\n"
  },
  {
    "path": "playbooks/roles/download-and-verify/defaults/main.yml",
    "content": "---\nsignature_extension: \"asc\"\n"
  },
  {
    "path": "playbooks/roles/download-and-verify/tasks/main.yml",
    "content": "---\n\n# Import the GPG playbook vars\n- include_vars: \"../../gpg/vars/main.yml\"\n\n- name: \"Download the {{ project_name }} files\"\n  get_url:\n    url: \"{{ project_download_baseurl }}/{{ item.file }}\"\n    dest: \"{{ project_download_location }}/{{ item.file }}\"\n    owner: www-data\n    group: www-data\n    mode: 0644\n  with_items: \"{{ project_download_files }}\"\n\n- name: \"Download the {{ project_name }} signatures\"\n  get_url:\n    url: \"{{ project_download_baseurl }}/{{ item.sig }}\"\n    dest: \"{{ project_download_location }}/{{ item.sig }}\"\n    owner: www-data\n    group: www-data\n    mode: 0644\n  with_items: \"{{ project_download_files }}\"\n\n- name: \"Verify the {{ project_name }} download signatures with the Streisand GPG keyring\"\n  command: \"gpgv2 --keyring {{ streisand_gpg_keyring }} {{ project_download_location }}/{{ item.sig }} {{ project_download_location }}/{{ item.file }}\"\n  environment:\n    # We need to explicitly override the configured LANG, LC_MESSAGES and LC_ALL\n    # env vars to ensure that we can match on English output even on systems\n    # that have a non-english locale configured. It's _probably_ enough to\n    # override just LANG but it sounds like there are some cases where LC_ALL\n    # takes precedence and setting env vars is cheap!\n    LANG: \"en_US.UTF-8\"\n    LC_MESSAGES: \"en_US.UTF-8\"\n    LC_ALL: \"en_US.UTF-8\"\n  register: gpg_verification_results\n  with_items: \"{{ project_download_files }}\"\n\n- name: \"Verify the {{ project_name }} download signature checks all passed\"\n  assert:\n    that:\n      - \"not item.failed\"\n      - \"item.rc == 0\"\n    msg: \"Verifying {{ item.item.file }} GPG signature failed!!\"\n  with_items: \"{{ gpg_verification_results.results }}\"\n  loop_control:\n    label: \"{{ item.item.file }}\"\n  # NOTE(@cpu): Unfortunately because of an open Ansible issue[0] related to the\n  # verbosity of `assert` tasks we need a `no_log: true` here to avoid creating\n  # a TON of output in the \"pass\" case. This `no_log` will complicate debugging\n  # and should be removed if the assertions are failing.\n  #\n  # [0]: https://github.com/ansible/ansible/issues/27124#issuecomment-376523736\n  no_log: true\n\n- name: \"Verify the {{ project_name }} download signatures were from the correct keys\"\n  assert:\n    that:\n      # By default gpgv outputs to stderr. For a good signature the first line\n      # always ends being like:\n      # \"gpgv: Signature made Fri 16 Mar 2018 11:16:40 PM UTC using RSA key ID\n      #   C3C07136\"\n      # Since we've already verified the gpgv2 return code we can just check for\n      # the presence of the key ID we expect in the first line of stderr output\n      # and be confident we saw a valid signature from the expected key ID and\n      # not another unrelated key in the Streisand keyring.\n      - \"'key ID {{ project_signer_keyid }}' in '{{ item.stderr_lines[0] }}'\"\n    msg: \"The GPG signature on {{ item.item.file }} was not from {{ project_signer_keyid }}\"\n  with_items: \"{{ gpg_verification_results.results }}\"\n  loop_control:\n    label: \"{{ item.item.file }}\"\n  # See the above `assert`'s discussion on the purpose of `no_log`.\n  no_log: true\n"
  },
  {
    "path": "playbooks/roles/ec2-security-group/tasks/main.yml",
    "content": "---\n- name: Create the EC2 security group\n  ec2_group:\n    name: \"{{ aws_security_group }}\"\n    description: Security group for Streisand\n    region: \"{{ aws_region }}\"\n    vpc_id: \"{{ aws_vpc_id | default(omit) }}\"\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n\n- name: Pause for fifteen seconds to ensure the EC2 security group has been created\n  pause:\n    seconds: 15\n\n- name: Open necessary ports across supported services in the EC2 security group\n  ec2_group:\n    name: \"{{ aws_security_group }}\"\n    description: Security group for Streisand\n    region: \"{{ aws_region }}\"\n    vpc_id: \"{{ aws_vpc_id | default(omit) }}\"\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    rules:\n      # Nginx\n      # ---\n      - proto: tcp\n        from_port: \"{{ nginx_port }}\"\n        to_port: \"{{ nginx_port }}\"\n        cidr_ip: 0.0.0.0/0\n      # SSH\n      # ---\n      - proto: tcp\n        from_port: \"{{ ssh_port }}\"\n        to_port: \"{{ ssh_port }}\"\n        cidr_ip: 0.0.0.0/0\n      # HTTP (Let's Encrypt)\n      # ---\n      - proto: tcp\n        from_port: \"{{ le_port }}\"\n        to_port: \"{{ le_port }}\"\n        cidr_ip: 0.0.0.0/0\n    rules_egress:\n      - proto: all\n        from_port: 1\n        to_port: 65535\n        cidr_ip: 0.0.0.0/0\n\n# OpenConnect\n# ---\n- name: Open the OpenConnect ports in the EC2 security group\n  ec2_group:\n    name: \"{{ aws_security_group }}\"\n    description: Security group for Streisand\n    region: \"{{ aws_region }}\"\n    vpc_id: \"{{ aws_vpc_id | default(omit) }}\"\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    purge_rules: no\n    purge_rules_egress: no\n    rules:\n      # OpenConnect TCP\n      # ---\n      - proto: tcp\n        from_port: \"{{ ocserv_port }}\"\n        to_port: \"{{ ocserv_port }}\"\n        cidr_ip: 0.0.0.0/0\n      # OpenConnect UDP\n      # ---\n      - proto: udp\n        from_port: \"{{ ocserv_port }}\"\n        to_port: \"{{ ocserv_port }}\"\n        cidr_ip: 0.0.0.0/0\n  when: streisand_openconnect_enabled\n\n# OpenVPN\n# ---\n- name: Open the OpenVPN ports in the EC2 security group\n  ec2_group:\n    name: \"{{ aws_security_group }}\"\n    description: Security group for Streisand\n    region: \"{{ aws_region }}\"\n    vpc_id: \"{{ aws_vpc_id | default(omit) }}\"\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    purge_rules: no\n    purge_rules_egress: no\n    rules:\n      # OpenVPN TCP\n      # ---\n      - proto: tcp\n        from_port: \"{{ openvpn_port }}\"\n        to_port: \"{{ openvpn_port }}\"\n        cidr_ip: 0.0.0.0/0\n      # OpenVPN UDP\n      # ---\n      - proto: udp\n        from_port: \"{{ openvpn_port_udp }}\"\n        to_port: \"{{ openvpn_port_udp }}\"\n        cidr_ip: 0.0.0.0/0\n  when: streisand_openvpn_enabled\n\n# stunnel\n# ---\n- name: Open the stunnel port in the EC2 security group\n  ec2_group:\n    name: \"{{ aws_security_group }}\"\n    description: Security group for Streisand\n    region: \"{{ aws_region }}\"\n    vpc_id: \"{{ aws_vpc_id | default(omit) }}\"\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    purge_rules: no\n    purge_rules_egress: no\n    rules:\n      # Stunnel\n      # ---\n      - proto: tcp\n        from_port: \"{{ stunnel_remote_port }}\"\n        to_port: \"{{ stunnel_remote_port }}\"\n        cidr_ip: 0.0.0.0/0\n  when: streisand_openvpn_enabled and streisand_stunnel_enabled\n\n# Shadowsocks\n# ---\n- name: Open the Shadowsocks ports in the EC2 security group\n  ec2_group:\n    name: \"{{ aws_security_group }}\"\n    description: Security group for Streisand\n    region: \"{{ aws_region }}\"\n    vpc_id: \"{{ aws_vpc_id | default(omit) }}\"\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    purge_rules: no\n    purge_rules_egress: no\n    rules:\n      # Shadowsocks TCP\n      # ---\n      - proto: tcp\n        from_port: \"{{ shadowsocks_server_port }}\"\n        to_port: \"{{ shadowsocks_server_port }}\"\n        cidr_ip: 0.0.0.0/0\n      # Shadowsocks UDP\n      # ---\n      - proto: udp\n        from_port: \"{{ shadowsocks_server_port }}\"\n        to_port: \"{{ shadowsocks_server_port }}\"\n        cidr_ip: 0.0.0.0/0\n  when: streisand_shadowsocks_enabled\n\n# Tor\n# ---\n- name: Open the Tor ports in the EC2 security group\n  ec2_group:\n    name: \"{{ aws_security_group }}\"\n    description: Security group for Streisand\n    region: \"{{ aws_region }}\"\n    vpc_id: \"{{ aws_vpc_id | default(omit) }}\"\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    purge_rules: no\n    purge_rules_egress: no\n    rules:\n      # Tor\n      # ---\n      - proto: tcp\n        from_port: \"{{ tor_orport }}\"\n        to_port: \"{{ tor_orport }}\"\n        cidr_ip: 0.0.0.0/0\n      # Tor obfs4\n      # ---\n      - proto: tcp\n        from_port: \"{{ tor_obfs4_port }}\"\n        to_port: \"{{ tor_obfs4_port }}\"\n        cidr_ip: 0.0.0.0/0\n  when: streisand_tor_enabled\n\n# WireGuard\n# ---\n- name: Open the WireGuard ports in the EC2 security group\n  ec2_group:\n    name: \"{{ aws_security_group }}\"\n    description: Security group for Streisand\n    region: \"{{ aws_region }}\"\n    vpc_id: \"{{ aws_vpc_id | default(omit) }}\"\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    purge_rules: no\n    purge_rules_egress: no\n    rules:\n      - proto: udp\n        from_port: \"{{ wireguard_port }}\"\n        to_port: \"{{ wireguard_port }}\"\n        cidr_ip: 0.0.0.0/0\n  when: streisand_wireguard_enabled\n"
  },
  {
    "path": "playbooks/roles/ec2-security-group/vars/main.yml",
    "content": "---\naws_security_group: \"streisand-{{ aws_instance_name }}\"\n"
  },
  {
    "path": "playbooks/roles/gce-network/tasks/main.yml",
    "content": "---\n- name: Create network\n  gce_net:\n    name: \"{{ gce_network }}\"\n    state: \"present\"\n    mode: auto\n    ipv4_range: \"{{ gce_ipv4_range }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n    service_account_email: \"{{ gce_service_account_email }}\"\n\n- name: Open the SSH port in the GCE firewall\n  gce_net:\n    name: \"{{ gce_network }}\"\n    fwname: \"streisand-{{ gce_server_name }}-ssh\"\n    allowed: \"tcp:{{ ssh_port }}\"\n    state: \"present\"\n    mode: auto\n    src_range: 0.0.0.0/0\n    service_account_email: \"{{ gce_service_account_email }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n\n- name: Open the Nginx port in the GCE firewall\n  gce_net:\n    name: \"{{ gce_network }}\"\n    fwname: \"streisand-{{ gce_server_name }}-nginx\"\n    allowed: \"tcp:{{ nginx_port }}\"\n    state: \"present\"\n    mode: auto\n    src_range: 0.0.0.0/0\n    service_account_email: \"{{ gce_service_account_email }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n\n- name: Open HTTP port for Let's Encrypt in the GCE firewall\n  gce_net:\n    name: \"{{ gce_network }}\"\n    fwname: \"streisand-{{ gce_server_name }}-letsencrypt\"\n    allowed: \"tcp:{{ le_port }}\"\n    state: \"present\"\n    mode: auto\n    src_range: 0.0.0.0/0\n    service_account_email: \"{{ gce_service_account_email }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n\n- name: Open necessary Tor ports in the GCE firewall\n  gce_net:\n    name: \"{{ gce_network }}\"\n    fwname: \"streisand-{{ gce_server_name }}-tor\"\n    allowed: \"tcp:{{ tor_orport }},{{ tor_obfs4_port }}\"\n    state: \"present\"\n    mode: auto\n    src_range: 0.0.0.0/0\n    service_account_email: \"{{ gce_service_account_email }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n  when: streisand_tor_enabled\n\n- name: Open the OpenConnect (ocserv) port in the GCE firewall\n  gce_net:\n    name: \"{{ gce_network }}\"\n    fwname: \"streisand-{{ gce_server_name }}-openconnect\"\n    allowed: \"tcp:{{ ocserv_port }};udp:{{ ocserv_port }}\"\n    state: \"present\"\n    mode: auto\n    src_range: 0.0.0.0/0\n    service_account_email: \"{{ gce_service_account_email }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n  when: streisand_openconnect_enabled\n\n- name: Open the OpenVPN ports in the GCE firewall\n  gce_net:\n    name: \"{{ gce_network }}\"\n    fwname: \"streisand-{{ gce_server_name }}-openvpn\"\n    allowed: \"tcp:{{ openvpn_port }};udp:{{ openvpn_port_udp }}\"\n    state: \"present\"\n    mode: auto\n    src_range: 0.0.0.0/0\n    service_account_email: \"{{ gce_service_account_email }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n  when: streisand_openvpn_enabled\n\n- name: Open the OpenVPN stunnel port in the GCE firewall\n  gce_net:\n    name: \"{{ gce_network }}\"\n    fwname: \"streisand-{{ gce_server_name }}-openvpn-stunnel\"\n    allowed: \"tcp:{{ stunnel_remote_port }}\"\n    state: \"present\"\n    mode: auto\n    src_range: 0.0.0.0/0\n    service_account_email: \"{{ gce_service_account_email }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n  when: streisand_openvpn_enabled and streisand_stunnel_enabled\n\n- name: Open the Shadowsocks ports in the GCE firewall\n  gce_net:\n    name: \"{{ gce_network }}\"\n    fwname: \"streisand-{{ gce_server_name }}-shadowsocks\"\n    allowed: \"tcp:{{ shadowsocks_server_port }};udp:{{ shadowsocks_server_port }}\"\n    state: \"present\"\n    mode: auto\n    src_range: 0.0.0.0/0\n    service_account_email: \"{{ gce_service_account_email }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n  when: streisand_shadowsocks_enabled\n\n- name: Open the WireGuard port in the GCE firewall\n  gce_net:\n    name: \"{{ gce_network }}\"\n    fwname: \"streisand-{{ gce_server_name }}-wireguard\"\n    allowed: \"udp:{{ wireguard_port }}\"\n    state: \"present\"\n    mode: auto\n    src_range: 0.0.0.0/0\n    service_account_email: \"{{ gce_service_account_email }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n  when: streisand_wireguard_enabled\n"
  },
  {
    "path": "playbooks/roles/gce-network/vars/main.yml",
    "content": "---\ngce_network: \"{{ gce_server_name }}-network\"\ngce_ipv4_range: \"10.240.16.0/24\"\n"
  },
  {
    "path": "playbooks/roles/genesis-amazon/defaults/main.yml",
    "content": "---\naws_instance_type: \"t2.micro\"\n# Search AMIs owned by this owner. This is the Amazon owner ID.\naws_ami_owner: \"099720109477\"\n# Find AMIs matching this name\naws_ami_name: \"ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-*\"\n"
  },
  {
    "path": "playbooks/roles/genesis-amazon/files/aws-metadata-instance.service",
    "content": "[Unit]\nDescription=Drop packets to the EC2 metadata instance\nAfter=network.target\n\n[Service]\nType=oneshot\nRemainAfterExit=true\nExecStart=/sbin/route add -host 169.254.169.254 reject\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "playbooks/roles/genesis-amazon/meta/main.yml",
    "content": "---\ndependencies:\n  - ec2-security-group\n"
  },
  {
    "path": "playbooks/roles/genesis-amazon/tasks/main.yml",
    "content": "---\n- set_fact:\n    streisand_genesis_role: \"genesis-amazon\"\n\n- name: \"Get the {{ streisand_ssh_private_key }}.pub contents\"\n  command: \"cat {{ streisand_ssh_private_key }}.pub\"\n  register: ssh_key\n  changed_when: False\n\n- name: Remove the 'streisand' SSH key from Amazon if it already exists. This is to prevent problems if two people with two different keys are sharing the same AWS account.\n  ec2_key:\n    name: streisand-ssh\n    state: absent\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    region: \"{{ aws_region }}\"\n    wait: yes\n\n- name: Add the SSH key to Amazon under the name of 'streisand-ssh'\n  ec2_key:\n    name: streisand-ssh\n    key_material: \"{{ ssh_key.stdout }}\"\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    region: \"{{ aws_region }}\"\n    wait: yes\n\n- name: Determine which AMI to use\n  ec2_ami_facts:\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    owners: \"{{ aws_ami_owner }}\"\n    region: \"{{ aws_region }}\"\n    filters:\n      name: \"{{ aws_ami_name }}\"\n  register: ami\n\n- name: Create the EC2 instance\n  ec2:\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    instance_type: \"{{ aws_instance_type }}\"\n    image: \"{{ ami.images|sort(reverse=True,attribute='name')|map(attribute='image_id')|first }}\"\n    region: \"{{ aws_region }}\"\n    vpc_subnet_id: \"{{ aws_vpc_subnet_id | default(omit) }}\"\n    assign_public_ip: \"{{ (aws_vpc_subnet_id is defined and aws_vpc_subnet_id != '') or omit }}\"\n    key_name: streisand-ssh\n    group: \"{{ aws_security_group }}\"\n    instance_tags:\n      Name: \"{{ aws_instance_name }}\"\n    wait: yes\n  register: streisand_server\n\n- name: Create CloudWatch alarm to auto-recover instance\n  ec2_metric_alarm:\n    name: \"autorecover-{{ aws_instance_name }}\"\n    description: \"This alarm will auto-recover the EC2 instance on host failure\"\n    state: present\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    region: \"{{ aws_region }}\"\n    namespace: \"AWS/EC2\"\n    metric: StatusCheckFailed_System\n    statistic: Minimum\n    comparison: \">\"\n    threshold: 0.0\n    period: 60\n    evaluation_periods: 2\n    dimensions:\n      InstanceId: \"{{ streisand_server.instances[0].id }}\"\n    alarm_actions:\n      - \"arn:aws:automate:{{ aws_region }}:ec2:recover\"\n  when: aws_instance_type.startswith((\"t2\", \"c3\", \"c4\", \"m3\", \"m4\", \"r3\", \"x1\"))\n\n- name: Wait until the server has finished booting and OpenSSH is accepting connections\n  wait_for:\n    host: \"{{ streisand_server.instances[0].public_ip }}\"\n    port: 22\n    search_regex: OpenSSH\n    timeout: 600\n\n- name: Allocate and associate Elastic IP\n  ec2_eip:\n    aws_access_key: \"{{ aws_access_key }}\"\n    aws_secret_key: \"{{ aws_secret_key }}\"\n    region: \"{{ aws_region }}\"\n    device_id: \"{{ streisand_server.instances[0].id }}\"\n    in_vpc: \"{{ aws_vpc_id is defined and aws_vpc_id != '' }}\"\n  register: instance_eip\n\n- name: Create the in-memory inventory group\n  add_host:\n    name: \"{{ instance_eip.public_ip }}\"\n    groups: streisand-host\n    ansible_user: ubuntu\n    ansible_become: yes\n\n- name: Set the streisand_ipv4_address variable\n  set_fact:\n    streisand_ipv4_address: \"{{ instance_eip.public_ip }}\"\n\n- name: Set the streisand_server_name variable\n  set_fact:\n    streisand_server_name: \"{{ aws_instance_name | regex_replace('\\\\s', '_') }}\"\n"
  },
  {
    "path": "playbooks/roles/genesis-azure/defaults/main.yml",
    "content": "---\nazure_instance_type: \"Standard_B1s\"\n\nazure_image_publisher: \"Canonical\"\nazure_image_offer:     \"UbuntuServer\"\nazure_image_sku:       \"16.04-LTS\"\nazure_image_version:   \"latest\"\n"
  },
  {
    "path": "playbooks/roles/genesis-azure/meta/main.yml",
    "content": "---\ndependencies:\n  - azure-security-group\n"
  },
  {
    "path": "playbooks/roles/genesis-azure/tasks/main.yml",
    "content": "---\n- set_fact:\n    streisand_genesis_role: \"genesis-azure\"\n\n- name: \"Get the {{ streisand_ssh_private_key }}.pub contents\"\n  command: \"cat {{ streisand_ssh_private_key }}.pub\"\n  register: ssh_key\n  changed_when: False\n\n- name: Create the Azure instance\n  local_action:\n    module: azure_rm_virtualmachine\n    resource_group: \"{{ azure_resource_group_name }}\"\n    network_interfaces: \"{{ azure_resource_group_name }}\"\n    name: \"{{ azure_instance_name }}\"\n    vm_size: \"{{ azure_instance_type }}\"\n    location: \"{{ azure_region }}\"\n    image:\n      offer: \"{{ azure_image_offer }}\"\n      publisher: \"{{ azure_image_publisher }}\"\n      sku: \"{{ azure_image_sku }}\"\n      version: \"{{ azure_image_version }}\"\n    admin_username: ubuntu\n    ssh_password_enabled: false\n    ssh_public_keys:\n      - path: /home/ubuntu/.ssh/authorized_keys\n        key_data: \"{{ ssh_key.stdout }}\"\n  register: streisand_server\n\n- name: Set the streisand_ipv4_address variable\n  set_fact:\n    streisand_ipv4_address: \"{{ streisand_server.ansible_facts.azure_vm.properties.networkProfile.networkInterfaces[0].properties.ipConfigurations[0].properties.publicIPAddress.properties.ipAddress }}\"\n\n- name: Wait until the server has finished booting and OpenSSH is accepting connections\n  wait_for:\n    host: \"{{ streisand_ipv4_address }}\"\n    port: 22\n    search_regex: OpenSSH\n    timeout: 600\n\n- name: Create the in-memory inventory group\n  add_host:\n    name: \"{{ streisand_ipv4_address }}\"\n    groups: streisand-host\n    ansible_user: ubuntu\n    ansible_become: yes\n\n- name: Set the streisand_server_name variable\n  set_fact:\n    streisand_server_name: \"{{ azure_instance_name }}\"\n"
  },
  {
    "path": "playbooks/roles/genesis-digitalocean/defaults/main.yml",
    "content": "---\ndo_ubuntu_x64_image_id: \"ubuntu-16-04-x64\"\ndo_small_droplet_size_id: \"s-1vcpu-1gb\"\n"
  },
  {
    "path": "playbooks/roles/genesis-digitalocean/tasks/main.yml",
    "content": "---\n- set_fact:\n    streisand_genesis_role: \"genesis-digitalocean\"\n\n- name: \"Get the {{ streisand_ssh_private_key }}.pub contents\"\n  command: \"cat {{ streisand_ssh_private_key }}.pub\"\n  register: ssh_key\n  changed_when: False\n\n- name: Set the DigitalOcean Access Token fact to the value that was entered, or attempt to retrieve it from the environment if the entry is blank\n  set_fact:\n    do_access_token: \"{{ do_access_token_entry | default( lookup('env', 'DO_API_KEY') ) }}\"\n\n- block:\n    - name: Add the SSH key to DigitalOcean if it doesn't already exist\n      digital_ocean_sshkey:\n        name: \"{{ do_ssh_name }}\"\n        ssh_pub_key: \"{{ ssh_key.stdout }}\"\n        oauth_token: \"{{ do_access_token }}\"\n        state: present\n      register: do_ssh_key\n  rescue:\n    - fail:\n        msg: \"* The API Access Token might be incorrect or missing the Write Scope. OR * The SSH key may already exist in the DigitalOcean Control Panel under a different name.\"\n\n- block:\n    - name: Create the new Droplet\n      digital_ocean_droplet:\n        name: \"{{ do_server_name }}\"\n        ssh_keys:\n          - \"{{ do_ssh_key.data.ssh_key.id }}\"\n        size: \"{{ do_small_droplet_size_id }}\"\n        region: \"{{ regions[do_region] }}\"\n        image: \"{{ do_ubuntu_x64_image_id }}\"\n        unique_name: yes\n        wait: yes\n        oauth_token: \"{{ do_access_token }}\"\n        state: present\n      register: streisand_server\n  rescue:\n    - fail:\n        msg: \"Unable to create the Droplet. Please ensure that the API Access Token you provided has the Write Scope enabled.\"\n\n- name: Wait until the server has finished booting and OpenSSH is accepting connections\n  wait_for:\n    host: \"{{ streisand_server.data.ip_address }}\"\n    port: 22\n    search_regex: OpenSSH\n    timeout: 600\n\n- name: Create the in-memory inventory group\n  add_host:\n    name: \"{{ streisand_server.data.ip_address }}\"\n    groups: streisand-host\n\n- name: Set the streisand_ipv4_address variable\n  set_fact:\n    streisand_ipv4_address: \"{{ streisand_server.data.ip_address }}\"\n\n- name: Set the streisand_server_name variable\n  set_fact:\n    streisand_server_name: \"{{ do_server_name | regex_replace('\\\\s', '_') }}\"\n"
  },
  {
    "path": "playbooks/roles/genesis-google/defaults/main.yml",
    "content": "---\ngce_machine_type: \"f1-micro\"\ngce_image: \"ubuntu-1604\"\n"
  },
  {
    "path": "playbooks/roles/genesis-google/meta/main.yml",
    "content": "---\ndependencies:\n  - gce-network\n"
  },
  {
    "path": "playbooks/roles/genesis-google/tasks/main.yml",
    "content": "---\n- set_fact:\n    streisand_genesis_role: \"genesis-google\"\n\n- name: \"Get the {{ streisand_ssh_private_key }}.pub contents\"\n  command: \"cat {{ streisand_ssh_private_key }}.pub\"\n  register: ssh_key\n  changed_when: False\n\n- name: Create the GCE instance\n  gce:\n    name: \"{{ gce_server_name }}\"\n    network: \"{{ gce_network }}\"\n    zone: \"{{ gce_zone }}\"\n    machine_type: \"{{ gce_machine_type }}\"\n    credentials_file: \"{{ gce_json_file_location }}\"\n    project_id: \"{{ gce_project_id }}\"\n    service_account_email: \"{{ gce_service_account_email }}\"\n    image: \"{{ gce_image }}\"\n    tags: \"{{ gce_server_name }}\"\n    metadata: '{\"ssh-keys\":\"ubuntu:{{ ssh_key.stdout }}\"}'\n  register: streisand_server\n\n- name: Wait until the server has finished booting and OpenSSH is accepting connections\n  wait_for:\n    host: \"{{ streisand_server.instance_data[0].public_ip }}\"\n    port: 22\n    search_regex: OpenSSH\n    timeout: 600\n\n- name: Create the in-memory inventory group\n  add_host:\n    name: \"{{ streisand_server.instance_data[0].public_ip }}\"\n    groups: streisand-host\n    ansible_user: ubuntu\n    ansible_become: yes\n\n- name: Set the streisand_ipv4_address variable\n  set_fact:\n    streisand_ipv4_address: \"{{ streisand_server.instance_data[0].public_ip }}\"\n\n- name: Set the streisand_server_name variable\n  set_fact:\n    streisand_server_name: \"{{ gce_server_name | regex_replace('\\\\s', '_') }}\"\n"
  },
  {
    "path": "playbooks/roles/genesis-linode/defaults/main.yml",
    "content": "---\n# Setting to most minimal linode plan size.\n# For a most recent list of types: curl https://api.linode.com/v4/linode/types\nlinode_plan_id: \"g6-nanode-1\"\nlinode_distribution_id: \"linode/ubuntu16.04lts\"\n\n### Preserving these varsfor when we can set these with the ansible linode apiv4 module:\n# linode_kernel_id: 210 # GRUB2 to utilize the distribution's kernel for compatibility\n\n# Threshold for receiving CPU usage alerts. Each CPU core adds 100% to total.\n# Since by default Streisand provisions a Linode 1024 with one core a value of\n# 90% seems ~reasonable\n# linode_alert_cpu_threshold: 90\n\n# Other values left as the defaults from the Linode module. See\n# https://github.com/StreisandEffect/streisand/issues/626 for more detail.\n# linode_alert_diskio_threshold: 10000\n# linode_alert_bwin_threshold: 10\n# linode_alert_bwout_threshold: 10\n# linode_alert_bwquota_threshold: 80\n"
  },
  {
    "path": "playbooks/roles/genesis-linode/tasks/main.yml",
    "content": "---\n- set_fact:\n    streisand_genesis_role: \"genesis-linode\"\n\n- name: \"Get the {{ streisand_ssh_private_key }}.pub contents\"\n  command: \"cat {{ streisand_ssh_private_key }}.pub\"\n  register: ssh_key\n  changed_when: False\n\n- name: \"Create the server\"\n  linode_v4:\n    access_token: \"{{ linode_api_token }}\"\n    label: \"{{ linode_server_name }}\"\n    type: \"{{ linode_plan_id }}\"\n    region: \"{{ regions[linode_datacenter] }}\"\n    image: \"{{ linode_distribution_id }}\"\n    authorized_keys: \"{{ ssh_key.stdout }}\"\n    state: present\n  register: streisand_server\n\n- name: \"Wait until the server has finished booting and OpenSSH is accepting connections\"\n  wait_for:\n    host: \"{{ streisand_server.instance.ipv4[0] }}\"\n    port: 22\n    search_regex: OpenSSH\n    timeout: 600\n\n- name: \"Create the in-memory inventory group\"\n  add_host:\n    name: \"{{ streisand_server.instance.ipv4[0] }}\"\n    groups: streisand-host\n\n- name: \"Set the streisand_ipv4_address variable\"\n  set_fact:\n    streisand_ipv4_address: \"{{ streisand_server.instance.ipv4[0] }}\"\n\n- name: \"Set the streisand_server_name variable\"\n  set_fact:\n    streisand_server_name: \"{{ linode_server_name | regex_replace('\\\\s', '_') }}\"\n"
  },
  {
    "path": "playbooks/roles/genesis-rackspace/defaults/main.yml",
    "content": "---\nrackspace_flavor: 2\nrackspace_image: \"Ubuntu 16.04 LTS (Xenial Xerus) (PVHVM)\"\n"
  },
  {
    "path": "playbooks/roles/genesis-rackspace/tasks/main.yml",
    "content": "---\n- set_fact:\n    streisand_genesis_role: \"genesis-rackspace\"\n\n- name: \"Get the {{ streisand_ssh_private_key }}.pub contents\"\n  command: \"cat {{ streisand_ssh_private_key }}.pub\"\n  register: ssh_key\n  changed_when: False\n\n- name: Create the server\n  rax:\n    api_key: \"{{ rackspace_api_key }}\"\n    username: \"{{ rackspace_username }}\"\n    name: \"{{ rackspace_server_name }}\"\n    flavor: \"{{ rackspace_flavor }}\"\n    image: \"{{ rackspace_image }}\"\n    region: \"{{ regions[rackspace_region] }}\"\n    files:\n      /root/.ssh/authorized_keys: \"{{ streisand_ssh_private_key }}.pub\"\n    wait: yes\n  register: streisand_server\n\n- name: Wait until the server has finished booting and OpenSSH is accepting connections\n  wait_for:\n    host: \"{{ streisand_server.instances[0].rax_accessipv4 }}\"\n    port: 22\n    search_regex: OpenSSH\n    timeout: 600\n\n- name: Create the in-memory inventory group\n  add_host:\n    name: \"{{ streisand_server.instances[0].rax_accessipv4 }}\"\n    groups: streisand-host\n\n- name: Set the streisand_ipv4_address variable\n  set_fact:\n    streisand_ipv4_address: \"{{ streisand_server.instances[0].rax_accessipv4 }}\"\n\n- name: Set the streisand_server_name variable\n  set_fact:\n    streisand_server_name: \"{{ rackspace_server_name | regex_replace('\\\\s', '_') }}\"\n"
  },
  {
    "path": "playbooks/roles/gpg/files/2D8330C2.daniel@binaryparadox.net.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n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\n=Do3m\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/files/2F2B01E7.security@openvpn.net.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2\n\nmQINBFicXUkBEAC9j2L+kJxqetXfslRL/UOqZUNpfNGUjpP2yb+j9UYdZbS3dq67\ni0oYINqKRO4fZEg0VLpW611fTUL3qhKADmSlrktY8p26T79I/TYAUuwlijTFKUVw\n3RGpMsfuldnk007uhx7Go5Ss6y7fPzwWxhvwuRhNdh8I+vswrsBMp08dQ36sIjnv\n5QQ1MekBiIiOnMwQBgUUSG7rsbGtrIlW0mlScO3fOAI2CtT2J4s3uGnktKsGSuoe\ns3qmRVrKceLygEJE9nB3vV7JhCfQWR97HCGrORcq6lBzi4dC0l9Mp28npQ/mcEtg\nB2oKA4Gs8qyhhhVLC6lBF38z9gfoLVqA+d9dY1l33atTyNfvA6swiA9hjklAzL3P\nzUqabmRzKalhVwhNKnua3Zw21OphLUk6vzZPZ6VB/Xddmenu0MCLx8mubKr+H+cj\n2YRgn9Np2NR7J6reSWD/WbG12DKa84rTrCw3bpUDR3PvB3IztRfDGlBonDaL1i62\nbav3zvqEia7kQiR6qLd6KMk4dcpE5UAdLii8yGNBF93aU4UPJg4zhTl4hBANp8jf\ntCd4LfxB1aurGfqSlwfE3c1wYXOAplzG/CAbvHch0mA1ckKKb9MYvmInYj/cnPxT\nZBhjT5qBq91qiqNbStVquyBwuyEsa3FpeUopTZWxeO6Ik6hz89g3+Mu2awARAQAB\ntDZPcGVuVlBOIC0gU2VjdXJpdHkgTWFpbGluZyBMaXN0IDxzZWN1cml0eUBvcGVu\ndnBuLm5ldD6JAj8EEwECACkFAlicXUkCGwMFCRLMAwAHCwkIBwMCAQYVCAIJCgsE\nFgIDAQIeAQIXgAAKCRAS9fe0LysB56coD/4/z1WaO6S6MW9GJUHnQC0xym6ZW3Ax\nc+iRT2M1FnBBEYEZXdPtQg6dkuAozip/V7MsYt/0xo0bR0ViE8SA53R+E3KW5/zW\nlebAF9E/QZMobVU3T2fbMDHckRyrSXfjTWnUi4EKrXbC41axwiRJisbFMPAY9aNP\nSHhPDvYvKCNvuVYB1cPOZ0pJYzeuGSiv4FGaUYKdNQOZhinVGccev/+ll/g1yW/Y\n2qFnQPh/z0LJnTwk4PAxrtt6sc+AUXo0CFAnGVYfw42TFqNb23osO8IFHENSS5Uo\nXakMbw+EZYd2gCnUptRUMLLH2mUexVQaFaIdi9j+zqhOfgZ9MRa9OhmC7sq+Poz6\nSxmQz6W//TczylpXixRJsK8rdIYMp717ycShX8mOqSWX53Ehc2q8kSCor1xOhDXt\noBkKYHucX33/+NS6l9XjyW6RMJg1sV4XSvu6Dfw/qnUFj+z00N8lQUiM7KPU6EhN\n/h5PeyLKxppkpndlBuHZ9YvpiQNnfPRlfwPi1o59N/rhN6Xet5kbD5e8yPnNXZlc\ngwanJBkwFyrgIKq9zoGD08TfVha44sIsq8iy+3QwFp1BgjBNFthl1JYWVHpnM5ni\nFIx87RaRp5CQJZ4+PfZ4B/oisX4Pr9QkEhGxqIy/34zOGnv/k1TDIPwYVXSx0zsK\nQ4GdxmxB0QRTbYkCOwQTAQIAJQIbAwUJEswDAAIeAQIXgAUCWJzLrgQLCQgHBBUK\nCQgFFgIDAQAACgkQEvX3tC8rAecE3A/+LCiwUH30gbauYFlk6tWL8GfEKmGqjyYV\nIJAmmkdlHXg/oiP96Xjrg6aOHLm/QNIvNIM2Z8u+0i/UxpPcnXp1qxy6YEl2rgbi\nb0njCC2L23ziEVQniPBrZCWvp5wQdMy3BG+1cvYV+H84YlW3IZm/P6mqgKNU1U1j\nY4zpIVe6oF+WhM7ijZGQFOYzaFBK3kZw5TNguXiQEdisDZF25zHBcz7aR1WtYsd6\nZm/Tfeaoaa8SW23GdhueruDpIEsEAcMrwfsYnUPTuIQ/NsiQoQWVKHRMxONuJB53\no07/1T8C8GPBL3t5xVZZK2Go0XQryUWuW380IrT120B+patIpdySOTzBlDeX75nN\ndM2epY8mBmlR6Jx1RTAAY1ImYD1myv2+kYZYczfThpN04G2L2LXbnOJ99UmAxGIv\nabPYawYriEYI1r7+WeQXHoHS8SxZex7tSzuVkYYE3mxT0YaPD9FGjbcu/79GYF8O\nqouKUcjFTDOzL3yBZIbJSXlxgXD+AjIOjV54F9+xkmT0GAC55QbCPmvgMLhAbl8b\n+maKw0MORCTqhzpF5jOVPjhT36ZJXpCNCZ4MA0U1qWY5v/qKKpaP14CXV/rT8VR6\n7MgEBdIMUtRM0uMYQHYvHh2Am3BU/Oee4ns3s7OCVhhMeWQ85UEYKQ894fRwOANG\nNlSPHWw+LvKJAhwEEAEIAAYFAlijkAkACgkQV9udq2E7jaFf4w//d+Tx2ti5mWEj\n/7ZygilmqwR8w1yUZAZBeMXkSF4NEeGkInt2bLBDDHoEiRpM7pmPUq4uKEJmm145\ncLnfN2RScxefOAxGN2NhAKTHRbN7QIAy7oX7FVvEydOZzFYRYDLdC0fKiSg1BJG4\n+kaan18S2oWLfAQ9gEH8KD8zbF7a9okeM5GSUkIs6WdNjU3YM1bGiXIbPQWqHI1w\n/6GpraPbKRCDE/td6FjInpQy7eQl4GW0HPekLdWnrLyZ5KOwTAaDXkIVqse4bwi2\ne/4OWZLZGM3G5aCkMZ5aUehli4fAIRbjqhfh1lxtIZQsnImrHIIEp3cm/4DghoII\naqqmJ2Tngp/uLfVqy2uNFkM1dAhrW1U7TbLa+DmiYH9X5/0ctd75H1ZQoEjKwKGN\nqgw/Rq75rxSBvFSLU9fvuH7WG14WXdCwdFroXXDjhd1g+Pc4qvr9W8yJjBjfi/NI\n1s50iWhTXoBt7rKWwvYhy/LFAo9leEo+RzU6+ugUaOaPOU7F91HwLTut0Gri9rLe\ntujpNn59ZHk4zr+Mcw7UC8X57oW7dW6ZI19G0SWPPhyaU9epcfumlMSqI1r/66Ji\n4LJ11Td7Nv2JUTjo/SVGor2IUzABsNjb9s/ffLFvSePjRDJLe2I8l1Qs6bubjGPQ\nHZM2VxQw8mA5MjTFDDd+bk4AEU0bhpGIXQQQEQIAHRYhBJ1Sw0fqLFJAInfhLR/H\nT6mBfHpSBQJZ2PE1AAoJEB/HT6mBfHpSozAAn1xyDljEjokbnI7wNbGcCDlUlNW7\nAKCuxM+zG26UM2r0DxVefWTFhBIV+4heBBAWCAAGBQJaX6COAAoJEBu4nAYCNnRJ\n+tABAP7T3P1mw5hv3fl/F1K8RT9+ohTf/yrSzKahNT75AFKbAQDUv4MCnH6qrBQC\nD/kvOUcOcvmvjFN6sev95kR/dEPJDokBHAQQAQgABgUCWXeoHgAKCRA6fjL5C7vd\ns051CAClxiDpvmUjgDnHxm3+cesx8XhxykokxI6Pc7MWSuSvFHBy16PTrtv9ePOf\nqG3jpfO1ZSYBT89OO2bTcLPioHTNj+aYivCYRXf4An2ciPdurTDlQmhv5z8bC2Nz\ntCMSgVRN8j+ZWPZh/jv3LSIRdxjk563NL4vdq8U6Meezz5UVfaSm4G8N4oNNDZwK\n7UVoIYHlyjuPdW6RtBqTrNggs99QwFfRDWYYRoIZvC1qbOGepzPZhluDMmknkvVc\ntV5aheqtPPSGhS4C98i/PV8r6j2+usNKHABpabC4pU3JKBWNK0mR/VidF9zNtqtC\nyIewtxv7E5Avqq+MzuPxgcxl4cEXiQEcBBABCAAGBQJZpYy/AAoJEC20u+/5mSLk\noEcH/2PFU/80HepTS6o8RJRmEyBQp+1aGv3gt5MYkUEYTeTLW73qEqt0n4XXeCxn\nOrmFdhjf6PCK4yp+gk3KlmZ7b+ELxqMTF/7IpnlVUztio7NCsJStnJMaLiFPpa5A\nmZYn8xmsgvsrXiVerkvdF7txY7T8Cus6BXTn1Sp1av/c86zeU+Ibe9ZkGY/+Wns6\nTxOAplwHcG4uLXj2oxz9ry8r7Tgg/qB8Vo77c/+wS4hkiP4SyAwRVPHhzipN5eBl\nFwyW01lqESBYIhqD2z8vjPRTBwe0xyKa/KpeibD8KLf6fPMWGjQASLe6yRZTDAFO\nBAnatECtRp5SyWzbUfK7oO87wQ2JARwEEAEIAAYFAlqc7RwACgkQ17bfzgpEGOVe\nEwf9GacB2u9Cl/weGXgOL9abfQpyQsVf+xnZHnpcqfqXc4ES7ucJyObJ4Le+UOOk\nDgmWJ71w/v+dl10nQCG+DRoMQlMe0PQdxEYG3lAvWnfrxqVXz41nyqQmSOTfn/GM\nAe8EbCIuy2rqXYTLOStqxAAnfwHzo8l0tV+uwUvP8Q/2fEwoWJsNoiVQkVoKmeeL\nH/QAdh1JmO1StNMO8N3I76qiUffkTbdAnBZmeruO9DGpgyoAfRins7SJGRHth6ik\nGuuYc6dHa3PA10IGc+AdYoxPy4J443DiHhEmsBF95wJowJCDAspmhhDOpnPShvfG\ncU6O8x2Vez+EbnsSrTTQXQ/TdYkBHAQSAQgABgUCWZqAkQAKCRAjRRsQeqA5Qc0t\nB/9gG3MLp3yTuqkJ3JgXZEgdJn5VY9U8fVAmG8lqbr8e9fM2ZDIbWg99w1T/KW/k\nBOxhlSt/YNQk+SU2x61urRQFwKleJsHlaVRUc6eoAhiHzOwf1I6RT6pn31dhqhNp\nx2tvJtOLmKZkB53tkA3dOVbZaU3KaGVYzW2iMlT1aJOwTy7RMFO+pLxmIWqczNeA\ncu1zersa4nkIQI4F3snYI5WZwyuBeIWRK1YPvJqUm1IxKvigfmozos9+y72b6yjF\ncRllDKIt0eb9JnZ30TPm3nHBzXlLgNVvuQ0oN3s8waVgXnNSIUsbvOkWIsOz5r9C\nzt9c6cPFhPY6GCIUrvZ8T//BiQEzBBABCAAdFiEEVQXkUwUfTo/Nvb03sUAmce0N\n+90FAlnW1ssACgkQsUAmce0N+93lzgf+Nh+LSw3YHfwOBb/M/cvWB+2z42tDxLgf\nDri7rBKCprFW10pX5z6BX7aWvvG/o24McC6d15FTEpLw06tnIDWe52fUTI1HZkGt\nfl6c5W2Iz2ov5UXLjzfG+wN7Ep1xUEjC8sgST7+pOLz0QJ1Ac5GnMNnDAztqL+P5\nUOlAHAI1DaR5XLk7AVYAAJ9D+5I76oDfaIABn+ZMWzIoDgKcpX3hlgFrow66GHZZ\nJI/1lxB+8KNTY21fIYoNT52rT1RaLpNL1CqT7QkTs0Sy0HiFTeLfM8xRkMxML5e6\n8nF13x4PR8LABXmZp2ECM5Selr2p0uJQFCtjHX0ARp3IxdUry32LUokBMwQQAQgA\nHRYhBIIXWIefkIahtKRXo23OmZIpa7SiBQJaREaZAAoJEG3OmZIpa7SiSrUH/R2P\nYGiE+0SWTiYTgziSbX2TTsV5M+9N5bJk+ApyjxmvrOrRUeI7MSxwlLBgr3fVc02z\na+Bdv9ZcwqvaW1b3W1vBvHO8AxNId9HVY1g+HZYirmSo/RLy4S7Rq29Q4cd+kaUr\nl5ElynDVdNKkkAvfGySvDiUD6QgsojSjHZuUVjTJAIGaV8jOiJwfc3v87e9+0V5m\nng613wv6ObgDSVc66X0bGmUJSUq2rqfAE06SqLQ/Dtm4UpJuBA7QdFbQewHVJtw3\n8haK47qPPyp7FV64y/K54W+ZPyZ6qb0q93uMeRp0Be82M4tKYG0+VW40eeYsNwRR\ns48XUBtmwj5eDg48hJyJATMEEAEIAB0WIQSWaLi1rt+ia7Hj4S/ruxlddiv0cgUC\nWmy76wAKCRDruxlddiv0cnXOB/9djGvR1v3PK76yvbtiqG8nZnfVmu8em3sne1LI\nA5oHUYtqsWCHUrpEY5LmlqUDVD5EUir/EAZDy9Muf3PPMrWzg1NPZK4wuO3N62aU\n3ZgG/aaBJXuLHHA6rYjtPUt2unuIIEmLgzKst6AY8hJuov3C6l07WzE2guvTC8jv\nZtsJGikgVnEpgIyN6sY2QrxxJJbWaM+4bomZh/tFMaczupv98cRZzFv3JlCuNCG4\nTPUgNI5q7vxRGr2FnVqVTJ7ZR5AsIakBvAo2pzxE9M5q3ukyYpgMFG5LcUwNO/nR\noHXCTh2HEEYPf3VGKbHMraDswhlBL/J45Aqp3uh8tT+Jw4MEiQEzBBABCAAdFiEE\np2KtXeBBcXlrRORD2yVHL6i/yo0FAlpLhN8ACgkQ2yVHL6i/yo10Lgf+JehUT4dg\nsR/8+J4pM9EdQYBXH1SVaRzFsV/moLGiFfJEkM4aBe99gVDWY7ddfljLx/s3Vbyi\nWCX0DuPojCkTGnaXoYgPEmXrXmjftihPz8hHUXrKkMESGHQYDBtgds7cLEx8M8Zg\n8BK5zwbMWug+y9JJV24qHMttVCLYbWarHS7VCj8wrIUmLzZeQgi9T0U+D3jv007m\n4T2E40/UpclAe+nexDb0/ehbFKbkVVafIRq8mRcxuoNUChG6RvhD1rV4W904DqdE\nO+eIgDOMO6GRuaSav9NudG6wd8hlk/TFipTX9XUxhanrjGXmm2o0YjQ4vjwqvjy9\n2rcxhTaX/oe5IokBOQQTAQgAIxYhBG9AVoIRUvA7ayTy/PhIn4Odc2fzBQJalK8l\nBYMHhh+AAAoJEPhIn4Odc2fzLbwIAKRAjVowy/tiaBhO52PgKEjDAgq5sCOUiohp\ntA5IIONt8heIIl3YRf8mIRIwGUZGyTCf34lIYsMIhAuVizGxnbREZXeC1D5BWuvQ\n6PQEMRnTWttt2htaNZVXuJh8CJjFY5bYQP0Gqdqg39HZgYnuPTdMN7x3yUzUbPKc\nRoh77gUjyzOroqS0kGmoR0u0tHL+kCEKCHafsDqsXHz023yxlMuYdK+RPnsjBNXi\n2ygoU/DEpa1f+5E6ypDM103Fiebaal2OI2dCdVTXHbOZFMjiApQYWa8iL2R8/og+\n+JLzf7V28pLjpd1ildCmnccCcHQMMVq9rq4v5Pbjj0wxGmBwlEKJAZwEEAEKAAYF\nAlnluYYACgkQ/a4lZvPwGAdB7wv+LZrFo7356w6ui8U3a7/KJhlaX1/Kn/7mUMjr\nI52uprs65DHLSJzrt3IqB7uAmdhpsAyzJaSbRz0f7oKziZ/gFZvLw3Xofo9rMuj0\necZFpULCugZ/s2tWSXYZcFcQZA4tz24ZREIm7f+SEGMMfAI4jymBnxNJKahxvC3w\ndPCKD3ts0oK9YOzm6WnoyZLLwFAa1QUQ+/SbgqsO3I4/wn3BU2EvFihDtW1w1wIi\nNUZ3S940WCFHdMPeFg3itzLa9vat/+pSyA/fc5CufWeX7Hv9ie6jXofWzir1cFoQ\nGB2YdBNCb6AwuABnMzKVxLPQsTwksQ4twDBUifqDLUk85O7Y5ae49600SKRBb/qq\nERTQKTw+5QSG1RLdMHPrF0qUFDJ9U1mrKMZYmK8iCKx6W6BJsvV5Tsjz3YL2ZV88\n1Bn0LIzL2CBZLmLqgao3GI2nFsrPICfj0u7o7apK75chVXo/LNSbKpqsx5NXMQq8\nNvVd09HKK50oUohL3e2qYFDt0evEiQIcBBABCAAGBQJZl1x/AAoJEGzo53jf9lJ3\n/P0QAJ6tKU2y2zAZ6SCKnTHlJXUtTSsSHN4m4X1lzlKJj8a5+TG1l8ucAG3q76BX\n+tOriTQXUY6tsOIS69aI2BrkiEoSEsUb0DEZgjL4Nulql+/sSmyc4EB58BQLQG9Z\nhXdWtkaatyOSiMwsoQvwjfVvpzzDTfEK8AujRKNYiZ7zDp//juI8zioYSubuNzNQ\nJOUOr5/+9CUeyRMW88zqXesc+PTkB264DBpNGTXpshgYe38IMGsqhYxu5iW88SCb\n1f6Adi6ZDBfhg7OrJXqs9w8IgSauSD2uaAWXwQHDyxm/KmCs/crywzxvY3WkMdzY\nVoWO/jptY0YdgQkToef7b/MFILSQUgjpUbCKn1BEFVEy/12sb7hWx2r9C12jooue\nCg+APvKWe7jKAVDvXtC5Vx0xc6fEPY53wnVSgSfhf1uBHHoZeBLgWTr+lQjrKLI1\nv3uu2vGDwKk3octTh665Dc94tYO5o7uXIRvCetq4TlcBnRDyESMh1SQW06RZdGtP\nAY/LKfASYGZggTUBo5KIKGf4MhbwinDuldiRvjC4eASkDncwE68Cggq4cvE1vDvL\ndC9IfVexcayJHcm6yc75gOdkq4YxgUUL1C7pB5MnawQoI+4LQcmwMPdiIOcnBFX7\nICTUc0/LIIr22yteSG4E8DBRzJpdGV4AS2OySyuzRva6Pk/liQIcBBABCAAGBQJa\nBU8SAAoJEMsRIiOnlU8G6psQAKQRrLKzj4eI80vVV0vaV5xETUZQ0pTsek2hJN2E\n3C/qCYKWocD6a+JJWHlalFtirdgo1jh9AjFSBWHXJ1R8EeLbQRhH4vGkMKZgmyJa\n/3NKqjWO4+jMR1tCZqdWT+qIIzu2tB5c2cYDgNo0r62179axcYhYX+xkXzCdw82F\nZ8BISkczmP7qlvgxgx3vt7Sbm6hgOo/jdpHNIk3sMNMLmIkKc1RRqZJqAaeVZT/j\nCNVr80uafW7bDmWbVJG2db1h7ArnGTj+Zdkte6KiajVTpxYQNq6TdXcj5PTpf0NZ\nyAOEhWO7EDUXODxu6TggXETThdSSF5lLp4WbW3Xj7+MxNhNoGfBigwQRxN7KlyuJ\nZ9qusQkwCrButK4cQ0qfnO0jUbK/Rz5IjYCTW14gpHlD7v76/mIoE6NbPL6jFSri\n1PUffyyRmLmURJ4DVUx/ywMNCkNb+0sgJmltoNQJ+ABHJ1ar89i8Z+BSWHlgio4d\nIYZyB4xrQ5H19z44Na7gedXxWx+Ba5h2nzHtzMEEpEmbgs79Tzy9U2kRIDV7CL95\nttDmvcBskGFruUsgEEqvwI/NBHh7QN6VpsR1Lz6GuF/LKP2JCrZ4QEd+vhvwr2oU\nBghBO2Qqo6vjpy02K1WYinUpdxoyeFkovXpR6BD3Y7tQFeVQP7CleVJICCeZeqyS\nlOW3iQIzBBABCAAdFiEEM9fTErlUMy8TGMhG2vXIZQnVyJgFAlqrP0oACgkQ2vXI\nZQnVyJiWRxAAvqqyzPQlgKQX10hGqmG3xouYbigUrPXp/Px8GD12ISX+3tQbCueI\nDxOmp9vzM4gKmZ6Qwdi23154hw6DmOOtSTgpTLVrb9F+Htyv5QSkcXMM3fb4TcEP\nNeQlmqueZMYJelbwz+Euas7i6J3ZIFaGwPwu3x5QMvINYzj0X+wIKTwlxa65Cgmp\nMDI0wkZYkk25dda081xry3nz3UlVnE+YMQqOewGWWbmhVObEOAVlnC+M5fzQXdgt\nhx0mdrfYpsna/qkoAuwqB2l/v1zXWXZ9tqDOA1k4gx37Kaekgp1Rkijki8pOeKni\ncfALgejLU5eTBdGuzWjpjYfMJEYy0UOiz9mWcytm7d7UKFmeI3GdsKJ2pB8K7AmZ\nkrFC0zKMOo8e0V0ZwnCVts+BEvaQjsuhac+lplHLn2jDwzundy6ZPtEHP1X0Uqdp\nlrAUMVj7yCoUBG8ylvPzS688iBhNa0Mo5gghjxKs0BPxvDu6vtl401YiW92exk1+\nV0XUDrO2V8uZN5PkLZs/9DmVj2OwM+sXPDI7puWytADCiWE7+c55GB5KDG9AllhW\nPwMIDHAL3sZe3leNdFKw64efUDyMJhiqVjrhaDfg4W9p6I/rtF20u+7f8KTs+pnM\ntGJ3Fn1xTDiEKJ2H3ql0QLsJM0SNLj539Ouq71u3qCCJ/j9IJLZw7NOJAjMEEAEI\nAB0WIQRMPD6e3S2TZSduUuoN/Vzk05JP/QUCWpyVMAAKCRAN/Vzk05JP/VCcD/wK\npl8H1ejxjD4Y9Z2s5vJRPS2fxXtdtMWqegP9k9K/33/WqEXXspFB7kQk36TSLJu6\nFT+Y7PaQUQY2GWcvsmZdQRX2jy3SYIWuuQBoFudTSNMcZBwE98LKaSSkGI9p68M9\nCx7ym5EYfNj5vp6wYCdOggk95I4v8tAy+2a97FAWea2TBqNOq2Yt4Du4J6hSlIfU\naqUKH4sQ0F8oU+dGBsMxWW7EJP2rCSyQfiv1CHgRT9hnDSTXvRpWH/VkojY7d/2k\nP6ga5GN3hwi5db2rFY2wF/ZN4QFprqSpc6aRbibrGiS61aL/25JCz01Od72mwz2E\n3njK44uHSZoQamkcO9qqq1+6QrYsFegHQHEnOw5PGpGNGqs5HIfxaptwOYSLeuQL\n6TAPaYqpuwHc4FXdz1y1ZtnWXfaaAOQ+mYaasZvrPpfoEDojS3DgP7Wg+2wjtNJA\nk5xtO+bf9+7b/dhQ/rTsDCx4I7p96XAXBqDmFBlLcsDgEufGOii3EkpxjW6Xyuw/\nSnlQ4SpBorUoujLRCj3rRL3MyMXTxxGydxUbEjTbmnPO7rN2XY4L9gcStgo4t1Sc\njT+Hsd9rPnvd9v10+UvflEIhYnlREGFYnJodk2R9DKMIBEBVK9+Oln0tH4Q6bzXG\neHDopsKvEiZ1n59Xa9lqsfzqONiGATneIiRlsmzRnIkCMwQQAQgAHRYhBJ7tSGmo\n2iHzohr6Kc4eHKDusIDrBQJapS1mAAoJEM4eHKDusIDrL/wP/ihBvSKDk53liF3m\nyN6DLCWpCSTBjP30jxneWkQJv8Edf+jVxVOOp9XgONpksjx3mb7EbgHqWFmzu0zV\nUfXgHdKizSXZTTUuhTy6f2bcfzX0/LlRYJuY0hyG/3gNhIgWubaGPANU2RxHFpoc\nt+0STw5XBBm7Z5hIh5OeuH9LwzGR+vU5U9OI6NPzhMDgA7K3CSqZCcqara1BkNJG\n48Dj0E5aYMAdmcFroo83Q8Asxpb/Dbe7+gswuGsDxbShFxpLFqXe7LT2LP1aMrGl\nzd2IQtQ8M77wimKMZDF1KFZm5jAOmmdts7C2KTEAXOYi/OXMxj/eCN8rJQ7SpI2O\nFHusWrL66jMcUIYHIVuyaOHFs8QBqaWC7+I2GbK5DVO2M3i/m8/QFemvqsgmZZbX\noH55O6c/TKrV+bI6cG1yOxNdmzW7mfRNuNwh88nV2pWNT1vV8ZaPT/KtgbaDop7H\ncoTl1VD9QvE9m3LFyCoffou1eFM+YlEdDg1eN4DR77w+pO76zb5yjgjn1zW0d61K\nVRpSGwJv1TM7ttEgAXWxve1VAtCBD7jJXufa7wuBf8WC648Q9rqI9lWwdomWtbu1\nkC8SLobRxDngjRHt/Y677V7i1uH0CWOisP6t22uYvf+eA+bh19rWBiJAInCuXwQa\nBV6qzcOANjgAjsM9XSMYxttIiclMiQIzBBABCAAdFiEEzDhU424zJSWRT79Mt4Wy\n9/ObCB0FAlpjfVEACgkQt4Wy9/ObCB3EmQ//ZJdjAgCO9UN1jCzHxc2MNqO+hm8y\nlUoadobcgNFDXI7xgOTY88f99iv6PE8WDOcU2rPngqtjC9xgTzJMQNAWYXekF6xj\ngxpjN/Vx9osMmjHysO1sqCBr97Db8GkJlxuRsO/5ikumAwxQMryWDRi19mhVut2Q\n8ehuLYoT7PDtgUQmHHLLV0VeqRRz+zg+uzV/uMeK4q9c9ent1arkaWKHtyGMdEhv\n3jfDhKjCkevjj2NFK8LwYgI0BciSaORwkPkxsrgFb0PP1E9AL2T30Y2e2Dm+/Bvs\nOiluUi04fIfQ0iAyH5wryvWuHcgfkijPQ8o/erxrk63glZYoL3b2KWKfzuPrc2F4\n926R6lHXXNTc2Dq32jBbvLZcOaZlxtnfDVA5OyosUsPnh1PxDbUYVvwQ3DG90M1e\nhe5tBUz28HPC0QDHqVuRdAhKrihZloZRXlL64wOB2FVwnHGHDQwm3zSxb1IjpdsP\npJE7AkTOuileWjm9+hbpYrFcfsNeCUqTSOFjFml2nZryQMbYwaWHnYr1h/01MkQx\n5JCOuScQjxZbJBErIvs4ZMw6bSx9BW6JBYRg8HfoQ+PSGoLtqNDZ4wefUSOBHEtf\nJgpdGjp7rXREzAeuXYTo6U9tvhFYEvtvaGvz0u9rPMG0LF/MJZEKRBrsFOGUQowM\nEDcUmvmCXJkNJTaJAjMEEwEIAB0WIQTFm5JsvLuu0WF2I64e3w25nYt6hAUCWrGO\nOgAKCRAe3w25nYt6hGDSD/4p5gJWdiKLGA8U5Tj+qIVbn4RCIRJRZFtRrXwwtcM5\nN6RWWqVeTqpWFbpyOdVsvvolIjPtv85SFNREzOSQ/J5HVRAwbmgun6hleaWrFoJA\nYlglWLiWt+gx7ARhUHgao20QOIknk+gI6LIbMbU+hxRtK4szaDrJVQjvZ0laEkqy\ntlJKL4PVXJsHJ8JrZlxAr6q6E/8JoYmxVx0X6L615ORpLVK1G3SkAd4/hjEMsl7v\nmcHqniDFQfoCn6rt4NrvDgWnyVQwmUPkz+YSN7DIkXjrs82spV7qccRRJK0zijWD\nsJ5XaXXdybKOHbAwXJ0I625bf5vM1swJz9FlllBlkor9+1NrZCJAIWB/pnYL8BMi\nC3mfjzGbZe1MdDCdIpPbN0C2xNKMonVyr9znAQQI1jlh2WUkEOlm/Z6ksTOooQIx\n5Auw0Fra93e+cqapvyxSiODotpIClj1xuaJX8+2ZI8n7Us4DxVjWaUNeou9vrDjq\nRGNNeOSzw216RAuUJRiaykIC6nR51wSJU+NjPvcpzkKmkj2flQeygTsOdlwIcBW9\nfMpDD4PDiGVDgxS6bzENDwILw+1iLZZy6evaotQoiPPucb6t3VImw6uEjozmMn8f\nrKjfW6TT70NrWX5GHxj0UAC+fsxtm/p+Qbopes+SsfIVRDwypgwnFQ2s/eF8V5CG\nf4kCMwQTAQgAHRYhBPFNpZ21ZX1vSx6MHSPyK/O8drqJBQJasY9SAAoJECPyK/O8\ndrqJ1u0P/irt0WUhKBHcYuGV8bp1QipW7uigU7EqpF2uV0duc2+PwY6c/CTFGzKc\no7RXdN5qm9IbDW5E4c+gmRSp3MIruvtt8GMHvGX7WxqiJWHT+4sjJL94ykr/1AOZ\ndbiJ956gEZ8G6I8cyn0HwfQXxiLCK2GVipIe90Ymo/F9Zc0lY9BEvpDvTJb1jlGm\nd9Ch5QO6xpsptzMXBxMAdzSTkLLuwJpgxAyV4xK313DICq1qt6l3Jh3ISl2ZH8Qk\n+HZN5NMJKKq3tq9AtIxldBT4id1gPy/koE51bqNx9v/3CAR76y3uBksi+eOEAKle\nEpSnVsGkbUi6thAgThdaP4ege4ZbWRwpnF396Rq/upXSWzAEGgQVO2dFnEGTFWcG\nJXmzkScbCcd0azUkfQBXbN6jva85OvfvKYNTFr8yDrygAmZD33kxedEXkC2e2Ikz\nnZU3wBsflEpIwix4GiGI/Nbnv7MdIM7zc4UyUF78l9FihhF3KjuPNnJ8e/lbX7Xw\nubqZzUFXGOdCvVk7niOhXLmGrrEp4Vikyh0VW6r0wfYiUVAVEs6APlOmFbJR1ac2\nrPhYHfrrgPPRziOtYSyS+kdWf9A8F06Tc/N/oZtJau8HOD/YeUpZc93RMeRAjwZX\nwXwIxWUp1gNB3Vh2M3aUsgOApQ6qeFa7qjrQ2oMao1a00cc4mxwJuQINBFicXUkB\nEACjthQU6l5IgGHrq+Fs6jmpEgz5PKnlRmhs1iJHocuZfyVd56WnKoES2nz7zk3V\nA7o3dfqQGkQAVKwOS/i5SffAGYC88VssCG03ZC1RPuuYHRk3IRlPeVsak/R2Aczk\nTHV6XN2r1m519ACeQ32wRo95z7McE03soPBrrfKeQRlGCYNr72dlyYz0KxVKqTe9\nRS18JauI+n0MBvK6efywl0MANSjyaDZulvB09lfNdmXCl5n1dGyvPKiPbpL4TOnv\n9jpjgoX5tu4EdPgN4hpOhMfSoQNB4X1jwciNeD7BRwupkoNZyQYzeBeyGOXXT924\nNhCC8+g8dHMnYfxc52RzP4lxx3kFrtb5FFJw2di6fkFLvGGh41GxaH9IBMZ1Ok/y\nAMVI0XzQX/tf+TuG3qN4A+3Xly8FEOVKhVIxHYhq/e80bXi7xOgXDEFxL+fYG1oL\n1yhLeO6AOYkgguvysZNb3fdFqz1kj/BRs/Fv72Q2C7x6iwGdC3TNo1a2lceRdREo\n7Ml0PPbPQX1mljNpfFpaRgpz7/8+7AJM30yGbqgVAd0ZL0jXhToZMnal8QitZqBN\ndwnaP2CRAGAaEn9vMNBcZn4llFbqu9ZaTF21G0GUYPgMhxv20k4ouK4mTysLPpN/\nGuKKhzXwXCB6JFo/Wy4e5onplvBAJvojM5YOEHOl2LrzewARAQABiQIlBBgBAgAP\nAhsMBQJYo4tEBQkCAr97AAoJEBL197QvKwHn6loP/iads9T0n0LwHE86w4Bn7LEE\nEQ4R/KeSj5W0J43XOeDs+YBdqryTQVZxhCajKvB8rsl2hjQ+T5abVejU7pcYF9lO\nne4Ouu2nemqrnzvBAMzo+xFMWjjVR/4xnEYveYNi00eAifZs0uzNVWeKFFn8e/Ob\nocsssR7orhUXzKtc2WDrnMSd3yN8yFCTB7ehys8QdeGLcD38ieUQ/1VYmqvwIHJP\nRgmgHg5tHamZ5UH+csekeMbhKX6fvQivYrmjxl7ouSkLGGiKktsahWpBikNNia64\nUIB0z+wUSI817+IL/eBIrzePC+Y2qDZNXhyhxQ9tFzE9oaJ4Xgfylws3WM8+GyJX\nzaLLB6XEWoXKjDgLneewIApjv1/IbrFH3N/KyVDJa3L7ExDBaFqDV5ISpKP4XUXW\nBtAogALEYQqWPm+NzVD4BjOePSg8ibRy4vI3MwctRWFne9xyveRIEvrLk3VjfySG\n82BNjxzVvuAn09ljwYlMZKFdGbswHnI5rH32GQymYE9/llZnsMclUBjchpnkUNoj\nQ8X57ZIC+A0RyZAf68g7EpZbUZqsDjGyNLpzLdY9AkC5Zc2N00L1iImEXDAREhUR\nIMVq7+ZCSmTM3tPgTcAjEohJMDb5tic+dBGZjk4jRpeXdEqmIEMsPP4tbsQUrPNF\ngNROtCZSOxKkyR09g4LOuQINBFicXe4BEACvzk0n8cJ/dYzRk8tg9vf6SDwEfUNm\nmFfgGdVfLKa18IOV3hbx4DLHOO8Ah0oobt6DRmUdlxeTvoFxOpOPwWaQYAcXYoxr\nW/j92mB469MVDZjFsNVXSTg4en9rfta/xi1FBd/BlGC+h48ueLExfAh07uWn5uA7\noMVNWw8Dnx9UFzDmAu7SJ0NcvSVqKMCiLQnESnxtw7x34H5wfI32xjnclHCzDSLs\nQl3ALfaz4dUEQmyvjgQaJkvaTcF1YugLRm5MOCzXpobKZNa5vpGTjCQCyqc9pznP\nlQPQovuqB5F2lEybeayZvZZag+PadE7f8LSFj8q9E4SV6E8LrtWnkok9tr7QzvC6\nCa6IJ0bsc2w7NOaU+vFt4sAXPD/BfIzSYpuRc7vVNIZKpCb9MBz+AKfzAgxmd+gT\nEgBPKEFwbE4x8nVcnv2C9vHINxkXJC+AtRPJGNQZ9oZhwPUEGyt4gjXbiEgZjfGm\n2F/UQyY6qwpK7KUXnyJGweVlKNH+oVvu/lFYUFAg9txgOaj82ulHth40hFtmPET1\n23ARpNKYF93nvskW6fYszY5+c2/7UmMeRp3jGk8A62w3gdD9KaMPTaB9jjRrPoZF\n77Ci/qXO3K5LhWakREwHyDTr0A71Bf3raNr3wKzVuIcXKLKzAe/KVEPCzoLRcYyQ\nUeBBxAtuYMF5SQARAQABiQREBBgBAgAPBQJYnF3uAhsCBQkCAikAAikJEBL197Qv\nKwHnwV0gBBkBAgAGBQJYnF3uAAoJENcq80SMwrA0mnoP/j6/TvaimIH5oPJxNDON\nz+W1juqKLZGn/1HNi0A7l6okvFl5syvEucyLo8ZwR/QeM/J68Ar02eiWR1MoMoXZ\nL55A1wbTvjE1j7oGpcZjFgGhiv1dTNmV1h3UKcAHyu3an7gD/U7HtUqECVbCxYye\ny995RwMoChtuMyYaMEAkRh3NTePdTL24LBHQgomiEAclZKPIrScS5TmuQO4wycui\nNS+WHKARWOYuQptMv/E0V5Hwi4cLbJV3pbTw6Rwane4ihwXNjmGc/XJWTYK9aEBZ\n5Z7QkvR5Z7kj1UudMYOEXYncsjb0e7ZvCysdD7ZuAI/KuvtrNc1FWNcmW8nfLy6m\nf0MDe6WYQIYhmV6/3vj63JS+QWpUEdhZ3WKxmO+xwHLm1qU5M1wvohosz0mtZ54u\netq8B3UFl1j7d0eSgZnHSSoqzX3hdlohz++4BZ8goO6PV871rKp4u105vhxg6vhP\n0TBWHXks2CdMC/5Fmr6W0pHQjeBQUOBwHN4cqbEhxt1bomp+JMpCdIubg7YHXi8S\nZrYEPT6TWUnEqzAtZRgXRN+nEQrwEd8MH+58w9Rdb6E33uTDMe5OyFXcn7NQI546\n65v4ZUoRYn5fIUNlCMoTTPm0P2Hh7y9To6Q05iL8bnpSXD5jPfoPoBq1fA2MPmT6\nxQzk3xD4Eaj83tetPCUKdT+xbswP/2Xeoiwy+xJlZcd7CbO+ekpIlH0tWI/b02zU\nVT/xl/g+66h0C/70R0JXOK8aqUCH/09Y4Wp6lwfjQiBsFePcTtTg7A5Embiaoz1M\nlvAaarJEf5fjl2wmtOKAskQa4jLVhVFENLqrmoHb7XuHRKOoAuJe93M/HplJwemz\nigqv0Mb7Y6EEmv1bFq7Nw8SKMEDgk5PXlvWDpKcIa0kp5LLpmEtFflUOTaYGHrEe\n6B9+ne0oeUTRJPe7/U/jkHIw7T1wQ9nw+Xu58KPlFdKcdMvqQM83+hsIdtA/4JyC\naGzgIBZebv5dyxmmGZ1Ly+MSGilTR8Y5XV/AZh6LNfu8QtIuSR9CHTaAhxlxfAZp\nE8+7fQsLhEmXhaernLL07S3y7CVu9xOVdcuMlixNgWrnKY9/lhcEAVTN9df19phj\nExehTu5+VIgROdnZsu/JEhMn6TcHUyeDW6YmWnkRbrFhPSd81T/gCl5cgDY4pfxe\n8ZIG6it9gqw+ji3fwI8qEkHqgbhZNCiBFp4/BXEZ0mQk8tFeYqsf4Lgb8vYB8hh7\nN/cUR+Gpsm5p/8B1/b1C3SiWPWI1XY7R+jqUMPuyXPcR+PrSJxwQfjBK1/UNUwno\nP5ADWTwA9Gh4FK22sMjR0EL1cujCQ31krMerf0gMFBxeqyj4jd531kwjfCUHHD48\nPmYrvgvBiF4EEBYIAAYFAlpfoI4ACgkQG7icBgI2dEn60AEA/tPc/WbDmG/d+X8X\nUrxFP36iFN//KtLMpqE1PvkAUpsBANS/gwKcfqqsFAIP+S85Rw5y+a+MU3qx6/3m\nRH90Q8kOuQINBFqgQNgBEADPqgmj4AdMhHak5YXxljAYuiN6dy5+653LbyWqe+zJ\nvOuo54MFXGMwVhHFYYqDakwKBN8GsCF9DGo0jKHqLCDfYJgcTleF9PZQtjn5l80M\ndFqG/+8i+TMDh6vpe2Y9vHDu7RCYzd3+RJWUhqjE4ut+lbgqr/pLjOvItk7iUSRw\nYArS/Ax4nVRukQVtUvloNKGwECK6nr3PmOeKfJieZwaesbbBAsrtkqQ0QrRBybpX\nqJ61nSztqCyqHmmRnUANNWzjmL5ASEwaoJs3yMt7Nj4/IrKd/2P0qBpjnkcnvB3N\nHUTysH1j2nciAs7PuOnyP+m8QyDkVK+vAnO8wUcpMOSBxqGk21OapPZYAgIyH8jZ\nSdnlThzA6LyI7Kuht+5KgdDGcTHYBVzEKLXEuseokTa+CFvLjZTs+wy6KgNORahk\nniKoQITppW0l9/bh2GvNxeQaW5KHzsmGWPX0mNPFZZUEkUOvor4McQAm1u1NOdNS\n4VFoQE/m4jYpZYbaQamdY3qK0m7gmPo+VDFB+0/zrBUfWR/PA7zzioIClkOJ/LxN\ndDKaH3iPWul0kWu+C5q8xW0U6SBj963MnF+Q0l7fRxS3T7pM6+uKjAHUAoKitdjS\nA9wH7ARCYIJKogv+k6B5c7Fkw7eSV/biRV+j5ggN8TrSYpGPljyj0NJi1xWs+A/I\nZwARAQABiQREBBgBAgAPBQJaoEDYAhsCBQkB4TOAAikJEBL197QvKwHnwV0gBBkB\nAgAGBQJaoEDYAAoJEPEyscuvExyu+3YP/09D/XesaBhnPs3xMjyTHDDinzJw6XeO\n7WySemlSDcIsKhbrRVbSNRubMTjBx/jlS4XfN0R7SgMrLwNz5s8cl4iW01ZliWx/\n/Ie3ryfPUmhnl6mWXUDSx8BPVwyGNH0nijBh0C53DfjVHxd0All+orLmGp7lopgK\nrZeO8WBbK/HFwn+PTZKr+/SubJQsmQ55G5ys4bIUVi8wenaI9jNdia05YBXxPN4x\nxDqBYIzQ28HnkivH6S6zr7b6S45gia80l7/2CSPuoNwe81nns2pzPigCKs3aFBsM\nKBX+kkSRktEjbyDslSGzXChWnwoR1Iv/XlwhQCFRk7K3MLrqsUof8q/jWqBDA+lT\nK5j81R9p6oeb7Fnh/8qNYcGvEgHfo+ZV1ihushI9a381vuYq66RNhoBwdZJliwjI\nR6Z1UWP2jXhfyAcUhxcryOzdGPbj+LmKrDXGg46wXod5wNAMA0g0JYoXruM2O2tp\ngHtCVW/R3RSD07ipubVHAW2RwCC7mhUfrUZP6WMkyhGsNas0zcRPt9v66YXc0Mcp\nilbh3g1hcgb5H55YJyZW9IMVFWZqy3ewbI4DIyLQnrUW/yhhtlloBfEaenEEvnfo\nSWyr1o4W90lk3CjjHGqQ7sPG68lwtSxKCdrAR69cb/EtYl5hllqgeok75zOXJX6H\nkSDp3gKear1ZZucP/RdIEGmuQETA/7LzZF1gbQx/luWgXUJcmiqDDN0zlN+VrAqj\ncmWrkJACDF1gA/p7cA+mC22j1ENJLXWdOi9rNvoJxHP2Zcndc3EH/UkQJzp5KnNv\n9gedqAGrzlmaih9uSuH9Pukep5+tMJdJaXq0vPctM8iFdy+9iv8ocikBDGc/miDq\nXg2VDypUCyOqCAlVpAGqrxVXkeSNUceVzaEAQgjC+ehXgDtzHhtkgAtTLPzarufA\ncjt2kbLFdbELR8Fefq9jGXoCoWfVQUlxLHIPRh1L+11Y6T9DAMGi94kAxWxUn1oQ\nN32UQPrN88CePPrOngZ3gv9CLGbY2Ml/XlT1o6dk209Gauy8dxjraJoXq4WQ+hHv\nJSW0qR+n9E/an/apvIbndUCOzqBTzCoIG5LqfEiLEADez7V1YICaofZpL7RW4GoY\nPbLJMnfPq6PgHtT5QZVTQO98dZeZwmekMhwB7CTLGROp//Ko/FJ9hqE8pZ+N7Nrd\nv+WN/wq9dUjmSHDEbhTTNMJwcRadla7Dhcq4Gvb3lBpoy1o+DbLsEoDuQ3vivEaP\nX64eM9LGYkeBID0zv/LWQoYwBh5kqDyfxTLeOhr6VlueGWn2jNEao9e9Sn4psiKc\n73lcyOecSPhJ1Y3WJz5pqkU88P3KoFHwuztzxx/997XGEU8vcUQSmSmerv+muQIN\nBFqgQQcBEADPVquej+jmKwI7TVFgcsNGjJG92IQr27+1soFTzIvK7KceG603+LzJ\nAqUi5gCgz9qNwCV3C83iAPMhwJlJEQiNTJpHHOLw06MgD/A1BJEv+IAgNxGJEPxM\neBmENqzxGJBu27l4F7xfybN7jRRIy1sCyeuO+onaL9Z4ig0YMKYqMJQncA2NjZk2\n3ABB5PSMmUUxJ5ZimuLGhJ6qOUoZGsEKtMk2D3rgD6otng44ATakOHJ8cTJvfhPu\nqdJrIUeE6VslR0B61NW5wy2HfmEGyS4ZyBZZGKwxDHYMuBwIDnBf6ed9/8/V8z6R\n5J286vQzMy5DDTp9gRhvogDaX9lp+/RWAylFsZtFJquJ0GFyMkl48fA3CQ59HAXj\nLn5//BWH3WJMQu6oJGOm2it3LwasyYT5OlbxbPyxEG3htWB5aN5iFYHKMUoGcFkG\nhxMeIOYUvLYk8Esk5v8FH74R3ar5dd39sXdSbq1ZSoFy9A/kYBTQXc/OjnXlhzDc\nEbozSPNwfyxzED52ftFG74ZiJbaKZb2cJSsJlcx+KvWLr+2DEC/VBSmYjUTvVtSW\nJ2xBqomspYcHZvTk2J8T5+LUf7HoXCDMTfLQp4nvcFN5Kz7wfbbrAWmjZ4ppEYzb\nRWMY4aiNtcPTrFAwhkfSWc2gGEZgETItbncrdfRzVw4cB3EVDBlThwARAQABiQIl\nBBgBAgAPBQJaoEEHAhsMBQkB4TOAAAoJEBL197QvKwHnonEQAIY6nWM/GEp/eEd0\ngmlcUM9Cyv9m5PbARSum0CF3X5pzwbnY1ckg9ZAFUTI2og72o0SKPUgcoUvFFxZW\nV/+418ffZP6/zWDC9hOZjkgLM3R3uIVDN8HdjAC/ybf1gTQpEM0PfslsKgqomrXB\n8Lw+oqxkK8Uk0Le9zDsaFdZC/tpzGnTQouuo6B9gHTbpwHrtNTkkHqZh6t7+Jh9p\nhgVBxVgx6T1qKP4nx0x0qfAyv8dAVmp2uUxVO7tsK5pXwjT01293JKTQxLfyJI1/\n90ydtdsfVJobU8T2Tcin+EIMuaf7PfYb+7cTkCU82Sa/C2e7t8krXYN3Hk3/t7dd\nRecJSPmwhOijr5PuuGQerF47ovcH3XyyeWK7fOSqiX7jS3MIK9HaN1il18M2qZWl\nTzZQ614FZh/AwJN4uNTO2MdxHXqVSgvmp+QCYNoiyYBl4qE26L72XEVIcXxiMGlX\nwWJQI6+P0r+CjhJyY+vNdfaxy4HadD1h13KfsLNZc4+yKsxXerKZmCDIET+wFe1b\nPFsRNFfwKLjB+CCDqTpF4l03YlPwZwsghaQ8g+NZfl4qyR8NXospGuv7S7gBpsg6\nIcy08LU4uylmFHmVCPJSYXYtjkYRZMyEy8BEOiwQT2bLmePqqRS1GN5uz6ytX41E\nU9coVPCcdBfWUAxoPoOCPH/eNug4\n=Q4FQ\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/files/4AE8DA82.putty@projects.tartarus.org.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n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\n=5Mif\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/files/7F343FA7.nmav@redhat.com.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2\n\n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\nfx08azxnYdWAMp+HWVuMX5HUja5uy7Y=\n=W7zY\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/files/93298290.torbrowser@torproject.org.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2\n\nmQINBFSOr7oBEADQMs+Q5cAshRhj3YkKgCBKyrjFWMZqVhlf9Y3ePtFQ9kFEnYIS\nG9rzMhFC6KMXPn9bgg6OBPPUnnJ29UsKvAk+qa8F35R+s0ZXmPRfmv5/6PqxLOn4\nG733K67K0/eXYW1mTkz9sjY8u9E3T10JNT0zE/60WihuZGKZQDIqqig0fOsdvdGa\ng+srAW91T56kAT+y59VcvqVCQNjS897E3T9hsUNkQNCdOitQcnN8/5VNQUL0SjyD\nBV0y5ry+pUt1rnojj82KQ3WzZuD+XsDE+w2JSGqhcqf9b7D6puy1smhCNwZJ9L1l\npJlrCap6YQN8TPFTkf4aFBctxonAdQDDxbON6sPJALc/myPwTVTxD3nJJhv12yft\n2iwZLaCJcdq6tp96re1dwaETpvvKeWqhWGVkmNaAPhShcCKpVYC3+Jil6nTqN6LI\nhKD0ILBGOT/2/Rxd4kj1uDzvc2RVHe6LKLc5EQYO80/wSIL8LMdqZSX2R/AnhcNg\nG/k7yOQWWNY7RPU1cV+E9QKNwqS4Zj2VyU6s6ikaPuUnjW59iMkSGUuS+gJUR2hp\njOKjNzu8vxbotBgZ01upDUdl69OnR1dv9X+bMzGWUyOjAjK6SP8rFtWFBjWgWcED\nOHu51YpicSdN3uf7lppEXGx91n45xVMhL9d2KNp3DhWkKDuWhdliWC/r1wARAQAB\ntEBUb3IgQnJvd3NlciBEZXZlbG9wZXJzIChzaWduaW5nIGtleSkgPHRvcmJyb3dz\nZXJAdG9ycHJvamVjdC5vcmc+iEYEEBECAAYFAlWla5EACgkQ+y7y9FbF3ZAQmACb\nBJdYyWuOZqW65TQHuhBWUylmvosAoI7ZcRHthsc7rbxyyrVyxf7KQynciF4EEBEI\nAAYFAlaFeWIACgkQDChl4xJJA59WuQD+KFwkFRDR+btvd2i9AsDDuUaNKgLD2chP\nSBqGdunp7EMA/RljHbiv2IBT9/Qwh+OhsdlPNndZP8hlso3aLhnwmC/riF4EEBEI\nAAYFAlaFeYIACgkQSrRpVGbBgo3QGgEAk8kSk1JGmWgqN5Z/hPaKWphZPTGKILU1\nti5SbtWOX+8A/R/xhCSNvfo6hj9gD7Ke0RQDf6oaUYP+9QkLKrCtmVYpiF4EEBEI\nAAYFAlamHJsACgkQZ9V9uxJTl7vDXwEAh2D9WTqu9pMv6EtUwVXHbKuJqMQgdnlc\n5aQzsRMLOQ8BAJWpb4Yz/4kg0CReS2VEQQ0u5D3nQ4faAB/k0oba8pNxiF4EEBYI\nAAYFAlpeZdQACgkQG7icBgI2dEmfOAEArA4g32sKvzQ9mW5fpd/kJvITXLqSYC8w\nbw/MtXsow8UBAINQNm/XA29EgBdstsGRqW9Wsd87EPlaQcPQkGM3lR0PiQEcBBAB\nAgAGBQJVEjP0AAoJEB06P1DNYsLzp2YH/3NaY9upY/1JNHSir5vTCti5P60JJA0N\n5ZGE7FpQYcahsm1EugAiG4avfDf9aRTJT98W0zvNC5fnM4Ubiae4vk0bciG7cbzr\nNP7HyKZpe7NmVTIIeINXyzy3z267wKmbHuqzdE1GIIGiWsJbg7ojQ/1CQIlNdGLm\nGGe2nEx4To+z+mueLEJB8ClO2ucFN3Z0ISUpx1nZCUlJAvXZRGOxJy+oru2RI8yL\naAa/Fmf8UTMtVN8ktDGPCEl0Iz2m8R1B9WGmOlDpR5f61ZF95BSMPjasj0PW0NqC\nhW7tZtPBpDu9OkYRgZIa4HcSCqWoUijPjTdYO2tEd1U/jGajXGXE5WGJARwEEAEC\nAAYFAlUTRtkACgkQWCE+ooJH3UWzcQf/YSRLIRNV+RZ90f8cwqlk4Cj/XNGjgrG1\n0iO4NlPoRsjI0mKA9KgGCa1UN5hqOqwOdW3VWq97QotF9U8MRWGdky006uwfx+p4\n3ZSACHYegjmH3is5G7tMGpJh4sPwyLjtoZscPNva/LoFOiEg93JxklUZV78ndxZK\ndZqqxDaMGSwxmUpa5RwX772R/BeoPIMlbtm77V1MFZ9f0yC54YMF1fGdAeqwwJC1\nvFXoA+E2o7IzdkZ7Ik1YgOyHtM6C5SHHOWIsRJS2cvNQSeCnHs97WVEwRh3VQBBK\nezyKrq/9vE8t4OLMHqwwMM5QH40Wy/XAnpluLdXyqfihRfMKhJTLaIkBHAQQAQIA\nBgUCVS8zAgAKCRDKkPFV7oCnVI6vB/49fRFEWSEI5hzxteKl0nUZ6S2Ls6KF4x5C\nvRYN0Uo4fK5fH/Gcb7fRKCdrHD0ecTHJoRoogrSY0Drd7yWWAwe4N9hwgNH2hWy3\np7JdIna4JXXImiR/eTGriAW7Dj+yk/uMnaS2eM6rQrRLoyIbrMEUPDOWzDAwf7ky\n0uy0p5Ks4pxmYL/4yy0HbAx/sU6xDlkz+zUZwdwHzdD8vRi1W1Fuch0Ip+N2RsiN\nzg/TOVJRVlQtvD+qCcFr7IOEzmD2TKq2Xm3xXkAue4BCNCLE/5S1SA/lYvml34ZE\nFasRabJ7D9QYS0+mkfnNzBdihsAm7nXs3nYTVXD+G5XuNDPzbAqSiQEcBBABAgAG\nBQJWdVMcAAoJEBjGsF0UDVTocX0IAKIc6LmuNYPLUZteJ4asvyWStWmw7Y2sEQFk\nT8BaW2jyOgD84n4KZ5HkwnC5jrBPyqOemqJb0jDTZmZFYLdgRkJPvM+z6IV0yYp9\nJ7A2rpOoDuBnEiPlcQuEBWiw+faKX2SC5liQTv5XfxlFJFAIGE2g8PVgZvM790fh\nHBBtrE/h9/6rujRQ09z/DlgKyzvCyhjjXMdqQOsWI975b76L4go+JBTQ3sOj9onN\ngn7NtzF6sHUVlowOZa/ZXw9PS0jlH4B7m4d9Zr/Gtxg9aeJH2lSlWYaO0derjXAa\n94KYbsKRVX/cKeH0QonoB1Wx2pWyOFh15h5h0bVS1XszCNt6ifGJARwEEAECAAYF\nAlekf9kACgkQNmmNs52lQGU9WAf/WVq/GmfI33xfS6ub/slVbcSbPk0tyYBKNf5V\nrJ+c4Y97aak0ryMTnhkVzEPhwEDFJ7SFHzSwNmQLGtFXNokaGwq2RQk8n5NvLcF+\nhh7bEZlF5ujDGEDeQzHL+5pK8urbx8mFwBIEsGxc4VqTQTyXv07/aYy2+t8fxnND\nqYTyzkMRkboWVgCm9+S9/xDL9hq2xy7QnhrOnDHlxMJDRLCpJSPmE0m79yCjaQEM\njoJa91WpbK4HBfjA21DcQDGUEcvParyRx0EnTEHXDlCbAHaQSqNTdTl8VjWQSowx\nX8srGobzMMJnTpASEpdcvSjX0qPYtz8Hys7D3pSsUTKrIe5p6YkBHAQQAQgABgUC\nVLUlJAAKCRBBbwYQY/7mWar7CACWno76ZAaMxYSDbAB8FJjit4aG+C2JWU4bGCHD\n3RHdPfI/svYAos3frt+ewWWN6PsKzoe3SaplNrybVwK0k8KAxPn9neWFJkRe2llR\nU4SmdUNk61rS9UL+brzhBxz/uYmNI1ZE3yqGhFgYCHdS3f4dEQbjb11cBcwsHNI+\nT/LS27f5A8cTKcyW2stBatFkLgyV6UbKeLDCPZQtQLf1RQz2CHtMdFZ/jCzJYpLc\n0n50XRzfSRMA1zwryjDx0sgTR8skr7qIxDiMrP2Mlpqjvj+sIUMaJPhGP+XiCSem\nteDUOGTgwf0Qb7/sK/S+6czGiElHiusup3d4G8tpcfEaMrodiQEcBBABCAAGBQJW\nDfqiAAoJEAWnN/Y6+kUYfEwIAIarbj9rlslDYAGcgyiRVONu/t/YyzqThQdz5vdp\nwvFC0fGEfiKG54iqvOU/+uv34MmGUKovKCn+qFU6RstJPWUk6GWfl/D/QMpsWHy3\nyAfdd0rWsOKF3EfsYftEPXGiGrnr5AAJ0pLQ7slC91OFjA2/Vyyi9HfDOUCALblt\ntku2UlMSJEqKJvx5JaWVIuYerPvrhULhp4aspTBV4QtpPET7bAmDQpHXL3SuCghf\nVTNWK10eQwa42jUE+X12d5iXGkQewaMZAcBA75bEbeuxA+7PKI7uPNAPKnYB9vWB\nLd/+XW3ZB4jxWHc/Ga9X1jReEQliteVO8DkHwmLVxR5aeKeJARwEEAEIAAYFAlZO\nFkEACgkQp+axXpLQghfUEQf+OrPcZa3pWmphIpbhe2pDDknCy56NWOLHyvBSU511\n5FWGWRC+PJRJHFH76CVciakgRX3k5RXnEN+sH8kHBEhr0Ah32tSVDmSsf79ah/zK\ndAe+YodZHC2VNasH9ONf4CA16dPLBPjReGO1rEJYfl2w8OoRu9aL5rwuFH9fvu9C\n5sAHUFpE3Xvz3jnDzHEczmAXLBXkMAsqnRDULOaPCigLLnZXGqsBxjPsUr6GMZYI\n38jSkD9ExoqAYgEiCyq0OP+wmv5iyeuSqYXaAEnwAaZx3mdVi02nR7baqQ7ndYAE\nubOrYFTUVhwM1GvfOBigW6BTP16wNz2Ir5i2Q64PKUgDkokBHAQQAQgABgUCVpAS\n2wAKCRB37AfRtpL9a+1xB/9eHSTC0jZydARxJiHYZX/kQNrWDmtb1GdrWo7xOxfh\nEQZx8m/7SK/uAdQRNQCTIf3uAcFFrOfRNujRBhlikCVQlGuBaYc/facbYgIK6vn4\n7L4jRLcpKBs1i7Mv2qM6MCTgzJDtXH6dGYHBRTAp4JSB4URJekfgnoxk0sI/8Ihp\nuQ6WopuH5XEp1ly9/lmX+rrIvWmTr7ENGnuwJAcGKRPmKe2GBE0adREwSulvoTLn\nr6+1Sx3voI/jSNDnN0P681e63mN7kANCIRNE5MnUmsdxuG40ctzTAhg9ofSs9lL9\nJlQkGrsMIcJDPEreUNoqHPaQJJ9RwUd0VDXCZ13qFwquiQEcBBABCAAGBQJW4t52\nAAoJEIYPFBQYifLDbPgIAILq5yzZ0Xf812FrYHaO7tN4ZqtvdJOqjFXct/TBl2B/\nMdXSwmG/kwBgKJNhFEma4d17J5g7XNsBX4x55x6tCPbBOL63t3mkgTRkiZVRI3yp\ntV//unAzSNZB5IXsI5MBCSKVZ9oe0BA0GPX6WNizKIGYsgvxT+/73q0IocwHmSMN\n01mK+tSgmIYsojvKoPvBPOF8p62ELFtStCyOfrJ73b89SlxhYMV+U5059m7PIQtF\nUDHtqnV0de8zAjWJUNIGnjAqSyYjTgayeK4xQRU2aoShrwfIE0g80cCNNARNeMb3\nckolv+K2C85RTDe1HYEPt5/aUBaHQgPTKPNvmlUSLlqJARwEEAEIAAYFAlcnSooA\nCgkQDC5fyREfiHUADAgAjSn1OYu8xFloaBzj+r3ZH1+/GouoTq05gZ2SZouUOigl\n2yj8vnizSw+Gafohg/KK3SeLg1xXU1gmhnzTzgzZPiwKAE9EcxyBwVAbuEyiaNvL\nD9xHr+wyf+TcdrHdwjHBnGLQqhEiaV0lXjQZYBijuT1a+/wTUWLthSIUapHcrECC\nzjRKpntqZo45pVIwwlh1ufFcx0we+uYBrG/wlH2ZIUSc4I8/CllKr4QbEUhvzHYF\nZ0k/H+R3bMcX6skKulwzJxGqYyRzqWQv+xlBtKPC1MSkq29JgTv6Z/Zpi+Rx9jLL\nCIqRjTijmVg/1Pqvv+oBD1DLPw3cuCwYXnTgM7jN+YkBHAQQAQgABgUCV77uXgAK\nCRCD9WVq7ETKt/C7CACqxQ6CCIXqtvffOpttn0Rsu8kQlSWeJusa9wUmwufZRDwq\nLQ4+mer73o72AZb4qnto4RRnpP2TiHD+oedcwKcvZv3txc8VnvFNHkEE86XjumLc\nPkU3CUs3mERA0S3+/7OTEmjlW+RPTtbxtDKzZnQXcjKH/l+8FkOS/iF2N0CjqHMg\nxEXTJGFAQ8rmxMVTUnLoFjUBqaLPtOXuefMvyVkdMGG7efe1UE3/67PXibw6gnyy\nICQtjxvIgd7Hd4GXQ9H1jAM0q7790JMM7LK8GSv89XzTh3fRFFv0H95JiA62NGX0\nJ8GzgUXzE/yMFEAxSPFdIvd5Q05yRkC3tm6SOtZeiQEcBBABCAAGBQJXvy77AAoJ\nEI5EJuZR7f4otfgH+gJO9+z6/KdnCzJZG69C0yCE3suwAQFuNewUNkq+W0Kxn4TI\npfhei+Q0GuR/or5o1RkAOZzqwHY4q8mqifgDixbidVgzXkIVrzyWaQPCcvULhd6E\nPuzQm9ORhMB4WOPS51+AyCPXyz2F2y2FG8gnQhWRaCZDaZ1E5U+y4Z/Gtn7zkJMp\nD0oHirnE0TFMbMYMHXomLRSWejHj0xdLwKQ7wZsclLEeLklWYoMxxGSm7QL9opEt\n/mA/SRw5wcyzJR+ULbiBdFMCY8GZsGsPduHqZorfzBjiO/gm67W33UYO+lF6UAjw\nXWEs08L31tbyhPIxwTnnMLK3vwx4jMkfHXoK4O6JARwEEAEIAAYFAle/ty8ACgkQ\nABHAjFdUuK1R5gf/YvuT/9YfjuzmYxEHY+r2NHeLp4M1aAoCNIwoWqrxBAE/beqc\n5Pwu3slrFZe20+iWgjkoVToNJ3q0N/gHlJGRDEj0Lu6gGsBsTaIQ+kepVdh1dvJc\nEQIkfIgtGebR2IjUT56vyb07ZAHsE+mDGt/G9xOpQZs1dbK+fq32qA6iMaJ0ATlN\n8sETzjb/Y8OKiLz6R8xZPUVibToHGkSv9JbeFApzj33SJWaGkEMvk+kCqj5XBjxa\n7RoUMcpdV/njbFq1I5/ZfXLJcmide+E2974bT7z/m1V6SfDjk5UYnW90IDu87jJp\nmDEOiWkLH28s9sLWa5gn2Dzc5ji0qOwcyAcUFokBHAQQAQgABgUCV8Di0gAKCRDN\njJt+fEivprzFB/9fwX1KeXdM/jQKqf6+wswMEzUjXXvloCn8nQUMe1fclgzv+qCk\nkeeJHrnAhf6finr8nYdkGnxYuHFcUcHKZKSQ5F+i1gCTMT+qQrXK5PRALvuUzQmQ\nr9yzrJD1srbvzPxWdscc+0kWKT83E1VltNsfwI3slRv9dwxtGyzxBJZiL5ujNEXu\n6Hwu2ScUt4yn8M+HakUdEQamfPJ2+tuf7WGgnYy1LLXhBbhM1zy75Cr2jqapoojG\n8nMt7tIDPDHtZMASzOEJORaVGorIwzDTQi7vKpRdsH714JoZ6zoANAtWH4kxwj+7\nvU3LqvI7IH/MZBpxRiyhPyvK4wyjXS0hq640iQEcBBABCAAGBQJX49vAAAoJEEtE\nVOI5SB2W7A4H/3kiksXnIL+TgCNL1Qd2S7eOcwKFOzwxFgt5ibUA0MxdPxhF1EJ5\nZo9payBfKXFibYgCa6+PlB9TcsfuoBDjIkkhjMKyZZPrZ2drgFM7ASnQRMQUF57d\nY6zl+CHXFpVlT8orTXqZ7HUI4hw8458sHW6yfjcQl4wWHvmB+SEMON6XmE0w+KUM\nnjbZiQ+fsnWTctaAmfeX/gsC7xIcKVfxpDR7Syn/jYbsW/VInp0RtoBkW7bD8aVF\n0V7hAHt0BbLP+aaZDgDvA4EPdXM89B3zOfFJpB5dZ3fc7kBC9B0MX1YDVNTLTaeu\ndv2m/wpXJmxbF0JuR0AXawNPDkVNUqpfn8+JARwEEAEIAAYFAlf7QxUACgkQo/9a\nebCRiCSZAAgAlswIBoZXfZEIqhGp8rT5G3uOjr1XTRfxdzkLF2PkRX3gzLzFLuVv\nPp5I553F0XxN7GBKHsB34/GGVB43YSYQINn+M7cqyXbcszZRl/RXtWd9LvvcFk3g\nmiufa78q/5TdFjCJw6rFYberV/dU5RhaNL0YrYxENTYH4esQdtOiy9C8WUMxcZvk\ngBlCoXGhpotV/gjK1Xrjx+bhCYZMnm+RJM9T5R0LvN6nPDPB+ah/L5L3mpuynxt4\nTnAe+EBixI2CfMQgi3Mdl1KjfQ084N7fbDwQhSXwvXEA37bafDSbuYBCFrzbOYga\nnRplNSQHjPiWWjQMjzl0WIuCqAy0u8t1gokBHAQQAQgABgUCWCjv6QAKCRABFQpl\nW72BAlMCB/9VrmooiboSZiDwS2A0ik9ImbVQoVoDVGWehEUGSiF3spDFcKvFnOpP\nKr1oFb+IB1E9gsv/EW628uSL2c3lDBvcBoxCa7GzFs/zEgNG/ddLg/Qu7mT8ZqWG\nQD5UcxldXdB4P+lliAE04eas5C1wRZ39Oou0Uk6x90NkilPproN4oFMaiRj/sFRF\nCVj5L7f4r83bXIS+ooNOTbEXSBIgFFnMex0MX+8/dimIFbeDY0b41QGdeYgUsYLb\nsUOHUBe0hk2Nb3Qb5dQCLVOzi07eawqmVS5XvVsjNw7gwZnSaox/KiL4eetPrGxP\ngQBpjBDJ8nHpeAZSrffrCamY4Dg7ORxMiQEcBBABCAAGBQJYRQwiAAoJEBZQX7ST\n05Z9304H/0SHndrVnGgQUIsrF6VHaX+Aaq4dwVWEhq+S7NDQIAco2tdEx+1qUrp8\nVqDFppH6QO2dsepOJivxXLBEm++6Choy9VhqAy6dfgkkw6nNjP/SLySVt1NUKv6m\nY1q5uKczkRTBJTXbAQo1doZPJklsoJWtklWYwDkCVq0AMQr0fWAE5wH2G3B+ON8L\nSgjcSB6fVCGomFJi1t6yThchwDoByx+jKKsEukeP3nJ2scZZ6gCtORDWaGJkYH7q\n6aR1Yld0xB9KDCyM57nId1ruqq9gruEfWNsemTWjTpUTu9QNd0+yF+BSqT2pGZiU\nSx1MkmOLKwIdgZUFPI9iBIGCfsyOCaqJARwEEAEIAAYFAliB5u8ACgkQYetqaVZW\nutRCMggAoqrk/5/1i3PaZWTpPGtA+65o59eMxCz7Th8ss0LwkgDCvtmfemq7ShOn\nh1VXDMCbybcAwDqtVKMg1C/am3YMlVmwTLxcXwSpxDI9siP9mGb5pEBgmc7vOA/0\n4Djg4HCvB76J91HBj/fPvwwXU3hGWQGN9CjdW2Wk5J205FknIM8l3biLxd6HBtxF\nRcQ6wzRn91hLe0PT3vEqttMNUfuMxG+wwn33R6s/X5VWmVa+67jFGON5l9IMonNC\nEyUZSO84GJ8JpWwlNVTOw/44yD6Ej8TAEudP44C7fgUeEEmkxzcAVO+Hbo0IO8Ww\nxRel4qb+vX3l+IpGK8suOa4b5Yh1NYkBHAQQAQgABgUCWLsz2wAKCRAHBDBue5t8\nXPShCACHITFHbaola9eoo2+0up+mzSo2b38GfnXQUJ8AS5iwxui8ahd5zArrCoQx\nnya/mOiOvgMFWSVisyQMiayvJUtg6qH7u48woVmqkgDcZq2EHHs1QnqDXrK9TUV+\nTz/vEsjT51fJHecgyQEbIqGsekUgtlECMIogPga8FICQpF7pFWjx2fgnIujPkk+P\nrcqZENDZsyyih+hDR7X/cWjr4dN37exXwAWS9Ge7FhlvIuydG1QCmw+Gu2Jb5Fag\nrJK4IghfWUrfekrNVLPw68DvmwSBacelHB2M/KCwh8eP4SdSiFejmHDDnkbzKNr4\nruso4p0OGiKh0GCPsMROQZUo2pEGiQEcBBABCAAGBQJYwvUIAAoJECWkaE37Rwvu\nKmsH/jsqGnbh3a255VGPH/s72LfkJ93OYoH7JZLTDafxpECpEF2TYKdaFVnIrHXz\nV04UKVyuNHeRlF3mvw1+ZrxhYcpWvh6x/pBGI7L14NVH2HYVCRLhkM2u5h/TzMNp\nGVbEjvaTlvCM+McOIQzH7tRltDo28W0fP1rAa4mOv7Osq2PcDHaTrJ+g/lOpKFQp\n3uEv4GVL7Mi1F16+HqzadEs7aHauj/6a5t93QUYhYICYWrwzjXuXIK84G7LTLiKi\nDs4vwOlwbQqbeE5/k+qh87PogCrbqzftozONeakPDf8xLQYEgR5i21riOfGxNKQ+\nTMZZNKW/WtRHLccbAhgsGFNyytaJARwEEAEIAAYFAlj8OfsACgkQGMujHt3lFldd\njAf/ecv3tOkjaua0Mwk8iQ+FEJhsHEiINeIIqPF46us1bszyvcIHpuzETzXGVC29\nP8Noc6empB4R4jqvoi9sceE9Lv+X32hHveCN7iGsML9V6uRKQyzm32sDW3xM7Hed\nQXu70W7NEd+wrXBL8lpnnAJwyIeUIeo1g47hHENo53QE+9Vy4frENexqU3ukjvWF\n9OQMyW7etF0BM/QytC+4qe9kmgxkHEf5sry27IqgufrULy6Ie1fQC0/wzgMTVFOt\na5TsD0Aur3w9xZkvm69TFkFz2X9GeXsGQv5iuqBC0sJ2vV9B+AkgavFszlE6YfED\nSewbMXOPSLBba7RlF/mRz/0POIkBHAQQAQgABgUCWQPYbgAKCRDRHg0nTp0kyHJM\nB/97x44lq6n1nMrnfgzDEK00IksCUvD/tIgsJGgQZJG7DgUjZ2fSjYylQHwIzCPz\n9MHuqNl/H1MvbDuNp96lIEn6zJ5q8Z+HLEHjWch/yzdDiYcbdnL3y2ifGozB9KTQ\nUSRRwQxC7Tr5BC3G2dNR/xmD+fEHaKZIpkNAcannPjTboub7jsrZSXThtKdbkMiw\n0a5XTt8JVwFlMHxYtix8s6CsqPADgXUqerraJRNjvaiZ/JBJCD4mcBwzZyyTe2RR\nmMOj/iUda/VsWrGPNVUGlzTQHTh+InEKyA7FKFKvYeiADVXBaL47meJapCEjyq8g\n/KD1GVYaHlRLzQaWSyArWzUEiQEcBBABCAAGBQJZTKdKAAoJED02/IRpRG4F8XUI\nAI7bRK70TUk6QtgSAgJBQLXHvmpFMAWf38KKNzbGjZDXu+q0fe5WmQ5klO3Qr+8Q\nW+xRNL+ATScNgHtUZ3Ke7JYQ7MuiaF9+mbUE3yqkGb7ROBAc/A6lUVF7lSVHT/XY\nI1jxQSiVo4ZhwCkjxtUbIktS0+o/iHesI+kUzbywFNx3n4KlCDBrtQkAIhttpm/b\niUADtD50OY15V4zklPxcyMUxfbsmZVanD0gbCktDvPnr3u+XbkyjI2A8y4Z7MKJJ\npbTofxAvcmgShuiNVuNmxyoLTKJRPCMplwbaUK/umVMrv+v7cHCUFv8TAEmWZP00\ntU9D0AIVATtTEQAPQtsDKCuJARwEEAEIAAYFAlmJTPkACgkQW25sF6M8yg/qpQgA\n0D2PIrFjmsgRfb8p6UcFHu3LWhnQVcBIzBa11AxA0RQfdkByNm9v1n4lqHc3rH9O\nco9vZ3vtWUVbJFyrB6ZVQeq2t6OnbV5AzwJagn5OxKJvLUzp7H68ihcXs6YX1D0r\njDfQpQBWHEZWUwMpMuSMio1OihZ9o2JliZAbOer5itO1kH7YpyJWA+fIzcMLKIgK\n6s0Ou32xKh957TW2E9/PV+LxO/RkEoAVN5zttRD6ACv8La7X9OLbFU70dfhm0iF6\nf3TwVbK/cBrHBSWyPvqk/e+z9NmMR/ILNiAJQ1HDeVwJwaHy/MQ4J3P+80rohHcl\nDv/Ob15UHcXnHzNhQg0TPokBHAQQAQoABgUCVguZuwAKCRAts2JDzzixYP/2CACC\nJwxWfzk+sEpJIrqYpP3yhAmRAUarz3mGqHTIMPLEiUs39BfW9hN5l94/1Gvmf49Q\ne7hvlA5og8rhaDUMc7Ev5BOOcprfT4hdfOoalygvzkCZPNlH/w8XNYfXt9E2KZ8D\nP2guCjyfEc4N7mGCMZ057d8qkTRZqD5ygYqyOTzv3x2sX01Afd7To80qCZglJ3Sz\nKBxphvHYVcM53GsklkYt2PadZ/1gYqAaqor1W+VJHNBTeLZ7fxNpXmJQ0FdtQCl4\n3+LPQYhh+RKn4yNb1zvDCCKYCnn0lUOe48RiuX4kMzicr9zlPMm8tCQWymBE6iSo\nF5zm5CVOVuQYMbTgPflyiQEcBBABCgAGBQJXaErpAAoJELS/sQzEE82YGGMH/28u\nXhSZwR7l4YI/yqt4Gwd4pQg6sQyPT/hrCQKEhULpYIRwlLaRJ2cAmaYgQRGwTHmO\nE4gMs4X7LLmOKYjUapBSh+fBfnJNfil0dShIvYgwQCd50bEz5XBqYVrmWspqbtA9\nxpeA0oa+qH0CHCsXJIFOil2NZceli03xoJtlQqA0Z1LrHqKWN0i/xq028QVRqrmZ\nNK9eiHGI5h6LHXmXjFJkUWZa/kNtJQjQLUoi3jeKSdf3c6Q0oO4m753yb2Th9oU2\nGQ0HOzwTAlS15gdEGhA9vC2Pr4OdAmNmMb4l+tvbmFleYj2jV4H6qbyw8RBbMQER\nEtwbpov5HvvbetrMGgeJARwEEAEKAAYFAlgrgoUACgkQir9zMNfsQCiAtAgAl4Aw\nFZqRf1LaUGKstyVqfMEtiwi2AvWv57Y8ZnNJvHofrqrAi1dNSXC96QgPswH5ZmNE\nmNk52dMUlhnklYzXYcChi/iQCES2+5WcAVudDXrajjtoPRwkqbHuZde3LASxgGqN\nleli4roieuAq6V0O84K9JBEjV+PsydTTusfZfOgKKOfeWso15plRai/UVdyMoNPf\nkLbei1S+N7zqBazrFfz+xdapHnlTI2MqEJhPvJ4EaXtpqR0H1sV33sIbbI6zH+GQ\nISzfNjf1ppmjXfZJlJKZYKQH1hBi2durXN5qULsik+Mv/+6QsR/VqiTANPUSBm6B\ne8dWg44MF1V7BFq1DIkBHAQQAQoABgUCWftblgAKCRDyYJ4P5zRz0C73B/4qlDKy\ncDpg3RTbww8Q8Qp5sbgquUCi6bWcboknZ92v15A722OeSvl3XQDEg4WOf6bDrV18\ndp88xMctHW5I88QnGjUITs5exHaMphtqEhnF0y7OxpDUmFpnAHGdRNJBjpN+ksv4\naOdOcAPV8/JbPTLCjJuNZMFMbN5pwZeFqEVkHCh5tpW+IhSUiOoo7cpSxjaOhawy\n5lHHwvujTV1RHjwABzcLakGVeswYJEHpikO8t8ax3XHMoSKNL5MBa9kBnnw5ePki\nUfuuNLxe11GCPjwlabknzbxpzV/V8GhfOSyvgvdliIHOub2Z4eW4LPIkIAYH8LRg\nuDdKac7IPLfUZDzNiQEcBBABCgAGBQJaI1M8AAoJEOdr4GuipsukFfIH/iidFSeJ\nN3gx1nYE4i3BvFqmSIa4zg6a48kxmmzDSj5mgNccqwGODthDlM2Zjzmtv06Pukvi\nC02s0HjbzAxtCHowuvTL/Ksd2Lnh1kIUOqlUgT9ZHkNmkCECMc4CxX8IXCRlgpP5\n9Hkrh5LpjkDFUuCVfzZMThBAFcPn63Ng8/Ln4fKJ6PUIko6m/HxwepRnXIE1UPTw\n+P/nnTtrrdAYmtR4iH8DaqTH/k0451IelyggnOwr9PUEMxI5BSUKd6dGpIuEWWmN\nygTaws3hnuoW/elGrgaXIBAzYFKKEExB2WH6rHUQeixS9J+gqVDeGJARZFrO0O1D\nhzCDY2bewHzqmRSJARwEEAEKAAYFAlp81KAACgkQsTsPr7t0ug/+PQf/UQPEtKbe\nGUQh2noopB3QC2ixL1rk9HyxLIV3iECBGWDnmYHV9lhd+KKZm9ufDhTs+ZWJRBKb\nn0gzFeUXbiiXowoFOaCd0SVOr/WRThVvw9/uBWr+PbmAjWC4cWRJCeg37F1DoVRO\nuhngDrxgFbXqlZMxcDBmK7kaFjhxtP/wJ377CwU7BmzQKmBuF7N9LoU3sWgNU4K9\nSG0akVcMeWckOiV0lue8mDxYegq7bbkaYWpKBMnqHSkwhwoipGyeOWRKfNQNz7QE\nSZfoAeXorvN/71LZ7quEGeVCBZT/7jGDfvs+X4l3/T9h3XK0aUtr++BRGwH3Qtwk\n6cmJRAhNUNEaP4kBIAQQAQIACgUCVmvepQMFATwACgkQprLysGe07OpJ+Qf+JWGZ\nuPMxH+GqH8XEbSH+wow+cAXgi2KLBzwBXD759R16uvfhPxCBp7LA01GOonLEql9H\nRayKu8z6kCbacyWY12PNlftIjSMvUS0YQfThogM2QCr7P+oGM5JrEa3oYrhot7a3\nYElKB9aodneYsdY1vxNZgH30/ACuF/hdoobYn5CpctkoUCRfh0NkbfGimMCmaUgS\nghXJ/J7i+06rKQP+EHFFa96siRyv1BOy6/AmK5dt5dJsU56NrBKz5KmicBt7blsv\nFgUd91gQg9xKTWDbBmZGlSvicoEhA6AWNYTeqHTnip/3K47/W4A7+DKX/Y346zIs\nRmzkYon22MMWOC8liIkBMwQQAQgAHRYhBCPPrTqbfGjyjd9aLmuwuptwyx3dBQJa\nCdtUAAoJEGuwuptwyx3dVLMIAMcs/5MI9BWOOuMrFJkjQmRYpMJPMSBrKzN5FCPv\nQfhH9Cq97aikxrdB0JurPOWjTQRIvcKhpGOaIhyJGSZa4ya3o0SP2nG+YtqpidKf\n70EkL8z9GSnDhvtLAOVLbS9gGTVEwGocIQ5eT2vLqr33QXAN9dzjEUFebQHv04Xc\n/z/HrfO1g1WnFFGsHMh0ckeJCaSBgd8o6by63MKWiI0Ggbd3ZKh8txEZcPJePp5X\nH+WRM+M4XQ0plkepFff9diYmokKs8gN0l7SvAgOPXdp9DL8jzbskBADM9tZeHgCP\nrgJwwk48iqQ4z6P8m0vMf81j800JSF0OIlOzMAMeg9eWMzOJATMEEAEIAB0WIQQw\nY1NT3QMj8uSFwkjz8iffTP+GPAUCWnwsPAAKCRDz8iffTP+GPI/aB/9CXsNb014r\nVGFluwF4eeeqyJOnMHFWGN7Zv+jw/bN09IZsaclfPyKNlwCFiOzOvahdpYnmnz2c\nhy/PconQZioqtFzUcudv+TzzoYdi6Y/kldFbIZZpUUtfhT4KXAxbsaRaMcgVevFN\nRFZ6zBX2iDVIBQRDIpyQsDUmg5nQbfcTZx9zzdCl6QtUl/iiGyLcEaRx7hSrIV/F\n8ymHM6vl3an70QURItbzQdp9hhSwOLqcvLshzaoXgse5AGyjkF7z0DOZl0DjSVyp\njM7u5/c+eiGnVH5zm8+hzIjPVaYyyx7mdoH9aB/AkyxKjpnrCsNPIX5YFewX3nq4\nCWVhZoAPty9fiQEzBBABCAAdFiEEaBrzbYtAxPjAfxrnpB7HMp/goA8FAlpPjD4A\nCgkQpB7HMp/goA9QjQf/Sj7WFDlgYZIqOvP0SOyEswtDvUdV1ZIj6tNlZkLa5rPI\nCM+mJ5D411O8kzmeK6iWyNUz44jVhI1G5q08VgaXHT0uLStUYxXhJ0SLPnf5D6/4\n/Dch/cr/3/7Z4FyizVydBJPfV9RMDvN8/wCisgftmyyb02NFrVKUxeg4YeR/bjL2\nZlVvohG2pySWk70cHN9Pjs9gSD+Qt0SBzvRYM9WB0YHvhuzVEFaoUU0OL+aT/3AD\nbfa3iK5BEYVpwSJIIluLW0RjFRyMGy/tWp116OFoAIi1lmy/gHQAZ+UbeQntdj5Y\nkTioAPy43gQ0OFPibKUGQtY/YwWk03mu7K/zT6Iv64kBMwQQAQgAHRYhBIc7N7R0\ns6XGcUKmh7eiS6Il3/uLBQJaTMFpAAoJELeiS6Il3/uLD3AH/3ooXxY3yiC5DtIE\nEC2spHYcJsf30IGLZ9+iTHR5LFHj5JqhXoE4n6rlhC8lCOSj1WiWgenCkbova8O6\nZ9Ne37wI1LaFR8OZMWNmi+z1OCeqdJ6rpqa5/Y57Q/UM00RWGGj52ropFnBqxJch\nvWbQWxHQAmtmZlHv5b72YaGoAADKR2QEg6tIBQ10AM9QrnY9EnOBEksiSJKBewdy\nXzc7RwSi4A+JkVDz/PSI5LvCn2rqY6lkzk5NBgWcvau5MgVegjuoU4sZVAd3f5Gg\n7Mh9nVpA6a2/crBrx8YCXrMp83s3vLZ+s7OJxlQt4pskf4OEuF3cuo7pDLZmJFTF\nKzpTGkmJATMEEAEIAB0WIQSHlN5EYN4uRvqmCrCt2bekmwyDbgUCWhsh2wAKCRCt\n2bekmwyDboWuB/4r0qrycj/YJgC7OqWbS3a8DQ4K6NLwRPGlAdQaDkt4a/xNqnCy\nVaYuM3QM5Kxw1OhEY37q80d+0C0Fsy1co4Xfm1Gp1jZ5VG+wtK4B8EIeBgpC8Jd5\n+rOrtqRwiWfBpT4ebA+gFFxkkyHxHfb2FyeZA+Jsu69ZzZci8V7YfV/knde5+Lz1\ntTW+8mAd/2HOyqhfe1QwZh6vHh18qBcMelOTm3cBord4Zfe7QVsADPycqlfwV6cF\nlQoAluigl1LxsK4qKIk2XO4WzlS28M8pZ5yQcUnf2b7DP7P5WVoOWhJqfPyF/LO7\noEg3Tf0LoYPOt4Ps7D9Ucks/uOhAGg4IGqOmiQEzBBABCAAdFiEEjV7wDXsBRe+k\n+P9H6qJ3QkUHC3gFAloh4x4ACgkQ6qJ3QkUHC3hb7AgAmE3fh0GC+h7opgQN4tO/\nRwRnliT6ofLXPeAKC+2FXLbVWi/HaR6p2Xu/AlxJwhr1rMWZgERwh/bd+Pr5bYc4\nHQDIGv5Ph0xs1vnyUldhXwNVLutCOiLDe5VWkiJ/ZWwzoS2bnSFn9i5Kb+ryRw2E\ncwDXvnELp0kFlvkX9HQ5pc+im0mAT9Jf+trAwzLYUdOZ/IDWsM7L/KhP3wzu66cY\nFPh5Zn9SMKnymhAiDQbsUZ3Ae5SC1ZHVUlIcnzGPP3JwsISwpqd41OhCw6/GUyZH\nq/SyffORgPyvoBuN1a/b05qyAWE9hh/laFh4MvTFuut9Oe2QN+e6/1lznR3ltrIc\nFokBMwQQAQgAHRYhBKNO0mLrfdITCAwo5dSBgbReGiyQBQJaZwb/AAoJENSBgbRe\nGiyQgpYH/1Rfar35A9DNPcDm1tZ2VzWHFQL87IMtDYp8M53KKmTxppqFH3+8suo5\nQlyd+4niSq8E9QfgNVLaYyPuEyLDqU0lh6/HGThkNyfz1wxQh30GR+5qNlWsJI1u\n7iq9aJVcAweaPa9/55HWQicvhQqTkoGp1YLiXITA/qyHweq8j7g6N1dO+1XnIK99\nUDje3+GIPxwVO8qvfRBEKxZ5d9F90/AOgd+KSv7Wns0ut/T4cMvntDYwh2ftIo92\ntNdmSQ/U//84tUn5fBGycZHbGtt876OYqdTHrj8dwtJJhyx8gBVHzEA+nyc1lqQJ\nqFtzevhgtAHtYc4RorgtS2cwxigkp5CJATMEEAEIAB0WIQS1TeUUEuWHr44SueQa\nZNL3opd5sgUCWl/LWwAKCRAaZNL3opd5sszfB/9lq0Olt5vUm/mW7+N8HoBFKeO+\nCWUL/gA0B0iGL1Qxta5bsrC6PGq6XdOTnvxpIsBaz/H4K4BMl4YZKJGNOFEQrGFG\n7CVDYk0Rl66AhXN+tXx1Q3Dey+IAnB8nO3KPoVBr4cc62AXQrSRS48hHYF7qIKHY\nBiDDq7flBM/6mzwESkVnmcU3b0/qqQB7mhb9QJmaVfvccT932LXnyJCGcuG8ordV\nPHQ09W4cF2GMMdMnmjPqfhtj3+BlZfDu9sbX/d3MI0aAhFlqh64jl0quznjmM0PY\nK+WJP9zc07OLWpov/ysGJBe5B6UsvDjdDELwCtwX/YMyuL2lipOH/BPLAJgciQEz\nBBABCAAdFiEEwvGGrN8JPjrhpzfkzbRyCF5nXfgFAlp80vsACgkQzbRyCF5nXfiK\npwgAvUBTZk9L79BS9Qa5wmUu3mrAk2mdqXilxP48lixrRRXbMWwDoPVdJ5Qxr/ld\nBP2ABfyt3umdlNLp1mxrlb2YmRGnWvO2vL/ZTofhUPeXkfEdz82WywXR7Zy1Syib\neYa01/Esam/BGOzee/8iTsC1tGX/K0FhhKobepSHHt/i0+MMOM4bOtcpJxqw6MUX\n4IKycd3gGs+NpGarMfl/ih6oMzoI3LsL7MN9Lg7yv7ea9wOKgnS4NEBgcRoRYP97\nsVefashBUwyFtlmU9nTde4S/J+/dpG6WV3tZlrW/dNdg9cm0Mn/nIqKp1KvnkdZ/\nuOwu6L+wJ3wEvzjQCyitHPLRF4kBnAQQAQIABgUCVZRrpAAKCRBeWmshHQAymBM4\nDACr3N/DgNpdp4dkfh/WJHV0mddRn6TVfKvGBgeBVLCQCMJ7VSfiOgWDsJ5EIA7B\nECwyluJKJ/7XexG0TV1Mr3vqAMnAAk6eOjJOezugRPiqUnVNgQIYCaTd6aArcSdP\nevLVJZViJaiE5hoCXYeWZGteKt2uMFTy/vFqBzc2L0kUkRPy5HQKmk4P50Mvs1uN\ndmuxJ7HqeBE+PiN2XmUjflknJ+uojz6+UqLD/JN5KoFw14QLWSBbTLQFWVbRJ0Rj\nci5JV+tNDzqfoW01z6sCfN7gtIOn36vX1qOBQDuTWIMYAftTC8s1W175ehr8aKd9\nuyt3zk6Nf43NI8sTVy57aj331vIZfBdTFVSkvlxC6qZU5wu99XZPMVNMoJEg4dl0\nMUiM1hj9hwjpbvBM581E+u0dk58EHR0o9PgE91IygVRl7BghvTvPFZKAht143X24\nLg+VzDAJ/LHEf/M7g2KIKqbx+1WZh1EmDh/rot5uTsu5QuEn/z7DNgzao4giGI6l\nH0yJAZwEEAEKAAYFAln1jcIACgkQv9MWSXfStIBi/QwAzL9AWJsYPkpfhzRaHT3I\nAJez1emADHyn1cfXafO6KdpzgqZARZKkBpagbwCnl1ve/aNT/Chcct8GdimAP7BP\nkGMNdqKbQ0YlewhaRimQFeXQQiiI+G1L/F2qYRS5kJ8V/cramZTztO8u9SO4C3m9\nYEroTfhjbUKnxiFyI6SuT/t6B2RRY/PwJ6SYN2oCoOEWtVMWBKymYNdld+ZckpnF\nFi2c+Vlxqnj/nAn80zp4n83kAeNcZizxrsfEtyczeY97GBdf5lCWKGpkDGFqysqV\n5ANIFGzN1C0BVt/9YOEVmIWuKf7/lmzogBGqhUu8Y2aCINIYJoexWga6TjNeuJj4\nkgt7GSW0kGjIYuB1e2F8hwC5QJKjf9LMjKdgUa+04mH3wPzm0OdFHkANK1bG5097\nxkzN/XCLQQJOBvXBlKq0aByay+yo7pKyy/aX9rnUWSaLKdoXgcVbobrI7IoNkTfc\nMd8qjPsfIyWqNcf09REDkmdtpoWgL4nJG1+r0ohufA6ViQGcBBABCgAGBQJaB6E7\nAAoJEEs4ZvMpLu6ZWDEL/26OH34ojwR71dmqCQa0tX6kCjiYCkvlfkm9lAfa/G6X\nV/dvOr5E8LVo+9Blrk6oow8TkUqc8k3FEo5xXXI7UttwD2WMgqKuaWRFahiVEtsO\nR11I3tw4SawGe5gp87WHsm/VIr0yLlQfhuuB1QdauMCbqGD6cWl917tQDXyroBIj\nhuichVLHKNglUuGtm4LymFOJxtrJWixOFJ6k7HYUi7A6dloxp8piO3Q1QN0OYd7J\nqeMtyDVmjzCdSZ0VKKGxF09xA3F7ltpnX16jvCOXOEnQDWceUzHf7Aef5q5KD8rT\n1CAsylnRqyS30dxuJJeHHBE0zFHoKW6o+4wkL0KjiNU0TzmL8nzj5Q65aWvrkGWR\nySfY2zTiTxb3lTsUMSeO/RPg7L7qR9sAh7hdkz+0wR9fWiLqFho5I1AwpQzvH5JM\n51zlnlp6rjfFlxoThnirrmxg4JiyIRC1lQoV9yVmXlUpMEP4rZj0NSY1A0wyBert\nxnw1Any0+PduY99gyDZSWYkBswQQAQgAHRYhBGdymO2JaZ9mRABlvz3HNb6KYz9R\nBQJaoC3zAAoJED3HNb6KYz9RGpML/0nnbNrRSpS6xHqJMlu2CMBXxtOrC7HvRTV9\nC0NXjaK7wHqb/sbs4jup/Lb4w74mfk4JyX/YSISJy5fMzoH6cFtp288UMM6bsD0t\nAQMkap7eRwJNW/2Q3J8xbBsmccf6Zcd2dp6942AdPpuMeZwYEiIQJJt5LSGlrTJh\noVT4cW7uHO6p+p5FQSzBjsJdegntRq/7RPMJOzJJ0gAV7cpoF3RqwxhiGKY7kDTp\nU77sqBFnefRMTMYTYsPt/Qr1Ev28EocgxA2M8dmZUnAJ2M0AHV6lK+M+t6jxGfIy\nKqFG7axbotUaWyRfvVSzUxoHMg7MZFtji8Rz+kRobe3UEqIEhp4zQAYFm5Zv0Dko\nu529dXkBntiET+rGuPIeGbgQYA2QRZiUmEl0bKVu7hVphmnuMHvgAy6yOVD+isxS\nhkvvVm6vyP7lrYh6oKtMu4/+fLEsT9/++/f0n6XMHdttJyZ4Dtad03KAuFVE/kWh\nCtw87dq3SB65PbYXS6aJbJCHrO6sMYkCHAQQAQIABgUCVO8k+wAKCRAgZwAbG2eK\nY+7sD/9RpeGLnzMD/HtT37WSMBTB7KLDOf4Agph91yLSm49JB7eg1eVXzMrnqGH/\nL6aj+1epB32QaaJ329p2iWfdt3wSR0N5eAys+npG7RhKbTuqW/Kkl2Fbj3FN4vMo\nEVfP+jqM8sH+Y4OQneOQGBpoCnTSN4Ea/3h0qfP4xxVMzAkea3PjTq02kd1xaA3f\nOTly6IzvwCq3auSqkG8JjmHfUx7Bik5plf3voNFhwGfH9OD4i/eznOaqFAcnhjsE\n73HfWFwoaLd6vJ+oyRhJQSs7Hhk5F8cOImq1HBhCml+u4XPNiKt/jys1vdKqoFMl\nDncSMP4s5ABB29Yqz7dDgDxwmVzpO32hOqDdETk+tH14zmk6CV73kHPUHb5DifUW\nfbrY1jjyqPYi2Cv8vyhiiHnBWqW+acJ+7TmCUp763CuU0nAsdghJXUuPAaqJN/am\n9YWT1+WgSYekR8shK3B3wPwbChk41CrXOLD8nUVWydG+QJRGjMYM5bop1Yj2C1lv\nL/xYSDgpUPnPXuO0qFPjHaXyOK19mBwrEITUhrgGVqbKH/PoZCrtvbMuntWXLSLO\n6+elLd/tN2XQy97P4hObKoyCFbx+sSMp/LrrPxHSQ4H6TeN3sPHF/Ukrj7YWNILK\n49lijQEPsIlLvGz5kgEhFTh8eLMap3lfV5rhXlAvDsFlzFa3e4kCHAQQAQIABgUC\nVPJvegAKCRCvI7NJlch35avUD/9O/fF8kSDATJSTMtQBHCKr4Om7J9nU99VgBTGq\npMDvUhlItOadL9jJBdIAJzPHfl2RcivlKpsmzmiI2rTUABxUKAOW+hJzokj9lTRe\n01o5nfW7UGTCBPdnKkUwgGseZI3SLT2TcipVX2ajYrsujELhuhS4gRdJz7qw2d2V\nppnMVzC4Wi0VBXSNvaogeF2aI/QTZgjDNAYCnsRUz6nGyQupRNxxK5cPHdj2mmst\nZuRprvj3Szsec65KgEZwNL8PGNj+OUhzy7mIglkaSaoVBT/+oyORx92k5Yjf2/3l\nwb84pJvnSY4M3BIJvRognz0V+G2jxMCR+oxUAGQaVe/SAnsVaDHDZUS7XMNNFfGM\n6zpm/jhYivVmqaYXPjeCOmB6ANJBR5K3rC2m5eLOL/PrkT3lwLP0AfZMsYGUsEW5\nGawagDcjYoc1wxKEoqrp4F+/24Ybrlnb5B2yk7mFIHfBbKcsOhFm9i0pm70h1qxU\noTleDl6pIiJcT3wOdDQygK43exwMwsW4jRvpJCC2WpEYuDnW0+q0YA75OBTLe+Fo\nnOwFZJrJilbqJRo8zJgln2M+mxq/IMx1Ot4RSYbXtr+kZRBvdFF0xcHEuDXjbUz7\nXkoyRSSDP8rU4BiN5Sej++5GvYDye+BWHHEf3bf2vYbtZlUt06dTfMosxytdTP9N\nlbZMq4kCHAQQAQIABgUCVQbRAwAKCRAktkLfWX7QlfDLEACaf4WKcLzcc+PMmdXX\n8cCs1WOO+VFGxORoKqK67uebGQRJflU0wQbTjGUs46PoiM4gyg0b6nHUpIzLSCSr\nhS1JgAKiZRaxuUH90TS1BtBLSWxuh4KvKOY/p8xdLBSpPT2y2MB3PwSMRJepRPub\nmLRq5UmaLIVmOsOOcGyji1/2taO8aaXuS0af1KhJ1Viup8ci84kaxRheY1RibZLX\njYG7RhAMuEcqSaogx47lRovw+Gcj9uTlsl0KVra1AkzMpbBc1uRcMdR5dV1hcF7U\n8W8E4yDUV9js2wnmFl7KQ4Reu3PijLY/mXFdrZSidKjiKW7RmzEZsnDaDUJ1YPiT\nD+DQL4J3ELC/Cg/KuYA94KUzBfTEWbnEduPF2MkKsS4zIW6SyVtVp8m37Rg40I/g\nfDdZh8Pn97VM7eLReH/UXh/iyj2Btb0cLmURQQi1rACQqyCD3XkH2q9WXX+SqkVU\npYJp/gnUg1H4RxDcRwEI7AjvCnFNOzNxLAwKTki12cQf0UUfgLg6tYE5Yha0xZDA\nfk8lSbLwYPj3h5aPtZSfKFdkYDKdwgvjKZf4slB6/5GdTPgeq36mJ936VmZXivnm\nS7svRx6OtLANJFzR2PINfjV+V2l68q4KuDzZDwbOLOdEXbt31cveMjzkrn1fFx5d\n1EsOem6zvZFBpvm3/oSWMwyjK4kCHAQQAQIABgUCVR7AQwAKCRCDgslcKQI9+aaz\nD/9V4itwpI1I3hwcCzZ1gILAElplequgxm/YVx2IyyMyJEWNybt8CMdv8mVZDpM8\ni2gOZNMGYeS3CGAn8CEXRMkc288BmDnlO4HOYzid1VLsa6knHFiVP23cbDyQ69sZ\niVcTgvaX852j7nomxfnMiPGLlZg3V2m9jxLSvV611HVzDg9eUE4qd6ef5lTcm345\niZhL/vjGxCoA8as2ZX8LDLsQzRfb1L035RIw+dtJV/xjDftKapZARpCk/jMs92Ls\nVu+gugoKIhSaDaiFWSU+7imFg/KZZrnrGmUejq+XnFQSKhe7BBUja5N7xy/vB5r2\n+c3o6hdwpdx0rRyDxi/q2i4pkVVSgXpFzbjbq4BV7bU5qmSHbK13NC45+CWtsL9z\nSBOGjdDokrMRGbc6U1/6WKEVYrVMjjmgGl0CfWB8Wll6iR6H6yUmg8rxy7VV8Vcg\nFZUEFXpaLPwagrYRJU88xjulqIeU3FSzMAZj8g+Th9KaZLkc2U8yyELQfc4eYsj9\noy9j0PRxPr2JP1o3j3NFgZCgqrSNk7DdJymtxabpI2uSgrsbBxv6co221TkVPmL+\nGWAoC+vTp/G0PtYNGPV6U6x/CGyr7JIZ1/f+xZviOoyeM4e0pcN4sA3DCsJmUkFc\n4d4gSmVbLPTiFFWecNxlpVN7FytrFcecFDqGNYt/mKAiT4kCHAQQAQIABgUCVTLm\n1QAKCRB+3kLbaVG0+puXD/9xgKuNUrlsDlnSUMZL/9mbKzTmzCPhMA+dl6Qndnqi\nrRlCt/EuB/3hrCj/o4X0mikbKga40qeCfSw/7SqNNi0hXetr/OYFQXMNHv9sOXn8\nNHWCzgH1exF5y7vchtgSm7nFcW6U9tcnI3WiAGMktR82mXn7jqR3qTQT+GzEWbz/\nsTZolecsVnS/zz5qVQ4oUAXVjOltKbuat0+lbXupCQD75o7jearBaG5osC3CvIhE\nugBoUrnBjDf7evSHDVx2m75qlbEKQtTOarEgPUJ8GS+Qg/6/L34d+vvxG296bvPE\nRIrHfvU4rZaAwCfWZQ5PlEqxoVG/v0vMaCM26MpFjFQj6sQCkLjfywjdRKbm+UFC\npXG4qRT/06GhhFVAz1YjpMmd/8aGU8W7MxWqSiQpyRgVZKjXQSbejJ2/oJ1rXMwh\npSEY7XEn/ieUq6s1O7iPBKNsb2M9zjW37Z/hD+1AVm41GWBmePHh0UKQw0+SaBI3\nWgUVP9f/ErRv+BbFVCdGHzrIrILkq39ORaEXrdoL+OPrzjrFrJe6WSV/D5j0K4Pm\nlsbvlS/rRnjqhSKhXlSbIt8Y5QNrbHgkK95JbmGCfzq9zcO2zmgwwkXbx6XBldxr\nTAG2JtMZw1mGoBKKqMHMHzafOK+/8oaNF9LDSsfbFeAA7+DHVtzjuji1TZxvshNV\nzYkCHAQQAQIABgUCVhd7vgAKCRBO/U/cP0bUHnbtEAC3MEuEIRqthj8LDuG2JgDx\nd8lbmbxgWCPb8zbWTx9WJRQIlUmNZAyXcctG2zAyx3ngj/U3yWoHrlIaOS9RBUS/\n7iYoaB73qejhxvTbgx68ihseIfmCPflZvFvsICSkbGlIyvEEpXZVB7AheGFAgyyJ\namz68l+nXkGAMUxTc7Ffw8YHwrDNkhtTQ/rT62VLWlODq06q1hNvdGGicPXtwCOk\ngjwukNIn4nPuozPW/ZYCqJtvyc7T+9nuSm/FPAidYI23Nos6HQv1fYpn5ENOBtAz\nN3xLmv0jpXGlziVzRVeV/zhMaWkKPo/3dL1kF4gwfmRHfwy39LsvbPcnGfLMwpJz\nC9dfFoxknCLlC4APH2uRoXjli8kJwzL+LHvrnDSI4h4vjSbkqb5/tUSbMXrXV3KO\nrnADVwqeVXiiLey+YAvRRXZeKx/Hih9NIQQkLSzR21SaS/3q0t5BVQbFvfjZSN3P\nCp1qb7/naRy69gno4WYaVXKtrsF5B8Z4mORLu6mdU7aZcMMbrTgq3BMp6JawOLz2\nj0xxTbVScpfrke57MR3/UB1nFvsCAcx3twYHrOi/z6ABlqL+uzkiYRmVcHXm8Cx0\nw21LS8ZaqdBOjz7fKYhPBlZAWRiog1HFkcAux1gfSpyWpOeDPY4W25GcTr1PRS6t\nvjpyFkf+49z+Q2uNy/bqD4kCHAQQAQIABgUCVhy6ggAKCRCUW6rOjgkqjWq9D/4z\n37dp+/esWKh/FVUpcVVyc1SGYLOfj4pziPPo6u+qVrcH0wgtQCfs2MHCREPbRsP3\nZu+UzS6glzEg2dq57dmKFPRqy0NxaKqG6dIi5kNEHIMLggPy6ocvlzs6FE+uqtTa\nzl3jkcKhR3nowE3n5JNBQkRIALsREjISaFn8xRYGJoKLc8pKdlxid3roc5bSH+Ql\nFIa6zwSAE9apQ/N6jsojzGbUl36UYhhqQhU2XY2lY3K/7apbFr1CVYBOWyEvbKto\nsRNIeFpDeWBTsABbXo4oVhSl4P/2CDh6FwdgIAip9pq9NDlg5MKEuzLgRD3fS2yQ\nhE2geDCG7jP1uhs1YlyuCcO3MboJAqK2ZE/Q7i7qAcxr05+K7WMrfAGzoxqO9JzO\n9m8E27a0+9BUdPqYDs1/k3LWwPnv5OxI3IDsZTNzvY6TsKRMgi46CMePdFhhISY9\nkhAWkNfodFrjPf2lzBIsTuxF9nsynJDGnVz2GnhyavcG4qipXoVwdFszRXZjO+xG\nImLd0CvogmuMQOmCgS8PasH51R4tJDtO+7zViwdsuYKKRdBz6sTRXaL3qLbFLrsj\nYxtuh9lfu2Ri/CMyDDM7YccDPzqyhoMY6nGSVc51tWk8awKLPoIHtLIDVK+DBHUf\nF4875HEtT6HE+6EACS4tzL1OhMpscCUWzLZ9HhneM4kCHAQQAQIABgUCVvp4JAAK\nCRD76jEQqFN4lHLLD/9XwbSdXH7zaTW2GTKddOW9hi5nkBhaF5w46NFzlskj9qWj\nsuEl9huujeWgKerfOWiRNgfMAPAPv1WaBeGBtBKo6nGvGh8WjITU6qcwExwfODJU\nkOW60eal4hD4n7A/ndnC3F/YHzWM2hQqrE5mIKuWtrTKy4fPtcLUViYkeTjOZyFi\nXLmdZMBC2ME4dlo4FfyPqDhhFqkSNs0Xz45UWQ6NnmuEeMXB5hWNfSGOOkG2iLWE\nyRQgCO3O2WzKVLP8yy8aSzHYBw7dX78lpTpUcC6Ex3EcWt0xB3QHW4lHCx9U7OUK\nLhQbb1p0NwpT7/KH0RP0eBbKuby1NdiX7VUZq6cUJ7jwuP+lsbZoSsHvesBVUkwu\nyY57Zt/jJx7fa5VP9MCxA2VlzbNd3ENDo7aB7+JKdGVBiruDRQXEHs9D/KIaOnqd\niJGMxhqTNsZoGE1I15Kj1wx5RccbeEAoAQkQw1c2wZqaTXCsbVAFnCQ80yC1vDe4\nEK+O5gPcg9ZkDgmjEORAj4lVws8jRD30GVTAG+3tQh2FrDl62ASSnrFOG621HFcU\n5Ev17PXaevP6yt3Wl2Ev8OO+oKuhRT5V87qLnv39TnUIxHy8NJk+BELalCt56Jqk\nJD6slhfYKv0t04HtwDSSwBhfvpPdjm8GItxeM3sEDH+Qw94JLEjYsZTnkpFhZIkC\nHAQQAQIABgUCV4Lo/QAKCRCE45JqzjoIq/AeD/9ctmIWVh88Isdp4S0XrCHdo+9n\nDbDqXydO0BHXGw1dsqJSucrrQ7qK05MvHTcQv6vR/jdKxiZ0fISdNzW0pLvvLgcQ\n63HSVBb8LhoThO+MLx7rDY2mZJONmYtAwSq8B8NO1KkbMeehJsgzxawsr417pVkz\nKoP2HjXq2kEsSBcL2/7YFTeDxpnOrfuUa0bDwlBQKH7kaX9pcLWfVQapgFXHzX6/\nnOE02fpBD/dGlHv6HQUHDVMaaY9XO2nt2GrQ6euVjehbtN/mky0zev0drCC/8kNt\nP3u5J3UkNBYblXc1zfQkLDV8Lg9qfiqXcOCnH6K4ZTV/6OMyLZ+Al6yR+sVME1lE\ndLG+Y+QbgUWXvQ/ZN/egm+TXW3r/CH4TyfkVGNGD1zze4VzFjOr7ARjLRu7VO4iw\nXJHp0Svk58VHrecTOcCANZDVHy0ZTIIjyNYKovy2uc5RH6aC7hu8+N2m2+YPmL4L\n77gi+D7LW0ATX4Zt9CsXj2ykDISjDegeu4IZkMz2KTk2966U4o5sCzVmGwu/QBpO\nF+53H++gyNA/OaSqwgbWXTaZYAFx+1PU95ZHInDBysH9TwJxjGCNylZRYOUFEMrp\nqQCNHP9FCXm8cdX0pYZXcV+FuAsZQc8/Z0ts5NB97hIp72NI4Pkx4yOQngBTUzcQ\n6qbrp1rwpzuv6xW+GYkCHAQQAQIABgUCV8SbmQAKCRCHRRjtp1gifCutD/9yhXK5\nkwGevq8T1Rm6xFbtKefjMG0Gw6NIs9114XnbzqbJ7t98sNx/fr3mUrkQ3M7OtnOW\n8W2iaHffwYXccbXIT5dL90Uc11ripnMcFe1zdSt0yZuIi9QI2/fPfjMejMXrBZFx\ne3+7AzVVB+OQJz8LB0DrjCalPuNJ+FnQtc/5ZTjMrxyswbzOGgq7BIAclrorcKPp\nScPd2klZdoi+ipcE7jedeZFzT5YdiM7XKZpBqh3i4X/cjdcS8xBeLkxbv+4C4toC\ncBQ4Vqnf2oGVqqt5hVrTFRs1pHmlMW5RIXhn9wjK2PhLJ62LsiBnlXPHgKlElpXk\npS/zNIC2mEHaM3DYqUva+4uD3IyIye0tlXpcnHkdOPYFhNlPdBR/Op8BwUt+Dj/+\novbFbCFH94OEJKqWGryoNWG1s6igxVZYf/zfBMsgnljM6uaRgNk5bIn95xroHOjz\n8/xsnzhi3QQpjXYAuMg63c4DHv+Gxhb9Effzvneh/5ws4iaZ+K/CvlCsNVWtf3nz\nr5V0xOmZp72wrDY3+//Cdx6AtFYVETZqgHL8gALDBHBHRExyWkHFrACstHN4PZt9\nSVk2k0evsVjGJzFdpEf4awscLvg9Id0HpWaa3pnZvF+wOVJbB4XZ3bwXQKWhJQIM\n9wqNsZFqejd9Cnu1P2Rxo15OefqCwt2qxnP7T4kCHAQQAQIABgUCWVpd7AAKCRA/\nzls0ET1LS4W1D/4iIqFq0Xgi4s+gg94erema9Pn63DEEeFkZ8qBfIRug5jGcZkCl\nwGj6I+Pm3pOlU98zpejek1pWBs/VtWodYldGQRl2kIKeustbVeJ2RKjRBZSnwmaZ\nWX4TvhhC8DkDgK3CyUUfEuOQmPL0QGks5SyS2qamU+/rcPB9tJRGUzycx2F528j5\nKvjo27UKmJVt+zpGhzx97DXU/dzPj3IHVYH1v4FuGClGsw8AV/xQ7OCCi/p4uCt+\nSeDTcY7gYlcGqRzFEgAtDt2NQeIVIc/jOR0q4/Cu/hsATU1+EPSxmp1m+hJFeXBA\nNsmdzjWNDlIFwZhx5ugCsV+rzLfLlqTshaHYEHriWmt0iPyLtxttOCno6EMkz2K7\nispysXm3LSsqIG4UP23K3+wcLmmo6XanOgMxoatFgKma7rgz6QYCkUfa4lKvMGZn\nZ7OixqDx+X/hnhpg4Dlg6dkX3qLagp4lqX0HKd5/yVQ2Pdxu0/v3fE6+QjCKmdcA\nPpy+G25MjJlm0jMEA8c031JiPWb8IitXL+i9I0lbPNB6aWfdVUCm2oUW8SSTqTzj\nk1rLDjPpVd9Ei/HJlVFXW+qrvI7DMXBXKA5EP1FfzlbFyT4mKmDli0ryUuTazFec\n2RyQvMZBMLVbGTU4ggjNQ2TphS5Pq9BSgd8idKtUmEQ4GECIpxATm4B0Y4kCHAQQ\nAQIABgUCWc5azAAKCRBnMAIaMCen97xUD/9BjLcGLyiiGpAXrpeB+Hwu/wKSmLF6\nqpgViAFXW2xTylKBks4An/rE93H6tSAgR2UC4nMe+FwOR42UMNWf/tIzH0hwt4oz\nqT1thH8g6Y7Ow1h189fhRxWVXFDwZ+7zFsCGNLYj8Q12xBDMg9u0ODttmr101poL\neitFqTn5VcY6MJjDoLD/pCPErvYQjkJ93BzTfE53PShsC/FUxKRYdAU+HF+zuGDM\nFcfXL/fR8dJWkvMZjPpZmcxTks+WNrZnXU2hBs/YFIDVqFbC+EnggQ/nn3SSDpKR\niA/e6rjFoh7htdGopyrUvsSWxgofMNorYuZWBaXu7WgsnlZi1ul9iVKBWr+tyaYd\nYHV/E55wMdACuvgcyJ6YaJRaOKRGd9MhDvrhkK2+RJSCX/WNUv77OQOJdXU4WFj1\nLzJBpMzYh4gByvIaYDiWGLueXwH8+oIs3rLWhtti5qcWbzrCX5s2x9PEkjEUe6KZ\nqafM8CcR4UaUS5XiZNwt0VWcGCJ9R1V7+SfAqvuJGDVRjoprjfnxiZuweEJVBlvy\nLAtM+/bNy/7V8rQldfrpWd+GhhEdDZMVKJOvOZCJiZwfGA9Cp/Luq3oUwpDJaCNT\nRQb034cPCv3lCFVyzlr9rOF2JoBjq30/KEhucWO7tyQhLR+3vmM9nXTX6PXmLePh\n6gbzq5y/kf1Vm4kCHAQQAQIABgUCWoe37AAKCRCYQjjO/PmpjW+xEADBA091+rsP\nhApFLzggSVjlwHBLBg/XfSK7eAdRsVmrhPNYXY6kxG3ifjZBe4JPa2HgP8qQVWLM\nue06GqOUce4I39ApS6tT0zQH+m7jbd/++6/0JMgiMNSfZmyf+DfRLKbdbtoXztp2\nKBat43ep6vkvbYP1paNCVqc52tALOIbOAnm9ndQS2I8ekh88zM1gZUH2eJGQ1ZOw\nJjbfQCAdBP7YE4NetyYUZ0IK8vs0hwinW+IMK9EUjjeDheLxPjSzQWQMS8jjwf3H\njJshmszFk37XW8Htcdg36/Jg8BeUtxjaa1V1mH4OtQWymzcYgvSRwiKBmB1LVEJK\nmEsL0t2CEzZSgU0wGXczGz7jT2ZenamHO9RvwVrJC9/Kxwtst4way9l7VyYHvpmf\n83NvKQP3RSpjp3Oh/ZHkwXbcC43v1D7w0OTjR8YTGLpuTBdMjzGjExuMeejbxmqz\nslgx9rNaKtvJGLyrwSxRNP7eYt4M8J8ByH7YpPA6s3TdkOam4vwilQgnJXlG4G1e\na+dkO5RTAv4oU/wbNFv3cFI1O976U+bZXAX0e1FfqLTdr2UX7Rhh8C/F4ec7qY3y\ncX0LIPnHmLrv5HqxdIF81lrtrwyav/6zPeZEtus1uF0jwH7HlyEuEywQee0IrNHF\nG3wSgJmh/11JHngrVAQZ9lV4k6pAkDrn9okCHAQQAQgABgUCVPqkeQAKCRAS4khz\nkGZT3UgiD/9AlWJtmRGMTvpoAsRjrkE9/iMEJnZt7vqXP//DzNtd8BskA5bEO8zj\nu0rTMeDBCS5miGHrt6jOsg3TT+ZkE4Ko9irBvAZvyJozaECryAL39RqCN9iY/MSm\nMI8jvtHE7yhfEABhn+z9H2+1sFoPev8Gv/zxILJbpS8QSKm/fz0TDQBBhEFZqAYS\nRQn+zGLoqZ/SEVg6ZBUzIbnjWUY1KpTYkpVuDG+h0REG9JOr6xaAFRdrjgCNGHaV\n1kvJL97EoaZ+QOot3f/D1gPnYvbI+SgzUz9uaInpPNk+kWrCS+j7WbuVkqfBeiAQ\nNW7iSBWKP8t72rMHkmjEJXOWrrnPGAoBoXI9wTwZQhAguAKEda+axULN6PiHfOKF\nPRyivwZV4qBX2xDn3aa8KFG22wzCFe4VAA+mtuc+Og1z0mfyvB+LokOeWyed8vhF\nP9NjM3CYaqchANqsLokTyCD5kyr6A5Ux5nxZ9wMzPL/AdMEascgEGv9vzIo9q/1h\nhDskx+DuFc5qJWbwMobEi4RrG1sX+p0mL4W83lKezREZMrJi/pNqF+wuI9aRARgE\n8ionxVFmgxoX5q1u2ZzGrOp5GkwThKbljc+CCqFEmR2Mr3SbLyw8d8fgshZTLC1F\nQctLnCglZoAtQgXyef7vWldbNmWl+wKov61dq36hHFNucHK280Ye3IkCHAQQAQgA\nBgUCVSXaigAKCRDncnxWKMKjAMelD/45FzQUUCdAZw5fVceMQvBl2XuMWY+J60dM\nrRZcU3bqs9sTlsrgSomZV69UWq3xhzgqetS+9L+1ZJHUMS5D87hmPItwmv3QIvsA\nAS7ulvzvdmfa7zGDh4kyjYXVQ0XD2XiETm5fNpigsvWaLRKwhjbzP3ncmjX6o6h4\nLxGhrlLPgAtQW1KhymR3ZcDW7hkxYDfTgY6euGbnyhpemLt2TycqN8BWt879ZySY\n73aUv/5iAi5LEEoSBM5aoxssTYk9SkWc/riXEcttoW7RK4+Jqnwbho3QJymdBb6V\njVBZAliUuOT8naxSuQKrvPbIwphFPRDy/MVPhMiouST8VzECGJ4VjXFMMhAYpW5r\nKrqPYOy/XaeG2eXfx9ah523It5KJpD1t310gaQhh/P8J+HxR/WAK1MoPkaxf6s94\nEDzxHeWojxgPfeYuzTWaHrjcAf1ti4BGAdSQRIFsGXisyI01sfZMiB8qSiL0tqGU\nqJg5R0aGX5VJSSC5IJ1RHbO8cQSzPLV3sesed38/WhvUmAMhdlSoBmHLqfTJgIpD\now+YNje1OY3tZYgqml8RX4ZqQZd0RUVb6XUV+BWblOIasfkX6qVsYxu1ZPknGyoO\nRHBLr92dzcsqerIqudQYyBuZDopjEgBN5nvzhyOxBGDmBBbHZqgVUr4bQI+3MEui\n8kTikbJUvokCHAQQAQgABgUCVSmRBwAKCRAhT0cMjkseKB5BEACka2CnCvGichof\ntMv/fJbyePHcg0nGVz9W38FhsrgY2obz0fYDgcCNpWwW8Zb3QApnYXBCImKchVGo\n1l4jz1p6sxE6MU7E6jBm7NeulMIVdcXwoYXQfsFzXQliKx+4SwhJGvcVOHfgAWBl\nRJE6scPXzn1bACGyduf3xT5bogVgEd32VPAgUZRePWmkZ0BR+e8jA9HKEJORo8s8\ndcwlaJhA0Bc9ounZlSayBS7tHAxlqY4MLdAfU4islnil9L4UE2LbSeeP76XkOxSX\nGWWaif0A8UicVFV5eRAM7mGJjRCeDaD3bjoBV0n0NETtGxkZqH/H4R5Y9f8s3BFW\n/HuUXwm7eM3+tW+yx7TU1P1GPQ8oEDgTToiZLNoXAperT4q4K5MRlwQDKpH8t3Mv\nrnecZwz2efTNCpyu8mBMZfMvl13akkPexJWiOUWJhZWEQBm/o5iac2rwTQxbwHOG\nAJdV+rokAfTuDHk79QNW0+T5itM/73RtZKYMBtAcgLS42Ah/BeXnl/8OGL1jQQ5I\nJxjvthHCRdumEnPL0n9ioGfziYBtfSuwitudC2js168osoUNu4yqcsF96pPjTN7S\nVs+FXBW36HJA3BU8fXbqQDUAjfVkbgOEIRtgwAZNDehl5zuqzqF93zDB3Urs9xtm\nvsu36oeh4dqZwBTwjNwobEM4y3xmSYkCHAQQAQgABgUCVXhhtAAKCRBoQETiEcWg\nqAH2D/9/JxPv2D9iFCLJePL28cXV8o2SUHXtwjv0umZfAb6aTOKWHMGZQkQRQEzz\n1oYZEX2BDJWj2Sc7hOqSfZbcXBZK0kSmxaYpGelL+w3fRp6/iKQ7CHgKHVSrJgot\neRBvbRdTnaUO48U3kRPvUVBHsgCrkerj8mbiOCQdmNDeTKijl7R+muYla3SDh54c\niaF74pIuGMG0xs/l9wFJ6H6AiGrHc6RCJ9Cq1Nll0FNcs3Po4F/V5uYYhatnWHCf\n500KvLuxm3PLC5+JR+q3m8QGQQPvSSPa7Z7kurAGbTOC7Py+lQ8PdgtGBnk7acSl\nQEbkCE6WYFPoi3EULVvFAXEQuMjfOOUtUrUqYp//TdrgaPWc8yAnJZT+NIjjh1D8\n59TTm+ku0drtes+dXkuf6wRohV/HOnGZmao8fPNy9kuHMCCBbzgh80bCCBRtsWbE\nir/E5x7hl132ASAVoKZ3dRE0nuzVXGf3URbx6G0h60QC0GYBvkBUwIDG9XLOqwv1\nFoOUA1n1YDiS7kuc9X5JRROoZH+etjSnH/DoSAqb5DTSoUqlaiA9yPFzyoc/BfOx\nOorXHJSE7laYi2+IuXB5CEpk6Qi0aDN9pEkpPEGtlSEVpHJLMM/HAYk8PGihbjsP\nySRApjmhXd8px60x2KJBxPxHT2ipOErWbx1UYsod3sQ2pMdNnYkCHAQQAQgABgUC\nVZ0/hwAKCRCAznx+DKrUk8jaD/9mwwS2kr3ovVcqkZ2UMS9r+m1Jgbkova8/kReK\nm3gnRpXP68we/1/TPylsnXgNfBIToVLCNx/Fh7rvSiIvSazhdQ5wfnvfiC24Zza5\nLIzQSjRqX9rZtnsOCMQOFzaY6ugq6BM1IKja3BxfiMTyiY/vxy4yHKK266+VJV6p\n6RdGZh1zMrHCllNZaaaX6hRsMgDT40RMiExPifhfzlpegkIebTtanE1TMnmKeOQU\nTEElOtnoppD20BvjJDETZzvKFkClc/AmZeyEk7oHSPQijGU255H9SYjXiugqsPCf\nWOeiuezyMdJ7381ZmvYcuUCt9Y/JRzj/8ViNygCuHrZwrN8thCkZFogZy/4m81L/\nTWWCqJl6eUHjhHfVkDSftO1+xb2apeyvoRoFvBm1L4E5nt6hDpixLVBu3lbNcHqK\ncGpNFcftFkjEnIB5Cxs+yq+wc+x9uyx1tB6zlp9PdvK6WLeznj0zHmV2W3YzMaJj\n6PLomn8DMCq6JXYI8uM9PEDWBL+ApdYbLgIMJgHDcL6FFzlKcEbbOFOgXE7NHku9\np54UWt3cJLifML0Lwgjb3E/hYbvqN5ciIFmXplo4rDvMyKwjHfFkgm+tGqTeMBAd\ntDydj3827QAp13mIcrHcgeg3Juffn+vawdlNmqogjANmM7KTItB96CYvmiQxAjXq\no76qhYkCHAQQAQgABgUCVbDOBQAKCRC5joAqtchS0cHCD/9ELaZYy7EEkFrfhfR/\ns39u+G60/VA3BgUL1fVtfIiV6HvajxHhAWjnAoReVv9J/S0qfVeaX5RDhLuD4WlW\n0IhG3abBz46hhkGlDLUQuGVXMfvu0Rfvau850DVSivEOw6AYDHInEYsG6IB8Ebta\nAND3gC04E6d7FdDFDmnNlPcrp2mCle79k7tNsoNsJHUgpmaAkOMfSf/oBupSZsal\nYeK6r5U0n7nXlVxF8solb9YF9/qVVFtvXKxRiRBC1SAw8TtlVtJOPK47v6Ts7r9s\n5CELy1WF2z2iWbUjzHrSMJHmY0jsIFxylluz8neNn8bgyqy2/AATfW7Jd5P2W693\n1vpaGDoMGG6tM/gExXzoxZq0N/GVxVjQtNfaT3e9HKfx0RfXJ70Ad4YQkoVvzLan\nGlgCMC4/OWlVEPjhHQC++A2t9XkCnyiBwDosj7d+0vW1gWbdY772dMvCVTGyV4Qa\nFgNtcHnOnMaWQaL7Ceh3kaN9HT2SszqZ2bRjdXiXXaD9IiSpAZSBBHZWSf+R33Vm\nwhUkE/3Vet0lFkvllDtnmgWj4Vxp8OI/1HPdaN3gjgm+6bg7s2gSKU40H0ic9L+6\n8MXsne88yT1+Nt/scaadKYEgrRIbcetySweR6d4bnhZz06OeTTvVQ4IjRmP0rgWV\nz6wTtJNRE1MY6l9qECR/wzDViYkCHAQQAQgABgUCVbWo6gAKCRAp4Eebmcijl+qD\nEACJVXm+fEPVsV350zCS+hg5pqIeqrOnFxK6aGt6IT+U+M6SZ/4bHL7X9bbUhUB6\nKGDS6p8sruIqjxOBQULQqrnLmFTOPiQPFt/ejR8tR9gDHvkiufYLoZS6g4Wz2QF9\nhtGq8GIqFPJiBM4CYKQ75Skp/jU7a3DSynHMYQE7kwA0XH7hEZQYHrPsYReqCjEP\n9T85TblI9XRv0agfroyP+XFaOjINzUSO8OG237ka1TvJS1X3AiySOJhcOtgMA4NK\nta5Q80UOnZMeNpAmP2j9HyKJ/jnVyw/pX7rE9KiqxOGxafBZvaroDe8fxEEJh6t+\npONGI6SYiRF09SelFE+aXE9EgR5mqdzS5Em13EeNeQidDlK3I0yT2B0ETo7DDhx9\nT+fP+jcx/QVUK5DZEtsurElt+jrgGNtNR0ma9JGT+oW+p8uTargPSlSi56VtxLnS\n0IySIs/UscllxfOpPAKHF81avy2K2UXoAwUJLw3mnzXLvzOdssDtRFPhrysnzfLU\nCHTZ8LzFmZNaziqVfVdrQckNhjjhSlDkZ/YYBaKTUeVJ6v+F65b2YkJ4cfqbQhCp\nO7EWpdmUpHDUxXcDdAsGA2UvksARLHkyqfAZv0TghjeVlDpsjl7EP+DFjk8UXWef\naa+MrvW9zHZE0vXvHQBKLMo8IJ3wl/CwgytKxEBecjke/4kCHAQQAQgABgUCVcHC\n1gAKCRDHtbXsnnODof6mEACijtjWmPzeuuhk1noB3nMk8IqH11nsonaUQpWyXCqU\nwIQ0Jj2Ro+Z6yx54CvwtgkPRg48XBPtjpoJ2XKUdDpvawm15qZu1w2A9I+3tMLmm\nB3g16AQ53kAg1qJ56T1Zc62awQHRqXb5nSpUDgE5/HMnAoRIoRG7LCLXNs+G2xSk\n2M22YRx3doU1JdTGjxm8FZQUcrpvmmFtboid2x2HlqrHQX5YmQmre8OaqX/gCWqM\nJkH02OdI9wh1i/9lmKXH2IEHvQcdILTzBYrH0t9jiqGZVJ05qghZrkjHj9imnpfc\nCqWLpGDi/kCgemfrE+C7CjJffWM+9Z7GnK1D4XWZGWDS7WmhyLHN0PcNjdOfjlaQ\nd8TWucgRB8MoWGXjDRkhik7A9GLElN023/pZIrPzv8ZeQt+x97suN9lJXPWH7KE5\nnkWxbj/3tyV2I+ZnYYIrH/COKoLwHNel0XJu8MBgFRZQ6fF1azBAVINOqI3xC4OA\n0nshevinyyHkS5Xf48Eqe16mk3rI/yqNDn7vrhg9n98g+y5IBGh2K3ofz5F6sngY\nwlV+porFkJXLVNTw7CnLSEmRdRMolmVOtbwjIEgLYk+wtem4f5tJ+WtnpSTueyYY\n3pyuDW1UtED+Yt1orZWd7YFSCpj+o68fNZ/QL8jsqLkuKPevDTlwwHCvNoJzymwl\nFYkCHAQQAQgABgUCVcHFuwAKCRDHtbXsnnODoVswEACl4MrjZ38xiS/a/UjpADFm\n7P/PDJ7FCJfJ0DoIyDuScRQUYr7JcisngGDu26YqT/tzKtRDvzrBul2YNRxnAtCp\nqB05UbG+J4awOfLbzTrOOZlIY4eYsAZWu4Vn4mtX2evS1bKtbHYuVdEKisr/wz29\nHwLizkuSaV1PlILgKKJw3QLUyWUvkJ/xdGT35nIIqDLxxrO//D6hT5/l26zCIra9\nSp/gsUwgJUVGuQRGjzursyg/s71I5yxaZqTpuuyTVMmdGsP/NS8a4gQ+J1r670ng\n3fWK484JcnKHMgm9jwKPCNVfOoTJ9vzyCdNLfaEEfXPSbRB2WOoh6qOWNFeLaNLP\nUmg30M9fYM+16+LTBFQSEafCOTMxXgGNqlzIgUciQYLj07LPISqQd+CqzSi7lkFy\ngVJ/HNOZR+VC1hauAAt6Cxlv5hh1PfwffdpcRyC7ddFRkOYw7Km4+p0koQMrfuDG\nMTm9fNEcsTzP2Rsv1bb0M99JPj/Jnuw7UgTw/CAfDbD5z5qB9Q1QZu6vwD161X4S\ncgrw2ummqGXnSGNunDrHqa9CaioAgNapgLsWq7aIObcnCuvcC0uBG8A9XEdJjxDI\nafu/+xtoRs1pEpboqWYZjUi9ys2Gmj5YQlE3JMv2OeDYSzOKHuVwhvHFiXM1U3sO\n2F5dGyFrG5ASxL8hIcJri4kCHAQQAQgABgUCVdxjsAAKCRCbUU7A78vy7UhTD/0S\nryXVS9AJ8SsyjV0bYgfrXT1/GYL1eUg+aAi1T/ophfQV0uNzk24BkCE4/CzouESO\nzFWXETjnsWeJu362ZscDMqserZvHU1WmjVrXrZjSddYJxY5uObqnSjeJTnNjkmsZ\nZgyIEezbvM0t8LjMKh0Xqb2A2oJry60MQLWI8GhWsb+rvD/N8YjvUJY1fXLSejN0\nQNSZNQkYE4NuEP7wHqlnu58/36VAE+2aRQighxLeGW2jSsY2swqLCjb4UmNASxH6\nrh5cf3MKiPPxEw69sARQERgcOXVzRgXWxL1OEOsPt3Ei1bXUn558Lhc6KYuvk9Zg\npbiWwNG6F/7M8hvJLS5YK7oDKid2JvaBD1u8xbC0FATj+CrlbQ4leY7GMFahHut0\nfPFM4RINCB9Wt6L4+ALZfhVSYEo/ROvu309xEYE8gOX32yKP1k7FJxfTR9Tjcleb\nj5RWPwsYOsOndjqTIeQuz4wNLzYVZx+PC2Y+Rl/iR3/PPa9i+CeRunm8pmoMjgGe\nYbun00zkGqldXYXbu5sftT5AtzhX7Rc6R4D+JGSBnz/cD+nfEdSWQVwOrkunc4dJ\nG9MQN4i5sqcN4K6ngHwMNmwuGoQkE0Rbp8A3tK/d7HwjncYo2qlNgDfLiaaBWIKw\no9ghFXhv3RnKj39gm271xwJyPxPvrTOi9UESjPYsVIkCHAQQAQgABgUCVhAERAAK\nCRDCGFJYGfeEUapsD/47E3WAIkdNQAb18RbIg0cboq6uvz4Pc6aliYa4Ihkh97i0\nNPh4wVm/x4+7FEHSqr3qsYend+dyUzp7OJYw3/kmE3gCNxWVM9WHxPiRdgHM7TPy\nc75/DB9awPXZ1FpJ084EdGKvHdz8DI8u6qYUN9lvt22l+kakmmd4zinsvbAdJXOi\n0kcJYH7QgyEvufQst3ap/IzascbcyuKtQAer5bg3bbBj04ZavGS3EwbusLcoOyjJ\nSv3/aFz2X3BriS85QAxDQ/YLWT5JnBIIiIBdAeeXbTIGBzBUZBm+n57csryczcnE\n8kkXyPy3aIUcDvsFNjJu3L/bdC2pINueaTWZUX/D0dmVwDXvojENwrd586+mFTM5\n4sETWpqEB7iOuER9J0Plz+l0EhHaoi3MwjWVM939byFPxXyMwwlDUbhAt3itGiEX\nKBmX6Y2wUiIYYtZijlNYa5j+unp7iD01xn+8GvwXXSCbrwzCBitm4tV5DsiP3t/5\no0oHk7x55tdSHdcUA9rGMDU+hw65upnQJjF0WPAD+ENhdRvJz39ilanDyhhOlhLS\nD5uFWvHDgTry+ox4O6lYZcTq9IbFsubug7eysEvLi4ZDCPfpirlQ6WEOhleV/844\ndtNZ0RyljqsC3qNlHeFGIMmLXi8qd+4m8rOrMBEkk2SrkyWHv5V2nhrguFt04YkC\nHAQQAQgABgUCVhPy8QAKCRAT2/zQiyI2EeG9EAC0uG+RdmYGtLCyNBmOBWYhX34N\n/WQgRvJe6aWl/CLaYEFUE+82FledloDR55ofvU35sPACU0RODhnL+4rjAe/f2qhV\n3agPIShbaOYPXIgaXZHqwbJS9OykZD8hoN7aL0GsMgumP5kU6664iMcIfsNARRN3\ngdQiEup4AEYbEMgPLfTMBgXZu/mG/F14D6PN9y2AYzhZ4MQVUR772VIXOMyUh+jh\nGwa+NFEK2ClNSfeYunjZZ4uZn8W98SvtDpCykcSrBUyQ0/+qhs4/p8jjaTWfJApn\nCi0R0JLexy2iHMwNyjRH2yI6prHbxdDuMtlXhKP5EK/1Mtui02oIvOVWyXQMQJVK\ny7wtDn/c4YF6P4iJ1WAtiouV5P4oL70gHqfnp6If5/8swsrIGbCZFVArh5JJWSte\neI5iO6M4l0Mjq5r6omqo6WSn7bKj5gMQlXNMQjOqZAlLDWJHCyA3/yEhQbXjG1Km\nHXgDF+B1Gi6o+QwSy5NfGWgKi91Nrmx0m40h1o8i5Q+5ZngYQoBy948TUkYdK2gp\nXeRL0E3FXIrO06rx5pfjSviqJwNo0yqXzKjvKynyOeVa7a4vNdajLKYCyTPl0Ete\nvhXbiBL1WnjqDcDEbeIGE29ly+VB5Yc6ej1UY1EJgAEcnqcxHFNH7hfzUgufjKQH\nd7JiL8IEnbvEpircAIkCHAQQAQgABgUCVtg5hgAKCRBAPCZXzZlPcyIgEAClyh/B\nlglZmQMDZ2RlzxAHnpU/9VhqTL0OQGvTOJHeRLUHWLs3vnZ6RrE5djXzEV9WCQeo\nKQG7qdriwkFKM8NATeX+3/35JAxXWadNYEGoazEiLizxxWuwuMC2kU7NjOyeAHXX\nTgYRbGYHs0fZnFnmajSuCCwIWREVjRDmMKaC9RGKDyzFxog5kvRgwlAZ6tijUMRa\nITIm+Rbp8VXrIfIGcVwVvL0RMBoS6ZYrdXQsucylWsSgvcHJq0ha9wIjt+dU5GMV\nYzWr94ikEurdb3WwGNBKH6ls5n6mysM99BPh814cl5nsbv1wuF8b2qbNFQ7VSgXj\nArE9xhOJhcbwftGzbnHn2UF8OcpXg+GuWJpqEhdu95ZPqPJV0p+BHwT4b0dQb3fN\ntNBTQho0ZQPSD7Eo53i7uQWbqo16Emg4K6hTCwkYGmTR1YFKPRrVTLs95oYUSUAc\nU2VdxAHHWRjnXp77vssRbxDKvOwYtvt9/Wejxy18Uzfz7etHUO9m/eWHi8so4bY+\ntR70WH9mCffW7Xikrq7Xa7zKLONLIhni6WIa3NPXZXj24BKLs+dItKNcEu9lFD0E\naYy9DJLfET9VUO0aQRg1GKKQLNQ0363AVaV3NXNinTZDl7lnzTbLPwBDw1ul/yJj\niBtfuNRdFicH05ankED90y4Gn3m5AMUzhx9pJYkCHAQQAQgABgUCVuyQBAAKCRB8\nMYgMphHn2QHiD/4hu2JH7zjBJtEOIKU72N29CRQfU0vsViUC6Elimt3KUZStpgBa\nQUkgxTPTZenayE1EkjgIls9Kuy97lD5oa6znMEGHc4HscapfPk3kjuURDyPk37qP\nDQATJV69cq21YWpckd/USgywgRxUAmb7C4qso9Sxns4eDrRhWJDRejO0DXMFlIKR\nrcAw2Sr6VgfMoCZNB8RbBTyc78yOUcFzBmogkdBui7gqzLtcHQFGXz7S5ApKFtKp\nzsi2gwNgWG29cuubReuZd86U1DpHwXAg+I6c3TY3fCOSxqEKp2CDU+lSJNtPRYfN\nF5BDKgZ/IXo5h1ivwDTx9SpUznUYR9iVy5+auLo7ebEZbKELJxasLxYhFhvApzN8\nu5IJMEAafnF9hRQRET6AUdQmo/QIPFcq9mU0AWPtn7qs6x1/fY8SRF78g2AOg4QI\nidqz/+NAVsVoeQIYXx2YxGizE1vLZeFdXicBn+EGTxbzjZ2s1i0HKys/v3EA3dqm\nJzm6ph0+vjlOoCnvQrJm/zOXuOLk8j91e29M0GDZG6Uwns/1WEa0VvAFNyxeT6qW\n5fUEUrFQThq4v89dlC7fpz6c1/mloRDc7HZhmoFZAzOj71UuosN5PUGEuZe4yEXB\nbL7JmXlf+szuDuAE1m1yupBWTPkzbEKbmRnwdd2iTlFEhaf0JSIgHCELC4kCHAQQ\nAQgABgUCV4C7ZAAKCRBZcSzK7rVwFZyDEACej+0TVb1icBvs/Wi2AgCMkjg2StWU\nRDE6g8hShWjoY/qRkvngktGJOBJxifr2Kd1W4116sn9MgOYRpwhUlqhuENDAo30p\nWE+goZTviJl3mfp+DPubED/03fJuaIfLEuLtwGAGFMP5yh8R/ifxuVPXE2K6Dtkp\nKxfwidToHLdcG2s5o7osoXxCcuoJE+DUoh8QfjctZUTe+2QM4bh7b7qjB1TeJmwf\neUBec3j7a+b3GQsBnFFsfSf5UVpS2zJnU3yG3k7upoe/9gg+5hxH3uC2Y+1F7cJK\nQFxniOSwyCgZHV0tyVEY9OqUiqS5UyoVYfDLuCMPr6CNItQMIq4sPhOgnlJPqSEW\nUlX4eSdtu7srr2lsA4a2tsOwQzx1vizkm8Maw6coB4JH7fUm7WiSdOgDmG/tySCF\niNv2SayTeaaLtF694EOwRRaJQl18ly5WJcYcCMkgEjXRv+F1QbtaKQv7/3gRZ3gA\n+txCgqqjmm0DHr6DPCO/nxYAs5vtVqb6qFR+j+XnOtmqK9zpOeDYHNRvpVBaiR9L\noqoicXDMhShhBDStp37/67PsFHqjuM+8nnJnjGoDMxrBkDsAYyc78qTjhjGI5VC8\nuQ60XmMI521qH8TN2JF5MaZnJQ9izZTHf/kzB4M2vUVATYyCdSPtMMudbkMC3Vtt\njTbnSH5ZIIiGy4kCHAQQAQgABgUCV8jTXgAKCRDaOr3cF2zvkKe7D/0XLTBN2cd+\niwlqJ3gdy1laf/yKCeN+MbbhO/EaFnqpM+akwyRCQYm2YYONmAcjcvopgdql0ZfO\nzxFwzC3fedEaQG0QmDfAeg9sAkyn86Gp8eAy8lQVo2DdGXERtpEhtumHkmE2zuXT\nRdcJX0B26DIoxpBhvQ3bu7y+JMN0xQ9rpSd80xmVCu/muMw7HAhfdqfxV0fil/C8\n5Gg97kuzd0sWlCi6WlGj63OTmNss23ZnqGUcRpdcNMm20LBjjRNai/iYLWpdj1bL\nPZ9IWSoJvW7hIWxX0iaUX57N8Y1PGz80tulDIQCuX7ATiFq4A8au8kmJRjx1C4hA\nAeGfj3Sep8y9xU8adBU4Vgoq6nidJ4OOdCmm1VAef5cogJekdR0ca4KJE/+ar07L\n3WkOPD+ZWCe+tWIGt+4qYOqBtiUgnXPc472O7Aa0m66o8/4IpFjrOsR1RflPKFXj\nLLsKs1tnLvyEYbqmbfE+0g3KdteJggn8MRA8dyJFgSk23bGVnNTDmTa7S/Ngs8ls\nROXGfaku7XPxAZR7gKkOJQd2PWRAVrygSt7Jdog08rrOwYGIAQaMAg2SVXXdxymS\nxZumgzCjTpQDTSAdIIXqEM7aJL3pTBrP1bDYmt8mvacyXQyFqvnoxYuRoET2kiXn\nxAO3hg6pHrtPcw17Jsgkk0WrQj/sIipW6YkCHAQQAQgABgUCV/UovQAKCRBqoN5q\nqe0Ov2tQEACECE5yQbk3lK58Ugd3sk6YYV2c7oaXYzboOXg09Xol6A/qJQ7EF/Oc\nh0HAla5epbcnHMWS0k7EJQP1BPxtmJqgR5D/dbxgN+YIGYBMGqnAN5ELOupaex4c\n5U4TPbtegs6DB6HVIyIe1oKkM1J4ZiuluQajE2PGGUMR1X/LQbRBhvEUXBFha8l5\nx0YaSqidSExZB1S9WhQ9/jPJI1c01PZQP2oGyUBasKpRgsM+DuMdhKd6vGENoI+o\npa2dcvyA9qAiNXIDkCBqiCrXXvCbsaKc444YxfWDNF3L8gyonxJ0m2nI1w63burU\nttY6HQswfmxJ8m5nS0SIIYs4dHfM7npLMiB5nw1uiH91ZCs6NrH6JCdVxp+zCu2X\nkmW8xE48goev0m0PV5oWAkmehfpV0uB+3L6jLLe4GA8F6woKiJ9wqiyBJoQoY88D\nCijh6Ki45wADzLcgg+s83KpQO5ZaY19k0sUJRHO6jJW/Z2lFgBbXa5zO/6dgbXqR\ncpDYIzT02kGeRSnAhPEAghxyFYjKKaCDLOpxKF9gB3lim5Mbs18b4QHQoFyD/thw\nFCZhoX3VHrZ96JP0pDKSeZE+OOW68gnFsauEmgmEK8csmgUX76f3RegzjQN7tIcH\n5mdmddR2SXUKc+BRyeLvQl/LIfJTVhc2fDDlx9II75/mdfU5AUVtLokCHAQQAQgA\nBgUCV/tCxQAKCRACeCH/exz+xtJPD/4t5N/oVw1SAbpqfGD2cK52pVh9EkkhmRRl\nxkO16TFrLZyST5PuJw7FMBzYwFygv/zncdzJVtln+DXaDWtuir8qXo8Na1mYv7yG\n1oqLHxTIYYfg/MhuxHPntspBL0ntOt82oQ0W74gsjKOar2kMHKqyAfZwGRXTwqUi\nUxbeI9Q7laMorgrKXmnPJLWqa6HePJ2UC6j+mnyvczmPFF6Q037r80+zkld0vJHE\naiams/gSb+pyjFhFF5flZ5avhY+d3QCdIxoK25o7/73anoqAwEc/jAHhG2tY+xgd\nv06oCcPW7ezS6naKPZGd81WQ8BAS8tqN9JzJ6yZAHkEMXfzuqO1VfyVoPm3KAoVT\nx48HPNMX6PgVIQT+XCljeL+YpGqLm8+1a6PxhfIwEllydUAGpHopPkmRZq0d9WSF\nr1Uc+otnijcbSen4fWVEHNdu4xofOKK9f6Sfhr6TGXKzjhA9QIDgyvl2oXj0FyXx\ngv53Q1CV/SwWH6+NiYGqdMrpJl1JAQAtAXMwENN2cLtmC7mDT9FKxfeUviNcuNSv\noK9NRRhdCxHHEVDYSPJqr1JmBLtOfCeGQPh62T6OViXTCGhac6Q92R3xbK1DsiBV\nwbJ0DJ4Ur80JGC1hDURLy9P9FjRB2z1x/+l5GppnWUP/nqP5bfpQ6cBu82TaVzbi\n0h1e0oACF4kCHAQQAQgABgUCWAflrgAKCRCLBM8Ndbt+Nx7ID/9hoxtX9QifaH9x\nAHUOJaTduUS0dsqxHFpRAH0oIJDnLb3iGYoxcYYnq1jieVUY99+6/QNW2ZAfsnhB\nDmWB8G7DyCvX2CJpaL3OTBJ6KV8M5p8tU1FFZKtuCeFImhB7yNEk/ZxUae8s0KDB\nQxr3n7SXDVsa52Hdnoxb/sCjEHN//uSFH6e2BNLJf3jDdZhw/TYzPYN7LyYyaH2Q\nhIhkyDnodUwFxPKtBXmAJWJnhlqchz7uXCICWZeeZ8IsExKqaMEPsS/a/1Ze15j7\n3Ued3vs5cd+F3OVWxZsUa5m1RDf/O66QO2rX6Cd1N1yFaPbu3EBq4kKqTR/cK80S\nEwbDMrg3Zw9ZVzxT+nZ9nIDvHoCQBbpBjc+oCXb18KyTwD6GAmuqPS8lkqMl3gQK\nzoca4f8egh+bKQIzTNs4yc7ZR6f/vQvmBz1s9X9VaM3kQvuh+lAhHkneertbAlxD\na/SL/oDV33HYYjAskNnhpjdWoMkRZdj8t+yBAX/VJ8pErEsI2uYQY5Qz4Wa76pIV\n8Gw5ZEIUKdxZarxhexX4vciRBlHm0DCitFvfd5Z18NZrqODhJeSo136gnD/gw9l+\n6SEytyps634CEzEo+l/9SnJWFAKK3nPx/UMuk68vq59HhE8IE2cwNHECMzC7ZtU3\nFRvbiFyOLB5QoRgpsnzOa11IreKj5okCHAQQAQgABgUCWBSYvAAKCRAQScIEtcIO\n1phrEACRYJwn5T69DJqJebxXKWyMuNTWzfb2FNzuw/5dUHi/AkElAZixANQ4T8aK\nAXSx6GdSIz3AKN4TGi5dxxzmRUJx7OWLgAc4fM9V9r3lrTQpm0fPABr8o+j37bgZ\ni60VtHnjR9uzbrSUsOGpNVcJ+r0aTjX8vN32Flj6OtVuXqdgOOlgsbK74QUtooZi\n/PBwhrhSiGyL7PZyYm01ti4SMr3Hl1DU8Xbdsj3+iJu1F13CvWBQmYbvjUO+QHLL\n0SkH7AjSv1g6DhDwcIbhZvyMNOeYvWJCJZAhVWlSTig+nGOmLrODggQcUb1mQt70\noJkmMeq9xerWKQPkRgKyKx7n1Kwu+5Icm56soBN0Xw0UDcEhGktuLOo+tVzsn1+B\nBC3jSkmqVTHPV3OV9AmkX9EA0yJzDdHW2gV0CsdmjPFDtkOlKoiXf+ubWYzpT9GW\nPnXa4sUzRLxXQZdAu2QV5EiWDGdSzE/Ulus2FvCXg6JDYntiVsGKa5ilsHPEVt7j\n/+EOuuz5OVCnYtkOvpMtXXx4jTeotirLGjxOmRSYZAY5qxnlYa8QfS0xWwBzDP+I\n2GMR/8XdvnrqSeL9bQKOwLGcrI45S/QHLLhF+n9lTqKLGfZs9ZqKWO79MjIJvcwB\nqFGs3I6pIMdEZAmpOI2EZR+e3I1iKiTnATjBI0SmJbuMdEJmiYkCHAQQAQgABgUC\nWESN7QAKCRB0UAo+LxIDfrNuEACh5rveGrgFvbbbdG3rxdWpzkqnrkpFIZVSeZrw\nhGWyohfWS4nHVnwkwowWC9nP2cEJnhtUU2STnPqY6HBHXFvYCePop1MO1JRVnP+6\nVThA5OUlrMh5I1k7gNdEtjfOyZV4WO7TfwIyTJyBjPqRKF8NouJnMctzREQtZFqx\nhwtwemetO4XHuCz5tqAhifmQQMzNlt7nICNyKnCG/2Q8KWJ9MC7rvHHD8Pcf+du8\nCxFRKH/NVaQzniAf4JabRBA5xz5hcQD4HJLajV74EB3IvI/ja7PZssN6UgAdwceq\nz9PYhL0gfk0mrRhbi1cFvMcft3LOVNtdcHSfTE8RGTUGED7LS0HxauFF87F50aQK\ngeZnW72NlvFEAbsJt+GrC+OM7zMfwWkW7iF3xfxSmfiJvb1w09FZD7ZVC3JwwQST\nnNCyXwzMV048IsptX/4C9/75P3qhcM8SIxuhnz/J5HS/XO95ccmovU+Sq+DgynJX\nAVe+UrH/zG+QPBeWTjKrG7ROsVi9QoOYe8tijCdw5xn4F2LssNPDX0f9if8fLBBp\nusxQzhyVigiu5t23Uy8xVjvEVb3Bl+/YkC+6HD4CzqCNMM8CfvSThVYdqiF2htbP\ncnpIkA6utajGS44QIui1eDqitn5FXe4EpHML5YVyy+QjmwQPUFmKxsSBg1KwcVkq\nXKCVeIkCHAQQAQgABgUCWEaArwAKCRDVL+O1fn18VSdOD/9jiZnLQfr/3hFLByOw\nprwziOGjBn6GjXHQiIbyTNN5nOst33NXiT39MZn+pAH34KKSXa3phQgTk5hc2GYQ\n6avOR6znFse++pjZrkeqDDu4SUC4M77A+gkevUaKJ5LdxjK5R1ddFC2hHcl6ZzVf\nYmpq8dNd7GiQALLWB2cINW6N7cEgcr2blFcs1IFk+xYYwBiE2ATDqMHySdnJXjdD\nAX9d0SFbQCRtCTvLnElNTRSXnkc3E5OyQ6B0Tqa9jL5SkjFLUnp40onqzMzk3uKs\nlLwkN9EmT9UlWyX7wBK6PjVHVN/9tQ58vOMusf4ee8eOQUW3eSVh0/oqX6/+vqTN\nh0KA3WuEudxUVKAOFNZaY9K/xWD44RqMxsrpOAfbcdqvpZt0M737/50Lns3lhxVk\nqvYYjMKGfJAwxrAkOTvUJyAzh/53Hb/bOe2+t9D1KiB/6EUwP44ooOAsGzHHO7C9\nNRijlCyPDNDmR9FEKXQ16tNdiAnX4EKVEquRmOeqOnR548MUWs7CixHpEJX9GK4X\n1J1XOh36ImpsC/Vzx34ZdLAZoNe553DDE5DeI9kNHaz9KU+MzEIJrfaRF+9tCeH9\nIi6E8psLN/KJPGGu6FZucGg154YubvpoE3qYDsHx5kKX4B+3oDjLbGwcoS9cUJj4\nK09NzRwB2fLYoN3ZkBoZ2iNbLIkCHAQQAQgABgUCWLbDAQAKCRBiq2wtqTZrTIhc\nD/9qkEt0JAoh5bSg+ySVjKLEK4cSdCqsrq5txvxCcShcyxjn8CdB8sOoJh9PEAWl\njFpbBAj+4gtJgUHCwM1ksls7GM5A2l3+FLUg0drVkgxXSIQAeKM+sav4YQ5gWSbk\nim+lUZx7jsi/XOk3+01+GUmjXvHkwymCm83MijjUmKEjVYRr387rJ5V8SXtJ0/Co\npGM9yKibEpFpzXm+3hc4JJODUsLw/GBg7LfgAPZXYj7tTJ9qryucX1XpWeMXNRbr\nPPUjcZbtaJZQQNnfIJ73xdjpzwduAOdPUzgM6YXz1XnGwf5Xhz0p4NwlsID8YFxP\n52PiU2FfEgt+g73J3xzRaHx8s+/hxqZV28dho89HJee4LuZNJWG6YyBsesmTqRc3\n0aLyXVRhvZSaIEjKmwoIWVw2Ea/adF+ShaTMQR+G2WIoaU1GKjA/4S1aeTKBlklr\n7y0/DWwqAjwWTpFxwY0GE86yXZ3PdxytUqRtuljVM3T0Oizk1u4HEfdJZWmdWyTd\n8uwFX19GozQBbjLSeg0hwxgMFfHgFrXtwwMpXGTGjM0U8wTGiwFlAITwK5VLv6v8\necDPHa7zicepXJPTRnmu07gTvJWikYjzIfpcLN3iMbFv9RehwadFoYW6m0BQBOjl\nCXOBnfzrIUQWkcxNcXVmkg6EvywTU0W1VN2Qf1zQdHACD4kCHAQQAQgABgUCWNaU\n7QAKCRDMBnTgMY+1BMZOD/41foG1V/L7NV7zrcyzsyFWkbMuLQ4G0jkzTm4qXVp2\nomrlpATiYOsyAHpMEMFK3uUWorAu874jwOnXIKe0mEKwYiLNyenwMhzhXda6vyy6\nTz4/uN1R9I7WyUGE1zROWx0K1iM9t4CB/dd5cQTSLMBWaTHIiEBIpTyIh6DCZORZ\nLw/Lp/9cW2DWn1ZJaYlRncvfq3eizSxVj77nMmemwoyekcua0B4d3qKaFJKvi4Mf\n8t+pCX/V10/a8MJOZKRGjgbjjyVkrPH5dBycaRlZxYkF4o/rzv5iL9FBLEG7YbAX\n+FjWJ1dluAaOLk7xLMsZPUqcD+84Od+cPoCYlp3nQ0aY8iydbayU2dazAGrXfVUd\nzRiy9ZsU3uM5Ns6FrFt/KKJSj/ciUi/PPQaTyYzNMI6gOjkYFkn3nsz5UKS4/JMe\na3SfUkmGuV7iNbu2p0p0K2yfXG7i1SIv8RjVwQCMH54HpXlc/z7Pbxq0Q1f2OcRz\nWwKs7SysbpaCRILKpKyItbiWuyQIdCMYu2Y2gjOoTclt5XRxHef1mPWPBm6GzkBQ\nqnQhTZzxWEhC6VVeG7j0R1FEdBhXtgfoCcIc14tnzGdr91ifdqwS0gd8ltuAXkgx\n8XbteuYcTIH6wdBpQ8AmGZ/o1W+9JTXM3A0IFOjrWTHldb/HA3HzYyRmMVLjEpMB\nlIkCHAQQAQgABgUCWPxNUgAKCRClVdQSXJGzAi3vEACGdnvS/VCxYtT3lCG/i/rA\noD6C7sCQ0SQ8sYtlTJZsQPHEIIC0c+x//iCupPdBk47ViY1aK3P3vkDCWWlbnTFn\n0z9UuenyD69IZa88tTG/hAXZxvYEITpLNUq8xxoOQQ28Eo4eG7nO09fJYWD4dcGu\nMQcXOUHt1QatfpMLvR9xbX6N5kh/2aBkpTq1hbYPNa3ASvBH4lZxzTuLlAwqQUtL\nP3HBQlp8RqKxwadujHwgcJq/dbG6/KIq6y1ex7w+slFOBdUtzjIBtRQYJkvOEEOY\nQDt6wJyUDFS4oKFZPAT9/HbkPW/beHUgsOL/avpkp3g4M6OH2QhGyoKAltUNEbkp\noy0/EsFzwVtL+uk87HKopvgHrK8Fa6IcX49DydPzaAtbA8E3m9KBEYdWp2aAr59N\n44pxo3MGatLzXIZfmrLrpPyOxXIOigC2dfz9IxPyuW1Y4o/jrOB3Ugxv/91Imxxk\nnVzPtREy1I58EqHPU+U0Vy1wQ5VhFS5f+PB7AdDCJZQphlIuWs5aDtPubATVTb5M\nh8Sii03U5wKs+Xo6jx6PUsW87wGnBtjaP9ty6lmXmWZk03d23KCXSAO0DsJ/1QGI\nGZ0RHlPEtWeKkCyjYzvxsLpJibRsmSCc//ZG07YAUKlNPE/EWZkj1z+oVSTzNmca\nmeLOYYt3EL66RsFlJSJhf4kCHAQQAQgABgUCWQFNVgAKCRCP8kCZGBzgHtMyD/9e\nynGRSkJCYvVee6GEAEy+VvqwaC6wBsGR3fLZFJoAO9KH4V/lZz1Dxae8z9fTlH51\nPng/Kohdbyx2BJRgsmlCm8YKMWXjyhaKCFh1wWx/pxRDbb+3id08W/qTw/5YUBc3\n92Iy6NKOXDJVJgWzQrS06BYuFH8fYxR5HiPINZrJsnEVD4aBIs9eg0yCyxw+j/RS\n2LdzovosikYVcQ2O1+2waeNcLM3uZePnB/jLbd+TpT2gzXEBLo2W2p6pMfmZywuu\nQnGnUzLJODVvOhJaFG08JrVoyfB0tLfLinKjMMZJEV8bkPB0mtYbS/4CRzAhyElA\ndlR65plZEIAvc+ybUGRfP5q4j777fpoCIENIUE+DahMumCdJmpTUAr2PSNLD72Rj\nj24GjflA/zXTHjgt3zqkJNWsIHij3tcm34sxRA1kN5XiMJyF+53qIYbdZZnAxlh1\nia1pRXA1TLfe5+i3Iz0YxxcLITZN/r+UfQx9Ao9Brj3geNP4dGBqN5mPZZU3CMdx\nzWFW561x65GlJEBkRc0GTTW6b0K7ZCVLNfIwbabRSAB8uCQd399RMFyg9YFzgzdX\n+i6BbHOnIEipM/OnY9l2mF0U+wQMx/EGui0OFOnXeBLzClxzihB8Hdj8QR6UpYeo\nhGaEjmxos0rmzVntzak8IOEaQaM3y00XD63S6E09vokCHAQQAQgABgUCWQU6NwAK\nCRBybGG5kmgdjG06D/9kTpEeZfoeLTZxNXogA9KLlK++A0Wuoqv3exEE8hU1zRq8\nQ+rb6p+LRVwO9voSl+kMbPsgwz+ynlaQGDLd5nxXpDqs49V9QKhdV8aWzAUX3Rb1\nNkMWSP5Pa/CPlw7rtNTMG0qllgydMwEChI0hBVQyLuTzH5Z8ucOygeeHk2y+p0vb\nxakzpa70NsdeVHpzkAoFCGImXA/BPhLYWUdAmBlYnAMUcUU/gDbElEJX6MK97FWX\ne1ZM6mB+qwCBG9e5QrTuhzSaQunVrc5ZMMoitJC5qKVCQNk0GPmdzwYHQDfLWsnd\nnMn/pvqPYx6lebI59dpRoYq446zz7sV1lbDKq+hv3jy58+2I/NyVie8oK7ah3gq7\nA3sZk7HGZXgsf4DmtY5U9ZQrhgdJhliQW3oVrrGvvaGlHlBop83U0y3VsaFu6tVc\nSF2tb62ujym+lOIuS6nTRBPy+oB4q6+3PJ7FoNLtizyth+oak5cmdBfwAiY6DFwQ\nqVPIbo9ryEKMx0qlaJohpkRlgsXBAw03mu4+mCXahMVDKPIMLn/jBrpC2ITze7X8\nCXcJW0QIS2lAFrwV3Lum0JTO77max2rCVuGR6wCiSx0tfH6Rvjzr1LmzbZYvB122\nwDYD98ySylR6ng5CX+ELiUSvUyvCMJGy+93yVJRYj/+AfSSPg1rFWLQw8cGrPIkC\nHAQQAQgABgUCWSnqZQAKCRCvFE5NV2dMcxbaEAC35y1XxZsbwp357/ZXsQHodNQE\nCZK/aIynSKzxrPPyqYfR1WdG0MQ5YPHCLNO+GYNRTWlqPcEdXk/YJUuSYwIv1XVO\nm+i8KxQd3xxfpCvIWBfcDZ5uMWXdDebBrTlqZR+eMAcCxYGDQkUu5xNA4Mx0qCsV\niLRTyDSePYp28IAOp+YROEfRSNa3P75pRq+tthJM4hDWOxHzD0w9k0gWmXNaSoeI\naue6s4xtxNf7jpJkxHzp+eaeqrzKGTZs6WGxQyiLGYNKgFCygRxazJfH4rDQ/cFx\nrokQXiaKdMgfYtD+uDutvofT1eayrmyJWD6Dw4b5fDsAfZcBwEEWBcBl/wjHw8Dg\nc5i4l+8XHwLMM8hRCaJMMIiIckoWsESbpvihOyU8rCOVk8LvdZWGp8ctuoMe+cIo\nwTZ4BPUO5LAHIrDXVSzO9+I1TJ9aCSKhboU6Hu6xG+yQjmvpN0PNTdKV/fLiCXjS\nOAD/VI7Y+cWe4vS6AIhIQoDUwTx1u+CCaaOjLnbp3l/pZi5J4q6OzyV95SnyhXVt\ndYEOEa+5cg65oLOQo65ilxdB8CuEFHac09Zj2w8Fb7fzn5oJqdXTZIH5Nsz4CCK5\nsBLTsyfW6WWGxsXwdRG5AiY7Ms0o9WqczArDv1ssPDVNlQUoWilwLG6Lk9zdqywR\nkAviXXPO6BwLueUAk4kCHAQQAQgABgUCWXaRpQAKCRAnAN7eGG3yjfFvEACgcEJd\n5IbbO8s6WoqmUft60HOMhnUKh0ZeHP0mzsn85QtpYm0zC033z8IPbxKkfzR/WU0C\nYyQF40/0CrjIXcVliK1AOiPextdFi0PZxmhWzpAYmPO0VFxP8h1hZ3uIYbXaAkRK\nhsXipBwaFm1XTNuVibyLZ4APWZcOWa+sTLBrno2HLvXdlDFdE27bzmihnOncB3hT\n1jv/LWM1xAgYXiNc4otMJOwdHW6lXjYLjVptkRKOoZdc4QdCwo+N65tCnxUkCpUL\nGBzEbOvpwFdhg/5jqRB8IwFsbasLQQMKfSP/KPXHyxWT3ZB49f30kW2Yyijzyd++\ndGnwCooED5idDcbDz4U+YjX367XXR8wt81Da20LWYlUmFkOkVVPO/zxouTa/DtFg\noQjpqDfDuBP16EhvrBR1H/utfw0+W//MnyMs+OL17SR4KdvkA/VMLSYXJOS8Ompq\nVEV9tkvuGdgpVz1xyx8AMT7k3fuQu4ZXjsJapR8N0MHjCSJTmt76W42jNZdsk053\nfuZN+Sonx6a/CpGNMEMoSCGPCS5mFOlB7Qc4hdb2UEHLZse6GSbxrtuBymnsvBJf\nwB//tY8ILc7+ycJM/1pDb0Ukr6FgTm1bRSCkuOJGfMRbjuHin7BA4yTcngoLA5Bu\nSmzOkhLfxV1lk/rMUuB3mp723OO+HeFwQIe4ZYkCHAQQAQgABgUCWX2oFQAKCRB/\nvBICJNN1Ltj2D/9abdqRxlpOQrGjTF+/13Vv8tPtrCLqwz/uce2RCd/jRmct2+ct\nmpcBIsmjRxbSoBl9DU5e1i/LF8UcsgtHtiGcobFuKFMsP1mRLNdcY/H0cyyt3yGr\n+i75uDbUq4rSRkmslHmjxqTSxScggELVVVhT3pLAa7x4SN5gwtYTQE7h6xEHt2je\nOBzanG8IR2ORa7gtipfpgtumHjrrly4oUscyW6CS4l4pCWQDomsQ5xNK6y5KFiil\nuWJZfeMmEez9pes5VncsEhAf/1lJnsFfoYRT/42k0AwWqGub9cPh7nKeDMynvMpJ\ng0okkSiWnZsJDyFcQX57v6Qj70N8s677cjm3azx92wvnKuQ1IqK+QlF1uhSsJxsy\nTqH8UOzcvWYVqISTZRmpviil1b0ITZ268h9CnGg9heSva5yTAQfhGA3Xv8nlfpxZ\nJN7ExJiN74VTiBGKw3ZLT0sH25b9KWiKqPGK8pt5SqAPRwRwKvWL1h878Roeqd2s\npHqHElHsamKEBPSTR2rlVSVrOkQQtEJNnlAX8xFsLDJWVB7qBTjJX7crHjAXNlas\nFjXmSHW7u5i2QGKkCiqZnZDvqQlFkd4BQNDTAha6Odg4Tet2a8tImTkZrAPIntZ5\n3VqTRv+2Jn6xhHOfsRWJYPyDapKGSdrGf+kGXOpbXQekfsUnnkKV9WUBN4kCHAQQ\nAQgABgUCWYqIBAAKCRAOk3cJkACVABThD/0VQ0A8W4U2f9W97yNkRM26PVLxTzHn\nDp3rInONn5aA6kst7y6tHkMCuPYrZqJGh3/lP9wADh5qyolbh3tgge29+dRorUnQ\nBWsoUXcGuBPMiJKBn+PqdaD+6BmUkNkleJv6kgB4YDrtj9BqmCQcd0Zz76rr6RFW\n5MaPTKj4TirXhZCdt70on/RQV7Wdqek6C4Utso4XSacS0BXNg3SaUx4tSPAOhh1R\neNx4dP9XhrFa/Csq5sNuMJDvQuGjK/I4Q/xGONULfKZM6oawcsfwG1qNpfjWn7Wp\nm+O2e0zzjJ05foZSvwdYymh2eOvdmMde/LafphFmXIqQ/7qILioZ/SFsAay+azAf\naR02caaGPjzcqP1TE7E0E+t/WyJIbFnnsMABvGVQ2Q1c5eMVQkAFXcqgN82amlls\nXhumXBf7XTWHvJ3+MFPVYbsjKQhI7pZx9o0za4hgKtoWWgayj1AAUqKekUmUHIZI\n/5pb+60+ReKI5FOod4bH2o0aql/XRfo49TXCeQkAzHYLVJ4hS1hmUxshpzDIO6OM\nf7PLzljKrJ54gxtU0sRaIPJvJRCD3iincPqn1t2H3mbixuwqbyT/Qb74HfOCgeKZ\nnsrnvB1guTkRy4GQGnPOE97LwOIF8HsUtByMfytn+dVSxifEcmbqkvk11S55rQPK\nSXOyfHfqKhS2BYkCHAQQAQgABgUCWmxBGgAKCRBGsD0Lbopzha/fEADHa6JESRaK\ndV/NRrEOowvjfDzHh9f7veLciQHDw2KwwygAedZgZJdF2o6mm53eX3724xIKSD4v\nsOhKWrleUt5rUI8sLICe9oRmprnZBVtAZi6lxSu0G/S40GrUIPhK3J2mH0C6D0tI\n4zlfti64sFcAsl2U+e/HNQb0Mf0CmcxUtb+d691q80cHmZzcM5N+hAasfs4l0Pb/\ntwsN72jybBRYkHY3IFP6VTtdQ77PC16xaYTkbyVoNsduCovYtDavjxedZeKX0aRX\nqw9sEj/6o4FvFWzGoHLymdE9ThSIen7Ad4demYnNtnaMXH721n/kNIFVkZtpD8Ar\nnMySMCrvNnbkiPUP6cx8FmUbKV5Qk8iWaua4DLVlKSsophuuwvgyH+SgVl9466vl\nbWR6CAYIfeZzNafj3isVTsuwhYwg4QHlXBvnaUTmy46MwSsFMUEiV9qF0IuoneHF\nxh8gJq/U9/9IXAOwDNCy04B7DK2HvE5cttKYcuwCJUkDs9B/ZqPE2mNWKoy5twyE\nxg8N27tDrlQHykpiHL2rBjYIcib8yG8gMsRyy9eBem9ztbm69iUwjDGaJDVpoKgC\nXLbGYlngaBefW7xPFmKdSQ6eF3ALINDQENVQlF8h2FTb8pMh3GpcsyN8o0b3NjzJ\nolIAqkFwklAqbuYdZNGcjrnKlpE66V3nyYkCHAQQAQgABgUCWmxBRwAKCRBcuS9s\nKD31GiHsD/9QeeON4wpOlxLeV7QN0X3/2Wn+9BOvBpv0kko5shLXpumakQxMb4CX\nLpkvoh+6f3g+zsgXl1/mKbwsxPy3qWKQ1lDEU5uy/zIhr95+vRLV12BtVhLLYzuN\nU/8Vk8ELGNp5vLT7zOcHJuplXtzC1CUJd7jvL1fRDORDnaFG/EAe294cDsTy6Vy9\nlmU52rSHSNNwCvsdvzUecs0eZsFNN8OfYWHoINT3oRseRR1Hm47q8L1QK2hTN3r9\n2YqcflN3bEKOaC3YeYiMwKuJhkdIYwR0vUqEZGAOVe6ogwdTrlneWNfvX3ijdOiK\nP+JZTMUe1FBqrVQfhqgV+fMw88nnfd3+q6xLSHzXM++ERu6fgBJmlDLLl+lNPQUR\n4H912UD9ebFQDbsF3BotLdb8swDxYcR9XCQBMv/r8EIlVrd9qyOqrfXUAdRvOhjt\nCvt2PJiqvtt1FQK6AGlBdhngz8436KfwWMQ6eK39JXUNgdjqZ4P19JcCKEKOMNwx\nD87FO1n14b+/4pK0J/moMEmodZmIG4DAWuBz3ka3HCbVb/p2+7MpWTJ+oW9g3T28\n0sTlYPT+U03tOjfl5Di68GQbv7jCQ9qHzjEF5M0/84dXKgYab6liasRTqpnbPLPJ\nad09M5IQjTohwAghgj2rsrFEtB80Lz+Yw8EGsc+zyt6VHVyD1GV/VIkCHAQQAQoA\nBgUCVI6z0gAKCRCUNzqpS3wyI5Y/EAC7tcCBFFujAa7R6jP9i5ABPNB+UZqyTgWR\nObg0jU+u1Ssq68cZS7vywdGw1sb/E18OlFQ9134NxW3SxYT+hY40tOxbWATXCt78\nlRw/2PDj7eiC4QGWKTKRcGLWAxF1w63XUP7Jmbf7avrRm54iBhrrP6tO3qn+vshO\nR8PesdjkRiA4CcOG9veBrCAVgF9WpAtaJhhPqiTUUj0fdxsq4aRPklUixgvK4Gr0\nLVETiYnLPNlwbQItajOtj0Y+QMG/9bGz7VxikanFVT6IqUzkROoPmQEungK9SXjg\nQwaxk3mcyW5rSycERjDm6XafZkktcpX3NC3HuZaAHpuPz6sYI/okCVnt185s4sfa\nGcHlQTqa5/rIVOnUmnlDov22zDgGpx4pIwqxikUq8J+332gMK33SdpWDrc8BhiMC\nC75rP0bG2bseS0J4xQPsJHpzmElaaZyvph4HISserB45pEKE7byOHrZ0aSfXQ0TX\ne38xEU4/tmHlmfBeX2O0HYwDp5zkpqGUW+9tvt34QHYaW+5EoOKaoMzmk3QVXgCp\nYVY1EURFSk/5S/bZMh72CEYZ7+WSrfCxTcjjC7ZF8EKgtj7IkC4qUUwleiUyIigB\nnBW/1sZ7YuDLrmcK7dTi2AMs3aLyM7vgp/g5eOG01ci6NXGPjiHpn7ariUaKW7zl\nJeZPzX6CzYkCHAQQAQoABgUCVVs7uQAKCRBbghqBO5SnxB0dD/4/25V5mUo9Nx5z\ntl4Ht9XnjjgIVo4VF6PxKlo1m1PBPetcdrYamdzTxY+HMmU4SWuY4UZtqSnaPJfH\nWDMNDhCN816y//F/VgUYlek6oexUg3vs6fqNxaqUVQZY15MZYIdEI24LP0u2zMNY\nU1aeXNQJV817pYN7JyAyJRsc2kWclNAQ0FijebUDmwszo3+ICL/5MxPwVza1+h/u\nvGZ+KO2zsd9JFvJCu5Xr4eEKBo/jjMHPyBG1c6mDJdD9z80GVTyiZe988jqAJWM4\nVdRjxs6EL1qDVw2c8D0YVypUuCgrbqS6o/pZxGALWsnX/FUy3/sQJbQtCko6I4AN\ncSg5dYYF1mZ9fkdyq2VHD/8s2z0hcxPNKeo/bS2xh7Bk1shdhH+Tux4rLw9HAKw6\nBu+f8Atzf9bed2j9aILMauPiMlXpUNX/g7UrNxBObgdtTXjeyn7XjKu2cjcbhfnj\nhBxn3S0zVvuaDgo1L2gG65dPu3fo2Od5b1LnEUMt8njunWRw60BbUIMopoVQiMTK\nE/NJWp8Mlve+w1gjnXNEsICME8DiwAZQiV1FgDFMVV9+l1Bw5h2tsu1ngrFn3Igr\nzjhF9tJdUeNzAeSENgv0Gq2aNude/7pKhIrKcGfS+kkezGFe9gPkGs/2UC2WYhNQ\ncoSr0xMJgrv1O1IG84JqAJu1U2C5m4kCHAQQAQoABgUCVdgHSQAKCRDHtbXsnnOD\noRttD/92sCWHrU/h1wG5wcV72fO1co+YYB+YkoaBKe4CHWSIURrYcOvCqzY1S30Y\nQYcYKTOM1PQSMVzg79sIOt4c1m2Ot3j/Q5eBeN57pqHo71YwVHOUhKMCLZwM4JKr\nkzAiFd5Ae7RZrGIJUnK+WET4aklorAPmujqy0oEoGtDAQlYz7gdJPFkQ2+uF1B0G\nYK/f/FjQrVUPloTc3SKHtS/1DNTwTarC8loleug4Xf1JNjcCIB9HRmHXq2TRMJQX\njwMjTtjAK/2jV54M6V9bp/xxLAeqeSP1NfsrVXqm1voYuIfnN9Yy3js4ePct7Laj\n1bcsyjxJqJ5G7+XppHqd44BlbQesjpZ0vfqqvT58zsJ3RtO5SIRVn3ZrPOyO0UuP\njY8yDurgFee5wyconU5WSTliWhnT1U8AIUms3+xBAX2+RqId8Qn0WUHmAOmUBjsq\nm7HkiRfRUxCqvmBOomcpeRFtInbHOKvIs0wF3LgKTFyNn1WeverBVA1ba5NyfRbf\ni5XxMXptK6lZJ/4E3H4vI+e5PY/jgAQPPhw2kts5ng4T5FkLLN/jH3Y4J5n3nn8u\n/bQDuyAUqndO7hg5niThogDZWv7U2S/NcVrvN1fSV85MisImesHAvK89H9delnyG\n2NLXisizA/aKq07GUk1OsQcmpTHgDmCZrju2XPRoQzJypBTjfokCHAQQAQoABgUC\nVgVDPQAKCRB3zAv9xNaBBZb7D/9dG3q7COQM+MVhVaUzmsh51rvVepFUc16cZoeC\nnCPm6pmCX6ZAOZpLaqvPhMUgYrvSJy6g6ftJ3QbxcJBcRtNTR95ffovQghrIQufV\nMHO5zEOLaIHINhqXpIYloB6PQTTg6SsNGDYAxkj+imw0TOvHkBITQw4PeQp4K32I\nXrHXXHMeCCwNMBTxucagGZ/eDmDuLA1+mxYffSrUFLZXQlGJwSz6/JUUExMCTTad\ndQr0Aw57trkDwsRF2pT+Z90lOXbIlGC7iVQyjOfbRF9Qc7jEOcFhngUU9tkHb+aE\nVSFbVoR1BC5qhBlweKPOVHzmGrRFB508LFjj3VXc8KYcBwSMVRRx5zt+VOTf0DOY\n1gx8OW/vlZZmkqcuvTjjmt1UxbotF0aCdv331/CL7uTMLTMgAlz5ZNwFPyuCBJ62\n865W8L6P3r3BpiONLjuDjerGJGWkRtrj0e7CiY6Ekigi9QAeNUNGqKgTB9Utn8Zd\n5JPKZ4qDBjs9mJFwgbat7d8Le2ETzdB5m8W5ygsuhP9hG/5gpQh1d0iXPVbNNSs4\nhmcT2Pgc+HBoJBocLDXNyhaXybMAjqge+//otliawBVlo7GBlwv5lSmW9YvQEBwK\nvHgIPs0HfZGUAejWm/SJrkCXzMw4cxJYfkgWp/CNdKdS6zlfazjQh7t7rXzDwx+1\nY+AdT4kCHAQQAQoABgUCVnbamwAKCRDHtbXsnnODoeKHEADILox3597d4I9JP7tf\nx/KqItwgtTIEA0/EK5ls+1A9jsH+szPmU5nLCWuEMj1fKkmTi1bt0Q2hEYnlk8W1\nwV2x+ER+LiWLEeNlKyVTEpnVNXAgHwedUvXp0WeTwso4RD/zaA27Lca0NoaPqBwe\niKv8dbQkt6Bk/YSQn03w6AW9eKOIBJOfPPUWbEhKa6izf+9wsTzbZpq1/yVA+/Pr\nqEJ2mKoXjappqgrfOOS6pqu+MBvHAJ7HRxLu24/JlaEWAVRYwTkxPl27RPp01wOU\npbv2Wx6JjEkasL8NLvtmVp4TimNC9rmdOMABWqFKwy4X5h47BkP45ucXjiqAEjb5\nlVy96Gq2UaHlqavd1jZcL1XjMdHaxnYbO8e9cs6vtZKeKqKfdT2z69xwiiSxI+FW\n9zNfjFpnQ+OGs2p33AwKq5eIbplVQ3nBJqBcu1MuTfxop75qV4Ant3mvxGiiOKkb\nZYdOGRdnIp+1LCEnBPGgBDekKIKG4IONjfC6Z5tkQj7rutrhDTzyak7kb7aurF4C\nn8zocgtia934HdCuI8wFVXvqmtWeE8gQ0Bp19bq2UvdXxgHvju8LkYt5M0hcwqCJ\nWNJRrvK32i+f/bS4HsAkNY8YSpea436p55prrX7KNN/KIqRyd5PEPP4bKHptV1uW\nuBvIfs9zSnEI2O+Iv423qmQuvokCHAQQAQoABgUCVn5M8gAKCRCr1zgzpYbQ5kWS\nD/9aJ2DO3qydrOKYKDScbLtu3Y9RtMA80VkM6Zks1aGwEGqW1AlIOzyvfMBNZuCL\nuFNxWc6ekTdVBIQvRP94x0NYAKTt/YuBPacDbhVDJOpHSTXBy33p6JsK68sBjgdI\nsNUePPo3u8+t3sZdn+3u+9KvLOTZ2JKIs2NGkfua8O0Lvcz6Aw9P80NzEx8foA+b\n21iykcpkVcx/Ze8YU82butSXWf4jZphToe4NxbEgoVpEWX/cWZ3o1HU46HIjV351\nElAugVw4FSmvV31KJHLF/u4bhxE9r2b6H9vSSsFaEFuqoSpyVMPsVLrvPL3tw4fV\nJZuvP2wbdFHKuxTKeTcuk5hU8SK+PM8zKQduj7mOF7jZ8qQIHljsOxd69AfejwU2\nNGsmr51O1hI7tSXC3GxC5E4c8tuVdWvIxlWsZgyBPmMEHsuAz1bgtKW78KGsBNV7\n1CpuxglSRyTi05lHsSN4jNjYJzSwXCBbxpZd8jylIRArLbtAZRe5CPD2pDUnh7d1\nHKzM1yz9YiGoDthuCZyFXWggRgkbDCtQoG8yd7SsgEH7g++67J6LjFCnOXxHrWNi\nvoA9UNUcvbGQwVPZSHHn1xrl/gOKQUG6hnUum31X3aOhaOZQgDbx5gEPmV5qSc56\ngbGwynG1KTLKuksnQ+OSyN577fNLpsX94emMuVbujctJtIkCHAQQAQoABgUCVrko\nRQAKCRAjJ1GJuOdibDTTD/94MoIw9q1OzNKopu7XoHoxptYxN8K20NDjKyNQbjhb\n9nymfzVPmgXacZ83AGr83Aw29Ldc5lYVcXn4h7z9xg4GY1f5pNyImpW+R1AyGm8u\nscOmuoTLlZheKuIUgtfUHiV7dgDeznl7eAUyM8R5G5l37XRekv42G8gu/pf4tvFP\nAewg5HFztSDnsEDYILKC0PzniFqMSS9hhfInheqq17+tp3Qmy/XRaCLTSHpjOtlD\nLuBhEZ0RtDAXANHxz38S9Hsp3n9Xyq3V92Z1ggyplGOf+gytLX+Tf/9q6EBOsiuk\njANXbBEa9iYdFGHTUgtv7XQI6Vy/llGVAk1TtG8pk9fOT3iPLPlaeQS06T2QyQDz\ntQ+UEnMji2U7aB0lb1VVVPe8bSW3Fxjijr97nuMHqahMx673ZBVU4PAdrc2OumEY\ndz/Tluj2Dk/Qa04p1bPo7Km8ZFfxB1AUCgfuwTil/GA7P9DMruCKFfuP/nM39ntr\n0pKtIVk98XKHP0dDeQo1Z3O2zY9vJwdVa0hBrNWaDayAJcBpf7jTt+cp0Z974nkg\nY8GnAD/153m5cmdH04W8WK2o9gTlmNdI6MZLQDWQg9hWQF4FlyZza3gyOrosY0+z\ne/bUu/yg1a2Dzz16RdBxqiJIYd0X8NuYjH3H6IxEYrFCoXTmaSoUTjzKjl7wgc1/\nKYkCHAQQAQoABgUCV/y0HgAKCRBuDt7TgN4x2sLUD/4g6p41RXL3qYp4I7K1GRXw\nkaN4G1ttkhtDzt9CusrmKG0mnkKY2OJA09udaJkzVFLC+kQDdqlPpBK5XFFAZB8O\nMaDUDx1ItktOiw3pIrVrqJCsLHo4egWODNUcfWMSANmJbRLzSNDstgrCglKJYRD1\nBcX1fEIMpY0U76jR8kveGt9Tjy/1JS0lhaV/pi/nheMN41ZU9GEOB7inYR0SWUsj\nIZApHFNWGPLwix8SNmzlL0HC3/s/W3Z92Io+J3S00FRMMbh8VhTGoyHcuTfblrls\nKKWPKE35c3Ra0W+RigwXACD4Y0U+WTWD5UvhZ0AJ1g4bhQdtNPHY/E2AmDpi1mJG\nAC7gbu+kzLSXhJPL0a+JHss/776saDQoS1RN1cSeRc9FSQdyn7JurC97dRkyr7PS\nClhRTnl1OYsJxJIs5AZU/DXBPOnNccYQROYFYiyl+/DTTnja+bHNaWzbobqLFWQ8\nYdhE13IL8EQv6tf4mjYfLAKXin2wE32sQn/Cf46rPJrMyK/JsVTMVz/Dim8qyHCd\n7TtRfimn5hLUbsKLoXJQYaOc1tnFerfw+21zGTvgAvPyib6GmNfZFBw7qs8Z3mw0\n7v2nEMYFG2bVkD1AEcFtbtK7mMy6gi+HKrv28gAaAbzr4EHtEPS3zdeELglyBeXy\nB0KO4/lGhDKnaxB63BQvjokCHAQQAQoABgUCWLbDfwAKCRBiq2wtqTZrTFGyD/95\nNWQcP3RXuLsbKMrqTTsBPU1SHor1jg/dzTJNhvt2VgckKGGuNTLTzl8+QWcyzlsy\n4iy91CjZrojO83LWQy/zjV+/BaPIUK8Zr6vljB5BGqeVob04Du+Fyy6Iz3vKrGqF\nNtvIEg1BHB9j9s84dCrCXNQJaZn7te9HZiXVRnPFE2tlreoGxWDDcu8O5E2SBv76\np0XQZn/OW/Tja98DOS+4amjJfdtWeV5breL3rcCD129/9eDjHJ0n4+aXbKpmGXJs\nI2btNnMPGE0R2KFK7FdTyXPays0QJrvSkp9TJXBb8Gh1n8hm4svVFv5P7v+6SrkQ\np+O/5iyEPv59opOZDt/KkCl/3eKbPPiT4rBDDDtdcP200+u0WW36ocZL87epIv61\nVReCZsUNZQUJAdXy6OJF++YOL3/Zp2RwpNNs5Myyf8+KYVT/0IsD7m4WQphRprHx\nr/oti/MCeaaHeIUxmOI9jCgvbqiMBVs6A/gSGGEowxXr+I9P5ZJr+yT2gRkchU1c\n1cpWUvTpeH9z0M+Ym9g+0qyShSI1cxLD71iCERk+CzkOzRFAJ3w+gBX0uTLPurV6\ns2wdBOp2NwT/zSRlA3BSNVVey26OGUtk8A3aSDbrI4QIsLes2pR0h5Bo3DkZBdrr\nGQKxwm/FUIggQBjirbzgnnK1iRf/W+srpmM7S/gR2okCHAQQAQoABgUCWOeNPwAK\nCRCVdJl0QV+4pO2vD/0WJVxUl53qWUbALoksQA8RNwxYkIqnaakQmtO4M7pr+kMi\nN/locd1ePRgHmh01h7Xu0eQg+a/E6i2CNi/aHLTedg+ZffG9WMuL/ygAzgxpp7l/\nmH7AyAD7pqIpMYJ11r9Cy+t6eTBYH1GpvATXpOYd38phLY6r6DEPWBPLZtmJdOPm\nB4EGghXt/RQaFrQH3A97K24ifQaLVcIJgYVuLPY9ctbANjrMwmuZtKHIZb9bjFRE\ncTVhOuSEU91fYo3vLZvFpJZxI7xJCgIpWX7UTOfig8xprSVQ+Z+C5RyOw2YrAZSO\nIeHOeR/ZrkBogZFyIhsdB5jlmHXZ/9VWU3yPEevOSkx7c4d661/N0yuMwN57dsih\nNCu5fKq39FxmM55sGb5NBU+8ESu8dVM4cYopGeLlOjrP7+TADRa+yWUWH5uTwfHY\nTVVNdodF9T6LUzcUMTQ7X3UJUcwjw4SrEp6LleNZw/uW/FHy4LkpYEokGqxqb+s+\nJ0A295xww9zr33nWxS5xXfG98pjFUPwenC5ZUn1CMDeZGY/tvXTqd5+myDQ3w1SE\no/XwbLAXNvpUvGyxmaOHWIxieaFCnTjYUFYpg5ECVn4Qpze61cKBCioPgkD+AevV\nIs2e9Sf6tS5ATR8Fj/twWcNNzNS7DTNTo2ihZzXFLrgR3s/dtTwoM8YrnU0Is4kC\nHAQQAQoABgUCWPPhygAKCRBssbbW/muyelZhD/9c5j9ynaPuJG3f9zGXWIBgNX2S\nHeWHno7OuLcBBgmOVHqiGV6J817ya6v4vAvuh9d9QpU8Ufw/Lw24cimndgFXxQDY\nP44jVS9+7/ijPP9Ckw/OznGMbbp0xwWSzwala9VFJRhl+v+7Oo8dgCMtoEposSMP\niYWCNTSbJ84VJS/keIcKBmtrja/D54ujI9xGKwQTJuw6klDZje/NgciUfuNPEHjB\nrhwfLbOxyaKmMbZjoYGYaT0slL+AvPxBT8iI3g7l+OsbXlmPhQP16NY4PZ0xI+dQ\nIVrwha8UBeKOfXpVOnu/GJDan44C2obJqfYvpQWunraGG5gL5vW9lnQ9kuSLzRmq\nlQrLfCCaasdfAI7ZMR1wOUIVqC2x9/aLLs/loHmyK1uxiaytTuhYOyMZ/GaBO3ab\nwwLWmxDgl1CqaOvcaTecEtw/m2WQ+X0ZCH4xz5q8Zs7U+LEIqv9+ApJTVLc1ZpLj\njK38yOHOStm+SVWU6GcgrSfWexh9wzK3B3+pFwy1qR0xfdfZe8VUCSrgHugJ0RSZ\nH+Kqt5JxJLEUXwhu8gYNdtJkuM3gSyqO/yVTMGIlrKRBTTKKs/E7mteoNpRdJAe2\nInvKVG1MWJJetWMCMQgg0YM6uvrQYss46l5Spn687e6wRGkvJvol3Iy06fZ6LMba\nhqo+uR7cdLTz3anb/okCHAQQAQoABgUCWSYYcwAKCRCAOU+Rh5g1Ep/nD/4vvDIS\nUtjhgdJRMXwFuhCGnGce48IV/cRN0NOOeI7TJHR8CMvkm15ha0oCVy+TG2xk4TCb\nxyJJRXA82rQ5k3T+Cyri61KsbM1f7je2KfrckS1ZZeZZ76JL+WdDqTy9emxOfqaK\nIBDgngSoK8b4S0WA8VBtn2w4stnLsCGUI0jo0gN7abNeSw2k91a8SwthqQd4YGcx\n5VexrqMzktOht0O3lyFkpNYxhG/A2iVhuFiycmbZoj51cpr0p+oFMSENDcrACGW+\nv3fqcCNBPmM5WDq83quQA+dtaqf2JSeUmJ71le6sZwx4DJXXgblPm+EB+ebGer/8\nf7Nt/LxAz3AVJH99fKxe5EYkFhMWsbpWFtROsmI5uWkEbVpux+4b10spQtO7T/u5\n4pMFwt9sHGPOzruxjP0lemE7uH17Qy9tgH6I7phR9NYQAsSEeL3IHc3Qq7f/K/Ek\nG8dUnGto+FFmgV4Cq+dzlYf1St1Mn13HG1IxZZapLhoqd4fJl8wleaLyxBWxcGfG\nnhMdWg7s/0Bd55AyO2K1WvdItVemOdfGkD5I7d2tr4dZgHNHeX69ldI75jv4Z2cI\nDaBKxwTm2ZBmgrC5EWLpueoKrN7I0oiqzKc7V4Yc4I8GdGhOzt+ePVVPOD+EVn2R\nI06INXYdi2vEaLVqQuQAGw7vueFqcuYfTdcZr4kCHAQQAQoABgUCWbVp5AAKCRBi\nq2wtqTZrTLfsD/4wf/H8Sl6wf4H5qdOVKCo4vJrcj7Kn0g2fZQ/4fqnxcSyhNcmn\njDVbyAMpYFJnpkY60rVV57qLPa8nU0zwROY8mQ+NEGZaAiz7grU55Z4PUIS9Iy1t\nZY76YNOZdghNiVk9Zge2lxTkynu3OmiNdu+8u0Zfuz7d1NeflxUZkTbrtsJlJd1O\nl1Z9zTVWS6mIBceZ7J3SDJEN+6qjfLeBTCyv+vX7AJDWXI7gNG0drOknjDtKTy7s\nxTGcE620adW1EWa+2rKkCE146AviiIMa4psiXDkBq2K6AWdKkv3KNlb0JJQgGZO7\ng2/xNzbm9SCc8nZDHO8IahO5kw7gOtJN4iSmH2jEId6CApoeg5pPQIEUQ1vXL35H\n61WEHkVf/y2NnMVjDIk6wyOb8IKzYbmPMNVdGgGUMvSEVG2JL4uzC7fF2g0kNVIX\nnPWugOs+NrChu5ruLEuR3zWpn4a47vtYuyMTiICnjJ2q7Kgzs0JICBfjZwia9kRz\nFZlQioxhEc7V97ls1X5mHL3ASGiiApGThZ4JXLMaFiuP8KlaMJKuqiWVfOju+TXb\njmwiMPrsXyLTChn8xJTCUX4SZc+CqQu56WgpB3r5gsJkKrmZSrhUUgTY6yQTWxNo\nZq2xndQbzfEophHdyTqvvt003pKUSpvMMrtSQsHewPW/qLgGS4Ba77PlPIkCHAQQ\nAQoABgUCWpaFWgAKCRDaxZ+Z8QTrWHibD/43FIf1lYgE0dt/iy3CyZlQVAsfPqBm\n0fmSbT5d6MqaI96wnkqDQnWghi57MV5Wcl+jUxby2zvbRWmWzwOXI15TN4Vz5Ff2\ngYD0/G+OMFGvDqbHSq9UQJK3ll5pc3E81hhUIBpmCOOpZMmkMf9xruyOl0QTSy82\n+3tbRNwbT98IPucv3+pqoxz7zJQe21QIhegFufAAsn8GN+tg4GcUe+v7FHNkIpUe\nyyLv1JAqSnkrfKVi7P4LTgtIo4M1DsAwxNHwOPGZm8A63ImC4soENUzXjOahpcTH\ngo2kmuARXt25eqYZuSDVColgqkbGzbhDNB9LSVSL+gzL1tvFeCay7PlleBv+NVhT\nRKCST2WB7J/TbJANO6K6hhn5KOLhAVzpr9hNZ5cbGCvYE2lpBOsUmDCM+v7KaxXS\nUIzudWbD4JOJQ3xI8jEwA2RZzFzeWKexVJOVz6poZabq81k3HJTOIvCS3w4xtR+F\na2XNmExHfztVjM3W1GgkrkZ+euOzAgY2OBjh0wgdthvyM++MCh94eIV0WIYnpAeQ\nrr2w0qJhmh7cAfLF2odPHV92j5I7DDH80l1EdhEUm9JOYJ45kbziRKB1yQRqDGgX\naXRR3yJlh96YLj4eavqSBxESze+Bg1ukIrBfaWrxpSs/1ZMb+DdvssjyR4bkIMOE\nh7zfw9xSmuJjrIkCHAQSAQgABgUCVyc4pQAKCRBqFMoJ25auk6tID/0YuDAK5B6/\n5CFn7iUi3+An8oubm715iF8X8kkR1BOk64HgyTaeSzDlmnj72XYf/wnucfCpswKk\nxf7QAhnAAJJh2DquwL6K9E38ChF0T2glPB2Yd01luaL2mDihlrXlz8jgOAsUIpgy\n9Ak+7ayzISHxzp2wCkpDkNHfoUpcaU41wes1qGCTamhA3u08X6ZhdMYysmQU48Ik\nmlqdov6Rv7iqTrcuPdhL2gcc1UwpLJ4HI2ZD2wEsncPJXEJ4m+JbUg+s3SBREryA\nVcl7+Bz/IauMi+X+yJZfr+qshmXki8v1c3Mj24jv+TbWt2UY68wJEGqJBK8oHugt\nL9cKxYmhNiIjh0i6UKIGgpI2DDTZXo7fbAYdC8LLHXT9V+8qiupzzq3hF376z/6Y\nQaJeN4tvKQYe9vC7e8jkCR819Sg4AL5ZTf3RqiYcYh4RYO4VvNL8JpMZekOiqPSo\nOrTA1hXnPos2ZlxphB+mIvJplSuCOrGp68yoauBoNrb9+NrDQlWOU/feoVzBme0O\nDOiJ/eXzhUNqcCs26yvIzSJgXj0W3nadXxpQD1HO0NljYdKJPOjK2W9RT8AE0R9k\nYyQLQDSByEuV0Bc97+iITQbCqSoT3Dg/AqVKAkkuyAmMlsIhsmLOcsFVhODYiQYz\nJqnowYUte2oLDCpHKVIdxqULMDYJZWTFookCHAQSAQgABgUCVz4SGAAKCRBqFMoJ\n25auk2UBD/9vWQ21bbtZmXWnGVlx31Zz7zZERlNUmPNsX3C8uFyOPrW6rQm4ImyY\n5NNGlHlApirf3TVjZAEhbMiX/hoMN2C8ZQHYKsQBQIae/giADnyGccE6/7/d5j4K\n3hQoveKeinBzuR/sURIBdN4A8wVJzbhgfl0/UvEDulQ3qntOfVX70o0s0Qruy5QQ\nYIV5cMdQ68pOM9zSJG9Eo+h6KXj7m25bckEQyqM9xq6vZU01gTRmUuGVz5EWqofN\n+G8riUhv3xdDGTKQ1OVHS1u1SZhWDwsCc9gIOqAAp7VqUys3celNSW19T6Z3U5Fs\nMVpIc6MFEXeHUukjkyiRLg/XYEJroqZtMwpQ/uqPFk7vyLX90GWJ8vGeIo28X+cS\n/cK8Nse4eE91LCLA204BLkhF+2dE2/cPpF0vr7SToJwuLCUUhwmfJXxWac4IgrcH\nlkVdwuwlDYNOrFQcueKOPTCSq026dbTULndkBTs9dN2mvDMK5mz27hjU6+wotUMI\nMoCOmZ5MTqOAGt2DCzYuSGjZz32PxJtk24ECybL68zAbRhF+RqazIGyBmv2FF4Sj\n0GgrbK3UcJJEMuzglDv617Z+G5OPkjL/jprnVUVXueC6+1nDXE12FDqBUriz6C+b\n/wyZg9jT7duOEOGssA3NhBpWzdr7zkFpRnJTInwu1EYdUOAQeiKs+IkCHAQSAQgA\nBgUCWWLKIAAKCRC2y5V4CKp7XftlD/0VwLL5EvYPsiTZBmaEwF9kzeW0EijwdjeC\nzOuAYL0+++5hqFz5IGDOst+QRkwAsSwBDCoVJK07h8wM+PcrHm3BhdUt94YAzHBK\nlmtR+IRILBc5RNA3zZj4hIGINLWtMIFRYWIsFYjCcQoGpQGz6n4Yf75NIIzpvD+y\n1r6zlBa19QpEEG88BA26HsrPpSZjoDNVcntEyzHuDei66hDTuPFamgYyE2x5q6M0\nFF35810BtfWZGLcsn/uwLSWHybG83fPqtMidbvJ/sOazEK5GkUc0elnZ1KIleKb5\ntBgUo+QvuV3yLQyHaFCJpj14U8+B7ZZhMmdkaMZOBzyblXz7FPi2kS1OdTxGjnlV\nyIAW/q1AwLPOVTJ9cbRgHLT8xttvSVttwgNEFsYeVUxR8JQLXWTkG0vYNEMYRinW\njFdPzE/itbBjYsw/YE4T0OQRQkBMwFmC6X0wiAhInk9COCd2hXeI8LdP8iBCOwcN\n97Hlyr6JuQvvpPVtvboJ0hdedEBP+7dXtUvzfv8JHqZP0c139dGTiQJEtX8+Nmn6\nDjcR3OXbfU48StxUpUQujfHW3Rf5GI5K3rGMeRg2VjgODi+5o3AM3LNcmDkTsJZA\nqB3uvJ78SkEsdMdEVi+CHdZbMOvBWrftd3cB3HhpyCABjzecaRZg339H5guTeijt\nSAsibTDUvokCHAQSAQoABgUCWaJvHwAKCRBzUYoVujwUdjUXD/9jBx2kqUs74UGM\nEX3CArgZXh/odP4d2vOBd3nGSGQbLLfS4yqKY4SzLEax6Qo0FW3PcmpHOCMEYTo3\nDyaEJDBSz/bMu6eVauvRHXAhS0Jd0IPQaUh1FrombcjRe5BHsAUz0BBNCH1nHL/K\n+2TJOhVlILhbMD5+V5HXBk0XBuKfbGvgSWQ/hM+KK7cXh0CIzu5Gtwtgvr1ibA81\noQLfhAwdIy0k/zaGA9fZ12n9qrUxL1jG4wLA726wqJGhRyDEojllXdmQ/8ooOMjm\nLr0WRnJqYRY/s+TtMBK0ZTlOJauzGWTs28KGoyBXnlMWDxNFb85gbxEyR9SJzIoC\n/WptRh55msrbibKBOkVyLKvTOnzLbPWgk2w3hN2PhKXzgoPTNB4jQ9efc+dVNgi+\npoVKC2OL9ewQPpUn1ybqXHpBaBnONdllVndLDvoa1fVBsshddUrtGz2uyTCzxBch\n5pcIol2/Fa+w3r7tKXzgnOQv8KswQdIy2LcixEJo4V2DKDCdLEdRwlSzJ4T3C93Q\n6IEhPvFfdpvT2USP7hwzPBvYjAsrxp4vwgWfkmBh9RkhfBP/RDmLUZ4X43FIrij3\n437Opc8W+q4/24GiKEf93LU/Tkdmce49gx+LrJD/mRUEkJgKsh1F7xpYXiiYhTYD\nDsk/jP2apxm6Q/aD4c4EhcOhuQMGXYkCHAQTAQoABgUCVufuCAAKCRApXHRphK9/\nDJGCEACSvGiNiCyQ6wFhd/6C3A2sy+TtctIXJPmVMZlGzwsYDc77FXAohYnnfnYD\nK1MvC/IpXKl2Mw0loh2bQvKI4aG8DX5PcOJwviA9OHXBIuwHp9CYRk/PsXn5KARu\nOCab0Uv7OgcGSYhT1VqfE5y6ubQKELMIV197Fhk6DALrhGvf5uK2nLEKOHu01IHO\ngI6e/05GPipKse5ntj89ZEHxebOLHiTKrMg/JdYoaCEsJxO7MWMiyhszBwtiKd/2\nh9jJbox4ztCLpZh30lZbwlMO1PwtfeZCRfl/oIvMaS983yhsUS6LYQk+WMPe7bMM\nZ+ie3cotwYidKaKAEOVLFNaPs8iaebHnfgNjfo6pfwPW/57CJv2Vfihd1+IpM2TS\ncPRkgNg2fw3C8DDF7XCoB048DAI6cVUBhbrD0lFiPHDR7hYXq0CGjWUNmt28XHbv\nAq9vil+tuaLHlqGuiFPiKk4b+so80ISZAJM43hMDcrrwYBtvgLXNbUJhHtS5XIK3\nwOAF1A5uzaSdOGgJ/8VsbqLtRhZ8dWdM0AZmQMYYsIm0jwjTpwdXD6JjaGrwemAU\nhRdoadx9Yo7C8wBmQyph6bcs651q1E/RvKPSq3AbuWxJ5l/LWagGWIfzD8OVffW2\nV0Yilb7NDQQsVHXxyh0GCmrbYSNruU8lrc3dAaqna+bxWVZZI4kCHAQTAQoABgUC\nVufuIQAKCRAvmfkhu3flVAu5D/9ovMPlNS4H4gZ4bAolcpD2RRXUarO+vnicYWIN\nR5AnJAih2gJVXKfDDx5qHFx0IxfHvVcIlput+0ZoPGCIp1js8Nb5FMpUGAJRziSf\n6FyVQPegwFawSWV3/+RrUftURQYTW6QzZol6kUIIEg+efWgnqMPEyebXDvO0KNie\nSjvGUm7MedfWGySkKq81P/Ets1q+nvBKzTbwsNM7UClt31uhbvZUIuG7vSLWpvCa\nS1MWwNda/ZHffvETbucnL4TcForZ04cDob7bQ5LX6dbS9siFbcTaorfgUqZLYviO\nfrK02n4htGIUior9d0o3VTBT4Y+X7XOH0UP5yoYQb1AXrv9b7Gftd7Ga77J0lTFv\nRAnfFUzMfdp5oCEjCni2UoDBEWOUmhlyk+cXsns250tdkKQ3UWc5FuJuF4C95o/J\nmsflFI7lI90Mo3wBprX+ThvzWaDABGIDzmrCDWekWRvMBQ4kgRUKD74xbZ1yUKVM\nEJMiKxzi7SuBgtdjrwV8/6aDdPmg1MJbabK3khoUZrle3tSkK1GGTScYxGWTzDti\njo4SFKA6kT0Ge6HqpC1XD5wZUnOfHJRwze/oh5rNnkOH6BsI299InoKbNiNBag4x\niveR9zPfUP1Vn/8qDihu1CtTEhiJ+M54ukj3lH5FWnxtClNeTuHXzsnGbsOp6I7+\nI30G0okCHAQTAQoABgUCVufuMQAKCRAK9i3AydbwkNySEADiHvFqBWaYZfOt/pML\n5esJB8Z5BAcMHZxNZh2AhjLHWR/KN4JO2l9MZnQwTUdDeLhfA6rcuzFNxGalhDMv\nXJWGFEVy/6fV2qymVO1OlsLGPwqH3O5mgA4LjtKWHvKakMu4lOoJ8nNcWeJoVs/I\nX71tGnXIfXQnCEnm3kLbSquZzJAy3vt1F/Zp4Vhf4ZGp3YnJ4cEZuTHIWyk48L2N\nkIchVC+nAOweGtXlX19VaEKAdtMRhsoZCVL1MBZ08KQKoyiT66ydFJu/BeD0DJXH\nWMxF/x026aa6shPcRQ89N64jGIczhTwo9+Ewu0OXd+HTXWaCAjfIPZzJudJxFh8C\nYVbELmMsN2LwVEKu42ahRIhsnNELLXJerB0A/Q0iEVCWPfj6GzSKenf+0DfGb5qn\nSuyh7UBtFxjfGrvSCB07sfg76Y1dWKFFFNJUo1sjNqCI/WUJ5/I+WbNvxAPD8xvn\nWEM9ZqjayPMGFfJiXv0WujX6uXYu/TyZaOEJ2Q+ufTrUFZZZgMtoXN2lQPamHdlF\nOdlQfavMH/+60zpQ4zIMbr4YgtagAyyp008Nly9dctIi27SP6dakCX7r8IuYm7L1\njCCCjGFLIGkKgVDcnQ6JjUR3gdjjzg7RRmE5v/wZUWJHjoYyU8Wy0dFztk6dzVVD\nAHgABPafOb5YA/IfShifUwJPOIkCHAQTAQoABgUCWJHIzgAKCRBSuOLwgqnPgTM5\nD/9cJ8Tm+3fuJBXIDVR+uqlSVYQ/oP9rlsKueTwWdYuYbj5aBj5krI5hh2m6LGJN\n/xYgrl5lOjncKUTv3Q6uoANwNPuGPFjoEWOc5ICt0uWRqD+yxOexN50iQIYnc0UH\n4OnI9znMh1A0rh4RF/oY4ivzcnwZgnXfZpbHCtMmHSEk2bY43uaOFxoGjBgdgg8f\nyf+dBcBDQHFPgWesOH15dYWizhImh/0E5MrVbFlPbnNF90jl/jKD1lBHVzFEP9mU\nVKTcJM2sTxJ/M6PsmD4e82DD0k9cyK8/pvh7hhKHcu9Zq0bodq1cDu6lstuoVwtq\nECDy2a1MeLe4m+wvVN2C1Pbo3VCzxg6nd/0uOk64kLVvJjHNjNJeq2SA7TZKul9k\nbHC7a2ypi6mhS5OYFyERYYOaeJJ16JvP6zPKO8ge9Wszhv7m04CgMm8XryCZywPI\nPbKE1hN9ykjDSe3wPXTNSpMOwZFwWDS/MJtIvCVPb+W76Z2vMTnu72L1rAduInNi\niezczCkUb0LVibEYlzxfkYQkaegYuiA939v/GuGdw1k9qY8RrUI4L1ppGeI9BHye\nZ2TP08MVUXPWUXjxKlcPd/P5sZtChcgJNnn1SskU/yhKDTx7Zm+5hEj5JrQSSmWy\nQpKuu46tkGCC7DuQEIcvy4PRTE+SJlURE/UyfKt0orLPQIkCHwQQAQoACQUCVQWS\nmQIHAAAKCRBXTYyli55EaU0oD/9D7Yz2KCwQx05nrgJa3AMSPgw2TdauCN1jFW2G\noXRzRhLPqRm1SlVE18moXkppYVkORvQJEQj0f+Kz69hwA036uHgbY2GP6eb1Vnfu\nrGdJdlAJfh8HmlFhB0r7A+MG0NFLInszGt4EtmQHKqLt/RulnVi0KdGZmDOJWE3l\n4/a1+kMrsaMYtFs6GhHE3gHWu6ZBT7ARnu41d8VetXjkqHmEoJNu3JtAIXsrhlwq\nG/cylH2QHVu9icKOia1FxkaNaX0ftS6j8Z1S+WecdHr8RLjmXswq3ym7Fk54RGOR\nwhfyh7/Q1Thc1W/mOTSJCHnSgruAnx7JbtLUvfStQWav9wOGtUdwZY1nzqJvxreH\nn+wWOuTXWY6dowms2vRYebFNJH5oC1t0kcvjy0xnLRPVTdcihHSURntSh/g0++Pu\nNOSb94TA9D4mcQ3XfDm5BzDwLzCp+FPQDVH9ItW6JFDD5k7CQYIa2w970OFtBrOD\nvbzoArtKaDRMWwULF4wvhyASRlBWDiDfCO/ca8FdaDtH9DtIQgm5kDOq9FploxMh\nyNFjvHscKMSsPXZJCc/wHt0yzqkTILu1xH8Ob3d0+lPrtHihe5GyNlo6b2yARW3y\nvqQuxYWq9Rpjf2QZGONX8DQjtcLW8XfEGfqaOOGX4Pv5k1wIACq/pGR8EnA7jvij\n6V5QB4kCIAQQAQgACgUCV4CdlwMFATwACgkQa4qj/cna96rAcw/9FaHBt0d1fY3u\nrcDKjgAcsh59tb2vSD2cUqar2M58UEfVPqNoMt/s2yjl9wTDfTt9yrUlIeJlXQtm\nemtZYh5Z+F2MNe6BIaOsX5DOEqzoEK3bxQJObX3kKUX+zSkxKgDKbEPmgbOK5X0c\ndE4bDME/zb1DEbrrYwX6e3e4fZV0rC8z0DDuAwcANvE1VErKNVzdrXzCkvfMGRiO\njZpxLY3A9AbP6Lel2Fj2zssZXRjDyhQuFDIJjCNjyS46h4FT2y2wEa6LUJDBUkLz\nq6txskJLXar9Uo4S5OjiOvNJGLS5yeKtfNfhmvLos9CapjZZ/a1FjARXU9ybKqRo\n5a7zYHOUqexUOFYv19iVhqa5jw+7NqKMsXkoWHGbyi4mhiqX08Ne0oRKUidgcgb3\nQC+Ue0fSD+rhNYCHPfTuLe77/lNr+f8CfBl7GcqcC/Qf65fWi0xuIltiYqC+/pGV\nMI/KRB66tp5oPPpsICy1pCdNxYxAEJrm3WBaavgabULxCWmfuFIvyRPzv5TMA1Do\naUBfqYaA23vGI7+sAt0YRXkfgAAjSaA/BeIIx/tKMRkXpC3HluLgb3BuSRaZi5wX\nDuCx8vdTIlA+7EJ84ustqYDC8hcIDG+/6rnDa7NtNm7JvWTPjXgKvsyWXO51L26a\n1sUnLuzW8ynUl05SVPFUnsE5Do0ujCyJAiIEEAEIAAwFAlUh0uUFgweGH4AACgkQ\nPfx6oTqYgg9bGg//elBtDplqD3otCCiayUjl+kEGA092y4GedP24DcwxyHzcL/Ks\nPkwZWKHxWk4QSf0OUSkLZc3Hds4D5dWFCru5sv8gI6WjugSp0uOy1hjg5S4r5iG2\nm4SF4svdfjgBR9yvWJEet43Mwb5XobYYJXG+s4yuSMj4ds5st0Pr488jEz9uCUoE\n5xs8dCsZfGqpm/iBxkd/e5nIKK1UeqaVdLF23A6FkGg6LejdNvtpcHukXCuYERNR\n5IR0MVmd2MQSlV5RaduqOE5xhrqr+cFULw/g+mQgxuepZjKubAAsPLUvqL/j6i41\n8G8uSvFwtV+2Dsk1QZioF727nHFnPMO0HrGlHquhbuzoIzjx0Lw0KTt+wTGf4E2k\n6ik1Erg1n3w931MlWKDP0lK6XFan/fZ4mqJWqaxheiPZ2boYtDDQxq7zE5v1ybAj\nEN8yKcokTQJdte6QL4uZd6GGFBjXcgQHzZIbmS//KV3kL+Z3Z0vIl9x1qc2VxBWo\nzwocgreesIi78QAS+7NiQy+zoAM5jiLr5T7n/jpcFFD7oHQcFcXRy+TX4PDqBXoe\nOHOLvM0JGsZHikMBmz0fP9ZJ1blwp/Kg6bU6dJ0qKUNqeeiZEaSnlB/aBuKNxUqP\nd+GZRRqzn5qSHbwBCSjj91CCDdnephiNKv7OqAFqzn4PvcjXFxaX+wH9HeOJAiIE\nEAEKAAwFAlTuAD4FgwPFCgAACgkQq98KBV5P0v7S3RAAsSMgIMWxhXm2BwhXwgy7\nNGv+oRsGgt0dX4bBynTIWoJm1OM98x0kdC4z0IMFC4ibE36nkGLREo/7XFNWYjxB\n98DGYqMXuDT1WvtAPJNilLlnA+PnVq0hBK/PZYza0hpmAJP4F+ZNI3G/E9W/EJan\nhkjzjjBwuYA7mJ8/tE7pnOh0d0+XWWVMcPraXWcCs3GhOd8Pro3yQsKsNLtxvO4h\nE+RJVw73xheXDC1bK1YL79SeSlAirBaWOdKdF6IX0GJKo0kWXa3zCcQZ/OtR3AhD\nMceBsGLNCP2UcGQig4w+Ky+ZsghKOi8Hsua5jAMSIi9aPr1Bap2H0op9zPElhktU\nQgeyZbOcQN+WqNsShfwIZUZqrcr38al4ZoPZ5v0b+ztihcLHvPG0wqJgmu05pG4O\nsXQjU9WR/4ecH8eZvy5pWhDc+N+3d280JH/JOgBw7/7JZ8RfFg/9811zvqqH1cqf\n6sZSloPHSIq4MtIw/IOhxgsq/RPsfIbZShNsMXCFlk3ZyAErs5aiUTBVQN14TD5m\n6UmSSLi5x32bXZ7uKi5Mg26UUEDkYPGk2mFCInEQU3SqjA/ifjBYudMcbGcOmDEx\nd73FxOHD6Kjy12XZkMStj7IIteEyZnNvyLEcRPX0K5JTjebAJM2EDQcjpVLqz9y9\n+DJZhqBJ+gs0G0n+rN7BT6iJAiIEEAEKAAwFAlfeK+cFgwHhM4AACgkQlAwF5ySk\n/9oJjA//XN2vg3nLlwzA9sK4wq4LTvRejew3lBISyytynYuK/0MD77BB5kyrHAOQ\ny1K+a5+nKiUgHZOey+ayhMJwvOIlqFN950m2CPPMrll60eeNJ6FhEYXmYLPtcMDp\nW5wQ4kIs1cwM1y+7G+mQJl6y5S+9PEI1GRGvO3RfM986dQ++PjnXy1Qr74LdcX7A\nwCVEJMSq4KsjJ33IGA9H9XejrahXCsLpCVe+0paChm8YJLuPejbHvd4uXVe8tdFS\nLp2A06vJfvxejHRBl+GxRvt/yU6R8A9sDaciqkBEWS4+2eewrlVVJnR2wq3aHVTS\noO7C2EZdz0ZCWgSUjsALyM3dLaKQsUfU3LMuvtK3edvxP8UB8+P6c8Lrp9ryLA7W\nPkcrFcNQsbi2t8NUzphWSCnl4Ob167b9t9nKvLajt9/nvPFkpI8ifGXZqvuO3e5E\nH5zCJCH5hZgm3fuxWnHD0cFTHiY2SubfkmhuTh7dA5kZt2vUvQv3Rk1r42U7V2Um\nKiT9aWOiXBCXBaC6/RvXm8WY0PMQQkP7HrXz/+vU9Nlm01b/px6q2CEMf9wxBY5w\nTks/1WRbhGj+WF4cz4XPuCeSuIkYbL1wDgCJhjtV3hmuwXOqAllO7waACa4b+1Oi\nMiRC4edNGnlk28a9jTJkbV11Cev6MO2GBfpNYkwZf/ewFtgBP3eJAiIEEAEKAAwF\nAlkm1HkFgweGH4AACgkQGLLf2xH0BwSLHw/+IES8zbhvmfMXaRqTuRNiioxm+cZc\nNyePVPcPL4esRcEYixjiHf97HmAfEzTS/drgLjuRKfQw0SNEnAk5lCVQPwLMMUXa\nTkLTANm9q0mws5RXoSsEqaGC/TT23EIOpWt0YguVsMJisScCWmtxoxvMU4O/2vHj\nRpzZMh9hqCU2Db7JsOcofqbZ3kbCNfFnnbQ4X6GNapPdJcsA3Qm5ewv0r+uW+hOA\noeBoqEc7LI6SIKUGuqno4VhqqWnvDrgVTsFedKpoT1X8vuSpTFUxwr3o1xGa/ltE\nBifYaAwFMFPdzP1OH9r6aovuej2DxZJq8Wx/jCIBHYLAhJObxDEB8nJI+THtERS1\n34vxvHai9j7x/YnY6OiJ0uO5A48rmkreR5u2UB3AsNII6uZsTe7j0eoASLkijFq9\nHJnRaDGQTD4RHpEbBjoJCpEcgOFYp4MaYoS2BtyNjTLj2Nv/+qT1Pn2KzfxBT7yY\nh/jj/lGOPnsNrR1dk9NXMuXOKKemjXsSOlCULyi/ilxO09E41jAtpnT0kv/nvzRO\n8eyhYVQh25LuEAhWU91pft9ayZKjNPBOGjmo4IsSFTXIwzPjjujxp6F7qvExtM/S\nX+mpfJHI4kU9Y33CpFM/m8d/aGXrz97aKRVQS8sE3tfZw9r5WTdB5wAMxGM2cCrA\nMCnWEPx8jc/fw9SJAiIEEQEIAAwFAldtilsFgwPCZwAACgkQZqth2wp80XIo/Q/+\nKSmZMYuE+W6orS7v0G9KKNhnWto+Zn7HApAxG3TSUMJXBU4rWqrNeJFdjFX3IMQq\n/GxAfOdllygW/VnkJdwXGd9upVzCeWhHolJHGnanCbDCh3a+IaLKJSLdxVgWxa84\nFF5gVZDqUoyiRipVlEEKw3dKaIFr3D8B4ArA3id71f1j4uAl9JsAAIRIKti9HW9X\ntgYSkktd0ObEGA5DInm4Xe6HA7hoDH0d6jM1+w1F3Pv3CEDIh4b/4v5O6SjcU0a1\nAMcb4ZwRsoOv+lalSKYzAmrC1AWwAYFxZkXOMGXyNMxIV5W8r9cRPZcggi5UdClR\n0D08fWoh04XjaE3oHTAS+85lFnRNfIBoxUbdNhbEaswMuM9oQCB1VCXy2tk4kO2H\n9euAVAJmzIAIGI1w3bm4EsURuDGJhQbA2Atm7MMwX+vbaF7+U/SlEj3GCe5lcpgW\nbZ6BSahqZRKQzAC377FSQzZ/gtPXj7NOva+VG1qkaB5G3ts2ag4t3eFZGsEYIVJB\nxi4mzlpQVZhS5ka3+HMyMbkH6NkZHYVQIoFk/lisw4D3i1H2axo9fNs+Btf1arIg\nigdA94X3b2zjwQH1iXCqFRFMUPPTMq7DWEasNlWOCY6UtJfeamEhVdW2E7CENUy2\n6LSiUzvxC6FUuXGjL8KITIMaNyHrjsXzSao6+tu6v/OJAiIEEQEKAAwFAlily2EF\ngweGH4AACgkQJFtLccApuRaltw/9FudKXvdEPXznNdga1KfO87QOFjnQVvJVRI+b\nf+ChuKogHRh8+ZY+q0ag+zAGL8qOcKMJSHDFdy4SmSBNourP/ky1iBbghSEsm8py\nEFtm6ARWFwF6kMzxnOGjFaGUKOl+dzLT1Z2XBx15nkK9DmmhCHRw+AbU3Wq3kCp7\ng+Xu2MBadGpqFVHGmqMkD2bv5BskRSSmO9KsncmIuA8/lXlyI7nE5kjP1vlq2fga\nDCBLJnvSOh+wEF1/JYXK0R9wIwS3cqHOftEUYhfRnFx15HL78K1geBYrVtw1VRCD\nSe8SY5OZHx1MhbpFU/9S8bIACgxrX/6/CiGz3PnqJ4Vpa6HJ5W/3S+cwGVvlvT1s\nynD+TZMvfT01VehZ/1hMa85ENKrtOorcRnrUOGdYnuIV4nbpeiLgROZW0uOvl9MK\nlOuXRPvfaTFuY7m/yJI95jdYXMzDI+GjTx2fFvzDnW8CQ3N4lhR/1+Dv6IKeXSW0\nCr/cG4htD1qWC2keyjl12oLXixo9QHJddnuG1rBez+HIOy/+V83YdgC/c2Xr7xS/\nnXErqBs91lgDM6B+Ko5Ze3S3QutNyPB2hpCWtoXWPFY0QXykBQZua5sv4zt1DQha\nOYi0TOidqCCAmlZYqs264pGZLQF/jhqARW4h5k880hm0qycdGDcvFuUMemijGuyS\nluQppW6JAiIEEgEKAAwFAlXc2jsFgweGH4AACgkQgB0DF+GcfEgqLA/9HLmZ7pVa\nQ2a4WkQQmfWrnRbXEbOwnGuHZySF1Y/XJIF0kMuZZkdAoFGx3xwQ/9vm1DPRsM+g\nAdEm0hmTYneh1x4GLKvaZZe5IgbUNePnkyv7xtcV2Bt8OajqpdFZceICG4yPqdfB\nlrORNuq00wy+fP1k54OxFNpRb9oGqF/frwlVGldRsBoxJN/wVFqb5cUOrfmc52sh\n5h4XIbZx80QVjkedd9eP0V/gFlDnax3Oiw6otzcbeNUYtE5QvMqwieRXukqSEmX4\n7Kb2pMpBiAf7jJlLhtcXRdLz92S/nm+ZjDfzGOuaBFKB1zUlxHSj5V6vnVxkNKLc\nzbPltnbnRAVNAm+jJZw7pi8yc7I1YjJJKMQgGb7v5I6HnDkYKo0TZN43BJnpTFQc\nZMhqnexWmCZbpiZm4xAvyoGS8C+vx4XaVsKppHrJF1Iauc1zw3IdkdlXYsf2HVjX\nufjNiZtwDIi6v+XK/0lk8n30s6aqQEGUWm4VPzSN8hDSZGOp02BzmvEih8WVRUF+\nk+EG+walxJSZSjzurHcjtrs87VUfWbRYy0KYSpImyL8MkXCBOaZN/iCrXtVC5g7x\n0fZVj/TpC7nwF8gmLOx/J871gDOCk8HIddQYhiAlbGIbV/U4cE+0lmGlu/FrRfa/\nokfIpbgGxRyPn/H3qPRsm6DKtrdEReETIOSJAiIEEgEKAAwFAlYkBx0FgweGH4AA\nCgkQRQy6f5aPCUsSJA//aTJ4yHDduIodq+7TBNoebM14TfDa3PX89dvvwqC0Rmjo\nXE0Q3PXZxNzZ7xbwOTHp5hVKXhwED5xC7FTsYOhU5sYvhyxEaDRJc7/IC2HzJxaG\nT/NHI5eiElaOiodhvX37Ar1bLGmdMgx4nMBqcND9ShGVZXGeQiypkaNu7PsiYNS0\nOztzX3kDnnrHPhkDe79lmVekOmzLPizSiljAdkRTxzLUtgOwfV5wK1e0LdD1WGWF\nq64cZWee+MRdU6efSIXYSYOtXKtnwID/cauqnizYRff04BXhlSKBybEn1gCEfEx7\n1PvRL1pv0SjXBH6HIWrgxv3++ypr3pbpfiNwKo6QXowpFSotJnQ8gL42HcVgq/2W\nWLfZfUHIzVWrHBbb46qRBRg4lLpxBvW2nHIMhcc7BU9//Qx32SMl9NMCi5yChruw\nonGrklgFRnjobkJhq8tuGODyr4OzVn00QzKO6Yag0XyReAfO5Eud/i0qmlqhJjga\nPacDratnwiNMzQNrBThOcvtafeKUo5BBlvC+djaIemn/RYUlTRuXG427CNY8yUSc\nXyHHt99ppS7CZx1cdVN8xfkWyCecfN6dQHvUorpTtv3exkCqk7iBdWVtopxnAAp2\nmgBxv8D2CxTAl2hE3N6a8ZOb2vyQTwRBTgtARd/CG6Vh2EHPVE4FtTC9VgSPffGJ\nAiIEEgEKAAwFAldANiYFgweGH4AACgkQprwBwV1+3anfcA/+LqA1XAKGrVJUP+h0\n2/khUw95o6VrSrup/9UobjK50MRBqp/+++AffRcQOosiU8qEbzEGXLt2qpXrSv5e\neMowo9iKA5T5Op8raNrnO4isCOLL4NrPqWuBSGFrcs0QVPx7Yfd3ko8pL9CMncYR\nHrvdvZXg6ueH1ubm+rayP9DwtijeEVDW0WSlT57wANFvVvuKdLUflVD4NAg24Ys3\n+cbMyrv8RNSR81LxKwKtS5xNAB6lGjdMxg4K70A7febE+lHy8lb/JcItRtmnZs90\nEYZ2D3i8pmbmM0OId9yCuBFR+r2vIhQdrlwBabuJt8BR/lYKd4H9EUNKlA0TsSc/\nMlvaPCO/PqRamioSE+vUpfyCG1ED6cLV8wZwsAKY5XcEHaUQByIIH/j/tRxGpZ6F\nb8ZobmUvbLNwIfPJ8VFmOCUe9pAEsZx1R78KhPmwhedd44igeZMfOJxVf4Ag75Sa\ncdkI/ug3m8V3QZ4+uG9qaW73EUmI8SyKTHKQ0xy75aqIvkMvrI3dmg0FxaWg+RL1\nbz+ia97Lymxo/+finnSf3KpUduh6AxarodcEhB32qH31QRb1i+A5I7mVe8xcc7ss\nM0S/65G+gZeRuImH2ygEJUvMKISlLqzZaWtuBUKW8Fqn8kA/rHL10eAN3ADqSjXN\nsAPXBBsInQkO+jAxsrl9mtNbq+mJAiIEEgEKAAwFAljmcD8FgwUnrYAACgkQc0FA\nFkkP4mhhvQ/6A1rNbB4tn6mxhdp5aCvroHCu1D5+eNSWB/HH+ZOp3A6NP0GlbzY/\n1MFiDft7hcpRL0eXhhsUSX7ivpWnR/SzRxB14xEu4OkB4SFGHK5Xv1CIKWuj1zdV\nXmUBB4IzqOnPTzTZcoTN9ElEU3cS5q8pG8dJ8WyczY6JBKI+LtCu+z1vrvk6T3KL\nalyNbQYOFb7Mml7DDIqN/eU5NMi4DRKhsgU1ai5oHa7UaJM83L2WTc0vwZRm8Vcw\nOI3oVHQhGXiEMNQKpToQqcbz0f2CL2KMMtQ4WvGH3E7vYkozPU6qBE2DhNiEWOAj\nvV/kRT0W+pD9Ul6Y6QqU6pH4zFC6ZFK2iyyw4QwpRtLk4gjNVmb1vegabqdEO3PR\n16z5fSCmjEgsbwBxATJXSi8M1w4Pr7Y4NEj9RQBP4A+Xop1wBPa9AKtmA7eEI+7D\npK0FqMSanQMfFs3leyGEt5mnsrlbrXnGOalUyAc3svWuESc2Yv8CBqYHq0ZsD+4A\n6uwqougv4GC6nlWpWgf8uoiOwuHTac9Pr8JStIMGAWbv700huKEpWcw7hlyvOn2k\nCAWcWaGab+8zqDk3XrJvS+cMY3vswi3UQw+oaXPGmg13rMaEogTzeeVha9G57jmT\nbyLIOrDytiLqmKEl9il+CdPEENSEPrXj0C9XWybQAkmCY3kp9nmlrTOJAiIEEwEK\nAAwFAlZSEwcFgwHj1oAACgkQj2bz1ZN0RXBrug/+Mqq9JBgWmPhmA2QanCvp4p9U\nnlaUNeZKzI3J64Dt6jyJryn42BLaSZbFVHybJaqwCnuy9zQ65c7FThA7ZstusLHc\nyDDAgYkP3ynWmiPhENBoqaSLY0pom5E1oJ1i7FtUlHCqvvHBrZp0nfoBstjw5LVG\nvf+8dLeK3laQWzoCNzR88ymHjGpWeZ73TsEISin2GirPrk42i77hhyNhaKnwKPZV\nZsDg9dUxLRsz7wP1QSSR9tQE/eqQIWmD4hEJpy7gm1LDoGd7Qhlm3pJVFJgY0kgP\nQm9GDVcOjaoK6rVXCj/tO8HDrgKb/qqAtLqyQF6VT8xJ7YSD4lzTFGJPHQ/isSL1\nK5VXq3dtgToFd99pTbm/rSUVlbeJqZZ863IBjp7gUh85jEgLgJJTi9Xj4Z/Eahk4\nV7zcFlry0MC1HmFVXjIU2g3012nxdET7PZduojS2+kO6V8cbjcV6DoPforJz0Iz1\nUhWgtDGR90dO3CPp5TPKM1PbPoom9gGmAEbuqtE2dRvaavBC4Dd2/3CgbFFO29Ql\n8s94Trxtxia7Yw9GlX7ZvVQo9ROQJHcgd3ivg1dADx+S/Kl+aSct51I7iOLUhn+g\nx0pAfMRIQNPCyh/cgUbvqtK72HPcF2wSflDiCYVTOOMcN+juIsJoaBtYcMawUvAD\nrtqlO2jUtdLGA1o3QH2JAiIEEwEKAAwFAlgnYrkFgweGH4AACgkQcBQmyjWo0uLC\neA//Q1jM6fn5VmP6tz4nuX2uRBZUm+P4wesZ8pcjWHLtEc+tSIBcsy4ruZq7Kpqv\nipour0m2u1q7LF6XoKbsPYcaaETd8TaQyhimSEwIlPlkbdgFkLWdsp8fKLohR8U4\nexWq9D1+igVauju0w5pdfl0pUliuvpiDZDQHfDglqjF3SVRWSF8XnQ0cHrkh1OyZ\nKeYqRiyFmZMkaOk5xLpgtBYYfNWLGLtV9gzHrWDFXKrmeKjrwdRQKENW17tlQw0O\n57ibq/ZCdHbU+EIWaCOksWi41ZX1Yr7yokftN8t9jKt5T6UCEUtF1yK6KucL7sHb\nDuXvw5r9/A6mdcvjMtnb+sKnYKAFKDRvLSKdC/qxsoRCXZTuS0TwpFF2V+T2fMwC\nKgaakXxbbYiwBR1/Zge/BRD8mAY8vJuZYvWfw3jTOHZTt6nqhQWyQUyKcG+VFtWt\n0FpBZBgLt+e310HrN0QTfpKDme9+inxcmk98It2bUB+g7icZzDsG6ZeB6obRLprR\n4E5gUkFTfSgZexrzEpbJkCRlG+pbPbg8wkcN377CN2DzN1QWOdLz+tK6IUZrHo7i\nGDS+rOVFCX7mLzAQvaP64LWUSifo0MwcXsk1K6I7Y6QoYT+EvdShUsZcps2ZBXmG\nfc+QTpACFVcH10bfKtUNgP/WcG6Rkt0mUWGvq3UQBk+36/KJAiIEEwEKAAwFAlgt\nP2gFgweGH4AACgkQojjU1Jgg9GdgHRAApIpOgafPTYX/SSxCnYsD9FR/WVBHUtEb\nmtS7IpaOGEIY0WPR118qzDVJC9W5D66GcFpC57Pz6SqB/D16nTGUfas/TwNT8R7w\nS5lDLEXzuxXZlicf136chrExAlmoUQI1zkAKXzMGM2kt4JlwVx7RePc+6COEJoYP\nuen68R4DihhGb8BLovoF/DqnkwcmLqWUvHTJRf2phfnjMptJJeSgIl2LfJ4OIahY\nv5RFCIfzl0v7pH+0Xm8Ge8S49XoRjzLSW6k50YsSpmdE5ZETpYK4Ww1Mfh6aTuSd\nyXg6dLKQHoN8UvAP99FS648ER+8AuiIz3vhcmzuFP4gDWausL1aNyvu9TyZSIzrr\nP4ZocoioJJcmI+MnyrO7lg3X2v2EkMwQjIeqTDqGLQG76vQju2FnkYIl+9vX2oZD\nhqMPKpFojwT/Hm5Vj9C0OGsDudDjP/TEQf7q6UBd5udbWxh4F9ZcSOLiVaM/y8Nd\nDMfrBUF7s5nJ36+HO0SsI0ix3k/KW8HKgua4uqdXdXpXTYP6mz+0Fdr0xpaHtskp\nqeoZsayhfsG0ht9iVvGsLcJZyXNmOWhF5dsynPQsL5kMUcuikMqHYQEHyX+eSXu0\nopxJxJqSEwhgD+SOAlbwT78zHkiIo41tpD/Py4vVOe12vQ+z4TgSdc7tPBt6pSXL\nf0lrCA7TgReJAiIEEwEKAAwFAlmWOlMFgweGH4AACgkQaGGEunUOfwLGRw//VrIg\nGg5i4O2jmtFUq6TRDQBKCCAFQNK6md/wbW3Wr4gy1bJ+wMfP0GQAV5MF0sT9JQgJ\niIld9Z1PR1ndme7nieQedGY7XIVTuaro/ITv4Wp/OnS8j2W9TVd6P8gf9VJD+YGQ\nsPc2ziOwUYvwfd+9wxz9k3/f8Bix5BK4r/ztwx4LlkBnzQ6SSHvSR9mqTrWYsTco\nZuMA5INARnqUk0baetGJAB84j4vJvGj/R7qx0Wzfm7vfULYBdbja0A1AYRbSQmB8\nxnMJpnUDR/+GNv0to8M33vsASkuK82c+b7nQ+Exr3tnFl89rHo8QPgHPB6gaWjO8\nAnoV7rEw4OD3rWDunQ5HpdW//5EqLg/FpCSX4ry6RxsZhFgiAia5Hlt+N/pKDkBk\nugPsj1AoIV8hOrz/GRpMATLV8HwN7UZTP1Hkorc3+HGu1A80w1kHCeSI42VFR5Jq\n0vHveQcRvpoDuDT1B/3y2RRSbOiZ/Jvvm6Of/gZs/KT1FNjwuOOZQLicc0El7U0u\n0qezWEDstAKaTPFmFpNJ4qnndUFT9ME0G9ozT67aqKQ5e//MXJIM0zmG3QZ6q+uQ\n739pVEp6RR+CdPNQbFroHCWo+YLS3rfCtWI1AU6bVbcjS2214PqvmDsp1G5AmOJi\n9MTQIsn6lBlbe2HFbvdfka3u4TObttR4ADiuDvqJAjMEEAEIAB0WIQQPOtLgfu7G\nbNcXFkCp2tNSWEJM0QUCWrAxvgAKCRCp2tNSWEJM0Sy2D/0dcpmXGPQZHvgGX7S0\n+zGWDsR+rzr6UV7v2PQCNUtTLz2NfawLklv4kDRJa+A4rBnLnIMalDvinyvi1h5M\ntW8M8xcdarUeaZSKv1Psq5Nh1WeM0wgvsJbvzZlRfAVOSdo0DrIhjrbKCfjz6aM1\nkbNniIDdy5WBUxD6CbGJeORMN7M8xKW476JgNrrnjDqaZ5zVPn8DyUZdUib2nHIL\np31FKOXfsJeqbUVxSA7HTuNgePNbMaF8O9Rejm3xMRJkHkF2mU5vNgvAsVWzEKUg\niSAOCoQ2Ok4E6ztOOqAv1/kA3WOz6N/8iQmjB+Lr5xlkOiQSKKzHu5ElXqbq7G+3\ngHl94zJPKTLb4KA/GugHAYU3Tz5BC2gxYSCjDWHVq/GgcfF9bs2Cq3tF8qDkFWSz\nbZ/pRhpOtapNF0WOxvrVK6TnIQ7sDM5kRtGxI9cv9POw9XgFAB6e/nqzaLHM2dPa\nTiwPhs3hoeDOFtMrcMQrEJly14mMcBqtKp1z03qM7nq3IR6+j+gSahOUeotEIwWm\n+2QKYX1AoZRzB8UwB1k89VZkoicWU6Nuxayhi5z/QeWPzDwUA8nB0hmCQvAp8c6Y\nCxVDWDaerJfgH7mmkWe1E5gT92wlz9AMwQySXIelOGiWiqoVWUsoWDLLZ4UxKzH/\nvA8OTjHSaJEzCGsjl7joZmM83YkCMwQQAQgAHRYhBC6/YKc/eNr3HWvOmO3ysJDg\ncyKWBQJamlWtAAoJEO3ysJDgcyKWJMkP/jzVAM+QkSRUQp8970CGwYTmoJl+ph0w\nCoGxYkULPBtVigDhkxVHck7pEY4+wJ11WeykQJ550nBnmzqEzVvQ7h381JTyibpG\nosh+WrBLRXTeKs/zATuJ0WjEyw65tpVUiQmLhlVB0qbilVrp+2kLC22+lxC0eCHD\nM5kKeB9NnyaAqlinald7FShuPxw/YWSrg7SoT4dXQECatfIkSfWi0HVMgqLaIDum\nGtb1srUxWPQQoAFBG9hx9bG5k/ATdXOwSQ4ie0MaIMyGlCUBKcRC8qLkEbvMO7un\n/X0Xe7lt83bLX//KdF4aGAIlnHNl9i5iy+M2g1ZDp9RCHQVBTS3VLt+pe1lVjW03\nMp7aoh+WPZjucWqIKv9huMqXix+8puW2CmcC1Ywh1LJucPOfE3CdLJtgXtg9eNXF\nVICKZ42dJoBCISHWiHTHF3JzipaRhguF7HQliLsRBRooeXVbfnIIe01bZ/VHrb7Z\nDuSAfE5GGRI2ICoaQz7iHUTisdi+zQ9c4uV3f8msBUkJtSH6sLDgQJ15iuurWV/X\ndF8TPBwsNAMK9lo3qicEAGoJhxlkNYJ7lP0domy3lpcEHnOs6wE1HuOQfuGdd6HA\nEe6S4Cbmn2nNugXxjkXAJOoxeLB+6SaqqjvVHqVq0RAhhffiFYJIT80oC4e174sO\nl4uadXmR8IO2iQIzBBABCAAdFiEEM3FAc9jRuV2iWNzYvNWx1ksWfh4FAloaeHMA\nCgkQvNWx1ksWfh7LaA//UiNFH7whg/7VRJ7RwC3NYHKzLG7ecKYE6if9DHxditoF\nMEX6bqpvpln3Nj0cOCdkAGjC24irjEuNmTKdhD08Kkpz4ltTCA1Jci60XuXVFIZn\nVOe4da717SyNahRXoQbzwHj3aI5tF2e83dhwcXYjs0va5rtD8iK8gmp2dMyU4KkC\n5nFubIcvm0sjX9n2+5Yuo6MLKQc+UdPuAsb6JhPEEqq3uKYjsGdlFT4DdUlvL75q\nwbtnxCZiole6om1VJXk0bdzJ39wVvtFvisxPzR5xsDg0HVdHVJ+/DC/Vek//SH1T\nU+5IjydBr/7hO3FZWKXMEGVPqO31Arrd9QnP59cvE5G8UF2xXTf0YwduhT6v9fX8\nqJz7atcqgMAMSt8HVxUnULQKeOKnmptIuNbH6PWeBwwQ1okUkv1RjpYZx2JEr7qW\nVVjUhGYjuXhsNK2kv+L9NQFC0X85IGMQxLjOKn1yb+vuVKlPR8KhhtRby8SGY2HX\ntEUy82R4fCBtKOaXggSNJYsK3YbG0V58qGqslKnVgQxdNo1M6+4D1baEBp3fI7r0\n3p5GZcFF5/gqS7IRqkpUIWpDoI/83jwUw7uEV+fZD1BD7DRLUlSlWI6r48vOrpzr\nK4zxrUvxJCTbp0dKiCo7Ipplmk8HBAOJ76j2ZLfjbUK00kh00wkeVJGoB5yPsqqJ\nAjMEEAEIAB0WIQRHvH3oPUYui+0YqoYSJNvSmaT18wUCWd1H+QAKCRASJNvSmaT1\n81ZOD/9N9FqtMR+OX6BlZAnywQxVtQgDtCtptWrZCNLNJhcaMun1Mt3JyhGmf7a1\nUE1mODhJlQe5jFVZtTHpP9vfd1nUns+9cvpU/ruQi4NwJFe18/a1eJnskMpItgya\nwbrXWxgnY3Rv8EDOKBKMSPctqbbA/mRae42/p8jWiRsAc8f9QVxfC9JOo5o6U3XE\nigVrxk+KND6gSFyB8zdfpl29sw0Xyb4xWlYeBKXyGI8VvqhStDyZ9GC7UlV5fxAg\n7Ms6CnHn90PFKvnd4BMqAWgVQgbSIx0IXvsgdproC8lxQNd8uA8JEMfjMsBQjx7n\nywAkZuqTUZn6egfBjM+Wr/tDkGbZ6BoyfCGxDzqWzf51zvnVFBn2Q34emge/UsX3\nlD47R44tmQCbhiNh/4ttaHz7wIMYI3iC+qhCZ5AYZjft0ARjyJKeG9i/JaqwonbR\nv0TyjoBmsvhTNn40EnSNsnBm8xDgj8rEINpr1XL4hfVPDen/gGd/kCOEbWk26Viy\ntVkmai6RuT801NfrjCxCRbNnufuTrHGgyMufI+7x30Fv7LPw3Rf42VwPz10Ay+fK\nkU4QmETl4COOa4Bw6w66MHf7+Gp7tkuhjLKRZb24QrJcvqrC0hxKbPMzx19s07Ax\nNmOieOMLlOJsRKOdn+PAgNQbyhr1eDGePSAN+UPqQ1XK2ZXyQokCMwQQAQgAHRYh\nBElV7rRbNxnlyt8Ow3AyQJsrXzI0BQJYlOaTAAoJEHAyQJsrXzI0qcEP/R2DMQru\nwIOi5qXEfGYDT44jMAkeELN5IIj+ILPAmSX368eAJ3G0e7IZFOW/y6ODaGmKzqp8\n6v8xLk5vmSV/xyoNIYlStxd8a0qCJHpy1UoWbOBVUmuayN33fG0Kn0y5C4dQRpYC\n/593hSWleVibl4ije7E+4om9/T3puN9VCqaGkEV2m6D8U/y3UYZUqY0/2yTdfU03\nMHR44G+MNi8Kh6LkxLE2ZHePPtKEGFP3UR71vL6nmxggU8Nr4x+6dnwzWDvqmLBN\nPg2NzIpedk2djX8vHOVVau6zBQROnYXc3mcgvSluuZKrf30qgywFdapZRM0KHehf\n7CSahVPgM9KQ9kBhOIwPZRnKRGIcqwMCaNG9KzlMO3M0UN/OikqlU4UpGa9ZSGlD\n+sVBGChrJpbqcb2QjwruONDf1n5FFz4uj7WbDwjQurNhOcDsEjL1KQi9+DrxkrxL\nurxu+Lp7xaN6pblznKaJEzwwP2+z2et8LDVk/ixNqidCYmv9qVX8zicfLXwMfx/I\nbElPWC2HK2KB6r/oTltsZNwhYlzWES8uxjFcPQvWMhfITBXs0UItEjcGPpbnbnzE\n7EBTi4xXtq1EygMkqCT7KtMImD3SLqCnuZolO9Ce9Fh+fb3nwckpURFN1yTneC1T\nmZeX5qAtk6x1M1JYO2ELJPtPsx59GrVqd83KiQIzBBABCAAdFiEEXMJMAcZB2h1q\nZKMXNncuxnC2cmQFAln4kU0ACgkQNncuxnC2cmTcvw//S3W6jDW0DHOyVwf6JHiC\n5wk8PATWgwA7JCuuJBm320W24LIl4i+JnOux8UwbntU6+dEh2rXpw0N2CjzGaRIb\nBxpco/R3lW7zz6+FlLZPhEQpx7gtnq2BsnuEToZyFbGFQC1zVRF1s8Cn6p4zXVOQ\nixlhRBpgIs/CIOQyiMenN6CICwDwOlUFfNcfOo2XnloZyaIWyYR1v9t4/nS8IAr2\n6akHC41PbNM5vk8Knr2SffB+sp50TUemzxoKtKU80O3V/8Og4MffZXMg6R91Zpwh\n4/i4TpkMF0EBNWW4qJclbH7vgWPinUvh6lJw7gb/bY3wQVwg9XppwxBcWtq9NA4h\n/Jl0vJVi0WOS3M4y/HG2IhoE1+iBrhWJF+XwVjERh2vuJk8fEaaq8O/aOMSyo04L\nO5sPQJlZwaxZorodFAVjV1661SEFbM9SpAv7y4IaUeSVwbaAkO18cWRXF3aBgkFm\nbu+IiLuJeoq4ChBjojUvuxyzj0uWESU9uQaqIXlFLwVILqrx9ws03DiTPIUXpyHo\n/cNEx9WNMvYCPh7M3z3x+KoEfBCHBuLHZQqY1ARQwFrVMg9Mqt/hQlhYxsPZPbVc\n09lo8wU8OiwxGcA6wCbxGKEyejKpnckStrr2t7o57lra7TYp7HgX8NZnqm3F8Uw7\nb+66liGl7kAbeFTJ++5j25mJAjMEEAEIAB0WIQRs1i5zeo7vZNm5Z7f6n1q7eDQv\nxgUCWniiMwAKCRD6n1q7eDQvxuooD/4kwq0keU90Q04qXti6xsNraQ43/gvangSk\nMEnm1HxjdIC6qsqfhly0JgPNqVigZnx2iAe0OJEO/ZTdoWwRDfgNQKbr5KrsKZc8\nAojwuHVJXBCdFSm09b/oMgq4gwsOI+NuMneYyIDmVLPrL883aCWskvtEeO9fgrLE\nzjd54BX10VHvZW/N/PlvsGcOmBaK3WcyFxqjqNVgOmSzRVz79CkY8bcEA/cEGghV\n4CoTZ/kcNZamm4pdMZwFWQ2r65D0+7RmdOSAWHQvSRkG27j7Y5x23n/t/fdkQFNA\nPGGeCIopsonlZyRxXhxswU5FggY+w3ESA+iE8gI5kqkMGf1nnO5gCFi77Gl+o1zr\nU8FMf/VVEtwWRlmXKpYjFwEpI01m7GOJBd9h7NG633rNBqRzw/xtVqRdPPdGMFxP\njit99edv/MXP0TO62M1arr3AwqDdYWndUISBMOI6ocmXZFgLS3cB3Z4rspj6OJqy\nABXy46brP4UJjpq8GONkRoOP3u6RtmhORDsfKCJbtoKJX36ozaWg1Fczgz1TBSMm\nsGxlEk76rn0UPaMa/O7FvvyaeiN0JTFee/Htrvsdkqb4G2jkPYglGfSWQsnvDZVD\nufdV1I5de+m3vcvzd1UwtMJgR/Vmoz2q+OGKgom6z68YvQSSFXnBjCNdenhGYU+5\nSRfLnxDXMokCMwQQAQgAHRYhBJkCZhdnzUCBVRaPIEi4VzBPyXGPBQJZ0fPaAAoJ\nEEi4VzBPyXGPwaAQAJF4acA9k8Txr9yKp23yuviRa5c5Pc/g9pkyNr7+YuJvT8Az\n89l94Tj8vnlKEVpg+r+3isyVh/+R1Y5e58YqoU0f/r0K5eod510/Tvi+wxyaO3jL\noj5MIAW4BR9VQxabyUTKRq7B3RhumcHAE90qnSDi0+tQz1hLePmoXJhgdIPZUMoV\nVySEiSbSSKArOVx+N6u4FENnbfIcfLosl0LL0EwsxIwoD8B/QYVQB8vMa97g6k14\neaZ3a3kzSkuDuSTtPBSmuyL3XtW++betwW4IX3mSmMAsMwziV1Kk+06DdWBF7Z/1\nBpV7LeyNB7tsKW3QklnrvS+X1PkAv/FelazLmRt/Wx7deuBufEcMLV1IH0WF0zc4\nWitOytW5pjgHTXx48UxxVnwhtWC9UHaC3IHd8l3V1eCcqB5/pOi4UYljo0SYc6OG\n6zMhnqb8X/ZiEqodsBJ6j8ZV2QmEki8HyHwUd1BIlfYusjPa3Bcyw0gap0LpxVl/\nRsciib/Bz8wDiI9yE+5IQtdRkzzLoyMVpg7bxAGIFtGZpCWKgfRnDNE5wmvNACgv\n3Hk0ikXMLdVKvjR14EobeLqejKE10xUd6kujK5dw7houiS5jmRiUc+tCYbOucMC5\nHuTzprxu13jtU36g/W1X2tB3OeEvfYUTLDTVlB+d0Vojqlxp8wRAetV/5nEaiQIz\nBBABCAAdFiEEtW1GWOPNiVcPqH7LWm+MjFiO0EAFAlppo14ACgkQWm+MjFiO0ECF\nkRAAlOSuMMFhXrqjLQrZpZLK5XB9ppPMjnYgL9tCA2CIB6TyY0lRnR2BX3qJOb5f\nxwgy68odfHKFGgJBs2D3Ph7FFp1W3qHNl9JKNWiVj11Jbf0SEfr1DHoQFxJOgDcE\ncLJdL/kdiHKNn1hyuoMtq5Zv/Km6Cu62pFGQe1FGAPW616rj33x6OcpdSIDa9huw\nGz5LJ+f4qZb8avIBtFan//c76EGsl+fQESv92fCQtVlXm+kZGVIADcB3ILlyNuUs\ngfR5OEId4z0wbeGh2llrO85Rsvz1CVGcQpACbN+z0gTQl6AAwgfkXWYQ6ryGTdcr\n7766OEGf7c8+GIj6fjOtcyj/MxLw2fWa+ZEGsBnpigZBpcevEYI02+Ic5IGVnKhp\nNSKFquMsIm6ZPDg9iNpxGxubfI3PDJ19mFxx8vvpLlJVB5ToOrrZ2HxqEOmEuPDV\nBkmy1E4T0fUyAcLMEWWgQ9Qe5f3XHu0kwJKkbSEiCkwXqAlz1yCJNKimFp8i2hw7\n2o5XsH6j0SjAcEKMkSngf4OGsO3MOCF3zwVtYGfxxBQezn6+2EE0ahEe+fgI1hWN\nlFm9XsYrpgGJZCIYmkDsD7OwLPkLbJSHTWL677XGGTwdJr/XwaW2J1qVgr/ufDeF\nTCG69d3E+GOfE5TS4LuHOQD5hTfpbWrENhDYQhETMKLwYkCJAjMEEAEIAB0WIQTD\nhiI4nB0gl7A+/cmkNnnWKIEJNAUCWmz3oQAKCRCkNnnWKIEJNAMDD/9w4I3li2LB\n6NLQqGYrPiFL6g0QwUaI5+hRxy3Mj4OBQjFo+cz/EpORZckMDApiXuMNtBeKYUHw\nCDrVJMeGGHY0OSP8RTH5FURIU9QGnsHVV3xYjKL0A+w4cQ6eHej/N/meHjUIhyPq\nl7xrIzUEHv6t09n56+vBny0k5oqYwicyKc71VCxV8hWct0wb2zBXwYLB+YunCsFm\n37vimTAQZhptMnEh3EAelusixe8x/mqi2Y1Iws8Z5/pxIcGiHi0naS8gyCYgl0eR\nHijsMcjIM6BtZOwdQgJRUhZrnIAwaIggyhJLMSuIpy82ezdFiCN/b/HrwUaXnKhl\nogqJ7xYUYu1KLNGkMv3Pcy/pftezIGvDN3hyepXWqWTrek35dpx3lDdtzl4gIqDK\nZk0pCjjfIXavqPhM+bjF0pPYAtLEk2wseOoqqADdRQfA/X4s9u/IO9XRehJEP/aL\n11E0CHHjjkqVxlpXqle6Z8q7X9QLvaiAIxKg4DJCf38eSp+SGFAj8cYNmuJ7v+ts\n22YDaRyEUfkGrgqFxpkDFawkxuxdEiRQ0FfPh20jqgwAudBZ2rUEcjL5uIWa1rzh\nGaETFldB80qHQCUNH3IvAA1mBLshGQC9LWeTj48rj5v/5Y9Y99grYdo8nTOScIdR\nQSHHeIT7ZtVRu4hH/so69rQEHknPS+iMAYkCMwQQAQgAHRYhBNQg9cfNHkvCeBnt\nfCG8uBYcty/EBQJZ8N/PAAoJECG8uBYcty/Ei+UQALKdakYPhXgPoLovyQH9Lqnw\nalHjfYm2OA9xsKdwMHfSdO/6rG+mFZ8GXajo6zLadklPf6gOZKIWADm9NrH+z8uZ\nBoqeyFYYjmb1KNCNWId9VUrczXvsEVziPks6bkkUTHLGEDB80ILHBLSGItj8QUz1\nH4O88iElvEKUUxsJiDVHLREfIEqD+3/hmetg/d+OhBWiTtNz4KKh/yZtMwGSjfdi\n3IzUAtQN0pACS67hp5lAtGKsjqcqpd74lLgq8OISwqkjLPCQ2MQY26pMb3DM0QWI\n39e3eG/r7kvpSOPswFztN77MrQJxi7PLap6RqAtqfsfAi1WiSO47Dzs2LoZQLwWZ\np+jsaDP0VBwiNNZsR8f/AtUY2ceUSgL5Dr65WsUN4/wnOiugr20aoWgpoZnZ+wFu\n8qne+A6aLZf6HzaMZHL+nIamXNLYHWe50lciU5h2V0Sp90OoOsxjS92gEYxvjIDa\nQrixG7dH3QloJaqZEJu/qY3pZaCyIJX62E0JzYZVUIrZP7yEqKOfk53tk4hV2RCk\n6DjNiLo0eQn51pTQJXF9bWvsgKJDLoqxRnGzDIE/EZWeuahgkSwI/8OxUyC9XKHZ\n9LpNo5adiF808EkpNOErXVTYPxAR2lcI+4DgOdUAQuTXVHp3rFPRmC2sTqqBT0cq\ntmgobItyab0xEDFk2g0viQIzBBABCAAdFiEE1sqZlh2zGmJ/LFqOIFuBFV8dscAF\nAlp2tSQACgkQIFuBFV8dscBJAQ/+MGEnFtOIEeP5GNdhFqsLS2gUqyc0qI1Bbl7w\nIO/fQmvO54DHwPWUuCdJ4fCr7moqM6y/9KuAAmXUbop3wauSqc0w8Slw6zTgN9qt\nRDn84HD4SaaD/s/I63ljwsePnmcVpIIIl2BsAJFCeIHDlH9RJD6G2oWaO6/ob0mX\nsFDStpNgOcVy7XVY1lkIRSdz0J/+Zgx4rTw+paOmvjreWTEGREo2kgFPVVQFcY/7\nH79J7r/tz+01LdWUcRGbxMDsxzn5fXmfFqMh1yrDpju6ckGDCLapjYugSRtt9FnT\ng2FvOYr7Y8pwFla6iJYUQalyODgwAlCGi5g6Z4y0epVQsDlEIfCQcBUPhNH5ESzL\nmwlaDesbdCe1qQM9x1OCWl2KemZy/XLAVyTT51r0n98oSdtGDmj8PmveYmJEKVFc\nu16cK1aIz7xhdwMJHKC+esbP5MtpgwrUdH+zZm/gBvVJs4OocUuZskdPYnByBp7Q\nWtga+vNh2OZ2bdDaGAfryj6y5Amu8VuNAfRcmzr9OHW5kRJEfGkIto1v59orgHBh\n2D3lyXVtOWGs0xSjCubeYbsXiGrKT1dTzGQW313WOJDSEGoFlA4huGfyhkhD4I9J\n9JQSNdb72N5rSLQq+HeyBvzMe/63N3Gey5l9HfDxtHkmiiS6+4l3mDBF9PZqnyOZ\nt6dUq9eJAjMEEAEIAB0WIQTd0rUz1Fw5wtL8jSt5Xv7aO9xW3QUCWlT6VgAKCRB5\nXv7aO9xW3fC2EACRSk5ar5FGPggsBvT/CnMlRfcjbbgHTN180fpZgKXOTEnMZ5aV\nO9C8j2IbXKu0SY9dwPqVFJnIh7coiB4nr02uzHjiisgIruT4HSn1uAvs9VtiR9Yc\ngYPNBVla55fKsKFccHSKe+CNW3Eja2Vg0WQTfe5420ly+DtvNJkSN/xIexFdkB6x\n5CjVGSkYlm+GqVUam+4oZyVKM1PTMCJhT3Crsz8DxMXmz0NalGeyVWqyt5prcJ1T\nLVvayC/2/FvLsGigwfINVPKoAYerdoh43mup23oFHZBNtTbAHi5dseML59KGHOAH\nxcBgndEoP5kjJo6WgRsn5ICouHpVWBZEQJVwc06pqrDXUvaCqwEbL5K6wFI43Mxk\n42EQafNFlQ7pACkzJksALP0g6OOdCNDgGyImHnJzzz9az5Mrcg4fiP5kOE95xK2l\nuY8kB8+wYLOkIf891LhRn6e8ZBI2eGm4GYO+Ls1Y59Kdfv5Gfkz+NPe6vle6o8Rx\nSUwgQJn5vLqMc56AtjK7YajFTmokmt021NWow2wiHJufnbqIgXkLHwFPp5RNVmVL\nGz1Lqhf36Y7Nm5VEGjpxcfJH6M+Zck2LEQek6ddlzZiZ5MfaMsFYkOcBUF41dQdA\neoCK42hZKIH/GVY1Wh7s3jmXG6QKuIOK7MS4W/aBKGBI4JzROVrsLNbAUIkCMwQQ\nAQgAHRYhBO+sw7dTUnVXGPmVznr2DVSXJN7vBQJaI+CfAAoJEHr2DVSXJN7v47cP\n/ArG472N3pb3jbNCV9vtbxDi43oruvkHeEpf8AVJqQUTdv8jWqWtZSsyPMs95JDZ\noDGQtIqvNhDpwE4FPp1sK28Pf/YA1nA9WaIN0xvQ/xESCMRD6EoTVxvRboEiwuI/\nCvG/M5zrCHHQyjw62dgF/CLyAuu6ZwKLdTeRQqbPXpHevjYS11BPjVbXu3N6yhs/\nKm+BSQqFtYelfF7yx+omT6SLqEZFBr4JnipGqBxR24Sk93mcgrot7ZPih6s5/bSF\neNrhC9ksZWIEm6WqszzY7jH8up+6UnoCm7QUbxBYc557qPelCxiuAbOxcwuIOoeA\nms2yCDL3cY9ojIrJ3RqymOY7TH1fVVYbh4NXOmw+jwfHSM+n5q3/JT3xDYzwnFRX\n/lMksp6N0xF80iDqprbdohyFl/zPruIOsOfrSu8s6tQ87rFNqdEIcmZo5NLOraJt\nrYuPrZeXA11oIvvvpA1YNbRY5INk4oK4m0fcpi4H0h2JeX1e19qlp86VQ1Yp+JDc\n82AieZ48GUBWi+KFpx///iLMv+wyNwn1xEXDxDpr6vRs0PhrrLm4K37izhJxzUIh\nhh5ojtPtVLain8BYaEBO0/+2P79fybNdM6gevUDlBcFcXtJ2t/c7YFoc2ZBayopS\nuSkdAQ2PbiHXVrxRSi7IImVeCn2D6Ap9sJ0IUMOH/K+eiQIzBBABCgAdFiEEE6zP\nPtTjs29ib9OuQVxlNBO0NHUFAlquaqkACgkQQVxlNBO0NHXB2hAAu0bR4Ube5AWI\nCIHcIywmTzWxFesJQa0Q9BAQy48IRStneanTEALOEAtwF1qpoWaxfZNkwghyKReX\ndoEAes6lrarUk5L7f7/2wEgkY6cUHavcV1dgVyekLruoHOttPvoyJAhPTRRefZ5h\nlDp9xi2CeCnI1CFpZMEJ6rrlFYBDo1fiL2ZBnnEk0kpWM4Lex9Zu7YeKUyeMjOaG\nM6+LzeENnvwpxC+eauGjvLUVEx1JvGi+ht8dUT29Tf8I7iHSHtEtbf8lnzs4wepe\nn/8L3PKHbGnId0biw/6c+0PCak8ZspIViZ7LGEY5GUJ5HQRP7KOI/qFH3EdpUl5o\n7UijN6LFB/Fh9qkvw6YC7SfV14rFHcOwQWqwAt7p7Q6nuKUtJh1isgpIgWYAP1rn\nkoU+OjXS5AmvMyPCNMg2DRxTaro9uOHIBaSLQTRSTh5nBCXGX6Junm8NLV1l0AIe\nlP6W5iXJh4aBmtchWD9cP9Ntg20gSPybgl8rgZYFF5unyI15xM9elyfmBkum9US5\niSZbCBWxG7Ajuo+iN7JG82UB90rult6WZfUZ/pQwXTGmvzyzzFN/mcH+dNQx0SBA\ngtfotrxAOp9cgJkHKYx0o3Pyr8Jsz5Nut7l6XybV7jgRrgUPpf+PRTXOZuLzi/GK\nAPVQjRgspi81EXzrmTTBklKbaSMwoOuJAjMEEAEKAB0WIQQZGDXtDq7GNipHOpJc\nG46CuAMPygUCWRn3aQAKCRBcG46CuAMPyngnD/9lmZ5T9PAIE52ohs8HOSVNjNsr\n3Ircowy/GTVGgmErZqTMjIIZaZyLTaJvCRVvdmhTLHDy6DIK3idQ9Cw7h9nKBwIr\nstReoRudbjVV1qKWxSxdXmMwGGor1jLH5SQDeW6tTaVkik8kOaD97mAmdv5y/eBi\nMiAJKgJNJpxW//m4QpKg2/5WTome/fhzGPmVbnh88ImN1SdjhvGE9AsbMOcRTHWt\nhOc4fABjpCXmuWksJU8AoUXa8ElMG/4N52mSOG62xyJw3FHU8lnI/ojgNU8Muk8B\ng2tGaiZEHzm7k83Ksq82vld0iYPZONflytrZdhGm/nRnA55/1/En1jKUP0lwWZht\nWdAfDBxVfzsaMPmZTLBPQAYZ1EBprmBh6JB8b35Nsa4UTaqUPjZvD6uuz8ERYoS6\nb16LUlrb0yxj4pnZkuFefPNoWYe2Q8/yFrDPSzeZYEECNBmnJ4NeJfYgpXEdQgO9\n6xhmTUJecgcNkTN1NlXtjVrQgldNM/+6EjWzLgtnJRTjuTQAyzp1g3gCeFc8NGX2\nTAOS3ebNpGK+3CP5D1/6Q77ohpUTvqAYsbs/bRSivC74Tbf6yltRUISonPvhANgV\nRkvxYfgYZ30nAUQEM70wPSIMzVo46SVlaO+uDn0atVWn2VE6AvXy20iiJIvqlNS6\nN91DrcgC8LAazV+dtYkCMwQQAQoAHRYhBHKpf3By3c4oBY3vMDI8nxeEvd1DBQJZ\nY1XMAAoJEDI8nxeEvd1D26wQALphSj0pcC79ES9xVqzMssJE4ui7VODpmiqUYLEs\nrAS/3BWm87a8KFFb6vw1oVeZNV11Jsfv42nu/wDhrxmUgQUsaR6KxoKfYzIOHnT6\nxDA1kgPgb9qIubf6KksvXsubhWhwLpZiFvavK0H9ZOBpQ9hPN8OEUyOG2iIwRcJl\n0G0rFkjaNYvnh7NAb5t9B9QucH4SqD0Yvl2d4/aIA8gz0KFODPWG2OORiYe77LbM\ni0o78gZvD8gEXgOD0tTKG3kiqNgf83m83T8qP5jCDB57lUBubmqAox63Gn4+qt9F\nDtEoGyjyKQ1fTNsxF+BqnFg0pKCBiWvfNBz56e/SuYzy6NLNHD0vGBSXx3qAYTmN\n+fdfUJ/yGjM3oB7WYzO0JpRAP0wZLEMH5XDekAVvk6fhf0LKqppOoD2NbpeeZSgT\n4p5X6lkg5DtRWMHwzZR3HJfW6RE693k2tSyMBlMwf5OTiWINR9K5bbAkt4HKY9wl\nSmpqW10WdYdO+aWyIui72/vb8aU32OrMTMSzQaudEVY9ll8V9fP7y6qUqdIESCX3\nSQ0d9F5vDC4T8YPNnWW86w6Jn7KAv0mu7g31iBy9EljSWyAKd4ZjV9qJnpSH/WBN\nJt3BqWUTsd0s9MqWjzCiQzxsQsWMRh8yVnRUKwBNZPoqVDgtleiNW/YhWAlQpTpX\nrhsuiQIzBBABCgAdFiEEmy/52H2krRdju+d2+GQcuhDvLUgFAllyVR0ACgkQ+GQc\nuhDvLUgFlRAAr7F9PhffSHCco8fTPtjVtwnndITPazVHi47kHpsorRfnB1MsyIMn\nF8xZf+OWqPIe+pTHY/bGl7hYWz6R9sbRxoWDpsrSt8nPy4kSWCBPusjWOZLYtbgN\n9+8t3r/fcEGFwOojZhhJ6dptTNVU6D3sWfjGjqC4Q/ZZykvz+hHy/cU4Q3QiWWiu\naPgIk8qe92+fixqKJH7mPQKSIrA4q8YRazplP8WJRiy1+A5XeORcxbt3Gm3b8lrA\ngRFITp57VYnfUDfVDlkGLugI2TBBCiODEqsPWMPTxWSihhzsoYWtW9LsS/GOcF2I\n6wAieLo0QRrNxU4fI6FpyYb0L8UdvPxvyBfaLBtNEdtKWeBhB180ePRr1nDqhFs5\nstrVDMAAGmhDAczlnS1dqcWFUzjtUUDaAe0A2J5sYGMFWdKQaaKfS9P90eqSK7ax\nxUQAScfSDAtoxPVoD8Xhl6OMjgUlkElScfzD1SwwwNVW2NIabh9L4FoiaNCB3Ndv\nk0dDtGlHRV8BUhTu1RpYAB1Ts1gXbdkzqx6qh842i71iDHWrJsQTyr2aFCMl2tJ7\nLLGcqBtuvrRK/RMTqtQDzvan7zASbQEzEb6keLiQqMjy6OtrkvstKLAxJA1AYwoA\n7wrKY/m1BZyv2Fgz1HleFNASbRfeJDVDAquxur4ooue2CvPa/1VJjcuJAjMEEAEK\nAB0WIQSwJ9pJBXmBWkENQv2khaDtUbi3xAUCWhTPlgAKCRCkhaDtUbi3xJ3RD/9T\nJXzx8Js1cLtV/iWPXns2ppIUr0sQpP4iaF0uLzlY6y3FUgXFMq4/aMkdzxaH/5qW\nH5O8z4GfVRJ1hE2+SGHoWn9YvbDu75WCnRH8wgoKGXsmXgk1S1eJHjWutZcZj5Yp\np6Q5HkDKBSqYZYQxQSbuTXo84a2xTr58mJKBm1rh1wXhdlkSj4cr6ZBBB9+PQtCj\nCfEPV4dfDirPk0SonOuKw5hgyIpI8L/wcSF1M7xXzhT7mdrEjdcq6C2ebaZ1AnCs\neJJpqL/jiEWOi1CS11XtyH8BoQ/cC03Qy2oMrSnGVR+DIAPQSVyfOgdpC0VfN4Zu\n8GaatwVlBl9hz+Zv7fQgKmEPd6yPqtlXn+uyROtJdyimlYiin1ys3JG4xJPN2ATE\nb9Itixv6quoyWCjpklmxgqjjXl1NGaFmeqonqwAkKV4BpfLVsFZye56oh8PCzNf/\n0Xw6jYdFzKGTEPEaRBJy76hohVu7Y4Dw/eqqkyGTg9H0POQC69Z2UVxFK2QtNeVH\nGKfpacncsIfUJg+AFfR4w+QTJvdtYIJajEDUVal+0aOoDTYR3lTtOaDrW5xzA2aL\ndmChgfcCfaFX4IOMItEEZaX013lBwyy7iDis/UJWhizoOpFvuzPX95VEC6Mb8pTK\npriO/r5bjRCi3LNlrFBl7Jk8xLg1Zr4wsFsjkzT3uIkCMwQQAQoAHRYhBNwe38uA\n0tosjq6uIkljV0IYaftsBQJZLKg2AAoJEEljV0IYaftsWz8P/iZMVF/C/0kUd+BM\ndMjTATrDiCEyvsOMVjbtdnZE6daWOCWwGUIFs2gSDTx6HCXni+qmPzU3KxIwezKM\nUq4SJY/KZz3ibEJNZQ5P4HKPd23O8RPl6sC3LDZ53dmpyQ7FoFTRcE60tlmxKmfQ\nJGSKvDiT7Bw8FXRLv1kua83zmOnu49jxKMKW/Mth71jDlcskWgoM8tAO7H2t4X8E\nI8HmspBjyWD4QsLUNsKSMo6L9OKRjmF2lWUZc6Cvyopvq2xAdwISCnVpeRYjxMkZ\nnXVws17eXRFKmK7RzOmAYKMafWeZ75jmckdisQ/99Jjf6/49UNMDtvTyIvnvrHs8\nloQG8pXQE9K6ST7pf2UESBr/jRriO2ci06pUuaB0OaZirk2afGeMZ8W6sLTn/C+N\nE456Wm8yu6lQ+6zeeFi/w4leb3ZplHIlO6z3aTiS5HMKHgpRaQdZm2G2lD6kWcFs\nN3fP3X/jbd9138BSzfg4hxfXQHQ4C6CEzZD2JZQBPuM5PYWHsowf5R9Jb99okbus\nbvtbUKkjUUQL2OXg4M2oy2YlZQU8Ppz4hNIRr0Mx8Nx20oZBFeFSdGtcmtJnN+qK\nmY0229H+I4OcgeQE0IxMhDcfjpw4n5h4cuhqz0nqWJFly4Fnr75yv1Uxt+IN2THG\nrNF6tQk6WIRWf/Nqf5BB8AgNERLNiQI3BBMBCgAhBQJUjq+6AhsBBQsJCAcDBRUK\nCQgLBRYCAwEAAh4BAheAAAoJEE4sboeTKYKQsBUP/jPbrHHGo1G3ndP+Mayofvd1\nPNP9q995SzNFqHgE3TWHUt3Q4M0fSMV/iyOZ3QWClzxvs64LcWn9DYRJP79ptHOL\nppCYA4xn8SwMdpmMGEQqyiOdorIyvsAmV8N6BJXEozizRAm9WbKmdB8qkpcb3ZcO\nH9L7cr9mXbaMzFnfyrPpPYAHJNxoXjy8xJV/TFfQaHG7mNRGPBFfR7PNv1LAkVR1\n48Sx21K9m4yikojHTPpJ5R0Qe/zLj4Igc4lqpVNjaL05s8uDy4e4kXzOMnlZiF7V\nQeIwxJsaxiEagwQRemAXQT2NEwCOwwT11kLdyBT0MtmLmoS1gQiH7FELl1Xb8vuW\n5I/HBo/3SC6hOUIVLfgSNtqcnE4J9DPfzs91UlDSWlQgd+67CRN+OQLuJkaA46h8\nkN9ZzjVxw23EISB8Oq4PiEtOztk+gGSKHEmUfuTAQ+gHY0KimWWKhaAB7wy+w07Q\nTbAkd7e8fkzOeyYplJ+fxOhbwE1qgbU/lwmSX62M6qKRDa9a7VLfGyty5baCMijB\ndEiLxd+S5YTa+wP0Iia9rNKr+nA05rj0P/Lw9tSY95lNf9siHqHHWPpWezkUax4C\n04GovykJfrYMH2EAOg87wOQeUTYBGp07JddCd2HhUsutN/X6CMUxGYPaFcAdZr5H\nz0TZVVM8oWYPN/6uBsepiQI5BBIBCgAjFiEEooPHf74rFdh+9Bbpt+RzK03nRjEF\nAlny8XsFgwHhM4AACgkQt+RzK03nRjEFiw//bEYyOKb/xs2KXfQoEAi0BIXVUpJH\nS0GDcxCf1SFIJPe1ALIG/8uLJJQj9wxJsiZ6mBkNkFrdQ61WkKCkmi9flWojdMmW\niB5NrvopHARMEPpLygQJnyBtYQjDsbBc8aFeojT7x/KFB/VaOaf21CmZsZB4rm2f\nua/mQnvXMMoVEQHkAhiZTH0s7RXnlTu+EaUBgJtwO+HNcVJwsFJ4Q610P+cnuJ38\nb4d6IC9/5ePPieiKrKTdrTZ54nHkoGurpRmuG+YHi9Zz5UZYR0vnTuCGJuAK3vgh\n12PW2ruDDgQU9Gf9VxgfPAJa3Ur1zFumO8PcI4vbA8Jh/TvE3FgfZquHdjZ0fH7f\nNE71MnKmrpFlXHMzVw5F4hrAwLY892vIh6iwZLi09Ex2d7wz9vySH3+aF/wfrs+x\nb1O5K6JeOXm5ktf5vLXWZWBKq3elXO1SMgm0rGYSy2EvFhWT73WhuybTL3UxWL/I\nZAbK7QKrb7/Zmm9rHW96g1wUq10LZWW+zECn6Ps4paNRObtkebNKK5j+GBGs4z4m\nt/bEjaSVZ/5JcBH6u3jqaJ8zC87HAjCeRxb5IRuyPYTbFBRBKvVpdEshKZNWLTu6\n6gTwTzD8787Rz7N5B0693ZKHpDu0PUB/g2sL1004FM17xhJnu4/WU5Ka5LRFPaxq\nZkpeKtodiqboPlSJAj0EEwEKACcCGwEFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AF\nAlXdokUFCQq09AMACgkQTixuh5MpgpABExAAtDhyC2qUAv21Sh82raT8ypZpRf+w\nAaKlko+kcq9IFSBuaHA+weupcPwHErb+nO9wKSjjxweBHrSW6Y1mXZiHvaPc/xrN\nV+Y3EDB+NcvxCD7rYNGDvD6MSkUyaS6hXuEg3euELF06cGDq0/tXdW/HBFisSDtT\nmr4kDMfxrSagvfxOUyslyQDQ6yHopJ2nmVOLCdAxi/WOYwAbMiSjqPkjXQVDESik\n+VNn4xavZhl45NnTbcaO50Dp/5lOdEwNX8gwVXFZ0NWyEWIGvMjlkHIxKMn514gG\n0Vtjfqa9DEVgb2799nxGRiOculqHbdPaoH+ZZ04fO3zu9SpwDepqM3oeR0MIM2Ll\nOOI6rp49ydb0ZY/2VbAMH5pw7lWukVB3h+4si1YUYKXhHg/MC4cptrMS8TVFE5W4\ndN3X4Gm0RhCRbg0eZ1lOHJLhtLAE2ZTwhiLvok/fTYTgkkF5bBscDqKVZMQyJoYi\nni4mZheF0OcTNSqDvZ54kc/D1paBveNBncASRAWQmUWniUWdOkdwVZSTzJ5SWMzS\n5XWgu69rH/xXnwM4xI334NUF2dvomkuW4h3agf0Fju8x1j9/YR0DKwk98/830+DS\nxZQnvM1+IcBBbqGdZm4IGkm5WC+RR5b8e+/0xSY2C0a+J6xwy1lRTYoVEZ5TgA8S\nTwKOok3lP6pLLMqJAkkEEAEIADMFAlftbLosGmh0dHBzOi8vZW1pbHlzaGVwaGVy\nZC5tZS9zaWduaW5nLXBvbGljeS50eHQACgkQqR9xEdmvC11/uQ//TCWZ1VcNGSGy\nyQ6ak8C5wSJ1Z/H4KXTyWk0yY0MqDx7Nxm64Dn8KdBYaj7WXXz62FKjXjVqY+BUI\nEpJfOS0J9uI9N5xwLHOt7OEA3Fdz2tH15GnTRgLoyRhft9kpfjaMhftgrDnb8LT0\nz+AFXo3OI2RATm+utYMSTGITd01b/7UayAFXSvhUVtDZsJfBRcw6UkUj2JV5otaI\nMbxmzh04NM6wQQ9g9f1jKJaKFEWChFS36UHbRb8S6uL7R3ckrI9WqHXRVezgflw+\nwWzKmCiKYL17qylfuJ2gdyhDaZ7fVCIOxrpb5jlN26x6vzgzD91t7G+mZCBOSPSR\nyj8HjDxYElyGEqFeY+6FKAswj2CKjrQmYMRbs3timD7D6seaxtWELfuEBDf44Y+7\nMhrkHp9WPTn/w7pGLfFEe0Y7zIeZ9MOZvy/Vy23gsjfeQXgKWfr+T3JTG1IumFwb\nOvX6L67IWcUt5AGIXx9uA4SPYE6zccJyg4Xc3nlmYj39ZiJmgVGQrU4PFDqKcusX\ncpCsgBkpcz6zSKek/sHYz9cUpu3GtV5UZ+u/DIt+N9SJLdXZF6DGeijt+FWkuW6J\npJ+sAw2BBUSYVWPBA8jaoKpC/5Be8bvtrR0FgTC4XfzW49kLgVsCcaaGogN47CFG\n1wroQfVfx/g7qJchxwr8g6ZkpCThzwOJAkoEEgEKADQFAlYZCWAFgwWjmoAnGmdp\ndDovL2dpdGh1Yi5jb20vaW5maW5pdHkwL3B1YmtleXMuZ2l0AAoJEBMY76xfu9vO\n6cAP/jFXHWEyPQoEWLgNxOZ/oI5Br7UUFbs+MpJkFb2tLh+KfJybu35xNi8vPFt5\nFXmdyE0xJNNPLMGbqQ8/kh8BFsSejRN84qREbXHhp5B2e2rg6RN62sWaMTYKHsiS\nW+Z7GxoFYixw1r43FA2JGNPj+4TuE/FvW83KCTzHsRZGyNOKKzhWAWgEJjiqtzVg\n5dXd7dmCWQ+on1/5npw3+zErythQqv+3vaaRDACAEreHlaRuaAY+kYuSMkr6F4eM\nW6Zt78LC3ZxfB2okOmdqI7+zQj82Zj3OAshi/6vS7po3slcuEVjeMhzaF8Gt6Lyx\ne/KZW+Vf2AB/FzRMibLepZV+v8uOwrpoeLufrscqoZrkmjc00iUeQbfGnwUhvCH8\nP1+D5HE0JBOsdF06JOrewFocaMNg1TuAqmrkjUMSwL5tjQPejOHCeg8BK2ULAOq3\nbB+E0lQ3L7Sc985tGL1jQpgSYLdNw1IncjJCgHBEKDybO4CFo9V37An5jejG77gx\nNX0K81ErDIJw6oeLpicQjR3B363tXNDzhHBBmyjzafimsB2pE6cajMz3x+bUzSL3\nX7yGcAyWVkPIEir34u+z2+jfwfnK1XX2TjFlXLo7BtM4dyooeB5CM0s5nHjfoDkD\neazxd5lKkCPeJMbG88EZcC30/FJSOhtEpvnG5Lm3ZhV+254biQLtBBMBCgDXBQJV\nAMSiBYMJZgGATxSAAAAAAB4AKHZlcmlmaWVkQHBhdHRlcm5zaW50aGV2b2lkLm5l\ndEVGNkUyODZEREE4NUVBMkE0QkE3REU2ODRFMkM2RTg3OTMyOTgyOTBLFIAAAAAA\nGgAoaXNpc0BwYXR0ZXJuc2ludGhldm9pZC5uZXQwQTZBNThBMTRCNTk0NkFCREUx\nOEUyMDdBM0FEQjY3QTJDREI4QjM1LhpodHRwczovL2Jsb2cucGF0dGVybnNpbnRo\nZXZvaWQubmV0L3BvbGljeS50eHQACgkQo622eizbizVqrw/9GOt7yBURbGtG2Pef\nEovIK3WJJHouIEd1q8FtaPSbs+NQfXv0o8F1Kz6S1J+/707Vx5dQZeHiyRXuMbJr\nBmyENWGx3P5s6eYmTMB/dAE6odwXrep13oOMYNlhLlsnKNU7vM8D9kzWDBI5U+Gk\n4LXjNs228B6MgsBjYzRAbUfP6e8JPOxNABWi+zBnMlDOoa9XgbcCsIxQ5FaGIVpV\nJId962IwG7wgBL/ZQT0FxnZ8e9+KBDHhy4weZ79mm10p4CdtCw6v82Di4Q1HRbkW\nLrBukt9L64OAwuiBe0K0J654bu8HZujwAgXmJjrjdw3SwaNh6Yv64IWwkODCQ1Li\neF+fH0j4fDrR3se+kzOTMsUceysqhwJ11JRJA6cUeEEwtMmeBNf+aRl7gbfEoPQk\nmkEDX4/wN5dZOuOimavjghn2xLYyEgff1na9WXHcIT/zLwscG7Or4XEt8iGCFcmj\noWuZQZbjGYrvrR394ywvKf/rWAOeFBkQ84f1ErizXhQo6/28bG+DpjmhESIaxXyR\nDpU+qgadWyjo70s8ihrl2JDJVIYjk0Y7RukEndE/Z61szeg14QccsShdTwptyoYu\nRvzCc8ooeVsbLr654P8HGz46yP0VzZ2eNv65+1ZdgU8qO40276Lhr2S32LxYBdjF\nOATANKD3I4lmmHfO0v/dwJIULtqJAu0EEwEKANcFAlfVSBIFgwlmAYBPFIAAAAAA\nHgAodmVyaWZpZWRAcGF0dGVybnNpbnRoZXZvaWQubmV0RUY2RTI4NkREQTg1RUEy\nQTRCQTdERTY4NEUyQzZFODc5MzI5ODI5MEsUgAAAAAAaAChpc2lzQHBhdHRlcm5z\naW50aGV2b2lkLm5ldDBBNkE1OEExNEI1OTQ2QUJERTE4RTIwN0EzQURCNjdBMkNE\nQjhCMzUuGmh0dHBzOi8vYmxvZy5wYXR0ZXJuc2ludGhldm9pZC5uZXQvcG9saWN5\nLnR4dAAKCRCjrbZ6LNuLNZzfD/4niHzydJAeq0mKa2IrO2/pCZJWCC6wH47xkuQJ\nmGyxw+PVRxEBXWNMm2swt2vwuFVRt7ljLWQlEUJsrWQlmEoCV0KcNup7DIcLrJOR\nsHp8cLdx3PCepSvSz0qApkQ1/5iOhK8UsLCKrNg8/ErMTRxeMESlzivxB5aHxqSy\nT352vTAkic0DHc3/szgb84XufbmHc22K4zdZRhSFh5Tv3Mk/xLH4nHYWqPznoIeo\nRV96Jst0gP3GQ2GQNmzqaf3fvKjNUch28B9WlcvYr1vRJkY76degqCDRaWaClS2F\ntHUNU1qXF07uwFpk1CqkD9+7/ocKo4gJlXOHRgGrtnDBCLXmaNNLMrBEBYekMt81\nfppo1MQQe74s9CGWDQelhl/TBzHhD59wjr5Q0fm4ccM50GkWcMYafUuLV3F7xIFb\nhuUtzSSqONzDPwNVNmvfxcsbQpcd/c50gFrKOFwypcTNfogd59A5dEP7vO153NKI\n6tiZMBvhfSSOKasI1zYcXimLaF211BxKJkGSqgko/rOGqhIXPCHPmrTYaemBIRHp\nvp7P/W1I9dsWhkIkvxCd1/+TJTAL8malkQS8F4X7xpczcmpZTBgIUKttwfYrk0QB\nTbO3PWmpDQAdDsUL53cO2vkQ/kYliJUDxp0yL4DQ40yEWqzbsYJSCuDWzCMqMfj8\n9VitT4kEPQQSAQoAJwUCVthxySAaaHR0cHM6Ly9taWtlLnRpZy5hcy9wZ3AvcG9s\naWN5LwAKCRCpk+cVbg6ZI2fbH/0Uz0bi9P78MscBIEyQKvkEkV9iD4v8jJcBzbRm\nvRw+RJ7aDRsPfnK+AWLfNGR6I0oqF0Z6+Si4xSME2Wi3ycaax4n5oeGXz+eM2/iH\ncM4SPq5hyFTnvqla9eSbvly5e8y0B0eONP1XR3/2onokOrKEyHHxtGrxD7V19siA\n7ZtikPJa5Eb3hjilhy8y98IdoWNksHtge0sHrI2585t5IjctXNrgJTIQzTn9aBU4\n7IA5LmYTsPVCOfK5C1dK88IjerZqiBn4MeJ/xYqiuSHRaEHrd+/c5vniDDPjaPBx\ni0xsfRvrRrEoVtuHZiPRNTyAuYoRLKsjeQA/CJP85+0rpdtusL/ImnSDZNAIFLyo\n3D4mpk7ysxlniKSr3j9cRUEq1JLE0ICYjP749H4NrTfjGMC8JLNSfVMdAWoyUXLq\nemh1Lxha3DV0lxCURDCjz38L6pZC1nZikTLG/GIwlaOKJQk8hjywkQpfeVy2xSj5\nTIHc1bPYtAg5iGBAP/iiybUNaHnH2nEKuDtuoGuzAMmqXFPt+Xxqn3D28CuQthAz\noN6rUi2rCXq/Y7/gBW4EUzO4HgQyZ7ihK0yWIlnB1nU2xZEdZ1azb829f06x17y3\nTSm5pfDbLKHWOJHC0g5B9txF5VlBxL3hW1QeWFI8no5yy7euGK1ZCjwV5BNX3oY5\nRhW7HxvlVhcKocN270YwF3gA32za6Lq8quVT4VjuJmEXXk67XvinAypavEmKqM35\nlBM6VaGwxjRBMCcDMhRYXgA33hVFkVnj2Jv8XcAHDPLEGcNU8QFDTyZTHW5ukGBu\ndndo6OL3oPQoXOdOqGFXI0O1qjSv0Pl3SLboYnWTRqZRDb0xfs7QvT0g4+eHj14A\nHfsQaVTn6HWDVfFfCBdMzqPX6t3PS5udIlctq9FXMxOxS+G54in7agDjo5ay7kSc\nwvwZVpbFQUE9rOJOzqCNrB60XhDlz7E2sk3yfohjtH4/hTtmy7eI5wFjuTohhuTg\nvcK6SO0XHqSxV9piwFjw8niy5Y6iDK+/4idPTuaOn53MBPJjBV+p96FX/ScfntAJ\nl/5LiX7Bju0qTuY+cw83Lpxy5Ic5jC82+7l9dcnIg8WENBJgEjU8kT/Fh3jctriy\noBypQa6m67p5xClyJcfo+oNB9lWBZRgfDPNtntkR7kSfKkt7CpCFlmkAMg783mGx\nxijtYkbkwuLSCRs2NaOGgKkxFk2PkYHvclW2CxSPdss9o1q6BQPOi5hgFPItfczx\nFgS7XtPsm0d461qGLVzmgxWr90/w+Rg9cV1qVGcOMYMnT/G3ind4QMMhtjsSFuuV\ndaEkKzxI9pOEJ259nuCSwe2Vtcn2Pun+ITsCcw4XdevZbYmoiQQ9BBIBCgAnBQJW\n2HHJIBpodHRwczovL21pa2UudGlnLmFzL3BncC9wb2xpY3kvAAoJEKmT5xVuDpkj\nZ9sf/RTPRuL0/vwyxwEgTJAq+QSRX2IPi/yMlwHNtGa9HD5EntoNGw9+cr4BYt80\nZHojSioXRnr5KLjFIwTZaLfJxprHifmh4ZfP54zb+IdwzhI+rmHIVOe+qVr15Ju+\nXLl7zLQHR440/VdHf/aieiQ6soTIcfG0avEPtXX2yIDtm2KQ8lr/////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n//////////////////////////+5Ag0EVI6v+wEQAMqjOEpP9zV1se4h/gfeSKB2\nrpWy80aUMolBqRtMm4wrFVFzie7iPYxSGBrCXO81BaJQR/kILlf8GpTnB0vXJuGE\nV3GxeCQIt4WnGKbV34Uh/S8G/1d0H5nkO/jDvQJ6bDiozYeJfJoqW3ATJzRTtk3z\nD49aannoz73IOBjBafy+Lsa1sAS6BoX1zSO+WYrkLSXpcpQsyv4Ky1hF0zILUDrK\nF7dq9a7u5RBebA8tSPebDPJlJhTSxP0rDYuYn7A5UllKDEh8YW/0JEDOvGXghmfb\nazwViifFT/0PLu93ZEHYT3NHH+Gd/2Sy9OFyBr1sJX2MRrTSstXUxMjaKqwt2j+E\n6EUxgMX+RPSVJqRyTVE6ydSEiYyptcddtBeapMStuVZlsdK6l3H6IzY64VCGeFwy\nXY1HHUM0Kpk1niHm87/bJ8ZmOQmKDVsAplj0kHoWtf3xiDVtLVWJMwTVTfICZB7F\no5frjmiW6r9kUbgIm3a6LNt79ev6H7uTbRj+Cgw7dBvbyP+DOtyhRWYgS220FAUF\nRvjLz9R0Q8rDX3JYXIwm0FEoMAVvp/BPH/rQMZpf+4j+aHZu3WcLIfW45Ok7u8C9\n4vFGcy9Nk1V5jn1JuFa/KD34vElXkM4aFg3+szAmRKIMUrEoBm1lmwG7nNOhSJn/\nThiwENhWoQEMl3q1bdQXABEBAAGJBEQEGAEKAA8CGwIFAlXdobsFCQURWLACKcFd\nIAQZAQoABgUCVI6v+wAKCRBwF63O9lwgNsnqEADFuK5Ql1CAt0AvPS83yUkEOHHj\nxh2pK86fYAwAOPr4RO8LehWGnVXi+IIjgFDKO5e4bQC/axXm57c4qZ4IUQ+eIcDf\n6zuO3SSa6GcMildfyQcXTBW2sIjig/ImSdTPsLsOyWwiprq1fPCyARYpXzNa4Tiv\n4rTypP0YNzhPSnjrJtAEmcBm/X0lH39cn/PNwahyBujGnuJTnwYcCMzXJMP+Dnj2\n5HvnmPfywEdkYSlFQE/jtzLIX9pcSsdFcZuugZQlyYemPnTZRiWTJx1Ld6nFGe5k\nGP0bajCd8AbJZwjmtIYHhcFuN0yrea0zDMwreVaBH6z1oiStejs81CsrC3c1vkYj\n+VZ5II8YNXxMxCnv8a+vPkQWaLt0ayzgvpl5EayihLmdMDgZpBR4hpe80lzv+BRV\nGqTX83g6+LJ/MlkwG0DzP/nt+DFM5GlCrinB1sY3JhXzjH5g5Nb7XJ7rlzmd4Gjn\n9b4hnSNrpXHayGLHQR9fOhhhfRbSsGHULMMYiGjl5zggME36w/Jc7VaQyBlgWjVP\neNHHWTjqqVzwhzX4JvI2R/5maztlFKpThmlvHoRSDISBM5NB2RwjtAwlWfRF39nX\n79eqx6SztA/3+vdzDSxRWGEjk4D+2gWMMa2ydJy9IMpsQr7M1s3d/Y33OmYVXjp9\nycuC2GCrMgME95lFxgkQTixuh5MpgpBpSRAAqYhRv2QkAkRDVG+AqgUjnI5EpYYR\nGXPZM5u88abdlLVQeH2rWH+LDL/8MisnfmJWv8Bi1igch0W8nxDUdtjIjnGcaLpV\nwIo4DZX76TLnr/j2O1IHvSDiPdEIFgSFsPA5CMCOUSmt7rWmk3wYxMGSBhBWfZgN\njj61e5Z4+WtSdsY8BLmLdXSo3tur5msxt1+8A/OTvcA/yy84B6cOvPwAkELklyC4\n/AwGuRTucg68tIA960DIzJIIF46dJ1gtd76YWonFHoIxNhRX/wdy+7Ca0nyhlXIu\nvOyOL/7+K3VXS/lUdFQA6BX0u7WOF0086Gs7DLALF09Gqmu1w44u63CPzVFGfO4f\nNCOf8vFKLUofcDpkK7QFvX63VTAXxUNkkq+0KKcpyTiVQztmv2CPmQUu9G/W1Nex\nLDaxIwbKQ+FT+dSVKNGSUT3rDgDv9bycd4PQhz9E4tuG+TRxLizFqjzn7Azk+fT0\nvbkmRA+83Dmyvyx18LjpEb1pWoS8mLVHv4mfNzOK4NuAfUWxT/WvR3z7aXzvhxWl\nNrfLYOSp4XssvPFBpUS5qNB5yUiKRJd4iMT9ouGG7XkNlUqyyfJ9aEfdCiq0yB8d\nqIb9aF0OUx+Gi9wStWqNboXn1k6O6pSrTfOEt/uKQgAlVRn7o7TnRHfFjOkos9M2\nF0ARYaGcR1QJyQu5Ag0EVI6wVgEQAMHv1i+IMWNjqbCMUPS7DXTm4JGw1F88gf3Y\nHVwSF7dZfUdHS4fb65fVs4APafKZqQral0qjDIsI2oZgued24/IDF9JIYWX+Kks5\nWbHJP3k7Gk68wDcGBnGMSoaKvOQtc/L3/7AHnhxnFvtsD8aydtUfBNIBBiNzAXsf\npP/Wf+tGV6z+7U+CT7wE3UCot2Erb/Ud5PVSq8GMHZR+Io45XbDZEHCtmWgs3l+z\n8zh4LnFf3HP+UuDNl2PCmxAql+WXOI3NbB640O+4Y4sIxt08C3wyzKuGH6kIlRvX\nGvY7kC+JNfn8oMG1knKeO7Wf3dDzuUK9QvCGxNm2zyObvzzt9+lCvjJndpNEUEDl\ne8bo3xajQBexm6CFYI3luZjEbLKMI2FY0Wl3R2bEmCk3G+nlQlmc/+5s7qmYZSo/\nZnvgoUDTUMhvVypgTkydK4+zoQuyd6qFHbeKWaPr6eZIjdO5J3t5v+2WbFjAqXW/\n89rHv9aVaZiWL7DksmrBgvxWIHriTdwptDfNYeFOnICQkCHqUoWQ2WgrWDuuoXs+\nt0bOna6NJHKSNZn2G4mHZqi8tUv22ImkYaIVVDmkoGcidbPv16nDvnoU6m22fi9C\nKoqoFVNKwyLRz7t9VqCM2Z2Tqqc5PGvw3of1chqIOV18AD/fk1kHtfKcn9L9A9X+\nbXuFUg+dABEBAAGJBEQEGAEKAA8CGwIFAlXdomsFCQURWRACKcFdIAQZAQoABgUC\nVI6wVgAKCRAuGsaO1AgU4JKjEACXrUoJM4iskF/tRCc67bl/QWVy4RDQlVhcCfnU\nAnuIr76f3EjuYqrD6c8QacbTFzggTwttYXx09Mf3A388T/jZHV/9HkPG3cxpgpNm\nq/YiQhxCVvdvHo/IGkpS9UMt4f7hFjsL7dlW157ys8OQ8cgRSQ0A/FEeMvzE6uni\n7cYZ4lfLkrS896o0layi/uCg7BKRhz44a9lYWpQ+d7BFC+rmMEk7nhWgUeLjb+oL\n22MsVunbRE4clEKYvyT63B4imtmzJsdGiQPK/+xzCcwYqtROI9r7dOjSHKI5U0s1\nP/PvXbZipzyhNFxTPL8fORW8DJSW6dhd04B+ipz4ZMEMkywNOWU8w6EevVts7Dk5\nMvuauPZsSNSJLyVZmB9LljXNbYBMGsXC5e1M09Rvo5XVdKj8PgbJ9ipCWbcfu1GB\nRiPf/crEH5OXSBWnzQlt+NzuL/66kQNuWCKnQ/K7v258QleHYY5/E7Sn4xRiMTa5\nTc+nmYmGByV0wNjBmRxXWptZ4DY4cpl1TfDl7iWEriqc+ZOmQ1Uii5hkN6Svm8a4\nu+OSg88ZlnrDEQtQRRg2ddKnGt47WqEbk69J/1dWVuTXbqdfGqUnuW7wZ0FKlMOa\nkDQipgLXcyigC/DjAUGQd9RvMKoRA+tgJJP0r5rDCdi+CYcUyjRfwuDqUycBNz1H\n8/lTJAkQTixuh5MpgpBSgQ/6Av17Fok/ajbfxiBCeaZblsvvHzP7VcMda/geC/3n\n6VZZK5RxpjVab+Oeh43HZvLXuJP/tLIPgsxn+Ih446DO1AnQZsdCBPYcvtyYNgBv\nYvyFg24WB2xrsgMSUNfxbdcUMgM3C8CW/sxIVUMFdUOvLxkiiG22ZTcAyhVFCf71\nkGRh4NsGeUlHTGIfDqyrk/6b7Ii/OvBrj7wvjPTbqaFpkOYPqqLkv6PtyQ6n+bF7\nbuwAw8PTHVa/E8Y2OowZBypTTQrwhoPpjwk22ZjCnB/Iyp02CdnxrgZQKMCefCzd\nroJKkMEQFi0PQg2D0e2BB5zGHpOzjIKz53Qd9ITRcAw4wmFHjR8pvr1UhdJpbhKE\nn4d7JW5ieUaDT5R91zzp77d345TgU6AhtRIUD6pAukeOXgVrG2dVEWzcSKMrgJuQ\nkAGsoXSJ/oKsPEHdN1bZqgG4Amr3lI3U+F0gzkQdkWRv3BX38VAJsfExRwqdUDil\nT4Md37RpZTITMXGiyjV4QgaUy+46W3P2UjJkINLgQSyBOQ9hE8ifc9EoEB9SlCPZ\nTuQ/4Z9ne3Z9s29HI3VaKp4ErBglxIkaiwZ7901UugRwKn0onOTS9z5RT+PkBpl7\nsU9BCuXIr65XhkJuUqc06kPYstToMCTqod4uXMV+ET3LB2qoGax5WNqMbwp3BG/E\nYwy5Ag0EVI6w6gEQAOSdq/N0T8db8PTutfkBRVtkdVpvhumkKWbjBoN4CwA8BVZS\nAfdgNCE74tyP+k7Pa802eQBUE6f0j4rD8E7ohGO61vo3ZLIIMPGCQOLtvOThNKU8\nZBnCPdUbk6msbPmnfh9Khz33zGkjozzr3uLkRDKqgwCu22sgxMMa+Szs2yBpejab\n4mSRglNgEgm1sLxoIUBX2DzuV6jh4+J3jCCSOSUDSl8HF3ELaBebNo2VegGdvOqT\nOKPLZp+8d//8ezi/W62wUhxJltJsFPRKw3rFkIeGgSUog5ooX/V9V9YO0UsDmCO3\nVgy5s4byctgCuEbxa2ZPabwrRgpaXUgOGu/a5PDO1veesCJhKbAuHvwgntaODpY6\nPjmnNA/9QzrKhUpAYp4jeSANxtd2tLFM+n/HwK4n8yxnBcM2dqc2WebfZDHNzNyq\nCGv+3CugTouqW97cgJPbS7IkEMAVm2zygMezx3y3p7bVC502SxkGsnLcw9H+qbBS\ng01v8hiKVtI/7jFRQxAHSmpQOtk+Y7jApxox123BGOtJKjsxkUo1GEk+rIpCkun+\nDk13NlYw4DNtIKPQBngx+OBNi9XLS0s5ZslfOwk4fxTdJlmNAGLmXvsVyoOAsJo+\nKt7HH5KKKJL7YUrE7a658G/6ZuiYy9XbWI40tLpKrArFodTON9W6+AeqG1bRABEB\nAAGIXgQQFggABgUCWl5l1AAKCRAbuJwGAjZ0SZ84AQCsDiDfawq/ND2Zbl+l3+Qm\n8hNcupJgLzBvD8y1eyjDxQEAg1A2b9cDb0SAF2y2wZGpb1ax3zsQ+VpBw9CQYzeV\nHQ+JAh8EKAEKAAkFAlXdoO0CHQIACgkQTixuh5MpgpCV3RAAizJNW4PdKa90EiAV\nL63tTlz4+L4ahPFNXYeB5WXt/2fZS97B8kr3uFP7GnGj7ojj4/+9x6vTWiFguHw3\nZGpJRkWeoHRLge+eAxl9AXXtMDdeJk0hzqd14Nj23eRmssoqeAtQm1zXPvmmC0yb\nfm7CxnAIdvZNCITt4J0g6bMqyerR2550+ZY6mAlN/x65JNfmG3XJ3Xo6WKCGy8ha\nOjaWrcTM9BR1wM8266raCJakjZXLhOLJWMRAvcYIwpCdKKATe+AcoDT5N8gQJmgD\nJjXRfstGLPkJkmu9hmo9AfLjrZhtqRGexmaPnqb2eQSvlzuADZuuy9GyIx5+t85q\n7OHs77pyYBm88so2LkJbwhL51XNJW6z6j1jX9ubbLgZmJlAkx8nNmVMWPexKHr2a\nE+nHkRmuS9e2TIK7o5cutlt0MuIRjBz5SLrB6m7TH543/Ym+h/vWxjXSGFOeMfVx\n6e8zpNDu4WmRPmR8QlHXrnOhlWuwFY3kIGaEWtWIxalKz1XyZijaWnZ+AIbAnfLh\nVPTjcwaky2Em0NDQqCLwk4jwuWUByzwVurNJkwAwlhXVh3cAyV8fiwDXopI4Rzyr\ngcuW+yLyCsXTF0Fgp7KzYkfLo5M9OGlKvPVvLmCzu+oRif2EGVBdGj7+65pV4E3/\nYTdzsw8EdYBZKKfetxATY9ZJcBOJBD4EGAEKAAkFAlSOsOoCGwICKQkQTixuh5Mp\ngpDBXSAEGQEKAAYFAlSOsOoACgkQLQAJiFiYOaO2UQ//cmWSSkfbgSPwAT5cFnC3\nipqcFvY+L+/ODcp723unIwfslaSDssUZKlBMgbj8c59EZqEbrxJA0rI9L4xTCG2p\nCusR84aeZd/5NLYXVOopUYiwWk2I1KLnNbhDYYGWHANOw8Y6ycACOWxGOSDDB6Cr\npQQMlhPPdfW2RtjaIUfihKv+F2mA54jhnasdCaAk0aGkdJmJ04/2BhkwWpBepFpl\n6+WMwe1oA0lNCg/eXhoxW8BT5ExK6w0lzp2/4P9wZjVtAYpOOU9SdHj7g1XpH6va\nvapQlcz8Nfw+ByX6ZLIr1YaQpOsOr/EBcjyw02LCPiP+tIo/Bw4o8jm8+OIt/qnr\nEqlwBLBFlQO5Nisy6Dr7uyqEALv7MGbExJm33jnCSyHR5oyRDFI4BYip2PdFZ5WA\nUKZvlq5+lh+Yd3Bf8uC2ljMZD6Ed6rAp00M4MWLnzUmrPg/4JzWc7S+V5dBZEhEW\nJesPU8T7xr8utG7b2LxFXYzZRq5jSyr62WPMbLHzlRTIdzsBdNsBnJLgo5PCbHwI\nQxGXeJoHWd+YTHtMORBF3uCpC/AgHKioU551ipcx1e8aFypskMxZZRHllTObwKex\neO8c2fT1V9GvQnEn572l0QpY9zz3duB83s80rpHnl6NjRowEbPuqBKpLIxw3a7Wo\n319qRQDYOFm9TXrO0CDZ8MY7+w/8DSi8KSDRNxrMbhME1R/CcSNoBQrQOoGSJLdB\nhW9QSEjMP+6hATkenbGmrVxl1mICzHuqXgr+JW92DbPwR8z6A1k5SO8V1xOesX7z\ngt2sy5RvfNZe9mmiaa0CxeY6YG0NaqF2+OA5vvpHXh3vwGOcN481rTLdKF4lQhzv\npzdHlYUTYwtf3MIwAOJdzsZB+jGJphRh6XS+mTABtAigXFAP901sRfiL+41Zo1nQ\ntm7sjBVhHVEISObFZLTdXwvTn5ufw+3rmY5X5n8A2QK1V9j4y0DYFk1P4dW9Ooan\nWU/kLRyqPDsPjr8Ey0UeZyEur4HXBdFucy1Fn2/EtUFTYWaPOqyVl0/IlKTlfGY0\n566l/n48kwOx/P4PHIVr36tE6XHPRB1d6ui6fpzjm2FgC7odjna2gD9IhHAeLfjG\n1wvXXHcFCeZHdf1B0nicivxYAGb0Nc8ICl89WMfKp+/LMzD08Alzz26Mfmglv6zJ\nx2J0b8puMEtTiM4ESrDVrMxewibZ4cI9e1g86WXGPlIZ0ApicFlr69bTIPzIYNmY\nwWqab2tqm0MQVRpNDWMIkWJ/r3TTmNN+Fqv827Fo7qR8zjPVi8DyoKmFzfgya2Zo\nE7od5bGg7lcM7UhzEPfwZUMqKaawlrnzqy1sGLJi0QZErUhHo3tU9sHYqAtUENvs\n4LC7dEG5Ag0EV72EYAEQAKtZnxTBzFY44H2+xwmXQU/qvdshOrfMi3Jw8UbOpoyZ\nAs/6Rgnl5UunyuyS6XQiSaBzFaoZ56TuEFnVvu9mMPwKrVSlRstAeHXM91nd5P3W\n6iM7Z94mZ4iRNz98e5pB86w7gt+RT9iNLIhtdZ97xVRFw1Qi36cFo80doXEJv1Pe\nS+5RG7S5ijHK7l9gzWWf0yesU8uNhYee14FPjjyCjf/+8+u+o2TiM1SVYiF/j9IG\nMX7FaWo4n43NHT4OYJx8BhHsw+NDMflK+KUYGLKUpBLs3yWNlnNYCT0SDzc0ddDw\nQYdLsAbClkzVewPfNV06bIig7huSm7JHlIYYs4eGKXcMROZxSM2RcwbF/+TC72n5\nss6t1o/qr+6L4KPXLJyMnIBWznLDiQ+/cfOLh41GF2bfX+FtoqLaZKsFyP7fZ4o4\nRDfW28rBECrgeQ6cfSwn5/ODuUzz3seu5x75jyX5VvDMJDjdSNQEy28INtO2XhjF\nFyx4wYCY5/RF5bWnv6ORhVBeoAdABTL0Tpde4LML+OO0a6qP2KfvV8a/c7FPM9mR\navG8CGgOitBmIyaUpjGD09KgYqn/977xpNb3+YS4agnIWGNp4fMxzQiWBkeqXbGE\nFy0S9gmXx12txmXeTuyxeYxUm9sCoIm5RnxoFohxhq5ltNwB1/Acy/Rn6MNKaxHT\nABEBAAGJAhwEEAEIAAYFAlYQBEQACgkQwhhSWBn3hFGqbA/+OxN1gCJHTUAG9fEW\nyINHG6Kurr8+D3OmpYmGuCIZIfe4tDT4eMFZv8ePuxRB0qq96rGHp3fnclM6eziW\nMN/5JhN4AjcVlTPVh8T4kXYBzO0z8nO+fwwfWsD12dRaSdPOBHRirx3c/AyPLuqm\nFDfZb7dtpfpGpJpneM4p7L2wHSVzotJHCWB+0IMhL7n0LLd2qfyM2rHG3MrirUAH\nq+W4N22wY9OGWrxktxMG7rC3KDsoyUr9/2hc9l9wa4kvOUAMQ0P2C1k+SZwSCIiA\nXQHnl20yBgcwVGQZvp+e3LK8nM3JxPJJF8j8t2iFHA77BTYybty/23QtqSDbnmk1\nmVF/w9HZlcA176IxDcK3efOvphUzOeLBE1qahAe4jrhEfSdD5c/pdBIR2qItzMI1\nlTPd/W8hT8V8jMMJQ1G4QLd4rRohFygZl+mNsFIiGGLWYo5TWGuY/rp6e4g9NcZ/\nvBr8F10gm68MwgYrZuLVeQ7Ij97f+aNKB5O8eebXUh3XFAPaxjA1PocOubqZ0CYx\ndFjwA/hDYXUbyc9/YpWpw8oYTpYS0g+bhVrxw4E68vqMeDupWGXE6vSGxbLm7oO3\nsrBLy4uGQwj36Yq5UOlhDoZXlf/OOHbTWdEcpY6rAt6jZR3hRiDJi14vKnfuJvKz\nqzARJJNkq5Mlh7+Vdp4a4LhbdOGJAhwEEAEIAAYFAlYT8vEACgkQE9v80IsiNhHh\nvRAAtLhvkXZmBrSwsjQZjgVmIV9+Df1kIEbyXumlpfwi2mBBVBPvNhZXnZaA0eea\nH71N+bDwAlNETg4Zy/uK4wHv39qoVd2oDyEoW2jmD1yIGl2R6sGyUvTspGQ/IaDe\n2i9BrDILpj+ZFOuuuIjHCH7DQEUTd4HUIhLqeABGGxDIDy30zAYF2bv5hvxdeA+j\nzfctgGM4WeDEFVEe+9lSFzjMlIfo4RsGvjRRCtgpTUn3mLp42WeLmZ/FvfEr7Q6Q\nspHEqwVMkNP/qobOP6fI42k1nyQKZwotEdCS3sctohzMDco0R9siOqax28XQ7jLZ\nV4Sj+RCv9TLbotNqCLzlVsl0DECVSsu8LQ5/3OGBej+IidVgLYqLleT+KC+9IB6n\n56eiH+f/LMLKyBmwmRVQK4eSSVkrXniOYjujOJdDI6ua+qJqqOlkp+2yo+YDEJVz\nTEIzqmQJSw1iRwsgN/8hIUG14xtSph14AxfgdRouqPkMEsuTXxloCovdTa5sdJuN\nIdaPIuUPuWZ4GEKAcvePE1JGHStoKV3kS9BNxVyKztOq8eaX40r4qicDaNMql8yo\n7ysp8jnlWu2uLzXWoyymAskz5dBLXr4V24gS9Vp46g3AxG3iBhNvZcvlQeWHOno9\nVGNRCYABHJ6nMRxTR+4X81ILn4ykB3eyYi/CBJ27xKYq3ACJAhwEEAEIAAYFAlbY\nOYYACgkQQDwmV82ZT3MiIBAApcofwZYJWZkDA2dkZc8QB56VP/VYaky9DkBr0ziR\n3kS1B1i7N752ekaxOXY18xFfVgkHqCkBu6na4sJBSjPDQE3l/t/9+SQMV1mnTWBB\nqGsxIi4s8cVrsLjAtpFOzYzsngB1104GEWxmB7NH2ZxZ5mo0rggsCFkRFY0Q5jCm\ngvURig8sxcaIOZL0YMJQGerYo1DEWiEyJvkW6fFV6yHyBnFcFby9ETAaEumWK3V0\nLLnMpVrEoL3ByatIWvcCI7fnVORjFWM1q/eIpBLq3W91sBjQSh+pbOZ+psrDPfQT\n4fNeHJeZ7G79cLhfG9qmzRUO1UoF4wKxPcYTiYXG8H7Rs25x59lBfDnKV4Phrlia\nahIXbveWT6jyVdKfgR8E+G9HUG93zbTQU0IaNGUD0g+xKOd4u7kFm6qNehJoOCuo\nUwsJGBpk0dWBSj0a1Uy7PeaGFElAHFNlXcQBx1kY516e+77LEW8QyrzsGLb7ff1n\no8ctfFM38+3rR1DvZv3lh4vLKOG2PrUe9Fh/Zgn31u14pK6u12u8yizjSyIZ4uli\nGtzT12V49uASi7PnSLSjXBLvZRQ9BGmMvQyS3xE/VVDtGkEYNRiikCzUNN+twFWl\ndzVzYp02Q5e5Z802yz8AQ8Nbpf8iY4gbX7jUXRYnB9OWp5BA/dMuBp95uQDFM4cf\naSWJAhwEEAEIAAYFAlbskAQACgkQfDGIDKYR59kB4g/+IbtiR+84wSbRDiClO9jd\nvQkUH1NL7FYlAuhJYprdylGUraYAWkFJIMUz02Xp2shNRJI4CJbPSrsve5Q+aGus\n5zBBh3OB7HGqXz5N5I7lEQ8j5N+6jw0AEyVevXKttWFqXJHf1EoMsIEcVAJm+wuK\nrKPUsZ7OHg60YViQ0XoztA1zBZSCka3AMNkq+lYHzKAmTQfEWwU8nO/MjlHBcwZq\nIJHQbou4Ksy7XB0BRl8+0uQKShbSqc7ItoMDYFhtvXLrm0XrmXfOlNQ6R8FwIPiO\nnN02N3wjksahCqdgg1PpUiTbT0WHzReQQyoGfyF6OYdYr8A08fUqVM51GEfYlcuf\nmri6O3mxGWyhCycWrC8WIRYbwKczfLuSCTBAGn5xfYUUERE+gFHUJqP0CDxXKvZl\nNAFj7Z+6rOsdf32PEkRe/INgDoOECInas//jQFbFaHkCGF8dmMRosxNby2XhXV4n\nAZ/hBk8W842drNYtBysrP79xAN3apic5uqYdPr45TqAp70KyZv8zl7ji5PI/dXtv\nTNBg2RulMJ7P9VhGtFbwBTcsXk+qluX1BFKxUE4auL/PXZQu36c+nNf5paEQ3Ox2\nYZqBWQMzo+9VLqLDeT1BhLmXuMhFwWy+yZl5X/rM7g7gBNZtcrqQVkz5M2xCm5kZ\n8HXdok5RRIWn9CUiIBwhCwuJAhwEEAEIAAYFAleAu2QACgkQWXEsyu61cBWcgxAA\nno/tE1W9YnAb7P1otgIAjJI4NkrVlEQxOoPIUoVo6GP6kZL54JLRiTgScYn69ind\nVuNderJ/TIDmEacIVJaobhDQwKN9KVhPoKGU74iZd5n6fgz7mxA/9N3ybmiHyxLi\n7cBgBhTD+cofEf4n8blT1xNiug7ZKSsX8InU6By3XBtrOaO6LKF8QnLqCRPg1KIf\nEH43LWVE3vtkDOG4e2+6owdU3iZsH3lAXnN4+2vm9xkLAZxRbH0n+VFaUtsyZ1N8\nht5O7qaHv/YIPuYcR97gtmPtRe3CSkBcZ4jksMgoGR1dLclRGPTqlIqkuVMqFWHw\ny7gjD6+gjSLUDCKuLD4ToJ5ST6khFlJV+Hknbbu7K69pbAOGtrbDsEM8db4s5JvD\nGsOnKAeCR+31Ju1oknToA5hv7ckghYjb9kmsk3mmi7ReveBDsEUWiUJdfJcuViXG\nHAjJIBI10b/hdUG7WikL+/94EWd4APrcQoKqo5ptAx6+gzwjv58WALOb7Vam+qhU\nfo/l5zrZqivc6Tng2BzUb6VQWokfS6KqInFwzIUoYQQ0rad+/+uz7BR6o7jPvJ5y\nZ4xqAzMawZA7AGMnO/Kk44YxiOVQvLkOtF5jCOdtah/EzdiReTGmZyUPYs2Ux3/5\nMweDNr1FQE2MgnUj7TDLnW5DAt1bbY0250h+WSCIhsuJAhwEEAEIAAYFAlfI014A\nCgkQ2jq93Bds75Cnuw/9Fy0wTdnHfosJaid4HctZWn/8ignjfjG24TvxGhZ6qTPm\npMMkQkGJtmGDjZgHI3L6KYHapdGXzs8RcMwt33nRGkBtEJg3wHoPbAJMp/OhqfHg\nMvJUFaNg3RlxEbaRIbbph5JhNs7l00XXCV9AdugyKMaQYb0N27u8viTDdMUPa6Un\nfNMZlQrv5rjMOxwIX3an8VdH4pfwvORoPe5Ls3dLFpQoulpRo+tzk5jbLNt2Z6hl\nHEaXXDTJttCwY40TWov4mC1qXY9Wyz2fSFkqCb1u4SFsV9ImlF+ezfGNTxs/NLbp\nQyEArl+wE4hauAPGrvJJiUY8dQuIQAHhn490nqfMvcVPGnQVOFYKKup4nSeDjnQp\nptVQHn+XKICXpHUdHGuCiRP/mq9Oy91pDjw/mVgnvrViBrfuKmDqgbYlIJ1z3OO9\njuwGtJuuqPP+CKRY6zrEdUX5TyhV4yy7CrNbZy78hGG6pm3xPtINynbXiYIJ/DEQ\nPHciRYEpNt2xlZzUw5k2u0vzYLPJbETlxn2pLu1z8QGUe4CpDiUHdj1kQFa8oEre\nyXaINPK6zsGBiAEGjAINklV13ccpksWbpoMwo06UA00gHSCF6hDO2iS96Uwaz9Ww\n2JrfJr2nMl0Mhar56MWLkaBE9pIl58QDt4YOqR67T3MNeybIJJNFq0I/7CIqVumJ\nAhwEEAEIAAYFAlf1KL0ACgkQaqDeaqntDr9rUBAAhAhOckG5N5SufFIHd7JOmGFd\nnO6Gl2M26Dl4NPV6JegP6iUOxBfznIdBwJWuXqW3JxzFktJOxCUD9QT8bZiaoEeQ\n/3W8YDfmCBmATBqpwDeRCzrqWnseHOVOEz27XoLOgweh1SMiHtaCpDNSeGYrpbkG\noxNjxhlDEdV/y0G0QYbxFFwRYWvJecdGGkqonUhMWQdUvVoUPf4zySNXNNT2UD9q\nBslAWrCqUYLDPg7jHYSnerxhDaCPqKWtnXL8gPagIjVyA5Agaogq117wm7GinOOO\nGMX1gzRdy/IMqJ8SdJtpyNcOt27q1LbWOh0LMH5sSfJuZ0tEiCGLOHR3zO56SzIg\neZ8Nboh/dWQrOjax+iQnVcafswrtl5JlvMROPIKHr9JtD1eaFgJJnoX6VdLgfty+\noyy3uBgPBesKCoifcKosgSaEKGPPAwoo4eiouOcAA8y3IIPrPNyqUDuWWmNfZNLF\nCURzuoyVv2dpRYAW12uczv+nYG16kXKQ2CM09NpBnkUpwITxAIIcchWIyimggyzq\ncShfYAd5YpuTG7NfG+EB0KBcg/7YcBQmYaF91R62feiT9KQyknmRPjjluvIJxbGr\nhJoJhCvHLJoFF++n90XoM40De7SHB+ZnZnXUdkl1CnPgUcni70JfyyHyU1YXNnww\n5cfSCO+f5nX1OQFFbS6JAhwEEAEIAAYFAlf7QsUACgkQAngh/3sc/sbSTw/+LeTf\n6FcNUgG6anxg9nCudqVYfRJJIZkUZcZDtekxay2ckk+T7icOxTAc2MBcoL/853Hc\nyVbZZ/g12g1rboq/Kl6PDWtZmL+8htaKix8UyGGH4PzIbsRz57bKQS9J7TrfNqEN\nFu+ILIyjmq9pDByqsgH2cBkV08KlIlMW3iPUO5WjKK4Kyl5pzyS1qmuh3jydlAuo\n/pp8r3M5jxRekNN+6/NPs5JXdLyRxGomprP4Em/qcoxYRReX5WeWr4WPnd0AnSMa\nCtuaO/+92p6KgMBHP4wB4RtrWPsYHb9OqAnD1u3s0up2ij2RnfNVkPAQEvLajfSc\nyesmQB5BDF387qjtVX8laD5tygKFU8ePBzzTF+j4FSEE/lwpY3i/mKRqi5vPtWuj\n8YXyMBJZcnVABqR6KT5JkWatHfVkha9VHPqLZ4o3G0np+H1lRBzXbuMaHziivX+k\nn4a+kxlys44QPUCA4Mr5dqF49Bcl8YL+d0NQlf0sFh+vjYmBqnTK6SZdSQEALQFz\nMBDTdnC7Zgu5g0/RSsX3lL4jXLjUr6CvTUUYXQsRxxFQ2Ejyaq9SZgS7TnwnhkD4\netk+jlYl0whoWnOkPdkd8WytQ7IgVcGydAyeFK/NCRgtYQ1ES8vT/RY0Qds9cf/p\neRqaZ1lD/56j+W36UOnAbvNk2lc24tIdXtKAAheJAhwEEAEIAAYFAlgH5a4ACgkQ\niwTPDXW7fjceyA//YaMbV/UIn2h/cQB1DiWk3blEtHbKsRxaUQB9KCCQ5y294hmK\nMXGGJ6tY4nlVGPffuv0DVtmQH7J4QQ5lgfBuw8gr19giaWi9zkwSeilfDOafLVNR\nRWSrbgnhSJoQe8jRJP2cVGnvLNCgwUMa95+0lw1bGudh3Z6MW/7AoxBzf/7khR+n\ntgTSyX94w3WYcP02Mz2Dey8mMmh9kISIZMg56HVMBcTyrQV5gCViZ4ZanIc+7lwi\nAlmXnmfCLBMSqmjBD7Ev2v9WXteY+91Hnd77OXHfhdzlVsWbFGuZtUQ3/zuukDtq\n1+gndTdchWj27txAauJCqk0f3CvNEhMGwzK4N2cPWVc8U/p2fZyA7x6AkAW6QY3P\nqAl29fCsk8A+hgJrqj0vJZKjJd4ECs6HGuH/HoIfmykCM0zbOMnO2Uen/70L5gc9\nbPV/VWjN5EL7ofpQIR5J3nq7WwJcQ2v0i/6A1d9x2GIwLJDZ4aY3VqDJEWXY/Lfs\ngQF/1SfKRKxLCNrmEGOUM+Fmu+qSFfBsOWRCFCncWWq8YXsV+L3IkQZR5tAworRb\n33eWdfDWa6jg4SXkqNd+oJw/4MPZfukhMrcqbOt+AhMxKPpf/UpyVhQCit5z8f1D\nLpOvL6ufR4RPCBNnMDRxAjMwu2bVNxUb24hcjiweUKEYKbJ8zmtdSK3io+aJAhwE\nEAEIAAYFAlgUmLwACgkQEEnCBLXCDtaYaxAAkWCcJ+U+vQyaiXm8VylsjLjU1s32\n9hTc7sP+XVB4vwJBJQGYsQDUOE/GigF0sehnUiM9wCjeExouXccc5kVCcezli4AH\nOHzPVfa95a00KZtHzwAa/KPo9+24GYutFbR540fbs260lLDhqTVXCfq9Gk41/Lzd\n9hZY+jrVbl6nYDjpYLGyu+EFLaKGYvzwcIa4Uohsi+z2cmJtNbYuEjK9x5dQ1PF2\n3bI9/oibtRddwr1gUJmG741DvkByy9EpB+wI0r9YOg4Q8HCG4Wb8jDTnmL1iQiWQ\nIVVpUk4oPpxjpi6zg4IEHFG9ZkLe9KCZJjHqvcXq1ikD5EYCsise59SsLvuSHJue\nrKATdF8NFA3BIRpLbizqPrVc7J9fgQQt40pJqlUxz1dzlfQJpF/RANMicw3R1toF\ndArHZozxQ7ZDpSqIl3/rm1mM6U/Rlj512uLFM0S8V0GXQLtkFeRIlgxnUsxP1Jbr\nNhbwl4OiQ2J7YlbBimuYpbBzxFbe4//hDrrs+TlQp2LZDr6TLV18eI03qLYqyxo8\nTpkUmGQGOasZ5WGvEH0tMVsAcwz/iNhjEf/F3b566kni/W0CjsCxnKyOOUv0Byy4\nRfp/ZU6iixn2bPWailju/TIyCb3MAahRrNyOqSDHRGQJqTiNhGUfntyNYiok5wE4\nwSNEpiW7jHRCZomJAhwEEAEIAAYFAlhEje0ACgkQdFAKPi8SA36zbhAAoea73hq4\nBb2223Rt68XVqc5Kp65KRSGVUnma8IRlsqIX1kuJx1Z8JMKMFgvZz9nBCZ4bVFNk\nk5z6mOhwR1xb2Anj6KdTDtSUVZz/ulU4QOTlJazIeSNZO4DXRLY3zsmVeFju038C\nMkycgYz6kShfDaLiZzHLc0RELWRasYcLcHpnrTuFx7gs+bagIYn5kEDMzZbe5yAj\ncipwhv9kPClifTAu67xxw/D3H/nbvAsRUSh/zVWkM54gH+CWm0QQOcc+YXEA+ByS\n2o1e+BAdyLyP42uz2bLDelIAHcHHqs/T2IS9IH5NJq0YW4tXBbzHH7dyzlTbXXB0\nn0xPERk1BhA+y0tB8WrhRfOxedGkCoHmZ1u9jZbxRAG7CbfhqwvjjO8zH8FpFu4h\nd8X8Upn4ib29cNPRWQ+2VQtycMEEk5zQsl8MzFdOPCLKbV/+Avf++T96oXDPEiMb\noZ8/yeR0v1zveXHJqL1Pkqvg4MpyVwFXvlKx/8xvkDwXlk4yqxu0TrFYvUKDmHvL\nYowncOcZ+Bdi7LDTw19H/Yn/HywQabrMUM4clYoIrubdt1MvMVY7xFW9wZfv2JAv\nuhw+As6gjTDPAn70k4VWHaohdobWz3J6SJAOrrWoxkuOECLotXg6orZ+RV3uBKRz\nC+WFcsvkI5sED1BZisbEgYNSsHFZKlyglXiJAhwEEAEIAAYFAlhGgK8ACgkQ1S/j\ntX59fFUnTg//Y4mZy0H6/94RSwcjsKa8M4jhowZ+ho1x0IiG8kzTeZzrLd9zV4k9\n/TGZ/qQB9+Cikl2t6YUIE5OYXNhmEOmrzkes5xbHvvqY2a5Hqgw7uElAuDO+wPoJ\nHr1GiieS3cYyuUdXXRQtoR3Jemc1X2JqavHTXexokACy1gdnCDVuje3BIHK9m5RX\nLNSBZPsWGMAYhNgEw6jB8knZyV43QwF/XdEhW0AkbQk7y5xJTU0Ul55HNxOTskOg\ndE6mvYy+UpIxS1J6eNKJ6szM5N7irJS8JDfRJk/VJVsl+8ASuj41R1Tf/bUOfLzj\nLrH+HnvHjkFFt3klYdP6Kl+v/r6kzYdCgN1rhLncVFSgDhTWWmPSv8Vg+OEajMbK\n6TgH23Har6WbdDO9+/+dC57N5YcVZKr2GIzChnyQMMawJDk71CcgM4f+dx2/2znt\nvrfQ9Sogf+hFMD+OKKDgLBsxxzuwvTUYo5QsjwzQ5kfRRCl0NerTXYgJ1+BClRKr\nkZjnqjp0eePDFFrOwosR6RCV/RiuF9SdVzod+iJqbAv1c8d+GXSwGaDXuedwwxOQ\n3iPZDR2s/SlPjMxCCa32kRfvbQnh/SIuhPKbCzfyiTxhruhWbnBoNeeGLm76aBN6\nmA7B8eZCl+Aft6A4y2xsHKEvXFCY+CtPTc0cAdny2KDd2ZAaGdojWyyJAhwEEAEK\nAAYFAlVbO7kACgkQW4IagTuUp8QdHQ/+P9uVeZlKPTcec7ZeB7fV5444CFaOFRej\n8SpaNZtTwT3rXHa2Gpnc08WPhzJlOElrmOFGbakp2jyXx1gzDQ4QjfNesv/xf1YF\nGJXpOqHsVIN77On6jcWqlFUGWNeTGWCHRCNuCz9LtszDWFNWnlzUCVfNe6WDeycg\nMiUbHNpFnJTQENBYo3m1A5sLM6N/iAi/+TMT8Fc2tfof7rxmfijts7HfSRbyQruV\n6+HhCgaP44zBz8gRtXOpgyXQ/c/NBlU8omXvfPI6gCVjOFXUY8bOhC9ag1cNnPA9\nGFcqVLgoK26kuqP6WcRgC1rJ1/xVMt/7ECW0LQpKOiOADXEoOXWGBdZmfX5Hcqtl\nRw//LNs9IXMTzSnqP20tsYewZNbIXYR/k7seKy8PRwCsOgbvn/ALc3/W3ndo/WiC\nzGrj4jJV6VDV/4O1KzcQTm4HbU143sp+14yrtnI3G4X544QcZ90tM1b7mg4KNS9o\nBuuXT7t36NjneW9S5xFDLfJ47p1kcOtAW1CDKKaFUIjEyhPzSVqfDJb3vsNYI51z\nRLCAjBPA4sAGUIldRYAxTFVffpdQcOYdrbLtZ4KxZ9yIK844RfbSXVHjcwHkhDYL\n9BqtmjbnXv+6SoSKynBn0vpJHsxhXvYD5BrP9lAtlmITUHKEq9MTCYK79TtSBvOC\nagCbtVNguZuJAhwEEAEKAAYFAlXYB0kACgkQx7W17J5zg6EbbQ//drAlh61P4dcB\nucHFe9nztXKPmGAfmJKGgSnuAh1kiFEa2HDrwqs2NUt9GEGHGCkzjNT0EjFc4O/b\nCDreHNZtjrd4/0OXgXjee6ah6O9WMFRzlISjAi2cDOCSq5MwIhXeQHu0WaxiCVJy\nvlhE+GpJaKwD5ro6stKBKBrQwEJWM+4HSTxZENvrhdQdBmCv3/xY0K1VD5aE3N0i\nh7Uv9QzU8E2qwvJaJXroOF39STY3AiAfR0Zh16tk0TCUF48DI07YwCv9o1eeDOlf\nW6f8cSwHqnkj9TX7K1V6ptb6GLiH5zfWMt47OHj3Ley2o9W3LMo8SaieRu/l6aR6\nneOAZW0HrI6WdL36qr0+fM7Cd0bTuUiEVZ92azzsjtFLj42PMg7q4BXnucMnKJ1O\nVkk5YloZ09VPACFJrN/sQQF9vkaiHfEJ9FlB5gDplAY7Kpux5IkX0VMQqr5gTqJn\nKXkRbSJ2xziryLNMBdy4CkxcjZ9Vnr3qwVQNW2uTcn0W34uV8TF6bSupWSf+BNx+\nLyPnuT2P44AEDz4cNpLbOZ4OE+RZCyzf4x92OCeZ955/Lv20A7sgFKp3Tu4YOZ4k\n4aIA2Vr+1NkvzXFa7zdX0lfOTIrCJnrBwLyvPR/XXpZ8htjS14rIswP2iqtOxlJN\nTrEHJqUx4A5gma47tlz0aEMycqQU436JAhwEEAEKAAYFAlYFQz0ACgkQd8wL/cTW\ngQWW+w//XRt6uwjkDPjFYVWlM5rIeda71XqRVHNenGaHgpwj5uqZgl+mQDmaS2qr\nz4TFIGK70icuoOn7Sd0G8XCQXEbTU0feX36L0IIayELn1TBzucxDi2iByDYal6SG\nJaAej0E04OkrDRg2AMZI/opsNEzrx5ASE0MOD3kKeCt9iF6x11xzHggsDTAU8bnG\noBmf3g5g7iwNfpsWH30q1BS2V0JRicEs+vyVFBMTAk02nXUK9AMOe7a5A8LERdqU\n/mfdJTl2yJRgu4lUMozn20RfUHO4xDnBYZ4FFPbZB2/mhFUhW1aEdQQuaoQZcHij\nzlR85hq0RQedPCxY491V3PCmHAcEjFUUcec7flTk39AzmNYMfDlv75WWZpKnLr04\n45rdVMW6LRdGgnb999fwi+7kzC0zIAJc+WTcBT8rggSetvOuVvC+j969waYjjS47\ng43qxiRlpEba49HuwomOhJIoIvUAHjVDRqioEwfVLZ/GXeSTymeKgwY7PZiRcIG2\nre3fC3thE83QeZvFucoLLoT/YRv+YKUIdXdIlz1WzTUrOIZnE9j4HPhwaCQaHCw1\nzcoWl8mzAI6oHvv/6LZYmsAVZaOxgZcL+ZUplvWL0BAcCrx4CD7NB32RlAHo1pv0\nia5Al8zMOHMSWH5IFqfwjXSnUus5X2s40Ie7e618w8MftWPgHU+JAhwEEAEKAAYF\nAlZ22psACgkQx7W17J5zg6HihxAAyC6Md+fe3eCPST+7X8fyqiLcILUyBANPxCuZ\nbPtQPY7B/rMz5lOZywlrhDI9XypJk4tW7dENoRGJ5ZPFtcFdsfhEfi4lixHjZSsl\nUxKZ1TVwIB8HnVL16dFnk8LKOEQ/82gNuy3GtDaGj6gcHoir/HW0JLegZP2EkJ9N\n8OgFvXijiASTnzz1FmxISmuos3/vcLE822aatf8lQPvz66hCdpiqF42qaaoK3zjk\nuqarvjAbxwCex0cS7tuPyZWhFgFUWME5MT5du0T6dNcDlKW79lseiYxJGrC/DS77\nZlaeE4pjQva5nTjAAVqhSsMuF+YeOwZD+ObnF44qgBI2+ZVcvehqtlGh5amr3dY2\nXC9V4zHR2sZ2GzvHvXLOr7WSniqin3U9s+vccIoksSPhVvczX4xaZ0PjhrNqd9wM\nCquXiG6ZVUN5wSagXLtTLk38aKe+aleAJ7d5r8RoojipG2WHThkXZyKftSwhJwTx\noAQ3pCiChuCDjY3wumebZEI+67ra4Q088mpO5G+2rqxeAp/M6HILYmvd+B3QriPM\nBVV76prVnhPIENAadfW6tlL3V8YB747vC5GLeTNIXMKgiVjSUa7yt9ovn/20uB7A\nJDWPGEqXmuN+qeeaa61+yjTfyiKkcneTxDz+Gyh6bVdblrgbyH7Pc0pxCNjviL+N\nt6pkLr6JAhwEEAEKAAYFAlZ+TPIACgkQq9c4M6WG0OZFkg//Widgzt6snazimCg0\nnGy7bt2PUbTAPNFZDOmZLNWhsBBqltQJSDs8r3zATWbgi7hTcVnOnpE3VQSEL0T/\neMdDWACk7f2LgT2nA24VQyTqR0k1wct96eibCuvLAY4HSLDVHjz6N7vPrd7GXZ/t\n7vvSryzk2diSiLNjRpH7mvDtC73M+gMPT/NDcxMfH6APm9tYspHKZFXMf2XvGFPN\nm7rUl1n+I2aYU6HuDcWxIKFaRFl/3Fmd6NR1OOhyI1d+dRJQLoFcOBUpr1d9SiRy\nxf7uG4cRPa9m+h/b0krBWhBbqqEqclTD7FS67zy97cOH1SWbrz9sG3RRyrsUynk3\nLpOYVPEivjzPMykHbo+5jhe42fKkCB5Y7DsXevQH3o8FNjRrJq+dTtYSO7Ulwtxs\nQuROHPLblXVryMZVrGYMgT5jBB7LgM9W4LSlu/ChrATVe9QqbsYJUkck4tOZR7Ej\neIzY2Cc0sFwgW8aWXfI8pSEQKy27QGUXuQjw9qQ1J4e3dRyszNcs/WIhqA7Ybgmc\nhV1oIEYJGwwrUKBvMne0rIBB+4Pvuuyei4xQpzl8R61jYr6APVDVHL2xkMFT2Uhx\n59ca5f4DikFBuoZ1Lpt9V92joWjmUIA28eYBD5leaknOeoGxsMpxtSkyyrpLJ0Pj\nksjee+3zS6bF/eHpjLlW7o3LSbSJAhwEEAEKAAYFAla5KEUACgkQIydRibjnYmw0\n0w//eDKCMPatTszSqKbu16B6MabWMTfCttDQ4ysjUG44W/Z8pn81T5oF2nGfNwBq\n/NwMNvS3XOZWFXF5+Ie8/cYOBmNX+aTciJqVvkdQMhpvLrHDprqEy5WYXiriFILX\n1B4le3YA3s55e3gFMjPEeRuZd+10XpL+NhvILv6X+LbxTwHsIORxc7Ug57BA2CCy\ngtD854hajEkvYYXyJ4Xqqte/rad0Jsv10Wgi00h6YzrZQy7gYRGdEbQwFwDR8c9/\nEvR7Kd5/V8qt1fdmdYIMqZRjn/oMrS1/k3//auhATrIrpIwDV2wRGvYmHRRh01IL\nb+10COlcv5ZRlQJNU7RvKZPXzk94jyz5WnkEtOk9kMkA87UPlBJzI4tlO2gdJW9V\nVVT3vG0ltxcY4o6/e57jB6moTMeu92QVVODwHa3NjrphGHc/05bo9g5P0GtOKdWz\n6OypvGRX8QdQFAoH7sE4pfxgOz/QzK7gihX7j/5zN/Z7a9KSrSFZPfFyhz9HQ3kK\nNWdzts2PbycHVWtIQazVmg2sgCXAaX+407fnKdGfe+J5IGPBpwA/9ed5uXJnR9OF\nvFitqPYE5ZjXSOjGS0A1kIPYVkBeBZcmc2t4Mjq6LGNPs3v21Lv8oNWtg889ekXQ\ncaoiSGHdF/DbmIx9x+iMRGKxQqF05mkqFE48yo5e8IHNfymJAhwEEAEKAAYFAlf8\ntB4ACgkQbg7e04DeMdrC1A/+IOqeNUVy96mKeCOytRkV8JGjeBtbbZIbQ87fQrrK\n5ihtJp5CmNjiQNPbnWiZM1RSwvpEA3apT6QSuVxRQGQfDjGg1A8dSLZLTosN6SK1\na6iQrCx6OHoFjgzVHH1jEgDZiW0S80jQ7LYKwoJSiWEQ9QXF9XxCDKWNFO+o0fJL\n3hrfU48v9SUtJYWlf6Yv54XjDeNWVPRhDge4p2EdEllLIyGQKRxTVhjy8IsfEjZs\n5S9Bwt/7P1t2fdiKPid0tNBUTDG4fFYUxqMh3Lk325a5bCiljyhN+XN0WtFvkYoM\nFwAg+GNFPlk1g+VL4WdACdYOG4UHbTTx2PxNgJg6YtZiRgAu4G7vpMy0l4STy9Gv\niR7LP+++rGg0KEtUTdXEnkXPRUkHcp+ybqwve3UZMq+z0gpYUU55dTmLCcSSLOQG\nVPw1wTzpzXHGEETmBWIspfvw00542vmxzWls26G6ixVkPGHYRNdyC/BEL+rX+Jo2\nHywCl4p9sBN9rEJ/wn+OqzyazMivybFUzFc/w4pvKshwne07UX4pp+YS1G7Ci6Fy\nUGGjnNbZxXq38Pttcxk74ALz8om+hpjX2RQcO6rPGd5sNO79pxDGBRtm1ZA9QBHB\nbW7Su5jMuoIvhyq79vIAGgG86+BB7RD0t83XhC4JcgXl8gdCjuP5RoQyp2sQetwU\nL46JAhwEEgEIAAYFAlcnOKUACgkQahTKCduWrpOrSA/9GLgwCuQev+QhZ+4lIt/g\nJ/KLm5u9eYhfF/JJEdQTpOuB4Mk2nksw5Zp4+9l2H/8J7nHwqbMCpMX+0AIZwACS\nYdg6rsC+ivRN/AoRdE9oJTwdmHdNZbmi9pg4oZa15c/I4DgLFCKYMvQJPu2ssyEh\n8c6dsApKQ5DR36FKXGlONcHrNahgk2poQN7tPF+mYXTGMrJkFOPCJJpanaL+kb+4\nqk63Lj3YS9oHHNVMKSyeByNmQ9sBLJ3DyVxCeJviW1IPrN0gURK8gFXJe/gc/yGr\njIvl/siWX6/qrIZl5IvL9XNzI9uI7/k21rdlGOvMCRBqiQSvKB7oLS/XCsWJoTYi\nI4dIulCiBoKSNgw02V6O32wGHQvCyx10/VfvKorqc86t4Rd++s/+mEGiXjeLbykG\nHvbwu3vI5AkfNfUoOAC+WU390aomHGIeEWDuFbzS/CaTGXpDoqj0qDq0wNYV5z6L\nNmZcaYQfpiLyaZUrgjqxqevMqGrgaDa2/fjaw0JVjlP33qFcwZntDgzoif3l84VD\nanArNusryM0iYF49Ft52nV8aUA9RztDZY2HSiTzoytlvUU/ABNEfZGMkC0A0gchL\nldAXPe/oiE0GwqkqE9w4PwKlSgJJLsgJjJbCIbJiznLBVYTg2IkGMyap6MGFLXtq\nCwwqRylSHcalCzA2CWVkxaKJAhwEEgEIAAYFAlc+EhgACgkQahTKCduWrpNlAQ//\nb1kNtW27WZl1pxlZcd9Wc+82REZTVJjzbF9wvLhcjj61uq0JuCJsmOTTRpR5QKYq\n3901Y2QBIWzIl/4aDDdgvGUB2CrEAUCGnv4IgA58hnHBOv+/3eY+Ct4UKL3inopw\nc7kf7FESAXTeAPMFSc24YH5dP1LxA7pUN6p7Tn1V+9KNLNEK7suUEGCFeXDHUOvK\nTjPc0iRvRKPoeil4+5tuW3JBEMqjPcaur2VNNYE0ZlLhlc+RFqqHzfhvK4lIb98X\nQxkykNTlR0tbtUmYVg8LAnPYCDqgAKe1alMrN3HpTUltfU+md1ORbDFaSHOjBRF3\nh1LpI5MokS4P12BCa6KmbTMKUP7qjxZO78i1/dBlifLxniKNvF/nEv3CvDbHuHhP\ndSwiwNtOAS5IRftnRNv3D6RdL6+0k6CcLiwlFIcJnyV8VmnOCIK3B5ZFXcLsJQ2D\nTqxUHLnijj0wkqtNunW01C53ZAU7PXTdprwzCuZs9u4Y1OvsKLVDCDKAjpmeTE6j\ngBrdgws2Lkho2c99j8SbZNuBAsmy+vMwG0YRfkamsyBsgZr9hReEo9BoK2yt1HCS\nRDLs4JQ7+te2fhuTj5Iy/46a51VFV7nguvtZw1xNdhQ6gVK4s+gvm/8MmYPY0+3b\njhDhrLANzYQaVs3a+85BaUZyUyJ8LtRGHVDgEHoirPiJAhwEEwEKAAYFAlbn7ggA\nCgkQKVx0aYSvfwyRghAAkrxojYgskOsBYXf+gtwNrMvk7XLSFyT5lTGZRs8LGA3O\n+xVwKIWJ5352AytTLwvyKVypdjMNJaIdm0LyiOGhvA1+T3DicL4gPTh1wSLsB6fQ\nmEZPz7F5+SgEbjgmm9FL+zoHBkmIU9VanxOcurm0ChCzCFdfexYZOgwC64Rr3+bi\ntpyxCjh7tNSBzoCOnv9ORj4qSrHuZ7Y/PWRB8Xmzix4kyqzIPyXWKGghLCcTuzFj\nIsobMwcLYinf9ofYyW6MeM7Qi6WYd9JWW8JTDtT8LX3mQkX5f6CLzGkvfN8obFEu\ni2EJPljD3u2zDGfont3KLcGInSmigBDlSxTWj7PImnmx534DY36OqX8D1v+ewib9\nlX4oXdfiKTNk0nD0ZIDYNn8NwvAwxe1wqAdOPAwCOnFVAYW6w9JRYjxw0e4WF6tA\nho1lDZrdvFx27wKvb4pfrbmix5ahrohT4ipOG/rKPNCEmQCTON4TA3K68GAbb4C1\nzW1CYR7UuVyCt8DgBdQObs2knThoCf/FbG6i7UYWfHVnTNAGZkDGGLCJtI8I06cH\nVw+iY2hq8HpgFIUXaGncfWKOwvMAZkMqYem3LOudatRP0byj0qtwG7lsSeZfy1mo\nBliH8w/DlX31tldGIpW+zQ0ELFR18codBgpq22Eja7lPJa3N3QGqp2vm8VlWWSOJ\nAhwEEwEKAAYFAlbn7iEACgkQL5n5Ibt35VQLuQ//aLzD5TUuB+IGeGwKJXKQ9kUV\n1Gqzvr54nGFiDUeQJyQIodoCVVynww8eahxcdCMXx71XCJabrftGaDxgiKdY7PDW\n+RTKVBgCUc4kn+hclUD3oMBWsElld//ka1H7VEUGE1ukM2aJepFCCBIPnn1oJ6jD\nxMnm1w7ztCjYnko7xlJuzHnX1hskpCqvNT/xLbNavp7wSs028LDTO1Apbd9boW72\nVCLhu70i1qbwmktTFsDXWv2R337xE27nJy+E3BaK2dOHA6G+20OS1+nW0vbIhW3E\n2qK34FKmS2L4jn6ytNp+IbRiFIqK/XdKN1UwU+GPl+1zh9FD+cqGEG9QF67/W+xn\n7Xexmu+ydJUxb0QJ3xVMzH3aeaAhIwp4tlKAwRFjlJoZcpPnF7J7NudLXZCkN1Fn\nORbibheAveaPyZrH5RSO5SPdDKN8Aaa1/k4b81mgwARiA85qwg1npFkbzAUOJIEV\nCg++MW2dclClTBCTIisc4u0rgYLXY68FfP+mg3T5oNTCW2myt5IaFGa5Xt7UpCtR\nhk0nGMRlk8w7Yo6OEhSgOpE9Bnuh6qQtVw+cGVJznxyUcM3v6IeazZ5Dh+gbCNvf\nSJ6CmzYjQWoOMYr3kfcz31D9VZ//Kg4obtQrUxIYifjOeLpI95R+RVp8bQpTXk7h\n187Jxm7DqeiO/iN9BtKJAhwEEwEKAAYFAlbn7jEACgkQCvYtwMnW8JDckhAA4h7x\nagVmmGXzrf6TC+XrCQfGeQQHDB2cTWYdgIYyx1kfyjeCTtpfTGZ0ME1HQ3i4XwOq\n3LsxTcRmpYQzL1yVhhRFcv+n1dqsplTtTpbCxj8Kh9zuZoAOC47Slh7ympDLuJTq\nCfJzXFniaFbPyF+9bRp1yH10JwhJ5t5C20qrmcyQMt77dRf2aeFYX+GRqd2JyeHB\nGbkxyFspOPC9jZCHIVQvpwDsHhrV5V9fVWhCgHbTEYbKGQlS9TAWdPCkCqMok+us\nnRSbvwXg9AyVx1jMRf8dNummurIT3EUPPTeuIxiHM4U8KPfhMLtDl3fh011mggI3\nyD2cybnScRYfAmFWxC5jLDdi8FRCruNmoUSIbJzRCy1yXqwdAP0NIhFQlj34+hs0\ninp3/tA3xm+ap0rsoe1AbRcY3xq70ggdO7H4O+mNXVihRRTSVKNbIzagiP1lCefy\nPlmzb8QDw/Mb51hDPWao2sjzBhXyYl79Fro1+rl2Lv08mWjhCdkPrn061BWWWYDL\naFzdpUD2ph3ZRTnZUH2rzB//utM6UOMyDG6+GILWoAMsqdNPDZcvXXLSItu0j+nW\npAl+6/CLmJuy9YwggoxhSyBpCoFQ3J0OiY1Ed4HY484O0UZhOb/8GVFiR46GMlPF\nstHRc7ZOnc1VQwB4AAT2nzm+WAPyH0oYn1MCTziJAhwEEwEKAAYFAliRyM4ACgkQ\nUrji8IKpz4EzOQ//XCfE5vt37iQVyA1UfrqpUlWEP6D/a5bCrnk8FnWLmG4+WgY+\nZKyOYYdpuixiTf8WIK5eZTo53ClE790OrqADcDT7hjxY6BFjnOSArdLlkag/ssTn\nsTedIkCGJ3NFB+DpyPc5zIdQNK4eERf6GOIr83J8GYJ132aWxwrTJh0hJNm2ON7m\njhcaBowYHYIPH8n/nQXAQ0BxT4FnrDh9eXWFos4SJof9BOTK1WxZT25zRfdI5f4y\ng9ZQR1cxRD/ZlFSk3CTNrE8SfzOj7Jg+HvNgw9JPXMivP6b4e4YSh3LvWatG6Hat\nXA7upbLbqFcLahAg8tmtTHi3uJvsL1TdgtT26N1Qs8YOp3f9LjpOuJC1byYxzYzS\nXqtkgO02SrpfZGxwu2tsqYupoUuTmBchEWGDmniSdeibz+szyjvIHvVrM4b+5tOA\noDJvF68gmcsDyD2yhNYTfcpIw0nt8D10zUqTDsGRcFg0vzCbSLwlT2/lu+mdrzE5\n7u9i9awHbiJzYons3MwpFG9C1YmxGJc8X5GEJGnoGLogPd/b/xrhncNZPamPEa1C\nOC9aaRniPQR8nmdkz9PDFVFz1lF48SpXD3fz+bGbQoXICTZ59UrJFP8oSg08e2Zv\nuYRI+Sa0EkplskKSrruOrZBgguw7kBCHL8uD0UxPkiZVERP1MnyrdKKyz0CJAh8E\nEAEKAAkFAlUFkpkCBwAACgkQV02MpYueRGlNKA//Q+2M9igsEMdOZ64CWtwDEj4M\nNk3WrgjdYxVthqF0c0YSz6kZtUpVRNfJqF5KaWFZDkb0CREI9H/is+vYcANN+rh4\nG2Nhj+nm9VZ37qxnSXZQCX4fB5pRYQdK+wPjBtDRSyJ7MxreBLZkByqi7f0bpZ1Y\ntCnRmZgziVhN5eP2tfpDK7GjGLRbOhoRxN4B1rumQU+wEZ7uNXfFXrV45Kh5hKCT\nbtybQCF7K4ZcKhv3MpR9kB1bvYnCjomtRcZGjWl9H7Uuo/GdUvlnnHR6/ES45l7M\nKt8puxZOeERjkcIX8oe/0NU4XNVv5jk0iQh50oK7gJ8eyW7S1L30rUFmr/cDhrVH\ncGWNZ86ib8a3h5/sFjrk11mOnaMJrNr0WHmxTSR+aAtbdJHL48tMZy0T1U3XIoR0\nlEZ7Uof4NPvj7jTkm/eEwPQ+JnEN13w5uQcw8C8wqfhT0A1R/SLVuiRQw+ZOwkGC\nGtsPe9DhbQazg7286AK7Smg0TFsFCxeML4cgEkZQVg4g3wjv3GvBXWg7R/Q7SEIJ\nuZAzqvRaZaMTIcjRY7x7HCjErD12SQnP8B7dMs6pEyC7tcR/Dm93dPpT67R4oXuR\nsjZaOm9sgEVt8r6kLsWFqvUaY39kGRjjV/A0I7XC1vF3xBn6mjjhl+D7+ZNcCAAq\nv6RkfBJwO474o+leUAeJAiAEEAEIAAoFAleAnZcDBQE8AAoJEGuKo/3J2veqwHMP\n/RWhwbdHdX2N7q3Ayo4AHLIefbW9r0g9nFKmq9jOfFBH1T6jaDLf7Nso5fcEw307\nfcq1JSHiZV0LZnprWWIeWfhdjDXugSGjrF+QzhKs6BCt28UCTm195ClF/s0pMSoA\nymxD5oGziuV9HHROGwzBP829QxG662MF+nt3uH2VdKwvM9Aw7gMHADbxNVRKyjVc\n3a18wpL3zBkYjo2acS2NwPQGz+i3pdhY9s7LGV0Yw8oULhQyCYwjY8kuOoeBU9st\nsBGui1CQwVJC86urcbJCS12q/VKOEuTo4jrzSRi0ucnirXzX4Zry6LPQmqY2Wf2t\nRYwEV1PcmyqkaOWu82BzlKnsVDhWL9fYlYamuY8PuzaijLF5KFhxm8ouJoYql9PD\nXtKESlInYHIG90AvlHtH0g/q4TWAhz307i3u+/5Ta/n/AnwZexnKnAv0H+uX1otM\nbiJbYmKgvv6RlTCPykQeuraeaDz6bCAstaQnTcWMQBCa5t1gWmr4Gm1C8Qlpn7hS\nL8kT87+UzANQ6GlAX6mGgNt7xiO/rALdGEV5H4AAI0mgPwXiCMf7SjEZF6Qtx5bi\n4G9wbkkWmYucFw7gsfL3UyJQPuxCfOLrLamAwvIXCAxvv+q5w2uzbTZuyb1kz414\nCr7MllzudS9umtbFJy7s1vMp1JdOUlTxVJ7BOQ6NLowsiQIiBBABCAAMBQJVIdLl\nBYMHhh+AAAoJED38eqE6mIIPWxoP/3pQbQ6Zag96LQgomslI5fpBBgNPdsuBnnT9\nuA3MMch83C/yrD5MGVih8VpOEEn9DlEpC2XNx3bOA+XVhQq7ubL/ICOlo7oEqdLj\nstYY4OUuK+YhtpuEheLL3X44AUfcr1iRHreNzMG+V6G2GCVxvrOMrkjI+HbObLdD\n6+PPIxM/bglKBOcbPHQrGXxqqZv4gcZHf3uZyCitVHqmlXSxdtwOhZBoOi3o3Tb7\naXB7pFwrmBETUeSEdDFZndjEEpVeUWnbqjhOcYa6q/nBVC8P4PpkIMbnqWYyrmwA\nLDy1L6i/4+ouNfBvLkrxcLVftg7JNUGYqBe9u5xxZzzDtB6xpR6roW7s6CM48dC8\nNCk7fsExn+BNpOopNRK4NZ98Pd9TJVigz9JSulxWp/32eJqiVqmsYXoj2dm6GLQw\n0Mau8xOb9cmwIxDfMinKJE0CXbXukC+LmXehhhQY13IEB82SG5kv/yld5C/md2dL\nyJfcdanNlcQVqM8KHIK3nrCIu/EAEvuzYkMvs6ADOY4i6+U+5/46XBRQ+6B0HBXF\n0cvk1+Dw6gV6Hjhzi7zNCRrGR4pDAZs9Hz/WSdW5cKfyoOm1OnSdKilDannomRGk\np5Qf2gbijcVKj3fhmUUas5+akh28AQko4/dQgg3Z3qYYjSr+zqgBas5+D73I1xcW\nl/sB/R3jiQIiBBABCgAMBQJU7gA+BYMDxQoAAAoJEKvfCgVeT9L+0t0QALEjICDF\nsYV5tgcIV8IMuzRr/qEbBoLdHV+Gwcp0yFqCZtTjPfMdJHQuM9CDBQuImxN+p5Bi\n0RKP+1xTVmI8QffAxmKjF7g09Vr7QDyTYpS5ZwPj51atIQSvz2WM2tIaZgCT+Bfm\nTSNxvxPVvxCWp4ZI844wcLmAO5ifP7RO6ZzodHdPl1llTHD62l1nArNxoTnfD66N\n8kLCrDS7cbzuIRPkSVcO98YXlwwtWytWC+/UnkpQIqwWljnSnReiF9BiSqNJFl2t\n8wnEGfzrUdwIQzHHgbBizQj9lHBkIoOMPisvmbIISjovB7LmuYwDEiIvWj69QWqd\nh9KKfczxJYZLVEIHsmWznEDflqjbEoX8CGVGaq3K9/GpeGaD2eb9G/s7YoXCx7zx\ntMKiYJrtOaRuDrF0I1PVkf+HnB/Hmb8uaVoQ3Pjft3dvNCR/yToAcO/+yWfEXxYP\n/fNdc76qh9XKn+rGUpaDx0iKuDLSMPyDocYLKv0T7HyG2UoTbDFwhZZN2cgBK7OW\nolEwVUDdeEw+ZulJkki4ucd9m12e7iouTINulFBA5GDxpNphQiJxEFN0qowP4n4w\nWLnTHGxnDpgxMXe9xcThw+io8tdl2ZDErY+yCLXhMmZzb8ixHET19CuSU43mwCTN\nhA0HI6VS6s/cvfgyWYagSfoLNBtJ/qzewU+oiQIiBBEBCAAMBQJXbYpbBYMDwmcA\nAAoJEGarYdsKfNFyKP0P/ikpmTGLhPluqK0u79BvSijYZ1raPmZ+xwKQMRt00lDC\nVwVOK1qqzXiRXYxV9yDEKvxsQHznZZcoFv1Z5CXcFxnfbqVcwnloR6JSRxp2pwmw\nwod2viGiyiUi3cVYFsWvOBReYFWQ6lKMokYqVZRBCsN3SmiBa9w/AeAKwN4ne9X9\nY+LgJfSbAACESCrYvR1vV7YGEpJLXdDmxBgOQyJ5uF3uhwO4aAx9HeozNfsNRdz7\n9whAyIeG/+L+Tuko3FNGtQDHG+GcEbKDr/pWpUimMwJqwtQFsAGBcWZFzjBl8jTM\nSFeVvK/XET2XIIIuVHQpUdA9PH1qIdOF42hN6B0wEvvOZRZ0TXyAaMVG3TYWxGrM\nDLjPaEAgdVQl8trZOJDth/XrgFQCZsyACBiNcN25uBLFEbgxiYUGwNgLZuzDMF/r\n22he/lP0pRI9xgnuZXKYFm2egUmoamUSkMwAt++xUkM2f4LT14+zTr2vlRtapGge\nRt7bNmoOLd3hWRrBGCFSQcYuJs5aUFWYUuZGt/hzMjG5B+jZGR2FUCKBZP5YrMOA\n94tR9msaPXzbPgbX9WqyIIoHQPeF929s48EB9YlwqhURTFDz0zKuw1hGrDZVjgmO\nlLSX3mphIVXVthOwhDVMtui0olM78QuhVLlxoy/CiEyDGjch647F80mqOvrbur/z\niQIiBBIBCgAMBQJWJAcdBYMHhh+AAAoJEEUMun+WjwlLEiQP/2kyeMhw3biKHavu\n0wTaHmzNeE3w2tz1/PXb78KgtEZo6FxNENz12cTc2e8W8Dkx6eYVSl4cBA+cQuxU\n7GDoVObGL4csRGg0SXO/yAth8ycWhk/zRyOXohJWjoqHYb19+wK9WyxpnTIMeJzA\nanDQ/UoRlWVxnkIsqZGjbuz7ImDUtDs7c195A556xz4ZA3u/ZZlXpDpsyz4s0opY\nwHZEU8cy1LYDsH1ecCtXtC3Q9VhlhauuHGVnnvjEXVOnn0iF2EmDrVyrZ8CA/3Gr\nqp4s2EX39OAV4ZUigcmxJ9YAhHxMe9T70S9ab9Eo1wR+hyFq4Mb9/vsqa96W6X4j\ncCqOkF6MKRUqLSZ0PIC+Nh3FYKv9lli32X1ByM1VqxwW2+OqkQUYOJS6cQb1tpxy\nDIXHOwVPf/0Md9kjJfTTAoucgoa7sKJxq5JYBUZ46G5CYavLbhjg8q+Ds1Z9NEMy\njumGoNF8kXgHzuRLnf4tKppaoSY4Gj2nA62rZ8IjTM0DawU4TnL7Wn3ilKOQQZbw\nvnY2iHpp/0WFJU0blxuNuwjWPMlEnF8hx7ffaaUuwmcdXHVTfMX5FsgnnHzenUB7\n1KK6U7b93sZAqpO4gXVlbaKcZwAKdpoAcb/A9gsUwJdoRNzemvGTm9r8kE8EQU4L\nQEXfwhulYdhBz1ROBbUwvVYEj33xiQIiBBIBCgAMBQJXQDYmBYMHhh+AAAoJEKa8\nAcFdft2p33AP/i6gNVwChq1SVD/odNv5IVMPeaOla0q7qf/VKG4yudDEQaqf/vvg\nH30XEDqLIlPKhG8xBly7dqqV60r+XnjKMKPYigOU+TqfK2ja5zuIrAjiy+Daz6lr\ngUhha3LNEFT8e2H3d5KPKS/QjJ3GER673b2V4Ornh9bm5vq2sj/Q8LYo3hFQ1tFk\npU+e8ADRb1b7inS1H5VQ+DQINuGLN/nGzMq7/ETUkfNS8SsCrUucTQAepRo3TMYO\nCu9AO33mxPpR8vJW/yXCLUbZp2bPdBGGdg94vKZm5jNDiHfcgrgRUfq9ryIUHa5c\nAWm7ibfAUf5WCneB/RFDSpQNE7EnPzJb2jwjvz6kWpoqEhPr1KX8ghtRA+nC1fMG\ncLACmOV3BB2lEAciCB/4/7UcRqWehW/GaG5lL2yzcCHzyfFRZjglHvaQBLGcdUe/\nCoT5sIXnXeOIoHmTHzicVX+AIO+UmnHZCP7oN5vFd0GePrhvamlu9xFJiPEsikxy\nkNMcu+WqiL5DL6yN3ZoNBcWloPkS9W8/omvey8psaP/n4p50n9yqVHboegMWq6HX\nBIQd9qh99UEW9YvgOSO5lXvMXHO7LDNEv+uRvoGXkbiJh9soBCVLzCiEpS6s2Wlr\nbgVClvBap/JAP6xy9dHgDdwA6ko1zbAD1wQbCJ0JDvowMbK5fZrTW6vpiQIiBBMB\nCgAMBQJWUhMHBYMB49aAAAoJEI9m89WTdEVwa7oP/jKqvSQYFpj4ZgNkGpwr6eKf\nVJ5WlDXmSsyNyeuA7eo8ia8p+NgS2kmWxVR8myWqsAp7svc0OuXOxU4QO2bLbrCx\n3MgwwIGJD98p1poj4RDQaKmki2NKaJuRNaCdYuxbVJRwqr7xwa2adJ36AbLY8OS1\nRr3/vHS3it5WkFs6Ajc0fPMph4xqVnme907BCEop9hoqz65ONou+4YcjYWip8Cj2\nVWbA4PXVMS0bM+8D9UEkkfbUBP3qkCFpg+IRCacu4JtSw6Bne0IZZt6SVRSYGNJI\nD0JvRg1XDo2qCuq1Vwo/7TvBw64Cm/6qgLS6skBelU/MSe2Eg+Jc0xRiTx0P4rEi\n9SuVV6t3bYE6BXffaU25v60lFZW3iamWfOtyAY6e4FIfOYxIC4CSU4vV4+GfxGoZ\nOFe83BZa8tDAtR5hVV4yFNoN9Ndp8XRE+z2XbqI0tvpDulfHG43Feg6D36Kyc9CM\n9VIVoLQxkfdHTtwj6eUzyjNT2z6KJvYBpgBG7qrRNnUb2mrwQuA3dv9woGxRTtvU\nJfLPeE68bcYmu2MPRpV+2b1UKPUTkCR3IHd4r4NXQA8fkvypfmknLedSO4ji1IZ/\noMdKQHzESEDTwsof3IFG76rSu9hz3BdsEn5Q4gmFUzjjHDfo7iLCaGgbWHDGsFLw\nA67apTto1LXSxgNaN0B9iQIiBBMBCgAMBQJYJ2K5BYMHhh+AAAoJEHAUJso1qNLi\nwngP/0NYzOn5+VZj+rc+J7l9rkQWVJvj+MHrGfKXI1hy7RHPrUiAXLMuK7mauyqa\nr4qaLq9Jtrtauyxel6Cm7D2HGmhE3fE2kMoYpkhMCJT5ZG3YBZC1nbKfHyi6IUfF\nOHsVqvQ9fooFWro7tMOaXX5dKVJYrr6Yg2Q0B3w4Jaoxd0lUVkhfF50NHB65IdTs\nmSnmKkYshZmTJGjpOcS6YLQWGHzVixi7VfYMx61gxVyq5nio68HUUChDVte7ZUMN\nDue4m6v2QnR21PhCFmgjpLFouNWV9WK+8qJH7TfLfYyreU+lAhFLRdciuirnC+7B\n2w7l78Oa/fwOpnXL4zLZ2/rCp2CgBSg0by0inQv6sbKEQl2U7ktE8KRRdlfk9nzM\nAioGmpF8W22IsAUdf2YHvwUQ/JgGPLybmWL1n8N40zh2U7ep6oUFskFMinBvlRbV\nrdBaQWQYC7fnt9dB6zdEE36Sg5nvfop8XJpPfCLdm1AfoO4nGcw7BumXgeqG0S6a\n0eBOYFJBU30oGXsa8xKWyZAkZRvqWz24PMJHDd++wjdg8zdUFjnS8/rSuiFGax6O\n4hg0vqzlRQl+5i8wEL2j+uC1lEon6NDMHF7JNSuiO2OkKGE/hL3UoVLGXKbNmQV5\nhn3PkE6QAhVXB9dG3yrVDYD/1nBukZLdJlFhr6t1EAZPt+vyiQIzBBABCAAdFiEE\nSVXutFs3GeXK3w7DcDJAmytfMjQFAliU5pMACgkQcDJAmytfMjSpwQ/9HYMxCu7A\ng6LmpcR8ZgNPjiMwCR4Qs3kgiP4gs8CZJffrx4AncbR7shkU5b/Lo4NoaYrOqnzq\n/zEuTm+ZJX/HKg0hiVK3F3xrSoIkenLVShZs4FVSa5rI3fd8bQqfTLkLh1BGlgL/\nn3eFJaV5WJuXiKN7sT7iib39Pem431UKpoaQRXaboPxT/LdRhlSpjT/bJN19TTcw\ndHjgb4w2LwqHouTEsTZkd48+0oQYU/dRHvW8vqebGCBTw2vjH7p2fDNYO+qYsE0+\nDY3Mil52TZ2Nfy8c5VVq7rMFBE6dhdzeZyC9KW65kqt/fSqDLAV1qllEzQod6F/s\nJJqFU+Az0pD2QGE4jA9lGcpEYhyrAwJo0b0rOUw7czRQ386KSqVThSkZr1lIaUP6\nxUEYKGsmlupxvZCPCu440N/WfkUXPi6PtZsPCNC6s2E5wOwSMvUpCL34OvGSvEu6\nvG74unvFo3qluXOcpokTPDA/b7PZ63wsNWT+LE2qJ0Jia/2pVfzOJx8tfAx/H8hs\nSU9YLYcrYoHqv+hOW2xk3CFiXNYRLy7GMVw9C9YyF8hMFezRQi0SNwY+ludufMTs\nQFOLjFe2rUTKAySoJPsq0wiYPdIuoKe5miU70J70WH59vefBySlREU3XJOd4LVOZ\nl5fmoC2TrHUzUlg7YQsk+0+zHn0atWp3zcqJAj0EEwEKACcCGwEFCwkIBwMFFQoJ\nCAsFFgIDAQACHgECF4AFAlXdokUFCQq09AMACgkQTixuh5MpgpABExAAtDhyC2qU\nAv21Sh82raT8ypZpRf+wAaKlko+kcq9IFSBuaHA+weupcPwHErb+nO9wKSjjxweB\nHrSW6Y1mXZiHvaPc/xrNV+Y3EDB+NcvxCD7rYNGDvD6MSkUyaS6hXuEg3euELF06\ncGDq0/tXdW/HBFisSDtTmr4kDMfxrSagvfxOUyslyQDQ6yHopJ2nmVOLCdAxi/WO\nYwAbMiSjqPkjXQVDESik+VNn4xavZhl45NnTbcaO50Dp/5lOdEwNX8gwVXFZ0NWy\nEWIGvMjlkHIxKMn514gG0Vtjfqa9DEVgb2799nxGRiOculqHbdPaoH+ZZ04fO3zu\n9SpwDepqM3oeR0MIM2LlOOI6rp49ydb0ZY/2VbAMH5pw7lWukVB3h+4si1YUYKXh\nHg/MC4cptrMS8TVFE5W4dN3X4Gm0RhCRbg0eZ1lOHJLhtLAE2ZTwhiLvok/fTYTg\nkkF5bBscDqKVZMQyJoYini4mZheF0OcTNSqDvZ54kc/D1paBveNBncASRAWQmUWn\niUWdOkdwVZSTzJ5SWMzS5XWgu69rH/xXnwM4xI334NUF2dvomkuW4h3agf0Fju8x\n1j9/YR0DKwk98/830+DSxZQnvM1+IcBBbqGdZm4IGkm5WC+RR5b8e+/0xSY2C0a+\nJ6xwy1lRTYoVEZ5TgA8STwKOok3lP6pLLMqJAkkEEAEIADMFAlftbLosGmh0dHBz\nOi8vZW1pbHlzaGVwaGVyZC5tZS9zaWduaW5nLXBvbGljeS50eHQACgkQqR9xEdmv\nC11/uQ//TCWZ1VcNGSGyyQ6ak8C5wSJ1Z/H4KXTyWk0yY0MqDx7Nxm64Dn8KdBYa\nj7WXXz62FKjXjVqY+BUIEpJfOS0J9uI9N5xwLHOt7OEA3Fdz2tH15GnTRgLoyRhf\nt9kpfjaMhftgrDnb8LT0z+AFXo3OI2RATm+utYMSTGITd01b/7UayAFXSvhUVtDZ\nsJfBRcw6UkUj2JV5otaIMbxmzh04NM6wQQ9g9f1jKJaKFEWChFS36UHbRb8S6uL7\nR3ckrI9WqHXRVezgflw+wWzKmCiKYL17qylfuJ2gdyhDaZ7fVCIOxrpb5jlN26x6\nvzgzD91t7G+mZCBOSPSRyj8HjDxYElyGEqFeY+6FKAswj2CKjrQmYMRbs3timD7D\n6seaxtWELfuEBDf44Y+7MhrkHp9WPTn/w7pGLfFEe0Y7zIeZ9MOZvy/Vy23gsjfe\nQXgKWfr+T3JTG1IumFwbOvX6L67IWcUt5AGIXx9uA4SPYE6zccJyg4Xc3nlmYj39\nZiJmgVGQrU4PFDqKcusXcpCsgBkpcz6zSKek/sHYz9cUpu3GtV5UZ+u/DIt+N9SJ\nLdXZF6DGeijt+FWkuW6JpJ+sAw2BBUSYVWPBA8jaoKpC/5Be8bvtrR0FgTC4XfzW\n49kLgVsCcaaGogN47CFG1wroQfVfx/g7qJchxwr8g6ZkpCThzwOJAkoEEgEKADQF\nAlYZCWAFgwWjmoAnGmdpdDovL2dpdGh1Yi5jb20vaW5maW5pdHkwL3B1YmtleXMu\nZ2l0AAoJEBMY76xfu9vO6cAP/jFXHWEyPQoEWLgNxOZ/oI5Br7UUFbs+MpJkFb2t\nLh+KfJybu35xNi8vPFt5FXmdyE0xJNNPLMGbqQ8/kh8BFsSejRN84qREbXHhp5B2\ne2rg6RN62sWaMTYKHsiSW+Z7GxoFYixw1r43FA2JGNPj+4TuE/FvW83KCTzHsRZG\nyNOKKzhWAWgEJjiqtzVg5dXd7dmCWQ+on1/5npw3+zErythQqv+3vaaRDACAEreH\nlaRuaAY+kYuSMkr6F4eMW6Zt78LC3ZxfB2okOmdqI7+zQj82Zj3OAshi/6vS7po3\nslcuEVjeMhzaF8Gt6Lyxe/KZW+Vf2AB/FzRMibLepZV+v8uOwrpoeLufrscqoZrk\nmjc00iUeQbfGnwUhvCH8P1+D5HE0JBOsdF06JOrewFocaMNg1TuAqmrkjUMSwL5t\njQPejOHCeg8BK2ULAOq3bB+E0lQ3L7Sc985tGL1jQpgSYLdNw1IncjJCgHBEKDyb\nO4CFo9V37An5jejG77gxNX0K81ErDIJw6oeLpicQjR3B363tXNDzhHBBmyjzafim\nsB2pE6cajMz3x+bUzSL3X7yGcAyWVkPIEir34u+z2+jfwfnK1XX2TjFlXLo7BtM4\ndyooeB5CM0s5nHjfoDkDeazxd5lKkCPeJMbG88EZcC30/FJSOhtEpvnG5Lm3ZhV+\n254biQLtBBMBCgDXBQJVAMSiBYMJZgGATxSAAAAAAB4AKHZlcmlmaWVkQHBhdHRl\ncm5zaW50aGV2b2lkLm5ldEVGNkUyODZEREE4NUVBMkE0QkE3REU2ODRFMkM2RTg3\nOTMyOTgyOTBLFIAAAAAAGgAoaXNpc0BwYXR0ZXJuc2ludGhldm9pZC5uZXQwQTZB\nNThBMTRCNTk0NkFCREUxOEUyMDdBM0FEQjY3QTJDREI4QjM1LhpodHRwczovL2Js\nb2cucGF0dGVybnNpbnRoZXZvaWQubmV0L3BvbGljeS50eHQACgkQo622eizbizVq\nrw/9GOt7yBURbGtG2PefEovIK3WJJHouIEd1q8FtaPSbs+NQfXv0o8F1Kz6S1J+/\n707Vx5dQZeHiyRXuMbJrBmyENWGx3P5s6eYmTMB/dAE6odwXrep13oOMYNlhLlsn\nKNU7vM8D9kzWDBI5U+Gk4LXjNs228B6MgsBjYzRAbUfP6e8JPOxNABWi+zBnMlDO\noa9XgbcCsIxQ5FaGIVpVJId962IwG7wgBL/ZQT0FxnZ8e9+KBDHhy4weZ79mm10p\n4CdtCw6v82Di4Q1HRbkWLrBukt9L64OAwuiBe0K0J654bu8HZujwAgXmJjrjdw3S\nwaNh6Yv64IWwkODCQ1LieF+fH0j4fDrR3se+kzOTMsUceysqhwJ11JRJA6cUeEEw\ntMmeBNf+aRl7gbfEoPQkmkEDX4/wN5dZOuOimavjghn2xLYyEgff1na9WXHcIT/z\nLwscG7Or4XEt8iGCFcmjoWuZQZbjGYrvrR394ywvKf/rWAOeFBkQ84f1ErizXhQo\n6/28bG+DpjmhESIaxXyRDpU+qgadWyjo70s8ihrl2JDJVIYjk0Y7RukEndE/Z61s\nzeg14QccsShdTwptyoYuRvzCc8ooeVsbLr654P8HGz46yP0VzZ2eNv65+1ZdgU8q\nO40276Lhr2S32LxYBdjFOATANKD3I4lmmHfO0v/dwJIULtqJAu0EEwEKANcFAlfV\nSBIFgwlmAYBPFIAAAAAAHgAodmVyaWZpZWRAcGF0dGVybnNpbnRoZXZvaWQubmV0\nRUY2RTI4NkREQTg1RUEyQTRCQTdERTY4NEUyQzZFODc5MzI5ODI5MEsUgAAAAAAa\nAChpc2lzQHBhdHRlcm5zaW50aGV2b2lkLm5ldDBBNkE1OEExNEI1OTQ2QUJERTE4\nRTIwN0EzQURCNjdBMkNEQjhCMzUuGmh0dHBzOi8vYmxvZy5wYXR0ZXJuc2ludGhl\ndm9pZC5uZXQvcG9saWN5LnR4dAAKCRCjrbZ6LNuLNZzfD/4niHzydJAeq0mKa2Ir\nO2/pCZJWCC6wH47xkuQJmGyxw+PVRxEBXWNMm2swt2vwuFVRt7ljLWQlEUJsrWQl\nmEoCV0KcNup7DIcLrJORsHp8cLdx3PCepSvSz0qApkQ1/5iOhK8UsLCKrNg8/ErM\nTRxeMESlzivxB5aHxqSyT352vTAkic0DHc3/szgb84XufbmHc22K4zdZRhSFh5Tv\n3Mk/xLH4nHYWqPznoIeoRV96Jst0gP3GQ2GQNmzqaf3fvKjNUch28B9WlcvYr1vR\nJkY76degqCDRaWaClS2FtHUNU1qXF07uwFpk1CqkD9+7/ocKo4gJlXOHRgGrtnDB\n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\n=m01L\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/files/96865171.nmav@gnutls.org.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2\n\n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\nipUmbs4A/1iZlpnIDl9JaFrMlvSdOwJahurU7A7R5fA7yokrrEcBiF4EEBEIAAYF\nAk1P6jUACgkQnUKBHfuLs3Z3QwEAtklBLDDU4slBNg7aIa4EAZ2K4/Go+F13JS16\nre/N5O4BALPgNAB+0qLgDg/UQmDmyFjIO1r5vtp97BeAdSwm1Y64iF4EEBEIAAYF\nAk1U+1IACgkQ7o02PRaHlzjKfQD+IAQsHP/uh//SpCno/dgUf3W5uD7vCHstanq7\nubxJiYIA/jvS+U1ZrGt/EVPbMpoSlbwwr8g+R1nWsF+s6tqKkLhniGUEExEIACUF\nAk1WxLgeGmh0dHA6Ly93d3cuZ290aGdvb3NlLm5ldC9wZ3AvAAoJELR14ge6tYIp\nl7gAnjkbjnRS6lFVa09WXgGzX0+K3niEAJ4sxP/qlOOoHUjzTh0MZN9yb/TAmohl\nBBMRCAAlBQJNVsS7HhpodHRwOi8vd3d3LmdvdGhnb29zZS5uZXQvcGdwLwAKCRCU\nj9ag4Q9QLintAJ4tis8eBtXw05q3qRSW0GGQHeFrTwCfcNHWvfiXCLW8QAlQSIAC\nGESRUc6IdAQSEQIANAUCTU/RXS0aaHR0cDovL3d3dy5hMnguY2gvZGUva29udGFr\ndC9wZ3AtcG9saWN5Lmh0bWwACgkQcW1EEz2MIi1OvwCfQjG0eHr/kHanCZLFuf6S\nX19OdUkAn06K3zrS/gYyMLrJegK+/Lku9eO5iHQEEhECADQFAk1P0W8tGmh0dHA6\nLy93d3cuYTJ4LmNoL2RlL2tvbnRha3QvcGdwLXBvbGljeS5odG1sAAoJEFbVKT7J\negZU584An1wa2HTUiR9GsvdO1OR8/q/a0Fq7AJ9WtmrUp/EI0hq0IGy14TPqWHdi\nW4h1BBAWCAAdFiEEEaFmtlnT6CXpZS+hG7icBgI2dEkFAlihkW0ACgkQG7icBgI2\ndEnSHgD+NKvpKk2Pyt5/S7NdDhP3EwMe6a1ayGEp9fLIdymXHnkA/38Btt8ZnoI/\nG6m9H+oZy/+qPGmz9Xl3yKl10v6iRZYBiH0EExECAD0FAk1g1F4yGmh0dHA6Ly93\nd3cubmljLW5hYy1wcm9qZWN0Lm9yZy9+YmxhYXAvcG9saWN5Lmh0bWwDBQF4AAoJ\nEHLU3/jUw/GX7UEAn1q0nJa4PKV0iXBk6itVnzK6ZHi4AJ0T7BdWBAOW+pvBMXYD\n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\n/lL4fNapao8+Yj/N6oT8HBcA/2PB62hLyyIQwGSqovcYC3R5QWxcpEg0+FXBq52p\nrCj6iF4EEBEIAAYFAk1P6jUACgkQnUKBHfuLs3Y2iwD6AzC0tTOHa4fKisvAoWlN\nEjqxbgs/wyfdvaeyAMKDZoIA/3PgfPsF1dYqm2WiUUzS6fE7ral+ULtA6DfS2s6B\nV219iF4EEBEIAAYFAk1U+1IACgkQ7o02PRaHlziNaQD/Va8yZU0v/UbrbB7uZ6TS\nrfzvf6SUx9Wnm0kiOTcOGoQA/3BcTLSDeiEWG/hbI2vaQjuWHCisRdbFx0cxSEFj\nxeE1iGUEExEIACUFAk1WxLgeGmh0dHA6Ly93d3cuZ290aGdvb3NlLm5ldC9wZ3Av\nAAoJELR14ge6tYIpBx8AoNRcJvGN+QmiOqxZSBZkFy7zawNAAKCjBJUz1dzYDiDl\nRDdJEkIIP6R52ohlBBMRCAAlBQJNVsS7HhpodHRwOi8vd3d3LmdvdGhnb29zZS5u\nZXQvcGdwLwAKCRCUj9ag4Q9QLp3gAKCIe0+D6ZYXfdISEWMDxWVwuFfliACfVp70\nkqaGLsOR3duqU7JNrp9ikVSIdAQSEQIANAUCTU/RXS0aaHR0cDovL3d3dy5hMngu\nY2gvZGUva29udGFrdC9wZ3AtcG9saWN5Lmh0bWwACgkQcW1EEz2MIi1zsgCgtTqN\n/X4Kby8uY1RrB/pUH+4BB74An03/W8DJ5jfWt6pNhrbZcoesyGfHiHQEEhECADQF\nAk1P0W8tGmh0dHA6Ly93d3cuYTJ4LmNoL2RlL2tvbnRha3QvcGdwLXBvbGljeS5o\ndG1sAAoJEFbVKT7JegZUk0cAoNfv3bXzPDca17Hk8hyGGw/dv+GZAKDmTUP08lt+\nlspGi2mannl6iSHCcoh1BBAWCAAdFiEEEaFmtlnT6CXpZS+hG7icBgI2dEkFAlih\nkXQACgkQG7icBgI2dEm1YwEA0FqDfQlOVUqxei7La0ranvEfp5frFAA9RPeF0zIT\ndHgBAMUFHxO7Y5sAfhtv+8tG6UJB3iP6UtU7Y57wJ9lD6XcEiH0EExECAD0FAk1g\n1F4yGmh0dHA6Ly93d3cubmljLW5hYy1wcm9qZWN0Lm9yZy9+YmxhYXAvcG9saWN5\nLmh0bWwDBQF4AAoJEHLU3/jUw/GXE8IAn1BlJ+kOR2BNPIMfCs4nLpIWy7AFAJ0W\nkbr6QRD7gRzDMCgj0rl0hjBpKIkBHAQQAQIABgUCTVBE/AAKCRB9wybazXKm/YF/\nCACWALOtUjV/htkc3ph8TH7Wven8Qo4NM2Xgq9GXrvDO1ySbajtrCy7eq99v9PFR\nNIrNQTo6MT0HtPcyy+/MaE/JJKKpksaN/3PKvEvY0tQVCJx5D0vl+6lZlv5Wmz5A\nWeZks/5G5mYoCuic2rb2gv6G5ISDmizwZCzCi/GaWr/Dtq6P0aQQe6z90ZfYxGke\nqtLHQmNMKPaVpd6zjH6gS5RS99tyMYMaKO9LyHARr5uKmEdPCj48e3bZsf2ULO/L\nQJrgnq9EX4mtLbSFfEpuJPX3c7oyeWsW+eLebq1ybkhN4R0IcFzpfJqc3Yo8F56I\ndpvdF1IExaWky+hCx2rvzWA9iQEcBBABAgAGBQJNURGNAAoJEJyvzxFWdG+VWh0H\n/0RV5a6QeAKzUMLdR5BHNAX4E3FLds7/prgZ+hLT3LpGYm9Oi8CN8FqE8vIR6UKF\nNtLGFjirQS1deWsPKcBEiZIgniu9C2Lt5YJ9nLDzNhELAfvwGlux/k6lMtqK6/0S\n3IIt2QFRqH8oGf5XErjKWxoUBQZpaV1CPk0D1Wsij7NZb8wSDNhFDMDcnqxJ8GRO\n+krX85sxBnsgDLnJTgjx2u3mUFuANHdUOCoY34i2Qxe4KGn5I/VJ6CwlNzKsIhcc\nqODrgRAUdAx6mut3FThpc/7DR/aBvLLXch/ddu5DsDYbCSU0JYLMap2c/pYJx1Zk\nq4395whvR7NCYniMuApAzk2JARwEEAECAAYFAk+FKoQACgkQZ+dy8INR4K/rPAf/\nbtZujCAZigMz2V9VcxeQVvXC5TBKIRgAlgFL71wxYMZgJDxvBBMzuGp1BHCxKpH1\n979LUNUyXNAVd+UV1UqcPNLUQKgMuWNcd2+edTaLNQUb3MD9SE0b1kRgHBKFG8YI\nB9Ab1i2ts+CozTzX/iDn40ELuduiWSuzQampUYkKvYeUt8lqWsWSoiYCCFxIbtss\nmS58ZFza1a3US+TR9WC11VFlQFUknV7wH9eIfOeiawUvY1dYViE4iAKl9antVmaL\nI9mGy5+QyHhj/L1PustRPVi4AhOhjwI8IfacH1ejWIgS5PvBOc36KsIYP+mPAxfK\nHW4RXn/XcRDUfEah0jnyYYkBHAQQAQIABgUCT4UqhAAKCRCoziimAQ1vOus8B/49\nyPw2c7ZFoCyivUVRoZVimJ5didiJTpXqKs2q/A/P78J0ngHMkeOZRccuyoWZiIdT\nKOJsdYJLqTBfRl76Wrx5iJsnsN/39MchqajWHVwJv7MnrBtfOOXaw1LDjG704j1+\npfqcdJQhvTapvlPV8RaIjvxUvMOwgibeUPDX27yKAAMyMTX8fJou5QmpjZT+n+gb\n2lpxtBFY7DZ4VQwGIs1GfgiO5+dlV05CDQiujwJDvFZLTLCF84IIChOWkGqtQ6Wy\nHZ4GB7XmTEnQEmk6fTOuAxTVXr4/wEn1BPPYtENQYQZDYnIdapq170/26XCqyXdh\nBVeoKo/OduuMDWb2FczUiQEcBBMBAgAGBQJNUabfAAoJEOlagbieQb42FroH/0xD\n6p9+IETAtRDQVlTTAyHFgJwTBbfsjmFgECtJR9f+9Uz56bna0AldDd+Fz7ZR8B2z\nfvkHou6KslDHVCVdZZiPrT9rjqJ5upgw2mQuEsuicLY4ozwchBLjyBHNHbIxg2pI\nKpKJlH4H/+YjBoeBMG/FMuMDjPXO+J5SdvRb7A4OuorKLq+RdrAGb3ddLKITtvOb\n7NKfGVZAY3zk4ya+btk1o1f8W7upQXBFdDqjYdxDbH0ecejwUsYhOBEe/JqNqW9x\nKTIjeE7vNGIW5EMbsy8dHqr34Un2JDo1Km0zrWV04EHCQEqoD3U/a/eSeu94eBAD\n0Lb7FXmLvH/zmv01VQiJAZwEEAECAAYFAk1PB/4ACgkQ4NgPxjjU1YekhQwAiY4B\nP4/KMJ5zuwzF/HtdjYj7W+i9K3p0pMGkdWrtaPnnvlKX7RGnZii8Lmcaks3H1O3d\nX+o0MdkCiSQXz9c+rBzCa9UUuxd88NvBwBJ/7UUR1cB/gArepqW3sEpVX3nShQrD\nzwMm6KBzXgO0iBg4iIodFDyGi3y0U6XqrWJHi09iyXP6CRuTFzvBZBiw+lH/ftKG\nfrRBkyRkrtDtHBz2DX+D0hkMDwDepUjM8C9XXkYxhvsxaaOL7KzrM8Z13519fwBs\nTVkUb3ESRWt8kjAZ3xi6rSdvSn1IpbyQWaduVdU8AT6FqtRIfWhaHNRyK347iBhr\nresxLcCLq5wwMn1hdepVPaxA0oDFHV8JxKiZU8bHccP3lchZVtBcFCE8T8Ulj/jL\nXvZzGULYqk/T0xFMoPk6teWyfacKyjV93yqfjdobET72i4LulZwtKQ+EtE99BD7V\nHEZ/S1KqCGQD+BjSoumn/AyczTnpoOBCWUaMDYbpSOTcmHy5G3gLBXM0VtSjiQGc\nBBMBAgAGBQJNUGXiAAoJEODYD8Y41NWH7UUMAIC6WCBaVDK0x+vNohak4x3k2qhR\nHGlasxxjR+pwyryap7DQc4ipjYtIjSrFVg0poQJy5QjiQJ+HJEO5kSu33MhBww1z\ngU/JNye3mIETNqHxRdmErUgIUAJfmjvllf7BGfOPY2CcLOmsEdKsvi3WppZwikvw\n2N7pBmbKzCnrwz4H9JwthnkI96gAG7IrlrJzqmN9cToQlP3r6r8D4NWr3WsXqDBA\nKFjJQsYgrc42WO0LjCgmKqMiSpDfApHx+oVHscJmOpT+4+41jn0nfuZUrJETu5WE\nVJ5g2wJWCDReJT7goVrYWMlwkc96wAWntrvLsDSnsJZci9uaBocC/KjrP3F3X65c\n8KEM9KmrhY+sJyq6avOgEsHhdR7L/+KZMDb7HTWpaCQdkVc2D7K2tfPKNn9LQkvP\nHeHLPnX2QQQCDX0sk9ljSSYulA/nvYF1Mnttc5pO47PRDqlxkEWu8VWnLtbX/RF9\nPYF5cYU9MGMKXNx9myJzROsUYkdz8oRWePHWH4kBwAQTAQIAJgUCSB3m1QIbAwUJ\nJZgGAAYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJECnuWLmWhlFxC+MMHiboc7xt\nuJFKBhF3tStS5KZE1yhY/dbaZ63K1Kr26BGwWGCXeWUcQySBZMRfOxBM9lc+rubt\no1c9ryz+JsP6pkBsVJG8khKun8T5zWAK3gBCb+cPfYXlEixUqmD0nSkrusKszIuU\nP4+Ib76MmsbeKe6TgqtzcQeP3Ysml8SdWBolHRqPC5Uc1339A6uSvFDuOUtySX1l\naaq5PKb8YKWwfs1w+erBztg7ScbVf+X0cma9LJocaLhSfOMLxOqHhq+zUDa5R9ej\nQ4LAs7rVuqey3WUjICfse2J1U0Eh9BcoN3eNbP5bDJmTQZGDNEF9FZKGmLKbFWLc\ntZSC1cvQVMQr+kWke8huGmK82rVE9N66U7W474FvvxVjO9DHdwhf3qBGipql0j3M\n7wGUTN72WPWBmxFUGVZWRHnwhme49i06a4igZfc0VpMGTisgo95cTMIYL+J4cMcS\nfb2ZmguTz1WsKr7tY0p1JiOI9wwulFia8FwlLFjpjGczmt+IFJbmG5Xe5i5lDz2J\nAhwEEAECAAYFAk1O6qEACgkQZ2YA3NpamUNlFA//VVzNc6WkL8wEKZQKUQH6NBC+\nSGJBs5YD3y7oK9s62FqHeuxl8m6zq4ZiONK1fkto/bd3FsI7+skLuTK3D9Tk+HGs\nnBoQRqgOUzuugf/+OSyH+FaraMqc1W35HIrtm9jWsJ4R7BQjqCXz2hMrT5lAeg4D\npPsUde30CuNQWpa6PNkddN3giCkWexb16ucIHZATKjLZ/+9dAbmXX2kmB+y0qdOr\naVQP6SkyDxGAI1osPLKOhm8HBtrUJReAcG3ERLLnjqW2nIIj8uREpx+Att0/svKn\nP4JiOaBdkSPHbaZTPEcSrncBNlqraUYvMx4k9jD8oK2wrxffbYHGBv1s1gRUyKdx\n0zaZq/jSjv29cT1ZsWhuPls+2dsBBwILkfM/jWlRPZi5bOvG38lzP8qkGCsNWTyn\n/01kwRSWTE7wQFhGwcwfwsGUJgK62UzD6kKOKO51cH9ApAr42BJmyucMfx8BmZvE\nAYN3KU6idwLaIRrUXPemFJqGzC7U551jCTpadH+HYe3lBH04JNpgwIP529O0wEYd\nghTpRPDdbYCd+LssX4H2q5b4TcgL9PvXaUOnnba7za8Ci8uKaaBHu7G2OcQyoX8P\nxD/zHOTE38aUkJpteTrTlG2iWFIEN6GN9qiWQuKfit8KVRhsS88Lcg6J7h8vRK58\n3XhZTsK7eFMvglft4BuJAhwEEAECAAYFAk1P2zoACgkQfpcqy/4KevMLmRAAj23T\ndm5GO2HxV7IP2x3Aa7kFo/pzVUUuvpn0HFIWBFK+fJEOMeD1SpI9nGHfziUrNruw\ntjqgSMHGy+ZP7IM0ERvmkp8r1La67P4AsH6Qk+jBwwlGPs0bE5y1I9vip9rWhVTr\nnBWUgblAWWvjNaArCRA0XtOLYZcoUNZUf9KGFns7OSVCKjysoLuAyw05ZIUcHyRe\n9Jf6Ps372726qDAcDFM5175rL2Mo3khm4riq4ezIa63SWSfUCHfUg7z2ZTPA+9Jf\nwAyYw1+pOgwM3Sg6NFhWYlG2itewJd71PfAOU7D5jRTjHGGyYkxq2Xu6Yt3auBIo\n1M2ZDQVYaxxfBalOyk8HRMo7+IXiMZLfP2cqBghGBjfO7usfKU/2WkmBlO+gZ9v4\nsnVynfJszwjqqJaulfzKdOlwfYvoEuA6C+ZtXQsjI6vniWoiuDN3zQaDgjvEDMBH\nuaxDtxJP8ElbSByKNB9ilCe81H0vDWtzHrrntK+yekt2OhfwbJBTa5Zyu54HF9If\ncpv2AAU1/kquZz5lWDzx8GQc42L4dIs2JtSbnIzZI+vOBkgUaepffvM+vmI/z4zA\nAMwXuPgH7jHZVSXz592Kc8vD0SMryiajdm7+H9m80JZoJGvGa8tL83wjE3AfkNt4\nx4jFyEkrqNzFMG4Pf3KCYIgE4EGGXWZh1QE1f7KJAhwEEAECAAYFAk1QW0AACgkQ\n52EC4M3+rC8x6xAAg41ibZaXUVehZrpqP4AKtOXS2leAIi5+fahS7fasDAqoQ9fB\nqWlDB7bv2qyUxHnf3Pp2Jedbs76MXZJrcGTI4si2ceUe8JtiwuA84GeWeFAsaAEi\n8L8XdT998C0975GBfWRwDCPkkJ9r+Ya2N3IM6RGAgxjYSoDvHpqcyPp2ut/rLvvz\nhY2klSpAYgvzLOSkQ0AQye6DWzGr2ua6XQ5ix1M4youzOhu6QMxAVq52XOVlziJN\nFGLqOkAUkW+ZWkgw57ylvARXOxA4+HFm16KJTTVxQqw/fBTWdRbj6GU7epHXUOqF\nuqicnQoLzw9dSC3C9ADfUg9vQ0XcDHkqdb5FR2AP7cPltyQsj/oGw7elqgK98n8w\nYCWzExbwyXGYePWD+iy+7x58ptT2eUMmCU2oigl2tvLSiwzjWK21+fQlzpcMRNkh\n2exGa4x5sMiTPgBOsS+T/Rk/EWS+S8Ts0WGb1r5kh2PTKRCDSOCC7RJPCdQ5wc3J\nbpUUiTlNoRBkMFLx0TwMtxKH+OuOea3TBM7KJne5/S4jJRfBkYNXV/cE8wNT2JYQ\np/BHeupBTxlvQJq8hT+/8rDGtQjd5vEEdkSaEMj474MJnVUnOb7DkxTXHuRPzlVA\n0Wan7Xmiwktpl65fvyhiEi+WPv2+EOwwNNTmWbVIhPAKT24Tns+UFL2f3mqJAhwE\nEAECAAYFAk1R4MIACgkQXrE+nUCPPD/Gag//fKUghjZzTvun23xfYfB5aNG3sH6A\nRoI4b+zd3zwTWwcOBrj8/O25YtO6Ro8cA62GnQra0kHTsIoE3enYqkb9qvGJVZh+\n19eU6G0TlYP0bVT3utogBEpOPstKm3WlGaYYhzRzYsCrgea9Ezt9oiX5Eq5hyoSe\n4QNynBVqNtnnqYs28nQS9bB9By7mYdE35DyiXzrQ52yEOJV4/xlJ9atSfOspAIET\npxCse8qUKt780hd3Z3s8uPYo7YN3xGuD0qg1tC1gg6AdJZzq7p2CbH3TLXGrvVeK\n0nRGmxvRY93Wv5gCoA7GQrSr9E6rTSIUiwK78jSWNLyYMO5YezRRmR5jyW/McN03\nKv1alakAFD8767j1ciLarQn0qMOBsi5gcZyMU/LSZWBGcmQwviJ7EVuee28JcC2C\n5uDQcNgLWOhNGn9Wnuog2bp9xL50dLUfb4m13LS35PxGIzezxl3xTUmNMgzKfnAm\nMCg3EdFlHDarWQXJT8I0uWBwQCd0RWT2IJpbRCVITaDY+YK73EHsMIN4B1Qz8XLv\nC4XPRa/Az02PBKaepT01KLUhAs//oxK7a0USPwZuxManchSzqckc9aPDv04knqFz\nWeuwfN3CNKC4H+bsQRc0JFI3wMuEKOqMYt98tI4f3i4oMGeD2e5zzOB8gelQkr7R\nCpMvUiXrkAyikwSJAhwEEAECAAYFAk1R4PAACgkQES/3QIOJfhI1jBAAlDT5AHza\n1U2fSTJ4KfRHbGBDyozihiWI+wl8L9DQ45ivLkivvYi4V9f6vbBVOJQsgcO4gBwe\nxB9te3PFgodW9qPBCJsJlwkZ5pwMSooP1B7OfHL9eDqxEEH2sQDoDxAgLuyMt8zF\n55BJCa4f7xDTS7n5GmNC7dal1RcwX1mineus9v+6icAY8efneV8UnW93KYZrfTMv\nK8S8qlmytoLp8cOUdjdGweogrD4MiOz6zJT0km/5Ef+UePuxrxByMCdDAkSoFsWM\njsEODT+W3KgTjx4qYizMPvixv7AdhbwusbMRP3f+kzzrI35k9haloBRSjXry7JfJ\n9pwtkONM8RiqYV31GVNNlbQ+V/klZii90CsmQ31OuVSQrby4phQt1IHxjiHOnWYs\nAxr7h8psZSzlQddwDom4pHe2obDo02TW7TXhsEWoC8u8VhFczDVdrI7NEmrhAFlD\nJoq/XTmGkJscEpHVBjWnUJhcN/DJkElWHKn8ybfx42JPrILN0839nTQ15fnCD6a4\n17YGsmwGO9pHGEzoTrx+gEHsUJ21brT4XCpt4OodJLX/JFerb0pw7QN9tPCVlQkl\n4QiULDaXXVaZscyHnSTSSqENb2DAGPGGBlphEhMx40CmRvQR5RaAiQW/Q0SeTAbn\ngFF8Uqa4xQYsLF5yYDYCYJorKbn/TvtZBjaJAhwEEAECAAYFAk1R4PAACgkQES/3\nQIOJfhI1jBAAlDT5AHza1U2fSTJ4KfRHbGBDyozihiWI+wl8L9DQ45iv////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////+JAhwEEAEC\nAAYFAk1Sb+MACgkQKukB5ccCGNJYKBAAzsVGoGNds0Mz+LMsKypZqwAiDGi4hOpj\nKU9V40sjp4DKkM/x8ieZU+UJgOR/13EHy0vTD22NFT7sC29p1VWbobdk+jluQAJq\n0IgNZAqNGkFA2jvV1zRj5o8rJ26+G6A95Eyiq0NnrKDDy0bsO8nVtM6GBmgSY6MU\nKIvGcDCvOewDz3B98IoEet6J+7qxEvoCg8fPlwKzDv7H1NjOkpTq7+TUnv4rvPRZ\n3eIcRXIfRn4cgfKk13K+k8YZTiMtl/2yt06PtC9S1vZzrYpKBIEAy+pDWRz2aZJn\nXaWOrz5aNZNLiqvjc9hmMN0uDXl93XXBI/SFlFEX/r0+6/9LPPUvwBdet8I6X0QU\nhsvW3Ahw8NoyXZHTE6auOotoirsDdLS8z/TuAZ58YnMEtJswOayhzn1MimprywS6\n9S9/jb5BOHW/lR2VB/UUfM+Tv/2+hrGJCAcAI5m2biqV1sHYhHoRVOWvW4OLaQ7u\n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\n+Rf44bJMHaxnzi5x\n=F8jg\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/files/A697A56F.corban@raunco.co.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFnZjGYBEADgPzrgbPSIwVcEVTNgEMwBFR3LrezsPQoQH5Sh9TKkZrqF3lIH\nLCjzGA0crZ7Z+LqcWhlz8eXdbza1/D/eSNIIn40P7FLRsYCTA97a9xkCk9ACIC0r\n68E8q7zCqoEPAr/6tv+G76CyVEzSDYKiQk/CSqflEvItmwVjl/B9atoI7sxNHTSA\nyHsO8Qz7VSLsp4annhg55H0BqhoXWzsIUqM1seeF4oR+RYMm9eUcpxmv3L1LxhuG\nMgI+wCRxahP13vQYZQke11KegzjX+QyXo/YgJcB3vWhoFWaCIEIm4I1TJsBj5trm\nxhABk0deNYRA87DIOBNctmbsuq4GHLlbYB3qYGao7pAk+5AWcmD1J/IDw/40GxHR\na0XHkwD00+ZmS3+btJkZmMoDWvNY9aNyIKw6n0F+xMS9mu8uW3c5lkHGHCpEMvv4\nO18AC8bfnLshuxkP9gJLpxLTYilxiK+OtX/pQ80wAgNxzJ7N8slJuiytfoZ6DUkD\naWtqagX4slQLgTg1QYOYSwlhw2EKoKQDCOWL3t/eupRicHFoEfPs6aPWO5Hx6tgx\nrlGuN6gynVaWrl78lArHw4EPruyZyJ7Yb+1ROW/jUQoijtr6Wx0Vt3Nbm22/bQid\nI3UorVsEzWrd6RFm4hIFdIdkveOTOmFDmg+9TkEi79eNkKO79Lmt66kDEwARAQAB\ntB5Db3JiYW4gUmF1biA8Y29yYmFuQHJhdW5jby5jbz6JAlQEEwEKAD4WIQRmBwsk\njOVk7SLOCVCml6VvHxURiQUCWdmMZgIbAwUJGlTFgAULCQgHAwUVCgkICwUWAgMB\nAAIeAQIXgAAKCRCml6VvHxURif4HD/9daMdrOZJI4IzE5M7jWsH/0SP1Bvzm85If\nqz8bDju492b3sTDIbj1kctm/5pZtqny8GbLOCjsARHPpsG5jfAMPKIY3tfcxC6r1\n7Q1696s1j0v+0zISI4IiSNRsrVERgGjkXumVWpCBcia+HCw70ZD4qBrwitf7LUjt\nlnq+ow35iszixyz7rOyN670lPpFIqEVcYcyV86DWJTztsN69bCai6H4r3jajco97\nus8yzAyqEUnPHo+yiByDLwKNAgVX/KlvhhpliyMxb2oAA6gaOB5mVJkxbdR2l0kX\nxU9BzCWo6X19/p3BMVmhkcVqwYpkP90wM8IodLqMGJZP+7WWm4JEPp5Hux+cC1Y/\nva4h4cTRtqeGSEwFn0BWWB2aML2VAmQGGd7aChtDffrQLWeOD+Q7j7YwJK4Po8Nj\nAkfxBVR4laoNdNX4HKBV6RNJwcOe+HiiZGM+5R4QvYGyIMtBPIlvr/aov/3HSgGd\nBFHZzb/stpqhJV6JC70Kv+oKN+/OFJnNl6/inIOzl7kSxsnLohyoe5CJHReA01m3\nTcotQA/79iZyk3/DpM7fcbthLHzRdl3RVPOuFRb2e8D+Tmvca0E5ejGbAhuSbxZB\nwlgybRiAVshZA9hTgD1l2BIBk3WeN2FlIfNuQhMUB5RQVkfLS2Nap2mm7NsOHzKe\nrejwyLByfYkCNwQTAQoAKwUCWdmMZgkQppelbx8VEYkCGwMFCRpUxYAFCwkIBwMF\nFQoJCAsFFgIDAQAAAEB3D/9bHAnRkxWLs1r+p0wXnxKYZhgk73wsPGRK8iAxnFpk\nwuDCPuvk+XD/kvIOjbCLk5HSDXYOcLVINr3lxORGkgwKg43n4/J4YILqm3eQr0bI\noKSPZEe921sQPLSOQijRs5CAigUhFEXcsMQgc37WSDTIm08uvFBH/q8xYW9smWUD\nD7tAuBFmV5/x7jzYKz2r46iI058vgeN9LEDAaOnuhJXcBY3y3XDtT1rGm8h/dJuu\nSdZtCjJW5YWiROzDplTOG++++MhMJxI7UTSG2LQlYP5prjzW4/YyBhbTU3f1hpGu\ndlcdK5FoEBKyUwShJFIeDd5iacnV0052zwE29DdfpZ6TM/7wq52wLiyb3BP6p9ml\n+5+BCcOYkv0mdb0p/EzmpKLoeqO1iV6omaMRDRCSLcwDMO+3oAcWbL0sF9xRU/Z3\nEtH99lwBTAIt8Nm5Y4l8biWSIadYn2n2SkTLJsmFWuQKNkQZ/VSDb00eRhvNVzWA\nH+siG6UOK6N7UyOYApI3l8/saUtEPDP27ZzpsSlA6SVPxlruK+aNLZromWa3CpaQ\nzAiBeO/ROwDOfeWYqSrZ9AR3tczylgl+qBPAoeGs3AVILeFWIgveDSwpgAow1njo\nMP9tK5wAnWqlThbdLIubyHGKmJLZjW4mKh9POu2kJVaoQpObI7voSf91gZeUXUgl\n8rkCDQRZ2YxmARAA5lbdUlezhtK+q+ABpYDVhTIF/xh9zm04HUvFCgbQB5yV005S\n18cmUrzMyrlATJK39WZXJUadeyNYHDDQdw5eCw7RsSs6oxLLLvmu65xhAxvTjJQd\nu1JjV1Xt6Lqre97ce0uorYJ8pMT2yZ3qIwM2hvcl4vnUoWZpSi3K0mzwY+T4jrCU\no046jjq0xMz9PGQs85tf5/CUayvX8idd334WwZLnkHZNnhVd6xstIrlezmmh/sDi\nwCJaGZ8psruTvGwG7IrOvKzWuWZHqlLvH0nM7N3UaJc1DGJeibD2Srow7RVTX+eh\nma7lv8Ye5R1ULfM8aZQsuDA4ZkfigNCxKl36OFKG/ZVRmF0qb+bWBkdcFa6Hsbj2\nsg+kHyD3FiPocZdPClCGi3H4IztGYbwufidaye4U/eK/3lfF67HpsswqIYsKHyEA\nSICZEDaPlx0RIVAPfFts1KXJ0sMixAhkKlRPZeNRnljzIeI/1PC9GNrWvl6LN5tF\n41jycnAuXFy/aLFghpmndD4t48VsfDZzjgHn3adAeyqZMRU8DH+nIpxuwmrzQrAa\nHK9vrDGdPsYDEl2FW9ylZjN8PbS0TyqvSKUSb/unGyOm8IrhpvIfyiNU09mnP8XR\n4sgOtaA4LGk89JmU9z5scocvPU2m1FU/QjC3iscekJ0tlMq7kvMBjAdt/IcAEQEA\nAYkCPAQYAQoAJhYhBGYHCySM5WTtIs4JUKaXpW8fFRGJBQJZ2YxmAhsMBQkaVMWA\nAAoJEKaXpW8fFRGJz/sP/0tE7RV60TaYA8KpTV/P9F6zIKADpBqFWhJbvlUdYwOO\nR7hrdmjq+g9YiaIHak7FT95JnQHAMqnJKRqPSu5SLwKU4NpZiU9MulyTAIU/pCeg\nC332UssCJN2rVa2VyfssjLrWyssCKcjsqoQ2jY2Uhh4MgMn4et1jEFmhX3QGK907\nxreM1MHun5+y6yFjmsOANI03utUJS7Pzu8t4fxf+ORs0j8SbFk/5fE6TvZhk1tJT\nkY0PQRJ4WSnkPcv+QX6UlrBRgDvAijoqRdzmdz394m3mVXWQJgBijb6V5kM5S7w/\nykuI8o2hiD3twvjz4Z7YI8F0TlXZCQOV+Kl3Xfy6ZiduA6Wmxcjxz4KRChICRajd\nOQ4IDrJyc4HMp6HfxjWXCzikyheS2+NkMevQABOxtf/CI9vUtECl6SdgThX48SfH\nM9mii/Lp8TY6//IVAg1z5y3OVZUGfHggVXQ6oghIcV8jT91xqKaNGLkEhMuiebYW\nmzBUgMK8aXHbOvnMAYEMTScW9aHALFQ8k1sfLsXDCf+BNFwYtitdZ74B09eYdgjR\nAS+YAAO5pTiREWCh3NlfZVkCy9EszHH9RVeeR0MbuopA0V36UuHHPEFsVR3l9w83\n4Ieam1pQDlV93S9rHKPHMVLGNDA2GHG6VDcqnumIbnwlukZXxVZRGB2XmdiVddXa\n=IEyv\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/files/AF16234E.alimakki@gmail.com.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n\r\nmG8EWrT8mhMFK4EEACIDAwTdpZNOKCX/kAf9MAU1PM7N1BKcpPdBZFJsG/xVeJRv\r\nOAtFw6oqKYlZbR/GF1N+FL5kHJ98rKippyzgbGlrJ7ybgL4IzpMW1e1DdpgnG6If\r\nZlfbGntuLVRzTp01+Smz5U20HkFsaSBNYWtraSA8YWxpbWFra2lAZ21haWwuY29t\r\nPoi2BBMTCQA+FiEEpFXaOWgX6MbiyBm/rxYjTsk9zfsFAlq0/JoCGyMFCQtJ/+YF\r\nCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQrxYjTsk9zfschwF/eUEa+z+2wqhe\r\n6VAEZgaqchxmQpjMGP1H8l4MheWZVBQc1qtfdXl9s+QDCyYfzNDXAYCw1GIm8DUT\r\nGT3loxmuMYuyzUWohMLY7yEgXn6U8k2NB/CRAcfsz5AT3LAndNuf8Zu4cwRatPya\r\nEgUrgQQAIgMDBCH9Rs++/u1zpHuFKZ/9nj21hHC3bFfOfqcVdru92ES+tr8PCwZT\r\nyXercMUb3179Ej6VEZbJMoZ+7lKwVj77UzlMHvYBNRQX0DS7wztI+yEvbcckxySO\r\nPxvk2X9px/awmAMBCQmIngQYEwkAJhYhBKRV2jloF+jG4sgZv68WI07JPc37BQJa\r\ntPyaAhsMBQkLSf/mAAoJEK8WI07JPc37JVcBfRLZW0ESnzcSpkfnt2w9hucXT2xo\r\nB/xvKiSl6NBmeO8xmV6giTt+bbiGnGsdMQ5ebgGAqcBpBSXIjNB1onV/wq6k1jr6\r\n05KnSv5lIRwKQvdDpU3mr70j8Rw5L1tem0NPjkyO\r\n=CFDD\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n"
  },
  {
    "path": "playbooks/roles/gpg/files/CDF6583E.josh@joshlund.com.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBFGauS0BCAC+3c+kVPOsMmWQ1IWobTn2WDzbMpgzH9YBVNCs7Rihv1cBufjC\nqCetEp+GFfoWdNWl/GFFhdousBSOOOPervnYUiLdIW+BXc/FTbysrXy7qJfCofUf\nJB7LOJw261eUYPglHES/IM6F6rmtkbfcnD+NPfJ3t/cEFMWDYid1BZcJAGdQ6pES\nydIG7RW4cbQHJPgzjubwEa/JsnSiGORsaqAjXwcD9ii4q/UkahMpfnmk/iLBh/Sl\nY03Cob9xGx2nW1agzjFbRFUFd5iqKN4RpUwutPsvQDy3gmiEX5abpwZ8nWHlb3Ed\nGu8acwrbMDebwJ/HsC5PA2+0bpNEmE9LqsF9ABEBAAG0H0pvc2h1YSBMdW5kIDxq\nb3NoQGpvc2hsdW5kLmNvbT6JATgEEwECACIFAlGauS0CGwMGCwkIBwMCBhUIAgkK\nCwQWAgMBAh4BAheAAAoJEM32WD6no1bWnZQH/1EHoD/bbnQfgY/ceUi1pFQF0vls\n00Ish1Wyva/VVoBXj7x72WW2GNPA+FLKRolFtnNo+BUNWFwDQV6mN3sjHuonOCyB\n4GpoX/W30+PKo2VCnml3mheFlAoD6i5aikQcqO/VetFljLl7enfmpd67nUJ0Tw7L\nPI6g21zy45RDCXip32XJF1bNDGONN35U5j8fga17w3K2vWV//Rl3SbCO+3erbBhw\nO8oAuc93MNtXmOrNoHiMUjdJ18jGMpJ0WUGdjzUuyNXhHYtkrf9KE/W7gk2+Wp85\nzumWGiZFU/OKs3U98ujDNS9vk1urWpkrucIwdSbGB+ad3AK7L2NtqQwuGZK5AQ0E\nUZq5LQEIALh3+2B3AlWBT+H8BmolIGSz/AHF+CwJkDPqf/BeKrcQxVMjGMHI0LBN\nRwcXIVqPnNx5tO80Eu99kIXqUmcpgnq3sS/dbHx5pBPWLwC3PJHpsKO+zlIVkj/q\npN3MpuABy3LfBI97DoC4AwLe5HwNcBjLGY7d7viNnnzk1sA1NJF6kZQ0Y+9wcxKL\nU1EYMiFJH2MPurQzS8BHJV3aVp7zCM59YrBUhF0aL0jPs0b/zm+LTvqSn9+72iIq\n1GYV0voBX8ogxBPqf/kSKFuxdox2EN9e3MKwRMcSck6Y4e1rGn5I9QlpCGBCoCBj\ngWtlylurM1vgTPhUwOMtgrxbEXoo9y0AEQEAAYkBHwQYAQIACQUCUZq5LQIbDAAK\nCRDN9lg+p6NW1pzpB/4lIKZh2vH5p1vKPNUNBL7remReaUJjWS9U5SdQPSB6DWFh\nMfEwK3dfcHF6bAPyiWf6JSPGcJSgmcOv4FW1wBuiK51+N8x3fAblp0DrlewFox95\nClWkr94rvHqIPhuKv636Wgo0a0/4A3jPGBqKpkQcxpZ/vW43dxrsfP6e+LZyfASo\n3ft7So0908f0Ij5lKIZO5DgjQJsNaqEK93Onu1++CxEwSMwbFxmDSrwXujaOtMgu\n7LVm/WuZFtfpvzr9bG8n0oyW0cQXJW5jmBsGx6ulrMdvtnEwOEXq+OmhSqW0EMWA\n/MJViGcd0lsmd03uuugIp92I2ZorHGFU2H3IELKi\n=2maT\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/files/DD3AAAA3.Michal.Trojnara@stunnel.org.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2\n\nmQINBFTU6YwBEAC6PP7E4J6cRZQsJlFE+o3zdQYo7Mg2sVxDR6K9Cha52wn7P0t0\nhHUd0CSmWyfjmYUy3/7jYjgKe4oiGzeSCVK8b3TiX3ylHi/nW3mixwpDPwFmr5Cf\nce55Ro3TdIeslRGigK8Hl+/l4n9c9z/AiTvcdAEQ34BJhERce4/KFx+/omiaxe7S\nfzzU/+52zy+v4FfnclgRQrzrD8sxNag6CQOaQ8lTMczNkBkDlhQTOPYkfNf76PUY\nkbWpcH7n9N50nddjEaLf7DPjOETc4OH/g5a99FSEJL7jyEgn+C8RX7RpbbAxCNlX\n1231NZoresLmxSulB6fRWLmhJ8pES3sRxE1IfwUfPpUZuTPzwXEFJY6StY5OCVy8\nrNFpkYlEePuVn74XkGbvv7dkkisq4Hp59zfIUaNVRod0Xk2rM8Rx8d5IK801Ywsn\nRyzCE02zt3N2O4IdXI1qQ1gMJNyaE/k2Qk8buh8BsKJzZca34WGocHOxz2O5s7FN\nQ1pLNpLmuHZIdyvYqcsenLz5EV8X2LztRmJ3Se4ag/XyXPYwS6lXX1YUGVxZpk0E\nsQDRdJvYCsGcUy253w+W7Nm/BtjKi6/PJmjEEU7ieHppR9Yp+LI3lyzNBeZAIVqk\n4Hco05l4GUKtEDFfOQ58sULDqJWmpH4T72DHeCpfRB0guaPa5TYY7B0umQARAQAB\ntCtNaWNoYcWCIFRyb2puYXJhIDxNaWNoYWwuVHJvam5hcmFAbWlydC5uZXQ+iEoE\nEBECAAoFAlTVFpIDBQJ4AAoJEPzVPp10xzLRWKMAoN6R8pzjT7vwHYDHYFlZqnEm\n7Ty5AJ9RsArkFD6YLaw4vlTboX0V1kuxNYkBMwQQAQgAHRYhBDxu+k4KK2cNXBlH\n+J1+uqtZhJK2BQJakQc7AAoJEJ1+uqtZhJK2qbMH/00biTSOHDZ5Zs/1itJwLkcK\ncOb8SuL6QmXdkd23OG8TBcCvEyjU/pR3EdNFP5oonoA3OjCk9lEkyxhm9RutCtJn\nQGQMvu1ZD3C1ZXYvLl+yTXhFlojXlVyZBGCUxPR4zLbp53IOz9bkfwhuE7Exi1c9\n0fVYTXXtBTe/oUqkSafbNwc+drDL6bL5GMXQlf5E411+hlzUnwtCAKecs+4lq9yb\ntZdsTq6srd0aLKKAEQt8769XOTLFPRyFVEQCQdKXwFIInXJu1AMSiR+HRh6vTq4Y\njZoXyTEQvZvw/BDxl8zsH1J5K9XvSquORZOaAXplMFLSpXv9u5wWHR78n7T7XOKJ\nAjgEEwECACIFAlTU6YwCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJELEE\niTLdOqqjj/UP/jDb+7B3MdcuMR+IsrD5oy/gAU6J2XlCFv49TJYL3vI8bWuwKbg5\ntFiIDEHf6VoIxvPIP9oUrNQ0ZrqOu6T/r95fh4JoUGqkHvV6GkB8soH6w8BhCgIw\nOfvuoYPPFxeRjbnIVKGNsBwiwcrsXWmk/cA0lBh84/lZUGHGlaq8v7vPsEYbsa/P\nWr4e53m49g8NapCLkevsLmmAFNfZms85nZwy4f962B0+71Sbe+dSR8seH5ybSiO3\ng1saUhn4XCut0lrR06CSoOI23SGTDkVVbznraUWz7xfKqEd9i2Unxf6zybTYVoHL\nC1AqWZ+hMhuo4oMfJoWNlrqUTR7rUhEvqijX3wjIu326UH5eMCas5TcSSStcxrtq\nMdueZfn1yXkCYe3773DYnrkAKSoTi/pjs9X8kZ1Icfxoxp3DpgoGZXUyxBfA3h7r\npbl4BZQ1yXF+qaIe78rd7ideEgsoldXC515gqMV0ZkDZW+M0xqAL3zsPwxR9xM0O\nOHSv2dRziHyXmCC8XviT9hPEzV1L6/8HJNdskPJGqhcx0kAXFftEuPfqSKaCuO+S\n1azrOkvSY4TLeFlX1+D2PiBPMBp2cicNYLz13ZNT/fJR0fxb9Fhv5Fonpqw1zzNb\nY5yGrOhBps8U/4ssBheLXbFR74hE1YERqSh4BLQf4cLAnhlEwJhw210EtC5NaWNo\nYcWCIFRyb2puYXJhIDxNaWNoYWwuVHJvam5hcmFAc3R1bm5lbC5vcmc+iEoEEBEC\nAAoFAlTVFpIDBQJ4AAoJEPzVPp10xzLRtFkAn3XOJUuQUnruzeO2oa4+BJMBsmJL\nAJ4pc6dtGRcoQrDqUk/vZyliX8Hb0okBMwQQAQgAHRYhBDxu+k4KK2cNXBlH+J1+\nuqtZhJK2BQJakQc7AAoJEJ1+uqtZhJK2mQYH/2XCL/4AP87o6fkgwcW7YPBvWxyi\nR6C3WKbYREYAt9YTJpPQTzJCPGXTszkhvIzmgj7RDl/TqaFCibNEoLnZxpNZMxqq\nijMJ4hSHr+0JSh5VrR9NGlKqdI1csXnS5rnMywFXj2GD9HGYnZl+ZlcML0WlS4i0\ngCafK6Ao1U6sI4+VnfrrbqmCQ6LxnG/5Ldld6ZcuNqiXKHVij3MIsnluOsToTtvj\nJ6EgLSN3x3b05HgQBS7UQW/7NO82H+Rk4kUgv5KejFGCzP7EiLhNGv3arJTZHebT\nHrIbsDay1GQTJKEbsMXSj7n2DG+rmketmZkt0liXLKFOd61cHE7L+xN9ueyJAjgE\nEwECACIFAlTVDWUCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJELEEiTLd\nOqqjvVMQAJY7fVkg6uScKyCYT3RDTIE9gPwIDxoz04s72pVhFH5IpDpUAWf+pYKg\nb/Pdow5QkkUMyYENNKIZnjeNF5BVzU++g1QoVeQPXe+sM0aD4gyv6N5+PL9GQULm\nt0gA7OXqcxEUfkP8oO2+5dQZ+No302isLK/lpw5roaKdMUA0dhbv0NK+3R1pMbRE\nWKZVMq0CHyjHEEYZS9n/rRIlPkjenAopfm3q34tpSBTP/nmnmPfp3KFlOaRfqNXJ\nzOR+MHDL2LaMPyRnXD4RA48bLWEcIdpo3mS7cGHiGJmuWHydymKk4x44nljvULN7\n8lE7K7eORH/n0u48kttSTA09le4wz4PgRjX01YqpYWByyNoXmO5LfrGBuVCh0A5c\nFlyfMfXhvGVESVY0uEyJv6mIgvQForZymmXAn5vNBGTJbOquXnG78B4T99AF15HE\nvWODh707N6Lg+TPRpyjEiDaZ1HpvfpSk5Yq8FBhnybhNuxYFGsONzEp66Xs5uyh0\nWgZO15HGo32CWE136flskB6wbNQ3zp7c2YKjEJRAxoqWswRVQzBppI5VZg0J/BdJ\n7jZ0rZmtXimwhgjB+S1OQXrQ3cp4FtOzv8eFL9Hbb36VAIv3RtwpGK/ZLNy+pHq/\nvzGducA2bRJf9vozvE0F/yVZfBL1OVH0DMDhcLsWo0thMwZXnpOYtC9NaWNoYcWC\nIFRyb2puYXJhIDxNaWNoYWwuVHJvam5hcmFAbW9iaS1jb20ubmV0PohKBBARAgAK\nBQJU1RaSAwUCeAAKCRD81T6ddMcy0YdJAKCqUM57aBB0MKtB7I258foylNoLowCf\nWMXExoUnz3AspRzdCi22vIeMNBaJATMEEAEIAB0WIQQ8bvpOCitnDVwZR/idfrqr\nWYSStgUCWpEHOwAKCRCdfrqrWYSStgepB/9MLcUR0BdC+jvipNOqSNFAjgtTleoM\nQixns2qsgFc8tsHDBQNfpvC8CMkaSRUSqVDaMyh5AnJAHqN70eia3Ng/lEYx321E\nVc0Z7GuTV7vi1ZopZecTONEID3N1FJ05y2VBSfbP6H3S4opCnLnfAr3I2R1sjT/0\nxA+C3tgaAlQywEJXZWik8+Ahlxc0jYhQbabOHvNrzlTPufYDxm/9lpb2/Nu9UJrS\nHJwhcsAH6wm6Y+SpQbEG/RLCXMkHnhRs2Zk6mpn6wHvCvflABKbtWaHj5YsK46Er\nMNJ+QJ/7likoL60AHiMcYX1nyuEfq9eKtadozBbITRyLAb9K77051WLIiQI4BBMB\nAgAiBQJU1Q03AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCxBIky3Tqq\noyVkEACtMHa7x5PQ0ZNJ8TrvVd/VrT5USuHwwFwnnsYUNzSc95gSwSEaPC3xwgs9\ncX3VRmOwb3IiCQQ7R0EamH/ydmZnlesbCsnamLl6dEmzS284lnnMd5X0wep2qq3S\nlS1z+5wW4ZnoodX98E7RyecjMYPLH+uAqGqg3nHG8eOpoSDMvIOJtOIvDc9Y6tbN\nsBbeKbOCyB7A08TMzVqayQvXzm6QShHTicra69oqIzhmu2zII3ZWVwkfEGweuN0v\ndocoXiqrentcyF3KLUX/LooDzdCAxuoJdovg41E69rXEWF//IP5XBT0LUDTzqwmB\ne7nOfoJF2RAHn3ySogdL6WNSGaH5B5NK1jGflj/Hr/HBHIYYx820P4aEXSyxbLQW\n1F0HWlAAQ9+EmjJssbv7cIq2DV2Ls3AOeY0GAWhTdvUVdVpOG+TuWRUi61XwjWPf\nvrJDH8MEoLRb2MhNRffle8hSdF8TP4CO1TCxtSFs0NXT1I/HazvacHzvbXspFDJv\nbYJsy+pRvOsf2QCcY5xb633duU60+IHJ9GMOV/ZqQR744wAxu+e/ZHpa2+mpI9Vp\nTMuBTMFCOQKbiLacsDJtFqsenZAyhcTU4DPFa0bkMO67Gwl0skuk2x8/0R3EgJ9J\nvNlsEz6vBaHpWhEddU1m6FMKKZkfo0xnyFr/WPT6zti9iKTnIbkCDQRU1OvDARAA\n8gIC641dK6ap9W1K3EkqRn0z6zizdVGr/jvf8xFXeUq+auxixZ0tEY6NM5CBSya5\nBCK9IGVWmJNbazyWUa4llA6EvmUxcTeGE7ppQA4Kl1bzvUq5upo+8+0VuqvLC/bV\nz0DUnFSWJYHAZrPZ+yO0yMq8vaGTo5kwKixQ4Ni+N+1EiALKZex1g6UW9d0HAcYE\na/lTWhz3J0V1yyY4Vov30gtoo67KkSC/SswZzIR00CQGrz3twlGuB73Sm1YfqDqb\nY8dQLJeyU0ovIeU95VI5cQF6D1H8YdaMWQm6MtVAfIX5WMoH+eq4Ank9hilReGAN\nkIWNSqM21Drdu3crbGIYiZPEadKfGxwquwvRDTEgD4gjqMvEdxA2W6s4WR36SwMk\neOtESj21MiR2YDcbIzIbUh9p0P8DZGvQcVh45jCgdOcL5th9R076npXHn8FIe2If\nAZnX1OnpsKn/YqJ0wNFhGYWxV/yZA10NbFKFXhD1FGqrOz6lSqmqDz00tXofF432\nae+7PzTP9n4cij4k0SYG1l/LThnOYL3SNUCG3rCASeWoXmhxCYRGi0Xw3IJrcpVN\nmNQD+SLLTjVB94AlDjSlx1q0V+9ymhGHi51wsBSajMwDexaSI/WM1y9lROwl7eeA\nD41fPArzTleAqT89akWLevTBLWvj59mku9vZAW26/1UAEQEAAYkCHwQYAQIACQUC\nVNTrwwIbDAAKCRCxBIky3Tqqo2NCEACHJ7e0l8NhS4slfzej1AAXOwL1wDexn6th\npgexAyqZLIaibqhIybhSo1LOL1NY/55ytscbOQL7NliRAXVN6F9lcer+qzxL5Jgx\nzUU6dryapNZYs06u3wfr8ZtSbvIAON/w89tm9tHxoNUIYZZUZROFBW6fn8RkhboQ\ns0hJFxWfWghOxhS0TXJ8/MZ4YcfDy+Ew6LIAym3A1XY+++2VMEHqKcyhU95W5sqA\nsfO5MkRWa0E9JTS2dWTteNTWPonywJGX/mSVVMZgOZF6o32Vb9LTnB676YQaPiMl\nu2qg+vRkRM/zyGjvPx7hilf68CWxZcIHslfp5gJV6RvtlK+muEvIkSmNYyi8hQp1\nY5C6uWb9JWt/9ISJ+Xz+n+5nAHEUzW/LeEDyhjVlS9vOoAAy18r47mQybzJ2q2zO\nHo9zl3fKOJ2S4SFBKGHuIhPOxG2CruhxN9U5+RwTDqKECeuCZROMYQLzlmIP2vM/\nNuFVhQm8iNhbTvEenh4mWD4IuOHJkqvzKKzAXllosuUK4B0kblh4GaOVmEjaXGw8\n789rOlQzD5566SgKPDNUtom5/eIcy6/UYBoFd7lLltIVSSCA1VUMU4MWJgjwa9gk\n6MxoNe8dcJ197oQMfhZNjJ80S5C+a2al4wrR2vL/3hXhy2M2kG73RLSzxEiVoJsG\n+hbzNtfIa7kCDQRU1O5ZARAA1pGrQ1V3YMXF3DzwvA/uWb912pwqUvMAAKvYCDiE\nLIOP07c32+z04N/bOXjiZ2Jb8AuICj4v92tXAygtf18zxwoU8AOXiuScP3wy1Zpr\nBw8k71dNy0XmEXbiX7tkLoe0OzWlCaNTajSXTELT+nYHTOkBsrC4T+y7AwYueQJY\nUaRkJR/5Tc68UnRSO295pgJd7EoWWAky3bdH+TKN0MsagCJwa+RrXFGtIKjU0XAK\nsddTxQKx2SUGF0QVdNZ/14Duo73btoXtHgB0oxewnsiJp5XKWYm57RSNLv1LKr26\niSUtUM1CAIZALuGMAyQXVEo7OmzuZmN0yRYM7FSnpG4rIDnDxYhDTaa+xWb738V8\nuLQDZAVnAuBEhq1RQEDrRM/XLbibvVBzpd+JI9WneNEp0ehq5sEC6FbKYz0HqVk2\nSH1Dpb0tgrtxz3c7rPs7vRdmFMxTuYctSzuqNHpKX+C6rgyAW2sxEKD0ys8OYEa3\nhvrQFSAznM/j3X8dge1DriHIQd/Dt4+LMdPcsQk3vty7pYxZIDRa9hl7ngaesQSZ\n/7PV/cj7U7qieTr1ulO1Gc5GcyS2Hu4P9109HX1tBEQvGHpbqe9Lc2d0VKgHVjG9\nvDLrE1h/qXKbmn0LF1YR4djaM+sYCfYOO+WzZKUACPdMq3Lid/3oQ71p6eNgu6lQ\ncgEAEQEAAYkEPgQYAQIACQUCVNTuWQIbAgIpCRCxBIky3Tqqo8FdIAQZAQIABgUC\nVNTuWQAKCRAu/H/w1BbgFNx6EACR7CKB3Mv2lNaRRraVRwjNrumyODqsnX/oe3la\nd04iCBb9JxGyNyTGF0s6teoaocXxIeZ50bF7GuYcnepMGpniMCkE2ymlM6ruFNNT\nUYC02FsrowKQboC7S5DN2l7lb4nlgyDX7nOlOMmhTc3D/QsduMyS9H5kjFFKtzLY\nOwREV/RHI/wQUyTyze8qs/BxpT3/HsSJuGZybLSd/fmeM43xghcdfDgKTaGkFkhh\nW7UWgtOhQtYxr0VD4HEw4C+nMyksqKAIFMBjJAqtsuWeSgavVrbU8KrzlcJFHSro\nvZ7Pi0mKMYHGomPstZcZxwr15t3BhDvogMSRscU1mLUigLEGiWxPVxtQlmHTZfMn\ns4Cy04S7jK4Gix0PN4Xi/9rOcLFCb5zddcLVrqiuT+dt/O/TPKUKHTvLL1gF4Dly\npbu8TQWtO7xDSPy7wSdPWUN5GBjsxbZfVlWpvvVMmGUuygIl0LkrJLKGxk36AnNp\nEPqsQ9e9Rsgu5dP9lGPz3igxE3p+UlhWo5eqJqZwAfEFb+0PQzKSQ6zIFQAf50eS\nI/pWf+Xp9XOT47d4y8aWzHA7T/ja9tbyd+eg71ZOqOFtVP8zFWvmPnoosxrBR7qK\n/RBY5/PXKhfG10yEYXSjTap4dmsy430l8Mcuqo55iixgT5vxZfTeyFjTjHmjuHD1\nrTTfpXk4D/9GI9cIfrWczhrbWN8BoP66ImMXpVhZzDt6S5u9dHSNJdqivDzCkktb\n/psXILvvu3qLmb1nJbsNzN9GJm6LoduzCJ4SqaodjhMkNi/Tc95dx0n2cCP2Rh/j\nvzo7zrqQO09c8at/pFEiF8LgUlc5QaB/GNhXBqJog2yOzUPGKq0OMy/wttW42TCe\n7V+J8fnn16xfGhnVwmiWRQaqdCiFDY2IiOHhnRwfJVANrddfuU/AJ8vY8XXzrxI7\nYZL43V530Wich1VB00XLFU8aj08FsjdFvR77AAxFU+Cd6sH6yq6jsRXppQ0BOO15\naR+wopEvtKwDdRu3TaweC1XMLLQ4XuN9Ql0bMH0d626uMG2zUfZGO1jNTOS4sUhE\nqJsImbsL/hgNDKYvfo0wSHPWmQo9njw7aG8Mey77I3fL1ELj/Tfa86njPpJ/tmFM\nLV9ntWACcW/c3tojdcP278rTw/4zk+Sr2Zv+3bP1yjJd0z4B3gYYz2BUYTU7dyiA\n41Kgk4ZfV1n2NUAxQJYzvEIAZcMEWA3rOTb+AjcBVXX89Gk0BEykVmA9G808tbmI\n+4DUd2c/+d1xeufb43TGOiwKqwY+Os9iey3FbsnoYuzKPsd5LByJFEudbMB152h9\n5u/NysaM0AjC+yPtlpSLUIaDUW75VAlQKPWj1Ag5uVpc2ScMEjevQQ==\n=uMki\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/files/F67DA905.nop@nop.com.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFjdUwkBEADEAIBYC2JyhylLiwFOif465AZjbuNavvTVUzrRm4T4auwWjpgt\ndRFrdji0dSq4BST8/yHweEOTDMVPFNo8U6vvFg0io8+MyBILtMpbSI5fCWirYAn4\njLyqLEa1NYT7eCxrLOn90ALvqWMXUXGD0l4veLuNX2MozV3WGjPXujtK+jspSxgs\nu7kMUD+7QRwyHCIDkN+SxoQnVZg80eFiQPeIH/XKp8C4wfikWPYk4/28odEpbXia\nbe56Ne2KSgRsytBcJBbN71W8XEsFp+JfWW953vEAqKIoXHrhOKjU2akdshDEoElm\nYoNtIkXHU1MGqGRQVLbPE1ZHcowLl2uJa477YCLJhb7mpKo91ppiv/th0DMDw86N\n4+aia+EvmnZdS6tL34lwKpqtwOah1tzTwEezkhjpCQkTfE6dzYFUIqCB1r6pc9yf\nZ9VPr3g6zyh03qXv+XDPOKyos5d52gkt0/9W5sHTlOLzYm1f5EnKbHzH+YnOmF5h\np0Q2sofaesSt/ZOUBKn1XdK2lQtc59yQBVZ6hV2NeNBmu0nsYSCfk/lFHam1pPib\nionJe8qbjh0eZE3iH5eMvJ8XHiLBIK3a9H+jxpKfL991iYZ+Jf7W0RdaehGogXEB\nTBn6WgKcH2WxxCDs4KH3E944KoDI7CjWGG7hbSlnWwQBTr8jwrjPmRJv1QARAQAB\ntBlKYXkgQ2FybHNvbiA8bm9wQG5vcC5jb20+iQI9BBMBCgAnBQJY3VMJAhsDBQkF\no5qABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEO7FmQz2fakFw00P+gJKNgva\nA2rNpxuZ2H3FIWWnhBbCewufIQjF7s00u8/dsBh9zc7h2S8Xf5CQKCUMnQ5q1jDD\n5Ei28D6Hq8si+njtNlsE6wxbY6gUAu1Hq96+M44KnTSfnyLO2wmsKjRron2z8Ent\nwb/JhvwSCNJkzAlAKoTLTkzreVxMw10YtFxMNHp8JVLOkJG18QPLF2F5cMvstDgk\ndcvDbALyX/HiMBdl5Z3mKOw8iF4V2Yo9CQERbvtEcukfbiw4YYp1K3JorHAS/jQh\nqPFdbcjXsH9NYhLf9rWkW3eNajlHPwhbSjpING0b+BpeUWSvz0WNN28dTZQhBUqg\ncMXFOEckqvizdc3zLKT+VxNfNmCoKLMiZ5rZpIRTc4F4RFnGchXTQt1oifFtj20v\nrkRVVNvw0Ui9opqNEXn/59v/JN6NHF9EKKaisvcOr+P8OLQ6hPM7rBkUuRioryAI\n3xHsKakqG8s24wwRufIux4nuAQ7e+eBlzPc3wpBLHI76mnS5O7caC44v/y8MLLBA\nbzRlk0uNNhxwsvkqJ/4G5c+F1V/BDK9udcdhfAMGs9umIct1lsl3B9hODCOyxmsm\nWb9hJcOe29rZWotq9tytUN6q705YG85WgOjbN1c9XVIGIyYCKJfP6qT89yxCOO0p\nd0vwWDoruUf2PRe/P2/4FKThkiiixX0vOje5iQIiBBMBCgAMBQJY78HABYMHhh+A\nAAoJEHZ8ggrsbC0QFJcP/0mW5SchF4qowso+LHI/fmOSHDpJts+Z14VzkXgT0aQW\nuuk39aKHl1jNt/cYuv6Zffd/EgRT7moSWTyPFHodjF9hgTuUp84I78oJ6bAsVAGl\nFq28UpFRC/LEoMhFw683DD28KZZZc/yLfpuNlIIBgnnq2OelIk9wRdydCz1BKsoq\nkUP69B9RNxENbtjIAmBqbNGFid1n2whmCccBY/JJcUZYsIv6qunZvqAnCpBk2r+W\nq23FAX66lqw6SnwVIv+HRdQC20DqvC++4XfmthLOOjpYmeCIH3JKmGm0FuOL8XO+\n2lK1sB02PhxZSF9zs4bvvQ98KIQ1weol1jmVUFTT2DLle2raOfqi1JAOPWgEdQnu\ndELB2g9fOBUjl3nTQ5CdVmrkdiNeOWgeVicEbWLTwHLF2Gyc0P3x+g+vkEmFvnE4\n7XcND+d/WFOCI5ieYFLjASQCJPba7dFqIEOr26tSbJMHqceMJCLeWgAzfxbHfYWA\nQWqL83Yi21FGdtQI8KIRlNJ7pHSH96fmd9luu+4fPDQhKGNOBg7f9wuQrgY2Jb0K\nCmAFKsPU7BfgpLhCD62WQfXyvqWqpi/dg38jsFct1ZaQjDu8v5YC+f5kNLu2F3Zd\nF13apEqC4bZkYYdTBnPRFEi9I4046vezlLH3bf1rARvwB1RLUACxDnNItVrfTVVR\nuQENBFjdVLkBCACnD0zRUal08HGD9qdRkor9dM3tl+VU6b2CuurjTlXKc9hMvCWs\njuvpG55MyP9px3b2zyr05SoFltmUDgLTruW6DGuRZcATmJFkYji3uqPQomREwSAL\nFs8ayiXHSaYlmAHTflBXUc/n0e27K9hO5gmTfWeArtWfbTbwH+kUVAJrFqQMY1qS\nN2TXw4ek6Nz2F9X4WcBUjmDq6cJyWaSF8WPWFAA6+0r8ibhw4coGlx6AlRSi/Izy\nGwqzIn27e5FbwB/NPhtSZGnTJamY9OlYIdgcr94OjKmuVahRoYe23CrcHuavcsXT\nWsrcoCe0oyRn82Sv6izsbEzg04wxinAZpNQRABEBAAGJA0QEGAEKAA8FAljdVLkC\nGwIFCQB2pwABKQkQ7sWZDPZ9qQXAXSAEGQEKAAYFAljdVLkACgkQ7ZnjEUVf7Bp/\n6ggAjO6bv5okEWAOX5gN+4eEJuZpg9ifeV0lQqAmktQIcPcMGoIAMVwfd8btGGCh\nm0cTSMdM8ZJ+Ux99J0T8E9Q4JiT4LP3/B8nQMnUK/eaIBe9exM6dTeWPQ0ay98lI\n7vhwycQKjlUf6D67IN23E+irnI2WbmC4+yKGC0hKaUuAdon8zDeo9LtsY/NFIIvv\nJOLRDot9wP9VhX9ZkU51DUyDJSoXVP4aEhET9fY2WPO14nndGWuTwofOxcre6C9y\nMkpxdRu59+EZVMucg//iH7Bptd+60tAXF+m5Y+FR/G2MSzA8GfR6F8FGpFFcXGP1\nqeqVwtcwAxYcXiw36sbyw4lHUmxBD/9Y4E2ThpHNqxUj4MtH2djdH9gs/Iu0dBef\ncCZw+HTI8airYMQyvJY3FAorLQrv+qKPI5xTbRm+L9JPY4SZK4oUVfXwpHey1KOa\n1oJvY3M0hwbY7X9/ru+PsOrXMcJ7tlywZQy5t6AcKpzZR9k69FOn2I9Xp5o1XJBK\nMlzATI8Q9GOwIrtGEjHmMPiefksTsQMa+yPlbEHsOXE6aEgCpybXJsxQUcLWfWUU\nNMGRu2HodQz3h5+kKTfX4ucbCwgc8ul8OcROWaUmXE6K51RYLxoJXCb3N0viSiVF\nGt604ZOKH6OLQgwx5VPOTGPYq6y3q/xbg2fVx8KDtf4brtdvZhv0izdPOC/RBxr6\nyirqNwToVrin97Mhky/A7OjQl7rsqo+pBUyrGgPR5YpOiZB0ARCGeSb/Y8AxPa8D\ngg952GPGxHtT1V1D33nQiUd8B0uW3iIVoH1WEYMMb1IbVplW1a8tismSL/kZiZZ1\nkfGbU50xk7tMLN+93wiL90fzVNbS+qv5afnaymycluFWlL4KgYqOSagQVh4mGuZ9\noJ+tk7yVi1n5WKacNyhE/riGT4GSWY3d8WO3dPwTkJ1bo9prGQkECXV9hWGRjZw0\nDUs8iYRFuh2ZLZfdrETcWh93wrlb/VZaLpilMKim4LHvtax18BxFzW32Q9py1oXs\nagIJ0r31bYkDRAQYAQoADwIbAgUCWVUe0gUJBDuCmQEpwF0gBBkBCgAGBQJY3VS5\nAAoJEO2Z4xFFX+waf+oIAIzum7+aJBFgDl+YDfuHhCbmaYPYn3ldJUKgJpLUCHD3\nDBqCADFcH3fG7RhgoZtHE0jHTPGSflMffSdE/BPUOCYk+Cz9/wfJ0DJ1Cv3miAXv\nXsTOnU3lj0NGsvfJSO74cMnECo5VH+g+uyDdtxPoq5yNlm5guPsihgtISmlLgHaJ\n/Mw3qPS7bGPzRSCL7yTi0Q6LfcD/VYV/WZFOdQ1MgyUqF1T+GhIRE/X2NljzteJ5\n3Rlrk8KHzsXK3ugvcjJKcXUbuffhGVTLnIP/4h+wabXfutLQFxfpuWPhUfxtjEsw\nPBn0ehfBRqRRXFxj9anqlcLXMAMWHF4sN+rG8sOJR1IJEO7FmQz2fakFYk0P+wSm\nR34nZsFko8hWdZ/JHABFQah9zneouNPHiCNL3w5QmOHfwFDaNoJxNdkkViq5SO6Q\n+Q6YRHEZJ/IUlwvdVGENBMPNzScCeU+i9FkYVe3WeptJ1v4hFCejy2c1TMRwWdf6\nscfUcmvW5wB20IQ71ZUAL+9l0euqX+jgEuFCiI4oD7tuRN3HLA41hqPyEpHtXkJl\nW3x6GstU8JEulr4LnRkKmBD26nu0JX59efbJTqNv+kp8ikfi2dbYInlgDOFFSL4h\npt7IFatulNPBHDCu4TjDX3OrYNXC6nFdkUzjsPjLxLQlUW1jtizJtC/SxLfcObz2\nS2LSmA7JOmD0iChl8KUvctbJffy57UmRA7I64AsZMgpYZUKT7PAC8IL3Hx3Miohb\nMwZiqzY1Lq7ROlkovIcRBr2SgAqJ/k2dqT1vmpOANOu8ptql8wNLaYBpEodULbsr\nSYdXhTXhs09AAeZE1KEaYJ0Jwx6Q5XWQ39Vw+TSWzTBntXbYO4GFqvNDE/UIsv03\ndOo5vFf6Q6XBhzX46qKuwDa0WRbRrlrhlvGyEC3ekDQtERDiiamvoanL0AEb+Kku\nmrssOg6meN0PMIjbAHA55cA402TDEuJqI77GE3VSGTfkm5WyfaUgo07Q2DYS7DNC\nSDNNCwB4d8zlsNMFyhJ4kgdcwfshxm8VYDaQPQjVuQENBFjdVQEBCAC23mj+EBEr\nm0JwFLMuE58rDEOa1Uy2oyZOrd6E7zexprksF0zWLMwZZHYbccE74YMSahIyIyL+\nv1bsjSNknWmvjuWRBKPB+++UvwAq6EUOGu5tBZqo5+S5ETSZXSTJEdw8vvhF75/9\ni1RkjJWYN+yCHOEYqxVP6SnTW0o705OpYkQiFNtf/0ANWXECB62yJGSQP+zCzLkF\nrzfZmOFIZMnrox0p5DAzTHqYB2+Mo22MWS922n/k/fUjI1byFQTsU1IRJCU5Ep8j\nCm0HvH4HYbEAaabECpSF1mUaH6WLeYrnn+OVleGS+ZvXJNrpXS11feuUBgaqnQxt\n56pAEk2KKhGlABEBAAGJAiUEGAEKAA8FAljdVQECGwwFCQB2pwAACgkQ7sWZDPZ9\nqQXKeBAAgWJ2DdnxbjmhwoGeLWbXd69yQVs2MB79+yZUucITMjqcatmxTn2Y1Fkg\nJQQxqmce5hlzhq2oKi1J1sVlextej9AI/DGbZTX42i8Slwu30ALbuVSRDezW0mW4\n13lG9UO4qjgQDI1jHBuXu7eeGnB7RnPy419ALhfaKIS1W5fpnOoKS2PCAilPvElm\nUC7hNI1oJONPPjJQ5AHV/OdMzN1rdxsWEzzH6EQ194042T5FtHfcdmJNKPToVhhh\nZY5tQU9aGr108DH8WU6zjvW7ZBdtmPbMdVXDcjdJQ10DYh0mC1sKHqAOUbPj7IfW\n9N81Cb5+uJiJ5IgDjXdXaJSLlNg/duArKOijjkL6jkXCmD4hBJN7H+EPoBsMELfT\n5dbgdOCkaxZsAYKKpaTG+XBUNlBqVx63JYDsm79P3r1MUxA0z12YKo17yBiOcUVv\n//8ofExUUVGKbpaxRlHFX5UeCDw6RhAtRc6NmwDjbOwIX/OlgpX9uRqsaumcUlGj\nVrIk10+LsCOqH8z1tEzaUeI6uSwFg9KsYE5SNyJPjbFtHBaUZse/YJUAKatONkp0\n/jqOFpYsNnPZzV9M9+gdrxJQg/5Lp24JQ0TEgk1CRMfd8K5ml8U/2/306b0I3v9i\nr9GJhXN13yzZ305ZlwuVMjhO0DIOm1rKOavzXFWU6fhlMsgoSViJAiUEGAEKAA8C\nGwwFAllVHvMFCQQ7gnIACgkQ7sWZDPZ9qQUrYxAAs420HJoUFd6/nbM90D7wylDR\nAPgiGPa9p+LZPkwfnScEQ2frhepUWoRg9tg4kMSMqzjkvl+OUKtI62m5Ha77fz1b\n3LDyeeyxP7vVVzD6g3URHw4ymr/mvUaHT8AFMgEbnPW3sPHeAdikoWV8DKAdpU2O\nlz8PrZPYTXAHw9kLmC7wcvTEbTOHh9ZqBw0+ee6tkpxYF8q8OeyPUfQ0XVqcZZnT\nPNliZKrngdqxVWGucTDa92gTlUkpKuLbyvXzbycXqpT/te+H3yz1bsGUK6C0r/Yg\nhGm1F1NPaPtpYoivXwFqqGa2mILKZEs/S4YKyGWW2JrGCsey8cbtKl4DYbf8OGWv\nHFxttPF9brp3YTMSObajLNWsIkepYEc3RLhdiS9MORcoPw3lHaGrtjtpGCQrveJg\nFMmxOxkpmXG7iLAxiIOPGneWw0ZXBWHK/osQc88FjOwl4KgM1sze3oCtID+4wD6y\nNb7ptyx5YetbWqgioywqBBHB6q2hxT+DvSh13gIiNCp1SLuooNUimN7AZlqyxPuC\n63VihM3cFJTDgVd5nMY4QSVKbVJKH+uolYEa5m4Dz6hSGKfomQTfzjqHFirDLIID\nzQHdI2s5rgtubxfre1opnWgIOQS+FUp3/NC7NTjcWuOqxPanJ88bEFBLOknSdCVz\nf5DF98xH2R+RInfyydC5AQ0EWN1VHAEIANyQXLr5yBq4gTZQNlzZsu6WKbJkItui\nxW//inZ1ouz/johaqJdp1ioR4JErZK7xPWuNO6NIajT7GNaMfYcMwI7cbg5PHmSy\n83kpKBsmqgK+3xkxTaW7CBGB8RqH+jW7a0pSzQ4Ds8rgsxKJ03puCtDeew+IY1Tc\nl7AEB9KvIc+yuCzEinGpkUm3TElsOxI5RaYL7V35kuE1pjunjQRrl/618dwnjRgu\ntTdhUGEs6mzZH8Z2JMi5JgXVuU/5kq0s3YodkYO1Q6Gv42c9NX+AUTQKqg/cHswY\ntvQHJYoisB7cPYOdNek26cdKukvGu5G1s+0pE/8FfoM+jEXJv2tTnKEAEQEAAYkC\nJQQYAQoADwUCWN1VHAIbIAUJAHanAAAKCRDuxZkM9n2pBVFKEAC0gTrVc8f1Uao5\nZrXGEmO6iyT1/CwBu/I55yUdvMQGukJh2L77bVzPSaLyzxkSLr6jXk+5P2MdjVIl\najQdxaRhH5DCR2hAAkXotCdkegViMpNAZaZw4lRfWFv4TMg7pqHMK+RBBfNsBot5\nhm2lCe8m+p4c7er01QaluUo2DV6DIgdutoCe7wGygipokJ8sY1S9v5tzBl5aAE02\nddVA9RHvHXFPLTHuhZsgiuOFmwK17+1Du+99HeQlzuINTXNBZpN+D7+lkHCHPbH5\n3kfLc5G/IbVdoJM/6SGf0966kLHO5K9pHB2qc2smlaI3h1A6vyJzOd0VPtToOkvt\n0Vgp8W9xu/xGYNc632W+H12IH3PC9bL7Sp/JFxfN1mHC/LEheYgl1ghN4pTKwC4f\nle27LbV5rl7Knt+A8YXtPx/G5CzoIdlbTRdrmYL/sbfGSZ9d4+OoxTkWYtnenKQB\nUB+vb2mGfv+xJuHeveE/J8VDDJgzm7qIG+Qe0YoUl4RoWS2lNGjKYaMeL64SR8/b\nsxna4+sVGxJ/xNHQHIF3yUIkRmP0MJiexTy7a+eGZUoVX4VDBFyj5+S0pyFD7cDe\nKccZISUmsEI28yFQGEr1URCIU+cRIBhi6B3mKNheU7x0f9g16K5KjqemU/EtBrnU\nI0BENiwS1PKwPVn2P4Z94LCxO4YFe4kCJQQYAQoADwIbIAUCWVUfAAUJBDuCZAAK\nCRDuxZkM9n2pBT9GD/4w3dytziUyAMF8H4VV1e2bmledAU6IO2c88D5tscV4QvsC\nv0ncYVuJdk5wM4LC3ohUiA2o9Wu1gTSUPeef2m4l969MiFjiEXOoFPNNyGzuImet\nJU9t+CoPJanlqlkdcTKbsbMiKkOwNSpmqNtbrz9V2GF2dEVeV4R2WpRtO3r2QN9z\nYbnlXVwyZ0ILO5NyzTJqFcn0K+WtYxarnvA+aGpCMeoW50X4EU+2oBlkffVM2Srk\nW9sHHYvy5d0Rtzm/VwFQs/CpVQvDbk/kIPi8kPmzNSPiqukeVYhK7QePoIQwtKFS\nD2Z5ImjdRpcVyEm8ds5S8dHHc2v9Fbbgwam03Mko+Q8O6oYLLfqJg+EssYIKHpJW\nGZm2e5Wy4tefqI9BDRFCeH8WosC8jqYSFw5pFrCNNF5g5bR5xXq/xUMjoAHRdQDj\nNPrjYerdBiLVRcG8+t3amhUdj1vuJwckDVqSn4Pyht51NUj0bRtE3Ah222U9MOW8\nG8xJU4Li8wAyid5NfVf4VDLrXv0DToZcxRpeHrMEu6rHkH2h7EJPqQmby6DjWyzz\n4QkK8WIQc92dXDTwJ9yJEtTw56LpUfu5h9tsKBKR/F4Y0QnL8myFB8Enzrdh5yQC\nYW/J8XxbnZMLNe9sbyPv+UcE+5mwKpmnup56lYx4AtoE6gUQh1PQuxm7xWtQuQ==\n=E0RQ\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/gpg/tasks/main.yml",
    "content": "---\n- name: \"Install GnuPG 2, dirmngr and gpgv2\"\n  apt:\n    package:\n      - gnupg2\n      - dirmngr\n      - gpgv2\n\n- name: \"Create the GPG directory\"\n  file:\n    path: \"{{ root_gpg_dir }}\"\n    state: directory\n    owner: root\n    group: root\n    mode: 0750\n\n- name: \"Create the Streisand GPG directory\"\n  file:\n    path: \"{{ streisand_gpg_dir }}\"\n    state: directory\n    owner: root\n    group: root\n    mode: 0750\n\n- name: \"Create the Streisand GPG keys directory\"\n  file:\n    path: \"{{ streisand_gpg_dir }}/keys\"\n    state: directory\n    owner: root\n    group: root\n    mode: 0750\n\n- name: \"Write the Streisand GPG dirmngr config\"\n  template:\n    src: \"dirmngr.conf.j2\"\n    dest: \"{{ root_gpg_dir }}/dirmngr.conf\"\n    owner: root\n    group: root\n    mode: 0750\n\n- name: \"Ensure a GPG agent is running\"\n  command: \"gpgconf --launch gpg-agent\"\n\n- name: \"Reload gpg-agent to pick up configuration changes\"\n  command: \"gpgconf --reload gpg-agent\"\n\n# It turns out that \"--reload\" doesn't work on dirmngr.\n- name: \"Kill any existing dirmngr\"\n  command: \"gpgconf --kill dirmngr\"\n- name: \"Start a new dirmngr with our config changes\"\n  command: \"gpgconf --launch dirmngr\"\n\n- name: \"Wait for the GPG agent and dirmngr control sockets\"\n  wait_for:\n    path: \"{{ root_gpg_dir }}/{{ item }}\"\n    state: present\n    sleep: 5\n    timeout: 60\n  with_items:\n    - \"S.dirmngr\"\n    - \"S.gpg-agent\"\n\n- name: \"Create the Streisand GPG keyring\"\n  command: \"gpg2 {{ streisand_default_gpg_flags }} --fingerprint\"\n  args:\n    creates: \"{{ streisand_gpg_keyring }}\"\n\n- name: \"Copy the bootstrap GPG public keys to the Streisand instance\"\n  copy:\n    src: \"{{ item }}\"\n    dest: \"{{ streisand_gpg_dir }}/keys/{{ item }}\"\n  with_items: \"{{ streisand_bootstrap_gpg_keys }}\"\n\n- name: \"Import the bootstrap GPG public keys to the Streisand GPG keyring\"\n  command: \"gpg2 {{ streisand_default_gpg_flags }} --import {{ streisand_gpg_dir }}/keys/{{ item }}\"\n  with_items: \"{{ streisand_bootstrap_gpg_keys }}\"\n\n- name: \"Refresh the Streisand GPG keyring with keyserver information\"\n  command: \"gpg2 {{ streisand_default_gpg_flags }} {{ streisand_default_key_import_flags }} --refresh\"\n  register: gpg2_refresh_result\n  until: \"gpg2_refresh_result is success\"\n  retries: 10\n  delay: 5\n  # NOTE(@cpu): We skip the keyring refresh in CI so that when the static keys\n  # in the repo become too stale to be used without successsful refresh the\n  # maintainers will notice failed builds and fix them by refreshing their own\n  # keyrings and updating the static repo keys until the build passes again.\n  when: not streisand_ci\n\n- name: \"Set up a daily cronjob to refresh the Streisand GPG keyring\"\n  template:\n    src: \"streisand-gpg-refresh.j2\"\n    dest: \"/etc/cron.daily/streisand-gpg-refresh\"\n    owner: root\n    group: root\n    mode: 0755\n  # There's no point installing a cronjob in CI\n  when: not streisand_ci\n"
  },
  {
    "path": "playbooks/roles/gpg/templates/dirmngr.conf.j2",
    "content": "keyserver {{ streisand_gpg_keyserver_address }}\nhkp-cacert /etc/ssl/certs/{{ streisand_gpg_keyserver_root_ca }}\n"
  },
  {
    "path": "playbooks/roles/gpg/templates/streisand-gpg-refresh.j2",
    "content": "#!/bin/sh\n\n# Refresh the Streisand GPG keyring\n/usr/bin/gpg2 {{ streisand_default_gpg_flags }} {{ streisand_default_key_import_flags }} --refresh >/dev/null 2>&1\n"
  },
  {
    "path": "playbooks/roles/gpg/vars/main.yml",
    "content": "---\n\nroot_gpg_dir: \"/root/.gnupg\"\n\n# Keep Streisand's GPG cruft out of the way\nstreisand_gpg_dir: \"{{ root_gpg_dir }}/streisand\"\n\n# GPG Keyserver's Root CA Cert\n# Currently the keyserver is using an Amazon certificate, whose root CA is signed\n# by \"Starfield Services\", which should be available by default in /etc/ssl/certs\nstreisand_gpg_keyserver_root_ca: \"Starfield_Services_Root_Certificate_Authority_-_G2.pem\"\n\n# Where is the Streisand specific GPG keyring kept?\nstreisand_gpg_keyring: \"{{ streisand_gpg_dir }}/pubring.gpg\"\n\n# By default use the Streisand GPG keyring\nstreisand_default_gpg_flags: \"--no-default-keyring --keyring {{ streisand_gpg_keyring }}\"\n\n# NOTE(@cpu): Since GNUPG 2.1.11 (the version Ubuntu 16.04 installs meets this\n# criteria) the CA certificate for the HKPS SKS-Keyservers.net pool has been\n# built into the GNUPG distribution, so we don't need to specify a CA cert\n# explicitly in a dirmngr config if we stick with this particular pool.\n# By default use HKP over HTTPS to the SKS Keyserver pool\nstreisand_gpg_keyserver_address: \"hkps://gpg.mozilla.org\"\n\n# The default timeout is 30s, we use something larger\nstreisand_gpg_timeout: \"120\"\n# Specify some options when searching for keys in the keyserver\nstreisand_default_key_import_flags: \"--keyserver-options timeout={{ streisand_gpg_timeout }}\"\n\n# Which keys from files/ do we add to the keyring in first setup? These keys are\n# trusted ultimately to verify software signatures during Streisand provisioning.\nstreisand_bootstrap_gpg_keys:\n  # OpenVPN release signing key\n  - 2F2B01E7.security@openvpn.net.asc\n  # Openconnect\n  - 7F343FA7.nmav@redhat.com.asc\n  - 96865171.nmav@gnutls.org.asc\n  # Tor browser release signing key\n  - 93298290.torbrowser@torproject.org.asc\n  # PuTTY release signing key\n  - 4AE8DA82.putty@projects.tartarus.org.asc\n  # Stunnel release signing key\n  - DD3AAAA3.Michal.Trojnara@stunnel.org.asc\n  # Streisand maintainer - Github @cpu\n  - 2D8330C2.daniel@binaryparadox.net.asc\n  # Streisand maintainer - Github @jlund\n  - CDF6583E.josh@joshlund.com.asc\n  # Streisand maintainer - Github @nopdotcom\n  - F67DA905.nop@nop.com.asc\n  # Streisand maintainer - Github @CorbanR\n  - A697A56F.corban@raunco.co.asc\n  # Streisand maintainer - Github @alimakki (Commented out for now because it\n  # breaks CI)\n  #- AF16234E.alimakki@gmail.com.asc\n"
  },
  {
    "path": "playbooks/roles/i18n-docs/defaults/main.yml",
    "content": "---\n# The jina2 template filename (without extensions)\ninput_template_name: \"instructions\"\n# The output file name (without extensions)\noutput_file_name: \"index\"\n"
  },
  {
    "path": "playbooks/roles/i18n-docs/tasks/main.yml",
    "content": "---\n- name: \"Generate the {{ title }} Markdown page\"\n  template:\n    src: \"{{ input_template_name }}{{ item.value.file_suffix }}.md.j2\"\n    dest: \"{{ i18n_location }}/{{ output_file_name }}{{ item.value.file_suffix }}.md\"\n  with_dict: \"{{ streisand_languages }}\"\n  loop_control:\n    label: \"{{ item.value.language_name }}\"\n\n- name: \"Convert the {{ title }} Markdown page into HTML\"\n  shell: >\n    markdown {{ output_file_name }}{{ item.value.file_suffix }}.md | \\\n    cat {{ streisand_header_template }} - {{ streisand_footer_template }} > {{ output_file_name }}{{ item.value.file_suffix }}.html\n  args:\n    chdir: \"{{ i18n_location }}\"\n  with_dict: \"{{ streisand_languages }}\"\n  loop_control:\n    label: \"{{ item.value.language_name }}\"\n"
  },
  {
    "path": "playbooks/roles/i18n-docs/templates/languages.md.j2",
    "content": "- - -\n{% for key, value in streisand_languages.items() %}\n  [{{ value.language_name }}]({{ output_file_name }}{{ value.file_suffix }}.html)&nbsp;\n{% endfor %}\n- - -\n"
  },
  {
    "path": "playbooks/roles/ip-forwarding/files/streisand-ipforward.sh",
    "content": "#!/bin/sh\n### BEGIN INIT INFO\n# Provides:          streisand-ipforward\n# Required-Start:    $network $remote_fs $local_fs\n# Required-Stop:     $network $remote_fs $local_fs\n# Default-Start:     2 3 4 5\n# Default-Stop:      0 1 6\n# Short-Description: Persist IP forwarding settings for Streisand\n### END INIT INFO\n\necho 1 > /proc/sys/net/ipv4/ip_forward\n\necho 0 | tee /proc/sys/net/ipv4/conf/*/*_redirects\n\nexit 0\n"
  },
  {
    "path": "playbooks/roles/ip-forwarding/tasks/main.yml",
    "content": "---\n- name: \"Enable IPv4 traffic forwarding\"\n  sysctl:\n    name: net.ipv4.ip_forward\n    value: 1\n  when: ansible_virtualization_type != 'lxc'\n\n- name: \"Add IPv4 traffic forwarding persistence service to init\"\n  copy:\n    src: streisand-ipforward.sh\n    dest: /etc/init.d/streisand-ipforward\n    mode: 0755\n\n- name: \"Enable the streisand-ipforward init service\"\n  service:\n    name: streisand-ipforward\n    enabled: yes\n"
  },
  {
    "path": "playbooks/roles/lets-encrypt/files/01-reload-nginx.sh",
    "content": "#!/bin/sh\n\n# Deploy hook that runs after a successful certbot renewal (not each attempt)\n\n# Reload nginx to gracefully shut down old worker processes and serve the new cert.\nsystemctl reload nginx\n"
  },
  {
    "path": "playbooks/roles/lets-encrypt/tasks/firewall.yml",
    "content": "- name: Ensure incoming HTTP traffic is allowed\n  ufw:\n    to_port: \"{{ le_port }}\"\n    proto: tcp\n    rule: allow\n"
  },
  {
    "path": "playbooks/roles/lets-encrypt/tasks/install.yml",
    "content": "- name: Enable the Universe repository\n  apt_repository:\n    repo: \"deb http://archive.ubuntu.com/ubuntu {{ ansible_distribution_release }} universe\"\n    state: present\n  register: le_add_apt_repository\n  until: not le_add_apt_repository.failed\n  retries: \"{{ apt_repository_retries }}\"\n  delay: \"{{ apt_repository_delay }}\"\n\n- name: Add the certbot PPA\n  apt_repository:\n    repo: \"ppa:certbot/certbot\"\n  register: le_add_certbot_ppa\n  until: not le_add_certbot_ppa.failed\n  retries: \"{{ apt_repository_retries }}\"\n  delay: \"{{ apt_repository_delay }}\"\n\n- name: Install certbot\n  apt:\n    package: certbot\n"
  },
  {
    "path": "playbooks/roles/lets-encrypt/tasks/main.yml",
    "content": "- import_tasks: install.yml\n- import_tasks: firewall.yml\n\n# Now we try to request a certificate. If it fails. We print a warning and\n# fall back to self-signed certificates.\n- block:\n    - set_fact:\n        le_email_flag: \"--email {{ streisand_admin_email }}\"\n      when: streisand_admin_email != \"\"\n    - set_fact:\n        le_email_flag: \"--register-unsafely-without-email\"\n      when: streisand_admin_email == \"\"\n\n    - name: Request initial certificate from Let's Encrypt\n      # Use certbot's \"standalone\" plugin to listen on port 80 for the initial\n      # challenge request/response. After this role runs, the nginx config\n      # handles port 80 requests, and whitelists the ACME challenge response dir.\n      command: |-\n        certbot certonly --standalone -d {{ streisand_domain }}\n        {{ le_email_flag }} --agree-tos --non-interactive\n        --rsa-key-size {{ le_rsa_key_size }}\n        --server {{ le_api_endpoint }}\n      args:\n        creates: \"{{ le_certificate }}\"\n\n    # We modify certbot's renewal config file to use the \"webroot\" plugin.\n    # By default, certbot uses the same options during the initial cert request\n    # when doing renewals. This would cause port conflicts since nginx will\n    # be listening on 80 (for 80->443 redirects, and allowing ACME challenges).\n    # We could technically let certbot restart/modify nginx temporarily for\n    # port 80 during renewal, but using \"webroot\" helps avoid downtime, since\n    # it just needs to write to the webroot directory to complete the challenge.\n    - name: Modify certbot renewal options to use webroot authenticator\n      ini_file:\n        path: \"/etc/letsencrypt/renewal/{{ streisand_domain }}.conf\"\n        section: renewalparams\n        option: authenticator\n        value: webroot\n\n    - name: Point webroot to the right directory where nginx will serve challenge responses.\n      ini_file:\n        path: \"/etc/letsencrypt/renewal/{{ streisand_domain }}.conf\"\n        section: renewalparams\n        option: webroot_path\n        value: \"{{ nginx_default_html_path }}\"\n\n    - name: Setup deploy hook to reload nginx after successful auto renewal\n      copy:\n        src: 01-reload-nginx.sh\n        dest: \"{{ le_base }}/renewal-hooks/deploy/01-reload-nginx.sh\"\n        owner: root\n        group: root\n        mode: 0750\n\n    - set_fact:\n        le_ok: True\n\n  rescue:\n    - set_fact:\n        le_ok: False\n\n    - name: Failed to get Let's Encrypt certificates. We are falling back to use self-signed ones. You could re-run the playbook to try again.\n      pause:\n        seconds: 10\n"
  },
  {
    "path": "playbooks/roles/lets-encrypt/vars/main.yml",
    "content": "---\nle_base: /etc/letsencrypt\nle_port: 80\n# RSA key size to request for SSL certificate\nle_rsa_key_size: 4096\nle_api_endpoint: \"https://acme-v02.api.letsencrypt.org/directory\"\nle_certificate: \"{{ le_base }}/live/{{ streisand_domain }}/fullchain.pem\"\nle_private_key: \"{{ le_base }}/live/{{ streisand_domain }}/privkey.pem\"\nle_chain: \"{{ le_base }}/live/{{ streisand_domain }}/chain.pem\"\n"
  },
  {
    "path": "playbooks/roles/nginx/files/nginx.conf",
    "content": "user  www-data;\nworker_processes  4;\n\nevents {\n    worker_connections  1024;\n}\n\nhttp {\n    include       /etc/nginx/mime.types;\n    default_type  application/octet-stream;\n\n    sendfile       on;\n    tcp_nopush     on;\n    tcp_nodelay    on;\n\n    server_names_hash_bucket_size  128;\n    types_hash_max_size   4096;\n    client_max_body_size  10M;\n    server_tokens off;\n    keepalive_timeout  65;\n\n    gzip on;\n    gzip_types text/css text/xml text/plain application/x-javascript application/atom+xml application/rss+xml;\n\n    autoindex on;\n    index index.html index.htm;\n\n    include /etc/nginx/sites-enabled/*;\n}\n"
  },
  {
    "path": "playbooks/roles/nginx/files/nginx_signing.key",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2.0.22 (GNU/Linux)\n\nmQENBE5OMmIBCAD+FPYKGriGGf7NqwKfWC83cBV01gabgVWQmZbMcFzeW+hMsgxH\nW6iimD0RsfZ9oEbfJCPG0CRSZ7ppq5pKamYs2+EJ8Q2ysOFHHwpGrA2C8zyNAs4I\nQxnZZIbETgcSwFtDun0XiqPwPZgyuXVm9PAbLZRbfBzm8wR/3SWygqZBBLdQk5TE\nfDR+Eny/M1RVR4xClECONF9UBB2ejFdI1LD45APbP2hsN/piFByU1t7yK2gpFyRt\n97WzGHn9MV5/TL7AmRPM4pcr3JacmtCnxXeCZ8nLqedoSuHFuhwyDnlAbu8I16O5\nXRrfzhrHRJFM1JnIiGmzZi6zBvH0ItfyX6ttABEBAAG0KW5naW54IHNpZ25pbmcg\na2V5IDxzaWduaW5nLWtleUBuZ2lueC5jb20+iQE+BBMBAgAoAhsDBgsJCAcDAgYV\nCAIJCgsEFgIDAQIeAQIXgAUCV2K1+AUJGB4fQQAKCRCr9b2Ce9m/YloaB/9XGrol\nkocm7l/tsVjaBQCteXKuwsm4XhCuAQ6YAwA1L1UheGOG/aa2xJvrXE8X32tgcTjr\nKoYoXWcdxaFjlXGTt6jV85qRguUzvMOxxSEM2Dn115etN9piPl0Zz+4rkx8+2vJG\nF+eMlruPXg/zd88NvyLq5gGHEsFRBMVufYmHtNfcp4okC1klWiRIRSdp4QY1wdrN\n1O+/oCTl8Bzy6hcHjLIq3aoumcLxMjtBoclc/5OTioLDwSDfVx7rWyfRhcBzVbwD\noe/PD08AoAA6fxXvWjSxy+dGhEaXoTHjkCbz/l6NxrK3JFyauDgU4K4MytsZ1HDi\nMgMW8hZXxszoICTTiQEcBBABAgAGBQJOTkelAAoJEKZP1bF62zmo79oH/1XDb29S\nYtWp+MTJTPFEwlWRiyRuDXy3wBd/BpwBRIWfWzMs1gnCjNjk0EVBVGa2grvy9Jtx\nJKMd6l/PWXVucSt+U/+GO8rBkw14SdhqxaS2l14v6gyMeUrSbY3XfToGfwHC4sa/\nThn8X4jFaQ2XN5dAIzJGU1s5JA0tjEzUwCnmrKmyMlXZaoQVrmORGjCuH0I0aAFk\nRS0UtnB9HPpxhGVbs24xXZQnZDNbUQeulFxS4uP3OLDBAeCHl+v4t/uotIad8v6J\nSO93vc1evIje6lguE81HHmJn9noxPItvOvSMb2yPsE8mH4cJHRTFNSEhPW6ghmlf\nWa9ZwiVX5igxcvaIRgQQEQIABgUCTk5b0gAKCRDs8OkLLBcgg1G+AKCnacLb/+W6\ncflirUIExgZdUJqoogCeNPVwXiHEIVqithAM1pdY/gcaQZmIRgQQEQIABgUCTk5f\nYQAKCRCpN2E5pSTFPnNWAJ9gUozyiS+9jf2rJvqmJSeWuCgVRwCcCUFhXRCpQO2Y\nVa3l3WuB+rgKjsQ=\n=EWWI\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/nginx/tasks/main.yml",
    "content": "---\n- name: Ensure that the Apache web server is not installed in order to avoid conflicts with Nginx\n  apt:\n    package: \"{{ apache_packages_to_remove }}\"\n    state: absent\n\n- name: \"Add the official Nginx APT key; hiding 25 lines of log...\"\n  apt_key:\n    id: 7BD9BF62\n    data: \"{{ item }}\"\n  with_file: nginx_signing.key\n  no_log: True\n\n- name: Add the official Nginx repository\n  apt_repository:\n    repo: \"deb https://nginx.org/packages/{{ ansible_distribution|lower }}/ {{ ansible_lsb.codename }} nginx\"\n  register: nginx_add_apt_repository\n  until: not nginx_add_apt_repository.failed\n  retries: \"{{ apt_repository_retries }}\"\n  delay: \"{{ apt_repository_delay }}\"\n\n\n- name: Install Nginx\n  apt:\n    package: nginx\n\n- name: Update Nginx configuration\n  copy:\n    src: nginx.conf\n    dest: /etc/nginx/nginx.conf\n    owner: root\n    group: root\n    mode: 0644\n\n- name: Set up Nginx vhost directories\n  file:\n    path: /etc/nginx/{{ item }}\n    state: directory\n  with_items:\n    - sites-available\n    - sites-enabled\n\n- name: Create the nginx systemd configuration directory\n  file:\n    path: \"{{ nginx_systemd_service_path }}\"\n    state: directory\n\n- name: Generate the nginx systemd service file\n  template:\n    src: nginx.service.j2\n    dest: \"{{ nginx_systemd_service_path }}/10-restart-failure.conf\"\n    mode: 0644\n\n# This directory is used to create ACME challenge responses when using letsencrypt.\n# N.B.: this should be different from streisand's gateway path to avoid any\n# chance of leaking gateway files (VPN credentials, configs, etc.) over port 80.\n# The nginx rules do redirect http to https, with the only exception\n# being requests to /.well-known/acme-challenge for letsencrypt.\n# So there is probably a low risk of that ever happening,\n# but still, keeping them separate can't hurt.\n- name: Ensure the default nginx HTML directory is empty\n  file:\n    state: absent\n    path: \"{{ nginx_default_html_path }}/\"\n  when: streisand_le_enabled\n\n- file:\n    state: directory\n    path: \"{{ nginx_default_html_path }}\"\n  when: streisand_le_enabled\n\n- name: Enable the nginx service\n  systemd:\n    daemon_reload: yes\n    name: nginx.service\n    enabled: yes\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/nginx/templates/nginx.service.j2",
    "content": "[Service]\nPrivateTmp=true\nRestartSec=5s\nRestart=on-failure\n"
  },
  {
    "path": "playbooks/roles/nginx/vars/main.yml",
    "content": "---\napache_packages_to_remove:\n  - apache2\n  - apache2.2-bin\n  - apache2.2-common\n  - apache2-mpm-event\n  - apache2-mpm-itk\n  - apache2-mpm-prefork\n  - apache2-mpm-worker\n\nnginx_systemd_service_path: /etc/systemd/system/nginx.service.d\nnginx_default_html_path: /usr/share/nginx/html\n"
  },
  {
    "path": "playbooks/roles/openconnect/defaults/main.yml",
    "content": "---\nocserv_ca_cn: \"Streisand\"\nocserv_ca_organization: \"Streisand Effect Automated Signing, Inc.\"\nocserv_port: \"4443\"\nocserv_server_organization: \"Streisand Effect Servers, Inc.\"\nocserv_key_ou: \"nogroup\"\n"
  },
  {
    "path": "playbooks/roles/openconnect/files/ocserv-pam",
    "content": "account required pam_listfile.so \\\n\tsense=allow item=user file=/etc/allowed_vpn_certs\n\nauth required pam_listfile.so \\\n\tsense=allow item=user file=/etc/allowed_vpn_certs\n\npassword required pam_deny.so\nsession required pam_deny.so\n\nother required pam_deny.so\n"
  },
  {
    "path": "playbooks/roles/openconnect/files/openconnect.conf",
    "content": "#\n# Filter out all OpenConnect entries to prevent IP address logging.\n#\n:msg, contains, \"ocserv\" then stop\n"
  },
  {
    "path": "playbooks/roles/openconnect/handlers/main.yml",
    "content": "---\n- name: Restart ocserv\n  service:\n    name: ocserv\n    state: restarted\n\n- name: Restart rsyslog for OpenConnect\n  service:\n    name: rsyslog\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/openconnect/meta/main.yml",
    "content": "---\ndependencies:\n  - { role: ufw }\n  - { role: ip-forwarding }\n"
  },
  {
    "path": "playbooks/roles/openconnect/tasks/docs.yml",
    "content": "---\n- name: Create the OpenConnect/AnyConnect Gateway directory\n  file:\n    path: \"{{ ocserv_gateway_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0750\n    state: directory\n\n- name: Copy the CA certificate file to the OpenConnect Gateway directory\n  command: cp {{ ocserv_ca_certificate_file }} {{ ocserv_gateway_location }}\n  args:\n    creates: \"{{ ocserv_gateway_location }}/ca-cert.pem\"\n\n- name: \"Copy the client PKCS #12 files to the OpenConnect Gateway directory\"\n  command: cp {{ ocserv_path }}/{{ ocserv_client_password.client_name.stdout }}/{{ ocserv_client_password.client_name.stdout }}.p12 {{ ocserv_gateway_location }}\n  args:\n    creates: \"{{ ocserv_gateway_location }}/{{ ocserv_client_password.client_name.stdout }}.p12\"\n  with_items: \"{{ vpn_client_pkcs12_password_list.results }}\"\n  loop_control:\n    loop_var: \"ocserv_client_password\"\n    label: \"{{ ocserv_client_password.client_name.item }}\"\n\n- name: \"Copy the client .mobileconfig files to the OpenConnect Gateway directory\"\n  command: cp {{ ocserv_path }}/{{ ocserv_client_password.client_name.stdout }}/{{ ocserv_client_password.client_name.stdout }}.mobileconfig {{ ocserv_gateway_location }}\n  args:\n    creates: \"{{ ocserv_gateway_location }}/{{ ocserv_client_password.client_name.stdout }}.mobileconfig\"\n  with_items: \"{{ vpn_client_pkcs12_password_list.results }}\"\n  loop_control:\n    loop_var: \"ocserv_client_password\"\n    label: \"{{ ocserv_client_password.client_name.item }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"OpenConnect/AnyConnect\"\n    input_template_name: \"instructions\"\n    i18n_location: \"{{ ocserv_gateway_location }}\"\n"
  },
  {
    "path": "playbooks/roles/openconnect/tasks/firewall.yml",
    "content": "---\n- name: Ensure UFW allows DNS requests from OpenConnect clients\n  ufw:\n    to_port: \"53\"\n    proto: \"udp\"\n    rule: \"allow\"\n    from_ip: \"192.168.1.0/24\"\n\n- name: Ensure UFW allows OpenConnect (ocserv)\n  ufw:\n    to_port: \"{{ ocserv_port }}\"\n    proto: \"any\"\n    rule: \"allow\"\n\n- name: Install the ocserv iptables service file\n  template:\n    src: ocserv-iptables.service.j2\n    dest: /etc/systemd/system/ocserv-iptables.service\n    mode: 0644\n\n- name: Enable the ocserv-iptables service\n  systemd:\n    daemon_reload: yes\n    name: ocserv-iptables.service\n    enabled: yes\n    state: started\n"
  },
  {
    "path": "playbooks/roles/openconnect/tasks/install.yml",
    "content": "---\n\n# It *shouldn't* be necessary to run this particular apt_repository\n# call in a \"retry\" loop; enabling Universe doesn't reach out to the\n# network, so this shouldn't have transient failures. For the sake of\n# consistency with the other apt_repository calls, it does retry.\n\n- name: Enable the Universe repository\n  apt_repository:\n    repo: \"deb http://archive.ubuntu.com/ubuntu {{ ansible_distribution_release }} universe\"\n    state: present\n  register: openconnect_add_apt_repository\n  until: not openconnect_add_apt_repository.failed\n  retries: \"{{ apt_repository_retries }}\"\n  delay: \"{{ apt_repository_delay }}\"\n\n- name: Install ocserv\n  apt:\n    package: ocserv\n\n- name: Create the OpenConnect rsyslog configuration directory\n  file:\n    path: /etc/rsyslog.d/openconnect.d/\n    owner: root\n    group: root\n    mode: 0644\n    state: directory\n\n- name: Copy the modified rsyslog configuration into place that prevents OpenConnect traffic from being logged\n  copy:\n    src: openconnect.conf\n    dest: /etc/rsyslog.d/openconnect.d/openconnect.conf\n    owner: root\n    group: root\n    mode: 0644\n  notify: Restart rsyslog for OpenConnect\n"
  },
  {
    "path": "playbooks/roles/openconnect/tasks/main.yml",
    "content": "---\n# Download, compile and install ocserv and its dependencies\n- import_tasks: install.yml\n\n- name: Create ocserv's PAM control\n  copy:\n    src: ocserv-pam\n    dest: /etc/pam.d/ocserv\n    owner: root\n    group: root\n    mode: 0644\n\n- name: Create the ocserv configuration directory\n  file:\n    path: \"{{ ocserv_path }}\"\n    owner: root\n    group: root\n    mode: 0750\n    state: directory\n\n- include_role:\n    name: certificates\n  vars:\n    ca_path:            \"{{ ocserv_path }}\"\n    tls_ca:             \"{{ ocserv_ca }}\"\n    tls_client_path:    \"{{ ocserv_path }}\"\n    tls_key_ou:         \"{{ ocserv_key_ou }}\"\n    vpn_name:           \"ocserv\"\n    generate_ca_server: yes\n    generate_client:    yes\n    generate_pkcs:      yes\n    tls_server_common_name_file: \"{{ ocserv_server_common_name_file }}\"\n    tls_sans:\n      - \"{{ streisand_ipv4_address }}\"\n\n- name: Base64 encode the client PKCS12 file(s)\n  command: \"openssl base64 -in {{ ocserv_path }}/{{ client_name.stdout }}/{{ client_name.stdout }}.p12\"\n  register: ocserv_clients_base64\n  changed_when: False\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: Generate a UUID for .mobileconfig client PKCS12 certificate\n  command: uuid -v4\n  register: ocserv_client_mobileconfig_uuid\n  changed_when: False\n\n- name: Generate a UUID for .mobileconfig vpn payload identifier\n  command: uuid -v4\n  register: ocserv_payload_mobileconfig_uuid\n  changed_when: False\n\n- name: Generate a UUID for .mobileconfig config payload identifier\n  command: uuid -v4\n  register: ocserv_config_mobileconfig_uuid\n  changed_when: False\n\n- name: Generate a UUID for .mobileconfig global identifier\n  command: uuid -v4\n  register: ocserv_global_mobileconfig_uuid\n  changed_when: False\n\n- name: Generate the iOS client mobileconfig file(s)\n  template:\n    src: client.mobileconfig.j2\n    dest: \"{{ ocserv_path }}/{{ client_content[0].stdout }}/{{ client_content[0].stdout }}.mobileconfig\"\n    owner: root\n    group: root\n    mode: 0600\n  with_together:\n    - \"{{ vpn_client_names.results }}\"\n    - \"{{ ocserv_clients_base64.results }}\"\n    - \"{{ vpn_client_pkcs12_password_list.results }}\"\n  loop_control:\n    loop_var: \"client_content\"\n    label: \"{{ client_content[0].item }}\"\n\n- name: Generate a random ocserv password\n  shell: \"{{ streisand_word_gen.psk | trim }} > {{ ocserv_password_file }}\"\n  args:\n    creates: \"{{ ocserv_password_file }}\"\n\n- name: Set permissions on the unhashed ocserv password file\n  file:\n    path: \"{{ ocserv_password_file }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Register the ocserv password\n  command: cat {{ ocserv_password_file }}\n  register: ocserv_password\n  changed_when: False\n\n- name: Create an ocpasswd credentials file\n  expect:\n    command: ocpasswd -c {{ ocserv_hashed_password_file }} streisand\n    responses:\n      \"Enter password\": \"{{ ocserv_password.stdout }}\"\n      \"Re-enter password\": \"{{ ocserv_password.stdout }}\"\n    creates: \"{{ ocserv_hashed_password_file }}\"\n\n- name: Generate the ocserv configuration file\n  template:\n    src: config.j2\n    dest: \"{{ ocserv_config_file }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Generate the ocserv systemd service file\n  template:\n    src: ocserv.service.j2\n    dest: /etc/systemd/system/ocserv.service\n    mode: 0644\n\n- name: Stop and disable ocserv.socket\n  systemd:\n    name: ocserv.socket\n    state: stopped\n    enabled: no\n\n- name: Enable the ocserv service\n  systemd:\n    daemon_reload: yes\n    name: ocserv.service\n    enabled: yes\n    state: restarted\n\n# Set up the openconnect firewall rules\n- import_tasks: firewall.yml\n\n# Generate Gateway documentation\n- import_tasks: docs.yml\n\n# Mirror the OpenConnect clients\n- import_tasks: mirror.yml\n"
  },
  {
    "path": "playbooks/roles/openconnect/tasks/mirror.yml",
    "content": "---\n- name: Include the OpenConnect mirror variables\n  include_vars: mirror.yml\n\n- name: Make the directory where the OpenConnect mirrored files will be stored\n  file:\n    path: \"{{ openconnect_mirror_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0755\n    state: directory\n\n- block:\n    - name: Mirror the OpenConnect clients\n      get_url:\n        url: \"{{ item.url }}\"\n        dest: \"{{ openconnect_mirror_location }}\"\n        checksum: \"{{ item.checksum }}\"\n        owner: www-data\n        group: www-data\n        mode: 0644\n      with_items: \"{{ openconnect_download_urls }}\"\n  rescue:\n    - name: \"{{ streisand_mirror_warning }}\"\n      pause:\n        seconds: \"{{ streisand_mirror_warning_seconds }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"OpenConnect mirror\"\n    i18n_location: \"{{ openconnect_mirror_location }}\"\n    input_template_name: \"mirror\"\n"
  },
  {
    "path": "playbooks/roles/openconnect/templates/client.mobileconfig.j2",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n   <dict>\n      <key>PayloadContent</key>\n      <array>\n         <dict>\n            <key>Password</key>\n            <string>{{ client_content[2].stdout }}</string>\n            <key>PayloadCertificateFileName</key>\n            <string>{{ client_content[0].stdout }}.p12</string>\n            <key>PayloadContent</key>\n            <data>{{ client_content[1].stdout }}</data>\n            <key>PayloadDescription</key>\n            <string>Client PKCS12 certificate</string>\n            <key>PayloadDisplayName</key>\n            <string>{{ client_content[0].stdout }}.p12</string>\n            <key>PayloadIdentifier</key>\n            <string>com.apple.security.pkcs12.{{ ocserv_client_mobileconfig_uuid.stdout | upper }}</string>\n            <key>PayloadType</key>\n            <string>com.apple.security.pkcs12</string>\n            <key>PayloadUUID</key>\n            <string>{{ ocserv_client_mobileconfig_uuid.stdout | upper }}</string>\n            <key>PayloadVersion</key>\n            <integer>1</integer>\n         </dict>\n         <dict>\n            <key>IPv4</key>\n            <dict>\n               <key>OverridePrimary</key>\n               <integer>0</integer>\n            </dict>\n            <key>PayloadDescription</key>\n            <string>Configures VPN settings</string>\n            <key>PayloadDisplayName</key>\n            <string>VPN</string>\n            <key>PayloadIdentifier</key>\n            <string>com.apple.vpn.managed.{{ ocserv_payload_mobileconfig_uuid.stdout | upper }}</string>\n            <key>PayloadType</key>\n            <string>com.apple.vpn.managed</string>\n            <key>PayloadUUID</key>\n            <string>{{ ocserv_payload_mobileconfig_uuid.stdout | upper }}</string>\n            <key>PayloadVersion</key>\n            <integer>1</integer>\n            <key>Proxies</key>\n            <dict>\n               <key>HTTPEnable</key>\n               <integer>0</integer>\n               <key>HTTPSEnable</key>\n               <integer>0</integer>\n            </dict>\n            <key>UserDefinedName</key>\n            <string>{{ client_content[0].stdout }}</string>\n            <key>VPN</key>\n            <dict>\n               <key>AuthName</key>\n               <string>{{ client_content[0].stdout }}</string>\n               <key>AuthenticationMethod</key>\n               <string>Certificate</string>\n               <key>PayloadCertificateUUID</key>\n               <string>{{ ocserv_client_mobileconfig_uuid.stdout | upper }}</string>\n               <key>RemoteAddress</key>\n               <string>{{ streisand_ipv4_address }}:{{ ocserv_port }}</string>\n            </dict>\n            <key>VPNSubType</key>\n            <string>com.cisco.anyconnect</string>\n            <key>VPNType</key>\n            <string>VPN</string>\n            <key>VendorConfig</key>\n\t\t\t<dict>\n\t\t\t\t<key>Group</key>\n\t\t\t\t<string>{{ ocserv_key_ou }}</string>\n\t\t\t</dict>\n         </dict>\n      </array>\n      <key>PayloadDisplayName</key>\n      <string>{{ client_content[0].stdout }}</string>\n      <key>PayloadIdentifier</key>\n      <string>streisand.{{ ocserv_config_mobileconfig_uuid.stdout | upper }}</string>\n      <key>PayloadRemovalDisallowed</key>\n      <false/>\n      <key>PayloadType</key>\n      <string>Configuration</string>\n      <key>PayloadUUID</key>\n      <string>{{ ocserv_global_mobileconfig_uuid.stdout | upper }}</string>\n      <key>PayloadVersion</key>\n      <integer>1</integer>\n   </dict>\n</plist>\n"
  },
  {
    "path": "playbooks/roles/openconnect/templates/config.j2",
    "content": "auth = \"plain[passwd={{ ocserv_hashed_password_file }}]\"\nenable-auth = \"certificate\"\ntcp-port = {{ ocserv_port }}\nudp-port = {{ ocserv_port }}\nrun-as-user = nobody\nrun-as-group = {{ ocserv_key_ou }}\nsocket-file = {{ ocserv_socket_file }}\nserver-cert = {{ ocserv_server_certificate_file }}\nserver-key = {{ ocserv_server_key_file }}\nca-cert = {{ ocserv_ca_certificate_file }}\nisolate-workers = true\n\n# The anyconnect client issues a bye and expects for the session to\n# be usable afterwards, however ocserv on a bye packet invalidates the\n# session. Use 'persistent-cookies = true' to force the server keep\n# these sessions even after disconnect.\npersistent-cookies = true\n\nkeepalive = 32400\ndpd = 240\nmobile-dpd = 1800\ntry-mtu-discovery = true\ncert-user-oid = 2.5.4.3\ncert-group-oid = 2.5.4.11\n\n# https://gnutls.org/manual/gnutls.html#Priority-Strings\n# SECURE192: All known to be secure ciphersuites that offer a security level 192-bit or more.\n# %SERVER_PRECEDENCE: The ciphersuite will be selected according to server priorities and not the client’s.\n# %LATEST_RECORD_VERSION: Use the latest TLS version record version in client hello.\n# -VERS-ALL: Disable all TLS/DTLS versions\n# +VERS-TLS1.2: Allow TLSv1.2\n# +VERS-DTLS1.2: Allow DLSv1.2\ntls-priorities = \"SECURE192:%SERVER_PRECEDENCE:%LATEST_RECORD_VERSION:-VERS-ALL:+VERS-TLS1.2:+VERS-DTLS1.2\"\n\nauth-timeout = 40\nmin-reauth-time = 300\nmax-ban-score = 50\nban-reset-time = 300\ncookie-timeout = 300\ncookie-rekey-time = 14400\ndeny-roaming = false\nrekey-time = 3600\nrekey-method = ssl\nuse-occtl = true\npid-file = {{ ocserv_pid_file }}\ndevice = vpns\ndefault-domain = example.com\nipv4-network = 192.168.1.0\nipv4-netmask = 255.255.255.0\nping-leases = false\ncisco-client-compat = true\nmax-clients = {{ vpn_clients + 1 }}\n\n# Limit the number of identical clients (i.e., users connecting\n# multiple times). Unset or set to zero for unlimited. \nmax-same-clients = 1\n\n# Whether to tunnel all DNS queries via the VPN. This is the default\n# when a default route is set.\ntunnel-all-dns = true\n\n{% for item in upstream_dns_servers %}\ndns = {{ item }}\n{% endfor %}\n\nacct = pam\n"
  },
  {
    "path": "playbooks/roles/openconnect/templates/instructions-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nOpenConnect / Cisco AnyConnect\n------------------------------\n\nOpenConnect est un serveur VPN extrêmement performant et léger qui offre une compatibilité totale avec les clients officiels Cisco AnyConnect. Le [protocole] (http://www.infradead.org/ocserv/technical.html) repose sur des normes telles que HTTP, TLS et DTLS, et c'est l'une des technologies VPN les plus populaires et largement utilisées parmi les grands multi-nationales. En raison de son utilisation dans les grandes multinationales, cela signifie souvent qu'au niveau du protocole, il est peu probable d'être ciblé pour la censure.\n\n---\n* Plateformes\n  * [Certificats](#clientcerts)\n  * [Windows](#windows)\n  * [macOS](#macos)\n    * [OpenConnect GUI](#macos-openconnect-gui)\n    * [OpenConnect CLI](#macos-openconnect-cli)\n  * [Linux](#linux)\n  * [Android](#android)\n  * [iOS](#ios)\n\n<a name=\"clientcerts\"></a>\n### Certificats du serveur et des clients (macOS, Android) ###\n\nLes certificats clients sont un mécanisme par lequel les clients peuvent s'authentifier de manière sécurisée avec un serveur.\n\n1. Votre serveur OpenConnect émet son propre __certificat serveur__. Ceci est utilisé par le logiciel du client de votre appareil (tel que AnyConnect pour iOS) afin de  s'identifier de manière sécurisée avec le serveur VPN. Téléchargez le certificat de ce serveur.\n   * [ca.crt](/openconnect/ca.crt)\n1. Chaque appareil que vous souhaitez configurer nécessite un __certificat client__ en plus du certificat serveur ci-dessus. Un certificat client est utilisé pour identifier et authentifier de manière sécurisée votre appareil sur le serveur VPN. Deux appareils ne peuvent pas utiliser le même certificat de client et être connectés simultanément (un certificat de client pour chaque appareil). Chaque certificat client est protégé par une mot de passe, qui sera nécessaire pour le déverrouiller une fois que vous l'importez dans votre appareil.\n{% for client in vpn_client_pkcs12_password_list.results %}\n   * [{{ client.client_name.stdout }}.p12](/openconnect/{{ client.client_name.stdout }}.p12), mot de passe: `{{ client.stdout }}` \n{% endfor %}\n\n<a name=\"windows\"></a>\n### Windows ###\n\n1. Téléchargez [l'installateur OpenConnect GUI](/mirror/index-fr.html#openconnect).\n1. Lancez le programme d'installation OpenConnect GUI.\n1. Compléter l'assistant de configuration TAP-Windows.\n   * Choisissez les options par défaut et permettez au pilote TAP du projet OpenVPN d'être installé.\n1. Lancez l'application OpenConnect.\n1. Cliquez sur l'icône *Edit* (Engrenage).\n1. Saisissez `{{ streisand_server_name }}` pour le *Name* (Nom).\n1. Saisissez `{{ streisand_ipv4_address }}:{{ ocserv_port }}` pour la *Gateway* (passerelle).\n1. Saisissez `streisand` pour le *Username* (nom d'utilisateur) et cliquez *Save* (Enregisterer).\n1. Cliquez *Connect* (Connexion).\n1. Une invite apparaîtra pendant la connexion initiale en vous demandant de faire confiance au certificat du serveur. Cliquez *The information is accurate* (l'information est précise) et le serveur sera automatiquement vérifié pour toutes les connexions suivantes.\n1. Saisissez `{{ ocserv_password.stdout }}` pour le *Password* (mot de passe) et cliquez *OK*.\n1. Cliquez *Non* lorsque l'invite de Windows apparaît en vous demandant *Voulez-vous permettre à votre PC d'être découvrable...*.\n1. La version bêta actuelle de l'interface graphique OpenConnect [ne supporte pas la modification automatique des paramètres DNS](https://github.com/openconnect/openconnect-gui/issues/48). Afin d'éviter les fuites de DNS, les étapes suivantes doivent être effectuées:\n   1. Faites un clic droit sur le bouton Démarrer de Windows.\n   1. Cliquez *Connexions réseau*.\n   1. Cliquez-driot sur le appareil que vous utilisez pour vous connecter (Ethernet ou Wifi) et cliquez sur *Propriétés*.\n   1. Double-cliquez *Protocol Internet Version 4 (TCP/IPv4)*.\n   1. Sélectionnez *Utiliser les adresses de serveur DNS suivante* et saisissez:\n{% for item in upstream_dns_servers %}\n      * `{{ item }}`\n{% endfor %}\n   1. Cliquez *OK*.\n   1. Cliquez *OK* pour fermer les propriétés de connexion.\n1. Vous devriez être prêt à partir! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n<a name=\"macos\"></a>\n### macOS ###\n\n\n<a name=\"macos-openconnect-gui\"></a>\n#### OpenConnect GUI\n\n1. Téléchargez [l'installateur OpenConnect GUI](/mirror/index-fr.html#openconnect).\n1. Lancez le programme d'installation OpenConnect GUI.\n1. Lancez l'application OpenConnect.\n1. Cliquez sur l'icône *Edit* (Engrenage).\n1. Saisissez `{{ streisand_server_name }}` pour le *Name* (Nom).\n1. Saisissez `{{ streisand_ipv4_address }}:{{ ocserv_port }}` pour la *Gateway* (passerelle).\n1. Saisissez `streisand` pour le *Username* (nom d'utilisateur) et cliquez *Save* (Enregisterer).\n1. Cliquez *Connect* (Connexion).\n1. Une invite apparaîtra pendant la connexion initiale en vous demandant de faire confiance au certificat du serveur. Cliquez *The information is accurate* (l'information est précise) et le serveur sera automatiquement vérifié pour toutes les connexions suivantes.\n1. Saisissez `{{ ocserv_password.stdout }}` pour le *Password* (mot de passe) et cliquez *OK*.\n1. Vous devriez être prêt à partir! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n<a name=\"macos-openconnect-cli\"></a>\n#### OpenConnect CLI\n1. Installer [Homebrew](https://brew.sh/), si vous ne l'avez pas.\n1. Installer OpenConnect en utilisant Homebrew:\n\n   `brew install openconnect`\n\n   * Si l'installation de Homebrew n'est pas une option, vous pouvez également télécharger et compiler le [code source OpenConnect](/mirror/index-fr.html#openconnect).\n1. Téléchargez le fichier [ca.crt](/openconnect/ca.crt) et un [fichier de certificat client](#clientcerts) dans la liste ci-dessus.\n1. Placez les fichiers téléchargés dans un dossier distinct (par exemple `{{ streisand_server_name }}-openconnect`), ouvrez votre terminal, et `cd` dans la directoire.\n1. Lancez OpenConnect:\n\n   `sudo openconnect --cafile ca.crt --certificate votre-certificat-client.p12 --key-password 'mot-de-passe-du-certificat' --pfs {{ streisand_ipv4_address }}:{{ ocserv_port }}`\n1. Vous devriez être prêt à partir! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n<a name=\"linux\"></a>\n### Linux ###\n1. Installer le plugin OpenConnect pour NetworkManager.\n\n   `sudo apt-get install network-manager-openconnect-gnome`\n1. Téléchargez le certificat serveur:\n   * [ca.crt](/openconnect/ca.crt)\n1. Ouvrez votre *Paramètres du système*.\n1. Cliquez sur l'icône *Réseau*.\n1. Cliquez le bouton *+* dans le coin inférieur gauche de la fenêtre.\n1. Sélectionnez *VPN* à partir de la liste déroulante et cliquez *Créer*.\n1. Sélectionnez *VPN compatible Cisco AnyConnect (openconnect)* et cliquez *Créer*.\n1. Saisissez `{{ streisand_server_name }}` pour le *Nom du connexion*.\n1. Saisissez `{{ streisand_ipv4_address }}:{{ ocserv_port }}` pour la *Gateway* (passerelle).\n1. Sélectionnez le fichier `ca.crt` Que vous venez de télécharger pour *Certificat CA*.\n1. Cliquez *Enregisterer*.\n1. Sélectionnez le VPN dans le menu à gauche, et faites glisser l'interrupteur vers la position *ON*. Vous pouvez également activer/désactiver le VPN en cliquant sur l'icône WiFi/Réseau dans la barre de menu, défiler vers *Connexions VPN* et en cliquant sur son nom.\n1. Saisissez `streisand` pour le champ *Nom d'utilisateur* puis cliquez *Connexion*.\n1. Saisissez `{{ ocserv_password.stdout }}` pour le champ *Mot de passe*, cocher *Enregistrer mots de passe*, et cliquez *Connexion*.\n1. Vous devriez être prêt à partir! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n<a name=\"android\"></a>\n### Android ###\n\n1. Téléchargez [Cisco AnyConnect](https://play.google.com/store/apps/details?id=com.cisco.anyconnect.vpn.android.avf&hl=fr) depuis Google Play.\n1. Lancez l'application.\n1. Tapez *OK* pour accepter \"Supplemental End User License Agreement for AnyConnect&reg; Secure Mobility Client vx.x and other VPN-related Software\".\n1. Tapez sur l'icône du menu et sélectionnez *Paramètres*.\n1. Décochez l'option *Bloquer les serveurs non fiables*.\n   * Le certificat du serveur sera importé pendant la connexion initiale et vérifié automatiquement pour toutes les connexions ultérieures.\n1. Tapez sur le bouton arrière.\n1. Tapez *Connexion* en suite tapez *Ajouter une nouvelle connexion VPN...*.\n1. Tapez *Description* et saisissez `{{ streisand_server_name }}`.\n1. Tapez *Adresse du server* et saisissez `{{ streisand_ipv4_address }}:{{ ocserv_port }}`.\n1. Tapez *Préférences avancées*.\n1. Tapez *Certificat*.\n   * Chaque profil peut être téléchargé sur l'appareil lui-même à l'aide des [liens ci-dessus](#clientcerts), ou copié depuis votre ordinateur via USB.\n1. Tapez *Import*, tapez *Système de fichiers*, et sélectionnez un [fichier certificat client](#clientcerts)\n1. Vérifiez le dossier `Téléchargements` si vous avez téléchargé le fichier directement sur l'appareil. C'est là que Chrome place ses fichiers, par exemple.\n1. Saisissez votre mot de passe de certificat client lorsque l'invite *Mot de passe* s'affiche, en suite tapez *Se Connecter*.\n1. Vous verrez une coche à côté du certificat nouvellement importé. Tapez sur le bouton de retour.\n1. Tapez *Terminer* deux fois pour sauvegarder la connexion.\n1. Tapez sur le bouton retour pour revenir à l'écran principal. Vous devriez voir `{{ streisand_server_name }}` dans la section *Connexion*.\n1. Faites glisser l'interrupteur *VPN* vers la position Ouvert.\n1. Tapez *Détails* avertissement de securite est affiche when the Security Warning is displayed.\n1. Tapez *Import and Continue* sommaire du certificat est achhife when the Certificate Summary is displayed.\n1. Tapez *Se Connecter* dans l'écran de selection de groupe. Le défaut correct a déjà été choisi.\n1. Si c'est la première fois que vous utilisez AnyConnect, vous devrez accepter la boîte de dialogue de la demande de connexion affichée par Android.\n1. Vous devriez être prêt à partir! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n#### Avez-vous été demandé pour le nom d'utilisateur? ####\n\nCertains utilisateurs [ont signalé](https://github.com/StreisandEffect/streisand/issues/847) que leurs clients Android AnyConnect demandent un nom d'utilisateur et un mot de passe. C'est un bug connu que nous n'avons pas résolu. Voir la liste de [questions ouvertes Streisand AnyConnect](https://github.com/StreisandEffect/streisand/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20anyconnect). Si vous êtes affecté, vous pouvez nous aider à comprendre le bug en signalant vos informations en utilisant le modèle du bouton *New issue* de la liste des problèmes. Les correctifs sont également acceptés.\n\nSi vous êtes affecté, vous pouvez utiliser cette solution alternatif:\n\n1. Lorsque vous êtes invité à entrer un utilisateur, entrez `streisand`\n1. Lorsque vous êtes invité à entrer un mot de passe, utilisez `{{ ocserv_password.stdout }}`\n\n<a name=\"ios\"></a>\n### iOS ###\n\n#### Note: Lorsque vous utilisez AnyConnect pour la première fois, vous pouvez être invité à entrer un mot de passe avant d'être connecté. Saisissez `streisand` comme nom de l'utilisateur et `{{ocserv_password.stdout}}` pour le mot de pass et continuez. Les tentatives de connexion suivantes ne vous demanderont plus.\n\n#### Note: Un seul profil AnyConnect peut être configuré à tout moment. Pour supprimer un profil existant, naviguez vers *Règlages* -> *Général* -> *Profil*, tapez sur le profil que vous souhaitez supprimer, puis tapez sur *Supprimer le profil*.\n\n1. Transférer un fichier .mobileconfig à chaque appareil que vous souhaitez configurer:\n{% for client in vpn_client_pkcs12_password_list.results %}\n   * [{{ client.client_name.stdout }}.mobileconfig](/openconnect/{{ client.client_name.stdout }}.mobileconfig)\n{% endfor %}\n   * Le profil peut être envoyé par courrier électronique sur votre appareil (simplement appuyez sur la pièce jointe), transféré via l'utilitaire [Apple Configurator](https://itunes.apple.com/us/app/apple-configurator/id434433123?mt=12), ou téléchargé directement en regardant ces instructions sur l'appareil lui-même.\n1. Suivez les instructions à l'écran.\n1. Vous serez invité à entrer le mot de passe ou le code NIP de votre appareil.\n\n1. Téléchargez l'application [Cisco AnyConnect](https://itunes.apple.com/fr/app/cisco-anyconnect/id1135064690) depuis l'App Store.\n1. Lancez l'application.\n1. Tapez *OK* pour activer le logiciel lorsque la boîte de dialogue apparaît.\n1. Tapez *Paramètres*.\n1. Éteignez l'interrupteur *Bloquer les serveurs non fiable*.\n   * Le certificat du serveur sera importé pendant la connexion initiale et vérifié automatiquement pour toutes les connexions ultérieures.\n1. Faites glisser l'interrupteur *VPN* vers la position ON.\n1. Tapez *Détails* lorsque l'avertissement de sécurité s'affiche.\n1. Tapez *Importer* dans le coin supérieur droit.\n1. Tapez *Se Connecter* dans l'écran de selection de groupe. Le défaut correct a déjà été choisi.\n1. Vous devriez être prêt à partir! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n"
  },
  {
    "path": "playbooks/roles/openconnect/templates/instructions.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nOpenConnect / Cisco AnyConnect\n------------------------------\n\nOpenConnect is an extremely high-performance and lightweight VPN server that also features full compatibility with the official Cisco AnyConnect clients. The [protocol](http://www.infradead.org/ocserv/technical.html) is built on top of standards like HTTP, TLS, and DTLS, and it's one of the most popular and widely used VPN technologies. Due to its use among large multi-national corporations, it often means that at the protocol level, it is seldom targetted for censorship.\n\n---\n* Platforms\n  * [Certificates](#clientcerts)\n  * [Windows](#windows)\n  * [macOS](#macos)\n    * [OpenConnect GUI](#macos-openconnect-gui)\n    * [OpenConnect CLI](#macos-openconnect-cli)\n  * [Linux](#linux)\n  * [Android](#android)\n  * [iOS](#ios)\n\n<a name=\"clientcerts\"></a>\n### Server and client Certificates (macOS, Android) ###\n\nClient certificates are a mechanism by which clients can authenticate themselves securely with the server.\n\n1. Your OpenConnect server issues its own __server certificate__. This is used by your device's client software (such as AnyConnect for iOS) to securely identify the VPN server. Download this server's certificate.\n   * [ca.crt](/openconnect/ca.crt)\n1. Each device you wish to configure needs a __client certificate__ in addition to the server certificate above. A client certificate is used to securely identify and authenticate your device to the VPN server. Two devices can't use the same client certificate and be logged in at the same time (one client certificate per device). Each client certificate is protected by a password, which will be needed to unlock it once you import it into your device.\n{% for client in vpn_client_pkcs12_password_list.results %}\n   * [{{ client.client_name.stdout }}.p12](/openconnect/{{ client.client_name.stdout }}.p12), password: `{{ client.stdout }}` \n{% endfor %}\n\n<a name=\"windows\"></a>\n### Windows ###\n\n1. Download the [OpenConnect GUI installer](/mirror/#openconnect).\n1. Run the OpenConnect GUI installer.\n1. Complete the TAP-Windows Setup Wizard.\n   * Choose the default options, and allow the TAP driver from the OpenVPN project to be installed.\n1. Launch the OpenConnect application.\n1. Click the *Edit* icon (gear) and select 'New profile advanced'.\n1. Enter `{{ streisand_server_name }}` for the *Name*.\n1. Enter `{{ streisand_ipv4_address }}:{{ ocserv_port }}` for the *Gateway*.\n1. Enter `streisand` for the *Username* and click *Save*.\n1. Click *Connect*.\n1. A prompt will appear during the initial connection asking you to trust the server's certificate. Click *The information is accurate* and the server will be automatically verified for all future connections.\n1. Enter `{{ ocserv_password.stdout }}` for the *Password* and click *OK*.\n1. Click *No* when the Windows prompt appears asking *Do you want to allow your PC to be discoverable...*.\n1. The current beta version of the OpenConnect GUI [does not support automatically changing the DNS settings](https://github.com/openconnect/openconnect-gui/issues/48). In order to avoid DNS leaks, the following steps must be performed:\n   1. Right-click on the Windows Start Button.\n   1. Click *Network Connections*.\n   1. Right-click on the device that you are using to connect (Ethernet or Wi-Fi) and click *Properties*.\n   1. Double-click *Internet Protocol Version 4 (TCP/IPv4)*.\n   1. Select *Use the following DNS server addresses* and enter:\n{% for item in upstream_dns_servers %}\n      * `{{ item }}`\n{% endfor %}\n   1. Click *OK*.\n   1. Click *OK* to close the connection properties.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"macos\"></a>\n### macOS ###\n\n<a name=\"macos-openconnect-gui\"></a>\n#### OpenConnect GUI\n\n1. Download the [OpenConnect GUI installer](/mirror/#openconnect).\n1. Run the OpenConnect GUI installer.\n1. Launch the OpenConnect application.\n1. Click the *Edit* icon (gear) and select 'New profile advanced'.\n1. Enter `{{ streisand_server_name }}` for the *Name*.\n1. Enter `{{ streisand_ipv4_address }}:{{ ocserv_port }}` for the *Gateway*.\n1. Enter `streisand` for the *Username* and click *Save*.\n1. Click *Connect*.\n1. A prompt will appear during the initial connection asking you to trust the server's certificate. Click *The information is accurate* and the server will be automatically verified for all future connections.\n1. Enter `{{ ocserv_password.stdout }}` for the *Password* and click *OK*.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"macos-openconnect-cli\"></a>\n#### OpenConnect CLI\n\n1. Install [Homebrew](https://brew.sh/), if you haven't already.\n1. Install OpenConnect using Homebrew:\n\n   `brew install openconnect`\n\n   * If installing Homebrew is not an option, you can also download and compile the [OpenConnect source code](/mirror/#openconnect).\n1. Download the [server certificate](/openconnect/ca.crt) file, and a [client certificate file](#clientcerts) from the list above.\n1. Place the downloaded server certificate and a selected client certificate into a separate folder (e.g. `{{ streisand_server_name }}-openconnect`), open your Terminal, and `cd` to that directory.\n1. Run OpenConnect:\n\n  `sudo openconnect --cafile ca.crt --certificate your-client-certificate.p12 --key-password 'your-client-certificate-password' --pfs {{ streisand_ipv4_address }}:{{ ocserv_port }}`\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n\n<a name=\"linux\"></a>\n### Linux ###\n\n1. Install the OpenConnect plugin for NetworkManager.\n\n   `sudo apt-get install network-manager-openconnect-gnome`\n1. Download the server certificate file:\n   * [ca.crt](/openconnect/ca.crt)\n1. Open your *System Settings*.\n1. Click the *Network* icon.\n1. Click the *+* button in the lower-left of the window.\n1. Select *VPN* from the Interface drop-down and click *Create*.\n1. Select *Cisco AnyConnect Compatible VPN (openconnect)* and click *Create*.\n1. Enter `{{ streisand_server_name }}` for the *Connection name*.\n1. Enter `{{ streisand_ipv4_address }}:{{ ocserv_port }}` for the *Gateway*.\n1. Select the `ca.crt` file that you just downloaded for the *CA Certificate*.\n1. Click *Save*.\n1. Select the VPN in the left-hand menu, and flip the switch to *ON*. You can also enable/disable the VPN by clicking on the WiFi/Network icon in the menu bar, scrolling to *VPN Connections*, and clicking on its name.\n1. Enter `streisand` for the *Username* and click *Login*.\n1. Enter `{{ ocserv_password.stdout }}` for the *Password*, check *Save passwords*, and click *Login*.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"android\"></a>\n### Android ###\n\n1. Download [Cisco AnyConnect](https://play.google.com/store/apps/details?id=com.cisco.anyconnect.vpn.android.avf) from Google Play.\n1. Launch the application.\n1. Tap *OK* to accept the \"Supplemental End User License Agreement for AnyConnect&reg; Secure Mobility Client vx.x and other VPN-related Software\".\n1. Tap the menu icon and select *Settings*.\n1. Uncheck the *Block Untrusted Servers* option.\n   * The server certificate will be imported during the initial login and automatically verified for all future connections.\n1. Tap the back button.\n1. Tap *Connection* and then tap *Add New VPN Connection...*.\n1. Tap *Description* and enter `{{ streisand_server_name }}`.\n1. Tap *Server Address* and enter `{{ streisand_ipv4_address }}:{{ ocserv_port }}`.\n1. Tap *Advanced Preferences*.\n1. Tap *Certificate*.\n  * Each profile can be downloaded on the device itself using the [links above](#clientcerts), or copied from your computer via USB.\n1. Check the `Download` folder if you downloaded the file directly to the device. This is where Chrome places its files, for example.\n1. Tap *Import*, tap *File System*, and select a [client certificate file](#clientcerts) from the list above that you transferred.\n1. Enter your client certificate password when the *Password* prompt is displayed, and tap *Connect*.\n1. You'll see a checkmark next to the newly imported certificate. Tap the back button.\n1. Tap *Done* twice to save the connection.\n1. Tap the back button to return to the main screen. You should see `{{ streisand_server_name }}` in the *Connection* section.\n1. Slide the *AnyConnect VPN* switch On.\n1. Tap *Details* when the Security Warning is displayed.\n1. Tap *Import and Continue* when the Certificate Summary is displayed.\n1. Tap *Connect* on the group selection screen. The correct default has already been chosen.\n1. If this is your first time using AnyConnect, you will need to accept the Connection Request dialog that Android displays.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n#### Prompted for username? ####\n\nSome users [have reported](https://github.com/StreisandEffect/streisand/issues/847) that their Android AnyConnect clients prompt for a username and password. This is a known bug we don't understand. See the list of [Streisand AnyConnect open issues](https://github.com/StreisandEffect/streisand/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20anyconnect). If you're affected, you could help us understand the bug by reporting your details using the issue list's *New issue* button's template. Fixes are gratefully accepted too.\n\nIf you're affected, you can use this workaround:\n\n1. When prompted for a user, enter `streisand`\n1. When prompted for a password, use `{{ ocserv_password.stdout }}`\n\n<a name=\"ios\"></a>\n### iOS ###\n\n#### Note: When using AnyConnect for the first time, you may be prompted for a password prior to being connected. Enter `streisand` for the username, `{{ ocserv_password.stdout }}` for the password and continue. Subsequent connections will not prompt you again.\n\n#### Note: Only one AnyConnect profile can be configured at any give time. To remove an existing profile, go to *Settings* -> *General* -> *Profile*, tap on the profile you wish to remove, then tap on *Remove Profile*.\n\n1. Transfer a .mobileconfig file for each device you wish to configure:\n{% for client in vpn_client_pkcs12_password_list.results %}\n   * [{{ client.client_name.stdout }}.mobileconfig](/openconnect/{{ client.client_name.stdout }}.mobileconfig)\n{% endfor %}\n  * The profile can be emailed to your device (simply tap the attachment), transferred via the [Apple Configurator](https://itunes.apple.com/us/app/apple-configurator/id434433123?mt=12) utility, or downloaded directly by viewing these instructions on the device itself.\n1. Follow the on-screen instructions.\n1. You will be prompted to enter your device password or pin.\n\n1. Download [Cisco AnyConnect](https://itunes.apple.com/us/app/cisco-anyconnect/id1135064690) from the App Store.\n1. Launch the application.\n1. Tap *OK* to enable the software when the dialog box appears.\n1. Tap *Settings*.\n1. Turn off the *Block Untrusted Servers* switch.\n   * The server certificate will be imported during the initial login and automatically verified for all future connections.\n1. Tap *Home*.\n1. Slide the *AnyConnect VPN* switch on.\n1. Tap *Details* when the Security Warning is displayed.\n1. Tap *Import* in the top-right corner.\n1. Tap *Connect* on the group selection screen. The correct default has already been chosen.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n"
  },
  {
    "path": "playbooks/roles/openconnect/templates/mirror-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"openconnect\"></a>\n### OpenConnect ###\n\n**Source**\n\n* [{{ openconnect_source_filename }}]({{ openconnect_source_href }})\n  * Somme de contrôle: *{{ openconnect_source_checksum }}*\n\n**Windows**\n\n* [{{ openconnect_windows_filename }}]({{ openconnect_windows_href }})\n  * Somme de contrôle: *{{ openconnect_windows_checksum }}*\n\n**macOS**\n\n* [{{ openconnect_macos_filename }}]({{ openconnect_macos_href }})\n  * Somme de contrôle: *{{ openconnect_macos_checksum }}*\n"
  },
  {
    "path": "playbooks/roles/openconnect/templates/mirror.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"openconnect\"></a>\n### OpenConnect ###\n\n**Source**\n\n* [{{ openconnect_source_filename }}]({{ openconnect_source_href }})\n  * Checksum: *{{ openconnect_source_checksum }}*\n\n**Windows**\n\n* [{{ openconnect_windows_filename }}]({{ openconnect_windows_href }})\n  * Checksum: *{{ openconnect_windows_checksum }}*\n\n**macOS**\n\n* [{{ openconnect_macos_filename }}]({{ openconnect_macos_href }})\n  * Checksum: *{{ openconnect_macos_checksum }}*\n"
  },
  {
    "path": "playbooks/roles/openconnect/templates/ocserv-iptables.service.j2",
    "content": "[Unit]\nDescription=Set the firewall rules required for ocserv\nAfter=network.target\nBefore=ocserv.service\n\n[Service]\nType=oneshot\nRemainAfterExit=true\nExecStart=/sbin/{{ ocserv_firewall_rule }}\n\n[Install]\nWantedBy=multi-user.target"
  },
  {
    "path": "playbooks/roles/openconnect/templates/ocserv.service.j2",
    "content": "[Unit]\nDescription=OpenConnect SSL VPN server\nDocumentation=man:ocserv(8)\nAfter=network-online.target\nAfter=dbus.service\n\n[Service]\nPrivateTmp=true\nPIDFile={{ ocserv_pid_file }}\nExecStart=/usr/sbin/ocserv --foreground --pid-file {{ ocserv_pid_file }} --config {{ ocserv_config_file }}\nExecReload=/bin/kill -HUP $MAINPID\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "playbooks/roles/openconnect/vars/main.yml",
    "content": "---\nocserv_path: \"/etc/ocserv\"\nocserv_ca: \"{{ ocserv_path }}/ca\"\nocserv_config_file: \"{{ ocserv_path }}/ocserv.conf\"\nocserv_firewall_rule: \"iptables --wait {{ streisand_iptables_wait }} -t nat -A POSTROUTING -j MASQUERADE\"\n\nocserv_days_valid: \"1825\"\nocserv_pid_file:    \"/var/run/ocserv.pid\"\nocserv_socket_file: \"/var/run/ocserv-socket\"\nocserv_ca_certificate_file: \"{{ ocserv_path }}/ca.crt\"\nocserv_ca_key_file:         \"{{ ocserv_path }}/ca.key\"\n\nocserv_server_certificate_file: \"{{ ocserv_path }}/server.crt\"\nocserv_server_key_file:         \"{{ ocserv_path }}/server.key\"\n\nocserv_hashed_password_file:    \"{{ ocserv_path }}/ocpasswd\"\nocserv_password_file:           \"{{ ocserv_path }}/ocserv-password\"\nocserv_server_common_name_file: \"{{ ocserv_path }}/ocserv_server_common_name\"\n\nocserv_client_name: \"streisand-openconnect-{{ streisand_ipv4_address }}\"\n\nocserv_gateway_location: \"{{ streisand_gateway_location }}/openconnect\"\n"
  },
  {
    "path": "playbooks/roles/openconnect/vars/mirror.yml",
    "content": "---\n# OpenConnect Download variables\n# ------------------------------\nopenconnect_mirror_location: \"{{ streisand_mirror_location }}/openconnect\"\nopenconnect_mirror_href_base: \"/mirror/openconnect\"\n\n# Source\nopenconnect_source_version: \"7.08\"\nopenconnect_source_filename: \"openconnect-{{ openconnect_source_version }}.tar.gz\"\nopenconnect_source_href: \"{{ openconnect_mirror_href_base }}/{{ openconnect_source_filename }}\"\n# This CDN mirrors the OpenConnect source code, and helps mitigate\n# connection errors that were occurring when using the project's\n# official download location.\nopenconnect_source_url: \"https://d25kfp60e9u1dw.cloudfront.net/{{ openconnect_source_filename }}\"\nopenconnect_source_checksum: \"sha256:1c44ec1f37a6a025d1ca726b9555649417f1d31a46f747922b84099ace628a03\"\n\n# Windows\nopenconnect_windows_version: \"v1.5.3\"\nopenconnect_windows_filename: \"openconnect-gui-1.5.3-win32.exe\"\nopenconnect_windows_href: \"{{ openconnect_mirror_href_base }}/{{ openconnect_windows_filename }}\"\nopenconnect_windows_url: \"https://github.com/openconnect/openconnect-gui/releases/download/{{ openconnect_windows_version }}/{{ openconnect_windows_filename }}\"\nopenconnect_windows_checksum: \"sha256:b1d4bd76b41f32d08287bf043b3dc8c798a145c02319217d45a74b0d9545a23d\"\n\n# macOS\nopenconnect_macos_version: \"v1.5.1\"\nopenconnect_macos_filename: \"openconnect-gui-1.5.1-Darwin.dmg\"\nopenconnect_macos_href: \"{{ openconnect_mirror_href_base }}/{{ openconnect_macos_filename }}\"\nopenconnect_macos_url: \"https://github.com/openconnect/openconnect-gui/releases/download/{{ openconnect_macos_version }}/{{ openconnect_macos_filename }}\"\nopenconnect_macos_checksum: \"sha256:b2c338cfe9d0725bee98893225449e27cf7e337d43b0f8b08aec96de6f761f08\"\n\nopenconnect_download_urls:\n  - { url: \"{{ openconnect_source_url }}\",  checksum: \"{{ openconnect_source_checksum }}\" }\n  - { url: \"{{ openconnect_windows_url }}\", checksum: \"{{ openconnect_windows_checksum }}\" }\n  - { url: \"{{ openconnect_macos_url }}\", checksum: \"{{ openconnect_macos_checksum }}\" }\n"
  },
  {
    "path": "playbooks/roles/openvpn/defaults/main.yml",
    "content": "---\nopenvpn_key_country:  \"US\"\nopenvpn_key_province: \"California\"\nopenvpn_key_city: \"Beverly Hills\"\nopenvpn_key_org: \"ACME CORPORATION\"\nopenvpn_key_ou: \"Anvil Department\"\n\nopenvpn_port: \"636\"\nopenvpn_port_udp: \"8757\"\nopenvpn_port_sslh: \"443\"\nopenvpn_key_size: \"4096\"\nopenvpn_cipher: \"AES-256-CBC\"\nopenvpn_ncp_ciphers: \"AES-256-GCM:AES-128-GCM\"\nopenvpn_auth_digest: \"SHA256\"\nopenvpn_connect_timeout: 10 #seconds\n\n# If stunnel is enabled generating OpenVPN stunnel profiles requires these\n# variables to be defined\nstunnel_local_port: \"41194\"\nstunnel_remote_port: \"993\"\n"
  },
  {
    "path": "playbooks/roles/openvpn/files/openvpn_signing.key",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBE45PsIBCAC2K2LRZPQIUmJlCDKcncfR6vok2wowDpGpHZffvEEoUj/DoocR\nLLpPHR5RB1zMWIs2IjF8vOtXMCBguDgtEvQTh6p6DM3D1fTnYp3pPlQyyzAuC81v\nCQo44h09R4Nh2e38oMRVztmAnacC4g5aiSEamrZ4PbWdAdPc4uZdCPOGmUDJw8+q\naAYvL/8pM7YqEu05FqE+aNcG02K+mDhA2bqRLLKoLEFpeMSO6vV8BrE7Vw1Rs1PM\nVLDJt9HdXmC6vP+WWqDuj7/qfRb2wwlSIp5+aFyRHOUNyFKnWZYIObeV3+Y6oG6h\ngmBtU1673mHDqVy26TwfjpJeudMKHVCrKXVXABEBAAG0QVNhbXVsaSBTZXBww6Ru\nZW4gKE9wZW5WUE4gVGVjaG5vbG9naWVzLCBJbmMpIDxzYW11bGlAb3BlbnZwbi5u\nZXQ+iQFVBBMBAgA/AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgBYhBDDr9Oc8\nzmPu4STdJ45tqLThWMVpBQJZeJ2tBQkQ4vlrAAoJEI5tqLThWMVpPDUH/RdLsdG/\n4kmal/rfbso3YVxZXGp2fHKrptvCVrUWluYs6H/XBV4x6aMe8Q6K7Qa7BSLA9jZ8\nv+UN/4aA+urBcs6Ted/XbP3mKU47tOotW24nA1LRjd4gUSEXCaEOBbCSyw3uw6Vz\nU1wr1gEmkC7kvBziL+Pcbt5tKTRhUfgbcjYNNdp/nAwn3Pm3OFRaBt/qDU2aYAOH\n+k191x/ovDRO/UiU2CVvrdfv/VMZfo/rwxe8IiirxQ4k5DR2Vyu0DMNzlNTqRk8l\nrUH0FBdl0rOiefH0m6ubKstpYCaOUYsh/FaW53O6qqrTlZqPtAav1cRog8zb8mhT\nsFFAarhnZcQ/DG+5AQ0ETjk+wgEIAOg+Bjk8Wnb7fbbwBDDUalLsIEgFUhsrSLD5\nVVYB8tOq7djshckp/3LwfkSsmUzEtXMXxIbDUON1vbCQXZlQDe7E7uY5KFNWyi4+\nUJwLMrs+oqfeduUzDxQ+voq/6NGl+2olqd6vT/c/uPb/RPZpOdgoEkqFEOTMRVz0\nDZwAyzyYEWBrwDECNbEtqefMLPIaUGUzZvUc80I+MYL6AzRe/utIWcBnZ2nydZ0S\nvWKRJ0lOs69e6KoFVeE5QXzmTXkjzSbR9eN3ADm2j0EjLnpt/zR4hF8s4l4HLdRd\nSn47tAdvahsNfgWmOfiQD8btnu8DiMiJMd8IpVsZX/zCJbSUChcAEQEAAYkBPAQY\nAQIAJgIbDBYhBDDr9Oc8zmPu4STdJ45tqLThWMVpBQJZeJ2DBQkQ4vlBAAoJEI5t\nqLThWMVpCCIH+QFqEY+Xk5gJc10lbJUZEhJIknS/3GEd+3WBHgBtBaQCeK7+bFQP\nZagTN4SJLiwYcQDV04mZTpFOJV1k9AYaz7ENEjHe51mGhPM9sm5Ix7KwMNo0lHJ+\nryZ0zyie28IbGz+rYa7OdkhE2EmcQkezYNWC03G8yR9yGk3QZ3CtPPO/xYP2tBGc\nOocqWUkVuR7KpitT9QnOZ4af26b83Vr/+qJ1FdSfW6/VAbyboVWya4oEnKSUusBm\n0WCQzaLH15EpzgcdB/x8KVOTS1dAA5GNyRyhbRfP6yBXgBruCkPa4/np78/72jjW\nvbAvOhOEMnfzWmf3VZq+q6hhIJf6Sp+dcoU=\n=P3ax\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/openvpn/handlers/main.yml",
    "content": "---\n- name: Restart OpenVPN\n  systemd:\n    name: \"{{ item }}\"\n    state: restarted\n  with_items:\n    - \"{{ openvpn_service_names }}\"\n"
  },
  {
    "path": "playbooks/roles/openvpn/meta/main.yml",
    "content": "---\ndependencies:\n  # OpenVPN needs to be added to the firewall\n  - { role: ufw }\n  - { role: dnsmasq }\n  - { role: ip-forwarding }\n"
  },
  {
    "path": "playbooks/roles/openvpn/tasks/docs.yml",
    "content": "---\n- name: Create the OpenVPN Gateway directory\n  file:\n    path: \"{{ openvpn_gateway_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0750\n    state: directory\n\n- name: Copy the client files to the OpenVPN Gateway directory\n  command: cp --recursive {{ openvpn_path }}/{{ client_name.stdout }} {{ openvpn_gateway_location }}\n  args:\n    creates: \"{{ openvpn_gateway_location }}/{{ client_name.stdout }}/ca.crt\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"OpenVPN\"\n    input_template_name: \"instructions\"\n    i18n_location: \"{{ openvpn_gateway_location }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"OpenVPN stunnel\"\n    input_template_name: \"stunnel-instructions\"\n    output_file_name: \"stunnel\"\n    i18n_location: \"{{ openvpn_gateway_location }}\"\n  when: streisand_stunnel_enabled\n"
  },
  {
    "path": "playbooks/roles/openvpn/tasks/firewall.yml",
    "content": "---\n- name: Allow OpenVPN through the firewall\n  command: \"{{ item }}\"\n  with_items: \"{{ openvpn_firewall_rules }}\"\n\n- name: Ensure UFW allows DNS requests from OpenVPN clients\n  ufw:\n    to_port: \"53\"\n    proto: \"udp\"\n    rule: \"allow\"\n    from_ip: \"10.8.0.0/24\"\n\n- name: Ensure UFW allows DNS requests from OpenVPN UDP clients\n  ufw:\n    to_port: \"53\"\n    proto: \"udp\"\n    rule: \"allow\"\n    from_ip: \"10.9.0.0/24\"\n\n- name: Ensure UFW allows OpenVPN\n  ufw:\n    to_port: \"{{ openvpn_port }}\"\n    proto: \"tcp\"\n    rule: \"allow\"\n\n- name: Ensure UFW allows OpenVPN over UDP\n  ufw:\n    to_port: \"{{ openvpn_port_udp }}\"\n    proto: \"udp\"\n    rule: \"allow\"\n\n- name: Install the OpenVPN iptables service file\n  template:\n    src: openvpn-iptables.service.j2\n    dest: /etc/systemd/system/openvpn-iptables.service\n    mode: 0644\n\n- name: Enable the openvpn-iptables service\n  systemd:\n    daemon_reload: yes\n    name: openvpn-iptables.service\n    enabled: yes\n    state: started\n"
  },
  {
    "path": "playbooks/roles/openvpn/tasks/install.yml",
    "content": "---\n- name: \"Add the official OpenVPN APT key; hiding 25 lines of log...\"\n  apt_key:\n    id: E158C569\n    data: \"{{ item }}\"\n  with_file: openvpn_signing.key\n  no_log: True\n\n- name: Add the official OpenVPN repository\n  apt_repository:\n    repo: 'deb https://build.openvpn.net/debian/openvpn/stable {{ ansible_lsb.codename }} main'\n    state: present\n  register: openvpn_add_apt_repository\n  until: not openvpn_add_apt_repository.failed\n  retries: \"{{ apt_repository_retries }}\"\n  delay: \"{{ apt_repository_delay }}\"\n\n- name: Install OpenVPN and its dependencies from APT\n  apt:\n    package:\n      - openvpn\n      - udev\n"
  },
  {
    "path": "playbooks/roles/openvpn/tasks/main.yml",
    "content": "---\n# Add the apt key and install OpenVPN\n- import_tasks: install.yml\n\n- name: \"Configure DNSMasq to listen on {{ dnsmasq_openvpn_tcp_ip }}:53 and {{ dnsmasq_openvpn_udp_ip }}:53\"\n  template:\n    src: openvpn_dnsmasq.conf.j2\n    dest: /etc/dnsmasq.d/openvpn.conf\n  notify: Restart dnsmasq\n\n- include_role:\n    name: certificates\n  vars:\n    ca_path:            \"{{ openvpn_path }}\"\n    tls_ca:             \"{{ openvpn_ca }}\"\n    tls_client_path:    \"{{ openvpn_path }}\"\n    generate_ca_server: yes\n    generate_client:    yes\n    tls_request_subject:         \"{{ openvpn_request_subject }}\"\n    tls_server_common_name_file: \"{{ openvpn_server_common_name_file }}\"\n    tls_sans:\n      - \"{{ streisand_ipv4_address }}\"\n\n- name: Register the OpenVPN server common name\n  command: cat \"{{ openvpn_server_common_name_file }}\"\n  register: openvpn_server_common_name\n  changed_when: False\n\n- name: Generate HMAC firewall key\n  command: openvpn --genkey --secret {{ openvpn_hmac_firewall }}\n  args:\n    creates: \"{{ openvpn_hmac_firewall }}\"\n\n- name: Register CA certificate contents\n  command: cat ca.crt\n  args:\n    chdir: \"{{ openvpn_path }}\"\n  register: openvpn_ca_contents\n  changed_when: False\n\n- name: Register client certificate contents\n  command: cat client.crt\n  args:\n    chdir: \"{{ openvpn_path }}/{{ client_name.stdout }}\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n  register: openvpn_client_certificates\n  changed_when: False\n\n- name: Register client key contents\n  command: cat client.key\n  args:\n    chdir: \"{{ openvpn_path }}/{{ client_name.stdout }}\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n  register: openvpn_client_keys\n  changed_when: False\n\n- name: Register HMAC firewall contents\n  command: cat ta.key\n  args:\n    chdir: \"{{ openvpn_path }}\"\n  register: openvpn_hmac_firewall_contents\n  changed_when: False\n\n- name: Create the client configuration profiles that will be used when connecting directly\n  template:\n    src: client-direct.ovpn.j2\n    dest: \"{{ openvpn_path }}/{{ item[0].stdout }}/{{ openvpn_direct_profile_filename }}\"\n  with_together:\n    - \"{{ vpn_client_names.results }}\"\n    - \"{{ openvpn_client_certificates.results }}\"\n    - \"{{ openvpn_client_keys.results }}\"\n  loop_control:\n    label: \"{{ item[0].item }}\"\n\n- name: Create the client configuration profiles that will be used when connecting directly via UDP\n  template:\n    src: client-direct-udp.ovpn.j2\n    dest: \"{{ openvpn_path }}/{{ item[0].stdout }}/{{ openvpn_direct_udp_profile_filename }}\"\n  with_together:\n    - \"{{ vpn_client_names.results }}\"\n    - \"{{ openvpn_client_certificates.results }}\"\n    - \"{{ openvpn_client_keys.results }}\"\n  loop_control:\n    label: \"{{ item[0].item }}\"\n\n- name: Create the client configuration profiles that will be used when connecting via sslh\n  template:\n    src: client-sslh.ovpn.j2\n    dest: \"{{ openvpn_path }}/{{ item[0].stdout }}/{{ openvpn_sslh_profile_filename }}\"\n  with_together:\n    - \"{{ vpn_client_names.results }}\"\n    - \"{{ openvpn_client_certificates.results }}\"\n    - \"{{ openvpn_client_keys.results }}\"\n  loop_control:\n    label: \"{{ item[0].item }}\"\n\n- name: Create the client configuration profiles that will be used when connecting via stunnel\n  template:\n    src: client-stunnel.ovpn.j2\n    dest: \"{{ openvpn_path }}/{{ item[0].stdout }}/{{ openvpn_stunnel_profile_filename }}\"\n  with_together:\n    - \"{{ vpn_client_names.results }}\"\n    - \"{{ openvpn_client_certificates.results }}\"\n    - \"{{ openvpn_client_keys.results }}\"\n  loop_control:\n    label: \"{{ item[0].item }}\"\n  when: streisand_stunnel_enabled\n\n- name: Create the combined client configuration profiles that will be used to connect from the fastest to the most compatible\n  template:\n    src: client-combined.ovpn.j2\n    dest: \"{{ openvpn_path }}/{{ item[0].stdout }}/{{ openvpn_combined_profile_filename }}\"\n  with_together:\n    - \"{{ vpn_client_names.results }}\"\n    - \"{{ openvpn_client_certificates.results }}\"\n    - \"{{ openvpn_client_keys.results }}\"\n  loop_control:\n    label: \"{{ item[0].item }}\"\n\n- name: Copy OpenVPN configuration file into place\n  template:\n    src: etc_openvpn_server.conf.j2\n    dest: \"{{ openvpn_path }}/server.conf\"\n\n- name: Copy OpenVPN UDP configuration file into place\n  template:\n    src: etc_openvpn_server_udp.conf.j2\n    dest: \"{{ openvpn_path }}/server-udp.conf\"\n\n- name: Stop and disable the bundled openvpn.service\n  systemd:\n    name: openvpn.service\n    state: stopped\n    enabled: no\n\n- name: Copy the OpenVPN system unit files\n  template:\n    src: openvpn.service.j2\n    dest: /etc/systemd/system/{{ item }}\n    mode: 0644\n  with_items:\n    - \"{{ openvpn_service_names }}\"\n\n- name: Enable the OpenVPN services\n  systemd:\n    daemon_reload: yes\n    name: \"{{ item }}\"\n    enabled: yes\n    state: restarted\n  with_items:\n    - \"{{ openvpn_service_names }}\"\n\n- name: Copy the ca.crt and ta.key files that clients will need in order to connect to the OpenVPN server\n  command: cp {{ openvpn_path }}/{{ item[1] }} {{ openvpn_path }}/{{ item[0].stdout }}\n  with_nested:\n    - \"{{ vpn_client_names.results }}\"\n    - [\"ca.crt\", \"ta.key\"]\n  loop_control:\n    label: \"{{ item[0].item }}\"\n\n# Set up the OpenVPN firewall rules\n- import_tasks: firewall.yml\n\n# Generate Gateway documentation\n- import_tasks: docs.yml\n\n# Mirror the OpenVPN clients\n- import_tasks: mirror.yml\n\n# Install stunnel\n# NOTE (@alimakki) - must be done after OpenVPN's Gateway task\n# since it depends on the OpenVPN gateway directory being present\n- include_role:\n    name: stunnel\n  when: streisand_stunnel_enabled\n"
  },
  {
    "path": "playbooks/roles/openvpn/tasks/mirror.yml",
    "content": "---\n- name: Include the OpenVPN mirror variables\n  include_vars: mirror.yml\n\n- name: Make the directory where OpenVPN's mirrored files will be stored\n  file:\n    path: \"{{ openvpn_mirror_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0755\n    state: directory\n\n- block:\n    - name: Mirror Tunnelblick for macOS\n      get_url:\n        url: \"{{ tunnelblick_url }}\"\n        dest: \"{{ openvpn_mirror_location }}\"\n        checksum: \"{{ tunnelblick_checksum }}\"\n        owner: www-data\n        group: www-data\n        mode: 0644\n\n    - include_role:\n        name: download-and-verify\n      vars:\n        project_name: \"OpenVPN Community\"\n        project_download_baseurl: \"{{ openvpn_base_download_url }}\"\n        project_download_files: \"{{ openvpn_download_files }}\"\n        project_download_location: \"{{ openvpn_mirror_location }}\"\n        project_signer_keyid: \"{{ openvpn_gpg_keyid }}\"\n  rescue:\n    - name: \"{{ streisand_mirror_warning }}\"\n      pause:\n        seconds: \"{{ streisand_mirror_warning_seconds }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"OpenVPN mirror\"\n    i18n_location: \"{{ openvpn_mirror_location }}\"\n    input_template_name: \"mirror\"\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/client-combined.ovpn.j2",
    "content": "client\n\n<connection>\nremote {{ openvpn_server }} {{ openvpn_port_udp }} udp\n</connection>\n<connection>\nremote {{ openvpn_server }} {{ openvpn_port }} tcp\nconnect-timeout {{ openvpn_connect_timeout }}\n</connection>\n<connection>\nremote {{ openvpn_server }} {{ openvpn_port_sslh }} tcp\nconnect-timeout {{ openvpn_connect_timeout }}\n</connection>\n\n{% include \"client-common.j2\" %}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/client-common.j2",
    "content": "dev tun\ncipher {{ openvpn_cipher }}\nauth {{ openvpn_auth_digest }}\nresolv-retry infinite\nnobind\npersist-key\npersist-tun\nremote-cert-tls server\nverify-x509-name {{ openvpn_server_common_name.stdout }} name\ntls-version-min 1.2\ncompress\nverb 3\nroute {{ streisand_ipv4_address }} 255.255.255.255 net_gateway\n\n<ca>\n{{ openvpn_ca_contents.stdout }}\n</ca>\n\n<cert>\n{{ item[1].stdout }}\n</cert>\n\n<key>\n{{ item[2].stdout }}\n</key>\n\n<tls-crypt>\n{{ openvpn_hmac_firewall_contents.stdout }}\n</tls-crypt>\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/client-direct-udp.ovpn.j2",
    "content": "client\nremote {{ openvpn_server }} {{ openvpn_port_udp }}\nproto udp\n{% include \"client-common.j2\" %}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/client-direct.ovpn.j2",
    "content": "client\nremote {{ openvpn_server }} {{ openvpn_port }}\nproto tcp\n{% include \"client-common.j2\" %}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/client-sslh.ovpn.j2",
    "content": "client\nremote {{ openvpn_server }} {{ openvpn_port_sslh }}\nproto tcp\n{% include \"client-common.j2\" %}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/client-stunnel.ovpn.j2",
    "content": "client\nremote 127.0.0.1 {{ stunnel_local_port }}\nproto tcp\n{% include \"client-common.j2\" %}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/etc_openvpn_server.conf.j2",
    "content": "server 10.8.0.0 255.255.255.0\npush \"dhcp-option DNS {{ dnsmasq_openvpn_tcp_ip }}\"\nproto tcp\nport {{ openvpn_port }}\n{% include \"etc_openvpn_server_common.j2\" %}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/etc_openvpn_server_common.j2",
    "content": "dev tun\nca ca.crt\ncert server.crt\nkey server.key  # This file should be kept secret\ndh none\nifconfig-pool-persist ipp.txt\npush \"redirect-gateway def1\"\n\n# Fix for the Windows 10 DNS leak described here:\n# https://community.openvpn.net/openvpn/ticket/605\npush block-outside-dns\n\nclient-to-client\nremote-cert-tls client\n\n# Allow multiple clients with the same common name to concurrently connect.\n# In the absence of this option, OpenVPN will disconnect a client instance\n# upon connection of a new client having the same common name.\n# duplicate-cn\n\nkeepalive 1800 3600\ntls-crypt ta.key # This file is secret\ncipher {{ openvpn_cipher }}\nncp-ciphers {{ openvpn_ncp_ciphers }}\n\n# limit the tls ciphers\ntls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384\n\nauth {{ openvpn_auth_digest }}\ntls-version-min 1.2\ncompress\nuser nobody\ngroup nogroup\npersist-key\npersist-tun\nverb 0\n\nscript-security 2\ntls-verify \"/usr/share/openvpn/verify-cn /etc/allowed_vpn_certs\"\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/etc_openvpn_server_udp.conf.j2",
    "content": "server 10.9.0.0 255.255.255.0\npush \"dhcp-option DNS {{ dnsmasq_openvpn_udp_ip }}\"\nproto udp\nport {{ openvpn_port_udp }}\n{% include \"etc_openvpn_server_common.j2\" %}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/instructions-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nOpenVPN\n-------\n{% if streisand_stunnel_enabled %}\nSi les connexions OpenVPN sont bloquées dans votre pays, reportez-vous aux instructions [OpenVPN (stunnel)](/openvpn/stunnel-fr.html) qui vous aideront à envelopper votre trafic OpenVPN dans un tunnel crypté afin qu'il ressemble à du trafic TLS standard.\n{% endif %}\n#### Une note sur les fichiers clients ####\nPour des raisons de sécurité, ce serveur OpenVPN a été configuré pour n'autoriser qu'une seule connexion client par paire de certificats. Toute tentative de ré-utiliser les certificats clients entraînera une session client existante de se déconnecter.\n\n---\n* Plateformes\n  * [Windows](#windows)\n  * [macOS](#macos)\n  * [Linux](#linux)\n  * [Linux (Ubuntu 16.04)](#linux-ubuntu-16.04)\n  * [Linux (Ubuntu 17.10)](#linux-ubuntu-17.10)\n  * [Linux (Ubuntu 18.04)](#linux-ubuntu-18.04)\n  * [Android](#android)\n  * [iOS](#ios)\n\n<a name=\"windows\"></a>\n### Windows ###\n\n1. Téléchargez et exécutez [l'installateur Windows](/mirror/index-fr.html#openvpn) OpenVPN.\n1. Cliquez sur *Suivant* et acceptez le contrat de licence en sélectionnant *J'accepte*.\n1. Cliquez *Suivant* sur l'écran *Choose Components* (Choisir les composants). Laissez toutes les options par défaut cochées.\n1. Notez le dossier de destination. C'est là que vous placerez le profil de configuration client `{{ openvpn_direct_profile_filename }}` après l'installation. Cliquez sur *Install* (Installer).\n1. Un avis de sécurité Windows apparaîtra et demande *Voulez-vous installer ce logiciel de périphérique?*. Cliquer *Installer*.\n1. Cliquez *Next* sur l'écran *Installation Complete* (installation complète).\n1. Décochez *Show Readme* puis cliquez *Finish* (finir).\n1. Cliquez-droit sur l'icône OpenVPN GUI et choisissez *Propriétés*.\n1. Allez à l'onglet *Compatibilité* et cochez la case *Exécuter ce programme en tant qu'administrateur* dans la section *Niveau du privilège*.\n1. Double-cliquez sur l'icône OpenVPN GUI situé sur votre bureau afin de lancer l'application.\n1. Téléchargez l'un de ces profils OpenVPN unifiés :\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Profils alternatifs](#sslh-profiles) sont disponibles si vous êtes sur un réseau qui ne permet l'accès au port `443`.*\n   * *[Profils UDP](#udp-profiles) sont disponibles.*\n   * *[Profils combinés](#combined-profiles) sont maintenant disponibles.*\n1. Ouvrez le répertoire *config* situé dans le dossier de destination. Pour la plupart des utilisateurs, ça sera *C:\\Programmes\\OpenVPN\\config* ou *C:\\Program Files (x86)\\OpenVPN\\config*. Vous verrez un seul fichier README dans ce répertoire.\n1. Faites glisser et déposez le `{{ openvpn_direct_profile_filename }}` téléchargé a ci-dessus, et placez-le dans le même répertoire que le fichier README.\n1. Faites un clic droit sur l'icône OpenVPN dans la barre des tâches et choisissez *Connecter*.\n1. Vous verrez des journaux se déplacent à mesure que la connexion est établie, suivie d'une notification de la barre des tâches indiquant votre adresse IP attribuée.\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n<a name=\"macos\"></a>\n### macOS ###\n\n1. Téléchargez et lancez [Tunnelblick](/mirror/index-fr.html#openvpn).\n1. Saisissez votre mot de passe pour permettre le processus d'installation de finir, et cliquez ensuite sur *OK*.\n1. Cliquez *Lancer* une fois l'installation terminée.\n1. Cliquez *J'ai des fichiers de configuration*.\n1. Téléchargez l'un des profils unifiés d'OpenVPN:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Profils alternatifs](#sslh-profiles) sont disponibles si vous êtes sur un réseau qui ne permet l'accès au port `443`.*\n   * *[Profils UDP](#udp-profiles) sont disponibles.*\n   * *[Profils combinés](#combined-profiles) sont maintenant disponibles.*\n1. Double-cliquez le profil OpenVPN.\n1. Vous devrez choisir si le profil doit être disponible pour tous les utilisateurs ou seulement pour l'utilisateur actuel. Après avoir effectué votre sélection, vous devrez entrer votre mot de passe.\n1. Recherchez l'icône Tunnelblick dans votre barre de menus. Cliquez dessus et choisissez *Connecter*.\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n<a name=\"linux\"></a>\n### Linux ###\n1. Installer OpenVPN:\n\n   `sudo apt-get install openvpn` où `sudo yum install openvpn` où `gestionnaire-de-paquetage-esoterique hipster openvpn`\n\n   * Si l'installation de OpenVPN via votre gestionnaire de paquet n'est pas une option, vous pouvez également télécharger et compiler le [code source OpenVPN](/mirror/index-fr.html#openvpn).\n1. Téléchargez l'un de ces profils OpenVPN unifiés :\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Profils alternatifs](#sslh-profiles) sont disponibles si vous êtes sur un réseau qui permet uniquement l'accès au port `443`.*\n   * *[Profils UDP](#udp-profiles) sont disponibles.*\n   * *[Profils combinés](#combined-profiles) sont maintenant disponibles.*\n1. Copiez le fichier `{{ openvpn_direct_profile_filename }}` téléchargé vers l'emplacement de votre choix. */etc/openvpn/* est une bonne option.\n1. Sur certaines distributions, l'option DNS DHCP poussée du serveur OpenVPN sera ignorée. Cela signifie que vos requêtes DNS seront toujours acheminées via les serveurs de votre FAI qui les rend vulnérables à ce que l'on appelle une fuite DNS.\n   * Vous pouvez tester si votre DNS ou non est en train de fuir [ici](https://dnsleaktest.com/).\n   * Vous pouvez vous assurer que les serveurs DNS corrects sont utilisés en ajoutant les lignes suivantes au début du fichier `{{ openvpn_direct_profile_filename }}`:\n     * `script-security 2`\n     * `up /etc/openvpn/update-resolv-conf`\n     * `down /etc/openvpn/update-resolv-conf`\n1. Exécutez OpenVPN et passez le profil .ovpn en option.\n\n   `sudo openvpn {{ openvpn_direct_profile_filename }}`\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n<a name=\"linux-ubuntu-16.04\"></a>\n### Linux (Ubuntu 16.04) ###\nEn raison d'un problème lié à NetworkManager d'Ubuntu 16.04, vous ne pouvez pas utiliser le plug-in OpenVPN. De plus, vous ne pouvez pas utiliser la version de OpenVPN qui est dans les dépôts par défaut. Pour résoudre ce problème, nous devons télécharger OpenVPN directement depuis le dépôt de projets.\n\n1. Téléchargez l'un de ces profils OpenVPN unifiés :\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * [Profils alternatifs](#sslh-profiles) sont disponibles si vous êtes sur un réseau qui permet uniquement l'accès au port `443`.*\n   * [Profils UDP](#udp-profiles) sont disponibles.*\n   * [Profils combinés](#combined-profiles) sont maintenant disponibles.*\n1. Copiez le fichier téléchargé {{ openvpn_direct_profile_filename }} `à l'emplacement de votre choix. */etc/openvpn/* est une bonne option.\n1. Ajouter le dépôt APT OpenVPN à vos sources en exécutant les commandes suivantes :\n\n   `curl -s https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add`\n   `echo \"deb http://build.openvpn.net/debian/openvpn/stable xenial main\" > /etc/apt/sources.list.d/openvpn-aptrepo.list`\n1. Mettre à jour et installez OpenVPN avec la commande suivante :\n\n   `sudo apt update && sudo apt install openvpn`\n1. Une fois l'installation terminée, vérifiez que vous disposez de la version OpenVPN 2.4+ avec la commande suivante :\n\n   `openvpn --version`\n1. Dans certaines distributions, l'option DNS DHCP poussée du serveur OpenVPN sera ignorée. Cela signifie que vos requêtes DNS seront toujours acheminés par les serveurs de votre fournisseur de services Internet qui les rend vulnérables à ce qu'on appelle une fuite DNS.\n   * Vous pouvez tester si votre DNS fuit ou non [ici](https://dnsleaktest.com/).\n   * Vous pouvez vous assurer que les serveurs DNS corrects sont utilisés en ajoutant les lignes suivantes au début du fichier `{{ openvpn_direct_profile_filename }}` :\n     * `script-security 2`\n     * `up /etc/openvpn/update-resolv-conf`\n     * `down /etc/openvpn/update-resolv-conf`\n1. Exécutez OpenVPN et transmettez-lui le profil .ovpn en option.\n\n   `sudo openvpn {{ openvpn_direct_profile_filename }}`\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n<a name=\"linux-ubuntu-17.10\"></a>\n### Linux (Ubuntu) ###\nIl est préférable de configurer Ubuntu en utilisant le plugin OpenVPN pour NetworkManager. Cela vous donne une jolie petite interface pour la connexion, et il gère correctement les modifications DNS nécessaires lors de la connexion / déconnexion. Malheureusement, le plugin ne prend pas en charge les profils .ovpn, les étapes sont donc un peu plus compliquée.\n\n1. Premièrement, téléchargez le certificat CA d'OpenVPN, le certificat client `.crt`, la clé privée du client `.key`, et finalement la clé d'authentification TLS `ta.key` pour l'un ces profils en dessous:\n{% for client in vpn_client_names.results %}\n   * {{ client.stdout }}\n      * CA Cert: [ca.crt](/openvpn/{{ client.stdout }}/ca.crt)\n      * Client Cert: [{{ client.stdout }}.crt](/openvpn/{{ client.stdout }}/client.crt)\n      * Client Clé: [{{ client.stdout }}.key](/openvpn/{{ client.stdout }}/client.key)\n      * TA Clé: [ta.key](/openvpn/{{ client.stdout }}/ta.key)\n{% endfor %}\n1. Installez le plugin OpenVPN pour NetworkManager.\n\n   `sudo apt-get install network-manager-openvpn-gnome`\n1. Ouvrez votre *Paramètres système*.\n1. Cliquez sur l'icône *Réseau*.\n1. Cliquez sur le bouton *+* en bas à gauche de la fenêtre.\n1. Sélectionnez *VPN* dans la liste déroulante Interface et cliquez sur *Créer*.\n1. Sélectionnez *OpenVPN* et cliquez *Créer*.\n1. Saisissez `{{ streisand_server_name }}` pour la *Nom de la connexion*.\n1. Saisissez `{{ openvpn_server }}` pour le *Gateway*.\n1. Assurez-vous que *Certificates (TLS)* est sélectionné pour le *Type*.\n1. Sélectionnez le fichier `client.crt` de votre choix pour le *User Certificate*.\n1. Sélectionnez le fichier `ca.crt` pour le *CA Certificate*.\n1. Sélectionnez le ficher `client.key` pour le *Private Key*.\n1. Cliquez le bouton *Advanced*.\n1. Accédez à l'onglet *General*.\n   * Vérifier *Use custom gateway port* et entrer `{{ openvpn_port }}` comme sa valeur.\n     * Port `443` est disponible en alternative si vous êtes sur un réseau qui ne permet l'accès au le port HTTPS standard.\n     * Vous pouvez également utiliser le port `{{ openvpn_port_udp }}` pour une connexion UDP.\n     * Le profil combiné qui parcourt le port UDP `{{ openvpn_port_udp }}`, le port TCP `{{ openvpn_port }}`et `{{ openvpn_port_sslh }}` est également disponible.\n   * Cochez *Use a TCP connection* sauf si vous avez choisi d'utiliser le port UDP ou le profil combiné.\n1. Accédez à l'onglet *Security*.\n   * Sélectionnez `{{ openvpn_cipher }}` pour le *Cipher*.\n   * Sélectionnez `{{ openvpn_auth_digest }}` pour le *HMAC Authentication*.\n1. Accédez à l'onglet *TLS Authentication*.\n   * Dans le menu déroulant *Server Certificate Check* selectionnez `verify name exactly` et saisissez `{{ openvpn_server_common_name.stdout }}` pour sa valeur.\n   * Cochez *Verify peer (server) certificate usage signature*.\n   * Cochez *Additional TLS authentication or encryption*.\n     * Sélectionnez `TLS-Crypt` pour *Mode*.\n     * Sélectionnez le fichier `ta.key` que vous avez téléchargé depuis le répertoire client-files pour le *Key File*.\n   * Cliquez *Valider*.\n1. Cliquez *Enregistrer*\n1. Sélectionnez le VPN dans le menu à gauche, et faites glisser l'interrupteur sur *ON*. Vous pouvez également activer/désactiver le VPN en cliquant sur l'icône WiFi/Réseau dans la barre de menu, défiler vers *Connexions VPN* et en cliquant sur son nom.\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n<a name=\"linux-ubuntu-18.04\"></a>\n### Linux (Ubuntu) ###\nIl est préférable de configurer Ubuntu en utilisant le plugin OpenVPN pour NetworkManager. Cela vous donne une jolie petite interface pour la connexion, et il gère correctement les modifications DNS nécessaires lors de la connexion / déconnexion. Malheureusement, le plugin ne prend pas en charge les profils .ovpn, les étapes sont donc un peu plus compliquée.\n\n1. Premièrement, téléchargez le certificat CA d'OpenVPN, le certificat client `.crt`, la clé privée du client `.key`, et finalement la clé d'authentification TLS `ta.key` pour l'un ces profils en dessous:\n{% for client in vpn_client_names.results %}\n   * {{ client.stdout }}\n      * CA Cert: [ca.crt](/openvpn/{{ client.stdout }}/ca.crt)\n      * Client Cert: [{{ client.stdout }}.crt](/openvpn/{{ client.stdout }}/client.crt)\n      * Client Clé: [{{ client.stdout }}.key](/openvpn/{{ client.stdout }}/client.key)\n      * TA Clé: [ta.key](/openvpn/{{ client.stdout }}/ta.key)\n{% endfor %}\n1. Installez le plugin OpenVPN pour NetworkManager.\n\n   `sudo apt-get install network-manager-openvpn-gnome`\n1. Ouvrez votre *Paramètres système*.\n1. Cliquez sur l'icône *Réseau*.\n1. Cliquez sur le bouton *+* en bas à gauche de la fenêtre.\n1. Sélectionnez *VPN* dans la liste déroulante Interface et cliquez sur *Créer*.\n1. Sélectionnez *OpenVPN* et cliquez *Créer*.\n1. Saisissez `{{ streisand_server_name }}` pour la *Nom de la connexion*.\n1. Saisissez `{{ openvpn_server }}` pour le *Gateway*.\n1. Assurez-vous que *Certificates (TLS)* est sélectionné pour le *Type*.\n1. Sélectionnez le fichier `client.crt` de votre choix pour le *User Certificate*.\n1. Sélectionnez le fichier `ca.crt` pour le *CA Certificate*.\n1. Sélectionnez le ficher `client.key` pour le *Private Key*.\n1. Cliquez le bouton *Advanced*.\n1. Accédez à l'onglet *General*.\n   * Vérifier *Use custom gateway port* et entrer `{{ openvpn_port }}` comme sa valeur.\n     * Port `443` est disponible en alternative si vous êtes sur un réseau qui ne permet l'accès au le port HTTPS standard.\n     * Vous pouvez également utiliser le port `{{ openvpn_port_udp }}` pour une connexion UDP.\n     * Le profil combiné qui parcourt le port UDP `{{ openvpn_port_udp }}`, le port TCP `{{ openvpn_port }}`et `{{ openvpn_port_sslh }}` est également disponible.\n   * Cochez *Use a TCP connection* sauf si vous avez choisi d'utiliser le port UDP ou le profil combiné.\n1. Accédez à l'onglet *Security*.\n   * Sélectionnez `{{ openvpn_cipher }}` pour le *Cipher*.\n   * Sélectionnez `{{ openvpn_auth_digest }}` pour le *HMAC Authentication*.\n1. Accédez à l'onglet *TLS Authentication*.\n   * Dans le menu déroulant *Server Certificate Check* selectionnez `verify name exactly` et saisissez `{{ openvpn_server_common_name.stdout }}` pour sa valeur.\n   * Cochez *Verify peer (server) certificate usage signature*.\n   * Cochez *Additional TLS authentication or encryption*.\n     * Sélectionnez `TLS-Crypt` pour *Mode*.\n     * Sélectionnez le fichier `ta.key` que vous avez téléchargé depuis le répertoire client-files pour le *Key File*.\n   * Cliquez *Valider*.\n1. Cliquez *Enregistrer*\n1. Sélectionnez le VPN dans le menu à gauche, et faites glisser l'interrupteur sur *ON*. Vous pouvez également activer/désactiver le VPN en cliquant sur l'icône WiFi/Réseau dans la barre de menu, défiler vers *Connexions VPN* et en cliquant sur son nom.\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n<a name=\"android\"></a>\n### Android ###\n\n1. Installez [OpenVPN pour Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn&hl=fr).\n1. Téléchargez l'un de ces profils OpenVPN unifiés :\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Profils alternatifs](#sslh-profiles) sont disponibles si vous êtes sur un réseau qui permet uniquement l'accès au port `443`.*\n   * *[Profils UDP](#udp-profiles) sont disponibles.*\n   * *[Profils combinés](#combined-profiles) sont maintenant disponibles.*\n1. Copiez le fichier `{{ openvpn_direct_profile_filename }}` sur votre téléphone.\n1. Lancez OpenVPN pour Android.\n1. Appuyez sur l'icône du dossier en bas à droite de l'écran.\n1. Sélectionnez le profil `{{ openvpn_direct_profile_filename }}` que vous avez copié sur votre téléphone.\n1. Tapez sur l'icône de sauvegarde (disquette) en bas à droite de l'écran une fois l'importation est terminée.\n1. Tapez le profil.\n1. Acceptez l'avertissement de connexion VPN Android.\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n<a name=\"ios\"></a>\n### iOS ###\n\n1. Téléchargez [OpenVPN Connect](https://itunes.apple.com/fr/app/openvpn-connect/id590379981) et lancez-le.\n1. Téléchargez l'un de ces profils OpenVPN unifiés:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Profils alternatifs](#sslh-profiles) sont disponibles si vous êtes sur un réseau qui permet uniquement l'accès au port `443`.*\n   * *[Profils UDP](#udp-profiles) sont disponibles.*\n   * *[Profils combinés](#combined-profiles) sont maintenant disponibles.*\n1. Ouvrez iTunes sur votre ordinateur et connectez votre téléphone.\n1. Sélectionnez votre téléphone, cliquez sur l'onglet *Apps* et trouvez OpenVPN dans la section *Partage de fichiers*.\n1. Faites glisser et déposez le fichier `{{ openvpn_direct_profile_filename }}` téléchargé dans la fenêtre de partage de fichiers.\n1. OpenVPN sur votre téléphone va vous dire *1 new OpenVPN profile is available for import*.\n1. Appuyez sur le bouton vert *+* pour importer le profil.\n1. Tapez sur le l'interrupteur pour vous connecter au serveur OpenVPN.\n1. Succès! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n<a name=\"sslh-profiles\"></a>\n### Profils alternatifs unifiés pour l'accès via le port 443 ###\n\n{% for client in vpn_client_names.results %}\n* [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_sslh_profile_filename }})\n{% endfor %}\n\n<a name=\"udp-profiles\"></a>\n### Profils alternatifs unifiés pour accéder via le port UDP {{ openvpn_port_udp }} ###\n\n{% for client in vpn_client_names.results %}\n* [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_udp_profile_filename }})\n{% endfor %}\n\n<a name=\"combined-profiles\"></a>\n### Profil alternatif qui parcourra le port UDP {{ openvpn_port_udp }}, le port TCP {{ openvpn_port }}, et le port TCP {{ openvpn_port_sslh }} ###\n\n{% for client in vpn_client_names.results %}\n* [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_combined_profile_filename }})\n{% endfor %}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/instructions.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nOpenVPN\n-------\n{% if streisand_stunnel_enabled %}\nIf OpenVPN connections are being blocked in your country, please refer to the [OpenVPN (stunnel)](/openvpn/stunnel.html) instructions instead which will help you wrap your OpenVPN traffic in an encrypted tunnel so it looks like standard TLS traffic.\n{% endif %}\n#### A note on client files ####\nFor security reasons, this OpenVPN has been configured to only allow one client connection per certificate pair. Attempting to re-use client certificates will cause an existing client session to disconnect.\n\n---\n* Platforms\n  * [Windows](#windows)\n  * [macOS](#macos)\n  * [Linux](#linux)\n  * [Linux (Ubuntu 16.04)](#linux-ubuntu-16.04)\n  * [Linux (Ubuntu 17.10)](#linux-ubuntu-17.10)\n  * [Linux (Ubuntu 18.04/18.10)](#linux-ubuntu-18.04)\n  * [Android](#android)\n  * [iOS](#ios)\n\n<a name=\"windows\"></a>\n### Windows ###\n1. Download and run the OpenVPN [Windows Installer](/mirror/#openvpn).\n1. Click *Next* and accept the license agreement by selecting *I Agree*.\n1. Click *Next* on the *Choose Components* screen. Leave all of the default options checked.\n1. Make note of the Destination Folder. This is where you will place the `{{ openvpn_direct_profile_filename }}` client configuration profile after installation. Click *Install*.\n1. A Windows Security notice will appear and ask *Would you like to install this device software?*. Click *Install*.\n1. Click *Next* on the *Installation Complete* screen.\n1. Uncheck *Show Readme* and click *Finish*.\n1. Right-click on the OpenVPN GUI desktop icon and choose *Properties*.\n1. Go to the *Compatibility* tab and click the *Run this program as an administrator* checkbox in the *Privilege Level* section.\n1. Double-click the OpenVPN GUI desktop icon to launch the application.\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Alternate profiles](#sslh-profiles) are available if you are on a network that only allows access to port `443`.*\n   * *[UDP profiles](#udp-profiles) available.*\n   * *[Combined profiles](#combined-profiles) are now available.*\n1. Open the *config* directory that is located in the Destination Folder. For most users, this will either be in *C:\\Program Files\\OpenVPN\\config* or *C:\\Program Files (x86)\\OpenVPN\\config*. You will see a single README file in this directory.\n1. Drag and drop the downloaded `{{ openvpn_direct_profile_filename }}` file to this location alongside the README.\n1. Right-click on the OpenVPN icon in your taskbar and choose *Connect*.\n1. You will see a log scroll by as the connection is established, followed by a taskbar notification indicating your assigned IP.\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"macos\"></a>\n### macOS ###\n1. Download and open [Tunnelblick](/mirror/#openvpn).\n1. Type your password to allow the installation process to complete, and click *OK*.\n1. Click *Launch* after the installation is finished.\n1. Click *I have configuration files*.\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Alternate profiles](#sslh-profiles) are available if you are on a network that only allows access to port `443`.*\n   * *[UDP profiles](#udp-profiles) available.*\n   * *[Combined profiles](#combined-profiles) are now available.*\n1. Double-click the OpenVPN profile.\n1. You will be asked to choose whether the profile should be available for all users or only the current user. After making your selection, you will be asked to enter your password.\n1. Look for the Tunnelblick icon in your menu bar. Click on it, and choose *Connect*.\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"linux\"></a>\n### Linux ###\n1. Install OpenVPN:\n\n   `sudo apt-get install openvpn` OR `sudo yum install openvpn` OR `esoteric-package-manager hipster openvpn`\n\n   * If installing OpenVPN via your package manager is not an option, you can also download and compile the [OpenVPN source code](/mirror/#openvpn).\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Alternate profiles](#sslh-profiles) are available if you are on a network that only allows access to port `443`.*\n   * *[UDP profiles](#udp-profiles) available.*\n   * *[Combined profiles](#combined-profiles) are now available.*\n1. Copy the downloaded `{{ openvpn_direct_profile_filename }}` file to the location of your choice. */etc/openvpn/* is a decent option.\n1. On some distributions, the pushed DHCP DNS option from the OpenVPN server will be ignored. This means that your DNS queries will still be routed through your ISP's servers which makes them vulnerable to what is known as a DNS leak.\n   * You can test whether or not your DNS is leaking [here](https://dnsleaktest.com/).\n   * You can ensure that the correct DNS servers are used by adding the following lines to the top of the `{{ openvpn_direct_profile_filename }}` file:\n     * `script-security 2`\n     * `up /etc/openvpn/update-resolv-conf`\n     * `down /etc/openvpn/update-resolv-conf`\n1. Execute OpenVPN, and pass it the .ovpn profile as an option.\n\n   `sudo openvpn {{ openvpn_direct_profile_filename }}`\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"linux-ubuntu-16.04\"></a>\n### Linux (Ubuntu 16.04) ###\nDue to an issue related to Ubuntu 16.04's NetworkManager you cannot use the OpenVPN plugin. Additionally, you cannot use the version of OpenVPN which is in the default repositories. To fix this issue we must download OpenVPN directly from the projects repository.\n\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Alternate profiles](#sslh-profiles) are available if you are on a network that only allows access to port `443`.*\n   * *[UDP profiles](#udp-profiles) available.*\n   * *[Combined profiles](#combined-profiles) are now available.*\n1. Copy the downloaded `{{ openvpn_direct_profile_filename }}` file to the location of your choice. */etc/openvpn/* is a decent option.\n1. Add the OpenVPN APT repository to your sources by running the following commands:\n\n   `curl -s https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add`\n   `echo \"deb http://build.openvpn.net/debian/openvpn/stable xenial main\" > /etc/apt/sources.list.d/openvpn-aptrepo.list`\n1. Update and install OpenVPN with the following command:\n\n   `sudo apt update && sudo apt install openvpn`\n1. After the install is complete, ensure you have OpenVPN version 2.4+ with the following command:\n\n   `openvpn --version`\n1. On some distributions, the pushed DHCP DNS option from the OpenVPN server will be ignored. This means that your DNS queries will still be routed through your ISP's servers which makes them vulnerable to what is known as a DNS leak.\n   * You can test whether or not your DNS is leaking [here](https://dnsleaktest.com/).\n   * You can ensure that the correct DNS servers are used by adding the following lines to the top of the `{{ openvpn_direct_profile_filename }}` file:\n     * `script-security 2`\n     * `up /etc/openvpn/update-resolv-conf`\n     * `down /etc/openvpn/update-resolv-conf`\n1. Execute OpenVPN, and pass it the .ovpn profile as an option.\n\n   `sudo openvpn {{ openvpn_direct_profile_filename }}`\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"linux-ubuntu-17.10\"></a>\n### Linux (Ubuntu 17.10) ###\nIt's preferable to configure Ubuntu using the OpenVPN plugin for NetworkManager. This gives you a nice little interface for connecting, and it properly handles the necessary DNS changes when you connect/disconnect. Unfortunately, the plugin does not support .ovpn profiles, so the list of steps is a little more involved.\n\n1. First, download the OpenVPN CA certificate, the certificate `.crt` file, private key `.key` file, and TLS authentication key `ta.key` file for one of the client profiles below:\n{% for client in vpn_client_names.results %}\n   * {{ client.stdout }}\n      * CA Cert: [ca.crt](/openvpn/{{ client.stdout }}/ca.crt)\n      * Client Cert: [{{ client.stdout }}.crt](/openvpn/{{ client.stdout }}/client.crt)\n      * Client Key: [{{ client.stdout }}.key](/openvpn/{{ client.stdout }}/client.key)\n      * TA key: [ta.key](/openvpn/{{ client.stdout }}/ta.key)\n{% endfor %}\n1. Install the OpenVPN plugin for NetworkManager.\n\n   `sudo apt-get install network-manager-openvpn-gnome`\n1. Open your *System Settings*.\n1. Click the *Network* tab on the left side.\n1. Click the *+* button under *VPN*.\n1. Select *OpenVPN*.\n1. Enter `{{ streisand_server_name }}` for the *Name*.\n1. Enter `{{ openvpn_server }}` for the *Gateway*.\n1. Make sure *Certificates (TLS)* is selected for the *Type*.\n1. Select the `client.crt` file you downloaded for the *User Certificate*.\n1. Select the `ca.crt` file you downloaded for the *CA Certificate*.\n1. Select the `client.key` file you downloaded for the *Private Key*.\n1. Click the *Advanced* button.\n1. Go to the *General* tab.\n   * Check *Use custom gateway port* and enter `{{ openvpn_port }}` as its value.\n     * Port `443` is available as an alternative if you are on a network that only allows access to the standard HTTPS port.\n     * You can also use port `{{ openvpn_port_udp }}` for a UDP connection.\n     * A combined profile which cycles through UDP port `{{ openvpn_port_udp }}`, TCP port `{{ openvpn_port }}` and `{{ openvpn_port_sslh }}` is also available.\n   * Check *Use a TCP connection* unless you have chosen to use the UDP port or the combined profile.\n1. Go to the *Security* tab.\n   * Select `{{ openvpn_cipher }}` as the *Cipher*.\n   * Select `{{ openvpn_auth_digest }}` as the *HMAC Authentication*.\n1. Go to the *TLS Authentication* tab.\n   * Under *Server Certificate Check* choose `verify name exactly` and enter `{{ openvpn_server_common_name.stdout }}` as its value.\n   * Check *Verify peer (server) certificate usage signature*.\n   * Go to *Additional TLS authentication or encryption*.\n     * Select `TLS-Crypt` as the *Mode*.\n     * Select the `ta.key` file you downloaded from the client-files directory for the *Key File*.\n   * Click *OK*.\n1. Click *Add*\n1. Select the VPN in the left-hand menu, and flip the switch to *ON*. You can also enable/disable the VPN by clicking on the WiFi/Network icon in the menu bar, scrolling to *VPN Connections*, and clicking on its name.\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"linux-ubuntu-18.04\"></a>\n### Linux (Ubuntu 18.04/18.10) ###\nIt's preferable to configure Ubuntu using the OpenVPN plugin for NetworkManager. This gives you a nice little interface for connecting, and it properly handles the necessary DNS changes when you connect/disconnect. Unfortunately, the plugin does not support .ovpn profiles, so the list of steps is a little more involved.\n\n1. First, download the OpenVPN CA certificate, the certificate `.crt` file, private key `.key` file, and TLS authentication key `ta.key` file for one of the client profiles below:\n{% for client in vpn_client_names.results %}\n   * {{ client.stdout }}\n      * CA Cert: [ca.crt](/openvpn/{{ client.stdout }}/ca.crt)\n      * Client Cert: [{{ client.stdout }}.crt](/openvpn/{{ client.stdout }}/client.crt)\n      * Client Key: [{{ client.stdout }}.key](/openvpn/{{ client.stdout }}/client.key)\n      * TA key: [ta.key](/openvpn/{{ client.stdout }}/ta.key)\n{% endfor %}\n1. Install the OpenVPN plugin for NetworkManager.\n\n   `sudo apt-get install network-manager-openvpn-gnome`\n1. Open your *System Settings*.\n1. Click the *Network* tab on the left side.\n1. Click the *+* button under *VPN*.\n1. Select *OpenVPN*.\n1. Enter `{{ streisand_server_name }}` for the *Connection name*.\n1. Enter `{{ openvpn_server }}` for the *Gateway*.\n1. Make sure *Certificates (TLS)* is selected for the *Type*.\n1. Select the `ca.crt` file you downloaded for the *CA Certificate*.\n1. Select the `client.crt` file you downloaded for the *User Certificate*.\n1. Select the `client.key` file you downloaded for the *User Private Key*.\n1. Click the *Advanced* button.\n1. Go to the *General* tab.\n   * Check *Use custom gateway port* and enter `{{ openvpn_port }}` as its value.\n     * Port `443` is available as an alternative if you are on a network that only allows access to the standard HTTPS port.\n     * You can also use port `{{ openvpn_port_udp }}` for a UDP connection.\n     * A combined profile which cycles through UDP port `{{ openvpn_port_udp }}`, TCP port `{{ openvpn_port }}` and `{{ openvpn_port_sslh }}` is also available.\n   * Check *Use a TCP connection* unless you have chosen to use the UDP port or the combined profile.\n1. Go to the *Security* tab.\n   * Select `{{ openvpn_cipher }}` as the *Cipher*.\n   * Select `{{ openvpn_auth_digest }}` as the *HMAC Authentication*.\n1. Go to the *TLS Authentication* tab.\n   * Under *Server Certificate Check* choose `verify name exactly` and enter `{{ openvpn_server_common_name.stdout }}` as its value.\n   * Check *Verify peer (server) certificate usage signature*.\n   * Go to *Additional TLS authentication or encryption*.\n     * Select `TLS-Crypt` as the *Mode*.\n     * Select the `ta.key` file you downloaded from the client-files directory for the *Key File*.\n   * Click *OK*.\n1. Click *Add*\n1. Find the VPN and flip the switch to *ON*. You can also enable/disable the VPN by clicking on the WiFi/Network icon in the menu bar, scrolling to *VPN Connections*, and clicking on its name.\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"android\"></a>\n### Android ###\n1. Install [OpenVPN for Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn).\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Alternate profiles](#sslh-profiles) are available if you are on a network that only allows access to ports `80` and `443`.*\n   * *[UDP profiles](#udp-profiles) available.*\n   * *[Combined profiles](#combined-profiles) are now available.*\n1. Copy the `{{ openvpn_direct_profile_filename }}` file to your phone.\n1. Launch OpenVPN for Android.\n1. Tap the folder icon in the lower-right of the screen.\n1. Select the `{{ openvpn_direct_profile_filename }}` profile that you copied to your phone.\n1. Tap the save icon (floppy disk) in the lower-right of the screen after the import is complete.\n1. Tap the profile.\n1. Accept the Android VPN connection warning.\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"ios\"></a>\n### iOS ###\n1. Download [OpenVPN Connect](https://itunes.apple.com/us/app/openvpn-connect/id590379981) and launch it.\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_profile_filename }})\n{% endfor %}\n   * *[Alternate profiles](#sslh-profiles) are available if you are on a network that only allows access to ports `80` and `443`.*\n   * *[UDP profiles](#udp-profiles) available.*\n   * *[Combined profiles](#combined-profiles) are now available.*\n1. Open iTunes on your computer and connect your phone.\n1. Select your phone, click on the *Apps* tab, and find OpenVPN under the *File Sharing* section.\n1. Drag and drop the downloaded `{{ openvpn_direct_profile_filename }}` file into the file sharing window.\n1. OpenVPN on your phone will say that *1 new OpenVPN profile is available for import*.\n1. Tap the green *+* button to import the profile.\n1. Tap the slider to connect to the OpenVPN server.\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"sslh-profiles\"></a>\n### Alternate unified profiles for access via port 443 ###\n{% for client in vpn_client_names.results %}\n* [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_sslh_profile_filename }})\n{% endfor %}\n\n<a name=\"udp-profiles\"></a>\n### Alternate unified profiles for access via UDP port {{ openvpn_port_udp }} ###\n{% for client in vpn_client_names.results %}\n* [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_direct_udp_profile_filename }})\n{% endfor %}\n\n<a name=\"combined-profiles\"></a>\n### Alternate profile that will cycle through UDP port {{ openvpn_port_udp }}, TCP port {{ openvpn_port }}, and TCP port {{ openvpn_port_sslh }} ###\n{% for client in vpn_client_names.results %}\n* [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_combined_profile_filename }})\n{% endfor %}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/mirror-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"openvpn\"></a>\n### OpenVPN ###\n\n**Source**\n\n* [{{ openvpn_source_filename }}]({{ openvpn_source_href }}) ([sig]({{ openvpn_source_sig_href }}))\n\n**macOS**\n\n* [Tunnelblick\\_{{ tunnelblick_version }}.dmg]({{ tunnelblick_href }})\n  * Somme de contrôle: *{{ tunnelblick_checksum }}*\n\n**Windows**\n\n* [{{ openvpn_windows_installer_filename }}]({{ openvpn_windows_installer_href }}) ([sig]({{ openvpn_windows_installer_sig_href }}))\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/mirror.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"openvpn\"></a>\n### OpenVPN ###\n\n**Source**\n\n* [{{ openvpn_source_filename }}]({{ openvpn_source_href }}) ([sig]({{ openvpn_source_sig_href }}))\n\n**macOS**\n\n* [Tunnelblick\\_{{ tunnelblick_version }}.dmg]({{ tunnelblick_href }})\n  * Checksum: *{{ tunnelblick_checksum }}*\n\n**Windows**\n\n* [{{ openvpn_windows_installer_filename }}]({{ openvpn_windows_installer_href }}) ([sig]({{ openvpn_windows_installer_sig_href }}))\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/openvpn-iptables.service.j2",
    "content": "[Unit]\nDescription=Firewall rules required for OpenVPN\nAfter=network.target\nBefore={{ openvpn_service_names | join(' ') }}\n\n[Service]\nType=oneshot\nRemainAfterExit=true\n{% for rule in openvpn_firewall_rules %}\nExecStart=/sbin/{{ rule }}\n{% endfor %}\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/openvpn.service.j2",
    "content": "# source: https://github.com/OpenVPN/openvpn/blob/master/distro/systemd/openvpn-server%40.service.in\n[Unit]\nDescription=OpenVPN service for %I\nAfter=syslog.target network-online.target\nWants=network-online.target\nDocumentation=man:openvpn(8)\nDocumentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage\nDocumentation=https://community.openvpn.net/openvpn/wiki/HOWTO\n\n[Service]\nType=notify\nPrivateTmp=true\nWorkingDirectory={{ openvpn_path }}\nExecStart=/usr/sbin/openvpn --config %i.conf\nCapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE\nLimitNPROC=30\nDeviceAllow=/dev/null rw\nDeviceAllow=/dev/net/tun rw\nProtectSystem=true\nProtectHome=true\nKillMode=process\nRestartSec=5s\nRestart=on-failure\n\n[Install]\nAlias=openvpn@%i.target\nWantedBy=multi-user.target\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/openvpn_dnsmasq.conf.j2",
    "content": "# Listen on the OpenVPN TCP and UDP addresses\nlisten-address={{ dnsmasq_openvpn_tcp_ip }},{{ dnsmasq_openvpn_udp_ip }}\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/stunnel-instructions-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nOpenVPN (enveloppé dans stunnel)\n--------------------------------\n\nCes instructions ne doivent être utilisées que si les connexions OpenVPN sont bloquées activement dans votre pays ou par votre FAI. La performance sera meilleure si vous pouvez vous connecter directement, mais certains pays (notamment la Chine et l'Iran) emploient 'Deep Packet Inspection' pour détecter et affronter les connexions OpenVPN. Certaines entreprises font de même. Si vous ne rentrez pas dans cette catégorie, reportez-vous à la norme [instructions OpenVPN](/openvpn/index-fr.html) à la place.\n\nSuite à ces étapes, vous enveloppez votre trafic OpenVPN dans un tunnel crypté, de sorte qu'il ressemblera comme du trafic SSL standard soit dirigé vers un port où ce type de trafic serait attendu. Cela empêchera le 'DPI' d'identifier la nature veritable de vos paquets, ce qui vous permetera d'utiliser OpenVPN librement.\n\n#### Une note sur les fichiers clients ####\nPour des raisons de sécurité, les clients OpenVPN ont généralement leurs propres certificats et clés privées. Le serveur auquel vous vous connectez a été configuré pour permettre aux clients de partager le même certificat et la même clé privée, mais vous pouvez éventuellement donner à votre téléphone et votre ordinateur portable des clés différentes, par exemple.\n\n---\n* Plateformes\n  * [Windows](#windows)\n  * [macOS](#macos)\n  * [Linux](#linux)\n  * [Android](#android)\n  * [iOS](#ios)\n\n<a name=\"windows\"></a>\n### Windows ###\n#### Installation Stunnel ####\n1. Téléchargez et exécutez [l'installateur stunnel](/mirror/index-fr.html#stunnel).\n1. Téléchargez le fichier `stunnel.conf` qui a été personnalisé pour fonctionner avec ce serveur:\n   * [stunnel.conf](/openvpn/stunnel.conf)\n1. Ouvrez le répertoire où vous avez installé stunnel. Pour la plupart des utilisateurs, cela sera dans *C:\\Program Files\\stunnel* ou *C:\\Program Files (x86)\\stunnel*.\n1. Faites glisser et déposez le fichier `stunnel.conf` téléchargé dans ce répertoire.\n1. Double-cliquez sur *stunnel.exe* dans le répertoire d'installation pour lancer le service.\n\nMaintenant, vous êtes prêt à installer OpenVPN et à le configurer pour acheminer son trafic via Stunnel. Un profil .ovpn personnalisé préconfiguré pour fonctionner à côté du fichier `stunnel.conf` rendra cela facile.\n\n#### Installation OpenVPN ####\n1. Téléchargez et exécutez [l'installateur Windows](/mirror/index-fr.html#openvpn) OpenVPN.\n1. Cliquez sur *Suivant* et acceptez le contrat de licence en sélectionnant *J'accepte*.\n1. Cliquez *Suivant* sur l'écran *Choose Components* (Choisir les composants). Laissez toutes les options par défaut cochée.\n1. Notez le dossier de destination. C'est là que vous placerez le profil de configuration client `{{ openvpn_direct_profile_filename }}` après l'installation. Cliquez sur *Install* (Installer).\n1. Un avis de sécurité Windows apparaîtra et demande *Voulez-vous installer ce logiciel de périphérique?*. Cliquer *Installer*.\n1. Cliquez *Next* sur l'écran *Installation Complete* (installation complète).\n1. Décochez *Show Readme* puis cliquez *Finish* (finir).\n1. Cliquez-droit sur l'icône OpenVPN GUI et choisissez *Propriétés*.\n1. Allez à l'onglet *Compatibilité* et cliquez sur la coche *Exécuter ce programme en tant qu'administrateur* dans la section *Niveau du privilège*.\n1. Double-cliquez sur l'icône OpenVPN GUI situé sur votre bureau afin de lancer l'application.\n1. Téléchargez l'un de ces profils OpenVPN unifiés:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_stunnel_profile_filename }})\n{% endfor %}\n1. Ouvrez le directoire *config* situé dans le dossier de destination. Pour la plupart des utilisateurs, ça sera *C:\\Programmes\\OpenVPN\\config* ou *C:\\Program Files (x86)\\OpenVPN\\config*. Vous verrez un seul fichier README dans ce répertoire.\n1. Faites glisser et déposez le `{{ openvpn_stunnel_profile_filename }}` téléchargé a cette location juste à côté du fichier README.\n1. Faites un clic droit sur l'icône OpenVPN dans la barre des tâches et choisissez *Connecter*.\n1. Vous verrez des journaux se déplacent à mesure que la connexion est établie, suivie d'une notification de la barre des tâches indiquant votre adresse IP attribuée.\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n<a name=\"macos\"></a>\n### macOS ###\n#### Installation Stunnel ####\n1. Installer [Homebrew](https://brew.sh/), si vous ne l'avez pas.\n1. Installer stunnel utilisant Homebrew:\n\n   `brew install stunnel`\n\n   * Si l'installation de Homebrew n'est pas une option, vous pouvez également télécharger et compiler le [code source stunnel](/mirror/index-fr.html#stunnel).\n1. Téléchargez le fichier `stunnel.conf` qui a été personnalisé pour fonctionner avec ce serveur:\n   * [stunnel.conf](/openvpn/stunnel.conf)\n1. Remplacez le fichier défaut stunnel.conf avec la version personnalisée. Assurez-vous de mettre à jour l'emplacement de la source si vous avez téléchargé le fichier dans un répertoire différent.\n\n   `cp ~/Downloads/stunnel.conf /usr/local/etc/stunnel/`\n1. Lancez stunnel:\n\n   `stunnel`\n\nMaintenant, vous êtes prêt à installer OpenVPN et à le configurer pour acheminer son trafic via Stunnel. Un profil .ovpn personnalisé préconfiguré pour fonctionner à côté du fichier `stunnel.conf` rendra cela facile.\n\n#### Installation OpenVPN ####\n1. Téléchargez et lancez [Tunnelblick](/mirror/index-fr.html#openvpn).\n1. Saisissez votre mot de passe pour permettre le processus d'installation de finir, en suite cliquez *OK*.\n1. Cliquez *Lancer* une fois l'installation est terminée.\n1. Cliquez *J'ai des fichiers de configuration*.\n1. Téléchargez l'un des profils unifiés d'OpenVPN:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_stunnel_profile_filename }})\n{% endfor %}\n1. Double-cliquez le profile OpenVPN.\n1. Vous devrez choisir si le profil doit être disponible pour tous les utilisateurs ou seulement pour l'utilisateur actuel. Après avoir effectué votre sélection, vous devrez entrer votre mot de passe.\n1. Recherchez l'icône Tunnelblick dans votre barre de menus. Cliquez dessus et choisissez *Connecter*.\n1. Succès! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n<a name=\"linux\"></a>\n### Linux ###\n#### Installation Stunnel ####\n1. Assurez-vous que stunnel est installé:\n\n   `sudo apt-get install stunnel` où `sudo yum install stunnel` où `gestionnaire-de-paquetage-esoterique hipster stunnel`\n\n   * Si l'installation de stunnel via votre gestionnaire de paquets n'est pas une option, vous pouvez également télécharger et compiler le [code source stunnel](/mirror/index-fr.html#stunnel)..\n1. Téléchargez le fichier `stunnel.conf` qui a été personnalisé pour fonctionner avec ce serveur:\n   * [stunnel.conf](/openvpn/stunnel.conf)\n1. Copiez `stunnel.conf` vers la bonne destination. Assurez-vous de mettre à jour l'emplacement de la source si vous avez déplacé le répertoire ailleurs.\n\n   `cp ~/Downloads/stunnel.conf /etc/stunnel/`\n1. Les utilisateurs d'Ubuntu doivent ajuster le fichier `/etc/default/stunnel4` et assurez-vous que `ENABLED` est défini sur `1`.\n1. Redémarrez le service Stunnel:\n\n   `sudo service stunnel4 restart` ou `sudo service stunnel restart`\n\nMaintenant, vous êtes prêt à installer OpenVPN et à le configurer pour acheminer son trafic via Stunnel. Un profil .ovpn personnalisé préconfiguré pour fonctionner à côté du fichier `stunnel.conf` rendra cela facile.\n\n#### Installation OpenVPN ####\n\n1. Installer OpenVPN :\n\n   `sudo apt-get install openvpn` où `sudo yum install openvpn` où `gestionnaire-de-paquetage-esoterique hipster openvpn`\n\n   * Si l'installation de OpenVPN via votre gestionnaire de paquetage n'est pas une option, vous pouvez également télécharger et compiler le [code source OpenVPN](/mirror/index-fr.html#openvpn).\n1. Téléchargez l'un de ces profils OpenVPN unifiés :\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_stunnel_profile_filename }})\n{% endfor %}\n1. Copiez le fichier `{{ openvpn_direct_profile_filename }}` téléchargé vers l'emplacement de votre choix. */etc/openvpn/* est une bonne option.\n1. Sur certaines distributions, l'option DNS DHCP poussée du serveur OpenVPN sera ignorée. Cela signifie que vos requêtes DNS seront toujours acheminées via les serveurs de votre FAI qui les rend vulnérables à ce que l'on appelle une fuite DNS.\n   * Vous pouvez tester si votre DNS ou non est en train de fuir [içi](https://dnsleaktest.com/).\n   * Vous pouvez vous assurer que les serveurs DNS corrects sont utilisés en ajoutant les lignes suivantes au début du fichier `{{ openvpn_stunnel_profile_filename }}`:\n     * `script-security 2`\n     * `up /etc/openvpn/update-resolv-conf`\n     * `down /etc/openvpn/update-resolv-conf`\n\n1. Exécutez OpenVPN et passez le profil .ovpn en option.\n\n   `sudo openvpn {{ openvpn_stunnel_profile_filename }}`\n\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\nLe plugin OpenVPN pour NetworkManager semble devenir très confus à la manière dont il doit acheminer le trafic lorsque vous vous connectez à un serveur OpenVPN via une connexion stunnel. L'ajout manuelle d'informations sur l'itinéraire ne semble pas aider. Par conséquent, contrairement aux [instructions non stunnel](/openvpn/index-fr.html), les étapes ci-dessus sont également la méthode de connexion recommandée pour Ubuntu.\n\n<a name=\"android\"></a>\n### Android ###\n#### Installation SSLDroid ####\n1. Téléchargez la clé PKCS #12 stunnel\n   * [stunnel.p12](/openvpn/stunnel.p12)\n1. Copiez le fichier `stunnel.p12` sur votre téléphone.\n1. Installez [SSLDroid](https://play.google.com/store/apps/details?id=hu.blint.ssldroid&hl=fr) et lancez-le.\n1. Appuyez sur le bouton de menu.\n1. Tapez *Add tunnel*.\n1. Tapez *Tunnel name* et saisissez `{{ streisand_server_name }}`.\n1. Tapez *Local port* et saisissez `{{ stunnel_local_port }}`.\n1. Tapez *Remote host* et saisissez `{{ openvpn_server }}`.\n1. Tapez *Remote port* et saisissez `{{ stunnel_remote_port }}`.\n1. Appuyez sur le bouton 'browse' (Parcourir) à côté du fichier *PKCS12* et sélectionnez le fichier `stunnel.p12` que vous avez copié sur votre téléphone durant la première étape. Vous pouvez laisser le champ *PKCS12 pass* vide.\n1. Tapez *Apply*.\n\nMaintenant, vous êtes prêt à installer OpenVPN pour Android et à le configurer pour acheminer son trafic via SSLDroid, qui est connecté au port Stunnel sur le serveur distant. Un profil .ovpn personnalisé qui est préconfiguré pour fonctionner avec SSLDroid rendra cela facile.\n\n### Installation OpenVPN ###\n1. Installez [OpenVPN pour Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn&hl=fr).\n1. Téléchargez l'un de ces profils OpenVPN unifiés :\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_stunnel_profile_filename }})\n{% endfor %}\n1. Copiez le fichier `{{ openvpn_stunnel_profile_filename }}` sur votre téléphone.\n1. Lancez OpenVPN pour Android.\n1. Appuyez sur l'icône du dossier en bas à droite de l'écran.\n1. Sélectionnez le profil `{{ openvpn_stunnel_profile_filename }}` que vous avez copié sur votre téléphone.\n1. Tapez sur l'icône de sauvegarde (disquette) en bas à droite de l'écran une fois l'importation est terminée.\n1. Tapez le profil.\n1. Acceptez l'avertissement de connexion VPN Android.\n1. Succès ! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n\n<a name=\"ios\"></a>\niOS\n---\nIl n'y a pas d'applications de tunneling compatibles dans l'App Store en ce moment.\n"
  },
  {
    "path": "playbooks/roles/openvpn/templates/stunnel-instructions.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nOpenVPN (wrapped in stunnel)\n----------------------------\n\nThese instructions should only be used if OpenVPN connections are being actively blocked in your country or by your ISP. Performance will be better if you are able to connect directly, but certain countries (notably China and Iran) employ Deep Packet Inspection to detect and thwart OpenVPN connections. Some companies do the same. If you do not fall into this category, please refer to the standard [OpenVPN instructions](/openvpn/) instead.\n\nFollowing these steps will wrap your OpenVPN traffic in an encrypted tunnel so it looks like standard SSL traffic being directed to a port where this type of traffic would be expected. This prevents DPI from identifying the true nature of the packets, thereby allowing you to freely use OpenVPN.\n\n#### A note on client files ####\nFor security reasons, OpenVPN clients typically have their own unique certificate and private key. The server you will be connecting to has been configured to allow clients to share the same certificate and private key, but you may still wish to give your phone and laptop different keys, for example.\n\n---\n* Platforms\n  * [Windows](#windows)\n  * [macOS](#macos)\n  * [Linux](#linux)\n  * [Android](#android)\n  * [iOS](#ios)\n\n<a name=\"windows\"></a>\n### Windows ###\n#### Stunnel Setup ####\n1. Download and run the [stunnel installer](/mirror/#stunnel).\n1. Download the `stunnel.conf` file that has been customized to work with this server:\n   * [stunnel.conf](/openvpn/stunnel.conf)\n1. Open the directory where you installed stunnel. For most users, this will either be in *C:\\Program Files\\stunnel* or *C:\\Program Files (x86)\\stunnel*.\n1. Drag and drop the downloaded `stunnel.conf` file into this directory.\n1. Double click *stunnel.exe* in the installation directory to start the service.\n\nNow you are ready to install OpenVPN and configure it to route its traffic through stunnel. A custom .ovpn profile that is preconfigured to work alongside the `stunnel.conf` file will make this easy.\n\n#### OpenVPN Setup ####\n1. Download and run the OpenVPN [Windows Installer](/mirror/#openvpn).\n1. Click *Next* and accept the license agreement by clicking *I Agree*.\n1. Click *Next* on the *Choose Components* screen. Leave all of the default options checked.\n1. Make note of the Destination Folder. This is where you will place the `{{ openvpn_stunnel_profile_filename }}` client configuration profile after installation. Click *Install*.\n1. A Windows Security notice will appear and ask *Would you like to install this device software?*. Click *Install*.\n1. Click *Next* on the *Installation Complete* screen.\n1. Uncheck *Show Readme* and click *Finish*.\n1. Right-click on the OpenVPN GUI desktop icon and choose *Properties*.\n1. Go to the *Compatibility* tab and click the *Run this program as an administrator* checkbox in the *Privilege Level* section.\n1. Double-click the OpenVPN GUI desktop icon to launch the application.\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_stunnel_profile_filename }})\n{% endfor %}\n1. Open the *config* directory that is located in the Destination Folder. For most users, this will either be in *C:\\Program Files\\OpenVPN\\config* or *C:\\Program Files (x86)\\OpenVPN\\config*. You will see a single README file in this directory.\n1. Drag and drop the downloaded `{{ openvpn_stunnel_profile_filename }}` file to this location alongside the README.\n1. Right-click on the OpenVPN icon in your taskbar and choose *Connect*.\n1. You will see a log scroll by as the connection is established, followed by a taskbar notification indicating your assigned IP.\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"macos\"></a>\n### macOS ###\n#### Stunnel Setup ####\n1. Install [Homebrew](http://brew.sh/), if you haven't already.\n1. Install stunnel using Homebrew:\n\n   `brew install stunnel`\n\n   * If installing Homebrew is not an option, you can also download and compile the [stunnel source code](/mirror/#stunnel).\n1. Download the `stunnel.conf` file that has been customized to work with this server:\n   * [stunnel.conf](/openvpn/stunnel.conf)\n1. Replace the default stunnel.conf file with the customized version. Be sure to update the source location if you downloaded the file to a different directory.\n\n   `cp ~/Downloads/stunnel.conf /usr/local/etc/stunnel/`\n1. Start stunnel:\n\n   `stunnel`\n\nNow you are ready to install OpenVPN and configure it to route its traffic through stunnel. A custom .ovpn profile that is preconfigured to work alongside the `stunnel.conf` file will make this easy.\n\n#### OpenVPN Setup ####\n1. Download and open [Tunnelblick](/mirror/#openvpn).\n1. Type your password to allow the installation process to complete, and click *OK*.\n1. Click *Launch* after the installation is finished.\n1. Click *I have configuration files*.\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_stunnel_profile_filename }})\n{% endfor %}\n1. Double-click the OpenVPN profile.\n1. You will be asked to choose whether the profile should be available for all users or only the current user. After making your selection, you will be asked to enter your password.\n1. Look for the Tunnelblick icon in your menu bar. Click on it, and choose *Connect*.\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"linux\"></a>\n### Linux ###\n#### Stunnel Setup ####\n1. Make sure stunnel is installed:\n\n   `sudo apt-get install stunnel` OR `sudo yum install stunnel` OR `esoteric-package-manager hipster stunnel`\n\n   * If installing stunnel via your package manager is not an option, you can also download and compile the [stunnel source code](/mirror/#stunnel).\n1. Download the `stunnel.conf` file that has been customized to work with this server:\n   * [stunnel.conf](/openvpn/stunnel.conf)\n1. Copy `stunnel.conf` to the right destination. Be sure to update the source location if you have moved the directory elsewhere.\n\n   `cp ~/Downloads/stunnel.conf /etc/stunnel/`\n1. Ubuntu users should adjust the `/etc/default/stunnel4` file and make sure `ENABLED` is set to `1`.\n1. Restart the stunnel service:\n\n   `sudo service stunnel4 restart` OR `sudo service stunnel restart`\n\nNow you are ready to install OpenVPN and configure it to route its traffic through stunnel. A custom .ovpn profile that is preconfigured to work alongside the `stunnel.conf` file will make this easy.\n\n#### OpenVPN Setup ####\n1. Install OpenVPN:\n\n   `sudo apt-get install openvpn` OR `sudo yum install openvpn` OR `esoteric-package-manager hipster openvpn`\n\n   * If installing OpenVPN via your package manager is not an option, you can also download and compile the [OpenVPN source code](/mirror/#openvpn).\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_stunnel_profile_filename }})\n{% endfor %}\n1. Copy the downloaded `{{ openvpn_stunnel_profile_filename }}` file to the location of your choice. */etc/openvpn/* is a decent option.\n1. On some distributions, the pushed DHCP DNS option from the OpenVPN server will be ignored. This means that your DNS queries will still be routed through your ISP's servers which makes them vulnerable to what is known as a DNS leak.\n   * You can test whether or not your DNS is leaking [here](https://dnsleaktest.com/).\n   * You can ensure that the correct DNS servers are used by adding the following lines to the top of the `{{ openvpn_stunnel_profile_filename }}` file:\n     * `script-security 2`\n     * `up /etc/openvpn/update-resolv-conf`\n     * `down /etc/openvpn/update-resolv-conf`\n1. Execute OpenVPN, and pass it the .ovpn profile as an option:\n\n   `sudo openvpn {{ openvpn_stunnel_profile_filename }}`\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\nThe OpenVPN plugin for NetworkManager appears to become very confused as to how it should route traffic when you connect to an OpenVPN server through a wrapped stunnel connection. Manually adding route information does not seem to help. Therefore, unlike in the [non-stunnel instructions](/openvpn), the steps above are the recommended connection method for Ubuntu as well.\n\n<a name=\"android\"></a>\n### Android ###\n#### SSLDroid Setup ####\n1. Download the stunnel PKCS #12 formatted key:\n   * [stunnel.p12](/openvpn/stunnel.p12)\n1. Copy the `stunnel.p12` file to your phone.\n1. Install [SSLDroid](https://play.google.com/store/apps/details?id=hu.blint.ssldroid) and launch it.\n1. Tap the menu button.\n1. Tap *Add tunnel*.\n1. Tap *Tunnel name* and enter `{{ streisand_server_name }}`.\n1. Tap *Local port* and enter `{{ stunnel_local_port }}`.\n1. Tap *Remote host* and enter `{{ openvpn_server }}`.\n1. Tap *Remote port* and enter `{{ stunnel_remote_port }}`.\n1. Tap the browse button next to *PKCS12 file* and select the `stunnel.p12` file that you copied to your phone during the first step. You can leave the *PKCS12 pass* field blank.\n1. Tap *Apply*.\n\nNow you are ready to install OpenVPN for Android and configure it to route its traffic through SSLDroid, which is connected to the stunnel port on the remote server. A custom .ovpn profile that is preconfigured to work alongside SSLDroid will make this easy.\n\n#### OpenVPN Setup ####\n1. Install [OpenVPN for Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn).\n1. Download one of these unified OpenVPN profiles:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/openvpn/{{ client.stdout }}/{{ openvpn_stunnel_profile_filename }})\n{% endfor %}\n1. Copy the `{{ openvpn_stunnel_profile_filename }}` file to your phone.\n1. Launch OpenVPN for Android.\n1. Tap the folder icon in the lower-right of the screen.\n1. Select the `{{ openvpn_stunnel_profile_filename }}` profile that you copied to your phone.\n1. Tap the save icon (floppy disk) in the lower-right of the screen after the import is complete.\n1. Tap the profile.\n1. Accept the Android VPN connection warning.\n1. Success! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"ios\"></a>\niOS\n---\nThere are no stunnel-compatible tunneling applications available in the App Store at this time.\n"
  },
  {
    "path": "playbooks/roles/openvpn/vars/main.yml",
    "content": "---\nopenvpn_days_valid: \"1825\"\nopenvpn_request_subject: \"/C={{ openvpn_key_country }}/ST={{ openvpn_key_province }}/L={{ openvpn_key_city }}/O={{ openvpn_key_org }}/OU={{ openvpn_key_ou }}\"\nopenvpn_path: \"/etc/openvpn\"\nopenvpn_ca: \"{{ openvpn_path }}/ca\"\nopenvpn_hmac_firewall: \"{{ openvpn_path }}/ta.key\"\nopenvpn_server: \"{{ streisand_ipv4_address }}\"\nopenvpn_server_common_name_file: \"{{ openvpn_path }}/openvpn_server_common_name\"\n\nopenvpn_direct_profile_filename:     \"{{ openvpn_server }}-direct.ovpn\"\nopenvpn_direct_udp_profile_filename: \"{{ openvpn_server }}-direct-udp.ovpn\"\nopenvpn_sslh_profile_filename:       \"{{ openvpn_server }}-sslh.ovpn\"\nopenvpn_stunnel_profile_filename:    \"{{ openvpn_server }}-stunnel.ovpn\"\nopenvpn_combined_profile_filename:   \"{{ openvpn_server }}-combined.ovpn\"\n\ndnsmasq_openvpn_tcp_ip: \"10.8.0.1\"\ndnsmasq_openvpn_udp_ip: \"10.9.0.1\"\n\nopenvpn_firewall_rules:\n  - \"iptables --wait {{ streisand_iptables_wait }} -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT\"\n  - \"iptables --wait {{ streisand_iptables_wait }} -A FORWARD -s 10.8.0.0/24 -j ACCEPT\"\n  - \"iptables --wait {{ streisand_iptables_wait }} -A FORWARD -s 10.9.0.0/24 -j ACCEPT\"\n  - \"iptables --wait {{ streisand_iptables_wait }} -t nat -A POSTROUTING -s 10.8.0.0/24 -o {{ ansible_default_ipv4.interface }} -j MASQUERADE\"\n  - \"iptables --wait {{ streisand_iptables_wait }} -t nat -A POSTROUTING -s 10.9.0.0/24 -o {{ ansible_default_ipv4.interface }} -j MASQUERADE\"\n\nopenvpn_gateway_location: \"{{ streisand_gateway_location }}/openvpn\"\n\nopenvpn_service_names:\n  - \"openvpn@server.service\"\n  - \"openvpn@server-udp.service\"\n"
  },
  {
    "path": "playbooks/roles/openvpn/vars/mirror.yml",
    "content": "---\n# OpenVPN Download variables\n# --------------------------\nopenvpn_mirror_location:  \"{{ streisand_mirror_location }}/openvpn\"\nopenvpn_mirror_href_base: \"/mirror/openvpn\"\n\nopenvpn_base_download_url: \"https://build.openvpn.net/downloads/releases/latest\"\n\nopenvpn_source_filename:      \"openvpn-latest-stable.tar.gz\"\nopenvpn_source_sig_filename:  \"{{ openvpn_source_filename }}.asc\"\nopenvpn_source_href:          \"{{ openvpn_mirror_href_base }}/{{ openvpn_source_filename }}\"\nopenvpn_source_sig_href:      \"{{ openvpn_mirror_href_base }}/{{ openvpn_source_sig_filename }}\"\n\nopenvpn_windows_installer_filename:     \"openvpn-install-latest-stable-win10.exe\"\nopenvpn_windows_installer_sig_filename: \"{{ openvpn_windows_installer_filename }}.asc\"\nopenvpn_windows_installer_href:         \"{{ openvpn_mirror_href_base }}/{{ openvpn_windows_installer_filename }}\"\nopenvpn_windows_installer_sig_href:     \"{{ openvpn_mirror_href_base }}/{{ openvpn_windows_installer_sig_filename }}\"\n\nopenvpn_gpg_keyid: \"5ACFEAC6\"\nopenvpn_download_files:\n  - { \"file\": \"{{ openvpn_source_filename }}\", \"sig\": \"{{ openvpn_source_sig_filename }}\" }\n  - { \"file\": \"{{ openvpn_windows_installer_filename }}\", \"sig\": \"{{ openvpn_windows_installer_sig_filename }}\" }\n\n# macOS\ntunnelblick_version:  \"3.8.1\"\ntunnelblick_build:    \"5400\"\ntunnelblick_filename: \"Tunnelblick_{{ tunnelblick_version }}_build_{{ tunnelblick_build }}.dmg\"\ntunnelblick_href:     \"{{ openvpn_mirror_href_base }}/{{ tunnelblick_filename }}\"\ntunnelblick_url:      \"https://tunnelblick.net/release/{{ tunnelblick_filename }}\"\ntunnelblick_checksum: \"sha256:a619a1c01a33a8618fc2489a43241e95c828dcdb7f7c56cfc883dcbb22644693\"\n"
  },
  {
    "path": "playbooks/roles/service-net/files/10-service0.netdev",
    "content": "[NetDev]\nName=service0\nKind=dummy\n"
  },
  {
    "path": "playbooks/roles/service-net/files/10-service0.network",
    "content": "[Match]\nName=service0\n\n[Link]\nRequiredForOnline=yes\n\n[Network]\nAddress=10.10.10.10/24\n"
  },
  {
    "path": "playbooks/roles/service-net/files/service-net.conf",
    "content": "# Listen on the service network's IP\nlisten-address=10.10.10.10\n"
  },
  {
    "path": "playbooks/roles/service-net/meta/main.yml",
    "content": "---\ndependencies:\n  - role: dnsmasq\n"
  },
  {
    "path": "playbooks/roles/service-net/tasks/main.yml",
    "content": "---\n- name: Install service0 network configuration\n  copy:\n    src: \"{{ item }}\"\n    dest: /etc/systemd/network/\n    owner: root\n    group: root\n    mode: 0644\n  with_items:\n    - 10-service0.netdev\n    - 10-service0.network\n\n- name: Enable and start systemd networking\n  systemd:\n    daemon_reload: yes\n    name: systemd-networkd.service\n    enabled: yes\n    state: restarted\n\n- name: Install dnsmasq for service0 network\n  copy:\n    src: service-net.conf\n    dest: /etc/dnsmasq.d/\n    owner: root\n    group: root\n    mode: 0644\n\n# NOTE(@nop): From wireguard/tasks/main.yml:\n# NOTE(@cpu): We don't use a `notify` to \"Restart dnsmasq\" here because it seems\n# that in some conditions Ansible mistakenly believes the dnsmasq restart can be\n# skipped. We also don't use \"reloaded\" instead of \"restarted\" here because\n# dnsmasq doesn't seem to reload _new_ config files in that case, just existing\n# ones. A full restart is required in practice (sigh)\n- name: \"Restart DNSMasq to pick up the new configuration\"\n  service:\n    name: dnsmasq\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/defaults/main.yml",
    "content": "---\nshadowsocks_server_port: \"8530\"\nshadowsocks_local_port: \"1080\"\nshadowsocks_timeout: \"600\"\nshadowsocks_encryption_method: \"chacha20-ietf-poly1305\"\nshadowsocks_tcp_fast_open: \"true\"\nshadowsocks_v2ray_plugin: \"v2ray-plugin\"\nshadowsocks_v2ray_cover_domain: \"github.com\"\nshadowsocks_v2ray_plugin_options: \"host={{ shadowsocks_v2ray_cover_domain }}\"\nshadowsocks_v2ray_plugin_protocol: \"http\"\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/handlers/main.yml",
    "content": "---\n- name: Restart shadowsocks-libev\n  systemd:\n    name: shadowsocks-libev.service\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/meta/main.yml",
    "content": "---\ndependencies:\n  # Shadowsocks needs to be added to the firewall\n  - { role: ufw }\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/tasks/docs.yml",
    "content": "---\n- name: Create the Shadowsocks Gateway directory\n  file:\n    path: \"{{ shadowsocks_gateway_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0750\n    state: directory\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"Shadowsocks\"\n    i18n_location: \"{{ shadowsocks_gateway_location }}\"\n    input_template_name: \"instructions\"\n\n- name: Generate the Shadowsocks QR code\n  # The ss:// URI format is documented here:\n  #   http://shadowsocks.org/en/config/quick-guide.html\n  shell: echo -n '{{ shadowsocks_encryption_method }}:{{ shadowsocks_password.stdout }}@{{ streisand_ipv4_address }}:{{ shadowsocks_server_port }}' | base64 --wrap=0 | sed 's/^/ss:\\/\\//' | qrencode -s 8 -o {{ shadowsocks_qr_code }}\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/tasks/firewall.yml",
    "content": "---\n- name: Ensure UFW allows Shadowsocks\n  ufw:\n    to_port: \"{{ shadowsocks_server_port }}\"\n    proto: \"any\"\n    rule: \"allow\"\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/tasks/main.yml",
    "content": "---\n- name: Apply the sysctl value to enable TCP Fast Open\n  sysctl:\n    name: net.ipv4.tcp_fastopen\n    value: 3\n    state: present\n  when: ansible_virtualization_type != 'lxc'\n\n- name: Add the Shadowsocks PPA\n  apt_repository:\n    repo: 'ppa:max-c-lv/shadowsocks-libev'\n  register: shadowsocks_add_apt_repository\n  until: not shadowsocks_add_apt_repository.failed\n  retries: \"{{ apt_repository_retries }}\"\n  delay: \"{{ apt_repository_delay }}\"\n\n- name: Install shadowsocks-libev\n  apt:\n    package: \"shadowsocks-libev\"\n\n- name: Create the shadowsocks-libev config directory\n  file:\n    path: \"{{ shadowsocks_location }}\"\n    owner: root\n    # The nobody user in nogroup needs to be able to read the config file\n    group: nogroup\n    # It is safe to make this directory world read only because the password\n    # file and config file are not\n    mode: 0755\n    state: directory\n\n- name: Populate the shadowsocks-libev systemd defaults\n  template:\n    src: shadowsocks-libev.default.j2\n    dest: \"/etc/default/shadowsocks-libev\"\n    mode: 0644\n\n- name: Generate a random Shadowsocks password\n  shell: openssl rand -base64 48 > {{ shadowsocks_password_file }}\n  args:\n    creates: \"{{ shadowsocks_password_file }}\"\n\n- name: Set permissions on the Shadowsocks password file\n  file:\n    path: \"{{ shadowsocks_password_file }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Register Shadowsocks password\n  command: cat {{ shadowsocks_password_file }}\n  register: shadowsocks_password\n  changed_when: False\n\n# Add V2ray support\n- import_tasks: v2ray.yml\n  when: streisand_shadowsocks_v2ray_enabled|bool\n\n- name: Generate Shadowsocks config file\n  template:\n    src: config.json.j2\n    dest: \"{{ shadowsocks_location }}/config.json\"\n    # The nobody user in nogroup needs to be able to read the config file\n    group: nogroup\n    mode: 0640\n\n- name: Create the shadowsocks systemd configuration directory\n  file:\n    path: \"{{ shadowsocks_systemd_service_path }}\"\n    state: directory\n\n- name: Generate the nginx systemd service file\n  template:\n    src: shadowsocks-libev.service.j2\n    dest: \"{{ shadowsocks_systemd_service_path }}/10-restart-failure.conf\"\n    mode: 0644\n\n- name: Enable the Shadowsocks service so it starts at boot, and bring it up\n  systemd:\n    name: shadowsocks-libev.service\n    daemon_reload: yes\n    enabled: yes\n    state: restarted\n\n# For some providers (e.g. GCE/AWS) the streisand_ipv4_address != the\n# ansible_default_ipv4.address, and the Shadowsocks service is bound to the\n# latter instead of the former. We check both, tolerating errors checking the\n# former. This mess should probably be addressed in a more forward facing\n# manner.\n- block:\n    - name: \"Check that the Shadowsocks service started ({{ streisand_ipv4_address }})\"\n      wait_for:\n        host: \"{{ streisand_ipv4_address }}\"\n        port: \"{{ shadowsocks_server_port }}\"\n        state: started\n        timeout: 30\n      ignore_errors: yes\n  rescue:\n    - name: \"Check that the Shadowsocks service started ({{ ansible_default_ipv4.address }})\"\n      wait_for:\n        host: \"{{ ansible_default_ipv4.address }}\"\n        port: \"{{ shadowsocks_server_port }}\"\n        state: started\n        timeout: 30\n\n# Apply the Shadowsocks firewall rules\n- import_tasks: firewall.yml\n\n# Generate the Shadowsocks gateway docs & client QR code\n- import_tasks: docs.yml\n\n# Mirror the Shadowsocks clients\n- import_tasks: mirror.yml\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/tasks/mirror.yml",
    "content": "---\n- name: Include the Shadowsocks mirror variables\n  include_vars: mirror.yml\n\n- name: Make the directory where the Shadowsocks mirrored files will be stored\n  file:\n    path: \"{{ shadowsocks_mirror_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0755\n    state: directory\n\n- block:\n    - name: Mirror the Shadowsocks clients\n      get_url:\n        url: \"{{ item.url }}\"\n        dest: \"{{ shadowsocks_mirror_location }}\"\n        checksum: \"{{ item.checksum }}\"\n        owner: www-data\n        group: www-data\n        mode: 0644\n      with_items: \"{{ shadowsocks_download_urls }}\"\n  rescue:\n    - name: \"{{ streisand_mirror_warning }}\"\n      pause:\n        seconds: \"{{ streisand_mirror_warning_seconds }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"Shadowsocks mirror\"\n    i18n_location: \"{{ shadowsocks_mirror_location }}\"\n    input_template_name: \"mirror\"\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/tasks/simple-obfs.yml",
    "content": "---\n- name: Clone the simple-obfs source code at tag {{ simple_obfs_version }}\n  git:\n    repo: \"https://github.com/shadowsocks/simple-obfs\"\n    dest: \"{{ simple_obfs_compilation_directory }}\"\n    version: \"v{{simple_obfs_version}}\"\n\n- name: Update the simple-obfs source code submodules\n  command: git submodule update --init --recursive\n  args:\n    chdir: \"{{ simple_obfs_compilation_directory }}\"\n    # if one of the submodules (libcork) has been populated we assume all of\n    # the submodules were updated.\n    creates: \"{{ simple_obfs_compilation_directory }}/libcork/Makefile.am\"\n\n- name: Autogen simple-obfs {{ simple_obfs_version }} source\n  command: ./autogen.sh\n  args:\n    chdir: \"{{ simple_obfs_compilation_directory }}\"\n    creates: \"{{ simple_obfs_compilation_directory }}/configure\"\n\n- name: Configure simple-obfs {{ simple_obfs_version }} source\n  command: ./configure {{ simple_obfs_configure_flags }}\n  args:\n    chdir: \"{{ simple_obfs_compilation_directory }}\"\n    creates: \"{{ simple_obfs_compilation_directory }}/Makefile\"\n\n- name: Compile simple-obfs {{ simple_obfs_version }} source\n  command: make -j{{ ansible_processor_cores }}\n  args:\n    chdir: \"{{ simple_obfs_compilation_directory }}\"\n    creates: \"{{ simple_obfs_compilation_directory }}/src/obfs-server\"\n\n- name: Install simple-obfs {{ simple_obfs_version }} binaries\n  command: make install\n  args:\n    chdir: \"{{ simple_obfs_compilation_directory }}\"\n    creates: \"/usr/local/bin/obfs-server\"\n...\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/tasks/v2ray.yml",
    "content": "---\n- name: Add the repo for getting the latest version of Go\n  apt_repository:\n    repo: 'ppa:longsleep/golang-backports'\n  register: golang_add_apt_repository\n  until: not golang_add_apt_repository.failed\n  retries: \"{{ apt_repository_retries }}\"\n  delay: \"{{ apt_repository_delay }}\"\n\n- name: Install golang-go\n  apt:\n    package: \"golang-go\"\n\n# Temporary workaround for insecure v2ray.com redirection\n# see https://github.com/StreisandEffect/streisand/issues/1642\n# for more info. We clone the v2ray-core repository to avoid\n# the \"go get\" command failing with an \"insecure redirect\" error.\n- file:\n    path: \"{{ go_path }}/src/v2ray.com\"\n    state: directory\n\n- name: \"[Temporary] Clone v2ray-core repository manually to GOPATH\"\n  git:\n    repo: \"{{ v2ray_core_github }}\"\n    dest: \"{{ go_path }}/src/v2ray.com/core\"\n\n- name: Get V2Ray-plugin\n  shell: \"go get {{ v2ray_github }}\"\n  environment:\n    GOPATH: \"{{ go_path }}\"\n\n- name: Copying v2ray-plugin to shadowsocks-libev directory\n  shell: \"cp -rf {{ v2ray_location }}/v2ray-plugin {{ shadowsocks_location }}\"\n...\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/templates/config.json.j2",
    "content": "{\n    \"server\":\"{{ ansible_default_ipv4.address }}\",\n    \"server_port\":{{ shadowsocks_server_port }},\n    \"local_port\":{{ shadowsocks_local_port }},\n    \"password\":\"{{ shadowsocks_password.stdout }}\",\n    \"timeout\":{{ shadowsocks_timeout }},\n    \"method\":\"{{ shadowsocks_encryption_method }}\",\n    \"fast_open\":{{ shadowsocks_tcp_fast_open }}\n{%- if streisand_shadowsocks_v2ray_enabled -%}\n,\n    \"plugin\":\"{{ shadowsocks_location }}/v2ray-plugin\",\n    \"plugin_opts\":\"{{ v2ray_options }}\"\n{% endif %}\n}\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/templates/instructions-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nShadowsocks\n-----------\n\n---\n* Plateformes\n  * [Windows](#windows)\n  * [macOS](#macos)\n  * [Linux](#linux)\n  * [Android](#android)\n  * [iOS](#ios)\n{%- if streisand_shadowsocks_v2ray_enabled -%}\n\n* Plugins\n  * [v2ray-plugin](#V2ray-plugin)\n\n{% endif %}\n\n<a name=\"windows\"></a>\n### Windows ###\n1. Téléchargez [Shadowsocks pour Windows](/mirror/shadowsocks/index-fr.html).\n1. Extrayez l'archive et double-cliquez sur le fichier Shadowsocks.exe.\n1. Assurez-vous que le code QR ci-dessous est centré et complètement visible, cliquez avec le bouton droit de la souris sur l'icône de la barre d'état système de Shadowsocks, puis accédez à *Servers* > *Scan QRCode from Screen...*\n\n   ![Shadowsocks QR code](/shadowsocks/shadowsocks-qr-code.png)\n1. Vous pouvez également aller à *Servers* > *New server* et procédez manuellement aux étapes suivantes:\n   1. Saisissez `{{ streisand_ipv4_address }}` pour le *Server IP*.\n   1. Saisissez `{{ shadowsocks_server_port }}` pour le *Server Port*.\n   1. Saisissez `{{ shadowsocks_password.stdout }}` pour le *Password*.\n   1. Le *SOCKS 5 Proxy Port* devrait être `{{ shadowsocks_local_port }}` et le *Encryption Method* devrait être `{{ shadowsocks_encryption_method }}`.\n   1. Assurez-vous que le support de l'authentification unique (OTA) est activé.\n   1. Cliquez *Save*.\n1. Cliquez sur l'icône de la barre de menus Shadowsocks et sélectionnez *Enable*.\n1. C'est tout! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n<a name=\"macos\"></a>\n### macOS ###\n1. Téléchargez [ShadowsocksX-NG](/mirror/shadowsocks/index-fr.html).\n1. Double-cliquez sur le DMG et faites glisser l'icône dans votre dossier Applications.\n1. Lancez ShadowsocksX-NG. Vous serez invité à saisir votre mot de passe afin que vos paramètres de proxy système puissent être modifiés.\n1. Tapez sur l'icône du l'avion en papier rond dans la barre inférieure gauche.\n1. Assurez-vous que le code QR ci-dessous est centré et complètement visible, et choisissez *Scan QR Code from Screen...*\n\n   ![Shadowsocks QR code](/shadowsocks/shadowsocks-qr-code.png)\n1. Vous pouvez également configurer la connexion en allant sur *Servers*, sélectionnant *Open Server Preferences...*, et en cliquant le bouton *+* sur la barre latérale:\n   1. Saisissez `{{ streisand_ipv4_address }}` et `{{ shadowsocks_server_port }}` dans le champ *Address*.\n   1. Assurez-vous que `{{ shadowsocks_encryption_method }}` est sélectionné pour la valeur *Encryption*.\n   1. Saisissez `{{ shadowsocks_password.stdout }}` pour le *Password*.\n   1. Chocher `Enable OTA`.\n   1. Cliquez *OK*.\n1. Cliquez à nouveau sur l'icône Shadowsocks dans la barre de menu, puis choisissez *Global Mode*.\n1. Vous pouvez utiliser l'icône Shadowsocks pour activer/désactiver le VPN. La couleur de l'icône changera en fonction de son activation ou pas.\n1. C'est tout! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n<a name=\"linux\"></a>\n### Linux ###\nTéléchargez [shadowsocks2-linux-x64.gz](/mirror/shadowsocks/index-fr.html) et extrayez-le:\n\n   `gunzip shadowsocks2-linux-x64.gz`\n\nModifier le binaire qu'il soit exécutable\n\n    `chmod +x shadowsocks2-linux-x64`\n\nDémarrez le proxy SOCKS shadowsocks:\n\n    `./shadowsocks2-linux-x64 -c {{ streisand_ipv4_address }}:{{ shadowsocks_server_port }} -password \"{{ shadowsocks_password.stdout }}\" -socks localhost:{{ shadowsocks_local_port }} -verbose -cipher {{ shadowsocks_encryption_method }}`\n\n\nPour référence, voici les informations de configuration dont vous aurez besoin:\n\n        Server: {{ streisand_ipv4_address }}\n        Port: {{ shadowsocks_server_port }}\n        Password: {{ shadowsocks_password.stdout }}\n        Encryption Method: {{ shadowsocks_encryption_method }}\n\nUne fois que vous avez Shadowsocks fonctionnant localement, vous devrez transférer le trafic de votre navigateur via le proxy SOCKS qu'il fournit.\n\n#### Configuration de Firefox pour se connecter via un proxy SOCKS ####\n1. Cliquez sur le bouton *Menu* à côté de l'icône *Accueil* à droite de la barre d'adresse.\n1. Cliquez *Préférences*.\n1. Cliquez l'icône *Avancé*.\n1. Allez à l'onglet *Réseau*.\n1. Cliquez le bouton *Paramètres* pour *Configurer la façon dont Firefox se connecte à Internet*.\n1. Choisissez *Configuration manuelle de proxy*.\n1. Saisissez `127.0.0.1` et port `{{ shadowsocks_local_port }}` pour la ligne *Hôte SOCKS*.\n1. Sélectionnez *Utiliser un DNS distant lorsque SOCKS v5 est actif*. Cela configure Firefox pour envoyer toutes les requêtes DNS via le proxy SOCKS. Cela vous protégera contre l'empoisonnement du DNS et vous garantira que les fausses entrées DNS ne peuvent pas être utilisées pour censurer votre accès.\n1. Cliquez *OK*.\n1. Cliquez *OK* encore pour fermer la fenêtre de paramètres de Firefox..\n1. C'est tout! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n\n<a name=\"android\"></a>\n### Android ###\n1. Téléchargez Shadowsocks pour Android à partir de [Google Play](https://play.google.com/store/apps/details?id=com.github.shadowsocks&hl=fr). Si Google Play est bloqué dans votre pays, vous pouvez [télécharger une copie en miroir](/mirror/shadowsocks/index-fr.html) de ce serveur!\n1. Lancez l'application.\n1. Tapez sur l'icône Ajouter un profil +, en haut à droite de l'écran.\n1. Tapez l'icône *+* en bas à droite.\n1. Sélectionnez *Scan QR code*.\n1. Utilisez votre téléphone pour numériser cette image, ou si vous utilisez votre téléphone _maintenant_, vous pouvez choisir la *Manual Settings* et copiez/collez les informations à partir de la section Linux ci-dessus:\n\n   ![Shadowsocks QR code](/shadowsocks/shadowsocks-qr-code.png)\n1. Tapez sur l'icône de l'avion en haut.\n1. Acceptez l'avertissement de connexion VPN Android.\n1. Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n\n<a name=\"ios\"></a>\n### iOS ###\n\n1. Téléchargez [Shadowrocket](https://itunes.apple.com/fr/app/shadowrocket/id932747118?mt=8) et lancez-le.\n   * Vous serez invité à vous connecter à l'iTunes Store la première fois que vous exécutez Shadowrocket.\n   > **Note:** Shadowrocket n'est pas disponible dans l'App Store chinois\n1. Appuyez sur l'icône d'importation du code QR en haut à gauche de l'écran.\n1. Utilisez votre téléphone pour numériser cette image, ou si vous utilisez votre téléphone _maintenant_, vous pouvez ajouter manuellement un nouveau proxy à partir de l'onglet *Home* et copier et coller les informations de la section Linux ci-dessus:\n\n   ![Shadowsocks QR code](/shadowsocks/shadowsocks-qr-code.png)\n1. Mettez le commutateur de connexion situé à droite du texte *Not connected* sur l'onglet *Home*.\n   * Si c'est la première fois que vous utilisez Shadowrocket, iOS vous demandera de vérifier que l'application devrait avoir la permission d'ajouter des configurations VPN. Tapez *Permettre* et suivez les instructions.\n1. Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n{%- if streisand_shadowsocks_v2ray_enabled -%}\n\n<a name=\"V2ray-plugin\"></a>\n### v2ray-plugin pour les réseaux peu fiables/hostiles ###\nPour les utilisateurs sur des réseaux peu fiables ou hostiles (en particulier la limitation de la qualité de service (QOS)), l'utilisation du plugin simple-obfs peut vous aider à atténuer ces problèmes. La configuration supplémentaire du client Shadowsocks pour utiliser le plugin v2ray-plugin peut être effectuée via la configuration suivante:\n\n        Server: {{ streisand_ipv4_address }}\n        Port: {{ shadowsocks_server_port }}\n        Password: {{ shadowsocks_password.stdout }}\n        Encryption Method: {{ shadowsocks_encryption_method }}\n        Plugin: {{ shadowsocks_v2ray_plugin }}\n        Plugin_Options: {{  shadowsocks_v2ray_plugin_options }}\nLes utilisateurs d'Android devront d'abord télécharger l'application [V2ray-plugin](https://play.google.com/store/apps/details?id=com.github.shadowsocks.plugin.v2ray), puis modifier le profil existant de Streisand sur votre client pour utiliser ce plugin. Vous pouvez le faire en appuyant sur le bouton d'édition (edit) à côté du profil, en tapant l'option Plugin en bas du profil et en sélectionnant le plugin \"V2ray-plugin\" dans le menu. Votre trafic Shadowsocks sera maintenant obscurci en tant que {{ shadowsocks_v2ray_plugin_protocol }} trafic vers `{{ shadowsocks_v2ray_cover_domain }}`.\n\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/templates/instructions.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nShadowsocks\n-----------\n\n---\n* Platforms\n  * [Windows](#windows)\n  * [macOS](#macos)\n  * [Linux](#linux)\n  * [Android](#android)\n  * [iOS](#ios)\n{%- if streisand_shadowsocks_v2ray_enabled -%}\n\n* Plugins\n  * [v2ray-plugin](#V2ray-plugin)\n\n{% endif %}\n\n<a name=\"windows\"></a>\n### Windows ###\n1. Download [Shadowsocks for Windows](/mirror/shadowsocks/).\n1. Extract the archive, and double-click on the Shadowsocks.exe file.\n1. Make sure the QR code below is centered and completely visible, right-click on the Shadowsocks system tray icon, and go to *Servers* > *Scan QRCode from Screen...*\n\n   ![Shadowsocks QR code](/shadowsocks/shadowsocks-qr-code.png)\n1. You may also go to *Servers* > *New server* and manually complete the following steps:\n   1. Enter `{{ streisand_ipv4_address }}` as the *Server IP*.\n   1. Enter `{{ shadowsocks_server_port }}` as the *Server Port*.\n   1. Enter `{{ shadowsocks_password.stdout }}` as the *Password*.\n   1. The *SOCKS 5 Proxy Port* should be `{{ shadowsocks_local_port }}` and the *Encryption Method* should be `{{ shadowsocks_encryption_method }}`.\n   1. Click *Save*.\n1. Click on the Shadowsocks menu tray icon and select *Enable*.\n1. That's it! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"macos\"></a>\n### macOS ###\n1. Download [ShadowsocksX-NG](/mirror/shadowsocks/).\n1. Double-click the ZIP, and extract the application into your Applications folder.\n1. Launch ShadowsocksX-NG. You will be prompted to enter your password so that your system proxy settings can be modified.\n1. Look for the Shadowsocks paper plane icon in your menu bar and click on it.\n1. Make sure the QR code below is centered and completely visible, and choose *Scan QR Code from Screen...*\n\n   ![Shadowsocks QR code](/shadowsocks/shadowsocks-qr-code.png)\n1. You may also configure the connection by going to *Servers*, selecting *Open Server Preferences...*, and clicking the *+* button on the sidebar:\n   1. Enter `{{ streisand_ipv4_address }}` and `{{ shadowsocks_server_port }}` in the *Address* fields.\n   1. Make sure `{{ shadowsocks_encryption_method }}` is selected for the *Encryption* value.\n   1. Enter `{{ shadowsocks_password.stdout }}` as the *Password*.\n   1. Click *OK*.\n1. Click on the Shadowsocks icon in the menu bar again, and choose *Global Mode*.\n1. You can use the Shadowsocks icon to enable/disable the VPN. The color of the icon will change based on whether or not it is active.\n1. That's it! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"linux\"></a>\n### Linux ###\nDownload [shadowsocks2-linux-x64.gz](/mirror/shadowsocks/) and extract it:\n\n    `gunzip shadowsocks2-linux-x64.gz`\n\nMake the binary executable:\n\n    `chmod +x shadowsocks2-linux-x64`\n\nStart the shadowsocks SOCKS proxy:\n\n    `./shadowsocks2-linux-x64 -c {{ streisand_ipv4_address }}:{{ shadowsocks_server_port }} -password \"{{ shadowsocks_password.stdout }}\" -socks localhost:{{ shadowsocks_local_port }} -verbose -cipher {{ shadowsocks_encryption_method }}`\n\nFor reference, this is the configuration specified:\n\n        Server: {{ streisand_ipv4_address }}\n        Port: {{ shadowsocks_server_port }}\n        Password: {{ shadowsocks_password.stdout }}\n        Encryption Method: {{ shadowsocks_encryption_method }}\n\nOnce you have Shadowsocks running locally, you'll need to forward your browser traffic through the SOCKS proxy it provides\n\n### Testing with Curl\n\nYou can quickly test using curl:\n\n     `curl -I --socks5 localhost:1080 google.com`\n\nThis should return a 301 Found response **not** a connection refused error.\n\n#### Configuring Firefox to connect through a SOCKS proxy ####\n1. Click the *Menu* button next to the *Home* icon to the right of the address bar.\n1. Click *Options*.\n1. Click the *Advanced* icon.\n1. Go to the *Network* tab.\n1. Click the *Settings* button to *Configure how Firefox connects to the Internet*.\n1. Choose *Manual proxy configuration*.\n1. Enter `127.0.0.1` and Port `{{ shadowsocks_local_port }}` on the *SOCKS Host* line.\n1. Select *Remote DNS*. This configures Firefox to send all DNS requests through the SOCKS proxy. This will protect you against DNS poisoning and ensure that false DNS entries cannot be used to censor your access.\n1. Click *OK*.\n1. Click *OK* again to close the Firefox preferences window.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n\n<a name=\"android\"></a>\n### Android ###\n1. Download Shadowsocks for Android from [Google Play](https://play.google.com/store/apps/details?id=com.github.shadowsocks). If Google Play is blocked in your country, you can [download a mirrored copy](/mirror/shadowsocks/) from this server!\n1. Launch the application.\n1. Tap the Add Profile *+* icon, second from the top-right of the screen.\n1. Select *Scan QR code*.\n1. Use your phone to scan this image, or if you are using your phone _right now_ you can choose the *Manual Settings* option and copy and paste the information from the Linux section above:\n\n   ![Shadowsocks QR code](/shadowsocks/shadowsocks-qr-code.png)\n1. Tap the round paper plane icon along the bottom-left bar.\n1. Accept the Android VPN connection warning.\n1. You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"ios\"></a>\n### iOS ###\n1. Download [Shadowrocket](https://itunes.apple.com/us/app/shadowrocket/id932747118?mt=8) and launch it.\n   > **Note:** Shadowrocket is not available in the China App Store.\n1. Tap the QR code import icon in the top-left of the screen.\n1. Use your phone to scan this image, or if you are using your phone _right now_ you can manually add a new proxy by tapping *Add Server* and using the information from the Linux section above:\n\n   ![Shadowsocks QR code](/shadowsocks/shadowsocks-qr-code.png)\n1. Toggle the connection switch located to the right of the *Not Connected* text on the *Home* tab.\n   * If this is your first time running Shadowrocket, iOS will ask you to verify that the application should have permission to add VPN configurations. Tap *Allow* and follow the instructions.\n1. You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n{%- if streisand_shadowsocks_v2ray_enabled -%}\n\n<a name=\"V2ray-plugin\"></a>\n### v2ray-plugin for unreliable/hostile networks ###\nFor users on unreliable or hostile networks (esp. experiencing quality-of-service (QOS) throttling) using the [v2ray-plugin](https://github.com/shadowsocks/v2ray-plugin) may help alleviate these issues. Further configuration of the Shadowsocks client to use the v2ray-plugin can be carried out via the following configuration:\n\n        Server: {{ streisand_ipv4_address }}\n        Port: {{ shadowsocks_server_port }}\n        Password: {{ shadowsocks_password.stdout }}\n        Encryption Method: {{ shadowsocks_encryption_method }}\n        Plugin: {{ shadowsocks_v2ray_plugin }}\n        Plugin_Options: {{ shadowsocks_v2ray_plugin_options }}\n\nAndroid users will first need to download the [V2ray-plugin](https://play.google.com/store/apps/details?id=com.github.shadowsocks.plugin.v2ray) plugin app, and then modify the existing Streisand profile on your client to use this plugin. You can do this by hitting the edit button next to the profile, tapping the `Plugin` option at the bottom of the profile and selecting the \"V2ray-plugin\" plugin from the menu. Your Shadowsocks traffic will now be obfuscated as `{{ shadowsocks_v2ray_plugin_protocol }}` traffic to `{{ shadowsocks_v2ray_cover_domain }}`.\n\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/templates/mirror-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"shadowsocks\"></a>\n### Shadowsocks ###\n\n**Linux x64**\n\n* [{{ shadowsocks_go_filename }}]({{ shadowsocks_go_href }})\n  * Somme de contrôle: *{{ shadowsocks_go_checksum }}*\n\n**Android**\n\n* [{{ shadowsocks_android_filename }}]({{ shadowsocks_android_href }})\n  * Somme de contrôle: *{{ shadowsocks_android_checksum }}*\n\n**macOS**\n\n* [{{ shadowsocks_x_ng_filename }}]({{ shadowsocks_x_ng_href }})\n  * Somme de contrôle: *{{ shadowsocks_x_ng_checksum }}*\n\n**Windows**\n\n* [{{ shadowsocks_gui_filename }}]({{ shadowsocks_gui_href }})\n  * Somme de contrôle: *{{ shadowsocks_gui_checksum }}*\n\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/templates/mirror.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"shadowsocks\"></a>\n### Shadowsocks ###\n\n**Linux x64**\n\n* [{{ shadowsocks_go_filename }}]({{ shadowsocks_go_href }})\n  * Checksum: *{{ shadowsocks_go_checksum }}*\n\n**Android**\n\n* [{{ shadowsocks_android_filename }}]({{ shadowsocks_android_href }})\n  * Checksum: *{{ shadowsocks_android_checksum }}*\n\n**macOS**\n\n* [{{ shadowsocks_x_ng_filename }}]({{ shadowsocks_x_ng_href }})\n  * Checksum: *{{ shadowsocks_x_ng_checksum }}*\n\n**Windows**\n\n* [{{ shadowsocks_gui_filename }}]({{ shadowsocks_gui_href }})\n  * Checksum: *{{ shadowsocks_gui_checksum }}*\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/templates/shadowsocks-libev.default.j2",
    "content": "# Defaults for shadowsocks systemd service\n# See /lib/systemd/system/shadowsocks-libev.service\n# installed by Streisand from template\n\n# Configuration file\nCONFFILE=\"{{ shadowsocks_location }}/config.json\"\n\n# Extra command line arguments\nDAEMON_ARGS=\"{{ shadowsocks_daemon_args }}\"\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/templates/shadowsocks-libev.service.j2",
    "content": "[Service]\nPrivateTmp=true\nRestart=on-failure\nRestartSec=5s\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/vars/main.yml",
    "content": "---\nshadowsocks_location: \"/etc/shadowsocks-libev\"\nshadowsocks_password_file: \"{{ shadowsocks_location }}/shadowsocks-password.txt\"\n\n# V2ray-plugin\ngo_path: \"{{ ansible_env.HOME }}/go\"\nv2ray_github: \"github.com/shadowsocks/v2ray-plugin\"\nv2ray_core_github: \"https://github.com/v2ray/v2ray-core\"\nv2ray_location: \"{{ go_path }}/bin\"\nv2ray_options: \"server;host={{ shadowsocks_v2ray_cover_domain }}\"\n\n# Add -v for verbose mode to help with debugging\nshadowsocks_daemon_args: \"-u\"\n\nshadowsocks_gateway_location: \"{{ streisand_gateway_location }}/shadowsocks\"\n\nshadowsocks_qr_code: \"{{ shadowsocks_gateway_location }}/shadowsocks-qr-code.png\"\n\nshadowsocks_systemd_service_path: \"/etc/systemd/system/shadowsocks-libev.service.d\"\n"
  },
  {
    "path": "playbooks/roles/shadowsocks/vars/mirror.yml",
    "content": "---\n# Shadowsocks Download variables\n# ------------------------------\nshadowsocks_mirror_location: \"{{ streisand_mirror_location }}/shadowsocks\"\nshadowsocks_mirror_href_base: \"/mirror/shadowsocks\"\n\n# Android\nshadowsocks_android_version: \"4.3.2\"\nshadowsocks_android_filename: \"shadowsocks-nightly-{{ shadowsocks_android_version }}.apk\"\nshadowsocks_android_href: \"{{ shadowsocks_mirror_href_base }}/{{ shadowsocks_android_filename }}\"\nshadowsocks_android_url: \"https://github.com/shadowsocks/shadowsocks-android/releases/download/v{{ shadowsocks_android_version }}/shadowsocks-nightly-{{ shadowsocks_android_version }}.apk\"\nshadowsocks_android_checksum: \"sha256:333833ed934a22767e19ebf468f51e59fff16f9d12ca2cf223b8d1e0eedd5895\"\n\n# Windows\nshadowsocks_gui_version: \"4.1.9.2\"\nshadowsocks_gui_filename: \"Shadowsocks-{{ shadowsocks_gui_version }}.zip\"\nshadowsocks_gui_href: \"{{ shadowsocks_mirror_href_base }}/{{ shadowsocks_gui_filename }}\"\nshadowsocks_gui_url: \"https://github.com/shadowsocks/shadowsocks-windows/releases/download/{{ shadowsocks_gui_version }}/{{ shadowsocks_gui_filename }}\"\nshadowsocks_gui_checksum: \"sha256:7a52b4827a4dac14ccd0c8a05a46c7debafca33672285e7630ee8f8e54387738\"\n\n# macOS\nshadowsocks_x_ng_version: \"1.9.4\"\nshadowsocks_x_ng_filename: \"ShadowsocksX-NG.{{ shadowsocks_x_ng_version }}.zip\"\nshadowsocks_x_ng_href: \"{{ shadowsocks_mirror_href_base }}/{{ shadowsocks_x_ng_filename }}\"\nshadowsocks_x_ng_url: \"https://github.com/shadowsocks/ShadowsocksX-NG/releases/download/v{{ shadowsocks_x_ng_version }}/{{ shadowsocks_x_ng_filename }}\"\nshadowsocks_x_ng_checksum: \"sha256:dc06a995b63f8e32be9b86c265fd2979a6d73d4742d0ff16e1b2bb8f538d77a3\"\n\n# Linux (x64)\n# NOTE(@cpu): if 32bit Linux clients are to be supported then we should add `shadowsocks2-linux-x86.gz`\nshadowsocks_go_version: \"0.0.9\"\nshadowsocks_go_filename: \"shadowsocks2-linux-x64.gz\"\nshadowsocks_go_href: \"{{ shadowsocks_mirror_href_base }}/{{ shadowsocks_go_filename }}\"\nshadowsocks_go_url: \"https://github.com/riobard/go-shadowsocks2/releases/download/v{{ shadowsocks_go_version }}/{{ shadowsocks_go_filename }}\"\nshadowsocks_go_checksum: \"sha256:9c08118a0caa60acdb6764112fd181513dbaa2c85d63e7b4b333895b7fe225e9\"\n\nshadowsocks_download_urls:\n  - { url: \"{{ shadowsocks_android_url }}\", checksum: \"{{ shadowsocks_android_checksum }}\" }\n  - { url: \"{{ shadowsocks_gui_url }}\",     checksum: \"{{ shadowsocks_gui_checksum }}\" }\n  - { url: \"{{ shadowsocks_x_ng_url }}\",    checksum: \"{{ shadowsocks_x_ng_checksum }}\" }\n  - { url: \"{{ shadowsocks_go_url }}\",      checksum: \"{{ shadowsocks_go_checksum }}\" }\n"
  },
  {
    "path": "playbooks/roles/ssh/defaults/main.yml",
    "content": "---\nssh_port: 22\n"
  },
  {
    "path": "playbooks/roles/ssh/files/sshd_config",
    "content": "# Adapted from the \"Modern\" configuration detailed on the Mozilla Security\n# Guidelines wiki (https://wiki.mozilla.org/Security/Guidelines/OpenSSH).\n#\n# Three notable changes were made from that initial configuration:\n# 1) All logs are disabled.\n# 2) Root logins are allowed. This is the default way that most users\n#    connect to a new VPS. Brute-force attacks against the root user\n#    are mitigated because public-key authentication is required.\n# 3) PAM support is enabled.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this file,\n# You can obtain one at http://mozilla.org/MPL/2.0/.\n\n# Supported HostKey algorithms by order of preference.\nHostKey /etc/ssh/ssh_host_ed25519_key\nHostKey /etc/ssh/ssh_host_rsa_key\nHostKey /etc/ssh/ssh_host_ecdsa_key\n\nKexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256\n\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr\n\nMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com\n\n# Password based logins are disabled - only public key based logins are allowed.\nAuthenticationMethods publickey\nPermitRootLogin Yes\n\n# Disable logging.\nLogLevel QUIET\n\n# Ensure that logging is disabled for SFTP connections as well.\nSubsystem sftp  /usr/lib/openssh/sftp-server -f AUTHPRIV -l QUIET\n\n# Use kernel sandbox mechanisms where possible in unprivileged processes\n# Systrace on OpenBSD, Seccomp on Linux, seatbelt on macOS/Darwin, rlimit elsewhere.\nUsePrivilegeSeparation sandbox\n\n# Enable PAM.\nPasswordAuthentication no\nChallengeResponseAuthentication no\nUsePAM yes\n"
  },
  {
    "path": "playbooks/roles/ssh/handlers/main.yml",
    "content": "---\n- name: Restart SSH\n  service:\n    name: ssh\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/ssh/tasks/main.yml",
    "content": "---\n- name: Reconfigure OpenSSH with enhanced security settings\n  copy:\n    src: sshd_config\n    dest: /etc/ssh/sshd_config\n    owner: root\n    group: root\n    mode: 0644\n  notify: Restart SSH\n\n- name: Generate a stronger RSA host key\n  shell: \"rm {{ ssh_rsa_host_private_key }} {{ ssh_rsa_host_public_key }} && ssh-keygen -h -t rsa -b {{ ssh_rsa_host_key_size }} -f {{ ssh_rsa_host_private_key }} -N '' && touch {{ ssh_rsa_host_key_change_verification }}\"\n  args:\n    creates: \"{{ ssh_rsa_host_key_change_verification }}\"\n    warn: no\n  notify: Restart SSH\n\n- name: Ensure missing host keys are generated\n  command: ssh-keygen -A\n\n- name: Register the server's SSH fingerprints\n  command: ssh-keygen -lf /etc/ssh/{{ item }}\n  register: ssh_server_fingerprints\n  with_items:\n    - ssh_host_ecdsa_key.pub\n    - ssh_host_rsa_key.pub\n"
  },
  {
    "path": "playbooks/roles/ssh/vars/main.yml",
    "content": "---\nssh_rsa_host_key_size: \"3072\"\nssh_rsa_host_key_change_verification: \"/etc/ssh/ssh_host_rsa_key_was_regenerated\"\nssh_rsa_host_private_key: \"/etc/ssh/ssh_host_rsa_key\"\nssh_rsa_host_public_key: \"{{ ssh_rsa_host_private_key }}.pub\"\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/defaults/main.yml",
    "content": "---\nssh_default_socks_port: 8080\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/tasks/docs.yml",
    "content": "---\n- name: Create the SSH Gateway directory\n  file:\n    path: \"{{ ssh_gateway_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0750\n    state: directory\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"SSH instructions\"\n    i18n_location: \"{{ ssh_gateway_location }}\"\n    input_template_name: \"instructions\"\n\n- name: Copy the SSH private key that can be used to connect as the 'forward' user to the SSH Gateway directory\n  command: cp {{ forward_location }}/.ssh/id_rsa {{ ssh_rsa_key }}\n  args:\n    creates: \"{{ ssh_rsa_key }}\"\n\n- name: Install the putty-tools package to facilitate converting the standard OpenSSH key into PuTTY's unique .ppk format\n  apt:\n    package: putty-tools\n\n- name: Convert the OpenSSH key into a PuTTY .ppk\n  command: puttygen {{ forward_location }}/.ssh/id_rsa -o {{ ssh_putty_rsa_key }}\n  args:\n    creates: \"{{ ssh_putty_rsa_key }}\"\n\n- name: Generate a SSH known hosts file\n  shell: 'ssh-keyscan {{ streisand_server_name }} {{ streisand_ipv4_address }} > {{ ssh_known_hosts }}'\n  args:\n    creates: '{{ ssh_known_hosts }}'\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/tasks/main.yml",
    "content": "---\n- name: Add the SSH forwarding user and generate a key\n  user:\n    name: forward\n    generate_ssh_key: yes\n    ssh_key_bits: \"{{ ssh_rsa_host_key_size }}\"\n    ssh_key_comment: streisand\n    home: \"{{ forward_location }}\"\n    shell: /bin/bash\n    comment: \"SSH Forwarding User\"\n\n- name: Register the forwarding user's public SSH key\n  command: cat {{ forward_location }}/.ssh/id_rsa.pub\n  register: ssh_forward_key\n  changed_when: False\n\n- name: Authorize the forward users's key for accessing the forward user\n  authorized_key:\n    user: forward\n    key: 'command=\"{{ ssh_force_command }}\" {{ ssh_forward_key.stdout }}'\n\n- name: Add the sshuttle user and generate a key\n  user:\n    name: sshuttle\n    generate_ssh_key: yes\n    ssh_key_bits: \"{{ ssh_rsa_host_key_size }}\"\n    ssh_key_comment: streisand-sshuttle\n    home: \"{{ sshuttle_location }}\"\n    shell: /bin/bash\n    comment: \"sshuttle User\"\n  when: streisand_sshuttle_enabled\n\n- name: Register the sshuttle user's public SSH key\n  command: cat {{ sshuttle_location }}/.ssh/id_rsa.pub\n  register: sshuttle_forward_key\n  changed_when: False\n  when: streisand_sshuttle_enabled\n\n- name: Authorize the sshuttle users's key for accessing the sshuttle user\n  authorized_key:\n    user: sshuttle\n    # NOTE(@cpu): Unlike the forward user the sshuttle user does not have\n    # a ssh_force_comamnd in the ssh authorized keys file. This means the\n    # sshuttle user is a *full* shell user and can SSH in. They don't have root\n    # but this is a more significant foothold on a server than is offered by the\n    # ssh fowrarding user. This is why by default Streisand no longer enables\n    # sshuttle by default.\n    key: '{{ ssh_forward_key.stdout }}'\n  when: streisand_sshuttle_enabled\n\n# Generate the gateway documentation for the SSH forward user\n- import_tasks: docs.yml\n\n# Mirror Putty for SSH forwarding from Windows\n- import_tasks: mirror.yml\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/tasks/mirror.yml",
    "content": "---\n- name: Include the SSH mirror variables\n  include_vars: mirror.yml\n\n- name: Make the directory where the SSH client mirrored files will be stored\n  file:\n    path: \"{{ ssh_mirror_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0755\n    state: directory\n\n- block:\n    - name: Mirror shuttle if enabled\n      get_url:\n        url: \"{{ sshuttle_url }}\"\n        dest: \"{{ ssh_mirror_location }}/{{ sshuttle_filename }}\"\n        checksum: \"{{ sshuttle_checksum }}\"\n        owner: www-data\n        group: www-data\n        mode: 0644\n      when: streisand_sshuttle_enabled\n\n    - include_role:\n        name: download-and-verify\n      vars:\n        project_name: \"PuTTY\"\n        project_download_baseurl: \"{{ putty_base_download_url }}\"\n        project_download_files: \"{{ putty_download_files }}\"\n        project_download_location: \"{{ ssh_mirror_location }}\"\n        project_signer_keyid: \"{{ putty_gpg_keyid }}\"\n  rescue:\n    - name: \"{{ streisand_mirror_warning }}\"\n      pause:\n        seconds: \"{{ streisand_mirror_warning_seconds }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"SSH mirror\"\n    i18n_location: \"{{ ssh_mirror_location }}\"\n    input_template_name: \"mirror\"\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/templates/instructions-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nTunnel SSH\n----------\n\n---\n* Plateformes\n  * [Windows](#windows)\n  * [Linux et macOS](#linux-and-macos)\n{% if streisand_tinyproxy_enabled %}\n  * [Android](#android)\n{% endif %}\n  * [Notes](#notes)\n\n<a name=\"windows\"></a>\n### Windows ###\n1. Téléchargez [PuTTY](/mirror/ssh/index-fr.html) et lancez-le.\n1. Allez à la section *Session*.\n1. Saisissez `{{ streisand_ipv4_address }}` pour le champ *Host Name*.\n1. Saisissez `{{ ssh_port }}` pour le chaml *Port*.\n   * Le port `443` est disponible en option de recharge si vous êtes sur un réseau qui restreint l'accès au port SSH par défaut.\n1. Allez à Connection --> Data.\n1. Saisissez `forward` dans le champ *Auto-login username*.\n1. Allez à Connection --> SSH.\n1. Cochez `Don't start a shell or command at all`.\n1. Allez à Connection --> SSH --> Tunnels.\n1. Saisissez `{{ ssh_default_socks_port }}` dans le champ *Source port*.\n1. Assurez-vous que les boutons radio `Auto` et `Dynamic` sont sélectionnés.\n1. Cliquez sur *Add* pour ajouter le tunnel. Vous devriez voir `D {{ ssh_default_socks_port }}` dans la section *Forwarded ports*.\n1. Allez à Connection --> SSH --> Auth.\n1. Téléchargez la clé privée `streisand_rsa.ppk` utilisée pour authentifier la connexion SSH. Cliquez-droit; Enregistrer la cible sous...\n   * [streisand\\_rsa.ppk](/ssh/streisand_rsa.ppk)\n1. Cliquez le bouton *Browse*.\n1. Cliquez le *PuTTY Private Key Files* menu déroulant à côté du champ *File name* et sélectionnez *All Files*.\n1. Sélectionnez le fichier `streisand_rsa.ppk` téléchargé et cliquez sur *Open*.\n1. Revenez à *Session* (le premier élément dans le menu de gauche).\n1. Saisissez `{{ streisand_server_name }}` dans la première boite *Saved Sessions* et cliques le bouton *Save*. La prochaine fois que vous lancez PuTTY, vous pouvez choisir la session et cliquer sur *Load* pour restaurer tous ces paramètres.\n1. Cliquez *Open* pour vous connecter! PuTTY vous demandera de confirmer l'empreinte digitale. Vérifiez que les empreintes numériques correspondent à l'un des éléments ci-dessous:\n\n   `{{ ssh_server_fingerprints.results[0].stdout }}`\n\n   `{{ ssh_server_fingerprints.results[1].stdout }}`\n\n\nVous êtes maintenant connecté à un proxy SOCKS qui est prêt à transférer votre trafic chiffré via SSH. L'étape suivante consiste à configurer votre navigateur Web pour l'utiliser.\n\n#### Configuration de Firefox pour se connecter via un proxy SOCKS ####\n1. Cliquez sur le bouton *Menu* à côté de l'icône *Accueil* à droite de la barre d'adresse.\n1. Cliquez *Paramètres*.\n1. Cliquez l'icône *Avancé*.\n1. Allez à l'onglet *Réseau*.\n1. Cliquez le bouton *Paramètres* pour *Configurer la façon dont Firefox se connecte à Internet*.\n1. Choisissez *Configuration manuelle de proxy*.\n1. Saisissez `127.0.0.1` et port `{{ ssh_default_socks_port }}` pour la ligne *Hôte SOCKS*.\n1. Sélectionnez *Utiliser un DNS distant lorsque SOCKS v5 est actif*. Cela configure Firefox pour envoyer toutes les requêtes DNS via le proxy SOCKS. Cela vous protégera contre l'empoisonnement du DNS et vous garantira que les fausses entrées DNS ne peuvent pas être utilisées pour censurer votre accès.\n1. Cliquez *OK*.\n1. Cliquez *OK* encore pour fermer la fenêtre de paramètres de Firefox..\n1. C'est tout! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n<a name=\"linux-and-macos\"></a>\n### Linux et macOS ###\n\n#### sshuttle ####\n\nSshuttle est une simple solution de tunneling VPN qui fonctionne sur le transport SSH. C'est rapide, facile à installer et offre de bonnes performances.\n\n1. Téléchargez la clé privée `streisand_rsa` qui sert à authentifier la connexion SSH:\n   * [streisand\\_rsa](/ssh/streisand_rsa)\n1. Copiez le fichier `streisand_rsa` dans une répertoire de votre choix.\n1. Définissez les autorisations correctes sur le fichier clé RSA:\n   * `chmod 600 streisand_rsa`\n1. Ajoutez une nouvelle entrée à votre fichier `.ssh / config`. Il devrait ressembler à ceci.Le port `443` est disponible en option de recharge si vous êtes sur un réseau qui restreint l'accès au port SSH par défaut. Assurez-vous d'ajuster l'emplacement du IdentityFile:\n\n         Host {{ streisand_server_name }}\n           User           sshuttle\n           Port           {{ ssh_port }}\n           HostName       {{ streisand_ipv4_address }}\n           IdentitiesOnly yes\n           IdentityFile   ~/.ssh/streisand_rsa\n\n1. Téléchargez [sshuttle](https://github.com/sshuttle/sshuttle) en exécutant la commande suivante dans une répertoire de votre choix:\n\n  `git clone https://github.com/sshuttle/sshuttle.git`\n\n  * Si l'accès à GitHub a été bloqué, vous pouvez télécharger une copie en miroir [içi](/mirror/ssh/index-fr.html)!\n  * sshuttle est également disponible via [Homebrew](http://brew.sh/) pour les utilisateurs de OS X: `brew install sshuttle`\n\n1. Entrer dans la répertoire:\n\n   `cd sshuttle`\n1. Exécutez sshuttle et connectez-vous au serveur:\n\n   `./run --dns -r sshuttle@{{ streisand_server_name }} 0/0 -vv`\n1. Vérifiez que les empreintes numériques correspondent à l'un des éléments ci-dessous:\n\n   `{{ ssh_server_fingerprints.results[0].stdout }}`\n\n   `{{ ssh_server_fingerprints.results[1].stdout }}`\n1. Tout votre trafic, y compris DNS, est maintenant transmis de manière transparente via une connexion SSH cryptée. Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{ streisand_ipv4_address }}*.\n\n#### SSH forward ####\n\n1. Téléchargez la clé privée `streisand_rsa` qui sert à authentifier la connexion SSH:\n   * [streisand\\_rsa](/ssh/streisand_rsa)\n1. Copiez le fichier `streisand_rsa` dans une répertoire de votre choix.\n1. Ajoutez une nouvelle entrée à votre fichier `.ssh / config`. Il devrait ressembler à ceci.Le port `443` est disponible en option de recharge si vous êtes sur un réseau qui restreint l'accès au port SSH par défaut. Assurez-vous d'ajuster l'emplacement du IdentityFile:\n\n         Host {{ streisand_server_name }}\n           User           forward\n           Port           {{ ssh_port }}\n           HostName       {{ streisand_ipv4_address }}\n           IdentitiesOnly yes\n           IdentityFile   ~/.ssh/streisand_rsa\n\n1. `SSH`ez dans le serveur et transférer un port SOCKS dynamique:\n\n   `ssh -vND {{ ssh_default_socks_port }} forward@{{ streisand_server_name }}`\n1. Vérifiez que les empreintes numériques correspondent à l'un des éléments ci-dessous:\n\n   `{{ ssh_server_fingerprints.results[0].stdout }}`\n\n   `{{ ssh_server_fingerprints.results[1].stdout }}`\n1. Vous êtes maintenant connecté à un proxy SOCKS qui est prêt à transférer votre trafic chiffré via SSH. L'étape suivante consiste à configurer votre navigateur Web pour l'utiliser. Vous pouvez suivre les mêmes instructions contenues dans la section Windows ci-dessus pour configurer Firefox pour acheminer son trafic via le proxy SOCKS.\n\n{% if streisand_tinyproxy_enabled %}\n<a name=\"android\"></a>\n### Android ###\n1. Installez [SSH persistent tunnels](https://play.google.com/store/apps/details?id=org.ayal.SPT&hl=fr) par Shai Ayal. Cette application permet de transférer facilement plusieurs ports via un tunnel SSH, et fonctionne assez bien pour s'assurer que les tunnels restent actifs même lorsque vous changez régulièrement entre LTE, 3G et WiFi. L'application est [open source](https://bitbucket.org/ayal_org/ssh-persistent-tunnel/) et peut être compilée gratuitement, mais la version Play Store coûte $1,50 (USD).\n1. Téléchargez la clé privée `streisand_rsa` qui sert à authentifier la connexion SSH:\n   * [streisand\\_rsa](/ssh/streisand_rsa)\n1. Copiez le fichier `streisand_rsa` dans une répertoire de votre choix.\n1. Démarrez l'application. Il sera répertorié comme *SPT* dans votre lanceur, et son icône ressemble à un tunnel de train.\n1. Tapez sur l'icône du menu en bas à droite de votre écran.\n1. Tapez *Settings*.\n1. Tapez *Host name* et saisissez `{{ streisand_ipv4_address }}`.\n1. Tapez *User Name* et saisissez `forward`.\n1. Tapez *Port* et saisissez `{{ ssh_port }}`.\n   * Le port `443` est disponible en option de recharge si vous êtes sur un réseau qui restreint l'accès au port SSH par défaut.\n1. Tapez *Private Key File* et sélectionnez le fichier `streisand_rsa` que vous avez copié sur votre téléphone.\n1. Tapez *Dynamic Forward Port* et saisissez `1080`.\n1. Tapez *Forwards* et saisissez `L8888=localhost:8888`.\n1. Retourner et tapez le bouton *Connect Tunnel*.\n1. Vérifiez que les empreintes numériques correspondent à l'un des éléments ci-dessous:\n\n   `{{ ssh_server_fingerprints.results[0].stdout }}`\n\n   `{{ ssh_server_fingerprints.results[1].stdout }}`\n\nVous êtes maintenant prêt à configurer vos applications pour acheminer leur trafic via le tunnel SSH fourni par SPT.\n\n#### Configuration d'Android pour acheminer la plupart du trafic via SPT ####\nCes étapes ne fonctionneront que si vous êtes connecté via WiFi. Ils doivent également être appliqués individuellement sur tous les réseaux WiFi auxquels vous vous connectez. La plupart des applications respecteront ces paramètres, y compris le navigateur par défaut, Chrome, YouTube et bien d'autres.\n\n1. Ouvrez les paramètres de votre téléphone.\n2. Tapez *Wi-Fi* dans la section *Sans fil et réseaux*.\n3. Appuyez longuement sur le réseau WiFi auquel vous êtes actuellement connecté. Un menu contextuel apparaîtra.\n4. Tapez *Modifier le réseau*.\n5. Tapez *Options avancées*.\n6. Sélectionnez *Manuel* dans la section proxy.\n7. Tapez *Nom d'hôte du proxy* et saisissez `127.0.0.1`.\n8. Tapez *Port du proxy* et saisissez `8888`.\n9. Tapez *Enregistrer*.\n\nCertaines applications vous permettent de rendre ces paramètres persistants pour tous les réseaux. Twitter pour Android et Firefox pour Android peut acheminer son trafic via le tunnel SPT SSH indépendamment de votre connexion actuelle (WiFi, 3G, HSPA +, LTE, etc.).\n\n#### Configuration de Twitter pour Android pour utiliser SPT ####\n1. Ouvrez Twitter.\n2. Appuyez sur les trois points en haut à droite de l'écran.\n3. Sélectionnez *Paramètres*.\n4. Tapez *Général*.\n5. Tapez *Proxy*.\n6. Cocher *Activer le proxy HTTP*.\n7. Tapez *Hôte du proxy* et saisissez `127.0.0.1`.\n8. Tapez *Port du proxy* et saisissez `8888`.\n\n#### Configuration de Firefox pour Android pour utiliser SPT ####\n1. Ouvrez Firefox.\n2. Tapez `about:config` dans la barre d'adresse et appuyez sur le bouton 'Go' de votre clavier.\n3. Tapez `proxy` dans la barre de recherche.\n4. Définissez la valeur de *network.proxy.socks* à `127.0.0.1`.\n5. Définissez la valeur de *network.proxy.socks\\_port* à `1080`.\n6. Définissez la valeur de *network.proxy.socks\\_remote\\_dns* à `true`.\n7. Définissez la valeur de *network.proxy.type* à `1`.\n{% endif %}\n\n<a name=\"notes\"></a>\n1. Si vous voyez le message \"This account is for port forwarding only\", assurez-vous de configurer votre client SSH pour ne pas exécuter les commandes shell sur le serveur distant (`-N`).\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/templates/instructions.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nSSH Tunnel\n----------\n\n---\n* Platforms\n  * [Windows](#windows)\n  * [Linux and macOS](#linux-and-macos)\n{% if streisand_tinyproxy_enabled %}\n  * [Android](#android)\n{% endif %}\n  * [Notes](#notes)\n\n<a name=\"windows\"></a>\n### Windows ###\n1. Download [PuTTY](/mirror/ssh/) and run it.\n1. Go to the *Session* section.\n1. Enter `{{ streisand_ipv4_address }}` in the Host Name field.\n1. Enter `443` in the Port field.\n   * Port {{ ssh_port }} is available as an option if your network does not block it.\n1. Go to Connection --> Data.\n1. Enter `forward` in the *Auto-login username* field.\n1. Go to Connection --> SSH.\n1. Check `Don't start a shell or command at all`.\n1. Go to Connection --> SSH --> Tunnels.\n1. Enter `{{ ssh_default_socks_port }}` in the *Source port* field.\n1. Make sure the `Auto` and `Dynamic` radio buttons are selected.\n1. Click *Add* to add the tunnel. You should see `D{{ ssh_default_socks_port }}` in the Forwarded ports box.\n1. Go to Connection --> SSH --> Auth.\n1. Download the `streisand_rsa.ppk` private key that is used to authenticate the SSH connection. Right-click; Save target as...\n   * [streisand\\_rsa.ppk](/ssh/streisand_rsa.ppk)\n1. Click the *Browse* button.\n1. Click the *PuTTY Private Key Files* drop down next to the *File name* field and choose *All Files*.\n1. Select the downloaded `streisand_rsa.ppk` file and click *Open*.\n1. Go back to *Session* (the very first item in the left-hand menu).\n1. Enter `{{ streisand_server_name }}` in the first *Saved Sessions* box and click the *Save* button. The next time you launch PuTTY you can choose the session and click *Load* to restore all of these settings.\n1. Click *Open* to connect! PuTTY will ask you to confirm the fingerprint. Make sure it matches one of these:\n\n   `{{ ssh_server_fingerprints.results[0].stdout }}`\n\n   `{{ ssh_server_fingerprints.results[1].stdout }}`\n\n\nYou are now connected and have a SOCKS proxy up and running that is ready to forward encrypted traffic through SSH. The next step is to configure your web browser to use it.\n\n#### Configuring Firefox to connect through a SOCKS proxy ####\n1. Click the *Menu* button next to the *Home* icon to the right of the address bar.\n1. Click *Options*.\n1. Click the *Advanced* icon.\n1. Go to the *Network* tab.\n1. Click the *Settings* button to *Configure how Firefox connects to the Internet*.\n1. Choose *Manual proxy configuration*.\n1. Enter `127.0.0.1` and Port `{{ ssh_default_socks_port }}` on the *SOCKS Host* line.\n1. Select *Remote DNS*. This configures Firefox to send all DNS requests through the SOCKS proxy. This will protect you against DNS poisoning and ensure that false DNS entries cannot be used to censor your access.\n1. Click *OK*.\n1. Click *OK* again to close the Firefox preferences window.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n<a name=\"linux-and-macos\"></a>\n### Linux and macOS ###\n\n#### SSH Forwarding ####\n\n1. Download the `streisand_rsa` private key that is used to authenticate the SSH connection:\n   * [streisand\\_rsa](/ssh/streisand_rsa)\n1. Copy the `streisand_rsa` file to the directory of your choice.\n1. Set the correct permissions on the RSA key file:\n   * `chmod 600 streisand_rsa`\n1. Add a new entry to your `.ssh/config` file. It should look like this. Port {{ ssh_port }} is available if your network does not block it. Be sure to adjust the location of the IdentityFile:\n\n         Host {{ streisand_server_name }}\n           User           forward\n           Port           443\n           HostName       {{ streisand_ipv4_address }}\n           IdentitiesOnly yes\n           IdentityFile   ~/.ssh/streisand_rsa\n\n1. SSH into the server and forward a dynamic SOCKS port:\n\n   `ssh -vND {{ ssh_default_socks_port }} forward@{{ streisand_server_name }}`\n1. Verify that the fingerprint matches one of these:\n\n   `{{ ssh_server_fingerprints.results[0].stdout }}`\n\n   `{{ ssh_server_fingerprints.results[1].stdout }}`\n1. You are now connected and have a SOCKS proxy up and running that is ready to forward encrypted traffic through SSH. The next step is to configure your web browser to use it. You can follow the same instructions contained in the Windows section above to configure Firefox to route its traffic through the SOCKS proxy.\n\n{% if streisand_sshuttle_enabled %}\n#### sshuttle\n\nSshuttle is a simple VPN tunnelling solution that operates over the SSH transport. It's fast, easy to set up, and offers great performance.\n\n1. Download the `streisand_rsa` private key that is used to authenticate the SSH connection:\n   * [streisand\\_rsa](/ssh/streisand_rsa)\n1. Copy the `streisand_rsa` file to the directory of your choice.\n1. Set the correct permissions on the RSA key file:\n   * `chmod 600 streisand_rsa`\n1. Add a new entry to your `.ssh/config` file. It should look like this. Port {{ ssh_port }} is available if your network does not block it. Be sure to adjust the location of the IdentityFile:\n\n         Host {{ streisand_server_name }}\n           User           sshuttle\n           Port           443\n           HostName       {{ streisand_ipv4_address }}\n           IdentitiesOnly yes\n           IdentityFile   ~/.ssh/streisand_rsa\n\n1. Download [sshuttle](https://github.com/sshuttle/sshuttle) by running the following command in the directory of your choice:\n\n  `git clone https://github.com/sshuttle/sshuttle.git`\n\n  * If access to GitHub has been blocked, you can download a mirrored copy [here](/mirror/ssh/)!\n  * sshuttle is also available via [Homebrew](http://brew.sh/) for OS X users: `brew install sshuttle`\n\n1. Enter the directory:\n\n   `cd sshuttle`\n1. Run sshuttle and connect to the server:\n\n   `./run --dns -r sshuttle@{{ streisand_server_name }} 0/0 -vv`\n1. Verify that the fingerprint matches one of these:\n\n   `{{ ssh_server_fingerprints.results[0].stdout }}`\n\n   `{{ ssh_server_fingerprints.results[1].stdout }}`\n1. All of your traffic, including DNS, is now being transparently forwarded through an encrypted SSH connection. You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n{% endif %}\n\n{% if streisand_tinyproxy_enabled %}\n<a name=\"android\"></a>\n### Android ###\n1. Install [SSH persistent tunnels](https://play.google.com/store/apps/details?id=org.ayal.SPT) by Shai Ayal. This application makes it easy to forward multiple ports through an SSH tunnel, and it does a decent job of ensuring that the tunnels remain active even when you switch back and forth regularly between LTE, 3G, and WiFi. The app is [open source](https://code.google.com/p/ssh-persistent-tunnel/) and can be compiled for free, but the Play Store version costs $1.50.\n1. Download the `streisand_rsa` private key that is used to authenticate the SSH connection:\n   * [streisand\\_rsa](/ssh/streisand_rsa)\n1. Copy the `streisand_rsa` file to the root directory of your phone.\n1. Start the application. It will be listed as *SPT* in your launcher, and its icon looks like a train tunnel.\n1. Tap the menu icon in the lower-right of your screen.\n1. Tap *Settings*.\n1. Tap *Host name* and enter `{{ streisand_ipv4_address }}`.\n1. Tap *User Name* and enter `forward`.\n1. Tap *Port* and enter `443`.\n   * Port {{ ssh_port }} is available if your network does not block it.\n1. Tap *Private Key File* and select the `streisand_rsa` file that you copied to your phone.\n1. Tap *Dynamic Forward Port* and enter `1080`.\n1. Tap *Forwards* and enter `L8888=localhost:8888`.\n1. Go back and tap the *Connect Tunnel* button.\n1. Verify that the fingerprint matches one of these:\n\n   `{{ ssh_server_fingerprints.results[0].stdout }}`\n\n   `{{ ssh_server_fingerprints.results[1].stdout }}`\n\nYou are now ready to configure your applications to route their traffic through the SSH tunnel provided by SPT.\n\n#### Configuring Android to route most of its traffic through SPT ####\nThese steps will only work when you are connected via WiFi. They also must be applied individually to every WiFi network you connect to. Most applications will respect these settings, including the default browser, Chrome, YouTube, and many more.\n\n1. Open your phone's Settings.\n2. Tap *Wi-Fi* in the *Wireless & Networks* section.\n3. Long-press on the WiFi network you are currently connected to. A pop-up menu will appear.\n4. Tap *Modify network*.\n5. Tap *Show advanced options*.\n6. Select *Manual* in the Proxy section.\n7. Tap *Proxy hostname* and enter `127.0.0.1`.\n8. Tap *Proxy port* and enter `8888`.\n9. Tap *Save*.\n\nSome applications allow you to make these settings persistent for all networks. Twitter for Android and Firefox for Android can route their traffic through the SPT SSH tunnel regardless of your current connection (WiFi, 3G, HSPA+, LTE, etc.).\n\n#### Configuring Twitter for Android to use SPT ####\n1. Open Twitter.\n2. Tap the three dots in the upper-right of the screen to open the menu.\n3. Choose *Settings*.\n4. Tap *General*.\n5. Tap *Proxy*.\n6. Check the *Enable HTTP Proxy* checkbox.\n7. Tap *Proxy Host* and enter `127.0.0.1`.\n8. Tap *Proxy Port* and enter `8888`.\n\n#### Configuring Firefox for Android to use SPT ####\n1. Open Firefox.\n2. Type `about:config` into the address bar and tap the 'Go' button on your keyboard.\n3. Type `proxy` into the search box.\n4. Set the value of *network.proxy.socks* to `127.0.0.1`.\n5. Set the value of *network.proxy.socks\\_port* to `1080`.\n6. Set the value of *network.proxy.socks\\_remote\\_dns* to `true`.\n7. Set the value of *network.proxy.type* to `1`.\n{% endif %}\n\n<a name=\"notes\"></a>\n1. If you see the message \"This account is for port forwarding only\", make sure you configure your SSH client to not execute shell commands on remote server (`-N`).\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/templates/mirror-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"ssh\"></a>\n### SSH ###\n\n**Windows**\n\n* [{{ putty_filename }}]({{ putty_href }}) ([sig]({{ putty_sig_href }}))\n\n{% if streisand_sshuttle_enabled %}\n**Linux and OS X**\n\n* [{{ sshuttle_filename }}]({{ sshuttle_href }})\n  * Checksum: *{{ sshuttle_checksum }}*\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/templates/mirror.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"ssh\"></a>\n### SSH ###\n\n**Windows**\n\n* [{{ putty_filename }}]({{ putty_href }}) ([sig]({{ putty_sig_href }}))\n\n{% if streisand_sshuttle_enabled %}\n**Linux and OS X**\n\n* [{{ sshuttle_filename }}]({{ sshuttle_href }})\n  * Checksum: *{{ sshuttle_checksum }}*\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/vars/main.yml",
    "content": "---\nforward_location: \"/home/forward\"\nssh_force_command: \"echo 'This account is for port forwarding only.'\"\n\nsshuttle_location: \"/home/sshuttle\"\n\nssh_gateway_location: \"{{ streisand_gateway_location }}/ssh\"\n\nssh_rsa_key: \"{{ ssh_gateway_location }}/streisand_rsa\"\nssh_putty_rsa_key: \"{{ ssh_gateway_location }}/streisand_rsa.ppk\"\nssh_known_hosts: \"{{ ssh_gateway_location }}/streisand.known_hosts\"\n"
  },
  {
    "path": "playbooks/roles/ssh-forward/vars/mirror.yml",
    "content": "---\n# SSH Client Download variables\n# -----------------------------\nssh_mirror_location: \"{{ streisand_mirror_location }}/ssh\"\nssh_mirror_href_base: \"/mirror/ssh\"\n\nputty_base_download_url: \"https://the.earth.li/~sgtatham/putty/latest/w32\"\n\nputty_filename: \"putty.exe\"\nputty_sig_filename: \"{{ putty_filename }}.gpg\"\nputty_href: \"{{ ssh_mirror_href_base }}/{{ putty_filename }}\"\n# download-and-verify.yml renames files with non-standard extensions\nputty_sig_href: \"{{ ssh_mirror_href_base }}/{{ putty_filename }}.asc\"\n\nputty_gpg_keyid: \"4AE8DA82\"\nputty_download_files:\n  - { \"file\": \"{{ putty_filename }}\", \"sig\": \"{{ putty_sig_filename }}\" }\n\nsshuttle_version: \"0.78.0\"\nsshuttle_filename: \"sshuttle-{{ sshuttle_version }}.tar.gz\"\nsshuttle_href: \"{{ ssh_mirror_href_base }}/{{ sshuttle_filename }}\"\nsshuttle_url: \"https://codeload.github.com/sshuttle/sshuttle/tar.gz/v{{ sshuttle_version }}\"\nsshuttle_checksum: \"sha256:0742e3e670c8df629ae702a32cfad96c7c4e8f7ab8f66c26d94c55d42b01e4b4\"\n"
  },
  {
    "path": "playbooks/roles/sslh/handlers/main.yml",
    "content": "---\n- name: Restart sslh\n  systemd:\n    name: sslh.service\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/sslh/tasks/main.yml",
    "content": "---\n- name: Install sslh\n  apt:\n    package: sslh\n    install_recommends: false\n\n- name: Generate the sslh port multiplexer systemd defaults file\n  template:\n    src: sslh.default.j2\n    dest: /etc/default/sslh\n  notify: Restart sslh\n\n- name: Generate the sslh port multiplexer config file\n  template:\n    src: sslh.cfg.j2\n    dest: /etc/sslh.cfg\n  notify: Restart sslh\n\n- name: Create the sslh systemd drop-in configuration directory\n  file:\n    path: \"{{ sslh_systemd_service_path }}\"\n    state: directory\n\n- name: Generate the sslh systemd drop-in service file\n  template:\n    src: sslh.service.j2\n    dest: \"{{ sslh_systemd_service_path }}/10-restart-failure.conf\"\n    mode: 0644\n\n- name: Enable the sslh service\n  systemd:\n    daemon_reload: yes\n    name: sslh.service\n    enabled: yes\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/sslh/templates/sslh.cfg.j2",
    "content": "verbose: false;\nforeground: true;\ntimeout: 5;\nuser: \"sslh\";\npidfile: \"{{ sslh_pid_file }}\";\n\nlisten:\n(\n    { host: \"{{ ansible_default_ipv4.address }}\"; port: \"443\"; }\n);\n\nprotocols:\n(\n     { name: \"ssh\";     host: \"127.0.0.1\"; port: \"{{ ssh_port }}\";     probe: \"builtin\"; fork: true; },\n     { name: \"tls\";     host: \"127.0.0.1\"; port: \"{{ nginx_port}}\";    probe: \"builtin\"; },\n{% if streisand_openvpn_enabled %}\n     { name: \"openvpn\"; host: \"127.0.0.1\"; port: \"{{ openvpn_port }}\"; probe: \"builtin\"; },\n{% endif %}\n     { name: \"anyprot\"; host: \"127.0.0.1\"; port: \"{{ nginx_port }}\";   probe: \"builtin\"; }\n);\n\non-timeout: \"tls\";\n"
  },
  {
    "path": "playbooks/roles/sslh/templates/sslh.default.j2",
    "content": "# Default options for sslh initscript\n# sourced by /etc/init.d/sslh\n\nRUN=yes\n\nDAEMON=/usr/sbin/sslh\n\nDAEMON_OPTS=\"-F /etc/sslh.cfg\"\n"
  },
  {
    "path": "playbooks/roles/sslh/templates/sslh.service.j2",
    "content": "[Service]\nPrivateTmp=true\nStandardOutput=null\nRestartSec=5s\nRestart=on-failure\nPIDFile={{ sslh_pid_file }}\n"
  },
  {
    "path": "playbooks/roles/sslh/vars/main.yml",
    "content": "---\nsslh_pid_file: \"/var/run/sslh/sslh.pid\"\nsslh_systemd_service_path: \"/etc/systemd/system/sslh.service.d\"\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/defaults/main.yml",
    "content": "---\nnginx_key_country:  \"US\"\nnginx_key_province: \"California\"\nnginx_key_city: \"Malibu\"\nnginx_key_org: \"Streisand\"\nnginx_key_ou: \"Streisand Effect Department\"\n\nnginx_port: \"443\"\n\nstreisand_gateway_username: \"streisand\"\nstreisand_gateway_rsa_key_size: \"3072\"\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/handlers/main.yml",
    "content": "---\n- name: Restart Nginx for the Gateway vhost\n  service:\n    name: nginx\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/meta/main.yml",
    "content": "---\ndependencies:\n  - { role: nginx }\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/tasks/docs.yml",
    "content": "---\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"Gateway index\"\n    i18n_location: \"{{ streisand_gateway_location }}\"\n    input_template_name: \"index\"\n\n- name: Ensure the Streisand temporary gateway directory exists\n  file:\n    path: \"{{ streisand_temp_gateway_path }}\"\n    owner: root\n    group: root\n    mode: 0600\n    state: directory\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"Gateway {{ doc.template }}\"\n    i18n_location: \"{{ streisand_temp_gateway_path }}\"\n    input_template_name: \"{{ doc.template }}\"\n    output_file_name: \"{{ doc.output_file }}\"\n  with_items:\n    - { template: \"instructions\", output_file: \"{{ streisand_server_name }}\" }\n    - { template: \"firewall\", output_file: \"{{ streisand_server_name }}-firewall-information\" }\n  loop_control:\n    loop_var: \"doc\"\n    label: \"{{ doc.template }}\"\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/tasks/fetch-and-cleanup.yml",
    "content": "---\n- name: Find the files to fetch from the Streisand temporary gateway directory\n  find:\n    paths: \"{{ streisand_temp_gateway_path }}\"\n    recurse: no\n    pattern: \"*.html\"\n  register: gateway_local_files\n\n- name: Fetch the local Gateway files\n  fetch:\n    dest: ../{{ streisand_local_directory }}/\n    src: \"{{ file.path }}\"\n    flat: yes\n  with_items: \"{{ gateway_local_files.files }}\"\n  loop_control:\n    loop_var: file\n    label: \"{{ file.path }}\"\n\n- name: Delete the Streisand temporary gateway directory\n  file:\n    path: \"{{ streisand_temp_gateway_path }}\"\n    state: \"absent\"\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/tasks/main.yml",
    "content": "---\n# Use OpenSSL to generate self-signed certificates if we do not have Let's Encrypt.\n- import_tasks: openssl.yml\n  when: not le_ok\n\n# Include Let's Encrypt variables for template rendering\n- include_vars: ../../lets-encrypt/vars/main.yml\n\n- name: Generate a random Gateway password\n  shell: \"{{ streisand_word_gen.gateway | trim }} > {{ streisand_gateway_password_file }}\"\n  args:\n    creates: \"{{ streisand_gateway_password_file }}\"\n\n- name: Register the Gateway password\n  command: cat {{ streisand_gateway_password_file }}\n  register: streisand_gateway_password\n  changed_when: False\n\n- name: Install the required package for the htpasswd command\n  apt:\n    package: apache2-utils\n\n- name: Generate the htpasswd file\n  command: htpasswd -b -c {{ streisand_gateway_htpasswd_file }} {{ streisand_gateway_username }} {{ streisand_gateway_password.stdout }}\n  args:\n    creates: \"{{ streisand_gateway_htpasswd_file }}\"\n\n- name: Set permissions on the unhashed Gateway password file\n  file:\n    path: \"{{ streisand_gateway_password_file }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Copy the Streisand gateway password file locally\n  fetch:\n    src: \"{{ streisand_gateway_password_file }}\"\n    dest: \"{{ streisand_gateway_password_localpath }}\"\n    fail_on_missing: yes\n    flat: yes\n  when: streisand_client_test\n\n- name: Generate the virtual host and restart Nginx if it is updated\n  template:\n    src: vhost.j2\n    dest: /etc/nginx/sites-available/streisand\n    owner: root\n    group: root\n    mode: 0644\n  notify: Restart Nginx for the Gateway vhost\n\n- name: Enable the virtual host\n  file:\n    path: /etc/nginx/sites-enabled/streisand\n    src: /etc/nginx/sites-available/streisand\n    state: link\n\n  # TODO:\n  #   Add to CI testing https://github.com/StreisandEffect/streisand/issues/643\n- block:\n    - name: Keep a copy of our diagnostics on the server\n      copy:\n        src: ../../../../streisand-diagnostics.md\n        dest: \"{{ streisand_gateway_location }}/streisand-diagnostics.md\"\n\n    # generate the streisand server instructions and documentation\n    - include_tasks: docs.yml\n\n    # fetch and clean up\n    - include_tasks: fetch-and-cleanup.yml\n\n    - name: Ensure that all of the files in the Gateway have the proper permissions\n      file:\n        path: \"{{ streisand_gateway_location }}\"\n        owner: www-data\n        group: www-data\n        mode: 0750\n        state: directory\n        recurse: yes\n\n    - meta: flush_handlers\n\n    - block:\n        - name: Success!\n          pause:\n            prompt: \"Server setup is complete. The `{{ streisand_server_name }}.html` instructions file in the generated-docs folder is ready to give to friends, family members, and fellow activists. Press Enter to continue.\"\n\n        - name: Attempt to open the instructions on Linux (if applicable). Errors in this task are ignored because the `xdg-open` command is not always available.\n          local_action: command xdg-open ../{{ streisand_local_directory }}/{{ streisand_server_name }}.html\n          ignore_errors: yes\n          when: hostvars['127.0.0.1']['ansible_system'] == \"Linux\"\n          become: no\n\n        - name: Open the instructions on macOS (if applicable)\n          local_action: command open ../{{ streisand_local_directory }}/{{ streisand_server_name }}.html\n          when: hostvars['127.0.0.1']['ansible_system'] == \"Darwin\"\n          become: no\n      when: not streisand_noninteractive\n  when: not streisand_ci\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/tasks/openssl.yml",
    "content": "- name: Make the necessary directories for the certificate authority\n  file:\n    path: \"{{ item }}\"\n    owner: root\n    group: root\n    mode: 0750\n    state: directory\n  with_items:\n    - \"{{ openssl_ca_base }}\"\n    - \"{{ openssl_ca_private_dir }}\"\n    - \"{{ openssl_ca_newcerts_dir }}\"\n\n- name: Generate a local openssl.cnf\n  template:\n    src: openssl-local.cnf.j2\n    dest: \"{{ openssl_ca_base }}/openssl-local.cnf\"\n\n- name: Create private key and self-signed certificate for Nginx Certificate Authority.\n  command:\n    openssl req -new -nodes -x509\n    -config \"{{ openssl_ca_base }}/openssl-local.cnf\"\n    -days {{ nginx_days_valid }}\n    -extensions v3_ca\n    -newkey rsa:{{ streisand_gateway_rsa_key_size }}\n    -keyout {{ openssl_ca_key }}\n    -out {{ openssl_ca_certificate }}\n    -subj \"/C={{ nginx_key_country }}/ST={{ nginx_key_province }}/L={{ nginx_key_city }}/O={{ nginx_key_org }}/OU={{ nginx_key_ou }}/CN=Streisand {{ streisand_ipv4_address }} Root CA\"\n  args:\n    creates: \"{{ openssl_ca_certificate }}\"\n\n- name: Create a certificate signing request for a leaf certificate issued by the Nginx CA\n  command:\n    openssl req -new -nodes\n    -config \"{{ openssl_ca_base }}/openssl-local.cnf\"\n    -days {{ nginx_days_valid }}\n    -newkey rsa:{{ streisand_gateway_rsa_key_size }}\n    -keyout {{ nginx_private_key }}\n    -out {{ nginx_self_signed_certificate_request }}\n    -reqexts v3_ca_req\n    -subj \"/C={{ nginx_key_country }}/ST={{ nginx_key_province }}/L={{ nginx_key_city }}/O={{ nginx_key_org }}/OU={{ nginx_key_ou }}/CN=Streisand at {{ streisand_ipv4_address }}\"\n  args:\n    creates: \"{{ nginx_self_signed_certificate_request }}\"\n\n- name: Set permissions on the SSL private key\n  file:\n    path: \"{{ nginx_private_key }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Seed a blank database file that will be used when generating the self-signed certificate\n  file:\n    path: \"{{ openssl_ca_base }}/index.txt\"\n    state: touch\n\n- name: Process certificate signing request with the Nginx CA to create leaf certificate\n  command:\n    openssl ca\n    -batch\n    -create_serial\n    -config \"{{ openssl_ca_base }}/openssl-local.cnf\"\n    -extensions v3_req\n    -days {{ nginx_days_valid }}\n    -in {{ nginx_self_signed_certificate_request }}\n    -out {{ nginx_self_signed_certificate }}\n  args:\n    creates: \"{{ nginx_self_signed_certificate }}\"\n\n- name: Remove the CA private key. It has signed its first and last certificate.\n  file:\n    path: \"{{ openssl_ca_key }}\"\n    state: absent\n\n- name: Register MITM mitigation fact (leaf certificate serial number)\n  command:\n    openssl x509\n    -in {{ nginx_self_signed_certificate }}\n    -noout\n    -serial\n  register: ssl_certificate_serial_number\n\n- name: Register more MITM mitigation facts (fingerprints)\n  command:\n    openssl x509\n    -{{ item }}\n    -in {{ nginx_self_signed_certificate }}\n    -noout -fingerprint\n  with_items:\n    - sha256\n    - sha1\n    - md5\n  register: ssl_certificate_fingerprints\n\n- name: Convert the CA certificate into the right format for a data uri\n  command: base64 --wrap=0 {{ openssl_ca_certificate }}\n  register: streisand_certificate_data_uri\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/templates/firewall-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nInformations à propos du pare-feu\n---------------------------------\n\nCes ports sont ouverts par défaut lorsque Streisand crée un nouveau serveur à partir de zéro sur un fournisseur soutenu.\n\nSi vous installez Streisand sur un serveur existant ou un fournisseur alternatif, vous devez vous assurer que le pare-feu autorise les ports suivants:\n\n---\n* Nginx (Passerelle Streisand)\n  * TCP - {{ nginx_port }}\n{% if streisand_le_enabled %}\n* HTTP (Let's Encrypt)\n  * TCP - {{ le_port }}\n{% endif %}\n{% if streisand_openconnect_enabled %}\n* OpenConnect / Cisco AnyConnect\n  * TCP - {{ ocserv_port }}\n  * UDP - {{ ocserv_port }}\n{% endif %}\n* OpenSSH\n  * TCP - {{ ssh_port }}\n{% if streisand_openvpn_enabled %}\n* OpenVPN\n  * UDP - 53 de/à `{{ dnsmasq_openvpn_tcp_ip }}`\n  * UDP - 53 de/à `{{ dnsmasq_openvpn_udp_ip }}`\n    * Dnsmasq écoute le trafic DNS sur ces adresses IP et répond aux requêtes des clients OpenVPN connectés.\n  * TCP - {{ openvpn_port }}\n  * UDP - {{ openvpn_port_udp }}\n{% if streisand_stunnel_enabled %}\n* stunnel\n  * TCP - {{ stunnel_remote_port }}\n{% endif %}\n{% endif %}\n{% if streisand_shadowsocks_enabled %}\n* Shadowsocks\n  * TCP - {{ shadowsocks_server_port }}\n  * UDP - {{ shadowsocks_server_port }}\n{% endif %}\n{% if streisand_tor_enabled %}\n* Tor\n  * TCP - {{ tor_orport }} - Pont\n  * TCP - {{ tor_obfs4_port }} - obfs4 transport enfichable\n{% endif %}\n{% if streisand_wireguard_enabled %}\n* WireGuard\n  * UDP - 53 de/à `{{ dnsmasq_wireguard_ip }}`\n    * Dnsmasq écoute le trafic DNS sur cette IP et répond aux requêtes des clients WireGuard connectés.\n  * UDP - {{ wireguard_port }}\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/templates/firewall.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nFirewall Information\n--------------------\n\nThese ports are open by default when Streisand creates a new server from scratch on a supported provider.\n\nIf you are installing Streisand on an existing server or alternate provider then you need to make sure the firewall allows traffic to the new server on the following ports:\n\n---\n* Nginx (Streisand Gateway)\n  * TCP - {{ nginx_port }}\n{% if streisand_le_enabled %}\n* HTTP (Let's Encrypt)\n  * TCP - {{ le_port }}\n{% endif %}\n{% if streisand_openconnect_enabled %}\n* OpenConnect / Cisco AnyConnect\n  * TCP - {{ ocserv_port }}\n  * UDP - {{ ocserv_port }}\n{% endif %}\n* OpenSSH\n  * TCP - {{ ssh_port }}\n{% if streisand_openvpn_enabled %}\n* OpenVPN\n  * UDP - 53 to/from `{{ dnsmasq_openvpn_tcp_ip }}`\n  * UDP - 53 to/from `{{ dnsmasq_openvpn_udp_ip }}`\n    * Dnsmasq listens for DNS traffic on these IPs and responds to requests from connected OpenVPN clients.\n  * TCP - {{ openvpn_port }}\n  * UDP - {{ openvpn_port_udp }}\n{% if streisand_stunnel_enabled %}\n* stunnel\n  * TCP - {{ stunnel_remote_port }}\n{% endif %}\n{% endif %}\n{% if streisand_shadowsocks_enabled %}\n* Shadowsocks\n  * TCP - {{ shadowsocks_server_port }}\n  * UDP - {{ shadowsocks_server_port }}\n{% endif %}\n{% if streisand_tor_enabled %}\n* Tor\n  * TCP - {{ tor_orport }} - Bridge\n  * TCP - {{ tor_obfs4_port }} - obfs4 pluggable transport\n{% endif %}\n{% if streisand_wireguard_enabled %}\n* WireGuard\n  * UDP - 53 to/from `{{ dnsmasq_wireguard_ip }}`\n    * Dnsmasq listens for DNS traffic on this IP and responds to requests from connected WireGuard clients.\n  * UDP - {{ wireguard_port }}\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/templates/index-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nBienvenue sur le serveur passerelle **{{streisand_server_name}}** de [Streisand](https://github.com/StreisandEffect/streisand). Vous n'êtes qu'à quelques minutes d'une connexion libre et non-censurée à l'internet.\n\nInstructions de connexion\n-------------------------\n---\n\nIl existe de multiples façons de contourner la censure, et Streisand vous propose plusieurs choix et différents protocoles dans le cas où l'un d'entre eux ne marche pas.\n\n{% if streisand_openconnect_enabled %}\n* [OpenConnect/Cisco AnyConnect](/openconnect/index-fr.html)\n{% endif %}\n{% if streisand_openvpn_enabled %}\n* [OpenVPN (direct)](/openvpn/index-fr.html)\n{% if streisand_stunnel_enabled %}\n* [OpenVPN (stunnel)](/openvpn/stunnel-fr.html)\n{% endif %}\n{% endif %}\n{% if streisand_shadowsocks_enabled %}\n* [Shadowsocks](/shadowsocks/index-fr.html)\n{% endif %}\n{% if streisand_ssh_forward_enabled %}\n* [SSH](/ssh/index-fr.html)\n{% endif %}\n{% if streisand_tor_enabled %}\n* [Tor](/tor/index-fr.html)\n{% endif %}\n{% if streisand_wireguard_enabled %}\n* [WireGuard](/wireguard/index-fr.html)\n{% endif %}\n\n{% if streisand_mirrored_clients %}\nMiroirs des clients\n-------------------\n---\n\nVous pouvez télécharger le logiciel client nécessaire directement auprès de Streisand au cas où les sites officiels seraient bloqués. Ces versions pourraient être un peu dépassées (selon la configuration de ce serveur), mais elles peuvent être facilement mises à jour une fois que vous avez connecté à l'i'nternet ouvert.\n\n{% if streisand_openconnect_enabled %}\n* [OpenConnect](/mirror/openconnect/index-fr.html)\n{% endif %}\n{% if streisand_openvpn_enabled %}\n* [OpenVPN](/mirror/openvpn/index-fr.html)\n{% if streisand_stunnel_enabled %}\n* [stunnel](/mirror/stunnel/index-fr.html)\n{% endif %}\n{% endif %}\n{% if streisand_shadowsocks_enabled %}\n* [Shadowsocks](/mirror/shadowsocks/index-fr.html)\n{% endif %}\n{% if streisand_ssh_forward_enabled %}\n* [SSH](/mirror/ssh/index-fr.html)\n{% endif %}\n{% if streisand_tor_enabled %}\n* [Tor Browser Bundle](/mirror/tor/index-fr.html)\n{% endif %}\n\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/templates/index.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nWelcome to the **{{ streisand_server_name }}** [Streisand](https://github.com/StreisandEffect/streisand) Gateway server. You are only moments away from an uncensored connection to the Internet.\n\nConnection Instructions\n-----------------------\n---\n\nThere are multiple ways to bypass censorship, and Streisand provides several choices and different protocols in the event that any of them are restricted.\n\n{% if streisand_openconnect_enabled %}\n* [OpenConnect / Cisco AnyConnect](/openconnect/)\n{% endif %}\n{% if streisand_openvpn_enabled %}\n* [OpenVPN (direct)](/openvpn/)\n{% if streisand_stunnel_enabled %}\n* [OpenVPN (stunnel)](/openvpn/stunnel.html)\n{% endif %}\n{% endif %}\n{% if streisand_shadowsocks_enabled %}\n* [Shadowsocks](/shadowsocks/)\n{% endif %}\n{% if streisand_ssh_forward_enabled %}\n* [SSH](/ssh/)\n{% endif %}\n{% if streisand_tor_enabled %}\n* [Tor](/tor/)\n{% endif %}\n{% if streisand_wireguard_enabled %}\n* [WireGuard](/wireguard/)\n{% endif %}\n\n{% if streisand_mirrored_clients %}\nClient Mirrors\n--------------\n---\n\nYou can download the necessary client software directly from Streisand in case the official websites are blocked. These versions could be slightly out of date (depending on when this server was set up) but they can be easily updated once you have connected to the open Internet.\n\n{% if streisand_openconnect_enabled %}\n* [OpenConnect](/mirror/openconnect/)\n{% endif %}\n{% if streisand_openvpn_enabled %}\n* [OpenVPN](/mirror/openvpn/)\n{% if streisand_stunnel_enabled %}\n* [stunnel](/mirror/stunnel/)\n{% endif %}\n{% endif %}\n{% if streisand_shadowsocks_enabled %}\n* [Shadowsocks](/mirror/shadowsocks/)\n{% endif %}\n{% if streisand_ssh_forward_enabled %}\n* [SSH](/mirror/ssh/)\n{% endif %}\n{% if streisand_tor_enabled %}\n* [Tor Browser Bundle](/mirror/tor/)\n{% endif %}\n\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/templates/instructions-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nVotre passerelle Streisand contient des instructions étape par étape pour les services qu'elle fournit, et des miroirs de tous les logiciels clients nécessaires.\n\n{% if le_ok %}\nCe document vous montrera comment vous connecter à la passerelle afin de décrire comment configurer vos clients pour se connecter aux services fournis par Streisand.\n{% else %}\nCe document couvre les instructions d'installation du certificat SSL et vous montrera comment vous connecter à la passerelle afin de décrire comment configurer vos clients pour se connecter aux services fournis par Streisand.\n{% endif %}\n\n---\n{% if not le_ok %}\n* [Installation du certificat SSL](#ssl)\n  * [Windows](#ssl-windows)\n  * [macOS](#ssl-macos)\n  * [Android](#ssl-android)\n  * [iOS](#ssl-ios)\n  * [Chromium](#ssl-chromium)\n  * [Firefox](#ssl-firefox)\n  * [Vérification du certificat](#ssl-manual)\n{% endif %}\n* [Connexion à votre passerelle Streisand](#connecting)\n  * [SSL](#connecting-ssl)\n{% if streisand_tor_enabled %}\n  * [Service Caché Tor](#connecting-tor)\n{% endif %}\n\n\n{% if not le_ok %}\n<a name=\"ssl\"></a>\nInstallation du certificat SSL\n------------------------------\nVous devez installer le certificat SSL de la passerelle afin que votre navigateur puisse vérifier automatiquement l'intégrité de la connexion. Cela empêche quiconque de falsifier votre trafic et également protègera  vos identifiants de connexion. Le certificat a été incorporé directement dans ce fichier HTML, et vous pouvez le télécharger içi:\n<p><a download=\"{{ streisand_ipv4_address }}.crt\" id=\"download\" href=\"data:application/x-x509-ca-cert;base64,{{ streisand_certificate_data_uri.stdout }}\">Télécharger le certificat</a></p>\n\n\n<a name=\"ssl-windows\"></a>\n### Windows ###\nCes instructions fonctionnent pour Chrome et Internet Explorer. Firefox utilise son propre gestionnaire de certificats interne, mais est également [facile à configurer](#ssl-firefox).\n\n1. [Téléchargez le certificat SSL](#download) intégré dans ce document.\n1. Double-cliquez pour ouvrir le certificat téléchargé.\n1. Cliquez sur *Installer le certificat...*\n1. L'Assistant d'importation de certificat démarrera. Cliquez sur *Suivant*.\n1. Sélectionnez *Placer tous les certificats dans le magasin suivant* puis cliquez *Parcourir*.\n1. Sélectionnez *Autorités de certification racine de confiance* puis cliquez *OK*.\n1. Cliquez *Suivant* en suite *Finir*.\n1. Confirmez que vous souhaitez installer le certificat en choisissant *Oui*.\n1. Redémarrez votre navigateur Web.\n1. Vous êtes prêt à vous connecter. Voir [Connexion à votre passerelle Streisand](#connecting-ssl).\n\n\n<a name=\"ssl-macos\"></a>\n### macOS ###\nCes instructions fonctionnent pour Chrome et Safari. Firefox utilise son propre gestionnaire de certificats interne, mais est également [facile à configurer](#ssl-firefox).\n\n1. Lancez *Trousseaux d'accès*.\n1. [Téléchargez le certificat SSL](#download) intégré dans ce document.\n1. Faites glisser le certificat téléchargé dans la section de session.\n1. Faites un clic-droit et choisissez *Lire les informations*.\n1. Cliquez sur le triangle à guache de *Se fier* pour ouvrir le menu contextuelle.\n1. Choisissez l'option *Toujours approuver*  dans le menu deroulant pour le champ *(SSL) Secure Sockets Layer*.\n1. Fermer la fenêtre\n1. Une fenêtre apparaîtra qui vous demandera votre mot de passe; saissisez-le, puis cliquez sur *Mettre à jour les réglages*\n1. Vous êtes prêt à vous connecter. Voir [Connexion à votre passerelle Streisand](#connecting-ssl).\n\n\n<a name=\"ssl-android\"></a>\n### Android ###\nCes instructions fonctionnent pour Chrome Firefox pour Android utilise son propre gestionnaire de certificats interne mais ne fournit pas d'interface pour l'importation de certificats. Chrome est donc la manière recommandée de se connecter à la passerelle Streisand.\n\n#### Moins sécurisé, mais facile ####\n\n1. [Téléchargez le certificat SSL](#download) intégré dans ce document.\n1. Envoyez le certificat téléchargé par courrier électronique à un compte auquel vous pouvez accéder à partir de l'appareil Android.\n1. Ouvrez l'e-mail, puis appuyez sur la pièce jointe.\n1. Une invite apparaîtra, entez `{{ streisand_server_name }}` pour le *Nom du certificat*, et assurez-vous que *VPN et applications* est sélectionné pour la valeur de *Utilisation du certificat*.\n1. Tapez *OK*.\n1. Vous êtes prêt à vous connecter. Voir [Connexion à votre passerelle Streisand](#connecting-ssl).\n\n#### Plus sécurisé ####\n1. Connectez l'appareil Android à votre ordinateur.\n1. [Téléchargez le certificat SSL](#download) intégré dans ce document.\n1. Faites glisser le certificat téléchargé vers la racine du système de fichiers de l'appareil Android.\n1. Lancez l'application *Paramètres*.\n1. Faites défiler jusqu'à la section *Appareil* et tapez sur *Sécurité*.\n1. Faites défiler jusqu'à la section *Stockage des identifiants* et tapez *Installer depuis la carte SD*.\n1. Sélectionnez le certificat que vous avez copié sur votre téléphone.\n1. Entrez `{{ streisand_server_name }}` pour le *Nom du certificat*, et assurez-vous que *VPN et applications* est sélectionné pour la valeur de *Utilisation du certificat*.\n1. Tapez *OK*.\n1. Vous êtes prêt à vous connecter. Voir [Connexion à votre passerelle Streisand](#connecting-ssl).\n\n\n<a name=\"ssl-ios\"></a>\n### iOS ###\n#### Moins sécurisé, mais facile ####\n1. [Téléchargez le certificat SSL](#download) intégré dans ce document.\n1. Envoyez le certificat téléchargé par courrier électronique à un compte auquel vous pouvez accéder à partir de l'appareil iOS.\n1. Ouvrez l'e-mail avec l'app Mail de iOS, en suite appuyez sur la pièce jointe.\n1. L'écran *Installer le profil* apparaîtra. Vous pouvez afficher les détails du certificat et vous assurer qu'ils correspondent aux informations de la section <a href=\"#verification\">Verification SSL</a> . Tapez *Installer*.\n1. Saisissez votre code NIP.\n1. Tapez *Installer* à nouveau lorsque l'avertissement apparaît.\n1. Tapez *OK*.\n1. Vous êtes prêt à vous connecter. Voir [Connexion à votre passerelle Streisand](#connecting-ssl).\n\n<!---\nI am unable to download the app from the App Store since\nit is only available for macOS 10.12, of which I do not have currently installed.\nThis section below is a best effort. -@alimakki\n-->\n#### Plus sécurisé ####\n1. Connectez le périphérique iOS à votre ordinateur macOS.\n1. Tapez *Se fier* si l'avertissement *Faire confiance à cet ordinateur* apparaît.\n1. Installez l'utilitaire <a href=\"https://itunes.apple.com/fr/app/apple-configurator-2/id1037126344?mt=12\">Apple Configurator 2</a> depuis le Mac App Store.\n1. Lancez l'utilitaire Apple Configurator et acceptez la licence.\n1. Cliquez *Start Preparing Devices*.\n1. Cliquez *Install Profiles...*.\n1. Allumez le téléphone et déverouille-le.\n1. Cliquez *Next*.\n1. Cliquez *New...* and entrez `{{ streisand_server_name }}` dans le champ *Name* dans la section *General*.\n1. Faites défiler jusqu'à la section *Certificates*.\n1. [Téléchargez le certificat SSL](#download) intégré dans ce document.\n1. Cliquez *Configure*, sélectionnez le certificat téléchargé et cliquez sur *Open*.\n1. Cliquez *Save*.\n1. Cocher l'options à côté du profil `{{ streisand_server_name }}` que vous avez crée. Cliquez *Next*.\n1. L'écran *Installer le profile* apparaîtra sur votre appareil iOS. Tapez *Installer*.\n1. Tapez *Installer* à nouveau lorsque l'avertissement apparaît.\n1. Tapez *OK*.\n1. Vous êtes prêt à vous connecter. Voir [Connexion à votre passerelle Streisand](#connecting-ssl).\n\n\n<!--\nA best effort translation here as well.\nA review of the correct words used in context will be needed\n--@alimakki\n-->\n<a name=\"ssl-chromium\"></a>\n### Chromium ###\n1. Cliquez sur le bouton Menu et accédez à *Paramètres*.\n1. Faites défiler jusqu'au bas de la fenêtre et cliquez sur *Afficher les paramètres avancés...*\n1. Faites défiler jusqu'au la section HTTPS/SSL et cliquez *Gérer les certificats...*\n1. Accedez a l'ognlet *Autorités*.\n1. [Téléchargez le certificat SSL](#download) intégré dans ce document.\n1. Cliquez *Importer...*, sélectionnez le certificat, en suite cliquez *Ouvrir*.\n1. Une invite apparaîtra. Cochez l'option à côté de *Confiez ce certificat pour identifier les sites Web* et cliquez sur *OK*.\n1. Cliquez *OK*.\n1. Vous êtes prêt à vous connecter. Voir [Connexion à votre passerelle Streisand](#connecting-ssl).\n\n\n<a name=\"ssl-firefox\"></a>\n### Firefox ###\n1. Lancez Firefox.\n1. Ouvrez le panneau *Options*, et sélectionnez *Préférences*.\n1. Naviguez vers *Vie privée et sécurité*.\n1. Défiler jusqu'à la rubrique *Sécurité > Certificats*\n1. Cliquez sur *Afficher les certificats*.\n1. Une fenêtre apparaîtra. Cliquez sur l'onglet *Autorités*.\n1. [Téléchargez le certificat SSL](#download) intégré dans ce document.\n1. Cliquez *Importer...*, sélectionnez le certificat, en suite cliquez *Ouvrir*.\n1. Une invite apparaîtra. Cochez l'option à côté de *Confiez ce certificat pour identifier les sites Web* et cliquez sur *OK*.\n1. Cliquez *OK* pour fermer le gestionaire des ceritificats, en suite fermer le panneau de *Préférences*.\n1. Vous êtes prêt à vous connecter. Voir [Connexion à votre passerelle Streisand](#connecting-ssl).\n\n\n<a name=\"ssl-manual\"></a>\n### Verification SSL manuelle ###\n*L'option de vérification du certificat manuel est significativement moins sécurisée que l'installation du certificat en utilisant l'une des méthodes ci-dessus. Votre navigateur affichera un message d'avertissement et vous serai plus vulnérable aux [attaques de l'homme du milieu](https://fr.wikipedia.org/wiki/Attaque_de_l%27homme_du_milieu) car les empreintes digitales doivent être vérifiées lors de chaque tentative de connexion. Il devrait être utilisé avec beaucoup de soin, et seulement en dernier recours.*\n\nLes détails du certificat doivent correspondre aux informations suivantes:\n\n##### Numéro de série #####\n`{{ ssl_certificate_serial_number.stdout }}`\n\n##### Empreintes #####\n{% for fingerprint in ssl_certificate_fingerprints.results %}\n    {{ fingerprint.stdout }}\n{% endfor %}\n\nSi tout vérifie, vous êtes prêt à vous connecter. Voir [Connexion à votre passerelle Streisand](#connecting-ssl).\n{% endif %}\n\n\n<a name=\"connecting\"></a>\nConnexion à votre passerelle Streisand\n--------------------------------------\n\n<a name=\"connecting-ssl\"></a>\n### SSL ###\n{% if le_ok %}\n[{{ streisand_domain }}](https://{{ streisand_domain }}/index-fr.html)\n{% else %}\n[{{ streisand_gateway_url }}]({{ streisand_gateway_url }}/index-fr.html)\n{% endif %}\n\nusername: `{{ streisand_gateway_username }}`\npassword: `{{ streisand_gateway_password.stdout }}`\n\n{% if streisand_tor_enabled %}\n<a name=\"connecting-tor\"></a>\n### Service Caché Tor ###\n*Toutes les connexions aux services cachés Tor sont entièrement chiffrées.*\n\n[{{ tor_hidden_service_url }}]({{ tor_hidden_service_url }}/index-fr.html)\n\nusername: `{{ streisand_gateway_username }}`\npassword: `{{ streisand_gateway_password.stdout }}`\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/templates/instructions.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nYour Streisand Gateway contains step-by-step instructions for the services it provides, and mirrors of all necessary client software.\n\n{% if le_ok %}\nThis document will show you how to connect to the Gateway to learn how to configure clients to use the Streisand services.\n{% else %}\nThis document covers the SSL Certificate installation instructions and will show you how to connect to the Gateway to learn how to configure clients to use the Streisand services.\n{% endif %}\n\n---\n{% if not le_ok %}\n* [SSL Certificate Installation](#ssl)\n  * [Windows](#ssl-windows)\n  * [macOS](#ssl-macos)\n  * [Android](#ssl-android)\n  * [iOS](#ssl-ios)\n  * [Chromium](#ssl-chromium)\n  * [Firefox](#ssl-firefox)\n  * [Manual Certificate Verification](#ssl-manual)\n{% endif %}\n* [Connecting to your Streisand Gateway](#connecting)\n  * [SSL](#connecting-ssl)\n{% if streisand_tor_enabled %}\n  * [Tor Hidden Service](#connecting-tor)\n{% endif %}\n\n\n{% if not le_ok %}\n<a name=\"ssl\"></a>\nSSL Certificate Installation\n----------------------------\nYou should install the Gateway's SSL certificate so your browser can automatically verify the integrity of the connection. This prevents anyone from tampering with your traffic and also protects your login credentials. The certificate has been embedded directly into this HTML file, and you can download it here:\n<p><a download=\"{{ streisand_ipv4_address }}.crt\" id=\"download\" href=\"data:application/x-x509-ca-cert;base64,{{ streisand_certificate_data_uri.stdout }}\">Download Certificate</a></p>\n\n\n<a name=\"ssl-windows\"></a>\n### Windows ###\nThese instructions work for Chrome and Internet Explorer. Firefox uses its own internal Certificate Manager, but it's [easy to configure](#ssl-firefox) too.\n\n1. [Download the SSL certificate](#download) embedded in this document.\n1. Double-click to open the downloaded certificate.\n1. Click *Install Certificate...*\n1. The Certificate Import Wizard will start. Click *Next*.\n1. Select *Place all certificates in the following store* and click *Browse*.\n1. Select *Trusted Root Certification Authorities* and click *OK*.\n1. Click *Next* and then click *Finish*.\n1. Confirm that you would like to install the certificate by choosing *Yes*.\n1. Close and re-open your browser.\n1. You are ready to connect. See [Connecting to your Streisand Gateway](#connecting-ssl).\n\n\n<a name=\"ssl-macos\"></a>\n### macOS ###\nThese instructions work for Chrome and Safari. Firefox uses its own internal Certificate Manager, but it's [easy to configure](#ssl-firefox) too.\n\n1. Go to *Applications > Utilities* and launch *Keychain Access*.\n1. [Download the SSL certificate](#download) embedded in this document.\n1. Drag the downloaded certificate into the login keychain section.\n1. A window will appear asking if you want to trust the certificate. Click *Always Trust*.\n1. Enter your password when you are prompted to do so, and click *Update Settings*.\n1. Right-click on the imported certificate and select *Get Info*.\n1. Click the arrow next to *Trust* and more options will appear.\n1. Choose *Always Trust* next to the *Secure Sockets Layer (SSL)* option.\n1. Close the certificate window and enter your password again.\n1. You are ready to connect. See [Connecting to your Streisand Gateway](#connecting-ssl).\n\n\n<a name=\"ssl-android\"></a>\n### Android ###\nThese instructions work for Chrome. Firefox for Android uses its own internal Certificate Manager but does not provide an interface for importing certificates yet. Chrome is therefore the recommended way to connect to the Streisand Gateway.\n\n#### Less secure, but easy ####\n\n1. [Download the SSL certificate](#download) embedded in this document.\n1. Email the downloaded certificate to an account that can be accessed from the Android device.\n1. Open the email and tap the attachment.\n1. A popup will appear. Enter `{{ streisand_server_name }}` for the *Certificate name*, and make sure *VPN and apps* is selected for the *Credential use* value.\n1. Tap *OK*.\n1. You are ready to connect. See [Connecting to your Streisand Gateway](#connecting-ssl).\n\n#### More secure ####\n1. Connect the Android device to your computer.\n1. [Download the SSL certificate](#download) embedded in this document.\n1. Drag the downloaded certificate to the root of the Android device's filesystem.\n1. Launch the *Settings* application.\n1. Scroll to the *Personal* section and tap *Security*.\n1. Scroll to the *Credential Storage* section and tap *Install from storage*.\n1. Select the certificate that you copied to your phone.\n1. Enter `{{ streisand_server_name }}` for the *Certificate name*, and make sure *VPN and apps* is selected for the *Credential use* value.\n1. Tap *OK*.\n1. You are ready to connect. See [Connecting to your Streisand Gateway](#connecting-ssl).\n\n\n<a name=\"ssl-ios\"></a>\n### iOS ###\n#### Less secure, but easy ####\n1. [Download the SSL certificate](#download) embedded in this document.\n1. Email the downloaded certificate to an account that can be accessed from the iOS device.\n1. Open the email in the iOS Mail app, and tap the attachment.\n1. The *Install Profile* screen will appear. You can view the certificate details and make sure they match the information from the <a href=\"#verification\">SSL Verification</a> section. Tap *Install*.\n1. Tap *Install* again when the warning appears.\n1. Tap *Done*.\n1. You are ready to connect. See [Connecting to your Streisand Gateway](#connecting-ssl).\n\n#### More secure ####\n1. Connect the iOS device to your macOS computer.\n1. Tap *Trust* if the *Trust This Computer?* popup appears.\n1. Install the <a href=\"https://itunes.apple.com/us/app/apple-configurator-2/id1037126344?mt=12\">Apple Configurator 2</a> utility from the Mac App Store.\n1. Launch the Apple Configurator utility and agree to the license.\n1. Click *Start Preparing Devices*.\n1. Click *Install Profiles...*.\n1. Turn the phone on and unlock it.\n1. Click *Next*.\n1. Click *New...* and enter `{{ streisand_server_name }}` in the *Name* field of the *General* section.\n1. Scroll down to the *Certificates* section.\n1. [Download the SSL certificate](#download) embedded in this document.\n1. Click *Configure*, select the downloaded certificate, and click *Open*.\n1. Click *Save*.\n1. Check the checkbox next to the `{{ streisand_server_name }}` profile you just created. Click *Next*.\n1. The *Install Profile* screen will appear on your iOS device. Tap *Install*.\n1. Tap *Install* again when the warning appears.\n1. Tap *Done*.\n1. You are ready to connect. See [Connecting to your Streisand Gateway](#connecting-ssl).\n\n\n<a name=\"ssl-chromium\"></a>\n### Chromium ###\n1. Click the Menu button and go to *Settings*.\n1. Scroll to the bottom of the window and click *Show advanced settings...*\n1. Scroll to the HTTPS/SSL section and click *Manage certificates...*\n1. Go the *Authorities* tab.\n1. [Download the SSL certificate](#download) embedded in this document.\n1. Click *Import...*, select the downloaded certificate, and click *Open*.\n1. A popup will appear. Check the box next to *Trust this certificate for identifying websites* and click *OK*.\n1. Click *Done*.\n1. You are ready to connect. See [Connecting to your Streisand Gateway](#connecting-ssl).\n\n\n<a name=\"ssl-firefox\"></a>\n### Firefox ###\n1. Launch Firefox.\n1. Open the *Options* panel, and select *Preferences*.\n1. Go to the *Privacy & Security* tab.\n1. Scroll down to the *Security > Certificates* heading.\n1. Click *View Certificates*.\n1. A window will appear. Click on the *Authorities* tab.\n1. [Download the SSL certificate](#download) embedded in this document.\n1. Click *Import...*, select the downloaded certificate, and click *Open*.\n1. A popup will appear. Check the box next to *Trust this CA to identify websites* and click *OK*.\n1. Click *OK* to close the certificate manager, and then close the *Preferences* panel.\n1. You are ready to connect. See [Connecting to your Streisand Gateway](#connecting-ssl).\n\n\n<a name=\"ssl-manual\"></a>\n### Manual SSL Verification ###\n*The manual certificate verification option is significantly less secure than installing the certificate using one of the methods above. Your browser will display a warning message, and you are more vulnerable to man-in-the-middle attacks because the fingerprints must be verified on every connection attempt. It should be used with great care, and only as a last resort.*\n\nThe certificate details should match the following information:\n\n##### Serial Number #####\n`{{ ssl_certificate_serial_number.stdout }}`\n\n##### Fingerprints #####\n{% for fingerprint in ssl_certificate_fingerprints.results %}\n    {{ fingerprint.stdout }}\n{% endfor %}\n\nIf everything checks out, you are ready to connect. See [Connecting to your Streisand Gateway](#connecting-ssl).\n{% endif %}\n\n\n<a name=\"connecting\"></a>\nConnecting to your Streisand Gateway\n------------------------------------\n\n<a name=\"connecting-ssl\"></a>\n### SSL ###\n{% if le_ok %}\n[{{ streisand_domain }}](https://{{ streisand_domain }})\n{% else %}\n[{{ streisand_gateway_url }}]({{ streisand_gateway_url }})\n{% endif %}\n\nusername: `{{ streisand_gateway_username }}`\npassword: `{{ streisand_gateway_password.stdout }}`\n\n{% if streisand_tor_enabled %}\n<a name=\"connecting-tor\"></a>\n### Tor Hidden Service ###\n*All connections to Tor hidden services are fully encrypted.*\n\n[{{ tor_hidden_service_url }}]({{ tor_hidden_service_url }})\n\nusername: `{{ streisand_gateway_username }}`\npassword: `{{ streisand_gateway_password.stdout }}`\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/templates/openssl-local.cnf.j2",
    "content": "# The examples in https://github.com/stanzgy/wiki/blob/master/network/openssl-self-signed-certs-cheatsheet.md\n# were very useful in the creation of this file.\n\ndistinguished_name = req_distinguished_name\n\n[ ca ]\ndefault_ca = CA_default\n\n[ CA_default ]\n\ndir = {{ openssl_ca_base }}\ncerts = $dir\ncrl_dir = $dir\ndatabase = $dir/index.txt\nnew_certs_dir = {{ openssl_ca_newcerts_dir }}\n\ncertificate = {{ openssl_ca_certificate }}\nserial = $dir/serial\ncrl = $dir/crl.pem\nprivate_key = {{ openssl_ca_key }}\nRANDFILE = $dir/.rand\n\ncopy_extensions = copy\n\nx509_extensions = v3_ca\n\ndefault_days = {{ nginx_days_valid }}\ndefault_crl_days= 30\ndefault_md = {{ openssl_ca_default_md }}\npreserve = no\npolicy = policy_anything_including_no_cn\n\n[ policy_anything_including_no_cn ]\ncountryName = optional\nstateOrProvinceName = optional\nlocalityName = optional\norganizationName = optional\norganizationalUnitName = optional\n# This differs from the certificates role:\ncommonName = optional\nname = optional\nemailAddress = optional\n\n[ alt_names ]\nIP.0 = {{ streisand_ipv4_address }}\nDNS.0 = {{ streisand_ipv4_address }}\n\n[ req_distinguished_name ]\ncountryName = Country Name (2 letter code)\ncountryName_default = {{ nginx_key_country }}\n\nstateOrProvinceName = State or Province Name (full name)\nstateOrProvinceName_default = {{ nginx_key_province }}\n\nlocalityName = Locality Name (eg, city)\nlocalityName_default = {{ nginx_key_city }}\n\n0.organizationName = Organization Name (eg, company)\n0.organizationName_default = {{ nginx_key_org }}\n\norganizationalUnitName = Organizational Unit Name (eg, section)\norganizationalUnitName_default = {{ nginx_key_ou }}\n\ncommonName = Common Name (eg, your name or your server\\'s hostname)\ncommonName_default = STREISAND\n\n[ v3_ca ]\nbasicConstraints = CA:TRUE\n# Note: we need an EKU when we do OCSP, but don't open that can of worms yet.\n# extendedKeyUsage = OCSPSigning\n\n[ v3_ca_req ]\nbasicConstraints = CA:FALSE\nkeyUsage = digitalSignature, keyEncipherment, nonRepudiation\n\n[ v3_req ]\nbasicConstraints = CA:false\nsubjectAltName = @alt_names\nkeyUsage = digitalSignature, keyEncipherment, nonRepudiation\nextendedKeyUsage=serverAuth,clientAuth\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/templates/vhost.j2",
    "content": "# Setup an http -> https redirect\nserver {\n  listen 80;\n\n  {% if streisand_le_enabled %}\n  server_name {{ streisand_domain }};\n  # Allow ACME challenge requests by the ACME server (letsencrypt)\n  location /.well-known/acme-challenge/ {\n    # This directory is intentionally set to be different\n    # than the Streisand gateway directory. We want to avoid any\n    # chance of leaking gateway credentials/pages over port 80.\n    root {{ nginx_default_html_path }};\n    allow all;\n  }\n  {% else %}\n  server_name {{ streisand_ipv4_address }};\n  {% endif %}\n\n  location / {\n    return 301 https://$server_name$request_uri;\n  }\n\n  # Disable all logging\n  # Comment these lines out if you want to verify the letsencrypt\n  # ACME challenge/response process is working for debugging purposes.\n  access_log /dev/null;\n  error_log  /dev/null crit;\n}\n\n# Catch-all server to prevent requests that either change the HOST header\n# or request an invalid domain/subdomain.\nserver {\n  listen 80 default_server;\n  server_name _;\n  return 444; # \"Connection closed without response\"\n}\n\n# SSL Gateway\nserver {\n  listen 127.0.0.1:{{ nginx_port }} default_server ssl http2;\n\n{% if le_ok %}\n  ssl_certificate         {{ le_certificate }};\n  ssl_certificate_key     {{ le_private_key }};\n  ssl_trusted_certificate {{ le_chain }};\n  ssl_stapling on;\n  ssl_stapling_verify on;\n  # resolver\n  resolver {{ upstream_dns_servers | join(' ') }} valid=300s;\n  resolver_timeout 5s;\n  # It'd be great to include HSTS in non-LE installs too, but\n  # HSTS disables \"clicking through\" the HTTPS error pages.\n  add_header Strict-Transport-Security max-age=63072000;\n{% else %}\n  ssl_certificate      {{ nginx_self_signed_certificate }};\n  ssl_certificate_key  {{ nginx_private_key }};\n{% endif %}\n\n  auth_basic            \"Authorization Required\";\n  auth_basic_user_file  {{ streisand_gateway_htpasswd_file }};\n\n  ssl_protocols TLSv1.2;\n  ssl_prefer_server_ciphers on;\n  ssl_ciphers '{{ streisand_tls_ciphers }}';\n  ssl_ecdh_curve auto;\n  ssl_session_timeout  10m;\n  ssl_session_cache shared:SSL:10m;\n  ssl_session_tickets off;\n\n  # headers\n  add_header X-Frame-Options DENY;\n  add_header X-Content-Type-Options nosniff;\n  add_header X-XSS-Protection \"1; mode=block\";\n  add_header X-Robots-Tag none;\n  add_header Referrer-Policy \"no-referrer\";\n\n  # Disable all logging\n  access_log /dev/null;\n  error_log  /dev/null crit;\n\n  root  {{ streisand_gateway_location }};\n  index index.html index.htm;\n  \n  location / {\n    autoindex off; \n  }\n\n}\n"
  },
  {
    "path": "playbooks/roles/streisand-gateway/vars/main.yml",
    "content": "---\nstreisand_gateway_url: \"https://{{ streisand_ipv4_address }}\"\n\nstreisand_gateway_htpasswd_file: \"/etc/nginx/htpasswd\"\nstreisand_gateway_password_file: \"/etc/nginx/gateway-password.txt\"\nstreisand_gateway_password_localpath: \"../{{ streisand_local_directory }}/gateway-password.txt\"\nstreisand_temp_gateway_path: \"/var/local/streisand.gateway\"\n\nopenssl_ca_base: \"/root/ca\"\nopenssl_ca_private_dir: \"{{ openssl_ca_base }}/private\"\nopenssl_ca_newcerts_dir: \"{{ openssl_ca_base }}/newcerts\"\nopenssl_ca_key: \"{{ openssl_ca_private_dir }}/cakey.pem\"\nopenssl_ca_certificate: \"{{ openssl_ca_base }}/cacert.pem\"\nopenssl_ca_default_md: \"sha256\"\n\nnginx_days_valid: \"1825\"\n\nnginx_self_signed_certificate: \"/etc/ssl/certs/{{ streisand_server_name }}.crt\"\nnginx_self_signed_certificate_request: \"/etc/ssl/certs/{{ streisand_server_name }}.csr\"\nnginx_private_key: \"/etc/ssl/private/{{ streisand_server_name }}.key\"\n"
  },
  {
    "path": "playbooks/roles/streisand-mirror/tasks/main.yml",
    "content": "---\n- name: Determine if there is a need to mirror client software\n  # NOTE(@cpu): If any additional roles start to mirror client software this\n  # conditional fact value should be updated to include the role's enabled var.\n  set_fact:\n    streisand_mirrored_clients: >\n      streisand_openconnect_enabled or\n      streisand_openvpn_enabled or\n      streisand_shadowsocks_enabled or\n      streisand_ssh_forward_enabled or\n      streisand_stunnel_enabled or\n      streisand_tor_enabled\n\n- name: Make the directory where mirrored files will be stored\n  file:\n    path: \"{{ streisand_mirror_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0755\n    state: directory\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"Streisand mirror\"\n    i18n_location: \"{{ streisand_mirror_location }}\"\n    input_template_name: \"mirror-index\"\n  # Only generate the Markdown mirror page when there is a role enabled that\n  # mirrors client software\n  when: streisand_mirrored_clients\n"
  },
  {
    "path": "playbooks/roles/streisand-mirror/templates/mirror-index-fr.md.j2",
    "content": "Miroirs des clients\n-------------------\n\nLes fichiers reflétés ci-dessous ont tous été cryptographiquement vérifiés. Dans le cas où c'est possible, vérification avec les clés de signature GPG officielles de chaque projet ont été utilisées. Les sommes de contrôle SHA-256 vérifie l'intégrité de tous les autres fichiers.\n\n---\n* Les clients\n{% if streisand_openconnect_enabled %}\n  * [OpenConnect](openconnect/index-fr.html)\n{% endif %}\n{% if streisand_openvpn_enabled %}\n  * [OpenVPN](openvpn/index-fr.html)\n{% if streisand_stunnel_enabled %}\n  * [Stunnel](stunnel/index-fr.html)\n{% endif %}\n{% endif %}\n{% if streisand_shadowsocks_enabled %}\n  * [Shadowsocks](shadowsocks/index-fr.html)\n{% endif %}\n{% if streisand_ssh_forward_enabled %}\n  * [OpenSSH](ssh/index-fr.html)\n{% endif %}\n{% if streisand_tor_enabled %}\n  * [Tor Browser Bundle](tor/index-fr.html)\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/streisand-mirror/templates/mirror-index.md.j2",
    "content": "Client Mirrors\n--------------\n\nThe files mirrored below have all been cryptographically verified. Where possible, each project's official GPG signing keys were used. SHA-256 checksums verified the integrity of all other files. \n\n---\n* Clients\n{% if streisand_openconnect_enabled %}\n  * [OpenConnect](openconnect/)\n{% endif %}\n{% if streisand_openvpn_enabled %}\n  * [OpenVPN](openvpn/)\n{% if streisand_stunnel_enabled %}\n  * [Stunnel](stunnel/)\n{% endif %}\n{% endif %}\n{% if streisand_shadowsocks_enabled %}\n  * [Shadowsocks](shadowsocks/)\n{% endif %}\n{% if streisand_ssh_forward_enabled %}\n  * [OpenSSH](ssh/)\n{% endif %}\n{% if streisand_tor_enabled %}\n  * [Tor Browser Bundle](tor/)\n{% endif %}\n"
  },
  {
    "path": "playbooks/roles/streisand-mirror/vars/main.yml",
    "content": "---\nstreisand_mirror_location: \"{{ streisand_gateway_location }}/mirror\"\n\nstreisand_mirror_warning: \"One or more of the VPN clients could not be mirrored. Please file a bug report on GitHub so that the version number, checksum, or download location can be updated. Setup will now continue.\"\nstreisand_mirror_warning_seconds: \"20\"\n"
  },
  {
    "path": "playbooks/roles/stunnel/defaults/main.yml",
    "content": "---\nstunnel_cert_country:  \"GB\"\nstunnel_cert_province: \"Berkshire\"\nstunnel_cert_city: \"Slough\"\nstunnel_cert_org: \"Wernham Hogg Paper Company\"\nstunnel_cert_ou: \"Gareth Keenan Investigations\"\n\nstunnel_key_size: \"3072\"\n"
  },
  {
    "path": "playbooks/roles/stunnel/handlers/main.yml",
    "content": "---\n- name: Restart stunnel\n  systemd:\n    name: stunnel.service\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/stunnel/tasks/firewall.yml",
    "content": "---\n- name: Ensure UFW allows stunnel\n  ufw:\n    to_port: \"{{ stunnel_remote_port }}\"\n    proto: \"tcp\"\n    rule: \"allow\"\n"
  },
  {
    "path": "playbooks/roles/stunnel/tasks/main.yml",
    "content": "---\n- name: Install stunnel\n  apt:\n    package: stunnel4\n\n- name: Generate the stunnel private key\n  command: openssl genrsa -out {{ stunnel_key }} {{ stunnel_key_size }}\n  args:\n    creates: \"{{ stunnel_key }}\"\n\n- name: Generate the stunnel certificate.\n  shell: openssl req -new -nodes -x509 -key {{ stunnel_key}} -days {{ stunnel_days_valid }} -subj \"{{ stunnel_request_subject }}/CN=stunnel\" > {{ stunnel_cert }}\n  args:\n    creates: \"{{ stunnel_cert }}\"\n\n- name: \"Export the key and certificate file in PKCS #12 format\"\n  command: \"openssl pkcs12 -export -in {{ stunnel_cert }} -inkey {{ stunnel_key }} -out {{ stunnel_pkcs12 }} -password pass:\"\n  args:\n    creates: \"{{ stunnel_pkcs12 }}\"\n\n- name: Set the proper permissions on the stunnel key file\n  file:\n    path: \"{{ stunnel_key }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Generate remote stunnel configuration file (for the server)\n  template:\n    src: stunnel-remote.conf.j2\n    dest: \"{{ stunnel_path }}/stunnel.conf\"\n  notify: Restart stunnel\n\n- name: Generate local stunnel configuration file (for connecting clients)\n  template:\n    src: stunnel-local.conf.j2\n    dest: \"{{ openvpn_gateway_location }}/stunnel.conf\"\n\n- name: Stop (init.d's) stunnel4\n  systemd:\n    name: stunnel4.service\n    state: stopped\n    masked: yes\n\n- name: Copy the stunnel system unit file\n  template:\n    src: stunnel.service.j2\n    dest: /etc/systemd/system/stunnel.service\n    mode: \"0644\"\n\n- name: Enable the stunnel service\n  systemd:\n    daemon_reload: yes\n    name: stunnel.service\n    enabled: yes\n    state: restarted\n\n# Set up the stunnel firewall rules\n- import_tasks: firewall.yml\n\n# Mirror the stunnel client\n- import_tasks: mirror.yml\n"
  },
  {
    "path": "playbooks/roles/stunnel/tasks/mirror.yml",
    "content": "---\n- name: Include the stunnel mirror variables\n  include_vars: mirror.yml\n\n- name: Make the directory where the stunnel mirrored files will be stored\n  file:\n    path: \"{{ stunnel_mirror_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0755\n    state: directory\n\n- block:\n    - include_role:\n        name: download-and-verify\n      vars:\n        project_name: \"stunnel\"\n        project_signer: \"Michal Trojnara\"\n        project_download_baseurl: \"{{ stunnel_base_download_url }}\"\n        project_download_files: \"{{ stunnel_download_files }}\"\n        project_download_location: \"{{ stunnel_mirror_location }}\"\n        project_signer_keyid: \"{{ stunnel_gpg_keyid }}\"\n\n  rescue:\n    - name: \"{{ streisand_mirror_warning }}\"\n      pause:\n        seconds: \"{{ streisand_mirror_warning_seconds }}\"\n\n- name: Get the current stunnel version from the downloaded source file\n  shell: ls *.tar.gz | tail -n 1 | sed -e 's/stunnel-\\(.*\\)\\.tar\\.gz/\\1/'\n  args:\n    chdir: \"{{ stunnel_mirror_location }}\"\n  register: stunnel_latest_check\n  changed_when: False\n\n- name: Set the target stunnel version\n  set_fact:\n    stunnel_version: \"{{ stunnel_latest_check.stdout }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"stunnel mirror\"\n    i18n_location: \"{{ stunnel_mirror_location }}\"\n    input_template_name: \"mirror\"\n"
  },
  {
    "path": "playbooks/roles/stunnel/templates/mirror-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"stunnel\"></a>\n### stunnel ###\n\n**Source**\n\n* [{{ stunnel_source_filename }}]({{ stunnel_source_href }}) ([sig]({{ stunnel_source_sig_href }}))\n\n**Windows**\n\n* [{{ stunnel_installer_filename }}]({{ stunnel_installer_href }}) ([sig]({{ stunnel_installer_sig_href }}))\n"
  },
  {
    "path": "playbooks/roles/stunnel/templates/mirror.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"stunnel\"></a>\n### stunnel ###\n\n**Source**\n\n* [{{ stunnel_source_filename }}]({{ stunnel_source_href }}) ([sig]({{ stunnel_source_sig_href }}))\n\n**Windows**\n\n* [{{ stunnel_installer_filename }}]({{ stunnel_installer_href }}) ([sig]({{ stunnel_installer_sig_href }}))\n"
  },
  {
    "path": "playbooks/roles/stunnel/templates/stunnel-local.conf.j2",
    "content": "client = yes\n\n[stunnel]\naccept = 127.0.0.1:{{ stunnel_local_port }}\nconnect = {{ streisand_ipv4_address }}:{{ stunnel_remote_port }}\n"
  },
  {
    "path": "playbooks/roles/stunnel/templates/stunnel-remote.conf.j2",
    "content": "cert = {{ stunnel_cert }}\nkey = {{ stunnel_key }}\ndebug = 4\noptions = NO_SSLv2\noptions = NO_SSLv3\noptions = NO_TLSv1\noptions = NO_TLSv1.1\nciphers = {{ streisand_tls_ciphers }}\n\n[stunnel]\naccept = {{ stunnel_remote_port }}\nconnect = 127.0.0.1:{{ openvpn_port }}\n"
  },
  {
    "path": "playbooks/roles/stunnel/templates/stunnel.service.j2",
    "content": "# source https://github.com/liuliang/centos-stunnel-systemd/blob/master/stunnel.service\n[Unit]\nDescription=SSL tunnel for network daemons\nAfter=openvpn@server.target\n\n[Install]\nWantedBy=multi-user.target\nAlias=stunnel.target\n\n[Service]\nType=forking\nExecStart=/usr/bin/stunnel {{ stunnel_path }}/stunnel.conf\nExecStop=/usr/bin/killall -9 stunnel\n\n# Give up if ping doesn't get an answer within the timeout\nTimeoutSec=600\n\nRestart=always\nPrivateTmp=true\n"
  },
  {
    "path": "playbooks/roles/stunnel/vars/main.yml",
    "content": "---\nstunnel_days_valid: \"1825\"\nstunnel_request_subject: \"/C={{ stunnel_cert_country }}/ST={{ stunnel_cert_province }}/L={{ stunnel_cert_city }}/O={{ stunnel_cert_org }}/OU={{ stunnel_cert_ou }}\"\nstunnel_path: \"/etc/stunnel\"\nstunnel_cert: \"{{ stunnel_path }}/stunnel.crt\"\nstunnel_key: \"{{ stunnel_path }}/stunnel.key\"\nstunnel_pkcs12: \"{{ openvpn_gateway_location }}/stunnel.p12\"\n"
  },
  {
    "path": "playbooks/roles/stunnel/vars/mirror.yml",
    "content": "---\n# Stunnel Download variables\n# --------------------------\nstunnel_mirror_location: \"{{ streisand_mirror_location }}/stunnel\"\nstunnel_mirror_href_base: \"/mirror/stunnel\"\n\nstunnel_base_download_url: \"https://www.stunnel.org\"\n\nstunnel_installer_url: \"stunnel-latest-installer.exe\"\nstunnel_installer_sig_url: \"stunnel-latest-installer.exe.asc\"\n\nstunnel_installer_filename: \"{{ stunnel_installer_url }}\"\nstunnel_installer_sig_filename: \"{{ stunnel_installer_filename }}.asc\"\nstunnel_installer_href: \"{{ stunnel_mirror_href_base }}/{{ stunnel_installer_filename }}\"\nstunnel_installer_sig_href: \"{{ stunnel_mirror_href_base }}/{{ stunnel_installer_sig_filename }}\"\n\nstunnel_source_filename: \"stunnel-{{ stunnel_version }}.tar.gz\"\nstunnel_source_sig_filename: \"{{ stunnel_source_filename }}.asc\"\nstunnel_source_href: \"{{ stunnel_mirror_href_base }}/{{ stunnel_source_filename }}\"\nstunnel_source_sig_href: \"{{ stunnel_mirror_href_base }}/{{ stunnel_source_sig_filename }}\"\n\nstunnel_source_url: \"stunnel-latest.tar.gz\"\nstunnel_source_sig_url: \"stunnel-latest.tar.gz.asc\"\n\nstunnel_gpg_keyid: \"D416E014\"\n\nstunnel_download_files:\n  - { \"file\": \"{{ stunnel_installer_url }}\", \"sig\": \"{{ stunnel_installer_sig_url }}\" }\n  - { \"file\": \"{{ stunnel_source_url }}\", \"sig\": \"{{ stunnel_source_sig_url }}\" }\n"
  },
  {
    "path": "playbooks/roles/sysctl/tasks/main.yml",
    "content": "---\n- block:\n    - name: Apply custom sysctl values\n      sysctl:\n        name: \"{{ item.key }}\"\n        value: \"{{ item.value }}\"\n        ignoreerrors: yes\n        sysctl_set: yes\n        reload: yes\n        state: present\n      with_items: \"{{ sysctl_values }}\"\n  when: ansible_virtualization_type != 'lxc'\n"
  },
  {
    "path": "playbooks/roles/sysctl/vars/main.yml",
    "content": "---\nsysctl_values:\n  - { key: kernel.sysrq, value: 0 }\n  - { key: kernel.core_uses_pid, value: 1 }\n  - { key: net.ipv4.tcp_syncookies, value: 1 }\n  - { key: kernel.msgmnb, value: 65536 }\n  - { key: kernel.msgmax, value: 65536 }\n  - { key: kernel.shmmax, value: 68719476736 }\n  - { key: kernel.shmall, value: 4294967296 }\n  - { key: net.ipv4.conf.all.accept_source_route, value: 0 }\n  - { key: net.ipv4.conf.default.accept_source_route, value: 0 }\n  - { key: net.ipv4.conf.all.log_martians, value: 1 }\n  - { key: net.ipv4.conf.default.log_martians, value: 1 }\n  - { key: net.ipv4.conf.all.accept_redirects, value: 0 }\n  - { key: net.ipv4.conf.default.accept_redirects, value: 0 }\n  - { key: net.ipv4.conf.all.send_redirects, value: 0 }\n  - { key: net.ipv4.conf.default.send_redirects, value: 0 }\n  - { key: net.ipv4.conf.all.rp_filter, value: 0 }\n  - { key: net.ipv4.conf.default.rp_filter, value: 0 }\n  - { key: net.ipv4.icmp_echo_ignore_broadcasts, value: 1 }\n  - { key: net.ipv4.icmp_ignore_bogus_error_responses, value: 1 }\n  - { key: net.ipv4.conf.all.secure_redirects, value: 0 }\n  - { key: net.ipv4.conf.default.secure_redirects, value: 0 }\n  - { key: kernel.randomize_va_space, value: 1 }\n  - { key: net.core.wmem_max, value: 12582912 }\n  - { key: net.core.rmem_max, value: 12582912 }\n  - { key: fs.suid_dumpable, value: 0 }\n  - { key: fs.protected_hardlinks, value: 1 }\n  - { key: fs.protected_symlinks, value: 1 }\n"
  },
  {
    "path": "playbooks/roles/test-client/files/openvpn_signing.key",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBE45PsIBCAC2K2LRZPQIUmJlCDKcncfR6vok2wowDpGpHZffvEEoUj/DoocR\nLLpPHR5RB1zMWIs2IjF8vOtXMCBguDgtEvQTh6p6DM3D1fTnYp3pPlQyyzAuC81v\nCQo44h09R4Nh2e38oMRVztmAnacC4g5aiSEamrZ4PbWdAdPc4uZdCPOGmUDJw8+q\naAYvL/8pM7YqEu05FqE+aNcG02K+mDhA2bqRLLKoLEFpeMSO6vV8BrE7Vw1Rs1PM\nVLDJt9HdXmC6vP+WWqDuj7/qfRb2wwlSIp5+aFyRHOUNyFKnWZYIObeV3+Y6oG6h\ngmBtU1673mHDqVy26TwfjpJeudMKHVCrKXVXABEBAAG0QVNhbXVsaSBTZXBww6Ru\nZW4gKE9wZW5WUE4gVGVjaG5vbG9naWVzLCBJbmMpIDxzYW11bGlAb3BlbnZwbi5u\nZXQ+iQFVBBMBAgA/AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgBYhBDDr9Oc8\nzmPu4STdJ45tqLThWMVpBQJZeJ2tBQkQ4vlrAAoJEI5tqLThWMVpPDUH/RdLsdG/\n4kmal/rfbso3YVxZXGp2fHKrptvCVrUWluYs6H/XBV4x6aMe8Q6K7Qa7BSLA9jZ8\nv+UN/4aA+urBcs6Ted/XbP3mKU47tOotW24nA1LRjd4gUSEXCaEOBbCSyw3uw6Vz\nU1wr1gEmkC7kvBziL+Pcbt5tKTRhUfgbcjYNNdp/nAwn3Pm3OFRaBt/qDU2aYAOH\n+k191x/ovDRO/UiU2CVvrdfv/VMZfo/rwxe8IiirxQ4k5DR2Vyu0DMNzlNTqRk8l\nrUH0FBdl0rOiefH0m6ubKstpYCaOUYsh/FaW53O6qqrTlZqPtAav1cRog8zb8mhT\nsFFAarhnZcQ/DG+5AQ0ETjk+wgEIAOg+Bjk8Wnb7fbbwBDDUalLsIEgFUhsrSLD5\nVVYB8tOq7djshckp/3LwfkSsmUzEtXMXxIbDUON1vbCQXZlQDe7E7uY5KFNWyi4+\nUJwLMrs+oqfeduUzDxQ+voq/6NGl+2olqd6vT/c/uPb/RPZpOdgoEkqFEOTMRVz0\nDZwAyzyYEWBrwDECNbEtqefMLPIaUGUzZvUc80I+MYL6AzRe/utIWcBnZ2nydZ0S\nvWKRJ0lOs69e6KoFVeE5QXzmTXkjzSbR9eN3ADm2j0EjLnpt/zR4hF8s4l4HLdRd\nSn47tAdvahsNfgWmOfiQD8btnu8DiMiJMd8IpVsZX/zCJbSUChcAEQEAAYkBPAQY\nAQIAJgIbDBYhBDDr9Oc8zmPu4STdJ45tqLThWMVpBQJZeJ2DBQkQ4vlBAAoJEI5t\nqLThWMVpCCIH+QFqEY+Xk5gJc10lbJUZEhJIknS/3GEd+3WBHgBtBaQCeK7+bFQP\nZagTN4SJLiwYcQDV04mZTpFOJV1k9AYaz7ENEjHe51mGhPM9sm5Ix7KwMNo0lHJ+\nryZ0zyie28IbGz+rYa7OdkhE2EmcQkezYNWC03G8yR9yGk3QZ3CtPPO/xYP2tBGc\nOocqWUkVuR7KpitT9QnOZ4af26b83Vr/+qJ1FdSfW6/VAbyboVWya4oEnKSUusBm\n0WCQzaLH15EpzgcdB/x8KVOTS1dAA5GNyRyhbRfP6yBXgBruCkPa4/np78/72jjW\nvbAvOhOEMnfzWmf3VZq+q6hhIJf6Sp+dcoU=\n=P3ax\n-----END PGP PUBLIC KEY BLOCK-----\n"
  },
  {
    "path": "playbooks/roles/test-client/files/shadowsocks-qr-decode.py",
    "content": "#!/usr/bin/python2\n#\n# shadowsocks-qr-decode.py\n#\n# This script accepts a path to a QR code image as an input. If the QR code\n# contains an encoded `ss://` URL for the Shadowsocks protocol[0]\n# then it is processed and the constituent parts (method, password, server\n# address, etc) are output to stdout.\n# This allows other tools (e.g. a test script) to configure itself based on\n# a QR code from a Shadowsocks server.\n#\n# This script requires `zbar-tools` be installed from apt. You might ask\n# yourself \"Why not use the `qrtools` Python package?\" The answer is that\n# getting a 3rd party Python dep requires `pip` be installed and we have no\n# other reasons to use it. More importantly, it turns out `qrtools` uses the\n# same lib underneath:`zbar`.\n#\n# TODO(@cpu) - update for python3 compatibility. The `urlparse` module was\n#              moved.\n\nimport urlparse\nimport sys\nimport base64\nimport re\nimport argparse\nfrom subprocess import check_output\n\nparser = argparse.ArgumentParser(description=\"Process a Shadowsocks QR Code\")\nparser.add_argument('file', help=\"path to a Shadowsocks QR code image\")\nparser.add_argument(\"--cipher\", help=\"output ciphername\",\n                    action=\"store_true\")\nparser.add_argument(\"--password\", help=\"output password\",\n                    action=\"store_true\")\nparser.add_argument(\"--server\", help=\"output server\",\n                    action=\"store_true\")\nparser.add_argument(\"--port\", help=\"output port\",\n                    action=\"store_true\")\nargs = parser.parse_args()\n\ncmd = [\"zbarimg\", args.file]\ntry:\n    urlData = check_output(cmd)\n    # Strip the leading \"QR-Code:\" that `zbarimg` adds\n    if urlData.startswith(\"QR-Code:\"):\n        urlData = urlData.replace(\"QR-Code:\", \"\")\nexcept:\n    print(\"Error running '{0}'\\n\".format(\" \".join(cmd)))\n\ntry:\n    parts = urlparse.urlparse(urlData)\nexcept:\n    print(\"Unable to parse decoded image data '{0}' as URL\\n\".format(urlData))\n    sys.exit(1)\n\nif parts.scheme != \"ss\":\n    print(\"URL had scheme {0}, which isn't 'ss' and is unsupported\\n\".format(\n        parts.scheme))\n    sys.exit(1)\n\nencodedData = parts.netloc\n\ntry:\n    shadowsocksURL = base64.b64decode(encodedData)\nexcept:\n    print(\"Unable to base64 decode encoded netloc '{0}'\\n\".format(encodedData))\n    sys.exit(1)\n\n# First capture group: cipher\n# Second capture group: password\n# Third capture group: server address\n# Fourth capture group: server port\nshadowsocksURLRegexStr = r'^([\\w\\-]+):([\\w+=\\/]+)@([\\w\\-\\.]+):([\\d]+)$'\nshadowsocksURLRegex = re.compile(shadowsocksURLRegexStr)\n\nmatch = shadowsocksURLRegex.match(shadowsocksURL)\n\nif match:\n    cipher = match.group(1)\n    password = match.group(2)\n    server = match.group(3)\n    port = match.group(4)\n\n    if args.cipher:\n        print(cipher)\n    elif args.password:\n        print(password)\n    elif args.server:\n        print(server)\n    elif args.port:\n        print(port)\n    else:\n        print(\"cipher: {0}\".format(cipher))\n        print(\"password: {0}\".format(password))\n        print(\"server: {0}\".format(server))\n        print(\"port: {0}\".format(port))\nelse:\n    print(\"Decoded Shadowsocks URL '{0}' did not match regex.\\n\".format(\n        shadowsocksURL))\n    sys.exit(1)\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/main.yml",
    "content": "---\n- name: \"Include the common vars\"\n  include_vars: \"../../common/vars/main.yml\"\n\n- name: \"Include the Shadowsocks default vars\"\n  include_vars: \"../../shadowsocks/defaults/main.yml\"\n\n- name: \"Remove existing state from client if required\"\n  file:\n    path: \"{{ item }}\"\n    state: absent\n  with_items:\n    - \"{{ gateway_password_file }}\"\n    - \"{{ test_client_profiles_file }}\"\n\n- name: \"Copy gateway password file to client\"\n  copy:\n    src: \"{{ streisand_gateway_password_localpath }}\"\n    dest: \"{{ gateway_password_file }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: \"Install the gateway test script\"\n  template:\n    src: \"streisand-gateway-test.sh.j2\"\n    dest: \"{{ test_script_dir }}/streisand-gateway-test\"\n    owner: root\n    group: root\n    mode: 0755\n\n- name: \"Wait for the Streisand gateway\"\n  wait_for:\n    host: \"{{ streisand_ip }}\"\n    port: 443\n    state: started\n    timeout: 60\n\n- name: \"Run the gateway test script\"\n  command: \"streisand-gateway-test\"\n\n- name: \"Download the client profile list\"\n  get_url:\n    url: \"{{ gateway_profile_inventory }}\"\n    dest: \"{{ test_client_profiles_file }}\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n    mode: 0600\n\n- name: \"Register the client profile list contents\"\n  command: \"cat {{ test_client_profiles_file }}\"\n  register: test_client_profiles\n\n# Run the SSH forwarding tests\n- import_tasks: ssh-forward.yml\n\n# Run the Shadowsocks tests\n- import_tasks: shadowsocks.yml\n\n# Run the WireGuard tests\n- import_tasks: wireguard.yml\n\n# Run the OpenVPN tests\n- import_tasks: openvpn.yml\n\n# Run the OpenConnect tests\n- import_tasks: openconnect.yml\n\n# Run the Tor tests\n- import_tasks: tor.yml\n\n# Run the Stunnel tests\n- import_tasks: stunnel.yml\n...\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/openconnect-profiletest.yml",
    "content": "---\n- name: \"Testing {{ profile_name }} OpenConnect PKCS12 client profile\"\n  block:\n    - name: \"Read the {{ profile_name }} PKCS12 password from the mobileconfig file\"\n      # Use `xmllint` to evaluate an XPATH against the client mobileconfig XML.\n      # The XPATH provided will extract the PKCS12 password for the given profile.\n      #\n      # Short breakdown of the XPATH expression:\n      #   `/plist/dict/array/dict`\n      #     Gets to the dict's with the config content\n      #   `/plist/dict/array/dict/key[text()=\"Password\"]\n      #     Finds the \"<key>Password</key>\" element\n      #   `/plist/dict/array/dict/key[text()=\"Password\"]/following-sibling::string[1]`\n      #     Finds the \"<string>...</string>\" element that is the\n      #     <key>Password</key> elements first sibling.\n      #   `/plist/dict/array/dict/key[text()=\"Password\"]/following-sibling::string[1]/text()`\n      #     Extracts the node text value from the <string>...</string> - this is\n      #     the PKCS12 password! Nice!\n      shell: >\n        xmllint --xpath '/plist/dict/array/dict/key[text()=\"Password\"]/following-sibling::string[1]/text()' \\\n                {{ openconnect_profile_dir }}/{{ profile_name }}.mobileconfig\n      register: openconnect_pkcs12_password_contents\n      changed_when: False\n\n    - name: \"Start OpenConnect with PKCS12 auth and the {{ profile_name }} profile\"\n      # OpenConnect expects the PKCS12 password to be provided via stdin so we\n      # use `echo -n` to send it to stdin without a newline.\n      # We use `--background` as an argument to make sure the shell returns\n      # immeidately. `--pid-file` helps us kill OpenConnect later.\n      # `--cafile` is used to validate the server's certificate against the\n      # Streisand OpenConnect CA. `--certificate` is used to specify our client\n      # PKCS12 file for client cert auth.\n      shell: >\n        echo -n '{{ openconnect_pkcs12_password_contents.stdout }}' | \\\n        openconnect \\\n          --background --pid-file {{ openconnect_pid_file }} \\\n          --cafile {{ openconnect_ca_file }} \\\n          --certificate {{ openconnect_profile_dir }}/{{ profile_name }}.p12 \\\n          {{ streisand_ip }}:{{ ocserv_port }}\n\n    - name: \"Read the OpenConnect PID file into a var\"\n      command: \"cat {{ openconnect_pid_file }}\"\n      register: openconnect_pid_output\n      changed_when: False\n\n    - name: \"Sleep a short time to allow OpenConnect to connect\"\n      pause:\n        seconds: 2\n\n    - name: \"Register the updated /etc/resolv.conf contents\"\n      shell: \"cat /etc/resolv.conf\"\n      register: openconnect_resolv_conf\n      changed_when: \"False\"\n\n    # TODO(@cpu) - We should be sending the dnsmasq server address down to\n    # clients instead of Google DNS. We also shouldn't be sending a bogus\n    # `search` parameter. For now, test against what Streisand does today.\n    - name: \"Assert that /etc/resolv.conf was updated with the correct nameservers\"\n      assert:\n        that:\n          - \"'nameserver 8.8.8.8' in openconnect_resolv_conf.stdout\"\n          - \"'nameserver 8.8.4.4' in openconnect_resolv_conf.stdout\"\n          - \"'search example.com' in openconnect_resolv_conf.stdout\"\n\n    - name: \"Check {{ external_test_url }} with OpenConnect up\"\n      get_url:\n        url: \"{{ external_test_url }}\"\n        dest: \"/dev/null\"\n        force: \"yes\"\n\n    - name: \"Stop OpenConnect\"\n      command: \"kill -INT {{ openconnect_pid_output.stdout }}\"\n\n    - name: \"Remove tun0 from resolvconf\"\n      command: \"resolvconf -d tun0\"\n      ignore_errors: \"yes\"\n\n    - name: \"Register the updated /etc/resolv.conf contents\"\n      shell: \"cat /etc/resolv.conf\"\n      register: openconnect_resolv_conf\n      changed_when: \"False\"\n\n    - name: \"Assert that the DNS was restored to pre-OpenConnect state\"\n      assert:\n        that:\n          - \"'nameserver 8.8.8.8' not in openconnect_resolv_conf.stdout\"\n          - \"'nameserver 8.8.4.4' not in openconnect_resolv_conf.stdout\"\n          - \"'search example.com' not in openconnect_resolv_conf.stdout\"\n\n    - name: \"Remove the OpenConnect pid file\"\n      file:\n        path: \"{{ openconnect_pid_file }}\"\n        state: absent\n\n  rescue:\n    - name: \"Bring down OpenConnect\"\n      command: \"killall openconnect\"\n      ignore_errors: \"yes\"\n    - name: \"Remove tun0 from resolvconf\"\n      command: \"resolvconf -d tun0\"\n      ignore_errors: \"yes\"\n    - name: \"Delete the tun0 interface\"\n      command: \"ip link delete tun0\"\n      ignore_errors: \"yes\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/openconnect.yml",
    "content": "---\n\n# Import the Streisand OpenConnect playbook default vars\n- include_vars: \"../../openconnect/defaults/main.yml\"\n\n- name: \"Remove stale test state if required\"\n  file:\n    path: \"{{ item }}\"\n    state: absent\n  with_items:\n    - \"{{ openconnect_profile_dir }}\"\n    - \"{{ openconnect_ca_file }}\"\n    - \"{{ openconnect_pid_file }}\"\n\n- name: \"Create OpenConnect profile directory\"\n  file:\n    path: \"{{ openconnect_profile_dir }}\"\n    state: directory\n\n- name: \"Install OpenConnect & required tools\"\n  apt:\n    name: \"{{ item }}\"\n  with_items:\n    - \"openconnect\"\n    # libxml2-utils provides xmllint which we use to extract a PKCS12 password\n    # from the mobileconfig XML files for testing\n    - \"libxml2-utils\"\n\n- name: \"Download OpenConnect CA certificate from the gateway\"\n  get_url:\n    url: \"{{ gateway_openconnect_ca_file }}\"\n    dest: \"{{ openconnect_ca_file }}\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n    mode: 0600\n\n- name: \"Remove existing OpenConnect PKCS12 files if they exist\"\n  file:\n    path: \"{{ openconnect_profile_dir }}/{{ profile_name }}.p12\"\n    state: absent\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n\n- name: \"Download each of the OpenConnect PKCS12 client profiles\"\n  get_url:\n    url: \"{{ gateway_test_url }}/openconnect/{{ profile_name }}.p12\"\n    dest: \"{{ openconnect_profile_dir }}/{{ profile_name }}.p12\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n\n  # NOTE(@cpu) - The Linux OpenConnect client cann not _use_ the mobileconfig\n  # profiles but they are a convenient way to get the PKCS12 password\n  # programmatically so we download them for this purpose.\n- name: \"Download each of the OpenConnect mobileconfig profiles\"\n  get_url:\n    url: \"{{ gateway_test_url }}/openconnect/{{ profile_name }}.mobileconfig\"\n    dest: \"{{ openconnect_profile_dir }}/{{ profile_name }}.mobileconfig\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n\n- name: \"Test each Openconnect PKCS12 client profile\"\n  include: openconnect-profiletest.yml\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/openvpn-profileget.yml",
    "content": "---\n- name: \"Remove existing {{ openvpn_profile_type }} OpenVPN profiles if they exist\"\n  file:\n    path: \"{{ openvpn_profile_dir}}/{{ profile_name }}-{{ openvpn_profile_type}}*.ovpn\"\n    state: absent\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n\n- name: \"Download each of the {{ openvpn_profile_type }} OpenVPN profiles\"\n  get_url:\n    url: \"{{ gateway_test_url }}/openvpn/{{ profile_name }}/{{ streisand_ip }}-{{ openvpn_profile_type }}.ovpn\"\n    dest: \"{{ openvpn_profile_dir }}/{{ profile_name }}-{{ openvpn_profile_type }}.ovpn\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n\n# NOTE(cpu): This is a little bit messy but there aren't really any good options\n# to add a few lines to the Streisand OVPN that we need - mainly the DHCP\n# up/down settings described in the Streisand docs for Linux clients without\n# NetworkManager and the PID tracking command we use to kill OpenVPN later\n- name: \"Concatinate the profile customization commands to each OpenVPN {{ openvpn_profile_type }} client profile if required\"\n  shell: \"cat {{ openvpn_profile_addons }} {{ openvpn_profile_dir }}/{{ profile_name }}-{{ openvpn_profile_type }}.ovpn > {{ openvpn_profile_dir }}/{{ profile_name }}-{{ openvpn_profile_type }}.client-test.ovpn\"\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/openvpn-profiletest.yml",
    "content": "---\n- name: \"Testing {{ profile_name }} - {{ openvpn_profile_type }}\"\n  block:\n    - name: \"Start OpenVPN with the {{ profile_name }} {{ openvpn_profile_type }} client profile\"\n      shell: \"nohup openvpn {{ openvpn_profile_dir }}/{{ profile_name }}-{{ openvpn_profile_type }}.client-test.ovpn&\"\n\n    - name: \"Read the OpenVPN PID file into a var\"\n      command: \"cat {{ openvpn_pid_file }}\"\n      register: openvpn_pid_output\n\n    # TODO(cpu): A nice follow up would be finding a way to add a second \"up\"\n    # command to the OVPN profile that tells Ansible somehow that the tunnel\n    # is up. It seems like you can only specify one \"up\" handler and we're using\n    # it to run the DHCP update per the Streisand docs.\n    - name: \"Sleep a short time to allow OpenVPN to connect\"\n      pause:\n        seconds: 20\n\n    - name: \"Register the updated /etc/resolv.conf contents\"\n      shell: \"cat /etc/resolv.conf\"\n      register: openvpn_resolv_conf\n      changed_when: \"False\"\n\n    - name: \"Assert that /etc/resolv.conf was updated for the DNSMasq OpenVPN IP\"\n      assert:\n        that:\n          - \"'nameserver {{ dnsmasq_openvpn_tcp_ip }}' in openvpn_resolv_conf.stdout\"\n\n    - name: \"Check {{ external_test_url }} with OpenVPN up\"\n      get_url:\n        url: \"{{ external_test_url }}\"\n        dest: \"/dev/null\"\n        force: \"yes\"\n\n    - name: \"Stop OpenVPN\"\n      command: \"kill {{ openvpn_pid_output.stdout }}\"\n\n    - name: \"Register the updated /etc/resolv.conf contents\"\n      shell: \"cat /etc/resolv.conf\"\n      register: openvpn_resolv_conf\n      changed_when: \"False\"\n\n    - name: \"Assert that the DNS was restored to pre-OpenVPN state\"\n      assert:\n        that:\n          - \"'nameserver {{ dnsmasq_openvpn_tcp_ip }}' not in openvpn_resolv_conf.stdout\"\n\n    - name: \"Remove the OpenVPN pid file\"\n      file:\n        path: \"{{ openvpn_pid_file }}\"\n        state: absent\n  rescue:\n    - name: \"Bring down OpenVPN\"\n      command: \"killall openvpn\"\n      ignore_errors: \"yes\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/openvpn-test.yml",
    "content": "---\n- name: \"Download each {{ openvpn_profile_type }} OpenVPN profile\"\n  include: openvpn-profileget.yml\n\n- name: \"Test each {{ openvpn_profile_type }} OpenVPN profile\"\n  include: openvpn-profiletest.yml\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/openvpn.yml",
    "content": "---\n#\n# Import the Streisand OpenVPN playbook vars\n- include_vars: \"../../openvpn/vars/main.yml\"\n\n# Install OpenVPN from PPA\n- import_tasks: \"../../openvpn/tasks/install.yml\"\n\n- name: \"Remove stale test state if required\"\n  file:\n    path: \"{{ item }}\"\n    state: absent\n  with_items:\n    - \"{{ test_client_profiles_file }}\"\n    - \"{{ openvpn_profile_addons }}\"\n    - \"{{ openvpn_pid_file }}\"\n\n- name: \"Generate a file with OpenVPN commands required to customize the profile for the test-client\"\n  template:\n    src: \"openvpn-profile-addons.j2\"\n    dest: \"{{ openvpn_profile_addons }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: \"Download and test each OpenVPN profile type\"\n  include_tasks: openvpn-test.yml\n  vars:\n    openvpn_profile_type: \"{{ item }}\"\n  with_items:\n    - \"direct\"\n    - \"sslh\"\n    # TODO(@cpu) - debug direct-udp and combined profiles. They don't work r.n.\n    #- \"direct-udp\"\n    #- \"combined\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/shadowsocks.yml",
    "content": "---\n- name: \"Download the Linux Shadowsocks client zip to the client machine\"\n  get_url:\n    url: \"{{ gateway_shadowsocks_client }}\"\n    dest: \"{{ shadowsocks_client_zip }}\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n    mode: 0600\n\n- name: \"Extract the Shadowsocks client on the client machine\"\n  # NOTE(@cpu): It's tempting to try and use the `unarchive` module here but with\n  # a brief test it seemed to barf trying to use `unzip` on a `.gz` file. This\n  # isn't a `tar.gz` and is probably too edge-case for `unarchive` so `command`\n  # it is!\n  command: \"gunzip -f {{ shadowsocks_client_zip }}\"\n  args:\n    chdir: \"/root\"\n    creates: \"{{ shadowsocks_client }}\"\n\n- name: \"Set executable mode on Shadowsocks client\"\n  file:\n    path: \"{{ shadowsocks_client }}\"\n    mode: 0700\n\n- name: \"Remove existing Shadowsocks QR code from client if required\"\n  file:\n    path: \"{{ shadowsocks_qr_file }}\"\n    state: absent\n\n- name: \"Download the Shadowsocks QR code to the client machine\"\n  get_url:\n    url: \"{{ gateway_shadowsocks_qr }}\"\n    dest: \"{{ shadowsocks_qr_file }}\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n    mode: 0600\n\n- name: \"Install zbar-tools\"\n  apt:\n    package: zbar-tools\n    force: yes\n\n- name: \"Copy Shadowsocks QR code parser tool to client machine\"\n  copy:\n    src: shadowsocks-qr-decode.py\n    dest: \"{{ test_script_dir }}/shadowsocks-qr-decode\"\n    owner: root\n    group: root\n    mode: 0755\n\n- name: \"Install Shadowsocks test script\"\n  template:\n    src: \"streisand-shadowsocks-forward-test.sh.j2\"\n    dest: \"{{ test_script_dir }}/streisand-shadowsocks-forward-test\"\n    owner: root\n    group: root\n    mode: 0755\n\n- name: \"Run Shadowsocks test script\"\n  command: \"streisand-shadowsocks-forward-test\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/ssh-forward.yml",
    "content": "---\n- name: \"Remove existing state from client if required\"\n  file:\n    path: \"{{ item }}\"\n    state: absent\n  with_items:\n    - \"{{ forward_ssh_key }}\"\n    - \"{{ forward_ssh_config }}\"\n    - \"{{ forward_ssh_hosts }}\"\n    - \"{{ ssh_pid_file }}\"\n\n- name: \"Download the forward user SSH key to the client\"\n  get_url:\n    url: \"{{ gateway_ssh_key }}\"\n    dest: \"{{ forward_ssh_key }}\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n    mode: 0600\n\n- name: \"Download the Streisand server SSH known hosts file\"\n  get_url:\n    url: \"{{ gateway_ssh_hosts }}\"\n    dest: \"{{ forward_ssh_hosts }}\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n    mode: 0600\n\n- name: \"Install an SSH config file for a SSH SOCKS connection with the forward user\"\n  template:\n    src: \"ssh-config.j2\"\n    dest: \"{{ forward_ssh_config }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: \"Test SSH forward user SOCKS proxy\"\n  block:\n    - name: \"Start an SSH connection with dynamic port forwarding\"\n      shell: >\n        nohup ssh streisand-host -N -T & \\\n        echo $! > {{ ssh_pid_file }}\n      args:\n        creates: \"{{ ssh_pid_file }}\"\n\n    - name: \"Read the SSH connect PID file into a var\"\n      command: \"cat {{ ssh_pid_file }}\"\n      register: ssh_pid_output\n      changed_when: False\n\n    - name: \"Wait for port {{ forward_socks_port }} to become open\"\n      wait_for:\n        port: \"{{ forward_socks_port }}\"\n        delay: 2\n        timeout: 60\n\n    - name: \"Access a test URL through the SSH SOCKS proxy\"\n      command: \"curl --socks5-hostname localhost:{{ forward_socks_port }} {{ external_test_url }}\"\n      # Don't warn about using command to execute curl - the get_url module\n      # doesn't support specifying a socks5 proxy\n      args:\n        warn: no\n\n    - name: \"Stop the SSH connection\"\n      command: \"kill {{ ssh_pid_output.stdout }}\"\n\n  rescue:\n    - name: \"kill any hanging SSH connections\"\n      command: \"kill -9 {{ ssh_pid_output.stdout }}\"\n      ignore_errors: \"yes\"\n\n\n- name: \"Test TinyProxy through a SSH forward user connection\"\n  block:\n    - name: \"Remove the SSH PID file\"\n      file:\n        path: \"{{ ssh_pid_file }}\"\n        state: absent\n\n    - name: \"Start an SSH connection with TinyProxy's port forwarded\"\n      shell: >\n        nohup ssh streisand-host-tinyproxy -N -T & \\\n        echo $! > {{ ssh_pid_file }}\n      args:\n        creates: \"{{ ssh_pid_file }}\"\n\n    - name: \"Read the SSH connect PID file into a var\"\n      command: \"cat {{ ssh_pid_file }}\"\n      register: ssh_pid_output\n      changed_when: False\n\n    - name: \"Wait for port {{ tinyproxy_local_port }} to become open\"\n      wait_for:\n        port: \"{{ tinyproxy_local_port }}\"\n        delay: 2\n        timeout: 120\n\n    - name: \"Access a test URL through the TinyProxy proxy\"\n      command: \"curl -x localhost:{{ tinyproxy_local_port }} {{ external_test_url }}\"\n      # Don't warn about using command to execute curl - the get_url module's\n      # support for HTTP proxies isn't great\n      args:\n        warn: no\n\n    - name: \"Stop the SSH connection\"\n      command: \"kill {{ ssh_pid_output.stdout }}\"\n\n  rescue:\n    - name: \"kill any hanging SSH connections\"\n      command: \"kill -9 {{ ssh_pid_output.stdout }}\"\n      ignore_errors: \"yes\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/stunnel.yml",
    "content": "---\n\n# Import the Streisand OpenVPN playbook vars\n- include_vars: \"../../openvpn/vars/main.yml\"\n\n- name: \"Install stunnel and openvpn\"\n  apt:\n    package:\n      - \"stunnel\"\n      - \"openvpn\"\n\n- name: \"Ensure the stunnel service is stopped and disabled\"\n  # We need to stop the stunnel service & disable it. By default the Ubuntu 16.04\n  # stunnel package enables & boots the service after being installed.\n  service:\n    name: stunnel4\n    state: stopped\n    enabled: no\n\n- name: \"Remove existing stunnel test state from client if required\"\n  file:\n    path: \"{{ stunnel_dir }}\"\n    state: absent\n  with_items:\n    - \"{{ openvpn_profile_addons }}\"\n    - \"{{ openvpn_pid_file }}\"\n    - \"{{ stunnel_dir }}\"\n\n- name: \"Create stunnel test dir\"\n  file:\n    path: \"{{ stunnel_dir }}\"\n    state: directory\n\n- name: \"Download stunnel client configuration from the Streisand server gateway\"\n  get_url:\n    url: \"{{ gateway_stunnel_conf }}\"\n    dest: \"{{ stunnel_conf }}\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n    mode: 0600\n\n- name: \"Add a pidfile option to the client configuration\"\n  lineinfile:\n    path: \"{{ stunnel_conf }}\"\n    line: \"pid = {{ stunnel_pid_file }}\"\n    state: present\n    insertbefore: BOF\n\n- name: \"Generate a file with OpenVPN commands required to customize the profile for the test-client\"\n  template:\n    src: \"openvpn-profile-addons.j2\"\n    dest: \"{{ openvpn_profile_addons }}\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: \"Start the stunnel daemon for testing\"\n  block:\n    - name: \"Start the stunnel daemon\"\n      command: \"stunnel4 {{ stunnel_conf }}\"\n\n    - name: \"Read the stunnel daemon PID file into a var\"\n      command: \"cat {{ stunnel_pid_file }}\"\n      register: stunnel_pid_output\n      changed_when: False\n\n    - name: \"Download and test each OpenVPN stunnel profile\"\n      include_tasks: openvpn-test.yml\n      vars:\n        openvpn_profile_type: \"stunnel\"\n\n    - name: \"Stop the stunnel daemon\"\n      command: \"kill -INT {{ stunnel_pid_output.stdout }}\"\n\n  rescue:\n    - name: \"kill stunnel instances\"\n      command: \"killall stunnel4\"\n      ignore_errors: \"yes\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/tor.yml",
    "content": "---\n\n- name: \"Install tor and obs4proxy\"\n  apt:\n    package:\n      - \"tor\"\n      - \"obfs4proxy\"\n\n- name: \"Remove stale test state if required\"\n  file:\n    path: \"{{ item }}\"\n    state: absent\n  with_items:\n    - \"{{ tor_config }}\"\n    - \"{{ tor_obfs4_qr }}\"\n    - \"{{ tor_pid_file }}\"\n\n- name: \"Ensure the tor service is stopped and disabled\"\n  # We need to stop the tor service & disable it. By default the Ubuntu 16.04\n  # tor package enables & boots the service after being installed.\n  service:\n    name: tor\n    state: stopped\n    enabled: no\n\n- name: \"Download tor obfs4 proxy QR code from the Streisand gateway\"\n  get_url:\n    url: \"{{ gateway_tor_qr }}\"\n    dest: \"{{ tor_obfs4_qr}}\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n    mode: 0600\n\n- name: \"Download tor hidden service hostname from the Streisand gateway\"\n  get_url:\n    url: \"{{ gateway_tor_hidden_service_hostname }}\"\n    dest: \"{{ tor_hidden_service_hostname}}\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n    mode: 0600\n\n- name: \"Read the tor hidden service hostname into a var\"\n  command: \"cat {{ tor_hidden_service_hostname }}\"\n  register: tor_hidden_service_hostname_output\n  changed_when: False\n\n- name: \"Extract the Streisand server obfs4 proxy info from the QR code\"\n  # NOTE(@cpu) - zbarimg prefixes the data with \"QR-Code\" so we strip it with\n  # sed before registering the output\n  shell: >\n    zbarimg -q {{ tor_obfs4_qr }} | \\\n    sed 's/^QR-Code://'\n  register: tor_obfs4_qr_contents\n\n- name: \"Install the Streiand obfs4 relay client torrc\"\n  template:\n    src: obfs4.relay.client.torrc.j2\n    dest: \"{{ tor_config }}\"\n\n- name: \"Test Streisand tor relay with obfs4proxy obfuscation\"\n  block:\n    - name: \"Start the tor daemon\"\n      command: \"tor -f {{ tor_config }}\"\n\n    - name: \"Read the tor daemon PID file into a var\"\n      command: \"cat {{ tor_pid_file }}\"\n      register: tor_pid_output\n      changed_when: False\n\n    - name: \"Access a test URL through the tor SOCKS proxy\"\n      command: \"curl --socks5-hostname localhost:{{ tor_socks_port }} {{ external_test_url }}\"\n      # Don't warn about using command to execute curl - the get_url module\n      # doesn't support specifying a socks5 proxy\n      args:\n        warn: no\n      register: tor_socks_check\n      # NOTE(@cpu): Tor and hidden services can be a little bit flaky. We give\n      # things a few tries before giving up entirely\n      retries: 3\n      delay: 3\n      until: tor_socks_check.rc == 0\n\n    - name: \"Check the Streisand server hidden service is up & requires auth\"\n      shell: >\n        curl -I \\\n          --socks5-hostname localhost:{{ tor_socks_port }} \\\n          --connect-timeout 20 \\\n          http://{{ tor_hidden_service_hostname_output.stdout }} 2> /dev/null | \\\n          grep -q \"Authorization Required\"\n      register: tor_hs_auth_reject\n      args:\n        warn: no\n      retries: 3\n      delay: 3\n      until: tor_hs_auth_reject.rc == 0\n\n    - name: \"Check the Streisand server hidden service is up & accessible with correct auth\"\n      shell: >\n        curl --socks5-hostname localhost:{{ tor_socks_port }} \\\n        --connect-timeout 20 \\\n        -u {{ gateway_test_user }}:{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }} \\\n        http://{{ tor_hidden_service_hostname_output.stdout }} 2> /dev/null | \\\n        grep -q \"Streisand\"\n      register: tor_hs_auth_accept\n      args:\n        warn: no\n      retries: 3\n      delay: 3\n      until: tor_hs_auth_accept.rc == 0\n\n    - name: \"Stop tor\"\n      command: \"kill -INT {{ tor_pid_output.stdout }}\"\n\n  rescue:\n    - name: \"kill tor instances\"\n      command: \"killall tor\"\n      ignore_errors: \"yes\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/wireguard-profiletest.yml",
    "content": "---\n- block:\n    - name: \"Replace wg0 with the {{ profile_name }} configuration\"\n      copy:\n        src: \"{{ wireguard_profile_dir }}/{{ profile_name }}.conf\"\n        remote_src: yes\n        dest: \"/etc/wireguard/wg0.conf\"\n        mode: 0600\n        owner: root\n        group: root\n        force: yes\n\n    - name: \"Bring up the WireGuard interface for the {{ profile_name }} config\"\n      shell: \"wg-quick up wg0\"\n\n    - name: \"Register the updated /etc/resolv.conf contents\"\n      shell: \"cat /etc/resolv.conf\"\n      register: wgclient_resolv_conf\n      changed_when: \"False\"\n\n    - name: \"Assert that /etc/resolv.conf was updated for the DNSMasq WireGuard IP\"\n      assert:\n        that:\n          - \"'nameserver {{ dnsmasq_wireguard_ip }}' in wgclient_resolv_conf.stdout\"\n\n    - name: \"Check {{ external_test_url }} through the WireGuard route\"\n      get_url:\n        url: \"{{ external_test_url }}\"\n        dest: \"/dev/null\"\n        force: \"yes\"\n\n    - name: \"Register the output from `wg` to check Wireguard status\"\n      shell: \"wg\"\n      register: wgclient_wg_output\n      changed_when: \"False\"\n\n    - name: \"Assert that there has been a successful Wireguard handshake\"\n      assert:\n        that:\n          - \"'latest handshake' in wgclient_wg_output.stdout\"\n\n    - name: \"Bring down the WireGuard interface\"\n      command: \"wg-quick down wg0\"\n\n    - name: \"Register the updated /etc/resolv.conf contents\"\n      shell: \"cat /etc/resolv.conf\"\n      register: wgclient_resolv_conf\n      changed_when: \"False\"\n\n    - name: \"Assert that the DNS was restored to pre-WireGuard state\"\n      assert:\n        that:\n          - \"'nameserver {{ dnsmasq_wireguard_ip }}' not in wgclient_resolv_conf.stdout\"\n  rescue:\n    - name: \"Remove the wg0 interface if present\"\n      command: \"wg-quick down wg0\"\n      ignore_errors: \"yes\"\n"
  },
  {
    "path": "playbooks/roles/test-client/tasks/wireguard.yml",
    "content": "---\n\n# Install the WireGuard PPA and packages\n- import_tasks: \"../../wireguard/tasks/install.yml\"\n\n# Import the Wireguard Streisand playbook vars\n- include_vars: \"../../wireguard/vars/main.yml\"\n\n- name: \"Remove any stale Wireguard profiles\"\n  file:\n    path: \"{{ wireguard_profile_dir }}\"\n    state: absent\n\n- name: \"Create WireGuard profile directory\"\n  file:\n    path: \"{{ wireguard_profile_dir }}\"\n    state: directory\n\n- name: \"Download each of the WireGuard client profiles\"\n  get_url:\n    url: \"{{ gateway_test_url }}/wireguard/{{ profile_name }}.conf\"\n    dest: \"{{ wireguard_profile_dir }}/{{ profile_name }}.conf\"\n    force_basic_auth: yes\n    url_username: \"{{ gateway_test_user }}\"\n    url_password: \"{{ lookup('file', '{{ streisand_gateway_password_localpath }}') }}\"\n    validate_certs: no\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n\n- name: \"Test each WireGuard client profile\"\n  include: wireguard-profiletest.yml\n  with_items: \"{{ test_client_profiles.stdout_lines }}\"\n  loop_control:\n    loop_var: \"profile_name\"\n"
  },
  {
    "path": "playbooks/roles/test-client/templates/obfs4.relay.client.torrc.j2",
    "content": "RunAsDaemon 1\nSOCKSPort {{ tor_socks_port }}\nPidFile {{ tor_pid_file }}\nUseBridges 1\nClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy\nBridge {{ tor_obfs4_qr_contents.stdout }}\n"
  },
  {
    "path": "playbooks/roles/test-client/templates/openvpn-profile-addons.j2",
    "content": "script-security 2\nup /etc/openvpn/update-resolv-conf\ndown /etc/openvpn/update-resolv-conf\nwritepid {{ openvpn_pid_file }}\n"
  },
  {
    "path": "playbooks/roles/test-client/templates/ssh-config.j2",
    "content": "# Connection profile for a SOCKS proxy over a SSH connection to the forward user\n# on a Streisand server instance\nHost streisand-host\n  HostName     {{ streisand_ip }}\n  # Open a SOCKS proxy port equivalent to using `-D {{ forward_socks_port }}` on\n  # the command line\n  DynamicForward {{ forward_socks_port }}\n\n# Connection profile for using the TinyProxy HTTP(S) proxy over SSH to the\n# Streisand server instance\nHost streisand-host-tinyproxy\n  HostName     {{ streisand_ip }}\n  # Forward port {{ tinyproxy_remote_port }} on the streisand_ip host to port \n  # {{ tinyproxy_local_port }} localhost. This  makes TinyProxy (bound to\n  # 127.0.0.1 on the Streisand host) accessible\n  LocalForward {{ tinyproxy_local_port }} localhost:{{ tinyproxy_remote_port }}\n\n# Default settings for all hosts\nHost *\n  Port         22\n  User         {{ forward_ssh_user }}\n  # Only use keys specified in this config\n  IdentitiesOnly yes\n  # Never try password authentication\n  PasswordAuthentication no\n  # Use the specified key for the connection\n  IdentityFile {{ forward_ssh_key }}\n  # Use the preconfigured SSH known hosts fingerprints to avoid having to make\n  # a trust-on-first use decision\n  UserKnownHostsFile {{ forward_ssh_hosts }}\n"
  },
  {
    "path": "playbooks/roles/test-client/templates/streisand-gateway-test.sh.j2",
    "content": "#!/bin/bash -xe\n#\n# NOTE: This test script relies on the -e argument to bash in the shebang above.\n#\n# Streisand Gateway Test\n#  - Confirms HTTP basic auth is present\n#  - Confirms HTTP basic auth rejects an incorrect password\n#  - Confirms using the correct username/password allows viewing the index\n#\n# TODO: Install the streisand gateway CA & remove the --insecure arguments.\n\n# Confirm that not sending a password/username results in a 401 error\ncurl --insecure -I {{ gateway_test_url }} | grep \"401 Unauthorized\"\n\n# Confirm that sending the wrong password/username results in a 401 error\ncurl --insecure -I -u \"{{ gateway_test_user }}:badpassword\" {{ gateway_test_url }} | grep \"401 Unauthorized\"\n\n# Read the password into a var\npassword=$(cat \"{{ gateway_password_file }}\")\n\n# Confirm that using the correct password/username results in a 200 OK\ncurl --insecure -I -u \"{{ gateway_test_user }}:$password\" {{ gateway_test_url }} | grep \"200 OK\"\n"
  },
  {
    "path": "playbooks/roles/test-client/templates/streisand-shadowsocks-forward-test.sh.j2",
    "content": "#!/bin/bash -xe\n#\n# NOTE: This test script relies on the -e argument to bash in the shebang above.\n#\n# Streisand Shadowsocks Client Test\n#   - Confirms the gateway mirror for the Linux Shadowsocks client works\n#   - Confirms the gateway Shadowsocks QR has correct information (password, cipher, etc)\n#   - Confirms that the Linux shadowsocks client can connect & route a HTTP request\n#\n\n# Read the Shadowsocks QR code attributes into vars\nshadowsocksCipher=$(shadowsocks-qr-decode --cipher \"{{ shadowsocks_qr_file }}\" 2>/dev/null)\nshadowsocksPassword=$(shadowsocks-qr-decode --password \"{{ shadowsocks_qr_file }}\" 2>/dev/null)\nshadowsocksServer=$(shadowsocks-qr-decode --server \"{{ shadowsocks_qr_file }}\" 2>/dev/null)\nshadowsocksPort=$(shadowsocks-qr-decode --port \"{{ shadowsocks_qr_file }}\" 2>/dev/null)\n\n# Read the gateway password into a var\ngatewayPassword=$(cat \"{{ gateway_password_file }}\")\n\n# Connect the Shadowsocks client to the server\n{{ shadowsocks_client }} -c \"$shadowsocksServer:$shadowsocksPort\" -password \"$shadowsocksPassword\" -socks localhost:{{ shadowsocks_local_port }} -verbose -cipher \"$shadowsocksCipher\" &\nCLIENT_PID=$!\n\nfunction cleanup {\n  # Kill the backgrounded Shadowsocks client\n  echo \"Killing PID $CLIENT_PID\"\n  kill $CLIENT_PID\n  echo \"Waiting for clean up to finish...\"\n  wait $CLIENT_PID\n}\ntrap cleanup EXIT\n\n# Sleep to give the Shadowsocks client a chance to start\nsleep 2\n\n# Check that the gateway website can be loaded through the Shadowsocks proxy\ncurl --socks5 localhost:{{ shadowsocks_local_port }} --insecure -I -u \"{{ gateway_test_user }}:$gatewayPassword\" {{ gateway_test_url }} | grep \"200 OK\"\n\n# Check that an external site can be loaded through the Shadowsocks proxy\ncurl --socks5 localhost:{{ shadowsocks_local_port }} --insecure -I -u \"{{ gateway_test_user }}:$gatewayPassword\" {{ external_test_url }} | grep \"200 OK\"\n"
  },
  {
    "path": "playbooks/roles/test-client/vars/main.yml",
    "content": "---\n# Path to the gateway password on the Ansible host\nstreisand_gateway_password_localpath: \"../{{ streisand_local_directory }}/gateway-password.txt\"\n\n# Path to the gateway password file on the Streisand client\ngateway_password_file: \"/root/gateway-password.txt\"\n# URL for accessing the Streisand server's HTTP gateway page\ngateway_test_url: \"https://{{ streisand_ip }}\"\n# User for accessing the Streisand server HTTP gateway page\ngateway_test_user: \"streisand\"\n\n# The directory to copy test scripts to\ntest_script_dir: \"/usr/local/bin/\"\n\n# An external URL used to test connectivity through Shadowsocks/WireGuard/etc\nexternal_test_url: \"https://github.com\"\n\n# The gateway URL for clients to download the forward user's RSA key\ngateway_ssh_key: \"{{ gateway_test_url }}/ssh/streisand_rsa\"\n# The gateway URL for clients to download the SSH known hosts file\ngateway_ssh_hosts: \"{{ gateway_test_url }}/ssh/streisand.known_hosts\"\n\n# Files created on the Streisand client test for SSH config:\nforward_ssh_key: \"/root/.ssh/streisand_rsa\"\nforward_ssh_config: \"/root/.ssh/config\"\nforward_ssh_hosts: \"/root/.ssh/streisand.known_hosts\"\n\n# Forwarding SSH username\nforward_ssh_user: \"forward\"\n\n# Port on the Streisand client to use for the SOCKS SSH proxy\nforward_socks_port: 9876\n\n# Port on the Streisand server for TinyProxy\ntinyproxy_remote_port: 8888\n\n# Port on the Streisand client for the TinyProxy port forward\ntinyproxy_local_port: 8888\n\n# PID file for open SSH port forward connections\nssh_pid_file: \"/tmp/ssh.pid\"\n\n# The gateway URL for clients to download the Shadowsocks QR code image\ngateway_shadowsocks_qr: \"{{ gateway_test_url }}/shadowsocks/shadowsocks-qr-code.png\"\n\n# Path to the Shadowsocks QR code image on the client machine\nshadowsocks_qr_file: \"/root/shadowsocks-qr-code.png\"\n\n# The gateway URL for clients to download the Shadowsocks2 Linux source\ngateway_shadowsocks_client: \"{{ gateway_test_url }}/mirror/shadowsocks/shadowsocks2-linux-x64.gz\"\n\n# Path to the Shadowsocks2 client source on the Streisand client\nshadowsocks_client: \"/root/shadowsocks2-linux-x64\"\nshadowsocks_client_zip: \"{{ shadowsocks_client }}.gz\"\n\n# The gateway URL for clients to download the WireGuard config file\ngateway_wireguard_config: \"{{ gateway_test_url }}/wireguard/wg0.conf\"\n\nwireguard_profile_dir: \"/root/wireguard-profiles\"\n\ngateway_profile_inventory: \"{{ gateway_test_url }}/test-client-inventory\"\ntest_client_profiles_file: \"/tmp/test-client-inventory\"\n\nopenvpn_profile_dir: \"/etc/openvpn\"\nopenvpn_profile_addons: \"/tmp/openvpn-profile-addons\"\nopenvpn_pid_file: \"/tmp/openvpn.pid\"\n\ngateway_openconnect_ca_file: \"{{ gateway_test_url }}/openconnect/ca.crt\"\ngateway_openconnect_password_file: \"{{ gateway_test_url }}/openconnect/password.txt\"\n\nopenconnect_ca_file: \"/root/openconnect.ca.crt\"\nopenconnect_pid_file: \"/tmp/openconnect.pid\"\nopenconnect_profile_dir: \"/root/openconnect-profiles\"\nopenconnect_password_file: \"{{ openconnect_profile_dir }}/openconnect.password.txt\"\n\ngateway_tor_qr: \"{{ gateway_test_url }}/tor/tor-obfs4-qr-code.png\"\ngateway_tor_hidden_service_hostname: \"{{ gateway_test_url }}/tor/hidden-service-hostname.txt\"\ntor_pid_file: \"/tmp/tor.pid\"\ntor_socks_port: 9050\ntor_obfs4_qr: \"/root/tor-obs4-qr-code.png\"\ntor_config: \"/etc/tor/streisand.obfs4.relay\"\ntor_hidden_service_hostname: \"/tmp/hidden-service-hostname.txt\"\n\ngateway_stunnel_conf: \"{{ gateway_test_url }}/openvpn/stunnel.conf\"\nstunnel_dir: \"/root/stunnel/\"\nstunnel_conf: \"{{ stunnel_dir }}/stunnel.conf\"\nstunnel_pid_file: \"/tmp/stunnel.pid\"\n"
  },
  {
    "path": "playbooks/roles/tinyproxy/handlers/main.yml",
    "content": "---\n- name: Restart Tinyproxy\n  systemd:\n    name: tinyproxy.service\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/tinyproxy/tasks/main.yml",
    "content": "---\n- name: Install Tinyproxy\n  apt:\n    package: tinyproxy\n\n- name: Stop (init.d's) tinyproxy\n  systemd:\n    name: tinyproxy.service\n    state: stopped\n\n- name: Create the tinyproxy config directory\n  file:\n    path: \"{{ tinyproxy_conf_dir }}\"\n    state: directory\n    owner: nobody\n    group: nogroup\n    mode: 0755\n\n- name: Generate the tinyproxy configuration file\n  template:\n    src: tinyproxy.conf.j2\n    dest: \"{{ tinyproxy_conf_file }}\"\n    owner: root\n    group: root\n    mode: 0644\n\n- name: Generate the tinyproxy system unit file\n  template:\n    src: tinyproxy.service.j2\n    dest: /etc/systemd/system/tinyproxy.service\n    owner: root\n    group: root\n    mode: 0644\n\n- name: Generate the systemd tmpfile for tinyproxy\n  template:\n    src: tinyproxytmp.conf.j2\n    dest: /etc/tmpfiles.d/tinyproxy.conf\n    owner: root\n    group: root\n    mode: 0644\n\n- name: Clean up the installed-by-default tinyproxy configuration file\n  file:\n    path: /etc/tinyproxy.conf\n    state: absent\n\n- name: Enable and restart the tinyproxy service\n  systemd:\n    daemon_reload: yes\n    name: tinyproxy.service\n    enabled: yes\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/tinyproxy/templates/tinyproxy.conf.j2",
    "content": "##\n## tinyproxy.conf -- tinyproxy daemon configuration file\n##\n## This example tinyproxy.conf file contains example settings\n## with explanations in comments. For decriptions of all\n## parameters, see the tinproxy.conf(5) manual page.\n##\n\n#\n# User/Group: This allows you to set the user and group that will be\n# used for tinyproxy after the initial binding to the port has been done\n# as the root user. Either the user or group name or the UID or GID\n# number may be used.\n#\nUser nobody\nGroup nogroup\n\n#\n# Port: Specify the port which tinyproxy will listen on.  Please note\n# that should you choose to run on a port lower than 1024 you will need\n# to start tinyproxy using root.\n#\nPort {{ tinyproxy_port }}\n\n#\n# Listen: If you have multiple interfaces this allows you to bind to\n# only one. If this is commented out, tinyproxy will bind to all\n# interfaces present.\n#\nListen {{ tinyproxy_listen_address }}\n\n#\n# Timeout: The maximum number of seconds of inactivity a connection is\n# allowed to have before it is closed by tinyproxy.\n#\nTimeout {{ tinyproxy_timeout_seconds }}\n\n#\n# DefaultErrorFile: The HTML file that gets sent if there is no\n# HTML file defined with an ErrorFile keyword for the HTTP error\n# that has occured.\n#\nDefaultErrorFile \"/usr/share/tinyproxy/default.html\"\n\n#\n# StatFile: The HTML file that gets sent when a request is made\n# for the stathost.  If this file doesn't exist a basic page is\n# hardcoded in tinyproxy.\n#\nStatFile \"/usr/share/tinyproxy/stats.html\"\n\n#\n# Logfile: Allows you to specify the location where information should\n# be logged to.  If you would prefer to log to syslog, then disable this\n# and enable the Syslog directive.  These directives are mutually\n# exclusive.\n#\nLogfile \"/var/log/tinyproxy/tinyproxy.log\"\n\n#\n# LogLevel:\n#\n# Set the logging level. Allowed settings are:\n#       Critical        (least verbose)\n#       Error\n#       Warning\n#       Notice\n#       Connect         (to log connections without Info's noise)\n#       Info            (most verbose)\n#\n# The LogLevel logs from the set level and above. For example, if the\n# LogLevel was set to Warning, then all log messages from Warning to\n# Critical would be output, but Notice and below would be suppressed.\n#\nLogLevel {{ tinyproxy_log_level }}\n\n#\n# PidFile: Write the PID of the main tinyproxy thread to this file so it\n# can be used for signalling purposes.\n#\nPidFile \"{{ tinyproxy_pid_file }}\"\n\n#\n# MaxClients: This is the absolute highest number of threads which will\n# be created. In other words, only MaxClients number of clients can be\n# connected at the same time.\n#\nMaxClients {{ [vpn_clients * 4,50]|min() }}\n\n#\n# MinSpareServers/MaxSpareServers: These settings set the upper and\n# lower limit for the number of spare servers which should be available.\n#\n# If the number of spare servers falls below MinSpareServers then new\n# server processes will be spawned.  If the number of servers exceeds\n# MaxSpareServers then the extras will be killed off.\n#\nMinSpareServers 5\nMaxSpareServers 20\n\n#\n# StartServers: The number of servers to start initially.\n#\nStartServers 10\n\n#\n# MaxRequestsPerChild: The number of connections a thread will handle\n# before it is killed. In practise this should be set to 0, which\n# disables thread reaping. If you do notice problems with memory\n# leakage, then set this to something like 10000.\n#\nMaxRequestsPerChild 0\n\n#\n# Allow: Customization of authorization controls. If there are any\n# access control keywords then the default action is to DENY. Otherwise,\n# the default action is ALLOW.\n#\n# The order of the controls are important. All incoming connections are\n# tested against the controls based on order.\n#\nAllow {{ tinyproxy_listen_address }}\nAllow {{ streisand_ipv4_address }}\n\n#\n# ViaProxyName: The \"Via\" header is required by the HTTP RFC, but using\n# the real host name is a security concern.  If the following directive\n# is enabled, the string supplied will be used as the host name in the\n# Via header; otherwise, the server's host name will be used.\n#\nViaProxyName \"tinyproxy\"\n\n#\n# ConnectPort: This is a list of ports allowed by tinyproxy when the\n# CONNECT method is used.  To disable the CONNECT method altogether, set\n# the value to 0.  If no ConnectPort line is found, all ports are\n# allowed (which is not very secure.)\n#\n# The following two ports are used by SSL.\n#\nConnectPort 443\nConnectPort 563\n"
  },
  {
    "path": "playbooks/roles/tinyproxy/templates/tinyproxy.service.j2",
    "content": "[Unit]\nDescription=tinyproxy - a light-weight HTTP/HTTPS proxy daemon for POSIX operating systems\nAfter=network-online.target sshd.service\nDocumentation=man:tinyproxy(8)\nDocumentation=https://www.banu.com/tinyproxy/\n\n[Service]\nType=forking\nPIDFile={{ tinyproxy_pid_file }}\nExecStart=/usr/sbin/tinyproxy -c {{ tinyproxy_conf_file }}\nExecStop=/usr/bin/killall -9 tinyproxy\nExecReload=/bin/kill -HUP $MAINPID\nPrivateTmp=true\nRestartSec=5s\nRestart=on-failure\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "playbooks/roles/tinyproxy/templates/tinyproxytmp.conf.j2",
    "content": "# Allow systemd to create a directory for\n# tinyproxy to write its PID file\n# https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html\nd {{ tinyproxy_pid_dir }} 0755 nobody nogroup -\n"
  },
  {
    "path": "playbooks/roles/tinyproxy/vars/main.yml",
    "content": "---\ntinyproxy_timeout_seconds: 600\ntinyproxy_port: 8888\n\ntinyproxy_listen_address: \"127.0.0.1\"\ntinyproxy_log_level: \"Critical\"\n\ntinyproxy_pid_dir: \"/var/run/tinyproxy\"\ntinyproxy_pid_file: \"{{ tinyproxy_pid_dir }}/tinyproxy.pid\"\n\ntinyproxy_conf_dir: \"/etc/tinyproxy\"\ntinyproxy_conf_file: \"{{ tinyproxy_conf_dir }}/tinyproxy.conf\"\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/defaults/main.yml",
    "content": "---\ntor_orport: 8443\ntor_obfs4_port: 9443\n\n# By default Streisand does *not* publish the Tor relay's service descriptor to\n# the tor network. Using a value of 0 ensures the relay is private to the\n# streisand operator and their users. See the Tor documentation[0] for more\n# information:\n# [0]: https://www.torproject.org/docs/tor-manual.html.en#PublishServerDescriptor\n#\ntor_publish_service_desc: 0\n\n# If you would like to contribute to the overall health of the Tor network by\n# submitting your bridge relay for use by others comment out the\n# `tor_publish_service_desc: 0` line above and uncomment the following line:\n#\n# tor_publish_service_desc: \"bridge\"\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/files/apparmor-local-override",
    "content": "# Site-specific additions and overrides for system_tor.\n# For more details, please see /etc/apparmor.d/local/README.\n\n# Workaround https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=862993\n# Tor v0.3.0.9 fails to read /var/lib/tor/hidden_service without this\n# app armor capability override\ncapability dac_read_search,\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/handlers/main.yml",
    "content": "---\n- name: Restart Nginx for the Tor hidden service vhost\n  service:\n    name: nginx\n    state: restarted\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/meta/main.yml",
    "content": "---\ndependencies:\n  # Tor needs to be added to the firewall\n  - { role: ufw }\n  # Tor needs to ensure Nginx is installed to host the hidden service vhost\n  - { role: nginx }\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/tasks/docs.yml",
    "content": "---\n- name: Create the Tor Gateway directory\n  file:\n    path: \"{{ tor_gateway_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0750\n    state: directory\n\n- name: Generate the Tor obfs4 QR code\n  shell: echo -n '{{ tor_obfs4_bridge_line }}' | qrencode -s 6 -o {{ tor_obfs4_qr_code }}\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"Tor\"\n    i18n_location: \"{{ tor_gateway_location }}\"\n    input_template_name: \"instructions\"\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/tasks/firewall.yml",
    "content": "---\n- name: Ensure UFW allows Tor bridge\n  ufw:\n    to_port: \"{{ tor_orport }}\"\n    proto: \"tcp\"\n    rule: \"allow\"\n\n- name: Ensure UFW allows Tor obfs4 pluggable transport\n  ufw:\n    to_port: \"{{ tor_obfs4_port }}\"\n    proto: \"tcp\"\n    rule: \"allow\"\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/tasks/main.yml",
    "content": "---\n- name: \"Add the Tor APT key\"\n  apt_key:\n    url: \"https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc\"\n    state: present\n\n- name: Add the Tor repository\n  apt_repository:\n    repo: 'deb https://deb.torproject.org/torproject.org {{ ansible_lsb.codename }} main'\n  register: tor_add_apt_repository\n  until: not tor_add_apt_repository.failed\n  retries: \"{{ apt_repository_retries }}\"\n  delay: \"{{ apt_repository_delay }}\"\n\n- name: Install the package to keep the Tor signing key current\n  apt:\n    package: deb.torproject.org-keyring\n\n- name: Install obfs4 and Tor\n  apt:\n    package:\n      - obfs4proxy\n      - tor\n\n# Update the firewall to allow Tor and obfs4proxy\n# NOTE(@cpu): we do this early in the role because the Tor daemon will check if\n# the obfs4proxy port is externally accessible during startup and we want to\n# make sure it is.\n- import_tasks: firewall.yml\n\n- name: Generate a random Nickname for the bridge\n  shell: \"{{ streisand_word_gen.tor_nickname | trim }} > {{ tor_bridge_nickname_file }}\"\n  args:\n    creates: \"{{ tor_bridge_nickname_file }}\"\n\n- name: Register the bridge's random Nickname\n  command: cat {{ tor_bridge_nickname_file }}\n  register: tor_bridge_nickname\n  changed_when: False\n\n- name: Generate the bridge config file\n  template:\n    src: torrc.j2\n    dest: /etc/tor/torrc\n    owner: root\n    group: root\n    mode: 0644\n\n# TODO(@cpu) - This should be removed once it isn't required, maybe in the next\n# release after tor 0.3.0.9\n- name: Copy a local override for the Tor AppArmor profile in place\n  copy:\n    src: apparmor-local-override\n    dest: /etc/apparmor.d/local/system_tor\n    owner: root\n    group: root\n    mode: 0644\n\n# TODO(@cpu) - In theory it seems like it should be possible to add the\n# following to the local override from above:\n#     /usr/bin/obfsproxy ix,\n#     /usr/bin/obfs4proxy ix,\n# but doing so results in an error from the existing `PUx` modifiers:\n#     profile system_tor: has merged rule /usr/bin/obfs4proxy with conflicting x modifiers\n# in the interest of fixing a regression we work around this by changing the\n# dist provided `/etc/apparmor.d/abstractions/tor` file.\n- name: Fix the distro Tor apparmor abstraction\n  replace:\n    path: /etc/apparmor.d/abstractions/tor\n    regexp: '^([\\s]*)/usr/bin/(obfs4?proxy) PUx,$'\n    replace: '\\1/usr/bin/\\2 ix,'\n    backup: yes\n\n- name: Reload the system_tor AppArmor profile for the override to take effect\n  command: apparmor_parser -r /etc/apparmor.d/system_tor\n\n- name: Restart Tor so the server fingerprint will be available in the state file, and the hidden service for the Gateway will start running\n  service:\n    name: tor\n    state: restarted\n\n- name: Wait until obfs4proxy information has shown up in its state file\n  wait_for:\n    path: \"{{ tor_obfs_state_directory }}/obfs4_state.json\"\n    search_regex: \"node-id\"\n\n- name: Wait until the hidden service is online\n  wait_for:\n    path: \"{{ tor_hidden_service_directory }}/hostname\"\n\n- name: Wait until the server fingerprint file is generated\n  wait_for:\n    path: \"{{ tor_state_directory }}/fingerprint\"\n\n- name: Register the Tor Hidden Service hostname\n  command: cat {{ tor_hidden_service_directory }}/hostname\n  register: tor_hidden_service_hostname_output\n  changed_when: False\n\n- name: Register the Tor Hidden Service URL fact\n  set_fact:\n    tor_hidden_service_url: \"http://{{ tor_hidden_service_hostname_output.stdout }}\"\n\n- name: Generate the hidden service virtual host and restart Nginx if it is updated\n  template:\n    src: hidden-service-vhost.j2\n    dest: /etc/nginx/sites-available/streisand-hidden-service\n    owner: root\n    group: root\n    mode: 0644\n  notify: Restart Nginx for the Tor hidden service vhost\n\n- name: Enable the virtual host\n  file:\n    path: /etc/nginx/sites-enabled/streisand-hidden-service\n    src: /etc/nginx/sites-available/streisand-hidden-service\n    state: link\n\n- name: Discover the server fingerprint\n  command: \"awk '{ print $2 }' {{ tor_state_directory }}/fingerprint\"\n  register: tor_fingerprint\n\n- name: Discover the obfs4 certificate details\n  shell: cat \"{{ tor_obfs_state_directory }}/obfs4_bridgeline.txt\" | grep 'Bridge obfs4' | sed -e 's/^.*cert=\\(.*\\) .*$/\\1/'\n  register: tor_obfs4_certificate\n  changed_when: False\n\n# Generate the docs gateway page\n- import_tasks: docs.yml\n\n# This needs to be done after the docs folder structure is generated\n- name: Copy the hidden service hostname to the webroot when in test client mode\n  copy:\n    src: \"{{ tor_hidden_service_directory }}/hostname\"\n    remote_src: yes\n    dest: \"{{ tor_gateway_location }}/hidden-service-hostname.txt\"\n    force: yes\n\n# Mirror the Tor browser bundle\n- import_tasks: mirror.yml\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/tasks/mirror-common.yml",
    "content": "---\n- name: Make the directory where the Tor Project's mirrored files will be stored\n  file:\n    path: \"{{ tor_mirror_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0755\n    state: directory\n\n- name: Discover the latest stable version of the Tor Browser Bundle\n  # The Python code below can be cleaned up once the Tor Project has\n  # finished transitioning away from putting the OS suffix in the\n  # RecommendedTBBVersions file. This check should work with both\n  # formats though.\n  #\n  # https://trac.torproject.org/projects/tor/ticket/8940#comment:28\n  shell: curl -s 'https://www.torproject.org/projects/torbrowser/RecommendedTBBVersions/' | python -c 'import json; import re; import sys; j = json.load(sys.stdin); print [re.sub(r\"-.*$\", \"\", tbb) for tbb in j if \"a\" not in tbb and \"b\" not in tbb][-1];'\n  args:\n    warn: no\n  register: tor_latest_recommended_check\n\n- name: Set the target Tor Browser Bundle version\n  set_fact:\n    tor_browser_bundle_version: \"{{ tor_latest_recommended_check.stdout }}\"\n\n- name: Include the mirror variables for Tor Browser Bundle\n  include_vars: mirror.yml\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/tasks/mirror.yml",
    "content": "---\n- name: Include the Tor common variables\n  include_vars: mirror-common.yml\n\n- name: Include the Tor download variables\n  include_vars: mirror-download.yml\n\n- block:\n    # Include the mirror-common tasks\n    - import_tasks: mirror-common.yml\n\n      # Download the Tor browser in each locale, verifying GPG signatures.\n    - include_role:\n        name: download-and-verify\n      vars:\n        project_name: \"Tor Browser ({{ locale }})\"\n        project_download_baseurl: \"{{ tor_base_download_url }}\"\n        project_download_files: \"{{ tor_download_files }}\"\n        project_download_location: \"{{ tor_mirror_location }}\"\n        project_signer_keyid: \"{{ tor_signer_keyid }}\"\n      with_items: \"{{ streisand_languages.values() | map(attribute='tor_locale') | list }}\"\n      when: locale in tor_available_locales\n      loop_control:\n        loop_var: locale\n  rescue:\n    - name: \"{{ streisand_mirror_warning }}\"\n      pause:\n        seconds: \"{{ streisand_mirror_warning_seconds }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"Tor mirror\"\n    i18n_location: \"{{ tor_mirror_location }}\"\n    input_template_name: \"mirror\"\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/templates/hidden-service-vhost.j2",
    "content": "# Streisand Tor Hidden Service Gateway\nserver {\n  listen {{ tor_internal_hidden_service_address }};\n\n  auth_basic            \"Authorization Required\";\n  auth_basic_user_file  {{ streisand_gateway_htpasswd_file }};\n\n  # Disable all logging\n  access_log /dev/null;\n  error_log  /dev/null crit;\n\n  root  {{ streisand_gateway_location }};\n  index index.html index.htm;\n}\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/templates/instructions-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nPont Tor\n--------\n\n---\n* Plateformes\n  * [Ordinateurs de bureau](#desktops)\n  * [Android](#android)\n  * [iOS](#ios)\n\n<a name=\"desktops\"></a>\n### Ordinateurs de bureau ###\n1. Téléchargez le [Tor Browser Bundle](/mirror/tor/index-fr.html) Pour votre plate-forme de choix. Le transport enfichable Obfsproxy obfs4 qu'il inclut vous permettra d'utiliser le réseau Tor, même si votre FAI effectue activement une inspection Deep Packet afin de bloquer votre trafic Tor.\n1. Lancez Tor Browser Bundle.\n1. Cliquez le bouton *Configurer* sous le texte qui lit *La connexion Internet de cet ordinateur est censurée ou relayée*.\n1. Choisissez *Oui* pour la question *Votre fournisseur d'accès à Internet (FAI) bloque-t-il ou censure-t-il vos connexions au réseau Tor?*\n1. Choisissez l'option *Saisir les ponts personnalisés*, et coller les informations suivantes:\n\n         {{ tor_obfs4_bridge_line }}\n1. Répondez a la question du serveur mandataire locale. Dans la plupart des cas la réponse sera *Non*.\n1. Cliquez *Se Connecter*.\n\nVous êtes prêt à partir! Tor est connecté au serveur de pont *{{ tor_bridge_nickname.stdout }}*, et votre trafic Tor crypté est totalement obscurci par obfsproxy afin qu'il ne ressemble pas au trafic Tor!\n\n<a name=\"android\"></a>\n### Android ###\n1. Téléchargez [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android&hl=fr) et lancez-le.\n1. Tapez le bouton *Menu*.\n1. Tapdz *QR Codes*.\n1. Tapez *Analyser BridgeQR*.\n1. Scannez le code QR suivant. Cela configurera automatiquement Orbot pour se connecter à ce serveur en utilisant le transport enfichable obfs4:\n\n   ![Tor obfs4 QR code](/tor/tor-obfs4-qr-code.png)\n1. Vous devez redémarrer Orbot pour que les modifications prennent effet. Tapez sur le bouton *Menu*, sélectionnez *Quitter*, et lancer Orbot à nouveau.\n1. Appuyez sur le bouton *DÉMARRER* pour activer Orbot.\n\nGénial! Orbot s'est connecté au serveur pont *{{ tor_bridge_nickname.stdout }}*!\n\nVous êtes maintenant prêt à configurer Twitter et Firefox pour acheminer leur trafic via Orbot.\n\n#### Configuration de Twitter pour Android pour utiliser Orbot ####\n1. Ouvrez Twitter.\n1. Accedez au menu de paramètres et confidentialité.\n1. Choisissez *Position et proxy*.\n1. Tapez *Proxy*.\n1. Chocher *Activer le proxy HTTP*.\n1. Tapez *Hôte du proxy* et entrez `127.0.0.1`.\n1. Tapez *Port du proxy* et entrez `8118`.\n\n#### Configuration de Firefox pour Android pour utiliser Orbot ####\n1. Ouvrez Firefox.\n2. Tapez `about:config` dans la barre d'adresse et appuyez sur le bouton 'Go' de votre clavier.\n3. Tapez `proxy` dans la barre de recherche.\n4. Définissez la valeur de *network.proxy.socks* à `127.0.0.1`.\n5. Définissez la valeur de *network.proxy.socks\\_port* à `9050`.\n6. Définissez la valeur de *network.proxy.socks\\_remote\\_dns* à `true`.\n7. Définissez la valeur de *network.proxy.type* à `1`.\n\n\n<!--\nApp is not localized in French -@alimakki\n-->\n<a name=\"ios\"></a>\n### iOS ###\n1. Téléchargez [Onion Browser](https://itunes.apple.com/fr/app/onion-browser/id519296448?mt=8) et lancez-le.\n1. Tapez le bouton menu sur le bas de l'écran et choisissez *Browser Settings*.\n1. Faites défiler jusqu'au bas et appuyez sur *Bridges & Netwrok Connection*\n1. Sélectionnez *Custom Bridges*\n1. TAppuyez sur l'icône de la caméra dans le coin inférieur droit. Vous devrez peut-être avoir besoin d'activer l'accès de la caméra pour Onion Browser dans vos paramètres iOS.\n1. Scannez le code QR suivant. Cela configurera automatiquement le navigateur Onion pour se connecter à ce serveur à l'aide du transport enfichable obfs4:\n\n   ![Tor obfs4 QR code](/tor/tor-obfs4-qr-code.png)\n1. Tapez *OK* l'orsque la confirmation est affichée.\n1. Tapez *Save*.\n1. Tapez *Restart app*.\n1. Relancez l'application. Si vous vous connectez avec succès, le pont *{{ tor_bridge_nickname.stdout }}* fonctionne correctement et votre connexion est obscurcie par le transport enfichable obfs4!\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/templates/instructions.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nTor Bridge\n----------\n\n---\n* Platforms\n  * [Desktops](#desktops)\n  * [Android](#android)\n  * [iOS](#ios)\n\n<a name=\"desktops\"></a>\n### Desktops ###\n1. Download the [Tor Browser Bundle](/mirror/tor/) for your platform of choice. The Obfsproxy obfs4 pluggable transport that it includes will let you use the Tor network even if your ISP is actively performing Deep Packet Inspection in an attempt to block all Tor traffic.\n1. Launch the Tor Browser Bundle.\n1. Click the *Configure* button underneath the text that says *I need to configure bridge, firewall, or proxy settings*.\n1. Answer *Yes* to *Does your Internet Service Provider (ISP) block or otherwise censor connections to the Tor Network?*\n1. Choose the *Enter custom bridges* option, and paste the following information into the text box:\n\n         {{ tor_obfs4_bridge_line }}\n1. Answer the Local Proxy Configuration question. In most cases the answer will be *No*.\n1. Click *Connect*.\n\nYou are ready to go! Tor has connected to the *{{ tor_bridge_nickname.stdout }}* bridge server, and your encrypted Tor traffic is completely obscured by obfsproxy so it doesn't look like Tor traffic at all!\n\n<a name=\"android\"></a>\n### Android ###\n1. Download [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android) and launch it.\n1. Tap the *Menu* button.\n1. Tap *QR Codes*.\n1. Tap *Scan BridgeQR*.\n1. Scan the following QR code. This will automatically configure Orbot to connect to this server using the obfs4 pluggable transport:\n\n   ![Tor obfs4 QR code](/tor/tor-obfs4-qr-code.png)\n1. You must restart Orbot in order for the changes to take effect. Tap the *Menu* button, select *Exit*, and launch Orbot again.\n1. Long press on the power button to activate Orbot.\n\nGreat! Orbot has connected to the *{{ tor_bridge_nickname.stdout }}* bridge server!\n\nYou are now ready to configure Twitter and Firefox to route their traffic through Orbot.\n\n#### Configuring Twitter for Android to use Orbot ####\n1. Open Twitter.\n1. Tap the three dots in the upper-right of the screen to open the menu.\n1. Choose *Settings*.\n1. Tap *General*.\n1. Tap *Proxy*.\n1. Check the *Enable HTTP Proxy* checkbox.\n1. Tap *Proxy Host* and enter `127.0.0.1`.\n1. Tap *Proxy Port* and enter `8118`.\n\n#### Configuring Firefox for Android to use Orbot ####\n1. Open Firefox.\n1. Type `about:config` into the address bar and tap the *Go* button on your keyboard.\n1. Type `proxy` into the search box.\n1. Set the value of *network.proxy.socks* to `127.0.0.1`.\n1. Set the value of *network.proxy.socks_port* to `9050`.\n1. Set the value of *network.proxy.socks\\_remote\\_dns* to `true`.\n1. Set the value of *network.proxy.type* to `1`.\n\n<a name=\"ios\"></a>\n### iOS ###\n1. Download [Onion Browser](https://itunes.apple.com/us/app/onion-browser/id519296448?mt=8) and launch it.\n1. Tap the menu button on the bottom of the screen and choose *Browser Settings*.\n1. Scroll to the bottom and tap *Configure Bridges*\n1. Tap *Enter Custom Bridges*.\n1. Tap the camera icon in the lower-right corner. You may need to enable camera access for Onion Browser in your iOS Settings.\n1. Scan the following QR code. This will automatically configure Onion Browser to connect to this server using the obfs4 pluggable transport:\n\n   ![Tor obfs4 QR code](/tor/tor-obfs4-qr-code.png)\n1. Tap *OK* when the confirmation is displayed.\n1. Tap *Save*.\n1. Tap *Restart app*.\n1. Relaunch the application. If you successfully connect, the *{{ tor_bridge_nickname.stdout }}* bridge is working correctly, and your connection is obscured by the obfs4 pluggable transport so it doesn't look like Tor traffic at all!\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/templates/mirror-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"tor\"></a>\n### Tor Browser Bundle (localisé en français) ###\n\n**Linux**\n\n* [{{ tor_linux32_filename_template | regex_replace('locale', item.value.tor_locale) }}]({{ tor_linux32_href | regex_replace('locale', item.value.tor_locale) }}) ([sig]({{ tor_linux32_sig_href | regex_replace('locale', item.value.tor_locale) }}))\n* [{{ tor_linux64_filename_template | regex_replace('locale', item.value.tor_locale) }}]({{ tor_linux64_href | regex_replace('locale', item.value.tor_locale) }}) ([sig]({{ tor_linux64_sig_href | regex_replace('locale', item.value.tor_locale) }}))\n\n**macOS**\n\n* [{{ tor_macos_filename_template | regex_replace('locale', item.value.tor_locale) }}]({{ tor_macos_href | regex_replace('locale', item.value.tor_locale) }}) ([sig]({{ tor_macos_sig_href | regex_replace('locale', item.value.tor_locale) }}))\n\n**Windows**\n\n* [{{ tor_windows_filename_template |  regex_replace('locale', item.value.tor_locale) }}]({{ tor_windows_href | regex_replace('locale', item.value.tor_locale) }}) ([sig]({{ tor_windows_sig_href | regex_replace('locale', item.value.tor_locale) }}))\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/templates/mirror.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\n<a name=\"tor\"></a>\n### Tor Browser Bundle ###\n\n**Linux**\n\n* [{{ tor_linux32_filename_template | regex_replace('locale', item.value.tor_locale)  }}]({{ tor_linux32_href | regex_replace('locale', item.value.tor_locale) }}) ([sig]({{ tor_linux32_sig_href | regex_replace('locale', item.value.tor_locale) }}))\n* [{{ tor_linux64_filename_template | regex_replace('locale', item.value.tor_locale)  }}]({{ tor_linux64_href | regex_replace('locale', item.value.tor_locale) }}) ([sig]({{ tor_linux64_sig_href | regex_replace('locale', item.value.tor_locale) }}))\n\n**macOS**\n\n* [{{ tor_macos_filename_template | regex_replace('locale', item.value.tor_locale) }}]({{ tor_macos_href | regex_replace('locale', item.value.tor_locale) }}) ([sig]({{ tor_macos_sig_href | regex_replace('locale', item.value.tor_locale) }}))\n\n**Windows**\n\n* [{{ tor_windows_filename_template | regex_replace('locale', item.value.tor_locale) }}]({{ tor_windows_href | regex_replace('locale', item.value.tor_locale) }}) ([sig]({{ tor_windows_sig_href | regex_replace('locale', item.value.tor_locale) }}))\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/templates/torrc.j2",
    "content": "SocksPort 0\nORPort {{ tor_orport }}\nExtORPort auto\nBridgeRelay 1\nPublishServerDescriptor {{ tor_publish_service_desc }}\nExitPolicy reject *:*\n\nNickname {{ tor_bridge_nickname.stdout }}\n\nServerTransportPlugin obfs4 exec /usr/bin/obfs4proxy\nServerTransportListenAddr obfs4 0.0.0.0:{{ tor_obfs4_port }}\n\nHiddenServiceDir {{ tor_hidden_service_directory }}\nHiddenServicePort 80 {{ tor_internal_hidden_service_address }}\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/vars/main.yml",
    "content": "---\ntor_bridge_nickname_file: \"/etc/tor/bridge_nickname\"\n\ntor_standard_connection_details: \"{{ streisand_ipv4_address }}:{{ tor_orport }}\"\n\ntor_obfs4_bridge_line: \"obfs4 {{ streisand_ipv4_address }}:{{ tor_obfs4_port }} {{ tor_fingerprint.stdout }} cert={{ tor_obfs4_certificate.stdout }} iat-mode=0\"\n\ntor_state_directory: \"/var/lib/tor\"\n\ntor_hidden_service_directory: \"{{ tor_state_directory }}/hidden_service/\"\n\ntor_obfs_state_directory: \"{{ tor_state_directory }}/pt_state\"\n\ntor_gateway_location: \"{{ streisand_gateway_location }}/tor\"\n\ntor_markdown_instructions: \"{{ tor_gateway_location }}/index.md\"\ntor_html_instructions: \"{{ tor_gateway_location }}/index.html\"\n\ntor_obfs4_qr_code: \"{{ tor_gateway_location }}/tor-obfs4-qr-code.png\"\n\ntor_internal_hidden_service_address: \"127.0.0.1:8181\"\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/vars/mirror-common.yml",
    "content": "---\n# Tor common variables\n# --------------------\n\ntor_project_name: \"Tor Browser Bundle\"\n\ntor_mirror_location: \"{{ streisand_mirror_location }}/tor\"\ntor_mirror_href_base: \"/mirror/tor\"\n\ntor_base_download_url: \"https://dist.torproject.org/torbrowser/{{ tor_browser_bundle_version }}\"\n\ntor_available_locales:\n  - ar\n  - de\n  - en-US\n  - es-ES\n  - fa\n  - fr\n  - it\n  - ja\n  - ko\n  - nl\n  - pl\n  - pt-BR\n  - ru\n  - tr\n  - vi\n  - zh-CN\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/vars/mirror-download.yml",
    "content": "---\n# Tor download variables\n# ----------------------\n\n# Windows\ntor_browser_bundle_windows_filename: \"{{ tor_windows_filename_base }}_{{ locale }}.exe\"\ntor_browser_bundle_windows_sig_filename: \"{{ tor_browser_bundle_windows_filename }}.asc\"\n\n# macOS\ntor_browser_bundle_macos_filename: \"{{ tor_macos_filename_base }}_{{ locale }}.dmg\"\ntor_browser_bundle_macos_sig_filename: \"{{ tor_browser_bundle_macos_filename }}.asc\"\n\n# Linux 32bit\ntor_browser_bundle_linux32_filename: \"{{ tor_linux32_filename_base }}_{{ locale }}.tar.xz\"\ntor_browser_bundle_linux32_sig_filename: \"{{ tor_browser_bundle_linux32_filename }}.asc\"\n\n# Linux 64bit\ntor_browser_bundle_linux64_filename: \"{{ tor_linux64_filename_base }}_{{ locale }}.tar.xz\"\ntor_browser_bundle_linux64_sig_filename: \"{{ tor_browser_bundle_linux64_filename }}.asc\"\n\ntor_signer_keyid: \"D9FF06E2\"\n\ntor_download_files:\n  - { \"file\": \"{{ tor_browser_bundle_windows_filename }}\", \"sig\": \"{{ tor_browser_bundle_windows_sig_filename }}\" }\n  - { \"file\": \"{{ tor_browser_bundle_macos_filename }}\", \"sig\": \"{{ tor_browser_bundle_macos_sig_filename  }}\" }\n  - { \"file\": \"{{ tor_browser_bundle_linux32_filename }}\", \"sig\": \"{{ tor_browser_bundle_linux32_sig_filename  }}\" }\n  - { \"file\": \"{{ tor_browser_bundle_linux64_filename }}\", \"sig\": \"{{ tor_browser_bundle_linux64_sig_filename  }}\" }\n"
  },
  {
    "path": "playbooks/roles/tor-bridge/vars/mirror.yml",
    "content": "---\n# Tor mirror variables\n# --------------------\ntor_mirror_location: \"{{ streisand_mirror_location }}/tor\"\n\ntor_windows_filename_base: \"torbrowser-install-{{ tor_browser_bundle_version }}\"\ntor_windows_filename_template: \"{{ tor_windows_filename_base }}_locale.exe\"\ntor_windows_sig_filename_template: \"{{ tor_windows_filename_template }}.asc\"\ntor_windows_href: \"{{ tor_mirror_href_base }}/{{ tor_windows_filename_template }}\"\ntor_windows_sig_href: \"{{ tor_mirror_href_base }}/{{ tor_windows_sig_filename_template }}\"\n\ntor_macos_filename_base: \"TorBrowser-{{ tor_browser_bundle_version }}-osx64\"\ntor_macos_filename_template: \"{{ tor_macos_filename_base }}_locale.dmg\"\ntor_macos_sig_filename_template: \"{{ tor_macos_filename_template }}.asc\"\ntor_macos_href: \"{{ tor_mirror_href_base }}/{{ tor_macos_filename_template }}\"\ntor_macos_sig_href: \"{{ tor_mirror_href_base }}/{{ tor_macos_sig_filename_template }}\"\n\ntor_linux32_filename_base: \"tor-browser-linux32-{{ tor_browser_bundle_version }}\"\ntor_linux32_filename_template: \"{{ tor_linux32_filename_base }}_locale.tar.xz\"\ntor_linux32_sig_filename_template: \"{{ tor_linux32_filename_template }}.asc\"\ntor_linux32_href: \"{{ tor_mirror_href_base }}/{{ tor_linux32_filename_template }}\"\ntor_linux32_sig_href: \"{{ tor_mirror_href_base }}/{{ tor_linux32_sig_filename_template }}\"\n\ntor_linux64_filename_base: \"tor-browser-linux64-{{ tor_browser_bundle_version }}\"\ntor_linux64_filename_template: \"{{ tor_linux64_filename_base }}_locale.tar.xz\"\ntor_linux64_sig_filename_template: \"{{ tor_linux64_filename_template }}.asc\"\ntor_linux64_href: \"{{ tor_mirror_href_base }}/{{ tor_linux64_filename_template }}\"\ntor_linux64_sig_href: \"{{ tor_mirror_href_base }}/{{ tor_linux64_sig_filename_template }}\"\n"
  },
  {
    "path": "playbooks/roles/ufw/tasks/main.yml",
    "content": "---\n- name: Install UFW\n  apt:\n    package: ufw\n\n- name: Disable UFW logging\n  lineinfile:\n    dest: /etc/ufw/ufw.conf\n    regexp: \"^LOGLEVEL\"\n    line: \"LOGLEVEL=off\"\n\n- name: Change the default forward policy\n  lineinfile:\n    dest: /etc/default/ufw\n    regexp: \"^DEFAULT_FORWARD_POLICY\"\n    line: 'DEFAULT_FORWARD_POLICY=\"ACCEPT\"'\n\n- name: Ensure UFW allows SSH\n  ufw:\n    to_port: \"{{ ssh_port }}\"\n    proto: \"tcp\"\n    rule: \"allow\"\n\n- name: Ensure UFW is enabled and denies by default\n  ufw:\n    state: \"enabled\"\n    policy: \"deny\"\n    direction: \"incoming\"\n\n- name: Ensure UFW allows nginx\n  ufw:\n    to_port: \"{{ nginx_port }}\"\n    proto: \"tcp\"\n    rule: \"allow\"\n"
  },
  {
    "path": "playbooks/roles/validation/defaults/main.yml",
    "content": "streisand_new_server_provisioning: true\n"
  },
  {
    "path": "playbooks/roles/validation/tasks/main.yml",
    "content": "---\n# Check SSH key exists\n- include: ssh.yml\n\n- name: Validate that OpenVPN optional variables are rational\n  fail:\n    msg: \"stunnel cannot be enabled if openvpn is disabled\"\n  when: not streisand_openvpn_enabled and streisand_stunnel_enabled\n\n- name: Validate that Tinyproxy optional variables are rational\n  fail:\n    msg: \"tinyproxy cannot be enabled if ssh forward user is disabled\"\n  when: not streisand_ssh_forward_enabled and streisand_tinyproxy_enabled\n\n- name: Validate that sshutle optional variables are rational\n  fail:\n    msg: \"streisand_sshuttle_enabled cannot be enabled if ssh forward user is disabled\"\n  when: not streisand_ssh_forward_enabled and streisand_sshuttle_enabled\n\n# tl;dr: increase vpn_clients beyond 20 at your own risk.\n#\n# We currently *support* up to 20 VPN client credentials. If you'd\n# like more, raising the limit might even work!  20 is conservative,\n# 50 is probably OK.  If you'd like to help us increase it, success\n# stories at https://github.com/StreisandEffect/discussions would be\n# nice. We can raise the limit after sufficient testing with each of\n# the VPN types.\n#\n# Places you'll run into trouble if you use more:\n#\n# * Generated documentation will become unwieldy.\n#\n# * OpenVPN, OpenConnect, and WireGuard each use /24 networks\n#   internally. Addresses 0, 1, and 255 are unavailable, leaving 253\n#   remaining.\n#\n#   o  OpenVPN and OpenConnect dynamically allocate addresses, so\n#      that's just a limit on concurrent users.\n#\n#   o  WireGuard permanently associates an IP address per client\n#      credential, so that's a hard limit of 253 generated\n#      certificates.\n#\n# * Generated client names are not checked/generated for\n#   uniqueness. (This will be fixed.)  Duplicates will cause\n#   mysterious failures. At 20 generated names, this essentially\n#   doesn't happen, but because of the birthday paradox, 200 users\n#   gives odds of 0.5%, I think.\n#\n# * There may be other resource exhaustion issues with large numbers\n#   of concurrent users.\n#\n#   Protocols like SSH and Shadowsocks don't have per-user\n#   credentials, so changing vpn_clients doesn't affect them. However,\n#   the vpn_clients value is our guess for what's safe for them.\n#\n#   Streisand operates over difficult-to-debug networks. The\n#   possibility of resource exhaustion may make troubleshooting other\n#   problems harder.\n#\n# Summary: When reporting problems, please try to reproduce them with\n# vpn_clients set to 20 or less. 50 is probably fine. 254 will fail to\n# deploy.\n\n- name: Validate that the maximum number of clients is set to a reasonable amount\n  when: (vpn_clients > 20) or (vpn_clients < 1)\n  fail:\n    msg: |-\n      Too many VPN clients specified. vpn_clients must be between 1 and 20.\n\n         See playbooks/roles/validation/tasks/main.yml.\n- name: Validate that at least one VPN is specified\n  fail:\n    msg: \"At least one Streisand VPN service must be enabled.\"\n  when: (not streisand_openconnect_enabled)\n    and (not streisand_openvpn_enabled)\n    and (not streisand_shadowsocks_enabled)\n    and (not streisand_ssh_forward_enabled)\n    and (not streisand_tor_enabled)\n    and (not streisand_wireguard_enabled)\n"
  },
  {
    "path": "playbooks/roles/validation/tasks/ssh.yml",
    "content": "---\n- block:\n    - name: \"Stat the Streisand SSH private key\"\n      stat:\n        path: \"{{ streisand_ssh_private_key }}\"\n      register: streisand_ssh_private_key_status\n    - name: \"Fail if the Streisand SSH private key file doesn't exist\"\n      fail:\n        msg: \"The Streisand SSH private key \\\"{{ streisand_ssh_private_key }}\\\" does not exist.\"\n      when: streisand_ssh_private_key_status.stat.exists == False\n    - name: \"Stat the Streisand SSH public key\"\n      stat:\n        path: \"{{ streisand_ssh_private_key }}.pub\"\n      register: streisand_ssh_key_status\n      when: streisand_new_server_provisioning\n    - name: \"Fail if the Streisand SSH public key file doesn't exist\"\n      fail:\n        msg: \"The Streisand SSH public key \\\"{{ streisand_ssh_private_key }}.pub\\\" does not exist.\"\n      when:\n        - streisand_new_server_provisioning\n        - not streisand_ssh_key_status.stat.exists\n  rescue:\n    - fail:\n        msg: \"Ensure you specified an existing SSH private key file. Ensure a corresponding SSH public key file exists if you are setting up a new server.\\n Try using `ssh-keygen -f {{ streisand_ssh_private_key }} to generate your key if it does not exist\\n\"\n"
  },
  {
    "path": "playbooks/roles/wireguard/defaults/main.yml",
    "content": "---\nwireguard_port: \"51820\"\n"
  },
  {
    "path": "playbooks/roles/wireguard/meta/main.yml",
    "content": "---\ndependencies:\n  - { role: dnsmasq }\n  - { role: ip-forwarding }\n"
  },
  {
    "path": "playbooks/roles/wireguard/tasks/docs.yml",
    "content": "---\n- name: Create the WireGuard Gateway directory\n  file:\n    path: \"{{ wireguard_gateway_location }}\"\n    owner: www-data\n    group: www-data\n    mode: 0750\n    state: directory\n\n- name: Copy the client configuration files to the WireGuard Gateway directory\n  command: \"cp {{ wireguard_client_path }}/{{ client_name.stdout }}/client.conf {{ wireguard_gateway_location }}/{{ client_name.stdout }}.conf\"\n  args:\n    creates: \"{{ wireguard_gateway_location }}/{{ client_name.stdout }}.conf\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: Generate the client configuration QR codes in the WireGuard Gateway directory\n  shell: \"qrencode -s 6 -o {{ wireguard_gateway_location }}/{{ client_name.stdout }}.png < {{ wireguard_gateway_location }}/{{ client_name.stdout }}.conf\"\n  args:\n    creates: \"{{ wireguard_gateway_location }}/{{ client_name.stdout }}.png\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: Copy the client OpenWrt configuration fragments to the WireGuard Gateway directory\n  command: \"cp {{ wireguard_client_path }}/{{ client_name.stdout }}/client-openwrt.txt {{ wireguard_gateway_location }}/{{ client_name.stdout }}-openwrt.txt\"\n  args:\n    creates: \"{{ wireguard_gateway_location }}/{{ client_name.stdout }}-openwrt.txt\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- include_role:\n    name: i18n-docs\n  vars:\n    title: \"WireGuard\"\n    i18n_location: \"{{ wireguard_gateway_location }}\"\n    input_template_name: \"instructions\"\n"
  },
  {
    "path": "playbooks/roles/wireguard/tasks/firewall.yml",
    "content": "---\n- name: Ensure UFW allows DNS requests from WireGuard clients\n  ufw:\n    to_port: \"53\"\n    proto: \"udp\"\n    rule: \"allow\"\n    from_ip: \"10.192.122.0/24\"\n\n- name: Ensure UFW allows WireGuard\n  ufw:\n    to_port: \"{{ wireguard_port }}\"\n    proto: \"udp\"\n    rule: \"allow\"\n\n- name: Allow WireGuard through the firewall\n  command: \"{{ item }}\"\n  with_items: \"{{ wireguard_firewall_rules }}\"\n\n- name: \"Add WireGuard firewall persistence service to init\"\n  template:\n    src: streisand-wireguard-service.sh.j2\n    dest: /etc/init.d/streisand-wireguard\n    mode: 0755\n\n- name: \"Enable the streisand-wireguard init service\"\n  service:\n    name: streisand-wireguard\n    enabled: yes\n"
  },
  {
    "path": "playbooks/roles/wireguard/tasks/install.yml",
    "content": "---\n\n- name: Determine the running kernel release\n  command: uname -r\n  register: kernel_release\n\n- name: Add the WireGuard PPA\n  apt_repository:\n    repo: 'ppa:wireguard/wireguard'\n  register: wireguard_add_apt_repository\n  until: not wireguard_add_apt_repository.failed\n  retries: \"{{ apt_repository_retries }}\"\n  delay: \"{{ apt_repository_delay }}\"\n\n- name: Install the WireGuard packages\n  apt:\n    package:\n      - linux-headers-{{ kernel_release.stdout }}\n      - linux-headers-generic\n      - wireguard-dkms\n      - wireguard-tools\n"
  },
  {
    "path": "playbooks/roles/wireguard/tasks/main.yml",
    "content": "---\n\n# Set up the PPA and install packages\n- import_tasks: install.yml\n\n- name: Generate private and public key for the server\n  shell: \"umask 077; wg genkey | tee {{ wireguard_server_private_key_file }} | wg pubkey > {{ wireguard_server_public_key_file }}\"\n  args:\n    creates: \"{{ wireguard_server_public_key_file }}\"\n\n- name: Register the server key file contents\n  command: cat {{ item }}\n  register: wireguard_server_key_files\n  changed_when: False\n  with_items:\n    - \"{{ wireguard_server_private_key_file }}\"\n    - \"{{ wireguard_server_public_key_file }}\"\n\n- name: Set the server key material facts\n  set_fact:\n    wireguard_server_private_key: \"{{ wireguard_server_key_files.results[0].stdout }}\"\n    wireguard_server_public_key:  \"{{ wireguard_server_key_files.results[1].stdout }}\"\n\n- name: Create client directory\n  file:\n    path: \"{{ wireguard_client_path }}\"\n    state: directory\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Create a directory for each client\n  file:\n    path: \"{{ wireguard_client_path }}/{{ client_name.stdout }}\"\n    state: directory\n    owner: root\n    group: root\n    mode: 0600\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: Generate private and public key for each client\n  shell: \"umask 077; wg genkey | tee client.key | wg pubkey > client.pub\"\n  args:\n    chdir: \"{{ wireguard_client_path }}/{{ client_name.stdout }}\"\n    creates: client.key\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n\n- name: Register client public keys\n  command: cat client.pub\n  args:\n    chdir: \"{{ wireguard_client_path }}/{{ client_name.stdout }}\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n  register: wireguard_client_pubkeys\n  changed_when: False\n\n- name: Register client private keys\n  command: cat client.key\n  args:\n    chdir: \"{{ wireguard_client_path }}/{{ client_name.stdout }}\"\n  with_items: \"{{ vpn_client_names.results }}\"\n  loop_control:\n    loop_var: \"client_name\"\n    label: \"{{ client_name.item }}\"\n  register: wireguard_client_privkeys\n  changed_when: False\n\n- name: Generate the client configuration profiles\n  template:\n    src: client.conf.j2\n    dest: \"{{ wireguard_client_path }}/{{ item[0].stdout }}/client.conf\"\n  with_together:\n    - \"{{ vpn_client_names.results }}\"\n    - \"{{ wireguard_client_privkeys.results }}\"\n  loop_control:\n    label: \"{{ item[0].item }}\"\n\n- name: Generate OpenWrt configuration fragments\n  template:\n    src: client-openwrt.txt.j2\n    dest: \"{{ wireguard_client_path }}/{{ item[0].stdout }}/client-openwrt.txt\"\n  with_together:\n    - \"{{ vpn_client_names.results }}\"\n    - \"{{ wireguard_client_privkeys.results }}\"\n  loop_control:\n    label: \"{{ item[0].item }}\"\n\n- name: Generate the server configuration\n  template:\n    src: \"server.conf.j2\"\n    dest: \"{{ wireguard_path }}/wg0.conf\"\n    owner: root\n    group: root\n    mode: 0600\n\n- name: Enable reload-module-on-update to upgrade WireGuard without user confirmation\n  file:\n    path: \"{{ wireguard_path }}/.reload-module-on-update\"\n    state: touch\n\n# Set up the WireGuard firewall rules\n- import_tasks: firewall.yml\n\n- name: Enable the WireGuard service so it starts at boot, and bring up the WireGuard network interface\n  systemd:\n    name: wg-quick@wg0.service\n    enabled: yes\n    state: started\n  # Temporary workaround for issue #500\n  ignore_errors: yes\n\n- name: \"Configure DNSMasq to listen on {{ dnsmasq_wireguard_ip }}:53\"\n  template:\n    src: wireguard_dnsmasq.conf.j2\n    dest: /etc/dnsmasq.d/wireguard.conf\n\n# NOTE(@cpu): We don't use a `notify` to \"Restart dnsmasq\" here because it seems\n# that in some conditions Ansible mistakenly believes the dnsmasq restart can be\n# skipped. We also don't use \"reloaded\" instead of \"restarted\" here because\n# dnsmasq doesn't seem to reload _new_ config files in that case, just existing\n# ones. A full restart is required in practice (sigh)\n- name: \"Restart DNSMasq to pick up the new configuration\"\n  service:\n    name: dnsmasq\n    state: restarted\n\n# Generate Gateway documentation\n- import_tasks: docs.yml\n"
  },
  {
    "path": "playbooks/roles/wireguard/templates/client-openwrt.txt.j2",
    "content": "### START-WIREGUARD\n\n# This OpenWrt (LEDE) /etc/rc.local script sets up the WireGuard profile\n# \"{{ item[0].stdout }}\" from the \"{{ streisand_server_name }}\" Streisand server.\n\n# Note that this script will replace the router's Internet access;\n# only run it when you're connected to the LAN/WiFi connection.\n\n# Open the LuCI web admin interface to the \"System:Startup\" page.\n# Paste this whole file into the \"Local Startup\" box. During the next\n# reboot, the script will run, and erase itself. It will leave a\n# success/failure message in the \"Local Startup\" box.\n\n# If you're using the web admin UI, you need the \"luci-app-wireguard\"\n# and \"luci-proto-wireguard\" packages installed.\n\n# LuCI instructions end here.\n\n############\n\n# If you aren't using LuCI, you need the \"kmod-wireguard\" and\n# \"wireguard-tools\" packages. You may need to reboot after running\n# this script (just restarting /etc/init.d/network may not be enough.)\n\n# Commenting out the next line will stop this script from messing\n# around with /etc/rc.local.\n\ntrap self_cleanup 0\n\n# Instructions end here.\n\n################################################################\n\n# Make errors fatal.\nset -e\n\nwireguard_completed=\"# Wireguard setup did not complete.\"\n\nself_cleanup () {\n    sed -i.bak -e '/^### START-WIREGUARD/,/^### END-WIREGUARD/ d' \\\n               -e \"\\$ a $wireguard_completed\" \\\n        /etc/rc.local\n}\n\n. /lib/functions.sh\n\n# This should be rewritten in terms of /lib/functions.sh callbacks.\nmove_to_firewall_zone () {\n    ifname=\"$1\"\n    fwzone=\"$2\"\n    for i in $(seq 0 20); do\n\t# No more zones?\n\tname=$(uci get \"firewall.@zone[$i].name\" 2>/dev/null) || return\n\tnetworks=$(uci get \"firewall.@zone[$i].network\")\n\tif list_contains networks \"$ifname\"; then\n\t    # Shell programmer wanted.\n\t    networks=$(echo \"$networks\" | sed \"s/ *\\\\b${ifname}\\\\b *//\")\n\tfi\n\tif [ \"$name\" = \"$fwzone\" ]; then\n\t    append networks \"$ifname\"\n\tfi\n\tuci set \"firewall.@zone[$i].network=$networks\"\n    done\n}\n\nifname=\"{{ item[0].stdout | replace(\"-\", \"_\") }}\"\n\nif ! uci get \"network.$ifname\" >/dev/null 2>&1; then\n    # Clean out any old peers\n    uci delete \"network.@wireguard_$ifname[0]\" >/dev/null 2>&1 || true\n\n    uci batch <<EOF\n\n\n# The local interface\nset network.$ifname=interface\n\nset network.$ifname.proto='wireguard'\nset network.$ifname.private_key='{{ item[1].stdout }}'\nset network.$ifname.addresses='10.192.122.{{ (item[0].item|int) + 1 }}/32'\nset network.$ifname.listen_port='51820'\n\n# The remote peer, i.e., the Streisand server\nadd network wireguard_$ifname\n\nset network.@wireguard_$ifname[-1].public_key='{{ wireguard_server_public_key }}'\nset network.@wireguard_$ifname[-1].endpoint_host='{{ streisand_ipv4_address }}'\nset network.@wireguard_$ifname[-1].endpoint_port='{{ wireguard_port }}'\n\n# Route *everything* through this peer.\nadd_list network.@wireguard_$ifname[-1].allowed_ips='0.0.0.0/0'\nset network.@wireguard_$ifname[-1].route_allowed_ips='1'\n\n# It is much more painful to debug when this is needed but missing.\nset network.@wireguard_$ifname[-1].persistent_keepalive='25'\n\n\nEOF\n\n    move_to_firewall_zone \"$ifname\" wan || true # FIXME\n\n    # Set the system-wide DNS\n    uci delete dhcp.@dnsmasq[0].server || true\n    uci add_list dhcp.@dnsmasq[0].server=10.192.122.1\n    uci set dhcp.@dnsmasq[0].noresolv=1\n\n    uci commit\n    # This seems necessary, and a full reboot may be as well.\n    /etc/init.d/network restart\nfi\n\nwireguard_completed=\"# Wireguard interface configured successfully\"\n\n### END-WIREGUARD\n#\n# Status\n"
  },
  {
    "path": "playbooks/roles/wireguard/templates/client.conf.j2",
    "content": "# \"{{ item[0].stdout }}\" - Streisand WireGuard Client Profile\n[Interface]\nAddress = 10.192.122.{{ (item[0].item|int) + 1 }}/32\n# The use of DNS below effectively expands to:\n#   PostUp = echo nameserver {{ dnsmasq_wireguard_ip }} | resolvconf -a tun.%i -m 0 -x\n#   PostDown = resolvconf -d tun.%i\n# If the use of resolvconf is not desirable, simply remove the DNS line\n# and use a variant of the PostUp/PostDown lines above.\n# The IP address of the DNS server that is available via the encrypted\n# WireGuard interface is {{ dnsmasq_wireguard_ip }}.\nDNS = {{ dnsmasq_wireguard_ip }}\nPrivateKey = {{ item[1].stdout }}\n\n[Peer]\nPublicKey = {{ wireguard_server_public_key }}\nAllowedIPs = 0.0.0.0/0,::/0\nEndpoint = {{ streisand_ipv4_address }}:{{ wireguard_port }}\n"
  },
  {
    "path": "playbooks/roles/wireguard/templates/instructions-fr.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nWireGuard\n---------\n\n[WireGuard](https://www.wireguard.com/) est certainement la meilleure option de connexion fournie par Streisand. Cela est dû à ses [performances incroyables](https://www.wireguard.com/performance/), [cryptographie de pointe](https://www.wireguard.com/protocol/), et des nombreuses autres avantages.\n\nWireGuard est disponible sur Linux et [d'autre plateformes](https://www.wireguard.com/xplatform/) ainsi que des implémentations portables d'espace utilisateur qui peuvent être téléchargées pour Android et macOS.\n\nUne [configuration expérimentale pour OpenWrt/LEDE](#openwrt) 17.01.4 (ou version ultérieure) est également disponible.\n\n---\n* Plateformes\n  * [Android](#android)\n  * [Linux](#linux)\n  * [macOS](#macos)\n  * [OpenWrt](#openwrt)\n\n<a name=\"android\"></a>\n### Android ###\n\n1. [Installez WireGuard](https://play.google.com/store/apps/details?id=com.wireguard.android).\n1. Lancez l'application et appuyez sur le bouton bleu pour ajouter un nouveau tunnel.\n1. Appuyez *Create from QR code* (Créer à partir du code QR) et autoriser l'application à accéder à la caméra. Un viewfinder (viseur) apparaîtra.\n1. Utilisez l'appareil photo pour numériser l'un de ces codes QR de configuration client. **Un seul appareil peut utiliser un profil à la fois**:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}.png)\n{% endfor %}\n1. Saisissez un nom pour le tunnel et appuyez sur *Create Tunnel* (Créer tunnel) pour sauvgarder la configuration.\n1. Appuyez sur le bouton situé à côté du nom du tunnel pour activer le VPN. Si c'est la première fois que vous utilisez WireGuard sur votre appareil Android, vous serez invité à accepter la demande de connexion VPN.\n1. Vous devriez être prêt à partir! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n<a name=\"linux\"></a>\n### Linux ###\n\n1. [Installez WireGuard](https://www.wireguard.com/install/)\n1. Téléchargez un fichier de configuration client. **Un seul ordinateur peut utiliser un profil à la fois**. Pour cet exemple, nous supposerons que vous avez téléchargé le fichier {{ vpn_client_names.results[0].stdout }}:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}.conf)\n{% endfor %}\n1. Déplacez le fichier de configuration du client dans le répertoire correct:\n\n   `sudo sh -c 'umask 077; mkdir -p /etc/wireguard; cat > /etc/wireguard/{{ vpn_client_names.results[0].stdout }}.conf' < ~/Downloads/{{ vpn_client_names.results[0].stdout }}.conf`\n\n1. Utilisez l'utilitaire `wg-quick` pour démarrer l'interface WireGuard:\n\n   `sudo wg-quick up {{ vpn_client_names.results[0].stdout }}`\n\n1. Vous devriez être prêt à partir! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n\n1. Pour arrêter de routé votre trafic via WireGuard, simplement arrêtez l'interface:\n\n   `sudo wg-quick down {{ vpn_client_names.results[0].stdout }}`\n\n#### Une note sur la configuration DNS ####\nChaque fichier inclure la commande `DNS` qui utilise `resolvconf` afin de diriger le trafic DNS vers le serveur dnsmasq qui est disponible via l'interface cryptée WireGuard à `{{ dnsmasq_wireguard_ip }}`. Bien que `resolvconf` soit un utilitaire commun, vous devrez peut-être remplacer cette ligne avec `PostUp`/`PostDown` pour votre distribution ou votre configuration réseau particulière.\n\n<a name=\"macos\"></a>\n### macOS ###\n\n**ATTENTION**: Le client macOS WireGuard en est aux premiers stades de développement et est toujours considéré comme expérimental.\n\n1. Installez [Homebrew](https://brew.sh/), si vous ne l'avez pas.\n1. Installez << WireGuard tools >> en utilisant Homebrew:\n\n   `brew install wireguard-tools`\n1. Téléchargez l'un des fichiers de configuration client. **Un seul appareil peut utiliser un profil à la fois**. Pour cet exemple, nous supposerons que vous avez téléchargé {{ vpn_client_names.results[0].stdout }}:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}.conf)\n{% endfor %}\n1. Déplacez le fichier de configuration du client dans le répertoire de configuration WireGuard. La commande suivante suppose que vous avez téléchargé le fichier de configuration dans votre dossier `Téléchargements` (ou `Downloads`). (Si ce n'est pas le cas, modifiez-le en conséquence):\n\n`sudo sh -c 'umask 077 && mkdir -p /etc/wireguard/ && cat ~/Downloads/{{ vpn_client_names.results[0].stdout }}.conf > /etc/wireguard/{{ vpn_client_names.results[0].stdout }}.conf'`\n\n1. Utilisez l'utilitaire `wg-quick` pour lancer l'interface WireGuard:\n\n   `sudo wg-quick up {{ vpn_client_names.results[0].stdout }}`\n\n\n1. Vous devriez être prêt à partir! Vous pouvez vérifier que votre trafic est correctement routé par [recherche de votre adresse IP sur DuckDuckGo]({{ streisand_my_ip_url }}). Il devrait dire *Votre adresse IP publique est {{streisand_ipv4_address}}*.\n1. Vous pouvez vérifier le statut du VPN à tout moment en utilisant `wg`:\n   `sudo wg show`\n\n1. Pour arrêter le routage de votre trafic via WireGuard, déconnectez l'interface avec:\n\n   `sudo wg-quick down {{ vpn_client_names.results[0].stdout }}`\n\n---\n\n<a name=\"openwrt\"></a>\n### EXPÉRIMENTAL: OpenWrt (LEDE) ###\n\nEn tant qu'expérience **non prise en charge**, ces profils sont disponibles pour les routeurs exécutant [OpenWrt](https://openwrt.org/). Le support nécessite OpenWrt/LEDE 17.01.4 ou ultérieur.\n\nLes périphériques OpenWrt exécutent Linux, mais ils sont gérés via un système de configuration centralisé appelé [UCI](https://openwrt.org/docs/guide-user/base-system/uci). La plupart des appareils OpenWrt ont une interface d'administration Web appelée LuCI, qui cache la complexité de UCI. Ces profils WireGuard peuvent être installés via un shell ou via l'interface Web LuCI.\n\nCes profils remplaceront la connexion Internet existante. Par conséquence, vous ne devez les installer que lorsque vous êtes connecté à l'interface réseau WiFi ou le LAN du routeur. Si vous êtes connecté à distance, vous risquez de vous enfermé de votre réseau.\n\n#### Installation du logiciel WireGuard ####\n\nAssurez-vous que ces progiciels sont installés: `luci-app-wireguard` et `luci-proto-wireguard`. Pour installer ces packages à partir de l'interface utilisateur Web:\n\n1. Naviguer vers la page LuCI *System:Software*, et cliquez sur le bouton *Update lists* (Mettre à jour les listes).\n2. Saisissez `wireguard` dans la boîte *Find package* (Rechercher un package).\n3. Cliquez sur l'onglet *Available packages (wireguard)* (progiciels disponibles).\n4. Cliquez sur *Install* à côté de `luci-app-wireguard`; Revenez à l'étape 2 pour installer `luci-proto-wireguard`.\n\n(Si vous gérez votre routeur sans l’interface utilisateur LuCI, vous pouvez utiliser à la place `opkg update; opkg install kmod-wireguard wireguard-tools` .)\n\n#### Installation du profil ####\n\nLes utilisateurs expérimentés peuvent installer ces profils à partir de la ligne de commande SSH du routeur. Placez-en un dans un fichier et exécutez-le en tant que un script shell.\n\nUn moyen simple existe pour simplifier l'installation à partir de l’interface Web. La page web LuCI *System:Startup* contient une zone de texte *Local Startup*. C'est un script shell qui est exécuté à chaque démarrage du routeur. Ces profils WireGuard sont conçus pour être collés dans la boîte *Local Startup*, remplaçant le contenu existant. (Assurez-vous de supprimer toutes les lignes `exit 0`.)\n\nAu prochain redémarrage du routeur, le script sera exécuté. Le script se supprimera automatiquement. Cochez la case *Local Startup* pour le résultat du statut.\n\n#### Modifications apportées par le profil ####\n\n* Une nouvelle interface nommée comme `poem_walk` sera créée\n* L'interface est ajoutée à la zone réseau *WAN*\n* La route par défaut vers Internet est définie sur l'interface. (Cela brisera la connectivité WAN, alors assurez-vous de ne l'installer qu'à partir du WiFi/LAN.)\n* Le keepalive WireGuard est réglé pour 25 secondes\n* DNS à l'échelle du système est obligé de pointer sur le serveur Streisand\n\nSi vous n'aimez pas le DNS configuré par défaut, vous pouvez modifier le comportement DNS sur la page LuCI: *Network: DHCP and DNS*. Mettez l'adresse du serveur DNS dans *Transfer DNS*. Sur l'onglet *Resolv and Hosts Files*, laissez *Ignore resolve file* coché, sauf si vous souhaitez utiliser votre DNS existant (non recommandé).\n\nSi vous savez que vous n'êtes pas derrière un périphérique NAT, modifiez l'interface WireGuard pour définir le paramètre keepalive sur 0.\n\n#### Profils OpenWrt ####\n\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}-openwrt.txt)\n{% endfor %}\n"
  },
  {
    "path": "playbooks/roles/wireguard/templates/instructions.md.j2",
    "content": "{% include \"languages.md.j2\" %}\n\nWireGuard\n---------\n\n[WireGuard](https://www.wireguard.com/) is almost certainly the best connection option that Streisand provides. This is due to its [incredible performance](https://www.wireguard.com/performance/), [class-leading cryptography](https://www.wireguard.com/protocol/), and many, many other benefits.\n\nWireGuard is available on Linux, and [cross-platform](https://www.wireguard.com/xplatform/) and portable userspace implementations can be downloaded for Android and macOS.\n\nAn [experimental configuration for OpenWrt/LEDE](#openwrt) 17.01.4 (or later) is also available.\n\n---\n* Platforms\n  * [Windows](#windows)\n  * [Android](#android)\n  * [iOS](#ios)\n  * [Linux](#linux)\n  * [macOS](#macos)\n  * [OpenWrt](#openwrt)\n\n<a name=\"windows\"></a>\n### Windows ###\n1. [Install WireGuard for Windows](https://www.wireguard.com/install/)\n1. Download one of the client configuration files. **Only one computer can use a profile at a time**. For this example we'll assume you downloaded {{ vpn_client_names.results[0].stdout }}:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}.conf)\n{% endfor %}\n1. Launch the app, and choose *Add Tunnel → Import tunnel(s) from file…*, select the downloaded file, then click *Open*.\n1. Select the imported tunnel and click *Activate* to connect.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n---\n\n<a name=\"android\"></a>\n### Android ###\n1. [Install WireGuard](https://play.google.com/store/apps/details?id=com.wireguard.android).\n1. Launch the app and tap the blue button to add a new tunnel.\n1. Tap *Create from QR code* and grant the app permission to access the camera. A viewfinder will appear.\n1. Use the camera to scan one of these client configuration QR codes. **Only one device can use a profile at a time**:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}.png)\n{% endfor %}\n1. Enter a name for the tunnel and tap *Create Tunnel* to save the configuration.\n1. Tap the switch next to the tunnel's name to enable the VPN. If this is your first time using WireGuard on your Android device, you will be prompted to accept the VPN connection request.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n---\n\n<a name=\"ios\"></a>\n### iOS ###\n1. Install WireGuard (by WireGuard Development Team) from the App Store.\n1. Launch the app and tap the blue button to add a new tunnel.\n1. Tap *Create from QR code* and grant the app permission to access the camera. A viewfinder will appear.\n1. Use the camera to scan one of these client configuration QR codes. **Only one device can use a profile at a time**:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}.png)\n{% endfor %}\n1. Enter a name for the tunnel and tap *Create Tunnel* to save the configuration.\n1. Tap the switch next to the tunnel's name to enable the VPN. If this is your first time using WireGuard on your iOS device, you will be prompted to accept the VPN connection request.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n---\n\n<a name=\"linux\"></a>\n### Linux ###\n1. [Install WireGuard](https://www.wireguard.com/install/).\n1. Download one of the client configuration files. **Only one computer can use a profile at a time**. For this example we'll assume you downloaded {{ vpn_client_names.results[0].stdout }}:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}.conf)\n{% endfor %}\n1. Move the client configuration file into the correct directory:\n\n   `sudo sh -c 'umask 077; mkdir -p /etc/wireguard; cat > /etc/wireguard/{{ vpn_client_names.results[0].stdout }}.conf' < ~/Downloads/{{ vpn_client_names.results[0].stdout }}.conf`\n\n1. (Ubuntu/Debian) For Ubuntu and Debian users you will need to install the `openresolv` package:\n\n   `sudo apt-get install openresolv`\n\n1. Use the `wg-quick` utility to bring up the WireGuard interface:\n\n   `sudo wg-quick up {{ vpn_client_names.results[0].stdout }}`\n\n1. For Linux systems using systemd you can also enable Wireguard at boot:\n\n   `sudo systemctl enable wg-quick@{{ vpn_client_names.results[0].stdout }}.service`\n\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n1. To stop routing your traffic through WireGuard, simply bring the interface back down:\n\n   `sudo wg-quick down {{ vpn_client_names.results[0].stdout }}`\n\n#### A note on DNS configuration ####\nEach client configuration profile includes a `DNS` command that uses resolvconf to direct DNS traffic to the dnsmasq server that is available via the WireGuard encrypted interface at `{{ dnsmasq_wireguard_ip }}`. Although resolvconf is a common utility, you may need to use `PostUp`/`PostDown` with a different command for your distribution or particular network configuration.\n\n---\n\n<a name=\"macos\"></a>\n### macOS ###\n**WARNING**: The macOS WireGuard client is in early stages of development and still considered experimental. It may be unstable or buggy.\n\n\n1. [Install the macOS WireGuard App](https://itunes.apple.com/us/app/wireguard/id1451685025) from the Mac App Store\n1. Download one of the client configuration files. **Only one computer can use a profile at a time**. For this example we'll assume you downloaded {{ vpn_client_names.results[0].stdout }}:\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}.conf)\n{% endfor %}\n1. Launch the WireGuard app, click *Import tunnel(s) from file* and choose the file downloaded in the previous step. If this is your first time using WireGuard on your macOS device, you will be prompted allow 'WireGuard' to add VPN Configurations.\n1. Click *Activate* to enable the VPN.\n1. You should be good to go! You can verify that your traffic is being routed properly by [looking up your IP address on DuckDuckGo]({{ streisand_my_ip_url }}). It should say *Your public IP address is {{ streisand_ipv4_address }}*.\n\n---\n\n<a name=\"openwrt\"></a>\n### EXPERIMENTAL: OpenWrt (LEDE) ###\n\nAs an **unsupported** experiment, these profiles are available for routers running [OpenWrt](https://openwrt.org/). Support requires OpenWrt/LEDE 17.01.4 or later; OpenWrt Chaos Calmer is too old.\n\nOpenWrt devices run Linux, but they're managed through a centralized configuration system called [UCI](https://openwrt.org/docs/guide-user/base-system/uci). Most OpenWrt devices have a web admin interface called LuCI, which hides the complexity of UCI. These WireGuard profiles can be installed through a shell, or through the LuCI web interface.\n\nThese profiles will replace the existing Internet connection. As a result, you should only install them when you're connected to the router's WiFi or LAN network interface. If you're logged in remotely, you may be locked out.\n\n#### Installing WireGuard software ####\n\nMake sure these software packages are installed: `luci-app-wireguard` and `luci-proto-wireguard`. To install those packages from the web UI:\n\n1. Go to the LuCI *System:Software* page, and click the *Update lists* button.\n2. Type `wireguard` into the *Find package* box.\n3. Click on the *Available packages (wireguard)* tab.\n4. Click *Install* next to `luci-app-wireguard`; go back to step 2 to install `luci-proto-wireguard` as well.\n\n(If you're managing your router without the LuCI user interface, you can instead `opkg update; opkg install kmod-wireguard wireguard-tools` .)\n\n#### Installing the profile ####\n\nExperienced users can install these profiles from the router's SSH command line; place one in a file, and run it as a shell script.\n\nThere's also a simple way to install via the web interface. The LuCI *System:Startup* web page contains a *Local Startup* text box. It's a shell script which is run each time the router boots up. These WireGuard profiles are designed to be pasted into the *Local Startup* box, replacing the existing contents. (Make sure to delete any `exit 0` lines.)\n\nThe next time the router reboots, the script will be run. It removes itself automatically. Check the *Local Startup* box for the status result.\n\n#### Changes made by the profile ####\n\n* A new interface named like `poem_walk` will be created\n* The interface is added to the *WAN* network zone\n* The default route to the Internet is set to the interface. (This will break WAN connectivity, so be sure to install only from WiFi/LAN.)\n* The WireGuard keepalive is set to 25 seconds\n* System-wide DNS is forced to point at the Streisand server\n\nIf you don't like the DNS default, you can change DNS behavior on the *Network:DHCP and DNS* LuCI page. Put the DNS server address in *DNS forwardings*. On the *Resolv and Hosts Files* tab, leave *Ignore resolve file* checked, unless you want to use your upstream DNS. (You probably don't.)\n\nIf you know you aren't behind a NAT device, edit the WireGuard interface to set the keepalive to 0.\n\n#### OpenWrt Profiles ####\n\n{% for client in vpn_client_names.results %}\n   * [{{ client.stdout }}](/wireguard/{{ client.stdout }}-openwrt.txt)\n{% endfor %}\n"
  },
  {
    "path": "playbooks/roles/wireguard/templates/server.conf.j2",
    "content": "[Interface]\nAddress = 10.192.122.1/24\nSaveConfig = true\nListenPort = {{ wireguard_port }}\nPrivateKey = {{ wireguard_server_private_key }}\n\n{% for client in vpn_client_names.results %}\n# \"{{ client.stdout }}\" Client Peer\n[Peer]\nPublicKey = {{ wireguard_client_pubkeys.results[(client.item|int)-1].stdout }}\nAllowedIPs = 10.192.122.{{ (client.item|int)+1 }}/32\n\n{% endfor %}\n"
  },
  {
    "path": "playbooks/roles/wireguard/templates/streisand-wireguard-service.sh.j2",
    "content": "#!/bin/sh\n### BEGIN INIT INFO\n# Provides:          streisand-wireguard\n# Required-Start:    $network $remote_fs $local_fs\n# Required-Stop:     $network $remote_fs $local_fs\n# Default-Start:     2 3 4 5\n# Default-Stop:      0 1 6\n# Short-Description: Persist WireGuard firewall rules for Streisand\n### END INIT INFO\n\n{% for rule in wireguard_firewall_rules %}\n{{ rule }}\n{% endfor %}\n\nexit 0\n"
  },
  {
    "path": "playbooks/roles/wireguard/templates/wireguard_dnsmasq.conf.j2",
    "content": "# Listen on the WireGuard address\nlisten-address={{ dnsmasq_wireguard_ip }}\n"
  },
  {
    "path": "playbooks/roles/wireguard/vars/main.yml",
    "content": "---\nwireguard_path: \"/etc/wireguard\"\nwireguard_client_path: \"{{ wireguard_path }}/clients\"\n\nwireguard_server_private_key_file: \"{{ wireguard_path }}/server.key\"\nwireguard_server_public_key_file:  \"{{ wireguard_path }}/server.pub\"\n\ndnsmasq_wireguard_ip: \"10.192.122.1\"\n\nwireguard_firewall_rules:\n  - \"iptables --wait {{ streisand_iptables_wait }} -A FORWARD -s 10.192.122.0/24 -j ACCEPT\"\n  - \"iptables --wait {{ streisand_iptables_wait }} -t nat -A POSTROUTING -s 10.192.122.0/24 -o {{ ansible_default_ipv4.interface }} -j MASQUERADE\"\n\nwireguard_gateway_location:      \"{{ streisand_gateway_location }}/wireguard\"\n"
  },
  {
    "path": "playbooks/ssh-setup.yml",
    "content": "---\n- name: Configure Ansible SSH\n  hosts: streisand-host\n  gather_facts: no\n  tasks:\n    - set_fact:\n        ansible_ssh_private_key_file: \"{{ streisand_ssh_private_key }}\"\n"
  },
  {
    "path": "playbooks/streisand.yml",
    "content": "---\n- import_playbook: python.yml\n- import_playbook: lets-encrypt.yml\n\n- name: Collect diagnostics in case of error\n  hosts: localhost\n  gather_facts: no\n  roles:\n    - role: diagnostics\n      when: not streisand_ci\n\n- name: Configure the Server and install required software\n# ========================================================\n  hosts: streisand-host\n\n  remote_user: \"root\"\n  become: true\n\n  roles:\n    - common\n    - gpg\n    - ssh\n    - service-net\n    - role: openconnect\n      when: streisand_openconnect_enabled\n    - role: openvpn\n      when: streisand_openvpn_enabled\n    - role: shadowsocks\n      when: streisand_shadowsocks_enabled\n    - role: ssh-forward\n      when: streisand_ssh_forward_enabled\n    - role: tinyproxy\n      when: streisand_tinyproxy_enabled\n    # tor-bridge is skipped in our full Ansible run on Travis CI due to\n    # connectivity issues.\n    - role: tor-bridge\n      when: not streisand_ci and streisand_tor_enabled\n    - sslh\n    - ufw\n    - role: wireguard\n      when: streisand_wireguard_enabled\n    - role: cloudflared\n      when: not streisand_ci and streisand_cloudflared_enabled\n    # streisand_le_enabled is set in lets-encrypt.yml based on user input.\n    # lets-encrypt roles sets le_ok, which is used by streisand-gateway.\n    - role: lets-encrypt\n      when: streisand_le_enabled\n    - role: ad-blocking\n      when: streisand_ad_blocking_enabled\n    - streisand-mirror\n    - streisand-gateway\n...\n"
  },
  {
    "path": "playbooks/test-client.yml",
    "content": "---\n- name: Configure the client server for Ansible\n# =========================================\n  hosts: streisand-client\n  gather_facts: no\n  remote_user: \"root\"\n  become: true\n\n  tasks:\n    - name: Install Python using a raw SSH command to enable the execution of Ansible modules\n      raw: apt update && apt install python -y\n      args:\n        executable: /bin/bash\n\n- name: Configure the client server as a Streisand test client\n  hosts: streisand-client\n  remote_user: \"root\"\n  become: true\n  roles:\n    - test-client\n...\n"
  },
  {
    "path": "playbooks/vagrant.yml",
    "content": "---\n- import_playbook: python.yml\n\n- name: Prepare the vagrant VM for Ansible\n# =========================================\n  hosts: streisand-host\n  remote_user: \"root\"\n  become: true\n\n  # Use pre_tasks to run these before the roles, since the role expects keys to\n  # exist.\n  pre_tasks:\n    # Ansible uses `ip -4 route get 8.8.8.8` to set the `ansible_default_ipv4`\n    # fact with an interface's details. Without the below route being added this\n    # results in enp0s3 being used when we want enp0s8 to be used. We work\n    # around this by setting a route for 8.8.8.8 through enp0s8.\n    - name: Workaround Ansible default ipv4 interface detection\n      raw: route add -net 8.8.8.8 netmask 255.255.255.255 enp0s8\n      args:\n        executable: /bin/bash\n      when: ansible_default_ipv4.alias != \"enp0s8\"\n\n    # We need a throwaway key pair created in the location expected by\n    # {{ streisand_ssh_private_key }}.\n    - name: Create throwaway SSH key pair directory.\n      file:\n        path: \"{{ streisand_ssh_private_key | expanduser | dirname }}\"\n        state: directory\n        mode: 0700\n        recurse: yes\n\n    - name: Create throwaway SSH key pair.\n      shell: \"ssh-keygen -h -t rsa -f {{ streisand_ssh_private_key }} -N ''\"\n      args:\n        creates: \"{{ streisand_ssh_private_key }}\"\n\n  roles:\n    - validation\n\n- import_playbook: ssh-setup.yml\n- import_playbook: streisand.yml\n...\n"
  },
  {
    "path": "playbooks/validate.yml",
    "content": "---\n- name: Perform global variables validation\n# =========================================\n  hosts: localhost\n  connection: local\n  gather_facts: no\n\n  vars_files:\n    - ../global_vars/globals.yml\n\n  roles:\n    - validation\n\n...\n"
  },
  {
    "path": "requirements.txt",
    "content": "# Install Streisand requirements with:\n#\n#   pip install -r ./requirements.txt\n#\n# If you have problems running this, try the util/venv-builder.sh script.\n\n# Core with Azure dependencies\n#\nansible[azure]==2.8.4\n\nSecretStorage\n\n# AWS\nboto\nboto3\n\n# Google Compute Engine\nrequests\ngoogle-auth\napache-libcloud\n\n# Linode\nlinode-api4\n\n# Rackspace\npyrax\n"
  },
  {
    "path": "streisand",
    "content": "#!/usr/bin/env bash\n# Streisand provisioning script\n\n# Set errexit option to exit immediately on any non-zero status return\nset -e\n\necho -e \"\\n\\033[38;5;255m\\033[48;5;234m\\033[1m  S T R E I S A N D  \\033[0m\\n\"\n\n# This is where Ansible looks for local modules. Disable it, in the\n# interests of consistency between installs.\nexport ANSIBLE_LIBRARY=\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"$0\")\" && pwd -P)\"\n\nDEFAULT_SITE_VARS=\"$SCRIPT_DIR/global_vars/default-site.yml\"\nGLOBAL_VARS=\"$SCRIPT_DIR/global_vars/globals.yml\"\nHOME_DIR=\"$HOME/.streisand\"\nSITE_VARS=\"$HOME_DIR/site.yml\"\n\n# Include the check_ansible function from ansible_check.sh\nsource util/ansible_check.sh\n\nfunction init_homedir() {\n  if [ ! -d \"$HOME_DIR\" ]; then\n    mkdir \"$HOME_DIR\"\n    echo \"Created new Streisand home directory: $HOME_DIR\"\n  fi\n  if [ ! -f \"$SITE_VARS\" ]; then\n    cp \"$DEFAULT_SITE_VARS\" \"$SITE_VARS\"\n    echo \"Created new Streisand site vars file: $SITE_VARS\"\n  fi\n}\n\n# check_python checks whether the 'python' interpreter is Python 2 or Python 3.\n# If it is Python 2 then the inventory file is updated to set the\n# ansible_interpretter host var explicitly\n# function check_python() {\n#     return 0\n#   local PYTHON_VERSION\n#   PYTHON_VERSION=\"$(python --version 2>/dev/null)\"\n#\n#   if [[ -n $PYTHON_VERSION && ! $PYTHON_VERSION =~ ^Python\\ 3\\..* ]]; then\n#     local INVENTORY_DIR=\"$SCRIPT_DIR/inventories/\"\n#     for INV_FILE in \"$INVENTORY_DIR\"/*; do\n#       sed \"s|=python\\$|=$(type python)|\" \"$INV_FILE\" > \"$INV_FILE.new\"\n#       mv \"$INV_FILE.new\" \"$INV_FILE\"\n#       git -C \"$INVENTORY_DIR\" update-index --assume-unchanged \"$INV_FILE\" 2>/dev/null || true\n#     done\n#   fi\n# }\n\n# validate runs the validation role to check the consistency of the Streisand\n# service vars (e.g. that at least one service is enabled after customization of\n# $SITE_VARS).\nfunction validate() {\n  local NEW_SERVER_PROVISIONING=$1\n  if [ -z \"${NEW_SERVER_PROVISIONING}\" ]; then\n    NEW_SERVER_PROVISIONING=true\n  fi\n  \n  echo; echo; ansible-playbook \\\n    --extra-vars=\"@$GLOBAL_VARS\" \\\n    --extra-vars=\"@$DEFAULT_SITE_VARS\" \\\n    --extra-vars=\"@$SITE_VARS\" \\\n    --extra-vars=\"streisand_new_server_provisioning=$NEW_SERVER_PROVISIONING\" \\\n    playbooks/validate.yml\n}\n\n# customize prompts the user to decide if they want to customize the Streisand\n# installation. If the user wishes, the playbooks/customize.yml role is used to\n# change the base installation by rewriting the $SITE_VARS file.\nfunction customize() {\n  read -r -p \"\nDo you wish to customize which services Streisand will install?\nBy saying 'no' Streisand will use the settings configured in $SITE_VARS\n\nPress enter to customize your installation: \" confirm\n  case \"$confirm\" in\n    no) echo; echo \"Installing Streisand services specified in $SITE_VARS\";;\n     *) echo; echo \"Confirmed. Customizing Streisand services.\";\n         # NOTE(@cpu): We don't pass the other `--extra-vars` here because the\n         # customize `vars_prompt` will only happen if the vars aren't already\n         # set. If you pass the site/defaults in no prompting will happen.\n         echo; echo; ansible-playbook \\\n           --extra-vars=\"@$GLOBAL_VARS\" \\\n           playbooks/customize.yml;;\n  esac\n}\n\n# run_genesis invokes the genesis playbook file specified by the first argument\n# to the function, or `streisand.yml` if none is provided. It uses the second\n# argument to the function as the inventory or `inventories/inventory` if none\n# is provided.\nfunction run_genesis() {\n  local GENESIS_PLAYBOOK=$1\n  local ASK_BECOME=\"\"\n  if [ -z \"${GENESIS_PLAYBOOK}\" ]; then\n    GENESIS_PLAYBOOK=streisand.yml\n  fi\n  local GENESIS_INVENTORY=$2\n  if [ -z \"${GENESIS_INVENTORY}\" ]; then\n    GENESIS_INVENTORY=inventories/inventory\n  fi\n  # Customize the Streisand services that will be installed\n  customize\n  # Ensure that the customization hasn't resulted in something inconsistent\n  # NEW_SERVER_PROVISIONING can be False or True (0 or 1), tests if we need \n  # to check existence of SSH public key\n  if [ \"$GENESIS_PLAYBOOK\" != \"existing-server.yml\" ] && [ \"$GENESIS_PLAYBOOK\" != \"localhost.yml\" ]; then\n    validate true\n  else\n    validate false\n  fi\n  \n  if [ -n \"${SSH_USER}\" ] && [ \"$SSH_USER\" != \"root\" ]; then\n    ASK_BECOME=\"--ask-become-pass\"\n  fi\n  \n  # Run the specified genesis playbook with the specified Ansible inventory\n  echo; echo; ansible-playbook \\\n    -i $GENESIS_INVENTORY \\\n    --extra-vars=\"@$GLOBAL_VARS\" \\\n    --extra-vars=\"@$DEFAULT_SITE_VARS\" \\\n    --extra-vars=\"@$SITE_VARS\" \\\n    $ASK_BECOME \\\n    \"playbooks/$GENESIS_PLAYBOOK\"\n}\n\n# be_careful_friend asks you to pay attention because you're about to do\n# something that might be impossible to undo!\nfunction be_careful_friend() {\n  read -r -p \"$1\" confirm\n  case \"$confirm\" in\n    streisand) echo; echo \"Confirmed. Continuing\";;\n    *) echo; echo \"Cancelling & exiting.\"; exit 1;;\n  esac\n}\n\n# local_provision handles provisioning the same machine as is running the\n# Streisand script/Ansible. It performs an additional \"ARE YOU SURE\" step before\n# invoking ansible-playbook. It uses the `inventory-local-provision` inventory\n# file from the inventories directory as the Ansible inventory.\nfunction local_provision() {\n  be_careful_friend \"\nLOCAL PROVISIONING WILL OVERWRITE CONFIGURATION ON **THIS** MACHINE.\nTHE MACHINE YOU ARE CURRENTLY EXECUTING THIS SHELL SCRIPT ON.\nARE YOU 100% SURE THAT YOU WISH TO CONTINUE?\n\nPlease enter the word 'streisand' to continue: \"\n\n  run_genesis localhost.yml inventories/inventory-local-provision\n}\n\nfunction existing_server() {\n  read -r -p \"What is the IP of the existing server: \" SERVER_IP\n\n  be_careful_friend \"\nTHIS WILL OVERWRITE CONFIGURATION ON THE EXISTING SERVER.\nSTREISAND ASSUMES $SERVER_IP IS A BRAND NEW UBUNTU INSTANCE AND WILL\nNOT PRESERVE EXISTING CONFIGURATION OR DATA.\n\nARE YOU 100% SURE THAT YOU WISH TO CONTINUE?\n\nPlease enter the word 'streisand' to continue: \"\n\n  # If ANSIBLE_SSH_USER is empty, default to root\n  if [ -z \"${ANSIBLE_SSH_USER}\" ]; then\n    SSH_USER='root'\n  # Otherwise, use whatever ANSIBLE_SSH_USER is set to as the SSH_USER\n  else\n    SSH_USER=${ANSIBLE_SSH_USER}\n  fi\n\n  # Create an inventory file string on the fly\n  read -r -d '' TEMPL << EOF || true\n[localhost]\nlocalhost ansible_connection=local ansible_python_interpreter=python3\n[streisand-host]\n$SERVER_IP ansible_user=$SSH_USER\nEOF\n\n  # Create the inventory file\n  echo \"$TEMPL\" > inventories/inventory-existing\n  # Invoke the Streisand playbook on the existing server inventory\n  run_genesis existing-server.yml inventories/inventory-existing\n}\n\n# Make sure the system is ready for the Streisand playbooks\ninit_homedir\n# check_python\ncheck_ansible\n\n# Figure out which genesis role to invoke\nread -r -p \"Which provider are you using?\n  1. Amazon\n  2. Azure\n  3. DigitalOcean\n  4. Google\n  5. Linode\n  6. Rackspace\n  7. localhost (Advanced)\n  8. Existing Server (Advanced)\n: \" reply\n\ncase \"$reply\" in\n  1) run_genesis amazon.yml;;\n  2) run_genesis azure.yml;;\n  3) run_genesis digitalocean.yml;;\n  4) run_genesis google.yml;;\n  5) run_genesis linode.yml;;\n  6) run_genesis rackspace.yml;;\n  7) local_provision;;\n  8) existing_server;;\n  *) echo; echo \"Invalid provider selected.\"; exit 1;;\nesac\n"
  },
  {
    "path": "tests/README.md",
    "content": "# Streisand-CI Testing\nStreisand CI testing uses Github Actions to test Ansible syntax and kick off a full playbook run.\nThe Full playbook run is executed against github runners\n\n## Testing Limitations\nThere were some connectivity issues with the `tor-bridge` playbook in the CI testing environment. Due to this, the role is currently skipped.\nStreisand doc generation is also skipped until some mock variables and tasks are added.\n\n## Local Testing\nYou can use this testing framework to test locally as well. Note that when testing locally, the `tor-bridge` role will be ran.\n\n### Host Environment Expectations:\n  - **Fresh** Trusty or Xenial Ubuntu install (Vagrant or DigitalOcean server, etc.)\n\nBecause LXC loads the host's kernal modules into the container. Libreswan needs to be compiled and installed on the host.\nThis allows the ipsec role to complete successfully inside the LXC container.\n\n#### Running the tests\n  - Clone the Streisand repository\n    - Run test script\n      - `./tests/test.sh full`\n        - The `full` argument will run `development-setup.yml`, `syntax-check.yml`, and `run.yml`.\n\n#### Syntax only\n  - `./tests/test.sh syntax`\n\n# TODO\n- Vagrant file which can automate setting up a local test environment for use with development-setup.yml, and run.yml\n- Figure out a way to test the Tor role\n- Add some mock variables for the document generation task\n- Add some automated client testing (Example: Automatically test an openvpn client)\n- Check if the tor-bridge is still an issue on github actions\n"
  },
  {
    "path": "tests/ansible.cfg",
    "content": "[defaults]\nnocows = 1\nroles_path = playbooks/roles:../playbooks/roles\nhost_key_checking = False\nremote_tmp = $HOME/.ansible/tmp\nlocal_tmp = $HOME/.ansible/tmp\ntimeout = 100\nforks = 15\ninternal_poll_interval=0.001\n\n[ssh_connection]\npipelining = True\n"
  },
  {
    "path": "tests/development-setup.yml",
    "content": "---\n# NOTE(@craun): Removed the \"install python\" steps for local dev setup. In order to even run this playbook ansible\n# already needs to be installed, which, implies that python is also installed.\n\n- hosts: localhost\n  gather_facts: yes\n  remote_user: root\n  become: yes\n  pre_tasks:\n    # NOTE(@alimakki): Due to key rotation, we pre-emptivley\n    # add the Google linux apt signing key required by some\n    # packages\n    - name: Add an Apt signing key, uses whichever key is at the URL\n      apt_key:\n        url: https://dl-ssl.google.com/linux/linux_signing_key.pub\n        state: present\n  tasks:\n    - name: Ensure consistent & clean apt state\n      apt:\n        update_cache: yes\n        autoclean: yes\n        autoremove: yes\n        purge: yes\n\n    - name: Remove old LXD/LXC from distro\n      apt:\n        name:\n          - lxd*\n          - lxc*\n        state: absent\n        autoremove: yes\n        purge: yes\n\n    - name: Install snapd\n      apt:\n        name: snapd\n\n    - name: Install LXD snap\n      snap:\n        name: lxd\n\n    - name: Connect LXD plug to slots\n      command: \"{{ item }}\"\n      with_items:\n        - \"snap connect lxd:lxd-support\"\n        - \"snap connect lxd:network\"\n\n    - name: Start lxd\n      command: \"snap start lxd\"\n\n    - name: Wait for the LXD socket\n      wait_for:\n        path: \"/var/snap/lxd/common/lxd/unix.socket\"\n        state: present\n        sleep: 5\n\n    - name: lxd init config\n      command: lxd init --auto --storage-backend dir\n      args:\n        creates: /var/snap/lxd/common/lxd/storage-pools/default\n\n    - name: lxd create network\n      command: lxc network create testbr0\n      args:\n        creates: /var/snap/lxd/common/lxd/networks/testbr0\n\n    - name: Retrieve the Ubuntu Xenial AMD64 LXC image fingerprint\n      uri:\n        url: https://images.linuxcontainers.org/1.0/images/aliases/ubuntu/xenial/amd64\n        return_content: yes\n      register: xenial_fingerprint\n\n    - name: Launch streisand container (this will take a while)\n      lxd_container:\n        name: streisand\n        state: started\n        url: \"unix:/var/snap/lxd/common/lxd/unix.socket\"\n        source:\n          type: image\n          mode: pull\n          server: https://images.linuxcontainers.org\n          protocol: lxd\n          # Use the retrieved alias to fetch the image\n          alias: \"{{ xenial_fingerprint['json']['metadata']['target'] }}\"\n        profiles: [\"default\"]\n        config:\n          security.privileged: \"true\"\n        wait_for_ipv4_addresses: true\n        timeout: 300\n\n    # TODO(@cpu): Why this is required is a mystery to me. Everything in\n    # development-setup.yml is able to access the unix socket without error.\n    # Without this gross chmod the LXD connection used to run the Streisand\n    # playbooks on the container fails with an access error. It would be nice to\n    # reduce these permissions. It's likely dangerous in a non-CI environment\n    - name: Open the permissions on the LXD socket\n      command: chmod 777 /var/snap/lxd/common/lxd/unix.socket\n\n    - name: Install python in container\n      delegate_to: streisand\n      raw: apt-get update && apt-get install -y python3 python3-apt python3-pip\n\n    - name: Set python3 as the default\n      raw: update-alternatives --install /usr/bin/python python /usr/bin/python3 1\n\n    - name: Set python3-pip as the default\n      raw: update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1\n"
  },
  {
    "path": "tests/group_vars/all/all",
    "content": "---\nstreisand_ci: yes\nstreisand_noninteractive: no\n\nserver_name: streisand\n"
  },
  {
    "path": "tests/inventory",
    "content": "[streisand]\nstreisand ansible_connection=lxd ansible_become=yes\n\n[localhost]\nlocalhost ansible_connection=local\n"
  },
  {
    "path": "tests/randomize_sitevars.sh",
    "content": "#!/bin/bash -e\n\n# randomize_sitevar.sh takes a Streisand site vars yml file and randomly enables\n# some # of services. It guarantees that at least one service is enabled. It\n# operates *destructively* - it will disable all services in the yml file before\n# enabling a random selection. The site var yml contents are changed in-place.\n\n# Keep track of how many services we've enabled so we can check there was at\n# least one enabled.\nENABLED_SERVICES=0\n\n# randomize_services mutates a site vars file provided as the first argument\nfunction randomize_services {\n  # Reset the state of the file to all disabled\n  sed -i 's/yes/no/' \"$1\"\n\n  # NOTE(@cpu): You might be tempted to pipe the `grep` into `read` for the\n  # `while` condition. This will make the loop body excute in a subshell that\n  # can not increment `ENABLED_SERVICES`. To work around this we use process\n  # substitution. See http://mywiki.wooledge.org/BashFAQ/024 for more\n  while read -r LINE\n  do\n    # Generate a random int between 0 and 100\n    FLIP=$((RANDOM%100))\n    # If the random int is >= 50, enable the service\n    if [ \"$FLIP\" -gt 50 ]\n    then\n      SERVICE=$(echo \"$LINE\" | cut -d: -f1)\n      case $SERVICE in\n        \"streisand_stunnel_enabled\")\n          # stunnel depends on openvpn\n          echo \"Setting 'streisand_openvpn_enabled: yes' to support stunnel\"\n          sed -i \"s/\\(streisand_openvpn_enabled\\): no/\\1: yes/\" \"$1\"\n          ;;\n        \"streisand_tinyproxy_enabled\"|\"streisand_sshuttle_enabled\")\n          # tinyproxy and sshuttle depend on the ssh-forward user\n          echo \"Setting 'streisand_ssh_forward_enabled' to support tinyproxy\"\n          sed -i \"s/\\(streisand_ssh_forward_enabled\\): no/\\1: yes/\" \"$1\"\n          ;;\n      esac\n\n      ENABLED_SERVICES=$((ENABLED_SERVICES+1))\n      echo \"Setting '$SERVICE: yes'\"\n      sed -i \"s/\\($SERVICE\\): no/\\1: yes/\" \"$1\"\n    fi\n  done < <(grep \"no\" \"$1\")\n}\n\n# Check that the provided site vars file exists\nif [ ! -e \"$1\" ]\nthen\n  echo \"site vars file \\\"$1\\\" does not exist\"\n  exit 1\nfi\n\n# Until we've enabled at least one service continue to randomize the input file\nwhile [ \"$ENABLED_SERVICES\" -eq \"0\" ]\ndo\n  randomize_services \"$1\"\ndone\n\necho \"Enabled $ENABLED_SERVICES random services\"\n"
  },
  {
    "path": "tests/remote_test.sh",
    "content": "#!/usr/bin/env bash\n#\n# Utility script for running the Vagrantfile.remotetest against a Streisand host\n#\n\n# Set errexit option to exit immediately on any non-zero status return\nset -e\n\necho -e \"\\n\\033[38;5;255m\\033[48;5;234m\\033[1m  S T R E I S A N D  R E M O T E  T E S T\\033[0m\\n\"\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"$0\")\" && pwd -P)\"\n\nVAGRANT_FILENAME=\"Vagrantfile.remotetest\"\nGENERATED_DOCS_DIR=\"${SCRIPT_DIR}/../generated-docs\"\nmkdir -p \"${GENERATED_DOCS_DIR}\"\n\nVAGRANTFILE=\"${SCRIPT_DIR}/../${VAGRANT_FILENAME}\"\n\nfunction backup_vagrantfile() {\n  cp \"${VAGRANTFILE}\" \"${VAGRANTFILE}.dist\"\n}\n\nfunction restore_vagrantfile() {\n  cp \"${VAGRANTFILE}.dist\" \"${VAGRANTFILE}\"\n  rm \"${VAGRANTFILE}.dist\"\n}\ntrap restore_vagrantfile EXIT\n\n# set_remote_ip replaces the \"REMOTE_IP_HERE\" token from the\n# Vagrantfile.remotetest with the response from a user prompt\nfunction set_remote_ip() {\n  read -r -p \"What is the Streisand server IP? \" SERVER_IP\n  sed \"s/\\\"REMOTE_IP_HERE\\\",/\\\"${SERVER_IP}\\\",/\" \"${VAGRANTFILE}\" > \"${VAGRANTFILE}.new\"\n  mv \"${VAGRANTFILE}.new\" \"${VAGRANTFILE}\"\n}\n\nfunction set_gateway_pass() {\n  local GATEWAY_PASS_FILE=\"${GENERATED_DOCS_DIR}/gateway-password.txt\"\n\n  read -r -p \"What is the Streisand gateway password? \" GATEWAY_PASS\n\n  echo \"${GATEWAY_PASS}\" > \"${GATEWAY_PASS_FILE}\"\n}\n\nbackup_vagrantfile\nset_remote_ip\nset_gateway_pass\n\npushd \"${SCRIPT_DIR}/..\"\n  VAGRANT_VAGRANTFILE=${VAGRANT_FILENAME} vagrant up --provision\npopd\n"
  },
  {
    "path": "tests/run.yml",
    "content": "---\n- hosts: streisand\n  gather_facts: yes\n  remote_user: root\n  become: yes\n  tasks:\n    - set_fact:\n        ansible_ssh_private_key_file: \"{{ streisand_ssh_private_key }}\"\n    - block:\n        - name: Generate SSH Key's for CI run\n          shell: \"ssh-keygen -b 2048 -t rsa -f /tmp/id_rsa_insecure -q -N ''\"\n          args:\n            creates: \"/tmp/id_rsa_insecure\"\n\n        - name: Get the default SSH key\n          command: \"cat /tmp/id_rsa_insecure.pub\"\n          register: ssh_key\n          changed_when: False\n\n        - name: Ensure permissions on insecure key are correct\n          file:\n            path: \"/tmp/id_rsa_insecure\"\n            mode: \"0666\"\n          when: streisand_ci\n\n        - name: Check Streisand configuration is valid\n          include_role:\n            name: validation\n      delegate_to: localhost\n\n    - name: Ensure openssh is installed\n      apt:\n        package: openssh-server\n\n    - name: Add authorized key\n      authorized_key:\n        user: root\n        state: present\n        key: \"{{ ssh_key.stdout }}\"\n\n    - name: Create the in-memory inventory group\n      add_host:\n        name: \"{{ ansible_default_ipv4.address }}\"\n        groups: streisand-host\n        ansible_ssh_private_key_file: \"/tmp/id_rsa_insecure\"\n\n    - name: Set the streisand_ipv4_address variable\n      set_fact:\n        streisand_ipv4_address: \"{{ ansible_default_ipv4.address }}\"\n\n    - name: Set the streisand_server_name variable\n      set_fact:\n        streisand_server_name: \"{{ server_name | regex_replace('\\\\s', '_') }}\"\n\n- name: Include streisand.yml\n  import_playbook: ../playbooks/streisand.yml\n"
  },
  {
    "path": "tests/shellcheck.sh",
    "content": "#!/bin/bash\n#\n# Streisand shellcheck wrapper\n#\n# This test script finds all of the *.sh shell files in the project tree and\n# runs shellcheck against them.\n#\n\n# Fail on errors\nset -e\n\n# Ensure shellcheck is present\nif ! command -v shellcheck > /dev/null 2>&1; then\n    echo \"The 'shellcheck' comand was not found in your PATH. Please install it\"\n    exit 1\nfi\n\n# NOTE(@cpu): We use -x to follow `source` directives across files\nSHELLCHECK_ARGS=(-x)\n\n# Determine the absolute path of this script file's directory\nSCRIPT_DIR=\"$(cd \"$(dirname \"$0\")\" && pwd -P)\"\n# The Streisand project directory is one up from this script's directory, tests/\nPROJECT_DIR=\"$SCRIPT_DIR/..\"\n\npushd \"$PROJECT_DIR\"\n  # Run shellcheck against all of the `.sh` script files in the Streisand\n  # project directory. Ignore any `venv` directory.\n  #\n  # NOTE(@cpu): While tempting to -exec shellcheck directly from find this will\n  # eat-up any non-zero exit codes :-( Instead we find the files first and then\n  # xargs shellcheck on the found files.\n  find . -path \"./venv\" -prune -or -name '*.sh' -print0 | xargs -0 -n1 shellcheck \"${SHELLCHECK_ARGS[@]}\"\n\n  # Also explicitly run `shellcheck` against the streisand wrapper script since\n  # it doesn't end in .sh\n  shellcheck \"${SHELLCHECK_ARGS[@]}\" \"$PROJECT_DIR/streisand\"\npopd\n"
  },
  {
    "path": "tests/site_vars/cloudflared.yml",
    "content": "---\n# This site config enables openvpn, wireguard, and cloudflared (DNS-over-HTTPS)\nvpn_clients: 5\nstreisand_ad_blocking_enabled: yes\nstreisand_cloudflared_enabled: yes\nstreisand_openconnect_enabled: no\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: no\nstreisand_shadowsocks_v2ray_enabled: no\nstreisand_ssh_forward_enabled: no\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: no\nstreisand_tinyproxy_enabled: no\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: yes\n"
  },
  {
    "path": "tests/site_vars/openconnect.yml",
    "content": "---\n# This site config only enables OpenConnect\nvpn_clients: 5\nstreisand_ad_blocking_enabled: no\nstreisand_cloudflared_enabled: no\nstreisand_openconnect_enabled: yes\nstreisand_openvpn_enabled: no\nstreisand_shadowsocks_enabled: no\nstreisand_shadowsocks_v2ray_enabled: no\nstreisand_ssh_forward_enabled: no\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: no\nstreisand_tinyproxy_enabled: no\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: no\n"
  },
  {
    "path": "tests/site_vars/openvpn.yml",
    "content": "---\n# This site config only enables openvpn\nvpn_clients: 5\nstreisand_ad_blocking_enabled: no\nstreisand_cloudflared_enabled: no\nstreisand_openconnect_enabled: no\nstreisand_openvpn_enabled: yes\nstreisand_shadowsocks_enabled: no\nstreisand_shadowsocks_v2ray_enabled: no\nstreisand_ssh_forward_enabled: no\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: no\nstreisand_tinyproxy_enabled: no\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: no\n"
  },
  {
    "path": "tests/site_vars/random.yml",
    "content": "---\nvpn_clients: 1\n\n# Streisand CI's task randomizes these \"_enabled\" vars at build-time\nstreisand_ad_blocking_enabled: no\nstreisand_cloudflared_enabled: no\nstreisand_openconnect_enabled: no\nstreisand_openvpn_enabled: no\nstreisand_shadowsocks_enabled: no\nstreisand_shadowsocks_v2ray_enabled: no\nstreisand_ssh_forward_enabled: no\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: no\nstreisand_tinyproxy_enabled: no\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: no\n"
  },
  {
    "path": "tests/site_vars/shadowsocks.yml",
    "content": "---\n# This site config only enables Shadowsocks\nvpn_clients: 5\nstreisand_ad_blocking_enabled: no\nstreisand_cloudflared_enabled: no\nstreisand_openconnect_enabled: no\nstreisand_openvpn_enabled: no\nstreisand_shadowsocks_enabled: yes\nstreisand_shadowsocks_v2ray_enabled: yes\nstreisand_ssh_forward_enabled: no\nstreisand_sshuttle_enabled: no\nstreisand_stunnel_enabled: no\nstreisand_tinyproxy_enabled: no\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: no\n"
  },
  {
    "path": "tests/site_vars/ssh.yml",
    "content": "---\n# This site config only enables SSH forwarding and sshutle\nvpn_clients: 5\nstreisand_ad_blocking_enabled: no\nstreisand_cloudflared_enabled: no\nstreisand_openconnect_enabled: no\nstreisand_openvpn_enabled: no\nstreisand_shadowsocks_enabled: no\nstreisand_shadowsocks_v2ray_enabled: no\nstreisand_ssh_forward_enabled: yes\nstreisand_sshuttle_enabled: yes\nstreisand_stunnel_enabled: no\nstreisand_tinyproxy_enabled: no\nstreisand_tor_enabled: no\nstreisand_wireguard_enabled: no\n"
  },
  {
    "path": "tests/syntax-check.yml",
    "content": "---\n\n# Include each playbook in order to check syntax of each playbook\n- name: Include amazon.yml\n  import_playbook: ../playbooks/amazon.yml\n\n- name: Include azure.yml\n  import_playbook: ../playbooks/azure.yml\n\n- name: Include cloud-status.yml\n  import_playbook: ../playbooks/cloud-status.yml\n\n- name: Include digitalocean.yml\n  import_playbook: ../playbooks/digitalocean.yml\n\n- name: Include existing-server.yml\n  import_playbook: ../playbooks/existing-server.yml\n\n- name: Include google.yml\n  import_playbook: ../playbooks/google.yml\n\n- name: Include lets-encrypt.yml\n  import_playbook: ../playbooks/lets-encrypt.yml\n\n- name: Include linode.yml\n  import_playbook: ../playbooks/linode.yml\n\n- name: Include localhost.yml\n  import_playbook: ../playbooks/localhost.yml\n\n- name: Include provider-detect.yml\n  import_playbook: ../playbooks/provider-detect.yml\n\n- name: Include python.yml\n  import_playbook: ../playbooks/python.yml\n\n- name: Include rackspace.yml\n  import_playbook: ../playbooks/rackspace.yml\n\n- name: Include ssh-setup.yml\n  import_playbook: ../playbooks/ssh-setup.yml\n\n- name: Include streisand.yml\n  import_playbook: ../playbooks/streisand.yml\n\n- name: Include test-client.yml\n  import_playbook: ../playbooks/test-client.yml\n\n- name: Include vagrant.yml\n  import_playbook: ../playbooks/vagrant.yml\n\n- name: Include run.yml\n  import_playbook: run.yml\n\n# Explicity include each role to ensure all roles are tested\n- hosts: localhost\n  remote_user: root\n  roles:\n    - azure-security-group\n    - certificates\n    - common\n    - diagnostics\n    - dnsmasq\n    - download-and-verify\n    - ec2-security-group\n    - gce-network\n    - genesis-amazon\n    - genesis-azure\n    - genesis-digitalocean\n    - genesis-google\n    - genesis-linode\n    - genesis-rackspace\n    - i18n-docs\n    - ip-forwarding\n    - lets-encrypt\n    - nginx\n    - openconnect\n    - openvpn\n    - service-net\n    - shadowsocks\n    - ssh\n    - ssh-forward\n    - sslh\n    - streisand-gateway\n    - streisand-mirror\n    - stunnel\n    - sysctl\n    - test-client\n    - tinyproxy\n    - tor-bridge\n    - ufw\n    - validation\n    - wireguard\n"
  },
  {
    "path": "tests/tests.sh",
    "content": "#!/usr/bin/env bash\n# Streisand CI test script.\n# Usage:\n#  ./tests.sh [setup|syntax|run|ci|full]\n\n# Set errexit option to exit immediately on any non-zero status return\nset -e\n\necho -e \"\\n\\033[38;5;255m\\033[48;5;234m\\033[1m  S T R E I S A N D  \\033[0m\\n\"\n\n# Compute an absolute path to the test ansible.cfg file\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nexport ANSIBLE_CONFIG=$DIR/ansible.cfg\n\n# Include the check_ansible function from ansible_check.sh\nsource util/ansible_check.sh\n\n# Use packages installed by snap first\nPATH=$PATH:/snap/bin:/var/lib/snapd/snap/bin\nexport PATH\n\nfunction run_playbook {\n  PLAYBOOK=\"$1\"\n  # shellcheck disable=SC2206\n  EXTRA_FLAGS=(${@:2})\n  # Special case: If $SITE is \"random\" then we mix things up\n  if [[ \"$SITE\" = \"random\" ]]; then\n    SITE=\"tests/site_vars/random.yml\"\n    \"$DIR/randomize_sitevars.sh\" \"$SITE\"\n  fi\n  SITE_DECL=\"\"\n  if [ -n \"$SITE\" ]; then\n    SITE_DECL=\"--extra-vars=@${SITE}\"\n  fi\n\n  ansible-playbook \\\n    -i \"$DIR/inventory\" \\\n    --extra-vars=@global_vars/globals.yml \\\n    $SITE_DECL \\\n    \"$PLAYBOOK\" \"${EXTRA_FLAGS[@]}\"\n}\n\n# syntax_check runs `ansible-playbook` with `--syntax-check` to vet Ansible\n# playbooks for syntax errors\nfunction syntax_check {\n  run_playbook \"$DIR/syntax-check.yml\" --syntax-check -vv\n}\n\nfunction dev_setup {\n  run_playbook \"$DIR/development-setup.yml\"\n}\n\nfunction run_tests {\n  run_playbook \"$DIR/run.yml\" --extra-vars=@\"$DIR/vars_ci.yml\" \"$1\"\n}\n\nfunction ci_tests {\n  dev_setup && run_tests\n}\n\nfunction ci_tests_verbose {\n  dev_setup && run_tests -vv\n}\n\n# Make sure the system is ready for the Streisand playbooks\ncheck_ansible\n\n# Allow overriding the RUN env var by providing an arg to the script\nif [ -n \"$1\" ]; then\n  RUN=\"$1\"\nfi\n\n# Setup prepares the local environment for running a Streisand LXC\nif [[ \"$RUN\" =~ \"setup\" ]] ; then\n    dev_setup\nfi\n\n# Syntax checks for Ansible syntax errors\nif [[ \"$RUN\" =~ \"syntax\" ]] ; then\n    syntax_check\nfi\n\n# Shellcheck checks for bash/sh errors/pitfalls\nif [[ \"$RUN\" =~ \"shellcheck\" ]] ; then\n  ./tests/shellcheck.sh\nfi\n\n# Yamlcheck checks for general YAML best practices\nif [[ \"$RUN\" =~ \"yamlcheck\" ]] ; then\n  ./tests/yamlcheck.sh\nfi\n\n# Run will run CI tests assuming the local environment is already prepared\nif [[ \"$RUN\" =~ \"run\" ]] ; then\n  run_tests\nfi\n\n# CI will setup the local environment and then run tests\nif [[ \"$RUN\" =~ \"ci\" ]] ; then\n  ci_tests\nfi\n\n# Full will do the same as \"ci\" but with verbose output\nif [[ \"$RUN\" =~ \"full\" ]] ; then\n  ci_tests_verbose\nfi\n"
  },
  {
    "path": "tests/vars_ci.yml",
    "content": "streisand_ci: yes\n\nstreisand_ssh_private_key: \"/tmp/id_rsa_insecure\"\n\n# Answer questions in playbooks/lets-encrypt.yml\nstreisand_domain_var: \"\"\nstreisand_domain: \"\"\nstreisand_admin_email_var: \"\"\nstreisand_admin_email: \"\"\nle_ok: no\n"
  },
  {
    "path": "tests/yamlcheck.sh",
    "content": "#!/bin/bash\n#\n# Streisand yamllint wrapper\n#\n# This test script finds all of the *.yml files in the project tree and\n# runs yamllint against them. Ignore any `venv` directory.\n#\n\n# Fail on errors\nset -e\n\n# Ensure yamllint is present\nif ! command -v yamllint > /dev/null 2>&1; then\n    echo \"The 'yamllint' command was not found in your PATH.\"\n    echo \"Please run 'pip install yamllint' to install.\"\n    exit 1\nfi\n\n# Determine the absolute path of this script file's directory\nSCRIPT_DIR=\"$(cd \"$(dirname \"$0\")\" && pwd -P)\"\n# The Streisand project directory is one up from this script's directory, tests/\nPROJECT_DIR=\"$SCRIPT_DIR/..\"\n\n# Streisand specifies a custom yamllint config to adjust what rules are applied\nYAMLLINT_ARGS=(-c \"$SCRIPT_DIR/yamllint-config.yml\")\n\npushd \"$PROJECT_DIR\"\n  # Run yamllint against all of the `.yml` files in the Streisand\n  # project directory.\n  #\n  # NOTE(@cpu): While tempting to -exec shellcheck directly from find this will\n  # eat-up any non-zero exit codes :-( Instead we find the files first and then\n  # xargs yamllint on the found files.\n  find . -path \"./venv\" -prune -or -name '*.yml' -print0 | xargs -0 -n1 yamllint \"${YAMLLINT_ARGS[@]}\"\npopd\n"
  },
  {
    "path": "tests/yamllint-config.yml",
    "content": "extends: default\n\nrules:\n  # Presently there are a large number of files that break the line-length\n  # limit.This changes the limit to a warning until we are ready to try and\n  # tackle these legacy files.\n  line-length:\n    max: 280\n    level: warning\n  # We allow a few rules for now to accept the \"pretty\" layout existing files\n  # use. It may be worth revisiting these in the future.\n  # Accept:\n  # * \"too many spaces after colon\"\n  # * \"too many spaces inside braces\"\n  # * \"truthy value should be one of [false, true] but we use [no, yes]\"\n  colons: disable\n  braces: disable\n  commas: disable\n  truthy: disable\n"
  },
  {
    "path": "util/ansible_check.sh",
    "content": "# shellcheck shell=bash\n\n# This is included by the main streisand script.\n\n# check_ansible checks that Ansible is installed on the local system\n# and that it is a supported version.\nfunction check_ansible() {\n  local REQUIRED_ANSIBLE_VERSION=\"2.8.4\"\n\n  if ! command -v ansible > /dev/null 2>&1; then\n    echo \"\nStreisand requires Ansible and it is not installed.\nPlease see the README Installation section on Prerequisites\"\n    exit 1\n  fi\n\n  ansible_version=\"$(ansible --version | head -1 | grep -oe '2[.0-9]*')\"\n\n  if ! ./util/version_at_least.py \"$REQUIRED_ANSIBLE_VERSION\" \"$ansible_version\" ; then\n      echo \"\nStreisand requires Ansible version $REQUIRED_ANSIBLE_VERSION or higher.\nThis system has Ansible $ansible_version.\n\"\n      exit 1\n  fi\n}\n"
  },
  {
    "path": "util/dependencies.txt",
    "content": "build-essential\npython3-pip\npython3-openssl\npython3-dev\npython3-setuptools\npython3-venv\npython-cffi libffi-dev\nlibssl-dev\nlibcurl4-openssl-dev\n"
  },
  {
    "path": "util/print-aws-regions.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n# Generate code fragments for amazon.yml\n\nnames = (\n    (\"us-east-1\",      \"US East\",      \"N. Virginia\"),\n    (\"us-east-2\",      \"US East\",      \"Ohio\"),\n    (\"us-west-1\",      \"US West\",      \"N. California\"),\n    (\"us-west-2\",      \"US West\",      \"Oregon\"),\n    (\"ca-central-1\",   \"Canada\",       \"Central\"),\n    (\"eu-central-1\",   \"EU\",           \"Frankfurt\"),\n    (\"eu-west-1\",      \"EU\",           \"Ireland\"),\n    (\"eu-west-2\",      \"EU\",           \"London\"),\n    (\"eu-west-3\",      \"EU\",           \"Paris\"),\n    (\"ap-northeast-1\", \"Asia Pacific\", \"Tokyo\"),\n    (\"ap-northeast-2\", \"Asia Pacific\", \"Seoul\"),\n    (\"ap-northeast-3\", \"Asia Pacific\", \"Osaka-Local\"),\n    (\"ap-southeast-1\", \"Asia Pacific\", \"Singapore\"),\n    (\"ap-southeast-2\", \"Asia Pacific\", \"Sydney\"),\n    (\"ap-south-1\",     \"Asia Pacific\", \"Mumbai\"),\n    (\"ap-east-1\",      \"Asia Pacific\", \"Hong Kong\"),\n    (\"eu-north-1\",     \"EU\",           \"Stockholm\"),\n    (\"sa-east-1\",      \"South America\", \"São Paulo\"),\n)\n\nsorted_names = sorted(names)\n\nprint(\"\")\nprint (\"\"\"\n    regions:\"\"\")\nfor i in range(len(sorted_names)):\n    j = i + 1\n    o = sorted_names[i]\n    print('      \"{j}\": \"{symname}\"'.format(j=j, symname=o[0]))\n\nprint (\"----------------------\")\n\nprint (\"\")\nprint (\"\"\"\n        In what region should the server be located?\"\"\")\nfor i in range(len(sorted_names)):\n    j = i + 1\n    o = sorted_names[i]\n    print(\"          {j:>2}. {symname:<15} {region:<14} ({nickname})\".format(\n        j=j, symname=o[0], region=o[1], nickname=o[2]))\n"
  },
  {
    "path": "util/source_check_and_default_site_vars.sh",
    "content": "#!/bin/bash\n#\n# This is intended to be sourced into a deploy script. It exists to DRY up the\n# codebase. It expects the following variables set:\n#\n# DEFAULT_SITE_VARS /path/to/default-site.yml\n# PROJECT_DIR /path/to/streisand\n# SITE_VARS /path/to/site.yml\n#\n\nset -o errexit\n\n# If no site vars file is provided, then use one of the two default options.\nif [ -z \"${SITE_VARS}\" ]; then\n\n  SITE_VARS=\"${HOME}/.streisand/site.yml\"\n\n  if [ ! -f \"${SITE_VARS}\" ]; then\n    SITE_VARS=\"${DEFAULT_SITE_VARS}\"\n  fi\n\n  echo \"Using default config file: ${SITE_VARS}\"\nfi\n\n# Make sure the alleged configuration file exists.\nif [ ! -f \"${SITE_VARS}\" ]; then\n  echo \"No such config file: ${SITE_VARS}\"\n  exit 1\nfi\n"
  },
  {
    "path": "util/source_validate_and_deploy.sh",
    "content": "#!/bin/bash\n#\n# This is intended to be sourced into a deploy script. It exists to DRY up the\n# codebase. It expects the following variables set:\n#\n# DEFAULT_SITE_VARS /path/to/default-site.yml\n# GLOBAL_VARS /path/to/globals.yml\n# INVENTORY /path/to/inventory\n# PROJECT_DIR /path/to/streisand\n# SITE_VARS /path/to/site.yml\n# PLAYBOOK /path/to/playbook.yml.\n#\n\nset -o errexit\n\nansible-playbook \\\n  --extra-vars=\"@${GLOBAL_VARS}\" \\\n  --extra-vars=\"@${DEFAULT_SITE_VARS}\" \\\n  --extra-vars=\"@${SITE_VARS}\" \\\n  \"${PROJECT_DIR}/playbooks/validate.yml\"\n\n# Update the server.\nansible-playbook \\\n  -i \"${INVENTORY}\" \\\n  --extra-vars=\"@${GLOBAL_VARS}\" \\\n  --extra-vars=\"@${DEFAULT_SITE_VARS}\" \\\n  --extra-vars=\"@${SITE_VARS}\" \\\n  \"${PLAYBOOK}\"\n"
  },
  {
    "path": "util/ubuntu-dependencies.sh",
    "content": "#!/bin/bash\n\n# Abort on any error.\nset -e\n\n# This script installs Streisand builder dependencies on an Ubuntu\n# 16.04 system; Debian jessie has been lightly tested. It installs\n# system-wide packages. As a result, this is most useful on a fresh\n# machine, where conflicting Python packages won't be installed. If\n# you're not on a fresh regular machine, consider using\n# venv-dependencies.sh instead.\n#\n# It's safe to run this script multiple times. For most cloud\n# providers, it should work as a boot/cloud-init script.\n#\n# The defaults are fine for an interactive install. If you are using\n# this as a cloud-init script, change the first two settings:\n#\n#  *  quiet must be \"--yes\"\n#  *  The \"DEBIAN_FRONTEND\" line must be uncommented.\n\n# We default to a regular, interactive upgrade.\nquiet=\n# quiet='--yes'\n\n# If you *really* want no interaction (for example, overwriting local\n# config files without prompting), then uncomment this:\n# export DEBIAN_FRONTEND=noninteractive\n\n# If you'd prefer to install dependencies in ~/.local/bin, uncomment\n# this function and comment the next.\n\n#function our_pip_install () {\n#    pip3 install --user --upgrade \"$@\"\n#}\n\nfunction our_pip_install () {\n    $sudo_for_pip_install pip3 install --upgrade \"$@\"\n}\n\n### No options below this line. ###\n\nsudo_command=\"sudo\"\nsudo_for_pip_install=\"sudo -H\"\n\n# If we're root, get rid of sudo--it may not be there...\nif [ \"$(id -u)\" == \"0\" ]; then\n    sudo_command=\"\"\n    sudo_for_pip_install=\"\"\nfi\n\n$sudo_command apt-get update\n# shellcheck disable=SC2086\n$sudo_command apt-get $quiet upgrade\n\n# Prefer binaries distributed by upstream OS over those in the pip\n# repository.\n\n# We explicitly want word splitting.\n# shellcheck disable=SC2046,SC2086\n$sudo_command apt-get $quiet install $(cat ./util/dependencies.txt)\n\n# Debian doesn't have python-nacl. We'll have to accept the pip\n# version.\n# shellcheck disable=SC2086\nif ! $sudo_command apt-get $quiet install python-nacl libssl-dev; then\n    our_pip_install pynacl\nfi\n\n# We only really wanted python-pip for its dependencies. Upgrade it.\nour_pip_install pip\n\n# The pip we want should be in our path now. Make sure we use it.\nhash -r\n\n# We explicitly want word splitting.\n# shellcheck disable=SC2059,SC2086\nour_pip_install -r requirements.txt\n\necho '\nStreisand dependencies installed.\n'\n"
  },
  {
    "path": "util/venv-dependencies.sh",
    "content": "#!/bin/bash\n\n# Abort on any error.\nset -e\n\n# Usage: util/venv-dependencies.sh NEW-DIRECTORY\n#\n# See the usage function below.\n\nquiet=\n# pip makes a lot of noise when installing. Uncomment the following\n# line to make it a little quieter.\n# quiet=--quiet\n\n#### Options end here.\n\nusage () {\n       echo \"\nUsage: $0 ./venv\n\nThis script creates an isolated Python virtualenv at './venv', and\ninstalls Ansible and dependencies into it.\n\nThe script depends on Python 3.5 or later.\n\nIf this system is running Debian or Ubuntu, this script will also\ncheck for other packages needed to install.\n\nAlthough './venv' is recommended, you can specify another location to\ncreate the virtualenv. If the location already exists, it should be an\nexisting virtualenv to overwrite.\n\n\"\n}\n\nis_root=\"\"\nif [ \"$(id -u)\" == \"0\" ]; then\n    is_root=1\nfi\n\n\npython=\"python3\"\nsudo_command=\"sudo\"\nsudo_for_pip_install=\"sudo -H\"\n\n# If we're root, get rid of sudo--it may not be there...\nif [ -n \"$is_root\" ]; then\n    sudo_command=\"\"\n    sudo_for_pip_install=\"\"\nfi\n\nrequest_python_3 () {\n    echo \"\nOn Debian, Ubuntu, and WSL:\n   $sudo_command apt install python3 python3-pip python3-virtualenv\n\nOn macOS:\n   # If you haven't, install homebrew from https://brew.sh/\n   brew install python\n\nOn other systems: please see your OS documentation on how to install\nPython 3.\n\"\n    exit 1\n}\n\nensure_python_3_5 () {\n    python_version=$($python --version 2>&1)\n    if [[ $python_version < \"Python 3.5\" ]]; then\n\techo \"\n\nThe $python command invokes $python_version. Python 3.5 or later is\nrequired.\n\"\n\treturn 1\n    fi\n    return 0\n}\n\nif [ \"$#\" -ne 1 ]; then\n   usage\n   exit 1\nfi\n\nif type -p $python >/dev/null; then\n    echo \"Found a python3 command....\"\n    if ! ensure_python_3_5; then\n\trequest_python_3\n\texit 1\n    fi\nelse\n    echo \"The command 'python3' doesn't appear to exist. Trying 'python'...\"\n    python='python'\n    if ! type -p $python >/dev/null; then\n\techo \"\n\nOn your system, neither 'python3' or 'python' exist as commands. Please\ninstall Python 3.5 or later.\n\n\"\n\trequest_python_3\n\texit 1\n    fi\n    if ! ensure_python_3_5; then\n\trequest_python_3\n\texit 1\n    fi\nfi\n\n# Whew. We now have a working Python 3.5 or later in $python.\n\nhard_detect_dpkg () {\n    dpkg-query --status \"$1\" 2>/dev/null | grep '^Status:.* installed' >/dev/null\n}\n\ncheck_deb_dependencies () {\n    critical=\"$(cat ./util/dependencies.txt)\"\n    packages_not_found=\"\"\n    for pkg in $critical; do\n\tif ! hard_detect_dpkg \"$pkg\"; then\n\t    echo \"*** Missing package: $pkg\"\n\t    packages_not_found+=\" $pkg\"\n\telse\n\t    echo \"Found: $pkg\"\n\tfi\n    done\n\n    if [ -n \"$packages_not_found\" ]; then\n\techo \"-------\"\n\techo \"Setup will fail without these packages. To install them:\"\n\techo \"\"\n\techo -n \"$sudo_command apt-get install \"\n\t# explicitly want word-spliting here\n\t# shellcheck disable=SC2086\n\techo $packages_not_found\n\techo\n\texit 1\n    else\n\techo\n\techo \"Found all critical packages.\"\n\techo\n    fi\n}\n\nif [ -f /etc/debian_version ]; then\n    echo\n    echo \"This system appears to be running Ubuntu or Debian. Checking\"\n    echo \"for critical packages.\"\n    echo\n    check_deb_dependencies\nfi\n\ndie () {\n    echo \"$@\"\n    exit 1\n}\n\nif ! $python -m venv -h >/dev/null; then\n    echo \"\n\nThe command 'python -m venv -h' failed. The venv module is a standard\npart of Python, and this script can't proceeed without it. Please\nreport details of your system to the authors of this package if stuck.\nThe output of 'python -m venv' is:\n\n\"\n    $python -m venv -h\n    exit 1\nfi\n\n# We want to run some tests on the parent of the path on the command\n# line.\nparent_dirname=\"$(dirname \"$1\")\"\n\nif [ ! -d \"$parent_dirname\" ]; then\n    die \"\nThe parent directory of $1 ($parent_dirname) does not exist. Please\nspecify a parent directory you can write to. './venv' is a good choice.\n\n\"\nfi\n\nif [ ! -w \"$parent_dirname\" ]; then\n    die \"\nThe parent directory of $1 ($parent_dirname) is not writable. Please specify a\nparent directory you can write to. './venv' is a good choice.\n\n\"\nfi\n\n# The virtualenv directory should be created from scratch. But if the\n# directory already exists *and* it looks like it was a virtualenv,\n# don't pester the user; just use \"virtualenv --clear\" to clean it out.\n\n# In any case, this script will not run \"rm -rf $1\", regardless of how\n# tempting.\n\nif [ -e \"$1\" ]; then\n    if [ ! -e \"$1/bin/activate.csh\" ]; then\n\tdie \"\nThe directory $1 already exists, and it does not appear to contain a\nPython virtualenv. Please specify a new directory to be\ncreated. './venv' is a good choice if it doesn't exist.\n\n\"\n    fi\nfi\n\nsudo_pip () {\n    # shellcheck disable=SC2086\n    # pip complains loudly about directory permissions when sudo without -H.\n    $sudo_for_pip_install pip3 $quiet \"$@\"\n}\n\nour_pip () {\n    # shellcheck disable=SC2086\n    pip3 $quiet \"$@\"\n}\n\nour_pip_install () {\n    our_pip install \"$@\"\n}\n\nNO_SITE_PACKAGES=\"\"\n\n# shellcheck disable=SC2086\nif ! $python -m venv --clear $NO_SITE_PACKAGES \"$1\"; then\n    parent_dirname=\"$(dirname \"$1\")\"\n    echo \"\n'python -m venv' failed to create directory '$1'\n\nNote that $1 must not exist, but its parent ($parent_dirname) must\nexist.\n\nThe first argument, 'new-directory', must be somewhere you can write\nto. A good place is './venv'. If it already exists, please delete the\ndirectory, or use a different name.\n\n\"\n    exit 1\nfi\n\n[ -d \"$1\" ] || die \"Missing venv directory $1! Something badly wrong.\"\n\n# This mucks around with our environment variables. We know where it\n# is at shellcheck time.\n\n# shellcheck disable=SC1090\nsource \"$1/bin/activate\"\n\n# Below this line, we are only installing into the virtualenv at \"$1\"\n\nour_pip_install --upgrade pip\n\n# The pip we want should be in our path now. Make sure we use it.\nhash -r\n\n# Now we can install all the Python modules.\nour_pip_install -r requirements.txt\n\necho \"\n*************\n\nAll dependencies installed into $1. To use this environment, run this\nin your shell:\n\n    source \\\"$1/bin/activate\\\"\n\nYou need to do this once in every terminal window you plan to run the\ncommand './streisand' in.\n\nAfter you've run that, you're ready to run ./streisand.\n\"\n"
  },
  {
    "path": "util/version_at_least.py",
    "content": "#!/usr/bin/env python\n\nimport sys\nfrom distutils.version import StrictVersion\n\nif len(sys.argv) != 3:\n    print(\"Usage: version_at_least minimum_version version_to_check\")\n    sys.exit(1)\n\nminimum_version = StrictVersion(sys.argv[1].strip())\nversion_to_check = StrictVersion(sys.argv[2].strip())\n\nif version_to_check >= minimum_version:\n    sys.exit(0)\nelse:\n    sys.exit(1)\n"
  }
]