OmniAICreator/Qiita-1.07M huggingface dataset:
無料枠のGoogle ColabでGPT-3.5を超えるLLMを動かす！Mixtral offloadingについて

## はじめに
2023年12月DeepMindやMeta出身の研究者が設立したMistral AIが、大規模言語(LLM)モデル「Mixtral 8x7B」をリリースしました。多くのベンチマークでGPT-3.5やLlama 2 70Bを上回る性能を持つと言われています。

https://mistral.ai/news/mixtral-of-experts/

Mixtral 8x7BはMixture-of-Experts（MoE）モデルを採用しています。
MoEとはモデルの中に複数のブロック(Expert)を用意しておき、入力によって適したブロック(Expert)のみを用いて推論をする手法です。Mixtral 8x7Bでは8つのExpertから2つのExpertのみを使用して推論します。

上記のMixtral 8x7Bは、通常の実装だと8つのExpertをGPU上に置いておく必要があるのでGPUのコストがかかります。

この問題を解決すべく、限られたGPU環境(例:無料枠のGoogle ColabのGPU)でMixtral 8x7Bを動かす手法を紹介した論文「Fast Inference of Mixture-of-Experts Language Models with Offloading」を紹介します。

- arXiv

https://arxiv.org/pdf/2312.17238.pdf

- GitHub

https://github.com/dvmazur/mixtral-offloading?tab=readme-ov-file

:::note
すぐ動かしたい方はこちら
:::

https://colab.research.google.com/github/dvmazur/mixtral-offloading/blob/master/notebooks/demo.ipynb

## 内容
本論文では以下3つの手法でMixtral 8×7Bの効率化をしています。

- Expertのキャッシュ保持
- Expertのプリロード
- 量子化

### Expertのキャッシュ保持
下図はExpertがどのように使われているかを示した図であり、縦軸がExpertで横軸が入力のトークンです。青色で示したExpertは実際に使われているExpertです。(灰色は後述)

![スクリーンショット 2024-01-05 11.56.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/ac5fcde6-5479-4a33-25d8-6ab672f38b26.png)

図より、各入力トークンによって異なるExpertが使われていることがわかると同時に、隣り合ったトークンで同一のExpertを使っていることが多いことがわかる。

このパターンを利用するために、本論文ではアクティブなExpertを将来のトークンのための「キャッシュ」としてGPUメモリに保持します。これにより同じエキスパートが再びアクティブになれば、即座に利用できるようになります。

キャッシュの保持の仕方としては、k個の直近使用されたExpertを常に保持するというLRU キャッシュを採用しています。

図の灰色の部分は、k=2の保持されたキャッシュを表しています。

![スクリーンショット 2024-01-05 11.55.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/886e5535-b129-f85e-f11b-02ee63541f0d.png)

上図はLRU キャッシュのヒット率を表していてk=2,3で大体5割程度キャッシュがヒットしていることがわかります。

### Expertのプリロード
上記キャッシュによってExpertのローディング時間を短縮できますが、依然キャッシュで対応できないExpertはローディングの必要があり、推論時間の大半を占めています。

MoEでは、前の層の最終出力を使って次回用いるExpertを選択することから、事前に確実にExpertをプリフェッチすることは不可能です。

しかし、何らかの手段で次のExpertを推測できればExpertをプリロードすることができます。(投機的なロード)

本論文では、次の層のゲーティング関数を前の層の隠れ状態に適用することで、次の層のExpertを正確に推測できることを発見しました。

![スクリーンショット 2024-01-05 12.20.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/5a8ba7da-42fd-4e5b-4d63-566c848f9bf2.png)

上図はプリロードのリコール(取りこぼしなくロードできたか)を示しており、実線が1層前の出力、点線が2層前の出力、ドット線が10層前の出力からExpertを予測しています。

層が手前であればあるほど、よりモデルの最終出力に近くなるので推測が容易になるためリコールが高くなります。（その分、並列処理内でプリロードできる時間が限られてしまいます。）

どの程度プリロードできるかはGPUサイズによりますが、プリロードできるExpertが1個(緑線)かつ2層前の出力を使ってもリコールが4,5割程度で、ランダムにプリロードする期待値よりは高いので効果がありそうです。

:::note 
期待値の計算の仕方は2通りあって、キャッシュを保持するかしないかによって計算方法が異なります。

プリロードできるExpertを1個としたとき、
(i)キャッシュを保持しない場合だと、2/8 = 25%が期待値であり、(ii)k=2でキャッシュを保持する場合だと、キャッシュヒット率を50%として(2-1)/(8-2) = 16%が期待値となります。

つまり前の層の出力からのExpertの推測は、期待値よりも高い精度で推測できていることがわかります。(これも論文に書けば良いんじゃなかろうかと思っています。)
:::

キャッシュの保持とプリロード1つ->キャッシュ保持をやめて、プリロードのエキスパートを3つにした方が精度が良く、時間を削減できそうですが、キャッシュ保持の方がメモリ的に嬉しそうです。(おそらく)

## 量子化
すべての非Expertを4bit、Expertをハーフ2次量子化（HQQ：Half Quadratic Quantization）（Badri & Shaji, 2023）で量子化しています。これによりMoEモデルの品質とサイズのトレードオフが改善されます。また1bit量子化では性能が著しく低下すると記述されています。


## おわりに
いかがだったでしょうか。

2023年12月11日に公開されたMixtral 8x7bを、即座にGPUコストを小さくするという変更を加えて実験を行い、2023年12月28日に初稿をarXivへ出すという仕事の速さが怖いです。(裏で実はやっていたのかもしれませんが、)

手法自体はとてもシンプルであり、今後応用が十二分にできそうなので参考にしたいと思います。
VSCodeからAmazonQを使ってみた(Amazon版のChatGPT)

