OmniAICreator/Qiita-1.07M huggingface dataset:
初心者のためのAlpine.js

## Alpine.jsとは
Alpine.jsは、JavaScriptフレームワークの一つで、VueやReactのようなフレームワークの機能を、より軽量で直感的な形で提供しています。。特に、HTML内に直接JavaScriptのロジックを書くことができるため、学習コストが低く、既存のプロジェクトにも容易に組み込むことができます。

## Alpine.jsで何ができるのか

Alpine.jsを使うと、ユーザーのクリックや入力に反応するインタラクティブなウェブページを簡単に作成することができます。例えば、ボタンをクリックするとメニューが表示されたり、テキストを入力するとリアルタイムで結果がフィルタリングされたりします。

## Alpine.jsのインストール方法

Alpine.jsのインストールは非常に簡単です。HTMLファイルの`<head>`タグ内に以下の`<script>`タグを追加するだけです。

```html
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
```

## 必要なHTMLファイルの作成

Alpine.jsを使って何かを作り始める前に、まずはHTMLファイルを作成しましょう。例えば、`index.html`という名前で作成することができます。そして、上記の`<script>`タグを追加します。

# Alpine.jsの基本的な機能

## x-data、x-on、x-text、x-show、x-model、x-forなどの主要なディレクティブ
Alpine.jsの主要なディレクティブには以下のようなものがあります：

- `x-data`：コンポーネントの状態を定義します。ここで定義したデータは、同じ要素内の他のディレクティブからアクセスできます。
- `x-on`：特定のイベント（例：クリックやマウスオーバー）に反応して何かを実行します。
- `x-text`：要素のテキスト内容を動的に更新します。
- `x-show`：要素の表示・非表示を制御します。
- `x-model`：フォーム要素の入力と状態を双方向にバインドします。
- `x-for`：配列の各要素に対して要素を繰り返し生成します。

# 実践！Alpine.jsでモーダルを作成しよう

## モーダルコンポーネントの作成手順とコードの説明

モーダルは、ウェブページ上に一時的に表示される小さなウィンドウのことを指します。Alpine.jsを使用して、以下のようにモーダルを作成することができます。

```html
<div x-data="{ isOpen: false }">
  <button @click="isOpen = true">Open Modal</button>

  <div x-show="isOpen" @click.away="isOpen = false">
    <h2>Modal Title</h2>
    <p>Modal Content...</p>
    <button @click="isOpen = false">Close Modal</button>
  </div>
</div>
```

このコードでは、ボタンをクリックすると`isOpen`の値が`true`になり、モーダルが表示されます。モーダル外をクリックするか、閉じるボタンをクリックすると`isOpen`の値が`false`になり、モーダルが非表示になります。

# 実践！Alpine.jsでドロップダウンを作成しよう

## ドロップダウンコンポーネントの作成手順とコードの説明

ドロップダウンは、クリックするとメニューが下に展開するUIの一つです。Alpine.jsを使用して、以下のようにドロップダウンを作成することができます。

```html
<div x-data="{ isOpen: false }">
  <button @click="isOpen = !isOpen">Toggle Dropdown</button>

  <div x-show="isOpen" @click.away="isOpen = false">
    <p>Dropdown Content...</p>
  </div>
</div>
```

このコードでは、ボタンをクリックすると`isOpen`の値が反転し、ドロップダウンメニューが表示・非表示が切り替わります。

# 実践！Alpine.jsで検索入力を作成しよう

## 検索入力コンポーネントの作成手順とコードの説明

Alpine.jsを使用して、ユーザーが入力したテキストに基づいてリストをフィルタリングする検索入力を作成することができます。

```html
<div x-data="{ search: '', items: ['Item 1', 'Item 2', 'Item 3'] }">
  <input x-model="search" placeholder="Search...">

  <template x-for="item in items" :key="item">
    <p x-show="item.includes(search)" x-text="item"></p>
  </template>
</div>
```

このコードでは、ユーザーがテキストを入力すると、そのテキストに一致するアイテムのみが表示されます。

# Alpine.jsの応用

## 複雑なコンポーネントの作成方法

Alpine.jsのディレクティブを組み合わせることで

、より複雑なコンポーネントを作成することができます。例えば、フォームのバリデーション、タブ切り替え、スライダーなどのコンポーネントを作成することが可能です。

## ディレクティブの組み合わせ方

Alpine.jsのディレクティブは、HTML要素に対して特定の動作を追加するためのものです。これらのディレクティブを組み合わせることで、様々な動作を実現することができます。例えば、`x-show`と`x-transition`を組み合わせることで、要素の表示・非表示をアニメーション付きで切り替えることができます。
LTspice : オープンループ特性の調べ方

## LTspice でループ回路のオープンループ特性を解析する

例えば以下のようなオペアンプのボルテージフォロワ回路があったとします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455249/5726e1ac-4a2b-4421-85ce-a34df9f10afe.png" width="930">

出力電圧を 100% 入力に戻すループ回路になってますが、この回路のオープンループ特性を調べたいとき、どうしてるでしょうか？
例えば、単純にループを切って回路の入出力を見る、というのも一つの手ですが、閉ループ状態の動作点に合わせるのが大変だったりします。
ゲインが高く、入力のオフセット電圧があったりすると、ちょっとした差で出力が飽和したりして、正常にオープンループ特性が計算できないこともあります。

実はオープンループ特性を調べるのに、ループを切る必要はありません。
ループ内に AC 信号源を置いて、回路の出力を vo、フィードバック側を vi とし、vo/vi を調べれば OK です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455249/c92536e8-36cf-7611-40ba-8a92e56ec5e7.png" width="930">

V(vo)/V(vi) をプロットして見てみると、Gain = 0dB で位相余裕 50°ぐらい ( この場合は 0°で不安定 ) なのがわかります。
この方法、もちろんオペアンプに限らず、フィードバックのパスがわかっていれば他のループ回路でも使えます。
LTspice : 時間微分・積分

## LTspice で信号の時間微分・積分を計算する

LTscpie で信号の時間微分・積分を計算する方法としては、Laplace式を使った方法がありますが、ここではそれに頼らない方法を紹介します。

L, Cって、交流回路での電圧・電流に対して以下ような動作をする素子でしたよね。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455249/5871725b-238c-20df-f5d5-d0fab4072dfc.png" width="220">

これを使って微分・積分を求めます。

入力電圧を時間微分して、電圧として出力するブロックの、回路図とシンボルは以下のようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455249/f6082c30-e239-75a0-6012-9e35ac4e21c5.png" width="930">

入力電圧を時間積分して、電圧として出力するブロックの、回路図とシンボルは以下のようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455249/97f44abe-e5e5-cdc6-3967-4d0b6a56df29.png" width="930">

なぜ Laplace 式を使わずにこういう形にしたかというと、実は上の L1, C1 は単なる 1[H], 1[F] の素子にしていないのです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455249/cdcb7f50-f57b-437c-8f28-8c7f68a2458c.png" width="216">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455249/a259c9f6-bbc2-3fc8-d49b-3a1ab18e180d.png" width="216">

L1 には直列に小さな抵抗を、C1 には並列に大きな抵抗を忍ばせています。
Laplace で微分・積分とったときに、DC 解析のところで計算が収束しなくて困ったことがあったのですが、この方法だと、計算結果に影響が出ない程度に付加抵抗をつけることで、それを回避できたりするので、あえてこんなことをしています。
LTspice : ノイズ電圧源

## LTspice でサーマルノイズ電圧源のモデルを定義する

LTscpie でノイズシミュレーションをする場合の話です。
LTspice にはノイズ電圧源のモデルがありません。必要なら自分で定義する必要があります。一つの方法として、抵抗をノイズ源として使用することが可能です。LTspice の回路図とシンボルは以下のようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455249/5adf27dd-3198-419a-fc91-7038619d0e7d.png" width="930">

抵抗 60.342Ωの出すサーマルノイズが 1nV/√Hz であることを利用しています。パラメータにより、任意の {pnoise}nV/√Hz のサーマルノイズを定義できます。

## LTspice でフリッカーノイズ電圧源のモデルを定義する

フリッカーノイズの場合は、1/f の周波数特性を表現するために、Laplace式を用います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455249/7961dd8e-21be-5657-7015-5bc23c99a345.png" width="930">

Laplace 式の s は微分を表しており、これによって、周波数に対し一定のサーマルノイズが、1/f の傾きを持ったノイズとなります。パラメータ pnoise は、1kHz におけるノイズ電圧を表しています。コイル L1 は電流出力で DC 的に飽和しないようにおまじない的に付けているものですが、計算が収束しないときはこういうのが必要だったりします。
剥がれない吸音材の貼り方

## 吸音材は剥がれやすいのか？？
吸音材に付属していたスポンジ系の両面テープはネットリ系で粘着力高そうでしたが、剥がれてしましました。

