OmniAICreator/Qiita-1.07M huggingface dataset:
AWS CloudFront + S3 の環境に「複数の」Basic認証をかける

# 概要

AWSのCloudFrontとS3で構成された環境に対して、Basic認証をかける方法自体は調べればたくさん出てきましたが、複数のBasic認証をかける方法がサクッと出てこなかったので、一応残しておこうと思いました。

# ひとつのBasic認証の場合

こちらの記事がとてもわかりやすいので、ご覧ください。丸投げ！

* [CloudfrontとS3でBasic認証をかける](https://qiita.com/m4fg/items/80db7ce0050e5f3ab801 "CloudfrontとS3でBasic認証をかける")

# 複数のBasic認証の場合

上記の記事のコードを参考に、複数のBasic認証に対応。

```lambda-basic-auth.js
'use strict';
exports.handler = (event, context, callback) => {

    // Get request and request headers
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    // Configure authentication
    var authUsers = [
        {
            'user':'user1_name',
            'pass':'user1_pass',
        },
        {
            'user':'user2_name',
            'pass':'user2_pass',
        },
    ];

    var authString = '';

    // Require Basic authentication
    if (typeof headers.authorization != 'undefined') {
        authUsers.forEach(function(authUser){
            // Construct the Basic Auth string
            authString = 'Basic ' + new Buffer(authUser.user + ':' + authUser.pass).toString('base64');

            if (headers.authorization[0].value == authString) {
                // Continue request processing if authentication passed
                callback(null, request);
            }
        });
    }

    // Reject request
    const body = 'Unauthorized';
    const response = {
        status: '401',
        statusDescription: 'Unauthorized',
        body: body,
        headers: {
            'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
        },
    };
    callback(null, response);
};
```

おしまい。
環境を判定するメソッドを作るなら静的メソッドにしよう。ツラみが増すから。

# 概要

本業の仕事に限らず、今までやってきた中で環境の判定を行うメソッドを作ったことがある。
その中でこのようなことがあったよという共有。もちろんケースバイケースでこれ以外にも良い方法はあるのでは？と思ってもいるが、当たり障りがないという意味ではそうかなと思った。なのでまとめておく。

# 今回の話の大前提

今回は環境変数に環境の判定をする値を持たせている前提で話を進めます。
変数名      : ENVIRONMENT
値(開発環境) : DEVELOP

他にも方法はありますが、今回はこれで。

# そもそも動的メソッドで何が悪いの？

全ての場合が悪いわけではない(と思っている)。駄菓子菓子辛い時もある。それが以下の時。



```php:Environment.php
class Environment
{
  public function isDevelopment() {
    if (getenv('ENVIRONMENT') === 'DEVELOP') {
      return true;
    }
    return false;
  } 
}
```

そしてそれを同じクラスで使おうとするとこうなる。

```php:動的メソッドサンプル
require_once('Environment.php');
class Environment
{
  public function isDevelopment() {
    if (getenv('ENVIRONMENT') === 'DEVELOP') {
      return true;
    }
    return false;
  } 

  public function sample1() {
    $environment = $this->isDevelopment(); // 使うのはこの箇所。
    if ($environment === true) {
      // なんかやりたい処理
    }
  }
}
```


このsample1メソッドをstatic(静的メソッド)にしたいなとなった時に本当のつらみが召喚される。

```php:静的メソッドにしたい時のサンプル(Environment.php)
public static function sample1() { // ここをstaticにした！
  $environment = $this->isDevelopment();
  if ($environment === true) {
    // なんかやりたい処理
  }
}
```

~~このメソッドを実行するとExceptionが発生するはず。
なぜなら静的メソッドの中でインスタンスを作って・・・といったことはできないからである。~~

@nunulk さんに指摘していただいた通り、できないのは$thisの参照でした・・・

# $thisの何が悪いのか

$this はそもそもinstanceを作らないと使用できないもの。
つまりは $environment = new Environment() とかしないと使えないということ。

何が悪いのかというと、以下のような呼び出し方(静的な呼び出し方)ができない。

```php:例えばsample1メソッドにおいて
public function sample1() {
  $is_development = self::isDevelopment(); // 左記のような静的な呼び出し方
  if ($is_development === true) {
    //開発環境でのみやりたい処理
  }
}
```

この静的メソッドの呼び出しができないと、一時退避としてこのメソッドを動的メソッドのまま使って・・・となってsample1を使っているところも静的メソッドにすることが叶わなくなり・・・の無限ループとなる。
(実際静的メソッドにするとしてもそんなに依存関係を強くするなよという声が聞こえてきそうですが、すでに汚いコードに対して少しずつ綺麗にしようとするとそうなりがち)

# 環境を判定するメソッドを静的メソッドにしてみたバージョン

こうなると困らないよね。見た目もちょっとスッキリ。

```php:環境判定を静的メソッドにした時のサンプル(Environment.php)
class Sample
{
  public static function sample1() {
    if (self::isDevelopment() === true) {
      // 開発環境でのみやりたい処理
    }
  }
}
```

別クラスで使う場合もスッキリ！

```php:環境判定を静的メソッドにした時のサンプルその２(別クラスで使用する場合)
require_once('Environment.php')
class AnotherClassSample
{
  public static function sample() {
    if (Environment::isDevelopment() === true) {
      // 開発環境でのみやりたい処理
    }
  }
}
```


# まとめ

こういうことが起きないように、環境を判定するメソッドは、静的メソッドにした方が後から困らないと思いました。まる。
JavascriptでVuex.Storeのmoduleを書く際、VS Codeのコードアシストを効かせる

# 概要

Vuex.Storeのmoduleはplain objectで記述する必要があります。
しかしこれだとVSCodeの補完が効かなくて悲しくなってきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/98318/a6910640-e38f-1206-3b22-a18b5c08c182.png)

Vuex.Storeのコンストラクタだと具合良く補完が効くのですが・・

# 解決策： JSDocを記述した薄いラッパーをかませる

そこで、こんな感じの薄いfunctionを用意しました。

```javascript:store_module.js
import {StoreOptions} from 'vuex' // eslint-disable-line

/**
 * @template T
 * @param {StoreOptions<T>} options
 * @returns {StoreOptions<T>}
 */
export default function StoreModule(options) {
  return options
}
```

これをかますと、いい感じで補完が効くようになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/98318/510bfa5c-6e2b-cd0a-0364-f741932f75b5.png)

素直にTypeScriptを使ったほうがいいんでしょうけど。。
テーブルを参照せずに、BigQueryの挙動を確認する方法

UNNESTを使うことで、配列からテーブルの行に変換することができます。
https://cloud.google.com/bigquery/sql-reference/query-syntax?hl=ja#unnest

### idとnameを持つテーブルの作成
* UNNESTは、`WITH OFFSET`を利用することで、配列のindexを出力することができます。

```
SELECT
  id,
  position,
  ['a', 'b', 'c'][OFFSET(position)] AS name
FROM
 UNNEST([1, 2, 3]) AS id WITH OFFSET AS position
```

### UNNESTを二つFROMにつける
* 各行に対して、追加したUNNESTの中の配列の数だけ繰り返される
* 以下の例だと、9つ行ができる

```
SELECT
  id,
  name
FROM
 UNNEST([1, 2, 3]) AS id,
 UNNEST(['a', 'b', 'c']) AS name
```

### Right Joinを実行

```
SELECT
  t1.id AS id1,
  t1.val AS val1,
  t2.id AS id2,
  t2.val AS val2
FROM
(
SELECT
  id,
  ['a', 'b', 'd'][OFFSET(position)] AS val
FROM
 UNNEST([1, 2, 5]) AS id WITH OFFSET AS position
) t2
right JOIN
(
SELECT
  id,
  ['a', 'b', 'c'][OFFSET(position)] AS val
FROM
 UNNEST([1, 2, 3]) AS id WITH OFFSET AS position
) t1
ON
  t1.id = t2.id
```
Laradockのmysqlで初期起動時に複数DBを作成する（ハマった）

# 背景
普段Laradockで色々遊んだりすることもあるんですが、
ユニットテスト用のDBをコンテナ初期起動時に用意しよう、と思って
やったことのメモ。

また、設定できたLaradockを別のデバイスで立ち上げると
mysqlが上のDBを作成せずにハマったのでその共有

# 前提条件
Laradockをgitのsubmoduleで取得している

```config:.ginmodule
[submodule "laradock"]
	path = laradock
	url = https://github.com/Laradock/laradock.git
```

~~書いてて思ったが、submodule取ってくるたびにこれだと最新のになっちゃう。。~~
追記：submoduleはコミットハッシュを記録しているので、自ら更新かけない限り、最新にはならない


