OmniAICreator/Qiita-1.07M huggingface dataset:
【SamuraiStats】1. 日本人メジャーリーガーの成績をスクレイピング

初投稿です。
日本人メジャーリーガーの成績を一目で見たい、と思い JavsScript でコーディングしました。
とりあえずスクレイピングの基礎は完成したよ、という記事です。

## きっかけ
プロ野球（NPB）観戦が趣味なのですが、最近は日本人メジャーリーガーの活躍が目覚ましく、ヌートバーの活躍も嬉しいということで、彼らの成績チェックも日課になっています。

メジャーの試合時間は、日本時間だとだいたい深夜～昼前くらいです。
おかげで、朝はメジャー、夜はプロ野球と野球に囲まれて楽しい日々です。
ちなみにロッテファンです。

成績のチェックは [スポナビ](https://baseball.yahoo.co.jp/mlb/japanese/players/) さんにお世話になっています。
ただ、成績を確認するには各選手のページか、所属チームの試合ページを開く必要があり、**一括で見れないのが手間**でした。

そこで、今回のコーディングに至りました。
ChatGPTの協力のおかげで思ったよりスムーズに書けました。

## コード
さっそくですが、現状のコードです。~~コード全体は [Github]() にあるので、重要な部分だけ貼り付けようと思います。~~ →Twitter API周りの情報もあるので一旦非公開。この記事にあるコードで十分なはず。
レポジトリ名は **scrapingTest** となっていますが、**SamuraiStats** に変える予定です。

### インポート
```js
import axios from "axios";
import cheerio from "cheerio";

const url = "URL"

axios.get(url).then((response) => {
  const html = response.data
  const $ = cheerio.load(html)
//ここから先は下記
})
```
めっちゃ雑談：axiosとcheerioをインポートして使用しています。ChatGPTにおすすめされました。  
一応、「PuppeteerとCheerioどっちにする？」と聞かれたので、比較して選択しましたが、再現性が低いな～知識つけなきゃな～と思ったり。とりあえず今回はコーディング優先。

### パーツとなる関数
#### ①CSSセレクタを使って要素を指定し、取ってきて、returnする。

"fetchToArray"となっているが、array以外でも使うことになるので名前変更しなきゃいけない。
```js
      const fetchToArray = (cssSelector) => {
        let returnArray = [];
        const elements = $(cssSelector);

        //セレクタに一致する要素がない時、エラーを吐く
        if (elements.length === 0) {
          throw new Error(`No elements found for selector: ${cssSelector}`);
        }

        elements.each((i, e) => {
          returnArray.push($(e).text().trim());
        });
        return returnArray;
      };
```

#### ②取ってきた要素の配列2つをつなげる。
Tableからヘッダ（th）とデータ（td）を別々で取ってくるため。
```js
      const mergeTableArrays = (headArray, dataArray) => {
        let returnArray = [];
        if (headArray.length === dataArray.length) {
          for (let i = 0; i < headArray.length; i++) {
            returnArray.push(headArray[i] + "：" + dataArray[i]);
          }
          return returnArray;
        } else {
          console.error("dataLength don't match");
          console.error(`array1.length: ${headArray.length}`);
          console.error(`array2.length: ${dataArray.length}`);
        }
      };
```

### 使用例
```js
      //名前の表示
      const name = fetchToArray("#contentMain > div.bb-centerColumn > div > div.bb-modCommon01 > div > div > div.bb-profile__data > ruby > h1");
      console.log(name);

      //最新試合成績の表示
      const recentStatsHeader = fetchToArray("#game_b > thead > tr > th");
      const recentStatsData = fetchToArray("#game_b > tbody > tr:nth-child(1) > td");
      const recentStats = mergeTableArrays(recentStatsHeader, recentStatsData);
      console.log(recentStats);
```
以下が出力したログです。
```shell
(1) ['吉田 正尚']
(11)  ['日付：5月25日', '対戦チーム：エンゼルス', '打数：4', '安打：1', '本塁打：0', '打点：0', '得点：1', '三振：0', '四球：0', '死球：0', '打席結果：一併打、中２、二ゴロ、一ゴロ']
```
こんな感じでスクレイピングできました。

「名前の表示」において、「fetchToArrayがarrayを返していない、nameという名称もよくない」という問題があり、そのほかにも
- データベース構築：おそらくLocalStorageを使用
- 指定日時に更新を確認し、更新があれば成績を取得しなおす
- できればツイートする  
- 各選手にまつわる絵文字をつける。成績に応じて増減する
- 非同期処理まわりの理解

……等々、タスクが残りまくっていますが、とりあえずスクレイピングの基礎は完成。
月2本程度で記事を書いていければと思うので、次回のネタになると思います。
ほな、また。

記録：初挑戦：import/export
rbs subtractを使ってみる


## この記事は何

記事投稿キャンペーン「[【RubyKaigi 2023連動イベント】みんなでRubyの知見を共有しよう](https://qiita.com/official-events/4d2a9eed42dbe0a4af21)」の参加記事です。
この記事では、「Let's write RBS!」で取り上げられていた`rbs subtract`について紹介します。

スライドは↓です。

<script defer class="speakerdeck-embed" data-id="923f0e7ecfa240239e9cf7e1ff75c91c" data-ratio="1.77725118483412" src="//speakerdeck.com/assets/embed.js"></script>

## `rbs subtract`について
`rbs subtract`については以下の記事に詳しく書かれていますが、二つのrbsファイルのうち、定義が重複しているものを片方から削除することができるようなコマンドです。

https://hackmd.io/seoMijXwRdG2uFITm2lLqw

以下のような二つのRBSファイルがあったときの例を考えます。

```rb:a.rbs
class Example
  def hello: (untyped name) -> ::String
  def good_morning: (untyped name) -> ::String
end
```

```rb:b.rbs
class Example
  def hello: (::String name) -> ::String
end
```

この二つのRBSファイルに以下のコマンドを実行をします。

```sh
$ rbs subtract a.rbs b.rbs
```

このコマンドの実行結果は以下のとおりです。

```rb:実行結果
class Example
  def good_morning: (untyped name) -> ::String
end
```

このように、`b.rbs`で定義されている型が`a.rbs`から削除されたRBSが結果として返ってきました。

## `rbs subtract`を使うことでできること

このコマンドが必要になる場面はズバリ「自動生成された型を自分で修正したい場合」です。
このコマンドがない場合、`rbs prototype`などで生成された型をより厳密に記述するようにしたい場合、
RBSファイルは重複した定義があるとエラーになるため、直接自動生成されたファイルを修正する必要があります。

しかしこのような対応を行うと、ぱっと見で「どの型は修正済みで、どの型は修正できていないのか」を把握するのが難しくなります。

`rbs subtract`を使うと、以下のようなフローでインクリメンタルに型の改善を行えます。

1. 自動生成されたRBSファイルから、修正したい型を把握する
1. 自動生成された型を修正したものを別ファイルに記述する
1. `rbs subtract`コマンドを用いて、修正した型を自動生成されたRBSファイルから削除する

このサイクルを回すことで、自動生成されたRBSファイルをTODOリストのように扱うことが可能になります。

## 参考文献

https://hackmd.io/seoMijXwRdG2uFITm2lLqw
<script defer class="speakerdeck-embed" data-id="923f0e7ecfa240239e9cf7e1ff75c91c" data-ratio="1.77725118483412" src="//speakerdeck.com/assets/embed.js"></script>
gridでアコーディオンメニューの実装

# はじめに
今回は、アコーディオンの開閉部分をgridでおこなう方法があることを知ったので、備忘録として記事にしました。

# （私が知ってた）今までの実装
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="poxQXLO" data-user="mgkita" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mgkita/pen/poxQXLO">
  accordion height</a> by chisato (<a href="https://codepen.io/mgkita">@mgkita</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

１．コンテンツの高さ（.accordion__body部分）に初期値として`height: 0px;`をcss設定し、コンテンツが表示されないようにする。

```scss
.accordion__body {
  height: 0px;
  overflow: hidden;
  transition: height 0.2s ease-out;
}
```
さらに`overflow: hidden;`をつけることで、高さ（height: 0px;）を超えるコンテンツ（accordion__text部分）を表示しないようにしています。

２．JSでクリック時のコンテンツの高さを計算することでアコーディオンを開閉させる。
```javascript
if (content.style.height) {
  content.style.height = null;
} else {
  content.style.height = content.scrollHeight + 'px';
}
```
コンテンツ要素の高さ（height）をチェックし、値が存在する場合はnullに設定。
存在しない場合はコンテンツの実際の高さ（scrollHeight）に設定します。

これで、アコーディオンの開閉ができるようになります。

# gridでの実装
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="xxyMENg" data-user="mgkita" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mgkita/pen/xxyMENg">
  accordion grid</a> by chisato (<a href="https://codepen.io/mgkita">@mgkita</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

１．.accordion__bodyにdisplay: grid;を設定、grid-template-rowsプロパティを使用して、コンテンツの行の高さを制御する。

```scss
.accordion__body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.2s ease-out;

  &[aria-hidden="false"] {
    grid-template-rows: 1fr;
  }
}

.accordion__inner {
  overflow: hidden;
}
```
初期状態は、`grid-template-rows: 0fr;`とすることでコンテンツを非表示。
[aria-hidden="false"]で`grid-template-row: 1fr;`とすることで高さがつき、開閉するようになってます。

:::note info
[aria-hidden="false"]は、[WAI-ARIA](https://developer.mozilla.org/ja/docs/Learn/Accessibility/WAI-ARIA_basics)とよばれるアクセシビリティを考慮した仕様のなかで定義されているaria属性のひとつ

　　|コンテンツが閉じている状態|コンテンツが開いている状態
---|---|---
aria-expanded（ボタン側）|false|true
aria-hidden（コンテンツ側）|true|false
:::

ボタン側でもaria-expandedで制御先（コンテンツ側）が展開しているかどうかの設定が必要なため、JSで設定をおこなっています。

今回で属性で開閉させるアクセシビリティを考慮した実装についても知ったので、このあたりについてはまた別で記事にできればと思います。

# おわりに
アコーディオンひとつとっても実装の仕方は色々あって、どれを採用するかは求められているものによるんだろうなと感じました。（アニメーションの有無や、アクセシビリティにどれだけ力を入れるかなど）

ただheightを使って高さを出すやり方だと、style属性でのつけ外しでHTMLタグに空のstyle属性がつくことや、JSでheightの計算をしないといけないところを、gridだとCSSだけで高さ問題が解決するのは大きな学びとなりました。

以下参考資料
https://keithjgrant.com/posts/2023/04/transitioning-to-height-auto/
私のAWS資格取得ノウハウ

## 記事の目的
ある程度AWS資格の勉強を進めた中で得た学びのシェア、意識していることの共有

## 記事の対象者
AWSの資格を取ろうと思っている人、勉強の仕方にいまいち自信がない人

## 自己紹介
 AWS JAPAN 認定エンジニア、所有資格SAP、DOP、MLS、DAS

## 以降本文
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/42c19d8f-831f-49e6-ef94-74bf7439bd39.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/0172b195-8f22-1f94-5949-84c6e9a94a9c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/e334c048-db57-b19d-f484-e9de4a06d3d8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/f604e26f-d02a-04d8-85f4-0e89457efdb1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/e72b3d44-fff2-9508-c452-5288a557fcab.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/722ed0f2-9faf-4f4d-5f23-46565cdc8c95.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/f4d9e221-cc1a-fe18-ad40-775c40542fcc.png)
【javascript】【jquery】スクロール

# コード
```javascript
    $(window).scroll(() =>{
        let scrollTop = $(window).scrollTop(); // スクロール上部の位置
        let areaTop = $("h2").offset().top; // 対象エリアの上部の位置
        let areaBottom = areaTop + $("h2").innerHeight(); // 対象エリアの下部の位置
        let windowHeight = $(window).height();  //ウィンドウの高さ
        // ↓要素がページの1番上を通過した場合
        // if (scrollTop > areaTop && scrollTop < areaBottom) 
        // ↓要素がページの1番下から見えた場合
        if (scrollTop > (areaTop - windowHeight + windowHeight/6)) {
            console.log('何らかの処理');
        } 
//「windowHeight/6」を最後に足して要素の可視範囲からウィンドウの高さ1/6の高さ分スクロールしたら表示
    });

```
リーダブルコード

リーダブルコードというのは初歩的な話になります。
だけど、学んだことでちょっと疑問に思いながら書いていたコードを自信をもって書くことができたり、勘違いしていた部分に気づけたので、学習の中で学んだことをいくつかピックアップしてメモ書き程度に共有したいと思います。

## コメントについて
#### コメントは書くべきか、コードをまとめてしまっていいのか
　コードは短い方がいいですが、1行増やしたり、コメントをつけたりすることで理解できるまでにかかる時間が短縮できるのであれば、そちらの方が良いという話です。理解のしやすさという点に重きはおくべきなんですね。
　コメントに関しては、案件によって書き方が指定されるとは思いますが、上記のことは意識したほうが良さそうです。

#### 曖昧を避け正確を重視しよう
「行数を返す」よりも「改行文字('\n')を数える」の方が伝わる情報は増えるというように、正確に単純に情報密度の高い言葉や表現を使用したほうがよいです。

#### コードの意図であったり、質問されそうなことはコメントとして残そう
曖昧さとの線引きが難しく感じますが、意図や要約コメントを簡単に正確に記載しましょう。



## 名前について
#### ループインテレータを分かりやすく
 ループインテレータが複数ある場合は、説明的な名前（club_i, members_i, users_iなど）にすることで明確さを付与し、バグの発見、防止に役に立ちます。

#### 単位をいれよう
時間やバイト数のように計算できるものであれば、変数名に単位を入れた方が良い。（elapsed　→　elapsed_ms）

## 制御フローについて
#### ブロックの並び順を意識しよう
・条件は否定形よりも肯定形を使う。
・単純な条件を先に書く。
・関心を引く条件や目立つ条件を先に書く。
（否定形の条件であっても単純で関心や注意を引く場合もあるので、その場合はそれを先に処理する。）

#### 三項演算子の使い方
基本的にはif/else文を使うようにし、三項演算子はそれによって簡潔になるときにだけ使うようにした方が良いです。コードの短さよりも理解のしやすさの方が重要。

#### do/whileループは避けよう
コードは上から下へ読まれるので、条件式が下にあるdo/while文はコードを2回読む手間が発生します。
ほとんどの場合while文で書き直せます。

## 式の分割について
#### ド・モルガンの法則を使おう
下記のようにした方が論理式が読みやすくなる場合があります。
```java
if(!(A || B || C)) //下記に変更
if(!A && !B && !C)

if(!(A && B && C)) //下記に変更
if(!A || !B || !C)
```

## 変数について
#### 一時変数、中間結果、制御フロー変数は削除する
・複雑な式を分割したり、より明確になったり、複数回使われるといった性質を持たないのであれば、その変数を使う理由はないです。
・中間結果を保持するためだけに使用されている変数は、結果をそのまま使うことで削除できます。
・whileループ内で途中から抜けださないように設定される制御フロー変数は、breakを用いて上手くプログラミングすれば削除できます。breakが使えないようなネストの深いループの場合は、コードを新しい関数に移動させます。

https://www.oreilly.co.jp/books/9784873115658/
スイッチ後のユーザーでもローカルPCでX Windowの画面表示をする方法

# 前置き

クラウド環境のCompute VMではログインユーザーが指定されています（OCI Compute VMの場合はopcユーザー）。そのため、Compute VMにOracle DBを入れるために、GUIのDBCAで構築したいというとき、ログインユーザーからスイッチしたoracleユーザーでも、X WindowによってローカルPCに画面を飛ばす操作をする必要があります。
ここでは、スイッチ後のユーザー(oracleユーザー)でX Windowの画面表示するまでの手順を記述します。
環境はOracle Linux 7で実施しています。

# 手順

## 0.前提

opcユーザーにてローカルPCへのX転送ができる状態であるとします。
自分はこちらのQiitaの記事にお世話になりました。
https://qiita.com/ora_gonsuke777/items/765189e9e301415e7ba5
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/13b31415-c1a2-1882-8dc0-dea620c4f408.png)

opcユーザーでは表示できても、oracleユーザーにスイッチしたあとは表示できなくなってしまいます。
oracleユーザーにスイッチした後にX Windowの表示をローカルPC上で実施する手順を以下で紹介します

```
[opc@ymzkdb ~]$ sudo su - oracle
Last login: Thu Nov 24 17:53:40 GMT 2022 on pts/0
[oracle@ymzkdb ~]$ xeyes
Error: Can't open display:
```

## 1. oracleユーザーでX転送を実施するため、opcユーザーのxauthの情報をoracleユーザーにaddする

### opcユーザーのxauth情報を表示
```
[opc@ymzkdb ~]$ xauth list $DISPLAY
ymzkdb/unix:10  MIT-MAGIC-COOKIE-1  910381ebfbdc544809baa1f00401d88e
```

### oracleユーザーになり、opcユーザーのxauth情報を追加する
```
[opc@ymzkdb ~]$ sudo su - oracle
Last login: Mon Oct 24 06:26:19 GMT 2022 on pts/1
[oracle@ymzkdb ~]$ xauth add ymzkdb/unix:10  MIT-MAGIC-COOKIE-1  910381ebfbdc544809baa1f00401d88e
```


このとき、初回実行時など、以下のようなエラーがでることがあります。
```
xauth:  file /home/oracle/.Xauthority does not exist
```
.Xauthorityについては、xのアプリケーション(xeyesなど)を実行すれば作ってくれるとのことなのでxeyesを実行します
http://nalab.mind.meiji.ac.jp/~mk/knowhow-2014/node4.html

```
[oracle@ymzkdb ~]$ xeyes
Error: Can't open display:
[oracle@ymzkdb ~]$ ls -l  /home/oracle/.Xauthority
-rw-------. 1 oracle oinstall 52 May 26 07:42 /home/oracle/.Xauthority
```

## 2.DISPLAY環境変数を設定します

```
[oracle@ymzkdb ~]$ export DISPLAY=localhost:10.0
```
DISPLAY=localhost:10.0の10の部分はopcユーザーのxauth情報と合わせます
ymzkdb/unix:10(←これ)  MIT-MAGIC-COOKIE-1  910381ebfbdc544809baa1f00401d88e

## 3.x アプリケーションを実行して表示を確認

```
[oracle@ymzkdb ~]$ xeyes
```
これでoracleユーザーでも無事X Windowの表示がされました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/ad380b41-7656-f8ac-419b-bd680ee5578f.png)

目的であったDBCAの表示もできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/19f60510-3b83-25c7-121a-488c4358db5a.png)
Rust vs Python:例外処理

## 例外処理 in Python

```python
def raise_exception():
    raise Exception("例外が発生しました")

def main():
    try:
        raise_exception()
    except Exception as e:
        print("Exception: {}".format(e))


if __name__ == "__main__":
    main()
```

## 例外処理 in Rust

```rust
fn raise_exception() -> Result<(), String> {
    Err("例外が発生しました".to_string())
}


fn main() {
    match raise_exception() {
        Ok(_) => println!("OK"),
        Err(e) => println!("Error: {}", e),
    }
}
```
ニュースフィード Bot を利用して Developers のお知らせを受信する

LINE WORKS Developers の RSS が公開された。
無料で利用できる LINE WORKS ニュースフィード Bot を利用して、Developers の新機能や API 仕様変更などのお知らせをトークで受信できるようにする。

# ニュースフィードの利用を開始する

[管理者画面](https://admin.worksmobile.com/)のアプリメニューからニュースフィードアプリを追加する。

![1685066669.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726616/3054c56a-9b75-df94-0827-ce4a08f85e96.png)

![1685066635.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726616/e0e52ffb-88b1-f02f-279c-e1374938e422.png)

![1685066701.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726616/9a64369f-3330-32f6-cbab-64a4f1b52de3.png)

![1685066727.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726616/6f1f3085-db49-504d-345a-2c165905d81b.png)

任意で利用メンバーを制限することも可能。

![1685066750.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726616/da3cbae1-406b-b403-32e0-e1a1d2b05f95.png)

これでニュースフィードアプリが追加された。

# Developers のお知らせの RSS を取得する

![1685067141.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726616/2524412c-6768-d9fa-4123-4e6666605042.png)

Developers ニュースのページで RSS をコピーする。（記事を投稿した時点では以下の URL になっている）
```
https://jp1-notice.worksmobile.com/view/rest/article/rss/12?serviceLanguage=ja_JP
```

# ニュースフィード Bot の設定をする

トーク画面を開き、Bot の利用を開始する。

![1685066896.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726616/555ef483-872d-0d84-421c-636b11cf0878.png)

※モバイル版 LINE WORKS ではリッチメニューが利用できるため、以降はモバイルを利用

![1685088376.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726616/be8b12b5-009e-e226-4f14-5ca79cf16635.png)

メニューの「読みたいコンテンツを追加」を選択。Bot からコンテンツの URL を送信するようメッセージが届くので、先ほどコピーした Developers の RSS を送信する。

![l_1728761_366_9a62ec32321e910dea078e8a127a5192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726616/1835c355-6e98-553d-4453-f2bfabe4f14c.png)

「はい」を選択して追加完了。
通知時刻はデフォルトで毎日午前９時になっている。必要に応じて受信時間を変更する。

これで、Developers のお知らせが配信された際にニュースフィード Bot から通知されるようになった。
Next.js v13.4をAWS App Runnerで動かそうとしてハマった話

## TL;DR

- Next.js v13.4.xにはApp RunnerやFirebaseで発生するバグがあるようす。
    - https://github.com/vercel/next.js/issues/49777
    - https://github.com/firebase/firebase-tools/issues/5869
- Workaroundはあるけど、根本的な解決を待った方がよさそう。
- v13.3では正常動作することを確認


## はじめに

コンテナさえアップロードすればアプリケーションをいい感じに動かしてくれるAWS App Runner。Next.js(SSR)をコンテナで動作するようにして、App Runnerで動かしたかった、のにハマった。

## ハマった点①：CPUアーキテクチャ

Apple Siliconで何も考えずにコンテナをビルドすると`platform=linux/arm64`でビルドされる。一方APP Runnerは`linux/amd64`にしか対応していない。気づいたら単純な話なのだけど、気づくまでにえらい時間を食ってしまった。

https://zenn.dev/nakamura196/articles/7fcde4c2ffa2f1

## ハマった点②：Next.js v13.4の問題

やっとまともなエラーログが出るようになったと思ったら、冒頭で言及した問題を踏んでしまった。

https://github.com/vercel/next.js/issues/49777

https://github.com/firebase/firebase-tools/issues/5869

App Routerを使いたいのだけど、App Runnerで動かすなら時期尚早かもしれない。App Runner側の環境変数に`HOSTNAME='0.0.0.0'`をセットする方法が提示されているが、筋がいい感じはしない。`v13.4.x`で発生する問題のようなので、`v13.3.4`に戻せば問題ない模様（App RouterがExperimentalであることに留意）。

## 終わりに

この問題でハマる人が私で最後になることを祈念し本記事を投稿いたします。ECRにデプロイさえすればアプリケーションがいい感じに走るApp Runnerはとてもいいと思います！
WKWebViewのLocalStorageに設定した値がサーバー側で読み取れない

結論として、[WKUserScriptInjectionTime](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime)に`atDocumentEnd`を設定していたことが原因だった。

# 事象
WKWebView生成時にWebViewのLocalStorageへ値を設定したあと、URLRequestでWebページを読み込む処理において、Web側でLocalStorageが読み取れない事象が発生した。

## 悩んだ原因

`func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)`内でLocalStorageKeyの値を出力したときには値が確認できていたため「アプリ側では値はちゃんと設定できているな」と判断してしまった結果、事象の解決まで長引くことに・・・。

```.swift
// webViewのローカルストレージにキーを設定
webView.configuration.userContentController.addUserScript(WKUserScript(
    source: "localStorage.setItem('\(localStorageKey)', '\(key)');",
    injectionTime: .atDocumentEnd,
    forMainFrameOnly: true
))
```

```.swift
/// WebViewの読み込み完了時に呼び出される
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    webView.evaluateJavaScript("localStorage.getItem('key')") { result, error in
        if let error = error {
            print(error)
            return
        }
        print("LocalStorageKey: \(result ?? "nil")") // resultが出力される
    }
}
```

## 試したこと
- アプリ側でLocalStorageに値を設定したあと、Sleep()で数秒ディレイをかけてからURLRequestする。
→効果なし。変わらず。

- サーバー側でリクエストを受けた後、数秒ディレイをかけてからLocalStorageを読み込む。
→効果あり。
ここでLocalStorageのセット or 読み込みのタイミングに問題があると把握。

- 〜数週間放置〜

- いい加減に対応しないといけなくなり、printデバッグしつつコードを見直していたところ`atDocumentEnd`が目について「ん？」となる。
    - `atDocumentStart`：Web ページのドキュメント要素の作成後、他のコンテンツをロードする前にスクリプトを挿入する定数。
    - `atDocumentEnd`：ドキュメントの読み込みが完了した後、他のサブリソースを読み込む前にスクリプトを挿入する定数。
- 「ほ〜ん・・・」

## 結論
`WKUserScript`では指定したタイミングでJavaScriptをWebViewに注入することができる。
`injectionTime`のパラメータを指定すると「WebViewのドキュメントの読み込みが完了した後」に注入するか「ドキュメントの読み込みが完了する前」に注入するか選択できる。

今回は「WebViewのドキュメントの読み込みが完了した後」にJavaScriptをWebViewに注入していたため、サーバー側でのLocalStorage読み取りタイミングの段階ではLocalStorageに値が設定されていなかったことで発生していた。

## 原因
`WKUserScript`のコードをネット（ChatGPT）から拾ってきて深く考えずに使ったこと。
printデバッグで値が設定されていることを確認できていたため、アプリ側に問題があると真剣に考えていなかったこと。

## 修正後のコード
`injectionTime`のパラメータを`.atDocumentStart`に変更
```.swift
// webViewのローカルストレージにキーを設定
webView.configuration.userContentController.addUserScript(WKUserScript(
    source: "localStorage.setItem('\(localStorageKey)', '\(key)');",
    injectionTime: .atDocumentStart,
    forMainFrameOnly: true
))
```
Mermaid Markdownでフロー図を作成してみた

# はじめに
こんにちは。
最近、GitLabで資料作成をする機会がありました。
GitLabにフロー図を書きたかったのですが「Office製品で書いて画像として入れる？」など考えましたが面倒です。
もし、画像を更新することになったら、修正→画像化→GitLabに挿入と色々段取りが必要でとにかく手間がかかります。
何か方法がないかと調べていたところMermaid Markdownの存在を知りました。

Mermaid Markdown初挑戦だったので最初は違和感がありましたが、慣れてくればけっこうラクです。
私と同じような悩みを持っている人の参考と自分自身の備忘録も兼ねて記事を書きます。

# 環境準備
今回は環境準備に関する詳しい記載は割愛します。
色々な方法がありますが、VS Codeをインストールし、拡張機能「Markdown Preview Mermaid Support」をインストールするのが一番手っ取り早いかと思います。

# 基本形
~~~
```mermaid
ここにMermaid記法を記入する。
```
~~~

# コード例
~~~
```mermaid
flowchart TB
    A[起床] --> B[顔を洗う] -->
    C{眠い?} -- 眠くない --> D[朝食を食べる]
    C{眠い?} -- 眠い --> E[二度寝する] -- 起きる --> C{眠い?}
    D[朝食を食べる] --> 
    F[歯を磨く] -->
    G((やっぱり寝る))
```
~~~ 

# 出力結果
```mermaid
flowchart TB
    A[起床] --> B[顔を洗う] -->
    C{眠い?} -- 眠くない --> D[朝食を食べる]
    C{眠い?} -- 眠い --> E[二度寝する] -- 起きる --> C{眠い?}
    D[朝食を食べる] --> 
    F[歯を磨く] -->
    G((やっぱり寝る))
``` 

# オプションまとめ
コードの記載内容によってフロー図の向き、図形、矢印など変えることができます。

## フロー図の向き
「flowchart **xx**」の「**xx**」の部分に入れるものによってフロー図の向きを変えられます。
~~~
```mermaid
flowchart xx　←ここのxxを編集する。
    A[ノード1] --> B[ノード2] --> C[ノード3]
```
~~~

### オプションまとめ
|flowchart xx  |方向  |
|--------------|-----|
|TBまたはTD  |上から下  |
|BT  |下から上  |
|LR  |左から右  |
|RL  |右から左  |

### 出力例
```mermaid
flowchart TB
    A[上] --> B[から] --> C[下]
```

```mermaid
flowchart BT
    A[下] --> B[から] --> C[上]
```

```mermaid
flowchart LR
    A[左] --> B[から] --> C[右]
```

```mermaid
flowchart RL
    A[右] --> B[から] --> C[左]
```

## 線の種類
各ノードをどのように記載するかで線の種類を変えられます。
~~~
```mermaid
flowchart TB　
    A[ノード1] --> B[ノード2] --> C[ノード3]
               ↑
               ここの「-->」を編集する。
```
~~~

### オプションまとめ
|コード  |種類  |
|------|-----|
|A-->B  |実線 矢印 |
|A==>B  |太線 矢印 |
|A-.->B |点線 矢印 |
|A---B  |実線  |
|A===B  |太線  |

### 出力例
```mermaid
flowchart TB
    A[Start] --> B[Stop]
    C[Start] ==> D[Stop]
    E[Start] -.-> F[Stop]
    G[Start] --- H[Stop]
    I[Start] === J[Stop]
``` 


## ノードの形
ノードの内容を何で囲むかでノードの形を変えられます。
~~~
```mermaid
flowchart TB　
    A[ノード1] --> B[ノード2] --> C[ノード3]
     ↑      ↑
     ここの[ ]を編集する。
```
~~~

### オプションまとめ
|コード  |種類  |
|------|-----|
|A[]  |長方形 |
|A{}  |ひし形 |
|A() |長方形(角が丸い) |
|A([])  |楕円  |
|A(())  |円  |

### 出力例
```mermaid
flowchart 
A[長方形]
B{ひし形}
C(角が丸い長方形)
D([楕円])
E((円))
``` 

# おわりに
最後まで読んでいただきありがとうございました。
今回はフロー図を中心に記事にしましたが、他にもシーケンス図や円グラフも色々な図形が書けるようなので、機会があれば記事にしようと思います。
おまけですが、コードブロックの中に「```」を書きたいときは「~~~ 」で囲めばできることを初めて知りました。こういった発見もあるので、知識のアウトプット作業って大事なのだと改めて実感しました。
Docker上のRでプロットする（WSL2）

Docker公式イメージ[r-base](https://hub.docker.com/_/r-base)を利用するとお手軽にRの実行環境を立ち上げられます。ただし、plotなどGUIを表示する関数はこのままでは使用できません。

```shell-session
> docker pull r-base:4.3.0
> docker run --interactive --tty --rm r-base:4.3.0
```

```
> barplot(0:10)
# 何も表示されない
```

Windowsでは、`docker run`コマンドに`--env`および`--volume`オプションを加えることで、WSL2でplotのGUIを表示できます。

このコマンドはWSL2の環境変数とディレクトリを参照するため、必ずWSL2のシェルから実行してください。また、WSL2のシェルから`docker`コマンドを利用するためには、Dockerの`Settings > Resources > WSL integration > Enable integration with my default WSL distro`を有効にする必要があります。

```shell-session
$ docker run --interactive --tty --rm --env "DISPLAY=${DISPLAY:-:0.0}" --volume /mnt/wslg/.X11-unix/:/tmp/.X11-unix r-base:4.3.0
```

```
> barplot(0:10)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1550728/e7eb6e10-1b0e-2a95-e08e-80a49e6ae258.png)

余談ですが、WSL2でDockerコンテナのGUIを表示させる方法はPythonなどでも役に立ちます。

```shell-session
$ docker pull python:3.11
$ docker run --interactive --tty --rm --env "DISPLAY=${DISPLAY:-:0.0}" --volume /mnt/wslg/.X11-unix/:/tmp/.X11-unix python:3.11
Python 3.11.3 (main, May 23 2023, 13:25:46) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tkinter as tk
>>> tk.Tk().mainloop()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1550728/fe841159-b0cb-bd41-fa83-da337cdde2ef.png)
Googleが公開したC++のためのライブラリ(2007)のその後

『Google、C++開発者のための4つのライブラリを公開』(CodeZine, 2007)
https://codezine.jp/article/detail/1172
なる記事を見つけたのですが、Google Code で公開されていたものらしく、CodeZineの記事にある5つのリンクはすべてアクセス出来なくなっていました。残念、と思いつつちょっと調べ直してみたところ、実はまだ残ってるようなので、メモがてら整理してみました。

* Four Google open source tools on Google Code
http://googlecode.blogspot.com/2007/03/four-google-open-source-tools-on-google.html
* google-gflags
https://github.com/gflags/gflags
* google-perftools
https://github.com/gperftools/gperftools
* google-sparsehash
https://github.com/sparsehash/sparsehash
* google-ctemplate
https://github.com/OlafvdSpek/ctemplate

あるんだなあ。

参考になれば。
AmazonLinux2でCakePHP4を動かしたい

# 前書き
ちょっと手間取ったので。
AmazonLinux2にApache入れてCakephp4が動くまでの記録。

# 本文

suするのが正しいのかよくわからんけど。
まずはApache
```
sudo su
yum -y update
yum -y install httpd
systemctl start httpd
systemctl enable httpd
```
ここまでで、ブラウザのアドレスバーにIPアドレス打ち込んで、Apacheのテストページが出ればOK牧場。

次に、PHPを入れる。
今のところ最新が8.2。
```
amazon-linux-extras install -y php8.2
```
そして、この拡張機能？を入れるのが大事。
これが入ってなくて、CakePHPが全然動かんかった。
```
yum -y install php-intl.x86_64
yum -y install php-xml.x86_64
yum -y install php-mbstring
```

ここまできたら、後は公式を参考にCakeをインストール。
Composerをインストールし、任意のディレクトリにCakeAppを作成。
### 例
``` 
cd /var/www/html
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '55ce33d7678c5a611085589f1f3ddf8b3c52d662cd01d4ba75c0ee0459970c2200a51f492d557530c71c15d8dba01eae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
php composer.phar create-project --prefer-dist cakephp/app:"4.*" cakeapp
```
インストールの終わりごろに、必要なアクセス権を付与するか聞かれる。
yでいいと思う。詳しい人は自分で設定できるからnでいいと思うけど、そもそもこんなページ見てないか。

で、ブラウザのアドレスバーに、
http://(IPアドレス)/cakeapp
にアクセスし、
![cake.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241095/8bdecb13-4b4a-e662-e0cd-a3f8336b7002.jpeg)
が表示されれば牧場。

# あとがき
ここまで来たらデータベースにつないだり、Controller書いたり、Cakeの構築ができるz
Pydanticで自作の検証ルールを追加する

## Pydanticのデータ検証機能について

Pydanticを使用することで動的にデータの型を検証することができます。

```python
from pydantic import BaseModel


class Time(BaseModel):
    year: int
    time: int


time_1 = Time(year=2020, time=10) # OK
time_2 = Time(year=2020, time="10") # OK, Pydanticが自動で型変換してくれる
time_3 = Time(year="2020", time="ten") # NG, timeはint型に変換できない
```

このようにデータの型を検証することで、バグを事前に回避することができます。


## 独自の検証ルールを作成する

Pydanticでは独自の検証ルールを作成することができます。

```python
from pydantic import BaseModel, validator


class Time(BaseModel):
    year: int
    time: int

    @validator("time")
    def time_must_be_less_than_60(cls, v):
        if v >= 60:
            raise ValueError("time must be less than 60")
        return v


time_1 = Time(year=2020, time=10) # OK
time_2 = Time(year=2020, time=60) # NG, timeが60以上なのでエラーが発生する
```

この様に独自の検証ルールを作成することで、より細かい検証を行うことができます。

ルールは以下のフォーマットで作成します。

```python
@validator("検証対象のフィールド名")
def 検証ルール名(cls, v):
    if some_rule: # 検証ルール
        raise ValueError("エラーメッセージ")
    return v # 検証に成功した場合は値をそのまま返す
```
【Kotlin】Androidで音声ファイルを再生する(SoundPool,MediaPlayer)

## はじめに
今回はAndroid開発における、音が鳴るシンプルなコードを実装します。

主に'SoundPool'を使う方法と'MediaPlayer'を使う方法の２種類ありますが、両方実装してみます。

## 1.SoundPoolを使う方法
音源となるmp3, ogg, wavファイルなどを res/raw/ 以下に置きます。

「res」から「New」「Directory」で「raw」ディレクトリを作成し、そこにファイルを格納しておきましょう。

```kotlin
import android.media.SoundPool


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {


        // SoundPoolの初期化
        val soundPool = SoundPool.Builder()
            .setMaxStreams(1)
            .build()
        // サウンドファイルの読み込み
        val soundId = soundPool.load(this, R.raw.sound, 1)

        var soundButton = findViewById<Button>(R.id.sound_button)

        soundButton.setOnClickListener{
            //音を鳴らす処理
            soundPool.play(soundId, 1.0f, 1.0f, 0, 0, 1.0f)
        }
  }
}
```



## 2.MediaPlayerを使う方法
MediaPlayerを使う場合も、音源ファイルは 同じようにres/raw/ 配下に置いておきます。
```kotlin
import android.media.MediaPlayer

