OmniAICreator/Qiita-1.07M huggingface dataset:
マジックナンバーをやめてデータベースの情報からステータスの切替をする方法

# ステータスの管理
どんなシステムを作っていても、ステータスの管理は出てきます。
例えば顧客の状態とか。

``` 
SELECT * FROM customer;
+----+-----------------------+------------+
| id | name                  | status_id  |
+----+-----------------------+------------+
|  1 | おおがき               | 1          |
|  2 | さとう                 | 3          |
|  3 | すずき                 | 2          |
|  4 | いとう                 | 3          |
+----+-----------------------+------------+

SELECT * FROM m_status;
+----+-----------------------+
| id | name                  |
+----+-----------------------+
|  1 | 未発注                 |
|  2 | 見積済                 |
|  3 | 注文済                 |
|  4 | 支払済                 |
|  5 | 発送済                 |
+----+-----------------------+
```

そしてプログラムとかで、ステータス情報を変更したりしますよね。

``` index.js
// 見積終了時
customer.setStatus(2);
```

# マジックナンバーで書いてはいけない
ここで、2というステータスIDを直接書きました。
このようにプログラムに入っていて何を表しているかわからない数字をマジックナンバーと言います。
可読性が低いうえに、マスタデータが更新されてidがズレてしまったりしたら、一つ一つ手作業で直す必要があります。
バグの温床ですね。

できれば数字ではなく、定数で書いておきたい。
そうすればidがずれても修正が一か所済みますし、定数名なら検索や置換も簡単です。
こんな感じ。

``` index.js
// 見積終了時
customer.setStatus(STATUS.estimated);
```

しかし、こんなふうにconfigファイルに定数で書いておくというのもスマートじゃない気がします。

``` config.js
const STATUS = {
   contacted : 1,
   estimated : 2,
   ordered   : 3,
   paid      : 4,
   sent      : 5
}
```
マスタデータはデータベースに入っているわけですから、マスタデータを直した上にconfigを直すのも二度手間ですよね。
そこで今回は、データベースのマスタデータからステータス情報を取得してきてマジックナンバーを回避する方法についてご紹介します。

# ステータス情報をデータベースからとってくる
## データベースにカラムを追加
まずは、データベースのマスタデータにプロパティ名用のカラムを追加しましょう。

``` db
+----+-----------------------+--------------------+
| id | name                  | property_name      |
+----+-----------------------+--------------------+
|  1 | 未発注                 | contacted          |
|  2 | 見積済                 | estimated          |
|  3 | 注文済                 | ordered            |
|  4 | 支払済                 | paid               |
|  5 | 発送済                 | sent               |
+----+-----------------------+--------------------+
```

## マスタデータから辞書を作成するモジュールを作成
次に、`STATUS.estimated`みたいにするとidの2を返してくれるモジュールを作っておき、必要に応じて呼び出します。

``` module.js
export default{
   generateIdDict(objList, column){
      const status = {};
      objList.forEach((v) => {
         status[v[column]] = v.id;
      });
      return status;
   };
};
```

``` index.js
import customerModule from 'module';

// customerStatusにデータベースからデータを入れておく

// マスタデータからIDの辞書を作る
const STATUS = customerModule.generateIdDict(customerStatus, 'property_name');

// 使うときはこんな感じ
customer.setStatus(STATUS.estimated);
```


以上です。
ただ、後からの読みやすさはありますけど、書くときにはプロパティ名をある程度覚えておかないといけません。
今回はダミーデータで作りましたけど、ステータスを表すプロパティ名の命名ってどうすればわかりやすいか悩みますね。
そもそも日本語でも「〇〇中」とか「〇〇済」とか、全体の中のどの段階かわかりやすいかというと微妙ですし。
良いアイデアがあったら教えていただきたいです。
PlasticSCMクライアントでログアウトしたい(Mac)

