OmniAICreator/Qiita-1.07M huggingface dataset:
【Day 2】ユーザーストーリーを作ろう

## はじめに

![スライド3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/bb5a2468-6172-7750-c6f1-d76e24578d64.png)

---

**2023年アドベントカレンダー2日目**です。

https://qiita.com/advent-calendar/2023/life-sync-app

昨日は開発前にディレクトリ構成を考えてみました。

今回はサービスを作る前にユーザーストーリーを考えることで、提供できる価値単位でタスクにとりかかることができます。

## カンバン

今回はTrelloを使ってみます。<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/9d76b118-1e10-52a1-1a4e-6bfdfc56045d.png" width=20/>

https://trello.com/ja

カンバンは何でもいいですが、、
できるだけすぐ見れるようなものがいいと思います👍

## ユーザーストーリーとは？

ChatGPTに聞いてみました。

> ユーザーストーリーは、アジャイル開発の手法の一部として用いられる、製品やサービスの機能を記述する短い、簡潔な文です。
> ユーザーストーリーの目的は、ソフトウェア開発プロジェクトにおいて、エンドユーザーの視点とニーズを明確に表現することにあります。
> これにより、開発チームはユーザーのニーズに焦点を当てた製品を作ることができます。

ユーザーストーリーを作成し、価値が生まれる単位での開発を進めていきます

## ちょっとその前に

ユーザーストーリー作る前に**ルール**を決めています。

### ルールその① 主語は必ずつけること

**誰に**向けたストーリーなのかを明確にします

:::note info
Example
:no_entry_sign: トップページの実装
:ok: ユーザーはトップページを閲覧することができる
:::

### ルールその② リリース可能な単位であること

ストーリーはそれぞれ**リリース可能な単位**で切ります。

:::note info
Example
:no_entry_sign: APIの実装がないから、画面を開くと500エラーが表示されるような状態
:ok: 画面を開いても不自然のない状態
:::

### ルールその③. 最低限であること

最低限なストーリーにすることで、**フィードバックを最短で得られる**ようにします
フィードバックまで数週間かかるようなストーリーにはしません

:::note info
Example
:no_entry_sign: ユーザーはブログ機能すべてを使うことができる
:ok: ユーザーはブログの一覧を見ることができる
:::

## 作ってみた

### リスト

まず、リストを作っていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/6a5ac6f6-5a57-82cc-e562-46f13df1996e.png)

- TODO
    - ユーザーストーリーの一覧
- DEV
    - 開発中のストーリー
- RELEASE
    - リリース済みのストーリー

個人開発のタスク管理としてはこの程度に留めておきます。
チームで開発する際は、どのタスクを誰が、どの程度の進捗なのかを理解するために、より細かくしてもいいと思います。

### ラベル

そのストーリーがどの程度の影響範囲があるのかをパット見て判断できるようにラベルを作成しました
これは視認性向上のためなので、マストではないです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/be90a3df-ad74-320f-ca6f-e13c84b37bb8.png)

## ストーリー作成！

今回開発する機能を洗い出してみると、、、

- トップページ
    - デザインの作成・適用
    - ブログの一覧が見られる
- ブログ新規登録画面
    - デザインの作成・適用
    - ブログの新規登録ができる
- ブログ編集画面
    - デザインの作成・適用
    - ブログの編集更新ができる

このように洗い出せました。
これをユーザーストーリーに落とし込んでいきます

### 一部抜粋

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/82c99506-d355-3cc6-ce4a-782017eba6e5.png)

:::note
### ポイント
ブログタイトルの一覧を画面で見たいと思ったとき、
このようにまとめてしまうと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/0e9dd9e4-9458-cdc6-57c9-79611ffc4efa.png)

そうはせず、**ルールその③. 最低限であること**に従って、
1. まずは固定値のブログタイトルを見ることができることをでフィードバックを得る
1. 次に設定されたブログ一覧を見ることができる

といったように**最低限**を切り分けています。
ただし、順番が前後したり、片方のストーリーがスコープアウトしても大丈夫なようなストーリーの切り方にした方が良いと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/18a7ce97-cbb4-629b-1bac-0cb945ea4fff.png)
:::

### ストーリーポイント

作成したストーリーにストーリーポイントを振っていきます。

今回は`1, 2, 3, 5, 8`の中から設定するとして、ストーリーの後ろに追記します。

:::note info
**ストーリーポイントを設定するポイント**
- ストーリーポイントは規模・複雑性で考えるべし
- ストーリーポイント **≠** 工数
- ユーザーに価値が届けられる最小限にまで分割すべし
:::

こんな感じになりました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/40472bdf-a315-77d6-33b6-8a24039e83bd.png)

次回は実際にストーリーを消化していきます。
macOS Sonoma14.0でXcode14以下を起動する方法

macOSをSonoma 14.0にアップデートしたところXcode14系のアイコンに通行止めマークが表示され、クリックで開くことができなくなっていました。
![スクリーンショット 2023-11-13 12.06.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/ef3ac8c0-58b6-418d-f2ef-4cc5c10ce271.png)
開こうとすると15にバージョンアップしろと怒られます。
![スクリーンショット 2023-11-13 12.04.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/df9ada6c-d601-8777-a648-838fa34a9dab.png)

ここではSonoma 14.0でXcode14以下を開く方法を2つ紹介します。

## 1. ターミナルでコマンドを叩く
ホームディレクトリに移動し以下コマンドを叩く
```
/Applications/your_xcode_name.app/Contents/MacOS/Xcode ; exit;
```

<font color="red">'23.11.27追記</font>
xcode**14.2**がコマンドで開けなくなっていた。Finderからは開けた。


## 2. Finderから開く
1. Finderで開きたいxcodeの場所まで移動する
2. 該当xcodeを右クリックし「パッケージの内容を表示」を開く
![スクリーンショット 2023-11-13 12.04.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/cecf595b-5f8a-5253-5c14-863fec8d2f42.png)

<br>
3. 「Contents > MacOS > Xcode」をダブルクリックで開く

![スクリーンショット 2023-11-13 12.05.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/f4c181d9-715f-3745-55e3-093e58685ee1.png)

ターミナルが1つ余計に開いてしまいますが、上記2つの方法で開くことができます。


## 余談
この方法でxcode14.2を使用しているときにほぼ100%の確率でコード補完をするとxcodeがクラッシュします。
一度クラッシュするとしばらくの間毎回コード補完でクラッシュし、たまにクラッシュしなくなったと思っても少し経つとまたクラッシュするようになりかな〜〜〜りストレスです。
xcode14.3.1では再現しないので、バージョンによって起きたり起きなかったりするっぽいです。
JSON.parseで改行がある文字列の注意点

DBから取得したJSONの文字列がこんなようにします
```
{"text":"text検証\n test"}
```
JSONの文字列なので、textの値を取得したい場合、JSON.parse()が使われます。しかし、以下のエラーが発生します。
```
undefined:1
{"text":"text検証
               ^
SyntaxError: Unexpected token 
 in JSON at position 15
    at JSON.parse (<anonymous>)
```

原因は、JSON.parse()を使いたいが、制御文字が含まれているため、```\n```を```\\n```に変更する必要があります。
```
const str = '{"text":"text検証\\n test"}'
console.log(JSON.parse(str))
```
結果は
```
{ text: 'text検証\n test' }
```
問題ありません。
Bitriseの機能を使ってSwiftLintを導入

# 概要
BitriseでiOSアプリのCI/CD環境を構築すると簡単にSwiftLintのチェックを導入する事ができます。Bitriseの機能を使用しておりFastlaneやDangerを使用してません。
## 前提
本記事は以下の前提で作ってます。
- Bitriseでアプリのビルドを完了している事。
- SwiftLintをSwiftPMで導入している事。
  - `BuildTools`ディレクトリに`Package.swift`を置いている事。
  - `.swiftlint.yml`がプロジェクトルートにある事。
## Bitriseのステップ構成
全体のステップに関しては以下になります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559656/80d80dc1-3ee4-4140-4dab-967f9e993b02.png" width="300">
### 1. `Activate SSH key (RSA private key)` ステップ
- 役割
  - Bitrise->GitリポジトリのSSH接続が有効にする。
- 必要な設定
  - 特に設定する必要はありません。
### 2. `Git Clone Repository` ステップ
- 役割
  - Gitリポジトリからソースコードを取得する。
- 必要な設定
  - 特に設定する必要はありません。
### 3. `Script` ステップ
- 役割
  - SwiftLintのソースコードを取得する。
  - SwiftLintをビルドして実行バイナリを作成する。
