OmniAICreator/Qiita-1.07M huggingface dataset:
【Nuxt.js #4】プロジェクトの設定手順-Firebaseアプリの作成と関連パッケージの導入-

#手順1
Firebaseにログインする。
https://console.firebase.google.com/

#手順2
アプリで使用するプロジェクトをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/747f3b0a-bae2-1388-748d-36c5f8ea9e9b.png)

#手順3
「+アプリを追加」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/6f1b0631-f108-91d8-9e76-6c78c5a3fb26.png)

#手順4
「プラットフォームを選択」より、「Web」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/922a1338-f2a1-8b1e-46bf-cfca290ccead.png)

#手順5
「アプリのニックネーム」に任意のアプリ名を入力する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/84029cf8-38fb-bc41-ed83-fcac374d265c.png)

#手順6
「このアプリのFirebase Hostingも設定します。」にチェックを入れる
→　ドロップダウンリストから、Hosting先のプロジェクトを選択する　
→　「アプリを登録」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/0f1776dc-30c8-a2a1-fbec-3bfb53c928d3.png)

#手順7
「次へ」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/065b97dd-c0b0-9335-bc8b-04f57583fca0.png)

#手順8
以下のコマンドをコピーし、Visual Studio Codeのターミナルで実行する。
→　インストールが完了したら、「次へ」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/f2f1fc8d-fa69-fb14-cbda-3bbb6029a646.png)

#手順9
「コンソールに進む」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/e2d77acf-de38-3304-83d2-0b945908e7a6.png)

#手順10
画面左上の歯車ボタンをクリックする
→　「プロジェクトを設定」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/b34bad2d-974b-0b7e-0492-9e1995c59916.png)

#手順11
画面下の「SDKの設定と構成」より「CDN」にチェックを入れる。
→　下に表示される赤枠の個所の情報をコピーし、控えておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/25f8ac31-751b-f649-1016-c6b4c0657234.png)

#手順12
Visual Studio Codeのターミナルで以下のコマンドを実行する。

```
npm install --save firebase
```
#手順13
Visual Studio Codeのプロジェクト直下にplugins/firebase.jsを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1866473/659a773e-ad3a-7d26-5b86-02ea7928dda7.png)

#手順14
firebase.jsに以下を記載して保存する。
※XXXXXXXXX部分は、手順11でコピーした情報を張り付ける。

```plugins/firebase.js
import firebase from "firebase/app"

if (!firebase.apps.length) {
firebase.initializeApp({
  apiKey: "XXXXXXXXX",
  authDomain: "XXXXXXXXX",
  databaseURL: "XXXXXXXXX",
  projectId: "XXXXXXXXX",
  storageBucket: "XXXXXXXXX",
  messagingSenderId: "XXXXXXXXX",
  appId: "XXXXXXXXX",
  measurementId: "XXXXXXXXX"
})
}

export default firebase
```

以上
React】苦手だった条件分岐（boolean）を少し克服した方法

こんにちは。ひろっきーです。

現在ITエンジニア転職を目指して現在、独学９ヶ月目で日々学習、現在はNext.js、TypeScript などを学習しており、ポートフォリオとしてSNSアプリケーションを作成しています。
今回は最近やっと使えるようになってきた、条件分岐について忘備録を兼ねて書いて行きたいと思います。

# この記事を書こうと思ったきっかけ
私がプログラミングを学び出したのは、2０２０年の１１月で
１２月ぐらいにはJavascriptを学び初めていました。
その時はドットインストールを学習してましたが、私は各演算や値を学ぶ中で一番booleanが苦手でした。。。とにかく応用出来ない、、、

ドットインストールの先生が
> こういうときはbooleanですね

と言い正解のコードを書く度私の頭にはいつも「？」マークが浮かんでました。

# そもそも演算子とは？
最近気付いたことは
`１　＋　１　＝　２`
この式が成り立つ場合、この式は`true`になります。
この理論が成り立つか成り立たないかの値がbooleanです。

アプリケーション開発をするにあたってどこかの場面でbooleanは使われます。

# 条件分岐を覚えるきっかけ
苦手意識が拭えないまま、自身が参加しているコミュニティでライブコーディングという出来るエンジニアさんが、みんなの前で今作ってるもののコーディングを見れるというイベントがありました。

そこで、繰り出されるスマートな三項演算子で書かれた要素の出し分けを見て
**「カッコいい！」**
と思ったのが最初のキッカケでした（理由が浅はかｗ）

# 実際によく使う条件分岐やbooleanの自分なりの覚え方。
## 前提条件
私がアプリ開発を始めたときはReactから始めたので、Reactの書き方で解説していきます。
覚えやすいように読み方と、覚え方を同時に解説していきます。
例文として、関西の人はみんな知っている　５５１の蓬莱のCMに例えて説明していきます。（知らない方はググってみて下さいｗｗ）
## &&　論理演算子(論理 AND)
使用ケース

```js
 const Hourai = () => {
   let isHourai = true; //蓬莱がある (初期値）
   return (
    {isHourai && <div>嬉しい</div>}
    // 蓬莱がある時は嬉しい　
  ) 
 }
 // 返り値　：　蓬莱はtrue（ある）ので嬉しい

 ```

訳：　（is）蓬莱がある時は嬉しい
構文：　左辺がtrueなら右辺を返す
　読み方は「アンパサンド」と読みます。
＆＆といえば　〇〇かつという感じで覚えてる方も多いと思いますが、この様に覚えたほうが覚えやすいかと思います。

## 三項演算子
使用ケース

```js
 const Hourai = () => {
   let isHourai = true;　　//蓬莱がある　(初期値）
   return (
    {isHourai ? <div>嬉しい</div> : <div>悲しい</div>}
    // 蓬莱がある時は嬉しい　:ないときは悲しい
  ) 
 }
 
 // 返り値　：　蓬莱はtrue（ある）ので嬉しい

 ```

訳: （is)蓬莱がある時は嬉しい。そうじゃなかったら悲しい。
構文: 左辺がtrueのときは右辺を返して、falseの場合は　：　以降のコードを返す。
代表的な三項演算子の使い方です。
ボタンをクリックしたときに要素を出したり消したりするときなどに使われます。
※　?の後　改行や定数を使う場合は（）で囲む必要があります。＆＆も同じです

## if文,if else文

```js
const hourai = false;
if(hourai){　
 return <div>嬉しい</div>　 //もし蓬莱があれば嬉しい
}　else {
  return <div>悲しい</div>　//そうでなければ悲しい
}
 // 返り値　：　蓬莱はfalse（ない）ので悲しい
 ```
 訳: 蓬莱がある時は嬉しい。そうじゃなかったら悲しい。
 構文: 代表的なif else文です。　返り値がtrueならif文内を、falseならelse内を返す
 
代表的な書き方で基礎を学習している方も学んだことがあるかもしれません。
if文はほかの書き方も出来ます。

```js
const hourai = false;
if(hourai){　
 return <div>嬉しい</div>　 //もし蓬莱があれば嬉しい
}　
if(!hourai){
  return <div>悲しい</div>　//そうでなければ悲しい
}
 // 返り値　：　蓬莱はfalse（ない）ので悲しい
 ```
 訳：　同上
 構文:　今回はif　elseではなく、！マークを使い条件分岐しています。
 ！　は値の前に付けることで、反対の値を返します。
 （子供のときに一度は言ったことのある「お父さん、嫌いの反対」　みたいな表現です）
 
 私がよく使うのはこの３パターンかなと思います。
 
 # まとめ
 こんな感じで、コードを日本語訳出来るとこういった構文が理解しやすくなるかと思いました。
 皆さんもぜひ使ってカッコいい条件分岐を書いてboolean masterになりましょう。
支給データに#231815が入ってたらちょっと身構えた方が良い……かも？

## これは何

- CMYKとRGBを機械的に変換すると大変なことになるかもしれません
- データの不備に気づけるかもしれないTipsを書いた記事です

## `#000000`だと思ったら`#231815`だったら

クライアントからデータをもらってサイトに載せてリリース……みたいなフローはよくあると思います。
そしてロゴなどのデータにおいて、純粋な黒（=`#000000`）に見える黒が使われている可能性は割と高いのではないでしょうか。

もらったデータの形式がSVGまたはPNG[^1]で、`#000000`だと思った箇所が実は`#231815`だった場合、本来CMYKのデータなのに書き出し設定だけをRGBにしているデータな可能性があります。

試しにロゴっぽい画像を作ってみましょう。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/670bdfcb-5df6-d231-fed5-fbef3f745a2f.png)

文字を打つだけ打ちました。
真っ黒のデータを作成したので、CMYKとして確認するとK=100になっています。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/f4d419b1-eb0a-be78-435e-d91a621cb4be.png)

これを単にRGBでの色選択に変えると、こうなってしまいます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/49f5d24b-e92b-6c02-ac84-29a6d402841c.png)

`rgb(35, 24, 21)`でHexで言うと`#231815`。
計算式としては正しいのでしょうが、若干赤みがかかってしまうなど、人間が意図した変換ではないような気がしますね。
少なくとも昔の私は`K=100` = `#000000`だと思っていました。

## 具体的にどう問題になるのか

正直な話、パッと見て`#000000`と`#231815`の違いに気づける人はほとんどいないと思います。
そのためもしRGB用に作られたデータではなくCMYKを機械的にRGBに変換したデータを使ってサイトを公開しても、そう大問題になる可能性は低いはずです。

