OmniAICreator/Qiita-1.07M huggingface dataset:
KotlinでMockitoを使用したとき、Mockito.any() must not be nullエラーが発生する

Kotlinの実装のユニテでMockitoを使用したときに、表題のエラーでハマってしまったので、解決法を記事化しました。
## エラーの内容
```
java.lang.IllegalStateException: Mockito.any() must not be null
```
- Mockito は`any()`のようなメソッドの呼び出しに対して`null`を返しますが、Kotlinではデフォルトでnullが許容されないため上記のようなエラーが発生してしまいます。
- 上記の問題は、`mockito-kotlin`を導入することで解決できます。

## mockito-kotlinの導入
- `build.gradle.kts`に依存関係を追加
```kotlin
testImplementation("org.mockito.kotlin:mockito-kotlin:5.0.0")
```
## mockito-kotlinの使用方法
- モックの作成方法
```kotlin
val mock : MyClass = mock()
```
- スタブの作成方法
```kotlin
mock.stub { on { stringValue() } doReturn "test" }
// or
given(mock.method(any())).willReturn("hoge")
```
- メソッド呼び出しの検証
```kotlin
verify(myClass, times(2)).doSomething(any())
```
- Argument Matchers
```kotlin
verify(myClass).setItems(argThat { size == 2 } )
```
- Argument Captors
```kotlin
val messageCaptor: ArgumentCaptor<String> = ArgumentCaptor.forClass(String::class.java)
argumentCaptor<String>().apply {
  verify(myClass, times(2)).setItems(capture(messageCaptor))
  assertEquals("test", messageCaptor.value)
}
```

## (余談) KotlinでMockitoを用いる際の、final classに関する注意点(バージョン`4.x.x`以前の場合)
- Kotlinではデフォルトで全てのクラスがfinal classとなリますが、バージョン`4.x.x`以前のMockitoはデフォルトでfinal classをモックできないため、下記のようなエラーが発生してしまいます。
```
Mockito cannot mock/spy because :
 - final class
```
- 上記の問題点については、以下のいずれかを実施すれば解決できます
  1. `mockito-core`または`mockito-kotlin`のバージョンを`5.0.0`以上に上げる
      - `5.0.0`以上のバージョンでは、デフォルトでfinal class/method のモックをサポートするようになったため。
  2. `mockito-core`の代わりに、final class/methodのモックをサポートする`mockito-inline`を依存関係に含める。`mockito-kotlin`を使用している場合は、`mockito-inline`を依存関係に含める
  3. `src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker`ファイルを作成し、`mock-maker-inline`と記載し、final class/method用のモックメーカーを明示的にアクティブ化する。

## まとめ
- Kotlinでは、Javaと同じようにはMockitoを使えない箇所がありますが、基本的に`mockito-kotlin`のバージョン5以降を使うことで解決できそうです

## 参考文献
- https://github.com/mockito/mockito-kotlin/wiki
- https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
[UE5]DownloadImageでパスに半角スペースが入ったファイルが読み込めないときの対処法

＃ はじめに

UE5でDownload Imageを使いローカルPC内の画像をテクスチャ化するときに、ファイルパスに半角スペースが入っているせいで読み込めないという事象がありました。
その時の対処方法のメモです。

UE4.27の頃はパスに半角スペースが入っていてもそのまま読み込めていたので、UE5で挙動が変わったようです。

# 環境

Windows 11
Unreal Engine 5.2.1

# 対処方法

半角スペースを「%20」に置換することで読み込めるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668217/6a0f1489-721a-2380-f211-4f2bc01ba88d.png)

余談ですが、DownloadImageを使ってローカルPC内の画像を読み込むときは、上記画像のようにパスの先頭に「file:///」をつけると読み込めるようになります。

さらに余談ですが、半角スペースを「%20」に変換するようなことを「URLエンコード」とか「パーセントエンコーディング」と呼ぶらしいです。

https://wa3.i-3-i.info/word13354.html

# 参考記事

https://historia.co.jp/archives/8949/
curlコマンドでRangeを指定して少しずつダウンロードするスクリプト

# はじめに
業務で必要だったので、ChatGPTに聞きながら作ってみました。

# 環境
- Almalinux8

# スクリプト
ヘッダを見ることが目的だったので、ダウンロードしたコンテンツは全部、`/dev/null` に捨ててます。
定数 `FILE` にファイル名を指定することでファイルとして保存することもできます。

```bash
#!/bin/bash

URL="http://example.com/example.bin"   # 取得したいコンテンツのURLを指定
PROXY="http://192.168.1.1:8080/"
FILE="/dev/null"
RANGE_SIZE=100000000

TMP_FILE="templa"

# コンテンツのサイズを最初に取得します
TOTAL_SIZE=$(curl -sI "${URL}" | awk '/Content-Length/ {print $2}' | tr -d '\r')

START_RANGE=0
END_RANGE=$((RANGE_SIZE - 1))

DOWNLOADED_SIZE=0

download_content() {
	range_header="Range: bytes=${START_RANGE}-${END_RANGE}"
	curl -v -o "${TMP_FILE}" -H "${range_header}" -x "${PROXY}" "${URL}" 1>/dev/null
}

[ -f ${FILE} ] && rm -f ${FILE}

while [ $DOWNLOADED_SIZE -lt $TOTAL_SIZE ]; do
	download_content

	cat ${TMP_FILE} >> ${FILE}
	rm -f ${TMP_FILE}
	DOWNLOADED_SIZE=$((DOWNLOADED_SIZE + RANGE_SIZE))
	START_RANGE=$((END_RANGE + 1))
	END_RANGE=$((START_RANGE + RANGE_SIZE - 1))
done
```

# 注意事項
- HTTPしか試してません
[Oracle Cloud] 拡張メモリーVMでメモリやコアの追加設定を確認する

## はじめに

下記記事をベースに実際の設定画面を確認してみます
実際にインスタンスを作成出来ればよいのですが、リソースが極めて大きい為実際のデプロイは割愛します

https://blogs.oracle.com/oracle4engineer/post/oci-new-feature-highlight-20230517

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/0b80aae5-8f55-e957-27dc-000d3404f1dd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/666de4a5-422a-1e59-0f01-45e828ced7ca.png)

## 手順

こちらがコンピュートのコンソール画面です
「インスタンスの作成」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/a15a6f01-5686-1428-dc7e-0d60bfc09b67.png)

コンピュート・インスタンスの作成画面です
イメージとシェイプの箇所で「Change Shape」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/8e29c1ce-6dfd-4cb8-f27a-27d82e8080b9.png)

シェイプの選択画面です
この例では、E4が選択されています
注目すべきは、「OCPUの数」「メモリー量」の部分
Extended OCPU , Extended memory と表記があり、さらに大きなリソースを割り当てられるようになっています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/e8375d8b-93ff-ac33-b6cf-305dd44679d3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/ffcbf66b-0ac3-9f4a-9d02-871d6c2a35a5.png)

ちなみにiのマークをクリックすると下記のように表示されます

If the number of OCPUs is more than 64, the instance will become an extended memory VM.

If the amount of memory is larger than 1,024, the instance will become an extended memory VM.
AWS Cloud9におけるインスタンスプロファイルの利用(Proxy環境下)

あまりない構成だと思うが記載しておく

# 構成（環境）
- Cloud9を利用
- Cloud9が配置しているサブネットはインターネットに直接アクセスを行わないようにし、Proxy経由でインターネットにアクセスする
- Cloud9の`~/.bashrc`に以下のようにProxy設定をしている
- Cloud9はATMC(AWS AWS managed temporary credentials)を無効にしており、インスタンスプロファイルを利用している

```bash:~/.bashrc
export http_proxy=http://xxx.xxx.xxx:8080
export https_proxy=http://xxx.xxx.xxx:8080
```

# IAMロールのCredential情報がCloud9に引き継がれない
上記Proxyを設定している状態でCloud９にて`aws configure list`を実行するとインスタンスプロファイルからCredential情報が引き渡っていないことを確認

```config:aws configure listの結果①
Name           Value            Type           Location
---            ---              ---            ---    
profile        <not set>        None           None
access_key     <not set>        None           None
secret_key     <not set>        None           None
region         ap-northeast-1   config-file    ~/.aws/config
```

# インスタンスメタデータへのアクセスはProxy除外しなければならない
- `~/.bashrc`にてProxy設定をしていたが、インスタンスメタデータへのアクセスもProxy経由で取得しようとしていた為、接続できず、Credential情報が引き渡っていなかった。
- Proxy設定をいれている`~/.bashrc`にてNO_PROXYを追加しインスタンスメタデータへのアクセスはProxy経由にしないようにする

```bash:~/.bashrc
export http_proxy=http://xxx.xxx.xxx:8080
export https_proxy=http://xxx.xxx.xxx:8080
export NO_PROXY=169.254.169.254 # ←追加
```

- 除外設定を追加したところCredential情報が引き渡ってることを確認
```config:aws configure listの結果②
Name           Value            Type           Location
---            ---              ---            ---    
profile        <not set>        None           None
access_key     *****5GDH        iam-role
secret_key     *****VDI8        iam-role
region         ap-northeast-1   config-file    ~/.aws/config
```

