OmniAICreator/Qiita-1.07M huggingface dataset:
Windows Server 2016 Hyper-Vでできること

## はじめに
Windows Server2016上のHyper-Vをホストにしての運用サーバーを構築する際に地味に勉強になったことをメモメモ。


## 運用チェックポイント
実環境ではサーバーのバックアップ時にアプリに影響を与えられません。既存の標準チェックポイントには以下の問題があり、実環境では滅多に使われないものでした。

#### データ消失の可能性（Hyper-Vのバグ）

今まではアプリケーションでスナップショットが把握できなかったため、いざスナップショットで復旧した時に問題がよく起こっていたそうです。そこで、メモリの情報を取得せずディスクの状況のみをVolume Shadow Copy（VSS）の仕組みで取得することで整合性が保証されるようになりました。要はただのバックアップらしいです（2016年のde:codeでそう言ってました）。

#### 標準チェックポイントと運用チェックポイント

上記の通り、メモリの情報を取得しないためOS起動中にチェックポイントをとり、そのチェックポイントを適用するとシャットダウンされた状態で回復されます。データの整合性をそこまで気にしないなら、既存の標準チェックポイントの方が良さそうですね。

## ReFSによるVHDXファイル操作の高速化
- 仮想ハードディクスの作成の高速化に対応。
- 仮想ハードディスクのマージ（差分ディスクのマージやチェックポイントの削除を含む）の高速化に対応。

#### どんな時に使うべき？
Storage Spaces Directを利用している場合に、データ破壊を防いでくれるので使うべきとのこと。

#### メリットとデメリット
Hyper-Vのデプロイを高速化したい場合やReFSの回復力(resiliency)の強さからVHDXのバックアップを保存するうえでメリットとなる。ただし、ReFSはWindows Server2016の新機能であるディスクの重複排除には対応していないので注意が必要。