| | |
|--|--|
| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3375942/85f6f11a-2ebc-d9ec-fe80-310fe76731f9.png) |![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3375942/87a0021d-9094-62ef-b804-1f4db7102016.png) |



## 剥がれない貼り方
画像のように、`画鋲`と`クリップ`を使うことで簡単に固定することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3375942/95531ac1-e644-3f97-efab-1a680158fe9a.png)
組込TCP/IPネットワーク：アプリケーション

<h3>■ネットワークを使って何をやりたいか</h3>
そもそもなぜ組込機器にネットワークを入れたくなったのか、です。それによってプロトコルスタックやネットワークデバイスに必要な機能・性能も変わってきますので、まずここを考えましょう。

<h4>A) クラウド、サーバに情報を送りたい</h4>
組込機器で得られたなんらかの情報をLAN上やクラウドのサーバに送信するパターンです。データを受信するサーバ側も自社で開発するならデータを送信するプロトコルも独自開発するかもしれませんが、できれば既存の仕組みに乗っかりたいところです。AWSやAzureなどクラウドへ情報送信するIoTデバイスにするならMQTTSかHTTPSを使用することになるでしょう。白物家電や家庭内センサ情報をサーバで管理するHEMS（Home Energy Management System）を考えるとECHONET Liteというプロトコルを使用することになるかもしれません。

![cente-introduction_08_rev.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032022/41486e78-bafa-ff0a-5724-39aaf9b2029b.png)

クラウドを使わないでインターネット経由で情報を渡す方法として、組込機器からメールを出すのもあり得ます。一昔前はプロバイダから独立してSMTP/POPに対応したメールサーバもいくつかありましたが、悪用されることが多かったためかサービスが激減しました。そんな中でも認証・暗号化がしっかりしたGmailはまだ候補として残っていて、OAuth、SMTPまたはHTTP、TLSで実現できます。

データをファイルの形にして、FTPで送信するパターンもあります。サーバプログラムも豊富に存在したため以前は主流だったと思いますが、データが暗号化されず、ログインのユーザ名パスワードすらも平文で送るFTPは特にインターネットの世界では時代に合わなくなってきました。その場合もTLSを伴ったFTPSに切り替えてセキュア化することで、「ファイルで送る」という仕組みはいまだに選択肢の一つかと思います。

<b>★Centeでは...</b>
MQTTc、HTTPc、FTPd/c、SMTP/POPc、ECHONET Lite、TLSなど、この用途に使用できるミドルウエアをご用意しております。更に、AWS IoT、Azure IoTへ接続する場合のアプリケーションノートをご用意しており、素早い組込機器のIoTデバイス化が可能です。


<h4>B) 組込機器の設定・制御をしたい</h4>
その昔、組込機器に各種設定を行うI/Fは組込機器にとってはちょっと厄介な問題だったと思います。組込機器自体にボタンや液晶をつけて、という方法は古くからあり、組込機器自体を人が操作するようなもの（ICレコーダなど）ではいまだに主流でしょう。しかし、普段は人が操作しない組込機器の場合や、設定が複雑なもの・今後どんどん機能拡張されていくものの場合、液晶とボタンで操作するのはかなり使いづらい組込機器になってしまいます。そういったものは組込機器側にシェル機能を搭載し、シリアルケーブルでパソコンと接続してターミナルソフトで制御する方法もとられていました。
そういった組込機器の設定・制御をネットワーク経由で遠隔からできないか、という話題です。<br>
<br>
真っ先に思いつくのがtelnetdです。シェルのI/Oをシリアルからtelnetに変えるだけなので簡単で、実際ルータ含め多くの組込機器がtelnetdを実装してネットワークから便利に設定・制御をしてきました。しかし、これも今では代表的なアタックサーフェスになってしまい、世界中の攻撃プログラムがtelnetのポート番号23が開いている機器をインターネット上で探しているような状況です。製品出荷前までの開発用途であればtelnetdを組込機器に入れるのもありかもしれませんが、製品用ファームウエアであればLAN内での運用だとしてもtelnetではなくSSHにして、認証・暗号化をしっかり対策すべきです。<br>
<br>
シェルコマンドは慣れている人じゃないと使いにくいので、いっそのこと独自のプロトコルを規定して組込機器に実装、パソコンのアプリケーションもGUIがきれいなものを独自に開発するパターンもありました。ただ、これだと今度はMac版とWin版どっちをつくるの？対応バージョンは？のような問題がずっとついてまわります。そこで救世主のように現れたのがWebブラウザです。かなり「攻めた」画面デザインにしない限りWindows版でもMac版でもEdgeでもChromeでもそれほど見え方が変わらないですし、組込機器側も一般的なHTTPを使うことができます。暗号化が必要なHTTPSにするなど別のレイヤでケアできる（アプリケーションでケアしなくて良い）ので、現在は組込機器の設定・制御をしたいなら組込機器にHTTPdを入れてパソコンやタブレットのWebブラウザ、という設計が主流と思います。<br>
<br>
更に、最近はReact.js、Chart.jsなどインタラクティブなユーザI/Fを構築できるJavaScriptライブラリも登場してきました。組込機器から見るとJavaScriptはWebブラウザに送信するデータの一部なので、組込機器自体には特に機能追加は不要です。タブレットやスマホのWebブラウザから組込機器を設定・制御するのがトレンドになると考えています。

![cente-introduction_09_rev.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032022/e6525a40-7f4f-9db0-082e-918d6051e262.png)


<b>★Centeでは...</b>
シェル、telnetd、HTTPdといったミドルウエアをご用意しております。また、スマホから組込機器を制御するWebUI構築のためのアプリケーションノートをご用意しており、React導入の経験がない方でも実現可能です。


次回、もう少し他のケースも解説します。


<h3>■今日の閑話</h3>
Centeでは組込機器に必要とされるミドルウエアを提供しようと考えて今のラインナップになっていますが、作ったは良いけどほとんど使われないプロトコルもあります。その最たるものがtelnetcです。組込機器がtelnetでネットワーク上のPCに接続してコマンドを送る、というケースもあるんじゃないかと思って作ったのですが、やっぱり使い道ないでしょうか？そんな理由でSSHcを開発するモチベーションが沸かないのですが、<b>「うちはtelnetcをこうやって使ってるぜ！」</b>という方は是非コメント欄でお知らせいただければと思います。<br>
<br>

Cente：
https://www.cente.jp/

お問合せはこちら：
https://www.cente.jp/otoiawase/
dbt-coreにおけるOSS活動ことはじめ ~投稿記事まとめ~

# 本記事が目指すこと
- dbt-coreにおけるOSS活動を始めるにあたってやるべきこと、学びになったことを複数回に渡り投稿した。本記事では、それらの記事をまとめる

# 注意
- 本記事は筆者が所属する会社と関係なく、個人の記事であることをご了承ください

