OmniAICreator/Qiita-1.07M huggingface dataset:
03faxのサイトから請求明細を保存する

インボイス制度導入に伴い、使用しているFAXサービス(03fax)の請求明細をダウンロードして保存する作業を自動化したいと思い、Seleniumを使って以下のコードを書きました。

https://03plus.net/03fax/

```03fax.py
from time import sleep

from selenium.webdriver.common.by import By

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService

#Seleniumで使用するドライバのバージョンアップ自動化
from webdriver_manager.chrome import ChromeDriverManager

# Seleniumの初期化
def initialize():
   new_driver = ChromeDriverManager().install()
   service  = ChromeService(executable_path=new_driver)
   
   options = webdriver.ChromeOptions()
   options.add_argument('--headless')
   #保存先の指定
   prefs = {
       "download.default_directory": 'xxxxxxx',
   }
   options.add_experimental_option("prefs", prefs)

   return webdriver.Chrome(service=service, options=options)

URL = 'https://03plus.net/manage/login.php'

driver = initialize()

# ブラウザでurlを開く
driver.get(URL)

#IDの入力
account_id = driver.find_element(By.ID, 'login_id')
account_id.send_keys('xxxxx')
sleep(3)

#IDの入力
account_pw = driver.find_element(By.ID, 'login_passwd')
account_pw.send_keys('xxxxx')
sleep(3)

#ログイン
login = driver.find_element(By.ID, 'login_button')
login.click()
sleep(5)

#請求明細クリック
driver.get('https://03plus.net/manage/payment.php')
sleep(5)

#明細ダウンロードクリック
driver.find_element(By.LINK_TEXT, "ダウンロード").click()
sleep(10)

#ログアウトクリック
driver.find_element(By.LINK_TEXT, "ログアウト").click()
sleep(5)

#確認ボタン押下
from selenium.webdriver.common.alert import Alert
Alert(driver).accept()
sleep(5)

driver.quit()

```

最後まで手こずったのが、保存先を指定するところです。保存先を指定してSeleniumを初期化しているところですが、ブラウザをシークレットモードで起動するオプションを加えると設定が無効になるようです。調べてもこの情報が見当たらなかったので苦戦しました。

```03fax.py
def initialize():
   new_driver = ChromeDriverManager().install()
   service  = ChromeService(executable_path=new_driver)
   
   options = webdriver.ChromeOptions()
   #ブラウザをシークレットモードで起動する
   options.add_argument('--incognito')
   #options.add_argument('--headless')
   prefs = {
       "download.default_directory": 'xxxxxxxx',
   }
   options.add_experimental_option("prefs", prefs)

   return webdriver.Chrome(service=service, options=options)

   ```
###### 参考サイト

https://prtn-life.com/blog/selenium-download

https://note.com/kohaku935/n/n8b1674c1d45f?sub_rt=share_h
EKS CoreDNSアドオンのバージョンアップでPDBが競合した

EKS CoreDNSアドオンを `v1.9.3-eksbuild.5` から `v1.9.3-eksbuild.9`にバージョンアップする際に自前でマニフェスト管理しているPDBと競合するということが起きました。
本記事ではその解決方法を記載します。

# 調査
自前でマニフェスト管理しているPDBでは、`minAvailable: 1`として設定しています。
```yaml:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: coredns
  namespace: kube-system
spec:
  minAvailable: 1
  selector:
    matchLabels:
      k8s-app: kube-dns
```

エラー内容を見ると、minAvailableとmaxUnavailableは同時に設定することはできないという競合エラーが出ていることがわかります。
```bash: エラー内容
$ kustomize build k8s/dev/ | kubectl diff -f -
The PodDisruptionBudget "coredns" is invalid: spec: Invalid value: policy.PodDisruptionBudgetSpec{MinAvailable:(*intstr.IntOrString)(0xc02431df60), Selector:(*v1.LabelSelector)(0xc02431df80), MaxUnavailable:(*intstr.IntOrString)(0xc02431dfa0)}: minAvailable and maxUnavailable cannot be both set
```

公式ドキュメントを確認すると、v1.9.3-eksbuild.5以降およびv1.10.1-eksbuild.2ではPDBがデプロイされるようになり、
v1.9.3-eksbuild.7以降およびv1.10.1-eksbuild.4以降のPDBのデフォルト値は `maxUnavailable: 1` になっているようです。

```yaml
{
    "podDisruptionBudget": {
        "enabled": true,
        "maxUnavailable": 1
        }
}
```

https://docs.aws.amazon.com/eks/latest/userguide/managing-coredns.html

 `v1.9.3-eksbuild.5`の時はアドオン側が`minAvailable: 1`だったので競合していませんでしたが、`v1.9.3-eksbuild.9`ではPDBのデフォルト値が`maxUnavailable: 1`になっているために競合が発生していたとわかりました。

# 解決方法

v1.9.3-eksbuild.7以降およびv1.10.1-eksbuild.4以降では、PodDisruptionBudgetを変更できるようです。

https://docs.aws.amazon.com/eks/latest/userguide/managing-coredns.html

CloudFormationで管理しているアドオンの`ConfigurationValues`にPDB(minAvailable: 1)設定を追加します。
こうすることでアドオン側でデプロイされているPDB設定のデフォルト値(maxUnavailable: 1)を上書きすることができます。
```yaml
  CoreDNS:
    Type: AWS::EKS::Addon
    Properties:
      AddonName: coredns
      AddonVersion: !Ref CoreDNSVersion
      ClusterName: !Ref EKSCluster
      ResolveConflicts: OVERWRITE
      ConfigurationValues: |
        {
          "podDisruptionBudget": {
            "enabled": true,
            "minAvailable": 1
          }
        }
```

マニフェストで用意していたPDBは不要になるため削除可能です。

# まとめ
EKS CoreDNSアドオンを `v1.9.3-eksbuild.5` から `v1.9.3-eksbuild.9`にバージョンアップする際に自前でマニフェスト管理しているPDBと競合したときの解決方法をまとめました。
バージョンアップの際はドキュメントをよく読むことが大切です。
【HackGPT Tokyo2023】ChatGPTを活用したプロダクト開発に挑戦しました

## はじめに ##
Data Science Leagueのエンジニア、yodaです。2023年5月6日から5月7日にかけて開催された「HackGPT Tokyo2023」に参加しました。DSLからも複数のメンバーが参加しました。

https://hackgpt.tokyo/

ハッカソンではAPI使用に関する講義の後、開発を始めるためのKick Offセッションが行われました。ChatGPTのAPIを活用した新しいアイデアを出すために、チーム全員でブレインストーミングを行いました。最終的に、私たちのチームは4コマ漫画自己紹介アプリの開発に集中することを決めました。

開発期間中のBuild Timeでは、チームメンバーが協力してアプリの開発に取り組みました。私たちのアプリは、ユーザーがプロフィール写真やキャプションを入力すると、ChatGPTが自動的にそれに基づいて4コマ漫画を生成する機能を備えていました。

## ChatGPTのAPIを効果的に活用するための重要なポイント ##
ChatGPTのAPIを効果的に活用するためには、以下の重要なポイントに注意する必要がありました。

1. 適切なプロンプトエンジニアリング
ChatGPTは指示されたプロンプトに基づいて応答を生成します。したがって、明確で具体的な指示を与えることが重要です。プロンプトには、ユーザーのプロフィール情報や要求事項を適切に組み込むことで、よりパーソナライズされた結果を得ることができます。私たちのチームは、ユーザーの情報を適切にプロンプトに反映させることで、高品質な漫画の生成に成功しました。
```python
prompt = f"""
  「自己紹介」を基に、起承転結を意識して4コマ漫画を作りたい。「何コマ目か(数字)」と「起、承、転、結でそれぞれ文章(日本語)」と「その場面に該当する画像を出力するプロンプト(English)」を出力してください。
  
  出力はJSON形式のみにしてください。
  
  keyとvalueの対応を以下に示す。
  key:value
  = panels:何コマ目？
  = caption:その場面の説明
  = sceneDescription:その場面の絵を生成するプロンプト
～～～～～～～～
```

2. 高品質なデータセットの収集と整形
ChatGPTのファインチューニングには、高品質なデータセットが必要です。私たちのチームは4コマ漫画のデータセットを収集し、適切な形式に整形する作業に時間を費やしました。データセットの質と量は、モデルの性能に直接影響を与えるため、慎重に選択し、整形する必要があります。特に、特定のトピックやスタイルに合わせた漫画生成を行う場合には、適切なデータセットの収集が重要です。

3. エラーハンドリングと応答品質の向上
ChatGPTのAPIを使用する際には、エラーハンドリングと応答品質の向上にも注意を払う必要があります。ユーザーからの入力によっては、予期しない応答や不適切な結果が生成される場合があります。私たちのチームは、エラーハンドリングの仕組みを実装し、生成された漫画の品質を向上させるためにフィードバックループを活用しました。


## 成果 ##
最終プレゼンテーションでは、私たちのチームが開発した4コマ漫画自己紹介アプリを発表しました。その創造性とエンターテイメント性は他の参加者から高く評価され、最終的には1位を獲得することができました。

