OmniAICreator/Qiita-1.07M huggingface dataset:
暗号化方式まとめ

# 1.はじめに
普段「暗号化」や「SSL/TLS」という言葉を使ったり、耳にしたりします。
ですが、実際暗号化ってどんなことしているのかよくわかっていなかったので、調べてみました。

# 2.そもそも暗号化とは
##### ◼️暗号化とは？
・通信文を第三者が見てもわからないように変換する手法
・SSL/TLSというプロトコルを使っている

##### ◼️暗号化技術が実現する3つのこと
・機密性：秘密が守られること
・真正性：本人であることが検証できること
・完全性：データが改竄されることなく転送されること

##### ◼️TLSとは？
・Transport Layer Securityの略称
・転送される情報を守るためのプロトコル
・プレゼンテーション層のプロトコル
・トランスポート層のためのセキュリティ

##### ◼️SSLとは？
・Secure Socket Layerの略称
・TLSの前身
　
# 3.暗号化方式

## 3-1.共通鍵暗号化方式
仕組み：図3.1のようにAさんとBさんのみが知っている秘密鍵を使って暗号化、複合化を実施(AさんとBさんの使用している鍵は「共通」している「秘密鍵」)
良い点：第三者が暗号化されたデータを見ても、鍵がない限り元のデータを見れない
注意点：秘密鍵を第三者に盗まれると外部に情報が漏れてしまう

![pasted image 0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329544/69fea8d8-1a85-d738-5200-2fb1734afa8e.png)
図3.1.共通鍵暗号化方式


共通鍵暗号化方式は大きくストリーム暗号化方式とブロック暗号化方式に分かれる


### 3-1-1.ストリーム暗号化方式
・鍵ストリームという乱数列との排他的論理和に変換する手法
・同じ鍵ストリームを使用すると複合化が可能
・鍵ストリームの各バイトがどの位置にあたるか予測されてしまうと攻撃される
・同じ鍵を使い回さないことが重要

表3.1.1. 論理和真理値表

| A | B | 論理和 |
|---|---|---|
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 1 | 0 |

![pasted image 0 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329544/8dedbd23-a0e8-d8a0-87dd-d9832e97a3e8.png)

図3.1.1.ストリーム方式暗号化方式


### 3-1-2.ブロック暗号化方式
・データの塊をまとめて暗号化する手法
・入力における小さな変化が出力の結果を大きく変える
・ブロック暗号化方式を利用する際には、暗号化利用モードといわれる暗号化スキームを利用する(AES256等)

※その他暗号化利用モードの詳細はこちらの記事がわかりやすかったので、ご参照ください
https://qiita.com/shoichi0599/items/6082b765c1257b71985b

## 3-2.ハッシュ関数
仕組み：任意の長さの入力を受け取り固定長の出力へ変換するアルゴリズム
特徴：ハッシュ関数が出力した値をハッシュ値と呼ぶ
　　　一方向性
　　　ハッシュ関数で使用されている「SHA1」というアルゴリズムが「SHA256」への移行を推奨されている
メリット：大きなデータを手軽に表現して比較しやすい
デメリット：不可逆変換のため、管理者が元の値を予測しづらい

## 3-3.MAC(メッセージ認証コード)
・ハッシュ関数を拡張して認証可能にした関数
・HMAC(Hash-based MAC)を利用すると、ハッシュ鍵を安全な方法でメッセージに織り交ぜることができる


## 3-4.公開鍵暗号化方式
・「公開鍵」と「秘密鍵」の2種類の鍵を使用する
・秘密鍵は第三者に漏洩しないようにし、公開鍵は別の人と共有する
・大人数でデータを安全にやりとりする際に利用される
　(共通鍵暗号化方式は、複数の鍵を作る(管理工数がかかる)、もしくは一つの鍵を大人数に共有する(漏洩のリスクが増す)ため集団で利用するには不向き)
・以下2つの方式がある
　- 図3.4のように公開鍵で暗号化したものを秘密鍵で複合化する方式(秘密鍵でなければ複合できないようにする)
　- 秘密鍵で暗号化したものを公開鍵で複合化する方式(ディジタル署名に使用される)

![pasted image 0 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329544/4c47857f-d180-b669-d6dc-16af2661e5eb.png)
図3.4.公開鍵暗号化方式


## 3-5.ディジタル署名
・公開鍵暗号化方式を応用した手法
・電子的メッセージや文書に対する真正性を検証可能にする手法
・MACもディジタル署名の一種


# 4.まとめ
暗号化方式の基礎となる部分についてまとめました。
暗号化方式はここ数年で最新の技術やアルゴリズムが出てきているので、キャッチアップしていくのがとても大変だなと感じました。

ここまで書いてきた「鍵」というのは全て長文の文字列(乱数)です。そのため、単純な文字列を鍵としてしまったら、そもそもの暗号化の意味がなくなってしまうので、注意してください。