## Hyper-Vマネージャからの別の資格情報によるリモート接続
[このリンク](http://www.vwnet.jp/windows/WS16TP2/HVMan/Credential.htm)を手順通りに進めると、別のマシンのHyper-Vサーバーにつなぐことができるようになりました。

## 参考
de:codeの発表から

- https://channel9.msdn.com/Events/de-code/2016/INF-016

チェックポイントのデメリットに関して

- http://hyper-v-backup.backupchain.com/11-things-to-know-about-hyper-v-snapshots-checkpoints/

ReFSとStorage Spaces Directについて

- https://docs.microsoft.com/en-us/windows-server/storage/storage-spaces/plan-volumes

Windows Server 2016でのReFSの利用

- https://www.itprotoday.com/windows-8/when-use-refs-windows-server-2016
- https://www.virtualizationhowto.com/2017/05/when-to-use-windows-server-2016-refs/
blender学習その②

今日はインターフェースのプリセット切り替えができるようになった。

Fire > Use Preferences...から
![2018-12-29_23h18_37.png](https://qiita-image-store.s3.amazonaws.com/0/184524/5acca778-fdba-5c04-4693-0ae114726eeb.png)

ドン！
![2018-12-29_23h18_53.png](https://qiita-image-store.s3.amazonaws.com/0/184524/6fa9a569-ee13-e06d-106b-21ebf72e37b2.png)


色々と豊富ですね～。

あとカットツール
Tabキーで編集モードとか・・SIかよってなったよね。
んでもって　Kキーで呼ぶんですね。

![2018-12-29_23h57_54.png](https://qiita-image-store.s3.amazonaws.com/0/184524/34c070c7-38dd-1006-c2f0-e62f164c8671.png)
Homebrewでbrew doctorしたらWarning: "config" scripts exist outside your system or Homebrew directories.となった時の解決方法


#はじめに
```brew doctor```したらWarning（警告）が出たので、その解決方法をまとめました。

#Warningの内容
内容としてはHomebrewの管理外なconfigファイル（コンピューター上で動作するプログラム）があると衝突おこすかもよというものです。

```
Warning: "config" scripts exist outside your system or Homebrew directories.
`./configure` scripts often look for *-config scripts to determine if
software packages are installed, and what additional flags to use when
compiling and linking.
Having additional scripts in your path can confuse software installed via
Homebrew if the config script overrides a system or Homebrew provided
script of the same name. We found the following "config" scripts:
  /Users/Username/anaconda3/bin/icu-config
  /Users/Username/anaconda3/bin/freetype-config
  /Users/Username/anaconda3/bin/xslt-config
  /Users/Username/anaconda3/bin/libpng16-config
  /Users/Username/anaconda3/bin/python3.6m-config
  /Users/Username/anaconda3/bin/libpng-config
  /Users/Username/anaconda3/bin/xml2-config
  /Users/Username/anaconda3/bin/python3-config
  /Users/Username/anaconda3/bin/curl-config
  /Users/Username/anaconda3/bin/ncursesw6-config
```

#原因
どうやら、AnacondaとHomebrewは相性が悪く、お互い干渉する様です。
（Anacondaは、かなり前にpython環境を構築しようと思ってインストールしていたものです）

#解決方法
結論としては、Anacondaをアンインストールする事です。
手順は[こちら](https://qiita.com/hanio820/items/210d297493ff176d31fe)。

#対応後
brew doctorを実行して、

```
$ brew doctor
Your system is ready to brew.
```


と表示されれば、解決です。
vscodeとgithubとの連携

gitとは今時のファイルバージョン管理システムである。詳しい仕組みは以下参照

[サルでもわかるGit入門 〜バージョン管理を使いこなそう〜 | どこでもプロジェクト管理バックログ](https://backlog.com/ja/git-tutorial/)

gitとはファイルバージョン管理システムの名称であり、gitの仕組みを利用したファイルバージョン管理サービスが世の中に多数ある。今回はその中でも最大手であり我らがマイクロソフト様が買収したgithubを使ってリポジトリを管理していく。

### リポジトリへのUP

- .gitignoreファイルの作成(※後述)
- githubにリモートリポジトリを作成
- vscode上でローカルリポジトリを作成
    - ワークスペースをローカルリポジトリとする
- ローカルリポジトリとgithub上のリポジトリを紐づけ
    - ここだけはコマンドで実施する必要がある
        - git remote add origin https://github.com/<repo owner>/<repo name>.git
- ローカルリポジトリからリモートリポジトリへのpush

基本的には1ワークスペース <-> 1リポジトリで管理するようにすることにする。もしかして1フォルダ <-> 1リポジトリの方が適切かもしれないが、今はそこまで判断できる知識がない。

### リポジトリから除外したい

特に意識せずリポジトリを作成するとワークスペースは以下のnode_modulesも管理対象となり、githubのリモートリポジトリに大容量ファイルも転送されてしまう。対策として、特定のファイル/フォルダをリポジトリの管理外とする.gitignoreを利用する。

- [Git: バージョン管理の対象から外したいファイルを「.gitignore」に記述する - すたらブログ](http://sutara79.hatenablog.com/entry/2015/07/21/115842)
- [[Git] .gitignoreの仕様詳解 - Qiita](https://qiita.com/anqooqie/items/110957797b3d5280c44f)

文字コードをUnicodeだと動作しないので注意。UTF-8などで作成する事。Unicodeなんて使わないよ、と思うかもしれないが、Windows環境ではエクスプローラーから.gitignoreファイルが作成出来ず、コマンドプロンプトからecho "test" > .gitignoreで作成したらUnicodeになってしまい、ハマってしまった。

- [.gitignore 設定が反映されない場合の対応 - だるプロ](http://darupo.hateblo.jp/entry/2014/09/10/003326)

### その他自分用メモ

GitHubにリポジトリ作ってからプッシュしようと思ってよくエラーになるので

[初めてGitHubリポジトリにpushしたらrejectedエラーになったときの対応メモ - Qiita](https://qiita.com/takanatsu/items/fc89de9bd11148da1438)
Wio LTE から SORACOM Air のメタデータサービスにアクセスするコードスニペット

SORACOM Air の回線(SIM)を管理する機能の一つに[メタデータサービス](https://dev.soracom.io/jp/start/metadata/#read_subquery)があります。

タグを設定すると SIM のメタデータとして利用ができるので、例えばデバイスの設定情報を外に追い出すような事が可能です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/22754/2ccf3fba-4c7c-9cd4-7dc7-c994aaec29c6.png)

※ AWS で言えば [Amazon EC2 のインスタンスメタデータ](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)のようなものです。

Raspberry Pi 等 OS がある場合は `curl` とかを使えば楽勝なので、ここでは [Wio LTE](https://soracom.jp/products/module/wio_lte/) という LTE モデム搭載マイコンで SORACOM Air メタデータサービスにアクセスするためのコードスニペットを紹介します。

## Wio LTE から SORACOM Air メタデータサービスを利用する

```c++:get_metadata_by()
String get_metadata_by(WioLTE &wio, const char* tag_key, const char* default_value = "") {
    char url[1024];
    sprintf(url, "http://metadata.soracom.io/v1/subscriber.tags.%s", tag_key);
    char buf[1024];
    wio.HttpGet(url, buf, sizeof(buf));
    String content = String(buf);
    content.trim();
    if (content == "Specified key does not exist." || /* == 404 */
        content == "You are not allowed to access Metadata Server.") { /* == 403 */
        content = String(default_value);
        content.trim();
    }
    return content;
}
```

`get_metadata_by()` の使い方は以下の通りです。(エラー処理などは省略してます)

```c++:WioLTE_main.ino
// Wio は Wio.Activate まで終わっているインスタンスを指定してください
String v = get_metadata_by(Wio, "your_tag_name");
```

これで `v` に `your_tag_name` で設定されたタグの値が入ります。
`get_metadata_by()` メタデータが無効になってたり、キーが見つからない場合は `""` が返りますが、これをデフォルト値にすることができるのが 第3引数です。

例えばキーが見つからない場合は SIM の IMSI を採用するという実装も可能です。

```c++
char imsi[16];
Wio.GetIMSI(imsi, sizeof(or_imsi));
String v = get_metadata_by(Wio, "your_tag_name", imsi);
```

`your_tag_name` にアクセスできなかったら `v` には IMSI が入ります。

### 解説

SORACOM Air メタデータサービスには SIM から `http://metadata.soracom.io/v1/subscriber` にアクセスすれば JSON が降ってきますが、ここで使うのは[メタデータサービスのクエリ機能](https://dev.soracom.io/jp/start/metadata/#read_subquery)です。
`/subscriber.tags.[TAG_NAME]` とすると JSON ではなく plain text が返ってきますので JSON パーサーが不要です。

### ちょっと困った話 (2018年末)

Wio LTE のライブラリ https://github.com/SeeedJP/WioLTEforArduino の `Wio#HttpGet` には HTTP リザルトコードを受け取る仕組みが無いので、現在は SORACOM Air メタデータサービスが返すbodyを見て 404 なのか 403 なのかを判定しています。

## 使い時

こういった値は `#define` されがちですが、そうなるとデバイス毎の違いが発生するため、大量のデバイスを作るのに不利です。
一方 SD カード等を使って依存性を減らすことは定番の手法だと思いますが、やはり SD カードを作る手間は変わりません。

一方 SIM は IMSI と呼ばれる一意な値を持っており、またそれは通信事業者側で識別可能です。その特性を活かして、起動時にデバイスに必要な情報を取得するという動的構成を作ることができます。

## あとがき

ライセンスは MIT です。
ライブラリ化しようとおもったけど、あまりにも限定条件であることに加え、Wio LTE ライブラリからのみの利用と汎用性も低いため、コピペ用として公開しました。

良いお年を！

Eo
Ruby 2.5.3 + Devkit Windows Installerでインストール → RubyMineで作成したRoRプロジェクトでSqlite3のエラーが発生

__Big thanks to：https://qiita.com/yoru722/items/8a633d71148de0f0ae1f__

個人ノート程度で。
プログラム設定で毎回大混乱しますが、今回のチャレンジはRuby on Rails. Ruby公式ホームページからRuby＋Devkitのインストールーー＞Ruby on Railsのインストールして、RubyMineでお試しプロジェクトを作成しました。次に `start application` (= `rails server`と同様 )を押したら・・・

> cannot load such file -- sqlite3/sqlite3_native (LoadError)

というエラーが発生。

グーグル神に相談してみたら、上のqiitaポストを発見。
どうもありがとうございます。m(_ _)m

現在（2018.12)時点では最新バージョンが変わりましたので、

```
gem uninstall -a sqlite3 
```

を実施。その後

```
gem install sqlite3 -v "=1.3.13" --platform=ruby -- --with-sqlite3-include=C:\temp\sqlite-amalgamation-3260000 --with-sqlite3-lib=C:\Ruby25-x64\bin
```
と実施します。End codeが 0で終わればOK。

>★　Ruby, SQLiteのバージョンが変わったら↓
>- "=1.3.13" ---> 自分のsqlite3のversionに変更
>
>- "=sqlite-amalgamation-3260000" ---> 自分のsqlite3(Source Code) versionに変更
>
>- "C:\temp\"、"C:\Ruby25-x64\bin" ---> 各ファイルが入っているフォルダに変更


しかし、また`start application`を押しても動かず・・・
原因は dependency fileの位置を保存するキャッシュファイルと
自動インストールされたSqlite3のgemspecファイルでした。

__解決方法__

１．｛RoRプロジェクトルートfolder}/tmp/cache/bootsnap-load-path-cacheファイルを削除
 (後で再生成されます)

２．｛Rubyインストールfolder}/lib/ruby/gems/{ruby version}]/specifications/sqlite3-1.3.13-x64-mingw32.gemspecを削除。

これで解決。
`start application`を押したら、Yay! You’re on Rails!に無事到着でした。
vscodeでのNode.js利用準備

[前回](https://prius.cc/itya/20181218_vscode-workspace)でvscodeの基本設定を理解したことにしてNode.jsを触っていく

## Windows環境でのNode.jsのインストール

ここはvscodeとは関係なく共通でやるところ。

Node.jsはjavascriptプラットフォームであり、WindowsPCには規定でインストールされていない。Windowsに規定でインストールされているのはpowershell環境だけである…。よって[Node.js](https://nodejs.org/en/)の公式からささっとインストールする。

powershellコンソールを起動し"node -v"と実行してバージョンが返ってくればOK。

## 環境設定(プロジェクト)

これからあなたはnodejsアプリケーションを開発する。ということで、それ用のフォルダを1つ用意し、そこをワークスペースとする。ワークスペースの作り方は前回のエントリの通り。

ワークスペースを作成したら、**npm init**でnodejsプロジェクトを初期化する。するとpackage.jsonが生成される。いくつか質問を投げられるが、全てEnterを押せばよい。

## npmについて

npmとはnodejsのパッケージ管理ツールである。パッケージ管理ツールとはコマンド1つで指定したパッケージをしかるべきリポジトリ(ダウンロードサイト)からダウンロードしてくれるものである(もちろん他にも機能はある)。nodejsしかりphtyonしかり、最近の言語にはパッケージ管理システムが備わっており、このやり方が現在のデファクトスタンダードである。dllやらモジュールやらを窓の杜からダウンロードするのはやめましょう。

※ なお、我らがpowershellにもPackageManagementというそのまんまの名前すぎるパッケージマネジメントシステムが存在する。

## 環境設定(ESLint)

nodejsのコーディングルールをチェックしてくれるESLintをインストールする。

### 1. vscodeに拡張インストール

vscodeで拡張名"eslint"を指定するとインストールできる。

### 2. npm install eslint でeslintをダウンロード

nodejsのパッケージの一つとして存在するeslintをダウンロード

### 3. ダウンロードしたeslint.jsを設定する。

node .\node_modules\eslint\bin\eslint.js --init

で設定が可能である。

## 環境設定(開発に利用するパッケージ)

その他、自分が開発するプログラムに必要なパッケージを

npm install [パッケージ]

でダウンロードする。ダウンロードしたパッケージはnode_modulesというフォルダに保存される。また、package.jsonにパッケージ名が追記され、このプロジェクトでどのパッケージが必要であるかが記録されるようになる。仮に何らかの要因でダウンロードしたパッケージを消去して再ダウンロードしたい場合、単純に

npm install

を実行すればよい。githubなどより他人のプロジェクトをcloneした場合、通常github上にモジュールの実体はないがpackage.jsonに必要なパッケージの記録があるため、同じくnpm installを実行して環境を整える。

また、何らかの目的で依存しているパッケージをインストールしたくない場合、

.npmrc

に記載すると、指定したパッケージがインストールされなくなる。

## デバッグ設定

vscodeではF5を押下する事でプログラムのデバッグ開始が可能である。試しに自分がプログラムを作成しF5を押下すると、フォルダのユーザーセッティング配下にlaunch.jsonが自動的に生成されてしまう。これが通常の動きかはよくわからない。とにかく、このlaunch.jsonに設定を記載する事で、デバッグ設定をカスタマイズできる。

通常、デバッグ設定をカスタマイズするニーズは少ないと思うが、デバッグ対象プログラムが複数ある場合(index.jsとapp.jsなど)、2通りの設定を記載する事で、どちらのプログラムに対してもデバッグを行うことが出来る。

余談だが、vscode全体のユーザー設定でデバッグ設定を記載することも可能である。この場合、GUIからの設定は出来ず、settings.jsonを直接いじるように誘導される。どちらにせよ、全体の設定で統一されたデバッグ設定を使うニーズは少ないと思われる。

#### 自分用メモ

自分はWindowsでハードリンクを設定したフォルダで作業をしていたが、そのファイルにブレークポイントを設定してもブレークポイントが機能しなかった。デバッグ実行時はおそらくハードリンクパスではない、正規のファイル名でデバッグを実行しており、そのファイルにはブレークポイントが未設定と認識されたのではないか、と思われる。
vue.jsで汎用Viewを作成してみた

DjangoのGenelic View的なものを、Vue.jsで作成してみました。

##1.環境

| カテゴリ       | バージョンなど       |
|:-----------------|------------------:|
| os               |windows 10 home 64bit |
|vue |3.2.1|


##2.目的

DjangoのGeneric Viewを使うと、formにmodelのカラムをいちいち書かなくても、form.as_pなどとすることでModelのカラムを展開してくれます。

```form.html
<form method="POST">
{{ form.as_p }}
</form>
```

これをvue.jsを使って同じようなことをしてみたいと思います。

##3.実装

###(1)ファイル構成

``` folder/file
dist
│  vue.min.js
sample
│  sample.html
│  vue-genericview.css
│  vue-genericview.js

```

###(2)html

```sample/index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="vue-genericview.css">
<style>
    body{
      font-size: 14px;
    }
    .container {
      min-width:20%;
      width: 98%;
      padding: 6px;
    }
</style>
</head>
<body>  
  <div class="container">
      <div id="content">
        <edit-grid 
          :data="griddata"
          >
        </edit-grid>
      </div>
  </div>
<script type="text/javascript" src="../dist/vue.min.js"></script>
<script type="text/javascript" src="./vue-genericview.js"></script>
<script>
  //mydataは実践ではaxiosなどでサーバからjsonを取得します。
  var mydata = {};
  for (var i = 0; i < 5; i++) {
    mydata["label" + i] = "value" + i
  }

  new Vue({
    el: '#content',
    data: {
        griddata : mydata
    },
  })
</script>
</body>
</html>
```

###(3)js

コンポーネントです。props,dataだけを使います。
bootstrapなどを使う場合は、classを適時変更ください。

```sample/vue-genericview.js
  Vue.component('edit-grid', {
    template: `
  <div>
    <div class="block core-block" v-for="(value, key) in data">
      <label>{{ key }}</lavel><br/> <input type="text" v-model="value" />
    </div>
  </div>
    `,
    props: {
      data: Array,
    },
    data: function () {
        var data = this.data
        return data
    },
    computed: {
    },
    filters: {
    },
    methods: {
    }
  })
```

###(4)css

一例です。適時編集ください。

```sample/vue-genericview.css
    .block {
      padding: 3px;
      display:inline-block;
    }

    .core-block {
      min-width:98%;
    }

    .full-block {
      min-width:98%;
    }

    .block * {
      width: 99%;
      
    }
    
    .block input {
      border: none;
      border: 1px solid darkgray !important;
      padding: 3px;
    }
```

##4動作確認

![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/5151d8c4-175f-f803-f6c3-4f57544c4a89.png)

まだ荒っぽいですが、とりあえず目的は達成できました。
Ruby2.6 + Graphvizで抽象構文木をグラフにしてみる

[Pythonの抽象構文木をGraphvizで可視化する]( https://qiita.com/kaityo256/items/e83b369ba7518da0a519 )を見て、ruby でもやってみようと思った。

正直言って、`RubyVM` モジュールに触るのは初めてなので、正しいのかどうかはよくわからない。
でもまあ、それらしいツリーが出力できたからいいかなと思っている。

というわけで、ソースコード：

```ruby:ruby2.6
# ruby rubyast.rb sample.rb | dot -Tpng -oast.png
@symbol=:a
def sym
  @symbol = @symbol.succ
end

def show(x, parent)
  return if x.nil?
  label, shape = if x.respond_to?(:type)
    [ x.type.to_s, "oval" ]
  else
    [ "%s(%s)" % [x.inspect, x.class], "box" ]
  end
  this = sym
  puts( "%s -> %s" % [ parent, this ] )
  puts( %Q!%s[ label=%s; shape=%s ]! % [ this, label.to_s.inspect, shape ] )
  if RubyVM::AbstractSyntaxTree::Node===x
    x.children.each do |ch|
      show(ch, this)
    end
  end
end

puts( %Q!digraph{graph [dpi=288;];! )
src = File.open(ARGV[0]){ |f| f.read }
show(RubyVM::AbstractSyntaxTree.parse(src), "root")
puts("}")
```

食べさせたコードはこんな感じ：

```ruby:sample.rb
def foobar(hoge, fuga)
  p( hoge + fuga * 2 )
end
foobar(111,222)
```



出てくる絵は、こんな感じ：

![image.png](https://qiita-image-store.s3.amazonaws.com/0/6854/e297e483-53e5-7686-d873-40e110d9c58a.png)

なかなか楽しい。
Scrapbox SQUARE TOKYO ～開発現場の活用会議～ 勉強会メモ

# 発表概要

[Scrapbox SQUARE TOKYO ～開発現場の活用会議](https://nota.connpass.com/event/111163/)

> Scrapboxを活用したチーム開発の実践や導入までのストーリーを大公開！
> Scrapboxのことが気になっているエンジニアやデザイナー向けのカンファレンス。個人で Scrapboxを使っている方から既に会社で使っているよという方まで、どなたでもお楽しみいただける内容をお届けします。
> 記念すべき第1回は、既に開発チーム内でScrapboxを使いこなしているFiNCの高見さんとGMOペパボの川合さんにお話いただきます！

# 各発表と資料

- [Scrapbox公開から2周年の振り返りとこれから](https://scrapbox.io/scrapbox-square/Scrapbox_Square_%E7%99%BA%E8%A1%A8%E8%B3%87%E6%96%99_%E3%80%8C2%E5%91%A8%E5%B9%B4%E3%81%AE%E6%8C%AF%E3%82%8A%E8%BF%94%E3%82%8A%E3%81%A8%E3%81%93%E3%82%8C%E3%81%8B%E3%82%89%E3%80%8D)
 - [Nota社のScrapboxを一部公開](https://scrapbox.io/nota-private-sample/)
- [既存ツールより10倍以上書かれるScrapboxのFiNCでの運用事例](https://scrapbox.io/scrapbox-square/%E6%97%A2%E5%AD%98%E3%83%84%E3%83%BC%E3%83%AB%E3%81%AE10%E5%80%8D%E4%BB%A5%E4%B8%8A%EF%BC%81FiNC%E3%81%A7%E3%81%AEScrapbox%E3%81%AE%E7%88%86%E7%99%BA%E7%9A%84%E6%99%AE%E5%8F%8A%E3%81%AF%E3%81%AA%E3%81%9C%E8%B5%B7%E3%81%93%E3%81%A3%E3%81%9F%E3%81%8B)

- [SUZURIのScrapbox遍歴](https://scrapbox.io/scrapbox-square/SUZURI%E3%81%AEScrapbox%E9%81%8D%E6%AD%B4_(yuta25))

- [最近開発している機能の裏話](https://scrapbox.io/scrapbox-square/Scrapbox%E9%96%8B%E7%99%BA%E3%81%AE%E8%A3%8F%E5%81%B4)
- [ここだけの話！scrapboxを組織に定着させるコツとは](https://scrapbox.io/scrapbox-square/%E3%81%93%E3%81%93%E3%81%A0%E3%81%91%E3%81%AE%E8%A9%B1%EF%BC%81scrapbox%E3%82%92%E7%B5%84%E7%B9%94%E3%81%AB%E5%AE%9A%E7%9D%80%E3%81%95%E3%81%9B%E3%82%8B%E3%82%B3%E3%83%84%E3%81%A8%E3%81%AF)

# 収穫

- 用途の幅の広さがやばい
 - 自己紹介
 - タスク管理
 - 配属後のオンボーディング
 - 議事録
 - 手順書、作業ログ
 - etc.
- **scrapboxでプレゼンできることを勉強会で知る**
 - 使い始めたてのにわかです。。。

- 所感
 - ドキュメント化へのコストは少なくなりそう
  - 完全な偏見だが、ツイッター好むユーザはScrapboxも好きなのでは？
 - また、情報の透明性が高いので、チームビルディングにもつながりそう
 - 一方で、導入までのハードルは高そうだなという認識
  - 既存のwiki系ドキュメントからの移行もしかり、使い方や記法もしかり
【Laravel】リダイレクト処理でビューへ変数を受け渡すときの注意点

`with()` を使うことで、ビューに変数を受け渡すことができます。
ビュー側では `{{ $test }}` とすることで変数を展開できます。

```SampleController.php
class SsampleController extends Controller
{
    public function index()
    {
        return view('sample.index')->with('test', 'テストだよ');
    }
}
```

`with()` の書き方は同じですが、下記のようにリダイレクト処理を行なった場合は `'テストだよ'` が変数ではなくセッションに保存されるため、 `{{ session('test') }}` のように取り出すことになります。

```SampleController.php
class SsampleController extends Controller
{
    return redirect()->route('sample.index')->with('test', 'テストだよ');
}
```

`{{ $test }}` としても、そんな変数は存在しないと怒られてしまいます。
macOSをアップデートしたところDockerで開発していたブラウザページにアクセスできなくなったが、Dockerが止まっていただけだった件

#はじめに
macOSを、うっかりMojaveにアップデートしてしまったところ、Dockerで開発していたLaravelアプリのブラウザページが表示できなくなった。
吐き気を催しながら、インフラ担当の先輩に助けを求めた。

#結論
ただ単にDockerが止まっていただけだった。
今回は、戒めもかねて、Dockerが動いているかの確認、起動についてメモしておきます。



#確認方法
一旦作業ディレクトリに移動して、

**docker-compose.yml**

があるディレクトリまで移動。
そこで、

```terminal
$ docker-compose ps
```

と実行する。
Dockerが止まっている場合、以下のようなエラーが返ってきました。

```terminal
ERROR: Couldn't connect to Docker daemon. You might need to start Docker for Mac.
```

finderのapp、もしくはLaunchpadからDockerのアプリを起動させ、もう一度

```terminal
$ docker-compose ps
```

を実行すると、今度は

```terminal
               Name                             Command              State           Ports         
---------------------------------------------------------------------------------------------------
image_uploader_db                    docker-entrypoint.sh postgres   Up      0.0.0.0:5432->5432/tcp
infrastructure_image_uploader_web_   /sbin/init                      Up      0.0.0.0:80->80/tcp    
1 
```

と表示され、ブラウザからは開発中のページが確認できました。

#教訓
 - 安易にOSのアップデートしない。
 - 当たり前だが、Dockerが止まるとブラウザも表示されなくなる。
 - ***docker-compose.yml***のあるディレクトリで***$ docker-compose ps***実行で確認できる。
Julia v1.0でPortAudio.jlをインストールする

作者の人がうまいこと直すと言っていたのですぐに古くなると思います。

# 背景
Julia1.0でPortAudio.jlをインストールしようとするとUnsatisfiable requirements detected for package PortAudioがどうのこうのと言われてインストールできない。
これはjulia1ブランチを使えばよいのだが、julia1ブランチを使用してもいざコードを実行すると以下のエラーが出る。

```
symbol lookup error: /ひみつ/.julia/packages/PortAudio/pj3Gu/src/../deps/usr/lib/pa_shim_x86_64-linux-gnu.so: undefined symbol: PaUtil_GetRingBufferWriteAvailable
```
# 手順
現状、以下のようにインストールすればうまく行く。
Pkg REPL-modeで以下の手順を実行する。
1. ```add PortAudio#julia1```
2. ```add RingBuffers#master```
3. ```build RingBuffers```
4. ```build PortAudio```

# 試しに実行する
以下のコードでクラッシュしない。

```julia
import PortAudio
stream = PortAudio.PortAudioStream(1, 1) # ここでundefined symbolが出ていた
```
FOOBARキーボードを作る 【ビルド・完成編】2018/12/29

ようやくはんだ付けまで行きついたので、すごく簡単ですがビルドログ上げます。

##ビルド
PCBに部品をつけるのは、数々の自作キーボードのビルドログが上がっているので省略します。スミマセン…

特別なこととしてはPro Microをソケット化したことですが、[Romlyさんのサイト](
http://romly.com/archives/2017/12/gherkin_socketing_promicro.html)で紹介されていますので、同じ感じでソケット化しました。(後述しています)

それともう1つ。スイッチを直接PCBにはんだ付けしようとすると、位置が決まらないでぐらぐらするのが困りました。結局ちょこっとアロンアルファをつけて無理やり固定しちゃいました。
これがスイッチのピン数の違いなんだなと実感。

無事完成したので、続いてファーム焼き。
※アンドロイド機とつないでるわけではありません。
![IMG-1670.JPG](https://qiita-image-store.s3.amazonaws.com/0/283328/74a6b0c2-d46b-a6ee-c538-05112472b573.jpeg)

##ファーム焼き
前にmakeはできるのは確認済みなので、USBで接続し左右別々にファームを焼きました。リセットボタンをつけてなかったので、ピンセットでリセット。

```
E430 MSYS ~/qmk_firmware
$ make 40percentclub/foobar:mykeymap:avrdude
```

##テスト
テキストエディターでキーを押して入力できる事が確認出来たら、[kbv.exe](https://hp.vector.co.jp/authors/VA054714/)を使って割り当てたキーが入力できるか確認。長押しの設定をしている最下段のキーで、普通にタイプ(tap?)した時にkbv.exeで動作確認できなかったけど、テキストエディターで確認できてるから問題なし。
![Form1 2018-12-29 22.32.42.png](https://qiita-image-store.s3.amazonaws.com/0/283328/f04b1dd5-6b6d-b625-7e6d-d2e1fd533f7c.png)


無事動作する事は確認できましたが、良さげと思ったキーマップはいまいちな箇所が出てきたのでチューニングが必要ですね。ぼちぼちやっていこうと思います。

これで一通り完成。

##ソケット化手順を写真付きで紹介
1. PCBにはんだ付け済みのICソケットにカプトンテープを貼ります。
![IMG-1663.JPG](https://qiita-image-store.s3.amazonaws.com/0/283328/3a92ceae-6e6b-c69d-3a8e-58f779dfdc56.jpeg)
2. 4隅に余ったダイオードの配線をぶっ刺します。4隅にするのは次の工程のためです。
![IMG-1664.JPG](https://qiita-image-store.s3.amazonaws.com/0/283328/38aa7a62-30c1-1d4f-0080-91b862457318.jpeg)
![IMG-1665.JPG](https://qiita-image-store.s3.amazonaws.com/0/283328/9f188b8b-bb45-5c29-98ec-7fa6b965ee97.jpeg)
3. Pro Microを置いて残りのピンに配線をぶっ刺します。
![IMG-1666.JPG](https://qiita-image-store.s3.amazonaws.com/0/283328/be90d459-7077-7e5c-4943-f100dd6b79c3.jpeg)
4. はんだ付けして出来上がりです。
![IMG-1667.JPG](https://qiita-image-store.s3.amazonaws.com/0/283328/4278c468-3b59-7963-0fc2-3c2294f48ea3.jpeg)
C#のデリゲートについて（書き方の変遷など）

## デリゲートについて

- 現在ではほぼしない、古典的な書き方（デリゲートの型を自分で宣言する）

```csharp
public class ClassSample
{
    delegate int Delegate_A(string s); // Delegate_A という名前の「型」を定義
    
    static void Main()
    {
        // デリゲートはひとつの「型」なので、他のクラスを使用するときと同じ書き方でインスタンス化できる
        Delegate_A dlg = new Delegate_A(work);    // C#1.0
        //Delegate_A dlg = work;                // C#2.0 で new なしで書けるようになった

        // 作成したインスタンスに引数を渡しつつ呼び出す
        int result = dlg("123");
    }

    // デリゲートから呼び出されるメソッド
    private static int work(string s)
    {
        return int.Parse(s);
    }
}
```

- .NET Framework 3.5以降では、定義済デリゲートにより、独自のデリゲート定義が不要になりました。  
戻り値を持たない `Action<T>型` と、戻り値を持つ `Func<T,TResult>型` などが使えます。  
上記のコードを定義済デリゲートと使って書き換えると下記のようになります。

```csharp
public class ClassSample
{
    // 独自デリゲート型の宣言が不要になった
    
    static void Main()
    {
        // 定義済デリゲートのインスタンスを生成（newを省略した書き方）
        Func<string,int> dlg = work;

        // 作成したインスタンスに引数を渡しつつ呼び出す
        int result = dlg("123");
    }

    // デリゲートから呼び出されるメソッド
    private static int work(string s)
    {
        return int.Parse(s);
    }
}
```

- また、ラムダ式を使うことより、別メソッドに記述していた処理内容をその場で書けるようになりました。

```csharp
public class ClassSample
{
    static void Main()
    {
        // メソッドの内容を (引数) => {処理(式)} で書ける
        //Func<string,int> dlg = (string s) => { return int.Parse(s); };
        
        // 引数の型(string)は型推論により省略可能
        // 処理部分がreturn のみの場合は{}も省略可能
        Func<string,int> dlg = s => int.Parse(s);

        // 作成したインスタンスに引数を渡しつつ呼び出す
        int result = dlg("123");
    }
}
```
[Tips] Xcode10 スニペット(Snippet)の設定方法

<img width="894" alt="スクリーンショット 2018-12-29 21.53.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/69002/5cc06ffc-b9a6-43e6-2aa9-e140de9b4d29.png">

# 概要
Xcode10で任意のスニペットを利用・設定する方法。

# スニペットとは
#### 概要
Xcodeでコードを打つ際の入力補助機能。Xcodeデフォルトのものとは別にカスタムで追加することもできる。

#### 設定項目
|No.|項目|内容|備考|
|:--|:--|:--|:--|
|1|Title|タイトル||
|2|Summary|概要文。任意で。||
|3|Platform|対象プラットフォーム||
|4|Language|対象言語||
|5|Completion Shortcut|ショートカットを呼び起こすための文。ほぼ必須。||
|6|Completion Scopes|ショートカットを呼び起こすべき箇所。ほぼ必須。|クラス定義の場合は`TopLevel`|
|7|Value|スニペットのとして表示されるテキスト。`<#何か入るよ#>`の形式で囲んだ部分は仮置き文字になる。||

#### 利用方法
<img width="657" alt="スクリーンショット 2018-12-29 22.11.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/69002/1bc8bbe0-0826-9050-e880-1c0fb780b79f.png">
<img width="587" alt="スクリーンショット 2018-12-29 22.11.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/69002/b5dea787-6fac-f748-5f9e-cdfc0436e29f.png">
2通りある。
① 対象スニペットのCompletionScope箇所で、CompletionShortcutを打ち込む。
② スニペット一覧でスニペット項目をダブルクリックする。

# 設定方法
<img width="721" alt="スクリーンショット 2018-12-29 22.19.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/69002/9efbdae5-21db-e1de-e543-d7bf89940c82.png">

#### 追加する場合
1. 追加したいスニペットを用意し、副クリック。
2. メニューから`Create Code Snippet`を選択。

#### 編集する場合
1. ツールバーのスニペットアイコンをクリックする等して、スニペット一覧を表示させる。
2. 対象のスニペット項目をクリックすると編集画面が表示される。（急いでダブルクリックしないよう注意）
3. 内容編集する場合は、そのまま編集。削除する場合は、キーボードのdeleteボタンを押す。
|

# 備考
（特になし）
C#の静的メソッドと静的クラスについて

## 静的メソッドと静的クラス
### 静的メソッド
クラスをインスタンス化しなくてもお手軽に呼び出せるので、ユーティリティ的なメソッドを書いたりします。
静的クラスではない、通常のクラス内に記述できます。
（同じクラス内には通常のインスタンスメソッドも記述でき、こちらはクラスをインスタンス化してから呼び出します。）

```csharp
    // staticではない通常のクラス
    public class ClassSample
    {
        public static void Method_A() // 静的メソッド --> インスタンス化せずに呼び出せる
        {
            // 処理を実装
        }

        public void Method_B()  // インスタンスメソッド --> インスタンス化してから呼び出す
        {
            // 処理を実装
        }
    }
```

### 静的クラス
クラスのメンバ（フィールドやメソッド）はすべて static にしなければなりません。static キーワードを忘れると下記のように怒られます。
また静的クラスはインスタンス化することが出来ません。

```csharp
    // staticクラス
    public static class ClassSample
    {
        public static void Method_A() // 静的メソッド --> インスタンス化せずに呼び出せる
        {
            // 処理を実装
        }

        // 「静的クラスでインスタンスのメンバーを宣言することはできません」と怒られます。
        public void Method_B()
        {
            // 処理を実装
        }
    }
```
基礎からのVMware Cloud on AWSーその３

VMware Cloud on AWSの基礎を
おさらいするための記事を書いてます。

過去２回は以下の内容をお届けしました。

第１回　物理構成の理解
https://qiita.com/hiroito1118/items/48d8d66fab24acd16c1d

第２回　管理方法と初期デプロイの概要
https://qiita.com/hiroito1118/items/8ed96c156b8577ca4749


今回は順序的にきれいかどうかはさておき、
ユースケースについて解説します。


# １．VMware Cloud on AWSのユースケース

VMware Cloud on AWSに関しての利用シーンを
確認していると、次のユースケースを
目にすることになると思います。

１）データセンターの拡張
２）クラウドへの移行
３）ディザスタリカバリ

それぞれのユースケースについて、
詳しくみていきましょう。

##　１）データセンターの拡張
このシナリオでは、現在オンプレミスの環境をそのままとして、
追加でVMware Cloud on AWSの環境を構築して、
接続するというケースを想定しています。

つなぎかたは色々とありますが、
追加リソース的に使うにはおそらくL2延伸を実装する
イメージになろうかと思います。
※L2延伸については色々と注意点などありますので、
　後日の記事で解説します。

このケースでのメリットは、短期間であったり、
急遽リソース増強を行いたい場合に、
短時間でホスト単位でのリソース増強が可能なことです。
オンプレミスでの増強に何か月もかけていたかつ、
比較的頻度が多かったような場合には効果的と言えます。
また、双方の環境をvCenterで管理できる点は、
クラウドを使いながらも運用スキルセットを
一定範囲に抑えられる点で、現実的です。

しかし、越えるべきハードルとしては、
VMware Cloud on AWSの環境がそれほど小さくなく、
オンプレミスの環境を持ちながらも、
この規模のリソースを維持するだけの
ITリソースの要求があるかどうか、です。

※最小リソースサイズについては第１回目の記事参照
https://qiita.com/hiroito1118/items/48d8d66fab24acd16c1d

重要なこととして、VMware Cloud on AWSでは、
ネットワーク等のユーザ個別の情報をすべてSDDCの中に持つため、
ホストを落とす＝SDDCを削除する＝設定がすべて失われる
という仕掛けになっています。
そのため、使いたい時だけ上げることはできません。
最低３ノードは常時上げてもらい、
４ノード以上についてのみ、増減が可能です。

このため、データセンターの拡張シナリオでは、
オンプレミスとVMware Cloud on AWSの双方の
維持コストが発生します。
IT環境の規模に応じて、ご検討ください。

##　２）クラウドへの移行
このケースは、オンプレミスのVMware環境を、
VMware Cloud on AWSに完全にお引越しするというイメージです。

ネイティブなクラウド環境へのマイグレーションは、
サーバにエージェントを入れなければいけなかったり、
ソフトウェアでコンバートしたりとリスクを伴います。
VMware to VMwareであれば、コンバートする必要がなく、
リスクが抑えられかつスムーズに移行可能です、
というシナリオです。

個人的には、特に日本では
現実的なシナリオではないかと考えています。
理由としては、やはりリソース規模的に、
日本の顧客では多くがVMware Cloud on AWSの
最小規模に収まってしまう可能性があるためです。
（もちろん、それより大きいケースはあります）

Webのシステムなど変動性のあるものは現実的に
EC2なりAWSネイティブサービスの方を使うでしょうし、
SoR的なシステムだけをかき集めた時に、
最小サイズで収まってしまうのではないかなと。

そう考えると、現実的には、
このマイグレーションプランで、
　SoR系→VMware Cloud on AWS
　SoE系→AWSネイティブサービス
という構成にしてしまうと、
かなりわかりやすいのかなと思っています。


##　３）ディザスタリカバリ
最後はこのシナリオです。これが一番注意です。

初めに明確に伝えますが、
VMware Cloud on AWSはホストの停止が実質できないので、
DRサイトで使う場合もコストが定常的にかかります。
EC2インスタンスの様に落とせば課金なし、
というシナリオで検討しないでください。

大事なことなのでもう一度書きます。
#### DRサイトで使う場合もコストが定常的にかかります。

VMware Cloud on AWSへの期待として、
VMテクノロジだから切り替えスムーズだし、
##### 落としておけば金がかからないと勘違いして、
##### DRシナリオが提案されているケースが散見されます。
そんなことはありません。

先にも掲載しましたが、落とす＝SDDC削除です。
DRシナリオを実施するためには、
データを定期的に飛ばす必要がありますが。
それを受けるvSANはホストを上げていないと稼働しません。
なので、常時3ノードのホストを上げ続ける必要があります。

ネットワークの設定情報はNSX Managerが保持していますが、
これもvSAN上で稼働します。
落とせば消えます。再構築です。

なので、このディザスタリカバリシナリオで使う場合は、
常時稼働させておく環境として、データセンターの拡張と
ほぼ同じような考え方で利用する必要があります。

現実的には常時稼働させておくコストがもったいないので、
検証環境なり緊急時には落とせるようなもので
リソースを有効活用するのが現実的です。

##　おまけ）１ノードでの利用に関する注意
VMware Cloud on AWSの利用オプションとして、
１ノードに関する記述があります。
確かに１ノードでの構成は可能は可能なのですが、
PoC用途に限定して利用してください。

理由は、
　・そもそも30日間だけ利用可能な限定プランである
　・期間中にメンテナンスによるホストが停止を伴う場合、
　　作成していたSDDCが削除される
ためです。
著者も作業期間中にメンテナンスに遭遇し、
見事SDDCごと削除されました。
＃VPN等のネットワーク設定もすべてやり直し

１ノード構成は、
本当に少しだけ触りたいようなケースだけ使うようにしましょう。

今回は以上です。
次回は、調達方法について触れます。
Ruby環境構築２

# はじめに
前回、Rubyの全体像をまとめた。今回はRuby、rubygems、gem環境の構築についてまとめる。

# 概要
Rubyにはアドオンするパッケージ的は位置づけでgemがある。rubygemsはRubyをインストールすると付随してくるコンポーネントで、gemをインストールしてくれる。

# ディレクトリ構成とインストール
## ディレクトリ構成
全体の主要な構成は以下になる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/269452/f99a0845-387e-012b-b81d-62c759cbfb62.png)

## インストール
1. rubyとrubygemsのインストール（紺色）

    最初に`yum install ruby`でrubyをインストールする。rubygemsもインストールされる。ディレクトリは/usr/bin/の配下だ。他にもライブラリやらなんやらがインストールされる。
なお、rubygemsにはデフォルトのgemがいくつか入っている。これらは場所は/usr/share/gems/gems/にインストールされている。

2. gemのインストール（緑色）

    アプリケーションで使うgemをインストールする。ここでは例としてstrptimeをインストールする。コマンドは`gem install strptime`。これにより/home/ec2-user/配下に./gem/が作られ、その配下のgem/にインストールされる。

3. アプリ用ディレクトリ作成とプログラム作成

    `mkdir`でRubyAPPディレクトリを作り、rubyapp.rbを作成する。ec2app.rbの中ではstreptimeを使っている。

    ```ruby
# strptimeを要求
 require 'time'
 require 'strptime'
# 現在時刻を表示
 now = Time.now
# フォーマットを定義
 formatter = Strftime.new('%Y-%m-%dT%H:%M:%S.%L %z')
# 変換
 puts formatter.exec(now)
```

4. プログラム実行
   `ruby ec2rubyapp.rb`で実行。めでたしめでたし。

    ```bash
[ec2-user@ip-10-0-1-62 RubyAPP]$ ruby ec2app.rb
2018-12-29T09:54:18.776 +0000
```

# ポイント
## gemはユーザ単位にインストールされる
図をみて気づいたと思うが、`gem install`でインストールされるgemは/home/のユーザディレクトリにインストールされる。つまり、gemはユーザ単位でインストールされるのだ。２つのユーザで`gem list`コマンドをたたいた場合は、それぞれ以下となる。

* ec2-user

    ```ruby
[ec2-user@ip-10-0-1-62 ~]$ gem list
*** LOCAL GEMS ***
bigdecimal (1.2.0)
io-console (0.4.2)
json (1.7.7)
psych (2.0.0)
rdoc (4.0.0)
strptime (0.2.3)
```
* tmp-user

    ```bash
[tmp-user@ip-10-0-1-62 ~]$ gem list
*** LOCAL GEMS ***
bigdecimal (1.2.0)
io-console (0.4.2)
json (1.7.7)
psych (2.0.0)
rdoc (4.0.0)
string-to-bool (0.0.1)
```
ユーザごとにgemのリストが異なることが分かる。/usr/share/gemsにインストールされたデフォルトのgemは、どちらでも使える。

# まとめ
Ruby自体は全体にインストールされるが**gemはユーザに紐づく**。だからrubyのアプリケーションは各々のホームディレクトリに作るのがよい。
Object Detection API 導入手順の補足（Mac版）

# 概要
Object Detection APIのMacへの導入で、つまずいた点を記します。

# 環境
導入先：macOS Hight Sierra

# Object Detection APIの導入手順
導入手順は、こちらに記載あります。
https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/installation.md

# つまずいた点
## 1. tensorflowの導入ディレクトリにmodels/researchがない

COCO API installationで、以下の手順があります。

>cp -r pycocotools \<path_to_tensorflow>/models/research/

tensorflowのインストールディレクトリを見ても、models/researchはありません。

tensorflowをpipでインストールするだけではなく、modelをダウンロードする必要があります。下記をダウンロードすればOKです。

https://github.com/tensorflow/models

## 2. protocが実行できない

Protobuf Compilationで、以下の手順があります。

>protoc object_detection/protos/*.proto --python_out=.

Dependenciesのインストールに記載されている下記を実施するだけでは、protocを実行できません。

>Alternatively, users can install dependencies using pip:
>pip install --user Cython
>pip install --user contextlib2
>pip install --user pillow
>pip install --user lxml
>pip install --user jupyter
>pip install --user matplotlib

brewで、protobufを導入する必要があります。

```
brew install protobuf
```

しかし、途中でエラーしました。権限エラーです。
>Error:[0m Permission denied @ dir_s_mkdir - /usr/local/Frameworks

対応として、brew installする前に、sudoで事前に/usr/local/Frameworksディレクトリを作成しておきます。

```
sudo mkdir /usr/local/Frameworks
```

これで導入がうまくいき、protocを実行できます。

# 導入確認
最後は下記で導入確認できます。

``` 
python object_detection/builders/model_builder_test.py
......................
----------------------------------------------------------------------
Ran 22 tests in 0.167s

OK
```
InterfaceをInspectorでの登録によって取得する


![ComponentRestriction.gif](https://qiita-image-store.s3.amazonaws.com/0/113504/2460c131-20f7-5db0-e2c2-69374b7461bb.gif "ComponentRestriction.gif")


# 前提
UnityはコンポーネントをInspector上でアタッチすることによって参照を取得することができる

Interfaceを使うと疎結合になるため良い設計をするためには必須

**Interfaceは通常シリアライズできないためInspectorで登録できない**

# 対応策
1. Interfaceを実装しているComponentの参照を保持
2. InterfaceはGetComponentで取得する

# サンプル

```ISomeInterface.cs
public interface ISomeInterface
{
    void LogAny();
}
```

```SomeController.cs
public class SomeController : MonoBehaviour
{
    // 1. コンポーネントの参照を取得
    [SerializeField] Component someComponent;

    // 2. Interfaceを取得してキャッシュ
    ISomeInterface logger = null;
    ISomeInterface Logger{
        get{
            if(logger == null)
                logger = someComponent.GetComponent<ISomeInterface>();
            return logger;
        }
    }

    void Start()
    {
        Logger.LogAny();
    }
}
```

`SomeController`のように書くことで、Interfaceを取得することは可能になる。
しかし、このコードではsomeComponentにISomeInterfaceを実装していないコンポーネントでも登録できてしまう。
そこで登録できるコンポーネントに制限をかける。

# 登録できるコンポーネントに制限をかける
CustomoAttributeを作成する。

```ComponentRestrictionAttribute.cs
using System;
using UnityEngine;

[System.AttributeUsage (System.AttributeTargets.Field,Inherited = true, AllowMultiple = false)]
public class ComponentRestrictionAttribute : PropertyAttribute
{
    public Type type;
    public ComponentRestrictionAttribute(Type type){
        this.type = type;
    }
}


```


```ComponentRestrictionDrawer.cs
using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer( typeof ( ComponentRestrictionAttribute ) )]
public class  ComponentRestrictionDrawer : PropertyDrawer
{
    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {
        var restriction = (ComponentRestrictionAttribute)attribute;
        
        if (property.propertyType == SerializedPropertyType.ObjectReference) {
            EditorGUI.ObjectField(position, property, restriction.type);
        }else{
            EditorGUI.PropertyField(position, property);
        }
    }
}
```

ComponentRestrictionDrawerはEditorフォルダ以下に作成

```SomeController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SomeController : MonoBehaviour
{
    // ComponentRestriction追加
    [SerializeField, ComponentRestriction(typeof(ISomeInterface))] Component someComponent;

    ISomeInterface logger = null;
    ISomeInterface Logger{
        get{
            if(logger == null)
                logger = someComponent.GetComponent<ISomeInterface>();
            return logger;
        }
    }

    void Start()
    {
        Logger.LogAny();
    }
}

```

ComponentRrestrictionを追加

これでISomeInterfaceを実装していないコンポーネントは登録できなくなる
GifのAttributeTestは以下

```AttributeTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AttributeTest : MonoBehaviour, ISomeInterface
{
    public void LogAny()
    {
        Debug.Log("Hello");
    }
}

```

# まとめ
コード量は多くなってしまうもののInterfaceを取得することができた。
コードテンプレート、または自動生成がないとつらい。
トピックモデルを用いて国会と新聞を比較する


前回の続きの分析を行ってみました。
前回の記事はこちら↓
https://qiita.com/hasuminbanana/private/4babc9498f3e384a6639

前回は国会の衆参本会議のデータを11年分収集してLDAによって50トピックを推定し、該当する文書数の変化を年次でプロットしてみました。

今回は
・週次でデータを切り分け、より細かい変化をみる
・朝日新聞の一面のデータを収集し、同時期の新聞の変化を見る

を行っていきます。
今回は、前回の分析によってこんなことができるよ、という紹介なので、コードの記載は省略します。（ほとんど同じことをしました。）

#データの収集
国会の衆参本会議の議事録を2015年-2017年の３年間で取得しました。

朝日新聞のデータは学校のデータベースから地道に取得しました。
収集時に週ごとのデータに切り分けでテキストファイルに保存し、52×3の156週で分析を行っていきます。

#LDA
作業は前回の記事と全く同じで、国会と朝日それぞれの文書でLDAによる50トピック推定を行います。

国会と朝日新聞の一面では同じような話題が語られていることもありますが、当然ながら、異なる話題が両者に含まれており、50トピックの別れ方は異なります。

今回は両者で同じトピックだと考えられるものをピックアップして比較しました。

結果は以下のようになりました。（一部）
・国会
![スクリーンショット 2018-12-29 21.18.56.png](https://qiita-image-store.s3.amazonaws.com/0/271293/68992715-5732-c14e-b6c7-15dcb7571f1e.png)

・朝日
![スクリーンショット 2018-12-29 21.23.10.png](https://qiita-image-store.s3.amazonaws.com/0/271293/6685464d-a147-b1ba-d3be-79028daf818b.png)


各行がトピックであり、左側から順に構成比率の高い単語が並んでいます。

国会では答弁を行ったり、野党が与党を追求するようなトピックがあり、朝日ではシリアや北朝鮮、ロシアといった外国の名前が多く出てきています。

また、森友問題に関しては両者で同じようにトピックとして推定されていることがわかります。（国会8行目と朝日１行目）

#特定のトピックで文書数を時系列プロットする

今回は50トピックの中で共通していると推定される森友問題とTPPに関して、週ごとの文書数の時系列変化を辿っていきます。

前回の記事と同様にトピックxが20%以上含まれる文書をトピックx文書として、週次でトピック文書数をリストに格納していきました。

結果は以下のようになりました。


・森友問題
![スクリーンショット 2018-12-28 23.58.49.png](https://qiita-image-store.s3.amazonaws.com/0/271293/ce6a710b-e1c3-762e-53b1-8fcba70c4048.png)



・TPP
![スクリーンショット 2018-12-28 23.58.27.png](https://qiita-image-store.s3.amazonaws.com/0/271293/a6d42f55-b4d7-0f12-b539-d0868fe6c3a4.png)


注意点としては、国会は休会している時期があり、その時期のトピック文書数は0になっていることです。（毎年7,8月あたり）

可視化して見ると、
国会では週ごと(あるいは日ごと)に集中的に議論されているのに対し、新聞では数週に渡って議論されていることがわかります。

新聞はニュースを繰り返し、粘着的に報道することで、読者の記憶を補完するということが考えられます。また、一連の事件に関する新情報の報道や、一通り事件が終わった後にまとめて整理するといった記事も散見されますよね。

そして、分析のテーマである、国会と新聞の関連という点で考えると、比較的両者が関連していることがわかりました。

一部では先にニュースが増えて、国会がその後に増え、また一方では国会での議論が増えてからニュースが増えており、両者は双方向に話題に影響を与えています。


#時系列分析
先ほどのプロットしたデータの結果が統計的に得られるかどうか確認します。

Rを用いてグレンジャー因果性検定を行いました。

グレンジャー因果性に関してこちらの記事が参考になります。

https://tjo.hatenablog.com/entry/2013/07/30/191853

数式による説明は省略しますが、今回の件に即して説明すると、
国会のこれまでのTPP文書数から未来の国会のTPPの文書数を推定するよりも、
国会と新聞のこれまでのTPP文書数から未来の国会のTPPの文書数を推定するようがMSEが小さくなる時、新聞から国会へのグレンジャー因果性が存在する、ということになります。

新聞による報道が国会の議論に影響を与えているのか統計的に確かめる、ということです。

varsパッケージのVARモデルで森友問題,TPPについて国会と新聞の影響の因果関係を調べていきます。

結果
・森友問題　国会→朝日
![スクリーンショット 2018-12-29 20.56.24.png](https://qiita-image-store.s3.amazonaws.com/0/271293/94a35d2e-d72f-d670-4eea-ab67827bdbca.png)

・森友問題　朝日→国会
![スクリーンショット 2018-12-29 20.56.31.png](https://qiita-image-store.s3.amazonaws.com/0/271293/c0413c33-cad6-06ed-9616-e1d65a7ceec9.png)

・TPP 国会→朝日
![スクリーンショット 2018-12-29 20.56.46.png](https://qiita-image-store.s3.amazonaws.com/0/271293/b2d562d7-f90c-7ff4-50ee-3a4d86c6e479.png)

・TPP 朝日→国会
![スクリーンショット 2018-12-29 20.56.55.png](https://qiita-image-store.s3.amazonaws.com/0/271293/33718920-94e5-b48d-e2a1-d661420294ad.png)

いずれも有意な結果は得られず、因果関係があるとは言えないようです。


#終わりに
この記事は追加分析の報告ということで、コードは省略してこんなことがトピックモデルでできるよという説明をさせていただきました。

結果として因果関係は見れなかったのが残穢んですが、日次でデータを集める、一面以外の政治面や経済面もデータ集めるなどを行うと結果は変わってきそうです。
Oracle SQL Developer 18cでSQL文をフォーマットする方法

10分ほど真剣に探したところ、右クリックメニューの`書式`でした。

**書式**ですよ。

![syosiki](https://qiita-image-store.s3.amazonaws.com/0/10290/2a763a92-4e4c-de6b-ec9f-8aa7ff37ef00.png)

きっとformatみたいなのを直訳したのだと思いますが、書式って一体...
GitlabChatwork を用いた、GitLab から ChatWork への自動投稿

# 概要

GitLab には、プロジェクトの変更があったときに、Webhook に POST リクエストを行って通知する機能がある。Slack 等、よく利用されているものは、簡単な API 登録をするだけで使用できる。「ChatWork 投稿」は選択肢にないが、Webhook と Google Apps Script を使うと、無料・サーバレスで ChatWork に投稿する仕組みが構築できるので紹介したい。

Heroku を使うと [ChatworkにGitLabのプッシュやマージリクエストの通知を自動投稿する](https://qiita.com/zaru/items/ab4b257dd1ee6bc9dcc1) のような例もある。

https://github.com/infra-workshop/gitlab_chatwork_gas で整形し、
https://github.com/cw-shibuya/chatwork-client-gas を利用して投稿ができる。

https://github.com/infra-workshop/gitlab_chatwork_gas のプルリクエストがあれば、お待ちしています！

# 使い方

## エンドポイントの作成

### 準備

1. https://script.google.com/home から、新規プロジェクトを作成する。
2. プロジェクト名を入力する
3. ライブラリの登録
  1. リソース->ライブラリに `Chatwork Client for Google Apps Script` の `M6TcEyniCs1xb3sdXFF_FhI-MNonZQ_sT` を入力し、追加
  2. バージョンについて最新版を選択
  3. `GitlabChatwork` の `1X9e-skIjQXVAojqOr2l6lVJg2p2DmnqYp3y7WpVl-KH1Odx-FInM-yUg` も同様に追加し、保存する
4. ファイル->プロジェクトのプロパティ->スクリプトのプロパティ にて  
`CHATWORK_ROOM_ID` と `CHATWORK_API_KEY` を設定


### ソースコードを入力

``` js
function doPost(e) {
  var data = JSON.parse(e.postData.getDataAsString());
  var message = GitlabChatwork.constructChatworkMessageFromGitLab(data);
  
  GitlabChatwork.setChatworkAPIKey(PropertiesService.getScriptProperties().getProperty('CHATWORK_API_KEY'));
  GitlabChatwork.setChatworkRoomId(PropertiesService.getScriptProperties().getProperty('CHATWORK_ROOM_ID'));
  GitlabChatwork.setChatWorkClient(ChatWorkClient);
  GitlabChatwork.sendMessageToChatwork(message);
}
```

### 公開 URL の設定

1. 公開->ウェブ アプリケーションとして導入 を押下し、「アプリケーションにアクセスできるユーザー:」を「全員（匿名ユーザを含む）」に変更して「導入」
2. 「現在のウェブ アプリケーションの URL:」が得られる
3. コピーして控えておく(Webhook URL と表記する)

## GitLab に登録

プロジェクトの 設定->インテグレーション (`settings/integrations`) に URL を入力し、テストしてみる

これだけで ChatWork に投稿が可能！
Mac 環境で node-gyp 実行時に「xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance」エラーが出た時の対処法

こんなエラーが出た。

```
xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

Traceback (most recent call last):
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py\", line 16, in <module>
    sys.exit(gyp.script_main())
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/__init__.py\", line 545, in script_main
    return main(sys.argv[1:])
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/__init__.py\", line 538, in main
    return gyp_main(args)
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/__init__.py\", line 523, in gyp_main
    generator.GenerateOutput(flat_list, targets, data, params)
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/generator/make.py\", line 2170, in GenerateOutput
    part_of_all=qualified_target in needed_targets)
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/generator/make.py\", line 795, in Write
    self.Pchify))
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/generator/make.py\", line 1190, in WriteSources
    cflags = self.xcode_settings.GetCflags(configname)
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py\", line 551, in GetCflags
    archs = self.GetActiveArchs(self.configname)
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py\", line 420, in GetActiveArchs
    xcode_archs_default = GetXcodeArchsDefault()
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py\", line 118, in GetXcodeArchsDefault
    xcode_version, _ = XcodeVersion()
  File \"/Users/mkudo/.nodebrew/node/v8.11.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py\", line 1265, in XcodeVersion
    version = re.match(r'(\\d\\.\\d\\.?\\d*)', version).groups()[0]
AttributeError: 'NoneType' object has no attribute 'groups'
gyp ERR! configure error
```

Issue あがってました。

https://github.com/nodejs/node-gyp/issues/569

以下を確認すると良さそうです。

- Xcode、Command Line Tools のインストールはできているか？
- `xcode-select -p` でパスが問題ないか確認
- パスに問題があったら `sudo xcode-select --switch /Library/Developer/CommandLineTools` する
- 駄目なら `sudo xcode-select -r` を実行してみる
A-Frameで360°画像表示

# A-Frameで360°画像表示

## A-Frameとは？

Mozillaが作っている仮想現実体験を構築するためのWebフレームワークです。

3D取り扱ったり、360°画像や動画も表示できたり。
3DやVRでやることをWEBでやれるようにサポートしてくれます。

2018/12/29日現在ではバージョンは0.8.2。

公式サイトに色々サンプルもあるので除くだけでも面白いです。
[A-Frame – Make WebVR](https://aframe.io/)

## 360°画像表示

#### サンプルコード
単にHTMLだけ作ってやろうとするとCORSで怒られるので、適当にサーバを立ててやりました。
画像はRICOH THETA SCで撮ったものです。

[a-]がついたタグが沢山用意されています。
天球の画像はa-skyで表示できます。

```
<html>
  <head>
    <script src="https://aframe.io/releases/0.8.2/aframe.min.js"></script>
    <title> a-frame 360 image </title>
  </head>
  <body>
    <a-scene>
      <a-sky src="/images/360image.JPG" rotation="0 -90 -20"></a-sky>
    </a-scene>
  </body>
</html>

```

#### 表示結果
###### PC
Chromeで表示しました。マウスで見渡せます。
右下のメガネアイコンをクリックで全画面になりました。

![a_frame_chrome.gif](https://qiita-image-store.s3.amazonaws.com/0/329137/554c7e37-9cf7-e9d8-aca8-d8d15b53acc4.gif)

###### スマホ
スマホだとジャイロとスワイプで見渡せました。
右下のメガネアイコンでVR用に画面表示にできました。

AndroidのChrome、iOSのSafariで確認しています。
画像はAndroidです。

<img src="https://qiita-image-store.s3.amazonaws.com/0/329137/5f1b76fb-5a9d-72b2-3c8f-0be9f5d2e67c.png" height="360px">
</img>

<img src="https://qiita-image-store.s3.amazonaws.com/0/329137/053e4d16-f900-74a2-03d6-db8e6deab163.png" width="360px">
</img>

iOSだと上下のアドレスバーが消えなくて完全な全画面表示できないことがあるみたいです。
弄った感じだとiPhone7以上だと大丈夫で、それ未満だとアドレスバーが出ちゃう印象です。

## 参考
- [A-Frameを使った基本的なデモの作成 \| MDN](https://developer.mozilla.org/ja/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_A-Frame)
- [Introduction – A-Frame](https://aframe.io/docs/0.8.0/introduction/)
Emotion Recognitionをやってみる

AzureのFaceAPIを使い感情センシングをしてみる

Azureのライセンス登録を実施してFaceAPIの使用登録をする

ライセンスグループの設定

* FaceAPIの登録から
* Endpointとkeyを取得する
* EndpointはRegionのよって変わるの
* keyは個別で取得

で、python環境で実施するときには、下記のSDKをインストール
https://github.com/Microsoft/Cognitive-Face-Python

インストール方法はページを参考に
サンプルプログラムを実行する

でサンプルプログラムを実行すると

```python

#%%
import cognitive_face as CF

KEY = 'xxxxxxxxxxxxxxxxxxxxxxx'  # Replace with a valid Subscription Key here.
CF.Key.set(KEY)

BASE_URL = 'https://japanwest.api.cognitive.microsoft.com/face/v1.0'  # Replace with your regional Base URL
CF.BaseUrl.set(BASE_URL)

img_url = 'https://raw.githubusercontent.com/Microsoft/Cognitive-Face-Windows/master/Data/detection1.jpg'
result = CF.face.detect(img_url)
print(result)
```

入力画像は笑顔の眼鏡をかけた女性
https://raw.githubusercontent.com/Microsoft/Cognitive-Face-Windows/master/Data/detection1.jpg

Result

```
[{'faceId': '994e29b5-c2e1-4360-8ddd-bad720630fa2', 
'faceRectangle': {'top': 124, 'left': 459, 'width': 227, 'height': 227}}]
```
このままだと、感情がでないのね！ということで、調べてみるとオプションが必要な見たい
detectのオプションを追加して、emotionを返すように

```python
result = CF.face.detect(img_url,attributes='emotion')
```
結果
happinessのスコアが1の検出ができた

```
[{'faceId': 'c42a5934-50a7-4c7c-bac9-fad476b90bbe',
 'faceRectangle': {'top': 124, 'left': 459, 'width': 227, 'height': 227}, 
 'faceAttributes': {'emotion': {'anger': 0.0, 'contempt': 0.0, 'disgust': 0.0, 'fear': 0.0, 'happiness': 1.0, 'neutral': 0.0, 'sadness': 0.0, 'surprise': 0.0}}}]
```
LearnOpenCV の内容が充実してきている。


[サイト紹介 LearnOpenCV](https://qiita.com/nonbiri15/items/3544aab11c8d080e90d8) を追記しました。

OpenPose や Mask R-CNNなどについて加筆しました。


Githubのサイトの[Insights][Contributors]のグラフを見ると、2018年になってコミットが増えているのがわかります。

https://github.com/spmallick/learnopencv/graphs/contributors

役に立つサイトの情報を共有して楽できる部分は楽をしたいですね。
static_assertの評価を実体化まで遅延させる簡単な方法

#はじめに
`static_assert`[^0]の評価をインスタンス化[^1]まで遅延させるためには`false_v<T>`[^2]を使うのが一般的(?)ですが、条件式に`[]{return false;}()`を使うと、それよりも少しだけ簡単に書けます。なぜそのようなことをするかは、[ここ](https://qiita.com/saka1_p/items/e8c4dfdbfa88449190c5)などを参照してみてください。

[^0]: https://cpprefjp.github.io/lang/cpp11/static_assert.html
[^1]: https://programming-place.net/ProgrammingPlacePlus/cpp/language/021.html
[^2]: https://qiita.com/saka1_p/items/e8c4dfdbfa88449190c5


#コード例
```cpp
#include <type_traits>

template<typename T>
T get() {
    if constexpr (std::is_same_v<int, T>) return 0;
    else static_assert([]{return false;}(), "...");
}

int main() {
    get<int>(); // static_assertは評価されません
}
```

#解説
(この解説は、読まなくても大丈夫です！！)
上のコードは、次のコードとだいたい同じような意味です。

```cpp
#include <type_traits>

template<typename T>
T get() {
    struct lambda {
        constexpr auto operator()() const -> decltype(false) {
            return false;
        }
    };
    if constexpr (std::is_same_v<int, T>) return 0;
    else static_assert(lambda{}(), "...");
}

int main() {
    get<int>();
}
```

>ラムダ式の型（これはクロージャオブジェクトの型でもあります）は、クロージャ型と呼ばれる固有の名前のない共用体ではないクラス型です。そのプロパティについては後述します。
クロージャ型は、対応するラムダ式を含む最小のブロックスコープ、クラススコープ、またはネームスペーススコープで宣言されます。（google翻訳）
http://eel.is/c++draft/expr.prim.lambda.closure

より、この場合のラムダ式[^3]は`get`関数テンプレート[^4]内のブロックスコープ[^5]に含まれているので、クロージャ型はそこで宣言されます。ここでは、仮に`local struct lambda`[^6]としておきます（定義までしてしまっています）。

[^3]: https://cpprefjp.github.io/lang/cpp11/lambda_expressions.html
[^4]: https://programming-place.net/ProgrammingPlacePlus/modern_cpp/language/011.html
[^5]: http://www7b.biglobe.ne.jp/~robe/cpphtml/html01/cpp01068.html
[^6]: http://d.hatena.ne.jp/yohhoy/20120222/p1


>[Note: Within a template declaration, a local class (12.4) or enumeration and the members of a local class are never considered to be entities that can be separately instantiated (this includes their default arguments, noexcept-specifiers, and non-static data member initializers, if any). As a result, the dependent names are looked up, the semantic constraints are checked, and any templates used are instantiated as part of the instantiation of the entity within which the local class or enumeration is declared. -- end note] 
C++17言語仕様 §17.7.1 Implicit instantiation [temp.inst], Paragraph 1
（google翻訳するとかえって読みにくくなったので、原文で載せています）

より、テンプレート関数内の`local class（struct）`は依存名[^7]とみなすので、`local struct lambda` は`get()`のテンプレートパラメータ[^10]`T`に依存します。よって、two-phase name lookup[^8] により`lambda{}()`[^9]の評価は、`get()`がインスタンス化されるまで遅延されます。したがって、`static_assert`の評価も同様に`get()`がインスタンス化されるまで遅延されます。（結果として、`constexpr if`の`static_assert`のブランチは破棄されています）

[^7]: https://translate.google.com/translate?hl=ja&sl=en&tl=ja&u=https%3A%2F%2Fen.cppreference.com%2Fw%2Fcpp%2Flanguage%2Fdependent_name
[^8]: https://translate.google.com/translate?hl=ja&sl=en&u=https://blogs.msdn.microsoft.com/vcblog/2017/09/11/two-phase-name-lookup-support-comes-to-msvc/&prev=search
[^9]: lambda la; la(); とだいたい同じです
[^10]: https://programming-place.net/ProgrammingPlacePlus/cpp/language/022.html

#おわりに
[teratailの投稿](https://teratail.com/questions/166409)にて回答してくださった yumetodoさん、Chironianさん、yohhoyさんに感謝します！
Gemfileから使わないgemをソースごとまとめて削除する方法

Gemfileから使わないgemを削除してその実体も消してくれる便利なコマンドを探していたところ`bundle clean`を発見したので使い方メモ。

## `bundle clean`コマンド

[bundler公式](https://bundler.io/man/bundle-clean.1.html)によると、
bundlerのインストール先ディレクトリの使ってないgemを削除してくれるコマンドとのこと。
つまりgemをインストール後にGemfileから削除したが、個別に`bundle exec gem uninstall`していないものをまとめて消してくれる。

## gemを削除まとめて削除するときの手順

1. Gemfileから使わなくなったgemを削除する。
2. `bundle update`を実行し、`Gemfile.lock`から1.で削除したgemの情報を削除。
3. `bundle clean`を実行。すると下記のようにgemが削除された旨が表示され、インストール先のgemsフォルダから実体が削除される。

```
$ bundle clean
Removing sqlite3 (1.3.13)
```