OmniAICreator/Qiita-1.07M huggingface dataset:
ABC342回答メモ

# 0.はじめに
　3連休中日なので、うっかり忘れないよう気をつけながら参加。
 A問題が150点と歯ごたえのある問題から始まりましたが
 Cも350点と若干難しめ。
 それでも自分的最低ラインのD問題までは解けたので
 まぁ満足でした。時間は結構ギリギリでしたが。
　レートは微増の979と最高値更新。そろそろ緑コーダを名乗っても
 よさそうかなと思いました。


# 1.A - Yay!
　 意外と面倒な問題。
  いろいろやり方はありそうではありますが
  なんとなく思いついた以下で対応。
  【実装】
  　・辞書を用意
  　・文字列を頭から見ていく
  　 -辞書にない場合はキーに文字、値に位置を登録
  　 -辞書にある場合は、値を-1に変更
  　・辞書の値の最大値を出力して終了

　https://atcoder.jp/contests/abc342/submissions/50565226


# 2.B - Which is ahead?
　求められることを素直に実装すればよさそうな問題。
 素直に実装してAC
  【実装】
  　・辞書を用意
   ・辞書を用意
   ・リストAを読み込み、辞書のキーにリストの値を
   　値にリストの位置を登録
   ・クエリーを読み込む
   　-Aの位置とBの位置を辞書から取り出し
    　位置の値が小さい方を出力する。

　https://atcoder.jp/contests/abc342/submissions/50569366


# 3.C - Many Replacement
　なかなか厄介な問題で取り掛かるまでに悩みました。
 制約が大きいので、どこを繰り返すのが効率が良いかを考え
 以下に行きつきました。
 【考え方】
 　・アルファベットの文字毎に、最終的にどのアルファベット文字に
  　なるかの辞書を作って、最後に文字列Sアルファベットをそれぞれ
    変換していく。

 【実装】
　 1.辞書Dを用意
   2.辞書のキーと値にアルファベットのa～zまでの文字をセット
   3.クエリー数を読み込みクエリーごとに以下の処理を行う
　   -1.AとBを読み込む（問題上はCとDですが辞書にDを使ったので・・・）
　   -2.辞書のキーを変数kに、値を変数vに順に読み込んでいく
    　　→vがAと一緒の時、D[k]にBをセット
   4.リストansを用意
   5.文字列Sを読み込んでいいき、各文字ごとに
   　辞書Dから、値を検索してansに追加
　 6.最後にansを結合した文字列を作り出力して終了

　https://atcoder.jp/contests/abc342/submissions/50585713


# 4.D - Square Pair
　TLE回避のためには二工夫くらいしないといけない問題。
 解き終わった後に、なんか似た問題あったなと思ったりもしました。

 【考え方】
  ・リスト内の0は、どの数字とでも平方数を作れる
  ・２つの数字を掛け合わせて平方数になる場合
  　それぞれの数字を素因数分解して得られた値
    それぞれでペアを作れる
    　→素因数分解した時点でペアがあった場合は
       省いておけば、省いたあとの2つの数字が同じ場合
       平方数になると言える。
       例）３と１２の時
       　・3 →3
         ・12→2×2×3→3
         　→掛け合わせると平方数になる。
  ・リストＡから、０は省きつつ、各数字を素数の2乗で割りきれる
  　だけ割った後の数字を別リストに格納していき
    別リスト内で同じ数字の組み合わせ数を集計すれば
    回答ができる。
    （0を省くときはその時に残っている値数分答えに加算）
  　
　上記考え方を実装していきましたが、
 　・別リスト内で同じ数字の組み合わせ数を集計
  の部分を単純に全組み合わせを確認する実装したら
  TLEとなったので、慌ててpythonのCounterを調べ
  nCrの公式を調べ・・と泥縄式にバタバタしつつ
  10分残しでACとなりました。
  また、素数の2乗のリストを作るロジックが
  結構長くて埋め込むと見難かったので
  必要な分だけリストにして手動でソースに張り付けるという
  荒業を使ってしまいました。
  
 【実装】
 　1.変数NとリストAを読み込む
 　2.素数の2乗リストL（4、9、25・・・201601）を定義
 　3.以下を定義
   　・答えを格納する変数ansを0で定義
   　・Lから選抜した値をセットするリストPを空で定義
   　・L内の0以外の値の数を持たせるN2をNで定義
 　4.リストAを順にみて以下の処理を行う
  　-1.リストA[i]が0の時
   　→N2から、1を引きansに加算
  　-2.リストA[i]が0以外の時
   　--1.変数jに0をセット
   　--2.pにA[i]をセット
   　--3.以下を、L[j]がpより大きくなるか、pが1になるまで実施
    　---1.pがL[j]で割り切れる時
     　→pにをL[j]で割った値をpにセットし、jに0をセット
    　---2.pがL[j]で割り切れない時
     　→jに1を加算
   　--4.リストPにpを加算  
 　5.PNにcollections.CounterでPの値：個数の辞書を構成
 　6.PNの値xを順に読み込む。
  　-1.xが2以上の時
   　ansに(x*(x-1))//2を加算
 　7.ansを出力して終了
 
　https://atcoder.jp/contests/abc342/submissions/50604911


以上
StableDiffusionでLoraを使う（コードから使う）

# １行でテイストが変わる

Stable Diffusion はテキストから画像を生成してくれる AI ですが、
**Lora** は元のモデルにつけたしであるテイストを加えることができるものです。

たとえばこれは

```
a machine learning boy
```

というテキストから Stable Diffusion で生成した画像ですが、

