OmniAICreator/Qiita-1.07M huggingface dataset:
AWS SAA 試験に1ヵ月で合格するために行ったこと

# 自己紹介
新卒1年目のエンジニアです。
現在オンボーディング中。
この記事では、SAAの合格に向けて行ったことを書きます。

# SAAの合格に向けて勉強したこと
## 前提
7/27にCLFを取得している。
8/30に試験を受けたが玉砕覚悟。（50%オフクーポンが2つなければやってません。）
## 学習教材
* Tech Stock
* AWSの基本・仕組み・重要用語が全部わかる教科書
* 図解　AWSの仕組みとサービスがたった1日でよくわかる
* Udemy
## 勉強時間
**37時間**
これは、Udemyの視聴と問題集を解いた時間の合計です。
Google カレンダーで記録しているので大体あっていると思います。
YouTubeのAWS Black Belt Online Seminarの視聴時間は計算していないので実際はもっと多いです。
## 学習の詳細について
基本的にTech Stockを中心に行いました。
方法としては、比較的新しい問題（SAA#170）から降順で取り組みました。
理由は、SAA#1などは、昔の方式らしく効率が悪いからです。
（勉強したての時は、これに気付いていないので、若い問題で間違えた問題は放置してあります。）
自分の学習履歴は、画像で貼っておきます。
一つ一つじっくりやったり、何周もしたので、総問題数は少ないと思います。<br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844843/01d319ea-6f94-4caf-1b13-78a69ee5b1db.png)


* AWSの基本・仕組み・重要用語が全部わかる教科書
* 図解　AWSの仕組みとサービスがたった1日でよくわかる
* Udemy

これらの学習教材は、知らない単語が出てきた時に使いました。
上から順番に調べたイメージです。
## 試験結果
752/1000 （合格点720）
# まとめ
勉強が苦手な自分でも継続して学習することで合格しました。
SAAを受ける人の参考になれば幸いです。
CSRFトークンで対策済のWebAPI を POSTMAN から呼び出す方法

# はじめに
CSRFの対策済のWebAPI をテストする場合に、POSTMAN からアクセス出来ないと不便なことが多いので
POSTMAN への設定方法と、なぜこの方法で動くのかを説明したいと思います。

# POSTMANの設定
忙しい人向けに、POSTMAN の設定から見ていきましょう

Tests タブに、レスポンス後にサーバから取得した CSRF トークンを保存する処理を記載します。
```
var xsrfCookie = postman.getResponseCookie("XSRF-TOKEN");
postman.setEnvironmentVariable("xsrf-token", xsrfCookie.value);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303235/f7fc8bfc-fc30-ef69-e859-bff36047413f.png)

続いてheader タブに、前回リクエスト時に保存した CSRF トークンを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303235/b81b8e56-b24c-ffab-6a5c-cee121a3d3f5.png)

以上で設定終了です。
良いポストマンライフを！

では続いて、どうしてこれで動くのか？
CSRF対策 って何？って人向けに解説をしていきます。

# CSRF対策とは

一言で言ってしまうと、正規サイト以外からのWebAPIアクセスを防止しようとする仕組みです。

https://www.ipa.go.jp/security/vuln/websecurity/csrf.html

対策を怠ってしまうと、悪意を持ってWebAPIを動かされてしまう原因になってしまいます。
実際過去にこんな事がありました。

https://ascii.jp/elem/000/000/063/63560/

## どうやって対策するの？

正規サイトへのアクセスがあった際に、CSRF トークン を発行します。
WebAPI を呼び出す際には、正規サイトで取得した CSRF トークンをリクエストに含めることで
正規サイトからのアクセスだと判断するようにします。

POSTMAN では、CSRF トークンを取得して、取得したトークンを次回のリクエストで送信するようにしています。
[Tips]chef-td-agentで自作のpluginを利用する

[chef-td-agent](https://github.com/treasure-data/chef-td-agent)で、fluent-plugin-bigqueryの最新バージョンを使うために、chef-td-agentの記述で下記のように記述していたとします。


```ruby
name "base"
description "base server role."
run_list(
  "recipe[apt]",
  "recipe[yum]",
  "recipe[td-agent]",
)
override_attributes(
  :td_agent => 
    plugins: [
      { 'bigquery' },
    ],
  }
)
```

基本的に、pluginなどは正式にリリースされたものを利用するのが普通ですが、バグ修正や新機能をリリースより先に取り込みたいケースがあります。
その場合、自分で用意したソースコードを使用することになりますが、それには少々工夫が必要です。
いくつか方法はありますが、今回は`source`オプションを使って解決します。

## 手順
大まかには2ステップです。

- gemをビルドする
- ビルドしたファイルを読み込む

### gemのビルドする

やることは単純で、利用するgemに対してbuildコマンドを行うだけです。
例として、[fluent-plugin-bigquery](https://github.com/fluent-plugins-nursery/fluent-plugin-bigquery)　をビルドする場合は下記のようなコマンドになります。

```shell
gem build fluent-plugin-bigquery.gemspec
```

実行すると、`fluent-plugin-bigquery-3.1.0.gem`というバイナリが作成されます。3.1.0はfluent-plugin-bigqueryの執筆時点でのバージョンが3.1.0であるためです。

### ビルドしたファイルを読み込む

作成したバイナリファイルを使うように設定を書き換えます。バイナリファイルを`/tmp`に置いた場合下記のようにします。

```diff_ruby
name "base"
description "base server role."
run_list(
  "recipe[apt]",
  "recipe[yum]",
  "recipe[td-agent]",
)
override_attributes(
  :td_agent => 
    plugins: [
-      { 'bigquery' },
+      { 'bigquery' => { 'source' => '/tmp/fluent-plugin-bigquery-3.1.0.gem' } },
    ],
  }
)
```

`source`オプションを使うことで、gemをダウンロードするのではなく、オプションで指定したファイルを使います。
これにより、Chefで自作のfluentdのpluginを使えます。
PythonでAzure ADのIDトークンを検証する

## はじめに

案件でAzure ADが発行するIDトークンの検証をしたい・・・！となりましたが、全く見当もつかず困りました。
そんな時、社内の方に検証方法を教えていただき実現できたので、備忘も兼ねて共有させてください。

## 結論

Microsoftが提供している公開鍵を使用してIDトークンの検証が可能です。
[https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration](https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration)にアクセスすると公開鍵を取得できるURLが`jwks_uri`に記載してあり、このURLから公開鍵をJSONで取得可能です。

:::note warn
- 公開鍵は24時間で更新されるため、一度ダウンロードして恒久的に使用することは不可なのでご注意ください。
- IDトークンは`v1.0`と`v2.0`の2種類バージョンが存在し、公開鍵のURLも異なりますので、検証したいIDトークンのバージョンに応じて使用するURLを判断してください。（今回は`v2.0`を使用）

参考URL：https://learn.microsoft.com/ja-jp/azure/active-directory/develop/access-tokens#validate-tokens
:::

## 使用した環境

- Python・・・`3.9`
- PyJWT・・・`2.8.0`
- requests・・・`2.31.0`
- cryptography・・・`41.0.3`

## 実装

### ライブラリ

必要なライブラリをインストールします。

```shell:実行コマンド
pip install requests pyjwt cryptography
```

`requests`は公開鍵を取得するHTTPリクエスト送信に使用、`PyJWT`、`cryptography`はIDトークンの検証に使用します。

###  ソースコード

```python:main.py
import jwt
import requests
from jwt.algorithms import RSAAlgorithm
# 検証したいIDトークン
token = "XXX"
# Azure ADのクライアントID
client_id = "XXX"

# 1.公開鍵の一覧を取得
key_url = requests.get("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration").json()["jwks_uri"]
keys = requests.get(key_url).json()["keys"]

# 2.IDトークンの署名を検証する公開鍵を抽出
header = jwt.get_unverified_header(token)
for key in keys:
    # kidが一致している公開鍵を抽出
    if key["kid"] == header["kid"]:
        public_key = jwt.algorithms.RSAAlgorithm.from_jwk(key)
        break

try:
    # 3.IDトークンを検証
    decoded_token = jwt.decode(
        token,
        public_key,
        audience=client_id,
        algorithms=["RS256"]
    )
    print("有効なIDトークンです")

# 検証に失敗した場合
except jwt.exceptions.InvalidTokenError as e:
    print("不正なIDトークンです")
    print(f"Error詳細:{e}")
