OmniAICreator/Qiita-1.07M huggingface dataset:
ChatGPTで覚えておくと便利なMarkdown記法5選

## 1. はじめに
ChatGPTでプロンプトの書き方に迷ったり、指示がうまく伝わらなかったことはありませんか？
人間に指示を出すのと同様に、ChatGPTに対しても「何をしてほしいのか」を明確に示してあげる必要があります。文章の構造や文章同士の関連性がわかりやすいプロンプトの作成にはMarkdown記法が便利です。
その際に覚えておくと良いMarkdown記法を以下に挙げます。

## 2. プロンプトに便利なMarkdown記法
### ① 見出し「#」
「#」はh1見出し、「##」はh2見出し、のように「#」の数で見出しの階層を変えられます。
```
# 大見出し
## 中見出し
```

### ② リスト「-」「*」
「-」もしくは「*」をつけると箇条書きの意味になります。条件を連ねる時などに便利です。
```
- その1
- その2
```

### ③ 番号付きリスト「1.」「2.」......
リストに近いですが、こちらは頭に数字が付きます。
```
1. 起立
2. 礼
3. おはようございます
```

### ④ コードブロック「```」
「```（バッククォート）」で文章を囲むとひとつのブロックとして認識されます。指示内容にコードを含めたい時などに便利です。
````markdown
```
console.log("Hello world");
```
````
### ⑤ テーブル「|」
テーブルを作る時に使います。表形式でデータを出力させたい時に便利です。
```
|特徴|りんご|梨|
|色|||
|形|||
```

## 3. プロンプトの入力例
Markdown記法を使用したプロンプトの例を以下に示します。
````Markdown
以下の条件を厳守して、記事を作成してください。

# 仕様
- Markdown記法を使用すること
- 記事全体の文字数は500字～1000文字とすること
- 記事の最後に以下情報を入れること
```
※この記事はChatGPTを使用して作成されています。
執筆日：YYYY/MM/DD
執筆者：John Doe
```

# 対象読者
記事の対象読者は以下の要素を含む人物とする。
- ChatGPT未経験者
- ITエンジニア

# 記事タイトル
ChatGPT入門ガイド

# 記事内容
前述の# 対象読者を考慮し、以下内容で記事を作成すること。
1. ChatGPTについて解説
2. ChatGPTを使用する上でのメリットとデメリットについて
3. ChatGPTの使用例
4. GPT-3.5とGPT-4.0の違いについて以下の表形式に沿って説明してください。
|特徴|GPT-3.5|GPT-4.0|
|料金体系||
|性能||

````

## 4. さいごに
ChatGPTから精度の高い応答を得るためには、Markdown記法などを使用してわかりやすいプロンプトを書くことが推奨されます。
ただし、どんなに指示が的確でも求めていた完璧な応答が得られるとは限りません。そのため、一発で望んだ応答を得ようとせずに、応答を繰り返しながらプロンプトを修正したり、再生成を繰り返して調整していくことが重要です。
Local は Apple シリコンの Mac では Rosetta 2 が必要

WordPress のローカル開発環境を簡単構築できる Local ですが、Apple シリコンの Mac では Rosetta 2 が必要なようです。（2023年３月11日現在）

開発環境
```
MacBook Air M3 2024
macOS Sonoma 14.4
```

`brew install local` して、
以前のマシンで expoert した wordpress の zip ファイルをインポートところ、下記エラーが出ました。

```
Uh-oh! Unable to provision site.

Error: Error: spawn Unknown system error -86
at ChildProcess.spawn (node:internal/child_process:413:11)
at spawn (node:child_process:783:9)
at execFile (node:child_process:359:17)
at t.<computed> (node:electron/js2c/asar_bundle:2:2265)
at /Applications/Local.app/Contents/Resources/app.asar/main/_helpers/execFilePromise.js:1:583
at new Promise (<anonymous>)
at Object.<anonymous> (/Applications/Local.app/Contents/Resources/app.asar/main/_helpers/execFilePromise.js:1:534)
at Generator.next (<anonymous>)
at /Applications/Local.app/Contents/Resources/app.asar/main/_helpers/execFilePromise.js:1:330
at new Promise (<anonymous>)
```

```
Uh-oh! Could not update hosts file

Local ran into a problem when trying to update the hosts file.

Please ensure that the hosts file is not locked by anti-virus.
```

色々調べた末、行き着いた原因は Rosetta 2 がインストールされていないことでした。

Rosetta 2 のインストールコマンドは `softwareupdate --install-rosetta` です。

```
I have read and agree to the terms of the software license agreement. A list of Apple SLAs may be found here: https://www.apple.com/legal/sla/
Type A and press return to agree: a
```

上記ダイアログが返ってきますので、 `a` + `return` でインストールされます。
pandasを使って、データを文字列から数値に変換する

データエンジニアが遭遇する可能性のある最も一般的なデータの問題とその対処法についての備忘録です。

### サンプルデータフレームの生成
pandasを用いてサンプルのデータフレームを作成します。
```python
import pandas as pd

# 架空のデータフレームの作成
sales = pd.DataFrame({
    'SalesOrderID': [101, 102, 103],
    'Quantity': [10, 15, 12],
    # ↓汚いデータの例
    'Revenue': ["1500円", "2300円", "1800円"]
})

# データフレームの表示
print(sales)
```
下記が作成したデータフレームになります。
```
   SalesOrderID  Quantity Revenue
0           101        10  1500円
1           102        15  2300円
2           103        12  1800円
```

dtypes関数を使いデータ型を確認します。
```python
sales.dtypes
```
↓出力結果
```
SalesOrderID     int64
Quantity         int64
Revenue         object
dtype: object
```
dtypes属性を使用してカラムのデータ型を詳しく調べると、Revenue列ではobjectが返されます。objectは、pandasが文字列を格納するために使用するものです。


この状態でRevenue列にsum関数を適用すると、
```python
sales['Revenue'].sum()
```
下記のような出力結果になります。
```
"1500円2300円1800円"
```
ご覧の通り、各行の文字列を合わせた連結文字列が出力されます。これは期待するものではありません。

### 前処理を行う
```python
# Revenue列の全行から'円'を削除
sales['Revenue'] = sales['Revenue'].str.strip('円')

# Revenue列の全データをstringからintに変更
sales['Revenue'] = sales['Revenue'].astype('int')
```
再度、各カラムの型を確認します。
```
sales.dtypes
```
↓出力結果
```
SalesOrderID    int64
Quantity        int64
Revenue         int64
dtype: object
```
Revenue列がint型に変更されたことを確認できました。

### 確認

再度、Revenue列の合計を計算してみます。
```python
sales['Revenue'].sum()
```
↓出力結果
```
5600
```
期待通りRevenue列の合計額を取得できました！
C++ 文字列操作について

## はじめに
C++で文字列操作をする時にすぐわからなくなってしまうので、備忘録として残しておきます。

### 文字列のサイズを取得
**size()** を利用
```c++
string s1 = "testcode";
string s2 = "テストコード";
string s3 = "";

// 文字列の長さを出力
cout << "文字列の長さ：" << s1.size() << "\n";
cout << "文字列の長さ：" << s2.size() << "\n";
cout << "文字列の長さ：" << s3.size() << "\n";
```
```:結果
文字列の長さ：8
文字列の長さ：18
文字列の長さ：0
```

### n番目の文字を取得
取得したい部分のインデックスを指定
```c++
string s1 = "testcode";

// n番目の文字を取得
cout << "1番目の文字：" << s1[1] << "\n";
cout << "3番目の文字：" << s1[3] << "\n";
cout << "6番目の文字；" << s1[6] << "\n";
```
```:結果
1番目の文字：e
3番目の文字：t
6番目の文字；d
```

### n番目以降の文字列をi文字分取得
**substr(n, i)** を利用
```c++
string s1 = "testcode";

// n番目以降の文字列をi文字分取得
cout << "0番目以降の文字列を3文字：" << s1.substr(2, 3) << "\n";
cout << "5番目以降の文字列を3文字：" << s1.substr(5, 3) << "\n";
cout << "2番目以降の文字列：" << s1.substr(2) << "\n";
```
```:結果
2番目以降の文字列を3文字：stc
5番目以降の文字列を3文字：ode
2番目以降の文字列：stcode
```

### 文字列の挿入
**insert(n, "文字列")** を利用。n番目に"文字列"を挿入。
```c++
// 文字列の挿入
cout << "文字列の挿入：" << s2.insert(9, "対策") << "\n";
```
```:結果
文字列の挿入：テスト対策コード
```

### 文字列の結合
文字列同士を  + で足せばよい
```c++
// 文字列の挿入
cout << "文字列の挿入：" << s2.insert(9, "対策") << "\n";
```
```:結果
文字列結合：テスト対策コードの演習
```

### 末尾に文字を挿入
**push_back()** を利用
```c++
// 末尾に文字を挿入
s2.push_back('A');
cout << "末尾に文字を挿入後：" << s2 << endl;
```
```:結果
末尾に文字を挿入後：テスト対策コードA
```

### n文字目以降の文字列をi文字分削除
**erase(n, i)** を利用
```c++
string s1 = "testcode";

