OmniAICreator/Qiita-1.07M huggingface dataset:
体系化！ネットワーク基本まとめ

ネットワークの基本事項を物理的な部分にフォーカスして簡単に振り返ってみました。

## ネットワーク基本理解
必要最低限の用語を整理しておきます。  

* L2スイッチ...MACアドレスに基づいたテーブルで通信を行う。LANを形成する。
* L3スイッチ...ネットワークを分割して、VLANを生成することが可能。
* ルーター...ipsec・ファイアウォール・NATなどの機能を持ち、デフォルトゲートウェイになる。
* VLAN...１台の物理スイッチを複数の(論理的な)スイッチに分割する技術。
* VPN...インターネット上に特定の通信専用の回線を設けるインターネットVPNと大手の通信事業者の回線を用いてセキュアに通信を行うIP-VPNがある。
* IPsec...インターネット上で安全に通信を行うための暗号化技術。
* トンネリング...通信パケットをカプセル化してインターネット上でパケットの中身を見られないようにする技術。
* SSID...無線LANのアクセスポイントを識別する。アクセスポイントのSSIDを端末で設定することで通信が可能になる。
* CSMA/CD方式...衝突を検出したら即座に通信を中止し、ランダムな待ち時間が経過後、パケットを再送出する方式。
* CSMA/CA方式...パケットを送出する前に待ち時間を設ける。

