OmniAICreator/Qiita-1.07M huggingface dataset:
スプライトの当たり判定を見た目と別にする

Scratchでスプライトとスプライトがぶつかったかどうかを判定するには「〜〜に触れた」という調べるブロックを使うことができます。しかしこのブロックでは、１ドットでも重なってしまったらイベントが発生してしまいます。そのため、このようなロケットの自キャラを用意した場合、炎や煙の部分にも当たり判定ができてしまいます。

<img width="25%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/8e60fc88-93ae-d863-dcfa-13f65e860107.png">

そのため、表示用のスプライトとは別に当たり判定用のスプライトを用意して、常に当たり判定用のスプライトに表示用のスプライトが重なるようにします。

<img width="25%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/c25a3e35-9075-868d-0a8a-e150d457d010.png">

最後にこのスプライトを見えないようにする必要がありますが、「隠す」ブロックを使ってしまうと、「〜〜に触れた」というイベントが発生しなくなってしまいます。そのため、次の方法のいずれかで見えなくします。

* 当たり判定用のスプライトが表示用のスプライトに完全に隠れるような大きさにして、表示用のスプライトを最前面に移動する
* 幽霊の効果を100%にする
* 表示用のスプライトを複製して、当たり判定部分以外の場所を消しゴムで消したものを当たり判定用のスプライトにして、重なって表示されても見た目が問題ないようにする。

それぞれ一長一短あります。適した方法を使ってください。

サンプルプロジェクト

https://scratch.mit.edu/projects/615262936