![boy_snow (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/a2d42f52-7a34-3f47-57a8-2aa9b3255ecc.png)

水彩画を学習した Lora を Stable Diffusion にロードして同じテキストで生成すると、

![boy_snow (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/e702b78e-7a35-97f9-09a1-9c7226126d59.png)

こういうテイストになります。

LoraはWebUI（GUIでStable Diffusionを使えるライブラリ）の方で使うのも簡単だけど、
コードから使うのも簡単です。

# やり方

好きなテイストの Lora を [Hugging Face](https://huggingface.co/models?pipeline_tag=text-to-image&sort=trending&search=lora) などで探してダウンロードします。 .safetensorという拡張子のファイルです。
自分で作ることもできます。

さっきの水彩画のLoraはこれです。

https://huggingface.co/ostris/watercolor_style_lora_sdxl

```python
pipe.load_lora_weights(".", weight_name="watercolor_v1_sdxl.safetensors")
```

これで Stable Diffusion に Lora がロードされます。
あとは生成するだけ。

```python
from diffusers import StableDiffusionXLPipeline

pipe = StableDiffusionXLPipeline.from_pretrained('stabilityai/stable-diffusion-xl-base-1.0')
pipe.to( "cuda" )
pipe.load_lora_weights(".", weight_name="watercolor_v1_sdxl.safetensors")
image = pipe("delicious pizza",latents=latents).images[0]
image.save('pizza.png')
```

![boy_snow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/ab1e837e-37d1-a320-684c-8eba00ee1a14.png)

🐣
****
フリーランスエンジニアです。
AIについて色々記事を書いていますのでよかったらプロフィールを見てみてください。

もし以下のようなご要望をお持ちでしたらお気軽にご相談ください。
AIサービスを開発したい、ビジネスにAIを組み込んで効率化したい、AIを使ったスマホアプリを開発したい、
ARを使ったアプリケーションを作りたい、スマホアプリを作りたいけどどこに相談したらいいかわからない…

いずれも中間コストを省いたリーズナブルな価格でお請けできます。

お仕事のご相談はこちらまで
rockyshikoku@gmail.com

機械学習やAR技術を使ったアプリケーションを作っています。
機械学習／AR関連の情報を発信しています。

[X](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
Flutterのエラー"Error CocoaPods's specs repository is too out-of-date to satisfy dependencies."でビルドできないぞ

## IntelliJ IDEAでFlutterをrunしたらエラー発生。
```
To update the CocoaPods specs, run:
  pod repo update
```

と書いているので、updateをしてみる。

## 改善しない…

最新にしてみよう
```
> brew reinstall cocoapods
```

変わらないので調べていると、どうやらPodfile.lockを削除するのがいいみたい。

```
> cd ios
> rm Podfile.lock 
> pod install --repo-update 
> flutter clean
```
AWS Lambdaの内部構造

# はじめに
AWS Lambdaは、開発者がサーバーのプロビジョニングや管理を心配することなくコードを実行できるサーバーレスコンピューティングサービスです。
この記事では、Lambdaの仕組みとそのコンポーネントについて詳しく解説し、サーバーレスアーキテクチャがどのように開発のパラダイムを変えているかを探ります。

# AWS Lambdaの概要
AWS Lambdaは、「書いたコードを実行するだけ」のシンプルさで知られています。
開発者はコードを提供するだけで、後はLambdaがスケーラビリティ、実行、およびセキュリティを管理します。
Lambda関数は、トリガーに応じて自動的に実行され、使用した分だけ課金されます。
このモデルは、リソースのオーバープロビジョニングやアンダープロビジョニングを心配する必要がないため、効率的でコスト効果が高いです。

### コンポーネントの深掘り
AWS Lambdaのアーキテクチャは主に二つの大きなコンポーネントに分かれています。
呼び出しリクエストのルーティングとコンピュートインフラストラクチャです。
これらのコンポーネントはLambdaの柔軟性とスケーラビリティの根幹を成しています。

### 1. 呼び出しリクエストのルーティング
このプロセスは、Lambda関数へのリクエストがどのように処理されるかを決定します。
リクエストは、関数の実行環境へとルーティングされる必要がありますが、これには複数のステップが関与します。
図1は、このプロセスの概要を示しています。

![DALL·E 2024-02-19 10.44.35 - Create an infographic that illustrates the AWS Lambda invocation request routing process. The infographic should include the following steps in a clea.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/2c93f832-cccb-0c2d-24f3-227f90657259.png)
図1: Lambdaの呼び出しリクエストルーティングプロセス

1. リクエストがLambdaに到着
2. フロントエンドがリクエストを検証し、認証
3. プレースメントシステムが実行環境を割り当てる
4. 実行環境がリクエストを処理し、結果を返す

### 2. Lambdaインフラストラクチャ

実際にLambda関数が実行される場所です。
AWSはEC2インスタンスをベースにした仮想化技術を使用して、各Lambda関数のために隔離された実行環境を提供します。
このアプローチの進化として、AWSはFirecrackerという軽量な仮想マシンマネージャを導入しました。
Firecrackerは、セキュリティを犠牲にすることなく、迅速な起動時間と効率的なリソース利用を可能にします。
図2は、Lambdaのコンピュートインフラストラクチャの概要を示しています。

![DALL·E 2024-02-19 12.07.53 - Create a simplified infographic that illustrates the AWS Lambda compute infrastructure, focusing on clarity and simplicity. The infographic should inc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/7d8ddd95-fdc1-2be9-2691-f7d7faba8aef.png)
図2: Lambdaのインフラストラクチャ

1. EC2インスタンスがワーカーフリートを形成
2. Firecrackerが各関数のための軽量VMを提供
3. スナップショット技術によりコールドスタートを削減
 
### コールドスタート問題の解決
Lambda関数の初回起動時には、起動遅延（コールドスタート）が発生することがあります。
AWSはこの問題に対処するために、Lambda SnapStartを導入しました。
この技術は、関数の初期化後にVMのスナップショットを作成し、次回の起動時にはこのスナップショットから迅速に復元することで、起動時間を大幅に短縮します。

# まとめ
AWS Lambdaは、サーバーレスコンピューティングの可能性を広げる革新的なサービスです。
呼び出しリクエストのルーティングとコンピュートインフラストラクチャの進化により、開発者はインフラの管理から解放され、よりビジネスロジックの開発に集中できるようになりました。
Lambdaのこれらの特徴は、クラウドベースのアプリケーション開発をより迅速かつ効率的にし、サーバーレスアーキテクチャの未来を形作っています。
ReactとFlaskの組み合わせにおけるCORSの重要性と設定方法


## はじめに

近年、フロントエンドとバックエンドの分離が一般的な開発パターンとなっています。このような構成では、Reactのようなフロントエンドフレームワークを使ってUIを構築し、Flaskのような軽量なバックエンドフレームワークをAPIサーバーとして使用することがよくあります。しかし、このようなアーキテクチャを採用する際、Cross-Origin Resource Sharing（CORS）に関する理解と適切な設定が大切で、本記事がその備忘録です。
## CORSとは？

CORSは、ウェブページが異なるオリジン（ドメイン、プロトコル、ポート）のリソースにアクセスすることをブラウザが許可するようにするセキュリティ機能です。デフォルトでは、ブラウザは同一オリジンポリシーを強制し、異なるオリジン間のリソース共有を制限します。しかし、実際のアプリケーションでは、フロントエンドとバックエンドが異なるオリジンに存在することがよくあります。このとき、CORSポリシーの設定が必要となります。

## FlaskにおけるCORS設定

FlaskでAPIを構築し、Reactアプリケーションからのアクセスを許可するには、`flask-cors`ライブラリを使用するのが一般的です。以下は基本的な設定例です：

```python
from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # すべてのオリジンからのアクセスを許可

@app.route('/')
def hello():
    return 'Hello, CORS!'

if __name__ == '__main__':
    app.run(debug=True)
```

上記のコードでは、`CORS(app)`によって全てのオリジンからのアクセスを許可しています。実際のプロジェクトでは、セキュリティを考慮して特定のオリジンのみを許可するように設定することをお勧めします。
## さらに細かい設定


`flask-cors`を使用して特定のオリジンを許可する場合、`CORS`関数の`origins`パラメータに許可したいオリジンのリストを指定することで、特定のオリジンからのリクエストのみを許可することができます。これにより、アプリケーションのセキュリティを向上させることができます。

以下に、`flask-cors`を使用して特定のオリジンを許可する方法の例を示します。

```python
from flask import Flask
from flask_cors import CORS

app = Flask(__name__)

# 特定のオリジンだけを許可する
cors = CORS(app, resources={r"/*": {"origins": ["http://example.com", "https://example2.com"]}})

@app.route("/")
def hello():
    return "Hello, World!"

if __name__ == "__main__":
    app.run(debug=True)
```

この例では、`resources`パラメータを使用して、どのルートに対してどのオリジンを許可するかを詳細に指定しています。`r"/*"`はすべてのルートを指す正規表現で、`"origins"`キーに許可するオリジンのリストを指定しています。この設定により、`http://example.com` と `https://example2.com` からのリクエストのみが許可され、他のオリジンからのリクエストはブロックされます。

### より細かい制御が必要な場合

`flask-cors`は、さらに細かい制御が必要な場合にも対応しています。例えば、特定のHTTPメソッドのみを許可したり、ヘッダーやクレデンシャルの扱いをカスタマイズしたりすることが可能です。以下のように設定を追加することができます。

```python
cors = CORS(app, resources={
    r"/api/*": {
        "origins": ["http://example.com", "https://example2.com"],
        "methods": ["GET", "POST"],  # 許可するHTTPメソッド
        "allow_headers": ["Content-Type", "Authorization"],  # 許可するヘッダー
        "supports_credentials": True  # クレデンシャルをサポートするか
    }
})
```

## ReactからFlaskへのアクセス

ReactからFlaskのAPIにアクセスする際は、`fetch`や`axios`などのHTTPクライアントを使用します。CORSポリシーによってリクエストがブロックされないようにするためには、Flask側で適切なCORS設定がされている必要があります。

```javascript
fetch('http://localhost:5000/')
    .then(response => response.text())
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));
```

## まとめ

ReactとFlaskを組み合わせた開発では、異なるオリジン間でのリソース共有を可能にするためにCORSの設定が不可欠です。`flask-cors`を利用することで、簡単にCORSの設定を行うことができ、安全かつ効率的なフロントエンドとバックエンド間の通信を実現することが可能です。
symbol mainnet node用 fast-sync "fsdm"


※この fast-sync "fsdm" は @ryosasa氏の作成した
fast-sync

https://qiita.com/ryosasa/items/7313fc7d86c30e9c5d8f

を基にして data/databases の ﾀﾞｳﾝﾛｰﾄﾞ先を変更、改変を行ったものです

# symbol mainnet node用 fast-sync "fsdm"
**※注意　symbol-bootstrap ｺﾏﾝﾄﾞが sudoを付けずに実行できる nodeに限ります**

pasomi.netの補助 nodeである 10.dusanjp.comと 11.dusanjp.comの blockdataを使用しています
週に1度　金曜の夜くらいに更新してます
　
　
※fsdmで同期をすると 同期後に委任者は復元されません
元の委任者情報である`taget/nodes/node/data/harvesters.dat`を保存して置いて
同期後に`target/nodes/node/data/`に`harvesters.dat`を戻してから nodeを再起動して下さい
　
　
使用方法
nodeの状態は稼働中/停止中/異常停止中を問わず実行出来ます

nodeの作業ﾃﾞｨﾚｸﾄﾘにて
```
wget 10.dusanjp.com/fsdm/fsdm
```
又は
```
wget 11.dusanjp.com/fsdm/fsdm
```
file "fsdm"が downloadされます
```
sh fsdm
```
block data `target/nodes/node/data`と `target/databases`の圧縮fileが downloadされて解凍されます
時間は数時間掛かります

このまま放って置くと勝手に nodeが再起動して同期を開始します


# fsdm（10.dusanjp.com）の shellscript
※ 11.dusanjp.comから落とす方は blockDataの download先を 11.dusanjp.comに替えてあります
```
#!/bin/bash
#
# 1) symbol-bootstrap stop
#
# 2) recovery databases/data
#  10.dusanjp.com/fsdm/databases.tar.gz
#   -> $HOME/target/databases
#  10.dusanjp.com/fsdm/data.tar.gz
#   -> $HOME/target/nodes/node/data
#
# 3) symbol-bootstrap start -d
#
if [ $# -gt 0 ]; then
    BOOTSTRAP_HOME=$(cd $(dirname $1) && pwd)/$(basename $1)
elif [ -z "$BOOTSTRAP_HOME" ]; then
    BOOTSTRAP_HOME=.
fi
if [ ! -d "$BOOTSTRAP_HOME/target" ]; then
    echo "$BOOTSTRAP_HOME/target not found!"
    exit 1
fi
S3_URL=10.dusanjp.com/fsdm
recover_data()
{
    echo "start recover data"
    cd $BOOTSTRAP_HOME/target/nodes/node/
    wget -O -  $S3_URL/data.tar.gz | tar zxf -
    echo "end recover data"
}
recover_databases()
{
    echo "start recover database"
    cd $BOOTSTRAP_HOME/target
    wget -O -  $S3_URL/databases.tar.gz | tar zxf -
    echo "end recover database"
}
date
cd $BOOTSTRAP_HOME
symbol-bootstrap stop
#cp target/nodes/node/data/harvesters.dat bak.harvesters.dat
rm -rf $BOOTSTRAP_HOME/target/nodes/node/data
rm -rf $BOOTSTRAP_HOME/target/databases
recover_data &
recover_databases &
wait
symbol-bootstrap run -d
date

```
react + backend(flask)のviteを使った環境構築備忘録

## 前提
以下の環境を想定しています。
```
npm -v : 9.8.0
node -v : v20.4.0
python3 --version : 3.12.2
create-vite@5.2.1
```
## 手順
2024年現在最新の`vite`を使ったコマンドは以下の通り

①まずルートのディレクトリを作る
②その下に`backend`フォルダを作る
③ルートに戻って以下のコマンドを実行し、`frontend`フォルダを作る
```
npm create vite@latest frontend -- --template react
```
④`fronend`に`cd`し、`npm install`する。

## 大切なこと

- `frontend`と`backend`を完全に切り離して開発できること。
-  `frontend`と`backend`の通信はhttpを通してだが、`SOP`(`Same-Origin Policy`)が引っかかるので`CORS` を設定しないといけないこと。（`flask`だったら`flask-cors`
- backendの言語はなんでもいいこと
SQLServerに繋がらないとき...

プログラムからSQLServerに繋がらないときに見る記事です :eyes:

## SQLServerがリッスンしてしているか？
SQLServer構成マネージャー `SQL Server Configuration Manager`　を開いて状態が"実行中"であるかを確認します。変更を加えた場合、再起動が必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482880/4ec73737-65bf-a801-9234-12a76e537491.png)

`TCP/IP`が有効になっているかを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482880/6e329a1d-b8e0-5a41-21db-cb354023f487.png)

`TCP/IP`のプロパティにてTCPの静的ポート番号を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482880/51c67d3f-2700-2225-1a1e-f36552d4520a.png)

## ファイヤーウォールで許可されているか？
SQLServerの通信が許可されていない場合は、Windows Defender ファイヤーウォールの設定で[受信の規則]を右クリックして[新しい規則]→[プログラム]→[接続を許可する]→とウィザードに従って設定します。

<img width="450px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482880/9b92e721-7cfc-3014-fad0-fbdf0844aa6c.png" />

SQLServerの実行ファイルは、SQLServer構成マネージャーのSQLServerのサービスからプロパティを辿れば確認できます。恐らく、以下のようなパスになるかと思います。
`C:\Program Files\Microsoft SQL Server\MSSQL16.SQLEXPRESS\MSSQL\Binn\sqlservr.exe`

## 接続文字列が正しいか？
接続文字列が間違っているかも知れません。ユーザー名、パスワード、サーバー名、ポート番号、データベース名等を確認してみましょう。


`Gorm`で接続できるかテスト
```go
package main

import (
	"time"

	"gorm.io/driver/sqlserver"
	"gorm.io/gorm"
)

func main() {
	dsn := "sqlserver://testuser:p123@localhost:1433?database=testDb"
	db, err := gorm.Open(sqlserver.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
}
```
無事、接続できました :sunny:

## Reference
- [SQL Server が特定の TCP ポートでリッスンするように構成する](https://learn.microsoft.com/ja-jp/sql/database-engine/configure-windows/configure-a-server-to-listen-on-a-specific-tcp-port?view=sql-server-ver16&source=recommendations)
- [TCP/IP のプロパティ](https://learn.microsoft.com/ja-jp/sql/tools/configuration-manager/tcp-ip-properties-ip-addresses-tab?view=sql-server-ver16)
[Google Sheets API] セル内の空白をまとめて削除する

Google Sheets API v4（Java）を使用して、
スプレットシートのセル値の前後の空白（スペース、改行、タブ等）を削除する方法
についてご紹介します。

メニュー：「データ」 ⇨	「データ クリーンアップ」 ⇨　「空白文字を削除」
で実行できる内容と同じです。
指定した範囲のセルをトリミング(trim)します。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Sheets API] Google Sheets API v4をJavaで操作する](https://qiita.com/doran/items/3d43f776188b2281044c)
を参照ください。
```
例：requests.add(moveDimension(sheetId)); //実行したいリクエストのMethodを指定
```
:::

:::note info
その他のGoogle Sheets APIは、下記の記事を参照ください。
[⧉[Google Sheets API] JavaでスプレットシートのメニューとAPIを関連づけてみた](https://qiita.com/doran/items/2f6f8932b994fbd1a170)
:::

|No||目次|
|---|---|---|
|1||[セルのトリミング](#1-セルのトリミング)|
||1|[範囲を指定した場合](#11-範囲を指定した場合)|
||2|[範囲を指定しない場合](#12-範囲を指定しない場合)|

## 1. セルのトリミング
トリミングしたいシートとセルの範囲を指定します。

セルの範囲を指定しない場合はシート全体で適用されます。

### 1.1. 範囲を指定した場合
指定したセルの範囲がトリミングされます。

**サンプル コード**
A〜C列、1行目〜４行目の範囲をトリミングします。
```
public Request trimWhitespace(Integer sheetId) {
    Request request = new Request();

    GridRange range = new GridRange();
    range.setSheetId(sheetId);       //トリミングするシートID
    range.setStartRowIndex(0);       //開始行(0スタート)
    range.setEndRowIndex(4);         //終了行(1スタート)
    range.setStartColumnIndex(0);    //開始列(0スタート))
    range.setEndColumnIndex(3);      //終了列(1スタート)
    
    TrimWhitespaceRequest r = new TrimWhitespaceRequest();
    r.setRange(range);
    
    request.setTrimWhitespace(r);
    return request;
}
```
**実行結果**
分かりづらいですが、先頭と末尾に空白や改行が含まれたセルがあります。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/d6205520-3208-7722-8bf1-14764664fdb4.png">

指定範囲（画像の選択している範囲）のみトリミングされました。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/832f2e82-755c-a7f6-766b-aaf6038a9d3b.png">

### 1.2. 範囲を指定しない場合
指定したシートのセル全体をトリミングします。

**サンプル コード**
```
public Request trimWhitespace(Integer sheetId) {
    Request request = new Request();

    GridRange range = new GridRange();
    range.setSheetId(sheetId);       //トリミングするシートID
    
    TrimWhitespaceRequest r = new TrimWhitespaceRequest();
    r.setRange(range);
    
    request.setTrimWhitespace(r);
    return request;
}
```
**実行結果**
先程の指定した範囲外でトリミングされなかったセルもトリミングされました。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/f18a2d0d-3f0e-9f9d-d359-97f2c5c50dbf.png">

<br>
おしまい。。
GAEでデプロイできなくて困った話

## GAEでデプロイできなくなった！
タイトルの通り、GAEで、`gcloud app deploy`でデプロイできなくなってしまった。
Cloud Buildsのエラーのログを見ると、

```
ERROR: failed to initialize analyzer: getting previous image: getting config file for image "us.gcr.io/******-******/app-engine-tmp/app/default/ttl-18h:latest": GET https://storage.googleapis.com/us.artifacts.******-******.appspot.com/containers/images/sha256:*****************************************?access_token=REDACTED: unexpected status code 404 Not Found: <?xml version='1.0' encoding='UTF-8'?><Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Details>No such object: us.artifacts.******-******.appspot.com/containers/images/sha256::*****************************************?</Details></Error>
```
```
ERROR: build step 2 "us.gcr.io/gae-runtimes/buildpacks/google-gae-22/python/builder:python_20240218_RC00" failed: step exited with non-zero status: 1
```
直前のコードを利用してビルドしようとしているんだけど、直前のコードとか、ないんだけど？？と言われているような気がします。
20240218？　あ！

どこかで、Cloud Storage の Multi-region のバケットが課金対象になっちゃうから、消しました、課金がなくなりました、というような記事を見て、私も！とMulti-region のバケットをまるっと削除した気がします・・・
（画像は復旧後に取得）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679605/8bfeec07-bbe7-8f57-5ca7-116a2c057b33.png)

えー、別に古いのなくてもよくね？今に生きようゼ？
検索して、見つけたのが次の記事

https://otiai10.hatenablog.com/entry/2023/03/12/152243

```gcloud app deploy --no-cache``` でやってみろ、と。
やってみた！ → デプロイできた！

Qiitaでは見つけられず、ちょっと困ったので、残しておきます。
私みたいに適当に消したら、ダメだよ！

## 参考
[「Step #2 - "build": ERROR: failed to initialize analyzer: getting previous image」の解決法](https://qiita.com/komajo/items/45cd5749283f59349ed4)
こちらもやろうとはしてみました・・・が、権限がよくわからないせいか、うまくできませんでした。
[Multipass] macOSのzsh/VSCodeからUbuntuVMインスタンスにSSH接続する

# My Environment

> Chip: Apple M3 Max
> Memory: 64GB
> macOS: Sonoma 14.2.1

# 前回の記事 (Multipass&Ubuntuについてはこちら)

https://qiita.com/shisotem/items/3ae793b46ade832479c9

# Procedure

:::note info
- 以下のルールで表記します

  - %: macOSのzsh上でのコマンド操作
  - $: Ubuntuのbash上でのコマンド操作
:::

```zsh
% ssh-keygen -t ed25519 -C "<your_email_address@example.com>"
```
- 保存場所はデフォルト(~/.ssh/id_ed25519, ~/.ssh/id_ed25519.pub)でOK (Enter)
- パスワードを作成 &rarr; 再入力

```zsh
% multipass ls
Name                    State             IPv4             Image
foo                     Running           192.168.64.5     Ubuntu 20.04 LTS
```
- IPv4 (e.g. 192.168.64.5) を確認

```config
Host foo
    HostName 192.168.64.5
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    User ubuntu
```
- 上の内容をmacOSの~/.ssh/configに記述

```zsh
% pbcopy < ~/.ssh/id_ed25519.pub
```
- 公開鍵をコピー

```zsh
% multipass shell foo
```
- Ubuntuのbashにログイン

```bash
$ echo "<paste_here>" >> ~/.ssh/authorized_key
```
- Ubuntuの~/.ssh/authorized_keyに追記（ペースト）

```bash
$ exit
```
```zsh
% multipass start foo
```
- 注意: このUbuntuの再起動操作が重要

---

```zsh
% ssh foo
```
- zshからSSH接続をしてみる

  - 初回は`yes`の入力を求められる
  - パスワードを入力

---

- VSCodeからSSH接続をしてみる

  - VSCodeで **Remote - SSH** をインストール
  - 画面左下のボタンをクリック
  - Connect to Host ... を選択
  - foo を選択
  - 初回は`Continue`の選択を求められる
  - 遷移先のVSCodeウィンドウでパスワードを入力

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3269836/c30e5aef-4cc5-db36-bba0-8e8193b75203.png)

# References

- How to connect to Multipass via SSH (with VSCode):

https://note.com/inagy/n/ndee177461a6e
2024/2/25主にITとかセキュリティの記事

Atlassian Confluenceの新たな脆弱性「CVE-2023-22527」：リモートコード実行のリスクとその対策を解説(2/23)
https://www.trendmicro.com/ja_jp/research/24/b/unveiling-atlassian-confluence-vulnerability-cve-2023-22527--und.html

WordPressの人気テーマBricks Builder Themeに緊急の脆弱性、サイバー攻撃進行中(2/23)
https://news.mynavi.jp/techplus/article/20240223-2889098/

NCAとFBIがロシア関連のLockBitランサムウェア集団を解体へ(2/23)
https://nextmoney.jp/?p=64223

サイバー攻撃年間6000億回！　狙われるニッポン…国を挙げて迎え撃つ！【WBS】(2/23)
https://news.yahoo.co.jp/articles/fbd0cbc80c12638e43bfc8ef275b00da23c7b709?source=rss

「中国、セキュリティ会社を介して外国政府・企業の大規模ハッキング…韓国通信社を含む」(2/23)
https://japanese.joins.com/JArticle/315370?servcode=A00&sectcode=A00

攻撃グループ「Pawn Storm」が有力な組織に対してステルス型のブルートフォース攻撃を展開(2/23)
https://www.trendmicro.com/ja_jp/research/24/b/pawn-storm-uses-brute-force-and-stealth.html

パスワードは古い？｢パスキー｣の導入企業が急増
気になる｢セキュリティと利便性｣両立の仕組み(2/23)
https://toyokeizai.net/articles/-/734757

グーグルやアップルも自社サービスのログイン方法として採用、注目の「パスキー」は企業内でも導入が進むのか？(2/23)
https://news.yahoo.co.jp/articles/7907541736e3bf9f770dcc331e62b0abe1befa0a?source=rss

ビットコイン、グローバルストレスから恩恵を得る方法(2/23)
https://www.coindeskjapan.com/220210/

デベロッパーエキスパートが解説する“世にも奇妙な暗号技術”
「そんなことができるの！」を可能にする「検索可能暗号」と「秘密計算」の事例
世にも奇妙な暗号技術 -- うわっ・・・こんな事できるの？(12/5-12/6)
https://logmi.jp/tech/articles/330166

GovMarket が提供するデジタル主権がドイツでの経済的機会の創出に役立つ仕組み(2/22)
https://cloud.google.com/blog/ja/topics/customers/how-data-sovereignty-can-help-create-economic-opportunity-in-germany/

中国のサイバーセキュリティー、最大の脅威は米国ではなくインド―香港紙報道(2/23)
https://nordot.app/1133664042058203303

イーサリアムのヴィタリック・ブテリン氏、スケーラビリティ推進の中でのレイヤー2リスクに警告(2/23)
https://nextmoney.jp/?p=64238

中国製クレーン、米国家安全保障へのリスク－ロサンゼルス港責任者(2/23)
https://www.bloomberg.co.jp/news/articles/2024-02-22/S99JY9DWX2PS00?srnd=cojp-v2

Web3とは｜次世代を担う非中央集権的インターネット環境のメリットを解説(2/23)
https://coinpost.jp/?p=507406

ChatGPTの普及がGoogleに与える影響は？新たなフェーズに入ったブラウザ戦争の行方(2/23)
https://dime.jp/genre/1738273/

サポート代金約１万円を振り込んだつもりが・・・突如２７０万円に！？福岡市でニセ電話詐欺事件(2/23)
https://www.fnn.jp/articles/-/661691

2024年1月のフィッシングは思ったほど減らず
アップルを装うSMS詐欺が継続中。特にAndroidユーザーは危険(2/23)
https://ascii.jp/elem/000/004/185/4185778/?rss

AIを活用した事業構想の「可能性と限界」(2/23)
https://forbesjapan.com/articles/detail/69290

「サイバーセキュリティ対策9か条」で基礎知識を覚えよう
サイバーセキュリティ月間は3月18日(さいばー)まで実施中。駄洒落はアレだが動画は超オススメ(2/23)
https://ascii.jp/elem/000/004/185/4185932/?rss
https://news.nicovideo.jp/watch/nw14410358

クリプトとは？意味や仮想通貨・暗号資産との違いについて解説！(2/22)
https://xrcloud.jp/blog/articles/business/3051/

スマホ「マルウェア」に注意　バッテリーの消費激しく／データ通信料過度に増加(2/23)
https://www.hokkaido-np.co.jp/article/978757/?ref=top

"ゆめタウン"など展開｢イズミ｣サイバー攻撃で障害 一部商品が品薄に(2/23)
https://news.ntv.co.jp/n/kkt/category/society/kk93b985f453434a01a998790476abae14

＜サイバー攻撃＞イズミ品薄、業務に支障(2/23)
https://www.yomiuri.co.jp/local/hiroshima/news/20240222-OYTNT50239/

「ゆめタウン」「ゆめマート」で品薄・アプリ休止・新店の開業延期…運営会社にサイバー攻撃、影響広がる(2/23)
https://www.yomiuri.co.jp/local/kansai/news/20240223-OYO1T50024/
やっとAWS 12冠（全冠）達成したので何か書いてみる

# はじめに
2024/2/24 AWS 認定12資格の内、最後に残ったSOAに無事合格し、晴れてAWS 12冠（全冠）を達成したのでその記念に経緯やらなにやら書いてみることにした。

---

# 私のAWS歴
現在 46歳になるシステムエンジニア。AWSは2020年8月頃から仕事で使っている。
2020年8月～ 初めてAWSにふれる。Code系サービスを使う。
2021年10月～ 某プロジェクトにて構成管理のお仕事（Code系サービスを使い倒す）
2023年9月～ レガシーマイグレ（AWS）のお仕事

---

# AWS 12冠を目指すに至った経緯
当初は狙うつもりなど全くなかった（みんなそうかもしれないが）。
「せっかくAWSを使い始めたのだから何か形にしたい。」という思いと「とったほうが良いよ（とってほしいんだけど）」という上司のすすめ（微妙な圧力）もあり、SAAを取得。

その後、AWS有識者を増やしたいという所属部署の流れと、自分の今後のキャリアを考えた時に資格を持っておくのも一つの手段かなという思いからぼちぼちAWSの資格を取り始める。

AWS全冠を意識し始めたのは、7個目の資格を取得したあたり（2023年8月ごろ）。
調べてみると、SAP/SAAが来年の7月末で期限を迎えることが判明し、「やるなら今か？あと5個・・・やってみるか」と気合を入れた。

前々からALL Certificate Engineerに認定されたらちょっと自慢できるかもと思っていたし、AWSのHPに自分の名前が乗るというのにも惹かれた。

---

# AWS資格取得のスケジュール

| 資格 |資格 |取得日 |
|:-----------|:------------:|:------------:|
|AWS Certified Solutions Architect - Associate|SAA|2021-02-13|
|AWS Certified Developer - Associate|DVA|2021-03-06|
|AWS Certified Solutions Architect - Professional|SAP|2021-07-31|
|AWS Certified DevOps Engineer - Professional|DOP|2021-08-14|
|AWS Certified Security - Specialty|SCS|2022-08-15|
|AWS Certified Advanced Networking - Specialty|ANS|2023-08-14|
|AWS Certified Database - Specialty|DBS|2023-08-19|
|AWS Certified Cloud Practitioner|CLF|2023-09-16|
|AWS Certified Data Analytics - Specialty|DAS|2024-01-05|
|AWS Certified Machine Learning - Specialty|MLS|2024-02-03|
|AWS Certified: SAP on AWS - Specialty|PAS|2024-02-17|
|AWS Certified SysOps Administrator - Associate|SOA|2024-02-24|

---

# 私の勉強方法

## 勉強はいつやっているの？
　・勉強は休日のみ（毎日継続して勉強するのが苦手）。
　・連休にまとめて勉強して試験を受ける（正月、夏季休暇、その他連休など）
　・試験前日(休日)と試験当日の午前中に特に勉強する。

---

## 書籍による勉強（SAA、SAP、SCS）
　一通り読む。
　無理に覚えない（※）。
　※頑張って覚えようとすればするほど時間がかかり、進まない
 　　→モチベーションが低下する（自分の場合）。

---

## Udemyの活用（SAA、SAP、DVA、DOP、SCS）
　問題は解かない（※）。解説文で勉強する。
　ポイントは、「テストを開始」した直後に「テストを完了」して、「問題を見直す」を使う。
　問題文を読んだ後、解説を読み、最後に選択支を確認して正解の内容を理解する。
　わからないサービスがあれば検索して調べて概要を抑える。

  ※ 「70問解くのに1時間以上かかり、時々間違った答えを選択し、結果は1時間後にわかる」ということにあまり意味が感じられなかった。（勉強時間は短縮したい。効率厨っぽい？）

---

## CloudLicense（旧TechStock）（ANS、DBS、CLS、DAS、MLS、PAS、SOA）
　本番の傾向に沿った問題集だと評判だったのでCloudLicenseの問題集を途中から採用。
　基本的に、Udemyと同様に問題は解かずに「問題を読む→解説を読む→回答を確認する」を繰り返す（※）。
　
　※最後に受けたSOAは、問題集で初めから7割近くの正答率があったため、「問題を解く→間違った問題/自信がなかった問題の解説を読む→間違った問題を再度解く」といったやり方で　勉強時間を短縮し、短期の受験に間に合うように工夫した（今までのAWSの知識で解ける問題が多かった）

---

# 経験から導き出すおすすめの勉強方法
必須ではないけれど、スペシャリティ以外の試験（SAA、SAP、DVA、DOP、SOA）は、基礎力を高めるために書籍を読むなど問題集以外での勉強をしてもよいかと思う。AWS BLACK BELT もオススメ。
 https://aws.amazon.com/jp/events/aws-event-resource/archive/?cards.sort-by=item.additionalFields.SortDate&cards.sort-order=desc&awsf.tech-category=*all

問題集は、UdemyよりCloudLicense（旧TechStock）
　理由
　　類似問題がそこそこ出る。
　　問題を解くとすぐに解説が見れる。
　　解説がUdemyより丁寧（主観です）。

　使い方
　　最新の問題からさかのぼって210問(30セクション)はやる。
　　全問やったほうが良いけど、自分はそこまでできなかった（結構しんどい）。
　　※解説を理解すること前提ですが、おおむね合格できるのではないかと。

---

# モチベーションの保ち方
・まずは簡単な資格を取る。
・資格を取ったら、すぐに（※）次の準備をする（書籍購入、試験予約）。

　※自分もそうだったのですが、合格直後にはモチベーションがすごく上がりますが、1か月持たずに急速に冷めて（下がって）いきます。

---

# 最後に
社内でもちらほら全冠とりましたーという話を聞くので全冠自体がレアではなくなってしまったのがちょっと残念です。
それでもめげずにやり遂げた達成感は今後につながると信じています。
また、AWS全冠保持者ですっていうのは今後の自分のキャリア形成をしていく中での結構なアピールポイントになると思っています。


2024年7月までにはSAPの再認定受けたいですし、今後もメリハリつけて勉強していこうかと。

勢いに任せて書きましたが、少しでも誰かの参考になればよいかなと思います。
Go言語初学者がエラーに立ち向かう方法: fmt.Printfデバッグ、エラーハンドリング

# なぜエラーになったかを考える
### ①直近で自分は何をやっていたかを考える！
### ②エラー文の内容をみる！
### ③文法があっているかを考える！

# fmt.Printfデバッグ
fmt.Printfデバッグを使用することで、スコープ内で呼ばれているかや、変数の中身の型や値が自分の意図するものになっているかを確認することができます。

**fmt.Printfデバッグの例**
```Go:main.go
fmt.Printf("CustomerNameError: %v\n", customerName)
//fmt.Printf("任意の命名: %v\n", 中身を見たい変数)
```
複数のfmt.Printfデバッグを作成し、エラーの原因の箇所を探す。

**実践例**
```Go:main.go
fmt.Printf("CustomerNameError①！！！: %v\n", customerName)
row := db.QueryRow("SELECT id FROM members where name = ?",customerName)
fmt.Printf("CustomerNameError②???: %v\n", customerName)
err := row.Scan(&customerName)
fmt.Printf("CustomerNameError③***: %v\n", customerName)
```

**出力結果**
```Go:main.go
fmt.Printf("CustomerNameError①！！！: %v\n", customerName)//CustomerNameError①！！！:ひなっこ
row := db.QueryRow("SELECT id FROM members where name = ?",customerName)
fmt.Printf("CustomerNameError②???: %v\n", customerName)//CustomerNameError②???:ひなっこ
err := row.Scan(&customerName)
fmt.Printf("CustomerNameError③***: %v\n", customerName)//CustomerNameError③***: 1
```
上記の例では
`customerName = ひなっこ`が入っていて欲しかったが、SELECTでレコードを取得した後のCustomerNameError③デバッグの箇所では`customerName = 1`となり、スキャーンしたidが代入されているということがわかり、エラーが発見できた！

# エラーハンドリング

```Go:main.go
c := echo.New()
type Response struct {
	Message string `json:"message"`
}

db, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		c.Logger().Errorf("Database connection error: %s", err)
		res := Response{Message: "Database connection error"}
		return echo.NewHTTPError(http.StatusInternalServerError, res)
	}
```
**echoを使用している際`c.Logger().Errorf`はエラーログをサーバー側で出力する**
```Go:main.go
c.Logger().Errorf("Error opening file: %s", err)
```

**エラーが返された際、Message内容をclient側で出力する**
echoには`echo.NewHTTPError`というHTTPErrorHandler型が用意されており、それを使用することでエラーが出た際にクライアント側で`Database connection error`を出力することができる。

```Go:main.go
res := Response{Message: "Error opening file"}
		return echo.NewHTTPError(http.StatusInternalServerError, res)
  //type HTTPErrorHandler func(err error , c Context )
```
# 参考文献

https://pkg.go.dev/github.com/labstack/echo/v4#Logger

https://pkg.go.dev/github.com/labstack/echo/v4#NewHTTPError

https://zenn.dev/yagi_eng/articles/go-error-handling
Qiitaをはじめてみた(初投稿)

くいーた？
quiitaなるものを始めて見た。

![dasdaewqerszdf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3722357/0678de77-60b8-da08-ab54-3a0e603b26b7.png)

普段は絵を描いたりしている。
趣味でロボットを制作したりしているが、Pythonというものには
まだまだ慣れていない。。。
LangchainとFastchatを使ってWindowsでローカルRAGを構築してみたりしてみたが、
難しいことはまだ何一つできないといった状況である。

プログラマーのためになるものを投稿しろとあるが、この記事にはまったく意味はない。
削除されないと願おう

そんな私であるが、しばしの間、ブログ？投稿に付き合ってもらえたらなと思う。


以上。
ありがとう。
図書購入申請アプリの作成 by PowerApps

# 背景
[JPAUG広島](https://jpaug-hiroshima.connpass.com/)の24/2/24ハッカソンにて図書購入申請アプリのお題をいただきアプリ作成しましたので忘れないうちに中身解説いたします。豪さん、Kuroさん、参加者の皆様ありがとうございました。

# データソース
下記の列を持つSharepointリストを設定。
| 名前 | 型式 |
|:-:|:-:|
|タイトル   |一行テキスト   |
|金額   |通貨   |
|作者   |一行テキスト   |
|承認者   |一行テキスト   |
|承認状況   |一行テキスト   |
|申請理由   |複数行テキスト   |

# PowerAppsアプリ(自動生成)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/72f24b38-fe73-60fe-b3f6-834f3bc3183b.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/31001af8-01c9-ab64-e2a5-07ac21324f00.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/4ae94602-6f94-c5c6-bd46-e7828517db06.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/ad037471-0408-8562-6837-7924399dafdb.png)
の流れでデータソースのSharepointリストを選択。

# 自動生成アプリの修正＆機能追加
・添付ファイルのカードは不要なので削除します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/16c4ca24-39ef-e08c-1523-afef44f9b784.png)

・承認状況カードはユーザーにいじってほしくないのでロック解除してViewモードにします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/e8f2f306-9cab-d773-e652-ed3fb5b99e42.png)

・`SelectedRecordHeaderContainer1`に"承認依頼"ボタンを配置
    ⇒ Onselectに以下を記述
```
Patch(データソース,RecordsGallery1.Selected,{承認状況:"承認待ち"});
FlowApproveBookRequest.Run(RecordsGallery1.Selected.ID)
```

・`SelectedRecordHeaderContainer1`より"SelectedRecordTitle1"を削除

・`EditIconButton1`のDisplayModeプロパティに以下を記述
```
If(StartsWith(RecordsGallery1.Selected.承認状況,"承認"),DisplayMode.Disabled,DisplayMode.Edit)
```

・`FlowApproveBookRequest`のフロー作成
![flow.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/6e1edab2-b406-6fd4-e972-b8248da0458e.jpeg)


・ Formの各カードのWidthプロパティに次式を記述（はみ出し対応）
```
If(MainScreen1.Size = ScreenSize.Small, Parent.Width, Parent.Width/2)
```

# まとめ
以上で承認申請ボタン押下で購入申請が"承認者"へ入力したメルアドへ配信され、承認プロセス中は編集ロックがかかるシステムの実装ができました。


このままだと承認済後も承認申請ボタンが押下できてしまうので、承認申請ボタンのDisplayModeプロパティかVisibleプロパティへ条件式を記述してあげればより良いと思います。

また、"承認者"を自動設定とか、事前設定データを参照とかにしてあげればより良い感じです。

さらに、承認申請ボタンをForm1がViewモードの時だけVisibleになるように設定してあげるのが適切かと思います。
【Unity公式ObjectPool】プールにオブジェクトを返却する超便利機能！

# 解決したいこと
Unity2021.1から、Unity公式がオブジェクトプールを実装してくれています。

とても便利なのですが、
使い終わったオブジェクトをプールに戻す時、以下のように書く必要があります。

```csharp
pool.Release(obj);
```

このメソッドを呼び出すためには、Release呼び出すクラスが
* プールのインスタンス
* 返却対象にインスタンス

の両方を参照する必要があります。
そのため、機能が分離できず、返却ロジックも書きにくくて、とても不便です！！

**こちらは、Unity標準機能を利用することで、この問題に対処する方法の記事になります！**


# IDisposableを使う方法
実はPoolからオブジェクトを借りてくるときに、返却機能を一緒に取り出すメソッドが用意されています。

```Get()```メソッドの返り値を使わずに、``` Get(out T obj) ```メソッドを使って、out 修飾子のついた引数でオブジェクトを取り出してください。

```diff_c_sharp:仮にBullet型を取り出す場合

- Bullet obj = _pool.Get();

+ IDisposable disposable = _pool.Get(out Bullet obj);

```

このとき返り値となっている型は```IDisposable```を実装しており、```IDisposable.Dispose()```でこのオブジェクトをプールに返却する機能を持っています。

::: note
実際にこのとき返り値となっているのは``` PooledObject<T> ```という型です。
<details><summary>PooledObjectのコードを見たい方はこちら</summary>

```csharp
  public struct PooledObject<T> : IDisposable where T : class
  {
    private readonly T m_ToReturn;
    private readonly IObjectPool<T> m_Pool;

    internal PooledObject(T value, IObjectPool<T> pool)
    {
      this.m_ToReturn = value;
      this.m_Pool = pool;
    }

    void IDisposable.Dispose() => this.m_Pool.Release(this.m_ToReturn);
  }
  
```

</details>

今回必要なのは```IDisposable```の機能だけなので、変数宣言で```IDisposable型```を指定して変換しています。
:::




あとは、このIDisposableをObjの返却処理を担当するクラスに渡してあげれば完成です！

例えばBulletクラスを都度借りてきて返却するコード例は以下のようになります！！

```csharp
public class Bullet : MonoBehaviour
{
    private IDisposable _disposable;

    public void SetReturner(IDisposable disposable)
    {
        //外部からこのメソッドを叩くことで、返却機能を登録できるようにする
        _disposable = disposable;
    }

    private void Update()
    {
        if ( /*返却の判定処理*/)
        {
            // disposeを呼ぶだけで返却される
            _disposable.Dispose();
        }
    }
}
```

```csharp
public class BulletPool : MonoBehaviour
{
    private ObjectPool<Bullet> _bulletPool;

    private void Awake()
    {
       /* _bulletPoolをnewしておく */
    }

    public Bullet GetBullet()
    {
        //out修飾子でbulletを取り出し、返り値をIDisposableとして取得する
        IDisposable disposable = _bulletPool.Get(out var bullet);
        //取得したbulletのインスタンスに、プールへの返却機能を渡す
        bullet.SetReturner(disposable);
        //呼び出し側にBulletのインスタンスを返す
        return bullet;
    }
}
```

Poolからは```IDisposable```しか渡さず、
インスタンス側から返却ロジックを叩くことができるようになりました！

生成機能と返却機能を簡単に分離できるようになるので大変便利です！！

# おわりに

以上でこの記事はおわりです！

また、今回省略したPoolの生成処理の中では、
オブジェクト返却時のコールバックを登録することができます。

```gameObject.SetActive(false)```など、
返却時に他の処理が必要な場合はそちらで登録するのをオススメします！

ぜひ素敵なObjectPoolingライフを送ってください！！！


::: note warn
この利用方法は、```struct```である```PooledObject```を```IDisposable```にキャストしているのでボックス化が起ります。
おそらく、本来この機能は、```using```を利用して、短い期間で寿命管理ことを想定された機能です。

その機能をハック的に利用しているため、ボックス化が起きてしまいます。
パフォーマンスが重要な場面では、```PooledObject```と同じ働きをするclassを自作する方針も検討してみてください。

（検証、ご指摘くださった@junerさま、ありがとうございます！）

※2024/02/25追記>2024/03/04編集
:::
Proxmox VE 上のVMがio-errorになった場合の対応（ストレージ使いすぎ編）

## TL;DR

- PVE上のVMで、状態io-errorになっているVMがいるぞ？
- 原因はLVMの使いすぎ！
- VMの復旧方法
  - 対象VMを単純削除出来なかったので手順のメモ。

## 概要


先ほどまで利用できていたVMが、以下のようにIOエラー状態に。
IOエラーになればもちろんVMの利用はできません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2459468/1dfcd3c4-7bbe-ca0b-b548-b5ab49421f33.png)



## 原因

ディスクの使いすぎですね…
ディスク容量を意識しないで色々作りすぎました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2459468/0cf5a8e4-49fa-c2c8-d00a-698cc6518bef.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2459468/e27ea88a-02b6-ad98-dc78-642fccee3e3d.png)


マニュアルにも以下記載があります。

今回VMに割り当て元のストレージはLVM-Thinです。
動的割り当てされますので、実際の容量以上に割り当てることが可能です。
だからといって大量に割り当てたりすると、今回のような事象につながります。

以下マニュアルより抜粋。
```
7.1.1. シンプロビジョニング

注意　ストレージがいっぱいになると、そのストレージ上のボリュームを使用しているすべてのゲストがIOエラーを受け取ります。
これはファイルシステムの不整合を引き起こし、データの破損につながる可能性があります。
そのため、ストレージリソースの過剰なプロビジョニングを避けるか、あるいは自由なスペースを注意深く監視して、このような状況を避けることが推奨されます。
```




## 対処
今回は不要なVMごと削除しました。
VMは一度停止しないと削除できないのですが、IOエラー状態のVMの削除に関してTips。

- IOエラーVMは停止しないと削除できない。が…
  - 左ペインで対象VMを右クリックからは停止は不可。
  - 左ペインで対象VMを左クリック-右ペインのシャットダウン配下のメニューからは停止が可能。


## そのほか
### テンプレートもリソースを割り当てられていた
VMを増やしたり、割り当てディスクを大きくもしたのですが、上限いっぱいになるほどしたっけ？とは疑問に思っていました。
テンプレート、という名前先行でリソースを保持せずに、VM新規構築時に参照される設定群ぐらいに思って、大量にテンプレート作っていたのですが、テンプレートもリソースを割り当てられていることに気が付きました。

テンプレートについてはテンプレートとクローン、完全なクローンとリンククローンの違いと合わせて別途整理したいと思います。

## 参考


https://pve.proxmox.com/pve-docs/pve-admin-guide.html#chapter_lvm
【JavaScript】fetchのレスポンスのコンテンツタイプが正しいか検証する方法

以下のようにレスポンスヘッダーの`content-type`を確認することで検証できます。

```javascript
async function fetchSample(request) {
  try {
    const response = await fetch(request);
    
    const contentType = response.headers.get("content-type");
    if (!contentType || !contentType.includes("application/json")) {
      throw new TypeError("JSONではありません。");
    }
    const jsonData = await response.json();
    // ...
    
  } catch (error) {
    console.error("Error:", error);
  }
}
```

https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch#headers
SQLite入門:データベースファイル作成からテーブル作成の流れ！よく使うコマンド

# データベースファイル作成からテーブル作成の流れ
### ⚫︎リポジトリの直下ディレクトリからデータベースファイルを作成したいディレクトリに移動する。
今回はdbディレクトリに移動する
```
cd db
```
### ⚫︎dbディレクトリの中でsqlite3を動作する。

```
sqlite3
```
### ⚫︎customer.sqlite3という名前のデータベースファイルを作成

```
sqlite> .open --new customer.sqlite3
```
### ⚫︎テーブル作成
```
sqlite> CREATE TABLE customer(id INTEGER PRIMARY KEY, name TEXT NOT NULL);
```
### ⚫︎テーブルが作成できていることを確認
```
sqlite> .ta
```
# よく使うコマンド

### ⚫︎sqliteから抜ける
下のコマンドか、**control + D**でsqliteから抜けることができます。
```
sqlite> .exit
```
### ⚫︎テーブルを作成した際の定義を見たい時に使用
```
sqlite> .schema customer
```

### ⚫︎すでに作成したテーブルの定義を削除
```
sqlite> drop table customer
```
### ⚫︎テーブルに入っている中身を見たい時
```
sqlite> SELECT * FROM customer;
```

# 参考文献

https://www.javadrive.jp/sqlite/
[Azure] 仮想マシンの自動シャットダウンとその周辺（疑問に思ったこと）について調べた

# はじめに
どうも、SobaNyakuです。蕎麦と蒟蒻が大好きです。
今回は、Azure 仮想マシンの自動シャットダウンについて、挙動を調べたので記載いたします。※最新の正式な情報は公式から取得してください。



# 自動シャットダウンについて
誰もが使う機能だと思います。停止漏れを防げて便利ですよね。

> Azure VM の自動シャットダウン機能は、必要のないオフ時間帯に VM をシャットダウンし、再び必要になったら自動的に再起動することで、コストを削減するのに役立ちます。

https://learn.microsoft.com/ja-jp/azure/virtual-machines/auto-shutdown-vm?tabs=portal


# 設定の仕方
>1. Azure portal で、自動シャットダウンを構成する仮想マシンに移動します
>1. 仮想マシンの詳細ページで、[操作] セクションの [自動シャットダウン] を選びます
>1. [自動シャットダウン] 構成画面で、スイッチを [オン] に切り替えます
>1. 仮想マシンをシャットダウンする時刻を設定します
>1. [保存] を選んで自動シャットダウンの構成を保存します

# 通知
通知を設定すると以下のようなメールが届きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3659255/c2573cd8-d380-a904-1d00-cb24b52f7871.png)


# 疑問1. 30分前に通知くるけど、30分切った状態で設定するとどうなる？
例えば、21:40に22:00の自動シャットダウン設定をしてみました。
### 予想順
1. 通知は来ないが22:00になったら停止する
2. 通知は来ず、停止もしない（24時間と20分後に停止）
3. 通知が15分前とかに来て22:00に停止
4. バグって停止設定は有効化しない 

### 結果
結果は...**2番**でした！(`通知は来ず、停止もしない（24時間と20分後に停止）`)
20分以内には通知は来ず、停止もしません:cry:
ですが24時間待てば通知も停止もされますので、ご安心を。

# 疑問2. 通知先メールアドレスは自分のアカウント以外やgmailなどでも行ける？
いけました！（まぁそれはそうか）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3659255/6fc3cad2-3670-40a2-70b8-d2d03e2427cc.png)