// n文字目以降の文字をi文字分削除
cout << "0番目以降の文字列を3文字削除：" << s1.erase(2, 3) << "\n";
cout << "5番目以降の文字列を3文字削除：" << s1.erase(5, 3) << "\n";
cout << "2番目以降の文字列削除：" << s1.erase(2) << "\n";
```
```:結果
0番目以降の文字列を3文字削除：teode
5番目以降の文字列を3文字削除：teode
2番目以降の文字列削除：te
```

### 末尾の文字を削除
**pop_back()** を利用する
```c++
string s = "test";

// 末尾の文字を削除
s.pop_back();
cout << "末尾の文字を削除後：" << s << endl;
```
```:結果
末尾の文字を削除後：tes
```

### 文字の検索
**find()** を利用する
```c++
// 文字の検索
cout << "tという文字を検索：" << s1.find('e') << endl;
cout << "aという文字を検索：" << s1.find('a') << endl;
```
```:結果
tという文字を検索：1
aという文字を検索：18446744073709551615
```
文字が見つからない場合は、上記のような大きな数字が返却される。

### 文字列を数値へ変換
**stoi()** を利用する。
```c++
// 文字の変換
string sNum = "123";
int i = stoi(sNum) + 1;
cout << "文字列を数値に変換：" << i << endl;
```
```:結果
文字列を数値に変換：124
```
文字列「123」を数値に変換し、1を足している。結果、123 + 1 = 124となったため、string型からint型へ変換されて、正しく計算が行われた。
ちなみに、int型からstring型の変換は下記のように行う。

```c++
// int型からstring型への変換
int n = 100;
string s5 = to_string(n);
cout << "数値を文字列に変換：" << s5 + "123" << endl;
```
```:結果
数値を文字列に変換：100123 
```
文字列同士を結合させることができたので、int型からstring型へ変換されていることが分かる。

### 文字列の置換
**replace(i, n, "文字列");** でi番目からn個を"文字列"で置換することができる。
```c++
// 文字列の置換
s5 = "testcode";
cout << "置換前：" << s5 << endl;
s5 = s5.replace(4, 1, "C");
cout << "置換前：" << s5 << endl;
```
```:結果
置換前：testcode
置換前：testCode
```

### 文字列を判定
```c++
// 文字列の比較
if (s5 == "testCode") {
    cout << "「testCode」" << endl;
} else { 
    cout << "「testcode」" << endl;
}

// 文字を判定
if (s5[1] == 'e') {
    cout << "2番目の文字はe" << endl;
} 
```
```:結果
「testCode」
2番目の文字はe
```
OpenSearchコマンド備忘録

# OpenSearchコマンド
ElasticSearchと微妙に差異があるので備忘録に
自分でよく使うもののみ

### 起動確認
```
curl -XGET 'localhost:9200/'
```
## インデックス
### 一覧
```
curl -XGET 'localhost:9200/_cat/indices?v'
```
### 設定確認
```
curl -XGET 'localhost:9200/{indexName}/_settings?pretty'
```
### マッピング確認
```
curl -XGET 'localhost:9200/{indexName}/_mapping?pretty'
```
### インデックス削除
```
curl -XDELETE 'localhost:9200/{indexName}?pretty'
```
## エイリアス
### エイリアス追加
```
curl -H Content-Type:application/json -XPOST 'localhost:9200/_aliases' -d 
'{"actions": [{"add": {"index": "{indexName}", "alias": "{aliasName}"}}]}'
```

### エイリアス確認
```
curl -XGET 'localhost:9200/_aliases?pretty'
```

## ドキュメント
### 件数確認
```
curl -XGET 'localhost:9200/{indexName}/_count?pretty'
```
### フィールド定義追加
```
curl -H Content-Type:application/json -XPOST 'localhost:9200/{indexName}/_mappings/?pretty' -d '
{
  "properties" : {
    "field1" : {
      "type" : "text"
    },
    "field2" : {
      "type" : "keyword"
    }
  }
}'
```

### ドキュメント追加
```
curl -H Content-Type:application/json -XPOST 'localhost:9200/{indexName}/_update/{_id}' --d '
{
  "doc": { "name": "Jhon Doe", "age": 20 }
}'
```

### ドキュメント更新
```
curl -H Content-Type:application/json -XPOST 'localhost:9200/{indexName}/_update/{_id}' --d '
{
  "doc": { "name": "Jhone Doe", "age": 21 }
}'
```

### ドキュメント取得
```
curl -XGET 'localhost:9200/{indexName}/_doc/{_id}?pretty'
```

### ドキュメント検索(条件無)
```
curl -XGET 'localhost:9200/{indexName}/_search?pretty'
```

### ドキュメント検索(条件有)
```
curl -H Content-Type:application/json -XGET 'localhost:9200/{indexName}/_search?pretty' -d '
{
  "query": {
    "match": {
      "name": "Jhon"
    }
  }
}
'
```

## リインデックス
```
curl -H Content-Type:application/json -XPOST 'localhost:9200/_reindex?pretty' -d '
{
  "source": {
    "index": "fromIndex"
  },
  "dest": {
    "index": "toIndex"
  }
}'
```

## その他
### ユーザー名
[きめ細かなアクセスコントロール](https://docs.aws.amazon.com/ja_jp/opensearch-service/latest/developerguide/fgac.html)の機能を使っていてユーザー名を指定する必要がある時は以下のようにユーザー名とパスワードを指定する
```
curl -u {USERNAME}:{PASSWORD} -XGET 'localhost:9200/_cat/indices?v'
```

### 書き出したjsonファイルを使う
``` xxx.json
{
    "name": "Jhon Doe", 
    "age": 20
}
```

```
curl -H Content-Type: application/json -XPOST 'localhost:9200/{indexName}/_doc/' -d @xxx.json
```

## 参考にした記事
https://qiita.com/mug-cup/items/ba5dd0a14838e83e69ac
Minecraft Datapack 作りたいものリスト

# 作りたいもの
　これから配布ワールド等を作るときにこれだけ入れておけば、なんとかなるっていう
 ライブラリ的なのを作成するリスト的な感じです。
 　基本的には各項目に対して、記事を作成していく。

# リロードしたときの自動通知
　
・指定範囲のブロック設置
・手持ちアイテムをオール削除
・特定アイテムセットを取得
・棒立ちMOBの作成
・会話Common作成
随時追加予定
[error]API resolved without sending a response for ..., this may result in stalled requests.

タイトルの通りのエラーが表示されていたが、解決したので忘れないようにメモ

```改善前：/api/shop.ts
import prisma from '@/lib/prisma';
import { Shop } from '@prisma/client';
import { NextApiRequest, NextApiResponse } from 'next';

async function createShopHandler(req: NextApiRequest, res: NextApiResponse) {
    const shop: Shop = req.body
    await prisma.shop
        .create({
            data: shop
        })
        .then(async () => {
            res.status(201).json(shop)
        })
        .catch(async (e) => {
            console.error(e)
            res.status(500).json({ error: 'server error' })
        })
        .finally(async () => {
            await prisma.$disconnect();
        })
}
async function findShopsHandler(req: NextApiRequest, res: NextApiResponse) {
    await prisma.shop
        .findMany()
        .then(async (shops) => {
            res.status(200).json(shops)
        })
        .catch(async (e) => {
            console.error(e)
            res.status(500).json({ error: 'server error' })
        })
        .finally(async () => {
            await prisma.$disconnect();
        })
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    switch (req.method) {
        case 'GET':
            findShopsHandler(req, res)
            break;
        case 'POST':
            createShopHandler(req, res)
            break;
        default:
            res.status(405).json({ error: 'Required Method is not allowed.' })
            break;
    }
}
```
```改善後：/api/shop.ts
import prisma from '@/lib/prisma';
import { Shop } from '@prisma/client';
import { NextApiRequest, NextApiResponse } from 'next';