##  感想 ##
ChatGPTのAPIを効果的に活用するためには、適切なプロンプトエンジニアリングと高品質なデータセットの収集と整形、エラーハンドリングと応答品質の向上といったポイントに注意する必要があります。これらの要素を適切に組み合わせることで、優れたプロダクトの開発とユーザー満足度の向上を実現できるでしょう。
Blazor WebAssemblyのアプリをGitHub ActionsでビルドしてGitHub Pagesにデプロイ（2023年12月版）

# はじめに

今年の5月頃にBlazor WebAssemblyで開発したマークシートシステム Mark2をGitHub ActionsでビルドしてGitHub Pagesにデプロイするようにしました。その時のメモが以下になります。

https://qiita.com/kaorumori/items/3d478d037237bb4c1bcb

それから半年ほどが過ぎ、Mark2を.NET 8に対応させました。最初は`dotnet-version`を`8.0.x`に変更しただけだったのですが、`uses`で指定しているアクションもアップデートがあるかなと調べてみました。

# アクションのアップデートを確認

以下のリポジトリを確認すると、2023年5月時点で作成したMark2のGitHub Actionsのアクションは1つずつメジャーバージョンが上がっていました。

https://github.com/actions/checkout

https://github.com/actions/configure-pages

https://github.com/actions/setup-dotnet

https://github.com/actions/upload-pages-artifact

https://github.com/actions/deploy-pages

# アクションを更新

アクションのメジャーバージョンアップを反映して、Mark2のGitHub Actionsのアクションを以下のように更新しました。

```yaml:.github/workflows/github-pages.yml
name: Deploy to GitHub Pages

on:
  push:
    branches: ["main"]

  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Setup Pages
        uses: actions/configure-pages@v4
      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: 8.0.x
      - name: Install wasm-tools
        run: dotnet workload install wasm-tools
      - name: Publish
        run: dotnet publish Mark2.csproj -p:GHPages=true -p:GHPagesBase=/ -c:Release -o:publish
      - name: Upload Pages Artifact
        uses: actions/upload-pages-artifact@v2
        with:
          path: "publish/wwwroot"
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v3
```

# ビルド結果

エラーは発生することなくデプロイが完了しました。

Mark2はAOTコンパイルを有効にしているため、通常のアプリよりもビルド時間が長くなっています。アクションをアップデートする前のビルド時間は17分26秒で、今回の作業でアクションをアップデートしたビルド時間は13分15秒となって、ビルド時間が短縮されていました。ビルド時間はいろいろな条件で変動するので、単発の実行時間の比較は妥当ではないと思いますが、ご参考まで。

![runs.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2238166/1405c459-3e15-93d5-e312-fbd3bd46df59.jpeg)

# アクションの更新の確認を自動化

今回は手動でアクションの更新を確認して、その更新を反映させました。アクションの更新確認を自動化する方法はあるだろうと思って調べたら、Dependabotでそれができるようです。

https://docs.github.com/ja/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot

Dependabotの設定ファイルを作成しました。

```yaml:.github/dependabot.yml
# Set update schedule for GitHub Actions

version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
```

# おわりに

今回の作業ではDependabotを利用してGitHub Actionsのアクションの更新確認を自動化する設定をしました。アクションの更新確認は普段の開発では意識しづらい部分でもあるので、それを自動化することができてよかったです。
Crystalの「コンパイラ」のドキュメントを生成する

## はじめに

Crystal言語のコンパイラのソースコードを読んでみたいと思った人はいますか？
私は読んでみたいです（理解できるかどうかは別にして）

しかし、普通にドキュメントを生成しようとすると、コンパイラを構成するモジュールやクラスはドキュメントにならないようになっています。そこでどうやってコンパイラのドキュメントを生成すればいいか調べました。

## 結論

```sh
git clone https://github.com/crystal-lang/crystal
cd crystal
make docs DOCS_OPTIONS=src/compiler/crystal.cr
```

## ドキュメントの生成

まずは普通のCrystalのドキュメントを生成してみましょう。

```sh
git clone https://github.com/crystal-lang/crystal
cd crystal
make docs
```

これを実行すると `docs` ディレクトリが生成されて、普通のドキュメントが生成されます。しかし、これだとコンパイラのドキュメントは生成されません。

Makefileの中を覗いてみると `make docs` では

```makefile
.PHONY: docs
docs: ## Generate standard library documentation
        $(call check_llvm_config)
        ./bin/crystal docs src/docs_main.cr $(DOCS_OPTIONS) --project-name=Crystal --project-version=$(CRYSTAL_VERSION) --source-refname=$(CRYSTAL_CONFIG_BUILD_COMMIT)
```

上記のように `src/docs_main.cr` を呼び出していることがわかります。

そこで、`docs_main.cr` に `require "./compiler/requires.cr` を追加します。

```diff
diff --git a/src/docs_main.cr b/src/docs_main.cr
index 661163677..1f7cbb04b 100644
--- a/src/docs_main.cr
+++ b/src/docs_main.cr
@@ -5,6 +5,7 @@
 require "./annotations"
 require "./big"
 require "./compiler/crystal/macros"
+require "./compiler/requires.cr"
 require "./compress/**"
 require "./crypto/**"
 require "./crystal/syntax_highlighter/*"
```

これで `make docs` すればコンパイラのドキュメントも生成してくれるようになります。

やったね！

## 追記

でもよく見ると、環境変数で次のようにした方が簡単です。straight-shoota さんに教えてもらいました。

```sh
git clone https://github.com/crystal-lang/crystal
cd crystal
make docs DOCS_OPTIONS=src/compiler/crystal.cr
```

この記事は以上です。

## 参考

- [Crystal Forum - How to generate documentation for Crystal’s compiler?](https://forum.crystal-lang.org/t/how-to-generate-documentation-for-crystals-compiler/6208/7)
zodで、あるオブジェクトのkeyだけのユニオンのスキーマがほしい

githubのdisucussionsで見つけました。
https://github.com/colinhacks/zod/discussions/839
```ts
export const zodEnumFromObjKeys = <K extends string>(
	obj: Record<K, any>,
): z.ZodEnum<[K, ...K[]]> => {
	const [firstKey, ...otherKeys] = Object.keys(obj) as K[];
	if (typeof firstKey !== "string") throw new Error("key is not string");
	return z.enum([firstKey, ...otherKeys]);
};
```
これは便利だ


例
```ts
const user = {
    id: 2
    name: "TANAKA"
} as const
```
このときにidかnameになるユニオン型（というかenmuだけど)が取得できます。
関数の引数で、必ずあるオブジェクトのkeyにしたいときなどに使えます。

ちなみにTypeScriptの型なら```keyof typeof```で一発です。

```ts
type User = keyof typeof user;
```
メールの誤送信防止と生成AIを組み合わせられないだろうか

## はじめに

私は中小企業の情報システム部に勤務している社内SEです。
主な業務は

* クラウド基盤（AWS・OCI）の設計・構築・運用
* サーバー（Windows・Linux）の設計・構築・運用
* ネットワークの設計・運用
* 社内システムの運用

です。クライアントおよびヘルプデスクもしますが他のメンバーが担当となります。

## 記事

私はメールが苦手です。技術的な内容の問い合わせ等は問題ないのですがビジネスメールが苦手です。最近は生成AIに添削を依頼してもらっているのですが、誤配信防止機能の中に添削機能を入れれないかと考えました。

メール送信時に誤配信防止に添削機能が組み込まれており、送信時に勝手にきれいなビジネスメールに書き換えてくれるのです。さらに社外秘とか問題になりそうなものもAIが判断して止めてくれたらいいのではと考えました。

私は作る技術はありませんので誰か作ってください(笑)。
JPA内部プーリング利用際、閉じられたResultSet、再利用でエラー

```
JPAにて「EclipseLink」使用、「内部プーリング」使用際、エラー出たことをメモする
現象：「閉じられたResultSet、再利用でエラー」

エラー際のJPAプロパティ設定
<property name="exlipselink.jdbc.connector" value="Connectorパス">

対応方法：
⇨上記プロパティ設定削除
　　外部プーリング使用
```
W3CDTF形式のStringをDateに変換する

W3CDTF形式のStringをDateに変換します。

# W3CDTF形式について

W3CDTF（World Wide Web Consortium Date and Time Formats）は、World Wide Web Consortium（W3C）が定義した日付と時刻のフォーマットに関する標準です。

https://www.w3.org/TR/NOTE-datetime

以下の形式があります。

- Year:
    - `YYYY (eg 1997)`
- Year and month:
    - `YYYY-MM (eg 1997-07)`
- Complete date:
    - `YYYY-MM-DD (eg 1997-07-16)`
- Complete date plus hours and minutes:
    - `YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)`
- Complete date plus hours, minutes and seconds:
    - `YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)`
- Complete date plus hours, minutes, seconds and a decimal fraction of a second
    - `YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)`

# コード
上記の形式いずれが来ても変換できるようなフォーマッタを作成しようと思います。
基本的には `ISO8601DateFormatter` で全て対応ができます。

https://developer.apple.com/documentation/foundation/iso8601dateformatter

ただ、 *Complete date plus hours and minutes* に関しては ISO8601DateFormatterでの対応ができなさそうなので、Date.ParseStrategyでの対応を行います。