# はじめに
皆さん、こんにちは。都内でソフトウェアエンジニアをしている[YSasago](https://qiita.com/YSasago)です。今年のAWS re:Invent 2023で注目を集めた新サービス、[AmazonQ](https://aws.amazon.com/jp/q/)をもう試されましたか？私は、このサービスが特に大きな話題を呼んだと感じています。AmazonQは発表と同時にAWSコンソールにChatBoxが表示され、すぐに試すことができました。さらに、IDE（VSCodeなど）にも対応しているとのことで、私は日常的に使用しているVSCodeからAmazonQを使ってみました。

https://aws.amazon.com/jp/q/

# AmazonQとは
Amazon Qは下記の特徴があり、OpenAIのChatGPTに似た、Amazon版の生成AIアシスタントです。現在(2024年1月時点)はプレビュー版で、VSCodeからAmazonQの利用は無料です。

•AWSの17年分の知識を学習
•AWSコンソール、IDE、ドキュメント内でサポート
•AWSの新機能の開発、ソリューションの設計を対話で解決
•トラブルシューティング、新機能の構築、AWS上での言語アップグレードを共にサポート



# 事前準備
## VSCodeに拡張機能をインストール
[AWS Toolkit for Visual Studio Code](https://aws.amazon.com/jp/visualstudiocode/?trk=ad553193-613c-4a84-acde-bf4fa6c173a5&sc_channel=el)をVSCodeにインストールします。

![FireShot Capture 065 - Visual Studio コードプラグイン — AWS Toolkit for Visual Studio Code - AWS_ - aws.amazon.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95954/20f0a0dc-9c5c-2556-8cd6-401293b0eba0.png)

[VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.aws-toolkit-vscode)から直接インストールできます。

![FireShot Capture 066 - AWS Toolkit - Amazon Q, CodeWhisperer, and more - Visual Studio Marke_ - marketplace.visualstudio.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95954/1db7e8ef-d92a-7c00-72af-f284084efcc1.png)


インストール完了後のスクリーンショット：
![スクリーンショット 2023-12-28 14.58.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95954/fa33cde5-9894-03a8-0945-0581d1a84c96.png)

https://docs.aws.amazon.com/amazonq/latest/aws-builder-use-ug/q-in-IDE-setup.html


## AWS Builder IDと紐づけ
VSCodeでAmazonQを使用するには、AWS Builder IDが必要です。まだ作成されていない場合は、無料で作成しましょう。

![スクリーンショット 2023-12-27 10.17.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95954/7849856d-4e20-61a4-e19d-e74e3111bfa3.png)

![スクリーンショット 2023-12-28 16.32.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95954/2668bb9d-731a-bbff-ca2b-d9b1493338e8.png)

https://us-east-1.signin.aws/platform/login?workflowStateHandle=2bc87442-bd8e-447f-9b30-e6f19c01afbf

## 実際に使ってみる
AWS Builder IDとの連携が完了すれば、VSCodeからAmazonQが利用できます。現在（2024年1月時点）では英語にのみ対応しているので、英語で質問してみます。

![スクリーンショット 2023-12-28 16.33.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95954/18d1d5c6-69a5-9661-eebb-4d56273aa6a8.png)

![スクリーンショット 2023-12-28 16.35.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95954/b791048b-b478-09a1-36a7-124fc9d2f118.png)

しっかり回答してくれました。

AWSのドキュメントを探すのは大変ですが、AmazonQを使用すると、ドキュメントのURLも瞬時に提供してくれます。コードを選択して質問すると、説明もしてくれます。
![スクリーンショット 2023-12-28 16.38.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95954/0c70f04d-5548-ec75-ddd0-45b886e5d829.png)


# おわりに
AmazonQはAWSコンソールからも操作可能ですが、VSCodeを日常的に使用している方には、直接VSCodeから質問できる点が特に便利だと思います。現在は英語のみの対応ですが、日本語対応も待ち遠しいですね。現在は無料で様々なことを試せるので、いろいろと質問してみるのがおすすめです。最後までお読みいただき、ありがとうございました。
Qiita アップデートのお知らせ - 2023年 12月

![Qiitiaアップデートのお知らせ 2023年12月](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88/7f41fd81-f9c6-239e-fa2d-b798987eb68b.png)

## はじめに

Qiitaでは、エンジニアのみなさんからの声をもとに、日々開発を続けています。
この記事では、2023年 12月にリリースした内容を紹介します。

Qiitaでアップデートやバグ修正をリリースしたら、[リリースノート](https://qiita.com/release-notes)、[Qiita 公式 X(Twitter)](https://twitter.com/Qiita)、[Qiita Blog](https://blog.qiita.com/)でお知らせしています。

また、Qiitaへの質問や機能の要望などがありましたら、[Qiita Discussions](https://github.com/increments/qiita-discussions) へご投稿ください。

## 2023年振り返りレポートページを公開しました

![振り返りページのスクリーンショット。ユーザーのページにはContribution、書いた記事数、読まれた数が表示されている。Organizationのページには書いた記事数、投稿した人数、フォロワーそうか数、読まれた数が表示されている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88/e62052d6-f605-7488-9348-e4b4a0c15c08.png)

*2023年 12月26日 リリース*

2023年の活動を振り返ることのできるページを追加しました！
去年までは振り返りレポートをメールでお届けしていましたが、Qiita Discussions などの要望から、今年は振り返りレポートをページとして公開しています！

[自分自身のページ](https://qiita.com/yearly-summary/2023)と、所属しているOrganizationのページのみ閲覧が可能です。
詳しい内容は[振り返りページについてのQiita Blog](https://blog.qiita.com/yearly-summary-2023/)をご覧ください。

## 文章修正提案機能（ベータ版）にルールを追加しました

![Qiitaのエディタのスクリーンショット。「食べれない」と書かれた箇所に赤波線が引かれ。「ら抜き言葉を使用しています。」と表示されている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88/7d2ec209-5e7b-4db9-3d5b-6848420e1786.png)

*2023年 12月08日 リリース*

より記事執筆がしやすくなるように、ベータ版で公開している文章修正提案機能に以下のルールを追加しました。

- ら抜き言葉の確認
- AWSのサービス名のチェック
- 同一の単語が間違えて連続しているのを見つける
- 全角と半角アルファベットの混在をチェックする
- 1つの文中に同じ助詞が連続して出てくるかの確認

## Advent Calendar記事投稿バッジを追加しました

![バッジページのスクリーンショット。Advent Calendar 2023 記事投稿のバッジが並んでいる。Advent Calendar 2023 記事投稿のバッジのモーダルにはAdvent Calendar 2023 に1記事投稿から25記事までのバッジが並んでいる。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88/a6fec64b-967e-d2c2-2d03-f70e9c8fb158.png)

*2023年 12月01日 リリース*

Advent CalendarにQiitaの記事を投稿するとバッジがもらえるようになりました。
獲得したバッジは[バッジ一覧ページ](https://qiita.com/badges)から確認できます。

## エディタ上のプレビューの表示幅が記事ページと揃うようにしました

![変更前と変更後のエディタのスクリーンショット。変更前は画面幅いっぱいにプレビューが広がっているが、変更後は一定の幅になっている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88/2694db57-2c52-1b6b-beed-4c5fda24da96.png)

*2023年 12月13日 リリース*

エディタで表示されるプレビューに記事ページと同じ最大表示幅を設定し、記事ページとプレビューの見た目が揃うようにしました。
「エディタとプレビュー」モードの場合2画面表示になるため、1520ピクセル以上の画面幅の時に見た目が揃うようになります。

## 下書きページのサイドバーのボタンのUIを調整しました

![変更前と変更後の下書きページのスクリーンショット。変更後は変更前から「編集する」ボタンが追加されている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88/ee7faeeb-7b7f-26c0-7442-ba05ad1a2412.png)

*2023年 12月14日 リリース*

下書きページのサイドバーのボタンについてご意見をいただき、UIを調整しました。

- 「編集する」「削除する」ボタンの位置を左揃えに変更
    - モバイルで「削除する」ボタンの誤タップの恐れがあるため
- モバイルサイズでも「編集する」ボタンを追加
    - カード全体をクリックしてもエディタに遷移できます
VPSまるまるイメージバックアップ

Mondo Rescue を使用して、VPS環境を別の環境にインストール可能なisoを作成します。

CentOS7

```:インストール
cd /etc/yum.repos.d/
wget http://www.mondorescue.org/ftp/centos/7/x86_64/mondorescue.repo
wget http://www.mondorescue.org/ftp/centos/7/x86_64/afio.repo
yum -y install afio mondo lzop
```

```:インストールバージョンの確認
yum list installed | grep mondo
mondo.x86_64                         3.3.0-1.centos7           @afio
yum list installed | grep afio
afio.x86_64                          2.5-1.centos7             @afio
buffer.x86_64                        1.19-8.centos7            @afio
mindi.x86_64                         3.3.0-1.centos7           @afio
mindi-busybox.x86_64                 1.25.1-1.centos7          @afio
mondo.x86_64                         3.3.0-1.centos7           @afio
perl-IO-Interface.x86_64             1.05-2.el7                @afio
perl-Module-ScanDeps.noarch          1.10-3.el7                @afio
perl-MondoRescue.noarch              3.3.0-1.centos7           @afio
perl-ProjectBuilder.noarch           0.16.1-1.centos7          @afio
```



```
mondoarchive -Oi -L -N -s 10g -E /backup -d /backup -p Backup_20210605
```
Microsoft Store版Python環境でpipインストールしたコマンドにPathを通す

# 目的
Microsoft StoreでPythonをインストールした。インストールしただけでpythonコマンドやpipコマンドにはPathが通っていたが、pipでインストールしたパッケージのコマンドにはPathが通っていないようだ。

Microsoft Store版Python環境でpipインストールしたコマンドにPathを通したい。

# 調査
python.exeやpip.exeは```C:\Users\XXXXXXXX\AppData\Local\Microsoft\WindowsApps\```にインストールされていた。しかしその周辺にsite-packagesやScriptsディレクトリはないようだ。さてさて？

## pip showを使ってみる
pipでインストールされたパッケージがどこにインストールされているか？
pip show -fのLocation:が使えそうだ。

```shell-session
PS > pip show -f jupyter
Name: jupyter
Version: 1.0.0
Summary: Jupyter metapackage. Install all the Jupyter components in one go.
Home-page: http://jupyter.org
Author: Jupyter Development Team
Author-email: jupyter@googlegroups.org
License: BSD
Location: C:\Users\XXXXXXXX\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages
Requires: ipykernel, ipywidgets, jupyter-console, nbconvert, notebook, qtconsole
Required-by:
Files:
  __pycache__\jupyter.cpython-312.pyc
  jupyter-1.0.0.dist-info\DESCRIPTION.rst
  jupyter-1.0.0.dist-info\INSTALLER
  jupyter-1.0.0.dist-info\METADATA
  jupyter-1.0.0.dist-info\RECORD
  jupyter-1.0.0.dist-info\REQUESTED
  jupyter-1.0.0.dist-info\WHEEL
  jupyter-1.0.0.dist-info\metadata.json
  jupyter-1.0.0.dist-info\pbr.json
  jupyter-1.0.0.dist-info\top_level.txt
  jupyter.py
```
どうやら```C:\Users\XXXXXXXX\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages```にインストールされたらしい。

## 一つ上のディレクトリに移動してみる
```shell-session
PS > cd C:\Users\XXXXXXXX\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\
PS > dir

    Directory: C:\Users\XXXXXXXX\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2024/01/05    11:42                Scripts
d----          2024/01/05    11:42                site-packages

```
```Scripts```ディレクトリ発見。ここにpipでインストールされたパッケージのコマンドが入っている。

# Pathを通そう
ということで、以下のディレクトリにPathを通せばよい。
```C:\Users\XXXXXXXX\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\Scripts```
【ChatGPT有】Web版とアプリ版の違いが見つかりましたので、ご報告です。


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

　今回は、ChatGPT（有料版）でWeb版とアプリ版の違いがありましたのでご報告。

:::note info
本記事は、ChatGPT（有料版）で
行なっております。無料版での確
認はできておりません。あしからず。
:::
　まずは、
　　OpenAIからの
　　　メールが届いたことを
　　　　ご報告。

　まぁ、
　　有料版ユーザーである
　　　みなさんにも
　　　　来ていることでしょう。
![Screenshot_20240105-111740.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/15188798-29ba-4d9d-fdbd-22ae19138215.png)

　待望の
　　GPT Storeのオープンが
　　　来週になりました。

　用意は
　　済んでいますか？

　私？

　私は
　　使う側にまわりますw

　作ってはいるのですが、
　　特定のサイトのFAQが
　　　できるだけのものなので。

　OpenAI、
　　Wikipedia、
　　　Microsoft、
　　　　Discord。

　どれも
　　サイト名を
　　　変更しただけの
　　　　同じ内容w

　なので、
　　公開するのは、
　　　仲間内としています。

　みなさんがアップされる
　　GPTsを楽しみに待ちますね。
***
　さて、本題です。

　まぁ、
　　たいしたことでは
　　　ないのですが。

　Web版とアプリ版の
　　表示上の違いになります。

　内容が
　　個人的なものだったので
　　　画像のアップは
　　　　控えさせてください。
　　　　　m(_ _)m

　違いというのは、
　　ChatGPTの回答が
　　　長い場合でのことです。

　例えば、
　　小説を出力させた、とします。

　当然、長い。

　Web版では、
　　一度の回答に
　　　出力されます。

　ところが
　　アプリ版だと
　　　節目節目で切れて、
　　　　新たな回答のような
　　　　　表示になるのです。

　まるで、
　　“You”というユーザーの入力を
　　　削除したかのようでした。

　言葉での説明しか
　　できないのが
　　　申し訳ないのですが、
　　　　なんとなく、
　　　　　わかってもらえる
　　　　　　でしょうか？
***
　もしかしたら、
　　“すでに知っている”方も
　　　おいでかもしれませんね。

　私は知りませんでしたので、
　　相手のスクショを見て、
　　　疑問に思い、
　　　　問い詰めてしまいました。

　それで、
　　相手がアプリ版だと気付いて
　　　自分でもやってみたのです。

　そうしたら、
　　そのように再現され、
　　　相手に謝った次第です。

　長い回答を出力した
　　過去のセッションがあれば、
　　　確認してもらえるはずです。
***
　本来ならば、
　　違う表示をするのが
　　　いけないのですが、
　　　　OpenAIに文句を言っても
　　　　　詮無きこと。

　対処してくれる、とも
　　考えられませんからねw

　みなさんも
　　ご注意ください。

　今回は、ここまで。
Adafruit MCP23017 Arduino Library (Adafruit_BusIO)で I2C ピンを変更する


Adafruit MCP23017 Arduino Library (Adafruit_BusIO)で I2C ピンを変更する

# 環境


- Arduino IDE 1.8.19
- esp32 by Espressif Systems Version 2.0.14
- Adafruit MCP23017 Arduino Library Version 2.3.2
- Adafruit BusIO Version 1.14.5

# プログラム

「ファイル」-「スケッチ例」-「カスタムライブラリのスケッチ例」-「Adafruit MCP23017 Arduino Library」-「mcp23xxx_blink」

冒頭部分を MCP23017 に合わせて書き換え

```
#include <Adafruit_MCP23X17.h>
#define LED_PIN 8
Adafruit_MCP23X17 mcp;

void setup() {
  Serial.begin(115200);
  Serial.println("MCP23xxx Blink Test!");
  if (!mcp.begin_I2C()) {
    Serial.println("Error.");
    while (1);
  }
  mcp.pinMode(LED_PIN, OUTPUT);
  Serial.println("Looping...");
}
void loop() {
  mcp.digitalWrite(LED_PIN, HIGH);
  delay(500);
  mcp.digitalWrite(LED_PIN, LOW);
  delay(500);
}
```

# エラー

実行すると

```
MCP23xxx Blink Test!
Error.
```

# I2C ピンの変更

これは、デフォルトでは ESP32 は 

- SDA:GPIO21
- SCL:GPIO22

となっているため。しかしながら今回使用したハードウェアでは以下のようになっていた。


- SDA:GPIO14
- SCL:GPIO15

さて、 Adafruit_MCP23017 Arduino Library ではどのように指定したらいいかな・・・と調べてみたがドキュメントが無い? ソースもみてみたが関係しそうな記述がなかった。多分 Adafruit_MCP23017 Arduino Library が使用する Adafruit_BusIO でそこらへんは管理しているのだろう。

# 解決策

`setup()` 中に以下を入れる。

```
  Wire.setPins(14,15);
```

実行すると、

```
MCP23xxx Blink Test!
Looping...
```

となり、ポート8(MCP23017 のGPB0)に接続した LED を Blink できた。
個人メモ　docker-composeについて概要を理解する

## docker-composeとは
複数のコンテナの情報を定義して、操作するためのツール。たとえば、WebサーバーとDBサーバー、Redisのサーバーをコンテナでいっぺんに立ち上げたりといったことができる。
docker-composeを使う場合、「docker-compose.yml」という名前のファイルに、各コンテナに対する設定をあらかじめ定義しておく。
その上で専用コマンドを実行することにより、定義した内容に従い複数コンテナを一括で同時に起動させることができる。

## dockerとdocker-composeの違い・関係性
dockerは、dockerコンテナを運用するためのプラットフォーム。dockerが標準で搭載しているdocker engineでは、1度に1つずつしかdockerコンテナを操作できない。
一方でdocker-composeは、複数のdockerコンテナを1度に操作できるツール。

## docker-compose.ymlの定義内容
・service
Docker Composeによって動作させるアプリケーションの単位。
例えば「mysql」「web_app」など。

・image
利用するDockerイメージを指定。「mysql:8」など。

・build
Dockerコンテナをどのように実行(build)するかをまとめます。

・volume
Dockerコンテナをマウントするボリュームを指定します。

・ports
ポートマッピングの内容を指定します。

・depens_on
他サービスの依存関係に関する指定です。

## 基本的なコマンド例
・イメージ構築
```
docker compose build
```

・アプリケーションの起動
```
docker compose up -d
「-d」は、バックグラウンドでコンテナを起動するオプション。
```

・アプリケーションを停止
```
docker compose stop
```

・アプリケーションを停止し、コンテナを削除
```
docker compose down
```

・アプリケーションの再起動
```
docker compose restart
```
alias登録時に叩いているコマンドも表示する

# 登録した内容
```s
$ alias gf='echo "$ git diff --stat"; git diff --stat' 
```

# 実施結果
```s
$ gf #叩いたコマンド、以下は表示結果
$ git diff --stat
 gatsby-config.js                |  2 +-
 package.json                    |  2 +-
 src/components/social-share.tsx | 21 +--------------------
 3 files changed, 3 insertions(+), 22 deletions(-)
```

# 実施コマンドを反映した背景
ベアプロ時に叩くことが多く、見ている側が分からないとなることを避けるため
pythonでプログレスバーを表示【tqdm】

# はじめに
qiitaの住人のみなさま、あけましておめでとうございます！
2024年は元旦から不幸なニュースばかりですが、少しでも前を向きながら生きていきたいものです。
（私は胃腸炎で元旦から寝込むというスタートダッシュを切りました）

さて、最近は機械学習コンペにちょこちょこ参加しています。nishika様、お世話になっております（手コネコネ）。
勉強をしていく中で、pythonでプログレスバーを表示させる「tqdm」なるライブラリを見つけたので、少しご紹介します（n番煎じですがご容赦）。
ビッグデータの機械学習は長い処理が多くなるので、進捗を可視化するのに便利です。

https://www.nishika.com/

# tqdmとは
### 由来
tqdm はPythonで利用可能な便利なライブラリで、長い処理の進捗状況をプログレスバーとして表示することができます。公式サイトによると、この名前はアラビア語の「taqadum」（進行、進捗）から来ていて、スペイン語の「te quiero demasiado」（I love you so much）の略語らしいです。おっしゃれ～♪

**好きな人に勇気が出なくて告白できない方、パートナーに小恥ずかしくて愛を伝えられない方は「tqdm」とだけLINEに打って、そっと送りましょう。**

### これがLove＆Peace、違うかい？

ではここらへんで。次の記事でお会いしましょう。

https://tqdm.github.io/

<br>

間違えました、記事を終わろうとしてしまいました。でももうサビは終わったので以下は読まなくてもいいです。

### tqdm の主な特徴

簡単な使用法：tqdm は、forループに簡単に組み込むことができ、特別な変更を加える必要はありません。ループ内の各イテレーションの進捗状況を視覚的に追跡することができます。

柔軟性：さまざまな設定が可能で、プログレスバーの外観や情報の表示方法をカスタマイズできます。

広範な互換性：標準のforループのほか、リスト内包表記やPandasのデータフレーム操作など、多様な状況で使用することができます。

効率性：プログレスバーの表示が処理速度にほとんど影響を与えないため、パフォーマンスに悪影響を及ぼすことはほとんどありません。

# tqdmの使い方
非常に簡単です。いつもの `for i in hoge:` を `for i in tqdm(hoge):` にするだけです。

```python:例
from tqdm import tqdm
import time

for i in tqdm(range(10)):
    time.sleep(1) 
```

```python:出力
100%|██████████| 10/10 [00:10<00:00,  1.00s/it]
```

pandasのデータフレームの処理にtqdmを組み込むこともできます。
desc引数で処理の説明を追加しています。

```python:例
import pandas as pd
from tqdm import tqdm

# データフレームの作成
df = pd.DataFrame({'A': range(1, 11), 'B': range(11, 21)})

# tqdmを用いたデータフレームの処理
for index, row in tqdm(df.iterrows(), total=df.shape[0], desc="Processing rows"):
    time.sleep(2)  
```

```python:出力
Processing rows: 100%|██████████| 10/10 [00:20<00:00,  2.00s/it]
```

### 主な引数
desc: str
プログレスバーの前に表示される説明テキスト（例：desc="Loading"）。
total: int or float
イテラブルの総要素数。自動的に検出されますが、明示的に設定することもできます。
leave: bool
プログレスバーが終了した後も表示を残すかどうか（Falseの場合100%になったらバーが消失）。
ncols: int
プログレスバーの幅（文字数）。自動的に調整されますが、数値で指定することもできます。
mininterval: float
プログレスバーの最小更新間隔（秒）［デフォルト：0.1］。

# おわりに
まだまだ知らないライブラリがたくさんありますね。tqdmもGooglColabに標準インストールされていたので、私が無知なだけで有名なのでしょう。
日々勉強です。

ではここらへんで。次の記事でお会いしましょう。
DatabricksでOpenDalleV1.1を動かしてみる

画像系生成AIにも食指を。ライセンスは**Non-Commercial Personal Use License Agreement**なのでご注意ください。

https://huggingface.co/dataautogpt3/OpenDalleV1.1

GPUクラスターを準備します。
![Screenshot 2024-01-05 at 10.12.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/63dcd844-571f-e042-18a8-7a0b17eb6efc.png)

ライブラリのインストール。

```py
%pip install -U diffusers transformers accelerate
dbutils.library.restartPython()
```

```py
from diffusers import AutoPipelineForText2Image
import torch
        
pipeline = AutoPipelineForText2Image.from_pretrained('dataautogpt3/OpenDalleV1.1', torch_dtype=torch.float16).to('cuda')        
image = pipeline('black fluffy gorgeous dangerous cat animal creature, large orange eyes, big fluffy ears, piercing gaze, full moon, dark ambiance, best quality, extremely detailed').images[0]
```

```py
image
```

おおー。
![cat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/210b684f-d1d8-a417-2880-eceb4038207f.png)

なお、画像はノートブックにレンダリングされるので確認が楽です。
![Screenshot 2024-01-05 at 10.36.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1dbfdf0d-3eda-cb4f-ba98-3bf47215f55e.png)

別のプロンプトで。

```py
image = pipeline('2 birds facing each other. The one is white crow. The another one is red love bird').images[0]
image
```

若干解釈が混じっているようですが、これはこれで面白い。
![birds.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/49d3f8db-a541-7423-e15d-de6226b4bdaf.png)

日本語プロンプトだとなかなか難しいです。

```py
image = pipeline('賑わっている動物園').images[0]
image
```

賑わっている？動物園？
![zoo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/34b83c0b-2d53-e1a5-b181-dddedb627fda.png)

しかし、去年はMidJourneyなどを触って一喜一憂していた訳ですが、今では無料のモデルでこういうことができるようになったんだなとしみじみ感じる年始です。

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
namespace 


+ [Why the namespace is not blank](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Vg1Xs)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/eaa7ff11-e2e0-bd1c-5552-ca0ea90f80bd.png)

:::note
So far once if you registered your namespace then you can't remove/edit it. It's unique across all the organization.

If you need such feature you can vote for this idea => http:// https://success.salesforce.com/ideaview?id=08730000000BqjiAAC


https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007T43JfSAJ

Once a namespace prefix is created, it cannot be changed or deleted. The workaround is to move all your code to a new Developer Organization, where you can setup the desired Namespace Prefix.

https://help.salesforce.com/s/articleView?id=000385558&type=1
:::
Azure AI-102/Azure AI Engineer Associate を年末の忙しい一週間で突破する方法

## 概要
昨年末にAI-102に合格したので、効率的な勉強法や対策方法、試験を受ける上での注意点についてご紹介したいと思います。

https://learn.microsoft.com/ja-jp/credentials/certifications/exams/ai-102/

## 費用
AzureのCloud Skill Challengeに参加し、試験の半額クーポンを入手したので、通常2万円強のところ2万円程度程度ですみました。このCloud Skill Challengeで入手できる半額クーポンは大抵のAzure試験に使えるので、簡単なコースを手早く終わらせてパッとクーポンを入手すると良いです。

https://developer.microsoft.com/ja-jp/offers/30-days-to-learn-it

## 筆者の概要
・データサイエンティストとしてAI/DX関連のプロジェクトに従事
・専門は画像処理だが、一通りの機械学習の知識はある状態。
・関連保有資格：AWS Machine Learning Specialty/Azure Fundamentals(AZ-900)/kaggle expert
・Azureの経験：Power Apps/Form Recognizerを案件で１−２ヶ月扱った程度

## 動機
・以前はAWSを触ることが多かったが、転職後Azureの案件が増えてきた。特にPower Platform/AI Search/Form Recognizerなど
・会社のキャンペーンで２０２３年内に受けるとお得だったので、12/27の年内スレスレに受験

## 勉強方法
Day1〜Day3：以下の講座を斜め読みしたあとで一通り章末テストまで完了させ、Azureのサービス名や機能の概要などをここで一通り頭に入れる。章末問題はAI-102よりも簡単だが解説が丁寧で助かるので、ここで基礎を固めるのが重要。

https://learn.microsoft.com/ja-jp/training/paths/get-started-with-artificial-intelligence-on-azure/

Day4以降：上記の講座が終わったら、ひたすらUdemyの試験問題を解く。特に、ドキュメントの中から答えを探す訓練を積んでおき、わからない問題・知らないサービスをスムーズに探し、ドキュメントベースで理解するように心がける。教材が英語なので、edgeの翻訳機能を使いながら勉強を進めた。

https://www.udemy.com/course/ai-102-microsoft-azure-ai-solution-practice-tests-exam-prep/learn/quiz/5537146

・もしドキュメントでわからない場合は、Microsoft公式youtubeなどでサービス紹介の動画を見る。

## （参考）AWS Machine Learning　SpecialtyとAzure AI-102の違い
・AWSが機械学習の理論や基礎知識ををそのまま聞いてくるのに対し、Azureは必ずサービスに絡めて聞いてくるのがAI-102。AWS Machine Learning　Specialty　は「最もAWSの試験らしくない」と言われる理由がわかった。
・難易度はAWS Machine Learning　Specialtyよりも易しい。
・AI-102はAPIなどの細かい仕様や穴埋めが出題される。また、実際のユースケースに即した問題では、使用するサービスをどの順で並べてソリューション構築するかが問われる。（AWSは四択式）

## 感想
・AWS Machine Learning Specialtyの試験と比べ、丸暗記するプレッシャーから開放される一方で細かい出題が多い。この試験は公式ドキュメントを調べられる分、難易度はやや下がるが、時間をほぼフルで使った。
・問題集によく似た問題が出るので、分からなかった問題をしっかり振り返っておくことが重要。
・最低１−２問は訳がおかしい問題に遭遇するので、英語の原文も読みながら解くとよい。
・家でも受験はできるが、デスクの上をまっさらにする必要があるので、片付けが大変。試験官からの指摘も細かいので注意。
・プログラミングの知識は少し必要だが、プログラミングの知識そのものは問われることは少ない。例えばソースコードの形態で出題されていても、実は適切な機械学習アルゴリズムだけの簡単な問題だったりする。
・日本語入力モードで公式ドキュメント検索を行うとものすごくレスポンスが遅く役に立たないので、ドキュメントは必ず英語で調べる癖をつけると良い。

以上、ご参考になれば幸いです。読んでいただきありがとうございました！
XOR演算を使用して解く LeetCode Single Number

## 問題文
空でない整数 nums の配列では、1 つを除いてすべての要素が 2 回出現します。その 1 つを見つけてください。

実行時の複雑さが線形になるソリューションを実装し、一定の追加スペースのみを使用する必要があります。

## 解答
上記問題のポイントは、同じ数を確認できるかどうかです。
XOR演算＾を使用することにより、可能になります。
なぜなら、XOR演算では同じ数があった場合0になり、被っていない数は残るからです。

### コード　java
```java
class Solution {
    public int singleNumber(int[] nums) {
       int result = 0;
       for (int n : nums){
           result^=n;
       } 
        System.gc();
       return result;
    }
}
```
実行時間:2ms
メモリー：42.74
2024年の目標を表明する


新年あけましておめでとうございます。
![dragon_kotatsu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495456/7e4265c1-68cb-1454-6472-5c04c5491585.png)

今回は趣向を変えて今年の目標を定めたので共有したいと思います。

# 1. 定めた目標

***日本語力向上***
***英語の苦手意識をなくす***
***極力マウスを使わない***

テーマは中長期です。
長い期間をかけて身に付けるものや
ずーーっと使えるスキルを習得する一年にしようと思います。

一個一個解剖していきます。

# 2. 日本語力向上

日本語力は抽象的なのでもう少し具体的に言うと

- 語彙力
- 読解力
- 正しい文法

:::note warn
自分で勝手に定義してるからね！
:::


綺麗な景色やおいしい食べ物に出会った時など
「すご過ぎて言葉が見つからない」と思うことが多いのですが
よくよく考えるとそれって単に自分の語彙がないだけじゃね？？？

だったり

何かを伝えるとき自分が伝えたい内容じゃなく捉えられることが多いです。

日本語力を鍛えることで

- 言葉の引き出しが増えることで正しく伝わる言葉をつかえる（はず）
- 受け取った文字、言葉を今まで以上に理解できる（はず）
→技術書を正しく読み取ることできると、成長の加速が期待できる

いろんな良いことがあると信じています。


# 3. 英語の苦手意識をなくす

自分の英語力ですが
be動詞って結局何？
5W1Hの一個が分からない

など

:::note alert
絶望的です。
:::

絶望過ぎて警告文で表示しちゃいました。
本当に小学校一年生レベルだと思います。

やはりエンジニアとして仕事している以上英語との接触は不可避です。
何度か勉強をしようとチャレンジしましたがその都度挫折してきました。

昔のチャレンジを思い出すと目標が高かったので挫折したのかな思ったので今回はハードルを下げてみます。
その結果「苦手意識をなくす」ことにしました。

# 4. 極力マウスを使わない

具体的には
***Vimの習得とショートカットキーを覚えよう***
です。

![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495456/1e5dd6be-bb8f-012d-b213-c04b12a45614.png)


Vimを会得することでコーディングが爆速になります。
時短になるし何よりカッコいい。
学生時代Go言語の勉強会に参加した時があるのですが講師の方が超速でコーディングしておりその光景がカッコよすぎでした。

他によく使うソフトのショートカットですね。
主にはGoogle Chrome,Excel,Eclipse達です。
ここら辺はマウスを使わずキーボード操作ですべてを完結させたいです。

https://marketplace.eclipse.org/content/vrapper-vim

https://marketplace.visualstudio.com/items?itemName=vscodevim.vim

https://chromewebstore.google.com/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb

# 5. じゃ、何するの？

それぞれの目標を達成するために何をするかまとめます。

- 本を読む
- 小学1年生向けの英語教材で勉強する
- Vimを一回勉強して使う、忘れたら即調べる
- マウス使った瞬間にショートカットを調べる→使うを繰り替える

ちなみに読む本は決まっています。学びになる本を読もうかと考えましたが日本語力向上が目的なので物語系にしました。

https://j-books.shueisha.co.jp/books/jojo_thebooksz.html

ジョジョ4部の小説です。ジョジョ好きなのもありますし、学生時代友人に借りてから一切読まず返した思い出があるのでこれにしました。もともと本嫌いな性分なのでここで克服したいと思います。
（技術書は別だよ♪）

# 6. 終わりに

2024年はこの目標に向かって日々過ごそうと思います。
経過報告は6月下旬に投稿しようかな。

# 7. 予告
次回の投稿は1月19日の予定です！
Fargate上のGitLab起点でLambdaを更新するGitOpsを実現したい

# はじめに
この記事はDevOps on AWS大全 実践編の一部です。
DevOps on AWS大全 実践編の一覧は[こちら](https://qiita.com/tech4anyone/items/c27e74f9ae569ced259f)。

この記事ではGitLab起点でLambdaを更新するCICDパイプラインのアーキテクチャを決める流れを解説しています。

具体的には以下流れで説明します。

- 解決したい課題の整理
- 今回使うAWSサービスの整理
- アーキテクチャの策定
- 策定したアーキテクチャで達成できたこと

AWSの区分でいう「Level 400 : 複数のサービス、アーキテクチャによる実装でテクノロジーがどのように機能するかを解説するレベル」の内容です。

# この記事を読んでほしい人
- DevOpsエンジニアがアーキテクチャを決めるときにどのような思考フローを踏んでいるか知りたい人
- Lambdaを更新するCICDパイプラインのアーキテクチャを知りたい人
- AWS Certified DevOps Engineer Professionalを目指している人

# 前回までの流れ
[こちら](https://qiita.com/tech4anyone/items/7a3b481c385df3bccce3)の記事で以下のアーキテクチャを策定しました。
![](https://storage.googleapis.com/zenn-user-upload/7a291cfbe91e-20240104.png)

# 解決したい課題の整理
現在、解決したいと思っている課題は以下になります。
- GitLabにコミットしたLambdaの定義を使ってGitOpsを実現したい
- CICDパイプラインを実行した後、実行完了までの間はマネジメントコンソールを見たくない

ということで、これをどうやって解決するか考えていきましょう。

# 今回使うAWSサービスの整理
今回使う代表的なAWSサービスの概要とベストプラクティスは[前回](https://qiita.com/tech4anyone/items/7a3b481c385df3bccce3)同様です。


# アーキテクチャの策定
ここからはやりたいことを順番に考えながらアーキテクチャを策定していきます。
## GitLabにコミットしたLambdaの定義を起点にCIを実現したい
まずはCI部分としてアーティファクトの作成を実現します。
Fargate上のGitLabからCodeCommitにミラーリングしてCodepipelineの起点として利用します。

そのうえで、アーティファクトを作成するためにCodeBuildを起動し、S3にアーティファクトを格納します。

これらをまとめると以下のようなアーキテクチャになります。
![](https://storage.googleapis.com/zenn-user-upload/abc327cea5a4-20240105.png)

## GitLabにコミットしたLambdaの定義を起点にCDを実現したい
続いて、CD部分です。
まずは、作成されたアーティファクトをもとに変更内容を誰かに承認してほしいので、承認ステージを追加します。
![](https://storage.googleapis.com/zenn-user-upload/586b0f247e43-20240105.png)

そして、承認後にLambdaのデプロイを実行しますがここではCodeDeployを利用します。

CodeDeployを利用するメリットはLambdaのバージョン変更をエイリアンの切り替えで実現できる点です。

なお、SAMを利用したエイリアスの切り替えも裏側ではCodeDeployが動いているという点と、GitLabがミラーリングされているCodeCommit起点でCodepipelineを動かすほかの形式にそろえたほうが運用管理が楽な点を考慮しSAMは利用しません。

これらをまとめると以下のようなアーキテクチャになります。
![](https://storage.googleapis.com/zenn-user-upload/7ba4226b7d51-20240105.png)

## GitLabにコミットしたLambdaの定義を起点にChatOpsを実現したい
これまでと変わらずCodePipelineをずっと見ていたくはないのでチャットへの通知を実装します。
![](https://storage.googleapis.com/zenn-user-upload/cd90e01e164e-20240105.png)

これに加えてCodeCommitを保持していないアカウントのCodePipelineの起点にもしたいのでこれを実装します。

これらをまとめると以下のようなアーキテクチャになります。
![](https://storage.googleapis.com/zenn-user-upload/2cff16fd2060-20240105.png)

# まとめ
本記事ではGitLab起点でLambdaを更新するGitOpsを実現する方法をまとめました。

今回策定したアーキテクチャで実現できたのは以下の項目です。
- GitLabにコミットしたLambdaの定義を起点にイメージのビルドを実行するCI
- GitLabにコミットしたLambdaの定義を起点にECS関連の資材を作成するCD
- マネジメントコンソールを確認する必要があるタイミングでチャットに通知を飛ばすChatOps

次回はEC2 ImageBuilderの活用を考えてみたいと思います。
Streaming API

ストリーミング API では、プッシュ技術を使用してイベントのストリーミングを行い、ほぼリアルタイムでイベントを受信する登録メカニズムを提供できます。ストリーミング API の登録メカニズムでは、PushTopic イベント、汎用イベント、プラットフォームイベント、変更データキャプチャイベントを含む、複数のイベント種別がサポートされます。

+ [ストリーミング API アプリケーションのデバッグ](https://developer.salesforce.com/docs/atlas.ja-jp.246.0.api_streaming.meta/api_streaming/DebuggingStreamingAPIApplications.htm)


# PushTopic

+ [Salesforce error: "Unable to create Salesforce PushTopic"](https://support.zendesk.com/hc/en-us/articles/4408830295066-Salesforce-error-Unable-to-create-Salesforce-PushTopic-)
+ [Push Topics not working for the Asset Object](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A8UmvSAF)

:::note
Unfortunately, these are the only supported Standard Objects - 

Account
Campaign
Case
Contact
Lead
Opportunity
Task

Read this = 
https://developer.salesforce.com/docs/atlas.en-us.api_streaming.meta/api_streaming/supported_soql.htm
:::

+ [There was a problem connecting to the Salesforce push topic for the mapping 'Contact' and Connect is no longer receiving streaming events. Changes are only detected according to the configured poll frequency.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007W6Q92SAF)

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

# Access to XMLHttpRequest at 'Org 1.lightning.force.com/cometd/52.0' from origin 'Org 2.lightning.force.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

+ [Streaming API support for CORS](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000BqgSI)


:::note
I found the same question, so I did some research.

I assume you were setting up the connection cross domain. It appears the streaming API isn't supported.

https://salesforce.stackexchange.com/questions/179483/how-to-use-latest-cometd-version-in-salesforce-streamingapi
:::
[ポカミス]postgresqlで'error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed'が出た

## TL;DR
`pg_hba.conf`内でスペルミスをしていた。アレ？と思ったらログを見ようと思った(当たり前)。

## 何があった？
Ubuntu22.04に入れたpostgresqlに接続しようとしたところ、以下のようなエラーに遭遇した。
```
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
        Is the server running locally and accepting connections on that socket?
```

`systemctl status postgresql`としてもちゃんと動いているので「？」と思ったが、`/var/log/postgresql`の中にあったログファイルを見ると、最後5行が以下で、「あ～これやん」となった。
```
2022-07-17 22:10:57.919 JST [7287] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2022-07-17 22:10:57.942 JST [7287] LOG:  invalid authentication method "cram-sha-256"
2022-07-17 22:10:57.942 JST [7287] CONTEXT:  line 106 of configuration file "/etc/postgresql/14/main/pg_hba.conf"
2022-07-17 22:10:57.942 JST [7287] FATAL:  could not load pg_hba.conf
2022-07-17 22:10:57.943 JST [7287] LOG:  database system is shut down
```
Arduino と node.js で通信してみる

１．はじめに

　Arduino UNO と node.js 間で、シリアルポート経由の通信を行うサンプルは、たくさんありますが、試しにやってみると、「serialport.parsers.readline」がエラーになりました。
調べてみると、serialport の使い方が変わっているようです。
　サンプルを書き直して動作するようにしたので、紹介します。
なお、すべての環境や状況で動作を保証するものではありません。

２．環境

　下記のとおり、環境を構築しました。

① node.js
	専用ページからダウンロードして、インストールする。

② 作業フォルダ作成
	下記フォルダを作成する。
```
 c:\node
```
③ node_modules
	コマンドプロンプトを起動し、作業をカレントフォルダにした後、モジュールを読み込む。
```
	cd c:\node
	npm install socket.io 
	npm install serialport
	npm install express
```

３．ソースコード

 メッセージを連携するためのソースコードを作成します。
 いずれもUTF-8 で保存してください。

１）Ardunio UNO

　Arduino UNO からは、1秒おきにカウント文字列をシリアルポートへ出力します。
　下記スケッチを適当なフォルダに作成して、Arduino UNO に書き込んでください。

```
#define DELAY   1000

void  setup() {
  Serial.begin(115200);
  
}

void  loop() {
  static int  cnt = 0;

  Serial.print("count:");
  Serial.print(++cnt);
  Serial.println();

  delay(DELAY);
}
```
２）node.js

　c:\uno に適当なフォルダを作成し、ソースプログラムを作成します。
　ここでは、sample というフォルダを作成しました。
　```
　c:\node\sample
　```
　　node.js では、Arduino UNO からのテキストを serialport 経由で受け取り、クライアントへ socket.io 経由で転送します。
　　
```　index.js
　
　// ページの設定
const express  = require('express');
const http     = require('http');
const socketIo = require('socket.io');

const app    = express();
const server = http.Server(app);
const io     = socketIo(server);

const PORT = 8000;

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});

// クライアントからの接続待ち
server.listen(PORT, () => {
  console.log(`listening on port ${PORT}`);
});

io.on('connection', (socket) => {
  console.log('user connected');
  socket.on('disconnect', () => {
    console.log('disconnect');
  });
});

// serialport の設定
const { SerialPort }     = require('serialport')
const { ReadlineParser } = require('@serialport/parser-readline')
const port = new SerialPort({ path: 'COM3', baudRate: 115200 })

const parser = port.pipe(new ReadlineParser({ delimiter: '\r\n' }))
parser.on('data', console.log)

// serialport の読み込みと socket.io 経由で送信
port.on("open", () => {
    console.log('open');
    port.on('data', (data) => {
        console.log(data);
        message =  (new TextDecoder).decode(data);      // バイト配列から文字列へ変換する。
        io.emit('receiveMessage', message);
    });
});
```
３）html

　同一フォルダに、node.js から転送されたメッセージを表示するページを作成します。
　
```　index.html
　
　<html>
  <body>
    <h1>serialport & socket.io</h1>
    <ul id="messageList" />

    <script src="/socket.io/socket.io.js"></script>
    <script>

      const socket = io();

      const addMessageList = (message) => {
        const ul = document.getElementById('messageList');
        const li = document.createElement('li');
        const text = document.createTextNode(message);
        li.appendChild(text);
        ul.appendChild(li);
      };

      socket.on('receiveMessage', (message) => {
         addMessageList(message);
      });
    </script>
  </body>
</html>
```
４．実行

① Arduino UNO の電源を入れます。
② コマンドプロンプトを実行し、作業フォルダをカレントにしてから node.js でプログラムを実行します。
```　
　cd c:\node\sample
　node index.js
```
③ ブラウザを起動し、ページへアクセスします。
```
　http://localhost:8000
```
④ Arduino UNO が出力した文字列が、ブラウザに表示されます。
Macでのターミナル操作ログを残す方法

# 実施する手順
1. ターミナルを立ち上げてMacの操作ログを残したいディレクトリを作る。
    ```s
    $ cd /Users/<User名>/Documents/  #作成したいディレクトリまで移動
    $ mkdir terminal-log             #フォルダを作成
    $ cd terminal-log                #作成したフォルダに移動
    $ pwd                            #パスをフルパスで確認
    /Users/<User名>/Documents/terminal-log
    ```
1. ターミナル起動時に自動実行するように設定を仕込んでおく
    ```s
    $ cd           # ホームディレクトリに移動する
    $ ls -l .zshrc # .zshrcがあるかどうか確認する
    $ vim .zshrc   # 編集する
    以下4行を追記する
    # -----------------------------
    # Terminal Log get
    # -----------------------------
    if [ -z "$SCRIPT_STARTED" ]; then
      export SCRIPT_STARTED=yes
      script /Users/<User名>/Documents/terminal-log/`date "+%Y-%m-%d_%H%M%S"`.log
    fi
    ```
1. (動作確認) (スキップしてもOK) 反映を即時確認したい場合は以下を実施する。または、新規ターミナルを立ち上げる。
    ```s
    $ source .zshrc
    ```
1. (動作確認) 取得したログを開いて、ログが取得できていればOK
    ```s
    $ cat /Users/<User名>/Documents/terminal-log/20yy-hh-mm_hhmmdd.log
    ```

# 補足(.zshrc)
1. .zshrcへ以下の記述だと無限ループが発生する
    ```s
    $ vim .zshrc   # 編集する
    以下4行を追記する
    # -----------------------------
    # Terminal Log get
    # -----------------------------
    script /Users/<User名>/Documents/terminal-log/`date "+%Y-%m-%d_%H%M%S"`.log
    ```
    :::note alert
    script コマンドが新しいシェルセッションを開始し、それがまた .zshrc を読み込んで script コマンドを再度実行する為、無限ループが発生する

# 補足(文字化け)
1. script で出力した情報を普通にテキストエディタで開くと文字化けで表示される。
    回避方法を色々試してみたが、Macのターミナル上でcatで閲覧できるようだったのでそれでOKとした。
AtCoder解説 コーナーケース

# はじめに
AtCoderの過去問を解いていて、なぜかWAになってしまう。
その原因を特定するのに時間がかかってしまった問題についてまとめようと思います。
自分が解説記事調べた時にほしかった情報です。

# ABC216-B
$N$人の人がいて、
$i$人目の人の苗字が$S_i$で、名前が$T_i$です。
$N$
$S_1$ $T_1$
$S_2$ $T_2$
$\vdots$
$S_N$ $T_N$

同姓同名の人がいる場合$Yes$を、いないなら$No$を出力するという問題です。

方針としては、ハッシュマップを用意し、すべての名前を登録しておきます。
例えばaokiさんが2回現れると
$mp[aoki] = 1$
$mp[aoki] = 2$
という風に右側のinteger型の値が増えていきます。
全てを登録し終えたら、ハッシュマップの値すべてを探索し、右側の値が2以上のものがあれば$Yes$を出力します。

:::note warn
注意点(コーナーケース)
「青木 太郎(あおき たろう)」さんと、
「青 喜多朗（あお きたろう）」さん
は別人ですが、アルファベット表記では同姓同名と判断されてしまいます。そのため、苗字と名前の区切りをはっきりさせておく必要があります。
:::

```cpp
#include<bits/stdc++.h>
using namespace std;

int main(){
    int N; cin >> N;

    //ハッシュマップを作る
    unordered_map<string,int> mp;

    for(int i = 0; i < N; i++){
        string x,y; cin >> x >> y;
        /*
        ここで、
        string z = x + y
        としてはだめ
        */
        string z = x + " " + y;
        mp[z]++;
    }

    for(auto &[key,value]:mp){
        if(mp[key]>1){
            cout << "Yes" << endl;
            return 0;
        }
    }

    cout << "No" << endl;
    return 0;
}
```

# ABC247-B
$N$人の人がいて、
$i$人目の人の苗字が$S_i$で、名前が$T_i$です。
$N$
$S_1$ $T_1$
$S_2$ $T_2$
$\vdots$
$S_N$ $T_N$
問題文を言い換えると、$i$人目の人の苗字か名前どちらか一方がユニーク(ほかの人と重複しない)場合は$Yes$を出力するという問題です。

方針としては、ハッシュマップを用意し、すべての苗字と名前を一つのハッシュマップに登録しておきます。
その後、$N$人の苗字と名前それぞれについて、ユニークかどうか調べ、全員に対して成り立つかどうかを検証します。

:::note warn
注意点(コーナーケース)
苗字==名前のケース!!
3
tanaka tarou
suzuki jirou
kondou kondou
上記のようなケースでは、
kondouさんのあだ名はkondouでもいいはずですが
ハッシュマップ上ではmp[kondou]=2
という風に重複があるとみなされてしまいます
:::

```cpp
#include<bits/stdc++.h>
using namespace std;

int main(){
    int N; cin >> N;
    vector<vector<string>> S(N,vector<string>(2));
    unordered_map<string,int> mp;

    for(int i = 0; i < N; i++){
        string x,y; cin >> x >> y;
        S[i][0] = x; S[i][1] = y;
        mp[x]++;
        mp[y]++;

        //以下の一文が必要
        if(x==y) mp[x]--;
    }

    for(int i = 0; i < N; i++){
        if(mp[S[i][0]] != 1 and mp[S[i][1]] != 1){
            cout << "No" << endl;
            return 0;
        }
    }

    cout << "Yes" << endl;
    return 0;
}

```

# おわりに
他にもWAだけど一見どこが間違ってるのかわからないような問題に遭遇しましたら本記事に追加していく予定です。
間違いや質問等ありましたらご遠慮なくコメントください。
Postmanに入門する


## Postmanとは

Postmanは、API開発のためのテストツールで、APIリクエストを簡単に作成、テスト、デバッグすることができます。Postmanは、APIエンドポイントへのリクエストを手動で送信するだけでなく、自動化されたテストスイートを作成することもできます。

## Postmanは有償ツールですか？

Postmanは、基本的な機能が無料で利用できますが、高度な機能やエンタープライズレベルの機能を使用する場合は、有料のプランが必要になります。

無料のプランでは、APIリクエストの作成、送信、テスト、デバッグ、環境変数の管理などの基本的な機能が利用できます。有料プランには、APIのモニタリング、自動化されたテストスイートの作成、共同作業のためのチーム機能、アナリティクス、セキュリティなどの高度な機能が含まれています。

https://www.postman.com/pricing/


## Postmanの基本的な使い方
Postmanでは4階層構成になっています。
```
ワークスペース
   Lコレクション
      Lフォルダ（ランコレクション）
        Lリクエスト
```
ワークスペースはチーム間で共有したい単位で分割することが可能です。
フォルダはなくても構いませんが、フォルダ単位でAPIリクエストの同時実行が可能です。そのため、同時実行する単位でAPIリクエストをフォルダ分けしておくと良いです。
[Blender]Snapが上手くできないときのコツ

# 概要
Blenderで頂点同士をくっつけたい時はSnap機能を使いますが、普段使い慣れていないと上手くくっつけられなかったりします（←自分）

:::note info
これはギズモを使った移動では問題は起こりませんが、Gキーで移動させる場合だけ起こりうる事です
:::

![スクリーンショット 2024-01-05 073436.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/8519f218-85f2-ad7c-195a-23ed8c6d28e1.png)

# コツ
:x:頂点を移動先の頂点に引っ付けようとすると上手くいきません
:o:頂点の移動を開始したら「マウスポインタ」を移動先の頂点に合わせる。これで上手くいくと思います！

:::note info
別の言い方をすると、移動させる頂点は見ちゃだめで、マウスポインタだけを見て移動させる感じです
:::
canvasを使ってみる

## この記事の目的
canvasの基本的な使い方をマスターする。

## canvasとは
canvasとは、HTML5から使えるようになった、グラフィックやアニメーションを描画することができる機能です。

## 使い方
### １. HTMLのbody要素内にcanvas要素を用意する
~~~index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <!-- 中略 -->
        <script src="canvas.js" defer></script>
    </head>
    <body>
        <canvas id="my-canvas" width="1000" height="800">
            ここに代替コンテンツを記述します
        </canvas>
    </body>
</html>
~~~

::: note info
**代替コンテンツとは**
canvasに対応していない古いブラウザやJavaScriptが無効なブラウザで、canvasの代わりに表示されるコンテンツのことです。canvasが問題なく表示できる場合は代替コンテンツは無視されます。
:::

### ２. 描画コンテキストを取得する
JavaScript コード内で HTMLCanvasElement.getContext() を呼び出して描画コンテキストを取得し、キャンバス上に描画を開始します。
~~~canvas.js
const myCanvas = document.querySelector('#my-canvas');
const ctx = myCanvas.getContext('2d');   // 描画Contextを取得
ctx.fillStyle = "green";                // 塗りつぶしの色を設定
ctx.fillRect(10, 10, 100, 100);         // 座標(10, 10)に横100px縦100pxの長方形を描画
~~~

また、画像を描画したい場合は以下のようなコードになります。
~~~canvas.js
const myCanvas = document.querySelector('#my-canvas');
const ctx = myCanvas.getContext('2d');   // 描画Contextを取得

const img = new Image(); // imageオブジェクトを新規作成
img.src = '表示したい画像のパス';
const x = 100; // x座標
const y = 150; // y座標
const width = 200; // 画像の横幅
const height = 200; // 画像の縦幅
ctx.drawImage(img, x, y, width, height);   // 画像を描画
~~~

以上になります。
canvasの使い方をもっと詳しく知りたい方は下記リンクからどうぞ。

参考：

https://developer.mozilla.org/ja/docs/Web/API/Canvas_API/Tutorial
2023のAmazon購入履歴をEDAする


# はじめに
Amazonでの書籍の購買履歴をインプットに、ChatGPTでデータハンドリングを試してみます。



## データインプット

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/7f1e19ab-e66b-b3ed-27b6-d871d8722f93.png)


さらに、分析の方向性も提案してくれます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/e66a695a-c6e6-7dd0-4821-3fd2697b53f2.png)


## 前処理

はじめにデータの前処理を行ってもらいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/bf7a3cc5-a5ae-94cb-3786-df0798d1e0c6.png)

エラーを起こしながらも、それを含めて対処してくれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/772f6022-a701-2446-b9db-ec375dc8f878.png)

``` python

# Remove any potential quotes from the date column
data['注文日'] = data['注文日'].str.replace('"', '')

# Retry converting 注文日 to datetime
data['注文日'] = pd.to_datetime(data['注文日'], format='%Y/%m/%d', errors='coerce')

# Re-extract month, week, and day of week
data['月'] = data['注文日'].dt.month
data['週'] = data['注文日'].dt.isocalendar().week
data['曜日'] = data['注文日'].dt.day_name()

# Re-display the modified dataframe
data.head()

```
サンプルで内容を見てみましょう。


``` python

# Display the first 5 rows of the updated dataframe
data.head(5)

```

## 基礎統計の確認

- 年間の合計: 390,167円　/ 185冊
- 月の平均:32,514円 / 約15.42冊
- 1週間平均:7,503円 / 約3.56冊

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/977b5fd5-42d5-45f2-0413-354911dec131.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/13c907c4-252d-f624-7fd7-e3666cb2cfb7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/33f796fe-192e-ee2d-cadf-294e350f9961.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/fbe55855-dbc4-ba08-331e-a4424bda9e79.png)
プラグインするだけ - Aiven＆テンポラル

<font color="Grey">*[Just plug it in - Aiven & Temporal](https://aiven.io/blog/just-plug-it-in-aiven-and-temporal)の翻訳です。*</font>

2022年1月28日

#プラグを差し込むだけ - Aiven＆テンポラリー

Temporalはマイクロサービスのオーケストレーションプラットフォームを、Aivenはデータインフラを提供します。なぜこの2つが互いにぴったりなのか、その理由をお読みください！

ワークフローをコードとして管理するために[Temporal](https://temporal.io/)のマイクロサービス・オーケストレーション・プラットフォームを選択したわけですが、データの永続性をどのように防弾すればよいのでしょうか？


Aivenにお任せください！


Aivenは、Postgres、MySQL、Apache Cassandra、OpenSearch、M3などのデータインフラを管理することに特化しており、お客様はTemporalのビジネスワークフローに集中することができます。もちろん、マネージドデータベースインフラの選択肢がないわけではありません。


## Aivenはデータインフラを管理します


Aivenは、オープンソースコードの整合性を維持したフルマネージドクラウドサービス（Postgres、Apache Cassandra、Apache Kafkaなど）を提供しています。Aivenプラットフォームでは、顧客は複数のクラウドやリージョンにまたがるAivenサービスを作成するための無数のオプションがあります。


Aivenは、業界をリードする99.99%という一貫したアップタイムSLAでサービスを提供しており、過去36ヶ月間、5 9のアップタイムに近い値を観測している。Aivenの主要な差別化要因は、新しいバージョンやメンテナンス・アップデートが利用可能になると、ダウンタイムなしで適用されるという事実であり、これはサービスのアップグレードやダウングレードにも適用されます。


Aivenにとって、これらはフルマネージド・サービスとして当然のことであり、市場の他のサービスにはないものです。


Aivenのことはもういい。私たちは退屈なことを、そして上手にこなします。


## Temporalはマイクロサービスをオーケストレーションする


Temporalの（とても素晴らしい！）オープンソースのマイクロサービスオーケストレーションプラットフォームは、最新のワークフローアプリケーションを構築するために使用される。すでにStripe、Netflix、Coinbaseなどで採用されている。


Temporalを実行するには、まずTemporal Serverをセットアップして、コードとして書かれたビジネスルールである*ワークフロー*と、外部システム（ftp、ファイルシステム、REST APIなど）とやりとりするためのカプセル化されたコードである*アクティビティ*を実行する。ワークフローもアクティビティも、状態、永続性、再試行ロジックが組み込まれているため、開発者が管理しやすい。


ワークフローの永続性はAivenが優れている点です：Temporalでは、状態を永続的に保存するために複数のデータベースを接続することができ、Temporalを最大限に活用することに集中できます。Temporal自体のように、[PostgreSQL](https://aiven.io/postgresql)、[MySQL](https://aiven.io/mysql)、[Apache Cassandra](https://aiven.io/cassandra)のデータベースは100%オープンソースです。さらに、ロギング、モニタリング、可視化は[OpenSearch](https://aiven.io/opensearch)、[Prometheus (Aiven for M3)[](https://aiven.io/m3)、[Grafana](https://aiven.io/grafana)などのサービスに任せることができる。


これらはすべてAivenで利用できる。すべてのサービスを一つ屋根の下で調達し、同じAiven Terraformプロバイダーで完全に管理できることを考えると、TemporalとAivenは実質的にお互いのために作られたようなものだ！


## Temporal をAivenにプラグインする


[AivenのコードリポジトリTemporalIO](https://github.com/aiven/aiven-examples/tree/master/solutions/temporalio)には、Temporal ServerをAivenの様々なサービスに接続する方法の例があります：Cassandra、PostgreSQL、MySQL、Opensearchです。Temporalが提供するサンプルコードをご覧ください。


![AivenとTemporal](https://cdn.sanity.io/images/sczeoy4w/production/5e10496a7208d3e640c03d0f5759256bec347b76-2500x2500.png?q=80&fit=min&auto=format&dpr=1.5 "TemporalサービスをAivenとどのように組み合わせられるかを示すネットワーク図。上部にはTemporalのボックスがあり、中にはFrontend Service、Matching Service、History Service、Worker Serviceと書かれた4つのボックスがあります。データベースオプションのボックス（Postgres、MySQL、Cassandra）は、双方向の矢印で上のボックスに接続され、メトリクス/オブザーバビリティ（M3/Prometheus、Grafana）のボックスには、Temporalボックスから矢印が入力され、ログのボックス（OpenSearch）には、Temporalボックスへ向かう矢印がある。）


TemporalのプラガブルデータベースインフラストラクチャとAivenがすべてのサポートデータベースを提供するという追加ボーナスにより、エンジニアのスキルセットや、異なるTemporalワークフローのユースケースのベンチマークに合わせてデータベースを素早く切り替えることができます。CassandraとMySQLとPostgresの比較や、M3とGrafanaの統合についてなど、今後のブログにご期待ください。


## まとめ


まだAivenのサービスをご利用でない方は、<https://console.aiven.io/signup>から無料トライアルにお申し込みください！


それまでは、[changelog](https://aiven.io/changelog)と[blog](https://aiven.io/blog)のRSSフィード、または[LinkedIn](https://www.linkedin.com/company/aiven/)と[Twitter](https://twitter.com/aiven_io)のアカウントをフォローして、製品や機能関連の最新情報をご確認ください。
URL の en-us を ja-jp に、  ja-jp を en-us に置換するブックマークレット

つくりました。


https://qiita.com/e99h2121/items/b33866a517212fb1d7a9

```javascript
javascript:(function() { 
  var url = location.href; 
  var replacedUrl = url.replace(/en-us/gi, 'temp-value'); 
  replacedUrl = replacedUrl.replace(/ja-jp/gi, 'en-us'); 
  replacedUrl = replacedUrl.replace(/temp-value/gi, 'ja-jp'); 
  location.href = replacedUrl; 
})();
```


![la2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/616cb584-efcc-f572-dce3-574726280d15.gif)


## 参考

https://qiita.com/kanaxx/items/63debe502aacd73c3cb8
B - Pentagon をElixirで解いた〜トヨタ自動車プログラミングコンテスト2023#8（AtCoder Beginner Contest 333）

トヨタ自動車プログラミングコンテスト2023#8（AtCoder Beginner Contest 333）のB - PentagonをElixirで解いたので報告します．

## 問題

https://atcoder.jp/contests/abc333/tasks/abc333_b

## 最終的な解答例

https://atcoder.jp/contests/abc333/submissions/48688631

```elixir
defmodule Main do
  def main() do
    s = read_edge() |> r() |> l() |> t()
    t = read_edge() |> r() |> l() |> t()
    
    if s == t do
      IO.puts("Yes")
    else
      IO.puts("No")
    end
  end
  
  def read_edge() do
    IO.read(:line)
    |> String.trim()
    |> String.to_charlist()
    |> Enum.map(fn
      ?A -> 1
      ?B -> 2
      ?C -> 3
      ?D -> 4
      ?E -> 5
    end)
  end

  def r([a, b]) when a <= b, do: [a, b]
  def r([a, b]), do: [a, b + 5]

  def l([a, b]), do: b - a

  def t(a) when a <= 2, do: a
  def t(a), do: 5 - a
end
```

まずElixirの初学者にとって難しいのが，文字列`"AB"`のような辺の情報をどのように扱うかです．よくあるAtCoderの問題のように空白文字で区切られていないので，いつも使うような[`String.split/3`](https://hexdocs.pm/elixir/1.16.0/String.html#split/3)を使えないという問題があります．Elixirでこの問題を解こうとした時に，辺の情報を扱う方法がわからなかったのではないかなと思います．

この解答例では，[`String.to_charlist/1`](https://hexdocs.pm/elixir/1.16.0/String.html#to_charlist/1)をまず使います．この関数名，初学者にとって`charlist`って何？というところだと思います．`charlist`というのは，文字列`"AB"`を，整数のリスト形式に変換したものです．

この整数値は文字をコード化したものになります．また，Elixirでは文字`A`をコード化したものを`?A`と表記します．これを利用して，[`Enum.map/2`](https://hexdocs.pm/elixir/1.16.0/Enum.html#map/2)で，文字`A`を1に，文字`B`を2に，というように変換します．

関数`Main.read_edge/0`は，標準入力から1行読み込み，末尾の改行を取り除き，前述の処理を行うことで，文字列`"AB"`があったら`[1, 2]`のように変換します．

```elixir
  def read_edge() do
    IO.read(:line)
    |> String.trim()
    |> String.to_charlist()
    |> Enum.map(fn
      ?A -> 1
      ?B -> 2
      ?C -> 3
      ?D -> 4
      ?E -> 5
    end)
  end
```

次に，関数`Main.r/1`ですが，`if`を使って書き直すと次のようになります．

```elixir
  def r([a, b]) do
    if a <= b do
      [a, b]
    else
      [a, b + 5]
    end
  end
```

すなわち，引数`[a, b]`があったときに，もし`a`が`b`以下である場合には，そのまま返し，`a`が`b`より大きい時には，`b`に5を加える補正をします．こうすることで，`[a, b]`があったときに，必ず`a <= b`が成立するように変換します．

Elixirでは，このような条件分岐を関数パターンマッチという機能で，数学の場合分けのような感じで，簡潔に書くことができます．また，`do ... end` が1行のみの時には，`, do: ...` のように書けます．

```elixir
  def r([a, b]) when a <= b, do: [a, b]
  def r([a, b]), do: [a, b + 5]
```

慣れると，このような表現は，とても簡潔で，読みやすいと受け止められるようになります．

関数`Main.l/1`は，単純に`[a, b]`があったときに`b - a`を返します．

```elixir
  def l([a, b]), do: b - a
```

ここまで処理すると，`1, 2, 3, 4`のいずれかの値になります．それぞれに対応する辺の長さは`1, 2, 2, 1`となります．関数`Main.t/1`は，このような変換を行うために，引数`a`が2以下の時はそのまま返し，`a`が2より大きい時には`5 - a`を返します．

```elixir
  def t(a) when a <= 2, do: a
  def t(a), do: 5 - a
```

関数`Main.main/0`では，ここまでの処理をパイプラインで一気に行います．その後，値を比較して等しければ`Yes`等しくなければ`No`を標準出力に表示します．

```elixir
  def main() do
    s = read_edge() |> r() |> l() |> t()
    t = read_edge() |> r() |> l() |> t()
    
    if s == t do
      IO.puts("Yes")
    else
      IO.puts("No")
    end
  end
```