async function createShopHandler(req: NextApiRequest, res: NextApiResponse) {
    const shop: Shop = req.body
    await prisma.shop
        .create({
            data: shop
        })
        .then(async () => {
            res.status(201).json(shop)
        })
        .catch(async (e) => {
            console.error(e)
            res.status(500).json({ error: 'server error' })
        })
        .finally(async () => {
            await prisma.$disconnect();
        })
}
async function findShopsHandler(req: NextApiRequest, res: NextApiResponse) {
    await prisma.shop
        .findMany()
        .then(async (shops) => {
            res.status(200).json(shops)
        })
        .catch(async (e) => {
            console.error(e)
            res.status(500).json({ error: 'server error' })
        })
        .finally(async () => {
            await prisma.$disconnect();
        })
}

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    switch (req.method) {
        case 'GET':
            return findShopsHandler(req, res)
        case 'POST':
            return createShopHandler(req, res)
        default:
            return res.status(405).json({ error: 'Required Method is not allowed.' })
    }
}
```

switch利用時にreturnされていないため、requestが終わらないよう〜となっているようだった。

今度詳しく調査予定
replit.com Flet GitHub Google 認証

# [replit.com](replit.com) [Flet](flet.dev) [GitHub](github.com) [Google](https://console.cloud.google.com/apis/credentials/oauthclient) 認証 を手探りでやってみる

# Flet GitHub 認証 サンプル通りにやってみる
Fletのドキュメントで認証 [Flet Authentication](https://flet.dev/docs/guides/python/authentication)

MyApp ページが作成される。
- クライアントシークレット 【新しいクライアントシークレッツを生成する】 ボタンクリック
- Client ID と Client secret を控えておく

## replit.com で プロジェクト作成
【+Create Repl】クリック
- Template : Flet
- Title : MyAppOAuth

プロジェクトに`main.py`が作成される。  

## 開発環境URL確認
Run して Webview の URLをクリックして Dev URL: を控える。
![スクリーンショット 2024-03-11 231239.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366837/cf2e3289-35ee-b16f-8d61-5b1e24c102da.png)

## [Configuring OAuth provider](https://flet.dev/docs/guides/python/authentication#configuring-oauth-provider)
### [GitHub OAuth app](https://github.com/settings/developers)
フレッツ認証を GitHub と統合するには、最初に新しい[GitHub OAuth アプリ](https://github.com/settings/developers)を登録する必要があります (プロファイル設定→開発者設定→ OAuth アプリ)。

- アプリケーション名 :  MyApp
- ホームページURL : さっき控えた Dev URL
- アプリケーションの説明 : 
- 認可コールバック URL : さっき控えた Dev URL/api/oauth/redirect
ボタン【アプリケーションを登録する】クリック



## OAuth コードを上書き
Fletドキュメントの([OAuth](https://flet.dev/docs/guides/python/authentication#sign-in-with-oauth-provider))のコードをそのまま`main.py`に上書きする。

```main.py
import os

import flet as ft
from flet.auth.providers import GitHubOAuthProvider

GITHUB_CLIENT_ID = os.getenv("GITHUB_CLIENT_ID")
assert GITHUB_CLIENT_ID, "set GITHUB_CLIENT_ID environment variable"
GITHUB_CLIENT_SECRET = os.getenv("GITHUB_CLIENT_SECRET")
assert GITHUB_CLIENT_SECRET, "set GITHUB_CLIENT_SECRET environment variable"

def main(page: ft.Page):
    provider = GitHubOAuthProvider(
        client_id=GITHUB_CLIENT_ID,
        client_secret=GITHUB_CLIENT_SECRET,
        redirect_url="さっき控えた Dev URL/api/oauth/redirect",
    )

    def login_click(e):
        page.login(provider)

    def on_login(e):
        print("Login error:", e.error)
        print("Access token:", page.auth.token.access_token)
        print("User ID:", page.auth.user.id)

    page.on_login = on_login
    page.add(ft.ElevatedButton("Login with GitHub", on_click=login_click))

ft.app(target=main, port=8550, view=ft.WEB_BROWSER)
```

## Secret 作成
左ToolsペインのSecretsをクリック
右ペインに鍵がくるくる。

【+New Secret】ボタンをクリックして環境変数を作成する。
- Key : GITHUB_CLIENT_ID , Value : さっき控えた Client ID
- Key : GITHUB_CLIENT_SECRET, Value : さっき控えた Client secret

※ githubページ右上ユーザーアイコンをクリックして Settings > Developer settings > OAuth Apps > MyApp とクリックするといつでも Client ID は確認できるが Client secret は確認できないので控えてなければ作り直さないといけない。 

## 認証確認
【Run】ボタンクリック
開発環境なので`127.0.0.0:xxxx`のページが開くが閉じる。
Webview に 【Login with GitHub】ボタンが表示されてサンプルが実装できた。

## 開発環境のURLとPort
```main.py
ft.app(target=main, port=8550, view=ft.WEB_BROWSER) # ここの port=8550
```
この port=8550 は
青● :8550 -> :80 とポートフォワーディングされているようだ。
![スクリーンショット 2024-03-11 223239.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366837/600e803a-af7d-31e8-abd9-bcc34f19d2f0.png)
<font color="red">portを変更したときに Webview が表示されないときはここを正しいポートをクリックすると表示できた。</font>
REST APIとは

## REST APIとは
**API**(アプリケーション　プログラム　インターフェース）は、アプリケーションとデバイスの接続と通信の方法を定義する一連のルールです。
**REST API**とは、REST(Representational State Transfer)の原則に基づいて設計されたAPIの事です。Webシステムを外部から利用するためのAPIです。

## RESTの設計原則
**1.統一されたインターフェース**
ユーザーの名前やEメールアドレスなど、同じデータが1つのURI(Uniform Resource Identifier)だけに属するようにします。クライアントが必要とする可能性のあるすべての情報が含まれている必要があります。

**2.クライアントとサーバーの分離**
クライアント側とサーバー側は、互いに分離され独立している必要があります。クライアントはリソースを表すURIのみを知ってればよく、他の方法でサーバー側は、クライアントリクエストに関連するデータの保存を許可されてません。

**3.ステートレス**
REST APIはステートレスなので、各リクエストが個別で完結しており、前のリクエストとの状態を引き継ぎません。そのため、その処理に必要なすべての情報を含める必要があります。

**4.キャッシュ可能**
キャッシュが許可されている場合は、クライアント側またはサーバー側でリソースのキャッシュが可能である必要があります。サーバーの応答には、そのリソースがキャッシュ可能かどうかの情報が含まれてなければならない。

**5.階層化システム**
REST APIでは、クライアントとサーバーの間に中間システムが存在する可能性があります。そのため、クライアントとサーバーは直接通信していると想定せず、中間システムの有無に関わらず通信できるように設計する必要があります。

**6.コードオンデマンド(オプション)**
REST APIは通常、静的なリソース(HTML、画像、データ)を送信します。
しかし、場合によっては応答に実行可能なコードを含めることができます。その際、実行可能コードはオンデマンド（必要に応じて）で実行される必要があります。

## REST APIで使われるHTTPメソッド
| HTTPメソッド | 概要                                |
|-------------|------------------------------------|
| GET         | リソースの読み取りや取得に使用    |
| POST        | 新しいリソースを作成するために使用 |
| PUT         | 既存のリソースを更新するために使用 |
| DELETE      | リソースを削除するために使用       |

 movieをリソースとしたCRUD操作のURIとHTTPメソッドは、次のように定義できます。

| URI                | HTTPメソッド | 概要 |
|--------------------|-------------|-------------|
| /movies            | POST        | 映画を作成    |
| /movies            | GET         | 映画のリストを取得    |
| /movies/{movie_id}  | GET         | 特定の映画を取得    |
| /movies/{movie_id}  | PUT         | 特定の映画を更新    | 
| /movies/{movie_id}  | DELETE      | 特定の映画を削除    |
セキュリティ情報

https://www.ncsc.gov.uk/section/keep-up-to-date/ncsc-news?q=&defaultTypes=news,information&sort=date%2Bdesc

https://www.nist.gov/blogs

https://gblogs.cisco.com/jp/category/security/

https://www.paloaltonetworks.com/blog/?lang=ja

https://www.ipa.go.jp/about/ipanews/index.html
Vue.jsの公式ドキュメントを整理していく　2回目

公式ドキュメントがまたカタカナ語ばっかでわからん。
ということで、またブログにして整理していくことにした。今回は「Vueアプリケーションの作成」の章を整理していく。
## createApp関数
vueのアプリ開発は、まずcreateApp関数で、アプリのインスタンスを作ることから始まる。
要するにアプリの枠組みを最初に作ってしまうのだ。
```
import { createApp } from 'vue'

const app = createApp({
  /* ルートコンポーネント オプション */
})
```
ちなみにこのソースコードは公式ドキュメントをコピペしたもの。

この`/*ルートコンポーネント　オプション */`のところに実際に表示されるボタンだとかテキストだとかの部品を記述していくことになる。公式ドキュメントではこういう部品のことをコンポーネントと呼んでいるので、ここでもそう呼ぶことにする。実際はコンポーネントの意味も知らなかったなんて言えな((ry

## ルートコンポーネント
さっき、部品を記述していくとか言ったが、そのまま書き込むわけではないらしい。ルートコンポーネントという、ほかのコンポーネントをまとめられる親玉みたいのが必要になる。
単一ファイルコンポーネントでは、単一ファイルコンポーネント自身がルートコンポーネントになる。
```
import { createApp } from 'vue'
// ルートコンポーネントを単一ファイルコンポーネントからインポートする
import App from './App.vue'