# 疑問3. 自動起動は？
20240224現在、どうやら同じような設定は無いようでした。
（"VM上のポチポチで設定完結する需要"が高そうな機能ですが...）

Auromation Accountで皆さんやっているようです。

https://learn.microsoft.com/ja-jp/shows/it-ops-talk/auto-shutdown-and-auto-start-an-azure-vm?source=recommendations


# おわりに
最後まで見ていただき、ありがとうございます。
少しでも読んでいただいた方の役に立てたら幸いです。
よかったらチャンネル登録（フォロー）、高評価（いいね:heart_decoration:）、コメント:pen_fountain:などなど何でもお願いします:pray:

週一で投稿目指しています。もし何かリアクションをしてくれるとやる気が出るので、次週は投稿することを約束します。

※今週も週一投稿できました。いつもありがとうございます。
Ubuntu22.04でROS2開発環境のセットアップ

# この記事ついて

個人的な覚え書きです。

## 環境設定

### Raspberry Pi
rpi-imager
https://linuxfun.org/2021/01/17/how-to-use-raspberry-pi-imager-ubuntu/

### Ubuntu 22.04 LTS
<!--
https://jp.ubuntu.com/download
-->

https://kledgeb.blogspot.com/2022/04/ubuntu-2204-64-windowslinuxmacosubuntu.html