# 参考記事
https://dev.classmethod.jp/articles/execute-aws-cli-with-iam-role-on-cloud9/

https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/credentials.html

# あとがき
インスタンスプロファイルのアクセスをすっかり失念していた。
郵便番号から「地名の読み方」を調べるLINEBotをMakeを使ってつくってみた。

**何かLINEBotでつくってみたい!**
-----------------------


お疲れさまです。沖縄在住、小売店勤務のものです。
今回あるきっかけでLINEBotを自分でもつくれることを知りました。
普段全然LINE自体使いませんが、Makeというものを使って
郵便番号から地名の読み方がわかるLINEBot作成に挑戦してみました。
仕事でサンプル発送や出張申請する時に使えたらいいなと思いました。


**使ったもの**
-------------
+ LINEBot https://developers.line.biz/ja/docs/line-developers-console/
+ Make https://www.make.com/en
+ 郵便番号検索API http://zipcloud.ibsnet.co.jp/doc/api

**できたもの**
---------------

![1コメント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3481572/ee222b82-4b3b-4925-02a7-d0da8633465d.png)
こんな感じで郵便番号7桁を入れると県名市町村の読み方がわかるものがなんとかできました

![2コメント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3481572/0d6e220f-b0ab-4c4b-8a49-9fe1141231b3.png)
郵便番号がないところは「存在しません」という返答のパターンもなんとかできました。

**Makeのシナリオ**
![4コメント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3481572/11851241-ef7c-ea68-c058-355e4de93c14.png)
HTTPのモジュールに郵便番号番号APIを入れて、JSONのモジュールに基本の構造をGenerateで解析してもらいました

:::note info
使った郵便番号API　zipcloud
http://zipcloud.ibsnet.co.jp/doc/api
JSONはこんな感じになっていました
![5コメント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3481572/6bf8170b-85eb-047b-cc77-e35da3b451d4.png)
:::

勉強したお天気APIのやつを参考にして、
郵便番号ありなし判断の分岐Router付けれました。
![3コメント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3481572/e329fd75-7204-b39d-64b6-22eacfc14067.png)
上の方のモジュールのSet up a filterをExistsにして、下の方をyesにしました。
![4コメント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3481572/89ff9919-6611-5271-d211-e5bc3082edf2.png)
![5コメント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3481572/93f1f352-739f-4b11-0377-db0154644fe1.png)


**謎…**
-------------

できたと思って安心していたら謎が出てきました。
先日に出張で北海道と千葉に行ったので入れてみたら
![3コメント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3481572/7d3ed5d9-32df-8353-9737-0a1b6bbd231a.png)
先月行った場所なんですけど、なんででしょうか出ないです

HTTP・JSON・Replyのどれかで何か間違ったのだろうかと
何回か確認しなおしてもよくわからない。。。
サイトで千葉と北海道の郵便番号を試しに入れてみました
![6コメント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3481572/48936189-1157-44bd-7bbb-f651f234d785.png)

なぜか調べようと思ったのですが、仕事のタイミング上一旦ここで終了しました。

**やってみて**
-----------------
海外サッカーの試合結果選手情報がわかるAPIを見つけたので、
最初はこれを使ってつくろうと思っていました。
ただサイト登録とAPIキーの取得？が必要らしく、
いろいろ調べてもよくわからない。

次に、グーグルスプレッドシートを使ったものをつくろうとしました。
ただそもそもグーグルドライブを使ったことがなかったので、
これも調べるだけでただただ時間だけが過ぎていくばかり。。。
1個わからないことがあって調べたら、それ以上にわからないことが出てくるし
用語も聞いたことがないのばっかりでなかなか進まない。。。

まずは「何かつくることが大事」ということを自分に言い聞かせて、
郵便番号でやってみました。
とにかくやってみる精神でこれから他にもやってみたいと思います。
ご覧いただきありがとうございました。
ruby.wasmでひらがなの書き方を練習する紙を印刷するアプリケーションをつくりました

https://ledsun.github.io/kakikata/

## どんなアプリケーション？

ひらがなの書き方を練習する紙を印刷するためのアプリケーションです。

## なんでつくったの？

社内でアプリデプロイチャレンジというイベントがありました。
このイベントをきっかけに作りました。

## 特徴

### 印刷したらA4にぴったり

印刷して使うことを想定しています。
ブラウザの表示内容は印刷するとくずれがちです。
A4用紙にあわせて印刷出来ます。

### フォントが教科書体

日本語になれていると気がつきませんが、
書き方の初学者にはOSのデフォルトフォントの書体は難しいです。
読みやすくはあるのですが、クセがあるため学習上は問題になります。

たとえばメイリオの「ふ」はこのような字体です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15964/fc563048-3f2d-3492-1dc6-4cff4f6ab12a.png)

字の練習用としてみると次のように不自然な点があります。

- 1画目が水平すぎる
- ハネがない
- 3画目が反っている





教科書体を採用しました。
具体的にはGoogleフォントを使って[Klee One](https://fonts.google.com/specimen/Klee+One)を表示しています。

Klee Oneの「ふ」はこのような字体です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15964/04d9b4a9-56d7-2c22-8e24-4214102e2b8c.png)


## どんなところで苦労した？

### A4用紙

現代ではスタイルシートでA4が指定出来るのです。
実は簡単でした。

```css
@page {
  size: A4 portrait;
}
```

### 縦書き

これもスタイルシートで指定出来るので簡単です。

```css
.content {
  writing-mode: vertical-rl;
}
```

### 色

文字色を灰色に設定すると、黒字で印刷されることがあります。
文字色に透過を設定すると薄く印刷されます。

```css
.content {
  color: rgba(238, 238, 238, 0.496);
}
```

### 十字の点線

ChatGPTと相談したところ、before/after要素でボーダーを表示すると実現出来ました。

```css
.charactor::before,
.charactor::after {
  content: "";
  position: absolute;
  border: 1px dashed cyan;
  z-index: 1;
}

.charactor::before {
  width: 0;
  height: 100%;
  left: 15mm;
}

.charactor::after {
  width: 100%;
  height: 0;
  top: 15mm;
}
```

## 動作

一文字ずつ四角で囲ってあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15964/986f343f-f7f7-809c-3102-fd68035b683f.png)

四角はdivでレンダリングされています。

```html
<div class="charactor">
  <span>
    も
  </span>
</div>
```