```
下記流れでIDトークンの検証を実施します。
1. Microsoft提供のURLにHTTPリクエストを送信し、公開鍵の一覧を取得
2. 公開鍵の一覧からIDトークンと`kid`が一致する公開鍵を抽出
3. IDトークンを検証し、有効かチェック（引数`audience`はAzure ADのクライアントIDを指定）

検証に失敗した場合、`InvalidTokenError`が発生するため`try-except`句で検知可能です。

:::note info
Azure ADのクライアントIDは使用するADアプリの下記項目をコピーしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178305/a46d6643-2f23-c951-83b0-43feeeb2d165.png)
:::

## 動作確認

作成した`main.py`を実行して有効、不正なIDトークンを検証できるかそれぞれ確認してみましょう！

### 有効なIDトークン

```shell:実行結果
python main.py
有効なIDトークンです
```

### 不正なIDトークン

#### 改ざんしたIDトークン

```shell:実行結果
python main.py
不正なIDトークンです
Error詳細:Signature verification failed
```

#### 有効期限が切れたIDトークン

```shell:実行結果
python main.py
不正なIDトークンです
Error詳細:Signature has expired
```

それぞれ適切に検証されていますね！
不正な場合は署名の改ざんだけではなく、有効期限切れも検知可能です。

:::note warn
Azure ADが発行するIDトークンの有効期限は1時間です。
参考URL：[https://learn.microsoft.com/ja-jp/azure/active-directory/develop/id-tokens](https://learn.microsoft.com/ja-jp/azure/active-directory/develop/id-tokens)
:::

## おわりに
Azure ADのIDトークン検証方法を紹介させていただきました！必要に応じて活用いただけますと幸いです。最後までご覧いただきありがとうございました！
Ansible使ってSBOMのようなものを作った話

# はじめに
2022年1月に apache log4j 脆弱性に関するニュース が世間を賑わせました。
  
弊社も例外ではなく対応に奔走することになりましたが、実は影響範囲の特定に関しては非常にスムーズに実施する事が出来ました。
今回はその立役者である、弊社内で独自に設計構築した Ansible を利用した構成情報収集ツールを紹介しようと思います。

::: note
本ツールの設計・実装は 2021年末頃の話になります。
:::

# ツール開発の発端
情報セキュリティ対策の一つとして脆弱性対応は重要であり、システムの構成情報を把握しておく事はその前提となります。
しかし、弊社内ではシステムの大まかなアーキテクチャやサーバーOSなどは認識していても、導入されているパッケージの全量やライブラリの情報までは把握しきれてはいませんでした。

設計書は存在し、そこに記述があっても最新化されているかが不明であり、いざ脆弱性情報を拾っても「そもそも我々のシステムは対象なのか」「我々のシステムに導入されているパッケージやライブラリのバージョンは脆弱性に該当するのか」という点の確認をシステムベンダに頼らざるを得ず、初動対応に時間がかかっていました。

こういったところから、システム構成情報を収集し可視化するツールの必要性があったのです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1734719/34f03b0c-94da-8841-7810-bb6f7d243edd.png)




# 構成情報収集ツール概要
システムに導入されているパッケージや利用されているライブラリ情報は可視化と管理が難しいと以前から感じていました。設計書やパラメーターシートに記載する事は簡単でも、その管理は誰がするのか、パッケージやライブラリがアップデートされた時に誰が更新するのか、正しく最新化できているのか、といった問題が付きまといます。

そのあたりを解決する一手段として SBOM（Software Bill of Management）と言われる製品も存在しており、活用されているのかと思います。
しかし、製品導入となると見積もりを取り、PoCと共に製品選定を行い、決裁をとり…と、どうしてもスピード感が落ちてしまいます。

そこで弊社では、弊社なりに必要となる構成情報を定義し、それを収集し、一覧化するツールを独自に作成し、定期的に実行させています
Infrastructure composition Management（通称：ICM）と呼称しており、その構成は以下の様になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1734719/2cab6be8-028d-c2f8-c21b-4629d9865b79.png)




- 構成情報の収集はAnsibleで実装し、OSのクーロンで週次実行しています
- 収集した情報はICMサーバー上で加工して S3 に格納しています
- S3にあるファイルをQuickSightで可視化しています

 　
Ansible採用の理由としては

- コーディングが非常に容易である事
- エージェントレスで実装出来る事

という点で、非常にスピーディに且つ既存システムへの影響少なく実装できました。


# 収集している情報
- サーバー情報（ホスト名、OS情報、AWSリージョンなど）
- インストールパッケージ
- 共有ライブラリ
- ユーザー/グループ情報
- NW情報（IPアドレス、リスンポート等）

など


# どんな風に見えるの？  
画面の一例ですが、このような形で一覧化しています
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1734719/5be4f392-d2ff-4be3-16aa-a1e53ed24a68.png)



# Ansibleのスクリプト
実際に動いているスクリプトですが、例としてインストールパッケージ情報を取得するplaybookを以下に記載します。
  
::: note warn
スクリプト内にある特定の文字列は **** でマスクしております
:::

  
``` python
- name: Get packages from hosts file
  hosts:
    - servers
 
  tasks:
    - name: Get packages
      package_facts:
        manager: auto
      become: false
      ignore_errors: yes

# ansible template module で jinja2 file を target 側で実施する形でパッケージ取得
    - name: Output packages
      template:
        src: ../tmp/package.j2
        dest: "/home/****/result/{{ inventory_hostname }}/packages"
        mode: '0644'
      delegate_to: localhost

# 取得したFileのJsonへのパース
    - name: parse result to json
      command: '/home/****/shell/parse_json_package.sh {{ inventory_hostname }}'
      delegate_to: localhost

# サーバー側に作成される一時ファイルの削除
    - name: delete temporarily result file
      shell:
        cmd: "rm /home/****/result/{{ inventory_hostname }}/packages"
        warn: false
      delegate_to: localhost
```

# 今後について
現在の状況でもある程度の要件を満たしてはいますが、まだまだ使いづらい点はあります。
今後は検索機能の追加であったり、収集情報の追加、更に収集した構成情報や設定ファイルの意図しない変更の検出などをゆっくりと実装していければと思っています。
　
　
　
　

CCoE　西村
海外FX業者のEAについて徹底解説


## MT4とMT5のプログラムは違う
MT4とMT5はメタトレーダー社が提供する取引プラットフォームで、EA（Expert Advisors）を動かすために必要です。

しかし、MT4とMT5は互換性がなく、それぞれ専用のプログラム言語（MQL4とMQL5）で動作します。

MT4は長らく主流であったため、MT4専用のEAが多いですが、MT5の普及とアップデートが進んできています。

MT4とMT5両方で動作するEAも存在しますが、まだ少ない。MT4の利用が将来的に終了する可能性があるため、MT5のEAを探すことが推奨されます。

そして、EAを海外のFX業者で使用する際には、信頼性とライセンスを確認して選ぶべきです。特に、「XMTrading」とは厳格な英国FCAライセンスを取得しているため、信頼できる業者とされています。

なお、海外FXのEAを利用する際は、兼業トレーダーがおすすめです！

## 兼業トレーダーをおすすめする理由

FXトレードをするにはまず「専業」または「兼業」という選択肢がでてきます。

兼業トレーダーは精神的にも専業トレーダーに比べて安定性が違います。

兼業トレーダーの場合はプライベートや遊びなどを優先することができ、FXトレーダーにありがちな夜中まで張り付いて取引する必要がなく、自分のライフスタイルの範囲でトレードをすることができます。

専業の場合は、兼業よりも生活費などを稼ぐために無理をして取引しなければいけない場面があり、精神状態が悪い状態で取引をしても上手く稼ぐことはできません。

また、兼業の場合は既に他の仕事をしており、収入がある程度安定しています。そのため、万が一トレードが上手くいかなかった場合でも、生活に支障がでることは少ないと言えるでしょう。

兼業の場合は余ったお金などでやりくりできるため、マイナスは少ないです。

専業の場合は稼いだ額が全て生活費になるため、トレードをするにはその生活費の一部を使わなければいけません。
そのため、必要以上にお金を使ってしまったり、勝てる取引でもお金を使うことをためらってしまう場合があります。

このように、専業と兼業では投資する額が一緒でも精神的に安心できるのは兼業トレーダーになります。

FX取引では知識や経験ももちろん大切になりますが、安定した精神状態で取引を行うことも同様に大切になります。

専業トレーダーの場合は稼げたらラッキーくらいの気持ちで取引を行えるため、精神状態も良いと言えるでしょう。

投資の初心者は約9割の人間が負けていると言われています。

そのため、FX一本で成形を立てている場合は、今日稼げても明日は稼げないかもしれないと思い、毎日FXのことだけしか考えることができません。

先ほども説明しましたが、精神状態が追い詰められている状態でのFX取引はおすすめしません。
そのため、精神状態が比較的安定している兼業トレーダーをおすすめします。

## ゆくゆくは専業トレーダーに

ＦＸ取引である程度稼げるようになった場合、今している仕事をやめて専業トレーダーになりたいと考えている方も多いのではないでしょうか？

近年若い人を中心に、早期リタイアの「ＦＩＲＥ」が注目を浴びています。

ＦＩＲＥとは、経済的に自立し、早期リタイアすることを言います。

このＦＩＲＥに憧れてＦＸや株などに手を出す方が増えてきています。

早期リタイアして、後は自分の好きなことに時間を使いたいと考える方は多いでしょう。

そのため、今の仕事をやめて専業トレーダーになるにはまず兼業トレーダーになることが大切です。

先ほども紹介した通り、いきなり仕事をやめて専業トレーダーになるのはとても危険です。

多くの資産を持っているからといって、仕事をやめてＦＸトレードに専念してしまうと、今まで貯めていた貯金が全て無くなってしまうこともあり、安心できません。

また、どれだけＦＸトレードをしていても、ある程度稼ぐことができなければ世間一般からすると無職同然に思われてしまうこともあります。

別にそれでもいい！と思っている方は良いと思いますが、いきなり専業トレーダーになるにはそれなりの覚悟が必要となります。

安定して専業トレーダーになるにはまず確実に投資の知識や経験を積むことが大切になります。

また、お金が発生している以上どうしてもプレッシャーを感じることが多いです。兼業トレーダーの場合は専業トレーダーよりもプレッシャーを感じることが少ないため、本来のトレードスタイルを貫くことができます。

兼業である程度取引実績や自信を付けていないと、一気に負けがあなたを襲ってくる場合があります。
焦る必要はありません。

ＦＸは今しか稼げないことはありませんので、確実に着々と知識や経験を付ける必要があります。

### 兼業である程度の実績と資金を作る

ＦＸトレーダー専業になるには、自分で戦える手法やロジックとある程度まとまった資金が必ず必要になります。
もちろん、海外ＦＸ業者などで少額の資金をハイレバレッジで設定して何百倍もの利益を得ることもできます。
しかし、都合よく毎回毎回取引がうまくいくわけではありません。

専業トレーダーになるにはトレーダー資金といった生活費や生きるための最低限のお金が必要となります。

仮に、専業トレーダーでやっていけなくなったとしても、半年ほど生活できる資金があれば、その間にアルバイトや就活をすることもできます。

本気で今の生活から抜け出し、ＦＸ専業トレーダーを目指したいのであれば、目の前のお金だけでなく、ＦＸ取引による資金が尽きたことも想定してチャレンジしていかなければいけません。

このように、専業トレーダーになるにはある程度まとまった資金と本気で取り組む覚悟が必要になります。

ＦＸは少ない資金を何百倍、何千倍にすることができますが、その分リスクもありますので、しっかりと実績や知識を付けたから専業トレーダーを目指しましょう！

海外FXであれば、[海外FX ボーナスを徹底比較！](https://www.operafairbanks.org/kaigaifx-bonus/)を参考にして口座開設することで、口座開設ボーナスをタダでもらえます！自己資金なしで取引ができるので、まずは海外FX業者を利用してみてはいかがでしょうか。
AutoKeras Install 備忘録

# 概要
少し古いがAutoKerasを使ってみたかったのでインストールについて備忘録に残す。
さらっと調べた感じAutoKerasはENAS (Efficient Neural Architecture Search)という探索アルゴリズムを使いNeural Networkの最適化を行ってくれるパケージのよう。
ENASのpaperにはRNNやLSTMへの適用についても記載されているので、時系列系NN modelの精度改善も期待できる。


- 実施期間: 2023年8月
- 環境：Ubuntu20.04LTS
- GPU: GeForce RTX3070
- Python: condaのPython3.9

## 1.TensorFlow
[AutoKerasのオフィシャル](https://autokeras.com/install/)によるとTFが予め入っていることを前提にしているように読めるので、AutoKerasインストールの前にTFをインストールする。
下記公式サイトの「3. conda環境を作成する」以降を実行する。
AutoKerasの要件よりcondaの仮想環境はpython=3.9で作成する。

https://www.tensorflow.org/install/pip?hl=ja#step-by-step_instructions

仮想環境のactivate後、conda listでpipが見当たらなければ下記を行う。

```terminal
conda install -c conda-forge pip
```

上記公式サイトの最後で下記を実行することになっており、現時点では2.13.0が入る。

```terminal
pip install tensorflow==2.13.*
```
:::note info
AutoKerasだけをインストールするとGPUを使ってくれなかった。
:::

:::note info
TF単体のインストールの場合、`conda install -c conda-forge tensorflow`コマンドでインストールする。cuda関連も自動で仮想環境に入れてくれるからだが、AutoKerasとの相性が悪いのかfit()で大量のエラーを吐いたので上記の方法でインストールした。
:::

## 2. AutoKeras

https://autokeras.com/install/

つまり、
```terminal
pip install git+https://github.com/keras-team/keras-tuner.git
pip install autokeras
```

:::note warn
頻繁にメンテナンスわれているのかわからないがAutoKerasのインストール中でも最新版の同TF 2.13.0を入れようとする。今回はバージョンが同じなので先に入れたTF 2.13.0はアンインストールされなかったが、今後AutoKerasについているTFのバージョンが2.14以上になった場合、そのTFが正しく現行のcudaで動作するか不安。
:::



## 3. 動作確認

https://autokeras.com/tutorial/image_classification/

つまり、

```python
import numpy as np
import tensorflow as tf
from tensorflow.keras.datasets import mnist

