OmniAICreator/Qiita-1.07M huggingface dataset:
Flutter 〜ダークモードの設定〜

## ダークモード
MaterialAppウィジェットのdarkThemeパラメータを使ってアプリにダークテーマを指定する。
　
## 前半部分
mainでプログラムを実行する。

```dart
import 'package:flutter/material.dart';

// メイン関数。アプリケーションのエントリーポイント。
void main() {
  runApp(const MyApp()); // MyApp ウィジェットを起動。
}

```
## メイン部分
darkThemeの指定をする。

```dart
// アプリケーションのルートウィジェットを定義する StatelessWidget クラス。
class MyApp extends StatelessWidget {
  //コンストラクタ。キーを省略可能にする
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    // MaterialApp ウィジェットを構築し、アプリの基本設定を行う。
    return MaterialApp(
      title: 'Flutter Demo', // アプリのタイトルを設定。
      darkTheme: ThemeData(
        // ダークテーマの定義。
        brightness: Brightness.dark, // テーマの明るさをダークに設定。
        colorScheme: ColorScheme.dark(
          primary: Colors.deepPurple, // ダークテーマのプライマリカラーを紫に設定。
        ),
      ),
      home:
          const MyHomePage(title: 'Flutter Demo Home Page'), // ホーム画面のウィジェットを指定。
    );
  }
}

```
 
## 画面描画部分

```dart
// ホームページを表す StatelessWidget。
class MyHomePage extends StatelessWidget {
  final String title; // ページのタイトルを格納する変数。

  // コンストラクタ。タイトルを必須引数として受け取る。
  const MyHomePage({super.key, required this.title});

  @override
  Widget build(BuildContext context) {
    // Scaffold ウィジェットを使用して、基本的なビジュアルレイアウト構造を提供します。
    return Scaffold(
      appBar: AppBar(
        title: Text(title), // アプリバーにページタイトルを表示。
      ),
      body: Center(
        child: Text('Welcome to $title'), // ボディの中央にテキストウィジェットを配置。
      ),
    );
  }
}

```

## 全部を繋げる
こうなる。

```dart
import 'package:flutter/material.dart';

// メイン関数。アプリケーションのエントリーポイント。
void main() {
  runApp(const MyApp()); // MyApp ウィジェットを起動。
}

// アプリケーションのルートウィジェットを定義する StatelessWidget クラス。
class MyApp extends StatelessWidget {
  //コンストラクタ。キーを省略可能にする
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    // MaterialApp ウィジェットを構築し、アプリの基本設定を行う。
    return MaterialApp(
      title: 'Flutter Demo', // アプリのタイトルを設定。

      darkTheme: ThemeData(
        // ダークテーマの定義。
        brightness: Brightness.dark, // テーマの明るさをダークに設定。
        colorScheme: ColorScheme.dark(
          primary: Colors.deepPurple, // ダークテーマのプライマリカラーを紫に設定。
        ),
      ),
      home:
          const MyHomePage(title: 'Flutter Demo Home Page'), // ホーム画面のウィジェットを指定。
    );
  }
}

// ホームページを表す StatelessWidget。
class MyHomePage extends StatelessWidget {
  final String title; // ページのタイトルを格納する変数。

  // コンストラクタ。タイトルを必須引数として受け取る。
  const MyHomePage({super.key, required this.title});

  @override
  Widget build(BuildContext context) {
    // Scaffold ウィジェットを使用して、基本的なビジュアルレイアウト構造を提供します。
    return Scaffold(
      appBar: AppBar(
        title: Text(title), // アプリバーにページタイトルを表示。
      ),
      body: Center(
        child: Text('Welcome to $title'), // ボディの中央にテキストウィジェットを配置。
      ),
    );
  }
}

```
21日目 Lambdaについてまとめてみる社畜S


## 🎏はじめに
こんにちは、ローテが一巡して順番が回ってきました、三週間ぶりの社畜Sです。
現在、私たち社畜SMLの3人は  
#### 「AWS Certified Solutions Architect - Associate（通称SAA）」
の合格を目指して勉強を続けています。  
というわけで、今回のローテではSAAの学習成果のアウトプットも兼ねて
#### 「AWSのサービスを初心者目線でまとめてみた。」
をテーマに書いていこうと思います！  
まずは私、社畜Sが初回を飾り **AWS Lambda** についてまとめていきます！  
初心者の視点からの解説ですので、間違いなどがあればコメントで指摘していただけると幸いです。  
それではやっていきましょう！  

---
## 🎏そもそもLambdaって何？<br> 
公式の開発者ガイドでは
>AWS Lambda はサーバーのプロビジョニングや管理をする必要がなく、コードを実行できるコンピューティングサービスです。
>>Lambda は可用性の高いコンピューティングインフラストラクチャでコードを実行し、コンピューティングリソースに関するすべての管理を行います。これには、サーバーおよびオペレーティングシステムのメンテナンス、容量のプロビジョニングおよび自動スケーリング、さらにログ記録などが含まれます。Lambda で必要なことは、サポートするいずれかの言語ランタイムにコードを与えることだけです。Lambda サービスは、必要な場合にのみ関数を実行し、自動的にスケーリングします。消費したコンピュート時間に対してのみ課金されます。コードが実行されていない間は料金は発生しません。  

…と定義されています。  
初心者の私からしたら横文字が多すぎてなんのこっちゃって感じですね。とりあえず  
* サーバーの管理不要でコードを実行できる（サーバー、OS、リソースなどの管理を自動化する）
* 高い可用性を持つ
* 自動的にスケーリングする
* 使った分だけお金がかかる（**従量課金制**）

という点を把握しておけばSAA範囲内では大丈夫だと思います（多分）。  
ここだけ見ると全部に使えるような完璧なサービスと思えますが…もちろんメリットだけでなくデメリットも存在します。よくLambdaが使われる事例と合わせて紹介しようと思います。 

---

## 🎏Lambdaを活用できる/できない事例
### できる！
### ・イベント駆動型アプリケーションの開発
イベント駆動型アプリケーションは、簡単にいうと「特定のイベントがあったときに指定された処理を自動的に行うアプリケーション」のことです。  
 複数のAWSサービスからのイベントに反応できるのに加え、自動スケーリングと従量課金制によって**低コストで高可用性を実現**できるという点がよくつかわれる理由のようです。
 
### ・APIのバックエンド処理
APIのバックエンド処理とは、クライアントなどからのHTTPリクエストを受け取り、それに応じてデータを処理し、適切なレスポンスを生成する処理のことです。  
先ほどと同じように低コストで高可用性を実現できるのはもちろん、**API Gateway**というクライアントとバックエンドのサービスとの間の通信を仲介するサービスと組み合わせることでAPIのバックエンド処理を簡単に実装し、公開することができる点が優れているようです。 

---
### できない...

### ・長時間実行が必要な処理
Lambdaには、最大実行時間が15分までという制限があり、この時間を超えてしまうとLambdaの実行を強制的に中断してしまいます。そのため、長時間実行が必要なバッチ処理やデータ処理など、実行時間が15分を超える処理をLambda単体で行うには向いていません。
15分以上かかる処理を実行したい場合は**AWS Step Functions**等と組み合わせたり、代わりに**Amazon EC2**などを使うこともあるようです。（EC2については来週投稿予定！）
### ・外部のサーバー等との直接的な連携が必要な処理
LambdaはAWS内のサービスとの連携が得意であり、APIなどを介して他のAWSサービスと直接的な連携を行いますが、外部のサーバー等との連携はプロキシ制約やネットワーク制約など様々な制約がある関係上向いていないようです。  
一応他のサービスと組み合わせることで連携できなくはないようですが、管理の手間が増加したり、コストが増加したりするので十分な検討が必要になるようです。
この場合は**Amazon ECS**（こっちは再来週投稿予定！）などを使うこともあるようです。  

---

## 🎏まとめ

ということで、AWS Lambdaについて私が調べてみたことをまとめてみました。  
まとめる前から様々な用途に使うみたいでまとめるのが難しそうだなー…と思っていましたが、いざ調べてみると想定よりも情報量が多く、今回の投稿ではまとめ切れていない部分も多く出てきてしまいました。  
基礎的な部分のみになってしまいましたが、この記事が私たちのようにこれからAWSについて学習する人の手助けに少しでもなってくれればと思います。  
来週の「AWSのサービスを初心者目線でまとめてみた。」もお楽しみに！
BCM3383中間報告

とりあえずinitさんまで到達したので、中間報告です。

https://dmesgd.nycbug.org/index.cgi?do=view&id=7727

# 課題

* uartをちゃんと作る

BCM3383は16550A系ではなくて、独自仕様なのでそのコードが必要。FreeBSDは起動時のuart_cpuとデバイス認識後のuart_busでuartがサポートされているが、それと元となるuart_devを作る必要がある。とりあえず割り込みの処理を作ってみた。ボーレートの設定などはまだ作ってない・

* 割り込み処理

~~INTRNGでビルドしてあるが、SOC独自のPIC系の割り込みを動くようにする。~~ INTRNGを止めて動くようになっている。

* loginプロンプトがでない

~~uart由来の問題と思われるが。。。~~　uartの割り込み処理を作ったところ出た。

* USBが見えない

~~EHCI,OHCIが見えません。入り口のコードは書いてありますが、見えれば既存コードでサポートできると思う。~~ BCM3383のEHCIのコードは書いたが、USBの回路がないので試せてない。OHCIはオリジナルもコメントアウトしてあって、動かないのかもしれない。BCM3380はOTGで仕様が不明。

* GPIOが中身がない

スケルトンコードだけ入れてあるので、中身を書く。

* Ethernetサポート

~~BCM4系のbgmacが使えるかな。~~ これもBCM3383とBCM3380は違っていて、どちらも仕様不明で未着手。

* マルチCPU対応

動くのかな？

* コードのクリーンナップ

いろいろコピーしたが残骸が残っているので、クリンナップする。

* resetができない

仕様が分かりません。

* 遅い

~~クロックやメモリコントローラーの設定が必要なのではないかと思われます。~~ BCM CP0のCP0_BCM_CFG_ICSHEN,CP0_BCM_CFG_DCSHENを設定をしたところ早くなりました。CFEでは設定されるようですが、このターゲットのブートローダーでは設定していないようです。

