OmniAICreator/Qiita-1.07M huggingface dataset:
【合格体験記】ORACLE MASTER Bronze DBA 2019

# 本記事の概要

ORACLE MASTER Bronze DBA 2019 を取得したので勉強方法を備忘録として投稿します。
これから受けようと思っている方や、現在勉強している方がこの記事を参考の一つにしていただけたら幸いです。

# 使用した教材

参考書
・[オラクルマスター教科書 Bronze DBA Oracle Database Fundamentals](https://www.amazon.co.jp/%E3%82%AA%E3%83%A9%E3%82%AF%E3%83%AB%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC%E6%95%99%E7%A7%91%E6%9B%B8-Bronze-Oracle-Database-Fundamentals/dp/4798166367/ref=sr_1_1?crid=19B3YOISXBY7R&keywords=oracle+master+bronze+dba&qid=1704461660&sprefix=oracle+master+bronze%2Caps%2C160&sr=8-1)

WEBサイト
・[Ping-t](https://ping-t.com/)

# 勉強の流れ
今回の勉強期間は1ヶ月ですが、実際に勉強したのは1週間程の時間(4h*7dで28時間くらい)でした。
私の受験前のDB知識はCRUDが何かわかるくらい、つまりほぼゼロです。

1. **参考書を一周する(巻末の模擬試験を除く)**
まずは黒本と呼ばれる参考書を1周しました。何書いてあるかわからない箇所もありましたがとりあえず進むという意識でやるのがコツかなと思います。

1. **Ping-tで1章毎に実施**
黒本の章とPing-tの1単元がきれいに一致しているので、ここで各章の内容を深掘りしていきます。
Ping-tの問題は本番よりも難しい問題がたくさんあるので、全部を覚えようとせずに何度も問われるような基礎的な内容~中級くらいの内容を覚えるようにしましょう。
私の場合は全問をヒット状態(1回正解)にしただけで終わらせました。

1. **参考書の章末問題と模擬試験を実施**
この段階になると章末問題が易しく感じると思います。章末問題で各章をさらっと復習しつつ、巻末の模擬試験に臨みましょう。
その後は、試験本番まで自分が重点的に間違えている分野を克服できるようにしましょう。

# 試験結果

受験日：2024年1月5日
スコア：85%
合格ライン：65%
結果：pass

bronzeということで簡単な試験ですが、受験料はしっかり高いので1回で突破できてよかったです。

# 受験後の感想

インフラエンジニアとして仕事をしているのにDBのことをほぼ知らないのはまずいという危機感から受験した資格ですが、
DB(oracle)アーキテクチャの基礎や、DBの話題でよく出てくる単語を学習できたので個人的には役立ったと思います。
セグメントとかスキーマといった単語を雰囲気で理解していたので、しっかりと用語理解に繋がった点が一番の成果でした。
Silver以上に進むかどうかは悩みどころです。

この記事を開いていただき、また、ここまで読んでいただきありがとうございました。
インフラエンジニアなのに雰囲気でしか理解してないシリーズその2【ネットワーク】を克服するために本年度中にCCNA取得を目指します。
なろうをKindleで読みたかったのでM1 Macで設定してみた

## 概要

正月休みの暇つぶしにKindleでなろうをセットアップしてみたので備忘録。

モチベーションはスマホでの閲覧は目が疲れるのでKindleで読みたい。
調べた限りでは自炊する分には違反行為には該当しないとのこと。（問題があれば教えてもらえれば）

## 環境

- macOS Sonoma 14.0
- ruby 3.2.2

## [Narou.rb](https://github.com/whiteleaf7/narou)をセットアップする

Narou.rb(3.8.2)はruby3.2.2では入らないので3.0.6をセットアップする。
なお、Narou.rbは[2022/09/10から更新が止まっている](https://github.com/whiteleaf7/narou/blob/develop/ChangeLog.md)のでカクヨムが利用できない状態。

```
$ brew install rbenv ruby-build
$ echo 'export PATH="$HOME/.gem/bin:/opt/homebrew/opt/ruby/bin:$PATH"' >> ~/.zshrc
$ source ~/.zshrc
$ eval "$(rbenv init -)"
$ rbenv install -l
$ rbenv install 3.0.6
$ rbenv global 3.0.6
$ gem install narou
```

## epubへの変換

AozoraEpub3をセットアップしてKindleに対応する
epubへの変換には`AozoraEpub3`と`kindlegen`が必要なのでセットアップする。

- Javaをセットアップする
```
$ brew install openjdk
```
- AozoraEpub3がダウンロードページで404を返すので[改造版AozoraEpub3](https://www.vector.co.jp/soft/winnt/writing/se522586.html)をダウンロードして解凍
- [Kindle Previewer](https://kdp.amazon.co.jp/ja_JP/help/topic/G202131170)をダウンロードしてインストール
- AozoraEpub3を解凍したフォルダに下記のファイル(`kindlegen`)をコピーする
```
/Applications/Kindle\ Previewer\ 3.app/Contents/lib/fc/bin/kindlegen
```

## 使い方

```
$ mkdir MyNovel && cd MyNovel
// 実行するとAozoraEpub3のフォルダの場所を聞かれるのでパスを指定する
$ narou init
// 実行するとブラウザが立ち上がる
$ narou web
```

1. ブラウザで起動したアプリの「ダウンロード」ボタンを押してURLを入力するとダウンロードが開始
2. ダウンロード後、一覧から選択して「Convert」を押すと変換が走る
3. 変換で出力したepub形式ファイルを[Kindleに送信](https://www.amazon.co.jp/sendtokindle)

## その他

カクヨムはページのフォーマットが変わったので有志が作成したパッケージがある模様
https://github.com/whiteleaf7/narou/issues/412
WSL上でVSCodeでgdbする話

いろいろと躓いたので備忘を含めたメモメモ。 
まずWSLやらなんやらをインストールする。

[ここらへんを参考にする](https://qiita.com/_masa_u/items/d3c1fa7898b0783bc3ed)

## つまづきポイント
CMakeプロジェクトの時に以下のようなエラーが出たときは、WSLとwindows側で時刻の同期ができてない可能性がある。ninja-buildのissuesに書いてあった。

``` 
[build] [ 50%] Building CXX object 
[build] [100%] Linking CXX executable hogehoge
[build] [100%] Built target hogehoge
```

WSL側をntpで標準時刻に同期する。
``` 
sudo ntpdate ntp.nict.jp
``` 

## いよいよ本題(Cmakeは使わないver)

main関数を適当に作る。
``` main.cpp
#include <iostream>

int main(int, char**){
    int minaideyo = 0;

    char minaideyo_str[128] = "iyan"; 

    std::cout << "Hello gdb on vscode!\n";

    return 0;
}
```

VSCodeでCtrl+Shift+Pを押して、コマンドパレットを開き、Configuration Tasksを探す。クリックするとおおむね以下のようなファイルができるはず。ビルドするときに何を唱えるかということが書いてある。labelがポイント。
``` tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "My Make for WSL",
            "type": "shell",
            "command": "g++",
            "args": [
                "-g",
                "${file}",
                "-o",
                "HelloVSC"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
       }
    ]
}
```

VSCodeの左の三角ボタン（デバッグと実行）を押して、構成がなんたらを選ぶとおおむね以下のような設定ファイルが生成される。立ち上げる時のgdb設定を書いているようだが、preLaunchTaskのところにTasks.jsonのlabelで書いた名前を入れておくことがポイント。gdb起動する前にTasks.jsonの通りにビルドしろよって感じか。ここまでやって、再生ボタンを押すとうまくいくと、デバッグモードでプログラムが立ち上がる。ブレークポイントやらなんたらを設定すると変数のウオッチも可能だ。本家Visual Studioでもやってみたが、こちらのほうが簡単に設定できる印象。VSCodeは玄人向けなんよ。つらい。が、なんとか動かすことができた。
``` launch.json
{
    "version": "0.2.0",

    "configurations": [
        {
          "name": "(gdb) Hello gdb world",
          "type": "cppdbg",
          "request": "launch",
          "program": "${workspaceFolder}/HelloVSC",
          "args": [],
          "stopAtEntry": false,
          "cwd": "${workspaceFolder}",
          "environment": [],
          "externalConsole": false,
          "MIMode": "gdb",
          "miDebuggerPath": "/usr/bin/gdb",
          "setupCommands": [
            {
              "description": "Enable pretty-printing for gdb",
              "text": "-enable-pretty-printing",
              "ignoreFailures": false
            }
          ],
          "preLaunchTask": "My Make for WSL"
        }
      ]
}
```

### 参考文献

https://zenn.dev/boiledorange73/articles/0056-wsl-vsc-gcc

https://qiita.com/_masa_u/items/d3c1fa7898b0783bc3ed

https://daily-tech.hatenablog.com/entry/2018/11/17/012113
社員向けWebアプリケーションでAzureB2Cを採用するまでの検討経緯

とある社内向けWebアプリを開発するときに認証基盤をどうするか検討した。
クラウドはAzureを使うので、Azure内でなんとかする。

## 前提
* 特に社内でActiveDirectoryなど使用していない
* 社員全員がメールアドレスを持っているわけではない　
    * 社員番号くらい
* 使用するのは社員のみ、ゲストなども必要なし
* 認証基盤自体は無料で使いたい
* ユーザー数は〜１，０００程度

# 候補
Azureの認証基盤なので候補は実質２つ
1. EntraID
1. Azure AD B2C
## EntraID (Azure AD B2B)
* 会社などの組織向けの認証基盤
* すでにADを導入してると連携できたりする


### B2Bは導入しなかった、その理由

#### ログイン画面のカスタマイズができない
B2BではPremium（等）でないとログイン画面のカスタマイズができません。
通常のMicrosoftログインの画面になる。
参考）https://learn.microsoft.com/ja-jp/entra/fundamentals/how-to-customize-branding

### けどB2Bではできること

#### MicrosoftGraphAPIが使用できる
meの情報などを取ってこれる＝トークンに載らない追加情報をAPIから取ってこれる。
追加情報に部署など入れていても安心。

#### グループの情報がトークンに載せられる
グループ＝ロールの設定をすることによりロールベースのアクセス制御がかけやすくなる。



## Azure Active Directory B2C を利用することにした
* 一般Webアプリで使われるような感じ（ソーシャルログインなど）
    * 公式）https://learn.microsoft.com/ja-jp/azure/active-directory-b2c/overview

#### ログイン画面がカスタマイズできる
Webに不慣れな方でも一目で自社のアプリだとわかってもらえる。

### ただし…
#### GraphAPIは使用できない
`User.Read.All`の権限を与えてもダメみたい。

#### グループなど、トークンに載せられない属性がけっこうある
トークンに載せたい情報は無理やり他の項目にマッピングさせた。
上記のようにロールが使えないので、必然的にポリシーベース認証の実装が必要。

## B2Cを使うにあたり
不特定のサインアップをさせるわけではないので、ユーザーはSDKを利用して一括作成する。
### ユーザーのインポート
B2BとB2CではSDKからのユーザーの作り方が違います。
B2Bと同じように作ってしまうと、非ローカルアカウント＝B2Cのフローでログインできないユーザー
になってしまうので注意。
正しくは↓を参照
https://learn.microsoft.com/en-us/graph/api/user-post-users?view=graph-rest-1.0&tabs=csharp#request-1
Identitiesは複数無くても良い、メールアドレスでのログインなら

``` cs
SignInType = "emailAddress"
```

を指定しておく。


#### 所感
わかってしまえば簡単なんだけど、どうも公式がわかりにくい＆ネットでの情報が少なめ…
あとチュートリアルがそのまま動かなかったりするのもわかりにくい…
Queue　を使ってみよう

Queue
この単語を最近聞くようになり、用語として扱えていない、理解していない部分があるので、まとめておく。

# Queue とは
　Queue（キュー）は、コンピュータサイエンスにおいて非常に重要なデータ構造の一つ。Queueは、FIFO（First-In-First-Out）の原則に基づいて動作するコレクションのこと。
　これは、最初に追加された要素が最初に取り出される。Queueは、日常生活で行列に並ぶことに似ている。最初に並んだ人が最初にサービスを受けるのと同じというイメージがいいか。

主な操作は以下の通り

Enqueue: Queueの末尾に要素を追加します。
Dequeue: Queueの先頭から要素を取り出し、それを返します。
Peek/Front: Queueの先頭の要素を見ますが、それをQueueから取り除きません。
IsEmpty: Queueが空かどうかを確認します。

## Laravelで扱う時の例

Laravelでも、Queueを使って非同期タスクを処理することができる。これは、メール送信、データベースの大量のデータ処理、遅延API呼び出しなど、時間がかかる処理をバックグラウンドで実行するのに役立つ。LaravelのQueueシステムは、アプリケーションのパフォーマンスを向上させ、ユーザーエクスペリエンスを改善するのに非常に有効である。

### Queueの設定
.env ファイルでQueueドライバーを設定できる。
Laravelは、sync、database、beanstalkd、sqs、redis、nullなど、複数のドライバーをサポートしている。

### Jobクラスの作成
Queueで実行するタスクは、Jobクラスとして定義される。メール送信のjobを例に考えてみる。

```
php artisan make:job SendWelcomeEmail
```

```
namespace App\Jobs;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class SendWelcomeEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        // メール送信のロジック
    }
}
```

### Jobのディスパッチ
作成したJobをQueueに追加するには、dispatch メソッドを使用。
Modelクラスやcontrollerクラスで使用することが多い。
```
SendWelcomeEmail::dispatch($user);
```


### Queueの実行
```
php artisan queue:work
```

例えば、ユーザー登録後にウェルカムメールを送信する場合、ウェルカムメールの送信をJobとしてQueueに追加し、バックグラウンドで処理することができる。


# まとめ
Queueは、さまざまなシナリオで使用される。例えば、プリンタのタスク管理、コールセンターの呼び出し管理、オペレーティングシステムのプロセス管理などがある。仕組みを理解して、プロダクトの実装に落とし込んでいきた。
バイクのエンジン始動時のクランキング電圧・電流の測定

# 背景
以前バイクのバッテリあがりが気になり、暗電流の測定をしました。
その時、エンジンかかる時と、かからない時って何が違うんだろう？と疑問に思いました。

バッテリが古くなると、明らかにエンジンかけるときの振る舞いが変わってきます。
なら、電圧・電流を測ってみるかと思い立ちました。
![スクリーンショット 2024-01-04 21.19.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048586/3c1e348c-c78a-4a45-31a6-7d26e2102818.png)

# 結果
![スクリーンショット 2024-01-05 21.35.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048586/b187dfdd-1d07-ec9d-ffa1-3d103a45d332.png)
測定開始から3秒付近でイグニッションオン。セル回したら110Aに達しています。この時、電圧が約１２Vから約７Vに。　その後、約４Vまで落ちてます。
数回セル回しましたが、エンジンかからず。

# 計測環境

![スクリーンショット 2024-01-05 18.01.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048586/0bcba39a-2541-4be5-7112-73af1197d316.png)

Pythonコードと計測結果(csvファイル)は[こちら](https://github.com/AbeMarkn/AmpMonitor)

# 主な使用機器
| # | 品名        | 補足 |
|:-:|:----------:|:-:|
| 1 | バイク       | CB1300 15年ぐらい乗ってます  |
| 2 | ラズパイPico | 電圧・電流計測用  |
| 3 | EEPROM　     | 秋月電子通商さん [24FC1025-I/P](https://akizukidenshi.com/catalog/g/gI-03570/)  |
| 4 | 電流センサ   | Strawberry Linuxさん [INA226iso-250](https://strawberry-linux.com/catalog/items?code=14226)|
| 5 | ラズパイ5    | ログ解析用。技適未取得機器を用いた実験等の特例制度申請済み。  |

# 設計
![スクリーンショット 2024-01-04 21.48.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048586/bdbc688f-f923-c578-c0c3-ad34880660ba.png)

# 所感
もう少しでエンジンかかりそうだが、バッテリが大電流を供給しきれず、電圧も落ちて「はい終了」って感じかな。

# あとがき
今回作った装置で今まで見れなかった電流が計測できるようになりました。
車のバッテリだとエンジンかかったので、バッテリ交換が必要と判断し、Amazonでポチりました。
バッテリが届いたら、新旧バッテリと車のバッテリの3種類で波形取って比較してみようと思います。

# おまけ
### バッテリを充電するときも測ってみました
![スクリーンショット 2024-01-04 21.10.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048586/276982c1-ed31-8380-b9ed-4fa3f435fc29.png)
縦軸が電圧\[V\]（青)・電流\[A\](灰色)です。横軸が時間[ms]です。
突入電流を抑える工夫があるようです。また、　間欠的な制御はサルフェーション除去をしているようにみえます。
古い充電器なのですが、すごい。
APIを実装するために必要な概念

# 必要な概念

- まずAPIの完成を定義すること
    - リクエストに応じてデータをDBから**抽出**し、必要に応じて**加工**、レスポンスとして**返却**する。
- 抽出、加工、返却の流れがわかりやすいコードになっていること。

# 読みやすいAPIを実装するにあたって

API以外の実装にも言えるが下記を意識する。

#### rubyの場合
コードの流れに設計の概念が反映されているか

- 配列操作がしっかりと目的に応じて使い分けられていること
    - mapは各要素に対して処理を行い新しい配列を返す
    - selectは条件式に応じて配列から要素を抽出する
    - flattenは配列の入れ子構造を均して1次元配列にする
        - これらの用途に当てはまらないが操作が必要な時に消去法でfor文を使う 

- 一度しか呼ばれない処理はループに入れない
- 戻り値を入れる変数とメソッド名を見てどのような値がくるかをわかるようにする
    - その呼び出されるメソッドはプライベートメソッドなどにして分けておく
    - 例:ECモールにおいてユーザーの好みに応じてレコメンド商品を取得するAPI(ruby on railsを使用)
    ```ruby
    def index
    	# インスタンス変数にログインしたユーザー情報が入っていると仮定
    	user = @user
    
    	# パスパラメーターとクエリパラメーターをそれぞれハッシュにまとめる
        path_params = params.slice(:shop_id)
        query_params = params.slice(:order_by, :sort_direction, :limit, :offset)
        # パスパラメーターとクエリパラメーターを一つのハッシュに結合する
        parameters = path_params.merge(query_params)
    
    	# リポジトリから商品を取得
    	item_repository = Api::ItemRepository.new()
    	items = item_repository.find_all_by_shop_id(parameters)
    
    	#ユーザーの好みに応じてレコメンド商品を取得
    	recommend_items_by_user_preferences = select_items_by_user_preferences(items,user_id)
    	
    	return recommend_items_by_user_preferences
    
    def select_items_by_user_preferences(items,user_id)
    	# ユーザーの好みに応じてレコメンド商品を取得するロジック
    ```
    
    select_items_by_user_preferencesがindexから出されることで、index内の処理の流れが見やすくなる。
    
    またrecommend_items_by_user_preferencesという変数名からどういった値が来るのか想像がつき実際のロジックを見なくても処理の流れを推測できる。
【AWS】支払い方法の登録ができない

　AWSでアカウントを作成しようとしたところ、エラーで躓いてしまったので、備忘録としてエラー原因とその対策方法をまとめます。
※解決しない場合はAWSサポートに問い合わせてみてください。

# 状況
　アカウント作成後、支払方法にクレジットカードを登録したが、「未検証」状態になり、解消できない。
 
<br>

# 解決方法
#### 1. キャッシュを削除したうえで再度「検証」してみる
　サイトのキャッシュを削除したのち、ブラウザを閉じたうえで改めてAWSを開き、支払方法の「検証」を実行します。
Chromeのキャッシュクリア方法をご紹介します。

>1.パソコンで Chrome を開きます。
>2.画面右上のその他アイコン その他 をクリックします。
>3.[その他のツール] 次へ [閲覧履歴を消去] をクリックします。
>4.上部で期間を選択します。すべて削除するには、[全期間] を選択します。
>5.[Cookie と他のサイトデータ] と [キャッシュされた画像とファイル] の横にあるチェックボックスをオンにします。
>6.[データを消去] をクリックします。

(https://support.google.com/accounts/answer/32050?hl=ja&co=GENIE.Platform%3DDesktop　より引用)

#### 2. クレジットカード会社にセキュリティを解除してもらう
　クレジットカード会社の多くは、不正とみられる取引を確認すると不正検知アラートが発動してクレジットカードの新規利用を停止します。この影響でクレジットの登録ができていない可能性があるので、クレジットカード会社に連絡し、セキュリティロックを解除したうえで再度登録を実行してみてください。
※また、AWSでは確認のために1$課金できるか否かで認証作業をしています。

#### 3. 登録したクレジット情報を削除して、再度登録してみる
　支払方法設定画面で、登録済みのクレジットを選択して削除し、再度登録しなおしてみてください。
 ※また、支払方法が1種類しか登録されたいない場合、その支払い方法は削除できないので、別の支払方法を登録したうえで、検証エラーになっているクレジット情報の削除と再登録を実施してください。

<br>

# 支払情報の登録画面への進み方を間違えている可能性
　これは私の実例になりますが、クレジットカードの検証に失敗し、何を試してもうまくいかないので後日改めて支払方法の登録を試みたとき、以下の手順で行っていたことで、失敗していました。
```
①AWSのアカウントページを開くと表示されるメッセージから「サインアップを完了」へ進む
②メールアドレス、パスワードを入力
③国コード、電話番号、CAPTHA認証を入力
④「支払方法を設定してください」というメッセージが出力され、支払方法設定画面へ進む
```


　最初の数回は上記の手順で支払方法設定画面へ進めていましたが、何度か繰り返すうちに③から④へ進む段階で画像のエラーが出されるようになりました。
<img width=80% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3668935/0211d048-6e8c-2964-fb08-4febf0b9e029.png">


そこで色々調べた結果、AWSアカウントにログイン後、以下の手順で"サインアップを飛ばして"支払方法設定画面に進めることがわかりました。
```
①AWSにログイン
②アカウントページの左側メニューから「支払設定」を開く
```

<br>

# その他(最終手段)
#### 1. エラー発生時にAmazonから届くメールに記載の原因を確認

　支払方法登録エラーが発生すると、Amazonからエラー発生のメールが届きますが、その中に考えられるエラー原因の記載があるので確認してください。
以下に、Amazonからのメールに記載の「考えられるエラー原因」を引用します。

>- AWS は現在、CVV2 セキュリティコードに対応しておりません。カード会社により、特別に対応していただく必要がある可能性がございます。
(CVV2 セキュリティコードとは、不正使用防止のための特殊な番号のことです。カードに印刷された 3 桁または 4 桁の数字で、カード番号のように浮き彫りされていないものです)
>- 初回クレジットカード情報ご登録時に一時的に最大 1 米ドル（または現地通貨で同等の金額） を課金できるかどうかで認証作業をおこなっております。
　カード会社により、小額な決済を拒否している可能性があります。なお、実際にこちらの金額が引き落とされることはございません。
>- 複数の AWSアカウントを作成された場合、各アカウントに対して最大 1 米ドルの認証作業が行われます。
カード会社により、最初の認証は認めその後の認証作業を断る可能性がございます。
>- カード会社により、インターネット上の課金処理を制限するポリシーがある場合がございます。
>- デビットカードの際は、残高が0円の場合には認証が通りません。

#### 2. AWS公式サイトに掲載の事象を確認
これまで紹介した方法で解決できない場合、ほかの公式サイト等を参照してください。
以下にいくつかサイトをご紹介します。
* AWS 請求書の支払いを行おうとしたときにクレジットカードが拒否されたのはなぜですか?(https://repost.aws/ja/knowledge-center/credit-card-declined)
* クレジットカード支払い検証の管理(https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/manage-cc-verification.html)
*アカウント・請求関連のご質問 (https://aws.amazon.com/jp/aws-jp-faq/)

#### 3. AWSサポートに問い合わせ
　これまでに書いた方法で確認しても原因がわからない場合は、該当のクレジット会社、およびAWSサポートに問い合わせてみてください。

#### 4. 他のクレジットカードを登録する
　何をしても解決しない場合は、他のクレジットカードを登録してください。
Useful Links for AEM 6.5 Development

https://www.linkedin.com/pulse/aem-cq5-interview-questions-answers-beginners-ankur-ahlawat

http://aeminterviewquestions.com/index.html

https://experienceleague.adobe.com/docs/experience-manager-65/developing/introduction/website.html?lang=ja

https://experienceleague.adobe.com/docs/experience-manager-learn/foundation/development/set-up-a-local-aem-development-environment.html?lang=en

https://helpx.adobe.com/mt/experience-manager/kb/maven-no-longer-supports-insecure-communication-over-plain-http.html

https://github.com/adobe/aem-project-archetype/blob/develop/src/main/archetype/core/src/main/java/core/filters/LoggingFilter.java

https://sling.apache.org/documentation/the-sling-engine/authentication/authentication-authenticationhandler.html

https://sling.apache.org/documentation/the-sling-engine/authentication/authentication-authenticationhandler/form-based-authenticationhandler.html

https://sling.apache.org/documentation/the-sling-engine/servlets.html#caveats-when-binding-servlets-by-path-1

https://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html

https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/difference-between-slingservlet-vs-felix-scr-annotation-vs-osgi/m-p/286240

http://www.nateyolles.com/blog/2017/05/osgi-declarative-services-annotations-in-aem

https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/difference-between-slingallmethodsservlet-and/m-p/226838

https://sling.apache.org/documentation/the-sling-engine/servlets.html#servlet-registration-1

https://sling.apache.org/documentation/the-sling-engine/filters.html

https://github.com/nateyolles/aem-osgi-annotation-demo

https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager-blogs/how-to-clear-dispatcher-cache-in-aem-aem-community-blog-seeding/ba-p/593533#:~:text=Click%20on%20the%20%22Dispatcher%20Flush,that%20you%20want%20to%20refresh.

https://experienceleague.adobe.com/docs/experience-manager-65/developing/platform/query-builder/querybuilder-api.html?lang=ja&mt=false

https://www.aemcq5tutorials.com/tutorials/create-system-user-in-aem/#what%20is%20system%20user

https://experienceleague.adobe.com/docs/experience-cloud-kcs/kbarticles/KA-20589.html?lang=en

https://experienceleague.adobe.com/docs/experience-manager-65/content/implementing/deploying/configuring/configuring-osgi.html?lang=ja
GestureDetectorは、デフォルトでは透明要素に反応しない

アイコンが妙にタップしにくいので原因を調べていたら、タップ範囲が想定外に狭かったという話。

結論から述べると、透明要素にも発火させたい場合はGestureDetectorのbehavior: HitTestBehavior.opaqueする必要があるという事だ。

まずは、確認用のコード
```dart:main.dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'CollisionTest',
      debugShowCheckedModeBanner: false,
      home: MyHomePage()
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _count = 0;
  void _tapCounter() {
    setState(() { _count++; });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(child:
        Column(children: [
          Text("$_count", style: const TextStyle(fontSize: 30, color: Colors.red)),
          GestureDetector(
            // これが無いとタップ領域が見える部分だけになる
            behavior: HitTestBehavior.opaque,
            onTap: _tapCounter,
            child: const SizedBox(width: 350, height: 350, child: Icon(Icons.arrow_back_ios_rounded, color: Colors.black, size: 45))
          ),
        ]),
      )
    );
  }
}

```
折り返しが雑いのは許してほしい。
flutterで一番、気になるのはレイアウトの可読性が非常に悪い事です。
閉じ括弧の連打は分かり難さMAXですよね。
縦に長くなりやすくコード全体の俯瞰しにくくなるのも問題無きがします。

話を戻します。

赤枠部分(SizedBox(350))にイベントを設定したかった。
だが実際は、behavior: HitTestBehavior.opaqueを指定していないと、Icon要素の水色の領域がGestureDetectorの発火範囲になる。

余談だが、behavior: HitTestBehavior.opaqueが無くても、Container(width: 350, height: 350, color: Colors.red, child: Icon(...))の様にコンテナが不透明であればちゃんと発火します。
うーん、微妙な仕様だ。

![CollisionTest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3322199/79441bf7-d0eb-23f0-8445-5d75f53bc009.png)
AWS Secrets Managerとは何か？の備忘録


AWS Secrets Managerを使用すると、データベースの認証情報や、パスワードなどの任意のシークレット情報をAPIコールで取得できます。各サーバからこのAPIを叩くことでシークレット情報を取得でき、認証やサーバセットアップに利用できます。﻿

AWS Secrets Manager では、シークレットを一元的に保存、取得、アクセス制限、更新、監査、モニタリングできます。 保管中のシークレットを暗号化することにより、認可されていないユーザーが機密情報を見る可能性を低減できます。


AWS Secrets Managerは認証情報を自動的にローテーションできます。例えば、データベースの認証情報を保存し、ローテーションできます。
【Next.js】App RouterでApollo Client使用時にInvariant Violationのエラー

## 概要
Next.jsのApp RouterでApollo Clientを使用した際に、表題のエラーが起きましたので対応のメモ書きを残しておきます。
なお、2024年1月時点での事象ですので今後の更新で解消される可能性はあります。

## 前提
* 使用したNext.jsのバージョンは`14.0.4`です。
* 使用したapollo-clientのバージョンは`3.8.8`です。

## 対応
[Invariant Violation APOLLO: Using next.js and ts](https://stackoverflow.com/questions/77169033/invariant-violation-apollo-using-next-js-and-ts)のstackoverflowの回答で紹介されている通り、[apollo-client-nextjs](https://github.com/apollographql/apollo-client-nextjs)というライブラリを別途使用する対応が挙げられていて、今回これを試してみました。
ただ、このライブラリは2024年1月時点でまだexperimentalな状態です。現時点で私の方で軽く動作確認したところ基本的な動作は問題ない感じはしますが、まだ完璧ではない可能性がある点だけ認識しつつ使用してください。このライブラリを使った実装については[How to use Apollo Client with Next.js 13](https://www.apollographql.com/blog/how-to-use-apollo-client-with-next-js-13)で紹介されています。

## 実装サンプル
上記で紹介した記事の実装例ほぼそのままですが、クライアントコンポーネントでApollo Clientを設定する実装は以下の通りになります。
Provider部分だけ入れ替えれば、クエリの実行部分はコードを変更しなくても大丈夫そうです。

```react
"use client";

import { ApolloLink } from "@apollo/client";
import {
  ApolloNextAppProvider,
  NextSSRInMemoryCache,
  NextSSRApolloClient,
  SSRMultipartLink,
} from "@apollo/experimental-nextjs-app-support/ssr";

// ここに今回使用した環境のlink設定を定義してある（実装は割愛）
import { apolloLink } from "@/constants/ApolloLinkConstants";

function makeClient() {
  return new NextSSRApolloClient({
    cache: new NextSSRInMemoryCache(),
    link:
      typeof window === "undefined"
        ? ApolloLink.from([
            new SSRMultipartLink({
              stripDefer: true,
            }),
            apolloLink,
          ])
        : apolloLink,
  });
}

export function ApolloProvider({ children }: React.PropsWithChildren) {
  return (
    <ApolloNextAppProvider makeClient={makeClient}>
      {children}
    </ApolloNextAppProvider>
  );
}
```
React, TypeScriptでの環境変数の設定

React, TypeScriptでのプロジェクトを管理しているとき、開発、本番といった環境ごとに異なる設定をする必要があります。
これらの環境ごとに異なる環境変数を設定する方法を書いていきます。

前提として、```create-react-app```には、dotenvというパッケージが既に入っています。


## 環境変数の設定
プロジェクトルートに環境ごとの```.env```ファイルを作成します。

・```.env```：開発環境用の環境変数を設定します。

.```env.production```：本番環境用の環境変数を設定します。

例）

```.env
REACT_APP_API_BASE_URL=http://localhost
```


## 環境変数の読み込み方
jsファイルには、```REACT_APP_```のように設定することで読み込むことができます。

例）```LoginComponent.js```など

```js
const apiURL = process.env.REACT_APP_API_BASE_URL
```

## Gitで.envファイルを無視する方法
これらの ```.env``` ファイルを Git のバージョン管理から除外します。
これにより、セキュリティ上の問題を防ぐことができます。
```.gitignore``` ファイルに以下の行を追加します：

```.gitignore
.env
```

## 参考
https://qiita.com/itinerant_programmer/items/a2875b9bd63d1f6c5912
https://qiita.com/naogify/items/37de1baf1aebb648273b
【SwiftUI】状況によってonSubmitを無効化する

# はじめに
状況によって`onSubmit`を無効化したいことがあったとします。
onSubmit内で分岐処理を書けば解決する話ではありますが、SwiftUIの機能で`submitScope`というものがあります。
上位層についている`onSubmit`を一部Viewで無効化することができるようです。

```swift
Form {
    TextField("Username", text: $viewModel.userName)
    SecureField("Password", text: $viewModel.password)

    // このテキストフィールドではonSubmitは実行されない
    TextField("Tags", text: $viewModel.tags)
        .submitScope()
}
.onSubmit {
    guard viewModel.validate() else { return }
    viewModel.login()
}
```

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 - 2024-01-05 at 21.34.41.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/1df649f9-31e2-5aa7-81e5-0f4125da16ac.gif)

# 実装
```swift
import SwiftUI

struct ContentView: View {
    @State private var text = ""
    @State private var isBlockSubmit = false
    @State private var isShowAlert = false

    var body: some View {
        Form {
            TextField("文字を入力してください", text: $text)
                .submitScope(isBlockSubmit)
            
            Toggle("onSubmitを無効にする", isOn: $isBlockSubmit)
        }
        .onSubmit {
            isShowAlert = true
        }
        .submitLabel(.send)
        .alert("送信しました", isPresented: $isShowAlert) {
            Button {
                print()
            } label: {
                Text("OK")
            }
        }
    }
}
```

# 解説
本記事のメインである`submitScope`は引数に`isBlocking`を取ります。
`isBlocking`のデフォルトはtrueです。
`isBlocking`にtrueを渡すことで`onSubmit`を無効化できます。
```diff_swift
TextField("文字を入力してください", text: $text)
+   .submitScope(isBlockSubmit)
```

今回メインではありませんが、記事で扱ったことのない要素があります。
それは`submitLabel`です。
`submitLabel`を指定することで、キーボードのリターンキーを変更することができます。
```swift
.onSubmit {
    
}
.submitLabel(.send)
```

今回は`.send`を指定しているので以下のようになります。

![スクリーンショット 2024-01-05 21.40.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/b71326eb-6d85-35de-6ba4-0e70b0334500.png)

# おわり
今回紹介した`submitScope`と`submitLabel`はiOS15から使用できます。

# 公式ドキュメント
https://developer.apple.com/documentation/swiftui/view/submitscope(_:)

https://developer.apple.com/documentation/swiftui/view/submitlabel(_:)
realsense点群取得、カラーカメラの映像と合わせてリアルタイム描画

## 1: 必要な物
RealSenseデバイス: RealSenseデバイス（例えば、D415、D435など）が必要です。
RealSense SDK 2.0:動作確認用に [Intelの公式サイト](https://www.intelrealsense.com/sdk-2/)からRealSense SDK 2.0をインストールしてください。(なくてもOK)
Python: Pythonがインストールされていることを確認してください。
pyrealsense2: Python用RealSenseライブラリをインストールしてください。
```
pip install pyrealsense2
```
numpy: numpyインストールしてください。
```
pip install numpy
```
numpy: open3dインストールしてください。
```
pip install open3d
```
## 2: 点群取得のプログラムを作成
以下は、Pythonを使用してRealSenseから点群を取得し、カラーカメラの映像と合わせてリアルタイム描画するためのコードです。

```
import pyrealsense2 as rs
import numpy as np
import open3d as o3d
import datetime

# Configure depth and color streams
pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)

# Start streaming
pipeline.start(config)
align = rs.align(rs.stream.color)

vis = o3d.visualization.Visualizer()
vis.create_window('3D Point Cloud', width=1280, height=720)
pointcloud = o3d.geometry.PointCloud()

try:
    while True:
        dt0 = datetime.datetime.now()
        frames = pipeline.wait_for_frames()
        aligned_frames = align.process(frames)
        
        depth_frame = aligned_frames.get_depth_frame()
        color_frame = aligned_frames.get_color_frame()
        if not depth_frame or not color_frame:
            continue

        # Create point cloud
        depth_image = o3d.geometry.Image(np.asanyarray(depth_frame.get_data()))
        color_image = o3d.geometry.Image(np.asanyarray(color_frame.get_data()))
        rgbd = o3d.geometry.RGBDImage.create_from_color_and_depth(color_image, depth_image)
        
        intrinsics = rs.video_stream_profile(depth_frame.profile).get_intrinsics()
        pinhole_camera_intrinsic = o3d.camera.PinholeCameraIntrinsic(intrinsics.width, intrinsics.height, intrinsics.fx, intrinsics.fy, intrinsics.ppx, intrinsics.ppy)
        pcd = o3d.geometry.PointCloud.create_from_rgbd_image(rgbd, pinhole_camera_intrinsic)

        # Transform point cloud for proper visualization
        pcd.transform([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])
        pointcloud.points = pcd.points
        pointcloud.colors = pcd.colors

        # Visualize
        if not vis.has_geometry(pointcloud):
            vis.add_geometry(pointcloud)
        vis.update_geometry(pointcloud)
        vis.poll_events()
        vis.update_renderer()

        # Calculate and print FPS
        process_time = datetime.datetime.now() - dt0
        print("FPS: " + str(1 / process_time.total_seconds()))

except KeyboardInterrupt:
    print("\nProgram interrupted by user. Closing...")

finally:
    # Clean up
    pipeline.stop()
    vis.destroy_window()
    del vis
```
AWSでCI/CDを構築する

はじめまして。この記事は、私が執筆に携わらせていただきました、ハンズオン本をベースにCI/CDについて記載させていただいたものとなります。
なお、記載内容は所属会社を代表したものではなく、私の個人的な意見ということをご了承ください。

# はじめに
パイプラインを当たり前のように構築できるようになることを目指して記載しております。

# CI/CDとは
AWSに関係なく一般的にソフトウェア開発で使われる用語です。
下記参考：
https://it-trend.jp/cicd_tool/article/937-874

CI（継続的インテグレーション）
→ソースコードの修正とテストを自動化する。

CD（継続的デリバリー）
→開発製品と検証環境や、製品が実際に動作する本番環境との連携を自動化する。

CD（継続的デプロイ）
→修正したコードを一括で反映、展開させることを自動化する。

補足事項として、デリバリーとデプロイは下記の点で違います。
・デリバリーは人の手が残る開発プロセスの自動化
・デプロイは人の手が介在しない開発プロセスの自動化
ゆえに多くの人がイメージする開発プロセスの自動化は、CD（継続的デプロイ）となります。

#  CI/CDを推奨する背景
もし、CI/CDがなかった場合は以下のことが考えられます。AWSでコンテナをデプロイするケースで考えてみましょう。
1、新しくブランチをチェックアウトする。
2、Dockerfileの変更をコードリポジトリにコミット
3、Dockerfileの変更をコードリポジトリにプッシュ
4、レビュー
5、Lint
6、フォーマット
7、イメージのビルド
8、コンテナレジストリの作成
9、イメージをコンテナレジストリにプッシュ
10、コンテナレジストリからイメージをpull
11、コンテナ基盤にデプロイ

AWSの場合、ECRを利用します。ECRは異なるアカウントで同じリポジトリを設定することができます。そのため、プロファイル名を間違えてプッシュしてしまうこともあります。
デプロイするまでにはいくつかの工程を踏む必要があり、その工程を踏んだうえでソフトウェアの品質を確保する必要があります。
利益には直結しないが必要な作業をトイルと言います。これらの工程を人が作業する場合、ミスがつきもので、そのミスによってデプロイ作業に遅延が発生することが考えられます。
そこでCI/CDを導入することによってトイルを除去するために工程を自動化しようというのがCI/CDを推奨する背景となります。

#  AWSでCI/CDを実現するためには？
AWSでは下記のサービスが主に使われています。
AWS CodeCommit・・・コードを保管しておくGitリポジトリサービスを提供する。
AWS CodeBuild・・・コードをビルドする環境を提供する。
AWS CodeDeploy・・・実際に動作する環境にコードを自動でプロイする。
AWS CodePipeline・・・Codeシリーズのサービスの統括と他のAWSサービス、サードパーティツールとの連携を提供する。
AWS CodeStar・・・他のコードプロバイダとの連携、プロジェクト環境を提供する。
AWS CodeArtifact・・・ソフトウェアパッケージをAWS上にキャッシュして保存するサービス。
Amazon CodeGuru・・・コードのレビューやパフォーマンスを計測して推奨事項を回答するサービス。
Amazon CodeCatalyst・・・2022年12月のre:Inventに登場した統合開発サービス。
Amazon CodeWisperer・・・LLM（大規模言語モデル）を採用したAIコード支援サービス。

なお、AWSのみでCI/CDを実現するためには、AWS CodeCommit・AWS CodeBuild・AWS CodeDeployの3つのサービスをAWS CodePipelineで連携して自動化することが可能です。

具体的な手順は参考書籍でハンズオン形式で記載されていますのでそちらをご参照ください。

#  参考書籍
私も執筆に携わらせていただきました。
下記の書籍では初級者からでもCI/CDの構築が出来るように丁寧に説明されています。
*「CodeシリーズでハッピーなCI/CDを構築しよう【AWSハンズオン虎の巻シリーズ】: 知識がなくても手を動かしながらCI/CDをAWS上に実装できる一冊！」*
https://amzn.asia/d/aHqx6vF

![Screenshot 2024-01-09 23.24.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780811/0795e235-2e6a-1a7d-4121-4e9201c99674.png)
プログラミング初学者要注意コンテンツ まとめ

## Pythonの初学者は注意すべきだと思う教材まとめ

ざっと箇条書きにすると以下（思いつき次第更新予定）

1. 酒井さんのPython、Udemy講座
1. ドットインストール Python入門クラス編
1. ドットインストール Python入門 標準ライブラリ編

### 1. 酒井さんのPython、Udemy講座
こちらは別の記事に書きました。なぜ初学者におすすめでないかを書いています。
https://qiita.com/loggrammer/items/ec2d12413ed032028958

### 2. ドットインストール Python入門クラス編
Pythonで初めてクラスを学習する人にはあまりお勧めできないと思います。インスタンスを作る際、いきなりリストのなかに作成したりしていて、初学者はとにかく「うわ、クラスむっず。複雑すぎ」って印象を受ける気がします。
（クラスをまだ知らない人が最初から見ても、全然わからないのでは、、、と正直思います）
自分はPythonのクラスを初めて学ぶ時Paizaの教材で学びましたが、その時はもっとすんなり学べました。
（自分が学んだPaizaの教材はこちら）
https://paiza.jp/works/python3/primer/beginner-python8
またPythonのクラスを学ぶにはPaizaじゃなくProgateのコースもおすすめです。
https://prog-8.com/lessons/python/study/4
https://prog-8.com/lessons/python/study/5
順番はPaizaとProgateは、どちらが先でもいいですが、自分はPaizaでふんわり理解。Progateでしっかり理解。ドットインストールで、より実践的、応用的な使い方を学ぶ感じでやってよかったです。
（ドットインストールは内容がまとまっていて、教えてくれる内容が浅すぎない。そして1動画が短くて、復習しやすい。という自分の思うめちゃいい教材ではあります。ドットインストールで学ぶときは、そのコースの最初から通しで学ぶのがいいでしょう。途中から見るのではなくて。）

### 3. ドットインストール Python入門 標準ライブラリ編

これは、標準ライブラリーに遭遇した時、見ると端的にわかりやすく教えてくれていて助かります。
ですが、まだdatetimeモジュールに遭遇してない人からすると、ふーんなにこれ？となる気がします。そうなったら一旦飛ばして、必要になった時みるといいと思います。
そもそもライブラリって何？みたいな状態の人はまずライブラリが何かを教えてくれてる前の講座をみて勉強すると良いと思います。
全て順番通りに進めようとせず、目的のために勉強する方が頭にも入ってきやすいでしょう。
配列やオブジェクトはconsole.table()で見ると分かりやすい

## コード
- 以下の変数`menuList`は7個のオブジェクトを持った配列
```js
const menuList = [
  {
    name: "チーズバーガー",
    price: 500,
    category: "food",
  },
  {
    name: "てりやきバーガー",
    price: 550,
    category: "food",
  },
  {
    name: "月見バーガー",
    price: 600,
    category: "food",
  },
  {
    name: "ベーコンレタスバーガー",
    price: 550,
    category: "food",
  },
  {
    name: "コーヒー",
    price: 200,
    category: "drink",
  },
  {
    name: "オレンジジュース",
    price: 250,
    category: "drink",
  },
  {
    name: "コーラ",
    price: 180,
    category: "drink",
  },
];

console.table(menuList);
```

![スクリーンショット 2024-01-05 21.10.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/bcd091f1-e2e5-ea9c-bb39-0f821f35a77b.png)


## 最初(0番目)のオブジェクトだけ抜き出してみる

```
console.table(menuList[0]);
```

![スクリーンショット 2024-01-05 21.10.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/360e2b8d-8417-981f-8fe6-82c67fe4ff65.png)
【PowerShell 7】フォルダをzip形式に圧縮する際にメモリ使用量を抑える方法

# 前提
環境は、以下である。
OS : Windows 10 22H2
Powershell : 7.4.0
メモリ : 16GB
※ 最低限必要そうな情報のみ、記載している。
# 結論
ZipFileクラスのCreateFromDirectoryメソッドでフォルダをzip形式に圧縮する。
- フォルダを圧縮する場合のサンプルコード 
``` powershell
$folder = Join-Path $env:USERPROFILE "\Desktop\Test"
$zip = Join-Path $env:USERPROFILE "\Desktop\Test.zip"
[IO.Compression.ZipFile]::CreateFromDirectory($folder,$zip)
```
# 詳細
Compress-Archiveコマンドレットを使用して、サイズの大きいフォルダを
圧縮しようとすると、メモリ使用量が多くなる。

私が、以前、18.4GBのフォルダをCompress-Archiveコマンドレットで
圧縮した際は、メモリ使用量が90%以上になった。
同じフォルダをZipFileクラスのCreateFromDirectoryメソッドを使用して圧縮すると、
メモリ使用率が多い時でも、40%台に収まった。

# 参考文献
https://serverfault.com/questions/846493/powershell-compress-archive-consuming-all-memory

https://qiita.com/sueasen/items/91d931ef4a6f053aba26

https://qiita.com/pilot/items/f18139c0e41d0997f06d

https://learn.microsoft.com/ja-jp/dotnet/api/system.io.compression.zipfile.createfromdirectory?view=net-7.0#system-io-compression-zipfile-createfromdirectory(system-string-system-string-system-io-compression-compressionlevel-system-boolean-system-text-encoding)
日本語文字化けを解決する

Rocky LinuxにNotoフォントをインストールする手順を説明します。以下のステップに従って操作してください。

**ステップ 1:** ターミナルを開きます。

**ステップ 2:** Notoフォントを検索します。以下のコマンドを実行します。

```
sudo dnf search noto
```

このコマンドで、利用可能なNotoフォントのリストが表示されます。

**ステップ 3:** フォントをインストールします。日本語と中国語の両方に対応するフォントをインストールするために、次のコマンドを実行します。

```
sudo dnf install google-noto-sans-cjk-jp-fonts
sudo dnf install google-noto-serif-cjk-ttc-fonts
```

これにより、Noto Sans CJK JPフォントとNoto Serif CJKフォント（セリフスタイル）がインストールされます。

**ステップ 4:** インストールが完了すると、フォントはシステムに追加されます。Pythonスクリプトなどでこれらのフォントを使用する場合、フォントファイルのパスを指定する必要があります。

例えば、Noto Sans CJK JPフォントを使用する場合、フォントファイルは通常 `/usr/share/fonts/noto-cjk/` ディレクトリ内にあります。フォントファイルの正確なパスは、インストール後にシステムで確認できます。

これでRocky LinuxにNotoフォントがインストールされ、日本語と中国語のテキストを表示するのに役立ちます。

なお、Sans CJK JPフォントへのパスは以下です。
font_path = "/usr/share/fonts/google-noto-cjk/NotoSansCJKjp-Regular.otf"  # Noto 

### 事後追記
このエラーメッセージは、PythonのPillow（PIL）ライブラリが見つからないことを示しています。Pillowは画像処理のためのライブラリであり、PILの代替として使用されます。

Pillowをインストールするには、ターミナルで次のコマンドを実行します。

```
pip3 install Pillow
```

これにより、PillowライブラリがPythonに正しくインストールされ、エラーが解消されるはずです。インストールが成功したら、プログラムを再実行してみてください。
NetworkX入門 (2)

# ノードの色を変える

エッジに矢印を付ける（無向グラフから有向グラフに変換する）・・・次回。
ノードやエッジを増やす／別の方法で追加する・・・次回以降。

今回は、ノードの色を変えるだけ。デフォルトでは濃い青色で、文字が黒なので読みづらい。

```Python
import networkx as nx
import matplotlib.pyplot as plt

G = nx.Graph()
G.add_node(1)
G.add_edge(1, 2)

nx.draw_networkx(G, node_color='lightblue')
plt.savefig('file02.png')

```

最初の６行目までは前回と全く同じ。
ノードの色を変えるには、グラフ出力時にnode_colorを指定する。
1個1個のノードの色を変えることも可能だが、今回はただ見やすさのために薄い青色で統一した。

![file02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78475/19475252-3010-8bec-3efc-d26150a851f9.png)

エッジについても同様で、下のコードで変換可能。今回は濃い灰色に変換してみた。

```Python

nx.draw_networkx(G, node_color='lightblue', edge_color='dimgray')
```
EKS on ALB でターゲットが healthy になってから Pod を終了させる - Readiness Gate

# Pod readiness gate

ローリングアップデートで新しい Pod を起動
　↓
ヘルスチェックに成功し、新しい Pod が起動後、古い Pod を削除

EKS + ALBの場合 Pod の起動後に AWS Load Balancer Controller によって ALB にアタッチされるというステップがあるため、アタッチが完了するまでに古い Pod が削除されてしまうと処理可能な Pod がなくなり一時的なダウンタイムが発生する可能性がある。

Readiness Gate は AWS Load Balancer Controller でも ALB のターゲットが healthy になってから Pod の status を Ready にする(古い Pod の削除を開始する)という機能である。

https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.1/deploy/pod_readiness_gate/


# Readiness Gate 設定前

下記を参考に、EKS + ALB　を構成し、Readiness Gate を設定前の動作を確認しておく。

https://qiita.com/leomaro7/items/e79f1f057fefc523ff02

下記の通り、READINESS GATES のステータスは　none です。

```
kubectl get pod -o wide
NAME                                READY   STATUS    RESTARTS   AGE     IP                NODE                                                         NOMINATED NODE   READINESS GATES
nginx-deployment-797bc47df8-g7klt   1/1     Running   0          3m47s   192.168.106.180   fargate-ip-192-168-106-180.ap-northeast-1.compute.internal   <none>           <none>
nginx-deployment-797bc47df8-gkwmt   1/1     Running   0          4m48s   192.168.185.187   fargate-ip-192-168-185-187.ap-northeast-1.compute.internal   <none>           <none>
```

ALB のターゲットグループで新しい Pod の initial が走ると同時に古い Pod の Draining が始まりました。

![スクリーンショット 2024-01-05 20.08.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/dc6f584d-0b00-dd82-ea12-dd90f4255e2f.png)


# Readiness Gate 設定後

`elbv2.k8s.aws/pod-readiness-gate-inject: enabled`の label を namespace に入れる事で Readiness Gate を有効にします。

```yaml
apiVersion: v1
kind: Namespace

metadata:
  name: readiness
  labels:
    elbv2.k8s.aws/pod-readiness-gate-inject: enabled
```

下記の通り、READINESS GATES のステータスは　1/1 です。

```
kubectl get pod -o wide -n readiness

NAME                                READY   STATUS    RESTARTS   AGE     IP                NODE                                                         NOMINATED NODE   READINESS GATES
nginx-deployment-797bc47df8-rkgtg   1/1     Running   0          2m44s   192.168.187.137   fargate-ip-192-168-187-137.ap-northeast-1.compute.internal   <none>           1/1
nginx-deployment-797bc47df8-zw6lw   1/1     Running   0          91s     192.168.177.147   fargate-ip-192-168-177-147.ap-northeast-1.compute.internal   <none>           1/1
```

ALB のターゲットグループで healthy にならないと古い Pod が draining に入らないため、期待通りの動作となりました。

![スクリーンショット 2024-01-05 20.35.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/365b9ce7-b71d-1dab-1310-318dc0530fbc.png)
可能性ありそうなサービスを思いついたからとりあえずLPを作っ(てもらっ)た

::: note
株式会社mofmofは受託開発会社ですが、メンバー自らがオーナーとなってプロダクト開発にチャレンジしています。
この記事は、NestJS, 生成AIにチャレンジする「金曜日のチーム開発」の成果です。

https://indie-dev.mof-mof.co.jp/
:::

サービス作りの定石の一つとして「先に顧客を見つけてから作り始める」という方法がありますよね。
よく聞くのはLPだけを先に作って、反響があったら実際にサービス開発を始めるという方法などです。

今回はこのアプローチに挑戦できる機会があったので、それについて記事にまとめました。

「このアプローチをしてみてどうだったか」という内容ではなく、「こんなことをやってみました」という紹介に近いので、メッセージ性は薄い記事になります。

ちなみにタイトルが「作った」ではなく「作ってもらった」なのは、今回作ったサービスのPOは自分だけど、実際の開発はチームメンバーに作ってもらったためです。
まあPOとしてサービス作りにはずっと関わっていたので、以後は「作った」と表現してしまいます。


今回の取り組みは、会社全体としてNestJSと生成AIのキャッチアップを行おうためにチーム開発をするという企画に乗っかったものです。
生成AIを使ったサービスという条件の中で、ArgosというAPIサービスを考えました。


# 作ったもの
https://argos.tokyo/

詳しくは上記のLPを見てもらえばわかるのですが、Argosを簡単に説明するとArgosはセンシティブな文章かを判定したい文章を投げると、それがセンシティブかどうかを判定してJSONで返してくれるAPIサービスです。

今回はArgosを作成したのはLPとLP上で試せるデモです。


Argosの利用シーンとしては、漫画アプリや動画アプリのコメント欄、レビューサイトのレビュー欄、SNSなどユーザ投稿コンテンツのあるサービス全般です。
複数のユーザが思い思いの投稿を行うサービスでは、どうしてもユーザ同士が言い争う、いわゆる「荒れる」という状況が起きがちです。
そして、その発端は一人のユーザーの攻撃的な投稿からだったりします。

Argosを投稿時の処理に噛ませることで、あらかじめ荒れる原因となるようなセンシティブな文章かどうかを判定し、NGであれば弾くということを行うことで、荒れを事前に防ぐことができます。
そうすることで、荒れた後に人力で対応するオペレーションコストを節約することができます。

# なぜLPをつくったのか
時間やリソースが許すならサービス全体を開発してしまうという方法もありましたが、企画の都合上、開発にかけられるリソースは限られていました。
なので、まずはLPとデモだけを公開し、反響があるかどうかを確かめるところまでを行おうと決めました。

LPには問い合わせフォームを用意しているので、問い合わせから反響が得られたら、実際にサービスとして作っていくことを考えようという算段です。

# やってないこと
デモができるところまでは作りましたが、APIとして一般公開できるところまでは作成してません。
具体的には
- apiの一般公開
- apiを利用するためのtoken発行機能
- apiの利用量に応じた請求機能
- ユーザーが使う管理画面

などです。

# サービスコンセプトへの想定質問への回答
> センシティブ判定のサービスは既に存在しないの？

↓
あります。
ありますが、どれも単純な文字列一致での判定でした。
生成AIを利用すれば文脈まで理解した判定ができるので、そこが差別化ポイントだと考えています。


> Argos使わなくても自前でOpenAI API使えば良くない？

↓
そのほうが単純な利用コストだけならベストだと思います。
しかし、自前で実装するにはOpenAI APIの設定だとかプロンプトエンジニアリングの部分でのチューニングなどが必要になります。
Argosを使えばAPIに文章を投げればいいだけなので、実装コストが非常に低いです。
この面で差別化できると考えました。

# やってみての感想
「生成AIをつかったサービス作りはPoCがめちゃくちゃ重要」というのが一番の感想です。
正直なところ、今回のデモとして作ったセンシティブ判定機能は構想段階で想定していたレベルではありません。（満足いくところまで作り込む時間が足りなかった）。

具体的には「精度面」と「速度面」の二つです。
詳しくは省きますが、OpenAIのどのモデルを使うのかであったり、どんなプロンプトにするのかのチューニングが難しいと感じました。
また、プロンプトエンジニアリングだけ精度を高めきれない部分はプログラミングで解決する必要もあると感じました。


余談ですが、PoCが重要というのは生成AIを活用した受託開発の相談をもらった時にも強く感じることです。
というよりは、PoCからやり始めるしか選択肢がないというのが正しいかもしれません。

今回も開発中に新しいモデルが使えるようになり、それに対応するということがありました。
生成AIの領域は進化の速度が速く、思いついたアイデアが実現できるかどうかは実際にある程度試してみるまで本当にわかりません。

そのため、必然的に「まずはPoCからやりましょうか」という話になるんですね。


この企画においても、メイン目的が技術のキャッチアップだったためLPとデモを作るところまではやり切りましたが、サービス作りという意味では精度と速度面で満足できない可能性が見えた時点でストップするべき企画だったかもしれません。

# まとめ
というわけで、NestJSと生成AIを使ったセンシティブ文章チェックAPI「Argos」の紹介と、アイデアの検証のためにLPとデモを作ったという話でした。

ArgosのデモはLPから試すことができるので、気になった人は試してみてください。
そして実際にサービスとして利用してみたいと思った方はぜひお問い合わせをください！
本気で取り組みます！笑

https://argos.tokyo/


Argosの開発をしてくれたチームメンバーの記事もあるので、併せて読んでみてください。
[nest generateコマンドからざっくりとNestJSを把握する
](https://qiita.com/kmkkiii/items/adebde644012aedec1bd)

[センシティブな文章を判定するAPIを作りました（NestJS+OpenAI API）](https://qiita.com/shinji256/items/4f77069476754d25987e)

[NestJS・Handlebars・TailwindCSSでMVCアプリをつくる](https://zenn.dev/tatehito/articles/62ae9b8cf8f3b9)
個人開発でサービスを作ってみた

個人開発でサービスを作って公開したので、その諸々に関して記録に残しておこうと思います。

作ったものはこちらです！

https://lp.tuzuriba.com/

サービスのコンセプトや主な機能はこちらに書いてます。

https://media.tuzuriba.com/column/what_is_tuzuriba/

## なぜ作ったのか
ものづくりが好きだからで、完全に趣味です！

## どうやって作ったのか
### 1. 企画
お仕事の場合はお金を産まなければいけないので、誰の何をどうやって解決するのか・解決したとしてお金を産むのか、みたいなことを何度も繰り返し検証して精度を高めていく必要がありますが、個人開発なのでその辺は特に考えていません。

「こんな感じの世界観が実現出来たら良いなぁ」というふんわりした考えがあったので、開発着手する前にまずはランディングページを作って、血迷わないように考えを明確化しました。（ランディングページは上に貼ったものです）

### 2. 開発
ランディングページを見返しながら、最低限この辺の機能があればコンセプトを表現できそうかな？というラインを決め、それらの機能を実装していきました。

今回の個人開発は、技術を極めたいという思いではなく、少しでもちゃんと誰かに使ってもらえるようなサービスを作りたいという思いが強かったので、技術選定は割と適当で得に冒険とかもしてません。

使い慣れていて、この辺使っておけば実現できないことはないだろう、というような技術スタックです。

インフラ：主にGCP
バックエンド：Java（Spring）
フロントエンド：TypeScript, React, Tailwind

プラットフォームは基本的にWEBアプリのみですが、PWAにしているのでスマホアプリとして起動できるようにもしています。（一応Play Storeにも上げています。iPhone向けはお金かかるし大変そうだったので今は断念）

また、サービスのアップデートや将来的に集客も担うかもしれないメディアサイトをHugoで作成し、Netlifyにデプロイしてます。

### 3. リリース
動くものを早くデリバリーしたかったので、Cloudbuild・GitHub Actionsを使ってCICDを組み、ソースがマージされたら勝手にデプロイされるようにしています。

### 4. マーケティング
サービスのコンセプト的に、活字に抵抗が無くいわゆる丁寧な暮らしを心掛けているような方をユーザーとして想像しています。
なので、本屋とか読書メーターのようなサイトとかそういう所を入口に出来たら良いかもなぁ、なんて思っていましたがお金がかかりそうなのでやめました。

とりあえずMeta広告（ほぼインスタ）に2万くらい突っ込んでみました。

作ったものをユーザーに送り届ける過程は全然経験がないので、今後ゆっくりと色々試してみたいなと思っています。

## 現状
11月中旬頃にリリース（広告開始）をしてから、一か月半くらい経った今の状況はこんな感じです。

**LPに来てくれたユーザー数：** 1472
**ゲストユーザーを含む、総ユーザー数：** 956
**アカウント作成したユーザー数：** 50
**体感的にアクティブに使ってくださっているユーザー数：** 40くらい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2289954/aae94af2-13b7-3350-b159-9a5b85e0f8bf.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2289954/42111cfc-1d26-d339-9214-0497ec3f93bd.png)

#### うれしいお声
もっと使ってくれる人が増えてくれたら嬉しいなあと思う一方、使ってくださっている方からはいくつか良い声も挙がりました。めちゃんこ嬉しいです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2289954/7bca7636-56f8-240f-0a45-77018cc6904e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2289954/21c956a5-205b-50ea-827f-0f62723661bc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2289954/2a8b6fd1-6a3a-0ee6-107e-ab1033f72d1c.png)


## 今後
機能に関しては、コンセプトは変えずよりサービスが良くなるようなものがあれば実装していくつもりです。

また、今はインフラが無料枠に収まっているのでランニングコストがほぼゼロですが、もし嬉しいことにユーザーが増えてコストがかかってきたら、何かしらの方法でマネタイズすることを考えなきゃなと思っています。
（安易に広告とか出すと世界観を棄損しかねないので、何か別の方法を考えるつもりです）

あとはマーケティングをもっと頑張りたいです。
バリデーションエラーは302リダイレクトを返すのが「あたりまえ体操」だった件について

## はじめに
テストを書いている際、バリデーションエラーを返すスクリプトを書いているはずなのに、なぜかテストをパスしてしまうことがありました。

その理由は何でしょうか？

有識者の方は、症例を見ながら是非推理していただければと思います。

## 環境
Laravel 9.52.16

## 問題
* 以下のようなコントローラのアクションをテストしたい

```php: SalesOrdersController.php（一部略）
public function store(Request $request)
    {
        // バリデーション
        $request->validate([
            'title' => 'required|max:2000',
            'sales_abstract' => 'required|max:2000',
            'category' => 'required|max:50',
            'budget' => 'required|numeric',
            'schedule' => 'required|date',
        ]);

        // 認証済みユーザの発注として作成（リクエストされた値を元に作成）
        $request->user()->sales_orders()->create([
            'title' => $request->title, 
            'sales_abstract' => $request->sales_abstract,
            'category' => $request->category,
            'budget' => $request->budget,
            'schedule' => $request->schedule,
        ]);

        // 前のURLへリダイレクトさせる
        return back();
    }

```

そこで最初に次のようなテストコード（失敗例）を書きました。

```php: SalesOrdersControllerTest.php（一部略）
public function test_sales_store(): void
    {
        // テスト用のユーザを作成
        $user = User::factory()->create();

        // 作成したユーザで認証
        $response = $this->actingAs($user)->post('/my/sales/store');

        $response->assertStatus(302);
    }
```

しかし、上記テスト内ではpostメソッドにフォームデータを渡していません。

先ほどのコントローラ内にはバリデーションがあるので、フォームデータがなければバリデーションエラーを返すはずです。

つまり自分はこのテストが通らず、エラーを返すことを期待していました。

```terminal: Tinker上
root:/var/www/html/niches# php artisan test --filter test_sales_store

Deprecated: PHP Startup: Use of mbstring.internal_encoding is deprecated in Unknown on line 0

Deprecated: PHP Startup: Use of mbstring.internal_encoding is deprecated in Unknown on line 0

   PASS  Tests\Feature\SalesOrdersControllerTest
  ✓ sales store

  Tests:  1 passed
  Time:   9.81s
```

しかしなぜか上のようにテストが通ってしまい「？？？」となっていました。

バリデーションエラーは発生しなかったということでしょうか？

## 解決法（答え）
* 実際にはバリデーションエラーは発生していた
* しかしバリデーションエラーもreturn back()と同じく、302リダイレクトを返す
* そのためassertStatus(302)が通った
* よってテストが通った



### バリデーションエラー時の動作

**①リダイレクト**：
バリデーションルールに違反すると、Laravelはユーザをフォームがあった元のページにリダイレクトします。ユーザがフォームを修正して再度送信できるようにするためです。

**②エラーメッセージの表示**：
そしてリダイレクトともに、「パスワードは半角英数字16字以内で入力してください」といったエラーメッセージが表示されます。

**③ステータスコード**：
そしてこのリダイレクトはHttpステータスコード「302」を伴います。

つまり自分が書いたテストコードは、成功しても失敗してもパスされるような構造になってしまっていました。

## この場合の正しいテストコード
```php: SalesOrdersControllerTest.php
public function test_sales_store(): void
{
    $user = User::factory()->create();

    $formData = [
        'title' => 'テストタイトル',
        'sales_abstract' => 'テスト概要',
        'category' => 'テストカテゴリー',
        'budget' => 1000,
        'schedule' => '2023-01-01',
    ];

    $response = $this->actingAs($user)->post('/my/sales/store', $formData);

    $response->assertStatus(302);
    $this->assertDatabaseHas('sales_orders', ['title' => 'テストタイトル']);
}

```

まずはフォームデータを用意し、postメソッドに引数として渡します。

そして最後に「$this->assertDatabaseHas('sales_orders', ['title' => 'テストタイトル']);」と書いてあげることで、

正しくフォームデータがデータベースに保存されているか、テストすることができます。


## まとめ
よく考えてみたら、自分も日常生活の中でパスワードを設定する時にバリデーションエラーを起こす時があります。

そしてその時には、必ずパスワードを設定する画面に戻されていました。

今回の経験は「内部的にはこうなってるんや」と考える良い時間になりました。
ListのnullチェックにはCollectionUtils.isEmpty()を使おう！

<details><summary>はじめに（読み飛ばし推奨なので折り畳み）</summary>
こんにちは。なっしーです！<br><br>
しばらくQiitaを放置しつつ、業務や資格試験に挑戦などをしていたらあっという間に開発経験1年半強？くらいになってました。<br>
大学やPa〇zaで書いていた独りよがりなコードとは違い、きちんとした制約や原則に基づいた美しいコードにずっと触れる毎日でとても楽しいです。<br><br>
今回は業務で得た豆知識を紹介したいと思います!<br>
（おそらく多くの人が知っているものかもしれませんが、私と同じ若手向けの記事なのでﾕﾙｼﾃ…ﾕﾙｼﾃ…）
</details>

# 想定読者層
この記事は私と同じ若手向けのものです。
Javaがほんの少しだけわかり、Javaでの業務ロジックや個人開発などでコードを書き始めた人を想定しています。

# 忙しい人向け結論
- ListのnullチェックにはCollectionUtils.isEmpty()を使おう！
- CollectionUtils.isEmpty()はListだけでなく、Collectionであれば全部使えるよ！
- CollectionUtilsはSpring版とApache版があるよ！

# なぜCollectionUtils.isEmpty()を使うのか
主に可読性の観点から使用をオススメします。
このメソッドはCollectionであればList以外でも使用できます。

皆さんは以下のようなnullチェックを書いたことはありますか？
```java
List foge = new ArrayList<>();

if (foge == null || foge.size() == 0){
    // 何らかの処理
}
```

よくあるnullチェックですね。
この書き方でも問題なく動きます。

上記をisEmpty()を使って書き換えるとこうなります。
```java
// Apache版
import org.apache.commons.collections4.CollectionUtils;
// Spring版
// import org.springframework.util.CollectionUtils; 

// 中略

List foge = new ArrayList<>();

if (Collections.isEmpty(foge)){
    // 何らかの処理
}
```
「Collections.isEmpty」という名前によって、Collectionのnullチェックをしていることが一目でわかりますね。
また、`foge == null`と`foge.size() == 0`という2つの式を書かなくて良くなるので、どちらか一方の式を書き忘れてしまうというリスクもなくなります。

# Apache版？Spring版？
CollectionUtils.isEmpty()はApache版とSpring版が存在します。
双方の機能に差はありません。

自分が作っているプロジェクトの依存関係に合わせて選ぶと良いと思います。
チームのプロジェクトで使用したことがないライブラリであれば、使用許可は忘れずに…

🔻公式ドキュメントたち

https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/CollectionUtils.html

https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/util/CollectionUtils.html

# 終わりに
今回はCollectionUtils.isEmpty()について解説してみました！

これからも豆知識があれば共有していきたいと思います！

読んでいただき、ありがとうございました！
createjsで点線のアニメーション

点線が動いて見えるよう（photoshopとかで選択範囲指定した時みたいな感じの）にしたいな。

shape = new createjs.Shape();
let ofs = 0;
const draw = ()=>{
    shape.graphics.setStrokeDash([4,4],ofs);
    shape.graphics.beginStroke("#00ff00");
    shape.graphics.setStrokeStyle(2,0,0,10,true);
    shape.graphics.drawRoundRect(0,0,100,100,10);
    shape.graphics.endStroke();
    ofs++;
    ofs = ofs % 8;
}
draw();
setInterval(draw,250);