OmniAICreator/Qiita-1.07M huggingface dataset:
wordpress + nginxで日本のIPからのみログインページへアクセスを受け付ける(IPv6編)

# はじめに

WordPressでサイトを公開していると不正ログイン試行がたくさん来ます。
残念ながら、そのほとんどが海外からのものです。
私の使用ケースでは海外から更新する人はいないので、日本のIPからアクセスがあった場合のみログインページを表示するようにしてみました。


# とりあえずやってみる

下記サイトにて同じようなことをやっている方がいたので参考にさせていただき、次のようにしてみました。
[Nginxで特定の国のIPだけを許可する方法](https://oxynotes.com/?p=10527)

```nginx:wp-login_jpip_only.conf.parts
location = /wp-login.php {
    # JP IP Address
    allow 000.000.000.000/24;
    # ＜＜中略＞＞

    deny all;

    # 一時的に、確認のためにログを分ける
    access_log  /var/log/nginx/access_wp-login.log;
    error_log  /var/log/nginx/error_wp-login.log error;

    # WordPressを動かすPHPの環境に合わせて下記は変えてください
    # (例示は別ファイルに分けている場合です)
    include /etc/nginx/sites-available/wordpress-php.conf.parts;
}
```

設定後、nginxをリロードしたら `tail -f /var/log/nginx/access_wp-login.log` で来ているアクセスを監視してみましょう。

すると次のようなログが流れてきました

```/var/log/nginx/access_wp-login.log
＜＜IPv6アドレス＞＞ - - [06/Aug/2023:xx:xx:xx +0900] "GET /wp-login.php HTTP/1.1" 403 134 "-" "＊＊＊＊＊＊＊＊＊＊"
```

はい、タイトルで出オチしていますが **IPv6のことを考慮できていません** でした。
(IPv6が割り当てられているサーバーなのを忘れていました。)


# ではどうするのか

日本ネットワークインフォメーションセンター(JPNIC)で管理されているIPv6アドレスは、下記ページにて公開されています。
[https://www.nic.ad.jp/ja/dns/ipv6-addr-block.html](https://www.nic.ad.jp/ja/dns/ipv6-addr-block.html)

本記事では『JPNICで管理されているIPv6アドレス＝日本のIPv6アドレス』とします。
(話がややこしくなるので)

こちらで公開されているIPv6アドレスをもとに、先ほどのファイルを修正しましょう。

```nginx:wp-login_jpip_only.conf.parts(その2)
location = /wp-login.php {
    # JP IPv4 Address
    allow 000.000.000.000/24;
    # ＜＜中略＞＞

    # JP IPv6 Address
    allow 0000:0000::/32;
    # ＜＜中略＞＞

    deny all;

    access_log  /var/log/nginx/access_wp-login.log;
    error_log  /var/log/nginx/error_wp-login.log error;
    include /etc/nginx/sites-available/wordpress-php.conf.parts;
}
```

# さいごに

例示しているnginxの設定ファイル中のIPアドレスは大噓なので、くれぐれもそのままコピペしないようにお願いいたします。
せんせー、ダークウェブ解析ってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/7f59d21b-0564-377b-a326-47169950dc66.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/319ddbbb-e9dd-5833-688d-5808a705af9b.png)

せんせー、ダークウェブ解析ってなに？

# ダークウェブ解析とは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/754ad1db-cf66-be94-8f33-137d3e28f1cc.png)

ダークウェブ解析というのは、ちょっと難しい話かもしれないけど、まるで宝探しのようなものだと考えてみてください。

君がお家で遊んだり、公園で遊んだりする場所はみんなが見て、知っている場所ですよね。
これを「普通のウェブ」に例えることができます。

でも、隠れた場所や秘密の部屋など、みんなが見えない場所もありますよね。
これが「ダークウェブ」のようなものです。
ダークウェブは、普通のウェブで見つけることができない場所にあるから、特別な方法で見つけないといけないんです。

ダークウェブ解析とは、この隠れた「ダークウェブ」を探し、何が行われているのかを調べることです。
ちょうど宝探しのように、隠れた場所を見つけて、そこに何があるのかを探るんです。

でも、ダークウェブは大人たちが使っていて、時々良くないことが行われる場所もあるから、君たちが探しに行くべき場所ではないんです。大人たちはそのために、ダークウェブ解析を使って、インターネットが安全になるように助けてくれるんです。

だから、ダークウェブ解析は、ちょっとした宝探しのようで、でもとても大切な仕事なんです。

# まとめ

ダークウェブ解析というのは、ちょっと難しい話かもしれないけど、まるで宝探しのようなもの
せんせー、フォトニクスってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/7f59d21b-0564-377b-a326-47169950dc66.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/319ddbbb-e9dd-5833-688d-5808a705af9b.png)

せんせー、フォトニクスってなに？

# フォトニクスとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/754ad1db-cf66-be94-8f33-137d3e28f1cc.png)

フォトニクスというのは、光を使う科学のことです。
君が虹の色や、光が水やガラスを通るときにどう変わるかを見たことがありますか？
それもフォトニクスの一部なんです。

君が手元にあるライトをつけて、部屋を明るくしたり、暗くしたりすること、想像してみてください。
それは、光を使って物事をコントロールする一つの方法です。

フォトニクスの専門家たちは、光を使って色々なことをする方法を考えるんです。
例えば、光を使って情報を送ったり、物を見つけたり、さらには病気を治したりする方法を研究しているんです。

光は速くて、たくさんの情報を運ぶことができるから、とても便利です。
だから、フォトニクスは未来のテクノロジーを作るためにとても重要な学問なんです。

# まとめ

フォトニクスというのは、光を使う科学のこと
Javaアプリで、ある環境だけSSL証明書エラーが出るようになったら、SSL可視化が原因かも

ある日突然、ある顧客の環境で下記のエラーが出るようになってしまいました。

```
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
```

弊社環境では出ないですし、他社さんでも同様の報告はありません。

それって、SSL可視化が原因かもしれません。


# SSL可視化とは

常時SSL（AOSSL：Always On SSL）が進み、盗聴のリスクが低減した昨今ですが、それによりファイアウォールでの脅威検知ができなくなってしまいました。

そこでSSL通信も覗いちゃおうというのがSSL可視化です。

盗聴できないのに覗き見るとはどうやんの？？？


「ファイアウォールが中間者攻撃している」と言えばわかりやすいでしょうか。

証明書がすり替わるのでそのままだとブラウザは例のエラー画面になってしまいます。

しかし、ファイアウォール自身が発行するオレオレルート証明書をクライアントにインストールすると、エラー画面になりません！

Active Directoryで管理された環境ならオレオレルート証明書を自動配布することも可能で、管理下のPCでは特に気にすることなく普段の業務ができます。

ここで、Java環境がケアされていないと、JavaアプリだけSSL証明書エラーが出るようになってしまいます。

なお、SSL可視化はベンダーによって、SSLインスペクション、SSLインターセプトなどと呼ばれています。


# 解決策

先方環境のファイアウォールからエクスポートしたオレオレルート証明書をJava環境にインポートする必要があります。
（もしくは通信先をSSL可視化から除外する設定をする）

開発側は手を出せません。解決策はメールを出すのみ。


>お問い合わせありがとうございます。
>SSL証明書エラーが出るようになったとのことでご迷惑をおかけし申し訳ございません。
>弊社テスト環境で調査しましたが、正常に動作しました。また、他社で同様の不具合は報告されておりません。
>以前、同じ現象があった際は、その環境でファイアウォールの構成変更があり、それが原因だったということがありました。
>構成変更で、SSL可視化（SSLインスペクション、SSLインターセプトとも）が行われたとのことでした。
>恐れ入りますが、御社システム部門に一度お問い合わせいただけないでしょうか。
>お手数おかけし申し訳ございません。
>以上、よろしくお願いいたします。
せんせー、プロセッシングチップってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/7f59d21b-0564-377b-a326-47169950dc66.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/319ddbbb-e9dd-5833-688d-5808a705af9b.png)

せんせー、プロセッシングチップってなに？

# プロセッシングチップとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/754ad1db-cf66-be94-8f33-137d3e28f1cc.png)

プロセッシングチップというのは、コンピュータやスマートフォン、
テレビゲームなどに入っている、とても小さな頭脳みたいなものです。

この小さな頭脳は、コンピュータが考えたり、計算したりするのを手伝ってくれるんです。
だから、ゲームを遊んだり、動画を見たりするときに、スムーズに動くようにしてくれるんです。

プロセッシングチップを作ることは、ちょっとした魔法のようなものです。
とても小さいけれど、とても賢いです。開発するというのは、この小さな魔法の頭脳を作ることなんです。

おもちゃのブロックを組み立てるように、たくさんの小さい部品を組み合わせて、
1つのプロセッシングチップを作ります。それを使って、コンピュータやゲーム機が動くようになるんです。

だから、プロセッシングチップ開発は、とても小さな部品で大きな魔法を作る、特別な仕事なんです。

# まとめ

プロセッシングチップというのは、コンピュータやスマートフォン、
テレビゲームなどに入っている、とても小さな頭脳みたいなもの
2023年7月振り返り〜レビュワーデビュー〜

## はじめに
さぁ、7月の振り返りです！
毎月の振り返りは、自分用ではあるのですが、
社外の勉強会などで繋がった方が、時々読んでくださったり、見たことあると
言っていただけたり、このブログきっかけに嬉しいこともあったり。

とはいえ、今月も自分用に振り返りしています←。よろしくお願いします！

## 2023年7月のざっくり振り返り
**なかなか濃い1ヶ月でした** （毎月言ってる気がしますが、毎月思っています）

プラスの面だと、**レビュワーデビューしたり、初めて社外でLTしたり** 、
自信に繋がったり、成長を実感できることも多かった月だったなと。