override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

     //音を鳴らす処理
        val mediaPlayer = MediaPlayer.create(context, R.raw.sound)
        mediaPlayer.start()
        return root
}

override fun onResume() {
        super.onResume()
    }
```

## まとめ
マナーモード時の制御や、端末の音量設定と連動させたりなど、実践ではまだまだ考慮すべきことが他にもあるので、今後色々と試してみたいなと思います。
protocからBufに乗り換えて設定をソースコード管理しよう  [gRPC ✕ golangをDRYに Part.2]

## 対象読者
- [株式会社viviON](https://vivion.jp/)にちょっと興味ある
- gRPCちょっとわかる
- protoファイルちょっとわかる

## protobufの生成フローをそろそろソースコードで簡略化したくはないだろうか？

### ある日のprotobuf generateコマンド
``` sh
protoc -I . --grpc-gateway_out ./gen/go \
    --grpc-gateway_opt logtostderr=true \
    --grpc-gateway_opt paths=source_relative \
    --grpc-gateway_opt grpc_api_configuration=path/to/config.yaml \
    --grpc-gateway_opt standalone=true \
    your/service/v1/your_service.proto
```

いやいや、ターミナルにどんだけ書くんですか、っていう。

たいていの場合既にbashファイル化されているかもしれないですが。。。

## Bufとは何か？
「Buf Technologies, Inc」が開発してるproto APIマネージドツールです。
こちらが、[リポジトリ](https://github.com/bufbuild/buf)です。

要約すると、以下をソースから簡単にマネージド出来るCLIだよとのことです。

- build
- lint
- format

## Bufを使うとprotocと比較してどう変わるか

上記で記載したコマンドが下記のコードに変換ができ、```buf generate```コマンドでprotobufが生成できます。

``` yaml
version: v1
plugins:
  - plugin: go
    out: gen/go
    opt:
      - paths=source_relative
  - plugin: go-grpc
    out: gen/go
    opt:
      - paths=source_relative
  - plugin: grpc-gateway ## 使用するplugin名
    out: gen/go ## 生成されるDIR
    opt: ## pluginへのオプション
      - paths=source_relative
      - grpc_api_configuration=path/to/config.yaml
      - standalone=true
