OmniAICreator/Qiita-1.07M huggingface dataset:
Pageantを使用した踏み台サーバー経由のssh

# 今回の内容
各Cloudベンダで仮想OSを気軽に構築可能になった時代だが、疎かになりがちなセキュリティ。(この記事ももっとセキュリティ考えないといけないが…)
今回はその中で**ssh接続**をセキュリティを考慮しながら簡単に運用できるような検討をしたので備忘録として記事にした。
※既に世に出回っている内容で恐縮ですが。。。

# Cloudあるある
- どこのCloudベンダもssh用の鍵(公開鍵/秘密鍵)を使用して環境にアクセスするのが一般的となっている
- 踏み台サーバーを作成するのが必須
- sshd_configのPasswordAuthenticationを構築後に変更してパスワード認証にするのも可能だが、セキュリティ的にはアウト

# 環境の前提
今回検討した内容の環境構成を例として以下に図示する。
※可用性等については省略。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/278065/6954ee95-483b-6625-4bb9-c4f6e8950f91.png)

- Web/AP/DBサーバーへのsshアクセスは踏み台サーバーを経由する必要がある
- (可能なら)踏み台サーバーへのアクセス元も制御する(今回は図示していない)
- クライアント端末はWindowsとする

# sshで考慮したい内容
上記の環境の場合にsshで考慮したい内容としては以下が考えられる。

1. Web/AP/DBサーバーにアクセスするための秘密鍵を踏み台サーバーに保持したくない
2. (可能なら)それぞれの鍵は違う鍵にしたい

# 使用するツール
**Pageant**を使用すると考慮したい内容をクリアにできる。

## Pageantとは
OpenSSHのssh-agentと似たアプリで、エージェント転送を実施してくれるため、クライアント端末で起動したPageantに秘密鍵を登録することで、踏み台サーバーから他サーバーに経由する場合に、その秘密鍵を使用してsshを実施してくれる。

## 概要図
わかりずらいかもしれないので概要図を記載。