……しかし、本当は違う色なのにそのまま世に出してしまうの、なんだか嫌じゃないですか？
とくに他社様のデータを扱うときは私は敏感になります。

もし気付くことができて「本来の色と少し違うみたいですが、これこれこういうデータはありますか？」と聞くだけで解決するならその方がお互い嬉しいと思うため、あえてこういう記事を書いてみました。

[^1]: JPGは不可逆圧縮な都合上ノイズが乗ってしまうので、スポイトしても正しい色を得られない可能性が高いです。「モスキートノイズ」でググると良い感じの事例が色々出てくると思います。
初心者エンジニアがVSCodeでVimを導入してみた


## Vim導入のモチベーション
初心者ながら、Vimを始めることにしました。
主なモチベーションは、

<ul>
<li>VSCodeのショートカットに物足りなさを感じてきた</li>
<li>効率的な開発体験をしてみたいと思った</li>
<li>やるなら早めにやっておいた方が良いと思った</li>
<li>SSH接続時等、今後実務で使えるかもしれないと思った</li>
<li>Vimにはロマンがあると感じた</li>
<li>女の子にモテそうだから</li>
</ul>

こんな感じです。


## 導入自体はとても簡単だった
VSCode上でもVim同様のキー操作ができる拡張プラグインがあったので、まずはこれに慣れていきたいと思います。
VSCodeのマーケットプレイスから「vim」で検索すると一番上に出てきます。
https://marketplace.visualstudio.com/items?itemName=vscodevim.vim

動作が重くなることもなく、至極快適に動いてくれます。

## Vimtutorをやっておく
これです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1672759/d8e5582d-cceb-c41a-68ff-79e60af1b254.png)
Vimをインストールすると、一緒にVimtutorもインストールされます。ちゃんとした日本語、ハンズオン形式でVimの所作を体験できる貴重なチュートリアルなので、VIm初心者の必履修科目ですね。

vimのインストールは窓の杜さんから行いました
https://forest.watch.impress.co.jp/library/software/vim/

これをインストールした後は、windows左下の検索バーから「vimtutor」で検索すれば出てきます。


## Vimを恐れる必要はなく、少しづつ懐柔していけばいい
Vimには途方もない数のショートカットが存在し、それらを使いこなして効率的に入力を行っていくのがVimの真骨頂。これを覚えないとVimでの開発は難しい。。と思っていましたが、これは誤解でした。

カーソル移動に癖があるものの、導入自体はかんたんで2～3時間触った程度ですでに導入前と変わらずスムーズに開発が出来ています（逆に言うと、まだVimの威力を体感できていない）

まずは癖のある基本動作に慣れていきながら、少しづつショートカットを覚えたり、vimrcを作ってみたり、色々やりながらVimの恩恵にあずかれるようやっていきたいなと思いした。
JavaScript/PHP 月末付近でも月を繰り上げずに○か月増減した日付を取得

例えばJavaScriptで8月31日の1か月後を取得しようとして

```js:
const date = new Date('2021/08/31');
date.setMonth(date.getMonth() + 1);
```

としても、9月は30日までしかないので月が繰り上がり、実際に得られる日付は10月1日になってしまいますが、そのような日数の異なる月を目標月とした場合でも末日で丸めた9月30日として取得できるようにした関数です。

JavaScript/PHP版ともに、目標月+1月の0日を指定することで一旦目標月の末日にし、得られた末日と元の日付の「日」のうち小さいほうで「日」を再設定することで求めたい日付を取得しています。

####JavaScript版####

```js:
function addMonth(date, num) {
  const d = new Date(date);
  d.setMonth(d.getMonth() + num + 1, 0);
  d.setDate(Math.min(d.getDate(), date.getDate()));
  return d;
}

// sample
const baseDate = new Date('2021/08/31');
console.log('base date :', baseDate.toLocaleDateString('ja'), "\n");

for(let i = -12; i <= 12; i++) {
  const r = addMonth(baseDate, i);
  console.log('%s month : %s',
    `${(i < 0 ? i : `+${i}`)}`.padStart(3), r.toLocaleDateString('ja'));
}

/*
  base date : 2021/8/31

  -12 month : 2020/8/31
  -11 month : 2020/9/30
  -10 month : 2020/10/31
   -9 month : 2020/11/30
   -8 month : 2020/12/31
   -7 month : 2021/1/31
   -6 month : 2021/2/28
   -5 month : 2021/3/31
   -4 month : 2021/4/30
   -3 month : 2021/5/31
   -2 month : 2021/6/30
   -1 month : 2021/7/31
   +0 month : 2021/8/31
   +1 month : 2021/9/30
   +2 month : 2021/10/31
   +3 month : 2021/11/30
   +4 month : 2021/12/31
   +5 month : 2022/1/31
   +6 month : 2022/2/28
   +7 month : 2022/3/31
   +8 month : 2022/4/30
   +9 month : 2022/5/31
  +10 month : 2022/6/30
  +11 month : 2022/7/31
  +12 month : 2022/8/31
*/
```

####PHP版####

```php:
<?php
function addMonth($date, $num) {
  $d = (new DateTime)->setTimestamp($date->getTimestamp());
  $d->setDate($d->format('Y'), $d->format('m') + $num + 1, 0)
    ->setDate($d->format('Y'), $d->format('m'), min($d->format('d'), $date->format('d')));
  return (new DateTimeImmutable)->setTimestamp($d->getTimestamp());
}

// sample
$baseDate = (new DateTimeImmutable)->setDate(2021, 8, 31);
echo "base date : {$baseDate->format('Y-m-d')}\n\n";

for($i = -12; $i <= 12; $i++) {
  $r = addMonth($baseDate, $i);
  printf("%+3d month : %s\n", $i, $r->format('Y-m-d'));
}

// result
/*
  base date : 2021-08-31

  -12 month : 2020-08-31
  -11 month : 2020-09-30
  -10 month : 2020-10-31
   -9 month : 2020-11-30
   -8 month : 2020-12-31
   -7 month : 2021-01-31
   -6 month : 2021-02-28
   -5 month : 2021-03-31
   -4 month : 2021-04-30
   -3 month : 2021-05-31
   -2 month : 2021-06-30
   -1 month : 2021-07-31
   +0 month : 2021-08-31
   +1 month : 2021-09-30
   +2 month : 2021-10-31
   +3 month : 2021-11-30
   +4 month : 2021-12-31
   +5 month : 2022-01-31
   +6 month : 2022-02-28
   +7 month : 2022-03-31
   +8 month : 2022-04-30
   +9 month : 2022-05-31
  +10 month : 2022-06-30
  +11 month : 2022-07-31
  +12 month : 2022-08-31
*/
```

**引き数**
addMonth(日付オブジェクト, 月の増減値)

**戻り値**
指定した値で月を増減された日付オブジェクト

引き数チェックは入れていませんので必要に応じて追加してください。

----
hashicorp/logutilsを使ってログレベル指定のないログを非表示にするtips

