OmniAICreator/Qiita-1.07M huggingface dataset:
JUnitって案外難しいよね、ってはなし

# はじめに

JUnitテストで苦戦したときの話です。

# JUnitテストの構造

まずは、JUnitとはどんなものだったかを整理しましょう。

## テストの構成

JUnitに限らず、各言語のXUnitテストフレームワークは、ざっくりと次のような構造になっています。

```plantuml
rectangle UnitTestSuite {
rectangle UnitTestClass {
  rectangle BeforeMethod {
  }

  rectangle UnitTestMethod {
  }

  rectangle AfterMethod {
  }
}
}
```

テストは、テストスイート、テストクラス、テストメソッドという階層構造を取ります。

テストスイートは、一連のテストを実行する最大の実行単位です。
JUnitの場合はJUnitのクラスが格納されたパッケージがテストスイートに相当します。

テストクラスは、関連性の高いテストをまとめる単位です。
JUnitの場合はテスト対象のクラス名`XXX`に`Test`をつけた`XXXTest`というクラスがテストクラスに相当します。

テストメソッドは、テストクラス内でテストを実行する最小単位です。
テストメソッドに付随して事前準備メソッド(Before)と事後処理メソッド（After）が定義されることがあります。
事前準備メソッドと事後処理メソッドは、テストクラス内のすべてのテストで共通な処理をまとめるメソッドです。

**参考サイト**

https://tech.excite.co.jp/entry/2021/05/31/151713

## テストの実行

JUnitのテスト実行は次のような流れになります。

### テストスイートの実行

JUnitは、まずテストスイート、クラス、メソッドの順にテスト対象を特定し、その実行順序を決定します。

1. 実行すべきテストクラスを一覧化し、実行順序を決定する
1. 実行すべきテストメソッドをを一覧化、実行順序を決定する

テストの実行順序はアノテーションで制御することができます。

> 定義@TestMethodOrder(MethodOrderer.Random.class)を使用して、ランダムな順序を定義することもできます。この場合、メソッドの実行順序はランダムに選ばれます。テスト間に依存性がないという現在の状態を維持し、今後のステージでテスト間に余計な関係が構築されないようにしたい場合、この機能が意味を持つことになります。
> 
> https://blogs.oracle.com/otnjp/post/junit-5-6-makes-testing-easy-with-new-features-ja

### テストメソッドの実行

次に、テストメソッドを実行します。
テストメソッドの実行は次の順番に行われます

1. 事前準備メソッドの実行
    1. テストデータの作成、外部システムへの接続などテストにあたり事前にすべき処理を実行します。
1. テストメソッドの実行
    1. テストを実行します。テスト対象のメソッドを呼び出し、規格値(expect)と実測値(actual)を比較し、差異がないことを確認（assert）します。
1. 事後処理メソッドの実行
    1. テスト対象メソッドが生成したデータの削除、外部システムとの接続断などテスト後に事後的にすべき処理を実行します。

# 何が起きたか

次のような2つのテストクラスをつくりテストを実行しました。

1. テストクラス1
    1. テストメソッド1
        1. 事前準備メソッドでモックを作成
        1. テストメソッドの実行
        1. 事後処理メソッドは　ナシ
1. テストクラス2
    1. テストメソッド2
        1. 事前準備メソッドは　ナシ
        1. テストメソッドの実行
        1. 事後処理メソッドは　ナシ

このとき、JUnitは生成したモックを自動的に削除しません。
テストクラス1で作成したモックは削除されることなく次のテストクラスの実行時にもメモリ空間に残ります。

このため、次のようなことが起こりました。

1. テストクラス1 ー＞　テストクラス2の順にテストを実行したとき
    1. テストクラス1のモックがテストクラス2の実行時に影響し、テストに失敗。
1. テストクラス2 ー＞　テストクラス1の順にテストを実行したとき
    1. テストに成功

テストの実行順序は、JUnitのコード上で指定しない場合、実行環境に依存します。

たとえば、

* Maven ＝＞ ABC順
* Eclipse ＝＞ ランダム

というように。

テストの実行のたびに結果が変わるフレイキーテストとなり、その原因の解明にかなり苦戦しました。

https://blog.cybozu.io/entry/2020/12/23/100000

# まとめ

JUnitのテスト実行順序に起因するじどうテスト失敗事例について紹介しました。
rex0220 ちょっと便利なプラグイン  グラフ関連

ちょっと便利なプラグインで、グラフをちょっと便利にする機能をご紹介。
kintone の少し使いにくいところをちょっとだけ便利にするプラグインです。

# ちょっと便利なプラグイン　グラフ関連機能

フィルタに「グラフ」を入力するとグラフ関連機能が表示されます。
対象機能をチェックして、プラグインの「保存」で有効になります。

![2022-11-19_11h28_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/81e1eecd-45f5-020e-6658-11f1569610fd.png)


# グラフの項目選択

kintone のグラフには、集計項目ごとに、表示する・しないを切り替える機能がありますが、
集計項目数が多いと一部のみ表示するのが面倒です。
「F43 グラフの項目選択」を有効にすると、集計項目を一括で非表示に切り替えられますので、
全部非表示にした後に必要な項目のみ選択することができます。
下記のような操作を想定しています。

- グラフの「選択」のチェックを外すと、全項目を非表示
- グラフの「選択」のチェックすると、全項目を表示

![2022-11-19_06h05_26.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/699f5cf7-e1a6-0cc3-eab2-8ecb90c21f29.gif)


# グラフの印刷・ダウンロード

「F44 グラフの印刷」
「F45 ダウンロード」

グラフの印刷・ダウンロードボタンが、表示されますので、クリックすると印刷・ダウンロードされます。

![2022-11-19_11h34_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/65d10453-9beb-d490-3f7f-93fa07e7eb57.png)

- グラフの印刷プレビュー

![2022-11-19_11h36_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3dc421ae-18b0-a638-5fee-b7746157e776.png)

- グラフのダウンロード

png 形式で、グラフをダウンロードします。

![グラフ１-20221119-113743.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/310abfd6-1fbf-683f-b0b3-235f91f40897.png)
【Twilio】トライアルアカウントの制限


**Twilio**でアカウント作成すると**トライアルアカウント**として作成される
**トライアルアカウント**の制限について調べたことをまとめる

# トライアルアカウントの制限

## 主な制限
* 購入できる電話番号は1つまで
* SMSの送信と架電は、承認された電話番号のみ
* 架電時に流れるアナウンスは、特定のもの（トライアルアカウントを利用している旨）
* サブアカウントは1つまで

## その他制限
詳細な制限等については以下で確認できる

[トライアルアカウント制限事項 – Twilio Support](https://support.twilio.com/hc/en-us/articles/360046044073-%E3%83%88%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%AB%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E5%88%B6%E9%99%90%E4%BA%8B%E9%A0%85)

## 調査した感想
**トライアルアカウント**でもTwilioのほとんどの機能を検証・ハンズオンできることが分かった
不特定の相手に架電する場合、プロジェクトのアップグレードが必要なので注意したい

# 参考
https://ahoy.twilio.com/go-getting-started-with-twilio-part1-japan-1
【C#】型の種類と意味

# 型の種類(一部)

__void__
何もないことを意味するデータ型
まとめ記事
https://qiita.com/hanatan079/items/747b2556d5696629669c

__bool__
真偽値を入れられる(true、false)

__int__
整数型で、メソッドの戻り値のデータ型を示す。
例) 

__float__
有効桁数の大きくない小数を入れる
fをつける（0.0f）

__double__
有効桁数の大きい小数を入れる

【クラス】
Transform
ゲームオブジェクトの位置、回転、大きさを表す



【型について】https://qiita.com/hanatan079/items/fe1de7bd542719a62570
保存時のトーストでNameでなくてIdが表示される

[UI関係のトラブルに戻る](https://qiita.com/Keiji_otsubo/items/cc344223cfa02db6bed7)


+ [レコード作成後のメッセージはどのように制御されていますか](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000JepDMSAZ)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/70390a79-1ae9-45d5-dbec-5f404a2c94f5.png)

:::note
Adding the Record Name field back our page layout solved the issue.  We had removed it as invaluable to the user but instead put it at the bottom to clear this up.


レコード名フィールドをページ レイアウトに追加することで、問題は解決しました。ユーザーにとってかけがえのないものとして削除しましたが、代わりにこれをクリアするために一番下に置きました。

https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000A8ymUSAR
:::