https://ubuntu.com/download/desktop/thank-you?version=22.04.4&architecture=amd64

https://remylog.com/ubuntu-20-04-balenaetcher-install/

### ROS2のインストール
https://qiita.com/kccs_yoshiteru-imamura/items/2ff8d1f56e26d781afe4
```
sudo apt update && sudo apt install curl gnupg lsb-release
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
```

### ターミナルの設定
- システムのテーマ色を使用する　チェック外す
- 黒地に白文字
- 透過の背景を使用する　チェック入れる
- システムテーマから透過を使用する　チェック外す
- パレット：Linuxコンソール
- 太字のテキストを明るいで表示する　チェック入れる

### キーボードの設定

Mozcで日本語入力できるようにしておく
https://blog.kapiecii.com/posts/2020/05/10/ubuntu20-04-mozc-setting/

### エディタの設定

- https://zenn.dev/cacbahbj/articles/a753aaea7ad82b
- monokai

https://pulsar-edit.dev/

1. Download
1. x86_64 - For most desktops and laptops with Intel or AMD processors > .deb
1. sudo apt install ./Linux.pulsar_1.109.0_amd64.deb
1. https://zenn.dev/cacbahbj/articles/a753aaea7ad82b
1. ppm install --packages-file pulsar_packages.txt --verbose