Go言語のロガー実装の1つに[hashicorp/logutils](https://github.com/hashicorp/logutils)というシンプルなライブラリがあります。Goの標準パッケージ `log` を拡張するようなもので、覚えることも少ないですし、他のライブラリと組み合わせやすい点もメリットです。

利用例は次のようになります。

```go
package main

import (
	"log"
	"os"

	"github.com/hashicorp/logutils"
)

func main() {
	filter := &logutils.LevelFilter{
		Levels: []logutils.LogLevel{"DEBUG", "WARN", "ERROR"},
		MinLevel: logutils.LogLevel("WARN"),
		Writer: os.Stderr,
	}
	log.SetOutput(filter)

	log.Print("[DEBUG] Debugging") // 表示されない
	log.Print("[WARN] Warning") // 表示される
	log.Print("[ERROR] Erring") // 表示される
	log.Print("Message I haven't updated") // 表示される
}
```

このように、ログ文字列先頭の`[WARN]`などでログレベルを指定する仕様です。ログレベルは`MinLevel`で指定して、指定されたレベルより上位レベルのログを表示する、という挙動になっています。

## ログレベル指定のないログを非表示にするには

ところで、上の例だとMinLevelを最上位レベル（上の例なら`"ERROR"`）にしてもログレベル指定のないログ（上の例なら4つめの`Print("Message I haven't updated")`）は表示されてしまいます。これを抑制する方法はないのでしょうか。

実は、ログレベルの指定がないログはログレベル`""`として扱われます[^1]。ですから、`Levels`で`""`の優先順位を指定すれば簡単に抑制できます。

[^1]: ソースコードを読んだらそうなっていたというだけで、仕様かどうかは疑問です。

たとえば次のようにすればログレベル指定がないログは表示されません。

```go
package main

import (
	"log"
	"os"

	"github.com/hashicorp/logutils"
)

func main() {
	filter := &logutils.LevelFilter{
		Levels: []logutils.LogLevel{"", "DEBUG", "WARN", "ERROR"},
		MinLevel: logutils.LogLevel("WARN"),
		Writer: os.Stderr,
	}
	log.SetOutput(filter)

	log.Print("[DEBUG] Debugging") // 表示されない
	log.Print("[WARN] Warning") // 表示される
	log.Print("[ERROR] Erring") // 表示される
	log.Print("Message I haven't updated") // 表示されない
}
```

これは標準パッケージ`log`で作り始めてしまってログレベル指定がないログが大量にあるような場合に便利でしょう。

## 未知のログレベルが指定された場合にこれを抑制する方法はない

ちなみに、`Levels`に含まれないログレベルが指定された場合、そのログは必ず出力されます。上の例なら`log.Print("[INFO] info")`は`MinLevel`の指定が何だろうと必ず表示されます。これは状況によっては不便かもしれません。

## 参考記事

- [ええっ！？　文字列で書くの！？　ログレベル付きロガーhashicorp/logutilsのご紹介 \- Qiita](https://qiita.com/mackee_w/items/3c0940733b6c0922554c)
Javascriptでローカルにある設定ファイル(json形式)を読み込む

#やりたいこと

ローカル上にあるJSON形式で書かれたファイルを読み込みJavascript上で扱えるようにする。

#HTML
 ```html:index.html
<input type="file" id="profile_form">
```

#JavaScript
```typescript:reader.ts
const profile_form = document.querySelector("#profile_form");
profile_form.addEventListener("change", (e) => {
  var profile = e.target.files[0];
  var data;
  var filename = profile.name;
  var type = profile.type;

  if (window.File && window.FileReader && window.FileList && window.Blob) {
    var reader = new FileReader();
    reader.readAsText(profile);
    reader.onload = (file) => {
      if (type == "application/json") {
        data = JSON.parse(file.target.result);
        console.log(data);
      } else {
      }
    };
  }
}, false);
```
reader.readAsText(profile)で指定されたファイルをテキスト形式で読み込む。
読み込まれたテキストはpromiseで帰ってくるのでreader.onloadで読み込み完了イベントをキャッチする。
JSON.parseで読み込んだテキストをJSON形式に直す。
dataにファイルの中身が格納される。
データサイエンスの始め方

# データサイエンスの始め方

# プロダクトのグロースにデータを活用したい．．．

サービスグロースにデータを活用したいと思ったとき、わたしはまず最初にどこに着目し、ナニから始めればいいのだろう？

よくわからなかったので調べ始めてみた。


# 小さなテーマからはじめよう

データサイエンスは、最初、できるだけコンパクトに小さく始めて、その成果をもとに大きく波及させるのが、うまくいきやすいポイントらしい。

小さなテーマを100個ぐらい仕込んで、大きく化けるテーマを探すらしい。

小さく始めると、失敗しても影響が小さく、軌道修正も容易で、何度でもチャレンジできるメリットがあるとのこと。


# ．．．で、ナニをやるんだろう

始め方はわかったけど、小さくナニを始めるのか？

## 活用目的と、活用ストーリーと、分析ストーリー

このデータ分析は何のためにやるのか、を明確にするのが、活用目的を決めることだが、
データサイエンスの世界では、目的を決めるだけでは不十分らしく、
その目的に対して、分析データの活用ストーリーを明確にする必要がある。

分析結果をただ提示しても利用してもらえない

「分析結果がAの場合、1の施策を、また結果がBの場合は、2の対策を実践する」、のような、
結果と活用方法の対応が分かる情報を、
「活用ストーリー」として分析結果とセットで提示すれば、
分析結果は上手に活用してもらえるらしい

また、分析結果と「活用ストーリー」を事前にしっかり設計することにより、
提供すべき分析結果の精度や、確実に活用してもらえるデータ提供が可能になると思われる

そしてさらに、一元的な分析結果ではなく、いくつかの中間データを経て分析結果を得る場合に、
その各ステップや全体の構造を説明したものを、「分析ストーリー」と呼ぶことができる

多層構造を要する分析においてはこの分析ストーリーを明確にすることが
保守の面においても「活用ストーリー」の設計においても大切になってくる


## 筋のいいテーマ

以上の3つの要素、

* 活用目的
* 活用ストーリー
* 分析ストーリー

が明確で、さらに

* 成果が大きい
* やりやすい

テーマは、"筋のいいテーマ"らしい

"筋のいいテーマ"を見つけることが、
確実かつスピーディーに成果を出せるテーマを選択できるコツ、と言ってよさそうだ

よって、必須3要素である、活用目的、活用ストーリー、分析ストーリーを
上手に設計するトレーニングを重ねることが
データ分析上達の鍵な気がする

# モデルの選び方

## チートシート

分析を設計する際に必要になる統計解析・機械学習モデルについて、  
世にはチートシートというサンプルモデルも出回っているらしい

* チートシート
    * [Azure Machine Learning デザイナーの機械学習アルゴリズム チート シート](https://docs.microsoft.com/ja-jp/azure/machine-learning/algorithm-cheat-sheet)
    * [Python For Data Science - A Cheat Sheet For Beginners](https://www.datacamp.com/community/tutorials/python-data-science-cheat-sheet-basics)

## モデルの種類と特徴

採りたいデータごとに分析方法を選択して利用する

* フィッシュボーンチャート 特性要因図
    * 目的変数と複数の説明変数からなる魚の骨状の図
    * わかりやすく、要素を組み立てやすくてかなり便利
* 線形判別モデル
* ロジスティック回帰モデル
* クラスター分析
* 主成分分析
    * 似たような傾向を持つデータ項目（変数）を集約する
* グラフィカルモデリング
    * データ項目間（変数間）の構造を描く


## 分析の実践に役立ついくつかの手法 メモ

小さく始める際に、ジョハリの窓における「開放の窓」を狙うことで、
現場の感覚とズレのない項目から着手する

選択肢の分岐点となる閾値を算出するために、決定木（ディシジョンツリー）を利用する

ニーズ（needs） より ウォンツ（wants）
変革（change） よりも 改善（improvement）
つまり、ウォンツ ✕ 改善 の象限から着手する

痛み よりも 楽になること
全体最適 よりも 個々の部署のメリット（メリットの平準化）
つまり、楽になる ✕ メリットの平準化 の象限、
できるだけ多くの関係者がメリットを感じられるテーマから着手する

「実験計画法」（少ない実験で効率的にデータを取得する方法論）で、
データ取得計画を作り、実験しデータを取得し、
取得データから「応答曲面法」で設計変数、品質特性の関係性を数式化し、
その数式を使い「数理計画法」により最適な「設計変数値」を算出する


# 改善・変革系データサイエンスと、データエコノミー系データサイエンス

日本で成果が出ているデータサイエンスはSQCのような改善・変革系データサイエンス

GAFA系が実現したデータエコノミー系データサイエンスへの発展を目指す場合、
各社がふつうのタスクとしてあたりまえに取り組むことと、
社内で始めて自社外への拡大を実践することで、市場向けのデータサイエンスは可能になる


# まとめ

データサイエンスに着手するための基本情報を以上の通りピックアップしてみた

大枠として以下を意識してまずは実績を作成してみるのがよさそうだ

* 小さなテーマを100個作成して、大きく成長するテーマを探す
* 活用目的、活用ストーリー、分析ストーリーの3要素で設計する
* 用途に応じて使えるツールと手法のテンプレートが多く存在する


# ネクストアクション

次はこれを読んで情報をまとめる予定

* [ビジネスデータサイエンスの教科書 ／ マット・タディ、上杉 隼人 (翻訳)、井上 毅郎 (翻訳)](https://www.amazon.co.jp/dp/4799109154/)

それともう一冊、

データサイエンスにおいて『[孫氏](https://www.amazon.co.jp/dp/4003320719/)』は必読の書、らしいが、

どういうことかよくわからないので、とりあえず読まなければならない


#  参考図書

本稿では以下の書籍を参考にさせていただきました

* [データサイエンスがわかる本 ／ 高橋 威知郎](https://www.amazon.co.jp/dp/4862807062/)
PowerShellでのIPアドレスをスクリプト化してみた

# 目的

PLCを始めとした、ネットワークに接続されていない機器にノートPCなどから接続するときは、
コントロールパネルからIPアドレスを変更する必要がある。

製造業などでは一日に何度も接続する必要があり、IPアドレスを毎回切り替えるのは面倒だから、
Powershellを使って自動化しようと考えた。

インターネットを検索しても、特定のコマンドの説明だけでそれをどうまとめ上げるべきかの説明がなかったので、
自分でまとめてみた。

参考：https://qiita.com/hanakara_milk/items/1197ac9b91fa1fa3abab

## スクリプト

### 注意点

* Read-Hostコマンドの部分は初回実行時以外は固定値をもたせましょう。
* インターネットから切り離されている設備への接続が目的。
  * IPv4で接続する。
  * サブネットマスクは255.255.255.0固定、デフォルトゲートウェイも不要。

### 固定IPへ変更するときのスクリプト

```powershell
Write-Host 現在の設定は下記のとおりになっています。
Get-NetIPAddress | Select-Object -Property IPAddress, InterfaceIndex, InterfaceAlias
$changeIndex = Read-Host 何番のInterfaceIndexを固定IPに変更しますか？
$newIPAddress = Read-Host 新しいIPアドレスを指定してください。

$targetIpaddress = Get-NetIPAddress | Where-Object InterfaceIndex -eq $changeIndex | Select-Object -First 1

# 存在していないInterfaceIndexを選択していたら下記は通らない
foreach($nonNullAdress in $targetIpaddress){
    Remove-NetIPAddress -InterfaceIndex $changeIndex -AddressFamily IPv4
    $resultName = New-NetIPAddress $newIPAddress -InterfaceIndex $changeIndex -PrefixLength 24 -AddressFamily IPv4 | Select-Object -First 1

    Restart-NetAdapter $resultName.InterfaceAlias
}
```

### DHCPへ戻すときのスクリプト


```powershell
Write-Host 現在の設定は下記のとおりになっています。
Get-NetIPAddress | Select-Object IPAddress, InterfaceIndex, InterfaceAlias
Get-NetIPInterface | Select-Object InterfaceIndex, InterfaceAlias, AddressFamily, Dhcp

$changeIndex = Read-Host 何番のInterfaceIndexをDHCPへ戻しますか？
$target = Get-NetIPAddress | Where-Object InterfaceIndex -eq $changeIndex | Select-Object -First 1

# 取得失敗対策
foreach($nonNullTarget in $target){
    Remove-NetIPAddress -InterfaceIndex $changeIndex -AddressFamily IPv4
    Set-NetIPInterface -InterfaceIndex $changeIndex -Dhcp Enabled -AddressFamily IPv4

    $adapterName = $nonNullTarget.InterfaceAlias
    Restart-NetAdapter $adapterName
    Write-Host "$adapterNameのDHCPを設定しました"
}

```

## ポイント

* 最初にIPアドレスを変更する対象を変数に入れ、使い回す。
* 入力された値を使って変更対象のイーサネットアダプタ名等を取得し、入力ミスを減らす。
* foreach文を使って対象のイーサネットアダプターを取得できなかったときの対応をする。
  * もし対象が見つかったらforeach文の中を実行するようにしている。

nullチェックはif文でも大丈夫だが、個人的に条件式の作り方が気に入らなくて逃げているだけ。
毎回数値を手入力するような場合はif文にして、見つからなかったときの処理を作るほうがよさそうだ。
Reactって何者？

# Reactの概略
Facebook社が開発しているJSライブラリであるのが「React」になります。
Reactは従来のJS開発で課題になっている問題を大きく軽減できる可能性を秘めており、次世代の開発手法にも適していると呼ばれております。また、世界的にも非常に注目度の高いライブラリであるため、身につける価値が高いものとして脚光を浴びております。

# Reactの特徴って


Reactの公式サイトでは、下記3項目を特徴として掲載されています。

* 宣言的
* コンポーネントベース
* 一度の学びで何度も書ける

**宣言的**

Reactの最大の特徴は、ズバリなんでしょうか？それはJSと比較してUI開発と大きく異なるものとして「宣言的」である事です。jQueryとは異なってReactでは宣言的に実装する事が可能。それぞれ「どのような条件」「表示結果」など起重することが出来、「この時はこうであるべきと視点で」記述することがストロングポイントになります。

**コンポーネントベース**

コンポーネントベースとは、WEB・アプリを細かい部品に分け、作成した部品を組み合わせて構築手法になります。積み木をイメージしたらわかりやすいですね！　Reactでは、コンポーネントで構成としているため、複雑なUI実装のカプセル化も容易でもあり、拡張も可能なんです！現在のWebもUI構築では主流となってきてるみたいです。

**一度の学びで何度も書ける**

Reactで体得したスキルWebフロンドエンドだけではなく、アプリで使う「React Native」 VRコンテンツの制作「React VR」などでも汎用性が高く、違うフィールドでも使えるのはポイントです。

React公式(https://ja.reactjs.org/)

***

後書きとして、現在、Reactについて最近学習しているのですが、そもそもなぜReactが開発されたのかが把握できていなかったので調べてみました！フロントエンジニアを目指す私にとってこういった背景から知っておくべきだと思ったので今回発信してみました！
OpenCV2で背景差分法 〜 動いている物体が検出された座標値だけ、緑に塗りつぶして動画再生した


次のウェブサイトを参考にしました。

- [OpenCV – 背景差分で物体を検出する方法について](https://pystyle.info/opencv-background-substraction/)

##実行結果

```bash:Terminal
% python3 fulfill_moving_object_with_green.py --file_name f_22_fighter.mp4
```
![](https://user-images.githubusercontent.com/87643752/129759612-6b8d0c46-ef7a-4917-af7d-43b1fafced58.png)

![](https://user-images.githubusercontent.com/87643752/129759648-b3d13f00-a181-4849-9372-b0981fa49f09.png)

![](https://user-images.githubusercontent.com/87643752/129759706-6b3a59ca-2b66-4e8b-a482-c588d275ca49.png)

![](https://user-images.githubusercontent.com/87643752/129759716-1c7a9576-cf9d-429f-88c0-559f1daed027.png)

![](https://user-images.githubusercontent.com/87643752/129761208-1c364c02-6fd0-4b72-bd5a-eb196dab2d58.png)

![](https://user-images.githubusercontent.com/87643752/129761240-9c5d4415-f6a9-49bd-8f57-7be518af370d.png)

![](https://user-images.githubusercontent.com/87643752/129761272-582adcfe-f8f9-4631-ac4c-3511d8df2f00.png)

![](https://user-images.githubusercontent.com/87643752/129761281-bfd655c6-f090-4d00-be17-7ee46532a071.png)

![](https://user-images.githubusercontent.com/87643752/129761300-78d73234-3e43-4c98-801c-b5365bc1a603.png)

##コード

```Python3:fulfill_moving_object_with_green.py
import numpy as np
import cv2
import argparse

# 動画ファイル名をコマンドライン引数から受け取る
parser = argparse.ArgumentParser(description='')    #
parser.add_argument('--file_name')
args = parser.parse_args()

movie_file = args.file_name

cap = cv2.VideoCapture(movie_file)
wait_secs = int(1000 / cap.get(cv2.CAP_PROP_FPS))

model = cv2.bgsegm.createBackgroundSubtractorMOG()

while True:
    ret, frame = cap.read()
    if not ret:
        break

    mask = model.apply(frame)
    #print(mask) 動く物体の検出領域の値：255, それ以外の領域の値：0
    # 胴体検出座標値の画素値を緑色 BGR(0, 255, 0) にする。
    frame[mask == 255] = (0, 255, 0)

    cv2.imshow("Frame (Only Forground)", frame)
    cv2.waitKey(wait_secs)

cap.release()
cv2.destroyAllWindows()

```
We‘re sorry.but something went wrong[2回目のデプロイ後]

# はじめに
本記事では、先日発生したエラーの解決方法を記述します。
当時のターミナルのエラー画像を撮り忘れてしまったため、文字だけとなります。

# 2回目のデプロイ後、ブラウザにてエラー発生

![we're sorry.but....png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1768158/e35101f2-3846-197d-7462-96a7e3057758.png)

もう少しちゃんとした画像を残しておけば良かったと後悔しています。

# 結論
以下のコマンドで、解決しました。
一度マイグレーションをリセットして、また立ち上げるコマンドです。

```
% heroku run RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:migrate:reset

その後、以下のコマンドを入れました
% heroku restart
```

# 手順
当然ですが、
herokuにログインします。

```
% heroku login --interactive
適切なメールアドレス、パスワードを入力
```
その後、We're sorry, but something went wrong.
If you are the application owner `check the logs` for more infomation.
つまり`ログを見ろ`ということですので、

```
% heroku logs --tail --app アプリケーション名
```
これでログを見ることができます。
大変申し訳ありませんが、
ターミナル上でのエラー画像を保存し忘れてしまったため、画像は無いですが、
`error`と書かれている文章があり、
`Migrate`(確か...)という文字がありました。

つまり、マイグレーションに問題があるということになります。

1回目は上手くデプロイできましたが、
2回目はエラーが発生しました。

1回目から2回目にかけて、マイグレーションが変更になり、
herokuは、`1回目`と`2回目`マイグレーションは`どっちが正しい`の？
と分からない状態になっているため、エラーが発生したことになります。

以下のコマンドでひとまず、マイグレーションの状況を確認します。

```
% heroku run rails db:migrate:status  
記事の最後に、このコマンドについての参考サイトを載せております
```

```
Status   Migration ID    Migration Name
--------------------------------------------------
D, [2021-08-17T15:18:57.331809 #4] DEBUG -- :    (2.1ms)  SELECT `schema_migrations`.`version` FROM `schema_migrations` ORDER BY `schema_migrations`.`version` ASC
   up     20210804062811  Devise create users
   down     20210806062147  Create items
   down     20210806090601  Create active storage tablesactive storage
   down     20210811064603  Create purchases
   down     20210811065516  Create addresses
```
以上の結果が返ってきました。(確かこんな感じでした。)
`up`しておかなければならないマイグレーション達が`down`になっております。

冒頭で結論を記述しましたが、

```
% heroku run RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:migrate:reset
```

```
% heroku restart
```
で、全て`up`にすることができました。

# 反省点
`機能が実装するごとに、デプロイして機能を確認できていなかった`

実装するアプリケーションは本格的にサービスを開始する時には、エラーがない状態にしておく必要があり、
作り手側に、`全ての責任`があります。
機能を`１つ１つ確認`した上で、先に進める必要がありました。

# 終わりに
本日からオリジナルアプリの作成に取り掛かっています。
要件定義から実施をしており、本格的に企業就職を考えていくフェーズに入りました。
面接時や企業様へオリジナルアプリを説明するときにこのようなエラーが起きたら１発退場レッドカードです。
デプロイ後のエラーだけは絶対にないよう注意していきます！

以下参考サイトです。
[Railsガイド](https://railsguides.jp/active_record_migrations.html)
[heroku run rails db:migrate:status のコマンドの意味](https://qiita.com/miriwo/items/c8c097831674aef1ee2d)

明日も頑張ります！！
【Golang】ファイル作成→書き込み→読み込み、の一連の流れ

# はじめに

Golangでテスト用に一時ファイルを生成し、中身を書き込み、最後に中身を読み込みたい、となった際にはまったので備忘録として残す

結論からいうと、ファイル読み込み時には、ファイルの先頭から読み込まれるようにすると確実っぽい

# 環境
- go v1.13

# 一時ファイルの作成

``os.Create``でファイル名指定してファイルを作成
一時ファイルなので、``defer os.Remove(f.Name())``で処理完了後にファイル削除するようにする

※Goバージョン1.16以降だと``os.CreateTemp``という一時ファイル生成用メソッドが用意されているっぽい
が、こちらの場合でも明示的に削除する処理は記載必要とのこと（何のためのTempメソッドなのだろうか…）

参考：https://pkg.go.dev/os#CreateTemp

```golang
f, err := os.Create("example.csv")
if err != nil {
	panic(err)
}
defer os.Remove(f.Name())
```

# ファイル書き込み

こちらは標準パッケージの公式Docを参考にした
ここではCSV形式っぽく記載したり、見やすくするために改行したりしている

参考：https://pkg.go.dev/os#File.Write

```golang
c := `id,name,age
1,Alice,99
2,Bob,12`
if _, err = f.Write([]byte(c)); err != nil {
	panic(err)
}
```

# ファイル読み込み

こちらは下記のQiita参考にした
読み込み方法も書き込み方法も複数パターン載っているので参考なるかと

参考：https://qiita.com/qt-luigi/items/2c13ad68e7d9f8f8c0f2

```golang
b := make([]byte, 10)
for {
	c, err := f.Read(b)
	if c == 0 {
		break
	}
	if err == io.EOF {
		break
	}
	if err != nil {
		panic(err)
	}
	line := string(b[:c])
	fmt.Print(line)
}
```

# 一連のコード（失敗）

ここまでの情報をもとに一連のコードを記載してみるが、これでは何も出力されない悲しい結果になってしまった

```golang
package main

import (
	"fmt"
	"io"
	"os"
)

func main() {
	f, err := os.Create("example.csv")
	if err != nil {
		panic(err)
	}
	defer os.Remove(f.Name())

	c := `id,name,age
1,Alice,99
2,Bob,12`
	if _, err = f.Write([]byte(c)); err != nil {
		panic(err)
	}

	b := make([]byte, 10)
	for {
		c, err := f.Read(b)
		if c == 0 {
			break
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			panic(err)
		}
		line := string(b[:c])
		fmt.Print(line)
	}
}
```

# 一連のコード（成功）


どうやらファイル書き込み後、Closeなどせずにすぐに読み込むとファイルの末尾から処理が始まるらしい
つまり、失敗したコードでは``2,Bob,12``以降を読み取ろうとしていて、それ以降には何もないので何も出力されない結果になった

そのため、ファイルの中身全てを出力したい場合は、一度先頭に戻ってから読み取り処理始まるようにする必要がある
これを反映したコードが下記

```golang
package main

import (
	"fmt"
	"io"
	"os"
)

func main() {
	f, err := os.Create("example.csv")
	if err != nil {
		panic(err)
	}
	defer os.Remove(f.Name())

	c := `id,name,age
1,Alice,99
2,Bob,12`
	if _, err = f.Write([]byte(c)); err != nil {
		panic(err)
	}

	// ここから追記
	if _, err = f.Seek(0, 0); err != nil {
		panic(err)
	}
	// ここまで追記

	b := make([]byte, 10)
	for {
		c, err := f.Read(b)
		if c == 0 {
			break
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			panic(err)
		}
		line := string(b[:c])
		fmt.Print(line)
	}
}
```

# さいごに

先頭に戻る必要があることには気づいた背景には、gocsvのサンプルコード眺めていて``f.Seek(0, 0) //Go to the start of the file``のようなコードを見つけたことがある
コードリーディングって偉大
参考：https://github.com/gocarina/gocsv#easy-binding-in-go

また、今回のコードは下記のPlaygroundで試せるのでよければどうぞ

https://play.golang.org/p/521xoguow-U
【Laravel】でトランザクションをはる方法

# Laravelでトランザクションを張る方法メモ

## 方法は2つ
1. DBファサードの`beginTransaction()`、`commit()`、`rollBack()`を使用する。
2. DBファサードの`transaction()`メソッドにクロージャを渡す。

## 1の方法
```php
    public function create(Request $request)
    {
        try {
            DB::beginTransaction(); //トランザクション開始

            $author = Author::create($request->all());

            DB::commit(); //コミット

        } catch(\Exception $e) {

            DB::rollBack(); //ロールバック
        }
    }
```
`beginTransaction()`でトランザクションを開始して、問題がなければ`commit()`でコミット
例外が発生すれば`rollBack()`でロールバックされる。

## 2の方法
```php
    public function create(Request $request)
    {
        DB::transaction(function() use($request) {
            $author = Author::create($request->all());
        });
    }
```
問題がなく処理が実行されれば、自動的にコミットされる。
例外やエラーが発生した場合は自動的にロールバックされる。
GASで愛知県の新型コロナウイルスの感染者数が通知されるLINE Botを作ってみた

## はじめに
新型コロナウイルスの感染者数が日々気になるので、簡単に通知してくれる手段がないかなあと思っていました。そんなときにGASを使えば簡単にLINE Botができることを知ったので、愛知県の新型コロナウイルスの感染者数を通知してくれるLINE Botを作りました。

## 感染情報のデータ
新型コロナウイルスの感染情報は[新型コロナウイルス対策ダッシュボード](https://www.stopcovid19.jp/)に掲載されている、厚生労働省の報告に基づくデータを利用しています。更新頻度がまちまちですが、今回はこちらを使っていきます。

実際のデータ
https://www.stopcovid19.jp/data/covid19japan.json

## LINE Bot
LINE Botを利用するためには、LINE Developersに登録して、アクセストークンとユーザーIDを取得する必要があります。

ここから登録が可能です。
https://developers.line.biz/ja/

詳しいやり方は以下の記事を参考にしました。

https://qiita.com/oimo23/items/11a0c38bbe1e297fb611

## スクリプト
実際のスクリプトはこんな感じです。


```js
function SEND_MESSAGE() {
  // 新型コロナウイルスのデータが入ったJSONからデータを取得します
  var COVID19_URL = 'https://www.stopcovid19.jp/data/covid19japan.json';
  var json = UrlFetchApp.fetch(COVID19_URL).getContentText();
  var json_data = JSON.parse(json);
  
  // json_data.lastUpdate は日付です
  // 愛知県のデータを取得する場合は、json_data.area[22]
  
  var update_date = json_data.lastUpdate;
  var num_patients = json_data.area[22].npatients;
  var num_deaths = json_data.area[22].ndeaths;
  var data_arr = [update_date, num_patients, num_deaths];
  
  // 通知の内容を記載します
  var date_message_ver = Utilities.formatDate(new Date(update_date), 'JST', 'MM月dd日');
  var message = "【" + date_message_ver + "の感染者情報】\n" + "総感染者数：" + num_patients + "人\n" + "総死者数：" + num_deaths + "人";
  //Logger.log(message);
  
  // アクセストークン等を記載して、通知をする準備をします
  var access_token = 'YOUR_TOKEN';
  var user_id = 'YOUR_LINEDEVELOPERS_ID';
  var line_url = 'https://api.line.me/v2/bot/message/push';
  
  var options = {
    "headers": {
      "Content-Type": "application/json; charset=UTF-8",
      'Authorization': 'Bearer ' + access_token,
    },
    "method": "post",
    "payload": JSON.stringify({
      "to": user_id,
      "messages": [{
        "type": "text",
        "text": message,
      }]
    })
  };  
  
  
  // 通知します
  UrlFetchApp.fetch(line_url, options);
}
```

スクリプトの中に、アクセストークンなどが出てきます。これらを直接スクリプトに記載するのはよくないので、GASのスクリプトプロパティという機能を使って保管しておきましょう。やり方は以下の記事で簡単に記載しています。

https://qiita.com/zumi0/items/cc3cd4276c6a254781d3#gas%E3%82%92%E6%9B%B8%E3%81%8F

## 定期実行の登録
GASでLINE Botを作る大きな理由は、定期実行が簡単にできるからです。毎日ある程度決まった時間に新型コロナウイルスの感染者数の通知が来るようにすることは、GASでは簡単にできます。

やり方は、以下の通りです。
1. エディタ画面の左側にある時計のボタンをクリック
2. 画面右下にある「トリガーを追加」をクリック
3. 時間等を設定する

これで定期実行で、新型コロナウイルスの感染者数が通知されるようになります。

## さいごに
今回は簡単ではありますが、新型コロナウイルス感染者数が通知されるLINE Botを作成してみました。通知の内容がとても簡素なので、そこを更新してリッチなものにしていきます。
ActionView::MissingTemplateが出たときの対処法。

#結論。
###部分テンプレートの参照先が間違っている。
私自身作成したコードで例を挙げるとすると、下記のような修正をしました。

```erb
誤：<%= render 'favorites/favorite-btn', post_image: @post_image %>

正：<%= render 'public/favorites/favorite-btn', post_image: @post_image %>
```

#解決した経緯(上で分かったら見なくていい)
ポートフォリオ作成中、いいね機能の非同期通信実装時にこんなエラーが出てきました。

![qiita01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1789450/88a368aa-872b-e042-23f7-dfdae62a1e7a.jpeg)
(前にアップしたのはポートフォリオ情報が入ってたので消しました。)

####ActionView::MissingTemplate in ???????
なにこれ。
色々調べた結果、エラー君が言いたいことは、

```erb
<%= render 'favorites/favorite-btn', post_image: @post_image %>
```

こんなコード書いてるけど

```
『favorites/favorite-btn.html.erb』
```
↑ こんなファイルなんか無ぇよ!!!!!!!!
ってことらしいです。

....いやいや、作っただろ....って思っていたら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1789450/a000e107-6500-c114-4780-62966d0f9e03.png)
『public』フォルダに格納していることを忘れてました。
つまりは部分テンプレートの参照先が間違っているってことです。

なので部分テンプレートに記載するべき正しいコードとしては

```erb
<%= render 'public/favorites/favorite-btn', post_image: @post_image %>
　　　　　　 ^^^^^^^
```

私の場合は、publicの記載を忘れていたのでそれを追加したら解決しましたが、
もしそれでも治らなければコードの記載自体が間違っているかもです。

以上！
Poetry add numpyでFor numpy, a possible solution would be to set the `python` property to ">=3.7,<3.11"とでてしまう

# はじめに

会社でDockerの課題を作成して、環境構築の勉強をしていただいていました。
私も一応回答として課題で求めていた環境を事前に作成していました。

しかし、数日後に質問を受けて同じ環境を同じ手順で作成したところ、エラーがでるようになっていました。
まだ記事が(世界中でも？)存在しないため、解決方法を載せます。

# 環境

私が使っている環境は以下となります。

```Dockerfile
FROM python:3.7-alpine

USER root
WORKDIR /app

RUN apk update
RUN apk --no-cache add\
		alpine-sdk\
		libffi-dev\
		zeromq-dev\
		openssl-dev

RUN pip install --upgrade pip

ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1

RUN pip install\
		cryptography==3.4.1\
		poetry==1.1.78
```

```docker-compose.yml
version: '3'
services:
  python3:
    restart: always
    build: .
    container_name: 'jupyter'
    working_dir: '/app'
    tty: true
    volumes:
      - ./app/:/app/
    ports:
      - "8888:8888"
```

```pyproject.toml
[tool.poetry]
name = "app"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]

[tool.poetry.dependencies]
python = "^3.7"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
```

# 問題

`Poetry add numpy`をすると以下のエラーが発生します。

```
$ poetry add numpy
```

```
 Because no versions of numpy match >1.21.2,<2.0.0
   and numpy (1.21.2) requires Python >=3.7,<3.11, numpy is forbidden.      
  So, because app depends on numpy (^1.21.2), version solving failed.       

  at /usr/local/lib/python3.7/site-packages/poetry/puzzle/solver.py:241 in _solve
      237│             packages = result.packages
      238│         except OverrideNeeded as e:
      239│             return self.solve_in_compatibility_mode(e.overrides, use_latest=use_latest)
      240│         except SolveFailure as e:
    → 241│             raise SolverProblemError(e)
      242│
      243│         results = dict(
      244│             depth_first_search(
      245│                 PackageNode(self._package, packages), aggregate_package_nodes

  • Check your dependencies Python requirement: The Python requirement can be specified via the `python` or `markers` properties

    For numpy, a possible solution would be to set the `python` property to ">=3.7,<3.11"
```

数日前までは同じ方法でインストールできていたのでいきなりできなくなりました。

# 解決方法

これは`poetry add numpy`で最新のnumpyのバージョン`1.21.2`をインストールしていることが原因でした。
`pyproject.toml`にある`python = "^3.7"`では対応していないようです。

以前インストールできたのは、`1.21.1`でした。なんとこの記事を書いた前日に新たなバージョンがリリースしておりました・

解決方法は以下の二つです。

## 1. Numpy1.21.2(最新版を入れる)

`pyproject.toml`を以下のように変更します。

```
python = "^3.7"
↓
python = ">=3.7,<3.11"
```

すると最新版のnumpyがインストールできるようになります。

## 2. python="^3.7"でインストールする方法

python="^3.7"もしくはpython="3.7"の固定バージョンでインストールする場合はnumpyのバージョンを指定します。

```
$ poetry add numpy=1.21.1
```

# おわりに

Dockerは常にどの環境でも動くのでとても良いですが、環境のバージョンはしっかり固定しないとこのような問題が発生してしまいます。いつどのライブラリがバージョンアップしているかわからないので、気を付けていきたいです。
Word VBA キャンバス内の図を操作

##新しい描画キャンバス作成
挿入＞図形＞新しい描画キャンバス作成

##サンプルコード説明
* 選択中の描画キャンバス内にある「Rectangle」の図形に対して
 * 幅：30mm
 * 高さ：10mm
 * フォントサイズ：8p
 * 図形内フォント水平/垂直軸：配置中央
 * フォントネーム：MS Pゴシック
 * 図形内上下左右：余白0p
 * 行間：固定7p 

```sample.docm
Sub startMoldShapes()
    Dim itemMax As Long
    Dim itemName As String
    Dim pageName As String
    Dim ans As Boolean

pageName = Selection.ShapeRange(1).Name
ans = MsgBox("OK?", vbYesNo)
If ans = False Then End
itemMax = ActiveDocument.Shapes(pageName).CanvasItems.Count

For i = 1 To itemMax
    itemName = ActiveDocument.Shapes(pageName).CanvasItems(i).Name

    
    If itemName Like "*Rectangle*" Then
        With ActiveDocument.Shapes(pageName).CanvasItems(i)
            .Width = MillimetersToPoints(30)
            .Height = MillimetersToPoints(10)
            .TextFrame.TextRange.Font.Size = 8
            .TextFrame.HorizontalAnchor = msoAnchorCenter
            .TextFrame.VerticalAnchor = msoAnchorMiddle
            .TextFrame.TextRange.Font.Name = "ＭＳ Ｐゴシック"
            .TextFrame.MarginTop = 0
            .TextFrame.MarginBottom = 0
            .TextFrame.MarginRight = 0
            .TextFrame.MarginLeft = 0
        End With
        
        ActiveDocument.Shapes(pageName).CanvasItems(i).Select
        With Selection.ParagraphFormat
            .LineSpacingRule = wdLineSpaceExactly
            .LineSpacing = 7
        End With
    End If
Next
            
End Sub
```
axios 0.21.2で二重JSON.stringifyバグ? → 0.21.4で修正

Node.js およびブラウザ向けの XHR ライブラリ [axios](https://www.npmjs.com/package/axios)　のバージョン 0.21.2 で、アプリ側の実装によって発生するバグないし　breaking change が入ってしまい、近日公開の 0.21.4 で修正される見込みです。→ [修正PR](https://github.com/axios/axios/pull/4020)

axios で POST するとき、典型的には以下のように使います。

```js
const axios = require("axios");

const data = {"id": 123};

await axios.post("/api", data); // OK
```

上記は下記と同じ意味であり、これについては 0.21.2 でも問題ありません。

```js
await axios.post("/api", data, {headers: {"content-type": "application/json"}}); // OK
```

しかし、事前にボディを文字列化していた場合に従来との挙動が変わっていました。

```js
const json = JSON.stringify(data);

await axios.post("/api", json); // NG

await axios.post("/api", json, {headers: {"content-type": "application/json"}}); // NG
```

0.21.1 以前では、上記で `{"id": 123}` という文字列がそのまま送信されていたところ、
0.21.2 では二重に JSON.stringify 変換された `"{\"id\":123}"` という文字列が送信され、
API サーバ側で展開エラーが起きていました。この問題は 0.21.4 で直る見込みです。

ただし、今後は事前に stringify したい場合は、下記のほうが安全で速いかもしれません。

```js
const buffer = Buffer.from(JSON.stringify(data));

await axios.post("/api", buffer, {headers: {"content-type": "application/json"}}); // OK
```

個人的には、余計なことせずに、シンプルなままで保って欲しいが。
Python環境構築 (venv, Amazon Linux 2)

# ■ 参考
https://docs.python.org/ja/3/tutorial/venv.html

https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-install-extras-library-software/

# ■ Python3.8のインストール
普通にyumインストールすると3.6がインストールされてしまうため、 `amazon-linux-extras` を利用してインストールします。
`amazon-linux-extras` はAmazon Linux用のリポジトリで、より新しいバージョンのライブラリを利用することができます。

```bash
# amazon-linux-extrasパッケージがインストールされていない場合はyumでインストール
sudo yum install -y amazon-linux-extras

# python3.8をインストール
sudo amazon-linux-extras install -y python3.8
```


# ■ venv: プロジェクトを作成
venvは標準モジュールなので、インストールは必要ありません。

```bash
# 環境作成
python3.8 -m venv sample_project
cd sample_project
```

# ■ venv: 仮想環境の有効化
venvモジュールは、環境変数PATHを書き換えるシンプルな仕組みで実装されています。
仮想環境を有効化すると、PATHにプロジェクト内のpythonのパスが追加されます。

```bash
# 有効化
source bin/activate

# プロジェクト内のpythonが参照されているのを確認できます
type python
type pip
```

# ■ venv: パッケージ管理
パッケージ管理は下記のようなサイクルで行います。

1. pipでパッケージをインストール
1. requirements.txtに書き込み
1. requirements.txtからパッケージをインストール


```bash
# パッケージのインストール
pip install boto3

# インストールされたパッケージを requirements.txtに書き込み
# pip freezeはインストールされたパッケージ一覧をpip installが解釈可能なフォーマットで出力します。
pip freeze > requirements.txt

# requirements.txt からパッケージをインストール
pip install -r requirements.txt

```

# ■ venv: 実行
普通にスクリプトを書いて実行するだけです。

```bash
echo "print('Hello, World')" > sample.py
python sample.py
```

# ■ venv: 仮想環境の無効化

```bash
# 無効化
deactivate
```
Windowsでnpm installしたいけど環境汚したくないからWSL2でDocker-composeを使う

## 概要
- Docker初めて使います。
- VSCodeのシンタックスハイライトを作るためにyeomanをインストールしたかったのですが、npmが必要とのことでした。
- 単純にWSL2でnpm installしても良かったのですが、WSL2の環境を汚したくないのでDockerのコンテナの中で作業したいと思いました。
- 
 
## 事前準備
- WSL2: Ubuntu-20.04
- Docker : Docker version 20.10.8, build 3967b7d

## Docker-composeのための準備
WSL2の中に下記構成でファイルを作っておきます。

```bash
~/node-docker$ tree -f
.
├── ./docker-compose.yml
└── ./node
    └── ./node/Dockerfile

```

次にdocker-compose.ymlとDockerfileを書いていきます。ベースとしているのは参考記事[Docker-composeを使ってnode.jsの環境構築をしてみたのよ。](https://qiita.com/art_porokyu/items/8363334c358c67adb61a)中のコードです。npm installやimageの部分だけ変えています。

今回は./node/appを作業ディレクトリとしたいので、次のdocker-compose.ymlには次のように書いておきます。

```yml:docker-compose.yml
version: '3'
services:
  webserver:
    build: node
    image: node:latest　#ここだけ変えました。
    tty: true
    volumes:
      - ./node/app:/app
    ports:
      - "8080:3000"
```

yoをインストールするため、Dockerfileは次のように書いておきます。

```Dockerfile:Dockerfile
# ベースイメージを指定
FROM node

# node.js の環境変数を定義する
# 本番環境では production
ENV NODE_ENV=development

# 雛形を生成するのに必要なパッケージのインストール
RUN npm install -g yo generator-code #ここだけ変えました。

# ディレクトリを移動する
WORKDIR /app

# ポート3000番を開放する
EXPOSE 3000
```

## コンテナに入るまで
ここからは参考に記載した[Docker-composeを使ってnode.jsの環境構築をしてみたのよ。](https://qiita.com/art_porokyu/items/8363334c358c67adb61a)と全く同じ手順で進みます。
最初にbuildします。初回は必要らしいです。

```bash
$ docker-compose build
[+] Building 20.5s (3/6)
 => [internal] load build definition from Dockerfile
 => => transferring dockerfile: 390B
中略
 => => naming to docker.io/library/node:latest
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

```

イメージが作成されているか確認します。

```bash
$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
node         latest    9687fd56f5e5   26 seconds ago   982MB
```

コンテナを起動し、中に入ってみます。

```console
$ docker-compose up -d
[+] Running 2/2
 ⠿ Network node-docker_default        Created
 ⠿ Container node-docker_webserver_1  Started
$ docker exec -it node-docker_webserver_1 /bin/sh
# 
```

yoがインストールされているか確認してみます。

``` console
# yo --version
4.3.0
```

## 作業の終わりかた
1. コンテナから`exit`で抜けます。
2. `docker-compose stop`でコンテナを停止します。


## もう一度始めたいとき
1. `docker-compose restart`でコンテナ起動します。
2. `docker exec -it <コンテナ名> /bin/sh`でコンテナの中に入れます。

## 開発を終わるとき
`docker-compose down`でコンテナが削除されます。

## 終わりに
書いてて思いましたが、WSL2を使ってるものの特徴的な部分はありませんね。強いて言うならWSL1→2の移行とDockerDesktopのインストールが手間取りましたが、他の方が散々やっているのでこの記事では書きません。
yoのインストールは他の参考記事を見てもnpmバージョンが原因なのかうまくインストールできなかったので、どのimageを使ったかのメモとして記事を残しておきたいと思います。


## 参考
[Visual Studio CodeでCode Syntax Highlight Extentionを作る](https://www.1915keke.com/entry/vscode-syntax-highlight)
[Docker-composeを使ってnode.jsの環境構築をしてみたのよ。](https://qiita.com/art_porokyu/items/8363334c358c67adb61a)
[【Docker】docker-composeコマンド早見表](https://qiita.com/beanbeenzou/items/47207bb131ec5a158774)
[docker-compose `up` とか `build` とか `start` とかの違いを理解できていなかったのでまとめてみた](https://qiita.com/tegnike/items/bcdcee0320e11a928d46)
最尤推定法についてまとめ【緑本読書ノート】①

#読書ノート
緑本こと[データ解析のための統計モデリング入門](https://www.amazon.co.jp/%E3%83%87%E3%83%BC%E3%82%BF%E8%A7%A3%E6%9E%90%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E7%B5%B1%E8%A8%88%E3%83%A2%E3%83%87%E3%83%AA%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80%E2%80%95%E2%80%95%E4%B8%80%E8%88%AC%E5%8C%96%E7%B7%9A%E5%BD%A2%E3%83%A2%E3%83%87%E3%83%AB%E3%83%BB%E9%9A%8E%E5%B1%A4%E3%83%99%E3%82%A4%E3%82%BA%E3%83%A2%E3%83%87%E3%83%AB%E3%83%BBMCMC-%E7%A2%BA%E7%8E%87%E3%81%A8%E6%83%85%E5%A0%B1%E3%81%AE%E7%A7%91%E5%AD%A6-%E4%B9%85%E4%BF%9D-%E6%8B%93%E5%BC%A5/dp/400006973X)の勉強会を行ったので復習も兼ねて要点整理とメモをします。
Rコードや基礎的な統計知識については基本的に省き、自分が緑本で重要だなと思ったポイントを独断と偏見で書き殴ります。

著者の[久保先生の公式サイト](https://kuboweb.github.io/-kubo/ce/IwanamiBook.html)からいろいろな情報やまとめノートのリンクもあるのでこちらも参考にさせていただきます。
##データと確率分布とパラメータ
具体的なデータと、データのばらつきを見てみます。
ある50個の植物$(i=1・・・50)$から取れる種子数を$y_i$とします。
ここで
・$y_i$は0以上の整数
・$y_i$の平均は3.56（データより取れる標本平均）
・種子数にばらつきがあるっぽい（分散は2.99）
とします。

このようなばらつきのあるデータをあらわすためには確率分布の概念が便利です。
分布にはパラメータがあり、例えば正規分布であれば平均と分散がそれにあたります。

このデータの確率分布を知りたい時にはどうすれば良いでしょうか。

まず、この種のデータはゼロ以上で上限が不明なこと、整数のカウントデータであることから平均3.56のポアソン分布に従うと仮定します。
そしてポアソン分布のパラメータは一つで$\lambda$と書かれるのが一般的。
特徴的なのは$\lambda$$=$平均$=$分散であることです。この種データも平均と分散がそれぞれ3.56, 2.99と近いのでまあポアソン分布と仮定しも良いかなということで進めましょう。

##パラメータの推定：最尤推定法
ポアソン分布に従うと決めたのは良いものの、パラメータ$\lambda$が不明です。
ここでは最尤推定法でパラメータを推定します。
最尤推定法自体はポアソン分布以外のどのような確率分布でも適用できます。

最尤推定法は「尤度」というあてはまりの良さを最大にするようなパラメータを探す方法です。今回探すパラメータは$\lambda$です。
尤度とは、ある$\lambda$の値を決めたときに、すべての個体$i$についての$p(y_i|\lambda)$の積です。
例えば$\lambda$を$\lambda_t$という定数だとしましょう。
このときの尤度を$L(\lambda_t)$とすると、上の定義に則ると
$L(\lambda_t)=$($\lambda=\lambda_t$の下で$y_1$の確率)$\times$($\lambda=\lambda_t$の下で$y_2$の確率)$\times$・・・($\lambda=\lambda_t$の下で$y_50$の確率)
↓
$L(\lambda_t)=\prod_ip(y_i|\lambda_t)=\\prod_i\dfrac{\lambda_t^{y_i}exp(-\lambda_t)}{y_i!}$
$(i=1・・・50)$
右辺はポアソン分布の確率密度関数。

なんで確率の積なのかというと、$y_1$がある特定の値かつ$y_2$がある特定の値で・・・・と、この$i=1・・・50$の50個の事象が同時に起こる確率を計算したいからです。

尤度関数$L(\lambda)$はわかりましたがなんだか扱いにくい。なので対数変換します。
ここからは一般化するため$\lambda_t$ではなく$\lambda$で表記します。

$\log L(\lambda)=\sum_i (y_i\log \lambda-\lambda-\sum_k^{y_i} \log k)$

尤度、対数尤度は大きいほどデータに対する分布のあてはまりが良くなります。
なので対数尤度が最大になる$\lambda$を探します。$\log L(\lambda)$の傾きがゼロになる点が最大値となるので偏微分して

$\frac{\partial \log L(\lambda)}{\partial \lambda}=\sum_i\\{\frac{y_i}{\lambda}-1\\}=\frac{1}{\lambda}\sum_iy_i-50$

これがゼロの時、最尤推定値$\hat{\lambda}$が求まるので

$\hat{\lambda}=\frac{1}{50}\sum_iy_i=\frac{データ総和}{データ数}=データの平均=3.56$

これは最初に示した本データの平均と等しくなりました。

##まとめ
・データの特徴から確率分布を仮定する
・あるパラメータ$(\theta)$を推定するには最尤推定法を使う
・最尤推定値は確率の積である$L(\theta)=\prod_ip(y_i|\theta)$を対数変換した$\log L(\theta)=\sum_i\log p(y_i|\theta)$の最大値である。
最低限の知識を得たWebサービス開発初心者が次の一歩としてやるべきことまとめ

この記事は以下のような人（＝自分）にチェックしてほしいです。

* 5年程度のSE経験があり、システム開発やプログラミングに関する最低限の知識がある
* 自分でWebサービスを作ってみたいけど何をしたらいいかわからない

Webサービス開発に関する10以上の動画やブログ記事を見て、次の一歩としてどんなアクションを取るべきかをまとめました。

## 筆者の状況（ブログ執筆時点）
1. 大手SIerでの開発経験が8年あるが、クライアントサーバ型システムのクライアント側のアプリを担当していたため、Webシステムの開発経験はほぼなし。

2. 自分でWebサービスを開発した経験はゼロ

3. HTML、CSS、JavaScript、Spring、Gitの基本的な知識は学習済み
　筆者が学習に使ったコンテンツは以下。
　① [【書籍】HTML&CSSとWebデザインが 1冊できちんと身につく本](https://www.amazon.co.jp/HTML-CSS%E3%81%A8Web%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%81%8C-1%E5%86%8A%E3%81%A7%E3%81%8D%E3%81%A1%E3%82%93%E3%81%A8%E8%BA%AB%E3%81%AB%E3%81%A4%E3%81%8F%E6%9C%AC-%E6%9C%8D%E9%83%A8-%E9%9B%84%E6%A8%B9/dp/4774190640/ref=tmm_other_meta_binding_swatch_0?_encoding=UTF8&qid=&sr=)
　② [【Progate】JavaScript　多様な可能性を秘めたフロントエンド言語](https://prog-8.com/courses/es6)
　③ [【udemy】Spring 入門 ～ SpringBoot 2 を使ってお問い合わせアプリとToDoアプリを作る ～](https://www.udemy.com/course/java_spring_beginner/)
　④ [【udemy】Git： もう怖くないGit！チーム開発で必要なGitを完全マスター](https://www.udemy.com/course/unscared_git/)


## 参照した情報
### 動画
1. [誰も教えてくれない！ゼロからWebサービスを作る方法](https://www.youtube.com/watch?v=BpEDzrMKR_A)

1. [ポートフォリオがないエンジニア必見！革新的なWebサービスの作り方【ひろゆき切り抜き】](https://www.youtube.com/watch?v=MbGz9ZLlSes)

1. [【ひろゆき】自社開発・自社サービスを語るひろゆきまとめ【IT企業 Web系 ひろゆき 切り抜き エンジニア転職】](https://www.youtube.com/watch?v=ceObywPkR6k)

1. [Webサービスで起業した元COOに聞く！使われるWebサービスを作る秘訣【前編】](https://www.youtube.com/watch?v=giFRQ4UkrTo)

1. [Webサービスで起業した元COOに聞く！使われるWebサービスを作る秘訣【後編】](https://www.youtube.com/watch?v=QDGtTvZOOLk)
### ブログ記事

1. [【初心者向け】Webサービス開発の作り方をステップ形式で解説](https://www.sejuku.net/blog/5546)

1. [【入門】個人でWEBサービスを開発する手順と必要な言語やスキルを解説](https://www.pasonatech.co.jp/workstyle/column/detail.html?p=2490)

1. [エンジニアが個人開発したWebサービス・アプリ100個紹介します](https://note.com/haken_se_30manen/n/n4f379cc91f11)

1. [Webアプリとネイティブアプリの違い](https://yapp.li/magazine/2093/)

1. [初心者3人でwebサービス(webアプリ)を作ったので、立ち上げからリリースまでを時系列に書いていく](https://qiita.com/yuno_miyako/items/d6595719ae7065927499)

1. [【初心者でも確実に作れる】Webサービスの作り方を８ステップで解説
](https://hiroking.info/how-to-make-web-service/)


## 次の行動につながるポイント
上記の動画やブログを見て、大事だと思ったことは以下です。
**　・自分が普段使っているサービスの改善点を見つける**
**　・自分や周囲の人が悩んでいる問題点やアイデアに着目する**
**　・考えたことや浮かんだアイデアを日常的にメモに残す**
**　・既存のサービスに少し機能を追加したものでも十分
　　（真新しいアイデアでないとNG、というわけではない）**
**　・最低限の機能を実装して速くリリースする**
**　・開発にハードルが低いのはネイティブアプリよりもWebアプリ**



## 結論
10以上の動画やブログを見て考えを整理した結果、

システム開発やプログラミングに関する最低限の知識を得たら、次は
***日常生活の悩みや小さなアイデアをメモに書き留める***
ことをやっていくのがよいかと思います。
【LINE bot】 userId, groupId, roomIdを返してくれるBot【GAS】

# Botの動作イメージ
Botを招待しメッセージを投げると
個人チャットなら「**ユーザーID**」を
グループなら「**グループID**」を
LINEWORKS のトークルームなら「**ルームID**」を返してくれます。
※ルームIDに関しては、LINEWORKSを使っていないため、検証できていません、、

■個人チャット
![userId.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/9d7ffd24-6faf-4c02-0585-c2e3af938b2a.jpeg)
■グループ
![groupId.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/f69be31e-be0a-4e81-bb91-5bdf63fa004c.jpeg)

#プッシュメッセージ送信用のIDを取得できる
Botのメッセージ送信方法は大きく分けて(**応答メッセージ**、**プッシュメッセージ**)があり、プッシュメッセージを利用する場合、送信先のIDを指定する必要があります。
このBotでプッシュメッセージ送信用のIDを取得することが出来ます。

#GASでBotを実装
LINE developersのチャンネル作成など詳細は、いろいろな記事でまとめられているので省きますが
1. 以下のGASのACCESS_TOKENをLINE developers記載のトークンに書き換え
2. GASをWEBアプリとしてデプロイ
3. デプロイしたURLをLINE developersでWebhook URL設定、Webhook利用許可
これで、Botとして動作するはずです。

```javascript:
// LINE developers記載のアクセストークン
var ACCESS_TOKEN = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

function doPost(e) {
  // ----- 送られてきた値をパース -----
  var event = JSON.parse(e.postData.contents).events[0];

  // 応答用Token
  var replyToken = event.replyToken;

  // typeを取得 
  var type = event.source.type;
  
  // typeを判定して、idを取得
  if (type == 'user') {
    var id = event.source.userId;
  } else if (type == 'group') {
    var id = event.source.groupId;
  } else if (type == 'room') {
    var id = event.source.roomId;
  }

  // ----- メッセージ送信用パラメータ設定 -----
  var url = 'https://api.line.me/v2/bot/message/reply';

  var payload = {
    'replyToken': replyToken,
    'messages': [
      {
        'type': 'text',
        'text': type + '_id = '+ id
      }
    ]
  };

  var options = {
    'method': 'post',
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'payload' : JSON.stringify(payload)
  };

  // ----- lineメッセージ送信 -----
  UrlFetchApp.fetch(url, options)
}
```

#送信元の判定

```javascript
var type = event.source.type;
```
sourceオブジェクト内の'type'を見て判定し、取得するIDを切り替えています。
個人チャット：**user**
グループ：**group**
トークルーム: **room**
の3種類あるようです。


#スプレッドシートに書いてもOK
メッセージを送りたくなければ、スプレッドシートに書き出して確認するのもありです。

```javascript
var spreadsheet = SpreadsheetApp.openById("*********************");
var sheet = spreadsheet.getSheetByName("シート1");
sheet.getRange(1, 1).setValue(id);
```

#参考
https://developers.line.biz/ja/docs/messaging-api/sending-messages/

https://developers.line.biz/ja/reference/messaging-api/#send-push-message-request-body

https://developers.line.biz/ja/reference/messaging-api/#source-user

https://www.pre-practice.net/2018/11/line-botuserid-groupid-roomid.html
Proxy Protocol とは？

## 勉強前イメージ

プロキシのためのプロトコル？？？

## 調査

### Proxy Protocol とは？

端的に言うと
`httpの X-Forwarded-for みたいな機能を http以外で使用するときのプロトコル` になります。

よくあるアクセス方法で以下の図があります。

- アクセス元 : X.X.X.X
- LB : Y.Y.Y.Y
- EC2インスタンス

アクセス元からEC2インスタンスにアクセスされる際、
EC2から見たアクセス元IPはLBのY.Y.Y.YのIPアドレスになってしまいます。
Proxy Protocol を使用することで実際のアクセス元の X.X.X.X を取得することが出来ます。
つまり、DBサーバへのアクセスの際でも アクセス元IPを確認することが出来ます。

![12021-09-06 # Proxy Protocol とは？ - diagrams.net - G.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/e4e3366f-d3e0-0789-bc11-cd7e0cfb8330.png)


## 勉強後イメージ

確かにELBだとアクセス元IPはELBになっちゃうよね。
http以外でX-Forwarded-forみたいなのしたいなーってなったことなかったから考えたことなかったけど
調査とか、もしアクセス制御するならほしいよね。

## 参考

- [NLB (Network Load Balancer) が Proxy Protocol に対応しました](https://dev.classmethod.jp/articles/nlb-meets-proxy-protocol-v2/)
- [AWSでのHTTP/2 or SPDY運用の課題とPROXY protocol](https://developer.hatenastaff.com/entry/2016/04/19/140234)