OmniAICreator/Qiita-1.07M huggingface dataset:
Windows Serverを管理する方法の整理

### はじめに

Windows Serverを管理しようとするとWindows Admin CenterやSystem Center、さらにはAzureを使った管理方法など様々なツールが存在しており、何を使うことが適切か混乱するといったことがあると思います。このブログではどんな場面でどの管理ツールが適しているかを整理します。

### Azure Arc

Azure Arc-enabled serversはAzureの外にある物理および仮想のWindowsとLinuxのサーバーを管理することができます。この方法の特徴はAzure上で既に運用しているセキュリティやガバナンス、監視の手法をそのままAzureの外にも適用し、一貫した管理をAzureを通して行うことができるという点です。複数サイトに分散している環境や既にAzure上に運用環境が存在する場合は管理を効率化するためにこの方法が検討できるでしょう。ただし細かい変更や管理が必要な場合は後述のWindows Admin Centerの方が適切です。このWindows Admin Centerは[Azure上からの提供もプレビューで開始されている](https://learn.microsoft.com/en-us/windows-server/manage/windows-admin-center/azure/manage-vm)ため、ますますAzureからの集中管理の機能強化が加速しています。
また、[Azure Automanage](https://learn.microsoft.com/ja-jp/azure/automanage/automanage-arc)というMicrosoftのサーバー管理のベストプラクティスに準拠したサービスの自動構成機能を活用することで管理設定を簡素化できます。

### Windows Admin Center（WAC）

詳細なWindows Serverおよびクラスター管理を行う場合、Windows Admin Centerが最適でしょう。Windows Admin CenterはサーバーマネージャーやMMCのようなインボックス管理ツールの現代進化版であり、他の管理ソリューションを補完するものです。さらにツールを通じてPowerShellをリモートから実行することもできます。またWindows Admin CenterはAzureと接続することでハイブリッドAzure管理サービス機能を提供しており、オンプレミスのWindows Admin Center管理コンソールから一部のAzureの管理ソリューションを管理することもできます。

### System Center

データセンター全体の展開、構成、管理、監視を行うためにはSystem Centerが選択肢に入るはずです。System Centerでは環境内のすべてのシステムのステータスを確認できるのに対し、Windows Admin Centerは特定のサーバーにドリルダウンしてより詳細な管理およびトラブルシューティングを行うことを得意としており互いに補完関係にあります。Microsoftドキュメントに比較も記載されているので詳細は[こちら](https://learn.microsoft.com/ja-jp/windows-server/manage/windows-admin-center/understand/related-management#system-center)もご参照ください。

### Windows Server on Azure

もしAzure上でWindows Serverを動かしている場合は、Azureネイティブの管理ツールが用意されているのでそちらの活用が便利です。

### まとめ

Windows Serverを管理する複数の方法を整理しました。Azureの管理機能はAzure Arcを活用することでオンプレミスやエッジ、さらには他のクラウドプロバイダーの環境にあるWindows Serverにまで提供されているため、環境横断で一貫性のある管理を実現できます。詳細は[Microsoftのドキュメント](https://www.thomasmaurer.ch/2022/08/how-to-manage-windows-server/)もご確認ください。

### 参考

[How To Manage Windows Server](https://www.thomasmaurer.ch/2022/08/how-to-manage-windows-server/)
2023/5/1主にITとかセキュリティの記事

「Microsoft 365」を学校で“使用禁止”にしたドイツ　懸念する「特定の国へのデータ流出」のリスクとは？(4/29)
https://news.yahoo.co.jp/articles/64fa218516019612930b2cf4d3298723c0e7ba71?source=rss

サイバー攻撃から供給網守れ　監視サービス、商機は海外(4/29)
https://www.nikkei.com/article/DGXZQOUC10CAS0Q3A410C2000000/

神戸市、生成ＡＩルール条例化へ(4/28)
https://jp.reuters.com/article/idJP2023042801000279

中国ハッカーの数、米国サイバー専門家の50倍＝FBI長官(4/29)
https://mb.epochtimes.jp/2023/04/148305.html

パスワードマネジャーはどれを選ぶべき？　押さえておきたい10の機能とは(4/29)
https://atmarkit.itmedia.co.jp/ait/spv/2304/29/news018.html

黒船「チャットGPT」でザワつく霞ヶ関・・・警戒する企業も　問われる日本での活用(4/29)
https://news.yahoo.co.jp/articles/b1e4c5895cae6a04bfea8a722276174eb5ab9c20

名古屋大に不正アクセス、４４６人分の氏名・住所や成績など閲覧された可能性(4/29)
https://news.yahoo.co.jp/articles/289dfac3eeec5bd37c2e05358fdc4b23462b179f

マイクロソフトは組織内部へのサイバー攻撃をいかに防いでいるのか(4/29)
https://news.yahoo.co.jp/articles/4f553fac1b4d879d89a1cb5cdceb9a2880ed2149

宅配便「不在連絡」のSMSには注意すべし(4/29)
https://ascii.jp/elem/000/004/134/4134094/?rss

テキスト生成AIでスパムメール合戦は新時代へ(4/28)
https://www.gizmodo.jp/2023/04/chatgpt-ai-gmail-spam-personalized-inbox-flood-1.html

人気の印刷管理ソフトウェア「PaperCut」に重大な脆弱性、すぐ更新を(4/29)
https://news.mynavi.jp/techplus/article/20230429-2668040/

日本企業で広がる｢生成AI｣のビジネス活用最前線
法律相談から名作ゲーム､菓子のグリコまで(4/29)
https://toyokeizai.net/articles/-/666046

サークル（Circle）の革新的な新クロスチェーンUSDC転送プロトコルを発表(4/28)
https://nextmoney.jp/?p=58161

危険な改正、中国「反スパイ法」で〝日本人狩り〟も　ネット環境も監視対象に　「要職者と交流する場合に用心必要」識者警鐘(4/29)
https://news.yahoo.co.jp/articles/a7d47bda6ce9ebf7aeaadb92a5668c155dd6cd85?source=rss

「フレッツ光」通信障害、原因は「未知の不具合」 NTT東西が検証結果を報告(4/28)
https://news.yahoo.co.jp/articles/8f34462235f885cb6d6a7786b9fb4c433d27a156?source=rss
HTTP/2とHTTP/1.1の多重度比較

# はじめに
- HTTP/2のストリーム機能は，本当にTCP1コネクション内で多重化しているのか見てみたい。
- HTTP/1.1のHTTPパイプラインは，あまり使われていないという噂だが本当か試してみたい。
- HTTP/1.1よりもHTTP/2が本当に早いのか，試してみたい。

# 結論
- HTTP/2のストリーム機能は，本当にTCP1コネクションで多重化していた。
- HTTP/1.1のHTTPパイプラインは使われている。ただし，別のTCPコネクションも併用して効率化している(chromeで確認）
- HTTP/2はHTTP/1.1より速かった。

# 材料
- クライアント側はWindows11+Chrome112
- HTMLファイル(index.html，下記jpgファイルを埋め込んだ)
- 60kBぐらいのjpgファイル×5個（image[1-5].jpg）
- nginxのコンテナ
- オレオレ証明書(HTTP/2はTLS必須なので）
- nginxのconfファイル。所要時間が大きくなるようにlimit_rateを設定（帯域制限）
```
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        limit_rate 600k;
    }
```


# HTTP/1.1
- nginxのconfig
```
server{
    listen       443 ssl;
    listen  [::]:443 ssl;
    ...
    ssl_certificate /etc/nginx/ssl/***.crt;
    ssl_certificate_key /etc/nginx/ssl/***.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ...
}
```

- Chromeの開発者ツールのスクリーンショット（３回計測）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457890/b9c38de5-7d97-7900-6052-e51328363df7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457890/e44f27f5-dee0-0dd9-0053-707c9644e749.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457890/e9f2205d-6b58-ab4c-eace-afbceff97de4.png)
- TCPコネクションは，4本
- index.html+image1.jpg+image?.jpgの3ファイルが1つのHTTPパイプラインに乗っている。
- 残りのimage?.jpgの3ファイルは，それぞれ新規TCPコネクションで合計3並列。
- HTTPパイプライン（シーケンシャル）と，複数のTCPコネクション並列を組み合わせて多重化している
- 平均270msぐらい（かなり適当な目測）

# HTTP/2
- nginxのconfig
```
server{
    listen       443 ssl http2;
    listen  [::]:443 ssl http2;
    ...
    ssl_certificate /etc/nginx/ssl/***.crt;
    ssl_certificate_key /etc/nginx/ssl/***.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ...
}
```

- Chromeの開発者ツールのスクリーンショット（３回計測）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457890/7b710ed9-5a4d-e858-1440-9a35cfaa5d38.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457890/8786f127-4241-7747-a45a-7bcc22a60953.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457890/c3b9e3ca-7cb0-a336-f59f-d916e1ca12c2.png)
- TCPコネクションは，1本
- ストリームで多重されている
- 平均175msぐらい（かなり適当な目測）
120冊技術書を買った新人がおススメする新人に手に取ってみてほしい4冊。

# はじめに
駆け出しエンジニアの頃からエンジニアの方に勧めてもらった本や興味のある本を息を吸うように買っていたらいつの間にか120冊以上なってしまいました。
今回は、その中から右も左もわからなかったころから「読んでてよかった」と思った新人の方におススメしたい本を4選紹介したいと思います。

## Webを支える技術
webとは何なのか、HTTPやRESTについて学べます。
ステータスコードやCRUDはweb開発で必須な知識です。
ポートフォリオ作ったり実務でも役に立つと思います。

https://gihyo.jp/book/2010/978-4-7741-4204-3

## オブジェクト指向でなぜつくるのか 第３版
プログラミング言語を学ぶ前に本書を読んでおくことで、言語の理解が深まり習得が早くなるような気がします。
なぜシリーズは最初のエンジニア転職面接で教えてもらった本なのですが、読むことで前知識がついたのでいろいろと理解を助けてくれました。

https://bookplus.nikkei.com/atcl/catalog/21/S00180/

## UNIXという考え方
UNIX哲学について学べます。
UNIX哲学はいろんな考え方の原点になってる哲学だと思っています。(個人的感想です)
面接でUNIX哲学の話をすると受けがよかったですね。
本書は、エンジニアの友人に教えていただきました。エンジニアなら知っておきたい哲学だと思います。

https://www.ohmsha.co.jp/book/9784274064067/


読書会でも取り上げました。

https://qiita.com/sun33/items/64ec8cfaf0b1540cfba8

## プリンシプル オブ プログラミング
先輩エンジニア方々が使う呪文のような言葉「DRY」や「YAGNI」についてや考え方がまとめて学べます。
実際、自社開発をしていて、これらの呪文が詠唱されますので、ぜひ3年目までとは言わず1年目から知っておきたい項目ばかりです。

https://www.shuwasystem.co.jp/book/9784798046143.html

# おわり
今回は思想や考え方を中心におススメの本を紹介しました。
技術書で全体感を掴むことで、理解を助けてくれると思うので、ぜひ手に取っていただきたいと思います。おしまい。
【JTC向け】Excelで日本の祝日を判定する方法

### TL;DR
Execelで祝日判定するには下記を利用する
1. データ > Webの取得で内閣府の[日本の祝日CSV](https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv)を指定する
1. 当該のデータを指定して```=IF(COUNTIF(Sheet1!A:A,[[判定対象の日付]]),"祝日","")```などの式を書く


### モチベーション・背景
JTCで働いている初手の情報可視化、共有はExcelで実施される。
そして、Excelでカレンダー(GW/年末年始のメンバーごとの休み予定とか、メンバーの工数管理表)などを作成することがあり、祝日判定を作成する必要がでてくる。
だが、この作業をできるだけ人力でやりたくない。
使ってる方は常識的に使っていると思うが、GW前にやる機会があったのでアウトプットとして記事にしてみる。

### 前提
下記のように、日付データセルがある場合にのそのセルの値が祝日かを判定したい。
なんか条件追記書式とかで色とかかえるとなおいいとか言われそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/179f3b80-5c41-977e-00f5-55a2569cb9d4.png)

### データ取得
- Excelのヘッダリボンの[データ]タブを選択し、[Webから]を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/6978cc72-835c-95ea-d49e-124ef200d6b1.png)
- URL欄に内閣府の国民の祝日CSVのURL(https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv)を入力する
※ このCSVのやばさの歴史は[こちら](https://okumuralab.org/~okumura/stat/holidays.html)などをご参照いただきたい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/e4997ac3-b423-dc41-2c95-432caf1313cd.png)
- 多分普通に読み込まれるので、そのまま[読み込み]を押下する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/a390148f-1c36-5e17-41cd-daa1ef252296.png)
- [syukujitu]シートが追加される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/7e384d72-1b09-b8f2-5266-b4fd0b7aa2d1.png)

### 判定処理を追加
- 判定対象のセルに下記などを入力する
```=IF(COUNTIF(syukujitsu!A:A,[判定対象の日付])>0,"祝日","")```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/4f52e62e-7622-b78b-5059-b867102c9e68.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/6ae88a94-e84a-c822-aa47-70cce11a5207.png)
できた。よかったね。
RustのAPIコンテナをビルドしてみた

他の方に作ってもらったRustのRockerを使ったAPIをARM64/AMD64用のコンテナにしたくなったのでDockerfileがない状態からなんとかした話。

## 前提
- 開発環境: Windows10 + WSL2
- コンテナ起動環境: Oracle Cloud A1.Flex Instance (ARM64) + 任意の AMD64 PC

## まずRustのAPIを起動してみる
とりあえずコンテナのビルド以前に動作確認をしてみないとはじまらないのでやってみる。

1. (コードを git clone してくる)
2. RustUpを使ってRustの開発ツール一式をインストールする
  https://www.rust-lang.org/ja/tools/install
3. クローンしてきたフォルダ内で `cargo build --release` を実行する
4. `target\release` に 実行ファイル(Windowsならexe)がビルドされる
5. 起動してみる (動いた)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/e25bcb3c-785e-4544-35ee-ee3f9b46795c.png)