> [L2スイッチ、L3スイッチ、ルーターの違い](http://sc.ipsecdh.net/entry/656)

## 通信レイヤーの流れ
OSI参照モデルの７階層に沿ってアプリケーションが通信で使うレイヤーをまとめてみました。
複雑な部分は補完できていないかもしれませんが、単純化するとこんな感じです。
<img width="817" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122992/55ecb523-80ea-3a5c-658f-3584be18e874.png">


## システムの歴史とネットワーク機器

システムの歴史とともにネットワーク機器がどのように発展してきたのかを見ていくことにします。

### メインフレーム時代(1980年代~)
汎用コンピューターと言われる巨大なコンピューターだった時代。この当時はモデムと言われるアナログをデジタルに変換する装置を利用して、PCとメインフレームの通信を行なっていたそうです。速度も9.6kbpsと今に比べると超遅いですが、当時ではこのメインフレームで企業の大規模なシステムが動いていました。映画「ドリーム」でもNASAでIBMのメインフレームが導入され、月面着陸の計算が行われていたシーンは印象的です。

### クライアント/サーバー時代(1990年代~)
いわゆるメインフレームと言われる中央集権的なシステムから、リッチな表示機能や計算能力を持ったコンピューターが登場してきたことによって、受信した情報を処理することに集中するサーバーと利用者が操作するクライアントに分離して利用するよう変わりました。ネットワークはというとまだまだ遅延が多く、データを送受信するのでやっとの状態。

### Web2.0時代(2000年頃~)
<img width="527" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122992/1e105eb9-d2cb-8af2-fbee-275925110348.png">

ティム・オライリー(O'REILLY)によって提唱された概念。ウェブの利用を加速化させ、インターネット時代の幕開けとも言える時代。従来の決まった人から決まった人への送受信という考えから、よりオープンに全ての人が自由に情報へアクセスできるようにという考えに変わり、検索エンジンやSNSが発展します。(クライアント/サーバーも３階層になります)この頃になるとネットワークのトラフィックもかなり多くなり、サーバーへの負荷を減らすためにロードバランサーやリバースプロキシ・キャッシュといった技術に注目され始めます。

### データセンターネットワーク時代(2005年頃~)
<img width="473" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122992/580abd89-d79e-0513-9942-cb97c4c969e1.png">

現在多くの企業でもクラウド化へ向けた取り組みが進んでいますが、実際にIT資産を持っている企業の多くのシステムやアプリケーションではこのデータセンターネットワークのような仕組みが利用されています。ネットワークのパフォーマンスを向上させるのに重要な「遅延を少なく、帯域を広く」するために、データセンターネットワークの規模拡大で多くのスイッチが利用され、Ciscoの売り上げもかなり伸びました。


### マルチクラウド時代(2010年頃~)
<img width="378" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122992/9c932656-2cfc-5a6e-affe-568d392113bb.png">

クラウドの登場で、マシンリソースはネットワーク経由で利用可能になりました。スイッチの機能も仮想化されたサーバー上(VM上)でまかなおうという考え方になります。SDN(Software-Defined Networking)によって自由にサーバーリソースをネットワーク接続し、ネットワークコントローラーにネットワークの制御を集中管理できるようになりました。

> [ネットワークの仮想化技術](https://www.nic.ad.jp/ja/newsletter/No58/0800.html)

## 無線接続の仕組み
無線接続の仕組みを簡単に図にしてみました。

<img width="592" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122992/ba283413-0a8c-5363-7fa9-ed8292bb3990.png">

802.11とはIEEEが定めた無線通信規格で、CSMA/CAを採用しています。  
流れを説明しておくと、  
アクセスポイントのSSIDを設定した端末は、アクセスポイントが発信しているビーコンを受信します。この状態ではまだアクセスポイントとの接続を完了したに過ぎません。  
コントローラーとは複数あるアクセスポイントを管理するものだと理解してください。ここでアソシエーションが完了するとアクセスポイントから接続する完全なネットワーク通信を行うことが可能になります。  
認証サーバーで端末の認証を行ったのち、端末にIPアドレスを動的に割り振り、アクセスするドメインのIPを変換して、外部ネットークへアクセスが可能になります。
async/await使わないで同期実行的な書き方



APIが提供されていないWebサービスのデータをプログラマティックに処理したいようなときには[puppeteer](https://github.com/GoogleChrome/puppeteer)をよく使うのですが、プロジェクトの規模が大きくなってくると、複雑な非同期処理のつじつま合わせに時間をとられるようになっていき、結局書いたコードを放棄するというようなサイクルを数年前から辿っていました

`async/await`を使うと同期実行っぽく書けるのですが、毎回毎回同じ文字を関数の前に書くのも芸がないし、かといって`Promise`はインデントが深くなるし、コールバック地獄になるしで、うまい方法はないか考えていましたが、自分なりにしっくりくる方法が見つかったので、紹介します

```It.js
const It=class {
  constructor(it){
    this.it=Promise.resolve(it);
    this.last=Promise.resolve();
  }

  does(fn, ...args){
    this.last=this.last.then(
      dummy => this.it.then(
        it => it[fn](...args)
      )
    );

    return this.last;
  }
}
```

クラス名とかファイル名は何でもいいんですが、上のコードでいうと

1. コンストラクタで何らかのオブジェクト(コードでは`it`)を受け取って、それを`Promise`でくるんで持っておく
2. `does`という関数で1の`Promise`から`it`を取り出して、`it`のメンバ関数を実行する(`does`の第一引数で呼び出したいメンバ関数名を指定、第二引数以降はメンバ関数の引数)
3. `last`で最後に実行された3の結果を保持しておく(これも`Promise`になる)

このクラスを拡張することで例えば、以下のようなことができます(`puppeteer`のラッパークラス)


```Browser.js
const Browser=class extends It {
  constructor(){
    super(browser);
  }
}

const Page=class extends It {
  constructor(){
    super(
      new Browser()
        .does('newPage')
    );
  }
}

const page=new Page();
page.does('on', 'console',
  msg => console.log(msg.text())
);
page.does('goto', 'https://qiita.com/');
page.does('evaluate', ()=>{
  console.log('doing');

  return 'done'
}).then(console.log);
// doing
// done
```

`does('on' ~` `does('goto' ~` `does('evaluate' ~` はそれぞれ前の処理が完了してから次の処理が実行されます(同期実行)
`It`クラスの内部で`Promise`を延々とつなげているだけなんですが、インデントしないで処理がかけます

戻り値で何か処理をしたい場合は`does('evaluate' ~`の部分のように`then/catch`で受け取ることもできます

あと`async/await`の場合は、`await`中は関数の処理が止まるのですが、この書き方だとあくまで`Promise`なので、後続の処理で別の`Promise`があれば、待たずに実行されます

毎回`does`を書くのが嫌なら、必要に応じて`does`を隠蔽するfacade関数を各クラスに実装しておけばよいです
Cyrus-IMAP 

とりあえず業務の備忘録として記載します。
見苦しい記載になっていますが、とりあえずご容赦を！

#前提条件
　CentOS 7.2

#インストール
　#yum install cyrus-imapd cyrus-sasl cyrus-sasl-plain telnet mailx

#設定
　#vi /etc/imapd.conf
　変更箇所のみ記載
　----
　sasl_pwcheck_method: auxprop
　defaultdomain: host.domain.tld
　----

　#vi /etc/cyrus.conf
　今回の設定のみで必要な箇所のみ記載
　----
　imap          cmd="imapd" listen="imap" prefork=5
　lmtpunix      cmd="lmtpd" listen="/var/lib/imap/socket/lmtp" prefork=1
　----

#ユーザ作成
 #saslpasswd2 cyrus
 #saslpasswd2 -c (アカウント名) -u (ドメイン名)

 ユーザ確認するためには以下コマンドを実行
 #sasldblistusers2

#メールボックス作成
　//管理インターフェースへログイン
　#cyradm --user cyrus localhost
　//メールボック作成
　localhost > cm user.(ユーザ名)

#動作確認
　# systemctl start saslauthd
　# systemctl start cyrus-imapd
　# telnet localhost 143
　1 login (ユーザ名) (パスワード)

#postfix連携
　# vi /etc/postfix/main.cf
　----
　mailbox_transport = lmtp:unix:/var/lib/imap/socket/lmtp
　----　

#quota
　こんな使い方みたい。RFC読まないとわかんないかなぁ。
　localhost> sq INBOX 100000


#宿題
　https://www.ossnews.jp/oss_info/Cyrus_IMAP
　-密閉型システム設計とは
　　おそらく、cyrus-saslのauxpropを指している。
　　cyrus-saslが持っている独自ユーザ管理のこと。
　　cyrus-imapd特有の話ではないと思われる。
　-プライベートメールボックス
　　cyradmで作成できるメールボックス。デフォルトでは/var/spool/imap。
　　/etc/imapd.confのpartition-default: /var/spool/imapで設定する。
　-mboxのサポート可否
　　多分サポートしていない気がする。pamだとMaildirで動作するか要確認。
　-
RailsからMySQLに接続できなかった時のメモ

# TL;DR

RailsからMySQLに接続するときにcredentials.ymlから値を取得している場合には、ERBタグで囲うこと
例：

```yml:database.yml
username: username
password: <%= Rails.application.credentials.dig(:db, :pw) %>
# 以下のようにしない
# password: Rails.application.credentials.dig(:db, :pw)
```

# ハマるまで

Railsアプリの各鍵管理にはcredentials:editを使って暗号化するとのことだったので早速以下のようにDBのパスワードを設定

```
db:
  password: myPassword
```

この状態で railsコンソールからputsして値が返ってくるので問題ないと判断。

```
bin/rails c

puts Rails.application.credentials.dig(:db, :pw)
# => myPasswordが返ってくる
```

MySQL内にデータベースを作るためbundle exec db:create を実行。
しかし、以下のようにアクセス拒否されてしまう

```
Mysql2::Error::ConnectionError: Access denied for user 'username'@'localhost' (using password: YES)
```

MySQL側で使用しているユーザーの権限が足りないのかなど色々調査。

# 原因

config/database.yml内に記述しているcredentialsから値を取得している部分に誤りがあった。
以下のようにERBタグで囲んだ状態でcredentials.digしなくてはいけない。

```yml:database.yml
username: username
password: <%= Rails.application.credentials.dig(:db, :pw) %>
# 以下のようにしない
# password: Rails.application.credentials.dig(:db, :pw)
```

ActiveStorageなどの設定でもERBタグで囲んであるので、単純なミス。。

# 考察

ERBタグで囲わないと、ymlファイル内のRails.application.credentials.digメソッドが解決されずにリテラルとして評価されてしまうということなのだと思われる。
ただ、MySQLへ接続しに行くところのソースを見ると以下のようにHashで値をとってきている。

```ruby:bundle/ruby/2.5.0/gems/mysql2-0.5.2/lib/mysql2/client.rb
 module Mysql2
    module Util
      #
      # Rekey a string-keyed hash with equivalent symbols.
      #
      def self.key_hash_as_symbols(hash)
        return nil unless hash
        Hash[hash.map { |k, v| [k.to_sym, v] }]
      end
```

ERBタグで囲った時の変数解決はどんな場合に実施されるのか？　が不明
（単純にRailsアプリ内からファイルが読まれるときにはいつも行われるのか？）
詳しい方がいらっしゃったら教えていただけると幸いです。

# 参考

[【備忘録】credentials.yml.encにdatabase設定を保存する](https://qiita.com/NaokiIshimura/items/e5db6ca7d56f2cb1f1fb)
MS SQL server managementにpythonでアクセスするチートシート

## 記事の趣旨
アドホックの実務で頻繁に使うので、pythonを使ってMicrosoft SQL server managementにあるデータベースにアクセスしデータを取ってくる方法をメモする。

## ソースコード
```
import pyodbc
import pandas as pd
from datetime import datetime

# SQLの情報を入れる
def connect_pyodbc():
   return pyodbc.connect("Driver={***};"
                     "Server=***;"
                     "Database=***;"
                     "UID=***;"
                     "PWD=***")

# クエリをデータフレームで読ませる
def sql_to_pdDF(X):
   return pd.read_sql_query("SQL query", X)

# SQLのデータをデータフレームに入れる
X = connect_pyodbc()
Data = sql_to_pdDF(X)

```

## 使い方
・pyodbcというライブラリを使う
・***には該当するSQL serverのそれを入れる
・Xにはわかりやすい適当な変数名を付ける
・"SQL query"にはSQL上で実行したいクエリを入れる
（例えばselect account_name, date, contents from customer where year(date)=2019など）


## 補足
冗長だったり間違ってたらご指摘お願いします。ひとまずこれで動くはずです。
Gitコマンド逆引きチートシート

## 前提
1. masterブランチに対して複数人で開発作業をしている。
2. フォークは禁止し、同一リポジトリ内で個人のブランチを作成する。
3. masterへのmergeの際には必ずプルリクエスト→他の人の承認というフローを必要とする。

## 基本コマンド
※・・・普段の開発作業で特に頻繁に使用するコマンド

| ToDo | Command | reference |
----|----|----
| プルリクエスト対象のブランチ確認 | (なし) | (Web操作) |
| ローカルにファイルをダウンロード<br>（masterブランチをダウンロード） | git clone < URL > | |
| ※ git clone時master以外のリモートブランチをダウンロード | git clone -b <リモートブランチ名> < URL > | |
| ※ ローカルディレクトリ移動 | cd <ディレクトリパス> |  |
| ※ 現在のブランチを表示する | git branch | (変数なし) |
| 他のリモートブランチを表示する | git branch -a | (変数なし) |
| 他のリモートブランチデータをダウンロードしそのブランチに切り替える | git checkout -b <ローカルブランチ名> origin/<リモートブランチ名> | ローカルブランチ名はリモートブランチ名と同じにすることを推奨 |
| リモートブランチの最新情報（追跡ブランチ）取得するが反映はしない | git fetch | (変数なし) |
| ローカルブランチを追跡ブランチの状態に同期 | git merge | (変数なし) |
| ※ git fetch + git merge | git pull | (変数なし) |
| ※ 現在のブランチを元に新規ローカルブランチを作成して移動する | git checkout -b <ローカルブランチ名> |  |
| ※ 他のローカルブランチに移動する | git checkout <ローカルブランチ名> |  |
| ファイル追加 | git add <ファイル名> |  |
| ※ 現在のディレクトリ配下の未登録ファイル・ディレクトリを登録 | git add . | (変数なし) |
| ファイル・ディレクトリ登録消去＆データ削除 | git rm <ファイル名> |  |
| 指定したディレクトリ以下のファイル・ディレクトリ登録消去＆データ削除 | git rm -r <ディレクトリ名> |  |
| ファイル・ディレクトリ登録消去＆データ維持 | git rm --cached <ファイル名> |  |
| 指定したディレクトリ以下のファイル・ディレクトリ登録消去＆データ維持 | git rm --cached -r <ディレクトリ名> |  |
| ※ 編集後の差分出力 | git diff | (変数なし) |
| ※ 編集後の差分と新規登録・消去した差分出力 | git diff --cached | (変数なし) |
| ※ 現在のブランチに変更を反映 | git commit -am "<comment>" |【-a】変更のあったファイルすべてをコミット※ワーキングツリーからコミット<br>【-m】コミットにメッセージを添える  |
| ※ 現在のローカルブランチを元にリモートブランチを新規作成 | git push -u origin <ローカルブランチ名> |  |
| ※ リモートブランチをローカルブランチの状態に同期 | git push | (変数なし) |

## 整理や失敗したときに使うコマンド
| ToDo | Command | reference |
----|----|----
| コミットを一つ取り消す。ファイルも元に戻す | git reset --hard HEAD^<br>git reset --hard "HEAD^" | Windowsの場合、^が特殊記号扱いになるため引用符で囲む |
| コミットを一つ取り消す。ファイルはそのまま | git reset --soft HEAD^<br>git reset --soft "HEAD^" | Windowsの場合、^が特殊記号扱いになるため引用符で囲む |
| コミットをn回取り消す。ファイルも元に戻す | git reset --hard HEAD~n |  |
| コミットをn回取り消す。ファイルはそのまま | git reset --soft HEAD~n |  |
| git reset後の強制push | git push -f |  |
| コミット履歴（概要） | git log |  |
| コミット履歴（詳細&直前2エントリ） | git log -p -2 |  |
| 直前のコミットを打ち消すコミット | git revert HEAD |  |
| 特定のコミットを打ち消すコミット | git revert [ commit ID ] |  |
| リモートブランチでローカルブランチを強制上書き | git fetch origin <リモートブランチ名> <br> git reset --hard origin/<リモートブランチ名> | git pullに強制モードは存在しないため、こちらの手順が必要 |
| 不要なローカルブランチを削除する(マージしたか確認あり) | git branch --delete <ローカルブランチ名> |  |
| 不要なローカルブランチを削除する(マージしたか確認なし) | git branch -D <ローカルブランチ名> |  |
| 不要なリモートブランチを削除する | git push --delete origin <リモートブランチ名><br>git push origin :<リモートブランチ名> |  |
いじめブラックαをつくったー

この記事はフィクションです。実在の人物や団体などとは関係ありません 

元ネタ
> 【漫画】天才がいじめにあったらどうするのか？→倍返しするのか (マンガ動画）
> https://www.youtube.com/watch?v=R_Llrqnct6g

![Screenshot from 2019-06-10 01-42-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434367/7ca047ad-e1ad-27cf-0e66-a1be1bcbdffb.png)

# デモサイト
https://ijime-black-alpha.web.app/

# いじめブラックαとは
全国のいじめの加害者をブラックリストに登録して、企業が採用時の人格調査に役立てるシステムだ・・・！

# TODO
- いじめランクをつける https://youtu.be/R_Llrqnct6g?t=138

![Screenshot from 2019-06-10 01-46-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434367/ab9dfbcb-acdb-8ce9-2ca2-8e78277d8181.png)

- いじめの加害者を追加する
- どんな卑劣ないじめをしたのか詳細に記載する https://youtu.be/R_Llrqnct6g?t=142
- いじめを判別するAIの開発 https://youtu.be/R_Llrqnct6g?t=166
    - AutoML Action Recognitionでいじめを検出
    - AutoML Visionでいじめの物的証拠を検出
- LPサイトの作成 https://youtu.be/R_Llrqnct6g?t=185
UWP関連のメモ

# UWP 関連のメモ

## DLL の動的読み込みはできなさそう

[Dynamically Load Assembly – Welcome to the Windows developer feedback site!](https://wpdev.uservoice.com/forums/110705-universal-windows-platform/suggestions/18145291-dynamically-load-assembly)

[c# - Windows UWP - Dynamically Load Assembly In Side Loaded App - Stack Overflow](https://stackoverflow.com/questions/42237065/windows-uwp-dynamically-load-assembly-in-side-loaded-app)

したがって、MEF や MEF2 を使って、プラグイン的なものを作ることはできない。

## 画面遷移時に渡せるパラメータは基本的な型のみ

[Frame.Navigate Method (Windows.UI.Xaml.Controls) - Windows UWP applications | Microsoft Docs](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.frame.navigate)

> The navigation parameter to pass to the target page; must have a basic type (string, char, numeric, or GUID) to support parameter serialization using GetNavigationState.

string, char, numeric, or GUID ならいける。

独自定義の型の情報を渡すためには、文字列にシリアライズして渡す。
そうしないと、アプリケーション終了時やサスペンド時に、例外が発生した。
[Rails 5.2] credentialsだとrecapchaの環境変数が読み込めない[memo]

gemのrecapchaで必要なsitekeyとsecretkeyは環境変数から読み込まれますが、
credentialsなどは考慮されていないため、credentialsから環境変数を設定しました。

https://github.com/ambethia/recaptcha

    # vi config/initializer/recaptcha.rb

    +ENV['RECAPTCHA_SITE_KEY']   = Rails.application.credentials.recaptcha[:site_key]
    +ENV['RECAPTCHA_SECRET_KEY'] = Rails.application.credentials.recaptcha[:secret_key]
上記のようにすることで環境変数はcredentilasを利用しつつ、recapchaも使えるようになりました。
コードの共通化を意識する ②　モデル編

自分がエンジニアバイトをしているところでは週1回Rails勉強会をしています。今回はそのやったところのまとめを残しておきます。
参考書：[現場で使える Ruby on Rails 5速習実践ガイド]
(https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Ruby-Rails-5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E5%A4%A7%E5%A0%B4%E5%AF%A7%E5%AD%90/dp/4839962227)

# Modelの役割を確認
Modelは役割分担されたMVCの中でDBとのやりとりとビジネスロジック(アプリケーション特有の処理)を行っています。どういったデータをDB取得するのかといった処理、オブジェクトが持つデータを変更する処理などはModelで行うのが基本です。

## Model内のコードを共通化する
### 共通機能をモジュールで共通化する
モジュールに共通化した処理を定義しておくことで、それぞれのModelに必要な処理だけをモジュールとしてMix-inすることができます。
またRailsではActiveSupport::Concernが提供されており、これをextendしておくとActiveSupport::Concern が提供しているメソッドを使うことができるようになるため、素のRubyでモジュールを作るより楽になります。

### 単一テーブル継承(STI)をして、親クラス(基底クラスともいう)に共通処理をもたせる
似たクラスが存在する場合本質的に似ている部分を切り出し、それを基底クラスとして継承することで共通化をすることができます。RailsではModel一つにつき、それに対応したテーブルが存在します。STIでは継承関係にある複数のModelを一つのテーブルとして扱います。これは三つのモデルにそれぞれ存在するカラムを一個のテーブルに集約するということです。なお集約しているテーブルにはtypeというカラムを用意し、STI上で所属するModelのクラス名を文字列として格納します。例えばベースとなる親クラスAがあり、Aを継承するBとCがあります。Bには「name」というカラムが存在し、Cには「email」というカラムが存在します。通常ならテーブルBとCがありますがSTIではテーブルAに継承関係も含めて全てのカラムが存在します。BとCのカラムがテーブルAにあり、nameもしくはemailはどちらかはNULLになります。
STIの問題点としては以下があります。

- Rubyでは継承が一回しかできないため、一度継承を使うと他の類似性は継承できない
- 異なるクラスのレコードを一つに集中させるため、データ量が多くなる
- DBのtypeカラムがModel名に依存するため、Model名が変わると変更しないといけない
- クラスのデータ構造の差異が大きいと、データベースの利用効率が悪くなる。データメンテナンスの際に気にすべきこと
が増大するなど維持コストが高くなる。

なのでSTIを検討する場合は以下を満たすかを考慮しましょう。
- Model間の関係が「AはBの一種である」
- 各Model間のカラムに大きな差異がないこと
- DB上一つにまとまっていると便利なとき

ちなみに会社の先輩にSTIを複数人開発のときに使う場合はわかっている人同士でやらないと混乱すると言われたので使いづらそうですね。

## ApplicationRecordに共通処理をかく
ApplicationRecordはすべてのActiveRecordモデルクラスの基底クラスになっているため、ここに共通処理を書けば全てで使うことができます。ただし全てで使えるため、全てのModelで共通でない処理を加えると問題が発生することもある。

## ApplicationRecordとModelの間に別でModelを挟む
全てに共通する必要はないが一部の複数のModelに共通処理をもたせたい場合、ApplicationRecordとの間に別で特定のModelを継承していないModelを作り、継承させる方法です
ApplicationRecord - A(ここ) - B
RxJS+TypeScriptのシンプルな構成の作成

# 何
- RxJS+TypeScriptの挙動を確認するための簡単な構成を作成する。

## 環境
- 前提条件：nodeが入っていること。確認時のバージョンは以下

```
>node --version
v10.16.0

>npm --version
6.9.0
```
- 注意：RxJSが6系から書き方が大きく変わった。今回はinstall時にバージョンを指定しなかったので、現時点の最新の6系がターゲットとなった。バージョンを限定したい場合は、npm install時に指定する。

## 構築

``` sh
mkdir rxjs_test

cd rxjs_test

npm init -y

## 導入
npm install --save-dev typescript
npm install --save rxjs
npm install --save @types/node

## ファイルの準備
touch tsconfig.json
mkdir src
touch src/app.ts
```

``` tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2017",
    "sourceMap": true,
    "types" : ["node"]
  },
  "exclude": [
    "node_modules"
  ]
}
```

## バージョン確認
``` sh
npm list --depth=0
+-- @types/node@12.0.7
+-- rxjs@6.5.2
`-- typescript@3.5.1
```

## 確認したい実装の記述
``` src/app.ts

// RxJS v6+
import { of, Observable, throwError } from 'rxjs'
import { map, take, mergeMap, catchError } from 'rxjs/operators'

// ** 簡単な例

of(1,2,3).pipe(
    take(2),
    map((n) => n ** 2)
).subscribe(n => {
    console.log(n);
});

console.log('--------------------------------------------------');

// ** 複雑な例

// エラーを返しうるなんらかのAPIの模倣
function someApi(n: number): Observable<string> {
    if (n === 0) {
        return throwError('zeroはダメ');
    } else if (n < 0) {
        return of('ng');
    }

    return of('ok');
}

// 引数に属性を付けて返すなんらかのAPIの模倣
function someApi2(s: string): Observable<string> {
    return of(s + '@@@');
}

// ユーザの入力値の模倣
const userInput = of(1,3,-1, 0, 2);

userInput.pipe(
    mergeMap(n => someApi(n)),
    // someApiでのエラー時に、subscribeのエラー処理にフローを移す場合はcatchErrorをコメントアウトする
    catchError(error => of('catch_error')),
    mergeMap(someApiResult => {
        // someApiの結果によってsomeApi2の呼出しを分岐する
        if (someApiResult === 'ok') {
            return someApi2(someApiResult);
        }else if(someApiResult === 'catch_error') {
            // なんらかのエラー処理
            console.log('catched');
        }
        // throwErrorとしないことで、正常系として後続処理を行う（後続処理はnullチェックが必要になる）
        return of(null);
    })
).subscribe(
  next => {
      if (next !== null)  {
        // someApi2を呼んだときに行う何らかの処理
        console.log(next)
      }
  },
  error => console.log('error.' + error),
  () =>  console.log('complete.')
);

```

## ビルドと実行
``` bat
# ビルド(./src/app.jsができる)
./node_modules/.bin/tsc
# 実行
node ./src/app.js

# windows コマンドプロンプトの場合、以下でビルドからの実行
.\node_modules\.bin\tsc && node .\src\app.js

# windows powershellの場合、以下でビルドからの実行
.\node_modules\.bin\tsc ; node .\src\app.js

```

## 実行結果
```
1
4
--------------------------------------------------
ok@@@
ok@@@
catched
complete.
```
【Talend】テストデータ作成２

# 概要
[前回記事](https://qiita.com/shimiyou10/items/24764b187044d8864ddd)   にてテストデータを作るジョブを作成しましたが、データパターンの作成方法をいくつか書いてみます。
他にももっと良い方法などあるかもしれませんが、参考までにご覧ください。

# 使用環境
TalendOpenStudio 7.1.1

# 参照
[ルーチン一覧](https://help.talend.com/reader/onzulQGhW96zdL_th7rxpA/UNYfDoGI7D6aSPrxIoAYCQ) 

# 使用方法
tRowGenerator のRowGeneratorエディターにて、カラム別に関数を設定します。
関数欄にて、使用する関数を選択する方法と、
カスタマイズパラメータを選択して、式ビルダで指定する方法があります。
処理の融通が利くので、下記はカスタマイズパラメータを指定して、
式ビルダに設定した場合と考えてください。

![testdata_16.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165430/d6e4a31e-71d0-cb71-d75e-5e0a075d1131.jpeg)

# 数値ルーチン

- 連番を取得

関数：Numeric.sequence("連番名", 開始値, 増加値)
戻り値：Integer
式ビルダ設定 例) 

```
Numeric.sequence("s1",5,2)
```

| 出力結果 |
| --: |
|5  |
|7  |
|9  |
|11 |
|13 |

※5から開始し、2ずつ増えました。
※S1は、ジョブ内でグローバルです。
　resetSequence でシーケンス値をリセットできます。
　マイルーチンなどでシーケンス値を操作することができるでしょう。

- ランダム値を取得

関数：Numeric.random(最小値, 最大値)
戻り値：Integer
式ビルダ設定 例) 

```
Numeric.random(5,10)
```

| 出力結果 |
| --: |
|8  |
|10 |
|7  |
|6  |
|8  |

- ゼロ埋めした値を取得

関数：String.format("フォーマット", Numeric.random(最小値, 最大値))
戻り値：String
式ビルダ設定 例) 

```
String.format("%06d", Numeric.random(5,10)) 
```

| 出力結果 |
| --: |
|000008|
|000007|
|000006|
|000010|
|000009|


# TalendDataGeneratorルーチン

- ランダムな名前

関数：TalendDataGenerator.getFirstName()
戻り値：String
式ビルダ設定 例) 

```
TalendDataGenerator.getFirstName()
```

| 出力結果 |
| --: |
|Andrew  |
|William |
|Millard |
|Franklin|
|Benjamin|

- ランダムな姓

関数：TalendDataGenerator.getLastName()
戻り値：String
式ビルダ設定 例) 

```
TalendDataGenerator.getLastName()
```

| 出力結果 |
| --: |
|Carter |
|Clinton|
|Pierce |
|Kennedy|
|Hoover |

# TalendDateルーチン

- ランダムな日付

関数：TalendDate.getRandomDate("最小日", "最大日") 
戻り値：Date
式ビルダ設定 例) 

```
TalendDate.getRandomDate("2017-01-01", "2018-01-01") 
```

| 出力結果 |
| --: |
|2017/02/11 22:13:08|
|2017/10/22 20:07:50|
|2017/07/11 19:28:48|
|2017/12/10 10:48:20|
|2017/04/13 06:45:41|

※ヘルプでは、TalendDate.getRandomDate("format date of the character string", String minDate, String maxDate)　となっていましたが、"format date of the character string"は不要です。
スキーマのパターンにて、`"yyyy/MM/dd HH:mm:ss"`を指定することで時分秒のランダム値を設定することができました。

※また、下記のように戻り値をString型に変換する方法もあります。
この場合は、スキーマのタイプは、Stringを指定します。

```
TalendDate.formatDate("yyyy/MM/dd HH:mm:ss",TalendDate.getRandomDate("2017-01-01","2019-01-01") ) 
```

| 出力結果 |
| --: |
|2018/07/25 11:45:19|
|2017/11/05 19:33:12|
|2018/01/09 10:22:45|
|2018/01/26 19:19:03|
|2017/09/23 14:17:14|


# TalendStringルーチン

- ランダム文字列を取得

関数：getAsciiRandomString(文字数)
戻り値：String
式ビルダ設定 例) 

```
TalendString.getAsciiRandomString(5) 
```

| 出力結果 |
| --: |
|BBVF4|
|PjvyB|
|dluR0|
|MowPQ|
|jTxtW|
【随時更新】Rails自体のコードリーディングを解説している記事まとめ

いいコードを読むことで実力を上げていきたいですよね。
記事を見つけられましたらコメントいただけますと嬉しいです！

# 日本語
- [ActionView を単体で使ってみる](https://blog.eiel.info/blog/2014/07/18/action-view/)
- [[Rails5] Active Support Core ExtensionsのString#pluralize](https://techracho.bpsinc.jp/hachi8833/2016_12_30/32131)
- [初心者でもカンタンにRailsの中身のコードをコードリーディングする方法](https://qiita.com/jabba/items/8a9ac664eb2a0e61e621)
- [Railsのソースコード読んでみる | Active Support instance_values編](https://blog.shitake4.tech/entry/2018/02/26/Rails%E3%81%AE%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E8%AA%AD%E3%82%93%E3%81%A7%E3%81%BF%E3%82%8B_%7C_Active_Support_instance_values%E7%B7%A8)
- [ソースコード・リーディングしよう！[GemJam][ActiveSupport]](https://morizyun.github.io/blog/library-source-code-reading-acctive-support/index.html)
- @k0kubun さんの [Railsのredirect_toがurl_forを呼ぶまで](https://qiita.com/k0kubun/items/62f778ab555df434c13d)
- [[コードリーディング] link_toの:methodと:confirmの挙動](https://qiita.com/shohei1913/items/c01b8acf93837ca9a927)

# 英語
- 今後追加予定
React Native, Expo, Jest, TypeScript 的設定 （筆記）

！這是一篇可以快速配置環境的筆記，不會有詳細解說！

## 安裝各種需要的 packages

安裝和 React Native, Jest, Expo, TypeScript 定義檔 所有相關的玩意：

``` sh
yarn add -D jest jest-expo ts-jest react-test-renderer @types/jest @types/react-test-renderer
```

## Jest 的設定

在 `package.json` 檔案中，設定 "jest" 項下的各種參數

``` json
{
  "... 省略 ...",

  "jest": {
    "preset": "jest-expo",
    "transform": {
      "^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
      "^.+\\.tsx?$": "ts-jest"
    },
    "testMatch": [
      "**/__tests__/**/*.ts?(x)",
      "**/?(*.)+(spec|test).ts?(x)"
    ],
    "moduleFileExtensions": [
      "js",
      "ts",
      "tsx"
    ],
    "globals": {
      "ts-jest": {
        "tsConfig": {
          "jsx": "react"
        }
      }
    }
  },

  "... 省略 ..."
}
```

### 追加自定義 script

一樣是在 `package.json` 中， `scripts` 段加入這些：

``` json
{
  "... 省略 ...",

  "scripts": {
    "... 省略 ...",

    "lint:fix": "eslint --fix '*/**/*.{js,ts,tsx}'",
    "test": "yarn lint:fix && yarn tsc-test && yarn jest",
    "tsc-test": "tsc --project . --noEmit",
    "jest": "jest",

    "... 省略 ...",
  },

  "... 省略 ..."
}
```

### 執行測試

``` sh
yarn test
```

即可

## 參考資料


- [Creating a Minimal Expo React Native Project with TypeScript and Jest](https://levelup.gitconnected.com/creating-a-minimal-expo-react-native-project-with-typescript-and-jest-5979ab8d7c15)
- [Expo 官方 - Testing with Jest](https://docs.expo.io/versions/latest/guides/testing-with-jest/)
ExcelVBAでマクロが書かれているシートを読み込む方法

##手順
1. [変数を定義](#jump2)
2. [1で定義した変数に値を格納する](#jump3)

<a id="jump2"></a>
<a href="#jump2"><h2>1.変数を定義</h2></a>

##Dim <変数名> As <型>

```vb
' 変数定義
Dim wb_mybook As Workbook
Dim wb_mysheet As Worksheet
```

※変数名はお好きなもので構いませんが、
他の人が見ても分かりやすい名前だと、あとで修正しやすいです。

まずオブジェクトである、ワークブックとワークシートの宣言にはそれぞれ、
ワークブック型の`Workbook`とワークシート型の`WorkSheet`を使用します。
<a id="jump3"></a>
<a href="#jump3"><h2>2. 1で定義した変数に値を格納する</h2></a> 

オブジェクト型の場合は、変数名の前に**"Set"**を付ける必要があります。
オブジェクト型かどうかの見分け方については、下記リンクがオススメです。
[→Set の要否を見分ける方法]
(http://neos21.hatenablog.com/entry/2016/04/01/000000) 

##Set <変数> = <オブジェクト>##
```vb
'マクロワークブックセット
Set wb_mybook = ThisWorkbook --- 1 
Set wb_mysheet = wb_mybook.Sheet(シート名)--- 2
```
---1--- 
`ThisWorkbook`は、
マクロが書かれているExcelのブックを指します。

---2--- 
`.`を使うことによって、
〇〇**.**△△ → 〇〇**の**△△という風に、つなげることができます。

`wb_mybook.Sheet(シート名)`
→wb_mybook(ThisWorkbook) **の** "(シート名)" という名前の Sheet
という風に宣言することができます。

ここまで出来たら次は、指定のブックのファイルを
読み込むマクロを付け足していきます。
グラフと走査

# 二分木
- 木構造は、再帰的なデータ構造の典型例
- 各頂点の子の数が高々2であるような順序木
- 走査
    - `PreOrder`
    - `InOrder`
    - `PostOrder`

```go
package main

import "fmt"

type Node struct {
	val string
	left, right *Node
}

func (n *Node) PreOrder() {
	if n != nil {
		fmt.Println("val: ", n.val)
		n.left.PreOrder()
		n.right.PreOrder()
	}
}

func (n *Node) InOrder() {
	if n != nil {
		n.left.InOrder()
		fmt.Println("val: ", n.val)
		n.right.InOrder()
	}
}

func (n *Node) PostOrder() {
	if n != nil {
		n.left.PostOrder()
		n.right.PostOrder()
		fmt.Println("val: ", n.val)
	}
}

type BinaryTree struct {
	root *Node
}

func NewNode(val string) *Node {
	return &Node{val: val, left: nil, right: nil}
}

func NewBinaryTree() *BinaryTree {
	return &BinaryTree{root: nil}
}

func main() {
	b := NewBinaryTree()
	b.root = NewNode("*")
	b.root.left = NewNode("+")
	b.root.right = NewNode("-")
	b.root.left.left = NewNode("a")
	b.root.left.right = NewNode("b")
	b.root.right.left = NewNode("c")
	b.root.right.right = NewNode("/")
	b.root.right.right.left = NewNode("d")
	b.root.right.right.right = NewNode("e")
	fmt.Println("PreOrder")
	b.root.PreOrder()
	fmt.Println()

	fmt.Println("InOrder")
	b.root.InOrder()
	fmt.Println()

	fmt.Println("PostOrder")
	b.root.PostOrder()
	fmt.Println()
}
```
ファイルのパスを調べる方法


例えば、"読み込むbook1.xlsx" のパスを調べるときは、
ファイル名(読み込むbook1)を右クリック→プロパティで確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433296/2ad58d7d-5ce8-e363-ef25-ef87309fbc2c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433296/5bfd5410-7b64-38a0-235f-0a7ef7aefc5b.png)
"読み込むbook1.xlsx"
"読み込むbook2.xlsx"
達は、C:\aaa\bbb\Desktop\sample_file の中に入っています。

よって、
**C:\aaa\bbb\Desktop\sample_file\読み込むbook1.xlsx**
が読み込むbook1.xlsxのパスとなります。
抽象クラスとインタフェースの違いを理解しよう！

# 抽象クラスとインタフェースの違いを理解しよう！

きっと良く使う奴らが、いざ使おうとすれば、忘れてしまって困る時がある。
今回は、抽象クラスとインタフェースの違いを理解しましょう。

## 抽象クラス???

まず、抽象クラス(abstract class)は何ものから始めます。
抽象クラスは、簡単に言うと、【未完成のクラス】です。
→ 【未完成のMethod】を持っています。

抽象クラスは、
一人では、Classの役割を果たしませんが、
新しいClassを作成するため、Basic Classとなる親クラス(Super Class)として重要な意味を持っています。

一つの例を、準備しました。
図形の広さは求める例です。
Shapeという抽象クラスは、【図形の広さを求める】という抽象的な機能のみを定義します。
以後、サブクラスはどのように実装するかを定義します。

```java
abstract class Shape {         
   abstract void draw(double a, double b);
}
class Circle extends Shape {
   void draw(double r1, double r2) {
      System.out.println("Circle : " + (3.14 * r1 * r2));
}
class Rectangle extends Shape {
   void draw(double h, double v) {
      System.out.println("Rectangle  : " + (h * v));
}
class Triangle extends Shape {
   void draw(double a, double h) {
      System.out.println("Triangle  : " + (a * h / 2));
}
public class AbstractTest 
{
   public static void main(String args[]) {
      Circle c = new Circle();
      c.draw(5.0, 5.0);

      Rectangle r = new Rectangle();
      r.draw(5.0, 10.0); 

      Triangle t = new Triangle();
      t.draw(5.0, 10.0);  

      Shape s = new Circle();
      s.draw(5.0, 5.0);  
   }
}
```

## インタフェース???

インタフェースは、抽象クラスの友達です。
一種の抽象クラスですが、抽象クラスよりもっと抽象的です。
クラスでインタフェースを使用するためにimplementsを使います。

また、面倒くさいですが、インタフェースには色んな制約があります。
- すべてのメンバ変数は、public static finalでなければならない。(省略できる)
- すべてのメソッドは、public abstractでなければならない。(省略できる)

```java:TV.java
public interface TV{
   public int MAX_VOLUME = 100;
   public int MIN_VOLUME = 0;

   public void turnOn();
   public void turnOff();
   public void changeVolume(int volume);
   public void changeChannel(int channel);
}
```
TV.javaを作りました。
抽象メソッドと定数を定義することができます。

```java:LedTV.java
public class LedTV implements TV
{
    public void on(){
        System.out.println("TV ON");
    }
    public void off(){
        System.out.println("TV OFF");   
    }
    public void volume(int value){
        System.out.println(value + "volume Setting.");  
    }
    public void channel(int number){
        System.out.println(number + "channel Setting.");         
    }
}
```

```java:Test.java
public class Test{
    public static void main(String args[]){
        TV tv = new LedTV();
        tv.on();
        tv.volume(50);
        tv.channel(6);
        tv.off();
    }
}
```

もしTVインタフェースを実装するLcdTVを作成した場合には、
new LedTV部分だけnew LcdTVに変更しても、同じようにプログラムが動作できます。


## 抽象クラスとインタフェースの共通点

- 抽象クラスとインタフェースは、宣言だけあって実装内容がない。
- 自分自身がnewを使用してオブジェクトを生成することができず、継承された子だけがオブジェクトを生成することができる。
- 継承されたクラスが実装を必ずするようにすべきときに使用する。

## 抽象クラスとインタフェースの違い

| インタフェース       |       抽象クラス  |
|:---------------------:|:-------------------------:|
| 実装オブジェクトに同じ動作を保証するため|機能を利用して、拡張させるため|
| 多重継承が可能|多重継承は不可能|
| 抽象メソッドのみ可能|一般メソッド+抽象メソッド可能|
CloudFormation (公開S3バケット)

## 概要
CloudFormationに慣れるため、静的なファイルを外部公開するS3バケットを自動作成してみる。

## 前提条件
* macOS
* Docker Toolbox ( Docker for mac )

## ファイル構成
下記のようなファイルを作成します。

```:ファイル構成
opt
　├ docker
　│　└ aws-cli
　│　   └ Dockerfile
　├ src
　│  └ template.yml
　│
　└ docker-compose.yml
```

## Dockerfile作成
aws-cliコマンドが使えるコンテナを構築するファイルです。

```Dockerfile:docker/aws-cli/Dockerfile
FROM python:3.6

ARG pip_installer="https://bootstrap.pypa.io/get-pip.py"
ARG awscli_version="1.16.168"

# install aws-cli
RUN pip install awscli==${awscli_version}

# install sam
RUN pip install --user --upgrade aws-sam-cli
ENV PATH $PATH:/root/.local/bin

# install command.
RUN apt-get update && apt-get install -y less vim

# copy source code.
COPY ./src /src

WORKDIR /root
```

## docker-compose.yml作成
下記の内容で作成します。

```yaml:docker-compose.yml
version: '3'
services:
  aws-cli:
    container_name: 'aws-cli'
    image: aws-s3/aws-cli
    build:
      context: ./
      dockerfile: ./docker/aws-cli/Dockerfile
    tty: true
    environment:
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
      AWS_DEFAULT_REGION: ap-northeast-1
      AWS_DEFAULT_OUTPUT: json
```

## template.yml作成
CloudFormationの設定ファイルを作成します。
※ 「 ＜image-bucket＞ 」には、自分の作りたいS3バケット名を記載ください。

```yaml:src/template.yml
AWSTemplateFormatVersion: 2010-09-09
Description: "create public s3 bucket."
Resources:

  # S3Bucket作成
  ImageBucket:
    Type: "AWS::S3::Bucket"
    DeletionPolicy: "Retain"
    Properties:
      AccessControl: "PublicRead"
      BucketName: !Sub <image-bucket>

  # S3Bucketのポリシーを定義する
  ImageBucketPolicy:
    Type: "AWS::S3::BucketPolicy"
    Properties:
      Bucket: !Sub ${ImageBucket}
      PolicyDocument:
        Statement:
          - Action:
              - s3:GetObject
            Effect: "Allow"
            Principal: "*"
            Resource: !Sub arn:aws:s3:::${ImageBucket}/*

Outputs:
  ImageBucket:
    Value: !Ref ImageBucket
    Export:
      Name: !Sub "${AWS::StackName}-ImageBucket"
```

## サーバ構築
下記コマンドにてdockerコンテナのイメージを構築します。

```bash:ターミナル
$ docker-compose build
```

## AWSの環境設定
下記のように環境変数を定義します。
※ ここで定義した環境変数は、自動的にdockerコンテナに取り込まれます

```bash:ターミナル
$ export AWS_ACCESS_KEY_ID='xxxxxxxxxxxxx'
$ export AWS_SECRET_ACCESS_KEY='xxxxxxxxxxxxxxxxxx'
```

## CloudFormation実行
下記コマンドにて実行し、S3バケットとそのS3バケットのバケットポリシーを自動作成します。

```bash:ターミナル
# aws-cliコンテナ起動＆接続
$ docker-compose run --rm aws-cli bash

# aws-cliコンテナ内でcloudformationのデプロイを実行する
$ aws cloudformation deploy \
        --template-file /src/template.yml \
        --stack-name "{ここにスタック名を入力する}"

$ exit  <- aws-cliコンテナの接続解除 (コンテナも破棄されます)
```

以上
aws-cliコマンドが使えるコンテナを作る

## 概要
aws-cliコマンドが使えるコンテナを用意してみる。

## 前提条件
* macOS
* Docker Toolbox ( Docker for mac )

## ファイル構成
下記のようなファイルを作成します。

```:ファイル構成
opt
　├ docker
　│　└ aws-cli
　│　   └ Dockerfile
　└ docker-compose.yml
```

## Dockerfile作成
aws-cliコマンドが使えるコンテナを構築するファイルです。

```Dockerfile:docker/aws-cli/Dockerfile
# AWS ドキュメント - AWS CLI のインストール
# https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html

FROM python:3.6

ARG pip_installer="https://bootstrap.pypa.io/get-pip.py"
ARG awscli_version="1.16.236"

# create local bin directory
RUN mkdir -p /root/.local/bin
ENV PATH $PATH:/root/.local/bin

# install aws-cli
RUN pip install --user --upgrade awscli==${awscli_version}

# install sam
RUN pip install --user --upgrade aws-sam-cli

# install command.
RUN apt-get update && apt-get install -y less vim

WORKDIR /root
```

## docker-compose.yml作成
下記の内容で作成します。

```yaml:docker-compose.yml
version: '3'
services:
  aws-cli:
    container_name: 'aws-cli'
    image: aws-s3/aws-cli
    build:
      context: ./
      dockerfile: ./docker/aws-cli/Dockerfile
    tty: true
    environment:
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
      AWS_DEFAULT_REGION: ap-northeast-1
      AWS_DEFAULT_OUTPUT: json
```

## サーバ構築
下記コマンドにてdockerコンテナのイメージを構築します。

```bash:ターミナル
$ docker-compose build
```

## AWSの環境設定
下記のように環境変数を定義します。
※ ここで定義した環境変数は、自動的にdockerコンテナに取り込まれます

```bash:ターミナル
$ export AWS_ACCESS_KEY_ID='xxxxxxxxxxxxx'
$ export AWS_SECRET_ACCESS_KEY='xxxxxxxxxxxxxxxxxx'
```

## awsコマンド実行
下記コマンドにて実行し、aws-cliコンテナに接続して利用します。
※ exitしたらコンテナは、破棄される作りとなっています。

```bash:ターミナル
# aws-cliコンテナ起動＆接続
$ docker-compose run --rm aws-cli bash
$ aws --version
```

exitしてもaws-cliコンテナを破棄したくない場合は、下記のコマンドで実行します。

```bash:ターミナル
# コンテナをデーモン起動
$ docker-compose up -d

# aws-cliコンテナへ接続
$ docker-compose exec aws-cli bash
  ...
$ exit    <- aws-cliの接続を解除してもコンテナは起動したままです
```

以上
待ち行列

# 待ち行列
- Last In, Last Out

# リストで待ち行列を表現する

```go
package main

import "fmt"

type Cell struct {
	val int
	next *Cell
}

type Queue struct {
	head *Cell
	tail *Cell
}

func (q *Queue) Clear() {
	q.head = nil
	q.tail = nil
}

func (q *Queue) Enter(val int) {
	fmt.Println("<< Enter: ", val)
	c := NewCell(val)
	if q.head == nil && q.tail == nil {
		q.head = c
		q.tail = c
		return
	}
	q.tail.next = c
	q.tail = c
}

func (q *Queue) Remove() int {
	if q.head == q.tail {
		ret := q.tail.val
		q.head = nil
		q.tail = nil
		return ret
	}
	ret := q.head.val
	q.head = q.head.next
	return ret
}

func (q *Queue) IsEmpty() bool {
	return q.head == nil && q.tail == nil
}

func NewCell(val int) *Cell {
	return &Cell{val: val, next: nil}
}

func NewQueue() *Queue {
	return &Queue{head: nil, tail: nil}
}

func main() {
	q := NewQueue()
	q.Enter(0)
	q.Enter(1)
	q.Enter(2)
	fmt.Println(">> Remove: ", q.Remove())
	fmt.Println(">> Remove: ", q.Remove())
	fmt.Println(">> Remove: ", q.Remove())
}
```

# 配列で待ち行列を表現する
- リングバッファでデータの追加にかかる計算量を減らす

```go
package main

import (
	"fmt"
	"os"
)

const SIZE = 20

type Queue struct {
	arr []int
	head, tail, count int
}

func (q *Queue) Clear() {
	q.head = 0
	q.tail = 0
	q.count = 0
}

func (q *Queue) Enter(val int) {
	if q.count >= SIZE {
		fmt.Println("ERROR: no more space in queue")
		os.Exit(1)
	}
	q.arr[q.tail] = val
	q.tail += 1
	if q.tail > SIZE {
		q.tail = 1
	}
	q.count += 1
	fmt.Println("<< Enter: ", + val)
}

func (q *Queue) Remove() int {
	if q.count <= 0 {
		fmt.Println("ERROR: no element in queue")
		os.Exit(1)
	}
	ret := q.arr[q.head]
	q.head += 1
	if q.head > SIZE {
		q.head = 1
	}
	q.count -= 1
	fmt.Println(">> Remove: ", + ret)
	return ret
}

func (q *Queue) IsEmpty() bool {
	return q.count == 0
}

func NewQueue() *Queue {
	return &Queue{
		arr: make([]int, SIZE+1),
		head: 0,
		tail: 0,
		count: 0,
	}
}

func main() {
	q := NewQueue()
	q.Enter(0)
	q.Enter(1)
	q.Remove()
	q.Remove()
}
```
VS Code 1.35 の気になった変更点

[Visual Studio Code](https://code.visualstudio.com) の バージョン 1.35（2019年5月分アップデート）がリリースされたので、[リリースノート](https://code.visualstudio.com/updates/v1_35)を眺めてみて気になった変更点をチェックしてみた。(以前のバージョンを眺めてみた時のやつはこちら。[1.33](https://qiita.com/12345/items/733dd8322b0aaeddee89) / [1.32](https://qiita.com/12345/items/80ebfc7a4fb2430430e1) / [1.31](https://qiita.com/12345/items/4ba59be50c6ee9407131) / [1.30](https://qiita.com/12345/items/853b30a4769d76e64d56) / [1.29](https://qiita.com/12345/items/6993dc21f310e1b5dd99) / [1.28](https://qiita.com/12345/items/b53d93fcb225abfc702d) / [1.27](https://qiita.com/12345/items/6a3967dd424b2be57104) / [1.26](https://qiita.com/12345/items/8ce4b6e045d50a6049ce) / [1.25](https://qiita.com/12345/items/e7b5b9954f5d721be2c8) / [1.24](https://qiita.com/12345/items/935770c6a3515ca80472) / [1.23](https://qiita.com/12345/items/627298550aab19f1d8a6) / [1.22](https://qiita.com/12345/items/8253a1eee38b6741905e) / [1.21](https://qiita.com/12345/items/71ce73c52cf2232fc10c) / [1.20](https://qiita.com/12345/items/1390c7cab11d968e7691) / [1.19](https://qiita.com/12345/items/a331c014a9d3fa9dac0e) / [1.18](https://qiita.com/12345/items/9b827138b5044ca82482) / [1.17](http://qiita.com/12345/items/28d83361341ce3ff3c9c) / [1.16](http://qiita.com/12345/items/5215293977dde2149c0f) / [1.15](http://qiita.com/12345/items/cebf4b4e9bfb2d2ef771))

## VS Codeアイコンデザインの変更
https://code.visualstudio.com/updates/v1_35#_updated-visual-studio-code-icon
VS Codeのアイコンデザインが変更になった。また、これまではWindows版とLinux版/macOS版のアイコンデザインが異なっていたが、今回統一された。

安定版|インサイダー版
:-:|:-:
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181011/d6e187e8-e4f4-0173-d503-2bb4c5639ae2.png width=100>|<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181011/0ead8bbf-229b-f531-d79f-c7a2e2ebccd0.png width=100>

ちょっと柔らかい感じのデザインになった？
前回アイコンデザインが変更になったのがv1.17～1.18の時なので、１年８～９ヶ月ぶりの変更。
ちなみに前回の変更の時はデザインだけでなくベースカラーまでが一旦変更になった（[v1.17](http://qiita.com/12345/items/28d83361341ce3ff3c9c)）が、結局次のバージョンでベースカラーは元に戻された（[v1.18](https://qiita.com/12345/items/9b827138b5044ca82482)）、というドタバタがあった。

## 階層リンク（パンくずリスト）がデフォルト表示に
https://code.visualstudio.com/updates/v1_35#_breadcrumbs-displayed
[v1.26](https://qiita.com/12345/items/da13fc34e25b51de52c5)から使えるようになった階層リンク機能（いわゆるパンくずリスト）が、今までは設定で有効にしないと表示されなかったが、最初からデフォルトで表示されるようになった。

## ターミナルのプルダウンからのシェル切り替え(Windows)
https://code.visualstudio.com/updates/v1_35#_improved-surfacing-of-shell-selector-on-windows

Windowsの場合、VS Codeの統合ターミナルで使用できるシェルとしてコマンドプロンプトかPowerShellが選べ、さらにPCにbashを入れている場合はそれも選択可能となる。これらのシェルを切り替えたい場合は設定を変更する必要があるが、ターミナルのプルダウンからこのシェル切り替えが行えるようになった。やっていることは単にコマンド（`規定のシェルの選択`）を呼び出しているだけだが、このほうが直感的にわかりやすい。

![change_term.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181011/506801cc-f432-a7ba-6bc0-e7478cee196c.gif)

ただ、このコマンドは、設定`terminal.integrated.shell.windows`の値を書き換えているだけなので、起動時の引数の設定`terminal.integrated.shellArgs.windows`までは書き換わらない。なので例えばbash用に指定した引数がPowerShellに切り替えようとした際にエラーになってPowerShellが起動できない、ということも起こり得るので引数を指定する場合は注意が必要。
EC2のユーザーデータでLinuxのホスト名を変更する方法


#ユーザーデータ
ユーザーデータのcloud-initディレクティブで、fqdnキーを利用します。
ホスト名を変えるだけなら、これだけです。

```yaml:user-data.yaml
#cloud-config

fqdn: example.co.jp
```

**※ホスト名を設定するキーにはhostnameキーも存在します。
しかし、hostnameキーは、fqdnキーが利用される場合は無視されます。
AWSデフォルトのホスト名はfqdnキーで定義されているため、上書きするためにはfqdnキーを利用する必要があります。**

# ユーザーデータを入力する方法１：GUI

[インスタンスの作成]＞[手順3：インスタンスの詳細設定]の[ユーザーデータ]に張り付けて
インスタンスを作成するだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218139/5f7976b3-c053-402b-6550-d75089419e88.png)

# ユーザーデータを入力する方法２：AWS CLI

--user-dataオプションで、生のテキストファイルを渡します。yamlとしてますが、拡張子は何でもOKです。

```bash
aws ec2 run-instances --region $Region \
  --image-id $AmiId --count 1 \
  --instance-type $InstanceType --key-name $KeyName \
  --subnet-id $SubnetId --private-ip-address $PrivateIpAddress \
  --associate-public-ip-address \
  --security-group-ids $SecurityGroupIds \
  --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=$NameTag}]" \
  --credit-specification CpuCredits=standard \
  --user-data file://userdata.yml
```

※変数の値は適宜設定してください。Powershellで実行する場合は、改行文字を「\」から「`」に変更してください。

# 補足：作成したAMIから起動すると、ホスト名が初期化される問題

既定の動作として、cloud-initでホスト名、ロケール、デフォルトユーザーが初期化されます。
シンプルにこれを防ぐのであれば、ユーザーデータでpreserve_hostnameキーをtrueに設定しておきます。

```yaml:user-data.yaml
#cloud-config

fqdn: example.co.jp

runcmd:
 - echo "preserve_hostname: true" >> /etc/cloud/cloud.cfg
```

※preserve_hostnameキーがtrueに設定されていると、hostnameキー・fqdnキーは機能しません。


以上です。
Raspberry Pi 3 Model B+ に Debian buster (arm64)をインストール

### 概要
- debian busterのイメージをmacOS MojaveでSSDへ書き込む
- debian image(arm64)
  https://people.debian.org/~gwolf/raspberrypi3/20190628/20190628_raspberry-pi-3_buster_PREVIEW.img.xz

---

### 手順
1. イメージは "etcher" で書き込み
  https://www.balena.io/etcher/

2. イメージを書き込んだSSDをraspberry piに接続して起動するだけ

3. root の初期パスワードは、“raspberry”でログインできる

----

### raspberry pi の debian 起動後の設定

- rootパスワード変更

    ```
    # passwd
    ```

- network設定

    ```
    # vi /etc/network/interfaces.d/eth0
    auto eth0
    iface eth0 inet static
        address 192.168.1.XX
        netmask 255.255.255.0
        gateway 192.168.1.XX
        dns-nameservers 192.168.1.XX 8.8.8.8

    # systemctl restart networking
    ```

- 時刻同期(systemd-timesyncd)

    ```
    # vi /etc/systemd/timesyncd.conf
    [Time]
    NTP=ntp.nict.jp
    FallbackNTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org
    # systemctl daemon-reload
    # systemctl restart systemd-timesyncd
    ```

- タイムゾーンの設定

    ```
    # timedatectl list-timezones | grep -i tokyo
    Asia/Tokyo

    # timedatectl set-timezone Asia/Tokyo
    # timedatectl                        
                Local time: Sat 2019-06-29 22:59:37 JST
            Universal time: Sat 2019-06-29 13:59:37 UTC
                    RTC time: n/a
                    Time zone: Asia/Tokyo (JST, +0900)
    System clock synchronized: yes
                NTP service: active
            RTC in local TZ: no
    ```

- パッケージ最新化

    ```
    # cat /etc/apt/sources.list
    deb http://deb.debian.org/debian buster main contrib non-free
    # apt-get update
    # apt-get upgrade
    ```
【Swift】初心者でも絶対にできる"Hello World" iOS アプリを作成 ~iOS アプリ開発超入門~

# 1.はじめに
## この記事で学べること
- iOSアプリの開発プロジェクトの作成方法

## この記事で紹介しないこと
- Xcodeのインストール方法

## 完成形
<img width="374" alt="スクリーンショット 2019-06-29 23.17.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/385cb105-ad94-d27b-dae0-e9b0af955f5b.png">

# 2.プロジェクト作成
Xcodeを開きます。
「Create a new project」を選択
<img width="502" alt="スクリーンショット 2019-06-29 23.10.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/b1503dae-690b-8424-70aa-da5b478d8b03.png">

「Single View App」を選択して、「Next」を選択
<img width="732" alt="スクリーンショット 2019-06-29 23.12.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/49e67904-0733-14c1-3bdb-b1d7a341b068.png">

「Product Name」を入力してください。
入力完了後、「Next」 を選択
<img width="729" alt="スクリーンショット 2019-06-29 23.12.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/db347640-7366-ccc9-d1ad-a0dd033163f0.png">

これで、一旦、プロジェクトの作成が完了です。

# 3. 「Hello Worldの出力」
「Main.storyboard」を選択した、インタフェースの編集画面を開きます。
<img width="1400" alt="スクリーンショット 2019-06-29 23.14.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/626c4395-73e9-e503-7cd6-38427531f25a.png">

画面右上の赤枠箇所を選択して、UIのウィンドウを開きます。
<img width="1393" alt="スクリーンショット 2019-06-29 23.15.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/ce24ba69-2469-2fa4-baf4-d629010aa33c.png">

検索ボックスに「Label」と入力します。
検索結果のLabelをウィンドウから、画面上のiPhoneにドラッグ&ドロップをする。

<img width="1399" alt="スクリーンショット 2019-06-29 23.16.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/a8da0160-da5e-8c16-8358-21b1e83dd72a.png">

Labelを選択します。
右側のウィンドウの指定箇所を選択すると、選択したUI部品の編集ウィンドウが表示されます。
「Hello World!」を入力してください。
最後に左上の再生ボタンを選択してください。
<img width="1395" alt="スクリーンショット 2019-06-29 23.17.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/b890ae86-483b-ced7-4934-95214caa2f57.png">

シミュレータが起動し、「Hello World!」が出力されているでしょうか？
<img width="374" alt="スクリーンショット 2019-06-29 23.17.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/385cb105-ad94-d27b-dae0-e9b0af955f5b.png">

これで、一応「Hello World」アプリの作成完了です！！
Macの英字キーボードを使うときは入力方式は二つに絞ろう

## Macの英字キーボードを使うときは入力方式は二つに絞ろう
デフォルトの設定のままだと、RomajiやKatakanaが選択されてしまい不便になるときがあります。ABCとHiraganaの2つだけにしておいた方が便利です。

以下のようにKeyboardの設定画面を開き、KatakanaとRomajiのチェックは外しておくことをお勧めします。
<img width="657" alt="Screen Shot 2019-06-29 at 23.37.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250231/d5f6a25a-626e-0374-35d6-2a819b1e63c1.png">

この記事参考になれば幸いです。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
Ubuntu-18.04 new installerでbtrfsを使う際のサブボリューム構成の違いと修正

Ubuntu 18.04以降の新しいインストーラはbtrfsなルートパーティションの扱いが変わっている。
ハマりたくなければおとなしくalt imageの旧インストーラを使ったほうがいい。

### Ubuntu 旧インストーラでの挙動
旧インストーラ（名前はdebian installerで良いのだろうか？）でルートパーティションにbtrfsを指定すると、自動的にサブボリュームが作成され、ルート`/`とホーム`/home`にマウントされる。

たとえば、

```
/dev/mapper/vg-root /     defaults,subvol=@ 0 0
/dev/mapper/vg-root /home defaults,subvol=@home 0 0
```

これはbtrfsでは順当な構成。（@homeは要らない人も多いだろうが）

### Ubuntu 新インストーラでの挙動
サブボリュームが作成されず、そのままルートボリュームがマウントされる。

（ついでに`/boot`を`/`やLVMの中に置くことができず、`/boot`は通常のパーティションにext4などで作ることを強制される）

### 何が問題か？

btrfsのルートボリュームはサブボリュームと扱いが異なり、削除や移動ができない。
特に、ルートボリュームのスナップショットをサブボリュームとして作成することはできても、作成したサブボリュームでルートボリュームを差し替えることができない。

つまり、ルートパーティションとしてbtrfsのルートボリュームをそのままマウントしてしまうと、ロールバックができない。

一方サブボリュームならリネームができるので、ルートパーティションやinitramfsを壊してしまっても最悪古いスナップショットをRWにして置き換えるだけで最低限の復旧ができる。（配下のサブボリュームは作り直すか、同形になるようにスナップショットを作り直す必要があるが）

他にも、作成したサブボリュームはすべてルートボリューム配下、つまり`/`以下に見えてしまうのでapparmorなどのアクセス制御上の扱いが面倒になる。

## 修復

ルートパーティションの差し替えを行う。これはbtrfsに限らず通常の運用と同じ。

ルートボリュームのスナップショットは作れるので、

```
mkdir /mnt/chroot
sync
btrfs subvolume snapshot / /@
mount /dev/vda2 /mnt/chroot -o subvol=@

mount --bind /dev /mnt/chroot/dev
... 他sys/dev/procなど繰り返し

chroot /mnt/chroot
vi /etc/fstab  (subvol=@を追加)
update-initramfs -u -k all
update-grub
```

で行けるはず。

あとは忘れずルートボリュームをマウントしてサブボリューム以外を削除。
(Win10) Gitのssh_configへのシンボリックリンクを.ssh/configとして作成するスクリプト（備忘録）

## Gitのssh_configへのシンボリックリンクを.ssh/configとして作成する

「windowsのgitのssh_configを設定する(cmder」
https://qiita.com/fagai/items/5b74ef4cf6b497f54312
を参考に自分の場合、mklinkコマンドが少し違ったため備忘録として

```
mklink C:\Users\ユーザー名\.ssh\config "C:\Program Files\Git\etc\ssh\ssh_config"
```
これで、シンボリックリンクが作成できました。
elasticsearch-modelのimportメソッドのtransformパラメータは結構使える子

仕事で検索機能の改善をやってたときのメモを、秘匿事項を含まない部分だけ公開しとこうかなと思う。

## `Hoge.__elasticsearch__.import` の定義

https://github.com/elastic/elasticsearch-rails/blob/master/elasticsearch-model/lib/elasticsearch/model/importing.rb

ポイントとしては

```elasticsearch-model/lib/elasticsearch/model/importing.rb
          __find_in_batches(options) do |batch|
            response = client.bulk \
                         index:   target_index,
                         type:    target_type,
                         body:    __batch_to_bulk(batch, transform)

            yield response if block_given?

            errors +=  response['items'].select { |k, v| k.values.first['error'] }
          end
```

内部で、find_in_batchを使って1000件ずつ、Elastcsearchの[bulk API](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html)を使ってデータを一括投入するというスグレモノ。
（余談だが、find_in_batchesのデフォルトが1000なのは、Elasticsearch-modelではなくActiveRecord側の定義。 https://github.com/rails/rails/blob/6-0-stable/activerecord/lib/active_record/relation/batches.rb#L126 ）

### bulk insertだけじゃなくてupdate, deleteもできる

Elasticsearchのbulk APIは、たとえば

```
[
  { delete: { id: 123} },
  { index: { id: 124, data: { title: elasticsearch-modelが便利, ......... } } },
  { delete: { id: 125 } }
]
```

のようなペイロードを指定すると、

* 123, 125はインデックスされていたら削除する(delete if exists)
* 124は、まだインデックスされていなかったらインデックスする（insert or update）

といった複雑なこともできる。

先に書いたimportメソッドの中で、bulk APIに渡されているペイロードは `body:    __batch_to_bulk(batch, transform)` で、その定義を更に見ると

```rb:__batch_to_bulk
        def __batch_to_bulk(batch, transform)
          batch.map { |model| transform.call(model) }
        end
```

transformっていうのをmodelに適用したもののリストが渡されるようだ。


このtransformは、デフォルトだと
https://github.com/elastic/elasticsearch-rails/blob/v6.0.0/elasticsearch-model/lib/elasticsearch/model/adapters/active_record.rb#L114
に定義があるように

```rb:__transform
          def __transform
            lambda { |model|  { index: { _id: model.id, data: model.__elasticsearch__.as_indexed_json } } }
          end
```

モデルをそのままinsert or updateするような変換になっている。

たとえば、下書きと公開後でモデルを分けていないようなArticleみたいなモデルがあると、この変換は結構使えて、

```rb:公開済みと下書きを分けてimportする
# 公開済みの記事はインデックスする
Article.__elasticsearch__.import(scope: :published)

# 下書き状態のもの、公開後に下書きに戻されたものは、インデックスがある場合には削除する
Article.__elasticsearch__.import(
  scope: :draft,
  transform: ->(model) {
    { delete: { _id: model.id } }
  }
)
```

のようにtransform指定することで、公開済みのものだけを選択的にElasticsearch側に同期することができる。

あるいは、（可読性とのバランス次第だけど）

```rb:公開済みと下書きを分けてimportする②

Article.__elasticsearch__.import(
  transform: lambda do |article|
    if article.published?
      { index: { _id: article.id, data: article.__elasticsearch__.as_indexed_json } }
    else
      { delete: { _id: article.id } }
    end
  end
)
```

のようにすればbulk APIを叩く回数自体を減らすこともできそう。

　

そもそも、[Webサービス(Rails)＋スマホアプリを作るときにやってはいけないこと 2018年版](http://yusukeiwaki.hatenablog.com/entry/2018/08/17/Rails%E3%81%A7Web%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%EF%BC%8B%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%AB%E3%82%84%E3%81%A3%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91_1)でも書いたんだけど、モデル分けようね！って話なんだけどさ... :sweat_smile: 歴史的な経緯とかもろもろでそうはいかないときには、transformパラメータはかなり使える子だと思う。