OmniAICreator/Qiita-1.07M huggingface dataset:
HCP Terraform/Terraform Cloudのメリットをざっくりご紹介！


## はじめに

HCP Terraform が気になる・使ってみたいという人向けにメリットをざっくりご紹介します！

:::note
2024/4/22 に Terraform Cloud は HCP Terraform と名称変更されました。
:::

https://developer.hashicorp.com/terraform/cloud-docs

## HCP Terraform のメリット

### どこからでも実行可能

`terraform login` コマンドでログインすれば、どんな端末でもすぐに同じ環境を使えます。複数端末あっても楽ちんです。

![login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/57473fa5-4bf6-1b33-c595-0c5355a18e5a.png)

### 実行環境がクラウド

クラウドで実行されるので、サーバーの面倒を見る必要がありません。メンバー端末の環境差分なども関係なくなります。ステートファイルのロックや保管も気にしなくて良いですね。

![plan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/30135884-c07a-46be-eee0-2c5e5a2deddd.png)
![run.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/be1fafb8-6041-4cf0-fd9c-dc06355ab6aa.png)

### アクセスキーが不要

各種クラウドサービスと OpenID Connect (OIDC) で連携でき、非常にセキュアです。アクセスキーの発行は不要です。~~アクセスキーを使う記事が多すぎるので滅ぼしたい。~~

![id_provider.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/8aa489ab-8b6e-d594-f9f2-645ae256d61c.png)
![variables.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/67b4136e-4bed-4d3a-e9b9-c206d157955d.png)

### CI 実装が簡単

画面をポチポチすればすぐ CI/CD が実装できます。CI の整備やメンテナンスも馬鹿にならないので助かります。

![ci_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/4d28677e-1b03-47ca-949d-c781f41f1e1c.png)
![ci_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/b52c6fd3-5f15-338b-f2a9-f9320ade512e.png)

### GitHub 連携がイケてる

プルリクエストの画面から Plan 結果や Apply 結果がいい感じに確認できます。レビュアーも大助かりです。

![pr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/17747862-fd75-7532-a0fe-c54ae2a5ad68.png)
![checks1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/7ca14cf6-3fa4-840f-b4a4-644023128415.png)
![checks2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/f2c037e5-b2aa-58ef-9b5f-7f7cde35f9fc.png)
![checks3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/89d6abbf-1295-de9b-764b-0ad056ed5491.png)

### ガバナンスを効かせやすい

権限を持った人による承認がないと Apply できない設定ができます。コードがマージされたら自動で Apply もできますが、ガバナンスを効かせたい・タイミングを調整したい場合に。

![apply1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/4e66f555-b14f-27e3-2a35-a40760dbb9ab.png)
![apply2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/00ea45ef-6a6b-fde5-ca29-8196be90866c.png)
![apply3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/51eb1486-d79e-26bc-348d-648ee00138f1.png)

## まとめ

メリットが多いので、ぜひ一度体験してみてください！
NeoPixel制御ボードのサンプルプログラム⑤

- ## 商品概要
RP2040マイコンを使って、NeoPixelを制御して楽しもうというコンセプトです。
プッシュボタンが1つ　or　2つ搭載しているので、外部入力または切り替えなどで使えます。

- ## プログラム環境
ArduinoIDE バージョン：2.3.2
Adafruit NeoPixel Library 1.12.2

- ## ハードウェアの主な仕様
　①マイコン:PR2040-ZERO（RaspberryPiPico系）
　②NeoPixel接続ピン　 GPI08（R1でショート）
　③プッシュスイッチ１：GPI07
　④プッシュスイッチ２：GPI06（2個搭載しているボードのみ）
　⑤音声入力：GP26

 - ## メインプログラム（ArduinoIDEのスケッチ）
 ボタンを使ってLED表示を切り替える動作確認用サンプルプログラムです。
 ボタンの状態をモニタして、押されたら切り替えを確認できます。
 状態を変化させたい時の切り替えの参考にしていただけたらと思います。

```c++
// ボタンのテスト
#include <Adafruit_NeoPixel.h>

// 定数の定義
#define BUTTON1_PIN 7 // ボタン1のピン番号
#define BUTTON2_PIN 6 // ボタン2のピン番号
#define NEOPIXEL_PIN 8 // NeoPixelのピン番号
#define NUMPIXELS 36 // NeoPixelのLEDの数
#define BRIGHTNESS 32 // NeoPixelの明るさ

// NeoPixelオブジェクトの作成
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);

void setup() {

  // ボタンピンの設定
  pinMode(BUTTON1_PIN, INPUT); // ボタン1を入力に設定
  pinMode(BUTTON2_PIN, INPUT); // ボタン2を入力に設定

  // NeoPixelの初期化
  strip.begin(); // NeoPixelの初期化
  strip.setBrightness(BRIGHTNESS); // 明るさの設定
  setNeoPixelColor(strip.Color(0, 255, 0)); // 初期状態で緑色に設定
}

void loop() {
  // ボタンの状態を読み取る
  int button1State = digitalRead(BUTTON1_PIN); // ボタン1の状態を読み取る
  int button2State = digitalRead(BUTTON2_PIN); // ボタン2の状態を読み取る

  // 両方のボタンがHIGHの場合は何もしない
  if (button1State == HIGH && button2State == HIGH) {
      delay(100); // 状態を読み取る間隔を調整

    return;
  }

  // 両方のボタンが押された場合
  if (button1State == LOW && button2State == LOW) {
    setNeoPixelColor(strip.Color(0, 255, 0)); // 緑に設定
  }
  // ボタン1が押された場合
  else if (button1State == LOW) {
    setNeoPixelColor(strip.Color(255, 105, 180)); // ピンクに設定
  }
  // ボタン2が押された場合
  else if (button2State == LOW) {
    setNeoPixelColor(strip.Color(0, 255, 255)); // 水色に設定
  }

  delay(100); // 状態を読み取る間隔を調整
}

// NeoPixelの色を設定する関数
void setNeoPixelColor(uint32_t color) {
  for (int i = 0; i < NUMPIXELS; i++) {
    strip.setPixelColor(i, color); // 各LEDの色を設定
  }
  strip.show(); // 設定した色を表示
}

```

入力端子をプルアップ抵抗に設定でも良さそうですが、外付けの100kΩと
並列になるのでチャタリング除去の効果が変換するので注意が必要ですね。

```c++
  pinMode(BUTTON1_PIN, INPUT_PULLUP); // ボタン1をプルアップ入力に設定
  pinMode(BUTTON2_PIN, INPUT_PULLUP); // ボタン2をプルアップ入力に設定
```

- ## このプログラムを作成した時の考え方。
ボタンを押したら状態が変わる例です。
初期状態は、グリーン。
ボタン1を押したら、ピンク。
ボタン２を押したら、ブルー。
ボタンを両方押したら、グリーンに戻るのですが離した瞬間にボタンが
片方LO判定になってしまう恐れがあるので工夫が必要そうですね。

- ## 実行結果
![1723964016855.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782127/bb82a728-4758-7c66-85bc-2e9ba3f743a0.jpeg)
RESET直後

![1723964027204.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782127/4b5f5c38-9cb2-fe78-5ec3-85a9dad7813a.jpeg)
ボタン１を押した結果。

![1723964037398.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782127/a842e62d-4b75-758b-c215-b7b72e8eb45c.jpeg)
ボタン2を押した結果。
TypeScript ユーティリティ型 まとめ

## TypeScriptのユーティリティ型(utility type)とは

型から別の型を導き出してくれる型のこと、色々種類がありますが、以下よく使うものを忘備録としてまとめました。

### 1. Record型
`Record<Keys, Type>`

プロパティのキーがKeys、プロパティの値がTypeのオブジェクト型を作るユーティリティ型
```typescript
// サンプル
type StringNumber = Record<string, number>;

const value: StringNumber = { a: 1, b: 2, c: 3 };
```
Recordのメリットは柔軟性です。
動的なキーを持つオブジェクトや、プロパティが動的なオブジェクトなど複雑な型定義を行いたい時に便利です。
プロパティが決まっているオブジェクトの型定義であれば`type`や`interface`で作ります。

### ２. Exclude型
`Exclude<T, U>`

ユニオン型TからUで**指定した型を取り除いた**ユニオン型を返すユーティリティ型

```typescript
// サンプル
type Grade = "A" | "B" | "C" | "D" | "E";

type PassGrade = Exclude<Grade, "E">;

// PassGradeは次の型になります。
type PassGrade = "A" | "B" | "C" | "D";
```

### 3. Pick型
`Pick<T, Keys>`

型TからKeysに**指定したキーだけを含む**オブジェクトの型を返すユーティリティ型

```typescript
// サンプル
type User = {
  surname: string;
  middleName?: string;
  givenName: string;
  age: number;
  address?: string;
  nationality: string;
  createdAt: string;
  updatedAt: string;
};

type Person = Pick<User, "surname" | "middleName" | "givenName">;

// Personは次の型になります。
type Person = {
  surname: string;
  middleName?: string;
  givenName: string;
};
```
githubのwikiでチャットボット作りたい


この記事では、GitHubのWikiを使用して、Agent Builderを活用したチャットボットを構築する方法を紹介します

wikiはこちらを使用します

https://github.com/babu-ch/santa/wiki/

過去記事で使用したリポジトリのものです

https://qiita.com/babu-ch/items/6cd8dbea8e54aec41210

# データ準備

wikiをcloneするコマンドはwikiの右下らへんにあります