## 本題
無事APIが動いたので、次に本題のDockerfileを書く。

### 注意: 検索して出てくる内容はちゃんと読もう
`Rust Dockerfile` と Google検索すると 2番目に[ScrapBoxのもの](https://scrapbox.io/nwtgck/Rust%E8%A3%BD%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E6%A5%B5%E5%B0%8F%E3%81%AEDocker%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8BDockerfile
)がヒットしたので最初はそれを参考にコピった。が、これは極限までサイズを小さくする場合に参照する記事であって一般的なやり方ではなかったため、ビルド途中で詰まった。

### 作成した Dockerfile
一般的なやり方は [Rustの公式イメージ](https://hub.docker.com/_/rust)のREADMEに書いてあった。
なので、それを参考にして 下記のようなマルチステージビルドなDockerfileを書いた

```Dockerfile
FROM rust:latest as build
COPY . .
# Build
RUN cargo install --config net.git-fetch-with-cli=true --path .

FROM debian:bullseye-slim
# Copy executable
COPY --from=build /usr/local/cargo/bin/schedule /usr/local/bin/schedule
# Run a server
EXPOSE 8100
ENTRYPOINT [ "schedule" ]
```

今回作るAPIコンテナは ARM64とAMD64の両方で使いたいので 下記のコマンドを使いビルドした。

```shell
# Buildxで使うビルド環境作成
docker buildx create --use --name multi-arch-builder --driver-opt network=host --driver-opt image=moby/buildkit:v0.10.6
# (上記ビルド環境を使い) Gitlab container registry にPush
docker buildx build . --platform linux/amd64,linux/arm64 -t registry.gitlab.com/(org)/(repository):latest --push`
```

無事ビルドが通り、ローカルでコンテナを起動できた。


### 工夫した点
- debian-slimだと 若干コンテナサイズが大きいので よりコンテナサイズが小さい google/distroless を利用した(が動かなかったためもとに戻した)
  - https://zenn.dev/yoshii0110/articles/21ddb58c6f6bfa
- なぜか `cargo install` の途中で Killed になってしまったため configを足した
  - https://github.com/rust-lang/cargo/issues/10781#issuecomment-1351670409
- RocketのBindIPが 127.0.0.1 になっており APIがリクエストを受け付けてくれなったため0.0.0.0にして頂いた
  - https://rocket.rs/v0.5-rc/guide/configuration/
- Gitlab container registryにPushしたとき manifestがUnknownになってしまうためBuildxをダウングレードした
  - https://github.com/docker/cli/issues/3969


### 感想
コンテナ作るだけなら簡単かと思ったら割りと詰まる事が多くて苦戦しました。
この記事が誰かの参考になれば幸いです。
paddingとspacingの違い(SwiftUI)

## 結論

|用語|意味|主な用途|備考|
|:--|:--|:--|:--|
|`padding`|要素の __内側__ の余白|親要素との間に余白を設ける<br/>ボタンの見た目を変えずにタップ領域を広げる|Webの `padding` と同義|
|`spacing`|要素同士の間隔（要素の __外側__ の余白）|要素間に余白を設ける|Webの `gap` と同義|

## 環境

- OS：macOS Ventura 13.3.1
- Xcode：14.3 (14E222b)
- Swift：5.8

## 「padding」とは？

https://developer.apple.com/documentation/swiftui/view/padding(_:_:)

SwiftUIにおけるViewのモディファイアで、指定した方向に指定した値だけ余白を付けます。

Webのpaddingと同様で、要素の __内側__ に余白を付けます。
つまりViewのサイズ（ `frame` ）に影響を与えます。

## 「spacing」とは？

https://developer.apple.com/documentation/swiftui/vstack/init(alignment:spacing:content:)

`VStack` や `HStack` などのイニシャライザで指定できる値で、指定した値だけサブビュー間に余白を設けます。
Webのgapと同様と考えるとわかりやすいです。

`padding` と異なり、要素の __外側__ に余白を付けます。
Viewのサイズに影響を与えません。

## 主な用途

TBD

## おまけ: コンポーネントがmarginを持つと○ぬ

Webで言われている名言です。

https://twitter.com/murokaco/status/1382502888728010762

○ぬ理由をわかりやすく説明している引用リツイートがあったので紹介します。

https://twitter.com/rhirayamaaan/status/1382532340614713345

SwiftUIでも同様であり、要素同士の間隔は親要素の `spacing` で決めるべきです。

```swift
// ✅
VStack(spacing: 8) { // 親
  Image(systemName: "swift") // 子
  Text("Swift") // 子
}

// ❌
VStack(spacing: 0) { // 親
  Image(systemName: "swift") // 子
    .padding(.bottom, 8)
  Text("Swift") // 子
}
```

## おわりに

誤っていたらご指摘ください :pray:
シェルスクリプトで正規表現を使い指定したファイルから文字列を抽出する方法

## シェルスクリプトで正規表現を使い<br>指定したファイルから文字列を抽出する方法
今回は正規表現を使い指定したファイルから指定した文字列を抽出してみました。

### やりたいこと
データファイルとして下記のsample.txtを使用します。
実際に実行するシェルスクリプトファイルとデータファイルは別々とします。
```title:sample.txt
りんご:5個:300円
バナナ:3本:100円
みかん:6個:400円
```
sample.txtから指定した文字列を抽出し標準出力として下記のように出力させます。

```title:標準出力
りんご
5個
300円
```
### 文字列「りんご」がある行を取り出す
下記のコードはmacOSのzshで実行しました。
まずは文字列「りんご」が含まれる行を取得する。
```title:sample.sh
FRUIT="りんご"
fruit_data=$(grep -E "$FRUIT" sample.txt)
echo $fruit_data
```
下記の様にマッチした行が出力されます。
```title:標準出力
りんご:5個:300円
```

### マッチした行から「フルーツの名前、個数、値段」の順で表準主力する

```title:sample.sh
echo "$fruit_data" | sed -E 's/(.+):.+:.+/\1/'
echo "$fruit_data" | sed -E 's/.+:(.+):.+/\1/'
echo "$fruit_data" | sed -E 's/.+:.+:(.+)/\1/'
```
上記のコードでは`$fruit_data`の文字列に対して`sed`で指定した条件で置換をしている。`(.+):.+:.+`は正規表現の部分で`()`で文字列をキャプチャしています。`\1`はキャプチャした文字列を表しています。

マッチした行が出力されます。
```title:標準出力
りんご
5個
300円
```

### まとめ
今回は正規表現を利用して別ファイルから指定した文字列を抽出してみました。
grepコマンドを利用して指定した文字列が含まれる行を取得し、sedコマンドで正規表現による文字列の抽出を行いました。
さらに効率的な方法をご存知の方いらっしゃったらコメントしていただければ幸いです。

### 備考
正規表現を確認する際は[Rubular(Ruby)](https://rubular.com/)や[正規表現チェッカー(JavaScript)](https://www-creators.com/tool/regex-checker)などが便利です。
ちなみにRubularでチェックして、シェルスクリプトで実行したら意図しない結果になることがありました。
プログラミング言語によって正規表現のコマンドが変わっている部分もあるので注意が必要です。
シェルスクリプト用の正規表現チェッカーをご存知の方いらっしゃたらぜひご教示ください、ものすごく喜びます。


### 参考URL
[シェルスクリプトの正規表現の詳細解説](https://qiita.com/ko1nksm/items/53abc144558b9bb5629f)
[プログラミング言語の正規表現まとめ](https://tokitsubaki.com/regex-manipulation/448/#toc1)
[初心者歓迎！手と目で覚える正規表現入門・その１「さまざまな形式の電話番号を検索しよう」](https://qiita.com/jnchito/items/893c887fbf19e17d3ff9)
【Rails】renderパーシャル備忘録

renderメソッドを用いてパーシャルファイルを呼び出すときに引っかかった部分をまとめました。

## 通常時

```ruby
class PostsController < ApplicationController
 def index
  @posts = Post.all
 end
end
```

```erb
<%# posts/index.html.erb %>
<%= render @posts %>
<%# または %>
<%= render partial: 'post', collection: @posts %>
```

呼び出されるのは下記になります。

```erb
<%# posts/_post.html.erb %>
<%= post.id  %>
```
## コントローラーでデータを分ける場合
postデータにはcolorカラムが用意してあって２種類あるとします。

enum color: { blue: 0, red: 1}

```ruby
class PostsController < ApplicationController
 def index
   @red_posts = Post.where(color: :red)
   @blue_posts = Post.where(color: :blue)
 end
end
```

indexで表示する場合に、分けて表示したい場合。
### 通常時

```erb
<%# posts/index.html.erb %>
<h1>red_post</h1>
<%= render partial: 'red_post', collection: @red_posts %>
<h1>blue_post</h1>
<%= render partial: 'blue_post', collection: @blue_posts %>
```

```erb
<%# posts/_red_post.html.erb %>
<%= red_post.id  %>
------------------
<%# posts/_blue_post.html.erb %>
<%= blue_post.id  %>
```

のようにできますが、今回のように呼び出す内容が同じidの場合などは、次のようにできます。
### 省略時
```erb
<%# posts/index.html.erb %>
<h1>red_post</h1>
<%= render @red_posts %>
<h1>blue_post</h1>
<%= render @blue_posts %>
```

```erb
<%# posts/_post.html.erb %>
<%= post.id  %>
```

このようにしても、省略できます。


renderを省略形で呼び出す場合、@posts の中のモデル名（この場合は Post）に基づいてパーシャルファイルを探すからです。

### おまけ

コレクションを使用する際、パーシャルファイル内の変数名は、**@red_postsの単数形が常に適切であると考えがちですが、実際にはそうでない場合もあります。**

```erb
<%# posts/index.html.erb %>
<h1>red_post</h1>
<%= render partial: 'red_post', collection: @red_posts %>

```

上記の場合は

```erb
<%# posts/_red_post.html.erb %>
<%= red_post.id  %>
```

このようにファイルと同じ変数で問題ありませんが、

もしも、なんらかの処理があり、下記のように

```erb
<%# posts/index.html.erb %>
<h1>red_post</h1>
<%= render partial: 'red_color_post', collection: @red_posts %>
```
呼び出す必要があった場合はどうなるかというと、

```erb
<%# posts/_red_color_post.html.erb %>
<%= red_color_post.id  %>
```

にする必要があります。

何故なら、collection: @red_postsは、パーシャルファイルを表示する際に、@red_posts変数を使って繰り返しレンダリングすることを指定しているだけだからです。
このとき、パーシャルファイル内で使われる変数名は、パーシャルファイル名から自動的に導出されます。

partial: 'red_color_post'こそが重要で、partialファイルの名前がred_color_postなら変数もred_color_postにする必要があるということです。

ちなみに、下記のようにした場合は
```erb
<%= render partial: 'red_color_post', collection: @red_posts, as: :red_post %>
<%# または　〜〜〜, as: "red_post"でも可 %>
```
```erb
<%# posts/_red_color_post.html.erb %>
<%= red_post.id  %>
```
ファイル名と変数名が一致していなくても動きます。

まとめたグラフがこちらです。

| controllerの変数名 | モデル名 | 省略？ |  partial | collection | パーシャルファイル名 | パーシャル内変数名 |
| --- | --- | --- | --- | --- | --- | --- |
| @posts | Post | @posts|  |  | _post.html.erb | post |
| @posts | Post | ✖️ | post | @posts  | _post.html.erb | post |
| @red_posts | Post | @red_posts |  |  | _post.html.erb | post |
| @red_posts | Post | ✖️ | post | @red_posts | _post.html.erb | post |
| @red_posts | Post | ✖️ | red_post | @red_posts | _red_post.html.erb | red_post |
| @red_posts | Post | ✖️ | red_color_post | @red_post | _red_color_post.html.erb | red_color_post |
| @posts | User | @posts |  |  | _user.html.erb | user |
| @posts | User | ✖️ | user | @posts | _user.html.erb | user |
ChatGPTとBing検索

# ChatGPTはネオ直子の代筆
Bing検索だと文例が載っているサイトを紹介するだけだが、ChatGPTは真面目に適当な文章を作る。
なので論文みたいな「かしこまってガチガチな」ところだと確かに見破るのが困難かも。
ただ、挨拶文を作らせたらかなり強い。なので、入学式とかに使われるのは今後も増える。ただ、聞く文章が同じだと同じ結果が出やすいのは当然で、バレると恥ずかしいのでそのまま使わないほうが良い。

## ChatGPTのサイトは英語扱いらしい
なので、自動翻訳させているとバグを起こす。何回か英語に戻すと日本語が出てくる。

## 中でもプログラムは強い
VBSとか直してくれるし、Androidにこんな機能はない？とか聞くとAndroid StudioをいれてAPIを取って次のスクリプトを書くといいですよというのが出てくる。



# Bing検索
まず「より創造的」は本当にジョークサイトなみ。ぶっ壊れたAIという感じ。これは多分作った人が実験的に使っているのだと思われる。（認知プロファイリング）
検索に使うのはノーマルか厳密。そして割りとこちらのほうが検索に向く。

## まとめて短文を作っているらしい
うまくいった場合は、いくつかのサイトをまとめた文章ができる。
JustSystemが昔作っていたようなやつ。
さらに、サイトをいくつか紹介している。
これは本当は逆で、いくつかキーワードでヒットしたサイトから文章を作っていると思われる。
なので、横断検索してまとめているらしい。

## 商魂の怪物・・・？
食べるお店の検索はなぜか食べログに必ず持っていくんですがなにか繋がりがあるのでしょうか。。。

## 最後は別サイトに丸投げ
困ったことは別のサイトに投げるという無責任さ。
そのぶん、あまり嘘はつかない。

# Bingのアホさ加減
Bingはセーフサーチが解除できない。そうBing検索が言っている。単純なBing検索は解除できるが、Aiは無理。
そのくせジョークを作らせると書きかけて自己検閲してBANしてしまう。セルフ暴走セルフBAN。
笑える動きだが、実用性は全くない。
その割にストーミー・ダニエルズはスルー。どういう基準なんだよそのセーフサーチ。

# 著作権
これはChatGPTがどこから持ってきているのかソースがあまりない。Bingは見た目と逆だとすると、どこをソースにして文章を~~でっち上げて~~作成しているのかがわかる。
もう一つ、今度はその結果をそのまま文章にするのもやばい。ChatGPTはどこから持ってきたがわからない。
一瞬流行ってもう下火になったけど、AIで作成しましたというのもどのへんまでがAIなのか怪しい。

# 使い分け
## IT関連はChatGPT
ある質問がスマホに関連しているとかプログラミング言語ならChatGPTはキレキレ。
ある程度機能や言語を知っていて使うと効果が高いが無から有を作ることはできない。

## 作文はChatGPT
　文章を作るときにはChatGPTを使っても良い。でも現時点では部分的。
　しかし、町内会の招待状のようなごく小規模であればまあいいんじゃないですかね。
　でも中立的で責任あるAIになると文章がめちゃくちゃに長い。官僚の答弁みたいになる。しかも結局何をいっているのかよくわからない文章になる。
　なのでテンプレートな文章しか作成できない。

## 応用がChatBotなのはそうだろうな
　最もこの機能をChatBotに入れるのはそうだろうなと思います。
 あとWordにいれたらテンプレートがもうちょっと使えるようになるでしょう。

## 検索は結果がある程度予測できる場合はBing検索
ある程度結果が予測できる場合はBing検索を使う。

## 検索結果が全く予測できないときは両方使う
　教えてくださいと入力するするのが面倒くさいですね。自動的に教えてくださいって補完する機能はないのかな。
Postfixのメールキューに関するコマンド

●Postfixのメールキューに関するコマンド

・postqueue -p | mailq　メールキューを表示する
・postqueue -f | postfix flush　メールキュー内にあるメールを直ちに再送する
・postsuper -d　メールキュー内のメールを削除する
VMware Cloud on AWS の詳細な環境情報を REST API でお手軽に一覧取得してみる (API Explorer)

# 1. はじめに

VMware Cloud on AWS の環境情報をまとめて取得するときに利用できる便利なAPIツール「API Explorer」があるので、小ネタとして残しておきます。

今回は普段見ることがない(VMwareマネージドなので意識する必要がない)VMware Cloud on AWS SDDCが稼働するAmazon VPCの設定情報を、ちょっとだけ見てみることにします。

VMware Cloud on AWS 環境におけるAWSアカウントの考え方については、次のAWSブログもご参考ください。

https://aws.amazon.com/jp/blogs/news/account-and-vpc-considerations-for-vmware-cloud-on-aws/

# 2. 参考にさせていただいた記事

https://blogs.vmware.com/vmware-japan/2021/06/vmc-api-explorer.html

https://qiita.com/mtoyoda/items/631dcc10774126139efe

# 3. 「API Explorer」 is 何？

[VMware Japan Blog (VMware Cloud on AWS の REST API 管理で役立つ「API Explorer」)](https://blogs.vmware.com/vmware-japan/2021/06/vmc-api-explorer.html)からそのまま引用・抜粋します。

> API Explorer とは、以前から vSphere Client にも実装されている機能の一つで、REST API の仕様と動作を確認できるツールです。API Explorer は、VMware Cloud on AWS の管理コンソールにも実装されており、管理コンソール画面から VMware Cloud サービスや VMware Cloud on AWS 環境向けの API コールの書式やリソース名、ステータスコードなどがその場で確認できるようになっています。

下図のようなイメージです。
VMware Cloud コンソールから、「デベロッパーセンター」を開いて遷移します。
ざっくり眺めてみるとREST APIでさまざまな情報を登録、取得、更新、あるいは削除できることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/05a54fc1-3407-10c1-8b43-893ba3648926.png)

# 4. 「API Explorer」 で VMware Cloud on AWS の環境情報を取得してみる

対象のSDDCを選択します。
複数のSDDCの環境情報をまとめて取得することもできますが、今回はまず１つだけに絞っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/271eb222-b48d-b2c8-0499-5c946e7d259a.png)

次のAPIセットを探して、実行します。
> GET /org/{org}/sddcs/{sddc}

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/94167999-0cc2-3831-ceeb-65c6cbdf5b17.png)

API実行後、JSONファイルがダウンロードできるので確認していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/fe56abfc-4c07-385c-cd5a-4b6adfd11975.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/eb73925a-0fb3-71c3-de9d-b89cf41edc65.png)

普段見ることがない(VMwareマネージドなので意識する必要がない)であろうVMware Cloud on AWS SDDCが稼働するAmazon VPCの設定情報を確認できます。
また"vpc"あるいは"vgw"などでフィルターをかけられます。

例えば、VMware Cloud on AWSが稼働するAmazon VPCのIDだったり、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/cca7b2cf-102d-8c14-baa2-0acacc877e62.png)

VMware Cloud on AWSが稼働する(VMwareマネージドの)Amazon VPCのVGW-IDなどが確認できます。
これらの情報はVMware CloudコンソールGUIには表示されない情報なのですが、API経由だと確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/84a93437-7112-9801-e8a4-e705dfb05ce4.png)

# 5. さいごに

上記はいずれも通常利用する際には必要のない情報であったりするのですが、深めのトラブルシュートの際などに把握できると役立ったり、あるいは構成情報をまとめて取得する際に便利だったりするかと思います。

今回は、VMware Cloud on AWS の管理・運用効率化にAPIを活用できるという例のご紹介でした。

# 6. 参考記事

https://blogs.vmware.com/vmware-japan/2021/06/vmc-api-explorer.html

https://blogs.vmware.com/vmware-japan/2021/05/vmware-cloud-api-token.html

https://qiita.com/sanjushi003/items/e4fd5e9358d3b150c066
20行でOpenCvSharpのWebcamキャプチャ

## はじめに
C#でWebcamのキャプチャをするコンパクトなコンソールアプリを書いてみました。OpenCvSharpを使います。

## 前提
下記の条件が前提です。
* Windows PCでVisual Studio Codeがインストールされている
* C#とNugetの拡張機能がインストールされている
* .NET Framework 4.8をターゲットにする
    [Download .NET Framework 4.8.1](https://dotnet.microsoft.com/ja-jp/download/dotnet-framework/thank-you/net481-developer-pack-offline-installer)
　(追記：.NET 7.0でも動作確認しました)

## 準備
1. [OpenCV](https://opencv.org/)のインストール
   * [Download OpenCV (SourceForge)](https://sourceforge.net/projects/opencvlibrary/files/latest/download)
2. プロジェクト作成
    * .NET Framework4.8の場合
    `dotnet new console --target-framework-override net48 -lang c# -o webcam_console`
    * .Net 7.0の場合
   `dotnet new console -lang c# -o webcam_console`
3. VSCodeで`webcam_console`フォルダを開く
4. Nugetで`OpenCvSharp4.Windows`を追加

## コード
`Program.cs`
```csharp
using OpenCvSharp;
using static OpenCvSharp.Cv2;

namespace webcam_console
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var capture = new VideoCapture(0))
            using (var frame = new Mat())
            while (WaitKey(1) == -1)
            {
                capture.Read(frame);
                ImShow("Webcam: Hit any key to stop.", frame);
            }
            DestroyAllWindows();
        }
    }
}
```

`webcam_console.csproj`
* .NET Framework4.8の場合
```csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net48</TargetFramework>
    </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="OpenCvSharp4.Windows" Version="4.7.0.20230115" />
  </ItemGroup>

</Project>
```
プロジェクトを作成後に、エラーになる行を削除する必要がありました。

* .NET 7.0の場合
```
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="OpenCvSharp4.Windows" Version="4.7.0.20230115" />
  </ItemGroup>

</Project>
```
編集の必要はありませんでした。

## ビルドと実行
ターミナルで以下をタイプ：
* `dotnet build`
* `dotnet run`

## 実行環境
```
OS Name:                   Microsoft Windows 10 Home
OS Version:                10.0.19044 N/A Build 19044
```

## 参考


https://qiita.com/e4rfx/items/c2d8606229c4f88cfa08
【Python×AWS】DockerでBoto3を使ったら「botocore.exceptions.NoCredentialsError: Unable to locate credentials」と表示された場合

# エラー概要（`NoCredentialsError`）
* ローカル環境からdockerコンテナで起動したdjangoアプリで、Pythonのboto3を利用してAWSのリソースへアクセスする実装を行ったら、以下のエラーメッセージが返ってきました。

```terminal
raise NoCredentialsError
botocore.exceptions.NoCredentialsError: Unable to locate credentials
```

* 本記事では、上記エラーの原因と解決方法について記載します。

# 原因の追求: dockerを利用している場合は...
* 上記のエラーは、AWS SDK for Python（Boto3）を使用してAWSサービスにアクセスしようとした際に、クレデンシャル情報が見つからなかった場合に発生するエラーです。
* クレデンシャル情報=アクセスキーIDとシークレットアクセスキーであり、これらを設定する必要がありますが、自分の場合は以前既にしていました。まだの方は、以前以下にも整理したのでご参考ください。
    * [【Python×AWS】botocore.exceptions.NoCredentialsErrorエラー対応。clientとresourceの違いも](https://qiita.com/Ryo-0131/items/2f6f1125855c61d1a8c6)
* クレデンシャル情報の記載間違いという記事が多かったので、`\.aws\config`と`\.aws\credentials`を確認しましたが、間違いはありませんでした。
* そんな中、以下の記事を見つけました。
    * [初めてのAWSでNoCredentialsError: Unable to locate credentialsが出たのでDockerを設定する](https://qiita.com/Sicut_study/items/3a4a0f107462a8d9487a)
* そうか、ローカル環境から実施していましたが、、、Dockerを使っている、という点を忘れていました！！

# 解決策
* 上記の記事の通り、ローカル環境でクレデンシャル情報を設定していても、dockerコンテナはホストマシンをみに行っているわけではありません。Dockerコンテナ内でAWS SDKを使用する場合は、認証情報を直接コンテナに設定する必要があります。
* 以下、どちらでも解決できます。dockerイメージを作成する時か、コンテナを起動する時か、の違いです。

## ①`Dockerfile`で設定する場合

```Dockerfile
ENV AWS_ACCESS_KEY_ID <アクセスキーID>
ENV AWS_SECRET_ACCESS_KEY <シークレットアクセスキー>
```

## ②`docker-compose.yml`で設定する場合

```yml
environment:
- AWS_ACCESS_KEY_ID=<アクセスキーID>
- AWS_SECRET_ACCESS_KEY=<シークレットアクセスキー>
```

* 上記どちらでも、設定した状態で再度コンテナを起動すると、エラーメッセージが表示されなくなります。
* dockerを利用している今回の場合のエラー内容は、「Docker service is」`Unable to locate credentials`という意味だったんですね。今回はローカル環境から実施するだけの用途ですが、本番運用する際には環境変数で利用するようにしてください。`.env`ファイルを使えば簡単にできます。Do not hardcode credentials!!
【Salesforce認定資格挑戦】アドミニストレーター試験体験記

こんにちは、J.Lです。

2023年の４月最後の日に、先月の予定通りに認定資格のアドミニストレーター試験を受験しました。その体験をまとめてみました。

■試験結果
まず、結果としては合格でした。すごく嬉しいです。:v:
各トピックの配点は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290279/9c7b59e7-bb55-af7f-b18b-d144750943b5.png)


各トピックの割合により、計算して私の得点は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290279/9a9f4fee-e20f-6b54-06c4-29549fd8772c.png)

Platform デベロッパーと同じような勉強方法を利用しました。
■勉強実績
アドミニストレーター試験に向けた学習　→　復習（2週間）
問題練習(200ぐらい)　→　繰り返し強化（2週間）
問題練習はかなり行えば、実際の試験には、問題を見ただけで、答えがわかる問題もあります。しかし、選択肢を注意しなければならないです。

■今後予定
Platform デベロッパーとアドミニストレーターの知識をシェアしたいです。
Andrew Ng先生＋ChatGPT本家のプロンプト開発講座が無料で公開されています！

# はじめに
ChatGPTブームで世の中にプロンプトの講座や勉強サイトがあふれていますが、何で学べばいいのか迷ってしまいますよね。そんな皆さんにオススメしたいのがこちらの入門講座です！
いずれも現時点（2023年6月25日）では[DeepLearning.AI](https://www.deeplearning.ai/about/)が無料で公開中の講座です。

:::note info
この記事は個人で作成したものであり、内容や意見は所属企業・部門見解を代表するものではありません。
:::

## ChatGPT Prompt Engineering for Developers<br>（開発者向けChatGPTプロンプト エンジニアリング）

https://www.deeplearning.ai/short-courses/chatgpt-prompt-engineering-for-developers/

ChatGPTのプロンプト講座です。Pythonを使うためにエンジニア向けとなっていますが、実行しないで動画だけ見ることもできます。また、講座で使うコードはすでに用意されていてブラウザ内で実行できるので、開発環境の準備も不要で非常にお手軽です。

## Building Systems with the ChatGPT API<br>（ChatGPT APIを使ったシステム構築）

https://www.deeplearning.ai/short-courses/building-systems-with-chatgpt/

実際にシステム構築する際のヒントが満載の講座です。
安全性の確保方法やユーザーの質問内容を分類して段階的に処理する流れ、回答の評価方法とその改善のアプローチなどが学べます。商用サービスの展開を考えられている方にお勧めです。

## LangChain for LLM Application Development(LLM アプリケーション開発のための LangChain)

https://www.deeplearning.ai/short-courses/langchain-for-llm-application-development/

LangChainの入門講座です。私はLangChainをまだ使っていない（LangChainが安定する前に最初のサービスを作ってしまった）ので未受講です。

## How Diffusion Models Work(拡散モデルの仕組み)

https://www.deeplearning.ai/short-courses/how-diffusion-models-work/

拡散モデルの仕組みの解説です。私は未受講なのですが、中級になっていてTensorflowやPytorchの知識が必要になるみたいですね。

# 怪しくない？

確かに世の中には、個人が試してみたプロンプトを列挙しただけのような怪しい講座やサイトもあるようですが、この講座を提供しているDeepLearning.AI社は、AI研究で有名なAndrew Ng先生が2017年に設立したAI活用を支援する教育テクノロジーの会社なので安心です。さらに今回のコースは、ChatGPTの本家であるOpenAI社の協力の元で提供され、Andrew Ng先生自らが講師として教えてくれます。これ以上に安心で信頼できる入門講座はないでしょう。

# 日本語は？

残念ながら英語のみの提供です。ただ、英語が苦手な私も、MacのChrome＋Google翻訳で修了できました。

以下に、講義の途中の画面を貼り付けておきますので、動画の字幕を日本語にする際などの参考にしてください。

![翻訳駆使.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139624/e96c3a1e-90c7-5ab1-0b49-87fa26fa65f5.png)

# どれくらい時間かかる？

ホームページの紹介には1時間とありますが、私はGoogle翻訳を駆使しながらだったので、数時間かかってしまいました。

英語が問題ない方は、1時間（途中の課題でいろいろ試さなければ）で終わるのではないかと思います。

# 始め方は？

各ページの「Learn for Free」を選び、Sign Inの画面で一番下の「Create account!」を選んでアカウントの作成画面に進みます。ここでメールアドレスを入力すると「Verify your account with DeepLearning.AI」という件名のメールが送られて来ますので、このメールの「Activate your account」ボタンを押してください。名前とパスワードを設定する画面に進み、それらを入力すれば始められます。

# おわりに

~~時々、動画が見られないことがありました。
もし見られない場合は、動画の部分を右クリックすると動画のURLがコピーできるので、それを別タブで開けば見ることができます。ただし、この形だと字幕は表示されません。
なお、全滅ではなく一部の章だけで、後から再びその章に戻ったら正しく再生できたので、もし同じ現象になってしまった場合は、時間を空けるなどして工夫すると良いかも知れません。~~

2023年4月の終わりに「ChatGPT Prompt Engineering for Developers」を受講した時は動画が再生できないことがあったのですが、6月24日に「Building Systems with the ChatGPT API」を受講した時は全く問題ありませんでした。

以上、オススメのChatGPTプロンプト講座のお知らせでした。

# （追記）

よそ様の講座を紹介しただけでトレンド入りしてしまい、さすがに講座の概要くらいは追記しようかと考えていたところで、概要が端的にまとまった @mihoicchi さんの記事を見つけてしまいました。内容については、ぜひこちらを。

https://qiita.com/mihoicchi/items/a7d04d6b2b3bfbc96e72

（結局、よそ様の紹介しかしてない……）
【Git】git add した変更を取り消す方法

## ステージングのみ取り消す

変更内容はそのままにステージングのみ取り消すには以下を実行します。  

```zsh
git restore --staged パス
```

`test.txt`を作成して試しに実行してみます。  
作成後に`git add test.txt`を実行した状態が下の画像です。  

![5C0748CF-728C-4AC0-890B-7B5EEE254B94.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/ae503746-27d9-770f-ad8b-f23c6742dc4e.png)

「ステージされている変更」に`test.txt`があります。  
ターミナルでコマンドを実行し取り消します。  

```zsh
git restore --staged test.txt
```

![4C590208-CF47-49C4-B49F-11C8028F5F09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/9e788611-838d-5f59-893b-4af3228334d9.png)

ステージングが取り消されて「変更」に`test.txt`が表示されています。  

なお`--staged`をつけないで実行するとステージ後に加えた変更を取り消せます。  

ステージ後に`test.txt`へ変更を加えます。  

![DD5522BA-71BA-4B30-BF44-009522399D89.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/384593d0-da4a-38f7-90c5-c1bc303f5a30.png)

ステージ後に変更が加えられたため「ステージされている変更」と「変更」の両方に
`test.txt`が表示されています。

`--staged`をつけないで実行します。  

```zsh
git restore test.txt
```

するとステージング後の`test.txt`への変更が取り消されます。  

![6C8FE656-86BA-4F52-A7AA-0809F76C9B28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/54a7990b-627f-1122-4013-1db12ec45de7.png)

「変更」から`test.txt`の表示が消えました。  

## 変更内容ごと取り消す

変更内容ごとステージを取り消すには以下のように実行します。

```zsh
git restore --source=HEAD --staged --worktree パス
```

上記を実行するとステージと変更内容の両方が取り消され、直前のコミットの状態に戻ります。

## ステージング前の変更のみ取り消す

ステージング前の変更のみ取り消すには以下のように実行します。

```zsh
git restore --worktree パス
```
ペライチのhtmlファイルから外部APIを叩く

# やりたいこと

htmlファイルをブラウザで開くだけでAPIコール〜描画するまでの仕組みを構築したい。

# サンプルコード

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>任意のタイトル</title>
  </head>
  <body>
    <div id="result">データ取得中...</div>
    <script>
      const proxyUrl = "https://cors-anywhere.herokuapp.com/";
      const apiUrl = "APIのエンドポイント"
      const reqUrl = proxyUrl + apiUrl;
      const options = {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
          "Access-Control-Allow-Origin": "*",
          "X-Requested-With": "XMLHttpRequest",
          "Content-Type": "application/json",
          "Origin": "http://localhost:5500"  // VSCode: Live Serverで起動想定
        },
        mode: "cors"
      };
      fetch(reqUrl, options)
        .then((response) => response.json())
        .then((data) => {
          console.log(data)  // デバッグ用
          // データの表示処理など(div#resultに値を表示する等)
        })
        .catch((error) => console.error(error));
    </script>
  </body>
</html>
```

# ポイント

ローカルサーバ→外部APIに直接通信する際にCORSエラーが発生する。
なので、ローカルサーバ→プロキシサーバ(※)→外部APIのように通信すればCORSエラーを回避できる。
プロキシサーバがローカルからのリクエストを代わりに外部APIに送ってくれている。

※ https://cors-anywhere.herokuapp.com
GitにおけるHEADとは

# HEADってなんだ？
Gitの学習中､ちょいちょい出てくる HEAD というキーワード
例えばインデックスを取り消すときとか
```
$ git reset HEAD
```
リモートブランチにチェックアウトしたときとか
```
$ git checkout remotes/origin/main
Note: switching to 'remotes/origin/main'.
:省略

$ git status
HEAD detached at origin/main
nothing to commit, working tree clean
```
git reset HEADはインデックスを取り消せるので最新のコミットのようにも思えるがそれだと HEAD detached でコミットが切り離されてるのに､git log で最新のコミットが見えているのが説明つかない｡

そこで調べてみた
## HEADは現在自分がいるブランチを指すポインタ
そのままの意味なので､そんなの当たり前じゃんという方はこれ以上本記事を見ても学びはないと思います｡お疲れさまでした｡

上記見てもよくわからないよって方はもうしばらくお付き合いください｡まず上記の意味を理解するためには､ブランチを理解する必要があります｡

Gitを使い始めた方でもブランチの意味はなんとく理解できると思います｡mainブランチを始め､同じプロジェクト内のファイルを同時進行で修正変更できるよう枝分かれさせたやつです｡

ですが､実際のブランチは特定時点のコミットファイルを参照するポインタに過ぎません｡ある時点のバージョンを記録したファイルがコミットファイルですよね？このコミットファイルを参照しているものがブランチです｡以下を見てください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727038/ebd37310-1abd-c9ae-184c-80b67797e0fa.png)

98ca9 → 34ac2 → f30ab という順にコミットファイルが作成されています｡で､f30abをmasterブランチとtestingブランチが参照しています｡このようにブランチはある時点のコミットファイルを参照しているに過ぎません｡

で､話を戻すとHEADというのは､この図の通りブランチを参照するポインタです｡正確には現在自分がいるブランチを指しています｡なので HEADはブランチを通してコミットファイルの情報を参照できます｡

これを理解すると冒頭の話も理解できます｡

例えば git reset HEAD でインデックスの変更が取り消されるのは､インデックスの情報がHEADを通じてブランチの指すコミットと同じになる(= コミット後にステージングされた情報が消える)ためです｡

以下の状態は､リモートブランチのコミットファイルにポインタが移動したけどローカルにブランチがないということを意味しています｡

```
$ git checkout remotes/origin/main
Note: switching to 'remotes/origin/main'.
:省略

$ git status
HEAD detached at origin/main
nothing to commit, working tree clean
```
つまり HEADがブランチを介さず直接リモートリポジトリの指すコミットファイルを参照しています｡なので､コミット履歴が見えるのです｡

ちなみに余談ですが､git checkoutは多機能すぎるので､ブランチを移動する機能のみに分解された git switch というコマンドがあります｡git switch でリモートブランチに直接移動しようとすると怒られて移動できません｡
```
$ git switch remotes/origin/main
fatal: a branch is expected, got remote branch 'origin/main'
hint: If you want to detach HEAD at the commit, try again with the --detach option.
```
detach HEADの状態でswitchしたいなら --detach使えと言われてますね｡このようにswitch コマンドでは､オプションなしでリモートブランチに移動することができなくなっています｡ブランチなしでコミットを参照するのはよろしくないようです｡

ということで､HEADは現在のブランチを参照するポインタだよという記事でした｡ここを覚えておけば初学の段階でHEADに躓くことはないと思います｡

以上､お疲れさまでした｡
SlackのEvents APIのリクエストをGASで処理するときに複数回実行される問題(3秒のタイムアウト)の対策

# 複数回実行とは？

[SlackBotに各人毎のGoogle MeetのURLを出してもらう](https://qiita.com/rh_taro/items/a7ff977e61ede6400e2d) で作ったSlackbotが
1回だけレスポンスを返す想定のはずがたまに2〜4回レスポンスを返してくることがありました

![スクリーンショット 2023-04-30 21.54.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236978/486a9822-370c-c60c-d598-08536be2d534.png)

実害はなかったので無視していたんですが
最近新しく作ったbotでは深刻な問題だったので調査した結果解消することができました

# 原因
Slackからのリクエストに対してレスポンスを返すのに3秒以上かかるとリトライされる仕様を考慮できていなかったためでした
スプシ内での行の探索する処理が行数増えると遅くなるような実装になっていて
開発時やリリース当初は気付けず、しばらくしてから問題が起きていました

ちゃんと[公式ドキュメント](https://api.slack.com/apis/connections/events-api#retries)を見れば書いてあるし
ググれば[Slack Events APIの再送仕様と回避方法まとめ](https://dev.classmethod.jp/articles/slack-resend-matome/) といった記事も出てくる

迷宮入りするような問題でもないのに2年以上放置するなんて怠惰ですね〜(自戒)

# 対処方法
処理の先頭でリクエストに含まれる `client_msg_id` をキーにしてキャッシュに値を入れて
2回目以降のりトライされたリクエストの場合(キャッシュヒットした場合)は処理をせずレスポンスを返すようにしました

```js
function doPost(e) {
  const contents = JSON.parse(e.postData.contents);
  
  // slackの3秒タイムアウトリトライ対策
  let cache = CacheService.getScriptCache();
  if (cache.get(contents.event.client_msg_id) == 'done') {
    return ContentService.createTextOutput();
  } else {
    cache.put(contents.event.client_msg_id, 'done', 600);
  }

  // 時間かかる処理
  .
  .
  .

  return ContentService.createTextOutput();
```

### なぜキャッシュなのか
- キューイングしてすぐにレスポンスを返すことをSlackは推奨しているが、GASでキューイングはめんどくさい
- リトライされたリクエストの場合ヘッダに `X-Slack-Retry-Num` がついてくるがGASではヘッダ検証できない

からです

以上！
CHATGPTに技術ブログについて語ってもらうただそれだけの記事

## 発端

下記の記事を拝読した時に感銘を受けました。

なるほど、ワイ記法か、と。←感銘を受けるところが違う。

https://qiita.com/Yametaro/items/1f096e08e7a387ae3792

ということでこちらを参考にしてCHATGPTで遊んでみました。

技術ブログが大切なことは知っているのですが、最初のデビュー作に悩んでいたのでまずはこんな話題から記事にさせていただきました！

ちなみに元記事はAIが書いた文章の比じゃないぐらい素晴らしいのでぜひ皆様も一緒に読みましょう！

私は、この方の作品「パパシリーズ」が好きすぎて中毒になるぐらい読んでしまっています。

## CHATGPTの出力の結果

では実際にCHATGPTに命令文を入力して技術ブログに語っていただきましょう。

### 命令文
これから、議題のテーマについて、AとBの二役でRPしていただき、対話形式で議論をしていただきます。議題のテーマと役割はそれぞれ下記のように設定しています。最終的な結論はお任せします。
議題のテーマ：エンジニアはどこで技術ブログを発信したら良いのか
役割（A)：技術ブログを推している関西口調のフロントエンドエンジニア
役割（B）：技術ブログを書く必要がないと感じている新人エンジニア


### 議論

分かりました。それでは、議論を開始しましょう。

A: そんなわけないやろ、ワイが言うとるやろ！技術ブログはエンジニアがスキルアップするために必要なんやで！

B: でも、技術ブログって書いても誰も見てくれなかったり、評価されなかったりすることもあるじゃないですか。それなら別に書かなくてもいいのではないでしょうか。

A: それは確かにあるかもしれんけど、だからって諦めることはできへんで。自分がやったことを文章にまとめることで、自分の理解度も深まるし、他の人にも役に立つ情報を提供できるやん。

B: でも、どこで発信したらいいかわからないんですよね。自分のブログを立ち上げるには時間もお金もかかるし、SNSだと技術ブログを見てくれる人も限られてしまいます。

A: そうやな、でも自分のブログを立ち上げるにしても、無料で使えるブログサービスもあるし、ワイも始めたばかりの頃はQiitaで記事を投稿してたで。Qiitaはエンジニアに特化したサイトやから、情報が共有されやすいし、いい練習にもなるで。

B: なるほど、Qiitaですね。でも、ブログを書くこと自体が苦手なんですよね。何を書いたらいいかもわからないし、書くのに時間もかかるし。

A: そうやな、でもそこはちょっとした工夫で乗り越えられるで。例えば、日々の業務の中で、自分が解決した課題や工夫した方法、新しい技術の勉強方法などを書くと、自然な形で記事になるで。また、自分の周りにいるエンジニアとの議論や意見交換も、記事にするネタになるで。

B: なるほど、確かにそういうことなら書けそうな気がしますね。でも、ブログを書くのに時間がかかるという問題はどうすればいいんでしょうか？

A: それは自分に合ったスタイルを見つけることが大事やで。例えば、ワイは普段からメモアプリに記事のアウトラインを書いておいて、時間がある時に文章を書いていくスタイルを取ってるんや。あとは、書くことに集中できる環境を作ったり、定期的に書く習慣をつけたりすることも大切やで。

B: なるほど、アウトラインを書いたり、環境を整えたりすることで、効率的にブログを書くことができるんですね。そう考えると、技術ブログを書くことも悪いことばかりではないですね。

A: そうやで、技術ブログを書くことは、自分自身のスキルアップにも繋がるし、他の人にも役に立つ情報を提供することができるんや。ブログを始めるには、まずは簡単な記事から始めて、自分なりのスタイルを見つけていくといいで。

B: なるほど、ありがとうございました。ブログを書くことに対して前向きに考えられるようになりました。


## まとめ

うん。
Spring Boot でストリーム(SSE)対応する Azure OpenAI Service の API サーバを実装する

# 背景
- 社内で ChatGPT のようなサービスを展開したい
- OpenAI の API と互換性がある Azure OpenAI Service を使いたい
    - 以下 AOAI
- フロントの UI がオープンソースで複数公開されているが、API キーを入力するものが多い
- 社内で展開する場合、API キーは隠蔽したい
- フロント>実装するAPIサーバ>AOAI API とう構成でバックエンドに API キーを隠蔽
    - 中継 API サーバを立てるイメージ
- APIサーバを実装する際、ストリーム(SSE)対応したい
    - それにより、レスポンスが徐々に生成される UX を実現できる

# 手順
## Spring Boot プロジェクトの新規作成
- https://start.spring.io/ を開き、Dependencies に「Spring Reactive Web」を指定
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517184/99fb5541-b50f-9c84-d2c4-91138f54354a.png)

- または build.gradle などに `spring-boot-starter-webflux` を指定
    ```gradle
    dependencies {
    	implementation 'org.springframework.boot:spring-boot-starter-webflux'
    }
    ```

## ストリーム対応する AOAI の API を実行するためのクライアント準備する Config を作成
```java:Config.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class AppConfig {
	@Bean
	public WebClient webClient() {
		return WebClient.builder().build();
	}
}
```

## フロントからのリクエストを受け取り、AOAI の API を実行するコントローラを作成
```java:Controller.java
package jp.co.saison.chatbackend.controller;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;

@RestController
@CrossOrigin(origins = "${app.allowedOrigins}")
public class CompletionsController {
	private final WebClient webClient;

	public CompletionsController(WebClient webClient) {
		this.webClient = webClient;
	}

	@PostMapping(value = "/api/completions", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
	public Flux<String> completionsForStream(@RequestBody String body) {
		Flux<String> responseFlux = webClient.post()
				.uri("Azure OpeanAI サービス API のエンドポイント")
				.contentType(MediaType.APPLICATION_JSON)
				.header("api-key", "APIキー")
				.bodyValue(body)
				.retrieve()
				.bodyToFlux(String.class);
		return responseFlux;
	}
}
```
- フロントからのリクエストボディは stream が true であることが前提
    - https://learn.microsoft.com/ja-jp/azure/cognitive-services/openai/reference?source=recommendations#chat-completions
- 戻り値の型は `Flux<String>` とする
- `produces = MediaType.TEXT_EVENT_STREAM_VALUE` も指定
備忘録:SvelteKitで今いるURLを取得する

# 公式ドキュメント
https://kit.svelte.jp/docs/modules#$app-stores

SvelteKitではモジュール(Modules)と呼ばれている機能で、いろいろな便利情報が取得できて、$app/storesのpageを使うとURL周りの情報が取得できる。

# 結論
```svelte
<script lang="ts">
	import { page } from '$app/stores';
</script>
あなたはいまここにますよ：{$page.url.href}
```
こんな感じ。

公式ドキュメントに書かれている通り、サブスクライブしないといけないので importはpageだけど使う時は$pageです。

他にも、公式ドキュメントの[page](https://kit.svelte.jp/docs/modules#$app-stores-page)や[型情報](https://kit.svelte.jp/docs/types#public-types-page)のところに一部書いていますが、

| 変数               | 例                                                                           |
| ------------------ | ---------------------------------------------------------------------------- | 
| $page.params.id    | c1f0fe78-0dee-45a0-a2b3-4caaf7b0b6eb                                         | 
| $page.route.id     | /works/programming/[id]                                                      | 
| $page.url.href     | http://localhost:5173/works/programming/c1f0fe78-0dee-45a0-a2b3-4caaf7b0b6eb | 
| $page.url.origin   | http://localhost:5173                                                        | 
| $page.url.host     | localhost:5173                                                               | 
| $page.url.hostname | localhost                                                                    |
| $page.url.port     | 5173                                                                         | 
| $page.url.pathname | /works/programming/c1f0fe78-0dee-45a0-a2b3-4caaf7b0b6eb                      | 

みたいな感じで取れます。


# おまけ

ちなみに$pageを覗いてみると
```
{
  error: null,
  params: { id: 'c1f0fe78-0dee-45a0-a2b3-4caaf7b0b6eb' },
  route: { id: '/works/programming/[id]' },
  status: 200,
  url: URL {
    href: 'http://localhost:5173/works/programming/c1f0fe78-0dee-45a0-a2b3-4caaf7b0b6eb',
    origin: 'http://localhost:5173',
    protocol: 'http:',
    username: '',
    password: '',
    host: 'localhost:5173',
    hostname: 'localhost',
    port: '5173',
    pathname: '/works/programming/c1f0fe78-0dee-45a0-a2b3-4caaf7b0b6eb',
    search: '',
    searchParams: URLSearchParams {},
    hash: ''
  },
  data: {
    //略
  },
  form: null
}
```

こんな感じ。

routeではディレクトリの構造がそのまま出てくるので、例えば(guest)みたいな[groupディレクトリ分け](https://kit.svelte.jp/docs/advanced-routing#advanced-layouts-group)しているとそのディレクトリ名もそのまま出てくる。
Web技術の基礎的なところを復習してみた

プログラミングやアプリ開発についての勉強をしてはいるが、そもそもどのようにWebサービスが動いているかなど、まだまだ理解が足りないと感じたため、Web技術の基礎的なところを復習してみた。

そもそものWebの用途としては、下記が一般的である。
## 文書の閲覧

1つのドメインにある複数のWebページの集まりをWebサイトと呼んでいる。
ユーザーはハイパーリンクをたどることで文書を読むことができる。

## ユーザーインターフェース
ユーザーインターフェースとは、コンピューターの機能とユーザーのやりとりの橋渡しをする機能のことをいう。

## プログラム用API
ユーザーインターフェースに対し、ソフトウェア同士のやりとりと橋渡しをする機能をAPIと呼ぶ。
    例えば、天気予報アプリだとアプリが送信した地域情報をプログラム用APIの役割を持つWebサーバーが受け取り、Webサーバーは受け取った地域情報に対応する天気予報のデータをアプリに返す。
Object[] o = new String[2]

# これは何？

Java に関する素朴な疑問についての考えをメモしたもの

# 気になること

Java は当初より、そして今でも

```java:java
Object[] o = new String[2];
```

がコンパイルエラーにならない。
このあと

```java:java
o[1]=new Integer(1);
```

などとしたら **実行時**エラーになる。
そんなのおかしいだろと思うけれど、昔からそうで、今でもそうだと思う。

`ArrayList` を作った時代には、基底クラスを要素型にするコンテナにキャストできるのはおかしいと気づいたようで、

```java:java
ArrayList<Object> ao = new ArrayList<String>();
```

はエラーになるんだけど、配列の動作は変えられなかったのか、今でもエラーにならない。不思議。
気づいているのなら「次の次のバージョンでコンパイルエラーになるよ。まだ警告で済ますけど」とかいう対応すればよかったのにと思う。

## なんでこれが嫌なのか

そのまんま

```java:java
Object[] o = new String[2];
```

と、文字通り書いてあったらそれはちょっと奇妙なことと思うけれど、たとえば

```java:java
class Foo{
  static Object[] bar(int size){ /*不明*/ }
  static bar(Object[] o){ /*不明*/ }
}
```

で

```java:java
Object[] o = Foo.bar(2, "String");
if (0<o.length){
  o[0]="hoge";
}
```

のようなものや

```java:java
String[] s = new String[2];
Foo.baz(s);
```

が実行時エラーになるのは困る。
実行時エラーになるかどうかは、型から知ることができない。
そして、言語が頑張ればコンパイルエラーにできることが知られているので

* なんで最初にこの選択をしてしまったんだろう
* なんで放置してるんだろう

という疑問を持っている。

「なんで放置してるんだろう」については。

もちろん言語仕様の破壊的変更なのでサクッと変更するわけにはいかないわけだけど、言語仕様の破壊的変更をユーザーが困らないようにやる方法は、JavaScript の `'use strict';` など、わりと古来より知られている。

型システムの穴なんだから、塞げばいいのに。と思っている。

# C++ では

Java は C++ の強い影響を受けているので、C++ を見てみると。

C++ ではそもそも配列は左辺値になれない。
`std::vector` は、要素型に継承関係があっても `std::vector` 自体は無関係という点では `ArrayList` と同じ。

テンプレートなしで `Object[] o = new String[2];` と似たようなことをしようとすると:

```c++:c++
struct base { 略 };
struct dA : public base { 略 };
struct dB : public base { 略 };
```

として、

```c++:c++
dA da[2] = {略};
base * b0 = da; // これはコンパイルエラーにならない
base (&b1)[2] = da; // コンパイルエラー
```

という感じかな。
`b0` がエラーにならないのは C++ が悪いと言うより C言語の呪い（配列がポインタ経由でしかアクセスできないという仕様）から逃れられないのが原因かなと思う。

しかし、Java の Object や String は参照型なので、どちらかというと以下の感じかなと思う。

```c++:c++
dA * da[2] = {略};
base ** b0 = da; // コンパイルエラー
base *(&b1)[2] = da;// コンパイルエラー
```

これは C++ でもエラーになる。

そう思うと `Object[] o = new String[2];` を合法にしようと思った気持ちが全然わからない。

## 反変と共変

C++ の継承のロジックに 反変と共変 が入ったのはいつなんだろう。
手元の The Annotated C++ Reference Manual (1990年ぐらいの本）には反変と共変は入ってなさそう。C++98 で入ったっとすれば、 Java の人たちが気づいていないのは仕方ないと言えるかもしれない。

# C#

Java を見ながら作った C# も
`Object[] o = new String[2];` はコンパイルエラーにならず、このあと
`o[1]=3;`
などとすると **実行時** エラーになる。

なぜそういう選択をしたんだろうか。
Java に合わせたんだろうか。とても不思議。

# まとめ

特にまとめるべきことはない。

とても不思議。
ExpansionPanelListとflutter_hooksを使用して簡単に状態管理をする

ここではHookWidgetを継承したクラス、OriginalPanelを定めます。

```original_panel.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

class OriginalPanel extends HookWidget {
  final String title;
  final Widget icon;
  final List<Widget> children;
  const OriginalPanel({Key? key,required this.title,required this.icon,required this.children}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final isExpandedNotifier = useState(false);

    return ExpansionPanelList(
      expansionCallback: (int index, bool isExpanded) {
        isExpandedNotifier.value = !isExpanded;
      },
      children: [
        ExpansionPanel(
          headerBuilder: (BuildContext context, bool isExpanded) {
            return ListTile(
              leading: icon,
              title: Text(title),

            );
          },
          body: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16.0),
            child: Column(
              children: children,
            )
          ),
          isExpanded: isExpandedNotifier.value,
        ),
      ],
    );
  }
}

```
GitHub Actionsでレンタルサーバにsshしてpullする方法

ここ数日で大量にGitHub Actionsを用いたphpファイルの自動デプロイを行っていました。特に1つのサーバで複数の自動pullは試行錯誤したので、備忘録として残そうと思います。少しでも役に立てれば幸いです。

# 仕様
・Ubuntu18.04
・レンタルサーバ(無料枠内でOK)
　└ hoge.com
　└ special.hoge.com
・GitHub

# 手順（準備）
初めに、必要なファイルを作成します。
私のように、一つのサーバで複数のホームページを運用したい場合などは、GitHub Actionsをしたいプロジェクトの数だけ鍵を作成するようにしましょう。

・公開鍵と秘密鍵

```
$ssh-keygen -t rsa
Generating public/private rsa key pair. 
Enter file in which to save the key (~/.ssh/id_rsa): id_rsa_hoge #指定せず[Enter]を押すと（）内のファイル名になります。
Enter passphrase (empty for no passphrase): [Enter]
Enter same passphrase again: [Enter]

$ssh-keygen -t rsa
Generating public/private rsa key pair. 
Enter file in which to save the key (~/.ssh/id_rsa): id_rsa_special_hoge
Enter passphrase (empty for no passphrase): [Enter]
Enter same passphrase again: [Enter]
```

・config
```
Host github-hoge
    hostname github.com
    user git
    Identify ~/.ssh/id_rsa_hoge

Host github-special-hoge
    hostname github.com
    user git
    Identify ~/.ssh/id_rsa_special_hoge
```

次に、.ssh/authorizationに公開鍵を追記しておきます。
```
$cat ~/.ssh/id_rsa_hoge.pub >> ~/.ssh/authorization
$cat ~/.ssh/id_rsa_special_hoge.pub >> ~/.ssh/authorization
```

次に、サーバでpullしたいディレクトリなどを決め、cloneしていきます。
Gitのインストールは下記コマンド。

```
$sudo apt install git
```

なお、cloneする場合は保存先ディレクトリ（公開しているホームページのディレクトリ）は空にする必要があるため、WinSCPなどでファイルをバックアップしておいてください。

```
$git clone git@github.com/[userName]/[projectName].git [deployDirectory]
```

例えば、Godというユーザが作成した場合は、下記のようになります。

```
$git clone git@github.com/God/hoge.git ~/hoge.com
$git clone git@github.com/God/special.hoge.git ~/special.hoge.com
```

ディレクトリを指定しなかった場合は、現在居るディレクトリにプロジェクト名でフォルダが作成されます。

# 手順（GitHub Actions）

まず、デプロイ（サーバにpullしたいプロジェクト）したいプロジェクトで環境変数と公開鍵の設定を行います。
```
PORT=22
HOST=[サーバのIPアドレス]
HOST_NAME=[サーバのユーザ名]
PRIVATE_KEY=[秘密鍵をコピー]
```

※秘密鍵の貼り付けですが、改行を\nに置き換えて１行にする方法もありますが、私はwindows標準搭載のメモ帳からのコピペで動きました。なので下記のようになります。
```
-----BEGIN OPENSSH PRIVATE KEY-----↓
*******************↓
-----END OPENSSH PRIVATE KEY-----↓
[EOF]
```

環境変数の設定が終わったら、次に公開鍵を設定します。
→Deploy Key

ここまでで設定は終わりです。次にGitHub Actionを作成します。

```yml:manual.yml
circle: deploy
build

```

さて、いよいよテストです。
pushして動くか試してみましょう。もしエラーが出る場合はサーバに戻ってgithubへログインできるか確認してみます。

```
$ssh -T git@git-hoge
Hello git@github.com:God/hoge.com.
```

これでうまくいかない場合はサーバのファイアウォールの確認や、エラー文をネットで検索してデバッグしてください。

# ~Fin~
これで1つのサーバから複数のホームページでも自動的にpullできるようになり、開発がとても容易になりました。

# 参考文献