一方で、**組織やチームの課題に目を向ける機会**も多く、
**自分自身の能力不足や信頼不足などを痛感**することもあったり。
自己認識としてはあまり感情の上下はないタイプだと思っていましたが、
さすがに上下を感じた月でした。

ただ途中からは、**この半年、一旦やりきってみよう** と結構吹っ切れたなと。
（特に半年というのに意味はなく、年内区切りがいい、ぐらいです）
半年やりきって、また考えてみる。というか、毎日この繰り返しではあります。
結論の出ないことや、自分では変えられないことを考え続けてること自体、
勿体ないなと思うようにしているのと、
自分と同じように、またはそれ以上にチーム、組織に向き合っていただいているなと
感じることが多いので、ここで落ちている場合ではないと思えるようにはなりました。

#### 今月おもしろかった、気になった記事、本など
・Googleのコードレビューの観点

https://fujiharuka.github.io/google-eng-practices-ja/ja/review/reviewer/looking-for.html

ソースレビューに入らせていただくことになり、どうあるべきかを学びたいな〜と思っていたら
ちょうどTwitterで流れてきて見つけました。これは定期的に読んで血肉にしていきたい。


・プリンシプル オブ プログラミング3年目までに身につけたい一生役立つ101の原理原則

https://www.amazon.co.jp/%E3%83%97%E3%83%AA%E3%83%B3%E3%82%B7%E3%83%97%E3%83%AB-%E3%82%AA%E3%83%96-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B03%E5%B9%B4%E7%9B%AE%E3%81%BE%E3%81%A7%E3%81%AB%E8%BA%AB%E3%81%AB%E3%81%A4%E3%81%91%E3%81%9F%E3%81%84%E4%B8%80%E7%94%9F%E5%BD%B9%E7%AB%8B%E3%81%A4101%E3%81%AE%E5%8E%9F%E7%90%86%E5%8E%9F%E5%89%87-%E4%B8%8A%E7%94%B0-%E5%8B%B2/dp/4798046140

1年目に読んでいたのですが、**当時は抽象的で難しい、、** と思っていていました。
改めて読み返すと、落とし込まれる感覚が1年目のときと違いました。
このタイミングで読んでよかったなと同時に、本の難易度調整、大事だなと感じました。

## 印象に残ったトピック
今月は2点。
プラスの変化を感じた部分からピックアップしています

#### ①レビュワーデビュー
ソースコードの一部レビューすることになりました（パチパチ）
業務委託の方にレビューいただいたことをきっかけに
これならレビューも少しずつ任せられるのではということで、デビューです

力がついたことを評価いただけたこと自体嬉しかったですし、
レビューできることでチームの開発スピード向上にも貢献できるようになると思うと嬉しさ倍増です
レビュー時に感覚的なことを伝えるわけにいかないと思い、公式のdocや本を読み返すことになり
結果、　今が1番学びの吸収力高い気がしています。
やっぱり自分ごとになると学びの速度上がりますね〜〜〜

#### ②社外で初のLT発表
社外で初めて発表してきました。
ネタはこちら

https://qiita.com/makky/items/368567913b82f9646d98

社外の方からFBいただけるのは、社内にない視点も多く学びが多かったです。
今回のインシデント管理のLTでいうと、**1メンバーがこの経験をできたこと** 自体が
貴重な経験だったんだなと。社内だけでFBもらっていると気づかない点でした。
今月以降も定期的に発表できるよう、ネタ仕込んでいきます。


## 終わりに
下期1発目、相変わらずあっという間の1ヶ月、
そしてなかなかハードな1ヶ月でしたが、その分大きな変化も感じられた1ヶ月でした。


余談ですが、こういうときに、DeNA会長の南場智子さんの「こと」に向かう　を思い出します。

https://note.com/narumi/n/n1aeb76bbbe4e

https://dena.com/jp/article/3156/

成果に向かって進むことだけを考える、そう思うと個人的には気が楽になりますし、
ふと立ち止まる場所になっている感覚でもあります。
改めて成果に向かって1つずつ進んでいけたらなと。
[備忘録] error TS1005, TS1011, TS1128 の解消

# はじめに

AWS CDK TypeScriptプロジェクトを作成し、npm run build を実行したところ、下記のエラーが発生した。

```
node_modules/@types/babel__traverse/index.d.ts:68:50 - error TS1005: ']' expected.

68 export type ArrayKeys<T> = keyof { [P in keyof T as T[P] extends any[] ? P : never]: P };
                                                    ~~

node_modules/@types/babel__traverse/index.d.ts:68:53 - error TS1005: ';' expected.

68 export type ArrayKeys<T> = keyof { [P in keyof T as T[P] extends any[] ? P : never]: P };
                                                       ~

node_modules/@types/babel__traverse/index.d.ts:68:58 - error TS1005: ';' expected.

68 export type ArrayKeys<T> = keyof { [P in keyof T as T[P] extends any[] ? P : never]: P };
                                                            ~~~~~~~

node_modules/@types/babel__traverse/index.d.ts:68:70 - error TS1011: An element access expression should take an argument.

68 export type ArrayKeys<T> = keyof { [P in keyof T as T[P] extends any[] ? P : never]: P };
                                                                        

node_modules/@types/babel__traverse/index.d.ts:68:83 - error TS1005: ';' expected.

68 export type ArrayKeys<T> = keyof { [P in keyof T as T[P] extends any[] ? P : never]: P };
                                                                                     ~

node_modules/@types/babel__traverse/index.d.ts:68:84 - error TS1128: Declaration or statement expected.

68 export type ArrayKeys<T> = keyof { [P in keyof T as T[P] extends any[] ? P : never]: P };
                                                                                      ~

node_modules/@types/babel__traverse/index.d.ts:68:88 - error TS1128: Declaration or statement expected.

68 export type ArrayKeys<T> = keyof { [P in keyof T as T[P] extends any[] ? P : never]: P };
                                                                                          ~


Found 7 errors.
```

# 実施したこと

typescriptのバージョンを上げたら、ビルドできることが確認できた。

```package.json
"typescript": "~3.9.7"
```
↓
```package.json
"typescript": "^4.9.3"
```

# 最後に
参考にした文献を記す。
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/63431
スッキリわかるJava入門 第３版を読んでみて- part５ -メソッド

# はじめに
こんにちは(・ω・）ﾉ
今回はメソッドについて学びました！
## 第５章　メソッド
### 1.　メソッドとは
　複数の文をまとめ、それを１つの処理として名前をつけたもの
　部品の最小単位

:sparkles:メソッド利用のメリット
・プログラムの見通しがよくなり、全体を把握しやすくなる
・機能単位に記述するため、修正範囲を限定できる
・同じ処理を１つのメソッドにまとめることで、作業効率が上がる

:pencil2:メソッドの定義
```
public static 戻り値の型　メソッド名（引数リスト）{
　メソッドが呼び出された時に実行される具体的な処理
}
```
{}の中...メソッドブロック
メソッド名を呼び出した時に実行される

:pencil2:メソッドの呼び出し
`メソッド名(引数リスト)`
※mainメソッドより上に別のメソッドがあってもプログラムは必ずmainメソッドから始まる

:sparkles:メソッドにまつわる２つの立場
　メソッドを定義する立場とそのメソッドを呼び出す立場をわけて捉える

:sparkles:メソッド定義の１行目は人と人との接点
　メソッド定義の１行には、定義する人と呼び出す人との接点となる重要な情報が書かれる

### 2.　引数の利用
__引数__...呼び出し元から渡される値

:sparkles:引数の渡し方
何も渡さない場合：　`メソッド名()`
値を１つ渡す場合：`メソッド名（値）`
値を複数渡す場合：`メソッド名（値、値、...）`

渡す値...実引数
受け取る変数...仮引数

__ローカル変数__
・メソッド内で宣言した変数
・そのメソッド内でのみ有効

:sparkles:引数の渡し方
異なるメソッドに属するローカル変数は、お互いに独立していて無関係である

### 3.　戻り値の利用
戻り値とは
　呼び出されたメソッドから呼び出したメソッドに返す
　戻される値...__戻り値__

:pencil2:値の戻し方
```
public static 戻り値の型　メソッド（引数リスト）{
　メソッドが実行された時に動く処理
return　戻り値;
}
```
※何も戻さない時...「void」を指定する
void...何もない

:pencil2:戻り値の受け取り
```
型　変数名　= メソッド名(引数リスト);
```
戻り値は１つのみ

return文の終了
returnはメソッドの終了も行う
return文のあとに処理は書けない ⇨ エラーになる
### 4.　オーバーロードの利用
メソッドに同じ名前は基本的につけられない
同じ名前を定義すること...__オーバーロード（多重定義）__

:sparkles:オーバーロード
・仮引数の個数が型が異なれば同じ名前のメソッドを複数定義できる
・引数は同じで戻り値の型だけが異なるものは定義できない

__シグネチャ__
メソッド名、引数の個数や型とその並び順の情報のこと

オーバーロードはシグネチャが重複しない場合のみ許される
### 5.　引数や戻り値に配列を用いる
メソッドの引数には配列も使える
※メソッドに引数として渡しているのはアドレス情報のみ

値そのものが渡される呼び出し...値渡し

:sparkles:基本型の変数をメソッド呼び出しで渡すと
・呼び出し元の変数の内容が、呼び出し先の引数にコピーされる
・呼び出し先で引数の内容を書き換えても、呼び出し元の変数は変化しない

引数としてアドレスを渡すこと...参照渡し
呼び出し先で加えた変更が呼び出し先に影響する

:sparkles:配列をメソッド呼び出しで渡すと
・呼び出し元の配列のアドレスが、呼び出し先の引数にコピーされる
・呼び出し先まで配列の実態を書き換えると、呼び出し元にも影響する
### 6.　コマンドライン引数
:question:mainメソッドは「誰」が「どんな」引数を渡しているか
⇨Javaがプログラムを起動するとき「追加情報」を指定して起動している
追加情報...__コマンドライン引数__

:pencil2: コマンドライン引数を利用したJavaプログラムの起動
```
java　プログラム名　引数リスト
```

:sparkles:コマンドライン引数
プログラム起動時に指定したコマンドライン引数が、
JVMによって配列に変換されmainメソッド起動時に渡される

## まとめ
メソッドをうまく使うことでプログラムの見やすさや作業の効率が上がることを知りました。
mainメソッドから必ず始まることをちゃんと覚えておきたいと思います。
コードを見ている時にpublic static voidってなんだろ？と心の片隅にあった疑問が今回でなんとなくわかるようになったのがよかったです。
オーバーロードは理解しきれていない感じがするのでまた次回の時に見直しを入れたいです。
だんだんと内容も難しくなってきましたが頑張ります(๑•̀ - •́)و✧

今回もありがとうございました！
ではまた〜　＊˙︶˙＊)ﾉ"
Excelで階層構造を表現したパラメータを1行に変換する

