OmniAICreator/Qiita-1.07M huggingface dataset:
DatabricksのAIベースのオートコンプリート

どんどん、AIがソフトウェアを食べていきます。

https://docs.databricks.com/ja/notebooks/use-databricks-assistant.html#ai-based-autocomplete

:::note info
**プレビュー**
本機能は[パブリックプレビュー](https://docs.databricks.com/release-notes/release-types.html)です。
:::

# 機能の有効化

**設定**から**開発者**にアクセスし、**Databricks Assistantのオートコンプリート**をオンにします。
![Screenshot 2024-04-26 at 20.09.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/18d5abdd-36d7-730d-9db5-716717ef2cc1.png)

# オートコンプリートの活用

コーディングしている過程で少し待つと、アシスタントがコードを提案します。確定するには**Tab**を押します。

コメントを記述して次の行に移動して少し待つと、コメントに即したコードが提示されます。これも確定するには**Tab**を押します。

<iframe width="560" height="315" src="https://www.youtube.com/embed/0_1Z33HAspY?si=0C84TpeDYcTuD8K5" 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>

ちなみにタイトルもAIで自動生成されます。
ますますコーディングスタイルが進化していく…。すごいです。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
VSCode で isort, Black, flake8 を自動で実行する機能が動作しない！！

# TL;DR;
- `setting.json` で `Unknown Configuration Setting` と言われて，自動でコードを整形してくれなかった．
- 拡張機能で `ms-python` と検索し， `isort`, `Black Formatter`, `Flake8` を導入する．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3534163/de7ea22b-801b-45c8-fe46-be3cdc6dd73c.png)


# 問題
- `isort`, `Black Formatter`, `Flake8` を自動で実行してくれる拡張機能を `VSCode` に入れたかった．
- 何故か， `setting.json` で `Unknown Configuration Setting` と言われて，自動でコードを整形してくれなかった．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3534163/cfe9e6e0-1c93-9f90-220f-ff024ea742f8.png)
# 解決
- 拡張機能で `ms-python` と検索し， `isort`, `Black Formatter`, `Flake8` を導入して解決．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3534163/de7ea22b-801b-45c8-fe46-be3cdc6dd73c.png)


# 最後に
以下，どうでも良い経緯を載せます．
先日，自分のPythonコードを先輩に見せる機会があったんですよ．その先輩にコードを見せる前に，
*「`isort`, `Black Formatter`, `Flake8` の3つを実行して綺麗にしてから見せよう！！」*
と僕は思いました．そしてデバッグをしながら，それらを何回か実行してた時に，
*「シェルスクリプトで一発実行したろ」*
って思って，シェルスクリプトを作ったんすよ．いざPythonコードを先輩に見せる時，せっかくなので，このシェルスクリプトも一緒に自慢気に見せたら，
*「自動でそれらを実行してくれる `VSCode` の拡張機能あるよ」*
って言われたので， ~~渋々~~ 喜んでその拡張機能を入れようとしてみた時に，上記の問題が起こったんすよね．
Atcoderを真剣に入色しよう～ ABC350

# ABC350を解いた際の考え方と解説を読んだアウトプット
[ABC350](https://atcoder.jp/contests/abc350)

結果:C問題まで着手したが、解けたのはA問題のみ

## A - Past ABCs
*考え方*
1以上350未満かつ316でない場合はYesを返す
ABC000に引っかかってしまった

## B - Dentist Aoki
*考え方*
1回目:setを用いて重複を消し、総数 - 治療回数 + setの中身の数で回答
入力例3のようなものでマイナスの値を取ってしまう

*考え方2*
bool型のバケツを作り、バケツに入った数が答えとする
入力されるたびに判定をすることで回答を導き出すことができた

*解説を読んで*
自分はif文で制御していたが、0と1の入れ替えをする際にxorを用いる実装方法を知ることが出来た

## C - Sort
*考え方1*
ソート手法に入れ替えた回数と入れ替え部分を記録した
用いたアルゴリズムが*O(N^2)*となるため、TLEしてしまった

*考え方2*
swapを用いて入れ替える
swapを使うのはいいが、入れ替えた数字をメモすることを考えていたら手が止まってしまった(単なる実力不足ですね)

*解説を読んで*
線形代数で見たことあるやつを使っていて感動した(小並感)
数字の存在位置を示す配列を別途で用意することで処理回数を減らすことができるのは目から鱗だった

## D - New Friends 
*考え方*
連結可能なノードを探して数え上げる
言うのは簡単ですね(実力不足でした)

*解説を読んで*
>考え方は合っていた、嬉しい

*他の人の回答を見て*
[ngtkanaさんの回答より](https://atcoder.jp/contests/abc350/submissions/52565412)
>RustにもUnionFindのライブラリがあるんやなぁ、、、

## ドデカメモ
RustでのUnionFindの使い方
https://qiita.com/illumination-k/items/6fe0e91d4681fe48ab8e
↑参照

~~~ruby
  use petgraph::unionfind::UnionFind;
  let mut uf = UnionFind::new(); //UnionFindの宣言と初期化
  uf.union(a,b); //aとbのグループを結合
  let flag:bool = uf.equiv(a,b); //aとbが同じグループに属するか判定
~~~
CodePipelineからliquibaseのコマンド自体を渡す

# はじめに

CodePipelineもliquibaseも初めてなため、おかしなやり方かもしれませんが、誰かの役に立てばと思います。

# 背景

liquibaseをCodePipeline上で動かすにあたって、動的にコマンドやchangesetのファイルを指定したいため、CodePipelineからliquibaseのコマンド自体を渡せるようにしました。
（ほかにもっといいやり方があれば教えていただけると助かります）

# やり方

まずは出来合いのCodePipeline、CodeBuildを用意してください。
CodePipeline、CodeBuildの作り方は他記事を参照してください。

ざっくり構成を箇条書きすると以下です。

* CodePipeline
    * sourceステージ
        * githubからliquibaseのマイグレーションファイルを取得
    * buildステージ
        * liquibaseのinstallからコマンド実行までをCodeBuildで実行

## CodePipelineに`COMMAND`変数を作成する

以下画像の通り、Pipelineに変数を追加

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2263720/5ed117bd-24fd-0040-a26f-ccd49d400620.png)

## Buildステージに`COMMAND`変数を渡す

以下図のようにすれば、Buildステージに`COMMAND`変数を環境変数として定義できます。
CodePipelineで定義した変数は`#{variables.変数名}`とすれば、Buildステージで参照できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2263720/beb55f54-e430-556c-12e2-f5fa22a8d0d6.png)

## CodeBuildから、Buildステージで定義した`COMMAND`変数を参照する

出来合いのCodeBuildのbuildSpec.ymlを編集します。
buildフェーズでliquibaseコマンドにCodePipelineで定義した`COMMAND`変数を渡します。

```yml
    build:
        commands:
            - echo "COMMAND=$COMMAND"
            - liquibase $COMMAND 
```

## CodePipelineを実行

CodePipelineを実行すると、以下のように`COMMAND`の入力欄が出てきます。
ここで実行したいliquibaseコマンドを指定すれば、そのコマンドがCodeBuildが実行されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2263720/111bcfe9-a5df-b693-10f9-2bca83283e6d.png)
Unlocking Success with a Salesforce Consulting Partner

Unlocking success with a Salesforce consulting partner can be a game-changer for businesses aiming to maximize the potential of their Salesforce implementation. Here's how partnering with a Salesforce consulting firm can drive success:

Expertise and Experience: Salesforce consulting partners bring in-depth expertise and experience to the table. They understand the platform inside out and can offer insights on best practices, customization options, and integrations tailored to your business needs.

Strategic Guidance: A consulting partner can help you align your Salesforce strategy with your overall business objectives. They can assess your current processes, identify areas for improvement, and develop a roadmap for success.

Customization and Integration: Salesforce is a highly customizable platform, but navigating its complexities can be daunting. Consulting partners can customize Salesforce to fit your unique workflows and integrate it seamlessly with other systems, maximizing efficiency and productivity.

Training and Support: Effective adoption of Salesforce requires proper training and ongoing support for your team. Consulting partners offer training programs tailored to your specific requirements, ensuring that your team has the skills needed to leverage Salesforce effectively.

Continuous Improvement: Salesforce is not a one-time implementation; it's an evolving platform that requires continuous optimization. A consulting partner can help you stay ahead of the curve by monitoring performance, identifying opportunities for improvement, and implementing enhancements to drive business success.

Access to Resources: Partnering with a Salesforce consulting firm gives you access to a vast network of resources, including certified experts, industry insights, and specialized tools. This access can accelerate your Salesforce journey and help you achieve your goals faster.

Scalability: As your business grows and evolves, so do your Salesforce needs. Consulting partners can scale your Salesforce implementation to accommodate growth, ensuring that the platform continues to support your business goals effectively.

In conclusion, partnering with a Salesforce consulting firm can unlock the full 
potential of your Salesforce investment, driving success and enabling your business to thrive in today's competitive landscape.

Website: https://www.deltainfotek.com
何も考えずにUbuntu環境で最速でPDFから複数毎の画像をファイルを生成する (Pdftoppm)

複数ページから構成されるPDFを入力として、出力としてページ毎のPDFを画像として出力したい場合があることがある。

Pdftoppm といコマンドを利用すると一発でいけるみたい。このプログラムはPDF
処理用の関連ユーティリティの`poppler-utils`の中に含まれているみたい。