```sh
git clone https://github.com/babu-ch/santa.wiki.git

cd santa.wiki

// 今は.mdが対応してないのでtxtに変換する
for file in *.md; do mv "$file" "${file%.md}.txt"; done

// フォルダごと上げたいので.gitは消す
rm -rf .git/
```

# storage

cloud storageにフォルダごとアップします


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/1c171093-6b95-1dd7-37f2-99a8268d6085.png" width=50%>

https://cloud.google.com/storage?hl=ja

# Agent Builderの設定

Agent Builderでアプリを作成→チャット

https://cloud.google.com/products/agent-builder?hl=ja

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/14fe8604-8119-25f4-52dc-c1b56713eb27.png" width=50%>


言語設定を忘れずに

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/200760f7-be3c-ab65-495d-4d17952bbd04.png" width=50%>

データストアの設定は、データストアを作成→Cloud Storage

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/8e138eee-4247-689e-9c88-0007c86b8173.png" width=50%>

先程上げたフォルダを指定する
非構造化ドキュメントにチェックしてください

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/d57969ba-a39e-3d89-e6ac-14515af401a6.png" width=50%>

するとDialogFlowのTest Agentから質問できるようになっています（ストアの反映に時間がかかります）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/e28f6838-44e6-51c0-5d08-ed46080e59b3.png" width=50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/78ce2cf3-9d93-a801-7c45-50cdb5f65fb6.png" width=50%>

答えられない場合データストアでエラーがないか、インポート中じゃないかを確認してください

以下のエラーは、最初markdown形式のままアップしてエラーになっていた時のやつです

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/fc7851e9-2cbe-d3eb-ba51-b7b44fbe83f6.png" width=50%>

# prompt変えてみる

今のままだと味気ないのでちょっとプロンプトを設定してみます

AgentSettings->GenerativeAI->Data store modelなんたらかんたらを変更する

modelをgemini1.5にして、promptはほぼサンプルのデータを使用し、以下２行を追加

```
+   The answer MUST be in Japanese. // ここはEnglishだったとこをJapaneseに置換しただけ
+   Please answer humorously using emojis.
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/839a9557-f17b-a532-9278-e4ae7a83e679.png" width=50%>

プロンプトのサンプルはこちらにあります

https://cloud.google.com/dialogflow/vertex/docs/concept/data-store-agent-settings#customize-summarization-prompt

絵文字を交えて答えてくれるようになりました

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/ad5e5c60-ea3b-2677-4ce4-7c436a67a031.png" width=50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/5ecef212-baa5-0d81-e067-ec38eaaef4f3.png" width=50%>

# おわり

細かい手順は以下の記事のが分かりやすいです！

https://qiita.com/niwa2308/items/2bae101ccc489f053323

簡単に作れてすごいですね :astonished: 

slack連携して使ってみるのも便利そうですよね
リアルタイムログ解析を革新するHELP：新しい階層的埋め込み手法の紹介

# HELP: Hierarchical Embeddings-based Log Parsing - ログ解析の新時代へ

今回は、最新の研究成果である「HELP: Hierarchical Embeddings-based Log Parsing」という論文をご紹介します。この研究は、現代の複雑なソフトウェアシステムにおけるログ解析を革新する画期的な手法を提案しています。ソフトウェアの安定性とセキュリティを維持するために不可欠なログ解析が抱える課題に対して、どのようにHELPが解決策を提供するかを詳しく見ていきます。

### 論文情報
- **タイトル**: HELP: Hierarchical Embeddings-based Log Parsing
- **リンク**: [arXiv:2408.08313](https://arxiv.org/abs/2408.08313)
- **発表日**: 2024年8月15日
- **著者**: Andy Xu, Arno Gau
- **DOI**: [https://doi.org/10.48550/arXiv.2408.08313](https://doi.org/10.48550/arXiv.2408.08313)

## 背景と目的

### ログ解析の重要性と現状の課題

ログは、ソフトウェアシステムの運用状況をリアルタイムで記録する貴重なデータです。これらのログは、システムの保守、トラブルシューティング、異常検知、および根本原因分析の主要な情報源となります。しかし、現代のソフトウェアシステムは、分散型で複雑化しており、膨大な数のログが生成されるため、その解析は容易ではありません。

従来のログパーサーは、大きく分けてヒューリスティックベースとセマンティックベースに分類されますが、どちらにも固有の課題があります。ヒューリスティックベースの手法は、ドメイン知識に依存するため、汎用性に欠け、スケーラビリティの問題があります。一方、セマンティックベースの手法は、リアルタイムの解析が困難であり、コストが高いという問題があります。また、オンラインパーサーにおいては、ログドリフト（ログフォーマットの変化によるパフォーマンス低下）が大きな課題です。

こうした課題に対処するため、HELPは新たなアプローチを提案します。HELPは、ログを階層的に埋め込み、クラスタリングとテンプレート抽出を分離することで、効率的かつ高精度なリアルタイムログ解析を実現します。

## 研究の焦点

### HELPのアーキテクチャと技術的詳細

HELPは、以下の3つの主要なモジュールで構成されています。

1. **オンライン階層的埋め込みモジュール**:
   - このモジュールは、ログのセマンティックおよび構造的意味を捉えたベクトル埋め込みを生成します。まず、OpenAIのテキスト埋め込みモデルを使用して、ログの意味的特徴をベクトルに変換します。その後、特定のドメインに合わせたファインチューニングを行い、ログテンプレートに基づくクラスタリングを行います。さらに、ログの単語数も埋め込むことで、クラスタリング精度を向上させています。

2. **コンテキスト認識パーシングモジュール**:
   - HELPは、大規模言語モデル（LLM）であるClaude-3.5-Sonnetを利用し、少数ショット学習とChain of Thoughtプロンプティングを組み合わせてログテンプレートを抽出します。具体的には、ログの動的要素と固定要素を識別し、それらをテンプレートとして抽出するプロセスを、文脈に応じて自動的に行います。

3. **反復リバランシングモジュール**:
   - ログドリフトを防ぐために、定期的に既存のログクラスタを見直し、必要に応じてクラスタの統合を行います。このプロセスは、ログ解析の正確性を維持し、誤検知のリスクを軽減するために不可欠です。

## 実験の概要と結果

### 大規模データセットでの評価

HELPは、14の大規模なログデータセットで評価され、そのパフォーマンスが従来の最先端ログパーサーを大きく上回ることが確認されました。特に、HELPは以下の点で優れた結果を示しています。

1. **F1スコアの向上**:
   - HELPは、他のオンラインパーサーと比較して62.9%高いF1スコアを達成しました。この向上は、HELPがログテンプレートのクラスタリングとパーシングを効率的に行うためであり、特に大規模なデータセットでその効果が顕著でした。

2. **リアルタイム処理の実現**:
   - HELPは、ログのクラスタリングとテンプレート生成を並列で処理できるため、数千のログをリアルタイムで処理することが可能です。これにより、システムの停止を最小限に抑え、迅速な障害対応が可能になります。

3. **Iudex社での実装事例**:
   - HELPは、Iudex社の商用観測プラットフォームに統合され、実運用環境での有効性が実証されました。具体的には、ログ解析の速度と精度が向上し、システムの安定性が大幅に改善されました。

### 実験結果の詳細と議論

HELPは、すべての評価指標で他のオンラインログパーサーを凌駕しました。特に、クラスタリングの精度を示すFGA（F1-weighted Grouping Accuracy）においては、現行の最先端パーサーであるDrainやUniParserと比較して、約60%から80%の向上を達成しています。また、HELPは、オフラインパーサーの代表であるLILACとも競合する性能を発揮し、特定のデータセットではLILACを超える結果を示しました。

### 詳細な分析と今後の展望

HELPの成功は、その技術的な革新だけでなく、実運用環境での適用可能性を証明した点にあります。今後の研究では、さらなるパフォーマンスの向上や、新たなドメインへの適用が期待されます。また、ログドリフトや新しいログ形式への対応をより強化するためのアルゴリズムの改善が必要です。

## 賛否両論

**賛成意見**
- HELPは、従来のログパーサーが抱える課題を効果的に解決し、リアルタイムのログ解析を可能にしました。その高い精度と効率性は、商用環境においても実証されています。

**反対意見**
- HELPの導入には初期のファインチューニングが必要であり、これが導入コストを増加させる可能性があります。また、極めて特化されたログテンプレートが生成される傾向があり、これは特定のユースケースでは適切でない可能性があります。

## まとめ

HELPは、階層的埋め込みを活用した新しいログパーシング手法として、リアルタイムでの高精度なログ解析を可能にします。その技術的革新は、今後のログ解析において重要な役割を果たすことでしょう。本論文で提案された手法が、今後の研究や実務においてさらなる発展を遂げることを期待しています。

この記事が皆さんの研究や実務に役立つことを願っています。ご質問やフィードバックがありましたら、コメント欄にお寄せください。
[Authentication and Authorization][認証と認可] SAML型 SSO

# SSOとは
ユーザ認証を一度だけ行うことで、許可された複数のサーバをアクセスについても認証する

# SAML型 SSOフロー
```mermaid
sequenceDiagram
    participant User as ユーザー
    participant App as サービスプロバイダー（SP）<br>アプリケーション
    participant IdP as IDプロバイダー（IdP）

    User->>App: ログインリクエスト
    App->>IdP: 認証リクエストをリダイレクト<br>（ログインURL, 識別子, サインオンURL, リレー状態, AD識別子）
    IdP->>User: 認証画面を表示
    User->>IdP: 認証情報を入力（ID・パスワード等）
    IdP->>IdP: ユーザー認証を実施
    IdP-->>User: 認証成功・トークン発行
    User->>App: 認証トークンを送信<br>（SAML証明書, リレー状態, 応答URL）
    App->>IdP: トークンの検証
    IdP-->>App: トークンが有効であることを確認
    App-->>User: ログイン成功・サービス利用開始

    User->>App: ログアウトリクエスト
    App->>IdP: ログアウトリクエストをリダイレクト<br>（ログアウト応答URL, ログアウト要求URL）
    IdP-->>User: ログアウト完了

    Note over App, IdP: フェデレーションメタデータは事前にSPとIdPで交換・設定