[Record Name Not Appearing in Record Creation Success Message](https://help.salesforce.com/s/articleView?id=000389059&type=1)

解決策
To see the record name in record creation messages, add the record name field to the layout. 

# バグがあるみたい

+ [Spring '23 bug? Case created toast message](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000NEsM6)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/f1cbcdaf-3daf-6482-6deb-dba9e5998a2a.png)

# This page has an error. You might just need to refresh it. Action failed: c:validation2$controller$toaster [Cannot read properties of undefined (reading 'setParams')] Failing descriptor: {c:validation2$controller$toaster}.

+ [callback Error in aura Toast message](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007AhecP)
AWS S3のバケット名の命名規約のお話

AWS S3を色々いじっていて気がついたこと。バケット名の命名規約が他のAWSサービスとちょっと異なることに気が付きました。
バケットとはAmazon S3 に保存されるオブジェクトのコンテナのことで、複数作成可能。

バケット名命名規約が、ここにあります。
[バケットの命名規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)
> バケット名には、**小文字**、数字、ドット (.)、ハイフン (-) のみを使用できます。

えー、大文字は使えないんだ。何でだろ？

> バケット名は、パーティション内のすべての AWS リージョンのすべての AWS アカウントで一意である必要があります。パーティションは、リージョンのグループです。awsAWS には現在、(標準リージョン)、aws-cn(中国リージョン)、 aws-us-gov(AWS GovCloud (US)) の 3 つのパーティションがあります。

一番、不自然に感じたのはここ。バケット名がパーティション内のリージョン内の全てのユーザで一意でなければならない。すなわち、自分が使いたいと思っていたバケット名が既に違うユーザで使われていたらダメ。

他のAWSサービスの命名規約は自分のユーザ内で一意であればいいのに、なんでここだけ？
最初はスパゲティコードでもいいからまず書く

スパゲッティは、たらこスパゲッティが好きです。最近は、大盛りで食べれません（笑）

スパゲティコードとは、処理が整理されていない複雑に入り混じったコードのことです。
業務的に言うと、後から修正しにくい、新規機能を追加しにくいコードのことです。

作成する時も、機能を追加する時も、後から改修しやすい・自分以外の人が見てもわかりやすい（属人化しない）コードを書いたほうが親切です。
業務時間を減らすことにもつながるので、コスト面を考えても配慮したいポイントです。

最近は、どのプログラミング言語もフレームワークが増えているので、気にせずともMVCモデルなどオブジェクト指向を取り入れてコードを書くことが多いと思います。
（現場にも寄りますが・・・笑）

## 最初はスパゲティコードでもいいからまず書く
**コードは綺麗に書くことが大事です！**
と言っていますが、実際にコードを書く時は **「スパゲティコードでもいいから書く！」** ことをオススメしています。
コーディングは文章を書くのと同じで、書き始めると自然と筆が進むものです。
だから、 **考えるよりもまずは書きましょう！**

## 書いてから綺麗に整えれば良い

私の経験談ですが、若手のうちは「やりたいことはわかっている」だけども、「思ったとおりに書けない」ということが多かったです。
なので、一旦書いてみて、その中で処理をシンプルにできる部分を見つけるようにしました。
最初はめちゃくちゃなソースコードでしたが、やっていく中で省ける部分や関数にまとめられるところが分かるようになってきました。

昨日書いたソースを次の日に見ると、落ち着いて見れるので一人ソースコードレビューのような感覚で修正して行けます。
今思うと、この何気ない作業が、チーム内のコードレビューや綺麗なコードを書くための糧になっています。

## より良いコードを書くためには、上手い人のコードを見て真似するのも大事です

さらに良いコードを書きたいと思っている、そこのあなた！
上手い人が「何を考えて」コードを書いているかを真似しましょう。

次の本、読むのオススメです。
一読するだけでも、ためになること間違いなしですよ。

https://amzn.asia/d/4GLAXCe
viteに余分な設定をしたせいでFailed to resolve entry for package "firebase"と怒られたメモ

## 概要
愚かな指定ミスで以下のエラーを引き起こしたのでメモ。

```
vite v3.2.4 building for production...
✓ 427 modules transformed.
[commonjs--resolver] Failed to resolve entry for package "firebase". The package may have incorrect main/module/exports specified in its package.json: Missing "." export in "firebase" package
error during build:
Error: Failed to resolve entry for package "firebase". The package may have incorrect main/module/exports specified in its package.json: Missing "." export in "firebase" package
````

## 原因
`manualChunks`の指定ミス。
以下のように修正したら解消された。

```diff:vite.config.ts

export default defineConfig({
  build: {
    sourcemap: process.env.NODE_ENV !== 'production',
    rollupOptions: {
      output: {
        manualChunks: {
-          analytics: ['firebase', 'web-vitals'],
+          analytics: ['firebase/app', 'firebase/analytics', 'web-vitals'],
        },
      },
    },
  },
});
```

以下のようにimportしているのに、manualChunksでは`firebase`と指定していたのがまずかった模様。

```ts
import { getAnalytics, logEvent } from 'firebase/analytics';
import { initializeApp } from 'firebase/app';
import config from './config';
import type { ReportCallback } from 'web-vitals';

const firebaseApp = initializeApp(config);

const analytics = getAnalytics(firebaseApp);
```
Salesforce認定Platformアプリケーションビルダー試験の公式サンプル問題解説してみた-09

こんにちは

Salesforce認定Platformアプリケーションビルダー試験の公式練習問題があるのはご存じでしょうか。
Trailheadにフラッシュカードとして何度も解ける練習問題がございます。

https://trailhead.salesforce.com/ja/content/learn/modules/platform-app-builder-pt1/platform-app-builder-security-ui


今回は

Platform アプリケーションビルダー試験に向けた学習 
認定 Platform アプリケーションビルダー資格の受験準備: Data Modeling and App Deployment (データモデリングとアプリケーションリリース) 
データのモデリングと管理の学習

にある問題1問目をご紹介します

なお今回の内容は動画でも公開しております

https://www.youtube.com/watch?v=bBh17_EMJzQ

<iframe width="560" height="315" src="https://www.youtube.com/embed/bBh17_EMJzQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

![０１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/c243937c-fef0-22f3-74eb-7be9dca36cfb.png)

正解はBです


外部ID項目で設定できる項目型は限られていまs
テキスト、数値、メール以外では外部IDとしての設定はできません

詳細はこちらのヘルプをご確認ください


カスタム項目のデータ型の変更に関するメモ
https://help.salesforce.com/s/articleView?id=sf.notes_on_changing_custom_field_types.htm&type=5

＞外部 ID として設定されているカスタム項目のデータ型を変更する場合、テキスト、数値、メール以外のデータ型を選択すると、項目は外部 ID として機能しなくなります。
バッチファイル(.bat)をタスクスケジューラで予約する方法～ログ履歴の有効化まで紹介～

# バッチファイルとは？

バッチファイル(.bat)とはWindowsの環境で動作するコマンド列を記述したテキストファイルです。
バッチファイルに実行したいコマンドを複数登録しておくことで、いちいちプログラマがWindows PCに指示を出さなくても勝手に処理をしてくれます。

今回は『タスクスケジューラ』で実行日時を指定しておくと、決まった時間にバッチが実行されるという操作方法をやってみましょう。

一般的な用途としては、データベースのバックアップをバッチ処理として登録したりなど様々です。

『タスクスケジューラ』に登録しておけば、メリット その１『人間によるうっかり忘れが無くなること』、それと人間って意外と操作に慣れると些細なミスに気付かないことが多い...なのでメリット その２『実行コマンドの記述漏れを防ぐことが出来ること』が挙げられます。

では早速やっておきましょう！


# タスクスケジューラでバッチファイルを自動化

【環境】Windows10、Windows11


■スタートメニューから「タスクスケジューラ」を選択し、画面を表示しましょう。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/c620b07f-1148-2ce5-1e9c-632edeb7fc05.png)

■画面の右端にある「タスクの作成」リンクをクリックします。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/12d64467-3850-d61e-f500-1993334d6544.png)

■[タスクの作成画面]が表示されるので、まずは[全般タブ]で以下の項目を入力します。
①名前：（例）サンプルバックアップ
②ラジオボタン「ユーザーのログオンしているかどうかに関わらず実行する」を選択する。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/ab726df0-15a8-609a-bec2-387fe3583c20.png)

■[トリガー]タブを選択して、「新規」ボタンをクリックします。この画面で指定日時を登録します（例：お昼の12時の場合は、「12:00:00」と入力）
入力完了後、「OK」ボタンをクリックします。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/c70b5fa9-dbf4-d778-1fa1-bbd3d6548cb2.png)

[トリガー]タブに登録した指定日時が表示されます。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/bd27bba3-ab0a-1966-32d1-3956a5d2c238.png)


■[操作]タブを選択して、「新規」ボタンをクリックします。[プログラム/スクリプト]欄で実行バッチファイルを選択します。
その後、「OK」ボタンを選択します。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/ceaddf0d-edc5-81a6-4b4d-5fe04a8da71f.png)

[操作]タブに実行バッチのパスが表示されます。

■[タスクの作成画面]で「OK」ボタンをクリックすると、パスワード入力画面が表示されますので、PC起動時のパスワードを入力して「OK」ボタンをクリックします。

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/fc9c5483-77ce-c724-6554-567d5b17dae7.png)

■左側の「タスクスケジューラ」を選択すると、一覧に先ほど登録したバッチが表示されていることを確認します。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/af4366c1-b0dd-e155-a192-392e90ec4b98.png)

■以上でバッチの登録は完了ですが、デフォルトではログ履歴は無効状態になっています。なので、有効化するために「イベントビューア」の設定が必要になります。
さっそく、「イベントビューア」を起動します。

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/60878ab7-6892-3db3-3c1c-7a5379e42698.png)

■「イベントビューア」の[アプリケーションとサービスログ]→[Windows]→[Task Scheduler]→[Optional]の上で右クリックして、「ログの有効化」を選択します。

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/1c633cde-8583-bc4a-2bd5-6be3fd55d220.png)


![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/1cc3f6eb-dbbd-0391-3a75-3671a0e2fa71.png)






以上で、ログの有効化まで設定することが出来ました。
Active Adminで新規データ作成後に、処理を行わせる方法。

## 背景
Active Adminを利用していて、「特定のデータを作った時だけ、通知を送りたい」ニーズが発生しました。
モデル層に、:after_create_commitを置くというやり方もありますが、以下の前提があり、調べてみることにしました。
- 全てのデータ作成時に、通知するのではなくあくまで、ActiveAdmin上からデータを作成した時のみ行いたい。

## 方法
以下の方法で達成できます。
ActiveAdminで自動的に設定されているcreateメソッドをオーバーライドし、その後の後続処理を追記するやり方です。
DBに別フローでデータを作成してみましたが、ちゃんとその時は、以下のコードは動かないことを確認しているので、目的を果たすことができました。
```
ActiveAdmin.register #{モデル名} do
  controller do
    def create
      super do |format|
        # ここに処理を入れるだけでOK！
      end
    end
  end
end
```
毎日の検温の自動化

# 概要

毎朝検温をしてMicrosoft Fromsでその結果を送信するという、誰も真面目にやってないであろう"作業"がある
気が向いたからこれを自動化した
毎朝7:00に、Microsoft Fromsにログインし選択肢を選んで送信ボタンを押すというプログラムを実行する
実行環境はWin10
なお、本記事は基本的に実装の詳細を解説するのではなく、回答の自動化をする一つの手段を紹介するという意図で作ってある
詳細なソフトの使い方等は別途ググることを想定している

# 使ったツール等

### PowerAutomateDesktop
以下、頭文字を取ってPADと呼称する
Win11では標準搭載、Win10では[公式](https://powerautomate.microsoft.com/ja-jp/)からダウンロード・インストールして使用
無料版ではプログラムの定時実行をする機能がないから以下のPadFlowRunとタスクスケジューラを使用して定時実行を実装する

### PadFlowRun
以下、頭文字を取ってPFRと呼称する
前述のPADをコマンドラインで実行するためのマクロのようなもの
ダウンロード・解説はこの[リンク](http://yoshio-akz.blogspot.com/2021/03/stream-deck-power-automate-desktop.html)から

### タスクスケジューラ
プログラムを定時実行するためのWindows標準搭載のソフト
時間、間隔、実行するプログラムのパスを指定し、指定した時間に実行する
今回の場合、上記のPFRで生成したコマンドをバッチファイルとして保存し、定時実行する


# 実装の流れ

以下、実装の流れを軽く説明する
### 1. PADで回答を自動化する
- 詳細は別途ググった方が早いと思うから省くが、以下のようなフローを作成して回答を自動化した
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734184/2d61216c-393b-1a1f-065e-957d0d0f1618.png)

### 2. PFRでフローの実行をコマンドラインで行えるようにする
PFRの使い方に関しては[ここ](http://yoshio-akz.blogspot.com/2021/03/stream-deck-power-automate-desktop.html)を参考にどうぞ
- PFRで生成したコマンドをテキストファイルに保存し、拡張子を`.bat`あるいは`.cmd`に変更してバッチファイルを作成
    - ここで一旦バッチファイルを実行してPADで作成したフローが実行されることを確認
    - この際、Windowsのユーザー名に日本語やスペースが含まれている場合、対策をしないと正常に機能しない可能性がある([参考](https://qiita.com/wrmannjirou/items/967d0c631e9ed412c2e2))


### 3. タイムスケジューラでバッチファイルを定時実行
Windows標準搭載のタスクスケジューラで2. にて作成したバッチファイルを定時実行する
- 基本タスクを作成し、開始時刻を7:00に、間隔を1日に設定(どちらも値は任意)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734184/57880292-814f-aa05-cec9-e257e0a1dd04.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734184/39049790-49c3-dd83-bf39-0a88e0c19264.png)
- 「操作」は「プログラムの開始」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734184/6f354c89-0334-da39-5e5b-386d9657b0fe.png)
- 「プログラム/スクリプト」に、2. で作ったバッチファイルのパスを入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734184/50014f0d-bae6-56a7-178b-3eeca40fdd13.png)

- 確認画面で特に変更がなければ「完了」ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734184/72e9c32a-1c1a-3184-a537-7f2c373d8449.png)
- 追加で、左側の「タスク スケジューラ ライブラリー」から作成したタスクのプロパティを開き、以下のように設定を変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734184/e7e80c26-4835-4477-5f8b-4627ca287f71.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734184/5e05374b-ddec-2f42-fd7c-d283825f3fc5.png)

# 応用

今回PADで作成したフローではMicrosoft Fromsにログインするときに変数を使ってあらかじめメアドとパスワードを格納してあるが、この変数の代わりに[二次元配列](https://blog-tips.sekenkodqx.jp/2021/03/15/power-automate-desktop-datatable/)とループ処理を組み合わせれば複数のアカウントにログインしてそれぞれのアカウントからフォームに回答することも可能
【Twilio】概要・実績・ユースケース

# はじめに

**Twilio**について調べてみたことをまとめる

# Twilio[トゥイリオ]について

## 概要
様々な**コミュニケーションチャネル**を、**クラウド**を介して**プログラム可能**な状態で利用できるように整備した**顧客エンゲージメント**向けの基盤・サービス

## 実績
**1000万人超**の開発者コミュニティー
**25万超**のアカウントがアクティブに利用
**180ヶ国以上**で利用

## ユースケース
### 認証
* 新規アカウント作成
* 本人確認
### プロモーション
* 商品紹介
* ニュースレター
### 通知
* 予約／注文確認
* 配送状況通知
* アカウント情報変更確認
### 会話
* お客様サポート
* ビデオ商談
* 健康状況の確認

# 調べてみて感じたこと
Twilioはユースケースが多く、どんなアプリに対しても取り入れることができそう
また実績が多く、信頼性も高く感じた
ハンズオンも多く用意されていて、導入コストも低そう

# 参考
https://www.twilio.com/ja/

https://ahoy.twilio.com/go-what-is-twilio-japan-1
twitter api v1からv2へ

# はじめに
いやー、大変だった。
今まで、twitter api v1.1で[ang12-twitter](https://github.com/hideume/ang12-twitter)というのを作成していたのだが、これをtwitter api v2に移植しようかといろいろやって、今日、まあまあ筋道が見えたというご報告

# twitter api v2とは
　twitter developerにいけば、説明がある。v1だと、検索結果が10個ぐらいしかとれなくなってしまったので、しかたがないので移植を行っているということ。
v1に比べて、restを利用できる回数が多いということだ。

# Oauth2.0 with PKCE
　v2でめんどくさいのが、認証で、全ての機能を使いこなすには、Oauth2.0 PKCEをクリアするアプリを作らないといけない。ただ、まだ、この認証部分は作っていない。認証の中でもbearer_tokenを使えば、一部のRESTは使用することができる。(app onlyともいう）
　これが、わかるまでかなりかかった。
　このbearer_tokenはtwitter developerで自分用のアプリの申請を行って、取得することができる。
　この取得方法も、どこに何を書けばいいのだが、ようわからんのだが、ググれば説明があるので、ここでは触れない。
　最初はあまりドキュメントを読まないで、進めていたが、今は、翻訳ツールで日本語で読めるので、概念ぐらいはわからないと利用は難しい。
　内容が内容だけに、qiitaでググって簡単に作るというものではないので翻訳ツールでtwitter developerを一通り読むということをお勧めする。

# v1とv2のresponceの違い
 やはり、v2はv1と異なり、必要最小限のresponceになるように設計されており、v1のデータ構造をそのまま使えるような代物ではなかった。
　昔は、data.statuses:{text:"",id:"",user:{screen_name:"",name:""}}というような構造だったのだが
　v2では　data:{text:"",id:"",author_id:""},includes:{users[{id:"",name:"",userneme:""}
というように、user部分を切り離して応答するということになってしまって、これでは2つのデータをauthor_id==idで連携しないとscreen_name(v2ではusernameに変更）は表示できないということになってしまって、あらあら！ということになっている。
　やはり、初めから作り直した方がいいということなのだが、めんどくさいので、今はv1とv2を混在した状態でさっき、ようやくsearchを表示させることに成功した。

# twitter-v2のvulnerabilities
　clientを作成するのにtwitter-v2というnode-moduleをinstallしているんだが、
　どうも、現状ではvulnerabilitiesのhighが4つもある。ということでまだ公開していないのだが、どうも使っているtwitter-v2が理由なようので、そのうち、twitter-api-sdkに変えたいのだが、今使っているはtypescriptではないんだよなあ・・自分で書いてもたいしたことはないかなあ？悩む
　→上記の悩みはtwitter-api-sdkがjavascriptにも対応していたので、解決です。今ではang12-twitterにtwitter-api-sdkに対応したものが上がっています。これでいけば、pkce認証もうまくいきそうですなあ

# 今後
 しばらくは、Oauth2.0 with PKCEを使わないでもなんとかなりそうだが、クリアできたらまた報告することにしたいと思います。ちょっと参考にはならなかったかな？
 →[twitter api v1からv2へ(その2)](https://qiita.com/hawaii_hahaha/items/aa69c9bc0229c2877938)
PHPの変数の値をHTMLタグの属性値として使う。

# 前書き

PHPを利用してHTMLを書いていると、変数の値をタグの属性値にして使いたい時があったので、そのやり方

# コード

```php:input_sample2.php
<?php
$name=array('磯野波平','磯野フネ');

if(isset($_POST['namae'])
    AND in_array($_POST['namae'],array(0,1)))
    $input_value = $name[$_POST['namae']];
else
    $input_value = "";

$body =<<<BBB
<!DOCTYPE html>
<html lang="ja">
<head>
        <title>input sample page</title>
</head>
<body>
<form method="post">
    <p>名前を入力したい人を選択してください。</p>
    <label>お父さんの名前<input type="radio" name="namae" value="0" checked ></label>
    <label>お母さんの名前 <input type="radio" name="namae" value="1" ></label>
    <p><input type="submit"  value="入力"></p>
</form>
BBB;

$body2 =<<<BODY
    <h2>世田谷の有名家族調査</h2>

<form>
    <label>名前<input type="text" value="{$input_value}" size=20></label>
    <p><input type="submit" value="検索"></p>
</form>
BODY;

if($_SERVER['REQUEST_METHOD'] === 'POST'){
    $body = $body.$body2;
}

echo $body;
echo '</body></html>';
?>
```
# 実行

```bash
php -S localhost:8000
```
でPHPだけでWEBサーバを起動。

上記コマンドを打った場所がホームディレクトリーとなるので、そこに`input_sample.html`を配置
ブラウザで見てみる。

![スクリーンショット 2022-11-19 9.43.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/7fc56d93-b75f-f07f-c176-23fc5061e724.png)


![スクリーンショット 2022-11-19 9.43.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/9e8da726-5f34-7e6f-804c-35b8457aabfa.png)

うまくいった。

# 解説
~~コメントに書いているとおり、
[PHP:echo - Manual](https://www.php.net/manual/ja/function.echo.php)
の記載方法をつかって、`input`タグの`value`属性に値を渡している。~~

ヒアドキュメント内の変数展開と、数字のバリデーションを行なって、どんな値が来たとしてもなんとかなるようにした。

`in_array()`と`preg_match()`どっちがいいんだろ？考えやすいのは`preg_match()`の方だけど。

https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html

をみても
> 信頼できないデータは安全な属性のリスト（下記）にのみ配置、background, ID, nameなどの安全でない属性は厳密に検証する。

とのことなので、検証コードは必要。

# まとめ
属性も動的に設定できると、WEBページを使った簡易的なゲームなんかがもっと柔軟に作れるようになると思う。
Tree Maker_Convert Markdown to tree!_WebAssembly&ServiceWorker

https://ddddddo.github.io/gtree/

![web_example.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271313/83d52823-8f74-d5f8-14c3-4110f54110d6.gif)

# これは何か？
Markdown形式の入力を与えると、treeコマンド結果のような表示がされるWeb appです。
以下の4種類の記号が使えます。
`*`, `-`, `+`, `#`

また、出力されるツリーの各階層は、入力となるMarkdownでは半角スペース2つずつインデントすることで表現します。

# このサイトの特徴は？
- Markdownからtreeを生成する処理はGoで書いており、その処理部分はTinyGoでWebAssembly(.wasm)としてコンパイルしています。
	- コンパイルされたバイナリはJavaScriptから呼ばれます。
- ServiceWorkerを利用していて、このWeb appを構成する静的コンテンツ(.wasm含む)はブラウザにキャッシュされ、更新が無い(あるいはブラウザキャッシュから消えない)限り、一度このサイトを訪れた後は、オフラインでも使うことができます。

[source code](https://github.com/ddddddO/gtree/tree/master/cmd/gtree-wasm)

# 関連
- CLI tool/ Go packageとしても公開しています。
	- [CLI tool紹介記事](https://zenn.dev/ddddddo/articles/ad97623a004496)
	- [Go package紹介記事](https://zenn.dev/ddddddo/articles/8cd85c68763f2e)
ESP32: HTTP クライアント (Post)

こちらのプログラムを ESP32 に書き換えました。
[M5Stack Core2: HTTP クライアント (Post)](https://qiita.com/ekzemplaro/items/715990eb96ba19beac58)
Ubuntu 24.04 上の Arduino IDE 2.3.2 を使いました。
ボードは ESP32 Dev Module です。
ArduinoJSON を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/6688b136-45d7-4917-cbb4-ab136ebf3a01.png)

```text:http_post.ino
// ---------------------------------------------------------------
/*
	http_post.ino

					Jul/25/2023
*/
// ---------------------------------------------------------------
#include <Arduino.h>

#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

WiFiMulti wifiMulti;
HTTPClient http;

const char *ssid = "rs500m-e1eaf5-1";
const char *password = "7f7a63e07b1c6";

int count = 0;

// ---------------------------------------------------------------
void setup()
{
	Serial.begin(115200);
	Serial.println("*** setup start ***");

	wifiMulti.addAP(ssid, password);
	Serial.print("\nConnecting Wifi...\n");

	delay(3000);
	Serial.println("*** setup *** aaa ***");
	delay(1000);

	Serial.println("*** setup ***");
}

// ---------------------------------------------------------------
void loop()
{
	Serial.println("*** loop *** " + String(count));
	delay(2000);
	String url_target = "https://httpbin.org/post";
	http_post_proc(url_target);
	delay(3000);
	count++;
}

// ---------------------------------------------------------------
void http_post_proc(String url_target)
{
	DynamicJsonDocument doc(128);
	char data_json[128];

	doc["user"] = "jiro";
	doc["password"] = "123456";
	serializeJson(doc, data_json);

	if((wifiMulti.run() == WL_CONNECTED)) {
		Serial.print("[HTTP] begin...\n");
		http.begin(url_target);
		Serial.print("[HTTP] POST...\n");
		int httpCode = http.POST((uint8_t*)data_json, strlen(data_json));
		if(httpCode > 0) {
			Serial.printf("[HTTP] POST... code: %d\n", httpCode);

			if(httpCode == HTTP_CODE_OK) {
				String payload = http.getString();
				Serial.println(payload);
				}
			}else {
			Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
			}
		http.end();
	}
	else
		{
		Serial.print("connect failed");
		}
}

// ---------------------------------------------------------------
```

## ターミナルプログラム

```bash
cu -s 115200 -l /dev/ttyUSB0
```
ESP32: HTTP クライアント (Get)

こちらのプログラムを ESP32 に書き換えました。
[M5Stack Core2: HTTP クライアント (Get)](https://qiita.com/ekzemplaro/items/bf4a55395030524c5362)
Ubuntu 24.04 上の Arduino IDE 2.3.2 を使いました。
ボードは ESP32 Dev Module です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/fa57b26e-9c30-9b22-731a-0bf55df83700.png)

```text:http_get.ino
// ---------------------------------------------------------------
/*
	http_get.ino

					Jul/25/2023
*/
// ---------------------------------------------------------------
#include <Arduino.h>

#include <WiFiMulti.h>
#include <HTTPClient.h>

WiFiMulti wifiMulti;
HTTPClient http;

const char *ssid = "rs500m-e1eaf5-1";
const char *password = "7f7a63e07b1c6";

int count = 0;

// ---------------------------------------------------------------
void setup()
{
	Serial.begin(115200);
	wifiMulti.addAP(ssid, password);

	delay(1000);
	Serial.println("*** setup *** aaa ***");
	delay(1000);

	Serial.println("*** setup ***");
}

// ---------------------------------------------------------------
void loop()
{
	Serial.println("*** loop *** " + String(count));
	delay(5000);
	String url_target = "https://httpbin.org/get";
	http_get_proc(url_target);
	delay(5000);
	count++;
}

// ---------------------------------------------------------------
void http_get_proc(String url_target)
{
	if((wifiMulti.run() == WL_CONNECTED)) {
		Serial.print("[HTTP] begin...\n");
		http.begin(url_target);
		Serial.print("[HTTP] GET...\n");
		int httpCode = http.GET();
		if(httpCode > 0) {
			Serial.printf("[HTTP] GET... code: %d\n", httpCode);

			if(httpCode == HTTP_CODE_OK) {
				String payload = http.getString();
				Serial.println(payload);
				}
			}else {
			Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
			}
		http.end();
	}
	else
		{
		Serial.print("connect failed");
		}
}

// ---------------------------------------------------------------
```

## ターミナルプログラム

```bash
cu -s 115200 -l /dev/ttyUSB0
```
Databricks on GCPが東京リージョンでオープンしました！

長らくお待たせしました！

**New Google Cloud region: asia-northeast1 (Tokyo)**

https://docs.gcp.databricks.com/release-notes/product/2022/november.html#new-google-cloud-region-asia-northeast1-tokyo

早速試してみます。

GCPコンソールでマーケットプレースにアクセスして、「databricks」で検索します。
![Screen Shot 2022-11-19 at 8.37.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/37815c12-d01b-307c-df85-295abc1aadbb.png)

**プロバイダで管理**ボタンをクリックすると、Databricksのアカウントコンソールに移動します。途中ログインを求められます。
![Screen Shot 2022-11-19 at 8.38.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f2d1debb-5d99-b154-c0ca-d24b5bfd9361.png)

アカウントコンソールからDatabricksワークスペースを作成します。**Create workspace**をクリックします。
![Screen Shot 2022-11-19 at 8.39.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e23d9aee-2dfc-99af-6c1b-c64b60311ecf.png)

Regionで**asia-northeast1**が選べる様になっています！
![Screen Shot 2022-11-19 at 8.39.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e36cfc38-da7f-a782-6daa-357f800a2420.png)

ワークスペースをデプロイするGoogle cloudプロジェクトIDを指定して、**Save**をクリックします。
![Screen Shot 2022-11-19 at 8.40.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7c89b10e-4158-8327-8d5d-06b749f22bd9.png)

権限を許可します。
![Screen Shot 2022-11-19 at 8.40.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7faa2ba7-650d-2042-fcd9-9d9d151a1eab.png)
![Screen Shot 2022-11-19 at 8.40.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/916331b6-450b-beb9-3b01-e83a99f207c5.png)

ワークスペースのデプロイがスタートします。
![Screen Shot 2022-11-19 at 8.41.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b5ce4880-261c-9a4f-328f-bfc82fa848b1.png)

東京リージョンにDatabricksワークスペースがデプロイされました！
![Screen Shot 2022-11-19 at 8.50.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/ee054ed4-0f44-1fef-ad22-601a69997214.png)

**Open**のリンクをクリックして、ワークスペースにアクセスします。追加アクセスが求められたら**続行**をクリックします。
![Screen Shot 2022-11-19 at 8.50.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/06b06bfe-fc64-f6d7-9550-3c0044c0a96d.png)

ワークスペースにログインできました。
![Screen Shot 2022-11-19 at 8.51.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1d27b5ae-6a98-dcd5-96a7-ececab9aeaa4.png)

クラスターも無事起動できました。感慨深いです。
![Screen Shot 2022-11-19 at 9.01.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/5324c984-dcab-fc4c-a52f-a43ea8845759.png)

是非、東京リージョンでDatabricks on GCPをお試しください！

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
【Rails】each文内の要素をjQueryでシャッフル表示させる方法

# 何がしたい？

each文で回した親要素に含まれる子要素の順番をランダムにシャッフルさせて表示させたい。

![shuffle_card.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2688241/cb55a074-723a-8fa8-911d-f729018873ab.jpeg)


# 方法

## viewファイル

```erb
<% # each文の周回をiとする(iの初期値は0) %>
<% @cards.each_with_index do |card, i| %>
  <div class="container">
    <% # item_wrapperにRuby構文でインデックスを付与する %>
    <div class="row item_wrapper_<%= i+1 %>">
      <div class="card"><%= card.content_a %></div>
      <div class="card"><%= card.content_b %></div>
      <div class="card"><%= card.content_c %></div>
    </div>
  </div>
<% end %>
```

## jQuery

```javascript
function shuffleContent(container) {
  var content = container.find(".card");
  var total = content.length;
  content.each(function() {
    content.eq(Math.floor(Math.random() * total)).prependTo(container);
  });
}
$(function() {
  for (var i=1; i<1000; i++) {
    shuffleContent($(".item_wrapper_" + i)); // + を使って文字列と変数をつなげる
  }
});
```

### 解説

**Viewファイル**
`item_wrapper_<%= i+1 %>`の`i`はeach文のインデックス値が代入されるので、`item_wrapper_1`, `item_wrapper_2`, `item_wrapper_3`,,,という親要素が生成されます。

**jQuery**
`.item_wrapper_" + i`要素に対してJSのコードが適用されます。
このiはfor文により、1から999まで回ります。
Railsが生成したHTML上の`item_wrapper_1`, `item_wrapper_2`, `item_wrapper_3`,,,の親要素**それぞれ**のなかから`.card`要素を見つけ出し、それを**都度**シャッフルさせます。

これにより、`.card`要素をシャッフル表示させることができます。

# 参考

https://ecmemo.net/jquery-shuffle
スクロールバーのカスタマイズで困ったこと

# スクロールバーをカスタマイズするときに困ったこと

## 01. はじめに
開発中、少しだけ手こずった部分があったので、備忘録までに
（メモ程度にしか書いておりません🙏）

※ブラウザによってはのちにでてくるコードの書き方は変わります🙏

仕様ブラウザ：Google Chorme
使用言語：css

## 02. 横スクロールバーの幅が変わらなかった

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783573/be3084d2-d081-f824-c84d-b65c8fa99ed5.png">

こんな感じで縦スクロールの幅は変わるのに、横スクロールの幅は変化しない...
ちなみにCSSコードはこんな感じ
```
//「block」はスクロールバーを表示させているdivタグに付与したクラス
.block::-webkit-scrollbar{
   width: 5px;
}
```
なぜだ...

## 03. heightが必要だった
横スクロールバーの幅を変えるにはheightが必要だったと判明

```
//「block」はスクロールバーを表示させているdivタグに付与したクラス
.block::-webkit-scrollbar{
   width: 5px;
   height:5px;//ここを追加
}
```
すると
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783573/2bf54463-3d30-9210-4556-f96cd9633ee5.png">

いけた。縦スクロールは「width」、横スクロールは「height」で幅を変えれるみたい。
（横がheightって直感だとわかりづらかった）
各RDBMSで精度・スケール指定なし数値型は小数点を保持するか？

# 挙動の確認

## Oracle

```sql
SQL> create table test_tbl (num number);

表が作成されました。

SQL> insert into test_tbl values (12.34);

1行が作成されました。

SQL> select * from test_tbl;

       NUM
----------
     12.34
```

## MySQL

```sql
mysql> create table test_tbl (num decimal);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into test_tbl values (12.34);
Query OK, 1 row affected, 1 warning (0.03 sec)

mysql> select * from test_tbl;
+------+
| num  |
+------+
|   12 |
+------+
1 row in set (0.00 sec)
```

## PostgreSQL

```sql
mydb01=# create table test_tbl (num numeric);
CREATE TABLE
mydb01=# insert into test_tbl values (12.34);
INSERT 0 1
mydb01=# select * from test_tbl;
  num  
-------
 12.34
(1 行)
```

## SQL Server

```sql
1> create table test_tbl (num decimal);
2> insert into test_tbl values (12.34);
3> go

(1 rows affected)
1> select * from test_tbl;
2> go
num                 
--------------------
                  12
```

# まとめ

精度・スケール指定なしのデータ型は、

- Oracle / PostgreSQL：小数点を保持する
- MySQL / SQL Server：小数点を丸める

どうせ Oracle だけ挙動が違うんだろと思っていたら、PostgreSQL も一緒だった。

PostgreSQL のドキュメントを見ると、SQL 標準では小数点を持たないことが仕様っぽい？

[8.1.2. 任意の精度を持つ数](https://www.postgresql.jp/document/14/html/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL)

> 精度も位取りも指定せず、
> NUMERIC
> と記述すると、実装されている限界の精度まで、いかなる精度あるいは位取りの値も格納できる「制約の無い数値」列が作られます。 この類の列は入力値をいかなる特定の位取りにも変換しませんが、宣言された位取りを持つnumeric列は入力値をその位取りに変換します。 （標準SQLはデフォルトとして位取り0を要求していて、つまり、整数の精度に変換されます。 しかし、この方法はあまり役に立たないと思われます。 もし移植性を心配するなら、常に精度と位取りを明示的に設定してください。）
【Vue】Google Fonts を Vue3 で使用する（Vite 編）

## 概要
Google Fonts を Vue のソースに組み込む手順の備忘録。
今回は Vue-CLI や Webpack ではなく Vite を利用したバージョンの方法。

意外と記事が無かったので作成。
Viteの場合は、`vite.config.js` にフォント導入設定をします。

## 前提
- Vue: v3.2.41
- Vite: v3.2.3
- TypeScript: 4.6.4

※ TypeScriptを使用していない場合は、以降のファイル名記載が `.ts` の部分を、`.js` に読み替えてください

## Google Fonts とは
色んなWebフォントを無料で提供しているサービス。設定を行うと、Webサービスで好きなフォント（字体）を表示することができる。
![Google Fontsとは_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787582/9472a3a5-9a18-c4ce-46ee-463be2645e24.png)


## 手順

### 1. フォント選び
[Google Fonts](https://fonts.google.com) で好きなフォントを選ぶ。

フォントをどれか選ぶと、以下の様な詳細ページが表示される。そこで、フォントの太さをどれか選ぶ
![Google Fontsとは_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787582/693bcb8f-02ca-d76a-1b21-013eb3380827.png)

選んだら、そのフォントの設定値を確認しておく。
![Google Fontsとは_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787582/e37ca684-0bd4-8236-651a-1f154e3c4490.png)

とりあえず画面はこのままにしておいて、次の手順へ進む。

### 2. プラグイン導入
Viteで作ったVueプロジェクトのディレクトリをターミナルで開き、以下のコマンドで `vite-plugin-fonts` というプラグインを導入する（使用するプラグインは[こちら](https://www.npmjs.com/package/vite-plugin-fonts)）

```bash
npm i vite-plugin-fonts
```

### 3. 設定を追記
先程のフォントの設定値（フォント名のみ）をコピーして、プロジェクト内の設定ファイル `vite.config.ts` に、以下の様に追記する

```ts:vite.config.ts
import { defineConfig } from 'vite'
import { VitePluginFonts } from 'vite-plugin-fonts' // 追加
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [
    vue(),
    // 以下を追加 ----------------
    VitePluginFonts({
      google: {
        families: [
          'M PLUS 2' // ここに導入したいフォント名を入れる
        ],
      }
    })
    // 追加はここまで -------------
  ]
})
```

### 4. CSS で font-family を設定する

#### 全体（全画面）に適用する
Vite で作成した場合は、 `src/style.css` に既にファイルと中身が存在しているので、`font-family` という部分に、自分が設定ファイルに追記したフォント名を追記するだけです。

```css:src/style.css
:root {
  /* 自分が設定したフォント（ここでは「'M PLUS 2'」）を追加する */
  font-family: 'M PLUS 2', Helvetica, Arial, sans-serif;
}
```

#### 特定の要素だけに適用する
HTMLの一部の要素だけに部分的に適用したい場合は、クラス名やIDなどを使って以下の様に CSS を作成します。

```css
.my-fonts {
    font-family: 'M PLUS 2', sans-serif;
}
```

### 5. 画面で表示確認
あとは、Web画面を起動して確認してみましょう。
（以下は、部分適用で５種類のフォントを導入・表示した例）
![Google Fontsとは_04_Vue&Vite.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787582/5ec85549-d37c-3b6d-1a80-0ca8537ec79a.png)

以上、参考にしてみてください！
Vue3利用の基礎情報まとめ

備忘録的にVue.jsをインストールして基本的な環境を構築するまでに必要になった情報をまとめておきます。

# Vue-cliのインストール
簡単に利用するにはCDN経由で利用するのが便利なのですが、bootstrapやvue-routerを使おうと思うとやはりVue-cliを使うのが便利です。

https://qiita.com/567000/items/dde495d6a8ad1c25fa43

# vue-routerのインストール
画面遷移を行おうと思うと必須。

https://qiita.com/hshota28/items/765cf903f055754f7557

https://macareux.co.jp/blog/vue-routerurl

# Bootstrapの利用
デザインを簡単に整えるのに便利なのでいつも使っています。
bootstrap-vueはどうもVue3ではうまく動きませんでした。まだアルファ版ですがbootstrap-vue-3というものがありますのでそちらを利用してみました。

※その後、bootstrap-vue-3はbootstrap-vueプロジェクトに移行し、bootstrap-vue-nextパッケージとなったようです。

https://github.com/bootstrap-vue/bootstrap-vue-next

# npm run serve時に利用するポートを変更する
Docker上でVue.jsを利用しようと思ったのでポートバインドをするのに設定変更しました。

https://dev.classmethod.jp/articles/change-vue-project-devserver-port/

# vueのインストール
ということでまずは以下を実行してvue3と必要なライブラリをインストール

```
$ npm install -g @vue/cli
$ vue create [プロジェクト名]
$ cd ./[プロジェクト名]
$ npm install bootstrap-vue-next
```

# vue-routerとbootstrap-vueの利用設定
```javascript:src/main.js
import router from './router'
import {createApp} from 'vue'
import App from './App.vue'
import BootstrapVue3 from 'bootstrap-vue-3'

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue-3/dist/bootstrap-vue-3.css'

const app = createApp(App)
app.use(router)
app.use(BootstrapVue3)
app.mount('#app')
```

```javascript:src/router.js
import {createRouter,createWebHashHistory} from 'vue-router'
import [コンポーネント名] from './[コンポーネントファイル].vue'
・・・

const routes = [
  {path:'/[設定したいページへのパス]',component:[コンポーネント名]},
  ・・・
]

const router = createRouter({
  history:createWebHashHistory(),
  routes,
})

export default router;
```

# フロントエンド開発開始
あとは常の通り、**npm run serve**で開発用のサーバを起動して開発開始。

**npm run build**で./distフォルダにビルド済みファイルが出来上がります。

大体半日くらいかけてやっとVue3の環境を構築できました。
もっと短い時間で構築できるといいなと思ってます。
初稿

初投稿です。
これからPythonやC++についてアウトプットしていきたいと思います。
まずは手始めに挨拶を。

```python:qiita.py
print("Hello World.")
```

```c++:qiita.cpp
#include <iostream>

using namespace std;

int main(int argc, char** argv) {
    cout << "Hello World." << endl;
    return 0;
}
```

よろしくお願いします。
CSSだけでLeafletのマーカーの色を変える簡単な方法

Leafletのマーカーを変えたい時、検索するとプラグインを使う方法がヒットします。

- [Leaflet入門｜プラグインでマーカーの色を変更する（leaflet.sprite）](https://kita-note.com/leaflet-plugin-sprite)
- [【OpenStreetMap】Leafletでマーカーの色を変更する方法](https://medium-company.com/leaflet%E3%81%A7%E3%83%9E%E3%83%BC%E3%82%AB%E3%83%BC%E3%81%AE%E8%89%B2%E3%82%92%E5%A4%89%E6%9B%B4/)

しかし色を変えるためだけに外部ライブラリの依存関係を増やしたくありません。

色々試していたところ、CSSを使えば簡単にマーカーの色を変化させられることに気づきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678625/105b7665-37f6-28b8-58d9-9723ebe28f0b.png)

▲左が変更後、右が変更前（デフォルト）のアイコン

## CSSだけでLeafletのマーカーの色を変える方法

まず`L.icon`でカスタムアイコンを宣言します。
（指定するURLはデフォルトのアイコンが置いてある場所なら何でもOKです。適宜環境に合わせて変更してください。）

```js:javascript
const redIcon = L.icon({
  iconUrl: "https://esm.sh/leaflet@1.9.2/dist/images/marker-icon.png",
  iconRetinaUrl: "https://esm.sh/leaflet@1.9.2/dist/images/marker-icon-2x.png",
  shadowUrl: "https://esm.sh/leaflet@1.9.2/dist/images/marker-shadow.png",
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34],
  tooltipAnchor: [16, -28],
  shadowSize: [41, 41],
  className: "icon-red", // <= ここでクラス名を指定
});
```

ここで大事なのが`className`でアイコンのクラス名を指定することです。
ここで指定したクラス名は、後ほどCSSで色変え指定をする時に使います。
他の要素とクラス名が衝突しそうなときは自由に名前を変更してもらって大丈夫です。

次にマーカーの作成です。
`L.marker`でマーカーを作成する際に、第2引数の`icon`プロパティに先ほど宣言したアイコン（ここでは`redIcon`）を指定します。

```js:javascript
L.marker([35, 135], { icon: redIcon }).addTo(map);
                  // ^^^^^^^^^^^^^^^ オプションのiconプロパティに先ほど宣言したアイコンを指定
```

なおマーカーに対して`marker.setIcon(redIcon)`のように指定することで、後から動的にマーカーを変更することもできます。

最後にCSSの設定です。
最初のアイコン宣言時に指定したクラス名に対して、**filterプロパティで色を変更**していきます。

```css:css
.icon-red { /* icon-redは最初に指定したクラス名 */
  filter: hue-rotate(150deg);
}
```

`hue-rotate`は色相環を回転させる関数です。
（色相環については他の方の記事を参考にしてください。）

https://sevendex.com/post/7275/

ここでは`150deg`を指定しているため、元のアイコンの色である青色から150度回転した赤色のアイコンに変化します。

ここに他の値を指定すると別の色になります。試したところ、

- 50deg：紫
- 120deg：ピンク
- 150deg：赤
- 180deg：茶
- 250deg：緑

という感じになりました。

## まとめ

- CSSだけでLeafletのマーカーの色を変えることができる
  1. JSでアイコン宣言
  1. マーカー使用時に第2引数でアイコンを指定
  1. CSSでプロパティを設定して色変え
- 色相環を何度回転させるかによって、赤色だけでなく紫色や緑色もいける
DDDがわからない～リーダーたち～

# それぞれのリーダー
大きなシステムとなれば、複数のリーダー同士でのやり取りが必要です。人が多ければリーダーの関係性は様々になってきます。

# 仲がいいリーダー同士のやりとり
リーダー同士が仲が良く仕様の確認がとれるなら問題はありません。そのままリーダーどうして受け渡すメモを決めてやりとりをすればいいと思います。

# 仲がわるいリーダー同士のやり取り
リーダー同士の仲が悪く、渡す側のリーダーはグループ内で決めたメモをそのまま受け取り側のリーダーに渡すと決めてしまいました。受け取り側のリーダーはグループ内で使いやすいようにメモし直さないといけなくなります。

# 仲介人を利用しよう
仲が悪いときには、仲介人を用意しましょう。
仲介人は受け取ったメモを相手側に合った形に変更して渡すだけを担っています。
これにより、受け取り側は渡す側のシステムを理解せずともやりとりできるようになりました。

# 仲介人は頼みやすい
仲介人は仕事を頼みやすいのでの仕事がどんどん増えてしまいます。仲介人の仕事は2人のリーダーを取り持つだけです。最低限のしごとだけさせまましょう。
Cocos Creator 2.xの最新アップデート、Cocos Creator 2.4.10について

![40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852397/7c33e537-7de3-fdad-e108-65e59ecfd00b.jpeg)
[Cocos Creator 2.4.10をCocos Dashboardからダウンロード](https://www.cocos.com/en/creator/download)

2.4.10では、2.x関連の問題を修正し、エディターとエンジンの安定性を高め、ネイティブ・モバイル・プラットフォーム関連の問題を解決し、全ての2.xユーザーに推奨されるバージョンとなっています。このバージョンはプロジェクトやプラグインの互換性を損なわないので、2.4.7のアップグレード手順を参照してぜひアップデートしてください。

バージョン3.0の正式リリースに向けて、予定通り2022年は重要なバグフィックスを提供し続ける予定です。これらの修正は安定性と使いやすさを中心に最適化されますので、新規ユーザーやプロジェクトについては、3.x で開発することをお勧めします。

インストールに関するご質問は、[フォーラム内の開発者ログエリアをご覧ください。](https://discuss.cocos2d-x.org/t/the-newest-update-to-2-x-cocos-creator-2-4-10-is-available/57002)

# エディター
リッチテキストを編集した後、タイムラインエディターを終了するときに発生するエラーを修正。

リソースのエクスポート時に、セカンダリフォルダにあるメタファイルの保存場所が正しくないという問題を修正しました。(Finscn氏に感謝)。

フォルダ構成のバンドル優先度プロパティに誤った数値型がある問題を修正(Finscn氏に感謝)。

Mac上のネイティブプラットフォームの構築に必要なPython 2.xのインストールヒントが改善されました。

エディタープロパティパネルのヘルプリンクが機能しない問題を修正しました。

# エンジン
物理エンジンで、ポリゴンコンポーネントが衝突したときに報告されるエラーを修正(https://github.com/cocos/cocos-engine/pull/10888)

Tweenの停止後に内部データが解放されない問題を修正(https://github.com/cocos/cocos-engine/pull/11360) Finscn氏に感謝します。

Label と particle ノードを無効にすると、Timeline エディタに入った後、コンポーネント の有効状態がおかしくなる問題を修正(https://github.com/cocos/cocos-engine/pull/12384)

Director.EVENT_BEFORE_UPDATE, Director.EVENT_AFTER_UPDATE, Director.EVENT_AFTER_DRAW イベントで、deltaTime パラメータを追加 (https://github.com/cocos/cocos-engine/pull/11359), Finscn.Bhd に感謝します。

MotionStreak 効果の最適化。初期化時のトレイル位置を修正し、1フレームによるトレイル遅延を回避しました。(https://github.com/cocos/cocos-engine/pull/10982)

creator.d.ts のいくつかのインターフェイスの定義を改善しました (https://github.com/cocos/cocos-engine/pull/11981)

# ネイティブ
バックグラウンドに入ったときのオーディオ加速の問題を修正 (https://github.com/cocos/engine-native/pull/4288)

Android プラットフォームで広告にジャンプするときのクラッシュ問題を修正 (https://github.com/cocos/engine-native/pull/4289)

Android 7 バージョン以降、間違った言語が表示される問題を修正 (https://github.com/cocos/engine-native/pull/4290)

ネイティブの WebSocket 呼び出しの Close でゲームがクラッシュする問題を修正 (https://github.com/cocos/engine-native/pull/4291)

[Cocos Creator 2.4.10をCocos Dashboardからダウンロード](https://www.cocos.com/en/creator/download)!
クリック時に他の要素がblurする前に処理を実行する

##  何をしたかったのか

ページ内に複数のElement（要素A,要素Bとする）が設置されており、
要素Aにフォーカスがある状態で、要素Bをクリックする時に、要素AのOnBlurが発生する前に要素Bのクリック処理を実行したい。
例えば...

- 要素Aのフォーカスが外れると要素Bが消えてしまう
- 要素Aのフォーカスが外れると自動的にsubmitが走る

 
```HTML
<input type="text" placeholder="要素A" onBlur="console.log('この処理の前に何かしたい')">
<input type="text" placeholder="要素B">
```

## 解決策1
要素BのmouseDownイベントを取得し、クリック処理を実装する。
⇨要素Bのclickイベントは要素Aのblurイベントより遅いため、処理の前に割り込めない。

※注意
TABキーで移動された場合は処理が発火しません。

```HTML
<input type="text" placeholder="要素A" onBlur="console.log('要素Ablurイベント')">
<input type="text" placeholder="要素B" onmousedown="console.log('要素Bmousedownイベント')" onclick="console.log('要素Bclickイベント')">
```

コンソールの出力
```
"要素Bmousedownイベント"
"要素Ablurイベント"
"要素Bclickイベント"
```

参考：　イベントの発火順序
別記事にまとめました
https://qiita.com/zinc0765/items/2380f6872221faafaee4

## 解決策２（Vueなどを入れている場合）
vuetifyでは要素外がクリックされた時に発生する関数（v-click-outside）があるのでそちらを利用する。
https://vuetifyjs.com/ja/directives/click-outside/

## 参考文献
https://developer.mozilla.org/ja/docs/Web/API/Element/mousedown_event
https://developer.mozilla.org/ja/docs/Web/API/Element/blur_event
JavaScriptの要素のイベント発火順序

特定イベントの前に処理を行いたかった時に発火順序がはっきりわからなかったので調べました。


# 検証コード
検証するイベントについては、以下のイベント一覧から利用頻度の高いor気になるものを抜粋しました。
https://html.spec.whatwg.org/multipage/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects
また、複数のイベント間でどうなるかも調べました。

行った操作としては、クリックでフォーカスを当て、その後文字入力を行いました（複数あった場合はそれぞれ）

#### 単体の要素
```HTML
<input
       type="text"
       placeholder="要素A"
       onbeforeinput="console.log('beforeinputイベント')"
       onchange="console.log('changeイベント')"
       onclick="console.log('clickイベント')"
       onclose="console.log('closeイベント')"
       oninput="console.log('inputイベント')"
       onkeydown="console.log('keydownイベント')"
       onkeypress="console.log('keypressイベント')"
       onkeyup="console.log('keyupイベント')"
       onmousedown="console.log('mousedownイベント')"
       onmouseenter="console.log('mouseenterイベント')"
       onmouseleave="console.log('mouseleaveイベント')"
       onmousemove="console.log('mousemoveイベント')"
       onmouseout="console.log('mouseoutイベント')"
       onmouseover="console.log('mouseoverイベント')"
       onmouseup="console.log('mouseupイベント')"
       onblur="console.log('blurイベント')"
       onfocus="console.log('focusイベント')"
>
```

#### 複数の要素間
```HTML
<input
       type="text"
       placeholder="要素A"
       onbeforeinput="console.log('要素Abeforeinputイベント')"
       onchange="console.log('要素Achangeイベント')"
       onclick="console.log('要素Aclickイベント')"
       onmousedown="console.log('要素Amousedownイベント')"
       onmouseup="console.log('要素Amouseupイベント')"
       onblur="console.log('要素Ablurイベント')"
       onfocus="console.log('要素Afocusイベント')"
>
<input type="text" placeholder="要素B"
       onmousedown="console.log('要素Bmousedownイベント')"
       onclick="console.log('要素Bclickイベント')"
       onfocus="console.log('要素Bfocusイベント')"
>
```


# 結論
### 単体の要素
```
"mouseoverイベント"
"mouseenterイベント"
"mousemoveイベント"
"mousedownイベント"
"focusイベント"
"mouseupイベント"
"clickイベント"
"keydownイベント"
"keypressイベント"
"beforeinputイベント"
"inputイベント"
"keyupイベント"
"mousemoveイベント"
"mouseoutイベント"
"mouseleaveイベント"
"changeイベント"
"blurイベント"
```
※見やすさのためにmousemoveイベントを一部削除しています


### 複数の要素間
```
"要素Amousedownイベント"
"要素Afocusイベント"
"要素Amouseupイベント"
"要素Aclickイベント"
"要素Abeforeinputイベント"
"要素Bmousedownイベント"
"要素Achangeイベント"
"要素Ablurイベント"
"要素Bfocusイベント"
"要素Bclickイベント"
```
DDDがわからない～すべてを知ること～

# でかい複雑なシステムへ挑戦
少人数の人間のやりとりのシステムであれば、作る側全員が同じことを考えることは不可能ではないと思います。しかし、システムが大きく複雑になればなるほど全員が同じことを考えることは難しくなってきます。


# 諦める。。。
全部覚えることは諦めましょう。人間の認識できることには限度というものがあります。なので、覚えるべきものを絞って覚えましょう。

~~~text:最低限覚えること
1.システムのやり取りで大まかにグループ分けをしてグループ名を決め覚えましょう
2.全体で共通して使う言葉を決め覚えましょう
3.あとはグループごとに使う言葉を決めて覚えましょう
~~~

# やばいので注意しておくこと
グループ内で使用する言葉であればグループ内で決めればいいとしました。
しかし、言葉には、
**・ お雑煮など同じ言葉なのに違う意味を表すもの。**(お雑煮は地域によって中身が全然違う)
**・ 逆に大判焼きと今川焼きなどのように違う言葉なのに同じ意味を表すもの**
といったものが存在します。
これはトラブルの原因になりやすいので、なるべく見つけたら早急に分割(関西風お雑煮、関東風お雑煮と変更)や統合(今川焼と使っている個所を大判焼きに変更)をして全体で使う言葉として決定しましょう。
時間を大切にしたい全人類は食洗器を買った方がいいよ

パナソニックが2015年に行った調査で、1回の食器洗いに要する平均時間は 19.4 分だったそうです。

https://prtimes.jp/main/html/rd/p/000000009.000008708.html#:~:text=1%E5%9B%9E%E3%81%82%E3%81%9F%E3%82%8A%E3%81%AE%E6%89%80%E8%A6%81,%E3%81%A6%E3%81%84%E3%82%8B%E3%81%A8%E8%A8%80%E3%81%88%E3%81%BE%E3%81%99%E3%80%82

とはいえ世帯人数や食器の数・形状、毎食後洗うのか一日まとめて洗うのかなどのライフスタイルによって食器洗いの時間にバラつきはあるでしょう。上記は "パナソニックが行った調査” ということもありますし。

一人暮らしで1日に一度まとめて洗う私の体感値的には1日に 10 分程度でしょうか。
それでも1年間に食器洗いに要す時間は **3650 分**＝約 **61 時間**となります。

大変正直に申し上げれば、食器洗いという非生産的な活動にこれだけの時間を費やしているのがもったいないとしか思えなくてですね :sweat: 

今回は私が導入した食洗器と初期コスト、導入してどうだったかを書きます。
まあ、タイトルと書き出しで分かると思いますが、食洗器は最高です。

### 導入した食洗器と初期コスト
私が導入したのは卓上型食洗器の Panasonic NP-TCR2 です。現行より2つ前の世代のモデルですね。

![IMG_1499.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/dfbb5673-96e5-cf87-d211-5b8c02a786c3.jpeg)

庫内はこんな感じ。私の場合は1日分の食器がギリギリ入るサイズ感です。

![IMG_1501.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/4dab7ef4-1aaa-bf1e-b46b-6d94a917aa8d.jpeg)

食洗器の導入には分岐弁も必要です。これは設置個所の栓の種類に応じて選択する必要があります。

![IMG_1500.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/6b78c16b-6ec3-abd0-2811-47a89806d5e2.jpeg)

私はいずれも中古で購入し、食洗器は1.3万円＋分岐弁は0.7万円で計2万円で揃えました。

### 食洗器を導入してどうだったか
よかったことが大きく3つあります。

#### 1. 時間を有効に使える
冒頭にも書きましたが、食器洗いの時間が無くなるので時間を有効に使うことができます。年間 61 時間もの時間が使えるようになるわけですから、読書に換算したら何冊よめるでしょうね・・・？

#### 2. 食器が清潔
食洗器の導入を躊躇する人の理由に「食洗器って本当にきれいになるの？」があります。
私個人の回答としては「高温で洗浄するので基本的には手洗いよりはきれいになる。ただし、こびりつき汚れには弱いので工夫は必要。」です。ここで言った工夫としては食器洗いまでは水につけておくがありますね。
ちなみに、私は食洗器で洗う前に軽く手洗いをする前洗いはしていません。食洗器にかけてまだ汚れているようなら手洗いをします。それで十分かなと。

#### 3. 手荒れしない
冬場の乾燥する時期に食器洗いをすると手があれますよね。私はそうでした。いくらハンドクリームを塗ろうと抗えないものでした。
ただ、食洗器の導入ではそれは解決されました。

いかがでしたでしょうか。時間を大切にしたいあなたはぜひ食洗器の購入を検討してみてください。（ Panasonic さん、私に少しでいいので宣伝料をください。）
任意のsuffix（拡張子）のファイル名を生成するシェル芸


任意のsuffix（拡張子）のファイルがほしい場合があるかもしれません。
そんなときに使えるシェル芸を紹介します。

## 完全ランダムなsuffix（拡張子）を生成する場合

```bash
$ echo unko.{a..z}{a..z}{a..z}|tr \  \\n|shuf|head -n5|xargs echo
unko.yar
unko.uow
unko.tbs
unko.vxy
unko.zgb

## 実際にファイルが生成したい場合
$ echo unko.{a..z}{a..z}{a..z}|tr \  \\n|shuf|head -n5|xargs touch
```


## 存在するファイルフォーマットの拡張子から生成する

Wikipediaの[ファイルフォーマット一覧](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E4%B8%80%E8%A6%A7)のページに載っている拡張子から選択して生成したいかもしれません。
現実の拡張子の文字数は3文字以外も多いためこちらのほうが実用的かも？

```bash
$ curl -s 'https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E4%B8%80%E8%A6%A7'|pup '.sortable > tbody > tr > th > div json{}'|jq -r '.[]|select(.id != "")|.text'|grep -v null|grep -Eo '^[^,\-]+'|shuf|head|xargs -i{} echo unko.{}
unko.PYO
unko.GrADS
unko.PCM
unko.FNM
unko.W3G
unko.ORG
unko.MPA
unko.LIC
unko.XCK
unko.WP5

## 実際にファイルが生成したい場合
$ curl -s 'https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E4%B8%80%E8%A6%A7'|pup '.sortable > tbody > tr > th > div json{}'|jq -r '.[]|select(.id != "")|.text'|grep -v null|grep -Eo '^[^,\-]+'|shuf|head|xargs -i{} touch unko.{}

### すべての拡張子のファイルを生成したい場合
$ curl -s 'https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E4%B8%80%E8%A6%A7'|pup '.sortable > tbody > tr > th > div json{}'|jq -r '.[]|select(.id != "")|.text'|grep -v null|grep -Eo '^[^,\-]+'|xargs -i{} touch unko.{}
```

上記はワンライナーですが何度も実行する場合は様々な影響を考慮して、
下記のように一旦ファイルに書き出して実行するようにしましょう。

```bash
$ curl 'https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E4%B8%80%E8%A6%A7' -o suffix.html

$ cat suffix.html|pup '.sortable > tbody > tr > th > div json{}'|jq -r '.[]|select(.id != "")|.text'|grep -v null|grep -Eo '^[^,\-]+'|shuf|head|xargs -i{} echo unko.{}
```

### dependency
珍しいコマンドとしてhtmlの解析にpupを利用しています。便利です。ありがとうございます。

https://github.com/ericchiang/pup

## 感想

テストファイルの生成でつかえるのかな？