OmniAICreator/Qiita-1.07M huggingface dataset:
生成AIで歴史の闇を暴くぜ

> 歴史とは、勝者によって作り上げられたものである。

***


歴史は、その多くを戦によって語られてきた。
そこには必ず勝者と敗者が存在するが、描かれるのは常に勝者の華々しい事績である。
天下分け目の関ヶ原の戦いですら、その多くに創作が含まれているとされる。

歴史が<b>真実か、はたまた偽りか</b>、正しく理解する術は乏しい。

<br><br>

ChatGPTに代表されるLLM（大規模言語モデル）にも、近しい特徴がある。
<b>ハルシネーション（幻覚）</b>と呼ばれるこの現象は、あたかも真実かのように、不確かな情報をユーザに語りかけるのである。


十分な事前知識の無いユーザは、それが真実かを確かめることが出来ず、信じ込んでしまう。

<br><br>

富士通が無償公開している生成AIサービスの中でこの<b>ハルシネーションを検知する独自機能</b>を利用することが出来る。
これを用いて、歴史の闇を暴くことが出来るだろうか。試してみよう。

***

### ハルシネーション検知の実践

まずは薩長同盟。言わずと知れた幕末の薩摩藩、長州藩の間で結ばれた同盟である。
このシナリオを<b>Fujitsu Kozuchi (code name)</b>を用いて生成させてみる。

:::note warn
<b>Fujitsu Kozuchi (code name)とは</b>
富士通が研究開発した先端AI技術を迅速に試すことが出来るプラットフォーム。
生成AIに限らず、様々なAIコアエンジンを実装しており、その機能をポータルサイト上で試用できる。

お試しはこちらから：https://portal.research.global.fujitsu.com/
:::

<br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629239/ee31e554-c776-2f1d-0030-0945a88d7c00.png "薩長同盟のシナリオ")

<br>

ここで、さっそくハルシネーション検知機能を作動させてみよう。
回答の左下にあるチェックマーク（左から２番目）を押して、モードを選択した後Checkを押せばOKだ。
<br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629239/ab43c6c1-1eb2-61cb-5669-7d03b26cd547.png "ハルシネーション検知機能")

<br>

ここでは<b>２つのモデルを用いた解析</b>が可能で、それぞれ<b>[0], [17]</b>というスコアになった。
スコアが低いほどハルシネーションを起こしている確率が低いので、今回は比較的事実に近い内容が出力されたようだ。
<br>
ちなみに、17というスコアは、
「薩摩藩と長州藩が連携して、政府に対して<b>『改革を求める活動』</b>を行った」
という表記が、
正しくは<b>『攘夷運動』</b>とはっきり明記すべきという見解に基づいている。
（このように、文中のどの部分にどのような懸念があるかも詳細欄から閲覧可能。）
<br>
矛盾こそしていないが、より適切な表現があるだろうというAIの判断だととれる。

***

### さらに色々なテーマで

続いて、いくつかのテーマごとにそのスコアを見比べてみよう。
スコアは「キーフレーズに注目して多数決」の方式を参考にする。

| 出来事 | スコア |
|:------|------:|
|邪馬台国|3|
|平城京の建設|29|
|平安遷都|5|
|平将門の乱|20|
|源平合戦|5|
|応仁の乱|1|
|長篠の戦い|9|
|本能寺の変|16|
|黒船来航|14|
|薩長同盟|17|
|大日本帝国憲法公布|7|
|日露戦争|5|
|大正デモクラシー|10|
|第二次世界大戦|13|
|阪神淡路大震災|2|

<br>

もっともハルシネーションスコアが高かったのは<b>平城京の建設</b>で<b>[29]</b>だった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629239/3444cef3-7920-d387-f063-4761f70711e0.png "平城京の建設のハルシネーション検知")
<br>
背景としては、飛鳥時代の<b>飛鳥京が受けた自然災害</b>や、交通や防御上に関する<b>土地の理</b>、都城の中心に<b>整備された施設</b>などが曖昧な表現で書かれており、ハルシネーションとして検知したと判断されている。
<br>
興味深かったのはかの謎多き邪馬台国で、これはAIの回答が<b>「諸説ある」</b>というテイを適宜表明していたことから、<b>一部の誤りや不安定さに関してもハルシネーションと捉えなかった</b>と判断されている。

***

### さいごに

今回は、<b>歴史上の闇を生成AIを用いて暴く</b>ことを試みた。
とは言え、原理上、すでに正史が時代の勝者によって書き換えられていたとしたら、
そもそもLLM（大規模言語モデル）の出力からそれを検知することは不可能なことは自明である。
<br>
今回はそういうお遊びなので、細かいことは許して欲しい...。
<br><br><br>

今回利用したハルシネーション検知は、富士通のポータルサイトから誰でも無償で利用することが出来る。
富士通が研究開発した先端AI技術の体験が出来るウェブサイトが公開されており、今回もこちらを利用して実験を行った。

🔗<b>Fujitsu Research Portal : https://portal.research.global.fujitsu.com/ </b>

これをお読みの方もぜひ試してみて欲しい。
<br><br>

また、<b>技術の詳細</b>や<b>問い合わせ</b>などはこちらに簡潔にまとまっているので、こちらもぜひ。

https://pr.fujitsu.com/jp/news/2023/09/26-1.html

<br>
では。

<br><br><br>

富士通株式会社
淺間康太郎
JavaScript getMonth()＋1とdate()の罠

# 概要
「getMonth()」を使用して、日付の比較を行うプログラムを実装しましたが
実行時特有のJavaScriptの＋1の概念で思わぬ事件を生み出してしまたため、記事にします。

# やりたかったこと
JavaScriptを使用してユーザーが入力した日付のチェックを行いたかった。
例えば過去日を入力した場合には過去日を入力しないようにダイアログをだしたかった。


## 実装内容（修正前）
当初は以下のような実装を行っていた。
一見すると問題ないように見えるが、2023年1月29日に事件は発生した！！

```test.js
      // 現在の日時を取得
      var now = new Date();
      var nowDate = new Date(now.getFullYear(), now.getMonth() +1, now.getDate(), '00', '00', '00');
      // ユーザーが入力した日時を取得
      var targetDate = $(this).val().split('/');
      var checkDate = new Date (targetDate[0], targetDate[1], targetDate[2], '00', '00', '00')
```

## getMonth()のおさらい

そもそも「getMonth()」とは。。。。

>月を0から11の整数で取得します。 基準となるのは、そのタイムゾーンの現地時間（ある地点の子午線を基準として>定めた地方時）です。
>
>JavaScriptのgetMonth()メソッドでは、指定日の「月」から 1 を引いた数値が返ることに注意してください。 >getFullYear()メソッドやgetDate()メソッドでは、指定日の「西暦年」や「日」がそのまま返りますが、>getMonth()メソッドだけは「月 - 1」が返ります。

上記から当初は、現在日時を取得する場合には、＋1をすればよいと考えていた。
しかし、上記の実装で、比較を行ったところ、月末に悲劇を迎えることになる。。。

## 何が起こったか
2023年1月30日、ユーザーは「2023年2月1日」を入力すると、未来を入力したはずが、
過去日と判定されてしまった。
その時、比較していた変数は以下の状態を返していたのである。。。

```test.js
      // 現在の日時を取得
      var now = new Date();
      // now                ⇒ 2023/1/29
      var nowDate = new Date(now.getFullYear(), now.getMonth() +1, now.getDate(), '00', '00', '00');
      //　now.getFullYear()  ⇒ 2023
      //  now.getMonth() +1  ⇒　1
      //  now.getDate()      ⇒  29
      //  nowDate            ⇒　2023/3/1    ※!?!?!?!?!?
```

ここで、Date()についてもおさらいを行いたい。

## Date()のおさらい
様々な使い方がありますが、今回の今回の使用例としては、
日付の各要素を指定してDateを生成し、Dateで比較を行った。

```
new Date(year, monthIndex, day, hours, minutes, seconds)
```

注意点として、、、

>いずれかの引数が定義された境界を超えた場合、「繰り上げ」が行われます。例えば、 monthIndex に 11 よりも>大きな値が渡された場合、その月は年を増加させます。 minutes に 59 よりも大きな値が渡された場合、hours はそれに応じて増加します。したがって、 new Date(1990, 12, 1) は 1991 年 1 月 1 日を返し、 new Date(2020, 5, 19, 25, 65) は 2020 年 6 月 20 日の午前 2 時 5 分を返します。

>monthIndex
月を表す整数値です。 0 （1 月）から 11 （12 月）までの値です。

こちらも同じく、月は、0から11を指定する
ほぉ。。。。
つまり引数に、「2023,1,28 」を渡すと、「2023/2/28 00:00:00」を返すことになる。

じゃあ、「2023/1/29」、「2023/1/30」、「2023/1/31」はどうなるかというと。。
「2023/3/1」、「2023/3/2」、「2023/3/3」に繰り上がったということか！！！

## 修正したコード
```test.js
      // 現在の日時を取得
      var now = new Date();
      var nowDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), '00', '00', '00');
      // ユーザーが入力した日時を取得
      var targetDate = $(this).val().split('/');
      // 比較対象の月をマイナスした
      var checkDate = new Date (targetDate[0], targetDate[1]-1, targetDate[2], '00', '00', '00')
```

getMonth()がマイナス1で返すものの、Date()により、該当月を返す形になるため、
比較対象の月をあえてマイナスし、Dateの繰り上がり等を発生させてないように修正した。


そもそも、dateで比較を実施すること自体がナンセンスなきもするが、、
比較対象のデバックを行うとともに、JavaScriptでのgetMonthやdate()の使い方には気を付けたい。
【JavaScript】オブジェクトのプロパティを変数にしたいなら[]で囲む

# はじめに

