OmniAICreator/Qiita-1.07M huggingface dataset:
AWS認定機械学習スペシャリティ学習方法　AWS Certified Machine Learning - Specialty（MLS-C01）


AWS認定機械学習についてきちんと勉強したい方向けに書きました。
主に私が調べた予想出題範囲と機械学習のラーニングパスについてまとめています。
まとめたラーニングパスの使い方も載せていますので参考になれば幸いです。

※私自身が試験を受けるのは本記事を投稿した翌日になります。
（本来は受験後に検証結果として記事を書きたかったのですが都合が合いませんでした。合格していましたら以下で合格報告します）

合格してたか？「合格してました！記事で書いてることもまちがってないです！」

### 2023年時点でのAWS認定機械学習予想出題範囲

私が公式シラバス、Qiitaや個人ブログ、Udemy講座など様々な所から集めた情報をまとめました。

- 機械学習について（70％）
   ・機械学習アルゴリズムの特徴
   ・特徴量エンジニアリング
   ・モデルの最適化について
- AWS SageMakerやAIサービスについて（20％）
- AWSソリューションアーキテクトアソシエイトレベルの知識（10％）

主に機械学習の知識を問われる試験です。

機械学習の知識をもとにSageMakerでの実装方法を問われます。
しかしこの2つは独立したカテゴリではなく関連しています。
ですので前者、もしくは後者のどちらか一方を理解していない状態での合格は難しいと思われます。

AWS公式の試験範囲を参照しても、機械学習について多く問われることが書かれています。
``` 
推奨される AWS の知識
受験対象者は、以下の AWS の知識を有している必要があります。
• 基本的な機械学習アルゴリズムの背後にある直感的知識を表現する能力
• 基本的なハイパーパラメータ最適化の実行に関する経験
• 機械学習および深層学習のフレームワークに関する経験
• モデルトレーニングのベストプラクティスに従う能力
• デプロイのベストプラクティスに従う機能
• 運用上のベストプラクティスに従う能力
```

というかシラバスに書いてある内容、全部重要ですので見ておきましょう。
https://d1.awsstatic.com/ja_JP/training-and-certification/docs-ml/AWS-Certified-Machine-Learning-Specialty_Exam-Guide.pdf

### AWS認定機械学習のオススメ教材

AWS試験対策本シリーズには残念ながらまだ機械学習シリーズはありません。
しかし機械学習について真っ当に勉強を行えば合格を狙える試験だと考えられます。

以下の3冊とUdemyの講座を1つ、加えて公式のExam Redinessとサンプル問題をやるといいでしょう。

①深層学習教科書 ディープラーニング G検定(ジェネラリスト)公式テキスト 第2版
https://amzn.to/3t35f9P

この本の４−６章をやることで、基本的な機械学習の知識を仕入れる事ができます。

②ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
https://amzn.to/487yuac

①の本だと国語的な理解にとどまると思います。
この本で具体的な実装の理解を得ましょう。
シグモイド関数とかソフトマックスとかその他色々について、つまりなんなのさ？というところは実装を通してでしか理解できないはずです。
AWS認定機械学習で問われる機械学習の知識を正確に得ることができます。

余裕があればゼロから作るDeep Learning ❷ ―自然言語処理編もオススメします。
自然言語処理に関する知識もテストでは出題が考えられるからです。

③AWS Certified Machine Learning Specialty 2023 - Hands On!
https://www.udemy.com/course/aws-machine-learning/

超有名なAWS講座です。
boxなどの有名企業もこの講座で勉強しており、
講座の作成者はAWS Hero（超少数のAWS界隈のすごい人）として認定されているので講座の質は抜群に良いです。
https://aws.amazon.com/jp/blogs/news/announcing-the-newest-aws-heroes-august-2020/

ソリューションアーキテクトアソシエイトの知識を持っているなら、
Modeling Part1-4とMachine Learning Implementation and Operationsの5パートを重点的に学習してください。

①ー②では試験対策として不足していた知識を追加できます。
事前に①ー②を読んでからの方が頭に入っていくはずですので③番目に紹介しました。

機械学習に関する基本的な知識があるならこの講座から初めて良いでしょう。

おまけとして高校数学をこの機会に学び直したい方には以下の書籍がオススメです。
https://amzn.to/46PI5l3

### どの程度まで深掘りするか

目安として記載いたします。

・機械学習アルゴリズムの特徴
単に何に使うかくらいの理解だけでは不十分（似たようなアルゴリズムが多い）。
例えば分類でも顧客分類と画像分類では全然違う。
分類だけで覚えていると間違うはず。
構造化データを用いるか、非構造化データを用いるのか？
アルゴリズムの一般的なユースケースは何か？
これくらいは知っておきたい。

・特徴量エンジニアリング
L1, L2正規化など。
特徴量を操作してモデルのトレーニング精度を上げていく仕組みを知っておく。

・モデルの最適化について
トレーニング後の最適化について知っておくこと。
正解率、適合率、再現率、F値などを見て、どの尺度を用いてどう改善していくかがわかる。
過学習について原則的な対処ができる。
勾配降下法について知っていて対策ができる。

これ＋Sage MakerとAIサービスに関する知識が求められますので、機械学習未経験者がきちんと学ぼうと思うと相当な勉強量が求められます。

私自身は一時期機械学習をやろうと思い少しだけ知識がありましたが、それでも１ヶ月近くインプットに使っています。

結果的に面白かったですが、高額な受験料もあり相当ストレスを抱えながら勉強しておりました。


### 一言まとめ

機械学習ちゃんと理解しないと受からん。

以上

ありがとうございました。
アドベントカレンダーはいいぞ

:::note info
この記事はLITALICO Engineers Advent Calendar 2023 カレンダー2 の 8日目の記事です
:::

# アドベントカレンダーの何が良いのか

* 所属組織からすると対外的なアピールになるのでいいぞ
* 所属組織外の人からすると、勉強になったり、組織の雰囲気を掴めていいぞ
* アドベントカレンダーを書いてる人にとってもいいぞ
    * この記事ではこの書いている人にとっていいぞを掘り下げます

## 情報を整理する力を養えること

### 情報を整理する力とは何か

エンジニアに求められるものは様々ですが、その中の一つに情報を整理する力があります
情報を整理する力とは、例えば、インプットであれば情報の中のノイズを取り除いで自分の中に落とし込むことだったり、アウトプットであれば周りの人に対して自分の持っている情報を的確に伝えるために必要になってくる力のことで、エンジニアにとって、非常に重要な力となります

### 情報を整理する力が何故エンジニアにとって重要か

インプットの情報を整理する力に関しては、効率的に情報を吸収するために重要となります。エンジニアをやっていると、常に新しい情報に接する機会があり、それらの新しい情報を効率的に吸収していかないといけません。

アウトプットの情報を整理する力に関しては、多くの場合、チーム開発をしているはずで、チーム開発のためには自分の持っている情報を的確に伝える必要があります。ここがうまくいかないと認識齟齬を起こしてしまい、チーム開発の効率が悪くなってしまいます。また、エンジニア以外の方とコミュニケーションする上でも、それぞれの方に対して的確に情報を伝えていく必要がありますよね。

### 情報を整理する力を養うにはどうすれば良いか

インプットにしろ、アウトプットにしろ、全体像を捉えたり、情報を構造化する癖をつけることで、情報を整理する力を養うことは可能です。普段の業務の中で意識的に取り組まれている方もいるかと思いますが、個人的にはアドベントカレンダーを書くということは情報を整理する力を養うのに最適だと考えています。

何故ならば、普段接している方以外に向けて情報のやり取りを行う必要があるからです。普段接している方と情報のやり取りをする場合、意識していても、情報の構造化が甘かったり、全体像を捉えきれていない場合があります。これは、それらをしっかりしなくても、お互いに共通理解を得ている部分があったり、自身の状況を理解いただいているため、情報のやり取りが成立するためです。

それに対し、アドベントカレンダーを書くという形であれば、参考情報にしろ、自身が書く記事にしろ、普段接していない方との情報のやり取りを意識せざるをえず、より情報を整理することに注力するはずです。結果、アドベントカレンダーを書けば書くほど、その方の情報を整理する力は養われることになります。これは、LTへのスピーカーとしての参加でも同じことが言えますね。LTもいいぞ。

## 自ら課題を選定し、解決策を検討する経験ができること

### 社会人として良い成果を出すということ

私も社会人になってから気づいたのですが、社会人として良い成果を出すのは、学校の成績で良い成果を出すのとは全く別の要素があります。それは、学校の成績の場合は、課題を学校の先生が設定して、その設定された課題に対し良い解決策を提示できるかを見ているに対し、社会人としてでは、課題の設定から自身で行う必要があるということです。自ら設定した課題に対して、自身がどういった解決策を提示可能であるのか、また、その課題を解決した際に、どれくらいの成果があるのかを考えるのは初めてではなかなか上手くいかず、社会人として良い成果を出すのはかなり大変です。

それぞれの組織や役割にもよりますが、普段の業務の中で、課題の設定をする機会は割と限定されていると思いませんか。特に課題の設定に慣れていない新人やメンバーの方ほど、その機会が少なくのではないでしょうか。社会の中で自身が実現したいことを、自らの力で実現するためにも、課題を選定し、解決策を検討する必要は多いです。ただ、多くの場合、その経験を積むための役割を任せてもらうためには、そういった課題解決の実績を示していく必要があり、少ないチャンスをものにしていく必要があるかと思います。

### アドベントカレンダーを書くということは

その方の置かれている状況に寄らず、自ら課題を選定し、解決策を検討する経験を積むためにはどうしたら良いか。そう、私たちにはアドベントカレンダーがあるではないですか。アドベントカレンダーの記事に書くネタを見つけることは、自ら課題を選定することと同じです。広く世の中に発信し評価されるネタを考えるのは、世の中にある課題のうち、どういったものであれば、自身が解決策としての記事を書けるのか、これは正しく前述の課題を選定し解決策を提案、良い成果を出すと同じ思考ですよね。