# 記事タイトルと要約
- [dbt-coreにおけるOSS活動ことはじめその1 ~ CLAの話 ~](https://qiita.com/daおi_zamurai/items/6811e1d4ca9e2fad1ca7)
    - まずはCLAの署名が必須である。CLAの種類には、個人CLAと企業CLAがあり、職務におけるOSS活動では企業CLAへの署名が求められるが、誰に承認をもらうべきか、誰が署名すべきか、署名プロセスが明確でなかった。本記事では、他社事例を参考に、弊社にてOSSポリシーを制定し、CLA署名のプロセスを整備した経緯を紹介している

- [dbt-coreにおけるOSS活動ことはじめその2 ~ 環境構築の話 ~](https://qiita.com/dai_zamurai/items/021e64b4e495b32aa907)
    - PostgreSQLを用いた環境構築の手順について紹介した記事。ドキュメントには、前提となる実行環境や期待される出力に関して明記されてないため、詳細を記述した。本記事の手順にて環境構築することで、後述するテストの実行環境も構築できる


- [dbt-coreにおけるOSS活動ことはじめその3 ~ テストの話 ~](https://qiita.com/dai_zamurai/items/aecab2aec4b352f6d9a4)
    - テストの手順について紹介した記事。テストには、アダプタ(今回の場合はPostgreSQL)を使用しない単体テスト、アダプタを使用する統合テストの2種類が存在する。執筆時点では、そのまま統合テストを実行してしまうと、PostgreSQLを用いたスナップショットを削除するテストにて、タイムゾーンがJSTに設定されている場合はエラーが出てしまうため、バグを修正したコードを取り込む必要があることを述べた(現在、筆者がPRを出している)

- [dbt-coreにおけるOSS活動ことはじめその4 ~ Changieを用いた変更ログ管理の話 ~](https://qiita.com/dai_zamurai/items/2eb70c39413f96e504ba)
    - Changieを用いた変更ログをコミットする手順について紹介した記事。dbt-coreのリポジトリ では、変更ログをChangieというOSSツールを用いて管理している。その使い方を紹介している

- [dbt-coreにおけるOSS活動ことはじめその5 ~ Issueの立て方、見つけ方の話 ~](https://qiita.com/dai_zamurai/items/9c741686dd09245fc1f8)
    - Issueの立て方、見つけ方について紹介した記事。目を通しておくべきドキュメントや取り組みやすいIssueの見つけ方、テンプレートを利用したIssueの立て方を述べている

- [dbt-coreにおけるOSS活動ことはじめその6 ~ PRの話 ~](https://qiita.com/dai_zamurai/items/3ccaa79d8852ee48eb7b)
    - PRの立て方、dbt-coreの管理者とのコミュニケーションについて紹介した記事。目を通しておくべきドキュメントやマージされるまでの心算を述べている

- [dbt-coreにおけるOSS活動ことはじめその7 ~ デバッグの話 ~](https://qiita.com/dai_zamurai/items/c0f564d41be50b9dde3d)
    - 開発時につまづいた際のデバッグの方法について紹介した記事。ログレベルの変更方法やデバッガなどを紹介している

- [dbt-coreにおけるOSS活動ことはじめその8 ~ コミュニティの話 ~](https://qiita.com/dai_zamurai/items/439fd5dce6f37a5d25ec)
    - dbt-coreにおけるOSS活動をした際に思いついた疑問や質問を受け付けるコミュニティを紹介した記事。困った際には活用いただきたい

- [dbt-coreにおけるOSS活動ことはじめその9 ~ テストカバレッジをローカルで確認する話 ~](https://qiita.com/dai_zamurai/items/213f504b6e18ee663a2e)
    - dbt-coreにおけるOSS活動をする際に役立つ、テストカバレッジをローカルで確認する方法について紹介した記事


# 終わりに
ちゅらデータでは、クレイジーな仲間を募集しているでござる
データエンジニア、もしくはSE系からデータエンジニアになりたい方がいればぜひ、御仁の力量に応じたグレード（ジュニア/ミドル/シニア）にて、応募するでござる

https://herp.careers/v1/churadata/T6Oag1FxE34V
AccessのVBAでビープ音（確認音）を鳴らす

# 背景

タブレットなどの『指で操作する端末』でAccessを使っている。
そういった環境の場合、ユーザーから「処理が正常終了したら音鳴らしてほしい」と要望があがることがある。

# やり方（てろーんっていう固定音）

Windowsで音量を調整した時に鳴る「てろーん」でよいなら下記。

```vb:
DoCmd.Beep
```

# やり方（音の高さと長さを指定）

正常終了なら『ぽ↓ぴ↑』
エラーなら『ぶ→ぶ→ぶ→』
のように鳴る音を変えたい場合。

:::note warn
この方法はかなりデカいビープ音出るので注意。
:::

```vb
'『kernel32.dll』の力を借りるとカスタム音を鳴らせる。
Private Declare Function Beep Lib "kernel32.dll" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long

'フォーム上にbtn_1という名前のボタンがあり、それを押した時の動作。
Private Sub btn_1_Click()
    
    '第一引数が周波数 = 音の高さ。
    '第一引数が音の長さ。
    Call Beep(1000, 70)
    Call Beep(3000, 180)

End Sub
```

# 参考サイトさん

http://www.start-macro.com/55/w/s077.html

https://learn.microsoft.com/ja-jp/office/vba/api/access.docmd.beep

https://excel-databace.hatenablog.com/entry/64bit-vba-error

# バージョン

Windows 10 Pro 22H2 19045.3086
Microsoft Access for Microsoft 365 MSO (バージョン 2305 ビルド 16.0.16501.20074) 32 ビット
Maven Central へリポジトリを申し込む

# アカウントの申し込み
リポジトリの申請は、このサイトです。
https://central.sonatype.com

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/da72f107-3d54-2c47-304e-3e574fc13d1c.png)
「Sign in」ボタンを押して、アカウントを申請します。自分の場合GitHub連携を利用しました。言語を選べますが、日本語版の翻訳はよくないで、英語のほうを推薦します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/ff0d469e-c713-9b0e-e974-24a40facccd1.png)
# プロジェクトの申し込み
ログイン後、結構複雑な画面が表示されます。ものがいっぱいですから、とりあえず「help」をみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/636e471c-6a14-b3d2-30ad-1113994bd95e.png)
Producesへのサポート資料に、「New Project」のリンクを見つかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/8026a987-5041-4df9-6d69-ec15cf9f1d63.png)
リンクを押す場合、新規プロジェクト作成の依頼入力画面が表示されます。試していないが、タイトルの内容はあまりチェックされないみたいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/8564258f-4a64-1c46-6d2d-52abeb7e9c10.png)
Group Id：組織を表します。所有者チェックが実施されますので、jp.co.XXXと書く場合ドメイン管理権限ないと進まないです。自分の場合、推薦されてio.github.XXXのようにしました。
Project URL：存在するURLを要求されます。
SCM url：存在するURLを要求されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/177098d6-d029-2c3b-d3e6-663cba334f54.png)
# 審査対応
作成後、作成成功のメール通知がきます。しばらく後、サイトから審査のコメントがきます。その指示に従ってやれば、すぐ申込完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/6ab9644a-e87e-3231-31b2-f6583e79da92.png)
完了通知には、「deployment」に関わるリンクがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/3df16b3a-a3a7-5479-8a27-4b225bea6a4e.png)

https://central.sonatype.org/publish/publish-guide/#deployment

jarファイルをどうリリースするか別途資料をまとめます。おまちください。

[Maven Central へリポジトリを申し込む](https://qiita.com/changkejun/items/646825ddada989942149)
[Maven Central へ行く前にjarとpomを作成](https://qiita.com/changkejun/items/e90e5c18167cd43c6723)
[jarとpomを署名してMaven Centralへアップロード](https://qiita.com/changkejun/items/5c5151a68c32518a765d)
Wordpressのウィジェットって？どうやって追加して、どうやって表示させるのか？

# ウィジェットとは？
ブログの人気記事ランキングを表示させたい、など、プラグインを使って機能追加して、それを表示させたい時に活躍するのがウィジェットです。

多くの場合は共通するセクションをまとめて管理したい時に使ったりします。

例えば、ブログサイト全体に共通にサイドバーがあって、それを全ページに記述していくのは大変ですが、このウィジェットを使って管理すると管理画面からほぼノーコードで編集ができます。

具体的な使い方を見ないとイメージがわかないと思うので、以下へ[WordPress Popula Posts](https://wordpress.org/plugins/wordpress-popular-posts/)で人気記事ランキングのウィジェット追加から表示までを参考に流れを見ていきましょう。

# function.phpで管理画面にウィジェット編集画面を表示させる
よく、Wordpressの管理画面の外観 > ウィジェットを選択して、ウィジェットを追加しましょう、なんて案内がされているページをよく見かけますが、デフォルトではWordpressの管理画面に「ウィジェット」という設定項目が存在しません。
function.phpに、以下のように記述を追加しましょう。

```function.php
    function sample_widgets(){
        register_sidebar(array(
            'name' => 'ブログサイドバー', // ウィジェット名
            'description' => 'ブログのサイドバーに挿入するウィジェット', // 説明
            'id' => 'sidebar', // ウィジェットには任意のid名をつける必要があります
            'before_widget' => '<div class="sidebar">', // 表示させる時の開始タグ
            'after_widget' => '</div>', // 表示させる時の終了タグ
            'before_title' => '<h3>', // ウィジェットのタイトルの開始タグ
            'after_title' => '</h3>' // ウィジェットのタイトルの終了タグ
        ));
    }
    add_action('widgets_init', 'sample_widgets');
```

これで保存すると、Wordpressの管理画面の「外観」のなかへ「ウィジェット」が表示されていると思います。


# ウィジェット編集
Wordpressの管理画面の外観 > ウィジェットを開いてみると、先ほどfunction.phpのnameで指定した名前のウィジェットが出てきていると思います。
大きな＋ボタンを押すと、ブロックエディターのようにいろいろなボタンが出てきて、押すとウィジェットへどんどん追加できる様子が確認できると思います。

ウィジェットとして追加したいものを追加しましょう。

今回はWordPress Popular Postsを追加したいので、WordPress Popular Postsを検索して探して追加してみてください。
すると、WordPress Popular Postsの機能の編集画面の様なものが出てくると思います。
自分好みの人気記事ランキングを出力させるように、項目を設定して右上にある「更新」ボタンを押します。

# ウィジェットを表示させる
固定ページのテンプレートファイルを開き、function.phpで設定したid名を利用して以下なコードを追加するだけで、ウィジェットへの追加内容が表示できます。

```php
<div id="sidebar">
    <?php dynamic_sidebar('sidebar'); ?>
</div>
```

ウィジェットは幾つでも追加できるので、Topのサイドバーはこれ、下層ページのサイドバーはこれ、、、という様に簡単にカスタマイズできます。便利ですね。
投稿フォームでの改行を反映するには

## 解決したい問題
フォームオブジェクトで作ったフォームから投稿すると投稿時の改行が反映されない。

## 解決法
app/views/dialog.html.erb
```ruby
<%= h(@dialog.memo).gsub(/\n|\r|\r\n/, "<br>").html_safe %>
```

**h(@dialog.memo)**
hメソッドは、渡された文字列をHTMLエスケープするためのメソッドです。これにより、悪意のあるスクリプトやHTMLタグが表示されないようになります。

**gsub(/\n|\r|\r\n/, "＜br＞")**
gsubメソッドは、正規表現を使用して文字列内の特定のパターンを別の文字列に置換するためのメソッドです。ここでは、改行文字（\n）、復帰文字（\r）、および復帰と改行の組み合わせ（\r\n）を<br>タグに置換しています。つまり、改行をHTMLの改行タグに変換しています。

**html_safe**
html_safeメソッドは、文字列をHTMLとして解釈するためのメソッドです。これにより、HTMLタグが実際にHTMLとして表示されます。
[JavaScript]変数初期化などに使う三項演算子conditional/ternary operation)について

JavaScript のコードで3項演算子を使って変数の初期化がされていましたが、よくわからなかったので調べた時のメモです。

# 前提

+ JavaScript 初心者です
+ 検証は Node.js v18.12.1

# 参考資料

忘れたら以下を見るようにする

+ [条件・三項演算子(conditional/ternary operation)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Conditional_operator)
+ [三項演算子の適切な使い方（条件演算子）](https://qiita.com/smicle/items/7d3b9881834dc0142fb7)

```構文
condition ? exprIfTrue : exprIfFalse
```

> condition
> 値が条件として使用される式です。

> exprIfTrue
> condition が真値 (true と等しいか、 true に変換できる値) と評価された場合に評価される式です。

> exprIfFalse
> condition が偽値 (false と等しいか、 false に変換できる値) と評価された場合に評価される式です。


# 検証

参考資料を見た方がいいが自分でも試した内容をメモしておく

以下のようなコードがある。

```
var age = 26;
var beverage = (age >= 21) ? "ビール" : "ジュース";
console.log(beverage); // "ビール"

age = 18;
beverage = (age >= 21) ? "ビール" : "ジュース";
console.log(beverage); // "ジュース"
```

これを実行するとこうなる

```
$node test.js
ビール
ジュース
```

以下では `age` は 26 で 条件式 `age >= 21` の結果が `ture` なので `ビール` が代入される

```
var age = 26;
var beverage = (age >= 21) ? "ビール" : "ジュース";
console.log(beverage); // "ビール"
```

以下では `age` は 18 で 条件式 `age >= 21` の結果が `false` なので `ジュース` が代入される

```
age = 18;
beverage = (age >= 21) ? "ビール" : "ジュース";
console.log(beverage); // "ジュース"
```
【Query Builder：Expression】Try using DivSafe function

This time, we will use the **DivSafe** function from one of expression functions in [Sharperlight](https://sharperlight.com/).
Using this function can prevent error caused by **dividing n by 0**.
### Preparing a query ###
Launch `Query Builder` from the Sharperlight application menu.
Instead of querying the database, here we prepare a custom dataset.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/50d26d5b-efc1-69e2-72f8-f52b502f4575.png)
The dataset definition looks like this.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/6c84865c-7561-ec5a-60cf-9f5a53d363de.png)
Define outputs items.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/02c0a25a-12ef-d5a7-ad92-1eaf4c240242.png)
The query result looks like this.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/d832e32b-f553-7b36-1ed0-927d8c9c758a.png)
### Adding DivSafe function ###
Right-click in the output area and select **Add Extended Expression**.
Fill in the **Output Name** and **Description** in the `General` tab.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/dc2d51b0-f0fd-0d2f-6399-cbc51c2dab30.png)
Go to `Expression` tab. Find the **DivSafe** function in the function list and double-click to transfer the template to the upper editor area.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/dee743e7-507f-27c8-c7b0-a005d6443dde.png)
Edit the template as follows.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/31470ffe-f878-c944-6a0e-1825aeb31a9c.png)
Click `OK` to save it.
Add one more expression which does division but it doesn't use DivSafe function.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/22e0e2f6-c306-4dd2-6725-4367c91c2588.png)
Click `OK` to save it.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/1c8908c3-1923-314e-80f5-c52a11782b5f.png)
### Verification ###
You can see DivSafe function works well.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/a465b316-6f5a-1d04-0dee-906cf8e35264.png)

