OmniAICreator/Qiita-1.07M huggingface dataset:
受託開発でアジャイルを成功させるためのクライアントフェイシングテクニック

## はじめに

受託開発においては、ソフトウェア開発に詳しくないクライアントと協働することが多々あります。本記事では、そのような状況下でアジャイル開発を成功に導くための効果的なクライアントフェイシングテクニックを紹介します。

## 受託開発におけるクライアントの特徴と課題

受託開発では、クライアントがソフトウェア開発に関する知見を持っていないことが一般的です。そのため、以下のような特徴や課題が見られます。

1. ウォーターフォールで進めても、後になって頻繁に変更要求が発生する一方で、納期は守るよう要求される。
2. 技術的な説明に興味を示さず、後になって不満を訴えてくる。
3. 予算に見合わない夢を持ち、ユーザーのニーズを見落としがちである。
4. 市場に対する様々なコミットメントを抱えており、ステークホルダーからの要望による要件変更が発生しやすい。

これらの特徴や課題から、プロジェクトの遅延、赤字、プロダクトの品質低下など、関係者全員が不幸な結果に陥るリスクがあります。

## アジャイル開発で臨む際の注意点

上記の課題を乗り越え、アジャイル開発を成功に導くためには、以下の注意点に留意する必要があります。

### 1. 多段階契約の実現

プロジェクトを複数のフェーズに分けて契約を結ぶことで、各フェーズでアジャイル開発を実施し、初期のローンチに向けた開発を円滑に進められます。初期フェーズでは以下の項目を定義することをお勧めします。

- カスタマージャーニーマップ
- プロダクトロードマップ
- ビジネスモデル
- 収益構造
- ユーザーストーリー

これにより、プロダクトの全体像を明確化し、クライアントと認識を合わせることができます。特にユーザーストーリーについては、初期の想定ストーリーとポイントを記載し、次フェーズ以降の概算工数として活用できます。

#### 1.1. 現実的な目標設定

多段階契約を結ぶ際、予算と工数が合わないことが判明した場合、プロジェクトの断念も視野に入れる必要があります。クライアントの夢と現実のギャップを明らかにし、実現可能な目標を設定することが重要です。クライアントの期待をマネジメントし、現実的な計画を立てることで、プロジェクトの成功確率が高まります。

#### 1.2. 試作フェーズの導入

技術的な難易度が高い要求や機能ボリュームが多い場合、完成品がイメージと異なるリスクがあります。このリスクを軽減するために、マイルストーンに試作的なフェーズを組み込むことをお勧めします。試作フェーズでは、クライアントとベンダー双方が機能や設計についての理解を深め、修正点を早期に発見できます。この取り組みにより、クライアントの満足度が高まり、無駄な手戻りを防ぐことができます。

### 2. アジャイル開発を行える体制の整備

クライアントにアジャイル開発の知見がない場合、プロジェクトマネージャーの言うことを迎合してしまうリスクがあります。これを防ぐために、クライアントであるプロダクトオーナー（PO）に対する教育を実施し、模擬的なイテレーションやスプリント会議を通じて、プロダクトを発展させる仕組みを整えましょう。繰り返しスプリントを行いながらプロダクトを改善していく点についても、クライアントの理解を得ることが大切です。

### 3. 生産性と残作業工数の数値化

ストーリーポイントやベロシティをスプリント会議で視覚化することで、マイルストーンまでの残作業ボリュームや生産性を逆算して見積もることができます。機能追加や修正依頼によりマイルストーンまでに終わらない見込みとなった場合、追加予算の請求も可能になります。ただし、自分たちの不手際によるフィードバックの増加ややり直しについては請求できないため、受け入れ条件をクライアントと確実に握っておく必要があります。

### 4. 頻繁かつ透明性のあるコミュニケーション

アジャイル開発では、クライアントとの頻繁で透明性のあるコミュニケーションが欠かせません。定期的なスプリントレビューやデモを通じて、プロダクトの進捗状況や課題を共有し、クライアントからのフィードバックを得ることが重要です。また、バーンダウンチャートなどの可視化ツールを活用し、プロジェクトの状況をわかりやすく伝えることも効果的でしょう。

### 5. 信頼関係の構築

クライアントとの信頼関係は、アジャイル開発を成功に導く上で非常に重要です。クライアントの懸念事項に真摯に耳を傾け、適切なソリューションを提案することで、信頼関係を築いていきましょう。また、クライアントの意思決定プロセスを理解し、適切なタイミングでの情報提供や助言を行うことも大切です。

### 6. 技術面の理解促進

クライアントが技術面に興味を示さない場合でも、プロダクトの品質や開発の効率化に直結する重要な事項については、わかりやすく説明することが必要です。以下のような工夫を行うことで、クライアントの技術面への理解を深めることができます。

- 技術的な概念をビジネス上の利点と関連付けて説明する
- ビジュアルエイドやメタファーを用いて、複雑な概念をシンプルに伝える
- クライアントの関心事に沿った事例や実例を示す
- 技術的な意思決定が及ぼす影響について、具体的なシナリオを用いて説明する

クライアントが技術面の重要性を理解することで、より適切な意思決定が可能となり、プロジェクトの成功確率が高まります。

## まとめ

受託開発でアジャイル開発を成功させるためには、クライアントの特徴や課題を理解し、多段階契約の実現、現実的な目標設定、試作フェーズの導入、体制の整備、生産性と残作業工数の数値化、頻繁かつ透明性のあるコミュニケーション、信頼関係の構築、そして技術面の理解促進に注力することが重要です。これらのテクニックを活用することで、クライアントとの円滑なコミュニケーションを図り、プロジェクトの成功に導くことができるでしょう。アジャイル開発の適切な実践により、クライアントとベンダー双方にとって満足度の高いプロダクト開発が実現できます。
【SQLServer】フルテキストインデックス構築の進捗確認方法

# 背景

フルテキスト検索を利用するシステムの移行において、移行したデータベースに対してフルテキストインデックスの再構築が必要になった。

GUIからの操作ではインデックス再構築の進捗が見えないため、進捗を確認するための方法が必要になった

# そもそもフルテキスト検索とは何なのか

インデックスを設定した列の語句について、特定の言語でテキスト検索できる

LIKE句での検索と比べて高速、かつバイナリ列のドキュメントの中身をキーワード検索できる

参考：[フルテキスト検索 - SQL Server | Microsoft Learn](https://learn.microsoft.com/ja-jp/sql/relational-databases/search/full-text-search?view=sql-server-ver16)

# 手順

以下のSQLを実行する

［出力項目］
- インデックス項目：フルテキストカタログに含まれるテーブルのキーなどの項目数を出力する
- ステータス：インデックスカタログのステータス（0:アイドル状態　1:カタログ作成中）

［終了条件］
- インデックス項目数が作成対象の項目数と一致している
- ステータスが0になっている

```進捗確認.sql
SELECT fulltextcatalogproperty('フルテキストカタログ名', 'ItemCount') as 'インデックス項目数';  
SELECT fulltextcatalogproperty('フルテキストカタログ名','PopulateStatus') as 'ステータス' -- 0：作成完了、1：作成中
```

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/da8b5a4e-3b75-8558-13dc-a125558fc415.png)

# 参考

