OmniAICreator/Qiita-1.07M huggingface dataset:
Reactのカスタムフックス

**Reactのカスタムフックスは、自分のアプリのに必要なロジックを再利用可能な形で分離するための方法を提供します。Reactのカスタムフックスを使用することで、ロジックをコンポーネント化し、広く再利用することが可能になります。以下では、カスタムフックスの概念と、実際の使用例を説明します。**

# 1. カスタムフックスとは何か

Reactのカスタムフックスは、同じロジックを複数のコンポーネントで再利用するために使われるフィルター関数です。名前は「use」から始まり、Reactのヒーローフックスの規則に適合した形で実装されます。これにより、常に利用されるロジックを簡単に拡張したり共有したりすることができます。

例えば、APIからデータを取得する処理を常に使う場合、各コンポーネントにその設定を記述するのは仿作的です。ここで、カスタムフックスを使用することで、その処理をカプセル化して使い回せるようになります。

2. カスタムフックスの作成例

以下は、APIからデータを取得するカスタムフックスの例です。

```javascript

import { useState, useEffect } from 'react';

const useFetchData = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const result = await response.json();
        setData(result);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
};

export default useFetchData;

```

# 2.1 使い方

例えば、上記の useFetchData フックスを使用して、APIからデータを取得するコンポーネントの例は以下の通りです。

```javascript
import React from 'react';
import useFetchData from './useFetchData';

const UserList = () => {
  const { data, loading, error } = useFetchData('https://api.example.com/users');

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <ul>
      {data.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
};

export default UserList;

```

これにより、「データ取得」という常に必要な処理を簡単に共有し、再利用可能にします。

# 3. カスタムフックスのベストプラクティス

**名前は「use」から始めるReactのヒーローフックスの規則にのっとって、カスタムフックスの名前は必ず「use」から始めましょう。これにより、Reactがそれをヒーローフックスとして認識します。**

一般化された処理を含むカスタムフックスには、複数のコンポーネントで共有されるような一般化された処理を含めましょう。これにより、メンテナンス性が向上し、コードがクリーンになります。

独立性を保つカスタムフックスは、実装するロジックが別の部分に影響しないようにすることが重要です。これにより、内部の状態が他のコンポーネントに影響しないように保証します。

# 4. まとめ

Reactのカスタムフックスは、再利用可能なロジックをシンプルな形で共有するための有力な方法です。このガイドを参考に、自分のアプリに必要なロジックをカスタムフックス化して、書きたいろいなコンポーネントに適用してみてください。

**最後までよんでいただきありがとうございます。
@y-t0910をフォロー,いいねしていただけると嬉しいです！**
【Discord】アイコンの取得方法解説！

こんにちは、りょうです。
今回はDiscordのアイコンについてです。
ではれっつごー

## 初期アイコンとは
初期アイコンは１色の背景にDiscordのロゴがついてるアイコンです。
なにも設定しないとデフォルトでこれになります。
色はグレー、緑、黄、赤、ピンク、青があります。
こんなの↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/2452f1f6-1449-828f-c45d-22e325aa67c6.png)

それぞれのURLを紹介
**青の初期アイコン**
```
https://cdn.discordapp.com/embed/avatars/0.png
```
**グレーの初期アイコン**
```
https://cdn.discordapp.com/embed/avatars/1.png
```
**緑の初期アイコン**
```
https://cdn.discordapp.com/embed/avatars/2.png
```
**黄色の初期アイコン**
```
https://cdn.discordapp.com/embed/avatars/3.png
```
**赤の初期アイコン**
```
https://cdn.discordapp.com/embed/avatars/4.png
```
**ピンクの初期アイコン**
```
https://cdn.discordapp.com/embed/avatars/5.png
```

# discord.jsでのアイコン取得
**`avatarURL`** と **`displayAvatarURL`** があります。
`avatarURL`のほうはサーバープロフィールのアイコンが返ってきます。
ただ、設定されていない場合はnullが返ってきます。
`displayAvatarURL`のほうはアバターが設定されていない場合上記で紹介したデフォルトアイコンのURLが返ってくるようになっています。なのでこちらを使うのがいいです。
## オプション
```js
displayavatarURL({ extension:png, forceStatic:false, size:2048 })
```
- フォーマット指定
- 画像サイズ指定
- 優先する形式の指定

**フォーマット指定**
**`extension: 拡張子`** で指定。デフォルトはwebPです。
指定できるフォーマットは`webp, png, jpg, jpeg, gif`のどれかですが、webhookではgifが使えないのでそこは注意です。

**画像サイズ指定**
**`size: サイズ`** で指定。
指定できるサイズは`16, 32, 64, 128, 256, 512, 1024, 2048, 4096`のどれか。

**優先する形式の指定**
**`forceStatic: ブール値`** で指定。
v13であったdynamicオプションとは逆の働きをするものになります。
なのでデフォルト(false)ではGIFアバターの場合はそのURLを取得します。
これをtrueにしておくとGIFアイコンではなく静止画のURLが返ってくるようになります。
まあこれはふつうにfalseでいいとおもいます。

**⚠注意⚠**
v13で使用されていたformatオプション、dynamicオプションはv14で削除されています。
それぞれextension、forceStaticに置き換わっているので知っておきましょう
# まとめ
今回はDiscordの初期アイコン、アイコンの取得方法に関する解説でした。

わからないことあったら書いてくれれば答えていきます。

**Discordにいる荒らしの情報や対策方法の共有をしている自鯖です**
ぜひ参加お願いします↓↓↓↓

https://discord.com/invite/ESRGwGQhxc
【satto】15分でサッと作る名刺読み取り&シート転記スキル



### 1. 新規作成をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/067c457c-621b-b786-f877-ac7354b98637.png" width="800">

### 2. プラスボタンからアプリノードを追加
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/9b5b1f6c-947a-2952-eb10-5487c9bc2974.png" width="500">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/d63ca4ae-9612-d1f8-af64-6c561e5e9eaa.png" width="500">

### 3. アプリ選択からGoogleスプレッドシートを選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/2e1f10bb-4574-9a47-8dab-cbb3f273cc61.png" width="500">

### 4. テンプレートから「シートの最後の行に値を追加」を選択
「生成」をクリックするとURLとBodyが生成されます
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/d08dbfaa-6e70-7f66-a845-d76e813b3c4e.png" width="500">