以下はコードです。
ただし、*Complete date* のような、タイムゾーンがテキスト中に表現できていない形式の場合、GMTのDateが返されるので、ISO8601DateFormatterのtimeZoneに明示的に目的のtimeZoneを与える必要があります。

```swift
struct W3cDateFormatter {
    func callAsFunction(string: String) -> Date? {
        let iso8601DateFormatter = ISO8601DateFormatter()
        
        // YYYY-MM-DDThh:mm:ss.sTZD
        iso8601DateFormatter.formatOptions = [.withFullDate, .withFullTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withColonSeparatorInTimeZone, .withFractionalSeconds]
        if let date = iso8601DateFormatter.date(from: string) {
            return date
        }
        
        // YYYY-MM-DDThh:mm:ssTZD
        iso8601DateFormatter.formatOptions = [.withInternetDateTime]
        if let date = iso8601DateFormatter.date(from: string) {
            return date
        }

        // YYYY-MM-DDThh:mmTZD
        let strategy = Date.ParseStrategy(format: "\(year: .defaultDigits)-\(month: .twoDigits)-\(day: .twoDigits)T\(hour: .twoDigits(clock: .twentyFourHour, hourCycle: .zeroBased)):\(minute: .twoDigits)\(timeZone: .iso8601(.short))",
                           timeZone: .current)
        if let date = try? Date(string, strategy: strategy) {
            return date
        }

        // YYYY-MM-DD
        iso8601DateFormatter.formatOptions = [.withFullDate, .withDashSeparatorInDate]
        if let date = iso8601DateFormatter.date(from: string) {
            return date
        }

        // YYYY-MM
        iso8601DateFormatter.formatOptions = [.withYear, .withMonth, .withDashSeparatorInDate]
        if let date = iso8601DateFormatter.date(from: string) {
            return date
        }

        // YYYY
        iso8601DateFormatter.formatOptions = [.withYear, .withDashSeparatorInDate]
        return iso8601DateFormatter.date(from: string)
    }
}

```
M5StackでLoRaのデータを覗いてみる

この記事は、2023年の [M5Stack アドベントカレンダー](https://qiita.com/advent-calendar/2023/m5stack) の 11日目の記事です。

# はじめに

前回までにM5Stackを使ってゲートウェイ経由でAWS IoT Core for Wirelessに接続することができました。今回は、SenseCAP T1000が送っているデータをM5Stackで覗いてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/784f1e78-b85e-fd6a-85ec-703af6a33347.png)

# 受信概要

前回同様、Grove-Wio-E5を使用します。このデバイスでは周波数を指定して1つのチャンネルを受信することができます。LoRaWANの仕様では、ゲートウェイは2つのチャンネルでデバイスから送られる電波を待機するようになっており、SenseCAP T1000はゲートウェイ向けに2つのチャンネルでランダムに（実際にはチャンネルの空きを判断しながら）送信します。今回はそのうちの片方を決め打ちで受信するようにします。