```

## 使い方

### bufのインストール方法
``` sh
## マカー向け
brew install bufbuild/buf/buf
```

### bufの初期化　(プロジェクト単位で実行の必要あり)
``` sh
buf mod init
### buf.yamlが生成されます。
```
### 生成されたbuf.yamlの中身
linterのルールは他にも様々なものがあるため、詳しくはこちらの[ドキュメント](https://buf.build/docs/lint/rules/)を参照ください。
```yaml:buf.yaml
version: v1
breaking: ## 破壊的変更の検知
  use: ## 破壊的変更の検知として、何を起点(ID)にしてチェックを行うかを判別
    - FILE
lint:
  use:
    - DEFAULT ## bufが標準的に用意しているルールの適用
```

### protoファイルをlinterにかけるコマンド
```sh
buf lint
```

### protoファイルの整形コマンド
```sh
buf format -w ## --writeの略
```

### protobuf生成の設定ファイル

```yaml:buf.gen.yaml
version: v1
plugins:
  - plugin: go
    out: gen/go
    opt:
      - paths=source_relative
  - plugin: go-grpc
    out: gen/go
    opt:
      - paths=source_relative
  - plugin: grpc-gateway ## 使用するplugin名
    out: gen/go ## 生成されるDIR
    opt: ## pluginへのオプション
      - paths=source_relative
      - grpc_api_configuration=path/to/config.yaml
      - standalone=true