```

# SAML認証に関する主要な用語
## 基本概念
- `SAML`: 認証情報、属性情報、アクセス制御情報を異なるドメインに送信するためのWebサービスプロトコル  
- `フェデレーションメタデータ`: SPとIdPが相互に認識し合うための事前設定情報  
    - `SAML Metadata (IdP Metadata, SP Metadata)`, `Discovery Document (OIDC)`  
- `SAML証明書`: SAMLの通信をセキュアにするための証明書（署名・暗号化に使用）  
    - `IdP証明書 (IdPが署名するための証明書)`, `SP証明書 (SPが署名・暗号化するための証明書)`  

## 認証フロー関連
1. `ログインURL`: ユーザーが直接アクセスするIdPのログイン画面のURL  
    - `IdP Login Page`, `Identity Provider Login URL`  
1. `識別子`: アプリケーション（SP）からIdPへ認証リクエストを送る際に使用（SPを識別するため）  
    - `エンティティID`, `SPエンティティID`, `Issuer (発行者)`  
1. `サインオンURL`: IdP側の認証エンドポイント。SPはここにリダイレクトして認証を要求  
    - `SSOエンドポイント`, `Authorization Endpoint (OAuth, OIDC)`  
1. `リレー状態`: SSOの処理中にSPからIdPへ渡され、元のリクエストの状態を保持  
    - `RelayState (SAML)`, `state パラメータ (OAuth, OIDC)`  
1. `応答URL`: 認証後にユーザーをリダイレクトするURL（SP側の受け取りエンドポイント）  
    - `Assertion Consumer Service (ACS) URL`, `Redirect URI (OAuth, OIDC)`  

## ログアウト関連
1. `ログアウト要求URL`: SPがIdPへログアウトリクエストを送る際のエンドポイント  
    - `Single Logout Request Endpoint (SAML SLO)`, `End Session Endpoint (OIDC)`  
1. `ログアウト応答URL`: IdPがログアウト完了後にSPへリダイレクトするURL  
    - `Single Logout (SLO) Endpoint`, `Post Logout Redirect URI (OIDC)`  

## その他
- `AD識別子`: IdPがActive Directory（AD）と連携する際に使用する識別情報  
    - `User Principal Name (UPN)`, `ObjectGUID`, `ImmutableID`  

# その他のSSO
|型||
|:--|:--|
|Cookie型||
|リバースプロキシ型|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/99320486-2bab-9ecd-e758-1a2d3aebab11.png)|
|SAML型|[SAML型参照](#SAML型)|

# 参考リンク
- [令和4春41_リバースプロキシ](https://www.ap-siken.com/kakomon/04_haru/q41.html)
- [平成27秋29_SAML](https://www.ap-siken.com/kakomon/20_aki/q79.html)
- [SAML認証とは - IT用語辞典 e-Words](https://e-words.jp/w/SAML%E8%AA%8D%E8%A8%BC.html)
- [SAML認証とは？仕組みや流れ、メリット・デメリットを徹底解説 - GMOグローバルサイン](https://www.gmo.jp/security/security-all/information-security/blog/saml/)
- [SAMLとは？ SAML認証の仕組みとメリット - Okta](https://www.okta.com/jp/blog/2016/12/what-is-saml/)
- [SAMLをわかりやすく解説 - OneLogin](https://www.onelogin.com/jp-ja/learn/saml)
- [SAML認証とは？仕組みやメリットを大解説！ - Keeper Security](https://www.keepersecurity.com/blog/ja/2024/03/22/what-is-saml-authentication/)
Hyper-VマネージャーでリモートからAD外のHyper-Vホストを管理する

諸事情から、Hyper-Vホストは、Active Directoryに不参加としている。この場合に、Hyper-VマネージャでリモートのHyper-Vホストへ接続する方法について、コツを会得したのでメモしておく。
## NTLM通信を許可
### Hyper-Vホスト
```powershell:PowerShell
Enable-WSManCredSSP -Role Server
```
### クライアント
```powershell:PowerShell
winrm qc
Enable-WSManCredSSP -Role Client -DelegateComputer (ホスト名またはIPアドレス)
```
## グループポリシー設定
`gpedit.msc`で、コンピュータの構成→管理用テンプレート→システム→資格情報の委任 を開き、下記4項目を編集

1. 新しい資格情報の委任を許可する
`WSMAN/(ホスト名またはIPアドレス)`
2. 保存された資格情報の委任を許可する
`WSMAN/(ホスト名またはIPアドレス)`
3. NTMLのみのサーバー認証で新しい資格情報の委任を許可する
`WSMAN/(ホスト名またはIPアドレス)`
4. NTMLのみのサーバー認証で保存された資格情報の委任を許可する
`WSMAN/(ホスト名またはIPアドレス)`
`VMRDP/(ホスト名またはIPアドレス)`
↑このVMRDPを指定するのが、今回見つけたコツ。これを指定するまでは、VMへ接続するたびに「お使いの資格情報は機能しませんでした」と言われて再認証していた。だいぶ楽になった。

## 参考にしたサイト
https://www.vwnet.jp/Windows/WS16TP2/HVMan/Credential.htm

http://ayufishing.blog.fc2.com/blog-entry-14.html

https://hi-nemos.com/port/?port=2179
ポートフォリオサイトを公開しました！

初めての投稿を記念してポートフォリオサイトをご紹介します！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848925/cb97712c-f426-f89e-c91a-4dab69f602be.png)


## 概要
TypeScriptとNext.jsを中心に、フロントエンド開発のスキルやプロジェクトをまとめています。技術選定の背景や工夫した点についても今後記事化していく予定ですので、エンジニア仲間の皆さん、ぜひご覧ください！
🔗https://shunniehub.com

ver1としてリリースしたので、今後以下のような機能追加を検討しています。
* おしゃれなアニメーション追加
* 言語切り替え
* ダークテーマ切り替え

## 使用技術
* TypeScript
* Next.js
* React
* Firebase (App Hosting)


今後、プロジェクトで使用した詳細な技術スタックや、問題解決の過程についてもQiitaで共有していきます。お楽しみに！

また、別のプラットフォームでも発信を行っていますのでよかったら見に来てください！
* [X](https://x.com/nekonoko2323): 日々の情報発信やハブとして利用しています。
* [note](https://note.com/nekonoko_fi_lit): エンジニアとしての経験や資産形成に関する情報を発信中。
* [Zenn](https://zenn.dev/nekonoko2323): Qiitaと並行して技術記事を投稿しています。
画像をWebPに変換する方法

1. 以下のコマンドを実行して、WebPエンコーダーをインストールします：

   ```
   brew install webp
   ```

3. 変換したい画像があるディレクトリに移動します。

4. 以下のコマンドを使用して、画像をWebP形式に変換します：

   ```
   cwebp 元の画像ファイル名 -o 出力ファイル名.webp
   ```

   例：`cwebp test.jpg -o test.webp`

この方法で、JPG/JPEG、TIFF、PNG、WebPファイルを圧縮されたWebP画像に変換できます。
[TypeScript] Pickを利用して素早くテストコードを書く

以下のようなケースを考える
``` ts
interface Customer {
    name: string;
    email: string;
    address: string;
    age: number;
}

const checkEmail = (customer: Customer) => {
    console.log(customer.email);
};
```

`checkEmail`のようにCustomerの中の要素一つだけを使うときに、Customerに関するもの全てを書く必要がある。
``` ts
checkEmail({
    name: 'test',
    email: 'fuga@example.com',
    address: 'here',
    age: 30
});
```
要素が多くなるとこうやってモックを作ることが厳しくなる。特に階層が深いデータだとすぐ書けない。

### 必要な要素だけのオブジェクトを定義するのもあり

メールだけ確認するのでメールだけ渡す
``` ts
const checkEmail = (customer: { email: string }) => {
    console.log(customer.email);
};

checkEmail({email: 'test@example.com'});
```

しかし、誤字があってもそれに気づかない可能性がある。
``` ts
const checkEmail = (customer: { mail: string }) => {
    console.log(customer.email);
};
```

### Pickを使おう
Pickを使うことでCustomerに基づいてメールだけの型定義ができるようになる。
しかも、完全な形のCustomerのデータを入れてもエラーが出ない。
``` ts
const checkEmail = (customer: Pick<Customer, 'email'>) => {
    console.log(customer.email);
};

const customer = {
    name: 'test',
    email: 'fuga@example.com',
    address: 'here',
    age: 30
}