[Reactの公式チュートリアルの問題](https://ja.react.dev/learn/extracting-state-logic-into-a-reducer#challenges)を解いていたところ、オブジェクトのプロパティ名が`[]`で囲まれていました。

初めて見た書き方で何をしているかわからなかったため、調べました。

```react
messages: {
  ...state.messages,
  [state.selectedId]: action.message,
},
```

## Computed Property Names

この`[]`はEC2015から導入された、オブジェクトのプロパティを動的に生成するための構文です。

Computed Property Names、日本語だと「計算プロパティ名」という構文らしいです。

### サンプル

計算プロパティ名を使用することで、プロパティ名に変数を設定できます。

```javascript
let propertyName = 'UserName';

const profile = {
  age: 21,
  [propertyName]: 'taro',
};

console.log(profile.UserName); // taro
```

## おわりに

"計算プロパティ名"という名称の意味がよくわからずに混乱しましたが、「計算した結果をプロパティに入れたよ」というような意味合いですね。

## 参考

- 以下の「計算プロパティ名」の部分です。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Object_initializer#%E8%A8%88%E7%AE%97%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E5%90%8D
SwiftData で バックグラウンド処理

SwiftData への大量インサート。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/SwiftData?src=hash&amp;ref_src=twsrc%5Etfw">#SwiftData</a> ModelActor の使い方が分からない。<a href="https://twitter.com/hashtag/macos?src=hash&amp;ref_src=twsrc%5Etfw">#macos</a> <a href="https://twitter.com/hashtag/ios?src=hash&amp;ref_src=twsrc%5Etfw">#ios</a> <a href="https://t.co/8RLkgDBpFz">pic.twitter.com/8RLkgDBpFz</a></p>&mdash; chanzmao (@maochanz) <a href="https://twitter.com/maochanz/status/1732726071525879893?ref_src=twsrc%5Etfw">December 7, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Task.detached で @Query はそれなりに Observe してる。

スレッドの切り替えを考慮せずにUIスレッドのみで分かりやすく実装させようとするの強引すぎると思いながらも期待。

<a href="https://android.benigumo.com/20231205/persistentidentifier/" target="_blank" rel="noopener">👉 【Swift】モデルクラスの ID に UUID() を使ってたらヤバい - PersistentIdentifier&nbsp;<img src="https://b.hatena.ne.jp/entry/image/https://android.benigumo.com/20231205/persistentidentifier/" alt="hatena-bookmark" /></a>
<a href="https://www.youtube.com/watch?v=cU-vk2q9gm4" target="_blank" rel="noopener">👉 #SwiftData ModelActor の使い方が分からない。#macos #ios - YouTube&nbsp;<img src="https://b.hatena.ne.jp/entry/image/https://www.youtube.com/watch?v=cU-vk2q9gm4" alt="hatena-bookmark" /></a>
若手のデータサイエンティストでもPM経験を積む工夫

株式会社ブレインパッドでデータサイエンティストをしている河合広樹です。

この記事は[BrainPad Advent Calender 2023](https://qiita.com/advent-calendar/2023/brainpad) 8日目の記事です。

 

# はじめに
最近はデータサイエンスの学部も多くできて界隈が盛り上がってますよね。この影響でデータサイエンティストの若手がどんどん増えてきています。
一方で、 __プロジェクトマネージャー(PM)ができるデータサイエンティストが不足__ していると感じます。

この人材を社内で増やすために、弊社は中途採用を積極的に行ったり若手の育成に力をいれていますが、いきなり現場でPM経験を積むのは品質などの問題から厳しいものがあります。
若手としては、昇進するためにマネジメント経験を積みたいけどその機会がなかなか無いです。

そこで、何かマネジメント経験を学べるものはないかと考え、 __社内イベントの企画・運営__ にたどり着きました。



# 社内イベントの企画とPMスキルはどこが関連してるのか
社内イベントは直接お金を稼ぐことが目標ではないですが、社内の交流促進を促すという目標があるプロジェクトです。
そのため、社内イベントを企画・運営する役割はPMと同様であり、PM経験を培う良い機会にできます。

社内イベントの企画・運営では、以下のスキルが問われます
- 数ヶ月スケールのスケジューリング
- 遅延リスクの考慮
- 社長や役員、経理など各部署との連携（ステークホルダーとの連携）
- メンバーへの仕事の振り方
- どれもPMレイヤーでも求められるスキルだと思います。

私は2年間で約100人規模のイベントを4回企画してきており、メンバーへの仕事の振り方などで苦戦しつつも毎回学びを得ています。
まだ2年目なので業務でマネージャー的な動きはしていませんが、マネージャーの気持ちを理解して働くのには十分役立っています。



# 企画しやすい社内イベントはあるか
色々なイベントの中でも一番お手軽なのがBBQだと思います。

交流促進のためには、なるべく多くの人が参加して相互に交流できるイベントにする必要があります。居酒屋で飲むだけでは大人数集めても交流しずらいですし、運動会やゲームパーティなど尖った企画でも人が集まりづらいと思います。

この問題を解決してくれるお手軽イベントがBBQだと思います。

都内でも200人程度入れるBBQ場がいくつかあるので、100人程度の規模であれば十分の広さになります。費用も会場代が1人2,000円弱で残りが食費に回せるので5,000円程度で収まりイベント系にちょうどいい予算となり、経費申請も安易だと思います。

参加してやることはほぼ飲み会と変わらないのに、BBQという名前にするだけで特別感も出て参加者も募りやすいです。



# BBQ企画の流れ
大まかにBBQ企画の際の流れを記載しておきます。（部署約200人、社員約600人の会社の場合です）

1. 開催の許可を上司に伺う
2. 参加者を見積もる（回答フォーム作って展開するなど）
3. 場所の確保
4. 経費の見積もり + 社内の申請もろもろ
5. 偉い人（社長、役員、部長など）を個別に招待する
6. BBQの食材、BBQ中のイベントを準備
7. 当日がんばる
8. 後日、当日の知見を社内・社外に向けて発信する

この中でも「場所確保」さえうまくいけば失敗することはないと思います。ただ、場所確保に伴う参加者の見積もりでは、他の社員の社交性や期待値などを考えて予測する必要があるため若手には少し難易度が高く、どれだけ多くの上の人と相談できるかなどのコミュニケーションスキルも問われます。

そして、これらを全てスケジュールしたり幹事内で分担したりする工程でPMスキルを学ぶことができると思っています。
スケジュールにまとめると簡単に見えますが、メインの仕事をする傍らで実施するのでかなり苦労します。イベント企画にモチベーションの高い幹事で運営しないとぐだぐだになってしまう一方で、遂行しきった後の達成感はひとしおです。

ぜひBBQを通してPM力を鍛えて欲しいです。


# おわりに
社内イベントの企画・運営では役員の人含め多くの人と関わります。イベント企画のおまけとして、いろんな人と友達になれます。なので、困りごとがあった時の相談相手が増えますし、お互い知った中の同僚と仕事するのは気持ちがいいです。

こういうイベントは上の人が発案するよりも若手が発案した方がウケがいいと思うので、若手の方ぜひぜひBBQ企画してみてください。

ここまで読んでくださりありがとうございました。少しでもみなさまの参考になればなによりです。
続　Babylon.js で作成したメッシュの頂点を編集する

これは[Babylon.js Advent Calendar 2023](URL "https://qiita.com/advent-calendar/2023/babylonjs") の7日目の記事です。

## この記事について

[前回のメッシュの頂点を編集する記事](URL "https://qiita.com/Ykoba791/items/6786ed6a8ab687b3d375")の続きです。
今回は編集例をいくつか記載します。

## 球体の頂点を編集をする
今回はPlayGroundのデフォルトでも表示される球体をベースにします。

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594551/6997845a-a8a8-d137-cf37-fa413762da9a.png"/>

### 球体の上半分を拡大する
前回と同様に、getVerticesDataで頂点の座標を取得します。
次に　spherePos.length/2 で、取得した頂点の半数の座標を対象にし、座標のサイズを２倍の値にして updateVerticesData で球体に変更を反映します。
```javascript:球体の半分を拡大
    var spherePos = sphere.getVerticesData(BABYLON.VertexBuffer.PositionKind);
    var numberOfVertices = spherePos.length/2; //半分の座標までを対象にする

    for(var i = 0; i<numberOfVertices; i++) {
        spherePos[i] = spherePos[i] * 2;       //サイズを2倍にする
    }
    sphere.updateVerticesData(BABYLON.VertexBuffer.PositionKind, spherePos);
```
このPlaygroundは、下記のリンクにあります。
https://playground.babylonjs.com/#UY72D0#8

実行結果は、下図のようになりました。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594551/73cb656a-14a5-0622-bd74-7f14d93806a5.png"/>

### 球体の上半分を、縦方向にだけ拡大する。
次に、縦方向のみサイズを2倍にしてみます。
getVerticesDataで取得した頂点座標は、x,y,z,x,y,z,・・・と繰り返しなので、y座標のみを狙って２倍します。
```javascript:球体の半分を縦に拡大
    var spherePos = sphere.getVerticesData(BABYLON.VertexBuffer.PositionKind);
    var numberOfVertices =　spherePos.length/2/3;

    for(var i = 0; i<numberOfVertices; i++) {
        spherePos[i*3+1] = spherePos[i*3+1] * 2;
    }
```
spherePos[i*3+1]で、3つおきに座標を処理し、+1でyの部分を対象にしています。
このPlaygroundは、下記リンクにあります。
https://playground.babylonjs.com/#UY72D0#6

実行結果は下図のようになりました。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594551/7324e644-8f77-03ce-39ab-0dcd6807ea24.png"/>
半分だけ縦に伸ばしたので卵っぽいですね。

### 球体の上半分を、飛ばし飛ばしで拡大する
最期に、10個置きにサイズを拡大してみます。
if((i % 10) == 0){　で、10個おきに頂点を拡大していきます。

```javascript:球体の半分を縦に拡大
    var spherePos = sphere.getVerticesData(BABYLON.VertexBuffer.PositionKind);
    var numberOfVertices =　spherePos.length/3;

    for(var i = 0; i<numberOfVertices/2; i++) {
        if((i % 10) == 0){
            var idx = i*3 ;
            spherePos[idx]   = spherePos[idx] * 2;
            spherePos[idx+1] = spherePos[idx+1] * 2;
            spherePos[idx+2] = spherePos[idx+2] * 2;
        }
    }
```
このPlaygroundは、下記リンクにあります。
https://playground.babylonjs.com/#UY72D0#7

実行結果は下図のようになりました。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594551/09273ba3-0bc0-35bd-cac5-878118a30572.png"/>
ヤマアラシのようにガビガビしてますね。

## 最期に
球体の頂点を編集して、いろいろな形を作成してみました。

次回は、色の操作についても記述していこうと思います。
アプレンティス チーム開発 1回目 記録記事


# 山浦さん主催アプレンティスの1回目のチーム開発の記録

## 概要

私は、今年の10月より、山浦清人さんが開催しているアプレンティスに参加しています。

Linux、Git、Ruby、フロントエンドの学習を終え、次は、4人1組のグループを組んで、チーム開発をすることになりました。

チーム開発期間は、11/27(月) - 12/3(日)の１週間でした。

僕以外のメンバー3人が非常に優秀であったため、開発成果物のカレンダーアプリの完成度が高く、プレゼンも上手くできたため、`Best Student Award`をチームで受賞することができました。

少し、僕が足を引っ張ってしまった部分があったと思うので、反省しております。

※Best Student Awardとは、アプレンティス生全員の投票により最も投票数が多かったチームのことです。


## 今回のチーム開発のコンセプト

```
フレームワークを使わずに、RubyだけでWEBアプリを開発してみよう！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！
```


## 全体的な流れ

1. 自己紹介
1. アイデア決め
1. スライド作成
1. 要件定義
1. 設計
1. タスク出し
1. 実装
1. プレゼン


オリジナルを入れずに、この通りにやるべき


## 反省

できていなかったと感じること

1. チーム開発のために時間をしっかりとる｜決まった時間に、チーム開発の時間を取るべきだった
1. GitやDockerを使って開発したのですが、各々のツールの使い方をしっかりキャッチアップできていなかった
1. 話し手に関心を持ち注意深く話を聞く、ができておらず、コミュニケーションが円滑でなかった（私だけ）
1. チーム開発に積極的になること



## 今回のチーム開発経験で得れたと思うこと

`HRT`

※HRTとは、Humility（謙虚）、Respect（尊敬）、Trust（信頼）

私は、謙虚さ、尊敬、信頼、どれも完全に欠如しており、仲間意識が薄かったと思います。自分ばかりを優先してしまう性格のため、今回のチーム開発ではほぼ何もできませんでした。

発表会では、他のチームの方の制作物を拝見し、すごいと感じました。

今のままの自分では作れないと感じたとともに、

以前、山浦さんから言われていた、

```
チーム開発の成功は、

１：HRT
２：価値主体の姿勢
３：円滑なコミュニケーション
４：個人のタスク管理
５：プロジェクトマネジメント
６：チームビルディング
７：開発の生産性


があること

```

という言葉を思い出し、自分のかけている部分を強く認識しました。


正直に言ってしまうと、全部、できていなかったと思います。


## 今後

この約半年間のアプレンティスの期間内で、あともう一度だけチーム開発の機会があります。

その時には、もっと自分のバリューを出して、少しでも貢献できるよう、上記の山浦さんからの言葉を意識して取り組みたいと思います。

今までやってきた感覚として、

基本的には、毎日アプレンティス（チーム開発）の時間を取ること
１日8時間以上は、アプレンティス（チーム開発）の集中時間していること
毎日、チームメンバーと3回以上コミュニケーションを取ること
毎日、チーム内で進捗を報告し、他人ものも頭に入れておくこと


が必要だと思いました。


また、[FORチーム開発](https://www.youtube.com/watch?v=Pz4GgF0SskE)をみて感じたこととして、
テックリード的存在がいてくれることが、チームにいい影響を及ぼすんだと思いました。

例えば、今回DockerやGitでわからないところをサポートしてくれたメンバーの方がいたのですが、そのようなリードしてくれる存在は非常に頼もしかったです。

また、役割定義の重要性も再認識しました。誰がどこを開発するのか
そして、スケジュール通りに進めていくこと。
タスクをバラして、確実に1つずつ進めること

これが、必要でした。


アプレンティス時間は、

毎日アルゴリズム問題にトライすること
毎日日報とXを投稿すること
ゴールからの逆算思考で、QUESTに挑むこと
できれば、推薦と興味を持ったことも学びアプリに組み込むこと

集中してやっていきたいです。

また、アプレンティスのメンターの方がとてもいいアドバイスをくれるので、技術的にも確実に進化していけそうな予感がしていて嬉しいです。

いつもありがとうございます。

今後、作るアプリとして、

・　電子書籍配信アプリ

を予定しているので、開発するのが楽しみです。
UIが良くて高速なOSSのWiki「Wiki.js」とは？

OSS の Wiki といえば、Wikipedia に使われている「 Media Wiki 」をはじめとして、データベースが不要な「 DocuWiki 」、「 CROWI 」「 GROWI 」 などいろいろあります。

その中でも Wiki.js は 2017 年に発表されたかなり新しい OSS の Wiki で、高速な JavaScript のエンジンを使用しているために高速で、デザインも良く、とても多機能です。

公式ドキュメントをざっと読んで、その機能と特徴をまとめます。

https://js.wiki/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227791/abfaad74-06e2-bb1e-828d-26c885d827a3.png)



公式は、「最もパワフルで、拡張性のあるオープンソースのWiki」を謳っています。

次のような特徴があるとしています。

- どこにでもインストールできる
    - だいたいどんな仮想環境にもインストールできて、大抵のRDBに対応しています。
- 権限管理
    - 管理できるエリアを詳細に設定できます。
- 高いパフォーマンス
    - パフォーマンスを意識していて、高速な Node.js エンジンを使用しています。
- カスタマイズ性
    - デザインの変更が容易です。ライトモード・ダークモードもあります。
- 機密性
    - 一般公開や社内での限定公開、その組み合わせにも対応しています。
- スケーラブル
    - ラズパイ上でも、高性能なクラウド上でも、いい感じに動きます。
- 簡単にインストールできる


全てのユーザが全ての機能を必要としているわけではないので、オンデマンドで次のような機能をオンオフできるみたいです。オンデマンドというのは、初期構築時ではなく、後から設定を変更できるという意味のようです。

- 認証
    - ローカルでの認証 : これは超一般的な、ユーザ名やパスワードをDB内に保存する系の認証です。
    - ソーシャルログイン : サードパーティの Google, Facebook, Microsoft, GitHub, Discord, Slack とかでログインできるみたいです。
    - エンタープライズ : LDAP, SAML, CAS, Auth0, Okta, Azure AD とかの認証基盤が使える。OAuth2 と OpenIDコネクトのモジュールも含まれてます。
    - 2段階認証もあります。
- エディタ
    - マークダウン
    - ビジュアルエディタ
    - 生HTML
    - (実装予定) WikiText : MediaWiki(Wikipedia)と同じ記法みたいです。
- 履歴管理
    - 変更・削除のバージョン管理
    - バージョンの差分
    - 古いバージョンのページをエクスポートしたり新しいページにできます。
- ローカライズ
    - 40言語に対応
    - 右から書く言語にも対応
    - 同じページを複数言語で管理できます。
- メディア管理
    - メディアをフォルダ分けとかして管理できます。
    - (実装予定) 画像編集ツール
- レンダリング
    - シンタックスハイライト
    - UML、シーケンス図、フローチャート
    - TeX、MathML
    - (実装予定) YouTube の動画や音声、[asciinema](https://asciinema.org/) (ターミナルを録画できるやつ) のプレーヤー
- 検索
    - ビルトインの検索エンジン
    - Algolia, Azure Search などのクラウド検索エンジン
    - Elasticsearch
    - (実装予定) Manticore, Solr, Sphinxなど
- ストレージ
    - GitHub, GitLab, BitBucket, Azure DevOps などへのバックアップ
    - AWS S3, Azure Blob Storage, Google Cloud Storage, DigitalOcean Spacesなどへのバックアップ
    - (実装予定) Dropbox, Google Drive, MS OneDrive, Box など
    - ローカルディスクへの保存、SSHを使用したリモートサーバへの保存
- ユーザ管理
    - ユーザの作成や既存ユーザの変更が簡単にできます
    - グループ
    - ページの編集、アセット管理、管理画面へのアクセスなどをグループごとに細かく設定できます
    - ページへの前方・後方一致や正規表現を使用して、グループに細かい権限設定ができます
- テーマ
    - (実装予定) カスタムテーマ
    - ダークモード
    - (実装予定) デフォルトテーマのパーソナライゼーション（色とか）
    - CSS / JS のインジェクション


## さいごに

とても機能が豊富で、大抵の場合 Wiki として必要な機能は揃っていると感じました。

驚くことに、Wiki.js はこれをほぼ一人で作ってるみたいです！ :fearful:

https://docs.requarks.io/releases/about

次の記事では、実際に Wiki.js を AWS にデプロイする方法をご紹介したいと思います！
【社内 LT 会資料】M1 Mac でディープラーニングによる画像分類をやってみたら速度は出たが結果が NVIDIA と異なった

# 注意事項
 
- この資料は画像認識に関係の無い会社内でのLT会のもののため、基本的な内容から説明し詳細をかなり端折っています。
- ひとつだけのモデルとデータセットを使った検証なので、これを持ってすべてのケースで Apple シリコンによるディープラーニングは良くないという主張はしません。ひとつの技術的雑談のネタとしての位置づけです。

- - -

# ディープラーニングによる画像分類やってます

- - - 

# 画像分類とは

画像を渡すとそれが何であるか複数の候補のうちのどれかを教えてくれる。

- - - 

# 画像分類の事例

Google Cloud では[株式会社LIFULLの導入事例](https://cloud.google.com/blog/ja/topics/customers/automl-lifull)が紹介されている。
不動産の室内画像に対して、洗面台、キッチン、リビングなどのラベルをつけてくれて、サイトへの登録作業を省力化する。

- - -

# 私の活用方法

[スプラトゥーンの録画による振り返りの効率化](https://qiita.com/tfandkusu/items/b8b498d60ddff3db4d50#%E9%A0%AD%E5%87%BA%E3%81%97%E3%81%AE%E6%96%B9%E6%B3%95)

- - -

# 分類モデルの作成には NVIDIA の GPU が搭載されているゲーミングPCを使用

一般的には NVIDIA の GPU が搭載された PC でモデルを作成する。
ゲームの3Dグラフィック描画もディープラーニングもたくさんの行列演算なので、GPU との相性が良い。

NVIDIA の株価がエグい理由(Google 検索より引用)

![スクリーンショット 2023-12-05 20.46.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334798/0d2ba5d0-e07d-49fc-e394-45bcbca76a70.png)

- - -

# 分類モデルを作るプログラムはこんな感じ

https://qiita.com/tfandkusu/items/848eef16f2c2651474b2

画像をありもののニューラルネットワークのモデルに5万枚読み込まされているだけ。

- - -

# M1 Ultra 搭載の Mac Studio も手元にある

ディープラーニングは Windows の WSL2 上の Ubuntu を使っているが、普段スマホアプリ開発で Mac を使っている私からすると、キーバインドの違いから使いづらい。
Apple シリコンも GPU を内蔵している。
Mac で画像分類モデルを作れるならば、それで良いと思った。

- - - 

# まずは Windows PC と Mac のスペック紹介

| | Windows PC | Mac |
| --- | --- | --- |
| 製品名| HP OMEN 30L | Mac Studio |
| GPU | RTX 3080 | M1 Ultra 64コアGPU |
| CPU | Core i7-10700KF | M1 Ultra 20コアCPU |
| メモリ | DDR4-3200MHz 32GB | 128 GB |
| 購入時期 | 2021年9月 | 2022年3月 |
| 買ったときの値段 | 25万円 | 72万円 |

- - -

# 学習速度の比較

| GPU 名 | NVIDIA RTX 3080 | Apple M1 Ultra |
| --- | --- | --- |
| 時間 | 53分35秒 | 1時間02分53秒 | 

対象の学習モデルは[こちら](https://qiita.com/tfandkusu/items/848eef16f2c2651474b2)

- - -

# Mac でディープラーニングは悪くないのでは？

価格を考えると Windows PC が良いが、Mac も使う必要があり、2台維持するのが大変な場合はディープラーニングを Mac でやるのありかも？

- - -

# しかし計算結果が異なる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334798/cd799fef-afb5-6cc8-3429-701c9e921dcd.png)

縦軸は正解率 = 正しく分類された枚数/検証用画像枚数
横軸は学習の進み度合い

Apple M1 Ultra の方は結果が安定しない。

- - -

# 原因の推測

推測だがニューラルネットワークのオペレータを GPU に対する低レベルAPI(Metal)に変換する部分に不具合がある可能性がある。(その後の対応案は後述)

- - - 

# 結論

個人的な結論だが、ディープラーニングもやるモバイルアプリ開発者は Windows 機と Mac の2台を維持しないといけない。

- - -

# 以下、細かくて LT 会では説明しない補足

- - -

# 使用パッケージ

```pyproject.toml
tensorflow = "^2.15.0"
numpy = "^1.26.1"
scikit-learn = "^1.3.2"
pandas = "^2.1.2"
h5py = "^3.10.0"
tqdm = "^4.66.1"
tensorflowjs = "^4.12.0"
pillow = "^10.1.0"
tensorflow-metal = "^1.1.0"
```

M1 Mac では TensorFlow を 2.15.0 にしないとインストールできなかった。GPU を使用するために [tensorflow-metal](https://pypi.org/project/tensorflow-metal/) パッケージを使用する。

- - -

# Apple の開発エコシステムへの貢献を考える

理想的な振る舞いとしては、再現可能なミニマムなコードを作成して、[Apple Developer Forums](https://developer.apple.com/forums/tags/tensorflow-metal/) に報告することだが、他に優先したいことがあるので、この件はこれで終了にする。
Python のリストってやつは...

# Python のリストについて，残念に思うこと。

### sum はできるのに...

リストについて，まともな操作は殆どできない。


```python
my_list = list(range(1, 100001))
```

sum(), min(), max() ができるのは，信じられないくらい稀有なこと。

```python
sum(my_list)
```

    5000050000

mean(), std() そのほか，できるものがない。


```python
mean(my_list)
```


    ---------------------------------------------------------------------------

    NameError                                 Traceback (most recent call last)

    Cell In[4], line 1
    ----> 1 mean(my_list)


    NameError: name 'mean' is not defined



```python
std(my_list)
```


    ---------------------------------------------------------------------------

    NameError                                 Traceback (most recent call last)

    Cell In[5], line 1
    ----> 1 std(my_list)


    NameError: name 'std' is not defined


結局のところ，numpy とか statistic を使うしかない。


```python
import numpy as np
np.mean(my_list), np.std(my_list)
```




    (50000.5, 28867.513458037913)




```python
import statistics as st
st.mean(my_list), st.stdev(my_list)
```




    (50000.5, 28867.657796687745)



ちなみに，np.std(my_list) と st.stdev(my_list) が違うが，その原因はいつもの ARE.
不偏か不偏ではないかの些細なこと。


```python
np.mean(my_list), np.std(my_list, ddof=1)
```




    (50000.5, 28867.65779668774)




```python
st.mean(my_list), st.pstdev(my_list)
```




    (50000.5, 28867.513458037913)



背後でどんな汚いことをやってもよいので，mean(), var(), std() など主要な統計関数を利用可能にしてほしいなあ。

### それができるなら...

一般のベクトル演算もできるようjにしてほしいものだ。


```python
my_list = list(range(1, 6))
```

以下は，エラーにならないけどリストを n 回繰り返すという，別の動作をする。


```python
a = my_list * 3
a
```




    [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]



\+ も別の動作をする。


```python
my_list2 = list(range(11, 16))
```


```python
my_list + my_list2
```




    [1, 2, 3, 4, 5, 11, 12, 13, 14, 15]



片方がスカラーだと + や - や / や ** でもエラーになる。


```python
a = my_list + 2
```


    ---------------------------------------------------------------------------

    TypeError                                 Traceback (most recent call last)

    Cell In[16], line 1
    ----> 1 a = my_list + 2


    TypeError: can only concatenate list (not "int") to list



```python
a = my_list ** 2
```


    ---------------------------------------------------------------------------

    TypeError                                 Traceback (most recent call last)

    Cell In[17], line 1
    ----> 1 a = my_list ** 2


    TypeError: unsupported operand type(s) for ** or pow(): 'list' and 'int'


まあ，それはそれでリストという型に対して指定された動作をする演算子であると割り切ればよいのだが統一性という点ではちょっと残念。

つい最近になって導入された「セイウチ演算子」みたいに，現在の +, * を +++, *** みたいに変更するか(** はべき乗なので）？

でも，numpy.ndarray みたいな動作をするようにしてしまうと（今までのと混乱が生じるというのは別として）「リスト」の存在意義がないか。

リストという型の存在意義はどこにあるのか...
あるんだろうけど。
市民開発者を育てる上で気を付けないといけないこと

## 1,はじめに
下記の企画に参加しています！

https://t.co/56WibbNlvz

本日の投稿をもって、私の投稿は残り1投稿となりました。

本日は教育について書いていますが、どの程度のスキルがあるのか？と思いますので、それを簡単に載せておきます。
私は中高の私立で数学の教員を4年間していました。
また大学は数学、大学院では数学教育を学びながら、他大学のセミナーや日本数学教育学会で論文を書き発表していました。
故に教育については、詳しいです。

## 2.学び終えてUiPathに対してどんな気持ちでいてほしいかを考える。
ここは業務時短化などがあげられると思いますが、やはりこれに尽きるかなと思います。

:::note info
**UiPathが好き**や**UiPathが便利だから使っていこう**という気持ちがであるかが大事だと思っています。
:::

## 3,嫌いにさせてしまう発言・行動
:::note alert
(1)難しく考えすぎ、もっと簡単に考えてみよう。
:::
**エンジニアがよく言ってしまう言葉です。**
この言葉は、数学教員をしていた私からすると「数学が苦手な人に何でこれもわからないの？」と同じレベルの発言だと思っています。
なぜなら、エンジニア未経験かつよくわからないRPAをしている人とって、何が簡単なのか？何が難しいのか判断がつかないながら、自分で処理を一生懸命考えたのに、この発言をされたらやる気がなくなります。

:::note info
(1)の回答
話聞いたり、ロボの中身を見たりして難しく考えているなと感じたら、一呼吸置きましょう。
１回その案は置いておきましょう、この案はどうでしょうか？と投げかける。
その後、市民開発者が考えた案と提示案どちらがいいかな？と一緒に考えてあげるといいです。
:::


:::note alert
(2)トライ＆エラーでやってみよう。
:::
**特に新卒にはこの発言は気を付けた方がいいです。**
なぜなら、新卒は触ったこともないシステムで何か漏洩してしまったやExcel、CSVの情報が壊れたら怖いという不安があります。
「トライ＆エラーでやってみよう」と軽はずみで言って、実際にやらせて何か起こったら嫌な気持ちになります。

:::note info
(2)の回答
これは不安を取り除くことです。
つまり、システムなら講義者が事前にシステムの仕様を理解しているから大丈夫だよ、ExcelやCSVなら怖いならバックアップという手があるとあると言うこと。
これだけです。
:::


:::note alert
(3)口頭で長い説明する。
:::

**よく聞くと思いますが、説明は短い方がいいです。**
長すぎると受講者が混乱するだけで何もわかならなく、下手したらUiPath難しいんだ無理だとなりかねないです。

:::note info
(3)の回答
多くを話したい気持ちはわかりますがやめておきましょう。
これを言い換えると、それは開発を進めていくと言う場面が必ず出てきますので、その時にしましょう。
何が出来て、注意点は何かだけで充分です。
:::


:::note alert
(4)説明もなくこういう場合はこうすればいいとパソコンを取って勝手に修正してしまう。
:::

これをすることで疑問だらけになり、開発することをやめてしまいます。

:::note info
(4)の回答
自分がやったら速いからやるというのが先行してしまう時に起こると思っています。
この場合も一呼吸おいて、対話しながら修正する癖をつけましょう。
市民開発者は何が起こっていて、その解決方法を知りたい気持ちがあるのでその気持ちを大事にしましょう！
:::


:::note alert
(5)パターン化されていないアクティビティ、Vb.Netの使い方
:::

UiPathは多くあるアクティビティに加えて、Vb.Netも覚えないといけないため、受講者からしたら毎回整理しないとついていけないと思い、辛くなります。

:::note info
(5)の回答
これは私独自の教え方かもしれないですが、〜したいことを実現化するのがアクティビティとVb.Netだと思います。
〜したいでパターン化してあげると自然と理解できると思っています。
例としては、ファイルをコピーしたい＝ファイルコピーアクティビティなど。
下記の表は〜したいことに対するモダンとクラシックの対比表です。
モダンとクラシックを使用している場合は、このように提示するとわかりやすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327229/9bfdbb0f-5aee-dd8f-10f4-a62e00deca08.png)
:::


:::note alert
(6)市民開発者のマネジメントをしない。
:::

市民開発者は他業務を行いながら、自身で作成したロボットの保守運用をしています。
何かしらのエラーが出た時には、手作業でフォローしないといけないですし、ロボットの改修もしないといけないため、ロボットの改修見積もりなどを提示しないと焦りや不安になります。

:::note info
(6)の回答
市民開発者からの問い合わせが来たら、すぐにレスポンスし、ロボットの改修見積もりなどを提示しましょう。
私の場合は改修時には、進捗管理も兼ねて改修手順を市民開発者に提供しています。
:::

## 5.おわりに
教え方について初めて書きました。
書いてみると講師・先生という仕事は、楽しませるエンターテインメント性かつ俳優、女優が持つ演じる力が高くないとできないと思いました。
さらに講師・先生は受講者が見ている世界から専門的な世界を行き来ができ、常に受講者の目線から立たないといけないです。

:::note info
人口が少なくなっている今、将来的に教えることができる人は貴重になると思います。
なぜなら教え方がうまいとすぐに本質を理解し、それが次の世代に引き継がれていき、その教えから成長ができたと感じられ時、この会社にいたいと思うからです。
:::
3人寄れば文殊の知恵？ 空をreturnしてはいけない？

# はじめに
今年のカレンダーはとある会社のとあるチームで活動した1年間を振り返っていきます

今回初めてAPI Gateway WebSocket APIに触れたのですが発生したエラーの詳細までは追えないらしく、問題解決までに時間がかかってしまったので簡単にまとめてみたいと思います。

# やりたいこと
- フロントからデータをWebSocket経由でAPIに渡したい
- フロントから受け取ったデータはバックエンドで整形する

# 使用技術
- API Gateway WebSocket API 
- Lambda
- CloudWatch

## 登場人物

### 山田さん：
他チームからヘルプに来てくれた真面目で素直な新メンバー。音声繋いでペアプロしているが声質や話し方が某アイドルグループの某メンバーにそっくり(な気がする)。

### おっとりさん：
山田さんと同じチームメンバーで私と同期。社内ではマスコット的な存在となっている。山田さんと私が担当しているシステムを作り上げた本人。

---

私「こういうエラーが出ているのですが、まるまるうしうしで…(記事では簡単にまとめていますが実際は複雑)」
何か困ったら普段は山田さんと相談していましたが、今回ばかりは複雑な状況だったので、システムの生みの親であるおっとりさんに助けを求めました。

おっとりさん「zoomいきますね」

山田さん「私も一緒にみましょうか」

まずソースコードの確認から始まった。

おっとりさん
「なるほど、ここでprintされているということはこれが動いていて…ふむ」
「ここの分岐に入った後ってどうなってますか？」

私「そこは空でreturnしています」

おっとりさん「API Gatewayって空だと怒ってきたような気がするんですけど、どうでしたっけ山田さん」

山田さん「あ～もしかしたらだめかもしれないですね」

# An error occurred (GoneException) when calling the PostToConnection operation
フロントからデータを送信すると、「Internal server error」のエラーが発生。
バックエンドでエラーが起きていないかCloudWatchからLambdaのロググループを確認してみると、
「An error occurred (GoneException) when calling the PostToConnection operation」のエラーが発生していました。

結論として、該当処理の箇所で空をreturnしないようにすることで解決できました。


```python:sample.py
    if:
    else:
        // returnのみにしない
        return {
            "statusCode": 200,
            "headers": {
                "Access-Control-Allow-Origin": "*",
                "Content-Type": "application/json"
            }
        }
```

# おわりに
私「とても助かりました！ありがとうございます。」

おっとりさん「いえいえ、私もよく忘れるんですよね～」

山田さん「すみません、私もそこはreturnだけしておけば良いと思ってました」

---

今回の件で処理を色々追っていたのでシステムの理解度は深まりました。
API Gatewayも今までなんとなくで触っていたので、ここにきてツケが回ってきてしまいました。
Railsエンジニア向けRubyプロジェクトの始め方

この記事は新米エンジニアの著者の個人開発の経験を元に実践しているプロジェクトの始め方です。追加ですべき作業や、改善すべき箇所などありましたらコメント頂けれると有り難いです。
# はじめに
Railsのプロジェクトは`$ rails init`で、プロジェクトのディレクトリが作成され、ディレクトリ構成について考えずMVCモデルに従って実装を始められます。また、Gemを追加する場合もGemfileに記述することで、Gemを使って実装できるようになります。
この記事は、Ruby単体のプロジェクトを始める際の`$ rails init`の代わりになる手引き書になれば、と考え作成しております。

※ ここでいうプロジェクトとは、業務レベルの大規模なものは想定しておらず、個人で開発する小規模なプログラムを想定しています。「1つの`.rb`ファイルにまとめるには少し大きいけど、複数ファイルに分けるにはディレクトリ構成に悩む」、「グローバル環境を汚したくないからBundlerでGemを管理したい」、「rbenv globalが古いバージョンになっているが、趣味のプロジェクトぐらい最新のRubyを使いたい」のような実装前にもやもやと悩んでしまうことを回避するための記事です。

# 0. ディレクトリ作成
```bash
$ mkdir {project_name}
$ cd {project_name}
```

始めにプロジェクトのディレクトリを作成します。これはプロジェクト名と揃えると良いでしょう。
# 1. Rubyのバージョン指定
```bash
$ rbenv local 3.2.2
```
筆者がRubyバージョン指定にrbenvを使っているためRbenvでの例を記載します。
始めにで上げた「rbenv globalが古いバージョンになっているが、趣味のプロジェクトぐらい最新のRubyを使いたい」という思考を実現するための設定です。
しかし、globalとバージョンを分けるという視点以外にも、数年後にプロジェクトのコードを見返したときにどのバージョンのRubyで実行すべきかという手掛りにもなると考えています。そのためglobalと同じバージョンをプロジェクトで使う場合もlocalでバージョン指定することは利点があると考えています。
# 2. Bundlerの導入
```bash
$ bundle init
$ bundle install
```
必要に応じてdotenvやActiveSupportなど有用なGemlをGemfileに追加し、Ruby単体よりも効率的に作業を進めることができます。
プロジェクトの性質ごとに必要なGemは異なるため、本記事では詳細な説明は省略します

# 3. デイレクトリを構成する
```
$ mkdir lib
$ echo "def method \n  puts 'Hello World!'\nend" > lib/sub_script.rb

$ echo "require './lib/sub_script'" > main_script.rb
$ echo "method" >> main_script.rb

$ ruby main_script.rb
---> Hello World!
```
上のスクリプトは、小規模なプロジェクト向けにメインの処理を書くための`main_scirpt.rb`と、`/lib`配下に切り出した処理を書く構成です。オブジェクト指向でコーディングするなら`/lib`配下には各オブジェクトのクラスを定義したファイルが並ぶ想定です。上記の例では、クラス定義ではなくメソッド定義を切り出したパターンです。
`main_script.rb`以外を`/lib`に定義することで、プロジェクトのデイレクトリ直下にファイルが溢れることを防止しています。プロジェクトのデイレクトリ直下にはGemの設定ファイルを置くことが多いためです。(RubocopやRspec、Dotenvなど)

# 4. 実装開始!!

# おわりに
個人での開発を想定したプロジェクトの始め方ですが、本記事の手法でプロジェクトを始めると、RubyとGemのバージョン情報がプロジェクト内に記録されるためGitを導入することで、用意にコードを実行する環境を他の人に展開することも可能です。
Nuxt3,Vue3でのgenericsの使い方

nuxt3, vue3からpropsにジェネリクスを使えるようになりました。
今回はNuxt3で作成します。

例として以下のような `type="text"`, `type="number"`両方指定できるコンポーネントを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711419/d6cee3a0-fdf1-31ef-0a22-7eb9f3d74d0e.png)


## genericsなし
まずは、ジェネリクスなしで実装してみます。
この状態だと、emitされる値がnumberなのかstringなのか分かりません。

`/components/atoms/Input.vue`
```vue
<script lang="ts">
type Props = {
  inputType?: 'number' | 'text';
  value: number | string;
};

const props = withDefaults(defineProps<Props>(), { inputType: 'text' });

type Emits = {
  // props.valueの型が分からない
  (event: 'change', value: number | string): void;
};

const emits = defineEmits<Emits>();

const onChange = (event: any): void => {
  emits('change', event.target.value);
};
</script>

<template>
  <input :type="props.inputType" :value="props.value" @change="onChange" />
</template>

```
`/pages/index.vue`
```vue
<script setup lang="ts">
const strValue = ref('');
const numValue = ref(0);
</script>

<template>
  <div>
    <!--代入する際、型が分からないのでキャストしないといけない-->
    <AtomsInput :value="strValue" @change="strValue = String($event)" />
    <AtomsInput
      input-type="number"
      :value="numValue"
      @change="numValue = Number($event)"
    />
  </div>
</template>

```

## genericsあり
scriptタグに`generic="T extends number | string"`このように指定します。
すると親コンポーネントで指定された、valueの型が`T`の型となります。



`/components/atoms/Input.vue`
```vue
<script setup lang="ts" generic="T extends number | string">
type Props = {
  inputType?: 'number' | 'text';
  value: T;
};

const props = withDefaults(defineProps<Props>(), { inputType: 'text' });

type Emits = {
  // props.valueの型によってTが変わる
  (event: 'change', value: T): void;
};

const emits = defineEmits<Emits>();

const onChange = (event: any): void => {
  emits('change', event.target.value);
};
</script>

<template>
  <input :type="props.inputType" :value="props.value" @change="onChange" />
</template>
```
`/pages/index.vue`
```vue
<script setup lang="ts">
const strValue = ref('');
const numValue = ref(0);
</script>

<template>
  <div>
    <AtomsInput :value="strValue" @change="strValue = $event" />
    <AtomsInput
      input-type="number"
      :value="numValue"
      @change="numValue = $event"
    />
  </div>
</template>

```
VCIの適切な音量と調整方法

VCIには音声ファイルをつけて任意のタイミングで流したりできますが、どのくらいの音量が適切なのか、わかりにくいかと思います。今まで経験的に設定していましたが、なんか合ってるっぽいので記事にしてみました。

# なぜ、音量調整は必要なのか
VCI製作側からすると、「音量も調整しなきゃいけないのかよめんどくせー」って思うかもしれません。ですが、いくら機能が素晴らしいVCIでも音量が大きすぎると「うるせぇ！！！！」ってなって印象爆下がり。下手すればテロ行為にもなりかねません（割とマジで）。
小さすぎると「なんか鳴ってるな？」で済むので、まだマシです。

# この記事は、こんな人向けに書いてます
・Unityを使って自分でVCIを出力できる
・フリーの音楽編集ソフトAudacityをインストールしている

# 音声ファイルの音量を確認する
1. Audacityで音声ファイルを開く（ファイル＞開く…）
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935496/16c04ca5-8f4d-1669-ffda-5a0c0c10c1d0.png)
1. 再生ボタンをクリックして音声ファイルを再生する
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935496/e155408c-4059-0490-da31-e6866e31e5e5.png)
上下に同じ波形が2つあるのはステレオ（左右）だからです。
横軸が時間、縦軸が音量（みたいなもの）です。中心がゼロ。
1. 最大音量を確認する
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935496/c06c71b9-ef86-426b-45c1-81c1e9ae7fe8.png)
赤枠の中が再生中の音声ファイルの音量になります。数字の単位はdB（デシベル）で最大値が0です。
最大音量は青線で表示されます（再生終了後も残ってます）。
画像から、この音声ファイルの最大音量は-1dBくらいだとわかりました。
どの程度が適切かは、後述します。

# 音声ファイルの音量を調整する
1. トラックバーにある「ゲイン調整」をいじる
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935496/69a7fc3a-4909-0bd8-ef78-ad8b48ec2610.png)
画像の赤矢印の先の－と＋の間にあるツマミをドラッグして左右に動かすと、「ゲイン調整：-5dB」みたいな表示が出てきます。これで-10dBくらいにしてみてください。経験的には、-10dBとか-15dBにしちゃっていい感じです。
1. 調整した結果を確認する
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935496/539cd998-112e-0a4f-5744-69871fb2a021.png)
最大音量を示す青線が-12dBくらいになりました。調整の目安ですが、個人的には調整後に-10dB～-15dBの間くらいになってればいい感じな気がします。ちょっと調べてみると、
[宇都木昭研究室](https://sites.google.com/site/utsakr/Home/phonetics/recording)
では、
「音が最も大きいときで-6～-12の間あたりにおさまるようであれば，適切な音量」
[動画・映像編集時の音（オーディオ）のレベル調整の目安](https://zatta.link/video/adjustment-audio-level-in-decibel-and-loudness.html)
では、
「全体のターゲットレベル : -6dBFS ～ -10dBFS
　音声（会話・ナレーション等） : -8dBFS ～ -12dBFS
　音楽（BGM）：-18dBFS ～ -30dBFS
　効果音：-6dBFS ～ -10dBFS」
らしいです。単位がdBFSとなってますが、dBと同じなので気にしなくていいです。
1. 調整した音声ファイルの保存
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935496/32dfee21-2aac-8a10-8991-d9fd17c38739.png)
いい感じに調整できたら、名前を付けて保存して完了（ファイル＞オーディオの書き出し…）

後はVCIに仕込んでおしまい！

お借りした素材
[MindCoreCarbon VRChat WorldBGMs](https://booth.pm/ja/items/3867755)
ちなみに、以下のルームで-10dBした音声ファイルを使っています。
[MEMENTMORI](https://virtualcast.jp/rooms/m3GcVMgkWX6XioGa)
textlintでtypo検出を賢くできないかを試してみている


この記事は、[Qiita株式会社のカレンダー | Advent Calendar 2023 - Qiita](https://qiita.com/advent-calendar/2023/qiita-inc)の8日目の記事です。

https://qiita.com/advent-calendar/2023/qiita-inc

---

textlintでtypo検出を賢くできないかを試しているので、それについて紹介します。

## 解決したい課題

textlintでtypoを検出できるルールの代表として以下があります。

https://github.com/io-monad/textlint-rule-common-misspellings

https://github.com/textlint-rule/textlint-rule-prh

いずれも、

```
abandonned->abandoned
aberation->aberration
abilityes->abilities
abilties->abilities
abilty->ability
```

のように正誤の辞書があり、それにマッチしなければtypoを検出することができません。

（もしかしたら、僕が見つけれていないだけで既にあるかもしれません）

また、新しいtypoが出てきた際に辞書に追加していく手間もあります。

そのため、未知のtypoがあったとしても正しい単語の辞書だけで検出したいと思いました。

## やったこと

fuzzy finderのように正しい単語にある程度近い場合は、typoの恐れがあるとして検出するようにしてみました。

正しい単語と似ているかにはレーベンシュタイン距離を使い、一定の距離よりも近い場合はtypoとするようにしました。

https://qiita.com/tanuk1647/items/5a591da10e2ea5bedef6

そして、試しにつくったtextlint ruleは以下です。

https://github.com/ohakutsu/textlint-rule-typo-detection

現時点では、以下のように`.textlintrc.json`を設定することで使えます。

```json
{
  "rules": {
    "typo-detection": {
      "dictionary": ["world", "word"]
    }
  }
}
```

ですが、日本語の単語より英単語のほうが1単語あたりの文字数が多いことがあるため、typoかどうかを決めるほどよい距離のしきい値を決めるのが難しいなと感じています。
また、文章を単語に区切るのにword boundaryを使っているため、複数単語をあわせたもの（例: `Google Cloud`など）での検出ができないのが現状です。

## 最後に

もう少し改良ができそうとは思っているので、気長に改良していければと思います。
また、Pull Requestやコメント等いただけると嬉しいです！

---

記事を読んでいただきありがとうございます！
ぜひ、[Qiita株式会社のカレンダー | Advent Calendar 2023 - Qiita](https://qiita.com/advent-calendar/2023/qiita-inc)を購読設定して、明日の記事もご覧いただけると嬉しいです。
umask コマンドとは

Linuxの勉強をしていて初見のコマンドだったのでメモ

# umaskとは

ファイル・ディレクトリ作成時のデフォルトの権限を設定するためのコマンド/値

使い道としては
1. umask値の確認
1. umask値の変更
に使える。

## umask値とは

何も設定せずにファイル/ディレクトリを新規作成すると、ファイルの場合は666(rw-rw-rw-),ディレクトリの場合は777(rwxrwxrwx)で作成される。
これだと権限的に危ないので、umask値を使ってデフォルトの権限を設定することで権限を管理することができる。

例えばumask値が `022` に設定されている場合は

- ファイル: 666 - 022 = 744
- ディレクトリ: 777 - 022 = 755

で作成される。(引き算は各桁で繰り下がりなし)

## 使い方


引数なしで実行した場合は現在のumask値が表示される
```
$ umask
022
```
この状態でファイル・ディレクトリを作成するとこうなる
```
$ ls -l
total 0
drwxr-xr-x  2 xxx  xxx  64 12  7 20:20 hoge
-rw-r--r--  1 xxx  xxx   0 12  7 20:20 hoge.txt
```

引数にumask値を渡して実行すると該当のシェルのumask値が変更される(ログアウトすると消える)
```
$ umask 222
```
この状態でファイル・ディレクトリを作成するとこうなる
```
$ ls -l
total 0
dr-xr-xr-x  2 k.tanaka  staff  64 12  7 20:21 hoge
-r--r--r--  1 k.tanaka  staff   0 12  7 20:21 hoge.txt
```
キャッシュの使いどきと各層での使いかた

## この記事は？
この記事は アイスタイル Advent Calendar 2023/12/15の記事です。

こんにちは。アイスタイルで[@cosme](https://www.cosme.net/)の開発を担当しているエンジニアの村田です。今回は[@cosme](https://www.cosme.net/)でのキャッシュの使い方にも一部触れながら、キャッシュの使いどきと各層での使い方を解説します。

## キャッシュの使いどき
キャッシュはいわゆる永続層とは異なり、データが揮発しても良い部分に使うようにします。キャッシュには適切なTTL(Time To Live)を設けることで適切な有効期限を設けるとともに、適切なタイミングで更新するようにします。また、キャッシュのサイズが大きすぎるとサーバーのメモリーを圧迫してしまい予期せぬ挙動となることもあるので、不要なキャッシュは残さないようにするほか、サイズだけではなく、キャッシュを行う粒度に関しても適切な設計である必要があります。運用の開始後は、エビクションやヒットレートなどの情報を収集しておくことで、実装したキャッシュが意図通りに使われているか監視を行うことができて便利です。

**※エビクション**: キャッシュのメモリーが飽和状態のとき、溢れた情報を削除する。どのデータを削除するかはエビクションポリシーに従う。
**※キャッシュヒットレート**: CPU内部のキャッシュメモリーに目当てのデータが存在する割合。必要なデータがないことはキャッシュミスという。

## ・DBサーバー
DBのキャッシュです。DBサーバーのキャッシュの代表的な仕組みの一つとして、バッファプールがあります。バッファプールを使うことで、アクセス頻度の高いデータページをメモリにキャッシュできるほか、インデックスのキャッシュに関しても行うことが可能です。データは構造が複雑で、規模が大きくなるほど検索に時間がかかるようになりボトルネックになるので、まずはDB層で的確にキャッシュで高速化を行なっておきたいです。
## ・APサーバー
開発エンジニアであればキャッシュと聞いてAPサーバーで行うキャッシュが最も馴染み深いのではないか？と思います。ここでは、@cosmeメディアのAPサーバーにおけるキャッシュを考えてみましょう。ログインの仕組みはセッションキャッシュで実現されます。レスポンスを返すところで、特にキャンペーンなどアクセスが集中すると大量のクエリが発行されてDBサーバーへの負荷になってしまうため、@cosmeメディアではMemcachedといったインメモリキャッシュを採用することでデータキャッシュを行い、DBサーバーへの通信による負荷を最大限防ぐようにしています。
## ・Webサーバー
Nginxは代表的なWebサーバーで、**リバースプロキシ**としてキャッシュの機能を持たせることができます。リバースプロキシでは、リクエストに対する応答をキャッシュに保存しておき、リクエストが来たときにキャッシュがないとAPサーバーに転送するような仕組みをとってキャッシュを実現しています。本丸のAPサーバーにリクエストを届ける前でキャッシュできる前座のサーバーであると言っているといっていいでしょう。
## ・CDNサーバー
CDNもキャッシュを行うサーバーですが、先ほど紹介したリバースプロキシとはキャッシュの機構が違うため、注意が必要です。CDNでは、キャッシュサーバーが配信を行い、キャッシュがない場合はオリジンサーバーまでデータを取りにいくことで配信を実現しています。そうすることで、コンテンツ配信の最適化を行うことができるのです。CDNは各地のエッジロケーションからデータを配信するので、地域最適化や高速化に対して適したものになります。


## ・API ゲートウェイ
APIゲートウェイはAPIの管理に関心を持つ層で、それぞれのAPIに対して統括を行うような部分です。API ゲートウェイは、APIリクエストの応答を一時的にキャッシュし、同じリクエストに対して返すことでキャッシュを実現できます。キャッシュをどれくらい保持するかに関してはTTL(Time To Live)によって適切な時間を設定するようにします。
## ・クライアントキャッシュ
クライアントキャッシュに関する代表的なものとして、**ブラウザキャッシュ**があるので、ここではブラウザキャッシュを中心に説明します。ブラウザキャッシュのうち強いキャッシュは、ブラウザがサーバーに再度リクエストを送ることなく、キャッシュされたコピーを使用するよう指示するもので、サーバーにリクエストを送った上でキャッシュコピー使用を指示する弱いキャッシュとは異なっています。こういった特徴から、強いキャッシュはバナーなどの静的な部分に、弱いキャッシュは変化がある動的部分のキャッシュに適しています。


**・強いキャッシュ**
Expires ヘッダー
Cache-Control ヘッダー

**・弱いキャッシュ**
Last-Modified ヘッダー
ETag ヘッダー


クライアントキャッシュは、使用端末上のストレージに保存されます。ストレージへの負荷を下げるためにも、不要なものは削除するようにしましょう。

## 終わりに
本記事では各層にあるキャッシュの仕組みを紹介してきました。キャッシュは、知識がバックエンド寄りであればRedisなどAPサーバーのキャッシュに、クライアントサイド寄りだとクライアント寄りのブラウザキャッシュなど濃淡がつきやすい印象ですが、各層で的確なキャッシュをすることで最適化を行いたいものです。それぞれの層でのキャッシュを組み合わせることによって、大規模リクエストにも耐えられる仕組みの実現ができます。


## カジュアル面談
アイスタイルでは@cosmeを始めとした各種サービスを展開しています。Node.jsを使った開発、アイスタイルでの開発に興味を持たれた方は、ご気軽にカジュアル面談をお申し込みください。

https://open.talentio.com/r/1/c/isytyle_career/pages/74996
同時接続環境の負荷試験であったこと

本記事は [オルトプラス Advent Calendar 2023](https://qiita.com/advent-calendar/2023/altplus2023) の12/20の記事です。

# :christmas_tree:はじめに
はじめましての方は初めまして。
初めてじゃない方はおはようこんにちわこんばんわ。
オルトプラスの自称賑やかし担当兼サーバーサイドエンジニアすがやです。
今回は同時接続の負荷試験を実施した時の体験談に関しての記事になります。

# :christmas_tree:仕様や構成等
今回のゴール地点は最大８０００人が同時接続できる汎用的なロビー機能になります。
この８０００人はランダムに移動を繰り返したりアクションを起こしたりします。
仕様ツールは下記の通りです。
|内容|採用しているもの|
|:-:|:-:|
|環境と言語|Node.js + TypeScript|
|負荷試験ツール|k6|
|インフラ|AWS環境|

上記を用いて、nodejsのインスタンスを複数作成し、ALBで接続先をある程度分散させ、Redisのpub/subの仕組みを用いて、ユーザーがどのインスタンスに接続しても座標等の共有が可能なようにしました。

# :christmas_tree:実際に負荷試験をかけて起きた主な不具合
1. エモートを１回送信すると、複数回エモートが受信される。
2. 負荷試験中に突然止まる。
3. エモートを送信してもすぐに受信されない。
4. 画面がカクツク。

### ☆原因と解決の道のり
#### 1. エモートを１回送信すると、複数回エモートが受信される。
こちらの現象はローカルの環境では確認できず負荷試験環境でのみ確認することが出来ました。
エモートは複数種類あるのですが特定のエモートではなくランダムに現象が起きました。
この現象が起きる場合と起きない場合がありました（こういうの困る。本当に困る）

そこでログを確認し送信が1回であることを確認しました。
受信側のログで複数回出ているログを確認しました。
色々試した結果インスタンスが複数ある場合に怪しいのではないかと仮説を立てました。
実際のところ起きていた現象と手順は以下になります。
　1. ルームにAさんが１番のインスタンスから接続します。
　2. Bさんが２番のインスタンスから接続します。
　3. Aさんがエモート送信します。
この手順を行うと仕組み上１番のインスタンスと２番のインスタンスそれぞれでエモート情報を受信していることが分かりました。
そのためBさんはエモートが2回受信されるという不具合につながります。
プログラムで該当箇所を確認ご修正して解決しました。

#### 2. 負荷試験中に突然止まる。
こちらもローカルでは再現できませんでした。
ただ負荷試験環境で試したりログを確認しているうちにトリガーがあることに気づきました。
ダミーユーザーの接続が切れたタイミングで動かなくなっているかもしれない。
原因となる接続を切ったタイミングでログを追加して確認したところ切断時の処理に原因を発見しました。
```diff_*
socketList.splice(index, 1);
```

socketListには接続者一覧の情報があるんですが誰かが切断すると削除されてしまうようになってました。
切断時の処理に関して別のPJのコードを流用していたのですが、運用実績のあるコードとして扱っていたのでなかなか見つかりにくかったですね。

#### 3. エモートを送信してもすぐに受信されない。4. 画面がカクツク。
こちらに関してはどこかのタイミングで負荷が高すぎるため起きている現象なので試験方法を変えるところから検証を始めました。

# :christmas_tree:高負荷を解決するまでの道のり
不具合の修正後は高負荷状態を解決するための試行錯誤が始まります。
今までは一度に８０００人のダミーユーザーを追加していたのですが、２００人程度から動作確認することから始めました。

**が…**

200人の同時接続すら実現していないことがわかりました。
なので最初の目標としてまず２００人の同接を目指すことにしました。
原因としては一部データの送受信時にpub/subを経由するのに時間がかかっていました。
これを解決するために試したことは以下の通りです。

1. 負荷試験環境のサーバースペックを上げる
⇒特に効果なし:cry:

2. Redisのインスタンスを1台から10台に変更してpub/sub経由を分散させる
⇒AWS側を色々確認して見ると使用しているpub/subで経由するRedisのインスタンスが偏っていそうでした。
しかし、理由がわからなかったためこちらはAWSに問い合わせをし、回答を要約するとwebsocketの仕様のようでした。
この偏りについてはドメイン+ALB+ECSタスクの組を増やして、ある程度アプリ側で接続先を均等化することで解決します。

3. まだまだ解決しなさそうなので一度Redisを経由しない場合どれだけ違いが出るか検証をしました。
理論上はRedisを経由しなければ最速で座標等の情報が共有がされるはずだからです。
⇒そこまで違いは出なかったのでRedisが悪いわけではないことが分かりました。

4. 送信＆受信データの確認をしました。
負荷試験時は秒間8回の座標データを送っていたのですが一旦秒間1回に変更しました。
これで２００人が問題なく動くことを確認できました。
⇒ということで通信データを精査することにしました。
ちなみにこの対応で２０００人が同接可能な状態で、目標まであと６０００人です。

5. 送信データの精査
よくよく送信データを観察すると座標の移動がないのダミーユーザーの座標も送っていました。
そのため座標が変わらない場合は送信しないように対応しました。
また、setTimeoutを使って送信に関しては非同期に実行するようにしました。
⇒この改修で６０００人まで接続可能になり、目標まであと２０００人です。

5. Clusterモジュールの導入
色々インターネットで色々調べているうちにClusterモジュールの記事を見つけたのでこちらの導入を行いました。
劇的な変更が見られました。
⇒こちらの対応で８０００人を達成して目標クリアしました:tada:

# :christmas_tree:全体を通じた感想
一部の不具合は運用実績のあるコードを信用したため発見するのが割と困難になりました。
流用することによって工数を削減できるのは確かなのですが、今回の様なこともあるため、今後も気を付けていきたいなとは思います。
負荷試験で使用したk6というツールを今回初めて使用しました。
今まであまり負荷試験自体作業として携わったことがないため、良い経験になったと思います。

### 今後もよき同時接続ライフを！
PhoenixにてStripe決済のWebhookの実装でハマったので備忘録を書く

この記事は「Elixir Advent Calendar 2023」●日目の記事です
東京にいるけどfukuokaexのYOSUKEです。

普段は 合同会社TheWaggle で教材開発・システム開発・研修講師などマルチに活動してます。

 TheWaggleでは、Elixirを学びたい人を増やすためにコンシューマ向けにエンジニアスクールを開校しようと準備中です。プログラミング教室との違いは、エンジニアとして戦力になれる人の育成を目指してます。その為、Elixirの案件を増やす為にも今年から開発事業部を作り　自社プロダクトと他社プロダクトの作成を開始しました。

今期はアジャイルの開発とウォーターフォール形式の開発をそれぞれ一件ずつ着手したのですが、来期以降は完全にアジャイル開発のみに踏襲していく予定です。

教育系システム開発と教育コンテンツ開発には自信があります。

---

## 決済サービスはお好きですか？
と言うことで、つい先日 Square決済サービスで開発して、ローンチ前日にお客様の契約したSquareから取引できないとの返答が、えー！と言う事態が起こり、急遽、Stripe決済に切り替えると言うことで短期間で２つの決済システムをゴリゴリ書いておりました。

いや、最近はこういったサービスがあるので簡単に導入できるなんて、楽勝ですねw　と思ってたらStripeのWebhookでハマったのでハマった箇所と回避策を備忘録として書いておきます。

## 余談ですが、なぜSquareがNGだったのか？
ちなみに、既出の課題で知る人は知っている事と思いますが、Squareが取引不可となった理由は、CtoCサービスの決済を構築しようと見えてしまった事でした。実際には、BtoBtoCのビジネスサービスですが、CtoCと勘違いされてしまったようです。ただし、一度勘違いされたら申し立ても再考もされません。
クレジットの信用調査でNGになるので、どうすることもできません。

おとなしく、決済サービスを変える他ありません。と言うことでStripeに変更する事にしました。

## StripeのPaymentLinkを利用した決済サービスの構築
Stripeの決済サービス構築は、[stripity_stripe](https://hex.pm/packages/stripity_stripe) のモジュールがあるのでとても簡単でした。

が、しかし！　Webhookのところで少しハマって色々調べ、最終的には「stripity_stripe」のモジュールの中まで読んで、それでも原因が掴めず、一旦、他の言語（Nodejs)で実装して動くことを確かめてもうまくいかないというお悩みを抱えて、結果、エンドポイントをいじって解決しました。


## エンドポイントに追加
Webhookでハマったのは、 ヘッダーにstripeからの送信を保証する用途として送られてくる 「stripe-signature」 を受け取り、シークレットキーと 一緒に送られてくるBodyの要素を照らして、この送信は問題ないか確認するところで、「:OK」ルートに辿り着けない現象に悩まされてました。

## 最後にわかった、原因
試行錯誤でたどり着いたのは、Plugでbodyの要素が生データではなくなっている事に気がつき、解決策は、Endpoint時点でカスタムプラグを作って、生データをassignで突っ込んで渡しました。

```elixir

  # Stripe Webhook用 カスタムプラグ
  plug :put_raw_post, only: ["/webhook/v1"]

  def put_raw_post(conn, opts) do
    case conn.path_info do
      ["webhook", "v1"] ->
        {:ok, raw_body, conn} = Plug.Conn.read_body(conn, opts)
        Plug.Conn.assign(conn, :raw_body, raw_body)
      _ ->
        conn
    end
  end
```

これで、controller側で実装した際に受け取った生データを参照してstripeからの送信だと判定してその後の処理をするということが解決できました。

## 気がつかなんだー、最後にそんな実装すら必要なかったというオチw
さて、最後にめでたしめでたしと思っていた所、実は上記のようなことは一切不要だったというオチがついてきます。
実は、``` pipe_through [:api]```こいつが邪魔してただけ。

```elixir
  scope "/webhook", TestWeb do
    pipe_through [:api]

    post "/v1", Api.StripeWebhookController, :handle
  end
```

ということで、以下のようにすれば、わざわざ カスタムプラグを作らなくてよかったというオチです。

```elixir
  scope "/webhook", TestWeb do
    post "/v1", Api.StripeWebhookController, :handle
  end
```

ただ、このおかげで、色々と理解が深まったので、良い勉強になりました。w
gitでコミッターを変更する手順

本業と副業でgitアカウントを複数個持っていたりすると別の組織のアカウントでコミットしてしまうことがあると思います。そんな時に役立つコミッターを変更する手順です。

1. ログの確認
    ```
    git log --oneline
    ```
1. 変更したいコミットまでrebase
    ```
    git rebase -i #{変更したいコミットの1つ前のコミットID}
    ```
1. コミットを編集モードに
    2を実行するとターミナル上にエディタが開くので変更するコミットの先頭の`pick`を`edit`に変更します。変更できたら`:wq`でエディタを抜ける
1. コミッターの情報を入れる
    ```
    git commit --amend --author="sample_name <sample_name@example.com>"
    ```
    
    リモートのgitアカウントのユーザー名とメールアドレスを指定します
    ユーザー名とメールアドレスは以下のコマンドで確認できます
    ```
    git config user.name
    git config user.email
    ```
1. rebaseの続行
    ```
    git rebase --continue
    ```
1. リモートへpush
    ```
    git push --f origin target_blanch
    ```
RaspberryPiでProxy設定をする


# Raspberry Pi で Proxy 設定をする

Raspberry Pi で Proxy 設定をする方法をまとめます．

## 各種設定ファイルの編集

```bash:/etc/apt/apt.conf.d/apt.conf
Acquire::http::Proxy "http://proxy.example.com:8080/";
Acquire::https::Proxy "http://proxy.example.com:8080/";
Acquire::ftp::Proxy "http://proxy.example.com:8080/";
Acquire::socks::Proxy "http://proxy.example.com:8080/";
```

```bash:/etc/environment
http_proxy=http://proxy.example.com:8080/
https_proxy=http://proxy.example.com:8080/
ftp_proxy=http://proxy.example.com:8080/
```

```bash:~/.bashrc
export http_proxy=http://proxy.example.com:8080/
export https_proxy=http://proxy.example.com:8080/
export ftp_proxy=http://proxy.example.com:8080/
```

完了．
【IBM Business Automation Workflow】Coachのオブジェクトを非表示にする

Coachのオブジェクトの表示・非表示を動的に切り替えようとして、ドキュメントを探すのに苦労したので、メモしておきます。

## 方法

### 表示領域を確保したまま、表示・非表示を切り替える

visibility:hiddenですね。

```
// 表示する
${対象のコントロールID}.setVisible(true);

// 非表示にする
${対象のコントロールID}.setVisible(false);

```

#### 例

```
${My_Control}.setVisible(true);
${My_Control}.setVisible(false);
```

### 表示領域を残さずに、表示・非表示を切り替える

display:noneですな。

```
// 表示する
${対象のコントロールID}.context.setDisplay(true);

// 非表示にする
${対象のコントロールID}.context.setDisplay(false);
```

#### 例

```
${My_Control}.context.setDisplay(true);
${My_Control}.context.setDisplay(false);
```

## 詳細

https://www.ibm.com/docs/en/baw/23.x?topic=this-context-object
AtCoder初心者 DailyTrainingメモ 2023/12/07

# ABC292 B-問題
https://atcoder.jp/contests/adt_easy_20231206_1/tasks/abc292_b

![292B.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547298/a9f0527c-9a5c-31ed-7ad3-32b2a67e61fc.png)

**ポイント**
背番号をキーにイエローカードで +1 、レッドカードで +2 して
イベントナンバー3の場合に対象背番号の累積値を判定する

# 辞書に格納してカウントする方法
````Python:292B.py
from collections import defaultdict

N,Q = map(int,input().split())

dic = defaultdict(int)

for _ in range(Q):
    num, player = map(int,input().split())
    if num == 1:
        dic[player] += 1
    elif num == 2:
        dic[player] += 2
    elif num == 3:
        if dic[player] >= 2:
            print("Yes")
        else:
            print("No")
````

# 配列に格納してカウントする方法
````Python:292B-2.py
N,Q = map(int,input().split())

# インデックスで管理するので、先頭にゼロ番を追加する
arr = [0] * (N + 1)

for _ in range(Q):
    num, player = map(int,input().split())
    if num == 1:
        arr[player] += 1
    elif num == 2:
        arr[player] += 2
    elif num == 3:
        if arr[player] >= 2:
            print("Yes")
        else:
            print("No")
````

# ABC213 B-問題
https://atcoder.jp/contests/abc213/tasks/abc213_b

![213B.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547298/08cfc837-d1f1-a460-4b02-156f09e2f32b.png)

**ポイント**
・得点とインデックスの順で二次元配列に格納し、降順ソートする
・ブービー賞なので、先頭から２番目の選手の番号を回答する

# 辞書に格納してカウントする方法
````Python:213B.py
N = int(input()) 
A = list(map(int, input().split()))

ans = [] 
for i in range(N):
    # 二次元配列で、得点　と　順番　を格納する
    ans.append([A[i],i + 1])

# 得点を大きい方からソート
ans.sort(reverse=True)

# 前から 2 番目（インデックスでは、１）の人の並び順を出力する
print(ans[1][1])
````