OmniAICreator/Qiita-1.07M huggingface dataset:
AWS CLIのオプションまとめ


aws blackbeltを参考にAWS CLIの基本的な使用方法、オプションをまとめました。

## 使用するまでの流れ

1. AWS CLIのインストール
   詳細は省きます。zipのダウンロードだけではなくpip installなどを使用してもインストールできたりします。
1. AWS上でIAMを設定
    コマンドラインから実行できるコマンドはこのIAMの権限で制限されることになる
    1. IAMユーザーを作成し、必要な権限を付与する
    1. IAMのコンソール画面からアクセスキー、シークレットアクセスキーを取得
1.  `aws configure` をコマンドラインで打ち込み、設定を行う
   下記を最低限設定
    1.  アクセスキー
    1.  シークレットアクセスキー
    1.  リージョン
    1.  出力形式

上記をすれば使用できるようになります。

## 操作方法

### 実行コマンドの形式

```
$ aws [options] <command> <subcommand> [parameters]
```
- [options] : AWSコマンド全体で共通のパラメータ `--` から始まる
- <command> : ec2,s3など主にサービス名(例外としてconfigure, help)
- <subcommand> : サービスごとのコマンド
- [parameters] : コマンドごとのパラメータ  `--` から始まる

```shell
# 例：東京リージョンのEC2インスタンスを最大３つ表示する
$ aws --region ap-northeast-1 ec2 describe-instances --max-items 3
```

### オプション

#### `--profile` オプション
- 設定ファイル（プロファイル）を指定することで環境ごとの設定の切り替えができる
- `--profile (profile name)`
    - `~/.aws/credientials` にプロファイルの設定が書かれている
        - `[~~~]`のように書かれている箇所がプロファイル名なのでそれを指定することで切り替わる
    - このオプションが設定されていない場合はデフォルトプロファイル（`[default]`）が設定される


```
$ aws --profile (profile name) <command> <subcommand> [parameters]
```

#### `--region`オプション

- リージョンを指定

#### `--output`オプション

- Outputの形式を変更できる
    - Json,Text,Tableのいずれか
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623198/15ba2f67-df71-44f3-839d-b6cdf3da6563.png)

#### `--query`オプション
- 出力をフィルタリングできる
- クライアント側でフィルター処理を行う

#### `--filter`オプション
- サーバサイドでフィルター処理をする
- 使えるコマンドが限られている

## よくある使い方
### 複数環境でのプロファイルの切り替え（商用VS開発など）
```shell
# 商用環境(prod)の設定
$ aws --profile prod configure

# 実行時に商用環境を指定して実行
$ aws --profile prod ec2 describe-instances
```


## 備考
- EC2-Amazon Linux インスタンスにはデフォルトでaws-cliがインストールされている
    - ロールさえ割り当てればすぐに使用可能
    - アクセスキー、シークレットアクセスキーの生成も不要
- cloud9も同様にデフォルトでインストールされている
    - cloud9はクラウドの統合開発環境
    - ロールはデフォルトで付与されているが、足りないものは別途追加

## 参考

[AWS Black Belt Online Seminar AWS Command Line Interface](https://youtu.be/1FexvzegG3o)
プログラミングを勉強し始める前にしたこと

# プログラミング歴
　私は、「情報」の授業が必修化するはるか前に高校を卒業し、大学、大学院はやや理系より（統計学が必修）ながらも一応は文系で、学生の間にプログラミングに触れる機会はありませんでした。　
 
 プログラミングの経験は
①20代前半：アルバイト先でExcelVBAに触れる機会があった（既存のVBAで書かれたものを必要に応じて修正、機能の追加等をした）
②30代前半：当時の職場で行う業務のごく一部をExcelVBAを用いて自動化した
程度で、そのほとんどはExcelVBAを使わなくても、Excel関数でできないこともないくらいの機能しかありませんでした。

　それもかなり昔のことになり、今やExcelVBAに関する記憶もかなりあやふやで、プログラミングに関して完全な初学者と異なるのは「i = i + 1」が解けない方程式ではない、ということは理解していることくらいです。

# プログラミング言語の選択
　世の中には非常にたくさんのプログラミング言語があり、それぞれ用途が異なり、長所・短所（得意・不得意）があるようです。本来であれば「プログラミングを学んで何をしたいか」「どんなプログラムを作成したいか」により、どのプログラミング言語を習得するのがよいか決まると思いますが、自分にはそれがありません。現在の業務でプログラミング技術を必要としておらず、必要になる予定もなく、昇進や昇給に影響することもなく、プログラミングの技術を生かして転職するつもりもないです。ただの趣味、好奇心のため、独学が基本となり、お金もなるべくかからないようにしたいです。
　学習のしやすさではRuby、汎用性ならJava、仕事に多少なりとも有益そうなPHP、JavaScript、自分が使うとしたらスマホで利用できると便利なのでC＃、Go、kotlin（自身がAndroidユーザーなのでSwiftは選外）、安全性ならRustなど色々ありましたが、未経験・初心者でも学びやすい（らしい）Pythonを選びました。

# プログラミング学習用GoogleIDの作成
　いつ挫折するかわからない趣味なので日常的に使うメールアドレス以外にプログラミング学習用のメールアドレスを取得しました。とりあえず想定している用途はQiitaの利用者登録とGoogle Colaboratoryの利用ですが、将来的には学習サイトの利用者登録なんかでもGoogleIDだったら使いやすいところが多いんじゃないかと思っています。
Macでストレージをext4でフォーマットする

NTFSの外付けHDDをext4にフォーマットしたい


```sh
$ brew install e2fsprogs
```

初期化先を確認

```sh
$ diskutil list
```

```sh
$ sudo (brew --prefix e2fsprogs)/sbin/mkfs.ext4 /dev/disk9
mke2fs 1.47.0 (5-Feb-2023)
/dev/disk9: Resource busy while setting up superblock
```

怒られたのでumount

```sh
$ diskutil unmountDisk disk9
```

retry

```sh
$ sudo (brew --prefix e2fsprogs)/sbin/mkfs.ext4 /dev/disk9
mke2fs 1.47.0 (5-Feb-2023)
Creating filesystem with 732566644 4k blocks and 183148544 inodes
Filesystem UUID: a6274620-735f-44b0-83bb-d3f5d5f43d50
Superblock backups stored on blocks:
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
	4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
	102400000, 214990848, 512000000, 550731776, 644972544

Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done
```

以上
Windowsのbat（コマンドプロンプト）で高速スタートアップ無効化（完全シャットダウン）

# やり方

**管理者権限が必要** です。

```bat:
reg add "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Power" /v "HiberbootEnabled" /t REG_DWORD /d "0" /f
```

# ちゃんと設定できたかの確認も一緒に

```bat:
rem レジストリーで設定
reg add "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Power" /v "HiberbootEnabled" /t REG_DWORD /d "0" /f

rem 設定変更が反映されたか確認できるように電源オプションのシステム設定画面を開く
control /name Microsoft.PowerOptions /page pageGlobalSettings
```

# 参考サイトさん

https://automationlabo.com/wat/?p=1575

https://thanaism.com/archives/188

# バージョン

Microsoft Windows [Version 10.0.19045.3803]
寺社巡りの管理ページを作った

よく神社やお寺をめぐっているのですが、行ったことのある場所を備忘録として残しておこうと思い、管理ページを作成しました。
特に特別な機能を使っておらず、今まで習得した技術の詰め合わせです。（完全に自分用です ^_^;）

こんな感じのページです。
行ったところのある場所にマーカーを表示させるようにしています。数が多くなってきたので、都道府県でフィルタリングできるようにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/c458fee2-afec-cb4b-092b-98c513d1a720.png)

地図の描画にはLeafletを使っています。

マーカーをクリックすると、詳細情報が表示されるようにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/8457b1e5-8e19-4736-6942-fdd6aaf1c01c.png)

登録は、別のタブから行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/b41c31d9-1a14-d89a-6947-c29dca8880fe.png)

一緒に写真等の画像を添付するようにしています。大きなファイルの送信を避けるため、クライアント側で縦横の最大サイズ以下に縮小してからアップロードしています。

緯度経度の入力には、plus codeで入力できるようにしました。
plus codeから緯度経度への変換は、GoogleのGeocoding APIを利用しています。（ですので、APIキーの払い出しをしておく必要があります）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/3a944bcf-22ca-b73a-7258-56b22d095a49.png)

自分用なので、データベースは使わず、直接JSONファイルとして保存するようにしています。

以下、参考にした技術です。