// 両方いける
checkEmail(customer);
checkEmail({email: 'fuga@example.com'});
```

これは、Customerの中に`{email: string}`があるとみなされるTypeScriptの構造的タイピングの特徴から来るものである。
`{email: string}`を`extends`したこととして扱われるから。
Lang Chain でRAGチャットを構築する

### Lang Chain でRAGチャットを構築する

AIと自然言語処理の分野は日々進化しており、既存のツールを活用してカスタマイズされたソリューションを作成することが重要です。今回、Langchainフレームワークを活用して、医療対話を処理し、適切な応答を生成するPythonベースのソリューションを開発しました。このコードについて詳しく解説し、自分のプロジェクトで実装する方法を紹介します。

#### コードの概要

このコードの主な目的は、患者と医者の間の医療対話を処理できるシステムを構築することです。データセットと埋め込み技術を活用することで、医療に関する質問に対して適切な応答を提供できるようになります。以下は、コード全体です。

```python
import pandas as pd
from datasets import load_dataset
from langchain import PromptTemplate, LLMChain
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain.document_loaders import TextLoader
from langchain.indexes import VectorstoreIndexCreator
from langchain.embeddings import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# データセットの読み込み
dataset = load_dataset('medical_dialog', 'processed.en')
df = pd.DataFrame(dataset['train'])

# 対話データの処理
dialog = []
patient, doctor = zip(*df['utterances'])
for i in range(len(patient)):
  dialog.append(patient[i])
  dialog.append(doctor[i])

df_dialog = pd.DataFrame({"dialog": dialog})

# 成形終了したデータセットを保存
df_dialog.to_csv('medical_data.txt', sep=' ', index=False)

# ベクトルストアインデックスの作成
loader = TextLoader('medical_data.txt', encoding="utf-8")
index = VectorstoreIndexCreator(embedding=HuggingFaceEmbeddings()).from_loaders([loader])

# システムへのクエリと応答の生成
results = index.vectorstore.similarity_search("what is the solution for soar throat", k=4)
context = "\n".join([document.page_content for document in results])

template = '''
please use the following content to answer questions.
Content : {context}
-----------------
Question : {question}
Answer : Let's think step by step
'''
llm = ChatOpenAI(model_name="gpt-3.5-turbo-0125")
prompt = PromptTemplate(template=template, input_variables=["context", "question"]).partial(context=context)
llm_chain = LLMChain(prompt=prompt, llm=llm)

print(llm_chain.run("what is the solution for soar throat"))
```


この記事がコードの動作についての理解を深め、AIと医療対話の世界にさらに踏み込むきっかけとなれば幸いです。

ありがとうございました！
pythonでgnuradio その23

# 概要
pythonでgnuradioやってみた。
練習問題やってみた。

# 練習問題
vocoderを使え。

# サンプルコード

```
from gnuradio import gr
from gnuradio import audio
from gnuradio import blocks
from gnuradio import filter
from gnuradio import vocoder

def build_graph():
	sample_rate = 8000
	scale_factor = 32000
	tb = gr.top_block()
	src = audio.source(sample_rate)
	src_scale = blocks.multiply_const_ff(scale_factor)
	interp = filter.rational_resampler_fff(8, 1)
	f2s = blocks.float_to_short()
	enc = vocoder.cvsd_encode_sb()
	dec = vocoder.cvsd_decode_bs()
	s2f = blocks.short_to_float()
	decim = filter.rational_resampler_fff(1, 8)
	sink_scale = blocks.multiply_const_ff(1.0 / scale_factor)
	sink = audio.sink(sample_rate)
	tb.connect(src, src_scale, interp, f2s, enc)
	tb.connect(enc, dec, s2f, decim, sink_scale, sink)
	return tb

if __name__ == '__main__':
	tb = build_graph()
	tb.start()
	input('Press Enter to exit: ')
	tb.stop()
	tb.wait()

```

以上。
Ubuntuのパッケージ更新時に出る"Which services should be restarted?"や"Pending kernel upgrade"のダイアログをスキップする方法

## はじめに

以下のような画面のことです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304979/3197aa4b-7025-f8c6-404b-391632d7a29e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304979/0bb57ee3-3138-9c78-da24-73fa52fb1058.png)

せっかく`apt upgrade`の`-y`オプションなどでプロンプトをスキップしても、これらが出るとエンターキーを押すために画面の前で待たなければなりません。

アップグレード中にコーヒーでも淹れて戻ってきたら完了している、という理想を実現するために、これらをスキップしましょう！

## 方法

以下のコマンドを実行して`99_skip_dialog.conf`ファイルを作成します。

```
sudo tee /etc/needrestart/conf.d/99_skip_dialog.conf <<EOF
\$nrconf{kernelhints} = '0';
\$nrconf{restart} = 'a';
EOF
```

快適な自動化ライフを😊
DTOとドメインモデルの使い分け つづき

ドメインを定義しているファイルにDTOっぽいなと思えるコードが入っているまたは、入れることを設計思想に組み込むこともあります。
こうなるとややこしいし、複雑になっていきます。
なので、、、、↓↓↓↓↓↓↓↓

### 原則として分離
ドメインモデルとDTOは役割が異なるため、通常は別々に定義され、別のファイルやパッケージで管理されます。これにより、責任の分離が保たれ、システムの設計がより明確になり保守性も高まります。

- ドメインモデル: ビジネスロジックを持ち、データの整合性を維持し、ドメインルールを表現します。
- DTO: データ転送に特化しており、ビジネスロジックは含まず、データの構造や形式を担います。

### DTOがドメインに入るケース
ただし、以下のような特殊なケースでは、ドメインモデル内にDTO的な要素が含まれることがあります。

- 値オブジェクト: ドメインモデル内で値オブジェクトとして定義されるクラスは、DTOと類似したシンプルな構造を持つ場合があります。ただし、値オブジェクトは不変であり、ビジネスルールを持つことができます。
- 内部的なDTO: 特定のドメインサービスが、外部に公開されない内部的なデータ転送のためにDTOを使用することがあります。この場合も、DTOはドメインの一部として機能しますが、通常は外部に直接公開されません。
- 単純なケースの一元化: 非常にシンプルなドメインモデルや小規模なプロジェクトでは、設計の複雑さを避けるために、ドメインモデルとDTOを同じファイルに定義することがあるかもしれません。しかし、これにはリスクが伴い、プロジェクトが成長するにつれて保守性に問題が生じる可能性があります。

### 設計思想として組み込む場合の注意点

- 責任の明確化: ドメインモデルとDTOの役割が明確に区別されていないと、コードが混乱し、保守が困難になる可能性があります。
- 拡張性の確保: ドメインモデルが成長する中で、DTOをドメインモデル内に保持すると、将来的に分離が難しくなることがあります。
- テストの分離: ドメインロジックのテストとDTOのテストは分けて行う方が望ましいです。一緒にしてしまうと、どちらかの変更がもう一方に影響を与えるリスクが高まります。

### まとめ
ドメインモデルとDTOを同じファイルに含めることは、設計思想として避けるのが一般的です。責任の分離を徹底することで、コードの保守性や拡張性が向上します。ただし、特殊なケースやプロジェクトの要件によっては、そのようなアプローチが選ばれる場合もありますが、設計の複雑さや将来の拡張性を考慮したうえで判断することが重要です。

ご不明な点があれば、お気軽にご質問ください。また、行き届いていない説明があればご指摘いただきたいです
*.min.jsより遥かに小さい爆縮js file

minifyだけでは満足できない人向けの企画。今まで散々その手の記事を書いてきましたが、その応用という事になります。
圧縮率も重要ですが展開速度も重視したいところ。自己展開する事になるので復号処理も小型である必要があります。
## 爆縮形態
凄まじい圧力によって一瞬にして潰れてしまったjs fileの形態の1つ。自己展開能力により一瞬にして再生する。
ただし一瞬では潰れ切らずに、二瞬、百瞬と時間がかかりまくる事もざらにある。再生も同様である。そこは爆縮者の腕にかかっている。

## 爆縮対象
以下のfileとなります(link先は配布元)。随時追加予定。他にも要望があれば増やしていきます。ついでに元の大きさと爆縮後の大きさも掲載しておきます。
* [angular-1.8.2.min.js](https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js) 177324 -> 64656(36.4%)
* [bootstrap.bundle-5.3.0.min.js](https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js) 80421 -> 25704(31.9%)
* [jquery-3.7.1.min.js](https://code.jquery.com/jquery-3.7.1.min.js) 87526 -> 33620(38.4%)
* [three.module-0.167.1.min.js](https://cdn.jsdelivr.net/npm/three@0.167.1/build/three.module.min.js) 684042 -> 157710(23%)
* [vue.global-3.4.38.prod.js](https://cdn.jsdelivr.net/npm/vue@3.4.38/dist/vue.global.prod.js) 146843 -> 56783(38.6%)
* [vue.esm-browser-3.4.38.prod.js](https://cdn.jsdelivr.net/npm/vue@3.4.38/dist/vue.esm-browser.prod.js) 150058 -> 57855(38.5%)
* [p5-1.10.0.min.js](https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.10.0/p5.min.js) 1041843 -> 225805(21.6%)
## 成果物
さすがにここに丸ごと掲載するには余白が狭過ぎるので、[github](https://github.com/da0ka/min2js)に放り込んでおきます。ちなみに文字符号はUTF8形式
M5Stack Core2 for AWS チュートリアルでつまづいたこと

# はじめに
AWSの勉強と、遊びでセンサデータを集めることをしてみかったったので、
M5Stack Core2 for AWS を触ってみた。

https://www.switch-science.com/products/6784?srsltid=AfmBOooI5ypgAtr-6STw4OY7bKpKlL289vwVjbV1VAyj68utyeG-_Q3J

チュートリアルを参考に、AWSへの接続を試みたが、
一筋縄ではいかないチュートリアルであったので、
つまづいたポイントを、メモすることにした。

https://core2-for-aws-iot-kit.m5stack.com/ja/getting-started/

# 本ページの目的
M5Stack Core2 for AWS のチュートリアルで、
説明が足らなかったり、上手くいかなかったところをメモする。

私のように「IoT遊びをしてみたい！」という人が、
チュートリアル見ながらAWSに接続できるように。

なお、現在進行形でチュートリアルを進めながら書いているので、
内容は都度アップデートしていく予定。

# QRコードが出ない
環境セットアップの「デバイスの登録とプロビジョニング」の部分。
チュートリアルだと、以下のコマンドを実行して、しばらくするとQRコードが出るように書かれていた。
```
pio run --environment core2foraws --target monitor
```
しかし、このコマンドはファームのアップロードを行わないので、これだけでは、QRコードは出ない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595683/6a354072-1a0d-b3fe-386e-c3a931f7cb31.png)

VSCode の下の方にある「→」ボタンを押すと、ファームがアップロードされる。
このボタンをクリックしてから、上記モニタのコマンドを投げると、QRコードが表示される。

##### 参考文献

https://qiita.com/fukuebiz/items/73339f158337348ca8cd

# AWS CLI 動作確認ができない
チュートリアル「Lチカ」の[AWS CLI 動作確認](https://core2-for-aws-iot-kit.m5stack.com/ja/blinky-hello-world/prerequisites/)の部分。
```
aws iot describe-endpoint --endpoint-type iot\:Data-ATS
```
このコマンドを投げたところ、2回エラーが出た。
### IAM ポリシーエラー
`An error occurred (AccessDeniedException) when calling the DescribeEndpoint operation:`
AWS CLI で使用しているIAMアカウントのポリシーが不足しているとのこと。
この場合は、IoT関連のポリシーを、ユーザーに許可すればよい。

![スクリーンショット 2024-08-18 144229.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595683/34ca4305-4a89-f600-67b7-be4352b25567.png)

上記例では「AWSIoTFullAccess」をアタッチしたが、
過剰だと思うので、実際は使用するもののみアタッチすればよい。
よくわからない場合は、上記のようにFullAccessをアタッチする。

### リクエストエラー？
`An error occurred (InvalidRequestException) when calling the DescribeEndpoint operation: `
よくわからないが、コマンドが間違っていたみたい。
チュートリアルのコマンドの iot の後ろの\を取り除いたら、コマンド実行できた。
```
aws iot describe-endpoint --endpoint-type iot:Data-ATS
```

[AWS CLI コマンドリファレンス](https://docs.aws.amazon.com/cli/latest/reference/iot/describe-endpoint.html)だと\がないので、チュートリアルが間違いっぽい。

# Package.json が見つからないエラー
[デバイス証明書の取得とAWS IoTへthingの登録](https://core2-for-aws-iot-kit.m5stack.com/ja/blinky-hello-world/device-provisioning/)でコマンドエラー。
```
pio run -e core2foraws-device_reg -t register_thing
```
これを実行すると、以下のエラーが出た。
`“MissingPackageManifestError: Could not find one of ‘package.json’ manifest files in the package” `
どうやら前のファー？のpackageデータ？が残っていたみたいなので、
ユーザーフォルダ/ユーザー名/.platformio/packagesの中身を全部削除したら、エラーが消えた。

##### 参考文献
https://note.com/gu_pen/n/nca6059a595a7
paiza * qiita記事投稿キャンペーンに参加してみた：Bランクスキル「神経衰弱 C編」

# はじめに
paizaとqiitaの記事投稿キャンペーンに参加してみました。の流れでBランクの問題にもチャレンジ内容を解説しました。
・関連記事
https://qiita.com/hyonkichi/items/b17aef92bb560d6a53f3
https://qiita.com/hyonkichi/items/33890d18cf8d2ff57e0e

# 問題
https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration

# 解答コード
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
    // 自分の得意な言語で
    // Let's チャレンジ！！
    char str[1000];
    int i,j;
    int height, width, players_num, record_num;
    int trump[13][13]={0};
    int record[200][4]={0};
    int result[10]={0};
    int cur_num;
    char *pstr;
    
    // H, W, N取得
    fgets(str, sizeof(str), stdin);
    sscanf(str, "%d %d %d", &height, &width, &players_num);

    // トランプ情報取得
    for(i=0; i<height; i++)
    {
        fgets(str, sizeof(str), stdin);
        pstr = strtok((char*)str, " ");
        for(j=0; j<width; j++)
        {
            trump[i][j] = atoi(pstr);
            pstr = strtok(NULL, " ");
        }
        
    }
    
    // 記録数取得+枚数集計
    fgets(str, sizeof(str), stdin);
    sscanf(str, "%d", &record_num);
    
    cur_num=0;
    for(i=0; i<record_num; i++)
    {
        fgets(str, sizeof(str), stdin);
        sscanf(str, "%d %d %d %d", &record[i][0], &record[i][1], &record[i][2], &record[i][3]);
        
        //トランプ一致チェック
        if( trump[record[i][0]-1][record[i][1]-1] == trump[record[i][2]-1][record[i][3]-1] )
        {
            result[cur_num] += 2;
        }
        else
        {
            cur_num++;
            if(cur_num==players_num)
            {
                cur_num=0;
            }
        }
    }
    
    //結果出力
    for(i=0; i<players_num; i++)
    {
        printf("%d\n",result[i]);
    }
    return 0;
}
```
# 解説
プログラムの流れを説明します。