### Pdftoppm のインストール方法
```bash
$ sudo apt install poppler-utils -y
$ which pdftoppm
/usr/bin/pdftoppm ★ちゃんと入っている
```
### 使い方
一番、使うパタンがPDF（複数ページから構成される）をページ毎にpngファイルに変換する。

```bash
$ pdftoppm -png {入力PDF} {出力時のファイルのプレフィックス名}
```
例)
```bash
$ pdftoppm -png sample_01.pdf tmp
$ ls tmp*
tmp-1.png ★ tmpがプレフィックス
tmp-2.png ★ tmpがプレフィックス
```

参考URL:
[Pdftoppm、PDFファイルをUbuntuからの画像に変換](https://ubunlog.com/ja/pdftoppm-%E3%81%AF-pdf-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E7%94%BB%E5%83%8F%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%97%E3%81%BE%E3%81%99/)
pendo API openapi (自作

PendoのAPI使うためのオフィシャルなSDKがなく、かつ正直PendoのAPIドキュメンテーションがホストされているPostmanわかりにくい（正直でごめん

https://engageapi.pendo.io/

自分でライブラリ書こうにも何をどう対応したらいいのかわかりにくいので、openai対応を自力で頑張っています。

目検でopenapi記述しているので間違っているところもあるかと思います。

また、対応しているAPIが少ないです。

Visitor, metadata, Accountだけ。今後対応増やしていこうと思っています。

今後増やしていこうと思いますが、もし貢献いただけるかた居たらぜひ！

https://band-aid.github.io/pendo-openapi/
![CleanShotgAOgc2DO@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227518/fc08556c-25e6-e078-33d8-8eda030c96bc.png)


ソース：
https://github.com/Band-Aid/pendo-openapi
フレミングの左手の法則と磁束密度の分布

# はじめに
電動機が回転する理由は、フレミングの左手の法則によって説明することができる。フレミングの左手の法則は、平等磁場空間に電流を流した導体を垂直方向に置くと電磁気力が生じるというものである。その方向は、磁極と導体棒が作る合成磁場の密度が大きいところから、小さいところに向けて移動する方向である。今回は、そのことについて、Pythonを用いて調査することを目的とする。

# フレミングの左手の法則とは
磁束密度$\textbf{B}$平等磁界中に垂直方向に長さ$l$で電流$\textbf{I}$が流れている導体棒を置くと、以下のような力$\textbf{F}$が生じる。
```math
\textbf{F}=(\textbf{I}\times\textbf{B})l
```

この力の働く方向は、磁束密度が密から疎に行く向きである。
これをPythonプログラムを用いて説明する。

まず、導体棒に電流が流れた場合、右ネジの法則により、以下のような磁場が生じる。ただし、導体棒からの距離を$r$とする。

```math
H=\frac{I}{2\pi r}
```

これをプログラムによって再現すると以下のようになる。

```python lin_h.py
"""
画面垂直方向に伸びる導線の周辺に働く磁場について
"""

import numpy as np
import matplotlib.pyplot as plt
import math
plt.figure()


LX, LY=3,3

gridwidth=0.3 
X, Y= np.meshgrid(np.arange(-LX, LX, gridwidth), np.arange(-LY, LY,gridwidth)) 




#導線の位置
x1,y1=0,0 
z1=x1+1j*y1
I=10  #定常電流の値
R1=np.sqrt((X-x1)**2+(Y-y1)**2)
plt.plot(x1,y1,'o',color='blue')

#ベクトル関数の設定。定常電流が作る静磁場 F(U(x,y), V(x,y))


x=[]
y=[]

U=np.zeros((len(X),len(X)))
V=np.zeros((len(X),len(X)))
z=0

for i in range(len(X)):
    for k in range(len(X)):
        x=X[i][k]
        y=Y[i][k]
        z=x+1j*y
        z_1=z-z1
        H=I/(2*math.pi*abs(z_1))*((-1j)*z_1/abs(z_1))
        U[i][k]=H.real
        V[i][k]=H.imag
        # if abs(z_1)>0.3:
        #     plt.quiver(x,y,u,v,color='red',angles='xy',scale_units='xy', scale=4.5)

plt.streamplot(X,Y,U,V,color="red")
plt.xlim([-LX,LX])
plt.ylim([-LY,LY])

# グラフ描画
plt.grid()
plt.draw()
plt.savefig("線電流により生じる磁場.png")
plt.show()
```
これによって描かれる磁場は以下のようになる。ただし、電流は、画面表から裏方向である。

![線電流により生じる磁場.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/d8a6cd33-ea26-cf75-6342-e3c68525fa75.png)

次に、フレミングの左手の法則について考察する。

上図に対して左から右に平等磁場をかけるプログラムを以下に示す。

``` python jiba_f.py
"""
画面垂直方向に伸びる導線の周辺に働く磁場について
"""

import numpy as np
import matplotlib.pyplot as plt
import math
plt.figure()


LX, LY=3,3

gridwidth=0.3 
X, Y= np.meshgrid(np.arange(-LX, LX, gridwidth), np.arange(-LY, LY,gridwidth)) 




#導線の位置
x1,y1=0,0 
z1=x1+1j*y1
I=10  #定常電流の値
R1=np.sqrt((X-x1)**2+(Y-y1)**2)
plt.plot(x1,y1,'o',color='blue')

#磁極による磁場
H_x=0.8

#ベクトル関数の設定。定常電流が作る静磁場 F(U(x,y), V(x,y))


x=[]
y=[]

U=np.zeros((len(X),len(X)))
V=np.zeros((len(X),len(X)))
z=0

for i in range(len(X)):
    for k in range(len(X)):
        x=X[i][k]
        y=Y[i][k]
        z=x+1j*y
        z_1=z-z1
        H=I/(2*math.pi*abs(z_1))*((-1j)*z_1/abs(z_1))
        #導線による磁場と磁極による磁場の合成
        U[i][k]=H.real+H_x
        V[i][k]=H.imag
        # if abs(z_1)>0.3:
        #     plt.quiver(x,y,u,v,color='red',angles='xy',scale_units='xy', scale=4.5)

plt.streamplot(X,Y,U,V,color="red")
plt.xlim([-LX,LX])
plt.ylim([-LY,LY])

# グラフ描画
plt.grid()
plt.draw()
plt.savefig("線電流により生じる磁場.png")
plt.show()
```

これを実行すると以下のようになる。


![導線と磁極.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/813d0938-b245-57b6-830a-0f5ded54ce63.png)


この図を見るに、磁束密度が密な上部から磁束密度が疎な下部に向けて力が働くということが推測できる。これがフレミングの左手の法則の意味である。

# まとめ
今回はフレミングの左手の法則について、紹介してPythonによって図示することを試みた。これによって、電磁力は磁束密度が密な部分から疎の部分に働くということが推定することができるということが分かった。
RASIS？信頼性と可用性の違いを説明できますか？

RASIS（Reliability, Availability, Serviceability, Integrity, and Security）
RASIS？最初見たとき、ライスだと思いました。DEMO、ごはんじゃありません。

説明も上手く出来なかったので、 __一言で説明出来る__ ようにするために、整理しました。




| 項目       | 説明                                                                                         |
|------------|----------------------------------------------------------------------------------------------|
| 信頼性     | __システムの壊れにくさを評価する指標__<br>- ハードウェアとソフトウェアの両方において障害や不具合をゼロにすることはできませんが、最小限に抑えることは可能です。<br>- 平均故障間隔（MTBF）は、システムが安定稼働し続ける平均時間を示す指標。MTBFが長いほど信頼性が高いと言えます。     |
| 可用性     | __システムが障害などにより停止することなく稼働し続けることを指す__<br>- クラウド利用のメリットの一つとして重要視される。<br>- 稼働率はシステムの可用性を判断する指標であり、一定時間内でシステムが稼働可能な時間の割合を示す。                |
| 保守性     | __システムが機能や性能を維持できるかどうかを示す__<br>- ハードウェアではメンテナンスや修理の容易さ、ソフトウェアでは不具合修正や仕様変更の容易さが重要。<br>- サービスの停止時間が短いシステムは保守性が高いと評価される。                           |
| 保全性     | __データの正確性や完全性を示す__<br>- 情報処理や電気通信の分野ではデータの欠損や不整合がないことを重視する。<br>- 情報セキュリティの分野ではデータの妥当性に注目する。                                             |
| 安全性     | __システムが利用するデータに対して高いセキュリティを維持することを指す__<br>- 外部からの不正侵入やデータ漏えいを防ぐために対策を講じる必要がある。                                                |

では、どうやって信頼性を維持するのでしょうか？
--
AWS Well-Architected フレームワーク 信頼性を例に、見ていきましょう。
https://wa.aws.amazon.com/wellarchitected/2020-07-02T19-33-23/wat.pillar.reliability.ja.html
5つの設計原則からなります。


| 設計原則                                       | 具体的な例                                                                                                                                                      |
|--------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1. **障害から自動的に復旧する**               | Amazon Route 53の __ヘルスチェックと自動フェイルオーバー__ を使用して、EC2インスタンスやS3バケットなどのリソースの障害から自動的に復旧する。                                                   |
| 2. **復旧手順をテストする**                   | AWSのCloudFormationやTerraformを使用してインフラストラクチャのコード化を行い、定期的に __デプロイメントパイプラインを使用__ して復旧手順をテストする。                                                 |
| 3. **水平方向にスケールしてワークロード全体の可用性を高める** | Amazon EC2 __Auto Scaling__ を使用して、Webアプリケーションのインスタンスを自動的にスケーリングし、トラフィックの変動に応じてワークロード全体の可用性を維持する。                                               |
| 4. **キャパシティーを推測することをやめる**                 | AWSのCloudWatchを使用して、CPU使用率やネットワークトラフィックなどのメトリクスを __モニタリングし、必要に応じてインスタンスの数やサイズを調整__ してキャパシティを維持する。                                           |
| 5. **オートメーションで変更を管理する**          | AWSのCodeDeployを使用して、アプリケーションのデプロイを自動化し、変更を管理する。また、AWS Lambdaを使用して、サーバーレスアーキテクチャを構築し、__コードの実行とスケーリングを自動化__ する。 |

__これで、壊れにくい信頼性のあるシステムを構築するという事がどういう事か理解出来たと思います。__
UPDATE_ROLLBACK_FAILEDに陥ったCloudFormationスタックへの対処手順

Serverless Frameworkを用いてAWSにデプロイ・運用していたサービスについて久々に更新を掛けたところデプロイに使用していたIAMユーザーが必要なアクションの権限を持っていなかったことが原因で`UPDATE_ROLLBACK_FAILED`に陥ってしまいました。:cry:
このときの対応方針について調査、修正したときのメモになります。

## 1. エラーの原因を調査
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/08aca16b-fe5d-dc60-6984-d1d74dbffbb6.png)

1. まずはServerless Frameworkによって呼び出されるCloudFormationの更新処理（UpdateStack）が何由来で失敗に至ったかを調べるのにAWSのマネジメントコンソールにアクセス
2. CloudFormationのスタック一覧から該当のスタックを選択
3. イベントタブのログをさかのぼりエラー内容（状況の理由）を確認
   - 「根本原因を検出」というボタンを押すと直近のイベントログのうち一番古いエラーにジャンプできる
   - 最新のステータスがエラー状態のときのみ押下可能かも

今回はデプロイに使用しているIAMユーザーに必要なアクションの権限が不足していました。
エラーによってはServerless Frameworkのデプロイを行っている側のログにも同じ内容が出ることもあるかも。

## 2. エラーの原因を解決しロールバックを再実行
参考サイト内の情報によると`UPDATE_ROLLBACK_FAILED`状態に陥った状況で取れる対応は `ContinueUpdateRollback または DeleteStack のオペレーションのみ` とのこと。
- [DeleteStack](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_DeleteStack.html)
- [ContinueUpdateRollback](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_ContinueUpdateRollback.html)

DeleteStackは行えないのでまずはロールバックを完了させることにしました
1. まずはエラーの原因について解決（IAMユーザーのポリシーに必要なアクションを追加）
2. CloudFormationのスタック詳細画面で「スタックアクション > 更新ロールバックを続ける」を選択
3. ステータスが`UPDATE_ROLLBACK_COMPLETE`になれば正常にロールバックできたといえる？
   - `×アイコン出てるけどこれが正常な「更新ロールバックを完了させた状態」のステータスだと思います`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/e02e41a4-96ac-303a-cbb7-802744ed4275.png)