## はじめに
Excel内で階層構造を表現したパラメータを連結して表現したいことがある。

…あるかな？

あった。
あったので記事に残しておく。

## 一例
例えば「日本の関東地方の東京都の江東区」の様に階層構造（親子関係）を持つパラメータを以下のように表現することが出来る。

```
日本
┗関東地方
　┗東京都
　　┗江東区
```

それをExcelでインデントを空のセルで表し以下のように表現できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3300735/6fc4b605-49b6-56ef-e481-4b422786eeb9.png)

資料として参照するには見やすい場合もあるが、データとして読み込むには些か不便な形式といえる。
（これをなんと表現するのかが難しい…。方眼紙？）

その階層構造を以下の様に変換したい。
```
日本.関東地方.東京都.江東区
```


## 読み込みの具体例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3300735/9a6684e3-c130-9563-cce7-5445da94f708.png)

画像の一番右の様に変換したい。


## ソース
##### Typeの定義：保持したいデータ構造を定義する。
連結したパラメータはfullの方に、連結前の1セルのパラメータはfullでない方に。
```
Type データ定義
    param_full As String
    param As String
End Type
```
##### 関数「main」：ボタン等から呼び出させる主関数
```
Public Sub main(path As String)
    Dim wb As Workbook
    Set wb = Workbooks.Open(path)
    Call read(wb)
End Sub
```
##### 関数「read」：セル範囲を上から順に読み込む
```
Private Sub read(wb As Workbook)
    With wb.Sheets("対象のシート名")
        Dim r As Range
        Set r = Range("C4:E42") '読み取り範囲
    End With
    
    Dim data() As データ定義
    ReDim data(r.Rows.Count - 1) As データ定義
    Dim 階層1 As String, 階層2 As String, 階層3 As String
    
    For i = 1 To r.Rows.Count
        'パラメータがどのセルに入ってるかで処理を変える
        If r(i, 1) <> "" Then
            data(i - 1).param = r(i, 1).Value
            階層1 = r(i, 1).Value
            階層2 = ""
            階層3 = ""
        ElseIf r(i, 2) <> "" Then
            data(i - 1).param = r(i, 2).Value
            階層2 = r(i, 2).Value
            階層3 = ""
        ElseIf r(i, 3) <> "" Then
            data(i - 1).param = r(i, 3).Value
            階層3 = r(i, 3).Value
        ElseIf r(i, 4) <> "" Then
            'data(i).param = r(i, 4).Value
        Else
        End If
        data(i - 1).param_full = 連結(階層1, 階層2, 階層3)
        
    Next
End Sub
```
##### 関数「連結」：複数の引数をもとに連結した文字列を返却する
```
Private Function 連結(p1 As String, p2 As String, p3 As String) As String
    Dim 連結用リスト() As String
    ReDim 連結用リスト(0)
    連結用リスト(0) = p1
    
    If p2 <> "" Then
        ReDim Preserve 連結用リスト(1)
        連結用リスト(1) = p2
        
        If p3 <> "" Then
            ReDim Preserve 連結用リスト(2)
            連結用リスト(2) = p3
        End If
    
    End If
    
    連結 = Join(連結用リスト, ".")
End Function
```
最初は&で連結しようと思ったが、性能がより良さそうときいたJoinで実装



## 最後に
自分の適当に作ったソースを見せるのは恥ずかしい
DBeaverでParquetファイルを読み込む

Windows PCでParquetファイルを読み込むのって、簡単な方法がイマイチなくて困ってました。
個人の話ならpythonスクリプト書くなりなんなりで好きにやればいいわけですが…やはり簡単な方法を用意し、チームに展開できないと。

と思い度々調べていたんですが、なんと**DBeaver**で簡単に読み込める方法があるということをこちらのStackOverflowの回答から発見いたしました。

https://stackoverflow.com/questions/50933429/how-to-view-apache-parquet-file-in-windows/74010343#74010343

後から調べたところ、本質的にはDuck DBがParquetの読み込みをサポートしているということで、Duck DBをサポートしているDBクライアントツールなら何でもいけるかと。
チームに展開する際の備忘録としても、整理した内容をこちらに残します。

# Duck DB インスタンスの用意

と言ってもMySQLなどのように環境の準備が別で必要だったりはしません。
DBeaverの「新しい接続」からDuckDBというのを選択すればいいだけ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385410/8c9eb171-679a-a566-422d-1d12da3969b3.png)

その後表示される以下の画面の「パス」には __:memory:__ と記述するとインメモリのDBインスタンスとなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385410/253a8c8c-c2b6-9222-301c-30f50b68da9e.png)

試しにテスト接続を押してみましょう。
初回だと恐らくこのタイミングでドライバのインストール画面が表示されると思いますが、基本OKOKと選ぶ感じで。

無事、接続成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385410/8ee9dd64-12ad-41ae-e161-cad67f188376.png)

Finishのボタンを押すとDBの接続の一覧に"memory"という名前のDuckDBとの接続が追加されていることと思います。

ちなみにDuckDB公式の手順はこちら
https://duckdb.org/docs/guides/sql_editors/dbeaver

# Parquetファイルを読み込む

作成された接続を右クリックで新しいSQLエディタを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385410/10030462-d6d6-d933-f4a2-bb63b0deae52.png)

そして以下のようなクエリでファイルを指定して読み込んだらもう完了！

```sql
SELECT * FROM 'parquetファイルへの絶対パス'
-- example
SELECT * FROM 'C:\Users\nantoka-user\Downloads\test.parquet'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385410/f3e06440-b668-43f6-7be5-aee54f7ecdf1.png)
※適当なサンプルファイルをこちらから頂きました。
https://github.com/mukunku/ParquetViewer/tree/master/src/ParquetViewer.Tests/Data

# CTASでテーブルも作れる

読み込める、ということはもちろんCTASによってテーブル化できます。
大きなファイルをいちいち読み込む処理をかけるよりは、恐らくテーブルに持ってしまってその後の集計クエリなどをかけるのが良いかと。

```sql
CREATE TABLE test_p AS SELECT * FROM 'C:\Users\nantoka-user\Downloads\RANDOM_TEST_FILE1.parquet'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385410/5b6768a6-9620-64a0-1e0d-ff908fc84e90.png)

# parquetファイルへの書き出しもできる

以下のクエリで書き込みもできるようです。テスト用データの作成などに便利ですね。

```sql
COPY {テーブル名} TO 'ファイルパス' (FORMAT 'parquet')
-- example
COPY example_table TO 'C:\Users\nantoka-user\Downloads\example.parquet' (FORMAT 'parquet')
```

# 終わりに

少し前はtimestamp型の読み込みができなかったりもしたんですが、どんどんIssue対応で機能がアップデートされています。
今できないこともじきに対応されると思われますし、自身でDBeaverやDuckDBのリポジトリにIssueを上げてみるのも良いのではないでしょうか。
CakePHP4(3)で表示件数を変更するUI

limitのコントローラーでの変更やテンプレートの書き方の記述はいくつかあったけど、CakePHPの標準機能を使った方法が無かったの書いておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592669/c88c9c9d-a0a1-af90-9492-f2360ede64ef.png)


~~~Template
<?php
     echo $this->Paginator->limitControl(
        [
            25 => "25件",
            50 => '50件',
            100 => '100件'
        ],
            25,
        ['label'=>'表示件数:']
    );
 ?>
~~~

第二引数のデフォルトの表示件数は個人的にはcontroller側で指定した方が無難な気がします。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592669/44c81a0b-5842-ce33-7b50-ffdf30e43240.png)
https://book.cakephp.org/4/ja/views/helpers/paginator.html
SpringBoot環境でpropertiesファイルを分ける 

### はじめに
SpringBootは起動時パラメータを定義することで、使用するpropertiesファイルを変えることができるらしい
本番環境とテスト環境で接続DB等の情報を変更したいため分けてみる

### propertiesファイル作成
以下のように作成する

デフォルト：application.properties

環境1：application-env1.properties
環境2：application-env2.properties

### 起動時パラメータ
定義パラメータ
> --spring.profiles.active=xxx

環境1だと
> --spring.profiles.active=env1

環境2だと
> --spring.profiles.active=env2


Eclipseだと以下のような形で定義
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2091355/ed269a87-d8f6-97e9-fc69-8a5347187407.png)

VSCodeだと以下のような形で定義
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2091355/0a5c8fac-9cc5-5a0c-4718-e9c2671ef5a0.png)
【小ネタ】Flutterで作られたアプリの見分け方

# はじめに
「リュウジのバズレシピアプリ」がFlutterで作られてるとツイートしたらそこそこ反応あったので見分け方を紹介しておきます。

https://twitter.com/K9i_apps/status/1687707039332732928?s=20