const app = createApp(App)
```
上のコードでは、createAppにAppというルートコンポーネントを渡している。
そしてそのAppというルートコンポーネントは、インポートした単一ファイルコンポーネントのことだ。
## アプリのマウント
.mountメゾットでコンポーネントはアプリ上に表示されるようになる。
``` .html
<div id="app"></div>
```
```.js
app.mount('#app')
```
.mountのおかげで上のdivがページに反映されるようになる。
## まとめ
なんか公式にはほかにもいろいろ書いてあったが、結局は、
**アプリの枠組みはcreateApp()で作れる**
**createApp()には単一ファイルコンポーネントを渡す**
**mount()でアプリに反映できる**
ということ。
あと公式より、一つだけのアプリだけでページを作るんじゃなくて、いっぱいアプリを作ってページを作れとのこと。
SDL2.ｄｌｌが見つからないエラーの件

SDL2を導入したvisualstudioで、SDL2.dllが見つからないエラーが解決できなかったが、やっとこさ解決できた。原因のエラー↓
![スクリーンショット 2024-03-11 213032.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3739806/9f45af55-113c-aac4-fbf4-bc38c1acf59c.png)

原因：
ビルドの際に、プロジェクトに生成されるdebugfolderの中に、SDL2.dllが生成
されなかったために起きていたエラーだった。![スクリーンショット 2024-03-11 212347.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3739806/49b54c3e-3246-940e-36f5-c8235dbdf61e.png)
つまり、このSDL2.dllが生成されるようにすればいい。
それの設定がこれ↓![スクリーンショット 2024-03-11 212537.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3739806/892b2ff0-5f1f-306b-ea7a-dde6ed40e3c5.png)
このコマンドラインにしっかりとしたpathを通せば解決する。

結果：
単純にネットのpathをコピペしたのが原因だった。
必ず、SDL2が自身のパソコンのどこに保存されているのかを理解して、正しいpath
を通す必要がある。
mixhostでスパムメールが大量に送られるときの対処法


MixHost初期設定ではドメインに来たすべてのメールを捕獲してしまうためスパムメールが大量に送られてくる原因となっています。存在しないユーザーへのメールアドレスでは捕獲しないように設定変更する方法を紹介します。

:::note warn

※ これは2018-01-02に[個人ブログ](https://bicstone.me)で公開した記事を移植し、[CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.ja)で提供しています。情報は古い可能性があります。

:::

## スパムメールのほとんどがローカル部がランダム

mixhostのデフォルトメールアドレスには、登録したドメインに送られたすべてのメールが受信されてしまいます。次のスクリーンショットのように、ローカル部がランダムでありながらもすべて受信しています。

![webmaster@ や help@ など適当なユーザー部に向けてメールが送信され、すべて受信してしまう](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/09208432-5c5f-ccf6-a972-60db3753972b.png)

## 存在しないアカウントへのメールは受信しない

MixHostにてログイン →cPanelにログインより、電子メール → 規定のアドレスを開きます。

![MixHostにてログイン→cPanelにログインより、電子メール→規定のアドレスを開きます。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/941f91db-1007-b3b7-dd11-c2c4889b251e.png)

すべてのドメインについて、「システム アカウント に転送します」から、「サーバーで処理が行われていても電子メールをSMTP時間までに破棄し、エラー メッセージを生成します。」に変更して保存します。

![「システム アカウント に転送します」から、「サーバーで処理が行われていても、電子メールを SMTP 時間までに破棄し、エラー メッセージを生成します。」に変更して保存します。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/be27f2b9-8540-b69a-b5b9-60324d35adf4.png)

あまりにも件数が多く、送信数制限にひっかかる場合は、「廃棄」を選択します。

![件数が多く、送信数制限にひっかかる場合は、「廃棄」を選択します。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/c0872361-677c-4c83-c421-8ff54941e1ad.png)

この作業によって、アカウントのないメールアドレスへの受信が止まります。
allow_url_fopenが0のサーバーで外部ファイルを取得する方法


allow_url_fopenに0が設定されたレンタルサーバーではPHPのfile_get_contentsなどを用いて外部のファイルが取得できません。これを回避して取得する方法を紹介します。

:::note warn

※ これは2017-07-19に[個人ブログ](https://bicstone.me)で公開した記事を移植し、[CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.ja)で提供しています。情報は古い可能性があります。

:::

## レンタルサーバーのセキュリティが厳しい

(今は亡き)ウェブクロウというPHPが動作する無料サーバーにてPHPのfile_get_contentsを用いて外部ファイルを取得しようとしました。しかし、php.iniにてallow_url_fopen=0に設定されており、取得ができませんでした。

![取得エラーが発生したスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/e1b3f4be-5aa7-44b8-301a-06679225df63.png)

次のようなエラーが発生します。

> Warning: file_get_contents(): http:// wrapper is disabled in the server configuration by allow_url_fopen=0 Warning: file_get_contents(http://www.example.com/): failed to open stream: no suitable wrapper could be found

## 別の関数を使用する

外部ファイルを取得する方法として他にcURLライブラリを用いる方法があります。このライブラリ経由であれば、allow_url_fopenに0が設定されたレンタルサーバーでも外部ファイルを取得できます。ただし、cURLライブラリがインストールされていないサーバーでは使用できません。

下記ではexample.comの内容がそのまま取得できています。

![example.comの内容がそのまま取得できているスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/8bb29d01-86d5-7653-82cc-f1f0c7c8f07b.png)

下記はプログラムの例です。ユーザーエージェントやタイムアウトなどオプションが豊富なので[公式マニュアル](https://www.php.net/manual/ja/function.curl-setopt.php)を参考に色々試してみてください。

```php
<?php
$url="http://www.example.com/";
$cp = curl_init();
/*オプション:リダイレクトされたらリダイレクト先のページを取得する*/
curl_setopt($cp, CURLOPT_RETURNTRANSFER, 1);
/*オプション:URLを指定する*/
curl_setopt($cp, CURLOPT_URL, $url);
/*オプション:タイムアウト時間を指定する*/
curl_setopt($cp, CURLOPT_TIMEOUT, 30);
/*オプション:ユーザーエージェントを指定する*/
curl_setopt($cp, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
$data = curl_exec($cp);
curl_close($cp);
echo $data;
?>
```
【WordPress】「次回のコメントで使用するため…」を削除する方法


WordPress 4.9.6からコメント投稿フォームに追加された「次回のコメントで使用するためブラウザーに自分の名前、メールアドレス、サイトを保存する。」を削除・非表示にする方法を紹介します。

:::note warn

※ これは2018-05-23に[個人ブログ](https://bicstone.me)で公開した記事を移植し、[CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.ja)で提供しています。情報は古い可能性があります。

:::

## コメント投稿フォームにチェックマークが増えた

2018年5月19日に更新されたWordPress 4.9.6にアップデートすると、[`comment_form`](https://developer.wordpress.org/reference/functions/comment_form/)コマンドが用いられているテーマでコメント投稿コメント欄の送信ボタンの真上に次のスクリーンショットのようなチェックボックスとテキスト「次回のコメントで使用するためブラウザーに自分の名前、メールアドレス、サイトを保存する。」が追加されてしまいます。

![「次回のコメントで使用するためブラウザーに自分の名前、メールアドレス、サイトを保存する。」がコメント投稿欄に表示される](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/26d7120d-0f23-65d6-56b6-4a10e4d86d38.png)

## 原因

2018年5月25日に発効される「欧州連合（EU）の一般データ保護規則（GDPR）」に則るための新機能が原因です。Cookieの保存の可否を問う新機能を搭載したと公式ブログにも記載があります。

https://ja.wordpress.org/2018/05/19/wordpress-4-9-6-privacy-and-maintenance-release/

## 対処方法

テーマの `functions.php` に次のコードをコピペします。`functions.php` にすでにコードが追加されている場合は `<?php` 及び `?>` が二重にならないようお気をつけください。WordPressがエラーで起動できなくなってしまう場合があるためバックアップしてから保存してください。

```php
<?php
add_filter('comment_form_default_fields', 'comment_remove_cookiescheck');
function comment_remove_cookiescheck($arg) {
 $arg['cookies'] = '';
 return $arg;
}
?>
```

## 対処結果

WordPress 4.9.5までの従来の表示に戻りました。動作的には常に保存しない設定となります。

![「次回のコメントで使用するためブラウザーに自分の名前、メールアドレス、サイトを保存する。」がコメント投稿欄に表示されなくなった](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/ac4043c9-afb1-00de-eb6d-cd11f97467e6.png)
Microsoft アカウントで Windows にログインできない場合の対処方法


一瞬ウインドウが出ても消えてしまい、MicrosoftアカウントでWindows 10にログインできない場合の対処方法を紹介します。

:::note warn

※ これは2017-05-28に[個人ブログ](https://bicstone.me)で公開した記事を移植し、[CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.ja)で提供しています。情報は古い可能性があります。

:::

## 現象

MicrosoftアカウントでWindows 10の設定アプリにログインしたいと思い、「Microsoftアカウントでのサインインに切り替える」をクリックしましたが、一瞬ウインドウが出ても消えてしまい、ログインが出来ません。

「Microsoftアカウントでのサインインに切り替える」をクリックしても..。

![Windowsの設定から「Microsoft アカウントでのサインインに切り替える」をクリック](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/d6d42d74-bf74-9a3d-19b8-add49ce5c901.png)

一瞬ウインドウが現れ..。

![何も表示されないウインドウが表示される](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/75fc7017-1949-24c9-169d-a2f34ddb5031.png)

消えてしまいました。

![Windows の設定画面に戻る](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/7b4e4515-3e4e-6009-1026-e0d4a603e3fd.png)

## 原因

設定アプリが破損してしまっていることが原因です。

## 対処

Windowsキー + Xまたは、スタートメニューボタンを右クリックし、「コマンドプロンプト(管理者)」を開きます。

![Windows + X キーでメニューを開く](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/a83ad5fa-166e-d2a7-b7eb-baea260b4926.png)

`powershell` と入力してEnterを押します。

![コマンドプロンプトで、 `poweshell` を入力する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/23493c7c-9d73-a9ba-3b4a-f5605b498ba2.png)

まずは、すべてのアプリを終了させたあと、次のコマンドを入力してEnterを押します。このコマンドによってMicrosoft製のアプリをすべて再インストールします。尚、副作用として今までに削除したMicrosoft製のアプリはすべて復活します。

```powershell
Get-AppXPackage -AllUsers | Foreach {Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml" -Verbose}
```

![PowerShell のスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/3395226d-c12d-7a73-bdf7-8ab61476dbb2.png)

再起動後、正常にログインできるか確認してください。これでも出来ない場合はさらに次のコマンドを実行します。このコマンドによってWindowsの根幹ファイルの探査・修復します。

```powershell
DISM.exe /Online /Cleanup-image /Restorehealth
```

```powershell
sfc /scannow
```

すこし時間がかかります。終了後、再起動して正常にログインできるか確認してください。これでも出来ない場合、新しくアカウントを作ってその際にMicrosoftアカウントでログインできないか試してみてください。

## 結果

無事にログインできるようになりました。

![Windows のログイン画面が表示される](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/31a08b84-b918-12a1-22c6-6dc91208aa62.png)
レンタルサーバーにTiny Tiny RSSをインストール


レンタルサーバーにTiny Tiny RSSを簡単にインストールする方法を紹介します。今回はさくらのレンタルサーバでの例を紹介しますが、PHPとMySQLが動作する一般的なレンタルサーバーであれば、概ねインストールできます。

:::note warn

※ これは2017-05-28に[個人ブログ](https://bicstone.me)で公開した記事を移植し、[CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.ja)で提供しています。情報は古い可能性があります。

:::

## Tiny Tiny RSS とは

Tiny Tiny RSS (略称tt-rss)とはサーバーサイドのオープンソースRSSクライアントです。インストールしたURLにアクセスするだけで見られるのでスマホなどからどこでも見られる・高頻度でRSSを取得しに行くので更新頻度が高いサイトでも逃さずキャッチしやすい・登録したレンタルサーバー業者以外に登録しているRSSの情報が知られないなどの特徴があります。一方、定期的にtt-rssをアップデートするなどの保守が必要になります。

インストール不要で登録制のサービスとしてfeedlyがありますが、RSSの登録数に制限がある、Googleアラートの登録が不可、更新間隔が長い、RSS登録情報がfeedlyに知られるといった欠点があります。

## データベースの作成

まず、事前準備として、さくらのレンタルサーバのコントロールパネルより、MySQLのデータベースを作成します。

[さくらのレンタルサーバーのコントロールパネル](https://secure.sakura.ad.jp/rscontrol/)を開きます。

データベースの設定よりデータベースを新規作成します。

![データベースの新規作成を選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/0258ecf8-d167-6590-32e0-2f5384eb2973.png)

適当なデータベース名を設定し、作成します。

![適当なMySQLのデータベースを作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/5eb4a290-b99e-0eba-a6d5-4156c3dec11e.png)

## tt-rss をダウンロード

次に、tt-rssをダウンロードしてFTPでアップロードします。または、WebサーバーにSSHで入って同じコマンドを叩きます。

```sh
git clone https://git.tt-rss.org/fox/tt-rss.git
```

https://git.tt-rss.org/fox/tt-rss.git

## 設定

`「https://[インストールしたURL]/install/」` を開くとインストール画面が出てきます。

- Database typeは `MySQL`
- Usernameはユーザー名(初期アカウント名)
- Passwordは設定しているパスワード
- Database nameは先程設定したデータベース名
- Host nameはコントロールパネルに記載の `mysql[数字].db.sakura.ne.jp`
- Portは `3306`
- Tiny Tiny RSS URLは現在アクセスしているURLから/install/を消したもの

![Tiny Tiny RSS installer のスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/907e9295-64b3-9fbd-427d-0305610a6956.png)

Test configurationをクリック、その後Save configurationをクリックすると無事インストール完了です。

## ログイン

「`https://[インストールしたURL]`」からログインします。初期はログイン:「`admin`」、パスワード:「`password`」になっています。

![Tiny Tiny RSS のログイン画面のスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/f6e72b60-c93b-e07a-c5fd-a6da0d5b25f9.png)

ログイン後、右上の設定より、パスワードを変更します。他のユーザーアカウントが必要なければ、アカウントを追加せずにadminを引き続き使用してよさそうです。

![Tiny Tiny RSS の設定画面のスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/d25c6b28-80f7-efd1-7d22-0b6e37fe666d.png)

## CRON を設定する

tt-rssのRSSを巡回させるには、サーバー内部から「update.php --feeds --quiet」を定期的に実行させる必要があります。そのためにCRONを設定します。

[さくらのレンタルサーバーのコントロールパネル](https://secure.sakura.ad.jp/rscontrol/)より、「CRONの設定」を開きます。

次のCRONを設定します。この場合、30分ごとの取得となります。間隔が短すぎると取得先のサーバーから規制される場合があります(IPアドレスで規制されてしまった場合、IPアドレスを変更しなければ一生取得できなくなります…)。

- 実行コマンドは `/usr/local/bin/php /home/[ユーザー名]/www/[設置パス]/update.php --feeds --quiet`
- 月は `*`
- 日は `*`
- 時は `*`
- 分は `*/30`
- 曜日は `日月火水木金土`
- コメントは任意

以上で設定は完了です。

## アップデート

tt-rssは定期的にアップデートする必要があります(アップデートしないとセキュリティの懸念が発生する場合もあります)。

FTPでアップロードしている場合、 `git pull` してからFTPで上書きします。

SSHでWebサーバーにcloneしている場合、SSHで入って `git pull` します。

ただし、config.phpの書式が更新されている可能性があるので、注意します。また、更新中にCRONによってupdate.phpが呼ばれると不具合が生じることもあるので、update.phpは一時的に削除しておくことをおすすめします。
BitLockerを再ロックする方法


BitLockerはドライブをまるごと暗号化できるWindowsの標準ツールです。ドライブを接続したままで再ロックする方法を紹介します。

:::note warn

※ これは2018-01-10に[個人ブログ](https://bicstone.me)で公開した記事を移植し、[CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.ja)で提供しています。情報は古い可能性があります。

:::

## BitLocker を再ロックできない

BitLockerで暗号化したドライブを一度アンロックすると、利便性を高めるためか、ログアウトするかドライブを切断しない限り再ロックされません。

右クリックでの再ロックも不可能なようです。

![エクスプローラーのドライブを右クリックしてもBitLockerを再ロックする選択肢がない](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/6a1ea4c0-7ee9-df38-3e60-850c0222f9dd.png)

しかし、私の使用環境では、BitLockerをしたドライブはPC内部で接続しぱなしです。スリープし、しばらくログアウトしないことも多いため、せっかくの暗号化の意味が弱まってしまいます。

## コマンドプロンプトで再ロック可能

PowerShellでBitLockerを制御するプログラム `manage-bde` のパラメーター一覧を見てみたところ「`-lock` BitLocker暗号化データへのアクセスを禁止します。」との文字が！

![manage-bde のパラメータ説明。「 `-lock` BitLocker暗号化データへのアクセスを禁止します。」との文字がある](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/ba219e02-7b0d-75db-cef9-b1fe4ad6cf31.png)

試しに `manage-bde [ボリュームラベル]: -lock` を実行するとロックできました。

![`manage-bde H: -lock` するとボリュームHがロックされた](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/732de46b-80a3-d2cb-93f7-5a53c2bcb90d.png)

## バッチファイルにして簡単に実行できるように

`manage-bde [ボリュームラベル]: -lock` の1行を記載したバッチファイルを暗号化しているドライブに保存しておき、このバッチファイルを右クリックの管理者権限で実行するようにすると簡単にロックができます。

![lock.bat を作成する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/b73e20be-903d-94ee-b6e1-703b1eb75dcd.png)

![lock.bat を右クリックして、「管理者として実行」を選択する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/56ec8da0-6f0f-d69a-6640-969d0cc8a026.png)

## エクスプローラーの不具合

ただし、この方法ではエクスプローラーが誤作動します。

この方法でロックし、その後再びロック解除したあとにドライブをダブルクリックしても「BitLockerドライブ暗号化で保護されたドライブは既にロック解除されています。」と表示されます。

![Windows が 「BitLockerドライブ暗号化で保護されたドライブは既にロック解除されています。」と表示する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/0f0df1dc-3ee1-2e6e-fa15-b37edbd994ca.png)

その場合は、ドライブをダブルクリックせず、右クリックして「開く」をクリックしてください。

![エクスプローラーのドライブを右クリックして「開く」を選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/d5777946-49fa-fb47-b03f-f45d913db0dd.png)
Dockerで環境構築(Rails7＋mysql)

## はじめに
　ポートフォリオ作成のため、Dockerにて環境構築を行いました。
 その時の流れと、ファイルの意味について調べたことを記録しました。
 初学者のため、間違えていたら申し訳ありません。
 

## 環境
PC: mac（Apple M1）
Ruby: 3.1.4
Rails: 7.0.8


## 作業内容
### ① ディレクトリ下にファイルを作成する
ディレクトリ
```
好きなディレクトリ名/
├── Dockerfile
├── docker-compose.yml
├── entrypoint.sh
├── Gemfile
└── Gemfile.lock
```
#### ファイル一括作成コマンド
```
touch Dockerfile docker-compose.yml Gemfile Gemfile.lock entrypoint.sh
```
### ② ファイルの中身を記述する
#### ファイルの中身
```:Dockerfile
FROM ruby:3.1.4   #　rubyのバージョンを指定 

RUN mkdir /app   #　コンテナ内にappディレクトリを作成

WORKDIR /app   #　作成したappディレクトリを作業用ディレクトリとして設定

COPY Gemfile /app/Gemfile  
COPY Gemfile.lock /app/Gemfile.lock   # ローカルの Gemfile と Gemfile.lock をコンテナ内のapp配下にコピー

RUN bundle install   # コンテナ内にコピーした Gemfile の bundle install

COPY . /app   #　ローカルのディレクトリ配下のファイルをコンテナ内のapp配下にコピー

COPY entrypoint.sh /usr/bin/   #　ローカルのentrypoint.shを/usr/bin配下にコピー
RUN chmod +x /usr/bin/entrypoint.sh   #　ファイル所有者にentrypoint.shの実行権限を付与
ENTRYPOINT ["entrypoint.sh"]   #　コンテナ起動時にentrypoint.shを実行するように設定
EXPOSE 3000   #　ポート番号を指定

CMD ["rails", "server", "-b", "0.0.0.0"]   #　イメージの実行時に実行するメインプロセスを構成する

```

```:docker-compose.yml
services:
  db:
    image: mysql/mysql-server:latest   # 使用するimageを指定
    environment:
      MYSQL_ROOT_PASSWORD: pass
      MYSQL_ROOT_HOST: '%'　　　　　　　　# 環境変数を設定
    ports:
      - "3306:3306"                    # ポート番号を指定
    volumes:
      - db-volume:/var/lib/mysql　　　　# データを永続化

  web:
    build: .   # Dockerfileの場所を指定
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"　　　# rails server が起動していた場合は停止し、サーバーを起動
    volumes:
      - .:/app   # ローカル側のディレクトリ配下とコンテナ側のapp配下を同期
    ports:
      - "3000:3000"　　　# ポートの指定
    depends_on:
      - db　　　# MySQLのコンテナが起動してからRailsのコンテナを起動する
volumes:
  db-volume:   # Docker Composeにボリュームを作成するように指示


```


```:entrypoint.sh
#!/bin/bash　　　# bashを利用したシェルスクリプトであることを示す
set -e   #エラーが出たらスクリプトを中断

rm -f /myapp/tmp/pids/server.pid   # pidファイルが既に存在するためサーバーが立ち上がらないエラーを回避するため、server.pidファイルが既にあった場合、それを削除

exec "$@"   # DockerfileのCMDの部分に書いてあるコマンドを実行する

```

```:Gemfile
source 'https://rubygems.org'
gem 'rails', '~>7.0.8'
```

### ③ rails new を実行
```
docker-compose run web rails new . --force --database=mysql --skip-bundle
```

### ④ docker-compose build を実行
```
docker-compose build
```

### ⑤ database.yml を編集
```
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  #　以下2行を編集
  password: pass     
  host: db
```

### ⑥ データベースを作成
```
docker-compose exec web rails db:create
```

### ⑦ コンテナを起動する
```
docker compose up
```
http://localhost:3000 にアクセスし、Railsアプリが起動していることを確認する。
【Rails】環境変数で条件分岐するときの小ネタ

## これはなに？

Railsにて、条件分岐を環境変数でおこなおうと考えました。
このときに上手くいかなかった理由を深堀りし、より良い方法を学んだのでそのメモです。

### やりたいこと

環境変数に`HOGE=true`を設定し、以下のようなコードで条件分岐させることを目標とします。

```ruby
if # ENV[HOGE]がtrue
  # なんらかの処理
end
```

## やったこと

### 間違いパターン

```ruby
if ENV['HOGE']  == true
 puts "HOGE is true"
end
# "HOGE is true"は出力されない
```

このコードでは、if節はfalseを返します。
一見すると不思議です。

コンソールで`ENV['HOGE']`そのものの真偽値はtrueを返すのに、なぜでしょう？

```ruby
!!ENV['HOGE']
=> true
```

その理由は、環境変数から取得される値はすべて文字列として扱われるためです。
.envファイルで`HOGE=true`と設定した場合でも、`ENV['HOGE']` は `"true"`のような**文字列として返されます**。
これはRubyのtrue(ブーリアン値)とは異なります。

```ruby
ENV['HOGE']
=> "true"

!!("true" == true)
=> false

!!(ENV['HOGE'] == true)
=> false
```


### 正解パターン

ENVで取得する値は文字列で返されるため、if節の条件値も文字列にする必要があります。
つまり、第一段階として以下の形式をとる必要があります。

```ruby
if ENV['HOGE']  == 'true'
 puts "HOGE is true"
end
# "HOGE is true"が出力される
```

ここで終わらずに、更にコードをレベルアップします。
結論から言うと、以下のようなコードにしました。

```ruby
if ENV.fetch('HOGE', 'false').downcase == 'true'
 puts "HOGE is true"
end
# "HOGE is true"が出力される
```

この方法では、まず ENV.fetch メソッドを使って環境変数`HOGE`の値を取得します。

このとき環境変数が存在しなければ、`.fetch`メソッドの第二引数に設定した'false' をデフォルト値として返します。

その後 `.downcase`メソッドで取得した文字列を小文字に変換します。
これにより、環境変数の値が"TRUE", "True", "true"など、大文字小文字に関わらず一貫した比較が可能になります。
【React】Custom Hooksとは

# Custom Hooksとは
ReactのCustom Hooksは、再利用可能なロジックをカプセル化し、複数のコンポーネントで共有するための仕組みです。Custom Hooksは、ReactのHooks（useState、useEffect、useContextなど）を使用して作成されますが、通常の関数として定義されます。

Custom Hooksを使用することで、コンポーネント内のロジックを抽出し、独立した関数として再利用できます。これにより、コンポーネントがシンプルで読みやすくなり、同じロジックを複数のコンポーネントで使用する場合にコードの重複を避けることができます。

Custom Hooksを作成する際の一般的な手順は以下の通りです：

1. **カスタムフックの作成**: フックは通常、`use`という接頭辞を付けた関数名で定義されます。たとえば、`useFetchData`などです。この関数は、必要な状態や副作用を管理し、それらをコンポーネントに返します。

2. **フックのロジックの実装**: カスタムフックの中で、必要な状態や副作用（APIからデータをフェッチするなど）を管理します。また、コンポーネントから渡されたパラメータを受け取ることもできます。

3. **カスタムフックの利用**: 作成したカスタムフックをReactコンポーネント内で呼び出します。通常は、`useState`、`useEffect`、その他のReactのフックと同様に使用します。

# まとめ
カスタムフックは、ロジックを再利用するための強力な手段ですが、注意が必要です。カスタムフック内では、Reactのフックを直接使用する必要があります。また、カスタムフックの名前は、`use`で始まる必要があります。これにより、Reactがフックを自動的に検出し、正しく処理することができます。
IngressでSSL終端

## ingressでSSL終端してみる。
# 秘密鍵を作成 鍵長を指定すべきか？
```
openssl genrsa -out server.key
```
# 署名要求ファイル生成 (.csr)
```
openssl req -new -key server.key -out server.csr -subj "/C=JP/ST=Tokyo/L=Minato City/O=TeX2e/CN=rncherwork4020"
cat <<'EOS' > san.txt
subjectAltName = DNS:rncherwork4020
EOS
```
# 自分の秘密鍵で自己署名した証明書を作成する
```
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt -extfile san.txt
openssl x509 -text -in server.crt -noout
```

# windowsインストール用にp12ファイル作成
```
openssl pkcs12 -export -in server.crt -inkey server.key -certfile server.crt -out rncherwork4020.p12
```
hostsへ追加
```
192.168.40.20 rncherwork4020
```
# シークレットをkubectlで登録する
```
#kubectl create secret tls tls-secret --cert=server.crt --key=server.key
```
手動でRancherから登録でもよい。

# tlsシークレット
```
apiVersion: v1
data:
  tls.crt: >-
    省略
  tls.key: >-
   省略 kind: Secret
metadata:
  name: tls
  namespace: default
```

# Ingress
ingress.yaml
```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress
  namespace: default
spec:
  ingressClassName: nginx
  rules:
    - host: rncherwork4020
      http:
        paths:
          - backend:
              service:
                name: httpd
                port:
                  number: 80
            path: /
            pathType: Prefix
  tls:
    - hosts:
        - rncherwork4020
      secretName: tls
```
```
kubectl apply -f ./ingress.yaml
```

アクセスURL：
http://rncherwork4020
https://rncherwork4020
*直接IPでアクセスしてこれないこともチェック
【TypeScript】ESLintとは

# ESLintとは
TypeScriptのESLintは、コード静的解析ツールの1つであり、コードの品質や一貫性を向上させるためのツールです。ESLintは、JavaScriptおよびTypeScriptのコードを解析し、問題や潜在的なバグを見つけ、コーディング規約に適合させるためのルールを適用します。以下に、ESLintの主な特徴を示します：

1. **ルールベースの解析**: ESLintは、設定可能なルールを使用してコードを解析します。これらのルールは、コードスタイル、一貫性、パフォーマンス、セキュリティなど、さまざまな側面に関連しています。

2. **柔軟性とカスタマイズ性**: ESLintの設定は非常に柔軟で、プロジェクトのニーズに合わせてカスタマイズすることができます。また、プラグインを使用してカスタムルールを作成することもできます。

3. **自動化と統合**: ESLintは、多くの統合開発環境（IDE）やコードエディターに統合されており、保存時に自動的にコードを解析することができます。また、コマンドラインツールとしても使用できます。

4. **共同作業の向上**: チーム全体で一貫したコーディング規約を強制することで、コードの品質を向上させ、開発者間での議論やミスの可能性を減らすことができます。

# まとめ
TypeScriptの場合、ESLintを使用してTypeScriptのコードを解析し、JavaScriptのコードと同様に構文エラーや不適切なコードパターンを検出します。TypeScript専用のルールやプラグインもあり、TypeScriptの機能に特化した解析が可能です。これにより、より安全で堅牢なTypeScriptプロジェクトを構築することができます。
OpenFOAM9でswak4Foamビルド

# swak4FoamをOpenFOAM9でビルドしたい。
参考　https://www.cfd-online.com/Forums/openfoam-installation/237600-openfoam-9-compatible-swak4foam.html

OpenFOAM9はビルド済みとして，ついでにflexとbisonも自分でビルドして，インストール済みとする。

```
hg clone http://hg.code.sf.net/p/openfoam-extend/swak4Foam
cd swak4Foam
hg update develop
./AllwmakeAll
```

hg updateが重要みたい。

# swak4Foam
swak4Foamは数式使った初期条件等を設定できるライブラリ。
【TypeScript】Prettierとは

# Prettierとは
TypeScriptのPrettierは、コードフォーマッターツールの1つです。Prettierは、コードを一貫したスタイルで整形し、可読性を向上させることを目的としています。以下にPrettierの主な特徴を示します：

1. **一貫したスタイルの適用**: Prettierは、プロジェクト全体で一貫したコーディングスタイルを確保します。自動的にインデント、セミコロンの追加、行の折り返し、および他のスタイルのルールを適用します。

2. **柔軟性と設定のカスタマイズ**: Prettierは、さまざまな言語やフレームワーク（TypeScript、JavaScript、Reactなど）に対応しており、さまざまな設定をカスタマイズすることができます。ただし、基本的なルールは通常設定の変更が必要ありません。

3. **自動化と統合**: Prettierは、多くの統合開発環境（IDE）やコードエディターに統合されており、保存時に自動的にコードを整形することができます。また、コマンドラインツールとしても使用できます。

4. **プロジェクトの共通基準**: チーム全体でPrettierを使用することで、コードの一貫性を維持し、コーディング規約に関する議論を減らすことができます。

# まとめ
Prettierは、コードの整形に関する多くの煩わしさを解消し、開発者がコードの品質に集中できるようにします。その結果、コードレビューやコラボレーションのプロセスがスムーズになり、コードベース全体の保守性が向上します。
［用語整理］オンプレミスとは

こんにちは！れーあです。
インフラの仕事をしていると「オンプレミス」という用語を聞くことが割とあるのですがそういえばちゃんとどういうものか考えたことなかったなと思ったので本記事を投稿しました。

それではどうぞ。

## オンプレミスとは
オンプレミスについての説明は下記を参照しました。
https://www.ntt.com/bizon/glossary/j-a/on-premises.html

> オンプレミスとは、システムの稼働やインフラの構築に必要となるサーバーやネットワーク機器、あるいはソフトウェアなどを自社で保有し運用するシステムの利用形態です。

要するにシステムやインフラの環境について自社で所有して運用する利用形態のことです。

## クラウドとの違い
それではオンプレミスと対になるようによく耳にするクラウドとの違いはなんでしょうか。

まず調べてみる前に、自分の意見としては下記になります。
オンプレミスは「自社で環境を所有して運用する利用形態」のことでした。
それの反対となると、「環境を所有せず運用する利用形態」のことと予想しています。

では実際はどうでしょうか。
下記を見てみました。

https://www.ntt.com/business/sdpf/knowledge/archive_67.html

> 上述したようにオンプレミスとクラウドのもっとも大きな違いは、「IT機器やリソースを自社で保有・調達するか否か」という点です。

つまりは予想していた通り、環境を自社で用意するかどうかという部分が最も大きな違いのようです。

## ベアメタルとの違い
自社で環境を保有する＝物理環境というイメージを持っていたのですが同じく物理環境のような言葉のイメージがある「ベアメタル」との違いも見ていきたいと思います。

- ベアメタルとは？
下記が分かりやすかったので参照させていただきます。

https://jp.morgenrot.cloud/blog/what-is-bare-metal

> 一つ目は、サーバーの仮想化技術を指します。コンピューターを仮想化するためのソフトであるハイパーバイザーを使用せず、仮想マシンを作成できる仕組みを持ちます。

> もう一つは、サーバーそのものを指します。元々、ベアメタル（bare metal）は「むき出しの金属」を意味する英単語ですが、この場合は「まっさらなサーバー」を意味します。

つまりはサーバの仮想化技術または物理的サーバそのものを意味するようです。

オンプレミスは自社で保有する環境でしたので「オンプレミスを提供するために必要な物理環境」と捉えることができそうです。

## PCはオンプレミスか？
これは疑問だったことでオンプレミスが物理寄りの言葉の意味なら普段使っているノートPCもオンプレミスと言えるのではと思いました。
ただ、これまで記載してきた通り、自社で環境を保有して運用する利用形態ということはオンプレミスであるとはいえなさそうです。

ただ、ノートPCにサーバOSを直接インストールしてサーバとして運用するならオンプレミスと言えるのではと考えております。もっとも、検証機ならともかく商用機でノートPCをサーバにすることはないのでやはり現実的にはオンプレミスと呼ぶことはなさそうです。

## おわりに
オンプレミスが物理的環境と思っていたのですがそれは間違いで、実際には提供形態の種類ということがわかりました。
最近ではクラウドを利用することが多くなってきましたがそれでも物理的サーバや環境は使用するので漏れないように学習していきたいと思います。

## 参考
https://www.ntt.com/bizon/glossary/j-a/on-premises.html

https://www.ntt.com/business/sdpf/knowledge/archive_67.html

https://jp.morgenrot.cloud/blog/what-is-bare-metal
【TypeScript】型システムとは

# 型システムとは
TypeScriptの型システムは、JavaScriptの静的型付けを強化したものであり、開発者がコードの品質を向上させ、バグを事前に検出するのに役立ちます。以下に、型システムの基本的な概念とそれらの機能について説明します：

1\. **型注釈（Type Annotations）**:
TypeScriptでは、変数、関数、オブジェクトなどの要素に型を明示的に指定することができます。これにより、変数や関数の意図した使い方や期待される型を明確にすることができます。例えば：
```typescript
let myNumber: number = 10;
function greet(name: string): void {
    console.log(`Hello, ${name}!`);
}
```

2\. **型推論（Type Inference）**:
TypeScriptは、型注釈が与えられていない場合でも、変数や式の型を推論することができます。これにより、コードをより簡潔に記述することができます。例えば：
```typescript
let myNumber = 10; // TypeScriptが自動的に型をnumberと推論します
```

3\. **コンパイル（Compilation）**:
TypeScriptコードは、TypeScriptコンパイラ（tsc）を使用してJavaScriptに変換されます。コンパイラは、型エラーや警告を検出し、TypeScriptコードをECMAScript（JavaScript）に変換します。コンパイルを実行すると、静的型チェックが行われ、型エラーがある場合はエラーメッセージが表示されます。
```bash
tsc myFile.ts
```

また、プロジェクト全体を監視し、変更があるたびに自動的にコンパイルを実行することもできます。
```bash
tsc --watch
```

# まとめ
TypeScriptの型システムは、これらの機能を組み合わせて、安全で堅牢なコードを書くための手段を提供します。型注釈を使用して明示的に型を指定し、型推論を活用して冗長なコードを削減し、コンパイルを通じて静的な型チェックを実行することで、開発効率を向上させることができます。
UnityとVisualStudioでGitを使用（ローカル）

## 前置き
そこまでGitについて詳しいわけではないが、gitを運用できそうなので記録として残す。

## やりたいこと
Gitを使ってスクリプトをバージョン管理したい。

## 手順
普通にスクリプトをクリックしてVSを開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/9555196e-94f3-0d13-6d5c-e6ed0d973a9b.png)

Gitリポジトリの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/45c37441-6492-a8a7-0fbe-fa84ee81685d.png)

ローカルのみ
ローカルパス Unityのプロジェクトを作ったところ
gitignoreテンプレートにUnity
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/d781d81a-4427-6d00-f43b-48904090e569.png)



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/add6f273-2914-7551-af72-8730a3dd4fd2.png)

