OmniAICreator/Qiita-1.07M huggingface dataset:
crontabコマンドでシェルスクリプトが実行されない時の対処法

こんにちは、zawato（[zawato7](https://x.com/zawato7)）です。

今日も今日とて、エラーを解決していきますか。

# 問題事象：crontabコマンドでシェルスクリプトが実行されない

### 環境

- Mac OS Sonoma 14.7

### 問題事象

定期実行させたいシェルスクリプトを用意して、crontabを更新したにも関わらず、設定したタイミングに実行されていませんでした。

例として、以下のような簡単なシェルスクリプトを用意しました。

```~/Desktop/test_crontab.sh
echo $(date) >> ~/Desktop/crontab.log
```

これは、実行した日時をログファイルに追記するスクリプトです。初回実行時にデスクトップ直下にcrontab.logファイルが作成されます。

上記のシェルスクリプトを定期実行するために、crontabコマンドを編集しました。具体的な編集方法は以下の通りです。

ターミナル上で「crontab -e」と入力し、実行する。

Vimが開くので、「i」キーを入力し、挿入モードに切り替える。

「00 5,17 * * * zsh ~/Desktop/test_crontab.sh」と追記する。

「esc」キーを入力し、「:w」と入力し、内容を保存する。

「:q」と入力し、Vimを閉じる。

3.のコマンドは、毎日5時と17時にtest_crontab.shを実行するというものです。

具体的なcrontabコマンドの記載方法については、以下の記事を参考にしてみてください。

https://drdokutoku.com/programming/205/

これで、定期実行されるはずなのですが、なぜか設定した日時になってもログファイルに追記されていませんでいた。

# 対処法

対処方法は、以下の２ステップでした。

1. chmodコマンドによる権限確認
1. 「フルディスクアクセス」を許可する

それぞれについて、詳しく紹介します。

### 1. chmodコマンドによる権限確認
新しくシェルスクリプトを作成した際に、実行権限がどうなっているか確認しておく必要があります。

具体的には、ls コマンドで確認します。

```
ls -la
```
すると以下のような出力がされると思います。

![0d35ab530cf0d5830c02d277a8100c7a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982986/156f4e81-c8d3-7be4-07a4-545b475a6000.png)

どうやら、ファイルの所有者に対して、r（読み取り）と w（書き込み）が許可されているのですが、x（実行）が許可されていませんでした。

そのため、chmod コマンドで、権限を付与してあげる必要がありました。

```
chmod +x test_crontab.sh
```

![154dc9d56249dae782a84a45c6ebadd7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982986/18308f56-e702-8808-6a13-b75db024d6a6.png)

これで、シェルスクリプトを実行することができるようになりました。

### 2. 「フルディスクアクセス」を許可する
Mac OSで cron コマンドを実行させるためには、どうやら「フルディスクアクセス」を許可する必要があるようです。

「フルディスクアクセス」を許可する手順は以下の通りです。

1. 「システム環境設定」を開く
1. 「プライバシーとセキュリティ」を開く
1. 「フルディスクアクセス」を開く
1. 「+」を押す。（※この時、パスワードを求められることがあります。）
1. Finderが開くので、「command+shift+G」と入力すると検索窓が開きます
1. 「/usr/sbin/cron」と入力し、移動する。（※/usr/bin/cronではないので注意！）
1. 開くをクリックし、cronを追加する

以下のように、フルディスクアクセスにcronが追加されていればOK！
![47b2c5ee4aae33028a164c0d4ae2ccbe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982986/f0233e9c-40aa-0cc8-729e-71d7bf1c813d.png)

お疲れ様でした。対処法は以上になります。

これで、crontabコマンドが定期的に動いて、シェルスクリプトが実行されるはずです。

# おわりに

参考になれば嬉しいです！！！

また、似たようなエラーや他の対処法などがあればコメントください！！！

ここまで読んでいただけた方はいいねとストックよろしくお願いします。
@zawato をフォローいただけると励みになります。

データサイエンス・プログラミング・IT資格に関するブログも書いているので、チェックしてみてください！↓

https://drdokutoku.com/
解凍速度を比較する DecompressionStream(gzip)  vs Zstandard(WASM) vs Zstandard(fzstd)

以下の記事でZstandardのWASMをビルドしました。せっかくなので解凍速度を比較してみます。

https://qiita.com/wagadao-y/items/17a67a8f5842bba284fd

## 比較対象
- DecompressionStream　gzipまたはdeflate形式のデータストリームを解凍するためのブラウザAPI
- [zstddec-wasm](https://github.com/wagadao-y/zstddec-wasm)・・・Zstandard v1.5.6をWASMでビルドしたもの
- [fzstd](https://github.com/101arrowz/fzstd) v0.1.1・・・ZstandardのピュアJavaScript実装

## デモページ
[GitHubのリポジトリ](https://github.com/wagadao-y/decompress-compare)と[デモページ](https://wagadao-y.github.io/decompress-compare/)  
こんな感じで解凍処理を100回行い、解凍処理時間の平均値を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3770153/b7869949-1831-40f4-509e-e96188a5e490.png)

## 比較結果

対象データ：[PumpNoInvalidPoints.e57 (V1) - XYZ,INT,RGB,STR,MUL - 22.1MB](http://www.libe57.org/data.html)  
適当な点群データをgzip/zstdの圧縮レベルデフォルトで圧縮したものを利用しました。

```
22146048 Jan 12 16:44 pumpNoInvalidPoints.e57      # 元データ
16755425 Jan 12 16:44 pumpNoInvalidPoints.e57.gz   # gzip圧縮後(圧縮レベル6)
16051170 Jan 12 16:44 pumpNoInvalidPoints.e57.zst  # zstd圧縮後(圧縮レベル3)
```

| ファイル形式               | 平均解凍時間 |
|:-:                        |:-:          |
| DecompressionStream(gzip) | 65.9 ms     |
| Zstandard(WASM)           | 37.4 ms     |
| Zstandard(fzstd)          | 169.6 ms    |

ブラウザのネイティブAPIよりZstandard(WASM)のほうが処理速度速いんですね・・・
【2025年上期ITイベント】興味のあるITイベントをピックアップしてみた

# はじめに
新卒1年目で、希望すれば（業務の都合がつけば）ITイベントへの参加ができる環境なので、「興味ありそうなのにもう終わってる...」とならないために本記事を作成します。
（興味があるITイベント ≒ 興味があるキーワードを取り扱っているITイベント）
随時更新していきたいと思います。

なお、私の興味のあるキーワードは以下の通りです。
- DevOps
- Observability
- AWS
- 生成AI　など... 

### 目次
- [ITインフラSummit 2025](https://qiita.com/drafts/fee0c9447bc72631485e/edit#it%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9summit-2025)
- [おこしやす！DevOps×AIで実現する新ステージへ](https://qiita.com/drafts/fee0c9447bc72631485e/edit#%E3%81%8A%E3%81%93%E3%81%97%E3%82%84%E3%81%99devopsai%E3%81%A7%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B%E6%96%B0%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B8%E3%81%B8)
- [ObservabilityCON on the Road](https://qiita.com/drafts/fee0c9447bc72631485e/edit#observabilitycon-on-the-road)
- [DevOpsDays Tokyo 2025](https://qiita.com/drafts/fee0c9447bc72631485e/edit#devopsdays-tokyo-2025)
- [@IT 開発変革セミナー 2025春](https://qiita.com/drafts/fee0c9447bc72631485e/edit#it-%E9%96%8B%E7%99%BA%E5%A4%89%E9%9D%A9%E3%82%BB%E3%83%9F%E3%83%8A%E3%83%BC-2025%E6%98%A5)
- [AWS Summit 2025](https://qiita.com/drafts/fee0c9447bc72631485e/edit#aws-summit-2025)

# [ITインフラSummit 2025](https://www.nikkeibp.co.jp/ad/atcl/material/24/07/10/02828/250219_ki_NXT_itinfrastructureSummit2025.pdf)
日時：2025/2/19(水)・20(木)
場所：オンライン
主催：日経クロステック
### キーワード
- マイクロサービス・コンテナ・DevOps基盤
- AI・デジタルツイン・データ基盤
- クラウド基盤最適化

# [おこしやす！DevOps×AIで実現する新ステージへ](https://www.intra-mart.jp/seminar/20250221-kansai-event/?event_param=nttdreferralkansai2025nttd_dwp)
日時：2025/2/21(金)
場所：アーバンネット御堂筋ホール
主催：株式会社NTTデータ イントラマート
### キーワード
- DevOps
- AI
- ERPフロント事例

# [ObservabilityCON on the Road](https://grafana.com/ja/events/observabilitycon-on-the-road/2025/tokyo/)
日時：2025/2/25(火)
場所：東京ポートシティ竹芝 オフィスタワー1階 ポートホール
主催：Grafana Labs
### キーワード
- Observability
- Grafana

# [DevOpsDays Tokyo 2025](https://confengine.com/conferences/devopsdays-tokyo-2025)
日時：2025/4/15(火)・16(水)
場所：大崎ブライトコアホール・オンライン
主催：confengine（？）
### キーワード
- DevOps

# [@IT 開発変革セミナー 2025春](https://promotion.itmedia.co.jp/plan/2412_16)
日時：2025/6/4(水)～6(金)
場所：オンライン？
主催：@IT
### キーワード
- DevOps
- DevSecOps
- クラウドネイティブ
- ローコード

# [AWS Summit 2025]()
日時：未定
場所：幕張メッセ
主催：AWS Japan
### キーワード
- AWS

# おわりに
正直まだこの手のイベントの調べ方があまりよくわかっていないところではあるので、その点も含めて自分にとって有意義な情報を適切に集めれるようになりたいと思います。

# 参考サイト
- [【2025年上半期】ITフリーランスにおすすめのTECHイベント情報](https://geechs-job.com/tips/details/200)
- [【2025年1月〜6月開催】IT・DX関連の展示会まとめ](https://www.techfirm.co.jp/blog/events-2025firsthalf)
PowerShellでPythonコマンドが実行できない時の対処法

こんにちは、zawato（[zawato7](https://x.com/zawato7)）です。

今日も今日とて、エラーを解決していきますか。
# 問題事象：PowerShellでPythonコマンドが実行できない
### 環境
- Windows 11
### 問題事象
Pythonはインストール済み。

PowerShellで「python –version」と入力すると、「Python」と表示され、インストールしてあるPythonのバージョンが表示されない。

![ed2af3a862604c479378ec5732787be9-2-1024x526.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982986/8d2f1417-cb51-7332-1806-23108ebb84ab.png)

おそらくpythonコマンドが機能していないと思われる。
# 対処法：Pythonを再インストール
まずは、既にインストールされているPythonをアンインストールします。

スタートボタンから「設定」→「アプリ」を開きます。

インストールされているアプリの検索窓に「python」と入力すると、インストール済みのPythonの一覧が表示されます。

![79512d91a367703566d4592728d4e8c0-1024x330.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982986/5df58c3b-6a42-4bfb-3ad2-f16634727915.png)

「・・・」からアンインストールをクリックし、Pythonをアンインストールします。

再度、PowerShellで「python」コマンドを実行すると、Microsoft Storeが開き、Pythonが表示されるので、インストールします。

Pythonのインストールが完了したら、PowerShellで「python –version」コマンドを実行します。

新しくインストールしたPythonのバージョンが表示され、pythonコマンドが実行できるようになりました！
# おわりに
参考になれば嬉しいです！！！

また、似たようなエラーや他の対処法などがあればコメントください！！！

ここまで読んでいただけた方はいいねとストックよろしくお願いします。
@zawato をフォローいただけると励みになります。

データサイエンス・プログラミング・IT資格に関するブログも書いているので、チェックしてみてください！↓

https://drdokutoku.com/
辞書リストから指定項目と一致するデータを取得する方法【Python】

## 説明
-  取得条件のキーと値に一致するデータを取得
```python
# １件取得
def find_match_data(key_info, data_list):
    for data in data_list:
        if all(data.get(k) == v for k, v in key_info.items()):
            return data
    return None

# 取得条件
key_info = {
    'id': 1,
    'code': 'A'
}

# データリスト
data_list = [
    {'id': 1, 'code': 'A', 'name': 'apple'},
    {'id': 1, 'code': 'B', 'name': 'banana'},
    {'id': 2, 'code': 'A', 'name': 'cherry'},
    {'id': 2, 'code': 'B', 'name': 'doughnut'}
]

match_data = find_match_data(key_info, data_list)

print(match_data)
# {'id': 1, 'code': 'A', 'name': 'apple'}
```


```python
# 複数件取得
def select_match_data(key_info, data_list):
    match_list = []
    for data in data_list:
        if all(data.get(k) == v for k, v in key_info.items()):
            match_list.append(data)
    return match_list

# 取得条件
key_info = {
    'id': 1
}

# データリスト
data_list = [
    {'id': 1, 'code': 'A', 'name': 'apple'},
    {'id': 1, 'code': 'B', 'name': 'banana'},
    {'id': 2, 'code': 'A', 'name': 'cherry'},
    {'id': 2, 'code': 'B', 'name': 'doughnut'}
]

match_data = select_match_data(key_info, data_list)

print(match_data)  

# [{'id': 1, 'code': 'A', 'name': 'apple'}, {'id': 1, 'code': 'B', 'name': 'banana'}]
```
ゲームボーイ RGBDS 開発メモ 第12回 スクロールしてみる

### タイトル画面をつくってみる

まずはタイトル画面をつくってみようと思います。

![logo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733735/7ea72c70-0d92-f7c4-82fa-d55d26e6c430.png)

この画像をタイルデータに変換して、表示させようと思います。rgbgfx で変換できるらしいのですが、4色のpngでないとだめらしく、ImageMagickで変換しました。

```
% magick logo.jpg -resize 64x64 -dither None -colors 4 -define png:color-type=3 logo.png
% rgbgfx -o logo.bin -t tilemap.bin logo.png 
```

 タイルは8x8ドットなので、64個分のタイルデータ logo.bin が出来上がります。これを

```
SECTION "LOGO Tile", ROM0

LogoTiles: INCBIN "logo.bin"
LogoTilesEnd:
```

とすればタイルデータの完成です。チュートリアルと同じようにVRAMにコピーすれば、表示できました。まだパレットが考慮されておらす、また、ゲームボーイカラーにも対応していませんので、2階調のモノクロですが、あとで対応します。

### スクロール

スクロールは簡単で、rSCY というレジスタにオフセットの値をいれればY座標がずれるようですので、最初に 64（タイル8枚分) を入れておき、VBlank中にデクリメントすることによって、スクロールができました。

```
    ; VBlank中

    ld a, [rSCY]
    cp 0
    jp z, Main           
    dec a
    ld [rSCY], a
    jr Main
```

jr は相対ジャンプで jp よりも命令サイズが小さいそうです。cp 0 は or aのほうがいいのかな。

<iframe width="560" height="315" src="https://www.youtube.com/embed/aMKPHr6xCiw?si=b4i3gcZPjWMY3SDL" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
よく使うdpkgコマンドオプション

# dpkg -l
インストールされたパッケージの一覧を表示。大体grepと組み合わせてパッケージの有無を確認する。

```
$ dpkg -l | grep gcc
ii  gcc                    4:11.2.0-1ubuntu1        arm64    GNU C compiler
ii  gcc-11                 11.4.0-1ubuntu1~22.04    arm64    GNU C compiler
ii  gcc-11-base:arm64      11.4.0-1ubuntu1~22.04    arm64    GCC, the GNU Compiler Collection (base package)
ii  gcc-12-base:arm64      12.3.0-1ubuntu1~22.04    arm64    GCC, the GNU Compiler Collection (base package)
ii  libgcc-11-dev:arm64    11.4.0-1ubuntu1~22.04    arm64    GCC support library (development files)
ii  libgcc-s1:arm64        12.3.0-1ubuntu1~22.04    arm64    GCC support library
```

# dpkg -L {パッケージ名}
そのパッケージでインストールされたファイルを表示。

```
$ dpkg -L linux-image-5.15.0-130-generic
/.
/boot
/boot/vmlinuz-5.15.0-130-generic
/usr
/usr/share
/usr/share/doc
/usr/share/doc/linux-image-5.15.0-130-generic
/usr/share/doc/linux-image-5.15.0-130-generic/changelog.Debian.gz
/usr/share/doc/linux-image-5.15.0-130-generic/copyright
```

# dpkg -S {ファイルパス}
そのファイルをインストールしたパッケージを表示。

```
$ dpkg -S /boot/vmlinuz-5.15.0-130-generic
linux-image-5.15.0-130-generic: /boot/vmlinuz-5.15.0-130-generic
```

# dpkg-deb -R {debファイル} {ディレクトリパス}
debファイルをディレクトリに展開。`ar x`でも似たようなことが出来るけどディレクトリにまとめて展開してくれるから楽。
ARPスプーフィングについて

# ARPスプーフィング

[徳丸本](https://wasbook.org/)を読んでいて、なりすましの攻撃の一つにARPスプーフィングというものがあることを知った。
しかし、内容を読んでも理解しきれなかったので、調べてまとめた。

徳丸本での説明。

> ARPスプーフィングとは、ARPの偽応答を返すことで、IPアドレスを偽装する手法のことです。ARPスプーフィングによる成りすまし攻撃は、対象サーバーがゲートウェイのIPアドレスに対するMACアドレスを要求（ARP要求）する際に、偽のARP応答を返し、ゲートウェイに成りすますことで、すべてのパケットを経由させます。
>
> （安全なWebアプリケーションの作り方 第2版 p.620）

用語について整理。

- ARP：IPアドレスからネットワーク上のMACアドレスを求めるためのプロトコルのこと
- ゲートウェイ：異なるネットワークをつなぐコンピューターのこと

つまり、あるネットワークのゲートウェイに成りすますことで、そのネットワークないの全てのパケットが偽サーバーを経由することになるってこと？

大きいネットワークになればなるほど、被害がやばくなりそう...

# ARPスプーフィングの攻撃手法

## ARPの仕組み

ARPでは、ARP要求パケットとARP応答パケットの2つを用いて、MACアドレスの解決を行う。
ARP要求パケットには、MACアドレスを知りたいホストのIPアドレスが含まれている。ARP要求パケットはMACアドレスを要求するホストからブロードキャストされる。
同一リンク内のホストやルーターはARP要求パケットを受け取り、記述されているIPアドレスが自身のIPアドレスと一致した場合に、ARP応答パケットを返却する。

## 成りすましの仕方

まず攻撃者の端末が対象サーバーと同一セグメント内にあることが前提。

対象サーバーがゲートウェイのIPアドレスに対する、ARP要求パケットを送信する。
それを攻撃者の端末が受け取り、自分のMACアドレスをARP応答パケットに含め、対象サーバーに返却する。
これで、対象サーバーのARPテーブルでは、攻撃者の端末がゲートウェイであるかのように見える。

その後、対象サーバーから受けとった情報をゲートウェイへ転送しつづける。
これにより、傍聴していることがバレにくくなる。

# ARPスプーフィングへの対策

## 同一セグメントに脆弱なサーバーを置かない

ARPスプーフィングは同一セグメントにあることが前提となっているため、セグメント内に脆弱なサーバーを置かないことが対策の一つとなる。
レンタルサーバーなどで、他社のサーバーが同一セグメント内に存在する場合は、ホスティング事業者にARPスプーフィング対策の状況を確認するべきである。

## 静的ARPエントリの設定

ネットワークが小規模な場合は、ARPテーブルを手動で管理することによって、自動的にARPテーブルが書き換えられることを防ぐことができる。

## 通信の暗号化

ARPスプーフィングがされた場合でも、HTTPSなどで通信を暗号化することにより、攻撃者から情報の中身を確認されることがなくなる。

# まとめ

そもそも同一セグメント内に攻撃者の端末がつながってるって状況があり得るのかが疑問。
それでいうと、Free Wifiとかは怖い！ARPスプーフィングできちゃいそう...

# 参照文献

https://wasbook.org/

https://business.ntt-east.co.jp/bizdrive/word/arp.html

https://www.scskserviceware.co.jp/topics/primedesk/665.html
JuliaのプライベートなパッケージをGitHubで管理運用する

# 前提
- JuliaのProject環境で開発しているパッケージがある
- そのパッケージのコード管理をGitHubのprivate repositoryで行っている

# 方法
## 環境変数の設定
1. JuliaのPkg環境でgitのcliを使用するための設定
    ```zsh: shell
    export JULIA_PKG_USE_CLI_GIT=true
    ```
1. GitHubのsshキーをJuliaの環境変数に登録
    ```zsh: shell
    export SSH_PUB_KEY_PATH=~/.ssh/key.pub
    export SSH_KEY_PATH=~/.ssh/key
    ```
この設定はシェルを立ち上る度に行わなくてはいけないため，以下のようにJuliaのstartupで設定するといいと思います．
1. `~/.julia/config/startup.jl`が無ければ作成する
    ```zsh: shell
    mkdir ~/.julia/config
    touch ~/.julia/config/startup.jl
    ```
1. `startup.jl`内で環境変数を設定
    ```julia: startup.jl
    function set_env()
        ENV["JULIA_PKG_USE_CLI_GIT"] = true
        ENV["SSH_PUB_KEY_PATH"] = "~/.ssh/key.pub"
        ENV["SSH_KEY_PATH"] = "~/.ssh/key"
    end

    set_env()
    ```
    別に関数にしなくても良いですが，他の処理もある場合は関数にまとめとくと可読性が上がりメンテもしやすいと思います．

こうすることで，シェルでJuliaを起動する際に`startup.jl`が実行され，環境変数が設定されるようになります．

## 自作パッケージを読み込む
環境変数が設定できればあとは動かすだけです．  
試しにサンプルのProject環境を用意して自作パッケージを追加してみましょう．
1. Juliaを起動しProject環境を用意
    ```zsh: julia REPL
    julia> ]
    pkg> generate sample_prj
    pkg> activate sample_prj
    ```
1. Project環境に自作パッケージを追加
    ```zsh: julia REPL
    pkg> add git@github.com:<Username>/<repository_name>.git
    ```
これでProject環境にGitHubから自作パッケージを追加できます．

# うまくいかない場合
- 環境変数が設定できていない
    - JuliaのREPLにて`ENV`で環境変数の一覧を出力して確認
- GitHubとのssh接続がうまくいっていない
    - Juliaの環境変数に指定したパスが正しいか確認
    - 指定したキーがGitHubのものか確認
    - そもそもgit cloneできるか確認
- GitHubのrepositoryの中身がJuliaのProject環境と対応する形でない
    - repositoryの1層目に`Project.toml`があるか確認
    - `src/<Module_name>.jl`で`Module`が定義されているか確認

# まとめ
以下の目的を持つ方には有益だと思います．
- 自作パッケージを公式パッケージのようにしたくはないしpublic repositoryにもしたくなかったが，完全にローカルで管理するのも嫌だし公式パッケージのように扱いたい
- 仲間内のみで自作パッケージを使いやすい形で共有したい
#0012（2024/01/12）LDAP(Lightweight Directory Access Protocol)とは？

# LDAP(Lightweight Directory Access Protocol)とは？
- ディレクトリサービスにアクセスして情報の取得・操作するために通信プロトコル


## LDAPの主な特徴
1. 軽量
    - 既存のプロトコル（X.500）を簡略化した設計で、リソース消費が少なく高速
1. 階層構造データ
    - データはツリー構造（階層型）で管理され、親子関係に基づいて情報が整理されます
    - 例: 会社組織、部門、ユーザー、グループ
1. 柔軟な用途
    - ユーザー認証、リソース管理、アクセス制御など、幅広い用途に使用可能
1. 標準プロトコル
    - TCP/IP上で動作し、標準ポート（通常389または636）を使用

## LDAPの役割

1. ユーザー管理
    - ユーザー名、パスワード、メールアドレスなどの情報を一元管理
1. 認証とアクセス制御
    - シングルサインオン（SSO）や、アプリケーションへのアクセス権管理を実現
1. リソース管理
    - ネットワーク内のプリンター、サーバー、共有フォルダなどの情報を整理
1. 階層的な情報検索
    - ディレクトリデータベースから効率的に情報を取得

## LDAPを利用したシステム
1. Microsoft Active Directory (AD):
    - Windows環境でのディレクトリサービス
    - LDAPプロトコルを基盤とし、ユーザー管理や認証を実現
1. OpenLDAP:
    - オープンソースのLDAP実装
    - Linux環境でよく使用される
1. AWS Directory Service:
    - AWSが提供するディレクトリサービス（Managed Microsoft ADなど）


## LDAPの通信の流れ

1. 接続:
    - クライアントがLDAPサーバーに接続（ポート389または636）
1. バインド（認証）:
    - クライアントが認証情報（例: ユーザー名とパスワード）を送信して認証を行う
1. クエリ（検索）:
    - クライアントが検索条件を指定し、サーバーから情報を取得
    - 例: 「Sales部門のすべてのユーザー情報を取得」
1. 結果の返却:
    - サーバーが検索結果をクライアントに返す
1. 切断:
    - クライアントが接続を終了

## 参考
- chatgptの回答を元に作成
業務効率化×プログラミング 

1. テーマ：「データ型」について
・データ入力の自動化と計算の表示例について
  データ型の種類：数値型、文字列、真偽型、日付型

2. データ取得から計算

・function makeExpenseReport() {
  // シートを取得
  let sheet = SpreadsheetApp.getActiveSheet();

  // 費用データを取得
  let trainFee = sheet.getRange("B4").getValue();    // 交通費
  let foodFee = sheet.getRange("B5").getValue();     // 食費
  let hotelFee = sheet.getRange("B6").getValue();    // 宿泊費

  //合計の計算
  let totalFee = trainFee+foodFee+hotelFee;

  //税金の計算
  let tax = totalFee * 0.1;
  let totalWithTax = totalFee + tax;

  //計算結果を書き込む
  sheet.getRange ("B7").setValue(totalFee);    // 合計（税抜）
  sheet.getRange("B8").setValue(totalWithTax);   // 税込合計

  // 申請者の情報を取得
  let name = sheet.getRange("B1").getValue() // 名前
  let team = sheet.getRange("B2").getValue() // 部署

    // 申請文を作る
  let report =
  "経費申請書" +"\n"+
  "申請者"+ name + "("+ team + ")"+"\n"+
  "合計金額"+totalWithTax+"円（税込)";

  // 申請文を書き込む
  sheet.getRange("A15").setValue(report);
}

3. 気づき
・交通費はここではtrainFeeとなっていますが、transportationFeeとしてもちょっと長いができそう。
・「let」は「sheet.getRange・・・」の先頭には使わないこと
ABC388の振り返り

レート停滞期に入りそうな予感がしますね…
## [A問題](https://atcoder.jp/contests/abc388/tasks/abc388_a)(diff:8) ##
前回に続き簡単
またpythonで書きました。
ACコード(pypy59ms,c++1ms)
```python
print(input()[0]+"UPC")
```
AC時間:1:13
## [B問題](https://atcoder.jp/contests/abc388/tasks/abc388_b)(diff:30) ##
$heavy$ という長さ $D$ の配列を作ります。
各 $i(1 \le i \le N)$ について、$heavy_j(1 \le j \le D) = max(heavy_j,T_i(L_i+j))$ としていけば、答えが出ます。計算量は $O(ND)$ です。
ACコード(1ms)
```c++
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;

int main() {
  int N, D;
  cin >> N >> D;
  vector<int> heavy(D);
  for(int i = 0; i < N; i++) {
    int T, L;
    cin >> T >> L;
    for(int j = 0; j < D; j++) {
      heavy.at(j) = max(heavy.at(j), T * (L + j + 1));
    }
  }
  for(int o : heavy) {
    cout << o << endl;
  }
}
```
AC時間:5:00
## [C問題](https://atcoder.jp/contests/abc388/tasks/abc388_c)(diff:211) ##
[寿司屋](https://atcoder.jp/contests/abc382/tasks/abc382_c)ぶりの二分探索!
$A$ は既にソートされているという制約($A_i < A_{i+1}(1 \le i < N)$)から、$A$ をそのまま使えることが分かります。
もし $2 \times A_i(1 \le i \le N) > A_N$ なら、それ以上探索しても鏡餅を作ることはできません。なので、<code>for</code>文を回している間、$2 \times A_i > A_N$ となったら<code>break</code>すれば良いです。(もしくは<code>for</code>文の条件などを変えてもできます)
そうでなければ、$2 \times A_i \in (A_{r - 1},A_r]$ を満たす $r(1 < r \le N)$ を二分探索によって求め、$N - r + 1$ を答えに加算すればよいです。
ACコード(136ms)
```c++
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;

int main() {
  int N;
  cin >> N;
  vector<int> A(N);
  for(int &o : A) {
    cin >> o;
  }
  ll ans = 0;
  for(int i = 0; A.at(i) * 2 <= A.at(N - 1); i++) {
    int l = i;
    int r = N;
    int c = 0;
    while(r - l > 1) {
      c = (l + r) / 2;
      if(A.at(c) >= A.at(i) * 2) {
        r = c;
      }
      else {
        l = c;
      }
    }
    ans += N - r;
  }
  cout << ans << endl;
}
```
AC時間:11:01
## [D問題](https://atcoder.jp/contests/abc388/tasks/abc388_d)(diff:659) ##
終盤に公式解説の発想は思いつきましたが、実装できませんでした。
視点を変えることを積極的にやっていきたいです。
## 感想 ##
パフォーマンスは602でレートが515になりました。
レート停滞はしないよう気をつけたいです
DockerDesktopが起動できない

## 内容
DockerDesktopがマルウェア判定されて起動できない
既にGitに回避策があがっているので、以下自分用備忘録

https://github.com/docker/for-mac/issues/7527

## 対応
### Dockerデスクトップのインストールを診断する
[check.sh.txt](https://github.com/user-attachments/files/18378854/check.sh.txt)をダウンロードしてcheck.shに改名
```ruby:実行権限付与
chmod +x check.sh
```

```ruby:証明書の検証
./check.sh /Applications/Docker.app/Contents/Library/LaunchServices/com.docker.vmnetd
```
証明書の検証に失敗したので、DockerDesktopを再インストール
再インストール後、無事Docker起動
kotlinでリストのアップデートを共通化

# 初めに
今回はKotlinでリストのアップデート処理を紹介してきます
### 本文
さっそくですが、下記がコードになります
リストの中身はジェネリックにしてどんな型でも受け取れるようにします。
判定基準とアップデート内容を引数にとることで共通化することができます
```kotlin
fun <T> MutableList<T>.updateIf(predicate: (T) -> Boolean, transform: (T) -> T) {
    for (i in indices) {
        if (predicate(this[i])) {
            this[i] = transform(this[i])
        }
    }
}
```
### さいごに
いろいろなところで書くのが煩わしいので共通化してみました
どなたかのお役に立てれば幸いです
Reactの環境構築でcreate-react-appがうまくいかなかったのでViteを使って環境構築

# やりたかったこと
「React使ってみよ～」と思って、調べてみたら`npx create-react-app react_app`を実行したらめっちゃエラー出てうまくいかんかった
友達に聞いてみたところ`create-react-app`はもうメンテされてないらしく、使わないほうがいいとのこと

メンテされてないってことなのに「React 環境構築」って調べても全然その話出てこないなーと思ったので、備忘録的に残しておく


# お世話になったサイト
https://monotein.com/blog/react-vite-how-to-use

# node.jsをインストール

インストーラからインストール

コマンドはよく知らんです

https://nodejs.org/en/download

ちゃんとインストールできてたらコマンドが効くはず

```python
$ node -v
v22.13.0

# npmも一緒にインストールされてるはず
$ npm -v
10.9.2
```

# プロジェクトを作成

```python
npm create vite@latest
```

1. 実行するとプロジェクト名を聞かれるので入力
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/cd02e800-5afb-b339-cace-6207c4ed11b8.png)

    
2. Reactを使いたいので選択
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/90d1fe9d-46b0-4c24-9ecb-0751339d5271.png)

    
3. 使う言語を選択
    
    SWCを使ったほうが早い（らしい）

    ↓参考
    https://qiita.com/KokiSakano/items/563e99734850bb5b5723
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/8df995dd-fc3e-16cc-14cd-26445f04bc3b.png)


    
4. 表示されたコマンド実行する
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/313928ce-21df-2008-456d-78a66420d845.png)

    
    
    ```powershell
    cd vite-project
    npm install
    npm run dev
    ```
    
5. 実行完了
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/dbeafe6f-c0b1-e193-22e0-fcb473fce94d.png)

    

実行したいときはプロジェクトのディレクトリで `npm run dev` を実行する
データの保存方法について

# 現状
下記2つをGCSのバケットで管理している。
- データロック済みのデータcsv
- 上記から解析対象をマート化したデータcsv

# 課題
- マート化したデータ処理の紐づけ(現状はjupyter notebook)
- データ内容の理解が属人化している

# AIの回答で試そうと思っている案
## データカタログ:
GCSに保存されたデータの内容を管理するために、データカタログ（例: Google Cloud Data Catalog）の利用を検討してください。

各CSVファイルについて、試験名、データ取得日、カラムの説明、分析における注意点などを記述しておくことで、チームでの共有や再利用が容易になります。

## メタデータ管理:
ファイル名だけでなく、GCSのメタデータを利用して、データに関する情報を付与することも有効です。例えば、content-typeにtext/csvを指定したり、カスタムメタデータとして、データの説明やデータ作成者などを記述できます。

## アクセス制御:
権限管理は最小限の権限原則に従い、必要な人にのみアクセス権を付与します。
GCSのIAMを使用し、分析者には読み取り権限のみを付与し、データ管理者には書き込み権限を付与します。


## ファイル命名規則への紐付け:

前述の通り、ファイル名に試験名、日付、バージョンなどの情報を含めることで、どの分析コードがどのデータに対応しているかを推測しやすくします。

例えば、trial_A_20231027_v1.csvに対応する分析コードをanalyze_trial_A_v1.pyのように命名することで、紐付けが容易になります。

## メタデータによる紐付け:
GCSのメタデータや、データカタログのメタデータに、分析コードのファイル名やGitのコミットハッシュなどを記載することで、より正確な紐付けが可能です。

例えば、analyzed_byというメタデータにanalyze_trial_A_v1.pyを指定したり、analysis_commitというメタデータにGitのコミットハッシュを指定します


## bigqueryで保存してbigqueryからデータをpython dfにダウンロード
```python3
from google.cloud import bigquery
import pandas as pd

# サービスアカウントのJSONキーファイルのパスを指定
client = bigquery.Client.from_service_account_json('path/to/your/service-account.json')

# SQLクエリを実行
query = """
    SELECT
        trial_id,
        age,
        gender,
        diagnosis
    FROM
        `your-project.your_dataset.your_table`
    WHERE
        age >= 18
    LIMIT 1000
"""

query_job = client.query(query)

# クエリ結果をpandas DataFrameに変換
df = query_job.to_dataframe()

# DataFrameの内容を表示
print(df)

# DataFrameの情報を表示
df.info()

# DataFrameの最初の5行を表示
print(df.head())
```

# 結果
Coming soon
Draw.ioなるものを使ってみた！

## 概要
最近構成図を書く機会があったのですが、エクセルで行うのがしんどかったので
別の方法がないかと思い探したところ、Draw.ioというものを見つけたので試してみます！

## 良さげなポイント
- ブラウザで起動できる
- 日本語対応

## 手順
diagrams.netにアクセスする
下記サイトが表示されるので、Startをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882356/fe7273a3-22ba-75bf-d6a3-dac5cdaec7a4.png)

とりあえず今回はデバイスを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882356/1ee0b634-e3c0-930c-21cd-e9dceb2ef8c2.png)

ネットワークの図を作りたいので、これを選択してみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882356/7dba76f2-d0d7-cbf0-5cff-784dfdb81523.png)

作成すると、このような画面になりました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882356/40736ba6-fe86-96ec-fe2f-6babeccd8de4.png)

少し弄ってみたのですが、このようになりました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882356/3def905f-1361-4d7c-7b4b-af626276683f.png)

## 最後
なんとなくで、触ってみたのですがエクセルよりかはきれいなものができそうですね！
その他の図形からAWSのアイコンもあったので、そちらでも使えるのかなと思います。

次はこのネットワーク図を使って、自宅環境の整備で行ったことを記事にすると思います。
pixi/reactを使うとpixi-viewportが実質使えない

バージョン互換性の話です。
2025年1月の時点ではpixi/reactとpixi-viewportを使っていると実質現在のdependencyでは使用が出来ません。

↓追記
2025/2にV8.x.xがでました。

https://react.pixijs.io/getting-started/


## 原因

1. pixi-reactはVersion7.x.xまでのサポートです。
1. pix-viewportはV5.x.xだとpixi.js 7.2.xまでのサポート
v6.x.xだとpixi.js v8.x.xからのサポートです

現在pixi.jsのv7だと7.4.2が最新ですが、
pixi-viewportがv7.2までかv8.x以降のサポートとなっており
v7.4が空白地帯となってしまっています。

しかしpixi/reactのサポートがv7までなのでpixi.jsをv8にアップデートすることもできません。（仮にできてもv8へのマイグレーション作業が必要になりますし・・・）

## 対策
package.jsonのpixi.jsのバージョンを7.2.4に固定して
`"pixi.js": "7.2.4",`
--legacy-peer-depsつきでインストール
`npm install --legacy-peer-deps`
すればよいのですが、

その場合私はajvのエラーも出ましたので追加で
`ajv:"^8.0.0"`
も追加しました。

またこれは今回の件に無関係かもしれませんが合わせてtypescriptのエラーも出たので
`"typescript": "^4.9.5",`
も追加しています。

## 余談
メンテの活性度がそこまでではないライブラリを使っている場合は
動作がとれていた環境のpackage-lock.jsonを使用して
`npm ci`
をすることも考慮に入れなければならないかもしれない・・・と思いました
AttributeMethodPatternに使われるメソッドを調べた

### AttributeMethodPatternとは
```rb
        class AttributeMethodPattern # :nodoc:
          attr_reader :prefix, :suffix, :proxy_target, :parameters #これら属性のみ読み込める
          AttributeMethod = Struct.new(:proxy_target, :attr_name) #

          def initialize(prefix: "", suffix: "", parameters: nil) # 三つパラメータを入れることができる
            @prefix = prefix
            @suffix = suffix
            @parameters = parameters.nil? ? "..." : parameters
            @regex = /\A(?:#{Regexp.escape(@prefix)})(.*)(?:#{Regexp.escape(@suffix)})\z/　# 接頭辞、接尾辞をエスケープさせて
            @proxy_target = "#{@prefix}attribute#{@suffix}"
            @method_name = "#{prefix}%s#{suffix}"
          end
```
https://github.com/rails/rails/blob/cf6ff17e9a3c6c1139040b519a341f55f0be16cf/activemodel/lib/active_model/attribute_methods.rb#L471C1-L484C1

### Regexp
https://qiita.com/masatom86650860/items/b66ca899375f7dcdb6fc

### Regexp#escape　特殊な文字を表示させる
https://qiita.com/masatom86650860/items/4a448c2d6b6ee6b13831

### %記法　%sはハッシュを表せる
https://qiita.com/masatom86650860/items/6a7ef07c5b31506e0d89

### 試してみた
```rb
irb(main):110> name = 'Alice'
=> "Alice"
...
irb(main):113> @method_name = "#{name}%s#{name}"
=> "Alice%sAlice"
irb(main):114> puts @method_name
Alice%sAlice
=> nil
irb(main):115> @proxy_target = "#{name}attribute#{name}"
=> "AliceattributeAlice"
```

# 感想
何をしているクラスなのか知りたかった。
これから理解できるかもしれない。
%s、%i、%I

# ％記法でシンボル、バックスラッシュ記法を有効にしたりする
>%記法を使ってシンボルを作成することもできます。シンボルを作成する場合は%sを使います。
```rb
irb(main):107> %s!ruby is fun!
=> :"ruby is fun"
irb(main):108> %s(ruby is fun)
=> :"ruby is fun"
```

>シンボルの配列を作成する場合は、%iを使うことができます。この場合、空白文字が要素の区切りになります。
```rb
irb(main):109> %i(apple orange melon)
=> [:apple, :orange, :melon]
```
>改行文字を含めたり、式展開したりする場合は、%Iを使います
```rb
irb(main):110> name = 'Alice'
=> "Alice"
irb(main):111> %i(hello\ngood-bye #{name.upcase})
=> [:"hello\\ngood-bye", :"\#{name.upcase}"]
irb(main):112> %I(hello\ngood-bye #{name.upcase})
=> [:"hello\ngood-bye", :ALICE]
```
https://gihyo.jp/book/2017/978-4-7741-9397-7
[ODC]ブラウザバックを禁止できるAPI

実際にやりたくなることはあまりないと思うが、ブラウザのバックボタンやショートカットで前のページに戻る操作を禁止できる。
ODCのJavaScript API、Navigationを使う。

# 環境情報
ODC Studio(Version 1.5.2)

動作確認はMac上のChromeで行った。後述するように、複数回のブラウザバック操作に対する禁止は安定しなかった。

# ドキュメント
[Navigation - ODC Documentation](https://success.outsystems.com/documentation/outsystems_developer_cloud/outsystems_language_and_elements/outsystems_apis/javascript_api/navigation/)
2025/01/11時点ではまだ日本語訳がなかった。

# ブラウザバック操作時のハンドラを登録するAPI：registerBackNavigationHandler
1. Client Action内にJavaScript要素を配置
1. JavaScript要素内にハンドラとなる関数を定義
1. JavaScript要素内で、$public.Navigation.registerBackNavigationHandlerを読んで、2の関数をハンドラとして登録する

JavaScript要素というのは、以下の「JavaScript1」のような要素。Client Action内に配置して、要素内に記述したJavaScriptのコードを実行できる。
![スクリーンショット 2025-01-11 19.42.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/69ec45ec-8df8-1f60-e198-ba0659849869.png)

注意点
1. ハンドラは一回実行されると、登録が取り消される。このとき、本来のブラウザバック処理（前のページへ遷移）は行われない
1. ハンドラは複数登録できる（ブラウザバック処理時は、最後に登録されたハンドラから実行され、登録解除される。つまりスタックされる。ドキュメントにはキューであると書いてあるが、LIFOであるからスタックが正しいと思われる）
1. registerBackNavigationHandlerは、登録されたハンドラを表すIDを返す（後述）

以下は、alertで数字を表示するだけのハンドラを3つ登録する処理の例。この処理後、ブラウザバックを3回繰り返すと、2 -> 1 -> 0とポップアップ表示され、画面遷移は発生しない。4回目の実行ではブラウザバックが発生する。
``` .js
for(let i = 0; i < 3; i++)
{
    let handler = () => { alert(`${i}`);}
    $parameters.RegisteredId = $public.Navigation.registerBackNavigationHandler(handler);
}
```

# ハンドラの登録を解除するAPI：unregisterBackNavigationHandler
registerBackNavigationHandler実行時の戻り値（ID）を引数に、$public.Navigation.unregisterBackNavigationHandlerを呼ぶと、そのハンドラの登録を解除できる。

``` .js
// 登録時にIDを保存しておく
$parameters.RegisteredId = $public.Navigation.registerBackNavigationHandler(handler);
// ...

// 登録時のIDを引数に、unregisterBackNavigationHandlerを呼ぶことで登録を解除できる
$public.Navigation.unregisterBackNavigationHandler($parameters.RegisteredId); 
```

# 戻る・進む・画面遷移すべてに対応するハンドラを登録するAPI：registerNavigationHandler
$public.Navigation.registerNavigationHandlerを呼び、イベント発生時に動作させたいハンドラを登録する。

開発者ツールのコンソールタブを使い、argumentsを見て確認したところ、ハンドラの第1引数には遷移先の相対パス、第2引数には何らかの関数が渡ってきた。2025/01/12時点ではドキュメントに記述がないので正体は不明。

![スクリーンショット 2025-01-12 13.05.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/236a8d11-8a70-a27e-b6fe-166038582490.png)


動作確認したところ、ブラウザの戻る・進む・画面上のリンククリック時には、登録したハンドラが動作した。

``` .js
function navigationHandler(param) {
    console.log(param);
}

$public.Navigation.registerNavigationHandler(navigationHandler);
```

# 永続的にブラウザバックを防ぐのはちょっと難しそう
いろいろ試した限り、一度目のブラウザバック操作時には確実にハンドラが動いてくれるが、二度目以降は、ハンドラ登録方法に関わらずうまく行ったりいかなかったりする。バグだろうか。

必要になったときにもう少し詳しく見ることにする。

## うまくいかなかった方法①：ハンドラー内で自分自身をもう一度登録する
ハンドラーが動いたときに、そのハンドラーの登録が解除されてしまう。そこで、ハンドラー内で自分自身を再登録することで、実現できるのではないかと思ったが、うまくいく時といかない時があって使えなさそう。うまくいかない時は、一度ブラウザバックした時はちゃんと止められるのだが、もう一度バックすると普通に画面遷移してしまう。

原因がわからないので、今の所、この方法は取れないかな。

``` .js
function backNavigationHandler() { 
    $public.Navigation.registerBackNavigationHandler(backNavigationHandler);
    alert("stop");
}
$public.Navigation.registerBackNavigationHandler(backNavigationHandler);

```

## うまくいかなかった方法②：常に複数のハンドラが登録された状態を維持する
↑で書いた、一度に3つのハンドラを登録する処理をボタンに紐づけておく。ブラウザバックを３回繰り返す→ボタンクリック→もう一度ブラウザバックという手順で確認してみた。

この場合も、うまくいく時は想定通り、何度でもハンドラを動作させられる。しかし結構な確率で2回目のブラウザバックが普通に画面遷移してしまう。
Regexp#escape

# バックスラッシュ記法を有効にさせずに特殊文字を表示させる
>escape(string) -> String
quote(string) -> String
### 概要
>string の中で`正規表現において特別な意味を持つ文字の直前にエスケープ文字(バックスラッシュ)を挿入した文字列を返します`。

### パラメータ
>[PARAM] string:
正規表現において特別な意味をもつ文字をもつ文字列を指定します。

```rb
irb(main):009> rp = Regexp.escape("$bc^")
irb(main):010> p rp
"\\$bc\\^"
=> "\\$bc\\^"

irb(main):013> rp = Regexp.new("$bc^")
=> /$bc^/
```
https://docs.ruby-lang.org/ja/latest/method/Regexp/s/escape.html

```rb
irb(main):086> p = Regexp.escape("bc^")
=> "bc\\^"
irb(main):087> p = Regexp.escape("$bc^")
=> "\\$bc\\^"
irb(main):088> p = Regexp.escape("bc^")
=> "bc\\^"
irb(main):089> p = Regexp.escape("bc")
=> "bc"
```
### \を追加してエスケープしないようにしている
```rb
irb(main):094> puts "faafa\nfaaf"
faafa
faaf
=> nil
irb(main):095> p "faafa\nfaaf"
"faafa\nfaaf"
=> "faafa\nfaaf"
irb(main):096> a = Regexp.escape("faafa\nfaaf")
=> "faafa\\nfaaf"
irb(main):097> p a
"faafa\\nfaaf"
=> "faafa\\nfaaf"
irb(main):098> puts a
faafa\nfaaf
=> nil
```
### シングルクォートだとバックスラッシュ記法と式展開が有効にならない
>文字列はダブルクォートまたはシングルクォートで囲まれています。`ダブルクォートで囲まれた文字列ではバックスラッシュ記法と式展開(後述)が有効`になります。シングルクォートで囲まれた文字列では、 `\\ (バックスラッシュそのもの)と \' (シングルクォート) を除いて文字列の中身の解釈は行われません`。シングルクォートで囲まれた文字列では`行末の \ は \ そのものとして解釈`されます。

>複数行にわたって書くこともできます。この場合含まれる改行文字は常に\nになります。実際のソースファイルの改行コードとは無関係です。

>空白を間に挟んだ文字列リテラルは、コンパイル時に1つの文字列リテラルと見倣されます。

https://docs.ruby-lang.org/ja/latest/doc/spec=2fliteral.html#:~:text=%E6%96%87%E5%AD%97%E5%88%97%E3%81%AF%E3%83%80%E3%83%96%E3%83%AB,%E5%80%A3%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82

#### `\\ (バックスラッシュそのもの)と \' (シングルクォート) を除いて文字列の中身の解釈は行われません`
```rb
irb(main):101> puts 'faafa\nfaaf'
faafa\nfaaf
=> nil
irb(main):102> puts "faafa\nfaaf"
faafa
faaf
=> nil
```
```rb
irb(main):103> puts '\\'
\
=> nil
irb(main):104> puts '\''
'
=> nil
```
## 感想
エスケープするとは特殊文字を有効にしない
Kotlin Koans やってみた 5

# Introduction
## Nullable types
### 問題
Kotlin の null safety と safe calls について学び、以下の Java コードを1つの if 式のみを使って書き直してください。

```java
public void sendMessageToClient(
    @Nullable Client client,
    @Nullable String message,
    @NotNull Mailer mailer
) {
    if (client == null || message == null) return;

    PersonalInfo personalInfo = client.getPersonalInfo();
    if (personalInfo == null) return;

    String email = personalInfo.getEmail();
    if (email == null) return;

    mailer.sendMessage(email, message);
}
```

### 解答
```kotlin
fun sendMessageToClient(
        client: Client?, message: String?, mailer: Mailer
) {
    client ?: return
    val personalInfo = client.personalInfo ?: return
    val email = personalInfo.email ?: return
    if(message.isNullOrBlank()) return
    mailer.sendMessage(email, message)
}
```
テストはパスするけどなんだか違う気がする・・・

#### refactor
```kotlin
fun sendMessageToClient(
        client: Client?, message: String?, mailer: Mailer
) {
    val email = client?.personalInfo?.email
    if(!email.isNullOrBlank() && !message.isNullOrBlank()) mailer.sendMessage(email, message)
}
```
こうかな・・・？
`isNullOrBlank()`って知らなかった。けどサジェストされて知った☆なんかかっこいい。

#### koans の answer
```kotlin
fun sendMessageToClient(
        client: Client?, message: String?, mailer: Mailer
) {
    val email = client?.personalInfo?.email
    if (email != null && message != null) {
        mailer.sendMessage(email, message)
    }
}
```
素直に比較するほうがいいのかな〜・・・？

# おわりに
null safety は大事よね。
思わぬところでクラッシュしてたら嫌だしね。
型に `?` ついてたら、気をつけないと!!

---

[← 前回の記事](https://qiita.com/b-yuko/items/cc2baa1dedc979a0050e)　|　[次回の記事 →](https://qiita.com/b-yuko/items/6a4c8ba209c71c6e779a)
【Next.js】Providerの使い方をミスって" 'useContext' is not available in this environment."のエラーが出た

# はじめに

Next.js×TypeScriptでコーディングをしていたところ、下記のエラーに遭遇しました。
```
React functionality 'useContext' is not available in this environment.
```
 # 原因
**クライアントで動かすべき機能を、サーバーで動かそうとした**のが主な原因でした。

今回使用している`Provider`はサーバーコンポーネントとしてサポートされていません。
従って、クライアント側で動かしてあげる必要があるということです。

# 解決方法
**`Provider`を別コンポーネントに分けて、クライアントコンポーネントとして実行**しました。

公式ドキュメントにも同様の解決法が提示されています。

https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#using-context-providers

**修正前**
```tsx:layout.tsx
//サーバーサイド
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
       <ApolloProvider client={client}>{children}</ApolloProvider>
      </body>
    </html>
  );
}
```

**修正後**

`ApolloProvider`を扱うクライアントコンポーネントを新規作成しました。
```tsx:ClientProvider.tsx
"use client";
//クライアントサイドで実行

import { ApolloProvider } from "@apollo/client";
import { client } from "../lib /apolo-client";

export default function ClientProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  return <ApolloProvider client={client}>{children}</ApolloProvider>;
}

```

```tsx:layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <ClientProvider>{children}</ClientProvider>
      </body>
    </html>
  );
}
```

# 参考
https://ja.react.dev/reference/react/createContext#provider
FAISSとは？何をするためのライブラリ？

FAISSは、Facebook AIが開発した、大規模なベクトルデータの中から「類似したベクトル」を高速に検索するためのライブラリです。

たとえば、「ネコの養い方」に関連する情報を、100万件のデータの中から検索したいときに便利です。

FAISSの基本的な作業は下記の通りです：
※この記事は、ChatGPTの出力を基に作成しています。

---

### 1. データの準備

#### ステップ 1.1: テキストデータをベクトル化
FAISSを使う前に、検索対象のデータを準備します！

- 各文章をAIモデルでベクトルに変換します。
- 例：
  - 「ネコの飼い方」 → ベクトル `[0.12, -0.34, 0.56, ...]`
  - 「犬の世話」 → ベクトル `[0.45, -0.12, 0.67, ...]`

#### ステップ 1.2: FAISSのインデックスに変換
ベクトルをFAISSが処理できる形式に変換します。このインデックスは「検索を効率化するためのデータ構造」です。

---

### 2. インデックスの構築

FAISSには複数のインデックスタイプがありますが、一番基本的な「Flat Index」を使う例を解説します。

#### ステップ 2.1: ベクトルを登録
下記は、100万件のベクトルを300次元で処理した例です。

```python
import faiss
import numpy as np

# 例: 100万件のベクトルデータ、300次元
vectors = np.random.random((1000000, 300)).astype('float32')

# Flat Indexを作成
index = faiss.IndexFlatL2(300)  # L2距離（ユークリッド距離）を使用
index.add(vectors)  # ベクトルをインデックスに登録
```

- **`IndexFlatL2`**: ベクトル間のユークリッド距離を計算するインデックス。
- **`add`メソッド**: ベクトルデータをインデックスに追加。

---

### 3. 検索処理
ユーザーからのクエリ（例：「ネコの養い方」）に基づいて、関連するデータを検索します。

#### ステップ 3.1: クエリのベクトル化
「ネコの養い方」をベクトルに変換します！

```python
query_vector = np.random.random((1, 300)).astype('float32')  # クエリのベクトル
```

#### ステップ 3.2: FAISSで検索
クエリベクトルと似たベクトルを検索します。

```python
k = 5  # 上位5件を収集

distances, indices = index.search(query_vector, k)
```

- **`search`メソッド**: クエリベクトルに最も近いベクトルを検索。
- **結果**:
  - `distances`: クエリベクトルと検索結果のベクトルとの距離。
  - `indices`: 検索結果のベクトルのインデックス（元のデータと対応）。

---

### 4. 結果の収集
`indices`を使って元のデータから検索結果を収集します。

例：
- インデックス `[123, 456, 789, 1011, 1213]`が返された場合、対応する文章を取り出します！
  - 123 → 「ネコの健康管理」
  - 456 → 「子ネコの育て方」
  - 789 → 「犬とネコの比較」

---

### 5. 高速化のための工夫
FAISSは、検索を高速化するために構造化された複数のインデックスを提供しています。

#### 代表的なインデックス
1. **Flat Index**  
   - すべてのデータを総対象で計算。
   - 小規模データ（数万件）に適している。

2. **IVF (Inverted File Index)**  
   - データをクラスターに分け、検索範囲を絞る。
   - 大規模データに適している。

3. **HNSW (Hierarchical Navigable Small World)**  
   - グラフ構造を使用して高速検索を実現。
   - 高精度かつ大規模データにも適している。

---

### まとめ
FAISSの検索プロセスは下記の通りです：
1. データをベクトル化してインデックスに登録。
2. クエリをベクトル化して検索を実行。
3. 類似したベクトルの結果を収集。

これにより、大量のデータから意味の近い情報を高速に検出できます。
【C#】GitHubActions でテストする際のビルド時間を短縮したかった話

# はじめに

GitHubActions で PR（正確にはブランチをプッシュ）した際に自動テストしたい場合、C# だと ↓ の設定で実現できます。

(2025 年現在)

```yml:.github/workflows/test.yml
name: Test .NET

on:
  push

jobs:
  build:
    runs-on: windows-latest # ubuntu-latest, macos-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-dotnet@v4
      with:
        dotnet-version: 9.0.x
    - run: dotnet build
    - run: dotnet test
```

小さなプロジェクトであれば GitHubActions でテスト関係の一連の動作に 1~2 分程度かかります。これをもう少し短くできないか模索したものの、今回は**うまくいきませんでした**。

試したことを備忘録として残しておこうと思います。

## GitHubActions の動作の一例

↓ の表は一連の動作にかかっている時間です。

|Action|sec|%|
|---|---:|---:|
|Set up job|1|1|
|Run actions/checkout@v4|7|6|
|Run actions/setup-dotnet@v4|9|8|
|Run dotnet build|92|75|
|Run dotnet test|9|8|
|Post Run actions/setup-dotnet@v4|0|0|
|Post Run actions/checkout@v4|1|1|
|Complete job|1|1|
|total|120|100|

- コード量は１万行に満たない小さなプロジェクトです
- ビルドにかかる時間が全体に対して支配的です
- テストにかかっている時間そのものは比較的短いです

一連の動作にかかっている時間のうち、ボトルネックはビルド時間になりそうです。GitHubActions 上のビルドのコンソールを見てみます。

```text
Run dotnet build
  Determining projects to restore...
  Restored ♡♡♡.csproj (in 11.2 sec).
  QArticle -> ♡♡♡.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:01:05.25
```

ビルド処理以外にオーバーヘッドがあるため、ビルド時間よりビルドに実際かかった時間のほうが長いです。両者の時間は 1.4 倍ほど開きがあるので、ビルド処理はそもそもコストが高いようです。

## ビルド時間の短縮：キャッシュを使ってみる

これはうまくいかなかったためボツ案です。

<details>
<summary>ボツ案</summary>

```yml:.github/workflows/test.yml
name: Test .NET

on:
  push:
    branches-ignore:
      - main

jobs:
  build:
    runs-on: windows-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-dotnet@v4
      with:
        dotnet-version: 9.0.x
      - uses: actions/cache@v4
      with:
        path: |
            ./bin
            ./obj
            ~/nuget/packages
        key: dotnet-build
    - run: dotnet build
    - run: dotnet test
```

- ビルド時間はキャッシュの有無で変化しませんでした
- nuget に関しては GitHubActions 側に大体用意されているっぽいです。つまりライブラリのダウンロードに時間がかかっている、とかではなさそうです

</details>

## うまくいかなかった要因を考えてみる

これらは検証していないためテキトーです。

- ビルドまでの時間が長い
  - GitHubActions はそもそも OS 起動コストが毎回かかっている？
  - `dotnet build` 初回起動コストが毎回かかっている？
  - 確か dotnet コンパイラは C# 製なので初回起動コストがネイティブアプリより高いのかも？
  - 今回は OS に Windows を指定しているため、ubuntu と違いがあるのかも（ubuntu では未検証）
- ビルド時間が長い
  - GitHubActions の CPU パワー / スレッド数が制限されている？ ローカルだと 10 秒以内に終わるので、この影響は少しありそう
  - テスト自体の時間にはあまり違いがないため、影響は小さい可能性もある
  - 中間生成ファイルがたくさん発生するため、それらの生成・削除のパフォーマンスが影響してるのかも
  - ビルド時間は結構ブレる（2 倍くらい変わる）ため、GitHubActions の機嫌次第なのかも

## おわりに

今回は GitHubActions でテスト関係の一連の動作時間の短縮を模索したものの、うまくいきませんでした。  
何かいい方法を思いついたら再挑戦したいと思います。
大西配列を覚えてみる

# 前置き
## 目的
- 大西配列への入門
    - 成長仮定を計測しグラフ化する
- コンフォートゾーンから出る


## 大西配列とは
大西氏が作成したキーボード配列の一種.
日本語の統計と, キーボードの打鍵しやすい箇所から計算し綺麗に配置した, という特徴を持つ.

細かは説明は[本家サイト](https://o24.works/layout/)をご参照ください.


## コンフォートゾーンから出る
ある程度のストレス, 不安などが無い精神状態でいられる安全領域.
という感じの定義らしいです.

このゾーンにいすぎると, どうにも心地悪く, 刺激もなく, 成長せず, 生きている意味を感じなくなってきます.


## つまり
同僚の方に紹介いただいて興味を持った事と, QWERTY 配列には飽きたので新しい配列を覚えて見よう.
というものです.


## 懸念の払拭
QWERTYはスタンダードであり, 今も昔もこの配列が強制されます.
そのため, 双方使用出来るように若干の工夫をします
// また, それが許される場所で働けばいい, という割り切りもあります




# 準備と計測
## 双方の配列を混乱せずにしようするために
物理的にキーボードを分けます
QWERTY では hhkb だけを用い
大西配列では, 新調した [corne v4](https://shop.yushakobo.jp/products/8961) だけを用います

同僚の方がキーボードも色々あるよと紹介してくださり, hhkb も十数年使用していたため同様にコンフォートゾーンから出て見ようという範疇に入ります.


## 成長の過程を記録し, 計測する
利用したサイトは主に以下です. NPCとのタイピングバトルサイト
https://typingerz.com/

一戦の 打鍵数 / min が出力されるので, 記録してグラフ化します

最低20バトル / day 行い
1時間 / day 前後を使用していたと思います


## 制約
- 無印字キーボードを用いる
- 当初から完全にタッチタイピングを行う


# 結果

## グラフ
- 補足
    - 練習しなかった日を除外しています
    - 最初の300打付近は, QWERTY 配列での打鍵数になります.
        - 有名な寿司打ですと50皿程度になります.
    - また, 始めの数日は計測しておらず適当な値を入れています.

![スクリーンショット 2025-01-12 12.40.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118627/9c7a6826-8709-79cf-8291-be26a0c77f01.png)


## 所管
- 成長
    - 初日: 30打 / min
        - 一箇所思い出すだけで2~3秒かかりました
    - 約2週間程度:  200~210打 / min
        - 早く打てるパターンもありますが, 手が止まるパターンもまだまだある, という感じです
    - 全般
        - 練習中や睡眠後など, 異なるタイミングで打鍵数が上昇し, 面白い体験でした
- 配列の使い分け
    - 多少の混乱は出ましたが, 使い分け出来るようになりました
- リズム
    - 左右を交互に使う事が多いので, リズムを覚えると成長が見込めそうです


# まとめ
約二週間である程度利用できる様にはなりましたが, まだ止まることが多く疲れも感じます
不安なく使用できるまでには, あと2週 ~ １ヶ月くらいは必要そうです 

楽しく学べたので固定化しているものから少し外へ出てみると, 刺激になって良いかもしれません



# 余談
QWERTY では打鍵ミスが多く, クセになっていました
これは, とにかく早く覚えたい, 早く打ちたいと練習自体が雑になっていたからと思います

大西配列を覚える際には, せっかくなので腰を据えて丁寧に練習をと考えています
最初は時間がかかりますが, 基礎を綺麗にする事で後々の正確性や打鍵速度の向上に寄与すると思います



# 余談2
keyboard による論理配列の使い分け

2,3ヶ月経過したところ, 面白いもので
HHKB の前では, 大西配列を想起できず
corne v4 の前では, QWERTY を想起できない

という癖付けがしっかりなされていました
【AtCoder】ABC388 の D 問題の復習 (いもす法)

# はじめに
[HHKBプログラミングコンテスト 2025 (AtCoder Beginner Contest 388)](https://atcoder.jp/contests/abc388 "HHKBプログラミングコンテスト2025(AtCoder Beginner Contest 388)") にトライしました. A, B, C の 3 問は解けました. しかし D 問題はリストの特定範囲に定数を加算する効率的な方法が分からず, TLE (実行制限時間超過) で終了しました.

解説には **いもす法** を使うと書かれてたので, 復習しました.

# いもす法
[いもす法](https://imoz.jp/algorithms/imos_method.html "いもす法 - いもす研 (imos laboratory)") を読んで理解してください.

# ABC388-D の考え方
コーディング時のリストと合わせるため, 宇宙人のナンバリングは $0$ から $N-1$ とします. また宇宙人 $i$ が持っている石の数を ```A[i]``` とします.

## 渡す石の数
もし宇宙人 $i$ が十分な石を持っていれば, 宇宙人 $i+1$ から $N-1$ までの $N-1-i$ 人に石を渡します.

しかし宇宙人 $i$ が十分な石を持っていなければ, 自分の持っている石の数が上限になります.

そのため, 渡す石の数は以下のように表現できます.

```python
stone_give = min(A[i], N-1-i)
```

## もらう石の数
宇宙人 $i$ がもらう石の数を ```C[i]```, その差分を ```D[i] = C[i] - C[i-1]``` とします.

宇宙人 $i$ が成人すると, ```i+1``` から ```i+1+stone_give``` の宇宙人に石を渡します. そのため, **いもす法** の考え方で ```D[i+1]``` を 1 増やし, ```D[i+1+stone_give]``` を 1 減らします. (下のコードでは, 念のため, 範囲が $N$ を越えないように ```D[min(N, i + stone_give + 1)]``` を 1 減らしています) 

```python
D[i+1] += 1                        # D[] を 1 増やす
D[min(N, i + stone_give + 1)] -= 1 # stone_give+1 だけ先の D[] を 1 減らす 
```

```D``` を更新できたら, 累積和の考え方で ```C``` を更新し, 宇宙人 $i$ の石の数 ```A[i]``` を更新します.

```python
if i != 0:               # i=0 のときは石はもらわない
    C[i] = C[i-1] + D[i]
    A[i] += C[i]
```

# コード
以上を用いてコーディングします.

```python:ABC388_D.py
N = int(input())
A = list(map(int, input().split()))

C = [0] * N     # C[i] ; A[i] が受け取る石の数
D = [0] * (N+1) # D[i] ; C[i] - C[i-1] (C の差分, いもす法)

for i in range(N):
    if i != 0:                    # i=0 のときは石はもらわない
        C[i] = C[i-1] + D[i]
        A[i] += C[i]

    stone_give = min(A[i], N-1-i) # 渡す石の総数
    A[i] -= stone_give            # A[i] の残りの石の数
    
    D[i+1] += 1                        # D[] を 1 増やす
    D[min(N, i + stone_give + 1)] -= 1 # stone_give+1 だけ先の D[] を 1 減らす 

print(*A)
```

# 参考
- [いもす法](https://imoz.jp/algorithms/imos_method.html "いもす法 - いもす研 (imos laboratory)")
- [ABC388](https://atcoder.jp/contests/abc388 "HHKBプログラミングコンテスト2025(AtCoder Beginner Contest 388) - AtCoder")
- [私の回答結果](https://atcoder.jp/contests/abc388/submissions/61622380 "提出 #61622380 - HHKBプログラミングコンテスト2025(AtCoder Beginner Contest 388)")
2024年11-12月の学習記録

## 保守性を考慮したコーディング

下記は扱う言語にかかわらず、広く応用できる考えである。

### システム時刻の取得

システム時刻は、個別の業務ロジックのなかで取得せず、汎用的なモジュールを一度はさんだほうがよい。
そうすることで、テストの際に擬似的に時刻を変更して動作確認することが容易となり、テスト工数の削減につながる。

→ 具体的にどうテストしやすくなるのか、まだ分かっていない。今後の勉強が必要。

### クラス名のつけかた

class・IDなどの「定数名」の一部に「変数」をつけたすのは悪手である。
たとえば、`"class-" + $var` といったクラス名を用いるべきではない。
なぜなら、後々保守をするときに検索がかけづらくなる。
`class-alpha` の仕様を改修する必要が生まれたとき、`class-alpha` でソースコードを検索しても `"class-" + $var` はヒットしない。
このぐらい単純な例なら `class-` で検索すれば十分かもしれないが、もう少し複雑な例ならどうか。ソースコードを調査する時に「さまざまな区切り方の可能性」「検索漏れの可能性」が脳内にチラつくこと自体がノイズであり、作業効率を下げる。

## 「海外の電話番号」に対応した入力フォームの作成

JSライブラリ「[intl-tel-input](https://github.com/jackocnr/intl-tel-input)」を利用することで、海外の電話番号に対応した入力フォームを作成した。
各国の事情に応じて、適切なバリデーションをかけてくれる。たいへん便利だ。

## 「onsenUI」を用いたSPAの改修

「[onsenUI](https://ja.onsen.io/)」というフレームワークを用いた SPA の改修作業に従事した。
ページの切り替えひとつを取っても、今まで扱ってきた通常のウェブサイトとは勝手が異なるため、学ぶことが多い。

## 「WordPress.com」への移行作業

WordPress を用いたとあるウェブサイトを「WordPress.comへに移行する作業に従事した。
WordPress は何年も触ってきた経験があるが、「WordPress.com」は初めてだ。

Github と連携して自動でデプロイする機能や、ステージングサイトを半自動で作れる機能があり、便利だ。
その一方、サブディレクトリを切ることで、1つのドメインのもとに複数のサイトを並立運用することは出来ないというデメリットもある。
【TS】再エクスポートのまとめ

# 再エクスポートとは
複数個所からのファイルインポートを整理して、インポートのパスを使いやすく整理するための技術
index.tsファイルにexport構文で定義するのが一般的な使い方。


## export { default as ... }
- デフォルトエクスポートのみを再エクスポートする
- 元ファイルがデフォルトエクスポートを使用している場合に適切


## export * from ...
- 名前付きエクスポートのみを再エクスポートする
- 元ファイルが名前付きエクスポートを使用している場合に適切
Docker破損したやつはこれを見ろ

# 現状説明
Mac が Docker をマルウェアとして検出し、起動できない状態になっている。
これの解決法を転載する。

---
## 1. Docker 関連のタスクを停止する

まずは、**アクティビティモニタ** を使って、Docker に関連するタスク（プロセス）をすべて強制終了します。

1. **アクティビティモニタ** を起動する  
   - Finder から「アプリケーション」→「ユーティリティ」→「アクティビティモニタ」を開きます。
2. 「CPU」や「メモリ」のタブで「docker」や「Docker Desktop」に関連するプロセスを探します。
3. 対象プロセスを選んで「×(停止)」ボタンから強制終了します。

---

## 2. Docker Desktop をアンインストールする

次に、Docker Desktop アプリケーションをアンインストールします。  
アプリケーションフォルダから「Docker.app」を **ゴミ箱に移動** するか、**アンインストーラ** があればそれを利用してください。

- アプリケーションフォルダ内の「Docker.app」をドラッグしてゴミ箱へ
- （ある場合）Docker Desktop のアンインストーラを利用

---
## 3. Homebrew をインストールする

Homebrew がインストールされていない場合は、以下のリンクまたはコマンドを使用して **Homebrew** をインストールします。

- [Homebrew 公式サイト](https://brew.sh/) からインストールスクリプトを取得  
  もしくは、
- ターミナルで以下のコマンドを実行  
  ```bash
  /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  ```

---

## 4. Brew でインストールされている Docker のアンインストールを確認

以前 Homebrew で Docker をインストールしていた場合、競合を防ぐために一度アンインストールしておきます。以下のコマンドで Docker の cask 版・formula 版をアンインストール可能です。

```bash
brew uninstall --cask docker --force
brew uninstall --formula docker --force
```

- ※ すでにアンインストール済みの場合は何も起こりません。

---

## 5. Docker を Homebrew の Cask からインストールする

準備が整ったら、以下のコマンドで Docker をインストールします。

```bash
brew install --cask docker
```

インストール完了後、Launchpad または「アプリケーション」フォルダから **Docker** を起動できます。

---

## 6. インストール完了後の確認

Docker.app を起動すると、メニューバーに Docker アイコンが表示されます。アイコンをクリックしてメニューが開くようになれば、Docker が正常に動作している可能性が高いです。

- ターミナルで確認する場合  
  ```bash
  docker --version
  ```
  Docker のバージョンが表示されれば OK です。

---

## まとめ

- **Docker Desktop をアンインストール** → **Homebrew をインストール（未導入の場合）** → **Homebrew で Docker のアンインストールを確認** → **Docker を Homebrew から再インストール**
- この手順で、Docker 関連のプロセスを整理しつつ、M1 Mac 上でスムーズに Docker を再インストールできるはずです。

---
## 参考
https://github.com/docker/for-mac/issues/7520#issuecomment-2577815058
【備忘録】ALTER TABLE文について【Oracle Database SQL】

# 1.ALTER TABLE文とは
表作成後、何らかの理由で表の定義を変更する場合があります。そのときに使用する***DDL文***がALTER TABLE文です。
# 2.ALTER TABLE文による表の変更
ALTER TABLE文では、次のことができます。
* 新しい列の追加
* 既存の列の定義(データ型・サイズ・デフォルト値等)の変更
* 既存の列の削除
* 既存の列名の変更
* 表のモード変更(読み取り/書き込みモード、読み取り専用モード)

# 3.列の追加(ALTER TABLE ADD)
ADD句により列を追加できます。
***ALTER TABLE 表名 ADD
　( 列名 データ型(サイズ) [DEFAULT 値] [[CONSTRAINT 制約名] 制約タイプ,]
　　[列名 データ型(サイズ)] ...
　);***
列を追加する表に、すでに行が格納されている場合は、以下の制約が適用される。
* 追加する列にデフォルト値を指定しない場合、すでに格納される行の追加する列にはNULLが格納される。
* 追加する列にNOT NULL制約を設定する場合、デフォルト値を定義する必要がある。

# 4.列の定義変更(ALTER TABLE MODIFY)
MODIFY句により、列の定義(データ型・サイズ・デフォルト値・NOT NULL制約の有無)を変更できます。
ALTER TABLE 表名 MODIFY 
(列名 [データ型] [DEFAULT 値] [NULL| NOT NULL],
 [データ型] [DEFAULT 値] [NULL| NOT NULL]...
);

EMP1表のbirthdate列をDATE型からTIMESTAMP型へ変更しています。
```
ALTER TABLE emp1 MODIFY (birthdate TIMESTAMP);
```
***列の変更に関する主な注意点***
* 表に行データがある状態で、列のデータ型を変更する場合、原則的に、変更対象の列が全行についてNULLである必要があります。例外は以下のデータ型の変更です。
1. DATE型をTIMESTAMP型またはTIMESTAMP WITH LOCAL TIME ZONE型に変更
2. TIMESTAMP型またはTIMESTAMP WITH LOCAL TIME ZONE型をDATE型に変更
* 表に行データがある状態で、列のデータ型のデータサイズを変更する場合、データサイズを大きくする変更のみが実行できます。

# 5.列の削除(ALTER TABLE DROP)
DROP句により既存の列を削除できます。
***ALTER TABLE 表名 DROP ( 列名 [, 列名...]) [CASCADE CONSTRAINTS];***
列の削除に関しては、以下の注意事項があります。
・削除した列は戻せない
・表には最低1つの列を残す必要がある
・他から参照されるFOREIGN KEY制約の親表の列はCASCADE CONSTRAINTSオプションを指定する必要がある
・パーティション化キー列（表をパーティション化するためのキー列）は削除できない
・列に多くのデータが含まれている場合は、削除に時間がかかる



# 6.列の未使用化(ALTER TABLE SET UNSED)
SET UNSED句を使い、既存の列を「UNSED(未使用)」にできます。
ALTER TABLE文で既存の表の列を削除できますが、列の削除中は表にロックがかかり、列に多くのデータが含まれている場合は削除に時間がかかります。
この機能は、多くのユーザーがデータベースを利用する時間帯に負荷の高い削除処理を行いたくない場合の対処策として使用します。
***ALTER TABLE 表名 SET UNUSED ( 列名 [, 列名...]) [CASCADE CONSTRAINTS];***
SET UNUSED句に関しては、以下の注意事項があります。
* UNUSEDに設定した列は戻せず、DESCRIBEコマンドなどで列名やデータ型を確認できなくなる
* UNUSEDにした列に作成された索引や制約は削除される
* UNUSEDにした列と同じ名前の列を表に追加できる
* UNUSEDにした列の表名と列数は「USER_UNUSED_COL_TABS」ディクショナリで確認できる
* 表に対して作成したシノニムの再作成は必要ない
* UNUSEDにした列を含むビューは無効になる