![スクリーンショット](https://cdn2.scratch.mit.edu/get_image/project/615262936_480x320.png)
Developpers Boost 2021に参加した振り返り   

## なぜ参加したか
- エンジニアとして4年目になったが、今後の自身のキャリアについて不安になったため
- 自分はエンジニアとして何がしたいのかを考えるための方法を知りたかったため

## 参加したセッション
- 不安なあなたにおくるエンジニアのキャリア形成ガイド
- 面白い事業に関わり続けるために ～エンジニアとしての成長戦略～
- 経験学習型キャリア探索法 〜ふりかえりで始めるキャリアパスの見つけ方〜

## まとめ（今後、自身が意識していくべきこと）

### ◇意識面
- 主体的であり、武器を磨き続けること。（今持っているスキルを磨きつづける。）
- 市場価値を考える。
- 向いていないと決めつけず、まずはやってみる。そして、できることを増やしていく。（やりたいことに携わるチャンスを増やす。）
- 今いる環境をより良くする。（転職や、今いる職場をより良くするなど。）

### ◇行動面
- 日、週、年単位での振り返りを実施し、やりがいを感じたこと、やりたいことを見つけ出す。
- 振り返った結果、やりたいことを実現するために何をすべきかを考え、行動に移す。
Twilio Programmable Videoでボイスチェンジャーやバーチャル背景を実装する

# ボイスチェンジャー

こちらの記事ではブラウザ上で動作する [Twilio Programmable Video](https://www.twilio.com/go/video-api-sales-jp-1) の [JavaScript client](https://www.twilio.com/docs/video/javascript-getting-started) について説明します。オーディオデータにエフェクトをかけるのには [Tone.js](https://tonejs.github.io/) を利用します。他の何かを利用したい場合でも、入出力の扱い方は同じなのでまあ参考になるといいですね。

一般的にWebRTCによるビデオ通話を実装する場合、実行環境であるブラウザ側に用意されたデバイスへのインターフェース `getUserMedia` を通して取得した `MediaStream` である `LocalMediaStream` を相手方に送信し、相手方もまた同じ仕組みを通じてこちら側にデータを送り返すやり取りを繰り返すことになります。データの送受信は `MediaStreamTrack` という一種のコンテナを通じて実行されますが、そこに `track` と呼ばれる実際の映像や音声を追加したり外したりしてコントロールすることもできます。　音声を扱う `track` にはそれぞれ一つ以上の `channel` があります（例えばステレオの左右のチャンネルとか）が、まあ普通は `track` が最も低レベルのレイヤーになります。ただし、 `DataChannel` は違います。これは全然別のものです。

うん。訳がわかりませんよね。

```
 getUserMedia で↓をget!
+--------------------+        +--------------------+
|  LocalMediaStream  |        |    MediaStream     |
|  +-------------+   |        |  +-------------+   |
|  | Video Track |   |        |  | Video Track |   |
|  +-------------+   |        |  +-------------+   |
|                    |  ===>  |                    |  ===>  相手側に届く
| +----------------+ |        | +----------------+ |
| | Audio Track    | |        | | Audio Track    | |
| |                | |        | |                | |
| | "left channel" | |        | | "left channel" | |
| | "right channel"| |        | | "right channel"| |
| |                | |        | |                | |
| +----------------+ |        | +----------------+ |
+--------------------+        +--------------------+
```

魔法のようにわかりやすい図ですね。

さて、今回取り扱うのは、`Tone.js` 経由で取得した音声入力にエフェクトをかけ、改めてLocalMediaStreamにaudio trackとして追加してやる例です。省略の多いコードですがまあわかるでしょう。

```javascript
import * as Video from 'twilio-video';
import * as Tone from 'tone';

const micAudio = new Tone.UserMedia(); // Tone.jsのgetUserMedia
await micAudio.open().then(() => {
  // ピッチシフターで声の高さを変えます
  const shifter = new Tone.PitchShift(7);
  const effectedDest = Tone.context.createMediaStreamDestination();
  micAudio.connect(shifter);
  shifter.connect(effectedDest);
  const effectedTrack = effectedDest.stream.getAudioTracks()[0];

  // LocalTrackを作成してRoomに接続します
  Video.createLocalTracks({
    audio: true,
    video: true,
  }).then((localTracks) => {
    localTracks.push(effectedTrack); // エフェクトがかかったtrackを追加
    Video.connect(token, {
      tracks: localTracks,
    })
  }).catch(...省略)
}).catch(...省略)
```

これで凶悪犯の住んでいた地域の住民がテレビで匿名でインタビューを受けるような音声になります。Tone.jsには他にもいろいろなエフェクトが用意されているので、試してみてください。

# バーチャル背景

うん。

いろいろ書いたんだ。

でも

[ここ](https://www.twilio.com/blog/introducing-virtual-backgrounds-browser-based-video-applications-jp)を読んだ方が早いよ。ちゃんと検索すればよかったよ。
MutableStateの3通りの宣言方法とその使い分けを考える

Jetpack ComposeのComposable内でMutableStateを宣言する場合、大きく3通りの記述方法があります。

```kotlin
val mutableState = remember { mutableStateOf(default) }
var value by remember { mutableStateOf(default) }
val (value, setValue) = remember { mutableStateOf(default) }
```
https://developer.android.com/jetpack/compose/state#state-in-composables

公式ドキュメントによれば「機能は同じだから状況に応じて読みやすいものを使ってね」とのことですが、実際のところ、どう使い分けるべきでしょうか？

# 結論
- 基本的にはdelegated propertiesを使うのが良さそう
  - `var value by remember { mutableStateOf(default) }`
- state hoisting等でsetterを引数に渡したいときはdestructuring declarationsを使う
  - `val (value, setValue) = remember { mutableStateOf(default) }`

# 考察

まず、用途が似ているのは次の2つだと思います。

```kotlin
val mutableState = remember { mutableStateOf(default) }
var value by remember { mutableStateOf(default) }
```
記法としては前者が`.value`によってアクセスする一方、後者はシンプルです。

```kotlin
// Read
println(mutableState.value)
println(value)

// Mutation
mutableState.value = someValue
value = someValue
```

従って、基本的にはdelegated propertiesを使うのが良いでしょう。
Composeの公式サンプルでも基本的にはdelegated propertiesを使用しているようです。

https://github.com/android/compose-samples/blob/d38047520c00d5eed71eb731b1fa5ecd99f59a32/JetNews/app/src/main/java/com/example/jetnews/ui/home/PostCards.kt#L136

https://github.com/android/compose-samples/blob/fd91e3af7efd75afe8153c043b3c666e3be41036/Jetsurvey/app/src/main/java/com/example/compose/jetsurvey/signinsignup/WelcomeScreen.kt#L63

前者はいつ使うのか？という話ですが、valueではなくオブジェクトそのもの（State/MutableState)にアクセスしたい場合には前者の記法になりそうです。

次に`setValue`を同時に宣言するパターンです。

```kotlin
val (value, setValue) = remember { mutableStateOf(default) }
```

明らかな違いは`setValue`が変数として宣言されている点です。
これは他のComposableに実引数として渡すときに便利です。

```kotlin
val (value, onValueChanged) = remember { mutableStateOf(default) }
SomeComposable(value, onValueChanged)
```

これはstate hoistingの際に使うことが多そうです。公式サンプルでもそういったユースケースで使われています。

https://github.com/android/compose-samples/blob/e6994123804b976083fa937d3f5bf926da4facc5/Owl/app/src/main/java/com/example/owl/ui/courses/SearchCourses.kt#L58

https://github.com/android/compose-samples/blob/e6994123804b976083fa937d3f5bf926da4facc5/Owl/app/src/main/java/com/example/owl/ui/onboarding/Onboarding.kt#L209

# その他： なぜ3通りの書き方で動くのか？

`var value by remember { mutableStateOf(default) }`
はKotlinのdelegated propertiesによって実現されています。

https://kotlinlang.org/docs/delegated-properties.html

内部的には`State<T>.getValue`と`MutableState<T>.setValue`を実行しています。従って次のimport文が必要になるわけですね。

```kotlin
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
```

そして、
`val (value, setValue) = remember { mutableStateOf(default) }`
はKotlinのdestructuring declarationsによって実現されています。

https://kotlinlang.org/docs/destructuring-declarations.html

実際にMutableStateの定義を確認すると、`component1`及び`component2`が確認できると思います。

```kotlin
@Stable
interface MutableState<T> : State<T> {
    override var value: T
    operator fun component1(): T
    operator fun component2(): (T) -> Unit
}
```
CS50 filter RGBTRIPLE notation

## 概要
[CS50 week4 problemset4 Filter (less comfortable)](https://cs50.jp/x/2021/week4/problem-set/filter-less-comfortable/)にて、以下構文の**左辺**の理解に苦しんだ。　

```
RGBTRIPLE (*image)[width] = calloc(height, width * sizeof(RGBTRIPLE));
```
この表記法は講義では説明されなかったので、ネットで検索していても混乱している人も多い印象を受けた。
同じように迷った人がいる場合の手助けとなれば嬉しい。

## RGBTRIPLEとは
赤、緑、青の相対的な強さで構成される色を表す**構造体**。

```
typedef uint8_t  BYTE; // 8ビットの符号なし整数型

typedef struct
{
    BYTE  rgbtBlue; //青色の強度
    BYTE  rgbtGreen; //緑色の強度
    BYTE  rgbtRed; //赤色の強度
} __attribute__((__packed__))
RGBTRIPLE;
```

## 右辺について

```
calloc(height, width * sizeof(RGBTRIPLE));
```
C言語の**calloc関数**とは、**ヒープメモリに対し、指定したバイト数のメモリを指定個数分確保し、そのメモリブロックを0にクリアする関数**である。

**■calloc関数の書式**

```
calloc(確保するメモリの個数, 確保するメモリ1つあたりのバイト数)
```

**■calloc関数の戻り値**
成功時 : 確保したメモリblockのポインタ
失敗時:NULL

**■calloc関数とmalloc関数の違い**
これら2つの関数の本質的な違いは、**確保したメモリ領域に格納される値**。

**malloc関数**で確保した領域の値は**不定**である。
一般に、malloc関数を呼び出す前にそのメモリ領域に格納されていた値がそのまま残る。

それに対して**calloc関数**では、確保したメモリ領域の**全ビットがゼロにクリア**される。

## 左辺について
結論を言うと、左辺は<font color="FireBrick">**「RGBTRIPLE型のwidth個の要素を持つ配列」へのポインターimageを宣言して、右辺で初期化**</font>しているといえる。

簡単に言うと、imageは**配列へのポインター**だ。

```
RGBTRIPLE (*image)[width] = ...
```

これだけだと「ん？」と思われるかもしれない。
2日間探して「ベストアンサー」だと思った記事に出会えたので、引用しながら噛み砕いていく。

## (引用)配列へのポインターの書き方
**■参考記事**
https://atmarkit.itmedia.co.jp/ait/articles/1208/08/news133.html

以下、引用です。

配列へのポインターはどのように書くのでしょうか。
例えば、次のように書いたら、変数pの型はどうなるでしょうか。

```
int ary[] = { 1, 2, 3 };
int (*p)[3] = &ary;
```
これは、**「int型の3つの要素を持つ配列」へのポインターpを宣言して、aryで初期化**しています。

とはいえ、慣れないうちは読みづらいと思いますので、1つずつ追いながら読んでみます。

まず右側です。
&ary は配列 ary のアドレスになります。
ary の型はint型の3つの要素を持つ配列ですので、int [3] となります。

このアドレスですから、**&ary の型はint (*)[3]**となります。

なぜ * を()で囲う必要があるかというと、int *[3] では「int *型の要素を持つ3つの配列」という別の意味になってしまうからです。

次に左側を見てみましょう。
まず注目すべきは、p という識別子です。
pの型を見るには、近いところにある記号から見ていきます。

pの最も近くにあるのは()内にある * です。
型の中に出てくる * はポインターを表しますから、p は何かを参照するポインターであることがわかります。

ここで () 内を外してみると、int [3] になります。

これはint型の要素を3つもつ配列です。
これらをまとめて読むと、p は「int型の要素を3つもつ配列」へのポインターであることがわかります。

つまり、型の一部を取り除くと、取り除いた部分の型が残るのです。

また、左側から識別子pを取り払ってみると、int (*)[3]になります。

これは、**右側の型 int (*)[3]と同じ**です。
まずは識別子を取り除くだけでも、どんな型になるかわかりやすくなります。

このことを覚えておくと、見慣れない型に出会っても、落ち着いて対処できるはずです。

## 結論
先程結論は述べたが、改めて。
上記の引用の理由から、左辺は<font color="FireBrick">**「RGBTRIPLE型のwidth個の要素を持つ配列」へのポインターimageを宣言して、右辺で初期化**</font>していると言えます！

```
RGBTRIPLE (*image)[width] = ...
```
新人エンジニアが成長するために意識した方がいいこと

はじめまして。この記事を書いている私は、入社4ヶ月目のエンジニアです。
エンジニアになる前は全然パソコンも使わない仕事をしていたので、完全未経験の状態でエンジニアに転職しました。
いまだに上司や同僚の方にサポートをしてもらったり、迷惑をかけながら仕事をしている状態なのであまり偉そうなことが言える立場ではありません。
が、この4ヶ月を振り返って『もっとここ意識して生活してたら成長できたな〜』と思うことがいくつかあるので、今後入社してくる後輩と初心を忘れかけた自分のために記事に残します。

#①学習する時は自分で成果物を作る
プログラミングの学習をする際は絶対に何か形として残る成果物を作った方がいいです。
勉強し始めは特にわからないことだらけで、ある程度理解できてから手を動かしたくなると思いますが手を動かさない限りプログラミングが身につくことはありません。
記事や本を読んで理解したつもりになっていても、実際にコーディングしてみると99％思い通りに動くことはないので早めに1回失敗して、なぜ失敗したのかを調べるのが結局1番の近道です。

あと最近流行りのハンズオンで手を動かして成果物を作りながら学習していく教材も、動画や本に書いてある通りに完コピするだけだとほぼ確実に身につきません。
コードを色々いじってみて自分なりのカスタマイズを加えながら学習するのがいいと思います。

#②質問するまでの条件を決める
壁にぶち当たった時にすぐに質問してしまうと相手の時間を奪ってしまいますし、自分で考え調べて解決する力が身につきません。
しかしあまりに1つの課題に時間をかけすぎるのも効率が悪くなってしまいます。
そこで質問するまでの条件(時間)をあらかじめ決めておくと便利です。

例えば『30分自分で色々調べてそれでもどうしようもなかったら聞く』と決めておけば、時間を浪費しすぎることもなく調べる力も育ちやすいです。
さらに質問する時は困っていることの内容やそれまでの経緯、自分で調べた情報などを簡単に整理して伝えると答える側もわかりやすくなります。
質問するとしても、できるだけ答える人の時間と思考を浪費させないよう意識しましょう。

#③流行りの技術に惑わされない
エンジニアとして仕事をしているとどうしても流行りの言語や技術の話題が耳に入ってきます。
その度に流れに乗り遅れまいと新しい技術に飛びついてしまうとどれも中途半端に身について、結局時間を浪費してしまいます。

高度なフレームワークやツールは目まぐるしく入れ替わりますが、HTML・CSSやWebに関する知識などの基礎の情報はあまり変わらず1度身につければ長く役立てることができるので、特に学ばなければいけないことが多い新人のうちは高度な流行りの技術に惑わされず、しっかりと基礎を身につける学習に集中するのがおすすめです。

#④出来ないことよりも、出来るようになったことに目を向ける
新人のうちはできないこと分からないことばかりで自己肯定感が下がりがちです。
仕事で失敗したり、いくら調べても情報が出て来ず課題がクリアできない時は『自分はエンジニアに向いてないんじゃないか』と思うこともあります。
1つ何か言語を勉強してやっと少し理解できたと思ったら、その先にある膨大な量の知らない知識に気づきむしろモチベーションが下がってしまうこともよくあることです。

そんな時は一度落ち着いて自分ができるようになったことを整理してみましょう。
エンジニアになった頃の自分や先月の自分と比べて少しでも出来るようになったことを意識することで、前向きに学習に取り組むことができます。

#⑤自分の時間を使って学習する
エンジニアとして仕事をすると決めた以上、プライベートの時間を犠牲にして学習をすることは必須です。
業務の中で新しい言語や知識を学ぶこともありますが、成果を出すことが大前提なのでゆっくり理解できるまで調べるのは難しく、コピー＆ペーストでなんとか動かすだけで精一杯ということが多いです。

業務の中で分からなかった部分や気になったことを、自分の時間を使って学習し成長することができないといつまで経っても知識が身に付かずエンジニアとして成長するのが難しくなってしまいます。
最初のうちは特にしんどいですが、出来ることが増えてくると仕事そのものが楽しく出来るようになってくるはずなので、頑張りどころだと思って自分の時間に勉強するようにしましょう。

#まとめ
今回の記事は完全に過去の自分に向けて書いた内容なので、当てはまらない新人の方もいらっしゃるかと思いますがご容赦ください。
エンジニアになってから半年の間が特に自信をなくして辞めてしまいやすい期間だそうなので、まずはあと2ヶ月自己肯定感を高く持ってコツコツ頑張っていきたいと思います。
自分が新人エンジニアだった時は〇〇を意識してたよ〜とか〇〇がしんどかったよ〜といったエピソードがあればぜひ教えてください。
Drupal専用WAFで安らかなホリデーを手に入れる


ハッピーホリデー！
この記事は[Drupal Advent Calendar 2021](https://qiita.com/advent-calendar/2021/drupal)、14日目の記事です。
[Drupal Meetup Tokyo](https://drupal-tokyo.connpass.com/) の中の人の一人です。

## なぜ書いたか

しばらく前からウォッチしてたけど今年、2021年7月1日から**誰でもお金を払えば**利用できるようになった！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">&quot;Drupal Steward&quot; は物議をかもすなぁ</p>&mdash; snize (@snize) <a href="https://twitter.com/snize/status/1116162040106668032?ref_src=twsrc%5Etfw">April 11, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">セキュリティパッチがリリースされる前にファイアーウォールのルールを提供するってことかな。<br>大手のDrupalホスティングプロバイダだけでなく、小さな・あるいはセルフホスティングでも利用できるようにするのかな。うまくいけばいいな。<br>これ今回のDrupalConでは僕的にかなり目玉</p>&mdash; snize (@snize) <a href="https://twitter.com/snize/status/1116163804495093760?ref_src=twsrc%5Etfw">April 11, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## Drupal Stewardとはなにか？

Drupal StewardはDrupal Security TeamとDrupal Associationが提供するWebアプリケーションファイアウォールでありセキュリティーリリースが公開されてから、運用中のDrupalにパッチが適用するまでの時間差を埋めるためのものである。

## Drupalの保守をやってた頃のつらい思い出

お仕事としてDrupalの保守を担当していたころの話として結構つらかった、例えばこんな感じで

1. タイムゾーンの問題でセキュリティパッチの提供は日本時間の深夜から早朝にかけて
2. アメリカとかのDrupalの会社のTwitterでピザ食べながら待機みたいのを尻目にひたすら待つ
3. 眠気と闘いながらひとり寂しくリリースを待ちパッチを当てる
4. 朝が来て通常業務が開始する（昼寝するけど）

[セキュリティのリスク評価](https://www.drupal.org/drupal-security-team/security-risk-levels-defined)が **Highly Critical** とかだと数日前にパッチのリリースと時間帯だけ発表されるので気が重かった。

## 他のWAFとどう違うか？

たぶん仕組みとかはそれほど違わないけど、コミュニティなどから脆弱性の報告を受けたり修正対応するDrupal Security Teamが提供されるのが安心ポイントだと思う。

## 費用

月15ドルからの従量制で以下のリンクからアクセス数を入力することで概算が出せる

[https://www.drupal.org/steward#:~:text=renewed with LetsEncrypt.-,Pricing Estimator,-Number of domains](https://www.drupal.org/steward#:~:text=renewed%20with%20LetsEncrypt.-,Pricing%20Estimator,-Number%20of%20domains)

## 最後に

業務で使う分には高くない気がするし、だれか使ったらレビューして教えてください。
他のOSSのCMSに比べて、セキュリティ周りがしっかりしてるのもDrupalのアピールポイントかと思うのでこのDrupal Stewardでさらに良いものになると思います。

## リンク

- [https://www.drupal.org/steward](https://www.drupal.org/steward)
- [https://www.drupal.org/association/blog/drupal-stewards-first-activation-report](https://www.drupal.org/association/blog/drupal-stewards-first-activation-report)
- [https://www.drupal.org/drupalorg/blog/drupal-steward-now-available-to-all](https://www.drupal.org/drupalorg/blog/drupal-steward-now-available-to-all)
- [https://www.drupal.org/drupal-security-team/steward/faq](https://www.drupal.org/drupal-security-team/steward/faq)
Riverpod, StateNotifier, freezedの簡単な説明

[**Flutter Advent Calendar 2021**](https://qiita.com/advent-calendar/2021/flutter) **11日目**の記事です！

私は最近からFlutter開発に携わりました。
UI開発に慣れてきたものの、API周り、状態管理などの知見は浅々の浅です。
自分の学習用として、この記事を書きます。
どなたかにとっても有益な記事となることを切に願っております。

# [Riverpod](https://riverpod.dev/docs/getting_started/) とは何か
[note](https://note.com/mxiskw/n/n5c06bc2dd0d5)では神パッケージとされていました。
その中から、なるほどとなった特徴をピックアップします。

- **Flutterの状態管理パッケージであること**
    - value, flagを元にUIを作る仕組み = 状態を持つということ
    - アプリの状態 = 多様なvalue, flag
    - その状態を扱いやすく管理する仕組み = 状態管理
- **providerの改良版**
    - 機能
        - 親Widget→子Widgetのデータ受け渡しが可能
            - 親側: Provider<T>.value()
            - 子側: Provider.of<T>()
- **complie-safe**
    - ProviderNotFoundExceptionというランタイムエラーが起こらない
        - 状態にProviderで囲った配下のWidgetツリー以外からアクセスすると発生するエラー
- **実装の縛りが減った**
    - 同じ型で、複数の Provider を使用可能
    - 使われなくなった状態を自動で破棄 (dispose)
    - computed states を実装可能
    - Provider を private スコープで宣言可能
- **Dart言語のみを使っているので、Flutter に依存しない**
- **Providerのグローバル定義が可能**

サンプルコード

```dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

void main() {
 runApp(ProviderScope(child: MyApp()));
}

final counterProvider = StateProvider<int>((ref) => 0);

class MyApp extends HookConsumerWidget {
 @override
 Widget build(BuildContext context, WidgetRef ref) {
   final int count = ref.watch(counterProvider);
   return MaterialApp(
     home: Scaffold(
       body: Center(child: Text('$count')),
       floatingActionButton: FloatingActionButton(
         onPressed: () {
           ref.read(counterProvider.notifier).state++;
         },
       ),
     ),
   );
 }
}
```

# StateNotifier とは何か

- 状態の変更をリスナーに通知するために使う
- notifylisteners関数の改良版
    - 状態が変更される度にcallしなければならなかった
- 単一Stateを保持
    - 複数のStateを保持したい場合はオブジェクトを作成

サンプルコード

```dart
class CounterStateNotifier extends StateNotifier<int> {
  CounterStateNotifier(): super(0);

  void increment() {
    state++;
  }
}
```

# freezed とは何か

- StateNotifierで利用するState用のクラスをimmutableにした時の冗長さを解消するもの
  - immutable = 不変

サンプルコード（freezed使用なし）

```dart
@immutable
class CounterState {
  CounterState({
    this.count = 0,
    this.isEnabled = true,
  });
  final int count;
  final bool isEnabled;
}

// 変更時
class CounterStateNotifier extends StateNotifier<CounterState> {
  CounterStateNotifier(): super(CounterStateNotifier());
  void increment() {
    state = CounterState(
      count: state.count + 1,
      isEnabled: state.isEnabled,
    );
  }
  void disableCounter() {
    state = CounterState(
      count: state.count,
      isEnabled: false,
    );
  }
}
```

サンプルコード（freezed使用あり）

```dart
@freezed
class CounterState with $_CounterState {
  factory CounterState({
    int? count,
    bool? isEnabled,
  }) = _CounterState;
}

// 変更時
class CounterStateNotifier extends StateNotifier<CounterState> {
  CounterStateNotifier(): super(CounterState(count: 0, isEnabled: true));
  void increment() {
    state = state.copyWith(count: state.count + 1);
  }
  void disableCounter() {
    state = state.copyWith(isEnabled: false);
  }
}
```
[Raspberry pi] IPアドレスの固定

#IPアドレスを固定する。
IPアドレスとはネットワーク上の固有の番号である。
番号を通して，PC同士での情報交換が可能となる。
機器をネットワークに接続する際に，その機器に対するIPアドレスが自動に割り振られる。
ラズパイをネットに再接続するとIPアドレスが変わってしまう。


以下，Raspberry piで操作を行う。



#準備
①LXTerminalからRaspberry piのIPアドレスを調べる。
```ifconfing```
wlan0のinetの部分にRaspberry piのIPアドレスが記載されている。

②Router とDNS Serversの値を調べる。
```route -n```
"ゲートウェイ"の下に、デフォルトゲートウェイのIPアドレスが表示されている

③ローカルで使われいないIPアドレスを探す
```ping 192.168.11.12```
※192.168.11.12には自身の環境のIPアドレスに最後の.以下の数値を入れ替えて使用
time=0.11など出れば，使用中のIPアドレス
Unreachableと出れば，現在未使用のIPアドレス

#Raspberry piのIPアドレスの変更
①デスクトップ右上のwifiマークを右クリック
②wireless &Wired Network Settingを選択
③Configure：interface wlan0を選択
④IPアドレス, Router, DNS Serversの入力
IPv4 Addressに　新しいIPアドレス＋/24
※新しいIPアドレスは最後の.以下の数値を変更する
Router とDNS ServersにデフォルトゲートウェイのIPアドレスを入れる
⑤適応ボタンを押す
⑥再起動する

#一言
設定を変えたときには，再起動しよう

##参考
https://python-academia.com/raspberrypi-static-ipaddress/
デプロイデプロイデプロイデプロイ出来ない出来ない出来ない出来た！

#いやーデプロイにまた時間を取られましたが解決出来たので


今回のエラー

```ruby:qiita.rb

$ git push heroku
remote:  !   Failed to install gems via Bundler.
              （Bundler経由でgemをインストールできませんでした。）

remote:  !   Push rejected, failed to compile Ruby app.
           （プッシュが拒否され、Rubyアプリのコンパイルに失敗しました。）

remote:  ! ## Warning - The same version of this code has already been built: 
          （##警告-このコードの同じバージョンがすでにビルドされています：）

remote:  !   This article goes into details on the behavior:
            (この記事では、動作について詳しく説明します。)

remote:  !     https://devcenter.heroku.com/articles/duplicate-build-version
```
こんな感じで丁寧に説明されたので、上記の記事を読みながら進めていきました。


初めに、Gemfile.look内のBUNDLE WITHのバージョンと```$ bundler -v```を叩いた時に出るバージョンは同じか確かめる
これ結構重要です

同じでしたか？

次に、```$ git status```を叩いてmodified: （変更）があるか確認します
あれば、$ git add -A

もう一度$ git statusを叩き、modified: （変更）になっているか確認
```$ git commit -m “code”```を叩く

```$ git push```をして、Bitbucket（GitHub）へぶち込みます
さあリベンジだ…！


```$ git push heroku```


無事 Build succeeded！

herokuにデプロイ完了。

参考にした記事（上記のエラーに書いてあるurlです）
https://devcenter.heroku.com/articles/duplicate-build-version
[Laravel]例外処理時のログは汚したくない

## 背景

- 入社当初、例外処理の知識が薄い時に、こんなコードを書いた
    - エラーメッセージはユーザー向けに書いたつもりだった

```php
class LogController extends Controller
{
    public function index()
    {
				...
        try {
						...
            // エラー発生した時の処理
            throw new Exception('ユーザーは取得できませんでした。');
        } catch(Exception $e) {
            Log::error($e);
            throw $e;
        }
    }
}
```

- これで例外投げたときのブラウザはこう👇

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/780929/c29e4e5d-c068-cf0b-bc7e-b3d02551e716.png)


- そして、laravel.logはこう👇

```php
[2021-12-11 07:11:54] local.ERROR: ユーザーは取得できませんでした。 {"exception":"[object] (Exception(code: 0): ユーザーは取得できませんでした。 at C:\\xampp\\htdocs\\...\\LogController.php:17)
[stacktrace]
...
...
```

- これに対して、レビュワーさんからコメント

> 「例外処理の使い方見直して、修正お願いします。」

- 何が正しいんだ？と（本気で）思って自分で調べたり、質問したりして納得したのですが、そこからちゃんとログを見直すことになったな、と振り返り初心に帰りアウトプット

## 内容

まずは、問題点が2点。

1. **例外時に開発者向けのブラウザ表示は見せちゃダメ**
2. **この書き方ではログが汚れるのでダメ**

- まず、1についてはそりゃそうだ、ということで割愛します。
    - そもそも、「例外処理」というものは開発者向け、ユーザー向けのメッセージを出すものではない、という当たり前が頭に入っていなかったわけです…
    - ※当時は入社当初なので多めにお手柔らかにお願いします。。。

- そして、**本題は2**
- **「ログが汚れる」**とはどういうことか。
    - laravel.logで確認

👇before：先ほどのコードによるログ（再掲）

```php
[2021-12-11 07:11:54] local.ERROR: ユーザーは取得できませんでした。 {"exception":"[object] (Exception(code: 0): ユーザーは取得できませんでした。 at C:\\xampp\\htdocs\\...\\LogController.php:17)
[stacktrace]
...
...
```

- どういうことかというと
- 例外処理は**あくまで開発者向けに作られたもの**であるという大前提
- つまり、**ログに出すメッセージは「開発者に関係ないことは出力しない」**のが正しい
  - この前提に立つと、ここでログにでている「ユーザーは取得できませんでした。」はユーザー向けのメッセージであり開発者が読むには、ちと邪魔になる
    - この読みづらさを「汚している」と表現した、ということ
    - 開発者としては、運用時のシステム障害時にもっと具体的な詳細が欲しいところ
        - 今回であれば取得できないユーザーのID情報などが欲しい、など
- ということで以下のコードに書き変えた

👇after：修正版

```php
class LogController extends Controller
{
    public function index()
    {
        try {
            // エラー発生した時の処理
            throw new Exception();
        } catch(Exception $e) {
            Log::error($e);
            return redirect()->route('log.index')
				// セッションにerrorというキーでメッセージを渡し、遷移先でエラーメッセージを出力
                ->withErrors(['error'=>'ユーザー情報が取得できませんでした']);
        }
    }
}
```

- 再びlaravel.logを確認すると

```php
[2021-12-11 07:40:41] local.ERROR: Exception in C:\xampp\htdocs\basic_laravel\app\Http\Controllers\LogController.php:17
Stack trace:
```

- おお、最低限のログしか残らず（「ユーザーは取得できませんでした。」）、ログを汚さなくなった！

## 所見

- 当時は新規プロジェクトの開発しかやっておらず運用経験がないので、ログを見るという習慣があまりなかった
    - 「ログがどうなっているか」という点はあまり気にしたことなかったですね
    - Laravelであれば、ブラウザ上のエラーメッセージやデバッグバーでエラーの内容は大体わかるので、laravel.logを見ることはあまりない、、、

- ただここからは自戒。
- そもそも、自分で`Log::`を実装しているなら、自分で意図したLogが出力されるかはちゃんと確認しろよ…と我ながら思いました…
    - 自戒になりますが、**「新規開発であってもちゃんとログは見よう」**
    - もっと言うと**「自分の書いたコードには責任を持とう。」**
- 内容自体は非常に当たり前で薄いものですが、個人的に上の２つの教訓を日々の開発の中で習慣化できたきっかけだったので、記事にしました！

最後までお読みいただきありがとうございました！
Python mupltiprocessing 勉強してみた

# 初めに

並列処理について以下のドキュメントを参考に勉強してみました。
https://docs.python.org/ja/3/library/multiprocessing.html

# 並列処理と通常の処理の違い

まずは以下のコードを実行してみます。

```python
from multiprocessing import Pool

def f(x):
    return x * x

if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))
```

実行結果

```
[1, 4, 9]
```

これは以下のコードの処理と何が違うだろうと思いました。

```python
def f(x):
    return x * x

if __name__ == '__main__':
    print(list(map(f, [1, 2, 3])))
```

そこで以下のようにプリントログを書いてみました。

```python:multi.py
from multiprocessing import Pool
import time

def f(x):
    print('f is called.')
    print('time sleep 3 seconds...')
    for i in range(1, 4):
        time.sleep(1)
        print(f'--- {i} ---')
    return x * x

if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))
    print('end')
```

実行結果

```
f is called.
wait on 3 seconds...
f is called.
wait on 3 seconds...
f is called.
wait on 3 seconds...
--- 1 ---
--- 1 ---
--- 1 ---
--- 2 ---
--- 2 ---
--- 2 ---
--- 3 ---
--- 3 ---
--- 3 ---
[1, 4, 9]
```

3 秒間待機する処理が並列で動いています。つまり関数の実行が並列化されていました。

一方で `multiprocessing` を使用しないでプリントログを見てみました。

```python:no_multi.py
import time

def f(x):
    print('f is called.')
    print('wait on 3 seconds...')
    for i in range(1, 4):
        time.sleep(1)
        print(f'--- {i} ---')
    return x * x

if __name__ == '__main__':
    print(list(map(f, [1, 2, 3])))
```

実行結果

```
f is called.
wait on 3 seconds...
--- 1 ---
--- 2 ---
--- 3 ---
f is called.
wait on 3 seconds...
--- 1 ---
--- 2 ---
--- 3 ---
f is called.
wait on 3 seconds...
--- 1 ---
--- 2 ---
--- 3 ---
[1, 4, 9]
```

上記の出力の通り、合計 9 秒待機時間が発生しました。リストの各要素に対して、一つずつ関数が呼ばれています。

# ワーカープロセス数

並列処理のコードで気になったのが、`Pool(5)` の **5** です。なんの数字なのでしょうか。ドキュメントには以下のように記載されています。

> processes は使用するワーカープロセスの数です。

プロセス数を変えて実行してみます。**2** だとどうなるのでしょうか。

```python:multi_num_2.py
from multiprocessing import Pool
import time

def f(x):
    print('f is called.')
    print('wait on 3 seconds...')
    for i in range(1, 4):
        time.sleep(1)
        print(f'--- {i} ---')
    return x * x

if __name__ == '__main__':
    with Pool(processes=2) as p:
        print(p.map(f, [1, 2, 3]))
```

実行結果

```
f is called.
wait on 3 seconds...
f is called.
wait on 3 seconds...
--- 1 ---
--- 1 ---
--- 2 ---
--- 2 ---
--- 3 ---
f is called.
wait on 3 seconds...
--- 3 ---
--- 1 ---
--- 2 ---
--- 3 ---
[1, 4, 9]
```

関数 `f` が 2 つ並列に動いています。1 つ目が終了した後、3 回目の処理が実行されていました。つまりワーカープロセス数とは、いくつ処理を並列で走らせるか、という数のようです。

# まとめ

以下の点について調べました。

- 並列処理と通常の処理の違い
- ワーカープロセス数の意味

# 参考記事

https://docs.python.org/ja/3/library/multiprocessing.html#multiprocessing.pool.Pool
OutSystems Neo のマイクロサービスアーキテクチャ

先日(２０２１年１１月)、OutSystems は マイクロサービスアーキテクチャとクライドネイティブアーキテクチャをキーワードに、Project Neo を発表しました。本記事では、マイクロサービスアーキテクチャについて、少し解説してみたいと思います。

私は OutSystems インサイダーですが、本記事は OutSystems の公式文書ではなく、私の個人的な意見が含まれています。執筆時点で GA (製品化)はまだ先で、変更になる可能性があります。

#何がマイクロサービス化されたのか

開発者にとって一番影響のある個所は、”アプリケーション”がマイクロサービスになったということになるでしょう。"アプリケーション" とは、OutSystems Neo で開発をするときに定義するワークスペースの名前です。OutSystems 11 までは、モジュール、あるいは eSpace と呼ばれていました。

![Project Neo micro service.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348467/ad105262-e0a7-302f-aa69-3b1f119bdfe3.png)

同じコンテナにデプロイされるようなタイプのライブラリのようなものもでてくると思いますが、基本は、アプリケーションごとにリソースが割り当てられ、それぞれ独立して管理されることになります。

#マイクロサービス化が意味するもの

実行時のリソースのコントロールは、かなりやりやすいものになりました。原則システムリソースがアプリ別に分離され、それぞれがオートスケールできるであろうことが、容易に想像できます。

設計・開発時の恩恵もかなりあるでしょう。OutSystems 11 にも、マイクロサービスを定義する機能は備わっていますが、マイクロサービスにするには使っていけない機能や、Zone、複数環境を用意するなど、他にも様々検討要素がありました。Neo では、"アプリケーション" で作れば、マイクロサービスに必ずなるというのは、大きな違いです。

一方でマイクロサービスアーキテクチャでシステムを設計しないと、これらの恩恵にはあずかれないことは理解する必要があるでしょう。疎結合アーキテクチャを理解し、設計できない場合は、１つの "アプリケーション" にすべて機能を盛り込んでしまうモノリシックアプリケーションとなり、結局大きな箱の中で、すべてを動かす旧来通りのシステムになるはずです。

ただ、マイクロサービスアーキテクチャに自信のない方からみて、Neo は難易度が高いものだと思う必要はありません。旧来通りに作れるとも言えるわけです。恐れる必要はありません。むしろ、Neo を通じてマイクロサービスアーキテクチャを習得することで、エンタープライズアーキテクトへの近道を辿ることになるはずです。
【Azure】Application Gateway と Key Vault を統合したら直接アップロードのSSL証明書の更新が失敗するようになった

Application Gateway で TLS終端をする際、SSL証明書を Application Gateway にインポートする方法が２通りあります。

* SSL証明書のファイルをローカル端末から直接アップロードする
* 既存の Key Vault の証明書を参照するように指定する（本記事では「Key Vault 統合」と呼ぶことにします）

https://docs.microsoft.com/ja-jp/azure/application-gateway/key-vault-certs

今回、Key Vault 統合を行ったあと、直接アップロードのSSL証明書を Azure Portal から更新しようとしたところ、「関連付けられた KeyVault シークレットのアクセスと検証中に問題が発生しました。」というエラーが出て失敗しました。
Key Vault とは関係ないSSL証明書の更新でしたが、なぜかうまくいかないようです。
おそらくバグだと思われます。
https://github.com/MicrosoftDocs/azure-docs/issues/33157

今回の対処法としては、登録しただけで使用していなかった Kwy Vault 統合の証明書を削除することで解決しました。
Azure Portal からでは Application Gateway 内の証明書を削除できないようですが、 Azure CLI 等を使うことで削除できます。

```ApplicationGatewayの証明書を削除するコマンド例.sh
# Azure AD サインイン
az login

# 現在のサブスクリプション確認
az account show -o table

# 操作できるサブスクリプション一覧確認
az account list -o table

# サブスクリプションのセット
az account set -s {your-subscription}
az account show -o table

# アプリケーションゲートウェイに登録されている証明書一覧確認
appgwName="{your-ApplicationGateway}"
appgwResgp="{your-ResourceGroup}"
az network application-gateway ssl-cert list -g $appgwResgp --gateway-name $appgwName

# Key Vault 統合のSSL証明書削除
deleteCert="{削除するKeyVault統合の証明書名}"
az network application-gateway ssl-cert delete -g $appgwResgp --gateway-name $appgwName -n $deleteCert
az network application-gateway ssl-cert list -g $appgwResgp --gateway-name $appgwName
```

ちなみに、更新対象が Key Vault 統合の証明書であれば、 Azure Portal から問題なく更新できるようです。

### 参考
* [az network application-gateway ssl-cert](https://docs.microsoft.com/en-us/cli/azure/network/application-gateway/ssl-cert?view=azure-cli-latest)
『TMS WebCOREを使用しています』から１年経過しました。

フロントエンド開発として、RESTfulを扱うのも、少し慣れてきました。(現状は、従来の２層の開発+メンテも並行しい続けています。)
#####今の私が抱えている課題は、RESTfulのバックエンド側の構築ツールの選択です。
選択条件としては、データベースを変更(デーブル構造など..)した場合に、コードの変更箇所が少なく再現できるものを使用したい。(理由は長期間そのコードに触らない場合でも、メンテナンスが容易なもの使いたい為)
***
いま、新たに選択するとなると、RESTful API作成のツールの選択肢が非常に多いと感じています(私の知識不足で、適切な判断ができていない......)

######TMSさんでは all-accessで、xdataという製品が使用できます。
######言語では
　Java
　PHP
　Python FastAPI
　Python Django 
　Node.js + Express
　Go言語
　GraphQL　など
######変則的なもので、PostgreSQLが限定となりますが
　PostgREST (https://postgrest.org/en/v9.0/)
######CMSなどを使用するもの
　WP REST API (WordPress の REST API)
　concrete5 8.以降で　REST API がサポート　など
######有償無償のクラウドサービス
　Kintone
　プリザンター　　など
***
などなど、たぶん、知らないだけで、もっと多くあるのだと思います。

『なにがよいでしょう』の問いに対しては、おそらく『使用する目的により、最適なものは違います』
となってしまうかと思うので、実際に踏み込んで、試せる場があっても、よいか思い、
今回、『異種なプログラミング交流会　オフライン』
https://ishuprog.connpass.com/event/233617/
というのを2021/12/18土曜日14:00～大阪の本町で、開催します。
***
######今回の交流会で、実施予定としたいものは、バックエンドで作成したデータを、RESTfulAPIのURIとして、フロントエンドから、アクセスするといった内容です。

予定しているバックエンドは　PHP　Yii　で、データベースは　MySQL

```sql
CREATE TABLE test1
(
    id integer NOT NULL ,
    name varchar(20),
    qty  numeric(12,2)
);
```

```sql
INSERT INTO public.test1(id, name, qty) VALUES (1,'AAAA', 1.1);
INSERT INTO public.test1(id, name, qty) VALUES (2,'BBBB', 2.2);
INSERT INTO public.test1(id, name, qty) VALUES (3,'CCCC', 3.3);
INSERT INTO public.test1(id, name, qty) VALUES (4,'DDDD', 4.4);
INSERT INTO public.test1(id, name, qty) VALUES (5,'EEEE', 5.5);
```
このデータを、RESTful API として、　http://xxxxxxx.json などとして作成

これをフロント(クライアント)から

```
GET     http://xxxxxxx.json   
GET     http://xxxxxxx.json/1  
POST    http://xxxxxxx.json/6
PUT     http://xxxxxxx.json/6
DELETE  http://xxxxxxx.json/6
```
のような動作を
PostMan/RestDebugger/curl/TMS WebCOREを使用して(ハンズオン的な感じで)実行する予定です。
***
以下が、別のサンプルデータですが実行したいイメージです。
RestDebugger(サンプルURIのデータ表示)
![a002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88517/387c1c0a-0a6b-0095-77d7-80e09e635e7f.png)
curl(サンプルURIのデータ表示)
![a004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88517/6e43abf9-f136-745d-af2e-1fc3113f5851.png)
Delphi + TMS WebCORE(サンプルURIのデータ表示)
![a001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88517/ce6903a6-0e84-1c67-0eb6-fb7a66ab4584.png)
PostManは、使ったことないので、今回どなたかに教えてもらえると、ウレシイ。
![a003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88517/ac64be5c-774d-8f38-0f2e-0bcde88c2e8b.png)
****
今後は、認証やCORS、フロント開発ツールの比較など、(いままでどらかというと避けていた)その他のWeb開発で必要な知識が増えるような交流会も、参加もしくは実施できればと考えています。
【Ruby のまずいコード】文字列の先頭から n 文字を取得する

# お題

ローカル変数 `str` に文字列が代入されているとして，先頭から高々 10 文字までを `puts` で表示してください。
「高々 10 文字」というのは，`str` が 10 文字に満たないときはすべて表示する，という意味です。

次に，高々 `n` 文字までを同様に表示してください（`n` は正の整数とする）。

話を簡単にするため `str` は改行を含まないと仮定します。

# コード

```rb
puts str[0..9]
```

```rb
puts str[0..(n - 1)]
```

# 改善

10 文字表示させたいのに，配列式の終端に `10` ではなく `9` を指定しなければならない，というのは混乱の元ですね。
変数で与えたときも余計な計算式が必要になって面倒です。
こういう書き方はバグを誘う悪い習慣です。

あるいは `..` の代わりに `...` を使って


```rb
puts str[0...10]
```

```rb
puts str[0...n]
```

と書くこともできますが，もっと素直なのは

```rb
puts str[0, 10]
```

```rb
puts str[0, n]
```

でしょう。
String に対する `[ ]` で，引数[^a]として整数を二個与えたときは，第一引数が開始インデックス，第二引数が長さです。

[^a]: `[ ]` はメソッドであり，その中に書くのはこのメソッドに対する実引数です。

[String#\[\]](https://docs.ruby-lang.org/ja/3.0.0/method/String/i/=5b=5d.html) は多様な使い方ができるメソッドなので，ぜひリンク先の公式リファレンスをご覧ください。
UseRefのように配列を扱う

#はじめに
Reactの`useRef`は、React Hooksで参照するための変数を定義する関数である。ところが、この変数には配列やオブジェクトを入れることができない。`useRef`のように配列を扱うには、`useReducer`を用いる。

# 例

```javascript:sample.js
import React, {useRef, useReducer} from 'react';

// 配列をsomeArray、操作する関数をdispatchとそれぞれ定義。
// useReducerの引数はReducerFunc、初期配列
const [someArray, dispatch] = useReducer(reducerFunc, [])

//reducerFuncが更新後の配列を返す。
function reducerFunc(state, action) {
    if (action.type === "add") {
        return [...state, action.value]
    } else {
        throw `Invalid type:${action.type}`
    }
}

//実際に追加するときは、配列の操作関数であるdispatchにreducerFuncが読めるオブジェクトを渡す。
// この例では文字列"some_value"が配列に追加される。
dispatch({
    type: "add",
    value: "some_value"
}}
```

## 補足
dispatchをpropsで渡すことで、子要素からも配列の値を変更することができる。
Pythonで組み合わせ関数を作る

おはようございます。

本日はpythonで組み合わせ関数を作ってみようと思います。

作り方は3通りあるので、それぞれ作っていきたいと思います。

1つ目はfor文です。

```python:for.py
def combination(n,m):
  value = 1
  for i in range(m):
    value *= (n-i)/(i+1)
  return int(value)
```
最後にint型に直して整数で値を返すようにします。

2つ目はwhile文です。

```python:while.py
def combination(n,m):
  value = 1
  while m > 0:
    value *= n/m
    n -= 1
    m -= 1
  return int(value)
```
こちらも同様にint型に直して整数を返すようにします。

そして3つ目は再帰です。（個人的には一番好きです。）

```python:saiki.py
def combination(n,m):
  if m == 0:
    return 1
  return int(n/m * combination(n-1,m-1))
```
再帰もfor文やwhile文と同様にループのようなものです。
ここでは、m==0になるまで関数を繰り返し呼び出すというプログラムになっています。

以上でpython組み合わせ関数の書き方の説明を終わりたいと思います。
DOBOT公式のROSデモでDobot Magicianを制御する

ROSでDobot Magicianを制御したかったので色々と調べていたところ、公式からROSのデモパッケージが配布されているのを発見したので、ROSの勉強も兼ねて行ってみました。

# 環境
・VMware WorkStation Player
・Ubuntu20.04
・ROS Noetic

# 公式ROSデモパッケージをダウンロード
Ubuntu上で[DOWNLOAD CENTER](https://www.dobot.cc/downloadcenter/dobot-magician.html?sub_cat=72#sub-download)を開き、『ROS Demo for Dobot magician』をダウンロードしてください。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669160/c38440db-4008-6d11-c73c-73705e97070f.png)

その後、ダウンロードしたフォルダを展開し、dobot_wsディレクトリをホームディレクトリに移動させてください。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669160/2787e78c-f054-92bf-3526-ed8d51724c80.png)



# デモパッケージをコンパイル
### 1.シリアルポートの操作権限を一般ユーザに割り当てる
usernameは自身のユーザー名に置き換えてください。

```
$ sudo usermod -a -G dialout username
```

### 2.dobot_wsディレクトリにパーミッションを割り当てる

```
$ cd ~/dobot_ws
$ sudo chmod 777 ./* -R
```

### 3.コンパイルする

```
$ catkin_make
```

<br>dobot_wsディレクトリの中にbuild, devel, srcの3つのディレクトリが作られます。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669160/71a975b8-1cd3-bb75-2195-b00b592c2296.png)

ここまで来たらディレクトリ構造が下記のようになっているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669160/32ccbd78-c9ab-bac7-bc52-3018fd91c747.png)


### 4.dobot_wsの環境変数を追加
```
$ echo "source ~/dobot_ws/devel/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
```

# Dobot Magicianのシリアルポート名を調べる
UbuntuにUSBでDobot Magicianを接続する前と後の2回下記のコマンドを入力し、シリアルポート名を調べます。

```
$ ls /dev -l
```

<br>私の環境では、USBでDobot Magicianを接続すると『ttyUSB0』という項目が増えていました。これがシリアルポート名です。

# デモファイルを実行

### 1.ROSを起動
新しくターミナルを開き、下記のコマンドを入力してください。

```
$ roscore
```

### 2.サーバを立ち上げる
公式のROSデモではサービス通信でDobot Magicianを制御するため、サーバを立ち上げる必要があります。

さらに新しくターミナルを開き、下記のコマンドを入力してください。
ポート名の部分は自分の環境にあったものにしてください。

```
$ rosrun dobot DobotServer /dev/ttyUSB0
```

<br>私の環境では確認できませんでしたが、公式解説書によると間違ったシリアルポートを入力すると文字化けしたコードが表示されるそうです。

### 3.コマンドを実行する
さらに新しくターミナルを開き、下記のコマンドのいずれかを入力すると、Dobot Magicianが動き出します。

```
$ rosrun dobot DobotClient_JOG
$ rosrun dobot DobotClient_PTP
```

# ROSデモパッケージの概要
## 処理の流れについて
このROSデモでは、ROSで一般的によく使われるトピック通信ではなく、サービス通信で制御する構成になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669160/80a1415a-2b9b-2327-b69b-8deb1459c823.png)
~/dobot_ws/src/dobot/srcディレクトリにこれらのC++ファイルがあります。

## JOG（Jogging）モード
JOGモードはエンドエフェクタを指定した方向に一定の速度で動かしたいときに使用します。

```
$ rosrun dobot DobotClient_JOG
```
上記のコマンドにより、JOGモードでDobot Magicianを操作することができます。
このコマンドを実行すると、キーボードの各キーに対応してDobot Magicianを動かすことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669160/3bff8b95-271f-c501-46b6-3f5d6067d36b.png)
注意してほしいのが、このコマンドを実行してキーを押すと、他のキーが入力されるかアームの可動域の限界に達するまで動き続ける点です。
特にIキーでアームを下に下げる場合、やりすぎると台座が浮いて本体ごとひっくり返る恐れがあるので慎重に実行してください。

## TP（Point to Point）モード
PTPモードは指定した座標にエンドエフェクタを移動させたいときに使用します。

```
$ rosrun dobot DobotClient_PTP
```
上記のコマンドにより、PTPモードでDobot Magicianを操作することができます。
こちらは特に操作の必要はなく、自動で(x,y,z,r)=(200,0,0,0)～(x,y,z,r)=(250,0,0,0)を往復し続けます。
止めたい場合はctrl-cを押してしばらく待っていれば止まります。
[WSL]クリーンインストール直後でもgithubに草を生やしたい

## 結論
WSLをクリーンインストールする場合はWSLの機能に依存しない方法を検討すべき

言われてみれば当たり前なんですが、何とか環境構築しようと頭を凝り固めてしまったので、戒めとして記します。

## 発端
- 私はWSLを愛用している
- 頻繁にWSLをリセットする運用をしており、githubに草をはやしていたスクリプトが飛んだ
- 気づいた頃に作り直すも、githubが荒野になっていた

ループ。

つまり「WSLにCron入れて実行すればよくね？」では、WSLをリセットする度に環境構築しなければならないし、そのためShellを使うことはできない[^1]という問題があります。
[^1]: 普段はMacを使うのですが、凝った開発をする時はWindowsを使っているため、このような状態になっています。
そのために、windowsで実行する場合は`bat`、MacやLinuxで実行する場合は`sh`を使う事になります。

## 手順
Windowsだと
1. batを作る
1. タスクスケジューラを設定する（プログラム: batのパス）

Macだと
1. shを作る
1. cronを設定する

どちらも共通して

```
git clone
echo %date / echo $(date "+%Y/%m/%d")
git add～push
del リポジトリ / rm -rf リポジトリ
```

やってる事は同じですが、書き方がbat,shの作法で異なります。

## ハマったポイント
「WSLでcron動かせばよくね？」と考えたあたりから怪しくなりました。
気付けば上の通りシンプルですが、WSLで定期実行したいものがあったので、どうしてもcronから抜け出せなかったです。

たとえば「WSLで動かしたいshellがあり、WSLの状況を気にせずクリーンインストールした後でも動かせるようにしたい」という要件であれば

1. shを作る
1. タスクスケジューラを設定する（後述）

上記と比較すると、作ったファイルがbatかshかの違いですが、タスクスケジューラの設定を

- プログラム: `wsl`
- 引数の追加: `/mnt/.../フルパス`

としましょう。

なお、powershellでもできますが、実行権限の制御をする必要があり面倒くさいので慣れていないならbatで完結させる事をおすすめします。

## 読了後いいね！をお願いします。
どれだけの方に読んでもらっているか知りたいので、お手数をおかけしますがご協力いただけると嬉しいです。

### 注釈
歴代M1グランプリの得点を標準化


#1.初めに
過去のM-1グランプリの得点を各年で標準化し、その値を比較する。
[歴代M-1グランプリ結果](https://www.m-1gp.com/history)からスクレイピングしてデータを取得する。

#2.準備
スクレイプのためBeautifulSoupとrequestsを使う

```python3
import pandas as pd
from bs4 import BeautifulSoup  
import requests
```

```python3
url = "https://www.m-1gp.com/history"
res = requests.get(url)
soup = BeautifulSoup(res.text,'html.parser')
```

開催年を作成する。(2020年から2000年までの2011から2014年までを除いたもの。)

```python3
year_list = []
for year in range(2020,2000,-1):
    if year in [2011,2012,2013,2014]:
        continue
    year_list.append(str(year))
```


#3.実行
dfsに2000〜2020年までの結果が入る。

```python3
dfs = pd.DataFrame([])
for i in range(16):
    score_list = []
    for j in soup.find_all("div", class_='result')[i].find_all("td"):
        score_list.append(j.get_text())
    scores = [score_list[i:i+2] for i in range(0,len(score_list),2)]
    df = pd.DataFrame(scores)
    
    #indexを開催年とする
    df.index = [year_list[i]] * len(df)
    
    #得点をint型に
    df[1] = df[1].map(lambda x: x.replace('点','')).astype(int)
    #標準化
    df[2] = (df[1]-df[1].mean()) / df[1].std()
    
    dfs = pd.concat([dfs,df])

dfs
```

実行結果は以下
1列目は得点、2列目が各年で得点を標準化したものとなっている。
![スクリーンショット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548394/72d73d8a-30e6-08c5-5865-c88990f617f5.png)


この標準化された得点で降順にソートしてみると

```python3
#降順にソート
dfs_s = dfs.sort_values([2], ascending=False)
pd.set_option('display.max_rows', 200)
dfs_s
```
実行結果
![スクリーンショット 2021-12-11 14.44.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548394/391ff021-e8e2-2954-4109-e9f1efc69ac2.png)
----------------------(省略)----------------------
![スクリーンショット 2021-12-11 14.44.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548394/9005d7e2-0d2f-6eeb-6959-9a1b914780ae.png)

母集団や採点方法などが違うので一概に比較できないが、ミルクボーイ、次点でアンタッチャブルが抜けていることが分かる。
また、2001年の芸人が上位に来ないのは、審査員が付ける点に差があり得点差が大きく開き、分散、標準偏差が大きくなったことが原因だと思われる。
ずぼらな私でも取れたSAA in 2021

皆さんは資格習得をどんなモチベーションでやっているでしょうか。
所属している会社が推奨していたり、業務に必要ということで上司から指示されたり、いろいろなケースがあると思います。

自己学習の結果としての資格取得を目指す場合、しっかりとしたモチベーションがないと、だれることがあると思います。
まぁ、私がずぼらなだけなのかもしれませんが。
そんなこんなで私の AWS Certified Solutions Architect Associate 資格取得記録を共有したいと思います。

## 2018年
業務でAWSを少し触り始めたのをきっかけにAWSの資格取得を思いつく。
当時は、AWSのパートナー向け学習コンテンツを中心に勉強を始めました。

**業務が忙しくなり勉強中断。結局資格試験を受けてすらいません**

## 2019年
このままじゃいかんだろうということで、Udemyにてコースを受講しました
受講したコースは、SAAで定番となっている下記のコース

>これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座（SAA-C02試験対応版）
https://www.udemy.com/course/aws-associate/

**50%程進んだところで業務が忙しくなり。。。**

## 2020年
このままじゃいかんだろうということで奮起。何とか100%まで完了し、続いてテスト対策のために下記コースを受講

>【SAA-C02版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（6回分390問）
https://www.udemy.com/course/aws-knan/

**気が乗（ｒｙ**

## 2021年
もはや**自力で勉強を続けることは自分には無理**だということをいい加減、40代も半ばにして理解。みんチャレというサイトに登録して励ましてもらいながら勉強することに。

>みんチャレ
https://minchalle.com/

ここに来て勉強しなおして気づく、AWSのサービスや仕様が変わっていること。
2020年段階では正解とされていた問題が、2021年段階では不正解となっている箇所がいくつかあることがわかりました。
逆を言うと、受講したUdemyのコースは**仕様変更に伴って内容や試験問題が更新されている**ということ！！

なんと心強いことか。

そして、AWSに限った話ではないですが、これらの仕様は常に変化していくもので勉強し続ける必要があるということを理解した気持ちです。

こう振り返ってみるとこの資格に対して一体何年かけてしまっているんだろうという、なんとも情けない気持ちになってくるところです。
でも、継続して勉強しているといえなくも！！と前向きな気持ちでいっぱいです。

資格取得を終えた今でも、継続的に勉強していく中で、更新されるコンテンツのありがたみを感じながら、自分自身も更新していく大事さを感じる日々です。

中の人、ありがとう！
【Terraform】list, map, objectの結合を整理したい

この記事は[Terraform Advent Calendar 2021](https://qiita.com/advent-calendar/2021/terraform)の11日目です。

# これはなに
- Terraformのlist, map, objectの結合メソッドがいくつかあるので整理したい
    - ~~`for_each`で複数リソース良さげに作ろうとした際、この辺で格闘した思い出~~

# 結合系のメソッド

- `concat`
    - 複数のlistを結合して1つのlistにする
    - https://www.terraform.io/docs/language/functions/concat.html
- `flatten`
    - 1つのlist内にあるlistの要素を全て同階層に並べる
    - https://www.terraform.io/docs/language/functions/flatten.html
- `merge`
    - 複数のMap、Objectを結合して1つのMap、Objectにする
    - https://www.terraform.io/docs/language/functions/merge.html

# 試す

`terraform console`で対話モードに入って各メソッドの動作検証

## `concat`と`flatten`

### 基本的な使い方

```terraform
> concat([0, 1, 2], ["a", "", "c"])
[
  0,
  1,
  2,
  "a",
  "",
  "c",
]

> flatten([[0, 1, 2], ["a", "", "c"]])
[
  0,
  1,
  2,
  "a",
  "",
  "c",
]
```

### 空のlistを結合するパターン

空のlistは結果に含まれない

```terraform
> concat(["a", "b"], [], ["c"])
[
  "a",
  "b",
  "c",
]

> flatten([["a", "b"], [], ["c"]])
[
  "a",
  "b",
  "c",
]
```

### 多次元listを結合するパターン

concatは結果の要素にlistが含まれるが、flattenは含まれない

```terraform
> concat(["a", "b"], [["ca", "cb"], [], ["da"]])
[
  "a",
  "b",
  [
    "ca",
    "cb",
  ],
  [],
  [
    "da",
  ],
]

> flatten([["a", "b"], [["ca", "cb"], [], ["da"]]])
[
  "a",
  "b",
  "ca",
  "cb",
  "da",
]
```

## `merge`

### 基本的な使い方

結果はkeyでソートされる

```terraform
> merge({"b"="bb"}, {"a"="aa", "c"="cc", ""="dd"}, {"0"=00, "1"=11})
{
  "" = "dd"
  "0" = 0
  "1" = 11
  "a" = "aa"
  "b" = "bb"
  "c" = "cc"
}
```

### ダブルクォートで囲んでないkeyを持つmap、objectが含まれるパターン

結果はkeyがダブルクォートで囲まれる
valueはそのまま

```terraform
> merge({a="aa", b="bb"}, {1=11, 2=22})
{
  "1" = 11
  "2" = 22
  "a" = "aa"
  "b" = "bb"
}
```

### 空のmap, objectを結合するパターン

空のは結果に含まれない

```terraform
> merge({"a"="aa", "b"="bb"}, {}, {"c"="cc"})
{
  "a" = "aa"
  "b" = "bb"
  "c" = "cc"
}
```

### 重複keyの扱い

後続のkey, valueで上書きされていく（後続のものが優先される）

```terraform
> merge({"a"="aa"}, {"a"="ab", "b"="bb"})
{
  "a" = "ab"
  "b" = "bb"
}

# keyにダブルクォートなしでも同じ
> merge({"a"="aa"}, {a="ab", "b"="bb"})
{
  "a" = "ab"
  "b" = "bb"
}
```

### 0の扱い

ダブルクォートで囲まないと不要な0は除去される

```terraform
# 0が除去される
> merge({01=011}, {2=22, 3=33})
{
  "1" = 11
  "2" = 22
  "3" = 33
}

# 0が除去されるので後続のkey, valueが優先される
> merge({01=011}, {1=12}, {2=22, 3=33})
{
  "1" = 12
  "2" = 22
  "3" = 33
}

# 文字列扱いならば除去されない
> merge({"01"="011"}, {2=22, 3=33})
{
  "01" = "011"
  "2" = 22
  "3" = 33
}
```
v-dialogでよく使うattrsってなに？

# 要約
- Vuetify2の<v-dialog>のactivatorスロットのスロットプロパティの意味を調べる
- `attrs`はアクセシビリティのための属性が入ったオブジェクト

# 動機
Vuetifyにはv-dialogという、ダイアログを実装するためのコンポーネントが用意されており、実装例として、公式では[次のコードが紹介されている](https://vuetifyjs.com/ja/components/dialogs/#section-4f7f304465b)。

```vue
<template>
  <div class="text-center">
    <v-dialog
      v-model="dialog"
      width="500"
    >
      <template v-slot:activator="{ on, attrs }">
        <v-btn
          color="red lighten-2"
          dark
          v-bind="attrs"
          v-on="on"
        >
          Click Me
        </v-btn>
      </template>

      <v-card>
        <v-card-title class="text-h5 grey lighten-2">
          Privacy Policy
        </v-card-title>

        <v-card-text>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
        </v-card-text>

        <v-divider></v-divider>

        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn
            color="primary"
            text
            @click="dialog = false"
          >
            I accept
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>
</template>
<script>
  export default {
    data () {
      return {
        dialog: false,
      }
    },
  }
</script>
```

`v-dialog`の`activator`スロットに`v-btn`を与え、スロットプロパティからは`on`プロパティおよび`attrs`プロパティを取り出している。
この`on`プロパティはイベントハンドラであり、`v-btn`の`v-on`プロパティに与えることで、画面のボタンをクリックするとダイアログが表示される。

それでは、`attrs`プロパティとはなんだろうか？[v-dialogAPIのドキュメント](https://vuetifyjs.com/ja/api/v-dialog/#slots)を読んでも、プロパティとしては`on`と`value`しか説明がない。気になったので、`attrs`の正体を探した。

# 結論
このプロパティの正体は、ダイアログ展開のためのトリガとなるコンポーネントに指定すべき[WAI-ARIA属性](https://vuetifyjs.com/ja/features/accessibility/#section-30a230af30c630a330d930fc30bf30fc30b930ed30c330c8)のようだ。
実際`v-dialog`の`activator`スロットでボタンにバインドされた`attrs`には、ダイアログが閉じている状態では次のオブジェクトが入っている。

```json
{
  "role": "button",
  "aria-haspopup": true,
  "aria-expanded": false
}
```
aria-expanded属性は、ダイアログを展開するとtrueになる。

WAI-ARIA属性については次が詳しい。
https://developer.mozilla.org/ja/docs/Learn/Accessibility/WAI-ARIA_basics

Vuetifyでは、このような属性を付与しやすくし、アクセシビリティを担保しやすくしているようだ。
もちろん、バインド対象によってroleは変わらない。`div`や`input`にバインドしてもroleはbuttonのままである。
チーム開発でschema.rbを扱うときの注意

そもそもschema.rbは自分の環境次第で変わるのでrails  db:migrateした時にpull してきたブランチのschemaがそのまま反映される訳ではない。

Rails db:migrateした時点で元々のschemaとは別のschemaができる。それはいい。

ただ、schema.rb をリモートブランチにpushしてはいけない。何故か？

自分のブランチをpushする時にschemaごとpushしてしまうと本番環境のschemaを変更してしまう。それはダメ。

個人個人のブランチでschemaが変わるように本番環境もまた違うから。

ではどうするか。push する際はschemaはGitの管理下から外すようにする。

やり方としては二つ。

```
gitignore
```

にファイルを追加するか、

```
git update-index --skip-worktree [ファイル名]
```

で、ファイルをコミット対象から除外する。

ちなみに、上記コマンドで除外したファイルを対象下に再度おきたい場合

```
git update-index --no-skip-worktree [ファイル名]
```

コマンドを実行すればもう一度対象下におくことができる。

新しくモデルを作成したり、カラムの追加またはそのどれかを削除する場合はどうするか？

その場合は、新しく作成したmigration ファイルだけをcommit すれば良い。そうすれば本番環境のdb環境(schema)でmigration が実行されそれまでの部分に影響を与えることがない。

そして、その反映を取り込みたい人はそれ(migrationファイル)が追加されたmasterブランチをpullした時に自分のローカル環境でmigration を実行すればまた自分の環境下(schma)でDBの変更が可能になる。
C#でスクレイピングする。Curlコマンドでhtmlを取得し、AngleSharpを利用してparseする。

#これは何

C#で、スクレイピングする例

#注意書き

HTMLの取得は、Curlコマンドを利用している。
HTMLのParseは、AngleSharpを利用している。

AngleSharpのversionは0.11.0、
System.Text.Encoding.CodePagesのversionは4.3.0を利用している。
（AngleSharpと、CodePagesの、相性でエラーが出る模様で、他の方のページで、稼働実績のあったこの組み合わせを利用している。）

nugetを利用せず、DLLを取得して、利用している。
（nugetのファイルをzipとして解凍し、ファイルを取得している。）
DLLは、net46のフォルダ内のものを利用している。


#実行コマンド例
>ore_scrape.exe

#コンパイル例
c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /reference:AngleSharp.dll;System.Text.Encoding.CodePages.dll; /target:exe ore_scrape.cs

#ソース

```c#:ore_scrape.cs

//c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /reference:AngleSharp.dll;System.Text.Encoding.CodePages.dll; /target:exe ore_scrape.cs

using System;
using System.IO;
using System.Diagnostics;
using AngleSharp.Html.Parser;

public class ore_scrape
{

	////Main
	public static void Main(string[] args){
		path = System.Windows.Forms.Application.StartupPath + "/";
		string local_url = path + "temp.html";
		my_curl("https://www.yahoo.co.jp",local_url);
		my_parse(local_url);
	}///Main

	///--==--==--==
	private static void my_curl(string p1,string p2){
	    ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe"); 
		string p0 = "/c curl " + p1 + " > " + p2;
		processStartInfo.Arguments = p0;
	    //processStartInfo.CreateNoWindow = true;
	    processStartInfo.UseShellExecute = true;
		Process process = Process.Start(processStartInfo); 
		process.WaitForExit();
		process.Close();
		return;
	}//--==--==--==

	////--------------------
	private static void my_parse(string parse_url){
		var html = File.ReadAllText(parse_url, System.Text.Encoding.UTF8);
		var parser = new HtmlParser();
		var doc = parser.ParseDocument(html);
		var classpList = doc.GetElementsByTagName("h1");
		foreach (var c in classpList)
		{
			string t;
			t = c.TextContent;
			t = t.Trim();
			Console.WriteLine(t);
			File.AppendAllText(@".\temp.txt", t + Environment.NewLine);
		}
	}///--------------------

}
```

#実行例

※www.yahoo.co.jpのh1タグを取得している

※取得対象の画面例
![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107418/f4fda175-41a2-a675-3eea-0f81b95510ba.png)


※取得した結果の例

![img2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107418/23a76781-5c8b-4d7d-fb8f-bb4158e86756.png)

#参考サイト

##nuget
https://www.nuget.org/packages/AngleSharp
https://www.nuget.org/packages/System.Text.Encoding.CodePages/

https://www.nuget.org/api/v2/package/AngleSharp/0.11.0
https://www.nuget.org/api/v2/package/System.Text.Encoding.CodePages/4.3.0

##AngleSharp

2020-01-31
C#でAngleSharpを使ってHTMLをパースする
https://emotionwave.hatenablog.com/entry/2020/01/31/100000

2019.4.24
[C#] AngleSharpでHtmlParserの生成をするとFileNotFoundExceptionの例外が出る問題
https://d-vecter.blogspot.com/2019/04/c-anglesharphtmlparserfilenotfoundexcep.html