作成するとignoreや隠しファイルとして.gitフォルダが作成される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/f0dee202-03b7-dd06-7373-c6dccd0b6278.png)

隠しファイルなので表示するにはWindowsの設定をしてね。

VSに戻って赤いマークがあれば無視されているので
無視の解除設定
git管理するフォルダ右クリック>ソース管理に追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/547adabd-5815-b94b-a65b-4836e4ecc88d.png)

これで変更があった場合Git変更タブに表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/a40aa562-aa0c-8b97-bf8a-9009becfbfcc.png)
タブがなければ表示から出して

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/5ee31359-cc63-1d68-cd71-e187ae1efe43.png)

変更したところ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/80f72c7a-1b5b-7f65-62c5-eb23037129c9.png)

プラスでステージに挙げて

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/556e13a9-c2da-8e48-7c08-1ec72597b61b.png)
コメント入れてコミットで完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/a426c192-7d3d-7805-cb30-7d74fa34beaa.png)

Gitリポジトリから

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/79197a2b-16c5-a747-2759-a4274a232c96.png)

変更履歴が追加された。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/a526f3ae-2231-ba54-9701-1e2a152d593a.png)

ブランチやGitに関する説明はほかのページを参考にして。

以上！
rstatixと仲良くなりたい

# さいしょに
`rstatix`と仲良くなって様々な検定をささっと出来るようになりたいなあ、と思い少しかじった内容をまとめておきます。

