OmniAICreator/Qiita-1.07M huggingface dataset:
Salesforce のAPIでOpportunityは取得できるのにOpportunityLineItemsが取得できない時に確認する所

# まとめ
商談商品を取得するためには価格表オブジェクトの参照権限も必要になります。
※要出典
価格表 (Pricebook2) オブジェクトの参照権限も付与しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85205/f90022dc-880f-f15b-f337-0890d1e2d01e.png)


商談レコードの取得エンドポイント
`https://example.my.salesforce.com/services/data/v61.0/sobjects/Opportunity/{opportunityId}`

商談商品レコードの取得エンドポイント
`https://example.my.salesforce.com/services/data/v61.0/sobjects/Opportunity/{opportunityId}/OpportunityLineItems`
ORACLE MASTER Silver SQL 2019 (1Z0-071) の合格体験記

私が **ORACLE MASTER Silver SQL 2019 (1Z0-071)** に合格した際の体験談をシェアします。試験勉強の進め方や活用した教材についてお話しし、これから受験を考えている方に参考となる情報を提供できればと思います。

### 使用した教材

試験対策として、私は主に以下の2つの教材を使用しました。

1. **オラクルマスター教科書 Silver SQL Oracle Database SQL**
   - この教科書をメインに使いました。試験に必要な内容が網羅されており、非常に分かりやすい構成です。私はこの教材に載っていない内容は、試験でも出題されないと判断し、教科書をしっかりと読み込みました。本番では、教科書に載っていない内容の選択肢がいくつか出ましたが、それらは正当でない可能性が高いと判断して回答を進めました。
https://amzn.asia/d/bR3Vj1K

2. **Ping-t の Silver Oracle Master Silver SQL 2019 (1Z0-071)**
   - Ping-t の模擬試験をひたすら繰り返しました。最初の頃は正答率が50％ほどでしたが、間違えた問題の解説を読み、教科書の該当部分を確認することで少しずつ精度を高めていきました。無料で500問以上を演習ができたのはとても良かったです。
https://mondai.ping-t.com/g
私の演習結果も参考に載せておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821969/676bd3a0-ec35-2082-4ec0-5c66b555853f.png)


### 学習方法と試験対策

- **オラクルマスター教科書を読み込み、Ping-tでの演習**
  - オラクルマスター教科書を徹底的に読み込み、基礎を固めた後、Ping-t の模擬試験に取り組みました。Ping-t の問題は実際の試験形式に近く、実戦的な対策として最適です。

- **間違えた問題の徹底分析**
  - 模擬試験では最初、50％前後の正答率でしたが、ミスした問題は必ず解説を読み、教科書に戻って確認することで知識を固めていきました。

### 試験本番の感想
試験当日は、120分間のテストでしたが、80分ほどで全ての問題を解き終えました。Ping-t の模擬試験も60〜70分程度で解けていたので、特に時間配分を気にせず、試験に臨めました。結果は8割で合格でした！！嬉しい笑

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821969/955de470-c0f0-761d-2c0d-c2a5ed145a89.png)



### その他情報
  - 試験の代金は事前にチケットを購入し、そのチケットで支払いをする方が、ポイント分だけお得かと思います！
https://item.rakuten.co.jp/it-test/137327/

  - 試験を受ける際に、Oracleのアカウントやパスワードの準備等が必要かどうかが分からず、直前でバタバタしたのですが、不要でした。身分証明書を2つ（私は運転免許証と健康保険証）持っていくことをお忘れなく！

### まとめ

試験に向けた勉強のポイントは、「オラクルマスター教科書 Silver SQL Oracle Database SQL」で基礎を固め、Ping-t の模擬試験を繰り返すことです。間違えた問題をしっかり分析し、理解を深めることで、試験本番も自信を持って臨めるようになります。

皆さんも、自分のペースで学習を進め、合格を目指してください。応援しています！
パーティション機能について：データベース整理整頓術

# パーティション機能について：データベース整理整頓術
こんにちは、データベース愛好家の皆さん！株式会社アシストエンジニアリングのエンジニアのsawasatoです！今日は、データベースを整頓するための秘密兵器「パーティション機能」についてお話しします。これを知っていると、あなたのデータベース生活がグンと楽になりますよ！
# パーティション機能って何？
まずは基本から。「パーティション」って聞くと、オフィスの仕切りを思い浮かべるかもしれませんが、データベースの世界でも同じような考え方です。オラクルのパーティション機能は、テーブルを小さな「区画」（パーティション）に分割することで、データの管理をしやすくする仕組みです。
想像してみてください。あなたのデータベースが巨大なクローゼットだとします。パーティションは、そのクローゼットを「季節別の服」「仕事用の服」「カジュアルウェア」などに分けるようなものです。これで、探したいデータがどこにあるか、すぐにわかるようになります。
# パーティションの種類
オラクルのパーティション機能には、いくつかのタイプがあります。ここでは代表的なものを紹介します。
レンジ・パーティショニング
これは、データを特定の範囲で分ける方法です。例えば、「2023年の売上データ」「2024年の売上データ」という具合に、日付でパーティションを作ることができます。まるで、年ごとにアルバムを整理するようなものです。
リスト・パーティショニング
こちらは、特定の値に基づいてデータを分割する方法です。例えば、「東京の顧客」「大阪の顧客」といった感じですね。これで、「どこのお客様のデータだったかな？」と迷うことがなくなります。
ハッシュ・パーティショニング
データをランダムに分ける方法で、「さあ、どこにデータを置くかは運次第！」という感じです。実際には、ハッシュ関数を使って効率よくデータを分散させます。ちょっとしたカジノ気分？
コンポジット・パーティショニング
名前の通り、複数のパーティショニング手法を組み合わせたものです。「東京の顧客」の中でも「2023年の売上データ」をさらに分ける、といった具合です。まるで、二段構えの引き出しのようですね。
# パーティションのメリット
「でも、それで何が嬉しいの？」と思うかもしれません。パーティションの最大のメリットは、パフォーマンス向上と管理の簡素化です。
パフォーマンス向上
クエリを実行するとき、パーティションを使っていれば、必要な部分だけを読み込めばいいので、処理が速くなります。大きなクローゼットから必要な服だけを取り出すようなものです。
管理の簡素化
パーティションごとにデータを管理できるので、古いデータを削除したり、新しいデータを追加したりするのが簡単になります。季節ごとに服を入れ替えるように、データも簡単に入れ替えができます。
# まとめ
オラクルのパーティション機能は、データベースを整理整頓するための強力なツールです。クローゼットの中をスッキリさせるのと同じように、データベースもパーティションで効率よく管理してみてください。これであなたもデータベースの達人に一歩近づきましたね！それでは、快適なデータベースライフを！

## 採用拡大中！
アシストエンジニアリングでは一緒に働くフロントエンド、バックエンドのエンジニア仲間を大募集しています！
少しでも興味ある方は、カジュアル面談からでもぜひお気軽にお話ししましょう！
お問い合わせはこちらから↓
https://www.assisteng.co.jp/contact/
Snowflakeでユーザ個別の利用状況を可視化する方法

# 概要
**この記事は後ほど修正することを前提に作成しています**
Snowflakeで利用状況（特にコスト）を見る方法はいくつか存在します。
- SnowsightのGUI上で見る方法
Snowsightにログイン後、[管理者] → [コスト管理] で確認することができます
ただし、以下のような課題があります。
  - 使用状況データにアクセスできるロールが必要（e.g. ACCOUNTADMIN等）
  - ウェアハウス、ストレージ、クラウドサービス単位しか見れない
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3880471/160c7174-db3d-f02f-9143-e13573e7be6c.png)

- Cost Optimizer for Snowflake（NTTデータ社提供）で見る方法
利用方法を細かく記載はしませんが、[データ製品] → [アプリ] で該当アプリを検索してインストールすれば、コストの確認が行えます。
ただし、以下のような課題があります。
  - PrivateLinkの環境では動作しない
  - コスト最適化が目的のアプリとなることもあり、過去に遡った利用状況まで確認ができない
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3880471/63439200-14dd-7e2b-3fdb-dae2fca6fbf7.png)

- Query attribution costs のログを用いる方法
Snowflake社から2024/8/30に新しい機能の発表があり、Query attribution costsのログを用いると、ユーザ個別の利用状況を可視化することができます。こちらも本記事では細かくは説明しません。
ただし、以下のような課題があります。
  - 2024/8/20付近以降のデータしか確認できない
https://docs.snowflake.com/en/release-notes/2024/other/2024-08-30-per-query-cost-attribution

# 別のユーザ個別の利用状況を可視化する方法
上記方法での課題を解決して、ユーザ個別の利用状況を可視化する方法について解説します。
**一旦、超雑に全体像だけ記載した記事をリリースして後で手直ししていこうと思います**
用いる情報は、クエリログ（SNOWFALE.ACCOUNT_USAGE.QUERY_HISTORY）とウェアハウス情報（作成したウェアハウスのサイズや各サイズに対するコスト（契約状況で異なる））になります。私の場合、加えて、Snowflakeのユーザ名と社員マスタを紐づけて、ユーザの姓名を表示するようにしたかっため、Python（on Snowlfake）でプログラムを作成し、ユーザ個別の利用状況を可視化するために必要なデータマートを作成しました。

**今日はここまでにして、コードやSQLの追加、解説は別途にしようと思います。**
Julius.AI を使ったKaggleタイタニックチャレンジ結果

分析ツールJuliusを使用して、タイタニックデータを試してみました。

# 結果

結果から先に出すと下記のようなスコアでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181708/eafa4d57-df13-32a1-c373-2e05a3eeb6cf.png)

# Juliaの操作履歴