import autokeras as ak

(x_train, y_train), (x_test, y_test) = mnist.load_data()
print(x_train.shape)  # (60000, 28, 28)
print(y_train.shape)  # (60000,)
print(y_train[:3])  # array([7, 2, 1], dtype=uint8)

# Initialize the image classifier.
clf = ak.ImageClassifier(overwrite=True, max_trials=1)
# Feed the image classifier with training data.
clf.fit(x_train, y_train, epochs=10)


# Predict with the best model.
predicted_y = clf.predict(x_test)
print(predicted_y)

# Evaluate the best model with testing data.
print(clf.evaluate(x_test, y_test))
```

GPUを使っているなら1epochは5秒程度のはず。fit()中、別ターミナルで`nvidia-smi`コマンドでGPUメモリ使用量を確認してもOK。


### 番外　Windowsへのインストール
流れは上記のUbuntu向けと同じ。
下記のWindows向け手順に沿うこと。

https://www.tensorflow.org/install/pip?hl=ja#step-by-step_instructions

AutoKerasと関係ないが、VSCodeでconda仮想環境をインタプリタに選択し実行するとPowerShellがターミナルとして起動し、condaコマンドを知らないとエラーを吐く。
**「conda：用語 'conda'は、コマンドレット、関数、どうのこうの…」**
確かにconda仮想環境の設定はcommand promptで行ったため、PowerShellはcondaを認知していないだろう。

解決方法は[ココ](https://toonrobotics.com/vscode_anaconda_2022_8_27/)に書かれているが、
Anacondaのcommand promptで下記を実行

```terminal
conda init powershell
```

管理者権限でPowerShellを起動し、

```terminal
Set-ExecutionPolicy RemoteSigned
```

これでVSCodeで起動するPowerShellはcondaを認識するようになる。

以上
Javaで「クラスを利用してみる」の動作を確認してみた

# 概要
Javaで「クラスを利用してみる」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/start/about/index3.html

# 実装
以下のファイルを作成しました。
```CTest1.java
class CTest1{
  public static void main(String args[]){
    Television tv1 = new Television();
    Television tv2 = new Television();

    tv1.setPlace("居間");
    tv2.setPlace("寝室");

    tv1.setChannel(1);
    tv2.setChannel(8);

    tv1.dispChannel();
    tv2.dispChannel();
  }
}

class Television{
  int channelNo;
  String place;

  void setChannel(int newChannelNo){
    channelNo = newChannelNo;
  }

  void setPlace(String newPlace){
    place = newPlace;
  }

  void dispChannel(){
    System.out.println(place + "にあるテレビの現在のチャンネルは " +  channelNo + " です");
  }
}
```
以下のコマンドを実行しました。
```
$ javac CTest1.java 
$ java CTest1 
居間にあるテレビの現在のチャンネルは 1 です
寝室にあるテレビの現在のチャンネルは 8 です
```

# まとめ
何かの役に立てばと。
Spring Boot + Maven のチーム開発プロジェクトをEclipseでスタートする

# やりたいこと
- EclipseでSpring Boot + Mavenのプロジェクトを作成したい
- Gitでバージョン管理できる状態にしておきたい

# 1. 事前準備
[Pleiades All in One ダウンロード](https://mergedoc.osdn.jp/)から、JavaのIDEであるEclipseをダウンロードしておきましょう。また、[Git Bashをダウンロード](https://gitforwindows.org/)するなりして、Gitを使える状態にしておき、[GitHub](https://github.com/)にも登録を済ませておきましょう。

# 2. リモートレポジトリの作成とバージョン管理環境の整備
## 2.1. GitHubでリモートレポジトリを作る
ログインした後の[GitHub](https://github.com/)上で、ヘッダー右側にあるプラスマークから、[**New repository**]をクリックします。好きなレポジトリの名前を入力し、PublicかPrivateを選んだら、そのまま下部の[**Create repository**]でレポジトリを作成してください。

## 2.2. ローカルにクローンする
自分のわかりやすい場所で、`git clone <作ったリモートレポジトリのURL>`をしてください。これを行うことで、リモートで先ほど作ったレポジトリがローカル上で利用できるようになります。

`git clone`したローカルのディレクトリ上で、リモートレポジトリの名前と同じディレクトリが新しく生成されていたら完了です。

## 2.3. .gitignoreを作成する
クローンしたディレクトリに`cd <ディレクトリ名>`をして入ります。
このディレクトリ内に、`.gitignore`という名前のファイルを新しく作ります。作ることができたら、[このページ](https://gist.github.com/fedir/cd58012d42c8c1edbb3fff611de6c2f6)にある`.gitignore`の内容をファイル中にコピペしてください。
- [GitHub - fedir/.gitignore](https://gist.github.com/fedir/cd58012d42c8c1edbb3fff611de6c2f6)

これは、これから作成するプロジェクトをバージョン管理する上で必要となる`.gitignore`(バージョン管理の対象外とするファイル群を示したもの)です。

ディレクトリ内で`git status`して、`Untracked files`の中に赤字(デフォルト色)で`.gitignore`が追加されていればOKです。

## 2.4. 一旦pushしておく
このタイミングで一旦、ローカルの変更内容をリモートにも反映させておきます。以下の手順でやってみましょう。

```Bash
# すべての変更内容をステージする
git add .

# コミットする
git commit -m ".gitignoreを追加"

# リモートにpushする
git push