# 見分け方１
2本指でスクロールするとスクロール速度が2倍になるバグを利用します。
UIがFlutterぽいな？となったらスクロールする指の本数変えて速度が変わるかをチェックしている人が多いんじゃないかと思います。

https://github.com/flutter/flutter/issues/11884

## 【悲報】Flutter 3.19から無効に
このバグはFlutter 3.19で修正されました
あえて以前の挙動を維持するにはMultitouchDragStrategy.sumAllPointersを使えば良いとのこと（やる人いるの？😂）

https://docs.flutter.dev/release/breaking-changes/multi-touch-scrolling


# 見分け方２
FlutterSharkでチェックする。
FlutterSharkというアプリを使うと端末にインストールされているFlutterアプリの一覧、各アプリが利用しているパッケージが確認できます。

https://play.google.com/store/apps/details?id=com.fluttershark.fluttersharkapp

## Storeのスクショを拝借

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2542067/aa90b6bc-bd63-0611-fc86-2b8b6619d76b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2542067/aaee9abe-916f-99dd-5f47-9b7e91536f3a.png)

# 見分け方３
ライセンスページを確認する。（ホントはこれが正攻法な気がするけど、意外とライセンスページ実装されてない…）


# まとめ
自分がFlutterアプリを見分けるときに使っている方法の紹介でした。
FlutterSharkを使うと意外なFlutterアプリが見つかるかも？
【Python】関数名＆変数名のルール

# 関数名＆変数名のルールについて

### 関数名＆変数名のルールについてアウトプットしていきたいと思います!


①先頭はアルファベット「a～z」または「A～Z」または「＿（アンダースコア）」

②先頭に数字は使えない。例

```py:OK
test             # 頭文字小文字
test_answer      # アンダースコア
Test             # 頭文字大文字
test5            # 文字の後ろに数字
```

```py:NG
5test            # 頭文字に数字は使えない
```

③予約語も使えません(2023.8現在まで35個ある)
```py
False, None ,True ,and ,as ,assert ,async, await, break
class, continue, def, del, elif, else ,except ,finally
for, from, global, if, import, in, is, lambda, nonlocal
not, or, pass, raise, return, try, while, with, yield
```

ちなみにこれで検索できます。
```py:予約語検索の仕方
import keyword

arr = keyword.kwlist

arr.sort()

for a in arr:
	print(a)
```

これでもできます。

```py:予約語検索part2
import keyword

print(keyword.kwlist)
```



# 単語構成について


### ①スネークケース
2単語の間に「_（アンダースコア）」でつないだもの。
<font color="BlueViolet">pythonの変数名、関数名は`英小文字スネークケース`</font>、
<font color="MediumSlateBlue">定数名は`英大文字スネークケース`にします。</font>
```py:スネークケース
snake_case          # 変数名＆関数名は、小文字
SNAKE_CASE          # 定数名は、大文字
```

### ③パスカルケース
頭文字が大文字で始まる。
<font color="DarkOrange">Pythonでは`クラス名をパスカルケース`にします。</font>
```py:パスカルケース
PascalCase          #　クラス名、頭文字を大文字
```

## Pythonでは使わないケース
### ②キャメルケース（Pythonでは使わない）
頭文字が小文字で始まる
小文字で始まる言語を推奨しているものがある
<font color="DeepPink">`注意　※Pythonでは使わない`</font>
```py:キャメルケース
camelCase          # 最初の1文字目小文字、2単語目で大文字
```





### ④ケバブケース（Pythonでは使わない)
単語の間に「-（ハイフン）」を入れるもの。
<font color="DeepPink">`注意　※Pythonでは使わない。`</font>


```py:ケバブケース
kebab-case          # kebabcaseに「-（ハイフン）」 を入れる
```

-----
※なお、複数人でプロジェクト開発をする場合は、`コーディング規約`を確認してください。
【PHP】PDOのfetchでハマった話

## 使用バージョン
PHP 7.4

## 前提

| カラム名 | データの型 |
| :----| :----|
| id | int |
| type | int |
| name | varchar |

上記のようなテーブルがあります。
PDOでfetchしてきたものをJSに渡し、typeによって処理を分岐させていました。
分岐にはswitch文を使っていました。

### PHP
```
// ※だいたいこんな感じのコードというだけで、動作は検証してません。
$pdo = new PDO($connection['dsn'], $connection['username'], $connection['password']);
$sql = 'SELECT * FROM '. $connection['table'] .' ORDER BY id ASC';
$stmt = $pdo->prepare($sql);
$stmt->execute();
$records = $stmt->fetchAll();
$records_json = json_encode($records);
```

### JS
```
// ※だいたいこんな感じのコードというだけで、動作は検証してません。
var records = <?php echo $records; ?>;
// 何かしらの変換処理
type= records.type;
    switch (type) {
        case 1:
            hoge = 'hoge';
            break;
        case 2:
            hoge = 'fuga';
            …
```

## 起こったこと
switch文がすべて無視されました。
テーブルを参照するとtypeには1 や 2が確実に入っています。

## 原因
PDOでfetchしてきたものとテーブルの型が一致していないのが原因でした。
$recordsには例えば下記のようなデータが入っていました。
```
array(2) { ["id"]=> string(1) "1" ["type"]=> string(1) "2" ["name"]=> string(4) "hoge" } 
```
これをjsonに変換しても、typeはstringのままなので、JSのswitchの厳密な比較の処理ではすべてfalseになってしまします。

## 対応策
JS側でparseIntなどを使用して、typeを無理やりint型に変換しました。

## 注意
PHP8.2でfetchを試してみたところ、int型のカラムの値はint型で取得できました。
PHP8未満を使用する際は注意しなければならない様です。
忙しいエンジニアにおすすめ時短食事【ライフミール】

エンジニアも体が資本！在宅勤務が増えて食事をおろそかにしていませんか？
自宅で栄養がある食事が簡単に取れる！ライフミールがおすすめです！
https://nigekaji.com/lifemeal/
Rubyを使ってグループ分けをしてみる

# はじめに
今回はRubyを使って簡単なグループ分けをするプログラムを書いてみました

# 前提条件
A、B、C、D、E、Fという6人のグループがあります。
このグループは定期的にみんなで通話をしています。
しかし6人全員で通話はやりずらいので、3人ずつか2人と4人に別れることにしました。
このグループを3人と3人、または2人と4人にランダムに分けるプログラムを作成する。
このプログラムは実行するごとに結果が変わります。
また表示結果は以下のようにアルファベット順に出力する。
```sh
$ ruby random.rb
["B", "C"]
["A", "D", "E", "F"]
```

# コード

```ruby:random.rb
# 全員のリスト
members = ['A', 'B', 'C', 'D', 'E', 'F']

# ランダムにメンバーをシャッフル (元の配列はそのまま)
shuffled_members = members.shuffle

# グループの分け方をランダムに決める（2,4 or 4,2 or 3,3）
ratios = [[2, 4], [4, 2], [3, 3]]
ratio = ratios.sample
division_point = ratio[0]

# メンバーを取り出してグループに分ける
first_group = shuffled_members.slice(0, division_point)
second_group = shuffled_members.slice(division_point, ratio[1])

# アルファベット順に表示されるようにする
p first_group.sort
p second_group.sort
```

# Point
以下のコードで[sampleメソッド](https://docs.ruby-lang.org/ja/latest/class/Array.html#I_SAMPLE)を使って配列配列の要素を一個ランダムに取り出しています。

```ruby
ratio = ratios.sample
```


以下のコードで[sliceメソッド](https://docs.ruby-lang.org/ja/latest/class/Array.html#I_SLICE)を使って配列を切り分ける処理を実現しています。

```ruby
first_group = shuffled_members.slice(0, division_point)
second_group = shuffled_members.slice(division_point, ratio[1])
```


:::note info
**追記**
以下だともっと簡単に書けますね(Rubyらしい書き方..)

```ruby:random.rb
# %記法で文字列の配列を簡単に作成　=> ['A', 'B', 'C', 'D', 'E', 'F']と同じ
group = %w[A B C D E F]

group1 = group.sample([2,3,4].sample).sort
group2 = group - group1

p group1
p group2
```

## Point

以下の行では、sampleを用いてグループの人数比を決めています
```rb
group1 = group.sample([2,3,4].sample).sort
```

以下の行では、`group`配列から`group1`の要素を除いた結果を`group2`に格納しています。
[Array#-](https://docs.ruby-lang.org/ja/latest/class/Array.html#I_--2D)メソッドは、左側の配列から右側の配列の要素を除くことが出来ます

```rb
group2 = group - group1
```
:::
【JasperReports】Jaspersoft Studioのインストール

# 概要

JasperReportsは、帳票を作成するためのライブラリです。これを使って帳票を作成する手順を説明します。今回は事前準備作業となる、Jaspersoft Studioの入手方法を説明します。

# 前提

- Jaspersoft Studio : v6.20.5
- JasperReports : v6.20

# Jaspersoft Studioを入手

帳票のレイアウトを設計するIDE、Jaspersoft Studioを入手します。コミュニティ版は無償で利用できます。ただし、アカウント登録が必要になります。

まず、以下のURLにアクセスして、右上のDownload Nowボタンをクリックします。
https://community.jaspersoft.com/

ここで、右側のCOMMUNITY EDITIONの方のDOWNLOAD NOWをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/278c1130-820e-83ad-fdad-1d578f0a2baf.png)

そして、以下の画面になったら、Jaqspersoft Studio CEのDownloadをクリックします。
Inportant Informationのダイアログが表示されるので、Continue to Downloadをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/1a8aefee-9e9b-61e9-a3d9-37b54056fa68.png)

以下のようなJaspersoft Studioのダウンロード用画面が表示されるため、Windowsの場合はexeファイルのリンクをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/df1a0b5a-3185-f95e-4dff-c878eade8945.png)