## 変数の定義と初期化:
trump[13][13]は、トランプの情報を格納する2次元配列です。この配列には、各トランプカードの値が格納されます。
record[200][4]は、各プレイヤーの行動記録を格納する2次元配列です。各行動は4つの整数で表され、それぞれのプレイヤーが選んだトランプの座標を表します。
result[10]は、各プレイヤーの得点を格納する配列です。
cur_numは、現在どのプレイヤーの得点を計算しているかを追跡する変数です。
pstrは、strtok関数を用いて文字列をトークンに分割するためのポインタです。

## トランプ情報の入力:
最初に、トランプの高さ、幅、プレイヤー数を入力として受け取ります。
次に、トランプのカード情報を2次元配列trumpに格納します。この情報は、各行に対応する文字列を分割し、atoi関数を用いて整数に変換して配列に格納します。

## プレイヤーの行動記録の入力と処理:
プレイヤーの行動記録の数を取得し、その数だけ繰り返し処理を行います。
各行動記録は、4つの整数値（開始位置の行と列、終了位置の行と列）で表されます。
trump配列の指定された位置にあるカードが一致するかをチェックし、一致する場合は、現在のプレイヤーに2点を加算します。そうでない場合は、次のプレイヤーに移り、処理を続けます。

## 得点の集計と出力:
最終的に、各プレイヤーの得点をresult配列に集計し、それぞれの得点を出力します。

# 終わりに
お盆休みも今日で最終日。
Aランクまで投稿できるかなぁ・・
Pythonでリスト内の最頻値を簡単に求める方法

## はじめに

こんにちは！今回は、Pythonを使ってリスト内の最頻値（最も頻繁に出現する要素）を求める簡単な方法をご紹介します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/8bc2c6bf-fd2a-a699-d206-200de32c12bb.png)

## はじめに

データ分析や統計処理をする際、ある集合の中で最も頻繁に現れる値（最頻値）を求めることがよくあります。Pythonには、この処理を簡単に行うための便利な方法がいくつかあります。

## 方法1: Collectionsモジュールを使う

Pythonの標準ライブラリにある`collections`モジュールの`Counter`クラスを使うと、最頻値を簡単に求めることができます。

```python
from collections import Counter

def find_mode(numbers):
    counter = Counter(numbers)
    return counter.most_common(1)[0][0]

# 使用例
numbers = [1, 2, 3, 2, 4, 2, 5, 2, 6]
mode = find_mode(numbers)
print(f"最頻値は {mode} です")
```

### 出力例
```
最頻値は 2 です
```

この方法の利点は、コードが簡潔で理解しやすいことです。`Counter`クラスが要素の出現回数を数え、`most_common(1)`で最も頻度の高い要素を取得します。

## 方法2: リスト内包表記を使う

もし標準ライブラリを使いたくない場合は、リスト内包表記を使って同様の処理を行うことができます。

```python
def find_mode(numbers):
    return max(set(numbers), key=numbers.count)

# 使用例
numbers = [1, 2, 3, 2, 4, 2, 5, 2, 6]
mode = find_mode(numbers)
print(f"最頻値は {mode} です")
```

### 出力例
```
最頻値は 2 です
```

この方法は、`set`を使って重複を除いた要素のリストを作成し、各要素の出現回数を`count`メソッドで数えています。`max`関数と`key`パラメータを使って、最も出現回数の多い要素を見つけています。

## 注意点

- 同じ頻度で出現する要素が複数ある場合、これらの方法では最初に見つかった要素が返されます。
- 大規模なデータセットの場合、`collections.Counter`を使用する方が効率的です。

## 参考情報

1. Python公式ドキュメント - collections.Counter:
   https://docs.python.org/3/library/collections.html#collections.Counter

   `Counter`クラスの詳細な使い方や、他のメソッドについて学べます。

2. Python公式ドキュメント - list.count():
   https://docs.python.org/3/tutorial/datastructures.html#more-on-lists

   リストの`count()`メソッドの詳細について確認できます。

3. Python公式ドキュメント - max():
   https://docs.python.org/3/library/functions.html#max

   `max()`関数の詳細な使い方、特に`key`パラメータの使用法について学べます。

