OmniAICreator/Qiita-1.07M huggingface dataset:
HTML・CSSで要素を見えなくする方法とアクセシビリティ

## これは何

Webサービスなどを作っていると、しばしば「要素を非表示」にするタイミングがあります。

- モーダルやドロップダウン、ツールチップなどアクションによって「表示/非表示」になる要素
- 要素を開閉できるアコーディオンメニュー
- レスポンシブでdesktop/mobileの時だけ表示したい要素

などなどです。

こうしたUIを実装するときに、選ぶ方法によっては、アクセシビリティツリー上で削除されたりされなかったりします。

そのため、適切な方法を選ばないと、本来読み上げもスキップしたかったのに読み上げられてしまったり、逆に読み上げはして欲しいのに読み上げられなくなったりします。

また、見た目的には非表示になっていても、hoverやfocusができる場合とできない場合があり、意図せぬ挙動にもつながります。

:::note
アクセシビリティツリーとは、DOMツリーに基づいて生成されるスクリーンリーダーなどの支援技術に使用される情報です
:::

そこで、要素を見えなくする方法をレイアウト上で無視されるかとアクセシビリティツリー上でどう読み上げられるかでまとめてみました。

## 結論

結論は以下の図です。
HTML・CSSで要素を非表示にする方法は色々ありますが、主流っぽいものや比較的使われてそうなものを主観で集めました。

※そもそも表示されない要素はレンダリングしないという方法もありますが、今回はHTML・CSSに絞っているので入れてないです。

プロパティ | レイアウト上で | アクセシビリティツリー上で
-|-|-
`display: none` | 無視される | 削除される
`visibility: hidden` | 無視されない | 削除される
`hidden` （グローバル属性）  | 無視される | 削除される
`opacity: 0` | 無視されない | 削除されない
`transform: scale(0,0)` | 無視されない | 削除されない

実際にそれぞれを指定してみると以下のようになります。