- [FULLTEXTCATALOGPROPERTY (Transact-SQL) - SQL Server | Microsoft Learn](https://learn.microsoft.com/ja-jp/sql/t-sql/functions/fulltextcatalogproperty-transact-sql?view=sql-server-ver16)
ポートフォリオを作ってみた(5)

# 公開
以下の流れで説明をしていきます。今回は最後の(6)公開になります。
(1)環境説明
(2)ドメイン作成
(3)サーバー構築
(4)デザイン検討
(5)コーディング
(6)公開

公開場所は(3)で用意したCloudFlareのPagesになります。
Framework別の手順は[ここ](https://developers.cloudflare.com/pages/framework-guides/deploy-a-blazor-site/#create-the-build-script)にあります。

## Blazor(dotnet core)の場合の公開手順
(1) まずは[Cloud Flare](https://dash.cloudflare.com/)にアクセスします。
(2) 「Workers & Pages」をクリックします。
![](https://storage.googleapis.com/zenn-user-upload/f40f4c99c0ce-20240329.png)
(3) 「Create application」-> 「Pages」-> 「Connect to Git(Gitに接続)」をクリックします。
![](https://storage.googleapis.com/zenn-user-upload/8a861613f482-20240329.png)
(4) Githubアカウント、レポジトリを選択して「Begin Setup(セットアップの開始)」をクリックします。
![](https://storage.googleapis.com/zenn-user-upload/e3e8485ba270-20240329.png)
(5) ビルドとデプロイのセットアップでプロジェクト名を入力して、デプロイ対象のブランチを選択し、「Save and Deploy(保存してデプロイ)」をクリックします。
→ビルド設定は[ここ](https://developers.cloudflare.com/pages/framework-guides/deploy-a-blazor-site/)を参考にして、該当Frameworkに合わせた設定を行います。
(6) デプロイが完了するとアプリケーションの公開まで完了します。
→筆者の環境(Blazor)では、2回目以降、CustomDomainのURLについてはCSSの更新は遅延することがあるようです。
slide共有サイトが直接見られない場合の SSSSlide 利用の為のブックマークレット

# 背景

Data Loss Policy などで、投稿共有サイトへのアクセスが閉じられていることがあります。
閲覧だけは解禁してよって思うわけですが、以下サイトを介して閲覧可能だったりします。
とはいえ、禁止されていた場合に、URL修正が面倒なのでそれ用のブックマークレットの備忘録

https://sssslide.com/

ほんと、ありがとうございます

# 結論

以下をブックマークレットに登録するだけ

```javascript: view through sssslide
javascript:(function(){
  if (location.href.startsWith("chrome-error")) {
    let value = prompt("input URL to view via SSSSLIDE");
    location.href = 'https://sssslide.com/' + value;
  } else {
    location.href = 'https://sssslide.com/' + location.href;
  }
})();
```

# あとがき

以下に追加しようと思ったら、Title が 365 だった・・。業務用ブックマークレットでよかったような・・ :(

https://qiita.com/baku2san/items/ac02be7157d62f4b78da
日本語LLMのファインチューニング用データの作成方法について

昨日weights＆biases（Wandbの会社）が開催した日本語LLMのミートアップに参加しました。⇩
![03fc2672ab912f38a32b50277411521.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/092e1a47-68c6-8c8a-1450-4abed784d133.jpeg)

今回のトピックは非常に面白い内容で、日本語LLMをチューニングするために学習データをどのように準備するかを教えてもらいました。（これは多くの人が悩む問題だと思います）

現時点では、大きく分けて4つの手法があるそうです。


①翻訳ツール (Google、DeepL) で海外のデータセットを翻訳して使う
この方法では比較的簡単にデータを作成できますが、翻訳の質によっては誤りが含まれていたり、品質が低かったりするデータも多いです。そのため、翻訳されたデータの中から品質を評価する指標を作り、品質の高いデータだけを残して使用します。その結果、700件の高品質データでトレーニングされたモデルは、元の50,000件のデータでトレーニングされたモデルよりも性能が高かったです。(この品質を評価する指標の作り方は、データの有無によって精度がどの程度変化するかを比較ことで影響度を逆算し、プラスの影響度が高いデータを品質の高いデータと定義します)

②LLMで生成
こちらについては、基本的な方法に加えて、2つの最新手法についても紹介がありました。
一つはMicrosoftが公開した "GLAN" という手法です。まず、GPT-4を使って人間の知識を網羅的かつ非常に細かく木構造で表現し、それを参考に各項目ごとにinstructionデータを生成させる方法です。

もう一つは、AppleのWRAPという手法です。これは、LLMを活用してデータをクリーニングする方法で、品質の低いデータを特定し、それを再生成することでデータセットを拡張するものです。

![d282ff21f69a43185ddb421006454cd.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/b864a46c-8bc5-baf3-523c-e74396f12c98.jpeg)

③既存データの活用
IPA試験の過去問題や官公庁が公開された高品質なデータをメインで活用しています。
講演者の方は、”J-ResearchCorpus”という日本語論文で構成されたデータも作成中です。


④人力で作成
ここからは ichikaraデータセットの話になります。
このデータセットは非常に高品質な日本語データで、かなり複雑な手順で生成されています。(1万件で2,000万円かかったそうで、日本語教授の方とかから作ってもらった感じです。)
詳細は⇩の論文にも記載されています。

https://www.anlp.jp/proceedings/annual_meeting/2024/pdf_dir/A6-3.pdf

![94b670ff06db311ccd4e51f29a3daa7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/a96bce97-5737-a7f7-f976-5e3c1efa1c5c.jpeg)
![eaaa83fc7ee0a181e94b57ee1a3144e.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/c615d6a6-7f6c-5b24-028c-8dfcb7867c92.jpeg)


ちなみに、このデータセットは1,500万円で販売されています。（高いですがもう18社へ売れました）

その後は、最近のLLMファインチューニングに関する発見についても共有されました。ちょうど数日前の発見ですが、モデルのハルシネーションの8割は固有表現（人名、時間とか）が多い問題に発生する傾向がありました。なので、固有表現を含まない1,000件ほどのデータでファインチューニングを行うと、精度が大幅に向上し、以前は間違えていた質問にも正しく回答できるようになったです。

wandbについて：

https://www.wandb.jp/
DocFX（C#のXMLコメントをドキュメント化）へプライベートメソッドも出力する方法

## 使い方手順

### 作業フォルダ作成
```docfx.exe init -q -o DocFXTest```
多くの参考サイトで初期設定として、作業フォルダを作成する上記のコマンドが記載されていますが、
3.X系以降では、`-q`オプションが廃止になっているようで、
`Unknown option 'q'`というエラーがでます。

上記コマンドが使える2.X系は以下のリンクから取得できました。
https://github.com/dotnet/docfx/releases/tag/v2.59.2

参考

https://stackoverflow.com/questions/71475156/docfx-failing-on-init-command

### ドキュメント生成
1. 初期設定により出力されたDocFXTest/src配下へ、ドキュメント化したいC#プロジェクトとC#ソースファイルを配置
2. DocFXTest/src配下で次のコマンド実行 `../docfx.exe metadata`
3. DocFXTest/src配下で次のコマンド実行 `../docfx.exe build`
4. `_site`フォルダが作成される
5. `../docfx.exe serve`でドキュメントのサーバーが`http://localhost:8080`へ起動
6. HTMLファイルのローカルの実体の場所は、`_site/api`配下

### プライベートメソッドも出力する方法
また、デフォルトのままでドキュメントを作成するとプライベートメソッドが出力されない。
APIとして公開しないからドキュメント化は不要という考え方らしい。
（むしろ、プライベートメソッドの方をドキュメント化したかったのに！）


1. 作業フォルダ内（docfx.jsonの並び）に以下のファイルを作成
ドキュメントの作成をするクラス名を適宜記載。

```yml: filterConfig.yml
apiRules:
- include:
  uidRegex: ^{Namespace名}\.Internal\.{クラス名１}$
  uidRegex: ^{Namespace名}\.Internal\.{クラス名２}$
  uidRegex: ^{Namespace名}\.Internal\.{クラス名３}$
  type: Class
```

2. 作業フォルダ内にある`docfx.json`を以下の変更
- `filter` を`filterConfig.yml`
- `disableDefaultFilter`を`true`

```docfx.json
  "metadata": [
    {
      "src": [
        {
          "files": ["**/*.csproj"],
          "exclude": [ "**/bin/**", "**/obj/**" ],
          "src": "../src"
        }
      ],
      "filter": "filterConfig.yml",
      "disableDefaultFilter": true
    }
```




これで同様に
1. DocFXTest/src配下で次のコマンド実行 `../docfx.exe metadata`
2. DocFXTest/src配下で次のコマンド実行 `../docfx.exe build`


とすることで、プライベートメソッドも含まれたドキュメントが出力される。

参考

https://github.com/dotnet/docfx/issues/2561
Disocrd.js 主要権限名

# Discord.js v14のメンバーの主要権限名
d.jsで、メンバーが所持している権限の確認するなどの際に使用する権限名を書いていきますが、すべての権限を書いているわけではありません。

:::note warn
Disocrd.js v14で動作します。その他のバージョンでは動作はしない可能性があります。
:::
##
### サーバーでの権限 
- ADMINISTRATOR: サーバー全権限（管理者）
- KICK_MEMBERS: メンバーのキック権限
- BAN_MEMBERS: メンバーのBAN権限
- CREATE_INSTANT_INVITE: 招待リンクの作成権限

### テキストチャンネルでの権限
- VIEW_CHANNEL: チャンネルの閲覧権限
- SEND_MESSAGES: メッセージの送信権限
- MANAGE_MESSAGES: メッセージの管理権限
- MENTION_EVERYONE: everyoneメンションの送信権限

### ボイスチャンネルでの権限
- CONNECT: ボイスチャンネルへの接続権限
- SPEAK: ボイスチャンネルでの発言権限
- MUTE_MEMBERS: メンバーのミュート実行権限
- DEAFEN_MEMBERS: メンバーのスピーカーミュート実行権限

### その他
- CHANGE_NICKNAME: 自分のニックネームの変更権限
- MANAGE_NICKNAMES: 他のメンバーのニックネームの管理権限
- MANAGE_EMOJIS: サーバー絵文字の追加や削除権限
- MANAGE_WEBHOOKS: ウェブフックの管理権限

## 最後に
権限名で、権限を持っているかどうかを調べるのは以下のコードでできます。
```js:index.js
console.log(member.permissions.has('権限名'))
//権限を持っている場合はtrueをかえすます
```
【MSAL】TypeError: Cannot read properties of undefined (reading 'endsWith')の解決策

# 最初に

今回のエラーは、msalを利用してMicrosot EntraIDでログイン、ログアウト機能を実装し、本番環境にデプロイしようとしたときに起きたエラーです。
node_modulesの中の@msal-commonのAuthority.tsで起きたエラーだったので、認証関係のエラーかと疑い、フロントエンド側をデプロイしているAzure static appsにAzure portalから環境変数を格納するも、うまくいきませんでした。
また、msal-reactとmsal-browserを最新にしても、エラーは消えませんでした。

# 環境
・Windows
・react 18.2.0
・typescript 4.9.5
・@azure/msal-react 2.0.13
・@azure/msal-browser 3.11.0

# 解決策

結論から言うと、GitHubActionsに環境変数を書くことでエラーは解決しました！

```
- name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_BRAVE_HILL_07856D300 }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
          action: "upload"
          app_location: "Frontend" # App source code path
          api_location: "Backend" # Api source code path - optional
          output_location: "build" # Built app content directory - optional
        env: # Add environment variables here
            REACT_APP_CLIENT_ID:***************
            REACT_APP_AUTHORITY: https://login.microsoftonline.com/***********
            REACT_APP_REDIRECT_URI: https://**********.net/
            REACT_APP_SCOPES: api:*********/api.scope
```
環境変数は自分のものと置き換えてください。
Azure Deveopsを使う場合は、Azure pipelineのymlファイルに同じように書けば環境変数が読み込まれ、エラーは消えます。

# 感想

node_modules内のエラーだったので、最初はubuntu-latestのデフォルトのnodeが16なので古いのが原因かなと思いましたが、原因は環境変数がきちんと読み込まれていないことでした。
このエラーの情報は少なく、とても解決まで時間がかかりましたが、最後に解決できてよかったです。
みなさんも、デプロイの時は環境変数の読み込み方法にご注意ください！
【ChatGPT＋DALL-E3】だけじゃない。X-Twitterで画像の企画しました的な内容です。


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

　今回は、X-Twitterで企画しました的な内容です。みなさんもX-Twitterのアカウントがあるならば、参加して欲しいかなぁ、という気持ちでの記事？になります。

:::note info
本記事は、ChatGPT（有料版）
＋DALL-E3で行なっております。
画像はあります。　あしからず。
:::
　今日の東京は
　　ひどい暴風雨。
　　　片頭痛や花粉症が
　　　　いつもよりひどい人は
　　　　　低気圧のせいだとか。
　　　　　　お互い頑張りましょう。
***
　さて、まずは、
　　ニュースというか、
　　　話題ですねw

　昨日一昨日くらいから
　　X-Twitter上で話題になっている
　　　動画があります。
[動画](https://twitter.com/masahirochaen/status/1773474756119171227?t=H9vSsgx91jvj-Fyy7j-B1w&s=19)

　男性が歩きながら
　　何かを説明している姿が
　　　映されています。

　実はこれ、
　　すべてが
　　　生成AIによる
　　　　動画だと言うのです。

　どこにも破綻が見られず、
　　本当の人物を撮影しただけでは？
　　　なんていう発言も見られます。

　これは、
　　動画生成AI「HeyGen」に
　　　追加された新機能
　　　「 Avatar in Motion 1.0」による
　　　　　ものだそうです。

　こんなに自然に
　　動画が作れるなんて
　　　驚きですね。

　こちらは
　　OpenAIのSoraとは
　　　考え方が違うのでは、と
　　　　私は思っています。

　わかりませんけどねw
***
　さて、
　　本題です。

　今回は、
　　X-Twitter上で、
　　　企画を立てました。
　　　　その話になります。

　企画を立てるのは、
　　これで三度目か四度目です。

　今までほ
　　フォロワー数が
　　　一定数に達したお祝いに
　　　　やるような催しでした。

　ゴルフコンペで
　　ホールインワン
　　　しちゃった気分です。
　　　　（わからなくてもいいですw）

　でも今回からは
　　単なる企画にしました。

　理由は、
　　“おめでとう”の花束画像が
　　　たくさん届けられるからです。
　　　　それが目的な人もいますし、
　　　　　中には使いまわしの人も
　　　　　　います。
　　　　　　　それらに対応するのが
　　　　　　　　結構大変。
　　　　　　　　　ありがたいが……
***
　まぁ、
　　理由はともあれ、
　　　企画を立てます。
　　　　（記事を書いている
　　　　　　時点ではまだまだ）

　よかったら
　　X-Twitterのアカウントがある
　　　みなさんも、参加して
　　　　欲しいかなぁ、という
　　　　　気持ちでの記事？に
　　　　　　なります。

　別に参加しても
　　何もあげません。
　　　スポンサーがいませんので😅

　勝ち負けではなく、
　　新たな画像が見たい、という
　　　ただそれだけです。
　　　　いや、あとで使いたい、
　　　　　というのもありますけどw

　参加希望の方は
　　X-Twitterへのリンクを
　　　載せますので、
　　　　そちらをどうぞ。
[参加募集のお知らせ](https://twitter.com/kabumira862571/status/1773542484527693865?t=nV569BmH6QtX-mgTkX6hjw&s=19)
　この画像のポストです。
![1711681069710.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/2772cc36-a117-024c-d46b-0626a4b686e7.jpeg)


　また、
　　X-Twitterの私のアカウントは
　　　カーブミラー@kabumira862571
　　　　になります。

　“カーブミラー”で検索すると
　　たくさんのカーブミラーが
　　　出てきます。もちろん、本物がw
***
　企画内容を
　　書きますね。

　テーマ
　　『#AIファッション雑誌を飾ろう』

　期間
　　今週の金土日の３日間
　　　（2024/03/29〜2024/03/31）

　締め切り
　　2024/03/31の24時

　応募方法
　　上記の『参加募集のお知らせ』を
　　　参照してください。

　具体的な
　　注意事項も
　　　載せてありますので。

　みなさんの
　　ファッション知識が
　　　欲しいですね。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
　　お待ちしています🙋
ZED SDKについての情報源

# 想定する読者
stereolabsのzed2, zed mini, zed x などのステレオカメラの利用者
いまどきのステレオカメラは何ができるのかを知りたい人

# 前提
ZED SDK 4.0
Ubuntu 20.04
ZED2i
Python 版のAPI

# わからないところが出てきたら
- [Stereolabs Forums](https://community.stereolabs.com/)
- [github zed-sdk/Issues](https://github.com/stereolabs/zed-sdk/issues)

- 上記の情報源もたどってみてください。
- 同じ質問を持っている人はきっといると思います。
- 私の場合は、[ZED SDK を使いこなす inspectでデータ構造を理解する](https://qiita.com/nonbiri15/items/72d95f4cd3218925b27d) に書いたアプローチで探っています。
- 動いているサンプルコードは、最大のヒント。
    - Pythonの統合環境の中で、関数、メソッドやEnumで検索をする。
    - そうすればどういう使い方をするのかを見つけられる。

----
【しくじり】AWS認定試験　日程変更後は認定アカウントを必ず確認しよう

##  これは何
AWS認定アカウント(CertMetrics)上で受験日程を変更したつもりが出来ておらず、当初の日程で受験するはめになった人間の戒め・備忘録のための記事です。

## 結論
AWS認定試験において受験日程を変更した際は、以下を必ず確認しましょう。
 - 変更完了の確認メールが来ているか
    こちらのメールの受信をもって変更手続きの完了となるそうです。
    
 - 認定アカウント上の試験日程が変更後のものになっているか
    EXAM REGISTRATION > Schedule an exam を開き、Upcoming examsに変更後の日程が記載されていればOKです。
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758619/bf3ce91b-62ff-4ccc-38b4-6224e28e2670.png)

- 変更後の試験日程の数日前にピアソンVUEからメールが届くか
  試験前にはピアソンVUEから「ピアソン VUE 試験予約内容のご案内」というタイトルでリマインダーメールが届きます。
  今回は3/23が試験日のため、3/20にメールが届きました。
  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758619/8a916d18-e529-d451-5cdc-09d18c90d48c.png)

上記のいずれかが当てはまらない場合、**試験日程がきちんと変更されていない可能性があります。** 
必ずピアソンVUEに確認しましょう。

## 今回の出来事(時系列)
 - 1月末に、DVA-C02の試験を**3/23**で予約。
 
 - 2月末頃、思いのほか問題集や模擬試験の正答率が良いので「もう少し早めに受けてもいいかも」と思い、試験日程を**3/23**から**3/16の午後**に変更。

 - 当日(3/16)の午前、テストセンターの場所を確認するためにAWS認定アカウントにログイン
 - EXAM REGISTRATION > Schedule an exam を開いたところ… **Upcoming examsに記載されている日程が3/16ではなく3/23になっているのを発見**
 - すぐに[ピアソンVUEのカスタマーセンター](https://www.pearsonvue.co.jp/Test-takers/Customer-service.aspx)に問い合わせようとするも、土曜日だったため電話は繋がらず、お問い合わせフォームから連絡。
   3/23から3/16に試験日程を変更したこと、変更後や試験前日にピアソンVUEからメールが特に来ていないこと、ピアソンVUE上では試験日程が3/23のままなのか、という旨を送信。

 - ピアソンVUEから連絡。返信には2~3営業日かかるとのことでしたが、土曜日に送って月曜日の午前中に返信が来ました(ありがたい)。内容はというと、
  
	> お問い合わせの件についてでございますが、
	> お調べしましたが以下ご予約の変更は確認出来ませんでした。
	> 
	> 試験名：DVA-C02
	> 会場：**********
	> 日時：3月23日 10:00
	> 登録番号：**********
	> 
	> つきましては、恐れ入りますが上記日程での受験をお願いいたします。
	> 
	> なお、予約変更を完了した場合、以下のようにアクセス履歴が残ります。
	> ーーーーーーーーーーーーーーーーーーーーーーー
	> ①ダッシュボード
	> ②予約の詳細
	> ③新しい予約の検索
	> ④カート
	> ⑤ポリシーに同意する
	> ⑥内容を確認して下さい
	> ⑦もう少しで完了です
	> ⑧再予約されました
	> ーーーーーーーーーーーーーーーーーーーーーーー
	> 変更後の予約時間が表示された後も、確認と確定を終えるまでは、試験の変更は反映されません。
	> 
	> 
	> 日程変更が完了いたしますと、直後に変更完了の確認メールが送信され、こちらのメールの受信をもって変更手続きの完了となります。
	> 
	> 
	> 以降試験日を延長する機会のある際は、ご注意ください。

 とのことでした。

 結局、当初の日程である3/23に受験しました。スコア740でギリギリ受かりました。
 今回は幸運にも、試験日と他の予定が被っていなかったため受験できました。当初よりも前の日程に変更するというケースだったのも不幸中の幸いです。
これがもし後の日程に変更するケースだった場合、日程変更したつもりで出来ておらず、気付くのが遅ければ**試験をすっぽかす**はめになっていました。当然、受験料は戻ってきません。

## まとめ
試験を受ける際、AWS認定アカウントはこまめに確認しましょう。
CRDの反映で invalid: status.storedVersions になった時の対処法

CRDを反映した時に以下のようなエラーになった時の対処方法
```sh
The CustomResourceDefinition "foo.bar" is invalid: status.storedVersions[0]: Invalid value: "v1alpha1": must appear in spec.versions
```

CRDのversionsに`v1alpha1`,`v1beta1`が定義されていて、新しく反映するCRDからは`v1alpha1`が削除されてる時に発生する

以下コマンドを打てば解決する
```sh
$ kubectl get crd foo.bar -o yaml | yq .status.storedVersions
- v1alpha1
- v1beta1

$ kubectl patch crd foo.bar -p '{"status":{"storedVersions":["v1beta1"]}}' --subresource=status
customresourcedefinition.apiextensions.k8s.io/foo.bar patched

$ kubectl get crd foo.bar -o yaml | yq .status.storedVersions
- v1beta1
```
Laravelでcontrollerから受け取った変数をViewで表示する

4月からエンジニアとして働く初心者です。

今回はLaravelでView(bladeファイル)にControllerから受け取った変数の中身を表示する方法をまとめてみます。

## ControllerからViewに変数を渡す
### ①viewメソッドの第2引数
- 単一の変数を渡す
```php
public function sample() {
    $value = 5;
    return view( 'sample.index' , [ 'value' => $value ]); // [ 'view側で使うときの配列/変数名' => $設定した配列/変数名 ]の形。
}
```
- 第2引数で渡すとき、一般には連想配列（`[ 'キー' => 値 ]` ）にする
- 渡す変数は配列でも良い
```php
public function sample() {
    $fruits = array(
        'tomato' => 100,
        'apple' => 150,
        'banana' => 50,
    );
    return view('sample.index', ['fruits' => $fruits]); 
}
```
- 複数の値を渡すときはまとめることができる
```php
public function sample() {
    $fruits = array(
        'tomato' => 100,
        'apple' => 150,
        'banana' => 50,
    );
    $value = 5;
    return view('sample.index', [
        'fruits' => $fruits,
        'value' => $value,
    ]); 
}
```

### ②compact関数を使う
①の第2引数の部分にcompact関数を使います。
```php
public function sample() {
    $fruits = array(
        'tomato' => 100,
        'apple' => 150,
        'banana' => 50,
    );
    $value = 5;
    return view('sample.index', compact( 'fruits', 'value' )); 
}
```
- 設定した変数名を$マークをつけずに書きます
- 書き方がシンプルなため可読性が高い
- view側で使うときに別の名前を付けたいときは使えない


### ③withメソッドを使う
①の第2引数の内容をwithメソッドを呼び出して書くイメージ
```php
public function sample() {
    $fruits = array(
        'tomato' => 100,
        'apple' => 150,
        'banana' => 50,
    );
    $value = 5;
    return view('sample.index') ->with([
        'fruits' => $fruits,
        'value' => $value,
    ]); 
}
```
- 第2引数に指定するより可読性が高い
- view側で使うときに別の名前を付けることができる

全体のイメージとしては①は単純だが読みにくい、②が一番シンプル、③が可読性高く、柔軟ととらえています。状況に合わせて②か③使い分ける感じ…かな…？

## 渡された変数をviewで表示する
### ①単一の変数の場合

- 2重波括弧（マスタッシュ、{{ }}）で囲う（基本はこっちしか使わない）
- ` <?= $変数名 ?> `で囲う（PHPで短い形式の echo 文を書く方法）

Controller
```php
public function sample() {
    $value = 5;
    return view( 'sample.index' , [ 'value' => $value ]); 
}
```
View（bladeファイル）
```html
<div>
    <p>{{$value}}</p>
    <p><?= $value ?></p> 
</div>
```

### ②配列の場合
@foreachを使います。

Controller
```php
public function sample() {
    $fruits = array(
        'tomato' => 100,
        'apple' => 150,
        'banana' => 50,
    );
    return view('sample.index') ->with(['fruits' => $fruits]); 
}
```
View(bladeファイル)
```php
@foreach( $fruits as $fruit )
    <p>{{$fruit}}</p>
@endforeach
```
@foreachは繰り返しの処理。
$fruitsには配列が入っているので、それを一つずつ同じ作業を繰り返してくれる。


## おわりに
ひとまず変数の受け渡しと表示の一番よくみるところをまとめてみたつもりですが、まだまだ勉強すること多いですね、、、

間違いなどあれば教えてください。
個人でAWSを利用し始めた

# はじめに
[AWS][1]は言わずと知れたパブリッククラウドサービスである。
当記事は、個人でAWSを利用し始めるに至った思考や経緯と、その後の所感を綴った雑記である。
（AWS契約の手順などは当記事のスコープ外）

# 切っ掛け
## その1 業務でAWSを利用し始めた
内製でCTFの問題を作成したり、それをホスティングする環境を用意するにあたり、社が利用していた既契約のAWSを触ることになった。
最初は当然分からないことだらけであったが、幸いAWSに関するハンズオン研修を受ける機会があった為、そこで基本的な操作（主にEC2やS3関連）を習熟した。
慣れれば快適で、2000年代に自宅Webサーバを触っていた頃よりも感覚的には楽であった。
操作のほとんどがWeb上のGUIで済み、EC2インスタンスの中まで入ればお馴染みのLinux。
今時のサーバレスアーキテクチャと比べれば抽象度は低いが、逆に過去の経験からのとっつきやすさを覚えた。

## その2 既存利用サービスが値上げされた
一方で、個人的趣味で、Heroku Dynosをホスティングサービスとして利用していたが、コンテナへの理解も浅く、正直使い勝手の良さはあまり感じていなかった。ただ無料という理由での利用だったが、その無料サービスも終了、月額1ケタUSDとなり、魅力も薄れていた。しかし、環境を変えるほどのモチベーションは生まれず、そのまま惰性で利用していた。
しかし、前述の通りAWSを利用しはじめて、その手軽さに気付いた。おまけに条件付きだが無料利用枠がある。業務である程度利用し続けることも見えているなら、趣味と実益を兼ねて利用しない手はない。
コンサバ思考がちの私でも、乗り換えを決意した。

# 利用し始めてから
## むしろ使い易かった
業務で利用していたり、ハンズオン研修を受けていたこともあり、驚くほどスムーズにHerokuからAWSへ移行できた。システム開発業務に従事していた際のマイグレのノウハウも活用しつつ、実際の利用者（といっても非常に小さなコミュニティの内内の間だが）への影響を極小化しつつ実施できた。
## AWSクレジットの優待まで貰えた
AWSの利用は手段であったのだが、利用すること自体が楽しく思えると逆転してしまう。
何かAWSを利用して巻き取れないか、ライフハックできないか、という志向になってしまう。
幾つかEC2インスタンスを立てて遊んでいたところに、AWSより思わぬ福音、300 USDのクレジット付与のキャンペーンを受けることができた。使い切りの期限は半年程度だが、きっと色々利用している間に尽きてしまうだろう。
（なお、試している中で一番高額な費用が掛かったのは、友人の勧めの3Dゲームのサーバで、1カ月使い続ければ150 USDというものだった。）

# おわりに
以上、取り留めのない雑記となってしまったが、初期登録も簡単で、AWSクレジットの優待申請もある程度の技術英語が出来るならハードルの低いものだった。私自身がそうであったように、AWSという看板の大きさから来る手の届かなさそう感も十二分に理解できるが、ぜひ試すだけ試して、肌に合う合わないなど含めて評価することを勧めたい。

[1]:https://aws.amazon.com/jp/
任意のRHEL9へのインプレースアップグレードする方法

どうもこんにちは、Clefable_Tです。

今回は任意のRHEL9へのインプレースアップグレードする方法についてお話させてください。

<h1>免責事項

本記事の内容は、クライアント環境で実際に行った実績のある作業ではあるものの、<font color="red"><b>あくまで個人の一意見です。</b></font>
ですので本記事を参照し、実環境で作業を実施後、何らかの問題が生じた場合、筆者及び筆者所属会社は当該事象について責任を負いません。

※絶対個々人で検証、リハーサルしてね。という意味です
エンジニアであれば当然のようにするとは思いますが、念のため・・・

<h1>前提

RHELのVMがRHEL8.xであること
下記の条件を満たしていること

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/9/html/upgrading_from_rhel_8_to_rhel_9/planning-an-upgrade-to-rhel-9_upgrading-from-rhel-8-to-rhel-9

<h1>背景

RHEL8.8の状態からRHEL9.2にしたかったのですが、アップグレードの準備や、アップグレードにあたっての阻害要因を取り除く中で、RHEL8.8がRHEL8.9に上がってしまったことがありました。

RHEL8.9の状態でそのままアップグレードすると、RHEL9.2ではなく、RHEL9.3になってしまいます。
これではクライアント間で取り決めたことから逸脱してしまい、<b>まずいですよ</b>となってしまうので、何らかの対処が必要。ということで検証を行い、対処方法を見つけた。という背景があります。

調査に協力していただいたベンダーの皆様、本当にありがとうございました。

<h1>対処方法

前置きが長くなりましたが、ここからは作業手順について説明します。
誤解や認識齟齬が無いようにしたい私のエゴで申し訳ないです。

* 作業対象のRHELのバージョンを確認します
```
# cat /etc/redhat-release
```

* 次にupgrade_paths.jsonの中身を見ます。
```
# cat /etc/leapp/repos.d/system_upgrade/common/files/upgrade_paths.json
```
下記がupgrade_paths.jsonの中身が見れます。
_"8.9": ["9.3"],_ と _"8": ["9.3"]_　があると思います。
この _["9.3"]_ の部分を _["9.2"]_ へコンフィグを変更してください。

viエディタで変更可能です。
```
# vi /etc/leapp/repos.d/system_upgrade/common/files/upgrade_paths.json
```

_<<<----CHANGED TO 9.2_ と記載のあるところが変更箇所です。
実環境には、当該文字列はございません。
```json:upgrade_paths.json
    "default": {
        "7.9": ["8.6", "8.8", "8.9"],
        "8.6": ["9.0"],
        "8.8": ["9.2"],
        "8.9": ["9.3"], <<<----CHANGED TO 9.2
        "7": ["8.6", "8.8", "8.9"],
        "8": ["9.3"] <<<----CHANGED TO 9.2
    },
```

* コンフィグの編集が終わったら、下記コマンドでRHEL9へアップグレードにあたっての阻害要因の有無を確認して、阻害要因があれば取り除いてください
```
# leapp preupgrade
```

* 阻害要因を取り除いたら、下記コマンドでアップグレードを行ってください。アップグレードコマンドの実行が終わったらVMを再起動してください。再起動後、指定のRHEL9.xのバージョンになっていることを確認し、作業は完了です
```
leapp upgrade
```

<h1>最後に

このような状態にならないためにも、定期的にソースバージョンのロックを行うようにしてください。
阻害要因を取り除く中で、パッケージの入れ直し等が発生した時に、勝手にバージョンが8.9になりがちなので・・

```
# subscription-manager release --set <source_os_version>
```
や
```
# rhui-set-release --set <source_os_version>
```

で、対応可能です。

この記事がどなたかのお役に立てれば光栄です。
最後までお読みいただきありがとうございました。
mac OS, Linux で `chromedriver` をダウンロードして配置するスクリプト


`chromedriver` は selenium で利用する WebDriver の1つです。

通常なら brew や apt を使えば `chromedriver` を入手できると思いますが、
環境影響を減らしたいときには手動でダウンロード・配置したいです。

mac OS, Linux で `chromedriver` をダウンロードして配置するスクリプトを

2023年5月頃（バージョン115）以前・以後で `chromedriver` をダウンロードする方法が変わっていて、このスクリプトは以後の対応です。
公式案内、バージョンの選び方は以下のページから辿れます。

https://googlechromelabs.github.io/chrome-for-testing/

https://github.com/GoogleChromeLabs/chrome-for-testing#json-api-endpoints

## スクリプト

require: curl, jq, unzip

```sh
curl -s https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json -o last-known-good-versions-with-downloads.json
MAC64_DIR_NAME="chromedriver-mac-x64"
MAC64_URL=$(< last-known-good-versions-with-downloads.json jq -r '.channels.Stable.downloads.chromedriver[] | select(.platform == "mac-x64") | .url')
LINUX64_DIR_NAME="chromedriver-linux64"
LINUX64_URL=$(< last-known-good-versions-with-downloads.json jq -r '.channels.Stable.downloads.chromedriver[] | select(.platform == "linux64") | .url')
DRIVER_BIN_FILE=./chromedriver

if [ "$(uname)" = "Darwin" ]; then
	CHROME_DIR_FILE=${MAC64_DIR_NAME}
	CHROME_DRIVER_URL=${MAC64_URL}
else
	CHROME_DIR_FILE=${LINUX64_DIR_NAME}
	CHROME_DRIVER_URL=${LINUX64_URL}
fi

rm -rf ${DRIVER_BIN_FILE}
rm -rf "${CHROME_DIR_FILE}"
rm -rf "${CHROME_DIR_FILE}.zip"
curl -O -L "${CHROME_DRIVER_URL}"
unzip "${CHROME_DIR_FILE}.zip"
mv ${CHROME_DIR_FILE}/chromedriver ${DRIVER_BIN_FILE}
chmod u+x ${DRIVER_BIN_FILE}
rm -rf "${CHROME_DIR_FILE}.zip"
```
wslで、最小のカーネルをコンパイル その36

# 概要
wslで、kernel.elfのコンパイル、やってみた。
さらに、上のkernel見つけたので、コンパイルしてみた。
俺言語インタープリタを、移植してみた。
プログラムをロードする機能を実装する。
txtファイルをフロッピーイメージに焼く。

# 手順

# src\tools\fontフォルダに、kuku.txt fizz.txt zun.txt を、置く。



# Makefileをいじる。

```
JPFONT_TEST_FILE = src/tools/font/sjis.txt src/tools/font/euc.txt src/tools/font/kuku.txt src/tools/font/fizz.txt src/tools/font/zun.txt
```

# 結果

![スクリーンショット 2024-03-29 110808.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/3b852d34-278b-d9ba-bf41-5606d7ce1c12.png)


以上。
【PHP】PHPで外部のサイトを読み込む方法

# はじめに
こんにちは! 中学2年生のWardHamamatsu67です! 今回は、PHPで外部のサイトを読み込む方法について説明したいと思います。
# コード
```php
<?php
    $url = "file:///C:/xampp/htdocs/traffic_light.html";
    $output = file_get_contents($url);
    echo($output);
?>
```
こんな感じです。結構短めにできます。なお、今回読み込むサイトは一昨日紹介した気持ち悪い信号機のページです。
# 説明
```php
    $url = "file:///C:/xampp/htdocs/traffic_light.html";
```
この部分では、**$url**という変数を指定し、その中に、読み込みたいサイトのアドレスバーに書かれているURLを書きます。
```php
    $output = file_get_contents($url);
```
この部分では、**$output**という変数を指定し、先程指定された$urlのデータを読み込みます。
```php
    echo($output);
```
最後に、$outputで読み込まれたデータを出力します。
# どうなる??
![スクリーンショット 2024-03-29 142452.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749972/d53f6f6c-653b-813a-355f-69b1c174a030.png)
![uploading...0]()
ちゃんとそのまま表示されました!!
# おわりに
以上です。外部のサイトを読み込むことが出来るようになると、プログラミングのネタになるものが増えてくるのではないでしょうか?意外と簡単なので、皆さんもぜひ、試してみてください。
この記事が良いと思った方はいいねとフォローをしてくれると嬉しいです。
Ubuntu　UFWコマンドまとめ

<h2>自分用にまとめたものになります。
<p>ufwの動作状態確認 : ufw status　※空いているポートも確認できる
<p>ufwのアクティブ化：ufw enable
<p>ufwの再読み込み：　ufw reload　※ポート開放したときに必ず実行
<p>ufwポート開放：ufw allow {ポート番号かサービス名}
<p>例：ufw allow 80 か　ufw allow http

<p>　ポート開放はできたら、ポート番号で指定すること。サービス名で実行されないことがあるのとそのサービスのディフォルトのポートを開けるので、他のポート番号に変えた際に誤って開けられる

<p>ポートの削除　ufw delete　｛番号｝
<p> 番号はufw statusで確認できる。

<h3>解放の作業順番
<p>1,ufw enable
<p>2,ufw reload
<p>3,ufw allow {ポート番号かサービス名}
<p>4,ufw reload
歴史を作る時間 (paizaランク C 相当)

https://paiza.jp/works/mondai/query_primer/query_primer__history

タプルのやり方を完全に忘れてたので、調べつつ対応しました
まあ、中身としてはうーんnamesは必要ない気がします。。。
一応出したけど。
historiesは内包表記ができなさそうなので、普通に。タプル化して配列に入れてます。
タプル化したやつをどうやっていれるかってことでちょっと迷ったけども。

その後は、sortedしたやつをそのままプリントするだけですね。
クエリじゃない問題だと思ったのですが案の定でした。

```py
N,K = map(int,input().split())
names = {input() for _ in range(N)}
histories = []
for i in range(K):
    event,charge = input().split()
    histories[i] = (int(event),charge)

for year, name in sorted(histories):
    print(name)

```

とりあえず以上です。

すみません、間違えました。。。
これだとランタイムエラーが発生して失敗します。

```py
N,K = map(int,input().split())
names = {input() for _ in range(N)}
#あらかじめ配列の個数分のNoneが必要
histories = [None] * K
for i in range(K):
    event,charge = input().split()
    histories[i] = (int(event),charge)

for year, name in sorted(histories):
    print(name)
```
IPアドレスが一部重複したVPC間TGW接続

# はじめに
<!-- 発端や概要を記載 -->
TGWをつかったVPC間接続について、IPレンジが重複している場合は接続できないと記載がありましたが、IPレンジが丸かぶりでなければうまくいくのではないかと思い検証してみました。

また、今回の記事は備忘録っぽい感じです。
各サブネットの構成とか詳細は後日会社ブログのほうで紹介する予定です。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [登場するリソース](#登場するリソース)
1. [IPアドレスレンジ](#ipアドレスレンジ)
1. [検証内容](#検証内容)
1. [結果](#結果)
1. [接続確認](#接続確認)
1. [接続できない理由](#接続できない理由)
1. [さいごに](#さいごに)

# 登場するリソース
* VPC1
    Cidr:10.0.0.0/21
    EC2:10.0.4.14
* VPC2
    Cidr:10.0.0.0/20
    EC2:10.0.8.93
* VPC3
    Cidr:192.168.32.0/20
    EC2:192.168.40.116
        →**VPC3はVPC1,VPC2の両方に接続可能**

# IPアドレスレンジ
* VPC1(10.0.0.0/21)で使えるIPレンジ
    10.0.0.0～10.0.7.255
* VPC2(10.0.0.0/20)で使えるIPレンジ
    10.0.0.0～10.0.15.255

# 検証内容
→10.0.0.0～10.0.7.255まではVPC1,VPC2で重複しているが、10.0.8.0 ~10.0.15.255 はVPC1に存在しないため、VPC1からVPC2へは一方通行の接続が可能か検証する

# 結果
いきなり結論から書きますが通信できませんでした。


# 接続確認
接続はうまくいきませんでしたが、TGWのRTキャプチャをご紹介します。

**VPC1の場合**
接続可能VPC：VPC3のみ
* VPC1-Attachment
    * 【VPC1】:10.0.0.0/21
    * 【EC2】:10.0.4.14
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/95b08acb-6760-23b5-bc97-be423e4595be.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/137e563a-1505-27e2-203b-145024f4dcce.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/f122285c-aa1c-535d-507a-e4a5aafe1407.png)


***
**VPC2の場合**
接続可能VPC:VPC3のみ
* VPC2-Attachment
    * 【VPC2】:10.0.0.0/20
    * 【EC2】:10.0.8.93
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/859a8947-20ae-48f6-2e77-f67fdfd322e2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/141c9106-72ba-c158-3149-427e75995333.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/21fb5178-70dd-f110-884b-361a594a0356.png)

***
**VPC3の場合**
接続可能VPC:VPC1,VPC2ともに接続可能
* VPC3-Attachment
    * 【VPC3】:192.168.32.0/20
    * 【EC2】:192.168.40.116
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/996cbc03-d2c5-fea6-c848-26e5beca43c1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/f1a204a3-8c60-b2f8-a20c-5007c90f69ed.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/58b70daf-91bb-4529-9433-40278fb6041b.png)

# 接続できない理由
接続元VPCに存在しないIPアドレスに向けてなら一方通行な通信が可能かと思いましたが、接続先サブネットのルートテーブルに戻りルート（接続元EC2のIPアドレス）を記載できないため通信できませんでした。

もう少し詳しく説明すると
VPC1→VPC2と接続する場合、VPC2のサブネットのRTに戻りの経路【接続元EC2(10.0.8.93)→TGW】を記載しないといけないのですが、**10.0.8.93**はVPC2のIPレンジに含まれており、宛先としてテーブルに追加できないためです。
* VPC1(10.0.0.0/21)で使えるIPレンジ
    10.0.0.0～10.0.7.255
* VPC2(10.0.0.0/20)で使えるIPレンジ
    10.0.0.0～10.0.15.255
    
# さいごに
今回の構成では通信できませんでしたが、**Floating IP**を使った構成があると噂に聞いたので後日調べてみようと思います。
知識0からのFastlane match

プロジェクト内でFastlane matchを正しく使えるよう整備することになりました。
Fastlane初心者が一から調べてみた過程を記録します!
これから学ぼうと思う方にとって有益な情報となれば嬉しいです!:)

# なぜFastlaneを使うのか
以下を参考にして下さい!

https://codesigning.guide/

以下に載っているフローを見るとイメージがつきやすかったです!

https://zenn.dev/nomunomu0504/articles/746c9e07095078275e45#fastlane-match

# Fastlane matchで証明書・プロファイルを管理する
以下を参考にして下さい。

https://docs.fastlane.tools/actions/match/

https://qiita.com/kotarella1110/items/840af2cf80aaea1fb035

以下の内容を実行、設定すれば証明書の管理はできるようになりました。
* Fastlaneの導入
* init
* MatchFileのapp_identifier設定（チームで共有）
* MatchFileのusernameの設定
* Gitリポジトリ設定（チームで共有）
* passphraseの設定（チームで共有）
* fastlane match developmentの実行
* fastlane match appstoreの実行

フォルダ構成とか、証明書の作成も`fastlane match development`を実行すると自動でやってくれます!(すごい‥)
既に存在する場合は、Gitリポジトリに登録されているプロビジョニングファイルが更新されます。証明書の上書きはされないみたいです。プロビジョニングファイルが既に存在する場合は、名前の衝突を避けるために、ランダムな数字が名前につけられた別のプロビジョニングファイルが別途作成されるので、上書きしたい場合は、登録されている分を削除してからの方が良いです!

複数のプロジェクトの証明書を一つのGitレポジトリで管理する場合については、以下のように、`git_branch`を分けて登録します。`git_branch`パラメーターを指定して、コマンドを叩けばこれも自動でやってくれます!(すごい‥)
以下の「Multiple teams」を参考にしました。

https://docs.fastlane.tools/actions/match/

今回は、複数のチームを持っていたので、Fastfileに別途laneを追加して、コマンド実行しました。

```ruby
platform :ios do
  desc "証明書を更新する"
  lane :update_dev_certificate do
    match(
      app_identifier: ["jp.co.xxx"],
      team_id: "xxx",
      git_branch: "master",
      type: "development",
      force_for_new_devices: true
    )
    match(
      app_identifier: ["jp.co.xxx"],
      team_id: "xxx",
      git_branch: "master",
      type: "appstore"
    )
  end
end
```

bundlerを使用して、インストールした場合は、以下のコマンドを忘れずに!

```
bundle exec fastlane [lane]
```

# Fastlaneで証明書・プロファイルを取得する
やることは、作成する場合と同じですが、`readonly`プロパティを`true`にすることを忘れずに!!

```ruby
platform :ios do
  desc "証明書とプロファイルをダウンロードする"
  lane :fetch_dev_certificate do
    match(
      app_identifier: ["jp.co.xxx"],
      git_branch: "master",
      type: "development",
      readonly: true
    )
    match(
      app_identifier: ["jp.co.xxx"],
      git_branch: "master",
      type: "appstore",
      readonly: true
    )
  end
end
```

# 証明書の期限が切れた場合
一度削除してから再生成します。

https://zenn.dev/ncdc/articles/fastlane_match#%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%AE%E6%9C%9F%E9%99%90%E3%81%8C%E5%88%87%E3%82%8C%E3%81%9F%E5%A0%B4%E5%90%88%E3%81%AF%E3%81%A9%E3%81%86%E3%81%99%E3%82%8B%EF%BC%9F

# 手動でApple DeveloperコンソールからProfileを削除した場合
fastlane match developmentを実行すると再生成してくれます。

https://zenn.dev/ncdc/articles/fastlane_match#%E6%89%8B%E5%8B%95%E3%81%A7apple-developer%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%81%8B%E3%82%89profile%E3%82%92%E5%89%8A%E9%99%A4%E3%81%97%E3%81%9F%E3%82%89%E3%81%A9%E3%81%86%E3%81%AA%E3%82%8B%EF%BC%9F

# 端末を更新した場合

https://yamatooo.blog/entry/2020/11/19/083000_1

# 証明書取得時にエラーが出る場合
証明書の取得を行うと、"passphraseが違う”とエラーが出ていたので、再度ブランチから作り直したところ、正常に取得できるようになりました。新規作成する場合、passphraseの確認は怠らず、チームで管理をしましょう!!

# まとめ
Fastlane matchでの証明書管理の設定は比較的簡単にできたのでよかったです!!
色んな記事を書いてくださる先輩方に感謝です🙇
ChatGPT plusの利用制限が厳しいという話

昨日初めてChatGPT4が使えないという事態に陥った。

いままでは、それほどヘビーな使い方をしていなかったというのもあるが、原因はMy GPTs作成をしていたことにある。

思うようなアウトプットが出ないので、何度も指示を繰り返していたら、1時間もしないうちに、使えなくなった。

それまでは、利用制限について気にも留めていなかったが、2時間以上使えないという事態に直面して、どんな制限があるのか調べてみた。

ChatGPTのWebサイトで、GPT-4と3.5を切り替えるプルダウンを見ると、

![スクリーンショット 2024-03-29 092516.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212141/b9571f14-02a1-6870-e18c-bfcc9a2d9d61.png)

となっていた、3時間で40メッセージがリミット。

Pricingのページには3.5は無償でUnlimitedとなっていた。そんなに違うのか。

APIだとTokenが単位になっているので、考え方は異なるようだが、使用制限が掛かる直前は回答がいやに短くなっていたので、内部的にはtokenの制限も掛かっているように思う。

GPTsを作るにあたっては、GPT-4しか使えず、また作成のためにメッセージとしてロジックを伝えなければならないので、試行錯誤をしているとあっという間に制限に到達する。
それに加えて、テストでもやり取りする必要があるので、GPTsを作るには、40メッセージという上限は低すぎる。

ということで、GPTsは単純なものしか今のところ作れないというのが分かった。

今自分が使っているのは、ChatGPT plusだが、Teamになると、約2倍になると、OpenAIのヘルプに記載があった。約というのがよくわからないが、80メッセージ程度になるということか。

3時間の制限が実質無くなったと感じるのは、感覚的に今の4倍程度のメッセージ数だと思うので、160メッセージぐらいまで増えてくれると嬉しい。
【JS】スクロール量を取得する


# はじめに
案件で現在のページのスクロール量を取得する必要があった。
jQueryならscrollTop()で取得できるが、今回はjQueryが使えないのでJSで取得する方法を調べた。

# pageYOffset
pageYOffsetはスクロール量を取得するメソッド。
```
window.addEventListener('scroll', ()=> {
  console.log(window.pageYOffset);
});
```
これで取得可能！
wslで、最小のカーネルをコンパイル その35

# 概要
wslで、kernel.elfのコンパイル、やってみた。
さらに、上のkernel見つけたので、コンパイルしてみた。
俺言語インタープリタを、移植してみた。
プログラムをロードする機能を実装する。
構想編


# 方針

- 俺言語インタープリターにロード機能を付ける。

- fontフォルダーに、kuku.txt fizzbuzz.txt zundoko.txt janken.txtを、置く。
- フロッピーイメージに、焼く。

- l kuku.txtで、一行読んだら、RUNする。

fizzbuzz.txt

```
10 a=0
20 a=a+1
30 b=a%15
40 #=b=0*140
50 b=a%5
60 #=b=0*160
70 b=a%3
80 #=b=0*180
90 ?=a
100 ?=" "
110 #=a>100*200
120 #=20
140 ?="fizzbuzz "
150 #=20
160 ?="buzz "
170 #=20
180 ?="fizz "
190 #=20
```

zundoko.txt

```
10 a=0
20 b=123
30 b=b*5
40 b=b-1
50 #=b<127*100
60 ?="zun "
70 a=a+1
80 #=a>4*170
90 #=30
100 ?="doko "
110 a=0
120 #=30
130 ?="doko kiyosi!"
```

kuku.txt

```
10 a=1
20 b=1
30 ?=a*b
40 a=a+1
50 #=a<10*30
60 b=b+1
70 a=1
80 r
90 #=b<10*30
```




以上。
【JS】要素の位置を取得する



# はじめに
jQueryで要素の座標を取得するのにoffsetという便利なメソッドがあるが、jQueryが使えない環境でJSだけで座標を取得する方法を調べた。

# getBoundingClientRect
getBoundingClientRectは要素の座標を取得できる。

```
getBoundingClientRect().top;
getBoundingClientRect().bottom;
getBoundingClientRect().left;
getBoundingClientRect().right;
```
シェルの役割とは？どれを使えばいいの？（MacOSの場合）

今回はbashとzshについて学習したため、「シェルの役割」と「どれを使えばいいか」を簡単にまとめました。

bashとzshとは、シェルの一種であり、テキストベースのユーザーインターフェースを提供し、ユーザーがコンピューターと対話できるようにするプログラムです。

## シェルとは？
> 「シェル」という用語は、「コンピューターに直接命令を打ち込むことで対話する」という行為そのものを指すものではなく、そのような対話を可能にするプログラムや環境のことを指します。
> 
> つまり、シェルはユーザーがコンピューターのオペレーティングシステムとテキストベースで対話するためのインターフェースまたはツールです。
> （chatGPTから一部抜粋）

具体的にはシェルでコマンドを解析し、カーネルがそれを読み取り処理を実行し、最終的にその結果をシェルを経由してユーザーへ知らせるというフローになります。


カーネル：ざっくりいうとソフトウェアとハードウェアの仲介の役割を持っているというイメージ

## シェルの種類は？
「シェル」の種類は下記の内容がよく聞かれるものです。
（これ以外にも種類は存在します。）
・sh
・bash
・csh
・tcsh
・ksh
・zsh

現在（2024年3月現在）ではzshが主流で「sh と bash（以前は標準で使用されたシェル） の良いとこ取り ＋ 独自機能」の高機能シェルとなっています。※bash で出来ることは zsh にも出来る。

## zsh（ゼットシェル）とは？
ZshはBashよりも高度な機能を持つシェルでBashの上位互換という位置付けです。Zshはより進んだタブ補完機能や、コマンドのスペルチェック、テーマやプラグインによるカスタマイズが可能です。

## まとめ
シェルはコンピューターとのテキストベースでの対話を可能にするツールであり、bashとzshはこの分野で特に人気のある選択肢です。bashは堅牢で信頼性の高いシェルとして長年にわたり使われてきましたが、zshはbashの機能に加え、進化した補完機能やカスタマイズオプションを提供し、最近のMacOSではデフォルトのシェルとして採用されています。

しかし、どのシェルを選ぶかは、最終的にユーザーのニーズ、好み、そして特定の作業やプロジェクトの要件によって異なります。bashのシンプルさと広範なサポートが重要である場合もあれば、zshの高度な機能やカスタマイズ性を活用したい場合もあると思います。

## 参考文献
[Linuxの「Shell」とは？Shellの種類やできることなどをわかりやすく解説](https://www.rstone-jp.com/column/110007/ "shellの種類についての記事")
[【Shell】シェルの種類と設定ファイルの読み込み順（ざっくりまとめ）](https://qiita.com/to3izo/items/b6a735793d55d65c5b10 "shellの種類についての記事")
話した言葉を文字起こしするアプリの作成


今回は、pythonで、話した言葉を文字起こしするアプリを作成しました。
これは、タイピングが苦手な人や、紙のメモをパソコンにそのまま入力したいときなどに役立ちます。

https://github.com/mt1-m/voice_memo

# 使用方法
zipファイルをダウンロードして解凍したら、voice_memoディレクトリで下記を実行して必要なライブラリをインポート、
```
pip install -r requirements.txt
```
できたら下記を実行します。
```
python voice_memo.py 
```
## 実行結果
![実行結果1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3426433/f37203a1-ad41-3585-1a99-50f12abf4a89.png)
このように、話した言葉を文字起こししてくれます。頑張って発音すれば英語もいけます。終了するときは、'q'キーを押します。

# 実装方法
今回は、マイク入力と文字起こし共に、speech_recognitionを利用しました。
具体的には、まずSpeechRecognitionライブラリのRecognizerクラスのインスタンスを作成、
```python
import speech_recognition as sr

r = sr.Recognizer()
```
マイクから話した言葉を受け取るには下記の関数で、
```python
def get_audio_from_mic():
    with sr.Microphone(sample_rate=16000) as source:
        audio = r.listen(source, timeout=None)
        return audio
```
それを文字起こしするには下記の関数で、
```python
def convert_audio_to_text(audio_data):
    try:
        text = r.recognize_google(audio_data, language="ja-JP")
        print(text)
        save_to_file(text)  # テキストをファイルに保存
    except sr.UnknownValueError:
        pass
```
実装しました。main関数は以下のようになっています。
```python
def main():
    print("---メモ---")
    # 録音ループ
    while not exit_loop:
        audio_data = get_audio_from_mic()

        # マルチスレッドで音声をテキストに変換
        threading.Thread(target=convert_audio_to_text, args=(audio_data,)).start()
```
音声をテキストに変換中も音声を受け取れるように、マルチスレッドを導入しました。
## 全体のコード
```python:A.py
import os
import speech_recognition as sr
import threading
import keyboard
import datetime

r = sr.Recognizer()

# outputディレクトリが存在しない場合は作成する
OUTPUT_DIR = "output"
if not os.path.exists(OUTPUT_DIR):
    os.makedirs(OUTPUT_DIR)

# 現在の日時からファイル名を生成
now = datetime.datetime.now()
MEMO_FILE = os.path.join(OUTPUT_DIR, now.strftime("%Y-%m-%d_%H-%M-%S_memo.txt"))


def get_audio_from_mic():
    with sr.Microphone(sample_rate=16000) as source:
        audio = r.listen(source, timeout=None)
        return audio


def convert_audio_to_text(audio_data):
    try:
        text = r.recognize_google(audio_data, language="ja-JP")
        print(text)
        save_to_file(text)  # テキストをファイルに保存
    except sr.UnknownValueError:
        pass


def save_to_file(text):
    with open(MEMO_FILE, "a") as file:  # ファイルを追記モードで開く
        file.write(text + "\n")  # テキストをファイルに書き込む


# キーボードからの入力を監視して、'q'キーが押されたらループを抜ける
exit_loop = False


def on_key_event(event):
    global exit_loop
    if event.name == "q":
        exit_loop = True


keyboard.on_press(on_key_event)


def main():
    print("---メモ---")
    # 録音ループ
    while not exit_loop:
        audio_data = get_audio_from_mic()

        # マルチスレッドで音声をテキストに変換
        threading.Thread(target=convert_audio_to_text, args=(audio_data,)).start()


if __name__ == "__main__":
    main()

```
【SQLServer】監査ログの中身を確認する

# 背景
システムのサービスインから膨大な量の監査ログが出力されるようになったため
原因分析のために、監査ログの中身を確認しようとした

SSMSからGUI操作で監査ログを確認することも出来そうだったが、
監査ログのデータが膨大だったためにtempDBの容量がひっ迫し、開くことができなかった

特定のサイズ単位でログが切り出されているため、個々のログファイルの中身を確認した

その確認方法の備忘録

# 手順

システム関数（Sys.fn_get_audit_file）を利用して切り出されたログファイルを参照する

以下のSQLを実行することで、ログの中身を確認できる

```監査ログ確認.sql
SELECT 
    *
FROM
    Sys.fn_get_audit_file ('監査ログの絶対ファイルパス',null,null)
```



 # 参考
- [sys.fn_get_audit_file (Transact-SQL) - SQL Server | Microsoft Learn](
 https://learn.microsoft.com/ja-jp/sql/relational-databases/system-functions/sys-fn-get-audit-file-transact-sql?view=sql-server-ver16&tabs=sqlserver)
【C#】デリゲートを使ってみた

## 1. デリゲートとは

同じ型の引数を返す関数を格納できる変数のようなもの



## 2. デリゲートを使ってみる

次の処理を記述します
1. <b>void型でstring型の引数を1つ持つデリケートを定義する</b>
    （これと同じ引数、戻り値を持つ関数はオブジェクトとして扱うことができる）
    
2. <b>デリケートにMethodメソッドを代入</b>
    引数として受け取った文字列をそのまま返す
    
3. <b>デリケートにMethod2メソッドを代入</b>
    引数として受け取った文字列を2つつなげて返す
    
4. <b>デリケートを呼出</b>
    デリケートに追加した処理が実行される

```test.cs
// デリゲートの宣言
public delegate void Func(string)

static void Main(string[] args)
{
    string hoge = "hoge";
    Func func = Method; // Methodメソッドをデリゲートに代入
    func += Method2; // Method2メソッドをデリゲートに代入
    func(hoge); // デリゲートを呼び出す（Method,Method2が呼ばれる）
}

// Methodメソッド
private static void Method(string hoge)
{
    console.WriteLine(hoge);
}

// Method2メソッド
private static void Method(string hoge)
{
    console.WriteLine(hoge + hoge);
}
```

実行結果
```
>> hoge
>> hogehoge
```
モバイル端末ではパソコンで動いているWebサイトをアクセス

# 課題

 モバイルのWebアプリを開発する際に、カメラやマイクロホンなどの物理の端末で行う機能に対して、ローカルでどうのように開発して検証したらいいでしょうか？本記事ではどのようにWebアプリを物理端末でテストするのを紹介させていただきます。

# 結果
IpadでReactアプリにアクセスできます。実装の際に何か変更すればすぐに反映させます。
![IMG_3897.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/78e01f40-beb0-08ce-0323-7b62e9ecd55d.png)

# 仕組み

![Screenshot 2024-03-23 at 17.05.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/669373e2-3ae4-8a4f-a997-a1f6159585c2.png)

スマホで直接に153.242.155.111:3000へアクセスできません。なぜなら、Wi-Fiルートに厳しいアクセス制御がありますから。ルーターイントラネットのIpでアクセスします

:::note info
https://www.whatismyip.com でアクセスして自分のIP（例：153.242.155.111）を知りますが、
:::


# 仕方
**前提**

- パソコンとモバイルは同じWi-Fiルーターにアクセスします
- WEBサイトを行います。本記事はReactアプリをポート3000で立ち上がります

#### Wi-FiのイントラネットでパソコンのIPを探します

本記事はMacOS Solomaで実施します。その他はこちらでご参加ください
* [Soloma以前バージョン](https://www.security.org/vpn/find-router-ip-address/#:~:text=On%20Mac%20With%20System%20Settings)
* [Window](https://www.security.org/vpn/find-router-ip-address/#:~:text=computer1.-,On%20Windows,-Search%20%E2%80%9Ccmd%E2%80%9D%20to)

1. 画面の右上にてWi-Fiイコンを押下→ 「Wi-Fi設定」選びます
![Screenshot 2024-03-23 at 16.41.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/a60028fe-ec60-682d-a0f1-3cb3b4f52c94.png)
「詳細」を押下
![Screenshot 2024-03-23 at 16.42.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/f14965ac-8178-e22e-6091-53d4d880b36e.png)

![Screenshot 2024-03-23 at 16.42.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/c882906c-2e5e-5262-ebc3-9d572d7550a1.png)


IP address 192.168.0.2 → パソコンのIP
Router: 192.168.0.1 →　Wi-FiルーターのIp

### モバイル側で
設定->Wifi
同じwifiを確認します

![IMG_0049.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/fd6035dc-866b-eaf4-b375-57b9bbeba5b4.jpeg)

詳細
![IMG_0050.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/dfd54c16-c711-e483-c713-211b8cc7e7c6.jpeg)

IPアドレスは：ルーターのイントラネットで端末のIPです
ルーター：ルーターのイントラネットでルーターのIP



![IMG_0051.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/804de732-c20e-f901-c901-eef445f5fd63.png)

 Safariを開けて<パソコンのIP>:ポートにアクセスします。
（この記事では　192.168.0.2:3000)




# 更に

[ngrok](https://ngrok.com)といツールでもこちら課題を解決できます

ngrok はインタネットで、ドマイン名を登録してReactアプリを開放します。そして、モバイルでそのドメインにアクセスできます。しかし、同時で何人がアクセスできるのを制限されます。


# ソースコード準備

```jsx
npx create-react-app test
cd test
npm start
```

# 参考

https://www.security.org/vpn/find-router-ip-address/
https://ngrok.com
[Jest]toEqual(false)とtoBeFalsy()の違いについて

## はじめに
Jestでテストを書いていたときにtoEqual(false)とtoBeFalsy()について指摘を受けたので、どのような違いがあるのかをまとめてみました。

## どんな違い？
コードを実行してtoEqual(false)とtoBeFalsy()の違いを見てみました。

### toEqual(false)
以下のコードではbooleanのテスト以外失敗してしまいます。
```
describe("toEqual", () => {
  test("boolean", () => {
    const data = false;
    expect(data).toEqual(false); // pass
  });
  test("empty", () => {
    const data = "";
    expect(data).toEqual(false); // fail
  });
  test("0", () => {
    const data = 0;
    expect(data).toEqual(false); // fail
  });
  test("undefined", () => {
    const data = undefined;
    expect(data).toEqual(false); // fail
  });
  test("null", () => {
    const data = null;
    expect(data).toEqual(false); // fail
  });
});
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3057699/e839c4a6-dab7-f026-620f-541e7ca84090.png)


toEqual()は引数に渡された値と一致した値をパスします。

### toBeFalsy()
以下のテストコードを実行するとすべてPASSされます。

```
describe("toBeFalsy", () => {
  test.each([
    { testName: "false", data: false },
    { testName: "empty", data: "" },
    { testName: "0", data: 0 },
    { testName: "undefined", data: undefined },
    { testName: "null", data: null },
  ])("$testName", ({ data }) => {
    expect(data).toBeFalsy();
  });
});
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3057699/8954bbb3-a4ce-4da5-e15e-c1544bc467e3.png)

.toBeFalsy()はfalsyな値をパスします。

## 結論
booleanの値をチェックする場合には、toEqual(false)を使う
falsyな値をチェックする場合には、toBeFalsy()を使う

## 終わりに
以下を読むと今回確認した内容が記載されているので、ちゃんとドキュメントを読むべきだと実感しました。
https://jestjs.io/ja/docs/expect#tobefalsy

JestのMachersについてはまだ使ったことがないものも多いので、ドキュメントを読みつつ試して使ってみようと思います。
Git revertでcommit やPR, mergeを取り消す方法

## What you Learned?

- リモートのmain branchをPR merge前の状態に戻す。
- `git revert` コマンドの使い方。

## Goal

- リモートのmain branchをPR merge 前の状態に戻す。
- `revert` コマンドを使う。

## Contexts

- 何度かcommitしたbranchをリモートのmain branch にMergeした状態。
- これまでのcommitを無かったことにして、main branchを元の状態に戻したい。

---

## What I did

### Revertコマンドとは

- 特定のコミットを打ち消すコミットを作成するコマンド

公式 reference

```
git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>…
git revert (--continue | --skip | --abort | --quit)

# https://git-scm.com/docs/git-revert
```

### Resetコマンドとの使い分け

`git reset` コマンドはコミットを無かったことにするコマンド。正確にいうと

- `git reset --soft HEAD^` 
    - 直前のコミットを取り消す。ステージングとWorking directoryは変化なし。
- `git reset --mixed HEAD^` 
    - 直前のコミットとステージングを取り消す。Working directoryは変化なし。
- `git reset --hard HEAD^` 
    - 直前のコミットとステージングとWorking directoryを全部取り消す。

これに対し、 `revert` コマンドはcommitを打ち消すcommitを作成する。そのため、commitを無かったことにするのではなく、変更点をもとに戻すようなcommitを新しく作成するコマンド。

これは既にPRを出した後やリモートにmergeした後に打ち消したい時に使用する。
リモートに出してしまった後にresetを行うと、他の人がローカルにpullしたコードと整合性が取れなくなる可能性があるため、 `reset` は使わず `revert` を使う。

### 基本の使用例

公式referenceから使用例を参照。

- 特定のコミットを取り消したい場合、コミットIDを指定するか、 `HEAD` からいくつ前のコミットを取り消したいかを指定する。
- もし複数コミットを取り消す場合は、どこからどこまでを取り消すかを指定する。 `-n` オプションを使わない場合、各コミットを取り消すコミットメッセージを個別に入力することになる。同じ理由で複数コミットを取り消す場合は、 `-n` オプションを使って、最後に自分でコミットを作成する。
    - `revert -n`   はコミットなしで revertするというオプション。

> **EXAMPLES
`git revert HEAD~3`**
Revert the changes specified by the fourth last commit in HEAD and create a new commit with the reverted changes.
**`git revert -n master~5..master~2`**
Revert the changes done by commits from the fifth last commit in master (included) to the third last commit in master (included), but do not create any commit with the reverted changes. The revert only modifies the working tree and the index.
> 

### すでにコミットをMergeしてしまった場合

`revert` でmergeを打ち消す場合には、 `-m` オプションにてmainlineの番号を指定する。Mergeは2つ以上の親コミットを持つため、どちらの親を基準に変更を取り消すかを指定する必要がある、ということ。

ざっくりいうと、1がマージされたbranch (mainやmaster),  2がマージしたbranch (featureなど)になる。

親コミット確認方法

```
# 確認方法1:
git log
#　"Merge: <commit id> <commit id>"と出てくる順番に1, 2

# 確認方法2:
git show --pretty=%P <commit>
> <commit id> <commit id>
#と出てくる順番に1, 2
```

今回は、リモートのmain branchに行っている複数のMergeと複数のCommitを取り消したいため、以下を実行。

```
git revert -n -m 1 <commit id>..HEAD
```
意味は
* `git revert` を行う。
*  `-n` コミットをしない (最後に手動で行う、これをしないと打ち消すコミットごとにコミットを作ることになる)
*  `-m 1` Mergeをrevertして、親コミット 1 を元に戻す。
* `<commit id>..HEAD` <commit id> からHEADまでを打ち消す。


**`Revert` 中にエラーになる時がある。**

```
error: revert is already in progress
hint: try "git revert (--continue | --abort | --quit)"
```

上記のエラーが出る時がある。これは既に `revert` 作業中の時、さらに `revert` をすることができないということ。

その場合は、以下のいずれかによって作業中の `revert` を完了させる。

- `git revert --continue`
    - `revert` 操作を完了させる。
- `git revert --abort`
    - `revert` を中止させる。
- `git revert --quit`
    - `revert` 一時停止させる。

**`Revert` 中に conflictを起こす時もある。**

複数のcommitを取り消すときに、conflictを起こす時もある。その時は以下の手順で解決する。

- 該当するファイルからコンフリクトを修正する。
- 該当するファイルをステージング。　`git add <file name>`
- `revert` を続ける。 `git revert --continue`

### 参考
またさらに詳細が公式から用意されていたため、参照リンクを残しておきます。

https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt