OmniAICreator/Qiita-1.07M huggingface dataset:
SAFE Program Conultant 試験対策

大規模アジャイル手法SAFEの認定資格であるSAFE Program Conultant(以下SPC)試験をこれから受験される方へ、私がSPC試験対策に実施したことをまとめてみました。(2021年10月時点)

# 研修受講
SPC資格を取得するためには5日間のImplementing SAFe®研修を受講する必要があります。まずは集中して研修を受講してください。
研修が終わると受験方法の案内があります。試験は英語で研修後30日以内に受験する必要があります。
私の場合は研修を受講しただけでは試験合格に必要な知識水準に達することができませんでしたので、下記の学習を行いました。

# 試験範囲の確認
試験範囲と配点を下記ページより
https://support.scaledagile.com/s/article/Exam-Details-SPC-SAFe-Program-Consultant?language=en_US

# 試験対策
## 研修テキスト(英語)の読み込み
試験問題はテキストの内容を基に出題されるので、テキストの読み込みは必須です。
PythonでHTMLファイルをWordに変換する

以前の記事で、Spire.Doc for Pythonライブラリを使用してWordをHTML形式に変換する方法を紹介しましたが、このライブラリはHTMLからWord文書への変換も実現できます。プログラミングによってHTMLをWordに変換することで、手作業でコピー＆ペーストするような、時間がかかり、エラーが起こりやすく、書式が混乱してしまう可能性のある作業を避けることができます。