[通常のsshの流れ]
![image.png](https://qiita-image-store.s3.amazonaws.com/0/278065/2da5c903-5166-1f75-d9d4-b693e01b5470.png)

[Pageantを使用した場合]
![image.png](https://qiita-image-store.s3.amazonaws.com/0/278065/baf75fed-110b-1693-e8ba-be113d3c1e73.png)

## 注意事項
この構成を取るための注意事項としては、sshで考慮したい内容の2であげていた、それぞれの鍵は違う鍵にしたいという要件は満たすことができるが、**Pageantは登録した秘密鍵を上から順に実行していくため、sshd_configのMaxAuthTriesを超えないようにする設計が必要**だ。

## 追加考慮事項
また、公開鍵/秘密鍵のセットは、例えば**OSユーザー毎に用意する**ことでセキュリティを最低限担保した方が良いと考える。
※管理する鍵が多くなるので大変…

# 動作確認
実際に動作方法について簡単に記載する。
以下については今回は割愛するが、設定されていること。

- Teratermがクライアント端末にインストールされていること
- Pageantがクライアント端末にインストールされていること
- 公開鍵/秘密鍵があり、公開鍵だけが各サーバーに配置されていること

## Pageantの起動
[Pageantの起動]
Pageantを検索して起動。
<img width="149" alt="001.png" src="https://qiita-image-store.s3.amazonaws.com/0/278065/50c50ba4-55c0-1091-ecb2-8738675a6504.png">

[起動の確認]
隠れているインジケータに出てくる。
<img width="91" alt="002.png" src="https://qiita-image-store.s3.amazonaws.com/0/278065/1906248b-6c06-bce0-bad3-ee326f7ac0f5.png">

[秘密鍵の登録]
上記のPageantで右クリックして、「Add Key」を押す。
<img width="159" alt="003.png" src="https://qiita-image-store.s3.amazonaws.com/0/278065/6c53a3d4-0daf-9166-4a23-f17f49a61c71.png">
上記の後に秘密鍵を選択して、パスフレーズを入力する。
<img width="160" alt="004.png" src="https://qiita-image-store.s3.amazonaws.com/0/278065/4a0fa234-9524-01c6-b825-5c9edab93c3f.png">

以上でPageantの起動が完了。

## Teratermの起動
[Teratermの起動]
Teratermを起動して、接続したい踏み台サーバーにアクセスする。
認証画面で

- ユーザー名の入力
- エージェント転送するにチェック
- Pageantを使うを選択

してOKを押す。
<img width="372" alt="005.png" src="https://qiita-image-store.s3.amazonaws.com/0/278065/5b705a0a-73e0-8f2e-d41c-0ad8a09265e2.png">

[他サーバーへのssh]
Linuxのssh-agentは-Aオプションが必要だが、Pageantの場合はいらないので、下記で良い。

```
ssh XX.XX.XX.XX
```

sshをすると、下記の「エージェント転送要求を受け入れますか？」と表示されるので、「はい」を押す。
<img width="204" alt="006.png" src="https://qiita-image-store.s3.amazonaws.com/0/278065/b096f3b1-145b-b02d-0e2d-760025704f96.png">

下記画面はわかりずらいけど、踏み台サーバーから他サーバーにssh出来た。
<img width="557" alt="007.png" src="https://qiita-image-store.s3.amazonaws.com/0/278065/22ef5308-ad75-7a2f-7ce0-42185048a937.png">


# 最後に注意したい点
今回の方式(Pageant)は、結局はクライアントで秘密鍵をメモリに保持してしまうため、ある程度の妥協点だと考えている。
また、他にも考慮しないといけない部分たくさんあるけど難しいので割愛。（セキュリティとしてどうなの！？とは思うが…）
Web Components を使う際の設定



[Start using web components in React – Jens Jansson – Medium](https://medium.com/jens-jansson/start-using-web-components-in-react-6ccca2ca21f9)



### package.json

↓を追記
```js
"scripts": {
  "postinstall": "vendor-copy",
  ...
},
```

vendorCopyを追記

```js
"vendorCopy": [
  {
    "from": "node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js",
    "to": "public/vendor/custom-elements-es5-adapter.js"
  },
  {
    "from": "node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js",
    "to": "public/vendor/webcomponents-bundle.js"
  }
]
```


最終的には以下になる

```js
{
  "name": "react-web-components",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@webcomponents/webcomponentsjs": "^2.2.4",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "react-scripts": "2.1.3"
  },
  "scripts": {
    "postinstall": "vendor-copy",
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "vendorCopy": [
    {
      "from": "node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js",
      "to": "public/vendor/custom-elements-es5-adapter.js"
    },
    {
      "from": "node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js",
      "to": "public/vendor/webcomponents-bundle.js"
    }
  ],
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}
```


### public/index.html


```html
<script src="%PUBLIC_URL%/vendor/webcomponents-bundle.js"></script>
<script>if (!window.customElements) { document.write("<!--"); }</script>
<script src="%PUBLIC_URL%/vendor/custom-elements-es5-adapter.js"></script>
<!--! DO NOT REMOVE THIS COMMENT, WE NEED ITS CLOSING MARKER -->
```

`<!--! DO NOT REMOVE THIS COMMENT, WE NEED ITS CLOSING MARKER -->`は必須との事です。
その理由として、customElementsをサポートしていないブラウザではcustom-elements-es5-adapter.jsのロードが必要になるようです。

が、Chrome、Edge、IE11では、webcomponents-bundle.jsをロードしていれば、window.customElementsにはオブジェクトが入っているのでcustom-elements-es5-adapter.jsがロードされることはなさそうです。





##

```shell
npm install --save-dev babel-loader @babel/core
```

[Babel · The compiler for next generation JavaScript](https://babeljs.io/setup#installation)
dockerで(nginxと)php-fpmを連携させたときのメモ

nginxの環境を __docker-compose__で構築済。後にPHP(Laravel)のプロジェクトを動作させたいためPHPを実行する環境が必要。調べてみるとphp-fpmと言うモノが必要らしい。

#前提
nginxはド素人。PHP(Laravel)の環境を作る必要があり、使ったことが無いnginxで動かしてみようという軽いノリで始めたメモ。

すでに、[nginxに関するメモ有り。](https://qiita.com/niibori/items/a68e41a695fd1b1b80a1)
今回は、既に作成したnginxのコンテナとphpのコンテナを連携させる為のメモ。




#docker-compose.yml

```yaml:docker-compose.yml
version: '3'

services:
  web:
    build:
      context: ./docker
      dockerfile: web.docker
    container_name: web00
    depends_on:
      - app00
    ports:
      - 8080:80
    volumes:
      - ./proj/var/www/html:/var/www/html
      - ./docker/nginx.conf:/etc/nginx/conf.d/default.conf
    networks:
      - proj-net
  app:
    build:
      context: ./docker
      dockerfile: app.docker
    container_name: app00
    volumes:
      - ./src/var/www/html:/var/www/html
    networks:
      - proj-net
network:
  - proj-net
```

#./docker/app.docker
PHPからMySQLに接続する予定なので ```docker-php-ext-install pdo_mysql```を実行する。

```dockerfile:app.docker
FROM php:fpm
RUN docker-php-ext-install pdo_mysql
```

#./docker/nginx.conf

PHPファイルにアクセスされた際に、app00に連携されるようにnginx.confに ```location ~ \.php$ {...}```を追記した。

```conf:nginx.conf
server {
    listen       80;
    server_name  web00;
    root         /var/www/html;

    location / {
        # root   /usr/share/nginx/html;
        # index  index.html index.htm;
        root   /var/www/html;
        index  index.php index.html index.htm;
    }

    
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        # root   /usr/share/nginx/html;
		root   /var/www/html;
    }
    
    location ~ \.php$ {
       fastcgi_pass   app00:9000;
       fastcgi_index  index.php;
       include        fastcgi_params;
       fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
    }

}
```
json.Marshalにおける特殊文字の自動エスケープ

## ＆、＜、＞、記号の自動エスケープ
jsonパッケージのMarshal関数（*Encoder.Encodeメソッドも同様）では、
一部ブラウザがjsonに含まれる上記記号をhtmlと誤認しないよう、
下記のように自動でエスケープ処理がされる。

```
"&" => "\u0026"
"<" => "\u003c"
">" => "\u003e"
```
自動エスケープを無効にするには、
EncoderのescapeHTMLプロパティをfalseに設定した上で、
Encodeメソッドを呼び出す必要があるヅラ(・Д・)
[Encoder公式サイト](https://golang.org/pkg/encoding/json/#Encoder)



## サンプル
``` golang:encode.go
func main(){
    specialChars := struct{
        Ampersand     string    `json:"ampersand"`
        LeftAngleBracket string    `json:"left_angle_bracket"`
        RightAngleBracket string    `json:"right_angle_bracket"`
    }{
        Ampersand: "&",
        LeftAngleBracket: "<",
        RightAngleBracket: ">",
    }

    // Marshalを用いたJson変換
    bytes, _ := json.Marshal(specialChars)
    fmt.Println(string(bytes))
    // {"ampersand":"\u0026","left_angle_bracket":"\u003c","right_angle_bracket":"\u003e"}
    
    // Encodeを用いたJson変換
    encoder := json.NewEncoder(os.Stdout)
    // EscapeHTML設定値true(default)
    encoder.Encode(specialChars)
    // {"ampersand":"\u0026","left_angle_bracket":"\u003c","right_angle_bracket":"\u003e"}
    
    // EscapeHTMLをfalseに設定
    encoder.SetEscapeHTML(false)
    encoder.Encode(specialChars)
    // {"ampersand":"&","left_angle_bracket":"<","right_angle_bracket":">"}
}
```
WKWebViewで特定のリンクからアプリ側の処理を実行してみる with Codableを使う奴

若干変態的実装にもなっているので、マサカリ飛んでくるかなとおもって書いておく

# 今回やりたいこと

- WKWebViewで表示しているサイト上で、特定のリンクを踏んだ場合アプリ内での処理を実行したい。
- リンクはとりあえずqueryでパラメータやり取り
- どうせだからCodableあたりでも使って構造体にしてぇな？

# 若干手抜き気味の実装

一応やっていることの簡単な説明

- やりたいことに書いてある内容
- +αとしてこんなの
    - 指定したURLは内部処理へ
    - 別の指定したURLはWebViewで遷移
    - 指定したURL以外のアクセスはSafariで開く
    - それ以外は取りあえずキャンセル

```Swift:WebViewController.swift
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

        if let url = navigationAction.request.url,
            url.absoluteString.hasPrefix(WebViewConfig.openConciergeUrlScheme) {
            let params: [String: String] = url.queryParams()
            let jsonData = try! JSONSerialization.data(withJSONObject: params, options: [])
            let decoder = JSONDecoder()
            let hoge = try? decoder.decode(Hoge.self, from: jsonData)
            decisionHandler(.cancel)
        } else if let url = navigationAction.request.url,
            url.absoluteString.hasPrefix(WebViewConfig.baseUrl) {
            UIApplication.shared.isNetworkActivityIndicatorVisible = true
            decisionHandler(.allow)
        } else if let url = navigationAction.request.url {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
            decisionHandler(.cancel)
        } else {
            decisionHandler(.cancel)
        }
    }
```

`url.queryParams()`の部分は、こちらを使わせて頂きました。
https://qiita.com/roba4coding/items/9783625f7b2b469e17b8

```Swift:Hoge.swift
struct Hoge: Codable {
    let tab: String
    let room: String
    let message: String
}
```

以上、dump結果がこちらです。

```
  - tab: "2"
  - room: "default"
  - message: "あああああ"
```

割とスマートな形にはなっているが、変換が多すぎてなんかうーんってなる。
なお、暫定手抜き実装のソースなのでその辺はご了承ください。
他に良い方法があればご教示ください。

ではでは。
sckit-learnのアンサンブル学習「VotingClassifier」に触ってみる

# はじめに
最近、機械学習入門ということでsckit-learnを使い始めました。
しかし....

「ふむふむ、回帰問題をRegressorで分類問題をClassifierでとけばいいのか」

「タイタニック問題は分類だからClassifierを使えばいいか」

「使えるClassifier系のアルゴリズムは....」

「??? どれを使えばいいかわからぬ」

## VotingClassifierとは
> The idea behind the VotingClassifier is to combine conceptually different machine learning classifiers and use a majority vote or the average predicted probabilities (soft vote) to predict the class labels. Such a classifier can be useful for a set of equally well performing model in order to balance out their individual weaknesses.
（VotingClassifierの背景にある考え方は、コンセプトの異なる機械学習分類器を組み合わせ、
多数決や予測の平均(弱い投票)を使用し、クラスラベルを予測することです。
そのような分類器は個々の弱点を相殺するため、モデルの生成に有効である場合もあります。)
['1.11.5. Voting Classifier'][link-1]. scikit-learn.org (参照 2019-2-6)
訳は引用者による

「予測を重ねてそれぞれの弱点を補完する・・・」
「それって最強のアルゴリズムじゃん！！！」
　※ 個人の感想です。

# タイタニックでやってみる
[タイタニック][link-2]とはkaggleで公開されている、機械学習の基本を学ぶため用意されたコンペです。

## ソース

```python:sklearn_test.ipynb
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 〜〜〜データ処理部は省略〜〜〜
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier

# votingに使用する分類器の呼び出し
# パラメータは全てデフォルト
ada_clf = AdaBoostClassifier()
bag_clf = BaggingClassifier()
et_clf = ExtraTreesClassifier()
gb_clf = GradientBoostingClassifier()
rf_clf = RandomForestClassifier()
```

```python:sklearn_test.ipynb
vote_clf = VotingClassifier(estimators=[('rf', rf_clf),
                                        ('gb',gb_clf),
                                        ('et',et_clf),
                                        ('bag',bag_clf),
                                        ('ada',ada_clf)
                                        ])
vote_clf = vote_clf.fit(X_train, y_train)
```
[ソースコード全文][link-3]

「よっしゃ！スコアが0.765まで上がったぜ！」

# オチ
ソース中で呼んでいる「BaggingClassifier」単体でのスコアは0.770

# 参考サイト
[scikit-learn][link-4]
[Titanic: Machine Learning from Disaster][link-2]

[link-1]:https://scikit-learn.org/stable/modules/ensemble.html#voting-classifier
[link-2]:https://www.kaggle.com/c/titanic
[link-3]:https://www.kaggle.com/gsakabe/sklearn-ensemble-voting-test?scriptVersionId=10297638
[link-4]:https://scikit-learn.org/stable/index.html
Windows10でPythonのコーディング環境を準備する

ちょろっとコーディングしたいと思い、流行りに乗ってPythonでコーディングを始めるまでの備忘です
#環境
OS: Windows 10 Home( 64bit )
統合開発環境: Visual Studio Code(1.30.2)
バージョン管理システム: GitHub、Git(2.20.1)
プログラミング言語: Python(3.7.2)

#手順
  - Visual Studio Codeのインストール
     - Visual Studio Codeの日本語化
  - Visual Studio CodeとGitHubを繋ぐ
    - GitHubのアカウント作成
    - Gitをインストール
    - Git設定
    - GitHubでリポジトリを作成
    - GitにGitHubのリポジトリのクローンを作成
    - Visual Studio Codeでの変更をGitHubに反映
  - Pythonをインストール
    - Visual Studio Codeで自動補完を可能にする

#詳細
##Visual Studio Codeのインストール
自動補完がないとコーディングする気にならないので
[ https://code.visualstudio.com/ ](https://code.visualstudio.com/) からダウンロードしてインストール
特に難しいこともないのでガイドに従ってポチポチと
###Visual Studio Codeの日本語化
Visual Studio Codeのメニューから「View」->「Extensions」で「japanese」を検索
「Japanese Language Pack for Visual Studio Code」をインストール
Visual Studio Codeを再起動すると日本語化されている
##Visual Studio CodeとGitHubを繋ぐ
せっかく書いたコードがなくなってしまっては切ないので
###GitHubのアカウント作成
メールアドレスを準備して[ https://github.com/ ](https://github.com/) で「Sign up」
とりあえずfree planで十分 private repositoryも使える（publicは恥ずかしい）
###Gitをインストール
[ https://git-scm.com ](https://git-scm.com) からダウンロードしてインストール
「default editor」で「Visual Studio Code」を選択
他はデフォルトでポチポチと
###Git設定
コミット時のエラー回避の為nameとemailを設定する
Visual Studio Codeのメニューから「表示」->「ターミナル」

```powershell:ターミナル
git config --global user.name "[Name]"
git config --global user.email "[EMail]"
```

####GitHubでリポジトリを作成
- 「Repository name」はsample
- 「Private」を選択
- 「Initialize this repository with a README」にチェック
- 「Create a new repository」
- リポジトリのページで「Clone or download」で表示されるURLをコピー

####GitにGitHubのリポジトリのクローンを作成
- Visual Studio Codeのメニューから「表示」->「コマンドパレット」
- 表示された入力欄に`clone`と入れて`Enter`
- 上記コピーしたURLを張り付けて`Enter`
- リポジトリの場所を選択
- ウィンドウ右下の通知から「リポジトリを開く」
  - フォルダ「sample」が作られてファイル「README.md」が存在して入れば成功
 
####Visual Studio Codeでの変更をGitHubに反映
- Visual Studio Code「エクスプローラー」で右クリックし「新しいファイル」`sample.py`と入力し`Enter`
- Visual Studio Codeのメニューから「表示」->「SCM」
- 「Message」に`test`とでも入力してチェックマーク（コミット）
- ポップアップがでたら「はい」
- チェックマークの２つ右の「・・・」->「プッシュ」
  - GitHubのリポジトリページを確認してファイル「sample.py」があれば成功

##Pythonをインストール
[ https://www.python.org/ ](https://www.python.org/) から「Windows x86-64 executable installer」をダウンロードしてインストール
「Add Python 3.7 to PATH」にチェックして「Install Now」からの「Close」

###Visual Studio Codeで自動補完を可能にする
Visual Studio Codeのメニューから「表示」->「拡張機能」で「python」を検索
「Python(識別子: ms-python.python)」をインストールしVisual Studio Codeを再起動
ここで拡張機能からLinter Pylintが入ってないと怒られるので言われるがままにインストール

-----
以上
Bootstrap4のtooltipを出す方法

#1. JavaScriptを使用して機能させる
https://cccabinet.jpn.org/bootstrap4/getting-started/introduction
上記サイトどおりに、
以下の script をページの終わり近くにある body タグの直前に置いて有効にする。

```HTML
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
```

#2. HTML

https://cccabinet.jpn.org/bootstrap4/components/tooltips

```HTML
<li class="nav-item">
  <a class="nav-link" href="#">
  <i class="fas fa-sign-out-alt fa-lg fa-fw aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="ログアウト"></i>
  </a>
</li>
```

#3. JavaScript 実行コード

加えて、1.の3行の下にまずは直接書いてみた。

```javascript

<script>
  $(function () {
  $('[data-toggle="tooltip"]').tooltip()
})
</script>
```





#4. CSS
https://cccabinet.jpn.org/bootstrap4/javascript/tooltips/options

```CSS
.tooltip .tooltip-inner {
 color:red;
 background-color: #fff;
 border: solid 1px #000;
}


.tooltip-auto[x-placement^=bottom] .arrow::before, 
.tooltip .arrow::before {
 bottom: 0;     
 border-width: 0 !important;
 border-bottom-color: #fff !important; 
}
```

#5. 仕上がり

![image.png](https://qiita-image-store.s3.amazonaws.com/0/204239/822bf691-d3db-00c1-25a9-1b2d15d3b389.png)
[備忘録]Web3.jsのバージョン違いによる罠

Web3.jsをのリファレンスのサンプルコードを真似していたらエラーが出る。

```
Uncaught TypeError: web3.eth.Contract is not a constructor
```

面白いこと言うじゃん。。。

ぐぐったら同じ現象のひとがいた。

[TypeError: web3.eth.Contract is not a constructor (What is the reason ?)](https://ethereum.stackexchange.com/questions/47833/typeerror-web3-eth-contract-is-not-a-constructor-what-is-the-reason)

結論：バージョンが古い。1.0以上を使おう。

web3.jsのバージョンを調べてみたら、

```
> version = web3.version
> {api: "0.20.6", getNode: ƒ, getNetwork: ƒ, …}
```

草。

~~古い情報が溢れているので、気をつけましょう。という話。~~
ではなくちゃんと調べようという話。

---
【追記】2019.2.7
いろいろ調べてたら1.0はベータ版。０．２０．６が安定しているみたいな。
０．２０．６のリファレンスを探して書いてみる。
[画面イメージ付き]10分でECS を立ち上げるの巻き

#目的
ECS のデモで、最初の一歩を一緒に踏み出す

#目標
・nginx のWelcome ページを見る

#方針
時短でいきます

#作業
AWS マネジメントコンソールへログインし、ECS を選択する
![キャプチャ1.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/52fccc9c-134c-97be-fce1-4df2e56c3717.png)

今すぐ始めるを選択する
![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/e53d67b3-f4f5-98af-4305-802f707c1e56.png)

nginx を選択する
![キャプチャ3.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/49723d2e-c392-5411-1ed5-353dd4a7d20d.png)

コンテナ定義にて次へを選択する
![キャプチャ4.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/2a162362-91b1-ba5a-9256-b9903ff857b0.png)

今回はLB を使ってみましょう
![キャプチャ5.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/5a97b4cf-801e-a231-b420-500b72a42276.png)

クラスター設定（Fargate) はデフォルト設定で次へ
![キャプチャ6.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/f54d70c4-f8b4-64ea-4e91-7ff52a636b36.png)

全体設定を確認して、次へ
![キャプチャ7.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/e5e3b27f-08ce-49f8-9b4b-43f7f16e82a6.png)

5分ほど待つよ
![キャプチャ8.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/10736e11-c167-66b9-9d44-e55069158504.png)

コンプリート後、サービスを確認する
![キャプチャ9.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/c922d3a3-e186-cf12-d957-c640492662ed.png)

どの名前でアクセスできるか、LB の情報を確認する。
まずはLB の情報ページへジャンプする
![キャプチャ10.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/797edf92-8742-ac4b-b095-7715e055dfa0.png)

LB へ
![キャプチャ11.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/12918ad3-38eb-1c76-f41f-e83b7608868c.png)

DNS 名をコピーする
![キャプチャ12.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/161a57a4-8771-83a5-67e3-e3c7990caefa.png)

ブラウザへコピーした情報を張り付けて実行する
下のようにWelcome が見えたら完了
![キャプチャ13.PNG](https://qiita-image-store.s3.amazonaws.com/0/184724/2bb3db9e-617c-c50b-3595-ca4f86e2244c.png)

お疲れさまでした！
同じfunctionを何度も呼び出してるコードを可変個引数関数と...（スプレッド演算子）による整理

※本記事はphp5.6～で動作する内容になります。

引数違いの同じfunctionが複数書かれているものを少しスマートにした話です。
必ずこれにする必要は当然ありませんが、１つの方法としてこういったことができます。


```元のコード.php

mixJuice('Apple');
mixJuice('Strawberry');
mixJuice('Watermelon');
mixJuice('Guava');

function mixJuice($arg)
{
  ※※※ 処理 ※※※
}

```

```リファクタリングしたコード.php
mixJuice('Apple', 'Strawberry', 'Watermelon', 'Guava');

function mixJuice(...$args)
{
    for($i = 0; $i < count($args); $i++) {
        ※※※ 処理 ※※※
    }
}
```
osmbonuspack を使ってAndroid の OpenStreetMap 地図に KML をインポートする

[osmdroid を使って OpenStreetMap を Android に表示する](https://qiita.com/ohwada/items/c3741fb14a5142035314)
の続きです

## osmbonuspack

 osmdroid を 機能拡張するライブラリ。

https://github.com/MKergall/osmbonuspack

Google Play にデモアプリが公開されている。

https://play.google.com/store/apps/details?id=com.osmnavigator
## KML

Keyhole Markup Language　の略で、
地理空間情報を XMLで記述したもの。
Google Earth や Google Maps などで使用されている。

## KML をインポートするアプリを作る

### osmbonuspack ライブラリを取り込む

build.gradle

```
allprojects {
    repositories {
        jcenter()
      mavenCentral() 
       maven { url "https://jitpack.io" } // 追加する
    }
```

app/build.gradle

```
dependencies {

    compile 'com.github.MKergall:osmbonuspack:6.5.2' // 追加する
```
### AndroidManifestに permission を追加する

```
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

### MainAvtivity

```
private void loadKml() {
    mContext = this;
        new KmlLoader().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} 

class KmlLoader extends AsyncTask<Void, Void, Void> {
        KmlDocument kmlDocument;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        } 

        protected Void doInBackground(Void... voids) {
            kmlDocument = new KmlDocument();
            kmlDocument.parseKMLStream(getResources().openRawResource( R.raw.kmlfile), null);
    FolderOverlay kmlOverlay = (FolderOverlay)kmlDocument.mKmlRoot.buildOverlay(mMapView, null, null, kmlDocument);
        mMapView.getOverlays().add(kmlOverlay);
            return null;
        } 

        @Override
        protected void onPostExecute(Void aVoid) {
            mMapView.invalidate();
            BoundingBox bb = kmlDocument.mKmlRoot.getBoundingBox();
            mMapView.zoomToBoundingBox(bb, true);
            mMapView.getController().setCenter(bb.getCenter());
            super.onPostExecute(aVoid);
        } 

}

```

### KML ファイルの入手と配置

下記から ParisTour.kml をダウンロードする

http://mapsengine.google.com/map/kml?forcekml=1&mid=z6IJfj90QEd4.kUUY9FoHFRdE

kmlfile.kml にリネームし、res/raw に配置する

### スクリーンショット
![paris_tour.png](https://qiita-image-store.s3.amazonaws.com/0/64075/ec4420ee-41ca-345b-4f53-24997a6d42c4.png)


github にソースを公開した

https://github.com/ohwada/Android_Samples/tree/master/Osmbonuspack1
CakePHP3でERR_EMPTY_RESPONSEが発生するときの対処法

# はじめに
CakePHP3で開発をしている最中、「ERR_EMPTY_RESPONSE」が発生して、ページが表示されなくなりました。

# TL;TD
「tmp/debug_kit.sqlite」を削除すれば、OK

# 発生していた現象

```/var/log/apache2/error.log
Fatal error: Maximum execution time of 30+2 seconds exceeded (terminated) in /vagrant_data/src/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php on line 105
```

SQLiteでタイムアウトが発生しているようなので、SQLiteのDB（tmp/debug_kit.sqlite）を削除したところ、無事にページが表示されるようになりました。


# まとめ
CakePHP3にて、DebugKitのDBをSQLiteにしている方は、参考にしてみてください。
docker toolbox 共有フォルダへのボリュームを追加する際のコマンド


ShareFolderNameとは共有フォルダで追加したフォルダの名前。頭に`/`をつける必要がある。
container_dirはコンテナにボリュームを追加したい場所。
`-v /$ShareFolderName:$container_dir`

方法は下記urlを参照。
http://support.divio.com/local-development/docker/how-to-use-a-directory-outside-cusers-with-docker-toolboxdocker-for-windows
地球を分析してみよう

# はじめに

GoogleEarthEngineについて触れる機会があったので利用方法などさわりだけ簡単に書いてみます。
リモートセンシングなど観測や解析に詳しくなくても、クラウド上でサンプルを動かすだけでも面白いので興味がある方は是非やってみてください。

# 事前準備

## Googleアカウントの取得
アカウントを所持していない場合にはアカウンﾄを作成してログインしてください。

## Google Earth Engineへのサインアップ
- 下記サイトにアクセスし、右上の「SIGN UP」をクリック。
https://earthengine.google.com/
![googleearthenginetop.png](https://qiita-image-store.s3.amazonaws.com/0/226319/bcddc64c-46ff-ac96-142a-f2b4a1c0aeb8.png)

- 必要事項の入力
名前、所属、国、Engineの使用用途を記入。
下側の2つのチェックは、1つ目は[利用規約](https://earthengine.google.com/terms/)への同意なので必須、2つ目はEngineに関して情報が欲しい人のみチェックして「SUBMIT」押下で完了。

# サンプルの確認
[公式サイト](https://www.earthengine.app/)にサンプルがいくつかあります。
例えば、[Global Population Explorer](https://google.earthengine.app/view/population-explorer)を選択すると、全世界の人口密度などが視覚的に確認できるようになっています。
また、[サンプルのソースコード](https://code.earthengine.google.com/?scriptPath=Examples:User+Interface/Population+Explorer)としてGoogleEarthEngineのAPIを用いたJavaScriptが確認できるようになっており、少し変更してRunしたり、参考にして新規で作成したりととっかかりやすくなっています。

# まとめ
GoogleEarthEngineを利用開始するまでの手順とサンプルの見方を簡単にまとめました。
今後は様々な[API](https://developers.google.com/earth-engine/)を利用して色々動かしてみたいと思います。
（何か面白いネタないかなぁ）

また、2019年2月下旬に日本の衛星データプラットフォーム「Tellus」が利用できるようになるみたいです。
詳細はまだ調べていませんが期待。
Amazon Athenaで日次パーティションをDATE型の要素として使う

# これはなに
Amazon Athenaにスナップショットデータをためて行く場合、日次パーティションを利用することが多くあります。
日次でGROUP BYするなどして集計したい場合、集計日のカラムを追加し、ORDER BYすることがありますのでDATE型のカラムとして追加します。

# Query

`date(date_parse(year || month || day, '%Y%m%d'))`でDATEに変換できます。
`||`で文字列として連結し、`date_parse`でDATETIMEに変換、`00:00:00`の情報はいらないのでDATEにキャストします。

```sql
SELECT count(distinct(uid)),
         sum(amount),
         date(date_parse(year || month || day,
         '%Y%m%d')) AS date
FROM users
GROUP BY year, month, day
ORDER BY date(date_parse(year || month || day,
         '%Y%m%d'))
```
MacOS  iTerm2 | SSHログイン時にターミナルの背景色とタブの色を変更する

## 環境
- MacOSX : High Sierra 10.13.6
- iTerm2 : 3.2.7
- bash : GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)

## 成果物
[jxmtst/sshColor](https://gist.github.com/jxmtst/dafb2f5a39eb3ff7ee951ba7c6eb85fb)

## タイムライン
### ずっと思っていた事
色々なサービスの色々な環境を行ったり来たりしている間に
このタブがアクセスしているサーバがどこか忘れてしまう事がある、たまに困る

### こんな記事を見つけた

- [[macOS] SSHログインしたときだけターミナルの背景色を変えたい (iTerm2)](https://dev.classmethod.jp/etc/do-ssh-and-change-bg-color-iterm2/)

どうやらiTermには[コマンドラインから背景色を変更するエスケープシーケンスが独自拡張で実装されている](https://www.iterm2.com/documentation-escape-codes.html)らしい *1

```bash
# [背景色を変える]
echo -e '\033]1337;SetColors=bg=FF0000\a'
# => 背景色がFF0000(赤色)になる
```

```bash
# [タブ色を変える]
tab-color() {
  echo -ne "\033]6;1;bg;red;brightness;$1\a"
  echo -ne "\033]6;1;bg;green;brightness;$2\a"
  echo -ne "\033]6;1;bg;blue;brightness;$3\a"
}
tab-color 255 255 0
# => タブ色がFFFF00(黄色)になる
```

### 検索したらこんなGistを見つけた
- [BugRoger/ssh-background](https://gist.github.com/BugRoger/789887) 

こちらは[AppleScriptを使って背景色と透明度を変更している](https://www.iterm2.com/documentation-scripting.html) *2

```bash
# foreground: 文字色 RGBそれぞれを0-65535の間で指定(第4引数に透過度も指定できる)
# background: 背景色 RGBそれぞれを0-65535の間で指定(第4引数に透過度も指定できる)
# transparency: 透明度 0.0-1.0で指定 0.0が透過しない
bg_color() {
  /usr/bin/osascript <<EOF
tell application "iTerm"
  tell current session of first window
    set foreground color to {$1, $2, $3} 
    set background color to {$4, $5, $6} 
    set transparency to "$7"
  end tell
end tell
EOF
}
bg_color 65535 65535 65535 0 0 8738 0.1
# => 文字色(FFFFFF) 背景色(000022) 透明度(10%)
```

## ssh-backgroundをforkして改修した
1. 透明度が変更できるので、背景色変更の処理は*2を使用
- *1を見て背景色だけでなくタブ色も変更できる様にした
- 自分の開発プロジェクトではhost名にStaging環境は[stg-]Production環境は[prod-]のprefixがついているので、stgとprodで色を変えられる様にした
- 接続が重いときにCtrl-cで切断したら元の色に戻る様にした

## 使い方
*僕のデフォルトカラーは黒板色なので、各自で自分のデフォルトカラーに直して下さい

```
$ git clone https://gist.github.com/dafb2f5a39eb3ff7ee951ba7c6eb85fb.git dist
$ cp -p dist/sshColor /usr/local/bin/
$ chmod +x /usr/local/bin/sshColor
$ alias ssh=/usr/local/bin/sshColor
$ ssh prod-host
#=> 背景色が赤くなる!
prod-host$ exit
#=> 元に戻る
$ ssh stg-host
#=> 背景色が青くなる!
stg-host$ exit
#=> 元に戻る
```
`alias ssh=/usr/local/bin/sshColor` は.bashrcあたりに記述しておくと良いと思います
プログラムのコメントは、愚痴を書こう

# プログラムのコメントは愚痴を書こう

他人が作ったプログラムを見ていて役に立った経験がほぼありません。
「見りゃ分かるよ」という類のコメントがほとんどですね。

**世界一役に立たないコメント例**

```visualbasic
    'ループ変数に初期値0を入れる。
    i = 0
    While (true)
    :
```

見りゃ分かる


たまに、プログラムの和訳のようなコメントもありますが、プログラムを読んだ方が間違わないし。
コメント教育って必要なんじゃね？って思います。


設計書を充実させればよいじゃんというご意見もあると思いますが、設計書はプログラムと乖離しやすいと思います。特にバグなどの緊急対応時に、まず設計書を直してレビューがあるまでプログラミングは待つといった悠長なプロジェクトを経験したことがないですね。


#役に立つコメントって、
コメントを読むシチュエーションとは、こんなケースだと思う。


- 不具合が発生して緊急対応が必要な時。もしくは、仕様変更依頼がきた。

- 開発当時のプログラマーはいない。

- 詳細設計書から、どのようなデータを取得して、どう処理すべきかは把握している。でも、実際のプログラムは想像を超えていた。
 
- 不思議なプログラミングに対して、「技術的な制約があるのか」と不安になり調査時間がかかる。



### こんなコメントが望ましい

```vb
    '----------------------------------
    'このプログラムはガチャガチャしてます。
    'もっとシンプルに作成できると思うが、
    '途中で仕様変更が襲来したから突貫で直した。
    '
    'プログラムの流れはコレ
    '　１．テーブル　⇒　変数に格納
    '　２．変数から　⇒　一時テーブルに格納
    '　３．一時テーブル　⇒　もう一度、変数に格納
    '　４．CSV出力します。
    '
    'Update  20xx/12/24 23:40 メリークリスマス
    '----------------------------------
```


詳細設計書には載っていない部分の説明が、書いてあって理解が早くなります。

そして、「あー。いろいろあって、プログラムがガチャガチャしてしまったのね。」と技術的な制約への不安が払しょくされますし、更新日時刻に残る細やかな主張から優しい気持ちでプログラムの解読ができます。


#なぜ愚痴か

###まず、プログラマーは作文能力が低いです。

プログラマーは理系が多いので、設計書のような形式ばった文章だと情報が洩れる人が多いです。つまり、文章を書くのが苦手な彼らにどうしたら情報を漏らさずに書かせるかが重要となります。
少なくとも**しゃべり言葉で書いてもらった方だ断然伝わる情報になります**。

「しゃべり言葉で書いて」と依頼していたのですがそれでもまだ慣れない形式ばった文章を書くので、さらに踏み込んだ結果「愚痴を書け」に落ち着きました。




**結論。プログラムのコメントは、愚痴を書こう**
初心者が始めるMayaプラグイン作成 vol1(2018年Update5Ver)

#前提
想定環境「Windows7 64Bit」「Maya 2018-5」環境です。

使用しているのは「Visual Studio Community 2017」です
https://visualstudio.microsoft.com/ja/vs/community/

#Mayaの環境変数を設定
![WindowsMayaパス定義指定.png](https://qiita-image-store.s3.amazonaws.com/0/49072/326fb673-626c-35d8-936e-474ce20795d3.png)

#Mayaの実行ファイルがあるパスを指定
基本は「C:\Program Files\Autodesk\Maya2018\」
![Windows環境パス.png](https://qiita-image-store.s3.amazonaws.com/0/49072/e175bb57-9ab4-d211-95de-9434a76f7dfd.png)

#Visual Studioを起動

Visual Studioでプロジェクトを作成し
プロジェクト設定を[x86]から[x64]に変更
![VSx64.png](https://qiita-image-store.s3.amazonaws.com/0/49072/85a82530-055c-6c03-cb22-2a1fe76615d3.png)

#Visual Studioの全般設定
コンパイルしたファイルをMayaのプラグイン形式（*.mll）になるように設定
![全般設定.png](https://qiita-image-store.s3.amazonaws.com/0/49072/8d2f113e-cdb4-3edb-72ef-aec4893533fd.png)

#インクルードパス設定
C/C++→全般→「追加のインクルードディレクトリ」にMayaのパスを設定
![インクルードディレクトリ指定.png](https://qiita-image-store.s3.amazonaws.com/0/49072/bccf8725-0a06-3911-2636-2b791b8819d9.png)

#プリコンパイル済みヘッダーの設定
プリコンパイル済みヘッダーは「*使用しない*」に変更
![プリコンパイル済みヘッダー.png](https://qiita-image-store.s3.amazonaws.com/0/49072/e3098178-c0fe-27e1-61de-430872feb05f.png)

#プリプロセッサの定義の設定

```WIN32
_WIN64
_WINDOWS
_USRDLL
NT_PLUGIN
REQUIRE_IOSTREA
```
を追加
![プリプロセッサの定義.png](https://qiita-image-store.s3.amazonaws.com/0/49072/b4cd36c4-14f8-f23f-e57f-c28c0a46e3f8.png)

#ランタイム型情報の設定
ランタイム型情報を有効にする
![言語ランタイム型.png](https://qiita-image-store.s3.amazonaws.com/0/49072/cbd72fac-ea81-ee56-2807-a138f28e8c10.png)

#リンカー設定
追加のライブラリディレクトに

```
$(MAYA2018_PATH)\lib
```
Maya環境変数を指定
![リンカー全般.png](https://qiita-image-store.s3.amazonaws.com/0/49072/1c4d50c6-01b7-50ea-461a-d98fc4ac3eb2.png)

#リンカー入力

追加依存ファイルに書きを追記。末尾に[;]をつけ忘れないようにする

```
Foundation.lib
OpenMaya.lib
OpenMayaUI.lib
```
![リンカー入力.png](https://qiita-image-store.s3.amazonaws.com/0/49072/1142ed77-d3f9-14a6-bd37-25443d585733.png)

#リンカーコマンドライン
追加のオプション

```
/export:initializePlugin /export:uninitializePlugin
```

を追加する

![リンカーコマンドライン.png](https://qiita-image-store.s3.amazonaws.com/0/49072/494b2755-4b48-eefc-7185-7c45fcfd55d2.png)


#プラグインのテストコード
```HelloWorld.cpp
#include <maya/MSimple.h>
#include <maya/MGlobal.h>
DeclareSimpleCommand(HelloWorld, "Autodesk", "2018 update5");
/*
DeclareSimpleCommand マクロには、コマンドの実装に使用するクラスの名前
コマンドのベンダ(作者)の名前
コマンドのバージョン番号
という、3 つのパラメータが必要です。
*/
MStatus HelloWorld::doIt(const MArgList& args)
{
	MStatus stat = MS::kSuccess;
	char Hello[] = "\n Hello World\nMaya C++\n";
	cout << Hello << endl;
	MGlobal::displayInfo(Hello);
	return stat;
}
```

#Mayaに作成したプラグインを認識させる

.mllファイルをmayaのプラグインフォルダに入れる
![プラグインマネージャー.png](https://qiita-image-store.s3.amazonaws.com/0/49072/9b422a15-a2ef-1cc8-185c-b17dbe929b3f.png)

#プラグイン実行

プラグインフォルダに入れた後mayaを実行し
windows -> Settings/Preferences -> Plugin Manager
で
MayaTestProject.mllにチェックを入れ
scriptEditor
のmelタブに

```
HelloWorld
```

を入れ実行する

![実行結果.png](https://qiita-image-store.s3.amazonaws.com/0/49072/2f4770de-cafd-936b-49f9-4fa1d0993668.png)



#参考サイト
https://unpyside.wixsite.com/unpyside/single-post/2017/07/03/%E3%80%90Maya-C%E3%80%91Maya-C%E3%81%AE%E5%A7%8B%E3%82%81%E6%96%B9maya2017-update4
[メモ] TinkerOS 2.0.8でCPUの最大Clockが1.8→1.5 GHzになっている、のを修正


`/boot/rk3288-miniarm.dtb`を修正すると、なおる。

# TL;DR

```
# Fix Cpu Freq : /boot/rk3288-miniarm.dtb
curl -sSL https://github.com/mt08xx/files/raw/master/TinkerOS-v2.0.8_CPUFreqFix_rk3288-miniarm.dtb.bz2 | bzip2 -dc | tee rk3288-miniarm.dtb | md5sum
# => ce70fbd5cf42cc3e4d9728612837887e  - (Correct file ?)

# backup and copy to /boot
sudo mv /boot/rk3288-miniarm.dtb{,.bak}
sudo cp ./rk3288-miniarm.dtb /boot

# Reboot
sudo reboot
```


# 概要
- byobuを使ってると、CPUのクロックが表示されるが、以前は、1.8GHzとか出てたのに、1.5GHzくらいだなぁ、とは前々から気づいてたのだが、、、バグだったようです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/75594/dd0c8d94-4f10-6637-7d26-c064f91f4fa0.png)


- TinkerBoardForum より、[Maximum allowed frequency is 1.51GHz on 2.0.8 TinkerOS](https://tinkerboarding.co.uk/forum/thread-2204.html) という報告があって、githubで修正が入りました。
次のリリースでは、なおるようです。

# 環境
- TinkerBoard 
- TinkerOS v2.0.8 (`20181023-tinker-board-linaro-stretch-alip-v2.0.8.img`)


# 手順

1. イメージをmicroSDに焼く
2. とりあえず、`chromium`をアップデートしないようにして、パッケージ更新

    ```bash
sudo sh -c 'apt-mark hold chromium && apt update && sudo apt upgrade -y'
```

3. 必要そうなパッケージを入れる

    ```
sudo apt install -y byobu
```

4. `/boot/rk3288-miniarm.dtb`を修正する

	```bash
	# device-treeのツール.
	sudo apt install -y device-tree-compiler
	# 
	cd /boot
	# バックアップ
	sudo cp rk3288-miniarm.dtb rk3288-miniarm.dtb.bak
	# dtbから、dtsを作成
	sudo dtc -I dtb -O dts rk3288-miniarm.dtb -o rk3288-miniarm.dts
	# 修正
	#grep 'rockchip,max-volt' rk3288-miniarm.dts
	sudo sed -i -e 's/<0x149970>/<1400000>/g' rk3288-miniarm.dts
	# dtsから、dtbを生成
	sudo dtc -I dts -O dtb rk3288-miniarm.dts -o rk3288-miniarm.dtb
	# 再起動
	sudo reboot
	```



5. パフォーマンスモードにして、確認してみる？

    ```bash
echo performance | sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
```
twig で 独自フィルターを追加 

自分用メモ

```php:TwigCustomFilter.php
<?php

class TwigCustomFilter {
    private $customFilterList = [
        'ord' => 'twig_ord'
    ];
    public function getCustomFilterList() {
        return $this->customFilterList;
    }

    public function twig_ord($input) {
        if (!empty($input)) {
            return ord($input);
        } else {
            return 0;
        }
    }
}
```
```php
        Twig_Autoloader::register();
        $loader = new Twig_Loader_Filesystem($templateDir);

        $twig = new Twig_Environment($loader, []);
        
        $twigCustomFilter = new TwigCustomFilter();
        $customFilterList = $twigCustomFilter->getCustomFilterList();
        foreach ($customFilterList as $filterName => $functionName) {
            $filter = new Twig_SimpleFilter($filterName, [$twigCustomFilter, $functionName]);
            $twig->addFilter($filter);
        }
        $template = $twig->loadTemplate($templateFileName);
        $template->display($model->getValues());
```
pythonでファイルをzip形式に圧縮

大容量ファイルを圧縮する機会があったため、せっかくならPythonでできないのかと公式ドキュメントを検索したところ、

shutil
https://docs.python.org/ja/3/library/shutil.html

という便利なモジュールがあるようです。

ただ、そもそもzip形式には

・**最大圧縮可能ファイルは4GBまで**
・**解凍後は2GBまで**

という制約があるため、より大きいファイルを圧縮したい場合は

7zip
https://sevenzip.osdn.jp/

がおすすめです。
(70GB近いデータを共有する機会があり、その時に大変重宝しました。)

# shutilでzip形式に圧縮
使用法は極めて簡単で、

```python:zip.py
import shutil

shutil.make_archive('圧縮後のファイル名かPath', 'zip', root_dir='圧縮したいファイル名かPath')
```

です。
DAppsのバックエンドにGraphQL + MongoDBによるAPIサーバーを導入すべき理由

DAppsは日本語で、非中央集権型アプリや分散型アプリなどと呼ばれていますが、実際のアプリケーションは全く非中央集権型（Decentralized）ではなく中央集権型（Centralized）のアプリケーション「CApps」になっているというは周知の事実だと思います。
実際問題アプリケーションの楽しさやユーザビリティを考えると、ある程度は中央集権型になるのは仕方のないことなのだと思います。

ではDAppsのユーザービリティの向上を目指すにあたり、どのようなアーキテクチャにするべきなの考えてみます。
キーとなるのは、GraphQL + MongoDBによるAPIサーバーです。

## なぜAPIサーバー？
コントラクトの不得意なことの一つとして、一覧データの取得があります。
コントラクト内の一覧データを取ってくるには、データの件数だけループしてトランザクションを発行する必要があったり、コントラクト内で検索機能を実装しようとすると記述量が大幅に増えてコードがカオスになるためリッチな検索機能が提供しづらかったりします。
そのため、ユーザビリティを向上させるためにはコントラクトのデータをDBに同期し、API経由でデータを取得するようなバックエンドが必要になります。
また、複数のサービスが同じコントラクトを参照する場合、ABIとコントラクトアドレスを全てのサービスで共有する必要がありますが、DBにABIとコントラクトアドレスを保存することで、APIサーバー経由で自由にABIとコントラクトアドレスを取得できるようにもなります。

## 構成図
APIサーバーを導入すると、DAppsの構成は下記の図のようになります。
<img width="1097" alt="SystemConfiguration.png" src="https://qiita-image-store.s3.amazonaws.com/0/92492/661273d5-1c68-b6c3-f527-d30ee1deeb64.png">

| name | description |
| :--- | :--- |
| APP | SPAとして作られたフロントエンド |
| API Server | MongoDBに格納されたデータをGraphQLを用いて返却する参照用のサーバー |
| Sync Batch | コントラクトのイベントを監視し、コントラクト内のデータをMongoDBに格納する処理 |

## GraphQLを使う理由
基本的にDAppsにおける主役はフロントエンドです。
(トランザクションの代理発行をバックエンド側で行うようなサービスは別ですが。)
DAppsはフロントエンドに秘密鍵を持っている性質上トランザクションの発行を含む全てのビジネスロジックをフロントエンドが持ちがちなので、責務を明確に分離するためには、ビジネスロジックはフロントエンドに持ち、APIはデータを返すだけにする必要があります。

GraphQLであればQueryを用いてフロントエンド側で欲しい項目を指定してデータを取得できるので、データを返却する以外のロジックをサーバー側で持つ必要がありません。
また、データの更新はコントラクト側で行うためAPIサーバーは参照機能しか必要ないので、認証やバリデーションなどのロジックすらサーバー側で実装する必要がありません。
そのため、エンドポイント１つで自由度の高い参照機能を提供できるGraphQLを使うとサーバー側で実装すべきロジックが大幅に減り、とてもシンプルで分かりやすい構成になります。

これらの理由から、DAppsにおけるAPIサーバーではGraphQLを使うべきと考えています。

## MongoDBを使う理由
厳密にはMongoDBでなければならない理由はありませんが、コントラクト内のデータにはリレーションがなく、またコントラクトのイベントを監視してガンガンデータを格納していくのでパフォーマンス的な面からもRDBよりはNoSQLが向いていると思われます。
さらに検索機能をリッチにしたいので、NoSQLの中でも比較的自由度の高いクエリを発行できるMongoDBを使うべきと考えています。

## おわりに
現状DAppsにおけるデファクトスタンダートはまだ存在していないので、他にも良い方法があるかもしれませんが、GraphQL + MongoDBによるAPIサーバーを導入する手法はとても便利だと思います。
また、今後全ての機能をコントラクトで実装する良い解決案も出てくるかもしれないので、DAppsのこれからの進化に注目です。

---
ブログでも書いています
[DAppsのバックエンドにGraphQL + MongoDBによるAPIサーバーを導入すべき理由](http://blog.tanakas.org/api-server-by-graphql-and-mongodb-on-the-back-end-of-dapps/)
styled-components で Material Design の Text Fields (input) っぽいものを作る

[Material-UI](https://material-ui.com/) 等のライブラリを使わずに、[styled components](https://www.styled-components.com/)で [Material Design の Text Fields](https://material.io/design/components/text-fields.html#) (input)っぽいものを作ってみました。
簡易的なものであり、完全再現はできていません。コード量は60行程度です。
styled components 特有の機能を使っているわけではないので、[emotion](https://emotion.sh/) でも素の CSS でも実装できます。
また、React Hooks を使っていますが、もちろん Class Component 等でも実装できます。

# できたもの

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="y-takey" data-slug-hash="ZwXvdB" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="React/Babel Starter">
  <span>See the Pen <a href="https://codepen.io/y-takey/pen/ZwXvdB/">
  React/Babel Starter</a> by y-take (<a href="https://codepen.io/y-takey">@y-takey</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# ポイント

* 背景色を透明にし、枠線も下部以外はなしにするだけで Material-UI っぽくなる。
* input のフォーカスや値の有無でラベルの位置を調節して、inputの上側にしたり被せたりする。同様にラベルの文字色や下線の色もフォーカスの状態に応じて制御する。

---

ちなみに [Ant Design](https://ant.design/) 等の全く別のUIライブラリを使っていても、以下の様にすることで Material Design 化することができます。

```jsx
import { Input as AntdInput } from "antd";

const Input = styled(AntdInput)`
  // CSSは同じだけど、UIライブラリ特有の装飾が行われている場合は、その打ち消しが必要。
`;
```
VPC内のDBアクセスするため踏み台（BASTION)サーバをawscliで用意


こちらの資料を参考しながらこの手順を用意しました。
https://docs.aws.amazon.com/quickstart/latest/linux-bastion/

1. keypair 用意

    ないなら、EC2へアクセスできるようにKeyPairを作成します。

    ```
    aws ec2 create-key-pair --key-name bastion-keypair --region ap-northeast-1
    ```

     ローカルでPrivate Key `bastion.pem`を用意

    ```
    vi ~/.ssh/bastion.pem
    {上記で出力されたPRIVATE KEY情報をファイルに書き込む}

    # ファイル権限更新
    sudo chmod 400 ~/.ssh/bastion.pem
    ```


2. Bastion用のSecurity Groupを作成

    ```
    # Create security group
    aws ec2 create-security-group --group-name bastion-sg --vpc-id {使用するVPCID} --description "security group for basition instance(s) for acting as a intermediate jump of point for rds acccess"
    ```

    > 注意：CIDRを適切なIPで絞るべき


3. SSHアクセスを許可

    ```
    # Add authorization for ssh(port 22) to ingress
    aws ec2 authorize-security-group-ingress \
    --group-id $(aws ec2 describe-security-groups --query 'SecurityGroups[?GroupName==`bastion-sg`].GroupId' --output text) \
    --protocol tcp \
    --port 22 \
    --cidr "0.0.0.0/0"
    ```

4. 現状のRDS　Security Groupとの通信を許可

    ```
    export EXISTING_RDS_SECURITY_GROUPID={RDS Security Group ID }
    aws ec2 authorize-security-group-ingress --group-id ${EXISTING_RDS_SECURITY_GROUPID} \
    --protocol tcp \
    --port 5432 \
    --cidr "0.0.0.0/0" \
    --source-group $(aws ec2 describe-security-groups --query 'SecurityGroups[?starts_with(GroupName, `bastion-sg`)].GroupId' --output text)
    ```

5. 踏み台用のEC2を作成

    > ami-0f63c02167ca94956: Ubuntu 18.04 LTS

    ```
    aws ec2 run-instances --image-id ami-0f63c02167ca94956 --count 1 --instance-type t2.micro --key-name bastion-keypair --security-group-ids $(aws ec2 describe-security-groups --query 'SecurityGroups[?starts_with(GroupName, `bastion-sg`)].GroupId' --output text) --subnet-id {PUBLIC SUBNET ID} --associate-public-ip-address

    # 出たインスタンスIDを使って、用意されるまで待つ
    aws ec2 wait instance-status-ok --instance-ids　{INSTANCE ID}
    ```

6. SSHで踏み台（BASTION）サーバへアクセスして、DBに接続します。

    ```
    # IPを取得
    aws ec2 describe-instances --instance-id {INSTANCE_ID}  --query "Reservations[*].Instances[*].PublicIpAddress"   --output=text

    ssh -i ~/.ssh/bastion.pem ubuntu@{IP ADDRESS}
    ```

    # SSHで踏み台（BASTION）サーバにインストールしたいライブラリー・ツール

    ```
    # Pythonツール系インストールできるように準備
    sudo apt update
    sudo apt install python3-distutils
    curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
    sudo python3 get-pip.py 
    sudo apt install build-essential

    # python headersを取得（パッケージをビルド時に使用される）
    sudo apt install python3-dev

    # DBへ接続確認ために
    sudo python3 -m pip install pgcli
    ```


# SSH Tunnelにより、同じPCにDBがあるように接続する


1. 自分のPCからTunnel貼る：

    > postgresqlを使用例

    ```
    # LOCAL_PORT:REMOTE_ADDRESS:REMOTE_PORT
    ssh -nNT -L 5432:{VPC内のRDSIPADDRESS}:5432 -i ~/.ssh/bastion.pem ubuntu@{IP ADDRESS} &
    ```

2. 自分のPCからDBにへ接続：

    > [pgcli](https://www.pgcli.com/) postgresに接続できる簡易CLI

    ```
    pgcli -h 127.0.0.1 -p 5433 -d annotation_tool -U readonly -W
    ```
いいねの数などを「K」とか「M」とかで省略する拡張関数

Facebookのように「いいね!」の数を1.5Kとか10Mとか省略するための拡張関数を書きました。
ご自由にお使いください。
桁数を変えれば1.5万とかもいけると思います。


```Kotlin:Int.kt
package com.ringored.extensions

const val K = 1_000
const val M = 1_000_000
const val B = 1_000_000_000

/*小数点第1位まで表示*/
const val ROUND_DECIMAL = 10

fun Int.toStringKMB():String{
    val numUnit:String
    var num:Double = if(this < 0){-this.toDouble()} else {this.toDouble()}
    when {
        this < K -> {
            numUnit = ""
        }
        this < M -> {
            numUnit = "K"
            num /= K
        }
        this < B -> {
            numUnit = "M"
            num /= M
        }
        else -> {
            numUnit = "B"
            num /= B
        }
    }
    num = ((Math.round(num * ROUND_DECIMAL)).toDouble()/ROUND_DECIMAL)
    return if(num % 1 == 0.0) {
        (Math.round(num) * if(this<0){-1}else{1}).toString() + numUnit
    } else {
        (num * if(this<0){-1}else{1}).toString() + numUnit
    }
}
```

##使い方
```Kotlin:Main.kt
val random = (0..10).random()
val magnification  = (0..100000).random()
val test = (random * magnification)
val test2 = (0..100000000).random()

Log.i(LogUtils.TAG,"before:" +test.toString() +" after:"+test.toStringKMB() )
Log.i(LogUtils.TAG,"before:" +test2.toString() +" after:"+test2.toStringKMB() )
```

##出力結果
```
before:4887362 after:4.9M
before:196512 after:196.5K
before:97485003 after:97.5M
before:0 after:0
before:21898593 after:21.9M
before:67506 after:67.5K
before:54335794 after:54.3M
before:323694 after:323.7K
before:64874733 after:64.9M
Mac で Raspberry Pi 用のディスクをフォーマット（ SD メモリカードフォーマッター編）

# 概要
  
Raspberry Pi で使用するための、microSD カードをフォーマットします。今回は、SD メモリカードフォーマッターというアプリケーションを使ってみます。 

![20190205_SDカードフォーマッター_05_アイコン01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/598dbeb8-b0c6-a4a8-af68-68fe9040f726.png)


先日の投稿では、diskutil を使用しました。ご参考まで。

[Mac で Raspberry Pi 用のディスクをフォーマット（ diskutil 編）](https://qiita.com/stangler/items/b276db599636bc4d8c87)

# ホスト

## Mac

* [MacBook Pro ( 13-inch, Early 2011 )](https://support.apple.com/kb/SP619?locale=ja_JP&viewlocale=ja_JP) 魔改造済み


* メモリ: 16 GB

* ストレージ: SSD 512 GB

* OS: macOS Sierra 10.12.6
  
# ダウンロード
  
アプリケーションを以下のリンクからダウンロードします。  
  

[SDメモリカードフォーマッター](https://www.sdcard.org/jp/downloads/formatter_4/index.html)

# インストール
  
ダウンロードしたファイル SDCardFormatterv5_Mac.zip を解凍します。解凍してできたフォルダの中に Install SD Card Formatter 5.0.1.mpkg というのがあるので、それをダブルクリックし、指示に従って作業を進めます。
  
![20190205_SDカードフォーマッター_01_インストール01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/409ee624-5907-1525-3b61-41612b73b5db.png)

  
# フォーマット
  
インストールされた SD カードフォーマッターを起動します。  
  
![20190205_SDカードフォーマッター_02_フォーマット01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/4e69fc83-cdda-1331-8dc0-9d46157fbac9.png)

  
次に、カードを選択し、フォーマットオプション設定は「クイックフォーマット」にチェックを入れます。ボリュームラベルは適宜好きな名前を入力し「フォーマット」ボタンをクリックします。  
  
![20190205_SDカードフォーマッター_02_フォーマット01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/394f2308-7f4f-9037-f5c2-b835a640a442.png)

  
次に以下のようなダイアログが表示されますので「続行する」ボタンをクリックします。途中で、Mac のパスワードを求められるので、指示に従って入力しましょう。  
  
![20190205_SDカードフォーマッター_03_続行する01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/4622df20-cdb2-d966-f3de-b92fe8d55938.png)

  
最後に以下ように「フォーマット終了」と表示されれば OK です！  
  
![20190205_SDカードフォーマッター_04_終了01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/4e1f6a12-14a5-3701-d06d-0cb2fb585027.png)


以上です。
【MySQL】ワイルドカードを使って特定のデータベースにのみ権限を与える（GRANT）

いつも忘れてしまうのでメモ。

`piyo` ユーザーに対して `piyo_` というプレフィックスが付いたデータベース（ `piyo_sample` とか）にのみ権限を与える場合。

```sql
mysql> GRANT ALL PRIVILEGES ON `piyo\_%`.* TO 'piyo'@'localhost';
```

### `` `piyo\_%`.* `` について

`_` と `%` は SQL でワイルドカードとして使われるため、`_` をワイルドカードではなくそのままの文字列として認識させには `\` でエスケープさせる必要がある。

`%` についてはワイルドカードとして使いたいのでエスケープはしない。
S3バケットにブラウザから直接ファイルをアップロードしたい

#
```
curl -sS https://getcomposer.org/installer | php

vi composer.json

{
    "require": {
        "aws/aws-sdk-php": "2.*"
    }
}

php composer.phar install
ls vendor/aws/ -1

test.php
<?php
require 'vendor/autoload.php';
use Aws\Ec2\Ec2Client;

$client = new Ec2Client([
  'region' => 'ap-northeast-1',
  'version' => '2016-09-15'
]);
$result = $client->describeInstances([
  'Filters' => [
        [
            'Name' => 'tag:Name',
            'Values' => ['website'],
        ],
  ]
]);
print $result['Reservations'][0]['Instances'][0]['PrivateIpAddress'];



yum install php-mbstring.x86_64
php -m | grep mb
rpm -qa | grep openssl
rpm -qa | grep mod_ssl
rpm -qa | grep php-pdo
curl -sS https://getcomposer.org/installer | php
mkdir ~/bin
mv composer.phar ~/bin/composer
which composer
composer
yum install php-xml
composer require aws/aws-sdk-php
wget https://getcomposer.org/download/1.0.0-alpha11/composer.phar
php -d memory_limit=-1 composer.phar require aws/aws-sdk-php

```
【2019/2/6版】HDDの容量単価を計算してみた。お買い得はどれだ？

#憧れのZFSのために
唐突ながら…Oracleに対する思いは人それぞれいろいろあるとは思うのだが、シリコンバレーの一つの巨星だったSun Microsystemsの無残な最後を思うにつけ忸怩たる思いに駆られるのだった。そのSunの最後の、偉大なるレガシーがZFSだ。計算機の構成要素の中でもファイルシステムというのはCPUやOSなんかと比較すると地味目な存在だと思うが、もちろん縁の下の力持ち的な重要要素で、ZFSが発表されたときには大興奮したことを記憶している。「これぞ21世紀のファイルシステムだ」と。
その21世紀に突入してからすでに1/5近くが過ぎていったわけだが、ここのところずっとUnix系OSからは離れた生活が続いている。ところが先日、ひょんなことからLinuxでZFSが利用可能になっていることを知った。市井の人々がZFSを利用できる時代が、ついに来たのだ。
とはいえ、デスクトップパソコンとしてのLinuxシステムにZFSを使ってもあまりメリットがないように思う。もともとZFSは豊富な計算機資源が使えることを前提にした、未来のファイルシステムなのだ。憧れのZFSが向こうからやってきてくれたのだから、迎えるこちらとしても最大限のおもてなし（資源の用意）をせねばならぬ。ZFSの先進性を全身で浴びるような。

#そうだ、NASを作ろう
128bitアドレッシング、Copy on Write、RAID機能包含、遠隔スナップショットなど、やはり出自は隠せない。ZFSは大規模ストレージを構成するのがよく似合う。職場でそんなことをしていたら遊んでいるのがバレバレなので、自宅にファイルサーバー - NASを構築しようと思う。やはりディスクは10本くらいは欲しい。総容量は数十TBクラスか。今の時代平気で14TBなんていうHDDを売っている。10TB*10本=総容量100TBのNASなんてどうだろう。うん、キリも良いし縁起もよさそうだ。
そこで皮算用を始めるわけだが、WESTERNDIGITAL RED 10TBが2/6時点で41,131円。一本一本は大したことない金額でも10本となると41万円となるわけで、憧れだけで購入するにしてはこの金額、家族の信任を得られる自信は、全くない。

#HDD価格のスイートスポットはどこだ？
高騰が続くメモリなんかと違って、HDDはずっと下落基調にあることに変わりはない。容量と価格が絶妙にバランスするスイートスポットがあるはずだ。
というわけで、2019/2/6日付のAmazon.co.jpでの価格を調査した。下の表はいずれもSeagateのHDDで、Barracudaはデスクトップ向けのモデル、IronWolfはNAS向けのモデルということになっている。もう一方の雄であるWESTERNDIGITALのHDDもそうなのだが、NAS用のモデルは連続運転時の耐久性に優れているという付加価値がついているため価格設定も高くなっている。
注目してほしいのはTB単価である。1本の金額をその容量（TB）で除したもので、TB単価が同じであれば購入価値も同じと考えるのだ。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354946/85be8624-5058-d31c-3143-3122cb774adc.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354946/8b0b5967-f507-52e3-08fe-7449e8996f4d.png)
折れ線グラフを眺めてみるとデスクトップ向けのBarracudaでは4TBと6TBが最もコストパフォーマンスに優れていることがわかる。8TBも許容範囲内か。それより小容量のものは割高であり、逆に10TB超となるとポンっと価格が跳ね上がる。10TB級はまだ買い時ではなさそうだ。もちろんコストパフォーマンスよりもどうしても容量優先という人もいらっしゃるでしょうが。
NAS向けのIronWolfも4～8TBあたりが狙い目だ。6TBだけパフォーマンスが悪くなっているが、もちろん価格はコストと営業利益だけで決まるわけではなく、需要と供給も大きく販売価格に影響する。6TBがスイートスポットに入ってよく売れるため需給がひっ迫しているのではないだろうか。
一方、青とオレンジの線の乖離も非常に気になるところである。以下の表に価格差を数値化してみた。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/354946/75187544-3b5c-5811-0263-dd289c012514.png)
上の表はIronWolfのTB単価をBarracudaのTB単価で除したものである。すなわち高付加価値のIronWolfがBarracudaよりも高いか安いかを表している。
表を見るとわかる通りIronWolfはそもそもTB単価が非常に高い。ざっとBarracudaの1.5倍だ。高耐久という付加価値に対して1.5倍の価格を受容できるのか。1本1本は絶対値として大した差ではないとしても、10本まとめて購入することを考えると決して無視できない差といえそうだ。

#結局、狙いどころは？
容量でいうと4TB～8TBのレンジがコストパフォーマンスに優れることは分かったのだが、問題はNAS用のHDDの高価さだ。新たにNASを構築するにあたり初期費用に占めるHDDの割合は非常に大きく、購入計画に大きな影響を与えることになる。
結局どうすることにしたかというと、4TBのBarracudaを10本購入しようと思う。40TBで83,790円となる。現在稼働中のNASのデータ容量が10TB程度なので容量的には十二分といえる。HDDなんて遅かれ早かれ確実に壊れるものなので、壊れたところからIronWolfに換えてゆけばよい。ダブルパリティ＋ホットスペアでRAIDを組めば、めったなことで全損という憂き目にあうことはないだろう。Barracudaが壊れ始めるころには10TBクラスのTB単価も下がっているだろうから将来的な容量アップを狙うのもいい。10TB*10本=100TBも夢ではなさそうだ。

問題は100TBもの容量、何に使うか、ということなのだが。