- 必要な設定
  - [[SwiftLintのソースコード取得とビルド]](#swiftlintのソースコード取得とビルド)のbashコードを[Script content]に設定します。
### 4. `SwiftLint` ステップ
- 役割
  - `swiftlint`バイナリを実行する。(`swiftlint lint --config .swiftlint.yml`)
  - BitriseのArtifactsにレポートファイルを作成する。
- 必要な設定
  - 2023/11現在では`0.X.X`と`1.X.X`の2つ存在しますが、`1.X.X`の方を選択します。
  - [Select the path where Swiftlint should lint]
    - `$BITRISE_SOURCE_DIR/BuildTools/.build/release/`を設定する。
  - [Linting configuration file]
    - `$BITRISE_SOURCE_DIR/.swiftlint.yml`を設定する。
  - [Select the reporter type]
    - `html`を設定する。
### 5. `Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files` ステップ
- 役割
  - レポートファイルをBitriseのArtifactsにデプロイする。
- 必要な設定
  - 特に設定する必要はありません。
### 6. `Script` ステップ
- 役割
  - ArtifactsにあるレポートファイルのダウンロードURLを取得する。
- 必要な設定
  - [[レポートファイルのダウンロードURL取得]](#レポートファイルのダウンロードurl取得)のbashコードを[Script content]に設定します。
### 7. `Send Microsoft Teams message` ステップ
- 役割
  - MS Teamsに結果を通知する。
- 必要な設定
  - [Microsoft Teams Webhook URL]
    - TeamsのWebhook URLを設定する。
  - [A list of buttons attached to the message as link buttons]
    - `Install Page|${BITRISE_PUBLIC_INSTALL_PAGE_URL}`を追加する。
## SwiftLintのソースコード取得とビルド
```bash
#!/usr/bin/env bash

xcrun --sdk macosx swift build -c release --package-path $BITRISE_SOURCE_DIR/BuildTools --product swiftlint
```
## レポートファイルのダウンロードURL取得
``` bash
#!/usr/bin/env bash
# Fetch report file name
REPORT_FILE_NAME=`basename $SWIFTLINT_REPORT_PATH`

# Fetch report url
SWIFTLINT_REPORT_URL=$(echo $BITRISE_PERMANENT_DOWNLOAD_URL_MAP | tr "|" "\n" | grep -F $REPORT_FILE_NAME | sed 's/.*=>\(.*\)/\1/')

# Add environment value
envman add --key SWIFTLINT_REPORT_URL --value "$SWIFTLINT_REPORT_URL"
```
`BITRISE_PERMANENT_DOWNLOAD_URL_MAP`に`ファイル名=>URL|ファイル名=>URL`の形式でSwiftLintのレポートファイルのURLが格納されるため、そこからhtmlファイルのファイル名をgrepしてURLを取得します。
# 所感
Bitriseの機能を使用する事で簡単にSwiftLintのチェックをCI/CD環境に取り込める事ができました。GitLab環境でdanger-gitlabがうまく動作しなかったので、私の場合はこの方法がフィットしました。
MS Teams通知のステップは`Send a Slack message`ステップや`Comment on GitHub Pull Request`ステップに置き換えることでSlack通知やGithubのPRへコメントする事もできそうです。
また、この方法だとダウンロードリンクのURLが取得されるのですが、Bitrise APIを使用する事で直接レポートファイルのURLを取得できそうです。

https://support.bitrise.io/hc/en-us/articles/360015678277-Sending-a-link-to-a-file-in-Slack
よわよわエンジニア、UI・UX修行を始める ~そのUIは世間一般のアプリで採用されてますか？~

## はじめに
本記事では、UI・UXデザイン方面でつよつよになりたい筆者が、UI・UXデザインに取り組んでいくなかで身に染みて感じたことを書いています。

## 「自我を捨てろ」

強い言葉に思えるかもしれませんが、
要は **「変なところでオリジナリティを出そうとするな、まずは定石を守れ」** ということです。

筆者は、**「どこにもないオリジナルのデザインを作るのが良い、他のデザインをマネすることは悪だ」** と考えていました。
筆者はイラスト制作を趣味としています。絵の世界において他の絵をマネすること、いわゆるパクリはご法度です。やったら炎上します。
なので、デザインの世界においても「そう」だと思っていました。

確かに、見た目(色とか、ロゴとか、アイコンとか)はパクっちゃダメです。
ですが、**使い勝手に関しては、果たしてどうでしょうか。**

ウィンドウを閉じる×ボタンがウィンドウの左下にあったら戸惑いませんか？

ナビゲーションが左端ではなく右端にあったら違和感ありませんか？

スクロールバーが無くて、下へ送るのに[もっと読む]ボタンをいちいち押す必要があったら不便じゃないですか？

使い勝手の部分においては、**ユーザーは慣れ親しんだ操作でないと違和感を覚えます。**
世間一般で有名なアプリに採用されて、いろんな人に使われているUI・UXであれば、多くのユーザーはその操作に慣れ親しんでいるでしょう。
それこそ、ウィンドウを閉じる×ボタンはほぼすべてのアプリで右上にあります。
使ったことのないアプリであっても、ウィンドウを閉じようと思ったら無意識に右上にカーソルを動かしませんか？

ウィンドウを閉じる×ボタンは極端な例ですが、些細なところであっても、「よくあるUI・UX」ではないと、ユーザーは違和感や使いにくさを覚えます。

**そこは、オリジナリティを出すべきところではないのです。**

それに、多くの場合において、素人の思いつく程度の「誰もやらなかったこと」は、
「プロのみんなが、たとえ思いついても**いまいちだからやらなかったこと**」
なんです。

UI・UXデザインのド素人こと筆者は、「**いずれみんながマネしたくなるような新しいUI・UXデザインを作ってみせる**」という野望を胸に日々修行を積んでいます。
ですが、「みんながマネしたくなる新しいUI・UXデザイン」を提案するには、きちんと定石を踏まえて「**なるほど、これは使いやすい**」と思わせたうえで「**これは新しい！**」と思ってもらえるオリジナリティを出さないといけないのです。
そのため、まずは良いUI・UXデザインの見聞を広めて、外さないデザインができるようになりたいと思います。

## さいごに

UI・UXデザインに取り組むうえで最初の壁だったことが、本記事で書いたことでした。
お絵かき大好きなので、つい見た目の美しさ・奇抜さ先行でデザインを考えがちだった筆者。
デザインなのにマネしないといけないなんて、オリジナリティないじゃん！と悩んだこともありましたが、何度もレビューで指摘をもらって使い勝手のことを真面目に考えた結果、納得して今はデザインに取り組めるようになりました。

とはいえ取り組み始めたばかりで知識もまだまだ浅いので、おすすめの書籍などあれば教えていただきたいです。
gitのバージョン競合

## 問題の概要

- 案件ブランチに新しく追加されたファイルが、masterブランチにも既に存在します。
- 案件ブランチのファイルは最新ですが、masterブランチへのマージ時に問題が発生します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2715983/4526b92d-afe4-f8a8-da45-0a9c6e493e3c.png)
## 解決策

1. **最新のmasterブランチを取得**
   - まず、ローカルのmasterブランチを最新の状態に更新します。
     ```
     git checkout master
     git pull origin master
     ```

2. **案件ブランチにmasterをマージまたはリベース**
   - 案件ブランチに切り替えて、最新のmasterブランチをマージまたはリベースします。
     ```
     git checkout [案件ブランチ名]
     git merge master
     ```
     または
     ```
     git rebase master
     ```

3. **競合の解決**
   - マージまたはリベースの過程で競合が発生した場合は、それを手動で解決します。
   - 競合があるファイルを開き、Gitが示す競合部分を確認し、適切に修正します。

4. **変更をコミット**
   - 競合を解決したら、変更をステージに追加し、コミットします。
     ```
     git add .
     git commit -m "競合解決"
     ```

5. **masterブランチへのマージ**
   - 再びmasterブランチに切り替え、案件ブランチをマージします。
     ```
     git checkout master
     git merge [案件ブランチ名]
     ```

6. **変更をリモートにプッシュ**
   - 最後に、更新されたmasterブランチをリモートリポジトリにプッシュします。
     ```
     git push origin master
     ```

## 注意点

- マージやリベースの際には、常に最新の状態を保つことが重要です。
- 競合の解決には注意を払い、必要に応じてチームメンバーやプロジェクトリーダーと相談しながら進めてください。
【ChatGPT】履歴を保存する方法です。


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

　今回は、ChatGPTの履歴を保存する方法です。履歴があり過ぎて、過去のセッションにたどり着けなくなっている人も多いはず。

:::note info
本記事は、ChatGPT無料版有料版
関係なく、また web版アプリ版の
関係なくできるはず。あしからず。
:::

　履歴の保存は必要ない、
　　という人は、いないでしょう。

　でも、
　　意識に昇らないくらい
　　　放っといていませんか？

　利用率の少ない方は
　　構わないと思いますが、
　　　毎日毎日、それなりに
　　　　触っている方は
　　　　　多いはず。

　なので、
　　そろそろ履歴を
　　　保存しておいて
　　　　イザというときに
　　　　　備えましょう。
　　　　　　イザってなんだ、
　　　　　　　とか言わないようにw

　世の中、何が起こるか
　　わかりませんから。
***
　ここまで書いておいてなのですが、
　　保存しても、復元はできません。
　　　あしからず。

　でも、何もなくなるよりは
　　ありがたいですよ。
***
　さてはて、
　　やりましょうか。

　とりあえず、
　　ChatGPTさんに
　　　聞いてみた。
***
***User***
ChatGPTの履歴を保存したいです。
どうしたらいいですか？
箇条書き（説明不要）でお願いします。

***ChatGPT無料版***
1. チャット履歴をテキストファイルにコピーします。
2. ファイルを保存するディレクトリを選択します。
3. ファイル名を入力します。
4. 保存ボタンをクリックしてファイルを保存します。
***
　まぁ、
　　そういうのもあるけれど。
***
***User***
Exportは？

***ChatGPT無料版***
1. チャットアプリのメニューまたは設定から「Export」オプションを見つけます。
2. 「Export」を選択します。
3. チャット履歴を保存したい形式（テキスト、CSVなど）を選択します。
4. ファイルの保存先を指定します。
5. 「保存」または「Export」ボタンをクリックしてファイルを保存します。
***
　聞いたオイラが
　　悪かったw
***
　手順の説明しますね。
　まずは、web版。

　1.アカウントから、設定を選ぶ。
　　　Plusは、“プラス設定&ベータ”。
　2.データ制御タブをタップ。
　3.“データをエクスポート”の
　　　“エクスポート”ボタンをタップ
　4.注意点を書いたポップアップが
　　　出てくるので、
　　　　確定ボタンをタップ。
　5.メールが届く。
　　　見ると、緑色のボタンが。
　　　　これをタップ。

　アプリの方は、
　　メニューのData Controlsで
　　　Exportをすると、
　　　　メールが来ます。
　　　　　緑色のボタンをタップ。

　これで
　　履歴がダウンロードされます。
***
　さて、
　　ダウンロードされた
　　　ファイルですが、
　　　　圧縮ファイル（.zip）です。

　内容は、
　　.jsonが五つ。
　　　.htmlがひとつ。

　この.htmlが
　　履歴のやり取り集に
　　　なります。

　.jsonについては、
　　こちらを参照してください。
　　　kasamaさんという方が
　　　　書かれています。
[ChatGPTの履歴データがExportできるようになっていました](https://dev.classmethod.jp/articles/chatgpt-history-data-can-now-be-exported/)
***
　ブラウザで
　　開いてみますと
　　　本当にやり取りです。
　　　　セッションごとに、
　　　　　区切られています。

　ここで、**注意して欲しい**のは、
　　セッションで、プロンプトを
　　　編集している場合、
　　　　最新だけが残されます。

　つまり、そこまでのやり取りで
　　分岐が発生すると、
　　　最後の分岐だけが残され、
　　　　その前の分岐は
　　　　　残りません。

　その分岐の方が、大事な場合は、
　　ChatGPT上で、履歴を遡り、
　　　そのセッションにアクセスして
　　　　その分岐を選んで
　　　　　テキストやスクショで
　　　　　　コピーする。

　　　　または、追加の入力を
　　　　　してセッションを
　　　　　　更新しておく。

　　　　それで、
　　　　　再度、エクスポートする。
***
　どうでしたか？

　私も履歴を
　　エクスポートまでは
　　　していました。

　しかし、内容については、
　　今回初めて、知りました。
　　　みなさん、知っていました？

　また、
　　生成画像は、
　　　残りません。
　　　　残したい場合は、
　　　　　それぞれの画像を
　　　　　　個別にダウンロード
　　　　　　　してください。

　今回は、ここまで。
PWA（Progressive Web App）について調べ直してみた

## きっかけ

iOSでプッシュ通知ができない等のプラットフォーム間の差がありましたが、iOS16.4にてプッシュ通知がサポートされるようになったので改めてPWAについて調べ直したいと思います。

https://developer.apple.com/documentation/usernotifications/sending_web_push_notifications_in_web_apps_and_browsers


## PWAとは？
WEB技術だけでネイティブみたいなWEBアプリケーションを作るためのデザインパターンと個人的に解釈しました。

[Googleのドキュメント](https://web.dev/articles/what-are-pwas?hl=ja)を読んでも明確な事は示されていなかった。しかし、Progressive = 「発展、前進」と言う意味だし、「今後のWEBアプリ開発のガイドライン」と言った意味も含んでそうだと感じました。

## PWAの特徴
[MDN](https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames#%E4%BD%95%E3%81%8C%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92_pwa_%E3%81%AB%E3%81%99%E3%82%8B%E3%81%AE%E3%81%8B) や他ブログを読んで噛み砕いてみると下記要素を含むとPWAであると言えそう。

* __レスポンシブデザイン__：PC,スマホ等のデバイスの違いに対応できるデザインを提供する
* __WEB APIの活用__：ネイティブアプリの様にローカルファイル、カメラや地図等へアクセスする様々な機能を利用できる。
* __Service Workerの活用__：端末へのインストールやプッシュ通知で利用しているモジュール
* __UX重視__：キャッシュ等を用いてユーザーの体験を損なわない設計を是としている


## PWA（WEB）でできること
上記特徴にも上げましたが、ブラウザ上で使えるAPIが拡充されていていますね。
WebAssenblyも出てきたので、動画編集の様な、高負荷でネイティブでしかできなかったアプリもWEB化する未来があるかも？

https://whatpwacando.today/

https://developer.mozilla.org/ja/docs/Web/API


## PWAの要件
[Googleさんの定義するところ](https://web.dev/learn/pwa/getting-started?hl=ja#core_requirements)ではUX重視なのが伺えますね。

1. __Starts fast, stays fast__：ユーザーは表示に3秒以上かかると離脱すると言われているやつですね
1. __Works in any browser__：どのブラウザでも動作させる
1. __Responsive to any screen size__：モバイルファーストになりつつありますが、パソコンでの表示も考慮しましょう
1. __Provides a custom offline page__：アプリ体験を損なわないためにオフライン時の動作も考慮した方がUXが向上する
1. __Is installable__：インストール（ホームにアイコンを設置）すると、アクセスが向上する。インストール（キャッシュ活用）することでUXが向上できるらしい


要件通り実装できているかは Lighthouse で評価できるとのこと。

https://developer.chrome.com/ja/docs/lighthouse/


## PWAを構築するための手順
GoogleのドキュメントやWEBを見ると下記が必要になりそうだ。

1. __HTTPS対応__：Service Workerを利用するには必須みたいです
1. __Web App Manifest__：WEBアプリの情報を定義するJSONファイル。アプリ情報を格納するみたい
1. __Service Worker__：アプリのキャッシュやプッシュ通知用のバックグラウンドなタスク処理に利用するみたい

https://web.dev/learn/pwa/web-app-manifest?hl=ja

https://web.dev/learn/pwa/service-workers?hl=ja


## 調べて直してみた感想

お、覚えることが多い。。しかし、[web.dev](https://web.dev/learn/pwa)にまとまった資料が置いてあったので、時間を作って読み込みたいと思います。

現時点の懸念は、キャッシュファイルの管理とかオフライン時の状態管理とかを考慮しないといけなくなるのでアプリの複雑度が上がりそうだと感じました。（もしかしたら楽にできる？）
GitHub Actionsによるユニットテストの自動化

## **はじめに**

近年、CI/CDの自動化はソフトウェア開発の重要な部分となっています。特に、品質を保証しつつ迅速に開発を進めるためには、自動化されたテストとそのカバレッジのチェックが不可欠です。今回は、Go言語を使用したプロジェクトでGitHub Actionsを利用してユニットテストを実行し、テストカバレッジをチェックする方法を紹介します。

## **GitHub Actionsによるユニットテストの自動化**

GitHub Actionsは、ソフトウェアのワークフローを自動化するための非常に強力なツールです。これを使用して、プルリクエストやコミット時に自動的にユニットテストを実行できます。

### **ユニットテストの設定**

以下は、Go言語のプロジェクトにおけるユニットテストのための基本的なGitHub Actionsワークフローの設定例です。

```yaml
name: Unit Tests

on:
  pull_request:
    branches:
      - main

jobs:
  unit-tests:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Set up Go
        uses: actions/setup-go@v3
        with:
          go-version: 1.20

      - name: Run Unit Tests
        run: go test ./... -v
```

この設定では、**`main`**ブランチへのプルリクエスト時にユニットテストが実行されます。

### **テストカバレッジのチェック**

テストカバレッジは、テストがどれだけのコードをカバーしているかを示す指標です。良いカバレッジ率は、コードの品質を保証する上で重要です。以下のステップでカバレッジをチェックし、特定の閾値以下の場合にはエラーを発生させるように設定します。

1. テストコマンドにカバレッジオプションを追加します。
    
    ```yaml
    - name: Run Unit Tests with Coverage
      run: go test ./... -coverprofile=coverage.out
    ```
    
2. カバレッジの結果を分析し、指定した閾値（例えば80%）を下回っている場合にビルドを失敗させます。
    
    ```yaml
    - name: Check Coverage
      run: |
        COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print substr($3, 1, length($3)-1)}')
        echo "Code coverage is $COVERAGE%"
        if (( $(echo "$COVERAGE < 80.0" | bc -l) )); then
          echo "Code coverage is less than 80%"
          exit 1
        fi
    ```
    

この設定により、カバレッジが80%未満の場合にはエラーが発生し、ビルドが失敗します。この閾値はプロジェクトの要件に応じて調整してください。

# **おわりに**

GitHub Actionsを使用したユニットテストとカバレッジチェックの自動化は、Go言語プロジェクトの品質を維持しつつ、開発プロセスをスムーズにするのに大いに役立ちます。この記事があなたのプロジェクトにおけるCI/CDの実装に役立つことを願っています。
UITableViewの画面トップタップ＆トップ遷移は、UIScrollViewのscrollViewDidScrollメソッドで検出できる

# はじめに
UIScrollViewが提供する、スクロールした時を検出する[scrollViewDidScroll]("https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619392-scrollviewdidscroll")メソッドで、スクロールするアクションにおいて特定のスクロールアクションのみを検出する必要があったので、備忘録として記事化。

## UIScrollViewのscrollViewDidScrollメソッドとは

公式ドキュメントによると...

*ScrollView内でユーザがコンテンツをスクロールしたときにデリゲートに伝えます。by [Apple Docs]("https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619392-scrollviewdidscroll")*


以下、公式に載っていない気付き

 - 指が触れる、指でドラッグする、指が離れた後にスクロールアニメーションが起こっている状態で、発火する
 - 一度のスクロールで、**何度呼ばれるかわからない**

## 今回のキーとなるUIScrollViewのジェスチャー一覧

- [isTracking]("https://developer.apple.com/documentation/uikit/uiscrollview/1619413-istracking")
*ユーザーがコンテンツに触れてスクロールを開始したかどうかを示すbool値。*(=コンテンツに触れたかどうか)

 - [isDragging]("https://developer.apple.com/documentation/uikit/uiscrollview/1619384-isdragging")
 *ユーザーがコンテンツのスクロールを開始したかどうかを示すbool値。*(=触れてドラッグしたかどうか)

 - [isDecelerating]("https://developer.apple.com/documentation/uikit/uiscrollview/1619434-isdecelerating")
*ユーザーが指を離した後、ScrollViewでコンテンツが動いているかどうかを示すbool値。*(=触れてドラッグして離して、スクロールアニメーションが効いているかどうか)


## 満たすべき要件

画面トップをタップして、コンテンツのトップに遷移する動作のみ検出するためには...

#### コンテンツに触れても、ドラッグしてもいないが何故か動きを検出してしまった時


が検出できればゴールになります。


## まとめ(詳細な実装)

```
struct MyView: UIViewRepresentable {
    ...

    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator: NSObject, UITableViewDelegate {
        func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
            // トップに到達した時に発火する処理
        }
        
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            if !scrollView.isTracking, !scrollView.isDragging, !scrollView.isDecelerating {
                // 画面のトップをタップして、スクロールアニメーションが開始した時に、発火させる処理
            }
        }
    }
}
```

※尚、トップに到達した時に発火するメソッドは、`scrollViewDidScrollToTop(_ scrollView: UIScrollView) `を使用します。
vue + amplify アプリ　ログインの有無でのルーティング制御

## 記事の作成理由
備忘録として、記事を残しておきたい。
お困りの方がいらっしゃれば参考になればと思います。


## AuthUIの実装
App.vue（サインアウト）
 `<amplify-greetings></amplify-greetings>`
ログイン画面を表示させるページ
 `<amplify-authenticator></amplify-authenticator>`

src/store/index.vue
storeにユーザー情報を保存する
userというステートを追加します。
```js
export default createStore({
    state: {user: null,
    },
    mutations: {
 setUser(state, user) {
  state.user = user;
 },
    },
    actions: {
    },
    modules: {
    }
  })
```
ユーザーがサインイン済みであればこのuserステートに情報を保存し、
ユーザーがサインインしてなければこのuserステートを空にします。

routerも変更します。
追記
```js
import store from "@/store/index.js";
import Auth from "@aws-amplify/auth";

function getAuthenticatedUser() {
  return Auth.currentAuthenticatedUser()
    .then((data) => {
      if (data && data.signInUserSession) {
        store.commit("setUser", data);
        return data;
      }
    })
    .catch((e) => {
      console.error(e);
      store.commit("setUser", null);
      return null;
    });
}
router.beforeResolve(async (to, from, next) => {
  await getAuthenticatedUser();

  return next();
});
```

サインページ以外のログインされた場合のみ表示される画面
各ルーティングの場所に記述します
src/router/index.js
`meta: { requireAuth: true },`

```js
let user;

user = await getAuthenticatedUser();

if (to.name === "SignIn" && user) {
  return next({ name: "AlbumIndex" });
}

if (to.matched.some((record) => record.meta.requireAuth) && !user) {
  return next({ name: "SignIn" });
}
```

App.vue
```js
<div v-if="isSignedIn">
  <amplify-greetings></amplify-greetings>
</div>

<script>

    export default {
    
      computed: {
    
        isSignedIn() {
    
          return this.$store.state.user !== null;
    
        },
    
      },
    
    };

</script>

```

先ほどstoreに追加したuserステートを参照し、
もしuserステートが存在すればサインアウトボタンを表示し、
空であればサインアウトボタンを非表示にしています

## 感想
ここまで簡単にログイン画面が実装できてします
ここからcognito など使用すればさらにログインが簡単になると感じました
webpack 俺的最低限設定

Nuxtの短納期プロジェクトで採用した設定をメモ。

### cleanしないでキープする

```webpack.config.js
module.exports = {
  output: {
    clean: {
      keep: /index.html/,    // index.html を削除しない
    },
  }
}
```
ファイル名を囲むスラッシュはディレクトリを表すものではない。
正規表現のスラッシュ。

### ソースマップを出力
```webpack.config.js
module.exports = {
  devtool: "hidden-source-map”
}
```
hidden-だがこれで出力される。
【React】100本ノックやってみた #02 Counter

# はじめに
最近フロントエンドのフレームワークを勉強しようと思い、Udemyで一通り勉強しました。
しかしどうも身についた気がしないのと、もう少し実践的なことをやりたいと思ったため、
@Sicut_study(Watanabe Jin)さんが公開しているReact100本ノックをやってみました。

https://qiita.com/Sicut_study/items/3c5cd798313854a471a0

# 前の記事

https://qiita.com/kmmch/items/6850e0848a92dec3d08a

# ルール
* React, TypeScriptを使う
* その他ツールやライブラリの使用は自由

# 作成するもの
カウンターを作成する

# 成功条件（抜粋）
>1. 表示領域: 数字を表示するエリアが存在する。
>2. インクリメントボタン: このボタンをクリックすると、表示されている数字が 1 増える。
>3. デクリメントボタン: このボタンをクリックすると、表示されている数字が 1 減る。
>4. 初期表示: アプリを起動した際の数字は 0 である。
>5. ステート管理: React の useState や useReducer を使って、カウントの数字を管理する。

# 成果物
## 使用技術
* React 18.2.0
* TypeScript 4.9.5
* Chakra-UI 2.8.5

## URL

https://heroic-fox-d0301d.netlify.app/

## キャプチャ
### PC
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/7966dda2-b43c-f4d2-1af0-39e7c983759b.png)


### SP
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/fa4a97ac-f926-9a77-f2fc-84232a422ed6.png)


# 実装手順
## プロジェクトのセットアップ
```bash
# React×TypeScriptのプロジェクト作成
npx create-react-app helloworld --template typescript

# ディレクトリ変更
cd helloworld
```

```bash
# Chakra-UIのインストール
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
```

```bash
# react-helmetのインストール
npm i react-helmet
```

## コンポーネントの作成
リポジトリのsrcフォルダ配下をご確認ください。

https://github.com/kmmch/Counter


## デプロイ
NetlifyにGitHubを連携してデプロイ

# さいごに
React100本ノックの第2弾であるCounterアプリを作成してみました。

useStateの使い方を再確認できましたが、
「+」「-」ボタンをクリックするごとに数字を表示するコンポーネント以外のタイトルも再レンダリングされているのが現状です。

今後大規模なアプリを作成する際は不必要な再レンダリングを防ぐ必要もありますので、そのあたりを再確認してみようと思います。


# 次の記事
https://qiita.com/kmmch/items/107bfeb1d316e4702244
CloudFormationの超詳細解説 3/4 実行編

# はじめに
この記事はDevOps on AWS大全の一部です。
DevOps on AWS大全の一覧は[こちら](https://qiita.com/tech4anyone/items/b06f88035d27c6ef13b2)。

この記事ではCloudFomationの実行に関連する内容を超詳細にまとめています。

具体的には以下流れで説明します。

- Drift
- ChangeSets
- Rollback
- Service Role
- Stack Policy
- DeletionPolicy

AWSの区分でいう「Level 200：トピックの入門知識を持っていることを前提に、ベストプラクティス、サービス機能を解説するレベル」の内容です。

# この記事を読んでほしい人
- CloudFormationがどういうサービスか説明できるようになりたい人
- CloudFormationを採用するときのベストプラクティスを説明できるようになりたい人
- AWS Certified DevOps Engineer Professionalを目指している人


# Drift
DriftはCloudFormationで管理しているリソースがCloudFormationテンプレートの記述通りの状態で存在しているかを確認する機能です。

例えば、すべてのインフラストラクチャをCloudFormationテンプレートで管理してるプロジェクトがあるとします。
そのプロジェクトルールを知らない新規参画者がSecurityGroupをマネジメントコンソールで変更してしまいました。
という場合、CloudFormationテンプレートと実環境に差分が発生してしまいます。

この差分を見つけるために使うのがDrift機能です。
CloudFormationでスタック更新をする際には、念のためDriftを実行するのがベストプラクティスです。

なぜなら、トラブルシューティングなどで修正を最優先してCloudFormationテンプレートへの反映漏れがある、というのはよくある話だからです。
万が一Driftを実行しないと、トラブルシューティングで行った変更がすべて消え、再びトラブルを引き起こすことになります。

ただし、Driftはすべてのリソースで対応しているわけではないので自分たちが使っているリソースでも使えるかは[AWS公式](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/resource-import-supported-resources.html)で確認をお願いします。

# ChangeSets
ChangeSetsはスタック更新を実施するときに、変更の前後でどういった差分が出るかを一覧化したものです。
スタック更新をするときにChangeSetsを作るか作らないか聞かれるので、必ずChangeSetsを作って意図しない変更が入らないかを確認してからスタック更新を行うようにしましょう。

# Rollback
RollbackとはCloudFormationのスタック作成あるいはスタック更新が失敗したときに、以前の状態に自動で切り戻す機能です。

スタック作成が失敗した場合のRollbackは作成成功していたリソースも含めスタックで管理しているすべてのリソースが削除され、作成前の状態に切り戻されます。

スタック更新が失敗した場合には作成成功していたリソースも含めスタックで管理しているすべてのリソースが切り戻しあるいは削除され、一番最近の成功したスタックの状態に切り戻されます。

どちらの場合でもログに失敗原因が出力されるので、Rollbackしたらログから原因調査を行いトラブルシューティングします。

# Service Role
Service RoleはCloudFormationにスタックリソースを作成/更新/削除することを許可するIAMロールです。

IAMユーザにCloudFormationの細かい権限を設定するのではなく、CloudFormationというサービスがどういう権限かを設定します。

これにより、最小権限の原則を実現するためにスタックを操作するために必要なすべての権限をユーザーに与えたくないがCloudFormationのスタックを操作できるようにしたいという要件をクリアできるようになります。

# Stack Policy
Stack PolicyはCloudFormationのスタック更新でアップデートを許可/禁止するリソースを定義するためのポリシーです。

CloudFormationのスタック更新について、デフォルトではすべてのリソースに対するすべてのアクションが許可されています。

しかし、特定のリソースだけは絶対に更新されたくない、という場合にStack Policyで該当リソースの更新を禁止します。

ただし、スタックポリシーは、スタックの更新時のみ適用され、IAMポリシーのようなアクセスコントロールは提供しない点に注意しましょう。

# DeletionPolicy
スタック削除をするときに各リソースを残すのか、削除するのかをていぎできるのがDeletionPolicyです。
例えば、スタック削除するが、EBSはスナップショットを取っておきたい、という場合に利用できます。
| DeletionPolicy | スタック削除時の挙動 | 備考 |
|--- | --- | ---|
| Retain | スタック削除時にリソースは保持されます | なし |
| Snapshot | スタック削除時にSnapshotを取得しリソースは終了します | なし |
| Delete | スタックを削除するとリソースも削除されます | DeletionPolicyを指定しない場合のデフォルト動作です。<br> RDSのDBクラスターはデフォルトがSnapshotです。<br> S3バケットは中身が空でないと削除できません。 |

# まとめ
この記事ではCloudFomationの実行に関連する内容を超詳細にまとめました。

- Drift
- ChangeSets
- Rollback
- Service Role
- Stack Policy
- DeletionPolicy

次回はCloudFormationの超詳細解説 4/4 Stack編です。
windows11でIMEが勝手に全角英数モードになる件

設定だけ知りたい方は **[ここ](#設定方法)** からどうぞ！

# 対象者
- 入力の際に全角英数が現れて困ってる人
# わかること
- 入力中に入力モードが全角英数にならない方法
# 注意点
- 全角ひらがなモードのまま子音を押しても、入力される文字は全角のままです。この記事では、入力モードが変わらないようにするための設定方法です。
# 検証環境
- Windows11 Pro 22H2

# windows11にしたら現れたバグ
### 勝手にIMEが全角英数モードになる！
### しかも戻せない！！！

## 何が起きたか
- **日本語を打っている最中にタイプミスで子音を入力し、そのまま確定させる**
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515837/51041742-20cd-a8fa-4467-712ab5c32e60.png)
- **半角英数に切り替えようとすると、全角日本語→全角英数になる**


エンジニアだけでなく、日本のオフィスワーカーはご存じの通り、全角英数なんて裁判所の判例集くらいでしか使わない訳です。

普通にイライラしたので、半角固定になるように調査。
## 問題発生
旧IMEでは[こんな感じ](https://iinamotto.com/2013/04/724.html)で、右下の「あ」とか「A」を右クリックしたら「プロパティ」が出てきたんですよね。
### プロパティがない！！！！！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515837/cbcb5414-e28b-49d5-ed37-10e66da8f4ef.png)

**ほんまどないなっとんねん。**

どうやらWindows10あたりからなくなってるらしいです。windowsに対する怨嗟はさておき、どうやら**Microsoft IME を以前のバージョンに戻す**ことで一旦できそうということが分かりました。
ということで設定していきます。
# 設定方法
### IMEのところ(あとかAとか書いてるところ)を右クリックして設定をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515837/693ba0b9-9898-ac19-3826-1a1bbc6439cb.png)

### 次に全般をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515837/ca1f4395-df5c-2b3a-e8c0-97f64641d6cf.png)

### 互換性をオンに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515837/c740bf84-2d0b-e7c2-3853-e66cb7eeb8e2.png)

### すると....
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515837/ed5a4d6e-20f7-19cb-7261-c7ab4d6d40fc.png)

### プロパティが復活した。という訳でそのままクリックし、詳細設定を開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515837/b54150b3-c4be-ab6e-607a-dfa7451afac3.png)

### 1. 「オートコレクト」をクリック
### 2. 「英字」を選択
### 3. 「常に半角に変換」をクリック
### 4. 「OK」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515837/18421326-d59e-17e6-3c0b-dfeee0543b7a.png)

### ~~旧IMEから戻す~~
~~先ほどの互換性のところを「オフ」に設定~~
**元に戻すと再発するため戻さない方がいいです。**(2024/1/29追記)


以上で設定完了。
これで全角英数地獄から解放されました。

## 追記
**発生条件発生条件が分かったため追記しています。情報を提供下さった@ToMapon5555さん、ありがとうございます！**

役に立ったと思った方は高評価・フォローをお願いします！
Next.js + Rive でBad Header, Problem loading file; may be corrupted と出た時にチェックすること

## 概要

https://zenn.dev/shota1995m/articles/shota1995m-rive-app

こちらを見てNext.jsのアプリにrivをぶち込んで見ようとした時、

```
app/pages.tsx
```

では普通にレンダーできていたRiveComponentが、

```
app/chat-history/[id]/page.tsx
```

で呼ぼうとすると


```
Bad Header, Problem loading file; may be corrupted!
```

というエラーになってしまいました。


## そもそものRiveComponentの呼び方
ミニマムなRiveComponentは

```RivGirl.tsx
import { useRive } from "@rive-app/react-canvas";

export const RivGirl = () => {
    const { RiveComponent } = useRive({
        src: "girl.riv",
        autoplay: true,
    });

    return (
        <div style={{ width: "500px", height: "500px" }}>
            <RiveComponent />
        </div>
    )
}
```

としていました。
このとき、`girl.riv` は
プロジェクトのルートに`public`フォルダを作り、
`public/girl.riv`　とすること。


## 解決策


```RivGirl.tsx
import { useRive } from "@rive-app/react-canvas";

export const RivGirl = () => {
    const { RiveComponent } = useRive({
        src: "/girl.riv",
        autoplay: true,
    });

    return (
        <div style={{ width: "500px", height: "500px" }}>
            <RiveComponent />
        </div>
    )
}
```

と、

`src: "girl.riv"`
から
`src: "/girl.riv"`

と / を入れる必要がありました。

https://nextjs.org/docs/app/building-your-application/optimizing/static-assets

この辺を見ていたときに/がないことに気づきました。


以上。
Adobe Fontsが表示されるときのカクつきをどうにかしたい！

## やりたいこと
- Adobe Fonts（ウェブフォント）の読み込み中/読み込み後でフォントが切り替わらないようにしたい！
​
## とりあえず一旦の解決方法
​
- 下記のスタイルを組み込み、読み込み中の際に表示されないようにしました。
​
```
.wf-loading {
    opacity: 0;
}
```
​
---
​
## 何が問題なのか？
​
- サイトに使用しているAdobe Fontsの「Kinto Sans」のfont-display設定が変更できないので、フォント読み込み中と読み込み後で大きく見た目が変わってしまう。
- Adobe Fontsのサイト側でWebプロジェクトで設定できるはずの`font-display`が反映されていないので設定できない。
​
## 期待していたこと
​
- Adobe Fontsには、webプロジェクトという画面でfont-displayの設定ができるので、そちらで設定した通りにフォントの読み込みができる。
- 設定値は下記リンクのように指定されています。これは、CSSのfont-display設定と同様となります。
​
https://helpx.adobe.com/jp/fonts/using/font-display-settings.html
​
- `font-display`については、こちらを参照。
​
https://developer.mozilla.org/ja/docs/Web/CSS/@font-face/font-display
​
![スクリーンショット 2023-07-30 22.19.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31662/da212386-cdbc-c110-7cca-789bb6a15b6a.png)
​
- 画像の右下の部分で、設定をします。
- 今回だと、フォント表示の設定を「block」にすることで、webフォントが読み込まれるまでの間、代替フォントが表示されず、テキストが表示されないようにしようとしていました。（この設定がアクセシビリティ的に良いかどうかは今回は考慮していません。）
​
- - -
​
- ちなみにGoogle Fontsのwebフォントはサイトで発行されるURLにオプションとしてfont-display: swapが初期で設定されていて、任意で変更可能です。
​
![スクリーンショット 2023-08-21 22.56.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31662/41553301-f397-9dd0-3983-f5fbfca8ea4c.png)
​
- こちらはGoogle Fonts側で書かれた、Webフォントの最適化について、なんとAdobe Fonts側ではどこで設定するかまで書いてあります（英語ですが）
​
![スクリーンショット 2023-11-10 11.14.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31662/349d2c62-662c-ebe5-7b47-e7b25166451a.png)

​
https://fonts.google.com/knowledge/using_type/using_web_fonts
​
 ## やったこと
​
- Adobe Fontsのフォント読み込みコードを追加したHTMLを確認すると、下記のclassがタグに挿入されていることがわかります。

​
| 状態 | クラス名 |
|:------------|:------------|
| Web フォントの読み込み中 |.wf-loading|
| Web フォントがアクティブな状態 |.wf-active|
| Web フォントが非アクティブな状態|.wf-inactive|

​
https://helpx.adobe.com/jp/fonts/using/font-events.html
​
- こちらを利用して、読み込み中のクラスに透過を設定して、表示されないようにしました。
​
```
.wf-loading {
    opacity: 0;
}
​
```
​
---
​
## 良い解決方法を情報募集中です
​
- とりあえず、目的通りに閲覧中にフォントが切り替わって見えないようにはできたのですが、もっと良い方法をご存知の方は、コメントなどで教えていただけると助かります！（願わくば、Adobe Fonts側で動作が修正されることを願っています）
Thoughtspotの日付フィルターの話

### 軽くプロフィール
初めてThoughtspotの記事書きます。需要があるかはわかりません。
Thoughtspot利用歴2年目、毎日「Thoughtspotちゃんがんばれ」と思いながら利用しております。


### 日付フィルターの日本語訳と実際に反映される期間
で本題。
今年のどの段階のアップデートでだったか忘れましたがThoughtspotで日付フィルターが「ローリング」と「固定」で選べるようになりました。
例として以下のような選択ができます。

　これ　年　→　今年（this year）　
　最後　年　→　去年（last year） 　
　次へ　年　→　来年（next year）

矢印の左側が画面上で選択する文言
矢印の右側が実際に反映されるフィルター内容です。
フィルターで選択できるようになって便利になりましたね。

<details><summary>（※本音）</summary>
 まぁ、ね、英語ちょっとやっていればなんとなくわかるけれども。
 でもユーザーから『日付指定するところに具体的な数字ではなく、「これ」「最後」「次へ」という選択肢がでております。ご確認いただけますでしょうか？』って問い合わせ来ちゃったし。
 伝わらない人には伝わらない。</details>


あと完全に分からなくてエンジニアさんに問い合わせて回答いただけたのがこちら。

　前週比　→　週初から今日まで の意味（Week to date）
　前月比　→　月初から今日まで の意味（Month to date）
　前四半期比　→　四半期初から今日まで の意味（Quarter to date）
　前年比　→　年初から今日まで の意味（Year to date）

 なので画面上で「前週比」を選択したら、「週初から今日まで」の期間で表示されるわけです。

<details><summary>（※本音）</summary>
 これは……わからんなぁ。
 Thoughtspotでの言語を英語設定しておけば「Week to date」で画面上表示されるのでわかるのだろうけれど、デフォルト日本語表示なので気づかなかったです。</details>


 ### 終わりに
 これは2023/11時点での記事です。
 今後のアップデートで日本語訳も良くなることに期待です。
 みなさんはThoughtspotのどのガバガバ日本語訳が好き？
 私はデータタブからのワークシート名検索で入力した名前がHITしなかったときに『そこでワークシートを求めてこられたわけです…』と表示されるのが好きです（好きとは）。
関西オープンフォーラム 2023で登壇しました #kof2023

2023年11月10日〜11日に大阪市で開催された[関西オープンフォーラム 2023](https://www.k-of.jp/2023/)で『[Python 3.12の新機能紹介](https://www.k-of.jp/2023/session/python-3-12/)』というタイトルで登壇してきました。
今回は[一般社団法人PyCon JP Associationの運営メンバー](https://www.pycon.jp/committee/members.html#ryuji-tsutsui)として行ってきました。
この記事では私の登壇に関する内容や雑感などを書きます。イベント全体のレポートは[PyCon JP Blog](https://pyconjp.blogspot.com/)の方に書くので、どうぞお楽しみ。

![IMG_1001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7809/8273e3e9-7b75-8349-8bf2-f071a979ac63.jpeg)

私の発表の資料は以下に置いておきました。
https://kof-2023-python312-slide.ryu22e.dev/

練習では5分ぐらい時間が余ったので大丈夫だろうと思っていたのですが、本番では時間が足りなくなってしまったため、最後の機能を紹介できませんでした。
50分の発表は初めてだったのでペースを把握するのが難しかったです。念のため時間が足りなくなった場合にスキップする部分を決めておいたのが役に立ちました。
Python 3.12の新機能はかなり数が多いのですが、今回紹介した機能を頭の片隅にでも置いていただいて、実際にPythonを使う際に役立ててもらえると幸いです。

関西オープンフォーラムは今回始めての参加でしたが、みなさんに暖かく迎えていただいて、楽しく過ごすことができました。来年もまた都合が合えば参加したいと思っています。ありがとうございました！
（下の写真はイベント後に大阪観光したときに撮ったものです）

![458AEC08-AFB0-45D7-AA0A-9640C102D52A.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7809/c028738d-d788-80ac-f2d1-8f1cbef350ac.jpeg)

![010B4959-EADA-40BB-A7BD-C646DC7A956B.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7809/23890bcb-f2b1-1a58-c0ca-d104ed1aaa91.jpeg)
FPGAデバイス間のトリガ通知（失敗談）

まだ私がルーキーだった頃(18年くらい前)に２つのFPGA間でトリガ通知に失敗した話を紹介します。

FPGA入門者の参考になれば幸いです。


# 当初実現したかったこと
FPGA１から１Cycleのパルスを出して、FPGA２のフラグをセットしたかったのです。

![01.dio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204268/940fbff8-6197-7343-a0c1-73675cf041ad.png)

DPGA経験者であれば、「そんな無茶しちゃアカンで！」と即座に突っ込みをいれてくれるでしょう・・・

# 現実に起こったこと

当たり前田のクラッカーですが、デバイスから出た基板上の信号はナマリます・・・
２つのFPGAは同じクロック周波数で動作させていて、クロックの位相差も出たとこ勝負でしたので、FLG信号は取れたり取れなかったり・・・
![02.dio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204268/46db1ff1-8445-86a6-9d3a-5a7e5725fd68.png)

# 解決策
で、解決策は下図の回路です。（解決策というか定石なのですが）

![03.dio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204268/39430d93-1183-c464-3d77-c1be8d1bd0de.png)

- 基板上の信号はナマる前提なので１ショットトリガでは無く、oTOGをTRGのイベント毎にトグルする様にします。
- 受け側にメタステーブル対策の２段FFを構えます
- 両エッジの微分回路（EX-ORの部分）で１ショットのパルスに直します
おい、orderByとページネーション組み合わせる時は気をつけろよ

## とある管理画面でバグが発生

- 書類を一覧表示する機能がある
- 書類は送信日というdate型のカラムを持っている。
- 書類を一覧表示する機能にはページャー機能が実装されている。


そこで、送信日順に並び替えようと、クエリに`orderBy`を追加した。

```php
Document::query()->orderBy('send_date')->paginate(10);
```
この際にバグが発生。どういうバグが発生したかと言うと、

ページャーを1(1件目~10件目)から2(11件目~20件目)に切り替えた際  
ページャーを切り替えるたびに新規でクエリを発行している為、ソートキーに指定したカラムのデータに重複があった場合、以前取得したデータが再度取得されてしまう現象だ。

## バグの内容

例えば、以下のようなテーブルが存在しているとする

| id  | 送信日        | 
| --- | ------------- | 
| 1   | 2023年11月1日 | 
| 2   | 2023年11月2日 | 
| 3   | 2023年11月1日 | 
| 4   | 2023年11月1日 | 
| 5   | 2023年11月1日 | 
| 6   | 2023年11月1日 | 
| 7   | 2023年11月1日 | 




日付順かつ1件目から3件目を要求し、以下のようなレコードが取得できたとする。


| id  | 送信日        | 
| --- | ------------- | 
| 1   | 2023年11月1日 | 
| 3   | 2023年11月1日 | 
| **4**   | 2023年11月1日 | 


次に4件目から6件目を要求した際


| id  | 送信日        | 
| --- | ------------- | 
| **4**   | 2023年11月1日 |
| 5   | 2023年11月1日 | 
| 6   | 2023年11月1日 | 

こういう結果が出るかもしれないという話。


```php
orderBy('send_date')
```

は、「日付順」である事だけをDBに保証させるのであって、同じ日付同士のレコード並び順は保証してくれないのである。  

この例の場合、1件目から3件目を要求した時の  
**「DBが思う最適な同日付のレコード群の並び順」**

と、4件目から6件目までを要求した時の  
**「DBが思う最適な同日付のレコード群の並び順」**
が違っているのである。

具体的に表現すると  
日付順で表示した際、11月1日と2日は明確にソートされる、しかし同一日のレコードは発行するクエリ次第でDBが並び順を決めてしまうのだ。

## 何が起きているか


1. わい「日付ソートした順の1件目から3件目までくれ」  
2. DB「ほらよ、idが1と3と4の奴あげるわ」  
3. わい「さんがつ」  
4. わい「次は4件目から6件目までくれ」  
5. DB「ほらよ、idが4と5と6の奴あげるわ」  
6. わい「ふぁ！？id4はさっきもらったけど！？」   
7. DB「は？日付順っていう縛り以外聞いてへんから同じ日付同士の並び順はわいが勝手に決めるやで、  
8. 1件目から3件目まで要求されたと2件目から4件目要求された時で、全体の同一日の並び方変えてんねん」  
9. わい「ふぁー、ほなid順っていう縛りも入れてやらんといけへんな」

### 2の時点のバックグラウンド
DB「まず日付順でソートするでー」

| id  | 送信日        | 
| --- | ------------- | 
| 1   | 2023年11月1日 | 
| 3   | 2023年11月1日 | 
| 4   | 2023年11月1日 | 
| 5   | 2023年11月1日 | 
| 6   | 2023年11月1日 | 
| 7   | 2023年11月1日 | 
| 2   | 2023年11月2日 | 

ほなこっから1件目から3件目を渡すか

| id  | 送信日        | 
| --- | ------------- | 
| 1   | 2023年11月1日 | 
| 3   | 2023年11月1日 | 
| 4   | 2023年11月1日 | 

### 5の時点のバックグラウンド

DB「まず日付順でソートするでー」

| id  | 送信日        | 
| --- | ------------- | 
| 7   | 2023年11月1日 |
| 1   | 2023年11月1日 | 
| 3   | 2023年11月1日 | 
| 4   | 2023年11月1日 | 
| 5   | 2023年11月1日 | 
| 6   | 2023年11月1日 | 
| 2   | 2023年11月2日 | 

 ほなこっから4件目から6件目まで渡すか
 
| id  | 送信日        | 
| --- | ------------- | 
 | 4   | 2023年11月1日 | 
| 5   | 2023年11月1日 | 
| 6   | 2023年11月1日 | 


## 結論
発行するクエリによって、DBが最適だと思う並び順は変動してしまうので、並び順を保証させたければ一意にな値をorderByに加えよう。
WSL2上でlsしても全てのファイルが表示されない問題 　(ls: reading directory '.': Input/output error)

# 問題
## 前提
Windows10に外付けしたNTFSフォーマットのドライブ。
BitLockerで暗号化済み。
D:\temp_filesは一時的なファイルを保管するディレクトリ。
Windows上では正常に認識されており、ファイル数・フォルダ数、合わせて1000以上あること確認済み。
ドライブの破損かと考えWindows上でchkdsk /fしても問題無い。

## 状況


```
WSL内で実行
PS C:\Users/user> wsl
root@win10:/mnt/c/Users/user# cd /mnt/d/temp_files

root@win10:/mnt/d/temp_files# ls -1 | wc -l

ls: reading directory '.': Input/output error
25
```
ダメです。


```
WSL外で実行
PS D:\temp_files> wsl ls -1 | wsl wc -l
ls: reading directory '.': Input/output error
24
```
これもダメです。

```
wsl --version

WSL バージョン: 1.2.5.0
カーネル バージョン: 5.15.90.1
WSLg バージョン: 1.0.51
MSRDC バージョン: 1.2.3770
Direct3D バージョン: 1.608.2-61064218
DXCore バージョン: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows バージョン: 10.0.19045.3324
```

### Dockerコンテナ内からも同様
```
/temp_data/temp_files # ls -1 | wc -l
25
```
ダメですね

# 原因
DrvFs上で扱えるファイル名, ディレクトリ名の最長は255 byteまで。
Linuxを含むUnix系共通の問題でした。

# 解決法
ファイル名を255 byte, 一般的な日本語(3 byte)のみだと85文字以下に抑える。
絵文字や難読漢字(4 byte)も含めるなら、63文字以下に抑える。

```
疑似コード
shrink_file_name.exe /d/temp_files/*.* -byte 255
# or
shrink_file_name.exe /d/temp_files/*.* -str 63
```

# 結果
全てのファイルの文字数を63文字以下に変更しました。
結果は

```
PS D:\temp_files> wsl ls -1 | wsl wc -l
1224
```

# Take Home Message
WSLを使う際は、Linux、Windowsの差異を認識し、ファイル名・パスの最大長に注意を払いましょう。

# 参考
> ファイル名の最大長の限界を、ストレージのフォーマットタイプごとに調べる
> https://takuya-1st.hatenablog.jp/entry/2021/08/31/103744
DLRS Too many SOQL query の考察


自動化処理でToo many SOQL queryが出た場合、対象のオブジェクトに単にフローだけしか自動化処理がなければ、そのフローの中をチェックすれば済む。ループの中でSOQLを使ってないかなど...

しかし、Apexトリガーや他のフローが設定されているとややこしい。同じオブジェクトに対するすべての自動化処理でのSOQLの合算が影響してくるので、全てを見直さないと回避できないですね。

また、今回みたいに自動化処理とDLRSが関連すると少々お手上げです。

+ [We are currently getting a 'too many SOQL query' exception in the opportunity flow when Salesforce Support have checked the debug logs they could see on the 'dlrs_OpportunityTrigger' that we are getting the 'too many soql query' error, and this trigger is having some dependencies which is from the andyinthecloud.com managed package dslr. What is the solution here?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Pw9Ee)


基本的には、この回答なんだろうと思う。

The best way is to split some or all into schedule mode. The tool does try to reuse queries between rollups, but with that number and likely variance in criteria (which prevents the query reuse from working effectively) its hard for its optimization to be completely successful in all honesty. 

最良の方法は、一部またはすべてをスケジュール モードに分割することです。このツールはロールアップ間でクエリを再利用しようとしますが、その数と条件の差異 (クエリの再利用が効果的に機能しない可能性がある) を考えると、正直に言って、最適化を完全に成功させるのは困難です。 

https://github.com/SFDO-Community/declarative-lookup-rollup-summaries/issues/629


何でも、DLRSの最近のバージョンでは、このエラーを解決するための改善が行われているらしい

更新バージョン 2.19 ：　https://install.salesforce.org/products/dlrs/latest

このエラーが発生しないことを保証するものではありませんが、DLRS が原因である最も一般的な原因は解決されます。環境内に他の自動化がある場合でも、DLRS が何度も呼び出される可能性があります。

同じオブジェクトまたはそれより上位のオブジェクトで、起動している可能性のある他のオートメーションまたはロールアップはありますか? デバッグ ログを調べて、どのようなクエリが実行されているかを報告することができましたか? (管理パッケージの詳細は表示されませんが、実行されている SOQL クエリは表示できます)

---------------------

提供された Apex デバッグ ログを確認し、Certinia (旧 FinancialForce) のこれまでにない素晴らしい Apex Log Analyzer を使用しています

https://marketplace.visualstudio.com/items?itemName=financialforce.lana

自分でファイルを開いて確認することをお勧めします。

画像を添付しました。「今年の正しい収益予算に商談室を更新」と「来年の正しい収益予算に商談室を更新」が交互に繰り返されるパターンが確認できます。これらの実行のそれぞれで、「一致する収益予算の検索」が実行されているようです。これにより、それぞれの「update_child_lookup」が実行され、商談関連ルームの DLRS が起動されます。このサイクルを何度も繰り返します。

一般的に、私の疑いは、フローの構築と実行方法に関する何かが多くの「レコード更新」タイプのフロー アクションを引き起こし、それが DLRS を繰り返し起動させる原因になっているのではないかということです。これらのフローを一括実行することを検討すると、大きなメリットが得られますが、私の意見では、それが問題の根本原因になると考えられます。

DLRS は、単に一連の最初の失敗にすぎないようです。DLRS をアップグレードすると、この事実が改善されると確信していますが、ログに見られるパターンは、フローの動作を変更しないと問題が発生することを示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/98dd7092-4219-7420-bd42-899ead5d5ad8.png)

新しいバージョンのDLRSでも発生するとのこと。


これは、複数のレコード処理の結果として発生しているようです。これはバッチデータの変更中または何らかの種類で発生しているのでしょうか?

**バッチサイズの削減を検討してください。**

一度にいくつかの更新を行っています。すべての変更を収集し、最終的に変更をデータベースに一度に送信するには、そのフローを最適化する必要があります。

Salesforce では、あなたが行っていることを「ループ内の DML」と呼んでおり、このトピックを研究することで、この問題を解決するのに十分な洞察が得られる可能性があります。

この問題を解決するために契約できるコンサルタントや経験豊富な友人に連絡できますか? 残念ながら、単に「いくつかの変更を加える」以上のことを期待しているのではないかと思います。これを解決する正しい方法を理解するには、プロセスを理解し、いくつかの代替案をテストするのに時間を費やす必要があるでしょう。

それでも、これがバッチ作業の結果として発生している場合は、バッチの速度を下げることが問題を隠す最も簡単な方法である可能性があります。
Gitのコマンド　よく使うものまとめました(確認用)

# はじめに
自分のメモ用としてまとめました。
初心者なので、間違っている部分などあれば、コメントで教えていただけると嬉しいです。

## clone(クローン)
リモートからクローンする
```sh
git clone [リポジトリURL]
```

## push(プッシュ)
ローカルリポジトリの変更をリモートリポジトリにプッシュする
```sh
git push origin master
```
git pushのあとの`origin master`というのはoriginというリモートリポジトリのmasterというブランチにプッシュするという意味です。

## merge(マージ)
```sh
git merge [統合したいブランチ名]
```


## git pull(プル)
リモートリポジトリから変更を取得してローカルリポジトリにマージするためのコマンド
```sh
git pull
```
## add(アッド)
ファイルをインデックスに追加するためのコマンド(ステージング)
```sh
git add .
```
`git add ファイル名`でファイルごとにインデックスに追加できる

## commit(コミット)
インデックスに追加された（ステージングされた）ファイルをローカルリポジトリにコミットするためのコマンド
```sh
git commit -m "XXを修正しました"
```

## branch(ブランチ)
作業を枝分かれさせて記録するもの
### ブランチの一覧を見る
```sh
git branch -a
```


### リモートブランチからローカルにブランチを作成
```sh
git branch [ブランチ名]
```

## checkout(チェックアウト)
別のブランチに移動するためのコマンド
```sh

```
M5StickV / MAiXの深層学習モデルkmodelを作成する


M5StickV/Maix1 シリーズの深層学習モデルのkmodelの作リ方について説明していきます。学習データkmodelのトレーニングは、Tensorflowをフレームワークとして使用します。sipeedからGitHubで提供されているmaix_trainのコードを使います。

maix_trainを使うと、２種類の機械学習のモデルを作成することができます。

・クラス分類（Mobilenet V1を使用）： 写真に写っている物体が何であるかを識別します。
・オブジェクト認識（YOLO V2を使用）： 写真に写っている物体を検出し、同時に座標とサイズを求めます。

## PC環境
構築手順に入る前に、まずPCに以下のバージョンのUbuntuをインストールした環境で、構築しました。

```
Ubuntu 22.04.3 LTS(x64)
```

## Minicondaのインストール

まず最初に、Minicondaをインストールして、Pythonの環境を作ります。
Minicondaのインストーラは、Minicondaのウェブサイトからダウンロードして取得します。


```
% wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
% sh Miniconda3-latest-Linux-x86_64.sh
```

Miniconda上で、pythonの仮想環境を作成します。

```
% conda create -n maix python=3.7
```

condaをアクティブ化します。condaのアクティブ化する作業は、シェル立ち上げるごとに必要です。condaは、隔離したPython環境を作成してくれるので、システムのPython環境を誤って変更することがなく、安心してプログラミングができます。

```
% conda activate maix
```

## maix_trainのダウンロード

sipeedからGitHubで提供されているmaix_trainのコードをダウンロードします。

```
% git clone https://github.com/sipeed/maix_train --recursive
% cd maix_train/
```

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

```
% pip install -r requirements.txt
% pip install pynvml matplotlib requests
```

一度、初期化を行います。

```
python3 train.py init
```


## 学習データ変換ツールnncaseをインストールする

nncaseは、KerasやTensorFlowで作成した学習データを、KPUの学習データkmodelへ変換します。Kendryteがリリースしており、GitHubからダウンロードできます。
nncaseは、CNNのMobileNetV1/V2やYOLOV1/YOLOV3をサポートしています。
kmodel作成には、nccaseはv0.1.0-rc5のバージョンを使います。

```
% cd maix_train/
% mkdir -p tools/ncc/ncc_v0.1/
% cd tools/ncc/ncc_v0.1/
% tar Jxf ncc-linux-x86_64.tar.xz
% wget https://github.com/kendryte/nncase/releases/download/v0.1.0-rc5/ncc-linux-x86_64.tar.xz
% tar Jxf ncc-linux-x86_64.tar.xz
```
nncaseのバージョンを確認します。

```
% ./ncc --version
ncc 1.0.0
```
nncaseは、コマンドの引数でオプションを設定します。

```
-i,--input-format	必須. 入力ファイルのフォーマットを指定します
-o,--output-format	必須. 出力ファイルのフォーマットを指定します
--dataset	必須. データセット（画像データ）のパスを指定します
--dataset-format	(Default: image) データセットのフォーマットです
--help	ヘルプを表示します
--version	Versionを表示します
 input (pos. 0)	オプション指定ない引数の0個目で、入力ファイルのpathを指定します
 output (pos. 1)	オプション指定ない引数の1個目で、出力ファイルのpathを指定します
```

## クラス分類（Mobilenet V1）の学習モデル作成 

データセットを準備します。画像サイズは224x224で、フォーマットはmaix_train/datasetsのデータセット例を参照してください。

```
python3 train.py -t classifier -z datasets/test_classifier_datasets.zip train
```
outフォルダにzipファイルが生成されます。

<img width=50% alt="report.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73020/07c98dde-dd59-089e-9914-713133f83958.jpeg">

#### エラーが出た場合の対処
 [Errno 2] No such file or directory: 'maix_train/out/datasets/images/1/xxx.jpg'
エラーが出る場合、出力フォルダに画像をコピーします。

```
cp ./datasets/
nzip test_classifier_datasets.zip 
cp -r datasets/images/ ./out/datasets/
```

## オブジェクト認識（YOLO V2を使用）の学習モデル作成 

```
python3 train.py -t detector -z datasets/test_detector_xml_format.zip train
```

MaixhubやV-Trainで学習したモデルと同様に、outフォルダに結果を含むzipファイルが生成されます。ファイルをSDカードのルートディレクトリにコピーし、M5StickVの電源を入れて実行します。


## 参考資料
[Sipeed Wiki:Local model training](https://wiki.sipeed.com/soft/maixpy/en/course/ai/train/local.html)
https://wiki.sipeed.com/soft/maixpy/en/course/ai/train/local.html

[maix_train](https://github.com/sipeed/maix_train)
https://github.com/sipeed/maix_train
Pardot : Sandboxのまとめ

[Pardotの質問と回答をまとめに戻る](https://qiita.com/Keiji_otsubo/items/a3ccd1370697dd914723)

-----------------

+ [アイデア実現：sandboxからデプロイできる](https://ideas.salesforce.com/s/idea/a0B8W00000H6SsG/introduce-ability-to-deploy-from-pardot-sandboxes)

:::note
サンドボックスから本番環境への展開には、変更セット機能が必要です。これにより、時間の節約になり、間違いを回避できます。
:::

+ [Pardot の導入方法](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000PfDpg)

:::note
現在のソリューションは 2024 年 10 月にリリースされます。  

アカウントエンゲージメントサンドボックスから本番環境へのインストール手順 

[Salesforce ヘルプ | 記事](https://help.salesforce.com/s/articleView?id=000396734&type=1)

Salesforce には、環境間で MCAE (Pardot) アセットをコピーするのに役立つ複数のフローが存在するようになりました。 
:::

-------------

+ [Pardot サンドボックスのセットアップ](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V000077k4Iq)

:::note
Please check this article.

https://help.salesforce.com/s/articleView?id=000380418&type=1
:::


+ [アカウント エンゲージメント キャンペーンがサンドボックスに表示されない](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007OrOnI)

:::note
Pardot Sandboxes are blank slate. They need to be rebuilt fully after every refresh. We also need those campaigns in the CRM sandbox which we may or may not get depending on what sandbox type is being used.

Pardot サンドボックスは白紙の状態です。更新するたびに完全に再構築する必要があります。CRM サンドボックスにもこれらのキャンペーンが必要ですが、使用されているサンドボックスの種類に応じて取得できる場合と取得できない場合があります。
:::

+ [Pardot Deployment Method](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000PfDpg)

:::note
Looks like this is still an idea:

Introduce ability to deploy from Pardot Sandboxes
https://ideas.salesforce.com/s/idea/a0B8W00000H6SsGUAV/introduce-ability-to-deploy-from-pardot-sandboxes
:::

# ビジネスユニット

+ [アカウントエンゲージメント: サンドボックス更新後にビジネスユニットが消えた](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Yw312)

:::note
Every Pardot (AE) accounts are unique be it a sandbox or multiple business units tied to a same SF org. So yes, the organization ID will differ.

サンドボックスであっても、同じ SF 組織に関連付けられた複数のビジネスユニットであっても、すべての Pardot (AE) アカウントは一意です。はい、組織 ID は異なります。そして、移動に関しては手動で行う必要があると思います。

Salesforce サンドボックスが更新されると、対応する Pardot サンドボックス ビジネスユニット (BU) もアーカイブ/削除される必要があります。 

https://issues.salesforce.com/issue/a028c00000gAyuJAAS/salesforce-sandbox-refresh-does-not-always-archive-the-corresponding-pardot-sandbox-business-unit
:::

# Sandboxにインストールする前に、最初にPardotを本番環境にインストールする必要がありますか？

[Should I first install Pardot on production before I do on Sandbox?](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000A8o8sSAB)

:::note
I open support case on Salesforce and I got responce and successfully fixed the issue.

Problem was that unmatch of license between Sandbox and Production since Sandbox was created before provisioning of Pardot license.

"Match Production Licenses to Sandbox without a Refresh" solved the issue !!

https://help.salesforce.com/articleView?siteLang=en_us&id=000335272&type=1&mode=1

Salesforce でサポート ケースを開くと応答があり、問題は正常に解決されました。

問題は、Pardot ライセンスのプロビジョニング前にサンドボックスが作成されたため、サンドボックスと本番環境の間でライセンスが一致しないことでした。

「更新せずに本番ライセンスをサンドボックスに一致させる」で問題が解決されました。
:::