これらの公式ドキュメントを参照することで、今回紹介した方法の背景にある概念や、より高度な使用方法について理解を深めることができます。

## まとめ

Pythonを使えば、リスト内の最頻値を求めるのは非常に簡単です。用途や好みに応じて、`collections.Counter`を使う方法とリスト内包表記を使う方法を使い分けると良いでしょう。

以上、Pythonでリスト内の最頻値を求める簡単な方法をご紹介しました。この記事が皆さんのコーディングライフの助けになれば幸いです！
RubyのREPLとデバッグ：初心者から見たツールの進化と効率化

> Rubyの初心者として、最近私はRubyのREPL（Read-Eval-Print Loop）ツールとデバッグ機能について深く探求しました。この過程は、Rubyへの理解を深めただけでなく、ツールの進化と開発効率の関係について考えさせられる機会となりました。

### RubyのREPLツール：IRBからPryへ
Ruby公式が提供するIRB（Interactive Ruby）は強力なREPLツールですが、コミュニティ主導の需要により、Pryのようなさらに高機能なツールが生まれました。Pryはコード探索、コンテキストナビゲーション、リアルタイム編集など、より高度な機能を提供しています。

例えば、Pryを使用すると、クラスやメソッドの定義を簡単に確認できます：

```ruby
[3] pry(main)> show-source Array#map

From: array.c (C Method):
Owner: Array
Visibility: public
Number of lines: 17

static VALUE
rb_ary_map(VALUE ary)
{
    # ... メソッドの実装 ...
}
```
この機能により、コードの探索や学習の効率が大幅に向上します。

### デバッグ能力の重要性
プログラミングの旅で、私はデバッグ能力の重要性を徐々に認識しました。特に、Rubyのような開発者に大きな自由を与える言語では、デバッグツールの熟練した使用が非常に重要になります。

pry-byebugを組み合わせることで、Rubyコード内にブレークポイントを設定し、コードを段階的に実行できます：

```ruby
[14] pry(main)> require 'pry-byebug'
[15] pry(main)> def complex_method(x)
[15] pry(main)*   y = x * 2
[15] pry(main)*   binding.pry  # ブレークポイントの設定
[15] pry(main)*   z = y ** 2
[15] pry(main)*   z - x
[15] pry(main)* end
```
この対話型デバッグ方法により、問題の特定と解決が容易になります。

### ツールの進化と開発者の役割
ツールの進化過程は興味深いサイクルを示しています：

公式ツール（IRBなど）が出発点となる
開発者のニーズに応じて、新しいツール（Pryなど）が創造される
公式チームが価値ある機能を公式ツールに統合する
新たな革新が生まれる
このサイクルは、オープンソースコミュニティと公式開発者間の良好な相互作用を反映しており、ツールとエコシステム全体の進歩を促進しています。

### 最適な実践の重要性
ツールの選択に過度に焦点を当てるよりも、一般的な問題に対する最適な実践方法に注目することが重要です。RubyとRailsは多くの問題を解決し、多くのシナリオで効率的な開発を可能にしています。

### 結論

Rubyの世界では、ツールの選択と学習効率のバランスを取ることが重要です。REPLとデバッグツールの適切な使用は、開発プロセスを大幅に改善し、問題解決能力を向上させます。同時に、コミュニティと公式開発者の協力が、継続的な革新と進歩を促進していることを認識することも重要です。

Rubyの初心者として、これらのツールと概念を学ぶことは、言語自体の理解を深め、より効率的な開発者になるための重要なステップだと感じています。
FreeBSD+sendmail環境でSPF, DMARCを設定

# はじめに
SendmailとFreeBSDを使用した環境でSPFとDMARCを設定してみました。
受信したメールのエンベロープFromとヘッダFromが異なる場合に受信拒否できることを確認します。

DMARCは、Googleのガイドラインにて対応が求められたこともあって、急速に普及が進んでいます。

DMARCについては、下記ブログにて分かりやすく説明されております。
>ベアメール : DMARCとは？ 仕組みやメリット、導入方法まで解説
>(https://baremail.jp/blog/2022/05/09/2490/)
# 環境
FreeBSD : 14.1
sendmail : 8.18.1
bind : 9.18.27
opendmarc : 1.4.2
# SPF, DMARCの設定
## opendmarcの導入・設定
SPF, DMARCはどちらもopendmarcを使用して設定できます。

pkgを用いてopendmarcをインストールします。
```
# pkg install opendmarc
```
opendmarcをインストールすると、/usr/local/etc/mail内にopendmarc.conf.sampleというファイルができているはずです。

conf.sampleファイルを用いてconfファイルを作成します。
```
# cp /usr/local/etc/mail/opendmarc.conf.sample /usr/local/etc/mail/opendmarc.conf
```
confファイルを編集します。
```opendmarc.conf
# DMARC検証で失敗した場合にメッセージの受信を拒否する
RejectFailures true

# opendmarcによってSPF検証を実施するために、ヘッダのSPF検証結果を無視する
SPFIgnoreResults true

# opendmarcがSPF検証を実施する
SPFSelfValidate true
```
confファイルの内容について、詳しくは下記ドキュメントをご参照ください。
>opendmarc.conf(5)
>https://manpages.debian.org/unstable/opendmarc/opendmarc.conf.5.en.html

設定を適用・反映するためにopendamrcを再起動します。
```
# service opendmarc restart
```
## sendmailの設定
sendmail.mcにMilter設定を追記します。
```sendmail.mc
INPUT_MAIL_FILTER(`opendmarc', `S=inet:8893@localhost')
```
設定を適用・反映します。
```
# cd /etc/mail
# make
# service sendmail restart
```
## DNSの設定
ゾーンファイルに以下のSPFレコードとDMARCレコードを追記します。
```hogehoge.local.zone
        IN      TXT     "v=spf1 ip4:送信元のIPアドレス -all"