# mysqlで初期DBを作成する方法
詳細は、この記事とか見た方がわかりやすいです。（ありがとうございます）
[docker-composeでmysql使うとき初回起動時に複数のDBを作る方法](https://qiita.com/takyam/items/de87252fca60a9c914c6)

簡単にいうと特定のディレクトリにあるsqlやらshellはmysqlのイニシャライズ時に実行されるのでそれを利用する

# で、Laradockで初期DBを作成するには？
Laradockには最初から以下のようにexampleが用意されているのでそれをコピーして使うと良い。

```
/laradock/mysql/docker-entrypoint-initdb.d/createdb.sql.example
```

で、コピーしたファイルの拡張子をsqlに変更して、
以下の箇所をコメントアウトするとdev_db_1というDBが初回起動時に作成される

```sql:createdb.sql
CREATE DATABASE IF NOT EXISTS `dev_db_1` COLLATE 'utf8_general_ci' ;
GRANT ALL ON `dev_db_1`.* TO 'default'@'%' ;
```

それで`docker-compose up mysql`で起動すれば作成されるはず

# 何にハマったか

### 初期DBが複数作成されない
上記設定後に何度起動してもだめ
`docker-compose build --no-cache mysql`してもだめ。（でも原因になり得るのでした方が良い）
コンテナ消してもだめ、docker image消してもだめ。

### お前は何を持って初期起動なのか？
これが答えでした。
どうもmysqlが初期起動だと感知するのにはコンテナ内の/var/lib/mysqlの中身が関係しているみたいです（たぶん）
で、LaraDockは上記ディレクトリを起動時にローカルのディレクトリでマウントしているんですね。

```yaml:laradock/docker-compose.yml
### MySQL Container #########################################

    mysql:
      build:
        context: ./mysql
        args:
          - MYSQL_VERSION=${MYSQL_VERSION}
      environment:
        - MYSQL_DATABASE=${MYSQL_DATABASE}
        - MYSQL_USER=${MYSQL_USER}
        - MYSQL_PASSWORD=${MYSQL_PASSWORD}
        - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
        - TZ=${WORKSPACE_TIMEZONE}
      volumes:
        - ${DATA_SAVE_PATH}/mysql:/var/lib/mysql　　←--- これが原因
        - ${MYSQL_ENTRYPOINT_INITDB}:/docker-entrypoint-initdb.d
      ports:
        - "${MYSQL_PORT}:3306"
      networks:
        - backend
```

つまりマウントするディレクトリを消してやればよい。

```config:.env
### Data Path ###
# Choose storage path on your machine. For all storage systems.

DATA_SAVE_PATH=~/.laradock/data
```

これか・・・。

ちなみに最新のLaradockでは`DATA_PATH_HOST`という定数名になってました

# 結論
ローカルの`~/.laradock/data/mysql`を消してやれば解決しました。



# ソースコード
ここに上に書いたことができるものを置いておくのでご参考ください
https://github.com/SLEAZOIDS/laravel-on-docker

なおsubmodule以下の設定はgitで管理できないので`/setting`からshellでコピーできる形で利用している
~~そしてこの仕組みはsubmoduleのアップデートに耐えれないので、問題あり（いつか直そう）~~
追記：submoduleのアップデートには基本耐えれないが、アップデートしたい時に調整すれば良いだけなので問題はないっす
jsでメール本文の初期値を設定

メールリンクをクリックしてメーラーを起動した際に、
メール件名や本文、BCCが初期値として入力させるには

```html
<a href="mailto:mail@sample.com?bcc=test@sample.com&amp;subject=【メール件名】〇〇について&amp;body=メール本文">パンフレット請求メールを送る</a>
```
のように、`?`と`&amp;`で繋いでいく必要がありますが、
メールフォームなどで送信先がページによって変わる際にも
全ページに固定の件名や本文などを追加していくために、共通のJavaScriptで自動挿入する方法をまとめました。

```html
<div class="mail-link">
  <a href="mailto:mail@sample.com">メールを送る</a>
</div>
```
このようなメールリンクに対し、下記のように固定でBCCの宛先・件名・メール本文を挿入します。
メール本文はデータ型で区切り、改行コードを差し込んでいます。

```javascript
$(function(){
	var mailLink = $('.mail-link a');

	var lineFeed = "\r\n";
	// BCC
	var bcc = 'test@sample.com';
	// 件名
	var subject = '【メール件名】〇〇について';
	// 本文
	var body = [
			'お名前：',
			'電話番号：',
			'郵便番号：',
			'ご住所：',
			'その他連絡事項：'
	];

	var mailto = mailLink.attr('href');
			mailto += '?bcc=' + bcc;
			mailto += '&subject=' + subject;
			mailto += '&body=' + body.join(encodeURIComponent(lineFeed));

	mailLink.attr('href', mailto);
});
```

このメールリンクをクリックすると…

![mailer_up.png](https://qiita-image-store.s3.amazonaws.com/0/143784/ef757dd5-a08d-ec07-4d2c-7e08af7f0f1e.png)

出ました！ このようなメールが生成されます。

このように、メール内容を複数ページで一括管理したい時などに有効です。
Google API Client for pythonでSSL証明証エラーがでたので応急処置した

## 概要

Google API Client for pythonでCloud ML EngineのAPIにアクセスしようとしたらSSL証明書関連でエラーがでて困った話。
(2018/08/09時点)


## 再現コード

```txt:requirements.txt
google-api-python-client
```

```python:test.py
from googleapiclient import discovery

if __name__ == '__main__':
    discovery.build('ml', 'v1')
```

```sh:再現手順
> python -V
Python 3.6.6

> python -m venv venv
> . venv/bin/activate.fish

> pip -V
pip 18.0 from /(略)/python3.6/site-packages/pip (python 3.6)

> pip install -r google-api-python-client

> python test.py

(略)
  File "/Users/hoge/.anyenv/envs/pyenv/versions/3.6.6/lib/python3.6/ssl.py", line 814, in __init__
    self.do_handshake()
  File "/Users/hoge/.anyenv/envs/pyenv/versions/3.6.6/lib/python3.6/ssl.py", line 1068, in do_handshake
    self._sslobj.do_handshake()
  File "/Users/hoge/.anyenv/envs/pyenv/versions/3.6.6/lib/python3.6/ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:841)
```

## 対応

いろいろと調べたのですが、httplib2が参照するSSL証明書を最新にするって対応があったけど、それも少し古い記事だったので、解決には至らず。。。

下記記事を参考に```httplib2.Http```に'''disable_ssl_certificate_validation'''のオプションを指定して、とりあえずの対応をしました。

http://d.hatena.ne.jp/knaka20blue/20180314/1521020791

```python:対応

from googleapiclient import discovery

from httplib2 import Http

if __name__ == '__main__':
    http = Http(disable_ssl_certificate_validation=True)
    discovery.build('ml', 'v1', http=http)
```

SSL証明書のチェックを無効化するオプションなので、実運用でこのままだとキツめ。



Cloud FunctionsでPython利用記事まとめ
https://qiita.com/kai_kou/items/2f65db5305ba280ad81e
import/firstエラー解決のためにコメント文が必要


Windows10 & create-react-appで初期構築した環境でのこと．

Typescriptで記述した".tsx"ファイルを".js"へコンパイルして実行すると，以下のようなエラーが起こる．

```console
Import in body of module; reorder to top  import/first
```

原因は恐らく<b>import文より上にコード記述がある</b>こと．

クラスがReact.Componentを継承している場合などで，コンパイル後の".js"ファイルには「import文より上にもコードが書かれている」ことを確認した．

要するに<b>「import文は先頭に書け」</b>と意訳しているが，コンパイルしているのは僕ではなくtsc(コンパイラ)なので困る．

そこで，[GitHub上で見かけた議論](https://github.com/facebook/create-react-app/issues/2772)より，該当ファイル先頭に以下のコメント文を追記することで解決した．

```typescript
/* eslint-disable import/first */
```

ESLINTに関する問題とのことで，上記コメント文を該当ファイルに加えておけば，import文より上にコードがあっても無視してくれる．

「無視するだけじゃ結局エラー吐くんじゃ？」とも思ったが，確認した限りでは正常に動いているので御の字．

ちなみに<b>コメント記法が"//"だと動作しない</b>．"/**/"で初めて動作する．
（議論の下の方を見るまで僕も騙されて禿げそうになっていた）
AWSでLVSをつかってロードバランシングしてみる　第２回

前回はAWSのVPC上でLVSとWebサーバを同じネットワークに設置して実験してみましたが安定しませんでした。（前回 https://qiita.com/superdry/items/83286545061354f20d17 ）
#構成
今回はWebサーバを10.0.2.0/24のネットワークに設置します。LVSは10.0.0.0/24のネットワークに設置しますがネットワークインタフェースを２枚にして片方は10.0.2.0/24のネットワークにつながるようにします。
![ネットワーク分離.png](https://qiita-image-store.s3.amazonaws.com/0/263671/9df4aa1f-1008-0e2b-87dd-a5df0e32f7a9.png)


##WebSV1
10.0.2.0/24のサブネット側にインスタンスを作成します。
LVSのeth1のIPアドレスをデフォルトゲートウェイにします。
その他（httpdのインストールなど）は前回と同じです。

##WebSV2
  WebSV1と同様です。

##LVS
LVSのネットワークインタフェースを２枚にする方法は
インスタンス作成時のstep3でネットワークインターフェースの欄でデバイスの追加を押下します。
![デバイスの追加.png](https://qiita-image-store.s3.amazonaws.com/0/263671/4ad77e60-ee22-d7e3-f05c-ff57ea83ac9e.png)

eth0は10.0.0.0/24のサブネット、eth1は10.0.2.0/24のサブネットにします。
![デバイスの追加eth1.png](https://qiita-image-store.s3.amazonaws.com/0/263671/1695a5df-d58b-8cd5-9842-e8d5b0c732ff.png)



前回同様、送信元送信先チェックを外さなければなりませんがeth0はインスタンス画面のアクションから「ネットワーキング」→「送信元送信先変更チェック」で無効化できます。
しかし、eth1の方は有効化されたままですので個別にやらなければなりません。eth1のネットワークインタフェースIDをメモって置いて、ネットワークインターフェース画面でネットワークインタフェースIDで検索してアクションから「送信元送信先変更チェック」で無効化できます。（嵌ったところ）
![送信元送信先の変更チェック.png](https://qiita-image-store.s3.amazonaws.com/0/263671/cd540d35-a3a3-7dcd-c8fa-243457e26312.png)

eth1の設定ファイルであるifcfg-eth1は自動的に作成されるものだと思っていましたがそうではありませんでした。作成してあげないと機能しないので作成します。

```:/etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE="eth1"
BOOTPROTO="static"
ONBOOT="yes"
BROADCAST=10.0.2.255
NETMASK=255.255.255.0
NETWORK=10.0.2.0
IPADDR=10.0.2.75
```

```:
# systemctl  restart network
```
前回同様ipvsadmをインストールします。（前回 https://qiita.com/superdry/items/83286545061354f20d17 ）

ipvsadmでLVSの設定をします。

```:
# ipvsadm -C
ipvsadm -A -t 10.0.0.162:80 -s rr 
ipvsadm -a -t 10.0.0.162:80 -r 10.0.2.137:80 -m 
ipvsadm -a -t 10.0.0.162:80 -r 10.0.2.107:80 -m
# ipvsadm -l 
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  ip-10-0-0-162.ap-northeast-1 rr
  -> 10.0.2.107:http              Masq    1      0          0
  -> 10.0.2.137:http              Masq    1      0          0
```

LVSのeth0に関連付けられたElasticIP（グローバルIP）を指定してwebブラウザーでアクセスしてみます。

![ブラウザー.png](https://qiita-image-store.s3.amazonaws.com/0/263671/fc8043e6-75b5-0ec6-e084-59b85b5620dc.png)

なんとか安定しました。戻りパケットがLVSに行ったり、VPCのルータに行ったりせずに安定してLVS経由で返されていると思われます。tcpdumpは今回やってませんが。
ただし、ブラウザーをリロードしてもWeb1→Web2→Web1のように綺麗に切り替わりません。Webサーバとかブラウザーのキャッシュの設定かもしれません。でも前回のように見れなくなることはありません。
【上流工程】全体像をざっくり把握しながら勉強するための見取り図

###### ※ 用語には適宜、基礎的な説明がされているサイトにへのリンクを貼らせていただきました。

# ややこしい用語

| **用語** | **定義** |
| --- | --- |
| 要求 |ステークホルダーのXXしたいという希望<br>(必ずしも実現しなくてよい)|
| 要件 |オーナーの提示する、YYが必要という条件<br>(必ず実現しなければならない)|
| 要求工学 |要求の獲得、文書化、検査・確認、管理を行うための工学的技術を開発する学問 <br>(技術を使用する人間の教育も含む)|
| RFP<br>(Request For Proposal / 提案依頼書) |発注先候補の業者に具体的な提案を依頼する要求仕様書|
| [UML<br>(Unified Modeling Language / 統一モデリング言語](https://qiita.com/github129/items/80d39f2f043489033076)|ソフトウェアの機能や構造を表す「図」の描き方 |

# プロセス全体外観

顧客やユーザから要求を獲得した後の流れは以下のようになります。

| **プロセス名** | **アウトプット** |
| --- | --- |
| 要求分析 | 要求仕様書 |
| 設計 | 設計仕様書 |
| コーディング | プログラム |
| テスト・デバッグ | 製品 |
| 保守・運用 | アップデートされた製品 |

## 要求分析

ユーザーから要求を受けて、要求仕様書を作成する

###要求分析のプロセスと手法

* 要求獲得
    * Stakeholder識別
        * ビジネスプロセスモデリング
    * 要求抽出
        * インタビュー、会議支援
        * 発想法、意思決定法
        * 再利用（ドメインモデル、パターン、フレームワークなど）
        * [ゴール指向分析法](https://blog.goo.ne.jp/xmldtp/e/2efd32b1f9b8911882f6b8ddf988febe)、[シナリオ分析](https://inokara.hateblo.jp/entry/2018/05/03/194018#2-%E3%82%B7%E3%83%8A%E3%83%AA%E3%82%AA%E5%88%86%E6%9E%90)
        * 非機能要求の獲得
    * ネゴシエーション支援
        * 要求の優先順位付け
        * 意思決定支援
* 要求記述
* 要求検証(to-be)
* 要求管理
現状把握

### 記述法

- ユースケース
  - [ユースケース図](http://www.itsenka.com/contents/development/uml/usecase.html)
  - [ユースケース記述](http://linuxserver.jp/%E8%A8%AD%E8%A8%88/uml/%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E8%A8%98%E8%BF%B0)
- [NFR(Non-functional Requirements)](https://en.wikipedia.org/wiki/Non-functional_requirement)
- [Misuse Case](https://en.wikipedia.org/wiki/Misuse_case)

### ツール

| 種類 | ツール | 
| --- | --- | 
| ビジネス / プロダクト要求の文書化 | UMLを用いたモデリング<br>エッセンシャルユースケース<br>ビジネスプロセス定義<br>ビジネスリソース定義<br>ビジネスルール定義書  |   
| システム要求の仕様化 | 要求一覧（ユースケース図）<br>目的ベースのユースケース記述 |   
| ソフトウェア要求の仕様化 | 同上 |   

## 設計

要求仕様書を読み、設計仕様書を作成する。

### 手法

- [構造化設計法](https://sehermitage.web.fc2.com/softeng/soft_design.html)

### 記述法

- [クラス図](http://www.itsenka.com/contents/development/uml/class.html)
- [状態図](http://objectclub.jp/technicaldoc/uml/umlintro2#statechart)
- [データフロー図](http://www.dab.hi-ho.ne.jp/sasa/hyoryuki/dfd/)
- [ユースケース図](https://it-koala.com/usecasediagrams-1832)[(Use Case Diagrams)](https://it-koala.com/usecasediagrams-1832)
- [ユースケース記述](http://linuxserver.jp/%E8%A8%AD%E8%A8%88/uml/%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E8%A8%98%E8%BF%B0)

ちなみに、上記図を描写するのに便利なオンラインサービスが存在する。
[draw.io](https://www.draw.io/)

## コーディンング

設計書に基づき、コーディングを行い、プログラムを作成する。

## テスト・デバッグ

プログラムから、テスト・デバッグを行い、製品を完成させる。

## 保守・運用

完成された製品の運用と保守を行い続ける。

# 参考

* [要求定義と要件定義の違いを考える - Qiita](https://qiita.com/sunstripe/items/61df719fb1f6178b2605)
* [要求工学実践ガイド: REBOKシリーズ2 | 情報サービス産業協会REBOK企画WG |本 | 通販 | Amazon](https://www.amazon.co.jp/%E8%A6%81%E6%B1%82%E5%B7%A5%E5%AD%A6%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-REBOK%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA2-%E6%83%85%E5%A0%B1%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E7%94%A3%E6%A5%AD%E5%8D%94%E4%BC%9AREBOK%E4%BC%81%E7%94%BBWG/dp/4764904578)
* [IT関連の仕事で使う英語 - 技術情報Wiki](https://www.sangyo-rock.com/tech/index.php?IT%B4%D8%CF%A2%A4%CE%BB%C5%BB%F6%A4%C7%BB%C8%A4%A6%B1%D1%B8%EC#ne10a3e4)


###### TODO

* サンプルの追加
mkdirしたディレクトリにそのまま移動するfunctionをfishで実装した。

mkdirして追加したディレクトリに、そのまま移動するためのコマンドをfish shellのfunctionとして実装してみた。

```fish
function mkcd
  if test (count $argv) -eq 0
    echo "Pass dir name"
    return 1
  end

  set dirname $argv[1]
  mkdir -p $dirname
  eval "cd" $dirname
end
```

pオプションでmkdirを実行するので、複数階層を一度に作って遷移することも可能。
evalを使ってcdしているが、これをしないとコマンド終了時に元のプロセスに戻ったタイミングで実行していたパスになってしまう。この辺りはbashと同じ。

使い方は以下の通り。

```
~> mkcd test 
~/test> 
~/test> mkcd t1/t2
~/t/t/t2> 
```
Google Cloud Next '18 Day2 ノート

Day2 のメモ。

## Keynote [Bringing the Cloud to You](https://www.youtube.com/watch?v=XiGBWpxc6Lc)

- G Suite
- BigQuery ML
- Cloud Service Platform
- Cloud Armor
- Edge TPU

## [Microservices - Born and Raised (and Growing) on Google Cloud](https://www.youtube.com/watch?v=zE9CwUdy9Go)

Pizza Hut の実例。

- Kubernetes
- gRPC サービスと OpenAPI でアグリゲーション
- HA ([Global Load Balancer](https://cloud.google.com/load-balancing/))

Next

- istio
- apigee

## [API Management Best Practices](https://www.youtube.com/watch?v=a_oPGpMfjMg)

- Measuring Value to the End User
    - Application, Platform, APIs Usage
    - Traffic Growth
- Measuring Value to the Application Developer
    - #Consuming Apps
    - #Developers
    - Community Growth

## [Where Should I Run My Code? Serverless, Containers, VMs and More](https://www.youtube.com/watch?v=XcHE5V82OxM)

- It depends
- コンテナでレイヤの移動は容易になる
- 上に行くほど考えることは減る

| GCP | fit | constraints | hybrid |
| --- | --- | --- | --- |
| GCF | serverless, pub/sub or storage, don't want to think about runtime env, data transformations (ETL), and cloud-based http glue | runtimes (lang), function level granularity, and must interact via events | Function as a Service |
| App Engine | http/s, stateless, and scaling | runtimes (lang and binary extension), inherit docker constraints | Envoy, Istio & Knative on k8s |
| GKE | consistency, containers, team communication (dev, ops, security, etc.), ci/cd pipeline, and beyond http/s | must use containers, licensing, some architectual constraints | k8s |
| GCE | existing systems, specific os/kernel, databases, and beyond http/s | scaling speed ~20s per vm, 1000s in ~60s, updates yourself | Virtual machines |

## [From Your Workstation to Production: The Serverless Development Lifecycle](https://www.youtube.com/watch?v=OPj26MY16F8)

- code
    - typed
- testing
- deployment/rollback
    - cloud build
- config/environments
- monitoring
    - stackdriver
- pricing

## [One Platform for Your Functions, Applications, and Containers](https://www.youtube.com/watch?v=F4_2gxTtLaQ)

see also [108](https://www.youtube.com/watch?v=LtELzpw1l1M)

### Knative
- Serving
- blue/green
- auto scaling
- auto builds
- Eventing
Visual Studio Code で最新の C#  (C# 7.3) を使う方法

## **前提**

- **[.NET Core SDK 2.0 ~](https://www.microsoft.com/net/download) がインストールされている**
- **[Omnisharp](https://github.com/OmniSharp/omnisharp-vscode) がインストールされている**
    - ※ **Omnisharp** は vscode の拡張機能から入れられます。

## **サンプルプロジェクトの作成**

**vscode** で最新の C# 7.3 を使用するために必要なことは

- **`.csproj` の編集**
- **`omnisharp.path` の編集**

です。

サンプルのプロジェクトを作って順番に見ていきます。

```powershell
PS > mkdir LatestCsharp
PS > cd ./LatestCsharp
PS > dotnet new console
PS > dotnet build
```

**vscode** で `LatestCsharp`フォルダを開く。

:warning:`Required assets to build and debug are missing from 'LatestCsharp'. Add them?`
=> **Yes** を選択。


## **`<project_name>.csproj`の設定**

統合開発環境 Vsiual Stuido を使っている場合には、Visual Studio UI で変更できますが、
**vscodeの場合は`<project_name>.csproj`を直接編集**する必要があります。

<img width="310" alt="フライパン" src="https://qiita-image-store.s3.amazonaws.com/0/195024/66742cc3-995c-2574-4972-553a768ed586.png">

`<PropertyGroup>`の子要素に`<LangVersion>7.3</LangVersion>`を追加します。
プロジェクトによって`<PropertyGroup>`がない場合は追加してください。


```diff
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
+   <LangVersion>7.3</LangVersion>
  </PropertyGroup>

</Project>
```

## **`omnisharp.path` の編集**

**vscode** の`UserSetting.json`を開きます。
Windows の場合は `Ctrl` + `,` で開けます。

`"omnisharp.path": "latest"`を追加します。

```json
{
  "omnisharp.path": "latest"
}
```

一度ビルドしておきます。

```powershell
PS > dotnet build
```

最新の **Omnisharp** がインストールされます。

```powershell
Getting latest OmniSharp version information
Downloading package 'Latest OmniSharp Version Information' (xxx KB).................... Done!
Installing OmniSharp Version = 1.32.2-beta.33...
Platform: win32, x86_64

Finished
```

## **C# 7.3の機能を試す**

C# 7.3 の機能を使って正常に動作するか確かめます。
**C# 7.3 からタプル同士を `==` `!=` で比較できる**ようになったので、
そちらで確かめてみます。

`Program.cs`を以下のように編集します。

```c#:Program.cs
using System;

namespace LatestCsharp {
    class Program {
        static void Main(string[] args) {
            var monthdayA = (month: 8, day: 04);
            var monthdayB = (month: 8, day: 04);
            Console.WriteLine($"{nameof(monthdayA)} == {nameof(monthdayB)} is {monthdayA == monthdayB}");
        }
    }
}
```

`run` コマンドで実際に動かすと、ビルドが通って以下のように表示されるはずです。

```powershell
PS > dotnet run
monthdayA == monthdayB is True
```

タプル同士の比較は上記の場合、以下のように展開されるそうです。

```c#
monthdayA.month == monthdayB.month && monthdayA.day == monthdayB.day
```

参考： **[C# によるプログラミング入門 > C# 7.3 の新機能 > タプルの ==, != 比較](https://ufcpp.net/study/csharp/cheatsheet/ap_ver7_3/#tuple-equality)**
Qiitaを名刺代わりにしたい—本名でGoogle検索した時にプロフィールページが出てきてほしい


## なぜ？

Qiitaのプロフィールページが **Web上での名刺代わり** になってほしい。
**「本名でググったらQiitaのプロフィールが一番に出てくる」** とかいう状態になってほしい。

後述するがプロフィールページの名前設定は反映されず、現状、英数字のアカウント名でしかググることが出来ない。
せっかくSEOに強いサービスなので、今の状態はもったいない限りだと思う。


## 就活に役立ったりしない？

Qiita自体は「誰が書いたか」をそれほど全面に押し出さないサービスなのだとは思うけれど。

Google検索した時に引っかかるぐらいは、誰の目の邪魔にもならないし、利用ユーザー本人にも嬉しいし、エンジニア採用担当者にも優しいし、ということはひいては日本のシステムエンジニア業界にも寄与してしまってイイアンバイにグッドなリザルトをデリバリーしてくれる可能性だってあるんじゃないだろうかい？

## 妄想

採用担当者はググった‥あえて‥応募者から言わずとも‥そして見つけた‥Qiitaのプロフィールページ‥そして‥1万個のContirbutionsを‥！

### もちろん即採用‥！

ですよね？ Qiitaを書いているならね？

アウトプットするエンジニアならね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/b38f3213-6c16-cdf2-1fab-4f1531a8ca93.png)

[内定を貰った人のイラスト（男性） | かわいいフリー素材集 いらすとや](https://www.irasutoya.com/2015/03/blog-post_68.html)


## Qiitaでは本名でググれない

`自分の本名 + Qiita` というキーワードでググってもまったくヒットしない。

(Qiitaというキーワードを使っているのに、Twitterアカウントがヒットするレベル)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/3771a1d5-cc43-4ada-8064-4f898ab7f67d.png)

## アカウント名

`アカウント名 + Qiita` だとヒットする。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/63baf038-2f22-7e80-cd32-ba1bc7cbcf48.png)

プロフィールページのタイトルタグにはアカウント名しか入っていない。

## プロフィールページの設定を反映してほしい

この入力欄は何のためにあるのか。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/dd7f97f3-2d0b-2789-2709-51fcd366e4c5.png)

## 俺の暫定的ユーザー対策

- これがQiitaでの俺の代表作だ！
- しかもエンジニアとしての自分をよく表現していやがる！

という記事に、自分の本名を入れてググりやすくしてみるテスト中。

[瞑想するエンジニア ( by 稲浦悠馬 Yuma Inaura ) ( GoogleやFacebookもやっている「マインドフルネス」のススメ )](https://qiita.com/YumaInaura/items/f1a55b0b342954224207)

## Qiitaサポートに直接リクエストしないの？

あわせてやりたい。(やりました)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/088afa73-8304-0ea1-02da-ece63855d1c4.png)

[Feedback - Qiita](https://qiita.com/feedback/new)


Qiita最高！ はお世辞じゃないよ。
今さら言うのも照れるけど、Markdownで書きやすくて動作も軽いし、いいねも付くし、いい感じのゆるふわコミュニティもあるし。

ところで余談だが、Qiitaサポートには「リクエスト送信」と「Feedback(ご意見)」の二種類がある様子。

社内運用的に意見の重み付けというか、扱いが違ったりするんだろうか。 :thinking: 
まあ、ユーザーがいくら考えても分からないことだろうけど。
(もちろん片方が単方向で、片方が双方向。片方は意見フォームで、片方はユーザーサポート寄りという違いは分かる)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/3e727e69-c773-324a-fe67-613664dfdf24.png)

[リクエストを送信 – Qiita:Support](https://support.qiita.com/hc/ja/requests/new)

## あわせて読みたい？

- [QiitaのUI—シンタックスハイライト選択時の挙動を改善してほしい要望 - Qiita](https://qiita.com/YumaInaura/items/cf325a5548b19a806602)








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Azure Face API にデータをバッチで登録する

# はじめに

*こんにちは、のんびりエンジニアのたっつーです。*
*[ブログ](https://www.fast-system.jp/)を運営しているのでよろしければ見てください。*

Azure Face API ではAPIが提供されているが、事前にデータを準備しないとAPIを読んでも意味がない、今回はこの事前データを準備するためのバッチを作成したので以下にソースコードを示す。

# 概要
1. グループの削除・作成する（リセット）
2. Person を作成する
3. Person に Face を追加する
4. トレーニングを開始して終了まで待つ

# 使用方法
1. KEYを設定してください。
FACE_KEY = 'XXXXXX'

2. GROUP_IDを指定してください。
GROUP_ID = 'xxxxxx'

3. images 以下のフォルダに名前フォルダと画像ファイルを格納してください。

|-  |説明|
|---|----|
|main.py|メインプログラム|
|images|ここのフォルダ以下が登録対象になる|
| ├ 名前１||
| │  └ イメージ１||
| ├ 名前２||
| │  ├ イメージ２||
| │  ├ イメージ３||
| │  └ イメージ４||
| └ 名前３||
|  　 └ イメージ５||

※イメージは１人分の顔が映っている物を用意してください。

# ソースコード
```python:main.py
import os
import glob
import time
import urllib3
from time import sleep
import cognitive_face as CF

FACE_KEY = 'xxxxx'
FACE_URL = 'https://japaneast.api.cognitive.microsoft.com/face/v1.0'
GROUP_ID = 'xxxxx'

# init face api
urllib3.disable_warnings()
CF.Key.set(FACE_KEY)
CF.BaseUrl.set(FACE_URL)

def apiwait():
    sleep(5)

########################################################################
# テストコード
if __name__ == '__main__':

    # person の定義
    person = list()
    for d in os.listdir('./images/'):
        person.append({'user': d, 'personId': None})
    print('init : person cnt=' + str(len(person)))

    # image フォルダのファイルを列挙
    images = list()
    for p in person:
        dir = p['user']
        for fpath in glob.glob('./images/' + dir + "/*"):
            images.append({'user': dir, 'personId': None, 'url': fpath})
    # print(images)
    print('init : image cnt=' + str(len(images)))

    # group の再作成
    print('delete group...')
    try:
        result = CF.person_group.delete(GROUP_ID)
        print('delete group...OK')
    except CF.CognitiveFaceException as ex:
        print('delete group...SKIP')
    print('create group...')
    result = CF.person_group.create(GROUP_ID)
    print('create group...OK')

    # すべての person情報を作成
    for idx, p in enumerate(person):
        result = apiwait() or CF.person.create(GROUP_ID, p["user"])
        p['personId'] = result['personId']
        for i in images:
            if i['user'] == p['user']:
                i['personId'] = p['personId']
        print(str(idx) + '/' + str(len(person)) + ' person add', p)

    # faceの登録
    for idx, i in enumerate(images):
        try:
            print(str(idx) + '/' + str(len(images)) + ' face add...', i)
            result = apiwait() or CF.person.add_face(i['url'], GROUP_ID, i['personId'])
            # print(str(idx) + '/' + str(len(images)) + ' face add...OK')
        except CF.CognitiveFaceException as ex:
            print(str(idx) + '/' + str(len(images)) + ' face add...Exception\n' + "{0}".format(ex))

    # traningの開始
    result = apiwait() or CF.person_group.train(GROUP_ID)
    # print(result)
    print('training...')
    while True:
        result = apiwait() or CF.person_group.get_status(GROUP_ID)
        if result['status'] == 'succeeded':
            break
        time.sleep(5)
    print('training...OK')
```

# 終わりに

*よければ ブログ「[初心者向けUnity情報サイト](https://www.fast-system.jp/)」の方にも色々記載しているのでぜひご参照いただければと思います。*
[Swift][AVAudioFoundation] AVAudioPlayer でオーディオデータ再生が終了したらCallbackする


オーディオファイルの再生終了を知りたい時はAVAudioPlayerのcompletionHandlerを使用する。

しかし、単純に使用すると再生が終わる前にcompletionHandlerがFireされてしまう。

例えばこんな感じ

```completionHandler.swift
 self.audioFilePlayer.scheduleSegment(self.audioFile,
                                      startingFrame:startPlace,
                                      frameCount: frameCount,
                                      at: time,
                                      completionHandler: playCompletion())

func playCompletion(frameCount:Int, startCount:Int)
{
     /* 何か処理*/
}
```

どのタイミングでcompletionHandlerをFireするかは、completionCallbackTypeを指定することで制御できる。

```completionCallbackType.swift
 self.audioFilePlayer.scheduleSegment(self.audioFile,
                                      startingFrame:startPlace,
                                      frameCount: frameCount,
                                      at: time,
                                      completionCallbackType: .dataRendered, // <= これ
                                      completionHandler: playCompletion())

func playCompletion(frameCount:Int, startCount:Int)
{
     /* 何か処理*/
}
```

上の例では、.dataRenderedを指定し、再生が終わったらcompletionHandlerがFireされるようにしている。
completionCallbackTypeには他にも、以下のようなものがある。

```AVAudioPlayerNodeCompletionCallbackType.swift
public enum AVAudioPlayerNodeCompletionCallbackType : Int {

    
    case dataConsumed

    case dataRendered

    case dataPlayedBack
}
```


参考
https://developer.apple.com/documentation/avfoundation/avaudioplayernodecompletioncallbacktype?language=objc

https://github.com/AudioKit/AudioKit/blob/master/AudioKit/Common/Nodes/Playback/Player/AKPlayer.swift
えっ、まだPostgreSQLでダブルクォーテーション使ってるの？

##PosterSQLでは文字定数を「”」で括るとエラー
PostgreSQLで既存のテーブルにデータを挿入するために、以下のクエリ文を実行しました。  

```sql
INSERT INTO table_name VALUES ("value1", "value2", "value3"); 
```

するとこれ、エラーで返ってきました。  
（エラーメッセージはうろ覚えですが「value1なんてカラムは存在しないよ」的なことを言ってました）

PostgreSQLでは、ダブルクォーテーション「”」をシングルクォーテーション「'」にしないといけません。なので、以下のように変更します。

```sql
-- ダブルクォーテーションをシングルクォーテーションに変更
INSERT INTO table_name VALUES ('value1', 'value2', 'value3'); 
```

##「”」と「’」の違い
PostgreSQLなどの標準SQLでは、
<br/>

* <span style="color: #ff0000">シングルクォーテーションで囲う：文字列定数として扱う</span>

* <span style="color: #ff0000">ダブルクォーテーションで囲う：カラム名として扱う</span>

という仕様になっている。

`'value1'`は`value1`という文字列として捉え、`"value1"`は`value1`というカラムの名前として捉えられます。

テーブルになにか文字列を挿入するときはシングルクォーテーションで囲ってやらないと、SQLが文字列として認識してくれないわけです。


つまり、文字列定数をダブルクォーテーションで囲うな！ということです。

##一方MySQLでは…
世の中に存在するほとんどのDBMS（Database Management System）はこの標準SQLの仕様に従います。
しかしMySQLだけは独自の仕様を持っています。MySQLでは、

* シングルクォーテーション「'」で囲う：文字列定数として扱う

* ダブルクォーテーション「"」で囲う：文字列定数として扱う

* <span style="color: #ff0000">バッククォート「`」で囲う：カラム名として扱う</span>
という仕様になっています。

シングルクォーテーションだろうがダブルクォーテーションだろうが、<span style="color: #ff0000">どっちで囲っても文字列定数として認識されます。</span>カラム名として認識してほしいときはバッククォートを使わないといけません。

##雑感
私が初めて触ったDBMSはMySQLだったため、「”」と「’」の違いなんて全く気にしていませんでした。DBを初めて勉強するときは標準SQLの仕様に沿ったDBMSを使うべきだなあと感じました。
Swift：1mmを取得する

2019/07/13更新

```swift:
var millimeter: CGFloat {
    if let screen = self.view.window?.screen {
        let key = NSDeviceDescriptionKey(rawValue: "NSScreenNumber")
        let id = screen.deviceDescription[key] as! UInt32
        let physicalSize: CGSize = CGDisplayScreenSize(id)
        let pixelSize = screen.deviceDescription[NSDeviceDescriptionKey.size] as! CGSize
        return pixelSize.width / physicalSize.width
    } else {
        return 5.039370154423904 // According to MacBook Retina 13inch Default Resolution
    }
}
```

MacBookのディスプレイなら正しく1mmが取れるが，外部ディスプレイの場合正しく取れない場合もある模様．
Visual Studio Code のターミナルから Anaconda Prompt を開くようにする (Windows)

# 背景

昔はそうでなかったのですが、いつからか新しめの Anaconda をインストールしようとすると、インストーラに「環境変数 PATH に python.exe パスを追加しないことが推奨だよ。その代わりに Anaconda Prompt を使ってね！」と言われるようになりました。

それに従ってインストールを進めたところでそれほど不便はないのですが、 Visual Studio Code のターミナルですぐに python が使えないのはちょっと面倒を感じます。

ということで Visual Studio Code のターミナル起動時に Anaconda Prompt を使う方法をメモしておきます。

# 方法

スタートメニューから `Anaconda3 > Anaconda Prompt > (右クリック) > その他 > ファイルの場所を開く` を選択します。 

<img width="541" alt="0001.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/14284/72f25996-e38a-9952-979c-a985828502dd.jpeg">

エクスプローラが開きます。
`Anaconda Prompt を右クリック > プロパティ` を開き、 [リンク先] の文字列をクリップボードにコピーします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/14284/71e7c6a9-1078-ae2e-0bbd-2f0544223423.png)

Visual Studio Code を開き、 `ファイル > 基本設定 > 設定` もしくは `Ctrl+,` ショートカットで設定ダイアログを開きます。

[ユーザ設定] 欄に先ほどコピーした文字列を以下のように入力します。

```json
"terminal.integrated.shell.windows": "[コピー文字列のコマンド部分]",
"terminal.integrated.shellArgs.windows": [
    "[コピー文字列の第一引数]"
    , "[コピー文字列の第二引数]"
    , "[コピー文字列の第三引数]"
],
```

このとき、 `\` 文字は `\\` にエスケープする必要があります。

わかりにくいと思うので具体例を挙げると、筆者環境での設定は以下になりました。

```json
"terminal.integrated.shell.windows": "C:\\Windows\\system32\\cmd.exe",
"terminal.integrated.shellArgs.windows": [
    "/K"
    , "D:\\ProgramData\\Anaconda3\\Scripts\\activate.bat"
    , "D:\\ProgramData\\Anaconda3"
],
```

これを保存した後に VS Code のターミナルを起動すると、 Anaconda Prompt が起動します。


環境が読まれてることの確認は、例えば下記のコマンドです。

```cmd
> where python
D:\ProgramData\Anaconda3\python.exe         <== Anaconda の python パスが返ってくればOK
```

以上です。
React コンポーネントで自分の子要素を取得するときのイディオム

React コンポーネントで自分の子要素を取得するとき、[Callback Refs を使っていた](https://engineer.blog.lancers.jp/2017/05/react_avoid_finddomnode_and_refs_string/)。v16.3 以降は、[React v16.3.0: New lifecycles and context API](https://reactjs.org/blog/2018/03/29/react-v-16-3.html#createref-api) によると、createRef API を使うのが普通なのかもしれない。

以下は、コンポーネントがマウントされたら、input タグにフォーカスをもってゆくコード。createRef 版はこう書く。

```.js
export default class Parent extends Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }
  componentDidMount() {
    this.inputRef.current.focus();
  }
  render() {
    return <input type="text" ref={this.inputRef} />;
  }
}

class Child extends Component {
  render() {
    return <div>{this.props.children}</div>
  }
}
```

Callback Refs だとこうだ。

```.js
export default class Parent extends Component {
  componentDidMount() {
    this.inputRef.focus();
  }
  render() {
    return <input type="text" ref={node => this.inputRef = node} />;
  }
}
```

Callback Refs でも、十分シンプルでイージーだと感じるのは私だけだろうか。[「なるべく力の弱いものを使え！」](https://www.mew.org/~kazu/material/2011-fp.pdf)という言葉を思い出した。この投稿で有用なのは最後の引用だけだ。

## リファレンス

- [公式ブログ > React v16.3.0: New lifecycles and context API](https://reactjs.org/blog/2018/03/29/react-v-16-3.html)
- [公式ドキュメント > Refs and the DOM](https://reactjs.org/docs/refs-and-the-dom.html)
- [関数プログラミングの道しるべ](https://www.mew.org/~kazu/material/2011-fp.pdf)
自分流のWindowsでの開発環境構築

#目的
普段自分が使う環境をメモとして記載。
主にPHPでLaravelを用いたWebアプリを構築するための環境。

#環境
Windows 10 Home

#インストールするプロダクト一覧
| 用途 | プロダクト名 |
|:-----------|------------:|
| ターミナル                    | TeraTerm        |
| Diff                         | DF        |
| テキストエディタ(メモ用)       | サクラエディタ|
| テキストエディタ(開発用)       | Visual Studio Code|
| ファイル転送                  | Win SCP|
| スクリーンショット             | TeraTerm        |
| アーカイブ                    | 7-Zip        |
| 仮想環境                      | VirtualBox|
| 仮想環境                      | Vagrant        |
| ドライバ(キーボード)           | thinkpad トラックポイント・キーボード      |

#各種設定

##Vagrantのインストール

* BOX追加

今回はCentOS 7を追加する。

```:Vagrantファイル生成
cd (vagrat用のフォルダ)
vagrant init
```

```:Vagrantファイル修正
#config.vm.box = "base"
↓
#config.vm.box = "base"
config.vm.box = "centos/7"
```

* 共有フォルダの設定

以下を追記する

```:Vagrantファイル
config.vm.synced_folder "../share", "/home/vagrant/share"
```

```:ターミナル
vagrant plugin install vagrant-vbguest
vagrant reload
```
wpa_supplicant の脆弱性 CVE-2018-14526 の翻訳

下記投稿の私家版翻訳です。
http://lists.infradead.org/pipermail/hostap/2018-August/038749.html
脆弱性の内容ではなく対策だけ知りたい場合は一番下の「可能な対策」を見てください。

# 脆弱性の内容
wpa_supplicant の EAPOL-Key フレーム処理にて脆弱性が見つかりました。この脆弱性により攻撃者はフレームを改変することができます。これによりwpa_supplicantは妥当なMICが無いフレームであっても復号化してしまいます。つまり認証されていないフレームということです。この問題は WPA2/RSN においてユニキャスト暗号方式に TKIP を使用した場合に発生します。WPA2 はユニキャスト暗号方式に TKIP を使用することを想定しておらず、 CCMP を使用することが想定されています。そのため、この脆弱性は実際の運用では起こりません。（訳注:WPA2の初期の段階ではユニキャスト暗号方式に TKIP が認められており、その後禁止されました。ですのでその間に発売されたアクセスポイントのユーザーはこの脆弱性の影響を受けます。）

ユニキャスト暗号方式として TKIP が選択された場合、 EAPOL-Key フレームの Key Data field は RC4 を用いて暗号化されます。この脆弱性は認証されていない EAPOL-Key フレームが処理されることを許可します。また、 RC4 の設計により、攻撃者が Key Data field のプレインテキストバージョンを改変することを許可します。この時攻撃者はビットごとのXORを用い、中身を知る必要はありません。これによりステーションの GTK/IGTK を改変することで DOS 攻撃を行うことができます。この時攻撃者は鍵について知る必要はありません。この攻撃によりステーションはグループアドレス宛のフレームを受信できなくなります。さらに言えば、この攻撃で wpa_supplicant を復号オラクル（訳注:暗号化されたデータを復号化してくれるもの）として使用することができます。これによりグループ暗号キーを得るために GTK/IGTK の Key Data ペイロードを復元する試行が可能です。

グループ暗号キーの完全な復元のためには複数の試行（1オクテットあたり128回の接続試行）が必要です。それらの試行は 4-way handshake の失敗により切断されます。これらの失敗により、アクセスポイントやネットワークは一時的あるいは恒久的（有効にするにはユーザーのアクションが必要）に使用不可能になります。つまり、 AP がグループ暗号キーを変更する前にそれを解析するのは実質的には不可能ということです。デフォルトでは wpa_supplicant は接続試行の失敗の都度最低10秒待つことになっています。言い換えれば各オクテットを復元するために20分待つことになります。ただし、hostapdはTKIPを使用した場合、デフォルトでは10分でキーの更新を行います。つまり、実際的な攻撃のためには、大量のステーションが必要になります。

# 脆弱性のあるバージョン/設定
全てのバージョンの wpa_supplicant。

# 謝辞
この問題の発見と報告について imec-DistriNet research group of KU Leuven の Mathy Vanhoef に感謝します。

# 可能な対策
- RSN/WPA2 においてユニキャスト暗号方式から TKIP を削除します。これはアクセスポイント側でも対応できます。
- 下記のパッチを適用して wpa_supplicant をビルドします。

"WPA: Ignore unauthenticated encrypted EAPOL-Key data" https://w1.fi/security/2018-1

- リリースされたら、 wpa_supplicant v2.7 以上にアップデートします（訳注:2018/08/09時点ではまだリリースされていません）。
プログラミング初心者のPHP備忘録

#メモ
・PHP基本的な書き方

```
<php? プログラムの内容 ?>
```

<?php を宣言することでHTMLファイルにPHPを埋め込むことができる。

・echo
文字列などを出力したい場合「echo」を使う。

```
<?php echo 'おはようございます';?>
```

**コメントアウト**
1行だけコメントアウトしたいなら「//」か「#」
何行もまとめてコメントアウトしたいなら「/* ～ */」で囲めばいい

**データの種類**
PHPには文字列や数値などのデータの種類がある。

文字列はシングルクォーテーション「''」やダブルクォーテーション「""」で表すことができる。
また数値は四則演算をすることができる。

```
echo '5+2';//結果5+2
echo 5+2;//結果7
```
また文字列を連結させたい場合は「.」を用いる

```
echo 'プログラミング'.'勉強';//結果：プログラミング勉強
```

**変数**
PHPで変数を指定するときはドル記号($)を変数名の前につける
例えば年齢（20歳）を表す変数を作りたかったら以下のようになる

```
$age=20;
```

**配列**
配列を使うと、変数に複数の値をまとめて保存することができる。
配列の基本構文は「$配列名＝array(値１,値２,・・・);」
配列のデータには[0]、[1]、[2]というようにインデックス番号が割り振られており、配列のデータを取っ出す際はこのインデックス番号を用いる。

```
$names=array('Hana','Kenta','Bob'); //配列を定義
echo $names[0]; //結果：Hana
echo $names[1]; //結果：Kenta

$names[]='Mari'; //配列の末尾に値を追加
echo $names[3]; //結果：Mari;

$names[0]='Yui'; //値の上書き
echo $names[0]; //結果：Yui
```

・連想配列
連想配列は、インデックス番号ではなく「キー」と呼ばれる文字列などの値を指定できる。
「$配列名=array('キー名'=>'値１'・・・);」といったように、「=>」を用いてキーと値をセットする。

```
$my_info=array(
          'name'=>'ヒロ',
          'age'=>21,
          'gender'=>'men'
      );
echo $my_info['name']; //結果：ヒロ

$my_info['birthday']='3月10日'; //データの追加
```

**if文**
if文を使うことで条件に応じた処理をすることができる。

```
$x=10;
if($x<20){
  echo '$xは20より小さい';
}
```
・elseif：「もしも～だったら、それとも～であれば・・・」という条件分岐が可能。

・else：ifと組み合わせることで「もし～であれば、そうでなければ・・・」という条件分岐が可能。


**switch文**
条件分岐が多く複雑な場合、switch文で置き換えることができる。

```
switch($number){
   case:0; //$numberが0ならば
   echo '0';
   break; //caseブロックの最後に必要
   
   case:1; 
   echo '1';
   break;

   default: //どのcaseにも一致しない場合
   echo 'エラー';
   break;
```

**for文**
for文を使うことで繰り返しの処理ができる。
「for(➀初期化;➁ループの条件;➂変数の更新)」というように書く

```
for($i=0;$i<=100;$i++){
　//　➀;   ➁;   ➂  
 
echo $i; //繰り返す処理
```

**while文**
for文と同じく繰り返しの処理。
条件式を指定し、それがtrueの間、処理が実行される。

```
$i=0; //初期化
while($i<=100){ //ループの条件
   echo $i;　//繰り返す処理
   $i++; //変数の更新
}
```

**foreach文**
配列、または連想配列に対して、先頭のデータから順に繰り返し処理を行う。

```
$names=array('ユイ','ケンタ','ミホ');
foreach($names as $value){ 
//as の後ろの変数（ここでは$value)にデータを代入
   echo $value; //結果：ユイ　ケンタ　ミホ
}
```
MariaDB(MySQL) PostgreSQL  どちらを選ぶか?

私がフリーのSQLデータベースを選択する場合、MariaDB/PostgreSQLを採用することが多い。 この記事では改めて両者を比較してみる。

#正規表現(regexp_replace)

大きな差はない。PostgreSQLの正規表現がフラグなどがPerl等のプログラミング言語に採用されている正規表現に近く馴染みやすい。MariaDBのそれは少し異なる。

- MariaDB https://mariadb.com/kb/en/library/regexp_replace/
構文:REGEXP_REPLACE(subject, pattern, replace)

- PostgreSQL  https://www.postgresql.jp/document/10/html/functions-matching.html
構文:regexp_replace(source, pattern, replacement [, flags ])


#メモリストレージエンジン と UNLOGGEDテーブル

MariaDBはデータベースエンジンを選択できる。これにはPostgreSQLにはないメモリだけのデータベースであるメモリストレージエンジンを選択することが出来る。もちろん物理メモリを消費するので大きなテーブルはできないが、速度は圧倒的である。一方PostgreSQLには、UNLOGGED TABLEと呼ばれるジャーナルを作らないテーブルを作ることが出来る。一般のテーブルと比べると信用性が落ちるものの、これも高速動作する。使い勝手は容量を気にせず使えるUNLOGGED TABLEの方が良い。メモリストレージエンジンの場合、BLOB型とTEXT型は使えない点には注意が必要だ。

- MariaDB

```sql
CREATE TABLE test (id int, v varchar(10) ) ENGINE = MEMORY;
```

- PostgreSQL  

```sql
CREATE UNLOGGED TABLE test (id int, v text);
```

#ストアード・プロシージャ

ストアード・プロシージャの自由度はPostgreSQLの方が高い。例えば、MariaDBではストアド・プロシージャの入力にテーブルを扱うことができない。結局、一時テーブル(TEMPORARY TABLE)を経由することになるので、PostgreSQLと比べると使いにくい。一時ビュー(TEMPORARY VIEW)があれば、まだマシだったかもしれないがそれもない。その他PostgreSQLのストアード・プロシージャにはPerlやPythonを用いることが出来る。

#パラレルクエリー

PostgreSQLにはパラレルクエリーと呼ばれる一つのクエリーを複数のスレッドで処理する機能が実装されている。使いこなすのは難しいが、クエリーを高速にすることができる。MariaDBで同様のことをする場合、呼び出し側で処理を分割し複数プロセスから複数のクエリーを実行する必要がある。逆に言えば、マルチプロセス・マルチスレッドに対応できない言語(標準のPHPなど)で、パラレルクエリーと同様の性能を出すことはできない。パラレルクエリーはOracleやMS-SQLServerにも実装されている。

#MySQL

MySQLにも少し触れる。商用SQLデータベースの大手のORACLEが著作権・商標権をもっていることやライセンスやの問題から、昨今のLinuxの各ディストリビューションではMySQLから派生したMariaDBが採用されていることが多い。私もMySQLはあまり使用していない。正規表現関連の実装も遅れてregexp_replaceは、MySQL8からの実装になった。また、MySQL8はMariaDBと互換性がない。MariaDBと完全に互換性があるのは、MySQL5.Xまでである。MySQL8を採用する場合はこの点にも注意が必要だ。

#まとめと考察

性能的な評価はしていないが、使いやすいのはPostgreSQLだと考える。もしカリカリに調整が必要なくらいパフォーマンスが要求される場合は、OracleやMS-SQLServerも選択肢に入れてもいいのではないだろうか。
rails5 uninitialize constant Postscontrollerのエラー表示が出て悩んだ件

#uninitailize constantへの対応はどうすべきか

昨日からこのエラー表示が出てきて、自分もかなりの時間(それでも1日ほど)悩まされたので、一応備忘録として残しておく。


Postsコントローラーが何とかというのは、わかるが、何が問題なのか調べたところ、どうやらPosts_controller.rbつまり、Postsコントローラーのファイルが存在するかどうかを疑うべきらしい。
まずは、下記がroutes.rbで定義しているURLです。

```
new_user_session GET    /users/sign_in(.:format)       devise/sessions#new
            user_session POST   /users/sign_in(.:format)       devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy
       new_user_password GET    /users/password/new(.:format)  devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format) devise/passwords#edit
           user_password PATCH  /users/password(.:format)      devise/passwords#update
                         PUT    /users/password(.:format)      devise/passwords#update
                         POST   /users/password(.:format)      devise/passwords#create
cancel_user_registration GET    /users/cancel(.:format)        devise/registrations#cancel
   new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
       user_registration PATCH  /users(.:format)               devise/registrations#update
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy
                         POST   /users(.:format)               devise/registrations#create
                   posts GET    /posts(.:format)               posts#index
                         POST   /posts(.:format)               posts#create
                new_post GET    /posts/new(.:format)           posts#new
               edit_post GET    /posts/:id/edit(.:format)      posts#edit
                    post GET    /posts/:id(.:format)           posts#show
                         PATCH  /posts/:id(.:format)           posts#update
                         PUT    /posts/:id(.:format)           posts#update
                         DELETE /posts/:id(.:format)           posts#destroy
              posts_find POST   /posts/find(.:format)          posts#find
```

#考えられる問題点
今回、root_path/postsを叩いた時にタイトルのようなエラーが表示された。これは、rails sした時に、この叩いたURLのcontrollerファイルをrails側で探してきて、存在しない場合、タイトルのようなエラーが表示されるような仕組みらしい。


ただ、探したところposts_controller.rbファイルは存在した。この時、もう一つ気をつけないといけない点が、controller名は複数形でないとならないというrailsの命名規則に基づいているかどうかも考えなければならない。
今回、自分はこの命名規則に基づいてcontrollerを生成していたので、ここが問題ではなかった。

次に、考えるべきところが、ファイルパスである。ここで、問題が生じていた。
app/controllers/posts/posts_controller.rb
このようにcontrollerディレクトリ以下から、さらにpostsディレクトリを生成して、そのpostsディレクトリ以下に、posts_controller.rbファイルを管理していた。



#対策
デフォルトでのrailsでは、controllersディレクトリ以下のみを読み取るようになっており、これを上記のようなファイルパスで読み取るようにする場合は、どうやらinitialize/config以下でさらに設定を行なわなければならないらしい。
とりあえず
app/controllers/posts_controller.rb
という感じでposts_controller.rbファイルをcontrollersディレクトリ以下にすると、エラーが解消された。

このエラーはcontrollerだけではなく、modelsディレクトリ以下でも上記と同じような事でエラーになるので、気をつけるべきかと・・

以下がtwitterになります。
https://twitter.com/FujisawaRyohei
フォローよろしくお願いします。
Airio-baseでブラウザからLチカ

# やりたいこと
ブラウザからcommand.cgi経由でSDの接続ピンに信号おくり、Mbed側で値みてLEDを点灯

# Mbed側 

```c
#include "mbed.h"

//出力先、入力先
DigitalOut myled(LED1);
DigitalIn mycmd(P0_21);
DigitalIn mydata(P0_22);
DigitalOut myled2(P1_13);

//SDカード電源ON
DigitalOut sd_en(P1_16, 1);
int main() {
    //お試しのLチカ
    myled = 0;
    myled2 = 0;

    wait(0.5);
    
    //ループして状態を見る
    while(1) {
        if(mycmd) {
            myled = 1;
        }else{
            myled = 0;
        }
        
        if(mydata) {
            myled2 = 1;
        } else {
            myled2 = 0;
        }
    }
}

```

## FlashAir上にhtml用意

```html
<html>
<head>
  <meta charset="UTF-8">
</head>
<body>

<a href="http://flashair/command.cgi?op=190&CTRL=0x03&DATA=0x1f" target="out">全部消灯</a><br/>
<a href="http://flashair/command.cgi?op=190&CTRL=0x01&DATA=0x1e" target="out">LED1点灯</a><br/>
<a href="http://flashair/command.cgi?op=190&CTRL=0x02&DATA=0x1d" target="out">LED2点灯</a><br/>
<a href="http://flashair/command.cgi?op=190&CTRL=0x03&DATA=0x1c" target="out">LED1と2点灯</a><br/>

</body>
<iframe width="640" height="200" name="out">
</iframe>
</html>

```

あとはFlashAirをAirio-baseに取り付けて、ブラウザからhtmlを表示してリンクをクリックして動作確認。
自分用ごった煮メモ：shell編

自分用のメモです。
ネットに転がってるものを主にまとめたもの。おそらく自分以外が読んでもあまり意味のない内容になるとおもいますので、ご了承ください。

#shellのpathについて
- pathは`:`で区切られる
- pathを追加する際は、`PATH=$PATH:/home/user/mybin`みたいな形で行う。<b>`:`</b>で区切るのがポイント。<br>pythonのpath追加に関しても同様・<br>`export PYTHONPATH=$PYTHONPATH:/home/user/python/module`を、<br>`.bashrc`に書き込んどきましょう。
覚え書き：macOSからsshでAndroid(SSHDroid)にログインする

##はじめに
macOSからSSHDroidが起動しているAndroid端末にsshコマンドでログインする手順のメモです。
（SSHDroidはGoogle Playで入手してインストールし、起動させておいてください。）

参考）https://man.openbsd.org/ssh_config

紹介する手順は、openSSH利用時に必要な一般的な設定であり、macOS固有という訳ではありませんが、フリーソフトを利用することの多いWindowsと比べると、macOS/UNIX等では設定の定義などあらかじめ作成して置かなければならない作業があるため、覚え書きとしてまとめたものです。

macOSに標準のsshコマンド(OpenSSH)で、下記のようにユーザー名、IPアドレス、ポート番号を指定して接続しようとしても、"Could not resolve hostname ..."といったエラーメッセージが表示されて接続することができません。

```bash
yuza-no-MacBook:~ yuza$ ssh root@192.168.xxx.xxx:2222 
ssh: Could not resolve hostname 192.168.xxx.xxx:2222: nodename nor servname provided, or not known
```

###`~/.ssh/config`の作成、または`/etc/ssh/ssh_config`の編集
viエディタなどで、`~/.ssh/config`を作成します。
（全ユーザー共通の設定にしたい場合は、rootユーザー権限で`/etc/ssh/ssh_config`を編集してください。編集前にあらかじめバックアップもとっておきましょう。）

`192.168.xxx.xxx`は、Android端末でWiFi接続した際に割り当てらえれたプライベートIPアドレスです。皆さんの環境に合わせて変更してください。

"#"の文字以降はコメントです。動作には関係ありませんので入力しなくても構いません。

```bash
yuza-no-MacBook:~ yuza$ vi ~/.ssh/config
```

```bash:~/.ssh/config
# for SSHDroid running android terminal
Host my_android              # sshコマンドではこのエントリ名を指定します
 HostName 192.168.xxx.xxx    # 名前解決を利用しない場合は、IPアドレスでも記述可
 Port 2222
 User root
 IdentityFile ~/.ssh/id_rsa_secret_key
```
DNSでホスト名(FQDN)からIPアドレスへの名前解決ができる場合や、`/etc/hosts`ファイルにAndroid端末のホスト名を記述済みの場合は、`HostName`フィールドは下記のようにFQNDやホスト名で記述しても構いません。

```bash
yuza-no-MacBook:~ yuza$ cat /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1	localhost
255.255.255.255	broadcasthost
::1             localhost 

192.168.xxx.xxx	my_android
```

```bash
yuza-no-MacBook:~ yuza$ vi ~/.ssh/config
```
```bash:~.ssh/config
# for SSHDroid running android terminal
Host my_android         # sshコマンドではこのエントリ名を指定します
 HostName my_android    # 名前解決可の場合は、ホスト名またはFQDNで記述しても良い
 Port 2222
 User root
 IdentityFile ~/.ssh/id_rsa_secret_key
```

###sshコマンドの実行
下記のようにAndroid端末のIPアドレスまたは~./ssh/configに記述したエントリ名（`Host`の後に記述した名前）を指定してsshコマンドを実行します。

```bash
yuza-no-MacBook:~ yuza$ ssh my_android
```
初めての接続の場合、公開鍵が作成されて登録されたあと、`fingerprint`の表示に続いて`connecting (yes/no)?`と尋ねてくるので、`yes`と入力しておきます。

```
The authenticity of host '[my_android]:2222 ([192.168.xxx.xxx]:2222)' can't be established.
RSA key fingerprint is SHA256:　（ここにはフィンガープリントが表示される）
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[my_android]:2222' (RSA) to the list of known hosts.
```

続いてパスワードを入力します。`password:`のあとに、SSHDroidのデフォルトパスワード`admin`と入力します。

```bash
SSHDroid
Use 'root' as username
Default password is 'admin'
root@my_android's password:
```

下記のようなプロンプトが表示されれば、ログイン成功です。
（SSHDroidのユーザー名やホスト名は伏せています）

```bash
u0_aXXX@XX-XXXX:/data/data/berserker.android.apps.sshdroid/home $
```
あとは好きなようにコマンドを入力してみてください。