### 5. SheetIdとBodyの置き換え
SheetIdはスプシのURLの以下の部分をコピペしてください
```
https://docs.google.com/spreadsheets/d/{ここの文字列をコピペ}/edit?gid=0#gid=0
```
一旦、Bodyを以下の値に置き換えておきます。
```json
{
  "values": [
    ["新しいデータ1", "新しいデータ2", "新しいデータ3"]
  ]
}
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/d0134797-8aaa-3fb2-980d-4601e87cdf8c.png" width="300">

### 6. AIノードを削除
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/c0a17c09-a7bb-4c95-2946-b41d9590bfd8.png" width="300">

### 7. インプットノードからパラメータ追加をクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/313239ba-ae2e-d144-9fb1-bc042de1fb31.png" width="300">

### 8. ラベル名とパラメータの説明を入力
例として、「名前」をラベル名とパラメータの説明にそれぞれ入力します
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/e63f4cc4-457d-5f18-4036-0ed76e7ef05b.png" width="300">

### 9. 初期値オプションを選択
「AIに考えさせる」を選択します
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/c68c55cb-7195-c977-498b-557a3d6c33a1.png" width="300">

### 10. 他のパラメータも同様に作成
例として、名前だけでなく会社名やメールアドレスも同様に作成します
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/78049ed4-b4dd-c2d1-423f-0fcdde0e6234.png" width="300">

### 11. パラメータを参照
アプリノードのBodyから各パラメータを参照します 
注意: 現在の仕様では「半角」を入力してから「/」を入力しないとメニューが出現しないため、一度「半角入力 -> / -> 情報を選択 -> 半角を削除」の順番で対応してください
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/936cd7e1-9eb0-3f28-f2c2-4d60f4eaf0ce.png" width="300">

### 12. 実行して確認
作成した内容を実行し、入力されていることを確認します
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/20274ab8-64ee-684a-b65d-e3b88ef651fc.png" width="400">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/5bb59cbe-cbd7-0d26-4363-f9c985810a7f.png" width="400">

### 縦型でも試してみる...
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/ab7a83e8-fdf5-daa1-a201-1695e77e0778.png" width="300">

縦型でも無事読み取れました！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353509/5bb59cbe-cbd7-0d26-4363-f9c985810a7f.png" width="400">
最尤推定まとめ

# Abstract
- 最尤推定量は、点推定において「良い推定量」の各条件を自動的に満たしやすい、推定量の優等生
- 十分性を自動的に満たす
- 不偏性、一致性、有効性を持つ場合が多い。直接満たさなくても、ちょっとの修正を施せば、または極限を取れば漸近的に満たす場合が多い
# 点推定の目的
- 母数$\theta$点推定問題は以下のように定式化できる
標本空間を$\mathcal{X}$、母数空間を$\Theta$、決定空間を$\mathcal{D} = \\{ \theta を採用 | \theta \in \Theta \\}$とする.
損失関数を二乗誤差にとって、
$L:\Theta \times \mathcal{D} \to [0,\infty):(\theta,d) \mapsto L(\theta,d) = (\theta - d)^2$
とし、リスク関数
$E[L(\theta,\delta(X))]=E[(\theta - \delta(X))^2]$(平均二乗誤差,MSE)を最小にする決定関数$\delta:\mathcal{X}\to \mathcal{D}$を求める. 点推定における決定関数は「推定量」と呼ばれ、$\theta$の推定量はハットをつけて$\hat{\theta}=\hat{\theta}(X)$と書く.
- 統計的決定理論の一般論より、一般にすべての$\theta$について一様にリスク関数を最小にする決定関数は存在しない。つまり、ここでは最小二乗誤差を最小にする推定量を直接求める一般的な手段が無い.そこで次のような伝統的手続きが取られる
    - 考える推定量のクラスを制限し、制限されたクラスのなかで平均二乗誤差を最小にする推定量を求める
- MSEはバイアス-バリアンス分解できることから、バイアスをゼロにするような推定量=不偏推定量を制限クラスにして、その上で分散を最小化するという手順を取る。
- しかし、不偏推定量を構成するのが難しい場合や、分散とのトレードオフによって上手くいかないこともある.
- そこで最尤推定量を使う

# 最尤推定量の威力
不偏推定量$\hat{\theta}^{*}$が
$Var_\theta(\hat{\theta}^{*}) = \frac{1}{I_n(\theta)}, \forall \theta$
を満たせば$\hat{\theta}^{*}$はUMVUである
【React】React (+Vite) で TailwindCSS を適用する

## はじめに
ReactでのTailwindCSSの適用方法で少しつまずいたので、セットアップ方法をまとめます。
一般的な方法、Viteを用いた方法をそれぞれ記載しています。

## セットアップ方法
1. プロジェクト作成
    ```
        npx create-react-app my-project
        cd my-project
    ```

    :::note info
    Viteの場合、以下のコマンドで作成します。
        
    ```md:Vite
        npm create vite@latest my-project -- --template react
        cd my-project
    ```
        :::
    
1. TailwindCSSをインストール
    ```
        npm install -D tailwindcss
        npx tailwindcss init
    ```

    :::note info
    Viteの場合、以下のコマンドでインストールします。
    
    ```md:Vite
        npm create vite@latest my-project -- --template react
        cd my-project
    ```
        :::


    
1. 作成された`tailwind.config.js`ファイルを開く
1. contentプロパティのパスに、srcフォルダ内のファイルをすべてを参照するパスを指定する
    ```tailwind.config.js
    /** @type {import('tailwindcss').Config} */
    module.exports = {
      content: [
        "./src/**/*.{js,jsx,ts,tsx}",
      ],
      theme: {
        extend: {},
      },
      plugins: [],
    }
    ```
    ```JS
    "./src/**/*.{js,jsx,ts,tsx}"
    ```

5. `index.css`に、tailwindの情報を追加する

    ```index.css
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    ```

## さいごに
通常のReactの`create-react-app`での作成方法と、Viteを用いた方法では若干異なるところに注意しましょう！

### 参考
https://tailwindcss.com/docs/guides/create-react-app

https://tailwindcss.com/docs/guides/vite
Salesforceのプロンプトビルダーについて

## はじめに
今回は、SalesforceのAI機能のひとつであるプロンプトビルダーについて紹介していきます。

## プロンプトビルダーとは
プロンプトビルダーとは、Salesforceの生成AI機能であるEinstein GPTの構成要素であり、Einstein GPTに対する指示（プロンプト）を簡単に作成できるツールです。

## プロンプトテンプレート
プロンプトビルダーは、プロンプトテンプレートと呼ばれる変数を埋め込んだ雛形的なプロンプトを作成します。
プロンプトを呼び出す時に適切な値を変数にセットすることでプロンプトの再利用が可能になり、業務の効率化を図れます。

## グラウンディング
プロンプトテンプレート内の変数に値をセットしてプロンプトを具体化することをグラウンディングと呼びます。
グラウンディングでは、レコードの項目などのSalesforce内のデータに加え、Data Cloudのデータやテキスト、APIで取得した外部のデータ等も差し込むことが可能です。

## プロンプトテンプレートの活用例
### メール本文の自動生成
ワンクリックで顧客情報をもとにパーソナライズされたメールを自動的に作成することができます。

### 項目の値を自動生成
顧客情報をもとに、ロングテキスト項目等の項目の値を自動生成することができます。レコードの情報に応じて規則的に値が変化するような項目に活用することができます。

## まとめ
以上のように、プロンプトビルダーを活用してプロンプトを再利用することで、定型的なメールの作成を効率化できたり、担当者に依存しない一貫した文章を作成することが可能になります。それにより、業務の効率化だけでなく品質の一定化やヒューマンエラーの削減にも繋がります。
【Salesforc】帳票DXの概要

## 帳票DXとは？
「帳票DX」は、Salesforce上で帳票作成と自動化が可能なAppExchageです。Salesforce内のデータを活用し、各種帳票（例：見積書、請求書、注文書など）を迅速に作成できるため、業務の効率化を支援します。ドラッグ＆ドロップで簡単に帳票のレイアウトを設定でき、顧客の要望に応じた帳票を出力できます。

## 主な機能と特徴
### 柔軟な帳票レイアウト
帳票DXでは、帳票のレイアウトを自由にデザインできます。ドラッグ＆ドロップ操作で項目を配置でき、Salesforce上のデータと連携することで、複雑なレイアウトの帳票にも対応可能です。

### 多様なファイル形式での出力
帳票の出力形式はPDF、Excel、Wordなどに対応しており、ビジネスニーズに合わせた帳票形式を選択できます。PDF形式の請求書やExcelでの見積書作成など、顧客や社内の要望に応じて柔軟に対応できます。

### 自動化とワンクリック出力
Salesforceのプロセスビルダーやフローと連携し、条件に応じた帳票の自動出力も可能です。また、レコードページにボタンを追加することで、ワンクリックでの帳票出力を実現し、日常業務を効率化できます。

### リアルタイムデータの活用
Salesforce上のデータをリアルタイムで帳票に反映できるため、常に最新の情報をもとに帳票を出力可能です。これにより、手入力によるミスを防ぎつつ、顧客に正確な情報を提供できます。

### セキュリティとアクセス管理
Salesforceのアクセス制限と組み合わせて帳票の生成権限を管理できるため、セキュリティ面も安心です。役職や権限ごとに帳票生成のアクセス権を設定し、機密情報の漏えいリスクを軽減します。

### 導入メリット
時間の削減と効率化
手動で帳票を作成する手間を省き、帳票作成のスピードを大幅に向上させます。Salesforce内のデータを自動的に帳票に反映するため、手入力によるエラーや修正の必要も減ります。

### コンプライアンスの強化
帳票に含まれる内容はSalesforceのデータをもとに自動生成されるため、記載内容の整合性が保たれ、コンプライアンスの向上に寄与します。

### 柔軟なカスタマイズ性
帳票の内容やデザインは自社のブランドや業務ニーズに合わせてカスタマイズ可能で、他のアプリケーションとの連携も容易です。

## こんな要件におすすめ
請求書や見積書などの帳票を多く扱う
正確で一貫した帳票の作成
業務効率化と作業時間の削減

## まとめ
帳票DXは、Salesforceでの帳票作成をより簡単に、効率的に行えるよう設計されたAppExchageです。自由なカスタマイズ、豊富な出力形式、セキュリティに配慮した設計など、多機能で柔軟な帳票作成が可能です。顧客に合わせた帳票の出力や、リアルタイムデータを用いた正確な帳票作成を通じて、業務のDXを強力にサポートします。
Windows ServerでOneLake ファイルエクスプローラーを利用する

検証用途でプロキシ環境下のWindows ServerでOneLakeファイルエクスプローラーをインストールする際に詰まったため、備忘録としてまとめました。

### 要約
- プロキシ設定はシステム環境変数に追加
- Windows Searchサービスの有効化が必要

# 1. システム環境変数の設定

システム環境変数の設定から、下記のようにプロキシ情報を設定する。
|変数|値|
|:--|:--|
|http_proxy|http\://proxy.example.com (実際のプロキシ情報を設定)|
|https_proxy|http\://proxy.example.com (実際のプロキシ情報を設定)|

# 2. Windows検索サービスの有効化

サーバーマネージャ > 管理 > 機能と役割の追加」から「Windows Searchサービス」を追加。

# 3. OneLakeファイルエクスプローラーのインストール

[公式サイト](https://www.microsoft.com/en-us/download/details.aspx?id=105222)からOneLakeファイルエクスプローラーをダウンロードし、管理者権限のPowerShellで以下を実行。

```PowerShell:PowerShell
Add-AppxPackage -Path .\Onelake_PuPr_****.msix # ダウンロードしたファイルのパス
```
サーバを再起動し、ログイン画面が表示されることを確認。Fabricワークスペースへのアクセス権があるアカウントでログインすれば利用可能です。

:::note info
上記手順でOneLakeファイルエクスプローラーが起動しない(タスクバーにアイコンは出るのに操作できない)場合は、以下を試してください。
:::

### 参考

試行錯誤の過程で、下記のものをインストールしました。


**Microsoft.UI.Xaml.2.8** (appxファイル)
2.8系のAssetsから、Microsoft.UI.Xaml.2.8.x64.appxをダウンロードする。
https://github.com/microsoft/microsoft-ui-xaml/releases?q=2.8&expanded=true

**Microsoft.VCLibs.x64** (appxファイル)
https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx

**アプリインストーラー** (msixbundle)
https://aka.ms/getwinget

**インストール方法**
```PowerShell:PowerShell
Add-AppxPackage -Path .\****.appx # ダウンロードしたappx・msixbundleファイルのパス
```
FFmpeg で画像の透明度を変更する方法

FFmpeg を使って画像の透明度をサクッと変更できないか調べたらサクッとできそうだったのでメモ。

# やり方
`vf` オプションに `colorchannelmixer=aa=〇〇` 形式で `〇〇` に透明度（不透明度）を指定すればOK。

# 検証

## 元画像
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/2b455dda-f1b0-c474-9d8b-d8c93895cc43.png width=300 />


## 例：画像の透明度を50％にする（半透明にする）

```shell
ffmpeg -i input.png -vf "colorchannelmixer=aa=0.5" output.png
```

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/76630cc7-5c6a-e3d4-02dd-48851dcb2bfb.png width=300 />


## 例：画像の透明度を100％にする（透明にする）
```shell
ffmpeg -i input.png -vf "colorchannelmixer=aa=0.0" output.png
```

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/87fe7209-ba7c-c8f9-8f22-a3a6a05220bd.png width=300 />
「1ヶ月後」の定義

「翌月の同じ日。ただし同じ日が存在しない場合は、それより前の一番近い存在する日」とする派閥（Rails, moment js, PostgreSQL）と
「翌月の同じ日。ただし同じ日が存在しない場合は、余った日数の分、翌月にずれ込む」とする派閥（JS, Go）がある。

元の日付 | Rails派 | JS派
---|---|---
2024-01-28 | 2024-02-28 | 2024-02-28
2024-01-29 | 2024-02-29 | 2024-02-29
2024-01-30 | 2024-02-29 | 2024-03-01
2024-01-31 | 2024-02-29 | 2024-03-02
2024-02-01 | 2024-03-01 | 2024-03-01


## Rails

```ruby
irb(main):002> %w[2024-01-28 2024-01-29 2024-01-30 2024-01-31 2024-02-01].each { |d| puts "#{d} -> #{Date.parse(d) + 1.month}" }
2024-01-28 -> 2024-02-28
2024-01-29 -> 2024-02-29
2024-01-30 -> 2024-02-29
2024-01-31 -> 2024-02-29
2024-02-01 -> 2024-03-01
```

## moment
```js
> ["2024-01-28", "2024-01-29", "2024-01-30", "2024-01-31", "2024-02-01"].forEach(d => { console.log(d, "->", moment(d).add(1, "month").format("YYYY-MM-DD")); })
2024-01-28 -> 2024-02-28
2024-01-29 -> 2024-02-29
2024-01-30 -> 2024-02-29
2024-01-31 -> 2024-02-29
2024-02-01 -> 2024-03-01
```

## JS: setMonth(getMonth() + 1)
```js
["2024-01-28", "2024-01-29", "2024-01-30", "2024-01-31", "2024-02-01"].forEach(
	d => {
	  date = new Date(d); date.setMonth(date.getMonth() + 1);
		console.log(d, "->", (moment(date).format("YYYY-MM-DD")));
	}
);

