OmniAICreator/Qiita-1.07M huggingface dataset:
Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「Blob Storageの価格」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「Blob Storageの価格」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure でのストレージの実装と管理](https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-storage/)
◇対応するモジュール
[Blob Storage の価格を決定する](https://learn.microsoft.com/ja-jp/training/modules/configure-blob-storage/8-determine-storage-pricing)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「BLOBのアップロード」](https://qiita.com/fsd-jume/items/72cb13107e4b4a4df477)

## Blob Storageの価格
### Blob Storageの課金に関する考慮事項
**◆パフォーマンスレベル**
・アクセス層により、格納データ量/データを格納するコストが決まる
・コスト(GBあたり)：アーカイブ層 < クール層 < ホット層

**◆データアクセスコスト**
・クール層/アーカイブ層ではデータの取得にGB単位でコストが発生
⇒ホット層ではデータの取得にコストはかからない
・コスト(GBあたり)：アーカイブ層 < クール層

**◆トランザクションのコスト**
・すべてのアクセス層でトランザクションごとのコストが発生
・コスト(トランザクションあたり)：ホット層 < クール層 < アーカイブ層

**◆geoレプリケーションデータ転送コスト**
・2つ目のリージョンにデータをレプリケートする際に使用する帯域幅の料金
⇒GRS/RA-GRS/GZRS/RA-GZRSアカウントが対象
※上記アカウントに変更した場合も発生
・コストはGB単位

**◆送信データの転送コスト**
・外部(リージョン外)へのデータ転送は帯域幅の使用量に従ってコストが発生
・コストはGB単位

**◆ストレージ層の変更**
・クール層→ホット層：ストレージアカウント内の全データの読み取りと同等の課金
・ホット層→クール層：クール層への全データの書き込みと同等の課金※GPv2(汎用v2)アカウントのみ

## 次の学習内容
**◆Azure Storageのセキュリティ戦略**

https://qiita.com/fsd-jume/items/8411095ac53ddcdfc5b3

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
ChatGPTに聞きます。

**ChatGPTに聞きます。**
![6mMfkmBJhzTeFUzqrRoA8J4KaAY2/PszZkZrp2nz2GS8O.jpg](https://firebasestorage.googleapis.com:443/v0/b/type-c1c71.appspot.com/o/6mMfkmBJhzTeFUzqrRoA8J4KaAY2%2FPszZkZrp2nz2GS8O.jpg?alt=media&token=6de1a2fa-980d-494c-b27d-f7521a3874f5)
Pythonでfileか文字列を「標準入力へ」リダイレクトしstreamとして扱う

こんにちは、tdzzです。

pythonの標準入力はstreamの特性を持ちます。データを取得しながら少しずつ処理することができます。しかし、入力ソースは時々ファイル・url形式で提供されて、データを取得するとき、同じコードを複数回書く場合があります。リダイレクト記号「`<`」を使ってもいいですが、ユーザー側で使い分けなければなりません。ですから、入力ソースを標準入力へリダイレクトして、標準入力を優雅に処理するコードを再利用しましょう。

## やり方

リダイレクトしたいデータを`StringIO`か`BytesIO`オブジェクトに変換し、with文で`sys.stdin`に代入すればよい。

```py
import sys
from io import StringIO

s = """Carol
Yun Yan Cheng Yu
2021-11-02
"""

res = []
with StringIO(s) as sys.stdin:
    while True:
        line = sys.stdin.readline()
        if not line: break
        res.append(line)

print(res)
# 出力は ['Carol\n', 'Yun Yan Cheng Yu\n', '2021-11-02\n']
```


## 参照リンク

https://stackoverflow.com/questions/28797643/how-to-take-a-file-as-input-stream-in-python
【RubyMine】知っておくと便利なショートカット8選

# はじめに
私は普段、[RubyMine](https://www.jetbrains.com/ja-jp/ruby/) というIDE(Integrated Development Environment)を用いてMacでRuby/Railsプロジェクトの開発をしています。
そんなRubyMineには便利なショートカットが数多くあります。
中でも、**頻繁には使わないけど知っておくと便利なショートカット**を一部抜粋して紹介しようと思います。

すべてのショートカットを知りたい方は ▷[こちら](https://resources.jetbrains.com/storage/products/rubymine/docs/RubyMine_ReferenceCard_mac.pdf)。
よく使う便利なショートカットを知りたい方は ▷[こちら](https://qiita.com/kd_rn/items/69a3a97a0fe684ca9d4c)。

# 知っておくと便利なショートカット8選
| 記号 | 意味 |
|:-:|:-:|
| ⌃ |Controlキー|
| ⌥  |  Optionキー |
|  ⇧ |  Shiftキー |
|  ⌘ | Commandキー  |
|  ↑ | 上矢印キー  |


## 1. ⌥⌘T :  囲む(begin…end, if…then…end, その他)
選択している箇所を囲んでくれるショートカットです。
囲みは7種類あり、`()`や`if...end`、`begin...end` などがあります。
![囲み.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578726/c9a0247c-a888-2640-b683-d48941495fed.gif)

## 2. ⌘- / ⌘⇧- : コード ・ ブロックの縮小/すべて縮小
ブロック内にカーソルを置いてこのショートカットを叩くとブロックを縮小してくれます。
ブロックが多いテストファイルなどで使うことが多いです。
![縮小.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578726/e5e8fb88-6c2b-ec7a-08ea-829089051040.gif)

## 3. ⌃⌘↑ :  Rails モデル/ビュー/コントローラーなどに移動
関連するファイルに移動できるショートカットです。テストファイルにも移動できます。
`⇧⇧` で関連するファイル名を検索することさえ億劫な時に役に立ちます。
![移動.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578726/156b6388-a583-6f61-7065-b4bf3e5e5185.gif)

## 4. ⌘E : 最近使用したファイルのポップアップ
最近使用したファイルがポップアップで表示されます。
開いてるファイルが多くて整理していたら間違えて必要なファイルも閉じてしまった！なんてときに助かります。
![再度開く.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578726/a24db7b6-d7b5-8056-8ee8-c70733e2b695.gif)

## 5. ⌘⇧deleteキー : 最後に編集したロケーションにナビゲート
最後に編集した場所に飛べるショートカットです。
飛べるだけなので編集した箇所が編集前に戻ることはありません。
![編集箇所.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578726/6876ec3f-9df1-c9b2-55ee-fbb085fca733.gif)

## 6. ⇧F6 : 名前変更
リファクタリングのショートカットの一つです。クラス名、変数名、メソッド名などが変更できます。
但し、キーボードの配置上とても叩きづらいです。
![名前変更.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578726/f1e81f96-027c-5025-5544-16ab12f9fa2c.gif)

## 7. ⌥⌘M : メソッドの抽出
こちらもリファクタリングのショートカットの一つです。選択箇所をメソッドとして抽出できます。
![メソッド化.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578726/3779e072-287d-9af5-431e-ddbd5fd1ddba.gif)

## 8. ⌃T : リファクタリングのクイックリスト
名前変更やメソッド抽出、パラメーターの導入や定数の抽出などのリファクタリングのショートカットが簡易なリストで表示されます。
リファクタリングのショートカットを忘れてしまったらこのショートカットで確認しましょう。
![クイック一覧.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578726/c00926e3-cd23-1b96-5e01-b0ae0f7a0742.gif)

# 終わりに
今回は知っておくと便利なショートカット8選を紹介しました。
ショートカットをうまく使いこなして、生産性を上げていきましょう！
elm-pages を触ってみる

# elm-pages について

elm-pages とは `Elm` を使用した静的サイトジェネレータです。

https://elm-pages.com/docs/getting-started#cli-commands

# elm-pagesを始める

```shell-session
$ npx elm-pages init my-project
...
$ cd my-project
$ npm install
...
$ npm start

> start
> elm-pages dev

Ran elm make .elm-pages/TemplateModulesBeta.elm in 2876ms
Ran elm make ./.elm-pages/TemplateModulesBeta.elm in 2897ms
elm-pages dev server running at <http://localhost:1234>
...
```

ターミナルに表示されている `<http://localhost:1234>` にアクセスしてみると Index と表示されていると思います。

# ページを追加する

```shell-session
$ npx elm-pages add NewPage
$
```

`src/Pages/`配下に　`NewPage.elm`という新しいファイルが追加されます。

先ほどと同じように `npm start` でサーバーを起動させ、`<http://localhost:1234/new-page>` にアクセスすると　NewPage と表示されるページが出来上がります。

`src/Pages/NewPage.elm` の view 関数が表示を作る関数です。
以下のように変更することで表示される値を変更することができます。

```elm:src/Pages/NewPage.elm
view :
    Maybe PageUrl
    -> Shared.Model
    -> StaticPayload Data RouteParams
    -> View Msg
view maybeUrl sharedModel static =
    View.placeholder "Hello, World!"
```

このように修正することで`<http://localhost:1234/new-page>`のページに `Hello, World!` と表示されます。
ECSで定期実行するタスクをTerraformで作成する際のTips

AmazonECSにおいて、タスクを定期的に実行することができます。
その際に考慮すべきポイントが2点あります。
- [スケジュールされたタスクを作成する](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/scheduled_tasks.html#scheduled-task-create)

```sh
Terraform v1.4.2
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v4.48.0
+ provider registry.terraform.io/hashicorp/random v3.4.3
```

①cloudwatch_event_targetが依存関係を参照できないのでやむを得ず明示的にdepends_onを使用する
```cloudwatch_event_rule.tf
resource "aws_cloudwatch_event_rule" "example" {
  # ...
}

resource "aws_cloudwatch_event_target" "example" {
  # ...
  depends_on = [
    aws_cloudwatch_event_rule.example,
  ]
}
```

②最新のタスクが実行できるよう同期を取るため、リビジョン番号は記述しないようにする

```cloudwatch_event_rule.tf
// リビジョン番号を削除
locals {
  task_definition_arn_without_revision = replace(
    aws_ecs_task_definition.example_latest.arn, "/:[0-9]+$/", ""
  )
}

  ecs_target {
    task_count          = 1
    task_definition_arn = data.aws_ecs_task_definition.example_latest.arn
    launch_type         = "FARGATE"
  # ...
```

```data.tf
data "aws_ecs_task_definition" "example_latest" {
  task_definition = aws_ecs_task_definition.example.family
}
```

参考
[Terraformを使って常に最新のタスク定義でECS Scheduled Taskを実行する](https://dev.classmethod.jp/articles/terraform-ecs-scheduled-task-latest-md/)
ChatGPTに聞きます

**chatGPTに聞きます。**

![6mMfkmBJhzTeFUzqrRoA8J4KaAY2/B65JaoUvzVKVmhzs.jpg](https://firebasestorage.googleapis.com:443/v0/b/type-c1c71.appspot.com/o/6mMfkmBJhzTeFUzqrRoA8J4KaAY2%2FB65JaoUvzVKVmhzs.jpg?alt=media&token=21f96546-57e7-41a3-9028-34a0e78729c4)
Kotlinxがインポートできない件

Kotlinxは非推奨になり、2021年9月以降削除予定（すでに削除済みかも）との事・・・

### 参考サイト
https://qiita.com/mono_glyceride/items/28b32c1c259decfacf5d

という事で、ViewBindingにしました。
なんで非推奨にしたんだろうか・・・
discord botを手元環境からホスティングサービスへ移行する時にやらかしたミス

# tokenをpublicな環境で保存するな
今回やらかしたミスはこれです。
普通これ起きないと思うんですけど、同じ様なミスする人がいるはず(？)なので被害者を減らす為に色々書きます。

# 初めてのdiscord botを作成した時の話

半年か一年前くらいにスマブラの自分だけの相性表を作成する為、いちいちカウントするのが面倒だったので簡単に記録できるbotを作りました。
この時どうせ一回一回自分で動かせばいいやと思いtokenに関する実装はかなり適当にしてしまいました。

# ローカルからgitにあげる時は一回は目を通す

案の定、手動で実行するのめんどくさくなりました。
この時思った事として
- herokuで自動化すればええか

ここまでは正しい思考をしていたのですが人の記憶力は怪しいものでtokenを普通に存在させたままpushしてしまい流出しちゃいました。
ただ

https://github.blog/jp/2019-08-26-github-token-scanning-one-billion-tokens-identified-and-five-new-partners/

があったおかげですぐに検知されtokenが自動変更された為、無事でした。

# (軽い)対抗策

自分はすぐにprivateにかえとりあえずの安全を得ました。
がprivateにしただけです。

# 真　対抗策

良い子のみんなはこっちの方を使おうね

https://devcenter.heroku.com/ja/articles/config-vars

https://qiita.com/1ntegrale9/items/aa4b373e8895273875a8

自分のサーバーとかだったらもう少し別の方法もありそう(.gitignoreで除いたファイルに置く)

# 結論

自己流もいいけどより安全に作成するには

https://qiita.com/1ntegrale9/items/aa4b373e8895273875a8

みたいな先人たちの記録を覗いた方が良い。
【React】同じ画面にリダイレクトさせた後、更新後のstateを画面に表示したい

# はじめに
リダイレクト後に更新後のstateを表示させることについて、詰まったので簡単にまとめてみます

# やりたいこと
データを削除した後に同じ画面にリダイレクトさせたい。その際、画面に表示されるデータは削除後の内容にしたい

# 前提
リダイレクトさせてもDOMの更新がされないため、画面には削除前のデータが表示されている状況でした

# 方法
はじめにuseEffectを使い、強制的にレンダリングさせる方法を考えましたが、これはパフォーマンスやデバッグの観点からreact的に非推奨のようでした。
次にuseRecoilでstateをグローバルに管理する方法も考えましたが、修正する影響範囲が多かったことから一旦はコンポーネント間でpropsの受け渡しをしてstateを更新させる方法を選択しました


# ファイル(一部)

## components/pages/MyData.tsx(親)
```diff_typescript
略
  const [datas, setDatas] = useState<Data[]>();
  const getDatas = async () => {
    const res = await axios.get(`${apiURL}/data`).then(function (res) {
      setDatas(res.data.datas);
    });
  }
  useEffect(() => {
    getDatas();
  }, []);
略
-  <DataCards pageSize={6} datas={datas} my={true} />
+  <DataCards pageSize={6} datas={datas} my={true} refreshData={getDatas} />
```


## components/molecules/Cards.tsx(子)

```diff_typescript

type Props = {
  datas: Data[];
  my?: boolean;
+ refreshData?: () => void;
};

export const Datas = memo((props: Props) => {
略
+  const refreshDatas = () => {
+    if (props.refreshData !== undefined) {
+      props.refreshData()
+    }
+  }
  const navigate = useNavigate();

  return (
    <>
      {my ? (
-       <MyDataCard card={item} />
+       <MyDataCard card={item} datas={refreshDatas} />
      ) : (
        <DataCard card={item} />
    );
});
```

## components/molecules/MyDataCard.tsx(孫)

```diff_typescript
type Props = {
  card: Card;
+ datas: () => void;
};

export const MyDataCard = memo((props: Props) => {
  const deleteData = (id: string) => {
    setIsOpen(false)
    axios
    .delete(`${apiURL}/data/${id}`)
    .then((res: AxiosResponse<Data>) => {
      if (res.status === 200) {
-        navigation("/");
        console.log("削除しました");
        toaster('削除しました', 'success');
+        props.datas()
      } else {
        console.log("失敗しました");
        toaster('失敗しました', 'warning');
      }
    })
    .catch(() => {
      toaster('システムエラーです', 'error');
      console.log("catch");
    });
  }
略
}
```
 
# コンポーネントの関係
- 親コンポーネント(MyData.tsx)
- 子コンポーネント(DataCards.tsx)
- 孫コンポーネント(MyDataCard.tsx)

# 処理の概要
## ①孫コンポーネントで削除ボタンをクリックするとデータを削除する関数を実行
- 孫コンポーネントでonclickイベントにdeleteData関数を指定しています

## ②データを取得する関数を親から子を経由して受け取り、実行
- 今回は子コンポーネントを経由する必要があるので、親と子、子と孫間でそれぞれpropsの受け渡しを定義しています 
- 最終的にdeleteData関数内で親コンポーネントで定義したgetDatas関数を実行しています

## ③親のstateが更新され、画面のレンダリングが走る
親コンポーネントで定義したgetDatas関数が孫コンポーネントで呼び出されると、関数内のsetDatasでstateが更新されます。
これによって孫コンポーネントでの変更が親コンポーネントに伝わり、レンダリングが走ります


# おわりに
今後はuseRecoilも挑戦していきたいです。
[laravel]自動整形ツールpintを実装する

## はじめに
laravelの自動整形ツール`pint`を実装する。
コミット時にコマンドを打ち込むことで自動で整形をしてくれ、ルールに沿った形でコードを修正してくれる。
案件で実際に使用しており、非常に優れた機能だと感じたので個人開発でも導入することとした。

## pintを導入する
laravel8からの新機能のようで、導入自体は特段難しいものでもない。

### インストールする
使っているlaravelのバージョンがlaravel9なのでインストールは不要かと思ったのだが
どうやら検索してもないようだったのでインストールする。
```terminal
composer require laravel/pint --dev
```

### pintを実行する
基本的にはこれでOK。
あとは、コミット時などにコンテナ内に入って、下記コードを打ち込む。
```terminal
./vendor/bin/pint -v
```

`pint`で修正が入ると、再度ステージング環境に上げる必要があるので、
コミット前に必ず`git add .`をすること。

### pint実行時にエラーが出てしまう場合 
僕がそうだったのだが、下記のようなエラーが出てしまった。
```
 [ERROR] Your system is not ready to run the application. 
```

どうやらLaravel9アプリケーションを実行するために必要な依存関係が満たされていないため
起こられているらしい。
要因はいくつか可能性があるようなのだが、
僕の場合必要なパッケージをインストールして上げる必要があった。なので下記コードを打ち込む。
```terminal
composer install
```

おや。しかし、またエラーが。。
```
 Problem 1
    - laravel/pint is locked to version v1.6.0 and an update of this package was not requested.
    - laravel/pint v1.6.0 requires php ^8.1.0 -> your php version (8.0.8) does not satisfy that requirement.
```

どうやらPHPのバージョンをあげないといけないらしい。
PHPのバージョンアップは過去記事にあげてるのでそちらを見てください。

PHPバージョンをあげて、再度、
```
composer install
```
をすることで成功。
無事`pint`も実行することができました!

以上。
リニューアルしたRSpecの公式ドキュメント（旧Relish）を読む方法

## はじめに
RSpecではこれまで https://relishapp.com/rspec というサイトで公式ドキュメントが公開されていました。しかし、このページはいろいろあって現在はアクセスできません。

「いろいろあって」はざっくり説明するとこんな感じです↓

https://twitter.com/jnchito/status/1631593354562764801

しかし、先日めでたくこの公式ドキュメントが復活しました🎉
この記事ではこの公式ドキュメントのアクセス方法を説明します。

## 新しい公式ドキュメントを読む方法
https://rspec.info/ から "View Documentation" のリンクをクリックします。

![Screenshot 2023-03-22 at 17.15.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/600f098c-a66c-f173-66d9-5d0223cd96cf.png)

もしくは https://rspec.info/documentation/ に直接アクセスします。

すると以下のようなページが表示されます。

![Screenshot 2023-03-22 at 17.18.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/a0353448-1b32-ad18-b4e9-5bbd742f369d.png)

僕は「で、ここからどうしたらいいの？？ :thinking: 」と思ってしまったんですが、"Examples"の欄にマウスカーソルを当てると、バージョン選択のメニューが表示されます（といっても以下の表示例ではバージョン3.12のひとつだけです）。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f373436352f30376333663462302d653161642d666433662d633866382d3965633731613732616334612e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/66e70b76-f402-d887-16e2-843b8e2c6348.png)

ここでプルダウンメニューから読みたいバージョンをクリックすると、以前 https://relishapp.com/rspec で公開されていたものと同じ公式ドキュメントを参照することができます。

![Screenshot 2023-03-22 at 17.22.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/7a8e46d2-39c6-1333-c04a-48fb9348b1c8.png)

上の例で表示しているページには https://rspec.info/features/3-12/rspec-core/ で直接アクセスすることもできます。

https://relishapp.com/rspec の頃と同様に、ドキュメントは

- rspec-core
- rspec-expectations
- rspec-mocks
- rspec-rails

の4種類に分かれているので、それぞれプルダウンから選択可能です。

![Screenshot 2023-03-22 at 17.27.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/c5b19317-b393-e9f4-064b-588b3a52319d.png)

もしくはドキュメント右上のプルダウンメニューから、表示したいドキュメントを切り替えることもできます。

![Screenshot 2023-03-22 at 17.28.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/ee550a73-b5a2-59f4-bae5-3ad7d377c3e8.png)

参考までに、各ドキュメントへの直リンクを以下に貼っておきます。

https://rspec.info/features/3-12/rspec-core/

https://rspec.info/features/3-12/rspec-expectations/

https://rspec.info/features/3-12/rspec-mocks/

https://rspec.info/features/6-0/rspec-rails/

## Q. RDocとExamplesの違いは何？

以下の"Documentation"欄には"RDoc"と"Examples (Relish / Gherkin)"があります。

![Screenshot 2023-03-22 at 17.18.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/71c3172a-dcea-74a9-9fe0-cc499d67bf0c.png)

RDocの方を開くと、RSpecのAPIドキュメントが表示されます。

![Screenshot 2023-03-22 at 17.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/3a00f1dc-a3e7-096b-1791-38e057ba7bf5.png)

どちらも公式ドキュメントであることには違いはないのですが、個人的に実践的なユースケースに沿ったRSpecの記述例が載っている"Examples"（以前のRelish）を参照することが多いです（RDocを見に行くことは滅多にないかも？）。

## まとめ

というわけで、この記事ではリニューアルしたRSpecの公式ドキュメントを読む方法を紹介しました。

復活までもっと時間がかかるかと思いましたが、思ったより早く復活してくれて良かったです。

Matt Wynne氏、およびRSpec開発チームのみなさん、どうもありがとうございます！！
Gitでpushした時に発生したerror: failed to push some refs to "URL"のエラー対処法

# エラーの背景
Gitでpushする時に以下のようなエラーが発生しました。個人によって状況が違うので参考程度でもいいかなと思います。

```
laravelapp % git push origin feature/noriaki/common_file
#省略
 ! [remote rejected] feature/noriaki/common_file -> feature/noriaki/common_file (cannot lock ref 'refs/heads/feature/noriaki/common_file': 'refs/heads/feature/noriaki' exists; cannot create 'refs/heads/feature/noriaki/common_file')
error: failed to push some refs to 'https://github.com/省略'
```
他にもgit fetch,git mergeを使いましたが、解決できず、
```
laravelapp % git pull origin develop_a_yayoi_rab
```
などでgit pullで試してからgit pushで試しましたが、挙動が変わりませんでした。

調べて見たエラーの意味はリモートのファイルがローカルのファイルも最新版だから、
そのファイルにpushできないですよという意味だったみたいです。

# 解決した方法
まずアドバイスをもらったのがfeature/noriaki というブランチを
リモートに作ってしまっているので下のコマンドでリモートブランチを削除しようということになりました。

```
laravelapp %　git push origin --delete feature/noriaki
```
その後に
```
Username for 'https://github.com': 省略
Password for 'https://省略': 
remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/省略/'
```
注目したのが以下の文です
```
fatal: Authentication failed for 'https://github.com/省略'
```
Githubでアクセストークンの発行が必要でした。
トークンの期限切れだったのでトークンを再発行してから再度トークンを入れてみました。

### トークン再発行方法
以下の記事を参考にしてみてください。

https://capybara-notebook.com/github_accesstoken/

https://howpon.com/5308

https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token

https://qiita.com/gin_teacher/items/d52a25fb5ca9fed3108a

# 解決
トークン発行後に以下のコマンドを実行後

```
laravelapp % git push origin --delete feature/noriaki
laravelapp % git push origin feature/noriaki/common_file
```
を実行後pushができました。


# 資料

https://qiita.com/chiaki-kjwr/items/118a5b3237c78d720582

https://www.freecodecamp.org/japanese/news/how-to-delete-a-git-branch-both-locally-and-remotely/
Vue.jsとFastAPI間をaxiosで通信させたら404エラーが出た

# はじめに
初歩的な内容かもしれませんが、備忘録として残しておきます。
解釈の違いや指摘すべき点があれば是非お教えください。

また、Vueプロジェクト(Vue3)は`npm init vue@latest`にて作成したものです。

フロントエンド(Vue.js)は`npm run dev`、
バックエンド(FastAPI)は`uvicorn main:app --reload`で起動しました。


:::note info
ここでの`app`は`main.py`の`FastAPI()`インスタンスを格納した変数に連動しています。適宜置き換えてください。
:::


## 実行環境
- macOS Monterey バージョン12.6.3
- node: 16.19.1
- npm: 8.19.3
- axios: 1.3.4
- fastapi: 0.92.0
- uvicorn: 0.20.0

# 発生した問題
Vueプロジェクトを作成し、テスト用の`main.py`と`__init__.py`を用意して、それぞれのディレクトリでlocalhostを立てて動作確認しようとしたら、`404 (Not Found)` もとい`AxiosError`が投げられました。

## 原因
VueプロジェクトとFastAPIでのアドレスが異なっていたため、作ったAPIにアクセスできなかったようです。
```bash:例
http://localhost:5173 #フロントエンドへのアクセス
http://localhost:8000 #バックエンドへのアクセス
```

## 解決策
`vite.config.ts`に、開発サーバのカスタムプロキシのルールを設定することで解決しました。テストに用いた各種ソースコードを以下に記載しています。

:::note warn
`vite.config.ts`は、Vueプロジェクト作成時にTypeScriptを選択した場合のファイルであり、TypeScriptを選択していない場合は`vite.config.js`になっていると思います。
:::

```python:main.py(テスト用)
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware

app = FastAPI()

# CORS対策
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"]
)

@app.get("/api/test")
def test():
    return "test"
```

```vue:axiosTest.vue(テスト用)
<script setup lang="ts">
import axios from "axios";
import { ref } from "vue";

const test = ref("");

async function getTest() {
  await axios
    .get("/api/test")
    .then((res) => (test.value = res.data))
    .catch((e) => {
      console.log(e);
    });
}
</script>

<template>
  <button @click="getTest">getTest</button>
  <p>{{ test }}</p>
</template>
```

以下のように変更しました。`proxy`の内容はFastAPIにアクセスする際のアドレスにしています。
```diff_typescript:vite.config.ts
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
+ server: {
+   proxy: {
+     "/api": "http://localhost:8000",
+   },
+ },
});
```

コードの加筆後、`npm run dev`および`uvicorn main:app --reload`を実行し、サーバーを立ち上げた結果、ブラウザ上のボタンを押すと`test`という文字列が返ってくるようになりました！

# 参考にしたサイト
[サーバオプション | Vite](https://ja.vitejs.dev/config/server-options.html)
CDKでタグをcdk.jsonに定義する

## 方法
`cdk.json`に以下の様に`tags`を追記して、それぞれのキー・バリューペアを記入する。(配列の中にマップがあることに注意)

```json
{
    "context": {
        "xxx/yyyy": true,
    },
    "tags": [
        {
            "Key": "fruit",
            "Value": "orange"
        }
    ]
}
```

## 参考

https://github.com/aws/aws-cdk/issues/20854

https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-config
【Ruby/minitest】テスト実行時にコマンドライン引数を置き換える

# はじめに
コマンドライン引数を用いる処理のテストに際して、
引数を好きなように指定して処理を実行する方法を備忘録として残しておきます。

※ 実行環境: ruby 3.1.2p20
※ この記事では以下の`foo.rb`をテスト対象とします
```ruby:foo.rb
class Foo
  def initialize; end

  def call
    ARGV[0].to_i * 2
  end
end
```

# `Array#replace`を使う
`ARGV`の中身を`Array#replace`で置き換えてテストしたい処理を実行します。
テスト実行後に引数なしの状態に戻しておくことで、
後に実行される他のテストに置換の影響が及ぶのを防ぎます。
```ruby:foo_test.rb
require 'minitest/autorun'

class FooTest < Minitest::Test
  def test_specify_argv
    ARGV.replace([9])
    assert_equal(18, Foo.new.call)
  end

  def test_no_argv
    assert_equal(0, Foo.new.call)
  end

  def teardown
    # 他のテストへの影響を考慮しでARGVを引数なしの状態に戻す
    ARGV.replace([])
  end
end
```

# `Module#const_set`を使う
`Module#const_set`により定数`ARGV`を定義し直す方法です。
これだけだと定数の重複によって`ARGV`の値を設定できないため、
`Module#remove_const`により一度定数`ARGV`を除きます。
なお`Object#send`を用いるのは、`Module#remove_const`がprivateメソッドであるためです。
```ruby:foo_test.rb
require 'minitest/autorun'

class FooTest < Minitest::Test
  def test_specify_argv
    Object.send(:remove_const, :ARGV)
    Object.const_set(:ARGV, [9])
    assert_equal(18, Foo.new.call)
  end

  def test_no_argv
    assert_equal(0, Foo.new.call)
  end

  def teardown
    # 他のテストへの影響を考慮しでARGVを引数なしの状態に戻す
    Object.send(:remove_const, :ARGV)
    Object.const_set(:ARGV, [])
  end
end
```

# おわりに
以上テスト実行する際にコマンドライン引数を置き換える方法を2つまとめました。

いずれの方法でも後に実行されるテストへの影響を考慮して、
指定したコマンドライン引数を元に戻すための処理を書いておく必要があります。
もし何かより良い方法をご存知の方がいましたら教えていただけると嬉しいです。
演算子**と<< 速度比較 python

2**x と 1<<xの速度比較をしてみました。
下の表は秒です。
```
$ python3 -m timeit '2**__'
$ python3 -m timeit '1<<__'
```

```
50000000 loops, best of 5: ___ nsec per loop
```
↑ここは変わります
※ u(μ)secはnsecに変換します。
| x | 2**x | 1<<x |
| --- | --- | --- |
| 20 | 6.61 | 6.7 |
| 50 | 6.48 | 6.56 |
| 100 | 428 | 6.4 |
| 200 | 590 | 66.8 |
| 500 | 1170 | 66.4 |
| 1000 | 1740 | 70.3 |
| 2000 | 3190 | 73 |
| 5000 | 9620 | 193 | 
| 10000 | 21700 | 190 |

以上。シフト演算子<<の方が断然早いでしょう。
ウィンドウ関数を使って競馬アプリごとの売上前年比を調べる

# 環境

MySQL 8.0

# テーブル作成

架空の競馬アプリ`JRA-SAN`の2018年 ~ 2022年の売上情報を持った`jra_san_sales`テーブルを作成します

```sql
CREATE TABLE jra_san_sales (
    year VARCHAR(4),
    earnings INTEGER
);

INSERT INTO jra_san_sales VALUES('2022', 200);
INSERT INTO jra_san_sales VALUES('2021', 180);
INSERT INTO jra_san_sales VALUES('2020', 200);
INSERT INTO jra_san_sales VALUES('2019', 100);
INSERT INTO jra_san_sales VALUES('2018', 80);
```

各、架空の競馬アプリの年間売上情報を持った`horce_race_app_sales`テーブルを作成します

```sql
CREATE TABLE horce_race_app_sales (
    name VARCHAR(36),
    year VARCHAR(4),
    earnings INTEGER
);

INSERT INTO horce_race_app_sales VALUES('熱闘 keiba', '2022', 200);
INSERT INTO horce_race_app_sales VALUES('熱闘 keiba', '2021', 180);
INSERT INTO horce_race_app_sales VALUES('熱闘 keiba', '2020', 170);
INSERT INTO horce_race_app_sales VALUES('JRA-SAN', '2022', 150);
INSERT INTO horce_race_app_sales VALUES('JRA-SAN', '2021', 180);
INSERT INTO horce_race_app_sales VALUES('競馬！DO', '2022', 90);
INSERT INTO horce_race_app_sales VALUES('競馬！DO', '2021', 95);
```

# まずは、基本的な使い方から

各行の直近の年を求めてみます。
1行前の年を出力した結果がこちらです

```
 current_year | latest_year
--------------+-------------
 2018         |
 2019         | 2018
 2020         | 2019
 2021         | 2020
 2022         | 2021
```

```sql
SELECT
    year AS current_year,
    MIN(year) OVER (
        ORDER BY year ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING
    ) AS latest_year
FROM jra_san_sales;
```

`OVER句`・・・分析関数。行セットのパーティション処理と並べ替えを決定します

`分析関数 OVER(ROWS BETWEEN　開始位置 AND 終了位置)`・・・フレームを指定します

> `ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING`

上の例では、現在の行の前の1行だけを含むフレームを指定することを意味します
その結果、ウィンドウ関数が現在の行とその前の1行のみを対象として集計を実行するように指定することができます

ちなみに、`MIX(earnings)`の部分は`MAX(earnings)`でも同じ結果が得られます

集約関数`MIN`や`MAX`をしようする理由としては、
**フレーム範囲が複数になる場合があるので、集約関数を利用しています**。

# それぞれのアプリの売上前年比を求める

欲しいデータが以下です。year_on_yearは前年比です

```
    name    | year | earnings | year_on_year
------------+------+----------+-------------
 JRA-SAN    | 2021 |      180 |
 JRA-SAN    | 2022 |      150 |    -30
 熱闘 keiba  | 2020 |      170 |
 熱闘 keiba  | 2021 |      180 |     10
 熱闘 keiba  | 2022 |      200 |     20
 競馬！DO     | 2021 |       95 |
 競馬！DO     | 2022 |       90 |     -5
```

```sql
SELECT 
    name,
    year,
    earnings,
    earnings - MAX(earnings) OVER (
        PARTITION BY name 
        ORDER BY year
        ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING
    ) AS year_on_year
FROM horce_race_app_sales;
```

* `PARTITION BY`・・・グループごとに分けて集計を行います。

```sql
PARTITION BY name ORDER BY year
```

ここでは`PARTITION BY`でアプリ名(name)毎に対して、`ORDER BY`でyearの昇順で並べ替えています

* `分析関数 OVER(PARTITION BY カラム名,・・・)`・・・集計範囲を指定しています。

```sql
earnings - MAX(earnings) OVER (
        PARTITION BY name 
        ORDER BY year
        ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING
    )
```

その結果、`前年比(year_on_year) = 現在の列の売上 - 前年の売上`が得れます
Googleデジタルマーケティング＆Eコマース：メールマーケティング自動化ツール

# はじめに

”Googleデジタルマーケティング＆Eコマース プロフェッショナル認定証"　の受講が完了しました(2022/3/3)。私がこのコースから得られた素晴らしい体験を、テーマごとに分割して、わかりやすくご紹介しています。興味を持たれた方は、是非下記を受講してみてください。

https://jp.coursera.org/professional-certificates/google-digital-marketing-ecommerce

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/bc50df6f-2af4-4c58-96fb-829e0752d0af.png" width="800">

# メールマーケティング自動化ツール

メールマーケティング・オートメーションは、読者を見つけ、彼らが望むコンテンツだけを提供するのに役立ちます。メールマーケティング自動化ツールは、メールマーケティング担当者がリードを生成したり、見ず知らずの人を顧客にしたりするのに役立つツールです。

- 自動化により、メールマーケティング担当者は、購読者一人ひとりにパーソナライズされたメッセージを送ることができます。自動化の成功の鍵は、いかにターゲットを絞ってメールを配信できるかにあります。
- メールマーケティング自動化は、メールマーケティングのプロセスをよりシンプルに、よりスムーズにします。
- メールマーケティングはバックグラウンドで行われるため、必要であれば他の作業に集中することができます。例えば戦略立案や魅力的なコピーの作成。

# 自動化ツールでできること

- 効率的にリストを作成する
- リストをセグメントする
- 新規購読者へのウェルカム・メールやアクイジション・メールを自動送信する
- テンプレートを使ってニュースレター、プロモーションメール、リテンションメールでフォローアップする
- 各購読者の関心や行動を容易に追跡する

# 業界をリードするツールの特徴

### HubSpot

- 堅牢な機能を提供する非コストバージョン。
- パーソナライゼーションにより、ペルソナや主要な視聴者に応じて異なる体験を提供することができます。
- カスタマイズが可能なため、直感的かつ効果的なA/Bテストやメールマーケティングが可能であり、顧客がどのようなメールに興味を示すかを知る上で非常に有用です。

### Mailchimp

- ユーザーインターフェースと堅牢なメールテンプレートエディターにより、自動化プロセスを効果的に行うことができます。
- あらかじめジャーニーが組み込まれており、マーケティングオートメーションの最も一般的なユースケースのいくつかについてカスタマイズ可能なワークフローが提供されています。

### Salesforce Marketing Cloud

- 強力なカスタマイズを提供することで好評を得ています。
- 他の製品よりも少しエキスパートレベルですが、その分、インターフェースのカスタマイズなどの機能が充実しています。

# HubSpotによるメール作成

HubSpotでは、マーケティングチャネルの活動をすべて一箇所で管理することができます。Eメールマーケティングに関しては、HubSpotを使用してさまざまなEメールマーケティングのタスクを実行することができます。

下の画像は、HubSpotを使ったEメールマーケティングキャンペーンプロセスの実行可能なステップを示したものです。

1. ビジネスの目標を設定する。
1. 連絡先データベースを管理する。
1. それらの連絡先をセグメント化する。
1. パーソナライズされたターゲットメールを作成する。
1. メール送信の遅延時間を選択して、各ユーザーがメールを受け取るタイミングを決定する。
1. メールをテストする。
1. メールのパフォーマンスを分析します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/d8d44fd4-b3d5-11e9-045b-dc29dd8b8809.png" width="800">
Rubyの二次元配列がわからなかったからくそコード書いたから見て！

# 注意
・以下のネタバレあり。

https://paiza.jp/works/mondai/prob60/tic_tac_toe_2

# 気合のコード！
```Ruby
s = gets
# puts s

count = 0
count2 = 0
for i in 0..5
    if s[i] == 'O'
        count = count + 1
        # puts "Oの数は#{count}"
    elsif s[i] == 'X'
        count2 = count2 + 1
        # puts "Xの数は#{count2}"
    end
end
# puts count

ocount = 0
xcount = 0
if count == 5
    # puts "O"
    ocount =  ocount + 1
elsif count2 == 5
    # puts "X"
    xcount = xcount + 1
else
    # puts "D"
end

# ---------------------------------

s1 = gets
# puts s1

s1count = 0
s1count2 = 0
for i in 0..5
    if s1[i] == 'O'
        s1count = s1count + 1
        # puts "Oの数は#{count}"
    elsif s1[i] == 'X'
        s1count2 = s1count2 + 1
        # puts "Xの数は#{count2}"
    end
end
# puts count

if s1count == 5
    # puts "O"
    ocount =  ocount + 1
elsif s1count2 == 5
    # puts "X"
    xcount = xcount + 1
else
    # puts "D"
end

# ---------------------------------

s2 = gets
# puts s

s2count = 0
s2count2 = 0
for i in 0..5
    if s2[i] == 'O'
        s2count = s2count + 1
        # puts "Oの数は#{count}"
    elsif s2[i] == 'X'
        s2count2 = s2count2 + 1
        # puts "Xの数は#{count2}"
    end
end
# puts count

if s2count == 5
    # puts "O"
    ocount =  ocount + 1
elsif s2count2 == 5
    # puts "X"
    xcount = xcount + 1
else
    # puts "D"
end

# ---------------------------------

s3 = gets
# puts s

s3count = 0
s3count2 = 0
for i in 0..5
    if s3[i] == 'O'
        s3count = s3count + 1
        # puts "Oの数は#{count}"
    elsif s3[i] == 'X'
        s3count2 = s3count2 + 1
        # puts "Xの数は#{count2}"
    end
end
# puts count

if s3count == 5
    # puts "O"
    ocount =  ocount + 1
elsif s3count2 == 5
    # puts "X"
    xcount = xcount + 1
else
    # puts "D"
end

# ---------------------------------

s4 = gets
# puts s

s4count = 0
s4count2 = 0
for i in 0..5
    if s4[i] == 'O'
        s4count = s4count + 1
        # puts "Oの数は#{count}"
    elsif s4[i] == 'X'
        s4count2 = s4count2 + 1
        # puts "Xの数は#{count2}"
    end
end
# puts count

if s4count == 5
    # puts "O"
     ocount =  ocount + 1
elsif s4count2 == 5
    # puts "X"
    xcount = xcount + 1
else
    # puts "D"
end

# ---------------------------------

if ocount == 1 
    puts 'O'
elsif xcount == 1
    puts 'X'
else
    puts 'D'
end
    
```
paiza.ioでelixir その215

# 概要
paiza.ioでelixirやってみた。
練習問題、やってみた。

# 練習問題
udp serverとtcp serverを同時に動かせ。

# 方針
GenServer使う。
udpポートは、49152番
tcpポートは、8000番

# サンプルコード

```
defmodule UServer do
	use GenServer
	@port1 49152
	def start do
		GenServer.start(__MODULE__, %{socket: nil})
	end
	def init(state) do
		{:ok, socket} = :gen_udp.open(@port1, [:binary, active: true])
		{:ok, %{state | socket: socket}}
	end
	def handle_info({:udp, socket, data}, state) do
		:ok = :gen_udp.send(socket, data)
		{:noreply, state}
	end
	def handle_info({:udp_closed, _}, state) do
	    {:stop, :normal, state}
	end
	def handle_info({:udp_error, _}, state) do
	    {:stop, :normal, state}
    end
	def handle_info({:udp, socket, host, port, _} = data, server_socket) do
    	:gen_udp.send(socket, host, port, "#{inspect(data)}>\n")
		{:noreply, server_socket}
	end
end

defmodule TServer do
	use GenServer
	@port 8000
	def start do
		GenServer.start(__MODULE__, %{socket: nil})
	end
	def init(state) do
		{:ok, socket} = :gen_tcp.listen(@port, [:binary, active: true])
		send(self(), :accept)
		{:ok, %{state | socket: socket}}
	end
	def handle_info(:accept, %{socket: socket} = state) do
		{:ok, _} = :gen_tcp.accept(socket)
		{:noreply, state}
	end
	def handle_info({:tcp, socket, data}, state) do
		:ok = :gen_tcp.send(socket, data)
		{:noreply, state}
	end
	def handle_info({:tcp_closed, _}, state) do 
	    {:stop, :normal, state}
	end
	def handle_info({:tcp_error, _}, state) do
	    {:stop, :normal, state}
    end
end

UServer.start
TServer.start


{:ok, socket} = :gen_tcp.connect('localhost', 8000, [:binary, active: false])
|> IO.inspect
:ok = :gen_tcp.send(socket, "msg")
|> IO.inspect
{:ok, data} = :gen_tcp.recv(socket, 0)
data
|> IO.puts
{:ok, socket} = :gen_udp.open(49153, [:binary, active: false])
|> IO.inspect
:ok = :gen_udp.send(socket, '127.0.0.1', 49152, "hello")
|> IO.inspect
:gen_udp.recv(socket, 0)
|> IO.inspect





```

# 実行結果


```
{:ok, #Port<0.8>}
:ok
msg
{:ok, #Port<0.10>}
:ok
{:ok,
 {{127, 0, 0, 1}, 49152,
  "{:udp, #Port<0.5>, {127, 0, 0, 1}, 49153, \"hello\"}>\n"}}

```

# 成果物


https://paiza.io/projects/EI1Lleg8jUxxWDM7037bng


以上。
電気配線の接地側

いつもわからなくなるので備忘録


# 弱電直流

GND と アースがあり、アースが接地用、
GND は電子回路の 0V として使われることが一般的。

しかしながら GND とアースを兼ねていたり、分けてはいても接続されていることも多い。

以下はPC用の電源によく付く使われている色。


|意味|電線色|
|:---:|:---:|
|GND|黒|
|5V|赤|
|12V|黄|
|3.3V|橙|
|-12V|白|
|-5V|青|




# 商用交流(単相)

## 接地側
ニュートラル側、とも言う。

## 非接地側
ライブ側、電圧側とも言う

## アース
接地線、とも言う

以前は緑の線が使われていたが、近年は IEC規定 によって黄色と緑色のストライプとなっているらしい。

## 配線

###  白黒ケーブル

|意味|電線色|
|:---:|:---:|
|接地側|白|
|非接地側|黒|


### 白黒緑ケーブル

|意味|電線色|
|:---:|:---:|
|接地側|白|
|非接地側|黒|
|アース|緑|


### 青茶黄緑ケーブル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/90b7a9db-f84f-d89a-e637-b62d44d8e31f.png)

EN規格の色らしい

|意味|電線色|
|:---:|:---:|
|接地側|茶|
|非接地側|青|
|アース|黄/緑|


### 配線器具
「W」「L」「N」とモールドされている配線器具などは、以下の割当になります。

|意味|表記|
|:---:|:---:|
|接地側|W、L|
|非接地側|N|


### コンセント口

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/50a68b69-e4e0-973f-7302-4654296acf2a.png)

|意味|電線色|
|:---:|:---:|
|接地側|長穴|
|非接地側|短穴|
|アース|丸角穴|


# 商用交流(三相)


## 配線

白黒赤ケーブル

|意味|電線色|
|:---:|:---:|
|接地側|白または青|
|非接地側1|青または黒|
|非接地側2|赤|

基準により、色の割当が異なるらしい。
プリザンターのレコード更新APIをPower Automateで自動化してみた

# はじめに

今回はプリザンターのレコードを自動更新するPower　Automateフローを作成します。今回はサブスクリプションなどを契約している前提で自動更新するのか契約終了するのかの情報を自動更新していきます。下記、参考資料をもとに自動更新フローを作成しました。

# 設定

・一つのテーブルにつき複数のユーザー(レコード)が存在  
・一つのレコードにはタイトル・開始日・完了日・状況・自動更新の計5つの項目がある  
・完了日が過ぎているユーザーのレコードを毎日更新  
・自動更新がオンのレコードは完了日を過ぎたら完了日を1か月後更新  
・自動更新がオフのレコードは完了日を過ぎたら状況を完了に更新  

#### シチュエーション

今回のシチュエーションとしては昼食補助という福利厚生があり、利用人数を知りたいとします。ちなみに、今回のレコード更新対象は「タイトル」がメーテルさんと星野　哲郎さんです。想定では、メーテルさんは「完了」が1か月後に更新され、星野　哲郎さんは「状況」が完了になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/d4b766dc-bbb8-779c-e935-7dc16e3d63f5.png)

# フローの全体像

### フロー実行間隔・実行日時の設定と変数の初期化処理

繰り返し間隔と実行時間を設定します。そのあと、変数を初期化していきます。設定の内容としては毎日8:00に処理を実行します。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/4a0f0b2c-291f-c388-2893-5c328c70e54e.png)  

### 「自動更新」がオフのレコードの「状況」を完了に更新する処理

「状況」が200(=実施中)、かつ「完了」が前日以前、かつ「自動更新」がオフのレコード情報を取得します。取得したレコードの「状況」を完了に更新します。  

#### httpのaddHours(...)に関しては下記のように入力

UTCで取得した時間に対し、-1日することで前日の日付を設定します。そして、UTC→日本時間に修正するために9時間足し、「yyyy/MM/dd」の形式で返すように指定しています。

```
addHours(addDays(utcNow(),-1),9,'yyyy/MM/dd')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/1c6d321f-c670-cd00-6a71-edcdf477ead9.png)  

### 「自動更新」がオンのレコードの「完了」を1か月後に更新する処理

「状況」が200(=実施中)、かつ「完了」が前日以前、かつ「自動更新」がオンのレコード情報を取得します。取得したレコードの「完了」を1か月後に更新します。

#### http3のaddHours(...)に関しては下記のように入力

上記と同じです。

```
addHours(addDays(utcNow(),-1),9,'yyyy/MM/dd')
```

#### http4のaddHours(...)に関しては下記のように入力

UTCで取得した時間に対し、月に対して+1日することで今日から31日後を設定します。そして、UTC→日本時間に修正するために9時間足し、「yyyy/MM/dd」の形式で返すように指定しています。

```
addHours(addToTime(utcNow(), 1, 'Month'), 9, 'yyyy/MM/dd')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/dc7ea1b8-d69d-1f7e-0ab3-66b55c20b526.png)

# フロー実行前と後

#### フロー実行前

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/5780327c-05aa-e70d-1843-a764304dc6bb.png)

#### フロー実行後

想定通りの結果になっていることを確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/87258e09-2119-87a6-af51-c5aba8a4747d.png)

# さいごに

今回の自動化はライセンスが必要らしく、無料トライアル版を利用して作成いたしました。確か、90日の無料トライアルで続けるためには課金をしていくシステムでした。そのため、簡単な処理を自動化しましたが、いずれ有料版をサブスクして定型業務を自動化させていきたいですね。また、関数なんかもネットで調べれば色々出てきたので、使い勝手も少しずつ良くなっているのではないかと思われます。

# 参考資料
https://qiita.com/pierusan2010/items/77ee509b3f709d5dbbac
生年月日から年齢の求めかた

よく使うので、メモ。
誕生日と現在日をyyyyMMdd形式で引き算して10000で割ることで求められる。

```
//誕生日
Calendar cal = Calendar.getInstance();
cal.set(2000,01,01,10,00,00);

//計算用にフォーマットを揃える
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

//現在日 - 誕生日 を10000で割る
int age = (Integer.parseInt(sdf.format(new Date())) - Integer.parseInt(sdf.format(cal.getTime()))) / 10000;
```
GPT-4で恋愛シミュレーションゲームを生成してみたら

### GPT-4で恋愛シミュレーションゲームを生成してみた

以前に投稿した下記の二つの記事も参考にしてください。

https://qiita.com/quittardis/items/1675989ea4369a2f5ddd

https://qiita.com/quittardis/items/9e96f985ab623f1803b0

上の二つの実験を経て、より複雑なプロンプトに挑戦してみました。
恋愛シミュレーションゲームを生成します。

GPT-4でこのプロンプトは見事に動作しますが、GPT-3.5では察しが悪く
うまく動作しない場合もあります。その場合は、最初からやり直します。
やり直す度に、生成されたゲームワールドは、違いがでてきます。
この実験でGPT-4が遂げている進化がたんなる量的な面だけでないこ
とを実感できます。

GPT-4の場合、表示速度が難点ですが、ゲームとして妙にハマる魅力を持っています。
これを従来のプログラムで作ると、膨大な作業になります。
曖昧な日常言語でこのようなゲームができるのは驚異です。

デバッグ（プロンプトの修正など）はGPT-3.5でやってます。
debug on 
debug off
で、好感度を表示されるので、プロンプトを修正する際に参考にできます。

GPT-3.5での一例ですが、ゲームがスタートしないで、以下のような返答があった
こともあります。

![スクリーンショット 2023-03-22 112026.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/325f9b17-5bc1-f665-61d1-08fb7ef011a4.png)


選択肢の番号だけでなく、文字のコマンドも受け付けます。（例えば「～の部屋に行く」
などもOKです。

### プロンプト

```
以下のようなテキストベース、恋愛シミュレーションゲームを生成してください。


女性3人、男性3人が住むシェアハウスです。
Playerはその中の一人になります。
各人はPlayerの好感度があり、内部的に数値で　-10 から 10までの十段階で保持されます。
Playerとの会話や、クッキングや、いっしょにテレビを見たり、音楽を聴いたり、
その他のアクティビティの中でその数値は上がったり、下がったりします。
「debug on」と入力するといっしょにいる相手の好感度が数値で表現されます。
"debug off"と入力すると数値は表示されません。
ゲームスタート時は、"debug off"です。

各人には個性があり、趣味嗜好や価値観があるので、Playerと、の趣味や価値観が合えば
数値が上がり、それが異なれば下がります。また、人物には固有の外向性や内向性があり
内向的な場合、あまり積極的に迫られると好感度が下がったりします。
好感度が8以上になった時に告白したり、積極的な行動に出て、相手が受け入れれば
ゲーム終了です。
好感度が5以下の時に告白したり、積極的な行動に出て相手に拒絶されるても
ゲーム終了となります。好感度の数値の大きさによって受け入れや、拒絶の反応の
大きさも変わります。
好感度の初期値は、-2,-1,0,1,2の乱数です。
Player以外のカップル間でも、会話やアクティビティがあり、そのカップル間で
好感度が8以上になり、告白とその受容があれば、カップル成立で、それが表示されます。
その時点で、Playerへの好感度は0になります。

一日の終わりに、住人間のアクティビティがリポートされます。
それは誰と誰の親密度が上がったというふうに、数値を含まないものです。


各人の名前は適当につけてください。
また、適当なタイミングで日付が更新されます。その場合 DAY 1、 DAY 2というように
カレンダーの数字が増えていきます。
Playerはゲームが提示する行動の選択肢を選びながらステップ by ステップで進んでいきます。
ゲーム開始時に、Playerの性別を選択することで、Playerの性別が決定されます。
ゲームは、Playerが選択肢の番号を入力するか、行動を文字ですることで
次のステップに進みます。

それではゲームスタートです。
```

### シェアハウスラブストーリー
タイトルは、自動的に決まります。

![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/74bb5077-bb4e-949a-a23f-91b5c8747935.png)
### ゲームスタート
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/d3e7a05b-8caa-80a1-4e4b-a50bb74985ac.png)

![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/9e972ea2-fb95-bd9b-bd03-b5c82164d72f.png)

こうして、様々なアクティブティを経て、好感度をあげていきます。
そして、以下は、相手の好感度が上がった最後のほうの画面です。

### 倫理規定

ゲームの進行中に相手の気持ちを考えずに、積極的すぎると、倫理規定にひっかかります。
これは、GPT-4が決めたもので、プロンプトで指定したものではありません。

![スクリーンショット 2023-03-22 111517.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/29c76c1f-2392-131a-d38d-b53df0a7af4b.png)


### 告白タイム

![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/d0857407-9578-2c51-9512-82b397962423.png)
![005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/aa21d6fd-6b6c-fc7f-3967-1d7e6f61f9d5.png)

好感度ポイントが十分でも、相手の性格によって、告白が受け入れられない場合もあります。

様々なプロンプトを試して、より複雑で面白いワールドができたら、教えてください。
Mountpoint for Amazon S3 をコンテナから実行してみる

:::note warn
2023/3/21 時点の情報で作成しています。Mountpoint for Amazon S3 は現在アルファリリースであるため本番ワークロードには適しません。また将来的に動作や仕様が変更される可能性があります。動作を確認したバージョン: **0.2.0-b8363a4**
:::

## はじめに
[Mountpoint for Amazon S3](https://github.com/awslabs/mountpoint-s3) を Docker で試した際のメモです。コンテナ環境でとりあえずサクッと試してみたい方の参考になれば幸いです。

Mountpoint for Amazon S3 自体の概要や使い方は以下の記事に投稿しています。

https://qiita.com/hayao_k/items/dd741b37e41c22baac55


## Dockerfile

```Dockerfile
FROM rust:1.68.0 as Build

RUN apt-get update && apt-get install -y \
    clang\
    cmake \
    curl \
    fuse \
    git \
    libfuse-dev \
    pkg-config \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/* \
 && git clone --recurse-submodules https://github.com/awslabs/mountpoint-s3.git \
 && cd mountpoint-s3 \
 && cargo build --release


FROM debian:bullseye-slim
RUN apt-get update && apt-get install -y \
    ca-certificates \
    libfuse-dev \
    sudo \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*

COPY --from=build /mountpoint-s3/target/release/mount-s3 /usr/local/bin/mount-s3

RUN chmod 777 /usr/local/bin/mount-s3

RUN useradd -ms /bin/bash mount-s3-user \
 && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
 && adduser mount-s3-user sudo

USER mount-s3-user
```

## 動作確認
コンテナ内で s3 バケットをマウントするには、特権モード (`--privileged`)で実行する必要がありますのでご注意ください。
```shell
# イメージビルド
docker image build -t mount-s3:v0.2.0 .

# コンテナ起動
docker container run --privileged --rm -it mount-s3:v0.2.0 bash

# S3バケットのマウント
mount-s3-user@ce43831fda04:~$ sudo mount-s3 <bucket_name> /mnt --allow-other --region ap-northeast-1
mount-s3-user@ce43831fda04:~$ ls -l /mnt/test.json
-rw-r--r-- 1 root root 306424 Feb 21 02:42 /mnt/test.json
```

## EC2 on Docker での考慮事項
AWS 認証情報に EC2 の IAM ロールを使用する場合、コンテナ環境から IMDSv2 メタデータにアクセスできるようにするにはインスタンスメタデータオプションで IMDSv2 のホップ制限を 1 → 2 に増やす必要があります。

```shell
aws ec2 modify-instance-metadata-options \
    --instance-id i-xxxxxxxxxxxxxxxxx \
    --http-put-response-hop-limit 2 \
    --http-endpoint enabled
```

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html#imds-considerations

> コンテナ環境では、ホップ制限が 1 の場合、コンテナへの到達は余分なネットワークホップと見なされるため、IMDSv2 応答は返されません。IMDSv1 へのフォールバックプロセスとその結果として生じる遅延を回避するために、コンテナ環境でホップ制限を 2 に設定することをお勧めします。




以上です。
スプレッドシートをDataframeで読みたい時のスニペット

Google Colabで、スプレッドシートのデータをDataframeとして扱いたい時によく使うスニペット

```python
from google.colab import auth
from google.auth import default
import pandas as pd
import numpy as np
import gspread
from gspread_dataframe import get_as_dataframe, set_with_dataframe

SHEET_KEY = 'XXXXXXX';  
SHEET_NAME = 'foobar'

def main():
  #認証
  auth.authenticate_user()
  creds, _ = default()
  gc = gspread.authorize(creds)

  workbook = gc.open_by_key(SHEET_KEY)
  worksheet = workbook.worksheet(SHEET_NAME)
  df = get_as_dataframe(worksheet, usecols=range(8), header=0, evaluate_formulas=True).dropna(how='all')
  # usecols=[0,1,2,]　でも良い。カラムの使用範囲をリストで渡す。

  display(df)

if __name__ == '__main__':
  main()
```
ESLint / Prettier プラグイン集

# はじめに
この記事では、私が利用してきた ESLint と Prettier のプラグインを紹介します。
※随時更新していきます。
※ESLint と Prettier の導入方法については、別途こちらの記事を書いています。

https://qiita.com/Yasushi-Mo/items/e8e90a6690d731dc0a2d

# ESLintプラグイン
ESLintプラグインを種類別に紹介します。
## TypeScript
### @typescript-eslint/eslint-plugin

### @typescript-eslint/parser
TypeScriptのコードをESLintで利用できるようにパースする。

https://github.com/typescript-eslint/typescript-eslint

## React
### eslint-plugin-react
React向けのルール。

https://github.com/jsx-eslint/eslint-plugin-react

React17以上を利用していれば、ESLint 設定ファイルの `"extends"` に `"plugin:react/jsx-runtime"` を追加します。

:::note
以下のルールをOFFにするという方法でも同様の対処ができます。

```.eslintrc.json
{
  // ...
  "rules": {
    // ...
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off"
  }
}
```
:::

https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

### eslint-plugin-react-hooks

https://www.npmjs.com/package/eslint-plugin-react-hooks

## Next.js
### @next/eslint-plugin-next

https://www.npmjs.com/package/@next/eslint-plugin-next

## その他
### eslint-config-prettier
Prettierと競合するルールをOFFにする。

https://github.com/prettier/eslint-config-prettier

### eslint-plugin-sonarjs
バグを引き起こしやすいコードパターンを検知してアラートを出してくれる。

https://github.com/SonarSource/eslint-plugin-sonarjs

### eslint-plugin-jsx-a11y
アクセシビリティのルール。

https://github.com/jsx-eslint/eslint-plugin-jsx-a11y

# Prettierプラグイン
### prettier-plugin-organize-imports
インポートに関するフォーマット。
インポート順の整理や結合、未使用インポートの削除をしてくれます。
なお、VSCode の Organize Imports と同じ動作をします。

https://github.com/simonhaenisch/prettier-plugin-organize-imports

# 参考
- [ESLint のススメ](https://zenn.dev/yhay81/articles/def73cf8a02864)
- [ESLintを活用した漸進的リファクタリングのすすめ](https://blog.nnn.dev/entry/2019/12/03/022824)
- [Introducing the New JSX Transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html)
Laravelローカル環境構築

以下の2章まで実施する

https://reffect.co.jp/laravel/windows-xampp-laravel-install#PATH

以下の「Composer init」を実施

https://www.webdesignleaves.com/pr/php/php_composer.php

以下の「composerコマンドで作成」を実施
バージョンを指定するを省き、起動すると。。。

https://qiita.com/yukibe/items/5ee27163b603d7f68250

✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌
インフラ関係(ネットワーク・Linux)学習おすすめYoutubeサイト紹介

# はじめに
インフラ関係の知識が明らかに不足していたので、インフラ周りの勉強をしていました。その際自身が使用したネットワーク・Linux学習用Youtubeサイトを紹介します。

おすすめの学習法は1日1本動画を見ることです。一度に見てしまうのはエビングハウスの忘却曲線の観点から学習効率が悪いです。昨日学習した内容を思い出しながら、今日の学習を行いましょう。
![エビングハウスの忘却曲線](https://p.potaufeu.asahi.com/3855-p/picture/27384524/88e7383c36d053cef1edd9cedbbcc239.png)
出典: [エビングハウスの忘却曲線とは？最適な復習方法と注意点を解説](https://smbiz.asahi.com/article/14828411)

# ネットワーク
* [インフラエンジニアを目指すための「ネットワーク（CCNA）学習」](https://www.youtube.com/@UZUZCOLLEGE/playlists)
ウズウズカレッジさんのYoutubeチャンネルです。豊富な絵や例えで非常に分かりやすかったです。比較的ゆっくりとした速度なので２倍速推奨です。

* [PowerCert Animated Videos](https://www.youtube.com/@PowerCertAnimatedVideos)
超おすすめサイトです。Youtubeの最大の利点である動画を使用できることを活かしてアニメーションで様々な技術を解説してくれています。英語ですが、翻訳字幕も用意されていますので、そちらをご活用ください


# Linux
* [インフラエンジニアを目指すための「Linux ( LinuC/LPIC ) 講座」](https://www.youtube.com/@UZUZCOLLEGE/playlists)
ウズウズカレッジさんのYoutubeチャンネルです。比較的ゆっくりとした速度なので２倍速推奨です。

* [Linux オペレーティング システム - 初心者向けクラッシュ コース](https://www.youtube.com/watch?v=ROjZy1WbCIA)
有名な「freecodecamp」の動画です。動画を見ながら一緒に手を動かすことで理解が深まると思います。もし、freecodecampをご存知をご存知でなければ他にも素晴らしい動画がたくさんあるのでfreecodecampで検索してみてください。

# 終わりに
Youtubeを使用した学習の最大の利点は、アニメーションなどを用いて説明しているものにアクセスできることです。もし、本で学習をしているんだという人がいればYoutubeもぜひ試してみてください😉
VSCodeキーボードショートカット

# VSCodeキーボードショートカット
キーボードショートカットまとめ
|キーボード|動作|
|:---:|:---:|
|Ctrl+tab|タブ移動|
|Ctrl+1, Ctrl+2,,,|タブグループ移動|
|Ctrl+Shift+P|コマンドパレット|
|Ctrl+Shift+`|ターミナル起動|
RailsのMinitestでテスト実行後に、データが残ってしまう問題(複数DBを使用)

RailsのMinitestを使用していて、github actionを使用してCIを導入しようとしているのですが、その際に苦戦した話と対応方法を記載しておこうと思います。

## 前提
・1つのデータベースではなく、複数のデータベースを取り扱っている
・データベース単位かつテスト単位でfixtureを設定している
・setupの中でfixtureを設定している

## テスト実行後にDBに値が残り、それが他の自動テストのアサートに影響を与えてしまう
minitestを使用している時、基本的にはsetupの中でfixtureを設定しているようにしているのですが、テスト内で異なるDB同士でテーブルをjoinしているケースの場合にトランザクション範囲の関係で、fixtureで設定したデータが主テーブルに関しては引けるが、子テーブルでは引けないという事態になっていました。それを避ける為、runメソッドやuse_transactional_testsなどのオプションを使用することでトランザクションを無効にする対応を取っていました。ただこうしたケースの場合、transactionが効かない状態なのでロールバックされず、テスト実行後もデータが残り続けてしまいます。そしてデータが残ってしまうと、その他のテストでレコードが存在しないはずなのに取れてしまい、アサートがズレてしまうという現象が起きるわけです。

## 対策方法(teardownを活用しよう)
考えた対策として、teardownの中でデータ削除の処理を行うようにすることにしました。teardownは各テスト実行後に呼ばれるメソッドで、タイミングとしてここに記載するのが適切だと考えました。

```customer_controller_test.rb
setup do
    ActiveRecord::FixtureSet.reset_cache
    fixture_directory = Rails.root.join('test', 'fixtures', 'customer_controller_test')
   
    fixture_files = [
      :customer_products
    ]
    @fixture_models_customer_product = {
      customer_products: CustomerProducts
    }

    ActiveRecord::FixtureSet.create_fixtures(fixture_directory, fixture_files, @fixture_models_customer_product, CustomerProductsDb)
    
    fixture_files = [
      :customer_info
    ]
    @fixture_models_customer_info = {
      customer_info: CustomerInfo
    }
    ActiveRecord::FixtureSet.create_fixtures(fixture_directory, fixture_files, @fixture_models_customer_info, CustomerInfoDb)
  end

  teardown do
    delete_database
  end

```

teardownに記載しているdelete_databaseですが、これはtest_helperに定義しているメソッドです。ここではポイントとして、モデル情報を定義するハッシュ値をインスタンス変数にしている点です。こうすることでtest_helper内からもこの値を参照することができます。

```test_helper.rb
  def delete_database
    if @fixture_models_customer_product.present?
      CustomerProductsDb.connection.execute "SET FOREIGN_KEY_CHECKS = 0;"
      @fixture_models_customer_product.values.each { |model| model.delete_all }
      CustomerProductsDb.connection.execute "SET FOREIGN_KEY_CHECKS = 1;"
    elsif @fixture_models_customer_info.present?
      CustomerInfoDb.connection.execute "SET FOREIGN_KEY_CHECKS = 0;"
      @fixture_models_customer_info.values.each { |model| model.delete_all }
      CustomerInfoDb.connection.execute "SET FOREIGN_KEY_CHECKS = 1;"
    end
  end
```

あらかじめDB単位でここのif分に記載しておけば、運用としてrunメソッドやuse_transactional_testsを用いているテストは、teardownでこの関数を呼びさえすれば勝手にデータを削除をしてくれるような仕組みにしています。データを削除する際に外部キー制約を貼っている場合、その子テーブルを先に削除しろと怒られるので、SET FOREIGN_KEY_CHECKS = 0;で一時的に外部キー制約を無効にし、データを削除した後その外部キー制約を元に戻すようにしています。先頭のconnection.executeはActiveRecord::Baseクラスが保持しているSQLの実行を行うメソッドで、connection.executeの後にクエリを記載することでそのクエリを実行してくれます。

## 終わりに
CIを導入するつもりが、思わぬ伏兵に出くわして本来やろうとしてたことから大きくその範囲が広がってしまった印象です。同じようなケースで悩んでいる方がいらっしゃれば参考にして頂ければと思います。