# 始めに
今までUnityプロジェクトをGitで管理してきましたが、[PlasticSCM](https://forpro.unity3d.jp/products/plastic-scm-lp/)だとどのようにバージョン管理できるか気になり、
プライベートアカウントでサインインして集中型(Centralized)に設定し、検証をしていました。

途中から分散型(Distributed)で検証したいと思い、設定を変更しようとしたところ、そのような項目が見当たりませんでした・・・

また、アカウント切り替えする項目も見つからず・・・

# 対処方法(Macの場合)
PlasticSCMの設定ファイルなどが入っているディレクトリを消去してクライアントを起動すると、初期設定をすることができました。
こちらがパスです。

```
/Users/ユーザー名/.plastic4
```

# 最後に
ディレクトリごと削除してしまうと、全ての設定が消えてしまうため、
対象のファイルを探して編集するのが良いと思いますが、今回の方法がシンプルで手っ取り早いです。

PlasticSCMを触ってみて、良いシステムだなと思いましたが、
Gitと使い方と使い勝手が違うので、チーム全員が使い慣れるまでが大変そうです。

Gitで運用上問題があった時の解決方法の一つとしてPlasticSCMを持っておきたいと思います。
macでa tour of goをローカルで実行したときに詰まった

ひょんなことからgoを書くことになり、
[A Tour of Go](https://go-tour-jp.appspot.com/welcome/1)を実行しようとしてうまく行かなかったので記事に残します。

## 前提

- macOS (Big Sur)
- Homebrewインストール済み

## goのインストール

```zsh
$ brew install go
$ go version
```
これでバージョンが返って来ればOKです。自分は以下バージョンでした。
`go version go1.16.6 darwin/arm64`

> ローカルで Go Tour を実行するためには、はじめに、 Goのダウンロードとインストール し、コマンドラインで以下のように実行します:

```zsh
$ go tool tour
go tool: no such tool "tour"
```

はて・・・？
おそるおそる[英語版](https://tour.golang.org/welcome/3)を見てみるとコマンドが違う！？

```zsh
go install golang.org/x/website/tour@latest
```

これで`$GOPATH`に移動して、(`go env`とかで出てくるはずです。デフォルトは`/Users/[ユーザ名]/go`かな。)
以下で実行できます。

```zsh
cd ./bin
./tour
```
[SQL] UPDATE文の基本構文

##はじめに
前回に引き続き、今回はUPDATEぶんの基本構文の記事にしたいと思います。
よろしくお願いします。

##UPDATE文
UPDATE文は既存のデータを書き換えるためのものです。

```sql
UPDATE テーブル名
   SET 列名1 = 値1, 列名2 = 値2
```

1行目にUPDATEを記述して、どのテーブルのデータを書き換えたいか、テーブル名を指定します。


2行目ではSET句を利用して対象の列名（カラム名)を書いて、'='で書き換える値を代入するように書きます。
基本的にはWHERE句をこの後に書かなければその列全ての値が=の後の値に書き変わってしまいます。

下記のような家計簿テーブルがあったとします。

| 日付 | 費目 | メモ | 入金額 | 出金額 |
| --- | --- | ---- | ----- | ---- |
| 2021-08-02 | 食費 | パンを購入 | 0 | 300 | 
| 2021-08-03 | 食費 | 晩ご飯材料 | 0 | 1000 |
| 2021-08-08 | 交通費 | 電車代 | 0 | 520 |
| 2021-08-13 | 給料 | 7月分給料 | 250,000 | 0 |
| 2021-08-13 | 食費 | 外食 | 0 | 7000 |

もし下記のようにしてしまうと。。。

```sql
UPDATE 家計簿
   SET 出金額　= 1500
```

| 日付 | 費目 | メモ | 入金額 | 出金額 |
| --- | --- | ---- | ----- | ---- |
| 2021-08-02 | 食費 | パンを購入 | 0 | 1500 | 
| 2021-08-03 | 食費 | 晩ご飯材料 | 0 | 1500 |
| 2021-08-08 | 交通費 | 電車代 | 0 | 1500 |
| 2021-08-13 | 給料 | 7月分給料 | 250,000 | 1500 |
| 2021-08-13 | 食費 | 外食 | 0 | 1500 |


上記のように書き換えられてしまいます。
あまり実用的ではないですね。

WHERE句で日付を指定してみましょう。

```sql
UPDATE 家計簿
   SET 出金額　= 1500
 WHERE 日付 = '2021-08-03'
```


| 日付 | 費目 | メモ | 入金額 | 出金額 |
| --- | --- | ---- | ----- | ---- |
| 2021-08-02 | 食費 | パンを購入 | 0 | 300 | 
| 2021-08-03 | 食費 | 晩ご飯材料 | 0 | 1500 |
| 2021-08-08 | 交通費 | 電車代 | 0 | 520 |
| 2021-08-13 | 給料 | 7月分給料 | 250,000 | 0 |
| 2021-08-13 | 食費 | 外食 | 0 | 7000 |

このように任意のデータだけを書き換えることができました。

基本的にUPDATEを使うときはWHERE句はセットで使うことがほとんどになるでしょう。

参考: スッキリわかるSQL入門
コピペでLINEを叩く(Python)

# コード
```python:jupyter_lab.ipynb
!pip install line-bot-sdk

from linebot import LineBotApi
from linebot.models import TextSendMessage

CHANNEL_ACCESS_TOKEN = "アクセストークンを入れてください"
line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN)

def main():
    USER_ID = "ユーザーIDを入れてください"
    messages = TextSendMessage(text = "テキストを入れてください")
    line_bot_api.push_message(USER_ID, messages = messages)
    
if __name__ == "__main__":
    main()
```
これで完成！
重複数に上限がある場合の重複組合せを1回の計算で解ける場合

　重複数に上限がある場合の重複組合せにおいて、特殊なケースでは計算が簡単になるよという話。https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10113338515 を見て知った解法ですが、僭越ながら回答者さんの説明が少し分かりづらいかなと思ったので、自分の中での噛み砕きも兼ねて整理。

　問題は以下のような感じ。

```math
\displaylines{
「200個の区別のないボールを、A,B,Cの3箱に入れる。\\
ただし、それぞれの箱にボールは100個までしか入らない。\\
ボールの入れ方は何通りか。」\\
\\}
```

## 解1（包除原理）
　これが正攻法になると思います。上限数がないすべての場合から、上限数を超えた場合を除きます。

```math
_3H_{200}-3\times_3H_{99}\\
=5151
```

## 解2（特殊ケース）
　少しテクニカルになります。最初にすべての箱に100個ずつ入ってる（つまり合計300個）と考え、**そこからの100個抜き出す**場合の抜き出し方を考えます。

```math
_3H_{100} = 5151
```

　なんと1回の計算で解けてしまいました。

### 解2が成り立つケースは？

　$n$種類のものから$r$個を選び、各上限が$m$のとき、「抜き出す数」が$m$を超えると上の解法は破綻します。100個入の箱から101個のボールを取り出すことはできないので。

　さて、抜き出す数は$nm-r$となるため、

```math 
\displaylines{
nm-r \leq m\\
r \geq (n-1)m}
```

　$r$の上限は$nm$であることを考えると、

```math 
(n-1)m\leq r \leq nm
```

　つまり、解2は$r$が上の範囲でのみ成り立つことがわかります。
gauge run で`Error Message: Runner is not Alive`となりStacktraceに何も出力されない場合

## 現象
gaugeで以下のようなエラーが出ることがあった。
困ったことにStacktraceに何も出力されないので意味がわからない。

```bash
(venv) gauge-tests-py > gauge run
Python: 3.7.6

  Error Message: error reading from server: read tcp 127.0.0.1:56868->127.0.0.1:56867: wsarecv: An existing connection was forcibly closed by the remote host.
  Stacktrace: 
  

  Error Message: Runner is not Alive
  Stacktrace: 
  
Successfully generated html-report to = ...(以下省略)
```

## 解決方法

今回は、テストコードを記述した`step_impl.py`の読み込み時にインポートエラーが出ていたのが原因だった。
`step_impl.py`ファイルの冒頭などで`import hoge`などとしているが、タイポなどでこれが失敗すると、上記のようなStacktraceなしのエラーになってしまう。

エラーがあったら原因箇所を特定しやすいように、以下のようにimport時例外を出力するようにした。

```python
# gauge run からのインポートエラー時、何もでなくて困るので、try-except
try:
    from getgauge.python import step, before_scenario, Messages
    import sys
    import os
    import traceback
    import hoge
except Exception as e:
    print(traceback.format_exc())
    raise e

# --------------------------
# Gauge step implementations
# --------------------------
@step("何かする")
def do_something():
    hoge.do_something()

...
```

これは本件とは直接関係ないが、gaugeは、実行時に`step_impl`と`venv`等のpython環境内のパッケージしか見てくれないようで、テストコード内から、別ディレクトリにあるテストコード以外のソースを参照したい場合、`sys.path`に参照先ディレクトリを追加しておく必要がある。

たとえば、ディレクトリ構造が以下のようなとき...

```
hoge_src/
  hoge/
    __init__.py
gauge_tests/
  step_impl
    step_impl.py
```

`gauge_tests/`をワークディレクトリとして`gauge run`する前提で、`step_impl.py`から正しく`import hoge`するには、以下のようにする必要がある。

```python
# gauge run からのインポートエラー時、何もでなくて困るので、try-except
try:
    from getgauge.python import step, before_scenario, Messages
    import sys
    import os
    import traceback
    # gaugeは、分散したコードまで見てくれないのでソースパスを追加
    sys.path.append(os.path.join('..', 'hoge_src'))
    import hoge
except Exception as e:
    print(traceback.format_exc())
    raise e

# --------------------------
# Gauge step implementations
# --------------------------
@step("何かする")
def do_something():
    hoge.do_something()

...
```
[Qt] WindowのBackground Colorの変更方法


```c++:background

#include <QGuiApplication>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    /* ここから下が背景色を変える部分 */
    QPalette pal = palette();
    
    /* ピンクっぽい色を指定 */
    QColor color = QColor(234, 155, 211, 50);

    /* QPallete::Windowを指定することでBackgroundを指定したことになる */
    pal.setColor(QPalette::Window, color);

    this->setAutoFillBackground(true);
    this->setPalette(pal);
    this->show();
}

```
docker-composeでwebdavとsambaの両方から同じファイルに書き込む

## 発生した問題
[bytemark/webdav](https://hub.docker.com/r/bytemark/webdav/)を使ってdocker-composeで構築したWebDavのファイルをSamba経由で更新したい要件があったので[dperson/samba](https://github.com/dperson/samba)を追加し、ホストの同じディレクトリを双方にマウントしました。
しかし、WebDavで追加したファイルをSambaで変更・削除しようとすると権限が無いというエラーが発生しました。

## 原因
WebDavにファイルを追加するとサーバーにはパーミッション644でファイルが作成されます。
また、Sambaにファイル追加するとサーバーにはパーミッション664でファイルが作成されます。
WebDavとSambaは実行ユーザーが異なりファイルの所有者が違うため、お互い相手が追加したファイルの書き込みが出来ません。

## 対応
WebDavの実行ユーザーのUIDをSambaの実行ユーザーのUIDに変更して、ファイルの所有者を無理やり同じにします。

まず、WebDavのコンテナIDを確認します。

```bash
$ docker ps
CONTAINER ID  IMAGE             COMMAND                  CREATED             STATUS                       PORTS                                            NAMES
[コンテナID]   bytemark/webdav   "docker-entrypoint.s…"   About an hour ago   Up About an hour             443/tcp, 0.0.0.0:8882->80/tcp, :::8882->80/tcp   hoge_webdav_1
```

WebDavの実行ユーザーを確認します。

```bash
$ docker exec -it [コンテナID] cat /usr/local/apache2/conf/httpd.conf | grep ^User
User www-data
```
WebDavの実行ユーザーは www-data であることがわかりました。

WebDavのpasswdファイルをホスト側にコピーしておきます。

```bash
$ docker cp [コンテナID]/etc/passwd ./hoge
```
続いて、Sambaの実行ユーザーとそのUIDを確認します。

```bash
$ docker ps
CONTAINER ID  IMAGE             COMMAND                  CREATED             STATUS                       PORTS                                                                                                                                 NAMES
[コンテナID]   dperson/samba     "/sbin/tini -- /usr/…"   About an hour ago   Up About an hour             0.0.0.0:139->139/tcp, :::139->139/tcp, 0.0.0.0:137-138->137-138/udp, :::137-138->137-138/udp, 0.0.0.0:445->445/tcp, :::445->445/tcp   hoge_samba_1

$ docker exec -it [コンテナID] cat /etc/passwd | grep ^smbuser
smbuser:x:100:101:Samba User:/tmp:/sbin/nologin
```
Sambaの実行ユーザーのUIDは 100 であることがわかりました。

先程コピーしておいた passwd ファイルの www-data の行のUIDを100に書き換えます。

```bash
www-data:x:82:82:Linux User,,,:/home/www-data:/bin/false
　　　　　 　↓
www-data:x:100:82:Linux User,,,:/home/www-data:/bin/false
```
もし100のUIDがすでに使用されていた場合はhttpd.confを書き換えてApacheの実行ユーザーを変えることになると思います（未検証）

このpasswdファイルをdocker-compose.ymlに定義してマウントします。
docker-compose.ymlの全体は以下の通りです。

```yaml:docker-compose.yml
version: '3'
services:
  webdav:
    image: bytemark/webdav
    restart: always
    ports:
      - "80:80"
    environment:
      AUTH_TYPE: Digest
      USERNAME: hoge
      PASSWORD: fuga
      LOCATION: /hoge
    volumes:
      - ./hoge/dav:/var/lib/dav
      - ./hoge/zdav.conf:/usr/local/apache2/conf/conf-enabled/zdav.conf
      - ./hoge/passwd:/etc/passwd

  samba:
    image: dperson/samba
    ports:
      - "137:137/udp"
      - "138:138/udp"
      - "139:139/tcp"
      - "445:445/tcp"
    volumes:
      - ./hoge/dav/data:/mnt/hoge:rw
    command:
      -s "hoge;/mnt/hoge;yes;no;yes;all;none"
    restart: unless-stopped
```
zdav.confファイルは[こちら](https://qiita.com/rc-saka/items/25c06f9ebc7bc04a9f02)を参照して下さい。
node.js超入門ノート2(Express導入編)

# Expressとは
node.jsにおけるWebアプリ開発のフレームワークです。
今回はExpressのひな形と基本的なパッケージが用意されている、Express Generatorを使います。

# Express環境構築
前回のDockerでの環境構築で導入済みですが、まだの人は以下のコマンドでExpress Generatorをインストールしてください。

```
npm install -g express-generator
```

次にひな形を作成します。

```
express --view=ejs [アプリ名]
```
--view=ejsの指定でテンプレートエンジンの指定になります。
HTMLと似た言語であるので今回はEJSを使います。(デフォルトはJade)

次に必要なパッケージをインストールします。

```
cd [アプリ名]
npm install
```
先ほど作成したひな形の中のpackage.jsonをインストールします。

以下のコマンドでアプリケーションを起動します。

```
npm start
```

以下のURLにアクセス出来れば導入はひとまず終わりです。
http://localhost:3000/

#　ファイル構成
- binフォルダ 

アプリケーションを実行する為のコマンド保管場所

- publicフォルダ 

公開ディレクトリです。
ここにあるものはURLを指定して直接アクセスすることができます。

- routesフォルダ 

ルーティング(アドレスと実行するスクリプトの関連付け)を追加していくことができます。

- viewsフォルダ 

テンプレートファイルの保管場所

- node_modulesフォルダ 

node.jsのパッケージの保管場所

- app.js

アプリケーション本体部分のメインプログラム

- package.json

npmパッケージ関する情報を記載したファイル


https://qiita.com/Glider2355/items/b7f1ef2947b6e7e0ad71
【UNITY　C＃】　変数同士の割り算で少数を出したい時

変数同士の割り算で小数を出したいけど、変数の後ろにはｆが付けられないじゃないか（怒り）となったので、ググってみたけど中々出てこない。
探し求め続けること苦節３０分、ようやく見つけたのでここに記しておく。



float percent = (float)correct / (float)count 



要は変数の前に（float)をつければ良いのだ。

なぜこんな簡単なことを誰も書いていてくれなかったのか……
参考にさせて頂いた記事
https://norm-nois.com/blog/archives/5486
ありがとうございます。
自由度調整済み決定係数をPythonで求める

#作業環境
Jupyter Notebook(6.1.4)を用いて作業を進めた。
各versionは`pandas`(1.1.3), `scikit-learn`(0.23.2), `statsmodels`(0.12.0)である。

#やりたいこと
最小二乗法で最適化された線形回帰モデルについて学習し、そのモデルを評価する指標として決定係数や自由度調整済み決定係数を学んだ。学習時には手作業で係数を追加したり削除したりしながら決定係数を比較していたが、これを自動探索するプログラムを練習として組んでみたいと考えた。
つまりやりたいことは、データ全体を渡したら最も決定係数が高くなる説明変数の組み合わせとその決定係数を返してくれるプログラムを考えて作ってみたい。

その前準備として、決定係数や自由度調整済み決定係数について、その定義とPythonでの求め方をまとめる。

#決定係数、自由度調整済み決定係数とは
**決定係数$R^2$**は以下の式で定義される。

$$
R^2 = \frac{\sum(特徴量の効果)^2}{\sum(偏差)^2} = 1-\frac{\sum(回帰残差)^2}{\sum(偏差)^2}
$$

ここで、偏差とは目的変数の平均と各データ点の差であり、回帰残差とは回帰モデルの予測値と各データ点との差である。つまり、選んだ特徴量で作った回帰モデルがどれくらいよく目的変数を説明できているか、という解釈ができる。

さらに、**自由度調整済み決定係数${R^*}^2$**は以下の式で定義される。

$$
{R^*}^2 = 1-\frac{\frac{\sum(回帰残差)^2}{n-p-1}}{\frac{\sum(偏差)^2}{n-1}}
$$

ここで、$n$はデータ点の個数、$p$は説明変数の個数である。説明変数を増やすと必然的に決定係数は増加してしまうため、その影響を調整した指標である。簡単な式変形から$R^2$と${R^*}^2$の関係は以下の式となることがわかる。

$$
R^{*2}= 1-(1-R^2)\frac{n-1}{n-p-1}
$$

今回は自由度調整済み決定係数を比較して回帰モデルをチューニングしていく。

#検証に使用するデータ
今回は`scikit-learn`の`datasets`の中のボストン住宅データ(説明変数13個)を使って検証していく。以下のように説明変数データセットと目的変数データセットを作成した。

```python
import pandas as pd
from sklearn.datasets import load_boston
X = pd.DataFrame(load_boston().data, columns=load_boston().feature_names)
y = pd.DataFrame(load_boston().target, columns=['target'])
```

#Pythonで自由度調整済み決定係数を求める
今回は`sklearn.linear_model`と`statsmodels.api`を使用する方法を使用する方法の２通りで試す。
##`sklearn.linear_model`を使用して求める
まずは線形回帰モデルを作成して決定係数を求める

```python
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X, y)
model.score(X, y)
#---> 0.7406426641094094
```

`sklearn.metrics`の`r2_score`を使った方が決定係数をより早く求められる。

```python
from sklearn.metrics import r2_score
y_pred = model.predict(X)
r2_score(y, y_pred)
#---> 0.7406426641094094
```

自由度調整済み決定係数については式を定義して求める。

```python
#自由度調整済み決定係数を計算する関数を定義する
def adj_r2_score(y_true, y_pred, p=X.shape[1]):
    return 1-(1-r2_score(y_true, y_pred)) * (len(y_true)-1) / (len(y_true) - p - 1)

adj_r2_score(y, y_pred)
#---> 0.7337897263724629
```


##`statsmodels.api`を使用して求める
`statsmodels.api`を使用すると簡単に決定係数や自由度調整済み決定係数を求めることができる。

```python
import statsmodels.api as sm
#定数項の追加
X1 = sm.add_constant(X)
m = sm.OLS(y, X1)
result = m.fit()
#決定係数の表示
print(result.rsquared)
#---> 0.7406426641094095
#自由度調整済み決定係数の表示
print(result.rsquared_adj)
#---> 0.733789726372463
```

`LinearRegression`ではデフォルトとして定数項のある回帰モデルが作成されるが、`statsmodels`ではデフォルトでは定数項のない回帰モデルが作成される。そのためモデル作成前に定数項の追加を行っている。


2通りの結果を見比べるとほとんど同じ結果を得られることが確認できた。
⚠️【Sass】DEPRECATION WARNING: Using / for division is deprecated and will be removed in Dart Sass 2.0.0.

2021年8月現在の1系Dart Sassでは、スラッシュを計算式に使うと警告が出るようになっています。
[2系では廃止される](https://sass-lang.com/documentation/breaking-changes/slash-div)ため、除算を行うときにはビルトインモジュールの`sass:math`を利用します。

```scss:deprecated
body {
  font-size: 16px;
  line-height: (24 / 16);
}
```

↓

```scss:modern
@use "sass:math";

body {
  font-size: 16px;
  line-height: math.div(24 / 16);
}
```

## 💡 Fun fact

プライベートで実施したペアプロのなかで話題になったのですが、このスラッシュの非推奨～廃止の件は5月ごろに[bootstrapでもissueが立っていた](https://github.com/twbs/bootstrap/issues/34051)ようです。

Dart-sassの[mathモジュール](https://sass-lang.com/documentation/modules/math)には、除算の`math.div`以外にも様々な関数が用意されています。

モジュール自体も`math`の他にいろいろあるので、要チェック…🥒
https://sass-lang.com/documentation/modules

- `sass:math` - 数値計算系
- `sass:string` - 文字列の結合、検索、分割
- `sass:color` - 色の操作
- `sass:list` - いわゆる配列の利用
- `sass:map` - いわゆる連想配列の利用
- `sass:selector` - CSSセレクタの操作
- `sass:meta` - Sassの内部処理の利用、プログラミング的な処理に必要なもろもろ
GitHub公式がブラウザ上でVS Codeを使える機能を実装したので、レビュー

先日、GitHub がブラウザ上で VS Code を使える新機能を発表しました。


以前から予告されている Codespaces とは異なり、すべてのユーザーが無料で使用できます。

ということで、私も使ってみました。


# 使い方
使い方はとても簡単。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">🤫 New shortcut: Press . on any GitHub repo. <a href="https://t.co/AHTSDot4qc">pic.twitter.com/AHTSDot4qc</a></p>&mdash; GitHub (@github) <a href="https://twitter.com/github/status/1425505817827151872?ref_src=twsrc%5Etfw">August 11, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

このツイートの動画のように、GitHub のリポジトリ画面で、キーボードの「.」(ピリオド)キーを押すだけ！

# どんなものか

簡単に行ってしまえば、「VS Code がブラウザ上でも動く」サービスです。

GitHub が来月から提供を開始する類似のサービスとして、Codespaces がありますが、これは法人向けで、料金も発生します。その分機能が多いです。

一方、こちらの Web  Editor は誰でも無料で使えるサービスですが、機能は限られています。


# 使用感

使ってみましたが、とてもサクサク動きます。使っているのは、Celeron CPU の低スペノートPCなのですが、もっさりすることもなく、快適に使えます。

気になった点として、画面右下に「Layout: us」と表示されており、JIS配列では使えないのかと思っていましたが、問題なく使えました。記号の入力も含めてバッチリです。

![レイアウトがUSになっている](https://user-images.githubusercontent.com/75155258/129321958-cced00cc-e868-48f3-9dd5-b496114f544b.png)


では、この Web Editor のメリット・デメリットをご紹介します。

# メリット

## ローカルの VSCode の環境が同期される
ローカルの VSCode で GitHub アカウントでの同期を有効にしている場合は、Web Editor にも反映されます。

ただ、拡張機能と一部の設定は同期されませんでした...

## 動作が軽い

低スペックのパソコンでも、快適に動作します。

ちなみに、今回検証に使用した PC のスペックは Celeron N4020 / RAM 4GB です。

## GitHub との相性が抜群
当たり前ですが、GitHub との相性は抜群です！

Commit はもちろん、Issue や Pull Request だってできます。

ちなみに、Web Editor でコミットをすると、GitHub の方にも反映されます。`git push` の工程がないので、はじめは戸惑うかもしれませんが、すぐに慣れます。

## 拡張機能が使える

拡張機能もインストールできます。スニペット等もそのまま使えるので、安心です。

## OS を問わない
PC のみならず、タブレットでも開発ができます。スマホだと画面が小さすぎて無理がありますが。


# デメリット

## ターミナルが使えない
ターミナルは残念ながら使えません。Codespaces だと使えるようですが...

拡張機能でカバーできる部分もあるかもしれませんが、あまりハードな開発はできません。

## 使えない拡張機能が多い

ローカルでは使えても、Web Editor では使えない拡張機能が結構多いです。

個人的には、

- Live Server
- テキスト校正くん

が使えないのが痛いですね...

フォーマッターも使えません。逆に、スニペット系はサポートされているものが多いです。

Live Server に関しては、類似サービスの [Gitpod](https://www.gitpod.io/) では使えるので、 Gitpod に比べるとやや劣った印象を受けます。

ただ、Gitpod は無料プランだと時間制限があるので、結局はローカル環境での開発が一番快適でしょう。

法人の場合は Codespaces が良いと思います。実際に GitHub 社のエンジニアの方々が使いながら改善されているので、「かゆいところに手が届く」仕様になっていると思います。Codespaces ならターミナルも使えますし。

## Markdown を扱っている時、画像を挿入できない
昔からある GitHub のブラウザ上の編集画面では、画像をドラッグ&ドロップすれば Markdown で書いているものに画像を挿入できたのですが、Web Editor ではできません。

これが地味に面倒。いちいち Issue かなんかの編集画面に画像をアップロードして、URL を Web Editor にコピペしないといけない。

ただ、昔ながらのブラウザ上の編集画面とは違って、リアルタイムで作業が保存される(コミットはされない)点は便利です。

# どのような用途に向いているか
- コンパイルがいらない言語(JavaScript、Python など)での軽いプログラミング
- ブログの執筆
- コードの閲覧

Web Editor の用途はかなり限られてしまいますが、手軽な開発環境としてはかなり優秀ではないのでしょうか。
PyQtGraphとmatplotlibを真面目に比較する3（アニメーションの描画）

シリーズ3部作目です．
[1部](https://qiita.com/Yukiho_P/items/66d15413f53941c1a569)，[2部](https://qiita.com/Yukiho_P/items/29ef5d17cd6a7f06564f)

# 環境
- Mac mini(M1) Big Sur
- Python 3.9.6(arm64)
- numpy 1.21.1
- matplotlib 3.4.3
- PyQtGraph 0.12.2

# 目標
　高速レンダリングを活かしてmatplotlibよりもフレーム数の多いアニメーションを描画する．

# 実習
　以下を読み込んであることを前提とします．

```head.py
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import pyqtgraph as pg
from pyqtgraph import QtCore

np.random.seed(39)
x = np.linspace(0, 10, 100)
t = np.linspace(0, 10, 1000)
x, t = np.meshgrid(x, t)
y = np.cos(x - 100*t)
```

## matplotlib.animation
　matplotlibのアニメーションはまだよく分かっていないため，こちらの[質疑](https://teratail.com/questions/159258)を参考にしました．

```plot10.py
#fig, ax = plt.subplots()
win = pg.plot()

#ims = []
curve = win.plot()

'''
for I in range(Len(t)):
    axes = ax.scatter(x[I], y[I], c='k')
    title = ax.text(
                 0.5, 1.01,
                 f'time = {t[I,0]:.3f}',
                 ha='center', va='bottom',
                 transform=ax.transAxes,
                 fontsize='large',
               )
    ims.append([axes, title])
'''
idx = 0
def update():
    global curve, win, idx, x, t, y
    curve.setData(x[idx], y[idx])
    win.setLabels(title=f'time = {t[idx,0]:.3f}')
    idx = (idx+1)%len(t)

#ani = animation.ArtistAnimation(fig, ims, interval=1)
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(1)

#ani.savefig('animation.gif')
pg.exec()
```
　$x$軸方向に進行する波動が描画できるはずです．PyQtGraphだと実行と共にグラフが表示されるのに対して，matplotlibは23分もかかりました．画像貼ろうとすると重すぎるのかエラーが出るのでありません．
　PyQtGraphでの注意点として最初に`win = pg.plot()`で`PlotItem`をインスタンス化した後に，`curve = win.plot()`で`PlotDataItem`をインスタンス化しておく必要があります．[前回](https://qiita.com/Yukiho_P/items/29ef5d17cd6a7f06564f)調べたように`PlotDataItem`は描画される線や点を保持します．そして`update`を呼び出すごとに`setData`で中身を更新していく仕掛けです．この更新作業は`pg.QtCore.QTimre`がやってくれます．また最後の`start(1)`はおそらくフレーム間隔に1 msを設定できているはずです．フレームレートの計測ができてないので実際は分かりませんが，少なくともこの数字を大きくするとアニメーションの再生速度が遅くなりました．

## ani.savefig()
　どうにもPyQtGraph単体だと無理っぽい．[こちら](https://stackoverflow.com/questions/24961127/how-to-create-a-video-from-images-with-ffmpeg)の情報に従ってffmpegを試したいです．

# 結論
　描画も再生速度も申し分なし．保存は一手間要りそう．

# 希望
1. 全フレームを一度書き出してからffmpegでエンコードしたい
【VBA】任意のフォルダーのファイルを全て処理するコード

#はじめに
とあるフォルダーに処理したいファイルを複数個入れて、それらを読み込んで処理するコードです。

#コード
~~~VBA
Sub test()
'パスの指定。このコードではマクロがあるフォルダーを指定

  DIR_PATH = ThisWorkbook.Path
  Dim fl_name As String
  fl_name = Dir(DIR_PATH & "\*.xlsx*")
  If fl_name = "" Then
    MsgBox "エクセルファイルがありません。"
    Exit Sub
  End If

  Do
    Workbooks.Open Filename:=DIR_PATH & "\" & fl_name
    fl_name = Dir
    
    'ここに処理を入れる。
　　　Cells(1,1)="Hello"
    
  Loop Until fl_name = ""
End Sub
~~~

#コードの説明
　最初にパスを設定します。
　上のコードでは、Thisworkbook.Pathとしているため、このマクロが書かれたファイルのある場所を読み込むことになります。
　また読み込むファイルの拡張子を"xlsx"と指定しています。この2箇所を変えることで、他の場所・ファイルを読み込むことが出来ます。
　後はDo loopで全てのファイルに処理を施します。今回はセルの(1,1)、すなわちセルA1にHelloと入力されます。

#実際の使い方
例えば下の画像のような状態でtestに入れた上記のコードを実行すると、Book1～Book4のセルA1が"Hello"になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1177046/568d13bd-3106-6b58-a476-b3db61065a46.png)

#終わりに（注意点）
- このコードはopenでファイルを開くため、実行する処理の最後にcloseを入れた方がいいです。特に大量のファイルを処理する前にはテストをしておかないとPCが落ちてしまいます。
- このコードは処理速度の最適化が出来てません。
- 最後までお読みいただきありがとうございます。
4章 機械語 (コンピュータシステムの理論と実装)

# はじめに

これは、「コンピュータシステムの理論と実装」(以下「Nand2Tetris」という)の第4章 機械語のプロジェクトに対するレポートである。

Qiitaでは、画像の利用に制約があるため、フローチャートなど掲載することは省いている。

# プロジェクトに対するレポート

## 目標
* 機械語によるプログラミングを行いHackを知ること。

## 材料
* Nand2Tetrisで定義している機械語
* CPUエミュレータ

## 実装

### 乗算プログラム
Hackでは加算器しかないため、乗数分、被乗数を加算することで乗算を行う。

LOOPから抜け出す分岐は、ループの最初に入れている。そして分岐予測できるようにしている。

```asm:Mult.asm
    // Put your code here:
        @R2
        M=0
(LOOP)
        @R1
        D=M
        @END
        D;JLE
        @R0
        D=M
        @R2
        M=D+M
        @R1
        M=M-1
        @LOOP
        0;JMP
(END)
        @END
        0;JMP
```

### 入出力操作プログラム
キーボード入力部とスクリーンペイント部に大きく分かれる。

ペイント部では、最初1ビットずつ変更しようとしたが、メモリはワード単位であることに気づきワード単位で置き換えるように変更している。

レジスタの使い方は以下の通りである。

| レジスタ | 内容 |
|:-:|:-:|
| R0 | 色　黒：−1、白：0 |
| R1 | ピクセルアドレス  |

```asm:Fill.asm
    // Put your code here:
        @R0
        M=0
        @R1
        M=0
(LOOP)  
        @KBD
        D=M
        @COLORBLACK
        D;JEQ
        @R0    //color
        M=0
        @PAINT
        0;JMP
(COLORBLACK)
        @R0    //color
        M=-1
        @PAINT
        0;JMP
(PAINT)
        @SCREEN
        D=A
        @8191
        D=D+A
        @R1  // Address 
        M=D
(FILL)
        @R0  // color
        D=M
        @R1
        A=M
        M=D
        @R1
        MD=M-1
        @SCREEN
        D=D-A
        @FILL
        D;JGE
        @LOOP
        0;JMP
(END)
        @END
        0;JMP
```
ITエンジニアはキツイ面もあるがやりがいがある

インターネットが普及した今、IT業の需要が増えつつあります。中でもエンジニアは開発において重要な存在です。今後さらに教育の分野でも拡大されていくことでしょう。
 
企業の社員としてエンジニアは安定していると言えますが、やはり自分のペースで仕事を選べるフリーランスが魅力です。

<h2>ITエンジニアはきつい？その理由は？<h2/>

自分の場合IT業を始めたのが遅く、年齢的に企業で勤めることは難いのが現状でした。求人はどれも管理職ばかりで始めたばかりの自分には適していない難易度の高いものでした。
 
 そんな自分に残された道はフリーランスでした。フリーランスなら自分で仕事を選べる、マイペースで働けるといメリットも満載です。ただ、仕事はどれも待っているだけでは訪れません。自分から飛び込み多くの案件に参加し、仕事を求めました。クライアントの求める条件を具現化するのはなかなかたいへんです。満足いくまでに時間を費やすため、1つの仕事が終わるまでの期間も長くなります。
 
 1つの仕事が終了するまでに時間がかかるので、収入を得るためにいくつも同時進行が当たり前でした。それが想像していた以上にキツイです。


<h2>ITエンジニア時代のエピソード<h2/>


フリーランスとして開始した当時は、クライアントの条件をクリアするまでに時間を費やしました。クライアントが求めているのはこのようなことなんだろうなと自分なりに解釈するのですが、それが違うことも多々ありました。そんな時はまた1から組み立てなければなりません。しかし、そのようなマイナス点も貴重と思うべきです。今後にいかせるパターンもあるので、ムダにできません。
 
 クライアントとのやり取りを地道に続けたら継続の仕事が舞い込んで来たこともありました。思いがけないチャンスを掴めたので、結果的に失敗が良かったのかなと思います。

<h2>ITエンジニアになりたい人へ<h2/>


企業で社員として勤められるなら、安定した収入を得るためにもそちらが良いかと思います。しかし、フリーでも地道に小さな仕事を積み重ねることで自分の仕事に納得できるようになります。
 
 最初から良い具合にトントン拍子に進められる人もいるのかもしれませんが、多くの人は最初から思い通りにはいきません。ただ、好きな仕事を自分のペースでできるのがフリーランスの醍醐味でもあります。初めは小さな仕事をこなし、実力をつけてきたら大きな仕事に参加するというように段階を踏んでいくと良いかと思います。
 
 また、プライベートとのバランスも大切です。仕事をしながら気分転換もしましょう。

<h2>IT及びWebエンジニア専用の年収診断<h2/>

↓↓↓↓無料診断はこちら↓↓↓↓
<strong><a href="https://diagnostics.tech-freak.co.jp/">年収アガル</a></strong>
<br />※年収アガルは、登録なしの無料でご利用いただけます。
年収アガルについて詳しくは下記の記事及び公式サイトに記載していますので、ご覧ください。
<a href="https://tech-freak.co.jp/annual-income-diagnosis/"><strong>・【年収アガル】ITエンジニア専用の年収診断サービスをリリース致しました。</strong></a>
<strong><a href="https://tech-freak.co.jp/">・テックフリーク | IT・Webエンジニアの転職サポート専門SESメディア</a></strong>
【Vue.js 2.3以降】親子コンポーネントのプロパティ受け渡しは.syncでやると楽になる。【Vuetify】date-picker実装例


# 公式ページおよび結論

https://jp.vuejs.org/v2/guide/components-custom-events.html#sync-%E4%BF%AE%E9%A3%BE%E5%AD%90
> 2.3.0から新規追加

> “双方向バインディング”がプロパティに対して必要な場合もあります。残念ながら、本当の双方向バインディングはメンテナンスの問題を引き起こす可能性があります。子コンポーネントは親でも子でもその変更元が明らかでなくても親を変更させることができるからです。

> このため代わりに update:myPropName というパターンでイベントを発火させる事をお薦めします。例えば title というプロパティを持つ仮のコンポーネントがあった場合、意図的に新しい値を割り当てる事ができます


## 実装例

Vuetify（1.5、ドキュメント比較するとおそらくVuetify2.x以降でも動くと思う）のdate-pickerを用いて妙に長く書かないといけないdate-pickerをコンポーネント化する。

https://v15.vuetifyjs.com/en/components/date-pickers

※以下実装例はNuxt.jsの書き方で記述する。他Vue.js関連フレームワークであっても、プロパティなどの考え方は一緒だと考える。

### 親側

```vuejs
<template>
  <!-- 子であるdatepickerを設定する。このとき.syncを付けておくのが鍵。 -->
  <datepicker :date.sync="date"></datepicker>
  <!-- 他、自作コンポーネントdatepickerの配置および呼び出しなど色々あるけど中略 -->
</template>

<script>
export default {
  data() {
    return {
      // 親側のdate。こちらに反映される
      date:''
    }
  }
}

</script>
```

### 子側

```vuejs
<!-- 殆どはvuetify公式ページにある
　　「テキスト欄クリックでカレンダーがポップアップし、
　　　日付押下すると日付がテキスト欄に適用される部品」 -->
<template>
  <v-menu
    ref="datetime"
    v-model="datetime"
    :close-on-content-click="false"
    transition="scale-transition"
    offset-y
    min-width="auto"
  >
    <template v-slot:activator="{ on }">
      <!-- ここでのv-modelには親からのプロパティは直接指定しない。 -->
      <v-text-field
        autocomplete="off"
        v-model="_date"
        prepend-icon="event"
        v-on="on"
        readonly
        clearable
      ></v-text-field>
    </template>
    <v-date-picker
      v-model="_date"
      locale="ja-jp"
      :day-format="nowdate => new Date(nowdate).getDate()"
      no-title
      scrollable
      @input="datetime = false"
    >
    </v-date-picker>
  </v-menu>
</template>

<style scoped></style>

<script>
// emit時のupdate呼び出し文字列
const emitUpdate = 'update:'
// 親からのプロパティ名集
const propName= {
  date:'date'
}

export default {
  // 親からもらうプロパティ名を指定
  props: [propName.date],
  data() {
    return {
      datetime: false
    }
  },
  computed: {
    // 子コンポーネント側の算出プロパティをget,setで制御
    _date: {
      // 親からプロパティを貰ったら反映
      get: function() {
        return this.date
      },
      // 子で値が変更されたなら、その代わりにemit発火によって親へとupdate
      // update対象をプロパティごとに指定できるため、複数プロパティにも対応可能
      set: function(value) {
        this.$emit(emitUpdate + propName.date, value)
      }
    }
  }
}
</script>

```

子側で色々書いておけば、親側で使う時はコンポーネント呼び出しと引数設定をしておけば子側で処理した値を引っ張ってこれる。まさに理想。


# 結論にいたるまでの$emitの基本と面倒なところ

https://jp.vuejs.org/v2/api/#vm-emit

vue.jsにおいて、本当の双方向バインディングはメンテナンスの問題を引き起こす可能性があるため推奨されておらず、上手く動かないことが多い。

自身の認識では、emitは子コンポーネントから親コンポーネントへと「〇〇イベントを実行してください」といった発火イベントを起こすことができると考えている。
よっては基本的には親側のメソッドでイベント内容を記述する必要がある。


> 1：親が子へとプロパティを渡す（そのプロパティ自体は親コンポーネントのプロパティであるため、他コンポーネントが変更を行ってしまっては、何処で変更されたかといった情報が読み取れなくなってしまう）
2：子が処理を行った後、emitによって親へと「〇〇というイベントが親にはありますよね、実行してください」と発火させる
3：親が自身のイベントを実行し、親プロパティへの反映や親側の処理を起動させる


ただ、親子間での単純なプロパティ変更である場合、上記のような処理記述は面倒でしかないし、再利用時のバグになりかねない。
.syncの機能はそこらへんを簡略化してくれていると考えている。
vmware仮想マシン上のUbuntuでmultipassを動かす為に仮想 CPU パフォーマンス カウンタが必要だった話

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

# 0. はじめに

vmwareの仮想マシンでUbuntuを動かしてmultipassから仮想マシンをネストして動かそうとしたときに
「仮想 CPU パフォーマンス カウンタ」が必要だった、というお話です。

# 1. 何が起こったか？

multipassで仮想マシンを動かそうとすると以下の様なエラーがでました。

```io
user@user-virtual-machine:~$ multipass launch --name test2104 21.04
launch failed: The following errors occurred:
qemu-system-x86_64: error: failed to set MSR 0x48f to 0x7fffff00036dfb
qemu-system-x86_64: /build/qemu-rbeYHu/qemu-4.2/target/i386/kvm.c:2691: kvm_buf_set_msrs: Assertion `ret == cpu->kvm_msr_buf->nmsrs' failed.
```

# 2. 対応方法

## 2-1. vmware ESXiのNested Virtualizationを有効にします

ググれば沢山出てくると思うのでここでは割愛します。
`vhv.enable = "TRUE"`を`/etc/vmware/config`に書きましょう

```file:/etc/vmware/config
vhv.enable = "TRUE"
```

これで、vmxが有効になります。
cpuinfoをgrepすると以下の様にvmxが追加されます

```
$ grep -E 'svm|vmx' /proc/cpuinfo
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36
 clflush mmx fxsr sse sse2 ss syscall nx rdtscp lm constant_tsc arch_perfmon nopl xtopology 
tsc_reliable nonstop_tsc cpuid pni pclmulqdq vmx ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt 
tsc_deadline_timer aes xsave avx hypervisor lahf_lm pti ssbd ibrs ibpb stibp tpr_shadow vnmi 
ept vpid tsc_adjust arat md_clear flush_l1d arch_capabilities
```

## 2-2. 仮想 CPU パフォーマンス カウンタを有効にします

CPUのオプション設定で`仮想 CPU パフォーマンス カウンタの有効化`にチェックを入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/c83d1010-e39a-aa9c-bb29-88391b4df326.png)

# 3. 動作確認
VMwareホストと仮想マシンを再起動して`multipass start` します。

multipassの仮想マシンが動いたか`multipass listで`確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/d6a60808-a429-cff5-7890-9ae56290fb09.png)

バッチリ動きましたね。

# 4. 環境情報

VMware : ESXi 7.0
Ubuntu OS: Ubuntu 20.04.2 LTS
multipss: multipass  1.7.0
qemu: 4.2-3ubuntu6.17

# 5. まとめ

vmwareで動かせると、bridgeも使えるようになったmultipassは超便利だと思います！

最初、以下のQEMUのバグかとおも思ったのですが、
Bug #1882774 “issues with secondary VMX execution controls” : Bugs : qemu package : Ubuntu
https://bugs.launchpad.net/ubuntu/+source/qemu/+bug/1882774

メッセージをググり直すと以下の記事がヒットしました。
Can't start minishift on Ubuntu 18.04: "qemu-system-x86_64: error: failed to set MSR 0x38d to 0x0" · Issue #3210 · minishift/minishift
https://github.com/minishift/minishift/issues/3210#issuecomment-602923316

VMware + vMotionが有効な場合は、「CPUパフォーマンスカウンター」が利用できない場合があるそうなので、ご注意ください。

https://docs.vmware.com/jp/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-F920A3C7-3B42-4E78-8EA7-961E49AF479D.html

``` 
仮想 CPU パフォーマンス カウンタが有効になっている場合、互換性のある CPU パフォーマンス カウンタを持つホストにのみ
仮想マシンを移行できます。
ESXi ホストの BIOS がパフォーマンス カウンタを使用しているか、Fault Tolerance が有効になっている場合、一部の仮想
パフォーマンス カウンタは仮想マシンで使用できない場合があります。
```
SAM CLIでテンプレートを別名指定した時のmodule入りLambdaの注意点

# はじめに

* SAMでLambdaを作成する時、コードのディレクトリに`requirements.txt`を配置すると自動的にmoduleを拾ってきてくれる
* SAMでTemplate名を標準外のもので作成することもでき、その時は`-t [template path]` / `--template-file [template path]`で指定できる
  * コードは一緒で環境毎に内容を分けたいときとか
* このときに普通に以下のようなコマンドで実行するとmoduleがいないLambdaが上がってしまう

```bash
sam build -t template.dev-env.yaml
sam package --profile dev -t template.dev-env.yaml --s3-bucket artifact-no-bucket --output-template-file packaged.yaml
sam deploy -t packaged.yaml ~~~~~
```

# 解決方法

* `sam build`を実行すると`.aws-sam/build/`配下にmoduleが入った各種Lambdaがtemplateで指定したものごとにディレクトリを分けて出力される
* `.aws-sam/build/template.yaml`にはその出力されたディレクトリを`CodeUri`に指定した形のtemplateが出力されている
  * つまり`sam package`のときに`.aws-sam/build/template.yaml`をtemplateに指定してあげればよかった

```bash
sam build -t template.dev-env.yaml
sam package --profile dev -t .aws-sam/build/template.yaml --s3-bucket artifact-no-bucket --output-template-file packaged.yaml
                              ^^^このあたりのパスを変えた^^^
sam deploy -t packaged.yaml ~~~~~
```
github.devをiPadから起動する

昨日に、自分のGithub Repositoryでもgithub.dev(VS Code Web)が使えるようになりました。
Repository上でキーボードの「.」を入力すると起動するあれです。

こんな人がいるか分からないけど、ふと外部キーボードがないiPadでどうやって起動するのかと思ったけど、
![6C735A3C-B448-4306-958E-AFDFD6D26058.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123678/ba30c116-3837-ec46-ef6f-5dfa3ff50ebe.png)

Repositoryにアクセスして、

![0CBDC7BC-2220-43C8-BCBD-E663E2EFDC37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123678/eab7f086-0d54-da4d-7e10-7b7199c068d3.png)

URLの```github.com```を```github.dev```に変更してアクセスするだけでした。

![4352D508-C30A-4020-91D3-8D5D1DE49FF9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123678/e3894684-0a4e-a48e-48b6-d8add0e01dd8.png)

当たり前ですね。「.」はあくまでもキーボードショートカットですからね。

外部キーボードがあればiPadでの開発環境が少し良くなりそうな予感！！
何ができるのか分からないけど試していこうと思います。
【Composer】パッケージを追加時に「Allowed memory size」エラー。

自分用のメモとして残します。

下記コマンド（Laravel用のIDEヘルパー）を実行時にメモリ不足によるエラーが発生。

```shell
composer require --dev barryvdh/laravel-ide-helper
```
<details>
<summary>（クリックでエラー内容表示）</summary><div>

```shell

$ composer require --dev barryvdh/laravel-ide-helper
Warning from https://repo.packagist.org: Support for Composer 1 is deprecated and some packages will not be available. You should upgrade to Composer 2. See https://blog.packagist.com/deprecating-composer-1-support/
Using version ^2.10 for barryvdh/laravel-ide-helper
./composer.json has been updated
Loading composer repositories with package information
Warning from https://repo.packagist.org: Support for Composer 1 is deprecated and some packages will not be available. You should upgrade to Composer 2. See https://blog.packagist.com/deprecating-composer-1-support/
Updating dependencies (including require-dev)
PHP Fatal error:  Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes) in phar://C:/ProgramData/ComposerSetup/bin/composer.phar/src/Composer/DependencyResolver/RuleSetGenerator.php on line 129

Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes) in phar://C:/ProgramData/ComposerSetup/bin/composer.phar/src/Composer/DependencyResolver/RuleSetGenerator.php on line 129

Check https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors for more info on how to handle out of memory errors.
```
</div></details>


ちょこちょこなるので、自分用のメモとしてのこします。


#やり方
composer コマンドの前に **COMPOSER_MEMORY_LIMIT=-1**を付けてあげることで、
一時的に（当該コマンド実行に限り）メモリが無制限になります。


```shell
COMPOSER_MEMORY_LIMIT=-1 composer require  {パッケージ名等}
```




以上。
ファイル名に日付を付与してコピーを右クリックで行う方法

仕事でファイル名に日付を付与してバックアップを取ることが多かったので、右クリックで簡単にコピーできるようにしました。

#batファイルを作成する
ファイルに対して日付（<ファイル名>\_yyyyMMdd or yyyyMMdd\_<ファイル名>）を付与してコピーするバッチファイルを作成する。

####■実現イメージ
ファイル名「〇〇プロジェクト_WBS.xlsx」の場合
⇒20210813_〇〇プロジェクト_WBS.xlsx　or　〇〇プロジェクト_WBS_yyyyMMdd.xlsx　を作成する

####■ソース

```php:FileCopyAddDateAfter.bat
@echo off

rem フォルダ名の後ろに日付を付ける
rem 必要な部分の切り出し
rem 「日付」について
set YYYY=%date:~0,4%
set MM=%date:~5,2%
set DD=%date:~8,2%
 
rem 切り出した文字列を結合
set footer=%YYYY%%MM%%DD%

rem ヘッダーとフォルダ名の結合とコピー
copy %1 %~n1_%footer%%~x1
```

```php:FileCopyAddDateBefore.bat
@echo off

rem フォルダ名の後ろに日付を付ける
rem 必要な部分の切り出し
rem 「日付」について
set YYYY=%date:~0,4%
set MM=%date:~5,2%
set DD=%date:~8,2%
 
rem 切り出した文字列を結合
set footer=%YYYY%%MM%%DD%

rem ヘッダーとフォルダ名の結合とコピー
copy %1 %footer%_%~n1%~x1

```
#右クリック（送る）に設定する

エクスプローラーで「shell:sendto」を検索⇒表示されたフォルダに作成したbatファイルをコピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628999/e9690734-ca99-8311-d061-07149f4eb2fc.png)

あとは、日付を付与したいファイルに対して[右クリック] - [送る] - [FileCopyAddDateAfter.bat] or [FileCopyAddDateBefore.bat]を選択すれば、出来上がり！ 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628999/fcedb9a5-9446-6bc6-89ae-ffbbe426b362.png)
ESETインターネットセキュリティがインストールされたWindows PCにおいて、キーボード入力に不具合が発生する

私が使用しているPCのWindows 10は現在21H1です。
しばらく放置していたので、20H2の時からすでに発生したいのかもしれませんが、キーボード入力途中で1つ前のキーが入力されるような奇妙な不具合が発生していました。

![キーボー入力不具合のサンプル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667945/6d27ff37-eec2-4a01-7f5d-68d35b0d8cf3.png)

この不具合は、全部のアプリケーションではなく、Chromium Edgeのようなブラウザーのみです。


# 現象
どうやら、セキュアブラウザーのキーボード保護が有効だと怒る不具合のようです。
![ESET インターネットセキュリティ セキュアブラウザー キーボード保護がオフ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667945/8ae53ddf-3056-d939-999d-7cb6121567e6.png)

https://eset-support.canon-its.jp/faq/show/14372

少なくとも、ESET インターネットセキュリティ アップデート 14.0.22.0では発生していました。
![ESET インターネットセキュリティ アップデート 14.0.22.0](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667945/5cd2b563-20bd-ff84-f4f1-4ae2a0086260.png)

# 結論
標準のアップデートでは適用されない更新を適用することにより、不具合が軽減されるかもしれません。
私の環境では、14.2.19.0になりましたが、不具合が解消されたように見えます。

https://eset-info.canon-its.jp/support/versionup/eis.html

ただし、下記変更履歴には記載がないため、完全な修復に至っていない可能性もあります。

https://eset-support.canon-its.jp/faq/show/2273?#EIS

また、仕様変更によりお使いの環境では意図しない動作をすることもあるかもしれませんので、変更履歴の確認をされてから適用されることをおすすめします。
render先に設定したページにインスタンス変数を渡し忘れていたこと

# render先に設定したページにインスタンス変数を渡し忘れていた
このrenderの遷移先に設定した"prototypes/show"のページにはインスタンス変数が記述してあるため、このままではインスタンス変数が空なのでエラーが出てしまいました。

```ruby
def create
    @comment = Comment.new(comment_params)
    if @comment.save
      redirect_to prototype_path(@comment.prototype_id)
    else
      render "prototypes/show"  
    end
  end
```
そこでrenderでページを表示すると同時にインスタンス変数を渡す処理を記述することで無事にページを表示することができるようになりました。

```ruby
def create
    @comment = Comment.new(comment_params)
    if @comment.save
      redirect_to prototype_path(@comment.prototype_id)
    else
      @prototype = @comment.prototype
      @comments = @prototype.comments
      render "prototypes/show"  
    end
  end

```

かなり初歩的なことだとは思いますが、学習時に結構詰まってしまったところだったので書かせていただきました。ページ遷移させる記述の際は、ページ先の変数の確認と、ちゃんと変数の中身を渡すことができるのかを確かめるべきだと感じました。
HacobuneにNuxt.jsでビルドした成果物をデプロイしたいのでマルチステージビルドしてみる

こちらの続き
https://qiita.com/Yoshihiro-Hirose/items/7a3107fa3b0bd39603fe

# 概要
- Hacobune はコンテナをデプロイできる
- Nuxt.js のようなフロントエンドフレームワークでビルドしたものをデプロイしたい
    - Next.js など別のものでも応用できるはず
- Dockerfile 内でアプリケーションをビルドすれば実現できそう

# 対応手順
- 適当な Nuxt.js のプロジェクトを用意
- 以下 Dockerfile を用意する

```Dockerfile:Dockerfile
FROM node:12
WORKDIR /app
COPY . .
RUN yarn install
RUN yarn generate

FROM nginx
COPY --from=0 /app/dist /usr/share/nginx/html
```

- 以下 .dockerignore を用意する

```:.dockerignore
node_modules
.nuxt
```

- Hacobune でリポジトリを指定
    - デプロイしたサンプル： https://hirosenuxt.c1.hacobuneapp.com/
    - ソールコード: https://github.com/Yoshihiro-Hirose/hacobune-nuxt
        - マルチステージ対応差分: https://github.com/Yoshihiro-Hirose/hacobune-nuxt/commit/2dfe67bd871f8011dc6c735df4a2634a1a00c3c3

# やっていること
- Dockerfile 前半でアプリケーションをビルド
    - node:12 を指定
    - ファイルをコンテナにコピーする。その際、node_modules などは除外する(.dockerignore)
    - 一般的な手順でアプリケーションをビルド
- Dockerfile 後半で成果物を Web アプリケーションにまとめる
    - 前半でビルドしたものは dist ディレクトリに出力される
    - COPY でビルドしたコンテナからファイルをコピーしている

# 参考
- https://qiita.com/tmiyajima/items/b099fb707bfde9337a70
- https://docs.docker.jp/engine/userguide/eng-image/multistage-build.html
コーダーがコーディングするとき聞くと素晴らしく効率が上がる　Lo -fi  ヒップホップとは、、

広帯域では無い、、、しかもノイズっぽい、、　　　この音楽がドーパミンを発生させ、コーディング能力を覚醒させる

部屋の照明を暗くしてダークモードの画面に君の能力を発揮しよう、、、

https://youtu.be/5yx6BWlEVcY
OkHttpのInterceptorでAPIダミー応答を返して、アプリ開発効率化

アプリ開発はそのアプリで閉じるということは希で、通常バックエンドとしてのサーバーサイドの開発も必要です。開発初期段階ではテスト的にたたけるAPIが無かったりで、アプリの開発を始めにくい場合もあります。
OkHttpにはInterceptorというリクエストをフックする仕組みがあるため、ここで細工をすることで、特定のURLなどへのアクセスを止めて、代わりに埋め込みのダミー応答を返すようにすることができます。
OkHttpClientのインスタンスはプールされていると思うので、ここで細工をしておけば、他の処理は本番かダミー応答かを気にせず、実装を行うことができます。Retrofitを使う場合も、OkHttpClientのインスタンスを渡すだけでOKですね。

よくある使い方でもあると思うので、ほとんど自分用メモになってしまうかもしれませんが、説明します。

# Interceptor

OkHttpではNetworkInterceptorとInterceptorの2種類があって、これの違いがたまに話題になります。NetworkInterceptorはCacheの後の本当のネットワークへのリクエストの処理を行う場合に使用します。今回は、アプリケーションからのリクエストを差し替えるので、Interceptorを利用します。

## Interceptorの実装

Interceptorを実装します。
どのようなリクエストを何に置き換えるのか、URLを受け取ってそれを元に変換するラムダを複数登録削除できるようにしています。クエリに応じて動的にレスポンスを作ることもできますね。全部のラムダがnullを返す場合は本来のネットワークアクセスをします。
この辺の仕組みは各アプリの事情に応じて変更すれば良いと思います。

ポイントは、`chain.request()`で、リクエスト情報を読み出し、差し替えるべき応答があれば、その応答のResponseを返す。
無い場合は、そのまま本来のリクエストを実行するため、`chain.proceed(request)`で、後段の処理を実行します。

```kotlin:MockResponseInterceptor.kt
class MockResponseInterceptor : Interceptor {
    private val supplierMap = mutableMapOf<String, (URL) -> MockResponse?>()

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val url = request.url.toUrl()
        val data = supplierMap.values
            .asSequence()
            .mapNotNull { it.invoke(url) }
            .firstOrNull()
        return data?.let {
            Response.Builder()
                .request(request)
                .code(it.code)
                .message(it.message)
                .protocol(Protocol.HTTP_2)
                .body(it.body.toResponseBody("application/json".toMediaType()))
                .build()
        } ?: chain.proceed(request)
    }

    fun addSupplier(key: String, supplier: (URL) -> MockResponse?) {
        supplierMap[key] = supplier
    }

    fun removeSupplier(key: String) {
        supplierMap.remove(key)
    }

    data class MockResponse(
        val body: String,
        val code: Int = 200,
        val message: String = "OK"
    )
}
```

## 利用

利用箇所はかなりやっつけですが、OkHttpClientを作るところでInterceptorを渡しておいて、そのclinetを使うだけです。Retrofitなど、OkHttpのHttpClientを受け付けるライブラリならこのインスタンスを渡すだけです。

```kotlin
val interceptor = MockResponseInterceptor()
interceptor.addSupplier("hoge") {
    if (it.path.endsWith("hoge")) MockResponse("{}") else null
}
val client = OkHttpClient.Builder()
    .addInterceptor(interceptor)
    .build()
val request = Request.Builder()
    .get()
    .url("http://example.com/hoge")
    .build()
GlobalScope.launch(Dispatchers.IO) {
    client.newCall(request).execute().body?.string()
        ?.let {
            Log.e("XXXX", it)
        }
}
```

OkHttpClientはインスタンスを使い回すために、インスタンスプールを用意している場合が多いでしょうし、APIを叩いている場所ではなく、OkHttpCleintのインスタンス管理部分に細工をするだけで実現できるため、API利用箇所に変更を加えることなく、デバッグ時のみダミー応答を利用するとか、デバッグメニューによって応答を変えるなども比較的簡単に実現できると思います。

----

まだAPIが実装できていないとか、通常は発生しないような特定の応答を返した場合の動作確認をしたい、みたいな時に便利に使えると思います。

以上です。
【Google Analytics】 学習まとめ

Google アナリティクス の学習用メモです。
以前に出張中に少々時間があり、「オンライン試験で受講できる」点に惹かれて軽い気持ちで受講した内容です。
[Google アナリティクス](https://analytics.google.com/analytics/academy/)


# アナリティクスとは
AdjustのトラッカーURLにより自動的に蓄積されるデータを分析、収集、表示するための機能全体のこと
データを容易に扱うことができ、さまざまな用途に利用してパフォーマンスを向上させることができる

# 顧客がモノを購入するまで
Web閲覧~~クリックしてネット注文する際にも、以下の3工程に部類されることがわかる

1. 「集客数」：ユーザがどのサイトからアクセスしたのかを把握する指標のこと
2. 「行動」：ユーザ がビジネスを利用する(様々なサイトにアクセスする)指標数のこと
3. 「コンバージョン」：ユーザが購入をする(購入ボタンを押す)指標のこと

* ウェブサイト以外

>
* オンラインPOSシステム
* 顧客管理システム
* ゲーム機

などからも収集することが可能

## 集客数をデータ化する方法
各サイトのTopに__JSのトラッキングコード__を追加することで使用可能
ウェブサイトの <head> 開始タグの直後

* 直帰率
なにもしないでサイトから離れた行為のこと
クリックせずブラウザバックした行為

* トラッキング

現在使用している
> 
* 設定言語
* OS
* ブラウザ(safari,chrome…)

様々確認することができる

* サイトリーチ、定着度
ユーザ の特定の項目でのセッション数のこと

* セッション
30minごとにアクセスがないと切断される
更新ごとに情報を収集する機能
これがgoogleアナリティクスに送信されレポート化される

* DB
存在する
この中にデータが保存され、変更することができない使用

* Organazation
グループ
複数のアカウントをグループとしてまとめられる

* Account
アカウント内に __プロパティ__
__プロパティ__内に__View__

>
- アカウント
- Organazation 
    - プロパティ
        - View

* プロパティ、View
いくつでもアカウント内に作成ができる
プロパティがアクセス端末などを分けれて、Viewがフィルターをかけれる(地域別などで分ける)→徐々にネストされているイメージ

* フィルター
自分のIPアドレスを除外することでアクセス数を把握する
Exclude > IP >equal VIEW
__Setting__ 部分から設定をする

* View
括りみたいなもの
国ごとなどで分けるイメージ
その国ごとに分けてフィルターで範囲を指定して見やすくなる
※注意点、作成したその日からデータが保存される

* 権限
それぞれ3つごとに権限の使用を分けることができる
上位に依存
アカウント権限許可であればすべて可能だが
View権限許可のアカウントはプロパティやアカウントの変更設定ができない



### メディアには様々な集客方法がある
* オーガニック
ぐぐるなどの無料検索でひっかかったもの

* CPC
有料広告などのトラフィック

* 参照
検索エンジンなどからクリックしてきたもの

* メール
メールマーケティングなど

* キャンペーンには必須3、「メディア、参照元、キャンペーン」
・この2つは付け加えればできるキャンペーン、「キーワード、タグ」

* ヘルプセンターのURL生成
スペースはあんだーバーに変換される _

* 大文字と小文字は全く別のもので使用される

### 目標
>
* ビジネス目標：ユーザに行ってもらいたいアクションのこと
* コンバージョン：目標達成の行動に関する用語のこと

* マクロコンバージョン
重要なイベント「購入ボタン」などを選択した場合の達成
* マイクロコンバージョン　
マクロより大きくは無いが「目標達成に近づくための達成」のこと
eコマースサイト(購入サイト)と問い合わせサイトだと「マクロ、マイクロ」の達成項目が違う
→サイトごとによって達成項目が異なる

 
###目標の種類はさらに部類分けされる
> * 「到達」閲覧されたか
* 「イベント」特定の行動がされたか
* 「滞在」ある一定時間そのサイト内にいたか
* 「特定のページ数が閲覧されたか」

など...

目標設定はView の管理者でないと設定ができない
コンバージョンするまでの過程も確認することができる
目標できる件数はViewごとに20件

> 
例）google ショッピングのトラッキング目標→商品購入の完了
>>
商品ページに到達するのか購入するのかで目標設定が異なる



* クロスドメイントラッキング
複数のドメインをまたぐトラッキングをする場合に設定する

* ヒット
ヒットとはURL文字列のこと
ユーザが操作を行うたびにアナリティクスにヒットというものが送信される


* ヒットの種類
ページビューヒット　ユーザが画面を読み込むごとに送信される

* イベントヒット
動画再生ボタンやクリックなどがカウントされる
→イベントヒットのURL　アクション、カテゴリ、ラベル、値のパラメータを渡す
→これによりレポートを確認することができる

* トランザクションヒット　

* 新規ユーザかリピーターユーザか
ユーザがまずアクセスしたら「ランダムなID」をユーザのブラウザのcookieに関連づける
既存のIDであればリピーターと判断される
ユーザ側がcookieを削除した場合は新たに「新規」として扱われる
別デバイスからは関連付けされず新たに「新規」としてカウントされる

* measument protocol
これを利用するとPOSシステムやインターネットキオスクなどあらゆるデバイスから
アナティクスにデータを送信できる

* ディメンション
アナリティクスが反映される流れは、各集客ディメンションテーブルに
保存がされる、ディメンションとは行(上側にある項目のこと)、指標は列のこと

JSにトラッキングに設定することにより
アクセス者が関係者なのか新規なのかなどの区別ができる
 


--- 

試験内容は受講時に受けたテストと全く一緒だったので
内容を理解すれば誰でも受かります。

割とアナリティクス全般の知識に役立つと感じたので、
今後データ分析などする際は役立てたい内容でした。
GitHub、パスワード認証やめるって？

##GitHubの二段階認証、個人アクセストークン設定後のお話

この記事は、二段階認証、個人アクセストークン設定のHow toではなく、

2021年8月13日になる直前に二段階認証、個人アクセストークンを設定したという報告です。

と言うのも以前、GitHubさんから**パスワード認証を廃止する**という趣旨のメールが届いた。

調べてみると、運命の日は**8月13日**

後ろ髪を引かれつつも放置。

しかし直前で怖くなり、8月12日23時、意を決して、駆け込んだ。

(過ぎても後から設定すればいい話だが)

##二段階認証、個人アクセストークンを設定。

[GitHubでパスワード認証が廃止されるので二要素認証とトークン認証の設定方法をまとめた][参照1]
[GitHubがパスワード認証を廃止するらしいので][参照2]

これらを参照にさせてもらい、サクサク設定完了。

設定終わったところで、達成感を抱き就寝。

朝起きて、自分のポートフォリオを少し変更して、いざ、`git push`


```git:local
$ git push
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/username/repositoryの名前/'
```

うん、エラー。

あれ？個人アクセストークンきいてくれないの？

あ、そういえば、と思い
 
Githubを一旦、sign outした。

sign inの際、しっかり二段階認証になっていたので、認証アプリに表示される**6桁の数字**を入力。

 sign inできた。

次に、`git push` を再度実行。

**username , password**を求められた。

本当に設定されているかチェックするがてら、

Passwordには、今まで通り、Githubのpasswordを入力してみた


```git:local
Username for 'https://github.com': usernameを入力
Password for 'https://username@github.com': Githubのpasswordを入力
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/username/repositoryの名前/'
```
ちゃんと、エラー。

そこで、昨晩、決死の思いで控えた個人アクセストークンをペースト。

```git:local
$ git push
Username for 'https://github.com': usernameを入力
Password for 'https://username@github.com': 個人アクセストークンをペースト
Enumerating objects: 22, done.
Counting objects: 100% (22/22), done.
```

成功。

##まとめ
一瞬、焦ったけど、教えてくれる人がいて、本当に助かった。
これからの、仕様変更は落ち着いて早めに対応していきたい。

###参照

[GitHubでパスワード認証が廃止されるので二要素認証とトークン認証の設定方法をまとめた][参照1]
[参照1]:https://predora005.hatenablog.com/entry/2021/02/04/190000

[GitHubがパスワード認証を廃止するらしいので][参照2]
[参照2]:https://qiita.com/shiro01/items/e886aa1e4beb404f9038
Base64でエンコードされたバイナリデータをデコードしてバイナリデータとして別サーバーに中継する方法


# 概要
node.jsを使ってWebsocketクライアントから流れてきた、Base64形式のバイナリデータをバイナリ形式に直して別のサーバーに中継する実装をやった時のメモ

# 構成
クライアント　→ 中継サーバー（今回の実装）　→ 解析サーバー

# 実装
```node.js
var WebSocketServer = require('websocket').server;
var WebSocketClient = require('websocket').client;
var http = require('http');

var clientConnection;
var wsserver = http.createServer(handleRequest);

var server = new WebSocketServer({
  httpServer: wsserver,
  autoAcceptConnections: true,
});

client.connect('ws://localhost:8000','echo-protocol');
client.on('connect', function (connection) {
   clientConnection = connection;
});

server.on('connect', function(connection) {
  connection.on('message', function(data){
    const buff = Buffer.from(data.payload, 'base64');

　　　　　　　// データを加工する場合、以下実装を行う。加工が必要なかったら↑のbuffをそのまま中継する
    var outData = new Uint8Array(buff.length + 1);
    outData[0] = 0x70; // 追加する文字　※必要があれば
    for (var i = 0; i < buff.length; i++) {
      outData[1 + i] = buff[i];
    }

    if (clientConnection) {
      clientConnection.send(Buffer.from(outData));
    }
  })
});

wsserver.listen('8080', function(){
  console.log("Server listening on: http://localhost:%s", HTTP_SERVER_PORT);
});
```