_dmarc  IN      TXT	    "v=DMARC1; p=reject;"
```
設定を適用・反映します。
```
# service named reload
# service named restart
```
# メール送信テスト
## 受信拒否確認
SPFレコードは登録済みなattack.localからahoaho.localへメールを送信します。
以下のsendmailコマンドでメール送信し、ヘッダFromはhogehoge.localとします。
```attacker@attack.local
sendmail -t <<EOL
From: mail@hogehoge.local
To: mail@ahoaho.local
Subject: testmail
test 2024/8/18
EOL
```
すると、メールは受信されず、maillogファイルにエラーコードが表示されます。
```maillog
sm-mta[47351]: 44L5i8ei047351: Milter: data, reject=550 5.7.1 rejected by DMARC policy for hogehoge.local
```
受信拒否を確認できました。
## 正常なメールの受信確認
hogehoge.localからahoaho.localにメールを送信し、ヘッダFromとエンベロープFromに差異がない場合は、以下のメールヘッダが追加されます。
```
Authentication-Results: ahoaho.local; dmarc=pass (p=reject dis=none) header.from=hogehoge.local
Authentication-Results: ahoaho.local; spf=pass smtp.mailfrom=hogehoge.local
```
# おわりに
SPFとDMARCの組み合わせは理解しやすいフィッシングメール対策となっています。
今回はDKIMを導入しませんでしたが、ぜひDKIMも取り入れた設定にもチャレンジしてみてください！
AWS のリセール（請求代行サービス）って何？


意外と知られていない AWS の調達についてです。

## AWS のリセール（請求代行サービス）とは

AWS のリセールとは、リセラーが利用者に AWS を販売することです。利用者はリセラーと契約することで AWS を利用します。AWS への支払いはリセラーが行うため、請求代行サービスとも呼ばれます。

![resale.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/1764d938-d47b-2927-8492-d7864f6c827a.png)

リセラーについては「AWS リセール」「AWS 請求代行」等で検索してみてください。これらを利用するメリット・デメリットは以下の通りです。

:::note warn
一般的な話の記載にとどまります。実際に契約する際には、各リセラーのサービス内容や利用規約等をよく確認してください。
:::

## メリット

### AWS 利用料が安くなる

直接契約で利用する場合より、利用料が安くなります。 5% 前後のディスカウント（割引）が多いようです。少しでも利用料を安くしたい場合は検討の価値アリです。非常に大きなワークロードであれば、直接契約でもディスカウントを受けることができる可能性があります。

:::note
**なぜ安くなるのか？**
リセラーは AWS から大幅なディスカウントを受けています。数多の利用者による AWS リソースへのコミット、後述のサポート受付などにより、リセラーは通常より安い価格で AWS を提供できます。そのディスカウントの一部を利用者への料金割引として還元しているという仕組みです。
:::

### 請求書払いができる

AWS は通常クレジットカードでの支払いとなります。請求額が多い場合は特別に請求書払いへ切り替えることもできますが、クレジットカードの登録ができない場合に利用できます。

https://aws.amazon.com/jp/aws-jp-faq/

### 円建てで支払いできる

通常はドル建てでの支払いになります。社内稟議や支払いフローとしてこれが許容できない場合に利用できます。一方リセラー経由でも為替レートの変動に対して影響を受けるため、注意が必要です。

### 追加コストなしでサポートが利用できる

直接契約した際に無料で利用できる「ベーシック」サポートプランでは、アカウント・請求・サービスクォータ緩和についてのみケース起票ができます。開発時のサポートや運用時のトラブルシュート等が必要な場合、有料のサポートプランへの加入が必須です。

https://aws.amazon.com/jp/premiumsupport/plans/

一方リセラーは自身のポータルサイトを用意しており、追加コストなしでサポートを利用することが可能です。またリセラーで解決できない問題は、AWS へ取り次いでくれます。

### リセラーの構築・運用サービスが受けられる

リセラーが AWS の構築・運用サービスを行なっている場合は、そのサービスの利用にリセラー払い出しのアカウントが必要、もしくはリセラー払い出しのアカウント所持により有利に話が進められるといったケースがあります。

## デメリット

### ルートユーザーが利用できない

ルートユーザーはリセラーが管理し、利用者は `Administrator` 権限相当の IAM ユーザーを受け取ります。そのためルートユーザーが必要な作業はリセラーへ作業依頼する必要があります。

:::note
**ルートユーザーはいつ使う？**
以下のような場合です。最もよくあるケースは、バケットポリシーを誤って設定し S3 バケットに誰もアクセスできなくなった際の復旧などです。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/root-user-tasks.html

ただし上記以外にもルートユーザーが必要なケースが考えられます。例えば以下ドキュメントでは `AWS Fargate` の「タスク廃止の待機時間」の設定変更にルートユーザーを要求しています。

> 待機時間を設定するには、ルートユーザーとして `put-account-setting-default` または `put-account-setting` を実行します。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/task-maintenance.html#task-retirement-timeline
:::

### 利用できない AWS サービスがある

有名な例では、リセラー自身が利用者のアカウントを管理するために利用しているため `AWS Organizations` が使えないなどです。こちらはリセラーの上位プランや追加オプションの契約で開放できるケースが増えてきました。

他にも サービスデリバリープログラム (SDP) 認定の関係で、リセラーによっては再販できない、割引が適用されないサービスがあるので丁寧な確認が必要です。

:::note warn
リセラー契約の前に想定ワークロードを作成し、問題ないか相談しましょう。
:::

### AWS サポートに直接起票できない

リセラーはリセール条件より、利用者からの問い合わせを自社のポータルサイト等で一次受付し、回答する義務があります。また利用者はマネジメントコンソールからサポートケースを起票することはできません。

サポート回答の品質やリードタイムはリセラーによって変わります。AWS でないと回答できないケースは取り次いでくれるものの、直接起票と比べるとストレスを感じる可能性は増えるでしょう。

### マネジメントコンソールから料金を確認できない

利用者やリセラー自身も特殊なディスカウントを受けているため、マネジメントコンソールの Billing から料金を確認することができません。

リセラーの料金確認ポータルが使いにくい以外に、自家製のコスト分析ツールが導入できないなどのリスクも考えられます。

## まとめ

上記から AWS の調達にあたっては以下戦略が最適だと考えられます。

- リセラーを利用する
  - 小～中規模のワークロードである
  - 請求や支払いに条件がある
  - リセラーのサポートや構築・運用サービスを受けたい
- AWS と直接契約する
  - 大規模なワークロードである
  - サポートや利用サービスにこだわりがある
  - リソースは自社でコントロールしたい

個人的にはリセラー契約の場合に、優秀な AWS サポートに直接ケースを起票できないのが痛手だと感じたことがあります。検討の際には注意していただきたいです。合わなければリセラー変更や AWS との直接契約も視野に入れてほしいと思います。
DTOとドメインモデルの使い分け

いまだに混同してしまうことがあるので投稿します。
意味を考えると意外が出るが、コードだけ見ると悩ましくなってしまう
命名で分ける方法が私は最も一般的に思いますが、実際のコード設計ではアーキテクトの考えが入るので、難しいなと思いました
ドメインを定義しているファイルにDTOっぽいなと思えるコードが入っている時もあるので、以下に見分けの援助になれそうな内容を投稿します。

1. **異なる責任と役割**:
    - **ドメインモデル**: ビジネスロジックと状態管理を担います。ドメインモデルは、システムのビジネスルールを表現し、データの整合性を保つために存在します。
    - **DTO**: データの転送や表示に特化し、外部システムやレイヤーとのやり取りを容易にします。DTOはビジネスロジックを持たず、データの構造やフォーマットを整えるためのものです。

2. **DTOとドメインモデルの役割の違い**:
    - **入力DTO**: 外部から受け取ったデータを、ドメインモデルが理解できる形式に変換するために使用されます。たとえば、ユーザーがフォームに入力したデータを受け取り、内部のビジネスロジックで利用するために変換します。
    - **出力DTO**: ドメインモデルで処理した結果を、外部システムやUIが理解できる形式で提供するために使用されます。ビジネスロジックの結果を適切に整形して外部に返すためのものです。

3. **DTOとドメインモデルの重複を避けるために**:
    - **DTOはシンプル**: DTOは通常、データ転送のためのシンプルな構造で、ビジネスロジックを含まないため、ビジネスロジックが含まれるドメインモデルとは異なります。
    - **ドメインモデルは複雑**: ドメインモデルはビジネスルールや状態管理を含むため、より複雑な構造を持つことがあります。これにより、システム内でのデータの整合性を保ちます。

### **まとめ**

DTOとドメインモデルは役割が異なるため、通常は別々に定義します。DTOはデータ転送に特化し、ドメインモデルはビジネスロジックと状態管理を担当します。この分離により、システムの各レイヤーが独立して保守・拡張できるようになり、より柔軟で理解しやすい設計が可能となります。

ご不明な点があれば、お気軽にご質問ください。また、行き届いていない説明があればご指摘いただきたいです
さくらのVPSを使ってGROWIサーバーを立てる

[さくらのVPS](https://vps.sakura.ad.jp/)では、スタートアップスクリプトという仕組みがあります。そこでアプリケーションを選ぶだけで、自動的にインストールと設定が行われます。[GROWIのスクリプトも用意されている](https://vps.sakura.ad.jp/news/vps-ss-ubuntu_growi/)ので、試してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/dfe12332-e671-b60c-1fc8-5ebe2b5eab1d.png)


## 注意点

スタートアップスクリプトの設定で、FQDN（Fully Qualified Domain Name）を入力する箇所があります。ドメインはオプションですが、入力するとLet's EncryptでSSL証明書を取得して設定も行ってくれます。

ただ、これはあらかじめVPSのIPアドレスが分かっていないといけないので、新規VPS購入時には無理そうです。一度VPSを立ち上げた後、サーバー再インストールの際に指定する方法となります。

## 用意するもの

- さくらのVPS
- ドメイン（オプション）

## 利用するOS

OSはUbuntu 22.04 amd64を選択します。最新の24.04にはまだ対応していないので注意してください。

![FireShot Capture 448 - サーバーの設定 - さくらのVPS コントロールパネル - secure.sakura.ad.jp 448.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/e82d51ec-6d5c-678e-6c30-807fa3f9955a.jpeg)


### メモリ

個人用途であれば1GBでもいけるかも知れませんが、2GB以上を推奨します。

via [社内wiki選定にGROWIをおすすめする理由](https://zenn.dev/noxis/articles/fc4c456e183555)

石狩第1リージョンなら少し安くて、年間払いで19,118円（月1,593円）でした。

### スタートアップスクリプト

そして、スタートアップスクリプトでGROWIを検索・選択します。

![FireShot Capture 449 - サーバーの設定 - さくらのVPS コントロールパネル - secure.sakura.ad.jp 449.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/c3188c9f-6472-7702-efb0-ac676169c6d7.jpeg)


スタートアップスクリプト設定で、FQDNが入力できるので、逆引きできるドメインを設定します。そして、Let's Encrypt用のメールアドレスも設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/a253a08e-5821-d003-4fc0-6bd54497c4e1.png)

後はサーバーを立ち上げるだけです。しばらくすると、GROWIのインストールが完了します。

## オブジェクトストレージの設定

GROWIでは画像などを外部ストレージに保存します。Amazon S3互換のAPIを利用できるので、さくらのオブジェクトストレージを使ってみます。

![FireShot Capture 356 - オブジェクトストレージ - secure.sakura.ad.jp 356.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/0c67f8ca-bb3d-f666-7d2f-404014b4f552.jpeg)

[オブジェクトストレージ | さくらのクラウド](https://cloud.sakura.ad.jp/products/object-storage/)

リージョンなどはないので、バケットを作成するだけです。バケットを作成したら、アクセスキーを発行します。そして、以下の情報をコピーしておきます。

- アクセスキーID
- シークレットアクセスキー

## GROWIの設定

インストールが完了したら、 https://(ドメイン)/ にアクセスして、GROWIの初期設定を行います。ファイルアップロード設定にて、先ほどのオブジェクトストレージの情報を入力します。

| 項目                     | 設定値                            |
| ------------------------ | --------------------------------- |
| ファイルアップロード方法 | AWS(S3)                           |
| リージョン               | jp-north-1                        |
| カスタムエンドポイント   | https://s3.isk01.sakurastorage.jp |
| バケット名               | 作成したバケット名                |
| Access key ID            | 取得したアクセスキーID            |
| Secret access key        | 取得したシークレットアクセスキー  |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/84e14c15-2da6-5bbc-b1e8-65ad8b230452.png)


これで設定完了です。

## まとめ

ドメインについては[さくらのドメイン](https://domain.sakura.ad.jp/)がありますし、さくらのクラウドとオブジェクトストレージを組み合わせれば、さくらインターネットの環境下ですべて完結できそうです。

全体として価格は安価で済みますので、個人用途での利用もおすすめです。

[OSS開発wikiツールのGROWI | 快適な情報共有を、全ての人へ](https://growi.org/ja/)
web のアーキテクチャスタイル 〜REST の特徴〜


web のアーキテクチャスタイル である REST について解説します。

## そもそもアーキテクチャスタイルとは？

複数のアーキテクチャに共通する性質や様式、作法、流儀を指します（≒アーキテクチャパターンとほぼ同義）。

似たような言葉として「デザインパターン」≒「マイクロアーキテクチャパターン」と呼ばれるものもありますが、アーキテクチャスタイルよりも小さな粒度を指します。

その特性から実装詳細を指すわけではないので、本に具体的な実装方法まで載っていることが少なく、システム開発者は抽象化されたアーキテクチャスタイルを適用した実装をする必要があります。

### 関連するアーキテクチャスタイルとアーキテクチャパターン

- **MVC**
- **Pipe and Filter**
- **Event System**

## RESTの特徴

RESTはクライアント/サーバーアーキテクチャスタイルの派生であり、以下の特徴を持ちます。

1. **クライアント/サーバー**
    - ユーザーインターフェース処理を分離します。
    - フロントエンド以外の部分をデータだけで構築でき、サーバーの冗長化が容易です。

2. **ステートレスサーバー**
    - サーバー側でアプリケーションの状態を保持しません。
    - 前回通信した「相手」を覚える必要がなく、簡単に実装できます。

3. **キャッシュ**
    - クライアントとサーバーの通信回数および通信量を減少させます。
    - 通信量の軽減が可能です。

4. **統一インターフェース**
    - インターフェースを固定します（GET POST などの 8つのメソッドのみが使用可能です）。
    - 設計をシンプルに保ちます。

5. **階層化システム**
    - 階層に分離し、クライアントとサーバー以外の役割を挿入しやすくします。
      - クライアントとサーバーの構成の間にプロキシサーバーを挟んだり、サーバーの奥に HTTP 通信以外のコンテンツを配置する、などの変更が容易です。

6. **コードオンデマンド**
    - 必要に応じてコードをダウンロードして実行します。
    - クライアント側にソースコードやライブラリをインストールする必要がなく、ブラウザ等で指定されたHTMLやJavaScriptコードを実行するだけで済みます。

## HTTPというプロトコル (通信の規格)

Web通信のデファクトプロトコルであり、コンピュータで扱えるものであれば何でも転送可能です。
Webの設計思想であるRESTとアーキテクチャスタイルを遵守しています。
変数宣言についてメモ

JSでは変数宣言には以下の3つがある
- var 
- let
- const

## var

`var`は再宣言・再代入が可能な変数宣言。
3つの中で一番緩い。

``` js
var a = "a";
a = "b";  // ok
var a = "c"; // ok
```

あと、ホイスティングされる。

``` js
console.log(x); // undefined
var x = 10;
```
上記コードのように、宣言が先に巻き上げられる（実行される）。
初期化がされるわけではないので、undefinedにはなる。

## let

`let`は再宣言は不可能、再代入は可能な変数宣言。
``` js
let a = "a";
a = "b";  // ok
let a = "c"; // NG
```

宣言前にその変数にアクセスしようとするとエラーになる。
``` js
console.log(x); // ReferenceError: x is not defined
let x = 10;
```

## const
`const`は再宣言も再代入もできない変数宣言。
ただ、オブジェクトや配列の内容は変更可能。（再宣言でも再代入でもないため）

``` js
const a = "a";
a = "b";  // NG
const a = "c"; // NG