## ROS2

### 参考サイト
- https://github.com/youtalk/get-started-ros2
[Multipass] Running Ubuntu 20.04 LTS on macOS (Sonoma 14.2.1)

# My Environment

> Chip: Apple M3 Max
> Memory: 64GB
> macOS: Sonoma 14.2.1

# Installation

```zsh
% brew install multipass
% multipass version
```

# Usage

```zsh
% multipass fd  # Show available images
% multipass launch 20.04 -c 4 -m 8G -d 64G  # Create a new instance with Ubuntu 20.04, named 'foo', with 4 CPUs, 8GB of memory, and 64GB of disk space

% multipass ls  # List all your instances

% multipass start foo  # Start the 'foo' instance
% multipass shell foo  # Log into the 'foo' instance. If 'foo' is not started, this command will start it automatically before logging in.
$ exit  # Log out from the current instance
% multipass stop foo  # Stop the 'foo' instance

% multipass delete foo  # Move the 'foo' instance to trash
% multipass purge  # Clear the trash, removing all deleted instances
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3269836/e6e0828d-87ff-1972-ff2d-7ce8aeb09293.png)

# Next Article (SSH from zsh/VSCode to UbuntuVM)

https://qiita.com/shisotem/items/f59792aecb9453a75568

# References

- How to start Multipass:

https://www.farend.co.jp/blog/2022/08/multipass/

https://qiita.com/f-paico/items/4cf8c697bacba38ab0f5
【初心者向け】Javaの変数～参照型～

## :pushpin:前回の記事はこちら
https://qiita.com/nukoxo/items/5d9d72f3e451a9afb781

## :ledger:参照型とは
基本データ型は変数に直接データが代入されますが、参照型は異なります。

変数に代入されるのは`データが置かれているメモリ上の場所(アドレス)`となります。

コードサンプルを見てください
~~~java:基本データ型
int sum = 12;
~~~
こちらのコードには`sum`という変数に`12`という数字データが
直接代入されています。

~~~java:参照型（文字列）
String name ="あいう";
~~~
私たちには「あいう」と見えていますが
実際には「あいう」という文字列が代入されているのではなく
「あいう」という`データが格納されている場所（メモリ）の参照値`が入っています。

代入された値自体はメモリの別の場所に保存されています。

## :ledger:変数のまとめ

データ型変数や参照型変数を紹介してきました。

プログラム内で文字や数値などのデータを扱うには変数が必要です。

ひとつひとつの命令を実行するのはPCの中でもCPUという部分です。
CPUが命令を実行するには、PCのメモリ上にデータが展開されていないとできません。
<b>`変数と宣言は、メモリ上にデータを格納するための作業`</b>といえます。

***
メモリについても、もっとアウトプットしていきたいです。
ChromeのPriorityヘッダーについて

Chrome 124からHTTPリクエストにPriorityヘッダーが付加されるようになります。

簡単に、Priorityを紹介します。

## Priorityヘッダーについて
Priorityヘッダーは『[RFC 9218 Extensible Prioritization Scheme for HTTP](https://www.rfc-editor.org/rfc/rfc9218.html)』で定義されています。

HTTP/2やHTTP/3では一つのコネクション上で複数のHTTPリクエスト・レスポンスをやりとりできます。priorityヘッダーを用いて複数リクエストを投げた中で、どのレスポンスを優先度をサーバにシグナルできるようになります。
(あくまで一つのコネクション内の優先度なので、全部優先度上げたら良いということではない)

Webページをレンダリングする上で早く欲しい物もあればあとからでも良いものもあります。ブラウザが自身が欲しい物にあわせてPriorityを設定することは、First Contentful Paintを改善します。（もちろんサーバ側がPriorityヘッダーをサポートしている場合のみ）

Cloudflareの調査した『[Introducing HTTP/3 Prioritization](https://blog-cloudflare-com.webpkgcache.com/doc/-/s/blog.cloudflare.com/better-http-3-prioritization-for-a-faster-web)』によると、First Contentful Paintが最大37% 削減へるケースもあったとのことです。

### 例
priorityヘッダーの例を示します。

```
Priority: u=1, i
```
- u: Urgency、優先度の指定であり0~7の値をとり、0の方が優先度が高い
- i: Incremental、画像のように読み込みながら処理できることを示す。同一優先度でiがつくものへ並列に処理される

## Chromeで有効にする
本日時点の、Chrome Canary v124 では起動時にflagを付けることで有効にできる。

`--enable-features= PriorityHeader --flag-switches-end`

(なお起動バイナリの場所はChromeで `chrome://version/` にアクセスすると分かる)