[**Spire.Doc for Python**](https://www.e-iceblue.com/Introduce/doc-for-python.html)ライブラリは、わずか数行のコードでHTMLファイルをWord Docxフォーマットに変換します。以下はその方法です。

## Pythonライブラリのインストール方法：
Python Wordライブラリは、以下のpipコマンドでインストールできます：
```
pip install Spire.Doc
```

## HTMLをWordに変換するPythonコード例
```python
from spire.doc import *
from spire.doc.common import *
 
# Documentクラスのオブジェクトを作成する。
document = Document()
 
# HTMLファイルを読み込む
document.LoadFromFile("input.html", FileFormat.Html, XHTMLValidationType.none)
 
# HTMLファイルをDocx形式で保存する
document.SaveToFile("HtmltoWord.docx", FileFormat.Docx2016)
document.Close()
```

上のコードでは、まず.htmlファイルを読み込み、次に**Document.SaveToFile()** メソッドを呼び出してHTMLファイルを.docx形式で保存しています。HTMLからWordへの変換は、たった3行のPythonコードで簡単に実現できます。

* * *
> その他のWord文書処理や変換機能については、オンラインチュートリアルをご覧ください：
https://www.e-iceblue.com/Tutorials/Python/Spire.Doc-for-Python/Program-Guide/Spire.Doc-for-Python-Program-Guide-Content.html
Python静的型チェックツール(mypy)

## Pythonで静的型チェックを行う
本記事では型ヒントの静的型チェックツールであるmypyについて記載する。

### mypyとは
Pythonコードの静的型チェックを行うツール。
Pythonは動的型付け言語のため、型ヒントの利用に不整合があっても、プログラム実行時にはエラーとならない。そのため、無理に使用する必要はないが、静的型チェックツールと併せて利用することで不整合のない綺麗なコードを記述できる。

- mypyのインストール
```
$ pip install mypy
```

#### mypyによる静的型チェック
早速mypyを利用してエラーを出力する。
下記コマンドを実行して確認する。
```
$ mypy 'ファイル名'
```

##### エラーメッセージ
|エラーメッセージ|説明|
|---|----|
|Incompatible types in assignment|変数の型と異なる型の値を代入している|
|Incompatible return value type|戻り値の型と異なる型の値を返している|
|Argument 1 to "test1" has incompatible type "int"; expected "str"|引数の型と異なる型の値を渡している|


- 変数の型チェック

ファイルを作成し、下記コードを記述する。
```python
name: str = 1234
age: int = '18'
favorite: list = {"study": "プラグラム", "food": "ラーメン", "sports": "陸上"}
size: dict = [168.0, 77.0, 63.5]
```

コマンドを実行し、出力結果を確認する。
```
<出力結果>
mypy_test.py:1: error: Incompatible types in assignment (expression has type "int", variable has type "str")  [assignment]
mypy_test.py:2: error: Incompatible types in assignment (expression has type "str", variable has type "int")  [assignment]
mypy_test.py:3: error: Incompatible types in assignment (expression has type "dict[str, str]", variable has type "list[Any]")  [assignment]   
mypy_test.py:4: error: Incompatible types in assignment (expression has type "list[float]", variable has type "dict[Any, Any]")  [assignment] 
Found 4 errors in 1 file (checked 1 source file)
```

- 関数の型チェック

下記コードを記述する。
```
def test1(msg: str) -> int:
    return msg


print(test1(123))
```

コマンドを実行し、出力結果を確認する。
```
<出力結果>
mypy_test2.py:2: error: Incompatible return value type (got "str", expected "int")  [return-value]
mypy_test2.py:5: error: Argument 1 to "test1" has incompatible type "int"; expected "str"  [arg-type]
Found 2 errors in 1 file (checked 1 source file)
```

#### オプション一覧
|オプション|説明|
|---|---|
|disallow_any_generics|コンテナ(listやdictなど)の要素の型がないことを禁止する|
|disallow_untyped_defs|型がない関数定義を禁止する|
|disallow_untyped_calls|型がない関数呼び出しを禁止する|
|warn_unused_ignore|静的型チェックの対象外とするためのコメント「# type: ignore」がある場合に警告メッセージを表示する|
|warn_return_any|型がない変数を返す場合に警告メッセージを表示する|
|check_untyped_defs|型がない関数内部の型をチェックする|
|follow_imports|インポートしたモジュールをチェックするルールを指定する|
|ignore_missing_imports|インポートしたモジュールに関するエラーを抑制する|
|exclude|除外するファイルやディレクトリを正規表現で指定する|
GitHubのTeamにリポジトリをAPIで追加するスクリプト


## なぜこのようなスクリプト

Organizationの権限管理をTeamでやりたいということになった。

Teamにはアクセスできるリポジトリを設定できる。
しかしOrganizationのリポジトリが200以上あるためこれを手作業でやるのは苦行である。

そこでGitHubのAPIを使用して指定したTeamにOrganization配下のリポジトリを設定する簡単なスクリプトを作った。


## 作成したスクリプト

実行コマンド。
リポジトリの一覧APIの結果件数が最大100までなので、100件以上ある場合のため引数でページ番号を指定する。

```
./add-repo-to-team.sh 1
```

エラー制御はしていない。
リポジトリ一覧APIの結果件数を増やしたい場合は `per_page` を設定するといいが今回は細かく確認したかったのでデフォルトのままにしてある。

```add-repo-to-team.sh
#!/bin/bash

page="$1"
if [ -z "$page" ]; then
    echo "リポジトリ一覧のページ番号を設定してください。"
    exit 1
fi

read -p "GitHubパーソナルアクセストークンを入力してください（ https://github.com/settings/tokens/new でrepoをオンにする）: " token
if [ -z "$token" ]; then
    echo "パーソナルアクセストークンを設定してください。"
    exit 1
fi

read -p "Organization名を入力してください: " org
if [ -z "$org" ]; then
    echo "Organization名を設定してください。"
    exit 1
fi

read -p "Team名を入力してください: " team_slug
if [ -z "$team_slug" ]; then
    echo "Team名を入力してください。"
    exit 1
fi

# リポジトリ一覧取得
# https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-organization-repositories
response=$(curl -L \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $token" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/orgs/$org/repos?page="$page")
# echo "$response"

for repo_name in $(echo "$response" | jq -r '.[].name'); do
    echo "$repo_name"

    # Teamにリポジトリを追加する
    # https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#add-or-update-team-project-permissions
    response=$(curl -s \
      -X PUT \
      -H "Accept: application/vnd.github+json" \
      -H "Authorization: Bearer $token" \
      -H "X-GitHub-Api-Version: 2022-11-28" \
      https://api.github.com/orgs/$org/teams/$team_slug/repos/$org/$repo_name \
      -d '{"permission":"push"}')
    # echo "$response"
done
```
Playwright でページに複数個の要素が存在することを検証する

# 例


## HTML

HTMLにはこんな風にテキストが10個あるとする

```html
<div>FOO TEXT</div>
<div>FOO TEXT</div>
<div>FOO TEXT</div>
<div>FOO TEXT</div>
<div>FOO TEXT</div>
<div>FOO TEXT</div>
<div>FOO TEXT</div>
<div>FOO TEXT</div>
<div>FOO TEXT</div>
<div>FOO TEXT</div>

```

## Playwright

専用の書き方があるわけではなく、ループで回せば良いようだ

画面に `FOO TEXT` というテキストが10個あることを検証する例

```ts
for (let i = 0; i < 10; i++) {
  await expect(page.getByText('FOO TEXT').nth(i)).toBeVisible()
}



```

## nth

なお Playwright の nth では指定順番の要素を得られるようだが、 0始まりのカウントのようだ

- `nth(0)` が1番目の要素
- `nth(1)` が1番目の要素

>Returns locator to the n-th matching element. It's zero based, nth(0) selects the first element.



https://playwright.dev/docs/api/class-locator


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
【執筆中】HTML5ゲームのスコアランキングへのチーターの不正なアクセスを防ぐための方法の考案

# 前提条件

1. 会員登録などをさせられない
1. HTML5なカジュアルゲームである
1. サーバーのコストをとにかく下げたい

# 考え方

1. 怪しいアクセスに対してスコアランキングへの参加を排除しつつアクセス者に対しては投稿の送信が成功したように見せかけて応答する
1. 怪しいスコアののアクセスを排除しつつ自動管理のIPブラックリストにぶちこむ
1. 怪しいユーザIDのアクセスを排除しつつ自動管理のIPブラックリストにぶちこむ
1. 怪しいユーザエージェントのアクセスを排除しつつ自動管理のIPブラックリストにぶちこむ
1. 怪しいアクセスパターンのアクセスを排除しつつ自動管理のIPブラックリストにぶちこむ
1. ユーザIDを起動時にサーバーで生成するが同一IPからの大量生成ができないように制限をかける

# 怪しいIPとは？

1. 一般的に不正と思われるProxy/VPN等からのアクセスをブロックする
1. 自動管理のブラックリストで排除する
  - 怪しいIPに対して◯時間など一時的なブロックをする
1. 手動管理のブラックリストで排除する
  - 目視で明らかな不正を発見したらIP単位でブロックする

## 不正なIPからのアクセスをブロックする
### 1. プライベートアドレスを弾く

### 2. データセンターのアドレスを弾く
https://github.com/X4BNet/lists_vpn/blob/main/output/datacenter/ipv4.txt
https://ipapi.is/hosting-providers-table.html

### 3. TORのアドレスを弾く
https://check.torproject.org/torbulkexitlist

### 4. Pronyのアドレスを弾く
プロキシ IP アドレスを公開しているDBを利用する
https://github.com/firehol/blocklist-ipsets/master/firehol_anonymous.netset

### 5. VPNのアドレスを弾く
https://github.com/X4BNet/lists_vpn/blob/main/output/vpn/ipv4.txt

### 6.  IP が不正行為を行ったかどうか
https://github.com/firehol/blocklist-ipsets/blob/master/firehol_abusers_1d.netset
Vercel初心者🔰による、デプロイするブランチの切り替え作業💪

今月に入り、仕事でがっつりコードを書けており楽しくなってきた者です。
先月はずっとSTUDIOでノーコード開発をしておりました。

デザイナーに気軽にプレビューを共有したいとの思いでVercelを導入しよう！
と思い立ったのですが、初期設定ではmainブランチの内容がデプロイされる状態でした。
毎回mainブランチにマージするのはちょっと...と思い、developブランチをデプロイしたい！！と思い至りました。

ここまで前段...

Vercel初心者なりにsettingsをいじったのですが、デプロイエラーが発生。
社内のフロントエンドさんから教えてもらえたので、覚書としてこちらに書いておきます！

---
結論から言うと、Vercel側の設定はめちゃくちゃ簡単でした！
Varcelの該当プロジェクトの`Settings`>`Git`>`Production Branch`部分に該当のブランチ名を入力するだけ！
![qiita-vercel01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3081960/5f81b9c7-d98f-68bb-30ae-34382a883d90.jpeg)

設定が終わったら、`Deployments`>`デプロイし直したい部分の・・・メニュー`>`Redeploy`の順にクリックすれば、リデプロイが行われます！
![qiita-vercel02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3081960/80ef71a3-64d7-0698-8cc2-622e6134f2c2.jpeg)

以上で私のやりたかったことは実現できました！
簡単なことですが、教わらないとわからない。
独学でコーディングの勉強をしてきた身なので、教わる機会がないことばかりでしたが解決できて助かりました...！
会社内にフロントエンドの方がいらっしゃってとっても助かりました。よかった。
EC2になんでもかんでもやらせることのデメリット

# 前提とか能書き

まず前提として、AWSにおいて2024年現在のクラウド界隈、特に対顧客のブラウザやアプリなどと向かい合うインフラはセオリーともいえるべき構成や手法が確立されています。

多くのプロダクトがこの構成を採用していて、もっともホットなジャンルであるため、対応するAWSのサービスが生み出されて洗練されていったんだと推測します。

その中身を紐解くと、こんなかんじでしょうか

* 全体的な営みの簡略化
    * アプリケーション開発
    * インフラ構築
    * ビルドやデプロイ
* 非機能的な要件の充実
    * ロギング
    * セキュリティ
    * 可用性
    * 抗堪性
    * etc, etc..

# Once up on a time...
2009年くらいまでは古のオンプレミスなプラットフォームにおけるLAMP(Linux, Apache, MySQL, Perl/PHP)構成という鉄板構成がありました。
それらは全て一つあるいは役割を分割した複数の物理的なサーバ筐体構成されて、ネットワークで結合されていました。

いまやその機能の大部分はもろもろひっくるめてAWSのサービスとして置換されています。
かんたんにどう置換されていったかを説明します。

## Linux
ミドルウェアやアプリケーションが動作するOSとしては変わっていないです。
AWS上ではオンプレのサーバとしての機能が分割されているくらいでしょうか。

![machind_penguin.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570665/fb594183-1cb8-385d-9ded-e9bf613a96c0.png)


## Apache
nginxの場合もあるんでしょうけど、かなりの部分はCloudFrontで事足りるはずです。
CloudFrontは本質的にはコンテンツを配るためのもの(CDN)で、そのキャッシュ機構や配信できる能力は強力です。

この部分だけでも可用性や抗堪性の観点から運用が超絶楽になっています。

![apache_ti.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570665/8d882501-3605-6bb9-3b08-ede539376f23.png)

カスタマイズという観点ではapacheやnginxにまだ利があるのですが、そのためにEC2とか維持する？って考えるとちょっと
まあ、受け口をCloudFront、パスごとにEC2とか共存する道はありますが、なんでもかんでもapacheという思想は現状にそぐわないですね。

ただ、クライアント証明書としてTLSの証明書を扱う場合が問題で、これは既存のAWSのどのサービスでも無理だったはずです。(2年くらい前の調査であるため、今はなにかしらあるかも・・といってもVPN使うケースがほとんどでしょうけど）

## MySQL
PostgreSQLも含めかわってないです。
プラットフォームがRDSになり管理が超絶ラクになりました、この辺の事情はApacheの節と変わらず。

![dwh.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570665/9cfb924e-2b3b-be74-2985-f53ecec82168.png)

また、検索機能の一部はElasticSearch。
データの永続化はmongodbなどのNoSQLという選択肢も生まれておりそれぞれホスティングされています。

## PHP/Perl

言語を使っていて処理していた２つの内容。
1. サーバサイドでViewを生成する
1. ビジネスロジックを処理する

これらのうちViewやViewを生成する機能はSPAとして実装され、SSGまたはSSRとしてCloudFrontやAmplifyに移されています。

ビジネスロジックはコンテナの中でAPIとして提供され、BFFを置くというアーキテクチャもSSRに一部食われてたりするのかなあ・・といった現在進行的な時代の流れもあったりなかったりします。

コンテナに載るということを前提にしている以外ではあまり変わってませんね。

ところでみなさん perl ってご存知ですか？ CGIとか・・・・・え、知らない・・そうですよねハハハ・・・

# さて首題の話をしようか

さてこれらを全部EC2で作るとなぜダメなのかについて私の考えを述べます。

## マシンリソースとしてのEC2
EC2やFargateなどの決められたスペックで24時間365日動き続けるものでは、時間あたりに処理できる計算量が一定です。

オートスケーリングという技法を使って必要な時動的にマシンリソースを増やして運用できるようになりましたが、スパイクと呼ばれる瞬間的なアクセス増というか数の暴力には完全な対抗策がないように見えます。

だからといって常時マシンリソースを張るとそれはそれでコストです。
また、起動やアプリケーションの更新などのメンテナンスもイメージ化されたコンテナよりもめんどくさく、きちんと構築、運用されていなければデプロイやローテーションも面倒です。

この点はサーバレスに軍配があがります。

## プラットフォームとしてのEC2
**管理がとことんだるい** 構成を動かしづらい。
EC2周りのコンソールの複雑さが全てを物語っているような気がしています。

CDK等のIaCで構築するのであれば、細かい設定をしなければ１０行くらいなんですけどね。

何かを処理させるプラットフォームとしてつるしでEC2を立てるんだったら、もっと簡易に扱えるECSの方が良い。

戦略的かつ機動的にマイクロサービスを運用するのであればkubernetesも視野に入る。

# 結論
もろもろ便利なサービスがリリースされている中、私はt3.nanoかmicroあたりで動く踏み台サーバくらいにしかEC2を単体で運用するメリットを見いだせないです。
[Go言語]goqueryを用いたWebスクレイピングメモ

## 概要

* ライブラリ`goquery`を用いたWebスクレイピング方法についてメモする。

## goquery 概要

* Go言語で開発されたライブラリ。
* 主にHTMLドキュメントの解析と操作を行うために使用される。
* jQueryのようなシンタックスを模倣しており、HTMLドキュメントを簡単に選択、操作、抽出することができるように設計されている。

**主な特徴**

1. **jQuery風の操作**: jQueryの選択子やメソッドを模倣しているため、WebページのDOM要素を簡単にトラバース（走査）や操作が可能。これにより、HTMLドキュメントからのデータ抽出が容易になる。
2. **HTMLドキュメントのパース**: HTMLをパースしてドキュメントオブジェクトモデル（DOM）を作成し、その後、要素を簡単に検索して操作できる。これはWebスクレイピングやテストデータの生成など、さまざまな用途で利用できる。
3. **軽量で高速**: Go言語の軽量性と高速な実行速度を活かし、効率的なHTMLドキュメントの処理を実現する。

**使用時の留意事項**

1. エラーハンドリング

   - パースやDOM操作で、さまざまな例外が発生する可能性がある。
     - URLフェッチエラー、HTMLパースエラー、セレクター検索エラー、テキスト抽出エラーなど
   - 適切なエラーハンドリングを行い、パース失敗時などのエラー処理を実装する必要がある。

2. 並行処理

   - Goroutineを使ってマルチスレッドで処理を行うことができる。

   - 同時に同一のDOMツリーを操作すると競合が発生する可能性がある。適切な排他制御が必要となる。

     ⇒ 共有DOMツリーの排他制御、部分DOMツリーの排他制御、リードライタロックの利用、チャネルを使ったプロデューサ/コンシューマパターンなどの手法がある。

3. セレクターの最適化

   - XPathやCSSセレクターを使ってDOMを検索できる。一方で複雑なセレクターは処理速度が遅くなる可能性がある。
   - 必要最小限のセレクターを使うような形で、パフォーマンスを意識して設計する必要がある。

4. メモリ管理

   - HTMLドキュメントを完全にパースすると、大量のメモリを消費する可能性がある。
   - 必要最小限のデータのみ抽出するように実装し、メモリリークに留意する必要がある。

5. ユーザーエージェント情報の設定

   - 一部のサイトではユーザーエージェントチェックを行っているため、適切なユーザーエージェント情報を設定する必要がある。

6. Encoding情報の取得

   - HTMLドキュメントのエンコーディング情報を取得し、適切にデコードする必要がある。

## 事前準備

スクレイピング用ライブラリ`goquery`インストール

```sh
go get github.com/PuerkitoBio/goquery
```



## サンプルコード

次のような処理を行うgoqueryを用いたサンプルコードを作成する。

### 処理の流れ

```mermaid
flowchart TB
    start(開始) --> setURL[指定したURLにリクエストする]
    setURL --> checkResponse{レスポンスチェック}
    checkResponse -- Yes --> parseAndExtract[レスポンスを解析し、コンテンツを取得する]
    checkResponse -- No --> logError[エラーログ表示]
    parseAndExtract --> displayContent[コンテンツ表示]
    logError --> finish(終了)
    displayContent --> finish

```



### コード

* `main.go`

```go
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	// ターゲット URL
	url := "http://example.com"

	// ターゲットURLへGETリクエスト
	res, err := http.Get(url)
	if err != nil {
		log.Fatal("Error fetching URL: ", err)
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		log.Fatalf("Status code error: %d %s", res.StatusCode, res.Status)
	}

	// goqueryでdocumentをパースする
	doc, err := goquery.NewDocumentFromReader(res.Body)
	if err != nil {
		log.Fatal("Error loading HTTP response body: ", err)
	}

	// "title"要素を取得する
	title := doc.Find("title").Text()
	fmt.Println("Page Title:", title)
}
```



## 動作確認
* 下記コマンドを実行する。
```shell
go run main.go
```
* 実行結果
```
Page Title: Example Domain
```
※タイトル要素の中身が表示される


## 参考情報

* [goquery - a little like that j-thing, only in Go](https://github.com/PuerkitoBio/goquery)
historyコマンドで履歴番号から実行する方法

コマンド実行履歴を見れるhistoryコマンドで意外と知られていない使い方があったのでご紹介します。

historyコマンドで以下のような結果になったとします

```
$ history

 1110  ll
 1111  ps
 1112  pwd
 ```

この時、左の列の番号を実行すると、そのコマンドを実行出来ます。

試しに ll コマンドでやってみましょう。

## 通常実行
 ```
$ ll 

-rw-r--r--@ 〜 4 18 15:31 01.txt
-rw-r--r--@ 〜 4 18 15:31 02.txt
-rw-r--r--@ 〜 4 18 15:31 03.txt
-rw-r--r--@ 〜 4 18 15:31 04.txt
-rw-r--r--@ 〜 4 18 15:31 05.txt
 ```
 
## 履歴番号から実行
 ```
$ !1110 

-rw-r--r--@ 〜 4 18 15:31 01.txt
-rw-r--r--@ 〜 4 18 15:31 02.txt
-rw-r--r--@ 〜 4 18 15:31 03.txt
-rw-r--r--@ 〜 4 18 15:31 04.txt
-rw-r--r--@ 〜 4 18 15:31 05.txt
 ```
 
先頭に「!」をつけます。

うん、同じコマンドですね。

キーボードの↑を押してコマンドを探す人もいますし便利なのかは不明ですが、こんな実行方法あったんだなあと。
Red Hat Update Infrastructure (RHUI)を探して３千里、AWSの内側なのか外側なのか

# はじめに
某ベンダで、クラウドの人材育成企画と研修トレーニングのデリバリを担当しています。
先日、担当する講義の中で受講生の方からこんな質問ありました。

「AWSを閉域網で利用する場合、NAT GatewayなしにEC2からRed Hat Update Infrastructure （RHUI）にアクセスできますか？」

NAT Gateway使えばいいじゃん、は昔の話。ここ数年、重要システムのクラウド化が進んでおりNAT Gateway禁じ手の案件も増えているようです。（更なるクラウド利用機会の普及を使命と思う僕には嬉しい話。）

Amazon Linuxの場合は、S3にyumのリポジトリがあリます。S3からPrivate Linkを作成すれば、閉域網でのyumの利用が可能です。じゃあRHELは？、ちょっと気になるので、調べてみました。

先に結論を言うと、**外接できないとダメ**でした。

# Amazon Linux 2023の場合
Amazon Linuxのyumレポジトリを確認してみます。

```
#less /etc/yum.repos.d/amazonlinux.repo 
[amazonlinux]
name=Amazon Linux 2023 repository
mirrorlist=https://al2023-repos-$awsregion-de612dc2.s3.dualstack.$awsregion.$awsdomain/core/mirrors/$releasever/$basearch/mirror.list
priority=10
enabled=1
repo_gpgcheck=0
type=rpm
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-amazon-linux-2023
〜省略〜
```
リポジトリの指定先は、S3ですね。想定通り。

# RHEL9の場合
RHEL9のyumレポジトリを確認してみます。
```

#less /etc/yum.repos.d/redhat-rhui.repo 
〜省略〜
[rhel-9-appstream-rhui-rpms]
name=Red Hat Enterprise Linux 9 for $basearch - AppStream from RHUI (RPMs)
mirrorlist=https://rhui.REGION.aws.ce.redhat.com/pulp/mirror/content/dist/rhel9/rhui/$releasever/$basearch/appstream/os
enabled=1
〜省略〜
```

**rhui.REGION.aws.ce.redhat.com**、redhatのドメインぽいです。このドメイン名でgoogleするとEC2のFAQがヒットしました。

https://aws.amazon.com/jp/partners/redhat/faqs/

>Q: Red Hat Enterprise Linux を実行中の Amazon EC2 インスタンス用の更新や定期的なパッチを受け取るにはどうすればよいですか?
Red Hat Update Infrastructure (RHUI) は、<font color="red">**各 AWS リージョンの商用パーティションで Red Hat によって管理されており**</font color>、定期的な更新やパッチを入手するためにアクセスできます。Red Hat Enterprise Linux インスタンスは、リージョンレベルのリポジトリにアクセスして増分更新を受信でき、すべての料金に含まれています。
Q: Amazon Virtual Private Cloud (VPC) で Amazon EC2 での Red Hat Enterprise Linux インスタンスを作成した場合、Red Hat Update Infrastructure (RHUI) にアクセスするにはどのようにすればよいですか?
Red Hat Enterprise Linux (RHEL) のすべてのオンデマンド Amazon マシンイメージ (AMI) は、AWS で Red Hat Update Infrastructure (RHUI) を使用するように構成されています。<font color="red">**VPC では、Amazon EC2 RHEL インスタンスが VPC インターネットゲートウェイとアタッチされた仮想 IP を経由して EC2 の RHUI にアクセスするか、RHUI サーバーへの更新リクエストが一般のインターネットを経由するようにルーティングされた VPN または Direct Connect 接続経由でデータセンターに接続する必要があります。**</font color>
Red Hat Network Satellite のようなオンプレミスの更新リポジトリから更新を入手することをご希望の場合、Red Hat のアカウントでライセンスモビリティプログラムを使って Red Hat Cloud Access AMI の使用権を購入する必要があります。使用権は従来の年間サブスクリプションの形式で提供されます。


VPC インターネットゲートウェイを利用して外接できないとダメみたいですね。
yumレポジトリを調べるまでもなく、答えはFAQにありましたというオチでした。

# おわりに
RedHatの公式サイトには、リージョン毎のRHUIのホスト名、IPアドレスが情報公開されてます。より丁寧にSG/NACLでセキュリティ高度化を意識した通信制御したい場合、フィルタリング情報として必要ですね。

https://access.redhat.com/articles/6695491
Version Lensを使って開発の効率性を爆上げしよう

# これは何？

https://marketplace.visualstudio.com/items?itemName=pflannery.vscode-versionlens

Vscodeの拡張機能。インストールすると拡張機能のバージョンが最新なのか？そうじゃ無いのか？を教えてくれる。(インターン先のエンジニアの方が教えてくださった)

こんないつもの感じが
![CleanShot 2024-04-18 at 15.17.39@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1657253/9c1eb14c-cc84-eaa8-7e5d-95da1c18f1bc.png)

こういう感じに見やすくしてくれる。
黄色が古い
緑色が最新って感じ。
![CleanShot 2024-04-18 at 15.18.03@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1657253/c4a28979-225c-3f75-273f-fabc0755e561.png)


使っているパッケージの上に最新のバージョンが表示されるので、そこをクリックしてやれば勝手に置き換えてくれる。マジで便利。

いちいち
「このパッケージって今バージョンなんぼやろ（ググる）」
みたいな手間から解放されるので作業効率が非常に高くなるで。

![CleanShot 2024-04-18 at 15.19.24.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1657253/c567bfb9-d1a8-ccf9-8f4e-0ec0d076d984.gif)

あとFlutterだけではなくて他のフレームワークでも使えるみたいなので、入れといて損はないと思う。
Pythonの管理にRyeをおすすめしたい

Linux上でPythonをインストールするのってめっちゃ面倒くさいですよね。
Ryeを使えばPythonのインストールからバージョンの管理・変更、パッケージ管理がノンストレスでできちゃう！
# Ryeって何( 簡単に )
RyeはPython用の包括的なプロジェクトおよびパッケージ管理ツール。Pythonのインストール、プロジェクト・依存関係・仮想環境の管理を爆速で統合的に行える。
# インストール方法
Linuxにおいてのインストール方法。
以下を実行するだけ [Installation - Rye (rye-up.com)](https://rye-up.com/guide/installation/)
```bash
curl -sSf https://rye-up.com/get | bash
```

## 尋問される
インストール過程でいくつか質問される。

```bash
? What should running `python` or `python3` do when you are not inside a Rye managed project? › 
❯ Run a Python installed and managed by Rye 
  Run the old default Python (provided by your OS, pyenv, etc.)
```

Ryeに完全に移行したいなら前者、既にシステム内にPythonを使ったプログラムがあるなら後者、悩んだら後者を選ぶほうがセーフティ知らんけど、


```bash
? Which version of Python should be used as default toolchain? (cpython@3.12) ›
```

どうせ後々バージョン変更できるから、適当に入れておこう。(それするためのRyeやしね)

Rye自身のアップデートは以下。
```bash
rye self update
```


# 使い方
## プロジェクトの設定
新しいプロジェクトを作る。
```bash
rye init <PROJECT_NAME>
```
既存のディレクトリでやりたいときは
```bash
rye init
```
でも可

Pythonのバージョンを指定する。
```bash
rye pin <PYTHON_VERSION>
```

設定を反映させる。パッケージの変更のたびに実行する必要がある。
```bash
rye sync
```

### 任意のバージョンのpythonをインストールする方法
インストール可能なバージョン一覧の表示
```bash
rye toolchain list --include-downloadable
```

インストール
```bash
rye toolchain fetch <SUKINAYATU>
```

pinコマンド実行
```
rye pin <<SUKINAYATU>>
```

設定を反映させる。
```bash
rye syn
```

## 仮想環境の実行
仮想環境の実行は
```bash
source .venv/bin/activate
```
これだけ。

ファイルの実行
```bash
rye run python <FILE_NAME>.py
```

仮想環境の終了
```bash
deactivate
```
Nuxt3 server middlewareでbasic認証を入れた際に401エラーが発生した

# はじめに
Nuxt3でbasic認証を実装した際に401エラーとなり、それを解消したので備忘録を書きます。

# 状況
server middlewareで以下のようなコードを作成
(以下の記事を参考にさせて頂きました:bow:)

https://qiita.com/kazama1209/items/9cd0893bc311afbbfc5a

```typescript:/server/middleware/basicAuth.ts
export default defineEventHandler((event) => {
  const base64Credentials = event.node.req.headers?.authorization?.split(" ")?.[1];

  if (base64Credentials) {
    const credentials = Buffer.from(base64Credentials, "base64").toString("ascii");
    const [username, password] = credentials.split(":");

    if (username === "foo" && password === "bar") return;
  }
  event.node.res.statusCode = 401;
  event.node.res.setHeader("WWW-Authenticate", 'Basic realm="Secure Area"');
  event.node.res.end("Unauthorized");
});
```
これで、画面上でbasic認証のダイアログが表示されます。

ここで、画面から呼んでいるAPI内でさらに別のAPIを呼ぶコードを書いた時、401エラーとなりました。
```typescript:/server/api/getHoge.ts
export default defineEventHandler(async (event): Promise<string> => {
  const { id } = await readBody(event);

  // ここで401エラー
  const isFuga = await $fetch<boolean>("/api/isFuga", {
    method: "post",
    body: { id },
  });

  return isFuga ? "fuga" : "hoge";
});
```

# 原因
原因はシンプルで、`getHoge`内での`$fetch`でヘッダを指定していなかったためでした。
画面から呼ばれようが`server`内から呼ばれようが、APIコール時には毎回`middleware`が走るので、`getHoge`内では`$fetch`に対して明示的にヘッダを指定する必要がありました。

# 対策
対策としては、`getHoge`の`event`内に画面から受け取ったヘッダが入っており、その中にbasic認証の情報も入っているので、それをそのまま別APIにも渡せば良さそうです。

`readBody`みたいなのないかな～と思って調べたところ`useRequestHeaders`というComposableがあり使えそうに思いましたが、server内では使えないので結局自作しました。
```typescript:/utils/extractHeader.ts
import { type IncomingHttpHeaders } from "http";

// 引数: IncomingHttpHeaders === [key: string]: string | string[] | undefined
// 返り値: HeaderInit === [string, string][] | Record<string, string> | Headers
//       -> 今回は[string, string][]に変換
export default (headers: IncomingHttpHeaders): [string, string][] =>
  Object.entries(headers).flatMap(([key, value]) => {
    if (Array.isArray(value)) return [[key, value.join(",")]];
    if (value !== undefined) return [[key, value]];
    return [];
  });
```
`IncomingHttpHeaders`型から`[string, string][]`型に変換する過程で、keyに対するvalueがundefinedの場合は除外したかったのですが、`filter`だと型推論で`undefined`が残ってしまうので`flatMap`を使っています。
(TypeScript 5.5で`filter`でも正しく型推論できるようになるので、その際に修正する予定)
```diff_typescript:/server/api/getHoge.ts
+ import { extractHeader } from '../../utils/extractHeader'

export default defineEventHandler(async (event): Promise<string> => {
  const { id } = await readBody(event);

  const isFuga = await $fetch<boolean>("/api/isFuga", {
    method: "post",
    body: { id },
+   header: extractHeader(event.node.req.headers)
  });

  return isFuga ? "fuga" : "hoge";
});
```
これでエラーが解消されました。

今回はbasic認証で詰まりましたが、多分トークンでの認証とかでもserver middlewareを使う場合は同じことが起こると思うので、解消できて良かったです！


「実はserver内からのAPI呼び出しは他の方法があってmiddlewareを回避できるよ」などあればご指摘頂ければと思います:bow:
RFC3339とは？

## 概要
APIなどで時刻情報をやり取りする際に以下のようなフォーマットが使われていて、どういった形式なのか気になり調べてみました。
```タイムスタンプの例
2024-04-18T03:24:00Z
```

## 結論
- RFC3339もしくはISO8601という規格らしい
- RFCはRequest for Commentsの略
- ISOはInternational Organization for Standardizationの略
- 年月日はyyyy-mm-dd、yyyymmdd　どちらでもOK
- 時刻は00:00~24:00の24時間表記
- 日付と時刻の間に「T」を挟む。このTはただの区切り文字という意味しかないらしい
- 末尾の「Z」はタイムゾーンがUTC標準時という事を示す
- 日本時間は「yyyy-mm-ddThh:MM:ss **+09:00**」と表記する
量子フーリエ変換【付録】



![QFT3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/844109/66f68c5e-159d-e715-4561-a02568b53642.png)


図A1 様々な波動とその量子フーリエ変換結果。(左)量子計算機に各状態の係数として入力した波動。(右)それらの量子フーリエ変換結果。
ゼロから始める内製開発～案件編～

# はじめに
前回は内製開発チームのデビュー作であるPoC開発について投稿しました:beginner::flushed:
そちらのプロダクトは体制検証を主目的で構築したので、事業には直接関係のないものでした。
PoC開発を経て、開発案件としてグループ企業の一つであるオルビスの業務で利用するプロダクトを構築したので、今回はこちらについてご紹介します:smile::mega:
    
# 案件の背景・目的
私たちポーラ・オルビスグループは、「ポーラ」や「オルビス」といったブランドを取り扱う化粧品メーカーです:lipstick:
その中でもオルビスは、基幹システムを軸にお客様により良い体験を行っていただくためのサービスを実現しており、事業に必要な機能はほとんど基幹システム内に持っています:briefcase:
この基幹システムは10年超利用されており長年オルビスの事業を支えてきましたが、様々な改修を加えてきたのでシステムが複雑化・巨大化してしまい、システム開発の難易度が高くなり、スピード感をもってお客様に新たな価値を届けることができない点が課題となっておりました:confounded::spaghetti:
そこで、この課題解決のため、基幹システムの一部の機能を段階的に切り出し、マイクロサービス化して新たなシステムを構築する取り組みを行うことになりました:gear:
機能をマイクロサービス化することで、アジリティを高めて価値を提供することを目的にしています:bulb:
マイクロサービス化のイメージは下図の通りです:point_down:
    
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739961/72770593-5b23-867a-c8f9-1e611b387d56.png)
    
    
# 開発スコープ
この取り組みでは、基幹システムの全面刷新ではなく、一部の機能のみをマイクロサービス化のスコープとしております:eye:
スコープは、変化が大きく、アジリティ高くシステム改修が必要な領域としております:dart:
その中でも機能の影響範囲や難易度を考慮し、最初は「商品管理機能」に着手することになりました:clap:
    
また、商品管理機能のマイクロサービス化に合わせ、下記のようなオルビス内で利用している商品関連システムや社内資料統合を行い、新たなプロダクトを構築いたしました:robot:
    ・基幹システムの商品管理機能
    ・成分情報に特化した情報管理システム
    ・使用方法等お客様にご説明する情報に特化した情報管理システム
    ・商品情報を社内に共有するための資料
    
<img width="500" alt="e87baf38-6929-8533-66ff-ff7a6a690e4b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739961/e87baf38-6929-8533-66ff-ff7a6a690e4b.png">
    
# 開発した新商品管理システムの概要
    
我々が開発した新商品管理システムは、情報を登録・検索する機能、マスタ登録機能等、商品情報を管理するために必要な機能を持っています。
イメージは下記の通りです:point_down:こちらは商品情報を検索して閲覧する画面です:mag::eyes:
<img width="600" alt="d0d775a7-4e32-0fa6-89e4-87bc8a569d39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739961/d0d775a7-4e32-0fa6-89e4-87bc8a569d39.png">
    
基幹システムのマイクロサービス化と言うと、既存機能のリファクタリング案件の印象を持たれるかもしれません:thinking:
ですが、開発の進め方は単なるリファクタリングではなく、業務を起点として必要な機能を開発チームで考えて新規プロダクトを構築する形です:computer::sparkles:
もちろん現行踏襲すべき部分もあるので、現行の基幹システムを理解する必要もありますが:sweat_drops:
    
開発手法はアジャイルを採用しており、小機能単位で複数回のリリースを経て2月に正式リリースを行いました:cherry_blossom:
リリース以降いくつか不具合が発覚し、利用しやすくするための改善要望もたくさんあがっているので、現在も継続的な改善活動を行っています:muscle:

    
# さいごに
内製開発チームで構築してきたプロダクトのご紹介は以上になります:bow:
今回はプロダクトの概要のみとなりましたが、使用技術については開発チームのメンバーからご紹介しています:pen_ballpoint:
是非こちらもご覧ください:relaxed:

 https://qiita.com/t_kawada_pohd/items/ae5dcae996d06b02752b
量子フーリエ変換【ソース】

blueqatにおけるソースコードを載せます。

```
 
from blueqat import *
import numpy as np
import copy
import math

def binphase(n, t, circ):
    cres = circ.copy()
    cres.h[t]
    for j in range(2, n - t + 1):
        cres.cphase(2.0 * np.pi / 2**j)[t + j - 1, t]
    return cres


def qft(n, xket, circ):
    cres = circ.copy()
    for j in range(n):
        cres = binphase(n, j, cres)
    return cres

x = [0, 0, 0, 1]
c = Circuit(4)
c.h[:]
cres = c.copy()
r = [j for j in range(16)]
result = cres.run(shot = 100)
print(x, result)
 
```　
　
問1 逆量子フーリエ変換を実装してください。



問2 4量子ビットにおけるもっとも周波数の高い波はどのような状態からできるか。
UI Automationで TabControl のコンテンツが見つからない

WPF `TabControl`のコンテンツを`ControlTemplate`で作成している場合、 UI Automation で コントロール内のエレメントを検索できない

```xaml
<TabControl>
    <TabControl.Resources>
        <Style TargetType="TabControl">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="TabControl">
                        <StackPanel Orientation="Vertical">
                            <TabPanel IsItemsHost="True"/>
                            <ContentPresenter Content="{Binding SelectedContent, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TabControl.Resources>
    <TabItem x:Name="TabItem1" Header="TabItem1">
        <TextBlock Text="TextBlock @ TabIte1" />
    </TabItem>
</TabControl>
```

isnpectで確認すると`TextBlock`がツリーにない
![NG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399204/9d7aba56-2218-be93-0e44-82da76ee67d0.png)

## ContentPresenterに名前を設定する

[TabControl のパーツ](https://learn.microsoft.com/ja-jp/dotnet/desktop/wpf/controls/tabcontrol-styles-and-templates?view=netframeworkdesktop-4.8#tabcontrol-parts)

```xaml
<ContentPresenter x:Name="PART_SelectedContentHost" Content="{Binding SelectedContent, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />

```

![OK.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399204/27471b0a-5a34-b7a6-1f73-af62f24bbf97.png)

## まとめ

`ControlTemplate`、でカスタマイズしている場合は、`ContentPresenter`に名前付きパーツの名前を設定する  

- [コントロールのスタイルとテンプレート](https://learn.microsoft.com/ja-jp/dotnet/desktop/wpf/controls/control-styles-and-templates?view=netframeworkdesktop-4.8)
- <https://stackoverflow.com/questions/3638226/how-can-i-define-a-controltemplate-for-my-tabcontrol-without-breaking-automated>
JWTのBase64URLデコードで引っかかった話

JWTの各要素をパースする処理を自前で書いていたときに、ちょっと詰まってしまったので備忘録として記述しておく。

# 結論
- Base64エンコードとBase64URLエンコードは異なるものである。
- JWTのヘッダ、ペイロード、署名はそれぞれBase64URLエンコードされているものなので、取り出すにはBase64URLデコードしないとダメ。
    - Goならば `base64.RawStdEncoding.DecodeString`関数を使う。

# Base64エンコードとBase64URLエンコード
要約すると以下の違いあり。

**Base64エンコード**
`A-Z, a-z, 0-9, +, /`しか扱うことができない通信環境において、元のデータをこれらの文字にエンコードする方式。
パディング文字として`=`が使われる。
主にEメール、Basic認証、インターネット掲示板で使われる。

**Base64URLエンコード**
URLでは`+, -`は特別な意味をもつため、Base64エンコード済み文字列の中でこれらに相当する文字はそれぞれ`-,_`に変換して扱う方式。
パディングもしない。

# Go標準パッケージでのエンコード・デコード
- 普通のBase64エンコード、デコード: `base64.StdEncoding`を使用する
- Base64URLエンコード、デコード: `base64.RawURLEncoding` を使用する

# 参考
https://stackoverflow.com/questions/33704251/illegal-base64-data-when-trying-to-base64-decode

https://garafu.blogspot.com/2020/01/how-to-use-json-web-token.html

https://qiita.com/kunihiros/items/2722d690b1525813c45e

https://ja.wikipedia.org/wiki/Base64
[備忘][docker][postgres]dockerで立ち上げたpostgresコンテナのDBにpsqlコマンドでアクセスできない

## 問題発生までの過程
postgresコンテナを下記コマンドで起動した。
```
docker run --name some-postgres -e POSTGRES_PASSWORD=password -d postgres
```

次にpsqlコマンドでコンテナ内のDBに下記のようにアクセスしたが、接続できなかった。
```
psql -h localhost -p 5432 -U postgres

----結果----
psql: エラー: "172.17.0.2"、ポート5432のサーバーへの接続に失敗しました: Operation timed out
	サーバーはそのホスト上で稼働していてTCP/IP接続を受け付けていますか?
```
:::note info
postgresでは...
ユーザー名を指定しなければ、デフォルトユーザー名がpostgresとなる。
DB名を指定しなければ、DB名がユーザー名と同じになる（今回はユーザー名も指定してないので、postgresとなる）
ポート番号を指定しなければ、デフォルトポートが5432となる。
:::


## 解決
`docker run`のときに、ポートを指定していなかったから。
こう起動すべきだった。
```
docker run --name postgres-container -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres
```

## 原因究明まで
```
docker inspect postgres-container
----結果----
~~~
"NetworkSettings": {
            "Bridge": "",
            "SandboxID": "612d99cf70a9e6e694bc5987de054318c03188c629bc293e4b7c5e1617b74b29",
            "SandboxKey": "/var/run/docker/netns/612d99cf70a9",
            "Ports": {
                "5432/tcp": null
            },
~~~

```
ネットワークなどに詳しくはないが、この`"Ports": {
                "5432/tcp": null
            },`がnullとなっているのが変だと感じた。
で、コンテナ起動時に`-p 5432:5432`とポートマッピングしてやると
`"Ports": {
                "5432/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "5432"
                    }
                ]
            },`となった。

docker runでポートマッピングをしない場合は、デフォルトでホストの5432ポートとマッピングされるものだと思っていたがそうではなかったようです。
ホストからアクセスしたい場合は、マッピングを省略しないようにします。
Ruby – バイナリと16進数のHEXを相互変換する

# コード例

```rb
def bin_to_hex(str)
  str.each_byte.map { |b| b.to_s(16).rjust(2, '0') }.join
end

def hex_to_bin(hex)
  [hex].pack('H*')
end

bin_to_hex(binary_string)

hex_to_bin(hex_string)
```

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
Docker + Ubuntu で OpenSSLを使う

# dockerコマンドを使う場合

```
docker run -it ubuntu
```

dockerコンテナで以下を実行

```
apt update
apt install openssl

openssl version
```

# Dockerfileを使う場合

```Dockerfile
FROM ubuntu

RUN apt update
RUN apt install openssl
```

コマンド

```
docker build . -t ubuntu-openssl-test
docker run -it ubuntu-openssl-test bash
```


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
量子フーリエ変換【ソース公開有】

今回、量子フーリエ変換アルゴリズムの解説をします。blueqatのサイトにはチュートリアルはありますが、n量子ビットにおける例はありませんでしたので、それを載せることにしました。

通常の古典計算機における高速フーリエ変換(Fast Fourier Transformation(FFT))においては入力データビット長に対して$ O(n2^n) $オーダーの処理が可能ですが、これでは入力データ列の増大に対して容易に計算不能な時間がかかるようになります。

しかし量子フーリエ変換を用いれば、$ O(logn) $オーダーで済みます。
 
まず、あらゆる波動は様々な周波数成分の重ね合わせで表現できます。これは光、音波に限らずあらゆる波動に共通です。フーリエ変換とは、波動におけるそれを構成する周波数成分に分解し、それぞれの振幅を周波数座標(スペクトル座標)に写像して調べるものです。その式は、

```math 

F(\omega)=\int_{-\infty}^{\infty}e^{-i\omega t}f(t)dt

``` 

となります。ここで$ \omega $は角振動数（rad/s)です。手計算ではこの式で周波数成分は完全に分解することができます。本来、これは時間範囲には負の無限から正の無限まで取らなければなりません。しかしながら、計算機は無限を扱えません。そのため、計算機においてはこれを行列演算に直して有限時間範囲のみの計算を行います。これは離散フーリエ変換(Discrete Fourier Transformation(DFT))と呼ばれる手法で、次の式で表されます。

```math 

F_j=\sum_{k=1}^{N}e^{-i2\pi jk/N}f_k.

``` 

ここで、kは時間、jは周波数、Nは時間範囲(データ長)に相当します。この際、周波数成分への分解が可能な周波数の限界は、スペクトルとして用意するデータ長の長さ(解像度)の半分です。この式における$ e^{-2i\pi jk/N} $を成分とする行列が離散フーリエ変換の行列です。しかしながら、この行列を生成し、作用させるにはデータ長に対して$ O(2^{2n}) $オーダーの時間がかかります。

古典計算機いおいてはこれを改善した高速フーリエ変換アルゴリズム(FFT)があります。処理時間は前述のように$ O(n2^n) $となり、現状古典計算機における最速のものです。しかしながら、これ以上の高速化は古典では実現していません。量子計算機において、これを高速で行うアルゴリズムが考案されました。それが量子フーリエ変換(Quantum Fourier Transform(QFT))です。これは量子計算機においてその計算方式と位相が簡単にゲートでくわえられることを利用したもので、O(logn)オーダーでの計算が可能です。その式は、2進小数、

```math 
 
k = 0.k_1 k_2 \cdots k_{n}=\sum_{i=1}\frac{k_i}{2^i}

``` 



を用いて、

```math  
\begin{align}
\mid j \rangle &=& \sum_{k=0}^{2^n-1}e^{-2i\pi jk/2^n-1}\mid k \rangle \\   

&=& \sum_{k_1=0}^{1 
}\sum_{k_2=0}^{1}\ldots\sum_{k_n}^{1}e^{-2i\pi j(2^{n-1}k_1+2^{n-2}k_2+\ldots +k_n)/2^n}\mid k_1 k_2 \ldots k_n \rangle  \\    

\end{align}
``` 

 
と表されます。

量子回路の上では $ R_l\mid 0 \rangle \rightarrow \mid 0 \rangle , R_l\mid 1 
 \rangle \rightarrow e^{-2i\pi / 2^l}\mid 1 \rangle $ 任意位相ゲートRを用いて図1のようにあらわされます。そうして、これを用いて4量子ビットで表された状態 $ \mid 000 0 \rangle $のQFT結果が図2のようになります。[ 付録 ]( https://qiita.com/HWakaura/items/6bf789b42998ae877293 ) にはより様々な状態にフーリエ変換結果を載せました 。
  
  それらからわかるように、波の幅が狭くなるほどにスペクトルには高周波数の周波数成分が現れるようになります。この関係を覚えておくといろいろなところで役立ちます。例えば、電子が座標標空間においては局在している場合、ハイゼンベルグの不確定性関係二よって波数空間においては広範囲にわたって存在しているなどです。

![QFT2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/844109/1d34dbe7-75c5-d229-b4c7-141c547bdb85.png)


図1 量子フーリエ変換を実行する量子回路。

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/844109/7991fedb-d5af-13f2-8974-fca42aa92249.png)


図2 $ \mid 000 0   \rangle $の量子フーリエ変換結果。●は各状態における係数の実部、+は虚部を表します。

QFTを用いることで、入力するデータの長さを容易く増大させることができるため、誤り耐性量子計算が世に出れば、一気に量子計算機の需要が拡大することが期待されています。それのみならず、これは量子位相推定など様々な誤り耐性量子計算機用量子アルゴリズムにおける様々なアルゴリズムで利用されているため、誤り耐性量子計算の基本と言えます。そろそろ誤り耐性量子計算機の研究が始まっているため、2年以内には世に出る可能性が高いです。それまでに、これをマスターすることを私は勧めます。

https://qiita.com/HWakaura/items/f7e7a028d87ef221b6c3
最近流行りの 1 bit LLM って何？

最近 1 bit LLM という量子化技術を用いて学習した技術が登場し、話題になっています。
今回は 1 bit LLM の論文 (The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits) を要約して、1 bit LLM がどのようなものかを簡単に解説していきます。

ちなみに、「**1 bit LLM**」はジャンル名みたいなもので、論文で発表されたモデルの名前は「**BitNet b1.58**」です。

## The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits
### 1 bit LLM / BitNet b1.58 とは？
1 bit LLM こと BitNet b1.58 には以下のような特徴があります。

- 量子化機能
    - BitNet b1.58 では、重みを「-1, 0, +1」のいずれかに限定するために absmean 量子化関数が採用している
        - この関数は重み行列をその平均絶対値でスケーリングし、各値を最も近い整数に丸めるもの
        - 「3 パターンの重みしか取らないので、いわば 1.58bit」= BitNet b1.58 という命名らしい
    - これにより、量子化されたモデルは線形変換を行う際に乗算をほとんど必要とせず、整数加算のみで済むため、エネルギー消費を抑えつつ高速な計算が可能

- 活性化関数の量子化
    - 活性化関数に関しては、非線形関数への入力前に活性化をスケーリングしない方式が採用されており、システムレベルでの最適化が容易

- LLaMA コンポーネントの採用
    - RMSNorm、SwiGLU、ロータリー埋め込み等を利用

### BitNet b1.58 の性能

BitNet b1.58 の性能としては以下のようなポイントがあります
#### 同程度の性能のモデルと比べて、大きな性能の劣化は見られない
類似アーキテクチャの LLaMA と比較して、スコアは同じぐらい出ていますね。

```plantuml
@startuml
<style>
root {
  Padding 0
  Margin 0
}
footer {
  FontColor black
  FontSize 17
}
</style>
footer  BitNet b1.58 の zero-shot タスクのスコアまとめ\n(出典：The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits)
title <img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758571/e6097d5e-e119-c985-1fc3-aff6086ce640.png>
@enduml
```

#### メモリやレイテンシーは効率良し
メモリ占有量とレイテンシーは量子化しているので、明確に効率よくなっています。

```plantuml
@startuml
<style>
root {
  Padding 0
  Margin 0
}
footer {
  FontColor black
  FontSize 17
}
</style>
footer  BitNet b1.58 のコストまとめ\n(出典：The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits)
title <img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758571/118b80a1-d8d3-d322-40b6-a8ca2cb9bf6a.png>
@enduml
```

また、消費エネルギーの面でも効率良いです。

```plantuml
@startuml
<style>
root {
  Padding 0
  Margin 0
}
footer {
  FontColor black
  FontSize 17
}
</style>
footer  BitNet b1.58 のエネルギー消費量まとめ\n(出典：Mixtral of Experts)
title <img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758571/35ca8f6c-a757-f401-a91a-86ee2386fe3d.png>
@enduml
```
この図は以下とのことです。

> 7nmプロセスノードにおけるBitNet b1.58とLLaMA LLMのエネルギー消費量を比較したもの。左側は算術演算エネルギーの構成要素を、右側は異なるモデルサイズにおけるエンドツーエンドのエネルギーコストを示しています。


## 実際どうなの？

「BitNet b1.58 の zero-shot タスクのスコアまとめ」図を見ると、3B のモデルでは量子化後の性能の方が高くなっており、性能の逆転現象があるのではないかと巷では騒がれていましたが、
実際のところ、十分なデータで学習しており、正しく性能を測れるベンチマークで測れば、量子化して性能が高くなることはないようですね。

なので、「エネルギー効率の良さやパラメータ数」と「性能の高さ」はトレードオフにあるかなと思っています。

## まとめ

ということで、1 bit LLM についてまとめました。
LLM の低コストでの運用は非常に大きなポイントなので、今後の更なる技術発展に期待ですね。

おわり
意識低い系ゆるVimのススメ

# はじめに
みなさんVimはお使いでしょうか？
マウスなんていらんっていう強者もいれば、サーバー作業するときにだけ使うからファイルの保存方法くらいは知ってるっていう人もいると思います。

自分はVSCodeにVimプラグインを入れて使っているのですが、未だに使えるコマンドは10個もないと思います。
なんなら未だに移動はカーソルキーですしね。

覚えるの面倒なイメージがあるVimですが、別に全部キーボードで作業する必要もないし、なんかあまり使わないコマンドとか覚えてられないので、よく使うコマンドだけ紹介します。
あとは普通にマウスで移動するし、ちまちま作業します。私はVimmerにはなれなかったので、この先はみなさん頑張ってください。

# Vim基本
細かいことは割愛しますが、Vimにはモードがあります。

## ノーマルモード
最初にファイルを開いた時に、なっているモードです。この状態で移動とか何かコマンドを打ちます。
今日紹介するのは全てこのモードでのコマンドです。

## 入力モード
ファイルに書き込むモードです。

## ビジュアルモード
たまーに使いますが、基本使ってないです。無視です。

## コマンドラインモード
:wqとかファイルを保存するときとか、ファイルを閉じる時だけ使います。あとは分かりません。

# コマンド
基本的に全てノーマルモードでのコマンドです。

### ESCボタン
基本のボタンです。自分が何モードか分からなくなったら連打します。
ちなみに自分はあの悪名高いcaps lockにESCを割り当ててます。自分が使っているキーボードだと左小指てポッと押せるので楽ちんです。

### i
入力モードに移ります。
今指定されてる文字の**前**に入力カーソルが移ります。

### a
入力モードに移ります。
今指定されてる文字の**後ろ**に入力カーソルが移ります。
大文字のAを打つと、その行の一番後ろに入力カーソルが移ります。

### o
入力モードに移ります。
今指定されてる行の1行下に新しい行を作ってそこに入力カーソルが移ります。

### dd
今指定されてる行を1行消してくれます。
なんか6行くらい消したい時にはdを連打するだけです。

### di"
今""で囲まれた文字列の中にカーソルがあってる状態であれば、""の中の文字列だけを全て消してくれます。"を'にしたら''内を消してくれます。囲い文字ならなんでもいけると思います。

### yyp
今指定されてる行のコピーを下の行に作ってくれます。
なんか6行くらいコピーしたい時には最初にyyを押してあとはpを連打するだけです。

### w
1単語カーソルを進めてくれます。
正直使ってないです。

### b
1単語カーソルを戻してくれます。
正直使ってないです。

# まとめ
2,3年このvimプラグインを使ってますが、未だに自分が覚えてるコマンドはこれだけです。（まあ本当はあと2,3個ありますがそんなに使わないので）
たったこれだけでも十分便利だなぁって思うので、是非試してみてください。
あとは1年に1個ペースでコマンドを覚えていく所存です。
IP住所検索サービス作ってみた

## ■初めに
関西のとある企業でエンジニアをしている物です!

普段はバックエンド領域の構築や運用を行っています。
フロントエンド領域のエンジニアをみて華があって良いなと思う事があります.....

そこで今回は裏方の私がChatGPTの力を借りてwebアプリを作成したお話となります。

今回はサービス解説となります、技術解説は次回の記事に作成させて頂きます。

[IPアドレス住所検索サイト](https://ip.r1999.com/)

## ■IP住所検索サービス

![IP住所検索サービストップページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3668800/e9e3d3be-e391-8e1f-c09d-c22dbd12c974.png)

https://ip.r1999.com/

今回作成したwebサービスは「IP住所検索サービス」となります。
IPアドレスやドメインから所属する住所情報を取得し表示するサイトとなります。

フォームに入力したIPデータをJavaScriptのFetchAPIを使用しipinfo.ioのAPIから住所情報を取得します。

次に緯度経度情報を使用し「OpenStreetMap」にて位置情報を埋め込み表示させる機能を作成致しました。

ドメインが入力された際はgoogleのDNSを利用しIPに変換して上記の処理を実行しています。

また現在はベータ版とさせて頂いております!

## ■結果表示
![IP住所検索結果例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3668800/045f923d-a69c-73cb-fd39-e486e1b133b3.png)

今回は例として「8.8.8.8」を検索しました。
検索結果は上記画像の様に表示されます。

表示される項目は以下となります。
* マップ情報
* 検索情報
* 国情報
* 所属地域

## ■主な特徴
* ローカル環境で実行
* マップ表示
* ドメイン対応

## ■表示速度
![IP住所検索サービス表示速度](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3668800/fa19f29f-24a3-addd-e4df-8e24c7dd8890.png)

本サイトはHTMLとJSのみの静的サイトとなる為、比較的早いスピードで表示されます。
デザインも白を基調としたシンプルな構成となっております。

## ■コラム記事ページ

![IP住所検索サービスコラムページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3668800/6aac20f4-cd49-7c0d-6d54-e5d332fbee2d.png)

https://ip.r1999.com/article/article.html

コラムページではサービス利用方法やIP検索に関連する記事を掲載しております。

## ■まとめ
いかがでございますでしょうか。
今後はまだ未実装のマルチ言語対応等を進めていく予定となります。
こんな機能が欲しい等の要望がございましたらコメントよろしくお願い致します。
DjangoでAlpineJSを使う

個人メモ

公式 https://alpinejs.dev/essentials/installation の通り、headタグにCDNを記述

```html:templates/base.html
<html>
    <head>
        ...
 
        <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
    </head>
    <body>
        <div class="container">
          {% block content %}{% endblock %}
        </div>
    </body>
</html>
```

AlpineJSを使いたいところで `x-data` を記述して使用する

```django:app/create.html
{% extends "base.html" %}

{% block content %}
<div x-data="app()">
    <p>Hello <span x-text="message"></span></p>
</div>

<script>
  const app = () => {
    return {
      message: "AlpineJS"
    }
  }
</script>
{% endblock %}
```
ベイズ推定とは

# ベイズ推定とは

ベイズ推定とは、観測された事象から推定したい事柄を算出してリスクの平均を最小にする考え方です。

## ベイズの定理について

ベイズ推定の考え方をそのまま式に表したのがベイズの定理です。

以下の式で表すことができます

```math
P(A|B) = \frac{P(B|A) \cdot P(A)}{P(B)}
```

以上の式はある事象 B が起こった場合における事象 A の起こる確率です
また、P(A|B)を**事後確率**、P(B)を**事前確率**、P(B|A)を**尤度**と言ったりもします

ベイズの定理及びベイズ推定では事後確率を求めることが目的です

例えば、「何かを食べたら甘かった」という**事前確率**と「いちごを食べた」という**条件事象**があったとき、「いちごを食べたら甘かった」という**事後確率**を求めたいとします。

以上の説明をベン図として表すと以下のように表すことができます。
求めたいのは、**いちごを食べた時**、それが**甘いいちごだった時**の確率です

![スクリーンショット 2024-04-18 12.29.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2839531/8e37fdb1-8585-9db7-7110-642d35a51a96.png)

このベン図をもとにベイズの定理を適用すると

```math
甘いいちごだった確率 = \frac{甘く感じた食べ物がいちごだった確率 \cdot 何かを食べたら甘かった確率}{いちごを食べた確率}
```

以上のように書くことができます

ただ注意して欲しいのが、「甘いいちごだった」という事象と「甘く感じた食べ物がいちごだった」という事象が**ベン図上では同じように表現されるが全く別の事象である**ということです

「甘いいちごだった」という事象（積事象）空間は事後確率によって後から名付けられる事象だからです。

例えば、「いちごを食べた」という事象を**事前事象**、「なにかを食べたら甘かった」という事象を**条件事象**とした場合、**事後事象**は「甘いと感じた食べ物がいちごだった」となります。

# 参考文献

https://avilen.co.jp/personal/knowledge-article/bayes-estimator-theory/

https://ja.wikipedia.org/wiki/%E3%83%99%E3%82%A4%E3%82%BA%E6%8E%A8%E5%AE%9A

https://note.com/hakuhodoproducts/n/n44fc5732fd26
Variational Quantum Eigensolver(VQE)で求める微分期待値【付録】

原子間距離r=0.1,2.0で計算した値を付録として他の記事に載せます。

こちらも、r=0.7の場合と同じ傾向が見受けられます。

![Figadapt2vv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/844109/ca5615c4-2ef4-c40d-543a-30d2f1ea4fcd.png)

Fig. 1A 水素分子間距離0.1(Å)の場合における基底状態、三重項状態、一重項状態、二電子励起状態における各変数におけるeq.(2)で計算したハミルトニアン微分期待値の絶対値の常用対数。


Table. 1A 水素分子間距離0.1(Å)の場合における基底状態、三重項状態、一重項状態、二電子励起状態におけるエネルギーとそのSTO-3GにおけるFull-CIで計算された厳密解との差の絶対値の常用対数(対数エラー)。
  
![2021-01-20_19h31_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/844109/349b389b-090a-1680-67f6-42c3901acf22.png)


![Figadap4vv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/844109/c755ca91-d1fc-cafa-f436-2767f96352c4.png)

Fig. 2A 水素分子間距離2.0(Å)の場合における基底状態、三重項状態、一重項状態、二電子励起状態における各変数におけるeq.(2)で計算したハミルトニアン微分期待値の絶対値の常用対数。



Table. 2A 水素分子間距離2.0(Å)の場合における基底状態、三重項状態、一重項状態、二電子励起状態におけるエネルギーとそのSTO-3GにおけるFull-CIで計算された厳密解との差の絶対値の常用対数(対数エラー)。 


![2021-01-20_19h40_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/844109/eea50dc6-bafb-ffda-182d-14e91fabf179.png)
WindowsにDocker環境を構築する

# 1.はじめに
WindowsでDocker環境を構築する際のメモ

# 2.Ubuntuをインストールする
`Windows PowerShell`を起動して以下のコマンドを打つ。
```
wsl --install
```
PCを再起動すると、以下のコマンドが表示される。
指示通り、自分の好きなユーザー名、パスワードを入力する。
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772773/3b9258b1-d9c2-4115-3814-55b44f424413.png)
![pass.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772773/c4582962-d682-c0e2-f1c8-03f77e65a6cb.png)

# 3.UbuntuにPHPをインストールする。
Microsoft StoreからMicrosoftが推奨しているコマンド用のアプリをインストールする。
![terminal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772773/579ebf9d-d58c-ab45-3d74-48f0d944bd56.png)


`＋`横の部分をクリックしてUbuntuを選択
![terminal2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772773/a7b54d02-8ff1-aec4-5c1d-28e25efe6139.png)

以下のコマンドを実行し、software-properties-commonをインストールする。
```
 sudo apt install software-properties-common
```
2で設定したパスワードを求められると思うので、それを入力。
リポジトリの追加とモジュールの更新
```
$ sudo apt-add-repository ppa:ondrej/php
$ sudo apt update
$ sudo apt upgrade
```
PHPをインストールする。今回はphp8.2をインストール
```
$ sudo apt install php8.2
```
phpのバージョンを確認する
```
$ php -v
```

# 4.Composerをインストールする。
3のターミナル上でComposerをインストールする。
```
$ curl -sS https://getcomposer.org/installer | php
```

コマンドのパスを通す
```
$ sudo mv composer.phar /usr/local/bin/composer
```

全ユーザーにComposerのコマンド仕様の権限を付与する
```
$ sudo chmod +x /usr/local/bin/composer
```
Composerがインストールされているか確認する
```
$ Composer -v
```

# 5.Docker Desktopをインストールする。
[公式サイト](https://docs.docker.com/desktop/install/windows-install/)からインストーラーをダウンロードしてインストールする。
インストール後、設定の歯車マークから画像の通りにチェックをいれてAllky&restertをクリック。
![docker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772773/9dafa01e-ef10-824a-f435-c70219bc8a8c.png)

Windows TerminalのUbuntuのコンソールでDockerが使えるか確認する
```
$ docker --v
```

# おわり
【久留米工大 DS部コンペ-WEBアプリ】環境構築　フォルダの配置

# UbuntuサーバーにDjangoのフォルダを配置。

今回はscpコマンドでフォルダを配置したが、差分コピーができるsftpコマンドの方が使い勝手が良さそう。
## scpで送信
https://qiita.com/2ko2ko/items/fe3bd0d37d04d21344db
```
scp -P ポート番号 -r ローカルパス ユーザー@ホスト:リモートパス
```

## sftp(SSH File Transfer Protocol)で送信
sftpセッションを開始し、putコマンドを使用してファイルをリモートサーバーに転送します。
```
sftp username@remote_host
put ローカルパス リモートパス
```
https://www.digitalocean.com/community/tutorials/how-to-use-sftp-to-securely-transfer-files-with-a-remote-server-ja
## SSHで送信
```
ssh ユーザー@ホスト 'cat > リモートパス' < ローカルパス
```
https://qiita.com/sayama0402/items/c5c2795968ced798150a
PythonとSeleniumを使用した自動ダウンロードの実装方法


# PythonとSeleniumを使用した自動ダウンロードの実装方法

この記事では、PythonとSeleniumを活用して、特定のウェブサイト（例としてGigaFile便を使用）からファイルを自動でダウンロードする方法を詳しく解説します。特に、ダウンロードプロセスが完了するまでプログラムが終了しないようにする方法に焦点を当てます。

## はじめに

ファイルの自動ダウンロードは、定期的なバックアップ作業やデータ収集など、多くの業務自動化タスクで役立ちます。PythonのSeleniumライブラリを使用すると、ブラウザ操作を自動化し、このようなプロセスを簡単に実装できます。

## 環境設定

このスクリプトを実行する前に、以下の環境が整っている必要があります。

- Python 3.x
- Seleniumライブラリ
- ChromeDriver（Google Chromeと互換性のあるバージョン）

## スクリプトの解説

以下に、主要なステップごとにスクリプトを解説します。

### 1. 必要なライブラリのインポート

```python
import sys
import time
import os
import subprocess
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
```

### 2. ダウンロード完了の監視

`.crdownload` 拡張子を持つファイルがダウンロードフォルダに存在しなくなるまで監視します。

```python
def wait_for_download_completion(download_folder):
    while True:
        download_files = [f for f in os.listdir(download_folder) if f.endswith('.crdownload')]
        if not download_files:
            print("全てのダウンロードが完了しました。")
            return True
        time.sleep(1)
```

### 3. ダウンロード処理の実装

ブラウザを操作して指定されたURLからダウンロードを開始します。

```python
def download(url):
    global driver
    options = Options()
    options.page_load_strategy = 'eager'
    options.add_experimental_option("prefs", {
        "download.default_directory": download_folder,
        "download.prompt_for_download": False,
    })
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
    driver.get(url)
    element = driver.find_element("xpath", "//button[text()='まとめてダウンロード']")
    driver.execute_script("arguments[0].scrollIntoView();", element)
    element.click()
    time.sleep(5)
```

### 4. メイン関数

コマンドラインからURLを受け取り、ダウンロードプロセスを開始します。

```python
if __name__ == "__main__":
    if len(sys.argv) > 1:
        url = sys.argv[1]
        download_folder = "ダウンロードフォルダのパス"
        download(url)
        wait_for_download_completion(download_folder)
    else:
        print("URLを入力してください。")
```

## まとめ

このスクリプトは、自動化されたウェブブラウジングを通じてファイルをダウンロードし、ダウンロードが完了するまで待つことができます。これにより、定期的なデータ収集やバックアップなどのタスクを効率化することが可能です。