```

GitHubに戻って、作ったレポジトリの中に、`.gitignore`が追加されていれば完了です。


# 3. Eclipseでプロジェクトを作成する

## 3.1. Eclipseを開く
インストール済みのEclipseを開きます。ランチャーが立ち上がったら、デフォルトのワークスペースを選択したまま、[**起動**]します。

Eclipseのウィンドウが立ち上がったら完了です。

## 3.2. Spring スターター・プロジェクトを作成する
Eclipseの上部メニューバーから[**ファイル**]→[**新規**]→[**その他**]と進みます。出てきたダイアログウィンドウで、「Spring」で検索し、[**Spring スターター・プロジェクト**]を選択しましょう。

いくつか設定を行います。まず、[**デフォルトロケーションを使用**]のチェックを外します。そうすると、プロジェクトの保存先を自分で指定できるようになるので、前のセクションで作ったディレクトリを参照するようにします。また、[**タイプ**]に関しては、今回はMavenを選択します。済んだら、[**次へ**]を押して、初期設定での依存関係を定義していきます。今回は、デフォルトでチェックがついているものに加えて、[**H2 Database**]と[**Thymeleaf**]をそれぞれ選択しておきましょう。(もちろん後から必要に応じて消すことも、追加することもできます。)

[**完了**]をおすことで、[**プロジェクト・エクスプローラー**]に作成したプロジェクトが表示されたらOKです。試しに、プロジェクトを右クリックして、[**実行**]→[**Spring Bootアプリケーション**]してみると、プロジェクトが始動します。ここで、[http://localhost:8080/](http://localhost:8080/)にアクセスしてWhitelabel Error Pageが表示されれば、エラー画面ではありますが、Spring Boot自体は立ち上がっています。

## 3.3 リモートにpushする
他のプロジェクトメンバーが作業可能な状態にするために、リモートにプロジェクトをpushしておきましょう。さっき作ったディレクトリで、`git add`から`git push`までを行ってください。
【RHEL9】日本語を設定したのに、日本語入力できない場合

RHEL9.2を、RedHatの手順通りにインストールしていたら、日本語入力で地味に詰まったので、備忘録として残す。
# 何が起きたか？
- RHEL9.2のOSをインストール時に、キーボード設定でjpを設定。
- インストール後に「設定」から、Region & Languageでそれぞれ日本(語)に設定。
- 同様に「設定」から、Keyboardで入力ソースを日本語に設定。
- 実際にGUIは、日本語で表示されている。

**なのに、Shift & Spaceしても、日本語入力に切り替わらない！**

# 解決方法
結論としては、下図のように「設定」の「Keyboard」の入力ソース「日本語」がダメだった。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3431251/a29c1315-6057-5a86-33a3-2537b6989b9f.png)

入力ソース下の「＋」から、日本語 -> 日本語(Anthy) を選択して「追加」
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3431251/797abb72-49a2-5367-7b22-2d0c94c26291.png)

**入力ソースが日本語(Anthy)だと、Shift+Spaceで日本語入力できた。**
他の日本語の入力ソースでもできるかもしれないが、とりあえず「日本語」だとできない。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3431251/42dfa8da-515c-5b65-60bf-01f9d7a801ca.png)
Google Cloud Professional Cloud Network Engineer を取得しました

# Google Cloud Professional Cloud Network Engineer を取得しました

2023/8 に  Professional Cloud Network Engineer 認定資格を取得したので、そのときの学習方法をまとめます。

https://cloud.google.com/learn/certification/cloud-network-engineer?hl=ja

## 前提
Google Cloud 認定資格は Cloud Architect と Data Engineer 、Cloud Security Engineer を取得済みです。

https://qiita.com/ysmmb12/items/5327480781f28416685f

https://qiita.com/ysmmb12/items/a041a499106ad0df2754

https://qiita.com/ysmmb12/items/ef0031b2567c1a32f763

2023/5 に Cloud Security Engineer を受験しましたが、Cloud Security Engineer の試験ガイドを見るとネットワークに関するカテゴリが含まれているため、Cloud Security Engineer 対策で学習した知識を覚えているうちに受験しようと思ったのがきっかけです。（とはいえ3か月ほどあきましたが）

Professional Cloud Network Engineer は今まで受験言語が英語のみだったのですが、受験少し前に日本語が追加されました🎉ので日本語で受験しました。

## 学習方法


### Coursera
資格対策用のコースが用意されています。

https://www.coursera.org/professional-certificates/google-cloud-networking

1-3番目のコースは今までの資格勉強で受講していたので、今回は以下二つのコースを受講しました。

https://www.coursera.org/learn/hands-on-labs-google-cloud-networking-engineer?specialization=google-cloud-networking

https://www.coursera.org/learn/preparing-for-the-professional-cloud-network-engineer-journe

### 模擬試験
公式が公開している模擬試験を2回ほど受験しました。

また、 Coursera の「Preparing for Your Professional Cloud Network Engineer Journey」にも試験に似た問題と解説が用意されているので、解説や関連ドキュメントの読み込みは時間をかけて行いました。
また、Google Cloud 特有ではなくネットワークの基礎知識がないとわからない内容もあるので、そのときは都度調べてました。

Udemy で模擬試験を見てみましたが、一年以上更新されていない、回答や解説が間違っている、などでいいコースは見つかりませんでした。

### ドキュメント確認
Professional Cloud Security Engineer のときと同じく G-gen 様のブログを参考にさせていただきました。
記事の中でリンク付けされている記事も読み込みました。

https://blog.g-gen.co.jp/entry/professional-cloud-network-engineer

## 受験
テストセンターで受験しました。
受験形式は以前の試験から変更なく、受験直後に仮合格がわかりました。
Google 側のトラブル？により正式な合格通知は二週間後くらいでした。

## 受験した感想
今まで受験した試験の中で一番問題文が複雑で、どういう状況なのかを理解するのに時間がかかりました。
今回の試験範囲は個人で気軽に検証できないサービスが他試験よりも多いこともあり、公式ドキュメントや G-gen 様のブログのようなわかりやすい解説を通じて、各サービスへの理解を深める、文章からどういった構成なのかを想像する練習をすることが大切だと思っています。

以上です。
どなたかの参考になれば幸いです。
SvelteKitでルートごとに別のレイアウトを使う(group)

## あとから共通レイアウト増えると困る問題
Webアプリケーションを作成するときは設計が大事ですよね。
SvelteKitでガッツリ作り込んだWebアプリがあったのですが、後からLPを作りたいんだよね～という展開になりまして:angel:
本当は完全に別物として作りたかったのですが、LPとアプリで連携する部分があったため組み込むことになりました。

## SvelteKitの共通レイアウト
https://kit.svelte.jp/docs/routing#layout

SvelteKitでは、ヘッダー・フッターなど共通で使用するレイアウトは`+layout.svelte`に記載します。
最も上の階層に設置すると（`src/routes/+layout.svelte`）、すべてのページで引き継がれます。
特定のディレクトリに設置すると、それ以下のページに適用されます。

`+layout.svelte`を設置しない場合は、`<slot></slot>`が適用されます。空っぽのレイアウトですね。

そもそも共通で使いたいレイアウトが複数存在する可能性があるなら、最上階に`+layout.svelte`は設置しない方が良いです。
後からやっぱり全部のページにレイアウトが引き継がれると困るなあとなったときに、とても面倒くさいことになってしまいます（今回の私のように）。

ここでの困りポイントは、SvelteKitでは`src/routes/`配下に設置したフォルダーの構成がそのままビルド後の階層となるため、`+layout.svelte`を思い通りに設置できない可能性があることです。

そこで活用するのが(group)という機能です。

### Advanced layouts
https://kit.svelte.jp/docs/advanced-routing#advanced-layouts

(group)を使うと出力されるURLに影響しないグルーピングができます。

例えばアプリ・トップページ・LPと3種類の共通レイアウトが必要だったら
```
src/routes/
│ (app)/
│ ├ dashboard/
│ └ +layout.svelte
│ (top)/
│ ├ about/
│ ├ +layout.svelte
│ └ +page.svelte
│ (lp)/
│ ├ campaign/
│ └ +layout.svelte
```
という構成にすることができます。

カッコ付きでグルーピングされたディレクトリは、最終的に出力される階層には影響しません。
なのでこの構成でビルドした場合は
```
build/
├ dashboard/index.html
├ about/index.html
├ campaign/index.html
└ index.html
```
になります。

ここでは、出力されるindex.htmlやディレクトリがバッティングしないよう注意が必要です。
制作時は(group)を使って自由に設定できる分、その内部でディレクトリ名がカブったときに気づきにくいのでその点お気をつけください。

## おわり
SvelteKitは書きやすくて好きなのですが、情報の少なさでウワアアアとなることが多いですね。
調べてみたら便利機能あるな～と気づくことも多いので、やはり公式を読み込むのは大事やなあって感じです。

それでは！
パッチマネージャーでパッチ適用に失敗した件

インスタンスに対するOSパッチ適用は、パッチマネージャーを利用して適用しています。
2023年8月後半に以前と同様に対象インスタンスに対して適用を試みましたが、失敗したのでその内容を記録として残します。
ざっくりとした記載になってしまうこと、ご了承下さい。
OS：Amazon Linux2
## 何が起きた？
バケットに保管している実行ログには、以下が出力されていました。
```
Removing grub2-tools.x86_64 1:2.06-14.amzn2 - u due to obsoletes from grub2-tools.x86_64 1:2.06-14.amzn2.0.1 - u
08/xx/2023 xx:xx:xx root [ERROR]: yum update failed with result code: 1, message: [u'1:grub2-tools-2.06-14.amzn2.x86_64 \u306f grub2-common = 1:2.06-14.amzn2 \u3092\u8981\u6c42\u3057\u307e\u3059']

