OmniAICreator/Qiita-1.07M huggingface dataset:
Rails+WebpackerでのIE11対策

環境: Rails 6.0、Webpacker 4.2、Vue.js 2.6

参考にした記事:

- [Babel7.4で非推奨になったbabel/polyfillの代替手段と設定方法](https://aloerina01.github.io/blog/2019-06-21-1)
- [@babel/preset-env · Babel](https://babeljs.io/docs/en/babel-preset-env#usebuiltins)
- [zloirock/core-js: Standard Library](https://github.com/zloirock/core-js)

Babelが最新版（7.4以上）であることを確認します。

```
$ yarn list --pattern @babel 
```

## useBuiltIns: 'entry' の場合

babel.config.jsのpresetsの設定が`useBuiltIns: 'entry'`となっていることと確認します。

```javascript:babel.config.js
      (isProductionEnv || isDevelopmentEnv) && [
        '@babel/preset-env',
        {
          forceAllTransforms: true,
          useBuiltIns: 'entry',
          corejs: 3,
          modules: false,
          exclude: ['transform-typeof-symbol']
        }
      ]
```

エントリポイントとなるJS（application.js）に次の2行を入れます。これだけです。

```javascript:app/javascript/application.js
import "core-js/stable";
import "regenerator-runtime/runtime";
```

stableを付けないで`import "core-js"`とすると、提案中のECMAScriptの機能（proposals）が入って、コンパイル後のファイルサイズがちょっと大きくなります。

 <del>regenerator-runtime が何をやっているかはよくわかりませんでした。Generator に関連しているようですが、この行なしでもIE11でGeneratorが使えます。</del>

2020-03-21追記: [regenerator-runtime/runtime](https://github.com/facebook/regenerator/tree/master/packages/regenerator-runtime) は、asyncとawaitを使うときに使われます。asyncとawaitがコード中にまったくない場合は、regenerator-runtime なしでも動くと思います。

## useBuiltIns: 'usage' の場合

babel.config.jsのpresetsの設定を変更して、Babel7.4からの新機能`useBuiltIns: 'usage'`を使ってみます。

```javascript:babel.config.js
      (isProductionEnv || isDevelopmentEnv) && [
        '@babel/preset-env',
        {
          forceAllTransforms: true,
          useBuiltIns: 'usage',
          corejs: 3,
          modules: false,
          exclude: ['transform-typeof-symbol']
        }
      ]
```

この場合は、application.jsにimportを書かなくても、使っているJavaScriptの機能に合わせてモジュールが入ります。必要なものだけ入るので、コンパイル後のファイルサイズがだいぶ小さくなります（私のテストプログラムでは、developmentで1.2MB→750KB、productionで300KB→200KB）。

 <del>ただし、IE11でVue.jsを試したところ、「Promiseがない」というエラーが出ました。次の1行をapplication.jsに足すと動きましたが、ちょっと格好悪いですね。</del>

```diff:app/javascript/application.js
- Promise;
```

2020-03-22追記: 再度試したところ、`Promise;` がなくてもIE 11で動作しました。
【Twilio Flex × GCP】顧客とオペレーターの通話内容をリアルタイムにテキスト化

はじめまして、テラスカイでエンジニアをしていますkamikawaです。
今回は、Twilio Flex上に顧客とオペレータの通話内容をリアルタイムにテキスト化して表示してみたので、その紹介をしたいと思います。
#Twilio Flexとは？
クラウドで提供されているプログラマブルなコンタクトセンターです。
FlexはReact/Reduxで作られいて、それらの各種コンポーネントを自由にプログラミングでカスタマイズすることが出来ます。
なので、利用者が必要に応じて超自由にカスタマイズすることが出来ます！！すごいですね！！
https://www.twilio.com/flex
![Flex公式.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337592/34239e16-afd5-5c04-b87a-14c4a806bdd9.png)
#【Twilio Flex】リアルタイム文字起こしデモ動画
今回紹介する内容が、実際に動いているデモ動画がありますので、是非ご覧ください。
[Twilio Flex デモ](https://www.youtube.com/watch?v=ULsLheBvMwc)

#【Twilio Flex】リアルタイム文字起こし全体像
Twilio Flexで、リアルタイム文字起こしの全体像はこんな形になります。
![【Twilio Flex×GCP】リアルタイム文字起こし構成図 for blog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337592/26985ece-b798-3e38-7be0-45106ac08120.png)
##【Twilio Flex】システムの流れ
###１．顧客がTwilioの電話番号にかけると電話番号に設定したStudioが起動します。

![Studio.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337592/753f7c09-8e5e-837a-246a-95467f040a7d.png)
###２．Studioの中で、Media Streamのウィジェットを使い、インバウンドとアウトバウンドの音声情報を送るためにサーバーサイド側とWebsocketで接続をします。
![mediaStream.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337592/aea6a768-28c9-aaf4-e5af-b675678c8eb7.png)
###３．Studioで出来たタスクがTaskRouterを通って、最適なオペレータにタスクを割り振ります。
###４．Flex上にタスクが出来るので、オペレーターはそれを受け取り、電話に応じます。
![FlexPhoneReceive.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337592/be3c498e-e2d5-3e0e-c54f-c18bd16c2523.png)
###５．オペレーターが電話に出ると、Websocketを通じて顧客とオペレータの音声情報をherokuのアプリに送り続けます。
![Flex受け入れ後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337592/3c910d4f-1864-8656-0ebf-8f65ccf212c7.png)
###６．herokuはgoogle speech to textに音声情報を渡します。返ってきた結果を加工し、リアルタイムChat風のhtmlに描画し、それをiframeでFlex上に埋め込んで表示しました。
※緑色の吹き出しが顧客の通話内容、灰色がオペレータの通話内容をリアルタイム文字起こししたものになります。
![Flex文字起こし.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337592/e160a39a-d9a6-c7f7-fa17-bd9e98f9c920.png)
##良かった点
 - Google speech to textの精度は結構いい
 - そこまでコードを記述しなくても簡単に出来る

##苦労した点や、もっとこうすればよかった点
 - Google speech to textのレスポンス結果があまりイケてなく、サーバーサイド側でロジックを組まないといけないので少々面倒（具体的には以下の事）
    - レスポンスを特定できるキーを返してくれない。
    - 暫定結果を常に返すが、間が空いても前の言葉に繋げて返す。
    - 確定した結果が来るタイミングが遅い。
    - 1分経つと接続が切れる。（ドキュメント5分という記載があり、そのバージョンで試したが。。）
    - 句読点が日本語対応していない。
    - 専門用語などにはおそらく弱い。
 - iframeで埋め込むのではなく、直接テキストデータをFlexに渡してReactで描画するだけの方が良い。
 - そうすれば、キーワード抽出によるFAQ検索などの幅が広がる。
 - 専門用語への対応や、文章の要約なども出来たらいいなとは思う。
 - 今まであまりjavascriptをがっつり触ったことはなかったので、モダンなjavascriptのキャッチアップに少し時間がいりました。

##まとめ
Flexは本当に自由にカスタマイズが出来るので触っていて楽しいです。
今後も頑張っていきますので、何卒よろしくお願いします。

##参考にしたもの
 - Twilioのブログ：[Live Transcribing Phone Calls using Twilio Media Streams and Google Speech-to-Text](https://www.twilio.com/blog/live-transcribing-phone-calls-using-twilio-media-streams-and-google-speech-text)
 - ブログに載っていたGithubのリポジトリ：[twilio-media-stream-live-transcription-node](https://github.com/nokenwa/twilio-media-stream-live-transcription-node/blob/master/Readme.md)
Webフォントを使う時はbold時のfont-weightを読み込んだ上で扱う

# はじめに
Webフォントは無償のものもあり、気軽に利用できる環境になっています。中でもGoogle Fontsを利用している人も多いのではないでしょうか。私もよく使わせてもらっています。

今年、 コーディングしたものの、デザインと見比べると、`bold`の太さが異なるといったという事があり、Webフォントを使う時の注意点の1つを残しておこうと思います。

以下では `Google Fonts` の `M PLUS 1p` を利用する想定の例を挙げながら説明します。（キャプチャはMacのChrome 78.0.3904.108（Official Build） （64 ビット）で表示したものになります）

# import時に単一のfont-familyで利用する時の問題

[Google Fontsのページ](https://fonts.google.com/)を参照して、 `M PLUS 1p` を利用して選択すると、

```css
@import 'https://fonts.googleapis.com/css?family=M+PLUS+1p&display=swap&subset=japanese';
```

というようなURLになるよ、と教えてもらえます。

ただ、これで `bold` を指定しようとすると以下のように、表示されます。

<img width="524" alt="スクリーンショット 2019-12-07 15.27.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38510/1f04904f-5864-8709-ae54-691b0a9528ce.png">

https://codepen.io/aktuehr/pen/NWPGrPM

`font-weight` が `600` 以降の数値と、 `bold` のときに、気持ち太くなっているのに気づくでしょうか。

この太さですが、 `400` より少し太いくらいなのですが、 `500` よりは細いため、これはブラウザ側でよしなに解釈して `bold` の太さはこれくらいでしょうと、太くしてくれているようです。

これで問題なければ良いのですが、ブラウザに依存する形になるため、ブラウザのバージョンアップなどで太さが変わってしまうといった事があるかもしれません。

# import時にfont-familyにサイズを指定して利用して、太字をきちんと表示する

意図通りの太さの `bold` にするためには、Webフォントのimport時に `bold` にあたる `font-family` も指定する必要があります。

`font-weight` の `bold` は、数値では `700` にあたります。
https://developer.mozilla.org/ja/docs/Web/CSS/font-weight

また、通常時のフォントサイズは `regular` ですが、数値では `400` にあたります。

それぞれWebフォントに、 `400` と `700` の太さが用意されている事を確認し、その2つの`font-family`を含むようにimportします。

Google Fontsの場合は以下のようになります。

```css
@import 'https://fonts.googleapis.com/css?family=M+PLUS+1p:400,700&display=swap&subset=japanese';
```

上記のようにしてimportしたところ、以下のように、 `bold` の値が何も指定しなかった時より太くなりました。
![スクリーンショット 2019-12-07 16.30.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38510/2f0bd0c2-4135-4096-9b5e-837730207b80.png)

https://codepen.io/aktuehr/pen/bGNVaqX

ちなみに、Chromeでは `600` 以上の数値を入力した場合は `700` で表示されるようになっています。

# boldの太さを700ではなくしたい場合
先ほど、 `font-weight` の `bold` は、数値上では `700` と同じと紹介しましたが、デザイン上の都合などで、「このプロジェクトでは `bold` はもう少し細い/太いフォントが良い」というケースが出てくることもあります。

その場合は、CSSのカスタムプロパティ (変数)やSCSSの変数などで、 `bold` の値を定義して使用すると毎回悩みません。

```css
@import 'https://fonts.googleapis.com/css?family=M+PLUS+1p:400,900&display=swap&subset=japanese';

:root {
  --this-site-bold: 900;
}

.element {
  font-weight: var(--this-site-bold);
}
```

# 余談
全部の`font-family`を使える状況にするとこんな感じになります。

![スクリーンショット 2019-12-07 16.38.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38510/451e9046-c32d-419e-442b-64c50a347fe5.png)

https://codepen.io/aktuehr/pen/yLyYOwR

`bold` は `700` となっている事が確認できますね。

# さいごに
Webフォントは、ダウンロードを必要とするためページの表示速度に影響します。全ての`weight`の`font-family`を存在させる事は稀ですが、通常(`regular`)と、太字(`bold`)だけは代表として、`400`,`700`(もしくは、フォントが指定する `regular` と `bold`の数値)をimportしておくのが良いと思います。

また、デザイナーさんが別でいらっしゃる場合は、意図した太さになっているかの確認を一度取るのが良いでしょう。細かいところですが、全体の印象に関わるので大事な事だと思います。
indexに格納されている文字を確認する walklex

小ネタ

なお、
>This documentation applies to the following versions of Splunk® Enterprise: 7.3.0, 7.3.1, 7.3.2, 7.3.3, 8.0.0

[２０２０年問題](https://docs.splunk.com/Documentation/Splunk/latest/ReleaseNotes/FixDatetimexml2020)もあるし、大丈夫ですよね。

#walklex
[walklex](https://docs.splunk.com/Documentation/Splunk/8.0.0/SearchReference/Walklex)
こんなコマンドがあったのね。

[UseCASE and TERM to match phrases](https://docs.splunk.com/Documentation/Splunk/8.0.0/Search/UseCASEandTERMtomatchphrases)に書かれている通り、検索するにも`TERM()`を使うとちょっと速くなる。

でも[サーチはどのように動くか How Search Works - ブルームフィルタ、TSIDX、TERMによる匠の世界へ](https://www.slideshare.net/takashikomatsubara50/how-search-works-tsidxterm)の_P30_がうまく動くためには、メジャーブレイカーとか知らないといけない。

**だったら、そもそも登録されている内容を確認すればいいじゃない**

```Splunk:SPL
| walklex index=botsv1
```
>説明
>イベントインデックスの各バケットから用語またはインデックス付きフィールドのリストを生成します。 マージされたレキシコンファイルまたは単一のtsidxファイルを持つウォームバケットにのみ適用されます。

`term`に登録されている一覧がでるので、その単語で検索`TERM(" ")`すれば、高速！のはず。

###確認してみる。

```Splunk:SPL
index=botsv1 cs_uri_stem="/RootDevice.xml"

index=botsv1 TERM(cs_uri_stem::/RootDevice.xml)
```

結果は
`This search has completed and has returned 1 件の結果 by scanning 16 件のイベント in 1.268 seconds`
と
`This search has completed and has returned 1 件の結果 by scanning 1 件のイベント in 1.48 seconds`

なんだろう...またこんな結果に。でも、そもそもの検索時間が速い。

#まとめ
Splunkのバージョンが上がって新しいコマンドが増えている。
今回のコマンドは、ダッシュボードとか定期的に使用するSPLをチューニングする際に使えると思います。

:sweat:　昔つくったクエリー直さないとな
mailtoはwindow.openで開かないほうがよい

# 環境

Mac
Chrome
Macの標準メールクライアント

（Windowsでも同じ症例報告あり）

# window.openでmailtoをひらくと

```.js
let mailtoUrl = 'mailto:a@gmail.com?subject=おはよう&body=今日もいい天気だね'

// 普通に開く
window.open(mailtoUrl)

mailtoUrl = 'mailto:abcdefghijk@gmail.com?subject=おはよう&body=今日もいい天気だね'

// 宛先がa@gmail.comのまま開かれる
window.open(mailtoUrl)
```

最初は普通に開けるが
そのあと非同期でデータ取ってきて動的にmailto:を書き換えたりするとTo(宛先)の更新が反映がされない。

# 解決策

location.hrefを使うとToも絶対更新される。

```.js
const mailtoUrl = 'mailto:a@gmail.com?subject=おはよう&body=今日もいい天気だね'

location.href = mailtoUrl;
```

# 最後に
mailtoとwindow.open周りは地雷が多いので気をつけよう。
というかmailtoは使うのやめよう。
ログについて（Not logarithm But log）

## ログとは

数学者なら対数のことだというかもしれませんが、基本的にはコンピュータに関する情報を記録すること、またはその記録自体を指します。一応、有名どころからも意味を引っ張ってきますが、だいたい同じです。

> ログとは、コンピュータの利用状況やデータ通信など履歴や情報の記録を取る事、またその記録を指す。操作やデータの送受信が行われた日時と、行われた操作の内容や送受信されたデータの中身などが記録される。
> [ITトレンド](https://it-trend.jp/words/log)より引用

そしてサービス開発において、ログは以下の4種類に分けて考えることができます。

- アクセスログ
- エラーログ
- デバッグログ
- イベントログ(ユーザーログ)

## アクセスログ

Webサーバへのクライアントからのアクセス記録のことを指します。内容としては

- いつ
- だれが
- どこから
- どのような操作をして
- その結果はどうだったのか(リクエストの結果)

が記載されることが多いです。

普段はGoogle Analytics（以下、GA）や自前の管理ツールを使ってログを確認し、ユーザーの行動分析を行う際に使います。また、障害発生時には問題の原因を特定するためにサーバ内にあるアクセスログ(生データと呼んだりします)を見て、問題の原因を調べたりもします。

## エラーログ

文字の意味のごとく、エラーが発生したときの記録です。

プログラム上のエラーがあった時や意図的にエラーを発生させることで、エラーログとして記録されます。
エラーログは、ブラウザ上に表示されることもあれば(開発環境で表示されるのは問題ないですが、本番環境で表示されるのは望ましくありません)、ログファイルとしてサーバに蓄積されることもあります。

最近では、一定のエラーが貯まったらSlackに通知するようになっているチームも多いです。

## デバッグログ

不具合調査のために設置する記録です。

例えば、以下のコードで正の処理したいですが、当然実行されません。`$hoge` には `ABC` が入っていますが、正の処理が実行されるのは数字の `123`　のときだけだからです。

```php

$hoge = 'ABC';
if ($hoge === 123) {
    // 正の処理を実行する
    echo '正解';
}
```

こういう時に、if文の前で `$hoge` の中身を出力することで、なぜ正の処理が実行されないのかを調べることができます。

```php

$hoge = 'ABC';
// $hoge が下のif文の条件を満たしているか調べるために、$hogeを出力する。
var_dump($hoge);
if ($hoge === 123) {
    // 正の処理を実行する
    echo '正解';
}
```

上のサンプルは極端な例ですが、実際にサービス開発をするなかでデバッグログはよく使います。

デバッグログは開発・テスト時に使うログで、製品版では使わないことが多いです。(もちろん、チームの方針によって残す場合もあります)

## イベントログ(ユーザーログ)

最初のアクセスログとほぼ同義で、ユーザーがサービス内で行った行動に基づいて取られるログです。

Qiitaでいうと、

- 〇〇の記事を読んだ
- 〇〇の記事をいいね！した
- △△さんをフォローした
- プロフィールを変更した

等のログです。基本的に、ディレクターやマーケターからログを取れるようにして欲しいと言われたときのログは、たいていイベントログです。

こちらは、GAや自前の管理ツールを使ってログを確認し、ユーザーの行動分析を行う際に使います。アクセスログの違いとしては、アクセスログは指定のURLにアクセスがあった時にログとして記録を取るのに対し、イベントログはユーザーの行動に対してログとして記録を取ります。

例えばですが、ユーザーがスクロールをしただとか、ボタンとは関係ない箇所をタップしただとかのときに取るログはイベントログになります。(そういうログを取るかどうかは別として)

さらにややこしいですが、イベントログを送信する際にアクセスログも発生してしまいます。まあ、ここは気にする必要はないですが…。

```
ユーザーがイベントログの対象になる行動をする
↓
イベントログとしてサーバに送信する ← この通信自体はアクセスログになる
```

## 最後に

今回は4種類にログを分類して記載しましたが、ログの扱いはチームによって異なるかと思います。

そして、ログは取ろうと思ったらいくらでも取れてしまいますが、取れば取るほどノイズが増えてしまい大事な情報を見逃しがちになってしまいます。なので、ログを取る際にはきちんと用途をはっきりさせて取る方が良いかなと思います。
TikZで図を描く 忘れないようにメモ書き-間違っているかもしれません

# 図形の角度記号　－anglesライブラリを使う
```
\documentclass[12pt,dvipdfmx]{jsarticle}
\usepackage{tikz}
\usetikzlibrary{angles,quotes}
\begin{tikzpicture}
\coordinate(A) at(0,0);
\coordinate(B) at(3,0);
\coordinate(C) at(1.5,2.5);
\pic [draw=black, angle eccentricity=1.8, angle radius=1cm, "$\theta$"] {angle=B--A--C};
\end{tikzpicture}
```
- draw=black ：色を設定
- angle eccentricity：挿入したい文字列の位置決定
- angle radius：角度の弧の半径
- "文字列"：文字列を入れる

よくわからないが\usetikzlibrary{quotes}がないと，"文字列"の部分でエラーが出た。

# 交点に文字列を配置
```
\documentclass[12pt,dvipdfmx]{standalone}
\usepackage{tikz}
\usetikzlibrary{patterns,intersections,calc,angles,quotes}

\begin{document}
\begin{tikzpicture}
    \draw [name path=xaxis,->](-0.5,0)--(3,0);
    \draw [name path=yaxis,->](0,-0.5)--(0,3);
    \node [anchor=south] at(0,3) {$y$};
    \node [anchor=west] at(3,0) {$x$};
    \path [name intersections={of=xaxis and yaxis,by=in}];
    \coordinate (O) at(in);     %x軸とy軸の交点をOとする
    \node [anchor=north east] at(O) {O};
    \draw [name path=la, domain=-0.5:2] plot(\x,\x+1);
    \draw [name path=lb, domain=-0.5:2.3] plot(\x,-\x+2);
    \path [name intersections={of=la and lb,by=in2}];　%laとlbの交点をin2とする
    \node [anchor=west] at(in2) {A};　　%in2にAという文字列を配置
\end{tikzpicture}
\end{document}
```
- name path=名前：描画したものに，名前を付ける
- \path[name intersections={of= 図形１and 図形２,by=NAME}];：図形１と図形２の交点を計算させ，その交点にNAMEという名前を付ける

![交点-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547166/5e3dc154-6e7d-6546-ad27-59e3c0528fc8.jpeg)

参照：TikZ & PGF manual (version 3.0.1a)
Jetson AGX Xavier での Python/PyTorch 環境構築のメモ(2019 年 12 月 7 日時点)

# 準備

JetPack がインストールされているものとします.
初期状態だと CUDA 環境が入ってません.

## Python

Jetson の Ubuntu 18.04 では python2 がデフォルトです.
python3 は apt などでインストールする必要があります.

### 仮想環境

conda は現状 aarch64 に対応していないため(もうすぐ対応されるかも?), virtualenv を使うのをおすすめします.


## scipy

pip でソース(?)からビルドが必要です. lapack と gfortran が必要です.
ビルドに 30 分くらいかかります.

```
$ sudo apt install liblapack-dev
$ sudo apt install gfortran
$ pip install scipy 
# cython もいるかも
```


## PyTorch 

PyTorch for Jetson Nano - version 1.3.0 now available
https://devtalk.nvidia.com/default/topic/1049071/pytorch-for-jetson-nano-version-1-3-0-now-available/

1.3.0 + py3.6 の wheel があります.
インストール時なにかのモジュールがコンパイルしているようなので, いくらか時間かかります.


### その他

音声系の librosa は, aarch64 環境では pip でのインストールに失敗します(pip 版はなにやらいろんな依存ライブラリ有効な設定にしているようで, 最終的に scipy の特定のバージョンを利用しているようでコンパイルがこける).

librosa はソースコードからビルドください.

最初のほうにあるように, 事前に `pip install scipy` で scipy インストールしておく必要があります.
ffi も必要です.

`sudp apt install libffi-dev`
フロントエンドマスターへの道 その2 Vue.jsとPusherでチャットアプリ

- [2020年のフロントエンドマスターになりたければこの9プロジェクトを作れ](https://qiita.com/rana_kualu/items/915345b8f3f870cfe2aa)

上記記事の第二回。

Vue.jsとPusherのChatKitを使ってチャットアプリの作成をする、と言ってもコードは[ほとんどチュートリアル](https://www.sitepoint.com/pusher-vue-real-time-chat-app/)のコピペ。

![Screenshot from 2019-12-07 15-23-27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17669/19a9a087-3df2-baec-f90f-cefe2655443d.png)

- https://github.com/hbsnow-sandbox/vue-pusher-example

## install

@vue/cliは `npx vue create .` だと失敗して、globalにインストールしたものを実行したら普通にcreateできた。原因は後者で普通にインストールできたため調べていない。

```bash
Vue CLI v4.1.1
? Please pick a preset: Manually select features
? Check the features needed for your project: TS, Router, Vuex, Linter, Unit
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? No
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a linter / formatter config: Prettier
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
```

今回はTSを使った。ただし今の段階でchatkitの型定義ファイルがないのであまり意味がなかったかもしれない、面倒なのでほとんど `any` で通した。

- https://github.com/pusher/chatkit-client-js/pull/180

面倒でなければ上記 PR を参考にコピペすればよさそう。

Vuex の型をどう書けばいいのかよくわからなかったので

- [Nuxt.jsの新規プロジェクトでいい感じのテスト環境をつくる@2018](https://qiita.com/okmttdhr/items/48e8d4db1a7827d44ec4#typescript%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

この記事を参考にさせてもらってふわっと理解しておいた

## vuex-persist

Vuexの情報をCookieやlocalStorageに保存するもの。以前こういったことをしたかったときにはvuex-persistedstateを使っていたんだけど、両者の違いはちょっとわからなかった。

- https://www.npmtrends.com/vuex-persist-vs-vuex-persistedstate

vuex-persistedstate のほうが人気はありそうかな。

## rooms?room?roomId?

mutation の `setActiveRoom(state: any, roomId: any)` の `roomId` はいかにも ID だけを set するように思えるが、これの中身が

```js
{id: "roomID", name: "roomName"}
```

と、IDだけではなくNameも含まれていたりする。気になったので room にリネームした。このあたりは他の箇所でもわかりにくくて、`async changeRoom({ commit }, room)` は `async changeRoom({ commit }: ActionContext<any, any>, roomId: string)` 実際にはこんな感じで、room ではなく roomId がはいる。  

## 感想

Vue.jsは3になったらもう一度勉強し直そうとおもっているのでしばらく触ってなかったんだけど、コードを読んでいて `room` が紛らわしいなと思ったところ以外ではとくにつらいところもなかった（難しそうな認証まわりはこのチュートリアルに含まれていないしね）。

[ChatKit は無料でもそこそこ使える](https://pusher.com/chatkit/pricing) ので、なんかちょっとチャット作りたいなと思ったときにはすごい便利かもしれない。
誤ってdevelopブランチにpushした時に見るページ 

## 手順
1. pushする前のCommitIDを確認する
2. ローカルの環境をpush前のdevelopに戻す
3. リモートのdevelopを上書きする

## 1. Pushする前のCommitIDを確認する
以下のコマンドを実行することで過去のCommitを確認することができます。
実行してPushを実行する直前のCommitIDを確認してコピーしましょう。

```shell
$git log --oneline
```

実行結果

```shell
$git log --oneline
44500c3 (HEAD -> develop, origin/feature/downstream, origin/develop, origin/HEAD, feature/downstream) Fix: Function Name
c6a34d8 Add: Confirm Device ID
3028558 merge
f1ff511 Add: npm ←ここまで戻したい
```

## 2. ローカルの環境をPush前のdevelopに戻す
リモートのPushを取り消す前にローカル環境のCommitを取り消す必要があります。以下のコマンドを実行することでCommitをCommitIDの時点まで戻すことが可能です。

```shell 
$git reset --hard <CommitID>
```

実行結果

```shell
$git reset --hard f1ff511
HEAD is now at f1ff511 Add: npm追加
```
ここまで来ればあと一歩です。

## 3. リモートのdevelopを元に戻す
以下のコマンドでリモートを強制上書きします。
上書き権限が必要なので場合によって設定してください。

```shell
$git push origin develop --force
```

実行結果

```shlell
$git push origin develop --force
Total 0 (delta 0), reused 0 (delta 0)
To https://**********************************
 + 44500c3...f1ff511 develop -> develop (forced update)
```

誤ってdevelopにpushすることは**よくある**ことだと思いますので慌てずに対処したいですね。
code-server ローカル環境篇(7) DBなども含めたMVC環境を用意してみよう (4)

これは、2019年 code-server に Advent Calender の 第7日目の記事です。今回も、code-server って何だろう?と言う事を解説していきます。


(1) [code-server って何?](https://qiita.com/kyorohiro/items/35bab591cd4a6b975c80)
(2) [Dockerで独自のcode-server 環境を作って見る](https://qiita.com/kyorohiro/items/d991f6fbf77a425525c5)
(3) [VSCode の Plugin を 利用してみる](https://qiita.com/kyorohiro/items/11a13d32c8748f3d7002)
(4) [DBなども含めたMVC環境を用意してみよう (1)](https://qiita.com/kyorohiro/items/4ed279dd91e39321ed20)
(5) [DBなども含めたMVC環境を用意してみよう (2)](https://qiita.com/kyorohiro/items/94c75a13ddccc5f39d85)
(6) [DBなども含めたMVC環境を用意してみよう (3)](https://qiita.com/kyorohiro/items/71a8b6ce3cbb9b36019a)
(7) [DBなども含めたMVC環境を用意してみよう (4)](https://qiita.com/kyorohiro/items/106ebb7003072a8dc989)
(8) [DBなども含めたMVC環境を用意してみよう (5)](https://qiita.com/kyorohiro/items/a019e4ab6dcda55896e0)
(9) [DBなども含めたMVC環境を用意してみよう (6)](https://qiita.com/kyorohiro/items/287364f03ed7a88f714e)
(10) [おまけ](https://qiita.com/kyorohiro/items/f96d27bba9fb23c0a097)


(NEXT->) [オンライン環境篇 1日目 作業環境を整備する](https://qiita.com/kyorohiro/items/603d6ee693fc2300079e)

(..) ローカルで、DBなどの環境も含めて構築するには
(..) オンライン上に置くには?
(..) K8Sなどの最近の流行りの環境と連携するには?
(..) Code-Serverを改造して、より良くしたい


前回の続きで、db の初期化などを、していきます。

# 今回の何?
### コンテナー単位でツールを追加すると便利!!


# PHPMyAdminを追加してみよう!!

データを直接、CLIで操作しても良いでもすが、GUIで操作するのも一つの手です。
PHPMyAdmin を 利用して GUIからDBを操作できるようにしてみましょう。



docker-compose.yml に phpmyadmin を 追加します。

```yml:docker-compose.yml
version: '3'
services: 
  app:
    build: ./app
    ports: 
      - 8443:8443
      - 8080:8080
    volumes:
      - ./app:/works/app
    links:
      - mysqld
    command: /works/code-server --allow-http --auth none --port 8443 /works/app
  mysqld:
    image: mysql:5.7
    ports: 
      - "3306:3306"
    environment: 
      MYSQL_ROOT_PASSWORD: passwd
      MYSQL_DATABASE: hello
      #MYSQL_USER: user
      #MYSQL_PASSWORD: password
  phpmyadmin:
    #https://hub.docker.com/r/phpmyadmin/phpmyadmin
    image: phpmyadmin/phpmyadmin:4.8.5
    environment:
      PMA_HOST: mysqld
      PMA_USER: root
      PMA_PASSWORD: passwd
    links:
      - mysqld
    ports:
      - '18080:80'

```

# 動作確認をしてみよう

ブラウザ-で 'http://127.0.0.1:18080/' にアクセスする。


<img width="1393" alt="Screen Shot 2019-12-07 at 16.36.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54192/5c0a0bc6-2276-5f42-c595-cbc4f3c447ed.png">


phpMyAdmin を起動できました。

これで、DBもGUIで操作できます。

 

# 次回

SQLサーバーを初期化してみます。

# PS

## ソース
https://github.com/kyorohiro/advent-2019-code-server
pythonを使ってtargzファイルを展開する

Windowsでtargzファイルを展開したいなあと思っていたところ、以下のやり方でできるようなので記録しておきます。

``` extract_from_targz.py
import tarfile
import sys

args = sys.argv

with tarfile.open(args[1], "r:gz") as file:
    file.extractall(path=args[2])
    file.close()
```

```shell
>python extract_from_targz.py <targzファイル名> <展開後のディレクトリ名>
```
Azureの基礎　その２

#Core Cloud Services - Azureの概要

出展：https://docs.microsoft.com/ja-jp/learn/modules/welcome-to-azure/

##クラウドコンピューティングとは

・コンピューティング サービスをインターネット経由で、従量課金制価格モデルを使用して提供すること
（だれかのデータ センターからコンピューティング能力とストレージをレンタルする方法）

##Azureサービス

###全体図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/3f9881a9-ff2d-455b-bded-12a4c79f524c.png)

###コンピューティング

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/f4a303f9-c04d-c01b-2da3-07ddbc4e30b1.png)

###ネットワーク

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/e2b9be46-0e3c-bfdc-a6a3-31624359b098.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/dc06b5a1-54bc-4161-b218-fedf22289ea4.png)

###ストレージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/7ba03baf-75e3-6587-c5cd-89b49fce2416.png)


###データベース

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/838ee443-203e-bc96-c1a2-d1aa74598179.png)

###Web

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/ad3f8cf1-431e-1ec4-da41-7cf04ce2c5dd.png)

###IOT

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/9ef4ffef-c001-170f-df12-bcd09d0b4f7a.png)

###ビッグデータ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/cd513c0d-1097-c295-3af9-d05b1cfa19f4.png)

###人工知能

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/c25238a5-5b42-b47f-ae23-a2accdf1e3e1.png)

###DevOps

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545315/7468872a-364b-18a8-0ce0-fbc2772ea020.png)
Postmanがロードされない（Windows）

**ある日、Postman起動をしたらこのようにコンテンツが何も表示されなくなりました。**
再起動しても再インストールしても結果は同じでした。。

POSTMAN
https://www.getpostman.com/downloads/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358318/287d0ee0-b5b2-6718-d689-a640761bfd79.png)

**環境**
Postman: 7.13.0
OS：Windows10.0

**以下のリンク先の手順を参考に環境変数を設定することで無事に使用できるようになりました**

Postman will no longer load as of 6.1.2 (GPU issue)
https://github.com/postmanlabs/postman-app-support/issues/4594

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358318/ddb39e04-9ba7-81ae-e053-225fc148ff0d.png)
Notionで数式を書く

[アルプ株式会社](https://thealp.co.jp/)でエンジニアをしています、集約のエンティティ@pictinyです。
これは[Notion Advent Calendar 2019](https://qiita.com/advent-calendar/2019/notion) 7日目のエントリです。
6日目は[Notionのスラッシュコマンドを使おう](https://qiita.com/pictiny/items/d88a7025b8d121009ce0)でした。

# 数式

Notionでは数式を記述することができます。
スラッシュコマンドで `/math` と打つと、数式ブロックを作ることができます。

<img width="755" alt="Screen Shot 2019-12-05 at 0.10.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427952/002fec31-b096-215c-b53a-f73f26277da6.png">

数式ブロックをクリックすると、数式エディタが表示されます。
数式エディタにTeXの数式を入力すると、即座に数式ブロックに反映されます。

# まとめ

TeXで数式も書けるなんて便利ですね！
TeXの記法については[Math equations](https://www.notion.so/Math-equations-b4e9e4e03677413481a4910e8bd328c1)もご覧ください。
Amazon Connectについて事例などのリンク集

最近、Amazon Connectについてお話を聞くことがあったので、どんなサービスなのだろうと思い、調べてみました。主にリンク集です。

#Amazon Connectとは
> https://aws.amazon.com/connect/

**マルチチャネルのクラウドコンタクトセンターが、簡単に、コストをかけず、さらに業務フローの変更に容易に対応しながら、構築できる仕組み**です。東京リージョンでの利用が2018.12より始りました。また他のAmazonとのサービスと組み合わせることで、チャットとの連携や顧客情報との連携も可能です。
詳しくは下のサーバーワークスさんの資料をご覧下さい。

#US事例
###事例一覧
リンク先を参照。印象では、**金融・保険**が多く、**コールセンター事業者、飲食業、旅行業、自治体・鉄道会社など**で導入されています。飲食業(Subway, ピザオンライン注文プラットフォーム、クッキー製造販売)、自治体などは日本でもニーズがありそうです。

> https://aws.amazon.com/connect/customers/

IVR(Interactive Voice Response, 電話自動応答)だけのシンプルなソリューションだけでなく、下記のようなカスタマイズもありました。

* ブラックリスト対応
* 対応待ち電話件数のビジュアル化
* 電話転送(対応部署に直接転送)

###Rackspace
Rackspaceはホスティング業。上の事例集の中で1番複雑なフローでAmazon Connectを使用しており、個別のケーススタディとして下記に紹介されています。

> https://aws.amazon.com/solutions/case-studies/rackspace/

Rackspaceコンタクトセンター構築事例
![C6C535B4-F244-4DAF-A25C-06EC85F14130.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547116/244ad020-5d72-2bb3-db78-b14b45453378.png)


#日本事例

日本での事例も増えてきているようです。

###サーバーワークスさんのAmazon Connect事例紹介
2018.07.02の記事。Amazon Connectの基本機能紹介が最初から最後まで詳しく紹介されています。全体像が分かります。

> https://www.serverworks.co.jp/news/20180702_amazonconnect_document.html

###一休さんでのAmazon Connect導入事例紹介
2018.12.05の記事。サーバーワークスさんの資料より技術的な部分が多いです。コードも一部あり。

> https://user-first.ikyu.co.jp/entry/amazon-connect
年末まで毎日webサイトを作り続ける大学生 〜50日目 再帰的関数を用い、特定のタグの数を調べるシステムを作る〜

##はじめに
こんにちは！@70days_jsです。

再帰的関数の書き方を勉強しました。
タグ名を入力すると、ページ内にあるそのタグの数を自動で調べてくれます。

今日は50日目。(2019/12/7)
よろしくお願いします。

##サイトURL
https://sin2cos21.github.io/day50.html

##やったこと
動作としてはこんな感じです。↓
![test3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/9d5f6334-d68f-2b65-0a63-2da08adb7fd0.gif)

ページを開くとプロンプトが出るので、そこでタグ名を入力します。
入力したタグ名を持つタグの個数をDOMから自動で調べてくれます。

まず、htmlに適当にタグを書いていきます。↓

```html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <script src="day50.js" defer></script>
    <title>day50</title>
  </head>
  <body>
    <h1>タグ数検索システム</h1>
    <div>
      <p></p>
      <div>
        <p></p>
        <div><p></p></div>
        <div></div>
      </div>
    </div>
  </body>
</html>
```

今回はhtmlはなんでもいいです。
強いて言うならば、以下の部分を気をつけましょう。

> \<script src="day50.js" defer>\</script>

JavaScriptを読み込んでいるscriptタグですが、deferをつけています。
これをつけることで、htmlの読み込みが完了した後にJavaScriptを実行するようにしています。
今回はDOMを読み込んでタグを数えていくので、deferがあるのとないのとでは大きな違いになります。

JavaScript全文↓

```javascript
let element = prompt("調べたいタグを入力してください ex: div");
element = element.toUpperCase();
console.log(element);
let wantToCheckNode = [];

//第一引数にdocument（DOM調査の開始場所）、第二引数に数を調べたいタグ名
function checkNodeTree(node, element) {
  for (var i = 0; i < node.childNodes.length; i++) {
    if (node.childNodes[i].nodeType === 1) {
      if (node.childNodes[i].tagName === element) {
        wantToCheckNode.push(node.childNodes[i]);
      }
      checkNodeTree(node.childNodes[i], element);
    }
  }
}

checkNodeTree(document, element);
console.log(wantToCheckNode);
document.body.innerHTML +=
  element + "タグの数は" + wantToCheckNode.length + "個です。";
```

promptで調べたいタグ名をユーザーから取得します。
toUpperCase()を使い、タグ名を大文字にします。
これは要素のタグ名をtagNameで調べた時に、返ってくる値が大文字の状態だからです。


そして今回の主題である再帰はここです。↓

> **function checkNodeTree(node, element)** {
for(var i=0;...){
if(){if(){}
**checkNodeTree(node.childNodes[i], element);**
}}}

関数checkNodeTree()の中で、自分自身であるcheckNodeTree()を呼び出しています。
内側にある関数は引数にiを使っていますね。
こうすることで微妙に値が変わっていくので、DOMツリーの全てを調べられます。

他ポイントとしては、
for文とchildNodesの組み合わせで子要素を全て調べられるとか、
nodetypeで要素のタイプが判別できたりとか（ちなみにELEMENTノードは1）です。


##感想
再帰はうまく使えばかなり便利なものなんじゃないかと思いました。
今回は自分で作ったページ内のタグを調べるだけでしたが、これをベースに改良していけば、他サイトの分析を自分のやりたいようにできるなーとか思いました。
とにかく再帰、すごい。

最後まで読んでいただきありがとうございます。明日も投稿しますのでよろしくお願いします。

##参考
1.[Node.nodeType - ノードの種類を表す整数 | DOM] (https://syncer.jp/Web/API_Interface/Reference/IDL/Node/nodeType/)

参考にさせていただきました！ありがとうございます！
JavaScriptでonoffスイッチを作ってみた



```
<!DOCTYPE>
<html>

<body>
  <form>
    <input type="button" value="OFF" onClick="OnOff(this);">
  </form>
</body>
<script type="text/javascript">

  function OnOff(lol) {
    if (lol.value == "OFF") {
      lol.value = "ON";
    } else {
      lol.value = "OFF";
    }
  }
// -->
</script>

</html>

```
“削除を防ぐリーエンがプロジェクトに配置されました。削除を許可するには、リーエンを削除してください。”の対応

<img width="462" alt="スクリーンショット 2019-12-06 0.36.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271765/986be735-1097-85a3-a155-3dd3bde348db.png">

Firebaseだと，ぽんぽんとプロジェクトを立てて，要らなくなったら削除できるので非常に簡単だし，便利．

ただ，たまにこんな感じで，リーエンという仕組みで削除されずに保護される場合がある．このリーエンという機能は間違えて削除されないようにする仕組みで，Firebase-CLIではなくGCloudのコマンドから設定をすることができるようだ．

今回は保護する方法ではなく，逆に削除したい場合の方法を記録しておく．

今回の自分の場合ではDialogflowと連携をしていたため，リーエンが働いていた．そのため，Dialogflowのコンソールから，一般設定画面をみると一番下に「DANGER ZONE」として「Delete Agent」という項目がある．

<img width="538" alt="スクリーンショット 2019-12-06 1.13.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271765/5f333b84-441b-0793-52bb-3b9072d0c9db.png">

ここで「DELETE THIS AGENT」を選択して「DELETE」と打ち込むと，このプロジェクトが削除される．

この作業をした後にFirebaseのコンソールから削除すれば普通に削除できる（他に連携されている物がなければ）

今回はDialogflowでリーエンが働いていたが，実際には他にもいろいろな可能性がある．

そんな時にはGoogle Cloud Platformのコンソール画面 [https://console.cloud.google.com](https://console.cloud.google.com)

から対象となるプロジェクトの中の「APIとサービス＞認証情報」を確認すると，他のどのようなサービスと連携しているのかがわかるはずなので，ここで先ほどDialogflowのAgentを削除したように諸々の対応をすれば，Firebaseのプロジェクトを削除することができるはずだ．

誰かの参考になれば
シェルスクリプトでチェックボックス式の選択メニューを作る

![shell-selection.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271765/3b2827c9-0964-c4af-8e7c-3b9af398f684.gif)

自分の作業を効率化するようなCLIのツールを作ることはよくあると思います．
探してもあまり情報が多くはなかったので，作りました．Bash環境で動くチェックボックスのシェルスクリプトです．

```bash
#!/bin/bash

#メニュー
options[0]="option 1"
options[1]="option 2"
options[2]="option 3"
options[3]="option 4"
options[4]="option 5"

#各メニューごとに挙動を記述する
function DOIT {
	if [[ ${choices[0]} ]]; then
		echo "Option 1 selected"
	fi

	if [[ ${choices[1]} ]]; then
		echo "Option 2 selected"
	fi

	if [[ ${choices[2]} ]]; then
		echo "Option 3 selected"
	fi

	if [[ ${choices[3]} ]]; then
		echo "Option 4 selected"
	fi

	if [[ ${choices[4]} ]]; then
		echo "Option 5 selected"
	fi
}

clear

#現在フォーカスしているメニュー
current_line=0

#メニュー一覧を表示
function MENU {
	echo "移動:[↑]or[↓], 選択:[SPACE], 決定:[ENTER]"
	for NUM in ${!options[@]}; do
		if [ $NUM -eq $current_line ]; then
			echo -n ">"
		else
			echo -n " "
		fi
		echo "[${choices[NUM]:- }]"":${options[NUM]}"
	done
}


#メニュー選択のループ
function SELECT_LOOP {
	while true; do
		while MENU && IFS= read -r -n1 -s SELECTION && [[ -n "$SELECTION" ]]; do
			if [[ $SELECTION == $'\x1b' ]]; then
				read -r -n2 -s rest
				SELECTION+="$rest"
			fi	
			clear
		
			case $SELECTION in
				$'\x1b\x5b\x41') #up arrow
					if [[ $current_line -ne 0 ]]; then
						current_line=$(( current_line - 1 ))
					else
						current_line=$(( ${#options[@]}-1 ))
					fi
					;;
				$'\x1b\x5b\x42') #down arrow
					if [[ $current_line -ne $(( ${#options[@]}-1 )) ]]; then
						current_line=$(( current_line + 1 ))
					else
						current_line=0
					fi
					;;
				$'\x20') #space
					if [[ "${choices[current_line]}" == "+" ]]; then
						choices[current_line]=""
					else
						choices[current_line]="+"
					fi
					;;
			esac
		done

		read -p "選べた? [Y/n]" Answer
		case $Answer in
			'' | [Yy]* )
				break;
				;;
			[Nn]* )
				;;
			* )
				echo "YES or NOで答えてね"
				;;
		esac
		clear
	done
}

SELECT_LOOP
DOIT
```
https://gist.github.com/shinyaoguri/782adf1c6765dba0717745578aa9c85f


最初の```DOIT```の関数に選ばれたらやりたいことを入れておけば選択式で処理を行わせることができます．

個人的には，簡単なPCの環境構築のスクリプトなどをこれを使っていたりします．

誰かの参考になれば幸いです．

※この記事は以前自分のブログに書いた物をこちらに引越しさせた記事になります．元の記事は削除しました．
Pipenv シンプルに要点だけ

# 参考

[Python実践入門 ](https://amzn.to/2zBKOFm)

# なぜPipenvなのか？
`バージョン管理`と`パッケージ管理`を一括で出来る。

#おすすめする理由
・プロジェクトごとにパッケージを簡単に分けることができる。
・プロジェクトごとにpythonを簡単に分けることができる。
・pyenvにインストールしてないpythonのバージョンを指定すると自動でpyenvを実行してインストールしてくれる。



# pipインストール

####pip

```:2系
curl -kL https://bootstrap.pypa.io/get-pip.py | sudo python2
```

```:3系
sudo apt-get install python3-distutils && curl -kL https://bootstrap.pypa.io/get-pip.py | sudo python3
```

# pyenvインストール

[pyenvのインストール等](https://qiita.com/osorezugoing/items/f96ba179322cdafae2b7)

# pipenvインストール

```:pipenv
sudo pip install pipenv
```
virtualenv-clone, virtualenv, pipenvが`/usr/local/bin/`へインストールされます。（pyenvのローカル環境で実行しても`~/.pyenv/shims/`へはインストールされません！（当然か）

なおインストールすれば設定なしですぐに使えます。

# 仮想環境

##作る

```
作りたいディレクトリに移動して以下を実行
pipenv --python [バージョン指定]
```

例)test_pipenvディレクトリに仮想環境を作った場合
**[linux]** `~/.local/share/virtualenvs/test_pipenv-XxXxXxXx`に仮想環境のデータが保存される。


##場所

```
pipenv --venv
```

##開発環境に入る

```
pipenv shell
```

###入った状態でpipをする

```:pipを最新にする
pip install -U pip
```

こうすると開発環境内のpipのみ最新版になる。

####pipでインストールした実行ファイルの場所
juptyerやpipなどの実行ファイルは`~/.local/share/virtualenvs/環境名/bin`にあるが`jupyter`の`runtime`は`~/.local/share`にある.

###入らずに開発環境内のパッケージを管理する

```:インストールが遅いので非推奨
pipenv install pip
```


##開発環境から出る

```
exit
```

##開発環境を削除

```
pienv --rm
```

##仮想環境に入らずに実行

```
pipenv run python test.py
pipenv run pip show pip
```


#パッケージ管理

##バージョンを指定してパッケージをインストール

```
pipenv install パッケージ名==バージョン
（バージョンは省略可)
```

##開発環境用

```
pipenv install --dev パッケージ名
```

#Pipfile

##Pipfileの内容にする

````
 pipenv install 
pipenv install --dev
````

##Pipfile.lockの内容にする

```
pipenv sync
pipenv sync --dev 
```

##Pipfileをアップデート

```:アップデート後Pipfile.lockが更新される
pipenv update
```

#スクリプト

##設定

```terminal:Pipfile
...
...
[scripts]
script = 'echo infinity'
```

##実行

```
pipenv run script
```

##参考
[こちらも参考にしました](https://amzn.to/2xbp2Xv)
【C#】CSVのインデックスはenumで持ちたい

# はじめに
最近関わったプロジェクトで出くわしたCSV処理について、備忘の意味も込めて書きます。
恐らく今時こんな書き方をしている箇所を見ることはないだろうけど、参考までに。

# 何をしたかったのか
内容はいたってシンプルで、システムの既存機能として存在している`CSV取り込み`に手を加えるというもの。
具体的には、CSVのフォーマットが変わって、取り込むデータが1列増えたので対応する。
既存のCSVは`A列、B列、C列、D列`というフォーマットだが、今回は`B列とC列の間にBα列を追加`したいとのこと。

# ソース

メソッド名等々は適当にぼかしてあります。

```C#
using Microsoft.VisualBasic.FileIO;

// ...略

private void LoadCsv(string csvPath){
    // TextFieldParserでCSVを読み込み
    TextFieldParser parser = new TextFieldParser(csvPath, Encoding.GetEncoding("shift_jis"));
    parser.TextFieldType = FieldType.Delimited;
    parser.SetDelimiters(",");

    while (parser.EndOfData == false) {
        string[] datas = parser.ReadFields();
        int cols = datas.length;
    
        // 列数が不正だったら終了
        if(cols != 4){
            return;
        }
        
        // A列処理
        if(string.IsNullOrEmpty(datas[0])){
            // ...略
        }

        // B列処理
        if(string.IsNullOrEmpty(datas[1])){
            // ...略
        }

        // C列処理
        if(string.IsNullOrEmpty(datas[2])){
            // ...略
        }

        // D列処理
        if(string.IsNullOrEmpty(datas[3])){
            // ...略
        }
        
        // 取得したデータをDBに書き込んだり...
        // その結果を画面に表示させたり...
    }
}

```

ぼく「うわぁ・・・、まじかよ・・・」

見ての通り取り込むCSVのフォーマットに合わせてインデックスをハードコーディングしてあるので、先に書いた通り`B列とC列の間にBα列を追加`するとなると、C列は`datas[2]`ではなく`datas[3]`になり、D列は・・・
といった風に、Bα列以降のインデックスをインクリメントしないといけなくなってくる。
もっと言うと、合計列数は4から5になるので列数不正となる条件は`if(cols != 4)`から`if(cols != 5)`になる。
まだ元々のフォーマットが4列だったから良かったものの、もしこれが10数列もあったら・・・と考えるとゾッとする。

というわけで、以下のようにCSVのインデックスを`enum`で持たせることにしました。

```C#

// 列のインデックス定義
private enum CsvCols
{
    // A列
    ColA = 0,
    // B列
    ColB = 1,
    // Bα列
    ColBalpha = 2,
    // C列
    ColC = 3,
    // D列
    ColD = 4
}

// 列数
private static int CSV_COLS = Enum.GetNames(typeof(CsvCols)).Length;

```

そんでもって、各インデックスのハードコーディング箇所を以下のように修正

```C#

// 列数が不正だったら終了(修正前)
//if(cols != 4){
//    return;
//}

// 列数が不正だったら終了(修正後)
if(cols != CSV_COLS){
    return;
}

// A列処理(修正前)
//if(string.IsNullOrEmpty(datas[0])){
//    // ...略
//}

// A列処理(修正後)
if(string.IsNullOrEmpty(datas[(int)CsvCols.ColA])){
    // ...略
}

```

# おわりに

これなら今後対象となるCSVのフォーマットが変わっても、enumの中身を変える(追加・削除する)だけで対応できます。
もしかしたらもっといいやり方があるのかもしれない(あったら教えてください)
ボタンを押すと文章が表示される方法


```
<p id="p1">でも我慢する</p>
<input type="button" value="夜にお菓子たべたいな" onclick="clickBtn1()" />

<script>
//初期表示は非表示
document.getElementById("p1").style.display ="none";

function clickBtn1(){
	const p1 = document.getElementById("p1");

	if(p1.style.display=="block"){
		// noneで非表示
		p1.style.display ="none";
	}else{
		// blockで表示
		p1.style.display ="block";
	}
}
</script>
```
[電子ブック] ダブルイレブンの技術の特長、アリババエコシステムクラウドネイティブの実践

2019年のダブルイレブンの技術の電子ブックがダウンロード出来るようになりました。
私の中国語の勉強も兼ねて目次を訳してみました。訳がおかしいよと言うところがあったらぜひ教えてください。

重磅发布 | 《不一样的 双11 技术，阿里巴巴经济体云原生实践》电子书开放下载
https://developer.aliyun.com/article/728327

不一样的をなんと訳すか迷いましたが、「同じでは無い」、「違い」なので、そんじょそこらの技術とは違うんだよって事かなと思って、特長としてみました。

ダブルイレブンの技術の特長、アリババエコシステムクラウドネイティブの実践


2019年のダブルイレブンはピークトランザクション 54.4 万/秒 、1日のデータ処理量は 970PB に達して、世界レベルの処理量に直面して、今年のアリババはクラウドネイティブ技術を徹底的に活用して、100%稼働率を実現しました。

- ダブルイレブンのコアシステム 100% クラウド化
- ダブルイレブンのオンライン業務を支えるコンテナ規模は 200 万 に達した
- 第3世代 神龍ベアメタルサーバの処理性能は 20% 改善しました。

本書の中では、Kubernetes、クラウドネイティブ構成（Kubernetes+容器+神龙）、Service Mesh、Serverless、セキュリティと可観測性というテーマが並んでいます。Service Meshって何なのかは各自で読んでみましょう。

## 目次
寄语
発売に寄せて (的な？）

开篇词
开篇词:上云Cloud Hosting 到 Cloud Native 
はじめに：Cloud HostingからCloud Nativeへ

第一章——超大规模 Kubernetes 实践
超大規模 Kubernetes 実践

1、释放云原生价值才是拥抱 Kubernetes 的正确姿势
クラウドネイティブの価値を解放するのがKubergnetesを抱く正しい姿勢

2、阿里云上万个 Kubernetes 集群大规模管理实践
阿里雲上での数万クラスのKubergnetesクラスタ大規模管理実践

3、深入 Kubernetes 的“无人区” :蚂蚁金服双11 的调度系统
Deep Dive: Kubergnetesの「無人エリア」：Ant Financial ダブル11のスケジューリングシステム

4、云原生应用万节点分钟级分发协同实践
クラウドネイティブアプリ 数万ノード級配布共同実践

第二章——阿里巴巴云原生化的最佳组合:Kubernetes+容器+神龙
アリババ クラウドネイティブ化ベストな組みあわせ: Kubernetes+コンテナ+神龙(ベアメタル)

1、阿里巴巴大规模神龙裸金属 K8s 集群运维实践
アリババ 大規模 神龍ベアメタル K8S クラスと運用・維持の実践

2、PouchContainer 容器技术演进助力阿里云原生升级
Pouuch Container コンテナ技術発展が阿里雲クラウドネイティブのアップグレードを支えた

3、更强，更稳，更高效- 2019 年 双 11 etcd 技术升级分享
より強く、より安定し、より効率的に-2019年ダブル11 etcd技術のアップグレードを共有する。

第三章——Service Mesh 将带来的变革和发展机遇
Service Meshがもたらす変革と発展のチャンス

1、Service Mesh 将带来的变革和发展机遇
Service Meshがもたらす変革と発展のチャンス

2、阿里集团 双11 核心应用落地 Service Mesh 所克服的挑战
アリババグループ ダブル11 コアアプリケーションが Service Mesh を利用することによって克服される課題

3、蚂蚁金服 双11 Service Mesh超大规模落地揭秘
Ant Financial ダブル11 Service Mesh 超大規模着地の秘密

4、服务网格在“路口”的产品思考与实践
サービスグリッドは「交差点」での製品思考と実践

第四章——Serverless
Serverless

1、CSE:Serverless 在阿里巴巴 双11 场景的落地
CSE：Serverlessはアリババ ダブル11シーンでの応用

2、解密 双11 小程序云背后毫秒级伸缩的 Serverless 计算平台:函数计算
解読 ダブル11 ミニプログラムクラウドの背後のミリ秒の伸縮性があるServerlessコンピューティング プラットフォーム：Function Compute

第五章——云原生安全及可观测性
クラウドネイティブ Security と 可観測性

1、双11 背后的全链路可观测性:阿里巴巴鹰眼在“云原生时代”的全面升级
双11の背後にある全リンクの視聴率はかなり高いです。アリババイーグル・アイは「雲原生時代」の全面的なアップグレードです。

2、Kubernetes 时代的安全软件供应链
Kubernetes 時代のセキュリティソフトウェア サプライチェーン 

3、安全容器:开启云原生沙箱技术的未来
セキュリティコンテナ: クラウドネイティブ サンドボックス技術の未来を開く

4、云原生全链路加密
クラウドネイティブ 全リンク暗号化

5、Kubernetes 下零信任安全架构分析
Kubernetes 下の Zero Trust Secuurity Architecture Analysis

6、云原生时代的 Identity
クラウドネイティブ時代のIdentity

7、云原生开发者工具——Cloud Toolkit
クラウドネイティブ 開発者ツール Cloud Toolkit

寄语
おわりによせて（的な？）
テキストの感情分析をするためのクラウドサービス比較（2019年版）

# 概要
テキストの感情分析をするクラウドサービスについて、２０１９年の対応状況をまとめた。
２０１８年版はこちらの記事に。
[テキストの感情分析をするためのクラウドサービス比較（２０１８年）](https://qiita.com/kazu20/items/42fbfe6dfa81b716b4bc)


## 比較項目

1. 日本語対応の有無
- 無料で使える範囲
- クレジットカード登録の有無
- 料金
- 呼び出し方


# Google Cloud natural Language
|比較項目|調査内容|
|---------------|-------------|
|日本語対応の有無|APIは日本語に対応している。チュートリアルも日本語対応している。|
|無料で使える範囲|月５０００リクエストまでは、無料。登録すると、１２ヶ月利用できる３００ドル分のクレジットが付与される。|
|クレジットカード登録の有無|無料トライアルをするには、クレジットカードの登録が必要だが、有料アカウントに手動でアップグレードしない限り、課金されることはない。|
|料金|月５０００リクエストまでは、無料。ただし、１リクエストのMAXは１０００文字なので、１３００文字のリクエストを投げると、２リクエストとなる。月５０００リクエストを超えると、１０００リクエスト単位で課金される。料金表は以下のURLを参照のこと。高くても１０００リクエストあたり２ドル。https://cloud.google.com/natural-language/pricing?hl=ja|
|呼び出し方|RESTで投げるとJSONで帰ってくる。入門ガイドに言語ごとに参考プログラムがある。https://cloud.google.com/natural-language/docs/analyzing-sentiment?hl=ja#language-sentiment-string-go|



# Amazon Comprehend

|比較項目|調査内容|
|---------------|-------------|
|日本語対応の有無|2019年11月に日本語対応した。ただし、東京リージョンでは対応していないので、リージョン選択に注意。https://aws.amazon.com/jp/blogs/news/amazon-comprehend-japanese/|
|無料で使える範囲|12ヶ月間で５M文字まで無料。月ごとの無料枠があるわけではなく、アカウント作成から１２ヶ月間の期限つきの無料枠。|
|クレジットカード登録の有無|必要。無料枠を使い切ると自動的に課金されるが、上限に近づいたらメールで通知する機能がある。|
|料金|リクエストは１００文字を１ユニットとして計算されて、各リクエストに月３ユニットが最低料金となる。料金は１０Mユニットまでは、ユニットあたり0.0001$なので、最小のリクエストを１０００リクエスト投げても、3$。|
|呼び出し方|言語ごとにAPIが準備されていて、それを叩く。戻りはJSON。|

# Azure Cognitive Services
|比較項目|調査内容|
|---------------|-------------|
|日本語対応の有無|日本語に対応した。ドキュメントも日本語対応している。|
|無料で使える範囲|Azureは無料枠が２つある。ゲスト・・・７日間の試用期間が与えられる。クレジットカードの登録は不要だが、試用期間終了後にデータが削除される。無料のAzureアカウント・・・有効期限のない無料プラン。１ヶ月５０００トランザクションまで無料。そのほかに22,500円のクレジットが付与される。コンテナ作成時にFreeレベルで作成しておけば、5000トランザックションを超えると制限がかかるため、自動的に課金されることはない。|
|クレジットカード登録の有無|ゲストは不要、無料のAzureアカウントは必要|
|料金|500,000テキストレコードで224円。１テキストレコードは1000文字。1300文字は２テキストレコードとなる。|
|呼び出し方|RESTで投げるとJSONで帰ってくる。.NETはAPIが準備されている。|


# IBM Watson Tone Analyzer
|比較項目|調査内容|
|---------------|-------------|
|日本語対応の有無|APIは日本語未対応。ドキュメントは日本語もあるが、詳細なドキュメントは英語。|
|無料で使える範囲|ライトアカウントであれば、１ヶ月あたり2,500件のAPI呼び出しが無料。標準アカウントの場合は、1,000回のAPI呼び出しまで無料。|
|クレジットカード登録の有無|ライトアカウントであればクレジットカードの登録は不要。|
|料金|250,000呼び出しまでは、１呼び出しあたり0.0088$。|
|呼び出し方|RESTで投げるとJSONで帰ってくる。SDKもある。|

# COTOHA
|比較項目|調査内容|
|---------------|-------------|
|日本語対応の有無|NTTコミュニケーションズのサービスなので、もちろん日本語対応している。|
|無料で使える範囲|for Developersプランだと、APIごとに１日１０００コールまで無料で利用可能|
|クレジットカード登録の有無|for Developersプランでは不要。ただし、アカウント登録時に所属企業・団体名と氏名が必要。|
|料金 |for Developersプランだと、APIごとに１日１０００コールまで無料で利用可能。for Enterprizeは月１３万円で月に約２６０万コール利用可能とあるが、呼び出すAPIによってコールあたりの料金携帯が違うので、「約」となっている。つまり、月１３万円までは定額だが、それを超える分については従量課金制となっている。初回登録から３ヶ月は無料で使える。ただし、紙面での申し込みが必要。|
|呼び出し方|RESTで投げると、JSONで帰ってくる。|



# まとめ
有名どころの5サービスについて2019年12月時点での日本語対応状況を調査をしたが、日本語の感情分析に対応したサービスが増えてきた。
自身の使っているサービスとの連携のやりやすさや、精度によって使うサービスを使い分けれるようになってきている。
AWS Chaliceでchalice localしているかどうかを判定する

# はじめに
AWS上で[API Gateway](https://aws.amazon.com/jp/api-gateway/)と[Lambda](https://aws.amazon.com/jp/lambda/)を使ってWEBサービスを作るときに便利なPythonフレームワークの[AWS Chalice](https://github.com/aws/chalice)。便利ポイントの一つが、`chalice local`コマンド一発で、手元のPC（ローカル）にWEBサーバが立ち上がって、AWS上で動かすものと同じものが動いてしまう、というところ[^1]。テストとデバッグがめちゃくちゃ捗ります。

# 課題
という便利な`chalice local`なんですが、ローカルで動かしていることをコードで判定する直接的な方法が無さそうだったので、考えてみました。
*きっかけは、[実施例](#実施例)にも示したとおり、AWS上で動かすときとローカルで動かすときでログのフォーマットを変えようとしたことです[^2]。*

# 解決方法
以下でできます。環境変数を活用します[^3]。

- chaliceの設定ファイル（config.json）で`chalice local`用のstageを定義し、定義したstageに適当な環境変数を設定する。
- `chalice local`するときには、上記で定義したstageを`--stage`オプションで指定する。

これにより、コード側では、環境変数の存在をチェックすることで、`chalice local`している（ローカルで実行している）かどうかを判定できるようになります。

## 実施例

### 設定ファイル
```javascript:config.json
{
  "version": "2.0",
  "app_name": "testapp",
  "environment_variables": {
  },
  "stages": {
    "dev": {
      "api_gateway_stage": "api"
    },
    "local": {
      "environment_variables": {
        "IS_LOCAL": "true"
      }
    }
  }
}
```
`local`というstageに、`IS_LOCAL`という環境変数をセットしています。

### コード本体
```python:app.pyの一部
import logging
import os

# setup logger
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logformat = (
    '[%(levelname)s] %(asctime)s.%(msecs)dZ (%(aws_request_id)s) '
    '%(filename)s:%(funcName)s[%(lineno)d] %(message)s'
)
if os.environ.get('IS_LOCAL'):
    logformat = (
        '[%(levelname)s] %(asctime)s.%(msecs)dZ '
        '%(filename)s:%(funcName)s[%(lineno)d] %(message)s'
    )
formatter = logging.Formatter(logformat, '%Y-%m-%dT%H:%M:%S')
for handler in logger.handlers:
    handler.setFormatter(formatter)
```
AWS上で動かすときとローカルで動かすときでログのフォーマットを変更しています[^2]。

### 実行方法
```
$ chalice local --stage local
```
`chalice local`するときには、定義したstageを`--stage`オプションで指定します。

# おわりに
この方法、`chalice local`に必ず`--stage`オプションを付ける必要があるところがいまいちですが、課題は確かに解決できているので活用してます。
*ログフォーマット以外での活用例があれば知りたい。。。*(-;

[^1]: [Tutorial: Local Mode - Quickstart and Tutorial — Python Serverless Microframework for AWS](https://chalice.readthedocs.io/en/latest/quickstart.html#tutorial-local-mode)
[^2]: すごく細かい話なんですが、`logging.Formatter`に渡すフォーマット情報のうち、`aws_request_id`はlamba上で動かすときにしか値が得られません。`chalice local`するときにこの情報を使っているとエラーが出てしまうので、AWS上かローカルかでログのフォーマットを変えてあげたくなります。
[^3]: [Environment variables on chalice local · Issue #748 · aws/chalice](https://github.com/aws/chalice/issues/748)
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "users" does not exist

アプリを初めてherokuにデプロイすると、下記のエラーが出た。

```
remote:        ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "users" does not exist
remote:        LINE 8:                WHERE a.attrelid = '"users"'::regclass
remote:                                                  ^
remote:        :               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
remote:                             pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
remote:                             c.collname, col_description(a.attrelid, a.attnum) AS comment
remote:                        FROM pg_attribute a
remote:                        LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
remote:                        LEFT JOIN pg_type t ON a.atttypid = t.oid
remote:                        LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
remote:                       WHERE a.attrelid = '"users"'::regclass
remote:                         AND a.attnum > 0 AND NOT a.attisdropped
```

下記の記事を見ていると、
初回herokuデプロイ時、deviseで紐付けているモデルでscopeを定義していると発生する様子。

参考
https://github.com/rails/rails/issues/36755

https://www.reddit.com/r/rails/comments/chtk5l/model_scopes_and_db_tables/

なのでscopeをコメントアウトし、再度デプロイ。

```
$ git push heroku master
```

するとデプロイが出来た。

デプロイ後、コメントアウトしていたscopeをコメントインし、再度デプロイするとscopeを反映させることが出来た。
勉強記録　12日目 〜mutable修飾子〜 - Effective C++ 第3版 -

#　はじめに

Effective C++ 第3版の3項14ページから勉強していきます。
今回は、「mutable修飾子」についです。

# Effective C++ 第3版 - 3項　可能ならいつでもconstを使おう -

## mutable修飾子

### mutable修飾子とは？

前回の投稿で、メンバ関数にconst修飾子を付けると、メンバ関数内でメンバ変数を変更していけないということを勉強しました。

```cpp
class ClassA {
 public:
  explicit ClassA(int x, int y) : x_(x), y_(y){};
  void       testFunc() const;
  int        getX() { return x_; };
  int        getY() { return y_; };

 private:
  int         x_;
  int         y_;
};

void ClassA::testFunc() const {
  std::cout << __func__ << std::endl;
  // x_ = 4;  // コンパイルエラー      // constメンバ関数内で、メンバ変数x_を変更したため
  // y_ = 3;  // コンパイルエラー      // constメンバ関数内で、メンバ変数y_を変更したため
}
```

上のコードのように、constメンバ関数 testFunc 内で、メンバ変数 x_, y_ を変更しようとすると、コンパイルエラーとなります。
しかし、const メンバ関数内でも、メンバ変数を変更(書き換え)したいときがあります。
このような場合に、 mutable修飾子をメンバ変数に付けます。

```cpp
class ClassA {
 public:
  explicit ClassA(int x, int y) : x_(x), y_(y){};
  void       testFunc() const;
  int        getX() { return x_; };
  int        getY() { return y_; };

 private:
  mutable int    x_;  // mutable修飾子を付ける
  int            y_;
};

void ClassA::testFunc() const {
  std::cout << __func__ << std::endl;
  x_ = 4;       // constメンバ関数内で、メンバ変数x_を変更しているが、x_に mutable修飾子を付けているため変更可能
  // y_ = 3;  // コンパイルエラー      // constメンバ関数内で、メンバ変数y_を変更したため(mutable修飾子が付いていない)
}
```

上のコードのように、mutableを付けることで、constメンバ関数内でもメンバ変数を変更できていることが分かる。

以下に、勉強で使用したコードを示します。

### サンプルコード

```cpp:3_const_mutable.cpp
#include <iostream>

class ClassA {
 public:
  explicit ClassA(int x, int y) : x_(x), y_(y){};
  void testFunc() const;
  int  getX() { return x_; };
  int  getY() { return y_; };

 private:
  mutable int x_; // この変数は、constメンバ関数
  int         y_;
};

void ClassA::testFunc() const {
  std::cout << __func__ << std::endl;
  x_ = 4;
  // y_ = 3; // コンパイルエラー
}

int main(int argc, char* argv[]) {
  std::cout << "3_const_mutable.cpp" << std::endl;
  ClassA cc(1, 2);
  cc.testFunc();
  std::cout << "x : " << cc.getX() << std::endl;
  std::cout << "y : " << cc.getY() << std::endl;
}
```

### 実行結果

![3_const_mutable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367151/23281925-25d8-5dc3-4c40-801e944f4b53.png)

## 参考文献

・https://www.amazon.co.jp/gp/product/4621066099/ref=dbs_a_def_rwt_hsch_vapi_taft_p1_i0