受信したデータはLoRaWANの仕様で暗号化されています。これを [util-lorawan-packets](https://github.com/lobaro/util-lorawan-packets) を使って復号化します。オリジナルではダウンリンクのみ対応していたので、アップリンクデータも対応するようにして利用させていただきました。LoRa Allianceで公開されている仕様を参考にしました。

また、以下のサイトではオンラインでパケットの内容を確認できるので、データを受信した後の処理の確認など、非常に役立ちます。
[LoRaWAN packet decoder](https://lorawan-packet-decoder-0ta6puiniaut.runkit.sh/?data=40111111110001000175CD660A58A64C1C6815A92D1ECF15&nwkskey=11111111111111111111111111111111&appskey=11111111111111111111111111111111)

SenseCAP T1000が送信するデータは、こちらの [Tracker T1000 ユーザーガイド](https://files.seeedstudio.com/products/SenseCAP/T1000_Tracker/SenseCAP_Tracker_T1000-AB_User_Guide_v1.2.pdf) に記載されています。

指定した間隔（1分間）などで、ID=0x06 の GNSS Location and Sensor Packet が送信されていることが確認できます。たまに,ユーザーガイドに記載されていない ID=0x11 のデータが送信されます。こちらはデータを見ると ID=0x06 に位置情報が含まれていないような内容なので、GPSが取得できない場合のイベント情報なのかもしれません。




# ソースコード

ソースコードは [こちら](https://github.com/fukuen/M5Stack-LoRa-Viewer) をご覧ください。

# 実行例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/cd3587ca-7857-9355-1f4f-80a02809711d.png)


このようなログが出力されます。

```
+TEST: LEN:35, RSSI:-46, SNR:10
+TEST: RX "8000000000C04D0505325DE8A00787ECBD578FCB3E3DD377A78ABA739F172211221122"

LoRa| LoRaWAN Packet (Uplink)
LoRa| --------------
LoRa| MIC: 11221122
LoRa| MHDR: CONFIRMED_DATA_UP v0
LoRa| BODY:
LoRa| - mac.port: 5
LoRa| - mac.payloadLength: 22
LoRa| - mac.FCnt16: 1357
LoRa| - mac.DevAddr: 00000000
LoRa| - FCtrl: ADR 1, ADRACKReq 1, ACK 0, ClassB 0, FOptsLen 0
LoRa| PAYLOAD: 06 00 00 00 00 12 34 56 78 90 12 34 56 78 90 12 10 00 ba 00 00 39

id: 06
eventStatus: 000000
motionSegmentNumber: 0
utcTime: 1701656377
longitude: 139.000000
latitude: 35.000000
temperature: 18.6
light: 0
batteryLevel: 57

+LOG: DEBUG  8459517 TEST    TIME, 8459498, 8000000000C04D0505325DE8A00787ECBD578FCB3E3DD377A78ABA739F172211221122, -46, 10, 69310563, 322, 3150
+LOG: DEBUG  8459518 LORA    RX, 8000000000C04D0505325DE8A00787ECBD578FCB3E3DD377A78ABA739F172211221122, -46, 10
```


# さいごに

T1000が送信する、位置情報、気温、などをM5Stackで簡単に確認できるようになりました。

もしAmazon Sidewalkが日本に上陸することがあれば、この仕組みでテストできるかも？
https://sidewalk.amazon/testkit
本番環境からテストデータを作成してみた話

# はじめに
テストデータ作成に迷える後輩を救いたかった

# 問題
負荷検証するにあたり本番相当のデータで検証をしたかった。
検証用環境としても個人情報もりもりのデータをマスクせずに登録はしたくない。

# 解決方法
A5SQLというツールの取得データをInsert文に変換する機能を使い、取得結果をマスクするようなSQLを実行する。
SQLのCASEとCONCATを組み合わせて個人情報のカラムを置換して取得する。

~~~sql
select
    a.id
    , case 
        when a.email is not null 
            then concat('kensyo_', a.id, '@domain.com') 
        end as email
    , a.reset_password_token
    ...
~~~


# おわりに
caseを利用することで取得されたカラムに対して条件付け（データがあれば・・・等）が可能になる。
concatを利用することで対象のカラムを書き換えることができるため、個人情報を含むカラムを特定の文字列＋ID等に置換することができる。

一つ欠点を上げるとするとテーブル内のカラム数が増えた時に全カラム記載しないといけないのでアワワワワとなる。


# 参考
https://dev.mysql.com/doc/refman/8.0/ja/case.html
https://www.javadrive.jp/mysql/function/index35.html
https://a5m2.mmatsubara.com/
【12日目】OSS連携してみたい！(9)PythonRoboticsのpure pursuitを調査する

この記事は筆者オンリーの[Advent Calendar 2023](https://qiita.com/advent-calendar/2023/aichallenge_racing_for_mas)11日目の記事です。  

# 前回までのあらすじ
PythonRoboticsのpure pursuitを移植するためにAutowareの処理を調査しました。

# 今回やること
PythonRoboticsのpure pursuitの処理について調査してみたいと思います。

# pursuitの各処理について
PythonRoboticsのpursuitのソースコードは[こちら](https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathTracking/pure_pursuit/pure_pursuit.py)になります。
また、アルゴリズムの概要は[こちら](https://myenigma.hatenablog.com/entry/2017/06/05/111007)で紹介されています。



# Autowareのpursuitの構成
構成としてはクラス、関数があるようです。
クラスとしては
・Stateクラス
・Statesクラス
・TargetCourseクラス
があるようです。
Stateクラスは
・__init__メソッド
・updateメソッド
・calc_distanceメソッド
があるようです。
Statesクラスは
・__init__メソッド
・appendメソッド
があるようです。
また関数として
・proportional_control関数
・pure_pursuit_steer_control関数
があるようです
proportional_control関数では指定されたスピードと現在のスピードの差分を係数でかけて返しているようです。
pure_pursuit_steer_control関数では内部で現状態との最小距離の箇所を選択し、Trajectoryのインデックスと先の距離を算出しインデックスと曲率(？)を返しているようです。
上記のproportional_control関数とpure_pursuit_steer_control関数を用いてstateの更新を行った上でstatesに情報が付加されていくようです。

# まとめ
ちょっとはpure pursuitわかってきた気がする。
でもOSS連携できる気がしない。。。
vscode で jupyter notebook のカーネル選択ができなくなった時の対処方法

# この記事は何？
vscode に jupyter 拡張機能をインストールして ipynbファイルを開き実行しようとしたところ、カーネルの選択ができず動作させることができない現象に遭遇し時間を奪われたので、その対処法をメモしておきます。

# 現象
vscode で ipynbファイルを開くと、右上から使用するカーネルを選択してセルを実行できるようになるはずですが、カーネルに選択肢が何も表示されず、選択できない状態になりました。pytnon環境は問題なくインストールされている状態です。

![スクリーンショット 2023-12-08 10.14.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164843/4d557792-eb04-483c-b0d2-9d9238cfe918.png)

# 対応方法
以下を参考に、jupyter拡張機能のバージョンを一つ前のものに下げたところ、選択できるようになりました。
https://github.com/microsoft/vscode-jupyter/issues/10043#issuecomment-1465692694

# まとめ
急に使えなくなったので困りました。
誰かの役に立てば幸いです。
Eclipse,RADでソース行数を統計方法

```
①ctrl＋H を使い、「ファイル検索」で「¥n」を検索し、全ての行をとうけいする
②上記と同じで「^(¥s*)¥n」を検索し、空行を統計する
空行ないソース行数＝①ー②

```
"429 Too Many Requests - Server message: toomanyrequests: You have reached your pull rate limit."になったとき

## 問題

Dockerのイメージをpullしようとして次のような429エラーに遭遇したときの話。

```terminal
failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to create LLB definition: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/mysql/manifests/sha256:c86dfd69b3d1437e5d192447f0bdc57407d48bd379b97a453e11d72b97962e3b: 429 Too Many Requests - Server message: toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit
```

## 解決法

イメージの取得元をECRからにする。

具体的には、[Amazon ECR Public Gallery](https://gallery.ecr.aws/docker?page=1)から同じイメージを探して、そのイメージURIを取得。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144277/9f070acf-98cb-edea-9ae2-9a0a2e8d5f6f.png)

あるいは元のイメージ名の先頭に`public.ecr.aws/docker/library/`をつけるだけでも解決するはず。

なおこの解決方法はAmazon ECRにアップされているオフィシャルのイメージのみ。またそれぞれのイメージはまったく同じものです（下記参照）。

```
mysql                                 8.0.32    21978c3803ca   8 months ago     544MB
public.ecr.aws/docker/library/mysql   8.0.32    21978c3803ca   8 months ago     544MB
```

## 原因

Dockerイメージのpullにおける429エラーは、時間あたりのpullの回数制限に引っかかっていることを示している。[^1]

ローカル上の実行では引っかかることはないだろうが、IPアドレス単位の制限のためAWS環境だと引っかかることが多い。

そのため回数制限と関係ないAmazon ECRのECR Publicから取得することで解決する。

## 参照

[Docker オフィシャルイメージが ECR Public で利用可能になりました #reinvent | DevelopersIO](https://dev.classmethod.jp/articles/docker-official-images-on-ecr/)

[^1]: https://docs.docker.com/docker-hub/download-rate-limit/
画面フローのデータテーブル

[スクリーンフローのまとめに戻る](https://qiita.com/Keiji_otsubo/items/228717557f9a72b92a36)




+ [Datatableの使い方](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007RK0oe)
+ [画面フローのデータテーブル検索](https://qiita.com/Keiji_otsubo/items/c52e2a420f5b9fe585d8)

:::note
You need to check Clip text instead of Wrap text

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/efb59a32-f1c1-9f13-764b-ae2633b4e055.png)
:::

+ [Embed VF rendered as a pdf in a screen flow](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007H98GW)

:::note
Please check this article.

https://www.infallibletechie.com/2023/01/how-to-display-salesforce-visualforce-rendered-as-pdf-in-flow.html
:::

+ [テーブルにあるレコードの件数の数え方](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007RfLVW)

:::note
https://salesforce.stackexchange.com/questions/401476/how-to-evaluate-if-a-row-was-selected-from-a-flow-data-table-component
:::

+ [取引先（Account）に商談(Opportuniry)の関連リストをデータテーブルを使用して表示したいのですが、すべてテキスト表示になってしまいます。HYPERLINKが使えない](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007T56kQ)

:::note
以下の制約があるみたいです。

日付項目のフォーマットも数式項目の中で行った方が早いかもしれません。

参照項目または主従関係項目をデータテーブルに含めると、その項目値はテーブルに表示されません。たとえば、データテーブルでは関連レコードの [名前] 項目を表示できません。関連レコードの項目値を表示するには、オブジェクトの数式項目を使用します。オブジェクトの数式項目を使用して、関連レコード項目にリンクすることもできます。


例:

```
HYPERLINK( "/" & CASESAFEID(Id), Related_Record__r.Name, "_self" )
```

https://help.salesforce.com/s/articleView?id=sf.flow_ref_elements_screencmp_data_table.htm&type=5
:::

+ [フローでのデータテーブルコンポーネントの値の保存：前の画面に戻ったあともチェックボックスで選択された行を保持したい](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000KCJiq)

:::note
フローの API バージョンを 59 以降に設定したら、チェックボックスが保持されるようになりました。 

（12月に作成したフローを新しいバージョンとして更新していましたが 

最初のフロー作成時はAPIVer58で、新しいバージョンとしてフローを更新して使っていると自動ではAPIVerが更新されないようでした。 
:::

+ [Flow: DataTable Selection gives error "Hmm, that didn't work"](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PWCX7)


# 既知の問題

+ [画面フローのデータテーブルが縮小されて表示される現象が多発しています。「更新」ボタンを押下することで解決できます](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX000000Nl2q)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/8f8e2969-da38-ab6e-3b6c-2914efc6742b.png)

:::note
Salesforce社にも問合せをしたのですが、既知の問題で以下にあたるのではないかと連絡を受けました。

[Compressed Flowruntime Data Table fails | Known Issues](https://issues.salesforce.com/issue/a028c00000iwiY8AAI/compressed-flowruntime-data-table-fails-to-fully-re-expand-on-page-resize)
:::
dojo で開発したプロダクトを育て続ける

## はじめに

この記事は [DENSO アドベントカレンダー 2023](https://qiita.com/advent-calendar/2023/denso) の8日目の記事です。

私達の部署では、DENSO グループ社員向けに dojo という研修を不定期で開催しています。今回は、私自身が dojo に参加して開発したプロダクトを、有志で継続開発している話を紹介します。

dojo に関して詳しく知りたい方はこちらの紹介記事を参照してください。

https://qiita.com/takumiinoue/items/98167e550f8885d76e43

## プロダクト概要

エレベータピッチを掲載しておきます。

```
(機会)
リモート講演・オンラインセミナーにおけるコミュニケーション活性化を望んでいる

(ユーザー)
熟練講演者と前向きな聴講者にとって

(プロダクト名)
SOE.Lは

(ジャンル)
コミュニケーションサポートアプリであり、

(主機能)
リアルタイムに会場の反応や盛り上がりを可視化でき、

(ベンチマーク)
Slide, Zoom とは異なり

(ほか特徴)
以下の特徴を持っている。

- 聴講者の反応をリアルタイムに楽しく表示・共有できる。
- 匿名かつ手軽で反応できる。たくさん反応したくなる。
- 講演者が反応を良くするための仕組みを持つ。(サクラ機能)
```

こんな挙動をします。

![soel.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1134812/39aee24f-07b8-fe8d-4861-d4b034bc994c.gif)

## 社内の反応

dojo の期間が終わり、社内向けに私達の部署で開催している研修・イベントで SOE.L を使っていると、意外な反応がありました。

- これまでオンライン会議でコミュニケーションに使っていた他のチャットツールよりも多くの投稿が寄せられた(感覚値)
- 私達の部署のイベントで SOE.L を知った別の部署の方々が、社内向けの各種イベントで SOE.L を使ってくれた

こういった反応があったため、継続して SOE.L は社内では使える状態にしておき、元々開発に携わった dojo 同期とともに有志で開発・運用を継続していきました。

## ユーザーからの意見

その様な経緯で SOE.L を各種イベントで使っているうちに、色々な意見が寄せられました。

- 画像を投稿できる様にならないか
- 共有したい Web ページの URL を投稿すると文字数制限で見切れてしまう
- 講演者側で質問回答の管理をしやすくできないか
- etc.

実際使っていただけるユーザーがいて、意見が寄せられることは非常にありがたかったです。

## 追加する機能の判断軸

ただ、寄せられた意見全てを開発するのは有志では無理なので、以下の判断軸を有志メンバーでは共有していました。

- SOE.L のコンセプトとして重要視していた”気軽さ”を損なわないこと
- 有志開発メンバー自身も実体験として必要だと感じたこと

## スレッド機能の開発

有志メンバーで実際に SOE.L を社内向けのイベントで使った際に、”どの質問には回答していて、どの質問が回答できていないかの管理が難しい”という課題を感じていたため、この課題を解決できる機能として既存の SOE.L のシンプルな UI を踏襲したスレッド機能を作ることにしました。

実際に開発した機能の挙動はこの様になりました。

![SOEL.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1134812/3fd81bb7-37a0-e1f5-8e48-bb5214a4b5c6.gif)

提案してくれた有志メンバーからも満足の声が上がっています。

## 終わりに

dojo の延長線上の開発ですが、良い活動ができていると個人的には感じています。

- 使い続けてくれるユーザーがいること
- ユーザーから改善の意見が集まってくること
- 改善の意見の中からプロダクトの方針にマッチする要望を選別して開発できたこと

この記事を見て SOE.L に興味を持ってくださる社内外の方いらっしゃれば記事へのコメント等でリアクションいただけると嬉しいです。
「サーバーのタイムゾーンを変えて、クライアントのタイムゾーンはそのまま」を開発環境で再現したい

本番環境では、サーバー、クライアントがそれぞれ

- サーバー: UTC
- クライアント(ブラウザ): JST

のようなタイムゾーンとなっており、デバッグのために開発環境で同じ状況を再現したいことが時々発生します。

SSRをするときに、 `process.env.TZ` のようにタイムゾーンを指定できたらいいのですが、 mini_racer (V8) ではホストシステムのタイムゾーンを参照してしまうようで、開発環境(Mac)で再現するにはMacのタイムゾーンを変更する必要があります。
しかし、同時にブラウザのタイムゾーンもつられて同じタイムゾーンを参照してしまいます。

## 方法

1. PCのタイムゾーンをUTCに設定する
2. ブラウザのタイムゾーンをJSTに書き換える

### 1. PCのタイムゾーンをUTCに設定する

Macの設定から時間帯をUTCに変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/5d584980-2879-f2a4-df1d-3db5986836d2.png)

### 2. ブラウザのタイムゾーンをJSTに書き換える

Chrome開発者ツールでタイムゾーンを変更します。
Macなら `cmd + Shift + P`でパネルを表示して、 `sensors` と入力します。
その後Locationを 「Tokyo」 に変更します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/59395d7f-6eb1-d3c2-2f6d-2b77c9ab434d.png)

以下のようにタイムゾーンが変わっていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/c5ee2d36-de2e-b9ba-976d-ade9690307e8.png)
ブロックチェーンを利用した認証あれこれ

# はじめに
今年開催されたIVS京都2023ではNFT名刺を作って現地で配りました。
そのNFTではお会いしたことの証明として、後日そのNFTの所有を検証できるような仕組みを実装していました。残念ながらその仕組みを説明する機会は一度も訪れませんでしたが、その時にNFTを持っている証明として「認証」についてあれこれ考えたので共有させていただきます。

### 認証とは
ブロックチェーンでは、自分が秘密鍵を知っていることをさまざまな方法で証明して相手に伝えることができます。もちろん秘密鍵を誰にも教えないことが前提になります。Webサービスにおけるパスワードと同様に、事前の本人確認時に示し合わせたキーワードを持っておけば、そのサービスを利用したいときにはそのパスワードを伝えるだけで本人確認完了となります。秘密鍵とパスワードの違いは、パスワードはそのまま相手に伝えないといけませんが、秘密鍵の場合はその鍵は教える必要がなく、公開鍵という別の鍵で本人確認ができるためセキュリティが高くなります。一方で秘密鍵はパスワードのように「変更」することができないので管理する難しさが出てきます。


# 証明方法

### 1.ウォレットへのログインで証明する

ウォレットへログインして自分しか見ることのできない情報を提示することで認証します。

注意点：
検証する人がウォレットを信頼していることが必要になります。
ログインの必要が無いエクスプローラーではなりすましで提示できるので認証には不適切です。

### 2.検証者が提示したデータへの署名で証明する

検証する人が提示したキーワード（PIN番号などのワンタイムトークン）を秘密鍵で署名することで認証します。

注意点：
認証に使用した署名データは他人によって再利用されないように適切に無効化する必要があります。

### 3.トークンの所有で証明する

トークンを操作できることを提示することで認証します。

##### 3-1.検証者にトークンを送信して認証
注意点：
申請者の手数料負担が必要です。また、認証のたびにトークンが減ってしまいます。

##### 3-2.検証する人から申請者のトークンを回収して認証

注意点：
検証者の手数料負担が必要です。認証のたびに申請者のトークンが減ってしまいます。
発行者が回収できるような設定のトークンを準備しておく必要があります。
申請者がなりすましで他人のアドレスを提示していないか確認する必要があります。
（つまり、厳密にはこの方法は秘密鍵を所有していることの証明にはなりません）

##### 3-3.検証する人にトークンを送信し、同じトランザクション内で申請者にトークンを返送

注意点：
検証者、申請者双方の署名が必要です。
署名が集まるまでトランザクションをロックしておく仕組みがブロックチェーン上に必要です。

### 4.その他、トランザクションの記録事実で認証

トークンの移動させずとも、メタデータへの記録、ネームスペースのレンタル、トークンのロックなどのトランザクションを実行してもらい、その成功を監視することで認証することができます。

注意点：
厳密な検証にはマークルパトリシアツリーなどの使用が必要です。

# まとめ
以上になります。
ちなみにNFT名刺で実装したのは3-3の方法になります。この方法だとNFT所有者はトークンを減らさずにブロックチェーンの監査機能によって所有を証明することができます。実装にはSymbolブロックチェーンのアグリゲートトランザクションを使用しました。
他にもいい認証の方法があればぜひ教えてください。
【即修了】弁当テーブルを例に正規化を最速で説明する

# 正規化とは
DB 設計にて定義された **テーブル（エンティティ）** をルールに沿って **分割する** こと

# 嬉しいこと
- 「こういうふうにデータを組み合わせて出力したい」、「新しくカラムを作りたい」みたいな将来的なシステムの変更に強くなる（**拡張性**）
- 何度も出現するデータをグループ化し、別テーブルにまとめることで領域の節約になる。そしてそのデータの更新コストも減る（**冗長性**）

# 予備知識
- 主キーとは、属するレコードの識別子である
- 外部キーとは、参照したい他テーブルのレコードの主キーである
- 部分関数従属とは、主キーが複数ある時に全ての主キーが分からずとも、いづれかの主キーが分かればあるカラムの値が特定できる性質のこと。部分的な関数なので、一部にXならばYみたいな関係があればって感じですね。
- 推移的関数従属とは、主キーではないが、その値が分かると他のカラムの値を特定できてしまう性質のこと。つまり、Xが分かるとY,Zが分かるが、そもそもYが分かるとZが分かってしまうって感じですね。

# 正規化（第1~第3）
**第1正規形**
1. セル内に複数のデータがあれば、レコードを分割し1つのセルに対し1つの値が入るようにする。
2. 分割されたデータがあれば、最低限の主キーを設ける（個人的に）

元テーブル
|弁当番号<br>(主キー)|弁当名|材料|おかず|原産地番号|原産地|
|----|----|----|----|----|----|
|1|唐揚げ弁当|鳥もも肉<br>大根|唐揚げ<br>たくあん|1<br>2|宮崎県<br>北海道|
|2|鮭弁当|鮭<br>卵<br>大根|焼き鮭<br>卵焼き<br>すりおろし大根|2<br>3<br>4|北海道<br>茨城県<br>千葉県|

正規化後
|弁当番号<br>(主キー)|弁当名|材料番号<br>(主キー)|材料|おかず|原産地番号|原産地|
|----|----|----|----|----|----|----|
|1|唐揚げ弁当|1|鳥もも肉|唐揚げ|1|宮崎県|
|1|唐揚げ弁当|2|大根|たくあん|2|北海道|
|2|鮭弁当|3|鮭|焼き鮭|2|北海道|
|2|鮭弁当|4|卵|卵焼き|3|茨城県|
|2|鮭弁当|2|大根|すりおろし大根|4|千葉県|

セルの複数データを分割し、材料番号を主キーとして新しく設けました。
これで弁当番号と材料番号がわかれば、おかずや原産地など全て把握することができます。

**第2正規形**
[部分関数従属](#予備知識)のデータを他テーブルに分割する

今回、弁当番号と材料番号の２つの主キーがありますが、弁当番号が分かれば弁当名が分かりますし、材料番号が分かれば材料が分かると思います。
そのため、部分関数従属になっているので、これらをテーブル分割します。

弁当テーブル

|弁当番号<br>(主キー)|弁当名|
|----|----|
|1|唐揚げ弁当|
|2|鮭弁当|

材料テーブル
|材料番号<br>(主キー)|材料|
|----|----|
|1|鳥もも肉|
|2|大根|
|3|鮭|
|4|卵|

元テーブル
|弁当番号<br>(主キー・外部キー)|材料番号<br>(主キー・外部キー)|おかず|原産地番号|原産地|
|----|----|----|----|----|
|1|1|唐揚げ|1|宮崎県|
|1|2|たくあん|2|北海道|
|2|3|焼き鮭|2|北海道|
|2|4|卵焼き|3|茨城県|
|2|2|すりおろし大根|4|千葉県|

重複がかなり消えてスッキリしましたね。

**第3正規形**
[推移的関数従属](#予備知識)のデータを他テーブルに分割する。（主キー以外に主キーになっていそうなものを探す）

今回、弁当番号と材料番号の２つの主キーから、おかず・原産地番号・原産地が特定できます。
ただ、その中でも原産地コードから原産地は特定できる性質があるので、これらをテーブル分割します。

原産地テーブル
|原産地番号<br>(主キー)|原産地|
|----|----|
|1|宮崎県|
|2|北海道|
|3|茨城県|
|4|千葉県|

元テーブル
|弁当番号<br>(主キー・外部キー)|材料番号<br>(主キー・外部キー)|おかず|原産地番号<br>(外部キー)|
|----|----|----|----|
|1|1|唐揚げ|1|
|1|2|たくあん|2|
|2|3|焼き鮭|2|
|2|4|卵焼き|3|
|2|2|すりおろし大根|4|

さらにスッキリしましたね。

**まとめ**
元テーブルはもはやおかず情報しかないので、おかずテーブルにしちゃいます。
結果、以下の4つのテーブルができてかなりスッキリしましたし、拡張もしやすそうですね。
ただし、取り出す時は結合をする必要があるので、そこそこに抑えないと検索パフォーマンスが落ちてしまうので注意です。

弁当テーブル

|弁当番号<br>(主キー)|弁当名|
|----|----|
|1|唐揚げ弁当|
|2|鮭弁当|

材料テーブル
|材料番号<br>(主キー)|材料|
|----|----|
|1|鳥もも肉|
|2|大根|
|3|鮭|
|4|卵|

原産地テーブル
|原産地番号<br>(主キー)|原産地|
|----|----|
|1|宮崎県|
|2|北海道|
|3|茨城県|
|4|千葉県|

おかずテーブル
|おかず番号<br>(主キー)|おかず|弁当番号<br>(外部キー)|材料番号<br>(外部キー)|原産地番号<br>(外部キー)|
|----|----|----|----|----|
|1|唐揚げ|1|1|1|
|2|たくあん|1|2|2|
|3|焼き鮭|2|3|2|
|4|卵焼き|2|4|3|
|5|すりおろし大根|2|2|4|

即修了（即終了）！！！

# 参考
[正規化とは【データベース】](https://tech-blog.rakus.co.jp/entry/20221115/normalize)
[【入門】データベース設計まとめ](https://qiita.com/KNR109/items/5d4a1954f3e8fd8eaae7)
業務の自動化ってどうすればいいの？ってか自動化ってなに？自動化するといいことあるの？を考えるヒント

## はじめに
この記事は[弥生 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/yayoi)の8日目の記事です。

弥生株式会社のふぁです。情報システム部のインフラとCXチームのテクニカルリーダー (兼務) として弥生のシステム基盤を支えるプロジェクトであったり、新しい仕組みの導入推進を担当しています。

CXチーム (当時はCRMという名称でした) では「[オンプレミス データ ゲートウェイでPower Automateの課題を解消した話](https://tech-blog.yayoi-kk.co.jp/entry/2022/12/21/000000)」のようにデータ連携の自動化を進めていたり、インフラチームでは自動化を見据えた基盤設計や運用保守の自動化などにも取り組んでいます。

この記事では「業務の自動化ってどうすればいいの？ってか自動化ってなに？自動化するといいことあるの？」を考えるヒントになるような基礎的な内容を記載したいと思います。

## 業務自動化の目的
まずパッと思いつく目的は以下のようなものでしょうか。
1. 属人制排除 (工数安定、品質維持、負担軽減)
    1. 工数が安定し、見積もりしやすくなる → 「XX分で処理できそう！」
    1. 品質を維持しやすくなる → 「安定して結果が得られる！」
    1. 「XXXXさんしかできない」を回避しやすくなる → 「YYYYさんが代わりに対応します！」
1. 手間削減 (時間短縮)
    1. 単純に人間の手間を削減できる → 「捻出できた時間で新しいチャレンジ！」
1. ミス防止 (品質向上)
    1. コピペミス、判断ミスを削減して品質を向上させる → 「私、失敗しないので」

どれも解決できたらうれしいですね。
これらは自動化の仕組みを上手く利用することで、実現できます。

## 業務自動化するためには？
まずは業務を自動化する前に今どんな状態なのか把握することが重要だと思います。
自動化の状態にはいつかの段階があります。
1. 手動
1. 一部自動化
1. プロセス自動化
1. AI自動化

### 1. 手動 (非自動化)
言わずもがな。職人がゴリゴリ手作業で頑張っている状態です。
これはこれで職人のお仕事は大変ありがたいのですが、職人の方が万が一病気に・・・とかなったら心配な状態ではあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618452/4c44e739-6f27-76aa-63e7-6ee29979aaf7.png)

### 2. 一部自動化
職人が手作業で実施していたプロセスの一部分を自動化できた状態です。
例えば、下図①と③は自動化できています。(まだ②と③は職人が頑張っています)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618452/04797f78-4796-9b25-e0ba-f4dabd662cf7.png)

### 3. プロセス自動化
職人が消えました。
プロセスが一連として自動化されています。
ここまで実施できれば業務は自動化できたといっていいでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618452/c4b6d190-0a66-de7b-356f-85f135cc7f7f.png)

### 4. AI自動化
さらに発展させて、AI※を組み入れて状況に応じて柔軟な自動化が可能な状態を目指します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618452/7db8c63c-793c-a7ae-b904-94ea82e15fc0.png)
※そもそもAIの定義については別議論として、ここでは機械学習を想定します

このように、いまの業務プロセスがどのような状態なのかが分かれば、どの状態を目指したいのかが見えてきます。
あとは、Automation Platform と AI Platform の選択になってきますが・・・

## 最後に
次回は、実際にプロセスを自動化するために、Automation Platform部分の例をご紹介できればと思います。
【C言語】古典的超伝導体のギャップ方程式からTcを求めてみた

# 概要
　古典的超伝導体のギャップ方程式からTcを求めた。

# 動作環境
- Windows10(64bit)
- Python 3.7.7

# アルゴリズム
アルゴリズムは二分法を用いた。

# プログラム
```C
/* bcs.c */
#include <stdio.h>
#include <math.h>

/* ↓↓↓↓nを大きくすると精度が上がる*/
const int n = 100;
double y;

/*積分する関数 f(x,y)*/
double f(double k_x, double k_y, double kb_T,double myu)
{
double g = 2.5;
double t = 0.1;
double a = 1.0;
double epsilon =-2.0*t*(cos(k_x*a)+cos(k_y*a))-myu;
double E =sqrt(epsilon*epsilon);
return (g/(2.0*E))*tanh(E/(2.0*kb_T));
}

/* 積分の範囲 x0からx_max  yy0からy_max*/
const double x0 = -M_PI;
const double x_max = M_PI;
const double yy0 = -M_PI;
const double y_max = M_PI;

/* x方向の積分 */
double simpson_1(double y, double kb_T,double myu){
    double delta = (x_max-x0)/n;
    double a;
    a = f(x0,y,kb_T,myu);
    a += f(x0+delta*n,y,kb_T,myu);
    int i;
    for(i=1;i<n;i+=2){
        a += 4.0*f(x0+delta*i,y,kb_T,myu);
    }
    for(i=2;i<n;i+=2){
        a += 2.0*f(x0+delta*i,y,kb_T,myu);
    }
    return a*delta/3.0;
}

/* y方向の積分 */
double simpson_2(double half,double myu){
    double delta=(y_max-yy0)/n;
    double a;
    double kb_T = half;
    a = simpson_1(yy0,kb_T,myu);
    a += simpson_1(yy0+delta*n,kb_T,myu);
    int i;
    for(i=1;i<n;i+=2){
        a += 4.0*simpson_1(yy0+delta*i,kb_T,myu);
    }
    for(i=2;i<n;i+=2){
        a += 2.0*simpson_1(yy0+delta*i,kb_T,myu);
    }
    
    return a*delta/3.0;
}

int main(){
int max=1000;
double myu =-0.3;
int dmyu =600;
double array_Tc[dmyu];
double array_myu[dmyu];
double left, half, right;
double residue;

for(int j=0; j<dmyu;j++) #二分法
{
    left=0.0;
    right=20.0;
    for(int k=0; k<max; k++)
    {
        half=(left+right)/2;
        residue=1.0-simpson_2(half,myu);
        if(residue>0)
        {
        right=half;
        }else{
        left=half;
        }
    }
    array_myu[j] = myu; 
    array_Tc[j] = half;
    printf("%d",j);
    myu += 0.001;
}
FILE *fp; #計算結果をtxtファイルに書き出す
fp = fopen("data_c20.txt","w");
for (int l = 0; l <= dmyu; l++)
{
fprintf(fp,"%f %.20f\n",array_myu[l],array_Tc[l]);
}
fclose(fp);
return 0;
}
```
ジェミナイなのか？ジェミニなのか？Geminiに聞いてみた

ジェミニでいいのかなという感じでした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/a331c675-2207-6e66-e55b-0583d434cd8d.png)
【Next.js】VSCode上で絶対パスのimport補完ができるようにしたい

# はじめに
VSCode上で**絶対パス**でimport補完できるように手順をまとめました。


[![Image from Gyazo](https://i.gyazo.com/556a4249559ae1f10aa047595b633b3b.gif)](https://gyazo.com/556a4249559ae1f10aa047595b633b3b)

# 環境構築

`Next.js`は**14**で進めます。オプションは全てデフォルトです。

```ruby
npx create-next-app@latest
Need to install the following packages:
create-next-app@14.0.4
Ok to proceed? (y)
✔ What is your project named? … my-app
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
Creating a new Next.js app in /Users/keisukesakuma/projects/absolute-path-app.

Using npm.

Initializing project with template: app-tw


Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- autoprefixer
- postcss
- tailwindcss
- eslint
- eslint-config-next


added 333 packages, and audited 334 packages in 51s

117 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Initialized a git repository.
```

`tsconfig.json`に設定を追記します。

```json:tsconfig.json
{
	"compilerOptions": {
		"target": "es5",
		"lib": ["dom", "dom.iterable", "esnext"],
		"allowJs": true,
		"skipLibCheck": true,
		"strict": true,
		"noEmit": true,
		"esModuleInterop": true,
		"module": "esnext",
		"moduleResolution": "bundler",
		"resolveJsonModule": true,
		"isolatedModules": true,
		"jsx": "preserve",
		"incremental": true,
		"baseUrl": ".",
		"plugins": [
			{
				"name": "next",
				"@/*": ["./src/app/*"] //追加
			}
		],
		"paths": {
			"@/*": ["./src/app/*"] //追加
		}
	},
	"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
	"exclude": ["node_modules"]
}

```
`./src/app`が`@`エイリアスとして使えるようになります。

![スクリーンショット 2023-12-08 9.35.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517817/17bbb152-f60c-7a3b-f4fa-7c7f649ae23e.png)

また、`typescript.preferences.importModuleSpecifier`を`non-relative`に変更することで、コンポーネント呼び出しの`import`補完時にでも絶対パスで`import`されるようになります。

![スクリーンショット 2023-12-08 9.19.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517817/5e7698dd-dcb3-493a-00cf-7384ecff9671.png)
クリスマスがやってこないｶﾜｲｿｳな人たちに爆撃するdiscordBotつくった話

# まず初めに
投稿者は素人質問が飛んで来たらその場で地団駄を踏んで泣き崩れるくらいの技術力なので結構間違ったことを書くかもしれないし、自分でもよくわかってないので温かい目で見てください。
# なんでそんなもの作ったんだ…
自分にもわかりません。ほんと。誰も幸せにならない…けど思いついてしまったし某ハッカソンでチームメンバーから学んだ技術を生かしたい。そんな思いで作ることになりました。
# 環境
discord.js v14.13.0
node.js v18.18.0
# さて作ろうか
作ります。
### なにすればいいんだ…
某ハッカソンでは原型をすべて友人が作成していてコマンド部分しか知見を得ていなかったため何をすればいいかわからない…
とりあえずググる

### 原型はつよいひとと友人に提供してもらった
`index.js`(main),`deploy-commmads.js`はつよいひとをみならって自分でいろいろいじった。
# 主な機能
きたる12/24。Xmas前夜にクリスマスがやってこない場合
```
('ε' )くー
('ㅂ' ) り
('ε' )す
('□' )ま
('ε' )す
('□' )が
('ﾛ' )こ
('ﾛ' )と
('ㅂ' )し
('ﾛ' )も
('□' )やーっ
('ㅂ' )て
('ﾛ' )こ
('□' )な
('ㅂ' )い
('-' )
```
を
クリスマスがやってくる場合
```
('ε' )くー
('ㅂ' ) り
('ε' )す
('□' )ま
('ε' )す
('□' )が
('ﾛ' )こ
('ﾛ' )と
('ㅂ' )し
('ﾛ' )も
('□' )やーっ
('ㅂ' )て
('ε' )く
☝(^ε^ )☝るぅ
```
をコマンドを実行したチャンネルに送りつけます。

jsonにメッセージを送信するのかしないのか、またクリスマスがくるのかこないのかの情報が入ってます。
それらをコマンドを使って変更してます

#### 意味が分からない
考えるな感じろ

# メインの機能に使った技術
node-cronをつかって毎年12/24の0時にこのメッセージを送りつけるようにしました
```js:sendMessage
cron.schedule("0 0 0 24 12 *", async () => {
    if(data.com === true){
        //ここにメッセージがある
    }
    else if(data.come === false){
        //ここにメッセージがある
    }
}
```
cron.scheduleの`""`の中身は`"秒 分 時 日 月 曜日"`です。
`"* * * * * *"`にしたりすると毎秒メッセージを送りつけるほんとにテロみたいなbotになります。
`"1,3,10,15 * * * * *"`のようにすると毎1,3,10,15秒に実行されるようにできます。おもしろい！
動作確認するときは`"* * * * *"`にして一分ごとに実行してました。

その他はdisocrd.jsに入ってるﾅﾆﾔﾗを使ってます。
文献が多くてとても書きやすかったです。
# Botのコマンド

* /set-message
    * クリスマスイブにメッセージを送信するかどうかの設定を行います。
        trueなら送信、falseなら送信しません。
* /set-come-xmas
    * クリスマスがやってくるのかこないのか設定します。
        trueならクリスマスがやってきます。うれしい
        falseならクリスマスはやってきません。かなしい
        この設定で上記のメッセージが送信されます。
`preview`
        <img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574075/12d3c1fc-f5b2-f905-a2ee-0269880744db.png">
        <img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574075/cf4b1ec7-f65c-e599-9b6b-2e3f8cd6affa.png">
# 今後の発展
* メッセージを送信して1h以内の怒りのメッセージに対して煽ったりする機能
* 某クリスマスソングのリズムに合わせてメッセージを送信できるようにする
* DMでできるようにしても面白いと思った
# さいごに
初心者ながら頑張って作ったdiscordBotに関するお話でした。
友達がつよつよでわからない部分を聞いたら快く教えてくれて本当に助かりました。本当に良い友人を持ったと思います。
次はもっと機能も仕様もちゃんとしたものを作りたいです。

....いつになったらクリスマスは来るんだ
Word2VecとGloVe: 長所と短所

ベクトル検索やセマンティック検索の文脈で、文字の意味をベクトル化する際にWord2VecとGloVeの方法がありますが、それぞれの長所と短所を挙げて比較する質問をGoogle Bardにしてみた結果を記録として残しておきます。質疑は英語で行い、Bardが英語で回答した後にBardに和訳を指示した結果がこれです。

Word2VecとGloVeはどちらも単語埋め込みを生成する人気の方法ですが、それぞれ異なる長所と短所があります。以下は、両者の比較です。

# Word2Vec:

長所:
* 直接的な単語表現の学習: Word2Vecモデルは、テキストデータから直接単語ベクトルを学習し、単語間の意味関係を捉えます。
* 効率性: Word2Vecは効率的な学習アルゴリズムを持ち、大規模なデータセットにも適しています。
* 複数の学習方法: CBOWやSkip-gramなど、Word2Vecにはさまざまなモデルがあり、ニーズに応じて異なるメリットが得られます。

短所:
* 局所的な文脈に重点 Word2Vecは主に局所的な文脈に注目して学習するため、大規模な文脈や長距離の意味関係は無視されます。
* 頻度の影響 高頻度の単語はより支配的なベクトルを持つ傾向があり、モデルにバイアスをかける可能性があります。
* 稀少語への対応が不十分 Word2Vecは、学習データが少ないため、稀少語を正確に表現することが困難です。

# GloVe:

長所:
* グローバルな文脈の把握: GloVeは単語の共起統計量を利用して大規模な文脈における意味関係を把握し、より正確な単語表現を実現します。
* 頻度にあまり影響されない GloVeは単語の頻度の影響を受けにくいため、稀少語もより適切に表現できます。
* 類推推論により適している GloVeはグローバルな文脈と意味関係に焦点を当てるため、類推推論などのタスクでより良いパフォーマンスを発揮します。

短所:
* 間接的な学習: GloVeは単語の共起統計量から間接的に単語ベクトルを学習するため、テキストデータから直接学習するほど効果的ではない可能性があります。
* 学習速度が遅い GloVeの学習は、特に大規模なデータセットの場合、Word2Vecに比べて遅くなる可能性があります。
* 追加処理が必要 学習前に共起統計量を準備する必要があり、GloVeのワークフローに追加のステップが加わります。

# Word2VecとGloVeの選択

Word2VecとGloVeのどちらを選択するかは、特定のニーズと優先事項によって異なります。考慮すべき要素は次のとおりです。

* タスク: 類推推論や長距離の意味関係の把握が必要なアプリケーションの場合は、GloVeがより良い選択かもしれません。
* データセットのサイズ: 大規模なデータセットの場合は、Word2Vecの効率的な学習アルゴリズムが有利かもしれません。
* 単語の頻度: データに多くの稀少語が含まれている場合は、GloVeのバイアスが少ない表現がより適しているかもしれません。
* 計算資源: 計算資源が限られている場合は、Word2Vecのより速い学習が決定要因となる可能性があります。

最終的には、Word2VecとGloVeの両方を特定のデータセットとタスクで試して、どちらのモデルがニーズに合っているかを判断することをお勧めします。
ローカル環境のマージ済みブランチの一括削除コマンドを考えてみた

## 対象者
`git branch` コマンドを打ったらとんでもない量のブランチが出る人。

## 前置き
開発をしているとブランチを切って作業すると思いますが、本流ブランチにマージした後もついついそのままにしちゃいますよね。
かくいう私もそんなズボラ人間。
今回の記事はそんな私を始めとしたズボラ人間ズに刺されば良いと思って書きました。

## 先に結論
下記の1ライナーコマンドを「ローカルブランチ多くなってきたなー」てタイミングで叩くだけ。
```
git stash -u && git checkout master && git fetch --prune && git branch --merged | egrep -v "\*|master|main|staging" | xargs git branch -d && git checkout -
```

:::note info
各々のリポジトリのブランチ運用ルールによって変えたほうが良い部分もあるので、
次項の [コマンドの説明](#コマンドの説明) を見て各自の設定に変えてから使用してください。
:::

ちなみに私は後述する [fzf を使って更にカスタマイズしたコマンド](#リポジトリごとに退避先のブランチが違う場合) を使ってます。
気になる方はそちらもどうぞ。

## コマンドの説明
### `git stash -u`
(もしあれば) 作業中の変更箇所を退避させます。
もし変更箇所があると次の `git checkout` ができませぬ。
`-u` オプションをつけてuntrackファイルも対象にしています。

### `git checkout master`
今いるブランチが削除対象だった場合に削除できないので一旦チェックアウトします。
※ `master` の部分は任意の退避先ブランチ（手元の絶対消さないブランチ）を指定してください。

### `git fetch --prune`
ついでに手元のリモート追跡ブランチも掃除しちゃおうって感じで入れてるだけ。お好みで。

こういうやつですね ↓
```
remotes/origin/hogehoge
remotes/origin/hugahuga
```
これをしないとリモートリポジトリ上で既にないブランチが残り続けてしまい邪魔なのです。

### `git branch --merged | egrep -v "\*|master|main|staging" | xargs git branch -d`
本コマンドの肝。パイプ（`|`）を使ってうまくやってます。

`git branch --merged | egrep -v "\*|master|main|staging"`
→ `egrep` で指定した**以外の**マージ済みブランチ一覧を取得。

`xargs git branch -d` 
→ さっきのブランチ一覧をパイプで受け取って順番にブランチを削除。

※ `master|main|staging` の部分は任意の **削除したくないブランチ** を指定してください。

### `git checkout -`
退避先ブランチから元のブランチへ戻します（1個前のブランチにチェックアウト）
ただ、これを入れるかはお好みです。
何故ならもともと退避先ブランチにいる場合に別のブランチにチェックアウトしてしまうので。

## リポジトリごとに退避先のブランチが違う場合
これでも充分なのですが、いろんなリポジトリで並行して作業している人も多いハズ。
リポジトリ間でルールが統一されていれば良いのですがそうじゃない場合、退避先ブランチが存在しなかったりして使えなかったりします。

私がまさにそうなので下記のようにコマンドを改良しました。（めちゃ長いw
```
git stash -u && git checkout $(git branch | tr -d " " |fzf --height 100% --prompt "CHECKOUT BRANCH>" --preview "git log --color=always {}" | head -n 1 | sed -e "s/^\*\s*//g" | perl -pe "s/remotes\/origin\///g") && git fetch --prune && git branch --merged | egrep -v "\*|master|main|staging" | xargs git branch -d
```

違うところは下記の `git checkout` する箇所。
`git checkout $(git branch | tr -d " " |fzf --height 100% --prompt "CHECKOUT BRANCH>" --preview "git log --color=always {}" | head -n 1 | sed -e "s/^\*\s*//g" | perl -pe "s/remotes\/origin\///g")`

[fzf](https://github.com/junegunn/fzf) を使って退避先ブランチを自分で選べるようになってます。
`fzf` については好きすぎて説明すると長くなるので本記事では割愛します。


## 最後に
いつも通り「楽したい」をモットーに作りました。
同じ問題で困っている誰かの助けになれば幸いです。

はぁーーー、`xargs` 好き。
私のElastic ES|QL Tips集

# はじめに
ES|QLというクエリー言語が新たにElastic v8.11でテクニカルプレビューとして登場しました。フリー版から使えます！
Discoverからログなどの検索をする時に、もはや必須のツールとなると思うので、ぜひみなさんも試してください。
この記事では今の所わかっているTipsをまとめました。（まだGAではないので、多少仕様が変わる可能性はなきにしろあらずです）

基本的な構文や関数に関してこちらのマニュアルを参照ください。
https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-language.html

# Tips集
### 日本時刻（JST)でのWhere検索
以下のように行う。(@timestampは内部的にはUTCで保持しているため、こうやらないとUTCベースで検索されてしまう）
```
where @timestamp >= date_parse("yyyy-MM-dd'T'HH:mm:sszzzz", "2023-11-29T13:00:00+09:00") 
and @timestamp <= date_parse("yyyy-MM-dd'T'HH:mm:sszzzz", "2023-11-29T14:00:00+09:00")
```
### フィールドの名前に対してエスケープが必要な場合
例えばスラッシュが含まれるカラムは、バックティックで囲む。
```
where `kubernetes.labels.app_kubernetes_io/instance` == "abc" 
```
### 日本時刻（JST)ベースで、例えば朝の6時〜10時のデータを検索したい。
以下の例ではdropoff_datetimeにタイムスタンプデータが入っている前提です。
```
from nyc_taxis 
| limit 10 
| EVAL dt_long = to_long(dropoff_datetime)
| EVAL TIMEZONE_DIFF = 9
| EVAL dt_timezone_long = to_long(dt_long + TIMEZONE_DIFF * 60 * 60 * 1000)
| EVAL timezone_date = to_datetime(dt_timezone_long)
| EVAL hour = DATE_EXTRACT(timezone_date, "HOUR_OF_DAY")
| EVAL minute = DATE_EXTRACT(timezone_date, "MINUTE_OF_HOUR")
| WHERE hour >= 6 AND hour <=10
| KEEP dropoff_datetime, timezone_date, hour, minute
```

### Elastic ES|QLでアクセスログの怪しい403の高度なアラート検知をしてみる
別記事：　[Elastic ES|QLでアクセスログの怪しい403の高度なアラート検知をしてみる](https://qiita.com/nobuhikosekiya/items/fee05f4c54d75c2a236e)

# おわり
この記事は、随時何かあれば追加していきたいと思います！
熟考の心理【エンジニアデザイン心理学】





## 熟考の心理でもさぼろうとしている


前回の記事では「直観の心理」というものを扱った。
ここでは、

- 普段は直観で動いている
- 直観の心理の大部分を占める「習慣」は`キュー`,`ルーティン`,`リワード`の関係であること
- 日常の行動を変更するためには`キュー`,`ルーティン`,`リワード`のすべてに訴えかけることが大事であること
- 習慣によって、日常の判断をアウトソーシングし、楽できること

を学んだ。

熟考の心理では、キューやルーティーンのような体系的知識はないが、「楽しようとする」という点は同じである。

この、熟考の心理における楽をしようとするための性質を**ヒューリスティック**と呼ぶ


## ヒューリスティック一覧

### 質問を置き換えてしまう

人間は質問に答えるのに苦労してしまうことがあり、別の質問に置き換えて回答してしまうことがある。


<img src="https://github.com/minegishirei/psy/blob/main/img/UIUX/select_mode/1.png?raw=true">


### 自分と似た人間を選んでしまう

選挙や面接において、その人の能力ではなく

- 「この人は自分と似ているか?」
- 「この人の顔面は魅力的か?」

で選んでしまう傾向がある


### 選択をほかの人に委ねてしまう


####  多数派意見の尊重

ある行動をやるべきかどうかを判断するときに、「他の人がいいねをおしてくれるかな？」と考えることを**社会的証明** と呼ぶ。

> 例えば、テレビの後ろで流れる笑い声の音声があることで、視聴者は安心して笑うことができる。

#### 専門家意見の尊重

専門家の意見についてはほかの人の意見よりも高い比率で捉えられることが多い。

例えば、エンジニアが話した機能の提案よりも、コンサルタントが提案した機能のほうが案として成立しやすい（たとえそれが同じ内容であっても）



## 人間の選択能力の限界

たとえ上記のヒューリスティック一覧を克服できた時でも、人間の脳には物理的に限界がある。


### 記憶力の限界

いわゆる `7+-2` というやつである。
即自的な記憶の数が制限されており、これらの塊しか脳内にためることができない。


### 注意力の限界

人間が一度に視認できるものは一つだけである。
二つ同時に認識することはできない。


### 精神力の限界

精神的に困難なタスクは以下の状態に結果が依存してしまうらしい。

- 脳の疲れ
- どれくらい前に食べたり休んだか?
- どれくらいの仕事をこなしたか?

サウジアラビアの裁判の例では、仮釈放を認める割合が「休憩時間から判決までどれくらいの時間がかかったか」に依存するという。

我々は一つ選択するたびに大きなエネルギーを消費する。
エンジニアが意識するべきこととして、 **プロダクトがユーザーに選択を課すたびにユーザーは疲弊していることがある。**