また、組織にも寄ると思いますが、多くの場合、アドベントカレンダーというのは制約が少ないのではないでしょうか。実際に、私が所属している[LITALICOのアドベントカレンダー](https://qiita.com/advent-calendar/2023/litalico)も制約が少ないため実に多種多様な記事が書かれています。実際の業務の中では様々な制約があることで、余計に課題を見つけ解決策を提案し良い成果を出すという一連のステップが難しくなることが多いです。それに対し、アドベントカレンダーを書くという制約が少ない状況であれば、より成功体験を掴みやすいと言えます。

アドベントカレンダーはお祭り感もあって、普段の業務と比較すると、失敗のリスクは低いというのも魅力的です。リスクなく、誰でも経験を積むチャンスを掴みやすいわけですから、どんどんアドベントカレンダーを書いて、社会人として良い成果を出すための経験を積んでいきましょう。

# 最後に

アドベントカレンダーはいいぞ
いっぱいアドベントカレンダーを書くことが可能なLITALICOもいいぞ
数値と文字列の不等式

# 不等式
シンプルな事ですが、
数値の不等式と文字列不等式は結果が異なります。
当たり前のように聞こえますが、
基準が異なるために起こります。

数値の場合は数値同士の差分による結果
文字列の場合はUnicodeに沿ったポイントの差（unicode上の並び順というイメージ）

# 例
数値
9<10 結果 true

文字列
"9" < "10" 結果 false

これは9より1の方がunicodeのポイントが小さい為。
※さらに細かい理由は分かったら追記します。
OpenChain Japan Work Group - FAQサブグループの紹介

## はじめに
OpenChain Japan Work Group の島です。今年の2月からFAQサブグループのリーダを拝命しております（しかしちゃんとリードできているのかは不安あり…😢）。好きなライセンスは The Beer-ware License🍺 です。

毎年恒例アドベントカレンダーということで、FAQサブグループの活動を紹介がてらに棚卸ししようと思います。

## OpenChain Japan Work Group - FAQサブグループとは
OSSのライセンスに関するよくあるand/orありがちな誤解を解消し正しい理解を提供するための（主にOSSライセンス初心者🔰向けの）FAQ集「[**OSSライセンス関連でよくある誤解FAQ**](https://github.com/OpenChain-Project/OpenChain-JWG/tree/master/Education_Material/FAQ "OSSライセンス関連でよくある誤解FAQ")」を作成、公開することを主な活動としているグループです。普段、自社の業務などでOSSライセンス遵守に関わる参加メンバーが実際に受けた質問や、ライセンス文を読んでいて疑問に思ったこと、その他、一般的によく質問されそうなことをメンバー間で侃侃諤諤意見を交わしてQA化し、これをまとめてFAQ集として公開するということを行っています。

[QA成果物の一例]
![IMG_0352.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539510/452ab036-efdc-3068-790f-31e6d209ebdd.jpeg)


今年はFAQとして検討するネタを一時的に切らしてしまうことがあり、~~一時しのぎで~~  **「FAQとして公開できるようなフラットな結論を導き出せるかどうかは定かではないが、ライセンスや著作権法の理解を深めることはできそう」「細かすぎてFAQとして需要があるかどうか微妙なところだが、興味としてその細かな部分の適切な解釈が気になる」** というような、やや重箱の隅をつつく感のある疑問を検討してみるということも行ってきました。（ライセンスや著作権法を正しく理解することでライセンスを遵守しOSSや著作権を尊重する…というのが基本姿勢であって、決してライセンス違反にならないギリギリや隙間を模索するためではないということを申し添えておきます。）

結果としてやはり広く一般に公開できるQAという形にまとめることはできませんでしたが、議論に参加したメンバーの中では理解を深めることに繋げられたと思っています。

## FAQ集の品質について自己評価
かれこれ何年もOSSライセンスの相談に受けてきたエキスパートな方、かたやこれから社内でOSSライセンスに関する管理や統制等を行う必要性に駆られている方、、技術者の方やリーガルの方、、サプライチェーンの上流下流など…振り幅の広いさまざまなプロパティの方が集まっており、また多くの目でチェックしているため、（少なくとも私が自社内で同じことをやろうとする場合よりも）非常に均質でかつ解釈誤りの少ないFAQ集が作れていると思います。

## 今後に向けて
やはりトレンド的にAI関連のQAを検討したいなぁと考えています。ただおそらく結論めいたものを出すのは難しいと思っているので、情報ソースを集めて整理してメンバー間で議論、学習する形になるのではないかなという感じでしょうか。

また、いわゆるOSD(Open Source Definition)からは外れるライセンスも増えてきているので、このあたりも整理、議論してみたいなと考えています。

## English Summary
We have been discussing the finer points of licensing this year as well as FAQ material.
In the future (although I don't think we can reach a conclusion), we would like to organize and discuss topics related to AI and copyright and conduct activities to deepen understanding among participants.
【PM・エンジニア向け】消費型アイテム・コインでのiOSサブスクリプション実装時の注意

## ■はじめに
私はコンテンツ系アプリのプロダクトマネージャーとして、消費型コインやアイテムを基にしたサブスクリプション機能の実装に取り組んできました。この記事は同様の機能を実装しようと考えているPMやエンジニア向けに、Q&A形式で記載します。なお、各所情報は私の**2023年9月時**、iOS向けの実装経験を元にしています。Apple社による仕様変更で詳細が変わる可能性がありますのでご了承ください。

※この記事でサブスクと呼ぶものはiOSの「自動更新サブスクリプション」機能を指します。

## ■消費型のサブスク vs 無制限アクセスのサブスク
NetflixやHuluのような月額固定で無制限アクセスを提供するサブスクと異なり、ここで述べるサブスクは**都度支払いを行い、アプリ内通貨をコンテンツ消費に使用する形式**を指します。このモデルは、ゲーム、マンガ、ライブ配信などの従量課金を含むサービスに適しています。


## ■Q＆A
### 【Q1】 iOSサブスクリプションの「ランク」「レベル」とは何ですか？
App Store Connectでサブスクリプションを設定する際、各プランに「レベル（level）」をつける必要があります。iOS側では「レベル」の数字の大小を基準として、ダウン/アップ/クロスグレードの処理がされます。同じ文脈で「ランク（rank)」という言葉が使用されるケースもありますが、考え方は「レベル」と同様です。

:::note info
**Case Study**
・レベル1のプラン→レベル2のプランに契約更新=「ダウングレード」で処理
・レベル2プラン→レベル1に契約更新=「アップグレード」で処理
・同一レベルで設定したプランに切り替え＝「クロスグレード」で処理

＜参考記事＞
https://www.revenuecat.com/blog/engineering/ios-subscription-groups-explained/
:::

### 【Q2】iOSサブスクリプションの「グループ」とは何ですか？
App Store Connectでサブスクリプションを設定する際、「グループ」の設定が必要です。iOS developerの多くは「1年経過後の純収益率が85%」を狙って実装するケースがほとんどだと思います。グループ設定の仕方により、継続月数の「カウント」に影響が出ますのでお気をつけください。

:::note info

**Case Study**
・同じグループ内でのプラン変更：apple上の課金継続月のカウントはkeepされる
・違うグループへのプラン変更（複数のグループを設定）：apple上の課金継続月のカウントは0から再スタート

→「1年経過後の純収益率が85%」をよりスムーズに達成させるには、「グループは1つのみ」設定するのがベター
:::


### 【Q3】 ダウングレード、アップグレード、クロスグレードで注意すべき点は何ですか？
消費型コインのサブスクの場合、developerが目指す挙動としては「ユーザーがサブスクを契約→アイテム/コインを配布→ユーザーがアイテム/コインでアプリ内コンテンツを購入」だと思います。
この際、特に難しいのが「ダウングレード」「クロスグレード」「アップグレード」の取り扱いです。APPディペロッパー側がこの仕様をきちんと理解しない場合、意図しない「返金処理（ビジネス的には損失）」が生まれる可能性があるためご注意ください。

:::note warn
**Bad Case**
ユーザーにコインを配布し、コンテンツ購入でコイン消費される
→グレード処理で払い戻しが実行される
→developerがユーザーに現金の払い戻しをすることによって、コインの払い損が発生する

※グレード処理を理解しないまま設定すると上記のようなマイナスケースが発生します
:::

:::note info
**Case Study**
①ダウングレード
	-現在契約しているプランAが終わった後に、プランBが適用される
		-例：8/1〜8/31はプランAを契約済み、8/15にプランBに切り替え処理→プランA終了後の9/1からプランBに切り替わる
-プラン期間後に新プランが適用されるため、**返金処理は特になし**
　
②アップグレード
	-現在のプランが継続中でも、プラン変更の決済後に即時でプランが切り替わる
		-例：8/1〜8/31はプランAを契約済み、8/15にプランBの決済完了→即時でプランBに切り替わる、プランBの契約タームは8/15~9/14で取り扱われる
	-変更の決済適用時を基準に、**プランAの返金処理が行われる**

③クロスグレード
	-現在の契約プランが続いていても、変更の決済タイミングから即時で変わる
 -例：8/1〜8/31はプランAを契約済み、8/15にプランBの決済完了→即時でプランBに切り替わる、プランBの契約タームは8/15~9/14で取り扱われる
  	-**アップグレードと実質的に同じ返金処理が行われる**
:::



:::note info
**消費型コインのサブスクが目指すべき方向性**
・App Store Connectでは「1month」「1year」といった形で、どの頻度でプランを更新させるかの期間（duration)を指定できる
・「同じ期間（duration）」での課金軸は「1つ」のみとする

＜Goodな例＞
・月間1000円プラン
・年間9800円プラン
で実装。この場合は同じ期間/duration（月間、年間）で課金軸は1つずつのみなので、グレードによる「返金処理」に悩まされない。
:::

:::note alert
**改めて注意**
・同じ期間/dutationで複数の課金帯を用意する場合、現状のapple仕様では「返金処理」は避けられません。
・一部アプリではこの「返金処理」を許容として実装している例もありますが、オススメしません。
・グレードによる切り替えはappleの仕様上ユーザー側で無制限で実行できます。つまり「返金処理」も実質無制限で行わなければならないため、abusingとしてdeveloper側の運用リスクが高まります。
:::


## ■参考記事
・自動更新サブスクリプション（Apple社、iOSの公式記事）
 https://developer.apple.com/jp/app-store/subscriptions/#offering-subscriptions

 ・subtype（Apple社、iOSの公式記事）
https://developer.apple.com/documentation/appstoreservernotifications/subtype

・iOS Subscription Groups Explained
 https://www.revenuecat.com/blog/engineering/ios-subscription-groups-explained/

 ・iOS Subscription upgrades, downgrades, and service levels
 https://qonversion.io/blog/ios-subscription-upgrades-downgrades-and-service-levels/
シームレスプロジェクトを振り返ってみた

みなさんこんにちは、kitakです。
2023年も一ヶ月を切りました。特に今年は１年すぎるのが早かったなぁと感じてます。
また、個人としてもとても楽しい一年を過ごすことができました！

今年は、自分が１年以上ずっとメンバーとして動いていたとあるプロジェクトについて知見・教訓などを書いていきたいと思います。

私自身ディレクター職であるため、今回はテックテックした話にはなりませんが見て頂けますと幸いです。

## シームレスプロジェクトについて
このプロジェクトの中では、[@cosme](https://www.cosme.net/)に掲載する商品を登録・掲載するためのツールの改修を主に行ってきました。商品情報が網羅されていて、タイムリーにユーザーに届けることを目的としていることからシームレスプロジェクトという名称で動いてきました。

[@cosme](https://www.cosme.net/)に商品が掲載される流れとして、ブランドの方が掲載したい商品を申請し、申請された商品を登録作業者の方が精査・申請情報を確認した上でページ上に掲載される流れとなっています。

しかし、商品を掲載していく中で以下のような課題も発生しました。

・ブランド担当者が商品を一括で申請できない
・商品登録の進捗状況が伺えない
・登録作業を行う上での管理ツールが多岐に渡り、登録作業者の方が手動で登録せざるをえない状態だった
・新商品の情報掲載に時間がかかってしまった

そこで、上記の課題を改善し、より使っていただけるようなサービスを目指すことを目的に動いたのが本プロジェクトになります。

## 作ったもの
今回プロジェクトの中で作ったものは大きく以下の2つになります。
・掲載商品申請ツール(ブランド担当者の方が使用するツール)　※既存のツールを1から刷新
・商品登録作業ツール(商品登録作業者の方が使用するツール) ※新規ツールとして今回作成

### 掲載商品申請ツール
・[@cosme](https://www.cosme.net/)に商品の掲載を行うブランド担当者が使用するツールになります。
・掲載したい商品の新規申請、掲載商品の修正・廃盤申請等の商品管理が行えます。
・登録しているメーカー名、ブランド名の変更申請も行えます。
・申請した商品の進捗状況を確認することができるようになりました。　
・一括で掲載する商品の申請を行うことができるようになりました。

### 商品登録作業ツール
・掲載商品申請ツールで申請があったものの登録作業を行うツールになります。
・申請ごとに商品の登録・修正・廃盤、メーカー名・ブランド名の修正を行うことができます。
・商品登録作業ツールの中で掲載申請→登録も行うことができます。

## 学んだ知見・教訓
今回プロジェクトを動かした事で得られた知見・教訓をトピックごとにまとめました。
企画→仕様検討→開発→テスト→リリースまで1年半かかった長期プロジェクトとなりました。
長期でプロジェクトを動かす上での参考になれば幸いです。

### 既存仕様の把握・確認
problem:
・既存仕様の把握が曖昧だったことで仕様検討に時間を要してしまった。
・どの機能を入れるべきか、本当に適切であるべきかの判断をすることが最初難しかった。
try:
・なぜ現時点でこの仕様になっているのか、現状不足している箇所はどこか、
　改善できそうな部分はどこかなど課題を細分化してみる
・使用者が実際に使用するところをイメージしてみる

### 仕様書の作成
problem:
・複数人で役割分担をして作業を行っていた→他の人が作成したものと合わせて矛盾がないか、辻褄が合うものになっているかは念入りに行うべきだった。
・作成できたものから開発側とレビューを行なっていたが、都度レビュー頂く場合でも
　一度作成したものも含め通しで説明を頂かないとわからない箇所が多かった。
try:
・仕様書作成前に必要な要素は洗い出してFIXさせる。
・作成する画面・システムとの繋がりを意識する。関連する機能ごとにレビュー頂けるように
　レビューする順番は適切に決めておく。

### 仕様追加・更新等の管理
problem:
・作成した仕様の数が膨大なものになってしまい、以前までの差分などがわかりづらくなってしまったものがあった。
・仕様の量が膨大であったため、更新の反映に時間がかかってしまった。
・資料の履歴管理・反映箇所の管理など、開発側とのコミュニケーションが不足していた。
try:
・差分を記載する管理シートは必須。
・どこか、いつ、何を更新したかの記載は分かりやすくする。
・開発側が見落としてしまう、あるいは企画側で共有漏れなどが発生しないよう
　コミュニケーションを行った上でどこまで開発側と確認できているかを管理する項目をシートの中で用意する。


### 手戻りを発生しないために
problem:
・動作確認テスト・サービステストを行った際に追加要件を依頼してしまった。
→早急に対応が必要なバグの場合可能だが、仕様を大幅に変える要望を出すタイミングとしては不適切
try:
・手戻りをなくすために画面イメージから話すのではなく、必要な要素単位で洗い出し、既存画面との整合性、システム的な観点、事業部側の要望などを踏まえたものとして表示要件をFIX→その後画面イメージを作成する形の段取りにする。
・どういう判断にしたのかの記載は残す。
・仕様を設計後、上記要件を踏まえたポイントが抑えられているかチェックシートなどを用意する。


 ### コミュニケーションコストをかけないために
 problem:
・仕様や要望、課題・バグ管理などの工程においてコミュニケーションコストがかかってしまった。
・細かい確認を行っていく際、終盤のコミュニケーションで開発側に負荷がかかってしまった。
 try:
・当初は事業部側でも部署ごとに開発側とのコミュニケーションを分けていた。
→要求・要望の仕様策定を行った上で事業部側まとめて仕様の展開・共有を開発側と行うことで
　確認する際もその場で行うことができ、コミュニケーションコストを大幅に短縮することができた。
・実施タイミング・順番等の温度感ははじめに伝える。
・どれくらいの期間が必要かテストがいつ実施できるかの共有・確認はかかさず行う。

### 良かったこと・まとめ
・規模の大きいもの、長期に渡ってかかるプロジェクト管理ならでわの大変さを体験することができた。

・仕様の検討や変更など、企画側と開発側が密に議論しあって最終的な形として起こすことができた。

・1年半と長期に渡って思い描いてきたサービスを形に起こしたことで大きな達成感を得られた。

・ブランド担当者や登録作業者をはじめ、多くの人達が抱えている課題を解決することができた。

### さいごに
今回1からプロダクトをリニューアルしたため、かなり規模の大きいものになりました。
どのように動かなければならないか、何を準備しなければならないか、起こりうる問題は何かなどを考える良い経験になったと思います。

今後また大きなプロダクト・サービスを作ることにに携わる場合に今回のような教訓を活かしたいなと思います！

そして、個人的にもとてもやりがいを感じたプロジェクトであり、考えたものが形となって動いたことで大きな喜びも感じました。

技術よりの話ではありませんでしたが、最後まで読んでいただきありがとうございました。
みなさん良い年末をお過ごしください。以上、kitakでした。
App Distributionの開発環境にプッシュが届かない問題（xcargsを使う）

実機ビルドではプッシュが届くのにApp Distributionの開発環境からインストールしたアプリではプッシュが届かないという問題に直面しました。
App Distributionで確認出来ないとエンジニア以外の方がプッシュのテストを行えずデバッグ効率が非常に悪くなった為、原因の調査と解決を行いましたのでご紹介します。

## プッシュ関連の設定状況まとめ
・プッシュ証明書
⇒同じ証明書を使用（Sandbox & Production）

・Amazon SNSのプラットフォームアプリケーション設定
開発環境用：Apple iOS (開発環境)
本番環境用：Apple iOS (本番環境)

・App Distribution
開発環境：プッシュ届く
本番環境：プッシュ届かない

:::note warn
まとめ
・プッシュ証明書は同じものを使ってるので問題なし。
・Amazon SNS・App Distributionどちらかに問題がある。
:::

## 問題の原因調査
■Amazon SNSとApp Distributionどっちに問題があるのかを調べるための検証
Amazon SNS（本番環境）のプッシュならApp Distributionの開発環境に届くのか？

以下の状態でプッシュが届くか確認
・Amazon SNS：本番環境（プラットフォームアプリケーションをテスト用に新しく作成）
・App Distribution：開発環境のアプリ
⇒プッシュは届いた　

:::note warn
まとめ
・プッシュ自体は届くのでApp Distributionは問題なし。
・Amazon SNSの開発環境に問題あり。
App Distributionにプッシュを送るには、Amazon SNSは本番環境ではならない。
→開発環境でも実機ビルド・App Distributionで環境を分ける必要がある。

:::

## 対応方法
### ■Amazon SNSのプラットフォームアプリケーション設定
App Distributionの開発環境用にAmazon SNS(本番環境)のプラットフォームアプリケーションを新しく追加する。

開発環境用：Apple iOS (開発環境)　
本番環境用：Apple iOS (本番環境)
　　　　　↓↓
開発環境用（実機ビルド）：Apple iOS (開発環境)
**開発環境用（App Distributionの開発環境）：Apple iOS (本番環境)**
本番環境用：Apple iOS (本番環境)

:::note warn
開発環境用だけど、SNSの環境違いのものが出来る。（実機ビルドとApp Distribution）
なので、実機ビルドなのかApp Distributionを判別できるフラグ持たせる必要がある。
:::

### ■開発側の設定
フラグを持たせる為にxcargsを使う。
![スクリーンショット 2023-12-07 14.29.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370083/b5348357-f7e8-7318-0e42-ff33f3337612.png)
https://docs.fastlane.tools/actions/build_app/


### xcargsの導入方法
■Xcode（実機ビルド側の設定）
User-DefinedにXcargsで使う値を追加（今回は、IS_PUBLISH）
値は、0で指定（実機ビルドの時の値）
![スクリーンショット 2023-12-07 14.19.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370083/e844ea05-ea93-51bf-9cf8-ac74f473ab02.png)

■fastfile（App Distribution側の設定）
build_appにxcargsのパラメータを追加。
値は、1で指定（App Distribution時の値）
```ruby
    build_app(
      xcargs: "IS_PUBLISH=1", ##App Distributionでアプリを開いた場合、値を1にする。
    )
```

これで実機ビルドとApp Distributionで値を分けることができました。


あとは分けられたxcargsの値を使って、#if DEBUG（開発）の中でさらに開発環境（実機ビルド）か本番環境（App Distribution）で分岐を作ります。
こうする事で万が一にも、テストなのに一般ユーザーにもプッシュが届いてしまう心配はなくなります。
```swift
    private var environment: String {
        #if DEBUG
        guard let isPublish = Bundle.main.object(forInfoDictionaryKey: "IS_PUBLISH") as? String else {
            return "product"
        }
        
        if isPublish == "1" {
            return "product" //App Distribution開発環境
        } else {
            return "sandbox" //実機ビルド
        }
        #else
        return "product" //本番環境
        #endif
    }
```
これで実機ビルドとApp Distributionでプッシュ通知を分けることにはなりますが
安全性もを考慮しつつ、App Distributionの開発環境でもプッシュが届くようになりました。
産休明けの職場復帰について

こんにちは、NGUYEN THI LINH（鈴木りん）です。
私はコウェル在籍中に産休/育休を取得し、3年ぶりに職場復帰しました。

久々の復帰を楽しみに思う気持ちもありましたが、たくさんの不安を抱えながらのチャレンジでした。
実際に体験してみて心境の変化がたくさんありましたので、そちらを纏めてみました。
# 復帰前の気持ち
たくさんの不安を抱えていた中で、主に下記のように挙げられます。
慣らし保育はどう対応するのか
子供に寂しい思いをさせてしまうのではないか
新しいポジションできちんと仕事できるか。職場復帰ができるかどうか
保育園の送迎や病児の対応ができるか。遅刻早退や欠勤などで職場に迷惑をかけないか

# 復帰後の気持ち
復帰後の気持ちは大きく入れ替わりました！！！
上記のような不安もだいぶいい方向に状況が変わっていました。


### 1. 慣らし保育はどう対応するのか
復帰直後というタイミングで同時に慣らし保育が始まりました。
期間は2週間ですが、幸いこの期間はおじいちゃんおばあちゃんが面倒を見てくれたおかげで、無事に慣らし保育を終了しました。

慣らし保育期間終了後は、夫婦で話し合って、保育園のそれぞれの送迎担当とスケジュールをしっかり取り組んで行っていました。
全ての不安を解消できたわけではありませんが、毎日話し合っていく中で、少しずつ慣れていけたらと思います。


### 2. 子供に寂しい思いをさせてしまうのではないかとの不安が意外な展開に…
長男と次男が保育園に慣れてきたようで、保育園生活をとっても喜んでいます。
なんと熱が出ても保育園に行けないと言ったら、号泣して「どうしても行きたい！」と言われ困っていたこともありました。
一歳になったばかりの長女も慣らし保育期間に「まったく泣かず、おもちゃで遊んでいる」と言われたときに、なんか複雑な気分になりました！


### 3. 新しいポジションできちんと仕事できるか。職場復帰ができるかどうか
職場復帰を楽しみに感じる一方で「私にできるのか、今の生活環境と両立できるのか」などの不安もありました。

配属後は、幸せなことに所属部門の中で「先生」と呼ばれるほどの教育プロフェッショナルな方のチームに参画できて、とても運がよかったと感じました。まったく仕事の不安を解消できました。
ちなみに、働いているチームは、バングラデシュ人、韓国人、日本人、ベトナム人(私)混声のグローバルチームです。
みんなで流暢な日本語で会話して、仕事もスムーズにできています。
休憩時間に、たまに自分の国のことも教えてくれています。
バングラデシュのテツルテイーや韓国のVtalk（ブイトーク）ピンクエイドをいつか飲んでみたいです！
ということで、とても楽しい職場なんです。


### 4. 保育園の送迎や病児の対応ができるか。遅刻早退や欠勤などで職場に迷惑をかけないか
慣らし保育期間に次男がずっと高熱、咳などの症状があったため、保育園に預けられず、自宅で過ごしていました。
この期間はおじいちゃんおばあちゃんが毎日きてくれて面倒を見てくれたので、最初の一か月を乗り越えられました。
その後は夫婦で勤務時間を書き出して、毎日の送迎スケジュールを立ててそれに沿って動いていきますので、ここからが正念場です。
ただ、エンジニアのお仕事は前職の事務に比べて仕事のスケジュールを柔軟にコントロールしやすいと感じています。
今のところは子供の送迎時間や体調を見て調整できており、とても感謝しています。

## さいごに
もちろん、大変なこともあり不安は続きますが、
実際に復職してみてわかったポジティブなこともたくさんありました。

「今の職場や仕事内容なら前向きに続けられる」と感じており、一か月前の復帰前に心配していた自分に伝えてあげたいです。


復帰を躊躇して悩んでいる方は、もう一歩踏み出してみてはいかがでしょうか。
【C言語】Cコンパイラを作ってみた

Cコンパイラを自作した話です。

コンパイラってどんなもの？ということから、コンパイラの仕組みを簡単に説明していきたいと思います。

# コンパイラについて知るメリット

コンパイラには情報学のすべてが詰め込まれています。

（eg.ソフトウェア、ハードウェア、機械語、オートマトン）

そのため、コンパイラを作らなければ、始まらない！みたいな人もいるみたいです。。

普段プログラミングをしている際には、低レイヤの仕組みなどは意識することはないと思います。知らない人から見ればブラックボックス化していますね。

コンパイラを知ることで、その中身がどうなっているかを知ることができます。

箱があったら開けてみたいという精神で、好奇心で勉強していきましょう。


# コンパイラとは?

人が書いたプログラムを機械がわかるようにする翻訳機のような役割を果たすものです。

今回作るものは、C言語のコンパイラで、C言語のソースコードからアセンブリコードを吐き出すものとなります。

# C言語とアセンブリコード

## アセンブリプログラムとは
アセンブリ言語とは、機械語に近いプログラミング言語です。

ストレートに機械語へ翻訳でき、実行速度が速いという特徴もあります。

## AST(抽象構文木)について
理論的には、有限なラベル付き有向木である。また、演算子と変数や定数といったオペランドから成る数式などのようなものに対する抽象構文木を例にすると、分枝点は演算子、葉はオペランド（つまり、変数や定数）である。

コンパイラやインタプリタといったプログラミング言語処理系の場合は、中間表現のひとつであり、一部の最適化は抽象構文木の上の操作などによっておこなわれる。

引用（[抽象構文木](https://ja.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E6%A7%8B%E6%96%87%E6%9C%A8 "ウィキペディア")）


## Cコンパイラによる出力　（足し算編）
実際にCコンパイラが出力するアセンブリコードを見てみましょう。

例として次のC言語で記述されたプログラムを考えます。
```test.c
int printf ();
int i;

int main ()
{
    i = 2 + 3;                 // ここに対応するアセンブリコードを紹介します
    printf ("%d\n", i);
}
```

この足し算の部分をASTで表すと、
```
. . . . AST_expression_assign
. . . . . AST_expression_id
. . . . . . AST_IDENTIFIER
. . . . . AST_expression_add
. . . . . . AST_expression_int
. . . . . . AST_expression_int
```
これを図解します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622324/0a9277ba-106f-af2f-0377-bb3ac263a066.png)
木構造になっており、"="の子ノードが2つ存在し、左辺値と右辺値を評価する。それをさらにたどっていくという仕組みです。


このプログラムの足し算に対応するアセンブリプログラムは以下となります。
````
	pushq	$2
	pushq	$3
	popq	%rcx
	popq	%rax
	addq	%rcx,	%rax
	pushq	%rax
````


※大域変数の準備、関数の呼び出しなどその他の部分は省略しています。

## Cコンパイラのソースコード

ここではさらにクローズアップして、
「i = 2 + 3」のなかの「2 + 3」の部分に注目します。

```codegen.c
// 足し算
static void codegen_expression_add (struct AST *ast)
{
  assert (!strcmp (ast->ast_type, "AST_expression_add"));

  for (int i = 0; i < ast->num_child; i++) {
    visit_AST (ast->child[i]);
  }

  emit_code (ast, "\tpopq\t%%rcx\n");
  emit_code (ast, "\tpopq\t%%rax\n");
  emit_code (ast, "\taddq\t%%rcx,\t%%rax\n");
  emit_code (ast, "\tpushq\t%%rax\n");
  frame_height -= 8;

}
```
上記のコードが足し算のアセンブリコード吐き出すコードです。

visit_AST ();　という関数がASTをたどる関数です。それをたどったとき、AST_expression_addというノードにたどり着いたとき、上記の関数である、codegen_expression_add()が実行されます。

関数中の始めにあるfor文を用いて、現在のASTのすべての子ノードをたどります。ここでは、"+"の子ノードとして、intである"2", "3"を評価します。

その下のemit_code ()関数で、アセンブリコードを出力します。

最後にフレームハイトの調整をします。
レジスタにpopを2回、pushが1回でスタックにraxが積まれたため、合計でフレームハイトを8減らします。

## 最後に


普段見えないところを知れて面白かったです。

コンパイラの仕組みを理解できれば、自作のプログラミング言語も目指すこともできるので、勉強していこうと思います。
vscode-leetcodeにCookieでログインする

LeetCodeの問題をVSCodeで解きたいと思い、
VScodeのプラグイン「vscode-leetcode」をインストールしました。

下記の情報を参考にして環境構築を行い、一度ログインできましたが、
セッションが切れた後に再度ログインする際詰まってしまったので、
参考にさせていただいた記事の整理と備忘メモを記載します。

# 環境構築
* 参考にさせていただいた記事
vscode-leetcode で快適 LeetCode 生活
https://zenn.dev/ryo_kawamata/articles/introduce-vscode-leetcode
LeetCodeをVS CodeとGoで解くための環境づくり
https://zenn.dev/sadah/articles/ede353e39c0500
Use VSCode LeetCode extension
https://zenn.dev/nyancat/scraps/caa9f3029e3ab9

# ~/.lc/leetcode/user.jsonの設定
1. ChromeブラウザでLeetCodeにログイン
2. 開発者ツールのApplicationタブからCookieの情報を確認する
3. “csrftoken”, “LEETCODE_SESSION”のValueをメモ
4. ~/.lc/leetcode/user.jsonにメモした値を入力する

```
{
  "login": "[username]",
  "loginCSRF": "",
  "sessionCSRF": "[copied from csrftoken]",
  "sessionId": "[copied from LEETCODE_SESSION]"
}
```

* こちらの記事を参考にさせていただきました。
vscodeでleetcodeに入門しようと思ってハマった話（と回避策）
https://qiita.com/aiuecohei/items/42ec2d78712c576040fa

# 「vscode-leetcode」にCookieでログインする
1. ChromeブラウザでLeetCodeにログイン
2. どこでも良いので、ブラウザのLeetCodeのページをクリックする
2. 検証ツールのNetworkタブを開いてリクエストを選択し、Request Headersの属性を確認する
3. Cookieの値をコピーする(“Cookie: “ の文字列は除く)
4. VS Codeを開き、拡張機能LeetCodeを開く
5. Cookieでログインするオプションを選択
6. ユーザー名とコピーしておいたCookieの値を入力する

* こちらの記事の「Log in with the cookie」の章を参考にさせていただきました。
https://betterprogramming.pub/work-on-leetcode-problems-in-vs-code-5fedf1a06ca1
CapacitorでLive Updateできるようにする3つの方法

https://qiita.com/rdlabo/items/d98014fefe3f59f18009

で紹介したように、Google Playの新しい個人アカウントのルール下において、Live Updateは大きな存在感をみせるようになりました。また、それ以外でも、審査を受けることなくネットワーク経由にWebアセットを更新できるのは、不具合を見逃して配信してしまったアプリをすばやく修正するための方法であり、これによりユーザの離脱などを防ぐことができます。

~~ちなみに私は過去、課金アカウントでしかテストをしていなかったため、無料ユーザはメイン機能が使うことができない不具合をだしたままアプリをリリースしたことがあります。まじでユーザ離れました。~~

Live Updateはとても有用な手段ですが、アプリを配信する前にLive Updateの設定をアプリに仕込んでおく必要がある点が重要です。不具合をだしてからLive Updateを設定しようと思ったら、審査を受ける必要があり本末転倒なので、Live Updateは転ばぬ先の杖として __念のために__ まず設定することがおすすめです。

それでは、Live Updateを設定できるメジャーな3つの方法をみていきます。

# 1. Appflow

Ionicの公式サービスです。Live Updateの仕組みだけではなく、アプリストアへのデプロイや、デプロイ前のWebでのなど様々な機能が揃っています。

https://ionic.io/appflow

各種機能をみていると、CapacitorやCordova、React Nativeの開発を支えるプラットフォームという感じで、CI/CDだけではなく、これを利用することで開発者体験を一段向上を目指してるところがあります。ただ、様々な機能があるだけに、「Live Updateだけをみた時の金額」は少し高めに設定されています。

| フリープラン | Communityプラン | Basicプラン | Enterpriseプラン |
|:-:|:-:|:-:|:-:|
| 100ユーザ | 500ユーザ | 4,500ユーザ | Custom |
| 無料  | 月49ドル | 月499ドル | Custom |

ユーザ数は月毎なので、実際のところは月間アクティブユーザ相当になるかと思います。私は今のところ、これが手厚いのでフリープランで設定しておいて、大きなトラブルがあった時にいつでも上位プランにトラブルがあった当月だけ移行するようにしています。


# 2. Capgo

ロンドンのDigital Shift OU社が提供するCapacitorのLive Updateツールです。

https://capgo.app/

AppFlowと比べてLive Updateの機能だけをもっているだけ比較的安価ですので、まずは通常サービスの利用を検討してみてはいかがでしょうか。プランは以下の通りです。

| フリープラン | SOLOプラン | MAKERプラン | TEAMプラン |
|:-:|:-:|:-:|:-:|
| 250回 | 2,500回 | 25,000回 | 150,000回 |
| 250ユーザ | 2,500ユーザ | 25,000ユーザ | 150,000ユーザ |
| 無料  | 月14ドル | 月39ドル | 月99ドル |

料金体系が違い、Live Updateの数か、アクティブユーザの数かの多い方が適用されます。


# 3. 自己ホストする

とは言っても、Live Updateは、アプリ起動時にzipファイルをみにいって、現在のバージョンと異なればそれを現在のWebアセットのフォルダと入れ替えるだけです。これらのサービスを使うと、以下を自分でハンドリングする必要がなくなりますが、自分で実装することも可能です。

- アップデートの有無の確認
- 自動復帰
- アップデートに失敗した時のメール警告
- チャンネルの設定
- 更新の統計
- ダウンロード失敗時の更新

例えば上記で紹介したCapgoは100%OSSを謳っており、すべてのコードが公開されています。サービスとして自動化されている部分を以下のように自分で設定することで自己ホストが可能です。

```js
import { CapacitorUpdater } from '@capgo/capacitor-updater'
import { SplashScreen } from '@capacitor/splash-screen'
import { App } from '@capacitor/app'
let data = {version: ""}
CapacitorUpdater.notifyAppReady()
App.addListener('appStateChange', async(state) => {
     if (state.isActive) {
       // Do the download during user active app time to prevent failed download
       data = await CapacitorUpdater.download({
       version: '0.0.4',
       url: 'https://github.com/Cap-go/demo-app/releases/download/0.0.4/dist.zip',
       })
     }
     if (!state.isActive && data.version !== "") {
       // Do the switch when user leave app
       SplashScreen.show()
       try {
         await CapacitorUpdater.set(data)
       } catch (err) {
         console.log(err)
         SplashScreen.hide() // in case the set fail, otherwise the new app will have to hide it
       }
     }
 })
```

https://capgo.app/docs/self-hosted/manual/

更新頻度による話にはなりますが、軽微でもいいので毎日のアプリ更新を目指しているようなところは、サービスを使うとコストパフォーマンスが見合わない可能性が高いので、こういったのを自作することを検討するといいかと思います。

それではまた。
Re:Earthでよく使うものメモ

## Re:Earthでよく使うものメモ
私が個人的によく使うものをメモ用に残しておきます

### クリックした箇所にマーカーを追加する
```
reearth.on("click", (data) => {
  reearth.layers.add({
    extensionId: "marker",
    isVisible: true,
    title: "マーカー",
    property: {
      default: {
        location: {
          lat: data.lat,
          lng: data.lng,
        },
      },
    },
    tags: [],
  });
});
```

### レイヤーを検索する
```
reearth.layers.add({
  extensionId: "marker",
  isVisible: true,
  title: "東京スカイツリー",
  property: {
    default: {
      location: {
        lat: 35.71018463504105,
        lng: 139.81071112590806,
      },
    },
  },
  tags: [],
});

const marker = reearth.layers.find(
    layer => layer.type === "marker" && layer.title === "東京スカイツリー"
);

console.log(marker.id)
```

### フォームで入力した緯度経度の位置にマーカーを表示する
```
const html = `
    <style>
      body {
            margin: 0;
            padding: 10px;
            background-color: #fff;
        }
    </style>
    <div>
      <label for="latitude">緯度:</label>
      <input type="text" id="latitude" placeholder="例: 35.6895" required>
      <br>
      <label for="longitude">経度:</label>
      <input type="text" id="longitude" placeholder="例: 139.6917" required>
      <br>
      <button onclick="addMarker()">マーカーを追加</button>
    </div>
    <script>
      function addMarker() {
        var latitude = document.getElementById('latitude').value;
        var longitude = document.getElementById('longitude').value;
        parent.postMessage({ type: "addMarker", lat: latitude, lng: longitude }, "*");
      }
`;
reearth.ui.show(html);

reearth.on("message", (msg) => {
  if (msg.type === "addMarker") {
    reearth.layers.add({
    extensionId: "marker",
    isVisible: true,
    title: "マーカー",
    property: {
      default: {
        location: {
          lat: msg.lat,
          lng: msg.lng,
        },
      },
    },
    tags: [],
  });
  }
});
```

### CZMLファイルを追加する
```
const czml_data = [
  // 任意のczmlデータ
];

reearth.layers.add({
  id: "czml",
  extensionId: "resource",
  type: "resource",
  isVisible: true,
  title: "CZML",
  property: {
    default: {
      url: czml_data,
      type: "czml",
      clampToGround: true,
    },
  },
});
```
Bunの実行可能ファイルを作ってみた

Bunも実行可能ファイルを作ることができます。こんな感じです。

```sh: compile する
$ bun build ./hello.ts --compile
```

これで、hello.ts ファイルから hello という実行可能ファイルが生成できます。

--compile をつけて bun build するだけです。

ユーザーが Bun をインストールしていなくても、アプリを実行可能ファイルとして単一のファイルで配布できるわけで便利ですね。まぁ、Node.jsでも v19.7 から実装されていますが、ランタイム一体のアプリという感じでしょうか。



```sh:出力ファイル名を指定して compile する
$ bun build ./hello.js --compile --outfile myhello
```
--outfile ＜ファイル名＞ をつけると、hello.ts ファイルから myhello といった名前を指定して実行可能ファイルが生成できます。

前後しますが、今回はファイルの中身をこれにします。
```js:hello.ts や hello.js
console.log('Hello Bun')
```

本家の Document はここにあります。

<b>Bun > Executables</b>

https://bun.sh/docs/bundler/executables

リリースノートによれば、--minify オプションをつけることで、アプリの起動パフォーマンスを向上させることもできるようです。

今回はサンプルサイズが小さかったので比較はできていませんが、--minify 実行サンプルを置いておきます。
https://bun.sh/blog/bun-v0.6.0#standalone-executables
```sh:--minifyをつけて compile する
$ bun build ./hello.js --minify --compile --outfile minihello
```

注意したいのは、別のディレクトリやマシンへ、たとえば cp や rsync などで属性コピーもすれば大丈夫ですが、メールやFTP、WinSCPなどで配布したなどしたときなどに、もし実行権限をコピーしていなければ実行権限追加が必要です。

```sh:配布後、もし実行権限が無ければ実行権限を追加する
$ chmod u+x hello
```
実行は「./」をつけて次のようにします。

```sh:実行する
$ ./hello 
```
```sh:結果
$ Hello Bun
```
動きましたね。


# 最近 Qiita に書いた Bun 関連の記事10選

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

https://qiita.com/toshirot/items/74476af27e67d8534c5a

https://qiita.com/toshirot/items/94961b6dde72be80ab0c

https://qiita.com/toshirot/items/7a0555b46b3a64a4f643

https://qiita.com/toshirot/items/c4d090bc38f9b85d8cdd

https://qiita.com/toshirot/items/4e8e571dd50a45c651f0

https://qiita.com/toshirot/items/e4eb635596ae4f63bdfd

https://qiita.com/toshirot/items/a81f2073e373b0351493

https://qiita.com/toshirot/items/06a992af8cf8aca9ff95

https://qiita.com/toshirot/items/3af83303f95ac7baa546
ObservableマクロでBindingを使う方法


booksがObservableだとします。
それで、Viewの中で、@Bindable var book = bookを使います。
すると$book.titleのようにバインディングができます。

正直違和感があるかもしれませんが、公式ドキュメントにそう記載がありますので、とりあえずいいのでしょう。


```Swift
struct LibraryView: View {
    @State private var books = [Book(), Book(), Book()]


    var body: some View {
        List(books) { book in 
            @Bindable var book = book
            TextField("Title", text: $book.title)
        }
    }
}
```

以下のページの一番下の項目に記載があります。
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app

でわ。
図解生成AI「Visually」、折れ線グラフ（β）、棒グラフ（β）機能追加！

こんにちは！インター・ラボ株式会社でございます。
図解生成AI「Visually」に新しい機能が追加されました！
その新機能である折れ線グラフ（β）、棒グラフ（β）を紹介したいと思います。

# まずは使いたい機能をON
追加機能の折れ線グラフ（β）、棒グラフ（β）はデフォルトでは表示されていないので、設定から機能をオンにします。
エディター画面の赤丸部分、歯車をクリックして設定を開きます。

![](https://storage.googleapis.com/zenn-user-upload/059894efa86b-20231129.png)
*エディター画面赤丸部分歯車をクリック*

設定を開いたら、使いたい機能を選びオンにしていきます。
今回は折れ線グラフ（β）、棒グラフ（β）をオンにしたいので、赤丸の部分をそれぞれクリックし、閉じるをクリック。これで使いたい機能がオンになりました。

![](https://storage.googleapis.com/zenn-user-upload/cccc247f74ae-20231129.png)
*使いたい機能をオン。灰色はオフ。緑色はオンになっている状態*

# 折れ線グラフ(β)
折れ線グラフは作成する場面が比較的多いグラフではないでしょうか。
Visuallyだとテキスト入力で、折れ線グラフを生成できます。
早速作ってみましょう。エディター画面で折れ線グラフ（β）を選択し、テキストを入力します。
![](https://storage.googleapis.com/zenn-user-upload/0f732c26fbac-20231129.png)
*折れ線グラフを選択*
![](https://storage.googleapis.com/zenn-user-upload/90eae5e7c986-20231129.png)
*描画したい内容を入力*
この様にテキストを入力し、生成すると…
![](https://storage.googleapis.com/zenn-user-upload/66de5ef3da29-20231129.png)
*生成された折れ線グラフ*
あっという間に折れ線グラフが生成されました！


# 棒グラフ（β）
続いて棒グラフを作成します。
エディター画面で棒グラフ（β）を選択し、テキストを入力。
![](https://storage.googleapis.com/zenn-user-upload/078d4bf8734f-20231130.png)
*棒グラフを選択*
![](https://storage.googleapis.com/zenn-user-upload/bfa2d688e318-20231130.png)
*描画したい内容を入力*
![](https://storage.googleapis.com/zenn-user-upload/7d66c6c8d596-20231130.png)
*生成された折れ線グラフ*
棒グラフも簡単に生成することができました！

# グラフの編集
Visuallyでは、Mermaidを用いているので、画像赤枠内に直接書き込むことでグラフを編集することが出来ます。
![](https://storage.googleapis.com/zenn-user-upload/2a0ff8ba6c18-20231130.png)
*編集前*
![](https://storage.googleapis.com/zenn-user-upload/60936d41425f-20231130.png)
*編集後*


”2023年の来場者数”を”2024年の来場者数予想”へと変更し、人数も変更した例です。このように、グラフ生成後でも編集が可能です。
また、前述したようにMermaidを用いているのでMermaidの記法で入力し、編集することも可能です。

# 簡単生成・編集のVisually
今回は、Visually追加機能である折れ線グラフ（β）、棒グラフ（β）について紹介しました！エクセルだと、セルに入力して、範囲選択して、グラフにして…という過程を、Visuallyだとテキスト入力だけで生成することができます。まだβ版ではありますが、十分に活用できます。
会員登録だけで無料で使えるフリープランもあるのでぜひお試しください！

https://itl-portal.com/visually/
LaTeX：siunitxの\SIコマンドで変数，数式を扱う

## \SIコマンド
siunitxパッケージを使うと値と単位を綺麗に書けるので，レポートで多用する方が多いと思います．
私は\SI{}{}を良く使います．

### 例1
使い方：\SI{数値}{単位}
```tex
\documentclass[20pt,a4paper,dvipdfmx]{jsarticle}
\usepackage{siunitx}
\begin{document}

\SI{1.0}{[m/s]}

\end{document}
```

出力結果
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531123/40015a72-61fc-49ef-5432-8e1ff3ea22bc.png">
数値と単位の間に自動で隙間が入り，単位は斜体になっておらず，体裁が綺麗です．

## 数式を入れてみる
では\SI{数値}{単位}の数値のところに，数式を入れるとどうなるでしょう．

### 例2
```tex
\documentclass[20pt,a4paper,dvipdfmx]{jsarticle}
\usepackage{siunitx}
\begin{document}

\SI{\alpha}{[m/s]}

\end{document}
```

出力結果
logファイル
<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531123/68d6fa74-0f84-942f-ade4-644191b8d7b6.png">

するとこのようにエラーが発生しました．通常の\SI{}{}では数式を扱う事が出来ません．

## 解決策
\SI{}{}で数式を扱うにはオプションで```parse-numbers=false```を入れます．
```tex
\documentclass[20pt,a4paper,dvipdfmx]{jsarticle}
\usepackage{siunitx}
\begin{document}

\SI[parse-numbers=false]{\alpha}{[m/s]}

\end{document}
```

新しいコマンドを作れば何度も簡単に使えます．
```tex
\documentclass[20pt,a4paper,dvipdfmx]{jsarticle}
\usepackage{siunitx}
\newcommand{\SIeq}[2]{\SI[parse-numbers=false]{#1}{#2}} % 新しいコマンド
\begin{document}

\SIeq{\alpha}{[m/s]}

\end{document}
```
いずれも以下のような結果が得られたと思います．
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531123/047227c9-77a1-4803-8ec8-c8a8169d804e.png">


### 例3
このように色々な数式を入れられます！
```tex
\documentclass[20pt,a4paper,dvipdfmx]{jsarticle}
\renewcommand{\baselinestretch}{1.5}
\usepackage{siunitx}
\usepackage{derivative}
\newcommand{\SIeq}[2]{\SI[parse-numbers=false]{#1}{#2}}
\begin{document}

\SIeq{\int_{x_0}^{x_1} f(x) \odif{x}}{[m/s]}

\SIeq{\frac{\sum_{i = 1}^{n} x_i}{n}}{[m/s]}

\end{document}
```

出力結果
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531123/9339aa22-c2f0-9c8d-39c6-2e1de873bb6f.png">
Vue3で子エレメントの外側を別のエレメントでラップする方法2 - 子エレメントが`v-for`で動的に渡される場合

# 導入
今日の話題は[昨日](https://qiita.com/uenosy/items/a5090e6d14076102c484)の続きで子エレメントが`v-for`で動的に渡される場合にその子エレメントの外側を別のエレメントでラップする方法についてです。

:::note info
※ 私が株式会社愛宕 Advent Calendar 2023に書く記事は主に社内向けに共有しておきたいけど勉強会をするまでもないちょっとしたTipsにしたいと思います。
:::

もう一度、目的の構造を示します。
```html
<div class="group">
  <div class="group-item">
    <div>hoge</div>
  </div>
  <div class="group-item">
    <div>fuga</div>
  </div>
  <div class="group-item">
    <div>piyo</div>
  </div>
</div>
```

そして、次のように`ExampleGroup`を使用して目的の構造が出力されるようにする方法は昨日投稿した通りです。
```vue: app.ts
<template>
  <ExampleGroup>
    <div>hoge</div>
    <div>fuga</div>
    <div>piyo</div>
  </ExampleGroup>
</template>
```

今回は、こんな感じの場合どうしたらいいかという話です。
```vue: こうとか
<template>
  <ExampleGroup>
    <div v-for="item in items">{{ item.name }}</div>
  </ExampleGroup>
</template>
```

```vue: こんなんとか
<template>
  <ExampleGroup>
    <div>hoge</div>
    <div v-for="item in items">{{ item.name }}</div>
  </ExampleGroup>
</template>
```

# 解決

`$slots.default()`から直接vnodeを取得せず一旦必要なvnodeだけを取り出し、それをもとに`<component>`で描画するようにします。

```vue
<div v-for="item in items">{{ item.name }}</div>
```
で作成したエレメントはvnodeそのものではなく`vnode.children`に含まれているのがキモです。

```vue: ExampleGroup.vue
<script setup lang="ts">
// SFCでComposition APIを使うためにscript setupを使って書いています

import { isVNode } from 'vue'

// template内で書くときの$slotsと同じ
const slots = useSlots()

const vnodes = computed(() => {
  if (!slots.default) {
    // 念の為、slotが空の場合があってもいいように
    return []
  }

  const result = []
  
  for (let vnode of slots.default()) {
    if (Array.isArray(vnode.children)) {
      // template内でv-forでループさせた各エレメントはvnode.childrenに入っている
      for (let child of vnode.children) {
        if (isVNode(child)) {
          // 念の為、vnodeがどうか確認してから描画対象に追加する
          result.push(child)
        }
      }
    } else {
      // vnodeにchildrenがない場合は普通のvnodeなのでそのまま追加
      result.push(vnode)
    }
  }
  
  return result
})

</script>

<template>
  <div class="group">
    <div class="group-item" v-for="vnode in vnodes">
      <component :is="vnode"></component>
    </div>
  </div>
</template>
```
Terraformを使用したAWS SQSとLambdaの統合

この記事では、AWSのSimple Queue Service（SQS）とLambdaをTerraformを使用して統合する方法について説明します。具体的には、SQSキューからLambda関数をトリガーする設定と、Lambda関数からSQSキューにメッセージを送信する設定に焦点を当てます。

## SQSキューからLambdaをトリガーする

### 必要なリソース

- SQSキュー
- Lambda関数
- IAMロール
- VPC設定（VPC内でLambdaを実行する場合）

### ステップバイステップ

1.SQSキューの作成

```hcl
resource "aws_sqs_queue" "example_queue" {
  name = "example-queue"
}
```

2.Lambda関数の作成

```hcl
resource "aws_lambda_function" "example_lambda" {
  function_name = "example_lambda_function"

  // VPC設定
  vpc_config {
    subnet_ids         = [aws_subnet.example_subnet.id]
    security_group_ids = [aws_security_group.lambda_sg.id]
  }
}
```

3.IAMロールの作成
```hcl
resource "aws_iam_role" "lambda_exec_role" {
  name = "lambda_exec_role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Effect = "Allow",
        Principal = {
          Service = "lambda.amazonaws.com"
        },
      },
    ],
  })
}
```

4.イベントソースマッピングの設定

```hcl
resource "aws_lambda_event_source_mapping" "example_mapping" {
  event_source_arn = aws_sqs_queue.example_queue.arn
  function_name    = aws_lambda_function.example_lambda.arn
  batch_size       = 10
}
```

## LambdaからSQSへのメッセージ送信

### Lambda関数の設定

Lambda関数がSQSキューにメッセージを送信するためのIAMロールとポリシーを設定し、Lambda関数を定義します。

```hcl
resource "aws_iam_role" "lambda_exec_role" {
  // IAMロールの設定...
}

resource "aws_iam_role_policy" "lambda_sqs_policy" {
  // IAMポリシーの設定...
}

resource "aws_lambda_function" "producer_lambda" {
  // Lambda関数の設定...
}
```

## モジュールの使用と出力

### モジュールの定義

モジュール内でリソースを定義し、必要な出力を設定します。

```hcl
# モジュール内のoutputs.tf

output "lambda_function_arn" {
  value = aws_lambda_function.example_lambda.arn
  description = "ARN of the Lambda function"
}
```

### モジュールの使用

モジュールを使用して出力を取り出します。

```hcl
module "example_module" {
  source = "./path/to/module"
}

output "module_lambda_function_arn" {
  value = module.example_module.lambda_function_arn
  description = "ARN of the Lambda function from the module"
}
```

## まとめ

この記事では、Terraformを使用してAWSのSQSとLambdaを統合する方法を紹介しました。SQSキューからLambda関数をトリガーする設定と、Lambda関数からSQSキューにメッセージを送信する設定の両方をカバーしました。
【SQL関数】SQLのCOUNT(1) ←この1ってなに?

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

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

---

## そもそもCOUNT関数とは?
ほとんどの方は知っていると思ういますが、一応説明をしておきます。
COUNT関数とは、SQLの集約関数の一つで指定したカラムのレコード数を調べる時に用いたりします。
   
## カッコの中身について
COUNTの中身が`1`だったり、`*`だったり、`カラム名`だったり
現場においてもまちまちですよね。

例を出して説明していきます

下記のようなテーブルがあった際に

**user テーブル**
| user_id  | user_name |
| :-------------:  | :-------------: |
| 1| taro|
| 2| NULL|
| 3| taro|

```sql
SELECT COUNT(*) FROM user
```

```
+----------+
| count(*) |
+----------+
|        3 |
+----------+

```

`COUNT(*)`とすることで、全体のレコード数を計算することをができます

```sql
SELECT COUNT(user_name) FROM user
```

```
+------------------+
| count(user_name) |
+------------------+
|                2 |
+------------------+

```

`COUNT(user_name)`とすることで、`user_name`がNULLの場合を除いた
レコード数を取得できます。

`COUNT(1)`の場合はどうなるでしょうか

```sql
SELECT COUNT(1) FROM user
```

```
+----------+
| count(*) |
+----------+
|        3 |
+----------+

```

重複回避の`DISTINCT`もまとめるとこんな感じ

|列名|件数|内容
|---|--:|---
COUNT(*)|3|NULL含めた件数
COUNT(user_name)|2|NULLを除いたuser_nameの件数
COUNT(DISTINCT user_name)|1|NULLを除いたuser_nameをユニークとした件数
COUNT(1)|3|NULLを含めた件数


見ての通り、`COUNT(*)`と`COUNT(1)`の実行結果が一緒になります。

### じゃあCount(1)とCount(*)何が違うの?
**COUNT(*)** はデータベースエンジンに対して「すべての列をカウントする」という指示を出します。
そのため、行の存在そのものを数えるのでNULLであってもカウント対象になります。

じゃあ`COUNT(カラム名)`は何なのかというと、指定されたカラムに有効な値がセットされているものの行数が返ります。
もっというと、**カラムがNULLじゃない**ものの行数です。

それを頭に入れて以下を見て見ましょう

**COUNT(1)**
COUNT(1) は「1という値が存在する行をカウントする」という指示になります。

```sql
select 1 from user
```
のデータ件数となり、

|1|
|---|
1|
1|
1|

のようにNULLじゃないレコードが3件のため`COUNT(*)`と`COUNT(1)`が同じ実行結果になります。

### おまけ
ここまで見てもわからない人でも人でも以下を見ればわかるはず...!

```sql
SELECT 'takashi' FROM user
SELECT COUNT('takashi') FROM user
```

| 'takashi'  | COUNT('takashi')  |
| ------------- | ------------- |
|![スクリーンショット 2023-12-06 11.01.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/57200542-a6c6-45b1-be44-6a4fcba61564.png)|![スクリーンショット 2023-12-06 11.02.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/ee0dbcb4-ef8d-4ba0-6796-b14c493d5ccc.png)| 
   
**SELECT**された3件全て、`'takashi' IS NOT NULL`の条件に当てはまるので**COUNT関数**
で出力される件数は3になります！

```sql
SELECT NULL FROM user
SELECT COUNT(NULL) FROM user
```

| NULL  | COUNT(NULL) |
| ------------- | ------------- |
|![スクリーンショット 2023-12-06 11.06.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/851d23eb-614b-605a-d068-fc76328c4ad6.png)|![スクリーンショット 2023-12-06 11.07.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/d816f656-00db-ee4b-4739-5d8c33cc5e0d.png)| 

**SELECT**された3件全て、`NULL IS NOT NULL`の条件に当てはまらないので**COUNT関数**
で出力される件数は0になります！

## おわりに
今回はCOUNT関数とその中身について、自分の備忘録も兼ねてまとめさせて頂きました。
例題もいくつか出したので視覚的にも理解できたかなと思います。

より、COUNT関数に詳しい方がいれば性能面含めて、編集リクエストやコメント頂けると嬉しいです...!



### 参考文献
https://www.dbblogger.com/post/difference-between-sql-count-count-1-count-column_name-in-sql-server

https://qiita.com/tarosuke777000/items/a2860f3d1bdae3a1965f

https://sakaik.hateblo.jp/entry/20220719/mysql_count_function_with_null
【Unity】PUN2を学習する　オブジェクト同期の仕方や初期位置の設定

この記事は、[【完走したい】楽しくいろいろやる Advent Calendar 2023](https://qiita.com/advent-calendar/2023/notbeginner)の６日目の記事です。

３日間かけて簡単なエアホッケーを作ります。２日目です。
オブジェクト、キャラの同期の仕方を学びます。
# キャラを同期させる
キャラを同期させるためには、

1.Resourcesフォルダを作成

2.用意しておいたオブジェクトを入れる（これがPrefab Assetに変換されます。）

3.ルーム作成したときにクローンが呼び出されるようにする

この３ステップが必要なようです。
# 解説
1.Create>Folderで新しいフォルダーを作る
名前を「Resources」に変えればOKみたいです。
2.用意しておいたオブジェクトを作ったフォルダに入れ込む
Hierarchyに作っておいたオブジェクトでも、どっかから持ってきたよくわからんオブジェクトでも入れば動くっぽいです。
フォルダに入れておきましょう。
3.昨日書いたスクリプト（サーバー接続、ルーム作成）を書き換える
ルームに入った時点でInstantiate(オブジェクトの生成)が呼ばれるようにします。
今回はホッケーの操作するやつ（Cube）が生成されるようにします。
Resourcesに入れておいたものであれば生成できるっぽいです。
<b>public override void OnJoinedRoom()</b>に以下を追加します。
```
  PhotonNetwork.Instantiate("Cube", new Vector3(0,0,0), Quaternion.identity);
```
後、Photon Transform Viewなるものをくっつけておきます。
PrefabなCubeにAdd Componentから足しておきます。
これでオブジェクトを同期できました。
# プレーヤーの位置を調整する
今、プレーヤーは全員初めに(0,0,0)の位置に来るようになっています。しかし、今回はエアホッケーなので、自分は下側、相手は上側に来なければなりません。
図）
![2023図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961125/47e41eb8-d63d-e6a6-480c-1cec2632cfec.png)

ということで、プレイヤーごとにPrefabなcubeが生成される場所を変えます。
プレイヤーは、ルームに入ると１から順番に数字が割り振られます。
photonView.OwnerActorNrに自身の数字が入っています。
しかし、ルームに入ってオブジェクトが生成されるときに変更できませんでした。
そこで、新しく別のスクリプトを作り、
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
public class TFControll : MonoBehaviourPunCallbacks
{
    // Start is called before the first frame update
    void Start()
    {
        if (photonView.IsMine)
        {
            if (photonView.OwnerActorNr == 1)
            {
                this.gameObject.transform.position = new Vector3(0, 4, 0);
            }
            else
            {
                this.gameObject.transform.position = new Vector3(0, -4, 0);
            }

        }

    }
    // Update is called once per frame
    void Update()
    {
        
    }

}
```
オブジェクトが生成された後にこのスクリプトを読み込んだ段階で位置を移動させます。
こんな感じで、void startの段階で自身のプレイヤーIDに応じて位置を変化させました。
画像はとってなかったけど、ちゃんと動きました。
# キーボードの矢印キーで移動ができるようにする
↑上のスクリプトのUpdate()に、以下のコードを追加しました。
```
if (photonView.IsMine)
        {
            if (Input.GetKey(KeyCode.LeftArrow))
            {
                this.transform.Translate(-0.1f, 0.0f, 0.0f);
            }

            if (Input.GetKey(KeyCode.RightArrow))
            {
                this.transform.Translate(0.1f, 0.0f, 0.0f);
            }
        }
```
相手のものまで動かさないように、IsMineを使っています。
# 参加者数を取得し、ゲームを開始する
参加者数は、'PhotonNetwork.CountOfPlayersInRooms'を用いることで調べられるそうです。
参加人数が二人になったらゲームが開始されるようにします。
参加者が二人になった時にGameStartに飛びます。
```
      if (PhotonNetwork.CountOfPlayersInRooms == 2)
        {
            GameStart();
        }

    }
    public void GameStart()
    {

    }
```

とりあえず今日はここまで
# まとめ
オブジェクト同期の仕方を学んだ
参考

https://doc-api.photonengine.com/ja-jp/pun/current/class_photon_player.html

https://www.sejuku.net/blog/52747

https://doc.photonengine.com/ja-jp/pun/current/lobby-and-matchmaking/appandlobbystats

https://zenn.dev/o8que/books/bdcb9af27bdd7d
Google colabでRecBoleを使う方法(How to use RecBole on google colab)

<h1>RecBoleとは</h1>
以下はRecBoleのgithub上の文章を引用し、修正したものです.

(RecBole: https://github.com/RUCAIBox/RecBole)

RecBoleは、研究目的のために統一された、包括的で効率的なフレームワークで推薦アルゴリズムを再現および開発するために、PythonとPyTorchをベースに開発されたPythonのライブラリの一つです。当ライブラリには、以下の4つの主要なカテゴリをカバーする91の推薦アルゴリズムが含まれています。

 1. 一般的な推薦
 2. 順序推薦
 3. コンテキスト重視推薦
 4. ナレッジベース推薦
 
43のベンチマーク推薦データセットへのサポートを提供しています。ユーザーは提供されたスクリプトを使用して元のデータの処理を行うか、単に我々のチームが処理したデータセットをダウンロードすることができます。

以下はRecBoleの概要図です.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1878133/5ccfc791-1e92-aa0a-099e-b02c1ae7fbc9.png)



<h2>使い方</h2>
今回,Google ColabでRecboleを実行するために必要なコードを記載しておきます.

```ipynb
!pip install recbole
!pip install ray
!pip install kmeans-pytorch
```

上のコードで必要なライブラリをインストールします。
インストール後は、以下のコードを実行してエラーがないかを確認してください。

```py
import argparse

from recbole.quick_start import run

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--model", "-m", type=str, default="BPR", help="name of models")
    parser.add_argument(
        "--dataset", "-d", type=str, default="ml-100k", help="name of datasets"
    )
    parser.add_argument("--config_files", type=str, default=None, help="config files")
    parser.add_argument(
        "--nproc", type=int, default=1, help="the number of process in this group"
    )
    parser.add_argument(
        "--ip", type=str, default="localhost", help="the ip of master node"
    )
    parser.add_argument(
        "--port", type=str, default="5678", help="the port of master node"
    )
    parser.add_argument(
        "--world_size", type=int, default=-1, help="total number of jobs"
    )
    parser.add_argument(
        "--group_offset",
        type=int,
        default=0,
        help="the global rank offset of this group",
    )

    args, _ = parser.parse_known_args()

    config_file_list = (
        args.config_files.strip().split(" ") if args.config_files else None
    )

    run(
        args.model,
        args.dataset,
        config_file_list=config_file_list,
        nproc=args.nproc,
        world_size=args.world_size,
        ip=args.ip,
        port=args.port,
        group_offset=args.group_offset,
    )
```

実装が上手くいく場合には、以下のように学習の記録が出力が確認できます。

![Screenshot 2023-12-07 at 14.08.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1878133/c804bb7a-6c4a-b781-a734-1f96dbbca843.png)

<h2>最後に</h2>
今回は、自身の推薦モデル構築のためにRecBoleのsetupについて記事を作りました。
これから、RecBoleの具体的な使い道を記載できたらいいなと思います。
3.selenium4以降のエラーについて


**3.selenium4以降のエラーについて**

selenium3で使用可能だった一部のメソッドについて、selenium4では警告or廃止（エラー）になるため、下記にまとめます。

・目次
3.1.警告機能
　3.1.1.executable_path
3.2.廃止機能
　3.2.1.find_element_by_～


<br>
<br>
<br>
<br>

**3.1.警告機能**
executable_path：以下発生
　TypeError: __init__() got multiple values for argument 'options'

対策：
```Python.
webdriver.Chrome(ChromeDriverManager.install(), options=options)
```

↓　selenium4.5以前
```Python.
service = Service(executable_path=ChromeDriverManager().install())
webdriver.Chrome(options=options, service=service)
```

↓　selenium4.6以降（2022/11/4　リリース）
　※自動取得に変更された
```Python.
from selenium import webdriver
driver = webdriver.Chrome()
```

<br>
<br>
<br>

**3.2.廃止機能**
find_element_by_：以下発生
　AttributeError: 'WebDriver' object has no attribute find_element_by_css_selector'

selenium4.3.0（selenium4）で廃止された機能（2021/10/13　リリース）

対策：
```Python.
browser.find_element_by_css_selector("cssselector")
browser.find_element_by_class_name("classname") 
browser.find_element_by_xpath("xpath") 
browser.find_element_by_LINK_TEXT("by_LINK_TEXT")
```

↓
```Python.
browser.find_element(By.css_selector, "cssselector")
browser.find_element(By.class_name, "classname") 
browser.find_element(By.xpath, "xpath") 
browser.find_element(By.LINK_TEXT, "by_LINK_TEXT")
```


<br>
<br>
<br>

以上！
docker compose をv2にして現時点の最新にしたら、ネットワーク設定が原因で起動しなかった話

## 以下のようにおこられました

```shell
network mynet was found but has incorrect label com.docker.compose.network set to "mynet"
```

現在のdocker composeのバージョン
```shell
$ docker compose version
Docker Compose version v2.23.3
```

## migrateしないといけないのかな

ちなみに、今回バージョンアップするまで、ubuntuリポジトリの1.29.2-1使っていました...。

このように書き換えてみる。

```yaml

# 前略...

networks:
  default:
    name: bridge
    external: true
  container-net:
    name: mynet
    
```

こう書いていたら以前は大丈夫だったのですが、docker composeのv2.19.1からは動かなくなっている模様。

```yaml

# 前略...

networks:
  default:
    name: bridge
    external: true
  container-net:
    name: mynet
    external: true
    
```

無事起動しました。
動かなくてv2.18.1にダウングレードされた方もいるようなので動いてよかった。

※参考 https://github.com/docker/compose/issues/10797

ありがとうございます。