2024-01-28 -> 2024-02-28
2024-01-29 -> 2024-02-29
2024-01-30 -> 2024-03-01
2024-01-31 -> 2024-03-02
2024-02-01 -> 2024-03-01
```

## Go

```go
package main

import (
	"fmt"
	"time"
)

func main() {
	dates := []string{"2024-01-28", "2024-01-29", "2024-01-30", "2024-01-31", "2024-02-01"}

	for _, date := range dates {
		added, err := time.Parse("2006-01-02", date)
		if err != nil {
			panic("time.Parse failed")
		}

		// 1ヶ月後の日付を計算
		oneMonthLater := added.AddDate(0, 1, 0)
		fmt.Printf("%s -> %s\n", date, oneMonthLater.Format("2006-01-02"))
	}
}

2024-01-28 -> 2024-02-28
2024-01-29 -> 2024-02-29
2024-01-30 -> 2024-03-01
2024-01-31 -> 2024-03-02
2024-02-01 -> 2024-03-01
```

### PostgreSQL

```sql
# SELECT '2024-01-28'::date + '1 month'::interval;
---------------------
 2024-02-28 00:00:00

# SELECT '2024-01-29'::date + '1 month'::interval;
---------------------
 2024-02-29 00:00:00

# SELECT '2024-01-30'::date + '1 month'::interval;
---------------------
 2024-02-29 00:00:00

# SELECT '2024-01-31'::date + '1 month'::interval;
---------------------
 2024-02-29 00:00:00