* Leaflet
　[便利ページ：Leafletを使って緯度経度の表示や距離を表示する](https://qiita.com/poruruba/items/ffdf8e29a147c272f142)
　[ヤマレコの軌跡をLeafletで表示する](https://qiita.com/poruruba/items/88e23011815e8e0f4ffb)

* plus code
　[便利ページ：plus codeのエンコード・デコード](https://qiita.com/poruruba/items/8cc7cfab29ba428c5468)

* platform
　[Amplify CLIを使って、ローカルで実行＆AWSにデプロイ](https://qiita.com/poruruba/items/0030a40f148369c4130d)

ソースコードはGitHubに上げてあります。

poruruba/jisha_journal

https://github.com/poruruba/jisha_journal

# 実行方法

以下からZIPでダウンロードします。

https://github.com/poruruba/jisha_journal

```
> unzip jisha_journal-master.zip
> cd jisha_journal-master
> vi api/controllers/jisha-api/index.js
> mkdir api/controllers/jisha-api/data
> mkdir public/images
> vi .env
> npm install
> node app.js
```

index.jsにおいて、【GoogleAPIキー】のところにご自身のキーを指定します。
.envには、```PORT=30080``` など、待ち受けたいポート番号を指定してください。

ブラウザで以下を開きます。

```http://localhost:30080/```

以上
網羅率とテストスイートの質との関係

## 概要
網羅率が低いテストスイートの質が悪いことを示せても、網羅率が高いテストスイートの質がいいことは証明できない

## 定義
> **網羅率（coverage）とは、テストスイートに含まれているテストケースが実行するプロダクションコードの割合のことです。**
>
> _単体テストの考え方/使い方 p11_

## コード網羅率（テスト網羅率）の落とし穴
```math
コード網羅率 = \frac{実行されたコードの行数}{総行数}
```

下記のテストはコード網羅率100%になるが、実際にはテストされていない振る舞いがある（$inputの長さが5以上の場合）

```php
function isStringLong(string $input): bool
{
    return strlen($input) > 5;
}

function test入力文字の長さが5以下の場合falseが返る()
{
    $result = $this.isStringLong(3);
}
```

## 分岐網羅率
```math
分岐網羅率 = \frac{経由された経路の数}{分岐経路の総数}
```
分岐網羅率の場合、上記コードは `$input` が5以上か5以下の2つの分岐があり、そのうち１つ経由されているので、分岐網羅率50%となる。

## 網羅率で保証できないコードの検証
以下のテストスイートは分岐網羅率100%になるが、新たに追加されたクラス変数の更新については検証されていない。

```php
string $stringProperty;

function isStringLong(string $input): bool
{
    $this.stringProperty = $input; ## 検証されない
    return strlen($input) > 5;
}

function test入力文字の長さが5以上の場合trueが返る()
{
    $result = $this.isStringLong(6);
}

function test入力文字の長さが5以下の場合falseが返る()
{
    $result = $this.isStringLong(3);
}
```

## 確認不在のテスト
テスト対象のコードを実行するだけで何も確認しないテストのことを **確認不在のテスト** という。
下記のテストも分岐網羅率100%になるが全く意味がないテストになってしまっている。

```php
function test()
{
    $result = $this.isStringLong(6);
    $result = $this.isStringLong(3);
}
```

上記は極端な例だが、ある網羅率をプロジェクトの必須目標に設定した場合、このようなテストで網羅率をカバーし始める可能性がある。

## 使用するライブラリ内のコードは網羅率から外れる
たとえここまで示した例で分岐網羅率を100%にし、すべての振る舞いを検証したとしても、実は全てのコードを網羅していない。
上記の例ではphpの組み込み関数 `strlen()` を使用しているが、この関数を実装しているコードの分岐網羅率は考慮から外れてしまっている。

これはライブラリ内のコードを全て検証すべきというわけではなく、網羅率からはテストが十分に行われていることは本当の意味で知ることができないということである
 **＝網羅率の高さからはテストスイートの質の良さを示せない** 

## 参考文献
単体テストの考え方/使い方 p10~19

https://book.mynavi.jp/ec/products/detail/id=134252
サムネイルを押すとメイン画像が切り替わる動作の実装方法

<h1>サムネイルを押すとメイン画像が切り替わる動作の実装方法</h1>
<a href="https://illbenet.jp/view/js-switch_fadein_images">サムネイル画像をクリックするとメイン画像をふわっと切り替えるjQuery</a>
<a href="https://junpei-sugiyama.com/thumbnail-switching-image/">【jQuery】サムネイルをクリックしてメイン画像を切り替える方法【枠線の変更方法も解説】</a>
<a href=""></a>
<a href=""></a>
<a href=""></a>
<a href=""></a>
Tailwind cssのみでモーダルウインド実装する方法

<h1>Tailwind cssのみでモーダルウインド実装する方法</h1>
<a href="https://qiita.com/rotelstift/items/3ee95691e9ad98952113">tailwindcss だけでモーダルを実装してみる</a>
<a href=""></a>
<a href=""></a>
<a href=""></a>
<a href=""></a>
<a href=""></a>
<a href=""></a>
<a href=""></a>
Windows11が起動時にメーカーロゴ画面で固まる問題

# 経緯

新しく導入したWin11のマシンをセットアップしていたところ，再起動後にメーカーロゴが表示されるところで固まって一向に起動しない症状が発生した．

セーフモードで起動することはできたので，周辺機器の取り外し，ドライバの再インストール，システムの復元等色々試したものの，その時は結局原因がわからずクリーンインストールすることで解決した．

その後，別にWin11を搭載したSurfaceを購入し，セットアップをしていたところこの症状が再発．今回は何かあった時に原因が切り分けられるように，頻繁に再起動を挟みつつセットアップをしていたので，どうやらAdobe CS6をインストールしたことが原因であることがわかった．

その筋で色々検索をかけてみるとこんな情報が

https://goldear.net/adobe_cs6_install_01

つまるところ，Encoreで使われている古いドライバがWin11のメモリ整合性の設定とカチ合ってしまうのが原因のようで，当該ページではメモリ整合性の設定をOFFにすることで対処している．

が，これは当然セキュリティ的にはよろしくないので，メモリ整合性をONにするには？という筋でさらに調べていくとこんな情報が見つかり，

https://memorandum-000.diary.to/archives/16856040.html

単純に当該ドライバを削除してしまえばいいらしい．おそらくそれに伴ってEncoreは正しく動かなくなるのだろうが（未検証），筆者的にはEncore使う機会は今後まずないのでよしとした．


# 手順
* Win11をセーフモードで起動する
1. 起動→電源ボタンを長押しして強制終了を何回か繰り返す
2. 回復環境（青い画面）が出てくる
3. 「トラブルシューティング」→「詳細オプション」→「スタートアップ設定」→「再起動」
4. 再起動した後，別の青い画面が出るので4を選択
5. 勝手に再起動し，セーフモードでWin11が起動する

起動オプションで4ではなく5を選択すると，動作が怪しくなる代わりにネットが使えるようになる．もうCS6を削除するつもりで，アクティベーション解除をしたいのであればこちらを選択するとよい．

* PxHlpa64.sysを削除する
当該ファイルは`C:\Windows\System32\drivers\PxHlpa64.sys`にある．
普通にエクスプローラーで開いて削除可能．

* レジストリの修正（この工程は必要ないかもしれないが未検証）
レジストリエディターを開き，
`\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4d36e965-e325-11ce-bfc1-08002be10318}`
のLowerFilters（PxHlpa64.sysという値が入っている）を削除．

後は普通に再起動すれば無事正常起動．


---
その後Encoreは試していないが，少なくともイラレやフォトショを使った範囲で問題は起きていない．

1回目のトラブル時にはググってもCS6が原因だなんて情報は見つからなかったので，このメモが誰かの助けになれば幸い．まあWin11でCS6使ってる人なんて小数だろうしね…
WebViewの「戻る」操作をOnBackPressedCallbackで実装する

WebViewを使ったアプリ内ブラウザを作る場合、伝統的にWebView内の「戻る」操作は以下のように実装されてきました。

```kotlin
override fun onBackPressed() {
    if (webView.canGoBack()) {
        webView.goBack()
    } else {
        super.onBackPressed()
    }
}
```

WebViewのコンテンツが戻る操作を受け付ける場合は、WebViewにバック操作を行わせ、WebView内コンテンツが戻れない状態になったら、ネイティブのナビゲーションに利用し、最終的にアプリを終了させる操作につなげます。

しかし、`onBackPressed`はAPI 33でDeprecatedとなりました。

https://developer.android.com/reference/android/app/Activity#onBackPressed()

これからは `OnBackPressedCallback` を使って実装することが求められます。

https://developer.android.com/guide/navigation/custom-back?hl=ja

ただ、`onBackPressed`はバックキーが押されたときに処理をフックするべきかどうか判定できましたが、`OnBackPressedCallback` はバックキーが押される前にフックするかどうかを指定する必要があります。
この実装方法に慣れていないと、どうすればいいんだ？とフリーズしてしまうかもしれません。

# OnBackPressedCallbackを使ったWebViewの「戻る」操作

まずは、OnBackPressedCallbackを実装します。WebViewの`goBack()`を呼び出すだけです。コンストラクタ引数にはfalseを指定し、デフォルトで無効状態にしておきます。

```kotlin
private val onBackPressedCallback: OnBackPressedCallback =
    object : OnBackPressedCallback(false) {
        override fun handleOnBackPressed() {
            webView.goBack()
        }
    }
```

そして、（Activityの場合）以下のように、onBackPressedDispatcherにコールバックを登録しておきます。

```kotlin
onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
```

onBackPressedCallbackは無効状態なのでこの時点ではバックキーが押されても、onBackPressedCallbackが呼び出されることはなく、ネイティブ側のナビゲーションが実行されます（素のAcitivtyならActivityが終了）

WebViewの「戻る」操作をハンドリングするためには、onBackPressedCallbackを、WebViewが戻れる状態になった時に有効にして、戻れない状態になった時に無効化する必要があります。
これを判定するには、WebViewClientにて`doUpdateVisitedHistory`をoverrideします。WebViewのヒストリーが変化した際に呼び出されるメソッドですね。ここで、`canGoBack()`の結果に応じて、onBackPressedCallbackの有効・無効を設定します。

```kotlin
webView.webViewClient = object : WebViewClient() {
    override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) {
        onBackPressedCallback.isEnabled = webView.canGoBack()
    }
}
```

これで、WebViewの「戻る」操作をOnBackPressedCallbackで実装することができました。
以上です。
Python+OpenCVで画像を丸く切り抜いた

## 開発環境
- Visual Studio Code (Version: 1.85.1)
- Python 3.11.7
- numpy 1.26.3
- opencv-python 4.9.0.80

## 入力画像
![src.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611466/e130105e-0180-7759-a036-00bf4b8890b0.png)

## コード

```python
import cv2
import numpy as np

CROP_RADIUS = 256 
COLOR_WHITE = (255, 255, 255, 255)
src_img = cv2.imread("src.png")

if src_img is None:
    print("Error: Image not loaded")
else:
    src_height, src_width = src_img.shape[:2]
    center_point = (src_width // 2, src_height // 2)
    img = np.zeros((src_height, src_width, 4), dtype=np.uint8)
    img = cv2.circle(img, center_point, CROP_RADIUS, COLOR_WHITE, cv2.FILLED)
    img[:,:,:3] = src_img[:,:,:3]

    cv2.imwrite("circle_cropped.png", img)
```

## 出力画像
![circle_cropped.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611466/38a15eb7-ce12-805c-173e-afde4dd9d4b6.png)

## アンチエイリアス
境界のギザギザが気になったのでアンチエイリアスをかけました。

```python
img = cv2.circle(img, center_point, CROP_RADIUS, COLOR_WHITE, cv2.FILLED,lineType=cv2.LINE_AA)
```

## 出力画像
![cropped.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611466/edae96d0-a5bc-7726-e971-913002991631.png)
Goによるlocale(言語と地域の設定)の取得

## はじめに
多言語対応などのために、Goによるlocale(言語と地域の設定)の取得方法の一例を記載します。
## 要点
#### Request HeaderのAccept-Languageを取得する。
#### HeaderになかったらSessionの中身を取得する。(既に設定しているかもしれない)
#### 一切設定されていないならデフォルト値を設定する。
## 実際にコードを見てみよう
```
func GetLocale(w http.ResponseWriter, req *http.Request) (locale string){
    locale := req.Header.Get("Accept-Language")
    session := sessions.GetSession(req)
    default := “en-us”

        if locale == "" {
            l := session.Get("locale")
            if l == nil {
                locale = default
            } else {
                locale = l.(string)
            }
        }

    session.Set("locale", locale)
    return locale;
}
```
見たままですが、一番の肝はヘッダーの中から言語、地域設定に値する"Accept-Language"を取得するところですね。ここはブラウザなどで設定した言語設定が取得されます。
```
locale := req.Header.Get("Accept-Language")
```
ここからはoptionですが、下のようにコンテキストを設定したりしてもいいですね。
```
ctx := context.WithValue(req.Context(), "locale", locale)
```
不要な部分をstring.Splitなどで削除する、ミドルウェアとして使用して他のHandlerに渡すケースもあります。
MacにてZoomが利用できない状況に陥った

今までmacにて問題なく利用できていた、Zoomにて突然エラーが発生するようになったので、備忘録として投稿します。

Docker-Desktopを利用中にZoomへ接続しようとすると、Chromeにて以下画像のような`ERR_CONNECTION_RESET`が発生して利用できなかった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3666175/b280951b-4aea-3320-d5ae-4c0924090583.png)

Firefox の際には以下画像になり、利用できなかったのでブラウザに関する問題ではないことまでは確認済み。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3666175/6d0a4afd-7c7f-1043-7028-cab9cc686772.png)

`Docker-Desktop`に関する処理を停止などさせたら、正常にZoomが起動できるようになったので今のところ問題は解決しました。
詳細がわかった際には本投稿内容を更新します。
Turboとは

# Turbo
Turboは、Rails7以降を使用している方は必須の知識かと思います。

Railsで掲示板アプリの削除機能実装中に、ダイアログ機能を実装したつもりがダイアログが表示されず、即削除されてまい、意図した挙動をしなかった原因を追求したところ、Turboについて理解ができていなかったので、この記事でアウトプットとしていこうと思います。

## Turboとは

Turboを理解する前に、Hotwireを知っておく必要がある。

## Hotwire
Hotwireとは、Rails7からRailsのデフォルトになった、モダンなWebアプリケーションを作るための新しいアプローチ。

もう少し、詳しく説明すると、
サーバーサイドで生成されたHTMLを直接ブラウザに送信し、JavaScriptを最小限に抑えて、より高速でインタラクティブなウェブアプリケーションを構築することができるRuby on Railsのフレームワーク。

SPAではないが、React等のjsライブラリを使用せずに、SPA風のUXを実現することができるRailsのフレーワークというイメージだろうか。



#### Hotwireは、主に３つのコンポーネントで構成されている。

・Turbo
・Stimulus
・Strada

## Turbo
Turboは、htmlのbody タグのみ置換するSPA風のアプリケーションを作成することができるHotwireのコンポーネントの１つ。

Turboは４つの要素がある。

・Turbo Drive
・Turbo Frames
・Turbo Streams
・Turbo Native

### Turbo Drive
Rails7では、**Turbo Drive**が標準で有効になっている。
Turbo Driveは、ページ間のナビゲーションを高速化するために、全ページをリロードする代わりにHTMLのbodyタグのみを交換する。


今回は、この**Turbo Drive**を例に説明していく。


**従来のRails(Rails7より前）**

```Ruby
<%= link_to edit_board_path(board), id: "button-edit-#{board.id}" do %>
  <i class='bi bi-pencil-fill'></i>
<% end %>
<%= link_to board_path(board), id: "button-delete-#{board.id}", method: :delete, data: { confirm: t('defaults.message.delete_confirm') } do %>
   <i class="bi bi-trash-fill"></i>
<% end %>
```

これだと、削除自体は行えるが、ダイアログの表示は実行されない。

**Rails7以降**

```ruby
<%= link_to edit_board_path(board), id: "button-edit-#{board.id}" do %>
<i class="bi bi-pencil-fill"></i>
<% end %>
<%= link_to  board_path(board), id: "button-delete-#{board.id}",
            data: { turbo_method: :delete, turbo_confirm: t('defaults.delete_confirm') } do %>
<i class="bi bi-trash-fill"></i>
<% end %>
```

`method: :delete, data: { confirm: t('defaults.message.delete_confirm') }`
↓
`data: { turbo_method: :delete, turbo_confirm: t('defaults.delete_confirm') } `

link_toメソッドのdataの中に、method属性を追加し、属性の前に`turbo_`を付与している。

これにより、Rails7のデフォルト機能であるTurboが機能し、Rails7でダイアログの表示ができ、deleteメソッドも機能するようになる。


## ダイアログが表示されなかった理由
 Turboが標準で有効になっているRails 7アプリケーションでは、
 link_to ヘルパーで`method: :delete と data: { confirm: ... }` を使用しても、JavaScriptによる確認ダイアログが表示されず、リンクがクリックされると直接DELETEリクエストが送信される。これは、Turboによって通常のHTMLリクエストとして処理されるため。

 
## まとめ
Rails 7において、従来のRails UJS（Unobtrusive JavaScript）が提供していたいくつかの機能（例えば、link_to ヘルパーでの` method: :delete と data: { confirm: ... } `の使用）は、Turboの導入により異なる方法で実装されるようになった。

これにより、JavaScriptによる確認ダイアログが期待通りに表示されない場合があり、代わりにTurboに適した方法（`data: { turbo_method: :delete, turbo_confirm: ... }` の使用）を採用されているため、Turboを使用した実装をする必要がある。


## 参考記事
https://zenn.dev/shita1112/books/cat-hotwire-turbo/viewer/abstract#hotwire%E3%81%A8%E3%81%AF%EF%BC%9F

https://railsguides.jp/working_with_javascript_in_rails.html#turbo
Windowsのbat（コマンドプロンプト）で電源オプションのシステム設定画面を即開く

# やりたいこと

この画面をサッと開きたい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/fba8a6e6-7b90-2520-51fe-cdfc756412ba.png)
動作が遅いPCに対して **完全シャットダウン設定** を行う事が多いです。
**この画面に行きつくまでにマウスをぽちぽち** するのが毎回面倒くさい。
batを用意しておいてサッと開けるようにしておきたい訳です。

# やり方

```bat:
control /name Microsoft.PowerOptions /page pageGlobalSettings
```

# 参考サイトさん

http://wingsan.web.fc2.com/WinCom/index.html

https://www.bihoku-senior.net/niwatyotopc2/npc102.pdf

# バージョン

Microsoft Windows [Version 10.0.19045.3803]
CodeIQ:「ペア・ドロップ」問題の解答

Kawazoe（@riverplus）さん出題の問題です。
問題とテストケースはこちらのお世話になりました。解答もあります。
~~->https://blog.goo.ne.jp/r-de-r/e/3f51395af1c1d9b98d6c2488ab3aa3c9~~
(リンク切れしていました。2025.5.2)
URLが変わっていましたがみつかりました。（2025.5.3追加）
->https://sangaku0418.hatenablog.com/entry/2017/12/15/100100
ーーー2025.5.2追加
こちらでも問題と解答を提供されています。
https://sw-logic.com/Portfolio/Programing/CodeIQ/3485.php
ーーー

Aがk枚残ればBもk枚のこり、ペアの枚数もAと同数です。
Aのペアの組数　x=(n-k)/2=div(n-k,2)としますと
Aのペアの組み合わせの数はn組からx組選ぶ場合の数　-> nCx
Bのペアの組み合わせの数はn-x組からx組選ぶ場合の数　-> (n-x)Cx
残りk組は2枚のカードを区別するのでどちらがAに行くか　-> 2^k 
全体の組み合わせの数　-> (2\*n)Cn
となり、
F(n,k)=nCx * (n-x)Cx * 2^k / (2*n)Cn

計算途中巨大な数になりますのでJuliaではBigIntが必要でしたが、
nCrに対応するbinomialという関数がありますので楽です。

```Julia
#julia ver 1.41,1.53,1.73

function solve(n,k,a)
    n = BigInt(n)
    k = BigInt(k)
    x = div(n-k,2)
    ret = Int(trunc(binomial(n,x) * binomial(n-x,x) * 2^k / binomial(2*n,n) * 10^6))
   s = a == ret ? "ok " : "no "
   println(s,ret)
end

solve(2, 2,666666)
solve(4, 2,685714)
solve(5, 1,238095)
solve(13, 9,211187)
solve(30, 20,67130)
solve(41, 17,126481)
solve(80, 24,226)
solve(99, 47,137249)
```

場合の数の数え方はいろいろあって
ペアでないカードはn組からk組を選び2枚を区別するので組み合わせの数 -> nCk * 2^k
Aのペアはn-k組からx組選ぶので組みあわせの数 ->　(n-k)Cx
全体の組み合わせの数  ->  (2\*n)Cn　
F(n,k)=nCk * 2^k * (n-k)Cx / (2\*n)Cn
等でも良いのでPrologではこちらの式を使いました。

```Prolog
%SWI-Prolog ver 7.42,7.64

%:-initialization(start).   %ideone
%start.

ncr(_,0,1).
ncr(N,1,R):-R is N.
ncr(N,M,R):-N1 is N-1,M1 is M-1,ncr(N1,M1,R1),R is R1*N div M,!.

res(N,K,R):-
    N1 is N-K,N2 is (N-K)/2,ncr(N,K,R1),ncr(N1,N2,R2),ncr(2*N,N,R3),
    R is floor(R1 * 2^K * R2 / R3 * 10^6) .

solve(N,K,A):-
    (res(N,K,R)->(R==A->Str=" ok  ";Str=" no  ");
    write(fail)),write(" "),write(Str),writeln(R),!.

start:-f2(N,K,A),solve(N,K,A),fail.
start.

f2(2, 2,666666).
f2(4, 2,685714).
f2(5, 1,238095).
f2(13, 9,211187).
f2(30, 20,67130).
f2(41, 17,126481).
f2(80, 24,226).
f2(99, 47,137249).
```
2Dゲームのタイルマップを触ってみる

# はじめに

Unityでのゲーム開発初学者です。
2Dゲームのタイルマップ周りの用語や各機能の使い方がよくわかっていなかったので、
理解するためにいろいろと触ってみました。


# 環境
macOS Ventura 13.4
Unity 2022.3.2f1

# タイルマップでタイルを配置してみる

###### 1. タイル用の画像を作成してAssets配下に格納する（Sprite化する）
自分はFileAlpacaで作成した以下画像をAssets/Images配下に格納しました。

<img width="400" alt="images" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89159/d3a07254-cb1d-c6ef-9ac1-ea51e0e0cb77.png">

###### 2. HierarchyにTilemapを追加する
以下手順で作成する。
「2DObject」→「Tilemap」→「Rectangular」

###### 3. ProjectにTilePaletteを追加する
以下手順で作成する。
「Window」→「2D」→「TilePalette」

###### 4. TilePaletteにSpriteをD&Dで配置する

TilePaletteのここにD&Dしてくださいとなっている箇所にD&Dする。
Spriteを全選択して行うと纏めて配置できる。

###### 5. Sceneにタイルを配置していく

今回タイルに作成した画像は32x32で、各SpriteのPixelsPerUnitは100にしていたので、
GripのCellSizeはそれに合わせて0.32としている。


手順5までで以下のような状態。

<img width="400" alt="screen_state" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89159/4246ea5d-ab92-7e91-2630-26ec4794d723.png">


# コライダーを設定してみる

###### 1. タイルマップにコライダーを追加する

TilemapのInspectorからTilemapCollider2Dを追加する。
Tilemapを選択するとシーン上で配置したタイルの外側にコライダーが付与されているのが確認できる。

###### 2. 適当なオブジェクトをタイルの上から落としてみる

HierarchyにCircleオブジェクトを追加してタイルの上に配置する。
CircleのInspectorからRigidbody2DとCapsuleCollider2Dを追加する。

これでゲームを実行するとCircleオブジェクトがタイルと接触したところで止まるのが確認できる。

###### 3. 比較のため高さの違うタイルマップを作成して配置する

以下のような高さの低いタイルを追加してシーン上に配置してみる。
こういったタイルの場合、自動で色のついた部分にコライダーが付与される。
SprinteEditorのCustomPhysicsShapeでコライダーの範囲を好きなように設定することもできる。

<img width="400" alt="screen_state" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89159/fdc8c98f-e38c-7f26-db49-36c7c09cee43.png">


最終的には以下のようなフィールドを実装することができた。

![ezgif.com-optimize.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89159/3aab9d01-6430-fd93-e79a-5bc8d0c575c1.gif)

タイルマップを使えば2Dアクションゲーム用のステージも色々作れそうだ。

# タイルマップを使用するメリット

スプライトを１つ１つ使用するよりタイルマップを使用した方がパフォーマンスは改善するとのこと。詳細は以下の記事に記載されている。

https://unity.com/ja/how-to/optimize-performance-2d-games-unity-tilemap

※4年前の記事なので情報が古い場合があります。

# その他参考にした記事

https://kiironomidori.hatenablog.com/entry/unity-tilemap

https://nosystemnolife.com/tilemap/

>絵に例えると、Tilemapがキャンパス、TilePalleteがパレット、素材の画像が絵の具ですね。

この表現がイメージしやすくてとても分かりやすかった。

# 最後に

機会があればスプライトアトラスとかも自分で作って使ってみたい。
VOICEVOX APIのSpeakerパラメータを調べる方法

# VOICEVOX APIで使用するSpeakerパラメータの調べ方

１．VOICEVOXを起動した状態にしてブラウザで下記URLを開く
http://localhost:50021/docs

２．/speakers　の項目を開き「Try it out」と書かれている部分をクリック

３．Executeボタンをクリックするとリクエストが送られてspeakerに関する情報がJsonで帰ってくるので参照する。

以上

## やってみた動画
https://youtu.be/ZVfZ3k4RZek
H2Database username password 設定

``` Java
import java.sql.*;
import java.util.Properties;

public class Main {
    public static void main(String[] args) {
        try {
            Class.forName("org.h2.Driver");
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("ドライバのロードに失敗しました");
        }
        Connection con = null;
        try {
            // url, user, password
            con = DriverManager.getConnection("jdbc:h2:file:~/test", "sa", "");

            // 別の指定方法
            //Properties props = new Properties();
            //props.put("user", "sa");
            //props.put("password", "");
            //con = DriverManager.getConnection("jdbc:h2:~/test", props);

            PreparedStatement pstmt = con.prepareStatement("SELECT * FROM TEST");
            ResultSet rs = pstmt.executeQuery();

            while (rs.next()) {
                System.out.println(rs.getString("Name"));
            }

            rs.close();
            pstmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
```
ESP32でHSPIを使っていると初期化を繰り返すことがある問題

# 今回問題になった現象
ESP32-WROOM-32Eでオーディオプレーヤーを作っているのですが、マイコン起動後にSetupも実行されず初期化を繰り返すことがありました。HSPIを使いSDカードを挿し込んでいる時だけこの現象が発生しました。その際以下のようなエラーメッセージが出ていました。
```
rst:0x10 (RTCWDT_RTC_RESET),boot:0x33 (SPI_FAST_FLASH_BOOT)
invalid header: 0xffffffff
invalid header: 0xffffffff
```

# 原因
この問題を調べると以下の記事と症状が同じだったため、これを参考に対応したところ解決しました。
https://chakoku.hatenablog.com/entry/2020/01/25/234359
ESP32はデフォルト設定ではフラッシュメモリの電源電圧を起動時のGPIO12の状態で設定できるようになっています。ESP32の起動時にGPIO12がHighになっているとフラッシュメモリの電源電圧が1.8Vに設定されてしまい、プログラムを正常に読み込めなくなることが原因でした。

# 解決策
GPIO12はHSPIのMISOで使用しSDカードに接続されているため、回路の変更なく対応するには先ほどの記事でも書かれているようにESP32のefuseを書き換えてフラッシュメモリの電源電圧を3.3Vに固定する必要があります。
以下の手順でefuseを書き換えることができます。
（事前にPython等のインストールが必要です）
➀まずコマンドプロンプトで以下のコマンドを入力しesptoolをインストールします。
```
pip install esptool
```
➁次に以下のコマンドを入力して現在の設定を読み出します。
　COMxにはESP32のCOMポート番号を入れてください。
```
espefuse.py --port COMx summary
```
読みだした設定を見てXPD_XXXXX（XPD_SDIO_REG等）が0になっていれば次に進みます。
➂そして以下のコマンドでefuseの設定を書き換えます。
```
espefuse.py --port COMx set_flash_voltage 3.3V
```
書き込んで良いか聞かれるので"BURN"を入力すると設定が書き込まれます。

# 最後に
初めてQiitaで書いたので見にくいところなどあるかもしれませんが気に入っていただけたら今後も見ていただけると嬉しいです。主にESP32等のマイコンやオーディオ回路、自作ラジコンについて書きたいと考えています。
!pip install xxxしたらERROR:  dependency conflicts





# 問題
~~~
!pip install labelImg
~~~

したら、

~~~

Collecting labelImg
  Downloading labelImg-1.8.6.tar.gz (247 kB)
     -------------------------------------- 247.7/247.7 kB 1.9 MB/s eta.....
     .

     .いろいろかいてあって
     .
     .
     
Successfully built labelImg
Installing collected packages: PyQt5-Qt5, PyQt5-sip, pyqt5, labelImg
Successfully installed PyQt5-Qt5-5.15.2 PyQt5-sip-12.13.0 labelImg-1.8.6 pyqt5-5.15.10


~~~


~~~
ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.

~~~

が出た。
一応エラーメッセージのようである。この場合どうすればいいか



# 原因

chatGPTに聞いてみたら下記の通りきた
>このエラーは、labelImgのインストール中に既存のパッケージとの依存関係の競合が発生していることを示しています。具体的には、pyqt5のバージョンが競合しているようです。
>エラーメッセージにもありますが、labelImgのインストールが成功したようです。ただし、pyqt5のバージョン競合により、一部のパッケージ（例えば、spyder）との互換性に問題が発生しているようです。
>この状況では、いくつかのアプローチが考えられます。まず、labelImgが必要な場合は、それを使用してみることができます。labelImgは独立したアプリケーションであり、インストールされたパッケージとの競合に直接影響を与えることはないかもしれません。
>もう一つのアプローチは、仮想環境や別の環境を作成して、labelImgが必要なプロジェクトや作業に対して別々の環境を使うことです。仮想環境を使うことで、パッケージ間の競合を最小限に抑えることができます。

どうやら、そのままでもよさそう。

# 対処法

とりあえずインストールはできているので、そのままいったん使ってみましょう。
使えなかったら、もう少し細かいところをほかの出てきたエラーを調べながら解消していきましょう
「セマンティックとは何か」についてまとめてみる

## はじめに
### この記事の目的
* セマンティックという言葉の意味を知る
* 「セマンティックなコーディング」とは何で、何の為に行っているのかを知る

### 目指すレベル感
* 「言葉だけ知っている」から「ざっくりこういうこと」を説明できる状態になる
* 中堅以上のIT業界の方々には「そんなの知ってますが？」という内容かもしれない

## 「セマンティック」とはどういう意味か
まずは辞書的な意味から。
セマンティックの言葉の意味は以下の通り。

> セマンティックとは、一般的には「意味」や「意味論」に関することを指す語である。
> IT用語としては、コンピュータに文書や情報の持つ意味を正確に解釈させ、文書の関連付けや情報収集などの処理を自動的に行わせる技術について用られる語である。

セマンティックなコーディングとは、HTMLに限らずプログラミング言語を用いたコーディング全般に対して言えることのようです。

ここでの「コンピュータに文書や情報の意味を正確に解釈させ」るというのは、
例えば見出しなら`heading`タグを使用するといったように、文書にある情報が何なのかがコンピュータに分かるようにコーディングをするということ。

つまりセマンティックなコーディングとは、**コンピュータにこちらが表現したいものを伝え、正しく理解してもらうための作業である**ということですね。

## セマンティックなコーディングをすると何が良いのか
先ほどの章で、セマンティックなコーディングをするとこちらが表現したいことをコンピュータに理解してもらえるということが分かりました。

では理解してもらえると何が良いのか。
例として**HTMLでコーディングを行う場合**に絞ってまとめていきます。
主に以下の2つの理由が説明されていました。

### SEO対策になる
セマンティックを調べると必ずと言っていいほどセットで出てきました。
SEOについての詳細な説明はここでは省きますが、日本語で言えば「検索エンジン最適化」と言われるものです。
検索エンジンを通してターゲットとなる顧客が来てくれるように、Webサイトやコンテンツを最適化することです。

セマンティックなコーディングをすると、コンピュータに理解してもらえるということは先ほど述べました。
逆を言えば、セマンティックでないページはコンピュータに理解されにくくなります。

例えば以下のようなページがあるとしましょう。
``` html
<div>
    <div>見出しです</div>
    <div>
        <div>リスト1つ目です</div>
        <div>リスト2つ目です</div>
        <div>リスト3つ目です</div>
    </div>
    <div>
        <div>リストの要素です</div>
        <div>リストの要素です</div>
        <div>リストの要素です</div>
    </div>
</div>
```

これではコンピュータは「どこが何の要素なのか？」がわかりません。
自分が理解できないものは他人にもお勧めできないので、検索上位にも上がってきません。

``` html
<main>
    <h1>見出しです</h1>
    <ol>
        <li>リスト1つ目です</li>
        <li>リスト2つ目です</li>
        <li>リスト3つ目です</li>
    </ol>
    <ul>
        <li>リストの要素です</li>
        <li>リストの要素です</li>
        <li>リストの要素です</li>
    </div>
</main>
```
ページの主要エリアに見出し、箇条書きリスト、番号付きリストがあることを示しました。
先ほどよりもコンピュータにとってわかりやすいページ構造になっています。


### アクセシビリティのため
これも必ずと言っていいほどセットで出てきた理由です。

アクセシビリティとは特にWebサイト上における、情報やサービスへのアクセスのしやすさのことを指します。


具体例を列挙すると、以下のようなものです。


- スクリーンリーダーが、headingタグでコーディングされた見出しを拾い読みできる
- ボタン要素に、マウスだけではなくキーボードでもアクセスできる
- 画像が表示できないほど電波の悪い環境でページを開く


SEOが**対コンピュータ**だったのに対し、アクセシビリティは**対ユーザー**という見方もできるでしょうか。

## まとめ

大きく以下の2つです。
* セマンティックとは「意味」や「意味論」に関することを指す語で、コンピュータに文書や情報がもつ意味を正確に理解させること。
* セマンティックなコーディングを行うことで、SEO対策・アクセシビリティのためになる。


## 参考サイト
[セマンティックとは (semantic) IT用語辞典バイナリ](https://www.sophia-it.com/content/%E3%82%BB%E3%83%9E%E3%83%B3%E3%83%86%E3%82%A3%E3%83%83%E3%82%AF)
[セマンティック検索とは？特徴やSEOへの影響を解説！](https://gc-seo.jp/journal/semanticsearch/)
[セマンティックHTMLによるウェブアクセシビリティの向上とテスト技法・ツールについて](https://www.infoq.com/jp/news/2023/07/web-accessibility/)

## 関連記事
https://qiita.com/toraguitar/items/5f1102e4b6537e8ecfe6

https://qiita.com/toraguitar/items/0406e73c62ef907989c2
「SEO」についてまとめてみる

## はじめに
### この記事の目的
* SEOという言葉の概要を知る
* SEOのための具体的な取り組みを知る

### 目指すレベル感
* 「言葉だけ知っている」から「ざっくりこういうこと」を説明できる状態になる
* 言葉の意味と具体例に絞り、歴史的背景や周辺知識などは深く説明しない


## SEOって何？
まずは辞書的な意味から見てみます。
weblio辞書によると、以下のように説明されています。

> 「SEO」とは検索エンジン最適化を意味する言葉であり、ウェブページやサイトを検索エンジンの検索結果の上位に表示させることを目的に様々な施策を行う、Webマーケティング施策の一つである。

対検索エンジンに絞った対策という捉え方で良さそうです。

> 検索エンジンへの理解、Webマーケティングの知識、サイトを構成するHTMLタグやCSSの使い方など幅広い知識が必要であるため、初心者がすぐに実践するのは難しい場合も多い。

幅広い知識が必要とのことなので、webサイトに携わる様々な領域の人が協力して行っていく必要がありそうです。

## 検索エンジンのシステムを理解してみる
SEOは対検索エンジン用の施策なので、検索エンジンがどのように機能しているのかについてを知っておきましょう。

検索エンジンとは、キーワードやフレーズを入力し、インターネットにある膨大な情報から欲しい情報を見つけるためのシステムです。　
Google、Yahoo!、Bingなどが代表例ですね。

どんな仕組みで関連ページを持ってきているのか、大きく分けて以下の三行程で表されるそうです。

* 【情報収集】クローリング
* 【情報の分類・登録】インデックス
* 【ページの順位づけ】ランキング

### 【情報収集】クローリング
検索エンジン内のシステムである「クローラー」と呼ばれるロボットが、インターネット上にあるWebサイトのリンクを巡回しながらページを収集することです。

### 【情報の分類・登録】インデックス
クローラーが収集した情報を、Googleのデータベースに登録することです。

### 【ページの順位づけ】ランキング
インデックスされたページの中から検索されたキーワードに関連性が高いページを選出し、検索順位を決定していきます。


## SEO対策とは具体的に何をする？
検索エンジンの基本的な仕組みを理解したところで、SEOに話を戻しましょう。
Webページ制作において、SEO対策とは具体的に何をすれば良いのか？


結論から言うと、「**ユーザーファーストのwebページを作ること**」です。

クローラーがwebページを見る視点は、ユーザーに取って有益かどうかです。
ユーザーにとって見やすい、欲しい情報が揃っているページが優先的にインデックスされ、ランキング上位に順位付けされていきます。

いくつか具体例を列挙します。

### WEBサイトの3段階構造
ユーザーがトップページを訪れた際、行きたいページに2クリック以内に辿り着けるように設定されている構造のことを指します。

クローラーは浅い階層を頻繁に訪れるようです。
重要な情報やキーワードがあるページ、ユーザーにとって必要なページは3階層以内に作ると良いでしょう。

### リンクの整備
クローラーはリンクを介して巡回をするため、リンクの整備は有効な対策になります。

例えば内部リンクを設置し、サイト内の回遊を促すのは有効です。

また、クローラーの無駄な巡回を防ぐため、同じ内容のページで異なるURLが存在する場合は統一する、無効なページは削除するなどの対応をしましょう。

### パンくずリストの設置
パンくずリストとは、Webサイトを訪れたユーザーが今どの階層にいるのかを示すため、階層のリンクをリスト化したものです。
WEBサイトの3段階構造を明示的にでき、クローリングがスムーズに行われます。

## まとめ
* SEOとは「検索エンジン最適化」のこと。
* 検索結果の上位にWebページを表示させるための施策である。
* SEO対策のためには、ユーザーファーストのWebページを作ることが重要である。

Googleの基本理念には「ユーザーに焦点を絞れば、他のものはみな後からついてくる。」というものがあります。
ユーザーにとって的確な検索結果を表示するため、検索エンジンのアルゴリズムは絶えず変化し続けています。

Webページを制作する際にも「どう検索上位に表示させるか」だけではなく、
「ユーザーに取ってより良いページにするにはどうするか」を考えると良いということですね。

## 参考サイト
[「SEO」の意味や使い方 わかりやすく解説 Weblio辞書](https://www.weblio.jp/content/SEO)
[【最新版】正しいSEOとは？5つのSEO対策とチェックリスト](https://mieru-ca.com/blog/seo-measures/)
[検索エンジンとは 押さえておくべきSEO対策のポイントと検索順位の仕組みについて解説](https://gmotech.jp/semlabo/seo/blog/searchengine-guide/)
[【初心者必見】SEOとは？8つの基本対策を分かりやすく徹底解説](https://gmotech.jp/semlabo/seo/)
「webアクセシビリティ」についてまとめてみる

## はじめに
### この記事の目的
* アクセシビリティという言葉の概要を知る
* アクセシビリティのための具体的な取り組みを知る

### 目指すレベル感
* 「言葉だけ知っている」から「ざっくりこういうこと」を説明できる状態になる
* 言葉の意味と具体例に絞り、歴史的背景や周辺知識などは深く説明しない


## アクセシビリティとは？
webアクセシビリティを理解するにあたって、まず「アクセシビリティ」という言葉の辞書的な意味を押さえます。
> アクセシビリティ（accessibility）とは、近づきやすさ、利用しやすさ、などの意味を持つ英単語で、IT分野では、機器やソフトウェア、システム、情報、サービスなどが身体の状態や能力の違いによらず様々な人から同じように利用できる状態やその度合いのことを指す。

ここでの「身体の状態や能力の違い」とは、身体的・環境的制約を指します。
誰にとっても同じように情報の入手、サービスの利用が可能であるということですね。


なお、混同されがちな単語に「ユーザビリティ」があります。

アクセシビリティが「誰にとっても使いやすい」が目的であるのに対し、
ユーザビリティは「ターゲットとなる特定の人・状況において使いやすい」が目的です。

## webアクセシビリティとは
アクセシビリティの中でも特に「Webにおいて、あらゆる人が情報や機能を利用しやすい状態」を表す言葉です。

## 開発の4つの原則
webアクセシビリティのための取り組みにはガイドラインが存在します。
国際基準として広く知られているのは、Web技術の世界的標準化をおこなっている団体であるW3C（World Wide Web Consortium）の定めた「WCAG（Web Content Accessibility Guidelines）」です。

W3Cが掲げる4つの原則というものがあり、以下の通りです。

> 1. 知覚可能 － 情報及びユーザインタフェースコンポーネントは、利用者が知覚できる方法で利用者に提示可能でなければならない。
> 2. 操作可能 － ユーザインタフェースコンポーネント及びナビゲーションは操作可能でなければならない
> 3. 理解可能 － 情報及びユーザインタフェースの操作は理解可能でなければならない。
> 4. 堅牢 (robust) － コンテンツは、支援技術を含む様々なユーザエージェントが確実に解釈できるように十分に堅牢でなければならない。

日本では日本工業規格(JIS)として制定された、「高齢者・障がい者等配慮設計指針－情報通信における機器、ソフトウェア及びサービス」（JIS X8341シリーズ）という規格が、アクセシビリティの基準として体系的に整備されています。

W3Cの国際基準に則るように改正が行われているため、アクセシビリティのための取り組みはJISを用いることで可能となります。


## 取り組みの具体例
誰にとっても、どんな状況においても情報の入手が可能である状態とは、具体的にどのような取り組みによって作られるのかを見ていきます。

観点別に3つ紹介します。

### 視覚的配慮
目の不自由な方向けの対応です。
視力が低い、色の認識が難しいなどの不便に対し、以下のような対応がされています。

* スクリーンリーダーでの読み上げのため、画像にalt属性を付与する
* 文字を大きくする
* 色のコントラストをはっきりさせる

### 聴覚的配慮
耳の不自由な方向けの対応です。
音で情報を伝えることが難しいため、以下のような対応がされています。

* 動画に字幕をつける
* デバイスのLEDライトの光り方で情報を分ける

### デバイスの入力機能についての配慮
マウスorキーボードしかない環境下である、あるいは四肢が不自由でデバイスの入力機能をうまく使えない方に向けての対応です。

* クリックだけでなくタブ移動に対応する
* 音声入力対応
* アイトラッキング

## Webアクセシビリティを向上させると何が良いのか
### 様々なユーザーに見てもらいやすくなる
Webアクセシビリティが向上するほど、そのWebページを利用できるユーザー層が増えます。

### SEO対策になる
Webアクセシビリティが高いページは、それだけ多くのユーザーに利用され、利用しやすいページであるという評価を受けやすくなります。

検索上位に表示されるかどうかの基準として「ユーザーにとって使いやすいかどうか」は大きな評価基準です。

## 最後に
* Webアクセシビリティとは「Webにおいて、あらゆる人が情報や機能を利用しやすい状態」を表す言葉である
* Webアクセシビリティの取り組みには様々なものがある
* Webアクセシビリティを向上させることでユーザーにとって利用しやすいページとなり、SEO対策にもなる

## 参考サイト
[アクセシビリティとは - 意味をわかりやすく](https://e-words.jp/w/%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B7%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3.html)
[アクセシビリティとは？Webにおける外せないポイントも含めて具体例を交えて解説](https://blog.nijibox.jp/article/whats_accessibility/)
[Web Content Accessibility Guidelines (WCAG) 2.1 (日本語訳)](https://waic.jp/translations/WCAG21/)
【Go】ポリシーに則ったランダムパスワード文字列の生成

- Go でランダム文字列を生成するには crypt/rand などの乱数生成器を使う方法がある
    - https://qiita.com/nakaryooo/items/7d269525a288c4b3ecda
- 加えて、パスワードなどの平文を生成する際に、「**英大文字、小文字、数字が必ず一つ以上含まれていること**」などのポリシーに則った文字列を生成したい時がある
- そんな時用のスニペット

```main.go
package main

import (
	"crypto/rand"
	"fmt"
	"math/big"
)

func main() {
	pp, _ := newPlainPassword(16)
	fmt.Println(pp)
}

func newPlainPassword(length int) (string, error) {
	const (
		uppercaseCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		lowercaseCharset = "abcdefghijklmnopqrstuvwxyz"
		numbersCharset   = "0123456789"
	)

	const minimumTokenLength = 10
	if length < minimumTokenLength {
		return "", fmt.Errorf("長さは %d 文字以上である必要があります", minimumTokenLength)
	}

	var token []byte

	// 英小文字を追加、英大文字を追加、数字を一個ずつ追加
	for _, charset := range []string{lowercaseCharset, uppercaseCharset, numbersCharset} {
		randomIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
		if err != nil {
			return "", fmt.Errorf("failed to rand.Int, error: %s", err.Error())
		}
		token = append(token, charset[randomIndex.Int64()])
	}

	// 残りの文字を生成
	charset := uppercaseCharset + lowercaseCharset + numbersCharset
	for i := 3; i < length; i++ {
		randomIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
		if err != nil {
			return "", fmt.Errorf("failed to rand.Int, error: %s", err.Error())
		}
		token = append(token, charset[randomIndex.Int64()])
	}

	// 先頭3桁に法則性が発生してしまうため、生成したパスワードをランダムに並び替える
	for i := 0; i < len(token)-1; i++ {
		j, err := rand.Int(rand.Reader, big.NewInt(int64(len(token)-i)))
		if err != nil {
			return "", fmt.Errorf("failed to rand.Int, error: %s", err.Error())
		}
		token[i], token[int64(i)+j.Int64()] = token[int64(i)+j.Int64()], token[i]
	}

	return string(token), nil
}

```
Twitterリンクをvxtweetドメインに変換するBotを作ってみた2

2回目の投稿です。
あれからAPIの使い方を把握して、ある程度進化させました。
なお、前回は[こちら](https://qiita.com/nisinosora/items/d73b77806e25deed8467 "Twitterリンクをvxtweetドメインに変換するBotを作ってみた")

まずは、引用で返信する形にしました。
前回はどのリンクを変換したのかが分からなかったためです。

次に、リアクション「×」をBOTにより追加するようにしました。
これは、変換が不要な場合にメッセージ送信者自身がこのリアクションをタップまたはクリックした際に、BOTのメッセージを削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/c128d3dc-4e6d-e016-60e5-25017ff823ca.png)

スラッシュコマンドも追加しました。
ローカライズ対応もしており、現在は英語・簡体字・繁体字の言語設定で利用できます。

各コマンドについては、説明の通りです。
Discordのテキスト入力欄に「半角スラッシュ」を入力することで利用できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/d79484a2-3e0f-9f13-42ce-60f35e3b6bc6.png)

英語版（English）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/39226fc3-ffab-2f7b-9f3c-4f495728feba.png)

中国語（簡体中文）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/f95a6090-b109-f434-c722-f1c2873cae34.png)

台湾語（繁体中文）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/1ec76d54-74f4-4a90-3eb6-aa55f0f9aa78.png)

情報チャンネル設定使用例：
このコマンドで実行したチャンネルが、BOTの更新情報等を通知するチャンネルとなります。
オプションで、任意のチャンネルを選択することもできます。
※テキストチャンネル（スレッド等は除く）に限ります。
 ここで設定したチャンネルが次項の「お問い合わせ」の返信用チャンネルとなります。
 個別のDMに返信する形式でも良かったかなと思っていますが、
 個人管理の都合上、関係ないようなお問い合わせが来るのを抑制する目的もあるため、このような形にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/c2a5203a-a04f-ff7c-aced-aefc1b94ba6c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/92260f8c-2d35-f0a3-d381-214e25f7e06f.png)


お問い合わせ使用例：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/3c9c87a2-564c-2467-22b1-964ddfe2b927.png)

上記モーダルにて入力した内容を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/e20b1af3-9aa2-fc4b-4a3e-59eb2d790450.png)

送信を押すことで、自分のもとにお問い合わせが届きます。
返信時には、「送信先チャンネル」に送信します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583726/739db0a2-f316-b1c3-418b-959ba1a6fb41.png)

以上です。
【Salesforce認定アドミニストレータ試験】公式模擬試験の英日翻訳と図解解説 (3)

この試験を受けるための勉強をした際に思わぬ苦戦をしたので、英語公式模擬問題を翻訳しながら図解解説として整理しました。

第3回目の投稿です。　～レコードタイプとページレイアウトに関する問題～

第1回目、第2回目、第3回目で投稿した設問に共通するのは「レコードタイプ」です。第1回目の解説に書きましたが、レコード タイプを使用すると下記の制御ができます。

　1. ビジネスプロセス（フェーズ、進捗パターン）
　　　a. 商談：営業プロセス
　　　b. ケース：サポートプロセス
　　　c. リード：リードプロセス
　2. 選択リスト値
　3. ページレイアウト

第1回目と第2回目は「1-a」と「2」、今回（第3回目）は「3」に関する設問です。

Aung

![スライド1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626902/21d336ed-f7dc-71a1-668d-a0e391535e02.jpeg)
![スライド2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626902/d01d89a8-4b20-9670-b9b6-da35a4d1ec4f.jpeg)
![スライド3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626902/b5dee64c-3a2b-5b6f-25e1-caf9c0f1be7c.jpeg)



第1回目の投稿　～レコードタイプと営業プロセスに関する問題～
https://qiita.com/Aungz/items/204d20c5c2c72a52c9df

第2回目の投稿　～営業プロセスと選択リスト値に関する問題～
https://qiita.com/Aungz/items/5ecaa907ff6500924420
ヒープ領域とスタック領域

# はじめに
毎週1本様々な技術に関する記事を投稿しています。
もし興味のある方は下のリンクから他の記事も見ていただければ幸いです。
 [@7_inai_](https://qiita.com/7_inai_)

# 1.ヒープ領域とスタック領域とは
### 1.1.ヒープ領域とスタック領域の基本的な定義と役割
プログラムが実行される際、メモリは主に、ヒープ領域、スタック領域、静的領域、テキスト領域の4つに分かれます。本記事では、スタック領域とヒープ領域について解説します。
`スタック領域は、関数呼び出しやローカル変数の割り当てに使われます。一方、ヒープ領域は、プログラム実行中に必要なサイズのメモリを動的に確保・解放するのに利用`されます。

### 1.2.プログラムの実行時にメモリをどのように管理するか

スタック領域は、関数の呼び出し時に自動的に割り当てられ、関数の終了とともに自動的に解放されます。これに対し、ヒープ領域では、__プログラマが明示的にメモリの確保（mallocなど）と解放（freeなど）を行う__ 必要があります。これにより、動的なメモリ管理が可能になります。



# 2.ヒープ領域とスタック領域の違い
`スタック領域は後入れ先出し（LIFO）のデータ構造`を持っています。そのため、確保したのとは逆の順番で解放するのがスタック領域の特徴です。
`スタック領域が下から順番に積み上げていくのに対し、ヒープ領域には順序がありません。`どのような順序で確保・解放するかは、ソフトウェア側で自由に決められるため、柔軟性が高いのが、ヒープ領域の特徴です。

# 3.なぜ異なるデータ構造でメモリ管理を行うのか？
### 3.1.ヒープとスタックが異なるデータ構造を持つ理由
スタック領域は、前述した通りLIFOのデータ構造を持ちます。関数内で定義された変数や、引数として受け取ったパラメータは、その関数の実行中のみ使用されるため、LIFOのデータ構造とすることで、効率よくメモリを使用することができます。
これに対してヒープ領域は、動的にメモリを確保・開放するのに適したデータ構造を持っています。

# 4.終わりに
ヒープ領域とスタック領域はプログラムのメモリ管理において重要な役割を果たしています。正しい使い分けと理解が、プログラムの安定性と効率性を向上させる鍵となります。

最後までお付き合いくださりありがとうございました。
パブリック IP を持たない Azure VM に Azure Load Balancer からパブリックアクセスする構成を試してみた

パブリック IP を持たない Azure VM が既に存在していたとします。後から Azure Load Balancer を追加し、パブリック経由でアクセスできるようにしたい場合を想定して試してみました。

## 検証用のパブリック IP を持たない Azure VM を作成

```bash:bash
region=japaneast
prefix=mnrvmlb

az group create \
  --name ${prefix}-rg \
  --location $region

az vm create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-vm \
  --os-disk-name ${prefix}-vmOSDisk \
  --image Ubuntu2204 \
  --size Standard_B1s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-address "" \
  --nsg-rule NONE
```

## Azure VM に Nginx を入れて動作確認

```bash:bash
az vm extension set \
  --publisher Microsoft.Azure.Extensions \
  --version 2.0 \
  --name CustomScript \
  --resource-group ${prefix}-rg \
  --vm-name ${prefix}-vm \
  --settings '{"fileUris":["https://raw.githubusercontent.com/Azure-Samples/compute-automation-configurations/master/automate_nginx.sh"],"commandToExecute":"./automate_nginx.sh"}'

az vm run-command invoke \
  --command-id RunShellScript \
  --resource-group ${prefix}-rg \
  --name ${prefix}-vm \
  --query "value[0].message" \
  --output tsv \
  --scripts "curl -s http://localhost/"
```

下記のような結果になれば動作確認完了。

```txt
Enable succeeded: 
[stdout]
Hello World from host mnrvmlb-vm !

[stderr]
```

## Azure Load Balancer を作成

```bash:bash
az network public-ip create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-pip \
  --sku Standard

az network lb create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-lb \
  --sku Standard \
  --public-ip-address ${prefix}-pip \
  --frontend-ip-name myFrontEnd \
  --backend-pool-name myBackEndPool

az network lb probe create \
  --resource-group ${prefix}-rg \
  --lb-name ${prefix}-lb \
  --name myHealthProbe \
  --protocol tcp \
  --port 80

az network lb rule create \
  --resource-group ${prefix}-rg \
  --lb-name ${prefix}-lb \
  --name myHTTPRule \
  --protocol tcp \
  --frontend-port 80 \
  --backend-port 80 \
  --frontend-ip-name myFrontEnd \
  --backend-pool-name myBackEndPool \
  --probe-name myHealthProbe \
  --disable-outbound-snat true \
  --idle-timeout 15 \
  --enable-tcp-reset true
```

## Azure VM を Azure Load Balancer に登録

```bash:bash
az network nic ip-config address-pool add \
  --resource-group ${prefix}-rg \
  --lb-name ${prefix}-lb \
  --address-pool myBackendPool \
  --ip-config-name ipconfig${prefix}-vm \
  --nic-name ${prefix}-vmVMNic
```

## Azure VM の NSG に自分のパブリック IP を許可

```bash:bash
az network nsg rule create \
  --resource-group ${prefix}-rg \
  --nsg-name ${prefix}-vmNSG \
  --name myNSGRuleHTTP \
  --protocol Tcp \
  --direction inbound \
  --source-address-prefix $(curl -s inet-ip.info/ip) \
  --destination-port-range 80 \
  --access allow \
  --priority 200
```

## パブリック IP を持たない Azure VM に Azure Load Balancer からパブリックアクセスを試す

```bash:bash
pip=$(az network public-ip show \
  --resource-group ${prefix}-rg \
  --name ${prefix}-pip \
  --query ipAddress \
  --output tsv)

curl -s $pip
```

下記のような結果になれば動作確認完了。

```txt
Hello World from host mnrvmlb-vm !
```

## 参考

https://learn.microsoft.com/ja-jp/azure/load-balancer/quickstart-load-balancer-standard-public-cli
DockerでDataikuの最新版を始めよう

# Dataikuとは

DataikuはAI/MLワークフローをGUIで構築できるプラットフォームです。  
自分で用意したPCやサーバやクラウドにインストールして使える無料版、マネージドでも使える(SaaSとして利用できる)有償版があります。  
有償版ではSnowflake/BigQueryへの接続やSpark対応など様々な機能が解禁されますが、無料版でもかなりのことができます。  
また、有償版は14日間の無料トライアルもあるので、サーバなんて持ってないよ！という方でもすぐにDataikuを体験することができます。  

![Dataiku Screenshot](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/0e889b2b-31b0-1ad4-80ac-e2702fc2d7db.png)

ちなみにDataikuは「ダタイクゥ」あるいは「データイクゥ」と発音するようです。初期からのユーザは「ダタイク」、最近のユーザは「データイク」と呼んでいることが多い印象。  
参考：[Dataikuのカンファレンス「Everyday AI」におけるCROの発音](https://youtu.be/iJj2UvilOJ0?t=53)  

https://youtu.be/iJj2UvilOJ0?t=53

## 準備するもの

- Dockerfile
- run.sh：Dockerコンテナ内でDataikuを起動させるスクリプト
- dataiku-dss-12.5.0.tar.gz：Dataiku DSSのLinux向けインストールファイル

## 事前準備

まずDataikuのLinux向けインストールファイルをダウンロードします。  
2024年1月時点ではまだバージョン12.x.xのインストール手順がトップページに反映されていないのですが、以下の[サイト](https://cdn.downloads.dataiku.com/public/dss/)から最新版をダウンロードできます。  
ファイル名は例えば```dataiku-dss-12.5.0.tar.gz```のようなものになります。  

https://cdn.downloads.dataiku.com/public/dss/

## Dockerfileと起動スクリプトを作成する

```sh:run.sh
#!/bin/bash

# Trap signals and exit
trap "exit 0" SIGINT SIGTERM
# Start Dataiku service
/dataiku/bin/dss start
# Keep on running 
while true
do
  sleep 10 & wait $!
done
```

```dockerfile:Dockerfile
ARG BASE_IMAGE=almalinux:8.9
FROM $BASE_IMAGE
ENV DSS_VERSION 12.5.0
ENV DSS_INSTALLDIR /tmp
ENV DSS_DATADIR /dataiku
ENV DSS_PORT=10000
RUN useradd dataiku
RUN mkdir -p ${DSS_DATADIR} && chown -Rh dataiku:dataiku ${DSS_DATADIR}
COPY dataiku-dss-${DSS_VERSION}.tar.gz ${DSS_INSTALLDIR}
RUN tar -zxvf ${DSS_INSTALLDIR}/dataiku-dss-${DSS_VERSION}.tar.gz -C ${DSS_INSTALLDIR} && rm -f ${DSS_INSTALLDIR}/dataiku-dss-${DSS_VERSION}.tar.gz
RUN ${DSS_INSTALLDIR}/dataiku-dss-${DSS_VERSION}/scripts/install/install-deps.sh -yes
RUN yum install -y epel-release && yum install -y --enablerepo=powertools git nginx unzip zip glibc-langpack-en java-1.8.0-openjdk python36 freetype libgfortran libgomp && yum clean all
USER dataiku
RUN ${DSS_INSTALLDIR}/dataiku-dss-${DSS_VERSION}/installer.sh -y -d ${DSS_DATADIR} -p 10000
EXPOSE 10000
COPY run.sh /
USER root
RUN chmod +x /run.sh
USER dataiku
CMD /run.sh
```

## 起動手順

上記のDockerfileで実行しているインストールコマンドでは、Dataikuがポート10000で待ち受けするようになるので、そのポートをEXPOSEします。  
また、Dataikuのインストールフォルダにボリュームを割り当てて永続化します。  

```sh
docker build -t dataiku:latest .
docker run -p 10000:10000 -v dataiku:/dataiku dataiku:latest
```

localhost:10000で立ち上がるので、ブラウザでアクセスすればOKです！  

## 備考

Dockerでインストールするとアップデートでちょっと困ります…  
今後、やり方を確認します。
Crystalでは文字列を継承できない - inherited マクロ

## はじめに

タイトルの通りです。RubyとCrystalは文化が違うので、ところどころ挙動が違います。
面白いことにCrystalはStringを継承できません。たとえば、

```cr
class MagicSpell < String
end
```

を実行すると、次のようなエラーがでます。

```
Error: Cannot inherit from String
```

これがどのように実現されているのかというと、

## inherit マクロ

inheritマクロを使って書かれていました。使い方はとても簡単で、[こんな感じ](https://github.com/crystal-lang/crystal/blob/b8a24e7d94bd35999d0bf4eff0aac368f6be7bcb/src/string.cr#L153-L155)です。

```cr
class String
  macro inherited
    {{ raise "Cannot inherit from String" }}
  end
end
```

Rubyでも[Class#inherited](https://docs.ruby-lang.org/ja/latest/method/Class/i/inherited.html)がありますが、それと同じように使えるようですね。

このマクロがどのように定義されているのか調べようと思いましたが、よくわかりませんでした。Crystalでは、マクロは

```cr
macro define_method(name, content)
  def {{name}}
    {{content}}
  end
end
```

このような感じで定義します。そのため `macro inherited` という記法はそれ自体がマクロの定義になってしまいます。

[ここ](https://github.com/crystal-lang/crystal/blob/b8a24e7d94bd35999d0bf4eff0aac368f6be7bcb/src/compiler/crystal/types.cr#L943)のコードを見ると、`inherited` マクロは、他のいくつかのマクロ（`included`, `extended`, `method_added`, `method_missing`）などとともに名前のレベルで特別扱いされているようです。そんな用語はないですが、マクロの予約語といった感じでしょうか。

```cr
    def add_macro(a_macro)
      a_macro.owner = self

      case a_macro.name
      when "inherited"
        return add_hook :inherited, a_macro
      when "included"
        return add_hook :included, a_macro
      when "extended"
        return add_hook :extended, a_macro
      when "method_added"
        return add_hook :method_added, a_macro, args_size: 1
      when "method_missing"
        check_macro_param_count(a_macro, 1)
      else
        # normal macro
      end
```

このうち `method_missing` に関しては、開発者によって追加したことを後悔している発言もあったはずで、あまり推奨ではないと思いますし、これらの特別なマクロについてAPIリファレンスをググってもあまり出てきませんので、Crystalでも一応できるけど推奨はされていない黒魔術ということになると思います。

## Stringが継承できないことの意味


私はRubyの動的な性質やダックタイピングが好きです。しかし静的言語のCrystalで、Stringを継承したライブラリが無数に作られると、型の不整合で問題が発生しやすくなる気はします。文字列に関しては、標準ライブラリのStringを拡張せずそのまま使ってほしいというメッセージだと理解しました。
pdf-libで日本語のカスタムフォント使用時にpdfが作成できない

pdf-libで日本語のカスタムフォント使用時にpdfが作成されず、真っ白な状態になってしまった。
特にエラーなどは表示されていない状態だったのでどこがまずいのかがわからなかった。

最初のコードは以下

```js
const pdfDataUri = await pdfDoc.saveAsBase64({ dataUri: true });
document.getElementById('pdf').src = pdfDataUri;
```

日本語フォントを使って正常にpdfを作成できているサンプルコードを探したところ以下のように読み込んでいたので、同じように変更したところ見事に作成できた。

```js
const pdfBytes = await pdfDoc.save();
const file = new Blob([pdfBytes], { type: 'application/pdf' });
const fileURL = URL.createObjectURL(file);
document.getElementById('pdf').src = fileURL;
```

どうやらsaveAsBase64で読み込んでいた部分が問題だったようである。

解決後に改めて検索したところ類似のissueがあり、詳細はおそらくこれと一緒だろうと思われる。（saveAsBase64 fontで検索）
小さなサイズの日本語フォントだとsaveAsBase64でも表示されたのでサイズが原因であったと思われる。
Firefoxだとエラー表示されるらしいので色んなブラウザで試してみた方が早く解決できたかもしれない。

Something wrong with custom font. #430
https://github.com/Hopding/pdf-lib/issues/430

以上です。