:::note
それぞれ3つの四角を並べて、真ん中の四角に非表示になるように指定しています。
:::

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="ExrXOYK" data-user="kabechiyo" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kabechiyo/pen/ExrXOYK">
  Untitled</a> by kabechiyo_shunkaaizawa (<a href="https://codepen.io/kabechiyo">@kabechiyo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

レイアウトが無視される`display: none`と`hidden`は非表示になった四角の分左に詰まりますが、それ以外の指定はレイアウトが無視されないので見えなくてもスペースが空いています。

別途`width`と`height`を`0`にしたり、`position: absolute`を指定することで、レイアウトからも無視される（ように見える）ようにできます。

また、それぞれの要素をアクセシビリティツリー上でみてみると以下のようになっています。

プロパティ | アクセシビリティツリー上の表示
-|-
`display: none` | StaticText "1" <br /> StaticText "3"
`visibility: hidden` | StaticText "1" <br /> StaticText "3"
`hidden` （グローバル属性）  | StaticText "1" <br /> StaticText "3"
`opacity: 0` | StaticText "1" <br /> StaticText "2" <br /> StaticText "3"
`transform: scale(0,0)` | StaticText "1" <br /> StaticText "2" <br /> StaticText "3"

`display: none`と`visibility: hidden`と`hidden` （グローバル属性）では、指定した要素がアクセシビリティツリー上から削除されるので「2」が読み上げられず、それ以外は読み上げられます。

## 要素を非表示にする方法それぞれについて

それぞれの方法の特徴も簡単にみていきます。

### `display: none`

レイアウト上も無視されるようになり、アクセシビリティツリーからも削除されます。
要素を非表示にするだけでなくそもそもないものとして扱いたい時に使います。

https://developer.mozilla.org/ja/docs/Web/CSS/display

### `visiblity: hidden`

レイアウト上では無視せず、アクセシビリティツリー上からは削除されます。
要素の表示/非表示を切り替えた時に他の要素の位置に影響を与えたくない時などに使います。

https://developer.mozilla.org/ja/docs/Web/CSS/visibility

### `hidden`

CSSのプロパティではなく、グローバル属性として指定します。
レイアウト上も無視されるようになり、アクセシビリティツリーからも削除されます。
`hidden`が指定された要素に`display: block`などを指定すると上書きして表示されるようになります。

https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/hidden

### `opacity: 0`、`transform: scale(0,0)`

要素は存在したままで、透明度を0にしたりサイズを0にすることで見えなくしています。
こうしたツリー上は存在しているけど、視覚的に見えないようにする方法は他にも色々とありますが、指定がシンプルなものをピックアップしました。
ツリー上で存在しているのでアクセシビリティツリー上で読ませたい時に使います。

## 終わりに

HTMLとCSSを使って要素を見えなくする方法は複数存在しますが、それぞれ特徴があるので、うまく使い分けましょう :thumbsup:
Azure AI Bot Service メモ

# はじめに

Azure AI Service でナレッジ ベースを利用すると、 Language Studio の画面上でナレッジ ベースを作成からトレーニングとテスト、更にデプロイまで実施できます。
そして、デプロイ完了後に自動ボット作成機能を実行することで、 Azure portal で Web App Bot を作成できます。
つまり、画面上の操作のみで FAQ のボットを作成し、利用可能とすることができるのです！

# MS ドキュメント

- Azure AI Bot Service ドキュメント
  - https://learn.microsoft.com/ja-jp/azure/bot-service/?view=azure-bot-service-4.0
  - ※個人の M365 アカウントでは、 [Power Virtual Agents](https://learn.microsoft.com/ja-jp/power-virtual-agents/fundamentals-what-is-power-virtual-agents) は利用不可

# 自動ボット作成機能をを利用する場合の大まかな流れ

- Azure portal（[portal.azure.com](portal.azure.com)）で言語サービスを作成する。
- Language Studio（[https://aka.ms/languageStudio](https://aka.ms/languageStudio)）で作成した言語サービスのカスタム質問応答機能を使用して、ナレッジ ベースを作成する。
- Language Studio でナレッジ ベースのトレーニングとテストを行う。
- Language Studio でナレッジ ベースをデプロイする。
- デプロイ後に、 Language Studio の「ボットの作成」にて Azure portal を開く。（自動で別タブが開く）
- 開いた Azure portal に表示された画面から Web App Bot を作成する。

## 参考

- 質問への回答を調べる
  - https://microsoftlearning.github.io/AI-900-AIFundamentals/instructions/04d-create-a-bot.html
- Azure AI Language と Azure AI Bot Service を使用してボットを構築する
  - https://learn.microsoft.com/ja-jp/training/modules/build-faq-chatbot-qna-maker-azure-bot-service/

# カスタムのボットを作成する場合の情報

- 音声を使用する Bot を作成したり、自然言語を理解したり、質問や回答を処理する場合などで、カスタムの Bot を作成する。
- Microsoft Bot Framework SDK を使用
  - Microsoft Bot Framework と Azure AI Bot Service には、インテリジェント ボットを構築、テスト、デプロイ、管理するためのツールが用意。
  - Bot Framework には、ツール、テンプレート、関連する AI サービスなど、ボットを構築するためのモジュール式の拡張可能な SDK が含まれる。

## 参考

- Bot Framework SDK
  - https://learn.microsoft.com/ja-jp/azure/bot-service/bot-overview?view=azure-bot-service-4.0#bot-framework-sdk
- Bot Framework SDK を使用してボットを作成する
  - https://learn.microsoft.com/ja-jp/training/modules/design-bot-conversation-flow/
ssh config でマシンが所属するネットワークを判断して使用する設定を切り替える

特定のホストにSSHする際に、LAN内からかインターネットからかで使用するIPやポート番号などが異なるのはよくあることかと思う。Linux限定だが、所属ネットワークを自動判別して接続する設定例を下に示す。内部的には `ip` コマンドでネットワークを判断している。判定時に外部アクセスしない点がよいと思っている。

なお、ホスト名は `example` アドレスは `192.168.0.5/24` であり、それが外部からだと `203.0.113.10` で接続できるものとする。

```ssh
Match host example exec "test $(ip address show up to 192.168.0.0/24 | wc -c) != 0"
  Hostname 192.168.0.5
Host example
  Hostname 203.0.113.10
```

いたってシンプルである。
gawkで整数から微妙にずれた浮動小数点数を配列添字にしたときの挙動

ちょっとよくわからない現象にでくわしたのでメモ。

整数から微妙にずれた浮動小数点数というのを作ることがありますね。たとえば 1.0/5.0 を５倍するとか。
どうもそれをawk配列引数にすると変なことが起こります。

調べてみましょう。１より微少量大きな数値を作って、配列添字にして参照できるか試してみます。

```awk:aryidx.awk
BEGIN {
  print CONVFMT
  a[1] = 1
  a[2] = 2
  epsilon = 1
  for (i = 0; i <= 60; i++) {
    j = 1 + epsilon
    epsilon *= 0.5
    print "1+2**", -i, "=", j, "<", a[j], ">"
  }
}
```

実行すると、よくわからないのが次の３点：
* 浮動小数点数を文字列変換するときに、CONVFMT 組み込み変数（値 "%.6g"）を使うはずなのだが、どうも桁数が違う（実際、CONVFMT 変数を書き換えてみても１行目以外出力が変わらない）
* 配列添字は文字列で、数値を与えた場合には文字列に変換して用いる、とされているのだが、文字列変換結果が "1" なのに配列参照結果が a[1] と同じにならない場合がある
* おそらく、倍精度浮動小数点数として異なるものは、配列添字として別に扱われるようだ（1+2**-53は倍精度で表現できるが、1+2**-54は１と区別できなくなってしまうため）

```
$ gawk -f aryidx.awk 
%.6g
1+2** 0 = 2 < 2 >
1+2** -1 = 1.5 <  >
1+2** -2 = 1.25 <  >
1+2** -3 = 1.125 <  >
1+2** -4 = 1.0625 <  >
1+2** -5 = 1.03125 <  >
1+2** -6 = 1.01562 <  >
1+2** -7 = 1.00781 <  >
1+2** -8 = 1.00391 <  >
1+2** -9 = 1.00195 <  >
1+2** -10 = 1.00098 <  >
1+2** -11 = 1.00049 <  >
1+2** -12 = 1.00024 <  >
1+2** -13 = 1.00012 <  >
1+2** -14 = 1.00006 <  >
1+2** -15 = 1.00003 <  >
1+2** -16 = 1.00002 <  >
1+2** -17 = 1.00001 <  >
1+2** -18 = 1 <  >
1+2** -19 = 1 <  >
1+2** -20 = 1 <  >
1+2** -21 = 1 <  >
1+2** -22 = 1 <  >
1+2** -23 = 1 <  >
1+2** -24 = 1 <  >
1+2** -25 = 1 <  >
1+2** -26 = 1 <  >
1+2** -27 = 1 <  >
1+2** -28 = 1 <  >
1+2** -29 = 1 <  >
1+2** -30 = 1 <  >
1+2** -31 = 1 <  >
1+2** -32 = 1 <  >
1+2** -33 = 1 <  >
1+2** -34 = 1 <  >
1+2** -35 = 1 <  >
1+2** -36 = 1 <  >
1+2** -37 = 1 <  >
1+2** -38 = 1 <  >
1+2** -39 = 1 <  >
1+2** -40 = 1 <  >
1+2** -41 = 1 <  >
1+2** -42 = 1 <  >
1+2** -43 = 1 <  >
1+2** -44 = 1 <  >
1+2** -45 = 1 <  >
1+2** -46 = 1 <  >
1+2** -47 = 1 <  >
1+2** -48 = 1 <  >
1+2** -49 = 1 <  >
1+2** -50 = 1 <  >
1+2** -51 = 1 <  >
1+2** -52 = 1 <  >
1+2** -53 = 1 < 1 >
1+2** -54 = 1 < 1 >
1+2** -55 = 1 < 1 >
1+2** -56 = 1 < 1 >
1+2** -57 = 1 < 1 >
1+2** -58 = 1 < 1 >
1+2** -59 = 1 < 1 >
1+2** -60 = 1 < 1 >
$ gawk --version | head -1
GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.4, GNU MP 6.1.0)
```

オチはありませんよ。
【Laravel】with

Laravel=5.6
## withとは？
リレーションテーブルのデータを取得するための、Eloquentの記法。N+1問題を防止することができる。
#### 使い方
``` Account.php
public function posts () {
    $this->hasMany('Post');
}
```
```
Account::with('posts')->get();
```
#### N+1問題とは？
アカウント数+1回のSQLが実行されるためパフォーマンスが悪い
```
$accounts = Account::get(); // Account::get()でSQL1回実行
foreach ($accounts as $key => $account) { 
    $accounts[key]->posts = $account->posts; // foreachの回数分SQL実行
}
```
## 様々な記法
#### 2つ以上"先"のリレーション
```Post.php
public function comments () {
    $this->hasMany('Comment');
}
```
```
Account::with('posts.comments')->get();
```
#### 2つ以上のリレーション
```Post.php
public function account () {
    $this->belongsTo('Account');
}
```
```
Post::with(['account', 'comments'])->get(); 
```
#### whereやorder by
##### アカウントデータをアカウント名昇順でソート
```
Account::with('posts.comments')->orderBy('name')->get();
```
##### コメントデータをコメント日時降順でソート
```
Account::with(['posts.comments' => function ($query) {
    $query->orderByDesc('created_at');
})->get();
```
##### 投稿データを投稿日時でフィリタリングし、コメントデータも取得
```
Account::with('posts.comments')->with(['posts' => function($query){
    $query->where('created_at', '>', '2023-01-01 00:00:00');
}])->get();
```
## whereHas
リレーション元のデータを、リレーション先のデータでフィルタリング

※withでは、リレーション元のデータをリレーション先のデータでソートやフィルタリングできない
##### アカウントデータをコメント日時でフィルタリング
```
Account::whereHas('posts.comments', function ($query) {
    $query->where('created_at', '>', '2023-01-01 00:00:00');
})->get();
```
Scrapyの環境構築　備忘録

## Scrapy のインストール
```
pip intall scrapy
```

## プロジェクトの作成（作業フォルダの作成込み）
```
scrapy startproject test_project /Users/user/ScrapyTest
```
 上記のコマンドを入力すると
指定した場所に「test_project」という名前のプロジェクトが作成される

### プロジェクトの中身
```
ScrapyTest
├── test_project
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│          └── __init__.py
└── scrapy.cfg

```

## Spiderの作成
```
scrapy genspider get_scraping_list URL 

```
scrapy genspider　[スパイダー名]　[URL]で目的のサイトを指定したspiderの作成を行う。
※指定するURLはhttps://と最後の/を消しておく必要がある。

コマンドを実行すると、spidersフォルダの下にspiderのファイル、get_scraping_list.pyが作成される
【Node.js】Expressを使ってウェブアプリを作る

Node.jsで
さくっとウェブアプリで試したいとき
毎回、えーとって悩むので自分用備忘録


```
$ npm init
$ npm i express
```

作成された package.json
```package.json
{
  "name": "express-test",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.2"
  }
```

ルートディレクトリにmainに指定した app.js ファイルを作成

```app.js
var http = require("http");
var express = require("express");

var app = express();

app.get("/", function (req, res) {
  return res.send("Hello World");
});

// ルーティング
app.get("/hoge", function (req, res) {  
  return res.send("Hoge");
});

var server = http.createServer(app);
server.listen(3000);

```

app.js を実行

```
node app.js
```
http://localhost:3000/ にアクセスすると
「Hello World」
と表示されます。

ルーティングにより
http://localhost:3000/hoge にアクセスすると
「Hoge」
と表示されます。

以上です。
ガウス過程回帰とデータ数・次元数・計算時間

# 背景
ガウス過程回帰は[データ数nが増えると、n×nの行列計算が必要になりメモリや計算量を圧迫してしまう](https://www.jstage.jst.go.jp/article/isciesci/62/10/62_390/_pdf)という欠点が存在する。  
実務上どの程度影響するのかを把握するため、疑似データでモデル構築の時間を計測した結果をまとめる。  

# 環境  
Google Colab  

# 実験コード
```Python:GPR.py
import time
import warnings

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import WhiteKernel, RBF, ConstantKernel, Matern, DotProduct


warnings.filterwarnings('ignore')

list_time = []

# 自身で検討したい範囲を設定
# なおデータ数・次元数のどちらかが1000を超えると深層学習並みに時間がかかったので今回は割愛
list_samplesize = [10, 20, 50, 70, 90, 100, 200, 300, 400, 500, 600]
list_dimension = [3, 5, 7, 9, 10, 15, 20, 50, 100, 120, 150, 200, 300]

for i in list_samplesize:
    start = time.time()
    list_tmp = []

    for j in list_dimension:
        # データの用意
        data = pd.DataFrame(np.random.randn(i, j))
        X = data.iloc[:, :-1]
        y = data.iloc[:, -1]
        kernel = ConstantKernel() * RBF(np.ones(X.shape[1])) + WhiteKernel() + ConstantKernel() * DotProduct()

        # モデル作成
        start_ = time.time()
        model = GaussianProcessRegressor(alpha=0, kernel=kernel)
        model.fit(X, y)
        end_ = time.time()
        list_tmp.append(end_ - start_)

    list_time.append(list_tmp)
    end = time.time()

df_time = pd.DataFrame(list_time,
                       index=list_samplesize,
                       columns=list_dimension)

# 可視化
plt.plot(df_time, label=df_time.columns)
plt.legend(title='number of dimension')
plt.title('GPR calculation time \n when changing number of data and dimension')
plt.xlabel('number of data')
plt.ylabel('cal. time (sec.)')
plt.savefig('GPR_calculation_time.png')
plt.show()
```

# 結果・所感  
- 概ねデータ数と次元数が増えればモデル作成にかかる時間も伸びる傾向が見られた  
    - 200データ以下であれば、10秒以内に計算が終わる  
    - 300データ以上でもほぼ1分前後で計算できる
- 例えば600データ・300次元でモデル作成を行ったときのように、データ数・次元数が大きいにもかかわらずモデル作成時間が短い場合も存在  
    - scikit-learnの仕様？  
- 今回はやらなかったが、よりデータ数・次元数が多い場合は[GPyTorch](https://gpytorch.ai/)というGPUで演算可能なライブラリを利用することも検討か
    
![GPR_calculation_time.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1507794/bd4c03e2-bb80-eb75-59e5-7a14c98fc24b.png)
  

# 参考資料  
- ガウス過程の基礎 https://www.jstage.jst.go.jp/article/isciesci/62/10/62_390/_pdf
- GPyTorch公式ドキュメント https://gpytorch.ai/
Edge (というかChromium) の SSLエラー サンプル(?)一覧ページについて

# これは何？
かつてなくタイトルがカオスですがまあそのままです。
つまりは覚書。

# 経緯
[Chromium Code のとある場所](https://chromium.googlesource.com/chromium/src/+/66.0.3359.158/chrome/browser/ui/webui/interstitials/interstitial_ui_browsertest.cc) を眺めていたらなんか
[chrome://interstitials/ssl--invalid--](chrome://interstitials/ssl--invalid--) というリンクが目についたので踏んだ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/2fae8d85-9289-db1b-0d82-80a8e2a111ea.png)

なんかいろいろあった。
試しに Clock is ahead を踏むと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/77452af8-6d96-2f6b-fde5-eb3fc14d457b.png)
こんな感じ。要は組込の [BadSSL](https://badssl.com/) もどき(?)ですね。
Pythonで「指定した文字列が対象の文字列に含まれる位置を取得する(find, rfind, index, rindex)」の動作を確認してみた

# 概要

Pythonで「指定した文字列が対象の文字列に含まれる位置を取得する(find, rfind, index, rindex)」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/python/string/index16.html

# 実装

以下のファイルを作成しました。
```sample.py
print("dictionary".find("io"))
print("Good School".find("oo"))
print("Goooood".find("oo"))
print("Orange".find("aa"))
print("")
print("Good School".find("oo"))
print("Good School".find("oo", 3, 10))
print("Good School".find("oo", 3))
print("")
print("dictionary".index("io"))
print("Good School".index("oo"))
print("Good School".index("oo", 3))
#print("Orange".index("aa"))
print("")
print("dictionary".rfind("io"))
print("Good School".rfind("oo"))
print("Goooood".rfind("oo"))
print("Orange".rfind("aa"))
print("")
print("Good School".rfind("oo"))
print("Good School".rfind("oo", 0, 6))
print("Good School".rfind("oo", 3))
print("")
print("dictionary".rindex("io"))
print("Good School".rindex("oo"))
print("Good School".rindex("oo", 0, 6))
#print("Orange".rindex("aa"))
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
4
1
1
-1

1
8
8

4
1
8

4
8
4
-1

8
1
8

4
8
1
```

# まとめ

何かの役に立てばと。
【Flutter】GoogleFontsを適用したが、AppBarのtitleにだけ適用されない

## 問題
以下を参考にさせていただき、アプリの全体のフォントをGoogleFontsのキウイ丸に変更した。

https://qiita.com/an_pqn7/items/d108d5d5e2058d037191#%E5%85%A8%E4%BD%93%E3%81%AB%E5%A5%BD%E3%81%8D%E3%81%AAgoogle-fonts%E3%82%92%E9%81%A9%E5%BF%9C%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84%E3%81%A8%E3%81%8D

しかし、AppBarのタイトルだけ、元のフォントのまま変わらない。

## 原因
appBarThemeでtitleTextStyleを指定していたため、そちらが優先して、デフォルトのフォントで表示されてしまったようでした。

## 解決方法
appBarThemeのtitleTextStyleをGoogleFonts.kiwiMaru（ここはお好きなフォント名）で囲むことで解決しました。

```dart:MaterialAppのtheme
 theme: ThemeData(
          primarySwatch: AppColors.mainBackColorMaterial,
          appBarTheme: AppBarTheme(
            titleTextStyle: GoogleFonts.kiwiMaru( //元のtextStyleをGoogleFonts.kiwiMaruで囲んだ
                textStyle: const TextStyle(
              color: AppColors.mainTitleTextColor,
              fontWeight: FontWeight.bold,
              fontSize: 25,
            )),
          ),
          textTheme: GoogleFonts.kiwiMaruTextTheme(
            Theme.of(context).textTheme,
          )),
```
GPTsで 日本のSDGs頑張りを答えさせる

# こんなのを作ってみた

2023年11月6日 OpenAIから新サービスGPTsが発表されました。
→ 早速試してみました

#### 世界初！？ SDGsaas (SDGs as a Service)

https://chat.openai.com/g/g-hPAWfgVjD-ri-ben-noshi-ting-cun-nosdgsjiao-emasu-ling-he-4nian-ban

# 画面ショット
![スクリーンショット 2023-11-13 18.55.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111758/32969055-26e8-6c8c-3274-ea81e95c6e98.png)

# GIF
![SDGs-Japan-R4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111758/fbd82d7e-4454-4c04-0768-a8b0c421bf80.gif)


# Knowledgeデータ詳細
GPTsはKnowledgeファイルをアップロードすることで、データを分析しながら回答ができます。今回は下記のデータを利用しました。

入力データは事前にトリミングをしています。これは、ChatGPTがKnowledgeデータを分析する際に、内部でPandasを動かしてクエリを発行しているためです。

→ 今回はデータ分析でよく使われるトリミング手法を使いました。

## e-Stat 統計で見る日本
- SDGｓに関する全国アンケート調査
    - 調査担当： 内閣府 地方創生推進室
        - [SDGs 市町村別アンケート 2022年度](https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00100502&tstat=000001172047&cycle=0&tclass1val=0)

![スクリーンショット 2023-11-13 19.09.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111758/979c2eb7-15a8-b12a-970b-98b0ee70d987.png)
MacでAnsibleのprometheusコレクション実行時にエラーが起きる場合の対処方法

Ansibleのprometheusコレクションを使おうとしたときにエラーでちょっと詰まったのでメモ。

https://prometheus-community.github.io/ansible/branch/main/

roleを実行しようとしたところ以下の部分で、Pythonがクラッシュしてしまう。

```shell
TASK [prometheus.prometheus.node_exporter : Get checksum list from github] ************************************************************************************************************************************
objc[69554]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called.
objc[69554]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
ERROR! A worker was found in a dead state
```


## 解決方法
実行時に環境変数を設定
```bash
$ export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
```

これでクラッシュしなくなる。
【備忘録】Dockerを使ってBunを使って、Next.jsを起動する

# Dockerを使ってBunを使って、Next.jsを起動する
## 結論
nodeにBunいれた
## きかっけ
巷で話題のBunを使いたい！
## 起こったこと
1. BunのDockerイメージで構築→失敗
2. 諦めてNodeで構築→成功？
3. Nodeでnpmでbunをインストール→成功！
## 実際のコード
```Dockerfile:Dockerfile
FROM node:latest

WORKDIR /app

RUN npm install -g npm@latest

RUN npm install -g bun

RUN npm install create-next-app

RUN npm install && npm upgrade

EXPOSE 3000
```
```yaml:docker-compose.yaml
version: '3'

services:
  front:
    build: ./front
    container_name: front
    tty: true
    ports:
      - "3000:3000"
    volumes:
      - ./front:/app
    working_dir: /app/各々のプロジェクト
    environment:
      - WATCHPACK_POLLING=true
    command: sh -c "bun run dev"
```
後はDocker動かす
wslでelixir その101

# 概要
wsl(wsl2じゃない)で、elixirやってみた。
練習問題、やってみた。

# 練習問題
Livebookで、smart chartを使え。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/c705ef0a-b51a-5218-3e7c-29e97cdc7db6.png)

# サンプルコード

```
y =
  1..100
  |> Enum.map(fn x ->
    :math.sin(x / 5)
  end)

x =
  1..100
  |> Enum.map(fn x ->
    x
  end)

my_data = %{x: x, y: y}

```


以上。
マークアップ個人的チェックポイント

# 概要
マークアップ時に気をつける点をまとめました。
随時更新します。
レビュー依頼出す前や取り掛かる前などに漏れがないかで確認してもらえるといいかも。
参考記事も併せて載せておきます。

# チェックポイント
以下、チェックポイントです。

## CSS設計
主にlayoutとcomponentの命名規則を気をつけると良し。
参考記事) https://zenn.dev/wagashi_osushi/books/94efd21a66ccaa/viewer/52ffd6

## rel="noopener noreferrer"
target="_blank"で別タブに飛ぶ時にセキュリティ対策として気をつけたい。
参考記事) https://webst8.com/blog/rel-noopener-noreferrer/#st-toc-h-2

## marginとpadding
意外と使い分けが曖昧なもの。兄弟間はmargin-topとleft。
親子間はpaddingで間隔を空けると良し。
参考記事) https://eclair.blog/difference-between-margin-and-padding/

## alt
ちゃんとつけてますか？
空でもいいのでちゃんとつけましょう。
https://www.orange-sha.co.jp/blog/web07_alt/

## グリッドレイアウト
そのレイアウトdisplay: flexもいいけど、グリッドレイアウトの方が作りやすかったりしませんか？
https://qiita.com/yuya-yuya/items/3216eb28cff18aaf4ac4
ランタイムロードしたVRMモデルのボーン参照を取得

これは [ここのえ Advent Calendar 2023](https://qiita.com/advent-calendar/2023/99no_exit) Day 4 の記事です。

# Overview

**UnityでVRMを使用し、各種外部APIやデバイスを使ってモデルを動かしたい事、ありますよね……**？

予めインスペクタ上に配置したモデルであれば、対象となるボーンの参照をSerializeField等で捕まえておけばいいので簡単ですが、ランタイムロードしたモデルとなると少し話が変わってきます。

VRMのパッケージに付属している、`VRMUtility`を使ってランタイムロードした際、特定のボーンを取得することができます。

# 実装

```cs
// ランタイムロード
var path = "/path/to/vrm"
var instance = await VrmUtility.LoadAsync(path, new RuntimeOnlyAwaitCaller());
instance.ShowMeshes();
  
// アバターのGameObjectにHumanoid classをアタッチ
var avatar = instance.gameObject;
var humanoid = avatar.AddComponent<Humanoid>();
humanoid.AssignBonesFromAnimator();

// ボーンの参照を取得
var neck = humanoid.Neck;
var spine = humanoid.Spine;
```

:::note info
VRM 0.x系で動作確認しています。
:::

# 解説

ランタイムロードについては結構情報があるので、ここでは説明は省略します。

```cs
var instance = await VrmUtility.LoadAsync(path, new RuntimeOnlyAwaitCaller());
var avatar = instance.gameObject;
```
まずロード時の返り値ですが、`RuntimeGltfInstance`が返ってきます。
`RuntimeGltfInstance`は`MonoBehavior`を継承しているため、正常にVRMデータがロードできているならば、`avatar.gameObject`でGameObjectの参照を引っ張ってくることができます。

```cs
var humanoid = avatar.AddComponent<Humanoid>();
humanoid.AssignBonesFromAnimator();
```

今回の中心的な部分はこのコードになるのですが、VRMのパッケージ内に`Humanoid`コンポーネントが用意されています。
これはgltfで読み込んだモデルにヒューマノイドボーンが設定されていれば、シーンから直接Humanoid Avatarを作ることができます。

ここで用意されているメソッド `AssignBonesFromAnimator()` を呼び出すと、自動的にボーンの構成を読み込んでくれます。

また`Humanoid`コンポーネントで各種ボーンの参照を保持しているので、これを引っ張ってくることで、ランタイムロードされたモデルのボーン参照を取ってくることができます。

# おまけ

JINS MEMEを使って3Dモデルを動かす、VTuber向け配信用アプリケーション「[**Streameme**](https://github.com/nonuplet/streameme)」を開発しています。それの開発時に得た知見でした。

# 参考資料

https://vrm-c.github.io/UniVRM/ja/api/0_95_highlevel.html

https://vrm.dev/univrm/humanoid/meshutility_humanoid.html
Rubyで標準入出力がリダイレクトされてもリダイレクトされていない時と同じように動いてほしい

# はじめに
本題に至るまでに疲れて脱落者が出そうなので、はじめにお断りです。

Rubyでの\\$stdinや\\$stdoutの使い方の話ですよ！

では、始めましょう。

# 背景
最近Macを更新しました。接続規格が大幅に変わっているので、周辺機器が軒並み繋がらないのは覚悟していたのですが、「流石にこれは大丈夫ではないか」と思っていたバーコードリーダーも使えなくなってしまいました。バーコードリーダーはキーボードの振りをするのですが、最近のMacでは「そんな怪しいキーボードは使わせない」ということなのか接続されたことは認識するもののそれ以上は進みません。（おそらくセキュリティ強化のためなのでしょう。そういう時代ですよね、、、）
そこで「パンがなければお菓子を食べればいい」ということで、以下のように回避することにしました。
1. バーコードリーダーをFreeBSD（GhostBSD）に接続[^FreeBSD]。FreeBSDはUSBキーボードだと思ってくれるので、問題なく動作します。
1. FreeBSDで入力された値をネットワーク経由でMacに送信。
1. Macで受信したデータを標準出力に表示。
1. 今までコンソールで受け取っていたものの代わりに標準出力に表示されたものをデータとして受け取るように。

バーコードリーダーやFreeBSD（GhostBSD）は逸般の誤家庭にあるものをお使いください。

[^FreeBSD]: ちょっとここは省略し過ぎたのかもしれませんが「FreeBSDは仮想マシン上で動作しているのですか」と聞かれました。うーん、そういう時代なのかもしれませんね。だがしかし、だーかーらー、そもそもMacがハードウェアを認識しないのだから、Mac上の仮想マシンでOSを変わったのを使ったところで無駄でしょ！逸般の誤家庭なら当然実機です。

# ネットワーク通信（受信）の準備
ネットワークでデータを受信するプログラムはこんな感じでしょう。
~~~ receiver.rb
（抜粋です）
gs = TCPServer.open(port)
s = gs.accept
while a = s.gets
  print a
end
s.close
~~~
## 注意！！！
[背景](#背景)の内容から推測はつくと思いますが、データの送信側も受信側も自分の目の前にある（当然自分の目が行き届いている）というのが前提です。これを何も考えずにインターネット上でやって問題が起きても責任は負えません。

# 本題
ようやく本題です。以前は以下のようなプログラムでバーコードリーダーからのデータを受け取っていました。
~~~ input.rb
（抜粋です）
f = IO::console
print "ISBN: "
until f.eof
  t_isbn = f.readline.chomp
（以下略）
~~~
さて、receiver.rbを単体で動かすと「Macで受信したデータを標準出力に表示」ができていることが確認できました。
~~~
ruby receiver.rb | ruby input.rb 
~~~
で期待通り動作するといいですね。実際にやってみます。
、、、？？？input.rbがずっと入力待ちのままです。

# （半分）解決
そう言えば
~~~
f = IO::console
~~~
とコンソールから明示的に入力を受け付けるように書いてましたね。これでは動かないはずです。以下のように書き換えます。（もっと良い方法があるかも知れませんが、既存のスクリプトの書き換えが一番少なそうな方法なので、これで。）
~~~
f = $stdin
~~~
再挑戦します。データは確かに届きます。届くのですが、実際にバーコードリーダーを使っている時には何もデータは来なくて、FreeBSD側でネットワークを切断するとドドドっと来ます。
、、、そうじゃない！！！今までMacにバーコードリーダーを直接接続していた時みたいに動いてほしいんです。

# （残り半分）解決
解決に至るまで紆余曲折がありましたが、結果だけ書きます。
receiver.rbの初めの方で
~~~
$stdout.sync = true
~~~
と書けばよいです。
Rubyで標準出力を利用する機能は、標準出力先が「普通の」標準出力なのかそうでない（パイプとかリダイレクトとか）のかを把握して、それに応じて動作を変えているようです。上の設定は、「そういうのは気にしなくていいから、同期的に動いてね」という意味でしょう。
~~~
ruby receiver.rb | ruby input.rb 
~~~
で期待通り動作しました。

# おまけ
データの入力自体はうまくいっているのですが、バーコードリーダーが読み取った値はFreeBSD側の画面に表示されているだけで、Mac側には"ISBN: "とかの表示だけが流れていくだけです。これで妥協してもよかったのですが、「あとちょっとの労力」ということでMacでも表示されるようにしました。具体的には以下の２行目を追加です。
~~~
  t_isbn = f.readline.chomp
  puts t_isbn if not $stdin.tty?
~~~
これで画面表示も含めてそっくりになりました。めでたし、めでたし。

# おことわりなど

恒例のお断りですが、この文章の内容は、筆者が所属している会社・団体とは一切関わりがありません。いわゆる「自主的な研究の成果の発表」というものです。

え、タイトルが「リダイレクト」なのに書いてある内容は「パイプ」なのでは？ですか。その通りですけど、こまけぇこたぁいいんだよ!!
Next.js + Vercel AI でChatGPTのチャットボットなどをVercel にデプロイするときに引っかかったこと

## 概要

LangChainなどを使って、agentとチャットするアプリケーションをNext.jsやVercel AIを用いて構築して、
ローカルでは速度こそ遅いもののまあ動いていました。

それを
```
vercel build && vercel deploy
```

を用いてVercelにデプロイすると、アプリケーションのチャットのところで、
５０４のエラーが出て、調べると

https://community.openai.com/t/api-504s-in-production-vercel-only/28795

この辺りで議論されていることがわかりました。


## 解決策

結論として、タイムアウトが起きていました。
もともとvercel のfree プランでは１０秒でタイムアウトが出るようになっており、
vercel.json をルートディレクトリに作り、

```vercel.json
{
  "functions": {
    "app/api/**/*.ts": {
      "maxDuration": 60
    }
  }
}

```

このように書けば例えば６０秒までタイムアウトを防げるのですが、

１０秒を超えたければProプランをサブスクする必要があります。


というわけで、この構成で行きたければPro プランを使いましょう。
回避したければ他の方法になるということでした。そこはまだ調べていません。
とりあえずProプランが１４日間無料だったので契約して見ました。


## 追記
３０秒できっちりタイムアウトする人は、

```js
export const runtime = 'edge';
```

にしていませんか？

```js
export const runtime = 'nodejs';
```

 に変更しましょう。
 

以上。
マナビDX Quest 2023 ターム1に参加してみて

# はじめに
2023年度実施の[**マナビDX Quest**](https://dxq.manabi-dx.ipa.go.jp/)のターム1に参加してみての感想です。
「応募しようか迷っている」という方の参考になれば幸いです。
（ターム2も現在取り組み中なので、そちらの感想も2月下旬に投稿予定です）

# マナビDX Quest (ターム1)とは
経済産業省主催の「マナビDX Quest」。特徴を簡単に言うと...
- **ケーススタディ**
    - 「こんな企業があるとします。データはこれです。分析して、課題を見つけて、改善案を提案してください」という流れです。
- **講師がいない**
    - 講師による座学ではありません。
    - 参加者が情報交換して学び合い・教え合いながら、与えられた課題を解決していくPBL (Project-based Learning:プロジェクト型学習)を中心に据えたプログラムです。
- **とにかく受講生同士でワイワイ学ぶ**
    - 質問や、それに対する回答などの発信が受講生間で飛び交っています。
    - 有志で勉強会が開催されたりもしています。

# 参加した理由

### GCIを終えて
今回のマナビDX Questに応募する直前に、その頃参加していた[GCI 2023 Summer](https://www.u-tokyo.ac.jp/focus/ja/events/z0109_00882.html)が丁度終わりました。

GCIでは、`Python`を使った機械学習手法の基礎を学んでいました。
それに付随して独学では、生成AIの使い方、ショートカットキーの種類、論理的思考なども自分なりに学んでいました。

そんな中、GCIのアシスタントさんから、「マナビDX Questは更に**実践的**」という話を聞いたので、「GCIで学んできた知識をどれほど使えるのか試してみよう！」と思ったのがきっかけです。

### Excelを学びたかった
GCIで`Python`を学んだとは言え、そもそもExcelの基本的な関数の使い方すら危うかったため、「Excelを学びたい」と思い応募しました。

そういう訳で、マナビDX Questでは、Excelをメインに学ぶコース以外にもがっつりプログラミングをするコースもあるのですが、私はあえてExcelメインのコースを選択しました。

# 結果（所感）
- **Excel苦手意識は消滅した**
    - 基本的な関数は一通り、覚えるだけでなく使えるようになりました。（`vlookup`など）
    - Excelを使ったデータ分析手法も学ぶことができました（重回帰分析など）
- **ビジネス的な視点が身に付いた**
    - マナビDX Questでやることは、ただ与えられたデータを分析して自分なりに課題を見つけて解決策を提示して終わり、ではありません。
    - 経営層や従業員、顧客など、ステークホルダーの立場や意見も考慮した上で最終的な打ち手案を提案する必要があります。そのため、独りよがりのITコンサルティングではない、ビジネス的なDX推進力が身に付いたと感じています。

# その他
- マナビDXの「DX」は、「デジタル・トランスフォーメーション」ではなく、「デラックス」らしいです。意外ですね。
- 参加にあたって必要だったアセスメントテストが完全初学者の私にとっては非常に難しかったです。あれを何度もやり直したことで、既にマナビDX Quest開始時にはExcelの知識が大分ついていました。
【解決】Xcodeでプロジェクトを作るときにXcode error "Unable to create a save panel." when creating new Swift fileというエラーが出た時の対処法

<!-- 記述ルールは画面下部にあります。(コメントは削除して問題ありません) -->

# 概要

Xcodeで新しくプロジェクトを作成する時に、

```
"Unable to create a save panel." when creating new Swift file
```

というエラーが出た時の対処法です。

# 環境
Xcode Version 15.0.1 


- - -
# 詳細

***Macを外部ディスプレイに接続していることが原因です。***
備考欄にリンクを載せておきますが、stackoverflowで同様の事象が発生している方がおり、

>I think I have found what did I do that triggered this bug. With my external monitor (non-retina) still attached, I went to System Preferences -> Display, dragged the menu back to the MacBook internal display, restarted Xcode, then the problem went away. It seems to be related to external non-retina display chosen as the main monitor.

とあるように、メインモニターに外部モニターを選択し、新しくプロジェクトを作成しようとした時に起こりうるバグのようです。

私は以下の手順でプロジェクトを作成しなおしたところ、解決しました。

1\. モニターと接続しているケーブルを抜く
2\. Xcodeを再起動する
3\. プロジェクトを作成する

非常に単純な解決法ですが、日本語の記事が見当たらなかったため、記事を書きました。


- - -
# 備考
<!--
　補足、参照リンク等
-->

参照リンク(stackoverflow)
[Xcode error "Unable to create a save panel." when creating new Swift file](https://stackoverflow.com/questions/69950388/xcode-error-unable-to-create-a-save-panel-when-creating-new-swift-file)
Next.js + App Router (Version 13以降) をVercel にデプロイして、POSTが405になる問題

## 概要

タイトルの通りです。
ローカルで開発している時は何も問題ないのですが、
Vercelにデプロイすると、api/ へのPOSTリクエストが405(Not allowed) になります。


## 解決策

今の所私は、Next.jsのダウングレード（バージョンを落とす）で対応しました。

package.json にて、next.js を

```
next: 13.4.19,
```

にダウングレードしてください。
この後に npm install などで package-lock を更新するのを忘れずに。

たぶんですが

https://stackoverflow.com/questions/77171708/post-method-works-locally-but-not-in-production-405-method-not-allowed-nextj

ここなどをみるに、まだオープンイシューっぽいので、
あまり時間を使いたくない人はダウングレードして対応しましょう。
【Flutter】ListTileでleadingとtitleの間のスペースの幅を変える

## やりたいこと
ListTileで、以下のようにleadingにチェックボックスとアイコン、titleにテキストを配置しているが、
アイコンを変えたところ、leadingとtitleの間のスペースが広いのが目立ってしまったので、少しスペースを狭めたい。

![スペース変更前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661656/d8a9257b-95fd-3788-d0ea-e49fffba1fd9.png)


## 解決方法
ListTileのhorizontalTitleGapを調整することで、leadingとtitleの間のスペースの幅を変えることができました。
特に各WidgetにMarginなどを設定していないので、ListTileのソースを見ていたところ、以下のソースを見つけました。

```dart
  /// The horizontal gap between the titles and the leading/trailing widgets.
  ///
  /// If null, then the value of [ListTileTheme.horizontalTitleGap] is used. If
  /// that is also null, then a default value of 16 is used.
  final double? horizontalTitleGap;
  ```

  nullの場合は、[ListTileTheme.horizontalTitleGap]が使われ、それもnullの場合は、デフォルト値として16が使われるということでした。ListTileThemeというのは、おそらくMaterialAppの「theme」として指定している「ThemeData」のプロパティの一つのようでしたが、今回はこのリスト限定の幅調整として、
以下のように、horizontalTitleGapを7に変更しました。

  ```dart
  child: ListTile(
                      title: Container(
                        height: 20,
                        alignment: Alignment.topLeft,
                        child: Text(
                          model.items![i].itemName,
                          style: model.items![i].getItemColor(),
                        ),
                      ),
                      horizontalTitleGap: 7, //ここでスペースの幅を調整
                      leading: Wrap(children: [
                        Container(
                          width: 20,
                          height: 20,
                          alignment: Alignment.bottomCenter,
                          child: Checkbox(
                            value: model.items![i].isDone,
                            onChanged: (value) {
                              //動作
                            },
                          ),
                        ),
                        Container(
                          child: model.items![i].getShopIcon(),
                          alignment: Alignment.centerRight,
                          width: 30,
                          height: 20,
                        ),
                      ]),
                    ),
 ```

 無事に、スペースの幅を狭めることができました。

 ![スペース変更後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661656/ae8b7475-7def-2ecc-60bc-9437edb0b17c.png)
Controllerをテストする際のBasic認証の組み込み

## Controllerをテストする際のBasic認証の組み込み

Railsアプリケーションのテストでは、コントローラーのアクションが正常なレスポンスを返すことを確認する必要があります。しかし、時にはBasic認証が必要になることがあります。ここでは、テスト時にBasic認証をパスする方法を示します。

#### Basic認証のテストを組み込む

Railsのテストスイートでは、特定のアクションが期待どおりの振る舞いをするかを確認することが一般的です。ItemsControllerのindexアクションにリクエストを送り、その応答を検証することを目指します。ただし、このアクションにはBasic認証が必要となります。

```ruby
require 'rails_helper'

RSpec.describe ItemsController, type: :request do
  describe 'GET #index' do
    it 'indexアクションにリクエストすると正常にレスポンスが返ってくる' do
      # 環境変数からBasic認証情報を取得
      username = ENV["BASIC_AUTH_USER"] 
      password = ENV["BASIC_AUTH_PASSWORD"]
      
      # Basic認証情報を含めたリクエストを送る
      get root_path, headers: { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(username, password) }

      # レスポンスが正常に返ってくることを確認
      expect(response.status).to eq 200
    end
  end
end
```

このテストでは、環境変数からBasic認証情報を取得し、それをリクエストに含めます。そして、アクションが正常に応答するかを検証します。

#### 結論

Railsのテストスイートでは、Basic認証を含むリクエストを送ることで、アプリケーションが正常にBasic認証をパスして適切なレスポンスを返すかどうかを確認することができます。これにより、アプリケーションのセキュリティや動作を保証することができます。
Laravelの`Collection`におけるPHPDocの設定


こんにちは，ご覧いただきありがとうございます。

## はじめに

Laravelをお使いの皆さんはプログラミングする際にPHPDocを使われていますか？
私はいつも使っているのですが，`Collection`の際の使い方がいまいちわかっておりませんでした。
ググってもほしい情報はヒットしませんでした（キーワードの問題？）

今回，プログラミング中にたまたま書き方がわかったので共有します。
といってもシンプルに`array`と同様でした。笑

## `Collection`におけるPHPDoc

```php
/** @var \Illuminate\Database\Eloquent\Collection<, \App\Models\Model> */
// あるいは
/** @var \Illuminate\Database\Eloquent\Collection<int, \App\Models\Model> */
```

## 結論

ものは試しですね！
[Ubuntu] エディタ上などでカーソルが消える事への対処メモ

# はじめに

Ubuntu上でVSCode等のエディタを使っていたら、いつの間にかカーソルが見えなくなっていました。
これだと不便なので適当に調べて行った対策をメモしておきます。

# 環境

```:lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.3 LTS
Release:        22.04
Codename:       jammy
```

# 手順

1 ルートユーザになる。

```
> sudo -i
```

2 `/etc/gdm3/custom.conf`の編集


```
> nano /etc/gdm3/custom.conf
```

3 `# WaylandEnable=false,`のコメントを外して保存
4 gdm3の再起動

```
> systemctl restart gdm3
```

しばらく再起動を繰り返したので上手くいったか不安だったが問題ないよう。
距離センサ活用術



距離センサでできることがたくさんあるので、色々アイデアを出してみます。
ハッカソンになにか一つだけセンサを持っていく、となったら距離センサ１択です！


### 距離センサとは

ToFセンサと呼ばれることもあります。

- 光学式
- 音波式
などがあります。


距離センサからとある方向のどれぐらい先に物体があるか、を知ることができます。
光学式の場合は透明なガラスの距離が測れないとか、音波式だと布に弱いなどがありますので、取りたいものに応じて方式を変えるのがベストです。

![距離センサ.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/6cd541eb-bfc8-de3f-6260-5dba070fe594.png)




### 距離を測る
距離センサなので、もちろん単純に距離を測ります

- [椅子の間の距離を測る](https://protopedia.net/prototype/1960)
- [身長を測る](https://elchika.com/article/873c05f5-1c8e-4b71-8d70-2f53104f07b7/)
- [手の上下１軸ジェスチャーを測る](https://qiita.com/wicket/items/7280d6e9e399321653d5)
- [水面の高さを測る](https://elchika.com/article/395df679-e636-4dc3-a075-ee21e55119c1/)
- [ゴミの量をしる](https://protopedia.net/prototype/2478)

### 物体を検知する

物体の有無で距離が変動することを利用すると、物体の有無がわかります

- [人が机にいるかどうかを知る](https://elchika.com/article/1f239bc2-a08a-42cd-99e4-86609db58069/)
- [ドアが空いているかどうかを知る](https://elchika.com/article/6810b311-5787-480a-9a01-0a7ea2329451/)
- [宅配物がとどいているかどうかを知る](https://protopedia.net/prototype/792)
- [小物入れの蓋があいたかを知る](https://protopedia.net/prototype/3414)
- [非接触スイッチとして活用する](https://elchika.com/article/0c0aa99b-bf71-465d-b4ee-2064e70e984b/)
- [近接をしる](https://protopedia.net/prototype/4380)
- [在庫を有無を知る](https://protopedia.net/prototype/2438)

### うごきをはかる


距離センサなら1軸の動きを測ることができます
また、2個あれば動いているものの動きの方向がわかります。

- [手の上げ下げ（昇龍拳）をはかる](https://protopedia.net/prototype/1721)
- [駅の改札のように、人の出入りをカウントする](https://protopedia.net/prototype/2641)
- [手を右から左に動かしたのか、左から右に動かしたかの簡易的なモーションセンサにする]( https://protopedia.net/prototype/2852)



### 動いてない、状態が変わっていないということを測る

速度と似たようなことですが、距離が変動していない、ということは動いていないということです。

- プランクの姿勢維持を測る
- [姿勢がいい状態になっているか、を知る](https://protopedia.net/prototype/4633)
- [人が入っていない、ということを知る](https://qiita.com/mitazet/items/abeff4e2671bda763c2f)


### 速度を測る
距離を微分したら速度なので、簡易的には動きの速度が測れます（※要フレームレート）
また、距離が固定であれば通過から速度を知ることもできます


- ミニ四駆の速度を測る
- [100m走のタイムを測る](https://protopedia.net/prototype/2356)



### 距離の変動を見ることができれば、いろんなもののカウントもできます

- 縄跳びの回数をカウントする
- [腕立て伏せの回数をカウントする](https://protopedia.net/prototype/3517)
- [楽器にする](https://protopedia.net/prototype/882)



### 2Dスキャンをする
回転させればレーダーを作ることもできます

- [レーダー](https://elchika.com/article/a6ad11d0-3b9b-4ae3-bd03-9d6b1012d5b1/)


### ものの有無から他のことを知る

- [靴の有無で在宅かどうかを知る](https://protopedia.net/prototype/3532)
- [洗濯機の蓋から洗濯物が干されてないことを知る](https://elchika.com/article/db9fc797-d99e-4467-bac9-8d62024a1ea7/)

---


距離センサの活用を見てみましたが結構出てきますね。
なにかセンシングしたいなと思ったときは、そのときに
- 動く部分はどこかにあるか
- 動かない部分はないか
を探すとうまく距離センサでとれる方法が見つかるかもしれません！
Gitub actionsでGithub packageをnpm installする

## 前提
Install 対象のGithub packageも、Installを行うプロジェクトもどちらも同じアカウント（スコープ）内に存在する場合が対象です。

PATを散りばめたくなかったので、`GITHUB_TOKEN`利用に限定した設定とGithub workflow記述となります。


## Github package

Github package側で、Installを許可するリポジトリを指定します。

Package ランディングページ
↓
`Package settings`
↓
`Manage Actions access`
↓
リポジトリを選択し、`read`アクセスを与える。


## Github action workflow

チェックアウトした`.npmrc`に、`${{ secrets.GITHUB_TOKEN }}`を追記します。

```yaml:workflow.yaml
on: push

jobs:
  install-package:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      // Add the token value into .npmrc
      - run: echo -e "\n//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> ./.npmrc
      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18.x
      - run: npm i
```

`.npmrc`は以下のようになります。

```text:.npmrc
# GITHUB_TOKEN:Action時に自動で付与される値
# MY_ACCOUNT:アカウント名
//npm.pkg.github.com/:_authToken=GITHUB_TOKEN
@MY_ACCOUNT:registry=https://npm.pkg.github.com
```

## 最後に

上記の`Github package`と`Github actions`への設定追加で、**同アカウント内**というケースで、Package installが可能となります。

これが、異なるアカウント間の場合はPATが必要になってきます。

## 参考

[Stack overflowに質問](https://stackoverflow.com/questions/77471777/node-project-installing-a-github-package-in-a-github-action-workflow/77471836?noredirect=1#comment136578987_77471836)
【データベース勉強中】データベースの種類


# データベースとは
データベースは「収集した膨大なデータが格納されている、データの集まり」のこと。

データベースには主に3つの種類があります。

## 階層型
階層型は、**データを階層的な構造（木構造）で保存するデータベース**で、親に対して複数の子を持つ（子は1つの親に所属する）構造になっていて、PCのフォルダの構造や会社の組織図など一対多のデータを効率よく管理することができます。

![グループ 703.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587166/451b8443-3e61-c778-72a8-9bce442425af.png)

階層型データベースは、データにアクセスするためのルートが限定されるため、データへのアクセス速度が速くなるメリットがある一方で、複数の親が必要なデータの場合は重複登録が必要で、同じデータなのに複数の親で登録されているというような不自然なデータになってしまいます。
また、データの追加や削除などの際に、ルートを再登録する必要があり、データを管理するための柔軟性にも欠けています。

## ネットワーク型
ネットワーク型は階層型の柔軟性の欠如を補うために登場したデータベースで、複数の親ノードを持つことので多対多の関連性を扱うことができるようになり、複雑なデータの相互関係をより適切に表現することが可能になりました。

![グループ 705.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587166/9fac4048-3aba-f273-9348-5d170293d9b9.png)

階層型のデメリットだった複雑な関係性が実現（重複登録が不要になった）できデータを効率的に表現できるようになった一方で、データの依存関係が複雑になるため、データの管理が困難になりやすくなりました。

## リレーショナル型
リレーショナル(関係)型は、データをレコードという行とフィールドという列で構成され、テーブルと呼ばれる表構造のデータベースです。

テーブルを互いに関連付けて、データ同士の関連性から新しい表を作成することができたり、柔軟なデータの取り扱いができることや、複雑なデータの関連性を扱えることからさまざまな場面で使用されています。

![グループ 707.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587166/b76f17ae-e3d4-da54-924b-ff20f315cfcf.png)

リレーショナル型は複数の表データから、RDBMS（リレーショナルデータベース管理システム）」という管理システムを使って、必要なデータを組み合わせて引き出すことができます。

### DBMS(データベース管理システム)とは
DBMSは、「data base management system」の略でデータベースを操作するためのシステムです。
データベースのファイル構造の定義やデータの検索、更新、共有したり、データへのアクセス権限を管理したりします。

#### Oracle Database
Oracle Databaseは、米オラクル（Oracle）社が開発・販売するDBMSで世界で最も高いシェアを誇るRDBMSです。
高いパフォーマンスと耐障害性に優れていることから、小規模から大規模まで多くのシステムに対応しています。
Oracle Databaseは導入費用が高額になりがちで比較的予算に余裕のある大企業を中心に導入されています。

#### Microsoft SQL Server
Microsoft SQL Serverは、Microsoftが開発・販売しているDBMSです。
OracleやMySQLと比較してWindows製品との親和性が非常に高く、高い性能と堅牢性で多くの企業で導入されています。

#### PostgreSQL
PostgreSQLは後述のMySQLと同じ商用目的でも無償で利用できるオープンソースデータベースです。
PostgreSQLは多機能であり、また同じオープンソースソフトウェアとの連携により、高い拡張性を持っています。また、大手企業からの商用サポートも提供されています。

昨今最も急成長しているデータベースであり、機能拡張したPostgreSQLは商用データベースにも劣らない性能を有しています。

#### MySQL
MySQLは、世界で最も利用されているオープンソースのDBMSです。
高性能かつ高い堅牢性ながら低コストで利用できるので個人から大企業まで利用されています。
オープンソースは基本的に無償のためベンダーからのサポートはないのですが、MySQLは有償でOracle社からのサポートが受けられます。


:point_up_tone3:次回はオープンソースのDBMS、「PostgreSQL」と「MySQL」の違いについて
Power Queryで期間を日付ごとに分割する

## やりたいこと

2023-01-01 7:00 ～ 2023-01-03 23:00 のように、日を跨いだ期間を日付ごとに分割したい。
つまり、次ようなテーブルを得たい。

|Start|End|
|:-:|:-:|
|2023-01-01 07:00|2023-01-02 00:00|
|2023-01-02 00:00|2023-01-03 00:00|
|2023-01-03 00:00|2023-01-03 23:00|

## コード

```
(start as nullable any, end as nullable any, optional culture as nullable text) as table =>
let
    startDt = DateTime.From(start, culture),
    endDt = DateTime.From(end, culture),
    separators = List.Generate(
        () => Date.StartOfDay(Date.AddDays(startDt, 1)),
        each startDt < _ and _ < endDt,
        each Date.AddDays(_, 1)
    ),
    starts = {startDt} & separators,
    ends = separators & {endDt},
    durations = List.Zip({starts, ends}),
    schema = type table [Start = datetime, End = datetime]
in
    if List.MatchesAll({startDt, endDt}, each _ = null) then
        #table(schema, {})
    else if List.Contains({startDt, endDt}, null) then
        error "Cannot calculate the duration as either the start or end is null."
    else if startDt > endDt then
        error "start must be before end."
    else
        #table(schema, durations)
```
Laravelでpublicに置いた.htmlにアクセスできなかった時の対処

だいぶ前にvagrantで作った環境でLaravelのpublicディレクトリにファイルを置いてアクセスしようとすると、.php や .txt なら普通にアクセスできるのだが、.htmlファイルだけ403 NotFound になった。それを解決した時のメモ。

# 環境
たぶん Vagrant Cloud からダウンロードしてきたBOX。`/etc/os-release` や `/etc/system-release` には **Amazon Linux 2** とある。
PHPのバージョンは 8.1。
Laravelのバージョンは9（9.48.0）。

# php-fpmの場所
ググった情報によると問題を解決するには php-fpm の設定を変更して再起動する必要があるらしいが、php-fpm の設定ファイルが参考にしたページに記載されている場所にない。
自分の環境では以下にあった。

```
$ sudo find /etc -path '*php-fpm*'
/etc/logrotate.d/php81-php-fpm
/etc/systemd/system/multi-user.target.wants/php81-php-fpm.service
/etc/systemd/system/php81-php-fpm.service.d
/etc/opt/remi/php81/sysconfig/php-fpm
/etc/opt/remi/php81/php-fpm.conf
/etc/opt/remi/php81/php-fpm.d
/etc/opt/remi/php81/php-fpm.d/www.conf
```

`/etc/opt/remi/php81/php-fpm.d/www.conf` を編集して `security.limit_extensions` のコメントアウトを解除し末尾に `.html` を追記した。

# php-fpmの再起動
`sudo systemctl restart php-fpm` ではダメだったので php-fpm のサービス名を探した。

```
$ sudo systemctl list-unit-files -t service | grep php-fpm
php81-php-fpm.service                         enabled
```

サービス名は `php81-php-fpm` だった。よく見たら先ほどの find の結果の中にあった。
ということで `sudo systemctl restart php81-php-fpm` で php-fpm を再起動したところ、Laravel の public にある .html ファイルにアクセスして200が返ってくるようになった。


# 参考ページ
[CentOS8 + Apache2.4.37 + php7.2(php-fpm) で HTML ファイルの中で PHP を実行する](https://qiita.com/y_ito/items/394762bcc0a694ee2277)
[systemctlで有効・無効なサービス一覧を表示する | 晴耕雨読](https://tex2e.github.io/blog/linux/systemctl-list-services)
Tableau CloudのアクティブティログのS3を設定しよう(S3側の設定編)

## 前提
1.Tableau Cloudのサイト管理者ライセンス

https://www.tableau.com/ja-jp/products/online/request-trial

2.Tableau CloudのAdvanced Managementライセンス

https://help.tableau.com/current/online/ja-jp/itm_intro.htm

3.AWS S3のご用意
### 参考ヘルプ
https://help.tableau.com/current/online/ja-jp/activity_log_setup.htm
## 手順
### 1.Amazon S3バケットの作成と権限の設定
①AWSのS3画面にアクセスし、「バケットを作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/47b3d38f-8dcd-b88e-9d5f-35c4216adb16.png)
②次の設定で Amazon S3 バケットを設定
バケット名：任意(例：tableau-cloud-activitylog)
AWS リージョン：アジアパシフィック（東京）ap-northeast-1
オブジェクト所有者：ACL 無効(推奨)
バケットのバージョニング：有効にする
デフォルトの暗号化：AWS Key Management Serviceキーを使用したサーバー側の暗号化 (SSE-KMS)
AWS KMSキー：AWS KMS キーARNを入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/71ed7296-61d1-33e1-6d34-ee579c5ea5ee.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/0e5b7b6b-08e4-8840-a7e1-7016549ca8cd.png)
③「KMSキーを作成する」をクリック
キーのタイプ：対称
キーの使用：暗号化および復号化
「次へ」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/7a55ea03-79f0-bd5c-725a-1b143e7ad491.png)
④エイリアス名を入力し、「次へ」をクリック
エイリアス名：TableauCloud-AM-Key
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/48769786-a419-7582-dd52-3694a28e9868.png)
⑤キー管理者ページは、何もせず「次へ」をクリック
⑥キーの使用アクセス許可を定義ページは、何もせず「次へ」をクリック
⑦確認ページで、キーポリシーを追加し、「完了」をクリック
既存のポリシーのStatement[]間に以下を追加
```
{
"Sid": "AllowTableauS3ReplicationSourceRoleToUseTheKey",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::061095916136:role/prod-replication-rule-role"
},
"Action": [
"kms:GenerateDataKey",
"kms:Encrypt"
],
"Resource": "*"
}
```
⑧作成されたキーからARN値をコピーし、バケット作成ページのAWS KMSキーARN欄に入力し、「バケットを作成」をクリック
![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/4330b507-b2d6-b0e8-0dbe-7ebef6c1d585.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/9df9b288-dedb-d8f7-c517-1b660e299bae.png)
⑨バケット一覧から作成されたバケット(例：tableau-cloud-activitylog)をクリック
![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/f72552b2-f72c-7283-cc2b-0334fbec4098.png)
⑩「アクセス許可」タブ→バケットポリシー横の「編集」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/9ae4c91e-82d1-485e-53cc-fe812c22fe31.png)
11.バケット ポリシーの [ステートメント リスト] に以下を追加。[S3-BUCKET-NAME] をバケットの名前に置き換える。
```
{
"Sid": "TableauS3ReplicationRoleAccess",
"Effect": "Allow",
"Principal": {
"AWS":
"arn:aws:iam::061095916136:role/prod-replication-rule-role"
},
"Action": [
"s3:ReplicateObject",
"s3:ReplicateDelete"
],
"Resource": [
"arn:aws:s3:::S3-BUCKET-NAME",
"arn:aws:s3:::S3-BUCKET-NAME/*"
]
}
```
12.「変更の保存」をクリック
ChatGPTで決算短信分析をしよう (2/n) ~My GPTsの作成

# 前回のおさらい
https://qiita.com/kaizinZ/items/3bc0b4e771690f57d923

ChatGPTのいくつかの機能を利用しましたが，決算短信を読み込ませ分析させることができませんでした．
原因は大きく2つありました．
- 決算短信の特徴的なフォーマット
- 文字化け

これらに対応できそうな方法でパッと思いつくのは，
- 決算短信をpdfではなく，画像として読み込む
- pdfを自力で構造データに落とし込む
- pdf以外のデータソースを見つける

この3点です．しかしながら今回の記事ではこれらの対処法について少しも実践していません．なぜならば新機能によってその問題が解決できそうだったからです．

# 新機能: My GPTs
My GPTsは特定の目的に向けて自身でGPTのスタイルや知識をカスタマイズすることができます．

今までは長文のプロンプトをいちいち投げていましたが，これからは決算短信を投げるだけで分析してその結果を返すことができそうです．

# 決算短信分析をさせるにあたって

まず，最終成果物であるGPTのリンクを貼っておきます．

https://chat.openai.com/g/g-SbLGepHy3-jue-suan-fen-xi-gpt

GPT作成時に，注意したことを以下にまとめます．

### ターゲットは誰か？
今回，株式投資の初心者から中級者向けに分析結果を伝えることが主題です．

### pdfの読み込みについて
前回，pdfをアップロードしても最初の2ページしか読み込まれない，文字化けする，表を上手に読み取れないなどの問題が発生したため，OCR (光学的文字認識)で分析してくださいとお願いしてみました．

### 事実と考察の区別
一般的に重要であることですので，GPTにもこの区別を行うように指示しました.

### 何に焦点を当てるか
決算短信には定量的な情報と定性的な情報が存在します．

業績や財務などの定量的な情報，後発事象や注意事項など定性的な情報それぞれに対し焦点を当て，異なるプロンプトを使用することをユーザーに推奨します．

### ハルシネーション対策
嘘の情報を捏造してしまうことがあります．

そこで，不明な点があった場合の動作として，不明であると述べるか，ウェブで調べるかをGPTが選択します．
また，その途中で情報に矛盾がある可能性があればもう一度調べ直して正確な情報を提示するように指示しています．

### 回答の記述量
文字数が多すぎると，TL;DR　(Too Long; Didn't Read)と言われるように読みたくありません．

一度に回答する量を減らしたいが情報量を削るわけにもいかないので，出力する内容を絞り，追加で聞くための選択肢を提供することにしました．

```text
回答の最後に以下の文章を出力してください．
追加で知りたいことは何ですか？
1. 企業の基本情報，全体の業績とセグメントごとの業績
2. 株価に影響を与える事象の分類
3. その他，後発事象や備考，注意事項，定性的な情報など
4. GPTの考察
```
とGPT Builderに伝えるとよしなにしてくれます．

# PDFを投げてみる
ぜひ使ってみて欲しいのですが，決算短信をダウンロードして，というのが面倒な方向けに少しだけ触りを紹介します．

例として伊藤忠商事の決算短信を投げてみました．

![スクリーンショット 2023-11-13 15.49.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131671/ee987d5c-278c-b184-bac0-035db3108d7b.png)

まずは基本的な情報を返します．これに関してはそのまま決算短信読んでも大差ないですね．

My Consideration以下，GPTによる評価が行われます．

返答の最後には続けて提供可能な情報が提示されます．
2を選んでみると，重要な変更についての記述を得ることができました．
同様に，最後には続けて提供な情報が提示されます．

![スクリーンショット 2023-11-13 15.56.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131671/bfc13f24-de67-a1b7-0718-e0a93dfbb1e4.png)

このように，あの難しそうなpdfを読むよりもいくらか分かりやすく，GPTなりの考察が得られるので，株式初心者〜中級者には役立つのではないでしょうか．

# まとめ
前回のChatGPTを利用した決算短信分析には次のいずれか，もしくは全ての対処法が必要だと結論づけられました．
- 決算短信をpdfではなく，画像として読み込む
- pdfを自力で構造データに落とし込む
- pdf以外のデータソースを見つける

この記事では，そんなところに追加された新機能であるMy GPTsを活用することを考えました．
すると，pdfは全ページ読み込まれているし，文字化けも起こしていないし，というハッピーな結果が得られました．

(おそらくOCRで読み込むように指示したことが効いたのだと思います．しかし，GPTsの追加前にOCRで読み込むように指示したことがあって，その時はOCRに必要な環境がないと言われました．)

初心者向けの内容として申し分なし，だと思うのですが，もう少しいじって改良してみたいと思います．特に，知識としてファイルを工夫してみたいです．
マインドマップで頭の中を掃除

## 背景

自分の考えをまとめて、人に伝える機会が多くなりました

- 必然的にインプットする情報量も増加
- 定期的にSNSやネット記事から情報を摂取するように

## 問題

反面、アウトプットの質とスピードは低下しているような感覚に襲われました

- 基本的にスライドでまとめて伝えることが多い
- その際、情報の取捨選択、整理、伝え方などを考慮
- 扱う情報量が増えることで上記負担も増え、脳疲労的な感覚に繋がっている？
- 「[情報過多シンドローム](https://kenko.sawai.co.jp/healthcare/202001.html#:~:text=%E3%80%8C%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%84%E3%81%9F%E3%81%AF%E3%81%9A%E3%81%AE,%E3%80%8C%E6%83%85%E5%A0%B1%E9%81%8E%E5%A4%9A%E3%82%B7%E3%83%B3%E3%83%89%E3%83%AD%E3%83%BC%E3%83%A0%E3%80%8D%E3%81%A7%E3%81%99%E3%80%82
)」という言葉もあるらしい

## 解決策

いくつか試した中で、個人的にはマインドマップがしっくり来たので紹介したいと思います

## マインドマップ

https://www.mindmap-school.jp/mindmap/

## ツール

VSCodeの拡張機能である「MarkMap」を使ってみました

https://marketplace.visualstudio.com/items?itemName=gera2ld.markmap-vscode

- バージョン管理と相性が良いこと
- 普段使いのツールで完結すること

などがポイントです

## 使い方

以下のように、ひたすら思いついたことを記載していきます
階層を意識して、# の数を調整します

```markdown
<!-- markdownlint-disable -->
# マインドマップ
## マインドマップとは
### 放射思考を可視化するツール
## 特徴
### 簡単かつスピーディに作成できる
#### 思いつくままに記入するだけ
### 客観的に自分の思考を捉えられる
#### 散らかっている考えやアイデアを整理できる
#### 複数の視点から考えられる
### そのままプレゼンテーションにも使える
```

これを以下のように可視化できます
マウス操作で折りたたむことも可能です

![Nov-13-2023 15-26-08.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1666407/149cd153-2b8a-26d3-947c-8517c414ac2b.gif)

逆に折り畳んだ状態から開いていけば、簡易的なプレゼンにも使えそうです

## 雑感

- 「思考を整理する」という用途においては、非常に便利だと感じました
  - とりあえず書き出して眺める、というだけでも有用と感じます
  - 第三者の視点から眺めることで、自分に欠けている視点にも気づきやすいです
- 「情報を伝える」という用途においては、メリット/デメリット共にあるのでケースバイケースという感じです
  - スピードが重視される場面では重宝しそうです