※unicodeの部分は、"1:grub2-tools-2.06-14.amzn2.x86_64 は grub2-common = 1:2.06-14.amzn2 を要求します" と記載されているようです
```
## 原因を調べる
ググってみると、以下の情報が引っ掛かりました。
https://repost.aws/questions/QUGWErckBaTxe2yo6MtcKgdw/run-patch-manager-failed-on-amazonlinux2

どうやら、該当のエラーは特定のバージョンの grub2-common が必要であるが、grub2-tools の新しいバージョンと互換性がない、または使用できない可能性があることを示しているようです。
これだな。
## 対応する
grub2関連のパッケージは手動で更新し、残りはパッチマネージャーで適用することにしました。
```
$ sudo yum update grub2
```
上記実行後、パッチマネージャーより無事パッチ適用が完了しました。
## 補足
パッチマネージャーはインストール済パッケージがパッチ適用対象になっているかのチェックしかしていないようで、パッケージの依存関係は見ていないようです。
そのため、今回のような事象が発生したと考えられます。
類似の事象が発生した際に、参考になればと思います。

## 2025.03.06 update
先日、grub2関連パッケージが含まれる状態でパッチマネージャーを実行しました。
また失敗するかなと思っていましたが、なんとエラーは発生せず成功しました。
インスタンス10台ぐらいに対して実施しましたが、いずれもエラーは発生しませんでした。
裏側で依存関係を意識してパッチ適用してくれるようになったのでしょうか。。
JavaScript開発で使う用語


# 参照透過性
・同じ引数で呼び出した関数は常に同じ結果を返却するという性質
**つまり、関数が外部の状態を変更せず、引数だけに依存して結果を返す性質**
・参照透過性の保持と副作用がない関数を純粋関数という

# 副作用とは
・グローバル変数の読み書きや、外部のサービスへの通信など、
　外部の要因によって関数の結果が変わってしまう物の事を言います。
→プログラムの予測可能性やテスト容易性が低下する

副作用のある例
```js
let counter = 0;

function incrementCounter() {
  counter += 1; // 外部の変数 counter を変更
}

incrementCounter();
console.log(counter); // 1

incrementCounter();
console.log(counter); // 2
```


例)
グローバル変数の読み書き
静的ローカル変数の読み書き
ファイルの読み書き
他のコンピュータやプロセスとの通信
DBの読み書き
標準出力/入力
システムコール
乱数の取得
現在日時の取得
...etc

# immutability
・イミュータブルなコードだと挙動が予測可能になる。
・ミュータブルなコードだと、ドキュメントの精査、様々なパターンでの実行、あるいはコードの読解などの調査が必要になる

# Javascriptのコピーメカニズム
##### プリミティブタイプ
・Javascriptで変数などを宣言したら、その変数はパソコンのメモリに保存される。
プリミティブタイプの変数はコピーする際に新しいメモリ空間を確保して独立的な値を保存する。
つまり、違うメモリに保存される。

##### オブジェクトタイプ
・プリミティブタイプのように新しいメモリに保存するのではなく、原本のメモリアドレスを渡される。
つまり、原本とコピー本が同じメモリに保存されている同じデータを共有する。
→シャローコピーとディープコピーで解決


# プログラミング手法の違い
##### 手続き型(命令型)
・プログラムを手続きや手順の連続として捉えるアプローチ

```js
// 手続き型プログラミングのスタイル
let sum = 0;
for (let i = 1; i <= 5; i++) {
  sum += i;
}
console.log(sum); // 結果：15
```


##### 宣言型
・プログラムが「何をするか」を宣言し、コンピュータがそれをどのように実現するかは隠蔽するアプローチ
→関数型とか論理型とかがある

```js
// 宣言型プログラミングのスタイル
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // 結果：15
```


##### オブジェクト指向
・いわずもがな
デフォルトで起動するカーネルを変更した方法

[こちら](https://qiita.com/t_dragon/items/5f6ec609c779ae6f9782)の記事の通り、これまでは再起動をするたびにモニターに繋いで手動でカーネルを選択していた。
どうやらデフォルトの変更をできるみたいだったので、やってみた。
参考にしたのは[こちら](https://www.bigbang.mydns.jp/start-kernel-x.htm)。

# カーネルの確認

使用可能なカーネルの確認。確認すべきは名前とindex。
~~~
# grubby --info=ALL | grep ^title
title="CentOS Linux (4.18.0-348.7.1.el8_5.x86_64) 8"
title="CentOS Linux (4.18.0-305.19.1.el8_4.x86_64) 8"
title="CentOS Linux (4.18.0-147.5.1.el8_1.x86_64) 8 (Core)"
title="CentOS Linux (0-rescue-f45499ae913140a9beb740bdd3a78455) 8 (Core)"

# grubby --info=ALL | grep ^kernel
kernel="/boot/vmlinuz-4.18.0-348.7.1.el8_5.x86_64"
kernel="/boot/vmlinuz-4.18.0-305.19.1.el8_4.x86_64"
kernel="/boot/vmlinuz-4.18.0-147.5.1.el8_1.x86_64"
kernel="/boot/vmlinuz-0-rescue-f45499ae913140a9beb740bdd3a78455"

# grubby --info=ALL | grep -A 1 index
index=0
kernel="/boot/vmlinuz-4.18.0-348.7.1.el8_5.x86_64"
--
index=1
kernel="/boot/vmlinuz-4.18.0-305.19.1.el8_4.x86_64"
--
index=2
kernel="/boot/vmlinuz-4.18.0-147.5.1.el8_1.x86_64"
--
index=3
kernel="/boot/vmlinuz-0-rescue-f45499ae913140a9beb740bdd3a78455"
~~~

現在のデフォルトのカーネルの確認。
~~~
# grubby --default-kernel
/boot/vmlinuz-4.18.0-348.7.1.el8_5.x86_64
~~~

現在のカーネルの確認。
これまでは手動で変えていたので、デフォルトとは違う値であることを確認。
~~~
# uname -r
4.18.0-305.19.1.el8_4.x86_64
~~~

# デフォルトの変更

デフォルトのカーネルの変更。
~~~
# grubby --set-default-index=1
# grubby --default-kernel
/boot/vmlinuz-4.18.0-305.19.1.el8_4.x86_64
~~~
ちゃんと現在のカーネルになっている。これで成功したはず。
電子工作メモ - RGBLED

# RGBLED

様々な色を表示できるLED

- 端子

|pin|内容|
|:--|:--:|
|1|アノードコモン（長いピン）|
|2|R|
|3|G|
|4|B|

- 動作

３つのPWMを使用して動作させる。

- 05.1_RandomColorLight/05.1_RandomColorLight.py

```python
from machine import Pin, PWM
from random import randint
import time

pins = [13, 12, 11]
freq_num = 10000

pwm0 = PWM(Pin(pins[0]))  # PWM を設定する
pwm1 = PWM(Pin(pins[1]))
pwm2 = PWM(Pin(pins[2]))
pwm0.freq(freq_num)
pwm1.freq(freq_num)
pwm2.freq(freq_num)

def setColor(r, g, b):
    pwm0.duty_u16(65535 - r)
    pwm1.duty_u16(65535 - g)
    pwm2.duty_u16(65535 - b)
    
try:
    while True:
        red   = randint(0, 65535)
        green = randint(0, 65535)
        blue  = randint(0, 65535)
        setColor(red, green, blue)
        time.sleep_ms(200)
except:
    pwm0.deinit()
    pwm1.deinit()
    pwm2.deinit()
```
Goの変数宣言には気をつけよう。〜ポインタはnilになる〜

# 概要

DeepCopyを実装している際にjson.Marshal->UnMarshalでnil pointer(にるぽ？...w)と悩んでいた話

## 環境

|tool|Ver|
|---|---|
|golang |1.20|

# 既存コード

引数に`コピー先`と`コピー元`を指定する形の関数で問題なく動作していた。(今回はエラー処理を省略してます)

```go:既存コード
type MyString string

func main() {
	input := "test"
	var output MyString
	deepCopy(input, &output)
	log.Printf("output: %+v", output)
}

func deepCopy(src, dst interface{}) error {
	b, err := json.Marshal(src)
	if err != nil {
		return err
	}

	err = json.Unmarshal(b, &dst)
	if err != nil {
		return err
	}

	return nil
}
```

```bash:結果
> output: test
```

## 懸念点

上記のコードでも問題なく動いていたのだが、懸念点が二つ存在する。

### 1.コピー元とコピー先の順番を入れ替えると正しく動作しない
引数がどちらも`interface{}`で受け取っているため、順番が逆でも受け取ることが可能になっている。

```go:NG1
	input := "test"
	var output MyString
	deepCopy(output, &input)		//順序が逆
	log.Printf("output: %+v", output)
```

```bash:出力
output:        #outputからinputにコピーしているためエラーが出ている
```

### 2.コピー先はポインターを指定する必要がある

UnMarshalによって書き換えられた値を呼び出し元の関数で受け取るには、ポインタを渡して値を変更してもらう必要がある。(値渡しと参照渡し)

```go:NG2
	input := "test"
	var output MyString
	deepCopy(input, output)			//値渡しになっている
	log.Printf("output: %+v", output)
```

```bash:出力
output:     #outputの値は変更されていない
```

## 改善案

このようなこと事象は実装者本人が気をつけることで回避することができますが、エンジニアたるもの言語仕様として回避できる術があるのでリファクタリングしようと思い立ちました。

# 本題

ここからが本題です。
解決策として、1.18から追加されたジェネリクスを使用して、コピーしたい型を関数に渡し、UnMarshalされた値をマッピングしようと考えました。こうすることで呼び出す側は引数、コピーしたい型も明確になるため非常に見通しが良くなります。

```go:ジェネリクス
func deepCopyGeneric[T any](src interface{}) (*T, error) {
	
}