I hope this will help your work.
ChatGPT/何かの担当者としてアドバイスするときのプロンプトテンプレート

## 状況
自分が何かしらの立場として、アドバイスをしないといけないときのChatGPTへプロンプト例です
[]を適宜変えてください。
自分は学校の課題を書くのに役立ちました。

## プロンプト

```
context:
----
[
手元にある情報
例）
・Aさんは～日前に○○を購入
・○○の故障の原因はxxであることがおおい
・詳しいことはわからない
]

----

instruction:
----
今[相手]と[役職]が対話している。
[役職]は助言しようとしている
----
answer:
[役職]「
```
BDE=>FireDAC変換 TFDMemTable活用

（これは、以前ブログに書いていたものをQiitaに加筆、修正し再投稿したものです）

## BDE から FireDACへのマイグレーション TFDMemTable活用

BDEで作成されたC/Sモデルでは、データの編集に際して、サーバーからクライアントPCのParadoxのテーブルに一旦コピーして、編集し、その後サーバーに登録するという方法がとられるケースが多い。
また、印刷時に一時的な加工、編集でParadoxのテーブルを使うケースもある。

BDEからFireDACへマイグレーションするときの、上記のような、Paradoxのテーブルをどうするか。
この場合は、TFDMemTableに置き換える。

プログラムでは、TTableコンポーネントを使っていると思うので、.dfmファイルのTTableをTFDMemTable(*1)に書き換える。
（TTableについては、Field定義は事前に取り込んでおく必要はあります）

弊社の今までの実績では、LookupFieldやCalcFieldもそのままの定義、コードで使えます。また、イベントも変更無く使用可能です。
(すべてのイベント、メソッドの確認は行っていません)

注意点としては、TFDMemTableは、オンメモリで処理しますので、データの処理状況確認等が必要な場合は、必要なタイミングでSaveToFile()メソッドなどで、ファイルに出力することになります。
FDQueryで読み込んだデータは、
FDMemTable.Data := FDQuery.Data;
でコピーできます。
処理前は、FDMemTableは、Closeしておくことが必要です。

(*1)Delphiバージョンによっては、TADMemTable　(AnyDAC)
東京の気温を現実の7セグで表示するWEBAppをGPT-4と作る

# はじめに
唐突に「あー！７セグに、なんでも鑑定団みたいな感じで数字を表示したい！！！ 気温とか出したい！！！」
と思うこと、人生に５度ぐらいは有ると思います。

<figure>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605138/c05afb0c-b346-5c57-6d37-3581685f3404.png" alt="7セグimage" width="300"><br>
<figcaption><a href="https://coconutsdisk.com/news/kanteidan/">『開運なんでも鑑定団』にレコード鑑定士として出演いたします！ | COCONUTS DISKより引用</a></figcaption></figure><br>

<br>
とは言ってもモノホンの７セグメントディスプレイはハードウェア制御が絡み、  
表示させるところまでが色々と面倒です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605138/5eb82815-87ed-8432-d7ed-09beb6de7279.png" alt="7セグimage" width="300"><br>
<figcaption>[8.]と表示できる、これが7セグ</figcaption>