参考書籍
[プロフェッショナルSSL/TLS](https://www.lambdanote.com/products/tls)(参考にしたものは2015年度版のため、URL書籍の古いものです)
Ubuntu 定刻・プロセス監視による計画シャットダウン(at cron)

機械学習の終了時刻が深夜に及んだ時に、計画的にシャットダウンする必要があったので忘備録として残します。

# 環境
Ubuntu 18.04

# タイムゾーンを日本の時刻に設定

``` bash
# タイムゾーンを設定
sudo timedatectl set-timezone Asia/Tokyo
# 日付を確認
date
```

# atコマンド と cron


- at
  - 未来の日時で1回だけ実行するのに使う。
- cron
  - 毎時、日次、月次などの定期的な実行に使える。

本記事では「1.指定時刻にシャットダウンする」方法と「2.特定のプロセスの終了を確認したうえで、終了処理を行う」方法とをまとめます。

# 1．指定時刻にシャットダウンする。

未来日付で1度だけシャットダウンする場合は、```at``` コマンドが使える。
```at``` コマンドは以下のように使用する。

```bash
echo "[command]" | at [ 日時 ]
```

仮に、2019年9月12日 12:30にシャットダウンをするなら、以下のようにすればいい。

```bash
echo "sudo shutdown -h now" | at 12:30 09122019
```

```bash
# 実行結果
warning: commands will be executed using /bin/sh
job 3 at Thu Sep 12 12:30:00 2019
```

上記のように表示されれば、指定した時刻にシャットダウンが実施される。

## 誤った時刻で設定してしまった場合の対処

予約したコマンドのジョブリストを表示

```bash
at -l
```

```bash
# 実行結果
3       Thu Sep 12 12:00:00 2019 a [ user ]
```

表示されたジョブ番号を指定して、```at -d``` コマンドを実行

```bash
# at -d [ジョブ番号]
at -d 3
```

# 2．特定のプロセスの終了を確認したうえで、終了処理を行う。

以下の```.sh``` ファイルを作成する。内容は ```ps``` と ```grep``` コマンドで稼働中のプロセスを抽出して、特定のファイル名が含まれるプロセスがなければ、シャットダウンするというもの。

```bash:pscheck_shutdown.sh
#!/bin/bash
result=$(ps aux | grep "[ プロセス名 ]" | grep -v grep)
if [ -z $result ] ; then
        echo "shutdown instance"
        sudo shutdown -h now
else
        echo "instance is living"
fi
```

```[ プロセス名 ]``` は適宜、```filename.py``` などに書き換えて使用してください。

```bash
ps aux | grep "[ プロセス名 ]" | grep -v grep
```

## atコマンドで実行する場合

```bash
at 12:30 09122019 -f pscheck_shutdown.sh
```

## cronで実行する場合

cronの使い方は[こちら](https://qiita.com/UNILORN/items/a1a3f62409cdb4256219)を参照しました。

```/etc/crontab``` ファイルをコピーして、```/etc/cron.d/task_cron``` を作成

```bash
sudo cp /etc/crontab /etc/cron.d/task_cron
```

```/task_cron/``` の5～8行目を削除して、以下(編集後)の内容を追記。
（以下の例は、毎時実行）

編集前

```bash
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
```

編集後
（```[user]```には、使用しているユーザー名を設定してください）

```bash
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
0 * * * * root   . /home/[user]/pscheck_shutdown.sh
#
```

cronを実行

```bash
sudo service cron restart
```

上記の手順で、```cron``` による定期的なスケジュール実行の設定は完了です。


## cronのスケジュール実行を中止したいとき

```cron``` のスケジュール実行をやめたいときは、```/etc/cron.d/task_cron``` の追記した行を消去するかファイルごと削除して、```sudo service cron restart``` を実行すればOKです。

```bash
rm /etc/cron.d/task_cron
sudo service cron restart
```


# 参考
- [【GCP/AWS】インスタンスのシャットダウンし忘れを防ぐ](https://qiita.com/Gri_Gra/items/8789a921ad9e2ed8a171)
- [Cronの使い方とテクニックと詰まったところ](https://qiita.com/UNILORN/items/a1a3f62409cdb4256219)
- [atコマンドについて詳しくまとめました 【Linuxコマンド集】](https://eng-entrance.com/linux-command-at)
- [psをgrepした結果からgrep自身を除外する方法](https://webkaru.net/linux/ps-grep-exclude/)


以上
【Android】NavigationのSafe Argsを使うときの注意点

https://developer.android.com/jetpack/androidx/releases/navigation

JetpackのNavigationは画面遷移を手軽に書けて非常に便利です。

中でもargumentsを型安全に取り扱えるSafe Argsはとても重宝します。

ただし、Safe Argsに入れるのがintやStringではなく自作クラスの場合は注意が必要です。

## Safe Argsで自作クラスを使う場合

クラスが`Parcelable`か`Serializable`ならばSafe Argsに含めることができます(Safe Argsは`Bundle`のラッパーであるため)。自作クラスと書きましたが、自作でもライブラリのクラスでも同じです。

開発時はそれで普通に使えるかと思いますが、Releaseビルドにした途端に

> android.view.InflateException: Binary XML file line #33: Binary XML file line #33: Error inflating class fragment

といったようなエラーが発生したりします。

### proguardに追加

Releaseビルドで発生することから想像できるとおり、proguardに記述が必要です。

`com.example.hoge.Status`クラスをSafe Argsで使用するならば

```
-keepnames class com.example.hoge.Status
```

としてクラス名が難読化されないようにする必要があります。
フォーム  【 form 】 

（紙の）記入用紙や申請書のように、内容を書き込んだり選択肢から一つを選ぶ操作要素が並んだ画面や領域を入力フォーム（input form）と呼び、単にフォームと言った場合はこれを指すことが多い。

ソフトウェアの機能として用意される場合、ソフトウェアの設定画面や、新規の書類やファイルの作成、既存のデータの編集など、利用者が一つの目的のためにまとまった数の項目を入力・指定する必要がある場合に用いられる。

Webページの場合は閲覧者から必要な情報を聞き出してWebサーバに送信するために用いられ、会員登録や問い合わせ、アンケート、購入や決済、サービスについての各種の手続きなどでよく利用される。検索機能や検索エンジンのキーワード入力欄なども簡易なフォームの一種である。

フォームは入力内容や目的により様々な機能の要素が用いられる。例えば、任意の文字列を入力できる「テキストボックス」（Webページでは複数行のものを「テキストエリア」という）、複数の選択肢から一つを選ぶ「ラジオボックス」や「セレクトボックス」、複数の選択肢から複数を選ぶことができる「チェックボックス」、文字入力と選択肢を組み合わせることができる「コンボボックス」、はい・いいえやオン・オフなどを指定する「トグルスイッチ」、内容の送信やリセットなどを指示するための「ボタン」などがよく用いられる。
SwiftUIのViewをStoryboardで使用する方法とUIHostingControllerのライフサイクルについて

##SwiftUIで作ったViewをStoryboardで使用する


UIHostingControllerを継承したクラスを作成して

```swift
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder, rootView: ContentView())
}
```
このように初期化時にSwiftUIのViewをrootViewに指定します。


全体のコードです

```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello World")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

class ContentViewHostingController: UIHostingController<ContentView> {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder, rootView: ContentView())

    }

    override func viewDidLoad() {
        super.viewDidLoad()

    }
}

```

呼び出しは通常のSotryboardからの初期化と同じです。

```swift
let vc = UIStoryboard(name: "ContentViewHostingController", bundle: nil).instantiateViewController(identifier: "ContentViewHostingController")
```

### (補足) UIHostingControllerのライフサイクルについて

バグなのか仕様なのかはわかりませんが、
SwiftUIのViewからコードでContentViewHostingControllerへ遷移させたところ `viewDidLoad` が呼ばれませんでした。
上記のようにStoryboardからの呼び出しであれば `viewDidLoad` が呼ばれたので補足として書いておきます。
ローカル上にDockerで構築した環境をSSL対応にする

# 背景
本番でSSL通信するなら、ローカルの環境でもちゃんとSSLで開発をやるべきだよね。

# 前提　
- 環境差異によるバグをへらす為に、Dockerコンテナを本番のAWS環境とローカル環境の双方で共通化。
- ローカルではdocker-composeを利用し、AWSではbuildspecで環境変数等はコントロール。
- AWS上ではALBを介す為、ALBでSSL証明書を管理し、コンテナへは80番ポートでアクセスする。

# 方法

AWS ALBの代替えとしてnginx-proxyを使います。
Let's EncryptでSSL化する場合はnginx-proxy推奨で、letsencrypt-nginx-proxy-companionというコンテナイメージがあります。
このコンテナはnginx-proxy同様に環境変数を設定するだけで自動でLet's Encryptの証明書を取得してくれます。

- [jwilder/nginx-proxy](https://github.com/jwilder/nginx-proxy)
- [jrcs/letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion)

```yml:docker-compose.yml
version: '3.3'

services:
  #--------------
  # Proxy
  #--------------
  nginx-proxy:
    image: jwilder/nginx-proxy
    environment:
      - "DHPARAM_GENERATION=false"
    privileged: true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - proxy:/usr/share/nginx/html
      - proxy:/etc/nginx/vhost.d
      - ./docker/encrypt/certs:/etc/nginx/certs:ro
    labels:
      com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true"
  #--------------
  # letsencrypt
  #--------------
  letsencrypt-nginx:
    image: jrcs/letsencrypt-nginx-proxy-companion
    privileged: true
    environment:
      - NGINX_PROXY_CONTAINER=nginx-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - proxy:/etc/nginx/vhost.d
      - proxy:/usr/share/nginx/html
      - ./docker/encrypt/certs:/etc/nginx/certs:rw
    depends_on:
      - nginx-proxy
  #--------------
  # App
  #--------------
  app:
    build:
      context: .
      dockerfile: ./docker/app/Dockerfile
    environment:
      - VIRTUAL_HOST=${APP_HOST}
      - LETSENCRYPT_HOST=${APP_HOST}
      - LETSENCRYPT_EMAIL=${APP_ADMIN_EMAIL}
      - CERT_NAME=default
    volumes:
      - .:/var/www
volumes:
  proxy:
```

今回のポイントは下記

```
- CERT_NAME=default
```

Let's Encryptで証明書を生成する場合、認証サーバーと通信を行い、認証サーバーから所有確認の為に、該当サーバーにアクセスを行います。ローカルだと、そのアクセスができない為、ドメインが指定された証明書を発行できません。
なので、オレオレ証明書として、default.certを吐き出してくれるので、それを利用します。
C#で別アプリ実行

# Process.Start()で外部アプリを呼び出す
ExecuteAnotherApp(...)外部アプリを呼び出す
in string PathNameは呼び出したいアプリのパス
in string Argumentsはコマンドラインの呼び出し時の引数
bool UseShellExecuteはシェル機能を使うか
bool CreateNoWindowはコンソールウィンドウを開くか？デバッグのときは開いてもいい気がする
HageHage()呼び出し例

```C#:ExecuteAnotherApp.cs
        private void ExecuteAnotherApp(in string FileName, in string Arguments, bool UseShellExecute, bool CreateNoWindow) {
            System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo {
                FileName = FileName, Arguments = Arguments,
                UseShellExecute = UseShellExecute,//false：シェル機能を使用しない
                CreateNoWindow = CreateNoWindow    //true：コンソールウィンドウを開かない
            }).WaitForExit();//終了を待つ
        }

        private void HageHage() {
            ExecuteAnotherApp("FusaFusa.exe","hage husa husahusa", false, true);//"hage husa husa"引数は三つ．なしのときは""でいい
        }
```

参照
https://www.atmarkit.co.jp/fdotnet/dotnettips/805pipeasync/pipeasync.html
AWS上のMongoDBをAtlasにLiveMigrationする

## AWS EC2インスタンス上にインストールされているSelf ManagedなMongoDB Clusterを[Atlas](https://www.mongodb.com/cloud/atlas)に移行する際の覚書

2019/10/07 追記

関連記事: [NLBでTLS終端を行いAtlasのLiveMigrationを行う](https://qiita.com/georgeOsdDev@github/items/083f0d028c9ce8f834fb) も書きました。


基本的には[公式ドキュメント](https://docs.atlas.mongodb.com/import/live-import/)に網羅されているが

> Enter the hostname and port of the primary member of the source cluster into the provided text box. For example, mongoPrimary.example.net:27017.

とある。

Live Migration Server自体は、Atlas上に作成するClusterとは別物であるため、vpc peeringを行うことはできないので、PrimaryサーバがLive Migration Serverからインターネット経由で見える必要がある。

今回移行対象のDBサーバーは`Private subnet`に配置されているため、Elastic IPは存在しない。
そこで以下のように、`Network Load Balancer`を経由することでLive Migrationを実行する。

![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/210e1981-f083-b1de-3a3c-7eff08bb89a3.png)

PrimaryDBインスタンスが稼働しているサブネットのAZ内のpublic subnet内にNLBを作成し、
NLBのリスナーおよびターゲットとして、private subnetのDBインスタンスの27017ポートを指定する。

※ 今回のLBは負荷分散ではなく、LiveMigrationのための疎通が目的であり、かつPrimaryインスタンスに接続する必要があるため、LBの配置されるAZは1つのみ指定し、ターゲットも1つのインスタンスのみ指定する。
※ LiveMigration実施中にフェイルオーバーが発生した場合は未検証。

また、PrimaryDBが稼働しているEC2インスタンスに以下を許可するキュリティグループを一時的にアタッチする

 - AtlasのLiveMigration画面で指定されたCIDRからの27017ポートへのInbound通信
 - Public SubnetのCIDRから27017ポートへのInbound通信 (これがないとLBのヘルスチェックに成功しない)
 - 接続確認用のオフィスのIPなどから27017ポートへのInbound通信

LBのヘルスチェックが通れば

`mongo "mongodb://<LBのDNS name>"`

で接続することができるようになる。

Atlasのコンソールでも`<LBのDNS name>:27017`を指定することで無事Live Migrationが開始する。

関連:
[パブリック向けロードバランサーをプライベート IP アドレスを持つ EC2 インスタンスへ接続する方法を教えてください。](https://aws.amazon.com/jp/premiumsupport/knowledge-center/public-load-balancer-private-ec2/)
phpbrew に postgreSQL の拡張モジュールをインストール

CentOS6.8 に php7.3.9 をphpbrewからインストールするときにハマったのでメモ。
結論からいうと、なんか知らんけど入ってるっぽいという印象。


```
# phpbrew install 7.3.9 +default +dbs

checking for pg_config... not found
Cannot find libpq-fe.h. Please specify correct PostgreSQL installation path
```

phpbrewからPostgreSQLを見れないらしい。

```
# rpm -qa | grep postgresql
postgresql96-libs-9.6.15-1PGDG.rhel6.x86_64
postgresql96-9.6.15-1PGDG.rhel6.x86_64
postgresql96-server-9.6.15-1PGDG.rhel6.x86_64
```
postgresql-develが入っていないので、インストール

```
# yum install postgresql96-devel
```
もう一度、 `phpbrew install` したら入った。
 


次に、拡張モジュールをインストールする

```
# phpbrew ext install pgsql
===> Installing pgsql extension...
Log stored at: /root/.phpbrew/build/php-7.3.9/ext/pgsql/build.log
Changing directory to /root/.phpbrew/build/php-7.3.9/ext/pgsql
===> Phpize...
Error: Command failed: phpize > /root/.phpbrew/build/php-7.3.9/ext/pgsql/build.log 2>&1 returns:
```

失敗したので、ログを見てみる

```
# cat /root/.phpbrew/build/php-7.3.9/ext/pgsql/build.log
Configuring for:
PHP Api Version:         20180731
Zend Module Api No:      20180731
Zend Extension Api No:   320180731
configure.ac:3: error: Autoconf version 2.68 or higher is required
configure.ac:3: the top level
autom4te: /usr/bin/m4 failed with exit status: 63
```
autoconf のバージョンが低いようなので、バージョンを上げる
（あとから考えるとrpmを探せば良かった）

```
# curl -L -O http://ftp.gnu.org/gnu/autoconf/autoconf-latest.tar.gz
# tar zxvf autoconf-latest.tar.gz
# cd autoconf-2.69/
# ./configure
# make
# sudo make install
```

もう一度、モジュールをインストールする

```
# phpbrew ext install pgsql
===> Installing pgsql extension...
Log stored at: /root/.phpbrew/build/php-7.3.9/ext/pgsql/build.log
Changing directory to /root/.phpbrew/build/php-7.3.9/ext/pgsql
===> Phpize...
===> Configuring...
Error: Command failed: ./configure --with-php-config=/root/.phpbrew/php/php-7.3.9/bin/php-config >> /root/.phpbrew/build/php-7.3.9/ext/pgsql/build.log 2>&1 returns:
```
ログの中身↓

```
checking for pg_config... not found
configure: error: Cannot find libpq-fe.h. Please specify correct PostgreSQL installation path
```

コマンドのオプション追加を調べる

```
# phpbrew ext show pgsql
                Name: pgsql
    Source Directory: /root/.phpbrew/build/php-7.3.9/ext/pgsql
              Config: /root/.phpbrew/build/php-7.3.9/ext/pgsql/config.m4
            INI File: /root/.phpbrew/php/php-7.3.9/var/db/pgsql.ini
           Extension: Core
                Zend: no
              Loaded: no

   Configure Options: 

        --with-pgsql[=DIR]               for PostgreSQL support
```

下記のコマンドを試したが変わりなし。

```
# phpbrew ext install pgsql --with-pgsql=/usr/pgsql-9.6/bin/
```

```
# yum install php73-php-pgsql
```

もう一度、phpbrewからインストールしてみる。
`dbs` を別々に分けてみる

```
# phpbrew install 7.3.9 +default +sqlite +mysql +pdo +pgsql
```
もう一度、拡張モジュールをインストールしようとしても同じエラーが表示されたが、phpinfo()を見たら無事にインストールされていた。なんだこれ・・・・
GRUBの起動順序を変えてデュアルブートのWindowsのWindowsUpdateを寝ている間に済ませる

私の仕事PCはUbuntu MATEだが、一応Windowsもデュアルブートで入っている。
厳密に言えばWindowsのノートPCに、パーティションを切ってUbuntuを入れた状態。
仕事では基本的にはUbuntuしか使わないのだが、ごくたまにWindows環境で調査などの作業をすることがある。
しかも大抵そういうのは急ぎの仕事だ。
その時にWindowsを起動すると、何が起こるか。
永遠に終わらないWindows Updateである。
急ぎの仕事があるのに、平気で半日何もできない状態に陥る。

避けるためにはどうするか。
当然、たまに仕事の帰りにWindowsを起動して帰ればいい。それだけの話だ。
そうすれば、その夜中に勝手にアップデートを行い、勝手に再起動しやがってくれる。

…とは行かない。なぜなら私はUbuntuユーザーだからだ。
Windowsがアップデートを行い、再起動して、最後の仕上げをしようと目論んだところで、
起動するのはGRUBであり、Ubuntuだ。
勝手に再起動したWindowsに、自動的に自らを蘇らせる権利など与えられはしないのだ。ざまあみろ。

---

とも言ってられないので、一時的にGRUBのデフォルト起動カーソル位置をWindowsにして、
放置した状態でWindows Updateが最後まで終わるようにすることができるようにする。

まず、以下のコマンドを実行。

``` bash
$ grep -e "^\(menuentry\)\|\(submenu\)" /boot/grub/grub.cfg
```

こんな結果が出る。

> menuentry **'Ubuntu'** --class ubuntu --class gnu-linux --class gnu --c（略）
> submenu **'Advanced options for Ubuntu'** $menuentry_id_option （略）
> menuentry **'Windows Boot Manager (on /dev/sda1)'** --class windows --class（略）
> menuentry **'System setup'** $menuentry_id_option 'uefi-firmware' {

これは、GRUBの起動メニューに出る情報である。
ここから、Ubuntuは **0番目** 、Windowsは **2番目** と読み取る。
まあ別に単純に一度再起動して、GRUBのメニュー画面を見てもいい。
コマンドで調べる方法を書いたのは、単にかっこいいからだ。

その2番目がデフォルトになるようにすればいい事がわかった。次はその設定だ。
昔は先程grepした/boot/の下のgrub.cfgを直接書き換えたりしたものだが
grub.cfgを直接いじろうと開くと `DO NOT EDIT THIS FILE` と書かれている。
Ubuntuの作法はそうではない。

以下のファイルを編集する。

``` bash
$ sudo vim /etc/default/grub
```

```ini:/etc/default/grub
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
#   info -f grub -n 'Simple configuration'

GRUB_DEFAULT=0          👈ここ
#GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=true
#（以下略）
```
`GRUB_DEFAULT` の値を0→2に変更し、保存する。

最後に、以下のコマンドを実行（先程のファイルの先頭のコメントにも書かれている）。

```bash
$ sudo update-grub
```
これで、`/etc/default/grub` への変更が、実際にgrub.cfgに反映される。

再起動すると、GRUBの画面のカーソルはWindowsの行を示し、そのまま放っておけばWindowsが起動する。

あとはWindows Updateをつついて帰って、翌朝来たらログイン画面になっているWindowsを叩き落として再起動し、
GRUBでUbuntuを選んで起動し、
`/boot/default/grub` のGRUB_DEFAULTを0に戻して、
`sudo update-grub` すれば、元通りだ。
シグモイド関数とソフトマックス関数 概説

本記事では、特に機械学習の分類問題の観点から、シグモイド関数とソフトマックス関数の性質について概説します。

#シグモイド関数
##シグモイド関数の概要
シグモイド関数（sigmoid function）は、機械学習において多く用いられる関数です。
$S(x)=\dfrac{1}{1+ \rm{exp}\(\it{-x}\rm{)}}$
のような関数で表現されます。下図のとおりの単調増加関数です。
![sigmoid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452443/f9308a75-276c-ecd9-4f32-7a5a66a2b72d.png)
##ロジスティック関数との関係
シグモイド関数を一般化した関数は、ロジスティック関数（logistic function）
$f(x)=\dfrac{L}{1+\rm{exp}\(\it{-k\ \rm{(} \it{x-x_0}}\rm{))}}$
であり、シグモイド関数はロジスティック関数の特殊形といえます。
各パラメタの意味は下記のとおりです。

- $L$: 関数値が取りうる最大値。 $\rm{exp}\(\it{-k\ \rm{(} \it{x-x_0}}\rm{))}\geqq0$ （極限の厳密な定義は捨象）のため、$f(x)\leqq\dfrac{L}{1}$ が成り立つ。
- $x_0$: $S$ 字カーブをしている曲線の真ん中の変曲点における$x$ の値。$x$ の値の増加／減少に伴う$f(x)$ の増加／減少をコントロールする基点となる。真ん中にあるので、$f(x_0)=\dfrac{L}{2}$ となる。
-  $k$: 最小値から最大値に至る増加の緩急をコントロールするパラメタ。

ロジスティック関数のパラメタのうち、$L=1, x_0=0, k=1$ と設定したものがシグモイド関数です。

##シグモイド関数の性質

数学的には似た性質を持つ関数も多く、非常に興味深いのですが、機械学習への応用に限定して重要な性質を挙げます。
シグモイド関数は、$(-\infty, \infty) \rightarrow (0, 1)$ となるよう、$y=0$ 及び $y=1$を持つ単調増加関数です。これが意味するのは、$x$ がどのような値を取ろうとも$S(x)$ の関数値は$0$ から$1$ の間に押し込められることを意味します。確率論に出てくる累積分布関数（cumulative distribution function）の性質と同様であることから、当該関数は**ニューラルネットワークにおいて入力値$x$を確率値に相当する出力値$S(x)$に変換**する活性化関数（activation function）としてよく用いられます。

#ソフトマックス関数

シグモイド関数がある一つの値（実数値）の入力に対して出力を行った関数であるのに対し、ソフトマックス関数は**複数値からなるベクトル**を入力し、それを正規化したベクトルを出力します。
これの意味するところを具体例も用いて説明します。
##ソフトマックス関数の概要

入力値が$n$値からなるベクトルについて、
入力値ベクトル $(x_1,x_2,\dots ,x_n)$
出力値ベクトル $(y_1,y_2,\dots ,y_n)$

とした場合、
$y_1 = \dfrac{exp(x_1)}{exp(x_1)+exp(x_2)+\dots+exp(x_n)}$
$y_2 = \dfrac{exp(x_2)}{exp(x_1)+exp(x_2)+\dots+exp(x_n)}$
$\dots$
$y_n = \dfrac{exp(x_n)}{exp(x_1)+exp(x_2)+\dots+exp(x_n)}$

このとき、$y_1+y_2+\dots+y_n=1$になることが分かります。
例えば、
入力値ベクトル $(1,2,3)$
に対しては、関数値は以下を返します。
出力値ベクトル $(0.09003057, 0.24472847, 0.66524096)$
合計値が$1$になるのが分かるかと思います。
なお、Pythonでは下記のとおり実装できます。

```py
import numpy as np

def softmax_func(x):
    exp_x = np.exp(x)
    return exp_x/np.sum(exp_x)

x = np.array([1, 2, 3])
print(softmax_func(x))
```

##ソフトマックス関数の性質
ソフトマックス関数は、複数値からなる入力値ベクトル$x$ がどのような値を取ろうとも、出力値ベクトルの各要素を$0$ から$1$ の間に押し込め、全要素の合計が$1$となるように正規化する性質を持ちます。当該関数は**ニューラルネットワークにおいて入力値ベクトルの各要素を確率値に相当する出力値ベクトルに変換**する活性化関数（activation function）としてよく用いられます。
#機械学習における使い分け

以上のことから、シグモイド関数とソフトマックス関数には、共通する性質が読み取れます。
$n=2$の場合のソフトマックス関数は、以下のとおり表現されます。

$y_1=\dfrac{exp(x_1)}{exp(x_1)+exp(x_2)}=\dfrac{1}{1+\frac{exp(x_2)}{exp(x_1)}}=\dfrac{1}{1+exp(-(x_1-x_2))}$

このように、$n=2$のソフトマックス関数はシグモイド関数であり、シグモイド関数を一般化したものがソフトマックス関数です。

こうした両者の関数の関係性と、共に確率値を出力する関数であるという性質から、機械学習の分類問題においては**2値分類ではシグモイド関数**、**多値分類（3値以上）ではソフトマックス関数**が、出力層の活性化関数として用いられます。
（なお、回帰問題では出力層の活性化関数として恒等関数（identity function）を用います。）
Azure DevOps でプロジェクト作成〜Eclipseでwar開発

たまにしかやらない作業でよく忘れるのでメモします。

1. Azure DevOps にログイン
2. + New Project を選択
3. Project name, Visibility を指定して Create ←追記：「Files」から devブランチも作っておく
4. Eclipse を開く
5. Team Explorerを開く
6. Projects And My Team - Connect To Team Projects を開く
7. Team Project Selection で該当のプロジェクトを選択して Finish
8. Team Explorer の「HOME」を「Git Repositories」に切り替える
8. Team Exploere にてDevOps で作成したプロジェクトを右クリック - import Repository を開く
9. Repository Selection の画面が開くので該当のプロジェクトを選択して Next
9. 「Create generic Eclipse projects for selected folder」を選択して Next
10. Import Projects into Workspace にて該当のプロジェクトを選択して Finish
10. Eclipse にてプロジェクトを右クリック - [Configure] - [Convert to Maven Project] を開く
11. Packaging に「war」を選択 （Webアプリケーションとする場合）して「Group Id」にJavaパッケージ相当の値、「Artifact Id」にWARファイル名に相当する値を入れて Finish
12. プロジェクトはWARに変換されるが、足りないフォルダ・ファイルがあるので作成する
	- src/main/java
	- src/test/java
	- src/main/webapp/WEB-INF
	- src/main/webapp/WEB-INF/beans.xml
	- src/main/webapp/WEB-INF/web.xml
13. Project Properties - Project Facets - Java の Versionを修正
14. おわり
[漏洞预警]CVE-2019-14811/Ghostscript远程命令执行漏洞

### 漏洞描述
近日亚信安全网络攻防实验室研究员——Sommous监测到Artifex Software Ghostscript一个远程代码执行漏洞利用方式被公开.Ghostscript是美国Artifex Software公司的一款开源的PostScript（一种用于电子产业和桌面出版领域的页面描述语言和编程语言）解析器.该产品可显示Postscript文件以及在非Postscript打印机上打印Postscript文件。.攻击者可借助特制的PostScript文件利用该漏洞关闭安全保护,访问文件系统或执行任意命令。
### CVE编号
CVE-2019-14811
### 漏洞威胁等级
高危
### 影响范围
Artifex Software Ghostscript < 9.28
### 漏洞验证
使用公开的payload进行任意命令执行

使用py脚本生成带有OS命令的图片文件,将其上传到相应文件接口等待其解析即可​
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/2dcb1676-b47d-b27d-a85e-986a4bd1bb7f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/346a27ec-e8a3-d42a-92a5-a3eeb2c1d573.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/fb468d0b-8900-3b08-536d-f50016367e23.png)
### 修复建议
升级至9.28或其以后版本
### 时间轴
[0] 2019年08年28  CVE官方发布该漏洞
[1] 2019年9月12日 亚信安全网络攻防实验室发布预警公告
### Reference
http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-201908-2179
https://nvd.nist.gov/vuln/detail/CVE-2019-14811
【PlayCanvas】v1.23.0のバージョンでVRが使えなくなってしまった過去のプロジェクトでVRを使用する方法

PlayCanvasの最新版では現在サンプルを含め、VRのプロジェクトを動かすことができなくなっております。
理由としては使用をしているwebvr-Polyfillがかなり古かったため、新しいpolyfillに置き換えるためかと考えられます。
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">It&#39;s should be coming back soon! We&#39;re currently updating it to work with the latest webvr polyfill.</p>&mdash; David Evans (@daredevildave) <a href="https://twitter.com/daredevildave/status/1170492431420153856?ref_src=twsrc%5Etfw">September 8, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### PlayCanvasとは

PlayCanvasの開発はイギリスのPlayCanvas社（現在はSnapChatのSnap）が行っております。
<iframe width="800" height="480" src="https://www.youtube.com/embed/PS4oMLPyYfI" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
公式ドキュメントによると

>PlayCanvasは、インタラクティブなウェブコンテンツ用のビジュアル開発プラットフォームです。作成するツールとウェブアプリは、どちらもHTML5を使用しています。 プラットフォームはウェブでホストされているため、インストールするものは何もなく、対応されているウェブブラウザを実行する任意のデバイスからアクセスできます。  

> https://developer.playcanvas.com/ja/user-manual/introduction/

## 解消法 1. 新しいwebvr-polyfillを入れる

EXTERNAL_SCRIPTへ新しいVRのPolyfillを指定します。こちらを指定することでAndroidでうまく動かない問題などを解消した状態でVRを使用することができます。
```
https://cdn.jsdelivr.net/npm/webvr-polyfill@latest/build/webvr-polyfill.js
```

## 解消法 2. 既存のプロジェクトにVRのPolyfillを入れる

### 1. PlayCanvasのプロジェクトをダウンロードする


### 2. PlayCanvasを古いバージョンに置き換える
a. ダウンロードで生成されたPlayCanvasプロジェクトのPlayCanvasのバージョンを1.22に置き換えます

[https://code.playcanvas.com/playcanvas-1.22.0.js](https://code.playcanvas.com/playcanvas-1.22.0.js)

### 3. config.jsonを変更する
ダウンロードしてきたconfig.jsにVRのPolyfillを追加します
現在のPlayCanvas Editorからダウンロードしてきたときに生成される`config.json`


```config.json
{"layer":4,"transparent":true,"enabled":true}],"useKeyboard":true,"useMouse":true,"useTouch":true,"useGamepads":true,"i18nAssets":[],"externalScripts":[],"libraries":["ammo.dcab07b.js"]}
```

vrPolyfillUrlをconfig.jsonに追加する

`vrPolyfillUrl`のキーと値を追加します。

`"vrPolyfillUrl":"webvr-polyfill.bad0c71.js"`

```config.json
{"layer":4,"transparent":true,"enabled":true}],"useKeyboard":true,"useMouse":true,"useTouch":true,"useGamepads":true,"i18nAssets":[],"externalScripts":[],"libraries":["ammo.dcab07b.js"],"vrPolyfillUrl":"webvr-polyfill.bad0c71.js"}
```


一時的な避難のような形となりますが、この方法でVRのプロジェクトを使用をすることができます。
aws-vaultをdirenvと組み合わせて使う

# はじめに

最近 [aws-vault](https://github.com/99designs/aws-vault) 使い始めたのですが、 [direnv](https://github.com/direnv/direnv) と組み合わせる方法が分からなくて調べたメモ。

# 環境

- macOS 10.14 (Mojave)
- aws-vault v4.6.4
- direnv v2.20.1

# やりたいこと
ディレクトリにcdしたしたタイミングでAWSのアクセスキーの環境変数を切り替えたりするのにdirenvを使ってたのですが、aws-vaultのヘルプを見たかんじ、直接的に現在のシェルに環境変数をexportする機能がありませんでした。
例えばTerraformでprodとdevでAWSアカウントを分けて、ディレクトリでtfstateを分けるみたいな使い方をしてると、このようなことがしたくなります。

# 解決方法

最初 `aws-vault exec <profile_name> -j` でセッションの生データがJSONとして取れるので、これをjqなどでパースしてやればよいんでわ？って思ったんですが、よく考えると、envコマンドでAWS関連の環境変数をgrepで引っこ抜いてきたら、ほぼほぼやりたいことが達成できました。
一点だけ考慮ポイントとして、 aws-vaultは `AWS_VAULT` 環境変数が残ってるとネストしたセッションとみなしてエラーになるので、これだけ取り除きます。

つまり

``` bash
$ export $(aws-vault exec <profile_name> -- env | grep AWS_ | grep -v AWS_VAULT)
```

これをディレクトリcdしたタイミングで発動させればよさそうです。

`~/.direnvrc` に以下の関数を定義しておきます。
汎用性を高めるために引数としてAWSのプロファイル名を受け取れるようにしておきます。

```bash
use_aws_profile(){
  profile_name=$1

  export $(aws-vault exec $profile_name -- env | grep AWS_ | grep -v AWS_VAULT)
}
```

で、読み込みたいディレクトリに以下のような `.envrc` を作成します。
例えばAWSのプロファイル名がdevの場合は、以下のように設定すればOKです。

```
use aws_profile dev
```

これでディレクトリをcdしただけでaws-vault経由で環境変数がexportされた状態になります。

# おまけ

aws-vault exec の `--assume-role-ttl` のデフォルトのタイムアウトが15mで微妙に短いです。これは環境変数 `AWS_ASSUME_ROLE_TTL` で上書き可能です。例えば1hに設定したい場合は以下のとおり設定します。

```bash
use_aws_profile(){
  profile_name=$1

  export AWS_ASSUME_ROLE_TTL=1h
  export $(aws-vault exec $profile_name -- env | grep AWS_ | grep -v AWS_VAULT)
}
```

1h以上にしたい場合は、Assume Roleの設定で、12hまでは伸ばせそうに見えます。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_use.html

が、role chainingしていると1h以上には設定できないようです。

https://github.com/99designs/aws-vault/blob/6ef054e6e714994fbd110d30f118bddceee65aa1/USAGE.md#assuming-a-role-for-more-than-1h

ちなみにセッションの残り時間などは  `aws-vault exec` するときに `--debug` オプションを付けると見えます。

以上。
【Android】NumberPickerでテキスト入力した値を即時反映させる

`NumberPicker`での値の選択ではスワイプによる選択とテキスト入力による選択があります。

スワイプの場合は問題ないのですが、テキスト入力の場合は確定しないといけません。「テキスト入力したが確定していない」という状態では変更前の値になっています。

入力したら即時反映してくれるように動作を変えたいと思います。

# NumberPicker内のEditTextのイベントリスナーで処理

## EditTextの取得

`NumberPicker`は`LinearLayout`の子クラスなので、子要素を取得できます。

```kotlin
val picker = view.findViewById(R.id.number_picker)
val editText = picker.children.filterIsInstance<EditText>().first()
```

のようにして`EditText`を取得できます。

## イベントリスナーの設定

取得したEditTextに入力された時点で値を反映するイベントリスナーを設定します。

```kotlin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    view.main_number_picker.also {
        it.minValue = 0
        it.maxValue = 99
        it.findInput().addTextChangedListener(
            afterTextChanged = { s ->
                s.toString().toIntOrNull()?.let { inputNum ->
                    it.value = inputNum
                }
            }
        )

        it.value = viewModel.num
        it.setOnValueChangedListener { _, _, newVal ->
            viewModel.num = newVal
        }
    }
}
```

## 復元時の挙動

NumberPickerが一つだけならここまでで良いのですが複数存在している場合はもうひと工夫必要です。

画面回転などで再描画されるとSavedInstanceStateからEditTextの値を復元する過程で正しくない値が入力されてしまいます。

`onViewStateRestored`のタイミングで改めて復元する処理を追加しておくのがベターでしょう。

```kotlin
override fun onViewStateRestored(savedInstanceState: Bundle?) {
    super.onViewStateRestored(savedInstanceState)
    val view = requireView()

    view.main_number_picker.value = viewModel.num
    view.main_number_picker2.value = viewModel.num2
}
```
【そんなもん使うな】Scripting.Dictionaryはくそ遅いという話

## 経緯
とある業務アプリケーションが遅すぎると現場で話題に。
原因を調査した結果、「Scripting.Dictionary」が諸悪の根源だった。

## 検証
COMコンポーネントの「Scripting.Dictionary」と.NETアセンブリの「Generic.Dictionary」の実行速度を比較してみた。
書き込み50000回を10セット実行する。

```vb
Dim s As Date
Dim ts1 As New List(Of TimeSpan)
Dim ts2 As New List(Of TimeSpan)
Dim i_ = 50000
Dim j_ = 10

For j = 0 To j_ - 1
    s = Now
    Dim com As New Scripting.Dictionary()
    For i As Object = 0 To i_ - 1
        com.Item(i) = i
    Next
    ts1.Add(Now - s)
Next

For j = 0 To j_ - 1
    s = Now
    Dim gen As New Generic.Dictionary(Of Object, Object)
    For i As Object = 0 To i_ - 1
        gen.Item(i) = i
    Next
    ts2.Add(Now - s)
Next

Debug.WriteLine(String.Join(vbCrLf, ts1.Select(Function(x) x.ToString()).ToArray()))
Debug.WriteLine((New Date(ts1.Select(Function(x) x.Ticks).Average())).ToString("HH:mm:ss.fff"))
Debug.WriteLine("")
Debug.WriteLine(String.Join(vbCrLf, ts2.Select(Function(x) x.ToString()).ToArray()))
Debug.WriteLine((New Date(ts2.Select(Function(x) x.Ticks).Average())).ToString("HH:mm:ss.fff"))
Debug.WriteLine("")
```

## 結果
およそ370倍ほどパフォーマンスに差があった。

```
Scripting.Dictionary実行時間
00:00:02.2260328
00:00:02.2419714
00:00:02.2410784
00:00:02.1870029
00:00:02.2119736
00:00:02.2210343
00:00:02.2079682
00:00:02.1930362
00:00:02.2549694
00:00:02.2000345

Scripting.Dictionary実行時間平均
00:00:02.218

Generic.Dictionary実行時間
00:00:00.0050092
00:00:00.0079916
00:00:00.0049991
00:00:00.0070003
00:00:00.0079994
00:00:00.0080074
00:00:00.0049925
00:00:00.0070002
00:00:00.0049995
00:00:00.0070002

Generic.Dictionary実行時間平均
00:00:00.006
```

## 結論
Scripting.Dictionaryなんか使うな
（言われなくても使わないだろうけど...）
LaravelのバリデートエラーでJSONレスポンスを返す

## 概要

Laravelのバリデートに引っかかった場合（コントローラ以降の処理中に下のような記載をする）、

```php
Validator::make($request->all(), [
    'a' => 'bail|required',
])->validate();
```

に、レスポンスをJSON形式で返してくれるようにする。

※何故かHTML返される人向け

## 対応

リクエストヘッダに、↓を付与する。

```
X-Requested-With: XMLHttpRequest
```

## 備考

* [公式ドキュメント](https://readouble.com/laravel/5.8/ja/validation.html)に `AJAXリクエストにvalidateメソッドを使う場合、Laravelはリダイレクトレスポンスを生成しません。` という記載がある。

* `\Illuminate\Http\Request` 内の `ajax()` メソッド内の、`isXmlHttpRequest()` へジャンプすると↓になっている。

```
return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');
```

のが、決めて。

## 実際のところは。。

ヘッダがないと、リダイレクトでhtmlに飛んでしまうのはちょっとアレなので、手動でハンドリングした方が良いかもですね。。


```php
Route::get('/hoge', function (Request $request) {

    $validation = Validator::make($request->all(), ['aaaa' => 'required']);

    if ($validation->fails()) {
        return $validation->messages();
    }

    return ['aaaaa' => 'bbbbbb'];
});

```

もしくは（こっち推奨）

```php
class TestRequest extends FormRequest
{
    public function rules()
    {
        return ['aaaa' => 'required',];
    }

    public function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
    {
        throw new HttpResponseException(response()->json($validator->errors(), 422));
    }
}

Route::get('/hoge', function (TestRequest $request) {
    return ['aaaaa' => 'bbbbbb'];
});
```

もしくは、Handler.phpのなかでValidationExceptionがでた時用の共通処理でJSONをreturnするようにする。
※例外がValidationExceptionかどうかをチェックして、そうであれば。。みたいな感じ
※これが、一番良い気がする。
docker-composeでrailsを立ち上げた時にA server is already running.と言われる問題

# 問題
一度docker-composeで立ち上げて消すと`tmp/pids/server.ipd`が残るっぽいので、
こいつを消し去りたい。

```bash
$ docker-compose up
web_api_1           | A server is already running. Check /app/tmp/pids/server.pid.
web_api_1           | => Booting WEBrick
web_api_1           | => Rails 5.0.6 application starting in development on http://0.0.0.0:3000
web_api_1           | => Run `rails server -h` for more startup options
web_api_1           | Exiting
```

# 解決

`docker-compose.yml`の設定で`server.ipd`を消し去るコマンドを流すようにする。

```yaml
version: '3'
services:
  web_api:
    build: .
    # もともとの設定
    # command: bundle exec rails s -p 3000 -b '0.0.0.0'
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app
    ports:
      - "3000:3000"
```
CloudWatch Alarmの欠落データの処理方法

# TLDR

欠落データの処理方法には次の選択肢がある：
1. **notBreaching**（適正として処理）
2. **breaching**（不正として処理）
3. **ignore**（無視）
4. **missing**（見つかりませんとして処理）（デフォルト）

**missingが一番分かりづらいのでおすすめしない。**
- データが欠落しているときOKとみなしたい場合→notBreachingにする
- データが欠落しているときNGとみなしたい場合→breachingにする
- データが欠落しているときアラーム状態を現状維持したい場合→ignoreにする
- データが長期間欠落しているときOKでもALARMでもなくINSUFFICIENT DATAにしたい場合→missingにする

# 用語

「評価期間」と「評価範囲」が紛らわしいので注意。

- **アラームを発生させるデータポイント数（Datapoints to Alarm）** M/NのMのこと。分子
- **評価期間（Evaluation Periods）** M/NのNのこと。分母
- **評価範囲（Evaluation Range）** データポイントを取得する個数のこと

# アラーム評価の考え方
アラーム評価の際には、M/NのNより多くのデータポイントを取得する（これを「評価範囲」という）。評価範囲内の直近N個のデータポイントで判定する。N個が集まらなかった場合、「欠落データの処理方法」が適用される。

下図は3 / 3に設定した場合の例（[公式](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-missing-data)より引用）。
評価範囲（5個）のデータポイントを取得し、そのうち直近3個のデータポイントを見る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79394/cf87fb16-721c-e219-f79e-315c44777055.png)
- NOT BREACHINGの列: すんなり理解できる
- BREACHING: すんなり理解できる
- IGNORE: 2行目、少なくとも1個が0なので、3/3にはならない、よってOKになる。それ以外はすんなり理解できる
- MISSING: 全データポイント欠落の場合のみINSUFFICIENT DATAになる。5行目は[「アラーム状態への早期移行の回避」](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#CloudWatch-alarms-avoiding-premature-transition)という分かりづらいアルゴリズム。2行目はIGNOREと同じ理由によりOK。
Swiftが動かないのでHomebrewで入れたpythonを消した話

#お困りの内容
うっかりMojaveでターミナルからswiftをREPL実行しようとしたら、sixライブラリが足りないらしかった。

```
Traceback (most recent call last):  File <string>, line 1, in <module>  File /Applications/Xcode10.3.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/__init__.py, line 98, in <module>    import six
ImportError: No module named six
```

##対応
うっかりHomebrewでpython2.7.15いれて（High Sierra環境を引継いでた）ので消すことにした。
XCode10.3とかは、複数インストールするために改名してるだけです。
以下を実行。（@2つけたか忘れた）

```
brew uninstall python@2
```
なお、python@2以下のフォルダが残ってしまったのでゴミ箱へ。

##結果の確認
このままでは、pythonなんてないぜという怒られが発生するので、一旦ターミナルはクローズして別のターミナルを起動し直して、以下を確認した。

```
$python
Python 2.7.10 (default, Feb 22 2019, 21:55:15) 
[GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.37.14)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
$ swift
Welcome to Apple Swift version 5.0.1 (swiftlang-1001.0.82.4 clang-1001.0.46.4).
Type :help for assistance.
  1> print("Hello,World")
Hello,World
  2>  
```

めでたしめでたし。
[質問]boxとデータ連携する際に、別ファイルでアップロードされた「追加分データ」を自動的に結合する方法について

boxにアップロードされたcsvファイルを、Tableauとデータ接続させて分析してきます。

その際、日次で「トランザクションデータのCSV(増分のみ)」を1ファイルずつ、BOXにアップロード(追加)して、

その追加されたCSVを過去のCSVと自動で結合して、tableauに自動接続したいです。

 

何か方法はあるでしょうか。

 

※諸事情により、全量データを毎日BOXにアップロード(上書き)する方法が使用できないので、別の方法を模索しています。
リクエストパラメーター？？？

リクエストパラメータは「名前」と「値」のペアで送られてきます。GETメソッドとPOSTメソッドの両方で送られてくる可能性がありますが、サーブレットではどちらのHTTPメソッドで送られてきたかを意識せずに処理することが可能です。
ROS2をMacで動かす

ROS2の開発環境構築の際に、かなり手間取ったのでメモとして残します。

最初に断っておきますが、この記事では自分がうまくいったインストール手順を書いています。
この手順で万人がうまくいくとは限りません。

# 必要ソフトウェアのインストール

以下手順でライブラリをインストール。

```
$ brew install python3
$ brew install asio tinyxml2
$ brew install tinyxml eigen pcre poco

$ brew install opencv
```

DDSセキュリティ、RVizを利用する場合は以下が必要。

```
$ brew install openssl

$ brew install qt freetype assimp
```

更に必要なソフトウェアをインストール。

```
$ brew install log4cxx

$ brew install sip pyqt5
$ ln -s /usr/local/share/sip/Qt5 /usr/local/share/sip/PyQt5
$ brew install graphviz
$ python3 -m pip install pygraphviz pydot

$ python3 -m pip install lxml

$ python3 -m pip install catkin_pkg empy lark-parser pyparsing pyyaml setuptools argcomplete
```

# ROS2のインストール

以下ページから最新のROS2をダウンロード。

[ROS2 リリースページ](https://github.com/ros2/ros2/releases)

パッケージの解凍を行う。

```
$ mkdir -p ~/ros2_ws
$ cd ~/ros2_ws
$ tar -xvf ~/"ダウンロードしたROS2のファイル"
```

# ROS2の環境設定

現在開いているターミナルのみで使いたい場合。

```
$ source ~/ros2_ws/ros2-osx/setup.bash
```

ターミナルが起動するたびに勝手に設定した場合。

```
$ echo "source ~/ros2_ws/ros2-osx/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
```

# サンプルプログラムの実行

1つ目のターミナル

```
$ cd ~/ros2_ws
$ ros2 run demo_nodes_cpp talker
```

2つ目のターミナル

```
$ ros2 topic echo /rosout
```

1つ目のターミナルで送られたpublishが2つ目のターミナルで見ることができる。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308887/33a1f005-660f-62ea-a699-2a8d1d82846e.png)

以下のように、コマンドでpublishすることもできる

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308887/fa8b00b7-b0bf-a812-2635-beb509975fae.png)


# 自分の環境で起きた現象

実行できるのに不具合メッセージが出る場合

```
$ brew install console_bridge
```

colconのインストールを求められる場合

```
$ pip3 install -U colcon-common-extensions
```

# 最後に
ROS1のときから開発環境を作るのが大変でしたが、ROS2になっても相変わらずみたいです。
ローカル環境がごちゃごちゃになることを考えると、本格的に開発をし始める際には専用のUbuntuPC用意したほうが良さそうです。
UbuntuにDocker, docker-compose, Node.js, npm, express, express-generator, Nodemonをまとめてインストールするメモ

Ubuntu 18.04で、Docker, docker-compose, Node.js, npm, express, express-generator, Nodemonをまとめていっぺんに入れるメモ。
バージョンをあまり気にせず最新の安定版で良ければ、プロキシが必要なければこれで待つだけ。
docker-composeだけはバージョンを指定しているので要確認。

* Dockerのインストールは<https://docs.docker.com/>に親切に書いてあります。`Get Docker`タブ`Docker Engine - Community`
* docker-composeのインストールは<https://docs.docker.com/compose/install/>に書いてあります。

2019/09/12の実行では以下が入りました。

```txt:version.txt
docker : Docker version 19.03.2, build 6a30dfc
docker-compose : docker-compose version 1.24.1, build 4667896b
node : v8.10.0
npm : 3.5.2
express : 4.16.1
nodemon : 1.19.2
```

# いっぺんに入れる

```bash
# ====== Dockerとcompose ======
sudo apt-get update
sudo apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
# composeのバージョンは要確認
sudo curl -L https://github.com/docker/compose/releases/download/1.25.0-rc2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# ====== node関連 ======
sudo apt-get -y install nodejs
sudo apt-get -y install npm
# nodejsコマンドをnodeでリンク
sudo update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10
sudo npm install -g express
sudo npm install -g express-generator
sudo npm install -g nodemon
```

## 確認
`versions.txt`に出力して確認する

```bash
echo -n "docker : " > versions.txt
docker -v >> versions.txt

echo -n "docker-compose : " >> versions.txt
docker-compose -v >> versions.txt

echo -n "node : " >> versions.txt
node -v >> versions.txt

echo -n "npm : " >> versions.txt
npm -v >> versions.txt

echo -n "express : " >> versions.txt
express --version >> versions.txt

echo -n "nodemon : " >> versions.txt
nodemon -v >> versions.txt
```

出力結果は冒頭のものになります。
植物用物理数値シミュレータSiCroF　(0) Introduction




# なぜ植物に物理数値シミュレータを使うと面白いのか



### 物理数値シミュレーションとは？


SiCroFとは、Simulator for Crop in Fieldの略称で、植物科学や栽培、育種に係る現象の予測を行うことに特化した物理数値シミュレーションソフトウェアです。

物理数値シミュレーションとして有名な例に、航空宇宙産業や自動車産業で使われるCAE（Comuputer Aided Engineering）と呼ばれるものがあります。CAEは、部品や機体を設計する際に、それらの強度や安定性を検討したり、より合理的なデザインを検討するために使用されます。CAEでは、部品や機体をコンピュータ上で再現し、負荷をかけたり、形状を修正するなどして、実際の材料を消費することなく試行錯誤ができるため、ものづくり産業においては必須のツールとなりつつあります。

筆者の専門分野である農業土木分野でも、土構造物（ダムや堤防など）の設計施工から維持管理に渡って、この物理数値シミュレーションが活用されるようになり、土構造物の耐震性や安定性の検討を、実際の構造物を破壊することなく行うことができつつあります。より具体的には、土構造物の変形や、構造物内の水の流れ、溶質の流れ、温度の分布、空気の流れなどが予測されます。

### 植物に物理数値シミュレーションを適用すると何が嬉しいか？


筆者はまた、耐倒伏性の高いダイズを育種するべく、2013年からダイズ育種に取り組んでいます。倒伏は、多くの穀実作物において減収や作業効率低下の主たる要因となり、世界中で発生して農業者を困らせています。ダイズの倒伏は、開花・成熟期に台風が襲来し、水田転換畑で作付けを行うことの多い本邦では特に多発し、毎年のように雑草害を助長し、減収を引き起こし、管理・収穫作業を阻害する要因となっています。倒伏は力学現象であるため、力学現象を解ける物理数値シミュレーションにより予測し、よりよいデザインを検討できるのではないか？と考えたことが、SiCroF開発の最初の動機となりました。

蒸発散や光合成、シンク・ソース間の物質輸送といった現象もまた、物理数値シミュレーションにより予測できそうな問題です。そして、シミュレータの上で葉の形態やよりミクロな形質をあれこれと変えて理想形質を探してみたり、または逆に大量のフェノタイプデータを入力して、特徴的な物理量を抽出して品種間差や処理間差を検討することができれば、より効率的な育種や、より合理的な栽培方法が見つかるかもしれません。

加えて、物理数値シミュレータを基盤にして、その中の反応方程式の制御パラメータとして遺伝的要因を導入できれば、ほ場試験を計算機内で一部代替することも可能になるかもしれません。非常に夢があります。

こうしたモチベーションのもと、植物のミクロからマクロまでを繋ぐ物理数値シミュレータとして、SiCroFは開発されています。

### より具体的な例

物理数値シミュレーションには、２つ必要なものがあります。
一つは、メッシュデータと呼ばれる、多くの場合2次元や3次元の形状データです。一例として、イネ科草本の葉のメッシュデータを示します。
![grass_leafValues_000000.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489195/447aa7fc-b44e-0f1f-fc9f-cfccc05986fc.jpeg)
二つめは、シミュレータです。例えば、葉の最初の温度分布が分かっている状態で、与えられた環境下で、数秒後、数分後にどのような温度分布へと移り変わるのかを予測したい場合、熱拡散のシミュレータが必要になります。このメッシュデータをもとに、シミュレータによって温度変化の移り変わりを予測すると、例えばこのようになります。

![grass_leaf.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489195/6ab0e3e1-fe1c-4106-b849-f5f5c3cdcdb5.gif)

このシミュレーションの説明は一旦省きますが、このように、実際の葉を用いることなくその温度分布を予測するのがシミュレータの役割となります。

### 植物用物理数値シミュレータに要求されるものは、工業用と何が違うか？

この、メッシュデータの生成とシミュレータによる解析は、しばしば別々のソフトウェアを用いて行われます。
特に、CADとよばれる（多くの場合有償の）メッシュデータ加工ソフトウェアを用いてメッシュデータを手動で作成し、高額な商用シミュレータを用いて解析するという方法はよく行われます。ところが、植物を対象に物理数値シミュレーションを行う場合、両者が切り離されていることと、両者が商用であり経済的な負担が大きいことは問題となります。植物を対象とする場合、

- スキャナで撮影された2次元または3次元のデータを、
- ほとんど手作業を行うことなく（1データあたり数分程度）メッシュデータに変換し、
- メッシュデータをほとんど加工することなく（1データあたり数分程度）シミュレータに通して、
- できるだけ高速かつ大量のデータを処理（1データあたり数分程度）できる

ようにしたいものです。
また、変形、熱、水輸送、溶質輸送、光合成といった、植物の特性を理解する上で重要なシミュレーションについて一通りシミュレータが完備してあることが必要である一方で、電磁気や高速流体、衝突解析といった、工業分野でよく用いられるが植物においてはあまり重要でないシミュレータがあります。


### SiCroFは何が特徴か？

そこで、SiCroFは、植物の物理数値シミュレーションに特化したソフトウェアとして開発されています。

メッシュデータは、
- スキャナーにより撮影された画像データをほぼ直接メッシュデータに加工可能
- 初期条件や境界条件の設定はコマンド１行ずつで完了

シミュレータは、
- jupyter-notebookのテンプレートが用意されており、プログラミング不要でクリックだけでシミュレーションが動かせる
- PythonとFortran2003によるAPIを備え、大量データの同時処理に対応
- MPIに対応し、ワークステーション、サーバー、スーパーコンピュータなどのマルチコア環境での並列化に対応
- 変形、熱拡散、物質輸送、流体計算に対応し、幅広い生理現象の理解に役立つ
- 成長シミュレーションも実装予定


SiCroFはオープンソース・ソフトウェア（OSS)であり、GPLv2ライセンスのもとで自由に改変、再配布が可能です。
また、商用。非商用を問わずどなたでも無料でご利用いただけます。
あなたも、SiCroFのユーザーや開発者になってみませんか？

次回は、（１）環境構築とインストール方法を解説いたします。

次項: [(1)環境構築とインストール](https://qiita.com/soybean/items/e25435789775c945e264)
gitの使い方がわからないな〜

###gitの使い方わからないのはやばい

#ローカルのリポジトリで管理できるようにする

1.vagrantのssh接続を切る

2.gitで管理したいディレクトリに移動する
　（例えば　rails new aaaa でできたaaaってやつ）

3.git initで新しいレポジトリ作って初期化する

4.したっけinitializedなんちゃらが出てくる
　これで初期化完了おけまる

5.git add -Aでステージングっていうリポジトリに入る前の控え室的な所にいく
 git add file名でfileを指定することもできるよ

6.git commitでリポジトリに入って保存完了
　git commit -m ""でコメントも入れられるよ


*あとは、*
*git status とか、　git log　で色々確認できる*

#リモートリポジトリ作ってぶち込む

githubで作るやつは省略

1.git remote add origin リモートリポジトリのURL

2.git push -u origin master

これだけ？


#ブランチ作って作業する

1.リモートに上がってる状態で
 git clone 自分のURL

2.git branch [ブランチの名前]でブランチできたよ

3.git checkout [ブランチの名前]でmasterからブランチに移動します

4.git push origin [ブランチの名前]でリモートリポジトリに保存できるよ


###むずかしいなあ
【Python】ローカルに置いてあるHTMLファイルのタイトルをエクセルにまとめる

ローカルに保存された特定フォルダ以下の（大量の）HTMLファイルのタイトル一覧をエクセルにまとめます
tqdmでなんとなく進捗が出ます

``` .py
import pathlib
import glob
from tqdm import tqdm
import re
from bs4 import BeautifulSoup
import openpyxl

#フォルダを指定
p_temp = pathlib.Path('C:/hoge/')

#excelの準備
wb = openpyxl.Workbook()
sheet_title = wb.active
sheet_title.title = 'title'

#タイトルを取得（「titlelist」に格納）
titlelist = {}
filelist_t = p_temp.glob('*/*.html')
for i in tqdm(filelist_t):
    filename = str(i)
    with open(filename , encoding='utf-8') as f:
        html = f.read()
    soup = BeautifulSoup(html, "html.parser")
    title_tag = soup.find('title').text
    filelist = filename.split('\\')
    filenamecut = filelist[-1]
    titlelist[filenamecut] = title_tag

#A列にファイル名・B列に値を入れる
def toexcel(listname,sheetname):
    ii = 1
    for i in listname:
        f_name = 'A'+str(ii)
        f_value='B'+str(ii)
        ii +=1
        sheetname[f_name]=i
        sheetname[f_value]=listname[i]

toexcel(titlelist,sheet_title)

wb.save('titlelist.xlsx')
```
``` .py
soup.find('title').text
```
で必要な要素のテキストのみ取得

``` .py
    filelist = filename.split('\\')
    filenamecut = filelist[-1]
    titlelist[filenamecut] = title_tag
```
でファイル名のみの表示になっていますが、辞書型に格納するので階層ごとでまとめるとか適当に

結果
titlelist.xlsx
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322108/33c3f95a-b63c-ce31-e15b-22304b1954a7.png)
espressoでAlertDialogのsingleChoiceItemsを選択する方法

AlertDialogの`setSingleChoiceItems`で設定したアイテムをespressoで選択するには、次のように書けばよい。

```kotlin
onView(withId(R.id.showDialogButton)).perform(click()) // ダイアログを表示
onData(anything())
    .inAdapterView(withClassName(containsString("RecycleListView"))) // はっきりしたクラス名不明なのでcontainsStringを使う
    .atPosition(0) // 先頭の要素を選択
    .perform(click())
```
エクステンションとは？

エクステンション  【 extension 】  拡張 / ext / 拡張機能

エクステンションとは、拡張、拡大、延長、伸長、伸展、伸ばすこと、延期、内線電話、増築部分などの意味を持つ英単語。

まぁよく女の子たちが言うエクステというのもこのエクステンションからきてるんじゃないですかね。(+o+)

それはさておき、ソフトウェアの分野では、完成したソフトウェアに後から（あるいは外部から）機能を追加するソフトウェア部品や、追加された機能のことを、エクステンションあるいは拡張機能ということがあるみたいです。

外部記憶装置のファイルシステムで、ファイルの種類を表すためにファイル名の末尾に付加する短い符号のことを、拡張子あるいはエクステンションという。

データ圧縮の分野で、圧縮されたファイルやデータを元に戻す動作や機能のことを、展開、伸張、解凍、あるいはエクステンションということがあるみたいですYO。
cakephp modelメモ

cakephpのモデル機能で便利だと思った機能をまとめています。

- 複雑な条件で取得する場合共通部品化すると便利

```php
class UsersTable extends Table
{
    # 疎通確認済みの条件
    public function findActive(Query $query, array $options)
    {
        return $query->where(['Users.status' => 1]);
    }

    # 有料プランの条件
    public function findPaid(Query $query, array $options)
    {
        return $query->where(['Users.premium' => 1]);
    }
}

# コントローラ内、下記のように利用
# (この時点では SQL 文の作成しか行われず実行されませんが便宜上取得と書きました)

class UsersController extends AppController
{
    # 疎通確認済みのユーザの取得
    $active = $this->Users->find('active');

    # 有料プランのユーザの取得
    $paid = $this->Users->find('paid');

    # 疎通確認済み & 有料プランのユーザの取得
    $premium = $this->Users->find('active')
        ->find('paid');
}

```
[Node.js ダブルクリック 実行 ] プログラムをノンプログラマに実行してもらう方法

すみません、プログラムの話はしませんw

# 要件

便利なプログラムをサクッと書いて欲しい的なことを言われた時に、使えるテクニック。

実際にプログラムを、ノンプログラマにダブルクリックでサクッと実行してもらえたのでメモです。

自分はもっぱらJavascriptを書くことが多いのですが、多分他の言語でも使えると思う。

# 必要なもの

- Node実行環境
- プログラム
- 起動ファイル

**上記の3つなのですが、肝は「起動ファイル」です。**

### Node実行環境
Nodeの実行環境は赤枠の部分クリックしてwindowsならmsi,macならdmgファイルを落としてセットアップウィザードを感情0で進めてください。と言えばなんとかなるはず。
![スクリーンショット 2019-09-12 15.43.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204698/ae717dd5-6b78-04ec-0ff6-ccf05dc682e2.png)

### プログラム
好きなように書いてもらって、Nodeの場合は`package.json`の`script`の所に`npm run hoge`で起動できるようにして置いてください。

### 起動ファイル
はい。ここです。
自分が作ったのはめんどくさい系の作業をWebスクレイピングしてCSVファイルを作成するプログラムだったのですが、冒頭に言ったようにダブルクリックすると勝手にファイルができているみたいなものが作りたかったのです。

んで、調べると
windowsは`.cmd`
macは`.command`
という拡張子でコマンドプロンプトで実行できるコマンドをまとめて書いてダブルクリックで実行できることがわかった。

自分が作ったのは
`node_modules`のインストール用のsetupファイルと、実行用のexeファイル

#### setup

```:setup.cmd
cd /d %~dp0
npm i
```

```:setup.command
cd `dirname $0`
npm i
```

### exe

```:exe.cmd
cd /d %~dp0
npm run start
```

```:exe.command
cd `dirname $0`
npm run start
```

先頭の`cd`がないとダブルクリックしたところではなく、ホームディレクトリで`npm run start`しちゃうので、必要。

これをプログラムと同じディレクトリに置いてどうにかしてディレクトリごと渡して、最初に`setup.(cmd | command)`をダブルクリックして、`exe.(cmd | command)`をダブルクリックすれば実行できます〜となります。
*`setup.(cmd | command)`は次回以降不要。

こんな感じのフォルダを圧縮して渡せばOKかと。
![スクリーンショット 2019-09-12 16.13.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204698/79ce668c-cb27-e0b1-d580-9b7f52a145c6.png)




# どうだったか

最初に`node_modules`ごとプロジェクトに含めて渡したが、自分のパソコンがmacで渡した方がwindowsだったので、うまく動かなかった。(当たり前だが。)

なので、setupファイルを作成して再実行してもらったら動いた。

サクッとスクリプトを書いて実行してもらうのにはいいかもしれません。
shift, unshift, pop, pushまとめ

##shiftメソッド

```ruby:shift.rb
a = [0, 1, 2, 3, 4,]
a.shift
=> 0 #先頭の要素を返すため今回の場合はa.shift.classを実行するとIntegerが帰ってくる。
a #shiftは破壊的メソッドなので、ローカル変数aの値は[1, 2, 3, 4,]になる
=> [1, 2, 3, 4,]
a.shift(2)
=> [1, 2] #a.shift(2).classはArrayを返す。
a.size
=> 2
a.shift(3) #配列の要素数以上を指定すると、その時の要素全てを配列として返す
=> [3, 4]

b = [1, 2]
b.shift(0)
=> [] #引数を指定しないと空配列を返す。
b.shift(1) #引数に１を指定すると配列の最初の要素を配列に入れて返す。
=> [1]

#空配列に対する挙動
a = []
a.shift
=> nil #引数を指定しないとnilを返す
a.shift(2)
=> [] #引数を指定すると空配列を返す
a.shift(0)
=> []
```
[参考にしたページ](https://docs.ruby-lang.org/ja/latest/method/Hash/i/shift.html)


## popメソッド

```ruby:pop.rb
a = [0, 1, 2, 3, 4,]
a.pop
=> 4
a 
=> [0, 1, 2, 3,]
a.pop(2)
=> [2, 3]
a.size
=> 2
a.pop(3) 
=> [0, 1]

b = [1, 2]
b.pop(0)
=> []　
b.pop(1) 
=> [2]

#空配列に対する挙動
a = []
a.pop
=> nil
a.pop(2)
=> [] 
a.pop(0)
=> []
```

[参考にしたページ](https://docs.ruby-lang.org/ja/latest/method/Array/i/pop.html)


## pushメソッド
```ruby:push.rb
a = [0, 1, 2]
a.push(3)
a
=> [0, 1, 2, 3,]
a.push([4, 5])
=> [0, 1, 2, 3, [4, 5]]
a.pus('hoge') #String型のオブズエクトも大丈夫
=> [0, 1, 2, 3, [4, 5], 'hoge']
```

[参考にしたページ](https://docs.ruby-lang.org/ja/latest/method/Array/i/push.html)

## unshiftメソッド
```ruby:unshift.rb
a = [3, 4, 5]
a.unshift(2)
a
=> [2, 3, 4, 5]
a.unshift([0, 1])
=> [[0, 1], 2, 3, 4, 5]
a.unshift('hoge')
=> ["hoge", [0, 1], 2, 3, 4, 5]
```
[参考にしたページ](https://docs.ruby-lang.org/ja/latest/method/Array/i/unshift.html)

おまけ
pushとunshiftは自分自身を代入することができる。

```ruby:ruby,rb
a = [0, 1, 2]
a.push(a)
=> [0, 1, 2, [...]]
a.unshift('hoge')
=> ["hoge", 0, 1, 2, [...]]
a.pop #[...]を取り出す時のaを返す。
=> ["hoge", 0, 1, 2,]
```