```


### potobuf生成コマンド
コマンドを使用すると、```buf.gen.yaml```を元に、Protocol Bufferを生成します。

```sh
buf generate
```


## まとめ

いかがでしたでしょうか？protocからBufへ移行したくなりましたか？

[commit linter](https://commitlint.js.org/#/)で事前リンターしたり、[VScode](https://github.com/bufbuild/vscode-buf)に取り入れることで、より開発生産性を向上できそうですね。

Part. 3(Final)は 「[golang ✕ gRPCのprotoでルールベースValidateを行う](https://qiita.com/taisei_otsuka/items/e4466ba4bf47650c7480)」です☆

## 採用PR

https://hrmos.co/pages/vivion/jobs/0000226

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/2000f749-3e82-7a47-b1c4-4444e237f79c.png" width=45%>
（改良中）ソフトウェアエンジニアリングに関わる全ての人の最低限の常識を再度学習してみた

「言っていることが概略すぎてわからないので。君が提案しようとしているシステムの概要図を書いてくれ。」

大手通信会社の部長からそう言われて、死ぬ程悔しかったので初めてアーキテクチャについて勉強しようと思いました。

その学習録として記事を書いていきます。

# 概要
アプリケーション開発のアーキテクチャについて基礎的な知識をトピック毎に学べるように解説していきます。

これから新規にエンジニアリングの業界に入る人、またはエンジニアリングの基礎を復習したい人向けに有益な内容になっています。

学習対象者は以下の方になります。
・エンジニア2~5年目
・未経験者（ログイン機能レベルの実装は可能）

# ソフトウェア開発に携わる人の最低限の常識
1. *WEBアプリケーションにおけるセッション管理*

1. *システム間の呼び出し*
1. *データベースの排他制御*

上記の三つについて分かりやすく、誰でも理解ができるように解説をして行きます。


### 1. WEBアプリケーションにおけるセッション管理
学習ゴール：
・セッションの仕組みを理解。
・セキュリティインシデントを考慮したシステムの提案。

このコンテンツではクライアントからのセッション管理についての質問に対して、有効な手段を分かりやすく伝えられるようになる為の内容です。
セッション管理に対する理解が曖昧なままだと、期待した性能が得られなかったり、セキュリティインシデントによりステークホルダーからの信頼を失う可能性もあります。
セッションの管理を理解した上で的確な内容を提供出来るように学んで行きましょう。

<font color="#1e90ff">**読破時間の目安**</font>：60分
学習をスタート→[WEBアプリケーションにおけるセッション管理（１）](https://qiita.com/Kosuke0906/items/45bdef6efae3797a2d2f)


### 2. システム間の呼び出し
学習ゴール：
・新規提案時に実現案の提示。
・運用保守時に既存システムの構造の理解。

大きなアプリケーションでは、あるシステムが単独で動いている訳ではなく、他のシステムと連動して動いていることがよくあります。
強固なシステムの開発には、それらが互いに関係し合いながら、且つデータの生合成を保ちながら稼働させなくてはいけません。
クライアントに適切なアーキテクトを選択提示出来る様、最低限必要な知識をこのコンテンツで学んで行きます。

<font color="#1e90ff">**読破時間の目安**</font>：60分

### 3. データベースの排他制御
学習ゴール：
・トランザクションの効率改善。
・正しい処理の流れの記載。

ただプログラミングが出来ると言う状況から仕事に使えるコードを書く為のコンテンツです。
エンタープライズアプリケーションは多くのアクセスが見込まれるので、各トランザクション毎にデータの整合性を取る必要が出てきます。
ケーススタディを見ながら、どう言ったコードの構築が必要なのかを考えながら学習を進めて行きます。

<font color="#1e90ff">**読破時間の目安**</font>：60分
WEBアプリケーションにおけるセッション管理（webセッションについて１）

この記事ではイメージが付きにくいセッションについて学習をして行きます。

目標：セッションの理解とセキュリティを意識したシステムの提案を可能とします。

是非ここで学んだことを実務でのセキュアなシステムの構築に役立てていただければ幸いです。

# １　セッション管理とは？
### １−１　セッションて何？
webサイトの利用者がページを跨いで保持できる情報です。
![Screenshot 2023-05-25 at 17.13.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485403/e4274a1d-c260-f83e-925a-7395de02e39b.png)

セッションとは個人(利用者)を特定する一意のトークンと思ってくれて大丈夫です。

また同一のユーザーが一定の時間内に何度訪れようと一意のものとしてカウントされます。


時間が経つとセッションは廃棄されて新しい物が生成されます。
![Screenshot 2023-05-26 at 14.45.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485403/6dd8c03e-d16e-df94-9def-beca9629ae16.png)

___
###  １−２　何故セッションが必要？

webアプリで利用するHTTP通信はステートレスのプロトコルになります。

通信の前後で状態を補完することが出来ません。


セッションを利用してユーザーとシステムの会話を担保しているのです。
![Screenshot 2023-05-25 at 18.20.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485403/94cc4356-1236-cf43-55c0-aaf5ec3f98b1.png)

HTTPの通信単体では状態を保持することが出来ないので、cookie（クッキー）と言う情報を付与して通信を行います。

正確にはcookieの中にセッション情報を格納してクライアントとサーバーのやり取りを行なっています。
![Screenshot 2023-05-25 at 18.34.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485403/0facb0a1-cfcc-4153-e2a8-c8076e4f181c.png)

どうやってセッションを生成しcookieに格納するのかは以下のリンクで確認してください。
（セッションの生成とcookieへの格納の仕方）

![Screenshot 2023-05-26 at 14.52.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485403/9832bb17-36f0-2623-5cd6-27449d39f2fa.png)

###  １−３　セッションでデータとして管理するもの

・ログインユーザのデータ
　認証情報、許可情報、言語（日本語・英語・中国語等）

・仕掛かり中の業務データ
　申し込みフォーム、アンケート、買い物処理等

![Screenshot 2023-05-26 at 15.11.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485403/a865f2ab-52a9-bc14-c6cb-cf8ab2cb8829.png)



# このセッションのまとめ問題
１、セッションを使う目的は？
２、どこに格納する？
３、使い方を間違えると重大な事故を引き起こす可能性はある？

ぜひ質問や聞いてみたいことがあればコメントを貰えると嬉しいです。

次は脆弱なセッション管理が起こすインシデントケースと仕組みについて学習して行きます。
[脆弱なセッション管理が起こすインシデントの仕組み（webセッションについて２）](https://qiita.com/Kosuke0906/items/cf174ddee4d834fdb0ab)
【Spring】Field "フィールド名" in "インジェクション先のクラス名" required a bean of type 'インジェクション元のクラス名' that could not be found.

# はじめに
Springでとりあえず簡単なREST APIを作ってサーバを起動したところ↓のエラーに遭遇。
書籍を基に学習をはじめた初学者は、はまるかもと思い備忘録。

```error.log
***************************
APPLICATION FAILED TO START
***************************