func main() {
    input := "test"
	output, _ := deepCopyGeneric[MyString](input)
	log.Printf("output: %+v", output)
}
```

## やらかしポイント

突然ですが、問題です。以下の二つのコードはどちらが動くでしょうか？

```diff_go:その１
func DeepCopy[T any](src interface{}) (*T, error) {
    var dst T

	buf, _ := json.Marshal(src)
    json.Unmarshal(buf, &dst)
    return &dst, nil
}
```

```go:その２
func DeepCopy[T any](src interface{}) (*T, error) {
	var dst *T

	buf, _ := json.Marshal(src)
    json.Unmarshal(buf, dst)
    return dst, nil
}
```


...


..


.

正解は**その1**が正しく動作します。わかる方はそうだよね。となっていると思いますが、完全にハマってました。
エラー内容としては`json: Unmarshal(nil *MyString)`と出力されます。
関数内でポインタを作成しているのにも関わらずなぜかUnmarshalでこける。呼び出す側の関数は引数を正しく設定しており、関数でもポインタを返却している。エラーになる要素がないはず、、、なぜだと10分ほど悩んでいました。

### 原因

これです。

```go:原因
var dst *T
```

この時の処理内容としては、ポインタを生成していますがこの時点では`nil`になります。
盲点でした。

Goでは構造体のポインタを返却するときに`&`を使用することで返却できます。(正確には生成した構造体のアドレスを返却してますが)

```go
return &MyStruct{}
```

この考えが頭に染み付いていたので、変数宣言時にポインタで宣言したのにも関わらず、実態が生成されていないことに頭が回ってませんでした。


#### 後書き

まだまだGopherの道は遠そうです。。

今回の検証コード 

https://go.dev/play/p/qLqKSE42Qnp

DeepCopyの参考にした記事

https://moneyforward-dev.jp/entry/2021/12/22/go-deep-copy/
【fish】nodebrewでnodeのバージョンが変わらないときに確認すること

## はじめに
備忘録
`nodebrew use`コマンドを使ってもnodeのバージョンが変わらなくて困ったので、解決方法を共有します。
shellは`fish`です。
どなたかのお役に立てれば幸いです。

## 解決方法
### 1. fishにパスを通す
まず`config.fish`を開きます。
```bash
~> sudo vim ~/.config/fish/config.fish
```
`config.fish`に以下を追加します。
```bash:~/.config/fish/config.fish
set -x PATH $HOME/.nodebrew/current/bin $PATH  #これを追加
```
`config.fish`を再読み込みして設定を反映させます。
```bash
~> source ~/.config/fish/config.fish
```
### 2. nodeが既にインストールされていないか確認
以下のパスが出力されたら`nodebrew`ではなく`homebrew`で既にインストールされています。
```bash
~> which node
/usr/local/bin/node
```
`homebrew`でインストールされたnodeをアンインストールします。
```bash
~> brew uninstall node
# または
~> brew uninstall --force node
# または
~> rm -r /usr/local/bin/node
```
アンインストールできたか確認します。
```bash
~> which node
/Users/username/.nodebrew/current/bin/node
```

### 3. nodebrewでnodeを管理
`nodebrew`でnodeをインストール
```bash
~> nodebrew install-binary latest  # 最新版
~> nodebrew install-binary stable  # 安定版
```

インストール済みのnodeバージョンを一覧表示
```bash
~> nodebrew list
v16.13.1
v18.8.0
v18.12.1
v20.5.1
```

使うバージョンを指定する
```bash
~> nodebrew use v20.5.1
```

バージョンが変わっているか確認
```bash
~> node -v
v20.5.1
```
Lattice Estimator の使い方の備忘録


## 概要

LWE問題をベースにした格子暗号を利用する時に、
現在知られているいろいろな攻撃アルゴリズムに対して、
設定したパラメータを使ったLWE問題がどのくらいのセキュリティビットを備えているのか
を試すことができるのがLWE Estimorです。


github はこちらです。

https://github.com/malb/lattice-estimator


## 試してみよう

サクッと試したい時は、彼らが用意しているbinder
https://mybinder.org/

常に構築された　Jupyternotebook に遷移することによってすぐに使用することができます。

上記環境に飛ぶためには、github レポジトリ上の
Try it in your browser　のところのリンク

https://mybinder.org/v2/gh/malb/lattice-estimator/jupyter-notebooks?labpath=..%2F..%2Ftree%2Fprompt.ipynb


をクリックすることでJupyternotebook環境を使用することができます。


## テスト用のプログラム

Jupyternotebook 上で例えば、

```
# import
from estimator import schemes
from estimator import LWE
from estimator import lwe_parameters
from estimator import nd

my_param = schemes.NTRUHPS2048677Enc
LWE.estimate.rough(my_param)
```
を実行します。

この例では、標準化のために使用されている

```
NTRUHPS2048677Enc
```

のパラメータを利用しています。

結果は数十秒くらいで返ってきます。

```
Algorithm functools.partial(<function dual_hybrid at 0x7f9d75143100>, red_cost_model=<estimator.reduction.ADPS16 object at 0x7f9d751066d0>, mitm_optimization=True) on LWEParameters(n=676, q=2048, Xs=D(σ=0.61), Xe=D(σ=0.82), m=676, tag='NTRUHPS2048677Enc') failed with β = 79 > d = 61
usvp                 :: rop: ≈2^150.7, red: ≈2^150.7, δ: 1.003328, β: 516, d: 1186, tag: usvp
hybrid               :: rop: ≈2^222.3, red: ≈2^221.3, svp: ≈2^221.3, β: 515, η: 2, ζ: 234, |S|: ≈2^260.7, d: 1012, prob: ≈2^-68.8, ↻: ≈2^71.0, tag: hybrid
```

これで2^x　となっているところが、xビットのセキュリティビットという意味です。


### 設定するパラメータの説明へのリンク


lwe_parameters.LWEParameters に渡す引数はこちらで確認できます。

https://lattice-estimator.readthedocs.io/en/latest/_apidoc/estimator.lwe_parameters/estimator.lwe_parameters.LWEParameters.html



## 最後に

今回は簡単ではありますが、
LWE Estimator の使い方を備忘録としてまとめました。


今回はこの辺で。



@kenmaro
.bashrcカスタマイズ備忘録

# はじめに
IDEとしてcloud9を使っているのですが建てるたびにbashの設定がリセットされてしますので、自分向けに.bashrcの設定を残しておきます。

# 手順
```タイトル:コマンド
#viエディタで編集
$ vi ~/.bashrc
```
```タイトル:.bashrc
～最後尾に追記～
alias ll='ls -l'
alias la='ls -a'
alias tf='terraform'
alias tff='terraform fmt'
alias tfi='terraform init'
alias tfp='terraform plan'
alias tfa='terraform apply -auto-approve'

➡bashコマンドでリロード
```
```タイトル:コマンド
#エイリアスの確認
$ alias
```


以下のシェルを叩いてもOK！
```タイトル:.sh
#! bin/bash

#.bashrcカスタマイズ
cat <<EOL >> ~/.bashrc
#alias追加
alias ll='ls -l'
alias la='ls -a'
alias tf='terraform'
alias tff='terraform fmt'
alias tfi='terraform init'
alias tfp='terraform plan'
alias tfa='terraform apply -auto-approve'
EOL

#適用
bash
```
【CSS】ニコニコのスクロールバーをYouTubeに導入


# 0. はじめに

YouTubeで現在の動画見ながら次の動画探したいなぁ...

![before](https://raw.githubusercontent.com/SoniPana/Qiita-Content/main/images/23/08/31/00-01-before.gif)

ニコニコ動画みたいなスクロールバーがあればいいのになぁ...

![niconico](https://raw.githubusercontent.com/SoniPana/Qiita-Content/main/images/23/08/31/00-02-niconico.gif)

自分で作るかぁ...

![after](https://raw.githubusercontent.com/SoniPana/Qiita-Content/main/images/23/08/31/00-03-after.gif)

ということで、YouTubeの関連動画にニコニコ動画のようなスクロールバーを導入してみました。

# 1. 導入方法

## 1.1. Stylusのインストール

ウェブページに独自のCSSを適用するための拡張機能「Stylus」をインストールします。

https://chrome.google.com/webstore/detail/stylus/clngdbkpkpeebahjckkjfobafhncgmne?hl=ja

![install](https://raw.githubusercontent.com/SoniPana/Qiita-Content/main/images/23/08/31/01-01-install.png)

## 1.2. CSSの適用

YouTubeに移動し、StylusのアイコンをクリックしてCSSの編集画面を開きます。

https://www.youtube.com/

![open-stylus](https://raw.githubusercontent.com/SoniPana/Qiita-Content/main/images/23/08/31/01-02-open.gif)

その後、以下のCSSを貼り付け、左側にある「保存」ボタンを押します。

```css
@-moz-document domain("youtube.com") {
    #items.style-scope.ytd-watch-next-secondary-results-renderer {
        overflow-x: hidden;
        overflow-y: scroll;
        width: 420px;  /* 関連動画の幅 */
        height: 65em;  /* スクロールバーの高さ */
        margin-bottom: 80px;
        overscroll-behavior: contain;
    }

    #content.style-scope.yt-related-chip-cloud-renderer {
        display: none;
    }

    #items.style-scope.ytd-watch-next-secondary-results-renderer::-webkit-scrollbar {
        width: 8px;
    }

    #items.style-scope.ytd-watch-next-secondary-results-renderer::-webkit-scrollbar-track {
        background-color: #dddddd;
        border-radius: 8px;
    }

    #items.style-scope.ytd-watch-next-secondary-results-renderer::-webkit-scrollbar-thumb {
        background-color: #828282;
        border-radius: 8px;
    }

    #items.style-scope.ytd-watch-next-secondary-results-renderer::-webkit-scrollbar-thumb:hover {
        background-color: #909090;
    }
}
```

![貼り付け](https://raw.githubusercontent.com/SoniPana/Qiita-Content/main/images/23/08/31/01-03-paste.png)

## 1.3. 調整

`height: 65em;`の値を調整することで、スクロールバーの高さを調整できます。

スクロールバーが長すぎると、以下のようにスクロールしてもスクロール先の動画が読み込まれなくなってしまう(スクロールが途中で止まってしまう)場合があります。

![long](https://raw.githubusercontent.com/SoniPana/Qiita-Content/main/images/23/08/31/01-04-long.gif)

かと言って短すぎても使いづらいので、適度な長さに調整してください。

![short](https://raw.githubusercontent.com/SoniPana/Qiita-Content/main/images/23/08/31/01-05-short.png)

他にも、`width: 420px;`の値を調整することで関連動画の幅を調整できたり、~~`background-color: #dddddd;`の値を調整することでスクロールバーの色を調整できたり~~します。色々試してみてください。