しかし近日、弊社ビット・トレード・ワンより、  
USB経由のシリアル通信だけで英数字等の表示が可能なAD7SGPRという製品が出ます。
マイコンにRP2040、7セグドライバにTM1638を使用しています。[回路図等Githubで公開中](https://github.com/bit-trade-one/AD7SGPR)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605138/b0d44fed-0970-e135-9b72-1f10eaea4d83.png" alt="AD7SGPR本体画像" width="680"><br>
<figcaption>AD7SGPR本体画像</figcaption>

USBシリアル通信だけで文字を表示できるので、WEBSerialAPIを使用すれば、
ブラウザ上で様々なAPIから引っ張ってきた数字を7セグに表示することとかが可能です。
ブラウザで作成すればマルチプラットフォーム対応にもなりますし。
![接続イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605138/af602d04-4c8c-0590-479b-3f085c10d05b.png)接続イメージ

本記事ではAD7SGPRを使って東京の気温を7セグで表示するwebアプリを
GPT4に書いてもらいます。

# ソースを持って来てGPTにコーディングさせる
いくらGPT-4にコーディングしてもらうとしても中々面倒な作業です。
そこで骨となるソースコードを用意します。  
弊社からAD7SGPRでyoutubeチャンネル登録者数が表示できる  
WEBアプリがMITと同等のライセンスで[公開](https://github.com/bit-trade-one/AD7SGPR-youtubeCh)されているため、

このコードのSerial通信部分などは流用し、APIから値を取ってくるところだけを書いてもらいます。
![流用説明](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605138/44f6cc49-6e9e-cefa-bf3f-11e5e838e518.png)


私は曖昧な指示をしてAI(部下)が面白いものを作ってくれるのを待つという、  
庵野秀明氏にしか許されない方法でAIに成果物を作ってもらうのが好きなので、
天気を取得するAPIを指定しないで作ってもらうことにしました。楽ですしね。

# GPT-4への指示
以下のようにGPT-4に指示をしました。

<b>「以下はyoutubeのチャンネル登録者数を所得し、 その数をシリアル通信で送信するwebアプリのソースです。コレのyoutube登録者数取得部分を 東京の気温を取得するAPIに置き換えてください。
<サンプルソースをベタ貼り>」</b>

  
簡単なwebアプリの場合、HTML,CSS,JSがそれぞれ別ファイルになっていないものを渡したり、出力してもらうのが楽です。

私の中々に大雑把な指示を元に、GPT-4は返信でソースを書いてくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605138/ff246313-c7e3-0442-0ace-4e644532fc11.png)



優秀ですね。 後は動くかを確認し、エラーコードなどが出た場合はGPT-4に報告し、仕上げていきます。

今回のやり取りは<a href="https://chat.openai.com/share/488ec194-3195-4759-aeea-2a8429ede140">こちら</a>からご覧いただけます。 
(最後の方なんてこの記事の雛形書かせてます......)

# 完成物
動作の様子
![AD7SGPR_2動作.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605138/79c31264-61b9-f228-e416-87eba3b1a526.gif)

Appの画面
![画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605138/55f7d480-d344-0ad3-acd2-6f620b61781a.png)
ソースを提示したことも有り、  
試行錯誤も合わせて10回程度の会話ラリーで
webアプリから7セグにAPIの値を表示させることに成功しました！  

APIキーと頻度を設定すると東京の気温を取得し、  
シリアル接続ボタンからAD7SGPRと接続を行うと値を表示できます。  

(なんでも鑑定団風のアニメーションは本体側のファームウェアで実現しています。電源起動時のデフォルトでは値表示前のアニメーションは無しになってます。)

本WEBAppをGtihubにソースを上げたので閲覧は<a href="https://github.com/bit-trade-one/AD7SGPR-TokyoWeather">こちら</a>からどうぞ。

皆様も7セグ表示欲が出てしまった際はこの記事を参考にしてください。


以上です。
Error when deploying　apex


+ [UNKNOW_EXCEPTION: An unexpected error occurred...](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000PfC9q)

:::note alert
'UNKNOWN_EXCEPTION: An unexpected error occurred.  Please include this error Id if you contact support: 1864777442-209431 (1156755792)'. No other information.

...VARIABLE_SCOPE_BEGIN | [21] MetadataTriggerHandler.INVALID_CLASS_ERROR |String | false|true
...VARIABLE_SCOPE_BEGIN | [19] MetadataTriggerHandler.INVALID_TYPE_ERROR |String | false|true
:::

検証できてないApex Classがある。何か設定が変更されているがテストクラスが対応できていない感じ
javascriptのcontextmenuのOS依存について

# 環境
## 環境A
Microsoft Windows [Version 10.0.19045.2965]
chrome: 114.0.5735.110（Official Build） （64 ビット）
## 環境B
macOS Monterey 12.6
chrome: 114.0.5735.110（Official Build） （arm64）

# 状況
とあるWebアプリケーションでjavascriptによる右クリックメニューを実装した。
暗黙的に環境Aで動くように実装していたので、環境Bで動かしたときにおかしな挙動になった。

# 原因
[このサイト](https://ja.javascript.info/mouse-events-basics)を用いて挙動を調査したところ
環境Aでは、押しでmousedown、離しでmouseup, contextmenuだったのに対して
環境Bでは、押しでmousedown, contextmenu、離しでmouseupであった。
# まとめ
OSによってはイベントの発火タイミングも違えばイベント順も違った。
WebアプリケーションならOSに依存しないと高をくくっていたが足元を掬われた。
【備忘録】RPiにのUSBに接続されている機器のIDを確認する方法

## １．ラズパイへアクセスする
Raspberry PiにSSHやターミナルでログインします。

## ２．IDを調べる
①確認したい部品(該当部品）をUSBから外した状態で以下のコマンドを入力
```
ls /dev/serial/by-id
```
②確認したい部品(該当部品）をUSBに挿入し以下のコマンドを入力

```
ls /dev/serial/by-id
```
①で表示されず、②で表示されるのが
接続されているUSBデバイスIDとなる
JetsonNanoにPytorch(v1.10.0)をインストールする

(2025/06/20 追記)
pipでインストールするcythonのバージョンが3.0以上だとnumpyのインストールに失敗します。
そのため、3.0より下のバージョンでインストールするように変更します。


# はじめに

JetsonNanoにPytorchとtorchvisionをインストールするのに大変苦労したので備忘録として残しておきます。
他の誰かの参考になれば嬉しいです。

Jetson公式フォーラム
https://forums.developer.nvidia.com/t/pytorch-for-jetson/72048

公式フォーラムにインストール方法が記載されていますが、少々わかりにくい所もあったのでコードを載せます。
今回はJetsonNanoで使えるPytorchの中で一番バージョンが新しい1.10.0を選択しました。
Jetpackは最新の4.6.3を使用しています。(2023年06月14日現在)

## まずはアップデートから
```
sudo apt update
sudo apt upgrade
```

## pytorch(ver1.10.0)のインストール
```
wget https://nvidia.box.com/shared/static/fjtbno0vpo676a25cgvuqc1wty0fkkg6.whl -O torch-1.10.0-cp36-cp36m-linux_aarch64.whl
sudo apt-get install python3-pip libopenblas-base libopenmpi-dev libomp-dev
pip3 install "Cython<3.0" #2025/06/20 編集
pip3 install numpy torch-1.10.0-cp36-cp36m-linux_aarch64.whl
```

## torchvision(ver0.11.1)のインストール
```
sudo apt-get install libjpeg-dev zlib1g-dev libpython3-dev libopenblas-dev libavcodec-dev libavformat-dev libswscale-dev
git clone --branch v0.11.1 https://github.com/pytorch/vision torchvision
cd torchvision
export BUILD_VERSION=0.11.1 
python3 setup.py install --user
cd ../
pip install 'pillow<7'
```

torchvisionのインストールには**1時間弱**かかりました。
気長に待ちましょう。
また、エラーメッセージのようなものが表示されましたが放置で大丈夫です。
私はエラーメッセージのようなものが表示されていたのでインストールに失敗したのかと思ってしまい、途中で止めてしまいました。
そのせいでインストールが上手くいかず、時間をどろどろと溶かす羽目になったのです……

## インストールが上手くいったことを確認する
```
python3
> import torch
> import torchvision
> torch.__version__
> torchvision.__version__
> #GPUが使えるか確認(使用可能の時はtrueを返す)
> print('CUDA available: ' + str(torch.cuda.is_available()))
> #cuDNNのバージョンを確認
> print('cuDNN version: ' + str(torch.backends.cudnn.version()))
```

# おわりに
torchvisionのインストールが長すぎて心配になっても気長に待ちましょう。
初めての投稿なのでわかりにくい所もあったと思いますが、ご容赦ください。
【Query Builder：Expression】Try using RowSkip statement

In this article, I will use the **RowSkip** statement, one of the Sharperlight expressions.

Launch the `Query Builder` from the [Sharperlight](https://sharperlight.com/) application menu.
Make the following settings in the filter area;
- `Product` is **Dynamic 365 Business Central**
- `Company` is **DEFAULT**
- `Table` is **G/L Account**
- `Account No` is **\<ALL>** (This is a mandatory filter with G/L Account table)
- `Account Category` is **Assests** (This is a manual set filter. From the Selection list below by drag&drop) 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/27946b46-a603-f61c-caff-d9599a9204f2.png)
Set the following fields in the output area:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/fbc98ca4-373a-4fd2-fd75-074af195675c.png)
After completing the settings, check the query immediately with the preview function!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/2778b79b-d9ae-e2c0-dd6a-d0eb05e9b18d.png)
Now add the **RowSkip** statement.
Go back to your query and right click on the output area and select **Add Expression**.
When the Output Options dialog opens, find the **RowSkip** statement in the function list and double-click to transfer the template to the upper editor area.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/daed89fc-419b-ed08-cfc8-838187cda4c9.png)
Edit the template as follows. It is a definition that skips the row when `Account Type` is **Posting**.
```
RowSkip( {%AccTyp}="Posting")
```
After pressing `OK`, you will be prompted with the message **Change data type to Boolean**, select **Yes**.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/8710019a-8d86-17cd-c637-968bb1581214.png)
Now for the preview! !
All lines where `Account Type` is **Posting** are skipped.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/9b4cb689-7605-b3bf-a2c3-65fb9190c5e3.png)