* BCM3380サポート

~~かなり近いアーキテクチャでターゲットもあるので、サポートしたいがbootloaderが見えないので、考え中。~~ BCM3383といろいろ違っているので難しいかも。

あとmips/atheros/ar531xのファイルをいくつかコピーしたが、これも少しクリーンナップしたい。
プロパティのショートハンド記法

# 初めに

buildの実行で発生したエラーを解決できたので、共有します。

# 問題

```res.status(500).json({ error.error }); ``` で以下エラーが発生しました。

Expected property shorthand.eslint（object-shorthand）

```typescript
import { NextApiRequest, NextApiResponse } from 'next';
import { todoData } from '@/data/todoData';

const handler =  (req: NextApiRequest, res: NextApiResponse) => {
  try {
    res.status(200).json(todoData);
  } catch (error) {
    res.status(500).json({ error.error });
  }
};

export default handler;
```

# 原因

ESLintのルールである``` object-shorthand ```がプロパティのショートハンド記法の使用を期待しているからです。このルールは、オブジェクトリテラル内で変数名とプロパティ名が同じ場合に、ショートハンド記法を使うことを推奨しています。

# 解決方法

エラーも消えて、記述量も減りました。

```typescript
res.status(500).json({ error });
```

# 終わりに

ESLintのルールを知れたので、学びになりました。
StableDiffutionを触ってみた記録

StableDiffutionを触ってゲームとかする時用のアイコンを作ってみたので、また触るときに思い出せるように軽く残しておきます。
気が向いたら直すかもですが、雑に書きます。

## 触ってみた感想とか
ローカルにダウンロードして動かしてみたけど、やっぱり重いなと感じました。
ある程度の攻勢を決めるまでは、パラメータを低くしてある程度は回転率を上げていきたい。
GoogleColabとかVM使ってやったほうが良かったかも

あと１回で複数の画像を生成したほうが、望んでいる構成を見つけやすかった印象

最初はプロンプトにどんなものを入れたらいいかわからないから、サイトとかでほかの人のプロンプトを参考にしたり、img2imgから始めたりするのがいいのかも
１回のプロンプトで求めているものを出すより、生成した画像からさらに生成していって、ちょっとずつ理想に近づけていく感じ（プロの方とかは違うのかもだけど、、、）

mov2movもやろうと思ってたけど、動かなかったからまた次回

モデル大事！！

## 実行環境
- Win11
- Core i9-12900k
- RAM 16
- RTC 3070

世代はちょっと前だけど、まあそこそこかな？
金額でいえば25くらい

## モデル
最初はデフォルトのモデルでやってたけど、モデルを変えてから全然違った

[HimawariMix](https://civitai.com/models/131611/himawarimix)
[Anime Pastel Dream](https://civitai.com/models/23521?modelVersionId=28089)
[blue_pencil](https://civitai.com/models/79083/bluepencil)

このあたりを試したけど、最終的にはHimawariMixを使わせてもらっていました。

[civitai.com](https://civitai.com/)
ここでモデルを探したり、プロンプトの参考を探したり
[chichi-pui](https://www.chichi-pui.com/)
あとはこっちでもプロンプトの参考になりそうなのを探してました。

## プロンプト
最初っからいろいろ情報を入れるより、少ないところから足していく感じのほうがこんがらがらなそう
プロンプトには
masterpiece, best quality
ネガティブに
(worst quality, low quality:1.4), (bad_prompt_version2:0.8), EasyNegative, badhandv4, text, name, letters, watermark, unnatural fingers
を基本的に入れて、そこから 1 boy, grasses, upper body, blackcolor hairとか追加で入れていく感じ

ネガティブプロンプトのEasyNegativeはググってください

あとはほかの人のプロンプトを、GeminiとかChatGPTにぶち込んで解説させれば、なんとなく理解していけるのかなといった感じ

## パラメータ
詳しくはググってください

- Stepsは精度。構成を考えるうちは20とかでやって、決まってきたら45くらいで結構きれいになる
- scaleはよくわかんないけど、7 ~ 15くらいを適当にいじる
- sizeは基本 512×512。横長とかにするなら、StableDiffutionの得意な値にしてあげたほうがいい
- seed 目指す画像。いい感じのものができたら、それのseedをここに指定してあげるといい
- Denosing strength img2imgでどれくらい元の画像から離れた感じにするか。0.2とかだとほぼ変わらん
- countだっけ？ 生成する画像の数。4でやることが多かった。Apexしながらなら9とか

他の値はいじってたのもあるけどだいたいデフォルト

## 進め方
他の人がどうやっているのかは知らない
1. とりあえずで生成してみてモデルを決める（1 boy, grasses とか）
1. プロンプト、ネガティブを追加して理想に近づけていく
1. 少し近づいたなと思ったら、その画像をimg2imgに入れたり、seedに設定してずれないようにする
1. いったんstepsを45とかにしてきれいにする
1. 細かいところをinpaintとかで変えていく
1. きれいにして仕上げる

いらないものがあったときは、inpaintよりGoogleの消しゴムマジックとかで消しちゃったほうが早かったりするかも

## まとめ
めっちゃ時間かかった
PCめっちゃうるさくなるし、次やるときはColabでやろうかな

最初に生成したものと、最終的にこれでいいやってなってIconにしたものを張っておきます。
![00000-3795640118.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125193/69706348-ead8-60de-e82c-e4a1216cd43c.png)
![完成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125193/0b98de23-d252-38ae-0eab-43c00416e09a.png)

ヘッドフォンにOTAって入れたのは画像の上から落書きして、再度img2imgしました。
画像サイズが512*512じゃないのは、頭が途切れてたから、拡張しました。これもめっちゃ時間かかった

理想があってそれに近づけようとすると大変だけど、なんとなくいい感じのものが欲しいだけなら、モデル選んでtxt2txtで生成すれば結構簡単そうかなといった感じでした。

次はローラとか触りたい
ATtiny202でシリアル通信が文字化けする？

## TL;DR

platformio.iniに以下を追加。
board_build.f_cpu=20000000L

## 現象

``` main.cpp
Serial.begin(115200);
Serial.println("Hello world");
```
とかが文字化けするのです。ターミナルの設定を確認してみたりもしましたが、正しいような気がするのです。

## なんでわかったの？

これも現象といえば現症なのですが、tone()で指定した周波数より高い音が出てるんですよ。絶対音感があって良かったと思える数少ない経験であります、笑。

## からくり

platformioのデフォルトではCPUクロックは16MHzだと思っているようです。ところがマイコンのeFuseでは20MHz系が設定されています。そのまま動かすと時間関連が早回しになります。

## 結論

ということで、eFuseを16MHz系に修正するか、platformio.iniでクロック数を20MHz系にするかのどちらかということになります。たぶん後者のほうが楽です。
``` platformio.ini
board_build.f_cpu=20000000L
```

5MHz, 10MHz, 20MHzで動作することは確認しました。

では、楽しいTinyライフを！
【Oracleデータベース】メタデータ

アプリ開発者は「顧客テーブル」「注文テーブル」「商品テーブル」のような業務データ、いわゆるメタではないデータにアクセスすることがほとんどで、メタデータは未知の領域となっていた。

そこでOracleのメタデータの確認方法についてライトにまとめた。

# 1. メタデータを保持するテーブル・ビュー

DICTIONARYビューでメタデータを保持するテーブル・ビューの一覧を確認できる。
(…という記事を見たが、ここに載っていないビューもあるようだ。。。
全てが載っているビューはどれだろう。。。)

```sql
SELECT * FROM DICTIONARY;
```

## 1-1. 静的データ・ディクショナリ
データベースに関する管理メタデータ。

データ・ディクショナリが変更された場合(たとえば、新しく表が作成されたり、ユーザーに新しい権限が付与された場合など)のみ変更される。

所有者はSYSユーザー。
実表とビューがある。

- **実表(静的データ・ディクショナリ表)**
Oracleだけが読み書き可。ほとんどが暗号化されておりユーザーが直接アクセスすることを目的としていない。

- **ビュー(静的データ・ディクショナリ・ビュー)**
実表をユーザーが見ることを目的として加工したビュー。読み取り専用。

### 静的データ・ディクショナリ・ビュー
表示される情報の範囲に応じて以下3種類のビューに分類される。
また、SELECT文を実行したユーザーの権限によって閲覧できるビューやその内容が異なる。


- **USER_ビュー**
"USER_"から始まる名前のビュー。
自己が所有するオブジェクトの情報。

- **ALL_ビュー**
"ALL_"から始まる名前のビュー。
権限が付与されている範囲で閲覧可能な全ての情報。

- **DBA_ビュー**
"DBA_"から始まる名前のビュー。
データベース全体の情報。
SELECT ANY TABLE権限を持つユーザーのみが閲覧可能。

### CDBアーキテクチャの場合
CDBRootとPDBのそれぞれがデータ・ディクショナリを持つ。

- **CDBのデータ・ディクショナリ**
CDB全体に関わるメタデータを保持している。
"CDB_"から始まる名前のビュー。

- **PDBのデータ・ディクショナリ**
親であるCDBRootのデータディクショナリと、自分自身(各PDB固有)のデータディクショナリから成る。CDBRootのデータディクショナリについては、実データではなくポインタを保持している。

## 1-2. 動的パフォーマンス・ビュー(**V$ビュー**)
進行中のデータベース・アクティビティを監視するビュー。

データベースがオープンしている間、セッションやメモリ、ロックの獲得状況といった内部的な情報が継続的に更新される、参照専用の特別なビュー。

データファイルではなく内部ディスク構造およびメモリー構造のデータが表示されるので、一部のV\\$ビューはオープン状態でなくても参照できる。(仮想ビュー)

実ビューの接頭辞は"V_\\$"で、閲覧用のシノニムが接頭辞"V\\$"。

所有者はSYSユーザー。

SYSユーザーまたはSYSDBA権限が付与されているユーザーのみがアクセス可能。

### V$ビュー
"V$"から始まる動的パフォーマンス・ビュー。
動的パフォーマンス・ビューの別称でもある。

### GV$ビュー
グローバルV\\$ビュー。
"GV\\$"から始まる名前の動的パフォーマンス・ビュー。
ほとんどすべてのV\\$ビューに対応するGV\\$ビューが存在する。
V\\$ビューにはない、`INST_ID`列が存在する。

使いどころはRAC環境。
RAC環境でGV\\$ビューを参照すると、`INST_ID`列からインスタンスを特定できる。

# 2. メタデータを返すOracleパッケージ関数

Oracleが提供するパッケージ関数にメタデータを取得できるものがある。

たとえば[DBMS_ROWIDパッケージ](https://docs.oracle.com/cd/E82638_01/arpls/DBMS_ROWID.html#GUID-BEBBE522-9559-4433-9278-9F37C4917E02)。


# 参考文献

https://docs.oracle.com/cd/F82042_01/cncpt/data-dictionary-and-dynamic-performance-views.html#GUID-BDF5B748-EB43-4B48-938E-89099069C3BB

https://www.reqtc.com/blog/dictionary.html

https://www.reqtc.com/blog/dynamic-view.html

https://www.reqtc.com/blog/oracle-19cview-20220707.html

http://www.mitene.or.jp/~rnk/TIPS_ORCL_CRE_PACK.htm

https://docs.oracle.com/cd/E96517_01/arpls/introduction-to-oracle-supplied-plsql-packages-and-types.html

https://dekiruengineer.com/engineer/oracle_database_rac_gvsession/
【Oracleデータベース】概念・アーキテクチャ

Oracleデータベースの概念・アーキテクチャを理解するための個人メモ。

# 1. オブジェクトとスキーマ

### オブジェクトとは

表、ビュー、インデックス、プロシージャ、ユーザーなど、Oracleデータベースの世界に登場する様々な種類のアイテム。

スキーマに所属するスキーマ・オブジェクトと、所属しない非スキーマ・オブジェクトに分類される。

- **スキーマ・オブジェクト** の例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/1c03f0fd-500c-8111-d30d-7da8b94dfe4d.png)

- **非スキーマ・オブジェクト**の例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/e5d58567-f2fd-8a50-6af2-7c4e3a7ffbcd.png)

[【Oracle - オブジェクト一覧】](https://docs.oracle.com/cd/F19136_01/sqlrf/Database-Objects.html#GUID-1B1818AD-6A70-4C2A-8E86-98BECA723FB8)

### スキーマとは
ユーザーが所有するオブジェクトの論理集合。
各ユーザーが自分のオブジェクトを格納するために与えられるホームベースのようなイメージ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/1d7aa933-d04f-aeca-5108-967e0f1b0e28.png)

### ユーザーとは
非スキーマ・オブジェクトの一種。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/bb945712-e95b-f475-b42d-3fc5e813bd06.png)
1つのユーザーは1つのスキーマを所有する。
ユーザーを作成するときに同名のスキーマも作成され、ユーザーはそのスキーマの所有者となる。

ユーザーは、別ユーザーの所有スキーマにも、権限があればアクセスできる。
```sql:別ユーザーのスキーマにアクセスする例
SELECT * FROM スキーマ名.テーブル名;
```

# 2. 論理データ構造(表領域)

例えばあるテーブルにINSERTしたデータは、どれかしらの「表領域」の中の「データ・ブロック」に格納されている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/f3f29c40-0358-c28b-7831-1bd8b605bf8d.png)
[(引用元)](https://atmarkit.itmedia.co.jp/ait/articles/0809/22/news115.html)

- **表領域**　1つの表領域に0~複数個のオブジェクトのデータを格納している。
物理的には、1つ以上のデータファイルから成る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/ea577d29-2873-6eba-52ac-a2d23af3760c.png)

- **セグメント**　あるオブジェクトを構成するデータ全体を指す。
物理的には、ある表領域を構成するデータファイルたちの中で1箇所にまとまっているわけではなく、欠片(エクステント)になって散らばっている。同一荷主の複数伝票てきな。

- **エクステント**　複数の連続したデータ・ブロック。複数個口の荷物てきな。
- **データ・ブロック**　データを詰めた1つの段ボール箱てきな。

# 3. ソフトウェア構造

### インスタンスとは
SGA(共有メモリ) + バックグラウンドプロセス を指す。
メモリ上に展開される構造。

- バックグラウンドプロセスの一部
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/b987460e-9b5c-f466-f416-4f2e21f9a063.png)
```sql
select PID, PNAME, PROGRAM from V$PROCESS
where PNAME is not null
```

### データベースとは
インスタンスの対義語としてのデータベース。
物理ファイルの集合。ストレージ。

- 主要ファイル
    - **データファイル**　どれかしらの表領域の情報を格納している。
    - **REDOログファイル**　データが変更された時に即座にデータファイルの複数個所に直接書き込みにいくと時間がかかるので、代わりに一箇所にまとめようということで存在する変更履歴の情報。
    - **制御ファイル**　これがないとデータファイルやREDOログファイルの場所が分からない。
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/ebf9a7b2-a392-1782-e021-b44679d6d095.png)

