OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScriptを使ってWebブラウザにディレクトリをドラッグ＆ドロップしよう！

<br>RHEMS技術研究室の西田です！
今回ブラウザ上にファイルまたはディレクトリをドラッグ＆ドロップしてサーバにアップロードする、という機能が必要になったので、その際にハマったことや身についたナレッジなどを共有していきたいと思います！

#tl;dr.
・Webブラウザにファイルをドラッグ＆ドロップする機能は簡単に実装できた
・複数のディレクトリをドラッグ＆ドロップする機能は難しい。。。
・そうだ [File and Directory Entry API](https://developer.mozilla.org/en-US/docs/Web/API/File_and_Directory_Entries_API) を使おう！

#現在の進捗状況
・[単数|複数]の[ディレクトリ|ファイル]をドラッグ＆ドロップで取得できた！
・~~あれ？中身が見れない！もしかしてバイナリ取得できてない？？？どうやってみるんだ。。。~~
・やっぱり取得できてるじゃん！やったね！

#実装
コードは以下のようになっています。

```HTML:HTML/CSS
<div id="droparea">
    <button class="btn btn-primary btn-block" id="cover">
        ここにファイルを
        <br>
        ドロップしてください
    </button>
</div>

<style>
    #droparea {
        padding: 100px 25%;
    }

    #cover {
        width: 100%;
        height: 70px;
    }
</style>
```

```JavaScript:JavaScript
async function scanFiles(entry, tmpObject) {
    switch (true) {
        case (entry.isDirectory) :
            const entryReader = entry.createReader();
            const entries = await new Promise(resolve => {
                entryReader.readEntries(entries => resolve(entries));
            });
            await Promise.all(entries.map(entry => scanFiles(entry, tmpObject)));
            break;
        case (entry.isFile) :
            tmpObject.push(entry);
            break;
    }
}

document.getElementById("droparea")
    .addEventListener("dragover", event => {
        event.preventDefault();
    }, false);

document.getElementById("droparea")
    .addEventListener("drop", async event => {
        event.preventDefault();
        const items = event.dataTransfer.items;
        const results = [];
        const promise = [];
        for (const item of items) {
            const entry = item.webkitGetAsEntry();
            promise.push(scanFiles(entry, results));
        }
        await Promise.all(promise);
        console.log(results); //テスト表示
/*--------------------追加コード--------------------*/
        for(let result of results) {
            result.file(file => {
                const reader = new FileReader();
                reader.readAsText(file);
                reader.onload = () => {
                    console.log(result.fllPath);
                    console.log(file);
                    console.log(reader.result);
                };
            });
        }
/*-----------------------------------------------*/

    }, false);
```

追加コード部の処理がFileEntryから実体を取得し、表示するコードです。
この処理をゴニョゴニョすることで、サーバ側で同一ディレクトリ構造を復元したり、GoogleDriveのようにブラウザ上でディレクトリを扱えたり出来るようになります。
フルパスも中身も取得できてる上、複数選択しようが単数で投げようが、関係なくすべて処理してくれます。
ここに、条件を付け加えるだけで、文章のみ受け取ったり、画像だけ不可なども可能になります。
また、この機能は現在非標準ですが、GoogleChrome、Opera、FireFoxでの動作を確認しています。
Windowsマシンが届き次第、EdgeやIE(多分未対応)での動作も試してみます。
プロフィール画像が変更できない...railsチュートリアル改造日記

・問題
　railsチュートリアルでサンプルアプリ（SNS）を作りました。
　userとしてプロフィール画像を変更しようとすると、うまくいきません。

　1枚目の画像のchangeを押すとhttps://ja.gravatar.com/site/loginに飛ばされます。![sample_app cgange.PNG](https://qiita-image-store.s3.amazonaws.com/0/232561/83f712e0-244a-85ad-5eb7-68ab89a12781.png)
![画像変更しようとした後.PNG](https://qiita-image-store.s3.amazonaws.com/0/232561/49fedb7b-b923-9ad4-cb73-ec99d3e9b011.png)

　heroku logsで確認すると
Processing by UsersController#edit as HTML
User Load (0.9ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
Parameters: {"id"=>"3"}
Rendering users/edit.html.erb within layouts/application
User Load (2.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
Rendered users/edit.html.erb within layouts/application (15.3ms)
Rendered shared/_error_messages.html.erb (0.8ms)
Rendered layouts/_shim.html.erb (0.1ms)
Rendered layouts/_header.html.erb (1.0ms)
Rendered layouts/_footer.html.erb (0.2ms)
Completed 200 OK in 29ms (Views: 20.0ms | ActiveRecord: 2.9ms)



・解決策
ググっていて、もしかしてと思ったのがgemのgravatasticを入れるという話なのですが、これはgravatar画像が表示されない時にという事で、gravatar画像は表示されているので保留。

進めていてわかった事は、チュートリアルでは、gravatarにsignupして画像登録するということ。
https://www.adminweb.jp/wordpress/comment/index10.html
を参考にgravatarに画像登録するとプロフィール画像を変更できます。
本番環境herokuのデータベースpostgreSQLの使い方...railsチュートリアル改造日記

・課題
本番環境のテーブルに新たなカラムを追加したが、そこへの保存が上手くいかない。だから本番環境のテーブルを覗いてみる事に。

・経過
pgAdminというpostgreSQLに対する定番のGUIを使おうと思ったがcloud9には対応していないみたい。
ならばと、psqlコマンドを叩いて見る事にしよう。
postgreSQLの起動
sudo service postgresql start

postgresデータベースにユーザーpostgresdeで接続
psql -d postgres -U postgres

ここで返ってきた反応が
psql: FATAL:  Peer authentication failed for user "postgres"

認証されない。ググって気付いた。herokuのpostgresに接続しようとしてる訳じゃない事に。

・解決
heroku pg:psql -c "\d"
で確かにデータベースを覗く事ができ

 heroku pg:psql -c "select * from users;"
でusersテーブルを覗く事ができた。
本番環境のテーブルに新しいカラムを追加するのにハマった事...Railsチュートリアルの改造日記

・課題
アプリに自己紹介文を作りたい。settingに自己紹介文のフォームを作り、DBにカラムを作ったが、エラーが出るわけでもなく更新されない。

・経過
自己紹介文フォームに「こんばんみ」と入力して保存してみるも反映されない。テーブルを見ても保存されていない。logを見ると　Unpermitted parameter: s_introduction　という一文がある。ググってhttps://qiita.com/yusabana/items/78e8d1ed64ead5fe9e29を参考に解決。

・結論
要はuser_controller.rbの
def create
    @user = User.new(user_params)
と
def update
    if @user.update_attributes(user_params)

の部分の(user_params)に問題があった。このuser_paramsは同じuser_controller.rbのprivateより下にこう定義している。

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation,)
    end

ここに新しいカラム名を追加したらOK!!
Device Portalを用いてPCのキーボードから文字を入力する

ブラウザからHololensにアクセスできるDevice Portalを用いてPCのキーボードでHololensの文字入力を行う．AirTapキーボードを使えばいいのだが，これでは長文を打ったりするときに面倒（Hololensで長文を打つ時なんてほとんどありませんがww）

**1.Device Portalへのアクセス**
まず，HoloLensのIPアドレスを確認しましょう．
HololensでHolographic Remotingを開いて紫の画面をタップ
![20180601_180528_HoloLens.jpg](https://qiita-image-store.s3.amazonaws.com/0/257442/f35c34c9-a970-1f35-fe28-94f659d75456.jpeg)

するとこのようにIPアドレスが表示されます（これがHoloLensのIPアドレスです）
![20180601_180500_HoloLens.jpg](https://qiita-image-store.s3.amazonaws.com/0/257442/93050578-9259-7187-32e7-356853890829.jpeg)


**2.Device Portalへアクセス**
Device Portalへアクセスします（今回はChromeを使います）
ブラウザを開いてさっきのIPアドレスを打ち込むと...（警告が出ますがムシ）
![Inkedキャプチャ_LI.jpg](https://qiita-image-store.s3.amazonaws.com/0/257442/952d11ea-9e7a-a127-253c-13b76ae3eef3.jpeg)
アクセスできましたね．

つぎに画面左下にあるVirtual Inputをクリックします
![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/257442/26540971-15cc-8b25-e4db-9afb951ffddf.png)

あとは右のボックスを選択しキーボード入力するだけです．
Input textを用いるとまとめて文字列をSendすることもできますよ．

実行動画↓
https://youtu.be/b29ITt1otic

**まとめ**
私見ですがあまり使う場面は少なそうですねww
しかし，知ってて損はないと思います
本番環境が起動しない。(railsチュートリアル)

・問題　
git等をいじってたらherokuでの本番アプリが起動しなくなった。

Application error
An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.

・解決法
heroku logs | grep error
とエラーが起きてるのか見る。

$ heroku logs | grep error
2018-04-13T11:05:48.041458+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=boiling-springs-7.herokuapp.com request_id=f77ce1d1-e709-491d-853f-8012a3ed0c92 fwd="125.199.21.227" dyno= connect= service= status=503 bytes= protocol=https

desc="App crashed"　アプリ自体が壊れてしまった？

errorに絞らず heroku logs でログを見ると
/app/vendor/bundle/ruby/2.3.0/gems/carrierwave-1.1.0/lib/carrierwave/uploader/configuration.rb:78:in `eval': uninitialized constant CarrierWave::Storage::Fog (NameError)
の一文を発見。

どうやらチュートリアルの飛ばしていいと書いてある13.4.4を飛ばしたせいっぽい。
13.4.4を改めて終わらすと本番環境起動しました。
railsチュートリアル１１章　メイラーが機能しない

・問題
アカウント有効化のためにユーザーに送られてくるメールが届かない。

・解決策
ググったりしていると、よくある問題としてherokuにクレカが登録されてなかったりがあるみたいですがherokuのマイページを見るとされている、、、
heroku addons  で確認するもsendgridは機能している、、、

結論　→　情けないですがheroku run rails db:migrate をするとメールが届くようになりました。
　　　　これからも無いミスでは無さそうなので気をつけたいと思います。
php のエラーが設定によって挙動が変化することを理解する

php のエラーハンドリングは使用している環境の設定によって挙動が変わってくるので、Web上にあるコードを実行しても自分の環境だけ同じ結果にならなかったり、別の環境では異なる動きをして混乱することが多いです。
ここでは環境によってエラー時の動作が異なってくる部分を軽くまとめました。

# はじめに
以下のような感じで -r につづいてコードを記述すると php コマンドから直接 php のスクリプトを実行することができます。
これを利用して今回は例を示していきたいと思います。

```shell
php -r 'phpinfo();'
```

これは phpinfo() 関数を実行するだけのスクリプトを実行するだけになります。

# 実際に結果を見ながら理解する

myfunc という関数を実行するスクリプトです。-d でパラメータが大量についてますが、それは環境によって動作が異なってくるのを防ぐために指定しているので、省略せずにそのままコピペして実行しましょう。

```shell
php -d log_errors=On -d error_reporting=-1 -d display_errors=Off -r "myfunc();"
```

```
ore@mypc:~/$ php -d log_errors=On -d error_reporting=-1 -d display_errors=Off -r "myfunc();"
PHP Fatal error:  Call to undefined function myfunc() in Command line code on line 1
```

当然ですが、myfunc は定義されていないのでエラーになります

先程のスクリプトはいくつかパラメータがついていましたが、それが何か見ていきましょう。

## 指定していたパラメータについて
-d につづいて指定していたパラメータは通常 php の設定ファイル php.ini から設定されるものです。php.ini がどこにあるかは環境によって異なります。
php --ini を実行すると今どこにある php.ini ファイルが読み込まれているかどうかがわかります。

```shell
ore@mypc:~/$ php --ini
Configuration File (php.ini) Path: /etc
Loaded Configuration File:         /etc/php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)
```
私の環境で実行してみました。上のケースでは /etc/php.ini が実際に読みこれている php.ini ファイルとなります。
Loaded Configuration File が (none)になっている場合は、設定ファイルがない状態なので php のデフォルト値が使用されている形になります。Configuration File Path のところに php.ini ファイルを作れば新たに設定することができます。

## 指定していたそれぞれのパラメータについて
### log_errors
[ここ](http://php.net/manual/ja/errorfunc.configuration.php#ini.log-errors) に記載されているもので、エラーログを記録するかどうかを設定します。ドキュメントに書いてないですが、 cli モードから実行したときに標準エラーに出力だすかどうかというのも含まれているので ON にしないとエラー時に何も出力されません。なので必ず ON にします。

### error_reporting
[ここ|http://php.net/manual/ja/errorfunc.configuration.php#ini.error-reporting|] に記載されているもので、エラー出力レベルを設定します。このパラメータは特に環境ごとに異なることが多いです。
mac のデフォルトで用意されている php では以下のような設定になっていました。
```
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
```
これは E_ALL から E_DEPRECATED と E_STRICT というタイプのエラーを取り除いたものをエラーとして取り扱う、という設定になりますが、あまり望ましくはないですね。できれば E_ALL だけにしたいものです。

先程のコマンドでは E_ALL とは書かず -1 と指定していましたが、これは意味としては E_ALL と同じものになります。ただ php 5.4 未満の環境では　E_ALL を指定してもすべてのエラーは表示されず、-1 を指定するとすべてのエラーが表示されるという挙動だったので、-1 を指定しました。

### display_errors
[ここ](http://php.net/manual/ja/errorfunc.configuration.php#ini.display-errors) に記載されているもので、エラーを出力するかどうかを指定します。 log_errors と似てますが、こちらはデフォルトでは標準出力出すとのことです。今回オフにしたのはこれオンにしていると log_errors の標準エラー出力と display_errors の標準出力の結果の両方が表示されてしまうからです。以下を御覧ください。

```shell
ore@mypc:~/$ php -d log_errors=On -d error_reporting=-1 -d display_errors=On -r "myfunc();"
PHP Fatal error:  Call to undefined function myfunc() in Command line code on line 1

Fatal error: Call to undefined function myfunc() in Command line code on line 1
```

基本的にオフでも大丈夫ですが、以下のような Syntax Error になるようなコードを http サーバー経由で実行されるときに困ることがあります。

```php
test(;
```

```shell
php -d log_errors=On -d error_reporting=-1 -d display_errors=Off -S localhost:12345 test.php
```

こんな感じの syntax error があるファイルを開いたときに何も表示されないので何が起こっているのかログみないとわからないので、開発環境のphp.iniだけONにしておいてコード上で ini_set('display_errors', 'Off'); としておくと良いと思います。本番環境のphp.iniはもちろんOffです。


## まとめ
* php.ini に記載されている設定によってエラー発生時の挙動が変わる。
* 環境によって設定が異なるので手元で試すときは現在の設定に注意すること。
エラー制御演算子について理解する

phpには[エラー制御演算子](http://php.net/manual/ja/language.operators.errorcontrol.php)というものがあり、＠を記述するとエラーが発生しても処理を継続させることができる。

## どんなことができるのか
エラー制御演算子を使用した箇所で発生したエラーを無視することができます。
例えば以下のような未定義の変数を参照するようなコードを実行してみます。

```php
echo @$aaa;
echo "okay";
```
結果

```php
ore@mypc:~/$ php -d log_errors=On -d error_reporting=-1 -d display_errors=Off -d test.php
okay
```

$aaa は未定義変数なので通常 NOTICE レベルのエラーになりますが、未定義変数の前にエラー制御演算子 "@" がついているので、何もエラーにならず "okay" という文字列は出力されます。

## 注意すべきところ
エラーハンドラがどのように設定されているかによって動きが変わってきます。

php ではエラーをハンドリングするために [set_error_handler](http://php.net/manual/ja/function.set-error-handler.php) を多くのプロジェクトでは使用されていると思いますが、その場合でも正しく動作させるには以下のように if 文を追加する必要があります。

```php
set_error_handler(function($error_no, $error_msg, $error_file, $error_line, $error_vars) {
    if (error_reporting() === 0) {
        return;
    }
    throw new ErrorException($error_msg, 0, $error_no, $error_file, $error_line);
});
```
[error_reporting](http://php.net/manual/ja/function.error-reporting.php)は普段は現在のエラーレベルを取得する関数ですが、[set_error_handlerのドキュメント](http://php.net/manual/ja/function.set-error-handler.php)に記載されているように**エラー制御演算子が付加されている場合に呼ばれたときだけ error_reporting の値が 0 になる**という仕様があります。これを利用して判定することでエラー制御演算子だったら無視するようにしています。

set_error_handler はエラー制御演算子のあるなし関係なく呼び出せれるので、この if 文がない場合はここで ErrorException を投げてしまいい、エラー制御演算子は実質動作していないような状態になってしまいます。


# 最後に
* 私はどちらかというと、あまりエラー制御演算子に頼ったコードを書きたくないなーと思ってます。
* エラー制御演算子をプロジェクト内で使ってほしくないのであれば、上記の if 文を書かない状態にするのが良いと思います。
SSH接続する時の公開鍵の設置をルートとして行う時の注意点

自分がすでにSSH接続ができる状態で、他のユーザの公開鍵をサーバに設置したい時に
Permission denied (publickey)
で、ログインできなくてハマったので共有します。

結論から言うと、原因は.sshとautyorized_keysの所有者とグループがrootになっていたからでした。

他の投稿では、.sshに
chmod 700
で権限を与える、
authorized_keysに
chmod 600
で権限を与えるということは書いていると思いますが、
ls -al
を実行した時に、
-rwx------ 1 root root 108 6月 1 18:00 authorized_keys
などとなっていると、上記のエラーが起こってしまいます。

なので
cd ~
chown ユーザ名.ユーザ名 .ssh
cd .ssh
chown ユーザ名.ユーザ名 authorized_key
を行って
-rwx------ 1 ユーザ名 ユーザ名 108 6月 1 18:00 authorized_keys
となるようにすると、ログインできます。
Azure WebJobsをAPIで実行する

# Azure WebJobsをAPIで実行する

WebJobsをシェルでAPIの実行する処理を試しました。(2018/6/1時点の処理です)

## 認証

リクエストにcurlを使います
URLはappservice名.scm.azurewebsites.net
API /api/webjobsでWebJobsに登録している一覧が取得出来ます。

```
$ curl https://appservice.scm.azurewebsites.net/api/webjobs
```
401が返ってきました。認証が必要なようです。

1. Azure Potal画面にログイン
2. AppService > 対象のAppService名
3. 画面上の「発行プロファイルの取得」を押下、「AppService名.PublishSettings」がダウンロードされる
4. ダウンロードしたファイルを開いて以下を確認
  - userName="$〜"
  - userPWD="※※※※"
5. userNameとuserPWDをBase64エンコードしてcurlのヘッダに含める
6. userNameは先頭の"$"も含めてエンコードしてください

```
$ curl https://appservice.scm.azurewebsites.net/api/webjobs \
  -H "Authorization:Basic $(echo -n \$userName:userPWD | base64)"

```
これで結果が返ってきました。
あとはそれぞれのAPIに合わせて設定を行っていきます。

WebJobの登録時に"種類"で「継続」「トリガーされた」が選択できますが、
この種類によって若干リクエストが異なります。

## 登録(更新)

### トリガーされた
- URL
```
PUT /api/triggeredwebjobs/{job name}
```
- 名前 : {job name}
- 種類 : トリガーされた
- トリガー : 手動

### 継続
- URL
```
PUT /api/continuouswebjobs/{job name}
```
- 名前 : {job name}
- 種類 : 継続
- スケール : マルチインスタンス

```
# ファイル名と実行ファイルを設定してリクエストを行います。
curl https://appservice.scm.azurewebsites.net/api/〜 \
 -X PUT \
 -H "Authorization:Basic $(echo -n \$userName:userPWD | base64)" \
 -H "Content-Disposition: attachement; filename={file name}" \
 -T "{file path}"
```
※すでに登録済みのジョブ名に再度リクエストを実行すると内容が上書きされました。

- 「トリガーされた」でcronを設定する場合は、登録後に以下のリクエストを実行します

```
curl https://appservice.scm.azurewebsites.net/api/triggeredwebjobs/{job name}/settings \
 -X PUT \
 -H "Authorization:Basic $(echo -n \$userName:userPWD | base64)" \
 -H "Content-Type:application/json" \
 -d '{"schedule":"{cron}"}'
```

- 「継続」で単一インスタンスを設定する場合は、登録後に以下のリクエストを実行します

```
curl https://appservice.scm.azurewebsites.net/api/continuouswebjobs/{job name}/settings" \
 -X PUT \
 -H "Authorization:Basic $(echo -n \$userName:userPWD | base64)" \
 -H "Content-Type:application/json" \
 -d '{"is_singleton":true}'
```
※continuouswebjobsの登録は若干時間がかかるらしく、シェルスクリプトで登録後に単一インスタンスのAPIリクエストしたら404で登録出来ず、数秒sleepをいれたら登録できました

## 実行
種類によってURLの最後が変わります

- トリガーされた
```
/api/triggeredwebjobs/{job name}/run
```

- 継続
```
/api/continuouswebjobs/{job name}/start
```


```
curl https://appservice.scm.azurewebsites.net/〜 \
 -X POST \
 -H "Authorization:Basic $(echo -n \$userName:userPWD | base64)" \
 -H "Content-Length: 0"
```
※Content-Lengthを付けないと411エラーとなります

## 削除
共通にメソッドをDELETEでジョブ名を指定するだけで削除されます

```
curl https://appservice.scm.azurewebsites.net/〜 \
 -X DELETE \
 -H "Authorization:Basic $(echo -n \$userName:userPWD | base64)" \
```

## 追記(2018/6/13)
WebJobのcron設定の時間がAzureFunctionのタイマートリガーのcron式で
実行されるため、以下で設定する
```
{second} {minute} {hour} {day} {month} {day-of-week}
```
- 参考 [AzureFunctionのタイマートリガー](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-timer#cron-expressions)

また、AppServiceのタイムゾーンはデフォルトではUTCのため
WEBSITE_TIME_ZONEを変更していなければUTCの日時でcron実行される
php でお手軽ルーティング

シンプルなルーティングルールならライブラリなしで簡単にできます。


```php
<?php

try {
    routing();
} catch (\Throwable $e) {
    // なんかエラー処理
}
exit();

function routing()
{
    //parse_url() は相対パスを渡すと一部のパターンでおかしな動きをするので、このようにURL全体を渡している
    // http://koseki.hatenablog.com/entry/20120210/phpuri
    $request_url = parse_url('https://example.com' . $_SERVER['REQUEST_URI'], PHP_URL_PATH);
    $request_method = strtolower($_SERVER['REQUEST_METHOD']);

    $route_map = [
        '/v1/endpoint1' => ['get'  => function() { endpoint1();}],
        '/v1/endpoint2' => ['post' => function() { endpoint2();}],
    ];

    if (isset($route_map[$request_url][$request_method])) {
        $route_map[$request_url][$request_method]();
    } else {
        // ここは本当は throw したほうが取扱やすいと思う
        http_response_code(404);
        echo '404';
    }
}


function endpoint1() {
    echo 'endpoint1';
}

function endpoint2() {
    echo 'endpoint2';
}
```

あとは以下のような形で built in server を使えば動作確認も簡単にできます。
```
php -S localhost:12345 index.php
```

超簡単！
Visual Studio Code 環境構築メモ

会社の後輩が使ってて使い勝手がよさそうだったので導入してみることに。
昔のVisual Studioはめちゃ重いイメージだったけどVS Codeはサクサク動いてくれてる。
個人的には画面下部にターミナルが出て来てるのはうれしい。
アクティビティバーも画面下部に来てくれれば最高なんだけど今は無理そう？
XXXX.mdでファイル作ればMarkdownもプレビューできて便利(ショートカット：Ctrl ＋ Shift ＋ Vキー)。

# Win10版をダウンロード  
https://code.visualstudio.com/download  

# 拡張機能  
アクティビティバー→拡張機能アイコン→検索欄に拡張名を入れて検索→インストール  
  
## Activitus Bar  
アクティビティバー(ウィンドウ左にあるアイコン群)をコンソールと同様、
ステータスバーに表示してくれる。
画面下に配置できないかなぁと思っていたけど無理そうなのでせめてこの
拡張で対応。

## PHP IntelliSense
入れたけど定義にジャンプができない。
以下のエラーが表示される。

```
PHP executable not found. 
Install PHP 7 and add it to your PATH or set the php.executablePath setting
```
  
ローカル環境にPHPが入っていないからのようだ。
普段はVagrant環境でやってるからWinローカルにPHPとか入れてなかった。
 
1: PHPダウンロード→ZIP解凍→適当なディレクトリに置く
https://windows.php.net/download#php-7.2
VC15 x64 Non Thread SafeのZip(2018/06/01時点)

2: VS Codeの設定(メニュー→ファイル→基本設定→設定)に以下を記述
※パスはぞれぞれの環境に合わせて。

```
"php.validate.executablePath": "D:/TOOL/php-7.2.6/php.exe",
"php.executablePath": "D:/TOOL/php-7.2.6/php.exe",
```

3: 一応VS Code再起動
これは必要なんだろうか...。
設定変更したらついやってしまう。

* 参考URL
    * Visual Studio Codeを使ったPHPの開発環境の構築  
https://www.sumirelab.com/docs/tech/php/visual-studio-code%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9Fphp%E3%81%AE%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%81%AE%E6%A7%8B%E7%AF%89/
  
    * Windows10にPHP7.0をインストール  
https://qiita.com/darum/items/4011c467312cbafabbe7  
  
  
  
# 設定  
メニュー→ファイル→基本設定→設定、で設定ファイルに追記する。
(ショートカット：Ctrl + Commaキー)

* メニューバーを常に表示しておく

```
"window.menuBarVisibility": "visible"
```

* スペースを「・」表示

```
"editor.renderWhitespace": "all"
```

* エクスプローラー(エディタ左)からソースコードを開いた時に新規タブ表示

```
"workbench.editor.enablePreview": false
```

## ショートカット設定
メニュー→ファイル→基本設定→キーボードショートカット→keybindings.jsonの編集

* 大文字、小文字の変換  
地味にコレ使うので個人的に必須。  

```
// 大文字に変換
{
    "key": "ctrl+u",
    "command": "editor.action.transformToUppercase"
},
// 小文字に変換
{
    "key": "ctrl+l",
    "command": "editor.action.transformToLowercase"
},
```

「ctrl+u」が既存の"cursorUndo"と被るが使うことないのでそのまま使ってしまっている。
何か影響あるのか今のところわからない。
keybindings.jsonは編集が終わったら保存して閉じればもうショートカットが使えるようになっている。
WSLでビルドしたsphinxのhtmlをブラウザ（IIS経由）で表示できるようにする

# 謝辞
Windows10に入れられるUbuntuの名称が変わっていたようで、Windows Subsystem for Linux(WSL)と呼ぶのが正しいようです。
途中で気付いて旧称のBash on Windows on Ubuntu(BoWoU)を使っていたため、後に一括変換で直したのでおかしな表現があるかもしれません。
最近までBoWoUと思っていたばかりに、そのように略した記事を置いてるのが結構恥ずい…

気付いた方は適宜WSLと読み替えてもらえると喜びます。

# WSLでビルドしたsphinxのhtmlをブラウザ（IIS経由）で表示できるようにする
まずはじめに、掲題のようなケースならIISなんて使ってないでapacheとかnginxとかでWebサーバーを立てて使った方がいいです。
が、今回は制限の下で実施してます。

## 当然の疑問のQ&A
### なぜ置くだけではだめなのか？
システム直下にファイルを置いて、Windows側で動いているシステムにファイルを読ませる時に、権限がないのでこれらのファイルを読みに行けないのです。
たとえば、sphinxでビルドしたhtmlファイルをブラウザから見に行きたい、という事が考えられますが、Windows側でこれらのファイルに権限がないため、存在しないものとして振舞います。
Windows側の管理者権限をもったプロセスがファイルを操作しないと、

### Powershellでsphinxをビルドすればよいのでは？
全くもってその通りです。
当初はsphinx、というかドキュメントは後からゆっくりやろうと思ったツケがきました。
というのも、makeファイルとかパッケージ管理がつらくて、WSLでやった方が楽[^1]だったのでPowershellを選択しませんでした。
その割にはIISは使ってるのでなんだこれは、となりますが…。

[^1]: 【WSLでやった方が楽】pip install sphinxが優秀すぎた

# WSLからWindowsのアクセス権限エラーを回避してファイルを格納する
では、本題を。

まずはじめに、置くだけなら/mnt/c/Windows/...とかに直接置けばやりたい事はできると思います。
あるいは、WSLを管理者権限で実行してから同じようにコマンドを実行するのでも良いかと思います。

それでもダメだった方が対象です。
が、正直な話をすると開発環境を作るためだとか、大人の事情で仕方なくやる場合以外は素直にVagrantとか、Hyper-Vとかがあるのでそっちの方がいいですよ。
大事なことなので二回目です。

# 作業環境

``` tree.command
(root)
├── call.sh
├── 01_wsl_startup_cmd.bat
├── 02_cmd_startup_psh.bat
└── 03_psh_execute_command.bat
```

``` call.sh
# 予めsphinx関連のmakeを実行しておく

cd $(dirname ${0})
$(pwd)/01_bow_run_cmd.bat
```

``` 01_wsl_startup_cmd.bat
/mnt/c/Windows/System32/cmd.exe /k C:\\(rootまでのWindows形式のフルパス)\\02_cmd_startup_psh.bat
```

``` 02_cmd_startup_psh.bat
powershell start-process "03_psh_execute_command.bat" -verb runas
exit
```

``` 03_psh_execute_command.bat
(Windowsコマンド) \(sphinxでビルドしたディレクトリのフルパス）\ C:\inetpub\wwwroot\sphinx
```

## 解説
まずは通常通りsphinxでドキュメントファイルを作成します。
sphinxについては色々な場所で公開されている、すばらしい記事を参照してください。

call.shはドキュメントファイルがビルド出来た後からの実施です。
call.shにはWSLからbatファイルを実行させるようにしていますが、実際はただのテキストをコマンドラインに流しているだけです。
. xxx.sh のような形で実行していると思ってください。

なお、WSLからexeを起動できますが、起動したexeを操作することはできません。
今回はcmd.exeなので、cmd自身に終了コマンドを実行させてWSLを復帰させています。[^2]

あとはファイルをだれが実行しているのか、というだけです。
02.batを実行するのはcmdではなくpowershellでもいいんですが、WSLからwindowsの管理者権限で実行させることが出来なかったので、

- 01_callfrom_WSL: windowsで実行できるcmdを呼ぶ
- 02_callfrom_cmd: windowsの管理者権限を持たせてpshを呼ぶ
- 03_callfrom_psh: 管理権限を持っているのでコマンドを実行する

と、役割分担させています。

[^2]: 【WSLを復帰させる】02_cmd_startup_psh.batにexitを書いているためです。01_wsl_startup_cmd.batにexitとしても実行されません。

# ハマりどころ
powershellを使った事がないので、cmdを使わずpowershellで一本にしよう、というのが高い敷居になりました。
実装中はよく混乱させられたので、早いタイミングで上記のようにそれぞれの目標を明確化しました。
後述のメモの通り、なんとかならないかなぁ、と思ったものですが…

あと、どのタイミングをWSLが持つのか、Windowsが持つのかは意識しながらパスを書きましょう。
スラッシュとバックスラッシュ、**バックスラッシュの場合は個数にも注意が必要です。**

# メモ
<a href="https://qiita.com/resolver/items/7187bd6ee8016ee5c741">参考先</a>でも紹介されている通り、batが複数あるのは運用上思うところがあるので、01_bow_run_cmd.batはshでもいいと思います。
が、ここではよく分からない事になりそう[^3]なので拡張子をbatで統一して説明しますが、実際に運用する時はいい感じにしておかないと混乱します。

[^3]: 【よく分からない事になりそう】windowsの権限をどうにか回避するためにやってる事なので、WSLからもbatをshとして呼び出します。

# 参考
<a href="https://qiita.com/resolver/items/7187bd6ee8016ee5c741">管理者権限でbatを実行したい時にやッた事</a>

# 読了後いいね！をお願いします。
どれだけの方に読んでもらっているか知りたいので、お手数をおかけしますがご協力いただけると嬉しいです。
Huawei製Android端末で Google Play Services Vision が動かない

## 症状

2018年5月初旬より、Huawei製Android端末において、Google Play Services Vision の機能が使用できなくなる不具合が発生しています。

このため、今まで正常に動作していたバーコード読取や顔認証が突然反応しなくなる現象が起きています。

コード的には、BarcodeDetector のインスタンス作成後、isOperational が終始 false を返し、true になりません。
この時、下記エラーが繰り返し出力されます。

```
W/DynamiteModule(19073): Local module descriptor class for com.google.android.gms.vision.dynamite not found.
I/DynamiteModule(19073): Considering local module com.google.android.gms.vision.dynamite:0 and remote module com.google.android.gms.vision.dynamite:1702
I/DynamiteModule(19073): Selected remote version of com.google.android.gms.vision.dynamite, version >= 1702
I/Vision  (19073): Loading library libbarhopper.so
I/Vision  (19073): libbarhopper.so library load status: false
```

## 影響範囲

- Huawei製 Android端末(主に7.0)
- GooglePlayServices.Vision を使用したバーコード/QRコード読取、OCR、顔認証

※上記条件に該当すれば、Xamarinでも発生します。

## 原因・対策

現時点では原因は不明で、根本的な解決策は見つかっていません。
Google Play Services あるいは Huawei側の対応を待つしかない状況です。

因みに、端末で Google Play Services のキャッシュをクリアする等で一時的に解消するケースがありますが再起動で元に戻ってしまうようです。

## 詳細情報

Google「Issue Tracker」や GitHub の「Android Vision API Samples」に、本件に関する多数の障害情報が投稿されています。上記内容はこれらの情報に基づいています。
[So, no QR reader, no Ocr Detector, no face recognition on Huawei...]
(https://issuetracker.google.com/issues/80454351)
[Does not read the QR on Huawei devices](https://github.com/googlesamples/android-vision/issues/352)
[isOperational() returns false after a reboot](https://github.com/googlesamples/android-vision/issues/353)
[Library delays or fails on download](https://github.com/googlesamples/android-vision/issues/350)
ITaskbarList3.SetProgress[State|Value] に指定する Handle について (Delphi)

# ITaskbarList3.SetProgress[State|Value] に指定する Handle について (Delphi)

Windows 7 でタスクバーで進捗表示をする機能が実装された. Delphi 10.2.3 で以下の通り PoC を実装したところ動作した.

```pascal
procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  TaskBarList : ITaskbarList3;
begin
  TaskBarList := CreateComObject(CLSID_TaskbarList) as ITaskBarList3;
  TaskBarList.SetProgressState(Handle, TBPF_NORMAL);
  for I := 0 to 100 do
  begin
    TaskBarList.SetProgressValue(Handle, I, 100);
    Application.ProcessMessages;
    Sleep(100);
  end;
  TaskBarList.SetProgressState(Handle, TBPF_NOPROGRESS);
  TaskBarList := nil;
end;
```

ところが、このコードを Delphi XE2 で開発しているアプリケーションに持っていったところ、動作しなかった. ピンときて `Handle` を `Application.Handle` にしたところ動作した.

Delphi はウインドウ管理が MDI (Multiple Documents Interface) のような設計になっており、SDI (Single Document Interface) アプリケーションでも MDI のような振る舞いをする. そのせいで過去にも、最小化のアニメーションがないだの、タスクバーで右クリックしたときのメニューが普通と違うだの、微妙な挙動の違い問題が発生していた. なので、タスクバーに紐付いている本当の `Window Handle` である `Application.Handle` を渡したら動作したわけだ.

しかし、MDI とか死語になったなあ. EXCEL が SDI のフリをした MDI である以外に、広く使われている MDI アプリケーションは残っているのだろうか. って、EXCEL も 2013 から SDI になってしまったのか(チーン).

## 追記:

Delphi2007 以降であれば、以下の行を dpr ファイルに書くことにより、メインフォームの `Handle` がタスクバーに紐付いたものになるよう(また、新規にプロジェクトを作成すれば以下の行が含まれる).

```pascal
Application.MainFormOnTaskbar := True;
```

Delphi XE2 で開発しているアプリケーションで動作しなかったのは、Delphi 4 から引き継いできたソースコードが原因だった.
【新卒勉強会まとめ】再帰編

# 概要

再帰について新卒勉強会でまとめてみた。


# 出てくる問題

再帰といえば、よく出てくる問題をやってみた

- ハノイの塔
- フィボナッチ数列
- パスカルの三角形

数学的にいえば、漸化式で表せるものはだいたい再帰でいけるんじゃねーのかという話になった。
それが全てとは言わないけど、だいたいそうなんだろう。

他にも階乗なんかもよくある問題か・・

# では解いてみる


```PHP:ハノイの塔再帰版
hanoi(2,"A", "B", "C");
echo '<br>';
hanoi(3,"A", "B", "C");

function hanoi($n_hanoi, $a, $b, $c) {
    if ($n > 0) {
        hanoi($n_hanoi-1, $a, $c, $b);
        echo $n_hanoi .'番目の円盤を' . $a . 'から' .$b. 'に移動する';
        echo '<br>';
        hanoi($n_hanoi-1, $c, $b, $a);
    }
}
```


```php:フィボナッチ数列再帰版
<?php

echo 'メモ化再帰を使わない場合のgetFib(35)を求める';
echo '<br>';
$startTime = microtime(true);
echo 'getFib(35)の答えは' . getFib(35);
$endTime = microtime(true);
$deltaTime = $endTime - $startTime;
echo('<br>処理にかかった時間は' . $deltaTime . 'ミリ秒です');
echo '<br><br>';
echo 'メモ化再帰を使った場合のgetFibWithMemo(35)を求める';
echo '<br>';
$startTime = microtime(true);
echo 'getFibWithMemo(35)の答えは' . getFibByMemo(35);
$endTime = microtime(true);
$deltaTime = $endTime - $startTime;
echo('<br>処理にかかった時間は' . $deltaTime . 'ミリ秒です');
echo '<br><br>';
echo 'メモ化再帰であれば$n=100もイケちゃう！！<br>';
echo 'getFibByMemo(100)の答えは' . getFibByMemo(100);

function getFib($n) {
    if ($n == 0) {
        return 1;
    }
    if ($n ==1) {
        return 2;
    }
    return getFib($n - 1) + getFib($n -2);
}

$memo = array();
function getFibByMemo($n) {
    global $memo;
        if ($n == 0) {
        return 1;
    }
    if ($n ==1) {
        return 2;
    }
    if(isset($memo[$n])) {
        return $memo[$n];
    }
    return $memo[$n] = getFibByMemo($n - 1) + getFibByMemo($n -2);
}
```

# 再帰にも種類がある


手続き型言語にはないが、
[PHPで関数の末尾呼び出しを最適化する](https://qiita.com/nishimura/items/c42af4070124d28bd670)



# 参考

https://github.com/Khanashima/algorithm
Win64 における SetDIBits 関数の hdc パラメータについて

# Win64 における SetDIBits 関数の hdc パラメータについて

MSDN の [SetDIBits function](https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd162973(v=vs.85).aspx) には以下の記述がある.

> The device context identified by the hdc parameter is used only if the DIB_PAL_COLORS constant is set for the fuColorUse parameter; otherwise it is ignored.

DIB_PAL_COLORS ではない場合には hdc パラメータは無視される(is ignored)と書かれているが、実際には hdc を指定すると、6: ERROR_INVALID_HANDLE のエラーとなり、動作しない(Windows 10 April 2018 Update で確認). なので DIB_RGB_COLORS の場合には hdc に 0 を指定する必要がある.
スマホのChromeで開発ツールを使ってデバッグ

今回はちょっとだけ長くなります。
スマートフォンサイトの開発等を行っている時にスマホで開発ツールを使いたくなることありませんか？ありますよね。
一言で言うとPCからスマホのChromeを操作することができます。連動します。

- USBケーブルでPCとスマホを接続
- スマホのデバッグモードON
- PCのChromeでinspect実行
- スマホChromeの画面がPCに共有される

ざっくり言うとこんな感じです。
それでは備忘も兼ねて詳しく説明していきます。

#事前準備（Android）
##開発者向けオプションでデバッグモードを有効化
- 設定⇒端末情報⇒ビルド番号を7回タップ
- 「あなたは今開発者になりました」と表示されればOK
- 設定に戻ると「開発者向けオプション」というメニューが追加されている

<img src="https://qiita-image-store.s3.amazonaws.com/0/134325/989b68b4-0ebb-c122-f963-b34d42110a7d.jpeg" width="150">

- その中の「デバッグ」⇒「USBデバッグ」をON

<img src="https://qiita-image-store.s3.amazonaws.com/0/134325/a7810fe0-8af2-4e8d-a9aa-1708757e5ad4.jpeg" width="150">


#PC側作業
- Chromeを開きURLバーに「chrome://inspect/#devices」を入力してアクセス
- スマホ側に「USBデバッグを許可しますか？」のポップアップが表示されるのでOKする
- スマホChromeで開いているタブ（ページ）の情報が表示されているのでデバッグしたいページの「inspect」をクリック

<img src="https://qiita-image-store.s3.amazonaws.com/0/134325/897f150f-0645-abae-ce12-c0ccbbe20422.png" width=50%>


そうすると別ウィンドウでスマホと連動したページが表示されるので開発ツールでお好きなようにごにょごにょすることができるようになります。
Consoleからjavascriptの実行も可能です。

<img src="https://qiita-image-store.s3.amazonaws.com/0/134325/3c4ef6e4-bf9f-acd3-e794-6fa6c8062d5c.png" width=50%>

<img src="https://qiita-image-store.s3.amazonaws.com/0/134325/b13b3dcb-da10-3138-4bab-5c53bdccbb21.jpeg" width="150">

#応用編
スマホからはインターネットに公開された環境じゃないとアクセスできないので、PC等のローカル開発環境にアクセスすることができません。
これを解消するために、Wi-Fi環境でノートPCをアクセスポイントに設定し、スマホでそのWi-Fiに接続します。
これに何の意味があるのかと言うと、Wi-Fiアクセスポイントとして動いているPCのhostsがスマホ側でも共有されます。
ということは、スマホからまだ公開されていない開発環境にアクセスすることができるようになります。
言いたいことはもう分かりますね？
スマホの実機で開発環境を確認しつつ、Chromeのデベロッパーツールでデバッグも同時にできるということです。

とても良い時代になったものですね。
Node.jsでハンディスキャナを使う

Node.jsでハンディスキャナを使う場合、`node-serialport`モジュールを使うのがスタンダードのようだ

v4とv5～6でパーサの指定など変わったみたいなので、v6の使い方をまとめる

## node-serialport
https://github.com/node-serialport/node-serialport

# 環境
- Windows 10
- node 8.9.1
- serialport 6.2

ハンディスキャナは`COM5`に接続されているものとします。

# インストール
npmからインストールする

```bash
npm install serialport
```

yarnだとこう

```bash
yarn add serialport
```

# 最小構成で動かす

index.jsファイルを作成します。3行だけ！カンタン！

```js:index.js
const SerialPort = require('serialport');
const port = new SerialPort('COM5');
port.on('data', console.log);
```

でも実際動かして、バーコードをスキャンしてみるとバイナリで表示されてしまう。

```bash
> node index.js
<Buffer 54 45 53 54 2d 44 41 54 41 0a>
```

# ReadLineパーサを使う
ReadLineパーサを使うと`utf-8`でエンコードしてくれます。
https://node-serialport.github.io/parsers/ReadLineParser.html

デリミタは`\n`(LF)にしていますが、ハンディスキャナと合わせて下さい。

```js:index.js
#!/usr/bin/env node

const SerialPort = require('serialport');
// const Readline = require('@serialport/parser-readline');
const { Readline } = SerialPort.parsers;

const port = new SerialPort('COM5');
const parser = port.pipe(new Readline({ delimiter: '\n' }));

parser.on('data', data => console.log(data));
```

> ※公式のサンプルだと以下の形で`require`してますが、エラーで読めませんでした。
`const Readline = require('@serialport/parser-readline');`

これで読めるようになりました！

```bash
> node index.js
TEST-DATA
```

また、ほかにもいろんなパーサがあるみたいだね！
https://node-serialport.github.io/parsers/index.html

# エラーハンドリング

ハンディスキャナのエラーは`error`イベントで取得できる。

```js
port.on('error', err => console.log(err.message));
```

コンストラクタでもいける

```js
var SerialPort = require('serialport');
var port = new SerialPort('COM5', (err) => {
  if (err) {
    return console.log('Error: ', err.message);
  }
});
```

# テスト

モックが用意されているのでテストもできる

```js:test.js
const SerialPort = require('serialport/test');

const MockBinding = SerialPort.Binding;
const { Readline } = SerialPort.parsers;

MockBinding.createPort('/dev/ROBOT', { echo: true, record: true });
const port = new SerialPort('/dev/ROBOT');
const parser = port.pipe(new Readline({ delimiter: '\n' }));

parser.on('data', data => console.log(data));

parser.write('SERIAL PORT TEST\n');
```

データを書いてあげるとそのまま読みだしてくれる

```bash
> node test.js
SERIAL PORT TEST
```

# Shift-jisを読む

ReadLineパーサには`encoding`オプションがあるみたいだけど、どうやってもShift-jisが設定できなかった。

なので力ずくでやってやるぞ

```bash
npm install iconv-lite
```

```js:sjis.js
#!/usr/bin/env node

const SerialPort = require('serialport');
const iconv = require('iconv-lite');
const { Delimiter } = SerialPort.parsers;

const port = new SerialPort('COM5');
const parser = port
  .pipe(new Delimiter({ delimiter: '\n' }))
  .pipe(iconv.decodeStream('SJIS'));

parser.on('data', console.log);
```
IKSとオンプレK8sのkubectlの認証情報のマージ方法



IBM Cloud Kubernetes Service(以下 IKS) では、kubectl の認証情報を bxコマンドで認証情報をダウンロードして、環境変数 KUBECONFIG にダウンロード先のパスを設定するという流れになる。 それでは、オンプレ開発環境のKubernetesとの相互運用では、ただちにkubectlコマンドの接続先を切り替えられないので不便である。


また、KUBECONFIGをログイン・シェルに設定して、利用した場合、KUBECONFIGのパスがkubectlの設定記録先となり、`bx cluster-config mycluster` でダウンロードすると、後から追加したクラスタ情報を上書きされて消えてしまう。

これでは、オンプレのK8sクラスタとIKSの相互運用に支障があるので、IKSからダウンロードした認証情報とオンプレの.kube/configの認証情報とマージする方法をメモとして残しておく。


## 認証情報のダウンロード

次のコマンドで、認証情報をダウンロードする。 正常すると、次の様にexport KUBECONFIGが表示される。通常は、コピペして環境変数をセットするなどして、kubectlが認識できる様にする。

~~~
$ bx cluster-config [クラスタ名] --admin
...

mycluster の構成は正常にダウンロードされました。 環境変数をエクスポートして Kubernetes の使用を開始してください。

export KUBECONFIG=/Users/maho/.bluemix/plugins/container-service/clusters/mycluster-admin/kube-config-tok02-mycluster.yml
~~~


## PEMファイルのコピー

ダウンロード先のディレクトリを移動して、pemファイルを $HOME/.kube へコピーする。

~~~
$ cd mycluster5-admin/
$ ls -al
total 32
drwx------  6 maho  staff   204  6  1 15:08 .
drwxr-xr-x  6 maho  staff   204  6  1 17:07 ..
-rw-r--r--  1 maho  staff  3243  5 31 17:24 admin-key.pem
-rw-r--r--  1 maho  staff  1822  5 31 17:24 admin.pem
-rw-r--r--  1 maho  staff  1887  5 31 17:24 ca-tok02-mycluster5.pem
-rw-r--r--  1 maho  staff   470  6  1 15:08 kube-config-tok02-mycluster5.yml
~~~


## ファイルのマージ

ダウンロードされてきた認証情報ファイルは、マニフェストで利用されるYAML形式になっており、cluster, context, usersの３つのパートがある。 

~~~kube-config-tok02-mycluster.yml
apiVersion: v1
clusters:
- cluster:
    certificate-authority: ca-tok02-mycluster.pem
    server: https://***.***.***.***:21878
  name: mycluster
contexts:
- context:
    cluster: mycluster
    namespace: default
    user: admin
  name: mycluster
current-context: mycluster
kind: Config
preferences: {}
users:
- name: admin
  user:
    client-certificate: admin.pem
    client-key: admin-key.pem
~~~

下記の３個のパートを $HOME/.kube/configの同パートにコピペで挿入する。

~~~
- cluster:
    certificate-authority: ca-tok02-mycluster.pem
    server: https://***.***.***.***:21878
  name: mycluster
~~~


~~~
- context:
    cluster: mycluster
    namespace: default
    user: admin
  name: mycluster
~~~


~~~
- name: admin
  user:
    client-certificate: admin.pem
    client-key: admin-key.pem
~~~


## 切り替え

`kubectl config get-contexts` を実行すると、オンプレとIKSのコンテキストがリストされる。

`kubectl config use-context mycluster` とすれば、IKS側へ切り替わる。

あとは、kubectlの操作は同じです。



参考資料

https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/
Social LSTM: Human Trajectory Prediction in Crowded Spaces を読んだ

Alahi, Alexandre and Goel, Kratarth and Ramanathan, Vignesh and Robicquet, Alexandre and Fei-Fei, Li and Savarese, Silvio, "Social LSTM: Human Trajectory Prediction in Crowded Spaces", in CVPR2016, pp.961-971, 2016[Online PDF at CVF](http://openaccess.thecvf.com/content_cvpr_2016/papers/Alahi_Social_LSTM_Human_CVPR_2016_paper.pdf)

# 1.どんなもの？
歩行者は互いの未来の位置を予測し，衝突を避けるために経路を調整する
→過去の位置に基づいて人々の未来の軌道を予測するシーケンスタスクと言い換えられる．
この論文では一般的な人間の動きを学習し，将来の軌道を予測するLSTMモデルを提案する．

![スクリーンショット 2018-06-01 17.20.01.png](https://qiita-image-store.s3.amazonaws.com/0/249838/f2c1e589-4c13-ad61-fd04-80963bc70c9e.png)
# 2.先行研究と比べてどこがすごいの？
先行研究では２つの前提条件下での実装である
1)ハンドクラフトな関数を用いて相互作用のモデル化を行なっている
2)密接している人々の相互作用のモデル化に焦点を当てている(離れている人間同士が遠い未来でぶつかるような事象は考慮しない)

本論文では，未来の瞬間における人間の軌道を予測するための新しいデータ駆動型アーキテクチャを介して、2つの前提条件下に対処できるアプローチを提案している．

# 3.技術や手法の肝はどこにあるか？
空間的に近接したシーケンスのLSTMが互いの隠れ層の状態を共有することができるSocial-poolingの実装．
Social-poolingを導入したSocial-LSTMは時間的に一致する軌道間で起こる典型的な相互作用を自動的に学習する．
シーン内の各一人一人に一つのLSTMを用意する．
特定の半径内の全てのLSTMの隠れ状態は一緒にpoolingし，次の時間ステップで入力として渡されることで，隣接するLSTMと接続する．
すべての人が異なる数の隣人を持ち、非常に密集した群衆では、LSTMの数は非常に高くなる
→すべての隣接状態からの情報を組み合わせたコンパクトな表現が必要

![スクリーンショット 2018-05-24 1.52.22.png](https://qiita-image-store.s3.amazonaws.com/0/249838/a9c0aa3a-178e-e4ef-5477-22117b0ffe3a.png)
1.特定の半径内にあるLSTMをピックアップ
2.そのLSTMが区切られた小領域内に複数存在する場合，連結してpoolingを行う（データを一つに）
![スクリーンショット 2018-05-24 3.17.57.png](https://qiita-image-store.s3.amazonaws.com/0/249838/01ca4a62-2aac-10b1-ee14-b9887945a605.png)
http://cvgl.stanford.edu/papers/CVPR16_Social_LSTM.pdf




![スクリーンショット 2018-06-01 12.59.34.png](https://qiita-image-store.s3.amazonaws.com/0/249838/303a9432-73cc-8575-c911-3a7301d5928a.png)

eは特定の半径内の隠れ状態の情報をpoolingした値
hはeと一つ前のhの値を連結してLSTMに入力した値

## 4.どうやって有効だと検証した？
ETHとUCYの2つの公開されている人間歩行軌跡データセットで計5つのデータセットに対して実験を行った
実験は3.2秒間の軌跡を観察し，4.8秒間の経路を予測する．
比較には
1.予測した全部の軌跡の平均変位誤差
2.人と人がぶつかりそうな領域の平均変位誤差
3.予測軌跡の最後の変位誤差
を使う
O-LSTMはSocial-LSTMの簡略化したもので，LSTMから出てくるリッチな情報をプーリングしたものを使うのではなく，位置情報だけを使って予測
![スクリーンショット 2018-05-24 4.20.22.png](https://qiita-image-store.s3.amazonaws.com/0/249838/f62e7660-4c01-a641-fe38-d30af0fa5eb5.png)

上から３つは正しく予測できている例
最後の行は人が減速，直線的な動きをとった時の失敗例
![スクリーンショット 2018-06-01 13.32.47.png](https://qiita-image-store.s3.amazonaws.com/0/249838/d0e640ab-a769-edf7-fad1-119f997fa1c7.png)




## 5.議論はあるか？

## 6.次に読む論文はあるか？
IOS Swift Animation using Lottie

# iOS Swift animation with Lottie
In swift there are lots of way to do UI animation. The designer create complex animation using <b>Adobe After Effect</b> of any other animation software. As a developer, we have to deal with those animation design principle. Imagine if we have a way to export the design from the software and like <b>After Effect</b> and use it directly in your application. It would save you lots of time and effort. You can do that by using one library call <a href="https://airbnb.design/lottie/">Lottie</a>. It give you the capability to bring animation as json format and reuse it in your application. Let's how easy it is by using Lottie for animation.
## Project Setup
Create new project in Xcode and install <b>Lottie</b> using either <b>Cocoa Pod</b> or <b>Cathage</b>. As of now I use Cocoa Pod, so I assume you have Cocoa Pod install on your local computer. If you don't have let's go quickly checkout the installation process <a href="https://guides.cocoapods.org/using/getting-started.html">here</a>.
Run

```swift
pod init
```
and add lottie-ios in your pod file:

```swift
target 'LottieSample' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!
  pod 'lottie-ios'

  # Pods for LottieSample

end
```
Run

```swift
pod install
```
## Sample Code
* First, download the sample animation json file from <a href="http://lottiefiles.com">this website</a>. and drag it into your Xcode project.
* add this line right after the UIKit import

```swift
import Lottie
```
* create and initialize your animation view using <b>LOTAnimationView class</b>. Add this block of code to the bottom of your <b>viewDidLoad()</b>

```swift
let animationView = LOTAnimationView(name: "favourite_app_icon")
animationView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
animationView.center = self.view.center
animationView.contentMode = .scaleAspectFill
```
* After that add this animation view as subview of your ViewController and call <b>play()</b> to start the animation.

```swift
view.addSubview(animationView)
animationView.play()
```
* You can also control the animation looping and speed using this code:

```swift
animationView.loopAnimation = true
animationView.animationSpeed = 0.5
```
Now let's go ahead and run the application to see the result.
Since Lottie animation is also a subview of the ViewController you can also apply the view animation with it as well:

```swift
let timing = UICubicTimingParameters(animationCurve: .easeInOut)
let animator = UIViewPropertyAnimator(duration: 2.0, timingParameters: timing)
        
animator.addAnimations {
    animationView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
}
        
animator.addCompletion {_ in
    animationView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
}
        
animator.startAnimation(afterDelay: 0.3)
```
I also put my code in my <a href="https://github.com/phanithken/LottieAnimationSample">Github repo</a> so that you can clone and test it out right after reading this.
TITAN V で 0xBitcoin をマイニングする(1600 MH/s @ 135W)

漢なら 0xBitcoin を TITAN V でマイニングしたいですね! やりましょう!

できました.

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ねんがんの TITAN V での 0xBitcoin マイニングに成功したぞ!!!!! 😍😍😍😍😍😍㊗️㊗️㊗️㊗️㊗️㊗️㊗️⛓⛓⛓⛓⛓⛓✌️✌️✌️✌️😤😤😤😤😤⚡️⚡️⚡️⚡️⚡️⚡️ 135 W powerlimit で 1600 MH/s でした. ありがとうございます. 日々精進あるのみですね. <a href="https://t.co/K55cntdUYo">pic.twitter.com/K55cntdUYo</a></p>&mdash; Syoyo Fujita (@syoyo) <a href="https://twitter.com/syoyo/status/1002447280006356992?ref_src=twsrc%5Etfw">2018年6月1日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 0xBitcoin とは

イーサリアム上にスマートコントラクトで構築された Bitcoin(的なもの) です.

仕様については, マイニング可能トークン ERC918 とてプロポーザルが行われています

ERC-918 マイニング可能トークンについて
https://qiita.com/shora_kujira16/items/58d23bcb0f88ab17bfa6

ERC20, ERC721 に続く新たな流れになりそうですね.

2018/06/01 時点では 1080 Ti で $8/day とあります, すごい...

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">Join our discord channel <a href="https://t.co/O7DJ9e3CPs">https://t.co/O7DJ9e3CPs</a> for help and support with <a href="https://twitter.com/hashtag/mining?src=hash&amp;ref_src=twsrc%5Etfw">#mining</a> the immensely profitable <a href="https://twitter.com/hashtag/0xbitcoin?src=hash&amp;ref_src=twsrc%5Etfw">#0xbitcoin</a>. 0% fees at <a href="https://t.co/43h78CevnJ">https://t.co/43h78CevnJ</a>! <br><br>Current daily revenue<br>1060 $3.09 <br>1070 $4.94<br>1080 $6.79<br>1080ti $8.01<a href="https://twitter.com/search?q=%24lux&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$lux</a> <a href="https://twitter.com/search?q=%24btg&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$btg</a> <a href="https://twitter.com/search?q=%24btcp&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$btcp</a> <a href="https://twitter.com/search?q=%24zcl&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$zcl</a> <a href="https://twitter.com/search?q=%24zec&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$zec</a> <a href="https://twitter.com/search?q=%24btcz&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$btcz</a> <a href="https://twitter.com/search?q=%24zen&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$zen</a> <a href="https://twitter.com/search?q=%24rvn&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$rvn</a> <a href="https://twitter.com/search?q=%24eth&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$eth</a> <a href="https://twitter.com/search?q=%24vtc&amp;src=ctag&amp;ref_src=twsrc%5Etfw">$vtc</a></p>&mdash; Wolfpool.io (@wolfpoolmining) <a href="https://twitter.com/wolfpoolmining/status/1002362960088653824?ref_src=twsrc%5Etfw">2018年6月1日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## コンパイルする.

Prebuilt の GPU miner は, Ubuntu 16.04 では GLIB バージョンエラーで動かなかったので, ソースからコンパイルします.

https://github.com/0xbitcoin/0xbitcoin-miner

node.js(v8 以降)でコンパイルします.

CUDA のヘッダファイルが一部見つからずエラーがでますので, `binding.gyp` を編集してパスを通しておきます.

あとは手順通りにコンパイルすれば OK です!

## TODO

優秀なイーサリアム若人が, 0xBitcoin のマイニングをすることで, マイニング可能トークンについて完全に理解し, 人類史上最速で ERC918 を極めなさるスキームを確立する旅に出たい.
certificate verify failed で泣く

# SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
Railsのバージョンを4.1.0から4.3.10にあげた際に、gemをアップデートしたら、HttpClientがSSLでエラーになるようになってしまったが、解決したので、備忘録をあげておく。

http://d.hatena.ne.jp/komiyak/20130508/1367993536

ここに書いてあるように `http_client.ca_file` を指定する必要がある模様。
少しgemの中身を見渡していると、 `sample/ssl/ssl_client.rb` というファイルがあり、そこに使い方が書かれてた。

```
ca_path = File.join(File.dirname(File.expand_path(__FILE__)), "trust_certs")

proxy = ENV['HTTP_PROXY'] || ENV['http_proxy'] || nil
h = HTTPClient.new(proxy)
h.ssl_config.add_trust_ca(ca_path)

```

照英書の場所を明示的に指定してあげる必要があるようです。
Slackのstatus emojiを変更する(python3)

Slackでは、自分のステータスを「自宅」「仕事」「リモートで作業中」「休暇」のように、任意に変更することが出来ます。

この記事では、**Python3**を使って、status emojiを変更する方法を記述します。

##まずはAPI Documentationを確認
最初に、SlackAPIのAPI Documentationを確認してみましょう。
Slackにおける会話・チャンネル・データの抽出・更新等さまざまな操作が可能です。
例えば、今回使うのは、users.profile.setというメソッド（方法）です。

[users.profile.set method | Slack](https://api.slack.com/methods/users.profile.set)

###HTTPリクエストでPOSTする
`https://slack.com/api/users.profile.set` へ後述のパラメータを付与して **POST** します。

POSTについては、
[HTTP（HyperText Transfer Protocol）とは - IT用語辞典](http://e-words.jp/w/HTTP.html)
を参照してください。

pythonではこの処理を、requests.post()で

```python
requests.post('http://api.hoge.com', data={'foo': 'bar'})
```

のように書きます。

###パラメータ(抜粋•適宜和訳)

| Argument | Example | Required | Description |
|:--:|:--:|:--:|:--|
| token | xxxx-xxxxxxxxx-xxxx | Required<br>(必須) | Authentication token bearing required scopes. |
| profile | { first_name: "John", ... } | Optional<br>(任意) | Collection of key:value pairs presented as a URL-encoded JSON hash.<br>(URLにエンコードされたjsonハッシュとして渡される値の集まり) |
| user | W1234567890 | Optional<br>(任意) | ID of user to change. This argument may only be specified by team admins on paid teams. <br>(プロフィールを変更する対象ユーザーのID。この要素は場合によっては課金しているチームの管理人のみ有効。自分のプロフィールをいじる分には無課金チームでも使えます。)|



##実装

###Pythonでのrequestsの導入方法
[Requests の使い方 (Python Library) - Qiita](https://qiita.com/sqrtxx/items/49beaa3795925e7de666)
等を参考にしました。

###必用な値の取得
- 自分のUser tokenを取得する。
[Legacy tokens | Slack](https://api.slack.com/custom-integrations/legacy-tokens)
- 自分のUSER_IDを調べる。
[users.list method | Slack](https://api.slack.com/methods/users.list/test)
のTest Method で確認出来ます。

###コード
```Python3:change_status.py
import requests
import json

USER_TOKEN = "xoxp-********..."
USER_ID = "?????**" #@の後に続くユーザ名ではない

def change_status(text,emoji):
	data = {
	"token" : USER_TOKEN,
	"user": USER_ID,
	"profile":json.dumps({
		"status_text":text,
		"status_emoji":emoji
		})
	}
	res = requests.post('https://slack.com/api/users.profile.set',params = data)
	#print(res.text) POSTした結果を表示したい場合

if __name__ == '__main__':
	change_status("ラボ",":office:") #status_message,status_emojiの順
```

##実行
```bash
python3 change_status.py
```

##結果
無事変更されました。
![変更されたステータス](https://qiita-image-store.s3.amazonaws.com/0/186917/79c42e97-5d66-fdeb-2a65-a54db0761a75.png)
Python: 文字列のハッシュ化で安全なパスワード保存

## 概要
- たまにパスワードをそのまま(平文で)DBに保存しているという話を聞く。
- Pythonの標準モジュールに文字列をハッシュ化できるモジュール`hashlib`があったので使ってみた。

## ハッシュ化とは
- あるアルゴリズムによって文字列を規則性の見えない文字列に変換する。
- ハッシュ化のアルゴリズムは数種類ある。
- ハッシュ化によって生成された文字列をハッシュ値という。
- ハッシュ値から元の文字列を生成することは難しい。
- パスワードの管理などに利用される。
- 逆にパスワードをそのまま保存するようなウェブサイトは安全性に疑問があるし、万が一情報が流出したら他人のアカウントで容易にログインでき、個人情報の抜き取りや他人のクレジットカードを使った買い物などが発生してしまう。
- 一見規則性が見えないが、実際は規定のアルゴリズムにより生成されているので、何度やっても同じハッシュ値が生成される。

## サンプル

- MD5、SHA256、SHA512の3種類のハッシュ化アルゴリズムを使ってみた。
- 大文字、小文字の判定も可能。

```sample.py

# coding: utf-8

import hashlib

password = "PassWord12345"

>>> hashlib.md5(password).hexdigest()
9d314e160c006e4bddf054c516f110aa

>>> hashlib.sha256(password).hexdigest()
ed05e0bd8cd4c4d8d294522246e93705e0718fb56f9341c299f15841762d427c

>>> hashlib.sha512(password).hexdigest()
f1bea6640f6ad962db83b1413410f08d29d2c0579449e286e47293633718dc2a21b54d649da47a30e31fc11953a7cfffa8ce2ed20451eae3ba023b5e1773e800

```
元に戻すgitコマンド その6（間違えて git add したら 編）

## はじめに

Webエンジニアになって２年目。そろそろ、`add`、`copmmit`、`push`、`pull`、あと、ブランチ切ること以外も覚えたいなと思い、Gitでずっと気になってた各種**「元に戻す操作」**を勉強がてら記事を書こうと思いました。

Gitの操作をしていると、失敗して元に戻したい時は結構多いんじゃないかなーと思います。戻したい場面はいくつかあると思います。

今回は、**間違えて `git add`しちゃって取り消したい時**の対処について書いていこうと思います。

## どんな場面か？

下記のようなパターンが考えられます。

　- 間違えて `git add`しちゃって取り消したい時
　- 特定のファイルだけ`git add`を取り消したい時

## 解決方法

まず、下の図を見てください。

<img src="https://git-scm.com/images/about/index1@2x.png">

上記は、コミットまでに必要な２段階手順の模式図[^1]です。

ワーキング（作業）ディレクトリで作業をしていて、間違って`git add`しちゃってステージングにあるファイルが入ってしまったら、という場面を想定しています。

間違って、`practice.txt`というファイルをステージングエリアに入れてしまった場合

まずその確認には`git status`を使います。

```bash
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   practice.txt
```

このとき、`(use "git reset HEAD <file>..." to unstage)`と書いています。これは「ステージングエリアからワーキングディレクトリに戻す場合(unstageする)には、`git reset HEAD ファイル名`してね」と書いてます。

なので、いう通りにして見ましょう。

```bash
$ git reset HEAD practice.txt
Unstaged changes after reset:
M       practice.txt
```

確認のため`git status`を使います。

```bash
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   practice.txt

no changes added to commit (use "git add" and/or "git commit -a")
```

## `git reset`は注意が必要

今回は、ステージングエリアから、ワーキングディレクトリに戻しただけなので大丈夫です。
しかし、`git reset`のオプション`--hard`をつけた場合のコマンドは、完全に変更を削除してまうので注意が必要です。

以上です。

## 親記事（まとめ記事）

この記事の[親記事（まとめ記事？）](https://qiita.com/ryosuketter/items/34e429ae555179293fc3)がありまして、そこでは、gitを使ったさまざまな**元に戻す**方法の記事をまとめています。ぜひ、見てください。

## 参考

- https://backlog.com/ja/git-tutorial/intro/intro1_4.html

[^1]: https://git-scm.com/about/staging-area