---
ちなみに`UPDATE_ROLLBACK_FAILED`状態に陥ったあと、ロールバックを完了させない状態のまま再度Serverless Frameworkからの再度のデプロイ操作を行ったところ以下のようなエラーが出ました。
```bash
$ npx serverless deploy --verbose
~~~いろいろ~~~
Error:
Stack:arn:aws:cloudformation:ap-northeast-1:@@@@@@@@@@@@:stack/@@@@@@@@@@@@@@/@@@@@@@@@@@@@@@@@@@@@@@@@@ is in UPDATE_ROLLBACK_FAILED state and can not be updated.
```

## 3. 再度デプロイ
最新のステータスは`UPDATE_ROLLBACK_COMPLETE`のためスタックのステータスは赤い状態ですが、再度のデプロイ操作が可能となりました。
```bash
$ npx serverless deploy --verbose
~~~いろいろ~~~
✔ Service deployed to stack @@@@@@@@@@@@@@@@
~~~いろいろ~~~
```

`エラーの先にまた別のエラーが隠れていることもあり、実際には何度かロールバックと再デプロイをやりなおす必要があることも`

## 参考サイト
- [UPDATE_ROLLBACK_FAILED 状態のままになっている CloudFormation スタックを更新する | AWS re:Post](https://repost.aws/ja/knowledge-center/cloudformation-update-rollback-failed)
Proxmox VE 8.2 の自動インストールを試してみた

# はじめに
この記事は、Proxmox VE 8.2での新機能: **Automated Installation** を行った際の記録です。
検証したところ、**5分程度**でインストールが完了しました。

## 共著
- @marusoftware
- @rk76feWF 

# これまで
Proxmoxのインストールに使用する、ベアメタルISOインストーラは、自動化には対応していませんでした。自動化したい場合、Debianをセットアップし、Proxmoxのコンポーネントをインストールするなど、手間がかかる方法しかありませんでした。

https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_11_Bullseye

# 新機能
今回のリリースに含まれる Automated Installation は、ISOインストーラに私たちがインストールの際に入力する設定を`answer.toml`として内包することで、GUIやCLIでの設定画面をスキップし、自動的にインストールされるというもののようです。

Answerを渡す方法は主に3つあります。
1. ISOインストーラに`answer.toml`を直接内包する
1. 特定の名前`proxmox-ais` or `PROXMOX-AIS`が付けられたパーティションから読み込む
1. http経由で取得する

いずれの場合でも後述の`proxmox-auto-install-assistant`ツールを用いてインストーラに手を加える必要があり、それぞれで引数に渡す値が異なります。

https://pve.proxmox.com/wiki/Automated_Installation

# 使い方
`proxmox-auto-install-assistant`は、Proxmoxの無償版リポジトリにあります。
既にProxmoxがインストールされているマシンがある場合はそちらを使って作成することができますが、今回はPCのみで作成したいので、Dockerにて作成を行います。Windowsの方はwslを使用した方が手軽で良いかもしれません。

`proxmox-ve_8.2-1.iso`は公式サイトから最新のISOインストーラーをダウンロードして配置してください。

今回は一番手軽なISOインストーラに`answer.toml`を内包する方法を試してみます。
## 環境
```bash: PC
$ tree
.
├── Dockerfile
├── answer.toml
└── proxmox-ve_8.2-1.iso
```

```toml:answer.toml
[global]
keyboard = "jp" # en-us
country = "jp"
fqdn = "pve01.example"
mailto = "mail@example"
timezone = "Asia/Tokyo"
root_password = "proxmox"
# root_ssh_keys = [
#     "ssh-ed25519 AAAA..."
# ]

[network]
source = "from-answer" # or "from-dhcp"
cidr = "192.0.2.1/24"
dns = "192.0.2.254"
gateway = "192.0.2.254"

# NICが複数ある場合、どのNICかを選択するためフィルタをかける必要がある
filter.ID_NET_NAME_MAC = "*e43d1afa379a"
# filter.ID_NET_NAME = "enp0s25"

[disk-setup]
filesystem = "ext4"
lvm.swapsize = 0
lvm.maxvz = 0
disk_list = ['sda']
```

```Dockerfile:Dockerfile
FROM --platform=linux/amd64 debian:bookworm-slim

# apt リポジトリの更新と必要なパッケージのインストール
RUN apt update && apt install -y \
    wget \
    xorriso

# Proxmox VE 自動インストールアシスタントのダウンロードとインストール
RUN wget http://download.proxmox.com/debian/pve/dists/bookworm/pve-no-subscription/binary-amd64/proxmox-auto-install-assistant_8.2.5_amd64.deb \
        -O proxmox-auto-install-assistant.deb && \
    dpkg -i proxmox-auto-install-assistant.deb

# /proxmox ディレクトリに移動
WORKDIR /proxmox

CMD bash
```

## イメージの作成
```bash:PC
$ docker build -t proxmox-auto-docker .
$ docker run --rm -it -v ./:/proxmox proxmox-auto-docker
```
```bash:Docker
$ proxmox-auto-install-assistant prepare-iso proxmox-ve_8.2-1.iso \
  --fetch-from iso --answer-file answer.toml --output pve-auto_8.2.1.iso
```

## インストールメディアの作成
作成された`pve-auto_8.2.1.iso`をUSBメモリ等に書き込んでインストールメディアを作成します。

## 起動
インストールメディアをインストール対象のサーバに接続して、ブート順位を変更するなどして"インストールメディアから"起動します。
すると、そこからは何も触らずにインストール&再起動が行われます。


# 参考文献

https://pve.proxmox.com/wiki/Automated_Installation
PythonでテキストファイルをPDFドキュメントに変換し、PDFページにテキストを描画する

テキストファイルは、軽量で編集しやすいという利点があるため、日常のテキスト記録やデータ交換によく使用されます。一方、PDFドキュメントは、高忠実度、フォーマットの安定性、優れた読書体験を備えているため、正式なレポートや文献の公開など、さまざまな場面で好まれています。テキストファイルをPDFに変換し、PDFにテキストを正確に描画することで、コンテンツの標準的な表示とパーソナライズされたレイアウトの両立を図り、ドキュメント形式に対するさまざまな場面の特定の要件を満たすことができます。この記事では、Pythonを使用して**TXTファイルからPDFドキュメントへの変換**を簡単かつ迅速に行う方法を紹介します。これにより、さまざまなドキュメント処理のニーズを満たすことができます。

- **[Pythonを使用してテキストファイルを読み込んでPDFドキュメントに変換する](#pythonを使用してテキストファイルを読み込んでpdfドキュメントに変換する)**

---
この記事で使用する方法には、[Spire.PDF for Python](https://www.e-iceblue.com/Download/Spire-PDF-Python.html)が必要です。これは、公式サイトからダウンロードするか、PyPIからインストールできます。`pip install Spire.PDF`。

[無料ライセンスを申請](https://www.e-iceblue.com/TemLicense.html)

---

## Pythonを使用してテキストファイルを読み込んでPDFドキュメントに変換する
テキストファイルからPDFドキュメントへの変換は、テキストを読み込んで、テキストコンテンツをPDFページに描画することで実現できます。テキストファイルは書式情報を保存していないため、描画時にテキスト書式をカスタマイズして、生成されたPDFドキュメントをニーズにさらに適合させることができます。

読み込みと描画プロセスに必要な主なクラスとメソッドは次のとおりです。
- **PdfDocument** クラス： PDFドキュメントモデルを表します
- **PdfTextWidget** クラス： 複数のページにまたがるテキスト領域を表します。
- **PdfDocument.Pages.Add()** メソッド： PDFドキュメントにページを追加します。
- **PdfTextWidget.Draw()** メソッド： 指定された位置にページにテキストウィジェットを描画します。

テキストファイルの内容をPDFページに描画する手順を以下に示します。
1. 必要なモジュールをインポートします。
2. **File.ReadAllText()** メソッドを使用して、TXTファイルからテキストを読み込みます。
3. **PdfDocument** インスタンスを作成し、PDFファイルにページを追加します。
4. PDFフォントとブラシオブジェクトを作成します。
5. テキストの書式とレイアウトを設定します。
6. テキストコンテンツを保持するために**PdfTextWidget**オブジェクトを作成します。
7. **PdfTextWidget.Draw()** メソッドを使用して、PDFページの指定された位置にテキストウィジェットを描画します。
8. **PdfDocument.SaveToFile()** メソッドを使用して、PDFファイルを保存します。
9. リソースを解放します。

**コード例：**
```python
from spire.pdf.common import *
from spire.pdf import *

inputFile = "サンプル.txt"
outputFile = "output/テキストからPDFへの変換.pdf"

# テキストファイルからテキストを取得
with open(inputFile, "r", encoding="utf-8") as f:
    text = f.read()

# PdfDocumentのインスタンスを作成
pdf = PdfDocument()

# ページを追加
page = pdf.Pages.Add()

# PDFフォントとPDFブラシを作成
font = PdfTrueTypeFont("Yu Mincho", 12.0, 0, True)
brush = PdfBrushes.get_Brown()

# テキストの配置と行間隔を設定
strformat = PdfStringFormat()
strformat.LineSpacing = 10.0
strformat.Alignment = PdfTextAlignment.Justify

# テキストレイアウトを設定
textLayout = PdfTextLayout()
textLayout.Break = PdfLayoutBreakType.FitPage
textLayout.Layout = PdfLayoutType.Paginate

# テキストの内容を保存するためのPdfTextWidgetのインスタンスを作成
textWidget = PdfTextWidget(text, font, brush)

# テキストのフォーマットを設定
textWidget.StringFormat = strformat

# ページ内の指定位置にテキストを描画
bounds = RectangleF(PointF(0.0, 20.0), page.Canvas.ClientSize)
textWidget.Draw(page, bounds, textLayout)

# 結果ファイルを保存
pdf.SaveToFile(outputFile, FileFormat.PDF)
pdf.Close()
```

**結果ドキュメント：**
![Pythonを使用してテキストファイルをPDFに変換](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/e5a46dc3-c849-23fb-fc59-001dc17c7a25.png)


この記事では、Pythonを使用してTXTテキストファイルをPDFドキュメントに変換する方法を紹介しました。これは、テキストコンテンツを読み込んで、新しいPDFドキュメントページにテキストコンテンツを描画することで実現されます。

PDFドキュメントの変換や操作に関するその他のヒントについては、[Spire.PDF for Pythonチュートリアル](https://www.e-iceblue.com/Tutorials/Python/Spire.PDF-for-Python/Program-Guide/Spire.PDF-for-Python-Program-Guide-Content.html)を参照してください。

使用中に問題が発生した場合は、[Spire.PDFフォーラム](https://www.e-iceblue.com/forum/spire-pdf-f7.html)で技術サポートを受けることができます。
How to setup wifi on RaspberryPi via Ubuntu CUI

# Overview

Just some random notes for setting up wifi on RaspberryPi so that I won't forget.

## Environment
- Raspberry Pi 4 Model B
- Ubuntu Server 20.04 LTS

## Setting Up
### Wifi-file
You can edit the wifi settings here.
```Terminal: Terminal
/etc/netplan/50-cloud-init.yaml
```
### Edit the file
```Terminal: Terminal
sudo nano /etc/netplan/50-cloud-init.yaml
```
The Terminal will show yaml file like this.
```Terminal: Terminal
# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        eth0:
            dhcp4: true
            optional: true
    version: 2
    wifis:
            wlan0:
                    dhcp4: true
                    optional: true
                    access-points:
                            "SSID":
                                    password: "Password"
```

Make sure you change the SSID and the password to your environment.

### Apply the network
```Terminal: Terminal
sudo netplan apply
```

### Confirm
Check if you got wifi on

```Terminal: Terminal
iwconfig
```
or this may do
```Terminal: Terminal
wifi-status
```
AKSノード追加時にポート不足で怒られた件(InvalidLoadBalancerProfileAllocatedOutboundPorts)

# はじめに
AKSにノードプール追加した際、エラーで怒られたのですが、ブログなどで記事投稿されている方があまりいなかったので、備忘として投稿します。

# エラー内容
既にsystemというノードプール(ノード数1)が存在するAKSに新たにsystem2というノードプール(ノード数2)を追加しようと'az aks nodepool add'を実行した際にエラーが発生しました。

```
(InvalidLoadBalancerProfileAllocatedOutboundPorts) Load balancer profile allocated ports 24000 is not in an allowable range given the number of nodes and IPs provisioned. Total node count 3 requires 72000 ports but only 64000 ports are available given 1 outbound public IPs. Refer to https://aka.ms/aks/slb-ports for more details.
Code: InvalidLoadBalancerProfileAllocatedOutboundPorts
Message: Load balancer profile allocated ports 24000 is not in an allowable range given the number of nodes and IPs provisioned. Total node count 3 requires 72000 ports but only 64000 ports are available given 1 outbound public IPs. Refer to https://aka.ms/aks/slb-ports for more details.
Target: networkProfile.loadBalancerProfile.allocatedOutboundPorts
```
LoadBalancerのポート数(24000)に対して、デプロイするノード数が多いよー!って怒られてますね。
実際にAKSのLoadBalancerを確認してみると…
ポート数は24000に設定されていますね。(※今回はQiita記事の為に敢えて24000という極端な例にしました。)

![LB.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3065056/cb233191-b95d-0850-9c4e-cc046c89dd38.png)

コマンドだと「az network lb outbound-rule list --resource-group [rg_name] -lb-name kubernetes -o table」で確認できます。

# いくつならデプロイできるの？
MS公式ドキュメントによるとクラスタごとにいくつのノードをデプロイできるのかは
**LBのエフェメラルポート数÷アウトバウンドポート数×送信IP数**で算出できます。
今回に当てはめれば以下の式ですね。
**64000÷24000×1=2.66666667**

なので、このクラスタにデプロイできるのは最大2ノードということですね。

https://learn.microsoft.com/ja-jp/azure/aks/load-balancer-standard#configure-the-allocated-outbound-ports

# おわりに
こういった仕様は実作業で経験しないと中々把握できないので、ありがたい？経験でした。
ロールモデルを決めて、人生近道しよう。

# はじめに
社会人になってから「ロールモデルを見つけるといいよ！」と言われたことがある人は多いんじゃないでしょうか。
でも、ロールモデルを見つけてどうすればいいのか、なんでロールモデルを見つけるといいのかを説明できる人は多くないと思います。僕自身、曖昧だったのでこちらの書籍を読んでみました！

https://www.mikasashobo.co.jp/c/books/?id=100297200

今回の記事では、ポイントをご紹介します。


# ロールモデルとは？
コトバンクで検索したところ「**自分にとって、具体的な行動や考え方の模範となる人物のこと。**」だそうです。
無意識で憧れる人の行動や考え方を模倣することは誰しもあるそうです。(アニメキャラに憧れて隻眼になったり、手に包帯まいたりするのも一種のロールモデルを見つけた結果なのかも…)


# ロールモデルを見つけると何がいいの？
書籍では20代で成長するために**近道**をしましょうと。

上司からパワポ資料作成をお願いされたとき、みなさんならどうしますか？
・**まっさらなパワポに1から自分でスライドレイアウトを考え、適切なフォントを設定し、内容を記載していく。**
・**部署内で共有されているテンプレートを拾ってきて、内容だけ書き込んでいく。**
後者でやったほうが、圧倒的に速いし、クオリティも担保されていますよね。

キャリア形成も当然同じでテンプレートがあるなら真似したらいいんです。それが**近道**です。
ロールモデルを活用してメリットとなるのは「**しなくていい努力はできるだけせず、本来するべき努力に時間を費やす**」ことができる点です。


# ロールモデルハック
書籍のタイトルになっていますが、この言葉は著者の造語です。
>**ロールモデルを「ハック」するというのは、ロールモデルの思考をそのまま「取り入れ」、ロールモデルの成功パターンをそのまま「再現すること」**

ロールモデルとあなたとの違いは**行動パターンと思考パターン**です。
つまり、この2つを真似することができれば、あなたもロールモデルと同じように成長できます。

ここで大事なのは**行動だけを真似する**のではなく、**思考を取り入れる**という点です。
スタイルいい女性が「朝は白湯を飲んでいる」と言ったからといって、その行動を真似するだけでは意味がありません。(結構やりがちですが…)
なぜ朝なのか。なぜ白湯を飲むのか。その行動に至った、思考を真似することが重要です。

# ロールモデルの見つけ方
>**ロールモデルを見つけるときに大切なのは、「その人がどんな生き方をしているのか」「その生き方にあなたがどれだけ共感できるか」です。**

そのために、以下の7つの項目を10点満点で採点し、バランスよく高い点がつく人を選びましょう。

**1.人生で大切にしたいこと**
**2.ライフスタイル**
**3.パートナーシップ**(生涯独身？家族を持ちたい？…etc)
**4.働き方**(会社員？経営者？チームで働く？個人戦？…etc)
**5.お金**
**6.健康**(睡眠、運動、食生活、休息…etc)
**7.プライベート**(友人は多い方がいい？休日はスケジュール埋まってないと嫌？…etc)

**合計値が高い人ではなく、どの項目も高得点な人が適しています**。↓

>**年収という観点からは目指していることと一致しても、その人のライフスタイルが朝から晩まで仕事漬けで、あなたがプライベートや健康も大切にしたいという考えを持っていることがあとでわかったら・・・
「私、こういうのは目指していないんだよね」と感じて、大きなギャップが生じてしまいます。**

ギャップがあると行動や思考パターンを受けいれるのが難しくなりますからね…


# 思考パターンをどうやって把握する？
行動パターンは観察すればある程度は模倣できそうですが、思考パターンは見ているだけでは難しいですよね。
アナログですが、**思考パターンを把握するにはロールモデルと直接関わりを持つことが大事です。** ともに行動し、行動の裏にある思考を聞いてみましょう。
「**なんでいつもコーヒー飲んでるんですか？**」
「**なんで商談の時はそのネクタイなんですか？**」
こういった些細なところに成功の秘訣や思考パターンの特徴があるので、どんどん聞きましょう。


# ロールモデルハックするうえで大切な5つ
**①素直さ**
…アドバイスを受け入れ実践できる素直さは大事です。

**②苦手を克服しない**
…苦手の克服はコスパが悪いし、嫌なことをやっても成長の見込みは少ないから得意な分野に注力しましょう。

**③言われたら「すぐやる」**
…「今は忙しいから」「もう少し勉強してから」ではなく、瞬発的に実行しましょう。スピードは本気度が伝わりますし、20代に求められるのはクオリティよりもスピードです。失敗したらまた高速でやり直せばいいのです。

**④やったら「すぐ報告」**
…おすすめのお店や映画を伝えた数日後に感想聞けたら嬉しくないですか？同様にアドバイスをすぐ実行し、報告をくれたらロールモデル側も当然嬉しいし、もっと教えてあげようってなりますよね。

**⑤さらに喜ばれることはなんだろう**
…ロールモデルとのコミュニケーションに限らず、大切なことです。
要は「言われていないことをやる」ってことです。これは相手の気持ち(思考)を想像する訓練になりますし、上手くいけばロールモデルとよりいい関係になれますよね。
居酒屋での気配りなんかがいい例です。「そろそろ次の飲み物注文するかな」、「取り皿いきわたってるかな」とかですね。

# 終わりに
いかがでしたか。ロールモデルと直接関わりを持たないといけないので、社内の人でロールモデルを見つけると試しやすそうですね。
ITエンジニアのキャリア構築について包括的に解説した書籍が発売されました！

📚新刊情報！
ITエンジニアのキャリア構築について包括的に解説した書籍が発売されました！

**タイトル：『ITエンジニア働き方超大全』- 就職・転職からフリーランス、起業まで**

大手電機メーカーに就職し数年のエンジニア経験の後、経営の道を志され独立した株式会社テックワークス代表の小野歩氏が、自身の経験をもとに、ITエンジニアとしてのスキルアップやキャリアの展望について、たくさんの実例から導き出した最適解を掲載しています。

🔍本書の特徴
・就職から転職、フリーランス、起業まで、ITエンジニアとしてのキャリアパスを網羅
・実例を交えた具体的なアドバイスを掲載
・ITエンジニアとしての実力を養うための方法や次のステップへの進み方を詳しく解説

これからエンジニアを目指す方や、キャリアをさらに広げたい方にとって必読の1冊です！
Amazonでのご購入はこちらから👇
https://www.amazon.co.jp/dp/4296070924/
Salesforce 認定Platformデベロッパー試験レポート

## Salesforce 認定Platformデベロッパー試験レポート
この投稿は先日「Salesforce 認定Platformデベロッパー試験」に合格しましたので、そのレポートになります。

### 【目次】
1．勉強法について
2．試験結果・感想
3．まとめ

### 1．勉強法について

勉強内容としては
- Trailhead(Trailmix)（公式）
- 模擬問題（非公式）

の2つで
個人での勉強だけでなく、社内の勉強会にも参加していました。

#### ①Trailhead(Trailmix)
Trailheadは以下のSalesforce公式のものを使用していました。

https://trailhead.salesforce.com/ja/users/welcome4/trailmixes/salesforce-platform-dev-1

文章だけでなくPlaygroundで実際にApexやVisualforceに触れてみることができる点がよかったです。
不明なワードが出てきたときや、Trailheadだけでは十分に理解できなかった際は開発者ガイドや他のWebサイトで随時確認していました。
また業務でSalesforceを使用しているため、実際の業務ではどのように使われているのかを確認したりもしていました。

社内の勉強会でもTrailheadを使用しており、デベロッパー資格保持者の方に解説していただきながら進めていました。

#### ②模擬問題（非公式）

模擬問題はweb上で検索した以下のものを3周取り組みました

[TysonBlog【Salesforce認定Platformデベロッパー】 試験対策：第1問](https://tysonblog-whitelabel.com/salesforce-dev-practice1)

全215問あり、全問解説付きのためとても分かりやすかったです。
試験ではこの模擬問題がそのまま出たり、似たような問題が多く出題されていたため取り組んでいてよかったです。


### 2．試験結果・感想

試験は105分で60問を解き、合格ラインは68％です。
**結果は「合格」で、正答率は以下表の通り約70％です。**
（単元ごとの問題数と結果得点は公表されないため、結果は計算により求めた想定値となります）
試験に使用した時間は**95分**程でした。内訳は40～50分ほどかけて一周解き、40～50分ほどかけて見直しをしました。

| 単元 | 配点（%） | 問題数（想定）| 得点率（％）|得点数（想定）|
|:-----------|------------:|:------------:|:------------:|:------------:|
| デベロッパーの基本 | 23| 14|71|10|
| プロセスの自動化とロジック |  30 | 18|83|15|
| ユーザインターフェース | 25 | 15|60|9|
|テスト、デバッグ、リリース| 22 | 13 |69|9|
| 合計 | 100 | 60|71|43|

内容としては、知識をそのまま聞いてくるのではなくシナリオがありそれに対して相応しい答えを聞いてくるものが多かったです。
上記のTrailheadと模擬問題で試験内容のほとんどをカバーできていて、完全に初見の内容の問題は1問のみでした。

感想としては、模擬問題と類似しているものが多かったにもかかわらず結構悩みながらの回答になってしまい、もっと知識を定着させる必要があると感じました。
結果は合格でしたがぎりぎりの合格のため少し悔しい結果となりました。

### 3．まとめ
昨年12月にアドミニストレーター試験を受験したため、Salesforce試験は今回で二度目なので前回の経験を生かして勉強ができたため自信を持って取り組むことができました。
Salesforce試験はしっかりした過去問が少なかったり、問題文が特殊だったりするため経験が重要だと感じました。

業務では宣言型よりプログラム型開発がメインのためデベロッパーは取得したいと強く思っていた資格のため無事合格できてよかったです。

今後は他のSalesforce試験にも続けて挑戦したいと思います。
元QAが開発チームにjoinして品質向上を試みたこと3選

## はじめに
どうも、元QAのエンジニア @Syahu_Writer です。

今回は、元QAが開発チームにjoinしてから行った品質向上のための施策について紹介していきます。
大なり小なりいろいろとやってますが、代表して以下3つを話します。
・開発プロセスの改善
・シナリオテストケーステンプレートの改善
・不具合の再発防止

## 開発プロセスの改善
以下は当初の開発フローを図に書き起こしたものです。
![スクリーンショット 2024-04-24 134904.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3565882/f83ac50c-bd8f-6aa8-27be-f34a2c27c480.png)
この図から読み取れる問題点はざっくりと、
・すべて直列のフローだが、並列処理にしていいものも混じっている
・テスト完了レビューといった、不要で実際に行われていないものがある
・レビューのタイミングが悪く、大きく手戻りが発生する箇所がある
という状態でした。

それを以下の通り修正しました。
![スクリーンショット 2024-04-24 134923.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3565882/2aaa1cea-aae1-2000-7b55-c7636f2b7c20.png)
・並列にして問題ないものは並列にする
・不要なプロセスは削除する
・手戻りが最小限となるようにレビューを設置する

また、開発フローでは表せていない、以下の問題点もありました。
・出荷日の前日にテストが終わる日程で計画されている
　→バッファが存在しないため、テストで問題が出た場合に出荷日やスコープの変更が発生する
・実際に出荷されるものを利用してのテストが一切されていない
　→テスト用のものと出荷物に乖離があった場合、気付くことができない
それらについても、
・出荷日の2営業日前に評価までを終わらせるように日程を変更し、バッファを持たせる
・評価者テストでは実際の出荷物を用いてテストを実施する
と変更を行いました。

開発フローの変更による効果測定は難しいですが
（変更以前の状況をほとんど体験していないので）、
バッファは年に数回利用していることから、
出荷日が予定より遅くなってしまうことや、
急に出荷物の中身を変えることによって発生し得る不具合を、
未然に防ぐ効果は出ているのではないかと思います。

## シナリオテストケーステンプレートの改善
先述した開発フローから察した方もいらっしゃるかもしれませんが、
私の所属している開発チームは全員フルサイクルエンジニアです。
自分たちで設計、開発し、
自分たちで評価、出荷し、
自分たちで質問、問い合わせの対応まで、
すべてを実施しています。

つまるところ、多くの開発者の方には馴染みが薄いかもしれませんが、
結合テストやシナリオテストも自分たちで行っています。
（開発フローに書いてある「評価者テスト」は「≒シナリオテスト」です）

シナリオテストの詳細は一旦置いておくとしても、
開発者が行う単体テスト等とは全くの別物だという認識はあるかと思います。
その通り、全くの別物であるのですが、私がjoinした当初は、
単体テストもシナリオテストも同じテンプレートで作成されていました。
初見時、誤って同じテンプレートを開いてしまったのかと目を疑いましたが、寸分違わず同じでした。

ということで実際のテンプレートや作成した詳細は省きますが、
手塩にかけて1からシナリオテスト専用のテンプレートを作成し、
それを運用しています。

## 不具合の再発防止
品質を向上していく上で最ももったいないことは、
・一度起きたことをもう一度起こしてしまう
・誰かが引っかかったことに他の人がひっかかる
です。
「似た不具合をやらないよう気を付けます」
は品質向上に寄与できません。
人は忘れる生き物ですし、疲れていたらすっぽ抜けるし、
その不具合が起きたのを他の人は知らないかもしれないし、
新しくjoinしてきた人は教えない限り100％知りません。

これを解決するには、
・ナレッジ化し、誰でも常に確認できるようにする
・開発プロセス上、必ず確認するようにする
ように整備しました。
特にミソなのは2つ目の「プロセス上必ず利用する」ことです。
作っても使わなければ、忘れ去られて廃れます。

ということで、
・コードレビュー用
・開発者テストレビュー用
・評価者テストレビュー用
の3つのナレッジを作成し、それぞれレビュー時に確認することを手順に含めました。
中身は、不具合をチェックすることのできる観点表になっています。

また、作成しただけでは、
「一度起きたことをもう一度起こしてしまう」
ことは防げません。
まずは自分で、各種レビューや不具合が発生した時に、
それを防げる内容をそれぞれに追記していきました。
自分たちが起こしたことでなくとも、
世の中で起きた不具合の話で応用できそうなものは、
随時取り込んでいきました。

さらに、
「不具合を発見できなかった≒ナレッジに観点が不足している」
ということですので、
不具合を発見次第、再発防止策を検討し対応するようプロセスを追加し、
その再発防止策の一端に「適切なナレッジに観点を追加すること」を含めています。
（もちろんナレッジ追加以外の手も取っています。）

これは結構目に見えて効果が出ていると実感することができます。
・自分でOKと思っても、レビューでナレッジを元に指摘される
・各種テストがナレッジを元に確認するケースが増える
・実際に過去出してしまった不具合を、レビューやテストで引っかけた
などなど、実際の数はカウントしていませんが、有用だったと感じています。

## まとめ
今回は、元QAな私が開発チームにjoinしてから試みたことを3つ、ざっくりと紹介させていただきました。
「今見えている地雷をまず撤去する」「マイナスを0にする」という
駆け出しタイミングで実施したことですので、
まだまだ、もっと良い手法があると思っています。

開発フローの各処理について細かく定義したり、
QA時代に実現できなかったテストケーステンプレートを作ったり、
再発防止策のいろんな例などなど、
紹介したい細かいことはたくさんありますが、
それはいつか折があれば書かせていただきます。
IT系に苦手意識のある未経験高卒がIT系に入社して1年が経った話。

## 目次
1\.この記事を書こうと思った理由
2\.高校時代の私
3\.苦手意識を感じる要因
4\.なぜITの道へ
5-1\.入社してから今まで
5-2\.アプリとインフラ
6\.終わりに

## 1\.この記事を書こうと思った理由
　なぜ私がこの記事を書こうと思ったかというと、
「IT系に苦手意識のある未経験高卒」が同期の中で私だけであったからです。
社会経験も技術的なITの経験や知識も0に等しい状態でした。
会社全体を通しても同じような方が多くいらっしゃるのか、少ないかはわかりませんが。

## 2\.高校時代の私
　私がIT系が苦手であることを証明する1つの情報として
　私の高校時代について記載いたします。
#### 高校
  商業系の学科
#### 学んだこと
簿記、表計算(Excel)、ビジネス文書・タイピング(Word)、マーケティング、経済と法
#### 部活動
華道部
#### 受験検定[受験回数]
青字：最終的に合格　太字：内容的に業務に役立っていると思うもの

***【全国商業高等学校協会主催試験】***
  　<font color="DarkBlue">簿記実務検定2級[1]
      　簿記実務検定1級(財務会計[3]/原価計算[1])
     　珠算電卓実務検定3~1級(普通計算部門[1(1級のみ2)]/ビジネス計算部門[1])
      　ビジネス文書実務検定3級・1級(速度部門[3級:1,1級:3]/ビジネス文書部門[3級:1,1級:2])
        　情報処理検定3級[1]</font>
    　**情報処理検定1級ビジネス情報部門[2]**
     　英語検定2級[1]・1級[2]
      　<font color="DarkBlue">商業経済検定(経済活動と法)[1]</font>
***【日本情報処理検定協会主催試験】***
    　<font color="DarkBlue">**情報処理技能検定試験　表計算1級[1]** 
     　情報処理技能検定試験　データベース1級[1]</font>    　
***【その他】***
　<font color="DarkBlue">秘書実務検定3級・2級[1]</font>
 　 **ITパスポート[4]**

## 3\.苦手意識を感じる要因
　私の検定受験遍歴を見て気づいた方もいるかと思いますが、
太字の検定の合格率が低いのです。
受験回数7回に対して**1回**しか受かっていません。
これが、私が苦手だと思う最大の原因です。


## 4\.なぜITの道へ
　では、そんな私がなぜSEになろうと思ったのかをお話しします。
 志した理由はたった1つです。

 ##### 「できたらかっこいいのでは？！？！」

 この一言に尽きます。

　
 　私には高校時代に仲の良かった数名が情報系の学科に通っていました。
  数人で集まって勉強すると、私以外はみんなはプログラミングや電気の話をします。
  当たり前ですが、私だけは友人たちが言っていることは全くわかりません。
  ですが、そんな中で思うようになったのが、
  #### 「商業しかわからない私がこれ理解出来たらかっこいいのでは？！？！？！」
  です。
  
  　そのころの私は、ちょうど進路にも悩んでいるところでした。
   そんな中で「友人と勉強」という日常にヒントをもらいました。
   そこから情報系を頑張っていきたいと思うようになり、
   情報系の資格取得にもチャレンジするようになりました。


## 5-1\.入社してから今まで
　入社してから今日まで私は劣等感を感じなかったことはありません。
 社会性のある大卒、技術・知識のある専卒・高卒の同期。
 そしてどちらもない私。
　こんな状況は比較して落ち込まずにはいられませんでした。
 受けると決めた段階で覚悟していた状況でしたが、
 実際にそうなると、どうにも悩んでしまうものでした。<br><br>


　私が今まで頑張れているのは、**コミュニケーション**と**学習方法**の
 おかげだと思います。
 　ここでは**学習方法**のほうをご紹介します。<br><br>


幸いにもこの会社は温かい人が多く、周囲の人柄に困ることはありません。<br><br>

 そこで、私が苦戦していたITの知識・技術を伸ばしていくためにしたことは <br><br>

**プチ授業とアウトプット** <br>
です。
私があまりにも理解できていなかったため、
過去の研修先で先輩が私にしてくれたことです。

この２つをすることで、自分の理解度の把握と向上、説明力の向上が見込めます。
以下に具体的な内容を記載します。<br><br>

**プチ授業**
 　先輩が業務の合間で、「これわかる？」と聞いてくださり、
  私がわかりませんと答えると、サイトを閲覧したり、図を描いたりしながら
  用語や構成について説明してくださいます。<br><br>
  
**アウトプット**
  　これはプチ授業での宿題成果発表のようなものです。
   先輩に毎週お題となるIT用語を提示していただきます。
   その用語について1週間後に先輩に説明します。
   　☆私は、「インターネットとは」「クラウドとは」を説明しました。
    　　1週間後の説明で合格できなかったので、さらに1週間後にもう一度説明しました^^<br>

特にアウトプットに関しては、自信もつきます。
説明に成功した時の達成感と自信感は、次のモチベーションにもつながります。

## 5-2\.アプリとインフラ 
　研修期間中にアプリ系の部署とインフラ系の部署を経験させていただいています。
その中で、「どちらのほうが難しいか」を問われることが多々あります。<br><br>

結論としては、インフラのほうが難しいと感じます。<br><br>

ですが、大差はありません。どちらも難しいです。<br>


　アプリは言語や設計書的なところで、自分の行ったことがすぐ形になるような部分で、
「何がわからないのか」や「どこがうまくいってないのか」も分かりやすく、
相談しやすいように感じました。


　インフラに関しては、ネットワークにおいても、サーバにおいても、
アプリよりエラーが起きたりした際は、切り分けが難しいように感じました。<br><br>

## 6\.終わりに
　分からないことだらけで、心が折れそうになることもありますが、
それでもここまで頑張ってこれたのは、温かくて優しくて、時に面白い先輩たちのおかげです。

　先輩たちのおかげでわからないなりに楽しくやれています☆
これからも頑張っていきたいです<br><br>

　先輩と仲良くなるのおすすめですよ^^♪
java オーバーロード

## オーバーロード
同じメソッドを複数のバージョンで定義すること
引数の数や型が異なれば同じ名前で定義することができる

#### 型が異なるオーバーロード
```Main.java
public class Main {
 // 1つめ addメソッド(int型)
 public static int add(int a, int b) {
  return a + b;
 }
 // 2つめ addメソッド(double型)
 public static double add(double a, double b) {
  return a + b;
 }
 // 3つめ addメソッド(String型) 
 public static String add(String a, String b) {
  return a + b;
 }
 public static void main(String[] args) {
  // 1つめ addメソッド(int型)が呼び出される
  System.out.println(add(5, 10));
  // 2つめ addメソッド(double型)が呼び出される
  System.out.println(add(10.5, 5.6));
  // 3つめ addメソッド(String型)が呼び出される
  System.out.println(add("Hello", "world!"));
 }
}
```
```結果.
15
16.1
Helloworld!
```
上から　`int型` , `double型`, `String型` と型が異なるため正しく呼び出される


#### 引数の数が異なるオーバーロード
```Main.java
public class Main {
 public static int add(int a, int b) {
  return a + b;
 }
 public static int add(int a, int b, int c) {
  return a + b + c;
 }
 public static void main(String[] args) {
  System.out.println("5+10=" + add(5, 10));
  System.out.println("5+10+15=" + add(5, 10, 15));
 }
}
```
```結果.
5+10=15
5+10+15=30
```
引数の個数が異なるため、2つのメゾットは区別され正しく呼び出される

#### メソッドのシグネチャ
メソッド宣言に記述されているメソット名、引数の個数、型、並びの情報をまとめて、メソッドのシグネチャという。（戻り値の型は含まれない)
【Salesforce認定アドミニストレータ試験】公式模擬試験の英日翻訳と図解解説 (5)

この試験を受けるための勉強をした際に思わぬ苦戦をしたので、英語公式模擬問題を翻訳しながら図解解説として整理しています。

今回（第5回）は、第4回に続き「ケース」に関する問題と解説です。


![スライド1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626902/986c36f7-8589-3c48-68f0-99f6a40d6d23.jpeg)

■ これまでの投稿

① 出題分野2：Object Manager & Lightning App Builder（オブジェクトマネージャとLightning アプリケーションビルダー）[出題率 20%]

　＜レコードタイプに関する問題＞

　　第1回の投稿　～レコードタイプと営業プロセスに関する問題～
　　https://qiita.com/Aungz/items/204d20c5c2c72a52c9df

　　第2回の投稿　～営業プロセスと選択リスト値に関する問題～
　　https://qiita.com/Aungz/items/5ecaa907ff6500924420

　　第3回の投稿 ～レコードタイプとページレイアウトに関する問題～
　　https://qiita.com/Aungz/items/37058a7e6cb4d59025c1

② 出題分野4：Service and Support Applications（サービス＆サポートアプリケーション）」[出題率 11%]

　＜ケースに関する問題＞

　　第4回の投稿 ～ケース割り当てルールに関する問題～
　　https://qiita.com/Aungz/items/f95c61038770a2445f93

　　第5回の投稿 ～ケース割り当てルールに関する問題～ （今回）
ハッシュについて

# 暗号学的ハッシュとは？
任意の長さのメッセージを、固定長のハッシュ値にマッピングするアルゴリズム。
## Hashに求められる要件
端的に言えば、以下の特徴を理解しておくことが重要。
### 決定性
同じメッセージからは必ず同じハッシュ値が得られる。
### 効率性
任意の長さのメッセージに対して、ハッシュ値を求める効率的なアルゴリズムが存在する。
### 現像計算困難性
hash値から元のメッセージを解読することが事実上不可能。一方向性関数が持つ性質に関連し、この性質を持たないハッシュアルゴリズムは（第一）現像攻撃に対して脆弱である。言い換えれば、ハッシュ値から元のメッセージを復元できてしまう。
### 弱耐衝突性
メッセージ$m_1$のハッシュ値$h = f(m_1)$が与えられた時、それと衝突するメッセージ$m_2$を発見することが事実上不可能。この性質は第二現像計算困難性とも呼ばれ、この特性を持たないハッシュアルゴリズムは、（第二）現像攻撃に対して脆弱である。このハッシュ値$h$は与えられたものであり、任意には選べない（後述：強耐衝突性との差）。
### 強耐衝突性
ハッシュ値$h$に衝突するメッセージ$m_1, m_2$を発見することが事実上不可能である。弱耐衝突性と異なり、ハッシュ値$h$は任意に選んで良い（任意に選べたとしても衝突する2つのメッセージを発見できないということ）。強耐衝突性のためには、弱耐衝突性に必要なハッシュ空間の倍の大きさが必要であることが知られている。
### 雪崩効果
メッセージが僅かにでも変わると、ハッシュ値が予測不可能な様式で大きく変更される。

## 用途
### パスワードハッシュ
ユーザに対してログインなどのパスワード認証を必要とするサービスは、ユーザの検証のためにパスワードを保存しておく必要があるが、これが平文で置かれていると当然まずい。このため、ハッシュ値を保存しておき、ユーザから送られてきたパスワードのハッシュ値と突合することでユーザを認証する。
### 事実を知っていたことの表明
AliceとBobが同じ問題を解くことを考える。AliceはBobに先んじて問題を解けたが、答えをBobに伝えず、自分はある時刻で答えを導いたと表明したい。
この時、AliceはBobに対して、Hashアルゴリズムと、(答え + nonce)のハッシュ値を送信する。この時点で、ハッシュ値からは元のメッセージが復元できないため、BobはAliceから受け取ったハッシュ化されたメッセージからでは答えがわからない。
その後、Bobが答えがわかったとAliceに表明したら、AliceはBobに対して答えとnonceを送信する。Bobは、Aliceから受け取った答えとnonceを事前に共有されていたハッシュアルゴリズム使ってハッシュ化し、Aliceからもともと受け取っていたハッシュ値と一致することを確認する。こうすることで、Bobは、Aliceが過去のある時点で確かに答えを導いていたと確認できる。
## 代表的なハッシュアルゴリズム

- SHA-256
- MD2
- MD5
MD2は脆弱性が報告されているものの、今でも公開鍵基盤として使用されている。
また、最近聞いた話だと、RTX4090を使えばMD5の8文字（半角英数）も1時間あれば解けてしまうとのこと。ブルートフォースなので、後述の誕生日攻撃であるはずだが、処理能力の向上は、Polynomialの壁を攀じ登りつつあるように思う(https://pc.watch.impress.co.jp/docs/news/1588850.html)
## 誕生日攻撃
鳩の巣原理的に、ハッシュ空間の大きさが$N$であるとき、$N+1$個のインプットを与えると、必ず衝突が起こる。しかしながら、確率論的には、インプットの数が$N+1$に到達するよりもはるかに前に、かなりの高確率で衝突が生じる。具体的には、$N$が十分に大きい時、平均的には$1.25\sqrt{N}$回の試行で衝突する相異なるメッセージ$m_1, m_2$を発見できる。極論、全てのハッシュアルゴリズムは誕生日攻撃に対して脆弱だが、計算複雑性が高すぎるために事実上不可能となっている。
よって、全てのハッシュアルゴリズムに対して要求されるのは、そのハッシュアルゴリズムの現像計算攻撃が、少なくとも誕生日攻撃よりも効率的なアルゴリズムが存在しないことである。
zshが~/.ssh/configに書かれているホスト名を補完してくれない

# 困っていること

Macのzsh 5.9で

```console
$ ssh <Tab>
```

とすると、~/.ssh/configに書かれているホスト名を補完してくれない。

ホスト名の一部を入力してからタブを押すと補完してくれる：

```console
$ ssh a<Tab>
→aで始まるホスト名が補完される
```

この事象はMacでのみ再現し、Linuxのzsh 5.9では再現しない。
zshの補完関数 `_ssh` `_ssh_hosts`は双方同一であることを確認済み。

# ワークアラウンド1

~/.zshrcに
```zsh
typeset -gUa _cache_hosts
# sshホスト名のリスト
_cache_hosts=(
  host1
  host2
  ...
)
```
のようにキャッシュをベタ書きすることで補完されるようになった。
`$_cache_hosts` は補完関数`_hosts`で参照される変数。

# ワークアラウンド2

トレースに

```
+_description:109> zstyle -a :completion::complete:ssh:argument-1:hosts fake match
```

と出力されているのを発見。_descriptionは`fake`スタイルに対応しているようだ。
もしやと思い、下記を書いてみたらできた（これも~/.zshrcにベタ書き）。

```zsh
zstyle :completion::complete:ssh:argument-1:hosts fake \
  host1 \
  host2
```

# ワークアラウンド3

~/.ssh/configからホスト名を抜き出すだけの機能の関数を自作。
`_ssh_hosts` という名前にしておけばシステムの_ssh_hostsファイルは読み込まれない。

```zsh
_ssh_hosts() {
  local -a _hosts
  _hosts=($(command sed -ne '/^\s*Host\s*/{ s/^\s*Host\s*//; p; }' ~/.ssh/config))
  _describe -t hosts 'Remote Hosts' _hosts
}
```

# 原因調査

`_complete_debug` ウィジェットでトレースを出力したところ、`ssh <Tab>`の場合は`_ssh_hosts`の11-12行目：

```
  _combination -s '[:@]' my-accounts users-hosts \
    ${opt_args[-l]:+"users=${opt_args[-l]:q}"} hosts "$@" && return
```
でreturnしており、その後の~/.ssh/config読み込み処理が実行されていなかった。
しかし_combinationが何をしているのか分からず、その先までは追えていない。
Google Cloud SDKをサクッとインストールする。

今回はタイトルの通り、Google Cloud SDKをサクッとインストールしていきます。備忘録としてお使いいただければ幸いです。

まず、以下のGoogle Cloud SDKドキュメントからパッケージをダウンロードします。Cloud SDK：https://cloud.google.com/sdk/docs/install-sdk?hl=ja
![スクリーンショット 2024-04-26 16.29.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/66a6a81f-d632-72a8-8722-8cd92f630572.png)
ユーザー>PC名>ここにzipファイルを移動して解凍します。
![スクリーンショット 2024-04-26 16.33.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/f203b8c4-3d51-4a2a-548a-559e8d47d1b5.png)
次に解凍したSDKを以下コマンドで実行します。
```
./google-cloud-sdk/install.sh
```
インストール前の質問が開始されます。
Do you want to help improve the Google Cloud CLI (y/N)? `という質問ではNを解凍し、以降yを選択します。
![スクリーンショット 2024-04-26 16.36.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/03675117-948b-7949-1d02-0d87f2d94d02.png)

Macのパスワードを入力します。
```
Running Python 3.11 installer, you may be prompted for sudo password...
Password:
```
インストール完了後、以下のコマンドを実行します。

```
source ~/.zshrc
```
gcloudコマンドが使えるようになれば成功です。
```
gcloud -v 
```
![スクリーンショット 2024-04-26 16.44.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/708ae2db-1471-5757-1097-7daf08e50336.png)
最後にcloud components update コマンドで、Google Cloud SDK のコンポーネントを最新の状態にアップデートします。
Eclipseのチュートリアル 2/3

前回記事の続いて、今回はEclipseのTomcatとの連携に関する内容を紹介します。
Eclipseのチュートリアル 1/3：https://qiita.com/siheng-zhou/items/cbb03d361e9d68aba623

## Tomcat サーバ用プロジェクトの作成
Eclipseを起動し、メニューバーの[file]⇒[new]⇒[other]とクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/3d96cf66-1bf4-ae5e-45d0-7225383bd4b9.png)
[server]⇒[server]と選択し、[next]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/83832ff9-6f62-3de0-d4fd-1dcfc380e670.png)
[Tomcat v9.0サーバー]を選択し、[next]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/45d02b9a-e0d1-afc5-86be-fc973a87ac12.png)

[name]と[Tomcat installation directory]を、以下の値を設定し、[finish]をクリックします。
name ： 任意のランタイム名 (後手順で使用します)
Tomcat installation directory ： tomcatのディレクトリー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/fa81bc72-870e-895f-3d42-0695a68942de.png)

## 動的 Web プロジェクトの作成
Eclipseのメニューバーの[file]⇒[new]⇒[other]とクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/4ffce538-4dad-1714-cdea-99492943a39d.png)

 [web]⇒[Dynamic Web Project]を選択し、[next]をクリックします。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/454f0d7a-3a9d-085f-560b-162e63aa95b4.png)

 [Project name]に、任意のプロジェクト名を設定します。
また、[Target runtime]は、前手順で作成したTomcatの設定のランタイム名を指定します。
※特に変更せず進めている場合は、[Apache Tomcat Localhost]となるはずです。
その後、[next]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/463cf539-c6d6-c9cf-9fbe-31f16cc37a1d.png)
[next]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/f2e99bd9-563a-bed6-af2c-f76e2fb4df1e.png)
⑤ [Generate web.xml deployment descriptor]のチェックがONになっていることを確認し、[finish]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/63fd1090-379b-0706-4bb4-e2e0b07810a1.png)
プロジェクトが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/69a08222-f4eb-34db-d9a0-0e06046df96e.png)

## プログラムの作成
作成されたプロジェクトの中に、「index.jsp」jspファイルを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/230ba827-8d15-05de-fc16-dc41c028ae47.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/34d47e34-ddd8-d9e9-5c17-a00cf325aee8.png)

作成した後、jspファイルにHelloWorldを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/3ebe5d73-70b3-bfc4-17fc-b2df7f9053e9.png)
保存します。
## プログラムの実行
プロジェクトを右クリックして、[Run As]⇒[Run on Server]とクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/3c8ead1f-7033-6d25-319c-96d8d9f611a4.png)

前手順で作成したサーバーを選択し、[finish]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/63e76a02-f8fc-a099-30af-c2b6d3554fa2.png)

サーバーが起動しましたと確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/fc2e12f4-1105-6570-7209-30610acb291c.png)
ブラウザから「http://localhost:8080」 と入力し、Webページが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717257/2fcb44b6-a4f3-34e8-cc82-5cd695d6d3a8.png)
PythonでPDFファイルのページ数を取得する

PDF文書を処理したり印刷したりする前に、まずその文書が何ページあるかを知る必要があることがある。Adobe Acrobatのようなツールを使ってページ数を表示することもできますが、プログラマーにとっては、スクリプトを書いてこのタスクを完了させる方が効率的です。
この記事では、Pythonを使ってPDF文書のページ数を素早く取得する方法を紹介します。

## サードパーティ・ライブラリのインストール
このタスクには、PythonプログラムでPDFファイルの操作と変換をサポートするライブラリ、[**Spire.PDF for Python**](https://www.e-iceblue.com/Introduce/pdf-for-python.html) が必要です。作業を始める前に、以下のpipコマンドでインストールできます：
```
pip install Spire.PDF
```

## PDFのページ数を取得する
**Pythonコード：**
```python
from spire.pdf.common import *
from spire.pdf import *
 
# PdfDocumentオブジェクトを作成する
pdf = PdfDocument()
 
# PDF文書を読み込む
pdf.LoadFromFile("contract.pdf")
 
# 文書の総ページ数を取得する
count = pdf.Pages.Count
 
# ページ数を出力する
print("PDFの総ページ数：", count)
 
# ドキュメントを閉じる
pdf.Close()
```
**出力結果**
![PdfPageNumber.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/b3ac5bef-9380-74a0-769d-d81cba1c19fe.png)

> Pythonを使ってPDFファイルを操作するための他の機能について知りたい方は、こちらをご覧ください：
https://www.e-iceblue.com/Tutorials/Python/Spire.PDF-for-Python/Program-Guide/Spire.PDF-for-Python-Program-Guide-Content.html
`sum()`関数の結果がfloatになるケースで、間違えて戻りの型を`int`にすると、mypyで「expected "bool"」というエラーメッセージが出た

# 環境
* Python 3.12.1
* mypy 1.10.0


# 何が起きたか

`sum()`の戻り値を`result*`という変数に代入しています。
`result*`という変数の型を間違えて`float`ではなく`int`にしたとき、mypyでは以下のエラーが発生しました。


```python:sample.py
result1_ok: float = sum([1.1, 2.2])
# mypy error
result1_error: int = sum([1.1, 2.2])

result2_ok: float = sum({"a":1.1, "b":2.2}.values())
# mypy error
result2_error: int = sum({"a":1.1, "b":2.2}.values())
```


```
$ mypy sample.py
sample.py:3: error: List item 0 has incompatible type "float"; expected "bool"  [list-item]
sample.py:3: error: List item 1 has incompatible type "float"; expected "bool"  [list-item]
sample.py:7: error: Argument 1 to "sum" has incompatible type "dict_values[str, float]"; expected "Iterable[bool]"  [arg-type]
```

3行目は、「listの要素の型は`float`ではなく`bool`を期待している」と言っています。
7行目は、「boolのiterableが渡されることを期待している」と言っています。
なぜboolが期待されているか分からなかったので、エラーの原因を突き止めるのに少し時間がかかりました。

# "boolを期待している"というメッセージはどこから来るのか
`sum()`関数は以下のstubを参照しているようです。

```python
# In general, the return type of `x + x` is *not* guaranteed to be the same type as x.
# However, we can't express that in the stub for `sum()`
# without creating many false-positive errors (see #7578).
# Instead, we special-case the most common examples of this: bool and literal integers.
@overload
def sum(iterable: Iterable[bool | _LiteralInteger], /, start: int = 0) -> int: ...  # type: ignore[overload-overlap]
@overload
def sum(iterable: Iterable[_SupportsSumNoDefaultT], /) -> _SupportsSumNoDefaultT | Literal[0]: ...
@overload
def sum(iterable: Iterable[_AddableT1], /, start: _AddableT2) -> _AddableT1 | _AddableT2: ...
```

https://github.com/python/typeshed/blob/48a68f521ee1cb23a2aea43951a5000d2600d824/stdlib/builtins.pyi#L1696-L1701


一番上の`sum()`関数は`def sum() -> int`になっています。この定義を見て`sum()`の戻りの型が`int`ならば、`sum()`の引数の型は`Iterable[bool | _LiteralInteger]`で、「`bool`を期待している」というエラーメッセージが表示されるのかもしれません。
詳しい原因は分かりませんでした。