Description:

Field dao in com.kyosoba.service.KyosobaInfoService required a bean of type 'com.kyosoba.dao.JdbcKyosobaDao' that could not be found.

The injection point has the following annotations:
        - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'com.kyosoba.dao.JdbcKyosobaDao' in your configuration.
```
`@Component`とか`@Autowired`のアノテーションはつけてるしなんでだろう。。

# 問題のソースコード
以下のコードの何が原因でしょう？（細かいロジックは無視してください）
```Controller.java
/**
 * Controllerクラス
 */
@RestController
public class KyosobaInfoController {

	@Autowired
	KyosobaInfoService kyosobaInfoService;
	
	/**
	 *  URIにアクセスされたらデータを返却
	 */
	@GetMapping("/kyosoba-info-detail")
	public KyosobaInfoResource kyoso(String id) {

		// サービスクラスを使って検索
		KyosobaInfoResource kyosobaInfo = new KyosobaInfoService().findById(0);

		return kyosobaInfo;

	}

```

```Service.java
/**
 * Serviceクラス
 */
@Service
public class KyosobaInfoService {
	
	@Autowired
	JdbcKyosobaDao dao;
	
	/**
	 * 検索ロジック
	 */
	public KyosobaInfoResource findById(int kyosobaId) {
		
		// DAOクラスを使ってDBアクセス 
		int i = dao.find();
        
        /* 他処理省略 */
        
        return kyosobaInfoResource; 
    }
```

```Dao.java
/**
 * DAOクラス
 */
@Component
public class JdbcKyosobaDao {
	
