OmniAICreator/Qiita-1.07M huggingface dataset:
[init.sql] PostgreSQL+Dockerで初回起動時にSQLファイルを実行する！


# はじめに
PostgreSQLをDockerコンテナで立ち上げる際に、初期化SQLファイル（init.sql）を実行することで、データベースの作成やユーザーの設定を自動化することができます
本記事では、init.sqlファイルを使用してPostgreSQLコンテナをセットアップする方法を説明します

# 前提条件
- DockerとDocker Composeがインストールされていること
- 基本的なSQLとDockerの知識があること

# 手順
### 1. ディレクトリ構成の準備
まず、プロジェクトのディレクトリ構成を準備します
以下のようなディレクトリ構成にします

```
project_root/
├── containers/
│   └── postgres/
│       └── init.sql
├── Dockerfile
└── docker-compose.yml
```


### 2. init.sqlファイルの作成
次に、init.sqlファイルを作成し、データベースの初期化SQL文を記述します

```containers/postgres/init.sql

-- データベースの作成
CREATE DATABASE sotaheavymetal21_db;

-- ユーザーの作成
CREATE USER sotaheavymetal21 WITH PASSWORD 'password';

-- ユーザーに対するデータベースの全権限付与
GRANT ALL PRIVILEGES ON DATABASE sotaheavymetal21_db TO sotaheavymetal21;

```

### 3. Dockerfileの作成
次に、PostgreSQLイメージをベースにしたDockerfileを作成します
init.sqlファイルをコンテナの適切なディレクトリにコピーします

```dockerfile
# Dockerfile

FROM postgres:15.2

# init.sqlファイルをコンテナの/docker-entrypoint-initdb.dにコピー
COPY containers/postgres/init.sql /docker-entrypoint-initdb.d/
```


### docker-entrypoint-initdb.dとは
PostgreSQL Dockerイメージに特有のディレクトリであり、コンテナの初回起動時に初期化スクリプトを自動的に実行するためのディレクトリです
このディレクトリに配置されたSQLスクリプトやシェルスクリプトは、PostgreSQLコンテナが初めて起動するときに自動的に実行されます


### 4. docker-compose.ymlの作成
次に、docker-compose.ymlファイルを作成し、PostgreSQLサービスの設定を行います

```docker-compose.yml

version: '3.8'

services:
  db:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      POSTGRES_DB: usagi_db
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: posgres
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
```

### 5. コンテナのビルドと起動
すべてのファイルが準備できたら、Docker Composeを使用してコンテナをビルドし、起動します

```
docker-compose up --build
```


これで、PostgreSQLコンテナが立ち上がり、init.sqlファイルが実行され、データベースの初期化が行われます

### 6. 動作確認

コンテナが正常に起動したら、psqlコマンドやpgAdminなどのツールを使用してデータベースに接続し、正しく初期化されているかを確認します

```
# PostgreSQLコンテナに接続
docker exec -it <コンテナID> psql -U postgres -d usagi_db

# データベースの確認
\l

# ユーザーの確認
\du
```

# まとめ
PostgreSQLをDockerコンテナで立ち上げる際に、初期化SQLファイルを実行する方法について説明しました！
init.sqlファイルを使用することで、データベースのセットアップを自動化し、手動の設定作業を減らすことができます

是非、この記事を参考にして、自分のプロジェクトでも同様の手法を試してみてください！！🐰
【PostgreSQL】メタコマンド〜\prompt〜