This can be done by setting `Account Type != "Posting"` in the filter, but I used it like this to check the **RowSkip** statement.

I hope this will help your work.
AWSのログイン通知　wip

会社でAWSにログインしたときに不正ログイン通知が届く設定が昔からのこっており、
誰がログインしたのか申告制という運用だったので、IAMユーザ名を自動で出力するようにがんばった記録です


途中ですので

1. IAMユーザーのログインイベントを検出するために、Amazon EventBridgeを使用します。EventBridgeはAWSのイベント駆動型サービスであり、AWSアカウント内のさまざまなイベントに対してルールベースのアクションを設定できます。

2. EventBridgeのルールを作成します。ルールはイベントソース（CloudTrail）とイベントパターン（ログインイベント）に基づいて定義されます。例えば、次のようなイベントパターンを設定することができます:

```json
{
  "source": ["aws.cloudtrail"],
  "detail-type": ["AWS Console Sign In via CloudTrail"]
}
```

このイベントパターンは、AWS CloudTrailのログインイベントを検出します。

3. ルールのターゲットとして、AWS Lambda関数を指定します。Lambda関数はイベントがトリガーされると実行されるコードのエンドポイントです。

4. Lambda関数内でログインイベントを受け取り、必要な情報を抽出します。IAMユーザーのユーザー名やその他の詳細情報を取得することができます。

5. Slackへの通知を行うために、Lambda関数内でSlackのWebhookを使用します。WebhookはSlackにメッセージを送信するためのエンドポイントです。

6. Lambda関数は抽出した情報を使ってSlackへの通知メッセージを作成し、SlackのWebhookにPOSTリクエストを送信します。通知メッセージはユーザー名やログインタイムスタンプなどの情報を含むことができます。

7. Slack側でWebhookを受け取り、通知メッセージを指定したチャンネルに表示します。メッセージはログインしたIAMユーザーの情報を示し、ログインが行われたことを通知します。
base64コマンドのエイリアス

`base64`コマンドを使う時、毎回`echo`を噛ませるのが面倒なのでエイリアスを設定する。

```sh
# エンコード
$ echo foobar | base64
Zm9vYmFyCg==

# デコード
$ echo Zm9vYmFyCg== | base64 -D
foobar
```

## エイリアスの設定

リダイレクト`<<<`[^1]を用いる。

[^1]: 正式名称は[`Here Strings`](https://www.gnu.org/software/bash/manual/bash.html#Here-Strings)

```sh:.zshrc | .bashrc
alias b64='base64 <<<'
alias d64='base64 -D <<<'
```

Stack Exchangeの[こちらの回答](https://superuser.com/questions/120796/how-to-encode-base64-via-command-line#answer-1053880)を参考にしました。

### 確認

```sh
$ b64 foobar
Zm9vYmFyCg==                                                                               

$ d64 Zm9vYmFyCg==
foobar

$ b64 "line
> break"
bGluZQpicmVhawo=

$ d64 bGluZQpicmVhawo=
line
break
```

### 改行を除く

上記の方法ではエンコードした際に改行`Cg==`が入ってしまうので、これを除きたい場合は下記のようなシェル関数を定義します。

```sh:.zshrc | .bashrc
function b64() { echo -n $1 | base64 }
function b64() { printf '%s' "$1" | base64 } # @ko1nksm さんに教えていただきました
```

:::note warn
`.zshrc`(`.bashrc`)の編集後に`source ~/.zshrc (.bashrc)`を実行しても反映されない場合は、ターミナルを再起動してください。
:::
接地判定をCheckSphereとLayerMaskを使って行う

プレイヤーの接地判定のメモ

レイヤーにGroundを追加する
地面とするオブジェクトのレイヤーにGroundを設定する
プレイヤーのスクリプトに以下のコードを書く
```csharp
    
    public bool Grounded = true;
    public float GroundedOffset = -0.14f;
    public float GroundedRadius = 0.5f;
    public LayerMask GroundLayers;

    private void GroundedCheck()
    {
        // オフセットを計算して球の位置を設定する
        Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z);
        Grounded = Physics.CheckSphere(spherePosition, GroundedRadius, GroundLayers, QueryTriggerInteraction.Ignore);
    }
```
【ChatGPT】新機能「Function calling」が凄すぎた

# tl;tr
ChatGPTの新機能「Function calling」はすごい。
今後注目される機能になっていくと思われる。
# ChatGPTの新機能「Function calling」について
6/13のアップデートで、ChatGPTに新たな機能「Function calling」が実装
されました。

https://openai.com/blog/function-calling-and-other-api-updates

「Function calling」は、ChatGPTに「**呼び出すことができる関数**」を教えておく機能で、ChatGPTがこの関数を呼び出せるようになります。
この機能を活用すると、ChatGPTを経由することで、曖昧な指示でも関数が実行できるようになります。

# 「Function calling」の概要と可能性
### 概要
ChatGPTに呼び出せる「functions」をパラメーターとして渡します。
この状態で通常通りChatGPTに送信をすると、関数の呼び出しを要求するレスポンスが帰るようになります。このレスポンスを受けとった時に、関数を実行して結果をChatGPTに再度返却します。

<details><summary>関数の形式</summary><div>

```
const functions = [
  {
    name: "insert_todo",
    description: "Insert a new todo",
    parameters: {
      type: "object",
      properties: {
        title: {
          type: "string",
          description: "The title of the todo",
        }, 
      },
      required: ['title'],
    }
  },
  {
    name: "get_todos",
    description: "Get all todos",
    parameters: {
      type: "object",
      properties: {},
      required: [],
    }
  }
];
```

</div></details>

![図7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534453/becd8ec9-65f3-e2c0-eaf6-792055463c24.png)


### 可能性
この機能のすごいところは「**曖昧な指示**」を「**関数呼び出し**」という具体性のあるものに変換してくれることです。
例えば、ユーザーが「掃除をしておいて」という曖昧な要求を出した際にも、「掃除の実行」という具体的な手段に変換してくれます。
ユーザーの抽象的な指示を具体化してくれるため、とんでもないアプリケーションが作成できるようになります。

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534453/d190e8a8-58b8-e661-00c1-1ee71bd289ca.png)

# Function callingの利用: ToDoアプリ作成
今回は具体例として、「Function calling」を活用したToDoアプリを作成しました。
ChatGPTがユーザーの指示を受けて間接的にアプリケーションを操作してくれるので、日常会話のような指示でもアプリが正しく動作します。

## ToDoアプリの概要
ToDoアプリは２つの関数を持ちます。
- addToDo: ToDoの追加
- getToDos: ToDoの取得

ChatGPTにはすでにこの関数について伝えてあり、必要に応じてこの関数を呼び出します。

![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534453/719d2066-c51e-d6a6-ab00-ec3682d6c3f7.png)

## 動作
### addToDo
ChatGPTにToDoを追加する指示を出します。
`「リリース」をToDoリストに追加して`
すると、下のようなレスポンスを返しました。
```
> 「リリース」をToDoリストに追加して
(ログメッセージ: addTodo('リリース')が実行された)
ChatGPT: 「リリース」がToDoリストに追加されました。
```

![図4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534453/5baa2c37-26d5-2a41-5f3c-85aab0560726.png)


### getToDos
ChatGPTにToDoを取得する指示を出します。
`ToDoに何があるか教えて`
すると、下のようなレスポンスを返しました。
```
> ToDoに何があるか教えて
(ログメッセージ: getTodos('リリース')が実行された)
ChatGPT: 現在のToDoは、以下のものがあります：
1. リリース実行（2021年6月13日に作成されました）
他に何かお手伝いできますか？
```

![図5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534453/cf26e1d7-cdc3-6776-1665-261f11d27d35.png)


# まとめ
「Function calling」は曖昧なユーザーの動作を具体化してくれるという機能です。
これによってできるようになることはたくさんあると思います。
例えば、下のようなアプリケーションは作成可能になりそうです。
- タスク・スケジュール管理
- カスタマーサービスの効率化
- RPGなどのゲームの操作

また、副次的な効果として、リクエストに必要なメッセージを小さくすることができるので、使用料金を抑えることも期待できそうです。

自分としては「ToDoやスケジュール」と「音声認識」を組み合わせてAIアシスタントを作成したいなと思いました。
このToDo管理だけでも自分の秘書のように振る舞ってくれるのでロマンを感じます笑
かなりアイデアを触発される機能なので、ぜひ触ってみることをお勧めします！

# 補足
作成したアプリケーションは下のURLからみることができます。

https://github.com/semimaru141/function-test

# 追記
この記事で紹介した機能を使用し、実際にアプリケーションを作成してみました。
作成するにあたって行った「**対策・工夫**」とその時に感じた「**良かった点・注意すべき点**」についてまとめ、記事にしています。
よろしければご一読ください。

https://qiita.com/Haru141/items/54afcdf465039ca26621
PHPでLINE通知を行う

こんにちは。

サーバが死んでしまった場合などにLINEで通知を送る方法について調べました。
LINEのグループにも送ることができるため、複数人での開発などに利用することができます。

なお死活監視であれば専用のサービスを使った方が通知方法なども含め便利です。

# 下準備
LINE側で通知を送るグループ（トークルーム）を作成しておきます。

[LINE Notify](https://notify-bot.line.me/)でアカウントを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/a8ee40aa-3190-78ba-549e-eecf5258c4b3.png)

送信先のトークルームを選択し、トークンを発行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/c6493779-913a-3f7b-cf54-c63a17d7cd2e.png)

発行されたトークンを控えておきます。

![Screenshot 2023-06-14 at 14.51.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/a7fb33ff-ad7f-c0da-c830-d6fc81668450.png)

シェルから送信のテストを行っておきます。

```

```


下記のようなコードで通知を送ります。

```php
<?php
define('LINE_NOTIFY_TOKEN', 'xxxxxx');


/**
 * LINEへの通知。
 *
 * @param $message
 *
 * @return void
 */
function lineNotify( $message = '' ) {
	$url = "https://notify-api.line.me/api/notify";
	$ch  = curl_init(); // はじめ
	curl_setopt( $ch, CURLOPT_URL, $url );
	curl_setopt( $ch, CURLOPT_VERBOSE, 0 ); // 詳細を表示しない
	curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );//変数に保存する
	curl_setopt( $ch, CURLOPT_HEADER, true ); // ヘッダも出力したい場合

	curl_setopt( $ch, CURLOPT_HTTPHEADER,
		array( 'Authorization: Bearer ' . LINE_NOTIFY_TOKEN ) );

	$post_data = array( 'message' => $message );

	curl_setopt( $ch, CURLOPT_POST, true );
	curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $post_data ) );

	$res = curl_exec( $ch ); //実行
	curl_close( $ch ); //終了
}
```
円ドル為替レート（実勢相場と購買力平価）のグラフ化

# はじめに
円ドル為替レートの推移を実勢相場とともに購買力平価（消費者物価、企業物価指数、輸出物価基準のもの）を描いてみた。
データは、公益財団法人国際通貨研究所（ https://www.iima.or.jp/ ）から出されているExcelファイルのデータ（ https://www.iima.or.jp/docs/ppp/pppdata.xlsx ）にもとづいている。
もともとグラフも提供されているので描画の必要はないが、Excelファイルの読み込みの備忘録。
（2024/6/12追記）
輸出物価が90年基準から、他の物価指数同様に73年基準に変更されていたので、コードを若干修正した。

# コード
今回はmatplotlibでグラフを描くので、日本語フォントの準備から。
```Python
pip install japanize_matplotlib
```

以下、コード本体。
```Python
# モジュールの読み込み
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.dates as mdates
import japanize_matplotlib

# データの読み込み
url = "https://www.iima.or.jp/docs/ppp/pppdata.xlsx"
sheet_name = "ドル円（USD JPY）"
data = pd.read_excel(url, sheet_name=sheet_name, skiprows=2, dtype=str)

# データの前処理
blocks = [data.iloc[:, i:i+7] for i in range(0, data.shape[1], 7)]
blocks = [block.iloc[:, :-1] for block in blocks[:-1]] + [blocks[-1]]

combined_df = pd.DataFrame()

for block in blocks:
    block = block.copy()
    block.columns = ['Year', 'Month', 'Monthly Average' , 'CPI', 'CGPI', 'EPI']
    block = block.iloc[1:, :]
    block['Year'] = block['Year'].fillna(method='ffill')
    block.dropna(subset=['Monthly Average', 'CPI', 'CGPI', 'EPI'], how='all', inplace=True)
    block['Date'] = pd.to_datetime(block['Year'].astype(str) + '/' + block['Month'].astype(str), format='%Y/%m')
    block.drop(['Year', 'Month'], axis=1, inplace=True)
    block.set_index('Date', inplace=True)
    for col in ['Monthly Average', 'CPI', 'CGPI', 'EPI']:
        block[col] = block[col].astype(float)
    combined_df = pd.concat([combined_df, block])

# グラフの描画
plt.figure(figsize=(15, 10))
plt.title(
    f'円ドル為替レート：実勢相場と購買力平価\n{combined_df.index.min().strftime("%Y/%m")}～{combined_df.index.max().strftime("%Y/%m")}', 
    fontsize=20
)
plt.xlabel('年', fontsize=15)
plt.ylabel('為替レート（円/ドル）', fontsize=15)

for col, label in zip(
    ['Monthly Average', 'CPI', 'CGPI', 'EPI'],
    ['実勢レート', '消費者物価PPP（73年基準）', '企業物価PPP（73年基準）', '輸出物価PPP（73年基準）']
):
    plt.plot(combined_df[col], linewidth=2 if col == 'Monthly Average' else 1, label=f'{label}：{combined_df[col].iloc[-1]:.2f}')

plt.gca().xaxis.set_major_locator(ticker.FixedLocator(
    mdates.date2num(pd.date_range(start='1980', end='2021', freq='10YS').to_pydatetime())
))
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y'))

plt.legend(fontsize=12)
plt.show()
```
* 出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3305624/3dc980e5-dae7-5800-af86-c66657d088c5.png)