## FetchPriority属性をつけたときの挙動
基本的にはブラウザが自動でpriorityヘッダーを付与するので、デベロッパーが意識することは多くないはずです。

自前で優先度を制御する際はFetchPriority属性を付与することで、プロトコルレイヤの優先度も合わせて設定されめます。

```
  <img src="https://example.com?/1" fetchpriority="low">    // u=3
  <img src="https://example.com?/2" fetchpriority="auto">   // u=2
  <img src="https://example.com?/3" fetchpriority="high">   // u=1
```

また、JavaScriptでFetchする際は自前でヘッダつければコントロールできますね！
Rust と OS の知識 0 からはじめるRustで始める自作組込みOS入門 - 前半（スケジューラの実装まで）

# きっかけ・読んでいく本
うさねこらーじの Discord サーバーで、いろいろな先輩たちに技術のことを教えてもらっています。
https://discord.gg/RMq7e5qbQj

このなかで、著者の garasubo さんにサポートしてもらいながら以下の本の内容を実装しているのですが、 Rust の知識も OS の知識もない私にとっては内容がかなり高度なので、補助のためにこのブログを作成しています。

Rustで始める自作組込みOS入門
https://amzn.asia/d/ebuOUM1

ぜひこの本を読みながらこのブログを参照していただけると嬉しいです。

