OmniAICreator/Qiita-1.07M huggingface dataset:
Google翻訳について

【Google翻訳について】
どこを調べても出てきませんでしたので、質問させていただきます。

Google翻訳（サイト埋め込み）でプルダウンで出てくる言語の順番の変更はできますか？
例：
1.スペイン
2.ドイツ
3.フランス
4.韓国語
5.中国語
↓
1.中国語
2.韓国語
3.フランス....
など

![翻訳.jpg](https://qiita-image-store.s3.amazonaws.com/0/301389/7ddff5f1-0800-99da-3df2-cc7dd8982daa.jpeg)

よろしくお願いします。
MySQLのrootにパスワードを設定した後、rails sが出来なくなる問題を解決する方法

#問題
MySQLにrootパスワードを設定した後に、rails sをしようとするとMySQLにアクセスする事が出来ずに
######ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
が出てきてしまって困ってる方、僕だけじゃないはず。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/301628/b6531094-327f-cedf-6f6a-4fa4aa24778b.png)
自分は約三日間苦しんだのですが、先輩の方々に色々と教えてもらい何とか解決する事が出来ました。
今回はその解決方法を書いていきます！！

#まずはconfig/database.ymlを開く

```ruby:config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password:
  socket: /tmp/mysql.sock
```

ここで注意！！

#####:bangbang:やってはいけない例

```ruby:config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: あなたのMySQLのrootパスワード（例:aiueo1234）
  socket: /tmp/mysql.sock
```



defaultのpasswordの所に直接自分のパスワードをdatabase.ymlに書いてしまうのは絶対にやめましょう。確かにこれでrails s出来るようになるのですが誤ってGitHubにコミット、プッシュしちゃった時に自分のパスワードを悪用されてしまう危険性があります。

したがって、今回は環境変数と呼ばれるものを使用します。
だいぶざっくり説明すると環境変数とはコンピュータ自体が持てる変数のようなものです。


```ruby:config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: <%= ENV['RAILS_DATABASE_PASSWORD'] %>
  socket: /tmp/mysql.sock
```


passwordに<%= ENV['RAILS_DATABASE_PASSWORD'] %>を記入！
これで環境変数を利用する下準備が出来ました。
後は肝心の環境変数自体をターミナルで定義するだけです！

#ターミナルを開く

```terminal:ターミナル
 $
```

ディレクトリはホームディレクトリ（〜）でやります！
#「vim .bash_profile」と打ち込む

```terminal:ターミナル
 $ vim .bash_profile
```
enterを押して画面が切り替わったら
⓵　「i」を押してインサートモードへ
⓶ export RAILS_DATABASE_PASSWORD='あなたのMySQLのrootパスワード'を入力
⓷Escキーを押してインサートモード終了
⓸「:wq」と入力して保存&終了

⓶でデータベースのパスワードをbash_profileで定義する事でdatabase.ymlから呼び出せるって事です！

保存&終了が出来たら終了！！！、、かと思いきや
bash_profileは
######ターミナルを開き直すか、sourceコマンドで更新しないと反映されない
という性質があるのでターミナルを再起動するか

#source ~/.bash_profileを打ち込んで反映させる

```terminal:ターミナル
$ vim .bash_profile
$ source ~/.bash_profile //これを入力！
```
特に何も変わってなさそうに見えてしっかり反映されているので気にしなくて大丈夫です。
#終了！！お疲れ様です！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/301628/7713cfd3-c3d0-5bd5-266e-ef43709a3f55.png)
無事に動いてくれました！
[Azure]Microsoft Azureはじめてみる

