Repository: unkontributors/super_unko Branch: oshiri Commit: a73b56dc01a6 Files: 65 Total size: 131.4 KB Directory structure: gitextract_nf5gjjz4/ ├── .github/ │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── release.yml │ └── unko.yml ├── .tar2package.yml ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── activate.sh ├── bin/ │ ├── bigunko.show │ ├── super_unko │ ├── unko.any │ ├── unko.encode │ ├── unko.fizzbuzz │ ├── unko.grep │ ├── unko.king │ ├── unko.life │ ├── unko.ls │ ├── unko.ping │ ├── unko.printpnm │ ├── unko.puzzle │ ├── unko.pyramid │ ├── unko.question │ ├── unko.say │ ├── unko.shout │ ├── unko.think │ ├── unko.toilet │ ├── unko.tower │ ├── unko.tr │ └── unko.yes ├── doc/ │ ├── ci-push.puml │ ├── unko.puzzle.md │ └── unko.toilet.md ├── docker/ │ ├── Dockerfile │ └── install_bash.sh ├── docker-compose-ci.yml ├── docker-compose.yml ├── install.sh ├── lib/ │ └── super_unko/ │ ├── bigunko.txt │ ├── unko.cow │ ├── unko.csv │ ├── unko.lib │ ├── unko_command_not_found_hundle │ └── unko_mb.cow ├── linter.sh ├── package.sh ├── pkg/ │ ├── super_unko.deb │ └── super_unko.rpm ├── super_unko.plugin.zsh ├── test/ │ ├── functions.sh │ ├── super_unko-test.bats │ ├── unko.any-test.bats │ ├── unko.encode-test.bats │ ├── unko.fizzbuzz-test.bats │ ├── unko.grep-test.bats │ ├── unko.king-test.bats │ ├── unko.printpnm-test.bats │ ├── unko.pyramid-test.bats │ ├── unko.toilet-test.bats │ ├── unko.tower-test.bats │ ├── unko.tr-test.bats │ └── unko.yes-test.bats ├── test.sh ├── uninstall.sh └── 💩.💩 ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Check list * [ ] Were all tests passed of CI? * (Case: failing `test`) Please run tests and fix your code (see also: [Testing](https://github.com/unkontributors/super_unko/blob/oshiri/README.md#testing)) * (Case: failing `format`) Please run `./linter.sh format-save` (see also: [CodeStyle and lint](https://github.com/unkontributors/super_unko/blob/oshiri/README.md#codestyle-and-lint)) * (Case: failing `lint`) Please run linter and fix your code (see also: [CodeStyle and lint](https://github.com/unkontributors/super_unko/blob/oshiri/README.md#codestyle-and-lint)) * [ ] (Case: adding new command) Were tests added to cover new commands ? * [ ] (Case: adding new command) Were descriptions for new commands added to README? ================================================ FILE: .github/workflows/release.yml ================================================ name: release on: release: types: [published] jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - name: Set output id: vars run: echo ::set-output name=tag::${GITHUB_REF:10} - name: Set tag to .tar2package.yml run: sed -i 's:\$VERSION:${{ steps.vars.outputs.tag }}:g' .tar2package.yml - run: Print .tar2package.yml - name: Generate packages run: ./package.sh - name: Release uses: softprops/action-gh-release@v1 with: files: - pkg/*.deb - pkg/*.rpm env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/unko.yml ================================================ name: test on: push: branches: - oshiri paths-ignore: - 'LICENSE' - 'README.*' - 'doc/*' - 'img/*' - 'pkg/*' pull_request: paths-ignore: - 'LICENSE' - 'README.*' - 'doc/*' - 'img/*' - 'pkg/*' env: APP_NAME: super_unko DOCKER_BUILDKIT: 1 jobs: skip: runs-on: ubuntu-latest steps: - run: echo "Skip job" before: runs-on: ubuntu-latest if: "! contains(github.event.head_commit.message, '[skip ci]')" steps: - run: echo "no [skip ci]" test: runs-on: ubuntu-latest strategy: matrix: version: [default, "3.2", "4.0", "4.1", "4.2", "4.3", "4.4", "5.0"] needs: before steps: - uses: actions/checkout@v2 # FIXME: #95 # - uses: satackey/action-docker-layer-caching@v0.0.8 # with: # key: docker-image-cache-${{ matrix.version }}-{hash} # restore-keys: | # docker-image-cache-${{ matrix.version }}- - name: Test run: docker-compose -f docker-compose-ci.yml run ci_sh_${{ matrix.version }} format: runs-on: ubuntu-latest needs: before steps: - uses: actions/checkout@v2 - name: Run format run: ./linter.sh format lint: runs-on: ubuntu-latest needs: before steps: - uses: actions/checkout@v2 - name: Run lint run: ./linter.sh lint update-repository: runs-on: ubuntu-latest needs: [test, format, lint] if: github.ref == 'refs/heads/oshiri' steps: - uses: actions/checkout@v2 with: fetch-depth: 0 # deb, rpmファイルの生成 - name: Set latest tag version to output id: vars run: echo ::set-output name=tag::$(git tag -l '*.*.*' | sort -V | tail -n 1) - name: Set tag version to .tar2package.yml run: sed -i 's:\$VERSION:${{ steps.vars.outputs.tag }}:g' .tar2package.yml - name: Print .tar2package.yml run: cat .tar2package.yml - name: Generate packages run: ./package.sh - name: Git commit packages run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add pkg/* git commit -m ":arrow_up: [CI] update pkg/${{ env.APP_NAME }}.deb and pkg/${{ env.APP_NAME }}.rpm" # READMEに目次を埋め込む - name: Install gh-md-toc run: | wget https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc chmod +x gh-md-toc - name: Insert TOC run: | ./gh-md-toc --insert *.md doc/*.md rm *.md.orig.* rm *.md.toc.* rm doc/*.md.orig.* rm doc/*.md.toc.* - name: Git commit documents run: | git add *.md doc/*.md git commit -m ":memo: [CI] update TOC" - name: Git push uses: ad-m/github-push-action@v0.5.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} branch: oshiri ================================================ FILE: .tar2package.yml ================================================ name : superunko cmdname : superunko summary : Super Unko description : super_unko project is the one of the awesome, clean and sophisticated OSS project in the world. Let us create shit commands. version : $VERSION changelog : unko.tower power up url : https://github.com/unkontributors/super_unko author : Awesome Unkontributors email : super@unko.com libdir : /usr/lib ================================================ FILE: .travis.yml ================================================ language: bash env: global: - PATH=${PATH}:${HOME}/kcov/bin addons: apt: packages: - binutils-dev - libcurl4-openssl-dev - libdw-dev - libiberty-dev - bats before_install: # kcov - coverage - wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz install: # kcov - tar xzf master.tar.gz - cd kcov-master - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=${HOME}/kcov .. - make - make install - cd ../.. - rm -rf kcov-master - mkdir -p coverage script: - | if [[ "$SH_VERSION" == default ]]; then # コンテナ経由で実行しようとすると失敗するのでしかたなく直接実行 ./test.sh || true fi after_success: # ダミーで送信 - | if [[ "$SH_VERSION" == default ]]; then kcov --coveralls-id=$TRAVIS_JOB_ID test/coverage bin/unko.tower 3 fi ================================================ FILE: LICENSE ================================================ 💩 License Copyright (c) 2017 greymd Permission is hereby granted, free of charge, to any person obtaining a copy of this 💩 and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 💩, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial 💩 of the Software. THE SOFTWARE IS PROVIDED "💩", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ .PHONY: default default: usage .PHONY: usage usage: ## Print help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: setup setup: ## Setup docker images docker-compose build docker-compose -f docker-compose-ci.yml build .PHONY: check check: test lint ## Run tests and linter .PHONY: lint lint: ## Run linter ./linter.sh all .PHONY: test test: ## Run tests docker-compose -f docker-compose-ci.yml run --rm ci_sh_5.0 .PHONY: test-bash-version test-bash-version: ## Run test all bash version docker-compose -f docker-compose-ci.yml up .PHONY: clean package: ## Build packages ./package.sh .PHONY: clean clean: ## Clean packages $(RM) super_unko.tar.gz pkg/*.tmp ================================================ FILE: README.md ================================================

[![License](https://img.shields.io/badge/license-%F0%9F%92%A9-orange.svg)](./LICENSE) [![Build Status](https://travis-ci.org/unkontributors/super_unko.svg?branch=oshiri)](https://travis-ci.org/unkontributors/super_unko) [![Coverage Status](https://coveralls.io/repos/github/unkontributors/super_unko/badge.svg?branch=oshiri)](https://coveralls.io/github/unkontributors/super_unko?branch=oshiri) ![GitHub Actions Build Status](https://github.com/unkontributors/super_unko/workflows/test/badge.svg) super_unko project is the one of the awesome, clean and sophisticated OSS project in the world. Let's create poop commands! super_unko プロジェクトは世界で最もクリーンで洗練されたOSSプロジェクトの一つです。 うんこなコマンドを作りましょう。 Table of Contents * [Commands](README.md#commands) * [Installation](README.md#installation) * [Linux](README.md#linux) * [With yum (RHEL compatible distros)](README.md#with-yum-rhel-compatible-distros) * [With apt (Debian base distros)](README.md#with-apt-debian-base-distros) * [With AUR (ArchLinux base distros)](README.md#with-aur-archlinux-base-distros) * [macOS](README.md#macos) * [Docker](README.md#docker) * [Zsh plugin manager](README.md#zsh-plugin-manager) * [Additional Installation](README.md#additional-installation) * [Usage](README.md#usage) * [Development](README.md#development) * [Codestyle and lint](README.md#codestyle-and-lint) * [Help](README.md#help) * [Code format](README.md#code-format) * [Code format and save](README.md#code-format-and-save) * [Code lint](README.md#code-lint) * [Code format and lint](README.md#code-format-and-lint) * [Testing](README.md#testing) * [CI workflow](README.md#ci-workflow) * [Contribution](README.md#contribution) * [LICENSE](README.md#license) * [Source Code](README.md#source-code) * [Logo](README.md#logo) * [History](README.md#history) * [For Unkontributors (開発者向け)](README.md#for-unkontributors-開発者向け) Commands ======================== | Command | Description | |---------------|-------------| | super_unko | Controles sub unkommands | | unko.tr | Convert various expressions equals to poop into 💩 (poop). | | unko.ls | Shows various poop expression. | | unko.yes | Generate 💩 poop forever. | | unko.tower | Build your poop tower. | | unko.pyramid | Build your poop pyramid. | | bigunko.show | Big poop. | | unko.printpnm | Generate 💩 PNM image file. | | unko.puzzle | Sliding block puzzle. | | unko.toilet | Display large 💩 characters. | | unko.grep | Print lines matching a 💩 pattern. | | unko.say | King 💩 says a message. | | unko.shout | King 💩 shouts a message. | | unko.think | King 💩 thinks something. | | unko.life | Play 💩's game of life. | | unko.any | Simple wrapper to 💩 substitution for unko.shout. | | unko.king | Build your king shift tower. | | unko.fizzbuzz | No need to implement FizzBuzz. | | unko.ping | Ping the 💩 domain. | | unko.encode | Encode/Decode data and print to standard output. | | unko.date | TBD | | unko.awk | TBD | | unko.xargs | TBD | Installation ======================== ## Linux ### With `yum` (RHEL compatible distros) ``` $ sudo yum install https://git.io/superunko.linux.rpm ``` Uninstall (not `super_unko`) ``` $ sudo yum remove superunko ``` ### With `apt` (Debian base distros) ``` $ wget https://git.io/superunko.linux.deb $ sudo dpkg -i ./superunko.linux.deb ``` Uninstall (not `super_unko`) ``` $ sudo apt remove superunko ``` ### With AUR (ArchLinux base distros) You can install `super_unko` from https://aur.archlinux.org/packages/super_unko-git/ with your favorite aur helper. e.g. with yay: ``` $ yay -S super_unko-git ``` Uninstall (not `super_unko`) ``` $ sudo pacman -R super_unko-git ``` ## macOS * With Homebrew ``` $ brew tap unkontributors/unko $ brew install super_unko ``` Uninstall ``` $ brew remove super_unko ``` ## Docker * With docker ```bash $ git clone https://github.com/unkontributors/super_unko.git $ cd super_unko $ docker-compose build $ docker-compose run super_unko unko.shout こんにちは $ docker run --rm -it unkontributors/super_unko unko.shout こんにちは ``` ## Zsh plugin manager Zsh plugin managers like [antigen](https://github.com/zsh-users/antigen), [zplug](https://github.com/zplug/zplug) can be adoptive. Not only commands can be used but also [`command_not_found_handler`](https://github.com/zsh-users/zsh/blob/master/README#L249) is updated. It is extremely helpful for developers. * Example of antigen ``` antigen bundle "unkontributors/super_unko" ``` ## Additional Installation - [unko.puzzle](./doc/unko.puzzle.md) - unko.shout - Need a [echo-sd](https://github.com/fumiyas/home-commands) command - unko.say - Need a `cowsay` command (`$ apt install cowsay`) - unko.think - Need a `cowthink` command (`$ apt install cowsay`) - unko.toilet - Need a `toilet` command (`$ apt install toilet`) Usage ======================== ``` $ echo "うんこ" | unko.tr 💩 $ echo "うんち" | unko.tr 💩 $ ./unko.yes 💩 💩 💩 💩 💩 💩 💩 ... ``` Development ======================== ## Codestyle and lint We are checking code with [shfmt](https://github.com/mvdan/sh) and [shellcheck](https://github.com/koalaman/shellcheck). Please check your code by `linter.sh` if you want to add your origin unko commands. We must provide clean unkos. So, please run below and pass all checkings. ```bash make setup make lint # or ./linter.sh ``` `linter.sh` checks your code or all code of this project. **`linter.sh` depends on `docker` and `docker-compose` commands.** And you **don't** need to install `shfmt` and `shellcheck`. Usage examples of `linter.sh` are below. ### Help ```bash ./linter.sh help ``` ### Code format ```bash ./linter.sh format ``` ### Code format and save ```bash ./linter.sh format-save ``` ### Code lint ```bash ./linter.sh lint ``` ### Code format and lint ```bash ./linter.sh all ``` ## Testing We use the [bats](https://github.com/sstephenson/bats) testing framework. `test.sh` calls the `bats`. But you **don't** need to install `bats`. Test tasks use `docker` and the `docker` uses `bats` internally and runs tests. Run below for testing. ```bash make setup ## Need long times to build docker images. make test ``` Run below for testing on multiple Bash versions. Please do that and fix it if tests failed on CI. ```bash make check make test-bash-version ``` ## CI workflow CI workflow runs when you pushed. Workflow diagram is below. ![CI push](./doc/ci-push.svg) Contribution ======================== Welcome! Welcome! LICENSE ============== ## Source Code 💩 LICENSE (Something like BSD license) ## Logo Creative 💩 license (Something like public domain) History ============== * [シェル芸勉強会中に爆誕したsuper_unkoリポジトリを巡る悲喜交々 - Togetter](https://togetter.com/li/1144376) * [【まとめたくない】super_unkoリポジトリがスクスク成長【義務感】 - Togetter](https://togetter.com/li/1145304) For Unkontributors (開発者向け) ======================== Please put your commands under `bin` directory. Run `bash package.sh` on a host which `docker` installed to generate multiple installer packages under `pkg` directory. Codebase is supposed to be scanned with code formatter and static analysis tools to ensure the quality of the code. Please make sure prepared static checks are passed by running `./liner.sh all` before submitting your PR. It would be appreciated if you could add tests to `./test.sh`. Please make sure the default branch of this repository is `oshiri` (which means "bum") not `master`. bin 以下になんか思いついたコマンドを放り投げてください。 docker が入った環境で `bash package.sh` すると pkg 以下に各種インストーラーが作成されます。 CIでコードフォーマットと静的解析にかけてコード品質を維持するようになりました。 PRするときは`./linter.sh all`で静的解析をパスすることを確認してください。 可能なら`./test.sh`にもテストコードを追加していただけると助かります。 なお、このリポジトリのデフォルトのブランチは`oshiri`であり`master`ではありません。 ================================================ FILE: activate.sh ================================================ #!/bin/bash if ! type super_unko > /dev/null 2>&1; then THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) export PATH="$PATH:$THIS_DIR/bin" # shellcheck source=/dev/null source "$THIS_DIR/lib/super_unko/unko_command_not_found_hundle" fi ================================================ FILE: bin/bigunko.show ================================================ #!/bin/bash THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR LIB_DIR="${THIS_DIR}/../lib/super_unko" readonly LIB_DIR echo -ne "$(base64 --decode < "${LIB_DIR}/bigunko.txt" | tr -d \\n)" ================================================ FILE: bin/super_unko ================================================ #!/bin/bash set -eu THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR SCRIPT_NAME="$(basename "${BASH_SOURCE:-$0}")" readonly SCRIPT_NAME main() { if [[ $# -lt 1 ]]; then log "Must need sub command." usage >&2 return 1 fi local cmd="$1" shift case "$cmd" in help) usage return ;; *) local cmd_path local ret set +eu cmd_path="$(to_command_path "$cmd")" ret=$? if [[ "$ret" -eq 0 ]]; then "$cmd_path" "$@" return fi set -eu log "Illegal sub command. (cmd = $cmd)" usage >&2 return 1 ;; esac } usage() { cat << EOS $SCRIPT_NAME is a master of unko. About subcommands: $SCRIPT_NAME controles sub unkommands by own charisma. $SCRIPT_NAME can control them as unkommands if there are executables that called 'unko.*' or 'bigunko.*' in the same directory as $SCRIPT_NAME. Available commands: EOS local pad=" " echo "${pad}help" # bigunko.show系のを先に for cmd_fullpath in "$THIS_DIR/"bigunko*; do local cmd=${cmd_fullpath##*/} cmd=${cmd//unko./} echo "${pad}$cmd" done # unko.*系の for cmd_fullpath in "$THIS_DIR/"unko.*; do local cmd=${cmd_fullpath##*/*unko.} echo "${pad}$cmd" done } log() { echo -e "$SCRIPT_NAME: $*" 2>&1 } ## to_command_path はサブコマンド名からunkoコマンドのパスを得る to_command_path() { local cmd="$1" for cmd_fullpath in "$THIS_DIR/bigunko".*; do local big_cmd=${cmd//big/bigunko.} local c=${cmd_fullpath##*/} if [[ "$c" == "$big_cmd" ]]; then echo "$cmd_fullpath" return fi done for cmd_fullpath in "$THIS_DIR/unko".*; do local c=${cmd_fullpath##*/unko.} if [[ "$c" == "$cmd" ]]; then echo "$cmd_fullpath" return fi done return 1 } main ${1+"$@"} exit $? ================================================ FILE: bin/unko.any ================================================ #!/bin/bash set -eu usage() { cat << EOF Usage: $0 [PHRASE ...] UNKO: Alternative character of 💩. PHRASE: Phrase for shout. EOF exit 0 } if [ $# -lt 1 ]; then usage fi UNKO="$1" readonly UNKO shift UNKO_SHOUT="${0%/*}/unko.shout" readonly UNKO_SHOUT BASE_UNKO="$(exec "$UNKO_SHOUT" ${1+"$@"})" readonly BASE_UNKO echo -e "${BASE_UNKO//💩/$UNKO}" ================================================ FILE: bin/unko.encode ================================================ #!/bin/bash if [[ "$LANG" = zh* ]] || [[ "$LANG" = en* ]]; then export TEXTDOMAINDIR="/usr/share/locale-langpack/${LANG%%.*}/LC_MESSAGES" else export TEXTDOMAINDIR="/usr/share/locale-langpack/${LANG%%_*}/LC_MESSAGES" fi export TEXTDOMAIN=libc UNKO_OCT="うんこウンコ💩👑" usage() { echo "Usage: $0 [OPTION] [FILE]" echo "Unko encode or decode FILE, or standard input to standard output." echo "With no FILE, or when FILE is -, read standard input." echo " -d : decode data" echo " -h : display this help and exit" } encode() { od -b -v -An | sed -e "y/01234567/$UNKO_OCT/" | tr -d ' \n' echo } decode() { printf '%b' "$( sed "s/[^$UNKO_OCT]//g" | sed \ -e "s/${UNKO_OCT:0:1}/0/g" \ -e "s/${UNKO_OCT:1:1}/1/g" \ -e "s/${UNKO_OCT:2:1}/2/g" \ -e "s/${UNKO_OCT:3:1}/3/g" \ -e "s/${UNKO_OCT:4:1}/4/g" \ -e "s/${UNKO_OCT:5:1}/5/g" \ -e "s/${UNKO_OCT:6:1}/6/g" \ -e "s/${UNKO_OCT:7:1}/7/g" | tr -d '\n' | sed 's/.../\\&/g' )" } EXEC_COMMAND="encode" FILE="-" for arg in "$@"; do case "$arg" in "-h" | "--help") usage exit 0 ;; "-d" | "--decode") EXEC_COMMAND="decode" ;; *) FILE="$arg" ;; esac done if [ "$FILE" = - ]; then "$EXEC_COMMAND" else if [ -f "$FILE" ]; then "$EXEC_COMMAND" < "$FILE" elif [ -d "$FILE" ]; then printf '%s: %s: %s\n' "$0" "$FILE" $"Is a directory" >&2 exit 1 elif ! [ -e "$FILE" ]; then printf '%s: %s: %s\n' "$0" "$FILE" $"No such file or directory" >&2 exit 1 fi fi exit 0 ================================================ FILE: bin/unko.fizzbuzz ================================================ #!/bin/bash UNKO_FIZZ='💩' UNKO_BUZZ='🍺' king_unko() { unko.shout "$1" } usage() { cat << EOM $0: $0 [unsigned_int] $0: print fizzbuzz unkonized. EOM exit 0 } if [ $# -ne 1 ]; then usage fi is_integer() { IPT=$1 if [[ "$IPT" =~ ^[0-9]+$ ]]; then return 0 else return 1 fi } if ! is_integer "$1"; then usage fi for ((NUM = 1; NUM <= $1; NUM++)); do if [ $((NUM % 3)) -eq 0 ] && [ $((NUM % 5)) -eq 0 ]; then king_unko "fizzbuzz" elif [ $((NUM % 5)) -eq 0 ]; then echo "$UNKO_BUZZ < buzz" elif [ $((NUM % 3)) -eq 0 ]; then echo "$UNKO_FIZZ < fizz" else echo "$NUM" fi done ================================================ FILE: bin/unko.grep ================================================ #!/bin/bash THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR LIB_DIR="${THIS_DIR}/../lib/super_unko" readonly LIB_DIR UNKO_REGEXP="$(awk -F , '1&2 } main ${1+"$@"} exit $? ================================================ FILE: bin/unko.life ================================================ #!/usr/bin/env bash set -u CELL=() NEXT_CELL=() CURSOR_Y=0 CURSOR_X=0 ## Use ANSI-C quoting because my text editor's layout is broken.. readonly DEFAULT_UNKO_LG_PLAYER=$'\xf0\x9f\x99\x87' # Person bowing readonly DEFAULT_UNKO_LG_ALIVE=$'\xe2\xac\x9c' # White tile. Toilet = $'\xf0\x9f\x9a\xbd' readonly DEFAULT_UNKO_LG_DEAD=$'\xf0\x9f\x92\xa9' # Unko UNKO_LG_PLAYER=${UNKO_LG_PLAYER:-$DEFAULT_UNKO_LG_PLAYER} UNKO_LG_ALIVE=${UNKO_LG_ALIVE:-$DEFAULT_UNKO_LG_ALIVE} UNKO_LG_DEAD=${UNKO_LG_DEAD:-$DEFAULT_UNKO_LG_DEAD} trap 'clear; cursor_visible' EXIT usage() { cat <<- USAGE Usage: unko.life [OPTIONS] [HEIGHT] [WIDTH] OPTIONS: -h,--help Display this help and exit Environment Variables: * UNKO_LG_PLAYER ... Player icon * UNKO_LG_ALIVE ... Alive cell * UNKO_LG_DEAD ... Dead cell Example: Play with below the command if your environment does not support any Emojis. $ UNKO_LG_ALIVE=_ UNKO_LG_DEAD="@" UNKO_LG_PLAYER="+" unko.life USAGE } cursor_visible() { tput cnorm >&2 } cursor_invisible() { tput civis >&2 } cursor_topleft() { tput cup 0 0 } initialize() { local _height="$1" shift local _width="$1" shift IFS=$'\n' read -r -a CELL -d '' <<< "$(yes 0 | head -n "$((_height * _width))")" } display() { local _height="$1" shift local _width="$1" shift local _msg="$1" shift local i=0 cursor_topleft printf "\033[41m\033[4m\033[30m %s \033[0m: %s \\n" "Unko Generation" "$_msg" for s in "${CELL[@]}"; do ((i % _width == 0)) && echo if ((i == (CURSOR_Y * _width + CURSOR_X))); then printf "%s" "$UNKO_LG_PLAYER" else [[ "$s" == "0" ]] && printf "%s" "$UNKO_LG_ALIVE" [[ "$s" == "1" ]] && printf "%s" "$UNKO_LG_DEAD" fi ((i = i + 1)) done echo printf "\033[30m\033[47m %s \033[0m: %s \\n" "H" "Move Player Left" printf "\033[30m\033[47m %s \033[0m: %s \\n" "J" "Move Player Down" printf "\033[30m\033[47m %s \033[0m: %s \\n" "K" "Move Player Up" printf "\033[30m\033[47m %s \033[0m: %s \\n" "L" "Move Player Right" printf "\033[30m\033[47m %s \033[0m: %s \\n" "Space" "Generate Or Remove Unko" printf "\033[30m\033[47m %s \033[0m: %s \\n" "S" "Start Unko Life Game!" printf "\033[30m\033[47m %s \033[0m: %s \\n" "Ctrl + C" "Quit Game" } get_cell_state() { local _height="$1" shift local _width="$1" shift local _y="$1" shift local _x="$1" shift ((_y < 0 || _y >= _height || _x < 0 || _x >= _width)) && { printf "%s\\n" 0 return } printf "%s\\n" "$((CELL[_y * _width + _x]))" } get_next_cell_state() { local _index="$1" shift local _height="$1" shift local _width="$1" shift local _y=$((_index / _width)) local _x=$((_index % _width)) local alive_count= alive_count=$({ get_cell_state "$_height" "$_width" "$((_y - 1))" "$((_x - 1))" get_cell_state "$_height" "$_width" "$((_y - 1))" "$((_x))" get_cell_state "$_height" "$_width" "$((_y - 1))" "$((_x + 1))" get_cell_state "$_height" "$_width" "$((_y))" "$((_x - 1))" get_cell_state "$_height" "$_width" "$((_y))" "$((_x + 1))" get_cell_state "$_height" "$_width" "$((_y + 1))" "$((_x - 1))" get_cell_state "$_height" "$_width" "$((_y + 1))" "$((_x))" get_cell_state "$_height" "$_width" "$((_y + 1))" "$((_x + 1))" } | paste -sd+ - | bc) if ((CELL[_index] == 0)); then ((alive_count == 3)) && { printf "%s\\n" 1 return } elif ((CELL[_index] == 1)); then ((alive_count == 2 || alive_count == 3)) && { printf "%s\\n" 1 return } ((alive_count <= 1)) && { printf "%s\\n" 0 return } ((alive_count >= 4)) && { printf "%s\\n" 0 return } fi printf "%s\\n" "$((CELL[_index]))" return } main() { local _height="${1:-10}" shift local _width="${1:-10}" shift if [[ $_height == '--help' ]] || [[ $_height == '-h' ]]; then trap '' EXIT usage return 0 fi if ! [[ $_height =~ ^[0-9]*$ ]] || ! [[ $_width =~ ^[0-9]*$ ]] || ((_height <= 0)) || ((_width <= 0)); then trap '' EXIT usage return 1 fi initialize "$_height" "$_width" clear cursor_invisible while true; do display "$_height" "$_width" "Initialize" read -rsn1 key case $key in h) ((CURSOR_X > 0)) && ((CURSOR_X--)) ;; l) ((CURSOR_X < (_width - 1))) && ((CURSOR_X++)) ;; k) ((CURSOR_Y > 0)) && ((CURSOR_Y--)) ;; j) ((CURSOR_Y < (_height - 1))) && ((CURSOR_Y++)) ;; s) # START GAME break ;; *) # Reverse cell state ((CELL[CURSOR_Y * _width + CURSOR_X] = 1 - CELL[CURSOR_Y * _width + CURSOR_X])) ;; esac done CURSOR_Y=-1 CURSOR_X=-1 local generation=0 while true; do i=0 display "$_height" "$_width" " $generation " for s in "${CELL[@]}"; do NEXT_CELL[i]="$(get_next_cell_state "$i" "$_height" "$_width")" ((i++)) done CELL=("${NEXT_CELL[@]}") ((generation++)) done } main ${1+"$@"} exit $? ================================================ FILE: bin/unko.ls ================================================ #!/bin/bash # Jot down any expression that means 💩. THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR LIB_DIR="${THIS_DIR}/../lib/super_unko" readonly LIB_DIR awk -F , '1 /dev/null 1>&2 && echo "Success ping to ${unko}.${tld}" done < <(cut -d "," -f 1 < "${LIB_DIR}/unko.csv" | sed "1d") done exit 0 ================================================ FILE: bin/unko.printpnm ================================================ #!/bin/bash SCRIPT_NAME="$(basename "${BASH_SOURCE:-$0}")" readonly SCRIPT_NAME readonly VERSION=v1.0.1 ## main はメイン関数である。スクリプトの末尾で呼び出す。 ## ## @param level うんこの段数 ## @param color_r RGB値のR (0~255) ## @param color_g RGB値のG (0~255) ## @param color_b RGB値のB (0~255) main() { local level=$1 local color_r=$2 local color_g=$3 local color_b=$4 local col local row local rgb col=$(max_stage_col "$level") row=$(max_stage_row "$level") rgb=$(max_value "$color_r" "$color_g" "$color_b") cat << EOS P3 $col $row $rgb EOS cat << EOS | align_center 0 | sed -E "s/ /0/g;s/0/0 0 0 /g;s/[^ 0]/$color_r $color_g $color_b /g" 1 1 111 11111 $(stages "$level") EOS } ## max_stage_col は段のカラム幅を返す。 ## ## @param n うんこの段数 ## @return うんこの横幅 max_stage_col() { local n=$1 echo $((11 + 8 * (n - 1) + 2)) } ## max_stage_col は段数を返す。 ## ## @param n うんこの段数 ## @return うんこの高さ max_stage_row() { local n=$1 echo $((4 + 4 * n)) } ## max_value は引数のうち最も大きな値を返す。 ## ## @param 1 ## @param 2 ## @param 3 ## @return 前述の3つの値のうち、もっとも数値として大きい値 max_value() { echo -e "$1\n$2\n$3" | sort -n | tail -n 1 } ## repeat は渡された引数の数分だけ1を出力して返す。 ## 返す文字列は1行である。 ## ## @param n 何文字繰り返すか ## @param c 出力する文字 (デフォルト: 1) ## @return n回繰り返した1 repeat() { local n=$1 local c=${2:-1} seq "$n" | xargs -I@ echo -n "$c" } ## stage はうんこの段を返す。 ## 引数は段の横幅を指定する。 ## 段、はうんこの横野箇所をさす。 ## ( ) <- のこと ## ## @param i うんこの段の番号 ## @param i番目のうんこ段 stage() { local i=$1 local j=$((i + 2)) cat << EOS $(repeat "$i") $(repeat "$j") $(repeat "$j") $(repeat "$i") EOS } ## stages は引数に指定した数だけうんこの段を返す。 ## たとえば、2を指定したときは以下のようなイメージになる。 ## ( ) ## ( ) ## ## @param n うんこが何段か ## @param n回くりかえしたうんこの段 stages() { local n=$1 seq "$n" | while read -r i; do stage $((11 + 8 * (i - 1))) done } ## align_center は標準入力を指定の文字列で埋めて中央寄せする。 ## ## @param pad 中央寄せのために詰める文字列 ## 全角文字はNG ## @return 中央寄せされた文字列 align_center() { local pad="$1" # 最も大きい横幅を取得 local max_width=0 local lines=() while read -r line; do local w w=$(wc -c <<< "$line") if [ "$max_width" -lt "$w" ]; then max_width=$w fi lines+=("$line") done # うんこを1行ずつ出力 for line in "${lines[@]}"; do local w w=$(wc -c <<< "$line") local left_width=$(((max_width - w) / 2)) local right_width=$((max_width - left_width - w)) echo "$(repeat "$left_width" "$pad")$line$(repeat "$right_width" "$pad")" done } ## usage はこのスクリプトの使い方を標準出力する。 usage() { cat << EOS $SCRIPT_NAME はうんこをPNM画像として出力するためのコマンドです。 Usage: $SCRIPT_NAME [flags] [unko_level] Examples: # 通常の使用方法 $SCRIPT_NAME 3 > unko3.pnm # RGB値を指定する例 $SCRIPT_NAME 3 -r 255 -g 0 -b 0 > unko_rgb.pnm # PNG画像に変換する例(ImageMagickに依存) $SCRIPT_NAME 3 -r 255 -g 0 -b 0 | convert - -scale 100x100 /images/t.png Flags: -h, --help このヘルプを出力する --version バージョン情報を出力する -r, --red int RGB値のRを指定 (0~255) (default: 255) -g, --green int RGB値のGを指定 (0~255) (default: 255) -b, --blue int RGB値のBを指定 (0~255) (default: 255) -u, --unko-color RGB値にうんこ色を指定する EOS } ## log はスクリプト名と合わせて、メッセージをエラー出力する。 log() { echo -e "$SCRIPT_NAME: $*" >&2 } ## is_empty は引数が空文字列であるかを判定する。 is_empty() { [[ -z "$1" ]] } ## is_opt_key は引数がコマンドライン引数のオプションキーであるかを判定する。 is_opt_key() { [[ "$1" =~ ^-+ ]] } ## validate_opt_value は引数がコマンドオプションの値であるかを判定する。 ## 不正な値の場合はシェルを異常終了する。 validate_opt_value() { local value=$1 if is_empty "$value" || is_opt_key "$value"; then log "requires an argument -- $value" exit 1 fi } ## set_opts はコマンドライン引数を解析して変数にセットする。 ## セットする変数は下記の通り。 ## - opt_red ## - opt_green ## - opt_blue ## - opt_unko_level ## これらの変数はトップレベルの変数として初期値を設定しておくこと。 set_opts() { local opt_use_unko_color=false while ((0 < $#)); do local opt=$1 shift case "$opt" in '-h' | '--help') usage exit ;; '--version') echo $VERSION exit ;; '-r' | '--red') local color=$1 shift validate_opt_value "$color" opt_red="$color" ;; '-g' | '--green') local color=$1 shift validate_opt_value "$color" opt_green="$color" ;; '-b' | '--blue') local color=$1 shift validate_opt_value "$color" opt_blue="$color" ;; '-u' | '--unko-color') opt_use_unko_color=true ;; -*) log "illegal option -- $1" exit 1 ;; *) opt_unko_level=$opt ;; esac done if [ "$opt_use_unko_color" = true ]; then opt_red=217 opt_green=112 opt_blue=2 fi } # テストフラグが付与されている時はmain関数を呼び出さない。 if [ ! "$RUN_TEST" = true ]; then # コマンドライン引数を取得 opt_red=255 opt_green=255 opt_blue=255 opt_unko_level=3 set_opts ${1+"$@"} main "$opt_unko_level" "$opt_red" "$opt_green" "$opt_blue" fi ================================================ FILE: bin/unko.puzzle ================================================ #!/usr/bin/env bash set -eu FRAME=30 TILES=${TILES:-3} HEADER_HEIGHT=23 # Darwin RANDOM_SLIDE=$((10 + TILES * TILES * TILES / 2)) PIXEL_ART_COLS=60 # BIGUNKO' PIXEL_ART_ROWS=30 # BIGUNKO DEBUG_UNKO=${DEBUG_UNKO:-false} WINDOW_NAME="$(basename $0)" BIGUNKO="" WIDS=() log_debug() { if [ "$DEBUG_UNKO" = "true" ]; then echo "[$$] $@" >&2 fi } initialize() { platform=$(uname) # process stratum: this process -> shell(bash) -> terminal emulator ? pppid=$(ps -ef | awk "\$2==$PPID{print \$3}") case $platform in 'Darwin') HEIGHT_OFFSET=-44 WIDTH_OFFSET=0 ;; 'Linux') HEIGHT_OFFSET=-68 WIDTH_OFFSET=-10 ;; *) echo "error: $platform: unsupported platform" >&2 exit 1 ;; esac if [ $(ps -ef | awk "\$2==$pppid{print}" | grep [x]term | wc -l) -eq 0 ]; then echo 'error: require xterm' >&2 exit 1 fi which xdotool > /dev/null 2>&1 || { echo 'error: require xdotool' >&2 exit 1 } # expects current window is active root_cols=$(stty -a | grep columns | sed 's/.*columns \([^;]*\);.*/\1/') root_rows=$(stty -a | grep rows | sed 's/.*rows \([^;]*\);.*/\1/') root_wid=$(xdotool getactivewindow) root_wname=$(xdotool getwindowname $root_wid) root_wgeo=$(xdotool getwindowgeometry $root_wid | grep Geometry | awk '{print $2}') root_wpos=$(xdotool getwindowgeometry $root_wid | grep Position | awk '{print $2}') char_width=$((${root_wgeo%x*} / $root_cols)) char_height=$((${root_wgeo#*x} / $root_rows)) margin_width=$((${root_wgeo%x*} % $root_cols)) margin_height=$((${root_wgeo#*x} % $root_rows)) tile_window_width=$(($PIXEL_ART_COLS / $TILES * $char_width + $margin_width)) tile_window_height=$(($PIXEL_ART_ROWS / $TILES * $char_height + $margin_height)) tile_char_cols=$(($PIXEL_ART_COLS / $TILES)) tile_char_rows=$(($PIXEL_ART_ROWS / $TILES)) log_debug "window name: $WINDOW_NAME" log_debug "number of tiles on a side: $TILES" log_debug "root window columns: $root_cols" log_debug "root window rows: $root_rows" log_debug "root window id: $root_wid" log_debug "root window name: $root_wname" log_debug "root window geometry: $root_wgeo" log_debug "root window position: $root_wpos" log_debug "character width: $char_width" log_debug "character height: $char_height" log_debug "margin width: $margin_width" log_debug "margin height: $margin_height" log_debug "tile window width: $tile_window_width" log_debug "tile window height: $tile_window_height" log_debug "tile character columns: $tile_char_cols" log_debug "tile character rows: $tile_char_rows" } calculate_tile_position() { local tile_pos_x=$1 tile_pos_y=$2 local wpos_x=$((${root_wpos%,*} + $tile_window_width * $tile_pos_x + $WIDTH_OFFSET)) local wpos_y=$((${root_wpos#*,} + ($tile_window_height + $HEADER_HEIGHT) * $tile_pos_y + $HEIGHT_OFFSET)) log_debug "calculate position: tile=${tile_pos_x},${tile_pos_y}; window=${wpos_x},${wpos_y}" echo "${wpos_x},${wpos_y}" } set_root_window() { local wpos=$(calculate_tile_position 1 0) local wpos_x=${wpos%,*} wpos_y=${wpos#*,} log_debug "set root window: wid=$root_wid; geometry=${tile_window_width}x${tile_window_height}; position=${wpos_x},${wpos_y}" xdotool set_window --name "$WINDOW_NAME" $root_wid xdotool windowsize $root_wid $tile_window_width $tile_window_height xdotool windowmove $root_wid $wpos_x $wpos_y clear } create_children() { local num_children=$(($TILES * $TILES - 2)) log_debug "number of child windows: $num_children" for i in $(seq 2 $(($num_children + 1))); do local wpos=$(calculate_tile_position $(($i % $TILES)) $(($i / $TILES))) local wpos_x=${wpos%,*} wpos_y=${wpos#*,} log_debug "create child window: $i; geometry=${tile_char_cols}x${tile_char_rows}(chars); position=${wpos_x},${wpos_y}" xterm \ -geometry "${tile_char_cols}x${tile_char_rows}+${wpos_x}+${wpos_y}" \ -e "$0" & done sleep $(echo "scale=1; 0.3 + $TILES * $TILES / 10" | bc) } relocate() { local wids=($1) local i=1 for wid in ${wids[@]}; do local wpos_x=$((${root_wpos%,*} + $tile_window_width * ($i % $TILES) + $WIDTH_OFFSET)) local wpos_y=$((${root_wpos#*,} + ($tile_window_height + $HEADER_HEIGHT) * ($i / $TILES) + $HEIGHT_OFFSET)) log_debug "relocate window: wid=$wid; position=${wpos_x},${wpos_y}" xdotool windowmove $wid $wpos_x $wpos_y let ++i done } trim_bigunko() { local tile_pos_x=$1 tile_pos_y=$2 if [ "$BIGUNKO" == "" ]; then # cache bigunko to prevent broken pipe error BIGUNKO=$($( cd $(dirname $0) pwd )/bigunko.show | sed $'s/\(\033\[48;5;[0-9]*m\) /\\1 \\1 /g') fi echo "$BIGUNKO" | head -n $(($tile_char_rows * ($tile_pos_y + 1))) | tail -n $tile_char_rows | sed $'s/\(\033\[48;5;[0-9]*m\) /\\1 \\1 /g' | awk " { for (k = $tile_char_cols * $tile_pos_x + 1; k < $tile_char_cols * ($tile_pos_x + 1) + 1; k++) { printf \$k\" \"; }; printf \"\033[0m\"; if (NR != $tile_char_rows) { print \"\" }; }" } get_child_tty_names() { local child_wids="$1" for wid in $child_wids; do local pid=$(xdotool getwindowpid $wid) # get tty name of child process tty_name=$(ps -ef | grep "$WINDOW_NAME" | awk "\$3==$pid{print \$6}") log_debug "child process: wid=${wid}; pid=${pid}; tty=/dev/${tty_name}" echo $tty_name done } draw() { local child_wids="$1" local tty_names=($(get_child_tty_names "$child_wids")) local tile_pos_x=1 tile_pos_y=0 log_debug "draw window: root; tile position=$tile_pos_x,$tile_pos_y" trim_bigunko $tile_pos_x $tile_pos_y for i in $(seq 0 $((${#tty_names[@]} - 1))); do tile_pos_x=$((($i + 2) % $TILES)) tile_pos_y=$((($i + 2) / $TILES)) log_debug "draw window: child $((i + 1)); tile position=$tile_pos_x,$tile_pos_y; tty=/dev/${tty_names[i]}" trim_bigunko $tile_pos_x $tile_pos_y >> /dev/${tty_names[i]} done } terminate_children() { local child_wids="$1" local i=0 for wid in $child_wids; do # TODO: pid がない場合を考慮 local pid=$(xdotool getwindowpid $wid) kill -INT $pid let ++i done return } slide_window() { local wid=$1 local distance_x=$2 local distance_y=$3 local pos=$(xdotool getwindowgeometry $wid | grep Position | awk '{print $2}') local pos_x=${pos%,*} local pos_y=${pos#*,} log_debug "slide window: wid=$wid; pos=$pos_x,$pos_y; dis=$distance_x,$distance_y" for i in $(seq $FRAME); do xdotool windowmove $wid $(($pos_x + $distance_x / $FRAME * $i + $WIDTH_OFFSET)) $(($pos_y + $distance_y / $FRAME * $i + $HEIGHT_OFFSET)) done xdotool windowmove $wid $(($pos_x + $distance_x + $WIDTH_OFFSET)) $(($pos_y + $distance_y + $HEIGHT_OFFSET)) } shake_window() { local wid=$1 local pos=$(xdotool getwindowgeometry $wid | grep Position | awk '{print $2}') local pos_x=${pos%,*} local pos_y=${pos#*,} for i in $(seq 5); do xdotool windowmove $wid $(($pos_x - 10 + $WIDTH_OFFSET)) $(($pos_y + $HEIGHT_OFFSET)) xdotool windowmove $wid $(($pos_x + $WIDTH_OFFSET)) $(($pos_y + $HEIGHT_OFFSET)) xdotool windowmove $wid $(($pos_x + 10 + $WIDTH_OFFSET)) $(($pos_y + $HEIGHT_OFFSET)) xdotool windowmove $wid $(($pos_x + $WIDTH_OFFSET)) $(($pos_y + $HEIGHT_OFFSET)) done } can_slide() { local null_index=$1 local direction=$2 case $direction in 'up') if [ $null_index -lt $(($TILES * $TILES - $TILES)) ]; then return 0; fi ;; 'down') if [ $null_index -ge $TILES ]; then return 0; fi ;; 'left') if [ $(($null_index % $TILES)) -ne $(($TILES - 1)) ]; then return 0; fi ;; 'right') if [ $(($null_index % $TILES)) -ne 0 ]; then return 0; fi ;; esac return 1 } move_tile() { local direction=$1 local anotation=$2 local null_index=$(echo "${WIDS[@]}" | tr ' ' '\n' | nl -v0 | grep null | awk '{print $1}') local wid target_index distance_x distance_y # log_debug "current window ids: ${WIDS[@]}" if can_slide $null_index $direction; then case $direction in 'up') target_index=$(($null_index + $TILES)) distance_x=0 distance_y=$((-$tile_window_height - $HEADER_HEIGHT)) ;; 'down') target_index=$(($null_index - $TILES)) distance_x=0 distance_y=$(($tile_window_height + $HEADER_HEIGHT)) ;; 'left') target_index=$(($null_index + 1)) distance_x=-$tile_window_width distance_y=0 ;; 'right') target_index=$(($null_index - 1)) distance_x=$tile_window_width distance_y=0 ;; esac wid=${WIDS[$target_index]} # log_debug "slide window: direction=${direction}; target index=${target_index}; wid=${wid}" slide_window $wid $distance_x $distance_y WIDS[$null_index]=$wid WIDS[$target_index]='null' else if [ "$anotation" = 'true' ]; then case $direction in 'up') target_index=$(($null_index - $TILES)) ;; 'down') target_index=$(($null_index + $TILES)) ;; 'left') target_index=$(($null_index - 1)) ;; 'right') target_index=$(($null_index + 1)) ;; esac wid=${WIDS[$target_index]} shake_window $wid fi fi } randomize() { local direction local prev=-1 local count=0 while [ $count -le $RANDOM_SLIDE ]; do local rand=$((RANDOM % 4)) case $rand in 0) direction='up' if [ $prev -eq 1 ]; then continue; fi ;; 1) direction='down' if [ $prev -eq 0 ]; then continue; fi ;; 2) direction='left' if [ $prev -eq 3 ]; then continue; fi ;; 3) direction='right' if [ $prev -eq 2 ]; then continue; fi ;; esac local null_index=$(echo "${WIDS[@]}" | tr ' ' '\n' | nl -v0 | grep null | awk '{print $1}') if can_slide $null_index $direction; then move_tile $direction 'false' prev=$rand # log_debug "randomize: count=$count; direction=$direction" let ++count fi done } solve() { local collect_hash=$(echo -n $1 | md5sum | cut -d' ' -f1) while IFS= read -r -n1 -s key; do if [ "$key" == $'\x1b' ]; then read -r -n2 -s rest key+="$rest" fi case "$key" in k | $'\x1b\x5b\x41') move_tile 'up' 'true' ;; j | $'\x1b\x5b\x42') move_tile 'down' 'true' ;; l | $'\x1b\x5b\x43') move_tile 'right' 'true' ;; h | $'\x1b\x5b\x44') move_tile 'left' 'true' ;; esac local wids_hash=$(echo -n "${WIDS[@]}" | md5sum | cut -d' ' -f1) if [ "$wids_hash" = "$collect_hash" ]; then break; fi done } clean_up() { # reset root window xdotool set_window --name "$root_wname" $root_wid xdotool windowsize $root_wid ${root_wgeo%x*} $((${root_wgeo#*x} + $WIDTH_OFFSET)) xdotool windowmove $root_wid ${root_wpos%,*} $((${root_wpos#*,} + $HEIGHT_OFFSET)) stty echo clear exit 0 } processes=$(ps -ef | grep $WINDOW_NAME | grep -v grep) if [ $(echo "$processes" | wc -l) -le 2 ]; then # parent window initialize set_root_window trap clean_up 2 # 2:SIGINT create_children xdotool windowactivate $root_wid xdotool windowfocus $root_wid wids=$(xdotool search --name "$WINDOW_NAME") # newline separated child_wids=$(echo "$wids" | grep -v $root_wid | tr '\n' ' ') relocate "$root_wid $child_wids" draw "$child_wids" WIDS=('null' $root_wid $child_wids) randomize xdotool windowactivate $root_wid xdotool windowfocus $root_wid solve "null $root_wid $child_wids" terminate_children "$child_wids" clean_up else # child window cat fi ================================================ FILE: bin/unko.pyramid ================================================ #!/usr/bin/env bash # Sierpinski gasket is not unkoski gasket. # Sierpinski is great mathematician. # unkoski is peoples who love the unko. SCRIPT_NAME="$(basename "${BASH_SOURCE:-$0}")" readonly SCRIPT_NAME readonly VERSION=v1.0.0 draw_pyramid() { local input="${1:-1}" if [[ "$input" =~ ^1 ]]; then return 0 fi echo "${input//10/💩}" | cut -c 2- | tr 01 ' 💩' next_input=$(echo "0${input}0" | awk -F '' '{l=length($0);for(i=1;i<=l-2;i++){printf ($i+$(i+2))%2}}') draw_pyramid "$next_input" } rendering() { ## draw! 💩 turn! local pyramid_size="${1:-16}" draw_pyramid "$(printf "%0$((pyramid_size + 1))d%0${pyramid_size}d" 1)" } ## unko.printpnmを参考に... log() { echo -e "$SCRIPT_NAME: $*" >&2 } usage() { cat << EOS $SCRIPT_NAME is render unkoski gasket. Sorry, could not beautiful rendering by some environment... Usage: $SCRIPT_NAME [unko_size (default:16)] Examples: $SCRIPT_NAME 16 Flags: -h, --help show help --version show version EOS exit 0 } main() { while ((0 < $#)); do local opt=$1 shift case "$opt" in '-h' | '--help') usage exit ;; '--version') echo $VERSION exit ;; -*) log "illegal option '$opt'" exit 1 ;; *) unko_size=$opt if ! [[ $unko_size =~ ^[1-9]+[[:digit:]]*$ ]]; then log "Invalid number '$unko_size'" return 1 fi ;; esac done rendering "$unko_size" return 0 } main ${1+"$@"} exit $? ================================================ FILE: bin/unko.question ================================================ #!/bin/bash TEXT=$* eval unko.shout "${TEXT}" while :; do read -rp "ok? (y/N/u): " ynu case "$ynu" in [yY]*) # y|Yの場合は正常終了 exit 0 ;; [uU]*) # u|Uの場合は再度聞く eval unko.shout "ブリブリブリ…" "もう一度聞いてやろう" "${TEXT}" continue ;; *) # デフォルト(N)で127で終了 exit 127 ;; esac done ================================================ FILE: bin/unko.say ================================================ #!/bin/bash # Get current directory THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR LIB_DIR="${THIS_DIR}/../lib/super_unko" readonly LIB_DIR COW_FILE="${LIB_DIR}/unko_mb.cow" if ! (cowsay -f "${COW_FILE}" 'うんこ' | grep -qe 'うんこ' && cowsay -f "${COW_FILE}" 'もりもり' | grep -qe '💩'); then COW_FILE="${LIB_DIR}/unko.cow" fi cowsay -f "${COW_FILE}" "$@" ================================================ FILE: bin/unko.shout ================================================ #!/bin/bash echo-sd ${1+"$@"} t="${T:-👑}" # Top u="${U:-💩}" # Unko le="${LE:-${E:-👁}}" # Left Eye re="${RE:-${E:-👁}}" # Right Eye n="${N:-👃}" # Nose m="${M:-👄}" # Mouth l="${L:-(}" # Left side r="${R:-)}" # Right side s="${S:- }" # Space cat << EOF $s$s$s$s$s$s$t $s$s$s$s$l$u$u$u$r $s$s$s$l$u$le$u$re$u$r $s$s$l$u$u$u$n$u$u$u$r $s$l$u$u$u$u$m$u$u$u$u$r EOF ================================================ FILE: bin/unko.think ================================================ #!/bin/bash # Get current directory THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR LIB_DIR="${THIS_DIR}/../lib/super_unko" readonly LIB_DIR COW_FILE="${LIB_DIR}/unko_mb.cow" if ! (cowsay -f "${COW_FILE}" 'うんこ' | grep -qe 'うんこ' && cowsay -f "${COW_FILE}" 'もりもり' | grep -qe '💩'); then COW_FILE="${LIB_DIR}/unko.cow" fi cowthink -f "${COW_FILE}" "$@" ================================================ FILE: bin/unko.toilet ================================================ #!/bin/bash usage() { cat << EOS >&2 Usage: unko.toilet [ -hv ] [ -w outputwidth ] [ --crop ] [ --flip ] [ --flop ] [ --180 ] [ --left ] [ --right ] [ --border ] [ message ] -h, --help このヘルプを出力して終了します -w, --width 出力の幅です。autoを指定すると端末の幅になります --crop 上下左右の無駄なスペースを削除します --flip 水平方向に反転します --flop 垂直方向に反転します --180 180度回転します --left 左へ90度回転します --right 右へ90度回転します --border 枠線をつけます EOS exit 1 } not_found() { echo "[ERR] $* not found [unko.toilet]" 1>&2 exit 1 } append_opt() { toilet_opt+=("$@") } version() { echo "unko.toilet version 💩.💩.💩 (20💩💩/💩💩/💩💩)" exit 0 } unexpected() { echo "[ERR] Unexpected $1" 1>&2 echo "" 1>&2 usage } is_integer() { local num num=$1 [[ "$num" =~ ^[0-9]+$ ]] } # unko.toilet 用のオプションをパースする declare -a args declare -a toilet_opt while (($# > 0)); do opt=$1 shift case "$opt" in -h | --help) # --help か -h が指定されていたらUsage出して終了 usage ;; -v | --version) # --version か -v なら version情報を出力して終了 version ;; -w | --width) num=$1 shift if is_integer "$num"; then append_opt "--width" "$num" elif [ "$num" = auto ]; then append_opt "--termwidth" else unexpected "argument $opt $num <=" fi ;; --left | --right | --flip | --flop | --180 | --border | --crop) append_opt "--filter" "${opt//--/}" ;; -*) # いずれのオプションともマッチしなかった unexpected "option $opt" ;; *) # 引数 args+=("$opt") ;; esac done # 第一引数に与えた文字を変換、デフォルト文字はうんこ text=("${args[@]:-うんこ}") # stdinから入力されてるならそっちを使う [ -p /dev/stdin ] && text=("$(cat -)") # toilet がなかったらダメ type toilet &> /dev/null || not_found "toilet command" # フォントにbigmono9を使うので無かったらダメ echo | toilet -f bigmono9 &> /dev/null || not_found "bigmono9 font" # unko.toilet toilet "${toilet_opt[@]}" -f bigmono9 "${text[@]}" | # 薄いところは消す sed 's/░\|▒/ /g' | # スペース以外を💩へ sed 's/[^ ]/💩/g' | # 幅調整 sed 's/ / /g' ================================================ FILE: bin/unko.tower ================================================ #!/usr/bin/env bash set -u readonly THIS_CMD="${0##*/}" readonly DEFAULT_PADDING=" " readonly DEFAULT_HEIGHT=3 readonly UNKO_TOP="人" repeat_str() { local _num="$1" shift local _str="$1" shift awk \ -v NUM="$_num" \ -v STR="$_str" \ 'BEGIN{ for (i=0; i 0; i--)); do _left="$(repeat_str "$i" "$_padding")" _num1="$((_level - i + 1))" _mid1="$(print_array "${_msg[@]:$_msg_idx:$_num1}")" ((_msg_idx = _msg_idx + _num1)) _num2="$((_level - i))" _mid2="$(print_array "${_msg[@]:$_msg_idx:$_num2}")" ((_msg_idx = _msg_idx + _num2)) _result="${_result}"$'\n'"${_left}(${_mid1}${_mid2})" done printf "%s\\n" "${_result}" } unk_msg_error() { printf "%s\\n" "$THIS_CMD:error:${1-}" } unk_command_help() { cat << _EOS_ Usage: ${THIS_CMD} [OPTIONS] NUMBER OPTIONS: --help Display this help and exit -m Fill with the message -r Read message from stdin -s Change default stuffed string _EOS_ } # Calculate sum of the number of character to be filled in the Unko. char_sum() { local n="$1" echo "$((n * n + 2 * n))" } print_array() { for s in "$@"; do _pat='[ -~]' # cover all the ascii chars if [[ $s =~ $_pat ]]; then printf "%s " "$s" # padding else printf "%s" "$s" fi done } main() { local _msg=() local _opt_msg=0 local _opt_stdin=0 local _raw_msg= local _total_char= while (($# > 0)); do local _opt="$1" shift ## -ovalue → -o value (inspired by echo-sd) if [[ -n "${_opt}" ]] && [[ -z "${_opt##-[sm]?*}" ]]; then set -- "${_opt#??}" ${1+"$@"} _opt="${_opt%"${1}"}" fi case "$_opt" in --help) unk_command_help return 0 ;; -m) _opt_msg=1 _raw_msg="${1-}" shift ;; -s) _padding="${1-}" shift ;; -r) _opt_msg=1 _opt_stdin=1 ;; *) _num="$_opt" ;; esac done _padding=${_padding:-$DEFAULT_PADDING} _num=${_num:-$DEFAULT_HEIGHT} if ! [[ ${_num} =~ ^[[:digit:]]+$ ]]; then unk_msg_error "Invalid number '${_num}'" return 0 fi _total_char="$(char_sum "${_num}")" if [[ ${_opt_msg} -eq 0 ]]; then IFS=$'\n' read -r -a _msg -d '' <<< "$(repeat_str "$_total_char" "$_padding" | grep -o .)" elif [[ ${_opt_msg} -eq 1 ]]; then if [[ ${_opt_stdin} -eq 1 ]]; then IFS=$'\n' read -r -a _msg -d '' <<< "$(cat | grep -o .)" else IFS=$'\n' read -r -a _msg -d '' <<< "$(printf "%s" "${_raw_msg}" | grep -o .)" fi _gap=$((_total_char - ${#_msg[@]})) if ((_gap > 0)); then IFS=$'\n' read -r -a _rest_msg -d '' <<< "$(repeat_str "$_gap" "$_padding" | grep -o .)" _msg=("${_msg[@]:-"$_padding"}" "${_rest_msg[@]}") fi fi print_unko "${_num}" "${_msg[@]:-}" return 0 } main ${1+"$@"} exit $? ================================================ FILE: bin/unko.tr ================================================ #!/bin/bash # Get current directory THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR LIB_DIR="${THIS_DIR}/../lib/super_unko" readonly LIB_DIR sed -f <(awk -F , '1 * [unko.puzzle](doc/unko.puzzle.md#unkopuzzle) * [Requirements](doc/unko.puzzle.md#requirements) * [Additional installation](doc/unko.puzzle.md#additional-installation) * [Linux](doc/unko.puzzle.md#linux) * [With yum (RHEL compatible distros)](doc/unko.puzzle.md#with-yum-rhel-compatible-distros) * [With apt (Debian base distros)](doc/unko.puzzle.md#with-apt-debian-base-distros) * [macOS](doc/unko.puzzle.md#macos) * [With Homebrew](doc/unko.puzzle.md#with-homebrew) * [Usage](doc/unko.puzzle.md#usage) * [Linux](doc/unko.puzzle.md#linux-1) * [macOS](doc/unko.puzzle.md#macos-1) * [for development](doc/unko.puzzle.md#for-development) ## Requirements - X11 - XQuartz (macOS) - xterm ## Additional installation ### Linux #### With `yum` (RHEL compatible distros) * Enable epel repository (skip) * Install xdotool ```sh $ sudo yum install xdotool ``` #### With `apt` (Debian base distros) ```sh $ sudo apt install xdotool ``` ### macOS #### With Homebrew ```sh $ brew cask install xquartz $ brew install xdotool ``` ## Usage ### Linux 1. Launch xterm. 1. Run `unko.puzzle` on xterm. 1. Enjoy! ### macOS 1. Launch xterm. ```sh $ PATH=$PATH:/opt/X11/bin xterm & ``` 1. Run `unko.puzzle` on xterm. ```sh $ unko.puzzle ``` 1. Enjoy! --- ``` Warning: XTEST extension unavailable on '(null)'. Some functionality may be disabled; See 'man xdotool' for more info. ``` If you received such a message from xdotool, you may be able to resolve it by execute the following commands and restarting XQuartz: ```sh $ defaults write org.x.X11 enable_test_extensions -boolean true $ defaults write org.macosforge.xquartz.X11 enable_test_extensions -boolean true ``` See: https://stackoverflow.com/questions/1264210/does-mac-x11-have-the-xtest-extension ## for development - tile map ``` +-+-+-+ |x|1|2| +-+-+-+ |3|4|5| +-+-+-+ |6|7|8| +-+-+-+ ``` - debug ```sh $ DEBUG_UNKO=true TILES=2 unko.puzzle 2>>/tmp/unko.log ``` ================================================ FILE: doc/unko.toilet.md ================================================ # unko.toilet Text to UNKO Art!!!! Table of Contents * [unko.toilet](doc/unko.toilet.md#unkotoilet) * [Requirements](doc/unko.toilet.md#requirements) * [Additional installation](doc/unko.toilet.md#additional-installation) * [apt](doc/unko.toilet.md#apt) * [brew/linuxbrew](doc/unko.toilet.md#brewlinuxbrew) * [Usage](doc/unko.toilet.md#usage) ## Requirements - `toilet` - `figlet` ### Additional installation ### apt ```sh $ sudo apt install figlet toilet ``` ### brew/linuxbrew ```sh $ brew install figlet toilet ``` ## Usage ``` unko.toilet [ -hv ] [ -w outputwidth ] [ --crop ] [ --flip ] [ --flop ] [ --180 ] [ --left ] [ --right ] [ --border ] ``` ================================================ FILE: docker/Dockerfile ================================================ # vim: tw=0: FROM ubuntu:20.04 AS base RUN echo -e $'\n\ _人人人人人人人人人人人人人人人人人人人人人人_\n\ > super_unkoイメージを今からビルドするよ! <\n\ > これには少し時間がかかるよ!       <\n\  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄\n\       👑\n\     (💩💩💩)\n\    (💩👁💩👁💩)\n\   (💩💩💩👃💩💩💩)\n\  (💩💩💩💩👄💩💩💩💩)' ENV LANG ja_JP.UTF-8 RUN apt update -yqq \ && apt install -y --no-install-recommends \ language-pack-ja-base \ toilet \ figlet \ bc \ cowsay \ curl \ ca-certificates \ locales \ && locale-gen ja_JP.UTF-8 \ && rm -rf /var/lib/apt/lists/* COPY . /usr/local/src/super_unko WORKDIR /usr/local/src/super_unko RUN ./install.sh RUN curl --retry 3 https://raw.githubusercontent.com/fumiyas/home-commands/master/echo-sd > /usr/local/bin/echo-sd RUN chmod +x /usr/local/bin/echo-sd RUN echo -e $'\n\ _人人人人人人人人人人人人人人人人人人人人人人人人_\n\ > super_unkoイメージのビルドが無事完了したよ! <\n\  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄\n\       👑\n\     (💩💩💩)\n\    (💩👁💩👁💩)\n\   (💩💩💩👃💩💩💩)\n\  (💩💩💩💩👄💩💩💩💩)' FROM base AS ci ARG SH_VERSION=default # Install bash-x.x COPY ./docker/install_bash.sh /tmp/install_bash.sh RUN apt update -yqq \ && apt install -y --no-install-recommends build-essential bats byacc \ && rm -rf /var/lib/apt/lists/* \ && /tmp/install_bash.sh ${SH_VERSION} \ && ./install.sh ================================================ FILE: docker/install_bash.sh ================================================ #!/bin/bash set -eu SCRIPT_NAME="$(basename "${BASH_SOURCE:-$0}")" readonly SCRIPT_NAME usage() { cat << EOS $SCRIPT_NAME は指定のバージョンのBashを/bin/bashにインストールします。 インストール前のBashは同じディレクトリにbash.oldとしてバックアップされます。 Usage: $SCRIPT_NAME -h | --help $SCRIPT_NAME [default: default] Available version: default 3.2 4.0 4.1 4.2 4.3 4.4 5.0 EOS } case $1 in -h | --help) usage return ;; esac readonly TMPDIR=/tmp/bash readonly SH_VERSION=${1:-default} mkdir -p $TMPDIR if [[ "$SH_VERSION" != "default" ]]; then ( cd "$TMPDIR" curl -s --retry 3 "http://ftp.gnu.org/gnu/bash/bash-${SH_VERSION}.tar.gz" | tar xvz cd bash* ./configure make make install mv /bin/bash{,.old} cp -p ./bash /bin/bash ) fi bash --version ================================================ FILE: docker-compose-ci.yml ================================================ version: '3.7' x-build: &build context: . dockerfile: ./docker/Dockerfile target: ci services: ci_sh_default: &default build: <<: *build args: SH_VERSION: default volumes: - "$PWD:/usr/local/src/super_unko" working_dir: /usr/local/src/super_unko entrypoint: - ./test.sh ci_sh_3.2: <<: *default build: <<: *build args: # Because bats supports 3.2.57 or more https://github.com/bats-core/bats-core SH_VERSION: 3.2.57 ci_sh_4.0: <<: *default build: <<: *build args: SH_VERSION: 4.0 ci_sh_4.1: <<: *default build: <<: *build args: SH_VERSION: 4.1 ci_sh_4.2: <<: *default build: <<: *build args: SH_VERSION: 4.2 ci_sh_4.3: <<: *default build: <<: *build args: SH_VERSION: 4.3 ci_sh_4.4: <<: *default build: <<: *build args: SH_VERSION: 4.4 ci_sh_5.0: <<: *default build: <<: *build args: SH_VERSION: 5.0 ================================================ FILE: docker-compose.yml ================================================ version: '3.7' services: super_unko: build: context: ./ dockerfile: ./docker/Dockerfile target: base image: unkontributors/super_unko formatter: image: peterdavehello/shfmt container_name: formatter volumes: - "$PWD:/work" entrypoint: - "shfmt" - "-i" - "2" - "-ci" - "-sr" - "-d" linter: image: koalaman/shellcheck container_name: linter volumes: - "$PWD:/work" entrypoint: - "shellcheck" ================================================ FILE: install.sh ================================================ #!/bin/bash set -ue THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR readonly BINMODE=755 readonly LIBMODE=644 readonly PREFIX="${1:-/usr/local}" readonly PREFIX_BIN="${PREFIX}/bin" readonly PREFIX_LIB="${PREFIX}/lib/super_unko" install -d "${PREFIX_BIN}" install -m "${BINMODE}" "${THIS_DIR}"/bin/* "${PREFIX_BIN}" install -d "${PREFIX_LIB}" install -m "${LIBMODE}" "${THIS_DIR}"/lib/super_unko/* "${PREFIX_LIB}" ================================================ FILE: lib/super_unko/bigunko.txt ================================================ XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFww MzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1swbVxuClwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbMG1cbgpcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMz WzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7 MjQzbeOAgFwwMzNbNDg7NTsyNDht44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzBtXG4KXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFww MzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7 MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzBtXG4KXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFww MzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNb NDg7NTs5NG3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1swbVxuClwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMz WzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7 MjQzbeOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFww MzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbMG1cbgpcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFww MzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbMG1cbgpcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBc MDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7 OTRt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbMG1cbgpcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsxMDBt44CAXDAzM1s0ODs1 OzEwMG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBc MDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7 NTht44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbMG1cbgpcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsxMDBt44CAXDAzM1s0ODs1 Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFww MzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTs5 NG3jgIBcMDMzWzQ4OzU7MjQ4beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1swbVxuClwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMz WzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0 beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNb NDg7NTs5NG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzEwMG3jgIBcMDMzWzQ4OzU7MTAw beOAgFwwMzNbNDg7NTsxMDBt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbMG1cbgpcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQ4 beOAgFwwMzNbNDg7NTsxMDBt44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTsxMDBt44CAXDAz M1s0ODs1OzEwMG3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7 MjQ4beOAgFwwMzNbNDg7NTsyNDht44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1swbVxuClwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMz WzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7MjUybeOAgFwwMzNbNDg7NTsy NTJt44CAXDAzM1s0ODs1OzI1Mm3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTsxMDBt44CA XDAzM1s0ODs1OzEwMG3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTsyNTJt44CAXDAzM1s0 ODs1OzI1Mm3jgIBcMDMzWzQ4OzU7MjU0beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzU4 beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFww MzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzBtXG4KXDAzM1s0ODs1OzI0M23jgIBcMDMz WzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7 MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsxMDBt44CAXDAzM1s0ODs1OzI1Mm3jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyMzJt44CAXDAzM1s0ODs1OzIzMm3jgIBcMDMzWzQ4OzU7MjUybeOAgFwwMzNbNDg7NTs5 NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTsyNTRt44CAXDAz M1s0ODs1OzIzMm3jgIBcMDMzWzQ4OzU7MjMybeOAgFwwMzNbNDg7NTsyNTRt44CAXDAzM1s0ODs1 OzI0OG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzBtXG4KXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7OTRt 44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTsyNTJt44CAXDAzM1s0ODs1OzIzMm3jgIBcMDMz WzQ4OzU7MjMybeOAgFwwMzNbNDg7NTsyMzJt44CAXDAzM1s0ODs1OzI1NG3jgIBcMDMzWzQ4OzU7 OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTsyNDht44CAXDAzM1s0ODs1OzI1NG3jgIBc MDMzWzQ4OzU7MjMybeOAgFwwMzNbNDg7NTsyMzJt44CAXDAzM1s0ODs1OzI1NG3jgIBcMDMzWzQ4 OzU7MjUybeOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMz WzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1swbVxuClwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1Ozk0 beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7MjU0beOAgFwwMzNbNDg7NTsyMzJt44CAXDAz M1s0ODs1OzIzMm3jgIBcMDMzWzQ4OzU7MjMybeOAgFwwMzNbNDg7NTsyNTRt44CAXDAzM1s0ODs1 OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTsyNTRt44CA XDAzM1s0ODs1OzIzMm3jgIBcMDMzWzQ4OzU7MjMybeOAgFwwMzNbNDg7NTsyNTRt44CAXDAzM1s0 ODs1OzI1Mm3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbMG1cbgpcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTs1 OG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTsyNTRt44CAXDAz M1s0ODs1OzI1Mm3jgIBcMDMzWzQ4OzU7MjU0beOAgFwwMzNbNDg7NTsxMDBt44CAXDAzM1s0ODs1 Ozk0beOAgFwwMzNbNDg7NTsxMDBt44CAXDAzM1s0ODs1OzEwMG3jgIBcMDMzWzQ4OzU7MjU0beOA gFwwMzNbNDg7NTsyNTRt44CAXDAzM1s0ODs1OzI1NG3jgIBcMDMzWzQ4OzU7MjU0beOAgFwwMzNb NDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbMG1cbgpcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTs1 OG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTsxMDBt44CAXDAz M1s0ODs1OzI1Mm3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTsxMDBt44CAXDAzM1s0ODs1 OzEwMG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBc MDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTsyNDht44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7 NTs5NG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzBtXG4KXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTsxMDBt 44CAXDAzM1s0ODs1OzEwMG3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTsxMDBt44CAXDAz M1s0ODs1OzEwMG3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7 OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAz M1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzU4 beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1OzU4beOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzBtXG4KXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7OTRt 44CAXDAzM1s0ODs1OzEwMG3jgIBcMDMzWzQ4OzU7MTAwbeOAgFwwMzNbNDg7NTs5NG3jgIBcMDMz WzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7MjUy beOAgFwwMzNbNDg7NTsyNTJt44CAXDAzM1s0ODs1OzI1Mm3jgIBcMDMzWzQ4OzU7MjUybeOAgFww MzNbNDg7NTsyNTJt44CAXDAzM1s0ODs1OzI1Mm3jgIBcMDMzWzQ4OzU7MjUybeOAgFwwMzNbNDg7 NTsyNTJt44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7NTht44CA XDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1 OzU4beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1swbVxuClwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1Ozk0beOAgFww MzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5 NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMz WzQ4OzU7OTRt44CAXDAzM1s0ODs1OzI1NG3jgIBcMDMzWzQ4OzU7MjU0beOAgFwwMzNbNDg7NTsy NTRt44CAXDAzM1s0ODs1OzI1NG3jgIBcMDMzWzQ4OzU7MjUybeOAgFwwMzNbNDg7NTs1OG3jgIBc MDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7 OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzBtXG4KXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0 beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNb NDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3j gIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzI1NG3jgIBcMDMzWzQ4OzU7MjU0beOAgFwwMzNb NDg7NTsyNDht44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7OTRt 44CAXDAzM1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0 ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMz WzBtXG4KXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7 NTs5NG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBc MDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7 NTht44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7NTht44CAXDAz M1s0ODs1Ozk0beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1Ozk0 beOAgFwwMzNbNDg7NTs5NG3jgIBcMDMzWzQ4OzU7OTRt44CAXDAzM1s0ODs1OzU4beOAgFwwMzNb NDg7NTs1OG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzBtXG4KXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0 ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTs1OG3jgIBcMDMz WzQ4OzU7NTht44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7NTht 44CAXDAzM1s0ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7NTht44CAXDAzM1s0 ODs1OzU4beOAgFwwMzNbNDg7NTs1OG3jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbMG1cbgpcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzBtXG4KXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMz WzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7 MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1swbVxuClww MzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMz WzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7 MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb MG1cbgpcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFww MzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt 44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAz M1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1 OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23j gIBcMDMzWzBtXG4KXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4 OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQz beOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFww MzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7 NTsyNDNt44CAXDAzM1swbVxuClwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMz WzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7 MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOA gFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNb NDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsy NDNt44CAXDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CA XDAzM1s0ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0 ODs1OzI0M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0 M23jgIBcMDMzWzQ4OzU7MjQzbeOAgFwwMzNbNDg7NTsyNDNt44CAXDAzM1s0ODs1OzI0M23jgIBc MDMzWzQ4OzU7MjQzbeOAgFwwMzNbMG1cbg== ================================================ FILE: lib/super_unko/unko.cow ================================================ binmode STDOUT, ":utf8"; $the_cow =<&2 return 1 fi while ((0 < $#)); do local opt=$1 shift case "$opt" in help) usage return ;; setup) # フォーマットとlintに使うDockerイメージを取得 docker-compose pull formatter linter ;; format) # コードフォーマットにかける overwrite="" cmd_format "$@" print_check_result return $? ;; format-save) # コードフォーマットにかけて上書き保存 overwrite="-w" cmd_format "$@" print_check_result return $? ;; lint) # 静的解析 cmd_lint "$@" print_check_result return $? ;; all) # コードフォーマット+静的解析 cmd_format "$@" cmd_lint "$@" print_check_result return $? ;; *) usage >&2 return 1 ;; esac done } usage() { cat << EOS $SCRIPT_NAME はプロジェクト内のシェルスクリプトのコードスタイルチェックをします。 Usage: $SCRIPT_NAME Available commands: help このヘルプを出力する。 setup リントツールをセットアップする。 format [files...] コードフォーマットにかける。 format-save [files...] コードフォーマットして上書き保存する。 lint [files...] リントにかける。 all プロジェクト全体をフォーマットとリントにかける。 EOS } ## フォーマットにかけるサブコマンド。 cmd_format() { # 引数(ファイル)の指定があればそのファイルを解析する # なければデフォルト指定(プロジェクト全体)のファイルを解析する local files=("${DEFAULT_TARGET_FILES[@]}") if [[ 0 -lt $# ]]; then files=("$@") fi # テストするファイルの件数を加算 test_count=$((test_count + ${#files[@]})) # コンテナ内のマウントディレクトリのフルパスに変更 local fullpath_files=() for f in "${files[@]}"; do fullpath_files+=("$CONTAINER_DIR_PREFIX/$f") done run_shfmt "${fullpath_files[@]}" } ## フォーマットにかける。 run_shfmt() { local files=("$@") local ret docker-compose run formatter $overwrite "${files[@]}" ret=$? if [[ "$ret" -ne 0 ]]; then err_count=$((err_count + 1)) fi } ## 静的解析にかけるサブコマンド。 cmd_lint() { # 引数(ファイル)の指定があればそのファイルを解析する # なければデフォルト指定(プロジェクト全体)のファイルを解析する local files=("${DEFAULT_TARGET_FILES[@]}") if [[ 0 -lt $# ]]; then files=("$@") fi # テストするファイルの件数を加算 test_count=$((test_count + ${#files[@]})) # コンテナ内のマウントディレクトリのフルパスに変更 local fullpath_files=() for f in "${files[@]}"; do # unko.puzzleはスキップする if [[ "$f" =~ ^.*unko.puzzle$ ]]; then continue fi fullpath_files+=("$CONTAINER_DIR_PREFIX/$f") done run_shellcheck "${fullpath_files[@]}" } ## 静的解析にかける。 run_shellcheck() { local files=("$@") local ret docker-compose run linter "${files[@]}" ret=$? if [[ "$ret" -ne 0 ]]; then err_count=$((err_count + 1)) fi } ## テストの結果を出力する。 print_check_result() { echo "--------------------------------------------------------------------------------" if [[ "$err_count" -lt 1 ]]; then echo -e "[ ${GREEN}PASS${RESET} ] ($test_count/$test_count) all lint were passed." return else echo -e "[ ${RED}FAIL${RESET} ] lint were failed." return 1 fi } main ${1+"$@"} exit $? ================================================ FILE: package.sh ================================================ #!/bin/bash set -ue THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR { cd "${THIS_DIR}" tar zcvf super_unko.tar.gz bin lib .tar2package.yml docker run -i greymd/tar2rpm:1.0.1 < super_unko.tar.gz > pkg/super_unko.rpm.tmp mv pkg/super_unko.rpm{.tmp,} docker run -i greymd/tar2deb:1.0.1 < super_unko.tar.gz > pkg/super_unko.deb.tmp mv pkg/super_unko.deb{.tmp,} rm super_unko.tar.gz } ================================================ FILE: super_unko.plugin.zsh ================================================ source "`dirname $0`/activate.sh" ================================================ FILE: test/functions.sh ================================================ #!/bin/bash coverage() { # kcovのインストールされている環境でのみ実行 if type kcov 2> /dev/null; then local options=(--bash-dont-parse-binary-dir) kcov "${options[@]}" coverage "$@" || true fi } ================================================ FILE: test/super_unko-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="$(pwd)/../bin/super_unko" @test "コマンドを指定しない場合はヘルプを出力して、異常終了する" { run "$TARGET_COMMAND" [ "$status" -ne 0 ] coverage "$TARGET_COMMAND" } @test "ヘルプを明示的に出力するときは正常終了する" { run "$TARGET_COMMAND" help [ "$status" -eq 0 ] coverage "$TARGET_COMMAND" help } @test "unko.lsを呼び出す" { run "$TARGET_COMMAND" ls [ "$status" -eq 0 ] [ "${lines[0]}" = うんこ ] coverage "$TARGET_COMMAND" ls } @test "unko.anyを呼び出す" { run "$TARGET_COMMAND" any [ "$status" -eq 0 ] coverage "$TARGET_COMMAND" any } @test "unko.trを呼び出す" { run "$TARGET_COMMAND" tr <<< うんこ [ "$status" -eq 0 ] [ "${lines[0]}" = 💩 ] coverage "$TARGET_COMMAND" tr <<< うんこ } @test "unko.towerを呼び出す" { run "$TARGET_COMMAND" tower [ "$status" -eq 0 ] [ "${lines[0]}" = "     人" ] [ "${lines[1]}" = "   (   )" ] [ "${lines[2]}" = "  (     )" ] [ "${lines[3]}" = " (       )" ] coverage "$TARGET_COMMAND" tower } @test "unko.tower 2を呼び出す" { run "$TARGET_COMMAND" tower 2 [ "$status" -eq 0 ] [ "${lines[0]}" = "    人" ] [ "${lines[1]}" = "  (   )" ] [ "${lines[2]}" = " (     )" ] coverage "$TARGET_COMMAND" tower 2 } @test "bigunko.showを呼び出す" { run "$TARGET_COMMAND" bigshow [ "$status" -eq 0 ] coverage "$TARGET_COMMAND" bigshow } #@test "unko.pingを呼び出す" { # run "$TARGET_COMMAND" ping # [ "$status" -eq 0 ] # coverage "$TARGET_COMMAND" ping #} @test "存在しないコマンドのときは異常終了する" { run "$TARGET_COMMAND" unchi [ "$status" -ne 0 ] coverage "$TARGET_COMMAND" unchi } ================================================ FILE: test/unko.any-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="../bin/unko.any" readonly BASH_REQUIRE_VERSION=4.0 #============================================================================== # NOTE: # echo-sdはBash4.0以下では動かないため、Bash4.1以上のみテストする #============================================================================== bash_version=$(bash --version | grep -Eo "[0-9]+\.[0-9]+" | head -n 1) if [ $(echo "$BASH_REQUIRE_VERSION < $bash_version" | bc) -eq 0 ]; then echo " Bash${BASH_REQUIRE_VERSION}以下はスキップ" exit 0 fi @test '引数がない場合はヘルプを出力する' { run "$TARGET_COMMAND" [ "$status" -eq 0 ] coverage "$TARGET_COMMAND" } @test '引数が1つのときは💩の置換のみ' { run "$TARGET_COMMAND" あ [ "$status" -eq 0 ] [ "${lines[0]}" = "_人人人人人人_" ] [ "${lines[1]}" = "> 突然の死 <" ] [ "${lines[2]}" = " ̄Y^Y^Y^Y^Y^Y^ ̄" ] [ "${lines[3]}" = "      👑" ] [ "${lines[4]}" = "    (あああ)" ] [ "${lines[5]}" = "   (あ👁あ👁あ)" ] [ "${lines[6]}" = "  (あああ👃あああ)" ] [ "${lines[7]}" = " (ああああ👄ああああ)" ] coverage "$TARGET_COMMAND" あ } @test '引数が2つのときは💩の置換と文言変更' { run "$TARGET_COMMAND" あ い [ "$status" -eq 0 ] [ "${lines[0]}" = "_人人人_" ] [ "${lines[1]}" = "> い <" ] [ "${lines[2]}" = " ̄Y^Y^Y^ ̄" ] [ "${lines[3]}" = "      👑" ] [ "${lines[4]}" = "    (あああ)" ] [ "${lines[5]}" = "   (あ👁あ👁あ)" ] [ "${lines[6]}" = "  (あああ👃あああ)" ] [ "${lines[7]}" = " (ああああ👄ああああ)" ] coverage "$TARGET_COMMAND" あ い } @test '引数に /' { run "$TARGET_COMMAND" / [ "$status" -eq 0 ] [ "${lines[0]}" = "_人人人人人人_" ] [ "${lines[1]}" = "> 突然の死 <" ] [ "${lines[2]}" = " ̄Y^Y^Y^Y^Y^Y^ ̄" ] [ "${lines[3]}" = "      👑" ] [ "${lines[4]}" = "    (///)" ] [ "${lines[5]}" = "   (/👁/👁/)" ] [ "${lines[6]}" = "  (///👃///)" ] [ "${lines[7]}" = " (////👄////)" ] coverage "$TARGET_COMMAND" あ い } @test '引数にエスケープ文字' { run "$TARGET_COMMAND" '\\' [ "$status" -eq 0 ] [ "${lines[0]}" = '_人人人人人人_' ] [ "${lines[1]}" = '> 突然の死 <' ] [ "${lines[2]}" = ' ̄Y^Y^Y^Y^Y^Y^ ̄' ] [ "${lines[3]}" = '      👑' ] [ "${lines[4]}" = '    (\\\)' ] [ "${lines[5]}" = '   (\👁\👁\)' ] [ "${lines[6]}" = '  (\\\👃\\\)' ] [ "${lines[7]}" = ' (\\\\👄\\\\)' ] coverage "$TARGET_COMMAND" '\\' } @test 'ASCIIコード表33~127まででの置換 (エスケープ文字は除外)' { grep -o . <<< '!"#$%&'"'"'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~' | while read -r ch; do run "$TARGET_COMMAND" "$ch" [ "$status" -eq 0 ] [ "${lines[0]}" = "_人人人人人人_" ] [ "${lines[1]}" = "> 突然の死 <" ] [ "${lines[2]}" = " ̄Y^Y^Y^Y^Y^Y^ ̄" ] [ "${lines[3]}" = "      👑" ] [ "${lines[4]}" = "    ($ch$ch$ch)" ] [ "${lines[5]}" = "   ($ch👁$ch👁$ch)" ] [ "${lines[6]}" = "  ($ch$ch$ch👃$ch$ch$ch)" ] [ "${lines[7]}" = " ($ch$ch$ch$ch👄$ch$ch$ch$ch)" ] coverage "$TARGET_COMMAND" "$ch" done } ================================================ FILE: test/unko.encode-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="../bin/unko.encode" @test "-h でヘルプを出力する" { run "$TARGET_COMMAND" -h echo "$output" [ "$status" -eq 0 ] [[ "${lines[0]}" =~ ^Usage:.* ]] coverage "$TARGET_COMMAND" -h } @test "--help でヘルプを出力する" { run "$TARGET_COMMAND" --help echo "$output" [ "$status" -eq 0 ] [[ "${lines[0]}" =~ ^Usage:.* ]] coverage "$TARGET_COMMAND" --help } @test '引数なしのときは標準入力をエンコード' { run "$TARGET_COMMAND" <<< うんこ echo "$output" [ "$status" -eq 0 ] [ "${lines[0]}" = "ウンウこうんこう💩ウンウこうこここウウンウこうんここウうんこ" ] coverage "$TARGET_COMMAND" <<< うんこ } @test '-d で標準入力をデコード { run "$TARGET_COMMAND" -d <<< ウンウこうんこう💩ウンウこうこここウウンウこうんここウうんこ echo "$output" [ "$status" -eq 0 ] [ "${lines[0]}" = "うんこ" ] coverage "$TARGET_COMMAND" -d <<< ウンウこうんこう💩ウンウこうこここウウンウこうんここウうんこ } @test '--decode で標準入力をデコード { run "$TARGET_COMMAND" --decode <<< ウンウこうんこう💩ウンウこうこここウウンウこうんここウうんこ echo "$output" [ "$status" -eq 0 ] [ "${lines[0]}" = "うんこ" ] coverage "$TARGET_COMMAND" --decode <<< ウンウこうんこう💩ウンウこうこここウウンウこうんここウうんこ } @test 'ファイルが存在しない場合エラー' { export LANG=ja_JP.UTF-8 run "$TARGET_COMMAND" うんこ echo "$output" [ "$status" -eq 1 ] [[ "${lines[0]}" =~ .*そのようなファイルやディレクトリはありません ]] coverage LANG=ja_JP.UTF-8 "$TARGET_COMMAND" うんこ } @test 'ディレクトリの場合エラー' { export LANG=ja_JP.UTF-8 run "$TARGET_COMMAND" . echo "$output" [ "$status" -eq 1 ] [[ "${lines[0]}" =~ .*ディレクトリです ]] coverage LANG=ja_JP.UTF-8 "$TARGET_COMMAND" . } @test 'ファイルが存在しない場合エラー(英語版)' { export LANG=en_US.UTF-8 run "$TARGET_COMMAND" うんこ echo "$output" [ "$status" -eq 1 ] [[ "${lines[0]}" =~ .*"No such file or directory" ]] coverage LANG=en_US.UTF-8 "$TARGET_COMMAND" うんこ } @test 'ディレクトリの場合エラー(英語版)' { export LANG=en_US.UTF-8 run "$TARGET_COMMAND" . echo "$output" [ "$status" -eq 1 ] [[ "${lines[0]}" =~ .*"Is a directory" ]] coverage LANG=en_US.UTF-8 "$TARGET_COMMAND" . } ================================================ FILE: test/unko.fizzbuzz-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="$(pwd)/../bin/unko.fizzbuzz" readonly BASH_REQUIRE_VERSION=4.0 #============================================================================== # NOTE: # echo-sdはBash4.0以下では動かないため、Bash4.1以上のみテストする #============================================================================== bash_version=$(bash --version | grep -Eo "[0-9]+\.[0-9]+" | head -n 1) if [ $(echo "$BASH_REQUIRE_VERSION < $bash_version" | bc) -eq 0 ]; then echo " Bash${BASH_REQUIRE_VERSION}以下はスキップ" exit 0 fi @test "引数がない時はヘルプを出力する" { run "$TARGET_COMMAND" [ "$status" -eq 0 ] [[ "${lines[0]}" =~ .*unko.fizzbuzz:* ]] coverage "$TARGET_COMMAND" } @test "引数が正の整数でない時はヘルプを出力する" { for i in -1 1.1 a whoami '$(whoami)' あ 漢字 "" - "*" / "?" '_[$(whoami >&2)]'; do run "$TARGET_COMMAND" "$i" [ "$status" -eq 0 ] [[ "${lines[0]}" =~ .*unko.fizzbuzz:* ]] coverage "$TARGET_COMMAND" "$i" done } @test "引数が0のときは何も出力しない" { run "$TARGET_COMMAND" 0 [ "$status" -eq 0 ] [[ "${lines[0]}" == "" ]] coverage "$TARGET_COMMAND" 0 } @test "引数が3のときは3まで出力する" { run "$TARGET_COMMAND" 3 [ "$status" -eq 0 ] [[ "${lines[0]}" == 1 ]] [[ "${lines[1]}" == 2 ]] [[ "${lines[2]}" =~ .*fizz$ ]] [[ "${lines[3]}" == "" ]] coverage "$TARGET_COMMAND" 3 } @test "引数が16のときは16まで出力する" { run "$TARGET_COMMAND" 16 [ "$status" -eq 0 ] [[ "${lines[1]}" == 2 ]] [[ "${lines[2]}" =~ .*fizz$ ]] [[ "${lines[3]}" == 4 ]] [[ "${lines[4]}" =~ .*buzz$ ]] [[ "${lines[5]}" =~ .*fizz$ ]] [[ "${lines[14]}" =~ .*人人.* ]] [[ "${lines[15]}" =~ .*fizzbuzz.* ]] coverage "$TARGET_COMMAND" 16 } ================================================ FILE: test/unko.grep-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="../bin/unko.grep" @test "unko.grepはうんことマッチする" { run "$TARGET_COMMAND" <<< "$(echo -e 'うんこ\nあ')" [ "$status" -eq 0 ] [ "$output" = うんこ ] coverage "$TARGET_COMMAND" <<< "$(echo -e 'うんこ\nあ')" } @test "unko.grepはうんこ(2行)とマッチする" { run "$TARGET_COMMAND" <<< "$(echo -e 'うんこ\nうんち')" [ "$status" -eq 0 ] [ "${lines[0]}" = うんこ ] [ "${lines[1]}" = うんち ] coverage "$TARGET_COMMAND" <<< "$(echo -e 'うんこ\nうんち')" } @test "unko.grepは💩とマッチする" { run "$TARGET_COMMAND" <<< "💩" [ "$status" -eq 0 ] [ "$output" = 💩 ] coverage "$TARGET_COMMAND" <<< "💩" } ================================================ FILE: test/unko.king-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="$(pwd)/../bin/unko.king" readonly BASH_REQUIRE_VERSION=4.0 @test "-h でヘルプを出力する" { run "$TARGET_COMMAND" -h [ "$status" -eq 0 ] [[ "${lines[0]}" =~ ^unko.king.* ]] coverage "$TARGET_COMMAND" -h } @test "--help でヘルプを出力する" { run "$TARGET_COMMAND" --help [ "$status" -eq 0 ] [[ "${lines[0]}" =~ ^unko.king.* ]] coverage "$TARGET_COMMAND" --help } @test "-v でバージョンを出力する" { run "$TARGET_COMMAND" -v [ "$status" -eq 0 ] [[ "${lines[0]}" =~ ^v ]] coverage "$TARGET_COMMAND" -v } @test "--version でバージョンを出力する" { run "$TARGET_COMMAND" --version [ "$status" -eq 0 ] [[ "${lines[0]}" =~ ^v ]] coverage "$TARGET_COMMAND" --version } @test "引数未指定の時はデフォルト5になる" { run "$TARGET_COMMAND" [ "$status" -eq 0 ] [ "${lines[0]}" = "      👑" ] [ "${lines[1]}" = "    (💩💩💩)" ] [ "${lines[2]}" = "   (💩👁💩👁💩)" ] [ "${lines[3]}" = "  (💩💩💩👃💩💩💩)" ] [ "${lines[4]}" = " (💩💩💩💩👄💩💩💩💩)" ] coverage "$TARGET_COMMAND" } @test "引数 5" { run "$TARGET_COMMAND" 5 [ "$status" -eq 0 ] [ "${lines[0]}" = "      👑" ] [ "${lines[1]}" = "    (💩💩💩)" ] [ "${lines[2]}" = "   (💩👁💩👁💩)" ] [ "${lines[3]}" = "  (💩💩💩👃💩💩💩)" ] [ "${lines[4]}" = " (💩💩💩💩👄💩💩💩💩)" ] coverage "$TARGET_COMMAND" 5 } @test "0埋めの数値 (8進数のテスト)" { for i in '05' '07' '08' '09' '010'; do run "$TARGET_COMMAND" "$i" [ "$status" -eq 0 ] coverage "$TARGET_COMMAND" "$i" done } @test "引数 5 未満はNG" { for i in -1 0 1 2 3 4; do run "$TARGET_COMMAND" $i [ "$status" -ne 0 ] coverage "$TARGET_COMMAND" $i done } @test "引数 6" { run "$TARGET_COMMAND" 6 [ "$status" -eq 0 ] [ "${lines[0]}" = "       👑" ] [ "${lines[1]}" = "     (💩💩💩)" ] [ "${lines[2]}" = "    (💩👁💩👁💩)" ] [ "${lines[3]}" = "   (💩💩💩👃💩💩💩)" ] [ "${lines[4]}" = "  (💩💩💩💩👄💩💩💩💩)" ] [ "${lines[5]}" = " (💩💩💩💩💩💩💩💩💩💩💩)" ] coverage "$TARGET_COMMAND" 6 } @test "オプション以外の第1引数は数値のみ受け付ける" { for i in a whoami '$(whoami)' あ 漢字 "" - "*" / "?" '_[$(whoami >&2)]'; do run "$TARGET_COMMAND" "$i" [ "$status" -ne 0 ] [[ "$output" =~ ^.*ERR.*Invalid.*number.*$ ]] coverage "$TARGET_COMMAND" "$i" done } @test "第1引数に段数、第2引数が不正なケース" { for i in a whoami '$(whoami)' あ 漢字 "" - "*" / "?" '_[$(whoami >&2)]'; do run "$TARGET_COMMAND" 8 "$i" [ "$status" -ne 0 ] [[ "$output" =~ ^.*ERR.*Invalid.*sub.*command.*$ ]] coverage "$TARGET_COMMAND" 8 "$i" done } #============================================================================== # NOTE: # 以降のテストではecho-sdを使用する。 # echo-sdはBash4.0以下では動かないため、Bash4.1以上のみテストする。 #============================================================================== bash_version=$(bash --version | grep -Eo "[0-9]+\.[0-9]+" | head -n 1) if [ $(echo "$BASH_REQUIRE_VERSION < $bash_version" | bc) -eq 0 ]; then echo " Bash${BASH_REQUIRE_VERSION}以下はスキップ" exit 0 fi @test "第1引数にはshoutを受け付ける。デフォルトの段数は5" { run "$TARGET_COMMAND" shout こんにちは [ "$status" -eq 0 ] [[ "${lines[1]}" =~ ^.*こんにちは.*$ ]] [ "${lines[3]}" = "      👑" ] [ "${lines[4]}" = "    (💩💩💩)" ] [ "${lines[5]}" = "   (💩👁💩👁💩)" ] [ "${lines[6]}" = "  (💩💩💩👃💩💩💩)" ] [ "${lines[7]}" = " (💩💩💩💩👄💩💩💩💩)" ] coverage "$TARGET_COMMAND" shout こんにちは } @test "第1引数に段数、第2引数にshout" { run "$TARGET_COMMAND" 8 shout こんばんは [ "$status" -eq 0 ] [[ "${lines[1]}" =~ ^.*こんばんは.*$ ]] coverage "$TARGET_COMMAND" 8 shout こんばんは } @test "shoutの第3引数以降はオプション" { run bash -c "echo うんこ | $TARGET_COMMAND 7 shout -s" [ "$status" -eq 0 ] [[ "${lines[1]}" =~ ^.*うんこ.*$ ]] coverage bash -c "echo うんこ | $TARGET_COMMAND 7 shout -s" } ================================================ FILE: test/unko.printpnm-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="$(pwd)/../bin/unko.printpnm" setup() { export RUN_TEST=true load "$TARGET_COMMAND" } @test "unko.printpnmのmax_stage_col関数は引数1のとき13を返す" { run max_stage_col 1 [ "$status" -eq 0 ] [ "$output" -eq 13 ] coverage max_stage_col 1 } @test "unko.printpnmのmax_stage_row関数は引数1のとき8を返す" { run max_stage_row 1 [ "$status" -eq 0 ] [ "$output" -eq 8 ] coverage max_stage_row 1 } @test "unko.printpnmのmax_value関数は引数の中からもっとも大きな値を返す" { run max_value 1 2 3 [ "$status" -eq 0 ] [ "$output" -eq 3 ] coverage max_value 1 2 3 } @test "unko.printpnmのmax_value関数は引数の中からもっとも大きな値を返す。並び順は関係ない" { run max_value 3 2 1 [ "$status" -eq 0 ] [ "$output" -eq 3 ] coverage max_value 3 2 1 } @test "unko.printpnmのmax_value関数は引数の中からもっとも大きな値を返す。2桁の整数に対しても" { run max_value 10 12 3 [ "$status" -eq 0 ] [ "$output" -eq 12 ] coverage max_value 10 12 3 } @test "unko.printpnmのrepeat関数は引数の数だけ1を連続して返す" { run repeat 3 [ "$status" -eq 0 ] [ "$output" = 111 ] coverage repeat 3 } @test "unko.printpnmのrepeat関数は引数の数だけ引数を連続して返す" { run repeat 3 0 [ "$status" -eq 0 ] [ "$output" = 000 ] coverage repeat 3 0 } @test "unko.printpnmのalign_center関数は文字列を指定の文字で中央揃えして返す (奇数)" { run align_center 0 <<< "$(echo -e '1\n111')" [ "$status" -eq 0 ] [ "${lines[0]}" = "010" ] [ "${lines[1]}" = "111" ] coverage align_center 0 <<< "$(echo -e '1\n111')" } @test "unko.printpnmのalign_center関数は文字列を指定の文字で中央揃えして返す (偶数)" { run align_center 0 <<< "$(echo -e '1\n1111')" [ "$status" -eq 0 ] [ "${lines[0]}" = "0100" ] [ "${lines[1]}" = "1111" ] coverage align_center 0 <<< "$(echo -e '1\n1111')" } ================================================ FILE: test/unko.pyramid-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="../bin/unko.pyramid" @test 'unko.pyramidは引数なしのときは16段' { run "$TARGET_COMMAND" [ "$status" -eq 0 ] [ "${lines[0]}" = " 💩 " ] [ "${lines[1]}" = " 💩💩 " ] [ "${lines[2]}" = " 💩 💩 " ] [ "${lines[3]}" = " 💩💩💩💩 " ] [ "${lines[4]}" = " 💩 💩 " ] [ "${lines[5]}" = " 💩💩 💩💩 " ] [ "${lines[6]}" = " 💩 💩 💩 💩 " ] [ "${lines[7]}" = " 💩💩💩💩💩💩💩💩 " ] [ "${lines[8]}" = " 💩 💩 " ] [ "${lines[9]}" = " 💩💩 💩💩 " ] [ "${lines[10]}" = " 💩 💩 💩 💩 " ] [ "${lines[11]}" = " 💩💩💩💩 💩💩💩💩 " ] [ "${lines[12]}" = " 💩 💩 💩 💩 " ] [ "${lines[13]}" = " 💩💩 💩💩 💩💩 💩💩 " ] [ "${lines[14]}" = " 💩 💩 💩 💩 💩 💩 💩 💩 " ] [ "${lines[15]}" = "💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩" ] coverage "$TARGET_COMMAND" } @test 'unko.pyramidの美しさはブラウザのコードレビューでも確認できる' { run bash -c "$TARGET_COMMAND 8|tr 💩 🎄|sed '1s/🎄/👑/';yes 💩|head -2|xargs printf '% 11s\n'" [ "${lines[0]}" = " 👑 " ] [ "${lines[1]}" = " 🎄🎄 " ] [ "${lines[2]}" = " 🎄 🎄 " ] [ "${lines[3]}" = " 🎄🎄🎄🎄 " ] [ "${lines[4]}" = " 🎄 🎄 " ] [ "${lines[5]}" = " 🎄🎄 🎄🎄 " ] [ "${lines[6]}" = " 🎄 🎄 🎄 🎄 " ] [ "${lines[7]}" = "🎄🎄🎄🎄🎄🎄🎄🎄" ] [ "${lines[8]}" = " 💩" ] [ "${lines[9]}" = " 💩" ] } @test 'unko.pyramidの引数1' { run "$TARGET_COMMAND" 1 [ "$status" -eq 0 ] [ "${lines[0]}" = "💩" ] } @test "オプション以外の第1引数は数値のみ受け付ける" { for i in 0 16.5 a $ '_[$(whoami >&2)]' whoami '$(whoami)' あ 漢字 "*" / "?"; do run "$TARGET_COMMAND" "$i" [ "$status" -ne 0 ] [ "$output" = "unko.pyramid: Invalid number '${i}'" ] done } @test "第1引数に段数、第2引数が不正なケース" { for i in 0 16.5 a $ '_[$(whoami >&2)]' whoami '$(whoami)' あ 漢字 "*" / "?"; do run "$TARGET_COMMAND" 16 "$i" [ "$status" -ne 0 ] [ "$output" = "unko.pyramid: Invalid number '${i}'" ] done } @test "-から始まる不正なオプションはエラー" { for i in - -a --; do run "$TARGET_COMMAND" "$i" [ "$status" -ne 0 ] [ "$output" = "unko.pyramid: illegal option '${i}'" ] done } ================================================ FILE: test/unko.toilet-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="../bin/unko.toilet" @test "普通に実行" { run "$TARGET_COMMAND" [ "$status" -eq 0 ] coverage "$TARGET_COMMAND" } @test "おかしなオプション--お菓子" { run "$TARGET_COMMAND" --お菓子 [ "$status" -ne 0 ] coverage "$TARGET_COMMAND" --お菓子 } readonly HANAGE_BASE64="ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAg ICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIPCfkqkgICAg8J+SqSAg 8J+SqSAgICAKICDwn5KpICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAgIPCfkqkgIPCf kqkgICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICDwn5KpICDwn5KpICDwn5KpICAgIAogICAg 8J+SqSAg8J+SqSAgICAgIPCfkqnwn5Kp8J+SqSAgICAgICAg8J+SqfCfkqnwn5Kp8J+SqfCfkqkg IPCfkqnwn5KpICAgICAgICAgICAgICDwn5KpICAgICAgICAgIPCfkqnwn5Kp8J+SqSAgICAgIAog ICAg8J+SqSAgICDwn5Kp8J+SqfCfkqnwn5KpICAgICAgICAgICAgICAgIPCfkqkgICAgICAgIPCf kqnwn5KpICAgICAgICAgICAg8J+SqSAg8J+SqfCfkqnwn5Kp8J+SqfCfkqkgICAgICAgICAgCiAg 8J+SqSAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAg8J+SqSAgICAgIPCfkqkgICAgICAg ICAgICAgIPCfkqkgICAgICAgICAgICDwn5KpICAgICAgICAgIAogIPCfkqkgICAgICAgICAgICDw n5KpICAgICAgICAgICAgICDwn5KpICAgICAgICDwn5KpICAgICAgICAgICAgICDwn5KpICAgICAg ICAgICAg8J+SqSAgICAgICAgICAKICDwn5KpICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAg 8J+SqSAgICAgICAg8J+SqSAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgIPCfkqkgICAgICAg ICAgCiAg8J+SqSAgICAgIPCfkqnwn5Kp8J+SqfCfkqkgICAgICAgICAgICDwn5KpICAgIPCfkqnw n5Kp8J+SqfCfkqkgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICDwn5KpICAgICAgICAgIAog IPCfkqkgIPCfkqnwn5KpICAgICAg8J+SqfCfkqkgICAgICAgICAgICAgIPCfkqkgICAgICDwn5Kp 8J+SqSAgICAgICAgICAgICAg8J+SqfCfkqkgICAgICDwn5KpICAgICAgICAgICAgCiAg8J+SqfCf kqkgIPCfkqkgICAgICDwn5KpICDwn5KpICAgICAgICAgICAg8J+SqSAgICAgIPCfkqkgIPCfkqkg ICAgICAgICAgICDwn5KpICAgICAgICDwn5KpICAgICAgICAgICAgCiAgICDwn5KpICAgIPCfkqnw n5Kp8J+SqSAgICAgICAgICAgICAgICAgICAg8J+SqfCfkqnwn5KpICAgICAgICAgICAgICAgICAg ICAgICAgICDwn5KpICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK" @test "stdinから" { run bash -c "echo はなげ| $TARGET_COMMAND | base64" [ "$status" -eq 0 ] [ "$output" = "$HANAGE_BASE64" ] coverage "$TARGET_COMMAND" <<< はなげ } # @test "引数に" { # run bash -c "$TARGET_COMMAND はなげ | base64" # [ "$status" -eq 0 ] # [ "$output" = "$HANAGE_BASE64" ] # coverage "$TARGET_COMMAND" はなげ # } # @test "flip" { # run bash -c "$TARGET_COMMAND --flip | base64" # [ "$status" -eq 0 ] # [ "$output" = "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIPCfkqnwn5KpICAgICAg # ICAgIAogICAgICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICAgICAgICDwn5Kp # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICDwn5Kp8J+SqfCf # kqnwn5Kp8J+SqSAgICAgICAgICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICAg # ICAg8J+SqfCfkqnwn5Kp8J+SqSAgICAgICAgCiAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICDwn5Kp # 8J+SqSAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIPCf # kqkgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAgIPCfkqkg # ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAg # ICAgICDwn5Kp8J+SqfCfkqkgICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAKICAg # ICAgICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICDwn5KpICAgIPCfkqkgICAg # ICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAKICAgICAgICDwn5KpICAgICAgICAgIPCf # kqkgICAgICAgICAgICDwn5KpICAgICAg8J+SqSAgICAgIPCfkqkgICAgICAgICAgICAgICAg8J+S # qSAgICAgICAgICAgICAgCiAgICAgICAgICDwn5Kp8J+SqfCfkqnwn5Kp8J+SqSAgICAgICAgICAg # ICAgICDwn5KpICAgIPCfkqkgICAgICDwn5KpICAgICAgICAgICAgICAgICAg8J+SqSAgICAgICAg # ICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIPCfkqnwn5KpICAgICAg # ICAgIPCfkqkgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgIAogICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgIAo=" ] # coverage "$TARGET_COMMAND" --flip # } # # @test "flop" { # run bash -c "$TARGET_COMMAND --flop | base64" # [ "$status" -eq 0 ] # [ "$output" = "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAog # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAg # ICDwn5KpICAgICAgICAgIPCfkqnwn5KpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAKICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAgIPCfkqkgICAgICDwn5KpICAg # IPCfkqkgICAgICAgICAgICAgICAg8J+SqfCfkqnwn5Kp8J+SqfCfkqkgICAgICAgICAgCiAgICAg # ICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICDwn5KpICAgICAg8J+SqSAgICAgIPCfkqkgICAg # ICAgICAgICDwn5KpICAgICAgICAgIPCfkqkgICAgICAgIAogICAgICAgICAgICAgIPCfkqkgICAg # ICAgICAgICAgICAgICDwn5KpICAgIPCfkqkgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAg # ICAgICAgICAgICAgIAogICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICDwn5Kp8J+S # qfCfkqkgICAgICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICAgICAgCiAgICAg # ICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAg # ICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # IAogICAg8J+SqfCfkqkgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICAgIPCfkqkgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgCiAgICAgICAg8J+SqfCfkqnw # n5Kp8J+SqSAgICAgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAgICAgICAg # 8J+SqfCfkqnwn5Kp8J+SqfCfkqkgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAg # ICAgICAKICAgICAgICAgIPCfkqnwn5KpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgIPCfkqkgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgIAo=" ] # coverage "$TARGET_COMMAND" --flop # } # # @test "180" { # run bash -c "$TARGET_COMMAND --180 | base64" # [ "$status" -eq 0 ] # [ "$output" = "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAog # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICDwn5Kp8J+SqSAgICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAg8J+SqSAgICAg # ICAgICAKICAgICAgICAgIPCfkqnwn5Kp8J+SqfCfkqnwn5KpICAgICAgICAgICAgICAgIPCfkqkg # ICAg8J+SqSAgICAgIPCfkqkgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgCiAgICAg # ICAg8J+SqSAgICAgICAgICDwn5KpICAgICAgICAgICAg8J+SqSAgICAgIPCfkqkgICAgICDwn5Kp # ICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAg # 8J+SqSAgICAgICAgICAgICAgICAgIPCfkqkgICAg8J+SqSAgICAgICAgICAgICAgICAgIPCfkqkg # ICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAg # ICAg8J+SqfCfkqnwn5KpICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgCiAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAg # ICAgICAg8J+SqSAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAg # IAogICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg8J+SqSAgICAg # ICAgICAgICAgICAgICAg8J+SqSAgICAgICAg8J+SqfCfkqkgICAgCiAgICAgICAgICDwn5Kp8J+S # qfCfkqnwn5Kp8J+SqSAgICAgICAgICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAg # ICAgICAg8J+SqfCfkqnwn5Kp8J+SqSAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg8J+SqSAg # ICAgICAgICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgIPCfkqnwn5KpICAgICAgICAgIAogICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIPCf # kqkgICAgICAgIAo=" ] # coverage "$TARGET_COMMAND" --180 # } # # @test "right" { # run bash -c "$TARGET_COMMAND --right | base64" # [ "$status" -eq 0 ] # [ "$output" = "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDwn5Kp8J+SqSAgICAg # ICAgICAgICAgICAKICAgICAgICAgICAg8J+SqfCfkqkgICAgICAgICAgICAgICAgICAgICAgICAg # ICAg8J+SqfCfkqkgICAg8J+SqfCfkqnwn5Kp8J+SqQogICAgICAgICAgICAgICAg8J+SqfCfkqnw # n5Kp8J+SqfCfkqnwn5KpICAgICAgICAgICAgICAgIPCfkqnwn5KpICAgIPCfkqnwn5KpICAgIAog # ICAgICAgICAgICAgICAgICAgICAgICAgICAg8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCf # kqkgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAg8J+SqfCfkqkgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAg8J+SqfCf # kqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqkgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg # ICAgICAgICAgICAgICAgICAgICAgICAgICDwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+S # qfCfkqnwn5Kp8J+SqfCfkqkgICAgICAgIAogICAgICAgICAgICDwn5Kp8J+SqfCfkqnwn5Kp8J+S # qfCfkqnwn5Kp8J+SqSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAg # IPCfkqnwn5Kp8J+SqfCfkqkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # CiAgICAgICAgICAgICAgICAgICAg8J+SqfCfkqkgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgIPCfkqnwn5Kp8J+SqfCfkqnwn5Kp # 8J+SqSAgICAgICAgICAgICAgICDwn5Kp8J+SqSAgICAgICAgCiAgICAgICAgICAgICAgICDwn5Kp # 8J+SqSAgICAgICAgICAgICAgICAgICAgICAgIPCfkqnwn5KpICAgICAgICAgICAgCiAgICAgICAg # ICAgICAgICDwn5Kp8J+SqSAgICAgICAgICAgICAgICAgICAg8J+SqfCfkqnwn5Kp8J+SqSAgICAg # ICAgICAgIAogICAgICAgICAgICAgICAg8J+SqfCfkqnwn5Kp8J+SqSAgICAgICAgICAgICAgICAg # ICAg8J+SqfCfkqkgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo=" ] # coverage "$TARGET_COMMAND" --right # } # # @test "left" { # run bash -c "$TARGET_COMMAND --left | base64" # [ "$status" -eq 0 ] # [ "$output" = "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgIAogICAgICAgICAgICDwn5Kp8J+SqSAgICAgICAgICAgICAgICAgICAg8J+SqfCfkqnw # n5Kp8J+SqSAgICAgICAgICAgICAgICAKICAgICAgICAgICAg8J+SqfCfkqnwn5Kp8J+SqSAgICAg # ICAgICAgICAgICAgICAg8J+SqfCfkqkgICAgICAgICAgICAgICAgCiAgICAgICAgICAgIPCfkqnw # n5KpICAgICAgICAgICAgICAgICAgICAgICAg8J+SqfCfkqkgICAgICAgICAgICAgICAgCiAgICAg # ICAg8J+SqfCfkqkgICAgICAgICAgICAgICAg8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5KpICAgICAg # ICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICDwn5Kp8J+SqSAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICDwn5Kp8J+SqfCfkqnwn5KpICAgICAgICAgICAgCiAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAg8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqkgICAgICAg # ICAgICAKICAgICAgICDwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+S # qfCfkqkgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg # ICAgICDwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqSAgICAgICAgICAgICAgICAKICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDwn5Kp8J+SqSAgICAgICAg # ICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICDwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp # 8J+SqSAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgIPCfkqnwn5KpICAgIPCfkqnwn5Kp # ICAgICAgICAgICAgICAgIPCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqSAgICAgICAgICAgICAgICAK # 8J+SqfCfkqnwn5Kp8J+SqSAgICDwn5Kp8J+SqSAgICAgICAgICAgICAgICAgICAgICAgICAgICDw # n5Kp8J+SqSAgICAgICAgICAgIAogICAgICAgICAgICAgICAg8J+SqfCfkqkgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo=" ] # coverage "$TARGET_COMMAND" --left # } # # @test "border" { # run bash -c "$TARGET_COMMAND --border | base64" # [ "$status" -eq 0 ] # [ "$output" = "8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnw # n5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCf # kqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+S # qfCfkqkK8J+SqSAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg8J+SqQrwn5KpICAgICAgICAg # IPCfkqnwn5KpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgIPCfkqkK8J+SqSAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAg # ICAgICDwn5KpCvCfkqkgICAgICAgIPCfkqnwn5Kp8J+SqfCfkqkgICAgICAgICAgICAgICAgICAg # ICAg8J+SqSAgICAgICAgICAgICAgICAgICAgICAgIPCfkqnwn5Kp8J+SqfCfkqnwn5KpICAgICAg # ICAgIPCfkqkK8J+SqSAgICDwn5Kp8J+SqSAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAgICAg # 8J+SqSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICDwn5KpCvCf # kqkgICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg8J+SqQrwn5KpICAgICAgICAgICAgICAg # IPCfkqkgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgIPCfkqkK8J+SqSAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAg # ICAgIPCfkqnwn5Kp8J+SqSAgICAgICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICAg # ICAgICDwn5KpCvCfkqkgICAgICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICDwn5KpICAg # IPCfkqkgICAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAgICAgIPCfkqkK8J+S # qSAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgICAgICDwn5KpICAgICAg8J+SqSAgICAgIPCf # kqkgICAgICAgICAgICDwn5KpICAgICAgICAgIPCfkqkgICAgICAgIPCfkqkK8J+SqSAgICAgICAg # ICAgIPCfkqkgICAgICAgICAgICAgICAgICDwn5KpICAgICAg8J+SqSAgICDwn5KpICAgICAgICAg # ICAgICAgIPCfkqnwn5Kp8J+SqfCfkqnwn5KpICAgICAgICAgIPCfkqkK8J+SqSAgICAgICAgICDw # n5KpICAgICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICDwn5Kp8J+SqSAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAg8J+SqQrwn5KpICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAg8J+SqQrwn5KpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg8J+SqQrwn5KpICAgICAgICAg # ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg # ICAgICAgICAgICAgICAgICAg8J+SqQrwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCf # kqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+S # qfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp # 8J+SqfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqQo=" ] # coverage "$TARGET_COMMAND" --border # } readonly WIDTH_20="ICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAgCiAgICAgICAgICDwn5Kp8J+SqSAgICAgICAg ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICDwn5Kp8J+SqfCfkqnw n5KpICAgICAgICAgICAgCiAgICDwn5Kp8J+SqSAgICAgICAg8J+SqSAgICAgICAgICAKICAgICAg ICAgICAgICAgIPCfkqkgICAgICAgICAgCiAgICAgICAgICAgICAgICDwn5KpICAgICAgICAgIAog ICAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAKICAgICAgICAgICAgICDwn5KpICAgICAgICAg ICAgCiAgICAgICAgICAgICAg8J+SqSAgICAgICAgICAgIAogICAgICAgICAgICDwn5KpICAgICAg ICAgICAgICAKICAgICAgICAgIPCfkqkgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAg ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAg ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg ICAgICAgICAgICAgIAogICAgICAgIPCfkqkgICAgICAgICAgICAgICAgICAKICAgICAgICAgIPCf kqkgICAgICAgICAgICAgICAgCiAgICAgICAgICDwn5KpICAgICAgICAgICAgICAgIAogICAgICAg IPCfkqkgICAgICAgICAgICAgICAgICAKICAgICAgICDwn5KpICAgICAgICAgICAgICAgICAgCiAg ICAgIPCfkqnwn5Kp8J+SqSAgICAgICAgICAgICAgICAKICAgICAg8J+SqSAgICDwn5KpICAgICAg ICAgICAgICAKICAgIPCfkqkgICAgICDwn5KpICAgICAg8J+SqSAgICAgIAogICAg8J+SqSAgICAg IPCfkqkgICAg8J+SqSAgICAgICAgCiAg8J+SqSAgICAgICAgICDwn5Kp8J+SqSAgICAgICAgICAK ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAg IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgIPCfkqkgICAgICAgICAgICAgICAg ICAgIAogICAgICAgIPCfkqnwn5Kp8J+SqfCfkqnwn5KpICAgICAgICAgIAogICAgICAgICAgICAg IPCfkqkgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAg ICAgICAgICAgICAgICAgICAgCiAgICDwn5KpICAgICAgICAgICAgICAgICAgICAgIAogICAg8J+S qSAgICAgICAgICAgICAgICAgICAgICAKICAgICAg8J+SqSAgICAgICAgICDwn5KpICAgICAgICAK ICAgICAgICDwn5Kp8J+SqfCfkqnwn5Kp8J+SqSAgICAgICAgICAKICAgICAgICAgICAgICAgICAg ICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAg ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo=" # @test "-w 20" { # run bash -c "$TARGET_COMMAND -w 20 | base64" # [ "$status" -eq 0 ] # [ "$output" = "$WIDTH_20" ] # coverage "$TARGET_COMMAND" -w 20 # } # # @test "--width 20" { # run bash -c "$TARGET_COMMAND --width 20 | base64" # [ "$status" -eq 0 ] # [ "$output" = "$WIDTH_20" ] # coverage "$TARGET_COMMAND" --width 20 # } @test "--help" { run bash -c "$TARGET_COMMAND --help" [ "$status" -ne 0 ] coverage "$TARGET_COMMAND" --help } @test "-h" { run bash -c "$TARGET_COMMAND -h" [ "$status" -ne 0 ] coverage "$TARGET_COMMAND" -h } @test "-h == --help" { run bash -c "$TARGET_COMMAND -h 2>&1" [ "$status" -ne 0 ] [ "$output" = "$($TARGET_COMMAND --help 2>&1)" ] } @test "ヘルプメッセージは正しいかな?" { run bash -c "$TARGET_COMMAND --help 2>&1 | base64" [ "$status" -eq 0 ] [ "$output" = "VXNhZ2U6IHVua28udG9pbGV0IFsgLWh2IF0gWyAtdyBvdXRwdXR3aWR0aCBdCiAgICAgICAgICAg ICAgICAgICBbIC0tY3JvcCBdIFsgLS1mbGlwIF0gWyAtLWZsb3AgXQogICAgICAgICAgICAgICAg ICAgWyAtLTE4MCBdIFsgLS1sZWZ0IF0gWyAtLXJpZ2h0IF0KICAgICAgICAgICAgICAgICAgIFsg LS1ib3JkZXIgXSBbIG1lc3NhZ2UgXQoKICAtaCwgLS1oZWxwICAgICAgICAgICAgICAgICAg44GT 44Gu44OY44Or44OX44KS5Ye65Yqb44GX44Gm57WC5LqG44GX44G+44GZCiAgLXcsIC0td2lkdGgg PHdpZHRoLCBhdXRvPiAgIOWHuuWKm+OBruW5heOBp+OBmeOAgmF1dG/jgpLmjIflrprjgZnjgovj gajnq6/mnKvjga7luYXjgavjgarjgorjgb7jgZkKICAgICAgLS1jcm9wICAgICAgICAgICAgICAg ICAg5LiK5LiL5bem5Y+z44Gu54Sh6aeE44Gq44K544Oa44O844K544KS5YmK6Zmk44GX44G+44GZ CiAgICAgIC0tZmxpcCAgICAgICAgICAgICAgICAgIOawtOW5s+aWueWQkeOBq+WPjei7ouOBl+OB vuOBmQogICAgICAtLWZsb3AgICAgICAgICAgICAgICAgICDlnoLnm7TmlrnlkJHjgavlj43ou6Lj gZfjgb7jgZkKICAgICAgLS0xODAgICAgICAgICAgICAgICAgICAgMTgw5bqm5Zue6Lui44GX44G+ 44GZCiAgICAgIC0tbGVmdCAgICAgICAgICAgICAgICAgIOW3puOBuDkw5bqm5Zue6Lui44GX44G+ 44GZCiAgICAgIC0tcmlnaHQgICAgICAgICAgICAgICAgIOWPs+OBuDkw5bqm5Zue6Lui44GX44G+ 44GZCiAgICAgIC0tYm9yZGVyICAgICAgICAgICAgICAgIOaeoOe3muOCkuOBpOOBkeOBvuOBmQo=" ] } @test "--version" { run "$TARGET_COMMAND" --version [ "$status" -eq 0 ] coverage "$TARGET_COMMAND" --version } @test "-v" { run "$TARGET_COMMAND" -v [ "$status" -eq 0 ] coverage "$TARGET_COMMAND" -v } @test "--version == -v" { run "$TARGET_COMMAND" -v [ "$status" -eq 0 ] [ "$output" = "$($TARGET_COMMAND --version)" ] } @test "バージョン情報は正しいかな?" { run bash -c "$TARGET_COMMAND --version | base64" [ "$status" -eq 0 ] [ "$output" = "dW5rby50b2lsZXQgdmVyc2lvbiDwn5KpLvCfkqku8J+SqSAoMjDwn5Kp8J+SqS/wn5Kp8J+SqS/w n5Kp8J+SqSkK" ] } @test "全テスト終わり💩" { [ "💩" = "💩" ] } ================================================ FILE: test/unko.tower-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="../bin/unko.tower" @test 'unko.towerは引数なしのときは3段' { run "$TARGET_COMMAND" [ "$status" -eq 0 ] [ "${lines[0]}" = "     人" ] [ "${lines[1]}" = "   (   )" ] [ "${lines[2]}" = "  (     )" ] [ "${lines[3]}" = " (       )" ] coverage "$TARGET_COMMAND" } @test 'unko.towerで引数2' { run "$TARGET_COMMAND" 2 [ "$status" -eq 0 ] [ "${lines[0]}" = "    人" ] [ "${lines[1]}" = "  (   )" ] [ "${lines[2]}" = " (     )" ] coverage "$TARGET_COMMAND" 2 } @test 'unko.towerで引数4' { run "$TARGET_COMMAND" 4 [ "$status" -eq 0 ] [ "${lines[0]}" = "      人" ] [ "${lines[1]}" = "    (   )" ] [ "${lines[2]}" = "   (     )" ] [ "${lines[3]}" = "  (       )" ] [ "${lines[4]}" = " (         )" ] coverage "$TARGET_COMMAND" 4 } @test 'unko.towerでメッセージを埋め込む' { run "$TARGET_COMMAND" -s あい [ "$status" -eq 0 ] [ "${lines[0]}" = "     人" ] [ "${lines[1]}" = "   (あいあ)" ] [ "${lines[2]}" = "  (いあいあい)" ] [ "${lines[3]}" = " (あいあいあいあ)" ] coverage "$TARGET_COMMAND" -s あい } @test 'unko.towerで先頭から文字数分だけメッセージを埋め込む' { run "$TARGET_COMMAND" -m あい [ "$status" -eq 0 ] [ "${lines[0]}" = "     人" ] [ "${lines[1]}" = "   (あい )" ] [ "${lines[2]}" = "  (     )" ] [ "${lines[3]}" = " (       )" ] coverage "$TARGET_COMMAND" -m あい } @test 'unko.towerで半角文字は全角文字1つ分で置換される' { run "$TARGET_COMMAND" -m ab [ "$status" -eq 0 ] [ "${lines[0]}" = "     人" ] [ "${lines[1]}" = "   (a b  )" ] [ "${lines[2]}" = "  (     )" ] [ "${lines[3]}" = " (       )" ] coverage "$TARGET_COMMAND" -m ab } @test 'unko.tower -mで置換文字に/が含まれていても置換できる' { run "$TARGET_COMMAND" -m / [ "$status" -eq 0 ] [ "${lines[0]}" = "     人" ] [ "${lines[1]}" = "   (/   )" ] [ "${lines[2]}" = "  (     )" ] [ "${lines[3]}" = " (       )" ] coverage "$TARGET_COMMAND" -m / } @test 'unko.tower -sで置換文字に/が含まれていても置換できる' { run "$TARGET_COMMAND" -s / [ "$status" -eq 0 ] [ "${lines[0]}" = "     人" ] [ "${lines[1]}" = "   (/ / / )" ] [ "${lines[2]}" = "  (/ / / / / )" ] [ "${lines[3]}" = " (/ / / / / / / )" ] coverage "$TARGET_COMMAND" -s / } @test 'unko.tower -sで置換文字に\\が含まれていても置換できる' { run "$TARGET_COMMAND" -s '\\' [ "$status" -eq 0 ] [ "${lines[0]}" = '     人' ] [ "${lines[1]}" = '   (\ \ \ )' ] [ "${lines[2]}" = '  (\ \ \ \ \ )' ] [ "${lines[3]}" = ' (\ \ \ \ \ \ \ )' ] coverage "$TARGET_COMMAND" -s '\\' } @test 'unko.tower -sASCIIコード表33~127までの全ての文字は半角文字として扱う (\\は除外)' { grep -o . <<< '!"#$%&'"'"'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~' | while read -r ch; do run "$TARGET_COMMAND" -s "$ch" [ "$status" -eq 0 ] [ "${lines[0]}" = "     人" ] [ "${lines[1]}" = "   ($ch $ch $ch )" ] [ "${lines[2]}" = "  ($ch $ch $ch $ch $ch )" ] [ "${lines[3]}" = " ($ch $ch $ch $ch $ch $ch $ch )" ] coverage "$TARGET_COMMAND" -s "$ch" done } ================================================ FILE: test/unko.tr-test.bats ================================================ #!/usr/bin/env bats source functions.sh readonly TARGET_COMMAND="../bin/unko.tr" @test "unko.trでうんこは💩になる" { run "$TARGET_COMMAND" <<< うんこ [ "$status" -eq 0 ] [ "$output" = 💩 ] coverage "$TARGET_COMMAND" <<< うんこ } @test "unko.trでうんちは💩になる" { run "$TARGET_COMMAND" <<< うんち [ "$status" -eq 0 ] [ "$output" = 💩 ] coverage "$TARGET_COMMAND" <<< うんち } @test "unko.trで下痢は💩になる" { run "$TARGET_COMMAND" <<< 下痢 [ "$status" -eq 0 ] [ "$output" = 💩 ] coverage "$TARGET_COMMAND" <<< 下痢 } @test "unko.trで💩は💩になる" { run "$TARGET_COMMAND" <<< 💩 [ "$status" -eq 0 ] [ "$output" = 💩 ] coverage "$TARGET_COMMAND" <<< 💩 } ================================================ FILE: test/unko.yes-test.bats ================================================ #!/usr/bin/env bats source functions.sh #============================================================================== # NOTE: # yesをcoverageに渡しつつ、無限の出力を停止できないためcoverageを取得しない #============================================================================== readonly TARGET_COMMAND="../bin/unko.yes" @test "unko.yesの1つ目の文字列は💩である" { run bash -c "$TARGET_COMMAND | head -n 1" [ "$status" -eq 0 ] [ "${lines[0]}" = "💩" ] } @test "unko.yesの2つ目の文字列は💩である" { run bash -c "$TARGET_COMMAND | head -n 2" [ "$status" -eq 0 ] [ "${lines[0]}" = "💩" ] [ "${lines[1]}" = "💩" ] } ================================================ FILE: test.sh ================================================ #!/bin/bash SCRIPT_NAME="$(basename "${BASH_SOURCE:-$0}")" readonly SCRIPT_NAME readonly RED=$'\x1b[31m' readonly BLUE=$'\x1b[34m' readonly RESET=$'\x1b[m' cd test || exit 1 main() { # 引数未指定の場合は全てのテストを実行する local error_count=0 local ret if [[ $# -lt 1 ]]; then for test_script in *-test.bats; do echo -e "${BLUE}${test_script}${RESET}" ./"$test_script" ret=$? if [[ "$ret" -ne 0 ]]; then error_count=$((error_count + 1)) fi echo done return "$error_count" fi local cmd="$1" # ヘルプの出力 if [[ "$cmd" == help ]]; then usage return fi # マッチするコマンドのみ実行 for test_script in *-test.bats; do if [[ "$cmd"-test.bats == "$test_script" ]]; then echo -e "${BLUE}${test_script}${RESET}" ./"$test_script" ret=$? return "$ret" fi done usage >&2 return 1 } usage() { cat << EOS $SCRIPT_NAME はtestディレクトリ配下のテストスクリプトを実行する。 Usage: $SCRIPT_NAME 全てのテストを実行する $SCRIPT_NAME コマンド、あるいはテストスクリプトを実行する Available commands: help このヘルプを出力する test/*-test.batsの任意の1つのスクリプト Available test scripts: EOS for test_script in *-test.bats; do echo "${test_script//-test.bats/}" done } print_bash_version() { echo "------------------------------------------------------------------------------" bash --version echo "------------------------------------------------------------------------------" } type bats >&/dev/null ret=$? if [[ "$ret" -ne 0 ]]; then echo -e "[ ${RED}ERR${RESET} ] bats was not found. See a section of Testing on README." exit 1 fi print_bash_version main ${1+"$@"} ret=$? print_bash_version exit $ret ================================================ FILE: uninstall.sh ================================================ #!/bin/bash set -ue THIS_DIR=$( cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd ) readonly THIS_DIR readonly PREFIX="${1:-/usr/local}" readonly PREFIX_BIN="${PREFIX}/bin" readonly PREFIX_LIB="${PREFIX}/lib/super_unko" for cmd in "${THIS_DIR}"/bin/*; do rm -f "$PREFIX_BIN/$(basename "$cmd")" done rm -rf "$PREFIX_LIB" ================================================ FILE: 💩.💩 ================================================ 💩