### サーバープロセスとは
バックグラウンドプロセスに対してフォアグラウンドプロセスとも呼ばれる。
1つのコネクションを1つのサーバープロセスが担当。(専用サーバープロセスの場合)

### リスナープロセスとは
リモート接続の受付窓口。
クライアントからリクエストが来たらコネクションを確立し
サーバープロセスに引き渡す。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/c3aae060-cc85-d55b-d5cd-e5ea624d3a3f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2271094/46046132-a5b0-90e4-672e-b7d43c233888.png)

[(引用元)](https://www.oracle.com/jp/a/tech/docs/technical-resources/0420-1330-oracle-architecture.pdf)
yarn、npm、npx の違いについて

# yarn、npm、npx の違い


## はじめに

Node.js を学ぶ過程で、"yarn"、"npm"、"npx"という用語にたびたび出逢います。これらは JavaScript の開発において頻繁に使われる重要なツールですが、その機能や役割が初学者には混同しやすいものです。本記事では、これらのツールがどのように異なり、どのように役に立つのかを解説したいと思います。

## yarn

- **タイプ**: パッケージマネージャー（ソフトウェアのパッケージとその依存関係を管理）
- **目的**: Node.js プロジェクトの依存関係の管理
- **特徴**:
  - Facebook(meta)によって開発
  - キャッシングと並列処理により高速かつ効率的に動作
  - `yarn.lock` を使用してインストールされたパッケージのバージョンを固定
- **コマンド集(一部)**:

```sh
yarn init                 # 新しいプロジェクトの package.json ファイルを作成
yarn install              # package.json に記載されたすべての依存関係をインストール
    yarn add [パッケージ名]  # 指定したパッケージをプロジェクトの依存関係に追加。また、package.json と yarn.lock を更新
yarn upgrade [パッケージ名]  # 指定したパッケージを最新バージョンにアップグレード
yarn remove [パッケージ名]   # 指定したパッケージをプロジェクトから削除。また、package.json と yarn.lock を更新
yarn run [スクリプト]　        # package.json の scripts に定義されたスクリプトの実行
yarn cache clean          # キャッシュクリア
yarn list                 # インストールされたパッケージの一覧を表示
```

## npm

- **タイプ**: パッケージマネージャー（ソフトウェアのパッケージとその依存関係を管理）
- **目的**: プロジェクトの依存関係の管理や Node.js パッケージを npm レジストリへの公開
- **特徴**:
  - 広範なライブラリとツールを提供する最大のパッケージレジストリ
  - カスタムスクリプトとパッケージライフサイクルイベントをサポート
  - Node.js に統合されているため、インストール時に自動的で追加
- **コマンド集(一部)**:

```sh
npm init                   # 新しいプロジェクトの package.json ファイルを作成
npm install                # package.json に記載されたすべての依存関係をインストール
npm install [パッケージ名]    # 指定したパッケージをプロジェクトの依存関係に追加
npm update [パッケージ名]     # 指定したパッケージを最新バージョンにアップグレード
npm uninstall [パッケージ名]  # 指定したパッケージをプロジェクトから削除
npm run [スクリプト]　          # package.json の scripts に定義されたスクリプトの実行
npm cache clean --force    # キャッシュクリア(オプションをつけましょう)
npm list                   # インストールされたパッケージの一覧を表示
```

## npx

- **タイプ**: パッケージランナー（パッケージをインストールすることなく直接実行するためのツール）
- **目的**: グローバルにインストールせずに Node.js パッケージを実行
- **特徴**
  - npm 5.2 以降で提供
  - 事前にインストールすることなく、npm で利用可能な任意のパッケージを実行
  - 一時的なコマンドの実行やパッケージのテストに最適

## まとめ

パッケージマネージャーは "yarn" or "npm"、パッケージランナーは "npx" です。
"yarn" or "npm" の違いはあまりなさそうです。使う時になったらお好きな方を選択してください。速度が速いみたいなので、筆者の好みは yarn ですが正直違いがわからない。。。
Javaで「import文の使い方」の動作を確認してみた

# 概要

Javaで「import文の使い方」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/const/index9.html

# 実装

以下のファイルを作成しました。
```JSample9_1.java
import java.time.LocalDate;

class JSample9_1{
  public static void main(String[] args){
    LocalDate ld = LocalDate.now();
    System.out.println(ld);
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample9_1.java 
$ java JSample9_1 
2024-05-01
```

# まとめ

何かの役に立てばと。
(備忘録)pillowで画像を編集する

# はじめに

自分用の備忘録として使うことを想定しています。
ご覧になる際、理解や文章の拙いところが多々あると思われますがご了承ください。

また、仮に読んでいただけた場合、誤った理解などがあったら教えていただけると嬉しいです。

## 背景

1. pythonで画像を編集する際に、HSV表色系を介して画像の彩度や明度を操作する必要が出てきた。
2. pillowとopencvをそれぞれ試した。個人的にpillowでの操作の方が快適だった。
3. いずれ、webアプリ上でpillowを使った画像処理をさせる予定。(今回は、それぞれの処理の速さは特に考えないこととする)

HSV表色系についての詳細、またpillowやopencvの導入等については省略する。

# 実装

## 動作環境

・Windows11
・Anaconda
python 3.11.5
pillow 10.2.0

## 実装したいこと

今回実装したい処理は、

・HSV表色系への変換
・Vの値の変更
・複数の画像の連結(縦横)

## サンプルコード

```python
from PIL import Image

img = Image.open('処理したい画像ファイルのパス')
img = img.resize((128, 128))

img = img.convert("HSV") # HSV表色系への変換
h, s, v = img.split()
base_v = v
img_list = []
for j in range(3):
	v = base_v.point(lambda i: i+(32*(i-1))
	new_img = Image.merge("HSV", (h, s, v))
  imageList.append(new_img)

dst = Image.new("RGB", (128,384))
for k in range(3):
	dst.paste(img_list[k], (128*k, 0)
dst.save('出力したいファイル名')
```

### コードの簡易な説明+つまずいたこと

```python
img = Image.open('処理したい画像ファイルのパス')
```

最初に画像の読み込み。

まずはImageオブジェクトを読み込まないと処理が始められないから、変数imgに格納する。

```python
img = img.resize((128, 128))
```

画像のリサイズについて、サイズが更新されたImageオブジェクトが返される。

引数はサイズのタプルとする。括弧をつけることを忘れがち。

以下、公式のリファレンスより抜粋。

> Image.resize(*size*, *resample=None*, *box=None*, *reducing_gap=None*)
> 
> 
> 
> Returns a resized copy of this image.
> 
> **size** – The requested size in pixels, as a 2-tuple:(width, height).
> [https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.resize](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.resize)
> 


```python
img = img.convert("HSV") # HSV表色系への変換
```
Image.convert()で、任意の表色系へ変更されたImageオブジェクトが返される。今回はHSVにしたいから”HSV”と指定する。
他にもいろいろな形式に変えられるようだが、詳細は省略。

```python
h, s, v = img.split()
base_v = v
img_list = []
for j in range(3):
	v = base_v.point(lambda i: i+(32*(i-1))
	new_img = Image.merge("HSV", (h, s, v))
  imageList.append(new_img)
```
次に、明度の値を調整するために、imgを各要素に分割する必要がある。
split()メソッドを使って分割。

そして、vの値を更新する。
このとき、pointメソッドを使って変更させる。彩度なども同様の書き方で変更できる。

pointについては、リファレンスを読んでもまだ理解できていないと感じる。Imageオブジェクト全体のピクセル値を変更しているという解釈でいいのだろうか。

変更したvの値を用いて、mergeメソッドを使うことで指定形式でImageオブジェクトにできる。

```python
dst = Image.new("RGB", (128,384))
```
Image.newで出力画像を描画するためのImageオブジェクトを用意する。
```python
for k in range(3):
	dst.paste(img_list[k], (128*k, 0)
dst.save('出力したいファイル名')
```
用意したImageオブジェクトに、pasteメソッドで指定の位置に画像を張り付けていく。

引数として、Imageオブジェクトと、描画先の座標のタプル、そしてマスクを指定できる。

描画先の座標について、要素数2のタプルを指定すると、その座標が貼り付けたい画像の左上隅の座標となる。指定しない場合は要素数2のタプルの時と同様。

要素数4のタプルを指定すると、(左、上、右、下)と解釈される。

最後にImage.saveでImageオブジェクトをセーブして終了。


# おわりに

今回使わなかったけど、処理したい画像が多くなるならnumpyを導入したほうがいいかもしれない。

また、サンプルコードはpng形式のRGB画像に対して処理を行い、png形式で出力することを想定している。
試しにjpg形式を読み込んでjpg形式で出力できることも確認できた。

試してはいないが、pillowを用いる際、PNG形式を読み込んでJPG形式にするときは、透過情報のが入っていることが原因で失敗する可能性があるらしい。
仮に拡張子の変更が必要ならそれに対応するための処理の追加も必要だろう。


# 参考文献

https://pillow.readthedocs.io/en/stable/reference/index.html

https://note.nkmk.me/python-pillow-concat-images/

https://itc.tokyo/python/python-pillow/

https://valmore.work/how-to-use-pillow/

https://qiita.com/iso12800jp/items/a74852ebfd3041065aeb
自宅ネットワークにIPv6対応のDNS/DHCPサーバを建てた話

## 事の始まり
仕事でOCI証明書サービスの話が出て、自宅サーバのCockpitにOCIで発行した証明書インストールしてみっか！と思ったら、Windowsマシンからサーバにホスト名でアクセスできなかったｗ

dnsmasqでDNS/DHCPサーバを作っていて、Linuxサーバ同士では問題なかったのだけど、Windowsマシンは無線ルータのIPv6アドレスが優先DNSサーバになっていて名前解決できなかった。IPv6有効でもちゃんと名前解決できるようにしようと決意。

## 目指す姿
- 無線ルータのIPv4/v6アドレスがデフォルトゲートウェイに設定されること
- dnsmasqを動かしているサーバのIPv4/v6アドレスがDNSサーバとして登録されること

## 登場する機器およびソフトウェア
とてもシンプル。
- 無線ルータ/Aterm WX1500HP
- DNS・DHCPサーバ/dnsmasq-2.79-31.el8_9.2.aarch64
- Windowsマシン

今回の肝はおそらくAterm。家庭用の無線ルータで後述の設定ができるのはAtermしかないんじゃなかろうか。

## こうすればできるはず
無線ルータが出すRAパケットのRDNSSオプションでdnsmasqが動いているサーバのIPv6アドレスを伝えればよい。
→ 残念ながらそんな機能はAtermにはない。

dnsmasqもRAパケットを出せるようなので、こちらで伝えれば良いのでは？
→ 複数の機器がRAパケット出したらどうなるのか分からないけど、やってみるべ！

## 実装
### dnsmasqの出すRAのカスタマイズ①
そのまま実装するとdnsmasqが動いているサーバがデフォゲに登録されてしまうので対処。
```dnsmasq.conf
ra-param=<インターフェイス名>,60,0
```
60はRAの送出間隔？ AdvRDNSSLifetimeはデフォルト300っぽく、0をセットするとRAがしばらく送出されないタイミングでWindowsマシン側でDNSサーバのエントリが消えるという事象が発生。期限切れにならなきゃいいので60。もうちょっと大きい数字でも良いかも。
AdvDefaultLifetimeが0だとデフォゲとして登録されなくなる。末尾の0がそれ。

### dnsmasqの出すRAのカスタマイズ②
無線ルータが出すRAのprefixと同じものを出すために学習したものをそのまま再利用する。
あと、RAパケットのAdvOtherConfigFlagをOnにすれば、DHCPv6でDNSサーバを聞いてくるようになるのでra-statelessをセット。
```dnsmasq.conf
dhcp-range = ::,constructor:<インターフェイス名>,ra-stateless,ra-names
```
なお、ra-statelessじゃなくslaacだとAdvOtherConfigFlagがOffになる。
ra-namesは入れてみたけど、うまく動く相手がいなかった。まあ、邪魔にはならないと思う。

### dnsmasqの出すRAのカスタマイズ③
RDNSSオプションの指定はどうするのだろうと思ったら、dhcp-optionの値がそのまま使われるっぽい？ DHCPv6用の設定でもあるので、一石二鳥。
```dnsmasq.conf
dhcp-option = option6:dns-server,[<自身のIPv6アドレス(グローバル)>]
```
グローバルである必要があったかどうかは、知らないｗ

### まとめるとこんな感じ
IPv4とv6両方動くようにするにはこんな感じ。
```dnsmasq.conf
enable-ra
ra-param=<インターフェイス名>,60,0

dhcp-range = <IPv4のDHCPのレンジ(開始)>,<IPv4のDHCPのレンジ(終了)>,24h
dhcp-range = ::,constructor:<インターフェイス名>,ra-stateless,ra-names
dhcp-option = option:router,<デフォゲ(IPv4)>
dhcp-option = option:dns-server,<自身のIPv4アドレス>
dhcp-option = option6:dns-server,[<自身のIPv6アドレス(グローバル)>]
dhcp-option = option6:information-refresh-time,6h
```
リース時間やリフレッシュ時間は適当に変更してね。

### Aterm側の設定
dnsmasqと違っていろいろできないが、今回のような環境だとずばりの設定ができる。

- DHCPv6サーバ機能は「使用する(stateless)」
- DHCPv6によるDNSv6サーバアドレス通知は「OFF」
- RAオプションによるDNSv6サーバアドレス通知も「OFF」

「使用する(stateless)」はdnsmasqのra-statelessと同じで、RAパケットのAdvOtherConfigFlagがOnになる。iPhoneだとdnsmasq側のRAパケットは見てくれず、DHCPv6で問い合わせもしてくれなかった。Windowsマシンは見てくれたのに。AdvDefaultLifetimeが0だからかなあ？

家庭用の無線LANルータでこんな細かい設定ができるとはさすがAterm。
しかも、使っているのはエントリモデルですよ。

## 最後
radvd使ってRAパケットを送出する方法はぐぐれば色々出てきたけど、Atermとdnsmasqだけで済ませられたのが良かった。さーて、証明書サービスいろいろ試すかー。
【Oracleデータベース】入門者の孤独演習1：表領域

## つまづき

### 表領域を削除するときにデータファイルも一緒に削除するのを忘れてしまった
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11220003971?query=%E3%83%87%E3%83%BC%E3%82%BF%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%20%E5%89%8A%E9%99%A4%20oracle

✅ **解決方法**
OSからデータファイルを削除する。
(表領域のみを削除しようとすると、中にオブジェクトを持っていたならエラーになるはず。エラーが出ずに消せたのなら、OSからデータファイルを削除して問題ない。)

### ALTER TABLESPACEでエラーになる(表領域を変更できない)

https://oracle.programmer-reference.com/ora-32773/

✅**解決方法**
SMALLFILE表領域に対してALTER TABLESPACEはできない。
代わりに、ALTER DATAFILE を使う。

## 自主演習
[ベースにした記事](https://www.oracle.com/jp/technical-resources/articles/shibacho/dba02.html)

```sql: 表領域の演習
-- PDBにログインする (※マルチテナント構成のため)

-- データベース全体のデフォルトの表領域を確認する
select * from database_properties -- ローカルユーザーでも閲覧可
where property_name = 'DEFAULT_PERMANENT_TABLESPACE';

-- 以下SYSユーザー

-- 新しい表領域を作成する
create tablespace TEST_TBS
DATAFILE 'test_tbs_datafile'
SIZE 5m -- 5MB;

-- 表領域の情報を確認する
select tablespace_name, bytes, file_name
from dba_data_files;

-- 表領域のサイズを変更する
-- alter tablespace TEST_TBS resize 6m; -- 【注意！】SMALLFILE表領域にはalter tablespaceを使えない!
alter database 
datafile 'test_tbs_datafile'
resize 6m;

-- 既存のデータファイル(※表領域ではない)の情報を確認する
select * from dba_data_files;

-- 特定のユーザーのデフォルト表領域を変更する
alter user USER1 default tablespace TEST_TBS;

-- 特定のユーザーのデフォルト表領域を確認する(再)
select username, default_tablespace from dba_users
where username = 'USER1';-- ユーザー名は大文字じゃないとヒットしない

-- 以下USER1(ローカルユーザー)
-- 新しいテーブルを作成する(既存のTBL1と同じ定義のテーブルを作成)
create table TBL2
as select * from TBL1
where 1 = 2; -- 行を1行もコピーしない

-- テーブルにどの表領域が割り当てられているかを確認する
select table_name, tablespace_name from user_tables;

-- 既存のテーブルの表領域を変更する
alter table TBL1
move tablespace TEST_TBS;

-- テーブルにどの表領域が割り当てられているかを確認する(再)
select table_name, tablespace_name from user_tables;

```
Yolo v8の使い方

# はじめに
Yolo v8を用いた物体検出を試してみたのでその手順を紹介させていただきます。今回は手順のみ解説ということなので、Yolo v8の概要について詳しく知りたい方は以下のリンクを参照してください。<br>

(https://github.com/ultralytics/ultralytics）
<br>

今回はすでに学習済みのモデルを使って歩行者信号の検出をGoogle Colaboratory上で行いました。Google Colaboratoryを使うと自分のパソコンに何もインストールする必要がないため、とても楽です。

では、はじめましょう。

# 実際の手順
1\. 必要なパッケージのインストール
google colabratoryを開き、以下のコードを実行します。
```
%pip install ultralytics
from ultralytics import YOLO 
```
<br><br>

2\. google driveの呼び出し
検出用の画像を使うために以下のコードを実行し、google driveを呼び出します。(何でもいいのであらかじめ、歩行者信号が写る画像をgoogle drive上にダウンロードしておいてください）
実行すると、google driveへのアクセス許可を求められるので、許可をしてください。
```
from google.colab import drive
drive.mount('/content/gdrive')
```
<br><br>




3.\　歩行者信号検知
以下のコードを実行すると、歩行者信号を検知した結果が保存されます。なお、画像ファイルのパスは自分仕様に変更してください。

```
!yolo predict model=yolov8n.pt source='/content/gdrive/MyDrive/image.png'
```
<br>


結果は以下の通りです。歩行者信号の検知に成功しました！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767067/70f15ff1-fecb-4e51-f196-c0e30ed575f6.png)
<br><br>

# おわりに
Yolo v8を用いた歩行者信号の検知を行いました。今回は学習済みモデルを使いましたが、未知の物体を検出したいときは新たにデータセットを学習させて検出したい物体にあわせた学習済みモデルを構築することができます。学習の仕方は以下を参照してください。

[YOLOv8 Tutorial](https://github.com/ultralytics/ultralytics)

<br>

また、データセットの収集には通常ラベリングという作業が必要となりますが、検出したい物体によっては以下のサイトからラベリング済みのデータセットを手に入れられます。

[Roboflow](https://roboflow.com/)
Kong GatewayのAudit Log

# 概要
KongのAudit Logは、Kongが行う各種操作を記録することで、システムの状態やセキュリティに関する洞察を提供します。これにより、システムの変更や問題のトラッキング、セキュリティ侵害の検出などが可能になります。

KongのAudit Logには、一般的にJSON形式で、次のような情報が記録されます。
- リクエストやレスポンスのデータ
- ルートやサービスへのアクセス試行
- ユーザーまたはクライアントの認証情報
- APIキーの使用
- エラーまたは警告メッセージ
- システムイベントや構成変更

https://docs.konghq.com/gateway/latest/kong-enterprise/audit-log/

# 機能の有効化
Kong Audit logは、Enterpriseの機能です。デフォルトではOffであって、`audit_log`の変更で有効無効が設定できます。

```config
audit_log = on # audit logging is enabled
audit_log = off # audit logging is disabled
```

# 利用方法

例えば以下のようなアクセスがあった場合

```bash
$ curl -i -X GET http://localhost:8001/status
```

このアクセスはAudit logに記録され、以下のリクエストで取得できます。

```bash
$ curl -i -X GET http://localhost:8001/audit/requests

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Tue, 13 Nov 2018 17:35:24 GMT
Server: kong/3.6.1.3-enterprise-edition
Transfer-Encoding: chunked
X-Kong-Admin-Request-ID: VXgMG1Y3rZKbjrzVYlSdLNPw8asVwhET

{
   "data": [
       {
           "client_ip": "127.0.0.1",
           "method": "GET",
           "path": "/status",
           "payload": null,
           "rbac_user_id": null,
           "rbac_user_name": null,
           "removed_from_payload": null,
           "request_id": "OjOcUBvt6q6XJlX3dd6BSpy1uUkTyctC",
           "request_source": null,
           "request_timestamp": 1676424547,
           "signature": null,
           "status": 200,
           "ttl": 2591997,
           "workspace": "1065b6d6-219f-4002-b3e9-334fc3eff46c"
       }
   ],
   "total": 1
}
```

上記の場合、`rbac_user_id`と`rbac_user_name`は`null`になる理由は、RBACが有効になっていないからです。もしRBACがOnな状態でもう一度アクセスログを確認すると、以下のようにちゃんと`rbac_user_id`と`rbac_user_name`に値がありまして、誰がアクセスしたのかは分かります。

```bash
{
   "data": [
       {
           "client_ip": "127.0.0.1",
           "method": "GET",
           "path": "/status",
           "payload": null,
           "rbac_user_id": "2e959b45-0053-41cc-9c2c-5458d0964331",
           "rbac_user_name": "admin",
           "request_id": "QUtUa3RMbRLxomqcL68ilOjjl68h56xr",
           "request_source": "kong-manager",
           "request_timestamp": 1581617463,
           "signature": null,
           "status": 200,
           "ttl": 2591995,
           "workspace": "0da4afe7-44ad-4e81-a953-5d2923ce68ae"
       }
   ],
   "total": 1
}
```

## ログローテーション
Audit Logは、KongのDBに、`audit_log_record_ttl`で定義して期間内に保存されます。`audit_log_record_ttl`を過ぎたログは自動で削除されます。このパラメータのデフォルトは30日です。

PostgreSQLは、DBにinsertがあるときに、上記の自動削除が行われます。そのため、Audit Logのエントリは上記TTL設定より長い存在する可能性もあります。特に新しいAudit Logのエントリが入ってこない時にです。
rye sync で発生した AttributeError: module 'hatchling.build' has no attribute 'prepare_metadata_for_build_editable' の解消

Python 3.12.1 を使用して ChromaDB を利用したアプリを作っていて、`rye sync` したらエラーになりました。
手元のMacでは問題なく動いてたのですが、Debianのイメージを使用したDockerコンテナで`rye sync`したらこんなエラーが出ました。

```
#10 [6/6] RUN <<EOS (rye sync --no-dev --no-lock...)
#10 0.233 Downloading cpython@3.12.1
#10 4.336 Checking checksum
#10 4.865 Unpacking
#10 6.989 Downloaded cpython@3.12.1
#10 7.013 Initializing new virtualenv in /app/.venv
#10 7.013 Python version: cpython@3.12.1
#10 8.143 Installing dependencies
#10 8.144 Creating virtualenv for pip-tools
#10 16.41 Looking in indexes: https://pypi.org/simple/
#10 16.41 Obtaining file:///. (from -r /tmp/tmpdw7wp55s (line 22))
#10 16.41   Installing build dependencies: started
#10 17.77   Installing build dependencies: finished with status 'done'
#10 17.77   Checking if build backend supports build_editable: started
#10 17.83   Checking if build backend supports build_editable: finished with status 'done'
#10 17.83   Getting requirements to build editable: started
#10 17.94   Getting requirements to build editable: finished with status 'done'
#10 17.94   Preparing editable metadata (pyproject.toml): started
#10 18.13   Preparing editable metadata (pyproject.toml): finished with status 'error'
#10 18.14   error: subprocess-exited-with-error
#10 18.14   
#10 18.14   × Preparing editable metadata (pyproject.toml) did not run successfully.
#10 18.14   │ exit code: 1
#10 18.14   ╰─> [29 lines of output]
#10 18.14       Traceback (most recent call last):
#10 18.14         File "/tmp/.tmpMdbbCl/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 167, in prepare_metadata_for_build_editable
#10 18.14           hook = backend.prepare_metadata_for_build_editable
#10 18.14                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#10 18.14       AttributeError: module 'hatchling.build' has no attribute 'prepare_metadata_for_build_editable'
#10 18.14       
#10 18.14       During handling of the above exception, another exception occurred:
```

https://github.com/OpenDevin/OpenDevin/issues/879

を参考に、Python 3.11.7 にしたら解消しました。
ChromaDB側の問題なのかな？
ホスティング（レンタルサーバー）とは

# ホスティングとは
ホスティングサービスとは、**インターネットサービス事業者よりインターネット経由でサバーをレンタルして利用するサービス**のことを言います。
※サーバー・・・Webサイトやメールを利用するために必要なデータや情報を提供するコンピュータ

提供するサービス事業者のデータセンターにあるサーバを一定の期間料金を支払って利用します。
簡単にサイトやブログの運営ができたり、独自のメールアドレスを持つこともできます。

「ホスティング」とは「サーバーを借りる」ことを意味しており、「サーバーを借りる」というと、「レンタルサーバー」という単語を思い浮かべる人もいるかもしれませんが、「ホスティング」と「レンタルサーバー」は同じ意味として使用されます。

ホスティングと聞いたらレンタルサーバーのことだと覚えておきましょう。

# ホスティングサービスを利用する目的
ホスティングサービスは自身でWebサイトを立ち上げたい方やブログなどをのせる専用のサイトを欲しい方が利用します。しかし、本来サーバは自身で購入して利用できます。

もちろん、ホスティングサービスを使用せず、自分自身でサーバを構築して運用することも可能です。しかし、その場合は立ち上げから設定・運用までを全て自分で行う必要があり、専門的な知識と技術が必要になります。また、セキュリティ対策なども自身で行わなければなりません。

初心者が一からサーバを構築するには大変難しいです。また、ホスティングサービスを利用するより費用も高額になる可能性もあります。

そこで、ホスティングサービスを利用することで、専門的な知識や技術がなくても比較的簡単にウェブサイトやブログを立ち上げることができます。サービス事業者がインフラストラクチャーやセキュリティに関する管理を行ってくれるため、ユーザーはコンテンツに集中することができます。

さらに、ホスティングサービスは比較的低コストで利用することができます。自身でサーバを購入し、セットアップする場合に比べて、初期投資やランニングコストを抑えることができます。

# ホスティングとクラウドの違い
ホスティングとクラウドは、どちらも事業者が所有・管理しているサーバーをネットワーク経由で利用できるサービスです。どちらもサーバーをレンタル点は同じですが、CPUやメモリなどのリソースの扱いについて、大きな違いがあります。

ホスティングでは、複数のユーザーが1台の物理サーバーを共有して使用します。サーバーが持つCPUやメモリ、ストレージなどのリソースは、同一のサーバー上に「同居」するユーザー全員で利用することになるため、例えば、あるユーザーが負荷の高い処理を行うと、その間はほかのユーザーが実行しているアプリケーションやサイトのパフォーマンスが下がるなど、第三者の影響を受けやすくなっています。

それに対してクラウドは、1台の物理サーバー上に複数の仮想サーバーを作成し、ユーザーごとに独立した仮想サーバーを割り当てます。
複数のユーザーが1台の物理サーバーを共有するという点では同じですが、クラウドは、それぞれの仮想サーバーごとにリソースを確保して割り当てるため、ホスティングと比べて、第三者の影響を受けにくくなっています。

# ホスティングとクラウドのメリット/デメリット
ホスティングは導入時に初期費用こそかかるものの、運用面での手間が少なく扱いやすいのがメリットです。しかし一方で、手間がかからない分、カスタマイズなどの自由度が低くなってしまうのでデメリットでもあります。

一方クラウドは、自由度や柔軟性が高いものの、ユーザー側でのセキュリティ対策が必要になるなど、使いこなすには相応の知識が求められます。また、初期費用がかからず、高い柔軟性によって利用コストを最適化しやすいものの単位時間あたりの利用コストは割高になる場合もあります。

| 項目 | ホスティング | クラウド |
| --- | --- | --- |
|導入コスト | 導入時に初期費用が発生する。 | 初期費用はかからず、利用したリソースに応じて課金が発生する。　|
利用コスト | 決められた月額費用で利用できる。クラウドと比較して利用コストは安めで、かかるコストも計算しやすい。 | 従量制と定額制のどちらかを選択できる場合が多い。ホスティングと比較すると単位時間あたりの利用コストは高め。　|
運用面 | サーバーの設定や運用・保守などはすべて事業者が行うため、サーバーの構築や運用の経験がなくても扱いやすい。 | サーバーの構築作業やOS・ミドルウェアなどの運用・保守が発生するため、利用にあたってある程度の知識が必要となる。 |
カスタマイズ性 | ミドルウェアのインストールといったカスタマイズの自由度が低い。 | 好きなOSを選択できたり、ミドルウェアをインストールできるなど、カスタマイズ性に優れている。 |
柔軟性 | サーバーのスペックを変更したい場合は、プラン変更の手続きやサーバー移行が必要になる。 | 事業の拡大や縮小に応じて、サーバーの台数を自在に増減させることも可能（スケールアップ/スケールアウト）。また、設定した値以上の負荷がかかった際に自動的にスケーリングをしてくれる「オートスケール」という機能がある。 |

# ホスティングとクラウドの利用シーン
個人ブログやコーポレートサイトなどには、ホスティング（レンタルサーバー）が向いています。アクセス数の波が少なく、サーバーの負荷対策を取る必要がなく、一般的なWebサイトであれば特殊なミドルウエアのインストールやカスタマイズも不要なことが多いため、ホスティングのデメリットを気にする必要もありません。
カスタマイズが必要ないのであれば、運用の手間がかからないホスティングの方がおすすめです。

一方、アクセスが激しく変動し、リソースの増減が求められるようなサイトやアプリケーション、一時的にオープンするキャンペーンサイトは、クラウドの方が向いています。自動でリソースをスケールできるクラウドの柔軟性が必要になるからです。
もし、このようなサイトをホスティングで運用していた場合、最大のアクセスに耐えれる容量のサーバーを常に稼働する必要があり、アクセスが少ない場合などは無駄なコストが発生してしまいます。
また、一時的にオープンするサイトなども、従量課金制のクラウドの方が無駄なコストをかけず運用することができます。

間違った選択をしてしまうと、思いがけないコストが発生する場合もあります。
実際に運用する要件に応じて最適な選択をするようにしましょう。
[初心者向け]Laravel sailでマイグレーション時にSELECT権限でエラーが出た話

# [初心者向け]Laravel sailでマイグレーション時にエラーが出た話

## 目的
- migrationファイルを作成し、内容を変更後、`./vendor/bin/sail artisan migrate`を実行するとエラーが出力されたので、解決した方法を記載する

## エラー内容
```
$ ./vendor/bin/sail artisan migrate

   Illuminate\Database\QueryException 

  SQLSTATE[42000]: Syntax error or access violation: 1142 SELECT command denied to user 'sail'@'172.19.0.4' for table 'migrations' (Connection: mysql, SQL: select `migration` from `migrations` order by `batch` asc, `migration` asc)

  at vendor/laravel/framework/src/Illuminate/Database/Connection.php:829
    825▕                     $this->getName(), $query, $this->prepareBindings($bindings), $e
    826▕                 );
    827▕             }
    828▕ 
  ➜ 829▕             throw new QueryException(
    830▕                 $this->getName(), $query, $this->prepareBindings($bindings), $e
    831▕             );
    832▕         }
    833▕     }

      +27 vendor frames 

  28  artisan:35
      Illuminate\Foundation\Console\Kernel::handle()
```

## エラーの原因
- データベースユーザー sail に対して migrations テーブルへのSELECT権限がないため、クエリが失敗しているとのこと。

## 解決方法
- php myadminのユーザー権限を設定する。
メニューからユーザーアカウントを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781926/f8250eb5-2c6a-a0de-a4cf-5d3e5214b507.png)

以下の画像のように設定を変更して保存
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781926/a8317c2c-3962-750b-5c4b-164d373a6410.png)

## 注意
エラーの解決策として .env ファイルの DB_USERNAME を root に変更するという方法がありますが、誤ってデータベースを破壊したり、悪意のあるSQLインジェクションによって被害を受けやすくなるリスクが高まります。開発環境であっても、root ユーザーの使用は最小限に抑えるべきです。
Elastic Beanstalk

## はじめに

この記事はAWS SAA試験勉強のための、AWS Elastic Beanstalkに関する知識のまとめです。


## AWS Elastic Beanstalkとは
名称から機能を想像するのが少し難しいサービスですが、Java, .NET, PHP, Node.js, Python, Ruby, Goおよび<font color="red">**Docker**</font>を使用して開発されたウェブアプリケーションを、Apache、Nginx, Passenger, IISなど使い成れたサーバでデプロイ及びスケーリングするサービスです。
(C言語は対応していません)

Elastic Beanstalkを本番環境で利用する場合、Amazon RDSをElastic Beanstalkの外に設定することでブルーグリーンデプロイメントが可能になります。

### All at Once方式
All at Once方式は一度にすべてのインスタンスにデプロイする方法、ブルーグリーンデプロイメントはデプロイ時に同じ環境を隣に用意し、DNSのレイヤーで切り替える方式です。

### AWS Elastic Beanstalk Tomcat プラットフォーム

AWS Elastic Beanstalk Tomcat プラットフォームは、Tomcat ウェブコンテナで実行できる Java ウェブアプリケーションのプラットフォームバージョンのセット。Tomcat は、nginx プロキシサーバーの背後で実行されます。

## CloudFormationとの比較

CloudFormationはインフラの自動作成に優れていますが、Elastic Beanstalkのように簡単に環境を切り替える機能がありません。
【Swift】インデックスを使った文字列操作

# インデックスを使った文字列操作

### 解説する機能

 - 文字列のインデックス
 - `startIndex`プロパティ
 - `lastIndex`プロパティ
 - `index(:offsetBy:)`メソッド

## 解説

Swiftにおいて、文字列リテラルに「添え字で整数を指定する」ことは不正です。
したがって、`"swift"`の3文字目`i`を取得するために、「整数の`2`」は指定できません。

```swift
"swift"[2]  // error
// cannot subscript String with an Int, use a String.Index instead.
```

このようなコードに対して、コンパイラは「整数ではなく、文字列のインデックスを指定すべきだ」と警告します。

### 最初と最後のインデックス

文字列のインデックスは、「`String`型の内部」で定義された`Index`型の値です。
配列のインデックスと同様に、文字列のインデックスもゼロから数えます。
コード上では、インデックスは整数のように見えますが、実際は互いに互換性のない値です。

先頭や最後尾のインデックスは、文字列のプロパティから取得できます。

```swift
let start = "swift".startIndex   // 0
let last  = "swift".lastIndex    // 4
```

### 途中のインデックス

途中のインデックスは、`index(:offsetBy:)`メソッドで取得できます。
`index(:offsetBy:)`メソッドには「起点の位置」と「オフセット量」を指定します。
途中のインデックスを言い換えると、「先頭から任意の量だけオフセットした位置」です。

次のコードは、`"swift"`という文字列の「先頭から`2`だけオフセットした位置」のインデックスを取得します。

```swift
let offsetByTwo = "swift".index(start, offsetBy: 2)   // 2 
```

取得した`offsetByTwo`定数は`2`ですが、この値は整数ではなくインデックスです。
したがって、文字列の添え字に指定できます。

```swift
"swift"[offsetByTwo]    // i
```

`"swift"`という文字列の「インデックス`2`の位置にある文字」は`"i"`です。
実のところ、データ上は文字列を「一連の文字が並んだコレクション」とみなすことができます。
デスクトップPCの電源スイッチをラズパイで操作し起動させる

# 概要

デスクトップPCに付属している電源ボタンの回路を、ラズパイで電気的に横取り（？）し操作します。
ラズパイに外部からsshするなり、Webフロントエンドを適当に用意するなりすれば、リモートでデスクトップPCの電源を入れることができます。
回路構成図とPythonの実装サンプルを記載します。

- WakeOnLan非対応でも可能
- 電源ボタン長押しも再現できるため、PCの強制再起動までもリモートで実行可能

## 構成

- Raspberry Pi 4
- フォトカプラ（ [フォトカプラ PS817: オプトエレクトロニクス 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/g111729/) を使いました）
- GPIO23を使いました

![2024-04-30_23.32.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139537/707aae3d-10c6-2491-4869-25a8ce88693b.png)

> ラズパイGPIO図 [Raspberry Pi OS - Raspberry Pi Documentation](https://www.raspberrypi.com/documentation//computers/os.html#gpio-and-the-40-pin-header) より
> フォトカプラ図 PS817データシートより

## スクリプト

下記スクリプトを`~/make-pulse.py`に設置

```py
#!/usr/bin/env python3
# デスクトップPCのスイッチをラズパイで横取りすることでリモート起動させる
#
# Usage
# ./make-pulse.py <PIN> <DURATION_SECONDS>
#
# e.g.
# ./make-pulse.py 23 0.3
#

import RPi.GPIO as GPIO
import sys
import time

args = sys.argv

pin = int(args[1])
duration_seconds = float(args[2])

GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT, initial=GPIO.LOW)

# スイッチ押下
# （GPIO<PIN>の出力をオンにして、<DURATION_SECONDS>後、オフにする）
GPIO.output(pin, GPIO.HIGH)
time.sleep(duration_seconds)
GPIO.output(pin, GPIO.LOW)

GPIO.cleanup()
```

実行権限を付与

```bash
chmod +x ~/make-pulse.py
```

PCが起動するかテスト

```bash
./make-pulse.py 23 0.3
```

## おまけ

### iPhoneから起動させる

iOSの「ショートカット」アプリ経由で実行できるととても便利です。ラズパイへSSHできる設定がされているとして、下記のように設定します。

- アプリを起動
- 右上「+」を押下し新規ショートカット
- アクションを追加
- 「SSH経由でスクリプトを実行」を選択
  - スクリプト、ホスト、ユーザ、認証（パスワード・SSHキー）を入力

スクリプトは下記のように、先程のスクリプトの起動コマンドを入力します

```bash
~/make-pulse.py
```

ウィジェットなどで設定しておくと、リモコン感覚で起動できました。

## 参考

- [PCを電源ボタン押さずに念力（ラズパイ）で起動させてみた | なたで日記](https://blog.natade.net/2023/03/26/rasberry-pi-wlan-wol/)
パーティショニング、バケッティングって何？

最近、バケッティングに関するブログを書く機会があった。

https://aws.amazon.com/jp/blogs/big-data/optimize-data-layout-by-bucketing-with-amazon-athena-and-aws-glue-to-accelerate-downstream-queries/

ここで取り上げたパーティショニングとバケッティングはビッグデータ処理におけるIO削減手法の代表的な例ではあるが、両者の仕組み（特に後者）や使いどころの違いは案外知られていない気がするので、この機に整理しておく。

また、それぞれにやり方がいくつかあり、これも毎度ややこしいのだが、こちらについては項を改める。

## 前提

話を単純化するため、以下の前提で記載する。
- **Amazon S3との組み合わせで使う。** S3以外のデータストアはいったん忘れる
- **Amazon Athena、AWS Glueを用いる。** EMRとかEC2などはいったん忘れる
- **HiveとSparkの範囲内で使う。** Icebergとかはいったん忘れる

## 1）基礎

両方ともIO量を削減するためのテクニックだが、アプローチが異なる。

### パーティショニングのコンセプト
指定した列の値ごとにデータを物理に異なるS3プレフィックスに配置することで、クエリー時に読み取る**S3プレフィックス数**を減らせるようにデータを準備する手法。

クエリーの際、WHERE句でパーティション列と特定の値を指定し、その値以外のS3プレフィックスを読み飛ばすことでIOを削減する。

### バケッティングのコンセプト
指定した列の値を元に配置先のオブジェクトを計算・配置することで、読み取る**S3オブジェクト数**を減らせるようにデータを準備する手法。

※このオブジェクトを「バケット」と呼ぶので大変ややこしいが、S3用語としてのバケットとは何の関係もない。

仕組みとしては[Amazon Kinesis Data Streamsのパーティションキー](https://docs.aws.amazon.com/ja_jp/streams/latest/dev/key-concepts.html)と似通っていて、ハッシュ計算によって格納先のバケットを決める。このため、同じ値のレコードは常に同じオブジェクト内に収まるし、クエリー時に同様の計算をすることで特定の値がどのオブジェクトに格納されているかも高速に算出される。
なお対象のS3オブジェクト（バケット）はS3プレフィックス（パーティション）ごとに計算される仕組み。つまりバケット数を仮に10とすれば、各S3プレフィックス内に10個ずつS3オブジェクトが作成される。

クエリーの際、WHERE句でバケット列と特定の値を指定し、その値が含まれないS3オブジェクトを読み飛ばすことでIOを削減する。

## 2）使いどころ

### パーティショニングの使いどころ
年/月/日など、日付でパーティションを切るのが最も一般的で、たいがいの時系列データに有効なため広く使われている（`year=2024/month=05`のようなプレフィックス構造をどこかで目にしたことがあると思う）。
都道府県など、日付以外の列で切ることもでき、これらは日付と階層構造にしても効果がある（例：`city=Tokyo/year=2024/month=05/`）。

弱点として、対象の列のカーディナリティが高すぎるとパーティション数が多くなりすぎ、実行速度やコストの面で残念な結果になる。もう少し具体的に言うと、ETLジョブ実行時にS3プレフィックスの作成数が多すぎてPutのコストが高騰したり、パーティションの列挙に時間がかかったり（この弊害は近年解決されている）、パーティションあたりのデータ量が少なすぎてオブジェクトサイズが小さくなりクエリーが非効率になったりする。
また、当然だが、その列（例えば日付）がWHERE句に指定されないとIO削減効果は得られないので、**頻用されるクエリーから逆算してパーティション列を決定する**ことが重要となる。

### バケッティングの使いどころ
カーディナリティが高すぎてパーティショニングには適さない列、例えばIDのような列に対して、クエリー時のIO量を減らしたい時に威力を発揮する。例えば、ID列に対してバケット数=20に設定すると、S3プレフィックスごとに20個のS3オブジェクトが作成されて、あるIDのデータは常に特定のS3オブジェクトに格納される。この時、クエリー時に`WHERE id in [x,y]`とすれば、`x`と`y`のデータは理論上最大で2つ、ベストケースで1つのS3オブジェクトに格納されていることになるので、残りの18ファイル（または19ファイル）は読む必要がなくなる。

逆にカーディナリティが低すぎると、効果は限定的になる。例えば指定した列が含む値が二値の場合（例：True, False）、3つ以上のバケット＝S3オブジェクトは作成されず、クエリー時に読み飛ばせるオブジェクト数は最大で全体の50%に留まることになる。
カーディナリティだけでなく、偏差も効果に影響する。`x`、`y`、その他の値が概ね同程度の数であればS3オブジェクトごとのデータ量は概ね均等に配置されるが、例えば`x`が極端に多い場合（IDを例に取ると、特定のユーザーだけ突出して利用回数が多く時系列データ量が多いなどのケースが該当する）、`x`の含まれるファイルだけが巨大になるといった不均衡が生まれる。

つまり、バケッティングの効果を高めるためには、**値のカーディナリティが十分に高く、偏差がなるべく少ない列**を選ぶことが肝要と言える。
あくまで一般論であって、バケッティングの効果はデータやクエリーによってかなりばらつく傾向があるので、実際の効果は測定してみることをお勧めしたい。

なお、WHERE句で指定しなければ無用の長物という点はパーティショニングと同様なので、「どういうクエリーを使いたいか」が最重要なのはここでも同じである。

## まとめ
パーティショニングは比較的普遍的に利用できる。特に、時系列データでは多くの場合日付ベースでのクエリーが想定されることから、とりあえず日付でパーティションを切っておけばある程度効果が見込める利便性があり、広く利用されている。
一方、バケッティングはユースケースが限られるせいか、パーティショニングに比べるとマイナーで情報も少ないが、ハマればちゃんとIO量を減らせる。ただし列の選定やバケット数などの設計値、およびデータの内容によって効果が変動する気難しさがあり、検証と設計がより重要になる印象。

いずれも物理的な配置を伴う（厳密にはIcebergでは異なるがここでは割愛）ため、洗い替えを避けるには頻用クエリーを起点とした当初の設計が重要となる。
本記事がその一助となれば幸いです。
ActiveStorageで複数枚アップロードする時に罠があった

## はじめに
普段web開発を行う際、画像アップロードの要件がある場合、
RailsのActiveStorageを使っています。
ActiveStorageの基本的な使い方については以下ドキュメントをご確認ください。

https://railsguides.jp/active_storage_overview.html

今回、複数枚アップロードする時に罠があったため、記しておこうと思います。

## 罠の内容
結論から言うと、attach処理をtransaction内で行うと、指定のStorage（S3とかDisk）には一枚しかファイルがアップロードされず、成功した一枚以外のファイルのURLを参照すると404となってしまいます。

ドキュメント通りmodelにattachの設定をする

```model.rb
has_many_base64_attached :images
```

modelと、添付される画像の保存処理失敗時の整合性を取りたいので、transactionを書く

```model.rb

ActiveRecord::Base.transaction do
  model.build_hogehoge(params)
  model.save!
  
  params[:images].each do |image|
    model.images.attach(image) #attachはimagesの保存もなされるためsaveは記載しない
  end
end
```

実際にローカルで3枚画像アップロード処理を実行してみると、
以下のDisk Storage....のログが最後の1枚に対してしか出ませんでした。え？

![スクリーンショット 2024-04-30 20.34.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730383/465fb972-1305-ce52-6bef-6a76531f02ba.png)

active_storage_blobs、active_storage_attachments、active_storage_variant_recordsレコード自体は作成されています。
しかし、rails_blob_pathや、rails_storage_proxy_pathで得られるURLから画像参照すると、
1枚目と2枚目の画像は404となっていました。


## 対応状況

issueが上がっていました。

https://github.com/rails/rails/issues/41661

https://github.com/rails/rails/issues/42343


## 対応方法
該当のattachの処理部だけをtransactionから外す。という形で対応しました。
挙動としては問題なく動いています。

が、

今回の記事作成に伴い、もう少し深く調べてみました。

すると...

https://github.com/rails/rails/pull/42300

https://github.com/rails/rails/milestone/82?closed=1

修正されてマージされてるやん。
rails7.1からちゃんと動くみたいやん。
なんで当時ちゃんと見なかったんだろうか...

## 最後に

最近他でもバージョンが古いことによるバグに遭遇したんですよね。。

自分が普段使う技術をもっと知る必要があると感じたのと、
定期的に最新のバージョンに上げることの重要性を改めて感じました。

バージョンを上げる事を怖がってはいけませんね。
そのためにしっかりテストを書かないとなぁ。
単一テーブル継承(STI)について

## はじめに
チームとしてDB設計力をあげていかないとなぁと思っています。

1:1、1:N、N:Nの関連付けの設計や、正規化がしっかりとできるようになった後は、
単一テーブル継承(STI)について考え始めるタイミングかなと思います。
その時に備えて、ここに記しておこうと思います。



## 単一テーブル継承(STI)とは

STIを利用する目的は、複数の関連するクラスを単一のテーブルで管理する事により、
DB設計を単純にする事です。

Railsガイドに内容が簡潔に記載されていますが、もう少し噛み砕いて説明しようと思います。

https://railsguides.jp/v7.1/association_basics.html#%E5%8D%98%E4%B8%80%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E7%B6%99%E6%89%BF-%EF%BC%88sti%EF%BC%89

## STIを利用しない場合

```Car.rb
class Car < ApplicationRecord
end
```

```Motorcycle.rb
class Motorcycle < ApplicationRecord
end
```

```Bicycle.rb
class Bicycle < ApplicationRecord
end
```

### DB設計

car
| Field | Type |
|-------|--------|
| color | string |
| price | integer|

motorcycle
| Field | Type |
|-------|--------|
| color | string |
| price | integer|

bicycle
| Field | Type |
|-------|--------|
| color | string |
| price | integer|

構造が同じで名前だけ異なるテーブルが3つ存在することになります。
共通化してDBテーブル数を減らしたい気持ちになります。

## STIを利用する場合

Vehicleモデルは親です。
Carモデル、Motorcycleモデル、Bicycleモデルは子（サブクラス）です。
子（サブクラス）は、親を継承します。

```Vehicle.rb
class Vehicle < ApplicationRecord
end
```

```Car.rb
class Car < Vehicle
end
```

```Motorcycle.rb
class Motorcycle < Vehicle
end
```

```Bicycle.rb
class Bicycle < Vehicle
end
```
### DB設計

vehicle
| Field | Type |
|-------|--------|
| color | string |
| price | integer|
| type | string|

typeに入る値が、'Car'、'Motorcycle'、'Bicycle' に応じて、
RailsのModelが決定される形となります。

また、2通りのレコード作成方法があります。

- Carクラスでcreateする
```rb
Car.create(color: 'Red', price: 10000)
```

- typeに'Car'を指定してcreateする
```rb
Vehicle.create(color: 'Red', price: 10000, type: 'Car')
```

この方法により、DBテーブル数を1つに共通化する事ができます。

### 処理の共通化

各モデルで共通の処理があったとすると、それを親側で定義して共通化できます。

```Vehicle.rb
class Vehicle < ApplicationRecord
  # 共通のバリデーション
  validates :color, presence: true
  validates :price, numericality: { greater_than: 0 }

  # 共通のメソッド
  def display_info
    p "#{type}: Color - #{color}, Price - #{price}"
  end
end
```

例えば、carインスタンスはVehicleを継承しているのでdisplay_infoを呼び出せます。

```rb
car.display_info # Car: Color - Red, Price - 10000"
```

特段、STIでなくても親Classを作成すれば処理の共通化はできるのですが、
STIを利用することで親側に処理を寄せようと感じるきっかけになれば、それはそれで良いかなと思います。

## STIの課題

異なるサブクラスが異なる属性を持つ場合、多くのNULL値が発生する可能性があります。

vehicle
| Field | Type | Description |
|-------------------|---------|------------------------------|
| type | string | 'car', 'motorcycle', 'bicycle' |
| color | string | 共通属性 |
| price | integer | 共通属性 |
| doors | integer | car専用属性 |
| engine_capacity | integer | motorcycle専用属性 |
| has_basket | boolean | bicycle専用属性 |

この場合、typeが'Car'だと、engine_capacityとhas_basketはNULLになります。
Carにとっては不要な属性という訳です。

## STIの使用が適切な場合
サブクラス間で多くの共通属性があり、異なる属性が少しだけ存在する場合にSTIを利用するのが良いと言われています。
また、オブジェクトのタイプ（type）が比較的少ない場合、という条件も必要でしょう。
typeが増えると、その分あるModelに対して不要な属性が肥大化する懸念があるためです。
弊社案件に関しては、そこまでtypeを大量に扱うような要件はなさそうなので、これについてはそこまで気にしなくて良いかなと思います。


## 最後に

どのテーブルならSTIを利用できるかな〜と考えるきっかけになれば良いなと思います。

因みに、Rails7.1からDelegated Typesという項目が追加されています。

https://railsguides.jp/v7.1/association_basics.html#delegated-types

本記事で述べたSTIの課題を解決するために編み出されたようですが、
少し複雑に見えるので、どうなのかな。。
次の記事の内容にするかどうかはもう少し考えよう。
【CSS】子要素ホバー時に親要素にスタイルを適用する方法

以下のように記述ると子要素ホバー時に親要素に対してスタイルを適用できます。

```html
<div>
  <button>ボタン</button>
</div>

```

```css
div {
  background: white; 
  height: 100vh;
  width: 100%;
  text-align:center;
}

button {
  margin:80px auto;
  display: inline-block;
  padding: 20px 40px 20px 40px;
  color: aliceblue;
  font-weight: bold;
  background: #333;
}

div:has(button:hover){
  background: #0000ff;
}

```

上記の場合には`button`にホバーすると`div`の`background`が青になります。
GPTおすすめのLinux試験とは

# はじめに
GPTに聞いてみました。「AIのお薦めするLinuxの資格は何か？」

# GPT曰く(無修正)
Linuxに関する資格を選ぶ際、現代のIT環境においては、特に以下の二つが推奨されます。これらは、日本でも広く認知されており、Linuxの知識を証明する上で有効です。

1. **LPIC（Linux Professional Institute Certification）**
LPICは、Linuxのスキルを認定するための国際資格であり、日本国内でもその価値が認められています。三つのレベルに分かれており、それぞれがLinuxの知識およびスキルの深さを示します。レベル1は基本的なLinuxのコマンド操作やシステム管理に関する知識を、レベル2はより高度なシステム管理の技能を、そしてレベル3はLinux環境でのネットワーク管理やセキュリティ、診断技術などの専門知識をカバーしています。

2. **LinuC（Linux Certification）**
LinuCは、日本独自のLinux資格であり、産業人材育成支援のために設立された一般社団法人LPI-Japanによって提供されています。LPICと同様に、LinuCも複数のレベルに分かれており、Linuxの基礎知識から応用知識までを段階的に学んでいくことができます。特に日本のIT業界における需要を考えると、LinuCはそのキャリア形成にとって有利な資格となり得ます。

Linux を効果的に学び、利用するために必要な柔軟性、問題解決能力、そして予測不能な状況に対応する能力を身につけるためにも、これらの資格は非常に有用です。実際の作業環境では、書籍やオンラインコースから得られる知識を応用して実践的な問題を解決する必要があります。このようなスキルは、資格取得の過程で得られる知識や訓練によって鍛えることができます。

また、これらの資格の取得は、Linuxを効果的に学び、利用するために必要な柔軟性、問題解決能力、そして予測不能な状況に対応する能力を身につける際に非常に有用です。実際の作業環境では、書籍やオンラインコースから得られる知識を応用して実践的な問題を解決する必要があります。そして、資格取得の過程で得られる知識や訓練は、このようなスキルを鍛える絶好の機会となります。

LPICやLinuCは、それぞれが豊富なカリキュラムを提供しており、Linuxの基礎から応用まで、段階的に学ぶことができます。これらの資格を取得することにより、Linuxの専門家としてのキャリアを築く強固な基盤を持つことができるでしょう。

# さいごに
GPTの進化には目を見張るものがありますね。みなさんも活用していますか？
要約や翻訳など勉強にも活用できますよ。
Linuxを効果的に学ぶために、みなさんはどのようなことをしていますか。
私も参加しているLinuxのオープンコミュニティLinuC Open NetworkがLinuC 101向けの無料勉強会を開催します。
これから受験を考えている方、既に取得しているけど復習したい方も、この機会にぜひ。

参加申込はこちらから

https://linuc.org/study/seminar/5400/