OmniAICreator/Qiita-1.07M huggingface dataset:
【公式私家訳】Reduxの基本概念：Actions(アクション), Reducers(リデューサ), Store(ストア)とは何か？

# はじめに

　目下、reduxを使ったフロントエンド開発に従事している。そのさなか、teratailでの回答に対するコメントで、アクション、リデューサ、ストアとは？ にお答えする機会があった。こういう基礎知識を自分が点検する機会を作るためにteratailに回答しているようなものなのでまとめておく。
　アクション、リデューサ、ストアとは何か？
　こといった基本知識、特に基幹となるフレームワークのコアとなる諸概念の定義を問われたときにやってはいけないことは、自分の語彙や想像の範囲にある言葉で勝手な説明を作ってしまうことだと考えている。そうやって「俺のリダックス」なるものを作ってしまうのはいただけない。ということで、公式から引用、翻訳する。



# Actions (アクション）

[https://redux.js.org/basics/actions](https://redux.js.org/basics/actions) より引用。

> Actions are payloads of information that send data from your application to your store. 
･･･
> Actions are plain JavaScript objects. Actions must have a type property that indicates the type of action being performed.


以下は、上記を私家訳して箇条書きにしたもの。

---
【私家訳】
- アクションは情報の[ペイロード](https://www.weblio.jp/content/%E3%83%9A%E3%82%A4%E3%83%AD%E3%83%BC%E3%83%89%E3%83%87%E3%83%BC%E3%82%BF)で、アプリケーションからstoreにデータを送るものである。
- アクションは、Javascriptのプレーンオブジェクトである。
- アクションは、そのアクションが行うことを示唆するtypeプロパティを持っていなければならない。

---

# Reducers (リデューサ）

[https://redux.js.org/basics/reducers](https://redux.js.org/basics/reducers) より引用。

> Reducers specify how the application's state changes in response to actions sent to the store. Remember that actions only describe what happened, but don't describe how the application's state changes.


以下は、上記の私家訳

---
【私家訳】
リデューサーは、ストアに送られるアクションに対応して、アプリケーションの状態がどのように変わるかを明示する。アクションには、何が起こったかだけが記述されており、アプリーションの状態変更については何も記述されていないことを銘記されたい。

---


# Store (ストア）

[https://redux.js.org/basics/store](https://redux.js.org/basics/store) より引用。

> In the previous sections, we defined the actions that represent the facts about “what happened” and the reducers that update the state according to those actions.
>
The Store is the object that brings them together. The store has the following responsibilities:
>
・Holds application state;
・Allows access to state via getState();
・Allows state to be updated via dispatch(action);
・Registers listeners via subscribe(listener);
・Handles unregistering of listeners via the function returned by subscribe(listener).

以下は、上記の私家訳

---
【私家訳】

前節（上記に引用したアクションとリデューサーの説明）において、アクションを「何が起こったか」を表すものとし、リデューサを、アクションによって状態を更新するものとして定義した。ストア（The Store)は、それら（アクションとリデューサー）を引き合わせる。ストア（The Store)は、以下の責務を持つ。

・アプリケーションの状態を保持する。
・アプリケーションの状態に対しては、`getState()` で参照する。
・状態の更新は、`dispatch(action)` によって行う。
・リスナーの登録は、`subscribe(listener)` によって行う。
・リスナーの解除は、`subscribe(listener)` の返す関数によって行う。

---



# 補足： Reducers (リデューサ） とは何か？を補強する私見

※以下は私見（In My Opinion）なので、考え方として採用するかは、読者の皆様におまかせします。

---
【IMO】
個人的には、リデューサとは、[決定性有限オートマトン](https://ja.wikipedia.org/wiki/%E6%B1%BA%E5%AE%9A%E6%80%A7%E6%9C%89%E9%99%90%E3%82%AA%E3%83%BC%E3%83%88%E3%83%9E%E3%83%88%E3%83%B3)でいえば、状態遷移関数に相当するものと理解している。つまり、オートマトンの状態集合Q、文字集合Σとするときの、状態遷移関数 δ : Q × Σ → Q が、リデューサに相当する、というのが個人的なイメージ。

---

もし、「リデューサーを、オートマトンの状態遷移関数になぞらえるのはよろしくない」というご意見の識者の方がいらっしゃいましたら、ぜひ、その理由を伺って勉強させて頂きたいので、コメント頂ければ幸いです。
そろそろtandemで令和のコミュニケーションしよう

はしがき

リモートワークのコミュニケーションってどうしていますか？
私の所属しているチームは、
分報（Slack）＋常時接続VC[^1]（Discord）で程よくコミュニケーションを取っています。[^2]

しばらく運用していてとても平和だったので、これでエンドゲーム[^3]かなって思っていたら・・・

つよつよのプロダクトを見つけてしまいました。。。

**この記事には画像など（少ししか）ないです**

# tandem

公式： https://tandem.chat/

チームで使えるVCツールで、Discordを少しだけコワーク寄りにした感じです、

## つよつよポイント

### Discord感覚でZoomレベル[^4]のコミュニケーションができる

<img width="233" alt="Screen Shot 2020-05-21 at 1.17.37 PM.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426991/fe4f838e-1a8e-9d9e-a8fe-4c11d431943e.png">

Discord、触ったことがある方はご存知かと思いますが、
**VCまでのハードルが限りなく低い**です。

1. 起動する
2. 予め作られているVC部屋に入る

これだけです

ZoomやらWebex Meetingsのように、部屋を都度作り、接続先を共有する必要がありません。
例えるなら、仮想の会議室に入るイメージです。

これと同じことが**tandemでもできます**。

その上で**複数人の同時画面共有**や**Webカメラの配信共有**が可能です。
これをつよつよコミュニケーションツールといってなんと言いましょう。

### チームメンバが今使っているアプリ・ツールがわかる

これ、結構嬉しいのではないでしょうか。

- 話しかけたいけど作業してたらどうしよう
- コーディング中は話しかけられたら困る

のようなちょっとした心理的ハードルを下げること請け合いです。
ちなみに、CloudのOffice製品やGoogle製品など、共同編集が可能なものは
表示されるアイコンから直接遷移なんかもできちゃいます。

<img width="163" alt="Screen Shot 2020-05-21 at 1.17.44 PM.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426991/b055684a-bbf9-e335-792a-173b48764511.png">

### Quick Share

アクティブなブラウザのタブのページを、
**ショートカットキー一発で同じルームにいるユーザに通知で送る**[^5]ことができます。
何気に一番使ってます。
アドレスバーからURLをコピペしてチャットで送る、といった、
**前時代的な行動**をする必要がありません。

### ルームを作らなくても、1-1のチャット・VCができる

Discordはルームを作成し、そこに入らないとVCができません。
かえって、tandemではメンバを選択して 1 - 1 でコミュニケーションを取ることが可能です。
電話レベルの気軽さです。

### 画面共有している時に閲覧者のマウスカーソルが見える

言わずもがな、便利です。
リモートの欠点として挙げられやすい、ここ、そこ、ができます。

### オンラインなメンバをVCルームにインバイトして話しかけられる

いきなり話しかけられるやつ、賛否両論ありそうですが、
嫌ならBusyにしておけばいい話でもあります。
＃オンサイトでもいきなり話しかけられることはありますし、リモートに限った話ではない


## まとめ

- tandemはDiscord感覚でコミュニケーションを開始できる
- 複数人が同時に画面共有できるので、誰が何してる？などもわかる
- 画面共有時は閲覧者のカーソルが見えるので、誰が見ているか、がわかる
- 見ているページのリンクをショートカットで送ることができる（重要）
- VCに入っていないオンラインメンバをインバイトできる

## 最後にもう一回公式

https://tandem.chat/

おわり

[^1]: 'video conferencing' or 'voice chat'
[^2]: いずれも任意参加。コミュニケーションを課題にしていないメンバは入っていない。
[^3]: 求道の果てに見えるもの。
[^4]: 諸説あり、Zoomは片手で数えられるくらいしか使ってない。
[^5]: Airdropのような感じ。
RAK811 LoRa Tracker Board用のケースを作ったよ

RAK811 LoRa Tracker Boardは小型で良いのですが、ケースが存在しませんでした。
そこでRAK811 Tracker with add-on boardを基にケースを製作してみました
RAK811 Tracker with add-on board
https://grabcad.com/library/rak811-tracker-with-add-on-board-1

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/0ba4fa80-f2ab-e198-2169-9e3bf74d0016.png" alt="" width="300" height="">
![DSC_0375 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/3019184d-873e-71b0-6af8-2114303043ac.jpeg)

Githubにケースのデータをアップロードしています。
https://github.com/taisirou/RAK811-Tracker-Board-case
さわっておぼえるDocker入門🐳#5（Dockerfileを作る＋ボリュームを扱う）

# はじめに

Dockerコンテナでボリュームをマウントし扱う方法を学びます。

DBやファイルなどを扱う際は、ボリュームをマウントします。
コンテナでボリュームをマウントするのには、理由があります。
コンテナ内にデータを保存してしまうと、コンテナを削除したり移動した際に、保存したデータがなくなってしまうかもしれないからです。

そのため、Dockerではデータへの参照を主に扱い、**コンテナが消えてもデータは消えない形での運用が基本となります。**


# 目的

**Dockerを触りながら、コンテナにボリュームをマウントする方法を学ぶ**

今回は、下記の操作を行います。

- 簡単なDockerfileを自作する
- Dockerボリュームを指定してコンテナを起動




# 環境

- macOS Mojave 10.14.6
- Docker engine 19.03.5


# コンテナをアレコレしてみる

公式のnginxイメージで表示されるデフォルトの画面を変更してみます。

## まずはデフォルトの画面を見てみる

まずは公式nginxイメージからコンテナを立ち上げ、デフォルト画面を確認してみます。


```bash
docker container run -d --name nginx -p 80:80 nginx
```

ブラウザで`localhost`を開くと、デフォルトの画面が表示されます。

<img width="666" alt="スクリーンショット 2020-04-17 17.32.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452235/834f6b1f-4798-8d0e-f41e-7d796ef3788d.png">


## デフォルト画面を変更する

表示される画面を変更するために、公式イメージから自作のイメージを作成します。


### Dockerfileを自作する

適当なフォルダに`Dockerfile`という名前のファイルを作成します。これが自作イメージになります。（たった3行ですが...）


```dockerfile:Dockerfile
FROM nginx:latest

WORKDIR /usr/share/nginx/html

COPY index.html index.html
```

また、デフォルト画面として表示する`index.html`ファイルを作成しておきます。

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>My test page</title>
  </head>
  <body>
    <h1>くじらコンテナ🐳</h1>
  </body>
</html>
```


#### `FROM`

公式のnginxイメージをカスタマイズしていきます。
`FROM`で自分のイメージの元として現在の公式リポジトリを使います。

```dockerfile
FROM nginx:latest
```

#### `WORKDIR`

`WORKDIR`は、その名の通りコンテナ内の作業ディレクトリを指定します。

```dockerfile
WORKDIR /usr/share/nginx/html
```


#### `COPY`

`COPY`は、ローカルのファイルをコンテナにコピーします。
ここでは、`Dockerfile`と同じディレクトリに存在する`index.html`をコンテナ内に保存しています。


### 自作イメージからコンテナを立ち上げる

では、今作ったイメージからコンテナを立ち上げます。
先ほど`Dockerfile`を作成したディレクトリで、以下のコマンドを実行します。

```bash
docker container run -d --name nginx2 -p 8080:80 -v $(pwd):/usr/share/nginx/html nginx
```

### `-v`オプション

`-v[ホストディレクトリの絶対パス]:[コンテナの絶対パス]`で、ボリュームをコンテナにマウントできます。

今回コンテナにマウントしているのは、先ほどのローカルディレクトリです。

以下のコマンドについて説明します。

```bash
-v $(pwd):/usr/share/nginx/html
```

- `$(pwd)`：これはDocker関係ないのですが、現在のディレクトリまでのフルパスです
- `/usr/share/nginx/html`： Dockerファイルで指定した作業ディレクトリです

ローカルのディレクトリがコンテナからも参照されている状態になっています。



### ブラウザで確認する


`-p`コマンドで指定した`8080`番ポートをブラウザで確認すると...

<img width="355" alt="スクリーンショット 2020-04-17 17.58.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452235/320c0497-32ee-5e4d-6a2c-ea4a4981c177.png">


自作の画面が表示されました！


# まとめ

今回は

- 自作のDockerfileを作成する
- Dockerボリュームを指定してコンテナを起動

しながら、実際にコンテナにボリュームをマウントしてみました。
Azure App Service on Linux に Python Flaskアプリをデプロイ

こちらに記載されている内容とほとんど同じです。
https://docs.microsoft.com/ja-jp/azure/app-service/containers/quickstart-python?tabs=bash

# Azure CLI のインストール
```bash
brew update && brew install azure-cli
```
https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli?view=azure-cli-latest

# サンプルのダウンロード
```bash
git clone https://github.com/Azure-Samples/python-docs-hello-world
```

# サンプルを実行する
```bash
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
export FLASK_APP=application.py
flask run
```
Web ブラウザーを開き http://localhost:5000/ にアクセスして、"Hello World! " というメッセージが表示されていることを確認。

# Azure へのサインイン
```bash
az login
```

# 使用できるリージョンの確認
```bash
az account list-locations 
```

# デプロイ
az webapp up コマンドを実行すると、App Service 上に Web アプリが作成され、コードがデプロイされます。

```bash
az webapp up --sku F1 -n <app-name> -l <location-name>
```

実行例

```bash
az webapp up --sku F1 -n test-app -l japanwest
{
  "URL": "http://test-app.azurewebsites.net",
  "appserviceplan": "taro.yamada_asp_Linux_japanwest_0",
  "location": "japanwest",
  "name": "test-app",
  "os": "Linux",
  "resourcegroup": "taro.yamada_rg_Linux_japanwest",
  "runtime_version": "python|3.7",
  "runtime_version_detected": "-",
  "sku": "FREE",
  "src_path": "//Users//fjunya//Documents//PyCharm//pa_workspace//Ibasho-Qanat-Stub"
}
```
結果に表示されたURLにアクセスするとアプリにアクセスが可能です。

--sku F1 引数を使用すると、Free 価格で Web アプリが作成されます。 この引数を省略すると、Premiumを使用することができます。その場合、時間単位のコストが発生します。

# 更新の再デプロイ
```bash
az webapp up
```

以下のエラーが出た場合はsubscriptionを指定すれば更新可能です。

```
Webapp pbx-api-stub already exists. The command will deploy contents to the existing app.
Unable to retrieve details of the existing app pbx-api-stub. Please check that the app is a part of the current subscription
```

```bash
# subscriptionを指定
az webapp up --subscription b43fdb54-b148-4d60-a89f-xxxxxxxxxxxx
```
【Vue.js】条件分岐で要素を表示/非表示（v-if・v-showディレクティブ）

## はじめに
Vueでは```v-show```と```v-if```を用いることで条件分岐により要素の表示/非表示の切り替えを行うことができる。

## v-if　v-show
指定した値の真偽値によって要素を表示/非表示にする。

```sample.html
<template>
 <!-- showの値がtrueの場合はpタグが表示され、falseの場合は非表示 -->
 <p v-if="show">テキスト</p>
 <p v-show="show">テキスト</p>
</template>
```
```sample.js
new Vue({
  el:'#app',
  data: {
    show: true
  }
})
```

## v-ifとv-showの違い
下記のコードは条件を満たさなかった場合の両者の状態↓

```sample.html
<!-- v-if -->
<!---->
<!-- v-show -->
<p style="display: none;">テキスト</p>
```
v-ifはコメント化され、v-showはスタイルが付与されている。

##### v-if
条件が満たされなかった場合、DOM要素自体が削除される。

##### v-show
スタイルとして```display: none;```が付与され非表示の状態になる

#### DOMとは？
HTMLやCSS、javascriptなどによって構築されたものをブラウザが解釈したもの。
ブラウザのデベロッパーツールなどで見ることができるソースコードはDOMツリーと呼ばれるDOMの表現。

## v-ifのグループ化
v-ifは単一な要素に付与する必要があるが、いくつかの要素を同時に切り替えたい場合は```<template>```タグで囲うことでまとめることができる。
※v-showでは利用できない

```sample.html
<template v-if="show">
 <p>タイトル</p>
 <p>テキスト</p>
</template>
```

## v-else-ifおよびv-elseによる条件分岐
Vueでもif文のように複数の条件分岐が可能。```v-else-if```と```v-else```を組み合わせることで複数の条件を指定できる。

```sample.html
<template>
 <p v-if="type === A">
   タイプは A
 </p>
 <p v-else-if="type === B">
   タイプは B
 </p>
 <p v-else>
   A でも B でもない
 </p>
</template>
```
v-else-ifとv-elseはv-ifまたはv-if-elseを付与した```要素の直後でなければ機能しない。```
↓以下のようにpタグにv-ifを付与した場合、複数のpタグはそれぞれネストして子要素となっており連続していないので要素を表示/非表示することはできない。

```sample.html
<template>
  <div>
    <h2>タイプ</h2>
    <p v-if="type === A">
       タイプは A
    </p>
  </div>
  <div>
    <h2>タイプ</h2>
    <p v-else-if="type === B">
       タイプは B
    </p>
  </div>
</template>
```
今更ながらWPFに置き換えてみる（12）

#時報機能
いくつかのボケ問題は未解決ですがメイン機能はほぼ形になりまして一点残るのが時報機能。指定時刻または毎正時にバルーン的なお知らせが表示される機能です。
こんなやつ↓
![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590512/724cdd1d-a191-5633-06e6-6042353a241b.png)


普通Toastとかを使うんかもしれませんがコンポーネントを知らない悲しさから、VB＋FORMS版では子FORMを作成しメイン側から指定時刻に呼び出し、子FORM側に別途設定したタイマーで透明度を加算・減算してフェードIN・OUT表現と、表示時間を調整してました。VB↓

```VB
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        'Timer intavalは20?位だったはず
        Me.ticks.Text = CInt(Me.ticks.Text) + 1
        Select Case CInt(Me.ticks.Text)
            Case Is <= 100　
                Me.Opacity += 0.01   '2秒かけてフェードIN
            Case 101 To 300          '4秒間通常表示
            Case 300 To 400          '2秒かけてフェードOUT
                Me.Opacity -= 0.01
            Case Is > 400            '終わったら終わる
                Me.ticks.Text = "0"
                Me.Timer1.Enabled = False
                Me.Hide()
            Case Else
        End Select
        If Me.sec.Text <> Mid(Now.ToString("yyyyMMddHHmmss"), 13, 2) Then
            Call MakeClockImage()  'お知らせ内にアナログ時計描画
            Me.sec.Text = Mid(Now.ToString("yyyyMMddHHmmss"), 13, 2)
        End If
        Me.Refresh()
    End Sub
```
当初NotifyIcon用にインストールしたHardcodet.NotifyIconにある機能を使おうかと考えたんですが、お知らせ画面内のアナログ時計をリアルタイムで動かしたいので、VB版と類似した方法で行くことにします。

#GRIDVIEWでの残念な点
個別設定した時報情報をリスト表示する機能で、FORMS版のLISTVIEWでは普通にIMAGELISTを準備して、AddItemするといい感じでアイコンをつけて登録でき、削除するときもマウスポインタで領域選択することで一気に削除できました。
![listview_itemdelete.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590512/ed5c385f-4756-f82d-2944-b70bfa941125.gif)

WPF版ではGridviewを利用してXAML側でアイコンをつけて表示してるんですがマウス操作するとDragMoveが生きちゃってそうした選択ができず、クリックしての選択しかできないっぽくてやや残念。
![listview_itemdelete2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590512/e8728da7-dd33-a4a2-011f-b17a37fcedcd.gif)

#追記 プレデター文字
DrawLineでセグメント数字描画するロジック、ミスったらいきなりプレデター風味に。そういえばゲームが出るんたっけ・・。
![listview_itemdelete3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590512/088a88d6-516e-24c3-7c5e-608eef407e1c.gif)
[Rust] ブラウザで LaTeX を MathML に変換するツールを作成した話 [WebAssembly]

お久しぶりです, 先月の Qiita の炎上騒ぎで自ブログを作成しようかと思い, [zola](https://github.com/getzola/zola) を使ってみて悪くなかったんですが, 数式の扱いが不満だったので Rust で静的サイトジェネレータを自作していました. ですが完成する前に公開したい記事が溜まってきたので Qiita も使うことにします. 自作のジェネレータもおおよそ形にはなってきたので近々移行するかもしれません. 自ブログなら技術記事でない数学/物理の記事も書けますし.

それで, 静的サイトジェネレータで使うため[^1]に LaTeX 数式を MathML に変換する処理を Rust で実装したんですが, pure Rust なのだからブラウザでも動くはずと思い, 試しにブラウザで LaTeX を MathML に変換するアプリを作成してみました. もともと純粋な技術実証目的だったのですが, よく考えたらこれはこれで有用なツールだし, 必要な人もいるのではないかなと思い, 記事にまとめてみます.


# ツールについて

成果物はこちら: https://osanshouo.github.io/latex2mathml-web/index.html

![Screenshot_2020-04-17 LaTeX to MathML(4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466807/005069ff-b7c0-0aaf-ba36-ab8e17285fd1.png)

見たらわかると思いますが, テキストボックスに LaTeX を入力して Convert to MathML! ボタンを押すと変換処理が走って下のボックスに MathML が表示されます.

![Screenshot_2020-04-17 LaTeX to MathML(5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466807/7c60a602-003a-5b7f-c620-188e532b6b12.png)

数式の表示はもちろん MathML を用いているので, Firefox と Safari では表示されるはずですが, Chrome では正しく表示されません (MathML への変換自体は WebAssembly に対応するすべてのブラウザでできます). 早ければこの夏には Chromium に MathML が実装されると聞きましたが, どうなるんでしょうね, 待ち遠しいです.

なお, すべての処理はブラウザで完結しているため, サーバーに入力内容を送信するといったことは起こりません. いったんロードしておけばオフラインでも使えるんじゃないでしょうか.


# 技術的詳細

## LaTeX to MathML

「[[Rust] 『Go言語でつくるインタプリタ』Rustで読了](https://qiita.com/osanshouo/items/d1b18c90e06670d602fa)」という記事で書いたように, 2 月に Rust でインタプリタの実装をしていました. その経験のおかげで LaTeX の構文解析はすんなり実装できました. 技術的には前の記事で書いたものとほぼ同じで, 例えば `\frac{ 1 }{ 2 }` だったら子をふたつ持つノード, というように入力から構文木を生成し, それを XML にフォーマットします. Monkey との違いは MathML を出力する際に attribute が必要だったりするくらいです. 詳細は[ソースコード](https://github.com/osanshouo/latex2mathml)を見てください.

ただ, 複雑な添え字 (上下添え字が入り乱れるものや, ${}_n C_k$ みたいなもの) は `<mmultiscript>` を使うべきなんですが, 差し当たりそれは諦めてシンプルに `<msub>` と `<msup>` で実装したのであまり美しくないかもしれません. これに関しては LaTeX を機械的に MathML に置き換えるという部分に若干無理があるような… あと案外プライム ($x'$ のような) のお行儀が悪くて面倒でした.

## WebAssembly で使う

この部分も『[[Rust] WebAssemblyを用いたウェブフロントエンド開発入門](https://qiita.com/osanshouo/items/40f087cc79a1446ad7ef)』という記事で説明した通りですね. 自作の latex2mathml クレートに依存する Rust プロジェクトを作成し, wasm-pack でビルドして GitHub Pages で公開するだけで完成です.

なお変換に失敗したときの処理をさぼっていて, エラーが発生すると何事も起こりません. エラーメッセージが表示されるように改良しなければ…


# 感想

上で書いたように, 過去に自分で Qiita の記事にまとめた経験が生きた感じで, 基本的に大きな問題なく完成しました. それにしても誰が使うのかわからない謎の LaTeX コマンド (`\leftrightsquigarrow` ↭ とか `\boxbox` ⧈ とか `\beth` ℶ とか `\from` ⌢ とか) をひたすら定義する部分は単なる修行でしたが…

行列などで `\begin{pmatrix} ... \end{pmatrix}` となっている部分のパースだけは汚くなってしまったのが気になりますが, done is better than perfect ということで許してください. 通常使われるたいていの記法には対応しているはずです (していなければ issue を立てて欲しいです). Feynman スラッシュにも対応しています.


[^1]: 本当は `cargo doc` で生成される HTML に数式 (MathML) を埋め込むことが本来の目的です. 既に必要な機能は実装が終わっているんですけど, どういう形式で公開すべきか迷ってて… 普通に `cargo install` できたら嬉しいですかね？ docs.rs で数式を使おうと思うなら本家 `rustdoc` にパッチを送るべきなんでしょうが, それは大変すぎるし, どうしたものか…
MS Learnおすすめラーニングパス 4月号 【Azure試験合格編】

## MSLearnのおすすめラーニングパス第3弾！【Azure試験合格編】


自宅勤務を機会にスキルアップしてみませんか？4月は、Azure関連のマイクロソフト認定試験に合格するためのMSLearnのラーニングパスを紹介します！

  - [AZ-400：Microsoft Azure DevOps Solutions【約21時間】](https://aka.ms/AZ-400-DevOps-LP)：[AZ-400試験](https://aka.ms/AZ-400-JPN)に合格するためのラーニングパス
    - エンドユーザーニーズとビジネス目的に合うように、継続的に価値ある製品やサービスを提供するために人々やプロセスやテクノロジを結びつけるDevOpsプロフェッショナルを育てる試験です。継続的な統合、テスト、配信、および監視とフィードバックを可能とするための、アプリケーションコードとインフラストラクチャの戦略を設計し実装できるかが問われます。

  - [AZ-103: Microsoft Azure Administrator【約25時間】](https://aka.ms/AZ-103-Azure-Administrator-LP)：[AZ-103試験](https://aka.ms/AZ-103-JPN)に合格するためのラーニングパス
    - ストレージ、セキュリティ、ネットワーキング、コンピューティング Cloud機能にまたがる Cloud サービスを管理する方のための試験です。適切なリソースのプロビジョニング、サイズ設定、監視、調整と同様、最適なパフォーマンスおよび規模で使用するサービスを推奨できるかが問われます。

  - [AZ-120: Designing and Deploying SAP on Azure【約8時間】](https://aka.ms/AZ-120-SAP-on-Azure-LP)：[AZ-120試験](https://aka.ms/AZ-120-JPN) に合格するためのラーニングパス
    - Azure for SAP Workloads のアーキテクトは、SAP アプリケーション、SAP HANA、S/4HANA、SAP NetWeaver、SAP BW、SAP アプリケーションとデータベース用の OS サーバー、Azure Portal、ARM テンプレート、オペレーティング システム、仮想化、クラウド インフラストラクチャ、ストレージ構造、高可用性設計、災害復旧設計、データ保護の概念、およびネットワークの優れた経験および知識を有することが求められます。

  - [DP-100：Azureでデータサイエンスソリューションを設計および実装する【約9時間】](https://aka.ms/DP-100-Azure-Data-Science-LP)：[DP-100試験](https://aka.ms/DP-100-JPN)に合格するためのラーニングパス
    - ビジネスの目的を満たすためのAIソリューションを構成するモデルのトレーニング、評価、デプロイする機械学習テクニックが問われる試験です。自然言語の処理、会話、コンピュータービジョン、予測的分析をするアプリケーションを使用します。

  - [AI-100:Azure AI ソリューションのデザインおよび実装【約10時間】](https://aka.ms/AI-100-Azure-AI-Solution-LP)：[AI-100試験](https://aka.ms/AI-100-JPN)に合格するためのラーニングパス
    - Azure AI ポートフォリオを構成するコンポーネントと利用可能なデータ ストレージ オプションの理解；Cognitive Services、Azure ボット、Azure Search、および Azure のデータ ストレージを使用する AI ソリューションの実装；特定の要件を満たすためにカスタム API をいつ開発する必要があるかの理解などが問われる試験です。

※ [MS Learn](https://aka.ms/MSLearn-Japan)はマイクロソフトのラーニングプラットフォームです
【小ネタ】GASでHTMLをレンダリングするテンプレート

## 概要
小物制作でGASでWEBページを作ることがあるのですが、都度他プロジェクトからコピペしていたので、テンプレートとして残しておきます。

## コード
```g_main.js
function doGet(e) {  
  //スマホ表示に対応させる呼び出し方　GASではHTML内のviewportが反応しない
  var htmlOutput = HtmlService.createTemplateFromFile("h_index.html").evaluate();
  htmlOutput
    .setTitle('test')
    .addMetaTag('viewport', 'width=device-width, initial-scale=1')
  return htmlOutput;
}
```

```h_index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= HtmlService.createHtmlOutputFromFile('h_style.html').getContent(); ?>
    <?!= HtmlService.createHtmlOutputFromFile('h_script.html').getContent(); ?>
  </head>
  <body>
    <div class="container">
      <p class="target">これはテストメッセージです。</p>
      <input type="button" value="ボタン" onclick="OnButtonClick();"/>
    </div>
  </body>
</html>
```

```h_style.html
<style>
.container{
  line-height:200px;
  background-color:#eeeeff;
  text-align:center;
  border:#0000ff solid 3px;
}
.container .target{
  display:inline-block;
  vertical-align: middle;
  line-height:normal;
}
</style>
```

```h_script.html
<script language="javascript" type="text/javascript">
  function OnButtonClick() {
    alert('アラートです。');
  }
</script>
```

## 備考
* `公開->WEBアプリケーションとして導入` でWEBサイトのURLを取得できます。
* GASエディタはファイル名でソートされるようなので、g_ や h_ から始めるようにしています。
Active StorageのvariantでAnimated GIFを変換する

# TL;DR
このように書けば、Animated GIFを変換できます。

```ruby
image.variant(
  loader: { page: nil }, # GIFアニメーションの全フレームを変換する
  scale: '50%', # 1/2の大きさにする
  coalesce: true, # アニメーションシーケンスの最適化
  deconstruct: true, # アニメーションシーケンスの最適化2
  dither: true, '+': true, # エイリアシングを無効化して処理を早くする
  layers: 'Optimize', # GIFアニメーションを最適化
)
```

# コツ
重要なのは`loader: { page: nil }`というオプションで、**variantはデフォルトでは最初の1フレームしか変換を掛けてくれません**。なので、pageの指定を無くすことで全フレームに対して変換を掛けます。

coalesceオプションとdeconstructオプションについては、下記のサイトが詳しいと思います。
https://unoh.github.io/2008/12/11/imagemagickgif.html

あとは`+dither`というオプションの書き方です。`dither: true`と書くと、`-dither`というオプションになってしまいます。
今回は`+dither`で実行したいので、そういう場合は一度`dither: true`と宣言した直後に`'+': true`と書くことで、`+dither`というオプションにしてくれます。
...combine_options(Rails6から非推奨)で使っていた手法をそのまま持ってきたのですが、このやり方のドキュメントが見つからず苦労しました。正直ここの理屈も分かっていません。分かる方がいらっしゃったら、編集リクエストを送って頂くか、コメントにてご教授頂けると幸いです。
【Bootstrap】モバイルに適応されない時の対処法

Railsアプリのフロントをコーディングする時bootstrapを利用したのですが、
モバイル表示がちゃんとされてなかったので解決方法のメモ。

結論から言えばhtmlファイルのhead部分に以下を追加してない場合がほとんどです。

```erb:application.html.erb
< meta name="viewport" content="width=device-width, initial-scale=1">
```
viewportとはスマホ対応のレスポンシブデザインにする際に必要なmetaタグです。

これが無かったらなんかものすごく画面が小さく表示されてしまうので、そんな時はこいつを疑ってみてやってください。
【自分用メモ】pyenvメモ

## インストール可能なバージョン一覧の確認
```
$ pyenv install --list
```

## Pythonをインストール
```
$ pyenv install 3.8.2
```

## バージョンの切替え
```
$ pyenv local 2.7.10
$ pyenv global 3.5.0
```

## 現在のバージョンの確認
```
$ pyenv version
```

## インストール済みのバージョン一覧確認
```
$ pyenv versions
```
[ Mac ]パスを通してもコマンドライン（iterm）からVScodeが立ち上がらん！を解決!! 


今回ぶつかった問題は、
> iterm2からVscodeを起動するコマンド `code` が使えない問題

それでは本題へ
ちなみに参考にしたサイトはこれ
>
[Macで再起動するとVSCodeのパスが通らなくなる](https://maretol.hatenablog.jp/entry/2018/07/24/111857)

##ぶつかった問題点
 本来の挙動は、
`code`をitermで実行した時に、Vscodeが立ち上がるはず
しかしできない！

##ネット上に転がってる対応を・・・。（しかしこれじゃ解決できない）
ネット上に転がってる情報はこういうもの
1. Vscodeを開く
2. `Cmd + shift + p`を実行
3. `shell`で検索
4. `shell command install 'code' command in PATH`を選択してPATHを通す
5. 終了

というもの
しかしこれじゃ立ち上がらない！

ネットで調べても見つけれず、2ヶ月ほどこのままに・・・。

そして今回2ヶ月ぶりにリベンジ！


##解決策
結論から言うと、
`iTerm`をドラッグでダウンロードファイル→アプリケションに移動するといい




PATHの位置と、実際の場所がズレていたらしい。

単純なミスだが、こんな記事が為になる人がいたら嬉しい。
database.ymlのパスワード管理方法2パターン -環境変数とcredentials.yml.encの使用-

database.ymlにユーザー名やパスワードを平文で入力しGithub等にあげてしまうと、セキュリティ上の問題が発生する。そこで何かしらの方法で隠す必要があるが、その時の２つのパターンを説明します。

#●環境変数の使用

```ruby:database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>
  host: localhost
```
<%= ENV['DB_USERNAME'] %>に該当する部分が環境変数を利用している部分です。
このコードを記載しておき

```
$ export DB_USERNAME =sample_user
$ rails server
```
と実行すれば、<%= ENV['DB_USERNAME'] %>の部分にsample_userが代入され実行される。

#●credentials.yml.encの使用（rails5.2以降）
rails5.2以降では、credentials.yml.encを使用し、管理する方法がある。
vimを使用するため、アレルギーを発症する人もいるかもしれない（自分がそう）ですが、慣れておくと今後便利なので、できればこちらの方法をおすすめします。
使用方法は

```ruby
$ EDITOR="vi" bin/rails credentials:edit
```

```ruby:credentials.yml.enc
db:
  username: sample_user
  password: sample_password
```
このように情報を格納し、出力時は

```ruby:database.yml
default: &default
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  host: localhost
```
とすることで代入され実行できる。　
ちなみにvim実行時のコマンドで、本当に最低限覚えておく必要があるもを下記にまとめました。本当に最低限なので、別途学習してください。

・コマンドモード
vim実行時の最初の状態。最低限のコマンドを下記に記載

```
:wq #ファイルを上書き保存して終了
:q  #上書きせずに終了
：q! #上書きせず強制終了
shift+zz #ファイルに変更があれば保存して終了、なければ上書きせずに終了
```
・インサートモード
コマンドモード時、iを押すと切り替わり、入力ができるようになる。コマンドモードへ戻る際は、escキーを押す。

#●まとめ
パスワード管理方法をまとめた。AWS周囲をいじるとvimを使用する機会が増えるため、これからポートフォリオ作成を行うレベル感の方は、慣れておく意味でもcredentials.yml.encの使用をおすすめします。
Fast-ForwardマージとNon Fast-Forwardマージ

# 前提条件を仮定する

- masterブランチからfixブランチを派生させている。
- そこからfixブランチは複数回コミットをしている
- masterブランチは変更なし

# Fast-Forwardマージ

**今回の前提条件の場合、gitはデフォルトでFast-Forwardマージをします。**

## masterブランチにfixブランチをマージする

- fixブランチはmasterブランチの履歴を全て含んでいる。
- masterブランチは移動するだけでfixブランチの内容を読み込むことができる。これをFast-Forwardマージという。
- つまり、**マージする際に新しいコミット(=マージコミット)を作成しなくてよい。**

## デメリット

- fixブランチでコミットをし、masterブランチにFast-Forwardマージするということは、結果的にはmasterブランチに直接コミットしたのと変わらない。
- つまり、**「ブランチをマージした」という履歴が残らない。**
- 具体的な弊害
    - 間違えてfixブランチをマージした場合にどこまでがfixブランチでのコミットかわからないため、マージを取り消しにくい。

# Non Fast-Forwardマージ

Non Fast-Forwardマージとは、**マージしたことをコミット情報として持ちます。**
今回の前提条件の場合、**--no-ffオプションで早送りマージではなくなります**

## masterブランチにfixブランチをマージする

- Fast-Forwardマージの場合は新しくコミットを作りません
- Non Fast-Forwardマージの場合は**マージしたというコミットを作成する(=マージコミット)**

##メリット

- 間違えてfixブランチをマージした場合に、**マージコミットを取り消すだけでいい。**

# 参考リンク
https://www.slideshare.net/kotas/git-15276118
↑個人的に一番わかりやすかったリンク
https://qiita.com/nog/items/c79469afbf3e632f10a1
https://neos21.hatenablog.com/entry/2017/06/18/080000
https://backlog.com/ja/git-tutorial/stepup/04/
https://nullnote.com/web/git/merge_rebase/

# rebaseに関して

今後追記予定
【GAS】フォームを使用したワークフロー

フォームを使用した複数人の承認ワークフローを作りました。

function1～3にトリガーをそれぞれ設定
　→スプレッドシート編集時

チェックボックスにチェックを入れると、メッセージを送信し、二次認証者に…の繰り返しです。

スプレッドシート列の保護機能でアカウントを指定して、編集者のみ編集できるようにすることで他の権限のない人が触れないようにします。

フォームには既存の書式のエクセル・ワードなどの添付を必須にします。
あくまで、承認依頼の流れになりますが、。
　


```js
        var ss = SpreadsheetApp.getActiveSpreadsheet();　//アクティブなスプレッドシートを取得
        var rng = ss.getActiveCell(); //アクティブセルを取得
        var flag = rng.getValue(); //アクティブセルのチェックボックスの値を取得 

       function myFunction1() {
 
        if(rng.getColumn() == 5 && flag == true){ //アクティブセルが5列で、チェックボックスにチェックを入れた（true）の場合 
     var result1 = Browser.msgBox('送信確認', '上長へ承認依頼を流しますか？', Browser.Buttons.OK_CANCEL);
     if(result1 == "ok"){
    GmailApp.sendEmail('example.com', 'Aさんより承認依頼がありました”', '新規承認依頼があります。ご確認お願い致します。')   }
     else {
    Browser.msgBox('”再確認”')}
     } 
     }

   
       function myfunction2() { 
    

     if(rng.getColumn() == 6 && flag == true){ //アクティブセルが6列で、チェックボックスにチェックを入れた（true）の場合    
      var result2 = Browser.msgBox('"送信確認"', '"上長へ承認依頼を流しますか？"', Browser.Buttons.OK_CANCEL);
      if(result2 == "ok"){
    GmailApp.sendEmail('example2.com', 'Cさんより承認依頼がありました', '新規承認依頼があります。ご確認お願い致します。')}
      else {
    Browser.msgBox('”再確認”')}
     }
    }

       function myfunction3() { 
     if(rng.getColumn() == 7 && flag == true){ //アクティブセルが7列で、チェックボックスにチェックを入れた（true）の場合    
      var result3 = Browser.msgBox('"送信確認"', '"上長へ承認依頼を流しますか？"', Browser.Buttons.OK_CANCEL);
      if(result3 == "ok"){
    GmailApp.sendEmail('example3.com', '”’Cさん’より承認依頼がありました”', '新規承認依頼があります。ご確認お願い致します。')}
      else {
    Browser.msgBox('”再確認”')}
     }
     }

```
さくらのクラウドのサーバを AWS Lambda ＋ CloudWatch Events で定期的に起動/停止させる

## 概要

さくらのクラウド上に検証等の用途でサーバを作ることがありますが、毎日起動・停止を手作業で実行するのは面倒です。
毎朝始業時に自動で起動して、終業後に停止してくれるといいですよね。
何かそういったサービス(ニフクラでいうとタイマー)はあるかな・・・と探しましたが、見つかりませんでした。
さくらのサービスは安いので、定期処理実行用に VPS を 1個持っておく、といったことでも十分とは思いますが、そこはやはりサーバーレスにしたいところ。
ということで、AWS を使って Lambda ＋ CloudWatch Events で実装してみよう！ と思い立ちました。
(GCP で Cloud Functions ＋ Cloud Scheduler や、Azure で Azure Functions ＋ TimerTrigger でもできるかとは思いますが、試したことはありません)

## スクリプト

スクリプトは Python で作りたいと思います。
調べてみると、[こちら](https://manual.sakura.ad.jp/cloud/api/index.html)に saklient というライブラリが紹介されていました。
確認してみたところ動作したので、こちらを利用させていただくことにします。
Beta という記載があって、かつ数年前から更新が無さそうなので、そこは悩ましいところでしょうか。
実行結果は Slack に Incoming Webhook で通知するようにしたいと思います。

## 全体のコード

Terraform でまとめてデプロイできるようにしました。
以下で公開しています。

[https://github.com/shztki/lambda-sakuracloud-startstop](https://github.com/shztki/lambda-sakuracloud-startstop)

使い方は README に記載しています。
今回 Lambda の環境変数にアクセスキー等の情報が入るため、ここはなんとしても暗号化したいところです。
ただ `aws_lambda_function` に `kms_key_arn` を渡したとしても、`environment ` 内の `variables` の値は暗号化されません。
通常ですとデプロイ後、[こちら](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-envvars.html#configuration-envvars-encryption)にある「クライアント側で環境変数を暗号化するには」のとおり、AWSコンソールにアクセスして、手動で「転送中の暗号化のためにヘルパーを有効にする」を選択して「暗号化」しないといけません。
これは、忘れると非常に危険ですし、手動で暗号化するまでの間に、誰かに見られる可能性もあります。
なんとしても、デプロイが完了した時点で、環境変数には暗号化済みの値に入っていてもらいたい・・・。
苦肉の策ではありますが、今回は `kms.sh` というシェルスクリプトを用意し、AWS CLI で暗号化したものを `variables` に渡すことで、実現してみました。
※あとから気づいたら、Secret Manager を使ったり、Systems Manager パラメータストアを使う方法がありました。。。Systems Manager パラメータストアなら費用かけずにできそうですね。

```
data "external" "slack_webhook_url" {
  program = ["bash", "kms.sh"]

  query = {
    key_id    = module.kms_key.key_arn
    plaintext = var.slack_webhook_url
  }
}
```

```
#!/bin/bash

set -e

eval "$(jq -r '@sh "KEY_ID=\(.key_id) PLAINTEXT=\(.plaintext)"')"

result=$(aws kms encrypt --key-id $KEY_ID --plaintext $PLAINTEXT --query CiphertextBlob --output text)

jq -n --arg result "$result" '{"result":$result}'
```

## イメージ
Slack に毎日以下のように投稿されます。

![slack01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532524/d01a3947-c1f8-ca6a-7e5d-ccafaff8d63c.png)

## 今後

祝日は除外するような処理を追加しようかな・・・どうしようかなと考えています。

## 最後に

さくらのクラウドの操作を AWS でやるのかよ、というツッコミもあろうかと思いますが、そこはマルチクラウドな時代ということでご容赦ください。
VPS 1個分よりかは、月のコストは安くなるとは思います(正確なところは不明ですが)。
どうぞよいさくらのクラウドライフを！
Parcelableを継承したクラスを実装する方法(Kotlin)

## はじめに

Androidアプリ開発では、フラグメントやアクティビティ間で値を受け渡すときに `Bundle` を使います。
`Bundle` にはデフォルトで `String` や `Int` などの一般的な型しか入れられず、自作クラスは `Parcelable` を継承したクラスでないと入れられません。

今回はかんたんに `Parcelable` を継承したクラスを実装する方法を紹介します。

## 環境

- Kotlin：1.3.61

## `Parcelable` を継承したクラスの実装方法

実装方法は大きく3パターンあります。
「① > ② > ③」の順でオススメです。

### ① `@Parcelize` を使う

Kotlin 1.1で追加された `@Parcelize` アノテーションを使います。
渡したい `data class` に `@Parcelize` アノテーションを付け、 `Parcelable` を継承することで、自動的に `Parcelable` を継承したクラスが生成されます。

```diff_kotlin:MonsterEntity.kt
+ import android.os.Parcelable
+ import kotlinx.android.parcel.Parcelize
+ @Parcelize
data class MonsterEntity(
    val name: String,
    val description: String,
    val iconUrlString: String,
+     ) : Parcelable
```

### ②サードパーティ製のライブラリを使う

Kotlin 1.1未満、または何らかの理由で `@Parcelize` アノテーションが使えない場合、サードパーティ製のライブラリを使うことを検討します。

私は使ったことがないですが、[Parceler](https://github.com/johncarl81/parceler)というライブラリが有名です。

### ③ `Parcelable` を継承したクラスを自作する

自前で実装するのは手間ですが、 `Parcelable` を継承したクラスを自作する方法も考えられます。

私は自作したことがないので方法は省略します。

## `Parcelable` クラスを `Bundle` に入れる方法

実装した `Parcelable` クラスは、 `Bundle#putParcelable()` メソッドで `Bundle` に入れられます。

```kotlin:MonsterDetailFragment.kt
private const val MONSTER_ARG_PARAM = "monster"

class MonsterDetailFragment : Fragment() {

    companion object {
        @JvmStatic
        fun newInstance(monster: MonsterEntity) =
            MonsterDetailFragment().apply {
                arguments = Bundle().apply {
                    putParcelable(MONSTER_ARG_PARAM, monster)
                }
            }
    }

}
```

## おわりに

これでフラグメントやアクティビティ間でかんたんに自作クラスを受け渡せます！

Navigationを使っている場合、 `Bundle` に入れて渡すより、[Safe Args](https://developer.android.com/guide/navigation/navigation-pass-data?hl=ja#Safe-args)を使って渡すのがオススメです。

## 参考リンク

- [KEEP/android-parcelable.md at master · Kotlin/KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/extensions/android-parcelable.md)
- [Parcelable 実装生成ツール  |  Android デベロッパー  |  Android Developers](https://developer.android.com/kotlin/parcelize?hl=ja)
- [Kotlinの@Parcelizeを使ってみた - Qiita](https://qiita.com/ikemura23/items/1db32bb2b2396cbfe340)
Nuxt.js開発環境でproxyにhttpsを使用してエラーの場合の対処法

[HPM] Error occurred while trying to proxy request /***/*** from 192.168.1.2:3000 to https://localhost (UNABLE_TO_VERIFY_LEAF_SIGNATURE) (https://nodejs.org/api/errors.html#errors_common_system_errors)

上記のようなエラーが出た場合、nuxt.config.js に "secure": false を追加する。
"proxy": {
    "/api": {
      "target": "https://localhost",
      "pathRewrite": {
        "^/api": ""
      },
      "secure": false
    }
  },
在宅勤務のための燻製入門

# 「家ごもり」疲れ

在宅勤務も３週間が過ぎた頃、私は遊びに困っていた。Nintendo Switchもやり尽くした。本も読み飽きた。YouTubeなんて視聴し過ぎてオススメに東海オンエアしか表示されなくなった。私は東海オンエアを延々見るほど暇ではない。いや、暇なのだが。

私には「奥の手」があった。外出自粛の昨今、家から出ず、食料の充実を図り、人生を豊かにする特別な方法が…

**そう、燻製だ**

今回は初心者のために燻製の第一歩を踏み出す勇気を与える記事を書こうと思う。

# 燻製って？

木を加熱して出た煙で食材を燻すことで旨味を引き出す料理のことだ。これ以上はWikipediaを見てほしい。
知っておいてもらいたいポイントは以下の３つだ。その他はハマってから調べればいい。

* 保存が効く。冷蔵庫で数日は持つ。
* 換気扇がある程度強ければ、キッチンで作れる。火災報知器も鳴らない。ただし数日は部屋に燻製の残り香が漂うので、神経質な方は工夫してほしい。悪い匂いじゃないので、私は気にならない。
* 勘違いしやすいポイントなので書いておくが、木は燃やさない。もしスモークチップに引火するとそれはただの煙たい料理になる。

# 何を用意すればいいの？いくらかかるの？

まず揃えたいのが以下のアイテムだ。

* スモーカー（数千円から）
* スモークチップ（500円程度）
* アルミホイル

これくらい。お手軽でしょ？
好きなものを選んでもらえばいいが、一応オススメも書いておく。アルミホイルは好きなの買ってね。

### スモーカー

今まで3種類のスモーカーを試してきたが、一番のオススメはスノーピークのコンパクトスモーカー。
さすがスノーピークという作りの良さ（蓋がピタッと閉まる）と網が2段にセットできて大量に燻製できるところが気に入っている。
これに拘らずにデザインや予算で好きなものを選んでもらうとよいが、キッチンで燻製する場合は煙との闘いになるので、スモーカーの密閉性だけは考慮してほしい。隙間からモクモク煙が出てくるようじゃ火災報知器が鳴りかねないぞ！
<https://www.amazon.co.jp/dp/B000AR2OXE>

### スモークチップ

よくサクラのチップが入門用に用意されているが、個人的にちょっと癖があってオールマイティに使えないと思うので、ここではヒッコリーをオススメしたい。ウイスキーオークやりんごもオススメ。
<https://www.amazon.co.jp/dp/B000AR1L3I>

#### スモークチップとスモークウッドの違い

スモークチップは下から加熱して使う。加熱して使うので火加減の調整にテクニックが必要。
熱燻と呼ばれる加熱調理が必要なものがメイン。肉・チーズなんかはこちらがいいんじゃないか。使用量が少ないのでコスパがいい。

スモークウッドは木の塊に直接火を点けて使う。温度が上がらないので温燻と呼ばれる加熱しない調理に使う。
これを使う場合は燃焼に空気が必要なので、スモーカーに少し隙間があったほうがよい。使用量はあまり調整できないのでコスパが悪い。でも放置しておくだけだから簡単。

こんな違いがあるから好きなの選んでね！今回はスモークチップで作るよ！

# Let's燻製

初回はコンビニで買える食材で、準備なしに作れてすぐに食べられるお手軽燻製をしよう。

## 食材

* ６Pチーズ
* チー鱈
* 魚肉ソーセージ
* ちくわ

## 下ごしらえ

6Pチーズとちくわは常温に戻しておき、風に当てて表面を乾かしておく。触ったときにサラサラとしたら準備完了だ。
チー鱈はそのまま燻製する。
魚肉ソーセージは私の敬愛する燻製道士さんのレシピを見ながらレンジで加熱しておこう。
http://kunsei.livedoor.biz/archives/51898685.html

## 燻製開始

ここから燻製を行う。スモーカーを用意し、そこにくしゃくしゃにしたアルミホイルを敷く。一握りのスモークチップを入れ、食材を並べる。チーズは溶けやすいので火から離して置くようにしよう。

家庭用ガスコンロだと最初は中火で、煙が出てきたらごく弱火にして10分待つ。
ここでQiitaらしくスマートフォンのアプリを使って時間を計ろう。お手持ちのスマートフォンには、、、なんと、、、タイマーアプリが標準装備されている（！）
タイマーアプリを開いて10分と入力。スタートを忘れずにタップしておこう（取ってつけた技術ブログ感）

10分経てば完成だ。あとは好きに食べるなり、Twitterにアップするなりするとよい。
ちなみに1日置いておけば煙が落ち着き、より美味しく食べられるぞ！最後の我慢だ！

**それでは、よい家ごもりを！**
Google Chrome の効率向上, Shortcuts for Mac!

# Chrome Keyboard Shortcuts
グーグリングの効率は仕事の効率に直結すると感じ、ここに役に立つショットカットキーをまとめておきます。

## **TAB**
| GOAL　| SHORTCUT |
|:-----------------|:------------------|
| 新しい Tab を開く | Command⌘ + t |
| Tab を閉じる　| Command⌘ + w |
| Tab の移動　 | Command⌘　+ Option + ← or → |
| Tab の移動（ジャンプ） | Command⌘ + Option + Tab番号 |
| Tab を閉じる | Command⌘ + w |
| Tab を閉じる | Command⌘ + w |

## 検索
| GOAL　| SHORTCUT |
|:-----------------|:------------------|
| 検索 | Command⌘ + f |
| 検索の後、前進 | Command⌘ + g |
| 検索の後、後退 | Command⌘ + Shift + g |

### 参考： Mac の windowの表示

| GOAL　| SHORTCUT |
|:-----------------|:------------------|
| 全画面表示と解除 | Command + Control + f |
| 全画面表示と解除 （アドレスも非表示）| Command + Shift + f |

### 参考サイト
本文の内容は、書きサイトを参考しながら作成しました。

>  -　*[The 33 Most Useful Keyboard Shortcuts for Google Chrome](https://blog.hubspot.com/sales/chrome-keyboard-shortcuts/)*
>  -　*[Chrome のキーボード ショートカット
](https://support.google.com/chrome/answer/157179?hl=ja)*
Yandex Translation API を使って翻訳機能を試す

# はじめに
音声認識を試してみたら、翻訳できたら便利だなと思ったので、簡単に使えそうなAPIを探してみた
前回：[Speech Recognition API でブラウザ音声認識を試す](https://qiita.com/yunayunanaka/items/75c1ade41b6156d304d8)

# [YandexTranslation](https://github.com/RytNszn/mylaps-dashboard)

## 概要
- Yandexがロシア版Googleみたいなもので、そのYandexが出してる翻訳API
- APIの使用には無料登録が必要
- 使い方が簡単そうだったの試しに使ってみた
 
## 準備
### Yandexに登録
[登録画面](https://passport.yandex.com/auth/add?origin=translate&retpath=https%3A%2F%2Ftranslate.yandex.com%2Fdevelopers%2Fkeys)
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431932/155b00a6-8f40-630c-45f1-25f257117fd5.png)
### YandexAPIを発行
サインインして[API一覧ページ](https://translate.yandex.com/developers/keys)に飛んだら
`+ Create a new key` からAPIキーを発行
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431932/8bbbc50d-7f7e-c5ec-a40c-79a98d0cc9c7.png)
 
## 使用方法
[公式ページドキュメント]()によると

```
https://translate.yandex.net/api/v1.5/tr.json/translate
 ? key=<API key>
 & text=<text to translate>
 & lang=<translation direction>
 & [format=<text format>]
 & [options=<translation options>]
 & [callback=<name of the callback function>]
```

ということなので、URLに当てはめてHTTPのGETリクエストを投げることにした。

# テキスト翻訳してみる

## 仕様

1. inputに単語を入力
2. translateボタン押下 → 翻訳開始
3. ログに翻訳結果が出る

```translationTest.html
<!DOCTYPE html>
<html>

<head lang="ja-JP">
    <meta charset="utf-8">
    <title>Translation Test</title>
</head>

<body>

    <input id="input_text" placeholder="input a word here">
    <button onclick="translatebutton()">translate</button>

    <script>
        const base_url = "https://translate.yandex.net/api/v1.5/tr.json/translate"
        const api_key = "XXXXXXXXXXXXXXXXXXXXX" // 発行したAPIKeyを入力
        const format = "html"

        function translatebutton() {
            console.log("translate")

            const text = document.getElementById("input_text").value
            const lang = "en" // 英語に翻訳する。"ja"にすれば日本語に翻訳する
            const url = base_url + '?key=' + api_key + "&text=" + text + "&lang=" + lang + "&format=" + format

            const request = new XMLHttpRequest();
            request.open('GET', url);
            request.onreadystatechange = function () {
                if (request.readyState != 4) {
                } else if (request.status != 200) {
                    console.log("http request failed.")
                } else {
                    console.log("success", request.responseText);
                }
            };
            request.send(null);
        }

    </script>
</body>

</html>
```

## 結果

うまくいきました
![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431932/796afb45-160d-5f4c-4db7-d3d8749f1768.png)
【リーダブルコード】難しい用語集？まとめ【プログラム初心者用】

名著「リーダブルコード」を読みました！！！
特に7・８・９章が感動しました！！！

##プログラムの多少の前提知識が必要？？？
よくプログラム初心者にも勧められている本みたいなのですが、
多少プログラムに対する前提知識がないと、コード例の内容等がなかなか頭に入ってこず、途中で読むのをやめてしまう人も多いのではないか？と思いました。

そこで、個人的に本の中でよくわからなかった箇所を軽〜く、記事としてまとめておきます。
プログラム初心者が「リーダブルコード」を読む時に、一通り目を通されると参考になるかも？ならないかもw


##用語集
P.20
　**スロットルとは？**
　　APIの使用を制御するプロセス
　　スロットルは正確にはスピードを抑圧する意味
　　→スロットル全開はバイクのアクセルのイメージ
P.25
　**シンタックスハイライトとは？**
　　エディタの特定の記号とか文字に色がついたりして見やすくなる機能
P.36
　**OpenBSDとは？**
　　無料のOSの一つです(ざっくり)　　
　**高トラフィックとは？**
　　通信回線において、一定時間内にネットワーク上で転送されるデータ量のこと
　**traffic fractionとは？**
　　通信の断片化のこと
　　メモリや記憶装置を繰り返し使うと、中途半端な空間ができる
　　フラグメント(デフラグのフラグメント)と同義語
P.48
　**wgetとは？**
　　HTTP/HTTPS両方まとめて（ダブルで）データを取得できるもの
P.66
　**グルーコードとは？**
　　プログラムの要求仕様を実現するためのコードではないが、
　　互換性のないプログラムを繋ぐために橋渡しをするコード。
P.67
　**パーミッションとは？**
　　UNIX系OSのアクセス権のこと
P.78
　**ヒューリスティックとは？**
　　経験的な、という意味
　　IT分野では、問題の回答を得るための方法論の一つで、常に正しいとは限らないが経験的にある程度正しい解を導ける推論や経験則などのこと
　　また、セキュリティソフトのウイルス検出手法の一つ「ヒューリスティック機能」
　**ブルートフォースとは？**
　　強引な、という意味
　　パスワードとかの総当たり攻撃のこと「ブルートフォースアタック」
　**ナイーブソリューションとは？**
　　「経験豊富なプログラマーが最初に思い付く解決手段」や「愚直な（安易な）解決手段」
P.106
　**DRY原則とは？**
　　Don’t Repeat Your Self：繰り返しを避けること
P.117
　**static(静的)とは？**
　　private static int XXX;みたいに使う。
　　クラスに1つ→つまりアプリケーションに1つ
　　なので、インスタンス作らなくて、クラス.静的メソッドとかでよびだせる
　　注意点は静的メソッドの中は、静的フィールドしか使えないこと！
P.124
　**イミュータブルとは？**
　　変更できないオブジェクト！ 
　　例えばpythonのstringはイミュータブル
　　str=‘ABC’ にstr[0]=‘D’なんで変更できない！
P.137
　**ラップ関数とは？**
　wrap(包む)もとの関数などの使い方を変えたい場合とかに作る！
P.144
　**パースとは？**
　　parse、解析する、パーズ、パーザ、パーサーとも
　　一定の規則で記述されたテキストを解析し、プログラムとして扱いやすいようなデータに変換する処理のこと
P.145
　**ウィジットとは？**
　小型化されたアプリのこと


こんな感じです。
おわり！
Speech Recognition API でブラウザ音声認識を試す

# はじめに
WebVRの研究中に音声認識をやりたくなって調べてみたら面白そうだったので試してみた

# [SpeechRecognition](https://developer.mozilla.org/ja/docs/Web/API/SpeechRecognition/SpeechRecognition)

## 概要
- HTML5に備わってるAPI (Mozilla作)
- 音ブラウザで音声を認識してくれる

## 準備
なし

## 使用方法
[公式ドキュメント](https://developer.mozilla.org/ja/docs/Web/API/SpeechRecognition)

- `new SpeechRecognition()` した後に設定値を入れて、
(※ chromeでは "webkit" プレフィックスを付けないといけないので`webkitSpeechRecognition()`になる)

- `start()` で認識開始
- `onresult()`で音声取得結果がわかる
- `stop()` で終了

# 音声認識を動かしてみる

## 仕様

1. startボタンを押下 → 音声認識開始
2. 話す → ログに音声認識結果を出す
3. stopボタン押下 → 音声認識終了

## ソースコード

```speakTest.html
<!DOCTYPE html>
<html>

<head lang="ja-JP">
    <meta charset="utf-8">
    <title>Speak Test</title>
</head>

<body>

    <button onclick="startbutton()">start</button>
    <button onclick="stopbutton()">stop</button>

    <script>

        const SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
        const rec = new SpeechRecognition();
        rec.continuous = true;
        rec.interimResults = false;
        rec.lang = "ja-JP" // "en-US"なら英語で認識してくれる。指定がないとブラウザの言語になる

        rec.onresult = function (e) {
            console.log("on result")
            for (var i = e.resultIndex; i < e.results.length; ++i) {
                if (e.results[i].isFinal) {
                    const str = e.results[i][0].transcript;
                    console.log('Your speaking: ' + str);
                }
            }
        }

        function startbutton() {
            console.log("start")
            rec.start();
        }
        function stopbutton() {
            console.log("stop")
            rec.stop();
        }
    </script>

</body>

</html>
```

## 結果

うまくいきました
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431932/e128a08f-4a37-8467-878e-8c05bc8b0d90.png)
Nginx+FlaskでServer-Sent Events(SSE)が遅延するとき

# 問題
- FlaskのアプリケーションでServer-Sent Events(SSE)による更新を行っている
- Nginxに接続しなければ正常に動作する
- Nginxに接続すると，SSEの処理だけが絶望的に遅れる

# 原因
Nginxのリバースプロキシによってバッファリングが行われるため

# 解決
FlaskからJavascriptの`EventSource`に渡すレスポンスに，ヘッダ`X-Accel-Buffering: no`[^1]を付与する．

[^1]:[X-Accel | NGINX](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/)

```py:hoge.py
# Returns a response for the JS EventSource
@flask_app.route( "/stream" )
def stream():
    response = flask.Response( event_stream( "foo" ),
                               mimetype = "text/event-stream" )
    response.headers["X-Accel-Buffering"] = "no"
    return response
```

# その他
Nginx側の設定に以下を追記すれば良いとの情報がみられる[^2]が，Flask側でSSEの処理に絞って適用した方が綺麗だと考えられる．

[^2]:[ruby - EventSource / Server-Sent Events through Nginx - Stack Overflow](https://stackoverflow.com/questions/13672743/eventsource-server-sent-events-through-nginx)

```
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
```
バリデーション復習してみた

超初心者なのでまだそんなこと言ってるの？など色々思われることがあると思いますが、個人の向上のためつらつらと書いていきたいと思います。
※「それちゃうで！」などあればどんどんご指摘ください。

・苦手なバリデーションは所詮基礎ができていない。

①そもそもバリデーションとは？
端的にいうと不正なデータをデータベースに記録する前にチェック（検証）してふるいにかけてくれるすごいやつ。
もちろん、不正なデータだった場合はそれをお知らせする手立てもあります。

②バリデーションを書く場所は？
状況：雑魚Twitterアプリを作成
バリデーションの記載はmodelに記述します。

validatesメソッド を設定する

```ruby
※今回は存在性の検証と文字数制限（5０文字）の検証
class Post < ApplicationRecord
  validates :content, presence: true, length: { maximum: 50 }
end
```
今回は存在性の検証と文字数制限（5０文字）の検証

③実際にバリデーションできているのか確認
ここまで準備できたらひとまずOK。
これで本当にバリデーションが実行されるのかを確認してみる。
方法は簡単、rails c でコンソールを起動させて挙動を確認する。

```ruby
※空文字、つまりは存在しないcontentカラムをnewしてみると結果はfalseになります。
$ rails c
> post = Post.new(content: "")
> post.save
=> false
```

上では「Post.new(content: "")」空文字、つまりは存在しないcontentカラムをnewしてみるとpost.saveの実行結果はfalseになります。
ということは、validatesのpresence: trueが機能しているってこと！

※文字数制限も同じ要領で確認できます。

存在性の検証ができていることはここまででわかったと。
では、それをどうやって操作している人に知らせるのか。
ここで活躍するのが『エラーメッセージ』です。

ひとまず、エラーメッセージが実際に発行されているのか否か確認していく。

ここでもrails cでコンソール起動させてみましょう。

先程の不正なデータ（空のcontent）を生成。

```ruby
$ rails c
> post = Post.new(content: "")
```

次からがミソです。
post.errors.full_messagesを出力してみましょう。

```ruby
> post.errors.full_messages
=> []
```

現状はまだデータの生成のみなので特に検証にかかっていない状況です。
そのため、errors.full_messagesをしても何もメッセージが生成されていません。
もっといえば、生成はされているけれど空の配列が生成されている状況です。
では、saveしてみましょう。　...当然ですが失敗します。

```ruby
> post.save
=> false ← 検証で空のデータは受付ないよ ということでfalse
```

さて、検証に引っかかった状況がこれで整いました。
もう一度errors.full_messagesしてみると…。

```ruby
> post.errors.full_messages
=> ["Content can't be blank"]
```

空だった配列にエラーメッセージが見事に生成されています！

こんな感じでバリデーションからエラーメッセージを生成する流れとなります。
これに絡めてrenderについても書けたらと思いましたが、力尽きたのでまた今度まとめます。

ポートフォリオ様に雑魚システム作ってもやっぱりアウトプットしようとなるとうまく説明できませんね。
テキスト見ながら振り返りつつこの記事も作成していますが、時間かかりますけど改めて勉強になりました。

ただ、こういうエラーメッセージはサーバーサイドバリデーションになるのであまりよろしくないとな。
JavaScriptなどで即時フィードバックができるようにするべきという事です。
参考記事
https://ferret-plus.com/7724
https://popinsight.jp/blog/?p=4113

よし、さらに成長しちゃいますよ！
SubversionのリポジトリをGitリポジトリに変換したときの落とし穴

# はじめに
Subversion から Git に移行したあとに、どこを確認すれば移行が完了したと言えるのかについてメモを残しておきます。
どうやって Subversion リポジトリを Git リポジトリに変換するかに関しては数多の Qiita 記事が存在しますので割愛します。
あくまで、要件を満たすようにリポジトリの変換を行なった後に、本当にちゃんとできているのかを確認するという話です。
そのときに落とし穴があるよ、という話です。
語彙力がないので連続して同じような語尾を使ってしまいがちです。ごめんなさい。

# 背景
私の所属しているグループには Subversion で管理されているプロジェクトがありまして、最終更新日時が 2012 年とかなので、これがもはや化石と化しているわけです。
化石はとても貴重なので、移動させる場合には傷が付かないように気を付けないといけないんですね。

# ディレクトリ同士の差分を取得する

さて一般に、いや私はド素人なので一般を語るのには早いのですが、Subversion のリポジトリを Git リポジトリに変換する際には`git svn`コマンドを叩きます。
その結果として、ディレクトリ構成と各ファイルの中身が一致していれば
> 傷が付かない

ように無事に移行が完了したと言えるのではないでしょうか。

つまり、Subversion からチェックアウトしたディレクトリ`dirSub/`と、GitHub やら GitLab に push した後にそこから clone したディレクトリ`dirGit/`との差分を取ればよいわけです。
差分を取るので、`diff`コマンドが使えます。
ファイル単位ではなく、ディレクトリ単位で差分が取りたいので、`-r`のオプションを使います。
また、ファイル一個一個の差分が明確に知りたいわけではないので、差分があったかどうかの結果だけを表示させる`-q`オプションも使います。

まとめると、以下のようなコマンドを叩けばいい感じに差分が取れます。

```console
diff -rq dirSub/ dirGit/ > diff.txt
```

化石を移動させたとき損傷がなかったかの記録が大事なので`diff.txt`として出力しています。

# git svn コマンドの罠
この`diff.txt`をそのまま表示すると、めちゃくちゃいっぱいファイルが表示されるかもしれません。
というのも、まずディレクトリ内のルートに`.git/`が生成されるので、これに関しては確実に差分として出力されるでしょう。
また、「`.gitignore`というファイルが`dirGit/`にだけ含まれていますよ」という出力も見受けられるかもしれません。
`git svn`コマンドのオプションで、空ディレクトリを保持するための`--preserve-empty-dirs`というものがあります。
Git リポジトリでは、空ディレクトリの存在が許されないので、オプション無しだとディレクトリ構成が場合によっては維持できません。
そこで`--preserve-empty-dirs=true`を施すと、Subversion リポジトリ上の空ディレクトリ内に空ファイル（デフォルトでは`.gitignore`）を付与して Git リポジトリに変換してくれます。

ここまでは、確かに差分なのかもしれませんが、予定調和としての差分かと思います。（まぁ私はド素人なので、`diff`を取ってから「あぁ、そういえばこういう差分は当然出てくるかぁ」と気付かされたわけですが。。）

私が罠だというのはこの後で、「`hogehoge.txt`が`dirSub/`と`dirGit/`で異なりますよ」という出力もわんさか出て来るかもしれないんですね。

これは Subversion の仕様でプロパティの自動追加という機能がある際に起こりうるようです。
以下のように、あらかじめ設定しておいた情報をテキスト内に埋め込む機能が Subversion にはあります。

```dirSub/hogehoge.txt
#
# $Id: hogehoge.txt 123 2012-04-17 etc...$
#

（中略）

# end of $Id: hogehoge.txt 123 2012-04-17 etc...$
```

私は Subversion のことを微塵も理解していないのですが、このプロパティ情報が表示されるときとされないときがあるようです。
`git svn`コマンドで Git リポジトリに変換したあとは、以下のように、このプロパティ情報が落ちているようでした。

```dirGit/hogehoge.txt
#
# $Id$
#

（中略）

# end of $Id$
```

これが原因で、`diff`を取ると内容的には一致していても
> 「`hogehoge.txt`が`dirSub/`と`dirGit/`で異なりますよ」

と出力されてしまうわけですね。
なんという罠。

# おわりに
大変申し訳ないのですが、別に「この罠を回避するために、こういう技がありますよ」という記事ではないです。
「罠があるのは分かったので、みなさん気をつけましょうね。」と訴えているだけです。
プロパティ情報を除いて差分を取れるようなスクリプトを頑張って書いても良いのですが、上長も別にそこまで厳密に求めてはいなかったようなので今回はやらないことになりました。

古の遺産をどこかに移す際にはみなさん気をつけましょう。
COVID-19チャレンジ（フェーズ3）

#概要

signateのCOVID-19チャレンジ（フェーズ3）やってみた。

#写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/d6bc095a-2386-d160-6b7a-3ca1a278310a.png)


#サンプルコード


```

function predict(x) {
  return tf.tidy(() => {
    return tf.div(tf.exp(tf.mul(tf.mul(x.sub(a), x.sub(a)), tf.neg(b))), c)
  });
}
function loss(pred, label) {
  return tf.losses.meanSquaredError(pred, label).mean();
}
function train(xs, ys, numIterations) {
  for (let iter = 0; iter < numIterations; iter++) 
  {
    optimizer.minimize(() => {
      const pred = predict(xs);
      return loss(pred, ys);
    });
  }
}
const a = tf.variable(tf.scalar(Math.random() + 90));
const b = tf.variable(tf.scalar(Math.random() / 10));
const c = tf.variable(tf.scalar(Math.random() / 10));
const learningRate = 0.005;
const optimizer = tf.train.adamax(learningRate);
const numIterations = 300;
const yy =  [2, 0, 0, 0, 2, 0, 3, 0, 4, 4, 5, 0, 0, 2, 0, 0, 3, 0, 1, 0, 0, 2, 0, 1, 14, 16, 7, 8, 10, 10, 11, 17, 25, 12, 11, 19, 25, 14, 13, 15, 18, 19, 38, 29, 60, 41, 41, 9, 70, 58, 0, 62, 72, 66, 0, 39, 11, 35, 39, 44, 94, 27, 65, 114, 80, 81, 225, 173, 0, 87, 225, 317, 122, 522, 0, 515, 252, 351, 410, 863, 475, 743, 622, 275, 455,]
//alert(yy.length);
const buffer = tf.buffer([yy.length, 1]);
const buffer2 = tf.buffer([yy.length, 1]);
for (var i = 0; i < yy.length; i++) 
{
    var x = i; 
    var y = yy[i];
    buffer.set(x, i, 0);
    buffer2.set(y, i, 0);
}
const xs = buffer.toTensor();
const ys = buffer2.toTensor();
train(xs, ys, numIterations);
const aa = Number(a.dataSync());
const bb = Number(b.dataSync());
const cc = Number(c.dataSync());
alert(aa + ", " + bb + ", " + cc);
var values = [];
var j = 0;
var out = document.getElementById('out');
for (var i = 0; i < 120; i++)
{
  if (i < yy.length)
  {
    j = i;
  }
  values.push({
    x: i, 
    y: yy[j],
    pred: Math.exp((i - aa) * (i - aa) * - bb) / cc
  });
  out.value += Math.floor(Math.exp((i - aa) * (i - aa) * - bb) / cc);
  out.value += ",";
}
const spec = {
  '$schema': 'https://vega.github.io/schema/vega-lite/v2.json',
  'width': 300,
  'height': 300,
  'data': {
    'values': values
  },
  'layer': [{
    'mark': 'point',
    'encoding': {
      'x': {
        'field': 'x', 
        'type': 'quantitative'
      },
      'y': {
        'field': 'y', 
        'type': 'quantitative'
      }
    }
  }, {
    'mark': 'line',
    'encoding': {
      'x': {
        'field': 'x', 
        'type': 'quantitative'
      },
      'y': {
        'field': 'pred', 
        'type': 'quantitative'
      },
      'color': {
        'value': 'tomato'
      }
    }
  }]
};
vegaEmbed('#vis', spec);




```

#成果物

https://embed.plnkr.co/plunk/RquerGxSDghnxIuz

以上。