:::note warn
24/08/31 追記: 現在、スクロールバーの色を変更することはできません。
:::
AutoGenerateColumns の設定値によってDataGridView.DataSource に null を設定したときの挙動が変わります

バグ調査をしていたところ、[DataGridView.DataSoueceをnullで初期化すると、Columnsも初期化される](https://jingyo.seesaa.net/article/200912article_18.html) という記事を見つけました。

バグの原因は、記事に書かれている通りでした。（先人に感謝です）
AutoGenerateColumns の設定によって、DataGridView.DataSource に null を設定したときに、Columns が初期化されるかどうかが変わります。

|AutoGenerateColumns の値 |DataSource に null を代入したときの挙動|
|---|---|
|true  |Columns が初期化される（ヘッダーごと消える）|
|false  |Columns は初期化されない（ヘッダーは残る）|

## サンプルプログラムで確認してみる

こういうのは、動かしてみるのが一番分かりやすいのでサンプルプログラムを作りました。

作った画面はこんな感じです。
![Form1 2023-08-31 15.40.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960076/0a54d846-5a02-ee87-d92b-27ebd169f5c2.png)


上の表はカラムの自動生成ON => AutoGenerateColumns = true の表です。
下の表はカラムの自動生成OFF => AutoGenerateColumns = false の表です。
それぞれの表の横に DataSource を null にするボタンがあります。

動かしてみましょう。

![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960076/d5ce03c0-533a-a42e-0d03-85afb359984a.gif)


gif のように上の表（カラムの自動生成ON => AutoGenerateColumns = true）はヘッダーごと消えているのが分かります。
それに対して、下の表（カラムの自動生成OFF => AutoGenerateColumns = false）はヘッダーが残っているのが分かります。

デバッガで DataSource を null にした後を見てみます。
AutoGenerateColumns = true の表は columns の数が0になっています。
![DataGridViewTest (デバッグ中) - Microsoft Visual Studio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960076/647a45bf-42aa-db06-1e31-b296646be9bf.png)

対してAutoGenerateColumns = false の表は columns の数が1のままになっていました。
![2_DataGridViewTest (デバッグ中) - Microsoft Visual Studio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960076/465db800-15d0-3681-dbbc-2a33c2aae297.png)

この差により、DataSource = null セット後の挙動に差が出たと考えられます。

いやぁ、なかなかの罠ですね。ヘッダーごとリセットしたい場合は、AutoGenerateColumns の設定値によらず、 Columns.Clear() してあげたほうが良さそうです。

参考にこのサンプルプログラムの Form のコードも載せておきます。

```C# Form1.cs
using System;
using System.Data;
using System.Windows.Forms;

namespace DataGridViewTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // 上の表はカラムの自動生成ON
            dataGridView1.AutoGenerateColumns = true;
            // 上の表にデータをセット
            var table1 = new DataTable();
            table1.Columns.Add("text");
            table1.Rows.Add("カラムを自動生成");
            dataGridView1.DataSource = table1;

            // 下の表はカラムの自動生成OFF
            dataGridView2.AutoGenerateColumns = false;
            // 下の表にデータをセット
            var table2 = new DataTable();
            table2.Columns.Add("text");
            table2.Rows.Add("カラムを手動で追加");
            dataGridView2.DataSource = table2;

            // 下の表のカラムを手動で追加
            var textColumn = new DataGridViewTextBoxColumn();
            {
                textColumn.DataPropertyName = "text";
                textColumn.Name = "text";
                textColumn.HeaderText = "text";
            }

            dataGridView2.Columns.Add(textColumn);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            dataGridView1.DataSource = null;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            dataGridView2.DataSource = null;
        }
    }
}
```
VSCode で Laravel 用の静的解析ツール larastan を使えるようにする

`Laravel`のプロジェクトにおいて、静的解析ツール`larastan`を`VSCode`で使えるようにしたので、その備忘録です。

https://github.com/nunomaduro/larastan

以下環境で実施しました。

```sh
PHP : 8.2.9
Laravel : 10.20.0
VSCode : 1.81.1

# WSL
WSL バージョン: 1.2.5.0
カーネル バージョン: 5.15.90.1
Ubuntu 20.04.6 LTS
```

# 拡張機能`PHPStan`をインストールする

拡張機能を「`PHPStan`」で検索すると複数ヒットするのですが、今回は以下の拡張機能をインストールしました。

https://marketplace.visualstudio.com/items?itemName=SanderRonde.phpstan-vscode

以下の理由でこちらの拡張機能を選定しました。
- インストール数は類似拡張機能の中で最多ではないが、引けを取らない数字である
- 最終更新日が唯一年内（2023年8月末現在）であった
- ファイル単位で解析できる
    - 他の拡張機能だと「指定ディレクトリ以下全て」に対してしか行えないものもあるため

::: note warn 
バージョン 3.0以降（2024年4月～）
単一ファイルのチェックではなく、常にリポジトリ全体のチェックを行うようになっています。設定で単一ファイルチェックにすることも可能ですが、キャッシュを破壊するため推奨しないとしています。
:::


# `phpstan.neon`を配置する
`PHPStan`の設定ファイル`phpstan.neon`をディレクトリ直下に配置します。
※ディレクトリ直下以外に配置する場合は、拡張機能の設定からパスの修正が必要です

ひとまず`PHPStan`のレベル（今回は最大レベル）と、チェック対象パスを指定します。

```phpstan.neon
parameters:
	level: 9
    paths:
        - app
```

# `larastan`のインストール

以下コマンドからプロジェクトに`larastan`をインストールします。

```sh
composer require nunomaduro/larastan:^2.0 --dev
```

:::note warn
`larastan`のバージョンについて
`larastan`のバージョン`2.0.0`以上を使用するには
- `PHP 8.0+`, 
- `Laravel 9.0+`
が必要です。

それ未満の`PHP/Laravel`バージョンの場合は上記コマンドではエラーとなります。
その場合は、`^2.0`を`^1.9`に置き換えるなどで実行してください。
:::


`larastan`をインストールすると、`PHPStan`も含まれています。
そのため、この時点で静的解析（`larastan`的には「コード解析」という言葉を用いるそう）ができると思います。

任意の`php`ファイルを開き、`Ctrl` + `Shift` + `p`でコマンドパレットを開きます。
`PHPStan: Scan current file for errors`を選ぶことでも静的解析を実行できます。
![screenshot_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961694/1a5bf5a2-8904-bd98-fed9-e50fcabbf75a.jpeg)



`PHPStan`も静的解析ツールなのですから、それだけがあれば良いような気もします。

ただ、現状`larastan`の設定がないまま`PHPStan`だけを使うと、以下では`User::create()`や`redirect()->action()`などが`Call to an undefined (static) method ...`という解析結果になってしまいます:disappointed_relieved:

![screenshot_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961694/d375d49a-4f96-a35d-f129-63cd9460e863.jpeg)


## `larastan`を利用するための設定を追加する

`phpstan.neon`に`larastan`の設定を追加することで、`Laravel`用の解析を実行することができます。

```phpstan.neon
# larastanを使用する
includes:
	- ./vendor/nunomaduro/larastan/extension.neon

parameters:
	level: 9
```

上記`includes`を追加することで、先程の`Call to an undefined (static) method ...`というエラーがなくなります:cherry_blossom:
![screenshot_03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961694/0dc42e17-d10a-aaf6-b2c8-3208c1233c69.jpeg)


`larastan`に怒られないようにコードを書きたい！と意気込みながら生きています。
（でもlevelをmaxに設定すると結構大変なので、levelを1つ1つ上げていきながら解消するのがいいのかなと思ったり:sweat_smile:）

余談ですが、
- プロジェクトの`composer.json`に記載のPHPバージョン
- ローカルのPHPのバージョン
が合っていない場合はエラーで動かないのでお気をつけください！

```sh
# composer.jsonには">= 8.1.0"という指定なのに、ローカルのPHPバージョンが7.4.33で怒られる
PHPStan process exited with error  filteredErr=PHP Fatal error:  Composer detected issues in your platform: Your Composer dependencies require a PHP version ">= 8.1.0". You are running 7.4.33.
```

プロジェクトごとにPHPのバージョンが違うこともあります。
そのため、私は以下を参考にして、適宜切り替えられるようにしています。

https://qiita.com/murakami77/items/a9945f2a8e51ca3791de
【SwiftUI】"cannot preview in this file" の解決方法

## はじめに
備忘録
Xcodeでプレビュー画面を表示しようとしたときにつまずいたので書き残します。
どなたかのお役に立てれば幸いです。

## 解決方法
### 1. ライセンスに同意する
ターミナル上で`sudo xcodebuild -license`を実行します。
パスワードを聞かれるので入力してください。
```bash
＄　sudo xcodebuild -license
Password:
Xcode and Apple SDKs Agreement

PLEASE SCROLL DOWN AND READ ALL OF THE FOLLOWING TERMS AND CONDITIONS CAREFULLY・・・
```

規約を読むか、`q`を押すことで次のステップへ進めます。
```bash
Software License Agreements Press 'space' for more, or 'q' to quit
```

ここで`agree`と入力することでライセンスに同意できます。
```bash
By typing 'agree' you are agreeing to the terms of the software license agreements.
Type 'print' to print them or anything else to cancel, [agree, print, cancel]

You can view the license agreements in Xcode's About Box, or at /Applications/Xcode.app/Contents/Resources/en.lproj/License.rtf
```
### 2. Xcodeを再起動する
`cmd + q`などでXcodeを完全に終了し、もう一度起動し直してからプロジェクトを開くとプレビュー画面がきちんと表示されるはずです。
開業届と適格請求書発行事業者の登録申請

今月は残念ですが、SAPのコンサルタント資格のフォローにおける報酬を断念したため、赤字収支になりました。

2人FI資格に合格しつつも、あまりサポート出来なかった責任が大きいですが、契約に沿った業務内容のすり合わせを行えなかったのもあるので、これは今後のフリーランスの活動における反省として留意いたします。

表記の通り、私は8月18日に開業届および適格請求書発行事業者の登録をいたしました。

収入が保証されない環境で、免税事業者として継続しようと思いましたが、契約企業から消費税名目で報酬をいただいているのに、自分の懐に入れるのは納税の義務にかなり矛盾を感じておりました。

やはりフリーランスとはいえども健全な経営は信頼に大きな影響を与えますので、法改正があった場合は従うのが誠意だと感じております。

かなり健全な経営や開発を心がけてまいります。
Lit Elementでattributeが変更されたら関数を実行したい

# はじめに

Lit Elementで`attribute`で渡されているプロパティの変更を検知するのに迷ったところがあったのでまとめます

# やりたいこと

Web Componentsに渡しているAttributeである`eventId`が変更されたら、画面に表示されているメンバーリストを取得する`fetchMemberById`を再度実行して画面を再レンダリングしたいです

# 解決方法

ライフサイクルの`update`を利用することでうまくできました

https://lit.dev/docs/components/lifecycle/#reactive-update-cycle

```ts:sample.ts
@customElement('my-element')
export class MyElement extends LitElement {
  @property() eventId = '';

  updated(changedProperties) {
    changedProperties.forEach((oldValue, propName) => {
      if (propName === 'eventId') {
        this.fetchMemberById(this.eventId);
      }
    });
  }
```

変更は`Property`に設定したものが変わった瞬間に`update`で`changeProperties`に変更されたプロパティの名前が取れるのでそこでfetchを行うようにしています

# カイゼンする

`update`を利用する場合、`eventId`以外のプロパティがあった場合にそれが変わった際に、再レンダリングされてしまいます

そこでライフサイクルをみてみます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/e6072cc2-2c4d-c422-084b-2e355e324fe0.png)