# SELECT '2024-02-01'::date + '1 month'::interval;
---------------------
 2024-03-01 00:00:00
 ```
markdownからコードブロックを抽出してファイルに書き込むプログラム md2file.py [uuencoded]


タイトル通りです。
複数のMarkdownファイルから、コードブロックを抽出し、ファイルに保存します。

ファイル名がダブっていたら、上書きしてしまいます。
ファイル名が指定されてなかったら、ファイル名抽出をミスる事があります。

Designed BY T.Maekawa
Code BY Google AI studio and T.Maekawa
Check By T.Maekawa

google AI studioのコードはPDSなので勝手に使っていいと書いてあったけれど、クレジットを入れました。

必要ないですが、uuencodeでencodeしています。
`
uudecode md2file.py.uu
`
で復号してください。

uuencode,uudecodeのインストールは、archlinuxでは、`sudo pacman -S sharutils`でできます。

```md2file.py.uu
begin 755 md2file.py
M(R$O=7-R+V)I;B]P>71H;VX*:6UP;W)T(')E"FEM<&]R="!O<PII;7!O<G0@
M<WES"@ID968@97AT<F%C=%]C;V1E7V)L;V-K<RAM87)K9&]W;E]F:6QE<RP@
M;W5T<'5T7V1I<CTB97AT<F%C=&5D7V-O9&4B*3H*("`@("(B(@H@("`@Z*2'
MYI6PXX&N36%R:V1O=V[C@Y7C@J'C@J3C@ZOC@8OC@HGC@K/C@[SC@XGC@Y;C
M@ZWC@X/C@J_C@I+FBKWEA[KC@9?C@('C@Y7C@J'C@J3C@ZOC@:ODOYWEK9CC
M@9?C@;[C@9GC@((*"B`@("!!<F=S.@H@("`@("`@(&UA<FMD;W=N7V9I;&5S
M.B!-87)K9&]W;N.#E>."H>."I..#J^.!KN.#D>."N>."DN:@O.>TC>.!E^.!
MG^.#JN."N>.#B..`@@H@("`@("`@(&]U='!U=%]D:7(Z(.:*O>6'NN.!E^.!
MG^."L^.#O..#B>."DN2_G>6MF..!F>."B^.#A^."H^.#K.."K^.#B..#JN.`
M@@H@("`@(B(B"@H@("`@:68@;F]T(&]S+G!A=&@N97AI<W1S*&]U='!U=%]D
M:7(I.@H@("`@("`@(&]S+FUA:V5D:7)S*&]U='!U=%]D:7(I"@H@("`@8VYT
M/3`*("`@(&9O<B!M87)K9&]W;E]F:6QE(&EN(&UA<FMD;W=N7V9I;&5S.@H@
M("`@("`@('=I=&@@;W!E;BAM87)K9&]W;E]F:6QE+"`G<B<L(&5N8V]D:6YG
M/2=U=&8M."<I(&%S(&8Z"B`@("`@("`@("`@(&-O;G1E;G0@/2!F+G)E860H
M*0H*("`@("`@("`C(&!@8&9I;&5N86UE(..!J"!@8&`@XX&GY9NRXX&^XX*,
MXX&?Z8.HY8B&XX*2YHJ]Y8>Z"B`@("`@("`@;6%T8VAE<R`](')E+F9I;F1A
M;&PH<B)@8&`H+BH_*5QN*%M<<UQ372H_*6!@8"(L(&-O;G1E;G0I"@H@("`@
M("`@(&9O<B!M871C:"!I;B!M871C:&5S.@H@("`@("`@("`@("!P871H(#T@
M;6%T8VA;,%TN<W1R:7`H*2`@(R#C@Y7C@J'C@J3C@ZOED(WI@ZCEB(;C@I+F
MBKWEA[H*("`@("`@("`@("`@9FEL96YA;64@/2!O<RYP871H+F)A<V5N86UE
M*'!A=&@I"B`@("`@("`@("`@(&-O9&4@/2!M871C:%LQ70H*("`@("`@("`@
M("`@(R#C@Y7C@J'C@J3C@ZOED(WC@8SC@:KC@83EH+3ED(CC@((*("`@("`@
M("`@("`@:68@9FEL96YA;64]/2(B.@H@("`@("`@("`@("`@("`@9FEL96YA
M;64]9B)?7WMC;G0Z,'LU?7TB"B`@("`@("`@("`@("`@("!C;G0K/3$*"B`@
M("`@("`@("`@(&EF("(Z(B!I;B!F:6QE;F%M93H*("`@("`@("`@("`@("`@
M(&9I;&5N86UE(#T@9FEL96YA;64N<W!L:70H(CHB*5LQ70H*("`@("`@("`@
M("`@9FEL97!A=&@@/2!O<RYP871H+FIO:6XH;W5T<'5T7V1I<BP@9FEL96YA
M;64I"B`@("`@("`@("`@('=I=&@@;W!E;BAF:6QE<&%T:"P@)W<G+"!E;F-O
M9&EN9STG=71F+3@G*2!A<R!O=71F:6QE.@H@("`@("`@("`@("`@("`@;W5T
M9FEL92YW<FET92AC;V1E*0H@("`@("`@("`@("!P<FEN="AF(N."L^.#O..#
MB>.#EN.#K>.#@^."K^."DB![9FEL97!A=&A](..!J^2_G>6MF..!E^.!ON.!
ME^.!G^.`@B(I"@H*:68@7U]N86UE7U\@/3T@(E]?;6%I;E]?(CH*("`@(&UA
M<FMD;W=N7V9I;&5S(#T@<WES+F%R9W9;,3I="B`@("!E>'1R86-T7V-O9&5?
78FQO8VMS*&UA<FMD;W=N7V9I;&5S*0H`
`
end
```
UTテストの推移とその有用性：効率的な品質管理と開発スピードの向上を実現する方法

## はじめに
- 本記事では、**単体テスト（UT）を中心としたテストの推移が品質管理や開発プロセスに与えるメリット**を解説します
- **効果的なテスト自動化のベストプラクティス**と、**可視化によるテストデータ活用の重要性**について理解を深めます

## 1. テスト自動化のベストプラクティス：ピラミッド型とアイスクリーム型
### ピラミッド型

- 理想的なテスト自動化戦略のモデルとして知られているピラミッド型について解説します。

![ピラミット型.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169095/9104b52e-13ee-e01e-599c-db4d174bd5a0.png)

テスト自動化のピラミッド型は、理想的な自動化戦略のモデルとして知られています。以下のように階層ごとに異なるテストが配置されます：

- 単体テスト (Unit Test)
    - ピラミッドの基盤を形成し、全体の70-80%を占めることが理想とされます。各モジュールや関数単位での早期バグ検出と修正が主な目的です。コストも低く、メンテナンスしやすいのが特徴です

- 統合テスト (Integration Test)
    - モジュール同士の連携やシステムの中層部分を確認するテストで、15-20%の割合で行われます。ここでは、ユニットが連携して正しく動作するかを確認します
- E2Eテスト (End-to-End Test)
    - ピラミッドの最上層にあり、5-10%程度に抑えることが望ましいです。システム全体の流れをユーザー視点で確認し、主要な操作が正しく行われるかを確認しますが、テストの実行やメンテナンスのコストが高いことから最小限に留めます
- 手動テストの役割（5-10%）
    - 新規開発の確認:
        - 新しい機能や変更の初期検証
    - 画面レイアウトの確認:
        - UIの崩れやデザインの問題を検出
    - 探索的テスト: 
        - 自動化で対応できない部分を補完する柔軟な対応
- メリット: 
    - 効率的で低コストなテストが実現でき、システム全体の安定性が向上します
### アイスクリーム型

- 一方、アイスクリーム型は現状のテスト自動化に多く見られるバランスの偏りを示すモデルです。特にE2Eテストが多く、単体テストが少ない状態を指します
![アイスクリーム型.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169095/4ff6e33a-540f-344a-bd98-66e5710bb381.png)

- **メリット**
    - **ユーザー視点でのテストが充実:**
        - E2Eテストを多く実施するため、ユーザーが実際に行う操作に基づいてシステム全体の動作を確認でき、ユーザー体験を向上させることができます
    - **本番環境に近いテスト:**
        - システム全体が連携する状態でのテストが行えるため、運用環境に近い形での動作確認が可能になります
- **デメリット**
    - **実行時間が長い:**
        - **E2Eテストの割合が多いため、テスト全体の実行時間が長くなり**、素早いフィードバックが得にくくなります
    - **メンテナンス負荷が高い:**
        - UIやAPIの変更でテストが失敗しやすく、**頻繁な修正が必要で、メンテナンスに多くのリソース**がかかります
    - **バグの原因特定が難しい:**
        - システム全体を通してのテストのため、**問題がどこで発生したのか特定しづらく**、修正に時間がかかります
    - **テスト結果が不安定:**
        - **外部環境やネットワークに依存しやすく**、テスト結果が安定しないため、誤検知（偽陽性）が増え、信頼性が低下します
### 結論
- ピラミッド型は効率と安定性を追求した理想のモデルですが、現場でテスト自動化を推進時に陥るアイスクリーム型では、特にE2Eテストへの依存が課題となりがちです。ピラミッド型に近づけることで、テストのメンテナンス負荷が軽減し、開発のスピードと品質が向上します

## 2. UTテストの基礎と重要性

### 初期段階でのバグ検出率
「修正コストは、開発フェーズが進むにつれて指数関数的に増加」
![初期段階でのバグ検出率 .jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169095/27c7fc3b-9906-c7bc-786d-a2401834ec6d.jpeg)

初期段階でのバグ検出が後工程の修正にかかるコスト削減に直結。
### 役割とメリット
- **UTの役割:**
    - アプリケーションの最小単位で機能が期待通りに動作するかを確認するテスト
- **UTのメリット:**
    - 早期のバグ検出による修正コストの削減
    - 他のモジュールや機能とは独立して実施できるため、原因特定が容易でメンテナンスも効率的
## 3. 効果的なテストのバランス：UTとE2Eの役割分担
- **UTとE2Eのバランス:**
    - UTで基礎的な品質を確保し、E2Eで主要なユーザーフローの動作確認を行う戦略
- **具体的な効果:**
    - E2Eテスト依存の軽減、安定したテスト環境の構築が実現

## 4. テスト推移データの可視化とその効果

 - **推移データの活用方法:**
    - バグ数やテストカバレッジの推移をグラフ化し、品質の向上やリスク傾向を把握
- **可視化のメリット：**
    - バグ発生箇所の特定、新規テストケースの決定、リグレッションテスト強化など
- **実例:**

| プロジェクトA: | プロジェクトB |
|:-:|:-:|
|UTを継続的に実施→開発後期でのバグ修正数が30%減少。| UT未実施→開発後期でのバグ修正に多大な工数とコストが発生。|
- 結果: UTを実施したプロジェクトは、後工程での修正負担が軽減され、納期も短縮

## 5. チーム全体へのメリットとプロジェクトリスクの低減
- **品質管理の向上:**
    - バグ傾向の可視化とテストケースの優先度設定により、リリース後の不具合が減少
- **開発スピードの向上:**
    - リソースの効率的な利用が可能になり、後工程での修正時間が減少
- **コミュニケーションの活性化:**
    - テスト結果の可視化によるフィードバック共有と、QAエンジニアと開発チームの相互理解の深化
- **プロジェクトリスクの低減:**
    - バグの頻発箇所に対する重点的なテストがリスク管理に貢献

## まとめ
- **UTの重要性とテスト推移データの活用:**
    - 単体テストは、**後工程のコストを抑え、品質基盤を支える要素**
    - テスト推移データを活用することで、**リスクを管理し、効率的なプロジェクト運営が可能に**
ディレクトリ内の特定の拡張子を持つファイル数を数え上げるコード

ディレクトリ内に異なる拡張子を持つファイルが混ざっていているとし（↓のような状況）、どの拡張子がいくつあるのか数えるようなコードを作成してみます。
```
my_directory/
├── file1.html
├── file2.txt
├── file2.html
└── sub_folder
├── file3.html
```

今回は、試しにmy_directoryの```.html```のファイル数を数えてみましょう。

# ```import os``` から```os.listdir(directory）```
↓のような関数を定めます。
```python
import os
def count_html_files(directory):
    # ディレクトリ内のすべてのファイルをリスト化
    files = os.listdir(directory)
    # HTMLファイルのみを抽出してカウント
    html_files = [file for file in files if file.endswith('.html')]
    return len(html_files)
```
そして、さっき作成した関数を用いて以下のコードを実行すれば完了です！
```python
count_html_files(任意のディレクトリ名)
```

# ポイント ～```files = os.listdir(directory)```～ #
```files```には何がどのように格納されているでしょうか？
```
files = ['file1.html', 'file2.txt', 'file2.html', 'sub_folder', 'file3.html']
```
各ファイルがリスト形式で格納されているのですね。
Node.js app Apache2下で起動

Node.jsアプリをApacheサーバのVirtualHostにて、ドメインを割り当て、更にアプリを起動し、Proxy設定にて、起動したlocalportを指定し、80のPortとして、アクセスさせる。
下記にその手順を記載します。
１、nodeの環境に、foreverモジュールをInstallしてあること。

２、httpd.confのVirtualHost設定例を下記に示します。
```
<VirtualHost *:80>
    ServerAdmin webmaster@mail.example.com
    DocumentRoot /var/www/html/example
    ServerName message.example.com
    ErrorLog logs/example.com-error_log
    CustomLog logs/example.com-access_log common
   ProxyRequests off

    <Proxy *>
            Order deny,allow
            Allow from all
    </Proxy>

    <Location />
            ProxyPass http://localhost:3000/
            ProxyPassReverse http://localhost:3000/
    </Location>

</VirtualHost>
```
Appの直下に移動、foreverモジュールにて下記の様に実行、
forever start server.js
起動停止。
forever stop server.js
Sphinx: `:doc:`ロールに指定するパスには、拡張子を含めてはいけない

# 環境
* Sphinx 7.4.7


# やりたいこと
reStructuredTextで、プロジェクト内のドキュメントを参照するリンクを生成したいです。


```
.
├── docs
│   ├── foo.rst
│   ├── bar.rst
```

`foo.rst`から`bar.rst`を参照するために、`:doc:`ロールを用いて以下のように記載しました。


```:foo.rst
:doc:`bar.rst`
```

しかし、ドキュメントを生成すると以下の警告メッセージが表示されて、リンクは生成されませんでした。なぜでしょうか？

```
WARNING: unknown document: 'bar.rst'
```

# 原因
`:doc:`ロールで指定したパスに、`.rst`という拡張子があるため"unknown document"というメッセージが表示されたようです。
拡張子を取り除けば、期待通りのリンクが生成されました。

```:foo.rst
:doc:`bar`
```

なお、`toctree`ディレクティブでは、拡張子がある場合でもない場合でもリンクは生成されます。

```:foo.rst
.. toctree::

   bar.rst
   bar

```

`:doc:`ロールでも同じような動きになって欲しいですね。

:::note
TODO https://github.com/sphinx-doc/sphinx にIssueを作成する
:::

# 参考にしたサイト
* https://sphinx-users.jp/reverse-dict/writing/link.html [^1]
* https://www.sphinx-doc.org/ja/master/usage/referencing.html#role-doc

[^1]: サンプルコードには拡張子が付いていて正しくなかったので、[Pull Request](https://github.com/sphinxjp/sphinx-users.jp/pull/122)を作成しました。
UbuntuでMac用キーボードの「英数」「かな」を使えるようにする

自宅デスクのレイアウトを変更しようと思って、使っていなかったMac用のキーボードを引っ張り出しました。
やはりMacに慣れていないと使いずらい・・・（購入してから使ってこなかった理由です。）
デバイスが増えてきたので、とりあえずはMac用キーボードを使えるようにしたいと思います！
今回の作業では、Windowsキーでいう「半角/全角」キーがMac用キーボードには存在しないので、「英数」「かな」キーで、その役割を担ってもらう内容になります。

# 事前確認
- Ubuntu 22.04.4 LTSで行います。
- ログイン画面の右下の歯車マークから「Ubuntu on xorg」を選択してください。
![FF0A2083-9033-4CD6-B82E-1B07FE9B0EA6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/f07187cf-d824-2891-fd78-f76fe95e72ae.jpeg)

# キーボード配列の変更
- ターミナルを開いて``sudo dpkg-reconfigure keyboard-configuration``を入力します。
コマンドを実行したら、下記の画像通りに設定を行っていきます。
![アップルキー設定変更.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/2a0c51b0-4969-d603-6284-88642c2f6a55.png)
![アップルキー設定変更２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/ccad7c26-1b65-5b03-7f64-fbae6aa77d79.png)
![アップルキー設定変更３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/1c0ad438-3df8-7740-30b2-80ed0ed2308e.png)
![アップルキー設定変更４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/6282d32d-dbc6-ac5c-65cd-c88c784b4550.png)
![アップルキー設定変更５.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/4df96bba-1bc9-0302-06ff-4a32bb76b5dd.png)
![アップルキー設定変更６.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/b5ba0c55-f317-7255-a716-99939700dd3b.png)
- 下記画像のようになれば、keyboard-configurationの設定が完了したということになります。
![アップルキー設定変更７.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/8af2a249-286b-9519-92a7-56a8f89265a6.png)
- 新しいウィンドウからターミナルを別に開きます。
``xev``と入力し実行します。
「英数」キーを押下します。
「Hiragana_Katakana」の出力を確認します。
![key12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/918468d0-83ba-4c2c-b01d-696743801abd.png)
- 続いて「かな」キーを押下します。
「Eisu_toggle」の出力を確認します。
![key13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/74c824d2-4c50-c930-43f2-dedf3862ce9d.png)

# Mozcの設定
Mozcのプロパティから設定を行います。
- キー設定の選択から編集を選択します。
![key8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/d83e237e-153d-a44b-316a-a7b4f095ef9a.png)
- 「Eisu」を「IMEの有効化」にします。
![key10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/eefcfe48-a8af-5ec2-ab1c-9016cecfc61a.png)
- 「Hiragana」を「IMEの無効化」にします。
![key11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803710/5630c9b2-2591-13b2-18ec-e808b2a0b8c6.png)

設定は以上となります。
設定が適応されていない場合は、再起動を行うのも一つの手かもしれません。
実際、再起動して設定が反映されました。

# 最後に
Mac用のキーボード慣れなさすぎて、購入して2年くらい放置してました。
この機会に慣れてみようと思いますw
複数行もOK！2行以上のインライン要素のunderlineをアニメーションさせる方法

CSSで複数行のテキストに対してunderlineアニメーションを実装する方法を解説します。従来、複数行のインライン要素に対するアニメーション付きunderlineの実装は困難とされてきましたが、CSS `background`プロパティを活用することで実現可能です。

## 実装のポイント

1. `display: inline`の使用
2. `background`プロパティによる下線の表現
3. `linear-gradient`を使用したアニメーション効果
4. 適切な`transition`の設定

## 基本的な実装

```css
/* ベーススタイル */
.hvr-underline {
  display: inline;
  background: linear-gradient(to top, currentColor 2px, transparent 99%) no-repeat;
  transition: all 0.5s ease-out;
}
```

## アニメーションパターン

### 1. 左からのunderline

```css
/* 初期状態 */
.hvr-underlineInLeft {
  background-position: 0% 100%;
  background-size: 0% 1px;
}

/* hover時 */
@media (any-hover: hover) {
  .hvr-underlineInLeft:is(:hover, :focus) {
    background-size: 200% 1px;
  }
}
```

### 2. フェードインするunderline

```css
/* 初期状態 */
.hvr-underlineFadeIn {
  background-position: 50% 30px;
  background-size: 200% 20px;
}

/* hover時 */
@media (any-hover: hover) {
  .hvr-underlineFadeIn:is(:hover, :focus) {
    background-position: 50% 20px;
    background-size: 200% 1px;
  }
}
```

### 3. 中央からのunderline

```css
/* 初期状態 */
.hvr-underlineOpenIn {
  background-position: 50% 100%;
  background-size: 0% 1px;
}

/* hover時 */
@media (any-hover: hover) {
  .hvr-underlineOpenIn:is(:hover, :focus) {
    background-size: 200% 1px;
  }
}
```

## HTML実装例

```html
<a href="#" class="link">
  <span class="hvr-underlineInLeft">
    これは2行以上の<br>
    テキストです
  </span>
</a>
```

## 実装時の注意点

### 1. Flexbox環境での注意

親要素が`display: flex`や`display: inline-flex`の場合、underlineアニメーションが正しく表示されない場合があります。この場合は以下のような対応が必要です：

- 親要素のflexを解除する
- 別の要素構造を検討する

### 2. 単位の統一

アニメーション時の不自然な動きを防ぐため、`background-position`と`background-size`では単位を統一することが推奨されます：

```css
/* 良い例：pxで統一 */
background-position: 50% 30px;
background-size: 200% 20px;

/* 避けるべき例：%とpxの混在 */
background-position: 0 200%;
background-size: 200% 1px;
```

### 3. グラデーションの設定

滑らかなアニメーション効果を得るために、`linear-gradient`の値は以下のように設定します：

```css
/* 推奨される設定 */
background: linear-gradient(to top, currentColor 2px, transparent 99%) no-repeat;

/* 避けるべき設定（急激な変化） */
background: linear-gradient(to top, currentColor 1px, transparent 1px) no-repeat;
```

## ブラウザ対応

この実装は以下のモダンブラウザで動作確認されています：
- Chrome（最新版）
- Firefox（最新版）
- Safari（最新版）
- Edge（最新版）

## アクセシビリティへの配慮

アニメーション効果を実装する際は、以下の点に注意が必要です：

1. `prefers-reduced-motion`への対応
2. キーボード操作時の`:focus`状態の視認性確保
3. 十分なコントラスト比の確保

```css
@media (prefers-reduced-motion: reduce) {
  .hvr-underline {
    transition: none;
  }
}
```

## まとめ

CSS `background`プロパティと`linear-gradient`を組み合わせることで、複数行のテキストに対しても美しいunderlineアニメーションを実現できます。実装時は以下の点に注意しましょう：

- 適切なHTML構造の設計
- 単位の統一
- Flexbox環境での挙動確認
- アクセシビリティへの配慮

この実装方法は、従来の`text-decoration`や`border-bottom`では実現できなかった柔軟なアニメーション効果を可能にします。
24日目にLINEミニアプリが完成する初心者 ── Day1.イントロダクション

# はじめに

今年もこの季節がやってきました:christmas_tree::christmas_tree::christmas_tree:

https://qiita.com/advent-calendar/2024

いつもは指を咥えて見ていたこのお祭りですが、今年は完走賞を目指して25記事のシリーズ投稿を予定しています！（なんたってQiitanのぬいぐるみが欲しいから！！！）

<br />

今回書くのは題して、

**「24日目にLINEミニアプリが完成する初心者」** シリーズです！:crocodile:

<br />

このシリーズでは、LINEミニアプリ初心者の筆者がをゼロからLINEミニアプリについて学び開発を行い、最終的に審査に出すまでの流れを25日間にわたって解説します。

つまりこの記事を読んで毎日一緒にハンズオンをすることで、LINEミニアプリが作れるようになる！（はずです）

<br/>

ちなみに「25日なのになんで完成するのが24日目？」と思った方もいるかもしれませんが、予定としては24日間でアプリ開発、25日目には開発全体を通してのまとめや今後の展望について書ければと考えています。




# ところであなたは誰？

ここで簡単に自己紹介をさせていただきます！

名はのぶりんと申します。
株式会社グッドローカルでチーフエンジニアとして働いています。

https://goodlocal.jp/

<br />
仕事では最近はNext.jsでWebアプリケーション開発を行っています。

詳しい経歴について気になる方は以下をご覧ください。

https://note.com/goodlocal_inc/n/nd2fc5190c08d

<br />
今回扱うLINEミニアプリについては全くの未経験のため、勉強をしながら記事を書いていくことになると思います。

LINEは多くの人が利用するアプリのため、LINEミニアプリの開発需要は高く、社内でも注目されていたこともあり題材として選ぶことにしました。

以下から今回書く記事の概要について紹介していきたいと思います。




# アドベントカレンダーのゴールは？
今回のアドベントカレンダーのゴールは、 **「LINEミニアプリを審査に提出する」** ことです！

（そしてQiitanぬいぐるみを手にいれること）
<br />

今回はこの過程でLINEミニアプリの基本的な開発フローを25日間で習得していきたいと考えています。
具体的には以下のスキルが身に付くことを期待しています。

- LINEミニアプリの作成と設定
- LINE Messaging APIの基本的な利用方法
- Webhookの設定とイベント処理
- Googleスプレッドシートとの連携
- ユーザー情報と予約情報の管理
- リッチメニューの設定




# どんな人向けの記事？

LINEアプリの開発に初めて挑戦する方や、ビジネスニーズに応じた予約管理やメッセージ配信を実装してみたい方などに向けた記事にを予定しています！

ただし、初心者の中でもJavaScript/Node.jsの基本知識があるとスムーズに進められると思います。




# どんなアプリを作るの？

今回は弊社の中古リノベーション事業を行っているマハロリビングで使うことを想定したLINEミニアプリを作っていきたいと思います。

https://mahalo-living.com/

<br />

作成する主な機能は次の通りです。

#### 資料請求機能
ユーザーがリノベーションに関する資料をLINEから請求できるようにします。資料請求時に入力された情報は、自社のスプレッドシートに保存され、効率的な対応が可能になります。

#### 顧客情報管理機能
ユーザーの基本情報や過去のやりとり、資料請求や予約情報などを一元管理します。スプレッドシートとの連携により、LINEのやり取りを活かした顧客データベースを構築します。

#### 特定ユーザー宛のメッセージ配信
特定のユーザーやセグメントに向けて、LINEを通じたメッセージ配信が可能です。新しい物件情報やキャンペーンの案内を、LINEメッセージでタイムリーに届けます。

#### 来店予約機能（Googleカレンダー連携）
ユーザーが来店予約をLINE上から行えるようにします。予約情報はGoogleカレンダーに自動で登録され、空き状況に応じてスケジュールが管理されます。

#### 問い合わせ受け付けと応答機能
ユーザーからの質問や問い合わせをLINE上で受け付け、アプリ内で返答を行います。問い合わせ内容に応じて、自動返信や個別対応のメッセージを送り、迅速な対応を提供します。

<br />

お店などではよく使う機能も多いかと思います。
皆さんの参考になる機能があれば嬉しいです！




# 全体の流れは？

アドベントカレンダーの流れとして、今回のもくじを紹介していきたいと思います！

25日分ですので当初の予定と変更になる場合があります。
あらかじめご了承ください:bow_tone2:
<br />

**Day1. イントロダクション
Day2. 基本設定
Day3. LIFFスターターアプリの導入
Day4. LIFFスターターアプリのデプロイ
Day5. スターターアプリのLINEミニアプリ化
Day6. 資料請求フォームの開発準備
Day7. フォームUIの作成
Day8. 資料請求完了ページの作成
Day9. スプレッドシートとの連携
Day10. フォームデザインの最適化
Day11. 顧客データモデルの設計
Day12. 顧客情報のスプレッドシート保存
Day13. 顧客情報の表示機能
Day14. 顧客情報の検索と更新機能
Day15. 特定ユーザーへのメッセージ送信
Day16. 複数ユーザーへのメッセージ配信
Day17. メッセージテンプレートの導入
Day18. 予約フォームの作成
Day19. GoogleカレンダーAPIの準備
Day20. 予約データのGoogleカレンダー登録
Day21. 予約確認メッセージの送信
Day22. 問い合わせフォームの作成
Day23. 問い合わせデータの管理
Day24. LINEミニアプリの審査準備と提出
Day25. まとめと今後の展望**




# 最後に

25日もあるので正直走り抜けられるか、今はただただ不安ですが、いいクリスマスが迎えられるよう一生懸命書いていこうと思います:mountain_bicyclist:

早速明日は基本設定ということで、LINE Developersのアカウント作成とプロジェクトの初期設定を行なっていきます。

<br/>

応援してくださる方などいらっしゃいましたら、是非カレンダーを購読やフォローをお願いします！

https://qiita.com/advent-calendar/2024/line-mini-app
classがSendableに適合するためにはfinalなclassである必要がある件

# はじめに
swift concurrencyの対応を行なっているとclassを`Sendable`に適合させる必要がある場面があり以下のように実装してみたのですが、警告が表示されコンパイラに怒られました。

```swift
class Counter: Sendable {
    
    let value: Int = 0
}
```

警告の内容としては以下のとおりです。
```
Non-final class 'Counter' cannot conform to 'Sendable'; use '@unchecked Sendable'; this is an error in the Swift 6 language mode
```

今回は上記の警告での対応方法と、なぜこの警告が出たのかを調べたのでその内容を記事にしました。

# 警告の内容と対応方法
これはコンパイラの警告を日本語訳するとfinal出ないclassは`Sendable`には適合できまへんということなので、素直にclassにfinalをつけるとコンパイラを黙らせることができます。
(コンパイラは結構ちゃんと教えてくれていました)

修正後のコードは以下のとおりです。
```swift
final class Counter: Sendable {
    
    let value: Int = 0
}
```

これだけでは流石に味気ない記事で終わってしまうので、冒頭でも述べたとおりなぜfinalなclass出ないと`Sendable`に適合できないのか以降で考えてみます。

# なぜclassはfinalでないと`Sendable`に適合できないのか
これは`Sendable`の意味とfinalなclassの意味を理解すれば、理由が見えてきます。

### `Sendable`とは
データ競合しない型であることを保証するプロトコルです。
データ競合しないということは、型がイミュータブル(不変)であるということです。(複数のスレッドで同時に書き込みを含むアクセスがあったときにデータ競合が起きるため、書き込みが起きない型であれば書き込みができないのでデータ競合も起きない)

### finalなclassとは
継承されないclassのことです。

finalがついていないclassは別クラスで継承できますが、finalがついたclassを継承しようとするとコンパイルエラーになります。
つまり継承されないことを保証したclassとなります。

```swift
final class Counter: Sendable {
    
    let value: Int = 0
}

class inheritableCounter {
    let value: Int = 0
}

class SampleCounter1: inheritableCounter {} // OK

class SampleCounter2: Counter {} // コンパイルエラー
```

継承すると、以下`SampleCounter1`のようにプロパティの拡張が行えたり、継承元の型として振る舞うことができます。

```swift
class InheritableCounter {
    let value: Int = 0
}

class SampleCounter1: InheritableCounter {
    var extensionValue: Int = 0
}

let counter: InheritableCounter = SampleCounter1()
```

ここまでくると、なぜfinalなclassでないと`Sendable`に適合できないか見えてきました。

finalでないclassは継承によって ミュータブル(可変)な型になることが可能です。
そして、継承された型は継承元と同じ型として振る舞うことができる性質上、継承元がイミュータブルでも継承された型がミュータブルとなり継承元の型として振る舞うと継承元の型がイミュータブルであることつまり`Sendable`であることが保証されなくなってしまいます。
よってclassを`Sendable`に適合するにはfinalで継承されないことを保証してあげる必要があるわけでした。
(ちなみに、structは継承することができないので、finalをつけないと`Sendable`になれないといった制約はありません)

```swift
class InheritableCounter { // 定数しかないので、イミュータブルなクラス
    let value: Int = 0
}

class SampleCounter1: InheritableCounter { // 変数を持ったミュータブルなクラス
    var extensionValue: Int = 0
}

let counter: InheritableCounter = SampleCounter1() // ミュータブルなSampleCounter1がInheritableCounterとして振る舞っている
```

# おわり
元々はちょっとした警告の対応でしたが、なぜこれがダメなのかちゃんと考えると理由もちゃんとあって謎解きみたいで楽しかったです。
Power AutomateのExcel［表に行を追加］アクションで空行追加を回避する

# 空行追加の原因
Power Automateの［Excel Online(Business)］コネクタの［表に行を追加］アクションで以下テーブルにデータを追加します。

<img width="700" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/44c733ea-2ac8-6875-4037-c164cc5047fa.png">


クラウドフロー実行後、Excelテーブルの中身を確認すると、2行目以降にデータが追加されており、1行目が空白となっています。こちらの動作の原因は、Excelの製品仕様上、1行目にデータが存在すると判断されているからです。

<img width="700" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/41088767-d289-5885-d2f9-368167a4d278.png">

# 空行追加の回避方法

空行追加の回避する方法として、テーブルの1行目の行番号を右クリックで選択し、［行の削除］を実行します。

<img width="700" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/05a6cdff-5ad7-0ff3-af5d-3b0446a35586.png">

クラウドフロー実行後、Excelテーブルの中身を確認すると、空行は追加されることなく1行目からデータが追加されています。

<img width="700" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/4305d988-b85c-e5d2-868a-3b56b20d48c4.png">
新任リーダになったときに参考にしたudemy講座

# 概要
突然新任リーダになった私が、「そもそもリーダってなんだよ、なにするんだよ」と思って参考にしたudemyの講座とそこで勉強したことを紹介します。

# 結論、学んで役に立ったの？
### 役に立った！
- 上司の行動の理由が少しわかるようになった
    - なんでそれを気にするんだろう、を察せるようになった
    - 求められていることが分かりやすくなった
        - **これ↑は一番大事！と上司からも褒められたので、勉強する価値は間違いなくあった**
- 心理的安全性が一切ないチームにいたときの苦しかった理由が分かった
- どうしたら心理的安全性を確保できるのか？を学んだことで、自分が同じことを繰り返さない方法が分かった
    - ここは自分の得意領域っぽいこともわかった
    - なんとなくPMを志向していたが、正解のようだとわかった
- 上司に感想を伝えたところ「実践はねえ、出来ないんだよ」と言われたが、モデルとして覚えておきたい
    - が、今のチームは比較的やりやすいので、そういいつつも出来ているのでは？と思った

### 役に立たなかった…
- アジャイルの話をされても困る
    - あ、これアジャイル前提の話だな、というときも自分の現場に落とし込んでイメージは出来るが

# PMBOK
https://www.udemy.com/course/pmbok7-overview/?srsltid=AfmBOoqe2eZMz7COLWcM7iiolzxC8GWW7mDuPYJXjLEg10HRPa_O7Vst

### 視聴理由
上司「PM試験受けてよ」
私「え」

### 視聴してみて
- PMBOKの概要をざっくり学べた
    - PM試験はPMBOKに基づいて作られているので、本格的にPM試験の勉強を着手したときに理解がしやすかった
    - 特にアジャイルの経験はなく知識としても応用情報以上のことは知らなかったので、アジャイル宣言周りの話を学べたのは良かった（そしてPM試験はアジャイル重視に変わりつつあることを知り絶望した）


# マネジメント
https://www.udemy.com/course/team-management-basic/?srsltid=AfmBOooeA2BqJFUn38gilShbghemVpWIkEnJbfIPg6erCTi85xA873Ci

### 視聴理由
本音：`マネジメント`で調べて最初に出てきたから
建前：PM試験を受けるならもう一本くらい下地になる勉強をしたかった

### 視聴してみて
- チームビルディング
    - 私がリーダになった当時は別チームの人間関係が相当ぎくしゃくしていた時期だったり、以前私もチーム内の人間関係に苦労した経験があった
        - 視聴しながら、「もし自分がリーダだったらこうしてたな（こうしたかったな）」を考えながら学習出来た
- PM試験向けという観点で良かった
    - ここで学んだ「心理的安全性」とか「チームの成長モデル」とか、午後試験でかなりの重要ワードだった

# 結論
- UdemyでPMとしての勉強をしたことに意味はあった
- 理論と実践は別物と言うが、理論が分からないと実践も出来ないので若いうちに勉強してよかった
- 初めて動画教材使った
    - 通勤中にほかの本読みながら聞き流す、みたいな学習方法が出来てよかった
    - 平日聞き流して概要掴んで休日はしっかりノート取りながら聞く勉強方法が効果的だった
Discord.pyで好きなステータスメッセージを設定する

DiscordBotには基本的に好きなステータスメッセージを設定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/823378/42fbdc69-1ea9-0e05-0f51-5d346443aaf5.png)

画像のように、Bot名の下に表示されるのがステータスメッセージです。
これをチャットからコマンドで変更できるようにしてみます。

# 実装

まずはBot起動時にメッセージを設定してみましょう。

```python
import discord
from discord.ext import commands

# 諸々セットアップ
intents = discord.Intents.default()
intents.message_content = True 
bot = commands.Bot(command_prefix='/', intents=intents)

# 起動時にメッセージを設定
@bot.event
async def on_ready():
    await channel.send("起動しました") # 起動通知
    await bot.change_presence(activity=discord.Game(name="ステータスメッセージだよ"))
    
```
`change_presence`で自由にステータスメッセージを設定できます。
設定可能なアクティビティは以下の通り。詳しくは参考ページをご覧ください。

* Activity
* Game (〜をプレイ中)
* Streaming　(〜を再生中)
* CustomActivity

Activityを最適化したものがGame/Streamingです。最適なものを選択しましょう。
(ドキュメントを読んだ限りは割と拡張性がありそうなので活用したい)

```python
# 例:testをプレイ中
await bot.change_presence(activity=discord.Activity(name="test", type=discord.ActivityType.playing))
```

# コマンドで変更する
メッセージを変更するたびに再起動するのは面倒なので、管理者用コマンドで即時変更できるようにしていきます。

```python
@bot.command(name="sm", description="ステータスメッセージを変更します")
async def sm(ctx, sm: str):
    if ctx.user.guild_permissions.administrator:
        await bot.change_presence(activity=discord.Activity(name=sm, type=discord.ActivityType.playing))
        await ctx.response.send_message(f"ステータスメッセージを「{sm}」に変更しました")
    else:
        await ctx.response.send_message("このコマンドは管理者専用です。")
```
`ctx.user.guild_permissions.administrator`でコマンド実行者が管理者権限を持っているか判定し、trueであれば実際に変更。その通知を返します。

お読みいただきありがとうございました。
# 参考
https://discordpy.readthedocs.io/ja/latest/api.html#discord.BaseActivity
秋のアーキテクチャLT祭りに参加して①

# 背景
もともと私がよくお世話になっている、モローさんが所属するキッカケさんで
よくお話しさせていただいているキャメロンさんという方から、
８月に「アーキテクチャ系のイベントをやってください」とお願いされたのがキッカケでした。

もともと設計やアーキテクチャ系のイベントにはよく参加していたものの、
オフラインのイベントで自分が主催側に回るという機会は今回初でした。

いろんなアーキテクチャ系のイベントに参加していて思うことは、
開発系の畑でのアーキテクチャ、セキュリティ系の畑でのアーキテクチャ、
などがかなり分断されて考察されているというように感じていたため、
今回のイベントでは、
・開発畑のアーキテクト
・セキュリティコンサルさん
・マイクロサービスなどの大規模システムのQAをされている方

というかなり広義のエンジニアの方々を招待させていただきました。

https://it-bosatsu-moro.connpass.com/event/330009/

イベント自体は休憩や質疑応答も込みで5時間ほどのイベントでしたが、
内容が非常に濃密であったことと、異色のコラボであったと感じています。

今回はその濃密すぎる内容を１つの記事でまとめきれないと感じたため、
複数回に分けて、議事録及びアウトプットとして記事に残しておきます。

今回は米久保さんの登壇内容のアウトプットです。

# 米久保さんによるアーキテクト的戦略思考
米久保さんとは設計系のイベントでお会いしたことや、
吉祥寺.pmのMagnoliaさんの開催された、設計ナイトでよくお話ししたご縁と、
以下の書籍をプレゼントいただけたことからお声がけさせていただきました。

ちなみにこのアーキテクトの教科書は、難易度自体は比較的初歩～基礎レベル
になっており、初級者～中級者のアーキテクト向けな内容から
サービスレベルのマクロな量子になっても普遍的に使える設計原則など、
本質を抑えられるような構成になっていると感じ、新品で譲っていただいたのに、
ボロボロになるまで読み込ませていただきました。

![41BvLKnLt0L._SY445_SX342_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781175/0aa6662c-18f4-e423-6645-1a17fad10fa0.jpeg)


https://www.docswell.com/s/tyonekubo/ZXEW33-2024-10-26-124043?utm_source=twitter&utm_medium=social&utm_campaign=singlepage 

## 逆コンウェイ戦略
わたしは、完全に逆コンウェイの考え方を誤解していることにこの日気づけました。

ちなみによく誤解しがちな逆コンウェイの考え方が以下。
わたしもこれで考えてしまっていました。

:::note alert
逆コンウェイとは先にあるべきアーキテクチャを考えて、それに合わせて組織構造、コミュニケーションパスの設計を行うというものではない。
:::

:::note info
アーキテクチャと組織は常に相互に力学を及ぼし合うもので運命共同体。
ともに同時並行で仮説検証しながら、組織とアーキテクチャを同時に進化させていく。
:::

ちなみにこれは進化的アーキテクチャの考え方に通じる。

## 個人的に質問した内容

### DBが物理的に分かれたモジュラーモノリス
お恥ずかしながらモジュラーモノリスは、以下のようにDB部分で物理的に１つで結合しているものだと思っていた。

![20240408103259 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781175/322a83c2-db4c-21f9-531f-b1cbe7feb171.png)

しかしながら、アーキテクチャ関連の翻訳をしている島田さんも、
米久保さんもDBが物理的に分離されていて、アプリ部分で1つに結合しているものを
モジュラーモノリスと呼んでいる。

その理由は以下のようにお二方共におっしゃっていた。

:::note warn
データ部分が一番蜜結合になりがち問題
:::
データが物理的に結合していることによるリスクが大きい以上、
明らかに「そこにデータのコンテキスト境界はれるよね」って所は最初から物理的に別のDBとして分けておく。

そしてアプリ側でトランザクションの境界を跨いだりしないように疎な結合にしておくことで、すぐにマイクロサービス化できるような状態にしておく。

アプリ側ならば違反のチェックの担保もしやすく、データが物理的に結合している状態よりも、リスクを抑えられるからとのこと。

:::note warn
ただし、トランザクション境界を考える際に、
複数のモジュールにまたがらないようにモジュールを分割しなくてはいけない。
:::

### コンポーネントの粒度ごとのポリシー
参加者の方から、設計の際のポリシーに関するご質問が上がったので、
各マクロサイズ～ミクロサイズのコンポーネント(ミクロサイズのコンポーネントをJavaだったらパッケージのことを指すとする)に対してのポリシーと、監視すべきメトリクスの関係に関して質問させていただいた。

その結果、より解像度が上がった内容として、以下の結果が得られた。

:::note info
そのコンポーネントの設計ポリシーが定義されることで、自ずと見るべきメトリクスも決まる。
:::

逆にどんなメトリクスを監視したらいいのかわからないといった場合には、
まだそのコンポーネントの設計ポリシーが決まっていない可能性が高い。

下位のコンポーネントは、上位のコンポーネントのポリシーを継承する形でないといけない。
これはリスコフの置換原則を考えたら当然のことである。

逆に下位で「そのメトリクスは集められない」っていう制約があれば、
それを上位に反映するなど、具体と抽象レイヤーの行き来によるポリシー決めと
それによるメトリクス定義と改善活動が求められる。
Flutterでインナーシャドウ

Flutterでインナーシャドウを描画するコード、検索すると出てくるものが軒並みうまく描画できなかったので自作しました。数年前に調べたときはうまくレンダリングできていた気がするのですが…。

- 本記事執筆時点のFlutterのバージョン: 3.24.4

## 結論のコード
CustomPainterを使う方式で実装しました。ざっくり言うと単純にインナーシャドウを描画したい部分に穴を開けたパスを作って、そのパスを描画する際にMaskFilterでシャドウを付けています。

```dart
import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class InnerShadowPainter extends CustomPainter {
  const InnerShadowPainter({
    required this.shadows,
    this.borderRadius,
  });

  final List<Shadow> shadows;
  final BorderRadius? borderRadius;

  RRect applyBorderRadius(Rect rect, BorderRadius borderRadius) {
    return RRect.fromRectAndCorners(
      rect,
      topLeft: borderRadius.topLeft,
      topRight: borderRadius.topRight,
      bottomLeft: borderRadius.bottomLeft,
      bottomRight: borderRadius.bottomRight,
    );
  }

  Path createShadowPath(Rect rect, Shadow shadow) {
    final outerRect = rect.inflate(max(shadow.offset.dx.abs(), shadow.offset.dy.abs()) + shadow.blurRadius + 1);
    final path = Path()
      ..fillType = PathFillType.evenOdd
      ..addRect(outerRect);
    final innerRect = rect.translate(shadow.offset.dx, shadow.offset.dy);
    if (borderRadius != null) {
      return path..addRRect(applyBorderRadius(innerRect, borderRadius!));
    } else {
      return path..addRect(innerRect);
    }
  }

  @override
  void paint(Canvas canvas, Size size) {
    final rect = Offset.zero & size;

    canvas.save();

    if (borderRadius != null) {
      canvas.clipRRect(applyBorderRadius(rect, borderRadius!));
    } else {
      canvas.clipRect(rect);
    }

    for (final shadow in shadows) {
      final shadowPath = createShadowPath(rect, shadow);
      final shadowPaint = Paint()
        ..color = shadow.color
        ..maskFilter = MaskFilter.blur(BlurStyle.normal, shadow.blurSigma);
      canvas
        ..translate(shadow.offset.dx, shadow.offset.dy)
        ..drawPath(shadowPath, shadowPaint)
        ..translate(-shadow.offset.dx, -shadow.offset.dy);
    }

    canvas.restore();
  }

  @override
  bool shouldRepaint(InnerShadowPainter oldDelegate) {
    return !listEquals(shadows, oldDelegate.shadows) || borderRadius != oldDelegate.borderRadius;
  }
}

class InnerShadow extends StatelessWidget {
  const InnerShadow({
    super.key,
    required this.shadows,
    this.borderRadius,
    required this.child,
  });

  final List<Shadow> shadows;
  final BorderRadius? borderRadius;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      foregroundPainter: InnerShadowPainter(
        shadows: shadows,
        borderRadius: borderRadius,
      ),
      child: child,
    );
  }
}
```

## 使い方

```dart
InnerShadow(
  shadows: [
    Shadow(
      color: Color.fromRGBO(0,0,0,0.5),
      blurRadius: 2.0,
      offset: Offset(1, 1),
    ),
  ],
  child: Container(
    width: 200,
    height: 200,
    alignment: Alignment.center,
    color: Colors.white,
  ),
)
```

## 結果

![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43781/9cae2849-ed44-28e1-bdfa-fca9252dd60b.png)

## おわりに
最初はsaveLayerとBlendModeをこねくり回していたのですが、よく考えたら素直な方法で描画できました。
Goでのテストソースの書き方

### 概要

Go言語で、JavaのJUnitなどのようにプログラムを書いてテストを行う方法

### Goのテストソースのルール

①testingパッケージを利用する

```
package test
```

②テスト対象のファイルとテストファイルを同じディレクトリに配置する
③テストファイルのファイル名は
「テスト対象のファイル名_test.go」とする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3926100/805b8ec8-0a61-6bd7-81e0-b314bcbce2bb.png)

④テストの実行には「go test」コマンドやテストオプションを使う
以下の例ではテストの詳細を表示する-vオプションを使っている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3926100/df5a8a69-f922-e56d-1a20-a2d565720bbb.png)
受信したデータが windows-31j でエンコードされている場合に、これをそのまま UTF-8 で処理しようとすると、文字化けが発生する可能性ある？

受信したデータが windows-31j でエンコードされている場合に、これをそのまま UTF-8 で処理しようとすると、文字化けが発生する可能性があります。特にエンコーディングの変換が適切に行われなければ、データが期待する形式で表示されなくなることがあります。以下、各パターンごとに詳細を説明します。

## 1. 半角英数字 (windows-31j → UTF-8)
半角英数字（ASCII範囲内）は、windows-31j と UTF-8 の両方で同じバイナリ表現になるため、基本的に文字化けしません。
例えば、英数字の "abc123" はどちらのエンコーディングでも同じバイト列を保持します。
## 2. 一般的な全角文字 (windows-31j → UTF-8)
windows-31j の一般的な全角文字（例えば日本語の「あいうえお」）は、UTF-8 とは異なるバイト表現を持つため、UTF-8 として解釈されると文字化けします。
例：windows-31j でエンコードされた「こんにちは」を UTF-8 でデコードしようとすると、意味不明な文字列になる可能性が高いです。
## 3. 特殊文字 (windows-31j → UTF-8)
特殊文字（記号や一部の日本語以外の文字）については、windows-31j 特有のバイト表現を持つ場合があり、それを UTF-8 で扱うと文字化けが生じます。
例えば、windows-31j では特殊なダッシュやカッコの種類が UTF-8 とは異なるため、正しく表示されない可能性があります。
## 4. 外字 (windows-31j → UTF-8)
外字（企業独自に定義された文字など）は特に注意が必要です。windows-31j には外字領域があり、これらは通常の標準文字セットには含まれません。
外字は、UTF-8 に変換される際に正確にマッピングされない可能性が高く、ほぼ確実に文字化けします。外字に対応した変換が行われない限り、意図しない文字や表示できない文字（□などの表示）になることが多いです。
## 結論
半角英数字は問題ありませんが、全角文字、特殊文字、外字に関しては、windows-31j から UTF-8 への変換で文字化けする可能性が高いです。
適切な処理を行うには、windows-31j で受信した文字列を一旦そのエンコーディングでデコードし、UTF-8 で再エンコードする必要があります。具体的には以下のような処理を行うことができます
```java
byte[] bytes = receivedData.getBytes("windows-31j");
String convertedData = new String(bytes, "UTF-8");
```
これにより、文字化けを防ぐことができます。
【HTML】正確な日時を機械に対して伝える方法

`<time>`要素を使用することで機械に対して正確な日時を示すことができm

## `<time>`要素とは

`<time>`要素は日付や時刻、経過時間などを表します。
画面に表示される日時情報は人間が読みやすいようにしつつ、`datetime`という属性を使用して正確な日時を機械に対して伝えられます。


## 使用方法
`<time>`要素は、以下のように使用します。

```html
<time datetime="2023-10-01T14:30:00">2023年10月1日 14:30</time>
```

### `datetime`属性
`datetime`属性は、機械が理解できる形式で情報を提供します。
以下のような書式でなければなりません。

**有効な年の文字列**
- `2011`

**有効な月の文字列**
- `2011-11`

**有効な日付の文字列**
- `2011-11-18`

**年のない有効な日付の文字列**
- `11-18`

**有効な週の文字列**
- `2011-W47`

**有効な時刻の文字列**
- `14:54`
- `14:54:39`
- `14:54:39.929`

**有効なローカル日時の文字列**
- `2011-11-18T14:54:39.929`
- `2011-11-18 14:54:39.929`

**有効なグローバル日時の文字列**
- `2011-11-18T14:54:39.929Z`
- `2011-11-18T14:54:39.929-0400`
- `2011-11-18T14:54:39.929-04:00`
- `2011-11-18 14:54:39.929Z`
- `2011-11-18 14:54:39.929-0400`
- `2011-11-18 14:54:39.929-04:00`

**有効な期間の文字列**
- `PT4H18M3S`

## 具体例

### 記事の公開日

```html
<article>
  <h2>新しい技術のトレンド</h2>
  <p>この記事は、<time datetime="2023-10-01">2023年10月1日</time>に公開されました。</p>
</article>
```

### イベントの日付

```html
<section>
  <h2>カンファレンスのお知らせ</h2>
  <p>次回のカンファレンスは、<time datetime="2023-11-15T09:00">2023年11月15日 09:00</time>に開催されます。</p>
</section>
```

### 過去の出来事

```html
<aside>
  <h2>歴史的な出来事</h2>
  <p>月面着陸は、<time datetime="1969-07-20">1969年7月20日</time>に行われました。</p>
</aside>
```

## 参考

https://developer.mozilla.org/ja/docs/Web/HTML/Element/time
言語パックインストール後にprint spoolerサービスが起動しない場合があるらしい

# 経緯
Azure VMを作成後サードパーティーツールをインストールして使用しようとしたところ謎のエラーが発生。
原因はprint spoolerサービスが起動していないことであろうことは突き止めたものの、なぜ起動できないのかはさっぱりわからず放置。
先日ようやく原因がわかったので備忘も兼ねて投稿しておく。

# 結論
**言語パックインストール後はwindows Updateを実施しよう**

https://jpwinsup.github.io/blog/2022/06/22/UserInterfaceAndApps/LanguageSupport_IME/lp-consideration/
>言語パックのインストール後に、以下のような問題が発生したとのお問い合わせをいただくことがございます。
>・印刷やプリンターの追加に失敗する。
>・タスクバー上の検索ボックスが動作しなくなる
>・Azure VM にて、言語パックのインストール後、リモート デスクトップ接続に失敗する。
>・OS の設定画面などが、一部文字化けや、正常な表示とならない。
>・OS の動作に必須のサービスが起動しない、または異常終了する場合がある。
>・グループ ポリシー エディターを開くと複数のエラー メッセージが表示される
>(中略)
>上述のような問題が発生した際、言語パックをインストールいただいたタイミングでありましたら、まずは更新プログラムを適用いただくことで、問題が解消する可能性がございますため、ご検討いただけますと幸いです。