	@Autowired
	JdbcTemplate jdbcTemplate;
	
    /** 
     * テーブルアクセス
     */
	public int find() {
		String sql = "select max(id) from kyosoba";
		return jdbcTemplate.queryForObject(sql, Integer.class);
	}
}
```

# 答え
ControllerクラスでServiceクラスをnewしている`new KyosobaInfoService().findById(0)`が原因でした。newしているとDIが効かなくなるらしいです。

# 修正後
```Controller.java
/**
 * Controllerクラス
 */
@RestController
public class KyosobaInfoController {

	@Autowired
	KyosobaInfoService kyosobaInfoService;
	
	/**
	 *  URIにアクセスされたらデータを返却
	 */
	@GetMapping("/kyosoba-info-detail")
	public KyosobaInfoResource kyoso(String id) {

		// サービスクラスを使って検索
		KyosobaInfoResource kyosobaInfo = kyosobaInfoService.findById(0); //*** 修正 ***//

		return kyosobaInfo;

	}

```


# さいごに
書籍を参考にアレンジしながらいろいろごちゃまぜになってしまったのが原因ですね。

# 参考
https://aki-bunkei.com/spring-autowired/

https://www.yawintutor.com/field-required-a-bean-of-type-that-could-not-be-found/
指定コントロールが属しているTabControlのIsSelectedをTrueにする

## やりたかったこと
登録ボタンを押した時に入力エラーがあったコントロールにフォーカスを当てたい。
画面には複数のTabControlがあり単純にフォーカスを当てるだけだと表示されないので、
エラーコントロールがあるTabControlを選択する必要がある。

## 実装
```
private void SelectTabItem(DependencyObject obj)
{
    if (obj == null) return;

    var parent = LogicalTreeHelper.GetParent(obj);
    if (parent is System.Windows.Controls.TabItem)
    {
        var tab = parent as System.Windows.Controls.TabItem;
        tab.IsSelected = true;
    }
    this.SelectTabItem(parent);
}

```
ママ「人生のバグをデバッグし、メンテナンスするわよ！幸せなエンジニアになろう？！」

## まえがき

面白いので前回に引き続きオネエ風の記事にします。中の人は普通のエロいおっさんです。

## ごアイさつ

はぁ〜〜い、みんな💖

アタシ、今朝ひらめいたの👀💡
人生プログラマと名乗ることにしたわよ(•ө•)♡

なんでかーって❓❓
アタシの特技が活かせて、すんごいワクワクするからよ❗❗

特技がなにかって❓
アタシ、、実は〜、コミュニケーションが好きだってことに気づいたの❗おしゃべりだったの❗

それに気づくまでは結構シャイボーイの引っ込み思案で、コミュ障まではいかなくても、
コミュニケーションに苦手があったり、人と話すのが怖かったりしたわ。(T_T)

最近、コミュニケーション講座を受けたり、聴き合う体験をしたことで、ついに自分でもそれを自覚できたの。

## 幼少期のバグ

原因はどうやら、子どものときにバグを抱えたからだったのよ。
あ、バグっていうのは、一般的な心理学で言うところのトラウマとかジレンマとかコンプレックスかしら❓

アタシにはお姉さんがいて、１歳１１ヶ月差の年子でね。
お姉さんはとっても学業が優秀だったの。
お姉さんと比べられたり、自分で比べたりして、どんどん自尊心が保てなくなっていったわ。

そして、本来はしゃべりたい人間なのに、アタシが小さい頃から優秀なお姉さんが代わりに知らない人とかと話してくれててたの。
つまり、幼少期のコミュニケーションを学ぶ機会に学べなかったのね。
そのまま自分で話すチャンスを自分からつかみに行く勇気がなくて、特に小学校ではボッチくんになったわ。

菌扱いされて近寄るなって言われたり、
一握りの友だちからも、時々イジワルされて落ち込んだり、
色々なことを我慢して生きてたわ。

中学校になるとさすがに人並みに話すことはできてたけど、
受験に落ちたから、平和な国立小学校から、荒れ気味の市立の中学校に放り込まれることになったの。
普通の中学校で階級社会に揉まれたり、気の合う女子と仲良くすると男子に冷やかされて話せなくなったり、、、

そんなこんなで、すご〜〜く生きた心地がしなかったわ。

## 大人になっても

バグりすぎてたアタシは、精神的に成長できる環境がなくて、どこかで精神年齢ストップしたまま。
でも身体は大人になって、結婚もして、子どもも生まれたわ。

(自称３歳って冗談で言ってたけど、あながち間違いじゃなかったの。)

夫婦カンケイも表面上は仲良しっぽく見られてたけど、
二人になると全然本音で話せない、、
どこかわかりあえていない仮面夫婦だったの。

## 変化

最近、きっかけがあって、自分がボロボロだったことに気づいたの。
それは、コミュニケーション講座と聴きあう体験。

色々な人の人生を聞くことで、自分の人生を見返し、
あれ、、、、なんかボロボロじゃないの❗❗って気づいたの。

プログラミングのバグも、原因を見つけて修正していくように、
人生のバグも、原因と向き合って、修正することにしたわ。

## 癒やし

最初にバグを見つけたときは、ものすごい涙が出てきたの。
自分って、よく見たら傷だらけ❗

傷ができたときに、「痛かったよ〜〜〜うぇ〜〜〜〜ん」って言えてたら良かったのに、
ずーーーーーーっと我慢してたの。

それが一気に崩壊して、わぁっって泣いて、

痛かったね、ヨシヨシ。

って自分でしてあげることができたら、ものすご〜〜〜〜く楽になったの。

## これから

でね、アタシ、コミュニケーションを恐れてた分、人間のカンサツはすごく得意って思うの。
人とお話していく中で、このヒトってどんなことにフタをしてるのかな❓❓とか、こういう癖があるわね👀とか、見るのが好きなの💖

それって、プログラミングでバグを探していく作業にとっても似てるって思ってる。
アタシ、プログラミングでもバグを探すの、だ〜〜〜い好きなのよ💞

経験談から言うけど、プログラミングの世界と同じでね、
人生のバグに気づいて直せたら、人間もより良い動きができるようになっていくの。

アナタも人生、一緒にデバッグしましょ💖

[Twitter@is3to4](https://twitter.com/is3to4)
Ruff使用時に一部のルールを無効にするtomlの設定

## pyproject.tomlに以下のフォーマットでルールコードを追加する

```pyproject.toml
[tool.ruff]
ignore = ["E712"]
```

以上。

ちなみにE712は`x == True`と書いた時に`x is True`とするルール。
【FastLabelエンジニア一押し機能】3Dアノテーションツール


# はじめに

FastLabel新卒エンジニア 爲西です。

今回は、FastLabelの点群データのアノテーションで使われているthree.jsというライブラリについて簡単に紹介をします。

はじめに、FastLabelでのthree.jsが使われている部分について説明をします。

# 点群データとは

点群というのは、レーザー光を照射して、その反射光の情報をもとに対象物までの距離や対象物の形などを計測したデータのことです。この画像のような感じで、車や道路、奥の壁があることがわかります。
私は点群データの拡張子は”.pcd”で、こんな形式聞いたことがないという状態でした。

![スクリーンショット 2023-02-13 18.25.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1369844/a555184f-091e-a8ef-512d-e1d6128bc0f0.png)


FastLabelでは、点群データに対して車がある位置を直方体でアノテーションをすることができます。この直方体のアノテーションを学習させることでAI開発をすることができます。
![スクリーンショット 2023-02-13 18.02.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1369844/c45ac2a3-5abc-ffa9-b1a9-a31500f56038.png)


セグメンテーションで、車にアノテーションををつけた感じがこちらです！点群に対して色が割当られています。
![スクリーンショット 2023-02-13 18.25.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1369844/67173f18-c4a8-ca04-4ca4-67bfb3b00d2e.png)


# three.jsについて

three.jsを勉強する際に、webGLについての理解も必要です。three.jsがwebGLをラップしているからです。

webGLとは、ウェブブラウザで実行する3DをレンダリングするためのJavaScript APIです。GPUを使うため、高速に描画可能になります。

WebGLを使用するために最初に必要なのはキャンバス<canvas>です。webGLのコードは、JavaScript で記述する制御コードと、コンピューターの Graphics Processing Unit (GPU) で実行するシェーダーコード (GLSL) で構成されます。 

シェーダーを利用すると表現力が向上します。ただ、扱い方がかなり難しいためここでは割愛をします。

## 主なコンポーネント

### シーン

物体が配置される空間です。ワールドのことです。

### カメラ

物体を映すカメラです。どこから、3D空間を見ているのかという視点になります。遠近感が適用されるカメラと、平行投影が適用されるカメラの2種類があります。

シーンに、オブジェクトを配置してそれをカメラで投影すると物体をcanvasに描画することができます。

## オブジェクトの作成

オブジェクトの作成について覚えておかないといけない概念があります。ジオメトリ・マテリアル・メッシュです。

### ジオメトリ

オブジェクトの形状、骨格を表します。

### マテリアル

オブジェクトの色やマッピングする画像などを設定できます。

### メッシュ

ジオメトリとマテリアルをいい感じに組み合わせて描画をしてくれます。

例えば大きさ１の立方体を描画をしたいときは、以下のようなコードになります。

```jsx
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0x000000} );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube 
```

基本的に多角形・球などの物体を描画するときも、ジオメトリ・マテリアル・メッシュをセットで扱い、three.jsで用意されたクラス・コンポーネントを使えば何でも描画することが可能です。

# 最後に一言

以上がthree.jsの簡単な紹介になります。3D空間で物体を描画するのは意外に難しいんですよね、、

カメラの位置やオブジェクトの位置などの微調整がなかなか難しく、開発の工数がかかってしまいました。ただ、今はかなりthree.jsについての理解も深まり自由に扱えるように成長し、このライブラリの良さを身にしみて感じます。

ここでは、three.jsの説明について基本中の基本しか記載していないですが、別のところで発信をしていければと思っています。

[FastLabel 採用情報](https://www.notion.so/FastLabel-f60d25187d634b008388900525952985) 

[私のTwitter](https://twitter.com/ttarkkaru922)

[FastLabel ドキュメント](https://docs.fastlabel.ai/docs)
MUI v6 Date Calendarコンポーネントの日本語化

# 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532785/945f579d-9692-6f31-bf1f-fe6e5df16079.png)　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532785/d4b48e2c-0bb1-61c7-b918-0547157fb0cc.png)


# コード
```tsx
import { useState } from 'react';
import { ThemeProvider, createTheme } from '@mui/material';
import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { jaJP } from '@mui/x-date-pickers/locales';
import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";

class DateAdapter extends AdapterDateFns {
    // 参考サイトの実装例よりも、端折っているが、日曜始まりが固定なら以下で十分。
    getWeekdays = (): string[] => ['日', '月', '火', '水', '木', '金', '土'];
}

export const SpeechRecognitionEditPage: React.FC = () => {
    const TODAY = new Date();
    const [selectedDate, setSelectedDate] = useState(TODAY);

    const theme = createTheme(
        {},
        jaJP, // x-date-pickers translations
    );

    const onChangeHandler = (e: Date | null) => {
        if (!e)
            return;
        setSelectedDate(new Date(e.getFullYear(), e.getMonth(), e.getDate()));
    }

    return (
        <ThemeProvider theme={theme}>
            <LocalizationProvider dateAdapter={DateAdapter} dateFormats={{ monthAndYear: "yyyy年 MM月", monthShort: "MM月" }} >
                <DateCalendar
                    views={['month', 'day']}
                    value={selectedDate}
                    maxDate={TODAY}
                    onChange={onChangeHandler}
                />
            </LocalizationProvider>
        </ThemeProvider>
    );
}
```


曜日ヘッダーは、公式プロップスのdayOfWeekFormatterでもよさそう。

# 参考

https://zenn.dev/longbridge/articles/e6f0d6ac0a3559

https://github.com/mui/mui-x/issues/4605#issuecomment-1105257098

https://next.mui.com/x/react-date-pickers/adapters-locale/#custom-day-of-week-format
golang ✕ gRPCでWeb用のプロキシサーバやgRPC-WEBを挟まずにブラウザからRPCをコールする [gRPC ✕ golangをDRYに Part.1]

## この記事のターゲット層
- viviONという会社に興味がある方
- golangのAPIについて学びたい方
- [gRPC](https://grpc.io/)を触り始めた方

## 筆者が抱えているgRPCの最大の課題感

### クライアントサイドからRPCを呼び出す為には、やること多すぎて辛いんだってばよ。。。。！

ただでさえgolangは「ハハハ、golang？筋トレにはちょうどいい言語だね！」とDisられるほど特定のロジックを組むためには大量のcode stepを要求される言語です。

APIサーバ間の通信には当たり前ですが、クライアントサイドが存在しており、ただでさえ記述量の多い言語なのにgRPCでAPIコールをしようとするとリクエストstructを他のリクエスト用structに型変換するだけで一日が終わってしまいます。

### 問題その② ブラウザ(クライアントサイド)からカジュアルにRPCを呼べない

これを解消するためには、gRPCサーバの前段にProxyを置くかgrpc-webを利用する必要がありました。

以下がそのリポジトリです。

- https://github.com/grpc/grpc-web
- https://github.com/grpc-ecosystem/grpc-gateway

サーバなど立てずにもっとカジュアルに```curl http://xxx.com/posts```みたいなターミナルからワンライナーで呼び出せると嬉しいですよね > <

## 時代は進歩し前段にProxyを挟まくてもjson curlをサポートしてくれるOSSがあった

protobufジェネレータで有名な[Buf](https://buf.build/)を開発している「Buf Technologies, Inc」の[connect-go](https://github.com/bufbuild/connect-go)です。
![スクリーンショット_2022-06-22_21.04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170923/21bd2883-6a2f-b5e1-25f9-d764eddcdf1d.jpeg)

(※ Node.js版はまだ、試験運用段階で、今年中にはProductionになるのではないかとのことです。)

### connect-goはgRPCのラッパー
アプリ内部では基本的にこれまで通りリクエストとレスポンスにprotobufを利用するのですが、アプリケーションレイヤーレベルでconnectが存在しており、http/(1 or 2)でのリクエストをラッピングしてprotobufにコンバートしてくれます。

つまり、以下のようなgRPC呼び出しが
``` sh
grpcurl \
    -plaintext \
    -d '{"title": "Hello"}' \
    localhost:8000 example.v1.GreetService/Greet
```

以下のように呼び出すことが可能です。

``` sh
curl \
    --header "Content-Type: application/json" \
    --data '{"title": "Hello"}' \
    http://localhost:8000/example.v1.GreetService/Greet
```

更に凄いのがcurl + ```--http2```オプションで呼び出してもちゃんと動作する為、[guzzle](https://github.com/guzzle/guzzle)等の**メジャーHTTP Clientから高速なプロトコルであるhttp2を利用してRPCを呼び出すこともできます**。

### つまり、gRPCとJSON:APIの両対応ハイブリッド状態でAPIを公開できる ... ! (凄い!)

## まとめ
gRPCがAPIの標準になる世界はもうすぐそこまで来ているのかもしれない。。

Part.2は 「[protocからBufに乗り換えて設定をソースコード管理しよう](https://qiita.com/taisei_otsuka/items/78d49f03536086944d07)」です☆

## 採用PR

https://hrmos.co/pages/vivion/jobs/0000226

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/2000f749-3e82-7a47-b1c4-4444e237f79c.png" width=45%>
hashcatの使い方｜ハッシュ値のクラッキング

# 概要

hashcatは、パスワードハッシュのクラックや解析に特化したツールで、様々なハッシュアルゴリズムに対応しています。

# インストール

Kali Linux で hashcat をインストールします。ターミナルで以下のコマンドを実行します:

```bash
sudo apt update && sudo apt install hashcat
```

# 使い方

クラックしたいパスワードハッシュを取得します。
例えば、ハッシュがファイル`hashes.txt`に保存されているとします。

hashcat を実行します。以下のようなコマンド構文を使用します:

```
hashcat [オプション]... ハッシュファイル ワードリストファイル
```

例えば、ハッシュのタイプが MD5 である場合、次のようなコマンドを使用できます:

```
hashcat -m 0 hashes.txt wordlist.txt
```
`-m`オプションはハッシュのタイプを指定し、`0`はMD5を意味します。
`hashes.txt`はハッシュが格納されているファイル、`wordlist.txt`はクラックに使用するワードリストファイルです。

実行後、hashcatはワードリストを使用してハッシュをクラックしようと試みます。

# アルゴリズムに関して

|ハッシュアルゴリズム|オプション|
|---|---|
|MD5|`-m 0`|
|SHA1|`-m 100`|
|SHA-256|`-m 1400`|
|SHA-512|`-m 1700`|
|bcrypt|`-m 3200`|
Salesforce入力規則の基本を徹底解説してみた

こんにちは
本橋孝昭です

今回はSalesforceの入力規則の基本について解説しました

今回の内容は動画でも解説しています

https://youtu.be/0Va7o9UUoE4

<iframe width="560" height="315" src="https://www.youtube.com/embed/0Va7o9UUoE4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>




## 1 入力規則ってどんな時に使えるか？

入力規則は
・特定のレコード条件の場合特定の項目の値でない場合（空欄など）エラーを出して保存させないことが可能

という機能です
・入力規則作成例　商談フェーズを「受注」にした場合、必ず商談の金額項目を必須にしたい（新規作成時などは金額項目は必須でなくてもいい）


なお、似たような話として

・特定の項目を必須で入力してほしい
という場合は（入力規則でも対応可能ですが）一般的に項目やページレイアウトで「必須」設定にします


ここらへんの違いについては別途記事で解説していますのでご確認ください


Salesforceで項目の必須の考え方～入力規則や必須項目について
https://qiita.com/Takaa/items/16fc656ae27eb12aaca7

このように入力規則を設定すれば

・特定の条件の場合必ず項目変更や項目に記載を促すことでデータの入力間違えや入力漏れを防ぐ

という設定が可能です

特にSalesfroceのデータをのちのち分析に使いたい場合、データの入力漏れがあるとデータ分析が難しいので、この入力規則は便利ですね

（しかしながら、たくさん入力規則を作成してしまうと「何をやってもエラーになってしまうのでSalesforceのデータ入力が難しくなる」という問題も発生してしまうので入力規則作成は入力するユーザのことも考えほどほどでの作りこみがいいかもしれないですね）


## 2 入力規則はどのタイミングで適用されるか？

よくある質問として
「入力規則はいつ動くの？」という問題があります

基本的には
「レコードの保存ボタンをクリックした場合に動く」
と覚えれば大丈夫です
しかしながら、細かい話を入れると

・データローダなどの一括レコード作成や一括編集の場合も入力規則は適応されます
（一括作成や更新の場合、入力規則に引っかかる条件があった場合、その条件のレコードのみ作成や更新はできません）

（例　商談レコード100件をデータローダで一括作成しようとしたが入力規則に引っかかるデータが20レコードあった場合、80レコードは問題なく作成されるが20レコードは作成されない）

・WebtoリードやWebtoケースなど特定の機能でレコード作成の場合も入力規則jは適応されます


参考ヘルプより抜粋

＞Salesforce は、Web-to-リードおよび Web-to-ケースによって登録されたレコードを作成する前に入力規則を実行し、有効な値を持つレコードを作成します。

https://help.salesforce.com/s/articleView?id=sf.fields_validation_considerations.htm&type=5

## 2 入力規則が適用されない場合はどのタイミングでか？

Salesforceにはルール適応される順番があります

下記ヘルプにもあるように入力規則は結構最初のほうに動くルールであることがわかりますね
https://help.salesforce.com/s/articleView?id=000383414&type=1

そのため
・ワークフロールールの項目自動更新
や
・プロセスビルダーの項目自動更新
では入力規則は適用されません

## 3 入力規則作成方法

入力規則を作成するためにはエラー条件数式の作成が必須です

エラー条件数式の作成方法はこちらのサンプル数式をご確認ください

入力規則の例
https://help.salesforce.com/s/articleView?id=sf.fields_useful_field_validation_formulas.htm&type=5

[数式 サンプル] 入力規則により項目の入力を必須とする数式
https://help.salesforce.com/s/articleView?id=000384909&type=1

なお、エラー条件数式では特定のプロファイルユーザやカスタム権限を設定した特定のユーザのみ入力規則を適用させる　という高度な設定も可能です

詳細については別途まとめたこちらの記事をご確認ください

Salesforceで特定の複数ユーザのみ入力規則を適用させない方法
https://qiita.com/Takaa/items/931a0fd13ea1effcc83c

## 3 入力規則作成画面

入力規則を作成するためには以下の4つを埋めることが大事です

1 ルール名
2 エラー条件数式
3 エラーメッセージ
4 エラー表示場所

![会社002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/873dde5b-c92e-c813-dcff-c357d78e5de0.png)


エラーメッセージは入力規則が適用される場合に表示されるメッセージです

エラー表示場所は2種類あります

![会社001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/0771d715-d554-ecb6-8621-96c9c379c2d6.png)

　上画像のようにキャンセルの上のほうにメッセージを表示させることができるのは
・エラー表示場所　ページの最上位へ
です

![会社003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/5291bf0b-ebd7-0861-a59e-87fac9f1269e.png)

上画像のように項目部分にエラーメッセージを表示させるのが

・エラー表示場所　項目
です
jetpack composeで複数のジェスチャーを検知する方法

# 初めに
今回はjetpack composeで一つのViewに対して複数のジェスチャーを検知する方法を紹介していこうと思います
### 本文
```kotlin
Modifier.clickable{}
```
通常のクリックのみの場合は上記のようにすればいいのですが、それ以外のジェスチャーを取得するには下記のようにしなければいけません。
```kotlin
Modifier.pointerInput(Unit) {}
```
ただし、上記のように書いただけでは、タップ系のジェスチャーかピンチイン・ピンチアウト系のジェスチャーのどちらかしか設定できません。
両方設定しようとすると、片方に上書きされてしまいます。

そこで今回の本題です
```kotlin
Modifier.pointerInput(Unit) {}.pointerInput(Unit) {}
```
実は`pointerInput`は複数呼び出すことができ、片方ずつにタップ系とピンチ系を設定することで上書きされることなく使うことができます
### 最後に
Composeが使われるようになってきて段々と複雑なViewを作ることが増えてきたので備忘録として残しておきます
どなたかのお役に立てれば幸いです