OmniAICreator/Qiita-1.07M huggingface dataset:
ElixirとErlangVMでGoogle Comupte Engine内のインスタンスとノード間通信

# elixir初心者の初めての分散処理

1. [動作確認環境](#1-動作確認環境)
2. [erlangvmのノード間通信の仕組み](#2-erlangvmのノード間通信の仕組み)
3. [erlangvmのIPとcookie](#3-erlangvmのIPとcookie)
4. [通信できないときのtips](#4-通信できないときのtips)
5. [最後に](#5-最後に)


#1. 動作確認環境
- ubuntu18.04(僕はvagrant上のvmでやりました）
- Elixir 1.7.4 (Erlang/OTP 21)
- Google Computer Engin(ファイアウォール設定はデフォルトのままでつながります)　 

#2. erlangvmのノード間通信の仕組み
Erlangvmはepmdというデーモンプロセスを4369番ポートでプロキシサーバとして使います。なので双方に[elixirをインストール](https://elixir-lang.jp/install.html)して、GCEとlocalhost上の4369番ポートを使えるようにしてください。
epmdはipアドレスでノードを探し、共通のcookieが設定されている場合双方のノードを接続します。

#3. erlangvmのIPaddrとcookie
ipアドレスをノードに設定するには--nameオプションを使い node名@ IP の形でiexを起動します。また、cookieの指定は--cookieオプションで行います.

```localhost.erlangvm
iex --name foo@IP --cookie test
```
**GCEではcookieをこの形でiex起動時に設定してもインスタンスごとに異なるデフォルト?のクッキーに上書きされた状態でnodeが起動してしまいます**


なので

```gce_instance.erlangvm
iex --name bar@external_IP 
```
で立ち上げた後に

```gce_instance.erlangvm
iex> Node.set_cookie :"test"
```
を用いてGCE側のノードにlocalhostのノードと同じクッキーを設定します

ではlocalhostからGCEのノードに接続します。

```localhost.erlangvm
iex> Node.connect :"bar@external_IP"
true
```

ノードリストの確認（どちらかのノードで以下のコマンドを使用します)

```
iex> Node.list
```
接続先ノード情報の出力があれば成功です。

<a id="anchor4"></a>
#4. 通信できないときのtips
cookieの確認
`iex> Node.get_cookie`

IPアドレスの確認
`iex> :inet.getif`(ググれば一番上に出るけどドキュメントには載ってないerlangのモジュール関数）

IPの確認はpingとtcpdumpでもできます。

```localhost.shell
$ping external_IP
```
```gce_instance.shell
$sudo tcpdump
```
<a id="anchor4"></a>
#5. 最後に
今回はGCEインスタンスを用いたノード間通信を行いました。
**因みにwifi接続の場合gce側から実機に接続を試みてもwifiがwebサーバーからの攻撃対策でping接続をブロックするので繋がりません。もちろん上記のように実機から接続すれば通信できます。**

[またrubyプログラムでErlangVMプロトコルを実装してノード接続しちゃう本格的な人もいます](https://qiita.com/binzume/items/3a9ece799153ccfa237d)
OCR導入時の注意点：ベンダーのホームページには精度100％と書いてあったのに、実際に試したら70％も出なかった……という現象がなぜ起こるか

OCRがらみの仕事をやっているので、よくお客様から「このOCRの精度は何％なんですか？」と聞かれます。

これは正直あまり意味がない質問で、表題のような現象が起こるのも、平たく言えば**その手の意味のない質問にベンダーが苦肉の策で答えようとした結果**です。

この記事では、**こうした数値の乖離がなぜ起こるのか**とともに、**OCR導入時に気をつけるべきポイント**を解説していきます。

##この体重計に乗ると、体重は平均で何キロになりますか？

……という質問に意味がないことは、誰しもすぐにわかると思います。

**そんなの誰が乗るかによるよ！**　と思いますよね。

OCRの精度も同じで、**どんな帳票を読み込ませるかによります。**

にもかかわらず、OCRに関わる仕事の現場では、**「そのOCR、精度は何％なんですか？」**という質問が毎日のように飛び交っています。

体重計でいえば、「その体重計にAさんが乗ったら何キロになりましたか？」という具体的な質問であれば、もちろん回答が可能です。

Aさんを乗せて結果を見れば一目瞭然。

OCRも同じで、「そのOCRに**この帳票を読み込ませたときの精度は何％でしたか？**」という、具体的な帳票をテストした結果なら回答できますが、それなしに「OCRの精度を教えてください」と尋ねるのは、「体重計の平均体重」を尋ねるのと同じくあまり意味がありません。

##ベンダーが公開している精度の数字を鵜呑みにできない理由

そうは言っても、OCRといえばやはり精度が気になるのが人間の性。

ベンダーによっては、ホームページなどで精度を開示している例もあります。
筆者が見た限り、**精度を数字で開示している場合は、必ず「当社が選定した帳票によるテスト結果です」などのただし書きがついています。**

おそらくベンダー側も「精度の一般的な数値なんて出せないし、出しても意味ないよ……」と思いながら、問い合わせが多いので苦肉の策でそうしたものと思われます。

**精度の数値に客観性を持たせるには、業界共通のテスト基準や、それをクリアしているかどうかを判断する第三者機関が必要ですが、OCRに関してはそうした業界標準がありません。**

そこで、ベンダーとしては**自分たちが得意とする帳票の、得意とする項目でテストをして数値を公開する**ことになります。

**ベンダーが数値を開示するためにテストした帳票と条件の異なる帳票を読み込ませれば、当然、結果にも違いは出てきます。**

ベンダーのホームページには精度100％と書いてあったのに、実際に試したら70％も出なかった……というような現象は、こうした理由で発生します。

だったら精度100%などとホームページに書くなと思うかもしれませんが、ベンダーからすれば、「じゃあ精度は何％ですかって聞くな」と言いたいところだと思います。

##OCR選定の基準は精度だけじゃない

OCRの精度を本当の意味で比較したければ、現状は、自分たちがOCRにかけたい帳票の、OCRでとりたい項目を各社のOCRで読み込ませて比べてみるしかありません。

ですがOCRのベンダーは数が多いので、全社に帳票を配って結果を検証するというのもなかなかの手間になると思います。

OCRの製品を比較する場合には、精度以外にも重要になるポイントがあるので、その点を以下に列挙しておきます。

- 設定の簡単さ
- 補正機能の充実度（傾き補正、ノイズ除去）
- 固定フォーマットのみ対応か、多品種に対応しているか
- 誤りの検知方法
- 起動から検証までのフローや使い勝手（分類やアップロードを手動でする必要があるか、自動でできるか等）
- 価格

例えば多品種フォーマットへの対応が必要な案件であれば、固定フォーマットにしか対応していないOCRの精度がいくら高くても、そのOCRを導入する意味はありません。

補正機能に関しては、帳票をスキャンするときに少しでも位置がズレたり傾いたりするだけで項目がとれなくなるOCRもあれば、傾きやズレを自動補正したり、位置が多少ズレていたりしても項目が取得できるOCRもあります。

また、A社のOCRでは帳票全件を手動でアップロードする必要があり、B社は自動処理が可能だとすると、**精度ではB社が劣っていたとしても、業務全体の効率化という意味ではB社製品を採用するのが正解**といったケースも考えられます。

こうした精度以外の観点でも、製品をかなり絞り込むことができます。

#まとめ

「OCRの精度が何％か」という問いは、「この体重計の平均体重は何キロか」という質問と同じであまり意味がありません。
OCR導入時には、精度以外の機能もよく見て製品を絞り込んだ上で、業務で実際に使いたい帳票・使いたい項目に絞って精度の検証をするのが正解です。
STOW-RSでハマった話

# STOW-RSでハマった話

Docker Desktop for WindowsでOrthancコンテナを立ち上げ、DICOM Webの確認をしていたときのハマった事例を共有します。

## 環境

- Docker Desktop for Windows 
	- Orthanc
	- CentOS 8
- Postman

## ハマったこと

- Postman→OrthancにSTOW-RSでDICOMデータを登録しても登録されない。
	- HTTP 200応答される
	- データは登録されていない。

## 調査～解決

1. Orthancコミュニティで質問したところ、curlコマンドとDICOMファイルの提出を求められたのでPostmanからcurlを生成して調査
2. --formにContent-typeがついてないことに気がつく。
3. つけてみてcurl実行 (CentOS8上で) →成功・ファイル登録された。

```sh
curl --location --request POST 'http://172.17.0.2:8042/dicom-web/studies/' \
--header 'Content-Type: multipart/related; type="application/dicom"' \
--header 'Authorization: Basic b3J0aGFuYzpvcnRoYW5j' \
--form 'content=@sample.dcm; type=application/dicom' \
--verbose
```

### 仕様・規格

現行のPostman仕様とDICOM規格からすると、PostmanでSTOW-RSを使うのは不可能のようです。

- Postmanはバイナリには個別にContent-typeはつけない
![](https://live.staticflickr.com/65535/49915481562_95cce15c2f_z.jpg)
[https://learning.postman.com/docs/postman/sending-api-requests/requests/#sending-body-data](https://learning.postman.com/docs/postman/sending-api-requests/requests/#sending-body-data)

- 一方で、DICOM規格を見ると、Bodyの各パートごとに宣言が必要との記載が。。。
![](https://live.staticflickr.com/65535/49915493932_97e1842958_z.jpg)
[http://dicom.nema.org/dicom/2013/output/chtml/part18/sect_6.6.html](http://dicom.nema.org/dicom/2013/output/chtml/part18/sect_6.6.html)
表をドラッグ & ドロップで並び替えたい

# はじめに
表をドラッグ & ドロップで並び替える必要があったのですが、なにか良いライブラリがないか探すと[SortableJS](https://github.com/SortableJS/Sortable)というのがあり使ってみると便利だったので紹介したいと思います。

# インストール
#### npm
```
npm install sortablejs
```

#### CDNもあります
```html
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
```

# 使い方
並び替えたいhtml要素を用意します。
※わかりやすくするためにbootstrapでcssを適用しています

```html:html
<table class="table table-bordered w-25">
    <tbody id="sort-table">
    <tr><td>１行目</td></tr>
    <tr><td>2行目</td></tr>
    <tr><td>3行目</td></tr>
    </tbody>
</table>
```

用意したhtml要素をjsで取得して、SortableJSに設定します。

```js:js
// 以下のいずれかでSortableJSを読み込みます
// CDNの場合は不要です
import Sortable from 'sortablejs';
const Sortable = require('sortablejs/Sortable');

// html要素を取得をしてSortableJSに設定します
const sortElement = document.getElementById('sort-table');
Sortable.create(sortElement);
```

たったこれだけで並び替えができます。
![base.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589294/bfea16b7-d198-233f-48e5-72f4f2afe3fa.gif)

html要素はtableタグ以外でも利用できます。

ul、liタグ

```html:html
<ul id="sort-table">
    <li>1行目</li>
    <li>2行目</li>
    <li>3行目</li>
</ul>
```

divタグ

```html:html
<div id="sort-table">
    <div>1行目</div>
    <div>2行目</div>
    <div>3行目</div>
</div>
```

こんな使い方はしないと思いますが、以下のように子要素が異なるタグでも適用できます。

```html:html
<div id="sort-table">
    <p>1行目</p>
    <div>2行目</div>
    <section>3行目</section>
</div>
```

# オプション
SortableJSには[オプション](https://github.com/SortableJS/Sortable#options)があり、これらを利用することで簡単に機能の拡張ができます。

```js:js
const sortElement = document.getElementById('sort-table');
Sortable.create(sortElement, {
    handle: '.handle', // ドラッグのトリガーをセレクタで指定します
    chosenClass: 'chosen', // ドラッグで選択中の要素に付与するクラス名
    animation: 200, // ドラッグして並び替える時のアニメーションの速さを指定します
});
```

```css:css
<style>
    .chosen {
        background-color: #e0ffff;
    }
</style>
```

```html:html
<table class="table table-bordered w-25">
    <tbody id="sort-table">
    <tr><td><button class="handle">:</button>１行目</td></tr>
    <tr><td><button class="handle">:</button>2行目</td></tr>
    <tr><td><button class="handle">:</button>3行目</td></tr>
    </tbody>
</table>
```

![demo2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589294/8657937a-418f-969a-7d46-33605e7faa06.gif)

# まとめ
SortableJSを使うことで、ドラッグ & ドロップでの表の並び替えが簡単にできました。
[公式のデモページ](http://sortablejs.github.io/Sortable/)には他にもたくさんのサンプルがあったので、まだまだ色々できそうです。
VSCodeでvue.jsのデバッグ（console.logを使用）


console.logでvue.jsのデバッグを行う為、こちらの記事を参考に修正しました。

参照URL
https://www.atmarkit.co.jp/ait/articles/1807/10/news033_3.html

launch.jsonを開き、下記を追記します。

```"internalConsoleOptions": "openOnSessionStart"
```
![スクリーンショット 2020-05-09 19.05.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622315/3eef7a88-cb7f-e030-aa65-d5ee3f0e679b.png)

デバッグのアイコンをクリックし、実行ボタンを押します。

![スクリーンショット 2020-05-09 19.43.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622315/638c26d8-0a5a-d591-330d-237d673aa6b3.png)


console.logでコンソール画面に出力することができました。
PHP初心者がMacでLaravelに挑む

（試験的に勉強兼ねて英語で書いてみた）

# Goal
- To learn from the environment setup to the fundamental usage
- To create a To-do app with Laravel

# Environment setup
## 0. Development environment
Mac OS Catalina 10.15.4
MacBook Air (13-inch, Mid 2013)

## 1. Downloading & Installing
### 1.1. Choosing the version
Laravel 7 (the latest version as of May 2020)
PHP 7.3.11 (Laravel 7 requires above 7.2.5)

### 1.2. Installing composer
[Composer](https://getcomposer.org/)
<img alt="laravel1.png" width="300px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616261/f18f264d-5841-179f-83d9-ad4d039c3587.png">

Access the above website and click ```Download```

<img alt="laravel2.png" width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616261/e6bbf316-f1b8-de74-e937-5936683c75e5.png">

Execute these four lines on this webpage like:

```console
$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php -r "if (hash_file('sha384', 'composer-setup.php') === 'e0012edf3e80b6978849f5eff0d4b4e4c79ff1609dd1e613307e16318854d24ae64f26d17af3ef0bf7cfb710ca74755a') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$ php composer-setup.php
$ php -r "unlink('composer-setup.php');"
```

They mean that in order:

```
・ Download the installer to the current directory
・ Verify the installer SHA-384
・ Run the installer
・ Remove the installer
```

#### Move Composer

```console
$ mv composer.phar /usr/local/bin/composer
```

#### Check if it succeeded

```console
$ composer -V
Composer version 1.10.6 2020-05-06 10:28:10
```

### 1.3. Installing Laravel
Create a project called ```sample```, or what else you like.

```console
$ composer create-project --prefer-dist laravel/laravel sample
```

### 1.4. Starting a server
Move into the directory you made and start a server.

```console
$ cd sample
$ php artisan serve
```

Try to access your local server: ```http://localhost:8000``` on a web browser!
<img alt="laravel3.png" width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616261/683c423b-23ed-b4b5-91ba-939bee7222f4.png">

**Congratulations!!**

# Creating a ToDo app
Now I start to create a ToDo app known as that is simple and easy to develop for even a beginner.
I referred to this website:
[Laravelの知識ゼロから基本をマスターするチュートリアル | Awesome Blog](https://awesome-linus.com/2019/06/05/laravel-tutorial-basic-from-zero/)

# References
- [Laravel - The PHP Framework For Web Artisans](https://laravel.com/)
- [Installation - Laravel - The PHP Framework For Web Artisans](https://laravel.com/docs/7.x) : the Official documents
- [Laravelの知識ゼロから基本をマスターするチュートリアル | Awesome Blog](https://awesome-linus.com/2019/06/05/laravel-tutorial-basic-from-zero/)
VS2017メモ



# Unity連携
VSインストール時にPluginを入れるようになった。

# ファイルのエンコード、CRLF
ファイル保存時に設定する。
「保存オプションの詳細設定」はなくなった
https://nekko1119.hatenablog.com/entry/2017/03/28/003348
AfterEffects CC 2020 の雑な覚書２：タイムラインパネル、レイヤー操作

# 他の記事

雑な覚書シリーズ：

- [AfterEffects CC 2020 の雑な覚書１：コンポジション、レイヤー、シェイプ（図形）、動画読み込み](https://qiita.com/mml/items/9268b7a436e2a6bf0374)
- [AfterEffects CC 2020 の雑な覚書２：タイムラインパネル、レイヤー操作](https://qiita.com/mml/items/64fbf2f608cc18ae2485)（この記事）
- [AfterEffects CC 2020 の雑な覚書３：アニメーション、エフェクト](https://qiita.com/mml/items/78956c01d9a5a3d8fd22) 
- [AfterEffects CC 2020 の雑な覚書４：クロマキー、調整レイヤー、タイムリマップ、プリコンポーズ](https://qiita.com/mml/items/ba6a21dd6d0bf1667d10)

# とりあえず知っておくべき基本操作

ショートカットキー
-https://vook.vc/n/666

## 時間方向の拡大率を変える

ウィンドウ下のほうにある、山のマークの左側をおすと時間軸がより細かくなり、右側のマークを押すと粗くなる。時間軸が粗いときは、時間の単位はS（秒）で表示されるが、詳細にしていくと単位がF（フレーム）になる。

![ae12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c6331351-bbbf-2920-5884-d557839a9d27.gif)

タイムラインの上にある、バーみたいなものの左右についている、青いポチを動かすことでも拡大率（？）は変更できる。

この操作ができる方法がわからないと、めっちゃ苦労する。表示されている時間の単位（秒とかフレームとか）を切り替えるには、拡大率を変更するしかないことを知らないと、もっと苦労するはず。

# レイヤーの操作いろいろ

## レイヤーを切断する

ALT+[ キーで現在位置を先頭として、レイヤーを切断できる。ALT+] は現在位置+1フレームの位置を末尾として、レイヤーを切断する。この機能、メニューからどうやって選ぶかわからない…

![ae14.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/69a6b72c-0c33-4c7d-939d-af36f04bd9b0.gif)

切断されたレイヤーは、レイヤーの端をつかむことで、長さを変更できる。

## レイヤーを二つのレイヤーに分割する

Control＋Shift+Dで、現在位置でレイヤーを分割して、二つのレイヤに分けることができる。

![ae15.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c8596fa6-a65d-c3e3-c9ff-00cd410e3117.gif)

分割されたレイヤーをひとつに戻すみたいなことはできなくい（Undoで分割前に戻すことできる）。レイヤーをまとめて扱いたいときは「プリコンポーズ」という機能を使う。

## 任意のレイヤーにマスクをかける（トラックマット）

動画や画像のレイヤーは、図形を描画することでマスクをかけられるけど、シェイプレイヤーにマスクをかけようと思うと、図形描画ではうまくいかない。トラックマットを使うと、任意のレイヤーにマスクをかけられる。

まず、マスクをかけたいレイヤーのすぐ上に、マスクを描画するレイヤーを作る（シェイプレイヤーでOK)。次に、マスクとなる上側のレイヤーに、マスクとして使う矩形を描画する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0cf67ffe-5e16-2404-64d4-ee583ecef752.png)

上の例では、上側のレイヤーに赤い矩形を描いて、下のレイヤーに青い矩形を描いている。この状態で、下側のレイヤーの「トラックマット」の欄にあるポップアップメニューから「アルファ」を選ぶ。

![ae16.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/149a2f9d-b371-a184-36b1-4b60ff2cbbd4.gif)

すると、上側にあるレイヤーに描かれた図形の色が塗られている部分がマスクになる。上側のレイヤーは非表示状態になり、赤い矩形は表示されなくなる。

**トラックマットはマスクをかけられる側で設定する**。トラックマットの操作は、直上にあるレイヤーを自動的に非表示にする。この二つはとても重要。

トラックマットを解除したい場合は、マスクがかかっている側のレイヤーで、トラックマットのポップアップメニューから「なし」を選ぶ。ただし、この操作だけでは上側のマスクになったレイヤーは非表示のままになる。完全に元に戻すには、上側のレイヤーの左側の表示、非表示の切り替えボタンを押して、表示状態にする必要がある。

![ae17.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/2e66d183-2120-8a34-d27b-f93b6e7f0dab.gif)

## レイヤーの非表示

レイヤーの左側にある、目のようなアイコンのある場所を押すことで、レイヤーの表示状態と非常時状態を切り替えられる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/1bde2dce-c15b-9802-cc6b-ee7e401b70fc.png)

何らかの操作をしたあとに、レイヤーが全く表示されなくなったときは、この表示アイコンが消えている状態になっていないかをチェックしてみること。

目のすぐ右のダイヤみたいなマークは、レイヤーに音声が含まれているときに、表示されている図形や動画だけ非表示にして、音声だけを聞こえる状態にする。

## レイヤーを操作できないようにする：ロック

レイヤーの左側のカギマークのアイコンをつけると、レイヤーに描かれた図形や動画などを編集できなくなる。レイヤーがロック状態になっても非表示状態にしなければ、レイヤーの中身は表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b5120e23-8584-defe-5e89-a28abb5e0c3a.png)
【GCP】Cloud Interconnect、Partner Interconnectとは

https://cloud.google.com/interconnect/docs/concepts/overview?hl=ja

Cloud Interconnect には、オンプレミス ネットワークを拡張するための 2 つのオプションがあります。Dedicated Interconnect は、オンプレミス ネットワークと Google のネットワークを物理的に直接接続します。Partner Interconnect は、サポート対象のサービス プロバイダを介して、オンプレミス ネットワークと Google Cloud VPC ネットワークを接続します。
【GCP】Access Context Managerとは

Access Context Manager でアクセスレベルを構成できる
https://medium.com/google-cloud-jp/gcp-secure-protection-with-vpc-service-controls-part-1-85643fbfb674

▼アクセスレベルのタイトル

管理/運用しやすい任意の名前を入力します。

▼条件

今回の条件は許可したいIPアドレスを記載するだけで、条件は複数にはならないため、「OR ANDで結合」 の選択箇所はグレーアウトになっております。条件が満たされる場合に返される値にはTRUEを選択し、IPサブネットワーク欄に許可したい、IPアドレスをCIDRブロック表記で入力します。条件の箇所でFALSEを選択し、IPアドレスを選択すると、そのIPアドレス以外からのアクセスを許可することになります。
https://tech-cci.io/archives/1586

https://dev.classmethod.jp/articles/ec2-2-bigquery-with-ipcontrol/
https://gsuiteupdates-ja.googleblog.com/2019/03/chromemacwindows-endpoint-verification.html
【GCP】IAPとは

https://cloud.google.com/iap/docs/concepts-overview?hl=ja
IAP を使用すると、HTTPS によってアクセスされるアプリケーションの一元的な承認レイヤを確立できるため、ネットワーク レベルのファイアウォールに頼らずに、アプリケーション レベルのアクセス制御モデルを使用できます。

https://tellme.tokyo/post/2017/10/30/cloud-iap/
Cloud Identity-Aware Proxy (Cloud IAP、または IAP) を使うことで、任意の GCP リソース 1 に存在するロードバランサに対して、許可された Google アカウントやサービスアカウントによるアクセスのみに絞ることができます。 また、このアクセスリスト (ACL) の追加や削除などは GCP のウェブコンソールから簡単に制御することができます。
【GCP】Endpoint Verificationとは

https://support.google.com/a/users/answer/9018161?hl=ja
Endpoint Verification を設定すれば、管理者はデバイスに関する情報を確認し、現在地、デバイスのセキュリティ ステータス、その他の属性に基づいてアプリへのアクセスを制御できます。

組織の管理者は、Endpoint Verification を使用してデバイスによる組織のデータへのアクセスを制御し、デバイスの詳細情報を取得します。管理者が Endpoint Verification を使用するためには、お使いのパソコンに Chrome ブラウザ、Endpoint Verification 拡張機能、場合によってはネイティブ ヘルパー
アプリをインストールする必要があります。

https://www.njccloud.jp/2018/12/appschromeendpoint-verification.html
Endpoint Verificationを活用すると、
組織内で使用されているMacやWindows PC、Chromebookの端末情報や状態を、自動で収集し管理できるようになります。
【GCP】Cloud Identityとは

https://www.apps-gcp.com/cloud-identity/
GCP のログインユーザーを作成する
統合管理する

https://cloud.google.com/blog/ja/products/identity-security/cloud-identity-manage-users-devices-and-apps-one-location
https://cloud.google.com/identity?hl=ja
http://www.tech-joy.work/article/464263812.html

できることは以下
https://support.google.com/cloudidentity/answer/7431902
oak のサンプル (POST の処理）

次のプログラムを改造して POST の処理をするようにしました。
[oak のサンプル (その２)](https://qiita.com/ekzemplaro/items/a25c4201169d87ddc1b7)

```ts:oak_post01.ts
// ---------------------------------------------------------------
//	oak_post01.ts
//
//					May/20/2020
//
// ---------------------------------------------------------------
import { Application,Router } from "https://deno.land/x/oak/mod.ts"

const books = new Map<string, any>();
books.set("1", { id: "1", title: "それから", author: "夏目漱石", })
books.set("2", { id: "2", title: "夜明け前", author: "島崎藤村", })
books.set("3", { id: "3", title: "舞姫", author: "森鴎外", })

const router = new Router()
router
  .post("/", (context) => {
    context.response.body = "日本文学"
  })
  .post("/list", (context) => {
    context.response.body = Array.from(books.values())
  })
  .post("/book", async context => {
	const body = await context.request.body()
	context.response.body = books.get(body.value.key)
    })

const app = new Application()
app.use(router.routes())
app.use(router.allowedMethods())

console.log("*** start ***")
await app.listen({ port: 8000 })

// ---------------------------------------------------------------
```

実行方法

```bash
deno run --allow-net oak_post01.ts
```

総てのデータの取得

```bash
curl -X POST http://localhost:8000/list | jq .
```

key を与えてのデータの取得

```bash
curl -X POST -H "Content-Type: application/json" \
	-d '{"key":"1"}' http://localhost:8000/book
echo
curl -X POST -H "Content-Type: application/json" \
	-d '{"key":"2"}' http://localhost:8000/book
echo
curl -X POST -H "Content-Type: application/json" \
	-d '{"key":"3"}' http://localhost:8000/book
echo
```
【超絶爆速メモ】テクスチャをタイル状にたくさん置く

![x01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/f7acef62-8358-4bde-7a31-c896a17ebaac.png)
![x02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/1d9d829f-df0e-0e10-29a6-7428c9b6ebb7.png)
仕様書の作成時に気をつけたいこと

##はじめに
4月からエンジニアとして働き始めたひよっこです。現在所属にて開発の課題を進めている途中ですが仕様書の作成の際に勉強したことをメモ代わりにまとめておきます。自分で完結する開発したことしかなかったので"赤の他人が見てもわかるように"という視点が全く足りませんでした。次は今回勉強したことを活かして行きたいなと思います。
##仕様書とは
どのような機能をもたせるのか、どこからどのように遷移させるのかを明記したものをいいます。発注者が存在する場合は受注側と一緒に協議しながら書いていくことが多く、発注側の要件を満たすことが求められます。

##仕様書がなぜ重要なのか
仕様とは満たすべき要求事項のことを言います。満たすべきことを曖昧にした状態で開発を進めていくと発注側と受注側で認識に齟齬が生まれてしまいやすくなります。そういった誤解を解決するために作成するのが仕様書です。予め発注者側の要件に合わせて画面の仕様から機能の部分まで作り込むことによって工数の見積もりも立てやすくなりますし、急な変更などが起きづらくなるでしょう。

##仕様書づくりのポイント
###①全体像から詳細の説明でわかりやすい流れの設定
ものごとを説明する際にはわかりやすい順序というものがあります。１からものごとを説明する際には最初になんとなくで良いので全体像を説明しましょう。どんな流れで仕様書が書かれているのか、どんなwebアプリケーションなのかを最初に定義して、そこから画面の仕様や詳細な部分の説明をすることで読んでいる人は全体の中でどんな位置づけをしているのかをイメージすることができます。

###②画面設計に画像や図を使う
視覚的に理解するものを文字で伝えようとすると誤解が生まれがちです。なので画面を説明する際には積極的に図や画像を活用することで視覚的に理解できるようにしてみましょう。足りない部分を文字で補うような形で進めていけば、見る人も確認しやすくなります。

###③曖昧な部分は自分で判断しない。
仕様書の作成後に成約や機能については元も子もありません。要件について不明瞭なものについては積極的に確認、仕様書の時点で発注側と完成のイメージが共有できるようにしましょう。

###④言葉は正確に
作成中に私もやってしまいました｡
ex)この、その
を多用すると結局どの言葉を指しているのかが分かりづらいです。なるべく主語ははっきりと統一して使用するようにしましょう。

###⑤データベースの設計
例
データベース名：database_name<br>
テーブル名：table_name<br>

カラム名  |カラム説明  |データ型  |OPTION  |
---  |---  |---  |---  |

上記の4項目でまとめるようにします。NOT_NULLやDEFAULTについてはOPTIONで設定するようにします。カラム名やデータ型についてはデータベース設計については別の話になってくるのでOPTIONやデータ型については別途調べてみてください。

###参考文献
[エンジニア歴20数年の私が、設計書を書く際に心がけていること](https://qiita.com/y-some/items/90651c1e27f7798f87c6)
Gitの基本を5分で理解しましょう〜初心者向け〜

##はじめに

[Git](https://git-scm.com/)とは、一言にまとめるとアプリのバージョンを管理するツールの１つです。
（それ以外には、MercurialやSubversionがある）
新しいアップグレードをしてみたけど、１つ前の状態に戻したい。
そんなんときに役立つツールとなっています。

今回は、GUIの操作方法ではなくコマンドラインでGitの使い方を紹介します。
Gitのコミット方法については[こちら](https://qiita.com/daiki_tadokoro/items/d1a82e52a12169a1d213)で解説しています。
（GUIの使い方は[こちら](https://qiita.com/nakagawa1017/items/d831cbe21424e56d62a3)の投稿がとても参考になります。）


###Gitの必要性

Gitに限らずバージョン管理のツールを使うメリットは様々です。

・ファイルの変更時にバックアップが不要になる
・変更をしても戻れるので安心して作業できる
・複数人でファイルを変更できるので共同開発を行える

###Gitが保存する内容

Gitがファイルの変更に伴い、
下記の情報を保持して１つのバージョンとします。

・いつ
・誰が
・どのファイルの、どの箇所を
・どんなメッセージを残して変更したか

##GitHub(ギットハブ）ってなに？

GitHubとは、Gitを使って管理している情報を
オンライン上で共有や管理ができるサービスです。

例えば、BootstrapやjQuery、
Ruby on RailsもGitHubでチーム開発が行われている
オープンソースです。

##バージョン管理の方法

プログラミング言語を学んでいく中で、
聞きなれない用語も出てきますので１つずつ解説していきます。

###リポジトリ

リポジトリとはバージョンの”保存先”のことです。
リポジトリという箱をイメージし、
中にGit(バージョンの情報）を保管しているイメージと考えましょう。

リポジトリには2種類あります。

####ローカルリポジトリ

ローカルリポジトリは、自分の作業時に使われるリポジトリのことで
自分のPCやcloud9上で作られるリポジトリのことです。

####リモートリポジトリ

リモートリポジトリとは、ローカルリポジトリを
GitHub上に反映させたものになります。
チームでの共有やバックアップを目的として
ネットワーク先にあるリポジトリのことです。


###コミット

Gitでは、１つ１つのバージョンを”コミット”といいます。

コミットには様々な情報が入っているので重要な部分のみ紹介します。

　・リビジョン番号（1e92345894839f73489348cのような値）
　・コミットした人
　・コミットした日時
　・コミットした後と前のファイルの内容の違い
　・コミットメッセージ
　・親コミット（１つ前のコミットのリビジョン番号）

####リビジョン番号

リビジョン番号はIDのような役割と覚えておきましょう。

####コミットメッセージ

コミットメッセージは、コミット時に必要なメッセージです。

コミットが多くなれば、どんな変更があったのか
ファイルの内容を１つ１つ確認するのは手間です。
そこで、簡単なメッセージを書いておくものです。

####親コミット

親コミットとは１つ前のコミットのことです。
コミット時に１つ前のコミットのリビジョン番号を持っていることで
過去のコミット（親コミット）を辿ることができ変更履歴を管理できます。

###ワークツリーとインデックス

次に紹介するのは実際にコミットする際に
理解しておく必要があるワークツリーとインデックスについてです。

####ワークツリー

ワークツリーとは、Gitで管理されている自分が作業しているフォルダ内です。

ワークツリー（作業しているファイル）をコミットする際
フォルダ全てをコミットする必要はありませんので
変更箇所を選択することが必要です。

この変更箇所を選択することを"ステージする"といいます。

####インデックス

インデックスとは、ローカルリポジトリへコミットする前の中間地点です。
ステージングエリアともいわれる場所です。

ワークツリーからローカルリポジトリへコミットする際、
インデックスというエリアでコミットする変更箇所を選ぶ段階があります。

その後、コミットを行いバージョン管理が行えます。
コミットされる箇所はインデックスにステージされた変更箇所のみです。
つまり、リポジトリしたい箇所はインデックスにステージする必要があります。

##まとめ

なんとなくわかっていたつもりでも、
文字にして読むと改めて理解できたのではないでしょうか。

大まかなバージョン管理の流れは、ワークツリー→
インデックス→ローカルリポジトリと移動します。

今回の内容をまとめると以下になります。

　・コミットとは１つのバージョン
　・リポジトリには2種類ある
　・親コミットの情報のおかげで辿れる
　・インデックスへステージする必要がある

Gitのコミット方法については[こちら](https://qiita.com/daiki_tadokoro/items/d1a82e52a12169a1d213)で解説しています。
WordPress で、Snow Monkey Blocks のブロックを初期配置する

WordPressには、新規投稿にあらかじめブロックを初期配置しておく機能があります。(5.0から導入されたGutenberg活用が前提です)

![新規投稿時にブロック配置](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31643/acc59bb6-24dc-e8e4-035b-7aef60394ef5.gif)

(初期配置について詳しくは、[WordPressユーザーのためのPHP入門 はじめから、ていねいに。第3版](https://books.mdn.co.jp/books/3219203008/) p229-231を参照してください)

この機能は、WordPressのデフォルトで用意されているブロックだけでなく、テーマやプラグインの独自ブロックにも適用できます。

## アコーディオンブロックを置いてみる

試しに、[Snow Monkey Blocks](https://wordpress.org/plugins/snow-monkey-blocks/) のアコーディオンブロックを置いてみました。

![newpost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31643/e1c0653d-8c95-0781-a17b-eaaf826f78f5.png)

置いたブロックは、
 1. 見出しブロック - 「あらすじ」という文字列を初期設定する
 2. 段落ブロック
 3. アコーディオンブロック - 「ネタバレ」という文字列を初期設定する

です。見出しと段落はWP標準のブロックで、アコーディオンは Snow Monkey Blocks です。

### コード例

書いたコードは以下のようになります。

```PHP
$post_type_object->template = [
		[
			'core/heading',
			[
				'level'   => '2',
				'content' => 'あらすじ'
			]
		],
		[
			'core/paragraph',
			[
			]
		],
		[
			'snow-monkey-blocks/accordion--item',
			[
				'title'   => 'ネタバレ',
			]
		],
]
```

フックなどの詳細は[WordPressユーザーのためのPHP入門 はじめから、ていねいに。第3版](https://books.mdn.co.jp/books/3219203008/) でご確認ください。

### ブロック名はどうやって調べる？

↑のコードでは、``core/heading`` 等の名前で、ブロックを指定しています。ではこのブロックの名前はどうやって調べたらよいでしょうか？

WordPressのデフォルトのブロックは、[WordPressのデフォルトのブロック一覧](https://php4wordpress.calculator.jp/gutenberg/blocklist/)ページで名前を確認できます。

テーマ・プラグインの場合は、作者のウェブサイトやソースコードなどで確認します。Snow Monkey Blocksの場合は、ソースコードを読んでいくと https://github.com/inc2734/snow-monkey-blocks/blob/master/block/accordion/block/item/index.js#L11 ``snow-monkey-blocks/accordion--item`` という名前であることが分かります。
また属性は https://github.com/inc2734/snow-monkey-blocks/blob/master/block/accordion/block/item/attributes.json を見ると ``title`` と ``initialState`` が設定できることが分かります。

### 複数人で記事を書くときに便利

ブロックを初期配置する機能を使うと、記事フォーマットの統一化、入力作業の手間削減などに使えます。

さらに、複数人で記事を書くときに便利です。[ブックレコメンド](https://book-recommend.com/) では、寄稿者に下書きを作成してもらうことがあるのですが、そのようなときに重宝します。
Bluetooth認証のQDID Product Typeについて

# QDID Product Typeとは？

* Bluetoothを組込んだ製品を売る場合にはBluetooth SIGの認証が必要。
* なので「Bluetoothモジュール選びにはBluetooth認証が通っているか(QDIDが存在するか？)」が大事になる
* QDIDはQualified Design IDの略で、Bluetooth認証を取得するとBluetooth SIGから貰えるIDです(Bluetooth認証済みの証明になるものです)
* それだけじゃなくProduct TypeによってEPL登録（End Product Listing）のやり方が変わる

下記を参照

Bluetooth認証のQDIDとは？Bluetoothモジュール選びの際はQDIDとProduct Typeに要注意
https://musenka.com/bluetooth/howto/qdid-product-type/


# どんなProduct Typeがあるのか？

Product TypeにはEnd Product(最終製品)やComponent(部品)だけでなく他にもController SubsystemやHost Subsystem、Profile Subsystemなどがあります(下記参照)

+ End Product
+ Component
+ Controller Subsystem
+ Host Subsystem
+ Profile Subsystem

じゃぁそれぞれの違いは何？と思って調べてみたがEnd ProductとComponent以外の違いを書いている記事はありませんでした。
仕方なく英語の記事を探してみると、ジャストミートな記事を発見しました。
しかもすごくわかりやすい。
下記に元ソースと一緒に記載しておきます（Google翻訳かけただけだけど）

# 各Product Typeについての説明

（元ソース）What is the difference between component and EPL in product type? 
https://www.silabs.com/community/wireless/bluetooth/forum.topic.html/what_is_the_differen-RqBN

Bluetooth認定には、End Product(最終製品）、Subsystem(サブシステム)、Component(部品／コンポーネント)、の3つの主要なカテゴリがあります。
SubsystemとComponentのカテゴリはサブカテゴリに分類できます。

## End Product
Bluetoothテクノロジーの機能を実装した市場で販売されているすべての製品は最終製品として認定され、
SIGが管理する市販製品のディレクトリにリストされている必要があります。
最終製品は、独立して機能するBluetoothデバイスである場合があり、たとえば、Silicon Labs BGM111は最終製品として認定されています。
最終製品は、少なくとも認定済みのHostとController Subsystemに基づいている場合（さらにProtocol/Service/Profileに関連するサブシステムを含む場合があります）
または認定済みのテスト済みコンポーネントに基づいている場合組み合わせて、独立して機能するBluetoothデバイスに必要なレイヤーをカバーします。

サブシステムには、Controller Subsystem、Host Subsystem、Profile Subsystemの3つのサブカテゴリがあります。

## Controller Subsystem
Controller Subsystemは、最終的に補完的なHost Subsystemと組み合わせて、操作に必要な完全なBluetoothコアアーキテクチャを作成する必要があります。
Controller Subsystemは、たとえば、通常はBluetoothスタックの標準化されたHCIソフトウェアおよびハードウェアインターフェイスの下にある、RF-PHYおよびリンク層の実装を含むUSB商用Bluetoothドングルです。

## Host Subsystem
Host Subsystemは、最終的には補完的なController Subsystemと組み合わせる必要があります。
Host Subsystemは、たとえば、OS自体またはサードパーティによって提供される、オペレーティングシステムで実行されているBluetoothスタックおよびアプリケーションソフトウェアです。

## Profile Subsystem
Profile Subsystemは、最終的に補完的な最終製品またはHost Subsystemと組み合わせる必要があり、たとえば、採用されたBluetoothプロファイルの1つ以上を実装する製品拡張アプリケーションになる場合があります。
Profile Subsystemは、最終製品のリストを取得するために必須ではありませんが、採用されたProfileとの互換性を保証および実証するために使用できます。

## Component
認定コンポーネントの設計には、最低限のレイヤーサポートがありません。
それらは任意の層または層の組み合わせで作ることができます。
一緒に、またはサブシステムと組み合わせたコンポーネントは、新しい最終製品またはサブシステムの認定設計を作成するために必要な部品です。
認定コンポーネントは通常、RF-PHYレイヤーなどの特定のレイヤーです。
これらの認定レイヤーは設計で使用でき、テストを再実行する必要はありません。

![cb5e6c97-30e3-4985-9234-1cc77e676bf7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112253/a07e8c48-80f4-39b0-225a-06175c168653.png)
MindSphere/Cloud Foundryでカスタムエラーページを利用する方法

# 概説
MindSphereまたはCloud Foundryでカステムエラーページにリダイレクトする方法について説明します。

# Staticfileを作る
`index.html`などがあるディレクトリに`Staticfile`というファイルを作ります。
中身は以下のようにしてください

```yaml:Staticfile
status_codes:
  404: /404.html
  403: /403.html
```

これでNot Foundになると404.htmlにリダイレクトしてくれます。

# pathでpush
manifest.ymlのpath要素を利用して、例えば`dist`以下のファイルをpushするときがあります。
このときはdist内に`Staticfile`を入れましょう。ルートに置いても変化はないかと思います。
新しくなったStripeのCheckoutスニペットジェネレータがでない時

2019年にリニューアルされたCheckoutはクライアントサイドのみの実装であれば導入がJavaScriptのコードをどこかのHTMLに貼り付けるだけで超簡単なのだが、そのCheckout機能を有効化しないとコードスニペットが出てこないという罠にハマった。

<img width="200" alt="IMG_0394.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/05e47d67-7690-9ea0-c26f-645dd8a71ae3.png">
入力フォームも洒落乙になった。

##公式リファレンス
https://stripe.com/docs/payments/checkout/client
英語だけどこれを見つけられれば早い。ググってもレガシー版のリファレンスばかりがでてきた。

##新しいCheckoutのやり方
https://qiita.com/kskinaba/items/2ba42eda07227a9b96d5
基本は上記に従うが画像つきで説明する。`商品の設定`＞`Checkoutの設定`に行く。

<img width="1118" alt="スクリーンショット 2020-05-20 12.04.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/83adc381-0d75-2b21-f258-549b4bf01a31.png">

クライアント専用組み込みを有効にする。
<img width="1126" alt="スクリーンショット 2020-05-20 11.59.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/20dfabae-017b-4392-b260-0a660a79ee9d.png">

すると左側に商品メニューがでるので商品を作成する（本番とテストで商品は別扱いとなることに注意）
<img width="1393" alt="スクリーンショット 2020-05-20 12.02.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/76ebbbf7-0b66-f728-f704-fae1536546a1.png">

作成した商品の中のSKUごとに`Checkoutで使用`というボタンが出る。
<img width="1110" alt="スクリーンショット 2020-05-20 14.06.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/82ec60ff-6d1e-26c3-3ea7-05098c5dd1b1.png">

これを押して出てくるJavaScriptコードを任意のWebページに貼り付けてやれば、あとはよしなにやってくれる決済ボタンが表示される。ちなみに商品とSKU（購入情報）を混同しないように注意。

##補足
[レガシー版のCheckoutのドキュメント](https://stripe.com/docs/legacy-checkout/rails)ではRails向けに書かれていたのに、[新しい版のサーバーサイドも開発するドキュメント](https://stripe.com/docs/payments/checkout/accept-a-payment)ではRubyのコードとしてしか書かれていいないので、初心者からすると「ProgateでRailsはやったけど純粋なRubyのコードだけ見せられてもわけわからん…」となって結構ハードルが高い印象。


##その他の参考記事
###Railsでのやり方
https://qiita.com/roadfox303/items/b93e440c10af82bda7bd

###レガシー版のRailsでのやり方
https://qiita.com/disk131/items/8381f35be9c70bd7b9e2
ただしURLの`:id`の取得をうまくしてくれずルーティングがうまくできませんみたいなエラーが出た。
[Python] if 文

## if文
注意点
・条件式の後に **:**
・else if　は **elif**
・条件式左右等しい時は **==**

```python
if money > total_price:
    print("りんごを" + str(count) + "個買いました")
    print("残金は" + str(money - total_price) + "円です")
elif money == total_price:
    print("りんごを" + str(count) + "個買いました")
    print("財布は空になりました")
else:
    print("お金が足りません")
    print("りんごを買えませんでした")
```
###条件式組み合わせ
**and**
どちらの条件も満たす

```python
if time > 10 and time < 15:
```

**or**
どちらか一方の条件を満たす

```python
if time == 10 or time == 15:
```

**not**
条件の否定

```python
if not time == 20:
```
# 比較演算子
jsと違い左右が等しい時の＝の数などが変わる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636508/1bb0d662-3442-e387-ba6f-4f22eedb7a79.png)
git まとめ

## HEAD
現在使用しているブランチの先頭を表す名前で、デフォルトではmasterの先頭を表している
## stash
ファイルの変更内容を一時的に記録しておく領域
stashを使うことで、ワークツリーとインデックス中でまだコミットされていない変更を一時的に退避させることができる
退避させた変更は後から取り出して、元のブランチや別のブランチに反映させることができる
Python論理演算の躓き

## Pythonのbool
前提として，Pythonでは0や空じゃないものはbool値がTrueになる.

```python
bool(0) # False

bool(0.1) # True

bool("") # False

bool([""]) # True
```

逆に，TrueとFalseは1と0と同じように演算ができる．

```python

True*1 # 1

False*1 # 0

True+0 # 1

True+True # 2
```

## 論理演算

Pythonに限った話ではないが，andとorは両辺を短絡評価している．

```python
True and False # True

print("a") or print("b")
# a
# b

1 and print("b") # b
```

そしてPythonの論理演算は**結果がboolに限らない．**

```python

100 and 200 # 200

200 and 100 # 100

100 or 200 # 100

200 or 100 # 200
```

and，orではなく&，| を利用するとビット演算になる．

```python
True & False # False

True & 1 # 1

True & 2 # 0

123 & 125 # 121
```
IOSTコントラクト キャッシュ機構を用いたgasの削減

# 目的

storageAPIはgasの消費量が多いため(300gas)，同じkey, field の値を何度も参照したり変更する場合は，putやgetの回数を極力減らしたい．

# 着想

最も削減できる手段はコントラクトの最適化を行う事だが，ある程度の規模を超えてくるとコーディングが大変になる．そこで，storage API のラッパーを実装してgasの削減を目指した．

# 概要

storage情報にアクセスしたらその情報をキャッシュに保存．以降のアクセスはstorageではなくキャッシュに行う．
変更が行われると，そのkeyとfieldを記録する．
トランザクション処理の最後に，変更があったキャッシュの内容のみをstorageに反映する．

# 実装

```js
const state = (function () {
  const _cache = {};
  const _modified = {};
  function get(key, field) {
    if (typeof _cache[key] === "undefined")
      _cache[key] = {};
    if (typeof _cache[key][field] === "undefined")
      _cache[key][field] = storage.mapGet(key, field);
    return JSON.parse(_cache[key][field]);
  }
  function exists(key, field) {
    if (typeof _cache[key] === "undefined")
      _cache[key] = { [field]: storage.mapGet(key, field) };
    else if (typeof _cache[key][field] === "undefined")
      _cache[key][field] = storage.mapGet(key, field);
    return typeof _cache[key][field] === "string";
  }
  function require_exists(expect, key, field) {
    if (expect !== exists(key, field))
      throw `property_exists_expect_${expect}: ${key}, ${field}`;
  }
  function init(key, field, value) {
    require_exists(false, key, field);
    _cache[key][field] = JSON.stringify(value);
    if (typeof _modified[key] === "undefined")
      _modified[key] = [field];
    else if (_modified[key].indexOf(field) === -1)
      _modified[key].push(field);
  }
  function update(key, field, value) {
    require_exists(true, key, field);
    _cache[key][field] = JSON.stringify(value);
    if (typeof _modified[key] === "undefined")
      _modified[key] = [field];
    else if (_modified[key].indexOf(field) === -1)
      _modified[key].push(field);
  }
  function remove(key, field) {
    require_exists(true, key, field);
    _cache[key][field] = null;
    if (typeof _modified[key] === "undefined")
      _modified[key] = [field];
    else if (_modified[key].indexOf(field) === -1)
      _modified[key].push(field);
  }
  function merge() {
    for (const key in _modified)
      for (const field of _modified[key])
        if (_cache[key][field] === null)
          storage.mapDel(key, field);
        else
          storage.mapPut(key, field, _cache[key][field]);
  }
  return { get, exists, require_exists, init, update, remove, merge }
}());
```
急に家のネットが繋がらなくなったけど直せた。DNSの問題だった

# 概要
- 急に家のネットが繋がらなくなった
- モバイルルーターのLEDはオールグリーン
- ping 8.8.8.8は通る
- ping google.comはタイムアウト
- DNSを自動から手動にし、プライマリーを8.8.8.8、セカンダリーを8.8.4.4にしたら直った
- Windows 10とiPhoneと両方設定した

# 発端
リモートなので自宅のインターネットで仕事をしている。
朝ひと仕事して、焼肉ランチを食べに行き、帰宅して午後の仕事に掛かったところで、ネットに繋がらなくなった。
具体的に言うと、

- Webで検索してもgoogle.comというサイトが見つかりませんと言われる
- Slackも新規メッセージが取得できない
- WiFi経由でiPhoneを使っても同じ状態
- Windows 10のネットワークの状態を見ると、インターネット接続中と表示されている
- iPhoneのWiFiも接続されている

# 相談窓口に電話 -- 応答なし
自宅のインターネットはNTT東日本フレッツ光、ぷららを使っている。
レンタルルーターにAirMac Extremeをつなげ、そこから有線でPC、WiFiでiPhoneを使っている。

ここでフレッツの故障相談に電話した。
すでに契約しているユーザーの窓口[1]を押した。
保留音声が流れたので時刻を確認。
12:42。
# ハードの状態チェック -- 問題なし
AirMac Extremeの電源を抜いて入れたが緑点灯（正常）になるだけで問題なかった。

レンタルルーターはPR-400MIという型番。
iPhoneをモバイル回線（イオンモバイル）に繋いで「PR-400MI ランプ」で検索したら偉いものでランプの見方をまとめたブログに当たった。

http://ezxnet.com/ntt/entry13147/

電源を抜いて入れたがすべて正常に通信中。

また、念の為AirMacを飛ばしてレンタルルーターに直付けでノートパソコンを有線接続したが状況は変わらなかった。
# pingは通るけど外部サイトが見られない状態
Windowsでcmd.exeを起動。
ipconfigを実行するも特に問題は見つけられず。
ここで
`
C:\> ping 8.8.8.8
`
と入力するとちゃんと応答が帰ってきた。
8.8.8.8はGoogleの公開DNSサーバーだ。
つまりネットワーク通信はできている。
しかし、
`
C:\> ping google.com
`
だとタイムアウトになる。
つまりフレッツのDNSが死んでいるのであろう。
# DNSの再設定 -- Windows編
携帯回線でサイトを渉猟したが、「そもそもインターネットとは何でしょう」みたいなゴミ情報の末に「ちゃんと電源を入れてますか」「一回落として再起動してみましょう」「ファイアーウォールは動いていませんか」「最後の手段はサポートセンターに電話」みたいなことしか書いてない、クソみたいなまとめサイトがゴッチャリで辟易した。

結局「Windows DNS 手動」で以下のサイトに当たった。

https://did2memo.net/2018/04/06/windows-10-dns-8-8-8-8/

簡単に言うと、

(1) Windowsアイコン（田）＝＞設定キー（⚙）
(2) ネットワークとインターネット＝＞アダプターのオプションを設定する
(3) イーサネットを右クリック＝＞プロパティ
(4) インターネット・プロトコルバージョン4＝＞プロパティ
(5) 次のDNSサーバーのアドレスを使う
(6) プライマリー＝＞8.8.8.8
(7) セカンダリー＝＞8.8.4.4
(8) OK、閉じる

これで google.comにpingも通り、インターネットが正常に動作した。
# Windows設定の落とし穴
Windows 10の設定画面は、フラットデザインの青いやつと、Windows 7時代のままのスキューモーフィズムのやつがある。
最近のMicrosoftは、入り口だけフラットデザインの新UIで、急に途中からスキューモーフィズムの旧UIになる間抜けなパターンが多い。
上の作業でいうと(2)までは新UIで、(3)からは旧UIだ。
と、参考にしたブログには書いているが、いつまでたっても(3)の画面に遷移しなくて焦った。
結果は、ぼくが間抜けで、うちがマルチディスプレイ環境なので、(2)までと別のディスプレイに(3)の画面が出ていたのだ。
恥ずかしくも腹が立つ。

なお、IPアドレスを手打ちするときは、たとえば1.2.3.4と打つ時、1を打った後にタブを押してもうまくいかない。
別のUIにフォーカスが遷移してしまうのだ。
この場合、1ドット2ドット……と打つのが正しい。
（数字を打ったらピリオドを打つ）
Windows 95時代に身につけたワザだが、25年ぶりに使う日が来た。
# iPhoneの設定
iPhoneのDNSも手動で設定できる。
最近のGoogleは、検索するだけで一番役に立ちそうなサイトの情報を抜いて表示してくれる。

https://www.google.com/search?q=iPhone+DNS+%E5%A4%89%E6%9B%B4&oq=iPhone&aqs=chrome.0.69i59j69i57j0l5j69i65.3912j0j4&sourceid=chrome&ie=UTF-8

以下引用

(1) 設定 > Wi-Fi.
(2) 接続しているWi-Fiネットワークをタップ
(3) DNSを構成
(4) 手動
(5) サーバーを追加から「1.1.1.1」「1.0.0.1」を追加
(6) 元からあるDNSサーバーは削除する
(7) 保存

補足すると、(2)はネットワーク名の右横の(i)アイコンをタップする。
また、(5)では8.8.8.8と8.8.4.4を入力した。
# 解決
この時点で13:10。
28分間陽気な保留音を聞いていたが、結局フレッツのサポセンの出番はなかった。
2020-05-20のお昼、フレッツのDNSサーバーが落ちていたようだ。

**（この項終わり）**
初級試験テスト　１−２

I
1 c 
2 a
3 d
4 d (c)：phpは、CGIサポート以外のサーバが動作するできない
5 b
6 c
7 b
8 c (d):見間違い！
9 d

II
1 c
2 c
3 c(b)： 「%.1f」は5より小さいのを切りすで
4 a
5 c(b)：ucwordsは最初文字大文字にする，strtolowerはすべて小文字にする
6 d
7 d
8 b(b,e)：「-」は変数の中に含められない
9 a,c(c,d)：「==」は大小文字を区別する、strcasecmpは区別しない
10 b
11 c(d): 返り値：a++ -> a ; ++a -> a+1; ただ、a = a+1になる

III
1 a,d,e
2 b
3 a
4 e(c): ‘abc’ < ‘xyz’
5 a
6 b
7 ?(b): 「<=>」が 「strcmp」と同じ，例えば：　s1<=>s2に関して、s1 > s2 で正の値、s1 < s2 で負の値、s1 = s2で 0 を返す。この大小関係は一般に文字コード順による。
8 c
9 紙欲しい　e(c)　計算間違い
10 b

IV
1 d
2 ?(e)：a[] = 10; 要素ごとに1ずつ追加する
3 d
4 b(a)：配列のメモリ、追加「array_splice」、添字省略、ハッシュ知識不足！
5 a(b) : キーは数字でも可能　1, 2, 4, 3なら　順番はそのままで、キーは1、2、4、3となる
6 b(d)：asort, sort, ksort, rsort, arsort, krsort
7 d(b)：見間違え
8  c(b)：関数　count, explode, implode, unset, in_array, array_key_exist, array_search, array_reverse, array_splice 　
9 d
10 d, e

V
1 d
2 a,e(a,b)：関数名呼び出す際に大文字小文字区別しない
3 c
4 c(a,c)：関数の引数をデフォルトで設定しでも、設定した値を優先する、デフォルト引数は、値を設定しなかった時用
5 a(c)：return複数設定することが出来るが、最初の時の設定で値を返す。かつ、returnは一つの値にしか返さない。
6 a
7 ?(a)：スコープ変数、有効範囲
8 ?(a)：$GLOBAL, $GLOBALSが存在する、前者はグローバル変数を扱う、後者は、グローバル変数を配列に格納する用
9 ?(d) : スコープ変数、有効範囲 : 関数内部globalを使うと、有効範囲を関数外に拡大する
10 ?(e)

VI
1 d (c) : クラスー　オブジェクトでインスタンスを作られる；メソッド：操作function; プロパティ：データ変数
2 d (b)　：　インスタンス　new Obj();
3 c
4 c
5 e (a) : try catch : catchブロックに移すと　その次のプログラムを実行しなくなる
6 a d (d,e)　：　public : すべて，protected：継承クラス自身クラス親クラス，private: 自身の身
7 c
8 ? (b)：namespace, use. foo\bar\one::two()
if文の書き方宗教、推奨、怖




C++でif文推奨する。
しかし、感情的対立は生まれてしまう。
これは絶対ではない。だからお互いに許しあうしかない。
自動整形でもこうすると言う方向で。

推奨。
ブロックで囲む。

```c++
if (cond)
{
  return;
}
```
　利点：
処理を後から追加しやすい。
もしブロックがなかったら、それを付ける所から始まる。
ブロックをつけないと言うことは、ブロックをつける作業を相手に押し付ける行為である。

--
ダメな例。
ダメと言うと、反感と感情的対立が生まれてしまうのでダメとは言わない。

```c++
（1）
if (cond) return;

（2）
if (cond)
  return;
```
　理由：
（1）
・ブレークポイントは1行単位でしか付けられない。スクリプトとは違うので。（将来に期待）
なので分かりづらい。
リターンならステップすれば分かるだろうけど、ステップする事すらめんどくさいので。
・これが共有してるコードの場合は、改行すると差分が出てくるので戻すのがめんどくさい。
（2）
・ブロックがないと処理を一つ追加する際にブロックをつける作業が発生する。めんどくさい。
・あと分岐処理は重要ポイントなので、コードの自己主張が強い方が見やすいです。

---

その他。
関数の先頭にまとまっている 条件比較してのreturn; などは、
この関数の実行条件であると言う意図と、内容即座に理解できるならスルーする。

```c++
int SLogic(int num)
{
  if (cond1) return;
  if (cond2) return;

  ~~statement~~
  ~~statement~~
}
```

個人的に特に嫌な例。
見逃しやすい感じになるから。見ていけば分かるとしても、最初から見やすくしておいた方が時短になるため。

```c++
int SLogic(int num)
{
  ~~statement~~
  if (cond)
  {
    ~~statement~~
    if (cond2) ~statement;　//< 見逃す。　林に隠れた一本の木を見逃す感じ。
    ~~statement~~
  }
  ~~statement~~
}
```


ヌルチェックについて

```:c++
（1）
if (view) 
{
  ~statement~
}
return;

↓

if (view == nullptr)
{
  return;
}
~statement~

（2）
if (view != nullptr)  
↓
if(view)
```
理由：
（1）
特にifのネストを減らす効能があるので良い。
nullということはその後の処理が出来ないパターンが多い、であれば即時returnを書く方が分かりやすい。処理を書いてからreturnが書かれてるよりは。

（2）
`!=`を書いてnullptrか明記するのは不要に思う。ポインタ型なら`nullptr`かそれ以外かという判定しかないため。
ただし、`if (view == nullptr)`は明記する意味があると思う。`!view`とかくよりは見やすいため。
JavaScript: オブジェクトからundefinedを取り除く関数

JavaScriptのオブジェクトから、値が`undefined`なフィールドを取り除く関数です。


## オブジェクトからundefinedを取り除く関数


```js
function removeUndefinedFromObject(object) {
  return Object.fromEntries(
    Object.entries(object).filter(([k, v]) => v !== undefined)
  )
}
```

実行例

```js
console.log(
  removeUndefinedFromObject({
    a: undefined,
    b: 0,
    c: "",
    d: null,
    e: { e1: undefined, e2: 1 },
  })
)
//=> { b: 0, c: '', d: null, e: { e1: undefined, e2: 1 } }
```


## 注意事項

### 再帰的にはチェックしません

上の実行例で分かるように、ネストしたオブジェクトのプロパティはチェックされません。

### 対応バージョン

ES2017とES2019に未対応の環境では下記関数が動作しません:

* `Object.fromEntries` - ES2019
* `Object.entries` - ES2017

必要に応じてpolyfillを当てて下さい。
JavaScript 連番数値配列([0,1,2]や[3,5,7]や[-5,-4,-3])作成

# コード

```js

const createArray = (start, end, increment = 1) => {
  if (increment === 0) {
    throw new Error(`Error createArray args increment is 0`);
  }
  const result = [];
  if (start <= end) {
    for (let i = start, l = end; i <= l; i += increment) {
      result.push(i);
    }
  } else {
    for (let i = start, l = end; i >= l; i += increment) {
      result.push(i);
    }
  }
  return result;
}

// Operation check
console.log(createArray(0,4,1));    // [ 0, 1, 2, 3, 4 ]
console.log(createArray(0,4,2));    // [ 0, 2, 4 ]
console.log(createArray(2,4,1));    // [ 2, 3, 4 ]
console.log(createArray(2,5,2));    // [ 2, 4 ]
console.log(createArray(2,6,2));    // [ 2, 4, 6 ]
console.log(createArray(2,10,3));   // [ 2, 5, 8 ]
console.log(createArray(2,11,3));   // [ 2, 5, 8, 11 ]
console.log(createArray(2,12,3));   // [ 2, 5, 8, 11 ]
console.log(createArray(2,13,3));   // [ 2, 5, 8, 11 ]
console.log(createArray(2,14,3));   // [ 2, 5, 8, 11, 14 ]
console.log(createArray(14,2,-3));  // [ 14, 11, 8, 5, 2 ]
console.log(createArray(13,2,-3));  // [ 13, 10, 7, 4 ]
console.log(createArray(12,2,-3));  // [ 12, 9, 6, 3 ]
console.log(createArray(11,2,-3));  // [ 11, 8, 5, 2 ]

console.log(createArray(0,0,1));  // [ 0 ]
console.log(createArray(0,0,2));  // [ 0 ]
console.log(createArray(1,1,1));  // [ 1 ]
console.log(createArray(1,1,2));  // [ 1 ]
console.log(createArray(-4,1,2)); // [ -4, -2, 0 ]
console.log(createArray(-4,0,1)); // [ -4, -3, -2, -1, 0 ]

```

# 参考

連番の数字の配列を作成（es2015 ver) - Qiita
https://qiita.com/sakymark/items/710f0b9a632c375fbc31

JavaScriptで[ 0, 1, 2, 3, 4 ]のような連番の配列を生成する方法 - Qiita
https://qiita.com/suin/items/1b39ce57dd660f12f34b

JavaScriptで[ 0, 1, 2, 3, 4 ]のような連番の配列を生成する僕のやり方 - Qiita
https://qiita.com/leak4mk0/items/38529321f797ef8a2bd3

jsでrange関数をつくる - Qiita
https://qiita.com/akameco/items/a2b698dd4a067754997b

JavaScriptでrange関数作ってみた - Qiita
https://qiita.com/RyutaKojima/items/168632d4980e65a285f3

Javascriptでrange()みたいに指定長の配列を生成 - 動かざることバグの如し
https://thr3a.hatenablog.com/entry/20190413/1555134381

指定した範囲の整数配列の作り方 in JavaScript ES6 - 無駄と文化
https://blog.mudatobunka.org/entry/2015/10/31/222750

# 感想
検索しても Array.from とか、スプレッド構文とか、map とか可読性低いパズルプログラミングを追求してしまう人多い。これじゃあ、初心者が変なJavaScriptを覚えてしまうわけだ。

開始終了の変更とかincrement値の変更とか、start end の逆とか、0値のエラー排除とかの対応、パズル構文だと難しくて対応できない。そういえば整数だけじゃなくて実数もあった。(たぶん上記コードは対応してると思う)

実用的なのはパズル記述ではなく、コード可読性が高く変更容易性が高く機能が豊富だったりとかそういう部品であって、内部実装なんてどうでもいいことです。
🐨コアラでもわかるSplunkシリーズ　ログに書いている値で集計する

やあ、みんな　:koala:だよ

:koala:いつもの作者は「:koala:の記事もわかりづらいですね」と言われて凹んだので、僕が呼ばれたよ。よろしくね。 

:koala:今回はちょっと初心に戻って、ログに書いている値で集計してみるよ

Macosxで動かしているので、WindowsやLinuxの人はディレクトリやフォルダを読み替えてね。

#今回使うもの
<img width="1392" alt="スクリーンショット 2020-05-11 20.31.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/3592e332-a36f-139b-ab44-b1e2c997f313.png">
:koala:今回は、この起動した時のそのままの画面を使用するよ。
真っ黒い背景にSPL（エス・ピー・エル）を書いていくので、それを<font color="red">**赤枠**</font>の中、`ここにサーチを入力．．．`と書いているところにコピー＆ペーストしてもらって、🔍をクリックすると動くよ

:koala:時間:`過去２４時間`やモード:`スマートモード`は変更しないでね

#ログに書いている値で集計する。
##その１
```sql:aggregate_words.spl
index=_internal TERM("SUCCESS") OR TERM("ERROR")
| eval status=case(searchmatch("SUCCESS"),"SUCCESS",searchmatch("ERROR"),"ERROR",true(),NULL)
| stats count by status
```

|status|count
|:-:|:-:|
|ERROR|16
|SUCCESS|26

:koala:[searchmatch()](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/ConditionalFunctions#searchmatch.28X.29)は

>この関数を使用して、検索文字列 (X) がイベントに一致した場合に TRUE を返します。

なので、文字列だよ。`match()`と違って正規表現じゃないよ。
##その２
```sql:aggregate_words2.spl
| tstats count where index=_internal TERM("status") by PREFIX("status=") sourcetype
```

status=|sourcetype|count
|:-:|:-:|:-:|
skipped|scheduler|4
success|scheduler|25

:koala:Splunkの一番新しいのを使っていると、こんなこともできるよ。

:koala:`TERM()`も`PREFIX()`もログに書かれている文字列で検索しているんだ。

:koala:詳しくは[TERMはこっち](https://docs.splunk.com/Documentation/Splunk/ｌａｔｅsｔ/Search/UseCASEandTERMtomatchphrases)なんだ。意外と使いづらいけど、使えるときは使ってね。

:koala:[PREFIXはこっち](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Tstats#Use_PREFIX.28.29_to_aggregate_or_group_by_raw_tokens_in_indexed_data)だよ。[これ](https://docs.splunk.com/Documentation/Splunk/latest/Search/Eventsegmentationandsearching)も読んでみてね。
##その３
```sql:aggregate_words3.spl
index=_internal TERM("SUCCESS") OR TERM("ERROR")
| rex "(?i)(?<status>success|error)"
| stats count by status sourcetype
```
status|sourcetype|count
|:-:|:-:|:-:|
ERROR|splunk_web_service|2
ERROR|splunkd|7
ERROR|splunkd_ui_access|4
SUCCESS|splunkd_ui_access|27
error|splunk_web_service|4
success|scheduler|25
success|splunkd|1
:koala:正規表現でその文字を抽出してフィールド名をつけてあげているよ。

:koala:意外と思いつかないけど、集計するには便利だよ。

#まとめ
:koala:いくつかの方法を説明してきたけど、大丈夫だよね？

:koala:検索したときに使ったキーワードで数を数えるのって、意外と困るときがあるかもしれないけど、どれかの方法を使ってみてね

:koala:じゃ、またね〜

:koala:リクエストまってま〜す
【C#】 short型のerror CS0266について

##自己紹介
こんにちは。tetraです。
最近C#の学習を始めました。C#歴2ヶ月目の新卒エンジニアです。

##error CS0266について
学習課題としてコードを書いていた時にハマったポイントについて
Tipsを書いていこうと思います。

##発生例
簡単な例として、以下のようなコードを書きます。

```CSwork.cs
// x + y を計算するコード
using System;
public class main
{
    public static short calc(short x, short y)
    {
        return x + y;         //error CS0266
    }
    public static void Main()
    {
        Console.WriteLine(calc(1, 2));
    }
}
```

この場合、**short型で宣言しているにもかかわらず、int型で処理されてしまいます。**

##解決法
これの処理の仕方を以下のコードで書きます。

```CSwork2.cs
// x + y を計算するコード
using System;
public class main
{
    public static short calc(short x, short y)
    {
        return (short)(x + y);         
    }
    public static void Main()
    {
        Console.WriteLine(calc(1, 2));    //3
    }
}
```

どうでしょうか？変わっていないですか？
よくみてください。
**calc関数のところがカッコ（）で囲まれshort型として明示的に書かれています。**

これをキャストといい、変換できないものを強制的に変換する際使用します。
この場合、大きいものから小さいものに無理やり変換するので、データが損失する恐れがあります。

こうすることによって、short型の戻り値を持つ関数を処理することができるようになります。


##いかがでしょうか？
いかがでしょうか。経験が浅いため至らぬところがまだまだあります。
もし間違い等に気がつきましたら、コメント又は[tetra](https://twitter.com/_T_E_T_R_A_)までお知らせください。
1コマンドでjupyter環境を立ち上げたい

## はじめに

Python環境を構築していない人に、「Jupyter開いてみて！」ってお願いすることがまれにあります。

そのときに、

* pyenvのinstall
* python3のinstall
* pandas, Jupyterのinstall

などをお願いするのがとてもしんどいです。(たまに意図しないエラーでることもあるので)

## Dockerを使おう！

Dockerが入っている前提ですが、Dockerが入っていれば1コマンドで立ち上がります

※ macOSの場合、Dockerのinstallはこの記事あたりを参考に！brewですぐinstallできます

[Homebrew で macOS に Docker をインストールして Hello world](https://qiita.com/niwasawa/items/c8cfe350caa9f4730400)


### DockerでJupyterを立ち上げてアクセスする方法

Dockerのimageは
https://hub.docker.com/r/jupyter/datascience-notebook/ 
から拝借します。pandasなど必要なライブラリがほぼ入っているので、容量は食うもののストレスレスで分析・描画できます。

以下Usage.

* DockerでJupyterを立ち上げ．(http://localhost:9999 にアクセスすればJupyterみれる )

```sh
docker run -d --name notebook -v $PWD:/home/jovyan -p 9999:8888 jupyter/datascience-notebook
```

* tokenを取得(http://localhost:9999 にアクセスしたときに聞かれる)

```sh
docker logs notebook 2>&1 | grep 'http://127.0.0.1:8888/?token=' 2>&1 | sed -e "s/^.*token=\(.*\).*$/\1/" 2>&1 | sed -n -e \$p
```

* Dockerコンテナを落として削除(使い終わったら消しといたほうがいい)

```sh
docker stop notebook && docker rm notebook
```

* Dockerで使ってないコンテナやイメージを全整理(削除)する(ストレージ食うので)

```sh
docker system prune
```

### Dockerのゴミ削除

Dockerを使った環境作りの際、いろいろ試行錯誤しているとゴミがたまり、稀に50GBくらい食ってることがあります。
基本`docker system prune`を定期的にしていれば大丈夫ですが、ここあたりの記事も参考に！

[Docker一括削除コマンドまとめ](https://qiita.com/boiyama/items/9972601ffc240553e1f3)
PHPer脳の人がJavaScriptでarray_sumをする

# 前提

例えば、レジみたいなプログラム組むときにこんな感じの連想配列にぶち当たることがあるかと思います。

|品名(name)|金額(price)|
|---|---|
|ナナチ|100|
|ストロングゼロ|118|

で、こいつの総額の計算を出したいって思うことがあると思うんですよ。
これくらいなら暗算とか言わないでプログラムで計算してくださいね。

# PHPで書く

PHPだとこんな感じに書けると思います。

```php
$items = [
    ['name' => 'ナナチ', 'price' => 100],
    ['name' => 'ストロングゼロ', 'price' => 118],
];

// PHP7以前の書き方
$sub_total = array_sum(array_map(function($i){
    return $i['price'];
}, $items));

// PHP8以降の書き方
$sub_total = array_sum(array_map(fn($i) => $i['price'], $items));

echo $sub_total; // 218
```

この `array_sum()` という関数は「引数にとった配列の合計値を出す」ってやつなのです。
便利ですよね。
https://www.php.net/manual/ja/function.array-sum.php

# JavaScriptで書く

んで、JavaScriptなんですけど、 `array_sum()` 相当のものはないです。
その代わり `Array.prototype.reduce()` というのを使います。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

ってなわけでこんな感じになります。

```javascript
const items = [
    {'name': 'ナナチ', 'price': 100},
    {'name': 'ストロングゼロ', 'price': 118},
];

const subTotal = items.reduce((accumulator, currentValue) => {
    return accumulator + currentValue.price;
});

console.log(subTotal); // 218
```

# 参考に

PHPにも `array_reduce()` はあります。
https://www.php.net/manual/ja/function.array-reduce.php

さっきのを `array_reduce（）` で書くとこんな感じですかね？

```php
$items = [
    ['name' => 'ナナチ', 'price' => 100],
    ['name' => 'ストロングゼロ', 'price' => 118],
];

// PHP7以前の書き方
$sub_total = array_reduce($items, function($carry, $item){
    return $carry + $item['price'];
});

// PHP8以降の書き方
$sub_total = array_reduce($items, fn($carry, $item) => $carry + $item['price']);

echo $sub_total; // 218
```

意外とスッキリ書けるもんですね。array_mapするくらいならこっちでもいいのかも。

もうちょい詳しくはこちら。

https://qiita.com/miriwo/items/c994e09fd1b871636311