文字列を分割して、divで囲って、HTMLとしてレンダリングするロジックがあります。
このロジックをRubyで書いています。
[ruby.wasm](https://github.com/ruby/ruby.wasm)をつかってRubyをブラウザ上で動かしています。


## ruby.wasmに合ってたところ

### ERB

HTMLのレンダリングにERBが使えるのが便利です。
たとえば前述のdivは次のようにレンダリングできます。

```ruby
template = ERB.new(<<~'END_HTML')
  <div class="charactor">
    <span>
      <%= charactor %>
    </span>
  </div>
END_HTML

template.result_with_hash charactor: 'も'
```

### サーバーがない

このアプリケーションはサーバーなど外部と通信をする必要がありません。
ruby.wasmが苦手なところを扱わないですみました。

## 改善したい点

次の点を改善したいと思っています。

### スマートフォンで見たときの初期表示

スマートフォンで開くと、画面の横幅をはみ出して表示されます。
拡大縮小できるので、使えなくはないですが、少し不便です。

### クエリストリング

印刷する文章はランダムで表示している初期文章か、input要素で入力した文章です。
クエリストリングで指定できるようにすると、シェアしやすくなって良さそうだと思っています。


## 参考


- [A4サイズ1ページに収まる印刷用のCSSを書く - Qiita](https://qiita.com/e-sato/items/68470a4203f6abfaa801)
- [CSSで文章を縦書きにする方法をご紹介！ - WEBCAMP MEDIA](https://web-camp.io/magazine/archives/103632)
Spring Securityのtokenチェック

Spring Securityは、アプリケーションのセキュリティを強化するためのフレームワークです。
その中でも、トークンチェックは重要な機能の一つです。

トークンチェックの目的は、ユーザーがアプリケーションにアクセスする際に提供されるトークンが有効かどうかを確認することです。具体的には、以下の目的があります

1 認証の強化：トークンチェックにより、ユーザーが正当な認証情報を持つかどうかを確認することができます。有効でないトークンを持つユーザーは、アプリケーションへのアクセスを制限されます。
2. セッション管理：トークンチェックにより、アプリケーション内でユーザーのセッションを管理することができます。有効なトークンを持つユーザーに対しては、セッションを確立し、アクセス制御やセッションタイムアウトなどのセキュリティ機能を提供します。
3. アクセス制御：トークンチェックにより、ユーザーがアプリケーション内の特定のリソースや機能にアクセスできるかどうかを制御することができます。有効なトークンを持つユーザーに対しては、許可された範囲内でのみアクセスを許可します。
トークンチェックは、アプリケーションのセキュリティを強化し、悪意のあるアクセスや情報漏洩を防ぐために重要な役割を果たします。
社内ドキュメントとChatGPTを連携させて分かったこと (Azure OpenAI, Cognitive Search)

## はじめに

最近はAzureで[Add your data](https://learn.microsoft.com/ja-jp/azure/cognitive-services/openai/use-your-data-quickstart?tabs=command-line&pivots=programming-language-studio)機能が登場するなど、ちょっと今更感もありますが備忘録も兼ねて記事にしました。
ベースとしてMicrosoftの[サンプルデモ](https://github.com/Azure-Samples/azure-search-openai-demo)を使っています。
- あくまで個人的な所感です:writing_hand:
- 基本的なアプリ構築方法や機能の詳細については公式のサンプルデモの方に記述があるため、割愛させていただきます:pray:


## 1. インデックス作成時にはチャンクを細かくする

インデックス作成時には、出典（Citation）とインデックス（Supporting content）の内容が乖離するのを避けるために、チャンクを細かくすることが大事です。
元のサンプルデモは英語PDF向けですが、日本語PDFの場合、チャンクサイズがそのままだと回答内容と出典のページ数がズレてしまう問題が発生しました。
チャンクを細かくするとChatGPTのトークン数制限にも対応できるし、一石二鳥ですね。（もしモデルとしてGPT-4が使えるのであれば、トークン数についてはそこまで気にしなくてもいいのかも。）

::: note info
消費トークン数の合計は、
システムロール + 質問内容 + ChatGPT回答 + 参照インデックス*$n$ + 履歴（チャット形式の場合）
となるため、主にユースケースに応じて、システムロール、参照するインデックスの数 $n$ 、チャット履歴の長さを調整することになると思います。
:::


## 2. とりあえずの日本語対応は意外と簡単

元々ChatGPT自体が多言語で使えることもあり、サンプルデモの日本語対応はそこまで負担ではありません。
システムロールを修正したり、チャンクやセンテンスの区切り文字を日本語向けにしたり、Azure Cognitive Searchのアナライザーを変更したぐらいです。

::: note warn
厳密な日本語対応をするとなると、また話が変わってくるのかもしれません。
（文章の区切りを形態素解析で判別するとか）
:::


## 3. やっぱり具体的・明示的な質問がベスト

具体的な質問をすると、良質な回答と出典が得られる印象です。
逆にアバウトな質問だと、例えば該当するソースがいくつかある場合に、ChatGPT的にはどちらの情報を提供すればいいか分からず回答の質が下がります。

例えば「海外出張時の宿泊費」について質問したい場合に、単純に宿泊費について聞くと、
![before.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327096/8503eda7-a9e8-4a62-897f-d40653147b78.jpeg)
国内出張に関する回答が返ってきてしまいました…:innocent:
以下のように質問すれば、所望の海外出張に関する回答が得られます。
![after.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327096/762d1b83-8f48-f759-8476-ae0ea153d841.jpeg)

::: note info
この辺はプロンプトエンジニアリングの話題になってしまいますが、質問内容の粒度として最低限「〇〇における△△について教えて。」程度は必要だと思いました。
:::


## 4. 「厳密な出典の要求」と「回答の容易さ」はトレードオフ

当然ですが、システムロールで出典の要求を厳密にすると、ChatGPTが回答しない場合が増えます。
例としては、
```
システムロール：回答内容の全てに出典を紐づけてください、出典が不足する場合は回答しないでください。
ユーザ質問：就業規則について教えてください。
ChatGPT回答：わかりません。
```
といった具合ですね。

::: note warn
このあたりはトレードオフなため、導入するユースケースに応じて柔軟に調整する必要があるかと思います。
:::

## おわりに
以上が、社内ドキュメントとChatGPTを連携させる際に分かったポイントです。
個人的な所感を多々含んでますが、どなたかの参考になれば幸いです。


### 参考文献
https://github.com/Azure-Samples/azure-search-openai-demo
https://qiita.com/nohanaga/items/803c09b5a3a4e2d1776f
https://qiita.com/nohanaga/items/a3e236fdbb3ef5878012
[Oracle Cloud] ファイル・ストレージでポリシーベースのスナップショット設定をする

## はじめに

下記記事をベースに設定を実際に行ってみる

https://blogs.oracle.com/oracle4engineer/post/oci-new-feature-highlight-20230614

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/14acc567-6697-fd9c-a70b-d500ebbec2cd.png)

## 手順

用意したファイル・システムを使用していきます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/c5abb194-c96a-4a9a-05fb-91056bd95667.png)

こちらに基づいてスナップショット・ポリシーを作成します
「追加リソース」の「スナップショット・ポリシー」を選択
「スナップショット・ポリシーの作成」をクリック

https://docs.oracle.com/ja-jp/iaas/Content/File/Tasks/snapshot-policy-create.htm

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/af57a186-5e6c-1fd6-dc57-cc9c0d733185.png)

必要事項を入力
「作成」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/b22570a2-41a6-5d44-75f0-3f3070e9b846.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/fea18c62-4f79-c940-f0cc-cca767878c02.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/c781b9e9-5d1b-d07f-0cf1-77ed3b292471.png)

スナップショット・ポリシーが作成されました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/edb73376-582e-7154-62cd-b0f68571065c.png)

ポリシーを関連付けていきます
「関連付けられたファイル・システム」をクリック
「ファイル・システムのアタッチ」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/9119851b-23ab-0907-3092-9744cf67aaaf.png)

対象を選択して、「ファイル・システムのアタッチ」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/c479e9ea-d5c8-ef69-d2eb-6d3e2181718f.png)

アタッチ完了です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/2b69c81f-ba84-bfea-037d-20adfd890ce7.png)

設定はこれでおしまいです
数日於いて正しくスナップショットが作成されるか確認してみたいと思います
RESAS API使い方メモ

# 初めに
ゼミの研究発表の為に、人口データが必要になったのでRESASのAPIを使って市町村ごとの人口データ取得しました。その方法をまとめてご紹介します。

**目次**
- APIキーの取得
- 都道府県コードの取得
- 市区町村コードの取得
- 人口構成データの取得
- 人口ピラミッドの取得