#はじめに
従量課金で知らないうちに課金されていたり...など、少し不安もあり一歩を踏み出せていない状態でしたが、そうも言ってられない世の中になってきていますので、いまさらですがAzureに挑戦です。
#準備
###Microsoftアカウントの登録
[Microsoftアカウント](https://www.microsoft.com/ja-jp/msaccount/default.aspx)
マイクロソフトのさまざまなサービスを利用可能となります。
Windows 10などで利用しているユーザーも多いでしょうから、詳細は省略します。
Microsoftアカウントが用意できたら、AzureのサイトにサインインしてAzureアカウントを作成します。
###Azureアカウントの登録 
[Azureアカウント](https://azure.microsoft.com/ja-jp/free/)
このページにある［無料で始める］のリンクをクリックして登録すると、Azureのサービスを最大30日間、2万500円分まで試用できます。（2018/10時点）
先ほど作成したMicrosoftアカウントでサインインして、個人情報(氏名、住所、メールアドレス、電話番号、クレジットカードなど)を登録します。
「電話による本人確認」などありますが、ウィザード形式で進んで行くので迷うことはないでしょう。
30日間無料版の終了後は、有償プランを契約できます。

#Azureの管理用ポータルへアクセスする
[AzurePortal](https://azure.microsoft.com/ja-jp/features/azure-portal/)
サインインしてAzureの管理画面のトップページ（ダッシュボード）が表示されたら登録完了です。
![ポータル.png](https://qiita-image-store.s3.amazonaws.com/0/226493/a1f5a4ab-da5e-70ee-1c03-93c7ce0da686.png)

#リソースグループを作る
まずは、リソースグループを作成しないと始まりません。
リソースグループとは、その名の通りリソースの塊です。
目的別やライフサイクルごとにリソースグループを分けると管理しやすいと思います。
今回はお試しということで、「Trial」というリソースグループを作成します。
![Azureリソースグループ.png](https://qiita-image-store.s3.amazonaws.com/0/226493/0b9e26d5-5426-f314-3e4e-6f48683b521a.png)

>[リソースグループとは](https://docs.microsoft.com/ja-jp/azure/azure-resource-manager/resource-group-portal)
>リソース グループは、Azure ソリューションの関連するリソースを保持するコンテナーです。 リソース グループには、ソリューションのすべてのリソースか、グループとして管理したいリソースのみを含めることができます。 組織のニーズに合わせてリソースをリソース グループに割り当てる方法を指定してください。 通常は、同じライフサイクルを共有するリソースを同じリソース グループに追加して、グループとして簡単にデプロイ、更新、および削除できるようにします。
リソース グループには、リソースについてのメタデータが格納されます。 そのため、リソース グループの場所を指定するとき、このメタデータが格納される場所を指定することになります。 コンプライアンス上の理由から、データは特定のリージョンに格納されるようにする必要があります。

---
準備完了！さてクラウド上で何やろう？
async関数の戻り値をコールバック関数内から返す

async関数の戻り値をコールバック関数内から返す方法です。
といっても良くわからないと思うので、下のコードを見てください。
こんな感じで値を返したいときがあると思いますが、その方法の紹介記事です。

```dart
Future<String> hoge() async {
  fuga().then((){
    // ここからhoge関数の値を返したい
  })
  .catchError((){
    // ここからhoge関数の値を返したい
  });
}
```

Completerというクラスを使って次のようにかけます。

```dart
Future<String> hoge() async {
  final Comleter<String> completer;
  fuga().then((){
    completer.complete("then");
  })
  .catchError((){
    completer.completeError("error");
  });
  return completer.future;
}
```
DjangoのDBを初期化してリストアする手順

## この記事について

ただの備忘録です。すみません。
こんな備忘録でも役に立てばいいかなと思います。

## 使用環境

CentOS 7.5
Python 3.6.5
Django 2.1.2

## 手順

```sql:MySQL
DROP DATABASE [DB名];
CREATE DATABASE [DB名] CHARACTER SET utf8mb4;
```

ここでDjangoのmigrationファイルを消します。

```shell:コンソール
python manage.py makemigrations [アプリ名]
python manage.py migrate
python manage.py loaddata [アプリ名]/fixtures/app.json
systemctl restart httpd
```

## 最後に

もっとスマートな方法あればコメントいただけたら幸いです。
【Bitbucket Pipelines】Go 言語の依存パッケージ（vendor/）等を cache する

pre-defined cache の中に golang のものは無かったので、自分で定義する必要がある。

以下は `dep` を使った例。

```yml:bitbucket-pipelines.yml
image: golang

pipelines:
  default:
    - step:
        caches:
          - gobin  # ※ dep 等もキャッシュしている
          - vendor # 依存パッケージのキャッシュ
        script:
          - IMPORT_PATH="${GOPATH}/src/bitbucket.org/${BITBUCKET_REPO_OWNER}/${BITBUCKET_REPO_SLUG}"
          - mkdir -pv "${IMPORT_PATH}"
          - tar -cO --exclude-vcs --exclude=bitbucket-pipelines.yml . | tar -xv -C "${IMPORT_PATH}"
          - cd "${IMPORT_PATH}"
          - make setup
          - make

definitions:
  caches:
    gobin: "${GOPATH}/bin"
    vendor: "${GOPATH}/src/bitbucket.org/${BITBUCKET_REPO_OWNER}/${BITBUCKET_REPO_SLUG}/vendor"
```

※以下のような Makefile の想定

```makefile:Makefile
DEP := ${GOPATH}/bin/dep

.PHONY: default setup build

default: build

setup: $(DEP)
	$(DEP) ensure -vendor-only

$(DEP):
	go get -u github.com/golang/dep/cmd/dep

build:
	go build
```

## メモ

キャッシュを展開したあとに、同じ階層に `tar` でソースコードを展開しているのできちんとキャッシュが効くか不安だったが、問題無さそうだった。

## 参考

* [Caching dependencies - Atlassian Documentation](https://confluence.atlassian.com/bitbucket/caching-dependencies-895552876.html)
UDP, TCP通信をコマンドで実行する

#サーバー側

- UDPでListenする

```
nc -l -u -p [ポート番号]
```

- TCPでListenする

```
nc -l -p [ポート番号]
```

# クライアント側

- UDPで送信する

```
nc -u [ホスト名/IP] [ポート番号]
```

- TCPで送信する

```
nc [ホスト名/IP] [ポート番号]
```
[GAS] Google フォームの公開用URLを取得し、スプレッドシートにまとめる

# イントロダクション
## 背景
複数の細部が異なるアンケート管理のために、複数の Google フォームからアンケート用ページの公開用URLのまとめたい。
## 目的
Google フォームの選択→「送信ボタン」→「フォームを送信のリンク」から得られるアンケート回答者用の公開用URLを取得する。
## 目標
Google スプレッドシートに Google フォーム名, 公開用URLを列名としてデータをまとめる。イメージは下記のような図である。
![名称未設定2.png](https://qiita-image-store.s3.amazonaws.com/0/154819/bb4b8109-d247-50fb-d9f6-03a2e347bda3.png)


# ソースコード
## 単一のフォームと公開用URL
予め、フォーム名と公開用URLをまとめるためのスプレッドシートのIDを取得する。
下記のプログラムのIDの部分はスプレッドシードのIDを記入して実行する。

```javascript
function mySF3(){
  // IDで指定したスプレッドシートを開く
  var excel_data = SpreadsheetApp.openById('ID').getActiveSheet();
  // フォームを作成
  var form = FormApp.create("getPublishedUrl");
  // 公開用URLを取得
  var tmp = form.getPublishedUrl();
  
  // スプレッドシートに書き込み_列名を生成
  excel_data.getRange(1,1).setValue("ページ名");
  excel_data.getRange(1,2).setValue("公開用URL");
  
  // スプレッドシートに書き込み_内容を書き込み
  excel_data.getRange(2,1).setValue(form.getTitle());
  excel_data.getRange(2,2).setValue(tmp);
  
  
}
```

## 複数のフォームと公開用URL
単一のフォームと公開用URLのプログラムに for 文を追加した。二つのフォームとそれらに対応する二つの公開用URLをまとめる。


```javascript
function mySF32(){
  // IDで指定したスプレッドシートを開く
  var excel_data = SpreadsheetApp.openById('ID').getActiveSheet();
  // スプレッドシートに書き込み_列名を生成
  excel_data.getRange(1,1).setValue("ページ名");
  excel_data.getRange(1,2).setValue("公開用URL");
  
  for(i = 1; i <= 2; i++){
    // フォームを作成
    var form = FormApp.create("Test " + i );
    form.setTitle("Test " + i )
    // 公開用URLを取得
    var tmp = form.getPublishedUrl();  
    
    // スプレッドシートに書き込み_内容を書き込み
    excel_data.getRange(i + 1,1).setValue(form.getTitle());
    excel_data.getRange(i + 1,2).setValue(tmp);
  
  }
}
```
# 参考文献
ErgoDoxEZによるバッククォートからの逃走

[過去](https://qiita.com/chesscommands/items/ce2883ad0a0c6c27c8de#kc_gesc "自前投稿")に、グレイブキーをEscキーにして使い分ける投稿をしたが、まだ浅かったようだ。
そのため、もう少し踏み込む。
MacOSに対しても浅かったため、さらに[踏み込む](#macosでのバックティック)。


過去の検証は、タップでEscキーになり、GUIキーと組みあわせたときにグレイブキーになるというものだった。

WindowsOS：Ctrl+Shift+Esc
⇒タスクマネージャが起動する。
しかし、今回の設定を有効にしている場合、Escキーとして機能せず、タスクマネージャは動かない。

そのため、制限を掛けることが可能だ。
4種類ある。

* [GRAVE_ESC_ALT_OVERRIDE](#grave_esc_alt_override)：Altキー押下に限らずEscキー有効
* [GRAVE_ESC_CTRL_OVERRIDE](#grave_esc_ctrl_override)：Ctrlキー押下に限らずEscキー有効
* [GRAVE_ESC_GUI_OVERRIDE](#grave_esc_gui_override)：Guiキー押下に限らずEscキー有効
* [GRAVE_ESC_SHIFT_OVERRIDE](#grave_esc_shift_override)：Shiftキー押下に限らずEscキー有効

制限というのは、他で押している(GuiやShift)などに関わらず、Escキーとして動くようにする。


記載場所はご存じだろう。

```ErgoDoxEZ:クローンディレクトリ\github_repository\qmk_firmware\keyboards\ergodox_ez\config.h
#define GRAVE_ESC_GUI_OVERRIDE
```

`KC_GESC`は、いつも通りに、keymap.cファイルだ。












# GRAVE_ESC_ALT_OVERRIDE
これを定義しなくても起動していたウィンドウが次々入れ替わる。
これを定義したことで、何が変わったのかよく分からない。MacOS用か!?



# GRAVE_ESC_CTRL_OVERRIDE
これを定義しなくてもCtrl+KC_GESCにて、Windowsメニューが開く。
これを定義したことで、何が変わったのかよく分からない。MacOS用か!?

取りあえず、`Ctrl+Shift+KC_GESC`にて、タスクマネージャが起動するようになった。



# GRAVE_ESC_GUI_OVERRIDE
この定義で、`Guiキー+KC_GESC`にて、Escキーのままとなった。
ところで、\`記号は、どのようにして打てばよくなるのだろうか・・・。



# GRAVE_ESC_SHIFT_OVERRIDE
この定義で、`Shiftキー+KC_GESC`にて、Escキーのままとなった。
~記号は、どのようにして打てば良くなるのだろうか。

そして、今回の定義によって、`Ctrl+Shift+KC_GESC`の組合せからタスクマネージャが起動するようになった。








# [レディットからのコメント](https://www.reddit.com/r/olkb/comments/9ogiwv/grave_escape_not_sending_kc_grave_when_gui_is_held/)
[ソースコード](https://github.com/qmk/qmk_firmware/blob/master/quantum/quantum.c#L198 "ギットハブのQMK")を読みさえすれば、挙動を確認できるとのこと。
















# [MacOSでのバックティック](https://docs.qmk.fm/#/feature_grave_esc?id=caveats)
``commands + ` ``の組み合わせは、"次のウィンドウにフォーカスを移動"するショートカットが割り当てられているため、今回のキーコードは使えない。



















# 重要な注意点
レイヤー移動と合わせて使おうとした(LTなど)。
その場合、動かない。その辺は注意されたし。
原因は、今回の機能とは別の話になるのだが、レイヤー移動に設定できるキーコードは、決められている。
[Basic Keycodes](https://github.com/qmk/qmk_firmware/blob/713ec91147aa56849f9e2ff93ee98ef1eb6eebc0/docs/keycodes_basic.md)
この説明のなかに存在しないキーコードは設定しても無効化される。




# 感想
今回の検証は、WindowsOSでのみ試した。
MacOSやLinuxなどの他のOSでの挙動は分からない。


以上だ。
DjangoにおけるWSGI設定について

## この記事を書くに至った経緯

以前どっかのサイトを参考にしながら
Djangoの設定をしたのですが
設定ミスってLet'sEncryptが自動更新しなくなったので
(ApacheのドキュメントルートをDjangoのドキュメントルートにしたというやらかし)
復旧させるために~~(Forbidden喰らいまくった)~~試行錯誤してたら
すごく苦労してしまったので備忘録として書こうと思いました。

## 使用環境

CentOS 7.5
Apache 2.4
Python 3.6.5
Django 2.1.2

## 前提として

pipでmod_wsgiを導入しているので
`/etc/httpd/conf.module.d/`に自動生成されたconfファイルを使っています。
導入方法などはほかの記事などでも見つかると思いますので割愛します。

自分は`/home`直下に置いているので
その辺は読み替えていただければと思います。

## 設定ファイルと各項目について



```shell:[wsgi_module].conf
# NOTE:
# Only one mod_wsgi can be loaded at a time.
# Don't attempt to load if already loaded.
<IfModule !wsgi_module>
        LoadModule wsgi_module modules/[wsgi_module].so #自動生成で入っていると思います。
        WSGIScriptAlias /mysite /home/mysite/mysite/wsgi.py
        WSGIPythonPath /home/mysite
        Alias /static /home/mysite/static
        <Directory /home/mysite/mysite>
                <Files wsgi.py>
                        Require all granted
                </Files>
        </Directory>
        <Directory /home/mysite/static>
                Require all granted
        </Directory>
</IfModule>
```

LoadModuleは最初から生成されたままで修正なしです。
LoadModule以下は追記(もしくは変更)します。

まずWSGIScriptAliasは
第一引数(？)に実際アクセスするディレクトリ名を
第二引数にWSGIの設定があるファイル(Djangoならmysite/mysite/wsgi.py)
を指定します。

次にWSGIPythonPathは
Djangoでいうプロジェクトの場所を指定します。

Aliasですがstaticディレクトリでアクセスする場所を指定します。

Directoryディレクティブですが
wsgi.pyがある場所を参照できるようにする
staticディレクトリがある場所を参照できるようにする
って感じです。

最後にすべてに共通することですが
ディレクトリの最後のスラッシュは入れないようにします。
(**自分の勘違いかもしれませんが**動いたのでこういう指定なのだと思ってます)

## 最後に

これでやっと公開できました(別原因で正確にはまだ奮闘した)
すっごい初心者なのでもし何か間違ってたら
もしくは補足等ありましたらコメントいただけると幸いです。
Windows インストーラーでエラーが出てアンインストールできない

#はじめに
Windows7で起こったお話。
とあるアプリケーションをアンインストールしようとしたら、エラーメッセージが表示されて、アンインストールができません。
>インストールのログ ファイルを開くときに、エラーが発生しました。 指定されたログ ファイルの場所が存在し、書き込み可能であることを確認してください。

![capt_001.png](https://qiita-image-store.s3.amazonaws.com/0/226493/f24d400e-c3d5-31f8-d191-63a5479e8a42.png)

今回、エラーが発生したのは、独自で作成したアプリケーションでしたが、他のアプリケーションでも発生することはあるようですのて対象方法をメモっておきます。

#対処方法
Microsoftでも既知の問題として認識されているようで、この問題を解決するチェックプログラムが公開されています。

[プログラムのインストールまたは削除をブロックしている問題を解決する](https://support.microsoft.com/ja-jp/help/17588/fix-problems-that-block-programs-from-being-installed-or-removed)

１.上記ページからダウンロードした「MicrosoftProgram_Install_and_Uninstall.meta.diagcab」を実行します。

２.「プログラムのインストールとアンインストールのトラブルシューティングツール」が起動しますので、「次へ」をクリックします。
![17588-01.png](https://qiita-image-store.s3.amazonaws.com/0/226493/d15759cc-b2cd-c8bd-84f0-b3715344b488.png)
３．「問題を検出しています」ので、しばらく待ちましょう。
![17588-02.png](https://qiita-image-store.s3.amazonaws.com/0/226493/3432bd2d-083a-ffc4-bdda-76c6d6656dfa.png)
４．今回は、アンインストール時の問題なので「アンインストール」をクリックします。
![17588-03.png](https://qiita-image-store.s3.amazonaws.com/0/226493/fad40862-8059-5c67-8d21-21199baf8b72.png)
５．「問題を検出しています」ので、しばらく待ちましょう。
![17588-04.png](https://qiita-image-store.s3.amazonaws.com/0/226493/5406c312-6910-72c5-af28-3018654c3052.png)
６．リストから問題のアンインストールしたいアプリケーションを選択して、「次へ」をクリックします。
![17588-05.png](https://qiita-image-store.s3.amazonaws.com/0/226493/c42181f1-19a6-745e-866f-dd9b9589add0.png)
７．再確認されるので、「→はい、アンインストールを試行する」をクリックします。
![17588-06.png](https://qiita-image-store.s3.amazonaws.com/0/226493/a27bfa65-2831-c199-db86-42d2ac695922.png)
８．「問題を解決しています」ので、しばらく待ちましょう。
![17588-07.png](https://qiita-image-store.s3.amazonaws.com/0/226493/5a2f46f3-eee7-75f8-9bd6-a48efc24f7e5.png)
９．無事アンインストールされました。
![17588-08.png](https://qiita-image-store.s3.amazonaws.com/0/226493/ff973643-3599-2a3a-fc9c-149a3a9d342d.png)


Windows7で起こった問題ですが、スクリーンショットがWindows10なのは内緒です。
【備忘録】『JAVASCRIPTエンジニアのためのNODE.JS入門』の参考になった部分まとめ

<a href="https://www.amazon.co.jp/JavaScript%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AENode-js%E5%85%A5%E9%96%80-%E5%A4%A9%E7%94%B0%E5%A3%AB%E9%83%8E-ebook/dp/B01N2Y16BQ/ref=as_li_ss_il?s=digital-text&ie=UTF8&qid=1540281350&sr=1-1&keywords=JAVASCRIPT%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AENODE.JS%E5%85%A5%E9%96%80&linkCode=li3&tag=protein078-22&linkId=48333f6554098fd275d678cbc11cc021&language=ja_JP" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B01N2Y16BQ&Format=_SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=protein078-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=protein078-22&language=ja_JP&l=li3&o=9&a=B01N2Y16BQ" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

Node.jsに入門しています。気になる部分があればご指摘ください:joy:

## readFileメソッドは非同期で動作する

```javascript
var http = require('http');
var fs = require('fs');

var server = http.createServer(function(req, res) {
    fs.readFile('./temp.html', 'utf-8', function(err, data) {
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.write(data);
        res.end();
    })
});

server.listen(1234);
console.log('start server');
```

## 静的ファイルの供給にはストリームの pipe メソッドを使う

```javascript
var http = require('http');
var fs = require('fs');
var url = require('url');

var server = http.createServer(function(req, res) {
    var urlParts = url.parse(req.url);
    var path = __dirname + '/' + urlParts.pathname;
    var stream = fs.createReadStream(path);
    stream.pipe(res)
});

server.listen(1234);
console.log('start server');
```

## express を使った実装

```javascript
var express = require('express');
var ejs = require('ejs');
var bodyParser = require('body-parser');
var app = express();

app.engine('ejs', ejs.renderFile);
app.use(bodyParser.urlencoded({
    extended: true
}));

app.get('/', function(req, res) {
    console.log('---GET Reqest---');
    console.log('name is ' + req.query.name);
    console.log('age is ' + req.query.age);
    res.render('temp.ejs', {});
});

app.post('/', function(req, res) {
    console.log('---POST Request---');
    console.log('name is ' + req.body.name);
    console.log('age is ' + req.body.age);
    res.render('temp.ejs', {});
});

var server = app.listen(1234, function() {
    console.log('start server');
})
```
DockerのMySQLコンテナに外部のサーバーから接続する

## 概要
DockerでMySQLコンテナを立て、ホストOS、または外部サーバーから接続する方法。

## docker runの場合

```shell-session
$ sudo docker run \
    --rm \
    -v $(pwd)/db/mysql_init:/docker-entrypoint-initdb.d \
    -v $(pwd)/db/mysql_data:/var/lib/mysql \
    --name mysql \
    -e MYSQL_ROOT_PASSWORD=your_password \
    --hostname my-mysql \
    -e BIND-ADDRESS=0.0.0.0 \
    -p 3306:3306 \
    -itd mysql:5.7
```

## docker-composeを使う場合

```yaml:docker-compose.yml
version: '3.1'

services:
  db:
    image: mysql:5.7
    restart: always
    hostname: my-mysql
    env_file:
      - .env
    environment:
      MYSQL_USER: sample_user
      MYSQL_DATABASE: sample_db
      TZ: "Asia/Tokyo"
      BIND-ADDRESS: 0.0.0.0
    ports:
      - 3306:3306
    # データを永続化させる場合
    volumes:
      # 初期データを投入するSQLが格納されているdir
      - ./db/mysql_init:/docker-entrypoint-initdb.d
      # 永続化するときにマウントするdir
      - ./db/mysql_data:/var/lib/mysql
    tty: true
```

### envファイルにMySQLのROOTのパスワードを定義する

```ini:.env
MYSQL_ROOT_PASSWORD=your_password
```

## コンテナ起動

```shell-session
$ docker-compose up -d --build
```

## MySQLに接続
### ホストOSから接続

```shell-session
$ mysql -u root -p -h localhost -P 3306 --protocol=tcp
```

### 外部のサーバーから接続

```shell-session
$ mysql -u root -p -h hostname -P 3306 --protocol=tcp
```

## コンテナ間通信
### ネットワークを作成
sample-networkというネットワークを作成。

```
$ sudo docker network create sample-network
```

sample-networkを定義したコンテナ同士で、コンテナ間通信が可能となる。

### DBコンテナを作成
#### Dockerコマンドの場合

```shell-session
$ docker run \
  --name sample-db \
  -p 3306:3306 \
    -e MYSQL_USER=sample \
    -e MYSQL_PASSWORD=Sample_123 \
    -e MYSQL_ROOT_PASSWORD=Password_123 \
  --rm \
  --detach \
  mysql:5.7
```

#### docker-composeの場合

```yaml
version: '3.2'

services:
  db:
    container_name: sample-db
    image: mysql:5.7
    restart: always
    hostname: sample-db
    env_file:
      - .env
    environment:
      MYSQL_USER: sample_admin
      MYSQL_DATABASE: sample
      TZ: "Asia/Tokyo"
      BIND-ADDRESS: 0.0.0.0
    ports:
      - "3306:3306"
    # データを永続化させる場合
    volumes:
      # 初期データを投入するSQLが格納されているdir
      #- ./db/mysql_init:/docker-entrypoint-initdb.d
      # 永続化するときにマウントするdir
      - ./mysql_data:/var/lib/mysql
      - ./conf/my.cnf:/etc/my.cnf
    tty: true
    networks:
      - sample-network

networks:
    sample-network:
        external: true
```

### WEBコンテナを作成
#### Dockerコマンドの場合

```shell-session
$ docker run --rm \
    --name sample-web \
    --network sample-network \
    -itd sample-web /bin/bash
```

#### docker-composeの場合

```yaml
version: '3.2'

services:
  web:
    container_name: sample-web
    build:
      context: ./
      dockerfile: Dockerfile
    hostname: sample-web
    volumes:
      - ./code:/code
    ports:
      - "3000:3000"
    tty: true
    networks:
      - sample-network

networks:
    sample-network:
        external: true
```
SPSS Modelerでモデルナゲットのプッシュバック

SPSS ModelerでモデルによってはスコアリングをSQLプッシュバックさせることができます。
スコアリングがSQLプッシュバックできるとDB内で処理ができる部分が増えます。特にスコアリングだけがSQLプッシュバックできていない場合にはすべての処理を一つのSQLで処理することができて効果的です。

#環境
Modeler 18.1.1
Windows 10 64bit

Db2 Warehouse on cloud

#スコアリングのSQLプッシュバック
モデルナゲットを右クリックして編集します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/605838fa-fba5-ed0b-4e06-f327fa9399df.png)

設定タブで「欠損値のサポートのないネイティブSQLへの変換によるスコア」を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/3eb38751-cbfd-a5ba-8a69-9b0986a55cb6.png)

SQLプッシュバックがうまくいくとモデルナゲットが紫色にかわり、プッシュバックが成功したことが確認できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/3c9e50c6-b3ad-937d-61e0-17b622081620.png)

今回試したのは決定木なので、CASE文でそれが表現されています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/74833fa9-aa85-0fdc-52a7-ad27429345cb.png)
【個人的備忘録】pythonのリスト・タプル・dictなど

```
◎サンプルコード
・[リスト]
li = [[1,2,3],[4,5,6],[7,8,9]]

print(li[0])

・[タプル]
t = {"札幌","仙台","東京","名古屋","大阪","福岡"}

print(type(t))
print(t)

・[dict]
d = ({500:"aaa",400:"bbb",600:"ccc"})

print(d)
```

追記:ご指摘がありましたので訂正させていただきます。申し訳ありませんでした。
Spring Boot でセッションスコープBeanを定義したら動きがおかしかったので調整が必要だった

# はじめに

Spring Boot (Freemarker + Doma2)の構成でアプリケーションを構築しているときの話。
ゆるふわな理解で実装してるのが悪いんだけど、セッションスコープのBeanを定義したときに、ftl上で`hoge.fuga`のようにプロパティアクセスできなかった。
`hoge.getFuga()`のようにGetter経由でアクセスすればよかったんだけど、どうせなら原因究明してプロパティアクセスできるようにしたらいいと思って頑張ったらできた。
ついでにJSONとして返すときも変なプロパティがついてたので、つかないようにした

## 問題の原因

セッションスコープのBeanは`cglib`で作られたプロキシに包まれていた。
多分このプロキシが`ThreadLocal`な変数を持っていて、リクエストごとに異なったオブジェクトのプロキシになっているんだろう。


## 対応方針

出力時にプロキシを剥いて生のオブジェクトを取り扱うようにする、Configurationを書いてやればいい。
幸いにして、プロキシは`ScopedObject`というインターフェースを持っているようで、`ScopedObject#getTargetObject`で剥くことができた。

Freemarkerへの対応はこちら

```FreemarkerConfig.java


@Configuration
public class FreemarkerConfig {

  @Autowired
  void configureFreemarkerConfigurer(FreeMarkerConfig config) {
    freemarker.template.Configuration templateConfig = config.getConfiguration();
    templateConfig.setObjectWrapper(new CustomWrapper());
  }

  private static class CustomWrapper extends DefaultObjectWrapper {
    CustomWrapper() {
      super(freemarker.template.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
    }

    @Override
    protected TemplateModel handleUnknownType(Object obj) throws TemplateModelException {
      if (obj instanceof ScopedObject) {
        return super.handleUnknownType(((ScopedObject) obj).getTargetObject());
      }
      return super.handleUnknownType(obj);
    }
  }
}
```

Jacksonへの対応がこちら

```JacksonConfig.java

@Configuration
public class JacksonConfig {

  @Autowired
  public void configureObjectMapperConfig(ObjectMapper objectMapper) {
    objectMapper.registerModule(new ScopedObjectModule());
  }

  private static class ScopedObjectModule extends Module {

    @Getter
    private final String moduleName = "scopedObjectModule";

    @Override
    public Version version() {
      return PackageVersion.VERSION;
    }

    @Override
    public void setupModule(SetupContext context) {
      context.addSerializers(new Serializers.Base() {
        @Override
        public JsonSerializer<?> findSerializer(SerializationConfig config, JavaType type, BeanDescription beanDesc) {
          Class<?> raw = type.getRawClass();
          if (ScopedObject.class.isAssignableFrom(raw)) {
            return new ScopedObjectSerializer(type.getSuperClass());
          }
          return super.findSerializer(config, type, beanDesc);
        }
      });
    }
  }

  @AllArgsConstructor
  private static class ScopedObjectSerializer extends JsonSerializer<ScopedObject> {

    private JavaType type;

    @Override
    public void serialize(ScopedObject value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
      serializers.findValueSerializer(type).serialize(value.getTargetObject(), gen, serializers);
    }
  }
}
```
Powershellでカウンティングセマフォ


# 実装(Start-job,Wait-job,Remove-Jobを使う)

```powershell

# 第一引数に実行するスクリプトブロック、第二引数に処理の上限数を受け取る関数「counting-semaphore」
# 第二引数がない場合は処理上限数は10となる
function counting-semaphore ([scriptblock]${scriptbl},${number}=10) { 

	# カウント用変数のインクリメント
	$script:counting++

	# カウント用変数が上限数に達した場合、処理終了を待つ
	switch ($script:counting) { 
		{$_ % ${number} -ne 0} {start-job $scriptbl -name "name$script:counting"}
		{$_ % ${number} -eq 0} {start-job $scriptbl -name "name$script:counting"
					for ($i=1;$i -le ${number};$i++) {
						wait-job   -name "name$i"
						remove-job -name "name$i"
					}
			$script:counting = 0
			}
	}	 
}

```

# 実行例

```powershell

for ($i=1;$i -le 2;$i++) {
        counting-semaphore {echo $using:i} 1

}
```
Start-Jobについて
https://social.technet.microsoft.com/Forums/ja-JP/6451c2da-48b0-47f9-b620-2ee889974697/startjob-12398scriptblock?forum=powershellja


汎用化するなら重複しない名前を発行する仕組みが必要
RecursiveDirectoryIteratorで親ディレクトリまで対象に入る

## 前書き
ぼく「`/var/www/tmp/`以下にある全部のディレクトリを削除したいな～」
ぼく「`/var/www/`以下が全部消えた…」

## ダメなコード
```PHP:dame.php
<?php
    $iterator = new RecursiveDirectoryIterator("/var/www/tmp/");
    $iterator = new RecursiveIteratorIterator($iterator);

    foreach ($file_infos as $file_info) {
        //そのファイルがディレクトリなら
        if ($file_info->isDir()) {
            exec(escapeshellcmd("rm -rf " . $file_info->getRealPath()));
        }
    }
```

これだと、`.`や`..`まで削除してしまいます。つまり、`rm -rf /var/www`が実行されてしまいます。

## 大丈夫なコード
```PHP:ok.php
<?php
    $iterator = new RecursiveDirectoryIterator("/var/www/tmp/",FilesystemIterator::SKIP_DOTS);
    $iterator = new RecursiveIteratorIterator($iterator,RecursiveIteratorIterator::SELF_FIRST);
    $file_infos = iterator_to_array($iterator);

    foreach ($file_infos as $file_info) {
    //そのファイルがディレクトリなら
        if ($file_info->isDir()) {
            exec(escapeshellcmd("rm -rf " . $file_info->getRealPath()));
        }
    }
```

`FilesystemIterator::SKIP_DOTS`を入れることで、`.`や`..`をスキップします。

### ハマったこと
#### ディレクトリを取得できない
`/var/www/tmp/hoge/`に入った時にも`.`がスキップされるので、ディレクトリが取得できなくなります(伝われ)
そこで、[サブフォルダ内のファイルをまとめて取得する](https://qiita.com/re-24/items/94eeea3e8051e212d9ed)にあるように、`RecursiveIteratorIterator`の引数に`RecursiveIteratorIterator::SELF_FIRST`を付けると取得できます。

#### `UnexpectedValueException`が投げられる
`foreach`の部分、最初は

```PHP
foreach ($iterator as $file_info) {
```

と書いていたのですが、こうすると`UnexpectedValueException`が出ます。
これは`foreach`の中でディレクトリを削除しているので、`$iterator`が次の値を取るときに削除されていて取れないみたいな感じの感じだと思います。
そこで、[stackoverflow](https://stackoverflow.com/questions/7153826/recursivedirectoryiterator-throws-unexpectedvalueexception-on-too-many-open-fil)にあるように、`iterator_to_array()`を使ってイテレータを配列にしちゃいます。
メモリ使用量は増えますがまあいいや(適当)

## 最後に
`/var/www/html`も吹き飛ぶので気を付けようね！
makefile でのOS条件分岐

自動化のためにmakefileを書いています。

私の場合、Linux端末とMacとの異なる環境で共通のmakefileを使いますので、条件分岐を勉強してみました。無手勝流ながら以下の設定でうまく作動してくれるようになりました。


````shell
# makefile

ifeq ($(shell uname),Linux)
.txt.html:
	perl ~/Dropbox/Web/GH/mw/makeweb.pl $< $@
	chromium $@
else
.txt.html:
	perl ~/Dropbox/Web/GH/mw/makeweb.pl $< $@
	open -a "Google Chrome" $@
endif
````

### ifeq を使う

````shell
ifeq  ($(shell uname),Linux)
```` 

というところが条件判断の部分です。

何をしているかというと、[結城浩さんのMakeWebというPerlスクリプト](https://www.hyuki.com/makeweb/) を使って、TEXTフォーマットのファイルをHTMLフォーマットに書き出しています。この部分はLinuxもMacも共通です。


つづいて、書き出された当該ファイルを自動的に Chromeで開くという簡単なコマンドなのですが、LinuxとMacとでは命令の標記が異なるので分岐させて各々のコマンドを書いています。

### uname
unameは、Linuxコマンドなので、windowsでは使えないですが、Linux/Mac の判別には便利です。

ターミナルで ````uname```` コマンドを打つことで、OSの情報を得ることができます。


上記の例では、Linux かどうかを判断させてLinuxのコマンドを書き、elseでMac のコマンドを実行させていますが、逆にしたい場合は以下のように書きます。

````shell
ifeq  ($(shell uname),Darwin)
````
プライベートサブネット上のAmazon EMRクラスターにNATゲートウェイは不要か？

## 先に結論
* プライベートサブネット上のクラスターはサービスアクセス用のENIを介してEMRと通信するため
NATゲートウェイを使用せずにジョブを実行できる
    * ただしS3のVPCエンドポイントは必ず必要
* クラスタの起動リクエスト自体はインターネットを介してEMRのエンドポイントにAPIリクエストを投げる必要がある

|実行したい内容|NATGWが必要か|
|---|---|
|プライベートサブネット内からのRunJobFlow等のAPIリクエスト|必要|
|他のAWSサービスと通信が不要なジョブを実行|不要|
|VPCエンドポイントに対応していないAWSサービスと通信が必要なジョブ|必要|
|VPCエンドポイントに対応しているAWSサービスと通信が必要なジョブ|不要|


## ドキュメントやFAQによって記載がまちまち

**VPC 環境で Amazon EMR クラスターを起動する方法を教えてください。**
https://aws.amazon.com/jp/premiumsupport/knowledge-center/emr-launch-cluster-vpc/
> Amazon EMR のプライベートサブネットを使用する場合は、NAT ゲートウェイとセキュリティグループを使用する**必要があります**。

**ネットワークの計画と構成**
https://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-plan-vpc-subnet.html
> パブリックおよびプライベート VPC サブネットの両方で EMR クラスターを起動できます。これは、EMR クラスターを実行するために、インターネット接続が**必要ないことを意味します**。

また、以下からはAWSのサービスエンドポイントに対する通信が発生しなければ
NATゲートウェイは不要と読み取れます。

> ただし、たとえば企業イントラネット内、または AWS Key Management Service などのパブリック AWS サービスエンドポイントなど、VPC の外側にあるサービスまたはリソースにアクセスするために、サービスネットワークアドレス変換 (NAT) および VPN ゲートウェイを構成しなければならない場合があります。

以下のドキュメントからも通信が必要なAWSサービスにVPCエンドポイントが提供されていれば
NATゲートウェイが不要と読み取ることができます。

**Amazon VPC オプション** - プライベートサブネット
https://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-clusters-in-a-vpc.html#emr-vpc-private-subnet

> VPC エンドポイントを提供しない AWS サービスにアクセスするには、NAT インスタンスまたはインターネットゲートウェイを引き続き使用する必要があります。

## 実際に試してみる

クラスターの作成時、プラベートサブネットを指定すると以下のようなメッセージが出ますが、
クラスター自体の作成は可能です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/cf035f33-9935-61e4-8f2d-df3d3468f64f.png)

ちなみにEMRコンソール上からS3エンドポイント、NATインスタンスの作成はできるのですが、
今のところNATゲートウェイの作成には対応していないようです。

クラスターのブートストラップおよび、サンプルのHiveスクリプトの実行も問題なく完了します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/d02ac5e2-c7db-12ae-b643-99c96272d406.png)

**参考: ステップ 4: Hive スクリプトの実行によるサンプルデータの処理**
https://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-gs-process-sample-data.html

## クラスターはどのようにEMRのサービスエンドポイントと通信するか
NATゲートウェイがない環境でもEMRはクラスターの状態やジョブの処理状況を認識しています。
サブネット上に作成されたサービス通信用のENIを介してクラスターが管理されているためです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/703bf2e3-59d4-da25-dbed-2f77361bd4f3.png)
https://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-clusters-in-a-vpc.html#emr-vpc-private-subnet

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/1612ff2f-9d09-e3a1-5a3d-34d66df5a08a.png)

**参考: 当時のBlog Post**
【新発表】- Amazon EMRクラスタをプライベートサブネットで起動
http://aws.typepad.com/aws_japan/2015/12/new-launch-amazon-emr-clusters-in-private-subnets.html

> プライベートサブネットでは、EMRサービスがクラスタと通信するために使うENIに設定するセキュリティグループを指定することもできます。


以上です。
参考になれば幸いです。
[MyBatis]大量データをマッピングするときはCursorを使おう

# はじめに

この間仕事で、大量データを扱っていて、どうしてもレスポンスがでない処理を見直すことなりました。
全体的に、約4分くらいかかる処理でした。
この処理を見直すときに、MappperをListではなく、org.apache.ibatis.cursor.Cursorに修正しました。
その結果、レスポンスを早くすることができました。

せっかくなので、MyBatis3.4以降で追加されたCursorの使い方についてまとめていきます。

# 動作環境

- Java 1.8.0_181
- Spring FrameWork 4.3.16
- MyBatis 3.4.5
- mybatis-spring 1.3.1

※ mybatis-springだけ、プロジェクトによって必要／不必要が分かれると思います。

# 使い方

mapper.xmlは、Listで取得するときと特に変える必要はありません。
大量データを処理するので、fetchSizeでキャッシュのサイズを調整すると、さらに良いと思います。

```mapper.xml
  <select id="getColumns" fetchSize="50000" resultType="java.lang.String">
    SELECT columns FROM table1
  </select>
```

Mapper.javaは、org.apache.ibatis.cursor.Cursorをインポートします。
\<String>の部分は、SQLの戻り値に合わせてください。

```Mapper.java
import org.apache.ibatis.cursor.Cursor;

@Mapper
public interface Mapper {
    public Cursor<String> getColumns();
}
```

Mapperから呼び出す部分です。
Cursor\<T>型に呼び出し結果を格納する以外は、Listと同様です。

また、ループ処理で値を取り出す部分も、Listと同じように書くことができます。
サンプルでは、forEachとIteratorの2種類で書いています。

```Service.java
@Service
public class Service {
    @Autowired
    private Mapper mapper;

    public void getMapper() {
        try (Cursor<String> columnsCorsor = mapper.getColumns()) {

            // ループ処理１
            columnsCorsor.forEach(s -> {
                System.out.println(s);
            });

            // ループ処理２（2回目のループはエラーするので注意！！）
            Iterator<String> iterator = columnsCorsor.iterator();
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
            }

        } catch (Exception e) {
            e.printstacktrace();
        }
    }
}
```

注意しなければならないのは、Listで取得した時とは違い、**Cursor内のデータを全て読み込んだタイミングで**、closeされます。
そのため、1回でも全データを取り出したあとに、もう一度データを取り出しにいくと、下のようなエラーが出ます。

```
java.lang.IllegalStateException: Cannot open more than one iterator on a Cursor
```

基本的な使用方法の場合は、MyBatis側がクローズしてくれるので問題ないと思います。

しかし、途中でエラーが発生した場合、クローズしてくれる保証はありません。
なので、呼び出し元でtry~resource文かfinally句などで、**しっかりとクローズ**してあげましょう。

# 最後に

Cursorのおかげで、レスポンスを4分から2分まで短縮することができました。
（Cursor以外の部分も見直した結果ですが……）
大量データを処理する際は、ぜひCursorを活用してみましょう。


# 雑記
MyBatisって参考資料が少ないので、利用者は少ないのかなと思っています。
DBアクセス系のフレームワークは、何が主流なんでしょうか…？
MyBatisは生SQLをかけるし、良い感じにマッピングしてくれるので、個人的には気に入っているのですが…
~~アノテーションにたまにイラッとすることはありますが~~

# 参考文献
[MyBatis – MyBatis 3 | Mapper XML ファイル](http://www.mybatis.org/mybatis-3/ja/sqlmap-xml.html)
[Cursor | mybatis](http://www.mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/cursor/Cursor.html)
[5.2. データベースアクセス（MyBatis3編） — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.0.1.RELEASE documentation](https://terasolunaorg.github.io/guideline/5.0.1.RELEASE/ja/ArchitectureInDetail/DataAccessMyBatis3.html)
[補足・蛇足版] アジャイルとは何か？今あらためて誤魔化さずに実践的に説明してみる

[アジャイルとは何か？今あらためて誤魔化さずに実践的に説明してみる](https://qiita.com/567000/items/33c8821f014885024577)の続編、補足版です。

大きな話としては上の投稿の通りですが、そこでは表現しきれなかった細かな「アジャイル ≒ Scrum」のテクニックが存在しています。みなさん知りたいことはそれぞれなので、そういうものを補足的に離散的に説明。どれか１つでも知りたいことにヒットすることを願って。

もし、ここにはない知りたいことがあったら、コメントにでも書いてくれたら可能な限り説明試みてみますのでお気軽にどうぞ。

### Sprintを短く区切る心理的な理由。夏休みの宿題症候群、パーキンソン症候群を防げる

1年のタスクがあっても、1週間 x 52回のタスクがあっても、同じではないのか？
算数で考えると一緒ですが、実際は違います。
1年後にリリース日が決まっていた場合、最初の１日は、まだリリースまで1年ある！です。1週間Sprintに設定した場合、1週間後にリリースだ！急がないと！です。
Sprintを短くする、つまりは小さなGoalを定期的におくことで、ムラなく、1日1日を集中して作業することで、作業効率が上がります。

### 良く使われる機能は全機能のうちの7%

```
一般的なシステムのうち、全機能のうち7%が良く使われる機能、64%がまれに使う/まったく使われない機能といわれる
```

アジャイルでは、大きな1つの要件ではなく、小さな要件100個に分けて管理します。

トラディショナルな手法では全要件が完成するまでリリースしませんが、もし7個作ってリリースしてみてうまくいくのであれば、残り93個を作らなくてもいいかもしれません。その93個は、システムではなく、10年に1回マニュアル運用で十分回避できるかもしれません。
ほとんど使われない93機能を頑張って作るよりは、今使われている機能をブラッシュアップしたり、より使われる機能を検討する時間に使う方が建設的です。

### 🔖 引継ぎも１要件として扱う

引継ぎも「作業タスク（バックログ）」です、要件の１つです、リスクの１つです。他のバックログと同じく優先度を決めて対応します。

もちろんメンバが急に明日から来なくなる可能性も否定できません。では、そのために毎日引継ぎをするべきでしょうか。その引継ぎ先も本当に引き継いでくれる保証はありません。どこまでリスクを許容するかという問題です。
例えばプロダクトオーナーが「引継ぎ」を絶対的に最優先にするのであれば、「**Doneの定義**」に入れてしまうことも可能です。その場合、もちろんその分他の作業効率は落ちます。

アジャイル（Scrum）では、チーム全員が平準的にどんな作業でも出来るような構成を目指します。アジャイル（XP）ではコードの共同所有を目指します。無駄なドキュメントを作らない中でも、チーム内でノウハウを溜めるとともに最低限のリスク回避は目指しています。

なんにせよ最悪なのは、引継ぎ先もわからず、引継ぎ時期もわからない中で、優先度を無視して使われないドキュメントを作り続けることです。引継ぎが必要な時に、必要なだけ行う、というシンプルな理屈です。

### 🛁 見積もりも意外と普通に行う

基本的には他の開発手法と大きな差はありません。作業する前には見積もりをします。

細かなテクニックとしては、スプリントの最初に、プランニングポーカーで行う、というのが有名です。本質的には、作業の直前に、開発チーム全員でなっとくした見積もりを出す、ということが重視されます。アジャイル（Scrum）では「個人」ではなく「チーム」での開発を行いますので、見積もりもPMやリーダーや誰か1人の裁量ではないということです。

あとは、スプリントが細かく分かれるので、見積もりの精度がどんどん上がっていきます。1年に一回の見積もりよりも、1週間ごと52回の見積もりの方が熟練度も上がって精度があがるのは自然なことです。

### 🗿 どんなプロジェクトでもアジャイルでやった方がいいわけではない

１か月のプロジェクトに**Scrum**は向きません。
超少人数（2人とか）にも**Scrum**は向きません。
Scrumではチームを醸成するのに2～3か月かかると言われています。開発メンバ ＋ Scrum Master ＋ Product Owner が必ず必要なので、1人とか2人とかのプロジェクトにも使えません。
**Kabnan**とかなら使えると思います。

### ✨ サービス保守にアジャイルは使える？

何とも言えないです。
わたしは、開発はScrumでしてましたが、サービス保守でScrum使うのはやめました。

理由はシンプルです。 Scrumでは、リリースの日程が固定されますが（Sprintの最後になります）、例えばクリスマスにあわせて画面を変えたいとしてクリスマスは必ずしもSprintにタイミングがあってくれません。
なのでScrumはやめました。

ITILなどにのっとった社内システムなどでリリースタイミングが調整可能なのであれば十分使えると思います。B2Cシステムでは、Scrumのプロセスをそのまま使うのは困難な気がします。Scrumのエッセンスは使えると思います。

---

ということで思いつく限りで。
[iOS]IDFVの形式と取得方法

#背景
iOSアプリを開発する中で、端末を一意に識別できるキーを探していた。
初めはUDIDを使おうと考えたが、セキュリティの観点から現在は取得することができないらしい。
というわけで代わりに、~~広告識別子である~~IDFVを使用することにした。
(※**現在は、IDFVを広告識別子として利用することは禁止されている**)

#動作環境
- swift 4.2
- xcode 10.0

#IDFVの形式
- 36文字で固定。
- 英数字（大文字）とハイフンのみで構成。
- フォーマット：`{8}-{4}-{4}-{4}-{12}`
- 例：
3K0XXXXX-83XX-HEXX-KIXX-29KH83XXXXXX

#IDFVの取得方法（swift4）

```
let idfv = UIDevice.current.identifierForVendor?.uuidString
```
#参考
##広告識別子とは
以下サイトから引用。
[モバイル端末の広告識別子について知っておくべきこと](https://growthhackjournal.com/what-you-need-to-know-about-mobile-device-ids/)

> 広告識別子とは、モバイル端末を識別するために生成された一意の英数字の組み合わせ (識別子) のことを指します。
この識別子は、ユーザーの端末にアプリがインストールされることで取得できるもの。インストールされたら、スマートフォンやタブレットから送信された情報に基づいてユーザーの行動を追跡できます。ただし、このIDはユーザーが任意でリセットできる一時的なコードなので、完全に個人を特定できるものではありません。


##Identifier For Advertising (IDFA)とは
以下サイトから引用。
[モバイル端末の広告識別子について知っておくべきこと](https://growthhackjournal.com/what-you-need-to-know-about-mobile-device-ids/)

**なお現在は、IDFVを広告識別子として利用することは禁止されている。**
代わりに、**advertisingIdentifier**という識別子が用意されている。

>iOS端末の広告識別子。iOS6以前は、Unique Device Identifier (UDID) と呼ばれる端末ごとに固有のリセットできない識別子が利用されていました。IDFAは、ユーザー側でいつでもリセットできます。しかし、ユーザーが「追跡型広告を制限」を有効にすると、広告主はIDFAをマーケティングに使用できなくなるということも覚えておきましょう


##ちなみに
Android端末の場合は、Google Advertising ID (AAID)が広告識別子として用意されています。こちらの機能はIDFAと変わりません。
[Larabel 5.6] 入力した文字列（平文）と Hash::make() で生成されたハッシュ値を比較する方法

#環境
CentOS: 7.4
PHP: 7.2
Laravel: 5.6

#やりたいこと

こんな感じでパスワード更新機能を実装したい。
DBには`Hash::make()`でハッシュ化されたパスワードが登録済み。

![パスワード更新.PNG](https://qiita-image-store.s3.amazonaws.com/0/238891/15cea5de-b11f-fc0b-2927-7ff6dbb82384.png)

#`Hash::check()`を使う

ポストされた平文のパスワードと、DBに保存されているハッシュ化されたパスワードを比較したいときは`Hash::check()`を使います。

```php
Hash::check('plain-text', $hashedPassword)
```

例えば、コントローラー内ではこんな感じ。

```php
public function update(Request $request, $id)  // パスワード更新のアクション
{
    $user   = User::find($id);
    $newPwd = $request['new_password']

    if (Hash::check($newPwd, $user->password)) {
        // 一致したときの処理
    } else {
        // 一致しなかったときの処理
    }
}
```

#`Hash::make()`は毎回違うハッシュ値を返す

`Hash::make()`は、たとえ同じ値をハッシュ化したとしても、毎回違うハッシュ値になります。
これはハッシュ化される際に毎回違うソルトが付与されているからです。

```php
Hash::make('123456789')
// １回目 -> "$2y$10$Mwpc4sWmavJejMja/cLVaOcr51OuOdrmyZRLg2KCitqEgvAGwnvkO"

Hash::make('123456789')
// ２回目 -> "$2y$10$v9jdbMmI2N4x4/Osk.jDrOQKgTAEAKwKwfDtdjkoOcjP4bZ57Fqte"
```

なので、入力された現パスワードを`Hash::make()`でハッシュ化した値とDBに保存されているハッシュ化されたパスワードを比較しても一致することはないんですね。

```php
public function update(Request $request, $id)
{
    $user = User::find($id);
    $hash = Hash::make($request['new_password'])

    dd($hash == $user->password)  // -> FALSE
}
```

「ハッシュは同じ値に対しては同じハッシュ値を返す」と聞いていたので少し勘違いしてしまったのですが、`Hash::make()`はパスワード保存用にセキュリティを強化されたメソッドのようなので、単純なハッシュ関数とは違うんですね。なるほど。

#参考
https://readouble.com/laravel/5.6/ja/hashing.html
SSHのDynamic Forwardで学内ネットワークに入る

##やりたいこと
家やテザリングをしたネットワークから学内ネットワークに入りたい。やっていることとしては、SSHのDynamicForwardでトンネルを張って、クライアントのMac側でSOCKSプロキシの設定をしている。sshの設定が既に済んでいる人であれば、5分ぐらいで簡単にできる。

## SSHでダイナミックポートフォワードする
ターミナルからトンネルを張る。

```sh
$ ssh -D 10080 user@example.com
```

### 簡略化する場合

下のように設定すれば簡略化することも可能。`$ ssh tunnel`で接続。

```sh:~/.ssh/config
Host tunnel
  HostName example.com
  User user
  DynamicForward 10080
```

### バックグラウンドで走らせる
コマンドを実行する必要がないので、バックグラウンドで実行したい場合はこう。ターミナルのウィンドウを閉じてもコネクションが切断されないようになる。

```sh
$ ssh -N -f tunnel
```

### コネクションを切断する
バックグラウンドで走らせたときはこうやって切断する。

```sh
$ ps aux | grep ssh
$ kill ****
```

## SOCKSプロキシの設定（Mac）
Macなら`システム環境設定＞ネットワーク＞詳細設定＞プロキシ＞SOCKSプロキシ`から以下のように設定。

<img width="668" alt="Screen shot 2018-10-15 at 12.35.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/38428/0c63418d-6ac2-a818-d4a9-37f3f5ba16fd.png">

ターミナルからオン・オフを切り替えたい場合はこう。

```sh
networksetup -setsocksfirewallproxystate wi-fi on
```

### プロキシのオン・オフを簡単にする
こういうシェルスクリプトを書いて、`~/.zshrc`とかに`alias`貼ると便利。ターミナルから一発でSOCKSプロキシのオン／オフができるようになる。

```sh:proxy.sh
#!/bin/zsh
e=$(networksetup -getsocksfirewallproxy wi-fi | grep "No")
if [ -n "$e" ]; then
  echo "Turning on proxy"
  networksetup -setsocksfirewallproxystate wi-fi on
  echo 'display notification "ON" with title "proxy.sh"'  | osascript
else
  echo "Turning off proxy"
  networksetup -setsocksfirewallproxystate wi-fi off
  echo 'display notification "OFF" with title "proxy.sh"' | osascript
fi
```

```zsh:~/.zshrc
alias proxy='sh /Users/hoge/proxy.sh'
```


## まとめ

一回設定してしまえば、あとは簡単に接続できちゃう。

```sh
$ ssh tunnel
$ proxy
```


## 参考
- [SSH でトンネリング – nksg.org](https://nksg.org/archives/13)
- [特定のネットワーク内からしか見れないウェブページを外から見る方法](https://rcmdnk.com/blog/2014/09/04/computer-remote/)
- [sshのDynamicForwardで学内専用サービスを家から使う - Qiita](https://qiita.com/saa/items/35fc55343173b3d135f3)
- [Petit Tech: SSHとSOCKSでVPNしてみる。](http://petittech.blogspot.com/2011/12/sshsocksvpn.html)
- [SSH ダイナミックポートフォワード＋Socks プロキシで内部ページを閲覧する - Qiita](https://qiita.com/yulii/items/5403d9fa6f2ba1b3b863)
生産性向上のためにMacBookProを買い替えてx3倍のスピードを手に入れた話

この記事は、201８年10月に内輪の勉強会で発表したものです。

----


## 買いました

![IMG_9324.JPG](https://qiita-image-store.s3.amazonaws.com/0/13070/3543b199-cca3-413d-0e4e-21ea8e4c6ca3.jpeg)

----

## 理由

* iPhoneアプリはビルドが遅い
 * 特にSwiftのコンパイルが遅い
* 自分の仕事プロジェクトでは、1からビルドすると2-7分程度
 * 大規模なところでは10分以上かかる場合もあるらしい...

[失われた2人日をiMac Proで取り戻し、開発体験を向上するまでの軌跡 - pixiv inside](https://inside.pixiv.blog/kobaken/4943)

----

## 金の弾丸

> 「ソフトウェア開発に銀の弾丸は無いが、
> 『金の弾丸』はある」

----

## 金の弾丸とは

* (優秀なエンジニアをたくさん雇う)
* iMacProを配る
* 残業代をたくさん出す

[MicroViewControllerで無限にスケールするiOS開発 #iosdc #a (3ページ目) - Togetter](https://togetter.com/li/1262031?page=3)

----

## 買い替え

* 旧 : 2013年 13inchモデル
 * i5 2.6Ghz 2コア
* 新 : 2018年 15inchモデル
 * i5 2.2Ghz 6コア

```
金のヒノキの棒くらいにはなったかなー。
```

----

## 結果

仕事プロジェクトのReleaseビルドで比較

* 旧Mac(2014 i5 2.6GHz 2core) = 449秒
* 新Mac(2018 i7 2.2GHz 6core) = 142秒

仕事プロジェクトのdebugビルドで比較

* 旧Mac(2014 i5 2.6GHz 2core) = 133秒
* 新Mac(2018 i7 2.2GHz 6core) = 42秒

```
どちらも70%くらい減っている
コア数だいじ.
```

----

## 結論

* 遅いなと感じたらMacを買い換えましょう
    * 予算の範囲で一番速いもの
    * コア数が多い方が良い

----

## 参考サイト

* [MicroViewControllerで無限にスケールするiOS開発 #iosdc #a (3ページ目) - Togetter](https://togetter.com/li/1262031?page=3)
* [失われた2人日をiMac Proで取り戻し、開発体験を向上するまでの軌跡 - pixiv inside](https://inside.pixiv.blog/kobaken/4943)
* [Mac Benchmarks - Geekbench Browser](https://browser.geekbench.com/mac-benchmarks)
* [色んなMacでXcodeのビルド時間比較。開発用にどのMacを買うべきか？](https://qiita.com/alt_yamamoto/items/494b882333acc0cf9951)
人間中心デザイン入門03(人間中心設計)

# 人間中心設計について

---
## 人間中心設計(ISO9241-210)の6つの原則
1. ユーザー、タスク及び環境の明確な理解に基づいて設計する
2. 設計及び開発の全体を通してユーザーが関与する
    - 全てにユーザーが関与する必要はないが、ユーザーの代わりにユーザーの立場になれる専門家であればOK
3. ユーザー中心の評価に基づいて設計を方向づけ、改良する
4. プロセスを繰り返す
5. ユーザーエクスペリエンスを考慮して設計する
6. 設計チームに様々な専門分野の技能及び視点をもつ人々がいる
    - 閉じた視点になるとその視点にハマってしまうため

---
## ISO9241-210が示す人間中心設計プロセス
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138681/87fee03b-442d-1fe8-1ba2-204ef1f401ac.png)

---
## ISO9241-210における人間中心設計の定義
- 人間中心設計
    - システムの利用に焦点を当て、人間工学及びユーザビリティの知識と手法とを適用することによって、インタラクティブシステムをより使えるものにすることを目的としたシステムの設計及び開発へのアプローチ

---
などいろんな決まりがある。
要するに、いろんなシステムや日常でつかっているもの全てにおいて人間中心に設計するべきだというようなことが書かれている:point_up_tone1:

---
## アクセシビリティとユーザビリティの関係性の変化
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138681/a3ff0c99-bf1f-ec55-1375-e12bc2d20c0f.png)


- 以前はアクセシビリティ＝障害者向け、ユーザビリティ=健常者向けというような認識があったが、今は全てをユーザビリティとして考えていくという流れになってきている。
    - 障害は人によって違い、一括りにできるものではないし、障害自体がその人の特徴であるという考え方からきている。

---
### おしまい:pray_tone1:
Web開発とは

#目次
Web開発とは
Webとは
Webのしくみ
フロントエンドとサーバーサイド


#Web開発とは
Web開発とは主にWebサーバー側の環境を構築することを指します。

#Webとは
WWWはWorld Wide Webの略で、Webとは、「クモの巣」を表します。
インターネットやイントラネットで標準的に用いられるHTML文書など利用したシステムで、
文字や画像、動画、音楽などの情報を利用する事ができます。
Web利用してできたページを「Webページ」、「Webサイト」と呼びます。

#Webのしくみ
![web開発とは.jpg](https://qiita-image-store.s3.amazonaws.com/0/290624/3843f22d-c64c-3f53-7db2-435f6e6c8cbb.jpeg)

ウェブ上で情報を公開しているソフトウェアやコンピュータのことをWebサーバと呼び、Webサーバから情報を受けとる側をWebクライアントと呼びます。
文字や画像、動画、音楽などの情報をサーバーからインターネットを通してクライアントに届けることで成り立っています。

簡単なウェブサイトを公開する際は、フロントサイドをHTML・CSSで作成し、レンタルサーバーを借りて公開しています。

*インターネットについて詳しくは次項書きます


#フロントエンドとサーバーサイド

###フロントエンド
フロントエンドとはクライアントとのインターフェースのことを指し、代表する言語としてHTML,css,javascriptがあげられます。

**HTML**
HTML(Hyper Text Markup Language)はマークアップ言語の一つでWebページを作成するために作られた言語である。
ハイパーテキストとは文字情報を載せたり、***ハイパーテキストリンク***を埋め込んでブラウザに表示できるものである。
https://qiita.com/yousuke_asami/items/a18778d7380d2438b1ab

**css**
CSS（Cascading Style Sheets)はスタイルを指定するための言語で、マークアップしたタグを装飾することができる。

**javascript**
WEB上でインタラクティブな表現をする為に開発されたオブジェクト指向のスクリプト言語で、動きなどを加えることができる


###サーバーサイド
サーバーサイドはフロントエンドからのデータなどのやり取りをするところで、代表する言語としてJava,PHP,Rubyなどがあげられます。
最近ではjavascriptによるサーバーサイドの開発も進んでいて、Node.js、React、Ajaxなどがある
人間中心デザイン入門02(哲学回)

# 人間中心というデザインの哲学について

---
## 人間中心デザイン入門(歴史回)のつづき
 **それぞれの分野の人たちが人間(ユーザー)中心に考えられるようにする** ためにみんなが心得ておかなければならないことがある
<div align="center">
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138681/eee6a489-e98f-ec82-fc27-38012780c0c7.png)
</div>

---
### UXデザインについて
 - UXデザインではユーザーとデザイナーの関係は **二次的理解** に基づくものだ。だから限界がある。

---
## ん？つまりどういうこと？

---
### ユーザーの理解の過程
1. インタフェースを見る
2. 感覚的にインタフェースを認知する
3. インタフェースの意味を理解する
4. このインタフェースでどんなことをすればよいか(できるか)を認識する
5. 操作してみる **←ここでやっと操作できる** 
<div align="center">
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138681/b0b32eaf-8628-4b43-167e-1a845c54c854.png)
</div>

---
### インタフェースを使う人(ユーザー)と作る人(デザイナー)の関係性
<div align="right">
【作る人(例)】<br>
調査から仮説を立て要件をもとにインタフェースのデザインを作成<br>
<img width="200" alt="design" src="https://qiita-image-store.s3.amazonaws.com/0/138681/23bb2d4f-e707-36b4-3532-ada03e2e1127.png">
</div>
<div align="center">
 ⏬ 
</div>

【使う人(例)】
大体は操作できたが、ベストな使い方ができているわけではない状態
<img width="200" alt="user" src="https://qiita-image-store.s3.amazonaws.com/0/138681/957e1f30-e813-f41e-128e-468562dfab20.png">
<div align="center">
 ⏬ 
</div>

<div align="right">
【作る人(例)】<br>
前回気づけなかった部分についてリサーチなどをしてユーザーがどんな理解をして行動をしているかをデザイナーが理解し、ユーザーにとってよりよいものに改善<br>
<img width="200" alt="search" src="https://qiita-image-store.s3.amazonaws.com/0/138681/476ed716-3856-4228-1480-56150e4ce39f.png">
</div>
<div align="center">
 ⏬ 
</div>

【使う人(例)】
なんだかちょっと使いやすくなった気がするし、興味のあるものが増えた！という気持ちになる
<img width="200" alt="userhappy" src="https://qiita-image-store.s3.amazonaws.com/0/138681/edbde448-24aa-e321-1f2b-b5eab1fa51a1.png">

---
## つまり、ユーザーと作り手では視点が違うので分けて考える必要がある

---
###  それぞれの分野の人たちが人間(ユーザー)中心に考えられるようにする ために
 **二次的理解** という関係だからこそ、ユーザーに常に確認しながらデザインを進めなければ、ズレが生じてしまう
<div align="center">
ユーザー
<img width="200" alt="user02" src="https://qiita-image-store.s3.amazonaws.com/0/138681/d292f9e1-a25f-0a5d-6db8-7713b7ad38c3.png">
</div>


<img width="100" alt="sekkei" src="https://qiita-image-store.s3.amazonaws.com/0/138681/46042459-b213-8093-0bf3-b4b97c14ba4b.png"><img width="100" alt="engineer" src="https://qiita-image-store.s3.amazonaws.com/0/138681/7e3b7d23-6496-b33d-adde-2c9497ad3760.png"><img width="100" alt="hanbai" src="https://qiita-image-store.s3.amazonaws.com/0/138681/b94e38bf-533f-d9b2-e02b-7aabfffec757.png"><img width="100" alt="marke" src="https://qiita-image-store.s3.amazonaws.com/0/138681/43301005-5f8b-693c-ae57-42339c03d939.png"><img width="100" alt="design" src="https://qiita-image-store.s3.amazonaws.com/0/138681/71c79b59-8f11-ca5c-c2e4-77ff01a1b382.png"><img width="100" alt="kikaku" src="https://qiita-image-store.s3.amazonaws.com/0/138681/3d67a5fa-94c2-54c6-2695-1b6d7feec4a1.png">
製品・サービスづくりに関わるすべての関係者

---
### それぞれの分野ごとに視点が違うという課題が...！

---
### いろいろな視点を横につなぐための規格が **ISO** 

---
### つづく
[Laravel5.7]Policyを使ってモデルに対するアクセス制御を追加する

Laravelでモデルに対するupdate、destroyなどのメソッドに対して、アクセス制御をしたい場合がある。
よくあるのは作成した本人しか編集、削除できないようにする、といった制御。


# 適用までの流れ
1. Policyを作成する
2. Policyを登録する
3. Policyを適用する

# 1. Policyを作成する

```bash
# modelに対応したPolicyではないため、一からメソッドを追加していく必要がある
$ php artisan make:policy PostPolicy

or

# modelを元にPolicyを作成する(view, create, update, deleteが作成される)
$ php artisan make:policy PostPolicy --model=Post
```

↓modelを元に作成した時点のPolicy
https://gist.github.com/NAKKA-K/c931d687bd177a87586f1a59a07e2712.js

---
Policy内のメソッドはcontrollerと対応付ける必要はない。
今回はedit, update, destroyに対して付与したいアクセス制御は同じものなので、Policy内に1つだけメソッドを定義する。
メソッドの戻り値がtrueであれば許可、falseであれば拒否になる。

```php:app/Policy/PostPolicy.php
<?php

namespace App\Policies;

use App\User;
use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    // Postを引数に設定することによって、サービスコンテナによって依存かいけr
    public function destructive(User $user, Post $post)
    {
        // Postを作成したユーザーのみ許可する
        return $user->id == $post->user_id;
    }
}
```

# 2. Policyを登録する
作成したPolicyをmodelに対してマッピングする。

```php:app/Providers/AuthServiceProvider.php
/**
 * The policy mappings for the application.
 *  
 * @var array
 */
protected $policies = [
    'App\Model' => 'App\Policies\ModelPolicy',
    \App\Post::class => \App\Policies\PostPolicy::class,
];
```

# 3. Policyを適用する
今回はControllerでPolicyを適用する方法を説明する。

まず、ここのcontrollerメソッドにPolicyを適用する方法。
edit, update, destroyなど、適用させたいメソッド全てに記述する必要がある。

```php:app/Http/Controllers/PostController.php
class PostController extends Controller
 {
     public function edit(Post $post)
     {
         // Policyのdestructiveメソッドを適用($postは第2引数にあたる)
         $this->authorize('destructive', $post);
         return view('posts.edit', ['post' => $post]);
     }
```

---
middlewareとして一括で適用する方法。

```php:app/Http/Controllers/PostController.php
class PostController extends Controller
{
    public function __construct()
    {
        // can(Policy)の、destructiveメソッドの、postに対しての制約をmiddleware指定する。
        // edit, update, destoryに対してのみmiddlewareを適用する。
        $this->middleware('can:destructive,post')
             ->only(['edit', 'update', 'destroy']);
    }
```


# まとめ
今回はControllerに適用する方法のみ紹介したが、middlewareをrouteから指定する方法や、Bladeに適用し、許可されない場合は表示しない、等といった制御も可能。

### 参照
※Policyを適用する方法は多数あるため、他の方法も知りたければ以下のURL先を参照。
[日本語ドキュメント](https://readouble.com/laravel/5.7/ja/authorization.html#authorizing-actions-using-policies)
[公式ドキュメント](https://laravel.com/docs/5.7/authorization#authorizing-actions-using-policies)


[Laravel5.7: 認可 (記事の編集はオーナーに限る、などの制限)](https://qiita.com/sutara79/items/11d8417a6fc91ca1b841)