この図から`shouldUpdate`を利用することで、**eventIdが変更されたときのみ再レンダリングをする**という最適化が可能になります

# おわりに

Litで調べていたところドキュメントからよくわからずまとめてみました
よくやる操作かなと思ったので参考になると嬉しいです

# 参考

https://lit.dev/docs/v1/components/lifecycle/
AWS CloudShell が起動できない！そんなときの対処法

こんにちは。
今回は、新しく作成した AWS アカウントで AWS CloudShell が起動できなかったので、その解消法をまとめました。

AWS CloudShell を起動しようとすると、以下の様にエラーが発生し使用できません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/53b88fc7-542d-2284-59bf-7b4c323cb0aa.png)

エラーメッセージに「contact AWS Support」と記載されている通り、問題解決には AWS Support の力が必要です。

というわけで、早速問い合わせました。

> AWS CloudShellを利用しようとしましたが、以下のメッセージが表示され、利用不可です。AWS CloudShellを利用したいため、ご対応のほどよろしくお願いします。
＊＊＊
環境を開始できません。You must verify your account before accessing CloudShell. To verify your account, contact AWS Support 
＊＊＊
本AWSアカウントはAWS ControlTowerを利用して払い出されたアカウントであるため、管理アカウント側で操作しないとならない内容があればその旨ご連絡ください。
ちなみに、同様に払い出した別のアカウントについては問題なくAWS CloudShellの利用ができております。

半日後に AWS Support から届いたメッセージを要約すると以下の通り

> 海外担当部署との確認作業を行いたく、恐れ入りますが、当該サービスのご利用リージョンをお知らせいただけますでしょうか。

問い合わせ時の基本中の基本である情報が足りてませんでした💦
その後、東京リージョン(ap-northeas-t1)やバージニア北部(us-east-1)などで動作しない旨を伝えたところ、4時間程度（問い合わせから1日少々）で、 AWS CloudShell が正常に起動し、利用できるようになりました。

> 担当部署との確認作業が完了し、現在本アカウントでは両リージョンにて当該サービスがご利用いただける状態となっております。

原因自体は不明ですが、同様の事象について、 AWS re:Post で質問している方が過去にいらっしゃいました。
https://repost.aws/questions/QUH54A371dRvej5J1G_yZogw/error-when-launching-aws-cloudshell-unable-to-start-the-environment



その中で興味深い書き込みがありました
> It is possible your account is not 100% verified. Try this: Create a CloudFront distribution if you get the below error it confirms your account is unverified or if you can create 2 distributions and can't create the 3rd one.
(機械翻訳)アカウントが100%確認されていない可能性があります。これを試してください: CloudFront ディストリビューションを作成する 以下のエラーが表示され、アカウントが未検証であることを確認する場合、または2つのディストリビューションを作成でき、3番目のディストリビューションを作成できない場合。



**あくまで憶測の域を出ませんが**、AWS re:Post のコメントにあるように、AWSアカウント が完全に使える状態ではないまま、作成完了になったと思われます。

皆様の環境でもこういった問題発生時の参考になれば幸いです。

ーーー
記載されている会社名、製品名、サービス名、ロゴ等は各社の商標または登録商標です。
今更聞けない(かもしれない)Win32API概要

## はじめに

ある日、筆者が特定のプロセスのウィンドウをC#でアクティブにできなくて困っていたところ、「**Win32API**を使えばできるよ！」ということを教えてもらいました。

しかし、筆者はWin32APIというものを使ったことがなかったし、それがどういうものなのかも一切知りませんでした。

「もしかして、C#で開発してるエンジニアにとっては常識だったりする……？」

というわけで、ちょっと調べてみました。
誤りがあれば教えていただけますと幸いです。

## Win32APIって何？

WindowsのOSの機能に、Windows上で動作するプログラムからアクセスするときに利用できる、Windowsの機能やリソースにアクセスするための関数やデータ構造を提供するAPIです。
C言語やC++のプログラムからアクセスすることができます。
Windows NT(32bitOS)が登場したころから存在するAPIであるため、かなり歴史は長いです。

## 何ができるの

Win32APIはコンピュータを制御・操作するための基本的な機能を提供しているため、Win32APIを利用すれば、Windowsの動作する環境であれば実行できるアプリケーションを作ることができます。
筆者はウィンドウをアクティブにするために使いましたが、他にも以下のリストに書かれているようなことができます。
https://learn.microsoft.com/ja-jp/windows/win32/apiindex/windows-api-list

それこそUIの作成からファイルアクセス、印刷、再起動やシャットダウンまで、WindowsのOSの機能をだいたい使えるようです。

## どうやって使うの

筆者はC#で開発を行っています。
C言語とC++で使えるというWin32APIは、C#環境で使えるのでしょうか？
実は.NETにはそれを実現する仕組みがあります。

### P/Invoke(プラットフォーム呼び出し)

P/Invokeはマネージドコード(.NET Framework等の.NET実行環境で実行が管理される、.NETの共通中間言語で記述されたプログラム)からアンマネージドコード(.NET実行環境で実行が管理されないプログラム)を呼び出すための仕組みです。マネージドコードからアンマネージドコードを呼び出す仕組みがあることで、Win32APIのような、OSの機能と深く関連づいているライブラリの機能を利用することができるのです。

System.Runtime.InteropServices名前空間を利用して、以下のように記述することでwin32APIを利用できます。

```C#
System.Runtime.InteropServices

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd); 

```
呼び出したいAPIを、DllImport属性を付けて呼び出します。
DllImport属性の引数には、利用するライブラリのdll名を記載します。
また、Win32APIのメソッドはuser32.dll内にある(→プログラム内にない)ため、メソッドが外部にあることを示すextern修飾子を付ける必要があります。

ちなみに、例で紹介しているメソッドの引数の`IntPtr hWnd`はウィンドウハンドルです。
ウィンドウハンドルはWindowsが各ウィンドウに割り振る管理番号(ポインタ)のことです。

## さいごに

新しい武器を手に入れた気持ちです。まだウィンドウをﾋﾟｮｺﾋﾟｮｺさせただけですが……。
P/Invokeは、C#の学習を始めたばっかりの頃に書籍で学習した覚えはあったのですが、実際に使うことになって改めて調べ直しました。当時よりは理解できた気がします。

(externとかポインタとか、C言語の勉強をした時以来だなあ……)