全体的に、自然言語で命令でき
「XXXとの相関は？」
「ファミリーネームが同じ人を家族あり、とした場合は？」
と簡単に操作ができました。
（こういう分析系は全くの素人なので、適当な命令しかしていません。無料枠一杯で、あれして、精度上げてと無茶ぶりしていました）

↓ここで流れが確認できます。
https://julius.ai/s/d8b86a3d-0b32-4df5-9dbe-39715b739a98

抜粋
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181708/030266de-2adb-c534-3705-dfece413df45.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181708/71ab7b14-2b9a-f6e1-c41b-5be3fe79ae5b.png)
分析結果をお伝えします。

全体的な生存率の比較: 全男性の生存率: 18.89%
子供がいる家族の男性の生存率: 14.29%

この結果から、子供がいる家族の男性の生存率（14.29%）は、全男性の生存率（18.89%）よりも低いことがわかります。

統計的有意性:
p値: 0.5422

この差は統計的に有意ではありません（p >= 0.05）。

p値が0.05より大きいため、この差は統計的に有意ではありません。つまり、子供がいる家族の男性と全男性の生存率の差は、偶然による可能性が高いと言えます。
Microk8sで error getting ClusterInformation: connection is unauthorized: Unauthorized とか言われてpodが起動しないとき

## 事象

```
Events:
  Type     Reason                  Age   From     Message
  ----     ------                  ----  ----     -------
  Warning  FailedCreatePodSandBox  9s    kubelet  Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "xxxxx": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
  Normal   SandboxChanged          8s    kubelet  Pod sandbox changed, it will be killed and re-created.
  ```

## 解決

```
$ kubectl rollout restart daemonset calico-node -n kube-system 
```

この前にも各ノードでsnap restart microk8sとかしたのでそのへんも効いていたかもしれない。
自己紹介

# 自己紹介
**この記事は後ほど修正することを前提にしています**
博士（情報学）。2012年に修士号を取得した後、通信事業会社に就職。プライベートクラウド基盤やアプリケーション開発を経験した後、様々な技術（NW、サーバ、クラウド、プログラミング）を組合せすることで、データ活用を推進するためのプラットフォームを運営。2019年から社会人ドクターとして研究活動を行い、2023年に博士号を取得。「実社会に役立つデータ活用」を推進する技術者兼研究者。

# 関心のある技術領域
- オペレーションズ・リサーチ
  - 数理最適化
  - 組合せ最適化
- クラウド
  - AWS
  - Azure
  - Google Cloud
  - Snowflake
- インフラ
  - サーバ（HPとか）
  - ネットワーク（Ciscoとか）
  - ストレージ（EMCとかNetAppとか）
  - 仮想化（VMwareとか）

# 保持資格
- 博士号（情報学）（2023.3）
- 2024 Japan AWS All Certifications Engineers（2024.6）
- Microsoft Top Partner Engineer Award（2024.7）
-
python: UV いいねって聞いたので、やってみた際のメモ for windows

# 背景

とりあえずやってみた際の自分用メモ 

# uv install

```powershell
pwsh -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```
or
```powershell
pwsh -c "irm https://astral.sh/uv/install.ps1 | iex"
```

:::note warn
powershell 7.x 系は、pwsh.exe になっているので注意。
とはいえ、install 結果は変わらない気もする・・
:::

以下、公式は、powershell.exe (5.x以前) を想定？

https://docs.astral.sh/uv/getting-started/installation/#__tabbed_1_2

## version 確認

```powershell
uv --version
```

## エラー対処
### uv: The term 'uv' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

- <code>%userprofile%\.cargo\bin</code> がinstall 先なので、ここにパスを通せばよい

現在のPathの確認
```powershell
Get-ChildItem -Path Env:PATH
```

## pwsh とする理由について

公式によると、以下だが

```powershell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```

powershell は、7.0 以降、起動ファイルが変わっている。故に、今どきの powershell を使ってる人は <code>pwsh</code> で install したほうが良いと思う。

https://learn.microsoft.com/ja-jp/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7.4#powershell-executable-changes



# python 準備

## 使える一覧

自分の環境に入っているものを見られて便利。
これまでのぐちゃぐちゃさがよくわかる瞬間

```powershell
uv python list
```

## version install 
適当に好きなバージョンを入れるだけ
```powershell
uv python install 3.10 3.11 3.12
```

# python project 作成

開発はプロジェクト単位で、npm init みたいな感じ

```powershell
uv init {project name}
```

# python 実行

この際、.venv が作成されていなければ、自動的に作成され、その仮想環境で実行される。
up pip install などは、その環境に行われる。
※Activate しなくても。明示的に Activate は可能

```powershell
uv run {***.py}
```

<code>uv run hello.py</code> を実行すると、以下 .venv が勝手に出来る

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/d44ea065-1ae8-5a29-ce81-25a5700ae377.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/a0019adf-9d66-fe22-0faf-1d3a0402ec4f.png)


## 実行時エラー

### error: The requested Python interpreter (3.11.9) is incompatible with the project Python requirement: `>=3.12`

pyproject.toml 内の以下確認

> requires-python = ">=3.12"

---

# requirements.in / requirements./txt

## 依存関係の install
超高速になってありがたいやつ

```powershell
uv pip install -r requirements.txt
```

## 依存関係解決 by compiling .in

で、requirements.txt を自動で生成する方法もほぼ困ることはない

### pip-tools install
```powershell
uv pip install pip-tools
uv pip install --upgrade pip-tools
```
### compile

- compile 確認
pip compile の場合は default で txt 吐いてたけど、uv だと確認だけになってる。設定次第かも？
```powershell
uv pip compile .\requirements.in
```
- txt 作成
```powershell
uv pip compile .\requirements.in --output-file requirements.txt
```

---
# 仮想環境

## 簡単に作成
- カレントに、.venv を、カレント python で作成
とはいえ、uv run {*.py} で自動生成されるので・・
```powershell
uv venv
```
## activate
```powershell
{venv folder}/Scripts/activate
```
作成時に、以下のように表示されているので、迷うことは無い筈

> Activate with: venv311\Scripts\activate

## version と 仮想環境フォルダを指定して作成
- version & folder 指定で作成
```powershell
uv venv -p 3.11 venv311
```

# あとがき

うん、確かに便利。
python やりはじめて浅いわけだけど、使う機会増えたから、アンテナ張っておかないと :sweat:
複数のクラスにCSSを効率よく追加する場合のショートカット（ctrl+F, cmd+D, Shift+矢印, Shift+cmd+矢印, ）

## はじめに
こんにちは、未経験からエンジニア転職を目指しているものです。
オンラインスクールで本格的に学習して4ヶ月目に入りました。勉強し始めの頃の自分が疑問に思っていたことを整理してみようと思い記事を書いております。今回はHTML,CSSでウェブサイトを模倣してみた時、クラスにCSSを追加する時にどうすれば効率よく出来るか考えてみました。

## トライ内容
Macでのトライ内容になります。
1. HTML内で、cmd + F で対象のclassを探す
1. cmd + Dで同じclass名を選択し、cmd + Cでコピー
1. CSS内にcmd + V でペースト
1. Shift+矢印で余分にコピーした部分で削除したい部分の始点に移動
1. Shift+cmd+矢印を使用し、余分にコピーした部分で削除したい部分の終点まで選択
1. backspaceで削除

### 使用例
以下のHTMLの記述があります。

```html
<li class="a">
                <dl class="b">
                    <dt class="b-a">ccccccccc</dt>
                    <dd class="b-c">
                        <img src="./c/image/d.png" width="100" height="100" alt="c">
                    </dd>
                    <dd class="b-d">dddddddddddd</dd>
                </dl>
            </li>

```
上記コードで以下のclassにCSSを追加したいとき
class="a"
class="b"
class="b-a"
class="b-c"
class="b-d"

トライ内容の通りに説明すると、
①　cmd + D でclassを選択
![cmd + D.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/16e2c09d-f03c-547c-459c-c4fda9e6469a.png)
②　shift + →を入力、shift + cmd + →を入力　し　cmd + Cを入力し、コピー
![shift + →、shift + cmd + →.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/a6342cbb-ea7b-6a5f-612c-f4ee298c086b.png)
③CSS画面にて、ctrl + Vで貼り付け後、cmd + Dで再度classを選択
![cmd＋D(CSS).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/19ffa548-bcaa-3661-d898-fb2be084917b.png)
④　BS で削除後、.を入力。
![BS + ..png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/6e0d0779-a706-1b2e-fb41-7c7de61bc4e2.png)
⑤　残りの余分な部分は手作業で削除

## まとめ
cmd + F で対象のクラスを探す: クラス名を素早く検索できます。
cmd + D で同じクラス名を選択: 同じクラスを複数見つけて選択できるので便利です。
cmd + C でコピーし、CSSファイルにペースト: コードをコピーしてCSSにすぐに反映できます。
Shift + 矢印で不要部分を削除: HTMLの属性部分など不要な部分を簡単に削除できる
この方法なら、余分なコピー部分の削除と手打ちを最小限にしつつ、クラス名を効率よくCSSに反映できると考えました。

最後までご覧いただき本当にありがとうございました！！
Angularと戯れる④