# rstatix概要
`rstatix`とはRのライブラリのひとつで、`tidyverse`のデザインと親和性のあるpipe-friendlyな感じに色々と検定する関数を提供します。
導入は単純にcranからインストールすれば良いですし、以下のように`pacman`を使っても良いです。
```r
#パッケージ管理用のpacmanをインストール
if (!require(pacman)) {install.packages("pacman")} 

#必要なライブラリがインストールされていなければインストールしたうえで呼び出し
pacman::p_load(tidyverse, rstatix)
```
# t検定のやりかた

t検定のやりかたを通して`rstatix`の特徴を見ていきます。

### base関数の場合から説明
最初にbase関数でのt検定を見ていきます。base関数では`t.test()`関数を使います。base関数でもパイプ関数を使ってデータを渡すことができますが、したのように`.`で指定する必要があります。なお、パイプ関数も`magrittr`のほうの`%>%`では可能ですが、nativeな`|>`のほうでは指定できません。
```r
#base
ToothGrowth %>%
  t.test(len ~ supp, data = .)
```
で、下ような結果が返ってきます。詳細が書かれているのはありがたいですが、取り扱いが不便です。
```console
	Welch Two Sample t-test

data:  len by supp
t = 1.9153, df = 55.309, p-value = 0.06063
alternative hypothesis: true difference in means between group OJ and group VC is not equal to 0
95 percent confidence interval:
 -0.1710156  7.5710156
sample estimates:
mean in group OJ mean in group VC 
        20.66333         16.96333 
```
### rstatixの場合
`rstatix`では`t_test()`関数を使います。"."のかわりに"_"になっていますね。dplyrの操作と同じ感じで使えるようになっているので、dataを指定する必要はありません。