# 第 2 章 ベアメタルで Hello World
## 単語のかみくだいた説明
### ベアメタルプログラミング
OSのない環境で実行するためのプログラムを書くことです。この環境下では CPU ごとに決まった動作（たとえば、決まったアドレスにあるプログラムを実行する）が行われます。
### 例外ハンドラ
例外ハンドラは、例外が発生したときにジャンプする命令のアドレスを記した配列のことです。
### ベクターテーブル
Armv7-M のマニュアル https://developer.arm.com/documentation/ddi0403/latest/ によると以下のようになっています。
> スタックポインタや、例外ハンドラのエントリーポイントのアドレスを含んでいます。

スタックポインタの初期値と例外ハンドラを含めることで、リセット時やエラー時の挙動を定義しています。
どこに置かれているかはチップの実装によります。
### リンカ・リンカスクリプト
リンカはコンパイルにより生成された機械語の断片たちを適切な場所に配置していく作業を行います。イメージとしては、高水準言語のなかで関数名による呼び出しなどを行っていたところを、機械語の断片がある実際のアドレスに置き換えていくという感じです。リンカスクリプトは、ベアメタルプログラミングをする際にメモリのレイアウトやプログラムをそこにどうやって配置するかを定義することで、リンカが関数のポインタなどを正しく使えるようにしているイメージです。今回は `link.ld` がそれに当たります。

