OmniAICreator/Qiita-1.07M huggingface dataset:
コメントをMarkdown形式で書いてXcodeのQuick Helpとチーム仲を豊かにする

Xcodeの機能の一つである Quick Help を自分で書いたコードでももっとスマートにできないか調べたら見つけたの共有します。

ちなみに Quick Help とは、下記のようなものです。
![quick_help_sample.png](https://qiita-image-store.s3.amazonaws.com/0/37274/98ebdd81-afd8-16b9-610b-1e15ca696fc3.png)

カーソルをメソッド／クラスに合わせて option + クリック で出てきます.

# 前提

この記事では、コメントのフォーマットについて説明が主旨であるので、
記事中のコードは、適当で価値ないコードなので、参考にしないでください。

# どういった感じになるの？

書き方を習って書くことで、下記のようになります。

![quick_help_final_0.png](https://qiita-image-store.s3.amazonaws.com/0/37274/4cd4c471-c2a2-c899-5672-0e62daa45bcc.png)
![quick_help_final_1.png](https://qiita-image-store.s3.amazonaws.com/0/37274/03c3c17f-6715-b0fe-e336-374a72ac0b2a.png)



# どうやって書いてるの？

ほとんどのMarkdown記法を使えます。

## 定義箇所

```swift
public struct AuthJwt {
    var alg:String
    var typ:String
}
public enum AuthNError : Swift.Error {
    case invalidJwt(msg:String)
}

/**
 # ユーザ認証ユースケース(by protocol)
 */
public protocol AuthNUseCase {
    /**
     ## トークン取得
     
     認証用トークンをOPサーバーにリクエストをPOSTします.
     
     - precondition: 
       - JWTは検証済み.
       - 最初にこのメソッドを呼ぶこと.
     - postcondition : 戻り値の検証をすること.
     - requires:
       - 通信環境が確保されていること.
       - OP側と鍵の共有されていること.
     - note:
       - [JWTについて](https://www.rfc-editor.org/info/rfc7519)
     - warning: 
       - メインスレッド上で通信処理を行う.**スレッド管理については呼び出し責任とする.**
     
     ---
     - parameter jwt: 認証用JWT
     - returns: RSA526形式トークン
     - throws: AuthNError
     ```
         let authN = AuthNUserCaseImpl()
         authN.fetchToken(jwt:AuthJwt(alg:"HS256", typ:"JWT"))
     ```
     */
    func fetchToken(jwt:AuthJwt) throws -> String?
}

/**
 ## ユーザ認証ユースケース(by struct)
 */
struct AuthNUserCaseImpl : AuthNUseCase {
    /**
     # ほげほげ
     */
    func fetchToken(jwt: AuthJwt) -> String? {
        return nil
    }
}
```

## 呼び出し元

```swift
let authN:AuthNUseCase = AuthNUserCaseImpl()
let token = try! authN.fetchToken(jwt: AuthJwt(alg: "HS256", typ: "JWT"))
```

# めんどうじゃない？

はい。正直全てのメソッドやクラスをこのように書くのは、億劫ですね。
「コードがドキュメントです」とは言わないけど、メンテナンスコストが恩恵を上回っても本末転倒ですし。

## 道具は振り回されずに使いまわす

どこまで書き込むかどうかはチーム内運用によって決めてもらえればと思います。

#### 例えば

「共通コードの公開I/Fに関しては、事前条件、事後条件、サンプルコードは必須にしよう」など決めておくことで

#### 使う側／１週間後の自分／新人からしたら

- やりたいことが分かりやすい
- 作った人以外でもメンテナンスしやすい
- 新人でもコードレビューを使って先輩に斧を投げれる
- 新人に陥りがちな「作り終わったら違う目的を達成」をセルフレビューできる

# 注意事項

注意ってほどでもないですが、いくつか挙動にルールがありました。

- 書いた順番に表示されない
- TODO: FIXME: などは動かない

## 書いた順番に表示されない

例えば紹介したコードでは、サンプルコードを一番最後に記述していますが、Quick Helpだと最初に記述していた引数や例外、戻り値などが下の方に表示されます。

## TODO: FIXME: などは動かない

ブロックコメントだとそういう仕様なので別仕様ですがコメントで

```swift
//TODO: hogehoge
```
と書けば
![todo_sample.png](https://qiita-image-store.s3.amazonaws.com/0/37274/c2dcc749-911e-d5ab-7736-deba43e9edf8.png)
と表示されますが、コメント内に 

```swift
/**
- note:
  - [JWTについて](https://~~~~)
  - TODO: hogehgoe
*/
```

とついうっかり箇条書きでTODOを書いてしまいがちですが、書いても反応しません。

この場合は

```swift
/**
- note:
  - [JWTについて](https://~~~~)
- TODO: hogehgoe
*/
```

と記載することで Quick Helpに別枠としてきちんと表示されます。
しかし、一行コメント時と同じエディタ上部のパンクズリストには出ません。

# 参考

他の詳細は下記にまとまってあります。

[Markup Formatting Reference](https://developer.apple.com/library/content/documentation/Xcode/Reference/xcode_markup_formatting_ref/index.html#//apple_ref/doc/uid/TP40016497-CH2-SW1 "Markup Formatting Reference")
MongoDB入門してみた（３）ソート

自分用備忘録

# 目的
MongoDBの検索結果をソートする方法を整理する。

# sort()コマンド

```bash:ソードコマンド
カーソル.sort(ソート条件)
```

```json:ソート条件の記法
{
    ソートに使うキー1: 1 or -1,
    ソートに使うキー2: 1 or -1,
    ...
    ソートに使うキーn: 1 or -1
}
```

1を指定すると昇順ソート、-1を指定すると降順ソート
skip()とlimit()を指定することも可能。
MongoDB入門してみた（2）インデックスの取り扱い

個人用備忘録。

# このページでわかること
MongoDBにおけるインデックスの取り扱い方法

# インデックス操作の種類

1. インデックスを確認する
2. インデックスを新規作成する
3. インデックスを削除する

# インデックスの確認

## データベース全体のインデックス確認

```bash:データベース全体のインデックス確認
use 利用するデータベース名
db.system.indexes.find()
```

となっているが、Percona server for mongodbでは表示されず。。。。。。
(明示的にインデックスを作成していないのが原因か？)

## 特定のコレクション毎のインデックス確認

```bash:コレクション毎のインデックス確認
db.コレクション名.getIndexes()
```

```json:コマンドの実行結果例
[
	{
		"v" : 1,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "test.col1"
	}
]
```
う〜ん、_idフィールドにインデックスかかっていて,
インデックス名が＿id＿、名前空間がtest.col1ってことないな
(データベース名がtest, コレクション名がcol1)

# インデックスの新規作成

```bash:インデックスの作成
db.コレクション名.createIndex(インデックス指定ドキュメント)
```

```json:インデックス指定ドキュメントの記法
{
    インデックスの対象とするキー名: 1 | -1
}
```

1を指定すると昇順のインデックス、
-1を指定すると降順のインデックスとなる。

複数のキーを指定することで、**複合インデックス**になる。

## インデックスの利用有無の確認

インデックスが利用されているかを確認する手段をしては
カーソルに対してexplainを行います。
(つまりfindの結果を変数で受けるとそれがカーソルとなるので、
それに対してexplain()を実行する)

```bash:インデックスの利用確認(explain())
db.コレクション名.find(~~~~~).explain()
```

winningPlanの内容からindexNameなどが指定されているかを確認する。

### explainの結果の例

```json:explain結果(例)
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "test.col2",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"$and" : [
				{
					"n" : {
						"$lt" : 10005
					}
				},
				{
					"n" : {
						"$gte" : 10000
					}
				}
			]
		},
		"winningPlan" : {
			"stage" : "FETCH",
			"inputStage" : {
				"stage" : "IXSCAN",
				"keyPattern" : {
					"n" : 1
				},
				"indexName" : "n_1",
				"isMultiKey" : false,
				"isUnique" : false,
				"isSparse" : false,
				"isPartial" : false,
				"indexVersion" : 1,
				"direction" : "forward",
				"indexBounds" : {
					"n" : [
						"[10000.0, 10005.0)"
					]
				}
			}
		},
		"rejectedPlans" : [ ]
	},
	"serverInfo" : {
		"host" : "69af8510a0fa",
		"port" : 27017,
		"version" : "3.2.7-1.1",
		"gitVersion" : "3bd0157c170e79dcc91b3a1525facd9eba3c9ba3"
	},
	"ok" : 1
}
```

stageでIXSCAN(IndeXSCAN)となっているので、インデックスが利用されている。
stageでCOLLSCANの場合はコレクションの全スキャンが行われている。

# インデックスの削除

```bash:インデックスの削除
db.コレクション名.dropIndex(インデクス指定ドキュメント)
```


# 補足

## 様々なインデックス

|インデックスの種類|意味|
|---|---|
|TTLインデックス|生存期間が指定されたインデックス一定時間が経過下ドキュメントは削除される|
|スパースインデックス|インデックスに指定したキーが存在しないドキュメントはインデックスの対象としないインデックス|
|地理空間インデックス|距離・包含関係・重なりなどを計算するためのインデックス|
|テキストインデックス|全文検索用インデックス(日本語の形態素解析には対応していないので基本的に日本語相手では役に立たない)|

## カバードクエリ

カバードクエリとは、インデックスの中に含まれるデータのみのアクセスで
処理が完結し、実際のドキュメントへのアクセスが発生しない場合のクエリを指す。


## 操作の情報取得

```bash:操作の情報取得
db.setProfilingLeve(プロファイリングのレベル)
```

プロファイリングのレベルは3種類

|レベル|内容|
|---|---|
|0|情報を取得しない|
|1|遅いクエリの情報のみを取得|
|2|すべての操作の情報を取得|

遅いクエリの定義は...(汗


## 操作の実行統計取得

db.setProfilingLevel()で1か2を指定した後ならば、
操作の実行統計を取得できる。(1は遅いクエリのみ、2は全クエリ)
通常の運用なら1にしておけば良い？

```bash:操作の実行統計取得
db.system.profile.find({}, {command: 1, millis: 1})
```
youtube-dlを使いやすくするScript

# 追記

### 2021/12/27

現在`youtube-dl`が遅くて使い物にならない状態ですが代わりに[yt-dlp](https://github.com/yt-dlp/yt-dlp)を用いると十分な速度で落とせました。

```shell
$ python -m pip install yt-dlp
$ python -m yt_dlp 動画のurl
```

# youtube-dlが必要なのでInstall

```
$ pip install youtube-dl
```

[youtube-dl公式site](https://rg3.github.io/youtube-dl/)

# youtube-dlを使いやすくするScript
[youtube-dl-helper.py](https://gist.github.com/gottadiveintopython/4c697595c60eb9062e10342206e8a413)

# Scriptを実行する事で作られる`history.txt`

これはDownload済みの動画のIDが記録された物で、これによって同じ動画を再び落とさずに済みます。

# Downloadが上手くいかない時

品質を表す数値を直接指定してやる事で上手くいく場合がある。

### 品質を表す数値を列挙

```
$ youtube-dl --list-format <動画のIDもしくはURL>
```

```:コマンド例
$ youtube-dl --list-format _m6U18GE1CM
```

```:出力
[info] Available formats for _m6U18GE1CM:
format code  extension  resolution note
140          m4a        audio only DASH audio  129k , m4a_dash container, mp4a.40.2@128k (44100Hz)
160          mp4        256x144    DASH video  108k , avc1.4d400b, 6fps, video only
134          mp4        640x360    DASH video  200k , avc1.4d4016, 6fps, video only
133          mp4        426x240    DASH video  242k , avc1.4d400c, 6fps, video only
135          mp4        854x480    DASH video 1155k , avc1.4d4014, 6fps, video only
137          mp4        1920x1080  DASH video 1266k , avc1.640028, 6fps, video only
136          mp4        1280x720   DASH video 2310k , avc1.4d4016, 6fps, video only
17           3gp        176x144    small , mp4v.20.3,  mp4a.40.2@ 24k
36           3gp        320x180    small , mp4v.20.3,  mp4a.40.2
43           webm       640x360    medium , vp8.0,  vorbis@128k
18           mp4        640x360    medium , avc1.42001E,  mp4a.40.2@ 96k
22           mp4        1280x720   hd720 , avc1.64001F,  mp4a.40.2@192k (best)
```

### 品質を直接指定してDownload

上の出力を見ると最高画質は1920x1080で、その"format code"は137です。又"audio only"の付いた物は一つだけで、その"format code"は140です。なので

```text
--format 137+140 --merge-output-format mkv
```

とする事で、最高品質がDownloadができます。


# 最後に

Youtube側の仕様変更に対応する為なのか、頻りに(月に数回)Versionアップしてるようです。今まで動いていたのが何故か動かなくなった時は、まずUpdateする事をお薦めします。またPCを使わずにスマホだけで落としたい場合はgoogle play storeから`Pydroid3`と`Pydroid repository plugin`を入れるとできるのでおすすめです。
Mochaを用いたJavaScriptのテスト実行

# 概要

JavaScriptでBotを実装していたら「テストコードを書くとコードがきれいになる」との助言を受けた。
今回は[mocha](https://mochajs.org/)を使ったテストの実行例を紹介する。
**なお、当エントリは「Fate/stay nighgt」および「Fate/hollow ataraxia」のネタバレを含んでいる。**

# 環境構築

```bash
npm install --global mocha
```
`package.js`への依存関係の記載が必要。

# 実装

## テスト対象となるコード
```js:src/HolyGrail.js
// 「座」に存在する英霊
const SERVANT_LIST = {
  "sheath"  : "Arthur",
  "earring" : "Cuchulain",
  "pendant" : "Emiya",
  "mirror"  : "Medusa",
  "book"    : "Medea",
  "gate"    : "Kojiro",
  "ax"      : "Hercules"
};

/**
 * @classdesc 聖杯
 */
var HolyGrail = function() {
  /**
   * 英霊召喚
   * @param {string} catalyst - 触媒
   */
  this.contract = function(catalyst) {
    var servant = SERVANT_LIST[catalyst];
    return servant;
  };
};

module.exports = HolyGrail;
```

## テストコード

```test/test.js
var assert = require('assert');

// テストスクリプトからの相対パスでrequire
var HolyGrail = require('../src/holygrail');

describe("HolyGrail", function(){
  // 凛が所持するペンダントに対応する英霊はアルトリアではない
  it("Rin tried:", function(){
      var servant = new HolyGrail();
      assert.equal("Arthur", servant.contract('pendant'));
  });
  // 士郎の体内の剣の鞘に対応する英霊はアルトリア
  it("Shiro tried:", function(){
    var servant = new HolyGrail();
    assert.equal("Arthur", servant.contract('sheath'));
  });
});
```
テストコードの書き方は以下のような感じ。

```js
it("テスト名", function(){
  var <インスタンス> = new <クラス>(<引数>);
  assert.equal(<結果>, <インスタンス>.<メソッド名>(<引数>))
})
```

今回はわざとコケるテストを書いています。

## 実行結果
```bash
-bash 19:02:43 ]mocha


  HolyGrail
    1) Rin tried:
    ✓ Shiro tried:


  1 passing (12ms)
  1 failing

  1) HolyGrail Rin tried::

      AssertionError: "Arthur" == "Emiya"
      + expected - actual

      -Arthur
      +Emiya
      
      at Context.<anonymous> (test/test.js:6:14)
```

期待通り「Rin」の英霊召喚は彼女の思い通りにはなりませんでした。

## `package.json`の`scripts`プロパティを用いたテスト実行

### `package.json`の記述（部分）
```json:package.json
  "scripts": {
    "test": "mocha"
  },
```

### 実行結果
```bash
-bash 19:06:00 ]npm test

> Sebastien@0.0.0 test /Users/wifeofvilon/Projects/mochaTest
> mocha



  HolyGrail
    1) Rin tried:
    ✓ Shiro tried:


  1 passing (10ms)
  1 failing

  1) HolyGrail Rin tried::

      AssertionError: "Arthur" == "Emiya"
      + expected - actual

      -Arthur
      +Emiya
      
      at Context.<anonymous> (test/test.js:10:14)



npm ERR! Test failed.  See above for more details.
npm ERR! not ok code 0
```

# ポイント
- mochaは特に何も指定しないと`test/`下のファイルを実行するらしい
- `module.exports`を指定しないとテストが実行できない
- 「Fate」シリーズの「クラス」概念ってすごいよね

# 参考
[MochaでJavaScriptのテストを書く - CLOVER](http://d.hatena.ne.jp/Kazuhira/20160306/1457271963)
[Node.jsでmochaやproxyquireを使った単体テストをやってみたメモ - Qiita](http://qiita.com/toshihirock/items/67e51303318d5a6030cd)
[package.json の scripts - Qiita](http://qiita.com/shuhei/items/87aadb0cc3d113b94234)
とりあえずUnityでスクリーンショットがしたい

基本的にはこちら↓の記事を参考にすると良いかと思います！
[Unityで画面のスクリーンショットを撮る(Application.CaptureScreenshotじゃない方法)](http://qiita.com/tempura/items/e8f4bbb4419407916d12)

一番簡単な「Application.CaptureScreenshot」をやったんですが、正直３時間ハマりました。あはー

ハマった原因は、Android6.0以上のパーミッションの件です。
Androidアプリ開発者ならご存知かと思いますが、TargetSDKがAndroid6以上の場合は、パーミッションの確認が必要ですよね。。。

自分の端末はNexus5X(Android7.1.1)だったため、バッチリ当てはまっちゃいました。あはー

# Android6以上端末で、とりあえずスクリーンショットがしたい
1. Write AccessをExternal(SDCard)に変更 
    * 場所は→ Build Settig > Player Setting > Configuration > Write Access
2. Application.CaptureScreenshot("screenshot.png")をボタンなどにアタッチ
3. スクリーンショットメソッドの前にandroid.permission.WRITE_EXTERNAL_STORAGEのパーミッション許可を実装する
    * 参考1：[UnityでAndroid6.0におけるパーミッションを対応する](http://freelyapps.blog.jp/archives/1052604413.html)
    * 上記記事にも記載があるが、supportv4が必要なので、ファイルの追加、フォルダの追加を行う必要がある。フォルダについての参考：[Unityの特殊フォルダと各々の役割](http://tsubakit1.hateblo.jp/entry/20131026/1382759405)
    * 参考2：[UnityでRuntimePermissionを実装する](http://smartgames.hatenablog.com/entry/2016/03/22/232819)
    * とりあえずスクリーンショットの動きが見たいのであれば、3は一旦実装せずに、2の状態でビルドして、設定のアプリ一覧で当該アプリを選択して、権限一覧のストレージ項目をON状態にして、アプリでスクリーンショットを実行すればOK
WebGLでモアレを作ってみる

正月休み最終日です。去年はインプットばっかりでなかなか作ることができていなかったので、今年はアウトプットを増やしていきたいと思います:muscle:

新年一発目の記事は、前々から作れそうだなぁと思っていたモアレをWebGLで実装してみました〜ほんとはWebGLのアドカレに参加したかったんですけど[別の](http://qiita.com/advent-calendar/2016/fusetools)で忙しく、間に合いませんでした。。

そもそものきっかけは一昨年のアドカレでdoxasさんが書いていた[これ](http://qiita.com/doxas/items/caaa7471ad2d08571579)をみて、なるほど、こういうこともできるのか、と思い立ちやってみた次第であります。

###モアレとはなにか

[モアレ - wikipedia](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%82%A2%E3%83%AC)より

> モアレまたはモワレ（仏: moiré）は、干渉縞ともいい、規則正しい繰り返し模様を複数重ね合わせた時に、それらの周期のずれにより視覚的に発生する縞模様のことである。

文章だけ見てもなんのこっちゃという感じなので、WebGLモアレ第１弾として目標とした画像をはっつけておきます。

<img src="https://github.com/tkskto/webGLMoire/blob/images/document/moire3b.jpg?raw=true">

出典:[正多面体クラブ](http://www.h7.dion.ne.jp/~kagaku/moire/moire.html)

いわゆるパンチングボードというやつを2枚重ねて、ずらしてあげると干渉縞が浮かび上がります。

###デモ

ブラウザで見るとこんな感じです。

![01.png](https://qiita-image-store.s3.amazonaws.com/0/100937/afac8299-9141-ffce-333d-c09219447799.png)

GitHub Pagesで[デモ](https://tkskto.github.io/WebGLMoire/)をアップしました。マウスでクリックしながら上下に動かすと、上(手前？)に配置したボードが回転するようになっています。一応スマホでも見れます。

###感想

先に言っておきますが、WebGLでやることに特に意味はないですし、実用性もないと思います。画像でよくない！？と言われればそれまで。自己満です:nail_care:

まず、穴あき水玉模様を作らないとなぁと思い、Shadertoyで[検索](https://www.shadertoy.com/results?query=Polka)しました。その中から一番シンプルな[こちら](https://www.shadertoy.com/view/ldXSRs)を参考にさせてもらってます。

そこまで難しくない（自分にとっては難しかった）と思いますが、フラグメントシェーダだけ載せておきます。

```shader
precision mediump float;

const float rad = 0.3; //白い円の半径
const ivec2 reps = ivec2(20, 20); //intのvec2 縦横何分割するか（１辺の円の個数/2）
const float angle = 45.0; // 全体の傾き
const float RADIANS = angle * 0.0174532; // 傾きをラジアンにする
mat2 rot = mat2(vec2(cos(RADIANS), -sin(RADIANS)), vec2(sin(RADIANS), cos(RADIANS))); //傾けるための正方行列

uniform vec3 color; //ボードの色
varying vec3 vPos; //座標変換後のポジションを受け取る

void main(){
    vec2 p = vPos.xy;
    p *= rot; //全体を傾ける

    //原点からピクセルの長さを測るときに、距離を0~1にするための処理
    vec2 repeat = vec2(fract(p.x * float(reps.x)), fract(p.y * float(reps.y)));
    vec2 distFromMid = repeat - vec2(0.5); //中心点を基準にする
    float dist = length(distFromMid); //原点からの距離をとる

    //半径分移動させて白黒はっきりさせる
    float sharpness = 20.0;
    float circ = (rad - dist) * sharpness;
    float alpha = 1.0 - circ;

    gl_FragColor = vec4(color, alpha);
}
```

同じものを2回レンダリングして重ね、上の面だけマウスイベントでz軸回転させています。
もしかしたら、面を回転させるんじゃなくて、2つの面の間に少しスペース空けて、視点を動かした方がより自然かもしれないな・・・:thinking:

最初はステンシルバッファを試したくて始めたんですが、意外とめんどくさくて、結局シェーダでやってしまいました。。ステンシルを使ったやり方で作ったよってコメントをお待ちしています:santa_tone5:

ということで、本年もよろしくお願い致します。
rbenv install がうまく動作しなかった時の対処法

##前置き
Rubyのバージョン変更を行おうとしたら、変更したいバージョン（ここでは2.3.3）が見当たらず、Rubyの2.3.3がインストールできない。。。という状況に陥ってしまったので、自分用のメモとして残します。

##現象
```
$ brew update
$ brew upgrade ruby-build
$ rbenv install —l
$ rbenv install 2.3.3
```

としても

No such file or directory -- install (LoadError)

という悲しいエラー（そんなファイルやディレクトリはありません、というもの）が出てしまい、あたふたしながらググることになりました。

その結果

```
$ cd ~/.rbenv/plugins/ruby-build
$ git pull
```

とコマンドを打てば不足しているバージョンのものも追加してくれることが判明しました。

あとは
####インストール
```
rbenv install 2.3.3
```
####インストール済みのrbenvを確認する
```
rbenv versions
```
####bundlerのインストール
```
gem update bundler
gem install bundler
```
####gem 再インストール
```
bundle install
```

これでなんとか更新することができました。
ご参考になれば幸いです。
NumberPicker の DisplayItems の増減が面倒すぎる


[``NumberPicker``](https://developer.android.com/reference/android/widget/NumberPicker.html) には数値だけじゃなくて ``setDisplayedValues`` で数値以外の任意の文字列を項目群として設定できる。

以下のようにすると、 NumberPicker には 「A, B, C」が表示される。

```java:
final List<String> words = Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O");
final NumberPicker numPicker1 = (NumberPicker)findViewById(R.id.numPicker1);

numPicker1.setMinValue(0);
numPicker1.setMaxValue(2);
String[] displayWords = words.subList(0, 3).toArray(new String[3]); // A,B,C
numPicker1.setDisplayedValues(displayWords);
```

項目群を、 A,B,C から A,B,C,D に増やしたいときに、下のようコードを書くと、

```java:
final Button buttonAdd = (Button)findViewById(R.id.buttonAdd);
buttonAdd.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        int newMax = numPicker1.getMaxValue() + 1;
        String[] displayWords = words.subList(0, newMax + 1).toArray(new String[newMax]);

        numPicker1.setMaxValue(newMax);
        numPicker1.setDisplayedValues(displayWords);
    }
});
```

``setDisplayedValues`` で ``ArrayIndexOutOfBoundsException`` が出て落ちる。

> E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: net.amay077.numberpickersample, PID: 3828
                  java.lang.ArrayIndexOutOfBoundsException: length=4; index=4
                      at android.widget.NumberPicker.ensureCachedScrollSelectorValue(NumberPicker.java:1825)
                      at android.widget.NumberPicker.initializeSelectorWheelIndices(NumberPicker.java:1640)
                      at android.widget.NumberPicker.setMaxValue(NumberPicker.java:1445)
                      at net.amay077.numberpickersample.MainActivity$1.onClick(MainActivity.java:36)

項目を増やすときは、``setMaxValue`` よりも  ``setDisplayedValues`` を先に呼ばないといけないらしい。

```java:
final Button buttonAdd = (Button)findViewById(R.id.buttonAdd);
buttonAdd.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        int newMax = numPicker1.getMaxValue() + 1;
        String[] displayWords = words.subList(0, newMax + 1).toArray(new String[newMax]);

        // 増やすときは先に setDisplayedValues
        numPicker1.setDisplayedValues(displayWords);

        numPicker1.setMaxValue(newMax);
    }
});
```

逆に、項目を減らすときは、``setMaxValue`` よりも  ``setDisplayedValues`` を後に呼ばないといけないらしい。

```java:
final Button buttonRemove = (Button)findViewById(R.id.buttonRemove);
buttonRemove.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        int newMax = numPicker1.getMaxValue() - 1;
        String[] displayWords = words.subList(0, newMax + 1).toArray(new String[newMax]);

        numPicker1.setMaxValue(newMax);

        // 減らすときは後で setDisplayedValues
        numPicker1.setDisplayedValues(displayWords);
    }
});
```

![](http://blog.amay077.net/assets/images/posts/android_numberpicker_01.gif)

項目が増えたときと減ったときで、呼び出しの順番を変えないといけないのが面倒すぎる。
Google Chrome の 拡張機能にまったく目を向けてこなかった

<font color=red><b>以下の記事にて世界が変わりました。</b></font>

[【2017年版】Google Chromeを10倍魅力的にする拡張機能【おすすめ】 - Sub.colle](http://www.subcolle.com/entry/chrome_function)

そりゃぁこういったものはあるのでしょうけど。
今までまったく目を向けてこなかったのです。

これで、自分自身の普段の作業効率も良くなりますし、なによりこちらの開発も面白そうです。

特に最近英語周りで苦労している分上記記事では翻訳関連の拡張機能を紹介してくださっていましたので、格段に便利になりました。

ちなみに、ただしくはChromeエクステンションでしょうか。
Qiitaのタグ付けで"chrome-extension"とありましたので、付けてみました。

以上

|前回|一覧|次回|
|:--|:--:|--:|
|(ここがスタート)|[シリーズ一覧](http://qiita.com/rrryutaro/items/015b67568ddd947ec2b5)|[はじめのいっぽ](http://qiita.com/rrryutaro/items/bcfc0e593914e8ba0a9a#_reference-3bf2614c502705f1a84c)|
Windows で IRuby Notebook 環境を構築する方法 2017年版

以前 [Bash on Ubuntu on Windows で IRuby Notebook を使う](http://qiita.com/kozo2/items/447d5edb6e3eb83268f0#_reference-3a4418285413867f39af) 方法を紹介しましたが，IRuby に新たなzeromq backendが追加される見込みなので，その新zeromq backend(**cztop**)を利用した(ネイティブ)インストール方法を紹介します．

この記事は未完成のものであり，近いうちに実現されるであろうIRubyの更新により簡略化される見込みです．

## Ruby のインストール

[RubyInstaller](https://rubyinstaller.org/downloads/) をダウンロード，インストールしてください．

## cztop のインストール

gemコマンド一発です．zeromqもcztopが依存するgem(czmq-ffi-gen)内に含まれており別途installする必要はありません．またパスを通すといった設定も不要です．
devkitも(このインストールには)必要ありません．あらかじめコンパイルされたバイナリを含むfat-gem形式のczmq-ffi-genがrubygems.orgにdeployされているためです．

スタートメニューから「Rubyコマンドプロンプトを開く」を実行し下記のコマンドを入力してください

```
gem install cztop
```

## IRuby のインストールとJupyter Notebook用Ruby kernelの登録

IRubyが依存するbondというgemはdevkitが必要です．
ですが私はこの依存は除くことが可能と見ています．
とりあえず現状はdevkitをinstall後，
スタートメニューから「Rubyコマンドプロンプトを開く」を実行し下記のコマンドを入力してください．
(まだcztopサポートが反映されたgemがリリースされていないためgitとspecific_installも必要になります．)

```
gem install specific_install
gem specific_install https://github.com/SciRuby/iruby.git
iruby register
```

## Jupyter Notebookのインストール

Jupyter Notebookは
- Anaconda, Miniconda
- python.org が配布しているPythonインストーラーに同梱のpip
どちらを使ってインストールしても構いません．Pythonのメジャーバージョンも2でも3で構いません．

condaの場合 `conda install jupyter`
pip の場合 `pip install jupyter`
でinstallできます

## IRuby Notebookの実行
condaの場合，Jupyter Notebookはスタートメニューに登録されここから立ち上げることが可能です．
もしスタートメニューに見つからない場合はコマンドプロンプトもしくはPowershellから
```
jupyter-notebook
```
を実行してください．
もしこのコマンドにパスが通っていない場合はエクスプローラーでjupyter-notebookを検索しそのパスを環境変数PATHに追加してください．

あとは新規Notebookの作成時にRubyのkernelを選択すればOKです．
やっぱり11acは速い!

* [MacユーザがPC自作してFreeBSD入れてみた](http://qiita.com/tenomoto/items/4774eaf16c5aa4cdd64c)
* [MacユーザならWindow Makerでしょ](http://qiita.com/tenomoto/items/b8fb40cf35e1e6eba335)
の続き。

# 敗北...

[TP-Link TL-WN725N](http://amzn.to/2i1tGLS)で我が家の[Time Capsule](http://amzn.to/2itvAXO)に接続していました。ウェブを見るには快適に使っていたのですが、Macから写真や音楽のファイルをrsyncで転送するとよく切断してしまいました。-POWERSAVEを指定しても効果なさそうでした。転送はLANケーブルで直結して済ませたのですが、時々途切れるのは不安。それから[Time Capsule](http://amzn.to/2itvAXO)は11acに対応しているので、11acで接続したいという誘惑。でもFreeBSDの11acのサポートは十分ではなさそう。そこで安直に無線ルータを導入して、自作機には有線で接続することにしました。

# 無線LANルータ選び

モバイルルータを使っていたので管理画面に馴染みがあるNECの[AtermWG1200HP](http://amzn.to/2ixYF2n)を選択。より高速なものも出ていますが、[Time Capsule](http://amzn.to/2itvAXO)より速い機種は意味ないので、安いものでよいかと考えました。一応11acでデュアルアンテナ搭載。似た型番の[1200HSは中継機能がない](https://121ware.com/product/atermstation/product/comparison.html)ので要注意。

# 設定

手持ちのMacBookを使って、次のように設定しました。

1. [つなぎかたガイド](http://www.aterm.jp/support/manual/wg1200hp/index.html)をみてスイッチをCNVにして電源をON。
2. MACアドレスフィルタリングしているので、MacBookのAirMacユーティリティで[Time Capsule](http://amzn.to/2itvAXO)に[AtermWG1200HP](http://amzn.to/2ixYF2n)のMACアドレスを登録して再起動。MACアドレスは5GHzのものと2.4GHzのものがあるが5GHzで接続するように5GHzのものを登録。
3. MacBookと有線で接続。MacBookには適当なIPを入れ、[AtermWG1200HP](http://amzn.to/2ixYF2n)に入り、[Time Capsule](http://amzn.to/2itvAXO)のSSIDとパスワードを登録。
[追記] 説明書によると、らくらくスタートポタンを押しながらDHCPモードにしてDHCPサーバを起動させるべきでした。
4. 自作機の/etc/rc.confを編集。Wifi関係の行はコメントアウト。

```/etc/rc.conf
ifconfig_em0="SYNCDHCP"
#wlans_urtwn0="wlan0"
#ifconfig_wlan0="HT WPA SYNCDHCP -POWERSAVE"
```
5. 再起動。

Firefoxを使ってみましたが、ページが瞬時に表示されました。爆速!

# 中継機能について追記 

* あれっ、オフのはずの子機のSSIDが見える... 2.4GHzのSSIDは親機と接続している5GHzとは別なのが既定でした。セキュリティキー等を一緒にするように警告が出ますが、SSIDは編集できました。
* 場合によって2.4Gzでも親機と接続できるように、[Time Capsule](http://amzn.to/2itvAXO)に[AtermWG1200HP](http://amzn.to/2ixYF2n)のSSIDを追加しておきました。
* 既定のIPで管理画面に入るために、[AtermWG1200HP](http://amzn.to/2ixYF2n)のらくらくスタートボタンを押して電源を入れ直しDHCPサーバ機能を起動しなければならないのが面倒でした。DHCPサーバ機能を入れるということは、普段はクライアントなはずだと考え、IPアドレスを推測して接続したらつながりました。
* う〜んやっぱり思った通りに設定するのは簡単でない... [無線LANビジネスから撤退](https://www.bloomberg.com/news/articles/2016-11-21/apple-said-to-abandon-development-of-wireless-routers-ivs0ssec)しないで下さい=>Appleさん
AngularJSで複数ファイルの一括アップロード


## はじめに
AngularJSでファイルアップロードする場合に１ファイルのみアップロードするのサンプルソースは多くありましたが、複数ファイルの一括アップロードのソースは全くありませんでした。
今回はAngularJSで複数ファイルの一括アップロードを行う場合の注意点をまとめました。
[AngularJSでファイルをアップロードする](http://qiita.com/zaburo/items/f03433caa710902d599f)の記事にあるサンプルソースから必要な変更点のみを記載します。

## 変更点
### inputタグにmultiple属性を追加
 
```
<input type="file" file-model="file" multiple="multiple">
```

### fileModelのdirectiveでfileオブジェクトのassign方法を変更

配列の先頭のみ値のみを設定していたところを、配列ごと設定するようい変更する。

```
model.assign(scope,element[0].files);
```

### Post時にFormDataに全てのファイルオブジェクトを設定する
上記の変更で、$scope.fileは単一ファイルオブジェクトから配列のファイルオブジェクトになったため、Postする際は以下のように個別にappendする。

```
var data = new FormData();
if ($scope.file) {
    for (var i = 0; i < $scope.file.length; i++) {
        data.append('file' + i, $scope.file[i]);
    }
}
```

## 最後に
上記の変更で、サーバ側へリクエスト時に選択した複数のファイルを送信することが可能です。
複数ファイルの一括アップロード時に参考にしてみてください。

## 参考
* [AngularJSでファイルをアップロードする](http://qiita.com/zaburo/items/f03433caa710902d599f)
* [HTML5 File API とAngularJSで画像をアップロード前にプレビュー](http://labs.septeni.co.jp/entry/20150309/1437473852)
Dockerはrunでbashrcが反映されずに困ったマヌケな話

こんにちはみなさん

いや、ホント、タイトル通りなんですが、しょうもないことでハマりまして。

Laradockを使っている人が増えてきたようで、私としては嬉しいところです。
そんなLaradockのworkspaceが使いやすいので、CIでも使っていたのですが、node系のコマンドを使う際に全然動かず、jsやcssのビルドができない事態に陥りました。

# 経緯

1. CIでLaradockのworkspaceを利用してアプリケーションのビルドとデプロイをしようとした
2. composerを使ってテストを走らせるところまではうまく行った
3. node系のnpmやbowerを使おうとしたら、エラーが出て失敗してしまった

エラーはこんな感じです。

```
$ docker run --rm workspace node
container_linux.go:247: starting container process caused "exec: \"node\": executable file not found in $PATH"
docker: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused "exec: \"node\": executable file not found in $PATH".
```

# 原因
タイトルでも書いてありますが、bashの対話シェルで実行しているわけではなく、`docker run`にてダイレクトにコマンドが実行されているため、.bashrcや.profileにある設定を読み込んでいないため、nodeの実行コマンドへのパスが通っていないという事態になっていました。

# 解決策(?)
全然応用きかないですが、Laradockのworkspaceの現在の構造を見るに、

```sh:buildnode
#!/bin/bash

. $NVM_DIR/nvm.sh && $*
```
こんな感じのスクリプトファイルを用意して

```Dockerfile
FROM laradock_workspace:latest
MAINTAINER Niisan <niisan@me.com>

COPY buildnode /usr/local/bin
RUN chmod +x /usr/local/bin/buildnode
```
みたいな感じの構成でLaradockのdocker-composeで生成されたイメージを基に別途イメージを作ってしまいます。
そうすると、

```
$ docker build -t niisantokyo/laradock_ws .
$ docker run -it --rm niisantokyo/laradock_ws buildnode node -v
v7.3.0
docker run -it --rm niisantokyo/laradock_ws buildnode npm -v
3.10.10
```
こんな感じでなんとか行きました。
Jupyter(IPython)上でメモリ食っている変数を探し出して削除する

# メモリ食ってる変数を確認・削除したい

Jupyter(IPython)上でデータ解析などを行っていると、データがメモリ上にどんどん蓄積されていくので、メモリを食っている変数を確認したくなる。
そのような時に以下のコマンドを実行すると、変数とその変数のメモリ容量を一覧にして表示してくれる。

```py:Python2
import sys

print "{}{: >25}{}{: >10}{}".format('|','Variable Name','|','Memory','|')
print " ------------------------------------ "
for var_name in dir():
    if not var_name.startswith("_"):
        print "{}{: >25}{}{: >10}{}".format('|',var_name,'|',sys.getsizeof(eval(var_name)),'|')
```

```py:Python3
import sys

print("{}{: >25}{}{: >10}{}".format('|','Variable Name','|','Memory','|'))
print(" ------------------------------------ ")
for var_name in dir():
    if not var_name.startswith("_"):
        print("{}{: >25}{}{: >10}{}".format('|',var_name,'|',sys.getsizeof(eval(var_name)),'|'))
```


出力結果は以下のような感じになる。
* * *
<img width="1156" alt="スクリーンショット 2017-01-03 17.34.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/88804/d2b7658e-b602-e74f-8bf5-658994371796.png">
* * *

しかしこのコマンドだとJupyter上で定義している全ての変数の結果が出力されてしまうので、例えば「メモリ容量がある一定の値以上の変数だけを取り出してほしい」と思ったら以下のようにアレンジする。

```py:Python2
import sys

print "{}{: >25}{}{: >10}{}".format('|','Variable Name','|','Memory','|')
print " ------------------------------------ "
for var_name in dir():
    if not var_name.startswith("_") and sys.getsizeof(eval(var_name)) > 10000: #ここだけアレンジ
        print "{}{: >25}{}{: >10}{}".format('|',var_name,'|',sys.getsizeof(eval(var_name)),'|')
```

```py:Python3
import sys

print("{}{: >25}{}{: >10}{}".format('|','Variable Name','|','Memory','|'))
print(" ------------------------------------ ")
for var_name in dir():
    if not var_name.startswith("_") and sys.getsizeof(eval(var_name)) > 10000: #ここだけアレンジ
        print("{}{: >25}{}{: >10}{}".format('|',var_name,'|',sys.getsizeof(eval(var_name)),'|'))
```

すると、

* * *
<img width="1095" alt="スクリーンショット 2017-01-03 17.39.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/88804/a182645c-6585-c058-8686-93bc059def11.png">

* * *

この通り、メモリ容量が大きい変数だけを抽出することが出来る。

ここまで出来たらあとは、

```py
del U_Global, V_Global
```

のように、いらない変数を指定して削除していったらいい。
メモリを開放して、快適にJupyter(IPython)上で解析を継続することが出来る。

# 備考

タイトルでは「Jupyter(IPython)上で」と銘打っていますが、他のインターフェースでも恐らく同じように表示してくれるかと思います。
ただし、str.format()を使用しているため、正しく出力されるにはPython2.6以上である必要があります。


# 参考URL

 - http://docs.python.jp/2/library/sys.html
 - http://qiita.com/Kodaira_/items/30c84806b61792b613f2
 - http://stackoverflow.com/questions/33978/find-out-how-much-memory-is-being-used-by-an-object-in-python
 - http://stackoverflow.com/questions/633127/viewing-all-defined-variables
 - http://stackoverflow.com/questions/9989334/create-nice-column-output-in-python
【社内SE向け】どんな問い合わせがきてもOKなヘルプデスク・サポートデスクになる方法

## 最強のフローチャート図

とりあえず質問や問い合わせが来たら、下の図に沿って対応しましょう。

>![tech_support_cheat_sheet_ja.png](http://railstutorial.jp/chapters/images/figures/tech_support_cheat_sheet_ja.png)
>[Ruby on Railsチュートリアル](http://railstutorial.jp/chapters/beginning?version=5.0#sec-introduction)より

上の図は一見ふざけてるように見えるかもしれませんが、重要な示唆に富んでいる…と思うので詳しく内容を見ていきましょう。

## その人たちの質問に関係ありそうなメニューなりボタンなりが画面にあるか?

まずは相談に来た人に、実際の画面を見せてもらいましょう。
システムトラブルは言葉では説明するのが難しいものです。
あれこれ質問するよりも、実際に画面を見てしまえば、一発で原因を理解してしまうことも多々あります。

PCが手元になかったり、電話口で実際の画面が見られないようなときは、以下のような方法もあります。

+ 画面をキャプチャして、メールで送ってもらう
+ スマートフォンやデジカメでモニターの写真を撮ってメールで送ってもらう
+ 画面に表示されてる文字、画像をとにかく全部コピペしてメールしてもらう
+ リモートデスクトップなどで接続して直接操作する
+ 画面に出てるメッセージを何でもいいから読み上げてもらう

百聞は一見にしかずと言いますし、まずは画面を見てみることが解決への最短ルートです。

## これかな？　⇒　クリック・クリック・クリック…

怪しいと思うところや、原因だと思われるところをとりあえずクリックしてみよう。
クリックすると何かメッセージが出るかもしれません。YesかNoで答えるボタンが出てくるかもしれません。
メッセージが出てきたら、よく読んでクリックしよう。YesかNoか聞かれたらとりあえずYesを押してみよう。

どこをクリックしていいかわからない時は、以下のような場所をクリックしてみるといいかもしれません。

+ ボタン
+ メニューバー
+ リンク
+ 画像
+ 表
+ 猫ちゃんマーク

まれにクリックするとデータが吹っ飛んだりするボタンがあるかもしれません。
そんなボタンを用意しとくアプリケーションが悪いと思いましょう。
まあ、そんなことはめったにないので、とりあえずクリックしてみましょう。

## ねーよそんなの　⇒　何でもいいから試す

クリックする以外にもアプリケーションを動かす方法はあります。

キーボードで何か入力してみましょう。CtrlキーやShiftキーと、なにか適当なキーを組み合わせて入力すると、何か起きるかもしれません。

Siriのように話しかけてあげると、なにか反応があるかもしれません。

何も反応がないなら、再起動してみましょう。再起動は誰でもできる強力なトラブルシュートです。
ただ単にフリーズしてしまっているだけかもしれません。
とりあえず再起動してみようぐらいの感覚で、やってみるとあっさり解決したりします。

## もう全部ためしたぜ　⇒　問題のプログラム名にキーワードを適当に追加してググれ、なにか見つかったらそれをとにかくやってみろ

[Google](https://www.google.co.jp/)にアクセスして、とにかく検索してみよう。エラーやメッセージが出ているならば、それをコピペして検索しよう。

きっと何かしら検索結果が出てくることでしょう。

それらしい解決策がヒットしなかったら、キーワードを追加したり、削除したり、変えたりしてまたググろう。

そのうち親切なサイトにめぐり合えるでしょう。そういうサイトはブックマークしておいて、後で見返せるようにしとくといいでしょう。

## うまくいった？　⇒　だめだ～　⇒　30分経過した？

30分というのはあくまで目安なので、この数字は適宜読み替えよう。

ある程度自分のなかで時間を決めて対応することは、だらだらと解決しないまま時間が過ぎていくよりよっぽどいいし、効率的です。

時間は有限だし、もっと価値ある仕事のためにも、効率的な時間の使い方をしましょう。

そして30分経っても解決しないようであれば、あきらめよう。直接問題が解決しなくても、以下のような方法でその場を凌ぐこともできます。

+ 別のPCを使ってもらう
+ 別のブラウザーを使ってもらう
+ 明日また対応しますと先延ばしする
+ 誰か自分より頭がよさそうな人に丸投げする
+ 誰か自分より立場が下の人に丸投げする
+ ゴメンで済ます

##  うまくいった？　⇒　いった　⇒　うっしゃ終了!

うまくいったならばあなたの仕事はひとまず終わりです。お疲れ様でした。

しかし、人間というものは一度苦労して対応したトラブルでも、時間が経つと、あの時どうやって解決したっけ？と忘れてしまうものです。

忘れないうちにメモ帳にでも記録を残しておきましょう。できれば誰かと共有するために、ドキュメントとして残しておきましょう。

## おわりに

もともと上司からヘルプデスクのマニュアルを作って欲しいと、前々から言われていました。

でも個別のトラブルに対して、いちいち解決策を書いていくのも芸がないしキリがないなあと思い、このような記事を書いてみました。
twitchの動画や音声を落とす

# 何故そんな事がしたい？

普段よくmobile端末でtwitchやyoutubeの外国語動画をBGMとして聴くのですが、母国語では無いため当然一回では理解できず何度も聴く事になります。そうなるとネットワークを無駄遣いしないためにも、また端末の消費電力を抑えるためにも一度落としてしまった方が効率が良いのは明らかです。というわけで今回はそういった事をするためのscriptを公開します。

# やり方

この[script][script]を落としたら、script内の大文字の変数達(`QUALITY`,`TMP_DIR`,`OUTPUT_DIR`)を自分好みに書き換えてから

```
python ./twitch_downloader.py https://www.twitch.tv/videos/123456789
```

という風に動画のURLを渡して実行するだけです。ただ多くのtwitch動画には序盤に無駄な部分(「あと○分で配信が始まるよ」みたいなやつ)があるので次のようにしてその部分を取り除くのがお薦めです。

```
(序盤の6分が要らない場合のコマンド例)
python ./twitch_downloader.py https://www.twitch.tv/videos/123456789 --offset=00:06:00
```

また必要に応じて`--duration`も使って必要な部分だけを切り取りとってあげます。

```
(序盤の6分を捨てて、そこから1時間分だけを落としたい時のコマンド例)
python ./twitch_downloader.py https://www.twitch.tv/videos/123456789 --offset=00:06:00 --duration=01:00:00
```

# その他

#### 配信用の制御情報は自動で削いでくれる

twitchから落とした動画には配信のため制御情報が含まれているせいなのか、落とした物を再エンコード無しで別のファイルに書き出すだけでファイルサイズが20%〜30%減ります。その作業は基本scriptが自動でやってくれるのですが、念の為に手動で行う方法も載せておきます。

```
ffmpeg -i 入力元ファイル -vcodec copy -acodec copy 出力先ファイル
```

[script]:https://gist.github.com/gottadiveintopython/b28fd7aef66b7ebcd7b188b34c18ff9e
音声認識を利用する

# Voice Control Using Win10-MS Speech Platform-RaspberryPi in Hackster.io

[Voice Control Using Win10-MS Speech Platform-RaspberryPi - Hackster.io](https://www.hackster.io/naadydev/voice-control-using-win10-ms-speech-platform-raspberrypi-32af97?ref=search&amp;ref_id=windows%20iot%20voice&amp;offset=2 "Voice Control Using Win10-MS Speech Platform-RaspberryPi - Hackster.io")

![](https://hackster.imgix.net/uploads/attachments/221468/iazVIfHNqrzGc7zh9Fx7.uploads/tmp/96ecc4f0-1e55-40ff-9e16-72aaac7d923a/tmp_image_0?auto=compress%2Cformat&w=900&h=675&fit=min)

音声認識の API <a href="https://msdn.microsoft.com/ja-jp/windows/uwp/input-and-devices/speech-recognition">Windows.Media.SpeechRecognition</a> を使って、LED を点灯したり、部屋の明かりをつけたりするサンプルです。音声認識自体は、Windows 10 に含まれているので通常の PC でも動作します。

あらかじめ、認識する単語を grammar.xml な形で用意しておいて、音声認識をさせる方式ですね。日本語が通るのかはわからないのですが、英語の例があります。

[naadydev/Voice-Control-IOT-RaspberryPi-Win10-MS-Speech-Platform: Simple Example for Control Anything Using Voice Control ( WIn10 IOT - MS Speech Platform - RaspberryPi )](https://github.com/naadydev/Voice-Control-IOT-RaspberryPi-Win10-MS-Speech-Platform "naadydev/Voice-Control-IOT-RaspberryPi-Win10-MS-Speech-Platform: Simple Example for Control Anything Using Voice Control ( WIn10 IOT - MS Speech Platform - RaspberryPi )")


```csharp
// Initialize Speech Recognizer and start async recognition
private async void initializeSpeechRecognizer()
{
    // Initialize recognizer
    recognizer = new SpeechRecognizer();

    #region Create Events
    // Set event handlers
    recognizer.StateChanged += RecognizerStateChanged;
    recognizer.ContinuousRecognitionSession.ResultGenerated += RecognizerResultGenerated;
    #endregion

    #region Load Grammer

    // Load Grammer file constraint
    string fileName = String.Format(SRGS_FILE);
    StorageFile grammarContentFile = await Package.Current.InstalledLocation.GetFileAsync(fileName);

    SpeechRecognitionGrammarFileConstraint grammarConstraint = new SpeechRecognitionGrammarFileConstraint(grammarContentFile);

    // Add to grammer constraint
    recognizer.Constraints.Add(grammarConstraint);
    #endregion

    #region Compile grammer
    SpeechRecognitionCompilationResult compilationResult = await recognizer.CompileConstraintsAsync();
    Debug.WriteLine("Status: " + compilationResult.Status.ToString());

    // If successful, display the recognition result.
    if (compilationResult.Status == SpeechRecognitionResultStatus.Success)
    {
        Debug.WriteLine("Result: " + compilationResult.ToString());

        await recognizer.ContinuousRecognitionSession.StartAsync();
    }
    else
    {
        Debug.WriteLine("Status: " + compilationResult.Status);
    }
    #endregion
}
```

これも PC にマイクをつけて常時起動しておけば済むはなしですが、Raspberry Pi で Windows IoT Core を使うことで電力量を減らすことができます。

サンプルに GPIO へ ON/OFF を流すほかにも、WiFi で飛ばしたり、Bluetooth を使ったり、赤外線を使ったりすることができるでしょう。
cocos2d-x(WinRT) UWP開発で2回目のBGMの再生でエラーが起きる　※バグ報告とエラー回避方法

#cocos2d-x(WinRT) UWP開発で2回目のBGMの再生でエラーが起きる

原因：cocos2d-xのバグです。
BGMを再生するときにLocalStateフォルダにキャッシュファイルを作成しています。
それを読み込む機能がまだUWP(WinRT)では足りてないことが原因でした。


ファイル名+ハッシュ値+.bat
bgm01_131278991235742657131278997873415683.dat

C:\Users\*****\AppData\Local\Packages\A2488D1E-A992-4F30-97A0-6C68D4046731_e8xk87pxx0yyw\LocalState
この中にBGMを再生させるだけでキャッシュファイルが作成され保存されます。
この仕組みは、たぶん再生時間の長いファイルに対して行われる仕組みに感じます。
SEなども同じ処理を通るのですが、キャッシュファイルは作成されていませんでした。

問題なのは、そこへ参照するためのPathが変でした。
キャッシュファイルを参照して読み込めずにいるからエラーが出てました。

誤り coin_getの前に//が入っている
C:/Users/****/AppData/Local/Packages/A2488D1E-A992-4F30-97A0-6C68D4046731_e8xk87pxx0yyw/LocalState//coin_get_131278900066040543131278993999933544.dat

正しい coin_getの前は/だけ
C:/Users/****/AppData/Local/Packages/A2488D1E-A992-4F30-97A0-6C68D4046731_e8xk87pxx0yyw/LocalState/coin_get_131278900066040543131278993999933544.dat



```c++:cocos2d-x-3.13.1\cocos\platform\winrtCCWinRTUtils.cpp
std::string computeHashForFile(const std::string& filePath)
{
    std::string ret = filePath;
	size_t pos = ret.find_last_of('/') + 1; //← +1してあげて / が入らないようにしてください。これがあると//になってエラーが起きます

	if (pos != std::string::npos) {
		ret = ret.substr(pos);
	}

    pos = ret.find_last_of('.');

    if (pos != std::string::npos) {
        ret = ret.substr(0, pos);
    }

    CREATEFILE2_EXTENDED_PARAMETERS extParams = { 0 };
    extParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
    extParams.dwFileFlags = FILE_FLAG_RANDOM_ACCESS;
    extParams.dwSecurityQosFlags = SECURITY_ANONYMOUS;
    extParams.dwSize = sizeof(extParams);
    extParams.hTemplateFile = nullptr;
    extParams.lpSecurityAttributes = nullptr;

    Microsoft::WRL::Wrappers::FileHandle file(CreateFile2(std::wstring(filePath.begin(), filePath.end()).c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &extParams));

    if (file.Get() != INVALID_HANDLE_VALUE) {
        FILE_BASIC_INFO  fInfo = { 0 };
        if (GetFileInformationByHandleEx(file.Get(), FileBasicInfo, &fInfo, sizeof(FILE_BASIC_INFO))) {
            std::stringstream ss;
            ss << ret << "_";
            ss << fInfo.CreationTime.QuadPart;
            ss << fInfo.ChangeTime.QuadPart;
            ret = ss.str();
        }
    }

    return ret;
}
```

上記の修正だけではエラーが起きます。
ファイルサイズを取得する部分が記述されていないためエラーが起きます。
一時的に回避するためにキャッシュファイルを読み込む部分をコメントアウトして対応します。

```c++:cocos2d-x-3.13.1\cocos\audio\winrt\AudioSourceReader.cpp
        //349行目付近をコメントアウトしておく
        //getFileSizeでエラーが起きる
        /*
        if (createMappedCacheFile(_filePath, _mappedWavFile, ".dat")) {
            _isStreaming = _largeFileSupport;
            _audioSize = FileUtils::getInstance()->getFileSize(_mappedWavFile);
            if (!_largeFileSupport) {
                buffer.resize(_audioSize);
                readFromMappedWavFile(buffer.data(), 0, _audioSize, nullptr);
                chunkify(buffer);
            }
            break;
        }
        */
```

ここにもhttps://github.com/cocos2d/cocos2d-x/pull/15097/files
修正方法がありましたがキャッシュを強制的に削除する方法です。
vimで文字化けするときの対応


$HOME/.vimrcにset encoding=utf-8を指定する。

## set encoding=utf-8指定なし
```shell-session
# vim ~/.vimrc
"縷Bｿ縷C~V縷Aｯ縷Bｹ縷C~Z縷Cｼ縷Bｹ・~R縷A､縷Aｫ螟~I諧O~[
set tabstop=2
set autoindent
set expandtab
set shiftwidth=2
```


## set encoding=utf-8指定あり
```shell-session
# vim ~/.vimrc
"タブはスペース２つに変換
set tabstop=2
set autoindent
set expandtab
set shiftwidth=2
```
lessで文字化けするときの対応


環境変数`LESSCHARSET`を設定する。

## LESSCHARSET設定前
```shell-session
# less ~/.vimrc
"<E3><82><BF><E3><83><96><E3><81><AF><E3><82><B9><E3><83><9A><E3><83><BC><E3><82><B9><EF><BC><92><E3>
<81><A4><E3><81><AB><E5><A4><89><E6><8F><9B>
set tabstop=2
set autoindent
set expandtab
set shiftwidth=2
```

## LESSCHARSET設定後
```shell-session
# export LESSCHARSET=utf-8 
# less ~/.vimrc
"タブはスペース２つに変換
set tabstop=2
set autoindent
set expandtab
set shiftwidth=2
```
Macにbrew installしたmysql Version5.7 rootパスワードを忘れた時の対処方法


# 今日のお悩み

ずいぶん昔にインストールしたMySQLにパスワード設定したっぽいけど、忘れてアクセスできない


```bash
$ brew info mysql
mysql: stable 5.7.16 (bottled)
```


# 解決

### > MySQLプロセス終了

```bash
sudo mysql.server stop
```

### > mysqld_safeで起動

```bash
 $ /usr/local/bin/mysqld_safe --skip-grant-tables
2017-01-03T07:07:28.6NZ mysqld_safe Logging to '/usr/local/var/mysql/bohelabo.local.err'.
2017-01-03T07:07:28.6NZ mysqld_safe Starting mysqld daemon with databases from /usr/local/var/mysql
```

### > rootパスワードの更新

```bash
update mysql.user set authentication_string=password("new_pass") where user='root';
```

### > MySQLプロセス開始

```bash
sudo mysql.server start
```

### >新しいパスワードで接続

```bash
mysql -u root -pnew_pass
```
調査：ジャバのコンテンツ配布技術

# 調査：ジャバのコンテンツ配布技術

「あなたとJAVA, 今すぐダウンロー」「ド」で有名な https://java.com/ja/ ですが、130億のデバイスにジャバを配布しつづけるそのサービスのスケールは、我々が普段扱うサービスと比較しても大きいといえるはずです。一体どのような技術が使われ、このようなスケールのジャバ配布が実現されているのでしょうか。本日はその核心に迫ってみたいと思います。

## java.com は誰がホストしているのか

java.comのサービスはオラクルの新社屋にあるのでしょうか。これは単純にDNSから答えを出すことができました。

```
$ dig a java.com

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.47.rc1.51.amzn1 <<>> a java.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21399
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;java.com.                      IN      A

;; ANSWER SECTION:
java.com.               20      IN      A       23.212.82.138

;; Query time: 155 msec
;; SERVER: 172.31.0.2#53(172.31.0.2)
;; WHEN: Tue Jan  3 16:01:31 2017
;; MSG SIZE  rcvd: 42

```

```
$ dig -x 23.212.82.138

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.47.rc1.51.amzn1 <<>> -x 23.212.82.138
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3389
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;138.82.212.23.in-addr.arpa.    IN      PTR

;; ANSWER SECTION:
138.82.212.23.in-addr.arpa. 60  IN      PTR     a23-212-82-138.deploy.static.akamaitechnologies.com.

;; Query time: 137 msec
;; SERVER: 172.31.0.2#53(172.31.0.2)
;; WHEN: Tue Jan  3 16:01:37 2017
;; MSG SIZE  rcvd: 109
```

というわけで、java.com はakamaiを使っています。これは普通にNetStorageで契約した時と同じような名前のホストなので、残念ながらAkamaiのどのサービスを使っているかまではわかりません。

## どんなサーバーを使っているのか

HTTPのヘッダを見てみましょう。

```
$ curl -H 'Accept-Encoding: gzip' -I https://java.com/ja/
HTTP/1.1 200 OK
Server: Oracle-Application-Server-11g
Last-Modified: Sat, 17 Sep 2016 01:00:22 GMT
device_type: Any
host_service: FutureTenseContentServer:11.1.1.8.0
X-Powered-By: Servlet/2.5 JSP/2.1
Content-Type: text/html; charset=UTF-8
Content-Language: en
X-Frame-Options: SAMEORIGIN
Vary: Accept-Encoding
Content-Encoding: gzip
Date: Tue, 03 Jan 2017 07:06:18 GMT
Content-Length: 20
Connection: keep-alive

```

`Server: Oracle-Application-Server-11g` というヘッダはOracle Fusion Middleware Application Server 11gから出てくるらしいです。正直ウェブのこと良く知らないんで、これがどういうものか謎ですが、邪悪な雰囲気は伝わってきます。また、`host_service: FutureTenseContentServer:11.1.1.8.0` もCMSか何かっぽいんですが、ジャバサイトがほとんど更新されないところを見るとほんとうにこんなCMSなんていうものが必要なのか、疑問に思ってしまいます。

ちなみに、FutureTenseはFatWireに吸収され、FatWireはOracleに吸収されているらしいです。java.comを作る際のミーティングで「何か適当なCMS入手しておいて」と頼まれたのを勘違いして、CMSやってる会社を買っちゃったパターンでしょうか。謎は深まります。

ちなみに、NetStorageではリクエストヘッダに`Pragma:` を入れると診断用のヘッダが返って来ますが、ジャバサイトではそういうことはありませんでした。いずれにしてもこのボリュームだとかなり特殊な契約になりそうなので、ジャバリークスからの報告待ちです。

## 結論

あなたとジャバをいつでもダウンロードできるようにする舞台裏、お楽しみ頂けたでしょうか。
Laravel ViewComposer を使ってみよう

```php

// Home
Route::get('home', function() {
    $posts = Post::recent();
    return view('home', compact('posts'))
});

// このサイトについて
Route::get('about', function() {
    $posts = Post::recent();
    return view('home', compact('posts'))
});
```

こんなコードを書いていませんか？
全ページサイドバーに表示するような情報を各route(もしくはController)で取得している点が気になります。

全ページで使う値はViewComposerでまとめて記述してしまいましょう。

```(抜粋)SomeServiceProvider.php
public function boot()
{
    view()->share('posts', Post::recent());
}
```

もし単一 or 特定のViewでしかつかわない場合はこのように記述することもできます。

次の例は、サイドバー('common/sidebar.blade.php')が読み込まれた場合に `posts` を view に渡します。

```(抜粋)SomeServiceProvider.php
public function boot()
{
    view()->composer('common.sidebar', function($view) {
        $view->with('posts', Post::recent());
    }
}
```

サイドバー(`common/sidebar.blade.php`)に加えて、フッター(`common/footer.blade.php`)にも渡したい場合は配列で指定することができます。

```(抜粋)SomeServiceProvider.php
public function boot()
{
    view()->composer(['common.sidebar', 'common.footer'], function($view) {
        $view->with('posts', Post::recent());
    }
}
```

ここまで、ServiceProvider に直接記述する方法を紹介してきましたが、これも数が多くなってくると煩雑になってきます。クラス化してみましょう。

```app/Http/ViewComposers/RecentPostsComposer.php
<?php

namespace App\Http\ViewComposers;

use App\Post;
use Illuminate\Contacts\View\View

class RecentPostComposer
{
    public function compose(View $view)
    {
        $view->with('posts', Post::recent());
    }
}
```

```(抜粋)AppServiceProvider.php
public function boot()
{
    view()->composer(
        'common.sidebar',
        App\Http\ViewComposers\RecentPostComposer::class
    )
}
```
Qiita初投稿時、![Payload Too Large]()のエラーがよく出る

Qiitaで初めて記事を書く際に、画像添付すると途中から

```
![Payload Too Large]()
```
が表示され、戸惑う人が多いそうです。
これは、Qiitaにアップロード可能な容量が**月間2MB**だからです。画像複数添付したらすぐ達しちゃいますね。
ただ、**一度でも記事を投稿すると100MBまで増えます**。

なので、初投稿は気合を入れた超大作ではなく、軽〜い記事から投稿しましょう。
AWSのRekognitionを利用してSNOWの盛り度を調べてみた

AWSのRekognitionを利用してみました。
ざっくりいうと、画像に対し、
1. 顔認識
2. 物体認識
3. 2つの画像の類似度
4. 顔認識で感情等の認識
などができるAPIです。

ただ、それを利用するのも面白みに欠けるので、
SNOWがどれだけ盛っているかを調べてみました。

# 準備
まずは、AWSのアカウントでテスト用のIAMを作成します。
検証はしていませんが、
- Rekognitionのフルアクセス
- S3のフルアクセス
があれば問題ないかと思います。

# APIの利用
```ruby:sample.rb
# rekognition用のkey, secret
rekognition = Aws::Rekognition::Client.new(
  region: 'us-east-1',
  access_key_id: KEY_ID,
  secret_access_key: SECRET
)
```
上記コードでアクセスできます。
リージョンは東京では出来ないので要注意。

```ruby:sample.rb
KEY_ID = ""
SECRET = ""
```
実際のコードとは違いますが、どこかで上記を定義します。

# 使った画像
適当にSNOWで2つ撮影しました。
### SNOWバージョン
<img width="375" alt="IMG_0929.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/8854/9ab1da2e-4ce2-cde8-0140-214cc77fc3bc.jpeg">
### no SNOWバージョン
<img width="375" alt="IMG_0930.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/8854/dc023801-e73f-06ec-cbc2-0eda808b1bba.jpeg">

この2つの類似度を検出して、SNOWはどれくらい盛っているか調べていきます。

# 類似度の検出方法
類似度を検出するには次のコードを追記します。

```ruby:sample.rb
resp = rekognition.compare_faces({
  source_image: { # required
    s3_object: {
      bucket: BUCKET,
      name: "ファイル名",
      version: "適当なversionID",
    },  
  },  
  target_image: { # required
    s3_object: {
      bucket: BUCKET,
      name: "ファイル名",
      version: "適当なversionID",
    },  
  },  
  similarity_threshold: 1.0,
})

p "類似度 : #{resp.face_matches[0].similarity}%"
```
これは参考に、
[AWS-SDK Rubyのドキュメント](http://docs.aws.amazon.com/sdkforruby/api/Aws/Rekognition/Client.html#compare_faces-instance_method)
を見てみました。
上記ドキュメントでは、

```ruby:sample.rb
resp = client.compare_faces({
  source_image: { # required
    bytes: "data",
    s3_object: {
      bucket: "S3Bucket",
      name: "S3ObjectName",
      version: "S3ObjectVersion",
    },
  },
```
となっており、

```ruby:sample.rb
    bytes: "data",
```
JSONの中にこんなコードがありますが、これを追加したままだと、
> Cannot provide both S3 Location and Image Bytes.

というエラーが出てきたので消しました。

# 結果

気になる結果は、
> "類似度 : 78.0%"

となりました。

まとめると
「『AWS Rekognition』で『SNOWの盛り度』を調べると、『128%増しになる』」
これはトリビアの種でいうと5分咲きくらいにはなりそうですかね。なりませんかね。

# 補足
今回勝手に
盛り度 = 100%/類似度
と定義しましたが、
Rekognitionで出せるのはあくまで類似度のみなのでその点ご注意を。
PowerShellでスクリーン上の任意の位置のRGB値を取得する（カラーピッカー）

# 概要
PowerShell で、マウスカーソルの位置の RGB 値を取得するスクリプトを作りました（カラーピッカー、スポイトツール）。

#### 使い方
0. スクリプトを起動する。
0. スクリーン上の RGB 値を取得したい箇所に、マウスカーソルを **3 秒以内**に持っていく。
0. （スクリプトを起動してから 3 秒後時点の）マウスカーソルの位置の RGB 値が、コンソールに出力される。

#### オプション機能
- ピックした色をクリップボードにセットできるようにした。
    - スクリプトの最後に「C」キーを押すことで、この機能が動作する。
    - 16x16 サイズの、単色の画像としてセットする。

# コード
```ps1:ColorPikcer.ps1
Add-Type -AssemblyName System.Drawing, System.Windows.Forms

# Bitmap と Graphics オブジェクトを用意しておく (1x1 ピクセル)
$bitmap = New-Object System.Drawing.Bitmap(1, 1)
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)

# 3 秒間の猶予を与える
Write-Host "Move the cursor to the targt position in 3 seconds..."
Start-Sleep 3

# カーソルの位置 (X, Y 座標) を取得
$dpiScaling = 1.0
$positionX = [System.Windows.Forms.Cursor]::Position.X * $dpiScaling
$positionY = [System.Windows.Forms.Cursor]::Position.Y * $dpiScaling

# カーソルの位置のスクリーンの RGB 値を取得
$graphics.CopyFromScreen($positionX, $positionY, 0, 0, $bitmap.Size)
$pixel = $bitmap.GetPixel(0, 0)

# RGB 値をコンソールに表示
$decValue = "RGB({0}, {1}, {2})" -f $pixel.R, $pixel.G, $pixel.B
$hexValue = "#{0:X2}{1:X2}{2:X2}" -f $pixel.R, $pixel.G, $pixel.B
Write-Host "$decValue, $hexValue"

# 「C」キー押下で、取得した色をクリップボードにセット
Write-Host "Press 'C' to copy the color to the clipboard..." -NoNewLine
if ([Console]::ReadKey().KeyChar -eq 'c')
{
    $bitmap16x16 = New-Object System.Drawing.Bitmap(16, 16)
    $graphics16x16 = [System.Drawing.Graphics]::FromImage($bitmap16x16)
    $graphics16x16.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::NearestNeighbor
    $graphics16x16.DrawImage($bitmap, 0, 0, 16*2, 16*2)
    [Windows.Forms.Clipboard]::SetImage($bitmap16x16)
}
```

# 実行結果
![cursor.png](https://qiita-image-store.s3.amazonaws.com/0/155410/f750ed67-69f3-8c99-1080-fa756ec80a40.png)

```text
Move the cursor to the targt position in 3 seconds...
RGB(89, 187, 12), #59BB0C
Press 'C' to copy the color to the clipboard...C
```
クリップボードにセットされた画像: ![Clipboard.png](https://qiita-image-store.s3.amazonaws.com/0/155410/e86f273d-b144-cc92-9976-0d3bb8a60509.png) ([#59BB0C](https://www.google.com/search?q=%2359BB0C))

# メモ
- **動作状況:**
    - マルチディスプレイ環境でも動作した。
    - **DPI のスケーリング値**を 100% より大きい値に設定していると、`[System.Windows.Forms.Cursor]::Position` の位置がずれてしまう。
        - スクリプト中の変数 `$dpiScaling` の値を変更することで、このずれを修正できるようにした。
            - 例。スケーリング値を 150% に設定している場合は、以下のように変更する:

                ```ps1
                $dpiScaling = 1.5
                ```

        - WinAPI からこのスケーリング値を取得することもできるらしい（が、面倒そうなので今回はパス……）。
    - 「マルチディスプレイ環境」かつ「DPI のスケーリング値がディスプレイ間で異なる環境」だと上手く動作しない（スケーリング値が合っていないディスプレイで位置ずれが発生する）。

- **欠点:**
    - 「マウスオーバーで動的に表示が切り替わるような箇所」から「切り替わる前の色」をピックすることができない。

- **その他:**
    - （大したメモリ量にはならないとは思い今回は省略したが、）Bitmap や Graphics の `Dispose()` はちゃんと書いたほうがお行儀がいいかもしれない。
    - `Write-Host` の `-BackgroundColor` オプションを使って、色の見本がコンソールに表示できたら便利だったのだが、このオプションで指定できるのは `"magenta"` や `"yellow"` などの[固定の 16 色](https://technet.microsoft.com/library/ff406264.aspx)だけだった。