```r
#rstatix
ToothGrowth %>%
  t_test(len ~ supp)
```
下ような結果が返ってきます。tibbleで返ってきますので、とても取り扱いがしやすいです。
```console
# A tibble: 1 × 8
  .y.   group1 group2    n1    n2 statistic    df      p
* <chr> <chr>  <chr>  <int> <int>     <dbl> <dbl>  <dbl>
1 len   OJ     VC        30    30      1.92  55.3 0.0606
```
また、以下のように3水準のものに対しても可能です。base関数のほうでは、2水準ではないのでだめですとエラーが出ますが、`t_test()`のほうは対応してくれます。
```r
ToothGrowth %>%
  t_test(len ~ dose)
```
結果は次ように出力されます。デフォルトでは総当たりでt検定を行い`p.adj`にholmの方法で調整したp値が示されています。ありがたいですね。指定することでbonferroniなど別の方法による調整に変更可能ですが、そのあたりの違いについてはリンク先を参照してください。
https://www.med.osaka-u.ac.jp/pub/kid/clinicaljournalclub1.html

```r
# A tibble: 3 × 10
  .y.   group1 group2    n1    n2 statistic    df        p    p.adj p.adj.signif
* <chr> <chr>  <chr>  <int> <int>     <dbl> <dbl>    <dbl>    <dbl> <chr>       
1 len   0.5    1         20    20     -6.48  38.0 1.27e- 7 2.54e- 7 ****        
2 len   0.5    2         20    20    -11.8   36.9 4.40e-14 1.32e-13 ****        
3 len   1      2         20    20     -4.90  37.1 1.91e- 5 1.91e- 5 ****    
```

