OmniAICreator/Qiita-1.07M huggingface dataset:
KeyCloakマネジメントコンソール画面を日本語化するのに苦戦した話

# はじめに

認証サーバーとして、KeyCloakを使い始めたのですが、
ネットに書いてある通りにやっても日本語化ができず、半ばあきらめていました。

ちょっとした落とし穴でしたが、他にも困っている方がいるかもしれないと思い記事にさせていただきました。


# docker-composeでkeycloak構築

docker-compose.ymlファイルを作成し、以下をコピペ。
ただし、※の部分は自由に変更すること。(変えなくても動く)

```yaml
version: '3'

volumes:
  mysql_data:
      driver: local

services:
  mysql:
      image: mysql:5.7
      volumes:
        - mysql_data:/var/lib/mysql
      environment:
        MYSQL_ROOT_PASSWORD: root   ※
        MYSQL_DATABASE: keycloak    ※
        MYSQL_USER: keycloak        ※
        MYSQL_PASSWORD: password    ※
  keycloak:
      image: quay.io/keycloak/keycloak:legacy
      environment:
        DB_VENDOR: MYSQL
        DB_ADDR: mysql
        DB_DATABASE: keycloak        ※ ↑のMYSQL_DATABASEに合わせる
        DB_USER: keycloak            ※ ↑のMYSQL_USERに合わせる
        DB_PASSWORD: password        ※ ↑のMYSQL_PASSWORDに合わせる
        KEYCLOAK_USER: admin         ※
        KEYCLOAK_PASSWORD: password  ※
      ports:
        - 8080:8080  ※
      depends_on:
        - mysql
```

```bash:bash
$ docker-compose up --build
```

# 日本語化

1. [localhost:8080](http://localhost:8080)にアクセス(ポートは自分で決めたものに)
1. Administration Consoleを選択

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/105baaa0-b6d3-3170-5ada-f022032999fe.png)

1. docker-compose.ymlファイルで設定したユーザー名とパスワードで入る

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/f6063a79-19a6-b60e-5cc3-7bf9f058ce9f.png)

1. `Master`レルムのまま`Realm Settings`を開く

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/406aed21-9648-c311-acf3-03a90859ebcf.png)

1. `Themes`タブより、`Internationalization Enabled`をオンにし、`Default Locale`を`ja`にする

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/c8b47d21-fb25-668e-2f76-6d59007532d8.png)

1. saveをしたら設定完了。

1. 一度右上のメニューから`Manage account`に移動すると日本語化されている

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/5726b8e3-fc79-67b4-4d84-09e0ae25b27a.png)
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/4177d107-fcee-51f1-fdb5-8878ec8752ff.png)
    

# 落とし穴

自分の場合は先にレルムを作成し、そのレルムで設定を変更していました。
マスターの設定が優先されるのか、Masterレルムの言語設定を変えないと反映されない仕様でした。


意外と気が付けなかったので他にも落とし穴にはまっている人がいたらご参考に
IntelliJでKtorのプラグインが見つからない

# はじめに

以下の書籍をやるのに`IntelliJ`をいれました。そして`Ktor`のプラグインをいれようとしたところ躓いたのでまとめます

https://www.amazon.co.jp/Kotlin%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/479806467X/ref=sr_1_2_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1S5T2XFC5YAG2&keywords=kotlin&qid=1671433900&sprefix=kotli%2Caps%2C198&sr=8-2-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExU0hOVVZRQlUwVTBKJmVuY3J5cHRlZElkPUEwODgwMDQwM043Mkg2MjlDRzVMNyZlbmNyeXB0ZWRBZElkPUEyTVI4TDUyVzRaWjhNJndpZGdldE5hbWU9c3BfYXRmJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ==

# 問題

「設定」→「プラグイン」で`Ktor`と検索しても表示されない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/2db2c207-7c4b-bb64-f517-1b2719d2649e.png)

# 解決方法

