OmniAICreator/Qiita-1.07M huggingface dataset:
channelのsliceのselect（reflect.Selectの利用）

## はじめに

Goでタスクトレイに常駐させるようなツールを作りたい
↓
[systray](https://github.com/getlantern/systray/)が使えそう
↓
[example/main.go](https://github.com/getlantern/systray/blob/master/example/main.go)を流し読み

```go
go func() {
	for {
		select {
		case <-mChange.ClickedCh:
		// 略
		case <-mChecked.ClickedCh:
		// 略
		case <-mEnabled.ClickedCh:
		// 略
		case <-mUrl.ClickedCh:
		// 略
		case <-mToggle.ClickedCh:
		// 略
		case <-mQuit.ClickedCh:
		// 略
		}
	}
}()
```
↓
メニューの項目が増えるとselectのcaseも増える。
できればchannelのsliceをselectで待ちたい。

## 解決策
Stack Over Flowにちょいどいい回答がありました。
selectそのままではなく、`reflect.Select`を利用することで解決できるとのこと。
参考：[How to listen to N channels dynamic select statement](https://stackoverflow.com/questions/19992334/how-to-listen-to-n-channels-dynamic-select-statement)

サンプル

```go
package main

import (
	"fmt"
	"reflect"
)

func main() {
	numChans := 5
	var chans [] chan struct{}

	for i := 0; i < numChans; i++ {
		tmp := make(chan struct{})
		chans = append(chans, tmp)
		go DoFunc(tmp)
	}

	cases := make([]reflect.SelectCase, len(chans))
	for i, ch := range chans {
		cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
	}
	remaining := len(cases)
	for remaining > 0 {
		chosen, _, ok := reflect.Select(cases)
		if !ok {
			cases[chosen].Chan = reflect.ValueOf(nil)
			remaining -= 1
			continue
		}
		fmt.Println(chosen)
	}
}

func DoFunc(c chan<-struct{}) {
	c <- struct{}{}
	close(c)
}
```

タスクトレイから選択できる各メニューのchannelとそれに対応した処理を保持しておき、
メニューが選択された際にその処理を流せば実現できそうです。
flavorDimensionsが複数あるときのgoogle-services.jsonの設定方法

## Too long, Don't read
- アプリに必要なgoogle-services.jsonは開発用と本番用の二種類だけでいい
- productFlavors、flavorDimensionsがそれぞれ2種類以上ある
- フレーバーの組み合わせすべてのフォルダにgoogle-services.jsonを置かなきゃいけない:angel_tone2:
- だるい
- そんなときの解消法

## サンプルのbuild.gradle
```build.gradle
android {
//　略
    flavorDimensions "mode", "api"
    productFlavors {
        dev {
            dimension "mode"
            applicationIdSuffix '.dev'
        }
        prd {
            dimension "mode"
        }

        minApi23 {
            dimension "api"
            minSdkVersion '23'
        }

        minApi21 {
            dimension "api"
            minSdkVersion '21'
        }
    }

    buildTypes {
        debug {
           // 略
        }
        release {
           // 略
        }
    }
}
// 略
apply plugin: "com.google.gms.google-services"
```
`app/src/フレーバー名/`の直下に`google-services.json`を配置すれば拾ってくれるようになりましたが、
実際に使いたい`google-services.json`は開発用（dev）と本番用(prd)の二種類だけだったとします

しかし、この全部のフレーバーの組み合わせ
[dev/prd]×[minApi23/minApi21]×[debug/release] = 2 × 2 × 2 = 8
だけあるので、各フォルダにgoogle-services.jsonを配置しなきゃいけない

やってられんですね。

## 解決法
- app/src以下にdevとprdのフォルダを切る
- それぞれのフォルダ直下に`google-services.json`を配置
- gradleのbeforeTaskでdevかprdに応じてgoogle-services.jsonをコピーする

```gradle
gradle.taskGraph.beforeTask { Task task ->
    if (task.name ==~ /process.*GoogleServices/) {
        android.applicationVariants.all { variant ->
            if (task.name ==~ /(?i)processDev.*GoogleServices/) {
                copy {
                    from "src/dev"
                    into "."
                    include "google-services.json"
                }
            } else {
                copy {
                    from "src/prd"
                    into "."
                    include "google-services.json"
                }
            }
        }
    }
}
```
GoogleServicesを読み込むプロセス名は
`process${productFlavorName}GoogleServices`となるので、
productFlavorNameの頭がdevかprdかでgoogle-service.jsonのコピー元を判別してコピーしてます

そんだけっちゃそんだけなんですが、やってらんねー！な人がこれ以上増えないように書いときます。
Play Framework 2.6 (Java) の環境構築

※素人がわからないなりに調べながら進めている為えらい人達のご教授を求む

動的WEBプロジェクト作成から、今度はフレームワークで実装して見ようって事でPlayFrameworkである。とりあえずこれを使って作る前に動作させて見ようという所。

#【PlayFrameworkの特色について】
エンジニアをしていれば耳にするだろうRuby on RailsとDjangoから大きな影響を受けた、これらと似た同種のフレームワークである。wiki抜粋。
簡潔に述べると生産性の高いWEBフレームワークだ。ScalaとJavaで動作する。

ruby on railsは経験しておきたかったので類似フレームワークという事でspringより前に触って見る事に。

#【前提】
JDKの環境構築がされている事。
sbtの環境構築がされている事。
eclipseがインストールされている事。
※のちのちeclipseでガシガシ動かすつもりなので設定をば

#【やってみよう】
まずsbtってなんぞや、いきなり躓く（知識不足）
simple build toole の略らしい、でなんでsbtが必要なのかという理由はplayframeworkの動作に必要って事、じゃあ環境構築。

https://www.scala-sbt.org/download.html
上記よりsbtをダウンロード、今回私が選択したのは（sbt 0.13.17）zipでもmsiでも好きなのをどうぞ。msiだとNEXT連続でいける。ここで凄く時間使ったが重くてネットワークエラーとか起きてた。わからないとかじゃなくて通信的な問題、ふぁっきゅー！

インストール確認sbt aboutでバージョン情報がたたっと出てくる
![イメージ130.jpg](https://qiita-image-store.s3.amazonaws.com/0/241708/86f5ab83-9b6a-7312-712a-a28accc86e2e.jpeg)
※なぜかver1.1.1になってるけど気にしない・・・↓↓

コマンドプロンプトを立ち上げ
cd [プロジェクト作成したい場所]
↓
sbt new playframework/play-scala-seed.g8
※playframeworkでプロジェクト作成しますよって感じだと思ってる。

以下、プロジェクト名やバージョン指定がCUIに出てくるので指定する、指定しなければデフォルトになる。
name [play-scala-seed]: 
organization [com.example]: 
scalatestplusplay_version [3.1.0]: 
play_version [2.6.1]: 

で、指定した名前のプロジェクトがカレントディレクトリにいれば成功である、
作成されたプロジェクトにcdした後に以下を実行。

sbt run

初回のみプラグインの取り込みとかで結構がりがり動いてる、
(Server stated～って表示されている間に　
http://localhost:9000/
にアクセス※この画面が表示されてる間サーバーが立ち上がってるので動作確認が出来る。

![イメージ128.jpg](https://qiita-image-store.s3.amazonaws.com/0/241708/fc879452-3d7c-b756-f9c2-a54f82ea3c88.jpeg)

始めましてよろしくどうぞ。
無事それっぽく動作しているのは確認。

次にこのプロジェクトをIDEに取り込んで見るフェーズである、
intelliJの場合SBTをそのまま取り込めたりするらしいがeclipseはこのままではプロジェクトとして認識してくれない、くそう、まだ使ってるからeclipse淘汰は止めて欲しい。

①project/plugins.sbtに以下をaddする。
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.2")

②build.sbtに以下をaddする。
EclipseKeys.preTasks := Seq(compile in Compile)
EclipseKeys.projectFlavor := EclipseProjectFlavor.Java
EclipseKeys.createSrc := EclipseCreateSrc.ValueSet(EclipseCreateSrc.ManagedClasses, EclipseCreateSrc.ManagedResources)

③さきほど作成したプロジェクトで以下を入力。
sbt eclipse
メモ：sbt "eclipse with-source=true" 

これで作成したプロジェクトがeclipseでプロジェクトとして認識してくれるようになる、ふぅ・・・
先人達の知恵をお借りしてここまで勧める事が出来た、ありがとうございます。
とりあえず今回はここまで、次は課題抽出

#【課題】
・playframeworkのサンプルプロジェクトでコンパイルエラー（with utf-8　エンコードエラーっぽいの）が発生する。

起動確認が出来たので、じゃあがしがし作っていこうと思った時にプロジェクト構成を把握仕切れていない為、サンプルでどんな依存関係が調べようとして発生した事故、動的webプロジェクトを始めて作ったときよりは見えるようになってはいるが確信に至っていない為。詳しい方は補足して欲しい・・・がとりあえず対策としてplayframeworkの参考書をamazonでぽちる、困っていても他人は助けてくれないものだ、本は裏切らない（バージョン以外）最近そんな考えになった。でさくさく進めるしね、自己投資は惜しまない。

・scalaのコーディングを行った事がない

上記の参考書でplayframework使う分には困らないと思うが、javaは書いてきたがscalaは触れてきてないので少し困る。今後伸びる可能性もあるし触れると嬉しいけどね。

#【次章について】
フレームワーク使ってブックマークレットを作るつもり、
小難しい感じにしたくないのでアカウント情報をキーにリンクを引っ張ってくる簡素なものにする。webアプリにアクセスすれば自分の使うブックマークが共有出来て当初の目的は果たせる為。広く浅く。

#【最後に】
結構雑な感じ（画像ほとんど使わず）に記事をまとめたが結構時間かかる、
書いてる時間がしがし作っていきたい気持ちも沸くが後で見る時わからなくなるのでバランスが難しいものである。今回やった感じだと確かに慣れたら数時間でアプリ出来るくらいの手ごたえはあった。
SSHでリモートでファイル読み込み/書き出しをしてコマンドを実行する方法

# 概要
SSH接続でリモートからコマンドを実行することもあると思います。その際に接続先または接続元からファイルを読み込んでコマンドを実行したり、コマンドの実行結果を接続先または接続元に書き出すこともあると思います。
そのため、SSH接続でコマンドを実行し、その際にファイルの読み込み・書き出しをする手順をまとめて見ました。

ちなみに、SSH自体は下記の記事が参考になるかと思います
[インフラエンジニアじゃなくても押さえておきたいSSHの基礎知識](https://qiita.com/tag1216/items/5d06bad7468f731f590e)

# 1. SSH接続してコマンド実行

ssh接続してコマンドを実行する場合は、下記のようになります。

```
$ ssh username@hostname（IP adress）commmand
```

例1)

```
$ ssh hoge@xx.xxx.xxx.xxx echo hello
```

例2)(公開鍵認証の場合)

```
$ ssh -i ~/.ssh/hoge_rsa hoge@xx.xxx.xxx.xxx echo hello
```


以下の2,3が少しひっかかったところです。
先にポイントを書いておくと、クォーテーションの書き方でした。
クォーテーションで括られないコマンドは、コマンド解釈が先に行われます。
接続元ファイルを読み込む際は、クォーテーション外に書く必要がありました。逆に、接続先のファイルを使用する場合は、クォーテーションで囲うことで接続先で初めて解釈されるようにします。

# 2. SSH接続して**接続元**のファイルを使用してコマンド実行

例1)

```
$ ssh hoge@xx.xxx.xxx.xxx sh ./hogehoge.sh 
```

`<`でファイル読み込みを明示する形になります。
例2)

```
$ ssh hoge@xx.xxx.xxx.xxx 'sh' < ./hogehoge.sh 
```


# 3. SSH接続して**接続先**のファイルを使用してコマンド実行

例1)

```
$ ssh hoge@xx.xxx.xxx.xxx 'sh ./hogehoge.sh '
```

例2)

```
$ ssh hoge@xx.xxx.xxx.xxx 'sh < ./hogehoge.sh '
```


# 4. SSH接続して実行したコマンドを**接続元**のファイルに書き出し
上記の応用ですが、SSHでコマンドを実行した結果を接続先/接続元のサーバ内にに書き出す場合は以下になります。

```
$ ssh hoge@xx.xxx.xxx.xxx 'cat hoge.txt' > hogehoge.txt
```


# 5. SSH接続して実行したコマンドを**接続先**のファイルに書き出し

```
$ ssh hoge@xx.xxx.xxx.xxx 'cat hoge.txt > hogehoge.txt'
```

2,3と原理は同じで、接続元のサーバ内のファイルに書き出す場合はクォーテーションから外し、接続先にサーバ内のファイルに書き出す場合はクォーテーション内に含める書き方になります。
プロキシ環境下でAzurePowerShellを使う


プロキシ環境下でAzurePowershellのコマンドを実行する時は、powershell立ち上げた後、以下を実行しておくとプロキシを経由でのアクセスになる。

###プロキシURLの設定

```
$proxyString = "http://127.1.0.1:8888" #プロキシサーバのURL
$proxyUri = new-object System.Uri($proxyString)
[System.Net.WebRequest]::DefaultWebProxy = new-object System.Net.WebProxy ($proxyUri, $true)
```

###プロキシ認証の設定

```
System.Net.WebRequest]::DefaultWebProxy.Credentials = Get-Credential
```

Login-AzureRmAccountなどでポップアップするMicrosoftアカウントのログイン画面についてはIEのブラウザ側でプロキシ設定が必要。上記はあくまでpowershellで実行されるRESTアクセスに対するプロキシ設定。
最近だとCloud ShellのPowerShellを使う選択肢もあるけど、一応プレビューだし、classic（ASM）は対応してないので、ローカルでAzurePowershellを使う時もあるだろうということでメモ。

Azure Cloud Shell の概要
https://docs.microsoft.com/ja-jp/azure/cloud-shell/overview


##参考
[Quick Tip: Using Azure PowerShell with Web Proxy and Fiddler](https://blogs.technet.microsoft.com/keithmayer/2016/01/06/quick-tip-using-azure-powershell-with-web-proxy-and-fiddler/)
DataTablesでのAjaxエラー処理

[DataTables](https://datatables.net/)はリッチなUIを備えたテーブルを作るためのjQueryプラグインで、Ajaxを使って検索条件に応じて動的に表データを読み込むことができます。Ajax処理にてサーバーサイドでエラーが発生したときに、DataTables側でエラー処理を実装する方法を探すのに苦労したので、調査結果をまとめています。

### [$.fn.dataTable.ext.errMode](https://datatables.net/reference/option/%24.fn.dataTable.ext.errMode)をnoneに設定して[errorイベント](https://datatables.net/reference/event/error)を受け取る

この方法ではエラーの発生を検知できるが、エラーレスポンスの内容を取得することはできない。

```javascript
// エラー発生時にデフォルトで表示されるメッセージボックスを無効化する。
$.fn.dataTable.ext.errMode = 'none';

// errorイベントを受け取るハンドラ（エラーレスポンスの取得はできない。）
$('#example').on( 'error.dt', function ( e, settings, techNote, message ) {
  console.log( 'An error has been reported by DataTables: ', message );
});
```

### [xhrイベント](https://datatables.net/reference/event/xhr)を受け取る

xhrイベントではレスポンス内容を取得できるため、ステータスコードやボディから正常応答かエラー応答かを判別して、エラー処理を実装することができる。

```javascript
$('#example').on('xhr.dt', function ( e, settings, json, xhr ) {
  // xhrオブジェクトからレスポンス内容を取得できる。
  // ステータスコード: xhr.status
  // ボディ(JSON): xhr.responseJSON

  // error.dtイベントの発生を無効化するにはtrueを返却する。
  return true;
});
```

### 参考情報

[数年前のディスカッション](https://datatables.net/forums/discussion/14841/how-to-catch-response-of-server-side-processing-if-error-occurs)では、DataTables 1.10からajax.errorプロパティエラー処理を行う関数を登録できるようになるとの話もあったようだが、[現在の仕様](https://datatables.net/reference/api/ajax)ではこのプロパティは存在しない。
Unityでデスクトップマスコットのためにウィンドウ最大化した

#はじめに
Unityでデスクトップマスコットのために○○したシリーズの第3弾です。
今までは[ウィンドウの透過](https://qiita.com/gatosyocora/items/7cbe14914f8e603f2eab)や[タイトルバーの非表示](https://qiita.com/gatosyocora/items/b9bc12b4d56ac763e8c0)をやってきましたが
今回は**ウィンドウの最大化**をおこなっていきます。

「マスコットを動かしたいなー」と思いたちまして
今後の拡張内容を考慮して**「ウィンドウ内の表示場所を変える」**ことで
マスコットを動かそうと決めました。

それを実現するために
**「ディスプレイ画面にフィットするようにウィンドウサイズを変更する必要がある」**
と思い, ウィンドウの最大化を実装しました。

#開発および実行環境
- Unity 5.6.3f1
- Visual Studio C# 2017
- Windows 10 Home

#実際のコード
以下が実際に作成したコードです。

```C#:ChangeToMaxSize.cp
using UnityEngine;
using System;
using System.Runtime.InteropServices;

public class ChangeToMaxSize
{

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }

    [DllImport("user32.dll", EntryPoint = "FindWindow")]
    public static extern int FindWindow(String className, String windowName);
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    private static extern int SetWindowPos(int hwnd, int hwndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
    [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
    private static extern int GetDesktopWindow();
    [DllImport("user32.dll", EntryPoint = "GetWindowRect")]
    private static extern bool GetWindowRect(int hWnd, out RECT rect);


    static int handle; // ウィンドウ

    const String WINDOW_NAME = "[ウィンドウの名前]";

    const int HWND_TOPMOST = -1; // 常に最前面に表示
    const int SWP_SHOWWINDOW = 0x0040; // ウィンドウを表示

    private static int displayWidth; // ディスプレイの幅
    private static int displayHeight; // ディスプレイの高さ

    void Start()
    {

#if UNITY_EDITOR

#else

        // ディスプレイサイズを取得
        int display = GetDesktopWindow();
        RECT rect = new RECT();
        GetWindowRect(display, out rect);

        displayWidth = rect.right; // ディスプレイの幅を取得
        displayHeight = rect.bottom; // ディスプレイの高さを取得

        handle = FindWindow(null, WINDOW_NAME); // 起動したウィンドウを指定

        // SetWindowLongによる変更を適用
        SetWindowPos(handle, HWND_TOPMOST, 0, 0, displayWidth, displayHeight, SWP_SHOWWINDOW);


#endif

    }

}

```

今までと同様にUnityのPlayボタンから実行した場合は適用されずに
ビルドしたプログラムでのみ適用されるようにしています。


処理としては

ディスプレイのサイズを取得する
↓
サイズ変更するウィンドウを指定
↓
ウィンドウの場所をディスプレイ画面の左上(0, 0)に合うようにして
ウィンドウのサイズをディスプレイのサイズと同じにする

という感じにおこなっています。


#まとめ
今回はWindowsAPIを使ってC#でディスプレイを最大化させました。

今回は今までに比べ, デスクトップマスコットに必須な技術って感じはしませんが
どこかで使えるだろうとのことで記事にしました。

これでデスクトップマスコット実現に一歩近づいたかなと思います。

#参考
http://www-higashi.ist.osaka-u.ac.jp/~k-maeda/vcpp/sec2-5wndsize.html
https://dobon.net/vb/dotnet/graphics/screencapture.html
地域メッシュの計算にはミリ秒を使うべき

## 地域メッシュの仕様と抽象化
地域メッシュは1次メッシュ「緯度差は40分、経度差は1度」を分割したものです。

```
└─第1次 (約80km)
    └─第2次(縦横8分割 約10km)
        ├─第3次(基準) (縦横10分割 約1km)
        │  ├─10分の1 (縦横10分割  約100m)
        │  ├─20分の1 (縦横20分割  約50m)
        │  └─2分の1 (縦横2分割 約500m)
        │      └─4分の1 (縦横2分割 約250m)
        │          └─8分の1 (縦横2分割 約125m)
        ├─5倍 (縦横2分割 約5km)
        └─2倍 (縦横5分割 約2km)
```
上の親子関係通り、緯度差/経度差を分割していけば起点と辺長が求まるので面を作成することが可能です。  
緯度差 = 40/60
経度差 = 1
のみあればメッシュコード起点から分割していくだけで面を貼れます。

## 小数点誤差の積み重ねとミリ秒単位での計算
緯度差は40分の時点でわかる話ですがこれを積み重ねるとずれます。  

```javascript
var xdiff = 1;
var ydiff = 40/60;

var xorg = 134;
var yorg = 34;

var neX = xorg + xdiff * 2 * 8;
var neY = yorg + ydiff * 2 * 8;

console.log(neX);//135
console.log(neY);//34.666666666666664
```

10進緯度経度  

```javascript
var xdiff = 1;
var ydiff = 40/60;

var xorg = 135;
var yorg = 34.666666666666664;

var neX = xorg + xdiff * 2 * 8;
var neY = yorg + ydiff * 2 * 8;

console.log(neX);//136
console.log(neY);//35.33333333333333

//ミリ秒単位
console.log(neX *3600000); //489600000
console.log(neY *3600000); //127199999.99999999
```

ミリ秒  

```javascript
var xdiff = 3600000 / 8 / 2;
var ydiff = 2400000  / 8 / 2;

var xorg = 486000000;
var yorg = 124800000;

var neX = xorg + (xdiff * 2 * 8);
var neY = yorg + (ydiff * 2 * 8);

console.log(neX);//489600000
console.log(neY);//127200000

console.log(neX / 3600000);//136
console.log(neY / 3600000);//35.333333333333336
```

緯度経度に直す時点まではなるべくミリ秒単位で計算すべきでしたと言う話。。
[地域メッシュをブラウザ上で作成するライブラリを作成した話](https://qiita.com/MALORGIS/items/3d1ead8d53a2d3bdfb72)

ミリ秒 修正前後をMapshaperで確認すると1次メッシュ単位で緯度方向の面が重なってしまっている様子。( 左下隅からの積み重ねなので )
Typescriptで作成していた為、型の変数変更→依存部分修正と割と楽に修正できましたとさ。

修正前
![lineIntersections.jpg](https://qiita-image-store.s3.amazonaws.com/0/232676/3ca2f3ae-f562-8c16-701b-11c284a72233.jpeg)

修正後
![noerror.jpg](https://qiita-image-store.s3.amazonaws.com/0/232676/42eb69bb-3d00-1996-f42b-71cc7b35ab33.jpeg)
IPFS×秘密分散で、絶対に改竄不可な秘密分散ファイル共有システム

IPFS×秘密分散の技術を使って遊んでみました。
悪用されかけないので、そのままでは動かないようにちょいと細工してます。
https://github.com/hkiridera/IPFS-SecletSharing

# IPFSとは

InterPlanetary File System (IPFS)とは内容アドレスかつP2Pのハイパーメディア分散プロトコルである。
IPFSネットワークにあるノードは分散ファイルシステムを形成する。
IPFSは同じファイルシステムである全てのコンピューターへの接続を試みるP2P分散ファイルシステムである。
複数の点で、IPFSはWebと共通点があるが、IPFSは単一のBitTorrentスウォームのように1つのGitリポジトリの中でオブジェクトを交換することが出来る。
言い換えれば、IPFSはハイスループットの内容アドレスブロックストレージモデルを内容アドレスハイパーリンクで提供する。この形式はマークル木の有向非巡回グラフで生成される。また、IPFSは分散ハッシュテーブルとインセンティブブロック交換、自己証明名前空間を組み合わせている。また、単一障害点がなく、お互いに信頼しあう必要もない。
ローカルファイルもIPFSのファイルシステムに追加することができ、世界中で利用することができる。
ファイルはそれぞれのハッシュで識別することでキャッシングしやすくなる。
引用元：https://ja.wikipedia.org/wiki/InterPlanetary_File_System


# 要約すると、

- 分散型P2Pストレージ
- 誰でも参加可能なネットワーク
- Fileのハッシュを使って参照する
- Fileが変わるとハッシュも変わる
- 一度Uploadすると消せない
- 改竄、修正も不可
- ファイルは世界中のどこからでも誰でも参照可能
- 別名：惑星間ファイルシステム
![図1.png](https://qiita-image-store.s3.amazonaws.com/0/131124/6dbb8086-f344-c104-ab21-ea7dff635cc4.png)

# IPFS×秘密分散

- 複数ファイルに分割と暗号化しているので、復号鍵を知っている人以外誰も読み解くことができない。
- 分割後ファイルをどの順序で並べれば復元できるのかは、誰にも分からない。
- そもそも、どの分割後ファイルが、どの元ファイルの一部なのか誰にもわからない。= 解読不可

![図2.png](https://qiita-image-store.s3.amazonaws.com/0/131124/a0c37fa9-7103-cc01-52b4-b65551e6a752.png)

# IPFS×秘密分散をすると何ができるようになるのか

このままIPFSの世界にファイルを投稿すると、誰でも読めてしまうので特定の誰かにのみ共有するには向きません。
なので投稿する前に秘密分散の考えを取り入れて、ファイルを暗号化＆細分化することで、特定の誰かにのみ絶対に消えないファイルを提供することができます。
たとえば、ブロックチェーンと組み合わせて非中央集権型コンテンツ配信サービスを作ったとすると、
閲覧方法を知っている特定の誰かにのみコンテンツを届けることができるようになります。

# 復号方法

ファイル投稿後に、復号化するための情報を記録したmetadataファイルが生成されます。
このmetadataに書かれた分割後ファイルをIPFSから探し出し、復号＆結合することで元のファイルができあがります。

![図3.png](https://qiita-image-store.s3.amazonaws.com/0/131124/8ca04511-3bd5-1caf-6a38-86a4df065ea5.png)

# **くれぐれも悪用するんじゃないぞ～**
GIMPで新聞印刷風（モノクロ2階調）の画像を生成する

[ここのサイト](https://blog.keinos.com/20161208_1813)にあるように、GIMPの機能を利用すれば新聞印刷風（モノクロ2階調）の画像を生成できる。ドットサイズの修正方法や保存時の注意点などがわからなかったので、記事を作成した。

# 動作環境

- **OS** :Windows 10
- **GIMP** : 2.8.22

# 生成画像

**オリジナルカラー**

![color.jpg](https://qiita-image-store.s3.amazonaws.com/0/227399/d3e93e9b-adff-26cb-91dd-98e19cdb35b3.jpeg)

**モノクロ2階調**

- セルサイズ：5
- 角度（赤/青/黄）：60/90/30

![duotone.png](https://qiita-image-store.s3.amazonaws.com/0/227399/bdd411c9-0de5-4566-d774-a16b5c0acd59.png)


# 生成手順

## 新聞印刷フィルターの適用

まずは元になる画像をGIMPで開き、「フィルター」→「変形」→「新聞印刷」を選択。

<img src="https://qiita-image-store.s3.amazonaws.com/0/227399/6135a7d8-75e1-da98-a3bf-77f0441ef7ff.png" width="640px">

設定する場所は「セルサイズ」と「角度」。セルサイズは小さいほどドットが細かくなる。デフォルトまたはそれより小さい値が推奨。角度は大きめで、各色の角度をずらさないと色が被る。

<img src="https://qiita-image-store.s3.amazonaws.com/0/227399/7b3de68b-30b3-942c-54f8-12e8964582e3.png" width="400px">

## グレースケール変換

先にグレースケールに変換しないと後の処理が汚くなる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/227399/bdbdb30e-9d23-3c6d-39f0-201d270061c5.png" width="640px">

## インデックスカラー変換

グレースケール画像を二値データにする。

<img src="https://qiita-image-store.s3.amazonaws.com/0/227399/2ee32e8c-194f-6c07-3dc0-724e1c6db921.png" width="640px">

モノクロ2階調パレットを選択して実行する。

<img src="https://qiita-image-store.s3.amazonaws.com/0/227399/87eccc18-cd35-7efc-0173-90e81d456f4e.png" width="300px">

## 保存

保存するときはJPGではなくPNGにするのがおすすめ。今回のような画像はJPGにするとかなり大きいサイズになるので注意。

<img src="https://qiita-image-store.s3.amazonaws.com/0/227399/29035be5-1aa7-20b3-becc-55224058f092.png" width="400px">

先頭にあった天狗亭の画像サイズはJPGとPNGでこの程度差がある。

| 画像タイプ       |  JPG    |  PNG      |
|:----------------|--------:|:---------:|
| オリジナルカラー  |  283 KB  |  1.04 MB |
| モノクロ2階調    | 641 KB  |   21 KB   |


以上。
Python から JavaScript ソース（zlib 圧縮データも含める）を生成

こんにちは。
Python から JavaScript ソースを生成し、その中には JSON データを直書きしてみました。また書き込みデータは zlib 圧縮しました。このソースが実行されると元通りのデータ内容が得られました（伸長には [pako.min.js](https://github.com/nodeca/pako) を使用、下記例では ```console.log()``` へ表示）。

```temp.html
$ ./print_html.py > temp.html
$ cat temp.html
<script src="pako.min.js"></script>
<script>
var jsonz = "789cab56caad54b252502a2e2d482d52d251502a0033ac14a24d4ccd74144ccdcc63818289e5a9c5f9b9a920850589d9f94ab500bf3b1015";
console.log(parse(jsonz));

function parse(hexstr) {
  return JSON.parse(pako.inflate(unhexlify(hexstr), {to: 'string'}));
}
function unhexlify(hexstr) {
  var result = '';
  for (var i=0, l=hexstr.length; i<l; i+=2) {
  result += String.fromCharCode(parseInt(hexstr.substr(i, 2), 16));
  }
  return result;
}
</script>
```

```print_html.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json, zlib

jsondata = {'my': 'super', 'puper': [456, 567], 'awesome': 'pako'}

jsonz = zlib.compress(json.dumps(jsondata).encode()).hex()
js = f'''
var jsonz = "{jsonz}";
console.log(parse(jsonz));
'''
js += '''
function parse(hexstr) {
  return JSON.parse(pako.inflate(unhexlify(hexstr), {to: 'string'}));
}
function unhexlify(hexstr) {
  var result = '';
  for (var i=0, l=hexstr.length; i<l; i+=2) {
  result += String.fromCharCode(parseInt(hexstr.substr(i, 2), 16));
  }
  return result;
}
'''

html = f'''
<script src="pako.min.js"></script>
<script>{js}</script>'''

print(html)
```
いつも開くwebサイトを自動で開く

# 動機
やることが決まってくるといつも開くのが決まってきます。そこでまず楽したくなりますよね。そのために考えられる方法をいくつか考えてみました。
一つ目は開くと自動的に表示されるようにすること。ですがこれは一つしか開けなかったり、どうあがいても必ず最初に開いてしまいます。二度目からはしないという状況ではうざったいですね。
二つ目はブックマーク機能を使い、テンプレ集を作成してそれをすべて開くという方法です。この方法は良いのですが開き忘れが生じると困りますね。
三つ目はbatファイルで```start https://***```のようなコマンドを連続で並べて開かせる方法です。この方法にすると対応するリンク集毎にbatファイル（例えば漫画のリンクへのコマンドを集めたファイル）を作成するとそれを開けば目的のものをすべて開いてくれそうです。しかし、リンク集を作るのは簡単だけどいちいち```start```コマンドを最初につけるのはめんどくさくなりました。そこでリンク集から```start```をつけたコマンドを自動生成して実行する実行ファイルをHaskellで作成することにしました。

# 使い方
まず[github](https://github.com/ogata-k/webTmp)にて```webTmp.exe```をダウンロードしてください。
次にリンク集を用意してください。例えば以下のようにします。

```txt:link.txt
https://qiita.com/ogata-k
https://qiita.com/ogata-k/items/08de9637111bf61099da
https://qiita.com/ogata-k/items/ed53406a8e6010fe4a43
https://qiita.com/ogata-k/items/2b21326b2b7351bfc28c
https://qiita.com/ogata-k/items/23d70250ec42359b6bb5
https://qiita.com/ogata-k/items/874811cf1aca41bfe88e
```
そのファイルのパスを引数に```webTmp.exe```を実行してください。すると大量に開かれるはずです。
使い方はこれだけですが一つだけ注意してほしいところがあります。コードを簡単に書いたのでエラー処理やリンクとして正しくないときの処理を行っていません。その為上手くいかないときがあるかもしれません。（例えばファイルの中に空行があると次で説明する```system```関数の都合上空行一つにつきコマンドプロンプトが一つ残ってしまう。）普通に使う分には問題ありません。

# コード
次にコードの説明をします。コードは短いので直でここに載せます。

```haskell:webTmp/src/Lib.hs 
module Lib
    ( doStarts
    ) where

import System.Process
import Control.Monad

doStarts :: [String] -> IO ()
doStarts = mapM_ $ system . ("start " ++)
```
と

```haskell:webTmp/app/Main.hs
module Main where

import Lib
import System.Environment
import Control.Monad

main :: IO ()
main = do
    fPath <- head <$> getArgs
    ss <- lines <$> readFile fPath
    doStarts ss
```
だけです。全体は[github](https://github.com/ogata-k/webTmp/tree/master/webTmp)に載せておきます。といってもほかに重要なファイルはありません。
コードの説明をしていきます。説明といっても説明することはほとんどありません。
まず```Lib.hs```ファイルの説明です。
こちらは文字列のリストを分割して頭に```start```を取り付けてそれぞれを実行していきます。```system```関数は```System.Process```モジュールに入っており、文字列を受け取って実行、そして実行結果を返すという機能を持ちます。（詳しくは[こちら](http://hackage.haskell.org/package/process-1.6.3.0/docs/System-Process.html#v:system)）
次に```Main.hs```ファイルの説明です。
これは与えられた引数の```Filepath```を読み込んで文字列のリストとして```ss```に保持し、先ほどの```doStarts```関数に丸投げします。もう一度言いますが、簡単に書いただけなので引数の妥当性のチェックやファイルの中身が正しくリンクになっているかのチェックも行っていないので注意してください。（普通に使うなら問題はないはずです。）

# まとめ
いつも開くのがめんどくさくてやっつけ仕事で作ってみました。皆さんもどうぞ自己責任でお使いください。
Gethのオプション

Gethのオプションのメモ。

genesisブロックの定義。

```:geth
init
```

データを格納するディレクトリの指定

```:geth
--datadir 
```

networkidの指定、genesisブロックのconfigの中に書いた値と一致させる

```:geth
--networkid
```

指定したアカウントをアンロックした状態で起動

```:geth
--unlock
```

パスワードを指定、--unlockと一緒に使う

```:geth
--password
```

HTTP-RPCサーバーを有効化

```:geth
--rpc
```

アドレス、デフォルトでlocalhost

```:geth
--rpcaddr
```

ポート、デフォルトで8545

```:geth
--rpcport
```

マイニング実行状態で起動

```:geth
--mine
```

マイニングに使用するCPUの数、デフォルトは８

```:geth
--minerthreads
```

他のノードを探さない

```:geth
--nodiscover
```
Linux でトラックボールを設定する


標準でも最低限の操作はできるが、ボタンの個別割当とスクロールをやりたい

Linux Mint 18.3 Cinnamon
Kensington Expert Mouse 5

libinput で設定する
https://wiki.archlinux.jp/index.php/Libinput
https://www.mankier.com/4/libinput

# IDを調べる

```shell
$ lsusb
Bus 002 Device 004: ID 047d:1015 Kensington Expert Mouse
```
# ボタンの番号を調べる
`xev` と入力すると小さなウィンドゥが出てくるので、調べたいボタンを押せばよい

```shell
$ xev
...
ButtonPress event, serial 35, synthetic NO, window 0x7000001,
    root 0x1eb, subw 0x7000002, time 570051, (34,47), root:(896,1142),
    state 0x0, button 3, same_screen YES
...
```

```text:ボタン配置
+-------+
| 2 | 8 |
|--( )--|
| 1 | 3 |
+-------+
```


# 設定ファイル

左手で操作するので左右のボタンを入れ替えている

```text:/usr/share/X11/xorg.conf.d/30-kensington.conf

Section "InputClass"
	Identifier	"Kensington Expert Mouse"
	MatchUSBID	"047d:1015"
	Driver		"libinput"
	MatchDevicePath	"/dev/input/event*"
	Option		"ButtonMapping"	"3 2 1 4 5 6 7 8 9"
	
	Option		"ScrollMethod"	"button"
	Option		"ScrollButton"	"2"
	
EndSection
```

```shell
$ xinput list # id を調べる
Kensington USB/PS2 Expert Mouse  id=13
$ xinput list-props 13 # 設定内容の表示
```

# トグルスクロールの設定

上の設定ファイルだと、ボタン２（左上）をクリックしている間だけドラッグモードになる
トグル的な感じでモード切り替えができないかと思って DragLockButtons を設定したら Linux が起動できなくなってしまった
もしうまくいく設定がわかる人がいたら教えてほしい

```text:ダメ
        Option		"DragLockButtons"  "2 2"
```
BtoBアプリケーションの権限設定

目的は権限設定なのですが、内容はcurrent_userをmodelで使う方法になっております。。

## 背景
**Rails+deviseで稼働中のAPIで、ユーザー毎の権限設定を追加したい。**
いわゆるSaasで業務システムを開発しています。権限設定もいろいろなパターンがあると思うんですが、今回はデータに触れることが出来るかどうかを制御するパターンです（参照・更新できるかどうかではない）

## 実装検討
権限設定には大きく分けて２種類ある。。と思う。
1. 機能を制御（主にcontrollerで制御する。参照・更新・削除できるかどうか。）
2. データを制御（modelで制御？ あるデータを扱えるかどうか。）

１はイメージしやすい。各APIを使う権限であり、controllerのメソッドを制御できれば良く、cancancan、pundit等のgemがある。
２は主に対象データのあるレコードが参照可能か、更新可能かを制御する。
例えば、ユーザーAは、itemモデルのid:1のデータを更新可で、id:2のデータは参照不可。ユーザーBはid:2だけ更新可のような。

２のようなデータ制御ができるgemを自分は知らない。そこで、current_userをmodelのdefault_scopeで使ってしまうことにした。
本当はcontrollerでできると思うが、controller数もかなり多いので。。

## Thread.currentを使う
以下の様に書くと、modelでUser.current_idが使えるようになる。
User.current_id = nil で処理後にクリアしているので、これでも上手く動いていた。

```
def current_id=(id)
  Thread.current[:user_id] = id
end

def current_id
  Thread.current[:user_id]
end
  
around_action :scope_current_user

  private

  def scope_current_user
    User.current_id = current_user.id
    yield
  ensure
    User.current_id = nil
  end
```

## request_storeを使う
上記のThread.currentでもできるが、request_storeというgemを使うと、rack層でクリアしてくれる。

authenticated_controller.rbを以下のように変更する。
すると、RequestStore.store[:current_user_id] がmodelで使えるようになる。

```
  around_action :scope_current_user

  private

  def scope_current_user
    RequestStore.store[:current_user_id] = current_user.id
    yield
  end
```
以上で、modelでcurrent_user.idが使えるようになった。 current_user.idでユーザー毎に設定された権限を取得し、default_scopeに条件を追加する。これで、データを制御する権限設定が比較的かんたんに実現できる。
※ default_scopeは本来は使いたくないですね。

他に良い方法があればコメント下さい！！
講演会感想メモ-知識ゼロからわかるブロックチェーンと仮想通貨の全貌-

ブロックチェーンそろそろ理解してないと恥ずかしいなと思って、TECH::CAMPの主催する講演会、
「知識ゼロからわかるブロックチェーンと仮想通貨の全貌」にいってきたので、ちょっと書いてみます。

スピーカーは一般社団法人 日本ブロックチェーン協会 事務局長の 樋田 桂一さんです。
樋田さんは元々エンジニアだったのですが、 ビットコイン・アルトコインに可能性を感じて精力的に普及活動を進める熱い方でした。
講演内容はざっくりビットコイン・アルトコインについてとブロックチェーンについての２つに別れていました。
内容の比率でいうと8:2か9:1ぐらい。
5:5ぐらいを私は期待していたのですが、他の方の興味はビットコイン・アルトコインの方が高かったので、それはそうだろうなと。
私の目的にはあってなかったですが、ビットコイン・アルトコインについての思い込みを修正できたので有益でした。


##仮想通貨にはそれぞれ目的がある。

投機的な面が目立っていたため、仮装通貨それぞれに目的があって、独自の発展をしているというのは盲点でした。
例えばアルトコインの一種であるIOTAはIoTデバイス間の決済に最適化されているとか。
日本のモナコインは、コインを使うことが楽しみたいコミュニティができていて投げ銭的に使われ、コミュニケーションの一環にもなっているとか。
ビットコインは中央集権じゃないって聞いたことがあっていまいちピンときていなかったのですが、少し理解が進んだ気がしました。


##マイニングはやろうと思えば個人でもできる。
マイニングは電気代の安い国でしか成立しないと思ってこんでいました。
ただ、日本でもちゃんとやれば利益が出るようですね。
個人でもできて、去年の段階では秋葉原でマイニング用のセットを揃えると20万ちょっとぐらいで、半年ちょっとで利益が出てくるとか。
ちなみに、秋葉原にいかなくても空いてるノートパソコンがあればできるみたいですね。利益はあまり期待できないですが、試してみるにはいいのかも？https://hikicoin.com/bitzeny-mining/

---

だいたい以上でしたね。

ブロックチェーンについては講演で多くは聴けなかったのですが、その後の懇親会で詳しい人に聞けました。
知らないことを効率良く知ることができました勉強会でした。

また、そのうち別のテーマでも開催してほしいです。
Smartyディスられっぱなしだけどそんな悪くないと思うんだけどね。

#smartyテンプレート以外にいいじゃんと思ったのでまとめ

まず、smartyはかなり昔からあります。ナウな感じではないと思います。
ですが、ビューだけに特化して使う分には、すごい使いやすいなとここ最近になって感じています。

smartyではこれができるのにbladeだとできない…と思うときもありますし、結果的に行数もsmarty使ったほうが抑えられることもあります。

なので、皆さんが思うsmarty bladeについていろいろ聞いてみたいです。

もちろん、bladeは簡単に拡張することができるため、非常に使い勝手いいのは間違いないです。
しかし、smaryでは一行に書くことができるのに、bladeだと一行で書くことができない！という県がありまして、ずいぶん悩んだことがあります。

以下に例を示します。

```smarty
{if $user.name|default:'' == 1}
  <p>hoge</p>
{else}
  <p>huga</p>
{/if}
```
smartyだと上記のように書けますが、bladeだと

```HTML
@isset($user['name'])
　　@if ($user['name'] == 1)
　　　　<p>hoge</p>
　　@else
　　　　<p>huga</p>
　　@endif
@endisset
```

または

```HTML
@if ($user['name'] != null && $user['name'] == 1)
  <p>hoge</p>
@else
  <p>huga</p>
@endif
```

はい。全然いけてないですね。

データフォーマットとかなら、まぁ簡単に自作できるのでむしろbladeのほうが良かったりするかもしれませんが、ビューに特化した構文が何しろ豊富で、その点が優秀なのと、後ドットで繋げることができるのもいいですよね。laravelで関連付けしたテーブルをbladeで書くと

```PHP
$user->microposts['comment']
$user['microopsts']['comment']
```

上記のいずれかになるんですが、smartyなら

```smarty
{$user.microposts.comment}
```

こんな感じでメソッドチェーン式で書けるので書きやすいしわかりやすいんですよね。
そういう意味で、smartyのテンプレートエンジンも結構いいなーとは思うんですが、皆さんはどのように思っているでしょうか？
また、たいていsmartyディスっている人の多くは実はsmarty全然使ったことなくてよさがわからなかった。という可能性もあるので、改めてみていろいろ試してほしいなーって思ってる。

#ちなみに
もちろんbladeもすごくいいと思っています。smartyだとビュー呼び出し決まってincludeですが、bladeだとsection使ったり、もちろんincludeも使えたり、いろんな書き方ができますよね。
ただ、どうせblade使うんだったら、パーシャル化自動認識、$userとか渡したらliの中に入れ子でパーシャル作るようにする。みたいな感じで、rails並みにいろんなことができるようになるとさらに真の力発揮するんだろうなーって思っています。

ちなみになんでこんな話をしたかというと、実は入社３か月目あたりで、ある程度phpやフレームワーク理解したところで、とあるプロジェクトをcodeigniterからlaravelに移行作業することになりまして、その移行作業の中で思った節あったためこんな記事書いてみました。

炎上ウェルカム。どしどしコメント寄せてください。
使用Pythonモジュールをzip配布

Pythonスクリプト/スクリプトに使用しているサードパーティPythonモジュール群をzipファイル化して配布する方法を紹介します。

# 背景

pip経由で取得したサードパーティPythonモジュールを活用したPythonツール/スクリプトを配布するときに以下のように困った状況に陥ることがあります。

- ツールを使用するマシンではpipコマンドを使用できないため、Pythonモジュールをインストールできない。
- ツールを使用するマシンではDockerを使用できないため、PythonモジュールをDockerコンテナに同梱して配布できない。

Pythonは標準ライブラリが非常に充実しているため、ちょっと我慢して諦めてしまう人を結構見かけます。しかし上記の理由で「Pythonモジュールを使えば実装する時間を大幅に短縮できる」という選択肢を放棄するのは勿体なすぎます。

選択肢を放棄しないための手段の一つとして、本記事では**`Pythonモジュール群のzipファイルを作成し、これをPythonモジュールとしてimportする`**手順を紹介します。

# 手順

ここでは個人的にPythonスクリプトを作成する時によく利用するdocker, clickという2つのPythonモジュール(および依存関係)のzipファイルを作成してimportする手順を例として示します。

> NOTE: コマンドラインインタフェース(CLI)を持つツールを簡単に作りたい場合、clickはとてもお勧めなので是非とも利用してください

## zipファイルを作成

以下の手順で必要なPythonモジュール群のzipファイルを作成します。C言語モジュールが含まれている場合、作成したzipファイルはOS/プラットフォーム依存のものとなるため注意が必要です。

なおpipコマンドでPythonモジュール群を収集する手順については、`requirements.txt`等がある場合はそれを指定するようにしてください。

```bash
# 1. Pythonモジュール群を格納するディレクトリ作成
mkdir my-py-library

# 2. Pythonモジュール群をpip経由で収集
# -> この例ではdocker, clickを依存関係含めて収集
pip3 install docker click -t my-py-library

# 3. C言語モジュールがないかチェック
# -> 存在する場合は、OS/プラットフォーム依存となる
find my-py-library | egrep '\.so$|\.pyd$'

# 4. Pythonモジュール群のzip化
cd my-py-library
zip -r  ../my-py-library.zip *
cd ..
```

これで上記の例では`my-py-library.zip`というzipファイルが作成されます。これを次の手順でimportすることにより、このzipファイルに含まれているclick, dockerモジュールを利用できます。


## zipファイルをimport

Pythonスクリプトと同じディレクトリにzipファイルが配置されている場合、以下のようにimportします。

- `sys.path.insert(0, <zipファイルパス>)`でzipファイルをPYTHONPATHとして追加する
  - `os.path.realpath(__file__)`を使用することで、Pythonスクリプトの絶対パスを取得できる。この絶対パスを用いてzipファイルのパスを指定する。
- PYTHONPATHを追加した後、必要なPythonモジュールをimportする。

なお、下記例のようにPYTHONPATHを設定した場合、どこからPythonスクリプトを実行した場合でもPythonスクリプトと同じディレクトリのzipファイルを参照されます。Pythonスクリプトとzipファイルをセットで配布する場合は、このようにPYTHONPATHを設定した方が色々と都合が良いです。

```python
import os
import sys

# PYTHONPATHにzipファイルを追加
basepath = os.path.split(os.path.realpath(__file__))[0]
sys.path.insert(0, os.path.join(basepath, 'my-py-library.zip'))

# zipファイルに含まれるPythonモジュールをimport
import click
import docker

# Do something...
```

import文の箇所でエラーが発生しなければ正常にimportされています。


# 補足

- zipファイルではなくディレクトリでも利用できます。zipにしているのは以下の利点があるためです。やや特殊な開発、運用ルールがあるところでは意外と重宝します。
  - 配布が容易である
  - バージョン管理システムでソースコードとして管理する必要がない

- C言語モジュールが含まれる場合、動作環境がOS、CPUアーキテクチャ、Pythonバージョンに依存するようになります。また内部で特定環境(ex. Linux, mac OS)のコマンドを実行していたり、ライブラリにアクセスなどをしている場合はC言語モジュールが含まれていない場合でも同様です。

- ここで紹介した手順はPython2/3の両バージョンで利用できます。
  - Python2.3で導入された`zipimport`を使用した仕組みのため、基本的にPython2.3以上であれば利用可能。
自動車のアーキテクチャに対する脅威

車両のセキュリティの本を読んでいたら出てきた単語をまとめる。
参考文献：「[カーハッカーズ・ハンドブック](https://www.amazon.co.jp/%E3%82%AB%E3%83%BC%E3%83%8F%E3%83%83%E3%82%AB%E3%83%BC%E3%82%BA%E3%83%BB%E3%83%8F%E3%83%B3%E3%83%89%E3%83%96%E3%83%83%E3%82%AF-%E2%80%95%E8%BB%8A%E8%BC%89%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E5%88%86%E6%9E%90%E3%83%BB%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3-Craig-Smith/dp/4873118239)」
#携帯電話回線
最近の自動車は携帯電話回線で情報を送受信する。その結果、内部の車載ネットワークにアクセスされる可能性がある。
また、通信の盗聴の恐れもある。
#Wi-Fi
基本的に携帯電話回線を使用した際の脅威と似た感じ。
#キーフォブ（key fob）
スマートキーシステムの鍵のこと。不正なキーフォブリクエストを送信して、イモビライザ（自動車盗難防止システム）を異常状態にすることができる。こうすると、エンジンがかけられなくなる。また、キーフォブ信号をジャミングすることで、鍵を使用できない状態にできる。アルゴリズムが解読されれば、鍵を複製されてしまう。
#タイヤ空気圧監視センサ（TPMS: Tire Pressure Monitoring System）
タイヤの空気圧を監視するセンサ。この部分を悪用されると、パンクの通知などがめちゃくちゃになる。
#USB
USBポートに接続することで色々な悪さができる。
例えば、マルウェアのインストールなど。
#CAN(Controller Area Network)
CANバス接続を悪用されると、キーなしで車両の始動が可能となるらしい。
CUDA 9.1とcuDNN 7.1をUbuntu 16.04LTSにインストールする 

# CUDA Toolkit 9.1のインストール
[NVIDIAの公式ページ](https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&target_distro=Ubuntu&target_version=1604&target_type=debnetwork)からCUDA Toolkit 9.1をダウンロードする。ダウンロードしたフォルダで以下のコマンドを実行する。メタパッケージの`cuda-9-1`をインストールすると、全てのCUDA ToolkitとDriverパッケージがインストールされる。（CUDA 9.0のインストール方法は[こちら](https://qiita.com/JeJeNeNo/items/b30597918db3781e20cf)）

```bash:terminal
sudo dpkg -i cuda-repo-ubuntu1604_9.1.*_amd64.deb
sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
sudo apt update
sudo apt install cuda-9-1
```

# パスの設定
以下のechoコマンドでCUDAのパスを`.bashrc`のファイルの最後に書き込む。その設定をsourceコマンドで読み込む。

```bash:terminal
echo -e "\n## CUDA and cuDNN paths"  >> ~/.bashrc
echo 'export PATH=/usr/local/cuda-9.1/bin:${PATH}' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda-9.1/lib64:${LD_LIBRARY_PATH}' >> ~/.bashrc
source ~/.bashrc # CUDAのパスが書き込まれた~/.bashrcを読み込む。
```

```bash:.bashrcに追加される文字列

## CUDA and cuDNN paths
export PATH=/usr/local/cuda-9.1/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/cuda-9.1/lib64:${LD_LIBRARY_PATH}
```

CUDAのパスが通っているか確認。

```bash:terminal
echo $PATH             # 出力に"/usr/local/cuda-9.1/bin"が含まれているか？
echo $LD_LIBRARY_PATH  # 出力に"/usr/local/cuda-9.1/lib64"が含まれているか？
which nvcc             # 出力が"/usr/local/cuda-9.1/bin/nvcc"になっているか？
nvidia-smi             # nvidiaのGPUの情報が表示されているか？
```

# cuDNNのインストール
## cuDNN 7.1のインストール
https://developer.nvidia.com/rdp/cudnn-download からcuDNN 7.1 for CUDA 9.1のdebパッケージをダウンロードする（アクセスするにはメンバー登録が必要）。具体的には以下の３個のdebパッケージをダウンロードする。

- cuDNN v7.1.* Runtime Library for Ubuntu16.04 (Deb)
- cuDNN v7.1.* Developer Library for Ubuntu16.04 (Deb)
- cuDNN v7.1.* Code Samples and User Guide for Ubuntu16.04 (Deb)

ダウンロードしたフォルダで以下のコマンドを実行して、cuDNNをインストールする。

```bash:terminal
# Install Runtime library
sudo dpkg -i libcudnn7_7.1*+cuda9.1_amd64.deb
# Install developer library
sudo dpkg -i libcudnn7-dev_7.1*+cuda9.1_amd64.deb
# Install code samples and user guide
sudo dpkg -i libcudnn7-doc_7.1*+cuda9.1_amd64.deb 
```

# 動作確認
CUDAのサンプルコードを実行して動作確認する。
サンプルコードをホームディレクトリにコピーするシェルスクリプト（cuda-install-samples-9.1.sh）は　`/usr/local/cuda-9.1/bin/` にあるので、CUDAのパスが通っていればそのファイル名を指定するだけで実行できる。

```bash:terminal
cuda-install-samples-9.1.sh ~ # ホームディレクトリにサンプルコードをコピー。
cd ~/NVIDIA_CUDA-9.1_Samples/
make
cd 2_Graphics/volumeRender    # サンプルの実行ファイルがあるディレクトリに移動。
./volumeRender
```

![volume_render.png](https://qiita-image-store.s3.amazonaws.com/0/134160/9c0cea1a-53dd-7346-78f3-7513f65b5d70.png)

# アンインストール方法

```bash:terminal
sudo apt remove cuda-9-1
sudo apt autoremove
sudo apt remove libcudnn7 libcudnn7-dev libcudnn7-doc
rm -rfv ~/NVIDIA_CUDA-9.1_Samples/ # サンプルコードを消す。
# ~/.bashrcに追加されたPATHの設定をテキストエディタなどで消す。
# ログアウトしてPATHの設定の変更を反映
```

# 参考
https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#package-manager-metas
[CUDA 8.0とcuDNN 6をUbuntu 16.04LTSにインストールする](https://qiita.com/JeJeNeNo/items/05e148a325192004e2cd)
[CUDA 10とcuDNNをUbuntu 18.04LTSにインストールする](https://qiita.com/JeJeNeNo/items/045948694327977f614f)
kintoneの画像スライドショーからクリックでレコードを開く

# どういうこと？
こういうことです。

![demo.gif](https://qiita-image-store.s3.amazonaws.com/0/96599/0313ad25-309b-da43-c021-873d442da262.gif)

kintoneのデフォルトの機能では、添付ファイルのサムネイルをスライドショーで表示できますが、その写真をクリックしても該当のレコードを開いてくれません。
そこでJavaScriptでカスタマイズすることにしました。

# コード
```JavaScript
(function(){
    document.body.addEventListener('DOMNodeInserted', function(event){
        if(event.target.className == 'slideshow-cybozu'){
            var slideshow = event.target;
            slideshow.addEventListener('DOMNodeInserted', function(event){
                if(event.target.tagName == 'IMG'){
                    var img = event.target;
                    if(img.parentElement.className.includes('slide-image-cybozu')){
                        img.style.cursor = 'pointer';
                        img.onclick = function(){
                            var params = new URLSearchParams(img.src);
                            var rec_id = params.get('record');
                            open(`/k/${kintone.app.getId()}/show#record=${rec_id}`);
                        }
                    }
                }
            });
        }
    })
})();
```

# インストール方法

[kintoneのヘルプ](https://jp.cybozu.help/ja/k/admin/javascript_fullcustomize)を参照して下さい。
Yum - よく使うコマンドオプション、設定のまとめ

Yum について、よく使うコマンド、設定をまとめました。

# 想定環境

RHEL 7, CentOS 7

# yum コマンド関連

### パッケージアップデート

OS インストール後は、セキュリティパッチを適用するために、パッケージアップデートするのが鉄板です。

```
// アップデート可能なもの全て
# yum update

// セキュリティ更新を含むアップデートのみ(セキュリティに関するアップデートのみ。バグフィックスは適用しない)
# yum update-minimal --security

// セキュリティ更新を含むアップデートのみ(セキュリティに関するアップデートを行い、最新にする)
# yum update --security
```

### 使うリポジトリを指定したインストール

```
# yum install --disablerepo \* --enablerepo epel,base パッケージ名
```

### グループインストール

```
// 一覧を取得
# yum groups list

// インストール
# yum groups install グループ名
```

### パッケージを探す

```
// クエリ文字列にマッチするパッケージ一覧を取得
# yum search QUERY

// コマンド名などから、それを含むパッケージ名を取得
# yum provides FEATURE
```

### パッケージに含まれるファイル一覧を取得

```
// パッケージ未インストールの場合にも一覧取得可能
# repoquery --list パッケージ名
```

### パッケージの削除

```
# yum remove パッケージ名
```

### キャッシュの消去

古い不正な情報が残っていて、インストール失敗する場合に実行する場合に使用。

```
yum clean all
```

##### 使用履歴

```
# yum history

// undo もできる…が、今の時代なら、仮想マシンのスナップショットや、
// Immutable Infrastructure のようなサーバ管理をしたほうがよいかも。
# yum history undo 履歴番号
```

# リポジトリ関連

### リポジトリの一覧

```
// enableのみ
# yum repolist

// 全て
# yum repolist all
```

### リポジトリの有効化/無効化

```
// 有効化
# yum-config-manager --enable リポジトリ名
// 無効化
# yum-config-manager --disable リポジトリ名
```

# rpm コマンド

rpm コマンドは、個々のパッケージの情報を得たいときに。

### パッケージの一覧

```
$ rpm -qa
```

### パッケージの情報

```
$ rpm -qi パッケージ名
```

### パッケージが含むファイルの一覧

```
$ rpm -ql パッケージ名
```

# その他

### epel リポジトリの追加

```
# yum install epel-release
```

### proxy の設定

```/etc/yum.conf``` に記述する。

```
proxy=http://proxy.example.com:8080
```

### インストール用 ISO イメージをリポジトリ化

ISO ファイルをマウントする。

```
$ cp mount_dir/media.repo /etc/yum.repos.d/dvd.repo
```

```/etc/yum.repos.d/dvd.repo``` ファイルを編集。

```
baseurl=file:///mount_dir
```

### RPM ファイルをカレントに展開

```
# rpm2cpio RPMファイル | cpio -idv
```

# 参考

[システム管理者のガイド: 第8章 Yum](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-yum)
RaspberryPiにpyenvでPython3環境を作る

[RaspberryPiにpyenvを導入](https://qiita.com/h-sakano/items/cb8df027b81acd78bd77)を参考にして python3系をpyenv下でインストールする

pyenvに必要なパッケージのインストール

```
$ sudo apt-get install -y git openssl libssl-dev libbz2-dev libreadline-dev libsqlite3-dev
```

pyenvのインストール

```
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
```

クローンし終わったら`.bash_profile`に設定を追加する。

emacs信者の人は先に `$ sudo apt-get install emacs24` してemacsを入れておきましょう

```
$ sudo emacs ~/.bash_profile

# 以下の内容を追記
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
```
ちなみに、「`.bash_profile`？ `.bashrc`ではなく？」という人は[こちらのリンク](https://qiita.com/shyamahira/items/260862743e4c9794b5d2)参照

インストールできるバージョンの一覧表示

```
$ pyenv install --list
```

今回は適当に3.5.1あたりをインストール（けっこう時間かかると思うので☕でも淹れて待ちましょう）

```
$ pyenv install 3.5.1
```
もしもパッケージ無いよ的なエラーや警告が発生したら無いと言われたものをinstallする

現状のpythonのバージョンを確認

```
$ python --version
Python 2.7.5
```
インストールした python3系に切り替え

```
$ pyenv global 3.6.1
```

もう一度 `python -V`すると切り替わっていることわかる

```
pi@raspberrypi:~ $ python -V
Python 3.6.1
```

元のsystemのpythonに戻したくなったら

```
$ pyenv global system
```
特定のリポジトリでコミットしたときのアカウントを変える方法

会社アカウントのGitlab(Github)の特定リポジトリを自宅PCで作業してコミットしたときに、コミット履歴を会社アカウント名で表示させる方法

## nameとe-mailを変更

「git config local」のデータを変更すると、その特定リポジトリのみアカウントが変わる

### 変更箇所を確認

``` command:command
$ git config --local --list
```

- user.name
- user.email

上記の設定を会社アカウントに変更する

### 設定

```　command:command
$ git config --local user.name hoge
$ git config --local user.email fuga@foo.bar
```

下記に変わっていれば設定完了

``` command:command
$ git config --local --list
user.name=hoge
user.email=fuga@foo.bar
```

## 参考サイト

- [特定のgitリポジトリでuserとemailを変える](http://te2u.hatenablog.jp/entry/2013/08/02/222232)
GitHub の Pull Request を絞り込みで選択して手元に持ってくる


コードレビューが非常に多いので重宝していた。

んだけど、ちょっと前に今まで使っていたどこかで拾ったツールが動かなくなった。
多分 github の api の下位互換がなくなったかなんかだろう。

[github api v4](https://developer.github.com/v4/) は graph-ql になっていて、触ってみたくなったので自分で作り直すことにした。
（前のツールは僕の経験のない言語で出来ていたので書き足しをする気はなかった。）

## 準備等
`jq`と`percol`（とか）が必要。
あと github で personal access tokens を取っておく。

## pull request 一覧を取得
まずこれをどこかに置いておく。

git 管理されているディレクトリでこのスクリプトを実行すると、そのリポジトリの open な pull request が一覧で取得できる。

```sh:github_pull_requests.sh
#!/bin/bash

token_path=`dirname "${0}"`/token
token=`cat $token_path`

repo_owner=`git config --get remote.origin.url | tr -s '/' '\n' | tail -r | sed -n 2,2p`
repo_name=` git config --get remote.origin.url | tr -s '/' '\n' | tail -r | sed -n 1,1p | tr -s '.' '\n' | head -n 1`

fetched=`curl -sS -H "Authorization: bearer $token" -d @- https://api.github.com/graphql <<EOF
{
    "query": "query {
      repository(owner:\"$repo_owner\", name:\"$repo_name\") {
        pullRequests(last:20, states:OPEN) {
          edges {
            node {
              title
              number
              headRefName
              author {
                login
              }
            }
          }
        }
      }
    }"
}
EOF`

echo $fetched | jq --raw-output '.data.repository.pullRequests.edges[].node | [.number, .title, .author.login, .headRefName] | @tsv' | tr '\t' '®' | column -t -s '®' | sort -r
```

（`"`と`,`が pull request の title に含まれていてもちゃんと縦揃えするってのが大変だった...）

次に同じディレクトリに`token`というファイルで personal access tokens を書いて置いておく。
こんな感じで書けば良い。

```sh
echo '665axxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxa0' > token
```

きっとこんな感じに取れるはず。
![スクリーンショット 2018-03-04 13.55.52.png](https://qiita-image-store.s3.amazonaws.com/0/113398/35015f4a-e1cc-cae4-328f-a9cdf661b507.png)

## 選択とチェックアウト
`reviewing`というブランチ名でチェックアウトをする。
僕は`gprp`というコマンドとして`zsh`から呼び出して使っている。

```sh:gprp
#!/bin/zsh

git fetch --prune > /dev/null 2>&1
git branch -D reviewing > /dev/null 2>&1

script_path=`dirname "${0}"`/github-pull-requests/github_pull_requests.sh

number=`sh $script_path | percol --match-method regex | tr -s ' ' '\n' | head -n 1`

git fetch origin pull/$number/head:reviewing
git checkout reviewing
```

![github-pull-requests.gif](https://qiita-image-store.s3.amazonaws.com/0/113398/8dbc46d6-82d4-2b87-fad7-1f32d0cb351e.gif)

## 融通
という名の手抜き。

+ `branch`や`author`は絞り込み検索のためのみに取ってきている
  + 実際には`number`があれば実現できる
  + 好きな箇所を`query`で指定すれば良い
+ `gprp`にパスを通せば使えるだろう
+ 名前も好きにすれば良い
+ チェックアウト先のブランチ名とかも好みで
+ `peco`や`fzf`にもすぐ変えられるだろう
+ 特にエラー制御はなし

以上。
先週これが出来なくなっていて不自由していたので、これで安心。
自分で書いたことで縦揃えを組み込むことが出来たので、満足。
AWS Database Migration Serviceメモ

#Database Migration Serviceを触ってのメモ

##前提
- 移行元：VPC１のパブリックサブネットに用意したmySQL on EC2
 - ※リモート接続できるユーザを用意しておく。
 - ※今回は権限周りでつまづくのを嫌ってrootで用意した
- 移行先：VPC2のプライベートサブネットに用意したRDS for mySQL

##DMSを使うにあたっての準備
- DMS用のサブネットグループの作成
 - 複数のサブネットにまたがる必要がある
 - レプリケーションインスタンスがSource/targetの各DBにアクセスできる必要があるので、指定のサブネットに気をつける。
 - ※特にVPNやDXを使用しない場合においてはパブリックの通信ができるサブネットを選択する必要がある。

##レプリケーションインスタンスを作成
- 上記サブネットにDMSで使用するレプリケーション用のインスタンスを作成する
 - レプリケーションエンジンを選べる（1.9.0/2.4.1）※2018/03/04時点
- VPCを選択
- マルチorシングルAZを選択可能
- インターネット経由の場合、バブリックアクセス可能にチェック
- インスタンスのストレージ
- KMSキーの指定
- メンテンアンス時間を選ぶ


##エンドポイントの作成
Source（移行元DB）、target（移行先DB）に接続ができるエンドポイントを作成する
###制約事項は十分に確認すること
データ移行のソース
https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Source.html
###データ移行のターゲット
https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Target.html


##タスクを作成する
レプリケーションインスタンス

- ソースエンドポイント
- ターゲットエンドポイント
を指定する

移行タイプは以下から選べる

- 既存のデータ移行
- 既存のデータを移行して、継続的な変更をレプリケート
- データ変更のみをレプリケートする

すぐにタスクを開始したくない場合は、「作成時にタスクを開始」からチェックを外しておく

##タスク設定
- まとめて後述
Tinkercad > レーザーカットしてもらったギアを回してみる > Cog Ring2 (MDF)以外はすべて回った

ブラウザ動作するAutoDeskのTinkercad。


### 関連

- [Tinkercad > Download > レーザカット用にダウンロード > .SVGファイル | カットしてもらった](https://qiita.com/7of9/items/75d6a302362ec34a5fc3)
- [Tinkercad > オブジェクト間の距離を知る > ルーラーで2つの位置をそれぞれ見る](https://qiita.com/7of9/items/449a2250beffd8122a59)

### 概要

- Tinkercadにて作成したギアをレーザーカッターでカットしてもらった
    - [デザイン @ Tinkercad](https://www.tinkercad.com/things/kXT4eq0steK)
    - UNIVERSAL LASER SYSTEMS社製 VSL4.60 60W
- MDF材とアクリル材料を使用
- ギアを回すための板を検討
    - [Tinkercad > オブジェクト間の距離を知る > ルーラーで2つの位置をそれぞれ見る](https://qiita.com/7of9/items/449a2250beffd8122a59)

ギアが回るか確認した。

### 使用工具と材料

- Makita, インパクトドライバ TD111D
- TD111D用ビット
    - 木工用ショートドライバ, 穴径20.0mm
    - バイメタルホールソーJ型, 穴あけサイズ 20mm
- 材料: アガチス工作材 (3mm厚み)
- ギア各種 (6種類)
    - [Tinkercad > Download > レーザカット用にダウンロード > .SVGファイル | カットしてもらった](https://qiita.com/7of9/items/75d6a302362ec34a5fc3)
    - MDFは2mm厚み
    - アクリル材は3mm厚み

### 工作

[Tinkercad > オブジェクト間の距離を知る > ルーラーで2つの位置をそれぞれ見る](https://qiita.com/7of9/items/449a2250beffd8122a59)
で調べた通り、アガチス工作材に中心距離19mmで2つの穴をあける。

バイメタルホールソーJ型での工作では、時間がかかるが穴をあけることができた。

木工用ショートドライバでの工作では、穴をあけようとした途端に**アガチス工作材が破断して飛んでいった**。

下記の結果はバイメタルホールソーJ型であけた穴について述べる。

### 結果

- メートルギア(MDF材): 回転した
    - [YouTube動画](https://www.youtube.com/watch?v=gxJSYl0LUUU)
- メートルギア(アクリル材): 回転した
    - [YouTube動画](https://www.youtube.com/watch?v=d7B41fxPdlc)
- Useful Gear(MDF材): 回転した
    - [YouTube動画](https://www.youtube.com/watch?v=xpDndTP9XGs)
- Useful Gear(アクリル材): 回転した
    - [YouTube動画](https://www.youtube.com/watch?v=ErfxX2f1DXg)
- Cog Ring2(MDF材): 回転しなかった
    - [YouTube動画](https://www.youtube.com/watch?v=I-DszcMONOw)
- Cog Ring2(アクリル材): 回転した
    - [YouTube動画](https://www.youtube.com/watch?v=zoTCnfO1-qQ)

Cog Ring2(MDF材)以外、回転した。


### 備考

このギアの仕組みを使ってESP8266 + [L6470](https://strawberry-linux.com/catalog/items?code=12023)などを使って何かできるだろうか。

https://strawberry-linux.com/catalog/items?code=12023
> ・モータ電圧：ＤＣ８Ｖ～４５Ｖ　※外部から供給 

電圧が普段使用のものではない。
Wi-Fi接続してるPCでLinux Mintを使いたかった

Linux Mintを入れたはいいけどWi-Fiに接続できなくてケータイで原因を調べてる人（俺）向けの内容です。
#初期状態でワイヤレスドライバがインストールされていない
だからWi-Fiが使えないんですね。実に単純。
なんでドライバを入れたら解決です。

###1.メニューからドライバマネージャを起動
- 検索欄に`driver`と入れれば右のカラムの一番上に出てきます

![001.png](https://qiita-image-store.s3.amazonaws.com/0/240483/abbe052d-ac67-87f8-82ee-2aae9f3972cc.png)

###2.ドライバをインストール
- 基本的には一番上のbcmwl-kernel-source(推奨)を入れればOKです。
- これでも繋がらなければ2つ目、3つ目のドライバも試してみてください。<br>
使用されているWi-Fiモジュール等の違いでこれが発生するらしい。
    - その際はインターネットへの接続が必要になるので、一時的にイーサネットで接続します。
    - イーサネットポートが付いていないノートPCは以下のようなアダプタで接続できます。<br>
    [j5create イーサネットアダプタ](http://www.j5create.com/jpn/our-products/ethernet-adapters/jue130.html)

![002.png](https://qiita-image-store.s3.amazonaws.com/0/240483/89425128-5673-cbd6-df69-ac9c9dc2df45.png)

#まとめ
Linux Mintは初期設定でやる事がわりと多い。
気合で乗り越えよう
最少手順でLaravel APIを試す

たぶん最少手順。

# やりたいこと

- とりあえずLaravelでJSON返すAPIを作ってみたい
- 試したいだけなのでDBとか使わない

# 前提

- PHP7.x導入
- Composer導入
- Laravelプロジェクト作成

以上は済んでる前提で。
本稿環境はPHP7.2, Laravel5.6。

# 手順

## Controller作成

~~~bash
php artisan make:controller ApiTestController --resource
~~~

作られたController見るといろいろメソッドがあるがindex()だけ編集。
適当な配列返す機能を実装。

~~~php:app/Http/Controllers/ApiTestController.php
public function index()
{
    $testData = [
        ["id" => "1", "title" => "foo"],
        ["id" => "2", "title" => "bar"],
        ["id" => "3", "title" => "baz"]
    ];
    return $testData;
}
~~~

## Routes編集

末尾に以下を追記。

~~~php:routes/web.php
// APIテスト
Route::resource('test', 'ApiTestController');
~~~

## ビルドインサーバー起動

~~~bash
php artisan serve
~~~

## 動作確認

~~~
localhost:8000/test
~~~

<img width="458" alt="スクリーンショット 2018-03-04 13.19.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/176237/7a2b26d7-50d7-880d-f3c0-6bb180e33970.png">

こんな感じでJSON出力を確認できたらOK。

# 参考

- 『PHPフレームワーク Laravel入門』(掌田津耶乃, 秀和システム, 2017)