既にアカウントを持っている場合は、そのアカウント情報を入力してログインします。
まだアカウントを持っていない場合は、名・姓、国、メールアドレスを入力します。

登録する必要がある情報として、パスワード、会社名、会社の従業員数、役職、プロモーションメールの要否、電話によるプロモーションの要否になります。個人で利用する場合は、会社名・従業員数は任意の値を入力しても問題なくダウンロードできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/b8433bf4-762a-d168-1d7d-74b437b20eba.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/5d1b7d2e-cbd9-4fc7-0e2d-afdac5be5fbd.png)

アカウントを登録すると、指定したメールアドレスに確認用メールが届きます。そこに記載されているURLにアクセスすることで、アカウント登録が完了します。
Jaspersoft Studioのインストーラをダウンロードしたら、それを実行してインストールします。

Jaspersoft Studioを起動すると、以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/1bedc3e6-58af-8587-f76c-876cf2940635.png)

# まとめ

次回は、Jaspersoft Studioを使って、請求書サンプルを設計します。
React Hooksについて①

## React Hooks:label:
・useState
・useEffect
・useContext
・useReducer
・useCallback
・useMemo
・useRef
・useLayoutEffect
・useDebugValue

## フックって何？
Reactの機能に接続するためのReact専用の関数らしい

## 今回説明するフック
### useState
画面に表示されるデータやUIの状態を管理する。

```
// useStateを使用するときのインポート文
import React, { useState } from 'react';

function CounterApp() {
    // countという変数を定義
    // setCountの箇所はstateの更新関数
    // useState(0)の箇所で初期値を0に設定している
    const [count, setCount] = useState(0);

    // カウンターを１増やす関数
    const increment = () => {
        setCount(count + 1);
    };
    // カウンターを１減らす関数
    const decrement = () => {
        setCount(count - 1);
    };

    return (
        <>
            <div>
                // カウンターの数字をpタグで表示する
                <p>Count: {count}</p>
                // カウンターを１減らすボタンにdecrement関数を設置している
                <button onClick={decrement}>-</button>
                // カウンターを１増やすボタンにincrement関数を設置している
                <button onClick={increment}>+</button>
            </div>
        </>
    );
    }

export default CounterApp;


```
### useStateのイメージ
```
  [useState]
    └─ Initial Value
    │
    └─ State Variable (count)
    │
    └─ State Updater Function (setCount)
    │
    └─ Component Render

```

１．Initial Value (初期値): useState フックに渡す初期値。ここでは 0 が初期値として設定されています。

２．State Variable (ステート変数): useState フックが返すステート変数。ここでは count がステート変数として使われています。この変数は現在の状態を保持します。

３．State Updater Function (ステート更新関数): ステート変数を更新するための関数。ここでは setCount がステート更新関数として使用されています。この関数を呼ぶことでステート変数を更新し、コンポーネントの再レンダリングをトリガします。

４．Component Render (コンポーネントのレンダリング): コンポーネントの描画部分。count ステート変数の値を表示し、ボタンのクリックによって setCount 関数が呼ばれてステートが更新されると、この部分が再度レンダリングされます。

### この記事の最後に
useStateは、初期値とそれを更新するための関数を提供し、コンポーネントがその状態を保持・更新し、必要に応じて再描画をトリガできるようにします。簡潔に言えば、useState はReactコンポーネント内で可変なデータを管理するための便利なツールだと思います。
次回は、useEffectについて記事を書いてみたいと思います。
Salesforce SORP API (WSDLベースのAPI)でのJava開発環境作成

## はじめに
Salesforceとのデータのやり取りは、REST APIで実装していたが
Sorp API(WSDLベースのAPI)を使用しての実装も追加すべく、設定方法をメモ

## 参考
基本的には、以下ガイドに沿った形で環境作成

Java 開発者環境の設定
https://developer.salesforce.com/docs/atlas.ja-jp.salesforce_developer_environment_tipsheet.meta/salesforce_developer_environment_tipsheet/salesforce_developer_environment_overview.htm

## 開発環境
Spring　Boot 2.5.0
Java　 Openjdk 11

## 環境作成

#### 組織の WSDL ファイルの生成
Salesforceにログインし
1. 「設定」- 検索で'API'
1. APIを選択
1. 「Enterprise WSDL」の「Enterprise WSDL の生成」を選択　※今回はこれを使用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2091355/7f273e4b-e4d2-c23e-6e2a-9fb90db50b0d.png)
1. 「Generate」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2091355/1bcc44f3-0422-6af6-3bbe-59234f7cc806.png)
1. 以下のような形でxmlファイルが作成される為、名前を付けて保存する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2091355/ce0d3043-a6b5-b08e-869e-a2885a63b001.png)

今回は「enterprise.wsdl」として保管

#### 組み込みの WSC .jar ファイル作成
以下から対象APIバージョンのものを取得できるが今回はgitのソースから作成する
https://mvnrepository.com/artifact/com.force.api/force-wsc

gitソースは以下
https://github.com/forcedotcom/wsc 

基本的には、Gitに記載している通りに実施すればよいが
> git clone https://github.com/forcedotcom/wsc.git
cd wsc
mvn clean package -Dgpg.skip

自分の環境では以下でないとエラーになった
>mvn clean package -D gpg.skip

ターゲット以下にjarファイルが作成されるので
組織のWSDLファイルと作成したjarファイルを使用しJavaスタブファイルの生成する

>java -jar target/force-wsc-xx.x.x-uber.jar enterprise.wsdl wsc.jar

enterprise.wsdl ･･･Currentを意識してパス指定
wsc.jar　･･･作成ファイル

注意：コンパイルする際のJavaバージョンに注意
上記javaは開発環境のバージョンとそろえておいたほうが無難
React 18でのサーバーコンポーネント入門！クライアントとサーバーの最適なバランスを実現




React 18の新機能であるサーバーコンポーネントを使って、パフォーマンスの最適化やSEOの改善を図りたいですか？この記事ではサーバーコンポーネントの基本から、具体的な使い方に至るまでを解説します。

## 目次