# まとめ
`rstatix`を使ってt検定を行う方法についてみてきました。`rstatix`はpipe-friendlyでささっとコードが書けますし、結果もtibbleで渡されるので非常に取り扱いが楽です。たとえば`group_by()`と組み合わせて検定を行い、p値を小さい順に並べて順番に見ていく、という機械的な取り扱いも簡単にできます。この方法は褒められるようなやり方ではないと思いますが、製造業などで問題がありそうな工程を抽出したいときにひとまず行うには都合がよく、まあまあな正答率を得られたりします（そのときはanovaを主に使いますが、概ね関数の使い方は今回書いたのと同じです）。
以上で`rstatix`の概要をt検定を通して書きましたが、別の関数でハマったところもあるので、今後はその辺も書いていきたいと思います。

# 参考
https://www.med.osaka-u.ac.jp/pub/kid/clinicaljournalclub1.html

https://rpkgs.datanovia.com/rstatix/
【React】ミュータブルとは

# ミュータブルとは
Reactにおける「ミュータブル（mutable）」という用語は、データの変更可能性を示します。Reactコンポーネントの状態（state）やプロップス（props）は、ミュータブルな性質を持っています。これは、これらのデータが直接変更されることができることを意味します。

ミュータブルなデータは、値が変更されると元のデータが直接変更されます。これに対して、イミュータブル（immutable）なデータは、変更不能であり、変更するたびに新しいデータが生成されます。Reactでは、通常、状態やプロップスの変更に対してミュータブルなアプローチが取られますが、これはコンポーネントのパフォーマンスや開発の簡便さに影響を与える場合があります。

一般的に、Reactにおいては、状態やプロップスの変更には注意が必要です。不適切なミュータブルな変更は、コンポーネントの再レンダリングのトリガーとなり、パフォーマンスの低下や予期しないバグの原因となる可能性があります。そのため、状態やプロップスの変更が必要な場合は、適切な方法で行うことが重要です。たとえば、`useState`
フックを使用して状態を更新する場合、新しい状態を生成するためにイミュータブルなアプローチを取ることが推奨されます。