# はじめに
[Angularチュートリアル：Tour of Heroes](https://v17.angular.jp/tutorial)を読み進めていきます。

# 開発環境
- OS: Windows10
- Nodeバージョン: 18.18.0
- Angular CLI バージョン: 17.3.8
- エディタ: VSCode


# 3. フィーチャーコンポーネントの作成
[3. フィーチャーコンポーネントの作成](https://v17.angular.jp/tutorial/tour-of-heroes/toh-pt3)を読んでいきます。

## 関連コマンド
### コンポーネント作成
`ng generate component %コンポーネント名%`
今回は以下のコマンドを実行。
`ng generate component hero-detail`

これを実行することで、src/app/app.module.component.tsにhero-detailについての記載が追加されます。
```TS:src/app/app.module.ts
import { HeroDetailComponent } from './hero-detail/hero-detail.component';

...
@NgModule({
  declarations: [
    ...,
    HeroDetailComponent
  ],
  ...
})
export class AppModule { }
```

## ソースコードを読み解いてみる
### アプリの構成
![tour-of-heroes_3_create-feature-component.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3873589/d03a38cf-34de-56cf-5597-8673f7c2c293.png)


今までheroesコンポーネント内で行っていた「Heroの詳細を表示する」という責務をhero-detailコンポーネントに委託します。

最終的に、こんな感じの構成になります。
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3873589/3db1ce39-bd22-1eb7-20f5-bb96c48dedee.jpeg)

### 子コンポーネントへのデータの送信
#### ＠Inputデコレーター
親コンポーネントから子コンポーネントへの値の受け渡しの際に使われるデコレーター。

このチュートリアルの場合、「heroesコンポーネントが持っている値をhero-detailコンポーネントに渡す」ことを行います。

受け渡し元（今回の場合heroesコンポーネント）を親コンポーネント、受け渡し先（今回の場合hero-detailコンポーネント）を子コンポーネントと考えます。
<br>

- 子コンポーネント側の準備： 親から渡ってくる値を受ける窓口を作る
```TS:src/app/hero-detail/hero-detail.component.ts
import { Component, Input } from '@angular/core';
import { Hero } from '../hero';

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent {
  /*
   * ・親コンポーネントから渡ってくる値をhero（Hero型）という窓口で受ける。
   * ・@Inputデコレーターを使うことで、親コンポーネントからの入力を受け付けることができる。
   */
  @Input() hero?: Hero;
}
```

[参考]
- Inputデコレーター： https://v17.angular.jp/api/core/Input
- 親子間でのデータ共有： https://v17.angular.jp/guide/inputs-outputs

### プロパティバインディング
コンポーネントがもつ値（プロパティ）を、ターゲットのタグの特定の値に代入する手法。
`[%受け渡し先のプロパティ名%]="%受け渡し元のプロパティ名%"`

このチュートリアルでは、heroesコンポーネントが持つselectedHeroというプロパティを、hero-detailコンポーネントのheroというプロパティに渡します。
<br>
- 値を渡す側：heroesコンポーネント
```HTML:src/app/heroes/heroes.component.html
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
```
selectedFolderの値を、受け渡し先のhero-detailコンポーネントに渡します。heroという名前の窓口を先方が用意してくれているので、受け渡し先としてそこを指定します。

なお、app-hero-detailという名前は、hero-detailコンポーネントのtsのselectorに記載されている値と同じです。
```TS:src/app/hero-detail/hero-detail.component.ts
@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  styleUrls: ['./hero-detail.component.css']
})
...
```
<br>

- 値を受け取る側：hero-detailコンポーネント
```HTML:src/app/hero-detail/hero-detail.component.html
<div *ngIf="hero">
    <h2>{{ hero.name }}</h2>
    <div>id: {{ hero.id }}</div>
    <div>
        <label for="hero-name">Hero name: </label>
        <input id="hero-name" [(ngModel)]="hero.name" placeholder="name">
    </div>
</div>
```
受け渡し元であるheroesコンポーネントのselectedHeroプロパティを、受け渡し先であるhero-detailでは "hero" という窓口で受けます。
<br>

[参考]
- プロパティバインディング： https://v17.angular.jp/guide/property-binding
Macでcsvを見るならVScode

## VScodeの拡張機能Rainbow CSVを使えば見やすい
https://marketplace.visualstudio.com/items?itemName=mechatroner.rainbow-csv

## 使い方
#### 事前準備
VScodeの拡張機能から、Rainbow CSVをダウンロード

#### 実践
1. 開きたいCSVで右クリック
1. 「このアプリケーションで開く」から、VScodeを選択
1. VScodeが開き、選択したCSVが表示される

## 画面
カラムの色と値の色が同じで見やすい
![スクリーンショット 2024-09-12 21.17.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544489/af8404b4-5406-93f7-cda3-05d7e4d4467c.png)

カーソルを合わせるとその値のカラムが表示
![スクリーンショット 2024-09-12 21.16.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544489/a4585fe5-bdd0-9997-c8df-b64d2f0b5167.png)

## まとめ
CSVを使うときに覚えておくと便利！！！
Angularと戯れる①

# はじめに
Angularについて勉強しています。
学んだことを自分なりにまとめて書いていきます。
[Angularチュートリアル：Tour of Heroes](https://v17.angular.jp/tutorial)を読み進めていきます。

# 開発環境
- OS: Windows10
- Nodeバージョン: 18.18.0
- Angular CLI バージョン: 17.3.8
- エディタ: VSCode



# プロジェクトの作成
[プロジェクトの作成](https://v17.angular.jp/tutorial/tour-of-heroes/toh-pt0)を読んでいきます。

## 関連コマンド
### ワークスペースの作成
```
ng new ワークスペース名 --no-standalone
```
Angularアプリの土台となるリソースが格納されたフォルダが作成されます。

チュートリアルにもあるとおり、スタンドアロンを無効とするオプションを添えて実行します。

### アプリケーションの起動
```
ng serve --open
```
--openオプションを添えることで、ｈttp://localhost:4200 がブラウザで開かれます。

## コンポーネントとは
Angularの世界において、下記3点セットをひっくるめて「コンポーネント」と呼ばれます。
- htmlファイル
・ 例：app.component.html 
- cssファイル
・例：app.component.css
- tsファイル (TypeScript形式)
・例：app.component.ts

## ソースコードを読み解いてみる
```TS:src/app/app.component.ts
...
@Component({
  selector: 'app-root',                  //app-rootというタグを指定することで、外部のコンポーネント（のhtml）から参照できる
  templateUrl: './app.component.html',   //同じフォルダにあるhtmlファイルを読み込む
  styleUrls: ['./app.component.css']     //同じフォルダにあるcssファイルを読み込む
})
export class AppComponent {
  title = 'Hello, World!!';
}
```
Componentデコレータについて：[Link](https://v17.angular.jp/api/core/Component)

```HTML:src/app/app.component.html
<h1>{{title}}</h1>
```
app.component.tsのAppComponentクラスで定義されていた変数：title の値を参照します。

ダブルカーリーグレイシスという手法で、参照したい変数名を {{ と }} で囲むことで、値を動的に取得できます。

この状態でUIを確認すると、「Hello, World!!」という文字列が表示されていることを確認できます。
旧型MacBookAirでもXcodeを使いたい

中古のMacBookAirを買って
Swiftでプログラミングしたいなと思ったんですけど
バージョンの古いMacOSのMacBookには
AppStoreからXcodeをインストールできないとのこと

![スクリーンショット 2024-09-11 22.38.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/0922771e-1707-9fb5-9e2f-2bbfc18924e3.png)

MacOSをアップデートしようとしたが
私のMacBookAirがMontereyまでしか対応してない・・・

![スクリーンショット 2024-09-11 22.45.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/728736ad-c73e-47f2-ea6d-65c1afcaab15.png)

さてどうしたものか・・・🤔

どうやら軽い力技でインストールするしかないらしい🙄

https://developer.apple.com/download/all/
↑このページから古めのXcodeを直接ダウンロードします😊

ページの一番下の方にあった14.0.1をダウンロード

![スクリーンショット 2024-09-12 20.37.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/f5a24fdf-d3de-465b-dfe6-b76be779ae84.png)

xipファイルを解凍してインストール

![スクリーンショット 2024-09-12 20.37.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/45984ed3-6f00-dea9-6284-f8ba6e80bdb3.png)

起動してみる

![スクリーンショット 2024-09-12 20.41.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/0c9fb5a8-fa92-df52-a710-3bc5cb6143a8.png)

うん、大丈夫そ

終わり！🤗
ヘルスコネクトから歩数を取得したけど、なんだか合わないな…

# はじめに
この記事は、ヘルスコネクトから歩数を取得したけど、なんだか歩数の合計値が合わないな…ってなって、対処した時のメモです。

# 最初の実装
自分の場合は1日ごとの歩数の合計値を取得したくて AggregateGroupByPeriodRequest[^1] を使って下記のような実装をしていました。

```kotlin
// 1日ごとの歩数を集計する
// startTs, endTs ... Unix Time(ミリ秒)
AggregateGroupByPeriodRequest(
  metrics = setOf(StepsRecord.COUNT_TOTAL),
  // wrong
  timeRangeFilter = TimeRangeFilter.between(
    Instant.ofEpochMilli(startTs), 
    Instant.ofEpochMilli(endTs)
  ), 
  timeRangeSlicer = Period.ofDays(1),
  dataOriginFilter = setOf(DataOrigin("com.google.android.apps.fitness"))
)
```

その時、ヘルスコネクトで表示されている歩数とこのリクエストで得られる歩数に大きく差異あることがわかりました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255998/e8bccff0-b3d9-5e4f-9901-f37f96c02a46.png" width=30%>


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255998/2e1fd0d5-1ac4-391e-5db0-fb72e639e8ce.png" width=80%>

AggregateGroupByPeriodRequest の TimeRangeFilter[^2]の実装箇所に問題がありました。期間を指定するのに日付けのタイムスタンプ(ミリ秒)を使っていたのでそのまま、Instant にして TimeRangeFilter に渡していたのですが、この場合だとUTCベースでの1日(-9時間なので日本時間の`前日15:00:00-当日14:59:59`)でSliceされてしまいます。

# 修正後

1日分の歩数を日本時間の`00:00:00-23:59:59`でsliceしたい場合はLocalDateTimeで渡してやる必要があります。

```kotlin
// 1日ごとの歩数を集計する
AggregateGroupByPeriodRequest(
  metrics = setOf(StepsRecord.COUNT_TOTAL),
  // correct
  timeRangeFilter = TimeRangeFilter.between(
    LocalDateTime.ofInstant(Instant.ofEpochMilli(startTs), ZoneOffset.ofHours(9)),
    LocalDateTime.ofInstant(Instant.ofEpochMilli(endTs), ZoneOffset.ofHours(9))
  ), 
  timeRangeSlicer = Period.ofDays(1),
  dataOriginFilter = setOf(DataOrigin("com.google.android.apps.fitness"))
)
```

# まとめ
自分は原因追及と修正に丸1日かかってしまいました。取得データの `startTime` をチェックして初めて気がついた感じです。他の皆様のお役に立てれば幸いです。

[^1]: https://developer.android.com/reference/kotlin/androidx/health/connect/client/request/AggregateGroupByPeriodRequest

[^2]:https://developer.android.com/reference/androidx/health/connect/client/time/TimeRangeFilter
paddingとmarginを段ボールで例えてみました〜初学者の絞り出した知恵〜

## はじめに
こんにちは、未経験からエンジニア転職を目指しているものです。
オンラインスクールで本格的に学習して4ヶ月目に入りました。勉強し始めの頃の自分が疑問に思っていたことを整理してみようと思い記事を書いております。今回は初学者が疑問に思う部分であるpaddingとmarginについてまとめてみました。

## paddingとmarginとは？
HTMLの要素は「ボックスモデル」という仕様に基づいて構成されています。このボックスモデルには、以下の4つの要素が含まれます：content（コンテンツ）、padding（パディング）、border（ボーダー）、およびmargin（マージン）。

- `content`  :  要素の中身（テキストや画像など）を表します
- `padding`  :  要素の内側に設定される余白で、CSSプロパティpaddingを指定すると作成されます
- `padding`  :  コンテンツと境界線（border）の間に生まれるスペースです
- `border`   :  要素の境界線を指し、CSSプロパティborderを使用して設定します。borderはpaddingの外側に存在し、枠線を表します
- `margin`  :  要素の外側に設定される余白で、CSSプロパティmarginを指定すると作成されます。marginは他の要素との間隔を確保するためのスペースです

※paddingは英語で「詰め物」を意味し、marginは「余白」を意味します。

:::note
単語の定義については「[現役エンジニア＆インフルエンサー　セイト先生が教えるプログラミング入門 (堀口 セイト)](https://www.amazon.co.jp/%E7%8F%BE%E5%BD%B9%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%EF%BC%86%E3%82%A4%E3%83%B3%E3%83%95%E3%83%AB%E3%82%A8%E3%83%B3%E3%82%B5%E3%83%BC-%E3%82%BB%E3%82%A4%E3%83%88%E5%85%88%E7%94%9F%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80-%E5%A0%80%E5%8F%A3-%E3%82%BB%E3%82%A4%E3%83%88/dp/4296070754)」の内容を一部参考にさせていただきました。

:::

## 段ボールで例えると？
定義は理解したのですが、勉強し始めの頃はpaddingとmarginがごっちゃ混ぜになっておりました。そこで身近なものに例えたら分かりやすいと思い自分なりに例を作り、まとめてみました。
AさんとBさんと段ボールとAmazonが登場します。

[例]
AさんとBさんがいます。二人ともAmazonで買い物をしました。それぞれ段ボールが一箱ずつ届く予定です。
`～marginとは？～`
まず、トラックにAさんとBさんの段ボールが積まれました。Aさんの段ボールとBさんの段ボールの間には10センチの空間があります。この空間が"margin"です。**つまり、要素（段ボール）同士の外側にあるスペースがmarginです。**

`～paddingとは？～`
段ボールの中には、四角い箱に入った商品が入っています。この四角い箱と段ボールの内側の壁の間には20センチの隙間があります。これが"padding"です。つまり、**要素の中でコンテンツ（四角い箱）とその境界線（段ボールの内側の壁）との間にあるスペースがpaddingです。**

`～borderとは？～`
また、段ボール自体にも厚みがあります。**この段ボールの厚さや外側に貼られたテープが"border"です**。つまり、要素の外側の枠線部分を指します。段ボールがしっかりと中身を保護するように、要素のborderは見た目にアクセントをつけたり、要素を囲む役割を果たします。

### まとめ
段ボールの厚さ → border
段ボールと中の四角い箱との間の空間 → padding
AさんとBさんの段ボールの間の空間 → margin



最後までご覧いただき本当にありがとうございました！！
nRFConnectSDKを基盤としたSesameの暗号通信 #14 ECDH

![sesame](https://scontent-nrt1-2.xx.fbcdn.net/v/t39.30808-6/459410652_10221412949593457_7224567731006310393_n.jpg?_nc_cat=110&ccb=1-7&_nc_sid=127cfc&_nc_ohc=ZYQmP-n4cKMQ7kNvgGOYg_w&_nc_ht=scontent-nrt1-2.xx&_nc_gid=AhKnTPfjceiIVmlr8JH2BiN&oh=00_AYAv1zLAESIVTDKkmXHAIJMEQoyxpqH_cQJx5EmqyPziQg&oe=66E8B903)
「リーダブルコード」を身につける【第Ⅲ部】コードの再構成

# はじめに
リーダブルコード（オライリー）では、「読みやすさの基本定理」を下記のように定義している。

コードは他の人が最短時間で理解できるように書かなければいけない。
ここで、「他の人」とは、何週間後の自分自身も含む。また、「理解できる」とは、バグに気づき、コードの修正を行い、他のコードとの連携を設計することができることを指す。
本記事では特に、「カードの再構成」によるリーダブルコード達成方法を取りまとめる。
（前々回記事：[第Ⅰ部　表面上の改善](https://qiita.com/ThankYouYokohama/items/d5ac78f3c91482e5ea15)）
（前回記事　：[第Ⅱ部　ループとロジックの単純化](https://qiita.com/ThankYouYokohama/items/3db7c19a0b728eb84ab5)）
# コードの再構成
これまで、第Ⅰ部で「コードの表面的な改善」、第Ⅱ部で「小さな塊としてのコードの改善」について学んできた。第Ⅲ部では視点をマクロに変えて、巨大なコードブロックを再構成して解きたい問題を関数レベルに分解する方法について学ぶ。
以下の4項目について学ぶことで、理解しやすいコードを作成するテクニックが身につく。
- コードのデフラグによるタスク整理
- コードは短くする
- 明確なロジックでストーリーを建てる
- コードを独立させる

## コードのデフラグによるタスク整理
本項目の目標は、「一つの段落で一つのタスクを行えるように、コードのデフラグを行えるようになること」である。

:::note warn
デフラグとは
デフラグ（デフラグメンテーション）とは、バラバラになったデータの断面を整理して効率よく並び替えること（詳細はIT用語辞典へ→[こちら](https://e-words.jp/w/%E3%83%87%E3%83%95%E3%83%A9%E3%82%B0.html#:~:text=%E3%83%87%E3%83%95%E3%83%A9%E3%82%B0%E3%80%90%E3%83%87%E3%82%A3%E3%82%B9)）
:::
コードがデフラグされているメリットは下記の通りである。

:::note info
コードをデフラグするメリット
- 【簡潔化】重複削除により、コードがシンプルになる
- 【疎結合化】タスク同士が疎結合になることで、ある領域を読むときは他の領域のことを考えなくて済む
- 【修正容易化】ある機能に修正の必要が生じた際、1段落にまとまっていることで効率的に書き換えることができる
:::
適切にコードのデフラグを行うために、下記の手順を踏むとよい。
1. コードが行っているすべてのタスクを列挙する(下記画像の「コード内容」を洗い出す)
1. タスクをできるだけ異なる関数、または段落に分割する（同じ「コード内容」は1段落にまとめる）

![リーダブルコード_デフラグの説明_3-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692408/7c8c7cd9-c0d0-5782-063d-a96c94c7c7e1.png)

## コードは短くする
コードはなるべく短くするべきである。

:::note info
コードを短くするメリット
- テストや保守が容易になり、時間節約になる
- 管理や引き継ぎが楽になる
:::

コードを短くするために下記を意識すると良い。
| 意識すべきこと | 詳細 |
|:-----------|:------------|
|要求の削除・無用の機能の削除|本当にその機能は必要なのか？と自問自答する|
|より単純な問題の解決|もっと簡単なロジックで書けないか？視点を変えたりして考え直す|
|util関数による重複コードの削除|よく使う関数をモジュールとしてまとめておくことで余計なコピペを省ける|
|サブ単位に分割|答える問（実装したい仕組み）を細かく分割できないか考える|
|ライブラリ・組み込みモジュールの活用|Pythonなら便利なライブラリが山ほどある。ライブラリが提供しているものをしっかり理解しておく|
|コマンドラインの活用|Pythonで頑張って実装するよりも「!」でコマンドライン書いたほうが楽なことも|

## 明確なロジックでストーリーを建てる
明確なロジックで建てられたコードは、作成者が何をしたいのか容易に理解できる。
そのようなコードを作成するために、下記の手順を踏んでからコード作成に臨むと良い。
1. 作成したいコードの動作(ロジック)を簡単な言葉で説明する
1. 説明内のキーワードやフレーズをピックアップしておく
1. その説明に合わせてコードを書く

:::note alert
1.ができないとき…
ロジックの詳細が明確になっていない可能性が高いため、改めて何をしたいのか考え直す必要あり
:::

## コードを独立させる
プロジェクトでいくつもコードを作成していく中で、「汎用的なコード」は「プロジェクト固有のコード」から積極的に分離していくべきである。

:::note info
汎用的なコードを独立させるメリット
- 再利用が可能であるため、コードを各時間が短縮される
- 改善が楽であるため、機能追加や可読性向上が容易にできる
:::

:::note warn
汎用的なコードを独適切に独立させるために…
- キレイなインタフェースを心がける（スムーズに活用できるようにするため）
    - 引数が少ない
    - 事前設定が必要ない
- 作りすぎない（逆に理解の妨げになることもあるため）
:::
# 終わりに
本記事では、これまでよりもマクロな視点で読みやすいコードとは何か説明した。コーディング以外でも通ずる点がいくつかあり、本筋としては一般的な文章構成と同等の考え方で良いような気がしている。
ESを書くのが得意だった人は、特に意識しなくても本記事の内容はできてそうだなと思ったり思わなかったり…
nRFConnectSDKを基盤としたSesameの暗号通信 #13 AES-CCM

![sesame](https://scontent-nrt1-2.xx.fbcdn.net/v/t39.30808-6/459601612_10221412941633258_8629671700378090502_n.jpg?_nc_cat=102&ccb=1-7&_nc_sid=127cfc&_nc_ohc=oNJzwb1Z1pIQ7kNvgGN0Jk8&_nc_ht=scontent-nrt1-2.xx&_nc_gid=Aw_daERAp7pN4SXVCDNdFAv&oh=00_AYAvBMvxt3V9v73cySnEhkI0daT6XR5IpH6VcCSJILpkRg&oe=66E88E31)
【TypeScriptで学ぶデータ構造】キュー

## キュー
最初に入れたデータを最初に取り出すデータ構造の一種。

### 具体的な例としてはプリンターのジョブ管理

プリンターは、印刷の工程をキューで管理しています。複数のユーザーからの印刷要求があった場合、先に送られたものが最初に印刷されます。新しい印刷の要求はキューの中の末尾に追加され、プリンターはキューの先頭にある要求から処理していきます。

また実生活であれば、お店の行列もキューに相当します。（キューのことを待ち行列と言ったりもするそうです。）


## キューを再現したQueueクラス

enqueueメソッドで配列itemsに要素を追加します。
追加した要素を取り出す際はdequeueメソッドを使い、最初に入れたものから取り出せるようにしています。

```Queue.ts
class Queue<T> {
	private items: T[] = [];
	private front: number = 0; //キューの先頭を管理
	private rear: number = 0; //キューの末尾を管理

	//要素をキューに追加するメソッド
	enqueue(item: T): void {
		this.items[this.rear] = item;
		this.rear += 1;
	}

	//キューの先頭の要素を削除して返すメソッド
	dequeue(): T | undefined {
		if (this.isEmpty()) {
			return undefined;
		}
		const dequeuedItem = this.items[this.front];
		this.front += 1;
		return dequeuedItem;
	}

	//キューが空かどうかを確認するメソッド
	isEmpty(): boolean {
		return this.front === this.rear;
	}

	//キューの内容を表示
	printQueue(): void {
		console.log(this.items.slice(this.front, this.rear).join(" "));
	}
}

//使用例です
const queue = new Queue<number>();
//キューに1000を追加
queue.enqueue(1000);
queue.enqueue(5000);
queue.enqueue(10000);

//この時点では1000 5000 10000
queue.printQueue();

//取り出す処理。下記の場合、1000が取り出される
queue.dequeue();
//次に5000が取り出される
queue.dequeue();
//残ったのは10000！
queue.printQueue();
```
MacBookAirにDockerをインストールした

中古のMacBookAirを買ったので早速色々とイジってみて
Dockerもインストールしてみることに

まずはDocker Hubへの登録
https://www.docker.com/ja-jp/products/docker-hub/

メールアドレスとパスワードを入力して登録

終わったら
Dockerのインストールを開始します

インストール方法・手順については下記を参考にしました
https://matsuand.github.io/docs.docker.jp.onthefly/desktop/mac/install/

![スクリーンショット 2024-09-11 22.16.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/e6be0c35-ea27-97f1-8596-39bb43e84f7c.png)

私のはIntelチップのMacなので左側のボタンを押してインストール

インストール後にApplicationsにドラッグアンドドロップ
![スクリーンショット 2024-09-11 22.18.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/a3461164-e887-817b-71df-afd2430b4ab6.png)

アプリケーションの中にDockerのアイコンがあればOK

![スクリーンショット 2024-09-11 22.19.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/fe448ade-984f-e826-68c7-922949e1d4b4.png)

アイコンをダブルクリックして起動
下記表示が出てくるのでAccept
![スクリーンショット 2024-09-11 22.20.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/842503fb-0b79-ab14-0519-a38a7590fe7f.png)

recommended settingsにチェックを入れてFinish
![スクリーンショット 2024-09-11 22.20.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/f890d44c-d62f-e3a7-6a68-2bb7b8d8658d.png)

Docker Hubに登録したメールアドレスとパスワードを求められるので入力

![スクリーンショット 2024-09-11 22.22.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/0e462024-5d70-44a6-ed2c-374b9e49f60a.png)

↑で完了です
↓がトップ画面です

![スクリーンショット 2024-09-11 22.27.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/e22b5d57-60ff-4d3c-24cd-c0261056963b.png)

終わり！
![スクリーンショット 2024-09-11 22.29.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2790258/b379537f-8141-66a9-12e1-e35a668fb53e.png)
Oracle DatabaseのSELECT文でLIMIT句を使う方法

# はじめに
MySQLやPostgreSQLで行数の絞り込みに使用するLIMIT句、便利ですよね。一方Oracle Databaseでの行数の絞り込みは、ANSI SQL標準のFETCH FIRST句を使用します。しかし実行環境はAutonomous Database Cloud Service(以下ADB)に限られますが、Oracle DatabaseでもLIMIT句を使う方法が提供されましたので方法を共有したいと思います。

# 事前準備
ADBにはDatabase Actionsのような便利なWebツールがついていますが、残念ながらそういった環境では動きません。SQL*PlusやSQLcl、あるいはアクセスドライバ経由で開発言語経由での利用が前提となります。
事前準備といっても簡単で、以下のSQLを発行するだけです。
```
BEGIN
  DBMS_CLOUD_MIGRATION.ENABLE_TRANSLATION ('POSTGRES');
END;        
/
```
SQLのCALL文(`CALL DBMS_CLOUD_MIGRATION.ENABLE_TRANSLATION ('POSTGRES')`)でも構いませんし、SQL*PlusやSQLclであればツールのEXECコマンド(`EXEC DBMS_CLOUD_MIGRATION.ENABLE_TRANSLATION ('POSTGRES')`)でも構いません。
ADMIN以外のユーザーで実行する場合は、ADMINユーザーにてこのパッケージへの実行権限を付与してから該当ユーザーでログインする必要があります。下記「scott」の部分を権限付与対象のユーザー名に変更してください。
```
SQL> grant execute on dbms_cloud_migration to scott;

Grant succeeded.
```

ところでパッケージ名に「MIGRATION」と入っているのが気になるかもしれません。このパッケージ自体は本記事執筆時点ではPostgreSQLのみが対象ですが、本来はOracle Databaseへの移行を目的に他のDBMSのSQL文をOracle DatabaseのSQL文に変換するパッケージです。基本的には本記事では紹介していない、変換後のSQL文を出力する機能が利用の中心なのですが、今回紹介しているコマンドは指定したDBMSのSQL文を発行すると、Oracle Database側で内部的にOracle Databaseに変換して実行できるようにします。結果、Oracle Databaseに元のDBMSの書き方のままのSQL文を発行することを可能にします。

# 実行してみる
```
SQL> exec DBMS_CLOUD_MIGRATION.ENABLE_TRANSLATION ('POSTGRES')

PL/SQL procedure successfully completed.

SQL> select * from sh.costs
  2  where promo_id = 999 and channel_id = 2
  3  order by time_id
  4  limit 5;

   PROD_ID TIME_ID     PROMO_ID CHANNEL_ID  UNIT_COST UNIT_PRICE
---------- --------- ---------- ---------- ---------- ----------
       117 01-JAN-98        999          2        9.3        9.3
        41 01-JAN-98        999          2      47.88      47.88
        48 01-JAN-98        999          2         13         13
        39 01-JAN-98        999          2      40.05      40.05
       116 01-JAN-98        999          2       12.4       12.4
```

ちゃんと動きますね。
上記の状態のまま、Oracle Database固有のSQL文も流せます。
```
SQL> select * from sh.costs
  2  where promo_id = 999 and channel_id = 2
  3  order by time_id
  4  fetch first 5 rows only;

   PROD_ID TIME_ID     PROMO_ID CHANNEL_ID  UNIT_COST UNIT_PRICE
---------- --------- ---------- ---------- ---------- ----------
       117 01-JAN-98        999          2        9.3        9.3
        41 01-JAN-98        999          2      47.88      47.88
        48 01-JAN-98        999          2         13         13
        39 01-JAN-98        999          2      40.05      40.05
       116 01-JAN-98        999          2       12.4       12.4
```


# 終了方法
開始方法から想像がつくかもしれませんが、PostgreSQL互換モード終了方法は以下になります。もっとも、先述のとおり互換モードでもOracle Database構文も通るので、終了させる意味は薄いかも知れません。
```
BEGIN
  DBMS_CLOUD_MIGRATION.DISABLE_TRANSLATION ();
END;        
/
```
終了の場合引数は不要です。

# その他注意点など
本記事執筆時点のこの機能は、実際には対応範囲が狭いです。筆者が試した範囲ではLIMIT句とテーブルのデータ型を変換してくれる程度です。一例としてはSQL関数にはほとんど対応していません。ただし、元々Oracle Database 23aiではFROM句なしのSELECTやUPDATEでのJOINなど、MySQLやPostgreSQLではできるけど以前のバージョンのOracle Databaseではできなかったことの多くが素でできるようになっています。今後どこまで拡張されるかはわかりませんが、今後の機能拡張にご期待ください。


# 変更履歴
- 2024/9/12 初版
ElixirのログをJson形式にする 〜LoggerJson〜

# ブロジェクト作成

```
$ mix new logger_json_experiment
```

# LoggerJson設定
```diff_elixir:mix.exs
# 〜省略〜
  defp deps do
    [
+     {:logger_json, "~> 6.0"}
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    ]
# 〜省略〜
```
 
 ```
$ mix deps.get
```

```elixir:config/config.exs
import Config

config :logger, :default_handler,
 formatter: {LoggerJSON.Formatters.Basic, []}
```

# テスト用ソース

```diff_elixir:lib/logger_json_experiment.ex
defmodule LoggerJsonExperiment do
  @moduledoc """
  Documentation for `LoggerJsonExperiment`.
  """
+ require Logger

  @doc """
  Hello world.
  ## Examples
      iex> LoggerJsonExperiment.hello()
      :world
  """
  def hello do
+   Logger.error("hoge")
    :world
  end
end
```
# 実行

```
$ mix test
```
# 結果

Json形式になりました
```
{"message":"hoge","time":"2024-09-12T11:16:05.003Z","metadata":{},"severity":"error"}
```

# logger_jsonを組まない時のメッセージ

```
20:12:12.160 [error] hoge
```

# ソース(github)

https://github.com/ymn-t-yamanashi/logger_json_experiment
Neovimでコミットメッセージを自動補完(CopilotChat.nvim)


## はじめに

コミットメッセージって考えるの面倒ですよね。
最近は[CopilotChat.nvim](https://github.com/CopilotC-Nvim/CopilotChat.nvim)のおかげでメッセージを生成できるようになり、随分と楽になりました。
が、毎回コマンド( `:CopilotChatCommitStaged` )を実行して提案を採用( `<C-y>` )するのすら面倒になってきたので、コミット時にこのプロセスを自動化することにしました。

こんな感じで `git commit` 時に自動でチャットを開いてメッセージを補完します。

![autocomplete-commit-message.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303869/1f690d3c-77fc-28f9-a56d-c80d491f0ba6.gif)

## 実行環境

- NVIM: v0.10.3
- CopilotChat.nvim: v3.3.3

## 実装

実装には[CopilotChat.nvim の API](https://github.com/CopilotC-Nvim/CopilotChat.nvim?tab=readme-ov-file#api)を活用しました。
`git commit` の編集時にのみ自動補完を適用するため、 `ftplugin/gitcommit.lua` にスクリプトを配置します。

:::note info
(2025/1/17追記) `selection` ではなく `#git:staged` でステージングされた変更をコンテキストに含めるように変更しました。
:::

```lua:.config/nvim/ftplugin/gitcommit.lua
local has_copilot = vim.fn.exists(":CopilotChat") == 2

if has_copilot then
  vim.schedule(function()
    local chat = require("CopilotChat")
    chat.open()
    chat.ask('> #git:staged\n\nGenerate a concise and meaningful commit message title based on the changes made. Make sure the title has maximum 50 characters. Do not put quotes around the title. Focus solely on creating the title, not the full commit message body.', {
    callback = function(response)
      chat.close()
      vim.api.nvim_buf_set_text(0, 0, 0, 0, 0, {response})
    end,
    })
  end)
end
```

このスクリプトは `git commit` を契機にコミットメッセージを生成するプロセスを開始します。
`:CopilotChatCommitStaged` と同様に変更に基づいたメッセージを生成し、その結果を即座にバッファに挿入します。
今回用意したプロンプトではコミットメッセージのタイトルのみを生成するようにしました。

これによりコミットメッセージを手動で生成する手間を省き、よりスムーズにコミット作業が行えるようになりました。

## 参考

- https://zenn.dev/vim_jp/articles/041300c0f9cc50
学び直しFortran

「n十年前、学生時代に現場でカラダで覚えたFortranだが、どうも最近の進展はよくわかんねぇんだょなぁ」という、ある程度Fortranを読み書きできるんだけれどModern Fortranなどと呼ばれている最近の状況に乗り遅れている人がキャッチアップするために集めた情報。

# 正攻法で学ぶ
「こんな機能ないのかな？」「ネットの海を彷徨っていたら面白い情報を見つけた」という能動的に学習した事項

# エラーから学ぶ
直面したエラーから、解決のためにいろいろ学んだ、ある種対処療法的な事項

## 異なる関数の引数がマッチしていないと怒られる(GCC 11.4.0)

```fortran:Initialization.f90(問題のコードの抜粋)
  Call MPI_BCAST(input_data,256,MPI_CHARACTER,0,MPI_COMM_WORLD,ierr)
  Call MPI_BCAST(sys_name,256,MPI_CHARACTER,0,MPI_COMM_WORLD,ierr)
  Call MPI_BCAST(dir_name,256,MPI_CHARACTER,0,MPI_COMM_WORLD,ierr)
  Call MPI_BCAST(DFT_option,32,MPI_CHARACTER,0,MPI_COMM_WORLD,ierr)
  Call MPI_BCAST(Band_option,1,MPI_LOGICAL,0,MPI_COMM_WORLD,ierr)
```
を`openmpi-5.0.3 + gcc-11.4.0`でビルドしようとすると以下のようなエラーが出る。
```console:エラー出力
Initialization.f90:28:17:

   24 |   Call MPI_BCAST(input_data,256,MPI_CHARACTER,0,MPI_COMM_WORLD,ierr)
      |                 2
......
   28 |   Call MPI_BCAST(Band_option,1,MPI_LOGICAL,0,MPI_COMM_WORLD,ierr)
      |                 1
Error: Type mismatch between actual argument at (1) and actual argument at (2) (LOGICAL(4)/CHARACTER(*)).
```
引数のミスマッチが、異なる関数callの引数にされていて、わけわかめ。(MPIのAPI的には、同一callの`MPI_BCAST`ルーチンの第一引数の型と三つ目の変数の型説明が一致していれば良い。したがって、そもそも異なるcallに対してこれらが一致している必要はないのでエラーとして表示されるのが不可解。)

この解決策が[linux - fortran: Error: Type mismatch between actual argument at (1) and actual argument at (2) (INTEGER(8)/INTEGER(2)) - Stack Overflow](
https://stackoverflow.com/questions/69686755/fortran-error-type-mismatch-between-actual-argument-at-1-and-actual-argument)に書いてあって、ここから抜粋すると
>  ・Tells gfortran to ignore this concerns with option -fallow-argument-mismatch.
>  ・Use modern fortran interface (use mpi instead of include mpif.h) I chose the latter.  

となる。正直前者は副作用が怖いので、後者の方法を試してみたら問題は解決した。

### 戯言・感想
新しいGCCでは型チェックがstrictになったので、こう言った事例が現れるようになった みたいな記載がちらほら。実際、同じコードを`gcc-9.4.0`でビルドしたら何もエラーは出なかった。
chatgpt先生に尋ねたものの的をいた答えが返ってこず(2024/09/12時点)、結局この解決方法はgoogleでエラーをコピペして検索している過程で見つけた。
ちなみに、上記のコードはエラーを再現するために最低限必要な部分の抜粋で、実際は他の`MPI_BCAST`関数とも組み合わさって、何行もエラーが出てきた。一方で、必ずしも全ての`MPI_BCAST`のcallが引っかかっている訳ではなくて、理屈はよくわからなかった。
当該環境では、自身で`/opt`以下に入れた環境をEnvironmental Moduleでloadしたもの。これが遺留で、ヘッダーを探しに行っているフォルダの設定が間違っているのかと思ったけれど、`mpif90 --showme`で調べたら正しそうなフォルダが`-I`以下に書かれていたので、その可能性は薄いな というような考察はした。
投稿 59 RDBMS 2024/08/28

本日の勉強時間　1H

$name = "John";
このJohn は配列のこと。


PHPの変数は、データを格納するための名前付きのメモリ領域です。変数名は $ 記号で始まり、その後に変数名を続けます。データ型は特に指定せず、数値、文字列、配列など様々な型の値を格納できます。変数は値を変更可能です。
投稿 57 phpの定数 2024/08/26

本日の勉強時間　1H


define("PI", 3.14159); は、PHPで定数を定義するためのコード。

定数は一度定義すると変更できない値を格納するために使用。

（変数は変更できる！）


説明
```
define("PI", 3.14159);
```
・define 関数を使って、定数を定義
・"PI" は定数の名前で、文字列として指定
・3.14159 は定数の値で、数値として指定


-特徴-
定数の名前: 通常、大文字で書くことが多いです（例: PI）。
定数の値: 定数に設定した値は変更できません。
スコープ: 定義した定数は、スクリプト全体でアクセス可能です。
使用例
```
define("PI", 3.14159);
echo PI;  // 出力: 3.14159
```

このコードでは、PI という定数を定義し、その値 3.14159 を出力しています。


-注意点-
定数名は $ を付けず、全て大文字で記述するのが一般的です。
define 関数は、PHPの定数を作成するための方法の一つです。
もう一つの方法は、クラス内で const を使用することです。
投稿 56 phpの配列 2024/08/25

本日の勉強時間　1H

```
$colors = array("赤", "青", "緑"); 
```
PHPで配列を作成するためのコード。


・$colors は、配列を格納するための変数。
・array("赤", "青", "緑") は、配列リテラルのこと。
・"赤", "青", "緑" という3つの文字列要素を持つ配列を作成。

この配列は $colors 変数に割り当てらる。


このコードで作成される $colors 配列の内容は次の通りです:
```
インデックス 0: "赤"
インデックス 1: "青"
インデックス 2: "緑"
```
配列の使用例
```
foreach ($colors as $color) {
    echo $color . "\n";
}
```
このコードでは、$colors 配列の各要素を $color に代入し、echo で表示します。結果として、次のように出力されます:
```
赤
青
緑
```
投稿 55 <?php ?>とは何か 2024/08/24

本日の勉強時間　1H

<?php ?> は、PHP スクリプトをHTMLに埋め込むためのタグ.


このタグ内に書かれたコードは、PHPエンジンによってサーバー側で処理されます。


# 使い方
開くタグ: <?php - PHPコードの開始を示します。

閉じるタグ: ?> - PHPコードの終了を示します。
投稿 54 PHPにおけるコメントアウト 2024/08/23

本日の勉強時間　2H

PHPのコメントアウトは以下のように表される。
// This is a comment 
/* This is a comment */
#This is a comment


しかし、JavaScriptに見られるようなコメントアウト
<!-- This is a comment -->
は表されない。
【Error】シングルクォートとダブルクォート。Rubocopの自動修正機能

# はじめに
今回はタイトル記載の通り、「"」と「`」という違いだけでエラーが発生するのか、という事を知ったので、エラー発生から、どのような解決手法があるのかを記事にしていきたいと思います。

## 環境
- Windows, WSL
- Docker
- Ruby 3.2.3
- Rails 7.1.3


## 1：具体的なエラー内容

[![Image from Gyazo](https://i.gyazo.com/835262a6a83ca6bda966e23cc9e9c06b.png)](https://gyazo.com/835262a6a83ca6bda966e23cc9e9c06b)

```ruby
Run bin/rubocop -f github
  bin/rubocop -f github
  shell: /usr/bin/bash -e {0}

Error: Style/StringLiterals: Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
Error: Process completed with exit code 1.

```

## 2：エラーの原因:
- **Rubocopのルール**では、ダブルクォート（`" "`）を優先的に使うべきだという規則があり、シングルクォート（`' '`）を使っている場合にエラーを出します
- シングルクォートは、特定のエスケープ文字を避けたい場合のみ使うのが望ましいとされています。たとえば、文字列内にダブルクォートを含める場合です。


## 3：対処方法

エラー原因から察するに単純にシングルのコードをダブルにすればいいだけになります、いかんせん、どこに入力したのか全く覚えていません:scream:
調べえると次のような対処手順がありました。

### 具体的な手順、自分で探すのではなくコードを利用する！

エラーの数が多い場合、Rubocopには自動修正機能があります！
それを使ってまとめて修正していきます

1. 以下のコマンドを実行して、自動でエラーを修正します。
    ```bash
    bin/rubocop -a
    ```
    - なんと`a` オプションを使うと、自動でコードを修正してくれます！

2. そして再度下記を実行してエラーが解消されたか確認します
    ```bash
    bin/rubocop -f github
    ```


### 実際の流れ（どんなものが出力されるのか）
```ruby
$ docker compose exec web bash
# bin/rubocop -a
Inspecting 30 files
........................C.....

Offenses:

config/routes.rb:2:8: C: [Corrected] Style/StringLiterals: Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
  root 'static_pages#top'
       ^^^^^^^^^^^^^^^^^^

30 files inspected, 1 offense detected, 1 offense corrected
```


はい、上記でRubocopが自動的に修正してくれたました
具体的に言うと、`config/routes.rb` ファイルの2行目にあるシングルクォートを、Rubocopが自動的にダブルクォートに変更しています。

`1 offense corrected` というメッセージが出ているので、Rubocopがこの箇所を修正したことが確認できます。

- **Before (修正前)**:
    
    ```ruby
    root 'static_pages#top'
    ```
    
- **After (修正後)**:
    
    ```ruby
    root "static_pages#top"
    ```
    
最後に、修正が正しく行われたかもう一度確認して終了になります

    ```
    # bin/rubocop
    Inspecting 30 files
    ..............................
 
    30 files inspected, no offenses detected
    ```

# さいごに

単に文字列を囲むクォートの使い方に関するエラーでしたが、エラーが発生したコードを探しに行くのではなく、Rubocopの自動修正機能を使うことで解消できるという事を知りました！！すごい。
今回の記事が何か参考になれば幸いです。
Heroku(本番環境)のみエラー発生、開発環境は問題無し

この記事はプログラミング学習者がアプリ開発中に躓いた内容を備忘録として記事におこしたものです。内容に不備などあればご指摘頂けると助かります。

### 開発環境で機能を実装し終わって、いざHeroku(本番環境)へPushした時にエラーが発生しました。
NoMethodError in CommentsController#create
undefined method'parent_id=' for #<保存しようとしたデータ>

![Heroku デプロイ後のエラー画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/328aad5d-6767-159f-7815-0f6e62cbf644.png)

このエラーが開発環境で出ていたら、空(Nil)のデータをcreate → save しようとしているのかな、ということでbinding.pry等でデバッグして変数内の値をチェックしてみよう等といった動きを取ろうと考えるのですが、既に開発環境では動作の問題が無いことを確認できていました。

## マイグレーションが正しく動作して`parent_id`が追加されているか
まず、エラーメッセージで`undefined method 'parent_id='`と表示されていたので、`parent_id`がDB上に正しく反映されているかを確認することにしました。というのも`parent_id`は今回Pushした機能で初めてDBに追加したカラムだったからです。
それと`parent_id=`と`=`が末尾に付いているのが不自然だな、と初見での気付きでした。

コマンドラインから下記のコマンドを実行することでHeroku内のDBを操作できます。
`heroku pg:psql -a アプリ名`　※アプリ名はHerokuのサイトから取得
データベースに接続後はSQL操作をできるようになります。
※`select * from users;`など
テーブル一覧の表示は`\dt`
操作を終了する時は`quit`でローカルのコマンドラインに戻ります。

実際にparent_idカラムの有無を確認したところ、見つけることができました。![スクリーンショット 2024-09-12 6.25.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/6eefada2-bcd8-adbd-1da1-f4e65f135324.png)

## `parent_id'カラムが認識されているかどうかを確認
`parent_id`は確認できましたが、Herokuのデータベースが最新のスキーマに追従していない可能性があります。`heroku run rails db:migrate`を実行してもデータベースが適切に同期していないことがあるため、データベースの状態を確認することにしました。
`heroku run rails db:schema:dump`
上記のコマンドを実行することで、Herokuのデータベーススキーマがローカルの`db/schema.rb`に保存されます。その中のテーブル内で`parent_id`が正しく追加されているかを確認します。
※データベーススキーマ：データベースの設計図のようなもの

:::note warn
また、コマンドを実行するとその時点で記載されているローカルのデータベーススキーマは上書きされて消えてしまいます(再取得は可能)。
消えたら困るという方は事前にバックアップを取りましょう。
ローカルでのスキーマ再生成は`rails db:migrate`で可能です。
:::

以下は`db/schema.rb`の中身
![スクリーンショット 2024-09-12 6.44.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/e03e6f7d-4087-7234-1cca-8e0c41dbfd26.png)
`parent_id`カラムの確認ができました。

## キャッシュの問題を疑う
次にHeroku(本番環境)で、モデルやスキーマのキャッシュが残っていることが原因で、カラムが認識されていない可能性を疑いました。

Herokuのキャッシュをクリアして再デプロイを試みます。

`heroku run rake tmp:chache:clear` キャッシュをクリア
`heroku restart`　再起動

これにより、Herokuのキャッシュがクリアされ、最新のスキーマが適用されるはずです。

私の場合はこの対策をすることで冒頭のエラーは解消され、アプリが正しく動くようになりました。

以上、最後まで読んで頂きありがとうございます。

読まれた方のお役に少しでも立てたら幸いです。

-今回参考にした記事一覧-
[HerokuのDBを操作する方法](https://qiita.com/ysda/items/e4e17570373dff511882)
ヨーロッパ旅行にはどちらが最適？eSIMと従来のSIMを比較

海外旅行を計画する際、スマートフォンの通信方法を考えることは重要なポイントです。特にヨーロッパのような複数の国を訪れる旅行では、eSIMと従来のSIMカードのどちらがより適しているか迷うこともあるでしょう。この記事では、それぞれのメリットとデメリットを比較し、ヨーロッパ旅行に最適な選択肢を探ります。

## eSIMとは？
eSIM（組み込み型SIM）は、物理的なSIMカードを使わずにスマートフォンに直接組み込まれたデジタルSIMのことです。eSIMを利用することで、スマートフォンの設定を通じて複数の携帯電話会社のプランを簡単に切り替えることができます。多くの最新のスマートフォンがこの技術をサポートしており、特に海外旅行での使用が増えています。

### eSIMのメリット
eSIMの最大のメリットは、異なる国を訪れる際の利便性です。例えば、ヨーロッパ内で複数の国を訪れる場合でも、現地のSIMカードを購入する必要がなく、デジタルでプランを変更するだけで済みます。また、eSIMはスマートフォン内蔵のため、物理的なカードを紛失するリスクもなく、複数のプランを同時に利用できる柔軟性もあります。

## 従来のSIMカードとは？
従来のSIMカードは、物理的なカードとしてスマートフォンに挿入されるもので、携帯電話会社の通信プランを利用するための識別情報を含んでいます。長年にわたり多くの人々に利用されており、ほとんどのスマートフォンが対応しています。ヨーロッパSIMカードで、[ご旅行中も快適なご滞在を！詳しくはヨーロッパSIMカードをご覧ください](https://www.europesimcard.com.au/)。

### 従来のSIMカードのメリット
従来のSIMカードの利点は、広く普及しており、多くの国で手軽に入手できる点です。例えば、ヨーロッパに到着した際に、空港や市内のショップで簡単に現地のSIMカードを購入し、その国の通信ネットワークを利用することができます。また、従来のSIMカードはほとんどのスマートフォンで利用可能であり、特に古いモデルでも問題なく使用できます。

## eSIMと従来のSIMカードの比較
### 利便性の違い
eSIMは、旅行中に新しいSIMカードを探し回る必要がないため、時間と手間を大幅に削減します。一方、従来のSIMカードは、現地の通信料金が安い場合にはお得な選択肢となりますが、各国で別のSIMを購入する必要があるため、手間がかかる場合があります。

### コストの比較
eSIMは、複数国で利用可能な国際的なプランが多く提供されており、一度の購入で複数の国で使えるケースが増えています。ただし、これらのプランは従来のSIMカードに比べて割高な場合もあります。一方、従来のSIMカードは、特定の国での利用を前提としたプランが多く、短期間の利用であればコストを抑えることができます。次のご旅行を計画中ですか？[必要な旅行データ量をご確認ください](https://www.europesimcard.com.au/travel-data-how-much-do-you-need/)。

## ヨーロッパ旅行にどちらが向いているか？
ヨーロッパ旅行での最適な選択は、旅行者のニーズと予算に依存します。頻繁に国境を越える場合や、複数国でのデータ通信が必要な場合はeSIMが便利です。一方、特定の国で長期間滞在する予定がある場合は、現地のSIMカードを購入する方が経済的な場合もあります。最終的には、自分の旅行スタイルに最も合った方法を選ぶことが重要です。
RevenueCatを使ったサブスクリプション管理と私たちのアプリケーション

![ae6dd120-482e-4941-9d10-1149f828e419.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882896/7ff4352f-eb3f-4a91-3a8f-19d711145f07.png)


:::note info
## はじめに
こんにちは！今回は、私たちのハッカソンプロジェクトで導入したRevenueCatについてご紹介します。RevenueCatは、App StoreやGoogle Play Storeでの複雑なサブスクリプションシステムのサポートをシンプルにするためのモバイルSDKおよびAPIです。RevenueCatを利用することで、サブスクリプションの管理が容易になり、ビジネス運営に専念できるようになります。
:::

## RevenueCatとは？
RevenueCatは、アプリ内のサブスクリプション管理を一括で処理してくれるツールです。App StoreやGoogle Playでのサブスクリプションの購入、管理、解約、復元といった操作を簡単に実装でき、開発者はより重要な機能開発に時間を割くことができます。

**主な機能としては次のものがあります：**
- サブスクリプション管理：定期購入の状態を追跡し、更新やキャンセルの処理を行います。
- 収益レポート：アプリの収益状況を詳細にレポートし、ユーザーの行動分析も可能。
- クロスプラットフォーム対応：iOSやAndroidといった複数のプラットフォームに対応しているため、コードの重複が少なくなります。
## RevenueCatのメリット
RevenueCatを使うことで、私たちのアプリケーション開発がどれほど効率化されたか、具体的に説明します。

**1. 迅速なサブスクリプション機能の実装**
サブスクリプションのバックエンドシステムをゼロから開発する必要がなく、RevenueCatを使うことで最小限のコードで導入できました。

**2. クロスプラットフォームのサポート**
私たちのアプリはiOSに対応しており、RevenueCatが提供するAPIはそのまま両方のプラットフォームで使えたため、デバイス間でのデータ整合性もスムーズでした。

**3. サブスクリプションデータの一元管理**
RevenueCatを使うことで、各プラットフォームで得られるサブスクリプションデータを一元管理し、リアルタイムで追跡できるようになりました。
## 私たちのアプリとRevenueCatのサブスクリプション
私たちのアプリケーションは、タスク管理や目標設定を支援するAI搭載のツールです。ユーザーはタスクを入力したり、AIに目標を相談することができます。AIはそれに基づいて適切なタスクを自動生成し、優先度をつけて表示します。

アプリケーションには3つのサブスクリプションプランがあり、各プランに合わせた機能を提供します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882896/5e825057-5aff-1a84-2ce8-bad918305ff7.png)


**フリープラン**
- 音声を使ってメモを記録、チャットが可能
リマインダー設定
タスク作成と優先順位付け
使用制限あり

**プロプラン**
- AIによるタスクの優先順位付け
複数リストやツールへのアクセス
会議やスケジュールとの統合
目標とルーチンの設定

RevenueCatを使うことで、これらのサブスクリプションプランを簡単に管理できるようになりました。例えば、フリープランのユーザーがプロプランにアップグレードした際も、RevenueCatが自動的にその変更を追跡し、アプリ内での機能制限を動的に適用することができます。また、定期購読の解約や復元もワンクリックで行え、開発者側で複雑な処理を行う必要はありません。

### まとめ
RevenueCatを活用することで、私たちは短期間でサブスクリプション機能を実装し、開発効率を大幅に向上させることができました。今後、より多くのユーザーに便利なサブスクリプションサービスを提供し、アプリの成長を目指していきたいと思います。
エラーメッセージ「Rack::Multipart::MultipartTotalPartLimitError (Maximum total multiparts in content reached)」の対処法


## はじめに

担当システムのブログ投稿機能がありまして、お客様からブログが投稿できないというお問い合わせをいただきました。投稿ボタンを押しても反応がないという風にご連絡をいただきました。原因調査のため、ブログの投稿ボタンを押した際、Chromeの開発者ツールのネットワークタブでレスポンスを確認したところ、500エラーで返却されておりました。さらに詳細な原因を特定するためにAWSのログを確認したところ、エラーメッセージ「Rack::Multipart::MultipartTotalPartLimitError (Maximum total multiparts in content reached)」に遭遇しました。


## 使用技術
Rails 5.1.6
Vue.js 2系
AWS(EC2、RDS、S3、Cloud Watch等)


## 原因

担当システムのブログ機能にはカテゴリやタグを設定できます。ブログの投稿ボタンを押した際、フロントエンド→バックエンドへのパラメータに過去から現在まで作成していたタグを全て送信していたことが原因でした。

以下のコードでパラメータの数をチェックしており、デフォルトだと4096までになっておりました。それを超えるとエラーメッセージ「Rack::Multipart::MultipartTotalPartLimitError (Maximum total multiparts in content reached)」を出力されるようになっておりました。


https://github.com/rack/rack/blob/3d0b9f377a4753d1fca40fca011c2c0e9282ab50/lib/rack/multipart/parser.rb#L192C52-L192C95

https://github.com/rack/rack/tree/v2.2.9?tab=readme-ov-file#multipart_total_part_limit-

## 一時的な対応

ユーザ様が相当お急ぎで何度も弊社に問い合わせの連絡が来ておりましたため、とにかくブログを投稿できるようにする必要がありました。現在ではパラメータの制限がデフォルト値でしたため、それを一時的に制限解除するようにしました。

以下を「config/initializers/multipart_part_limit.rb」を新規で作成して、以下を定義しました。そして、定義後に本番環境のプロセスを再起動しました。(githubのコードを見ると、今回のエラーメッセージではmultipart_part_limitの制限は解除する必要はなかったかもしれませんが、、)
```
Rack::Utils.multipart_part_limit=0
Rack::Utils.multipart_total_part_limit=0
```

ちなみにですが、envファイルに上記の定義を追記して、プロセス再起動をしてもうまく機能しなかったため、initializersの下にファイルを作成しました。

## 恒久対応

ブログの投稿ボタンを押したタイミングで今まで作成していたタグをフロントからバックエンドに送信する仕組みの見直しました。投稿ボタンを押したタイミングでバックエンド側でタグの新規作成、削除、編集、記事とタグの紐付け処理などを一度に行なっておりました。上記のような実装にしていると以下のような問題がありました。

- コードが複雑になってしまい、可読性が低く、バグが発生しやすい。(過去にもこの処理がバグっており、ブログが投稿できないとお客様から問い合わせがありました、、)
- タグを作成や編集、削除などの処理をした後にブラウザをリロードすると、更新処理が全て消えてしまいます。投稿ボタンを押さない限り、タグの変更が反映できない仕組みなっていたため。

上記の問題を解決するため、タグを作成、削除、編集などを行なったら、それぞれの処理をバックエンド側で即座に処理するようにしました。Rails側でタグを作成、削除、編集などを行うためのAPIをそれぞれ実装しました。また、Vue.js側でもタグの更新処理を行なったら、即座にAPIを呼び出すようにしました。

今回の対応でお客様が意外にもタグを900件以上作成していたことも知れたため、Rails側のパフォーマンスにも気をつけて実装しました。具体的には以下です。
- N + 1が起きないように実装。DBからのデータ取得の際にpreloadを使用して、事前に読み込みを行いました。
- ブログ記事とタグの紐付け件数をフロントエンドで使用していたため、countメソッドではなく、sizeメソッドを使用。
- タグの更新処理を行なったら、タグ全量をフロントエンドに返却するのではなく、差分だけを返却するようにしました。（新規作成したタグのみ、編集したタグのみをフロントに返却。）


## 学び

今回は技術的に学びが多い障害対応でした。フロントエンドからバックエンドへのパラメータ数に制限があることは今まで知りませんでした。Rackというのがパラメータ数のチェックをしていることも今回初めて知りました。まだRackに関する深いところまでは理解できていないたため、今後学習していこうと思いました。

また、設計が本当に大切だと身にしみて感じました。設計が良くないと可読性だけでなく、品質面でもパフォーマンス面でも良くないコードになってしまうことを学びました。今回修正したコードは私が実装した箇所ではなかったものの、アンチパターンを知ることができてとても勉強になりました。