## 初めに
Qiita Engineer Festa 2024に参加中。完走目指してます。
他のメタコマンドについては以下から読んでください。
[【PostgreSQL】メタコマンドを纏めていく](https://qiita.com/dai_chi/items/04f5339d54130f070671)

## \promptとは

> 変数`name`に代入するテキストを入力するようにユーザを促します。 プロンプト`text`をオプションで指定することができます。 （複数の単語をプロンプトで使用する場合はそのテキストを単一引用符でくくってください。）
> 

[引用元：PostgreSQL 15.4](https://www.postgresql.jp/docs/15/app-psql.html#:~:text=%5Cprompt%20%5B%20text%20%5D%20name)

## 試してみた

psqlでpostgresにログインする

```bash
$ psql
```
`\prompt`を使用する
```sql
\prompt 'Please enter your name: ' user_name
```
すぐに入力が求められる
``` sql
# \prompt 'Please enter your name: ' user_name
Please enter your name: daichi
# \echo :user_name
daichi
```

なるほど、\setと何が違うんだ？

### \promptを活用してみる
再利用可能なスクリプトで利用すると有効活用できそうです。
例えば以下のようなテーブルがあったとします。

```sql
# select * from users;
 id |  name   | age 
----+---------+-----
  1 | Alice   |  30
  2 | Bob     |  25
  3 | Charlie |  35
  4 | Diana   |  30
(4 行)
```

prompt_test.sqlというファイルを作り以下の内容を記載します。

```bash
\prompt 'Please enter the table name: ' table_name
\prompt 'Please enter the column name to filter by: ' column_name
\prompt 'Please enter the value to filter: ' filter_value

SELECT * FROM :table_name WHERE :column_name = :'filter_value';
```

作成できたら実行してみましょう。

```bash
$ psql -f prompt_test.sql 
ユーザ postgres のパスワード: 
Please enter the table name: users
Please enter the column name to filter by: age
Please enter the value to filter: 30
 id | name  | age 
----+-------+-----
  1 | Alice |  30
  4 | Diana |  30
(2 行)
```

結果が返ってきました。
最終的には以下のSQLが実行されて結果が返ってきました。

```bash
SELECT * FROM users WHERE age = '30';
```

## まとめ
\promptについて実際に使ってみました。
自分も初めて触ってみたのですが、実務の中で活用できそうなシーンが浮かびました。

例えば特定のユーザーの権限を確認するコマンドですが、いつもSQL自体を調べているのでスクリプトを用意しておけば実行するだけで対象をそのときに指定できるので、調べる時間が短縮されるかと思ったので早速使っていきたいと思います。
GraphQLとはなにか

## はじめに

Rails7を触っており、いろいろネットの記事を見ているとGraphQLという文字を目にしました。

「はて、GraphQLとは何ぞや？」

と気になったので簡単に調べてみました。

## GraphQLとは

GraphQL（Graph Query Language）は**Web APIを開発するためのクエリ言語**です。近年急速に広まりを見せるデータ取得と操作のための新しいアプローチです。従来のRESTful APIに代わるものとして設計されています。

## GraphQLの特徴

1. **柔軟なデータ取得**
    GraphQLでは、クライアントが必要なデータを詳細に指定できます。例えば、特定のユーザーの名前と写真だけを取得することができます。これにより、不要なデータを取得することなく、効率的に情報を取得できます

2. **単一エンドポイント**
    GraphQLは単一のエンドポイントを持ちます。これは、すべてのデータ要求が1つの場所から行われることを意味します。RESTful APIでは、複数のエンドポイントを使うことが多いですが、GraphQLでは1つのエンドポイントで全てのデータ取得や変更を行います

3. **強力なタイプシステム**
    GraphQLには、データの型を定義する仕組みがあります。これにより、どんな種類のデータを取得できるかを明確にします。この型システムは、データの整合性を保ちながら、安全にクエリを実行するのに役立ちます

4. **リアルタイム通信**
    GraphQLでは、リアルタイムでデータの更新を受け取ることができます。例えば、チャットアプリケーションで新しいメッセージが届いたときに、自動的に画面に表示される仕組みです

## GraphQLの使い方

GraphQLを使う基本的な流れは次の通りです。

- **クエリの作成**
    クライアントが取得したいデータを指定するクエリを作成します。例えば、「ユーザーの名前とメールアドレスを取得する」というクエリを作成します

- **サーバーへのリクエスト**
    作成したクエリをGraphQLサーバーに送信します。このとき、クエリはJSON形式で送られます

- **データの取得**
    サーバーはクエリに対応するデータを取得し、JSON形式でクライアントに返します。クライアントはこのデータを使って画面に表示するなどの処理を行います

## おわりに

GraphQLは**データ取得と操作を柔軟かつ効率的に行うための強力なツール**です。初めての人でも理解しやすく、ウェブ開発の現場で幅広く活用されています。これからのウェブ開発を学ぶ上で、GraphQLの基本を抑えておくと役立つこと間違いありません。


## 参考記事
[GraphQL とは - 特徴、メリットとデメリット | Red Hat](https://www.redhat.com/ja/topics/api/what-is-graphql)
[【GraphQL】今注目されているGraphQLって何? 【API】](https://qiita.com/kim_t0814/items/c6ef7e3c668007f920a6)
[GraphQLを徹底解説する記事](https://zenn.dev/nameless_sn/articles/graphql_tutorial)
GoのLambdaをGithub Actions + Terraformでデプロイする

# はじめに
Terrformを使ってインフラ管理しているのですが、Lambdaのデプロイにちょっと手間取ったので、記録を残しておきます。

# 実現したいこと
- Github Actions + TerraformでLambdaをデプロイしたい
- LambdaコードはTerraformコードとは別ディレクトリで管理（同じリポジトリではある）
- 言語はGo
- Lambdaのコードに変更があった場合と、Terraform側のコードに変更があった場合のみデプロイが実行されるようにしたい

# Github ActionsでTerraformを扱えるようにする

OIDCを使って、Github ActionsでTerraformを扱えるようにする記事は色々ありますので、細かい説明は割愛させていただきます。

# Terraform
terraformの階層と違う階層にLambdaのファイルを保存したいと思いますので、その前提で以下のようなコードになります。

```terraform
resource "terraform_data" "build_lambda" {
　　　　// ファイルに変更があった場合のみ以下を実行
  triggers_replace = {
    file_content = md5(file("../lambda/main.go")) // 相対パスでLambdaファイルを指定
    // ファイルでなくディレクトリを指定したい場合は以下
    // file_content = sha1(join("", [for f in fileset("../lambda", "*") : filesha1("../lambda/${f}")])) 
  }

  provisioner "local-exec" {
    command = "cd ../lambda/ && GOOS=linux GOARCH=amd64 go build -o ../bootstrap" // ファイルの出力場所を指定する
  }
}

data "archive_file" "lambda" {
  type        = "zip"
  source_file = "${path.module}/bootstrap"
  output_path = "${path.module}/go.zip"
  // path.moduleはこのモジュールが配置されているディレクトリ

  depends_on = [terraform_data.build_lambda]
}

resource "aws_lambda_function" "some_func" {
  filename      = "${path.module}/go.zip"
  function_name = "some-function"
  role          = aws_iam_role.iam_for_lambda.arn
  handler       = "bootstrap"
  memory_size   = 128
  timeout       = 300

  source_code_hash = data.archive_file.lambda.output_base64sha256

  runtime = "provided.al2023"

  // build_lambdaしないと失敗するので、depends_onでbuild_lambdaがあれば実行されるようにする
  depends_on = [terraform_data.build_lambda]
}

```

# 注意点
terraform plan時点では、bootstrapというファイルは存在しないため、"archive_file"が失敗します。
そのため、空のbootstrapというファイルを設置しておく必要があります。
闘魂Elixir ーー AtCoder Beginner Contest 355(A)をElixirで楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>


# はじめに

[AtCoder Beginner Contest 355](https://atcoder.jp/contests/abc355)を[Elixir](https://elixir-lang.org/)で解いてみます。

[AtCoder](https://atcoder.jp/)を解くのが趣味で、休憩時間に解いているという若い人がいて、それってすごい意識の高い休憩時間の過ごし方だと思って、私も真似してみることにしました。


# [AtCoderをElixirでやってみる](https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01)

入力の読み取り方や解答の作り方は、別の記事にまとめています。


https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01

ご参照くださいませ。

[Elixir](https://elixir-lang.org/)で[AtCoder](https://atcoder.jp/)を楽しむためには、エントリポイントを`Main.main/0`にする必要があります。つまり`Main`モジュールを作って、その中に`main/0`関数を定義するわけです。

# [A - Who Ate the Cake?](https://atcoder.jp/contests/abc355/tasks/abc355_a)

問題はリンク先をご参照くださいませ。
私の解答を貼っておきます。


<details><summary>私の解答</summary>

_問題文を読んでいることを前提にひとこと解説をしておきます。_

`[1, 2, 3]`から入力値を削除して、残った要素数が1個なら犯人を特定でき、それ以外は特定できないという解法を取りました。
なんでも`6`から入力値の和を引くと答えを得られるという解法もあります。若い人に教えてもらいました。


```elixir
defmodule Main do
  def main do
    [a, b] =
      IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)

    solve(a, b)
    |> IO.puts()
  end
  
  def solve(a, b) do
    map_set = MapSet.new([1, 2, 3]) |> MapSet.delete(a) |> MapSet.delete(b)
    size = MapSet.size(map_set)
    do_solve(size, map_set)
  end

  defp do_solve(2, _map_set), do: -1
  defp do_solve(1, map_set), do: MapSet.to_list(map_set) |> Enum.at(0)
end
```
</details>



---

# さいごに

[AtCoder Beginner Contest 355](https://atcoder.jp/contests/abc355)を[Elixir](https://elixir-lang.org/)で解くことを楽しみました。

あなたのお好きなプログラミング言語でお楽しみください。

---


**闘魂**とは、  **「己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことである」** との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
**アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。**

---

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>
<b><font color="red">$\huge{１、２、３ ぁっダァー！}$</font></b>
switch文で複数の式を扱いたい時

こんにちは。
いきなりですが、皆さんはswitch文を使う機会は多いでしょうか？
私はJavaScript(以下JS)を学び始めた頃に、if文よりも一度に多くの「もしも」が書けるんだ！　と感動し、
それ以降現場でもよく使う事が多くなったのですが、ふとある時に躓いたケースがありました。

**一度に複数の式で条件の判定をしたい！**

例えば、フォームに入力された複数の回答を条件に処理を振り分けたいと思います。
思考が単純な私は最初、以下のようにコードを書いてみました。
```JavaScript
const A = // 項目1の回答;
const B = // 項目2の回答;

switch(A,B) {
	case 'C, D':
        // 回答の値が「C, D」だった場合の処理
        break;
}
```
……はい、動きませんね！（ここでは省略しておりますが、defaultの結果が返ってきます）
switch文の冒頭の括弧に入れられる式は1つだけです。
カンマを入れれば複数判定してくれるだろう……という甘い考えは通じません。

▼ご参考にMDNさんのリンクを載せておきます▼

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/switch

では、どのように工夫すれば複数の式でも成り立つのか？
やり方は様々あるかと思いますが、私が初めて知った時に目から鱗が落ちたのはこちらです。

```JavaScript
const A = // 項目1の回答;
const B = // 項目2の回答;
// 2つの値を1つの変数にまとめる。
let AB = A + ', ' + B;

switch(AB) {
	case 'C, D':
        // 回答の値が「C, D」だった場合の処理
        break;
}
```

2つの式を1つの変数にまとめてしまうんですね！
そうすれば式が1つという扱いになり、ちゃんと動くようになります。

JSは条件式まで覚えればある程度のプログラムは書けるようになる、と聞いた事がありますが、
自身の頭がいかに硬いかを痛感した方法でした……。

もし宜しければ他に「こんなやり方があるよ！」というのがあれば教えて頂ければありがたいです。
IBM i ACS 5250エミュレーターの地味な機能拡張

***いまさら5250エミュレーターに拡張する余地（必要）ある？***

というお題です。

## ACS 5250端末の拡張

以下はACS 1.1.9.0です。立派に機能拡張されていますがわかりますでしょうか？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/cf96e60c-a7a6-6a39-7b2e-d157df80b966.png)

ん？？

わかりませんか？W

ここです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/c3637bc9-0a07-c054-a037-b0e5ce8e0581.png)

ということで、

### ACS 5250端末の拡張はACSの各種機能を起動できるアイコンが追加されている

のが機能拡張でした。

簡単に解説すると以下になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/28b7fc1b-6f80-830b-81cf-45457000becc.png)

5250はまだ使う場面もあるよね、、でもこのあたり↑の機能も一緒に使うでしょう（使ってほしい）という事かと思います。

ぜひ使ってみてください。
【備忘録】PHPUnitのよく使うAssertions一覧

# はじめに

こんにちは、エンジニアのkeitaMaxです。
PHPUnitのAssertionsについて自分なりにまとめてみました。

# Boolean

### `assertTrue()`
中身がtrueであることを確認するものです。
```php
//ok
assertTrue(true)
//ng
assertTrue(false)
```

### `assertFalse()`
中身がfalseであることを確認するものです。
```php
//ok
assertTrue(true)
//ng
assertTrue(false)
```
# 2つの値が正しいことの確認

### `assertSame()`
`===`と同じように第一引数と第二引数が同じであることを確認します。
```php
//ok
assertSame("10","10")
//ng
assertSame("10",10)
//ng
assertSame("10","30")
```

### `assertEquals()`
`==`と同じように第一引数と第二引数が同じであることを確認します。
```php
//ok
assertSame("10","10")
//ok
assertSame("10",10)
//ng
assertSame("10","30")
```

# 配列関係

### `assertArrayHasKey()`
指定された配列のkeyがあることを確認します。
```php
//ok
assertArrayHasKey('foo', ['foo' => 'bar'])
//ng
assertArrayHasKey('foo', ['bar' => 'baz'])
```

### `assertContains()`
配列の中に指定された値があるかを確認します。
```php
//ok
assertContains(１, [1,2,3])
//ng
assertContains(4, [1,2,3])
```

### `assertCount()`
配列の要素数を確認します。
```php
//ok
assertCount(3, [1,2,3])
//ng
assertCount(1, [1,2,3])
```

# 数字の比較

### `assertGreaterThan()`
第二引数が第一引数より大きいことを確認します。
```php
//ok
assertGreaterThan(2, ３)
//ng
assertGreaterThan(2, 2)
//ng
assertGreaterThan(2, 1)
```

### `assertGreaterThanOrEqual()`
第二引数が第一引数以上であることを確認します。
```php
//ok
assertGreaterThanOrEqual(2, ３)
//ok
assertGreaterThanOrEqual(2, 2)
//ng
assertGreaterThanOrEqual(2, 1)
```

### `assertLessThan()`
第二引数が第一引数より小さいことを確認します。
```php
//ng
assertLessThan(2, ３)
//ng
assertLessThan(2, 2)
//ok
assertLessThan(2, 1)
```

### `assertLessThanOrEqual()`
第二引数が第一引数以下であることを確認します。
```php
//ng
assertLessThanOrEqual(2, ３)
//ok
assertLessThanOrEqual(2, 2)
//ok
assertLessThanOrEqual(2, 1)
```


# インスタンス
### `assertInstanceOf()`
インスタンスが同じかどうかを確認します。
```php
//ok
assertInstanceOf(Exception::class, new Exception)
//ng
assertInstanceOf(RuntimeException::class, new Exception)
```



# おわりに

個人的によく使うのはこの辺りかなと思っています。
今後よく使用するものがあったらここに追加していこうと思ってます。

また、その他のAssertionsを知りたい人は以下URLを参考にしてください。
https://docs.phpunit.de/en/10.5/assertions.html

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

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

# 参考

https://docs.phpunit.de/en/10.5/assertions.html
【Next.js】SPAっぽくふわっと現れる画面をtemplate.tsxで作ろう

# はじめに
こんにちは、H×Hのセンリツ大好きエンジニアです。（同担OKです😉）
Next.jsを使っていて、やっぱり思うことは出来る限りSPAっぽくしたいという欲望でした。。。

色々調べた結果、`template.tsx`を使えば万事解決とのことなので早速やっていきましょう！

# template.tsxとは？
簡単に言うと、各ページをラップして何か処理を行う時に使用されます。

各ページをラップするのは`layout.tsx`と似ていますが、`template.tsx`はページ遷移を行うたびに再レンダリングが行われるというものです。
（`layout.tsx`は再レンダリングされません）

つまり、各ページをラップしつつ再レンダリングが走るということは。。。フェードインアニメーションを仕込めば画面遷移のたびにふわっと現れるサイトの完成ですねえ(´＾ω＾｀)ニチャア

配置場所は`layout.tsx`と同様なので、サイト全体に適用させたい場合はappディレクトリのルートに置いちゃいましょう！😎

# SPA風にするためにtemplate.tsxを使ったアニメーションを作成

Next.jsでアニメーションを実現したい場合は、`framer-motion`が一つの手だと思います！
ですので、以下のようにすればOKです！

``` template.tsx
'use client'

import { motion } from 'framer-motion'
import React from 'react'

const variants = {
  hidden: { opacity: 0 },
  enter: { opacity: 1 }
}

export default function Template({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      variants={variants}
      initial="hidden"
      animate="enter"
      transition={{
        type: 'linear',
        duration: 1
      }}
    >
      {children}
    </motion.div>
  )
}
```

このコードでは、`children`を`motion.dev`でラップしています。

中身をざっくり説明すると、
- コンポーネントの初期状態は非表示（`opacity: 0`）
- コンポーネントがマウントされた時に表示（`opacity: 1`）させる
- 非表示から表示までアニメーションのトランジションを線形で1秒かけて実行する

こんな感じですね😁
これでふわっと現れてくれます！
後はお好きなように改造していただければ良いかと思います！

# おわりに
ここまで見ていただきありがとうございます！
今回は簡単な紹介でしたが、こんなもんなんだ〜くらいに思っていただけると幸いです！
以上、センリツでした🤓
OpenAPIのyamlファイルとoapi-codegenでGoの自動生成をやってみた

# 環境
OS：Ubuntu22.04
Go：v1.20.3
oapi-codegen: v2.2.0

# やったこと
タイトルにもあるとおり、[oapi-codegen](https://github.com/deepmap/oapi-codegen/tree/master)を使用してGoの自動生成の実行を行いました。

基本的にはREADMEに従っただけですが、手順を書いておきます。

## oapi-codegenインストール
```bash
go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@latest
```

バージョン確認のコマンドでインストールができているか確認しましょう。

```bash
oapi-codegen -version
> v2.2.0
```

## 生成したコードを入れるフォルダを作成
自動生成したコードを直接編集すると、再び自動生成を行った時に上書きする恐れや、上書きされるのを避けてyamlファイルの変更を手動で反映させる必要などがでてくることが考えられます。
そこで、自分は自動生成したファイルを入れておく`generated`フォルダを作成することにしました。
```bash
mkdir generated
```

## Configファイルを作成

```config.yaml
package: api
output: ./generated/{filename}.gen.go
generate:
    echo-server: true
    models: true
output-options:
    skip-prune: true
```

ほぼREADMEを真似しただけです。

ただ、自分が使用する自動生成元のファイルでは、`$ref`を使って別のファイルを参照しています。このまま`oapi-codegen`を実行するとエラーがおきます。

そこで、自動的にOpenAPIドキュメントを結合してくれる[Redocly CLI](https://redocly.com/redocly-cli/)を使用しました。

## OpenAPIドキュメントを結合

下記コマンドで結合できます。
子ファイルを勝手に読み込んでくれるのでラクでした。

```bash
npx @redocly/cli bundle {親ファイル名} -o {出力ファイル名}
```
## Goコード出力

```bash
oapi-codegen -config config.yaml {上記で出力したファイル名}
```

これでOpenAPIドキュメントからGoのコード生成ができました。

# 最後に

コードの自動生成は初めてさわりましたが、とても便利だと思いました。
コード自動生成ツールを上手く使うことで、設計に時間をより多くかけることができますね。
AppRouterなNext.jsで新しいページを作ってリンクを貼るやつ入門


シリーズのトップは↓こちら

https://qiita.com/every-month/items/a6a9f481ac31eb695d25

前回の記事は↓こちら

https://qiita.com/every-month/items/7345c2d8e23b2fb720fe

たまたまプライベートで人にAppRouterなNext.jsを叩き込む機会がありまして、せっかくなので再びこの場をお借りしていっしょに復習します。

## 前回までのポイント（再掲）（抜粋）

- `cd`
    - フォルダの中に入る
- `npm run dev`
    - （作ってる途中の）Next.jsを動かす
    - だいたい`http://localhost:3000`で見れる

## 今回のポイント

- `src/app/名前/page.tsx`
    - 新しいページを作る
- `<Link href="リンク先">リンクにする内容</Link>`
    - HTMLの`a`みたいなもの

## 新しいページを作る

`src/app/URLにしたい名前/page.tsx`のようにすると`http://localhost:3000/URLにしたい名前`とすることができます。

例えばここでは`src/app/cart/page.tsx`としてみます。

```tsx:src/app/cart/page.tsx

export default function Home() {
  return (
    <>
      empty
    </>
  );
}
```

中身は何でもいいので、ここでは`empty`とでもしておきます。

## リンクを貼る

`src/app/page.tsx`にいくつか追加してこのようにします。

```tsx:src/app/page.tsx
import Image from "next/image";
import icon from './icon_in_app.png';
import Link from 'next/link';

export default function Home() {
  return (
    <>
      hello world
      <Image src="/icon_in_public.png" alt="just an ordinary icon" width={100} height={100} />
      <Image src={icon} alt="just an ordinary icon" />
      <Link href="/cart">cart</Link>
    </>
  );
}
```

まず上の方にこの`import`を追加しました

```tsx:src/app/page.tsx（抜粋）
import Link from 'next/link';
```

これはリンクを貼るために必要です。

次にリンクを貼りたい場所に

```tsx:src/app/page.tsx（抜粋）
<Link href="/cart">cart</Link>
```

これを書きました。

ここで`href="/cart"`としていますがこれは先程`src/app/cart/page.tsx`を作ったからです。この`cart`の部分をそろえます。

## リンクを踏んでみる

まずは（まだ動かしていなければ）ターミナルで`npm run dev`を動かしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782801/f5d920fc-f6e2-4354-021f-03a240577c93.png)

画像の下にcartの文字があります。全然リンクに見えませんがリンクにはなっているので、これをクリックしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782801/0a1f6a6f-94ce-772e-403a-456c2e14f1a8.png)

新しく作った画面に遷移することができました🎉

そしてURLは……

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782801/28d66263-ad73-2dc5-3b12-18715adcc832.png)

`http://localhost:3000/cart`になっています🎉

この`cart`が`src/app/cart/page.tsx`の`cart`の部分です。

## 今回のポイント（再掲）

- `src/app/名前/page.tsx`
    - 新しいページを作る
- `<Link href="リンク先">リンクにする内容</Link>`
    - HTMLの`a`みたいなもの

## 参考

https://nextjs.org/docs/app/building-your-application/routing

https://nextjs.org/docs/app/building-your-application/routing/colocation

https://nextjs.org/docs/app/api-reference/components/link
Create and Activate a Segment in Data Cloud



https://trailhead.salesforce.com/content/learn/projects/quick-start-create-a-data-cloud-segment

+ [When I proceed to "Add Filter", there is no "Lead" object in the left pane "Related Attributes".Could you kindly help?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007clyFy)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/df9ef3fe-7f19-3337-cec2-28135d018237.png)

:::note
solved by add mappings in Data Stream "Lead"
:::
Engine Simulatorの作法 その13

# 概要
Engine Simulatorの作法を調べてみた。
構成要素を図解してみた。

# 構成要素

- cylinder_bank
- cylinder
- cylinder head
- crankshaft
- ignition system
- piston
- camshaft
- connecting_rod
- rod_journal
- intake system
- exhaust system
- ignition_wire

# 図解

![sim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/6f8e1958-93f3-951a-c927-67f26d2b0309.png)

以上。
Javaで「配列要素へのアクセスとインデックス」の動作を確認してみた

# 概要

Javaで「配列要素へのアクセスとインデックス」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/array/index4.html

# 実装

以下のファイルを作成しました。
```JSample4_1.java
class JSample4_1{
  public static void main(String[] args){
    int[] num = new int[4];

    num[0] = 10;
    num[1] = 8;
    num[2] = 16;
    num[3] = 5;

    for (int i = 0; i < 4; i++){
      System.out.println("num[" + i + "] = " + num[i]);
    }
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample4_1.java 
$ java JSample4_1 
num[0] = 10
num[1] = 8
num[2] = 16
num[3] = 5
```

# まとめ

何かの役に立てばと。
Parse solana raw transaction instruction data

```js
import bs58 from "bs58";
import * as borsh from "borsh";
import { Schema } from "borsh";

const schema = {
  struct: {
    discriminator: "u64",
    buyerPrice: "u64",
    tokenSize: "u64",
    buyerStateExpiry: "i64",
    buyerCreatorRoyaltyBp: "u16",
    extraArgs: {
      array: {
        type: "u8",
      },
    },
  },
};

const data = "UEVYJrzmev2UQ1cVQ8mBufZjnj8LT83s1ukeQvg1kERm5M7F3oaX";
const decoded = borsh.deserialize(schema, Buffer.from(bs58.decode(data)));
console.log(decoded);

//////
const schema2 = {
  struct: {
    discriminator: "u8",
  },
};
const data2 = "84eT";
const decoded2 = borsh.deserialize(schema2, Buffer.from(bs58.decode(data2)));
console.log(decoded2);

//////
const schema3 = schema2;
const data3 = "P";
let bytes3 = bs58.decode(data3);
console.log(Buffer.from(bytes3).toString("hex"));

const decoded3 = borsh.deserialize(schema3, Buffer.from(bs58.decode(data3)));
console.log(decoded3);

//////
const schema4 = {
  struct: {
    discriminator: "u8",
    authority: {
      array: {
        // Pubkey [u8; 32]);
        type: "u8",
        len: 32,
      },
    },
  },
};

const data4 = "6MnUrhc3pqaYAVEir8UMwNSBDdUmGJb8GxTkm1JzXQQev";
let bytes4 = bs58.decode(data4);
console.log(Buffer.from(bytes4).toString("hex"));

const decoded4 = borsh.deserialize(schema4, Buffer.from(bs58.decode(data4)));
console.log(decoded4);

const obj = JSON.parse(JSON.stringify(decoded4));
const uint8Array = new Uint8Array(obj.authority);
const addr = bs58.encode(uint8Array);
console.log(addr);
```

## discern Jupiter v6 inx: `SharedAccountsRoute`

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169726/d0252703-640e-abb6-d298-4baa73c9594b.jpeg)

```py
from hashlib import sha256

def camel_to_snake(text):
    import re
    str1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', text)
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', str1).lower()

ix_name = "SharedAccountsRoute"

stuff = f"global:{camel_to_snake(ix_name)}"
encode = sha256(stuff.encode()).digest()[:8]
print(encode.hex())

```

---

Ref:

https://github.com/near/borsh-js

https://solana.com/docs/core/transactions

https://solana.fm/tx/5YTgCGQpXjkwXLnEMgVt4A4XvXxJzBpGzni5wMQQQcWR9AL28VrH1FJeNM2g9yeb12C6rXT1yRvTSV7wh4CytjEM

https://appdevtools.com/base58-encoder-decoder
Qiita 投稿マラソン 2024 またの名を 人はいかにして学びの機会を捻出するか - DevOps 編 2 日目 Azure DevOps Labs 

[Qiita Engineer Festa 2024（キータ・エンジニア・フェスタ 2024） - Qiita](https://qiita.com/official-campaigns/engineer-festa/2024)

> 投稿マラソン
> Qiita Engineer Festa 2024 の記事投稿キャンペーンに紐づけて19記事投稿すると、「Qiitaオリジナルグッズ」を必ずプレゼント！38記事投稿すると更に特別な「Qiitaオリジナルグッズセット」を必ずプレゼント！

とのことで「学び」を強制的に自分に課したいな、どこまで走れるか分からないがちょうど目の前に、学びたい [Azure DevOps Services | Microsoft Azure](https://azure.microsoft.com/ja-jp/products/devops) があるじゃない、これをテーマに走り出してみたら良いじゃないという個人的コミット駆動です。


昨日の記事: [Qiita 投稿マラソン 2024 またの名を 人はいかにして学びの機会を捻出するか - DevOps 編 開会宣言 #AzureDevOps - Qiita](https://qiita.com/e99h2121/items/02fcccdc257a0c534fff)


## 本日のタイトル: Azure DevOps Labs 

https://azuredevopslabs.com/

中央からサインアップできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/bff9611d-7dff-008a-2c30-80cdd642e2f3.png)

https://github.com/Microsoft/azuredevopslabs

> About
Learn how you can plan smartly, collaborate better, and ship faster with a set of modern development services with Azure DevOps.

> <機械翻訳> Azure DevOpsを使用することで、最新の開発サービス一式を使用して、どのようにスマートに計画を立て、より良いコラボレーションを行い、迅速に出荷できるかを学びましょう。

とりあえずこの [Azure DevOps Hands-On Labs | Azure DevOps Hands-on-Labs](https://azuredevopslabs.com/) は Lab ということで、色々やってみようのテーマが置かれている模様。

画と動画が豊富
[Configuring CI/CD Pipelines as Code with YAML in Azure DevOps | Azure DevOps Hands-on-Labs](https://azuredevopslabs.com/labs/azuredevops/yaml/)
![](https://azuredevopslabs.com/labs/azuredevops/yaml/images/YAML-pipeline-workflow.gif)

コンテナもある
[【DevOpsLab 深堀】マルチコンテナアプリケーションを Azure Pipeline で AKS にデプロイする #Docker - Qiita](https://qiita.com/komiyasa/items/9c4318abb88a96f4b182)


## Azure DevOps にまつわる色々

トレーニング以外のドキュメントというドキュメントは以下にある。

https://learn.microsoft.com/ja-jp/azure/devops/?view=azure-devops

[DevOps ソリューション | Microsoft Azure](https://azure.microsoft.com/ja-jp/solutions/devops/)
[Microsoft DevOps Stories | Microsoft Azure](https://azure.microsoft.com/ja-jp/solutions/devops/devops-at-microsoft/)




## 本日のまとめ

ひとまず AzureDevOps の外観を眺めたところで折角以前覚えた AWS 知識を忘れそう。Code 兄弟の分野ですね。

[AWS サービスと Azure サービスの比較 - Azure Architecture Center | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/architecture/aws-professional/services#devops-and-application-monitoring)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/d5f8f00b-0f9f-1ada-1134-70dc15fc3cae.png)


2024.06.12 個人的注目記事
[コミット履歴が " きれい " なPRはすごく助かる。ありがたい。好き。 #初心者 - Qiita](https://qiita.com/_mi/items/f477e95a864474187e3d)

https://x.com/t_wada/status/904916106153828352

t_wada さんのこれは明快で役立ちます。


つづく
PythonにおけるDocker Containerと仮想環境venvの違い

この記事はPythonにおけるDocker Container(コンテナ)と仮想環境の違いから各種のメリットデメリットについて記述する．

# なんでコンテナや仮想環境を使うの？
仮想環境やコンテナを使用する主な理由は，アプリケーションの依存関係を管理し，開発・テスト・本番環境間での一貫性を確保するためである．

## 1.依存関係の管理
**仮想環境**
プロジェクト固有のPythonパッケージとそのバージョンを分離して管理することで、プロジェクト間の依存関係の競合を避けることができる．

**コンテナ**
アプリケーションとその依存関係をパッケージ化することで，異なる環境間で一貫した実行環境を提供できる．

## 2.環境の一貫性
**仮想環境**
異なる開発者間や，開発・テスト・本番環境間で同じPython環境を共有できる．

**コンテナ**
コンテナ化されたアプリケーションは，異なるシステム上で一貫して動作する．これにより，「開発環境では動作するが、本番環境では動作しない」といった問題を避けることができる．

## 3.複数プロジェクトの管理
**仮想環境**
プロジェクトごとに独立した仮想環境を作成することで，プロジェクト間の干渉を避けることができる．

**コンテナ**
各アプリケーションをコンテナ化することで，複数のアプリケーションを同じホストシステム上で実行できる．

# Docker Containerとは?
>Dockerについて詳しくはこちらの記事で

![スクリーンショット 2024-06-11 12.52.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/b41ef3e5-b7be-9d49-74b4-e482fbf34d28.png)
アプリケーションとその実行に必要なすべての依存関係を含む軽量な，スタンドアローンの実行可能パッケージ．
ある入れ物(コンテナ)の中に
**OS**
**依存関係**
**ミドルウェア**
**アプリケーション**

が入っており，これでアプリケーション単位での依存関係(パッケージ，フレームワーク，ライブラリ)の管理が可能になる．

# Python Virtual Environment(仮想環境)とは
Pythonプロジェクト用に独立した環境を作成するためのツール．仮想環境を使用することで，プロジェクト固有のPythonバージョンとパッケージを分離して管理することができる．

この二つを比較すると...一見違いはないのかもしれないが実は結構違う．

## 1.目的の違い
**Docker Container**
アプリケーションとその依存関係をパッケージ化し，異なる環境間で一貫した実行環境を提供することを目的としている．

**仮想環境**
主にPythonプロジェクト間でパッケージの依存関係を分離し，プロジェクト固有の環境を作成することを目的としている．

## 2.分離レベルの違い
**Docker Container**
オペレーティングシステムレベルで分離されており，各コンテナは独自のファイルシステム，プロセス空間，ネットワークインターフェースを持っている．

**仮想環境**
Pythonパッケージとそのバージョンのみを分離する．仮想環境間でオペレーティングシステムのリソースは共有される．

## 3.リソース使用量の違い
**Docker Container**
各コンテナはオペレーティングシステムのリソースを分離して使用するため，仮想環境よりもリソース使用量が多くなる傾向がある．

**仮想環境**
Pythonパッケージのみを分離するため，Dockerコンテナと比較してリソース使用量は少なくなる．

## 4.構成の違い
**Docker Container**
Dockerfileを使用コンテナの構成を定義し，イメージをビルドして、そこからコンテナを作成する．

**仮想環境**
通常，venvやvirtualenvなどのツールを使用して仮想環境を作成し，requirements.txtファイルを使用してパッケージの依存関係を管理する．

# 違いをまとめると...
Docker Containerはアプリケーション全体の実行環境を分離・パッケージ化するのに対し，仮想環境はPythonプロジェクトのパッケージ依存関係を分離するために使用される．プロジェクトの要件に応じて，適切な方法を選択することが重要である．

# Docker Containerの作成方法
こちらの記事を参考にしてほしい

https://qiita.com/tarakokko3233/items/6f6d03bd6d1e69c9e67e

# Python仮想環境の作成方法
仮想環境の作成
```
python -m venv myenv
```

仮想環境の有効化（Linux / Mac）
```
source myenv/bin/activate
```

仮想環境の有効化（Windows）
```
myenv\Scripts\activate
```
サービスのレスポンスが遅いと言われた時にトレースルートを使ってみた

#### はじめに
Webサービスにておたくのサイトが重いとかレスポンスが遅いとのクレームがあったことがよくありました。でもだいたい社内の検証では遅くないし、、どうエビデンスを渡せばクライアントが納得してくれるか。ということでトレースルートを使ってみることにしました。

---

### 問題の特定

まず、リモートなりでアクセスしクライアントの環境でサービスのエンドポイントに対してトレースルートを実行。

**Windowsの場合**:
```plaintext
tracert myservice.example.com　//あなたの製品のURL
```

**Unix/Linux/Macの場合**:
```plaintext
traceroute myservice.example.com
```

#### 検証結果

```plaintext
C:\Users\YourUser>tracert myservice.example.com

myservice.example.com [203.0.113.10] へのルートをトレースしています
経由するホップ数は最大 30 です:

  1   150 ms   160 ms   170 ms  192.168.1.1
　↑ここがまず遅い！
  2   200 ms   210 ms   220 ms  100.64.1.1
  3   250 ms   260 ms   270 ms  203.0.113.1
  4   300 ms   310 ms   320 ms  153.149.204.94
  5   350 ms   360 ms   370 ms  153.149.204.89
  6   100 ms    98 ms   100 ms  52.93.7.1
  7   110 ms   108 ms   110 ms  52.93.7.2
  8   120 ms   118 ms   120 ms  52.93.126.34
  9   130 ms   128 ms   130 ms  52.93.132.45
 10   140 ms   138 ms   140 ms  54.239.111.10
 11   150 ms   148 ms   150 ms  54.239.106.31
 12   160 ms   158 ms   160 ms  203.0.113.10

トレースを完了しました。
```
最初のホップから5番目のホップまでの遅延が異常に高いことがわかります。各ホップに対して3回のパケットを送信してRTT（ラウンドトリップタイム）を計測するんですね。
特にホップ1（192.168.1.1）は社内ルーターのIPアドレスですね。私の環境ではほぼ1msに対して、ここでは 150 ms、160 ms、170 msと既に明らか遅延が発生していることから、問題が社内ネットワーク内にあると判断ができます。rdpで試してそっちの環境のせいですよとすぐにそのままエビデンス提示できるのがいいですね。そして
実際はクライアントのルータの再起動で解消したようです。ルータのメモリリークが原因だったんでしょうか。

#### 再起動後の結果：


```plaintext
C:\Users\YourUser>tracert myservice.example.com

myservice.example.com [203.0.113.10] へのルートをトレースしています
経由するホップ数は最大 30 です:

  1     1 ms    <1 ms    <1 ms  192.168.1.1
  2    10 ms    10 ms    10 ms  100.64.1.1
  3    15 ms    14 ms    15 ms  203.0.113.1
  4    50 ms    48 ms    49 ms  153.149.204.94
  5    60 ms    58 ms    60 ms  153.149.204.89
  6    70 ms    68 ms    70 ms  52.93.7.1
  7    80 ms    78 ms    80 ms  52.93.7.2
  8    90 ms    88 ms    90 ms  52.93.126.34
  9   100 ms    98 ms   100 ms  52.93.132.45
 10   110 ms   108 ms   110 ms  54.239.111.10
 11   120 ms   118 ms   120 ms  54.239.106.31
 12   130 ms   128 ms   130 ms  203.0.113.10

トレースを完了しました。
```



   ルーター側が解消されると、そのあとのトラフィック、ホップ6以降も速くなるんですね。これがボトルネックてやつなんでしょうか。


#### クレームとしてのエビデンス

他にも対応方法はあると思うけどトレースルートの結果は、とにかくクレーム対応の即席エビデンスとして私にも気軽にできて有効だと思いました。
CSS Grid で repeat auto-fit や minmax を使って可変サイズを実現しても余白は固定なのかあ……待てよ？

## この記事の概要

CSS Grid を使うと、スクリーンの幅にあわせて列数や列サイズを可変させて、簡単にレスポンシブな実装ができます。

しかし、margin や padding、gap といった余白関連のプロパティは固定値です。

そのアンバランスさを解消すべく記事を書きました。

:::note
真面目な文章で書いていますが、半ばネタです。
メディアクエリーを書く方が早いし多分安全（意図しない表示崩れなどを引き起こしにくい）です。
:::

## 解消したいこと

次のような CSS があるとします。

```css
.some-class {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 32px;
  padding: 32px;
  width: min(100%, 800px);
}
```

この時点で次のような変化をします。

:::note warn
それぞれのグリッドが分かりやすいように画像を敷き詰めています。
また、重要なコードのみ抜き出しているので、上記をコピー・ペーストしてもまったく同じ見た目にはなりません。
:::

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/9f6eb54b-edca-6af1-02b9-251b74d59c54.gif)

グリッドのコンテナーサイズにあわせて、中の列数も、アイテムのサイズも可変しています。
ただし、要素自体のサイズや、スクリーン幅との相対的なサイズ感は変わっているのに、余白だけがずっと固定です。

分かりやすいように 3 パターンの表示を用意しました。

| 1 列 | 2 列 | 3 列 |
| --- | --- | --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/55372c3d-774d-8ab9-b16e-39074a10c368.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/4d5baa2d-f299-170e-9c88-d34667130007.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/6113a6dc-a36f-e568-d169-563ec6fb9092.png) |

`padding` や `gap` をメディアクエリー・コンテナクエリーで書けば解消できるのですが、せっかく条件分岐なしにここまで可変にできているのだから、余白も同様に処理したいわけです。

## アプローチ

[clamp](https://developer.mozilla.org/en-US/docs/Web/CSS/clamp) を使います。

フォントの可変サイズに使われることが多いように思いますが、幅や高さなど様々な場所に使えます。

今回は、以下の挙動になるように書き換えてみます。

- スクリーン幅が 400px 以下のとき、余白は 16px
- スクリーン幅が 800px 以上のとき、余白は 32px
- 間のスクリーンサイズのとき、余白は 16 - 32px の間で変化する

これをコードになおすと次のようになります。

```diff_css
  .some-class {
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
-   gap: 32px;
+   gap: clamp(16px, 4vw, 32px);   
-   padding: 32px;
+   padding: clamp(16px, 4vw, 32px);
    width: min(100%, 800px);
  }
```

自分で計算しても良いですが、ジェネレーターがあるので使うと便利です。

https://clamp.font-size.app/

こちらを適用すると見た目が次のように変化します。
（before の画像は先ほど載せたものと同じです）

| | 1 列 | 2 列 | 3 列 |
| --- | --- | --- | --- |
| before | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/55372c3d-774d-8ab9-b16e-39074a10c368.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/4d5baa2d-f299-170e-9c88-d34667130007.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/6113a6dc-a36f-e568-d169-563ec6fb9092.png) |
| after | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/2bf52c48-3c16-e1a3-6c1f-1df484d3fea8.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/8f286baf-b30e-7165-e7a5-99e4c40033c5.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/5c963dcd-5477-d60f-eb06-46b8b4fdcd1b.png) |

スクリーン幅が狭いときは余白も狭くなったことで、間延び感が減ったように思えます。

## まとめ

- CSS Grid で `repeat auto-fit` や `minmax` を使うと**グリッドアイテムのサイズ**が可変になる
- `clamp` をあわせることで**余白のサイズ**も可変になる
WWDC24旅行記 ~出発編~

WWDC24に向けていよいよ出発の日になりました。約10年ぶりの海外旅行なので、緊張は隠せません。なかなかパッキングも進んでいなかったのですが、駆け込みでなんとか準備することができました。

![IMG_1395.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/dee95c5d-78e1-d06d-2d30-e2018d6df761.jpeg)


羽田に着いて会社のWWDC組と合流、@treastrain さんが見送りに来てくれて旅安全のお守りを頂きました。感謝 🙏

![IMG_2040.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/b1088786-9cd4-c6f2-208a-23a3c241dc80.jpeg)

手荷物検査を完了させて中に入ると、まだ時間があったのでラウンジでまったり過ごします。

![IMG_1396.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/1f152596-ec6b-1df7-1d0b-385bbc92a6c4.jpeg)

飛行機って、ずっと見ていても飽きないですよね。

![IMG_1400.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/16d0d9a6-afff-c9fd-19cd-d0108bddebf7.jpeg)

同じ便に日本の iOS エンジニアもたくさん搭乗されるとのことだったので、合流するとまさにオールスターでした。みなさん既に乾杯をしていました。フライトは約9時間なので、なるべく疲れないように機内グッズをチェックしていよいよ搭乗です。

![IMG_1398.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/8ca65227-9283-4fb5-643f-c4a2a31581f9.jpeg)


順調に離陸すると、しばらくして夕食。自分はチキンを選びました。

![IMG_1401.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/87a19f90-ffef-8860-ae99-f306e98f4bfd.jpeg)

といってもまだ1時間程度、まだまだ長いです。今回は知人のオススメで機内にスリッパを持ち込んだお陰で少し楽に過ごすことができました。流石にずっと靴だと足も疲れますからね。以下はあると快適に過ごせるかも。

* ネックピロー
* ヘッドフォン
* スリッパ
* アイマスク
* 耳栓
* モバイルバッテリー（機内持ち込み必須）
* 動画コンテンツ（見たいコンテンツがある人）
* 本
* ガム（歯磨きできない）

そうしているうちにすぐに朝食になります。朝食といっても自分の時計は深夜0時を指しています。昼食も遅めだったので、このインターバルだとお腹が空きません。

![IMG_1404.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/ca3b335d-550e-693d-091d-139c6f5f2a87.jpeg)

メニューは無印良品バターチキンカレーです。お腹が空いていないのですが、食べないわけには行きません。あとは仮眠をしながら、残りの時間を過ごしました。9時間のフライトは結構疲れました。帰りは11時間なので、疲れて寝られることを祈っています。

そして、いよいよ SFO に到着です！入国の準備をしてホテルに移動します。いろいろ質問されると思いましたが、目的だけ聞かれて終了でした。

![IMG_1408.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/17630295-3185-b687-e6b0-6cdcb3d4c928.jpeg)

![IMG_1412.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/b266373d-8a7e-ab7b-777b-5fb4f601e88e.jpeg)

空港からホテルまでの移動は Uber です。事前に予約していたので、待たずに乗車することができました。

Uber アプリから飛行機の便を登録すれば予約が可能です。ただし、予約料金が 40$ 程度掛かるので注意してください。

![IMG_1415.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299135/35e50ab4-bba4-1481-c069-f1f795fb0b84.jpeg)

今回の滞在先はサニーベールなので、ハイウェイを進んで行きます。アーリーチェックインができるかは分からなかったのですが、スーツケースを置いて移動しようと思います！

次回は、1日目の滞在について紹介します。それでは！
会社の書籍購入支援制度がありがたい話

# まえがき
## 書籍購入支援制度とは？
弊社で2年前から導入されている、業務に関連する書籍の購入費用を経費として扱える制度です。
エンジニアの福利厚生的な扱いで導入されている会社さんも多いのではないかと思います。
弊社の場合購入した書籍の所有権は本人になるので、読んだ本が本棚や電子書籍の棚に貯まっていって、後で読み返すこともできますし、貯まっていくこと自体も楽しいです◎

## めちゃくちゃ本を読むようになりました（当社比）
もともと私は全然本を読む人ではありませんでした。
設計への拘りや知識欲は昔から強い方だと思いますが、色々試して自己流の設計を固めたり、ライブラリのコードを読んでみたり動かしてみたりというやり方でやることが多く、1年で1冊も技術書を読まなかったという年もあったと思います。

それがこの2年間では14冊技術書（とか業務の本とか）を読んでいるのでかなり変化があったと感じます。

## この記事に書くこと
そんなもともとさして読書好きではない人間がたくさん本を読むようになるにあたって、制度が存在することできっかけになってくれたり、ためらいを消してくれたりと色々なありがたポイントがあったなと思っています。
そんなありがたポイントを自己分析的に書きつつ、関連して実際に購入した書籍を書いていってみたいと思います。

# 書籍購入支援制度のありがたポイント
## 話題の本が躊躇なく買える
名著と呼ばれる本はやはり色々な示唆に富んでおり、エンジニアとして仕事をするにあたって押さえておくべき基礎知識になるようなものだと思います。

しかしこの本良いよ～という話題はたくさん出てきますし、重厚な技術書は値段も高いです。私はケチなので、「読んでみたいけど本当にこれ業務に活かせるかな？しっかり下調べしてから買おう」などと考えてしまいます。その下調べで機を逃す。

今はSlackやXで話題になっている本なども、だいぶ軽率に買ってしまえる体になりました。
結果として素晴らしい本に出会える機会が格段に増えたと思います。
業務に活きるかどうかなんて読んで業務をやってみないとわからんのや。

あと自分が買った本を良かったよ～とオススメもしやすくなったかなと思います。

### 買った本
- エリック・エヴァンスのドメイン駆動設計 
- プロダクトマネジメント ―ビルドトラップを避け顧客に価値を届ける
- エンジニアリング組織論への招待 不確実性に向き合う思考と組織のリファクタリング
- レガシーコード改善ガイド: 保守開発のためのリファクタリング
- Googleのソフトウェアエンジニアリング ―持続可能なプログラミングを支える技術、文化、プロセス
- JavaScript 第7版
- Web API: The Good Parts
- イシューからはじめよ――知的生産の「シンプルな本質」

## あるとちょっと便利だなという本が躊躇なく買える
あるとちょっと便利だと思うのだけれど、まあなくてもなんとかなるか。
というような本はまず買うことはなかったんですが、お金出るしなと思うと軽率に買えるようになりました。
結果的に早く物事が進んだり、新しい発見があったりしたと思います。

### 新人の方が研修で読んでいるらしいということで買った本
- プロになるJava―仕事で必要なプログラミングの知識がゼロから身につく最高の指南書
- ソフトウェアテスト技法練習帳 ~知識を経験に変える40問~
目を通しておくことでどういう知識を持って配属されてくるのかということが把握できました。テストに関してはあまり体系的に学んだことがなかったので新しい発見もありました。
### 業務でちょっとこれ使うから買ってみよで買った本
- クリーンなコードへのSonarQube即効活用術 

## チームメンバーにこの本買って！と言える
個人的書籍購入支援制度のありがたポイントナンバー１。
自費だと買って！とは言えないですが、会社の経費なのでみんなでこれ買おうか～というような提案がしやすくなりました。

### 勉強会のために買った本
- スッキリわかるサーブレット&JSP入門
- プロになるためのSpring入門 ゼロからの開発力養成講座
チームメンバーとWebアプリ開発の基礎を押さえるための勉強会をやることになり、その際に使う本を書籍購入支援制度で購入しました。継続して続けていきたいなと思っています。次はドメイン駆動設計かな。

### 機能開発のための前提知識として買った本
- 図解即戦力　産休・育休の導入と実務がこれ1冊でしっかりわかる本
機能開発していきたいがドメインに詳しい人が居ないねということで、想定業務フローを作るためにみんなで購入しました。

## 枠が余っているから何か買っておくか～というきっかけ
複合的な要素としてこれもあったと思います。貧乏性なので。
それがインプットのきっかけになったのであれば会社としてもOKでしょう。（と私は思っています）

# あとがき
こんな感じでたくさん本を読むようになったわけですが、それはとてもポジティブな変化だと思っています。
新たな知識のインプットを定期的に行うことで、既存の知識がつながる快感を得られる頻度が増えたと感じますし、アウトプットの質が良くなったなと実感できることも増えました。
今までもエンジニアという仕事が好きでしたが、より一層エンジニア楽しいなと感じています。
ありがたい制度に感謝しつつ、これからもたくさんインプット・アウトプットしてエンジニアライフを楽しんでいきたいです。
Supabaseでローカル開発する際にAndroid Emulatorの通信エラーが発生した

# はじめに

Supabaseとは、Firebaseの代替を謳っていてモバイル・Webなどのアプリ開発に伴う充実したサービスを提供してくれるSaasとなります。

また、本筋からずれてしまうため省略しますが、Supabaseの優れた機能の中の1つとしてLocal環境が簡単に構築できる機能があります。

https://supabase.com/docs/guides/cli/local-development

# 今回の問題

Supabaseはクライアントで利用する際、以下のような初期化処理を行います。

```dart
  await Supabase.initialize(
    url: 'https://domain.com:54321,
    anonKey: 'xxxxxxxxxx,
  );
```


今回、このローカル開発をする中でiOSでは正常にSupabaseにアクセスできるのにAndroidだとアクセスできない事象が発生していました。

もちろん、Androidのネットワーク設定は完了しています。

https://qiita.com/y-matsumoto/items/c2a5ce6020d77c5e91c9

# 解決法

今回、たまたまSupabaseを用いていましたがSupabaseが起因というより、PCのlocalhostはAndroid Emulatorからアクセスできないため別のURLを指定しないといけないのです。

そのため、`Supabase.initialize`をする際に指定するURLはそれぞれ以下のようにしてください。


### Before

💡 Supabaseのローカルは以下のURLで基本的にアクセスします

```
http://localhost:54321
```

### After

`iOS`
```
http://127.0.0.1:54321
```

`Android`
```
http://10.0.2.2:54321
```

以上です。
ネットワーク設定含め、初回しかしないし忘れがちなので備忘録として記載しました。
CharacterEncodingFilterで文字コードMS932にするとで特殊文字が？？になる。リクエストではUTF-8でうけて、返すときに文字コードをMS932にして返す？


CharacterEncodingFilterを使用して連携元の文字コードをMS932に設定すると、特殊文字が「？？」になる問題は、文字エンコーディングの変換ミスや対応していない文字セットが原因で発生することがあります。以下に、リクエストをUTF-8で受け取り、連携元に返す際に文字コードをMS932に変換する手順を説明します。

## CharacterEncodingFilterの設定:
リクエストをUTF-8で受け取るためには、CharacterEncodingFilterを適切に設定する必要があります。以下はweb.xmlに設定する例です。

```xml
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
```

## レスポンスをMS932に設定:
レスポンスをMS932に変換するには、レスポンスのエンコーディングを明示的に設定します。以下のようにServletのレスポンスエンコーディングを設定します

```java
response.setCharacterEncoding("MS932");
response.setContentType("text/html; charset=MS932");
```

## 特殊文字の対応:

特殊文字が「？？」になる場合は、MS932エンコードで表現できない文字が含まれている可能性があります。MS932は日本語のShift JISに基づくエンコードで、一部の特殊文字はサポートしていないことがあります。この場合、エンコード可能な文字セットを使用するか、特殊文字の変換やエスケープ処理を検討する必要があります。

---

以上の手順を踏むことで、リクエストをUTF-8で受け取り、レスポンスをMS932に変換する処理が正しく行えるようになるはずです。特殊文字が正しく表示されない問題が引き続き発生する場合は、問題の文字がMS932でサポートされているかどうかを確認し、必要に応じて代替文字やエスケープシーケンスを使用してください。
Next.js で output: "export" でも画像最適化をしたい（next-export-optimize-imagesを使う）

## この記事の概要

以前の記事で[next-image-export-optimizerを紹介](https://qiita.com/xrxoxcxox/items/0183010548458750c160)してみました。

よく似たライブラリである [next-export-optimize-images](https://github.com/dc7290/next-export-optimize-images) も使ってみたので、ライブラリ選定の備忘録がてら記事にしました。

使い勝手などを next-image-export-optimizer と比較もしています。

## 環境

主要なものだけ記載します。

| 依存関係 | バージョン |
| --- | --- |
| next | 14.2.3 |
| next-export-optimize-images | 4.5.0 |
| react | 18.3.1 |
| typescript | 5.4.5 |

この記事で話題にするのは next-export-optimize-images です。

## 公式ドキュメント

https://next-export-optimize-images.vercel.app/

リポジトリの README とは別に、ドキュメント用のサイトがあります。
README を読むのでも良いのですが、こうやって別でまとまっている方が分かりやすいのでありがたいです。
検索もできるので、目当ての設定を探しやすかったです。

## インストールとセットアップ

コマンドを叩きます。

```sh
npm install -D next-export-optimize-images
```

---

次に`next.config.js`を編集します。
[公式ドキュメント](https://next-export-optimize-images.vercel.app/docs/getting-started)では`require`を使っていましたが、2024 年 6 月 9 日現在の`create-next-app`では`next.config.mjs`が生成されたため、ここでは`import`を使っています。

```diff_javascript:next.config.mjs
+ import withExportImages from "next-export-optimize-images";

  /** @type {import('next').NextConfig} */
- const nextConfig = {
+ const nextConfig = withExportImages({
    output: "export",
- };
+ });

  export default nextConfig;
```

---

また`package.json`のスクリプトも書き換えます。

```diff_json:package.json
  "scripts": {
-   "build": "next build",
+   "build": "next build && next-export-optimize-images",
  }
```

これにより、ビルド時に複数の画像が書き出されます。

書き出されるサイズは`[...nextConfig.images.deviceSizes, ...nextConfig.images.imageSizes]` [^1]と記載がありました。
つまり、何もしなければ Next.js のデフォルト値である`16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840`[^2]に準じるようです。

[^1]: https://github.com/dc7290/next-export-optimize-images/blob/415e9054dff8f02ef50032d8ba04917182be12c6/src/loader/index.ts#L35

[^2]: https://github.com/vercel/next.js/blob/73e4895dfaeb5ac2f8efba90171140272f527b14/packages/next/src/shared/lib/image-config.ts#L104-L105

next-image-export-optimizer の記事では「枚数が少なくてもビルド時間が遅いので、サイズを間引いた方が良いかもしれない」と記載しました。
同じ枚数で比較すると next-export-optimize-images の方が確実に早かった[^3]ので、枚数が少ないうちはサイズを間引かなくても良いかもしれません。

[^3]: 私が試した条件では、next-image-export-optimizer では 10 秒かかっていたのが next-export-optimize-images では 0.5 秒ほどでした。

---

## Picture コンポーネントの扱い

ドキュメントで最初に紹介されているのは`next-export-optimize-images/image`なのですが、`next/image`と比べると画像の圧縮率が小さかったです。

また`next-image-export-optimizer`は設定無しで webp へ変換されていたのですが、`next-export-optimize-images/image`は元ファイルの拡張子を維持しているため、結果的にサイズの大きな画像を出していました。

ただ`next-export-optimize-images/picture`を使えば webp も元の拡張子のファイルも両方を配信できますし、画像サイズも同様に小さくなっていました。

自分が使うのであれば、デフォルトで`next-export-optimize-images/picture`を使うかもしれません。

## 開発環境での挙動

一応記載するだけですが、開発環境では画像の最適化はされていません。

（ビルド時に最適化した画像を書き出すのですから当たり前といえば当たり前な気もしますが）

## 結局どちらのライブラリを使うか

小さなテスト環境だけでの判断ですが next-export-optimize-images を使いそうです。

next-image-export-optimizer は、publicディレクトリ（= git の管理下）に画像が生成されたり、一度ビルドしないとコンソールにエラーが出たりと、わずかながら使いづらかったです。

next-export-optimize-images にはそういった引っ掛かりがなかったのに加え、画像の生成が速いです。

ビルド時間が伸びると色々な大変さが生まれますから、速いのはシンプルに嬉しいです。
Web系エンジニア数年やって思ったこと。

## 背景

エンジニアとして仕事を何年かやってみて思った幾つかやらかした事を
初心に立ち返って書こうと思っています。
とはいえ最近記事を書いていないので半分リハビリみたいなつもりで書いているので、気楽に見てください。


## いままでやって失敗した事
- 細かい仕様を決める時間がないからという理由で他の人に任せてしまっていたこと
- 質の悪いTESTを書かないこと
- コミュニケーションの取り方を煩雑にしていたこと
- レビューをちゃんとやること

以下それの説明を書いていきます。

### 細かい仕様を決める時間がないからという理由で他の人に任せてしまっていたこと


自分自身が複数の案件を跨いで作業を行なっていると、やはり集中力が散漫になってしまうのはどうしても避けられないと思っています。
なのでマルチタスクになってしまうと、以下の問題が発生してしまいます。

 1. 複数の案件を並列で進めようとするとどうしても案件同士の仕様が混ざってしまう。
 2. 余裕がないので、他人のアイディアをちゃんと聞いてし取捨選択できない。
 3. 会社がピリつくので会社の雰囲気が悪くなる。
 4. 残業が増える。

仕方ないところもあると思うのですが、どうしてもこれだけはやっとけというのは

- 別案件の事をやる場合リラックスする時間を作る
- 詳細設計フェーズは意地でも時間を作る

この2点はどんなに忙しくてもMustでやるべきでした。。。


#### まとめ
時間がないとしても自分がPLポジだった場合、意地でも時間を作って仕様を決めること
もし決められないのであれば後から後悔します。。。。

### 質の悪いTESTを書かないこと

サービスが肥大化していけば行くほど、TESTの重要度の比重は大きくなっていきます。
というのも影響範囲がでかい修正を行うとそれに紐付いている機能にも影響を与えてしまう可能性があるからです。
逆に小規模なサービスであればテストはそこまで必要ない。


とはいえテストの質が低いと意味をなさないので、品質のいいテスト書く必要があります。
(書かないとQAの負担が増えます😇)

テストの観点とかは話長くなりそうなので別のタイミングで話します。

#### まとめ
大きなプロジェクトになっていけばいくほどテストの価値が増大する。
テストを書くのであればある程度の品質を担保する必要がある。

## コミュニケーションの取り方を煩雑にしていたこと


これは前職の話になるのですがMTGをやる時、ずっとオンラインMTGをカメラOFFでやっていました。
一番の原因は自分の能力不足だと思いますが、そのせいもあってか、かなりピリついたことがありました。
あの時一緒に仕事をしてくれた先輩方には頭が上がらないとはいえ、やはりピリついているとストレスで体調も悪くなるし、仕事の進み具合もよろしくなかったです。

また、エンジニアではない人と話すのもとても大変です。
案件にもよりますが、PM的ポジションの人がいない場合直接エンジニアがお客さんや営業と話すことがあったりします。
そうなると本当に地獄です。
ITの話を噛み砕いて一般化して伝える必要があるので、それができない場合は要件が噛み合わなくてコミュニケーションが増えてしまいます。

おそらく周りに怒号を飛ばすつよつよエンジニアが一人いるより、能力がそこまで高くなくても、みんなで仲良く仕事を勧められる様な環境をつくれるエンジニアの方が費用対効果は高いのかなと思います。

非同期でコミュニケーションをするための文章を書くテクニックとかもありますが、それは一旦後回し。

#### まとめ
コミュニケーションをとるのはチームとしても、お客さんとの認識の齟齬を無くすためにもとても大事。
怒号を飛ばすつよつよエンジニア一人より、能力がそこまで高くなくても、ラポール形成できるエンジニアの方がいる方が費用対効果は高い。


## レビューをちゃんとやること

コードのレビューはコードの品質を保つために必須ですが、一方でどこまでやるべきかとても難しい。
時間をかければ間違いなくクオリティは上がりますが、どこまで時間かけるべきなのか？？？
とはいえ絶対にやる必要はあると思っています。


持論ですがレビューはこの観点でやると品質を担保できると思います。
- レビュワーに対して自身が書いたコードを説明できるか？
- レビュワーの観点で明らかにこのコードは冗長な処理をしてしまっているか？

自分のなかではまだ完全には煮詰っていませんが現状はこちらの観点でレビューするのがいいと思っています。

#### まとめ

レビューを行う際エンジニアにソースコードの意図を説明させるようにする。
自信に知見がある場合は、このコードは冗長な処理をしているのかを判断してレビューする

### 総評

コードを書くことはそれなりにできるようになってきたが、もう少し仕事のやり方などは改善の余地があると思っています。
引き続き自己研鑽に励み、より良い仕事をしていこうと思います。
US配列キーボードのすすめ

# はじめに
みなさんはMacのキーボード配列は何を使っていますか。
今回はUS配列の魅力についてご紹介したいと思います。

# USとJISの比較
JIS
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523103/c22622b7-edd0-6de8-b39a-c5403b077911.png)

https://www.apple.com/jp/shop/product/MK2A3J/A/magic-keyboard-%E6%97%A5%E6%9C%AC%E8%AA%9Ejis

US
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523103/112e70f7-e752-0d06-f151-7c0f0f5bb4a4.png)

https://www.apple.com/jp/shop/product/MK2A3LL/A/magic-keyboard-%E8%8B%B1%E8%AA%9Eus

# 見た目がシンプル
US配列には平仮名が書いてありません。
そのため非常にシンプルでスタイリッシュです。
基本的にはローマ字入力する方がほとんどだと思いますので平仮名の刻印はなくても問題ないと思います。
私は2年使って支障は全くありません。
もちろん好みですがせっかく高額のPCの買うのですからなるべくかっこいい見た目を選びたいですよね。


# タイピングがしやすい
前述では見た目のメリットを紹介しましたが、US配列は実用性も兼ね備えています。
USはJISに比べてキー配置のバランスが取れていると言われています。
キー全体がJISに比べて中心に寄っているためです。
他にはスペースキーが長く入力しやすいです。
また、エンターキーがJISに比べて小さいと思われるかも知れませんが意外となれると何の違和感もありません。（私がJISを使ったことないのもあるかも）


# 日本語↔︎ローマ字入力の切り替え方
「システム環境設定」→「キーボード」→「入力ソース」にある「Caps LockキーでABC入力モードと切り替える」をオンにすることで私は日本語↔︎ローマ字を切り替えています。（fnキーでもできそう）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523103/fb7b25db-7942-04aa-d82a-80c69054b600.png)


# おわりに
簡単ですがUS配列の魅力をご紹介しました。
Macの買い替えを検討している方はぜひUS配列も候補に入れみてはいかがでしょうか。
LeetCode挑戦日記：Day5

# はじめに

最近、業務で実装する時間よりも資料作成やレビューをする時間が多くなってきました。
このままでは自身のコーディング能力が落ちそうで怖いので、LeetCodeを始めてみました。

自身の学習の記録 & LeetCodeに興味のある人が挑戦しやすいように、記事に残していきます。
このような競技プログラミングをした経験がないので、ひよってEasyからやっていきます...

# [Easy] 1071. Greatest Common Divisor of Strings

インプット：文字列1、文字列2
アウトプット：文字列

インプットの文字列1とインプットの文字列2を共通して分割できる文字列をアウトプットとして返す。

## 素直に解いてみる

### 考え方

* インプットの文字列の長さが同じ場合
  1. 文字列が完全一致するか比較する
* インプットの文字列の長さが異なる場合
  * 長い方の文字列の長さが短い方の文字列の長さのn倍の場合
    1. 長い方の文字列を短い方の文字列の長さで分割したとき、全て完全一致するか比較する
  * 長い方の文字列の長さが短い方の文字列の長さのn倍ではない場合
    1. 長い方の文字列を短い方の文字列の長さで分割したとき、全て完全一致するか比較する
    1. 余った文字列の長さで短い方の文字列を分割し、全て完全一致するか比較する

### コーディング

```typescript
function getDividedString(longStr: string, shortStr: string): string {
    const longStrLength = longStr.length;
    const shortStrLength = shortStr.length;

    if (longStrLength % shortStrLength === 0) {
        const splitted = longStr.split(shortStr);
        return splitted.every((s) => s === "") ? shortStr : "";
    } else {
        const splitted = longStr.split(shortStr);
        if (splitted.length <= 1) {
            return "";
        } else {
            const reminder = splitted.pop() || "";
            if (!splitted.every((s) => s === "")) {
                return "";
            }
            return getDividedString(shortStr, reminder);
        }
    }
}

function gcdOfStrings(str1: string, str2: string): string {
    const str1Length = str1.length;
    const str2Length = str2.length;

    if (str1Length === str2Length) {
        return str1 === str2 ? str1 : "";
    }

    if (str1Length < str2Length) {
        return getDividedString(str2, str1);
    } else {
        return getDividedString(str1, str2);
    }
}
```

### 結果

Runtime：45ms
Beats 97.96% of users with TypeScript

Memory：51.89MB
Beats 42.19% of users with TypeScript