1. [サーバーコンポーネントとは何か？](#サーバーコンポーネントとは何か？)
2. [いつ使うのか？](#いつ使うのか？)
3. [メリット](#メリット)
4. [環境設定](#環境設定)
5. [サンプルコード](#サンプルコード)
6. [注意点とトラブルシューティング](#注意点とトラブルシューティング)

## サーバーコンポーネントとは何か？

サーバーコンポーネントはReactの特定のコンポーネントをサーバー側でレンダリングするための新しい機能です。クライアントとサーバーの間で最適なバランスを取りながら、レスポンシブなインタラクションを提供します。

## いつ使うのか？

- リソースが重いコンポーネントの処理
- SEOの改善
- ユーザーエクスペリエンスの向上

## メリット

- パフォーマンス向上
- 柔軟性
- コード分割

## 環境設定

### 1. 環境のセットアップ

```bash
npm init
npm install react@alpha react-dom@alpha react-server@alpha
```

### 2. レンダリングパイプラインの設定

以下のコードはExpressを使用してサーバーコンポーネントをレンダリングする例です。

```javascript
const express = require('express');
const { pipeToNodeWritable } = require('react-server-dom-webpack/writer');
const React = require('react');
const { renderToPipeableStream } = require('react-dom/server');

// ...

app.get('/', (req, res) => {
  const stream = renderToPipeableStream(<App />);
  res.setHeader('Content-Type', 'text/html');
  pipeToNodeWritable(stream, res);
});
```

## サンプルコード

サーバーコンポーネントの例:

```jsx
// MyComponent.server.js
import React from 'react';

function MyServerComponent() {
  return <div>これはサーバーコンポーネントです。</div>;
}

export default MyServerComponent;
```

## 注意点とトラブルシューティング

- サーバーコンポーネントはクライアントサイドの状態やイベントハンドラーに直接アクセスできません。
- 開発環境やフレームワークによってはサポートが限定的な場合があります。

---

この記事を通じて、Reactのサーバーコンポーネントを初めて試す方でも安心して取り組めるようになることを願っています。いいねやコメントは大歓迎です！何か質問があればお気軽にどうぞ！
SpringBoot Gradleでの静的jarファイルの読み込み

## はじめに
SpringBoot+Gradle環境で開発を行っていたが、個別の特定jarファイル環境に組み込む必要があり実装した結果のメモ

## 環境
Java　 Openjdk 11
Spring Boot 2.5.0
Gradle　3.x

## 手順

以下のように記載

build.gradle
>dependencies {
     implementation(fileTree(dir: 'libs', include: ['wsc-enterprise.jar']))
}

jarファイルの格納場所は以下の場合
　project - lib - wsc-enterprise.jar
Git 2種類のマージについて(Fast-ForwardとNon Fast-Forward)

## マージには2種類ある
- Fast-Forward
- Non Fast-Forward

### Fast-Forward
##### ブランチのポインタの移動だけを行い、新しいコミットは作成しない。
コミットが画像１の状態のとき、mainブランチはコミットDに移動するだけでsub1ブランチの内容を取り込むことができる。
mainブランチのコミット：A
sub1ブランチのコミット：ABCD
移動後のmainブランチ　：ABCD
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511376/a807be26-7767-7e18-f1f6-e6b9138e7928.png)


もし画像2の状態でFast-Forwardを行うと、commitEが消えてしまう。
mainブランチのコミット：AE
sub1ブランチのコミット：ABCD
移動後のmainブランチ　：ABCD
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511376/029bee24-e0b4-25cd-1f92-86e8c6a49590.png)
この場合に登場するのが、Non Fast-Forwardである。


### Non Fast-Forward
##### マージしたことを示す新しいコミットを作成する
新しくcommitFを作成することで、mainとsub1の両ブランチのすべてのコミットを取り込むことができる。
mainブランチのコミット：AE
sub1ブランチのコミット：ABCD
新しいコミットF  　 　　：AEBCDF
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511376/fee30706-3665-f7fe-160e-7a8e5a51fe76.png)


おしまい。
イベントと関数の関係性について野球部に解説してみる

おはようございます！
昨日に引き続いてイベントについての記事です！

https://qiita.com/yangyooji1946/items/16201ea673e46385ed80

今日は「関数」と「イベントハンドラ」について、野球部の練習を例にして解説します。


結論から言うと、
関数とは、プログラムの流れに沿って実行される処理のこと。
イベントハンドラは、特定のイベントが発生したときに実行される関数の一種です。

この二つの関係性を理解することで、プログラミングの基本的な動作の理解が進むことを目指します。
興味を持っていただけたら、ぜひ最後までお読みください！

## 野球的に考えると、、？
>関数とは、プログラムの流れに沿って実行される処理のこと。
イベントハンドラは、特定のイベントが発生したときに実行される関数の一種です。

について、野球的な解釈をしていきたいと思います！
今日は野球部の練習の風景を思い浮かべてください！

まず、通常の関数の処理ですが、「プログラムの流れに沿って実行される」とあります。これは野球部の練習メニューの予定のようなものだと考えることができます。
例えば、「ウォーミングアップ→キャッチボール→ノック→昼食→バッティング」という練習メニューの流れがあったとします。
これをコードにするとこんな感じです。
```
// 練習メニューを定義
function menu() {
　　　　ウォーミングアップ
　　　　キャッチボール
　　　　ノック
　　　　昼食
　　　　バッティング
};

// 練習メニューを実行
menu();
```
このように、もともと予定していた練習メニューをその通りこなしていくことが、「プログラムの流れに沿って実行される」という通常の関数の処理です。

では、イベントハンドラの「特定のイベントが発生したときに実行される関数の一種」とはどういうことでしょうか？
練習メニューの喩えでいうと、「急にノック好きのOBが来て、そこからノックが3時間続いた」というような状況のことを指します。
昼食を食べて、「よし！午後からは楽しいバッティングだ！」と思っていたら、ネガティブなあだ名のついている有名なOBが突然やってきて、午後からもノックが始まり、しかも終わらない。みたいな体験は皆さん1度や2度ではないはずです。

脱線しましたが、コードにするとこんな感じです。
```
// 練習をしている野球場の要素を取得
const ground = いま練習をしている野球場

//　OBが来たら実行するというイベントハンドラを設定
ground.OB = function () {
  ノックが3時間続く、、
}
```
通常の関数が処理中であっても、イベントハンドラが実行されればそのタイミングでイベントハンドラの処理が実行されます。
つまり、バッティングの準備をしているときに突然OBが現れて、練習メニューがノックに変更されてしまうというのは、イベントハンドラのOBが実行されたからだったのです。

このようにコードの流れによって実行されるのではなく、コードの外部からの操作によって実行される関数が「イベントハンドラ」と名付けられています。

## 実際のコードを見てみる

3.実際のコード解説パート
野球の喩えパートで見たように、通常の関数とイベントハンドラの違いを理解するために、具体的なコードを見てみましょう。

### 通常の関数
まず、通常の関数の例です。この関数は、背景色を赤に変更し、その後青、緑、黄色、黒に変更するという処理を行います。これは、野球部の練習メニューの予定のようなもので、予め決められた流れに沿って処理が進みます。

```
function btnColorChange() {
  document.body.style.backgroundColor = 'red'; // 背景色を赤にする
  document.body.style.backgroundColor = 'blue'; // 背景色を青にする
  document.body.style.backgroundColor = 'green'; // 背景色を緑にする
  document.body.style.backgroundColor = 'yellow'; // 背景色を黄色にする
  document.body.style.backgroundColor = 'black'; // 背景色を黒にする
}

btnColorChange(); // 関数を呼び出す
````
このコードは、プログラムが読み込まれた時に、背景色を順番に変更する処理を実行します。このように、通常の関数はプログラムの流れに沿って実行される処理です。

### イベントハンドラ関数
次に、イベントハンドラの例です。この関数は、ユーザーがボタンをクリックしたときに背景色をランダムに変更するという処理を行います。
```
const btn = document.querySelector("button");

btn.onclick = function () {
  const rndCol = `#${(Math.random() * 0x1000000 | 0).toString(16).padStart(6, '0')}`;
  document.body.style.backgroundColor = rndCol;
};
```
このコードは、ユーザーがボタンをクリックすると、背景色をランダムに変更するという処理を実行します。このように、イベントハンドラは特定のイベントが発生したときに実行される関数の一種です。急にOBが来てしまったというのもこのイベントハンドラに当たるでしょう。

## まとめ
今回の記事では、プログラミングの概念と野球の練習を組み合わせて、通常の関数とイベントハンドラの違いを解説しました。ここで、要点を2つのポイントでおさらいしましょう。

1.通常の関数はプログラムの流れに沿って実行される処理で、予め決められた流れに沿って処理が進むもの。
2.イベントハンドラは、特定のイベントが発生したときに実行される関数の一種で、ユーザーの操作など外部からの操作によって発火する。

最後に、このブログが皆さんの学習に役立ったことを願っています。
もし役立つと感じたら、ぜひ「いいね」や「フォロー」をお願いします！

それでは今日も学習をスタートします！
【メモ】 /dev/uinputをユーザ権限で読み書き可能にする (udev)

システムをアップデートしたらなぜか`/dev/uinput`の権限が不足してxkeysnailが動かなくなったので対策を調べました。<strike>原因がよくわからないので対処療法ですが。。</strike>

**[2023/12/21追記]** これはsystemd 254.1のバグだった模様（[参考](https://github.com/ReimuNotMoe/ydotool/issues/210)）。現在の255.1-1-archでは下記の変な挙動は起きませんので、安心して`660`を指定ください（なお、「対処」の設定でも問題は起きないのでどっちでも良い）。

### 環境
- Arch linux (6.4.7-arch1-3)
- Systemd 254 (254-1-arch)

### 現象
`udev`のルールで指定した`/dev/uinput`のパーミッションが指定通りにならない[^1] [^2]。660の二桁目はどこへ・・・？
```text:uinput.rules (old):
SUBSYSTEM=="misc", KERNEL=="uinput", MODE="660", GROUP="input"
```

```text:$ ls -l /dev/uinput
crw------- 1 root input 10, 223  8月  6 11:55 /dev/uinput
```

### 対処
`uinput.rules`を以下のように変更する。
```uinput.rules (new):
SUBSYSTEM=="misc", KERNEL=="uinput", TAG+="uaccess"
```

これにより`/dev/uinput`に`uaccess`タグが設定され、一般ユーザからの読み書きが可能になります（下記、動作の参考になりました）。

https://mrwk.hateblo.jp/entry/logind

以下のように、ACLでユーザ`clarry`からの読み書き権限が付与されていますね。

```text:$ ls -l /dev/uinput
crw-rw----+ 1 root root 10, 223  8月  6 12:08 /dev/uinput
```

```text:$ getfacl /dev/uinput
getfacl: Removing leading '/' from absolute path names
# file: dev/uinput
# owner: root
# group: root
user::rw-
user:clarry:rw-
group::---
mask::rw-
other::---
```

…特定のパーミッションを指定できるようになったわけではないのでちょっと気持ち悪いですね。またハマったら追記します。

[^1]: なお、`/etc/modules-load.d/uinput.conf`に`uinput`は記入してあります: [github.com](https://github.com/chrippa/ds4drv/issues/93#issuecomment-265300511)。
[^2]: ブートログを見る限り`uinput`モジュールの読み込み→`udev`の起動→ルールの適用の順になるが、これを`udev`起動→`modprobe uinput`の順にすると、何故か想定通り設定される？？
【ChatGPT無】に節約術について聞いた（ChatGPTについても書きました）

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　どうも、カーブミラーです。

　まずは、
　　Microsoft Bing Chatの
　　　三つのモードが、
　　　　また、GPT4切替スイッチに
　　　　　変わっていますね。

　興味のある方は、
　　下記を参照してください。

[【Microsoft Bing Chat】のあの三つのモードが消えた！？](https://qiita.com/kabumira/items/fbd32792734b621e2d8c)

[【Microsoft Bing Chat】戻った&新機能発見](https://qiita.com/kabumira/items/8f11ace9aed8f834b38c)
***
　さて、
　　今回は、節約術について、
　　　尋ねてみました。

　まずは、
　　そのやり取りをどうぞ。
```Text:節約術
User
節約術を知っていますか？
知っていましたら、箇条書き（説明不要）でお願いします。


ChatGPT
もちろん、節約術をいくつかお伝えしますね。

- 毎月の予算を立てる
- 不要な出費を削減する
- 定期的な節約チェックを行う
- クーポンや割引を活用する
- 食費を節約する
- 省エネ家電を使う
- 自炊をする
- 2ndハンド品を購入する
- 車の燃費を意識する
- 余分なサービスを解約する

これらの節約術を実践することで、お金を効果的に節約できます。



User
これらを行なう場合、出資がかさむことが考えられます。


ChatGPT
確かに、節約術を実践する際には初期の出費がかさむ場合がありますが、長期的に見ると節約によるメリットが大きくなることがあります。以下の点に留意することで、無理なく出費を抑えながら節約を進めることができます。

- 節約にかかる初期の出費を予算に組み込む
- 節約に関する情報をリサーチし、効果的な方法を見つける
- 小さな変化から始めて、徐々に改善していく
- 節約を趣味化して楽しむ
- 無駄な支出を見つけることで、無駄な出費を削減する

これらのアプローチを取ることで、無理なく節約を進めることができます。また、節約の成果が現れた際には、達成感や経済的な安心感を得ることができるでしょう。



User
もっと現実的な節約術をお願いします。箇条書き（説明不要）でお願いします。


もちろん、現実的な節約術を箇条書きでお伝えします。

- 毎月の予算を立てる
- 不要な出費を削減する
- クーポンや割引を活用する
- 食費を節約する
- 自炊をする
- 2ndハンド品を購入する
- 省エネ家電を使う
- 公共交通機関を利用する
- 定期的な節約チェックを行う
- 余分なサービスを解約する
- 無料の娯楽を楽しむ
- 家族や友人とシェアする
- エネルギー使用を減らす
- バーゲンセールを利用する
- オンラインで価格を比較する
- キャッシュバックやリワードプログラムを利用する
- 不要な会費を見直す
- 長期契約より短期契約を選ぶ
- プライスマッチを利用する
- 月額固定費を見直す

これらの節約術を実践することで、日常生活の中で無駄な出費を減らし、効果的にお金を節約することができます。



User
もっと具体的な節約術をお願いします。
箇条書き（説明不要）でお願いします。


ChatGPT
もちろん、具体的な節約術を箇条書きでお伝えします。

- 食材の値引き品を購入する
- 家計簿をつけて支出を把握する
- 電気製品を使わない時はコンセントを抜く
- 不要な定期購入を見直す
- 空き時間にアンケートサイトでポイントを稼ぐ
- 水道やガスの節約を心掛ける
- 自宅で過ごすことで外食費を削減する
- 中古品ショップで洋服を購入する
- 光熱費を見直して削減する
- レシートキャッシュバックアプリを利用する
- 定期的に財布の中身を整理する
- バーゲンセールやセール品を利用する
- 不要な物を売って収入を得る
- 睡眠不足を防ぐことで外食を減らす
- インターネットやケーブルテレビのプランを見直す
- 旅行やレジャーの割引チケットを探す
- 家族で共有するサブスクリプションを活用する
- 電気代のピークタイムを避ける
- デジタルコンテンツを利用する際にポイントサイトを経由する
- プレゼントや贈り物は自作する

これらの具体的な節約術を実践することで、さまざまな場面でお金を節約することができます。自分の生活スタイルに合った方法を選んで、賢くお金を使いましょう。



User
スケジュールとか流れとかをお願いします。
箇条書き（説明不要）でお願いします。


ChatGPT
分かりました。節約のスケジュールと流れを箇条書きでお伝えします。

1. バジェット作成
2. 不要な出費の洗い出し
3. 節約アイデアのリサーチ
4. 節約プランの策定
5. 節約を開始する
6. 定期的な節約チェックと見直し
7. 節約の成果を振り返る
8. 節約のメリットを享受する
9. 節約成功を継続する

これらのスケジュールや流れに従って、節約を計画的に実践することで、効果的な節約が可能です。毎日の生活に取り入れて、無駄な出費を減らし、より経済的に過ごしましょう。
```
***
　平凡ですw

　これでも
　　一時期、金欠で節約術を
　　　考えていましたから
　　　　ChatGPTさんの
　　　　　程度がわかります。

　ここから考えると、
　　やはり、ChatGPTさんは
　　　平均的なことしか出せない。

　ChatGPTさんに
　　画一的なアイディアを求めても
　　　定形的なことしか出せない。

　これは
　　例えGPT4だとしても
　　　同じでしょうね。

　ただし、
　　さまざまな知識を
　　　持っているのは、確かです。

　そこから、
　　得られるものは、
　　　多いでしょうね。
【すべての本好きへ！】ハイライトから新しい本に出会えるサービスHighlightPicker

ネットで本を探すとき、あたなはどうしてますか？

Amazonから色んな本の表紙をみて、概要を読んで、レビューをみて、購入を決める。
こんなステップを踏んでいると思います。

この方法を変えてみよう！というのがこの記事の主旨です。

これからの時代、「ハイライト」から、新たな本を見つけませんか？
![「ハイライトで見つける」機能紹介.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311150/a1c91606-4044-17d1-38f4-ffe2472b4649.gif)


それを実現してくれるサービスがHighlightPickerです。

https://kindle-auto-mailer.com/top


## 「本のオススメ文」がスライドショーで流れてくる！？
このツールには、**「ハイライトから本を見つける」** 機能が備わっています。

みんなが電子書籍で本を読んでいる中で、重要だと思ってマークした文章。
これらが、スライドショー形式で次々に流れてきます！

それをみて、「お！」と思える本を見つけられる。これが、新しいネット上での本の出会い方です！！

なお、本の表紙絵をクリックするとAmazonに飛ぶので、本の詳細を見たり、レビューを見て購入することもラクラクおこなえます。


## ネットで「リアルな本屋」に近い体験を！
「リアルな書店に行くメリットはなにか？」
よく、こういった疑問を目にしますが、答えは「偶然、自分に合う本に出会えること」です。

Amazonだと、探したい本が明確なときはすごく便利なんですが、逆にいうと目的の本以外は目につかない。
いわゆる、便利だからこその「偶然性」がなくなってしまっているんですね、、。

![ebook_reader.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311150/6ba36897-f860-5e43-d820-8a3bc7e67ee3.png)

その一方で、リアルな本屋はこの逆。
ふら～と本屋を5分も歩いていれば、「お！？」と思える本にまず出会えたりしますが、「目的の本がどこにある？」って探すと、すんなりと見つけられない。

![tatemono_honya.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311150/0f6cb166-8ea0-dbf1-8ba0-6e0bf2874e42.png)


こういう状況のなかで、
・買いたい本が決まってるならネットで。
・特に決まってないなら本屋で。
というすみ分けがされていました。

しかし！「ハイライトから本を見つける」機能を使えば、**ネット上でも「偶然の本の出会い」を実現**することができます。

## 使い方
ログイン後、機能一覧の「見つける」をクリックで、スライドショー画面にアクセスできます！

![「見つける機能」へのアクセス方法.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311150/c9838fa0-ce02-a527-bcfb-c288036049c6.gif)

なお、アクセスするたびに、スライドショーはランダムで表示されます。

## 技術的な説明
- Kindleハイライトデータを連携時、値を体系的にデータベースに登録することで、一覧表示やスライドショー表示を実現しています。
- 本の画像はimgデータをDBに保存するのではなく、imgのURLを保存しています。画面を開くたびにその画像をAmazonから呼び出す形式にしています。
- なお、その画像のURLはAmazonAPIを利用しています。ハイライト連携時に、タイトル情報からAmazonAPIを呼び出し本の画像URLを取得。そのURLをDBに保存する形式です。
- そのため、「既にAmazonで販売が終了している本」は、APIから画像の取得が失敗することが稀にあります。この点が欠点ですが、現状は良い解決策が分かっておりません。（どなたか詳しい方、教えていただけると嬉しいです！）

## 最後に
すべての本好きの人よ！
ぜひ、一度、試してみてください！！

https://kindle-auto-mailer.com/top

※Webアプリのため、スマホ・タブレット・PC問わず利用することができます。
Rustの関数をRubyやCrystalから呼び出す：方法と課題 - 1日目

## はじめに

最近では、新しいライブラリがRustで書かれるようになってきました。これに伴い、RubyやCrystalなどの好みの言語からRustの関数を呼び出したくなることが増えます。

Python言語に対しては、バインディングが最初から提供されることも多いのですが、それ以外の言語からRustの関数を呼び出したい場合、自身で作成する必要があります。

この記事は、Rustに全く触れたことがない人間が、数時間調査した内容をまとめたものです。
しかし、QiitaでMagnusをググっても記事がほとんどヒットしないことからわかるようにそれほど日本語の情報が多くない分野なので、調べ物の取っ掛かりとしては価値があると思います。

## 目標

Rustで作成したライブラリの構造体と関数をみて、RubyやCrystalからFFIで呼び出せるようになること

## Rustで共有ライブラリを作成する方法

Rustは共有ライブラリを書き出すことができます。

Tomlファイルに [lib] crate-type = ["dylib"] を設定します。

```toml
[lib]
name = "myrustlib"
crate-type = ["dylib"]
```

呼び出したい関数に #[no_mangle] という属性を追加し、関数でも pub extern "C" を指定します。

```rust
#[no_mangle]
pub extern "C" fn string() -> *const u8 {
  "Hello World\0".as_bytes().as_ptr()
}
```

構造体は、#[repl(c)]という属性を追加します。

```rust
#[repr(C)]
struct Foo {
    n: u32
}
```

C言語と互換性のある関数・構造体しか書き出せないことに注意してください。つまり、C言語と互換性のある関数や構造体を自分で追加してC言語のAPIを自分で作成する必要があります。

これでは不便なので、後述のMagnusのように自動で、Rustの(struct + trait)をRubyのクラスに変換する仕組みがあります。

## RubyにおけるRustのエコシステム

これまで多数のライブラリが作成されてきましたが、現状では [rb-sys](https://github.com/oxidize-rb/rb-sys) と、rb-sys 上に構築された [Magnus](https://github.com/matsadler/magnus) が有力です。Bundlerのgemテンプレートでも Magnus が使用されているため、今後も継続的なメンテナンスが期待できるでしょう。

```
bundle gem --ext=rust hoge
```

- rb-sys は低レイヤーを担当し、RubyのC APIを呼び出したり、Gem内でRustのコードをコンパイルするサポートをしています。今回のメインテーマではありませんが、RustからRubyのC APIを呼び出すことで、RubyのRust拡張を作ることができます。
- Magnusは rb-sys よりも上位のレイヤーを担当し、RustとRubyの型変換を担当します。特に、Rustのクラスに相当する部分（struct + trait）をRubyのクラスに自動的に変換する機能があります。以下の記事では、Magnusの使い方を簡単に紹介されています。

https://dawn.hateblo.jp/entry/2022/06/12/152159

Magnusを利用して作成された実用的で大規模なRubyのGemの一例として、[polars-ruby](https://github.com/ankane/polars-ruby)があります。これはRustで実装されたデータフレームのPolarsをRubyから利用できるようにするもので、現状ではRubyから利用できる最速のデータフレームです。このようなしっかりとした利用事例があるのもポイントです。

## CrystalにおけるRustのエコシステム

- Rustの関数をCrystalから呼び出したい需要は非常に強いですが、ディレクトリ構造、コンパイル方法、型変換のどの部分においてもデフォルトのものは存在しません。このため、自分でディレクトリ構造を考え、Makefileを作成し、型変換のコードを追加する必要があります。
- 他の言語からCrystalを呼ぶことは推奨されていません。その理由は以下のとおりです。
  - Crystalは静的な言語ですが、ダックタイピングが可能で、その結果、ライブラリを含む全てのコードを常にコンパイルし、必要な型を割り出します。しかし、コンパイル毎に型と型ID（数値）の対応が変わるため、共有ライブラリとしてコードを再利用する場合、動作の保証がないと公式に明言されています。そのため、RubyやRustなど、他の言語からCrystalを呼び出す試みはあまり行われていません。
  - 今のところ実行ファイルの中で「単一のCrystalの共有ライブラリとしかリンクしてない」という条件下においては、Crystalで書かれた共有ライブラリを使っても問題なく実行できると言われています。これは、型の不整合が起きる可能性がないからです。

## 感想・ポエムなど

Rustで書かれるライブラリは今後も増えると予想されます。したがって、Rubyユーザーとしては、Rustの関数を安全に呼び出す方法を確保したいと思います。

一方で、RustのライブラリはいつでもC言語との互換性があるわけではありません。

- 構造体は、Option型などを使用している場合、Cの構造体との変換が必要です
- 関数も、引数や戻り値にプリミティブな型以外を使用している時は、Cの関数でラップする必要があります

そのため、Rustのライブラリ関数を共有ライブラリに書き出していくには、それらをラップするAPIを整備する必要がありますが、これは手間がかかります。たとえ、C言語のAPIは自分で作成せずにMagnusなどの自動変換に頼る場合でも、Magnusのルールに則ったラッパーを自作する必要があるでしょう。

PythonやRubyなどの主要なオブジェクト指向言語では、Rustの(struct + trait)に属性を追加することで、それをPythonやRubyのクラスに自動変換するような方法が採用されています。

しかし、この方法は言語間での互換性がなく、RustのPythonバインディングがPyO3で提供されていても、それがRubyから呼び出せるとは限りません。これは、RubyやCrystalから見た場合、囲い込みのような状況に見えます。

しかし、RustでOSSのライブラリを公開してくださっている作者にC APIを提供するように求めることは現実的ではないし、道義的にも「どうかなぁ」と思われます。（もちろん本人がよろこんで提供している場合は別です）

そこで、Rustの(struct + trait)から、将来的にはCのAPIより少々高度な、さまざまな言語で共通に利用Attributeのようなものが求められるかも知れないなと思ったりしました。

この記事は以上です。
Intel Mac と M2 Mac を比較する

## はじめに

先日 M2 Mac が手元に届いたので、今まで使っていた Intel Mac とパフォーマンスを比較してみます

2019 モデルと 2022 モデルであり、メモリも違うので単純比較はできませんが、、、

あくまでも私のメモ用ということで

どの程度の差が出るのか Livebook で検証してみます

## 実行する処理

Nx の様々なバックエンドによる行列の加算処理を計測の対象とします

`Benchee.run` によって、IPS（Instructions Per Second 1秒間に何回処理を実行できたか）を計測します

```elixir
bench = fn backend ->
  tensor =
    {200, 200}
    |> Nx.iota(type: :f64, backend: backend)

  Nx.add(tensor, tensor)
end
```

```elixir
Benchee.run(%{
  "binary" => fn -> bench.(Nx.BinaryBackend) end,
  "exla" => fn -> bench.(EXLA.Backend) end,
  "torchx" => fn -> bench.(Torchx.Backend) end,
  "evision" => fn -> bench.(Evision.Backend) end
})
```

詳細な内容は以下の記事を参照してください

https://qiita.com/RyoWakabayashi/items/45edc8ddbccba139a5ba

`Nx.BinaryBackend` を使っている場合は単純に Elixir で 40,000 回足し算を行っています

`Evision.Backend` なら OpenCV 、 `EXLA.Backend` なら XLA を使った行列演算を実行しています

## Intel Mac

実行環境は以下の通りです

- MacBook Pro 13 inch, 2019
  - macOS Ventura 13.5
  - CPU 2.4 GHz クアッドコアIntel Core i5
    （物理的には 4 コア、 Hyperthreading による擬似 8 コア）
  - メモリ 16 GB
- Elixir 1.15.4
- Erlang 26.0.2
- Livebook 0.10.0

Elixir と Erlang は asdf でインストールし、 Livebook は GitHub からタグ指定でクローンしてきたコードをローカルビルドしています

実行結果は以下のようになりました

| バックエンド |  IPS    |
|:-----------|--------:|
| binary     |      79 |
| evision    |   2,560 |
| exla       |   8,090 |
| torchx     |   5,880 |

## M2 Mac

実行環境は以下の通りです

- MacBook Pro 13 inch, 2022
  - macOS Ventura 13.5
  - CPU Apple M2
    8 コア（パフォーマンス: 4、効率性: 4）
  - メモリ 24 GB
- Elixir 1.15.4
- Erlang 26.0.2
- Livebook 0.10.0

Elixir と Erlang は asdf でインストールし、 Livebook は GitHub からタグ指定でクローンしてきたコードをローカルビルドしています

実行結果は以下のようになりました

| バックエンド |  IPS    |
|:-----------|--------:|
| binary     |     152 |
| evision    |   5,910 |
| exla       |  12,490 |
| torchx     |   8,800 |

## 比較

Intel Mac と M2 Mac の比較表は以下のようになります

| バックエンド | Intel Mac IPS | M2 Mac IPS | M2 / Intel |
|:-----------|--------------:|-----------:|-----------:|
| binary 　  |            79 |        152 |       1.92 |
| evision  　|         2,560 |      5,910 |       2.31 |
| exla     　|         8,090 |     12,490 |       1.54 |
| torchx   　|         5,880 |      8,800 |       1.50 |

BinaryBackend 、つまり単純な足し算のループでは 2 倍近い差がありました

そして、 evision = OpenCV は 2 倍を超える結果に

## まとめ

単純な計算によるものではありますが、明らかに M2 Mac で高速化していますね
GitのHEADについて少し理解が深まったのでメモ

## GitのHEADについて
今までHEAD？なにそれ？状態だったが、色々調べているうちに少し理解できたのでメモ。

## 要するに現在地を指している
Gitは変更履歴を記録していくためにコミットを積み上げていく。
開発者は基本的に、それぞれのブランチの最新のコミットに対して作業をすることになると思う。

その、作業をしている場所を指すのがHEADとなる。
ブランチを移動するというのは、HEADを移動させること、と言っても良いかもしれない。

おしまい。
転職ドラフトエージェントで転職した話

# はじめに
:::note info
こちらの記事は転職ドラフトエージェント体験談投稿キャンペーンに参加しています。
:::
転職ドラフトと転職ドラフトエージェントで転職活動した体験を書きます。
ちなみに、転職ドラフトエージェントで転職成功後に、体験談を投稿するとAmazonギフト券一万円分がもらえます。
# 転職ドラフトエージェントに登録したきっかけ
前の職場で大きなプロジェクトが一段落ついたのと、給料に不満があったので転職ドラフトに登録しました。1件だけ指名を貰うことが出来たのですが、一次面接で落選しました。
そこで、転職ドラフトエージェントに登録したというわけです。
# 結果
330万→500万
170万くらいアップしました！！

__スペック__
文系
大卒
PHPエンジニア（3年半）
要件定義～テスト（3年半）
プライベートでプログラムの勉強はほぼしない。
技術記事の投稿経験なし
GitHubアカウントなどは転職先に共有してないです。

___エージェントの紹介＋転職ドラフトの指名（１件)___
1次面接 7社
最終面接 1社
内定 １社

__評価していただいた点__
面接中はとにかく明るく話していたところ。
現職でやっている知識で活かせそうなものが多かったところ。

__反省点__
プライベートでほぼ勉強してないところ。
技術的なレベルが低い。
受け身な印象。

# 転職活動をしてみての感想
プライベートでの技術に対するアウトプットを評価する企業が多かったです。仕事外でも勉強を頑張ってみようと思いました。
転職ドラフトの年収評価シートを通じて、今の会社で自分が何をやってきたのかを振り返ることが出来ました。
転職活動を通して、自分の技術力が低いことを自覚出来たため、それをカバーするために面接中は明るく振る舞えたのは良かったと思います。初期の方で自覚出来ていれば、もう少し一次面接も通ったかなと思いました。

# 転職ドラフトエージェント
#### 良かった点
面接後にフィードバックが返ってくるところ。
スケジュール調整をすべてエージェントがやってくれる。
最初にエージェントと面談して、自分のやりたいことを掘り下げてくれる。
希望年収に沿った求人を紹介してくれる。（自分の場合は、ミニマム450万くらいで紹介してもらえました。）

#### 改善点
転職ドラフトエージェントは転職成功プレゼントがありません。
職業紹介事業においては「職業安定法」にて金銭等の提供を禁止されているためだそうです。

# 転職ドラフトエージェントを使ったことがない方へのメッセージ
まず、転職ドラフトで年収評価シートを書くことをおすすめします（自分の経歴を振り返るため）。
１年から4年くらいの実務経験があり、年収300万台位の人なら一度使ってみることをおすすめします。多分給料が上がると思うので。。
転職ドラフトでばんばん指名が来る強者のエンジニアでなくてもエージェントが仕事先を見つけてくれるのでおすすめです。

転職ドラフト
https://job-draft.jp/
紹介コード`NRLV`

転職ドラフトエージェント
https://agent.job-draft.jp/