# APIキーの取得
公式サイトに登録をしてAPIキーを取得します。
[RESAS API公式サイト](https://opendata.resas-portal.go.jp/)
![スクリーンショット 2023-07-05 132025.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3482837/df388580-524c-5c7c-d965-ca0eb5e1591c.png)
下はRESAS-APIの仕様書のリンクです。
[RESAS-API仕様書](https://opendata.resas-portal.go.jp/docs/api/v1/index.html)

# 都道府県コードの取得
都道府県コードを指定することで、都道府県を指定することができます。
その為に必要な都道府県コード一覧をAPIを使って取得します。
```Python
import requests

api_key = "取得したAPIキーを入れてね"
headers = {"X-API-KEY": api_key}
```
```Python
response = requests.get("https://opendata.resas-portal.go.jp/api/v1/prefectures", headers=headers)
data = response.json()
```
![スクリーンショット 2023-07-05 133409.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3482837/35725be2-7db8-2887-47fa-d11d9f647f6f.png)
黄色でマーカーを引いた数字の部分が都道府県コードです。
都道府県コードを**prefCode**
市区町村コードを**cityCode**
といいます。

今回指定したURLは
![スクリーンショット 2023-07-05 133955.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3482837/5708d7fb-cb02-f1ea-0164-4360fed019d8.png)
都道府県一覧のsampleにURLがあります。

# 市区町村コードの取得
研究内容の関係で、熊本県の市町村コードを取得します。
熊本県の都道府県コードは43です。
```Python
# Make a GET request to the API endpoint
response = requests.get(" https://opendata.resas-portal.go.jp/api/v1/cities?prefCode=43", headers=headers)

# Process the response
data = response.json()
```
URLのprefCodeに43を指定しています。
![スクリーンショット 2023-07-05 134545.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3482837/eef3f5fb-b199-be8b-6c48-ea621f50a79b.png)
熊本市のcityCodeが43100であることがわかります。

今回指定したURLは
![スクリーンショット 2023-07-05 134742.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3482837/56694569-92ce-c2fe-a5c8-e4236c280769.png)
市町村一覧のsampleにURLがあります。

# 人口構成データの取得
cityCodeに43100、prefCodeに43を指定することで
熊本県熊本市の人口構成データが取得できます。
```Python
response = requests.get("https://opendata.resas-portal.go.jp/api/v1/population/composition/perYear?cityCode=43100&prefCode=43", headers=headers)

data = response.json()
```
![スクリーンショット 2023-07-05 135223.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3482837/be4a305d-cad7-7b49-10e4-b7947fc3b01f.png)
データの中身
総人口、年少人口、生産年齢人口、老年人口が1985～2045まで5年ごとに入っています。また、valueとrateで人数と割合がわかります。実績値は2020年まで、それ以降は推計値です。

sample URLは人口構成の所にあります。

# 人口ピラミッドの取得
cityCodeに43100、prefCodeに43を指定することで
熊本県熊本市の人口ピラミッドを取得できます。
```Python
response = requests.get("https://opendata.resas-portal.go.jp/api/v1/population/composition/pyramid?cityCode=43100&yearRight=1990&prefCode=43&yearLeft=2020", headers=headers)
data = response.json()
```
![スクリーンショット 2023-07-05 140055.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3482837/5fc97bed-1a16-28f5-365e-45435f911dc5.png)
地域単位、年単位の人口ピラミッドデータを返します。
1980-2045年（5年毎）で実績値は2020年まで、それ以降は推計値。

sample URLは人口ピラミッドの所にあります。

# 終わりに
RESAS APIの使い方をまとめてみました。
少しでもお役に立てると嬉しく思います。
【Rails】kaminariを使ってページネーションする

# 1. kaminariのインストール
ページネーションを導入するためにkaminariというgemをインストールする。
```Gemfile
gem 'kaminari'

→　bundle install
```
Gemfileにkaminariと記入し、bundle installする。
（gemをインストールした後は一度サーバーを再起動しないとうまく読み込まれない。
Ctrl-cでサーバを止め、$ rails sでサーバーを起動する。）

# 2. ページネーションのデフォルトの設定ファイルを作成/編集
ターミナルにて、設定ファイルの作成コマンドを実施。
```
rails g kaminari:config
```
config/initializers/kaminari_config.rbを開くと、デフォルトでコメントアウトされた状態で入っているので、設定したいもののコメントアウトを外す。

```
# frozen_string_literal: true

Kaminari.configure do |config|
  # config.default_per_page = 25
　　　　　　　　1ページあたりの表示件数(デフォルトは25レコード）

  # config.max_per_page = nil
　　　　　　　　1ページあたりの最大表示件数(デフォルトはnil。つまり無限）

  # config.window = 4
　　　　　　　現在のページから、左右何ページ分のリンクを表示させるか(デフォルトは4件)

  # config.outer_window = 0
　　　　　　　最初(First)と最後(Last)のページから、左右何ページ分のリンクを表示させるか(デフォルトは0件)

  # config.left = 0
　　　　　　　最初(First)のページから、何ページ分のリンクを表示させるか(デフォルトは0件)

  # config.right = 0
　　　　　　　最終(Last)ページから、何ページ分のリンクを表示させるか(デフォルトは0件)

  # config.page_method_name = :page
　　　　　　　モデルに追加されるページ番号を指定するスコープの名前:page by default

  # config.param_name = :page
　　　　　　　ページ番号を渡すために使用するパラメータ名(デフォルトは:page)
　　　　　　　↑Board.page(params[:page])のようにparamsメソッドで取得できる。

  # config.max_pages = nil
　　　　　　　最大ページ数

  # config.params_on_first_page = false
　　　　　　　最初のページでparamsを無視しない
end
```

# ３. コントローラーの編集
ページネーションを表示させたいところに.page(params[:page])を追加する。

```
def index
 @posts = Post.all.includes(:user).order(created_at: :desc).page(params[:page])
end
```
# 4. viewの実装
ページネーションさせたいviewに下記を追記する。
```
<%= paginate @words %>
```

# 参考記事
https://qiita.com/mmaumtjgj/items/771deb2f3da3eecb4f54
ちゃんと理解するSolidity (4) マッピングの活用：車の所有者とその車を管理しよう


Solidityでのプログラミングにおいて、マッピングはキーと値のペアを管理するための重要なデータ構造です。今回は、車の所有者とその車の情報を管理するためのマッピングの使い方について解説します。
![スクリーンショット 2023-07-05 午後12.35.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3479750/e2901030-b898-835e-d11c-f755188fe42a.png)

まずは、基本的なマッピングの作成方法から見ていきましょう。以下のコードは、車の所有者を表すアドレスとその所有する車のモデルを関連付けるマッピングを作成しています。

```solidity
pragma solidity ^0.8.0;

contract CarContract {
    mapping(address => string) public carOwners;
}
```

次に、新たな車の所有者とその車をマッピングに追加する方法を見てみましょう。`addCarOwner()`関数を通じて新たな車の所有者とその車を`carOwners`マッピングに追加できます。

```solidity
contract CarContract {
    mapping(address => string) public carOwners;

    function addCarOwner(address _owner, string memory _car) public {
        carOwners[_owner] = _car;
    }
}
```

さらに、複数の車を一人の所有者が持つことができるように、マッピングの中にマッピングを格納することも可能です。これをネストされたマッピングと呼びます。以下のコードでは、ネストされたマッピングを作成しています。

```solidity
contract CarContract {
    mapping(address => mapping(uint => string)) public carCollections;
}
```

この`carCollections`マッピングでは、外側のマッピングのキーが車の所有者（アドレス）、内側のマッピングのキーが車のID、値が車のモデルとなります。これにより、一人の所有者が複数の車を所有することを表現できます。

新たな車をこのマッピングに追加するには、以下のようにします。

```solidity
contract CarContract {
    mapping(address => mapping(uint => string)) public carCollections;

    function addCarToCollection(uint _id, string memory _car) public {
        carCollections[msg.sender][_id] = _car;
    }
}
```

![スクリーンショット 2023-07-05 午後12.42.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3479750/8c46da64-1123-f8f2-75d6-7001b0fa48c9.png)

### **msg.sender**ってなんだっけ
`msg.sender`はSolidityの特殊な変数であり、現在の関数を呼び出したアドレスを表します。通常、関数を呼び出す際にトランザクションを送信したアカウントのアドレスが`msg.sender`に割り当てられます。

記事のコード例では、`msg.sender`を使用して車の所有者を特定し、その所有者に関連する情報をマッピングに格納しています。

例えば、以下のコードを見てみましょう：

```solidity
function addCarOwner(address _owner, string memory _car) public {
    carOwners[_owner] = _car;
}
```

この関数では、`_owner`というアドレスと`_car`という文字列が引数として渡されます。`carOwners`マッピングは`address`型のキー（車の所有者のアドレス）と`string`型の値（車の情報）を持ちます。`msg.sender`は関数を呼び出したアドレスを表し、`carOwners[msg.sender]`を使って、呼び出し元のアドレスに対応する車の所有者情報を格納します。

同様に、ネストされたマッピングの例でも`msg.sender`を使用しています：

```solidity
function addCarToCollection(uint _id, string memory _car) public {
    carCollections[msg.sender][_id] = _car;
}
```

この関数では、`_id`という整数と`_car`という文字列が引数として渡されます。`carCollections`は外側のマッピングと内側のマッピングを持ち、外側のマッピングのキーは車の所有者のアドレスを表し、内側のマッピングのキーは車のIDを表します。`msg.sender`を使って、関数を呼び出したアドレス（車の所有者）に対応するマッピングに車の情報を格納します。

`msg.sender`を使用することで、トランザクションを送信したアドレスに関連するデータを正確に追跡および管理することができます。

以上が、Solidityでのマッピングの基本的な使い方です。マッピングを使うことで、複雑なデータの関連性を効率的に管理することができます。
Debian 11, Ubuntu 22.04, 23.04でemacs-mozcを使う

Debian 10やUbuntu 20.04では問題なかったemacs-mozc，Debian 11やUbuntu 22.04, Ubuntu 23.04では"Wrong response from server"となって動作しない．

原因は/usr/lib/mozc/mozc_serverが動かないこと．なぜ動かないかというと，~/.config/mozcディレクトリを新規に作成できないから．ディレクトリの中のディレクトリは上位から順番に作らなければならないのにそれを考慮できていない．2020/11/28のBUILD=4206より前は~/.mozcだったのでこの問題は無かった．

GUIでDebianやUbuntuを導入していると，ibus-mozcなどが~/.config/mozcを作るのでこの問題は発生しない．CUIだけの環境でemacs-mozcを使う，という場合にだけ表面化する．

解決するのは簡単．

```
$ mkdir ~/.config
```

として上位ディレクトリを作っておけば，mozc_serverは最初の起動時に~/.config/mozcを作成できるので問題無く動く．

互換性のために以前のディレクトリがあれば使うようになっているので，

```
$ mkdir ~/.mozc
```

として以前のディレクトリを作っておく方法でも回避可能．

mozc/src/base/system_util.cc に何行か追加するだけでも直せるが，いちいちビルドするのは面倒なのでディレクトリ作るのが簡単．
【Flutter】ダイアログを閉じた後に何かの処理をしたい時

仕事で実装したので記録として残します。
### 【環境】
Flutter 3.7.7
Dart 2.19.4

### 【やりたい事】
ログインをした後にHomeを表示する。
この時にAPI(A)を叩いて、DBにデータがあればAPI(B)を叩く。
もしデータが無ければダイアログ(DialigPage)を表示してDBにデータを格納する。
ダイアログが閉じられたら再度API(A)を叩いてデータの有無を確認し、データがあればAPI(B)叩く、データが無ければ再度ダイアログを表示する流れです。



### 【サンプル】
~~~dart:home_page.dart
class HomePage extends StatefulWidget {

}

class _HomePage extends State<HomePage> {

  @override
  void initState() {
  super.initState();
     _apiA();
}


  Future _apiA() async {
    // apiの取得処理　コードは省きます。
    if(データがなかった時){
      _showDialog(context);
    } else {
      await _apiB();
    }
 }

   _apiB() async {
    // apiの取得処理
 }

   _showDialog(BuildContext context) {
       showGeneralDialog(
       context: context,
       barrierDismissible: true,
       barrierColor: Colors.red,
       barrierLabel: MaterialLocalizations.of(context).closeButtonLabel,
       transitionDuration: const Duration(milliseconds: 200),
       pageBuilder: (BuildContext buildContext, Animation animation,
            Animation secondaryAnimation) {
            return DialogPage();
            }).then((value) {
                //ここで再度APIを叩く
                _apiA();
            });
       }
  }

~~~


~~~dart:Dialog_page.dart
class DialogPage extends StatefulWidget {

}

class _DialogPage extends State<DialogPage> {

   /*記述を省略
     DBにデータを格納後にpopで戻る*/
   Navigator.of(context).pop(true);
}

~~~


### 【解説】
showGeneralDialog内でDialogPageを表示しています。そして、showGeneralDialogが閉じられた後に _apiAメソッドを呼び出していることがわかります。
このようにすることで、_showDialogメソッド内でダイアログを表示し、ダイアログが閉じられた後に_showDialogメソッドを呼び出してAPIを実行することができます。
これにより、ダイアログとAPIのフローを制御し、APIの実行後に適切な処理を行うことができます。



### 【最後に】
今回はAPIですが他の処理も実行できますので、ダイアログを閉じた後に何かをしたい時の参考にして頂ければと思います。
最後までご覧頂きありがとう御座いました。
誰かのお役に立てれば幸いです。
シェルスクリプトを使用してVM間での増分バックアップを実行してみた

# 増分バックアップとは
前回行われたバックアップからの**変更・追加**部分をバックアップする手法である．
下記の図では，グレー色が前回からの変更や追加部分である．例えば，7月3日を見てみると7月2日までの15GBはバックアップをせずに，変更や追加部分である5GBのみをバックアップする．
こうすることで，1回あたりのバックアップ量を少なくすることができる．また，世代を残す際にも容量を圧迫せずに残すことができる．しかし，復元時に複数のデータブロックを繋ぎ合わせる必要があるため作業が複雑になる面もある．

![qiita1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851869/3f9bcf29-35fc-d299-2fff-4ea871a6fc3d.png)

# 増分バックアップの実装
今回は，シェルスクリプトを用いて増分バックアップを実装した．ソースコードを以下に掲載する．1行目では，BASEDIRという変数を用意して送信先の親パスを代入する．2行目では，LATESTBKUPという変数を用意してlsコマンドで送り先のディレクトリ状況を確認する．今回，バックアップを実行する際にbackup-(date+%Y%m%d-%H%M%S)というディレクトリを作成するようにしているためgrepコマンドを使用している．また，tailコマンドを使用することによって一番最後に作られたディレクトリ（つまり最新のバックアップディレクトリ）と比較することができる．こうすることで，増分バックアップが可能となる．最後に，3行目でrsyncコマンドとlink-destオプションを使用して増分バックアップを実現している．

```php
#! /bin/bash
BASEDIR="送信先の親パス"
LATESTBKUP=$(ssh 送信先のユーザ名@IPアドレス ls $BASEDIR | grep backup- | tail -n 1)
rsync -avh --progress --link-dest="$BASEDIR/$LATESTBKUP" 送信元のパス "送信先のユーザ名@IPアドレス:/送信先のパス/backup-$(date +%Y%m%d-%H%M%S)"
```

# 上記での注意点
・lsコマンドを使用する際にsshを使用する
　→ 違うサーバにある送信先のディレクトリを参照するため
・パスの指定方法
　→ ディレクトリごと送信するかディレクトリ配下のファイルを送信するかで最後に/（スラッシュ）を付けるか付けないかが変わる
　→ ディレクトリごと送信したい場合：スラッシュを付けない
　→ ディレクトリ配下のファイルを送信したい場合：スラッシュを付ける

# 実際の実行結果
・初回のフルバックアップ
　・送信元
![スクリーンショット 2023-07-05 12.18.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851869/f4cc31cb-3735-8a8e-7dc3-fd926ade03cd.png)
　・送信先
![スクリーンショット 2023-07-05 12.19.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851869/59244548-922c-0520-29bf-5fc2825a4c7c.png)
上記のように，実際にファイルを送信することに成功している．

・2回目のバックアップ（増分バックアップ）
　・送信元
![スクリーンショット 2023-07-05 12.19.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851869/9c825957-265c-f117-02fb-d68d22acf84f.png)
　・送信先
![スクリーンショット 2023-07-05 12.19.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851869/a37b9d29-beb2-4612-0bbc-09de61d5060b.png)
上記のように，1回目で送られた1,2,3.txtは送られずに追加された4.txtのみを送信することに成功している．つまり，増分バックアップに成功している．

# 最後に
今回は，シェルスクリプトを用いたVM間での増分バックアップの方法を説明しました．増分バックアップを利用することで，ファイル送信時間が速くなったり，送り先のディスクを圧迫せずにファイルを保存することが可能となります．気になる方は，是非ご自身の環境で試してみてください！！
【超初心者向け】技育CAMPを通じて考えた技術を身につける方法（個人差あり）

# まとめ
**とにかく挑戦しまくれ。時間があるならその時間を全部埋める勢いで色々やろう！**
挑戦したその経験は自身の糧になります。

# 初めに
今回、サポーターズが主催する技育CAMPに出たのですが無事に最優秀賞を取ってきました。なので今回はその経験を踏まえて何か記事を書こうと思い現在に至ります。正直、伝えたいことは上のまとめで全て話してしまったので残りは自己満足です。ですので、ブラウザバック等していただき、自身の時間を有意義に使っていただいても構いません。

# 本題
## ４月
私が入学したときですね。はい、この段階ではまだこんなことになるとは思っていませんでした。一応、何かのサークルには入ろうかなと思っていたので若干ここも影響を及ぼしていたのかもしれませんね。

## ５月
月の初めに担任から現在のサークルの説明会の案内が来ました。はい、ここですよ。テストに出ます。覚えなくて結構です。
一応、私はここらへんで説明会に申し込みました。んで、10日の21時半ぐらいに一件のチャットが来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3488546/62e545ff-3d17-79a0-0985-77db236a5b11.png)
**うん、この時私寝てたわ！！！！**
先輩、ごめんなさい。私は夢の世界へLet's GO!!!!!!!!!!!!!!!してました。
※この画像の掲載許可はちゃんと取りました。
後日、電車の中で参加したいと回答しました。だって圧力すごかったんだもん。
文章なのに物凄い笑顔で先輩が立っている気がしたんですもん。断れる訳ないじゃないですかぁ・・・
その後のチャットで「いや2人、前から喋ってた子は誘拐したんだけど」「5人までメンバーいけるからさ、もう1人拾おうかなって」って話をしまして。誘拐される新たな被害者は近くにいました。なんなら隣の席に。
その後、Node.jsやらReactやら触れてサークルの新入生歓迎会で先輩の話を聞き五月末ぐらいに基本情報をさっさと取るっていう目標決めました。んでそっから一週間ぐらい猛勉強が始まるんですが６月突入したんで次へ。

## ６月,７月
6月4日に基本情報の受験を申し込んで、さわやかでハンバーグ食って無事合格。正直、この時点で凄く疲れましたし、なんなら色々狂いました。最初の頃の資格取得予定から大きく道逸れてなんかショートカットしてました。はい、ここからハッカソンに向けて集中できますね^^
隣の被害者にも「はよ基本情報取れ」って催促してたら中旬ぐらいに合格してきました。
は？あんた高校で情報関係学んでないやろ？え、バケモンやん。（誉め言葉）
えー、ここから隣の被害者がバケモンの片鱗を見せ始めてきました。先輩はとんでもないヤツを発掘してしまったのかもしれない・・・
6月22日、ハッカソンキックオフ。翌日メンバーでハッカソンで開発する物の案を出しました。
私が出した案は全てヤギです。結局、技術的問題・時間的問題などがあり決まりませんでした。よって後日、再度案を持って会議。ここであのヤギのゲームを作ることが決まりました。発案者は・・・バケモンです。
ここから役割を分担し、開発が始まりました。私の担当はChatGPTのAPI周りでした。知らないことばかりでしたが無事おわり、しかも最優秀賞を取れてよかったです。
（先輩の経歴に泥を塗ることがなくて良かった・・・ﾌﾞﾙﾌﾞﾙ）

# 最後に
正直、今の私があるのは先輩が誘拐もとい勧誘していただき私に挑戦する機会を作ってくれたおかげだと思っています。今回、私は先輩に誘拐されましたが普通はこんなことあるのは数少ないでしょう。だからこそ、皆さんには様々なことに挑戦していただき、多くの事を経験してほしいです。そして、先輩になったとき後輩たちを巻き込んでいきましょう。私はこれからも挑戦する心を持ち、頑張っていきたいと思います。
わざわざ稚拙な文章をここまで読んでいただきありがとうございます。皆さんの人生に多くの挑戦が訪れることを祈っています。
OCIサービスが利用するCIDRリストをポーリングしてセキュリティルールを自動更新する

# 本記事について
Oracle Cloudの各種サービスとインターネット経由て通信する場合、
疎通するためのセキュリティルールの設定が必要となります。

Oracle Cloudのサービスが利用するCIDR範囲について以下マニュアルから取得することが可能です。
https://docs.oracle.com/ja-jp/iaas/Content/General/Concepts/addressranges.htm
しかしマニュアルの以下記載の通りCIDR範囲は定期的に変更されるため、
運用においてはポーリングして自動更新を行う実装が必要です。
> 公開済ファイルをポーリングして、新しいIPアドレス範囲を24時間ごとの頻度でチェックできます。公開済ファイルを少なくとも週に1回ポーリングすることをお薦めします。

以下のスクリプトは上記OCIサービスが利用するCIDR範囲をマニュアルからポーリングし、
OCI CLI(API)を使用してセキュリティリストを更新するスクリプトです。
cronなどに設定することで定期的に自動更新することが可能です。

```
#!/bin/bash

# URL, リージョン, キーの指定
url="https://docs.oracle.com/en-us/iaas/tools/public_ip_ranges.json"
region="ap-tokyo-1"
key="OSN"

# 更新するセキュリティリストのocid
seclist_ocid="xxxx.xxxx.xxxx"

# CIDR情報が記載されたJSONファイルをダウンロード
curl -O "${url}"

filename=$(basename "${url}")

# OSNタグがついたCIDRのリストを抽出
values=(`cat public_ip_ranges.json | jq '.regions[] | select(.region == "ap-tokyo-1")' | jq '.cidrs[] | select(.tags[] == "OSN")' | jq '.cidr'`)

# セキュリティルール更新用のJSONファイルを生成
echo "[" > sec_config.json
for value in "${values[@]}"; do
        tmp_config=`sed s#REPLACE_OSN_CIDR#${value}#g base_config.json`
        echo "$tmp_config" >> sec_config.json
done
echo "]" >> sec_config.json

# ダブルクォートが二重になっている箇所を修正
sed -i -e s/\"\"/\"/g sec_config.json

# 上記JSONファイルを使用してOCI CLIでセキュリティリストを更新
oci network security-list update --security-list-id $seclist_ocid --ingress-security-rules file://sec_config.json --force
```
素数判定プログラム

## はじめに
こんにちは、村田です。
同僚に出題した下記問題の解説です。
>ユーザから整数の入力を受け取り、その整数が素数（prime number）であるかどうかを判断するプログラムを作成してください。入力された整数が素数であれば、"Yes, it is a prime number."と表示し、素数でなければ、"No, it is not a prime number."と表示してください。ヒント：2と3と6k±1


## まず回答
```prime-check.py
def is_prime(n):
    if n <= 1:
        return False
    elif n <= 3:
        return True
    elif n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    while i * i <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i += 6
    return True

n = int(input("Enter a number: "))
if is_prime(n):
    print("Yes, it is a prime number.")
else:
    print("No, it is not a prime number.")
```

このプログラムでは、まずis_primeという関数を定義して、入力された整数が素数かどうかをチェックしています。この関数は、素数が1またはそれ自体以外には約数を持たない特性を利用しています。その後、ユーザから整数の入力を受け取り、その入力が素数であるかどうかを表示します。（ユーザーは必ず自然数を入力してくれるという信頼に依っています、、）

## 途中のwhileの解説
このコードブロックは、与えられた数が素数であるかどうかを効率的に判断するためのものです。特に、このコードは6k ± 1形式の最適化を利用して、素数判定の速度を向上させています。

まず、素数は6k ± 1形式で表現できることを理解することが重要です。なぜなら、2と3の倍数以外のすべての数（つまり、6k ± 1形式で表現できる数）だけをチェックすれば、それが素数かどうかを判断できるからです。

コードの詳細は以下のとおりです：

### i = 5
iを5に初期化します。このコードの前に、関数は既に2と3で割り切れるかどうかをチェックしています。ここからは6k-1形式で最初の数（k = 1のとき）をチェックします。

### while i * i <= n
素数判定では、与えられた数（この場合はn）の平方根までチェックするだけで十分であるため、iの値がnの平方根を超えるまでループを続けます。これは効率化の一環です。

### if n % i == 0 or n % (i + 2) == 0
ここで、数nが6k ± 1形式の数（つまり、i（6k-1）とi+2（6k+1））で割り切れるかどうかをチェックします。もし割り切れる場合、その数nは素数ではありません。

### i += 6
6k ± 1形式の次の数に移動します。最初のiは5（6*1 - 1）、次は11（6*2 - 1）、次は17（6*3 - 1）となります。

### return True
nが素数である場合、この行に到達します。すなわち、2や3、または任意の6k ± 1形式の数で割り切れない場合、nは素数であると判断されます。

このように、このコードブロックは素数判定をより効率的に行うための一部です。

## おまけの証明
2と3を除くすべての素数が、形式6k ± 1の数であるということを証明します。ここで、kは0より大きい整数です。

まず、任意の正の整数nは、6で割った余りにより次の6つの形式のいずれかで表すことができます：

6k (余り 0) 6k + 1 (余り 1) 6k + 2 (余り 2) 6k + 3 (余り 3) 6k + 4 (余り 4) 6k + 5 (余り 5) これらのうち、形式1、3、4の数はそれぞれ6、2、3で割り切れるので、これらは素数であることはありません（素数は1と自分自身以外の数で割り切れないので）。したがって、素数は形式2、5、6（すなわち6k + 1、6k + 4 = 6(k + 1) - 2、6k + 5 = 6(k + 1) - 1）のいずれかになります。

しかし、形式5の数（6k + 4 = 6(k + 1) - 2）は2で割り切れるため、これも素数ではありません。したがって、2と3を除くすべての素数は、形式2または6（すなわち6k + 1または6(k + 1) - 1）のいずれか、つまり6k ± 1の形式になります。

以上により、2と3を除くすべての素数が6k ± 1形式の数であることが証明されました。

## おわりに
数学の証明問題をプログラムに落とすのって楽しいですね。
[忘備録]AWS CLIでAWSアカウントで使用可能なリージョンを確認する

# 結論
`aws account list-regions`で、AWS CLIでAWSアカウントで使用可能なリージョンが確認できる。
```bash
$ aws account list-regions --output text --profile *****
REGIONS af-south-1      DISABLED
REGIONS ap-east-1       DISABLED
REGIONS ap-northeast-1  ENABLED_BY_DEFAULT
・・・・
```

長いので、無効になっているリージョンのみ確認
```bash
$ aws account list-regions --output text --region-opt-status-contains DISABLED --profile *****
REGIONS af-south-1      DISABLED
REGIONS ap-east-1       DISABLED
・・・・
```

## 参考サイト
https://dev.classmethod.jp/articles/cli-and-sdk-support-account-region-management/




# 確認することになった経緯
## AWS CLIでエラー発生(InvalidAccessKeyId/InvalidClientTokenId)

AWS CLI から AWSサービスのAPIをリクエストをした時に、以下のエラーが発生した

```bash
An error occurred (InvalidAccessKeyId) when calling the ListBuckets operation: The AWS Access Key Id you provided does not exist in our records.

An error occurred (InvalidClientTokenId) when calling the DescribeStacks operation: The security token included in the request is invalid.
```

## 原因
エラーメッセージからアクセスキーの設定ミスかと思ったけど、リージョンを変えてリクエストすると成功する。
**AWSアカウントで使用可能にしていないリージョン「af-south-1」にリクエストしていた**のが原因だった。


https://docs.aws.amazon.com/ja_jp/accounts/latest/reference/manage-acct-regions.html

>当初 AWS では、元フォルトですべての新しい AWS リージョン が有効になっていて、ユーザーはどのリージョンでもリソースを作成することができました。しかし、AWS でリージョンが追加されたときに、新しいリージョンはデフォルトで無効になりました。ユーザーが新しいリージョンでリソースを作成できるようにする場合は、リージョンを有効にする必要があります。

リージョンの有効化を完全に失念していた。
ちゃんと理解する Solidity(3) 配列：車のモデルを管理しよう



Solidityでのプログラミングにおいて、配列はデータを効率的に管理するための重要なメソッドです。
今回は、車のモデルを管理するための配列の使い方について解説します。

まずは、基本的な配列の作成方法から見ていきましょう。以下のコードは、車のモデルを表す文字列の配列を作成し、初期値として["Tesla Model S", "Toyota Corolla", "Ford Mustang"]を設定しています。

```solidity
pragma solidity ^0.8.0;

contract CarContract {
    string[] public carModels = ["Tesla Model S", "Toyota Corolla", "Ford Mustang"];
}
```

次に、新たな車のモデルを配列に追加する方法を見てみましょう。`addCarModel()`関数を通じて新たな車のモデルを`carModels`配列に追加できます。

```solidity
contract CarContract {
    string[] public carModels;

    function addCarModel(string memory _model) public {
        carModels.push(_model);
    }
}
```

配列の要素数を取得するには、`.length`プロパティを使用します。以下のコードでは、`getCarModelsCount()`関数で`carModels`配列の要素数を取得できます。

```solidity
contract CarContract {
    string[] public carModels;

    function getCarModelsCount() public view returns(uint) {
        return carModels.length;
    }
}
```

さらに、複数の車のモデルを一つのブランドで管理するために、配列の中に配列を格納することも可能です。これを多次元配列と呼びます。以下のコードでは、2次元の配列を作成しています。

```solidity
contract CarContract {
    string[][] public carBrands = [ ["Tesla Model S", "Tesla Model 3"], ["Toyota Corolla", "Toyota Camry"], ["Ford Mustang", "Ford Explorer"] ];
}
```

以上が、Solidityでの配列の基本的な使い方です。配列を使うことで、複数のデータを効率的に管理することができます。
【ChatGPT無】私がPromptを作る際のあれこれ

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　どうも、カーブミラーです。

　今回は、
　　指示プロンプトの作成に
　　　使う方法あれこれです。

　下記の記事で、
　　ひとつのパターンを書きました。
[【ChatGPT無】私がPromptを作るやり方](https://qiita.com/kabumira/items/472f4ac24e71d0dca17f)

　ここでは、
　　私がPromptを
　　　作成する際に
　　　　使用する小ネタを書きます。
***
　まずは、作る前に、
　　ChatGPTさんにお伺い。
　　　「＊＊を知っていますか？」
　　　「＊＊を書けますか？」
　　　「＊＊を作れますか？」等。

　知っている、書ける、作れる
　　と返事があれば、
　　　作業を進めます。
***
　簡単な指示プロンプトを
　　記述して、実行します。
　　　実行結果に満足できねば、
　　　　指示プロンプトに
　　　　　文言を追加します。

　これがほとんどw
***
　ChatGPTさんが
　　吐き出す文言にも
　　　ヒントがあったりします。

　簡単な質問から
　　得られる場合もありますし、
　　　プロンプトを作成している
　　　　ときにも、出てきます。

　その文言を
　　指示プロンプトに
　　　追加していきます。
***
　複雑な指示プロンプトだと
　　途中で、お互いに
　　　わからなくなります。

　そこで、
　　「**このプロンプトをあなたが理解できる指示プロンプトとして、書き直してください**」
　　　とします。

　ようするに、
　　ChatGPTさんが
　　　こちらの意図を
　　　　理解しているかを
　　　　　問うわけです。

　また、その指示プロンプトを
　　もとにして、
　　　意図した形に修整していけば、
　　　　目標にたどり着けるはず。
***
　どんなに
　　プロンプトを修整しても
　　　うまくいかない
　　　　こともあります。
　　　　　結構ありますねw

　そういうときは、
　　休憩です。

　そして、
　　NewChatで
　　　新たにスタートです。
***
　最後に。

　人は、
　　「楽をするために、苦労する」
　　　そういう存在です。

　でも
　　「車輪の再発明」
　　　（ウィキペディア参照）
　　　　をする必要もありません。

　できているパーツを
　　配置して、
　　　必要なものを作れば、
　　　　いいのです。

　まぁ、
　　そのパーツがどこにあるのか、
　　　が問題なんですけどねw
HTMLサイトテンプレート

2023-07-05 Bulma追加
そのうち Bootstrap追加

# Bulma
~~~code html
<html>
  <head>
      <title>Bulma Template</title>
      <meta name=”viewport” content=”width=device-width,initial-scale=1″>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
    <script>
      document.addEventListener('DOMContentLoaded', () => {

  // Get all "navbar-burger" elements
  const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);

  // Add a click event on each of them
  $navbarBurgers.forEach( el => {
    el.addEventListener('click', () => {

      // Get the target from the "data-target" attribute
      const target = el.dataset.target;
      const $target = document.getElementById(target);

      // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
      el.classList.toggle('is-active');
      $target.classList.toggle('is-active');

    });
  });

});
    </script>
  </head>
  <body>
    <nav class="navbar" role="navigation" aria-label="main navigation">
  <div class="navbar-brand">
    <a class="navbar-item" href="https://bulma.io">
      <p>Template</p>
    </a>

    <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
      <span aria-hidden="true"></span>
      <span aria-hidden="true"></span>
      <span aria-hidden="true"></span>
    </a>
  </div>

  <div id="navbarBasicExample" class="navbar-menu">
    <div class="navbar-start">
      <a class="navbar-item">
       Link1
      </a>

      <a class="navbar-item">
        Link2
      </a>
    </div>

    <div class="navbar-end">
      <div class="navbar-item">
        <div class="buttons">
          <a class="button is-primary">
            <strong>ボタン</strong>
          </a>
        </div>
      </div>
    </div>
  </div>
</nav>
    
    <div class="mx-2">
      <p>これはテストです。Qiita最高！！</p>
    </div>
  </body>
</html>
      
~~~

# Bootstrap
~~~code html
<h1>そのうち公開!!</h1>
~~~
忘れがちなWindows環境でlinuxコマンド実行方法

# 概要
Windowsのコマンドプロンプトで`ls`コマンドを使用したい.  

<details><summary>背景</summary>
標準ではリナックスコマンドは実行できず,`dir`コマンドを使用する必要がある.  

PCをセットアップするたびに`GitBash`のインストールと環境変数の設定を行っている気がするが,毎回やり方を忘れるので自分がわかるやり方を記録しておく.  
</details>

# GitBashのインストール
https://www.curict.com/item/60/60bfe0e.html

こちらを参考に行う.  
(2023/07更新と最新の記事っぽい)

インストールしただけではGitBashでしかlinuxコマンドを実行できません.  
 - 上 コマンドプロンプト
 - 下 GitBash
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505183/4b167279-ef7a-8f1d-4079-50f54331a608.png)

# 環境変数の設定
環境変数変更のために,システム環境変数の編集画面を開きます.  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505183/73369a5e-8d80-58ac-50ec-c699fefc45d1.png)

システムプロパティの詳細設定タブを開きます.  
環境変数をクリックし,ユーザー環境変数とシステム環境変数を表示します.  
今回はシステム環境変数をいじります.  

環境変数には,`変数`と`値`を設定することができ,1つの変数に対して複数の値を割り当てることができます.  

今回は`Path`変数に`GitBashのbinフォルダの場所`を割り当てます.  
`Path`を選択し,下記の編集をクリック  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505183/c2d75874-6960-0323-3421-4b52b4306187.png)

`参照`から新しい参照先を設定します.  
GitBashのbinフォルダは標準で以下に存在します.(インストール時に変えてたら知らん)  
 - `C:\Program Files\Git\usr\bin`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505183/d582a0ad-e054-0d72-da11-7b999ff6f52a.png)

新しくコマンドプロンプトを開いてコマンドを実行します.  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505183/55627eb9-f8f5-c34d-70ca-58aa164ad55f.png)

成功です.
文字列→Base64エンコードを理解する


以下の変換を、実際に確認していきます。

`HELLO WORLD` => `SGVsbG8gV29ybGQh`

### 文字列 → UTF-8 Binary


```TEX:String
HELLO WORLD!
```

これを[変換](https://base64.guru/learn/more/ascii-table)すると、

```TEX:UTF-8
<Hex>
\u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064\u0021

<Binary>
01001000 01000101 01001100 01001100 01001111 00100000 01010111 01001111 01010010 01001100 01000100 00100001
```

### UTF-8 Binaryを結合して、先頭から6 bitずつのグループに分ける

```TEX:結合
010010000100010101001100010011000100111100100000010101110100111101010010010011000100010000100001
```

```TEX:6で割る
010010
000100
010101
001100
010011
000100
111100
100000
010101
110100
111101
010010
010011
000100
010000
100001
```

### 各グループの先頭に00を付加する

6 bitずつのグループに分け、00を付加することで、必ず64(Decimal)以下の値となる。
つまり、各グループが64種類の文字列のどれかに該当することになる。

```TEX:00を付加
00010010
00000100
00010101
00001100
00010011
00000100
00111100
00100000
00010101
00110100
00111101
00010010
00010011
00000100
00010000
00100001
```

```TEX:Decimal表記
18
4
21
12
19
4
60
32
21
52
61
18
19
4
16
33
```


### 各数値をBase64で変換

これで[変換](https://base64.guru/learn/base64-characters)する。

```TEX:00を付加
S
G
V
s
b
G
8
g
V
2
9
y
b
G
Q
h
```

ということで、`SGVsbG8gV29ybGQh`に変換することができました！


## 参考

[Base64アルゴリズム](https://base64.guru/learn/base64-algorithm/encode)
VB.netで作ったフォームアプリケーションが異なる解像度環境でうまく表示されなかったが解決した

VB.netで作ったWindowsフォームアプリケーションを、異なる解像度の環境で実行したところ、フォームの下部に配置した一部のコントロールが表示されない不具合が発生した。

メインのディスプレイが4Kなので、メインディスプレイを変更したりしたが一向に改善せず。
また、作成環境側をいくら変更しても解決しなかったが、実行する環境側で設定を変更したところ正しく表示されたので、今回はその方法を記しておく。

1. exeファイルを右クリックして、プロパティを表示
2. 「互換性」タブに切り替えて、「高DPI設定の変更」をクリック
![image-20230704-063257.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267148/112e8233-bc69-79df-4511-a6393197abe4.png)
3. 次のウィンドウで、「高いDPIスケール設定の上書き」設定を入れる。
![image-20230704-063354.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267148/85fe1fd0-9fa8-22a7-5876-5aac87de90d4.png)
4. OKを押してプロパティを閉じる
5. exeファイルを実行（既に開いていた場合、閉じて開きなおす）

私の環境では、これで解消した。
PostgreSQL EXPLAIN ANALYZE

## EXPLAIN ANALYZE

:::note
**PostgreSQLデータベースで実行されるクエリの実行計画と実行時間を取得するためのコマンド**

PostgreSQLがクエリをどのように実行しているかや、どの部分がボトルネックとなっているかを詳細に分析できる
:::


```sql
EXPLAIN ANALYZE SELECT count(*) FROM a, b WHERE a.id = b.id; 
```

テーブルaとbを結合するとき、a.idとb.idが等しい行のみを取得

count(*)を使用して結果の行数をカウント

***

- EXPLAIN ANALYZEを付けてクエリを実行
→実行計画と実行時間の詳細な情報を返す

- クエリの実行にかかる時間や使用されるインデックス、テーブル結合方法などの情報を取得できる
→クエリのパフォーマンスを最適化するために必要な調整ができる
【随時更新】UiPath Document Understanding の環境構成図

# はじめに

- 本記事は、UiPath Studio の基礎知識をお持ちで、これから Document Understanding（以降、DUと略す） を利用したい方向けの内容となっています。
- DU は、ドキュメントから情報を抽出・解釈する機能群、フレームワークです。
- DU の利用には AI ユニットのAPIキーが必要です。
- 記事の内容は、個人の見解または確認結果であり、UiPath の公式見解ではありません。
- 製品仕様や参考画像は 23.4 バージョンで構成しています。

# DUの環境構成図
### フルラインナップ
![DU環境構成図_修正版.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/a50f0a98-59af-7449-e667-56f591d1b0a4.jpeg)
#### 各製品とプラットフォームの主な構成パターン
| ptn | オンプレミス | [Automation Cloud🔗](https://docs.uipath.com/ja/document-understanding/automation-cloud/latest/user-guide/introduction)  | [Automation Suite🔗](https://docs.uipath.com/ja/document-understanding/automation-suite/2023.4/user-guide/introduction) |
|:--:|:--:|:--:|:--:|
| 1 | ST/RT/OC | DU/AI |  |
| 2 | ST/RT | OC/DU/AI |  |
| 3 | ST/RT/OC |  | DU/AI |

補足：
- ST(Studio), RT(Robot), OC(Orchestrator), DU(Document Understanding), AI(AI Center) ※UR実行には Action Center のインストールも必要です。
- Automation Cloud および Automation Suite 上のメニューにある Document Understanding は、AIモデルの学習用のデータセットをつくる Document Manager です。Document Manager で作成したデータセットは AI Center に連携することでモデルの学習に使えます。

#### OCRの補足
インターネットアクセスおよびAPIキー
- ***要　➣***　CJK-OCR、UiPath ドキュメント OCR、Google Cloud Vision OCR、Microsoft Azure Computer Vision OCR 等
- ***否　➣***　 UiPath ドキュメント OCR（※）、OmniPage OCR、Tesseract OCR 等　※：Document Understanding OCR Local Server パッケージのインストールが必要です。

::: note warn
AIモデルやサードパーティのOCR製品を利用しない場合にも、分類や抽出等でパブリックエンドポイントにアクセスします。このため、オンプレミス & Automation Suite の構成（ptn3）をのぞき、***インターネットへのアクセスは必須***となります。
:::

### スタンドアロンのミニマム構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/4dcc4826-78b6-b1c9-dfd7-72462554c31a.png)
ミニマムでとりあえず DU を試したい方向けの構成です。（図の青枠内の）各アクティビティの使い方やOCRの読み取り精度などを確かめたい方は以下の記事など参考にお試しください。

https://qiita.com/Kajiita/items/552a1192ab457281bfb3

### URのミニマム構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/b6d915ad-7ef0-8c92-99e4-166fcc5b710e.png)
実運用では UR × Action Center のフローが一般的なため、導入に向けて本格的に検討をはじめられる際は、テンプレート（Document Understanding Process）をもちいた検証をお勧めします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/a4175f25-e137-3944-77e6-80ff457f79a9.png)
利用手順は以下の記事が参考になります↓

https://qiita.com/utanesuke/items/103cae121fc695b77f36

# おわりに

***ドキュメントの種類としては1つでもフォーマットが何パターンもある、PDFから対象のページを選り分ける作業がある***といったケースであれば、AIモデルをもちいるフルラインナップの構成がお勧めですが、
対象が***定型の特定帳票のみ***であればミニマム構成での実現も可能です。
AIモデルを利用する場合、モデルの学習コストが相応に発生するので、ROI はしっかり計算しないといけません。
逆に、既に UiPath を導入済みで、読み取り・加工が必要な大量の定型帳票をお持ちの方は、短期間で効果を実感いただけるとおもうので、ミニマム導入にあたっての質問があればコメント欄からお知らせください。
最後までお読みいただきありがとうございますm(_ _)m
ReactとNode.jsで作成したウェブサイトをVercelとRender.comを使用してデプロイする方法

はじめまして、エンジニア職へのキャリアチェンジのためカナダへ留学中のMayuです！

初めての記事で突然ですが、苦手なデプロイについて自分のメモ用に記録しておこうと思います。

まず今回デプロイしたいのが、下記を使用して作成したオンライン予約サイト。
デプロイURL: https://salon-booking-system-frontend.vercel.app/
・frontend: Vite+React（https://github.com/MayuHayakawa/salon_booking_system_frontend）
・backend: Node.js, MongoDB（https://github.com/MayuHayakawa/salon_booking_system_backend）

そしてデプロイに使用したサイトが
・frontend: Vercel
・backend: Render.com

なぜこの二つを使用したかという理由は特にありません
（というよりまだよくわかっていないという言い方の方が正しい・・・）
在学中の学校の先生に提示してもらったものをそのまま使いました。
いつかより詳しくなったらデプロイの際にどのサービスを使用するのが良いか比較もしてみたいところですが、
今はとりあえずデプロイしたい！ということで。。。


デプロイの手順は、
・Render.comでbackendのデプロイ
・Vercelでfrontendのデプロイ
で進めました。


<h2>Render.comでのbackendデプロイ方法</h2>
1) Render.comにログイン（https://render.com/）<br>
2) 新規で「Web Service」を選択<br>
3) デプロイしたいrepositoryを選択（frontとbackはrepositoryを分けています）<br>
4) Name, Build Command, Start Commandを入力し、Freeを選択して（ここはお好きなプランで）[Create Web Service]をクリック<br>
　Build Commandは npm install<br>
　※私の場合、Start Commandはpackage.jsonファイルのscriptsに追記した node index.js となります。

![Screenshot 2023-07-04 at 6.45.52 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782670/b8e341b3-c106-da93-4d69-30614acc8c0b.png)
5) 接続先のサーバーURLやPORT、その他必要なセキュリティパスワードが記載されている.envファイルの情報をEnviromentのSecretFilesに入力、保存
　※私の場合、Filenameを .env Contentsに.envファイルの内容をまるっとコピペしました
6) 最後に[Manual Deploy]から[Deploy latest commit]を選択し、backendのデプロイは完了
7) デプロイ完了後に、URLが表示されるためコピー（下記画像のrepositoryの下に表示されているはず）
![Screenshot 2023-07-04 at 6.58.07 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782670/60edd16b-44a0-a704-30c2-6fafbd099862.png)

<h2>Vercelでのfrontendデプロイ方法</h2>
1) Vercelにログイン（https://vercel.com/）<br>
2) [Add New Project]で[project]を選択、デプロイしたいrepositoryをimport<br>
3) Project Name（お好み）とEnvironment VariablesのNameとValue（backendのデプロイURL）の情報を記入<br>
 ※私の場合、Nameは.envファイルに記載している「VITE_BASE_URL」となります

![Screenshot 2023-07-04 at 7.09.21 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782670/2b55fd5a-3dea-aa35-1538-23563228707a.png)

下記はbackendからデータを読み込む関数の例
![Screenshot 2023-07-04 at 7.06.11 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782670/5d94f4f9-6943-d248-89f9-bdcbec08bc42.png)
4) [Deploy]をクリックするとfrontendのデプロイも完了！