[こちら](https://sheltie-garage.xyz/tech/2022/07/%E5%88%9D%E3%82%81%E3%81%A6%E3%81%AEktor/)の記事に答えがありました

>現在Intellij Idea Community Editionでは、プラグインを利用したKtorプロジェクト作成は行なえません

私が利用しているのは`Community`ですがおそらく同じかと思います

なので[こちら](https://start.ktor.io/?_ga=2.262078024.459640936.1671428689-431925290.1671428689&_gl=1*mdbzbf*_ga*NDMxOTI1MjkwLjE2NzE0Mjg2ODk.*_ga_9J976DJZ68*MTY3MTQzNTAzOS4zLjEuMTY3MTQzODg2OC4wLjAuMA..#/settings?name=ktor-sample&website=example.com&artifact=com.example.ktor-sample&kotlinVersion=1.7.22&ktorVersion=2.2.1&buildSystem=GRADLE_KTS&engine=NETTY&configurationIn=CODE&addSampleCode=true&plugins=)からプロジェクトを手動で作成することにしました

もし書籍のハンズオンをやるのであれば`Mustache`というプラグインを追加してください
あとから`build.gradle.kt`に手動で追加したところなぜかプラグインの読み込みができませんでした

また、importと静的ファイルが少し変わっています。最後以下のコードで動きました

```kotlin:Application.kt
package com.example

import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import com.example.plugins.*
import io.ktor.server.routing.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.http.*
import io.ktor.server.mustache.Mustache
import io.ktor.server.mustache.MustacheContent
import com.github.mustachejava.DefaultMustacheFactory
import io.ktor.content.*
import io.ktor.server.http.content.*
import java.io.File

fun main() {
    embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
        .start(wait = true)
}

@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
    install(Mustache) {
        mustacheFactory = DefaultMustacheFactory("templates/mustache")
    }

    routing {
        get("/") {
            call.respondText("HELLO WORLD!", contentType = ContentType.Text.Plain)
        }

        get("/html-mustache") {
            call.respond(MustacheContent("index.hbs", mapOf("user" to MustacheUser(1, "user1"))))
        }

        // Static feature. Try to access `/static/ktor_logo.svg`
        static("/static") {
            staticRootFolder = File("static")
            files(".")
        }
    }
}

data class MustacheUser(val id: Int, val name: String)
```

画像はsrcディレクトリと同じ階層にstaticディレクトリを作り、そこにロゴの画像をいれました

# おわりに

LinuxのPCを買ってIntelliJをいれましたが、ほとんどの設定をやってくれるので楽でした
Winowsしか使ったことなかったのでいつも選んでいましたが、今後は値段もやすいのでLinuxいれれば良いなと思いました

# 参考

https://ktor.io/docs/serving-static-content.html#serve-folder
ディスクの暗号化

[Teradata Vantage - セキュリティ管理ガイド](https://docs.teradata.com/r/bA1wB88x_bsZxqkhvCF0mQ/D5QuHHrmM30Jny4hP_yWrg) [2022/12/08時点]の翻訳です。

VantageCloudにおける、ネットワークおよびデバイスのセキュリティについてご説明させていただきます。

:::note information
各機能の詳細な説明に関しては、段階的にリンクを追加していきますので、リンクから詳細ページを参照してご利用下さい。
:::

# ディスクの暗号化
VantageCloudはデフォルトでディスクの暗号化を実現しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962009/0b5d036e-6529-4aea-9ebd-9a27ec691e46.png)
AWSを例にとってご説明させていただきます。

データ書き込み時は、データキーを使ってブロックデバイス（EBSディスク）への書き込みの際に暗号化を実施します。ブロックデバイス（EBSディスク）上は暗号化されたデータが保管されます。

暗号化に使われるデータキー自体はAWSにて生成され、ユーザーからのアクセスはできませんが、これに加えて、お客様にて管理するカスタマーマネジメントキーを使うことも可能です。これによりデータキー自体も暗号化することで、強固な鍵管理を実現しています。なお、暗号化アルゴリズムは、業界スタンダードなAdvanced Encryption System 256bit暗号化を使用しています。

以上より、仮にハッキング等を受けた場合でも、内容を参照することは不可能となります。



## おわりに
:::note warn
警告
この本書は[Teradata Vantageドキュメンテーション](https://docs.teradata.com/)よりトピックに必要な情報を抜粋したものです。掲載内容の正確性・完全性・信頼性・最新性を保証するものではございません。正確な内容については、原本をご参照下さい。
また、修正が必要な箇所や、ご要望についてはコメントをよろしくお願いします。
:::

#### Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)
ネットワーク・セキュリティ

[Teradata Vantage - セキュリティ管理ガイド](https://docs.teradata.com/r/bA1wB88x_bsZxqkhvCF0mQ/D5QuHHrmM30Jny4hP_yWrg) [2022/12/08時点]の翻訳です。

VantageCloudにおける、ネットワークおよびデバイスのセキュリティについてご説明させていただきます。

:::note information
各機能の詳細な説明に関しては、段階的にリンクを追加していきますので、リンクから詳細ページを参照してご利用下さい。
:::

# ネットワーク・セキュリティ
ネットワークのセキュリティとして、VantageCloudの接続形態についてご説明いたします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962009/1cfa67c5-13e0-d881-ab35-2e597d5b35dd.png)
各クラウドベンダーへの接続は「専用線接続（ダイレクトコネクト等）」か「VPN接続」となります。

「専用線接続（ダイレクトコネクト等）」の場合、お客様オンプレ環境とクラウド間はネットワーク的にクローズドな環境となります。「VPN接続」の場合は前段でご説明した通り、Ipsec,TLSによって暗号化されたセキュアな通信アクセスとなります。

お客様VPCとVantageCloud間は、「private link」での接続となります。信頼関係のあるVPC同士の接続であり、接続ポートを限定した形での一方通行のセキュアなアクセスとなります。

## おわりに
:::note warn
警告
この本書は[Teradata Vantageドキュメンテーション](https://docs.teradata.com/)よりトピックに必要な情報を抜粋したものです。掲載内容の正確性・完全性・信頼性・最新性を保証するものではございません。正確な内容については、原本をご参照下さい。
また、修正が必要な箇所や、ご要望についてはコメントをよろしくお願いします。
:::

#### Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)
通信の暗号化

[Teradata Vantage - セキュリティ管理ガイド](https://docs.teradata.com/r/bA1wB88x_bsZxqkhvCF0mQ/D5QuHHrmM30Jny4hP_yWrg) [2022/12/08時点]の翻訳です。
VantageCloudにおける、ネットワークおよびデバイスのセキュリティについてご説明させていただきます。

:::note information
各機能の詳細な説明に関しては、段階的にリンクを追加していきますので、リンクから詳細ページを参照してご利用下さい。
:::

# 通信の暗号化
VantageCloudは通信段階でも業界ベストプラクティスな方法でデータをセキュアに暗号化しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962009/2be9c222-bd32-0831-0db4-0630690bf19e.png)
暗号化の対象として「外部ネットワークからの通信」および「アプリケーションレベルでの通信」が対象となると思います。

「外部ネットワークからの通信」に関しては、さらに「専用線接続（ダイレクトコネクト等）」かそうでないかに分かれます。「専用線接続（ダイレクトコネクト等）」の場合は、ネットワーク的に閉じた世界となるため、特に考慮は不要です。

そうでない場合、クラウドへの接続はVPN接続が一般的だと思います。このVPN接続の暗号化として、VantageCloudでは、ネットワーク層およびデータリンク層での保護としてIpsec、トランスポート層での保護としてTLSによる暗号化が必須となっています。暗号化のアルゴリズムは、最新の鍵暗号アルゴリズム（Advanced Encryption Standard　256bit）を使用しています。

「アプリケーションレベルでの通信」に対する暗号化対策として、VantageCloudではSSHが必須となっており、ODBC接続・JDBC接続時には必ず暗号化設定を行ったうえでの接続が必要となります。

## おわりに
:::note warn
警告
この本書は[Teradata Vantageドキュメンテーション](https://docs.teradata.com/)よりトピックに必要な情報を抜粋したものです。掲載内容の正確性・完全性・信頼性・最新性を保証するものではございません。正確な内容については、原本をご参照下さい。
また、修正が必要な箇所や、ご要望についてはコメントをよろしくお願いします。
:::

#### Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)
シングルテナント

[Teradata Vantage - セキュリティ管理ガイド](https://docs.teradata.com/r/bA1wB88x_bsZxqkhvCF0mQ/D5QuHHrmM30Jny4hP_yWrg) [2022/12/08時点]の翻訳です。

VantageCloudにおける、ネットワークおよびデバイスのセキュリティについてご説明させていただきます。

:::note information
各機能の詳細な説明に関しては、段階的にリンクを追加していきますので、リンクから詳細ページを参照してご利用下さい。
:::

## シングルテナント
VantageCloudはすべての環境でシングルテナントにてサービスをご提供させていただいております。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962009/caa4f146-f923-aef7-9d33-dc757f14048b.png)

通常のクラウド系DWHは、A社のような「ハードウェアをマルチテナントで構え、個人情報等の最重要なデータ含めてデータ自体はオブジェクトストレージに配置する」パターンか、B社のような「ハードウェア自体はシングルテナントとするものの個人情報等含むデータはオブジェクトストレージに配置する」パターンになると思います。

A社の場合、ハードウェア、ストレージの両方ともマルチテナント環境となり、データベースのセキュリティ制御機能とストレージ単位の暗号化でセキュリティを担保する形になります。またB社の場合は、ハードウェアはシングルテナントとなりますが、データはオブジェクトストレージでマルチテナント環境に格納形になりますので、暗号化は可能ですがストレージ単位の暗号化までとなります。

VantageCloudの場合、「ハードウェアをシングルテナントとし、データも（オブジェクトストレージではなく）ブロックストレージへ配することにより、データ含めシングルテナント化」しています。さらに、このブロックストレージ自体も暗号化することで、個人情報等の機密性の高いデータをより強固に保護することが可能となっています。
また、ネットワークに関しても個別のインタフェースにて分離、ハードウェアレベルでのセキュリティを確保しております。
加えて、データアクセス時のトークナイズオプションも選択が可能であり、機密性の高いデータをよりセキュアに保護することが可能なシステムとなっております。

当然のことながら、必要時にはオブジェクトストレージ上のデータにも透過的にアクセス可能であり、データの配置場所にかかわらずシームレスにアクセス可能です。
重要なデータをクラウドに預けるということを考えた場合、各環境がシングルテナントで独立していること、暗号化されていることが、選択するうえでの重要なポイントになるのではと弊社では考えております。


## おわりに
:::note warn
警告
この本書は[Teradata Vantageドキュメンテーション](https://docs.teradata.com/)よりトピックに必要な情報を抜粋したものです。掲載内容の正確性・完全性・信頼性・最新性を保証するものではございません。正確な内容については、原本をご参照下さい。
また、修正が必要な箇所や、ご要望についてはコメントをよろしくお願いします。
:::

#### Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)
VantageCloudセキュリティ

[Teradata Vantage - セキュリティ管理ガイド](https://docs.teradata.com/r/bA1wB88x_bsZxqkhvCF0mQ/D5QuHHrmM30Jny4hP_yWrg) [2022/12/08時点]の翻訳です。

VantageCloudのセキュリティについてご説明させていただきます。

本シリーズでは、Vantageの持つ、セキュリティ機能についての情報を掲載していきます。

<iframe width="560" height="315" src="https://www.youtube.com/embed/cSP5e0WjKt4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

:::note information
各機能の詳細な説明に関しては、段階的にリンクを追加していきますので、リンクから詳細ページを参照してご利用下さい。
:::

## セキュリティ認証への対応
VantageCloudは各種機関のセキュリティ認証に対応しており、新たな認証への対応も適時進めております。

すでに、ISO、PCIDSS、SOCなど主要なセキュリティ認証に対応済みであり、認証に準拠可能なセキュリティ対策・体制を整えて、サービス提供しておりますので、お客様はデータベース環境のセキュリティについて安心してご利用頂くことが可能です。また医薬品の規制・ガイダンスであるGxPへの対応、金融機関様でのSecurity ReferenceとなるFISCにも対応完了しております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962009/cf05679a-3289-688d-2005-0c3441c48b86.png)

# セキュリティ管理プログラム
セキュリティ管理に関して、弊社ではNISTという米国の国立標準技術研究所にて規定された「NIST SP 800-39 情報セキュリティリスクの管理」をベースにセキュリティ管理プログラムを作成しております。
これはリスクを定義することを基準に、評価・対応・監視を繰り返すことで、未知なるリスクへもプロアクティブに対応できるよう作成されたものとなります。

具体的にはリスクを定義することを基準に、評価・対応・監視を繰り返すことで、未知なるリスクへもプロアクティブに対応することが可能となるよう作成されたものとなります。

:::note information
NISTとは科学技術分野における計測と標準に関する研究を行う米国商務省に属する政府機関であり、SP800シリーズはコンピュータセキュリティ関係のレポートで、米国の政府機関がセキュリティ対策を実施する際に利用することを前提としてまとめられた文書となります。
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962009/813d1bc4-c377-5b9d-d35a-b359c924e03e.png)

想定されるリスクを定義し、これを評価することで、リスクの重要度等を明らかにしたうえで適切な対応内容を策定します。
あわせて、常にリスクを監視することで、リスク管理のプロセス自体を改善していくことが可能となります。

リスクは常に発生するものであり、はじめにすべてを定義することは困難ではありますが、適切な監視および管理を行うことで新たなリスクに対する対応も可能となります。

# セキュリティ・フレームワーク
VantageCloudはセキュアな環境でデータを活用していただけるように、以下のフレームワークでデータを保護しています。
「ネットワークおよびデバイスセキュリティ」、「システムセキュリティ」、「データベースセキュリティ」の各カテゴリにて、それぞれ必要な対応・対策を実装しております。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962009/327bfd25-b6a5-2dec-f98f-a8fd9ce9acae.png)

| カテゴリ | 対応・対策 |
|:-|:-|
| ネットワーク<br>・デバイスセキュリティ| [シングルテナント](https://qiita.com/motomatsu/items/724385a7ca7e5e0e4caf) <br> [通信の暗号化](https://qiita.com/motomatsu/items/9d241e771ed320042d8e) <br> [ネットワークセキュリティ](https://qiita.com/motomatsu/items/0e60ebc8c1f8e6ea9200) <br> [ディスクの暗号化](https://qiita.com/motomatsu/items/2fc817af4de29e378a2a) 　　　　　　|
| システムセキュリティ<br> | [セキュリティインシデント検知](https://qiita.com/motomatsu/items/710c08c472ac10a42470) <br> [不正アクセス検知](https://qiita.com/motomatsu/items/c19b1622f7c842ae799b) <br> [ウィルス対策](https://qiita.com/motomatsu/items/0b271da990e9c4d2d8a6) <br> [脆弱性管理](https://qiita.com/motomatsu/items/de2f777cfcc4b6bb6eba) <br> [セキュリティパッチ](https://qiita.com/motomatsu/items/ac84f4a07db19fee8af4)  　　　|
|データベースセキュリティ<br> （後日更新予定） |  データ保護<br>パスワード管理<br>認証<br>ログ監査<br>データアクセス制御<br>データ暗号化トークナイズ　　|


## おわりに
:::note warn
警告
この本書は[Teradata Vantageドキュメンテーション](https://docs.teradata.com/)よりトピックに必要な情報を抜粋したものです。掲載内容の正確性・完全性・信頼性・最新性を保証するものではございません。正確な内容については、原本をご参照下さい。
また、修正が必要な箇所や、ご要望についてはコメントをよろしくお願いします。
:::

#### Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)
[web制作][初心者向け] position:relative を使わずに、gridで画像の中央にずれないテキスト（説明文）を重ねる方法

gridについて学んでいる際に便利なテクニックを知ったので、備忘録として残したいと思います。

# こういうのが作りたい
以下の図のように、画像の中心に説明文を配置したい。
![２　画像の中にテキスト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664550/945c3231-d27f-452c-7c34-9037f38c7895.png)

# position:relativeだと上手くいかない
画像の中心に説明文を配置する方法について調べてみると、
親要素に position: relative;
子要素に position: absolute;（今回の場合は中央にしたい説明文に対して）
を設定。
さらに子要素に　top: 50%; や left: 50%;
などを追加していく方法が紹介されていたので試したのですが、
画面の幅を変えると説明文が中央からずれてしまい、
レスポンシブ対応が上手くいきませんでした。
![２　右にずれる.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664550/c6c65b3f-6ca2-253a-4e8e-8922ce909c19.png)

# gridだとシンプルかつレスポシブル対応が簡単

そこで登場するのがgridです。
親要素をgridコンテナー
子要素をgridアイテム
として、子要素を同じ格子（場所）に配置することで、
子要素を重ねることができます。

# HTML
まずはHTMLからです。
今回はこの画像と説明文の１つの組み合わせをclass="card"とします。

```index.html
<div class="card">
  <img class="card-image" src="" alt="" />
  <div class="card-description">
    <h2 class="card-description-title">Heading</h2>
    <p class="card-description-text">テキストテキストテキスト</p>
  </div>
</div>
```
親要素をclass="card"として、
その子要素にimg(class="card-image")とdiv(class="card-description")
を入れています。

# CSS gridコンテナーとgridアイテムを設定
次はcssです。
早速gridを使用します。
```style.css
.card {
  display: grid;
}
```
これだけで親要素のclass="card"がgridコンテナーとなり、
子要素がgirdアイテムとなったため、自由に配置していくことができます。

# CSS 画像の中央に説明文を配置
それでは画像の中央に説明文を配置していきます。
まず画像についてです。
```style.css
.card-image {
  /* 格子のサイズに合わせて画像サイズを変更する */
  justify-self: stretch;
  grid-column-start: 1;
  grid-row-start: 1;
}
```
こうすることで、１×１マスの格子の中に、格子のサイズいっぱいに調整された画像が配置されます。

次に説明文です。
```style.css
.card-description {
  /* 説明文を水平方向の（横軸の）中央に配置する */
  justify-self: center;
  /* 説明文を垂直方向の（縦軸の）中央に配置する */
  align-self: center;
  grid-column-start: 1;
  grid-row-start: 1;
}
```
こうすることで、先ほどの画像と同じ1×1マスの格子の中央に説明文が配置されます。

つまり、この時点で画像の中央に説明文が配置されたので、目標達成です！

# 形を整える

では最後に理想の形に近づけていきます。
```style.css
.card-description {
  justify-self: center;
  align-self: center;
  grid-column-start: 1;
  grid-row-start: 1;
  /* 説明文の背景色を灰色にする */
  background-color: grey;
}

.card-description-title {
  /* 説明文の見出しを中央揃えにする */
  text-align: center;
}
```
![２　完成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664550/2f7db0d2-c541-4c6b-291c-8ed9a961a83c.png)

完成です！
画面幅を変更しても、説明文が画像の中央をキープしてくれます。

最終的なコードはこちらになります。
```index.html
<div class="card">
  <img class="card-image" src="" alt="" />
  <div class="card-description">
    <h2 class="card-description-title">Heading</h2>
    <p class="card-description-text">テキストテキストテキスト</p>
  </div>
</div>
```
```style.css
.card {
  display: grid;
}

.card-image {
  justify-self: stretch;
  grid-column-start: 1;
  grid-row-start: 1;
}

.card-description {
  justify-self: center;
  align-self: center;
  grid-column-start: 1;
  grid-row-start: 1;
  background-color: grey;
}

.card-description-title {
  text-align: center;
}

```
ゲーム会社におけるNotion利用術

本記事は[サムザップ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/sumzap)の12/20の記事となります。
昨日の記事は@norimatsu_yusukeさんの[【CRI】Asset Support Add-onを使ってCRIの音・動画をUnityアセットとして扱う](https://qiita.com/norimatsu_yusuke/private/8bbbeb57fcfbca304de0)でした。

# はじめに
Sumzapでサーバエンジニアをしています@chrno001です。

昨年のAdvent CalendarやPHPerKaigiにて

https://qiita.com/chrno001/items/10a474ded7ed488e8695

https://speakerdeck.com/sgeengineer/samuzatupuniokerunotionfalse-huo-yong-shi-li-tophpdefalsenotionapiwoli-yong-sitashi-zu-migou-zhu-falseshao-jie?slide=4

という風に、弊社におけるNotionへの移行について紹介させて頂きました。
今回は、移行後Notionをどのように使っているかを一例を紹介させて頂きたいと思います。


## 仕様書
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104363/4eba9ae0-4fa1-9869-9280-554cf521d1e3.png" width=45%>　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104363/186e3889-6a16-12ca-9aa2-c3e6d921b686.png" width=48%>
今まではプランナーさんがそれぞれ色々なツールで作成していたりしたため、そもそもどこに最新の資料が置いてあるのか直接ヒアリングしないと分からないといった状態が発生していましたが、Notionにまとめるようにしてからは資料を探す手間がだいぶ軽減されたかと思います。
さらに仕様書作成にはテンプレートを用意して作成してもらっている為、担当者毎の情報粒度の差を軽減したり、Notionのリレーション機能を使って各仕様書についてのQ&Aをまとめページにて確認できるようになっています。

## 技術共有・作業メモ
![技術メモ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104363/df963969-e973-5aa6-ef5e-0e81789ea1d2.png)
今までもドキュメントは残すようにしてもらっていましたが、なかなかエンジニアが積極的に資料を残すという事はあまりできてなかった印象でした。
しかしNotionに変わってからは手間なくドキュメント作成ができる為、指示がなくても作業メモを残すなど結構皆が活用してくれている印象で各種ルールや技術共有事項などのナレッジ蓄積が進んできていると思います。

## タスク管理
![タスク管理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104363/ff384971-252a-4d0f-89b9-2cf020ab6db9.png)
エンジニア内で課題と思う事や決めないといけないと思う事などが発生したらすぐにタスク化して残してもらうようにしています。
それを定例のMTGで話あい、詳細ややるやらの判断、実施時期を決めてスケジュールに落とし込むようにしています。
今までは取りこぼしていた事項もタスク化してある事で忘れずに対応できるようになった事は重要かなと思います。

## 議事録
![議事録.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104363/58c329c1-55f6-9428-a7a4-296a38443d0e.png)
MTGを実施したらかなり口煩く（汗）議事録を残すようにとチームには言っているおかげかどうかは分かりませんが、全体的にちゃんとNotionにて議事録を残すようになってきたと思います（ただ、このあたりは人による所も大きいので継続して啓蒙していかないといけなさそうです）
また、DBにて議事録を管理している為に後から確認するにも非常に便利になったかと思います（●●について言った、言ってないはつきものなのでちゃんと後から読み返して内容が把握できる議事録を残す事が重要ですね）


## NotionAPI活用
以前紹介していますが、別プロジェクトではNotionAPIも積極的に使用しているようです（自分のプロジェクトではそこまでまだ使用できていないので今後の課題です）
https://developers.notion.com/

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104363/b6c3bf20-7c51-3f7f-21ae-0d31b99885e0.png" width=46%>　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104363/0df7fafc-6fd7-8759-9b7c-e635bd99989c.png" width=50%>
NotionAPIの活用の一例として、マスターデータのバリデーションチェックに使っていたりします。
まず、マスターデータをスプレットシート上で入力し、その後slackにてデプロイコマンドを入力すると対話型botが起動し、デプロイ及びバリデーションスクリプトが実行される形となります。
バリデーションスクリプトが実行されると、バリデーション結果をNotionAPIを利用してNotionのデータベースに格納しどのようなエラーが発生したかをチェックできる仕組みとなっています。

# まとめ
上記で紹介した以外の活用もしてはいますが、Notion自体非常に多くの機能を有していて正直まだ全然使いこなせているとは言えないと思います。
業務活用においてこんな使い方もできるよ！！という事例がありましたら是非ご紹介頂ければと思います。
皆でNotionの沼にどんどんハマっていきましょう（笑）

明日は@shintsu_takamasaさんの記事です。お楽しみに！！
DebounceでVuejsのパフォーマンスを最適化

VueJsが利用されているWebアプリケーションをパフォーマンス向上したところでDebounceという概念を見当たりました。
良い改善点だと思いますので、こちらの記事でDebounceのやり方を紹介させて頂きたいと思います。

## 拝見

インタラクションWeb アプリケーションを開発するなら、特にVueJsのWebアプリケーションを実装する際に、パフォーマンス最適化について考えた方が良いと思います。Windowイベントリスナー登録の辺り、検索フォームの入力にタイピング、スクロール、エレメントのサイズ変更などのイベントをリッスンすると、重い処理を実行したら、アプリケーションが重くなって、レスポンスが反応できない可能性があります。

例：検索機能を開発する前提でユーザーに良いUI・UXを提供したい為、ユーザーが検索のテキストボックスに入力したら、自動的に検索結果を出すようにします。ただ、問題になるのはユーザーがキーボードを打つ度に、APIでデータを取得するという重い処理が実装されてきて、キーボードで入力する回数により、APIを呼び出す処理がどんどん溜まり、アプリケーションでは膨大なネットワークリクエストが生成されてしまいます。なので、パフォーマンスが減ることになっています。

## Debounceについて

上記の例で発生した問題はDebounceを導入したら、簡単に解決できます。
Debounceを導入したら、キーボード入力イベントで行う処理が一時的に待たせるようにします。キーボードの打つが一定時間止まった時に検索の処理を行います。決まったテキストで検索するなら、キーボードの打つを連続して文字を入力終わりまで、検索結果を所得リクエストは1回だけです。このようにdebounceを利用することでシステムの処理の負荷を下げることができます。

こちらはデバウンス関数のコードスニペットです。

```javascript
export function debounce(fn, wait){
    let timer;
   return function(...args){
     if(timer) {
        clearTimeout(timer); // イベントにトリガーする際に、すでに存在しているtimerを削除する。
     }
     const context = this; 
     timer = setTimeout(()=>{ // イベントにトリガーする度に、新しい timerを作成する。
        fn.apply(context, args); // 一時的に待たせてから、処理を実行する。
     }, wait);
   }
}
```
## DebouceをVueのwatcherで導入してみる。

Vueのwatcherでユーザーがテキストボックスに入力したときに値のログに記録して、Fetch API を呼び出すという単純なコンポーネントを検討しましょう。

- debounce利用しない。

```javascript
<template>
 <div id="app">
  <input v-model="value" type="text" />
</div>
</template>
<script>
export default {
  data() {
    return {
      value: "",
    };
  },
  watch: {
    value(newValue, oldValue) {
      console.log("value changed: ", newValue, oldValue);
      // APIを叩いて、データーを所得する
    }
  }
};
</script>

```
上記の例では、ユーザーがフォームに値を入力するたびに、コンソールに値のログが記録され、何かのAPIが呼び出されます。APIをそのように呼び出すなら、アプリケーショのパフォーマンスが改善できません。

- debounce利用する。
```javascript

<template>
 <div id="app">
  <input v-model="value" type="text" />
</div>
</template>
<script>
import {debounce} from "./Utils.js";
export default {
  data() {
    return {
      value: "",
    };
  },
  created(){
     this.debouncedFetch = debounce((newValue, oldValue)=>{
            console.log("value changed: ", newValue, oldValue);
           // APIを叩いて、データーを所得する
     }, 1000);
  },
  watch: {
    value(...args) {
      this.debouncedFetch(...args);
    }
  }
};
</script>
```
上記のコードでは、最後のキーボード打つことから 1000 ミリ秒が経ると、ユーザーはコンソールにログインするとAPIの呼び出すなどの処理が実行されます。

debouncedFetch のインスタンスを作成することで、Watcherにdebouncedが実装されます。debouncedFetchの中身にはコールバックと待ち時間を定義されています。このインスタンスはcreated()フックで作成され、Watcher内で適切な引数をコールバックの変数に渡します。

## 参考

https://blog.logrocket.com/debounce-throttle-vue/
visudoのエディタをnanoからviに変更する

## 環境
Ubuntu20.4

## はじめに
**/etc/sudoers**を編集するために**visudo**を起動したところ、**nano**が起動されたため、デフォルトのエディタを**vi**に変更しました。

## 現状確認
**visudo**を実行して起動されるエディタは、次のコマンドで確認することができます。**/bin/nano**にチェックがついているため、**nano**が起動されるようになっています。
```
$sudo update-alternatives --config editor
There are 4 choices for the alternative editor (providing /usr/bin/editor).

  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /bin/nano            40        auto mode
  1            /bin/ed             -100       manual mode
  2            /bin/nano            40        manual mode
  3            /usr/bin/vim.basic   30        manual mode
  4            /usr/bin/vim.tiny    15        manual mode
```

viには２つのエディションがインストールされているようです。
- vim.basic  ： 標準機能版
- vim.tiny   ： 最小機能版

どちらか選択する前に、普通にviを実行すると、どのエディションが起動されるようになっているかを確認します。
```
$ls -l /etc/alternatives/vi
 /etc/alternatives/vi -> /usr/bin/vim.basic
```

**vim.basic**が有効になっているようなので、visudoで起動するviも、**vim.basic**を選択することにします。

## 設定変更
vim.basicを設定するので、「3」を入力して、Enterを押します。
```
$sudo update-alternatives --config editor
Press <enter> to keep the current choice[*], or type selection number:
```

vim.basicで設定されたようです。
```
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/editor (editor) in manual mode
```

## 設定後の確認
確かに、vim.basicに変更されていることを確認します。
```
$sudo update-alternatives --config editor
There are 4 choices for the alternative editor (providing /usr/bin/editor).

  Selection    Path                Priority   Status
------------------------------------------------------------
  0            /bin/nano            40        auto mode
  1            /bin/ed             -100       manual mode
  2            /bin/nano            40        manual mode
* 3            /usr/bin/vim.basic   30        manual mode
  4            /usr/bin/vim.tiny    15        manual mode
```

visudoをすると、viが起動してくれるようになりました。
```
$sudo visudo
```

## おまけ
visudoを実行すると、viが起動されるようになったが、一時的にnanoを使いたい場合は、次のようにすれば、nanoで起動することができるようになります。
```
$sudo EDITOR=nano visudo
```

## 参考
https://qiita.com/koara-local/items/35b999631b6ab41fdc9f
Fernのdrawerでファイルを開いた時drawerを自動的に閉じる

## 環境
```
NVIM v0.8.0-1210-gd367ed9b2
Windows 10 Home
lambdalisue/fern.vim v1.51.4
```
## 動機
https://github.com/lambdalisue/fern.vim/issues/411  

や

https://github.com/lambdalisue/fern.vim/wiki/Tips#close-fern-after-open  

で提案されているような
```lua:
vim.keymap.set("n", "<CR>", "<Plug>(fern-action-open)" .. "<Plug>(fern-close-drawer)", {buffer = true})
```
といったキーマップだと、tキーの新しいタブで開く方法でFernを自動的に閉じることができない。

## 方法

```lua:init.lua
vim.api.nvim_create_augroup("vimrc", {})
vim.api.nvim_create_autocmd("WinEnter", {
  callback = function()
    if(vim.bo.filetype ~= "fern") then
      vim.cmd("FernDo close -stay")
    end
  end,
})
```

## 備考
引用元のIssueがやや古いため、もしかしたら既により良い解決策が実装されているかもしれません。
クロスビルドのすすめ

mruby 3.1のarmv5tのセルフビルドとRyzenでのクロスビルドのスピードを比較してみました。

armv5tの方はKirkwoodでクロックは1.2Gです。OSはNetBSD 9.0です。

RyzenはFreeBSD/amd64 13.1RのBastilleBSDに環境があります。Ryzen 2400Gでクロックは3.6Gです。クロス(OS)のクロス(アーキテクチャ)です。

セルフのほうを準備します。

まずここにあるruby30-baseのpkgをインストールします。

http://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/earmv4/9.0_2022Q3/All/

次にrakeをインストールします。

```
# gem30 install rake
```

~~bisonはインストールしてあったので、~~(必要なくなったようです)mruby 3.1をビルドします。

```
# /usr/pkg/lib/ruby/gems/3.0.0/gems/rake-13.0.3/exe/rake
```

クロスのほうは[ここに](https://qiita.com/yamori813/items/1eb41bf0c11b2ec1d0fa)書いた手順でビルドします。

クロスは33秒でした。

セルフは1582秒でした。

50倍くらい違いますが、クロスのツールとかライブラリの用意も必要なのでまるまるというわけでもありません。

セルフのarmは結構早いほうで、クロックが250Mのターゲットもあり、もしこれでビルドすると200倍くらい違うかもしれません。

armはNetBSDで動かしていますが、FreeBSD/armはクソでNetBSDの20倍くらい遅いので、1000倍くらい違いになるのかもしれません。

rakeがマルチコアに対応すればもっと差は広がるでしょう。

matzのスライドにウサギとカメがでてきますが、人生無限ではないので、資源がゆするのであれば、有効に時間を使いましょう。
JavaScriptでクリップボードにコピーする方法（ライブラリ不要）

現在Vue.jsで開発をしていて、以前ならvue-clipboard2というライブラリを導入していたのですが、現在はブラウザAPIに navigator.clipboardというのがあり、ほぼ全てのブラウザに対応していることを確認したのでこちらのAPIを利用して開発することにしました。

ですので、バニラJSのみ・数行のコードで完結します。特別なライブラリなどは不要です。

この記事ではその方法を紹介します。

## ブラウザの Clipboard API を利用する
ブラウザからクリップボードにアクセスできるのが Clipboad API です。

> Clipboard API は、切り取り、コピー、貼り付け機能をWebアプリケーションに実装するために使用できます。

CLipboard API に関するMDN Web Docs
https://developer.mozilla.org/ja/docs/Web/API/Navigator/clipboard

## コピーするメソッド
下記のコードで任意の文字列をコピーできます。
```JS
navigator.clipboard.writeText("任意の文字列");
```

## コピーする HTML & JS コード
事例として、ボタン(button)をクリックすることでコピーできるコードを紹介します。
```html
<div id="txt">コピーしたいテキストはこれ</div>
<button id="btn">コピーする</button>
```

```js
// HTML要素取得
const txt = document.getElementById('txt');
const btn = document.getElementById('btn');

// コピー処理（btnがクリックされたらtxtをコピーする）
btn.addEventListener('click', () => {
  if (!navigator.clipboard) {
    alert("残念。このブラウザは対応していません...");
    return;
  }

  navigator.clipboard.writeText(txt.textContent).then(
    () => {
      alert('コピー成功👍');
    },
    () => {
      alert('コピー失敗😭');
    });
});
```

## おわりに
一部ではiOS対応してないーという声もネットにはあったのですが、私のiPhone / iPadでは問題なく動作しました。

とはいえ、万が一動作しない場合や非対応ブラウザのためにif文で処理を書きました。

## 参考

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

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

https://noveblo.com/javascript-copy/
技術者にとってのフロー状態

「フロー状態」というのはいわゆる「神様が降りてきた状態」とでも言えばよいのでしょうか。ある作業に100%に没頭している非常に生産性が高い状態のことです。
「フロー」はflow。スポーツでは「ゾーンに入る」とも言いますね。ソフトウエア開発の世界では「邪魔されないフロー状態に入ること」を、「wired in」、「The Zone」、「hack mode」に入るなどと呼んでいます。


# ・フローの構成要素
心理学者のチクセントミハイ（ Mihaly Csikszentmihalyi ）は、フロー体験の構成要素を6つ挙げています。
1. はっきりした目的
2. その目的に対する高い集中
3. その活動にはまり込んだ感覚
4. あっという間に時間が経過する感覚
5. 成功と失敗が明確
6. 活動が易しすぎず、難しすぎない
を挙げています。

## ・フロー状態をへの入り方（例えば）

> 私はカレンダー通りに生活し、集中する時間をできるだけ多くとるようにしています。その時間は、すべての通知を切り、気の散るアプリケーションを終了して、歌詞のない音楽をかけます。フロー状態に入るまで大体 10 分から 15 分かかります。さらに、集中タイムは最低でも 2 時間ずつのブロックでとるようにします。そうでないと、いいところまで行く前に中断することになったり、反対に会議に遅れたりするからです。
—CATT SMALL、ASANA、製品デザイナー (ゴール)

> データサイエンティストとして、私はどんな分析を行う前にもフロー状態に入るように心がけています。フロー状態に入るためにはまず 5 分間の休憩を取ります。その間は特に何も考えないようにして、心を空っぽにします。その後、残った時間はひたすら呼吸に集中します。そうすると「ゾーンに入った」状態になり、難しい問題に挑戦する準備が整うのです。
—AVINASH NARAYANAN、ASANA、データサイエンティスト

> 私は、面白くて取り組みがいのある仕事をしていると、いつの間にかフロー状態に入ります。たとえば、ある程度得意な分野でのデバッグ作業や、実装したものが既存のコードと思ったようにうまくかみ合わない理由を探す作業などです。また、思う存分集中できる余裕も必要です。その時の気分に合った音楽を選んで、じっくり作業に集中します。”
—GINA BOLOGNESI、ASANA、製品エンジニア

> プログラムリーダーの私は、受信トレイに入ってくる仕事に対応する作業と、集中して取り組む個人の仕事の両方に時間をかける必要があります。受信トレイの仕事にまとめて応答する時間を決めておくと、かなりフロー状態に入りやすくなります。あるいは、何度も作業が中断されないように受信トレイの通知をオフにすることもあります。通知アイコンを見ると慌てるものですが、受信トレイに届くものがそこまで緊急であることは滅多にありません。
—YAMILEX AVILA-STANLEY、ASANA、ソフトウェアエンジニア

> 私は、自分がフロー状態に入るには「計画を立てる」「環境を作る」「集中する」の 3 つの段階があることに気づきました。フロー状態に入るには、長時間、邪魔が入らずに作業できることが必要です。月曜日は会議の予定をほぼ入れないことにし、ほかにも会議とランチ、個人的な休憩を組み合わせてカレンダー上でまとまった空き時間を作るようにしています。フロー状態に入りやすいスケジュールを立てることで、長期的に見ればより効果的なワークスタイルを確立し、影響力の高い仕事を達成できます。”
—DAVID BRANDT、ASANA、インフラエンジニア

## ・フロー状態を達成する条件（具体的には）

1. 明確な目標を立てる
2. 気が散るものを減らす
3. 割り込み（電話とか通知とか）をオフにする
4. マルチタスクをやめる
5. 好きなことをする、することを好きになる

## ・フローを妨げるもの

1. 曖昧な目標、明確でない指示
2. 暴力的な割り込み（電話とか通知とか）
3. 結果に対する曖昧なフィードバック

## ・技術者がフローのためにできること

1. 作業のゴールを書き出す
2. 遅いPCは使わない
3. 動きの早いツールを使う
4. 大きなディスプレイ
5. タイピング訓練
6. 騒がしい環境を減らす（電話オフ、通知オフ、イヤホン、歌詞のない音楽）
7. 割り込みを完全になくす


自分が仕事中に流す音楽（画面の中の人も勉強しているなーと思ってやる気が出る）
[https://www.youtube.com/watch?v=kgx4WGK0oNU](https://www.youtube.com/watch?v=kgx4WGK0oNU)
入社2年目インターン生のメンターになったよ

株式会社LabBaseで主にフロントエンドエンジニアをしている伊藤です。
昨日の記事は ゾネスさんによるChrome便利ツールNetLogを利用した問題判別の記事でした。([こちら](https://note.com/tyrwzl/n/n046d33d368a2))

今回は入社2年目でインターン生のメンターになる際に学んだこと、やっていく上で糧になったことまとめていこうと思います。

## はじめに
10月からメンターとして、インターン生の相談や不安、不満などのヒアリングや仕事のサポートを行ってきました。
始める前はいきなりメンターに任命されて不安なところなどが多々ありましたが、以下の本を読み少し緩和されつつ進めていきました。

## メンターとは
ある分野について経験豊富な人が"先輩"として、仕事の進め方やキャリア、モブプロなどをしていく人を指します。そして、その対象の人をメンティーと言います。

ですので、目的はメンティーの不安を取り除いて、お互いに成長、一人前にしていくこと。また、メンターを通じてマネジメント経験を積むことにより今後大きな人数での指導ポジションやリーダーなどをやっていく上での糧になります。

## リーダー・マネージャーとの違い
私は、メンターになる上で今のマネージャーとやることは似ているので、違いはなんだろうと思い少し調べました。
リーダー・マネージャーはメンバーの成長より組織の目標達成にコミットします。目的の優先順位が異なるため、同一人物がメンターとリーダーを兼務するのは難しそうです。メンター制度自体、従来のマネジメントでは成長にコミットできないためそこをサポートするために生まれた制度なので、良くないですね。

## メンターになる前に調べて意識したこと
- メンターになったら、メンティーの業務をこなし結果を出す力を強化することが、仕事
 ・メンターの役割は助けること、難しい部分などを助けつつ進めます

- 避けるべきこと
　・考え方(やる気)や力不足など、メンターがコントロールできないところに注力する

- 何も情報がない会話を避ける

- 参考
 [エンジニアリング組織論への招待](https://amzn.asia/d/0MpJuaU)

## やっていく上で注力したもの
- ２週に一回の1on1
 ・目標について話し合う
　　・不満点がないか
　　・作業をしていく上で不安点はないか

- 立てていただいた目標に基づき作業分担を考える
　・チケットの担当割り振りをより目標に近いものにする

- 技術的課題はモブプロで
　・不安点で出していただいた部分をモブプロ等を行って改善する
　　・課題が出れば都度モブプロを行う

- 楽しく
　・偶に雑談を交えて、モチベーションUPへ

## やっていく上での課題点
- 自分の作業時間が減る(コードを書く時間)
- 作業をしている実感がない(チケットのストーリーポイントなどに出てこない)ので、モチベーション管理が難しい
- 弊社ではインターンのプログラマーにおいて、育成は初めてなので正解がわからない

## やっていく上でよかった点
- 今後のキャリアで自分はエンジニアでずっとコードを書きたいと思っていたが、マネージャの道を考えることができた
- 人に教えるという過程ややり方を理解
- インターン生といった自分より若いかたと触れ合うことでフレッシュな気持ちになる:)
- 楽しい

## まとめ
メンタリングで必要なこと、
- 抽象的に動くのではなく、具体的に目標などのデータをもとに行動する
- 考えが止まった時にモブプロなどを通して補助を行う
- 能力を伸ばしていく

本稿は[株式会社LabBaseテックカレンダーAdventCalendar2022](https://qiita.com/advent-calendar/2022/labbase) 20日目の記事です。
明日、21日のアドベントカレンダーは@guevara-netさんです。よろしくお願いします！
lambdaにfontを適用する方法

フォントファイルと以下の設定ファイルをfontsフォルダに入れてzip

```
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <dir>/var/task/fonts/</dir>
  <dir>/opt/fonts</dir>
  <cachedir>/tmp/fonts-cache/</cachedir>
  <config></config>
</fontconfig>
```

これをlambda layerに登録したあと、使いたい関数にも追加してあげる。

最後にLambdaの環境変数に以下を追加
FONTCONFIG_PATH	/opt/fonts

参考は以下。
https://medium.com/creditorwatch/aws-lambda-fonts-libfontconfig-5e837281a4ce
n個以上欠損値があるカラム（列）を削除

# 概要
pandasのデータフレームで欠損値がn個以上あるカラム（列）を削除したい場合の方法。

# データを用意
```Python
import numpy as np
import pandas as pd

data_path = "path/train.csv"
df = pd.read_csv(data_path)
```

# 方法1
dropna()を使う方法。
dropna()は欠損値ではない要素の数がn個以上ある列（行）を残し、それ以外の列（行）を削除する。
よって、欠損値がn個以上ある列を削除したい場合は、行数を取得して、(行数-n)をdropnaに渡してやれば良い。
以下は、n=5の場合。
```Python
n_samples = len(df)
n_thresh = n_samples - 5  # 行数 - n
df_null_rm = df.dropna(thresh=n_thresh, axis=1)
```

# 方法2
各列の欠損数を算出して、欠損数がn個より少ない列だけ抜き出す方法。
isnull()で欠損値か判定し、sum()で列ごとの欠損数を算出する。
各列の欠損数がn個より少ないかどうかを示すブール型のSeries(もしくはリスト)を算出し、locで抜き出す。
以下は、n=5の場合。
```Python
df_null_rm = df.loc[:, df.isnull().sum()<5]
```

もしくは、リストを使いたい場合は、
```Python
df_null_rm = df.loc[:, list(df.isnull().sum()<5)]
```
WSLとWindowsのファイル共有(ディレクトリ)の話


みなさんWSL2は使い倒していますか。
筆者はフロントエンド開発を進めていますが、その際にWSL2をよく使うようになりました。
このWSL2、直接Windowsのフォルダとファイル共有できるのも一つメリットではあると思いますが、
今回は**知ってると開発効率を上げられるWSLとWindowsのファイル共有の仕組み** と事例を綴っていきます。

とは言いつつ、初めての記事なのでお手柔らかに…
(結論から知りたい人は実例と速度比較まで飛んでください)

## 目次
1. WSL2とWindowsの関係
2. 実例と速度比較
3. おわりに

#### 1. WSL2とWindowsの関係
WSLとWindowsの関係に入る前にざっくりWSLについての公式の内容です。
(あくまでファイル共有に関する内容のため、WSLとWSL2の違いについては割愛します。)
- **WSL(公式より引用)**
>Linux 用 Windows サブシステムを使用すると、開発者は、従来の仮想マシンまたはデュアルブート セットアップのオーバーヘッドなしで、ほとんどのコマンド ライン ツール、ユーティリティ、アプリケーションを含む GNU/Linux 環境を変更せずそのまま Windows 上で直接実行できます

以下は公式から引用したWSLの仮想マシンとWindowsホストの関係図です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478627/1abbb360-60fa-65b0-54b9-9f451fefca9c.png)
([Microsoft Devblogより引用](https://devblogs.microsoft.com/commandline/wslg-architecture/)) 

- **Windows -> WSL2 のディレクトリ参照** 
WindowsからWSLのディレクトリへアクセスする際は見慣れたエクスプローラーを使って、
アドレス入力部分で```\\wsl$```を入れると
インストール済みのWSLのディストリビューション毎のファイルシステムにアクセスできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478627/27bf3a11-e304-7ed9-d51f-f3211a1776cf.png)


- **WSL2 -> Windows のディレクトリ参照**
WSLからWindowsへアクセスする際は```/mnt/c/```(Cドライブ基準)に移動することで
Windowsディレクトリへのアクセスが可能になります。
以下は遷移先のディレクトリで、Windowsのものと一致していることがわかると思います。
(画像は一部加工しています)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478627/e231926a-8b39-2d90-0a47-eda5613a8437.png)

#### 3. 実例と速度比較
さて、ここまでWSLとWindowsのディレクトリ遷移方法について述べましたが、
アクセス方法に遅延が生じるのは「仮想ファイルシステムとしてマウントしているディレクトリへのアクセス」が原因です。

実際に私が構築したReactでビルドしてからブラウザの立ち上がりまでの時間を計測した結果が以下になります。
|方法|起動までの時間|
|--|:--:|
|Windowsのディレクトリ上でビルドした場合|約150秒|
|WSL2のディレクトリでビルドした場合|約7秒|

上記の通りWindowsを用いた時の遅延が一目瞭然です。
また、**Windows上のディレクトリでビルドすることによってホットリロードも効かない**ということがわかり、
開発速度がメタメタに落ちます。
これらのことから**WSL2上で動かしたいプログラムはWSL2上のディレクトリを使いましょう**。
ちなみにWSLとWSL2のアクセスパフォーマンスについては[公式でも発表](https://learn.microsoft.com/ja-jp/windows/wsl/compare-versions#comparing-features)されていました。


#### 4. 終わりに
いかがだったでしょうか。
今回は初のQiita記事でWSL2とWindowsのディレクトリアクセスの速度についてのお話をしました。
結果として、WSLとWindowsはそれぞれの環境の上で実行するのが実行速度は速いということですが、
さらに高速化したいという方は、
ぼうびろぐさんの[WSL2とWindowsのファイルのやり取りを500MB/sまで高速化した](https://wooolwoool.hatenablog.com/entry/2022/07/11/075915)
を使うことでもさらに速度を向上できるようなので是非試してみてください。

記事の内容に不自然な部分もあると思いますが、コメントいただければ更新もしていきますので宜しくお願いいたします。





-以上-
キャッシュ設計(3) - 依存 

## キャッシュは難しい

この記事ではWebアプリケーションの出力のキャッシュが困難な理由とそれを解決する方法について考えます。

## 静的コンテンツのキャッシュの実際

静的コンテンツは完全にHTTPキャッシュが実現されています。

CSSファイルやJSファイルをCDNに載せるのは簡単です。一度ディプロイしてしまえば基本的には変更がないものとしてTTL（生存期間）を設定できます。

HTMLではサーバーはそのファイルがいつ最後に更新したかを知ることができますし"Last-modified"ヘッダーに付加することができます。変更があれば以前のETagを無効にして新しい"ETag"を有効にします。いつコンテンツの変更があったのかを正確に、低いコストで知ることができます。そのETagの維持には関心を払う必要さえありません。全ては自動でHTMLファイルのキャッシュは完璧です。一度GETされたHTMLはCDNとクライアントに保存され、コンテンツに変更があっても条件付きリクエストで即座に反映されます。

## Webアプリケーションでは管理が必要

Webアプリケーションのイベントドリブンコンテンツの最終更新日付はいつでしょうか？これは誰がどう管理すべきでしょうか？

データベースの「記事テーブル」に作成日時や更新日時のカラムが加えられることがありますが、これをそのまま利用すればいいでしょうか？ブログの記事ページは、記事だけでなくカテゴリーや人気記事一覧などの他のコンテンツも含まれまれ、これを全体のページの最終更新日付とすることはできません。

含まれるコンテンツ全ての更新日付のうちの最も新しい日付が分かれば、それをページの最終更新日付にしてその日付が更新されるタイミングでコンテンツ全体のハッシュを計算してETagを生成することはできます。

## コンテンツ間の依存の管理

つまりイベントドリブンコンテンツのページ全体としてのキャッシュをするときは、サーバーサイドでのコンテンツの依存管理が必要です。ページAはコンテンツBとコンテンツCを含んでいて、コンテンツBはコンテンツDを含んでいる。このような場合、コンテンツB、C、Dいずれかが更新された時にコンテンツAの更新日付とETagを更新するような管理が必要になってきます。

しかもこの依存に基づいたキャッシュの無効化はRedisなどのサーバーサイドや、CDNの双方に必要です。こんな面倒な依存グラフを手動で管理したくありません。

## キャッシュタグ

しかしこの依存管理の強い味方となるソリューションがサーバーサイドのキャッシュ、CDNのキャッシュ双方にあります。

* Symfony Cacheの**タグ**機能 https://symfony.com/doc/current/cache.html#using-cache-tags
* Fastlyのサロゲートキー https://docs.fastly.com/ja/guides/working-with-surrogate-keys

それぞれ呼び方は違いますが、考え方は同じです。つまりコンテンツを保存するときに、その依存をタグとして保存しておいて後で、そのタグをキーにキャッシュの無効化を行うことができるのです。

先ほどの例だとページAを保存する時にB, C, Dのタグをつけて保存しておけば、B,C,Dのいずれかのコンテンツが更新されるタイミングでページAのキャッシュとそのETagが無効化されます。

- Symfony Cacheはスマートで、Redisなどタグの機能があるものはそれを使い、ファイルキャッシュなどタグの機能がないものは独自に実装しています。

## インバウンドリンク

RESTにおいて、外のリソースをリンクすることをアウトバウンドリンクと呼び、リソース自身の中に他のリソースをリンクして取り込むことをインバウンドリンクと呼びます。HTMLではAタグは外のリソースをリンクするアウトバウンドリンクで、`<img>`タグや `<script>`タグはそのHTML自身にコンテンツを埋め込むインバウンドリンクです。

BEAR.Sundayでは`#[Embed]`リンクがインバウンドリンクです。これはそのままコンテンツの依存関係に利用できます。埋め込むリソースにタグを命名して、そのタグをつけてページのコンテンツのキャッシュを保存すれば良いのです。

ETagを保存する時にもこの依存のタグを使用して、依存が変更になったときにETagを無効化します。

## セマンティックメソッド

一般的にMVCのコントローラーは以下のようなものでしょう。

```php
class HelloController extends Controller
{
    public function index()
    {
        // .... $bodyを自由に計算
        return new Response($body)
    }
}
```

モデルの取得とその合成は自由で、制約はありません。どのモデルもどのようにもアクセスできます。しかし、人はコードを読んで理解できますが、セマンティックがないので機械（フレームワーク）から見ればどのモデルからどのように合成されているかは分かりません。自由に名付けた`read`メソッドや`fetch`メソッドはそれが読み込み用のものと人は理解できるでしょうが、機械は理解できません。全てを合成したレスポンス（文字列）を返却するだけです。

BEAR.Sundayは全てのモデル（リソース）にURIを含みます。`#[Embed]`アトリビュートはリソースを埋め込みながら、特定のリソースがどのリソースに依存をしているのかを宣言しています。

BEAR.Sundayには`onGet()`は非破壊的リソース操作、それ以外は破壊的リソース操作というセマンティックがあります。フレームワークがキャッシュの依存性を管理できる素養が見えてきました。

## AOP

理想的にはリソースがドメインを扱うときにログやキャッシュに関心を持ちたくありません。複雑なコンテンツの依存グラフなど尚更です。

AOPの出番です。インターセプターはメソッドが実行されるタイミングでその操作を見て、サーバーサイドのキャッシュとETagの作成や依存グラフによる破壊、更新を行います。CDNのキャッシュの破壊に関してもAPI経由で行います。

## ソリューション

Webアプリケーションのコンテンツの依存の構造があり、イベントドリンブンコンテンツページ全体をキャッシュするためには、その依存構造が反映されていないといけません。

既存のMVCフレームワークのアークテクチャは通常コンテンツの構造に関心がありません。

これはWordpressとWikiPediaのコンテンツ入力と対比させることができます。Wordpressは最終出力だけを考えて本文に自由にコンテンツを入力します。コンテンツは構造化されていません。対してWikipediaは特定の意味を表す記法など制約があり、コンテンツが構造化されていて再利用性や検索性に優れます。更に詳しくは[DCC](https://www.borndigital.co.jp/book/25550.html)をご覧下さい。

REST制約のインバウンドリンクによるリソース合成とセマンティックを持つメソッドにより、難題であった依存関係のあるイベントドリブンキャッシュが可能になりました。
Raspberry Piで色々やってみた

今回の記事は社内のチーム活動でラズパイを学習し、
ラズパイを使用した電子工作の紹介記事になります。








# 電光表示器
ラズパイに電光表示器を接続して任意の文字を電光表示器に出力させることに挑戦しました。
文字の出力でアルファベットは出来たのですが、日本語を出力するのに苦戦しましたが、
何とか出力できました。

外部サイトからヘッドラインニュースを取得し、電光掲示板に出力することができました。<br><br>


<iframe width="500" height="515" src="https://www.youtube.com/embed/Bb2uohBdfxQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>





# 音声
ラズパイにBluetoothでスピーカーを接続し、任意の文書を読み上げに挑戦しました。

デフォルトの音声は女性のため、女性から男性の声に変更することに挑戦してみました。:microphone2:

挑戦してみて男性の声変更がなかなか出来ず、設定の見直しや再構築も行い原因を調べたうえで、製品サポートへ問い合わせした結果、男性用の音声セットが存在することがわかり、入手して適用することで男性の声も出るようになりました。
<br>

<iframe width="560" height="515" src="https://www.youtube.com/embed/hLl01po7Q4g" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


# BGM

スピーカーからBGMと音声を同時に出力することに挑戦してみました。:loud_sound:　


同時出力させるまでに時間がかかりましたが、
同時出力の方法について調べ、何とかコマンドから同時に出力させることができました。<br><br>

<iframe width="500" height="515" src="https://www.youtube.com/embed/pkMQ8g-rUEY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


# MP3プレイヤー

最後に電光表示器や音声・BGM出力を組み合わせてMP3プレーヤーの制作を行いました。



MP3形式の音楽ファイルに埋め込まれているID3タグ情報を読み取り、
音楽を流しつつ、アーティスト名やアルバム名が表示できるようにし、
さらに、自作のアニメーションを追加することで、市販のMP3プレイヤーのようにできました。<br><br>




<iframe width="500" height="515" src="https://www.youtube.com/embed/piTnstRp3qs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


# まとめ
去年からラズパイ学習し今年は様々なことに挑戦ができました。
これからもラズパイ工作をしていきたいです。
「UIサウンド」ってなに？

音出してますか！？

グレンジのサウンドクリエーター/サウンドデザイナーのかわのです。お初です。
今回は「UIサウンド」について少しだけお話しできればと思います。
![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985465/c4f14b1f-2b50-89ca-305f-c2d3c9771b29.png)
スマートフォンゲームの大半は
**「ユーザーとスマホ間のユーザーインターフェース（UI）のやり取り」**
によってゲームが成り立っています。

なのでUIのデザインはとっても大事。
ゲームの根幹といっても言い過ぎではないかと思います。
にも関わらず、UIの「サウンド」のデザインまで目を（耳を？）向けられている作品がとても少ないことに気づきます。

そもそも「UIサウンド」とは？
馴染みのない方もいるかと思いますが、言い方の問題だけで、普段の生活には満ち溢れています。
○レンジのチン
○踏切の警報機
○車のクラクション
○ATMやセルフレジの操作音
etc.

これらの音の有無で体験がどう変わるか想像するのが、
UIサウンドデザインの必要性を説く上でもっともわかりやすいかと思います。

UIサウンドとは一言で言うと、
**「状況や状態を知覚させるために意図的に鳴らす音」**
となります。


例えば電源の入ってないスマホをタップ。
音は鳴りますでしょうか？

鳴ります。

指が画面に触れる音、服が擦れる音（衣擦れ音）、勢いよくタップすれば指を振るう風切音なんかも鳴るかもしれません。
ただし、それらはスマホが何かを知らせるために意図的に鳴らした音ではないため「UIサウンド」とは言えません。

電源が入って起動音が鳴った。

この起動音は
**「スマホの電源が入ったことをユーザーに知覚させる」**
という意図を持って鳴らされているので「UIサウンド」と言えると思います。

ゲームではこう言った「意図を持ったサウンド」がゲームの進行に応じて複数無数に流れます。
![IMG_0572.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985465/29045416-d083-4fbc-e614-320532a12414.jpeg)

鳴らす音のもつメッセージ性、世界観。それらの再生タイミングや音量、同時発音数など、
ユーザーにとってより良い体験、よりゲームに没入できるよう、配置、整理、設計するのがUIサウンドのデザインです。

ゲームに限らず、スマートフォンアプリを構成する要素は
**「画面」（視覚）**
**「操作」（触覚）**
**「音声」（聴覚）**
の3つがほとんどを占めます。

その一角を担うサウンドという分野。
**サウンドのクオリティは、そのままアプリのクオリティに直結します。**

考えるべきことは色々ありますが、まずは
**「UIサウンドをデザインする」**
と言う意識を持つだけで、アウトプットは確実に変わります。

まずはサウンドのデザインを意識して音を出すことから始めてみてはいかがでしょうか？


（※UIサウンド、まだまだ研究勉強の余地がある分野なので一緒に追求してくれる方随時募集中です）
Web server one-liner by Ruby

# RubyによるWebサーバ・ワンライナー

```shell
ruby -e "require 'webrick'; WEBrick::HTTPServer.new({ DocumentRoot: './', BindAddress: '127.0.0.1', Port: 8000 }).start"
```

##### 参考にしたページ
- [【Ruby標準ライブラリ】WEBrickでWEBサーバーを作る手順 - shin>>media](https://shinmedia20.com/webrick-web-server)

## 追記
phpを使ったほうがはるかに楽ですね……。

```shell
php -S localhost:8000
```
C++のtemplate関数のファイル分割に関する覚書

先日、C++でライブラリを開発しようとしていたときにはまったtemplate関数についての覚書です。
### ファイル構造
.\\
  ├package
  │   ├sample.cpp
  │   ├sample.h
  └test_sample.cpp
### コードの内容
```package\sample.h
#pragma once

namespace sample
{
    tepmlate<typename tp>
    void func(void);
}

```
```package\sample.cpp
#include "sample.h"
template<typename tp>
void sample::func(void){}

```
```test_sample.cpp
#include "package/sample.h"

int main(void)
{
    sample::func();
}

```
### エラー
```terminal
PS .> g++ -c .\packages\sample.cpp
PS .> g++ -o test .\sample.o .\test_sample.cpp
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: C:\Users\iru\AppData\Local\Temp\ccmDDw3K.o:test_sample.cpp:(.text+0xc): undefined reference to `void sample::func<int>()'
collect2.exe: error: ld returned 1 exit status
```

### 解決方法
明示的にインスタンス生成を行う
具体的には./package/sample.cppを次のように変える
```package/sample.cpp
#include "sample.h"
template<typename tp>
void sample::func(void){}

template void sample::func<int>(void);

```
FuelPHP の Format でどうしても HTML のパースが失敗する場合

備忘録

## FuelPHP の HTML パーサー「Format」
FuelPHP で HTML をパースする時は、Format というライブラリを使います。使い方は以下です。

```php
$html = \Format::forge($html_body, "xml")->to_array();
$element = $html["path"][2]["html"]["element"];
```

でも、これでも失敗する場合があります。それは例えば、以下のような 文字列とタグを一緒にしたタグをパースする場合です。

```xml
<dblp>
<inproceedings key="conf/aaim/He07" mdate="2007-06-28">
<author>Dan He</author>
<title>
<i>BMA</i>
<sup>*</sup>
: An Efficient Algorithm for the One-to-Some Shortest Path Problem on Road Maps.
</title>
<pages>346-357</pages>
<year>2007</year>
<crossref>conf/aaim/2007</crossref>
<booktitle>AAIM</booktitle>
<ee>http://dx.doi.org/10.1007/978-3-540-72870-2_33</ee>
<url>db/conf/aaim/aaim2007.html#He07</url>
</inproceedings>
</dblp>
```

Title タグの中に、文字列とタグが一緒になっていますね。
このようなタグなどだと、Format は上手くパースしてくれません。

このような場合はどうするのでしょうか？

## Format の代わりに simplexml_load_string を使う

FuelPHP の HTML のパースは、`simplexml_load_string` というPHP組み込みの関数を使っています（該当コードは[ここ](https://github.com/fuel/core/blob/13b2bea30afc1a462003f5e6ff1794f413a8150b/classes/format.php#L425)）。
そして、自分の場合、パースが失敗するのは、この `simplexml_load_string` を出力する際に上手く結果が表示されないからでした。

---

なのでここではこの `simplexml_load_string` を使ってパースして、その結果を `dom_import_simplexml` という組み込みの関数で取得します。

```php
$body_xml = simplexml_load_string($html_body);
$unseen_xml = dom_import_simplexml($array_body2_xml->path->to-unseen->element);
echo $unseen_xml->textContent;
```

これで、Format で見えなかった要素も見れるようになれます。
（理想的には、Format::forge の結果から `dom_import_simplexml` したいのですが、コードだと [SimpleXMLELement から array にしている](https://github.com/fuel/core/blob/13b2bea30afc1a462003f5e6ff1794f413a8150b/classes/format.php#L429)ので上手くいきませんでした）

https://stackoverflow.com/questions/21660547/simplexml-load-string-has-a-bug

を参考にしました。
Wordpressでパンくずリストを実装（プラグインなし）

私がサイト構築する際に、使用している「パンくずリスト」です。

プラグインで簡単に実装は出来るのですが、お客様のサーバ環境によって、PHPのバージョンが古くプラグインが実装できない場合に重宝しています。
テーマファイルの別ファイルとして保存しているので、テーマさえ適用できれば、すぐに実装できる手軽さもあります。

ファイルはテーマファイルフォルダ内に`fnc-bredcrumb.php`として`fnc`フォルダへ保存して、`functions.php`に`get_template_part('fnc/fnc-bredcrumb');`を記述し、パンくずリストを使うテーマファイルで`output_breadcrumb();`で呼び出します。
※汎用性の高いファイルは、`fnc`フォルダへ別ファイルとして保存し、`functions.php`で読み込んでいます。

このデータは、特殊なページを想定していないので、カスタム投稿やタームによって表示を変えたい場合は、`elseif`で追加してください。
デザインが合えば、「HOME」の部分をFont Awesomeのアイコンや画像にしても良いですね。

このファイルを実装したら、CSSを適用するのを忘れずに。
`div`で囲まなくても良いように、`ul`に`.breadcrumb`を付与しているので、スタイルも当てやすいかと。
不要な場合は、下記コード内の3行目の`echo`内`class="breadcrumb"`を削除してください。
```diff_php
/////////////////////////////
//  パンくずリスト
/////////////////////////////
function output_breadcrumb() {
    $home = '<li><a href="' .get_bloginfo('url'). '">HOME</a></li>';
    echo '<ul class="breadcrumb">';

    //トップページの場合
    if(is_home() || is_front_page()) {
        //何も表示しない

    } elseif(is_category()) {
        $cat = get_queried_object();
        $cat_id = $cat->parent;
        $cat_list = array();
        while($cat_id != 0) {
            $cat = get_category($cat_id);
            $cat_link = get_category_link($cat_id);
                array_unshift($cat_list, '<li><a href="' .$cat_link. '">' .$cat->name. '</a></li>');
            $cat_id = $cat->parent;
        }
        echo $home;
        foreach($cat_list as $value) {
            echo $value;
        }
        the_title('<li>','</li>');

    } elseif(is_archive()) {
        echo $home;
        the_archive_title('<li>','</li>');

    } elseif(is_single()) {
         echo $home;

        $categories = get_the_category();
        if($categories) {
            echo '<li><a href="' . get_category_link( $categories[0]->term_id ) . '">' . $categories[0]->name . '</a><i class="fa-solid fa-arrow-right"></i></li>';
        }
        the_title('<li>','</li>');

    } elseif(is_page()) {
        global $post;
        $parent_id = $post->post_parent;
        $parent_title = get_post($parent_id)->post_title;

        if(is_page() && $post->post_parent) {
            echo $home;
            echo '<li><a href="' .get_permalink($parent_id). '">' .$parent_title.'</a></li>';
            echo the_title('<li>', '</li>');
        }else{
            echo $home;
            echo the_title('<li>', '</li>');
        }
    
    } elseif(is_search()) {
        echo $home;
        echo '<li>「' .get_search_query(). '」の検索結果</li>';
    
    } elseif(is_404()) {
        echo $home;
        echo '<li>404 ページが見つかりません</li>';
    }

    echo '</ul>';
}
```
簡単な条件分岐でできてしまうので、自分だけのパンくずリストを用意しておくのも良いかもしれません。