const arr = [1, 2, 3];
arr.push(4); // ok
```

宣言前にその変数にアクセスしようとするとエラーになる。
``` js
console.log(x); // ReferenceError: x is not defined
const x = 10;
```
GitHub の PR で編集されていない箇所にレビューコメントしたかった


## 概要

GitHub の PR で編集されていない箇所にレビューコメントしたかったのですが、どうしてもできなかったため代替策を記録しておきます。

## 課題

GitHub で コードレビューをしていると、その PR 内で編集されていない箇所にコメントしたいことがあります。ですが PR では編集された近辺の行にしかコメントを追加できません。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/7a6eb31b-da42-d29c-b436-d7469e23f8dc.png)
*コード編集箇所とその近辺では、青い＋マークが表示される*

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/79a6779f-a553-9810-903a-9051beaa3105.png)
*＋マークをクリックし、コメントを追加する*

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/cb6bcae7-73df-8496-bb91-e4ce73bd73b7.png)
*しかし編集箇所ではないところには＋マークが表示されずコメントできない*

## 対策

### 基本

この場合、PR のコード内に直接コメントをできる方法はありません。そのため以下の代替手順でコメントを残すことにしました。

1. View File を選択してファイルを開く
1. 該当する行を選択して Copy permalink をクリック
1. Conversation にコピーした URL を含めてコメント
1. Request changes にコメントを書いて Submit review をクリック

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/91f84ba6-d89c-4142-3bdf-759c549b448a.png)
*View File を選択してファイルを開く*

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/7869ae3c-d566-b755-13d0-c0059f65a4e1.png)
*該当する行を選択して Copy permalink をクリック*

:::note
複数行を選択するには、先頭行をクリック→末尾行をShift+クリックしてください
:::

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/c3981535-cb67-e1ba-dad1-60a82f6b6425.png)
*Conversation にコピーした URL を含めてコメント*

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/db4ddf21-0f34-45ea-2628-472cd592a10f.png)
*Conversation にコピーした URL を含めてコメント*

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/aea34896-1f3d-8845-439e-b75239c81351.png)
*Request changes にコメントを書いて Submit review をクリック（自作自演 PR のため Request changes にチェックが入れられず）*

### レンダリングされるファイルの場合

Markdown や CSV などレンダリング表示されるファイルの場合、Copy permalink が選択できない場合があります。この場合はコード表示に切り替えることで同様の操作が可能です。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/1a2eae31-2b23-33f7-784d-2256a016e265.png)
*Markdown では Copy permalink などのメニューが表示されない*

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/f7bc78c0-ce08-d726-a355-4f2aee42b90b.png)
*Code ボタンを押す事でコード表示に*

GitHub Enterprise を使っている場合、Display the source blob という表示の場合があります。

![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/6b4ad257-5066-25f3-3089-37acc3a47c9c.png)
*Display the source blob を押せばコード表示に*

## まとめ

どの箇所をどのように直すべきか一目でわかるようにしてあげる事で、レビュアー/レビュイー間の齟齬がなくなり結果的に早く仕事が進みます。良いコードレビューを！
Rustの好きなところ4:その他


# はじめに

私が今一番好きな言語は Rust です。
Rust は書いていて楽しいですし、学びも多い言語だと感じます。

そこで今回は私が特に好きな Rust の特徴を紹介しつつ、Rust の良さを伝えていきたいと思います。
今回は 4 回目でおそらく最後です。

今までカテゴリ分けして紹介してきましたが、今回はその他の特徴を雑に紹介していきます！

## 高速

言わずもがな、Rust の特徴です。C,C++に並ぶ速度を持っているとされています。
そのため、とりあえず Rust を使っておけば言語による速度の問題に引っかかることはほとんどないといって良いでしょう。
そのため、自信を持って Rust を使って開発を進めることができるのではないかと思います。

## モダンなパラダイムを取り入れている

Rust は他言語で取り入れられている機能を積極的に取り入れています。
その中でも FP(関数型プログラミング)チックなところが私としてはとても好きです。
以下はその一例です。

- 関数が第一級市民
- パターンマッチ
- Result, Option 型
- map, filter, fold など
- if 式
- if let, let else
- ジェネリクス
- トレイト境界

## テストが本番コードと同じファイルに書ける

これは好みが別れるかもしれませんが、私はとても好きです。
コードと同じファイルにテストを書くことができるので、すぐにテストを書くことができますし、逆にコードを読む時も近くにテストコードがあるのはとても便利です。

また、Rust は構造体のフィールドの可視性がプライベートの場合、その構造体以外にはアクセスできない、というわけではなく、同じモジュール内(mod キーワードで囲む範囲。大体ファイル単位になることが多い(と思う))であればアクセスできるという特徴があります。
そのため、テストコードで構造体のフィールドにアクセスすることができるのです。これも意見が分かれるところではありますが、やはりプライベートなフィールドにアクセスしたいケースはいつかは来ると思います。

テストコードが同じファイルにかけるかつ、プライベートなフィールドにアクセスできるというのは、テストを書く際に便利になってくることがあるのではないかと思います。

## コンパイラが優しい

Rust はコンパイラがとても優しいです。エラーメッセージがとてもわかりやすいですし、エラーが出た時にはどこが問題なのかがわかりやすいです。
ですので、コンパイラとペアプロしている気分にもなれます。
最近ではコンパイラ駆動開発という言葉もあるらしく、まずはコンパイラに怒られてからそのコンパイラを通していくという開発スタイルもあるようです。
Rust はコンパイラが優しいので、そのスタイルも取り入れやすいのかもしれません。

## 低レイヤを意識することになる → 学びが多い

Rust はメモリ配置やスレッドセーフなど、低レイヤの知識が必要になることがあります。
そのため、私は最初の頃`&str`と`String`の違いがわからなかったり、なぜ`clone`がよくないのかなどがわからなかったです。
ただ、Rust とともに低レイヤの知識も少しずつ学んでいったことで、とてもクリアになり、メモリやパフォーマンスなどについても考えることができるようになりました。

Rust がなければなかなかこのレイヤを学ぶ機会はなかったかもしれません。
Rust は低レイヤを意識することになるので、初学者が学べば多くのことを学ぶことができると思います。

## 終わりに

Rust はとても良い言語です！書いていて学びがあり、何より楽しいです！
これからも Rust を使い続けていきたいと思います。

ここまで読んでいただきありがとうございました！