# おわりに
このExcelファイルは、1970年代から10年ごとにデータがブロック化され、再利用がしづらくなっている。私の能力で整理するのはなかな大変だった。
GitHub Copilotの概要

サブライムコンサルティングの大塚です。  
今回はGitHub Copilotの概要についてまとめてみました。  

# GitHub Copilotとは

GitHub Copilotは、AIを使用してプログラミングを支援してくれるツールです。自然言語で指示を出して、ソースコードを提案してくれます。  

GitHub CopilotはChatGPT等で有名なOpenAIによって作成された生成的AIモデル`Codex`を使用しています。  
`Codex`はGitHubをはじめ一般に公開されているソースコードや自然言語テキストを入力して事前に学習されたコーディングに特化したモデルです。  
GitHub Copilotはクラウド上にある`Codex`に対してユーザーから受け取った自然言語による指示を送信し、指示に従ったソースコードを受信して、ユーザーに提案します。  

ただし、`Codex`は`GPT-3`をベースとしており、少し古いモデルです。  
`Codex`の[公式サイト](https://platform.openai.com/docs/guides/code)でも`Deprecated(非推奨)`の扱いとなっています。  
2023年3月にGitHub社から発表された`GitHub Copilot X`では2023年7月時点でOpenAIによる最新の大規模言語モデル(LLM)である`GPT-4`がベースとなっており、精度の向上も期待しています。  

## サポートされる開発環境

2023年7月時点において、[公式サイト](https://docs.github.com/ja/copilot/getting-started-with-github-copilot)を確認すると以下の開発環境がサポートされています。  
各開発環境用のプラグインが用意されており、それをインストールして、GitHub Copilotの機能を使用します。

* JetBrains IDEs
* Vim/Neovim
* Visual Studio
* Visual Studio Code

## コメントによる指示

GitHub Copilotでは各言語のソースコードのコメントに自然言語で指示を記述すると、指示に従ったソースコードを提案してくれます。  
以下はJetBrains社のIntelliJにGitHub Copilotプラグインをインストールして、Javaでソースコードを提案してもらう簡単な例となります。 
![github_demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476418/0b6935a7-c8c6-1d12-773f-519c26b12a17.gif)


基本的には、コメントで指示を記述して、Enterキーを押してしばらくするとソースコードが提案されます。  
提案されたソースコードを採用する場合は`Tab`キーを押して確定します。  
想定したものと異なる場合は代替候補を表示することもできます。Windowsであれば`Alt`+`[`もしくは`Alt`+`]`、Macであれば`Option`+`[`もしくは`Option`+`]`を押すことで代替候補のソースコードの表示することができます。　　


## 別タブで開いているソースコード

GitHub Copilotの大きな特徴として、IDEで別タブで開いているソースコードもインプットとすることが出来ます。  
別タブでソースコードをインプットにする簡単な例を試してみます。  


### 別タブに何を開かない場合

以下の動画はシステム日付を取得して文字列として返却するメソッドをGitHub Copilotに提案してもらった例となります。  
旧来の`java.util.Date`を使用したソースコードを提案してくれました。  

![github_demo2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476418/0f8d0ef4-66f4-6d1e-2bc7-4eeaff21efe4.gif)

### 別タブで参考となるソースコードを開いた場合

旧来のものではなく、Java8から導入されたタイムゾーン付きの日時を扱う`java.time.ZonedDateTime`を使用したい場合を想定します。

別タブで`java.time.ZonedDateTime`を使用したソースコードを開いた状態でGitHub Copilotに同様の指示を出すとZonedDateTimeを使用したソースコードを提案してくれます。  

![github_demo3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476418/7bb05611-3009-25c9-bd1c-a0c848c81a96.gif)


なお、上記のような単純な例であれば、コメントで以下の通り追加の指示を与えれば、想定通りのソースコードを提案してくれることも多々あります。  
```java
    // システム日付を文字列として返却するメソッド
    // java.time.ZonedDateTimeを使用
```


# 参考情報

GitHub Copilotの情報はまだまだ少なく、日本語の書籍は2023年7月時点で一冊も出版されていません。英語の書籍は出版されていますが、かなり数が少ないです。

以下はGitHub Copilotを使い始めるにあたり参考となるサイトです。  

[GitHub Copilot に関するドキュメント](https://docs.github.com/ja/copilot)  
公式サイトの日本語版です。  
必要最低限の情報が記載されており、一通り目を通すことをお勧めします。

[GitHub Copilot documentation](https://docs.github.com/en/copilot)  
公式サイトの英語版です。  

[AIネイティブ開発ガイド](https://www.ai-native.dev/docs/v/ja/)  
上記サイトの冒頭の記述の引用です。  

```text
このドキュメントでは、GitHub Copilot などをつかった
AI ネイティブ開発におけるベストプラクティスを特定の形式でまとめて、
簡単に理解、評価、そしてあなたの状況に適用できるようにしています。
```

具体的な使い方等は記載されていませんが、考え方的な部分でとても参考になる情報がまとめられています。  
それほどボリュームもないので、こちらも一通り目を通されることをお勧めします。  


では、本記事は以上となります。
Next.js 13 で deck.gl 8.9 を使う時の、モジュール読み込み（ESM）の設定

例えば、Next.jsの `app/page.tsx` を以下のように記述したとします:


```tsx
'use client'

import DeckGL from '@deck.gl/react/typed';
import {LineLayer} from '@deck.gl/layers/typed';


// Viewport settings
const INITIAL_VIEW_STATE = {
  longitude: -122.41669,
  latitude: 37.7853,
  zoom: 13,
  pitch: 0,
  bearing: 0
};

// Data to be used by the LineLayer
const data = [
  {sourcePosition: [-122.41669, 37.7853], targetPosition: [-122.41669, 37.781]}
];


export default function Home() {
  const layers = [
    new LineLayer({id: 'line-layer', data})
  ];

  return <DeckGL
  initialViewState={INITIAL_VIEW_STATE}
  controller={true}
  layers={layers} />
}
```

- deck.gl公式ドキュメントのサンプルが元 - 参考: [Using deck.gl with React | deck.gl](https://deck.gl/docs/get-started/using-with-react)
- 冒頭の `'use client'` により、クライアント・コンポーネントへ - 参考: [Getting Started: React Essentials | Next.js](https://nextjs.org/docs/getting-started/react-essentials#client-components)

## エラー

しかし上記では、以下のようなエラーが発生します:

```
Failed to compile

./node_modules/@deck.gl/layers/dist/es5/text-layer/font-atlas-manager.js:17:0
Module not found: ESM packages (@mapbox/tiny-sdf) need to be imported. Use 'import' to reference the package instead. https://nextjs.org/docs/messages/import-esm-externals

https://nextjs.org/docs/messages/module-not-found

Import trace for requested module:
./node_modules/@deck.gl/layers/dist/es5/text-layer/text-layer.js
./node_modules/@deck.gl/layers/dist/es5/index.js
./app/page.tsx
```

言及されているページ:

- [import-esm-externals | Next.js](https://nextjs.org/docs/messages/import-esm-externals)
- [module-not-found | Next.js](https://nextjs.org/docs/messages/module-not-found)


## 解消

上記のエラーを解消するには、 `next.config.js` へ以下のように設定を追加します:


```diff
- const nextConfig = {}
+ const nextConfig = {
+    transpilePackages: ['@deck.gl/layers', '@mapbox/tiny-sdf'],
+    experimental: {
+        esmExternals: 'loose',
+    },
+}
```

エラーメッセージでも言及される [import-esm-externals | Next.js](https://nextjs.org/docs/messages/import-esm-externals) というページで、 `experimental.esmExternals: 'loose'` を使う方法が提案されています。これにより、このエラーを自動修正するよう試みてくれるそうです。



## 参考

[SSR Error After Upgrading from 8.8 to 8.9 · Issue #7735 · visgl/deck.gl](https://github.com/visgl/deck.gl/issues/7735)（2023年3月~）

deck.glレポジトリでの上記イシューでは、これに関する、SSRでの事柄が議論されています。

[deck.gl 8.9（2023年3月にv8.9.0リリース）](https://github.com/visgl/deck.gl/releases/tag/v8.9.0)では、アップストリームの依存が更新されESモジュールになったため、ということだそうです:

> In 8.9 a few upstream dependencies are updated to their latest version, including @mapbox/tiny-sdf and d3-*. They are pure ESM modules and cannot be imported by require() from the commonjs entry point.
background-colorとbackgroundの違い

## 概要
この記事では、CSSの`background-color`と`background`の2つのプロパティの違いについて記述したいと思います。

## `background-color`
:::note
`background-color` はCSSプロパティで、**要素の背景色**を指定します。
:::
その色は、要素とその内容が占める全領域に適用されます。

基本的な使用方法は次のとおりです。

```css
selector {
    background-color: color;
}
```

ここで `selector` はスタイルを適用したいHTML要素を指定し、`color` は任意の色を表す値です。色はキーワード（`red`、`blue` 等）、RGB（`rgb(255, 0, 0)`）、RGBA（`rgba(255, 0, 0, 0.3)`）、HEX（`#FF0000`）など、様々な形式で指定することができます。

## `background`

:::note
`background` はCSSのショートハンドプロパティで、**要素の背景に関連する複数のプロパティを一度に設定する**ことができます。
:::

これには `background-color` だけでなく、 `background-image`、`background-repeat`、`background-position`、 `background-size`、 `background-origin`、 `background-clip`、 `background-attachment` などが含まれます。

基本的な使用方法は次のとおりです。

```css
selector {
    background: color image repeat position/size origin clip attachment;
}
```

これらの値はすべてオプションであり、任意の順序で指定できます。ただし、`position` と `size` はスラッシュ (`/`) で分割され、`size` は `position` の後に指定する必要があります。

## `background-color` と `background` の違い

これら2つのプロパティの主な違いは、`background-color` が単一のプロパティであるのに対し、 `background` は複数の背景に関連するプロパティを一度に設定できるショートハンドプロパティであることです。

それぞれの使用は目的による。`background-color` は特定の背景色のみを設定するために使用し、それ以外の背景に関連するスタイルを変更したくない場合に便利です。一方、 `background` は複数の背景に関連するプロパティを一度に設定したいときに使用します。これは特に背景画像を扱うときに役立ちます。

## 参考
[【CSS】background-colorとbackgroundの違い](https://memo.itsysgroup.com/?p=925)
jQueryなしでスクロール

# ページ外リンク

```js

// 現在表示されているディスプレイサイズを判定
const pcDisplayFlag: boolean = window.matchMedia('(min-width: 960px)').matches
// 移動させたい位置の値を決める要素を取得
const headerElement = pcDisplayFlag ? document.getElementById('pcHeader') : document.getElementById('mobileHeader')

const hash: string = window.location.hash ? window.location.hash.substring(1) : ''
if (hash) {
    const targetElement = document.getElementById(hash)
    if (headerElement && targetElement) {
    const rectangular = targetElement.getBoundingClientRect()
    window.scrollTo({
        top: window.pageYOffset + rectangular.top - headerElement.clientHeight - 30,
        behavior: 'smooth'
    })
    }
}

```

# ページ内リンク

```js

// 現在表示されているディスプレイサイズを判定
const pcDisplayFlag: boolean = window.matchMedia('(min-width: 960px)').matches
// 移動させたい位置の値を決める要素を取得
const headerElement = pcDisplayFlag ? document.getElementById('pcHeader') : document.getElementById('mobileHeader')

function linkScroll(event: Event, hash: string | undefined) {
    event.preventDefault()
    if (hash) {
    const targetElement = document.getElementById(hash)
    if (headerElement && targetElement) {
        const rectangular = targetElement.getBoundingClientRect()
        window.scroll({
        top: window.pageYOffset + rectangular.top - headerElement.clientHeight - 30,
        behavior: 'smooth'
        })
    }
    }
}

// ページ内リンク
const hashLinks = document.querySelectorAll('a[href^="#"]')
if (hashLinks.length > 0) {
    hashLinks.forEach((link) => {
    link.addEventListener('click', (event) => {
        linkScroll(event, link.getAttribute('href')?.substring(1))
    })
    })
}

```