### マングリング
https://tomoyuki-nakabayashi.github.io/book/interoperability/rust-with-c.html

Rust はコンパイラされるときに関数名を別の名前（シンボル）に変更します。これをマングリングといいます。そのため、 Rust の外にエクスポートする関数名はこの処理を行わないようにコンパイラに支持する必要があります。

## Rust の記法のうちコードを読むときに必要なものの紹介
-  関数の返り値が `!`で示されているとき、その関数は終了することがありません（発散します）

## `link.id` の説明
```
SECTIONS
{
  .vector_table ORIGIN(FLASH) :
  {
    LONG(ORIGIN(RAM) + LENGTH(RAM));　//(i)
    KEEP(*(.vector_table.reset_vector)); //(ii)
  } > FLASH
  ```

(i)...RAM 領域の末尾を指定して、スタックポインタの初期値を配置しています。スタックポインタは末尾から先頭に向かって伸びていくので、このように RAM 領域の先頭ではなく末尾から始めています。 
(ii)...KEEP() はリンカによるリンカ省略を防ぐための関数です。リンカ省略は、使っていない部分のコードをプログラムに含めないようにすることです。使っている関数をちょうど木のように (これを dependency tree といいます) 辿っていって、到達できるところのみをプログラムに含めます。 KEEP() は、中に入れた関数をこの tree の根本としてマークするようなイメージです。

# 第 3 章　割り込み制御
## 単語のかみくだいた説明
### ベリフェラル
直訳では周辺機器となりますが、マイコンにおいては内蔵された様々な装置を意味します。LCDや無線モジュールなど。
## 疑問解決
### スタック領域に保存されないレジスタの値ってどうなるの？
例外が発生するとき、LR, R12, R3 - R0 がハードウェアにより自動的にスタック領域に退避されますが、残りの R4 - R11 はそうされません。これらの範囲は、Arm の関数の呼び出し規約により、関数を呼び出したら関数側で値を戻す必要があります。
（なんでそうなっているのか知りたい）

# 第 4 章　プロセス切り替え
## 単語のかみくだいた説明
### スレッドモード/ハンドラーモード and カーネルモード
スレッドモードは通常のプログラムが実行されている状態で非特権状態になることが可能、ハンドラーモードが例外が発生して例外ハンドラに移動している状態で特権状態になる。
カーネルモードは２つとは全く別で、通常よりも権限の強い状態で CPU 上で動くこと（第一章）。本CPUでは触れなくて良い。

## 2 種類のスタックポインタ
Armv7-M ではメインとプロセスの 2 種類のスタックポインタを使い分けることができます。
> Two stack pointer (SP) registers, SP_main and SP_process. These are banked versions of SP, also described as R13.

## 複雑なポインタと参照の操作部分
```
let context_frame: &mut ContextFrame = &mut *(ptr as *mut ContextFrame);
```
ここでは、ptr の位置のデータを　ContextFrame 型として取り出しています。
まず、`ptr as *mut ContextFrame`でポインタ ptr の位置を ContextFrame 型のポインタとして認識して、それに`*`をつけることで中の値を取り出し、それに対して参照を生成してそれを context_frame に束縛しています。つまり、ポインタを参照に変換しています。

## Rust: `'a` ってなに？
これを読めばわかります。
https://doc.rust-jp.rs/book-ja/ch10-03-lifetime-syntax.html

## Rust: Deref ってなに？
これを読めばわかります。
https://doc.rust-jp.rs/book-ja/ch15-02-deref.html
Slackワークフロービルダー×Googleスプレッドシートで当番お知らせbotを作る

私の所属する開発チームでは、日々の朝会のファシリテーション担当をローテーションで回しています。
都度当番表を確認しにいく手間を省くため、毎朝ファシリ当番をメンションしてくれるbotを、Slackワークフロービルダーを用いて作ってみました。

## 完成形
![完成イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513849/c68170b4-c5a3-3707-3cdc-401081747335.png)
slackに上記の投稿がなされます。
<@メンバーID>で担当者にメンションは飛びますが、@ユーザー名だけで実現することはできませんでした。惜しい。


## 手順
### Googleスプレッドシート
以下のようなシートを作成し、Googleスプレッドシート完結でその日の担当者が自動入力されるように設定しました。
![スプレッドシート全体.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513849/bb620c30-3171-d28c-7ade-b943d769898c.png)

**1. メンバーリストを用意する（F, G列）**
メンバーリストは、メンバー名とメンバーIDで構成されています。
メンバーIDはSlackプロフィール画面の縦三点リーダー→メンバーIDをコピー で取得できます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513849/223fbd7b-d61d-e0bc-0424-94349c0a48f9.png" width=50%>

**2. 運用開始日からの経過日数を取得する（D列）**
TODAY()とNETWORKDAYS()を用いています。祝日一覧リストを参照することで、祝日を経過日数カウントから除外しています。

**3. 経過日数をメンバー数で割った余り（H4）を使って、本日の担当者名、担当者IDが格納されたセルを取得する（B4, C4）**
n人のメンバーがいるとき、余りは0からn-1の値を取りますが、作成したシート上でメンバーが格納された行番号は2行目からn+1行目までとなっています。そこで、担当者セルを取得する場合は、ADDRESS（{余り}+2, 6, 3）としてF列から担当者を抽出します。

**4. 土日祝ではない場合、ワークフロービルダーで読み取る箇所に担当者名と担当者IDを格納する（B2, C2）**
E列にWEEKDAY()を使った土日判定、祝日一覧リストとCOUNTIF()を用いた祝日判定を記入しています。その上で、B2, C2において、土日祝のいずれにも該当しない場合、INDIRECT()で先ほどB4, C4に設定したセル番号の値を表示するようにしています。
ワークフロービルダーのスケジュール実行では祝日の除外ができないのですが、上記のように、休みの日はスプレッドシート上で読み取り箇所に担当者を入れないようにすることで、誰にもメンションが飛ばないようにしました。

### Slackワークフロービルダー
ワークフロービルダーの画面には、Slack画面左上のワークスペース名の部分を押して、「ツールと設定」→「ワークフロービルダー」で遷移できます。
以下のようなワークフローを作成しました。
![ワークフロービルダー全体像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513849/3a4de7b7-df60-4764-efb9-c874bca02700.png)

**1. スケジュールに基づきワークフローを開始する**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513849/16c7f474-e1ea-0fff-f94b-92692731678f.png" width=60%>

**2. スプレッドシートと連携する**
ここで設定した「検索する列」と、その列の中から選択可能な「検索するセルの値」に基づき、スプレッドシート上で「検索するセルの値」の行に含まれる値をワークフロービルダーから読み取れるようになります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513849/bbe17073-e8ed-3ea3-e238-381e84f803e5.png" width=60%>

**3. メッセージを設定する**
「変数を挿入する」→「列の値」からスプレッドシートの値をメッセージに埋め込むことができます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513849/24df22e5-03f2-febf-48a4-001476b79f4f.png" width=60%>

## おわりに
綺麗な見た目とは言い難いですが、短時間で欲しい機能を作ることができて良かったです！お読みいただきありがとうございました。