diff --git a/.gitignore b/.gitignore index 4367994..8773f7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ var/ -.* +*~ diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..656da23 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,27 @@ +1. Clone the repo + + git clone https://github.com/fracz/git-exercises.git + cd git-exercises + +2. Adjust the environment variables + + cd docker + cp env.example .env + + Change the values of those variables according to your domain specifics : + + DOMAIN_NAME= # used in the cloning URL + SITE_ADMIN_NAME= # used as the committer name for given commits + SITE_ADMIN_EMAIL= # used as the committer email for given commits + + Change the value of this variable if you wish to use a different repo as a source of exercises : + + GIT_REPO= + +3. Run with docker-compose + + docker-compose up -d + +4. The web app should be available at https://$DOMAIN_NAME/ + +5. The exercise repo should be available at git://$DOMAIN_NAME/git/exercises.git diff --git a/README.md b/README.md index 872d449..7d20c5a 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,76 @@ This repository contains the source code of the [git-exercises](https://gitexercises.fracz.com/) platform for practising git. ![git-exercises](frontend/public/images/intro.gif) + +## Overview + +This project consists of two docker images: mysql and an apache server. + +## Setup + +*Windows 10*: +``` +Docker desktop community 2.3.0.3 + - docker-compose version 1.25.5, build 8a1c60f6 + - Docker version 19.03.8, build afacb8b +MySQL Workbench 8.0 +``` + +*Ubuntu 18.04.5*: +``` +docker-compose version 1.17.1, build unknown +Docker version 19.03.6, build 369ce74a3c +mysql-client-core-5.7 +``` + +## Configuration + +The only file you need to update is `docker/.env` + +## How to build + +In directory `/docker` run +``` +docker-compose build +``` + +Make sure the default branch of your repo is `verifications` + +## How to run + +In directory `/docker` run +``` +docker-compose run +``` + +## Database schema initialization + +First time you need to run `backend/schema/gitexercises.sql` + +To execute these instructions do + +```bash +# login to mysql running in docker container +mysql -h localhost -P 3306 --protocol=tcp -u root +# in mysql shell +CREATE DATABASE ; +USE ; +# run the sql file +source 'backend/schema/gitexercises.sql' + +``` + +## Start exercising + +Assuming you run on localhost, this is how you start with exercise 1 + +```bash +git clone http://localhost/git/exercises.git git-exercises +cd git-exercises +./configure.sh +git start +``` + +## Adding new exercises + +See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/backend/.gitignore b/backend/.gitignore index 11fe973..45aadc4 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,5 +1,4 @@ vendor/ composer.phar -config.php *.log *.bak diff --git a/backend/composer.json b/backend/composer.json index 24d23aa..87814a8 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -1,5 +1,5 @@ { - "name": "git-exercises", + "name": "fracz/git-exercises", "require": { "php": ">=5.5", "slim/slim": "2.6.2", diff --git a/backend/composer.lock b/backend/composer.lock deleted file mode 100644 index 2974559..0000000 --- a/backend/composer.lock +++ /dev/null @@ -1,118 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", - "This file is @generated automatically" - ], - "hash": "c36aa61e8aeb792c94395ec83b037042", - "content-hash": "5f274745c29131ac98a15dc99797f5d2", - "packages": [ - { - "name": "michelf/php-markdown", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/michelf/php-markdown.git", - "reference": "156e56ee036505ec637d761ee62dc425d807183c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/michelf/php-markdown/zipball/156e56ee036505ec637d761ee62dc425d807183c", - "reference": "156e56ee036505ec637d761ee62dc425d807183c", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-lib": "1.4.x-dev" - } - }, - "autoload": { - "psr-0": { - "Michelf": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Michel Fortin", - "email": "michel.fortin@michelf.ca", - "homepage": "https://michelf.ca/", - "role": "Developer" - }, - { - "name": "John Gruber", - "homepage": "https://daringfireball.net/" - } - ], - "description": "PHP Markdown", - "homepage": "https://michelf.ca/projects/php-markdown/", - "keywords": [ - "markdown" - ], - "time": "2015-12-24 01:37:31" - }, - { - "name": "slim/slim", - "version": "2.6.2", - "source": { - "type": "git", - "url": "https://github.com/slimphp/Slim.git", - "reference": "20a02782f76830b67ae56a5c08eb1f563c351a37" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/20a02782f76830b67ae56a5c08eb1f563c351a37", - "reference": "20a02782f76830b67ae56a5c08eb1f563c351a37", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "suggest": { - "ext-mcrypt": "Required for HTTP cookie encryption" - }, - "type": "library", - "autoload": { - "psr-0": { - "Slim": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Lockhart", - "email": "info@joshlockhart.com", - "homepage": "http://www.joshlockhart.com/" - } - ], - "description": "Slim Framework, a PHP micro framework", - "homepage": "http://github.com/codeguy/Slim", - "keywords": [ - "microframework", - "rest", - "router" - ], - "time": "2015-03-08 18:41:17" - } - ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.5" - }, - "platform-dev": [] -} diff --git a/backend/config.php b/backend/config.php new file mode 100644 index 0000000..787192b --- /dev/null +++ b/backend/config.php @@ -0,0 +1,10 @@ +getApp()->committerService->getPassedExercises($id); $result['nextExercise'] = $this->getApp()->committerService->suggestNextExercise($result['passedExercises']); } else { - $result['nextExercise'] = 'master'; + $result['nextExercise'] = 'main'; $result['passedExercises'] = []; } return $result; diff --git a/backend/hook/AbstractVerification.php b/backend/hook/AbstractVerification.php index dec1b87..c7dd6d3 100644 --- a/backend/hook/AbstractVerification.php +++ b/backend/hook/AbstractVerification.php @@ -21,14 +21,6 @@ public function verify() $this->doVerify(); } - public function getSolution() - { - $solutionFile = __DIR__ . '/hints/' . get_class($this) . '-solution.txt'; - if (file_exists($solutionFile)) { - return file_get_contents($solutionFile); - } - } - protected abstract function doVerify(); protected function ensure($condition, $errorMessage, array $formatVars = []) diff --git a/backend/hook/hints/CommitOneFile-solution.txt b/backend/hook/hints/CommitOneFile-solution.txt deleted file mode 100644 index 4e6c400..0000000 --- a/backend/hook/hints/CommitOneFile-solution.txt +++ /dev/null @@ -1,2 +0,0 @@ -git add A.txt -git commit -m "Commit A.txt file" diff --git a/backend/hook/hints/CommitOneFileStaged-hint.md b/backend/hook/hints/CommitOneFileStaged-hint.md deleted file mode 100644 index 043e5e2..0000000 --- a/backend/hook/hints/CommitOneFileStaged-hint.md +++ /dev/null @@ -1,3 +0,0 @@ -In order to remove files from staging area you should use the [`git reset`](https://git-scm.com/docs/git-reset) command. - -Files that are not in the staging area will not be taken into the next commit. diff --git a/backend/hook/hints/Executable-hint.md b/backend/hook/hints/Executable-hint.md deleted file mode 100644 index 8c3beef..0000000 --- a/backend/hook/hints/Executable-hint.md +++ /dev/null @@ -1 +0,0 @@ -You should use the [`git update-index`](https://git-scm.com/docs/git-update-index) command with appropriate `--chmod` flag. diff --git a/backend/hook/hints/FixTypo-solution.txt b/backend/hook/hints/FixTypo-solution.txt deleted file mode 100644 index 9c1c1bb..0000000 --- a/backend/hook/hints/FixTypo-solution.txt +++ /dev/null @@ -1,3 +0,0 @@ -# fix the typo in the file -git commit -a --amend -# fix the typo in commit message diff --git a/backend/hook/hints/MergeConflict-solution.txt b/backend/hook/hints/MergeConflict-solution.txt deleted file mode 100644 index 07d3f23..0000000 --- a/backend/hook/hints/MergeConflict-solution.txt +++ /dev/null @@ -1,4 +0,0 @@ -git merge another-piece-of-work -echo 2+3=5 > equation.txt -git add equation.txt -git commit --no-edit diff --git a/backend/hook/hook.php b/backend/hook/hook.php index 1fcc092..13ac3ae 100755 --- a/backend/hook/hook.php +++ b/backend/hook/hook.php @@ -8,14 +8,16 @@ ini_set("error_log", __DIR__ . "/../data/logs/hook-error.log"); require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/../config.php'; use GitExercises\hook\utils\ConsoleUtils; use GitExercises\hook\utils\GitUtils; +use GitExercises\services\ExerciseUtils; use GitExercises\services\CommitterService; use GitExercises\services\GamificationService; use GitExercises\services\ShortIdService; -define('DOMAIN', 'https://gitexercises.fracz.com'); +define('DOMAIN', 'http://' . DOMAIN_NAME); $branch = $argv[1]; $oldRev = $argv[2]; @@ -35,8 +37,9 @@ $shortCommiterId = (new ShortIdService())->getShort($committerId); $gamificationService = new GamificationService($committerId); -$possibleCommand = ucfirst(AbstractVerification::dashToCamelCase($exercise)); +$possibleCommand = ucfirst($exercise); $command = 'GitExercises\\hook\\commands\\' . $possibleCommand . 'Command'; + if (class_exists($command)) { (new $command())->execute($committerId); } else { @@ -55,7 +58,7 @@ try { $verifier->verify(); echo ConsoleUtils::green('PASSED') . PHP_EOL; - $solution = $verifier->getSolution(); + $solution = ExerciseUtils::getExerciseSolution($exercise); if ($solution) { echo PHP_EOL . ConsoleUtils::pink('The easiest solution:') . PHP_EOL . trim($solution) . PHP_EOL . PHP_EOL; } diff --git a/backend/hook/utils/GitUtils.php b/backend/hook/utils/GitUtils.php index ab97a51..6e45deb 100644 --- a/backend/hook/utils/GitUtils.php +++ b/backend/hook/utils/GitUtils.php @@ -48,9 +48,9 @@ public static function getCommitDate($commitId) * @param $commitId * @return array indexed by filenames, values are operations (M, A, D) */ - public static function getChangedFiles($commitId) + public static function getChangedFiles($commitId, $secondCommitId="") { - exec("git diff-tree --no-commit-id --name-status -r $commitId", $changes); + exec("git diff-tree --no-commit-id --name-status -r $commitId $secondCommitId", $changes); $changedFiles = []; foreach ($changes as $change) { $data = explode("\t", $change); @@ -83,7 +83,7 @@ public static function checkIgnore($commitId, $filename) { exec("git checkout -q $commitId"); exec("git check-ignore -v $filename", $result, $status); - exec("git checkout -q master"); + exec("git checkout -q main"); if ($status) { return false; } diff --git a/backend/hook/verifications/CommitOneFile.php b/backend/hook/verifications/CommitOneFile.php deleted file mode 100644 index 22501d3..0000000 --- a/backend/hook/verifications/CommitOneFile.php +++ /dev/null @@ -1,15 +0,0 @@ -ensureCommitsCount(1); - $file = $this->ensureFilesCount($commit, 1); - $this->ensure(in_array($file, ['A.txt', 'B.txt']), 'None of the generated files has been commited. Received %s.', [ConsoleUtils::blue($file)]); - } -} diff --git a/backend/schema/gitexercises.mwb b/backend/schema/gitexercises.mwb deleted file mode 100644 index 0211dde..0000000 Binary files a/backend/schema/gitexercises.mwb and /dev/null differ diff --git a/backend/scripts/exercise-tester.php b/backend/scripts/exercise-tester.php index 7c21d40..24af734 100644 --- a/backend/scripts/exercise-tester.php +++ b/backend/scripts/exercise-tester.php @@ -29,11 +29,11 @@ if (!is_dir($repo)) { system('cd ' . __DIR__ . ' && git clone ' . REPO_URL . ' ' . LOCAL_DIR_NAME); run('git checkout verifications'); - run('git branch -D master'); + run('git branch -D main'); run('git remote rm origin'); run('git remote add origin ' . VERIFICATION_URL); run('git fetch origin'); - run('git checkout master'); + run('git checkout main'); run('configure.sh'); } diff --git a/backend/services/ExerciseUtils.php b/backend/services/ExerciseUtils.php index 97e9b11..fcdf653 100644 --- a/backend/services/ExerciseUtils.php +++ b/backend/services/ExerciseUtils.php @@ -23,32 +23,23 @@ public static function getExerciseName($id) public static function getExerciseSummary($id) { - $name = self::dashToCamelCase($id); - return @file_get_contents(__DIR__ . "/../hook/hints/$name-summary.md"); + return @file_get_contents(__DIR__ . "/../hook/hints/$id-summary.md"); } public static function getExerciseHint($id) { - $name = self::dashToCamelCase($id); - return @file_get_contents(__DIR__ . "/../hook/hints/$name-hint.md"); + return @file_get_contents(__DIR__ . "/../hook/hints/$id-hint.md"); } private static function getExerciseReadmeContent($id) { - exec("git show remotes/origin/$id:README.md", $contents); + exec("cd ". __DIR__ ."/../../../git/exercises.git && git show $id:README.md", $contents); return $contents; } public static function getExerciseSolution($id) { - $name = self::dashToCamelCase($id); - return @file_get_contents(__DIR__ . "/../hook/hints/$name-solution.txt"); + return @file_get_contents(__DIR__ . "/../hook/hints/$id-solution.txt"); } - private static function dashToCamelCase($name) - { - return ucfirst(preg_replace_callback('/-(.?)/', function ($matches) { - return ucfirst($matches[1]); - }, $name)); - } } diff --git a/backend/services/JsonHelper.php b/backend/services/JsonHelper.php index 0d941a2..bd4024a 100644 --- a/backend/services/JsonHelper.php +++ b/backend/services/JsonHelper.php @@ -15,7 +15,7 @@ public static function setResponse(Response $response, $content, $status = 200) public static function toJson($content) { - return ")]}',\n" . json_encode($content); + return json_encode($content); } private static function prepareDataToSend($content) diff --git a/configure.sh b/configure.sh new file mode 100755 index 0000000..99e4beb --- /dev/null +++ b/configure.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Configure "git start" local alias for starting the exercise of user's choice and restarting the current one. +git config --local alias.start "! f() { export LC_ALL=C; currentBranch=\$(git rev-parse --abbrev-ref HEAD); exercise=\${1-\$currentBranch}; if [ \$exercise != HEAD ]; then if [ \$exercise != next ]; then if git show origin/\$exercise:start.sh >/dev/null 2>&1 ; then if git checkout -f \$exercise >/dev/null 2>&1 && git reset --hard origin/\$exercise >/dev/null 2>&1 && git clean -fdx >/dev/null ; then if echo \"Preparing the exercise environment, hold on...\" && ./start.sh >/dev/null 2>&1; then echo \"Exercise \$exercise started!\" && echo 'Read the README.md for instructions or view them in browser:' && echo \"http://gitexercises.fracz.com/e/\$exercise\" ; else echo 'Could not execute the start script.' && echo 'Try running the ./start.sh script yourself.' ; fi else echo 'Could not clean the working directory.' && echo 'Make sure that none of the files inside the working directory' && echo 'is used by another process and run git start again.'; fi else echo \"Invalid exercise: \$exercise\" && false; fi else git push origin master:next-exercise 2>&1 | sed -n '/\\*\\*\\*/,/\\*\\*\\*/p' | grep -v '\\*\\*' | sed 's/remote: //g' | xargs git start | grep -v Invalid || echo 'You have passed all exercises!'; fi else echo 'You need to use git start in detached HEAD'; fi }; f" + +# Add "git verify" local alias for submitting exercises solutions. +git config --local alias.verify "! f() { export LC_ALL=C; currentBranch=\$(git rev-parse --abbrev-ref HEAD); exercise=\${1-\$currentBranch}; if [ \$exercise != HEAD ]; then if git show origin/\$exercise:start.sh >/dev/null 2>&1 ; then if ! (git status | grep 'up-to-date' >/dev/null 2>&1 || git status | grep 'up to date' >/dev/null 2>&1) ; then if echo \"Verifying the \$exercise exercise. Hold on...\" && git push -f origin HEAD:\$exercise 2>&1 | sed -n '/\\*\\*\\*/,/\\*\\*\\*/p' | sed 's/remote: //g' | grep -v \"\\*\\*\" ; then : ; else echo 'Solution could not be verified - push failed.' && echo 'Do you have an internet connection?'; fi else echo \"You haven't made any progress on exercise \$exercise.\" && echo 'Did you forget to commit your changes?'; fi else echo \"Invalid exercise: \$exercise\"; fi else echo 'You need to use git verify in detached HEAD'; fi }; f" + +# Add "git exercises" alias that shows list of available exercises. +git config --local alias.exercises "! git push origin master:exercises 2>&1 | sed -n '/\\*\\*\\*/,/\\*\\*\\*/p' | grep -v '\\*\\*' | sed 's/remote: //g'" + +# Make sure you have a "current" push strategy set; this will allow you to push only current exercise with simple git +# push command instead of pushing all matching branches (default in Git < 2.0) +git config --local push.default current + +echo "OK" diff --git a/docker/.env.sample b/docker/.env.sample deleted file mode 100644 index dc3e563..0000000 --- a/docker/.env.sample +++ /dev/null @@ -1,16 +0,0 @@ -COMPOSE_PROJECT_NAME=gitexercises -DATABASE_PASSWORD=CHANGE_ME_BEFORE_FIRST_LAUNCH -# set this to the uid of the user that will run docker container (get it with: echo $UID) -UID=1001 - -VOLUME_SOURCES=../ -VOLUME_DATA=../var - - -##### STANDALONE MODE CONFIGURATION ##### -#PORT_HTTP=80 - - -##### PROXIED MODE CONFIGURATION ##### -#DOMAIN_NAME=gitexercises.fracz.com -#ADMIN_EMAIL=fraczwojciech@gmail.com diff --git a/docker/Dockerfile b/docker/Dockerfile index cc20f18..8f8daaf 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,10 +1,31 @@ -FROM php:7.1.26-apache +# Backend build stage +FROM composer:latest AS backend_build -WORKDIR /var/www +COPY backend/composer.json /var/www/ +RUN composer install -d /var/www/ + +# Frontend build stage +FROM node:lts-alpine as frontend_build +ARG DOMAIN_NAME + +RUN apk add git + +COPY frontend /app/ +RUN sed -i -r "s|REPLACE_ME|https:\/\/${DOMAIN_NAME}|g" /app/app/home/startCommands.coffee + +WORKDIR /app -RUN apt-get update \ - && curl -sL https://deb.nodesource.com/setup_6.x | bash - \ - && apt-get install -y --no-install-recommends \ +RUN npm install +RUN npm install bower -g + +RUN bower --allow-root install +RUN npm run-script dist + +# Production stage +FROM php:7.4.33-apache + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ libicu-dev \ libpq-dev \ ca-certificates \ @@ -12,32 +33,50 @@ RUN apt-get update \ libcurl4-gnutls-dev \ git \ unzip \ - nodejs \ - zlib1g-dev \ - && update-ca-certificates \ - && docker-php-ext-install \ + libzip-dev + +RUN update-ca-certificates +RUN docker-php-ext-install \ pdo_mysql \ opcache \ curl \ - zip \ - && apt-get autoremove \ + zip + +RUN apt-get autoremove \ && rm -r /var/lib/apt/lists/* +COPY ./docker/apache-conf/000-default.conf /etc/apache2/sites-enabled/000-default.conf RUN a2enmod rewrite expires deflate ssl cgi alias env headers -RUN mkdir git \ - && touch v4 \ - && mkdir workingarea \ - && git clone --bare https://github.com/fracz/git-exercises.git git/exercises.git \ - && ln -s /var/www/website/backend/hook/hook.php /var/www/git/exercises.git/hooks/update -COPY git-config git/exercises.git/config +ARG GIT_REPO +ARG SITE_ADMIN_NAME +ARG SITE_ADMIN_EMAIL + +RUN chown www-data:www-data /var/www +USER www-data +WORKDIR /var/www +RUN mkdir website + +COPY --chown=www-data:www-data ./backend website/backend +COPY --chown=www-data:www-data --from=backend_build /var/www/vendor website/backend/vendor +COPY --chown=www-data:www-data --from=frontend_build /app/ website/frontend/ +RUN mkdir -p website/backend/hook/hints website/backend/hook/verifications git workingarea + +# Get the exercises +COPY --chown=www-data:www-data exercises/ /tmp/exercises/ +RUN [ -z "${GIT_REPO}" ] || (rm -rf /tmp/exercises && git clone ${GIT_REPO} /tmp/) +# Copy the hints and verifications into the backend +RUN mkdir /var/www/git/exercises.git + +# Create the exercise branches WORKDIR /var/www/git/exercises.git -RUN git checkout master && git branch -D verifications +COPY docker/init-exercises.sh . +RUN ./init-exercises.sh +RUN rm -rf /tmp/exercises init-exercises.sh -WORKDIR /var/www +RUN ln -s /var/www/website/backend/hook/hook.php .git/hooks/update +COPY ./docker/git-config .git/config + +RUN git checkout main -ARG WWW_DATA_UID=1001 -RUN usermod --uid "$WWW_DATA_UID" www-data \ - && groupmod --gid "$WWW_DATA_UID" www-data \ - && chown -hR www-data:www-data /var/www diff --git a/docker/apache-conf/000-default.conf b/docker/apache-conf/000-default.conf index e42b99f..521771c 100644 --- a/docker/apache-conf/000-default.conf +++ b/docker/apache-conf/000-default.conf @@ -1,11 +1,12 @@ - #ServerName gitexercises.fracz.com - ServerAdmin fraczwojciech@gmail.com + ServerName ${DOMAIN_NAME} + ServerAdmin xx@gmail.com DocumentRoot /var/www/website/frontend/public SetEnv GIT_PROJECT_ROOT /var/www/git SetEnv GIT_HTTP_EXPORT_ALL SetEnv REMOTE_USER=$REDIRECT_REMOTE_USER + PassEnv DB_HOST DB_NAME DB_USER DB_PASSWORD DOMAIN_NAME ScriptAlias /git/ /usr/lib/git-core/git-http-backend/ diff --git a/docker/docker-compose.dbnetwork.yml b/docker/docker-compose.dbnetwork.yml deleted file mode 100644 index a522818..0000000 --- a/docker/docker-compose.dbnetwork.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: '3' - -# Use this config file if you want to expose application's database in the Docker's external network called dbnetwork. -# It enables you to launch another container with a database management tool like PHPMyAdmin and connect to the -# database via the external network. -# docker-compose -f docker-compose.yml -f docker-compose.dbnetwork.yml up --build -d - -services: - gitexercises-db: - networks: [dbnetwork] - -networks: - dbnetwork: - external: true diff --git a/docker/docker-compose.letsencrypt.yml b/docker/docker-compose.letsencrypt.yml deleted file mode 100644 index cfb9054..0000000 --- a/docker/docker-compose.letsencrypt.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: '3' - -# configuration file to use with https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion -# In order to run: -# 1. docker network create webproxy -# 2. Start the proxy -# 3. Configure DOMAIN_NAME and ADMIN_EMAIL in .env -# 4. docker-compose -f docker-compose.yml -f docker-compose.letsencrypt.yml up --build -d - -services: - gitexercises: - networks: [proxy] - environment: - VIRTUAL_HOST: ${DOMAIN_NAME} - LETSENCRYPT_HOST: ${DOMAIN_NAME} - LETSENCRYPT_EMAIL: ${ADMIN_EMAIL} - expose: [80] - -networks: - proxy: - external: - name: webproxy diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 7f0a20f..ca72dd8 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -2,36 +2,40 @@ version: '3' services: gitexercises: - container_name: ${COMPOSE_PROJECT_NAME} restart: unless-stopped - networks: [default] - ports: - - "${PORT_HTTP}:80" + environment: + DB_HOST: gitexercises-db + DB_NAME: gitexercises + DB_USER: ${DB_USER:-gitexercises} + DB_PASSWORD: ${DB_PASSWORD:-gitexercises} + DOMAIN_NAME: ${DOMAIN_NAME:-gitexercises.com} build: - context: . + context: .. + dockerfile: docker/Dockerfile args: - WWW_DATA_UID: ${UID} - volumes: - - ../:/var/www/website:z - - ./apache-conf:/etc/apache2/sites-available:z + GIT_REPO: ${GIT_REPO:-} + DOMAIN_NAME: ${DOMAIN_NAME:-gitexercises.com} + SITE_ADMIN_NAME: ${SITE_ADMIN_NAME:-Gitexercises Admin} + SITE_ADMIN_EMAIL: ${SITE_ADMIN_EMAIL:-admin@gitexercises.com} depends_on: - gitexercises-db + ports: + - ${PORT_HTTP}:80 logging: options: max-size: 50m gitexercises-db: - container_name: ${COMPOSE_PROJECT_NAME}-db restart: unless-stopped image: mysql - networks: [default] environment: - MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD} + MYSQL_ALLOW_EMPTY_PASSWORD: 1 + MYSQL_USER: ${DB_USER:-gitexercises} + MYSQL_PASSWORD: ${DB_PASSWORD:-gitexercises} MYSQL_DATABASE: gitexercises - MYSQL_USER: gitexercises - MYSQL_PASSWORD: ${DATABASE_PASSWORD} volumes: - - ${VOLUME_DATA}/mysql:/var/lib/mysql:z + - /var/lib/mysql + - ../backend/schema/gitexercises.sql:/docker-entrypoint-initdb.d/gitexercises.sql logging: options: max-size: 50m diff --git a/docker/env.example b/docker/env.example new file mode 100644 index 0000000..932237b --- /dev/null +++ b/docker/env.example @@ -0,0 +1,19 @@ +# SOME FANCY NAME +COMPOSE_PROJECT_NAME=gitexercises + +# MYSQL CONFIG +# this refers to the docker hostname +DB_HOST=gitexercises-db +DB_NAME=gitexercises +DB_USER=gitexercises +# for safety consider setting a passwd, note that you mannually need to change the mysql root password accordingly +DB_PASSWORD=gitexercises + +# YOUR GIT EXERCISES REPO +# GIT_REPO=https://github.com/fracz/git-exercises + +# EXPOSE HTTP SERVICE ON PORT +PORT_HTTP=80 + +# DOMAIN ASSOCIATED TO ONLINE ENVIRONMENT +DOMAIN_NAME=localhost \ No newline at end of file diff --git a/docker/init-exercises.sh b/docker/init-exercises.sh new file mode 100755 index 0000000..78caaa0 --- /dev/null +++ b/docker/init-exercises.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +dashToCamelCase() { + echo $1|awk -F"-" '{for(i=1;i<=NF;i++){$i=toupper(substr($i,1,1)) substr($i,2)}} 1' OFS="" +} + +# Config the name of the original committer +git config --global init.defaultBranch main +git config --global user.email "$SITE_ADMIN_EMAIL" +git config --global user.name "$SITE_ADMIN_NAME" + +# Create the first commits +git init && \ +echo init-exercises.sh > .gitignore +git checkout -b exercise-base && \ +touch README.md && \ +git add .gitignore README.md && \ +git commit -m "Initial commit" && \ +echo '#!/usr/bin/env bash' > .start.sh && \ +echo '#!/usr/bin/env bash' > .verification.sh && \ +echo '#!/usr/bin/env bash' > .teardown.sh && \ +chmod +x .start.sh .verification.sh .teardown.sh && \ +git add .start.sh .verification.sh .teardown.sh && \ +git commit -m "Exercice base" + +# Create the branches +cp /tmp/exercises/exercise-order.txt /var/www/website/backend/hook/ +shopt -s dotglob +for exercise in $(cat /tmp/exercises/exercise-order.txt) +do + git checkout exercise-base + git checkout -b $exercise + cp -r /tmp/exercises/$exercise/files/* . + git add . + git commit -m "Exercice files" + + # Copy the hind, summary, solution and verification files into the backend + [ -f /tmp/exercises/$exercise/hint.md ] && cp /tmp/exercises/$exercise/hint.md /var/www/website/backend/hook/hints/$exercise-hint.md || true + [ -f /tmp/exercises/$exercise/summary.md ] && cp /tmp/exercises/$exercise/summary.md /var/www/website/backend/hook/hints/$exercise-summary.md || true + [ -f /tmp/exercises/$exercise/solution.txt ] && cp /tmp/exercises/$exercise/solution.txt /var/www/website/backend/hook/hints/$exercise-solution.txt || true + [ -f /tmp/exercises/$exercise/verification.php ] && cp /tmp/exercises/$exercise/verification.php /var/www/website/backend/hook/verifications/$( dashToCamelCase $exercise ).php || true +done diff --git a/exercises/add-new-changes/files/.start.sh b/exercises/add-new-changes/files/.start.sh new file mode 100755 index 0000000..f7c1d25 --- /dev/null +++ b/exercises/add-new-changes/files/.start.sh @@ -0,0 +1,3 @@ +sed -i -e 's/Hello world/Bonjour le monde/' helloworld.cpp +git add helloworld.cpp +sed -i -e 's/le monde/tout le monde!/' helloworld.cpp diff --git a/exercises/add-new-changes/files/README.md b/exercises/add-new-changes/files/README.md new file mode 100644 index 0000000..969f51e --- /dev/null +++ b/exercises/add-new-changes/files/README.md @@ -0,0 +1,8 @@ +#Add new changes +You have already placed a file in the staging area, but you decided to make changes to it later. + +Try 'git status' first and see how the 'helloworld.cpp' file is both in the staging aread and marked as *modified*. + +Commit the new changes with the commit message: + + Translation of the welcome message diff --git a/exercises/add-new-changes/files/helloworld.cpp b/exercises/add-new-changes/files/helloworld.cpp new file mode 100644 index 0000000..d323a9e --- /dev/null +++ b/exercises/add-new-changes/files/helloworld.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + cout << "Hello world!"; + return 0; +} diff --git a/exercises/add-new-changes/hint.md b/exercises/add-new-changes/hint.md new file mode 100644 index 0000000..9eb35b7 --- /dev/null +++ b/exercises/add-new-changes/hint.md @@ -0,0 +1 @@ +Try adding the file to the staging area once again diff --git a/exercises/add-new-changes/solution.txt b/exercises/add-new-changes/solution.txt new file mode 100644 index 0000000..722fb27 --- /dev/null +++ b/exercises/add-new-changes/solution.txt @@ -0,0 +1,2 @@ +git add helloworld.cpp +git commit -m "Translation of the welcome message" diff --git a/exercises/add-new-changes/verification.php b/exercises/add-new-changes/verification.php new file mode 100644 index 0000000..dfc2918 --- /dev/null +++ b/exercises/add-new-changes/verification.php @@ -0,0 +1,23 @@ +ensureCommitsCount(1); + $file = $this->ensureFilesCount($commit, 1); + $this->ensure($file == 'helloworld.cpp', 'The wrong file has been commited. Expected but received %s.', [ConsoleUtils::blue($file)]); + + $message = GitUtils::getCommitSubject($commit); + $this->ensure($message == "Translation of the welcome message", "Wrong message. Expected : «Translation of the welcome message», received : «%s»", [ConsoleUtils::blue($message)]); + + $contenu_attendu = ' cout << "Bonjour tout le monde!!";'; + $contents = $this->getFileContent($commit, "helloworld.cpp")[4]; + $this->ensure($contents == $contenu_attendu, "The file does not contain the latest changes\nExpected: %s\nReceived: %s", [$contenu_attendu, $contents]); + } +} diff --git a/exercises/add-one-file/files/.start.sh b/exercises/add-one-file/files/.start.sh new file mode 100755 index 0000000..859bfc6 --- /dev/null +++ b/exercises/add-one-file/files/.start.sh @@ -0,0 +1 @@ +echo First commit > new.txt diff --git a/exercises/add-one-file/files/.verification.sh b/exercises/add-one-file/files/.verification.sh new file mode 100755 index 0000000..032b966 --- /dev/null +++ b/exercises/add-one-file/files/.verification.sh @@ -0,0 +1,22 @@ +#!/bin/bash +err=0 + +if [ "$(git diff --cached --name-only)" == "" ] +then + echo "The file new.txt has not been staged" + err=1 +fi + +if [ $err -eq 0 -a "$(git diff --cached --name-only)" != "new.txt" ] +then + echo Only new.txt should be staged + err=2 +fi + +if [ $err -gt 0 ] +then + exit $err +else + git commit -m "Files added to the staging area" &>/dev/null +fi + diff --git a/exercises/add-one-file/files/README.md b/exercises/add-one-file/files/README.md new file mode 100644 index 0000000..8adb06b --- /dev/null +++ b/exercises/add-one-file/files/README.md @@ -0,0 +1,5 @@ +#Placer a file in the stage stage Before committing a change, git must be informed that it must be kept. This operation is called "staging". + +Imagine a group photo. Before taking the shot, we take the trouble to stage all the participants (and exclude tourists that we do not want to have in the photo). + +Add the "new.txt" file to the staging area and check the exercise with the command 'git verify' diff --git a/exercises/add-one-file/hint.md b/exercises/add-one-file/hint.md new file mode 100644 index 0000000..7225d55 --- /dev/null +++ b/exercises/add-one-file/hint.md @@ -0,0 +1 @@ +Use [`git add`](https://git-scm.com/docs/git-add) followed by the name of the file to be staged. diff --git a/exercises/add-one-file/solution.txt b/exercises/add-one-file/solution.txt new file mode 100644 index 0000000..1e9abdb --- /dev/null +++ b/exercises/add-one-file/solution.txt @@ -0,0 +1 @@ +git add new.txt diff --git a/exercises/add-one-file/verification.php b/exercises/add-one-file/verification.php new file mode 100644 index 0000000..9f90af0 --- /dev/null +++ b/exercises/add-one-file/verification.php @@ -0,0 +1,17 @@ +ensureCommitsCount(1); + $this->ensureFilesCount($commit, 1); + $filenames = $this->getFilenames($commit); + $this->ensure($filenames[0] == 'new.txt', 'The wrong file was commited. Expected "new.txt" bet received %s.', [ConsoleUtils::blue($filenames[0])]); + } +} diff --git a/exercises/add-some-files/files/.start.sh b/exercises/add-some-files/files/.start.sh new file mode 100755 index 0000000..6b54da4 --- /dev/null +++ b/exercises/add-some-files/files/.start.sh @@ -0,0 +1 @@ +touch A.txt B.txt C.txt D.txt E.txt diff --git a/exercises/add-some-files/files/.verification.sh b/exercises/add-some-files/files/.verification.sh new file mode 100755 index 0000000..7e9ad38 --- /dev/null +++ b/exercises/add-some-files/files/.verification.sh @@ -0,0 +1,28 @@ +#!/bin/bash +err=0 + +for fichier in A.txt B.txt C.txt +do + if ! git ls-files | grep -q $file + then + echo "The file $file has not been staged" + err=1 + fi +done + +for fichier in $(git ls-files *.txt) +do + if echo A.txt B.txt C.txt | grep -qv $file + then + echo "The file $file should not have been staged" + err=2 + fi +done + +if [ $err -gt 0 ] +then + exit $err +else + git commit -m "Files added to the staging area." &>/dev/null +fi + diff --git a/exercises/add-some-files/files/README.md b/exercises/add-some-files/files/README.md new file mode 100644 index 0000000..f3bae8b --- /dev/null +++ b/exercises/add-some-files/files/README.md @@ -0,0 +1,5 @@ +#Add some files +A commit frequently concerns more than a single file. + +Add to the staging area the files ~A.txt~, ~B.txt~ et ~C.txt~ (and only those). + diff --git a/exercises/add-some-files/hint.md b/exercises/add-some-files/hint.md new file mode 100644 index 0000000..d1dc565 --- /dev/null +++ b/exercises/add-some-files/hint.md @@ -0,0 +1 @@ +The command `git add` allows for multiple filenames (or, of course, can be used multiple successive times). diff --git a/exercises/add-some-files/solution.txt b/exercises/add-some-files/solution.txt new file mode 100644 index 0000000..e49a4d7 --- /dev/null +++ b/exercises/add-some-files/solution.txt @@ -0,0 +1 @@ +git add A.txt B.txt C.txt diff --git a/exercises/add-some-files/verification.php b/exercises/add-some-files/verification.php new file mode 100644 index 0000000..55f2941 --- /dev/null +++ b/exercises/add-some-files/verification.php @@ -0,0 +1,17 @@ +ensureCommitsCount(1); + $this->ensureFilesCount($commit, 3); + $filenames = $this->getFilenames($commit); + $this->ensure(!array_diff( $filenames, ['A.txt', 'B.txt', 'C.txt'] ), 'The wrong file was commited. Expected "A.txt, B.txt and C.txt" but received %s.', [ConsoleUtils::blue($filenames[0])]); + } +} diff --git a/exercises/case-sensitive-filename/files/.start.sh b/exercises/case-sensitive-filename/files/.start.sh new file mode 100755 index 0000000..ae5c278 --- /dev/null +++ b/exercises/case-sensitive-filename/files/.start.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +echo "Some content" > File.txt +git add File.txt +git commit -m "Uppercase File.txt" \ No newline at end of file diff --git a/exercises/case-sensitive-filename/files/README.md b/exercises/case-sensitive-filename/files/README.md new file mode 100644 index 0000000..38fd19d --- /dev/null +++ b/exercises/case-sensitive-filename/files/README.md @@ -0,0 +1,7 @@ +## Change a letter case in the filename of an already tracked file + +You have committed a `File.txt` but then you realized the filename should +be all lowercase: `file.txt`. Change the filename. + +This one is tricky on Windows, or in any filesystem that treats `File.txt` +and `file.txt` as the same files. diff --git a/backend/hook/hints/CaseSensitiveFilename-hint.md b/exercises/case-sensitive-filename/hint.md similarity index 100% rename from backend/hook/hints/CaseSensitiveFilename-hint.md rename to exercises/case-sensitive-filename/hint.md diff --git a/backend/hook/hints/CaseSensitiveFilename-solution.txt b/exercises/case-sensitive-filename/solution.txt similarity index 100% rename from backend/hook/hints/CaseSensitiveFilename-solution.txt rename to exercises/case-sensitive-filename/solution.txt diff --git a/backend/hook/verifications/CaseSensitiveFilename.php b/exercises/case-sensitive-filename/verification.php similarity index 100% rename from backend/hook/verifications/CaseSensitiveFilename.php rename to exercises/case-sensitive-filename/verification.php diff --git a/exercises/change-branch-history/files/.start.sh b/exercises/change-branch-history/files/.start.sh new file mode 100755 index 0000000..33c4737 --- /dev/null +++ b/exercises/change-branch-history/files/.start.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +git branch -D hot-bugfix +echo "This is content of file.txt" > file.txt +echo "This is a bug" > buggy.txt +git add file.txt +git add buggy.txt +git commit -m "Base of work" +echo "This is better content of file.txt" > file.txt +git commit -am "Work on an issue" +git branch hot-bugfix HEAD^ +git checkout hot-bugfix +echo "Bug removed" > buggy.txt +git commit -am "Bug fix" +git checkout change-branch-history diff --git a/exercises/change-branch-history/files/README.md b/exercises/change-branch-history/files/README.md new file mode 100644 index 0000000..622353f --- /dev/null +++ b/exercises/change-branch-history/files/README.md @@ -0,0 +1,28 @@ +# Change branch history +You were working on a regular issue while your boss came in and told you to fix recent bug in an application. Because your +work on the issue hasn't been done yet, you decided to go back where you started and do a bug fix there. + +Your repository look like this: + + HEAD + | + change-branch-history + | + A <----- B + \ + \----- C + | + hot-bugfix + +Now you realized that the bug is really annoying and you don't want to continue your work without the fix you have made. +You wish your repository looked like you started after fixing a bug. + + HEAD + | + change-branch-history + | + A <----- C <----- B + | + hot-bugfix + +Achieve that. diff --git a/backend/hook/hints/ChangeBranchHistory-hint.md b/exercises/change-branch-history/hint.md similarity index 100% rename from backend/hook/hints/ChangeBranchHistory-hint.md rename to exercises/change-branch-history/hint.md diff --git a/backend/hook/hints/ChangeBranchHistory-solution.txt b/exercises/change-branch-history/solution.txt similarity index 100% rename from backend/hook/hints/ChangeBranchHistory-solution.txt rename to exercises/change-branch-history/solution.txt diff --git a/backend/hook/hints/ChangeBranchHistory-summary.md b/exercises/change-branch-history/summary.md similarity index 100% rename from backend/hook/hints/ChangeBranchHistory-summary.md rename to exercises/change-branch-history/summary.md diff --git a/backend/hook/verifications/ChangeBranchHistory.php b/exercises/change-branch-history/verification.php similarity index 100% rename from backend/hook/verifications/ChangeBranchHistory.php rename to exercises/change-branch-history/verification.php diff --git a/exercises/chase-branch/files/.start.sh b/exercises/chase-branch/files/.start.sh new file mode 100755 index 0000000..51c6219 --- /dev/null +++ b/exercises/chase-branch/files/.start.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +git branch -D escaped +git checkout -b escaped +echo "Sample content" > file.txt +git add file.txt +git commit -m "First escaped commit" +echo "More content" >> file.txt +git commit -am "Second escaped commit" +git checkout chase-branch diff --git a/exercises/chase-branch/files/README.md b/exercises/chase-branch/files/README.md new file mode 100644 index 0000000..6575a3a --- /dev/null +++ b/exercises/chase-branch/files/README.md @@ -0,0 +1,19 @@ +# Chase branch that escaped +You are currently on `chase-branch` branch. There is also `escaped` branch that has two more commits. + + HEAD + | + chase-branch escaped + | | + A <----- B <----- C + + +You want to make `chase-branch` to point to the same commit as the `escaped` branch. + + escaped + | + A <----- B <----- C + | + chase-branch + | + HEAD diff --git a/backend/hook/hints/ChaseBranch-hint.md b/exercises/chase-branch/hint.md similarity index 100% rename from backend/hook/hints/ChaseBranch-hint.md rename to exercises/chase-branch/hint.md diff --git a/backend/hook/hints/ChaseBranch-solution.txt b/exercises/chase-branch/solution.txt similarity index 100% rename from backend/hook/hints/ChaseBranch-solution.txt rename to exercises/chase-branch/solution.txt diff --git a/backend/hook/hints/ChaseBranch-summary.md b/exercises/chase-branch/summary.md similarity index 100% rename from backend/hook/hints/ChaseBranch-summary.md rename to exercises/chase-branch/summary.md diff --git a/backend/hook/verifications/ChaseBranch.php b/exercises/chase-branch/verification.php similarity index 100% rename from backend/hook/verifications/ChaseBranch.php rename to exercises/chase-branch/verification.php diff --git a/exercises/commit-lost/files/.start.sh b/exercises/commit-lost/files/.start.sh new file mode 100755 index 0000000..6766dbd --- /dev/null +++ b/exercises/commit-lost/files/.start.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +echo "This is the good version of a file." > file.txt +git add file.txt +git commit -m "Very imporant piece of work" +echo "I have accidentally deleted my work!" > file.txt +git commit -a --amend -m "Accidental change" diff --git a/exercises/commit-lost/files/README.md b/exercises/commit-lost/files/README.md new file mode 100644 index 0000000..20c15da --- /dev/null +++ b/exercises/commit-lost/files/README.md @@ -0,0 +1,11 @@ +## Find a commit that has been lost + +You have created a commit with very important piece of work. You then wanted to fix something in the last commit +so you have amended it. However, you have just realized you have accidentally committed the wrong changes and you +desperately need the first version of the commit you have just amended. + +However, there is no previous version in the history - you have edited the last commit with `git commit --amend`. + +Your goal is to find the first version of the commit in the repository. It must be somewhere... + +Once found, force the `commit-lost` branch to point at it again and verify the solution. diff --git a/backend/hook/hints/CommitLost-hint.md b/exercises/commit-lost/hint.md similarity index 100% rename from backend/hook/hints/CommitLost-hint.md rename to exercises/commit-lost/hint.md diff --git a/backend/hook/hints/CommitLost-solution.txt b/exercises/commit-lost/solution.txt similarity index 100% rename from backend/hook/hints/CommitLost-solution.txt rename to exercises/commit-lost/solution.txt diff --git a/backend/hook/hints/CommitLost-summary.md b/exercises/commit-lost/summary.md similarity index 100% rename from backend/hook/hints/CommitLost-summary.md rename to exercises/commit-lost/summary.md diff --git a/backend/hook/verifications/CommitLost.php b/exercises/commit-lost/verification.php similarity index 100% rename from backend/hook/verifications/CommitLost.php rename to exercises/commit-lost/verification.php diff --git a/exercises/commit-multiple-files/files/.start.sh b/exercises/commit-multiple-files/files/.start.sh new file mode 100755 index 0000000..61c6b85 --- /dev/null +++ b/exercises/commit-multiple-files/files/.start.sh @@ -0,0 +1,8 @@ +echo 'print("Hello world!")' > hello.py +echo 'print( 21 * 2 )' > calc.py +echo 'print( 20 * 2 )' > calc.py~ +echo "To get the answer to life, the Universe and everything else: python calc.py" > RUN.txt +echo "Grocery list : milk, peanut butter, chocolate chips cookies" > notes +echo "1. Find the answer to life" > todo.md +echo "2. Find the answer to the Universe" >> todo.md +echo "3. Find the answer to everything else:" >> todo.md diff --git a/exercises/commit-multiple-files/files/README.md b/exercises/commit-multiple-files/files/README.md new file mode 100644 index 0000000..db1d6cd --- /dev/null +++ b/exercises/commit-multiple-files/files/README.md @@ -0,0 +1,6 @@ +#Placer a file in the staging area +Most of the time, we will have more than one file to stage. Care must be taken to put in the preparation area only files with modifications that you want to keep. + +There are some files in the current directory that have been modified. Have it displayed with 'git status'. Then, stage only the files of type 'py' and 'txt' and none of the others. When this is done, make these changes with the message: + + Added calculation programs and execution instructions. diff --git a/exercises/commit-multiple-files/hint.md b/exercises/commit-multiple-files/hint.md new file mode 100644 index 0000000..3c5bd4a --- /dev/null +++ b/exercises/commit-multiple-files/hint.md @@ -0,0 +1,3 @@ +Simply use the command [`git add`](https://git-scm.com/docs/git-add) followed with the names of files to be added to the staging area. + +You can also use repetitively the command with a single filename. diff --git a/exercises/commit-multiple-files/solution.txt b/exercises/commit-multiple-files/solution.txt new file mode 100644 index 0000000..3207476 --- /dev/null +++ b/exercises/commit-multiple-files/solution.txt @@ -0,0 +1 @@ +git add calc.py hello.py RUN.txt diff --git a/exercises/commit-multiple-files/verification.php b/exercises/commit-multiple-files/verification.php new file mode 100644 index 0000000..9ea9749 --- /dev/null +++ b/exercises/commit-multiple-files/verification.php @@ -0,0 +1,20 @@ +ensureCommitsCount(1); + $this->ensureFilesCount($commit, 3); + $filenames = $this->getFilenames($commit); + $this->ensure(!array_diff( $filenames, ['hello.py', 'calc.py', 'RUN.txt']), 'The wrong files have been commited. Expected "hello.py", "calc.py" and "RUN.txt" but received %s.', [ConsoleUtils::blue(json_encode($filenames))]); + $message = GitUtils::getCommitSubject($commit); + $this->ensure($message == "Added calculation programs and execution instructions.", "Wrong message. Attendu : «Added calculation programs and execution instructions.», received : «%s»", [ConsoleUtils::blue($message)]); + + } +} diff --git a/exercises/commit-one-file-staged/files/.start.sh b/exercises/commit-one-file-staged/files/.start.sh new file mode 100755 index 0000000..366e900 --- /dev/null +++ b/exercises/commit-one-file-staged/files/.start.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +echo 'A' > 'A.txt' +echo 'B' > 'B.txt' +git add A.txt +git add B.txt diff --git a/exercises/commit-one-file-staged/files/README.md b/exercises/commit-one-file-staged/files/README.md new file mode 100644 index 0000000..63aca8e --- /dev/null +++ b/exercises/commit-one-file-staged/files/README.md @@ -0,0 +1,5 @@ +## Commit one file of two currently staged +There are two files created in the root project directory - `A.txt` and `B.txt`. They are both added to the staging +area. + +The goal is to commit only one of them. diff --git a/exercises/commit-one-file-staged/hint.md b/exercises/commit-one-file-staged/hint.md new file mode 100644 index 0000000..19eb658 --- /dev/null +++ b/exercises/commit-one-file-staged/hint.md @@ -0,0 +1,5 @@ +If you use `git status`, git will tell you the way to remove a file from the staging area (unstage). + +In order to remove files from staging area you should use the [`git restore`](https://git-scm.com/docs/git-restore) command. + +Files that are not in the staging area will not be taken into the next commit. diff --git a/backend/hook/hints/CommitOneFileStaged-solution.txt b/exercises/commit-one-file-staged/solution.txt similarity index 100% rename from backend/hook/hints/CommitOneFileStaged-solution.txt rename to exercises/commit-one-file-staged/solution.txt diff --git a/backend/hook/hints/CommitOneFileStaged-summary.md b/exercises/commit-one-file-staged/summary.md similarity index 100% rename from backend/hook/hints/CommitOneFileStaged-summary.md rename to exercises/commit-one-file-staged/summary.md diff --git a/backend/hook/verifications/CommitOneFileStaged.php b/exercises/commit-one-file-staged/verification.php similarity index 100% rename from backend/hook/verifications/CommitOneFileStaged.php rename to exercises/commit-one-file-staged/verification.php diff --git a/exercises/commit-one-file/files/.start.sh b/exercises/commit-one-file/files/.start.sh new file mode 100755 index 0000000..f374d71 --- /dev/null +++ b/exercises/commit-one-file/files/.start.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +echo 'A' > 'A.txt' +echo 'B' > 'B.txt' diff --git a/exercises/commit-one-file/files/README.md b/exercises/commit-one-file/files/README.md new file mode 100644 index 0000000..40faae4 --- /dev/null +++ b/exercises/commit-one-file/files/README.md @@ -0,0 +1,6 @@ +## Commit one file +There are two files created in the root project directory - `A.txt` and `B.txt`. + +The goal is to commit only one of them. + +NOTE: Remember that you can submit your solutions with `git verify` command instead of `git push`. diff --git a/backend/hook/hints/CommitOneFile-hint.md b/exercises/commit-one-file/hint.md similarity index 100% rename from backend/hook/hints/CommitOneFile-hint.md rename to exercises/commit-one-file/hint.md diff --git a/exercises/commit-one-file/solution.txt b/exercises/commit-one-file/solution.txt new file mode 100644 index 0000000..9a97f15 --- /dev/null +++ b/exercises/commit-one-file/solution.txt @@ -0,0 +1,2 @@ +git add B.txt +git commit -m "Commit B.txt file" diff --git a/backend/hook/hints/CommitOneFile-summary.md b/exercises/commit-one-file/summary.md similarity index 100% rename from backend/hook/hints/CommitOneFile-summary.md rename to exercises/commit-one-file/summary.md diff --git a/exercises/commit-one-file/verification.php b/exercises/commit-one-file/verification.php new file mode 100644 index 0000000..98ae7f8 --- /dev/null +++ b/exercises/commit-one-file/verification.php @@ -0,0 +1,18 @@ +ensureCommitsCount(1); + $file = $this->ensureFilesCount($commit, 1); + $this->ensure($file == 'B.txt', 'The wrong file has been commited. Expected B.txt bet received %s.', [ConsoleUtils::blue($file)]); + $message = GitUtils::getCommitSubject($commit); + $this->ensure($message == "Commit B.txt file", "Wrong message. Expected : «Commit B.txt file», received : «%s»", [ConsoleUtils::blue($message)]); + } +} diff --git a/exercises/commit-only-tracked-files/files/.start.sh b/exercises/commit-only-tracked-files/files/.start.sh new file mode 100755 index 0000000..70d22b9 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/.start.sh @@ -0,0 +1,511 @@ +b#!/bin/bash +export LC_ALL=fr_CA.UTF-8 +base64 -d > files.zip </dev/null +rm files.zip diff --git a/exercises/commit-only-tracked-files/files/10gag/build.gradle b/exercises/commit-only-tracked-files/files/10gag/build.gradle new file mode 100644 index 0000000..d73da52 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/build.gradle @@ -0,0 +1,40 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * User Manual available at https://docs.gradle.org/6.6/userguide/tutorial_java_projects.html + */ + +plugins { + // Apply the java plugin to add support for Java + id 'java' + + // Apply the application plugin to add support for building a CLI application. + id 'application' + id 'org.jetbrains.kotlin.jvm' version '1.7.10' +} + +repositories { + // Use jcenter for resolving dependencies. + // You can declare any Maven/Ivy/file repository here. + jcenter() +} + +dependencies { + // This dependency is used by the application. + implementation 'com.google.guava:guava:29.0-jre' + + // Use JUnit test framework + testImplementation 'junit:junit:4.13' + implementation "org.jetbrains.kotlin:kotlin-stdlib" +} + +application { + // Define the main class for the application. + mainClassName = 'dixgag.DixGag' +} + +run { + standardInput = System.in +} diff --git "a/exercises/commit-only-tracked-files/files/10gag/gags/B\303\251b\303\25101.gag" "b/exercises/commit-only-tracked-files/files/10gag/gags/B\303\251b\303\25101.gag" new file mode 100644 index 0000000..9888fc5 --- /dev/null +++ "b/exercises/commit-only-tracked-files/files/10gag/gags/B\303\251b\303\25101.gag" @@ -0,0 +1,3 @@ +Qu'est-ce qui est pire que lancer un bébé en bas d'un hélicoptère ? + +Le lancer en haut. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/Cercle_vicieux.gag b/exercises/commit-only-tracked-files/files/10gag/gags/Cercle_vicieux.gag new file mode 100644 index 0000000..0b9b08a --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/Cercle_vicieux.gag @@ -0,0 +1 @@ +Un muet dit à un sourd qu'un aveugle à vu sa femme le tromper. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/Gag3_1 b/exercises/commit-only-tracked-files/files/10gag/gags/Gag3_1 new file mode 100644 index 0000000..f851684 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/Gag3_1 @@ -0,0 +1,3 @@ +Comment reconnait-on une lettre envoyee par un lepreux ? + +La langue est collee au timbre diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/Harry.gag b/exercises/commit-only-tracked-files/files/10gag/gags/Harry.gag new file mode 100644 index 0000000..44dd2b3 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/Harry.gag @@ -0,0 +1,3 @@ +Pourquoi est ce que Potter est triste? + +Parce que personne Harry à sa blague diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/Le_pitbull.gag b/exercises/commit-only-tracked-files/files/10gag/gags/Le_pitbull.gag new file mode 100644 index 0000000..42798f4 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/Le_pitbull.gag @@ -0,0 +1,2 @@ +Que faire si un pitbull se branle sur votre jambe? +Simulez l'orgasme... \ No newline at end of file diff --git "a/exercises/commit-only-tracked-files/files/10gag/gags/Pur\303\251.gag" "b/exercises/commit-only-tracked-files/files/10gag/gags/Pur\303\251.gag" new file mode 100644 index 0000000..cb602ee --- /dev/null +++ "b/exercises/commit-only-tracked-files/files/10gag/gags/Pur\303\251.gag" @@ -0,0 +1 @@ +C'est une patate qui traverse la rue et qui se fait écraser. Une autre patate arrive et dis "Oh purée" ! \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/Trans.gag b/exercises/commit-only-tracked-files/files/10gag/gags/Trans.gag new file mode 100644 index 0000000..fec854d --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/Trans.gag @@ -0,0 +1,3 @@ +Comment appelle t-on le père et la mère de l’homme invisible ? + +Ses transparents. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/Windows.gag b/exercises/commit-only-tracked-files/files/10gag/gags/Windows.gag new file mode 100644 index 0000000..078c4c6 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/Windows.gag @@ -0,0 +1,3 @@ +Quand est ce que Windows ne bug pas ? + +Quand l'ordinateur est éteint. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/alligator.gag b/exercises/commit-only-tracked-files/files/10gag/gags/alligator.gag new file mode 100644 index 0000000..027de66 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/alligator.gag @@ -0,0 +1,3 @@ +Comment appelle-t-on un alligator qui enquête? + +Un investi-gator. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/ampoule.gag b/exercises/commit-only-tracked-files/files/10gag/gags/ampoule.gag new file mode 100644 index 0000000..4315198 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/ampoule.gag @@ -0,0 +1,3 @@ +Combien de psychologues sont nécessaires pour changer une ampoule? + +Une seule, mais il faut que l'ampoule veuille changer. diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/arbres.gag b/exercises/commit-only-tracked-files/files/10gag/gags/arbres.gag new file mode 100644 index 0000000..153e0d7 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/arbres.gag @@ -0,0 +1,3 @@ +Arbre #1 : t'avais pas un rendez-vous ce soir ? + +arbre #2 : oui... mais on m'a laissé planté diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/blagueDeMer.txt b/exercises/commit-only-tracked-files/files/10gag/gags/blagueDeMer.txt new file mode 100644 index 0000000..f67d968 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/blagueDeMer.txt @@ -0,0 +1 @@ +Quel est le crustacé le plus léger de la mer ? La palourde \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/blague_du_jour b/exercises/commit-only-tracked-files/files/10gag/gags/blague_du_jour new file mode 100644 index 0000000..c04dde5 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/blague_du_jour @@ -0,0 +1,3 @@ +Pour quoi la poule a traversé la rue? + +Pour aller de l'autre côté, évidemment. diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/blague_native3.txt b/exercises/commit-only-tracked-files/files/10gag/gags/blague_native3.txt new file mode 100644 index 0000000..91eaae7 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/blague_native3.txt @@ -0,0 +1,2 @@ +Pourquoi tant de poissons vivent-ils dans l’eau salée? +Parce que l’eau poivrée les ferait éternuer! \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/chasseur.gag b/exercises/commit-only-tracked-files/files/10gag/gags/chasseur.gag new file mode 100644 index 0000000..2bcdf0b --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/chasseur.gag @@ -0,0 +1,2 @@ +Pourquoi un chasseur prend son fusil aux toilettes +Pour tirer la chasse d’eau… \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/dinos01.gag b/exercises/commit-only-tracked-files/files/10gag/gags/dinos01.gag new file mode 100644 index 0000000..3cd00ee --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/dinos01.gag @@ -0,0 +1,3 @@ +Que faisaient les dinosaures quand ils n'arrivaient pas à se décider? + +Des tirageosaures diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/espagnols.gag b/exercises/commit-only-tracked-files/files/10gag/gags/espagnols.gag new file mode 100644 index 0000000..2ac334e --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/espagnols.gag @@ -0,0 +1,3 @@ +Quel est le bar prefere des espagnols ? + +Le Bar-celone diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/gerard.gag b/exercises/commit-only-tracked-files/files/10gag/gags/gerard.gag new file mode 100644 index 0000000..388f992 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/gerard.gag @@ -0,0 +1,3 @@ +Un électricien vient de mourrir. + +Il faut mettre sa famille au courrant. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/hippopotame.gag b/exercises/commit-only-tracked-files/files/10gag/gags/hippopotame.gag new file mode 100644 index 0000000..d27a3b1 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/hippopotame.gag @@ -0,0 +1,3 @@ +Pourquoi un hippopotame ne peut pas conduire? + +Parce qu'hippopotamener où tu veux. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/jaune.gag b/exercises/commit-only-tracked-files/files/10gag/gags/jaune.gag new file mode 100644 index 0000000..1dc63e6 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/jaune.gag @@ -0,0 +1,2 @@ +Qu'est-ce qui est jaune et qui attend? +Johnattan \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/linux.gag b/exercises/commit-only-tracked-files/files/10gag/gags/linux.gag new file mode 100644 index 0000000..531b286 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/linux.gag @@ -0,0 +1,3 @@ +C'est la fête à Linux, comment fait-on son gâteau? + +On le compile. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/magicien.gag b/exercises/commit-only-tracked-files/files/10gag/gags/magicien.gag new file mode 100644 index 0000000..411848b --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/magicien.gag @@ -0,0 +1,3 @@ +Comment on appelle un magicien mort? + +Un abracadavre. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/medecin.gag b/exercises/commit-only-tracked-files/files/10gag/gags/medecin.gag new file mode 100644 index 0000000..cb0f247 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/medecin.gag @@ -0,0 +1,3 @@ +Un malade chez le médecin +le médecin : Il vous reste deux semaines à vivre +Le malade : je vais prendre les deux dernières de Juillet \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/mexicain.gag b/exercises/commit-only-tracked-files/files/10gag/gags/mexicain.gag new file mode 100644 index 0000000..b4678fc --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/mexicain.gag @@ -0,0 +1,2 @@ +Comment appelle-t-on un Mexicain qui s'est fait voler sa voiture ? +Carlos. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/mouton.gag b/exercises/commit-only-tracked-files/files/10gag/gags/mouton.gag new file mode 100644 index 0000000..f50f60b --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/mouton.gag @@ -0,0 +1,3 @@ +Pourquoi les moutons se brossent les dents ? + +Pour avoir la laine fraiche ! \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/nain.gag b/exercises/commit-only-tracked-files/files/10gag/gags/nain.gag new file mode 100644 index 0000000..a1d45f7 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/nain.gag @@ -0,0 +1,3 @@ +Comment appelle-t-on un nain sans bras? + +On ne l'appelle pas! \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/noix.gag b/exercises/commit-only-tracked-files/files/10gag/gags/noix.gag new file mode 100644 index 0000000..346bfe3 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/noix.gag @@ -0,0 +1,3 @@ +Que dit une noisette quand elle tombe dans l’eau ? + +Je me noix. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/oeil.gag b/exercises/commit-only-tracked-files/files/10gag/gags/oeil.gag new file mode 100644 index 0000000..2a16bc7 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/oeil.gag @@ -0,0 +1,2 @@ +L’œil gauche dit à l’œil droit: +On sent quelque chose entre vous et moi. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/oeufs.gag b/exercises/commit-only-tracked-files/files/10gag/gags/oeufs.gag new file mode 100644 index 0000000..7765b3e --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/oeufs.gag @@ -0,0 +1,3 @@ +Deux œufs discutent : +– pourquoi t’es tout vert et aussi poilu ? +– parce que j’suis un kiwi connard » \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/paslui.gag b/exercises/commit-only-tracked-files/files/10gag/gags/paslui.gag new file mode 100644 index 0000000..bf1af7e --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/paslui.gag @@ -0,0 +1,3 @@ +C'est un mec qui entre dans un bar et qui dit "Salut c'est moi !" + +Mais en fait c’était pas lui. diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/patate.gag b/exercises/commit-only-tracked-files/files/10gag/gags/patate.gag new file mode 100644 index 0000000..0b72de9 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/patate.gag @@ -0,0 +1,3 @@ +Ou sont les comptables après leurs morts? + +Au paradis fiscale! (Désole) diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/porc.gag b/exercises/commit-only-tracked-files/files/10gag/gags/porc.gag new file mode 100644 index 0000000..0276407 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/porc.gag @@ -0,0 +1,3 @@ +Quel est l'animal le plus connecté ? + +Le porc USB diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/sommeil.gag b/exercises/commit-only-tracked-files/files/10gag/gags/sommeil.gag new file mode 100644 index 0000000..ff7634b --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/sommeil.gag @@ -0,0 +1 @@ +Qu'est-ce que dit un mathématicien qui est fatigué? Je vais aller un somme. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/thons.gag b/exercises/commit-only-tracked-files/files/10gag/gags/thons.gag new file mode 100644 index 0000000..d56bf91 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/thons.gag @@ -0,0 +1,3 @@ +Que se passe-t-il quand 2 poissons s'énervent ? + +Le thon monte diff --git "a/exercises/commit-only-tracked-files/files/10gag/gags/th\303\251.gag.txt" "b/exercises/commit-only-tracked-files/files/10gag/gags/th\303\251.gag.txt" new file mode 100644 index 0000000..52e2e38 --- /dev/null +++ "b/exercises/commit-only-tracked-files/files/10gag/gags/th\303\251.gag.txt" @@ -0,0 +1,2 @@ +Tu es vraiment comme une théière. +Puisque tu es rempli de bonté. \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/tommy.gag b/exercises/commit-only-tracked-files/files/10gag/gags/tommy.gag new file mode 100644 index 0000000..c731ee1 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/tommy.gag @@ -0,0 +1,14 @@ +tommy n'a pas de bras. +toc toc toc +qui est là? + + + + + + + + + + +Pas tommy diff --git a/exercises/commit-only-tracked-files/files/10gag/gags/toto.txt b/exercises/commit-only-tracked-files/files/10gag/gags/toto.txt new file mode 100644 index 0000000..ef3fea3 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gags/toto.txt @@ -0,0 +1,3 @@ +– Toto si je te donne 50 gâteaux et tu en manges 48 tu as donc ? + +– Mal au ventre . \ No newline at end of file diff --git a/exercises/commit-only-tracked-files/files/10gag/gradle.properties b/exercises/commit-only-tracked-files/files/10gag/gradle.properties new file mode 100644 index 0000000..336465c --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gradle.properties @@ -0,0 +1 @@ +org.gradle.console=plain diff --git a/exercises/commit-only-tracked-files/files/10gag/gradlew b/exercises/commit-only-tracked-files/files/10gag/gradlew new file mode 100755 index 0000000..4f906e0 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/exercises/commit-only-tracked-files/files/10gag/gradlew.bat b/exercises/commit-only-tracked-files/files/10gag/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/exercises/commit-only-tracked-files/files/10gag/settings.gradle b/exercises/commit-only-tracked-files/files/10gag/settings.gradle new file mode 100644 index 0000000..b835cad --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/settings.gradle @@ -0,0 +1,10 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/6.6/userguide/multi_project_builds.html + */ + +rootProject.name = 'DIXGAG' diff --git a/exercises/commit-only-tracked-files/files/10gag/src/main/kotlin/dixgag/DixGag.java b/exercises/commit-only-tracked-files/files/10gag/src/main/kotlin/dixgag/DixGag.java new file mode 100644 index 0000000..c59a8fb --- /dev/null +++ b/exercises/commit-only-tracked-files/files/10gag/src/main/kotlin/dixgag/DixGag.java @@ -0,0 +1,51 @@ +package dixgag; + +import java.io.*; +import java.nio.file.Files; +import java.util.Collections; +import java.util.List; +import java.util.Arrays; + +public class DixGag { + + public static void main(String[] args) { + + File répertoireGags = new File("./gags"); + + List gags = null; + try { + gags = Arrays.asList(répertoireGags.listFiles()); + } catch (SecurityException e) { + System.out.println("Erreur "+e.getMessage()); + e.printStackTrace(); + } + + if (gags == null || gags.size() == 0) { + System.out.println("Aucun gag trouvé"); + } else { + int compteur = 0; + Collections.shuffle(gags); + + for (File gag : gags) { + String texte = ""; + + try { + texte = new String(Files.readAllBytes(gag.toPath())); + } catch (IOException e) { + System.out.println("Erreur de lecture "+e.getMessage()); + e.printStackTrace(); + } + + compteur++; + System.out.println("Gag "+compteur+" : "+texte); + + try { + System.in.read(); + } catch (IOException e) { + System.out.println("Erreur impossible... félicitations!"); + e.printStackTrace(); + } + } + } + } +} diff --git a/exercises/commit-only-tracked-files/files/README.md b/exercises/commit-only-tracked-files/files/README.md new file mode 100644 index 0000000..24bc370 --- /dev/null +++ b/exercises/commit-only-tracked-files/files/README.md @@ -0,0 +1,5 @@ +# Only commit tracked files + +Frequently, temporary files are created in the work tree: compilation results, automatic backups, logs, etc. Normally, we do not want to commit files that can be recreated from the source code (or those that are unimportant). + +Commit all files that have already been tracked and have been modified without adding any untracked files. diff --git a/exercises/commit-only-tracked-files/hint.md b/exercises/commit-only-tracked-files/hint.md new file mode 100644 index 0000000..6c4b395 --- /dev/null +++ b/exercises/commit-only-tracked-files/hint.md @@ -0,0 +1 @@ +See the manual for [`git add`](https://git-scm.com/docs/git-add), specialy the `--update` option. diff --git a/exercises/commit-only-tracked-files/solution.txt b/exercises/commit-only-tracked-files/solution.txt new file mode 100644 index 0000000..f98f452 --- /dev/null +++ b/exercises/commit-only-tracked-files/solution.txt @@ -0,0 +1,2 @@ +git add -u . +git commit -m "only tracked files" diff --git a/exercises/commit-only-tracked-files/summary.md b/exercises/commit-only-tracked-files/summary.md new file mode 100644 index 0000000..71e2f9c --- /dev/null +++ b/exercises/commit-only-tracked-files/summary.md @@ -0,0 +1,9 @@ +The '-u' option or in its long form '--update' limits the addition of files to the staging area to those that are already tracked by git. + +It is best to avoid blindly adding all files modified with 'git add *' or 'git add .'. You risk polluting your repository with unnecessary files, which makes tracking changes more painful. A good practice is to: + +1. Add the changes to the preparation area with 'git add' +2. Validate that all changes are wanted and understood with 'git status' and 'git diff' +3. Commit with a clear message about what the changes bring + +You can also create a .gitignore file for files you never want to commit... That's the topic of the next exercise! diff --git a/exercises/commit-only-tracked-files/verification.php b/exercises/commit-only-tracked-files/verification.php new file mode 100644 index 0000000..db71292 --- /dev/null +++ b/exercises/commit-only-tracked-files/verification.php @@ -0,0 +1,15 @@ +ensureCommitsCount(1); + $this->ensureFilesCount($commit, 15); + } +} diff --git a/exercises/commit-parts/files/.start.sh b/exercises/commit-parts/files/.start.sh new file mode 100755 index 0000000..2156b86 --- /dev/null +++ b/exercises/commit-parts/files/.start.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +echo "This is a program" > file.txt +echo "It is supposed to work." >> file.txt +echo "It works" >> file.txt +echo "It is quite brilliant, actually." >> file.txt +git add file.txt +git commit -m "Base version of a program" +echo "I forgot to add file header." > file.txt +echo "This is a program" >> file.txt +echo "And this is new feature done in task 1." >> file.txt +echo "It lasts for many lines as task 1 was big." >> file.txt +echo "It is supposed to work." >> file.txt +echo "It works!" >> file.txt +echo "This is not related, it is task 2." >> file.txt +echo "It is quite brilliant, actually." >> file.txt +echo "Task 1 is finished." >> file.txt diff --git a/exercises/commit-parts/files/README.md b/exercises/commit-parts/files/README.md new file mode 100644 index 0000000..7cea278 --- /dev/null +++ b/exercises/commit-parts/files/README.md @@ -0,0 +1,8 @@ +## Commit part of work + +You are working on an issue for a long time and you noticed you have done too much. You want your work to be committed +in two separate commits instead of one. + +Unfortunately, your changes involve only one file so it is impossible to `git add` different files separately. + +Commit all new lines that contains "Task 1" phrase in the first commit and the rest of them in the second. diff --git a/backend/hook/hints/CommitParts-hint.md b/exercises/commit-parts/hint.md similarity index 100% rename from backend/hook/hints/CommitParts-hint.md rename to exercises/commit-parts/hint.md diff --git a/backend/hook/hints/CommitParts-solution.txt b/exercises/commit-parts/solution.txt similarity index 100% rename from backend/hook/hints/CommitParts-solution.txt rename to exercises/commit-parts/solution.txt diff --git a/backend/hook/hints/CommitParts-summary.md b/exercises/commit-parts/summary.md similarity index 100% rename from backend/hook/hints/CommitParts-summary.md rename to exercises/commit-parts/summary.md diff --git a/backend/hook/verifications/CommitParts.php b/exercises/commit-parts/verification.php similarity index 100% rename from backend/hook/verifications/CommitParts.php rename to exercises/commit-parts/verification.php diff --git a/exercises/config-user/files/.start.sh b/exercises/config-user/files/.start.sh new file mode 100755 index 0000000..2e739bc --- /dev/null +++ b/exercises/config-user/files/.start.sh @@ -0,0 +1,14 @@ +name=$(git config --get user.name) +email=$(git config --get user.email) + +git config user.prevname "$name" +git config user.prevemail "$email" + +git config user.name "Your Name" +git config user.email "you@example.com" + +sed -i "s/ORIGINAL_NAME/$name/" README.md +sed -i "s/ORIGINAL_EMAIL/$email/" README.md + +git add README.md + diff --git a/exercises/config-user/files/.teardown.sh b/exercises/config-user/files/.teardown.sh new file mode 100755 index 0000000..a720f4b --- /dev/null +++ b/exercises/config-user/files/.teardown.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +name=$(git config --get user.prevname) +email=$(git config --get user.prevemail) + +git config user.name "$name" +git config user.email "$email" + +git config --unset user.prevname +git config --unset user.prevemail + +exit 0 diff --git a/exercises/config-user/files/.verification.sh b/exercises/config-user/files/.verification.sh new file mode 100755 index 0000000..e4295ac --- /dev/null +++ b/exercises/config-user/files/.verification.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +err=0 +name=$(git config --get --local user.name) +prevname=$(git config --get --local user.prevname) +if [ "$name" == "" ] +then + echo "The name was not configured" + err=1 +fi + +if [ "$name" != "$prevname" ] +then + echo "The name should be $prevname" + err=1 +fi + +email=$(git config --get --local user.email) +prevemail=$(git config --get --local user.prevemail) +if [ "$email" == "" ] +then + echo "Pas de courriel configuré" + err=1 +fi +if [ "$email" != "$prevemail" ] +then + echo "Email should be $prevemail" + err=1 +fi + +if [ $err -gt 0 ] +then + exit $err +else + git commit -m "Commit with configured name and email." +fi + diff --git a/exercises/config-user/files/README.md b/exercises/config-user/files/README.md new file mode 100644 index 0000000..27a5812 --- /dev/null +++ b/exercises/config-user/files/README.md @@ -0,0 +1,6 @@ +#Configuration of Git +Before making a first commit, we must first fill in our credentials; mainly the name and email that will appear in the commit metadata. + +Type 'git log' for examples. See the 'Author' field? It is thanks to this information that we will be able to know the author of a commit and possibly write to him. + +For this exercise, your name and email have been reset to a default value. Reconfigure it as you entered it the first time (ORIGINAL_NAME). Then check the exercise with 'git verify'. When successful, check that your name appears correctly with 'git log'. diff --git a/exercises/config-user/hint.md b/exercises/config-user/hint.md new file mode 100644 index 0000000..9b9b1a0 --- /dev/null +++ b/exercises/config-user/hint.md @@ -0,0 +1 @@ +Use [`git config`](https://git-scm.com/docs/git-config) to configure variables `user.name` and `user.email`. diff --git a/exercises/config-user/solution.txt b/exercises/config-user/solution.txt new file mode 100644 index 0000000..2e71d00 --- /dev/null +++ b/exercises/config-user/solution.txt @@ -0,0 +1,2 @@ +git config user.name "bob" +git config user.email "bob@test.com" diff --git a/exercises/config-user/summary.md b/exercises/config-user/summary.md new file mode 100644 index 0000000..2f8aa0c --- /dev/null +++ b/exercises/config-user/summary.md @@ -0,0 +1,5 @@ +The 'git config' command is used to configure the variables used by Git. You can also view (and edit) them directly in the.git/config file of any project. + +To configure a variable in the same way for all your projects, use 'git config --global'. These variables are then stored in '~/.gitconfig'. It's a good idea to globally configure 'user.name' and 'user.email'. + +Now may be a good time to set up your default text editor. Git will frequently open a text editor for you. Choose the one you prefer to use by configuring the 'core.editor' variable diff --git a/exercises/config-user/verification.php b/exercises/config-user/verification.php new file mode 100644 index 0000000..51a34ac --- /dev/null +++ b/exercises/config-user/verification.php @@ -0,0 +1,23 @@ +ensureCommitsCount(1); + $file = $this->ensureFilesCount($commit, 1); + $name = GitUtils::getCommitterName($commit); + $email = GitUtils::getCommitterEmail($commit); + + $this->ensure( $email != "you@example.com" && $name != "Your Name", "Name and email are not configured properly" ); + $id = (new CommitterService())->getCommitterId($email); + $previousName = (new CommitterService())->getMostRecentName($id); + $this->ensure( $name == $previousName, "The name does not correspond to the one from previous exercises ($name != $previousName)." ); + } +} diff --git a/backend/hook/verifications/Escaped.php b/exercises/escaped/verification.php similarity index 100% rename from backend/hook/verifications/Escaped.php rename to exercises/escaped/verification.php diff --git a/exercises/executable/files/.start.sh b/exercises/executable/files/.start.sh new file mode 100755 index 0000000..3e73607 --- /dev/null +++ b/exercises/executable/files/.start.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +echo "#!/usr/bin/env bash" > script.sh +echo "echo \"Git exercises\"" >> script.sh +git add script.sh +git commit -m "Create script.sh" \ No newline at end of file diff --git a/exercises/executable/files/README.md b/exercises/executable/files/README.md new file mode 100644 index 0000000..7822090 --- /dev/null +++ b/exercises/executable/files/README.md @@ -0,0 +1,7 @@ +## Make the file executable by default + +You have created a simple bash script in `script.sh`. However, when you check it out +on Unix, it does not have required execute permissions so you can't launch it with +`./script.sh` without performing `chmod +x script.sh` beforehand. + +Fix it by adding an executable bit for `script.sh` in Git history. \ No newline at end of file diff --git a/exercises/executable/hint.md b/exercises/executable/hint.md new file mode 100644 index 0000000..71126e6 --- /dev/null +++ b/exercises/executable/hint.md @@ -0,0 +1 @@ +You should use the git update-index command with appropriate --chmod flag. diff --git a/backend/hook/hints/Executable-solution.txt b/exercises/executable/solution.txt similarity index 100% rename from backend/hook/hints/Executable-solution.txt rename to exercises/executable/solution.txt diff --git a/backend/hook/verifications/Executable.php b/exercises/executable/verification.php similarity index 100% rename from backend/hook/verifications/Executable.php rename to exercises/executable/verification.php diff --git a/backend/hook/exercise-order.txt b/exercises/exercise-order.txt similarity index 64% rename from backend/hook/exercise-order.txt rename to exercises/exercise-order.txt index fda2106..1326855 100644 --- a/backend/hook/exercise-order.txt +++ b/exercises/exercise-order.txt @@ -1,9 +1,19 @@ -master +main +config-user +add-one-file +add-some-files commit-one-file +commit-multiple-files commit-one-file-staged +add-new-changes +commit-only-tracked-files +new-branch ignore-them chase-branch merge-conflict +more-conflicts +modify-delete-conflict +too-many-conflicts save-your-work change-branch-history remove-ignored diff --git a/exercises/find-bug/files/.start.sh b/exercises/find-bug/files/.start.sh new file mode 100755 index 0000000..c38414d --- /dev/null +++ b/exercises/find-bug/files/.start.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +strings=(bWFpbGJveA== d2VzdHNpZGUgbWFpbGJveA== YmVoYXZlcnMgbWFpbGJveCB3ZXN0c2lkZQ== d2VzdHNpZGUgbWFpbGJveCBiZWhhdmVycyBtYWlsYm94 bWFpbGJveCB3b29sLWNhcmRpbmcgd2VzdHNpZGUgbWFpbGJveCBiZWhhdmVycw== YmVoYXZlcnMgZmxpbmdlciBtYWlsYm94IG1haWxib3ggd2VzdHNpZGUgd29vbC1jYXJkaW5n bWFpbGJveCBmbGluZ2VyIG1haWxib3ggd29vbC1jYXJkaW5nIHdlc3RzaWRl ZmxpbmdlciBtYWlsYm94IGNyaXNpcyB3b29sLWNhcmRpbmcgd2VzdHNpZGUgbWFpbGJveA== bWFpbGJveCB3ZXN0c2lkZSBjcmlzaXMgbWFpbGJveCB3b29sLWNhcmRpbmc= d29vbC1jYXJkaW5nIHdlc3RzaWRlIGNyaXNpcyBtYWlsYm94 ZmxpbmdlciBtYWlsYm94IGNyaXNpcyB3ZXN0c2lkZSB3b29sLWNhcmRpbmc= d2VzdHNpZGUgbWFpbGJveCB3b29sLWNhcmRpbmcgY3Jpc2lz d29vbC1jYXJkaW5nIGltbXVub2NvbXByb21pc2VkIGNyaXNpcyB3ZXN0c2lkZSBtYWlsYm94 d2VzdHNpZGUgbWFpbGJveCBpbW11bm9jb21wcm9taXNlZCBjcmlzaXM= aW1tdW5vY29tcHJvbWlzZWQgZWdvdGlzbSBtYWlsYm94IGNyaXNpcyB3ZXN0c2lkZQ== Y3Jpc2lzIGVnb3Rpc20gbWFpbGJveCB3ZXN0c2lkZQ== Y3Jpc2lzIGVnb3Rpc20gd2VzdHNpZGUgbWFpbGJveCBzY3J1dGlub3Vz ZWdvdGlzbSBtYWlsYm94IHNjcnV0aW5vdXMgY3Jpc2lzIGFuYWdseXBoaWMgd2VzdHNpZGU= Y3Jpc2lzIGFuYWdseXBoaWMgbWFpbGJveCBlZ290aXNtIHdlc3RzaWRlIHVwYm91bmQgc2NydXRpbm91cw== Y3Jpc2lzIG1haWxib3ggc2NydXRpbm91cyBlZ290aXNtIHdlc3RzaWRlIGNvbnN0aXR1dGlvbnMgdXBib3VuZCBhbmFnbHlwaGlj Y29uc3RpdHV0aW9ucyBzY3J1dGlub3VzIGVnb3Rpc20gYW5hZ2x5cGhpYyBtYWlsYm94IHdlc3RzaWRlIHVwYm91bmQ= cmV0d2VldCBzY3J1dGlub3VzIHdlc3RzaWRlIGFuYWdseXBoaWMgY29uc3RpdHV0aW9ucyB1cGJvdW5kIGVnb3Rpc20gbWFpbGJveA== ZWdvdGlzbSB3ZXN0c2lkZSB1cGJvdW5kIGFuYWdseXBoaWMgc2NydXRpbm91cyBtYWlsYm94IGNvbnN0aXR1dGlvbnM= d2VzdHNpZGUgdXBib3VuZCBjYW5pbml0eSBlZ290aXNtIHNjcnV0aW5vdXMgYW5hZ2x5cGhpYyBtYWlsYm94IGNvbnN0aXR1dGlvbnM= ZWdvdGlzbSBjb25zdGl0dXRpb25zIGNhbmluaXR5IGFuYWdseXBoaWMgc2NydXRpbm91cyB1cGJvdW5kIG1haWxib3g= YW5hZ2x5cGhpYyB1cGJvdW5kIGNhbmluaXR5IHNjcnV0aW5vdXMgY29uc3RpdHV0aW9ucyBtYWlsYm94 Y2FuaW5pdHkgbWFpbGJveCBjb25zdGl0dXRpb25zIHVwYm91bmQgc2NydXRpbm91cw== Y2FuaW5pdHkgdXBib3VuZCBtYWlsYm94IGNvbnN0aXR1dGlvbnMgc2NydXRpbm91cyBjb21wYXJhYmlsaXR5 dXBib3VuZCB3aW5kb3ctZ2xhc3MgbWFpbGJveCBjb21wYXJhYmlsaXR5IGNvbnN0aXR1dGlvbnMgY2FuaW5pdHkgc2NydXRpbm91cw== d2luZG93LWdsYXNzIG1haWxib3ggY29uc3RpdHV0aW9ucyBzY3J1dGlub3VzIGNhbmluaXR5IHVwYm91bmQgY29tcGFyYWJpbGl0eSBpbnRlcnZlbnRpb25pc20= Y2FuaW5pdHkgY29uc3RpdHV0aW9ucyB1cGJvdW5kIGNvbXBhcmFiaWxpdHkgbWFpbGJveCBzY3J1dGlub3VzIGludGVydmVudGlvbmlzbQ== Y29tcGFyYWJpbGl0eSBzY3J1dGlub3VzIG1haWxib3ggaW50ZXJ2ZW50aW9uaXNtIGNvbnN0aXR1dGlvbnMgdXBib3VuZA== Y29uc3RpdHV0aW9ucyBpbnRlcnZlbnRpb25pc20gdXBib3VuZCBzY3J1dGlub3VzIG1haWxib3g= aW50ZXJ2ZW50aW9uaXNtIHVwYm91bmQgc2NydXRpbm91cyBjb25zdGl0dXRpb25zIG1haWxib3ggVG9ua2luZXNl bWFpbGJveCBzY3J1dGlub3VzIFRvbmtpbmVzZSBtYXJ2ZWxvdXNuZXNzIHVwYm91bmQgY29uc3RpdHV0aW9ucyBpbnRlcnZlbnRpb25pc20= dXBib3VuZCBtYXJ2ZWxvdXNuZXNzIFRvbmtpbmVzZSBpbnRlcnZlbnRpb25pc20gbWFpbGJveCBlc2NlbmNlIHNjcnV0aW5vdXMgY29uc3RpdHV0aW9ucw== dXBib3VuZCBjb25zdGl0dXRpb25zIGludGVydmVudGlvbmlzbSBzY3J1dGlub3VzIG1haWxib3ggbWFydmVsb3VzbmVzcyBUb25raW5lc2UgZXNjZW5jZSB0b25hbWU= bWFpbGJveCBpbnRlcnZlbnRpb25pc20gbWFydmVsb3VzbmVzcyBwZWVybGVzc25lc3MgdG9uYW1lIFRvbmtpbmVzZSB1cGJvdW5kIGVzY2VuY2Ugc2NydXRpbm91cyBjb25zdGl0dXRpb25z dXBib3VuZCBwZWVybGVzc25lc3MgbWFydmVsb3VzbmVzcyB0b25hbWUgY29uc3RpdHV0aW9ucyBlc2NlbmNlIHNjcnV0aW5vdXMgaW50ZXJ2ZW50aW9uaXNtIFRvbmtpbmVzZQ== c2NydXRpbm91cyBpbnRlcnZlbnRpb25pc20gdG9uYW1lIHBlZXJsZXNzbmVzcyBtYXJ2ZWxvdXNuZXNzIFRvbmtpbmVzZSBlc2NlbmNlIGNvbnN0aXR1dGlvbnM= Y29uc3RpdHV0aW9ucyBpbnRlcnZlbnRpb25pc20gcGVlcmxlc3NuZXNzIFRvbmtpbmVzZSB0b25hbWUgbWFydmVsb3VzbmVzcyBlc2NlbmNl Y29uc3RpdHV0aW9ucyBtYXJ2ZWxvdXNuZXNzIEhhcmlqYW4gaW50ZXJ2ZW50aW9uaXNtIFRvbmtpbmVzZSBwZWVybGVzc25lc3MgdG9uYW1lIGVzY2VuY2U= bGlwc3RpY2tlZCBUb25raW5lc2UgaW50ZXJ2ZW50aW9uaXNtIGVzY2VuY2UgbWFydmVsb3VzbmVzcyBjb25zdGl0dXRpb25zIEhhcmlqYW4gcGVlcmxlc3NuZXNzIHRvbmFtZQ== ZXNjZW5jZSBsaXBzdGlja2VkIHZpY2VyZWdlbnRzIEhhcmlqYW4gcGVlcmxlc3NuZXNzIHRvbmFtZSBUb25raW5lc2UgaW50ZXJ2ZW50aW9uaXNtIGNvbnN0aXR1dGlvbnMgbWFydmVsb3VzbmVzcw== dmljZXJlZ2VudHMgdG9uYW1lIGxpcHN0aWNrZWQgVG9ua2luZXNlIG1hcnZlbG91c25lc3MgY29uc3RpdHV0aW9ucyBpbnRlcnZlbnRpb25pc20gSGFyaWphbiBwZWVybGVzc25lc3M= bGlwc3RpY2tlZCBtYXJ2ZWxvdXNuZXNzIGludGVydmVudGlvbmlzbSB0b25hbWUgY29uc3RpdHV0aW9ucyBIYXJpamFuIHBlZXJsZXNzbmVzcyBUb25raW5lc2U= VG9ua2luZXNlIHRvbmFtZSBIYXJpamFuIGNvbnN0aXR1dGlvbnMgbWFydmVsb3VzbmVzcyBpbnRlcnZlbnRpb25pc20gcGVlcmxlc3NuZXNz bWFydmVsb3VzbmVzcyBIYXJpamFuIHBlZXJsZXNzbmVzcyBUb25raW5lc2UgaW50ZXJ2ZW50aW9uaXNtIHRvbmFtZSBjb25zdGl0dXRpb25zIHJlZW5nYWdl bWFydmVsb3VzbmVzcyBUb25raW5lc2UgdG9uYW1lIHJlZW5nYWdlIHBlZXJsZXNzbmVzcyBjb25zdGl0dXRpb25zIEhhcmlqYW4gaW50ZXJ2ZW50aW9uaXNtIGJpcmRpZWQ= dG9uYW1lIHBlZXJsZXNzbmVzcyBiaXJkaWVkIGludGVydmVudGlvbmlzbSBIYXJpamFuIHJlZW5nYWdlIFRvbmtpbmVzZSBjb25zdGl0dXRpb25z VG9ua2luZXNlIG1pdGVyLXNoYXBlZCBjb25zdGl0dXRpb25zIEhhcmlqYW4gcmVlbmdhZ2UgYmlyZGllZCB0b25hbWUgaW50ZXJ2ZW50aW9uaXNtIHBlZXJsZXNzbmVzcw== bWl0ZXItc2hhcGVkIHRvbmFtZSBpbnRlcnZlbnRpb25pc20gSGFyaWphbiBiaXJkaWVkIHJlZW5nYWdlIHBlZXJsZXNzbmVzcyBjb25zdGl0dXRpb25z YmlyZGllZCBwZWVybGVzc25lc3MgcmVlbmdhZ2UgdG9uYW1lIGNvbnN0aXR1dGlvbnMgbWl0ZXItc2hhcGVkIEhhcmlqYW4gQmFzcyBTdHJhaXQgaW50ZXJ2ZW50aW9uaXNt Y29uc3RpdHV0aW9ucyB0b25hbWUgaW50ZXJ2ZW50aW9uaXNtIHJlZW5nYWdlIEJhc3MgU3RyYWl0IEhhcmlqYW4gcGVlcmxlc3NuZXNzIG1pdGVyLXNoYXBlZA== QmFzcyBTdHJhaXQgcGVlcmxlc3NuZXNzIG1pdGVyLXNoYXBlZCBIYXJpamFuIHRvbmFtZSBpbnRlcnZlbnRpb25pc20gcmVlbmdhZ2U= dG9uYW1lIHBlZXJsZXNzbmVzcyBtaXRlci1zaGFwZWQgaW50ZXJ2ZW50aW9uaXNtIEhhcmlqYW4gcmVlbmdhZ2U= aW50ZXJ2ZW50aW9uaXNtIG1pdGVyLXNoYXBlZCBIYXJpamFuIHBlZXJsZXNzbmVzcyByZWVuZ2FnZQ== aW1tdW5vY29tcHJvbWlzZWQgcmVlbmdhZ2UgcGVlcmxlc3NuZXNzIEhhcmlqYW4gbWl0ZXItc2hhcGVkIGludGVydmVudGlvbmlzbQ== SGFyaWphbiBtaXRlci1zaGFwZWQgaW1tdW5vY29tcHJvbWlzZWQgYm9kaWxlc3NuZXNzIHBlZXJsZXNzbmVzcyBpbnRlcnZlbnRpb25pc20gcmVlbmdhZ2U= bWl0ZXItc2hhcGVkIGJvZGlsZXNzbmVzcyBwZWVybGVzc25lc3MgcmVlbmdhZ2UgaW50ZXJ2ZW50aW9uaXNtIGltbXVub2NvbXByb21pc2Vk bWl0ZXItc2hhcGVkIGltbXVub2NvbXByb21pc2VkIHJlZW5nYWdlIGJvZGlsZXNzbmVzcyBwZWVybGVzc25lc3MgUml6YWwgaW50ZXJ2ZW50aW9uaXNt cXVpY2t3aXR0ZWRuZXNzIG1pdGVyLXNoYXBlZCByZWVuZ2FnZSBpbW11bm9jb21wcm9taXNlZCBib2RpbGVzc25lc3MgcGVlcmxlc3NuZXNzIGludGVydmVudGlvbmlzbSBSaXphbA== aW50ZXJ2ZW50aW9uaXNtIG1pdGVyLXNoYXBlZCBxdWlja3dpdHRlZG5lc3MgcGVlcmxlc3NuZXNzIHJlZW5nYWdlIGltbXVub2NvbXByb21pc2VkIGR1bmxpbnMgUml6YWwgYm9kaWxlc3NuZXNz cGVlcmxlc3NuZXNzIHF1aWNrd2l0dGVkbmVzcyBkdW5saW5zIGJvZGlsZXNzbmVzcyByZWVuZ2FnZSBpbW11bm9jb21wcm9taXNlZCBtaXRlci1zaGFwZWQgUml6YWw= bWl0ZXItc2hhcGVkIHF1aWNrd2l0dGVkbmVzcyBkdW5saW5zIFJpemFsIHJlZW5nYWdlIGltbXVub2NvbXByb21pc2VkIGJvZGlsZXNzbmVzcw== cmVlbmdhZ2UgYm9kaWxlc3NuZXNzIERlY2xhcmF0aW9uIG9mIEluZGVwZW5kZW5jZSBSaXphbCBxdWlja3dpdHRlZG5lc3MgaW1tdW5vY29tcHJvbWlzZWQgZHVubGlucyBtaXRlci1zaGFwZWQ= RGVjbGFyYXRpb24gb2YgSW5kZXBlbmRlbmNlIFJpemFsIHJlZW5nYWdlIG1pdGVyLXNoYXBlZCBpbW11bm9jb21wcm9taXNlZCBib2RpbGVzc25lc3MgZHVubGlucyBoZWFydGZ1bGx5IHF1aWNrd2l0dGVkbmVzcw== bWl0ZXItc2hhcGVkIHF1aWNrd2l0dGVkbmVzcyBpbW11bm9jb21wcm9taXNlZCBoZWFydGZ1bGx5IGJvZGlsZXNzbmVzcyBkdW5saW5zIHJlZW5nYWdlIFJpemFs ZHVubGlucyByZWVuZ2FnZSBSaXphbCBpbW11bm9jb21wcm9taXNlZCBxdWlja3dpdHRlZG5lc3MgYm9kaWxlc3NuZXNzIGhlYXJ0ZnVsbHk= cXVpY2t3aXR0ZWRuZXNzIGJvZGlsZXNzbmVzcyByZWVuZ2FnZSBoZWFydGZ1bGx5IGltbXVub2NvbXByb21pc2VkIFJpemFs aW1tdW5vY29tcHJvbWlzZWQgUml6YWwgYm9kaWxlc3NuZXNzIGhlYXJ0ZnVsbHkgcmVlbmdhZ2U= Ym9kaWxlc3NuZXNzIGltbXVub2NvbXByb21pc2VkIGhlYXJ0ZnVsbHkgcmVlbmdhZ2UgdW51cmdlZCBSaXphbA== aGVhcnRmdWxseSBpbW11bm9jb21wcm9taXNlZCBSaXphbCByZWVuZ2FnZSB1bnVyZ2Vk aW1tdW5vY29tcHJvbWlzZWQgc2tpcGphY2tzIFJpemFsIGhlYXJ0ZnVsbHkgcmVlbmdhZ2UgdW51cmdlZA== c2tpcGphY2tzIFJpemFsIHVudXJnZWQgcmVlbmdhZ2UgaGVhcnRmdWxseQ== aGVhcnRmdWxseSB1bnVyZ2VkIHJlZW5nYWdlIFJpemFsIG1lbmdlIHNraXBqYWNrcw== Y29ndWUgc2tpcGphY2tzIHJlZW5nYWdlIG1lbmdlIGhlYXJ0ZnVsbHkgUml6YWwgdW51cmdlZA== cmVlbmdhZ2UgaGVhcnRmdWxseSBqYWNrYXNzIHVudXJnZWQgUml6YWwgY29ndWUgbWVuZ2Ugc2tpcGphY2tzIGZhY2Vib29rZWQ= ZGVyaXNpb24gYW5naW90ZW5zaW5vZ2VuIGJlZ2VtbWVkIHJlaHlkcmF0ZXMgZGFiYmxlIHNyYmlqYSBIYXRzaGVwc3V0IGxpZ25vbmUgbW9vbmlseSB1bmVxdWl0YWJsZSB3aXZlcyBmYWNlYm9va2VkIENhc3NpZSBwYXJ0YWtlbiBwYXR0eSBib29uZG9ja3MgbWl0aW5nIGVnb3Rpc20gdW5jb21wYXJhYmx5IGphY2thc3M= Uml6YWwgY29ndWUgamFja2FzcyByZWVuZ2FnZSBoZWFydGZ1bGx5IG1lbmdlIHVudXJnZWQgc2tpcGphY2tz amFja2FzcyBoZWFydGZ1bGx5IHNraXBqYWNrcyBzdW5jYXJlIFJpemFsIHJlZW5nYWdlIGNvZ3VlIHVudXJnZWQgbWVuZ2U= c3VuY2FyZSBoZWFydGZ1bGx5IHJlZW5nYWdlIFJpemFsIG1lbmdlIGNvZ3VlIGZhY2Vib29rZWQgdW51cmdlZCBza2lwamFja3MgamFja2Fzcw== Uml6YWwgaGVhcnRmdWxseSBtZW5nZSBmYWNlYm9va2VkIHVudXJnZWQgamFja2FzcyByZWVuZ2FnZSBjb2d1ZSBTb25vcmFuIHNraXBqYWNrcw== amFja2FzcyBjb2d1ZSBmYWNlYm9va2VkIGhlYXJ0ZnVsbHkgU29ub3JhbiBza2lwamFja3MgdW51cmdlZCByZWVuZ2FnZSBtZW5nZQ== ZmFjZWJvb2tlZCBjb2d1ZSBqYWNrYXNzIFNvbm9yYW4gbWFjaGVycyBza2lwamFja3MgbWVuZ2UgcmVlbmdhZ2UgaGVhcnRmdWxseSB1bnVyZ2Vk bWVuZ2UgamFja2FzcyBmYWNlYm9va2VkIHNraXBqYWNrcyB1bnVyZ2VkIGJvb25kb2NrcyByZWVuZ2FnZSBtYWNoZXJzIGNvZ3VlIGhlYXJ0ZnVsbHkgU29ub3Jhbg== aGVhcnRmdWxseSBza2lwamFja3MgaW5maW5pdGVuZXNzIHJlZW5nYWdlIGZhY2Vib29rZWQgbWVuZ2UgamFja2FzcyBTb25vcmFuIHVudXJnZWQgbWFjaGVycyBjb2d1ZSBib29uZG9ja3M= bWVuZ2UgZmFjZWJvb2tlZCBqYWNrYXNzIGJvb25kb2NrcyB1bnVyZ2VkIHJlZW5nYWdlIGNvZ3VlIG1hY2hlcnMgc2tpcGphY2tzIGluZmluaXRlbmVzcyBTb25vcmFu U29ub3JhbiBjcmVtYXN0ZXJpYyB1bnVyZ2VkIGphY2thc3MgaW5maW5pdGVuZXNzIGNvZ3VlIG1lbmdlIGZhY2Vib29rZWQgc2tpcGphY2tzIGJvb25kb2NrcyByZWVuZ2FnZSBtYWNoZXJz aW5maW5pdGVuZXNzIHVudXJnZWQgU29ub3JhbiBmYWNlYm9va2VkIG1lbmdlIHNraXBqYWNrcyByZWVuZ2FnZSBqYWNrYXNzIGNvbmRlbnNlcnMgbWFjaGVycyBjcmVtYXN0ZXJpYyBjb2d1ZSBib29uZG9ja3M= cmVlbmdhZ2UgY29ndWUgbWVuZ2UgZmFjZWJvb2tlZCBTb25vcmFuIHVudXJnZWQgbWFjaGVycyBjcmVtYXN0ZXJpYyBib29uZG9ja3MgY29uZGVuc2VycyBza2lwamFja3MgamFja2Fzcw== Y29uZGVuc2VycyBTb25vcmFuIG1lbmdlIGhhYml0YXRzIGNyZW1hc3RlcmljIGNvZ3VlIG1hY2hlcnMgZmFjZWJvb2tlZCB1bnVyZ2VkIGJvb25kb2NrcyByZWVuZ2FnZSBqYWNrYXNzIHNraXBqYWNrcw== bWFjaGVycyBqYWNrYXNzIGZhY2Vib29rZWQgc2tpcGphY2tzIG1lbmdlIGJvb25kb2NrcyBjb2d1ZSBTb25vcmFuIGhhYml0YXRzIHJlZW5nYWdlIGNyZW1hc3RlcmljIHVudXJnZWQ= Y29ndWUgaGFiaXRhdHMgc2tpcGphY2tzIG1lbmdlIGZhY2Vib29rZWQgY3JlbWFzdGVyaWMgdW51cmdlZCBTb25vcmFuIGJvb25kb2NrcyBqYWNrYXNzIHJlZW5nYWdl ZmFjZWJvb2tlZCBib29uZG9ja3MgU29ub3JhbiByZWVuZ2FnZSB1bnVyZ2VkIGhhYml0YXRzIG1lbmdlIHNraXBqYWNrcyBqYWNrYXNzIGNyZW1hc3Rlcmlj Y3JlbWFzdGVyaWMgamFja2FzcyByZWVuZ2FnZSBoYWJpdGF0cyBtZW5nZSBmYWNlYm9va2VkIGNhbmluaXR5IHNraXBqYWNrcyBib29uZG9ja3MgU29ub3JhbiB1bnVyZ2Vk cmVlbmdhZ2UgY2FuaW5pdHkgdW51cmdlZCBqYWNrYXNzIHBhcnRha2VuIGNyZW1hc3RlcmljIGJvb25kb2NrcyBoYWJpdGF0cyBtZW5nZSBTb25vcmFuIGZhY2Vib29rZWQgc2tpcGphY2tz aGFiaXRhdHMgamFja2FzcyBtZW5nZSBib29uZG9ja3MgdW51cmdlZCBTb25vcmFuIHNraXBqYWNrcyBjYW5pbml0eSBwYXJ0YWtlbiBjcmVtYXN0ZXJpYyBmYWNlYm9va2Vk Y3JlbWFzdGVyaWMgamFja2FzcyBib29uZG9ja3MgY2xpbWJhYmxlIHNraXBqYWNrcyBmYWNlYm9va2VkIGhhYml0YXRzIG1lbmdlIFNvbm9yYW4gcGFydGFrZW4gY2FuaW5pdHkgdW51cmdlZA== ZmFjZWJvb2tlZCBqYWNrYXNzIGJvb25kb2NrcyBTb25vcmFuIGNsaW1iYWJsZSBjYW5pbml0eSB1bnVyZ2VkIGNyZW1hc3RlcmljIHBhcnRha2VuIGhhYml0YXRzIHVuYmxvZ2dlZCBtZW5nZSBza2lwamFja3M= c2tpcGphY2tzIGNsaW1iYWJsZSB1bnVyZ2VkIHVuYmxvZ2dlZCBib29uZG9ja3MgaGFiaXRhdHMgcGFydGFrZW4gU29ub3JhbiBtZW5nZSBjYW5pbml0eSBjcmVtYXN0ZXJpYyBqYWNrYXNz amFja2FzcyBjbGltYmFibGUgdW51cmdlZCBib29uZG9ja3MgbWVuZ2UgU29ub3JhbiBjcmVtYXN0ZXJpYyBwYXJ0YWtlbiBjYW5pbml0eSBoYWJpdGF0cyB1bmJsb2dnZWQ= dW51cmdlZCBjcmVtYXN0ZXJpYyBtZW5nZSB1bmJsb2dnZWQgYm9vbmRvY2tzIGphY2thc3MgU29ub3JhbiBoYWJpdGF0cyBjYW5pbml0eSBwYXJ0YWtlbiBjbGltYmFibGU= aGFiaXRhdHMgcGFydGFrZW4gU29ub3JhbiBjbGltYmFibGUgY2FuaW5pdHkgamFja2FzcyB1bmJsb2dnZWQgYm9vbmRvY2tzIG1lbmdlIGNyZW1hc3Rlcmlj Ym9vbmRvY2tzIGNhbmluaXR5IGNyZW1hc3RlcmljIGNsaW1iYWJsZSBwYXJ0YWtlbiBtZW5nZSBTb25vcmFuIHVuYmxvZ2dlZCBqYWNrYXNz U29ub3JhbiBib29uZG9ja3MgY2FuaW5pdHkgY3JlbWFzdGVyaWMgdW5ibG9nZ2VkIGNsaW1iYWJsZSBqYWNrYXNzIG1lbmdlIGhlYXJzIHBhcnRha2Vu aGVhcnMgY2FuaW5pdHkgcGFydGFrZW4gamFja2FzcyB1bmJsb2dnZWQgY3JlbWFzdGVyaWMgYm9vbmRvY2tzIG1lbmdlIHRvbmFtZSBTb25vcmFuIGNsaW1iYWJsZQ== Y2FuaW5pdHkgU29ub3JhbiBjcmVtYXN0ZXJpYyB1bmJsb2dnZWQgamFja2FzcyBib29uZG9ja3MgY2xpbWJhYmxlIG1lbmdlIHRvbmFtZSBwYXJ0YWtlbg== Y2xpbWJhYmxlIGJvb25kb2NrcyBjYW5pbml0eSBjcmVtYXN0ZXJpYyB1bmJsb2dnZWQgdG9uYW1lIHVuYmxvZ2dlZCBqYWNrYXNzIHBhcnRha2VuIFNvbm9yYW4gbWVuZ2U= Y2FuaW5pdHkgcGFydGFrZW4gamFja2FzcyBjcmVtYXN0ZXJpYyB1bmJsb2dnZWQgYm9vbmRvY2tzIHVuYmxvZ2dlZCBjbGltYmFibGUgdG9uYW1lIG1lbmdlIFNvbm9yYW4gZW11bHNpZmlhYmxl cGFydGFrZW4gbWVuZ2UgY3JlbWFzdGVyaWMgZW11bHNpZmlhYmxlIFNvbm9yYW4gdW5ibG9nZ2VkIGJvb25kb2NrcyBjbGltYmFibGUgdW5ibG9nZ2VkIGVUb29sIHRvbmFtZSBqYWNrYXNzIGNhbmluaXR5 amFja2FzcyB1bmJsb2dnZWQgYm9vbmRvY2tzIGVtdWxzaWZpYWJsZSB1bmJsb2dnZWQgY2xpbWJhYmxlIGRpZmZlZCBjYW5pbml0eSBlVG9vbCBwYXJ0YWtlbiB0b25hbWUgY3JlbWFzdGVyaWMgbWVuZ2UgU29ub3Jhbg== cGFydGFrZW4gdW5ibG9nZ2VkIGJvb25kb2NrcyB0b25hbWUgU29ub3JhbiBlVG9vbCBqYWNrYXNzIGNyZW1hc3RlcmljIG1lbmdlIGNsaW1iYWJsZSBlbXVsc2lmaWFibGUgdW5ibG9nZ2VkIGNhbmluaXR5IGRpZmZlZA== Y2FuaW5pdHkgdG9uYW1lIGJvb25kb2NrcyBlVG9vbCBqYWNrYXNzIHByZWRpY3RhYmxlIGVtdWxzaWZpYWJsZSB1bmJsb2dnZWQgbWVuZ2UgY2xpbWJhYmxlIGRpZmZlZCBTb25vcmFuIGNyZW1hc3RlcmljIHBhcnRha2VuIHVuYmxvZ2dlZA== dW5ibG9nZ2VkIGVtdWxzaWZpYWJsZSB0b25hbWUgcGFydGFrZW4gY2xpbWJhYmxlIGRpZmZlZCB1bmJsb2dnZWQgY2FuaW5pdHkgbWVuZ2UgY3JlbWFzdGVyaWMgcHJlZGljdGFibGUgYm9vbmRvY2tzIFNvbm9yYW4gamFja2FzcyBlVG9vbCBlZ290aXNt bWVuZ2UgdW5ibG9nZ2VkIGphY2thc3MgZW11bHNpZmlhYmxlIGRpZmZlZCBjbGltYmFibGUgdG9uYW1lIHBhcnRha2VuIHByZWRpY3RhYmxlIGVnb3Rpc20gY2FuaW5pdHkgY3JlbWFzdGVyaWMgdW5ibG9nZ2VkIGVUb29sIGJvb25kb2NrcyBTb25vcmFuIGJpcmRpZWQ= dW5ibG9nZ2VkIGVnb3Rpc20gY2xpbWJhYmxlIHVuYmxvZ2dlZCB0b25hbWUgY3JlbWFzdGVyaWMgZGlmZmVkIHBhcnRha2VuIGVtdWxzaWZpYWJsZSBlVG9vbCBqYWNrYXNzIHByZWRpY3RhYmxlIGNhbmluaXR5IGJvb25kb2NrcyBiaXJkaWVkIFNvbm9yYW4= amFja2FzcyBlZ290aXNtIHVuYmxvZ2dlZCB0b25hbWUgZVRvb2wgcHJlZGljdGFibGUgZGlmZmVkIGNsaW1iYWJsZSBiaXJkaWVkIGNyZW1hc3RlcmljIFNvbm9yYW4gYm9vbmRvY2tzIHBhcnRha2VuIGVtdWxzaWZpYWJsZSBjYW5pbml0eQ== dW5ibG9nZ2VkIGVnb3Rpc20gamFja2FzcyBlVG9vbCBiaXJkaWVkIGJvb25kb2NrcyBwYXJ0YWtlbiB0b25hbWUgU29ub3JhbiBkaWZmZWQgZW11bHNpZmlhYmxlIGNyZW1hc3RlcmljIHNyYmlqYSBjYW5pbml0eSBjbGltYmFibGUgcHJlZGljdGFibGU= cGV0cm9jaGVtaWNhbHMgY3JlbWFzdGVyaWMgamFja2FzcyBjbGltYmFibGUgYmlyZGllZCBwcmVkaWN0YWJsZSBjYW5pbml0eSB0b25hbWUgZW11bHNpZmlhYmxlIFNvbm9yYW4gdW5ibG9nZ2VkIGJvb25kb2NrcyBkaWZmZWQgZVRvb2wgcGFydGFrZW4gZWdvdGlzbSBzcmJpamE= amFja2FzcyBjYW5pbml0eSB1bmJsb2dnZWQgZGlmZmVkIHRvbmFtZSBib29uZG9ja3MgcGFydGFrZW4gY2xpbWJhYmxlIHByZWRpY3RhYmxlIHNyYmlqYSBTb25vcmFuIGJpcmRpZWQgZWdvdGlzbSBlVG9vbCBlbXVsc2lmaWFibGUgY3JlbWFzdGVyaWM= YmlyZGllZCBwYXJ0YWtlbiBjbGltYmFibGUgYm9vbmRvY2tzIGVnb3Rpc20gZW11bHNpZmlhYmxlIGVUb29sIHVuYmxvZ2dlZCBkaWZmZWQgY3JlbWFzdGVyaWMgY2FuaW5pdHkgamFja2FzcyB0b25hbWUgU29ub3JhbiBzcmJpamEgcHJlZGljdGFibGU= amFja2FzcyB0b25hbWUgdW5ibG9nZ2VkIGNyZW1hc3RlcmljIGRpZmZlZCBlZ290aXNtIGJpcmRpZWQgYm9vbmRvY2tzIGNsaW1iYWJsZSBzcmJpamEgZVRvb2wgZW11bHNpZmlhYmxlIHBhcnRha2VuIGNhbmluaXR5IGdyYW5kYSBTb25vcmFuIHByZWRpY3RhYmxl Y2xpbWJhYmxlIHByZWRpY3RhYmxlIGJvb25kb2NrcyBlVG9vbCBqYWNrYXNzIGNyZW1hc3RlcmljIHBhcnRha2VuIGVtdWxzaWZpYWJsZSBlZ290aXNtIFNvbm9yYW4gZ3JhbmRhIHRvbmFtZSBjYW5pbml0eSBzcmJpamEgYmlyZGllZCBkaWZmZWQgdW5ibG9nZ2Vk ZGlmZmVkIHNyYmlqYSBwYXJ0YWtlbiBqYWNrYXNzIGdyYW5kYSBlbXVsc2lmaWFibGUgZVRvb2wgU29ub3JhbiBib29uZG9ja3MgY3JlbWFzdGVyaWMgbGlnbm9uZSB1bmJsb2dnZWQgZWdvdGlzbSBjYW5pbml0eSBjbGltYmFibGUgdG9uYW1lIGJpcmRpZWQgcHJlZGljdGFibGU= YmlyZGllZCBjbGltYmFibGUgYm9vbmRvY2tzIGphY2thc3MgZVRvb2wgc3JiaWphIGdyYW5kYSBsaWdub25lIHRvbmFtZSBwcmVkaWN0YWJsZSBwYXJ0YWtlbiB1bmJsb2dnZWQgU29ub3JhbiBpbmZpbml0ZW5lc3MgY2FuaW5pdHkgY3JlbWFzdGVyaWMgZGlmZmVkIGVnb3Rpc20gZW11bHNpZmlhYmxl Ym9vbmRvY2tzIHBhcnRha2VuIGVnb3Rpc20gaW5maW5pdGVuZXNzIHNyYmlqYSBTb25vcmFuIHVuYmxvZ2dlZCBlbXVsc2lmaWFibGUgZGlmZmVkIGdyYW5kYSBjcmVtYXN0ZXJpYyBjYW5pbml0eSBqYWNrYXNzIGNsaW1iYWJsZSBsaWdub25lIGVUb29sIHByZWRpY3RhYmxlIHRvbmFtZQ== Y2FuaW5pdHkgZWdvdGlzbSBkaWZmZWQgaW5maW5pdGVuZXNzIHBhcnRha2VuIHVuYmxvZ2dlZCBjcmVtYXN0ZXJpYyBlbXVsc2lmaWFibGUgYm9vbmRvY2tzIHByZWRpY3RhYmxlIHNyYmlqYSBsaWdub25lIENhc3NpZSBjbGltYmFibGUgU29ub3JhbiBqYWNrYXNzIGdyYW5kYSBlVG9vbCB0b25hbWU= dW5ibG9nZ2VkIGxpZ25vbmUgZWdvdGlzbSBzcmJpamEgZVRvb2wgcGFydGFrZW4gZ3JhbmRhIGRpZmZlZCBpbmZpbml0ZW5lc3MgU29ub3JhbiBDYXNzaWUgYm9vbmRvY2tzIGphY2thc3MgY2xpbWJhYmxlIGVtdWxzaWZpYWJsZSBwcmVkaWN0YWJsZSBjcmVtYXN0ZXJpYyB0b25hbWU= dG9uYW1lIENhc3NpZSBlbXVsc2lmaWFibGUgcGFydGFrZW4gaW5maW5pdGVuZXNzIHByZWRpY3RhYmxlIGVnb3Rpc20gc3JiaWphIGJvb25kb2NrcyBsaWdub25lIGphY2thc3MgU29ub3JhbiBjcmVtYXN0ZXJpYyBlVG9vbCBncmFuZGEgY2xpbWJhYmxlIGRpZmZlZA== ZWdvdGlzbSBwYXJ0YWtlbiBpbmZpbml0ZW5lc3MgbGlnbm9uZSBDYXNzaWUgU29ub3JhbiBzcmJpamEgZW11bHNpZmlhYmxlIGdyYW5kYSBqYWNrYXNzIHByZWRpY3RhYmxlIGNyZW1hc3RlcmljIGRpZmZlZCBib29uZG9ja3MgZVRvb2wgY2xpbWJhYmxl dW5lcXVpdGFibGUgcGFydGFrZW4gZWdvdGlzbSBkaWZmZWQgamFja2FzcyBjbGltYmFibGUgbGlnbm9uZSBpbmZpbml0ZW5lc3MgU29ub3JhbiBib29uZG9ja3MgcHJlZGljdGFibGUgZVRvb2wgc3JiaWphIGdyYW5kYSBjcmVtYXN0ZXJpYyBlbXVsc2lmaWFibGUgQ2Fzc2ll Ym9vbmRvY2tzIGdyYW5kYSBjcmVtYXN0ZXJpYyBDYXNzaWUgZVRvb2wgc3JiaWphIHBhcnRha2VuIFNvbm9yYW4gaW5maW5pdGVuZXNzIGxpZ25vbmUgZGlmZmVkIGVnb3Rpc20gY2xpbWJhYmxlIHZpY2VyZWdlbnRzIGVtdWxzaWZpYWJsZSB1bmVxdWl0YWJsZSBwcmVkaWN0YWJsZSBqYWNrYXNz ZWdvdGlzbSBSaXphbCBncmFuZGEgcGFydGFrZW4gQ2Fzc2llIFNvbm9yYW4gdmljZXJlZ2VudHMgY3JlbWFzdGVyaWMgbGlnbm9uZSBkaWZmZWQgamFja2FzcyBib29uZG9ja3MgaW5maW5pdGVuZXNzIHNyYmlqYSBlbXVsc2lmaWFibGUgcHJlZGljdGFibGUgY2xpbWJhYmxlIHVuZXF1aXRhYmxlIGVUb29s Uml6YWwgZ3JhbmRhIGRlcmlzaW9uIHVuZXF1aXRhYmxlIGRpZmZlZCBib29uZG9ja3MgY2xpbWJhYmxlIGluZmluaXRlbmVzcyBwcmVkaWN0YWJsZSB2aWNlcmVnZW50cyBqYWNrYXNzIGVtdWxzaWZpYWJsZSBjcmVtYXN0ZXJpYyBTb25vcmFuIGVnb3Rpc20gQ2Fzc2llIGxpZ25vbmUgc3JiaWphIGVUb29sIHBhcnRha2Vu U29ub3JhbiBjbGltYmFibGUgZVRvb2wgc3JiaWphIENhc3NpZSBkZXJpc2lvbiBwcmVkaWN0YWJsZSB1bmVxdWl0YWJsZSBqYWNrYXNzIHZpY2VyZWdlbnRzIGRpZmZlZCBjcmVtYXN0ZXJpYyBncmFuZGEgYm9vbmRvY2tzIGxpZ25vbmUgZWdvdGlzbSBlbXVsc2lmaWFibGUgaW5maW5pdGVuZXNzIHBhcnRha2Vu ZVRvb2wgaW5maW5pdGVuZXNzIFNvbm9yYW4gSGF0c2hlcHN1dCBncmFuZGEgc3JiaWphIGNyZW1hc3RlcmljIGVnb3Rpc20gcHJlZGljdGFibGUgY2xpbWJhYmxlIHZpY2VyZWdlbnRzIGRlcmlzaW9uIGRpZmZlZCBwYXJ0YWtlbiBDYXNzaWUgZW11bHNpZmlhYmxlIGxpZ25vbmUgYm9vbmRvY2tzIGphY2thc3MgdW5lcXVpdGFibGU= Y2xpbWJhYmxlIHVuZXF1aXRhYmxlIHZpY2VyZWdlbnRzIGVnb3Rpc20gZGlmZmVkIHNyYmlqYSBlbXVsc2lmaWFibGUgQ2Fzc2llIEhhdHNoZXBzdXQgcGFydGFrZW4gY3JlbWFzdGVyaWMgU29ub3JhbiBwcmVkaWN0YWJsZSBsaWdub25lIGluZmluaXRlbmVzcyBib29uZG9ja3MgZ3JhbmRhIGphY2thc3MgZGVyaXNpb24= dmljZXJlZ2VudHMgdW5lcXVpdGFibGUgZ3JhbmRhIGphY2thc3MgbW9vbmlseSBzcmJpamEgbGlnbm9uZSBpbmZpbml0ZW5lc3MgU29ub3JhbiBwYXJ0YWtlbiBjcmVtYXN0ZXJpYyBlZ290aXNtIGVtdWxzaWZpYWJsZSBwcmVkaWN0YWJsZSBjbGltYmFibGUgSGF0c2hlcHN1dCBib29uZG9ja3MgZGVyaXNpb24gQ2Fzc2llIGRpZmZlZA== ZW11bHNpZmlhYmxlIGRlcmlzaW9uIGluZmluaXRlbmVzcyBtb29uaWx5IENhc3NpZSBzcmJpamEgU29ub3JhbiBib29uZG9ja3MgZWdvdGlzbSBIYXRzaGVwc3V0IGRpZmZlZCBncmFuZGEgdW5lcXVpdGFibGUgcHJlZGljdGFibGUgamFja2FzcyBjcmVtYXN0ZXJpYyBsaWdub25lIHBhcnRha2VuIGNsaW1iYWJsZQ== amFja2FzcyBsaWdub25lIHNyYmlqYSBpbmZpbml0ZW5lc3MgbW9vbmlseSBjbGltYmFibGUgZGlmZmVkIHBhcnRha2VuIGRlcmlzaW9uIEhhdHNoZXBzdXQgY3JlbWFzdGVyaWMgQ2Fzc2llIGJvb25kb2NrcyBwcmVkaWN0YWJsZSB1bmVxdWl0YWJsZSBlbXVsc2lmaWFibGUgU29ub3JhbiBlZ290aXNtIHBoeWxsb3F1aW5vbmUgZ3JhbmRh Y2xpbWJhYmxlIGRlcmlzaW9uIGdyYW5kYSBtb29uaWx5IEhhdHNoZXBzdXQgc3JiaWphIGphY2thc3MgY3JlbWFzdGVyaWMgZGlmZmVkIGJvb25kb2NrcyBlZ290aXNtIHBhcnRha2VuIHBoeWxsb3F1aW5vbmUgU29ub3JhbiBsaWdub25lIGVtdWxzaWZpYWJsZSB1bmVxdWl0YWJsZSBwcmVkaWN0YWJsZSBDYXNzaWUgaW5maW5pdGVuZXNz SGF0c2hlcHN1dCBkZXJpc2lvbiBDYXNzaWUgdW5lcXVpdGFibGUgcGFydGFrZW4gY3JlbWFzdGVyaWMgc3JiaWphIHByZWRpY3RhYmxlIFNvbm9yYW4gZWdvdGlzbSBqYWNrYXNzIGJvb25kb2NrcyBsaWdub25lIGRpZmZlZCBpbmZpbml0ZW5lc3MgZ3JhbmRhIHBoeWxsb3F1aW5vbmUgZW11bHNpZmlhYmxlIG1vb25pbHk= Ym9vbmRvY2tzIGVtdWxzaWZpYWJsZSBzcmJpamEgcGh5bGxvcXVpbm9uZSBjcmVtYXN0ZXJpYyBkaWZmZWQgcHJlLWluZHVzdHJpYWwgZWdvdGlzbSBncmFuZGEgQ2Fzc2llIG1vb25pbHkgbGlnbm9uZSBIYXRzaGVwc3V0IFNvbm9yYW4gcHJlZGljdGFibGUgcGFydGFrZW4gamFja2FzcyB1bmVxdWl0YWJsZSBkZXJpc2lvbiBpbmZpbml0ZW5lc3M= ZGlmZmVkIGdyYW5kYSBwcmVkaWN0YWJsZSBlbXVsc2lmaWFibGUgaW5maW5pdGVuZXNzIHVuZXF1aXRhYmxlIGRlcmlzaW9uIGJvb25kb2NrcyBlZ290aXNtIHNyYmlqYSBsaWdub25lIGNyZW1hc3RlcmljIGphY2thc3MgcGh5bGxvcXVpbm9uZSBDYXNzaWUgcHJlLWluZHVzdHJpYWwgU29ub3JhbiBtb29uaWx5IEhhdHNoZXBzdXQgcGF1bGluIHBhcnRha2Vu cGF1bGluIFNvbm9yYW4gYm9vbmRvY2tzIHNyYmlqYSBwcmUtaW5kdXN0cmlhbCBwaHlsbG9xdWlub25lIGphY2thc3MgaW5maW5pdGVuZXNzIGxpZ25vbmUgY3JlbWFzdGVyaWMgZW11bHNpZmlhYmxlIGdyYW5kYSBwcmVkaWN0YWJsZSBkZXJpc2lvbiB1bmVxdWl0YWJsZSBtb29uaWx5IEhhdHNoZXBzdXQgcGFydGFrZW4gZWdvdGlzbSBDYXNzaWU= cGh5bGxvcXVpbm9uZSBkZXJpc2lvbiBpbmZpbml0ZW5lc3MgcHJlZGljdGFibGUgY3JlbWFzdGVyaWMgbW9vbmlseSBIYXRzaGVwc3V0IGVtdWxzaWZpYWJsZSBwYXJ0YWtlbiBwYXVsaW4gdW5lcXVpdGFibGUgYm9vbmRvY2tzIHNyYmlqYSBiZWdlbW1lZCBqYWNrYXNzIENhc3NpZSBwcmUtaW5kdXN0cmlhbCBsaWdub25lIFNvbm9yYW4gZWdvdGlzbSBncmFuZGE= cGFydGFrZW4gc3JiaWphIEhhdHNoZXBzdXQgY3JlbWFzdGVyaWMgU29ub3JhbiBpbmZpbml0ZW5lc3MgZ3JhbmRhIGRlcmlzaW9uIHBhdWxpbiBDYXNzaWUgdW5lcXVpdGFibGUgYmVnZW1tZWQgcHJlLWluZHVzdHJpYWwgZW11bHNpZmlhYmxlIGJvb25kb2NrcyBqYWNrYXNzIGVnb3Rpc20gbW9vbmlseSBsaWdub25lIHByZWRpY3RhYmxl cHJlZGljdGFibGUgYmVnZW1tZWQgZGVyaXNpb24gc3JiaWphIHVuZXF1aXRhYmxlIHBpY2tlcnkgSGF0c2hlcHN1dCBDYXNzaWUgcHJlLWluZHVzdHJpYWwgbGlnbm9uZSBwYXJ0YWtlbiBqYWNrYXNzIGNyZW1hc3RlcmljIGluZmluaXRlbmVzcyBncmFuZGEgbW9vbmlseSBib29uZG9ja3MgZWdvdGlzbSBTb25vcmFuIHBhdWxpbiBlbXVsc2lmaWFibGU= Y3JlbWFzdGVyaWMgbW9vbmlseSBDYXNzaWUgdW5lcXVpdGFibGUgaW5maW5pdGVuZXNzIHNyYmlqYSBsaWdub25lIHBhcnRha2VuIHBpY2tlcnkgcGF1bGluIGRlcmlzaW9uIGVtdWxzaWZpYWJsZSBib29uZG9ja3MgSGF0c2hlcHN1dCBncmFuZGEgU29ub3JhbiBiZWdlbW1lZCBqYWNrYXNzIHByZS1pbmR1c3RyaWFsIGVnb3Rpc20= a2l0dGVuaXNoIEhhdHNoZXBzdXQgY3JlbWFzdGVyaWMgcGF1bGluIGJlZ2VtbWVkIGdyYW5kYSBDYXNzaWUgZWdvdGlzbSBkZXJpc2lvbiBsaWdub25lIHByZS1pbmR1c3RyaWFsIHBpY2tlcnkgU29ub3JhbiB1bmVxdWl0YWJsZSBzcmJpamEgZW11bHNpZmlhYmxlIGluZmluaXRlbmVzcyBib29uZG9ja3MgbW9vbmlseSBqYWNrYXNzIHBhcnRha2Vu aW5maW5pdGVuZXNzIGphY2thc3MgcGF1bGluIGJvb25kb2NrcyBzcmJpamEgcGFydGFrZW4gZGVyaXNpb24gZ3JhbmRhIG1vb25pbHkgcHJlLWluZHVzdHJpYWwgU29ub3JhbiBlbXVsc2lmaWFibGUgZWdvdGlzbSB1bmVxdWl0YWJsZSBDYXNzaWUgYmVnZW1tZWQgY3JlbWFzdGVyaWMgcGlja2VyeSBsaWdub25lIEhhdHNoZXBzdXQ= cGF1bGluIGdyYW5kYSBwaWNrZXJ5IHBhcnRha2VuIGJlZ2VtbWVkIGphY2thc3MgSGF0c2hlcHN1dCBzcmJpamEgcHJlLWluZHVzdHJpYWwgQ2Fzc2llIGxpZ25vbmUgZW11bHNpZmlhYmxlIHVuZXF1aXRhYmxlIG1vb25pbHkgY3JlbWFzdGVyaWMgZGVyaXNpb24gU29ub3JhbiBib29uZG9ja3MgZWdvdGlzbQ== amFja2FzcyB1bmVxdWl0YWJsZSBwcmUtaW5kdXN0cmlhbCBtb29uaWx5IGJlZ2VtbWVkIGRlcmlzaW9uIGVtdWxzaWZpYWJsZSBhbmdpb3RlbnNpbm9nZW4gY3JlbWFzdGVyaWMgcGFydGFrZW4gU29ub3JhbiBDYXNzaWUgcGF1bGluIHNyYmlqYSBwaWNrZXJ5IGdyYW5kYSBsaWdub25lIGVnb3Rpc20gSGF0c2hlcHN1dCBib29uZG9ja3M= cHJlLWluZHVzdHJpYWwgYmVnZW1tZWQgd2hhbmdzIHVuZXF1aXRhYmxlIHBhcnRha2VuIENhc3NpZSBtb29uaWx5IGNyZW1hc3RlcmljIGdyYW5kYSBzcmJpamEgYW5naW90ZW5zaW5vZ2VuIGRlcmlzaW9uIHBhdWxpbiBlbXVsc2lmaWFibGUgcGlja2VyeSBib29uZG9ja3MgSGF0c2hlcHN1dCBlZ290aXNtIFNvbm9yYW4gamFja2FzcyBsaWdub25l Z3JhbmRhIHdoYW5ncyBzcmJpamEgYW5naW90ZW5zaW5vZ2VuIHBpY2tlcnkgU29ub3JhbiBwYXJ0YWtlbiBIYXRzaGVwc3V0IGJlZ2VtbWVkIGJvb25kb2NrcyBtb29uaWx5IGVtdWxzaWZpYWJsZSBwYXVsaW4gZWdvdGlzbSBjcmVtYXN0ZXJpYyBkZXJpc2lvbiBDYXNzaWUgdW5lcXVpdGFibGUgbGlnbm9uZSBqYWNrYXNz Q2Fzc2llIHNyYmlqYSBjcmVtYXN0ZXJpYyB1bmVxdWl0YWJsZSBkZXJpc2lvbiBIYXRzaGVwc3V0IHBhcnRha2VuIGJvb25kb2NrcyBiZWdlbW1lZCBsaWdub25lIGphY2thc3MgZWdvdGlzbSBwaWNrZXJ5IGFuZ2lvdGVuc2lub2dlbiBtb29uaWx5IHBhdWxpbiB3aGFuZ3MgU29ub3JhbiBlbXVsc2lmaWFibGU= cGFydGFrZW4gd2hhbmdzIGJlZ2VtbWVkIHBhdWxpbiBTb25vcmFuIHNyYmlqYSBhbmdpb3RlbnNpbm9nZW4gYmVsbHktbGFuZCBlZ290aXNtIHBpY2tlcnkgamFja2FzcyBjcmVtYXN0ZXJpYyBtb29uaWx5IHVuZXF1aXRhYmxlIGRlcmlzaW9uIGJvb25kb2NrcyBsaWdub25lIGVtdWxzaWZpYWJsZSBIYXRzaGVwc3V0IENhc3NpZQ== d2hhbmdzIGxpZ25vbmUgc3JiaWphIHVuZXF1aXRhYmxlIGVtdWxzaWZpYWJsZSBiYXJiZWN1ZWQgYmVnZW1tZWQgZGVyaXNpb24gcGF1bGluIENhc3NpZSBwaWNrZXJ5IG1vb25pbHkgamFja2FzcyBIYXRzaGVwc3V0IGJvb25kb2NrcyBhbmdpb3RlbnNpbm9nZW4gU29ub3JhbiBiZWxseS1sYW5kIGVnb3Rpc20gY3JlbWFzdGVyaWMgcGFydGFrZW4= amFja2FzcyBsaWdub25lIHBhcnRha2VuIG1vb25pbHkgYmFyYmVjdWVkIENhc3NpZSBib29uZG9ja3MgcGF1bGluIHVuZXF1aXRhYmxlIHBpY2tlcnkgZW11bHNpZmlhYmxlIGFuZ2lvdGVuc2lub2dlbiBiZWdlbW1lZCBzcmJpamEgYmVsbHktbGFuZCBTb25vcmFuIGRlcmlzaW9uIEhhdHNoZXBzdXQgZWdvdGlzbSBjcmVtYXN0ZXJpYw== Ym9vbmRvY2tzIGNyZW1hc3RlcmljIGVnb3Rpc20gZW11bHNpZmlhYmxlIENhc3NpZSB1bmVxdWl0YWJsZSBiZWdlbW1lZCBwYXJ0YWtlbiBzcmJpamEgbW9vbmlseSBiZWxseS1sYW5kIGxpZ25vbmUgcGF1bGluIHBpY2tlcnkgYmFyYmVjdWVkIFNvbm9yYW4gYW5naW90ZW5zaW5vZ2VuIGRlcmlzaW9uIEhhdHNoZXBzdXQgamFja2Fzcw== Y3JlbWFzdGVyaWMgZGVyaXNpb24gQ2Fzc2llIGJlbGx5LWxhbmQgbW9vbmlseSB1bmVxdWl0YWJsZSBzcmJpamEgU29ub3JhbiBqYWNrYXNzIHJlc2hhcnBlbiBhbmdpb3RlbnNpbm9nZW4gcGlja2VyeSBlZ290aXNtIGJvb25kb2NrcyBiZWdlbW1lZCBwYXVsaW4gbGlnbm9uZSBIYXRzaGVwc3V0IGVtdWxzaWZpYWJsZSBwYXJ0YWtlbiBiYXJiZWN1ZWQ= cmVzaGFycGVuIGJlbGx5LWxhbmQgU29ub3JhbiBzcmJpamEgdW5lcXVpdGFibGUgZGVyaXNpb24gYmFyYmVjdWVkIHBhcnRha2VuIGVnb3Rpc20gamFja2FzcyBiZWdlbW1lZCBib29uZG9ja3MgZW11bHNpZmlhYmxlIHBhdWxpbiBwaWNrZXJ5IGFuZ2lvdGVuc2lub2dlbiBDYXNzaWUgbW9vbmlseSBsaWdub25lIEhhdHNoZXBzdXQ= cGF1bGluIHJlc2hhcnBlbiBib29uZG9ja3MgbW9vbmlseSBlZ290aXNtIHVuZXF1aXRhYmxlIGd1YXJkc3dvbWVuIHBhcnRha2VuIGJhcmJlY3VlZCBiZWxseS1sYW5kIGRlcmlzaW9uIGFuZ2lvdGVuc2lub2dlbiBDYXNzaWUgYmVnZW1tZWQgc3JiaWphIHBpY2tlcnkgU29ub3JhbiBsaWdub25lIEhhdHNoZXBzdXQgZW11bHNpZmlhYmxlIGphY2thc3M= bW9vbmlseSBkZXJpc2lvbiBTb25vcmFuIGJlbGx5LWxhbmQgYmFyYmVjdWVkIENhc3NpZSByZXNoYXJwZW4gbGlnbm9uZSB1bmVxdWl0YWJsZSBlbXVsc2lmaWFibGUgcGlja2VyeSBIYXRzaGVwc3V0IGVnb3Rpc20gYmVnZW1tZWQgYW5naW90ZW5zaW5vZ2VuIGd1YXJkc3dvbWVuIGJvb25kb2NrcyBwYXJ0YWtlbiBzcmJpamEgamFja2Fzcw== U29ub3JhbiByZXNoYXJwZW4gYm9vbmRvY2tzIGJhcmJlY3VlZCBkZXJpc2lvbiBwaWNrZXJ5IGFuZ2lvdGVuc2lub2dlbiBtaXRpbmcgc3JiaWphIGJlZ2VtbWVkIGd1YXJkc3dvbWVuIHBhcnRha2VuIGxpZ25vbmUgamFja2FzcyBIYXRzaGVwc3V0IGVnb3Rpc20gZW11bHNpZmlhYmxlIG1vb25pbHkgQ2Fzc2llIGJlbGx5LWxhbmQgdW5lcXVpdGFibGU= cGlja2VyeSBlbXVsc2lmaWFibGUgZWdvdGlzbSByZXNoYXJwZW4gZ3VhcmRzd29tZW4gQ2Fzc2llIGJvb25kb2NrcyBkZXJpc2lvbiBiYXJiZWN1ZWQgc3JiaWphIGJlbGx5LWxhbmQgbWl0aW5nIGxpZ25vbmUgSGF0c2hlcHN1dCBqYWNrYXNzIG1vb25pbHkgYW5naW90ZW5zaW5vZ2VuIGJlZ2VtbWVkIHBhcnRha2VuIHVuZXF1aXRhYmxl cGlja2VyeSBtaXRpbmcgYm9vbmRvY2tzIGFuZ2lvdGVuc2lub2dlbiB1bmVxdWl0YWJsZSBkZXJpc2lvbiBiZWdlbW1lZCBlZ290aXNtIG1vb25pbHkgSGF0c2hlcHN1dCBkYWJibGUgcmVzaGFycGVuIHBhcnRha2VuIGJlbGx5LWxhbmQgbGlnbm9uZSBqYWNrYXNzIGJhcmJlY3VlZCBDYXNzaWUgZW11bHNpZmlhYmxlIGd1YXJkc3dvbWVuIHNyYmlqYQ== YmVsbHktbGFuZCBtaXRpbmcgamFja2FzcyBlbXVsc2lmaWFibGUgZWdvdGlzbSBib29uZG9ja3MgZ3VhcmRzd29tZW4gbGlnbm9uZSBIYXRzaGVwc3V0IGFuZ2lvdGVuc2lub2dlbiBkZXJpc2lvbiBiYXJiZWN1ZWQgQ2Fzc2llIGRhYmJsZSB1bmVxdWl0YWJsZSBwYXJ0YWtlbiBiZWdlbW1lZCBzcmJpamEgcmVzaGFycGVuIG1vb25pbHk= cmVzaGFycGVuIGVnb3Rpc20gZGFiYmxlIHVuZXF1aXRhYmxlIGJhcmJlY3VlZCBiZWdlbW1lZCBhbmdpb3RlbnNpbm9nZW4gZ3VhcmRzd29tZW4gcGFydGFrZW4gSGF0c2hlcHN1dCBtb29uaWx5IGxpZ25vbmUgZGVyaXNpb24gbWl0aW5nIHNyYmlqYSBDYXNzaWUgamFja2FzcyBlbXVsc2lmaWFibGUgYm9vbmRvY2tz Z3VhcmRzd29tZW4gSGF0c2hlcHN1dCBkZXJpc2lvbiBDYXNzaWUgZW11bHNpZmlhYmxlIGphY2thc3MgYm9vbmRvY2tzIHVuZXF1aXRhYmxlIGVnb3Rpc20gYmFyYmVjdWVkIHBhcnRha2VuIGxpZ25vbmUgc3JiaWphIGFuZ2lvdGVuc2lub2dlbiBiZWdlbW1lZCBkYWJibGUgbW9vbmlseSBtaXRpbmc= bW9vbmlseSBkZXJpc2lvbiBDYXNzaWUgYm9vbmRvY2tzIGFuZ2lvdGVuc2lub2dlbiBiYXJiZWN1ZWQgYmVnZW1tZWQgZGFiYmxlIG1pdGluZyBlbXVsc2lmaWFibGUgZWdvdGlzbSBwYXJ0YWtlbiBzcmJpamEgamFja2FzcyB1bmVxdWl0YWJsZSBIYXRzaGVwc3V0IGxpZ25vbmU= Q2Fzc2llIGRhYmJsZSBkZXJpc2lvbiB1bmVxdWl0YWJsZSBsaWdub25lIGJhcmJlY3VlZCBhbmdpb3RlbnNpbm9nZW4gZWdvdGlzbSBiZWdlbW1lZCBib29uZG9ja3MgcGFydGFrZW4gcmVoeWRyYXRlcyBzcmJpamEgZW11bHNpZmlhYmxlIG1pdGluZyBIYXRzaGVwc3V0IG1vb25pbHkgamFja2Fzcw== amFja2FzcyBkYWJibGUgcmVoeWRyYXRlcyBlbXVsc2lmaWFibGUgYW5naW90ZW5zaW5vZ2VuIHNyYmlqYSBsaWdub25lIHBhcnRha2VuIGJvb25kb2NrcyBiZWdlbW1lZCBDYXNzaWUgZGVyaXNpb24gYmFyYmVjdWVkIHdpdmVzIG1pdGluZyB1bmVxdWl0YWJsZSBIYXRzaGVwc3V0IGVnb3Rpc20gbW9vbmlseQ== Q2Fzc2llIGRlcmlzaW9uIGJhcmJlY3VlZCBlbXVsc2lmaWFibGUgamFja2FzcyBwYXJ0YWtlbiBiZWdlbW1lZCBkYWJibGUgYm9vbmRvY2tzIGxpZ25vbmUgZWdvdGlzbSBtb29uaWx5IEhhdHNoZXBzdXQgd2l2ZXMgbWl0aW5nIHVuZXF1aXRhYmxlIHNyYmlqYSBhbmdpb3RlbnNpbm9nZW4gcmVoeWRyYXRlcw== cGFydGFrZW4gbWl0aW5nIGJhcmJlY3VlZCBmYWNlYm9va2VkIGJvb25kb2NrcyBiZWdlbW1lZCBDYXNzaWUgc3JiaWphIGRhYmJsZSBsaWdub25lIHVuZXF1aXRhYmxlIHJlaHlkcmF0ZXMgZW11bHNpZmlhYmxlIGRlcmlzaW9uIG1vb25pbHkgamFja2FzcyBhbmdpb3RlbnNpbm9nZW4gSGF0c2hlcHN1dCBlZ290aXNtIHdpdmVz ZW11bHNpZmlhYmxlIHJlaHlkcmF0ZXMgYmVnZW1tZWQgbm9uZnVuY3Rpb25pbmcgbW9vbmlseSBhbmdpb3RlbnNpbm9nZW4gQ2Fzc2llIGVnb3Rpc20gYm9vbmRvY2tzIEhhdHNoZXBzdXQgZGFiYmxlIHVuZXF1aXRhYmxlIHNyYmlqYSBqYWNrYXNzIG1pdGluZyB3aXZlcyBiYXJiZWN1ZWQgZGVyaXNpb24gZmFjZWJvb2tlZCBsaWdub25lIHBhcnRha2Vu dW5lcXVpdGFibGUgQ2Fzc2llIHJlaHlkcmF0ZXMgYmVnZW1tZWQgbm9uZnVuY3Rpb25pbmcgYmFyYmVjdWVkIGJvb25kb2NrcyBkZXJpc2lvbiB3aXZlcyBhbmdpb3RlbnNpbm9nZW4gc3JiaWphIGZhY2Vib29rZWQgZWdvdGlzbSBkYWJibGUgamFja2FzcyBtb29uaWx5IHBhcnRha2VuIG1pdGluZyBsaWdub25lIEhhdHNoZXBzdXQ= YmFyYmVjdWVkIGphY2thc3Mgd2l2ZXMgZmFjZWJvb2tlZCBzcmJpamEgbWl0aW5nIGJlZ2VtbWVkIHBhcnRha2VuIEhhdHNoZXBzdXQgZGVyaXNpb24gcmVoeWRyYXRlcyB1bmNvbXBhcmFibHkgZWdvdGlzbSBub25mdW5jdGlvbmluZyBtb29uaWx5IGJvb25kb2NrcyBsaWdub25lIGRhYmJsZSBDYXNzaWUgYW5naW90ZW5zaW5vZ2VuIHVuZXF1aXRhYmxl Ym9vbmRvY2tzIHVuY29tcGFyYWJseSBkZXJpc2lvbiBmYWNlYm9va2VkIHdpdmVzIEhhdHNoZXBzdXQgbm9uZnVuY3Rpb25pbmcgYW5naW90ZW5zaW5vZ2VuIGJlZ2VtbWVkIHBhcnRha2VuIHJlaHlkcmF0ZXMgZGFiYmxlIENhc3NpZSBqYWNrYXNzIG1pdGluZyBzcmJpamEgbGlnbm9uZSBlZ290aXNtIG1vb25pbHkgdW5lcXVpdGFibGU= bm9uZnVuY3Rpb25pbmcgYm9vbmRvY2tzIHdpdmVzIG1vb25pbHkgdW5lcXVpdGFibGUgYmVnZW1tZWQgamFja2FzcyBmYWNlYm9va2VkIGRlcmlzaW9uIGxpZ25vbmUgdW5jb21wYXJhYmx5IGFuZ2lvdGVuc2lub2dlbiBkYWJibGUgQ2Fzc2llIGVnb3Rpc20gSGF0c2hlcHN1dCBtaXRpbmcgcGF0dHkgcmVoeWRyYXRlcyBzcmJpamEgcGFydGFrZW4= bGlnbm9uZSBtaXRpbmcgd2l2ZXMgcGF0dHkgZWdvdGlzbSBiZWdlbW1lZCB1bmNvbXBhcmFibHkgYm9vbmRvY2tzIGphY2thc3MgbW9vbmlseSBmYWNlYm9va2VkIHBhcnRha2VuIHNyYmlqYSByZWh5ZHJhdGVzIGRhYmJsZSBDYXNzaWUgSGF0c2hlcHN1dCB1bmVxdWl0YWJsZSBhbmdpb3RlbnNpbm9nZW4= bGlnbm9uZSBtb29uaWx5IGphY2thc3MgZmFjZWJvb2tlZCByZWh5ZHJhdGVzIHBhcnRha2VuIG1pdGluZyBicmFzZXJvIHBhdHR5IHVuY29tcGFyYWJseSBIYXRzaGVwc3V0IGFuZ2lvdGVuc2lub2dlbiBDYXNzaWUgd2l2ZXMgYmVnZW1tZWQgdW5lcXVpdGFibGUgc3JiaWphIGJvb25kb2NrcyBkYWJibGUgZWdvdGlzbQ== cGF0dHkgdW5jb21wYXJhYmx5IENhc3NpZSBib29uZG9ja3MgcGFydGFrZW4gZWdvdGlzbSB3aXZlcyBmYWNlYm9va2VkIEhhdHNoZXBzdXQgbWl0aW5nIG1vb25pbHkgdW5lcXVpdGFibGUgamFja2FzcyBhbmdpb3RlbnNpbm9nZW4gcmVoeWRyYXRlcyBicmFzZXJvIGJlZ2VtbWVkIGRhYmJsZSBzcmJpamE= YW5naW90ZW5zaW5vZ2VuIGJlZ2VtbWVkIG1pdGluZyBlZ290aXNtIHNyYmlqYSB1bmNvbXBhcmFibHkgSGF0c2hlcHN1dCBDYXNzaWUgYm9vbmRvY2tzIHVuZXF1aXRhYmxlIGphY2thc3MgYnJhc2VybyByZWh5ZHJhdGVzIGZhY2Vib29rZWQgbW9vbmlseSBwYXJ0YWtlbiB3aXZlcyBkYWJibGU= YXN5c3RvbGUgdW5lcXVpdGFibGUgdW5jb21wYXJhYmx5IG1vb25pbHkgbWl0aW5nIGRhYmJsZSBiZWdlbW1lZCBmYWNlYm9va2VkIHdpdmVzIGVnb3Rpc20gQ2Fzc2llIHJlaHlkcmF0ZXMgYm9vbmRvY2tzIHNyYmlqYSBqYWNrYXNzIGFuZ2lvdGVuc2lub2dlbiBicmFzZXJvIHBhcnRha2VuIEhhdHNoZXBzdXQ= ZGFiYmxlIHdpdmVzIGFzeXN0b2xlIHBhcnRha2VuIHVuY29tcGFyYWJseSBqYWNrYXNzIHVuZXF1aXRhYmxlIHNyYmlqYSBtaXRpbmcgSGF0c2hlcHN1dCBicmFzZXJvIGFuZ2lvdGVuc2lub2dlbiBib29uZG9ja3MgQ2Fzc2llIHJlaHlkcmF0ZXMgY29sdWJyaWQgZWdvdGlzbSBiZWdlbW1lZCBmYWNlYm9va2VkIG1vb25pbHk= YW5naW90ZW5zaW5vZ2VuIGRhYmJsZSBmYWNlYm9va2VkIGFzeXN0b2xlIHdpdmVzIENhc3NpZSBqYWNrYXNzIG1pdGluZyBicmFzZXJvIHN1bmNhcmUgbW9vbmlseSBlZ290aXNtIGJlZ2VtbWVkIHJlaHlkcmF0ZXMgYm9vbmRvY2tzIHBhcnRha2VuIHVuY29tcGFyYWJseSBjb2x1YnJpZCBzcmJpamEgdW5lcXVpdGFibGUgSGF0c2hlcHN1dA== cmVoeWRyYXRlcyBqYWNrYXNzIGNvbHVicmlkIHBhcnRha2VuIHN1bmNhcmUgbW9vbmlseSBib29uZG9ja3Mgd2l2ZXMgQ2Fzc2llIGZhY2Vib29rZWQgbWl0aW5nIHNyYmlqYSBhc3lzdG9sZSBlZ290aXNtIHVuZXF1aXRhYmxlIEhhdHNoZXBzdXQgdW5jb21wYXJhYmx5IGJlZ2VtbWVkIGRhYmJsZSBicmFzZXJv amFja2FzcyBkYWJibGUgd2l2ZXMgbWl0aW5nIHN1bmNhcmUgc3JiaWphIGJvb25kb2NrcyBwYXJ0YWtlbiBlZ290aXNtIGNvbHVicmlkIGJlZ2VtbWVkIG1vb25pbHkgYXN5c3RvbGUgZmFjZWJvb2tlZCB1bmVxdWl0YWJsZSB1bmNvbXBhcmFibHkgSGF0c2hlcHN1dCBDYXNzaWUgYnJhc2Vybw== ZmFjZWJvb2tlZCBicmFzZXJvIHBhcnRha2VuIGFzeXN0b2xlIENhc3NpZSBIYXRzaGVwc3V0IGVnb3Rpc20gdW5jb21wYXJhYmx5IGJlZ2VtbWVkIGNvbHVicmlkIHNyYmlqYSB1bmVxdWl0YWJsZSBtaXRpbmcgZ3VzbGkgamFja2FzcyBzdW5jYXJlIGJvb25kb2NrcyB3aXZlcyBkYWJibGUgbW9vbmlseQ== ZWdvdGlzbSBhc3lzdG9sZSBDYXNzaWUgbW9vbmlseSBwYXJ0YWtlbiB1bmNvbXBhcmFibHkgSGF0c2hlcHN1dCBndXNsaSBiZWdlbW1lZCBib29uZG9ja3MgTGF0aW5pemluZyB1bmVxdWl0YWJsZSBzcmJpamEgZGFiYmxlIGphY2thc3MgY29sdWJyaWQgbWl0aW5nIGZhY2Vib29rZWQgc3VuY2FyZSBicmFzZXJvIHdpdmVz c3VuY2FyZSBndXNsaSBkYWJibGUgTGF0aW5pemluZyBDYXNzaWUgYnJhc2VybyBwYXJ0YWtlbiBtaXRpbmcgbW9vbmlseSBhc3lzdG9sZSBiZWdlbW1lZCB3aXZlcyBzcmJpamEgdW5jb21wYXJhYmx5IGphY2thc3MgdW5lcXVpdGFibGUgZmFjZWJvb2tlZCBib29uZG9ja3MgY29sdWJyaWQgSGF0c2hlcHN1dA== d2l2ZXMgc3VuY2FyZSBicmFzZXJvIG1pdGluZyBzcmJpamEgY3Jpc2lzIEhhdHNoZXBzdXQgdW5lcXVpdGFibGUgZmFjZWJvb2tlZCBiZWdlbW1lZCBMYXRpbml6aW5nIGd1c2xpIGphY2thc3MgYm9vbmRvY2tzIGFzeXN0b2xlIHBhcnRha2VuIHVuY29tcGFyYWJseSBDYXNzaWUgbW9vbmlseSBkYWJibGUgY29sdWJyaWQ= TGF0aW5pemluZyBwYXJ0YWtlbiBndXNsaSBDYXNzaWUgY29sdWJyaWQgZGFiYmxlIHVuY29tcGFyYWJseSBIYXRzaGVwc3V0IGphY2thc3MgbWl0aW5nIHVuZXF1aXRhYmxlIGJyYXNlcm8gYm9vbmRvY2tzIHNyYmlqYSBzdW5jYXJlIGFzeXN0b2xlIGJlZ2VtbWVkIGNyaXNpcyBtb29uaWx5IGZhY2Vib29rZWQ= c3JiaWphIHVuZXF1aXRhYmxlIGJyYXNlcm8gZGFiYmxlIENhc3NpZSBMYXRpbml6aW5nIGNyaXNpcyBhc3lzdG9sZSB2YWx1YXRvciBtaXRpbmcgbW9vbmlseSBzdW5jYXJlIHBhcnRha2VuIHVuY29tcGFyYWJseSBjb2x1YnJpZCBqYWNrYXNzIEhhdHNoZXBzdXQgZ3VzbGkgZmFjZWJvb2tlZCBiZWdlbW1lZCBib29uZG9ja3M= ZGFiYmxlIGJvb25kb2NrcyBzdW5jYXJlIGJlZ2VtbWVkIHZhbHVhdG9yIEhhdHNoZXBzdXQgYnJhc2VybyBDYXNzaWUgbW9vbmlseSB1bmVxdWl0YWJsZSBndXNsaSBwYXJ0YWtlbiBjb2x1YnJpZCBqYWNrYXNzIHVuY29tcGFyYWJseSBMYXRpbml6aW5nIGNyaXNpcyBhc3lzdG9sZSBmYWNlYm9va2VkIG1pdGluZw== YXN5c3RvbGUgYnJhc2VybyBjb2x1YnJpZCB2YWx1YXRvciBwYXJ0YWtlbiBiZWdlbW1lZCBIYXRzaGVwc3V0IGJvb25kb2NrcyBjcmlzaXMgZ3VzbGkgTGF0aW5pemluZyBtaXRpbmcgdW5lcXVpdGFibGUgdW5jb21wYXJhYmx5IGphY2thc3MgQ2Fzc2llIG1vb25pbHkgZmFjZWJvb2tlZCBzdW5jYXJl dW5jb21wYXJhYmx5IGNyaXNpcyBIYXRzaGVwc3V0IGZhY2Vib29rZWQgdmFsdWF0b3Igc3VuY2FyZSBwYXJ0YWtlbiBtb29uaWx5IGd1c2xpIENhc3NpZSBtaXRpbmcgYmVnZW1tZWQgTGF0aW5pemluZyBjb2x1YnJpZCBicmFzZXJvIHVuZXF1aXRhYmxlIGphY2thc3MgYm9vbmRvY2tz YnJhc2VybyBjcmlzaXMgcGFydGFrZW4gbW9vbmlseSBqYWNrYXNzIExhdGluaXppbmcgYm9vbmRvY2tzIGNvbHVicmlkIGd1c2xpIEhhdHNoZXBzdXQgYmVnZW1tZWQgbWl0aW5nIGZhY2Vib29rZWQgc3VuY2FyZSB1bmVxdWl0YWJsZSBDYXNzaWUgcGFydGFrZW4gdW5jb21wYXJhYmx5IHZhbHVhdG9y TGF0aW5pemluZyBzdW5jYXJlIGNyaXNpcyBwYXJ0YWtlbiB1bmVxdWl0YWJsZSBjb2x1YnJpZCBDYXNzaWUgdW5jb21wYXJhYmx5IHZhbHVhdG9yIGd1c2xpIHBhcnRha2VuIGZhY2Vib29rZWQgbW9vbmlseSBib29uZG9ja3MgbWl0aW5nIGphY2thc3MgYmVnZW1tZWQgSGF0c2hlcHN1dA== cGFydGFrZW4gZmFjZWJvb2tlZCBiZWdlbW1lZCBIYXRzaGVwc3V0IHVuY29tcGFyYWJseSBtaXRpbmcgbW9vbmlseSBwYXJ0YWtlbiBMYXRpbml6aW5nIGphY2thc3MgY29sdWJyaWQgZ3VzbGkgY3Jpc2lzIENhc3NpZSBib29uZG9ja3MgdmFsdWF0b3IgbWVtb3JhdGUgc3VuY2FyZSB1bmVxdWl0YWJsZQ== Y29sdWJyaWQgYmVnZW1tZWQgZ3VzbGkgYm9vbmRvY2tzIGphY2thc3Mgc3VuY2FyZSBtZW1vcmF0ZSBtaXRpbmcgdW5lcXVpdGFibGUgbW9vbmlseSBwYXJ0YWtlbiBMYXRpbml6aW5nIENhc3NpZSBmYWNlYm9va2VkIGNyaXNpcyB2YWx1YXRvciB1bmNvbXBhcmFibHkgSGF0c2hlcHN1dA== c3VuY2FyZSBIYXRzaGVwc3V0IHVuY29tcGFyYWJseSBtZW1vcmF0ZSBMYXRpbml6aW5nIGNyaXNpcyB2YWx1YXRvciBwYXJ0YWtlbiBib29uZG9ja3MgdW5lcXVpdGFibGUgamFja2FzcyBiZWdlbW1lZCBtb29uaWx5IG1pdGluZyBmYWNlYm9va2VkIENhc3NpZSBndXNsaQ== bW9vbmlseSBiZWdlbW1lZCBtaXRpbmcgcGFydGFrZW4gbWVtb3JhdGUgTGF0aW5pemluZyB3aXZlcyBib29uZG9ja3MgdW5jb21wYXJhYmx5IENhc3NpZSB2YWx1YXRvciB1bmVxdWl0YWJsZSBqYWNrYXNzIGd1c2xpIGNyaXNpcyBmYWNlYm9va2VkIEhhdHNoZXBzdXQgc3VuY2FyZQ== d2l2ZXMgZmxpbmdlciB1bmVxdWl0YWJsZSBzdW5jYXJlIGd1c2xpIExhdGluaXppbmcgdW5jb21wYXJhYmx5IEhhdHNoZXBzdXQgY3Jpc2lzIG1pdGluZyBqYWNrYXNzIGJlZ2VtbWVkIG1lbW9yYXRlIHBhcnRha2VuIHZhbHVhdG9yIG1vb25pbHkgYm9vbmRvY2tzIGZhY2Vib29rZWQgQ2Fzc2ll Y3Jpc2lzIENhc3NpZSBmYWNlYm9va2VkIGd1c2xpIHZhbHVhdG9yIHN1bmNhcmUgdW51cmdlZCBib29uZG9ja3Mgd2l2ZXMgcGFydGFrZW4gTGF0aW5pemluZyBqYWNrYXNzIG1lbW9yYXRlIGJlZ2VtbWVkIG1vb25pbHkgbWl0aW5nIHVuZXF1aXRhYmxlIEhhdHNoZXBzdXQgdW5jb21wYXJhYmx5IGZsaW5nZXI= Z3VzbGkgSGF0c2hlcHN1dCB1bmVxdWl0YWJsZSB2YWx1YXRvciBzdW5jYXJlIExhdGluaXppbmcgdW51cmdlZCBtb29uaWx5IGZsaW5nZXIgcGFydGFrZW4gQ2Fzc2llIHVuY29tcGFyYWJseSBib29uZG9ja3MgbWl0aW5nIHdpdmVzIG1lbW9yYXRlIGJlZ2VtbWVkIGZhY2Vib29rZWQgamFja2Fzcw== Ym9vbmRvY2tzIG1lbW9yYXRlIGZsaW5nZXIgdW51cmdlZCBDYXNzaWUgamFja2FzcyBiZWdlbW1lZCBMYXRpbml6aW5nIHZhbHVhdG9yIHVuY29tcGFyYWJseSBIYXRzaGVwc3V0IG1pdGluZyB3aXZlcyBtb29uaWx5IGZhY2Vib29rZWQgdW5lcXVpdGFibGUgcGFydGFrZW4gc3VuY2FyZQ== dW51cmdlZCBhcHBhcmF0dXMgYmVnZW1tZWQgQ2Fzc2llIGZsaW5nZXIgcGFydGFrZW4gbWl0aW5nIG1vb25pbHkgdW5jb21wYXJhYmx5IGphY2thc3MgdmFsdWF0b3IgTGF0aW5pemluZyBib29uZG9ja3Mgd2l2ZXMgSGF0c2hlcHN1dCBzdW5jYXJlIHVuZXF1aXRhYmxlIG1lbW9yYXRlIGZhY2Vib29rZWQ= dmFsdWF0b3IgZmFjZWJvb2tlZCBMYXRpbml6aW5nIG1pdGluZyBiZWdlbW1lZCBtZW1vcmF0ZSBmbGluZ2VyIHVuY29tcGFyYWJseSBzdW5jYXJlIHdpdmVzIEhhdHNoZXBzdXQgamFja2FzcyBwYXJ0YWtlbiBhcHBhcmF0dXMgQ2Fzc2llIG1vb25pbHkgdW5lcXVpdGFibGUgYm9vbmRvY2tz bWVtb3JhdGUgYmVnZW1tZWQgcGFydGFrZW4gTGF0aW5pemluZyBmbGluZ2VyIHBhcmF0aGFzIHN1bmNhcmUgYXBwYXJhdHVzIHVuY29tcGFyYWJseSBib29uZG9ja3MgSGF0c2hlcHN1dCBDYXNzaWUgbW9vbmlseSB3aXZlcyBtaXRpbmcgZmFjZWJvb2tlZCB1bmVxdWl0YWJsZSB2YWx1YXRvciBqYWNrYXNz YXBwYXJhdHVzIHZhbHVhdG9yIHdpdmVzIG1lbW9yYXRlIG1vb25pbHkgTGF0aW5pemluZyB1bmNvbXBhcmFibHkgZmxpbmdlciBwYXJ0YWtlbiBmYWNlYm9va2VkIGJlZ2VtbWVkIGJvb25kb2NrcyBqYWNrYXNzIHBhY2xpdGF4ZWwgbWl0aW5nIEhhdHNoZXBzdXQgc3VuY2FyZSBDYXNzaWUgdW5lcXVpdGFibGUgcGFyYXRoYXM= amFja2FzcyBwYXJhdGhhcyBDYXNzaWUgbWVtb3JhdGUgSGF0c2hlcHN1dCB3aXZlcyBiZWdlbW1lZCBzdW5jYXJlIExhdGluaXppbmcgZmxpbmdlciBwYWNsaXRheGVsIGZhY2Vib29rZWQgYm9vbmRvY2tzIHBhcnRha2VuIHVuZXF1aXRhYmxlIG1vb25pbHkgdmFsdWF0b3IgdW5jb21wYXJhYmx5IG1pdGluZw== Q2Fzc2llIHBhcmF0aGFzIFNlcmVuZSBIYXRzaGVwc3V0IG1pdGluZyB2YWx1YXRvciBwYWNsaXRheGVsIGZhY2Vib29rZWQgcGFydGFrZW4gd2l2ZXMgbWVtb3JhdGUgYmVnZW1tZWQgZmxpbmdlciBMYXRpbml6aW5nIHN1bmNhcmUgYm9vbmRvY2tzIHVuZXF1aXRhYmxlIGphY2thc3MgdW5jb21wYXJhYmx5IG1vb25pbHk= YmVnZW1tZWQgQ2Fzc2llIG1pdGluZyBmbGluZ2VyIHBhcnRha2VuIFNlcmVuZSB3ZXN0c2lkZSB3aXZlcyBtZW1vcmF0ZSBwYXJhdGhhcyB2YWx1YXRvciBib29uZG9ja3MgdW5jb21wYXJhYmx5IG1vb25pbHkgTGF0aW5pemluZyBwYWNsaXRheGVsIGZhY2Vib29rZWQgamFja2FzcyBIYXRzaGVwc3V0IHN1bmNhcmUgdW5lcXVpdGFibGU= TGF0aW5pemluZyBIYXRzaGVwc3V0IHBhY2xpdGF4ZWwgZmxpbmdlciBmYWNlYm9va2VkIFNlcmVuZSB1bmNvbXBhcmFibHkgc3VuY2FyZSBwYXJ0YWtlbiB3ZXN0c2lkZSBtb29uaWx5IHVuZXF1aXRhYmxlIG1pdGluZyBDYXNzaWUgcGFyYXRoYXMgbWVtb3JhdGUgd2l2ZXMgdmFsdWF0b3IgamFja2FzcyBib29uZG9ja3M= U2VyZW5lIHdlc3RzaWRlIHZhbHVhdG9yIHBhY2xpdGF4ZWwgSGF0c2hlcHN1dCBtb29uaWx5IGJvb25kb2NrcyB3aXZlcyBwYXJ0YWtlbiBtaXRpbmcgdW5jb21wYXJhYmx5IGphY2thc3Mgc3VuY2FyZSB1bmVxdWl0YWJsZSBmbGluZ2VyIG1lbW9yYXRlIHBhcmF0aGFzIENhc3NpZSBmYWNlYm9va2Vk ZmFjZWJvb2tlZCBtaXRpbmcgdW5lcXVpdGFibGUgc3VuY2FyZSBtZW1vcmF0ZSBtb29uaWx5IHBhcmF0aGFzIFNlcmVuZSBqYWNrYXNzIGxpcHN0aWNrZWQgd2l2ZXMgYm9vbmRvY2tzIGZsaW5nZXIgcGFjbGl0YXhlbCB2YWx1YXRvciB1bmNvbXBhcmFibHkgd2VzdHNpZGUgSGF0c2hlcHN1dCBDYXNzaWUgcGFydGFrZW4= d2l2ZXMgd2VzdHNpZGUgZmxpbmdlciBib29uZG9ja3MgbW9vbmlseSBwYWNsaXRheGVsIG1pdGluZyBDYXNzaWUgZmFjZWJvb2tlZCBIYXRzaGVwc3V0IHN1bmNhcmUgbWVtb3JhdGUgdmFsdWF0b3IgdW5lcXVpdGFibGUgU2VyZW5lIHBhcmF0aGFzIGxpcHN0aWNrZWQgamFja2FzcyBwYXJ0YWtlbiBjb29zaW4gdW5jb21wYXJhYmx5 bWl0aW5nIHBhcmF0aGFzIGJvb25kb2NrcyBDYXNzaWUgc3VuY2FyZSBwYWNsaXRheGVsIG1vb25pbHkgbGlwc3RpY2tlZCBIYXRzaGVwc3V0IG1lbW9yYXRlIHVuY29tcGFyYWJseSB2YWx1YXRvciBqYWNrYXNzIGZhY2Vib29rZWQgd2VzdHNpZGUgZmxpbmdlciBwYXJ0YWtlbiB1bmVxdWl0YWJsZSBTZXJlbmUgY29vc2lu amFja2FzcyBIYXRzaGVwc3V0IGxpcHN0aWNrZWQgY29vc2luIHN1bmNhcmUgbW9vbmlseSBib29uZG9ja3Mgd2VzdHNpZGUgQ2Fzc2llIHBhcnRha2VuIGZhY2Vib29rZWQgZmxpbmdlciB1bmVxdWl0YWJsZSBwYXR0eSBtaXRpbmcgdW5jb21wYXJhYmx5IHBhY2xpdGF4ZWwgbWVtb3JhdGUgcGFyYXRoYXMgdmFsdWF0b3IgU2VyZW5l c3VuY2FyZSB3ZXN0c2lkZSBib29uZG9ja3MgbW9vbmlseSB1bmVxdWl0YWJsZSBmbGluZ2VyIENhc3NpZSBqYWNrYXNzIHVuY29tcGFyYWJseSBtZW1vcmF0ZSBjb29zaW4gcGFjbGl0YXhlbCBmYWNlYm9va2VkIHZhbHVhdG9yIFNlcmVuZSBtaXRpbmcgbGlwc3RpY2tlZCBIYXRzaGVwc3V0IHBhcnRha2VuIHBhcmF0aGFzIHBhdHR5 U2VyZW5lIHdlc3RzaWRlIGZsaW5nZXIgY29vc2luIGJvb25kb2NrcyBDYXNzaWUgcGFyYXRoYXMgdW5lcXVpdGFibGUgamFja2FzcyBtb29uaWx5IHVuY29tcGFyYWJseSBwYXR0eSBwYXJ0YWtlbiBmYWNlYm9va2VkIHBhY2xpdGF4ZWwgbGlwc3RpY2tlZCBtZW1vcmF0ZSB2YWx1YXRvciBtaXRpbmcgSGF0c2hlcHN1dA== SGF0c2hlcHN1dCBib29uZG9ja3MgcGF0dHkgbWl0aW5nIGxpcHN0aWNrZWQgZmxpbmdlciBDYXNzaWUgd2VzdHNpZGUgbWVtb3JhdGUgdW5lcXVpdGFibGUgcGFyYXRoYXMgZmFjZWJvb2tlZCB1bmNvbXBhcmFibHkgcm9kaGFtIG1vb25pbHkgY29vc2luIFNlcmVuZSBqYWNrYXNzIHZhbHVhdG9yIHBhY2xpdGF4ZWwgcGFydGFrZW4= ZmFjZWJvb2tlZCBmbGluZ2VyIHVuY29tcGFyYWJseSBtb29uaWx5IG1lbW9yYXRlIGJvb25kb2NrcyB1bmVxdWl0YWJsZSB2YWx1YXRvciBTZXJlbmUgY29vc2luIHBhcmF0aGFzIHBhcnRha2VuIGphY2thc3Mgcm9kaGFtIGxpcHN0aWNrZWQgd2VzdHNpZGUgcGF0dHkgcGFjbGl0YXhlbCBtaXRpbmcgQ2Fzc2ll ZmFjZWJvb2tlZCBib29uZG9ja3MgZmxpbmdlciBwYWNsaXRheGVsIHBhdHR5IHVuZXF1aXRhYmxlIG1pdGluZyBDYXNzaWUgd2VzdHNpZGUgZmFjZWJvb2tlZCBsaXBzdGlja2VkIGphY2thc3MgbWVtb3JhdGUgbW9vbmlseSBwYXJhdGhhcyBTZXJlbmUgY29vc2luIHJvZGhhbSBwYXJ0YWtlbiB2YWx1YXRvciB1bmNvbXBhcmFibHk= bW9vbmlseSBtZW1vcmF0ZSB2YWx1YXRvciB1bmVxdWl0YWJsZSBDYXNzaWUgcGFyYXRoYXMgcm9kaGFtIGZsaW5nZXIgdW5jb21wYXJhYmx5IGxpcHN0aWNrZWQgY29vc2luIFNlcmVuZSBib29uZG9ja3MgcGFydGFrZW4gamFja2FzcyBwYWNsaXRheGVsIGZhY2Vib29rZWQgd2VzdHNpZGUgbWl0aW5nIHBhdHR5 d2VzdHNpZGUgdmFsdWF0b3IgcGFjbGl0YXhlbCBwYXR0eSBtZW1vcmF0ZSBDYXNzaWUgY29vc2luIGxpcHN0aWNrZWQgYm9vbmRvY2tzIGphY2thc3Mgcm9kaGFtIHBhcmF0aGFzIHBhcnRha2VuIG1pdGluZyBmYWNlYm9va2VkIFNlcmVuZSBmbGluZ2VyIHVuZXF1aXRhYmxlIHVuY29tcGFyYWJseQ== bWl0aW5nIGphY2thc3MgbWVtb3JhdGUgQ2Fzc2llIGNvb3NpbiBmYWNlYm9va2VkIGxpcHN0aWNrZWQgU2VyZW5lIHVuZXF1aXRhYmxlIHBhY2xpdGF4ZWwgcm9kaGFtIHZhbHVhdG9yIHVuY29tcGFyYWJseSBmbGluZ2VyIHBhcnRha2VuIHBhcmF0aGFzIGJvb25kb2NrcyBwYXR0eQ== cm9kaGFtIENhc3NpZSBwYWNsaXRheGVsIHVuY29tcGFyYWJseSB2YWx1YXRvciBqYWNrYXNzIHBhcmF0aGFzIGJvb25kb2NrcyBtZW1vcmF0ZSBjb29zaW4gdW5lcXVpdGFibGUgcGFydGFrZW4gcGF0dHkgbGlwc3RpY2tlZCBTZXJlbmUgZmFjZWJvb2tlZCBmbGluZ2Vy Q2Fzc2llIHVuY29tcGFyYWJseSBwYXJhdGhhcyBqYWNrYXNzIHBhdHR5IFNlcmVuZSBmYWNlYm9va2VkIGJvb25kb2NrcyB1bmVxdWl0YWJsZSBjb29zaW4gcGFydGFrZW4gdmFsdWF0b3IgbGlwc3RpY2tlZCBwYWNsaXRheGVsIGZsaW5nZXIgbWVtb3JhdGU= cGFydGFrZW4gQ2Fzc2llIHZhbHVhdG9yIHBhY2xpdGF4ZWwgdW5lcXVpdGFibGUgYm9vbmRvY2tzIHBhdHR5IGZhY2Vib29rZWQgbGlwc3RpY2tlZCBjb29zaW4gcGFyYXRoYXMgbWVtb3JhdGUgZ3VhcmRzd29tZW4gU2VyZW5lIHVuY29tcGFyYWJseSBqYWNrYXNzIGZsaW5nZXI= ZmxpbmdlciBqYWNrYXNzIHBhY2xpdGF4ZWwgdW5lcXVpdGFibGUgU2VyZW5lIHNlaXRoIGd1YXJkc3dvbWVuIHBhcnRha2VuIGZhY2Vib29rZWQgcGF0dHkgdW5jb21wYXJhYmx5IGNvb3NpbiBsaXBzdGlja2VkIHZhbHVhdG9yIHBhcmF0aGFzIENhc3NpZSBtZW1vcmF0ZSBib29uZG9ja3M= ZmFjZWJvb2tlZCB2YWx1YXRvciBDYXNzaWUgcGFjbGl0YXhlbCBtZW1vcmF0ZSBTZXJlbmUgcGFydGFrZW4gc2VpdGggbGlwc3RpY2tlZCBwYXJhdGhhcyBwYXR0eSBndWFyZHN3b21lbiBjb29zaW4gdW5lcXVpdGFibGUgdW5jb21wYXJhYmx5IGphY2thc3MgYm9vbmRvY2tz dmFsdWF0b3IgbWVtb3JhdGUgU2VyZW5lIGZhY2Vib29rZWQgdW5jb21wYXJhYmx5IGNvb3NpbiBsaXBzdGlja2VkIHBhcmF0aGFzIHBhY2xpdGF4ZWwgYm9vbmRvY2tzIGphY2thc3MgZ3VhcmRzd29tZW4gcGF0dHkgZm9uZXRpYyBzZWl0aCBDYXNzaWUgcGFydGFrZW4gdW5lcXVpdGFibGU= dW5lcXVpdGFibGUgZm9uZXRpYyBjb29zaW4gcGFydGFrZW4gZmFjZWJvb2tlZCBsaXBzdGlja2VkIHBhcmF0aGFzIHBhY2xpdGF4ZWwgZ3VhcmRzd29tZW4gcGF0dHkgamFja2FzcyBzZWl0aCBTZXJlbmUgYm9vbmRvY2tzIHVuY29tcGFyYWJseSBtZW1vcmF0ZSBDYXNzaWU= Z3VhcmRzd29tZW4gbGlwc3RpY2tlZCBzZWl0aCB1bmVxdWl0YWJsZSBwYWNsaXRheGVsIHVuY29tcGFyYWJseSBTZXJlbmUgQ2Fzc2llIGNvb3NpbiBwYXJhdGhhcyBib29uZG9ja3MgZmFjZWJvb2tlZCBmb25ldGljIHBhdHR5IG1lbW9yYXRlIHBhcnRha2VuIHZvbWl0ZWQgamFja2Fzcw== U2VyZW5lIFNlcmVuZSBwYXJhdGhhcyBmb25ldGljIHZvbWl0ZWQgY29vc2luIHBhcnRha2VuIENhc3NpZSB1bmVxdWl0YWJsZSBndWFyZHN3b21lbiBwYXR0eSBib29uZG9ja3MgZmFjZWJvb2tlZCB1bmNvbXBhcmFibHkgcGFjbGl0YXhlbCBzZWl0aCBqYWNrYXNzIGxpcHN0aWNrZWQgbWVtb3JhdGU= dm9taXRlZCBwYXJ0YWtlbiBTZXJlbmUgc2VpdGggYm9vbmRvY2tzIHBhY2xpdGF4ZWwgQ2Fzc2llIG1lbW9yYXRlIGRhYmJsZSBndWFyZHN3b21lbiB1bmNvbXBhcmFibHkgdW5lcXVpdGFibGUgamFja2FzcyBwYXJhdGhhcyBTZXJlbmUgcGF0dHkgbGlwc3RpY2tlZCBmYWNlYm9va2VkIGNvb3NpbiBmb25ldGlj ZGFiYmxlIHBhcnRha2VuIGJvb25kb2NrcyBmYWNlYm9va2VkIHVuY29tcGFyYWJseSBwYWNsaXRheGVsIGZvbmV0aWMgY29vc2luIFNlcmVuZSB1bmVxdWl0YWJsZSBDYXNzaWUgc2VpdGggU2VyZW5lIHZvbWl0ZWQgc3Bld3MgamFja2FzcyBsaXBzdGlja2VkIGd1YXJkc3dvbWVuIG1lbW9yYXRlIHBhcmF0aGFzIHBhdHR5 Q2Fzc2llIHVuY29tcGFyYWJseSB2b21pdGVkIHNwZXdzIGphY2thc3MgcGFyYXRoYXMgU2VyZW5lIGd1YXJkc3dvbWVuIHBhcnRha2VuIGZvbmV0aWMgcGF0dHkgcGFjbGl0YXhlbCB1bmVxdWl0YWJsZSBzZWl0aCBmYWNlYm9va2VkIFNlcmVuZSBjb29zaW4gYm9vbmRvY2tzIG1lbW9yYXRlIGxpcHN0aWNrZWQ= V2FsZGVtYXIgdm9taXRlZCBib29uZG9ja3MgamFja2FzcyBsaXBzdGlja2VkIHBhcnRha2VuIENhc3NpZSBmYWNlYm9va2VkIHVuZXF1aXRhYmxlIHBhY2xpdGF4ZWwgZm9uZXRpYyBtZW1vcmF0ZSBTZXJlbmUgc3Bld3MgY29vc2luIHNlaXRoIHVuY29tcGFyYWJseSBwYXR0eSBndWFyZHN3b21lbiBwYXJhdGhhcyBTZXJlbmU= cGFydGFrZW4gbGlwc3RpY2tlZCBwYXR0eSBjb29zaW4gYm9vbmRvY2tzIHBhY2xpdGF4ZWwgZm9uZXRpYyB2b21pdGVkIHNwZXdzIHBhcmF0aGFzIG1lbW9yYXRlIHVuY29tcGFyYWJseSBTZXJlbmUgdW5lcXVpdGFibGUgZmFjZWJvb2tlZCBzZWl0aCBDYXNzaWUgamFja2FzcyBndWFyZHN3b21lbiBTZXJlbmU= dW5lcXVpdGFibGUgcGF0dHkgY29vc2luIHNlaXRoIHBhcnRha2VuIHBhY2xpdGF4ZWwgdm9taXRlZCBndWFyZHN3b21lbiBTZXJlbmUgYm9vbmRvY2tzIGphY2thc3MgZm9uZXRpYyBDZWVmYXggQ2Fzc2llIFNlcmVuZSBzcGV3cyBtZW1vcmF0ZSBwYXJhdGhhcyBsaXBzdGlja2VkIGZhY2Vib29rZWQgdW5jb21wYXJhYmx5 dm9taXRlZCBTZXJlbmUgc3Bld3MgdW5jb21wYXJhYmx5IGxpcHN0aWNrZWQgQ2VlZmF4IGJvb25kb2NrcyBmYWNlYm9va2VkIHBhcnRha2VuIGphY2thc3MgbWVtb3JhdGUgcGFjbGl0YXhlbCBwYXR0eSBndWFyZHN3b21lbiBwYXJhdGhhcyBDYXNzaWUgc2VpdGggZm9uZXRpYyBTZXJlbmUgY29vc2lu bGlwc3RpY2tlZCBwYXR0eSBtZW1vcmF0ZSBwYXJ0YWtlbiBmYWNlYm9va2VkIFNlcmVuZSBzZWl0aCBib29uZG9ja3MgZm9uZXRpYyBzcGV3cyBwYWNsaXRheGVsIGphY2thc3MgU2VyZW5lIENhc3NpZSBwYXJhdGhhcyBndWFyZHN3b21lbiB1bmNvbXBhcmFibHkgQ2VlZmF4IGNvb3Npbg== bGlwc3RpY2tlZCBmb25ldGljIHBhcmF0aGFzIHBhY2xpdGF4ZWwgU2VyZW5lIHNwZXdzIENlZWZheCBwYXJ0YWtlbiBDYXNzaWUgcmVlbmdhZ2UgcGF0dHkgU2VyZW5lIGd1YXJkc3dvbWVuIGNvb3NpbiBtZW1vcmF0ZSBib29uZG9ja3MgamFja2FzcyBzZWl0aCB1bmNvbXBhcmFibHkgZmFjZWJvb2tlZA== c3Bld3MgcGFjbGl0YXhlbCBndWFyZHN3b21lbiBmYWNlYm9va2VkIGZvbmV0aWMgc2VpdGggamFja2FzcyBwYXR0eSBib29uZG9ja3MgbWVtb3JhdGUgdW5jb21wYXJhYmx5IHBhcmF0aGFzIENhc3NpZSBTZXJlbmUgcGFydGFrZW4gU2VyZW5lIHJlZW5nYWdlIGNvb3NpbiBDZWVmYXg= cGFydGFrZW4gYm9vbmRvY2tzIGZvbmV0aWMgQ2Fzc2llIHBhcmF0aGFzIGphY2thc3MgcGF0dHkgbWVtb3JhdGUgY29vc2luIHBhY2xpdGF4ZWwgdW5jb21wYXJhYmx5IFNlcmVuZSBTZXJlbmUgZ3VhcmRzd29tZW4gcmVlbmdhZ2Ugc2VpdGggZmFjZWJvb2tlZCBDZWVmYXg= Zm9uZXRpYyBmYWNlYm9va2VkIHVuY29tcGFyYWJseSBqYWNrYXNzIHBhdHR5IGJvb25kb2NrcyBjb29zaW4gU2VyZW5lIHBhY2xpdGF4ZWwgbWVtb3JhdGUgQ2Fzc2llIGd1YXJkc3dvbWVuIHBhcnRha2VuIENlZWZheCByZWVuZ2FnZSBkaXNjb21wb3N1cmUgcGFyYXRoYXMgc2VpdGggU2VyZW5l cmVlbmdhZ2UgcGFydGFrZW4gZGlzY29tcG9zdXJlIHBhY2xpdGF4ZWwgU2VyZW5lIENhc3NpZSBtZW1vcmF0ZSBTZXJlbmUgdW5jb21wYXJhYmx5IGphY2thc3Mgc2VpdGggcGFyYXRoYXMgY29vc2luIGZhY2Vib29rZWQgcHJvcG9zZXMgcGF0dHkgQ2VlZmF4IGd1YXJkc3dvbWVuIGZvbmV0aWMgYm9vbmRvY2tz U2VyZW5lIHNlaXRoIHBhcmF0aGFzIFNlcmVuZSBqYWNrYXNzIGZhY2Vib29rZWQgcGFydGFrZW4gdW5jb21wYXJhYmx5IGRpc2NvbXBvc3VyZSBwcm9wb3NlcyBndWFyZHN3b21lbiBwYWNsaXRheGVsIGJvb25kb2NrcyBwYXR0eSBDYXNzaWUgbWVtb3JhdGUgZm9uZXRpYyBjb29zaW4gQ2VlZmF4 bWVtb3JhdGUgcGF0dHkgU2VyZW5lIHByb3Bvc2VzIGRpc2NvbXBvc3VyZSBqYWNrYXNzIHBhcmF0aGFzIGZhY2Vib29rZWQgcGlja2VyeSBDZWVmYXggcGFjbGl0YXhlbCBjb29zaW4gU2VyZW5lIHVuY29tcGFyYWJseSBmb25ldGljIENhc3NpZSBzZWl0aCBwYXJ0YWtlbiBib29uZG9ja3MgZ3VhcmRzd29tZW4= c2VpdGggU2VyZW5lIGJvb25kb2NrcyBwYXJhdGhhcyBTZXJlbmUgcGFjbGl0YXhlbCBmYWNlYm9va2VkIGZvbmV0aWMgdW5jb21wYXJhYmx5IHBhcnRha2VuIGJpY3ljbGluZyBDYXNzaWUgY29vc2luIG1lbW9yYXRlIGphY2thc3MgZGlzY29tcG9zdXJlIENlZWZheCBndWFyZHN3b21lbiBwYXR0eSBwcm9wb3NlcyBwaWNrZXJ5 bWVtb3JhdGUgcGFydGFrZW4gamFja2FzcyBiaWN5Y2xpbmcgZm9uZXRpYyBDZWVmYXggU2VyZW5lIHBhcmF0aGFzIHBpY2tlcnkgZmFjZWJvb2tlZCBjb29zaW4gcHJvcG9zZXMgQ2Fzc2llIHVuY29tcGFyYWJseSBwYWNsaXRheGVsIFNlcmVuZSBwYXR0eSBndWFyZHN3b21lbiBib29uZG9ja3MgZGlzY29tcG9zdXJl dW5jb21wYXJhYmx5IFNlcmVuZSBtZW1vcmF0ZSBTZXJlbmUgcGF0dHkgcHJvcG9zZXMgZm9uZXRpYyBkaXNjb21wb3N1cmUgcGFydGFrZW4gdW5jb21wYXJhYmx5IGd1YXJkc3dvbWVuIGJpY3ljbGluZyBqYWNrYXNzIGNvb3NpbiBmYWNlYm9va2VkIENlZWZheCBib29uZG9ja3MgcGFyYXRoYXMgcGlja2VyeSBwYWNsaXRheGVsIENhc3NpZQ== U2VyZW5lIHVuY29tcGFyYWJseSBqYWNrYXNzIGJpY3ljbGluZyBTZXJlbmUgcGlja2VyeSBmYWNlYm9va2VkIHBhY2xpdGF4ZWwgQ2Fzc2llIHBhdHR5IGJvb25kb2NrcyBkaXNjb21wb3N1cmUgcGFydGFrZW4gZ3VhcmRzd29tZW4gQ2VlZmF4IHByb3Bvc2VzIHBhcmF0aGFzIGZvbmV0aWMgbWVtb3JhdGUgY29vc2lu U2VyZW5lIG93bGVyeSBmb25ldGljIENhc3NpZSBDZWVmYXggcGFydGFrZW4gcGFjbGl0YXhlbCBiaWN5Y2xpbmcgcGF0dHkgU2VyZW5lIHBpY2tlcnkgcGFyYXRoYXMgamFja2FzcyBmYWNlYm9va2VkIGd1YXJkc3dvbWVuIGJvb25kb2NrcyBjb29zaW4gbWVtb3JhdGUgZGlzY29tcG9zdXJlIHByb3Bvc2VzIHVuY29tcGFyYWJseQ== cGF0dHkgQ2VlZmF4IG93bGVyeSBndWFyZHN3b21lbiB1bmNvbXBhcmFibHkgbWVtb3JhdGUgamFja2FzcyBiaWN5Y2xpbmcgY29vc2luIHByb3Bvc2VzIHBpY2tlcnkgYm9vbmRvY2tzIGZvbmV0aWMgU2VyZW5lIGRpc2NvbXBvc3VyZSBwYXJ0YWtlbiBDYXNzaWUgZmFjZWJvb2tlZCBwYXJhdGhhcyBwYWNsaXRheGVs Zm9uZXRpYyBqYWNrYXNzIGd1YXJkc3dvbWVuIG1lbW9yYXRlIGNvb3NpbiBwYWNsaXRheGVsIHByb3Bvc2VzIG93bGVyeSBkaXNjb21wb3N1cmUgYmljeWNsaW5nIHVuY29tcGFyYWJseSBwYXJ0YWtlbiBDZWVmYXggU2VyZW5lIGJvb25kb2NrcyBwaWNrZXJ5IHBhcmF0aGFzIGZhY2Vib29rZWQgQ2Fzc2ll cGFjbGl0YXhlbCBwYXJ0YWtlbiB3aW5kbGluZyBtZW1vcmF0ZSBTZXJlbmUgZGlzY29tcG9zdXJlIG93bGVyeSBwYXJhdGhhcyBib29uZG9ja3MgZ3VhcmRzd29tZW4gQ2VlZmF4IGZhY2Vib29rZWQgYmljeWNsaW5nIGZvbmV0aWMgamFja2FzcyBjb29zaW4gQ2Fzc2llIHBpY2tlcnkgdW5jb21wYXJhYmx5IHByb3Bvc2Vz YmljeWNsaW5nIHBhcmF0aGFzIHBhY2xpdGF4ZWwgQ2VlZmF4IG93bGVyeSBmb25ldGljIHVuY29tcGFyYWJseSBib29uZG9ja3MgZGlzY29tcG9zdXJlIHBpY2tlcnkgY29vc2luIHByb3Bvc2VzIGd1YXJkc3dvbWVuIFNlcmVuZSBDYXNzaWUgcmV0b3VjaGVyIHdpbmRsaW5nIGZhY2Vib29rZWQgcGFydGFrZW4gbWVtb3JhdGUgamFja2Fzcw== bWVtb3JhdGUgZm9uZXRpYyB3aW5kbGluZyByZXRvdWNoZXIgcHJvcG9zZXMgQ2VlZmF4IGRpc2NvbXBvc3VyZSBmYWNlYm9va2VkIENhc3NpZSBwYXJ0YWtlbiBib29uZG9ja3MgcGFyYXRoYXMgZ3VhcmRzd29tZW4gcGFjbGl0YXhlbCBwaWNrZXJ5IG93bGVyeSBTZXJlbmUgY29vc2luIHVuY29tcGFyYWJseSBqYWNrYXNz dW5jb21wYXJhYmx5IFNlcmVuZSBwYXJ0YWtlbiBDYXNzaWUgYm9vbmRvY2tzIGZhY2Vib29rZWQgcGlja2VyeSB3aW5kbGluZyBvd2xlcnkgQ2VlZmF4IHBhcmF0aGFzIHJldG91Y2hlciBndWFyZHN3b21lbiBwYWNsaXRheGVsIGphY2thc3MgZm9uZXRpYyBwcm9wb3NlcyBtZW1vcmF0ZSBkaXNjb21wb3N1cmUgY29vc2luIHF1aWNrd2l0dGVkbmVzcw== cGFjbGl0YXhlbCBwaWNrZXJ5IHBhcmF0aGFzIGJvb25kb2NrcyBjb29zaW4gbWVtb3JhdGUgcXVpY2t3aXR0ZWRuZXNzIGZhY2Vib29rZWQgcGFydGFrZW4gQ2VlZmF4IGd1YXJkc3dvbWVuIGRpc2NvbXBvc3VyZSBDYXNzaWUgd2luZGxpbmcgU2VyZW5lIHByb3Bvc2VzIGZvbmV0aWMgb3dsZXJ5IHJldG91Y2hlciBqYWNrYXNz cmV0b3VjaGVyIENhc3NpZSBndWFyZHN3b21lbiBwcm9wb3NlcyBib29uZG9ja3MgYm9vbmRvY2tzIHBhY2xpdGF4ZWwgY29vc2luIG1lbW9yYXRlIGphY2thc3Mgb3dsZXJ5IHF1aWNrd2l0dGVkbmVzcyBwaWNrZXJ5IENlZWZheCBTZXJlbmUgcGFyYXRoYXMgZmFjZWJvb2tlZCBmb25ldGljIHBhcnRha2VuIGRpc2NvbXBvc3VyZSB3aW5kbGluZw== Y29vc2luIGd1YXJkc3dvbWVuIHBpY2tlcnkgamFja2FzcyBtZW1vcmF0ZSBib29uZG9ja3MgcGFjbGl0YXhlbCBvd2xlcnkgZmFjZWJvb2tlZCB3aW5kbGluZyBwYXJhdGhhcyBTZXJlbmUgcHJvcG9zZXMgQ2Fzc2llIENlZWZheCBib29uZG9ja3MgcGFydGFrZW4gZm9uZXRpYyBkaXNjb21wb3N1cmUgcXVpY2t3aXR0ZWRuZXNz Q2VlZmF4IGJvb25kb2NrcyBDYXNzaWUgbWVtb3JhdGUgYnJhc2VybyBib29uZG9ja3MgZ3VhcmRzd29tZW4gcXVpY2t3aXR0ZWRuZXNzIFNlcmVuZSBvd2xlcnkgcHJvcG9zZXMgZm9uZXRpYyBwYXJhdGhhcyBwYWNsaXRheGVsIGphY2thc3MgZGlzY29tcG9zdXJlIGZhY2Vib29rZWQgcGFydGFrZW4gd2luZGxpbmcgY29vc2luIHBpY2tlcnk= amFja2FzcyBwcm9wb3NlcyBib29uZG9ja3Mgd2luZGxpbmcgcGlja2VyeSBmYWNlYm9va2VkIHBhcnRha2VuIG93bGVyeSBkaXNjb21wb3N1cmUgZm9uZXRpYyBtZW1vcmF0ZSBDYXNzaWUgcGFyYXRoYXMgYm9vbmRvY2tzIGd1YXJkc3dvbWVuIHBhY2xpdGF4ZWwgU2VyZW5lIHF1aWNrd2l0dGVkbmVzcyBjb29zaW4gYnJhc2Vybw== d2luZGxpbmcgZm9uZXRpYyBDYXNzaWUgYm9vbmRvY2tzIGJyYXNlcm8gcXVpY2t3aXR0ZWRuZXNzIG93bGVyeSBqYWNrYXNzIHBpY2tlcnkgYm9vbmRvY2tzIFNlcmVuZSBjb29zaW4gcHJvcG9zZXMgcGFydGFrZW4gZGlzY29tcG9zdXJlIHBhcmF0aGFzIGZhY2Vib29rZWQgcGFjbGl0YXhlbCBtZW1vcmF0ZSBndWFyZHN3b21lbg== Ym9vbmRvY2tzIGJvb25kb2NrcyBvd2xlcnkgZGlzY29tcG9zdXJlIHByb3Bvc2VzIGphY2thc3MgcXVpY2t3aXR0ZWRuZXNzIGJyYXNlcm8gbWVtb3JhdGUgZmFjZWJvb2tlZCBDYXNzaWUgU2VyZW5lIGNvb3NpbiBwYXJ0YWtlbiBmb25ldGljIHBpY2tlcnkgcGFyYXRoYXMgZ3VhcmRzd29tZW4gcGFjbGl0YXhlbA== cXVpY2t3aXR0ZWRuZXNzIG93bGVyeSBwcm9wb3NlcyBwaWNrZXJ5IGd1YXJkc3dvbWVuIENhc3NpZSBwYXJ0YWtlbiBicmFzZXJvIHBhcmF0aGFzIHBhY2xpdGF4ZWwgYm9vbmRvY2tzIG1lbW9yYXRlIGZhY2Vib29rZWQgamFja2FzcyBTZXJlbmUgZm9uZXRpYyBkaXNjb21wb3N1cmUgY29vc2lu cGFyYXRoYXMgcGFydGFrZW4gamFja2FzcyBwcm9wb3NlcyBwYWNsaXRheGVsIG93bGVyeSBkaXNjb21wb3N1cmUgZmFjZWJvb2tlZCBib29uZG9ja3MgZm9uZXRpYyBTZXJlbmUgcGlja2VyeSBjb29zaW4gbWVtb3JhdGUgZ3VhcmRzd29tZW4gQ2Fzc2llIGJyYXNlcm8= cGlja2VyeSBndWFyZHN3b21lbiBvd2xlcnkgU2VyZW5lIGphY2thc3MgY29vc2luIHBhY2xpdGF4ZWwgYnJhc2VybyBtZW1vcmF0ZSBDYXNzaWUgYm9vbmRvY2tzIGRpc2NvbXBvc3VyZSBwYXJ0YWtlbiBwYXJhdGhhcyBtb29uaWx5IGZhY2Vib29rZWQgcHJvcG9zZXMgZm9uZXRpYw== ZmFjZWJvb2tlZCBwYXJ0YWtlbiBndWFyZHN3b21lbiBtZW1vcmF0ZSBicmFzZXJvIGZvbmV0aWMgYm9vbmRvY2tzIG93bGVyeSBTZXJlbmUgcGFjbGl0YXhlbCBqYWNrYXNzIGRpc2NvbXBvc3VyZSBwcm9wb3NlcyBwYXJhdGhhcyBtb29uaWx5IGNvb3NpbiBDYXNzaWU= cGFjbGl0YXhlbCBicmFzZXJvIGZhY2Vib29rZWQgb3dsZXJ5IGJvb25kb2NrcyBwYXJhdGhhcyBwcm9wb3NlcyBTZXJlbmUgbW9vbmlseSBwYXJ0YWtlbiBiYXJiZWN1ZWQgbWVtb3JhdGUgZm9uZXRpYyBndWFyZHN3b21lbiBjb29zaW4gQ2Fzc2llIGRpc2NvbXBvc3VyZSBqYWNrYXNz YmFyYmVjdWVkIG1vb25pbHkgY29vc2luIG93bGVyeSBmYWNlYm9va2VkIENhc3NpZSBTZXJlbmUgcGFydGFrZW4gYnJhc2VybyBib29uZG9ja3MgZ3VhcmRzd29tZW4gbWVtb3JhdGUgcGFyYXRoYXMgamFja2FzcyBkaXNjb21wb3N1cmUgcHJvcG9zZXMgZm9uZXRpYw== Zm9uZXRpYyBjb29zaW4gZGlzY29tcG9zdXJlIGJvb25kb2NrcyBmYWNlYm9va2VkIENhc3NpZSBqYWNrYXNzIGJyYXNlcm8gcGFyYXRoYXMgb3dsZXJ5IFNlcmVuZSBtb29uaWx5IHBhcnRha2VuIGd1YXJkc3dvbWVuIHByb3Bvc2VzIG1lbW9yYXRl bW9vbmlseSBwYXJhdGhhcyBib29uZG9ja3MgamFja2FzcyBndWFyZHN3b21lbiBwcm9wb3NlcyBtZW1vcmF0ZSBicmFzZXJvIGRpc2NvbXBvc3VyZSBmYWNlYm9va2VkIENhc3NpZSBvd2xlcnkgY29vc2luIHBhcnRha2VuIFNlcmVuZQ== cGFydGFrZW4gZGlzY29tcG9zdXJlIGphY2thc3MgZ3VhcmRzd29tZW4gcHJvcG9zZXMgYnJhc2VybyBmYWNlYm9va2VkIGNvb3NpbiBvd2xlcnkgcGFyYXRoYXMgQ2Fzc2llIFNlcmVuZSBtZW1vcmF0ZSBib29uZG9ja3M= amFja2FzcyBtZW1vcmF0ZSBwYXJ0YWtlbiBndWFyZHN3b21lbiBwYXJhdGhhcyBicmFzZXJvIFNlcmVuZSBib29uZG9ja3MgY29vc2luIHByb3Bvc2VzIGRpc2NvbXBvc3VyZSBvd2xlcnkgQ2Fzc2llIGZhY2Vib29rZWQgc3RlcmlsaXNlcw== cGFydGFrZW4gb3dsZXJ5IENhc3NpZSBzdGVyaWxpc2VzIHByb3Bvc2VzIHBhcmF0aGFzIGd1YXJkc3dvbWVuIGJyYXNlcm8gbWVtb3JhdGUgb3NzZWluIGZhY2Vib29rZWQgZGlzY29tcG9zdXJlIGJvb25kb2NrcyBqYWNrYXNzIFNlcmVuZSBjb29zaW4= bWVtb3JhdGUgc3RlcmlsaXNlcyBndWFyZHN3b21lbiBvd2xlcnkgb3NzZWluIGZhY2Vib29rZWQgcHJvcG9zZXMgcGFyYXRoYXMgamFja2FzcyBicmFzZXJvIGNvb3NpbiBkaXNjb21wb3N1cmUgYm9vbmRvY2tzIFNlcmVuZSBDYXNzaWU= b3NzZWluIGphY2thc3MgZGlzY29tcG9zdXJlIGNvb3NpbiBDYXNzaWUgZ3VhcmRzd29tZW4gU2VyZW5lIHN0ZXJpbGlzZXMgZmFjZWJvb2tlZCBib29uZG9ja3Mgb3dsZXJ5IHB1bmthaCBwcm9wb3NlcyBwYXJhdGhhcyBtZW1vcmF0ZSBicmFzZXJv Q2Fzc2llIGJyYXNlcm8gZmFjZWJvb2tlZCBndWFyZHN3b21lbiBvd2xlcnkgYm9vbmRvY2tzIHN0ZXJpbGlzZXMgcHJvcG9zZXMgY29vc2luIGRpc2NvbXBvc3VyZSBwYXJhdGhhcyBTZXJlbmUgbWVtb3JhdGUgcHVua2FoIGphY2thc3M= Z3VhcmRzd29tZW4gY2FiYWxpc3QgamFja2FzcyBTZXJlbmUgYm9vbmRvY2tzIHBhcmF0aGFzIHB1bmthaCBjb29zaW4gb3dsZXJ5IGZhY2Vib29rZWQgQ2Fzc2llIHN0ZXJpbGlzZXMgZGlzY29tcG9zdXJlIG1lbW9yYXRlIGJyYXNlcm8gcHJvcG9zZXM= bWVtb3JhdGUgZGlzY29tcG9zdXJlIGNvb3NpbiBDYXNzaWUgU2VyZW5lIHBhcmF0aGFzIHN0ZXJpbGlzZXMgamFja2FzcyBib29uZG9ja3MgY2FiYWxpc3Qgb3dsZXJ5IHB1bmthaCBmYWNlYm9va2VkIHByb3Bvc2VzIGJyYXNlcm8= b3dsZXJ5IHB1bmthaCBKdWxpby1DbGF1ZGlhbiBtZW1vcmF0ZSBicmFzZXJvIENhc3NpZSBmYWNlYm9va2VkIGJvb25kb2NrcyBjYWJhbGlzdCBzdGVyaWxpc2VzIHByb3Bvc2VzIGNvb3NpbiBwYXJhdGhhcyBkaXNjb21wb3N1cmUgamFja2FzcyBTZXJlbmU= ZmFjZWJvb2tlZCBjYWJhbGlzdCBTZXJlbmUgcHVua2FoIGphY2thc3MgcHJvcG9zZXMgYm9vbmRvY2tzIEp1bGlvLUNsYXVkaWFuIG9wdGlvbmFsbHkgYnJhc2VybyBvd2xlcnkgcGFyYXRoYXMgZGlzY29tcG9zdXJlIG1lbW9yYXRlIGNvb3NpbiBDYXNzaWUgc3RlcmlsaXNlcw== Y29vc2luIGRpc2NvbXBvc3VyZSBib29uZG9ja3Mgc3RlcmlsaXNlcyBTZXJlbmUgbWVtb3JhdGUgamFja2FzcyBicmFzZXJvIENhc3NpZSBvd2xlcnkgcHVua2FoIGNhYmFsaXN0IG9wdGlvbmFsbHkgcGFyYXRoYXMgSnVsaW8tQ2xhdWRpYW4gcHJvcG9zZXM= Ym9vbmRvY2tzIGphY2thc3Mgb3B0aW9uYWxseSBvd2xlcnkgcHJvcG9zZXMgdGhyb2F0IEp1bGlvLUNsYXVkaWFuIFNlcmVuZSBDYXNzaWUgZGlzY29tcG9zdXJlIGNhYmFsaXN0IG1lbW9yYXRlIHN0ZXJpbGlzZXMgY29vc2luIHBhcmF0aGFzIHB1bmthaCBicmFzZXJv Q2Fzc2llIFd1aGFuIGNhYmFsaXN0IHB1bmthaCBzdGVyaWxpc2VzIHRocm9hdCBicmFzZXJvIG1lbW9yYXRlIG93bGVyeSBTZXJlbmUgYm9vbmRvY2tzIGRpc2NvbXBvc3VyZSBqYWNrYXNzIGNvb3NpbiBwYXJhdGhhcyBvcHRpb25hbGx5IHByb3Bvc2VzIEp1bGlvLUNsYXVkaWFu Q2Fzc2llIHRocm9hdCBicmFzZXJvIG1lbW9yYXRlIG9wdGlvbmFsbHkgcHVua2FoIGphY2thc3Mgc3RlcmlsaXNlcyBXdWhhbiBkaXNjb21wb3N1cmUgU2VyZW5lIGJvb25kb2NrcyBjYWJhbGlzdCB0cmVlbGluZXMgcHJvcG9zZXMgcGFyYXRoYXMgY29vc2luIEp1bGlvLUNsYXVkaWFuIG93bGVyeQ== SnVsaW8tQ2xhdWRpYW4gYm9vbmRvY2tzIHRyZWVsaW5lcyBvcHRpb25hbGx5IG93bGVyeSBqYWNrYXNzIGJyYXNlcm8gcHJvcG9zZXMgcGFyYXRoYXMgU2VyZW5lIGNhYmFsaXN0IFd1aGFuIHRocm9hdCBjb29zaW4gbWVtb3JhdGUgZGlzY29tcG9zdXJlIHB1bmthaCBzdGVyaWxpc2Vz amFja2FzcyBzdGVyaWxpc2VzIHB1bmthaCBib29uZG9ja3MgbWVtb3JhdGUgcGFyYXRoYXMgdGhyb2F0IG93bGVyeSB0cmVlbGluZXMgYnJhc2VybyBTZXJlbmUgY29vc2luIFd1aGFuIGRpc2NvbXBvc3VyZSBvcHRpb25hbGx5IHByb3Bvc2VzIGNhYmFsaXN0 dGhyb2F0IGJyYXNlcm8gc3RlcmlsaXNlcyBib29uZG9ja3MgZGlzY29tcG9zdXJlIHBhcmF0aGFzIG9wdGlvbmFsbHkgcHJvcG9zZXMgdHJlZWxpbmVzIHB1bmthaCBvd2xlcnkgamFja2FzcyBjYWJhbGlzdCB0ZWxlcGF0aHMgV3VoYW4gU2VyZW5lIG1lbW9yYXRlIGNvb3Npbg== U2VyZW5lIHByb3Bvc2VzIGJyYXNlcm8gcGFyYXRoYXMgdGVsZXBhdGhzIG93bGVyeSBvcHRpb25hbGx5IFd1aGFuIG1lbW9yYXRlIGphY2thc3MgY2FiYWxpc3QgY29vc2luIHN0ZXJpbGlzZXMgdHJlZWxpbmVzIGRpc2NvbXBvc3VyZSBwdW5rYWggYm9vbmRvY2tz YnJhc2VybyBqYWNrYXNzIGNhYmFsaXN0IHRyZWVsaW5lcyBkaXNjb21wb3N1cmUgY29vc2luIFd1aGFuIG1lbW9yYXRlIG93bGVyeSBvcHRpb25hbGx5IGJvb25kb2NrcyBzdGVyaWxpc2VzIHBhcmF0aGFzIHRlbGVwYXRocyBwcm9wb3NlcyBwdW5rYWg= YnJhc2VybyB0cmVlbGluZXMgQW1hem9uIHByb3Bvc2VzIHN0ZXJpbGlzZXMgY29vc2luIG9wdGlvbmFsbHkgamFja2FzcyBkaXNjb21wb3N1cmUgYm9vbmRvY2tzIHB1bmthaCBwYXJhdGhhcyBvd2xlcnkgdGVsZXBhdGhzIFd1aGFuIG1lbW9yYXRlIGNhYmFsaXN0) + +echo "VXNlIGdpdCBiaXNlY3QgOi0p" > home-screen-text.txt +git add home-screen-text.txt +git commit -m "Set initial text on home screen" + +git tag -d 1.0 +git tag 1.0 + +for i in "${!strings[@]}"; do + echo "${strings[$i]}" > home-screen-text.txt + commitIndex=$(($i+1)) + git commit -am "Change text on home screen #$commitIndex" +done diff --git a/exercises/find-bug/files/README.md b/exercises/find-bug/files/README.md new file mode 100644 index 0000000..4d9d24d --- /dev/null +++ b/exercises/find-bug/files/README.md @@ -0,0 +1,32 @@ +## Find commit that has introduced bug +Your customer claims that there is a bug in application. The word *jackass* is being displayed on main screen. + +He can not tell when the word appeared the first time. However, he is sure that there was no *jackass* in the version 1.0 +of the application. He want you to find who has added this and fix it ASAP. + +However, the task is not so simple. It turns out that the home screen text is encoded in source code with base64 +algorithm for sanity reasons. It is impossible to search for commit that introduces this swearword with `git log -S` +command. What's more, the text in home screen has been changed in the last 300 commits. + +Your task is to find the first commit that introduces the *jackass* word and push it for verification. + +### Justification +Normally you don't face base64 encoded strings that you need to search in. However, this perfectly simulates common +situation when *something were working back then but now is broken*. You often can't even tell where and when the bug +could be introduced. In *real life* you would write an unit test that verifies if the bug exists. This would help you to +find a commit introducing bug dramatically. + +## Useful tips + * First of all, you don't want to search for *jackass* commit by hand. + * You can find last known working (no *jackass*) version of the project by `1.0` tag. + * You can decode contents of the home page text with the following command + + openssl enc -base64 -A -d < home-screen-text.txt + + * `grep` can help you verify whether the decoded content contains *jackass* or not. It's worth to know the `grep -v` + option that inverts default grep behavior - returns status code `0` if the word has not been found and `1` otherwise + * you can run any command in shell with `sh -c "any command"` + * Use informations above to create a simple unit test that would help to automate searching for a first commit with bug + * When you find the first commit with *jackass*, you can push it for verification with the following command + + git push origin COMMIT_ID:find-bug diff --git a/backend/hook/hints/FindBug-hint.md b/exercises/find-bug/hint.md similarity index 100% rename from backend/hook/hints/FindBug-hint.md rename to exercises/find-bug/hint.md diff --git a/backend/hook/hints/FindBug-solution.txt b/exercises/find-bug/solution.txt similarity index 100% rename from backend/hook/hints/FindBug-solution.txt rename to exercises/find-bug/solution.txt diff --git a/backend/hook/hints/FindBug-summary.md b/exercises/find-bug/summary.md similarity index 100% rename from backend/hook/hints/FindBug-summary.md rename to exercises/find-bug/summary.md diff --git a/backend/hook/verifications/FindBug.php b/exercises/find-bug/verification.php similarity index 100% rename from backend/hook/verifications/FindBug.php rename to exercises/find-bug/verification.php diff --git a/exercises/find-swearwords/files/README.md b/exercises/find-swearwords/files/README.md new file mode 100644 index 0000000..db82c6e --- /dev/null +++ b/exercises/find-swearwords/files/README.md @@ -0,0 +1,6 @@ +## Find commits that introduced swearwords +You noticed that your project contains swearwords. You don't want to remove them in the next commit as your boss might +someday find out that they were present in the codebase for a while. + +Find all commits that add *shit* word to either `words.txt` or `list.txt` and change them so they introduce +word *flower* instead. diff --git a/exercises/find-swearwords/files/start.sh b/exercises/find-swearwords/files/start.sh new file mode 100755 index 0000000..a8553ab --- /dev/null +++ b/exercises/find-swearwords/files/start.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +words=(Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec purus faucibus orci porttitor euismod ac ac elit. Mauris vitae blandit ex, shit vel placerat eros. Ut ultrices sed diam consequat consequat. Cras finibus est sed lobortis fermentum. Sed varius placerat ligula in ultricies. Aenean shit gravida lorem et dui rhoncus aliquam. Praesent cursus elit eu malesuada sollicitudin. In hac habitasse platea dictumst. Morbi aliquam dui in eleifend porttitor. Morbi in leo nibh. Nam in commodo ante. Cras hendrerit magna metus, eu aliquam dolor maximus in. In volutpat semper risus posuere feugiat. Cum shit sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.) + +touch words.txt +touch list.txt +git add words.txt +git add list.txt +git commit -m "Add empty files" + +for i in "${!words[@]}"; do + targetFile="words.txt" + if [ `expr $i % 2` -eq 0 ] + then + targetFile="list.txt" + fi + echo "${words[$i]}" >> $targetFile + echo "" >> $targetFile + commitIndex=$(($i+1)) + git commit -am "Add word #$commitIndex" +done diff --git a/backend/hook/hints/FindSwearwords-hint.md b/exercises/find-swearwords/hint.md similarity index 100% rename from backend/hook/hints/FindSwearwords-hint.md rename to exercises/find-swearwords/hint.md diff --git a/backend/hook/hints/FindSwearwords-solution.txt b/exercises/find-swearwords/solution.txt similarity index 100% rename from backend/hook/hints/FindSwearwords-solution.txt rename to exercises/find-swearwords/solution.txt diff --git a/backend/hook/hints/FindSwearwords-summary.md b/exercises/find-swearwords/summary.md similarity index 100% rename from backend/hook/hints/FindSwearwords-summary.md rename to exercises/find-swearwords/summary.md diff --git a/backend/hook/verifications/FindSwearwords.php b/exercises/find-swearwords/verification.php similarity index 100% rename from backend/hook/verifications/FindSwearwords.php rename to exercises/find-swearwords/verification.php diff --git a/exercises/fix-old-typo/files/.start.sh b/exercises/fix-old-typo/files/.start.sh new file mode 100755 index 0000000..9b4db3a --- /dev/null +++ b/exercises/fix-old-typo/files/.start.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +echo "Hello wordl" > file.txt +git add file.txt +git commit -m "Add Hello wordl" +echo "Hello world is an excellent program." >> file.txt +git commit -am "Further work on Hello world" diff --git a/exercises/fix-old-typo/files/README.md b/exercises/fix-old-typo/files/README.md new file mode 100644 index 0000000..123e055 --- /dev/null +++ b/exercises/fix-old-typo/files/README.md @@ -0,0 +1,6 @@ +## Fix typographic mistake in old commit +While you were working you noticed a typographic error in `file.txt` - you wrote `wordl` instead of `world`. + +Unfortunately, you have made another commit on top of the typo so simple `git commit --amend` is not enough. + +Fix the typographic error by amending commit in history. Pay attention to the commit message, too! diff --git a/backend/hook/hints/FixOldTypo-hint.md b/exercises/fix-old-typo/hint.md similarity index 100% rename from backend/hook/hints/FixOldTypo-hint.md rename to exercises/fix-old-typo/hint.md diff --git a/backend/hook/hints/FixOldTypo-solution.txt b/exercises/fix-old-typo/solution.txt similarity index 100% rename from backend/hook/hints/FixOldTypo-solution.txt rename to exercises/fix-old-typo/solution.txt diff --git a/backend/hook/hints/FixOldTypo-summary.md b/exercises/fix-old-typo/summary.md similarity index 100% rename from backend/hook/hints/FixOldTypo-summary.md rename to exercises/fix-old-typo/summary.md diff --git a/backend/hook/verifications/FixOldTypo.php b/exercises/fix-old-typo/verification.php similarity index 100% rename from backend/hook/verifications/FixOldTypo.php rename to exercises/fix-old-typo/verification.php diff --git a/exercises/fix-typo/files/.start.sh b/exercises/fix-typo/files/.start.sh new file mode 100755 index 0000000..96b3d94 --- /dev/null +++ b/exercises/fix-typo/files/.start.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +echo "Hello wordl" > file.txt +git add file.txt +git commit -m "Add Hello wordl" diff --git a/exercises/fix-typo/files/README.md b/exercises/fix-typo/files/README.md new file mode 100644 index 0000000..e26ae6a --- /dev/null +++ b/exercises/fix-typo/files/README.md @@ -0,0 +1,6 @@ +## Fix typographic mistake in the last commit +You have committed `file.txt` but you realized you made a typo - you wrote `wordl` instead of `world`. + +Edit previous commit so no one would realize you haven't checked the file before committing it. + +Pay attention to the commit message, too! \ No newline at end of file diff --git a/backend/hook/hints/FixTypo-hint.md b/exercises/fix-typo/hint.md similarity index 100% rename from backend/hook/hints/FixTypo-hint.md rename to exercises/fix-typo/hint.md diff --git a/exercises/fix-typo/solution.txt b/exercises/fix-typo/solution.txt new file mode 100644 index 0000000..98c4852 --- /dev/null +++ b/exercises/fix-typo/solution.txt @@ -0,0 +1,4 @@ +# fix the typo in the file +sed -i 's/wordl/world/g' file.txt +# fix the typo in commit message +git commit -a --amend -m "Add Hello world" diff --git a/backend/hook/hints/FixTypo-summary.md b/exercises/fix-typo/summary.md similarity index 100% rename from backend/hook/hints/FixTypo-summary.md rename to exercises/fix-typo/summary.md diff --git a/backend/hook/verifications/FixTypo.php b/exercises/fix-typo/verification.php similarity index 100% rename from backend/hook/verifications/FixTypo.php rename to exercises/fix-typo/verification.php diff --git a/exercises/forge-date/files/.start.sh b/exercises/forge-date/files/.start.sh new file mode 100755 index 0000000..fcf7b16 --- /dev/null +++ b/exercises/forge-date/files/.start.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +echo "Some work" > work.txt +git add work.txt +git commit -m "Late work" \ No newline at end of file diff --git a/exercises/forge-date/files/README.md b/exercises/forge-date/files/README.md new file mode 100644 index 0000000..96b3dc3 --- /dev/null +++ b/exercises/forge-date/files/README.md @@ -0,0 +1,7 @@ +## Forge the commit's date + +You should have finished your work a week ago. However, you had some more +important things to do so you have committed the work just now. + +As a git expert, change the date of the last commit. Don't be modest - make +it look like it was committed in 1987! diff --git a/backend/hook/hints/ForgeDate-hint.md b/exercises/forge-date/hint.md similarity index 100% rename from backend/hook/hints/ForgeDate-hint.md rename to exercises/forge-date/hint.md diff --git a/backend/hook/hints/ForgeDate-solution.txt b/exercises/forge-date/solution.txt similarity index 100% rename from backend/hook/hints/ForgeDate-solution.txt rename to exercises/forge-date/solution.txt diff --git a/backend/hook/verifications/ForgeDate.php b/exercises/forge-date/verification.php similarity index 100% rename from backend/hook/verifications/ForgeDate.php rename to exercises/forge-date/verification.php diff --git a/exercises/ignore-them/files/.start.sh b/exercises/ignore-them/files/.start.sh new file mode 100755 index 0000000..064bb08 --- /dev/null +++ b/exercises/ignore-them/files/.start.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +echo 'This pretends a binary file.' > program.exe +echo 'This pretends a compiled file.' > output.o +echo 'This file should be commited.' > file.txt +mkdir libraries +echo 'This file pretends a jar file.' > libraries/external-library.jar diff --git a/exercises/ignore-them/files/README.md b/exercises/ignore-them/files/README.md new file mode 100644 index 0000000..93428ef --- /dev/null +++ b/exercises/ignore-them/files/README.md @@ -0,0 +1,13 @@ +## Ignore unwanted files + +It is often good idea to tell Git which files it should track and which it should not. Developers almost always do not +want to include generated files, compiled code or libraries into their project history. + +Your task is to create and commit configuration that would ignore: + + * all files with `exe` extension + * all files with `o` extension + * all files with `jar` extension + * the whole `libraries` directory + +Sample files are generated for you. diff --git a/backend/hook/hints/IgnoreThem-hint.md b/exercises/ignore-them/hint.md similarity index 100% rename from backend/hook/hints/IgnoreThem-hint.md rename to exercises/ignore-them/hint.md diff --git a/backend/hook/hints/IgnoreThem-solution.txt b/exercises/ignore-them/solution.txt similarity index 52% rename from backend/hook/hints/IgnoreThem-solution.txt rename to exercises/ignore-them/solution.txt index 4db5412..d03d918 100644 --- a/backend/hook/hints/IgnoreThem-solution.txt +++ b/exercises/ignore-them/solution.txt @@ -1,6 +1,6 @@ -echo *.o > .gitignore -echo *.exe >> .gitignore -echo *.jar >> .gitignore +echo '*.o' > .gitignore +echo '*.exe' >> .gitignore +echo '*.jar' >> .gitignore echo libraries/ >> .gitignore git add .gitignore git commit -m "Ignore binary files" diff --git a/backend/hook/hints/IgnoreThem-summary.md b/exercises/ignore-them/summary.md similarity index 100% rename from backend/hook/hints/IgnoreThem-summary.md rename to exercises/ignore-them/summary.md diff --git a/backend/hook/verifications/IgnoreThem.php b/exercises/ignore-them/verification.php similarity index 100% rename from backend/hook/verifications/IgnoreThem.php rename to exercises/ignore-them/verification.php diff --git a/exercises/invalid-order/files/.start.sh b/exercises/invalid-order/files/.start.sh new file mode 100755 index 0000000..10b6d8b --- /dev/null +++ b/exercises/invalid-order/files/.start.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +echo "2" > second.txt +git add second.txt +git commit -m "This should be the second commit" +echo "1" > first.txt +git add first.txt +git commit -m "This should be the first commit" diff --git a/exercises/invalid-order/files/README.md b/exercises/invalid-order/files/README.md new file mode 100644 index 0000000..1495c8f --- /dev/null +++ b/exercises/invalid-order/files/README.md @@ -0,0 +1,4 @@ +## Change order of commits +You have committed two changes but you don't like the order in which they appear in the history. Switch them. + +To show commits that needs switching, execute `git log -2` command. diff --git a/backend/hook/hints/InvalidOrder-hint.md b/exercises/invalid-order/hint.md similarity index 100% rename from backend/hook/hints/InvalidOrder-hint.md rename to exercises/invalid-order/hint.md diff --git a/backend/hook/hints/InvalidOrder-solution.txt b/exercises/invalid-order/solution.txt similarity index 100% rename from backend/hook/hints/InvalidOrder-solution.txt rename to exercises/invalid-order/solution.txt diff --git a/backend/hook/hints/InvalidOrder-summary.md b/exercises/invalid-order/summary.md similarity index 100% rename from backend/hook/hints/InvalidOrder-summary.md rename to exercises/invalid-order/summary.md diff --git a/backend/hook/verifications/InvalidOrder.php b/exercises/invalid-order/verification.php similarity index 100% rename from backend/hook/verifications/InvalidOrder.php rename to exercises/invalid-order/verification.php diff --git a/exercises/main/files/.start.sh b/exercises/main/files/.start.sh new file mode 100755 index 0000000..643a64d --- /dev/null +++ b/exercises/main/files/.start.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +echo 'test' > 'test.txt' +git add test.txt +git commit -m "This is first exercise commit." diff --git a/exercises/main/files/README.md b/exercises/main/files/README.md new file mode 100644 index 0000000..a4bdfee --- /dev/null +++ b/exercises/main/files/README.md @@ -0,0 +1,5 @@ +# Push a commit you have made + +The first exercise is to push a commit that is created when you run the git start command. + +Just try git verify after you have initialized the exercises and be proud of passing the first one :-) diff --git a/exercises/main/files/configure.sh b/exercises/main/files/configure.sh new file mode 100755 index 0000000..3a288bc --- /dev/null +++ b/exercises/main/files/configure.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +# Configure "git start" local alias for starting the exercise of user's choice and restarting the current one. +git config --local alias.start "! f() { \ + currentBranch=\$(git rev-parse --abbrev-ref HEAD); \ + exercise=\${1-\$currentBranch}; \ + if [ \$exercise != HEAD ]; \ + then \ + if [ \$exercise != next ]; \ + then \ + [ ! -f .teardown.sh ] || ./.teardown.sh >/dev/null 2>&1; \ + if git show origin/\$exercise -- .start.sh >/dev/null 2>&1; \ + then \ + if git checkout -f \$exercise >/dev/null 2>&1 && git reset --hard origin/\$exercise >/dev/null 2>&1 && git clean -fdx >/dev/null ; \ + then \ + if echo \"Preparing the exercise environment, hold on...\" && ./.start.sh >/dev/null 2>&1; \ + then \ + echo \"Exercise \$exercise started\!\" && echo 'Read the README.md for instructions or view them in browser:' && echo \"http://gitexercises.fracz.com/e/\$exercise\" ; \ + else \ + echo 'Could not execute the start script.' && echo 'Try running the ./.start.sh script yourself.' ; \ + fi \ + else \ + echo 'Could not clean the working directory.' && echo 'Make sure that none of the files inside the working directory' && echo 'is used by another process and run git start again.'; \ + fi \ + else \ + echo \"Invalid exercise: \$exercise\" && false; \ + fi \ + else git push origin main:NextExercise 2>&1 | sed -n '/\\*\\*\\*/,/\\*\\*\\*/p' | grep -v '\\*\\*' | sed 's/remote: //g' | xargs git start | grep -v Invalid || echo 'You have passed all exercises\!'; \ + fi \ + else echo 'You need to use git start in detached HEAD'; \ + fi +}; f" + +# Add "git verify" local alias for submitting exercises solutions. +git config --local alias.verify "! f() { \ + currentBranch=\$(git rev-parse --abbrev-ref HEAD); \ + exercise=\${1-\$currentBranch}; \ + if [ \$exercise != HEAD ]; \ + then \ + if git show origin/\$exercise -- .start.sh >/dev/null 2>&1 ; \ + then \ + if [ ! -f .verification.sh ] || ./.verification.sh; \ + then \ + if ! (LC_ALL=C git status | grep 'up-to-date' >/dev/null 2>&1 || git status | grep 'up to date' >/dev/null 2>&1) ; \ + then \ + echo \"Verifying the \$exercise exercise. Hold on...\"; \ + if ! git push -f origin HEAD:\$exercise 2>&1 | sed -n '/\\*\\*\\*/,/\\*\\*\\*/p' | sed 's/remote: //g' | grep -v \"\\*\\*\" ; \ + then \ + echo 'Solution could not be verified - push failed.' && echo 'Do you have an internet connection?'; \ + fi; \ + else \ + echo \"You haven't made any progress on exercise \$exercise.\" && echo 'Did you forget to commit your changes?'; \ + fi; \ + fi; \ + else \ + echo \"Invalid exercise: \$exercise\"; \ + fi; \ + else \ + echo 'You need to use git verify in detached HEAD'; \ + fi; \ +}; f" + +# Add "git exercises" alias that shows list of available exercises. +git config --local alias.exercises "! git push origin main:Exercises 2>&1 | sed -n '/\\*\\*\\*/,/\\*\\*\\*/p' | grep -v '\\*\\*' | sed 's/remote: //g'" + +# Make sure you have a "current" push strategy set; this will allow you to push only current exercise with simple git +# push command instead of pushing all matching branches (default in Git < 2.0) +git config --local push.default current + +echo "OK" diff --git a/backend/hook/hints/Master-solution.txt b/exercises/main/solution.md similarity index 100% rename from backend/hook/hints/Master-solution.txt rename to exercises/main/solution.md diff --git a/backend/hook/verifications/Master.php b/exercises/main/verification.php similarity index 94% rename from backend/hook/verifications/Master.php rename to exercises/main/verification.php index be7763f..0be69d0 100644 --- a/backend/hook/verifications/Master.php +++ b/exercises/main/verification.php @@ -3,7 +3,7 @@ use GitExercises\hook\AbstractVerification; -class Master extends AbstractVerification +class Main extends AbstractVerification { private static $expectedContent = 'test'; diff --git a/exercises/merge-conflict/files/.start.sh b/exercises/merge-conflict/files/.start.sh new file mode 100755 index 0000000..6128555 --- /dev/null +++ b/exercises/merge-conflict/files/.start.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +git branch -D another-piece-of-work +echo 'print("? + ? = 5")' > equation.txt +git add equation.txt +git commit -m "Add equation without numbers" +git checkout -b another-piece-of-work +echo 'print("? + 3 = 5")' > equation.txt +git commit -am "Add the second number" +git checkout merge-conflict +echo 'print("2 + ? = 5")' > equation.txt +git commit -am "Add the first number" diff --git a/exercises/merge-conflict/files/README.md b/exercises/merge-conflict/files/README.md new file mode 100644 index 0000000..a5915cc --- /dev/null +++ b/exercises/merge-conflict/files/README.md @@ -0,0 +1,31 @@ +## Resolve a merge conflict + +Merge conflict appears when you change the same part of the same file differently +in the two branches you're merging together. +Conflicts require developer to solve them by hand. + +Your repository looks like this: + + HEAD + | + merge-conflict + | + A <----- B + \ + \----- C + | + another-piece-of-work + +You want to merge the `another-piece-of-work` into your current branch. +This will cause a merge conflict which you have to resolve. +Your repository should look like this: + + HEAD + | + merge-conflict + | + A <----- B <----- D + \ / + \----- C <----/ + | + another-piece-of-work diff --git a/backend/hook/hints/MergeConflict-hint.md b/exercises/merge-conflict/hint.md similarity index 100% rename from backend/hook/hints/MergeConflict-hint.md rename to exercises/merge-conflict/hint.md diff --git a/exercises/merge-conflict/solution.txt b/exercises/merge-conflict/solution.txt new file mode 100644 index 0000000..1f71e14 --- /dev/null +++ b/exercises/merge-conflict/solution.txt @@ -0,0 +1,4 @@ +git merge another-piece-of-work +echo 'print("2 + 3 = 5")' > equation.txt +git add equation.txt +git merge --continue diff --git a/backend/hook/hints/MergeConflict-summary.md b/exercises/merge-conflict/summary.md similarity index 100% rename from backend/hook/hints/MergeConflict-summary.md rename to exercises/merge-conflict/summary.md diff --git a/backend/hook/verifications/MergeConflict.php b/exercises/merge-conflict/verification.php similarity index 66% rename from backend/hook/verifications/MergeConflict.php rename to exercises/merge-conflict/verification.php index 8b5721c..05169e4 100644 --- a/backend/hook/verifications/MergeConflict.php +++ b/exercises/merge-conflict/verification.php @@ -12,8 +12,8 @@ protected function doVerify() $parents = GitUtils::getParents($mergeCommit); $this->ensure(count($parents) == 2, 'The last commit should be a merge commit.'); $lines = $this->getFileContent($mergeCommit, 'equation.txt'); - $this->ensure(count($lines) >= 1, 'You didn\'t resolve the conflict properly (too few lines).'); + $this->ensure(count($lines) == 1, 'You didn\'t resolve the conflict properly (there must be only one line).'); $equation = preg_replace('#\s+#', '', $lines[0]); - $this->ensure($equation == '2+3=5' || $equation == '3+2=5', 'You didn\'t resolve the conflict properly (expected 2+3=5 equation).'); + $this->ensure($equation == 'print("2+3=5")' || $equation == 'print("3+2=5")', 'You didn\'t resolve the conflict properly (expected 2+3=5 equation).'); } } diff --git a/exercises/modify-delete-conflict/files/.start.sh b/exercises/modify-delete-conflict/files/.start.sh new file mode 100755 index 0000000..010f39a --- /dev/null +++ b/exercises/modify-delete-conflict/files/.start.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +echo to be modified > keep.txt +echo to be deleted > delete.txt + +git add keep.txt delete.txt +git commit -m "initial commit" + +git checkout -b another + +echo This should be deleted > delete.txt +git add delete.txt +git rm keep.txt +git commit -m "More changes" + +git checkout modify-delete-conflict + +echo Changes done > keep.txt +git add keep.txt +git rm delete.txt +git commit -m "My changes" + + +git merge anothes diff --git a/exercises/modify-delete-conflict/files/.teardown.sh b/exercises/modify-delete-conflict/files/.teardown.sh new file mode 100755 index 0000000..5342743 --- /dev/null +++ b/exercises/modify-delete-conflict/files/.teardown.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +git branch -D another diff --git a/exercises/modify-delete-conflict/files/README.md b/exercises/modify-delete-conflict/files/README.md new file mode 100644 index 0000000..6325f88 --- /dev/null +++ b/exercises/modify-delete-conflict/files/README.md @@ -0,0 +1,8 @@ +#Conflit changed/deleted + +By merging your colleague's commits, two conflicts arise. Each of you modified a file that the other deleted. + +Keep the changes to the file keep.txt + +Delete the deleted file.txt + diff --git a/exercises/modify-delete-conflict/verification.php b/exercises/modify-delete-conflict/verification.php new file mode 100644 index 0000000..967c4c5 --- /dev/null +++ b/exercises/modify-delete-conflict/verification.php @@ -0,0 +1,24 @@ +ensureCommitsCount(4); + $parents = GitUtils::getParents($commits[0]); + $this->ensure(count($parents) == 2, 'The last commit should be a merge commit.'); + + + $files = GitUtils::getChangedFiles($commits[3], $commits[0]); + $this->ensure(count( $files ) == 2, "Two files should have been changed, %s were", [count($files)]); + $this->ensure(isset($files['delete.txt']), "You were supposed to remove delete.txt file."); + $this->ensure($files['delete.txt'] == 'D', "You were supposed to remove delete.txt file, not change it."); + $this->ensure(isset($files['keep.txt']), "You were supposed to modify keep.txt file."); + $this->ensure($files['keep.txt'] == 'M', "You were supposed to modify keep.txt file, not delete it."); + } +} diff --git a/exercises/more-conflicts/files/.start.sh b/exercises/more-conflicts/files/.start.sh new file mode 100755 index 0000000..bbb60fa --- /dev/null +++ b/exercises/more-conflicts/files/.start.sh @@ -0,0 +1,629 @@ +#!/usr/bin/env bash + +cat > additions.txt < subs.txt < additions.txt < subs.txt < additions.txt < subs.txt </dev/null)" = "1" ] + then + echo $eq + fi +done < additions.txt | uniq > additions_2.txt +mv additions_2.txt additions.txt + +while read eq +do + if [ "$(echo $eq|sed 's/=/==/'| bc 2>/dev/null)" = "1" ] + then + echo $eq + fi +done < subs.txt | uniq > subs_2.txt +mv subs_2.txt subs.txt + +# Validation +git add additions.txt subs.txt +git commit --no-edit diff --git a/exercises/more-conflicts/verification.php b/exercises/more-conflicts/verification.php new file mode 100644 index 0000000..74415bd --- /dev/null +++ b/exercises/more-conflicts/verification.php @@ -0,0 +1,21 @@ +ensureCommitsCount(4)[0]; + $parents = GitUtils::getParents($mergeCommit); + $this->ensure(count($parents) == 2, 'The last commit should be a merge commit.'); + $adds = implode("\n", $this->getFileContent($mergeCommit, 'additions.txt')); + $subs = implode("\n", $this->getFileContent($mergeCommit, 'subs.txt')); + $this->ensure(! (strpos($adds, "<") || strpos($adds, ">") || strpos($adds, "==") ), "Did you leave conflict marks?"); + $this->ensure(! (strpos($subs, "<") || strpos($subs, ">") || strpos($subs, "==") ), "Did you leave conflict marks?"); + $this->ensure($adds == "934 + 6339 = 7273\n18505 + 17201 = 35706\n12172 + 27394 = 39566\n2247 + 26966 = 29213\n32504 + 9058 = 41562\n7619 + 12380 = 19999\n3239 + 13605 = 16844\n9105 + 6193 = 15298\n25368 + 4386 = 29754\n26352 + 16196 = 42548\n23671 + 23237 = 46908\n28889 + 13536 = 42425\n26324 + 4540 = 30864\n11585 + 22039 = 33624\n9922 + 19456 = 29378\n24341 + 13292 = 37633\n21016 + 14311 = 35327\n31016 + 19745 = 50761\n20943 + 25628 = 46571\n1368 + 16613 = 17981\n534 + 9372 = 9906\n13542 + 21478 = 35020\n26027 + 7592 = 33619\n24700 + 8963 = 33663\n20535 + 28649 = 49184\n8471 + 27315 = 35786\n7792 + 22259 = 30051\n7766 + 10114 = 17880\n24607 + 29894 = 54501\n10421 + 28250 = 38671\n19295 + 15972 = 35267\n22430 + 26322 = 48752\n31785 + 22084 = 53869\n13836 + 17136 = 30972\n3156 + 29016 = 32172\n25178 + 355 = 25533\n20758 + 28156 = 48914\n17510 + 4770 = 22280\n8010 + 4615 = 12625\n13582 + 24973 = 38555\n24204 + 32572 = 56776\n30960 + 1782 = 32742\n12019 + 21638 = 33657\n20246 + 18817 = 39063\n13686 + 28522 = 42208\n21201 + 16642 = 37843\n4567 + 7896 = 12463\n16002 + 24293 = 40295\n12861 + 21565 = 34426\n29211 + 23055 = 52266\n9700 + 22131 = 31831\n30574 + 23287 = 53861\n20902 + 8842 = 29744\n8357 + 317 = 8674\n32588 + 7941 = 40529\n14742 + 17700 = 32442\n23140 + 6198 = 29338\n26235 + 2713 = 28948\n15721 + 23447 = 39168\n32647 + 814 = 33461\n8155 + 11950 = 20105\n15444 + 10948 = 26392\n22914 + 26632 = 49546\n23247 + 12940 = 36187\n28843 + 10645 = 39488\n4875 + 27624 = 32499\n29344 + 20738 = 50082\n7048 + 13599 = 20647\n150 + 32693 = 32843\n15241 + 26129 = 41370\n25972 + 1915 = 27887\n16553 + 30003 = 46556\n10785 + 9060 = 19845\n22562 + 21506 = 44068\n21732 + 17770 = 39502\n15492 + 5415 = 20907\n25 + 1611 = 1636\n30964 + 31112 = 62076\n15733 + 16147 = 31880\n22384 + 13172 = 35556\n29860 + 28201 = 58061\n4812 + 2027 = 6839\n16675 + 6481 = 23156\n30247 + 6582 = 36829\n724 + 6918 = 7642\n11072 + 26047 = 37119\n11191 + 26237 = 37428\n32758 + 15109 = 47867\n10628 + 20205 = 30833\n14418 + 7956 = 22374\n3320 + 2020 = 5340\n22466 + 29419 = 51885\n23762 + 23529 = 47291\n19159 + 26040 = 45199\n26389 + 19601 = 45990\n2088 + 29408 = 31496\n1967 + 13605 = 15572\n26354 + 25405 = 51759\n11797 + 8635 = 20432\n26314 + 24473 = 50787", "Something is wrong double-check your calculations"); + $this->ensure($subs == "4498 - 4316 = 182\n8139 - 13413 = -5274\n4190 - 17299 = -13109\n8810 - 20056 = -11246\n2678 - 28630 = -25952\n23522 - 27228 = -3706\n267 - 8854 = -8587\n13753 - 18566 = -4813\n3995 - 23352 = -19357\n10443 - 17727 = -7284\n18492 - 26611 = -8119\n11076 - 22230 = -11154\n21476 - 1176 = 20300\n27062 - 16390 = 10672\n4851 - 21989 = -17138\n22442 - 12431 = 10011\n8941 - 27284 = -18343\n4333 - 21247 = -16914\n18256 - 30609 = -12353\n4929 - 2381 = 2548\n31574 - 25238 = 6336\n27555 - 29355 = -1800\n6620 - 13085 = -6465\n28332 - 11740 = 16592\n30629 - 615 = 30014\n15258 - 6678 = 8580\n6593 - 29753 = -23160\n6811 - 24329 = -17518\n14822 - 19351 = -4529\n24873 - 12283 = 12590\n23788 - 8757 = 15031\n24092 - 10494 = 13598\n21710 - 30939 = -9229\n21021 - 26883 = -5862\n22051 - 18067 = 3984\n29239 - 1997 = 27242\n24620 - 25801 = -1181\n6775 - 21336 = -14561\n32382 - 28932 = 3450\n20913 - 5126 = 15787\n66 - 25644 = -25578\n4757 - 28093 = -23336\n15938 - 32414 = -16476\n15796 - 21157 = -5361\n10671 - 24619 = -13948\n32568 - 15249 = 17319\n1195 - 21995 = -20800\n8088 - 18449 = -10361\n9544 - 27843 = -18299\n19285 - 21436 = -2151\n362 - 22636 = -22274\n10665 - 31350 = -20685\n1062 - 31303 = -30241\n14441 - 18825 = -4384\n30586 - 23802 = 6784\n8292 - 6141 = 2151\n20963 - 29668 = -8705\n21867 - 18814 = 3053\n9939 - 20007 = -10068\n10602 - 25624 = -15022\n5105 - 9394 = -4289\n10751 - 40 = 10711\n20270 - 342 = 19928\n31454 - 10751 = 20703\n11326 - 31059 = -19733\n22850 - 7890 = 14960\n32436 - 4648 = 27788\n17041 - 3663 = 13378\n21340 - 26142 = -4802\n1054 - 20398 = -19344\n9184 - 15387 = -6203\n26260 - 878 = 25382\n4697 - 22796 = -18099\n5409 - 16241 = -10832\n29957 - 20303 = 9654\n8175 - 24778 = -16603\n22103 - 31674 = -9571\n15301 - 32285 = -16984\n17490 - 2827 = 14663\n3653 - 26909 = -23256\n8480 - 30767 = -22287\n26003 - 10190 = 15813\n3804 - 23784 = -19980\n9139 - 9452 = -313\n15209 - 21367 = -6158\n878 - 1378 = -500\n30247 - 4601 = 25646\n15570 - 7427 = 8143\n16799 - 31441 = -14642\n28524 - 20872 = 7652\n8030 - 6978 = 1052\n29921 - 19768 = 10153\n15416 - 31126 = -15710\n17503 - 15934 = 1569\n8860 - 24692 = -15832\n15244 - 1276 = 13968\n16100 - 10508 = 5592\n14798 - 5571 = 9227\n25315 - 15963 = 9352\n25203 - 11043 = 14160", "Something is wrong double-check your calculations"); + } +} diff --git a/exercises/new-branch/files/.start.sh b/exercises/new-branch/files/.start.sh new file mode 100755 index 0000000..a76e46c --- /dev/null +++ b/exercises/new-branch/files/.start.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +(git branch origin/old-branch; #simulate the remote exercise so it doesnt seem invalid\ + git checkout -b old-branch; \ + touch new_file && \ + git add new_file && \ + git commit -m "new_file" && \ + git branch -D new-branch ) &>/dev/null diff --git a/exercises/new-branch/files/.teardown.sh b/exercises/new-branch/files/.teardown.sh new file mode 100644 index 0000000..b3730b7 --- /dev/null +++ b/exercises/new-branch/files/.teardown.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +if ! git checkout new-branch +then + git checkout -b new-branch +fi + +git branch -D old-branch diff --git a/exercises/new-branch/files/.verification.sh b/exercises/new-branch/files/.verification.sh new file mode 100644 index 0000000..de5c20a --- /dev/null +++ b/exercises/new-branch/files/.verification.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +#Verify the exercice even if the new-branch was not checked out + +currentBranch=$(git rev-parse --abbrev-ref HEAD); +exercise=${1-$currentBranch}; + +if [ $exercise = "old-branch" ] +then + if ! git push -f origin new-branch 2>&1 | sed -n '/\*\*\*/,/\*\*\*/p' | sed 's/remote: //g' | grep -v "\*\*" + then + echo "new branch doesn't exist" + fi + exit 1 +fi diff --git a/exercises/new-branch/files/README.md b/exercises/new-branch/files/README.md new file mode 100644 index 0000000..d2bc22c --- /dev/null +++ b/exercises/new-branch/files/README.md @@ -0,0 +1,5 @@ +#Créer a new branch + +With Git, it's easy to create a new branch to start a new task. + +Create the new-branch from the old-branch. diff --git a/exercises/new-branch/hint.md b/exercises/new-branch/hint.md new file mode 100644 index 0000000..f3e7c84 --- /dev/null +++ b/exercises/new-branch/hint.md @@ -0,0 +1 @@ +The command `git branch` creates a branch from HEAD. diff --git a/exercises/new-branch/solution.txt b/exercises/new-branch/solution.txt new file mode 100644 index 0000000..888adb9 --- /dev/null +++ b/exercises/new-branch/solution.txt @@ -0,0 +1 @@ +git branch new-branch diff --git a/exercises/new-branch/verification.php b/exercises/new-branch/verification.php new file mode 100644 index 0000000..c8837ef --- /dev/null +++ b/exercises/new-branch/verification.php @@ -0,0 +1,14 @@ +ensureCommitsCount(1); + } +} diff --git a/exercises/pick-your-features/files/.start.sh b/exercises/pick-your-features/files/.start.sh new file mode 100755 index 0000000..abddd3c --- /dev/null +++ b/exercises/pick-your-features/files/.start.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +echo "This is base version of the program." > program.txt +echo "It has only two lines at the beginning." >> program.txt +git add program.txt +git commit -m "Base version of a program" + +git branch -D feature-a +git checkout -b feature-a +echo "This is complete feature A" >> program.txt +git commit -am "Implement Feature A" + +git branch -D feature-b +git checkout HEAD^ +git checkout -b feature-b +mv program.txt program_temp.txt +echo "This is complete feature B" > program.txt +cat program_temp.txt >> program.txt +rm program_temp.txt +git commit -am "Implement Feature B" + +git branch -D feature-c +git branch feature-c HEAD^ +git checkout feature-c +echo "This is first part Feature C" >> program.txt +git commit -am "Implement part of Feature C" +echo "This is second part of Feature C" >> program.txt +git commit -am "Complete Feature C" + +git checkout pick-your-features diff --git a/exercises/pick-your-features/files/README.md b/exercises/pick-your-features/files/README.md new file mode 100644 index 0000000..3d8c7f3 --- /dev/null +++ b/exercises/pick-your-features/files/README.md @@ -0,0 +1,16 @@ +## Pick your features +You have implemented three different features of a program in three different local topic branches. + + HEAD ---- B - feature-b + | / + pick-your-features - Z <--- A - feature-a + \ + ---- C1 <--- C2 - feature-c + +You want to have all these features as single commits in `pick-your-features` branch. + + HEAD + | + pick-your-features + | + Z <--- A <--- B <--- C diff --git a/backend/hook/hints/PickYourFeatures-hint.md b/exercises/pick-your-features/hint.md similarity index 100% rename from backend/hook/hints/PickYourFeatures-hint.md rename to exercises/pick-your-features/hint.md diff --git a/backend/hook/hints/PickYourFeatures-solution.txt b/exercises/pick-your-features/solution.txt similarity index 100% rename from backend/hook/hints/PickYourFeatures-solution.txt rename to exercises/pick-your-features/solution.txt diff --git a/backend/hook/hints/PickYourFeatures-summary.md b/exercises/pick-your-features/summary.md similarity index 100% rename from backend/hook/hints/PickYourFeatures-summary.md rename to exercises/pick-your-features/summary.md diff --git a/backend/hook/verifications/PickYourFeatures.php b/exercises/pick-your-features/verification.php similarity index 100% rename from backend/hook/verifications/PickYourFeatures.php rename to exercises/pick-your-features/verification.php diff --git a/exercises/rebase-complex/files/.start.sh b/exercises/rebase-complex/files/.start.sh new file mode 100755 index 0000000..d19efff --- /dev/null +++ b/exercises/rebase-complex/files/.start.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +echo "Hello" > file.txt +git add file.txt +git commit -m "Base commit for rebase complex" + +git branch -D your-master +git checkout -b your-master +echo "World" >> file.txt +git commit -am "First commit in your-master" +echo "Or mundo" >> file.txt +git commit -am "Second commit in your-master" + +git checkout rebase-complex +echo "Issue" > issue.txt +git add issue.txt +git commit -m "First issue commit" +echo "Bug" > bug.txt +git add bug.txt +git commit -m "First commit fixing bug" +echo "Bug fixed!" >> bug.txt +git commit -am "Bug finally fixed" + +git checkout HEAD^^ +git branch -D issue-555 +git checkout -b issue-555 +echo "More work on issue" >> issue.txt +git commit -am "More work on issue" +echo "Even more work on issue" >> issue.txt +git commit -am "Evnt more work on issue" + +git checkout rebase-complex diff --git a/exercises/rebase-complex/files/README.md b/exercises/rebase-complex/files/README.md new file mode 100644 index 0000000..4d73a83 --- /dev/null +++ b/exercises/rebase-complex/files/README.md @@ -0,0 +1,24 @@ +## Rebase complex + +You were working on an `issue-555` topic branch. You noticed a bug, which you fixed in `rebase-complex` topic branch. +Then, you finished `issue-555`. + +However, you need to have bug fixed in `your-master` branch without any work done on `issue-555`. + +Situation is as follows: + + your-master + | + A <--- B <--- C <--- D + \ + E <--- F <--- G - issue-555 + \ + H <--- I + | + rebase-complex + | + HEAD + +Only `H` and `I` commits should be rebased onto `D`. + +Try to do this with a single git command. diff --git a/backend/hook/hints/RebaseComplex-hint.md b/exercises/rebase-complex/hint.md similarity index 100% rename from backend/hook/hints/RebaseComplex-hint.md rename to exercises/rebase-complex/hint.md diff --git a/backend/hook/hints/RebaseComplex-solution.txt b/exercises/rebase-complex/solution.txt similarity index 100% rename from backend/hook/hints/RebaseComplex-solution.txt rename to exercises/rebase-complex/solution.txt diff --git a/backend/hook/hints/RebaseComplex-summary.md b/exercises/rebase-complex/summary.md similarity index 100% rename from backend/hook/hints/RebaseComplex-summary.md rename to exercises/rebase-complex/summary.md diff --git a/backend/hook/verifications/RebaseComplex.php b/exercises/rebase-complex/verification.php similarity index 100% rename from backend/hook/verifications/RebaseComplex.php rename to exercises/rebase-complex/verification.php diff --git a/exercises/remove-ignored/files/.start.sh b/exercises/remove-ignored/files/.start.sh new file mode 100755 index 0000000..ce41dd0 --- /dev/null +++ b/exercises/remove-ignored/files/.start.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +echo "This should be ignored" > ignored.txt +git add ignored.txt +git commit -m "Add ignored.txt" +echo "ignored.txt" > .gitignore +git add .gitignore +git commit -m "Ignore ignored.txt" diff --git a/exercises/remove-ignored/files/README.md b/exercises/remove-ignored/files/README.md new file mode 100644 index 0000000..ff2f7c9 --- /dev/null +++ b/exercises/remove-ignored/files/README.md @@ -0,0 +1,5 @@ +## Remove ignored file +File `ignored.txt` is ignored by rule in `.gitignore` but is tracked because it had been added before the ignoring rule +was introduced. + +Remove it so changes in `ignored.txt` file are not tracked anymore. diff --git a/backend/hook/hints/RemoveIgnored-hint.md b/exercises/remove-ignored/hint.md similarity index 100% rename from backend/hook/hints/RemoveIgnored-hint.md rename to exercises/remove-ignored/hint.md diff --git a/backend/hook/hints/RemoveIgnored-solution.txt b/exercises/remove-ignored/solution.txt similarity index 100% rename from backend/hook/hints/RemoveIgnored-solution.txt rename to exercises/remove-ignored/solution.txt diff --git a/backend/hook/hints/RemoveIgnored-summary.md b/exercises/remove-ignored/summary.md similarity index 100% rename from backend/hook/hints/RemoveIgnored-summary.md rename to exercises/remove-ignored/summary.md diff --git a/backend/hook/verifications/RemoveIgnored.php b/exercises/remove-ignored/verification.php similarity index 100% rename from backend/hook/verifications/RemoveIgnored.php rename to exercises/remove-ignored/verification.php diff --git a/exercises/save-your-work/files/.start.sh b/exercises/save-your-work/files/.start.sh new file mode 100755 index 0000000..46013cb --- /dev/null +++ b/exercises/save-your-work/files/.start.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +echo "This file contains bug" > bug.txt +echo "It has to be somewhere." >> bug.txt +echo "I feel like I can smell it." >> bug.txt +echo "THIS IS A BUG - remove the whole line to fix it." >> bug.txt +echo "How this program could work with such bug?" >> bug.txt +echo "This is a completely working program." > program.txt +echo "This has been written in Brainfuck" >> program.txt +echo "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>." >> program.txt +git add bug.txt +git add program.txt +git commit -m "Excellent version with a bug" +echo "This is the work I have done recently." >> bug.txt +echo "I would be very sad if I loose it." >> bug.txt +echo "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>." > program.txt +echo ",----------[----------------------.,----------]" >> program.txt +echo ",>,>++++++++[<------<------>>-]." >> program.txt +echo "<<[>[>+>+<<-]>>[<<+>>-]<<<-]" >> program.txt +echo ">>>++++++[<++++++++>-]<." >> program.txt diff --git a/exercises/save-your-work/files/README.md b/exercises/save-your-work/files/README.md new file mode 100644 index 0000000..5a11bd6 --- /dev/null +++ b/exercises/save-your-work/files/README.md @@ -0,0 +1,15 @@ +## Saving your work +You are working hard on a regular issue while your boss comes in and wants you to fix a bug. State of your current +working area is a total mess so you don't feel comfortable with making a commit now. However, you need to fix the found +bug ASAP. + +Git lets you to save your work *on a side* and continue it later. Find appropriate Git tool and use it to handle +the situation appropriately. + +Look for a bug to remove in `bug.txt`. + +After you commit the bugfix, get back to your work. Finish it by adding a new line to `bug.txt` with + + Finally, finished it! + +Then, commit your work after bugfix. diff --git a/backend/hook/hints/SaveYourWork-hint.md b/exercises/save-your-work/hint.md similarity index 100% rename from backend/hook/hints/SaveYourWork-hint.md rename to exercises/save-your-work/hint.md diff --git a/backend/hook/hints/SaveYourWork-solution.txt b/exercises/save-your-work/solution.txt similarity index 87% rename from backend/hook/hints/SaveYourWork-solution.txt rename to exercises/save-your-work/solution.txt index 65c3550..0487af0 100644 --- a/backend/hook/hints/SaveYourWork-solution.txt +++ b/exercises/save-your-work/solution.txt @@ -1,5 +1,6 @@ git stash # fix a bug +sed -i '4d' bug.txt git commit -am "Fix a bug" git stash pop echo "Finally, finished it!" >> bug.txt diff --git a/backend/hook/hints/SaveYourWork-summary.md b/exercises/save-your-work/summary.md similarity index 100% rename from backend/hook/hints/SaveYourWork-summary.md rename to exercises/save-your-work/summary.md diff --git a/backend/hook/verifications/SaveYourWork.php b/exercises/save-your-work/verification.php similarity index 100% rename from backend/hook/verifications/SaveYourWork.php rename to exercises/save-your-work/verification.php diff --git a/exercises/split-commit/files/.start.sh b/exercises/split-commit/files/.start.sh new file mode 100755 index 0000000..4fab97e --- /dev/null +++ b/exercises/split-commit/files/.start.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +echo "First" > first.txt +echo "Second" > second.txt +git add first.txt second.txt +git commit -m "This commit needs to be splitted" diff --git a/exercises/split-commit/files/README.md b/exercises/split-commit/files/README.md new file mode 100644 index 0000000..6e6fd27 --- /dev/null +++ b/exercises/split-commit/files/README.md @@ -0,0 +1,3 @@ +## Split the last commit +You have committed both `first.txt` and `second.txt` as one commit. However, you made a mistake. You intended to commit +`first.txt` in the first commit and the `second.txt` in the second one. diff --git a/backend/hook/hints/SplitCommit-hint.md b/exercises/split-commit/hint.md similarity index 100% rename from backend/hook/hints/SplitCommit-hint.md rename to exercises/split-commit/hint.md diff --git a/backend/hook/hints/SplitCommit-solution.txt b/exercises/split-commit/solution.txt similarity index 100% rename from backend/hook/hints/SplitCommit-solution.txt rename to exercises/split-commit/solution.txt diff --git a/backend/hook/hints/SplitCommit-summary.md b/exercises/split-commit/summary.md similarity index 100% rename from backend/hook/hints/SplitCommit-summary.md rename to exercises/split-commit/summary.md diff --git a/backend/hook/verifications/SplitCommit.php b/exercises/split-commit/verification.php similarity index 100% rename from backend/hook/verifications/SplitCommit.php rename to exercises/split-commit/verification.php diff --git a/exercises/too-many-commits/files/.start.sh b/exercises/too-many-commits/files/.start.sh new file mode 100755 index 0000000..c63ceb7 --- /dev/null +++ b/exercises/too-many-commits/files/.start.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +echo "This is the first line." > file.txt +git add file.txt +git commit -am "Add file.txt" +echo "This is the second line I have forgotten." >> file.txt +git commit -am "Crap, I have forgotten to add this line." diff --git a/exercises/too-many-commits/files/README.md b/exercises/too-many-commits/files/README.md new file mode 100644 index 0000000..a6a2e7c --- /dev/null +++ b/exercises/too-many-commits/files/README.md @@ -0,0 +1,6 @@ +## Too many commits + +You were working on an issue and created two commits introducing very small change. You don't want to mess up your +project history so you want to make only one commit that contains changes made in the last two. + +Execute `git log -2` to see last two commits. diff --git a/backend/hook/hints/TooManyCommits-hint.md b/exercises/too-many-commits/hint.md similarity index 100% rename from backend/hook/hints/TooManyCommits-hint.md rename to exercises/too-many-commits/hint.md diff --git a/backend/hook/hints/TooManyCommits-solution.txt b/exercises/too-many-commits/solution.txt similarity index 100% rename from backend/hook/hints/TooManyCommits-solution.txt rename to exercises/too-many-commits/solution.txt diff --git a/backend/hook/hints/TooManyCommits-summary.md b/exercises/too-many-commits/summary.md similarity index 100% rename from backend/hook/hints/TooManyCommits-summary.md rename to exercises/too-many-commits/summary.md diff --git a/backend/hook/verifications/TooManyCommits.php b/exercises/too-many-commits/verification.php similarity index 100% rename from backend/hook/verifications/TooManyCommits.php rename to exercises/too-many-commits/verification.php diff --git a/exercises/too-many-conflicts/files/.start.sh b/exercises/too-many-conflicts/files/.start.sh new file mode 100755 index 0000000..4fd53e9 --- /dev/null +++ b/exercises/too-many-conflicts/files/.start.sh @@ -0,0 +1,629 @@ +#!/usr/bin/env bash + +cat > additions.txt < subs.txt < additions.txt < subs.txt < additions.txt < subs.txt <ensureCommitsCount(2); + $message = GitUtils::getCommitSubject($commits[0]); + $this->ensure($message == 'Additions and substractions completed', 'This should not have been commited : %s', [ConsoleUtils::blue($message)]); + } +} diff --git a/frontend/app/committer/committer.html b/frontend/app/committer/committer.html index 9fc488c..a256838 100644 --- a/frontend/app/committer/committer.html +++ b/frontend/app/committer/committer.html @@ -5,7 +5,7 @@

We could not find any attempt made by this user.

Is {{ committerEmail || 'it' }} you? Go and do the first exercise!

-
+

{{ committerData.committerName }}

diff --git a/frontend/app/home/home-faq.html b/frontend/app/home/home-faq.html index dc824c1..3f01536 100644 --- a/frontend/app/home/home-faq.html +++ b/frontend/app/home/home-faq.html @@ -5,8 +5,8 @@

Why do you need my e-mail?

What does ./configure.sh do?

It configures git aliases to facilitate switching between tasks, starting them etc. It does not influence your global git configuration. Still in doubt? Go and check it yourself.

+ href="https://github.com/fracz/git-exercises/blob/main/configure.sh">check it yourself.

And the git start?

That is the first alias configured by the script described above. It initializes the - first exercise that is on master branch. Read the instructions + first exercise that is on main branch. Read the instructions and solve it!

diff --git a/frontend/app/home/start-commands.html b/frontend/app/home/start-commands.html index b7807b0..af74c5a 100644 --- a/frontend/app/home/start-commands.html +++ b/frontend/app/home/start-commands.html @@ -1,5 +1,5 @@
-