OmniAICreator/Qiita-1.07M huggingface dataset:
パスワードマネージャとしての Microsoft Authenticator

# TL;DR

パスワード管理ってわずらわしいですよね。

昔からパスワードマネージャがたくさんあるのも知っていましたが、わざわざ課金をしてそのようなサービスを利用する気があまり起きなかったことに加え、だからといって名前も知らない無料のサービスを使うのも嫌（だってパスワードを渡すわけですから）なもので、ずっと自力管理していました。

そんなある日、仕事柄マイクロソフト系のサービスを利用している中で、MFA やワンタイムパスワードで Microsoft Authenticator は使用していたのですが、パスワードも管理できそうなことに気が付いたので使ってみました。

__こんな人向け__
- スマホで使用するパスワードマネージャを探している（PCは別でいい）
- できれば無料がいい
- 既に MFA や OTP などで Microsoft Authenticator を使用している

# パスワード管理をはじめる

## アプリをインストール
まだ Microsoft Authenticator のアプリをインストールしていない方はこちらから ↓

https://www.microsoft.com/ja-jp/security/mobile-authenticator-app

アプリを使用するのに Microsoft アカウントが必要なので持っていない人は作りましょう。無料アカウントで問題ありません。

https://account.microsoft.com/account?lang=ja-jp

iPhone の方は 「設定」>「Authenticator」から Face ID を有効化しておきましょう。（Android はどうなんんだろ）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252806/fc08fb32-1e69-fd15-0195-bccbb631c841.png" width=50%>


## パスワードを登録
パスワードすでにブラウザや他の場所に保管されている場合は、それらを一括でインポートすることもできます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252806/948b94f4-c1ef-2bd8-92e0-9e08e3d6fa72.png" width=50%>

今回は手動で登録します。サイトの URL、ユーザー名、パスワードを入力する、ただそれだけ。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252806/92a0ce34-f2fb-0fd8-6630-d358ce25d253.png" width=50%>

## オートフィルを有効化
パスワードを登録したら、自動で入力やパスワードのサジェストをしてくれるオートフィル機能を有効化しておきましょう。

Microsoft Authenticator の「設定」>「オートフィルをオンにする方法」に従って設定します。これで完了です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252806/ed5f4eaf-994d-7a27-40ec-ce3aee0dbd9d.png" width=50%>


# パスワードジェネレータ機能
Microsoft Authenticator にはパスワード生成機能もあります。よくある制約（含める文字や文字数）に合わせてカスタマイズし、そのまま登録もできます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252806/c9286e11-2ab1-c243-1864-b1ee56f920e0.png" width=50%>

# 機種変をするときは
機種変をするときや別のパスワードマネージャに乗り換えるときはパスワードをエクスポートしておいた方がいいかもしれません。

Microsoft Authenticator の「設定」>「パスワードのエクスポート」から CSV ファイルにエクスポートできます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252806/d5850625-8086-ffdc-b4be-80fa7a0b65fe.jpeg" width=50%>

# まとめ
勝手に Microsoft Authenticator といえば OTP アプリと思い込んでいた私ですが、パスワードマネージャとしての使い勝手もよかったので紹介しました。

「はじめに」でも書きましたが、現状 Microsoft Authenticator はモバイルアプリしかないため、PC と同期してしようすることはできません（登録はしておいてメモ帳代わりに見ることはできる）。
今後 PC にも対応してくれると最強なんだけどなぁ。
5日間でReactの基礎を習得したい 0/5日目


折角ゴールデンウィークなので、日頃は中々勉強できていない事柄を勉強しようと思います。
私は仕事でWebアプリケーションを作ったことがないのですが、世の中の流れを見るとWebアプリケーションを作れないままで大丈夫なのか、少し不安があります。
そこで、Reactを概要だけでも勉強することにしました。

ただ、アウトプットなしで勉強すると知識として定着しなさそうですし、何より勉強をサボってしまいそうなので、Qiitaで記事を書きながら勉強することにしました。(この記事を書くことで、自分自身がサボれないようにしています笑)

# 現在の私のレベル

- Reactのコンポーネント・フックという言葉だけ見聞きした程度で、何のことかさっぱりわかっていない
- Material-UIというUIライブラリ？をGoogleが出していて、それを使えば綺麗なUIが作りやすいと聞いたことがある。
- C#, Pythonを主に仕事で使っている
- Webアプリケーションを作ったことがない


# 5日間のカリキュラム

## こだわり

GWは他にやることもあるので、毎日 1時間 x 5日間 をReactの勉強に当てることにします。

カリキュラムの中で以下の2点はこだわることにしました。

1. GitHubの1つのリポジトリをいじって学ぶ
経験上、本やWebサイトを読んだり、簡単なサンプルコードを書くだけでは、プログラミング言語を使いこなせるようになったことがありません。そこそこ複雑なコードを苦しみながら解読し、動かしていく中で、知らないうちに使いこなせるようになってきたと思います。そこで、Reactで作られたWebアプリケーションのリポジトリを一部編集して、動かしながら勉強しようと思います。
また、既存のリポジトリでそれなりにスター数があるものは、日頃Reactを使っている人が書いたコードである可能性が高いと思われます。編集する過程で、生きたコードから学びを得ようと思います。
1. テストを実施する
近年、テストコードを書く重要性は益々高くなってきていると思います。少し調べると、ReactではStorybookというツールを使用してテストするようなので、StoryBookを使用したテストを実施します。

この２件の制約のもと、ChatGPTにベースとなるカリキュラムを作ってもらいました。

<details><summary>入力したプロンプト</summary>
Reactを習得したいと思っています。5日間で習得したいのですが、毎日のカリキュラムを作ってください。ただし、4日目は"既存のリポジトリを編集する"、5日目のカリキュラムは"storybookを使ったテストを実施する"にしたいです。
</details>


## カリキュラムの内容

ChatGPTの提案から一部変更しましたが、以下がカリキュラムとなります。

### 1日目: 基本的な概念と環境設定
#### 目標: Reactの基本的な概念を理解し、開発環境をセットアップする。
#### 内容:
- Reactとは何か？コンポーネントベースのアプローチについて学ぶ。
- Node.jsとnpmのインストール。
- 新しいプロジェクトを始める。

https://qiita.com/MichaelHashimoto/items/b813096be60e63ba2816

### 2日目: コンポーネントとステート管理
#### 目標: コンポーネントの作成とステート管理の方法を学ぶ。
#### 内容:
- JSXとプロップスの基本を学ぶ。
- クラスコンポーネントと関数コンポーネントの違いを理解する。
- ステートの使用方法を学ぶ。
- イベントハンドリングを学ぶ。

https://qiita.com/MichaelHashimoto/items/f4779c8d7f9338d61646

### 3日目: フックとルーティング
#### 目標: React Hooksの使用方法とアプリケーション内のルーティングを実装する。
#### 内容:
- フックについて学ぶ。
- useState、useEffectを使ってみる。

https://qiita.com/MichaelHashimoto/items/9d36ab678813b438d435

### 4日目: 既存のリポジトリを編集
#### 目標: 学んだスキルを応用する。
#### 内容:
- GitHubから既存のReactプロジェクトをクローンする。
- コード変更を行う。

https://qiita.com/MichaelHashimoto/items/8c4ce6e8df40db9488df

### 5日目: Storybookを使用したテスト
#### 目標: Storybookを使用してReactコンポーネントの視覚的なテストを行う。
#### 内容:
- Storybookの基本設定とインストール方法を学ぶ。
- 既存のコンポーネントに対してStoryを作成し、異なるプロップスでのビジュアルをテストする。

https://qiita.com/MichaelHashimoto/items/1d838fbd986e93c15ebc

# 最後に

本取り組みを通して、https://qiita.com/asato4931/items/98598e108d8bdc27a0f7 で作られているような、おしゃれなHPやブログを作ることを目標にしていきます。

## React上級者の方へ 

もし、Reactを日頃から使われている方がこの記事を読んでおられたら、アドバイスのコメントなどを頂けると非常に助かります。

## React初級者の方へ

私と同じような動機で勉強を始められる方が読んでおられたら、一緒に頑張りましょう！
見守り番犬システムの運用（TWE-LITEによる見守り④外出お守り）

# １．はじめに
遠隔地に住む祖母の暮らしを見守るため、家に設置した各種センサーの情報をモニタする取り組みを行っておりましたので、主として備忘のためここにまとめます。

モノワイヤレス株式会社の[**「TWE-Lite（トワイライト）」**](https://mono-wireless.com/jp/products/twelite-pal/sense/openclose-pal.html)を使用してセンサ情報を収集し、親機であるRaspberryPiからLINE Notifyでスマホへ通知しする仕組みです。

https://mono-wireless.com/jp/products/TWE-LITE/index.html

## ２．外出お守り機能
`お守りに内蔵したでんしのちから、ハイテクお守りで在室を確認`
　「加速度センサ」を内蔵したお守りを渡しておき、リアルタイムで部屋に居るか、外出中かを判定してお知らせすることができます。
→[**「トワイライトキュー（TWELITE CUE）」**](https://mono-wireless.com/jp/products/twelite-cue/index.html)を使用。

https://mono-wireless.com/jp/products/twelite-cue/index.html

センサーを内蔵したお守りを外出カバンに入れておいて貰って、外出か在室かどうかでステータスが変化します。
写真左のお守りは、京都にある電電宮（電波の祖神として信仰されている神社）のもの、右はケースから出して剥き出しのTWELITE CUEです。
![31.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2944244/f9e23642-e640-4ef6-c59a-f3f555620a69.jpeg)

![30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2944244/61f973a2-994b-d960-078e-32149c2fdf31.png)

# ３．実装
・**準備するもの**
<table>
  <thead>
    <tr>
      <th>区分　</th> <th>　　　　名前</th> <th>説明</th>
    </tr>
  </thead>
  <tr>
    <td> 親機 </td> <td>Raspberry Pi 4 Model B</td> <td>親機となって、センサー情報を記録・発信する本体</td>
  </tr>
  <tr>
    <td>  </td> <td> MONOSTICK </td> <td> センサー情報を受信するデバイス。<BR>「App_PAL」をインストールしておくこと </td>
  </tr>
  <tr>
    <td> 子機 </td> <td>トワイライトキュー（TWELITE CUE）</td> <td>磁気・加速度センサーを内蔵した無線装置。<BR>別途、コイン型電池（CR2032）が必要</td>
  </tr>
  <tr>
    <td> その他 </td> <td>お守り</td> <td>
    
[**電電宮**](https://www.kokuzohourinji.com/dendengu.html) にて購入した有り難いもの</td>
  </tr>
</table>

# ４． DBからグラフ画像を作成する
① MySQLへ「お守りセンサー」のレコードを記録する。

> レコード追加については[「見守り番犬システムの運用（TWE-LITEによる見守り①寝起き動き）」](https://qiita.com/kiryuuyuudai/items/3cbde04f56e89229f8b3)の手順①②をご確認ください
> 

②センサーのデータがない期間を、グラフ上へ「外出」時間として色付けする。
![31_外出御守.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2944244/f4b49ac7-66a5-ce42-7b1e-50e0a0746e6d.png)


```python:#グラフ画像作成（外出期間の設定）
#1.データ集計処理
import pymysql.cursors
connector = pymysql.connect(
    #ここに「データベース接続」の処理を書く#
)
sql = "select NO,DATE,DATA1 from DATA_TABLE where DATA='外出' and DEVID='お守りセンサ'"
cursor.execute(sql)
result = cursor.fetchall()

time_goouts=[]
time_comehomes=[]
for data in result:#外出時間を確認する
    no_goout=data[0]  #続き番号
    time_goouts.append(data[1])#外出時間を記録
    sql2 = "select NO,DATE,DATA1 from DATA_TABLE where DATA='帰宅' and NO>"+str(no_goout)
    cursor.execute(sql2)
    result2 = cursor.fetchall()
    for data in result2:#帰宅時間を確認する
        id data[2]=="帰宅":
            time_comehomes.append(data[1])#帰宅時間を格納
            break
        
#2.グラフ描画処理
ax = plt.subplots()
for i in range(0,len(time_goouts),1):
    ax.axvspan(time_goouts[i], time_comehomes[i], color='red',alpha=0.1)

```
# ５．考察
伝統的な御守りと現代的なセンサーを融合したくて作った機能です。使って貰った結果として、前回でドアに設置した「開閉センサー」の意味がなくなりましたね。
でも、やっぱりセンサーデータを受信しない場合があるので（欠送ではないものの）、在室中でも急な外出が記録されてしまうエラーに対する改善が必要です。

## ●次回予告（インターホン機能）
`古い家屋にも後付け可能、工事不要のインターフォンを設置！`
　ドアベルとして設置した「押しボタン」を押すと、室内にチャイムを鳴らすことが出来ます。
→[**トワイライトパル（TWELITE PAL）**](https://mono-wireless.com/jp/products/twelite-pal/index.html)と接続した**押しボタン**を使用。
簡単な画面を作成してアイドルに紹介したお話

# 概要
- 日向坂46(アイドルグループ)のメンバーと会話ができるイベント「ミート＆グリート(通称ミーグリ)」に参加し、簡単な画面を資料にしてメンバーに紹介したお話
- 初投稿です

第二弾の記事も作成しました！

https://qiita.com/ohisamaru/items/7db62373028be9c97602

# 作成した画面(一部)
- サイトは非公開
- 画像コンテンツはお絵描きアプリで作成したり、生成AI、アイコンメーカーを活用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782193/046d9910-9374-05c7-52cb-327bbae0f383.png)

### 使用技術
- TypeScript
- React
- ChakraUI
- Docker

### 作成経緯と目的
「日向坂で会いましょう」というバラエティ番組でメンバーが「フェスを開催したい」とプレゼンしたことが発端
→ プレゼンを聞いてワクワクしたので、このワクワクを何かしらの形に残して共有したい
→ 妄想を具現化して4月のミーグリで見せよう！

### 所要時間：約70時間
- 設計/調査/実装：約20時間
- コンテンツ作成：約50時間

### 費用：約15,000円
- コンテンツ作成代：10,000円
画面に載せるコンテンツを作成するために2,000円でお絵描きアプリのProcreateを購入しました。併せて8,000円のお絵描きペンも購入。お絵描きは素人ですがとても使い勝手の良いアプリだと思います。

<br>

- 印刷代：100円
コンビニで50円×2枚のフルカラー印刷をしました。

<br>

- ミーグリ代：4,800円(画面の紹介に使用した分のみ)
メンバーと会話できる時間はCDの購入数に応じます。会話時間は約10秒/枚でCD価格は1,200円/枚です。今回紹介に要した分は4枚。

# スケジュール

### 2月中旬 なんちゃってプロジェクト稼働
- 作りたいものを決める
- ざっくりとした画面イメージを作る
- 画面にコンテンツを載せたいのでProcreateとお絵描きペンを購入
- 参考動画を見ながらお絵描きの練習

### 3月中旬
- タスク管理ボードを使用して実装開始
- 実際のボードはこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782193/089541bf-1b0e-c995-8a7d-eacdbf18e11a.png)

- 平日は2,3時間で実装し、土日は2～6時間でProcreateを使ってコンテンツを作成

### 3月下旬～4月上旬
- 他の予定があったため進捗なし(卒コン、ひな誕祭etc)

### 4月中旬
- 想定より時間がとれなくなってしまったため、プロジェクトのスコープをしぼる
→サイトを紹介したいのではなくコンテンツを紹介したいため、コンテンツの作成に時間をかける
→サイトは公開せず画面を印刷した資料を見せることにする(後から知ったのですがミーグリで端末画面を見せるのはダメみたいです)
- ミーグリでメンバーに紹介

# 所感(良かった点/反省点)
 ### 良かった点
- やり遂げられた
当初はリッチな作りにしようと画策していましたが、時間制約もあるので本当にやりたいことだけを実現するように予定を変更しました。終わってみてこれで良かったと感じています。
<br>

- 新しいことを学べた
サイトの自作やお絵描きなど新しい取り組みを経験できて楽しかったです。
<br>

- メンバーが喜んでくれた
これが一番良かったです。紹介時間はとても短かったですが、それでも直接会話して反応をもらえることに有難みを感じました。


 ### 反省点
- 作成物の定義を明確にしておこう
コンテンツの紹介が目的なら簡単な作りで良い、ユーザに利用してもらいたいのであればそれを踏まえた作りにして公開まで行う、など。
<br>

- どう作るかより、何を作るか
実装の方に頭を使ってしまいましたが、何を作るかの方に頭を使う。
<br>

- 紹介時間に余裕を持たせよう
想像ついてはいましたがやはり短すぎました。(1人は約10秒、もう1人は約30秒)
最大で約100秒会話できる仕様なのでたくさんCDを買おう。
<br>

- サイトの公開はした方が良い
メンバーに「公開してるの？」と聞かれたので公開しなかったことに"後悔"しました。


# 最後に
ミーグリの数十秒のために何十時間もかけて準備をしましたが、多くの学びや達成感がありました。当日まで楽しい日々を過ごすことができたので今後も続けていきたいと思います。
next.js+nginxでnet::ERR_BLOCKED_BY_CLIENTエラー

# 経緯
ステージング環境で動作確認した際にnginx経由でfrontendからbackendへのアクセスができない

# エラー内容
```
GET http://localhost:5000/api net::ERR_BLOCKED_BY_CLIENT
```
# 解決策
ステージング環境のlocalhostを見ているので、外部アクセスからでは見れないというエラー。
nginxの設定かと思ったが、私の場合はnext.jsで`http://localhost:5000/api`を直接叩いているのが原因だった。
サーバーのipアドレスとアクセスするポート番号に置き換えてあげる

```
http://server_ip:server_port/api
```
ruby-install failed :error: use of undeclared identifier 'RSA_SSLV23_PADDING'

### ruby-install failed :error: use of undeclared identifier 'RSA_SSLV23_PADDING'


```
$ ruby-install 2.7.4
（省略）
ossl_pkey_rsa.c:942:5: error: use of undeclared identifier 'RSA_SSLV23_PADDING'
    DefRSAConst(SSLV23_PADDING);
    ^
ossl_pkey_rsa.c:877:58: note: expanded from macro 'DefRSAConst'
#define DefRSAConst(x) rb_define_const(cRSA, #x, INT2NUM(RSA_##x))
                                                         ^
<scratch space>:160:1: note: expanded from here
RSA_SSLV23_PADDING
^
115 warnings and 1 error generated.
make[2]: *** [ossl_pkey_rsa.o] Error 1
make[1]: *** [ext/openssl/all] Error 2
make: *** [build-ext] Error 2
!!! Compiling ruby 2.7.4 failed!

```

主な原因は、OpenSSLのバージョンとRubyのバージョンの互換性の問題です。
Ruby 2.7系はOpenSSL 1.1.1系列と互換性があり、適切なバージョンを指定する必要があります。最新のOpenSSLバージョンと組み合わせると互換性の問題が発生する可能性があります。


現在使用しているOpenSSLのバージョンを調べる方法は以下の通りです。
```
openssl version
```

```
$ openssl version
OpenSSL 3.3.0 9 Apr 2024 (Library: OpenSSL 3.3.0 9 Apr 2024)
```

現在有効なOpenSSLのバージョンは`3.3.0`だとわかりました。
どうやらOpenSSLのバージョンとRubyのバージョンのミスマッチが原因で間違いなさそうです。

すでにインストールされているバージョンを確認します。

```
$ brew list | grep openssl
openssl@1.1
openssl@3
```

私の環境にはすでに`openssl@1.1`があるのでそれを指定する方向で進めることに。

もし必要なバージョンがない場合はbrewでインストールしましょう。
`brew install openssl@1.1`


色々調べてうまく行ったのは以下の設定でした。

```
export OPENSSL_ROOT_DIR=$(brew --prefix openssl@1.1)
export PATH="$OPENSSL_ROOT_DIR/bin:$PATH"
export LDFLAGS="-L$OPENSSL_ROOT_DIR/lib"
export CPPFLAGS="-I$OPENSSL_ROOT_DIR/include"
export PKG_CONFIG_PATH="$OPENSSL_ROOT_DIR/lib/pkgconfig"
ruby-install ruby 2.7.4
```

おわり


---
rex0220 計算式プラグイン ユーザー選択から上長セット

[rex0220 計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)で、ユーザー選択項目から上長をセットします。
一覧画面においてログインユーザーが上長となっているレコードを絞り込み、部下のレコードを見やすくすることができます。

# 概要

編集画面でユーザー選択から自動的に上長をセットします。

- 編集画面・詳細画面
![2024-05-01_17h31_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/c4d94828-3a1d-85d2-ac4a-52117706b864.png)


- 一覧画面　ログインユーザーが上長となっているレコードを絞り込み
![2024-05-01_17h36_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/19422f14-6b71-1bce-dfac-dc74ddea5f2f.png)

# 操作例

![2024-05-01_17h39_20.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/b798a333-1b4f-7733-962d-bf0a3baf4459.gif)

# プロフィール項目のカスタマイズ項目設定

カスタマイズ項目に、上司を設定します。

項目コード「boss」で設定

![2023-07-09_15h41_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/2d1afcfe-ca2d-2c56-bfd5-8f0858d6bc0f.png)

# ユーザー情報に上司を設定

ユーザー毎に、上司を設定します。、

![2024-05-01_17h44_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/2119a5a5-c238-c36d-d5c8-3e0937d29a2d.png)

# 計算式プラグイン設定

UINFO 関数を使用するため、「ユーザー情報」をチェックします。

![2024-05-01_17h41_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/c338b80a-fc78-4305-cd90-460a1aaff6d2.png)

```.js
// ユーザー名 SINGLE_LINE_TEXT
ユーザー選択

// 上長 USER_SELECT
LET(a,SEL_CODE(ユーザー選択,"array"), // ユーザーコード
  b,UINFO(UINFO(a,"#boss"),"code"), // 上司コード
  SET_CODE(b)
)

// 上長名 SINGLE_LINE_TEXT
LET(a,SEL_CODE(上長,"array"), // ユーザーコード
  b,UINFO(a,"name"), // 上司名
  REPLACEALL(b,",",", ")
)
```
Windows で画像ファイルを一括変換する (ImageMagick)

# 要約
Windows の PowerShell 上で複数の画像ファイルのフォーマットを変換するには, 以下のようにします.

```
> dir -Name * | % {magick convert "$_" "$_.png"}
```

# 背景
iPhone 使用者から LINE で送られてきた画像を Windows に転送すると, 数字だけのファイル名で拡張子が見当たりません. 調べてみると [HEIF](https://ja.wikipedia.org/wiki/High_Efficiency_Image_File_Format) というフォーマットのようでした.

これらのファイルを, 当初は [Gimp](https://www.gimp.org/) で 1 つずつファイルを開いてエクスポートして変換していました. しかしファイル数が増えてくると作業が非常に面倒になったので, コマンドラインで一気に変換できる方法を調べました.

# ImageMagick
画像フォーマットの変換には [ImageMagick](https://imagemagick.org/index.php) を使います. Windows 用のバイナリを普通にインストールすれば OK です.

Linux などで ImageMagick を使っていた私のような人向けの注意点として, コマンドは `convert` ではなく, `magick convert` とする必要があります.

# PowerShell
PowerShell でファイル名を得るためには, `dir -Name` を使います.

そして `dir -Name` の出力を ImageMagick に渡すには, 次のようにします.

```
> dir -Name * | % {magick convert "$_" "$_.png"}
```

`$_` にファイル名が入っているので, そこに ".png" を付けたファイルに変換後の画像を保存しています (この構文の細かい意味は理解していません).

この内容をバッチファイルにして実行するには, 例えば "myconvert.ps1" というファイルに保存して, 以下のように実行すれば OK です (あまり楽にはなっていない気がしますが).

```
> PowerShell -ExecutionPolicy RemoteSigned .\myconvert.ps1
```
# 補足
拡張子の付いているファイル名を別の拡張子のファイル名に変換したい (例えば foo.jpg を foo.png に変換したい) 場合にどうするか? も調べたのですが, ややこしくてあきらめました. どうしてもそれをやりたい場合は (私にとっては) [Git for Windows](https://gitforwindows.org/) の Bash を使うのが近道のような気がしますが, 今回はそこまでは試してません.

# 参考
- [ImageMagick – Mastering Digital Image Alchemy](https://imagemagick.org/index.php)
- [ImageMagick のインストール（Win10）convert.exeがない？](https://naotoshisami.com/2021/12/imagemagick-install-win10/)
- [PowerShell 使い方メモ](https://qiita.com/opengl-8080/items/bb0f5e4f1c7ce045cc57)
- [PowerShellでファイル名だけ、拡張子だけ、拡張子を除いたフルパスなど取得するコード色々](https://hollage.net/archives/136)
- [PowerShellでスクリプトファイルを普通に実行したい](https://monomonotech.jp/kurage/memo/m230112_powershell_scriptfile_exe.html)
Amplify functionでLayerのバージョンを上げようとしたらハマった話

## はじめに
私が携わっているプロジェクトでは、AWS Amplifyを活用し、ランタイムがPython 3.8のLambda functionとLayerを使用しています。
Python 3.8のサポート終了が近いため、問題を未然に防ぐためにPython 3.12へのアップグレードを決意しました。
詳細はAWSの公式ドキュメントを参照してください。
 [Lambda ランタイム](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html)
 
## 環境
- Amplify: 12.11.1
- Python: 3.12.2
- Pipenv: 2023.12.1

## 遭遇した問題
バージョンアップの過程で、以下のファイル内のruntimesやpython_versionを3.12に更新しました。
- amplify/backend/function/laynerName/parameters.json
- amplify/backend/function/laynerName/lib/python/Pipfile

ところが、上記の修正後にビルドをしても
` amplify/backend/function/laynerName/lib/python/lib/ `の配下に` python3.12/site-packages/ `が生成されず、代わりに以前のバージョンである、` python3.8/site-packages/ `が生成されてしまいます。
結果として、デプロイは成功しましたが、ランタイムがPython 3.12に更新されたfunctionからはLayerのライブラリを認識できませんでした。

## 問題解決の試み
Amplify CLIの` amplify-python-function-runtime-provider `のpackageUtils.ts中の` pythonPackage() `を調査したところ、` getPythonBinaryName() `で取得したPythonコマンドのバージョンに基づいてディレクトリが作成されていることがわかりました。
また、` getPythonBinaryName() `はpythonとpython3が実行可能な場合、python3を優先して選択します。

```typescript
export async function pythonPackage(context: any, params: PackageRequest): Promise<PackageResult> {
  if (!params.lastPackageTimeStamp || params.lastBuildTimeStamp > params.lastPackageTimeStamp || params.currentHash) {
    const packageHash = await context.amplify.hashDir(params.srcRoot, ['dist']);
    const zipEntries: ZipEntry[] = [];
    if (params.service) {
      const pyBinary = getPythonBinaryName();
      const pyVersion = await execWithOutputAsString(`${pyBinary} --version`);
      const layerPythonPath = path.join(params.srcRoot, 'lib', 'python' + majMinPyVersion(pyVersion), 'site-packages');
      const pipEnvDir = await getPipenvDir(params.srcRoot);
      // copy from virtualenv to layer path to maintain layer required structure
      fs.copySync(pipEnvDir, layerPythonPath, { overwrite: true });
```

https://github.com/aws-amplify/amplify-cli/blob/dev/packages/amplify-python-function-runtime-provider/src/util/packageUtils.ts
https://github.com/aws-amplify/amplify-cli/blob/dev/packages/amplify-python-function-runtime-provider/src/util/pyUtils.ts

これは完全に私の落ち度なのですが、Python 3.12をインストールした後、` python -V `は3.12を指すことは確認していたものの、` python3 `のバージョンチェックを怠っていたため、古いバージョンを指していました。

## 解決策
` python3 `を正しくpython3.12を指すように修正したところ、無事期待する形でデプロイができました。
` python3 `が意図したバージョンを指しているか確認しましょう。

ところで、
Pipfileの` python_version `を参照してsite-packagesディレクトリを作ればいいような気がしますが、なにか理由があるのでしょうか。
また、ランタイムに複数のPythonバージョンを指定した場合などこれを起因とする問題が発生しそうですが、これについてはまだ検証していません。
＜Microsoft Copilot Studio＞トピックを使用してチャットボットの動作を設計してみた

## はじめに

前回Microsoft Copilot Studioを使ってカスタムコパイロット（チャットボット）を
作成しました。

https://qiita.com/Odin/items/0afc741492cea6e90b05

今回はそれにアドオンし
トピックを使用してチャットボットの動作に分岐を作ってみます。

## 作ったもの

今回作ったものは人事規定について質問すると回答してくれるチャットボットです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566513/27fd785f-6442-fcdd-71eb-361b422afa7e.png)

何について聞きたいかジャンルを選ぶと、それに相対する答えを返します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566513/2bd5cab3-082d-d2c1-1e06-ed93588dca41.png)

期待する答えが見つからない場合、プロンプトを入力し生成AIが回答する
メニューを用意して、そこから探して貰います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566513/a6be71d0-0a25-bca5-f88f-9aa3b5923bbf.png)

※「交通費精算について」という部分は私のプロンプト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566513/49180aaa-e821-4b5a-16ed-baf997c02709.png)

## やってみた

- トピックの作成

　「トピック」メニューから「＋作成」⇒「トピック」⇒「最初から」を選びと
 　トピック作成画面が表示される。最初は以下のような画面がでる。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566513/8cb17dc3-9cff-467c-ed91-082b786dfedc.png)

- トピックフレーズの作成

　トピックを起動させるために必要なフレーズを決めます
 　「編集」からフレーズの追加メニューを呼び出し、適当なフレーズを決めます

  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566513/fee9fd7e-e097-5dc2-6b74-a6e334413e60.png)

- 選択肢の作成

　＋（ノードの追加）から「質問する」を選ぶと新しいトピックが追加されます
　以下では質問文「こんにちは、～」と選択肢（「ユーザのオプション」）を編集
 　してます。質問文はそのままテキスト入力するだけでOK
　選択肢は「＋新しいオプション」から追加できます。
 　（「総則」「出向」などの部分）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566513/5702b0bc-8843-882a-e2a9-4173be7d09cd.png)

- 選択肢を選んだ後の動作

　選択肢を選んだ後の動作を規定します。
 　聞いた結果に対する応答を決めています。
  　「メッセージを送信する」で応答するメッセージを規定しています。
  
　さらに今回は聞いた後に「必要な質問は得られましたか？」という質問を追加し
   　「はい」であれば、会話終了。
  　「いいえ」であればチャットボットの会話の冒頭に戻り
   　また質問可能な設計としました。
    　（図は割愛）
     
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566513/211629bb-a15c-e78f-d874-f3140542ff81.png)

　おおまかな流れとしては以上です。
　右上のメニュー「保存」することを忘れないように。

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566513/5bf63f2d-23dd-0e17-b230-0854d7170502.png)

　「トピックチェッカー」で作成したトピックでのエラーがないことの確認ができます。
 　エラーがある場合、チャットボットが稼働しないので注意。

  　「コパイロットのテスト」で動作確認をすることが可能です。
   　エラーがなければ保存してCopilot Studio上のプレビュー画面からも
    　動作確認出来るので、その場合はどちらでも大丈夫です。


## まとめ

　今回の記事ではトピックの作成について基本的な動作をまとめました。
 　単純な分岐条件でも、一般的なチャットボットの動作をさせることは
  　出来そうです。
  
 　もちろん他のメニューを使うことで色々な条件をつくり、要件に応じた
  　動作をさせることも可能ですので、色々と試して貰えればと思います。
[Linux]覚えておくと便利なシェルのショートカット

Linuxの勉強中、個人的によく使うショートカットキーを備忘録としてまとめました。
※cmdでは使えないものがほとんどです。予めご承知おきください。

## カーソル移動
| 入力 | 動作 |
|:-:|:-:|
|ctrl + A| 行頭に移動 |
|ctrl + E| 行末に移動 |
|esc押下後 F|1単語次へ移動|
|esc押下後 B|1単語前へ移動|

行頭と行末に移動できることを初めて知ったときは感動しました。
（何も知らない頃は矢印キーをポチポチ連打してました:cry:）



## カーソル位置からの文字列編集
| 入力 | 動作 |
|:-:|:-:|
|ctrl + W| 直前の空白まで削除 |
|ctrl + U| 行頭まで削除 |
|ctrl + K|行末まで削除|
|ctrl + Y|上記のショートカットで削除した文字列を挿入|

「ctrl + Y」はWindowsでいう「ctrl + Z」のようなものです。便利。



## その他
| 入力 | 動作 |
|:-:|:-:|
|tab|入力補完|
|ctrl + C| 実行中のコマンドを強制終了 |
|ctrl + L| 画面のクリア |
|ctrl + S|ロック（入力を受け付けない）|
|ctrl + Q|ロックの解除|

長いファイル名やディレクトリ内にあるファイルの候補を補完してくれるので、tabは特に使う機会が多いです。

## まとめ
ここまで読んでくださりありがとうございました。

今回の内容に限らず便利なショートカットは使えば使うほど身に付き、作業効率を上げてくれるツールだと思います。
普段から意識的に使ってクセを付けておこうと思いました。
Prisma + Nuxt でseedを使えるようにする

# はじめに
この記事は、Prismaの公式を参考にseedをつかえるようにした時のエラーメモです。
使っているソースコードと手順は[こちら](https://www.prisma.io/docs/orm/prisma-migrate/workflows/seeding#seeding-your-database-with-typescript-or-javascript)の通り。

# 環境
- Node.js: 18.17
- Nuxt: 3.11.2
- Prisma: 5.12.1
- ts-node: 10.9.2

# エラー内容
## typescript error - cannot find name 'process'
seed.tsの`process.exit(1)`でエラーがでました。
調べたところ`tsconfig.json`に以下の文を追加するとエラーが消えるみたいです。
typesを設定するとリストに列挙したパッケージのみがインクルードされます。
今回の場合は`./node_modules/@types/node`のみコンパイル対象。
```tsconfig.json
{
  // other settings...
  "compilerOptions": {
    "types": ["node"]
  },
}
```

## TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"
ts-nodeでTypeScriptのコードを実行しようとしたときこのようなエラーが出た。
解決策はtsconfig.jsonに次の文を追加する。以下[Node.jsの公式引用](https://nodejs.org/dist/latest-v18.x/docs/api/esm.html#customizing-esm-specifier-resolution-algorithm)
拡張子の自動解決とインデックス ファイルを含むディレクトリからのインポートを有効にするには、nodeを指定する必要があるみたいです。
> "The --experimental-specifier-resolution=[mode] flag can be used to customize the extension resolution algorithm. The default mode is explicit, which requires the full path to a module be provided to the loader. To enable the automatic extension resolution and importing from directories that include an index file use the node mode.

```tsconfig.json
{
  // other settings...
  "ts-node": {
    "esm": true,
    "experimentalSpecifierResolution": "node"
  }
}
```

# 参考
1. [Prisma公式](https://www.prisma.io/docs/orm/prisma-migrate/workflows/seeding#seeding-your-database-with-typescript-or-javascript)
1. [Node.js公式](https://nodejs.org/dist/latest-v18.x/docs/api/esm.html#customizing-esm-specifier-resolution-algorithm)
AnsibleでAWS S3にファイルを登録してみる

# AnsibleでAWS S3にファイルを登録してみる

★ この記事は3年前に執筆し、投稿し忘れていたものを投稿したものです

## 背景

お仕事でローカルファイルをAWS S3にアップロードする要件がありました。
AWS CLIでは何度もやってますが、今回はAnsibleから行うのが要件の一つにありましたので試してみることにします。

## 参考

・[Amazon AWS Collection](https://galaxy.ansible.com/amazon/aws?extIdCarryOver=true&sc_cid=701f2000001OH7YAAW)
・[amazon.aws.aws_s3 – manage objects in S3.](https://docs.ansible.com/ansible/latest/collections/amazon/aws/aws_s3_module.html)

## どうやればできる？

調べてみると、Ansibleには「amazon.aws」モジュールが存在していました。
こちらのモジュールを使えばAWSの各サービスにアクセス可能のようです。
今回はS3への登録が目的なので、「aws_s3」モジュールを使ってみます。
また、使用に際してBoto3も必要なのでインストールします。
なお、今回は事前にaws configureを実行し、ansible実行環境でaws cliが利用可能な準備が整っていることを前提とします。

## 検証ファイル構成

```
.
├── inventory
├── playbook.yml
├── readme.md
└── work
    └── sample.tgz
```

## インベントリファイル

今回はお試しなのでlocalhost、自サーバをターゲットとします。

./inventory

```
xxx.xxx.xxx.xxx
```

## プレイブック

動作確認もかねて、ｐｉｎｇモジュールを最初に実行したあと、aws_s3モジュールを実行します。

./playbook.yml

```
- hosts: all
  tasks:

  - name: ping
    ping:
    register: result

  - name: Simple PUT operation
    amazon.aws.aws_s3:
      bucket: xxxxxxxxxx
      object: /aaa/sample-s3.txt
      src: /home/xxxxx/job/ansible/aws-s3/work/sample.txt
      mode: put
```

## モジュールのインストール

実行に必要な「amazon.aws」モジュールをインストールします。

```
$ ansible-galaxy collection install amazon.aws
Process install dependency map
Starting collection install process
Installing 'amazon.aws:1.5.0' to '/home/xxxxx/.ansible/collections/ansible_collections/amazon/aws'
```

続いて、aws cli、botoをインストールします。

```
$ sudo apt install awscli
$ sudo apt install python-pip
$ sudo pip install boto boto3
```

## aws接続初期設定

```
$ aws configure
AWS Access Key ID [None]: xxxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxx
Default region name [None]: us-west-2
Default output format [None]: json
```

動作確認としてS3バケットの一覧を取得してみます

```
$ aws s3 ls
```

正常にバケット一覧が取得できたので実際にansibleを動かします。

```
$ ansible-playbook --ask-pass -i inventory playbook.yml
```

マネジメントコンソールにログインし、指定したバケットにファイルが登録されていることが確認できました。

## おわりに
今回はplaybookの中にアクセスキーやシークレットアクセスキーを記述するのが嫌だったので、予めaws configureを実行しておく方法を取りましたが、playbookの中に記述することも可能です。

```
  - name: Simple PUT operation
    amazon.aws.aws_s3:
      aws_access_key: xxxxxxxxxx
      aws_secret_key: xxxxxxxxxx
      region: us-west-2
      bucket: xxxxxxxxxx
      object: /aaa/sample-s3.txt
      src: /home/xxxxx/job/ansible/aws-s3/work/sample.txt
      mode: put
```

また、予めs3のバケットとフォルダは作成しておく必要がありますので、今回は既存のS3を使用しました。
ちなみに、バケットがあってもフォルダがなければ処理は正常に終わるがputされていませんでした。

前に検証したarchiveモジュールと組み合わせ、ローカルのファイルを圧縮して、そのファイルをS3に保存するという流れもできそうです。

お試しでAWSを触るならマネジメントコンソールにログインしGUI操作がわかりやすくて良いですが、これからIaCやCI/CDを学ぶなら、GUI操作ばかりでなく、こういったAnsibleで構築するもの良いと思います。
ただ、playbookに指定するパラメータはGUIで予め確認しておくと理解も深まると思います。
ansibleで圧縮ファイルを作成する

# ansibleで圧縮ファイルを作成する

★ この記事は3年前に執筆し、投稿し忘れていたものを投稿したものです

## 背景

お仕事で、Ansibleでtar.gzファイルを作成する必要がありました。
実際の作業は私自身ではないのですが、会話に参加できるよう、自己啓発を兼ねて試してみました。

## 参考
・[community.general.archive – Creates a compressed archive of one or more files or trees](https://docs.ansible.com/ansible/latest/collections/community/general/archive_module.html)
・[Community General Collection - Ansible Galaxy](https://galaxy.ansible.com/community/general)

## どうすればできる？

調べてみると、Ansibleには「community.general.archive」があるようで、こちらを使用すれば簡単に圧縮ファイルが作成できるようです。
ただ、このモジュールは最初からインストールはされていないようで、あとから「comunity.general」をインストールする必要があることがわかりました。

## 検証ファイル構成

```
.
├── inventory
├── playbook.yml
├── readme.md
├── work
│   ├── a.txt
│   └── b.txt
```

## インベントリファイル

今回はお試しなのでlocalhost、自サーバをターゲットとします。

./inventory

```
xxx.xxx.xxx.xxx
```

## プレイブック

動作確認もかねて、ｐｉｎｇモジュールを最初に実行したあと、Archiveモジュールを実行します。

./playbook.yml

```
- hosts: all
  tasks:

  - name: ping
    ping:
    register: result

  - name: archive
    community.general.archive:
      path: /home/xxxxx/job/ansible/archive/work
      dest: /home/xxxxx/job/ansible/archive/work.tgz
```

## 手順

* archiveモジュールを利用するために、community.generalをインストール

```
$ ansible-galaxy collection install community.general
Process install dependency map
Starting collection install process
Installing 'community.general:3.5.0' to '/home/xxxxx/.ansible/collections/ansible_collections/community/general'
```

* tgzファイルの作成をテスト

```
$ ansible-playbook --ask-pass -i inventory playbook.yml
SSH password:

PLAY [all] *************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
[DEPRECATION WARNING]: Distribution Ubuntu 18.04 on host xxx.xxx.xxx.xxx should use /usr/bin/python3, but is using
/usr/bin/python for backward compatibility with prior Ansible releases. A future Ansible release will default to using
the discovered platform python for this host. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information. This feature
 will be removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in
ansible.cfg.
ok: [xxx.xxx.xxx.xxx]

TASK [ping] ************************************************************************************************************
ok: [xxx.xxx.xxx.xxx]

TASK [archive] *********************************************************************************************************
changed: [xxx.xxx.xxx.xxx]

PLAY RECAP *************************************************************************************************************
xxx.xxx.xxx.xxx              : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

## おわりに

Ansibleをインストールしただけでは実現できないようなことも、追加モジュールをインストールすることでいろいろなことができることがわかりました。
ガッツリしたAnsibleを記述したことはありませんが、こういう小さなモジュールを組み合わせることでガッツリした処理も書けるようになると思います。
「小さなことからコツコツと。」
名言だと思います。

実はこの検証には続きがあり、この検証ができたからこそ次の検証に繋がりました。
まさに「小さなことからコツコツと。」をつなぎ合わせることになりました。
Ubuntu22.04にsupervisorをインストールしてLaravelプロジェクトのワーカーを作る

`php artisan queue:work`をsupervisorにやってもらう

## 環境

- さくらVPS
- Ubuntu(22.04)
- nginx(1.26.0)
- php(8.3.6)
- Laravel(11.1.0)

## 手順

supervisor をインストール

```リモート
sudo apt install supervisor -y
```

確認

```リモート
supervisord -v
4.2.1 # バージョン4.2.1がインストールされた
```

supervisor の自動起動を有効化

```リモート
sudo systemctl enable supervisor
```

プロジェクト用のワーカーファイルを作成

```リモート
sudo vi /etc/supervisor/conf.d/artisan-queue.conf
```

```/etc/supervisor/conf.d/artisan-queue.conf
[program:artisan-queue]
directory=/path/to/your/laravel/project
process_name=%(program_name)s_%(process_num)02d
command=php artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=nginx
numprocs=1
redirect_stderr=true
stdout_logfile=/path/to/your/laravel/project/storage/logs/queue/console.log
stderr_logfile=/path/to/your/laravel/project/logs/queue/error.log
startsecs=0
stdout_logfile_maxbytes=0
stderr_logfile_maxbytes=0
stdout_logfile_backups=0
stderr_logfile_backups=0
```

ログを保存するためのディレクトリを作る

```リモート
mkdir /path/to/your/laravel/project/storage/logs/queue
```

作成した.confファイル を読み込む

```リモート
sudo supervisorctl reread
```

ワーカーを再起動

```リモート
sudo supervisorctl reload
```
SAPアプリへの認証IdPをメールアドレスを使って仕分けたい

お疲れ様です。

今回はLauncpad等のSAPアプリケーションへアクセス時に
複数のIdPがあった場合、選択画面が
正直、あまりいけていない...
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500270/c4e33554-1de7-4e1d-511d-34bea9575a47.png" width=80%>
なのでいい方法が無いか調査しましたのでその結果をお伝えします。

## 事前準備
1)SAP CISが構築済みであること

## 実装（メールドメインでの制御）
1)SAP CISへログイン
2)Application＆Resource＞Applicationsを押下
3)対象のアプリを押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500270/e5f75940-9a8d-23bf-b06d-4c32477ecb24.png" width=80%>
4)Trust＞Conditional Authenticationを押下
5)Conditional Authenticationを押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500270/b85246fc-3b56-873b-05fc-e22c6d8904e3.png" width=80%>
6)Default Authenticating Identity Provider＞Default Identity Providerを[Identity Authentication]を設定
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500270/17140c0b-d161-7a34-9903-f0f1ecfd62d8.png" width=80%>
7)Authentication Rules>Add Ruleを押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500270/3779e8b5-a296-dd15-1331-123f0aa43dde.png" width=80%>
8)Identity Providerを押下し、今回設定するIdPを選択
9)conditions below>Email Domainに制御したいメールドメインを設定
10)OKボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500270/2180354f-3bf5-138c-97e9-4b4e58ad6ee1.png)

## 最後に
今回はIdpが複数あった場合、登録しているメールアドレスのドメインで制御する方法を紹介しました。
まだまだ、わからない部分もありますが皆様にお伝えできればと思います。
Web業界者向け！業務が捗る拡張機能

[今回の記事はこちら](https://qiita.com/yamashee/items/389c44a033b61551274b)

前回に引き続き、私が愛用しているおすすめのChrome拡張機能を紹介します。今回はWeb業界者及び志望者向けのものを厳選しました。
## シミラーウェブ
サイトドメインのトラフィック情報を観ることができます。競合サイトの分析やSEO対策に役立ちます。
ただし、無料版の場合閲覧できる情報に制限があります。またアクセスが少なすぎるサイトの場合、適切に情報が表示されません。<br>
[シミラーウェブを入手](https://chromewebstore.google.com/detail/%E3%82%B7%E3%83%9F%E3%83%A9%E3%83%BC%E3%82%A6%E3%82%A7%E3%83%96-%E3%83%88%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%83%A9%E3%83%B3%E3%82%AF%E3%81%A8%E3%82%A6%E3%82%A7%E3%83%96%E3%82%B5%E3%82%A4%E3%83%88%E5%88%86/hoklmmgfnpapgjgcpechhaamimifchmp)

## Wappalyzer - Technology profiler
サイトに使われているフレームワークやサーバーやライブラリなどの技術（フレームワーク、サーバー、ライブラリ、CMSなど）を見ることができます。
他のサイトがどんな技術選定を行っているかの参考になります。<br>
[Wappalyzer - Technology profilerを入手](https://chromewebstore.google.com/detail/wappalyzer-technology-pro/gppongmhjkpfnbhagpmjfkannfbllamg)

## HTMLエラーチェッカー
文字通り、HTMLの構文エラーがないか、チェックできます。閉じタグの入れ忘れなどはこれで検出できます。<br>
[HTMLエラーチェッカーを入手](https://chromewebstore.google.com/detail/html%E3%82%A8%E3%83%A9%E3%83%BC%E3%83%81%E3%82%A7%E3%83%83%E3%82%AB%E3%83%BC/ohdllebchmmponnofchalfkegpjojcaf)

## Alt & Meta viewer
画像のalt属性と、ページのmeta情報（title、description、ogpなど）を取得できます。<br>
[Alt & Meta viewerを入手](https://chromewebstore.google.com/detail/alt-meta-viewer/jjcjblcbnjhgjlnclhficglfjedhpjhl)
## Pasty
複数のページを一括で開きたい...
そんな時に便利なのがこのPastyです。
クリップボードにコピーした複数のURLをブラウザで一気に開くことができます。<br>
[Pastyを入手](https://chromewebstore.google.com/detail/pasty/hdjihnnclpjhfdbbinmgoiehhoehhlgf)
## まとめ
いかがだったでしょうか？
拡張機能の流行り廃りは早く、入れていた拡張機能がいつのまにかサービス終了していたり、上位互換の拡張機能が出てたりします。
業務効率アップのために、定期的に拡張機能をチェックするのがおすすめです。
pythonでgifアニメを画像で切り分けて加工後元に戻す

:::note info
pythonでgifアニメを画像で切り分けて加工後gifに戻します
gifアニメの元画像をなくした時に再度編集したい時とかにご利用ください
:::

# ファイル構造
```
├── gifStep1.py
├── gifStep2.py
├── step1
│   └── input.gif
├── step2
│   ├── step1で出力されたinput.gifの分割画像
├── step3
│   ├── 加工後のpngファイル(gifでも可。その場合「gifStep2.py」のpngの部分をgifに変更する)
└── step4
    └── output.gif

```

# gitを保存する
分割したいgitをstep1のフォルダーに入れる。input.gifに名前を変更する
(プログラムのファイル名を修正してもよいです)

![aimkbiz.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/cd749571-c129-a8bd-fd1f-f07e6a0e611e.gif)

# gifを分割するプログラム
gifStep1.py

```
from pathlib import Path
from PIL import Image, ImageSequence

IMAGE_PATH = 'step1/input.gif'
DESTINATION = 'step2'
DEBUG_MODE = True

def main():
    frames = get_frames(IMAGE_PATH)
    write_frames(frames, IMAGE_PATH, DESTINATION)

# フレーム一覧を取得する
def get_frames(path):
    im = Image.open(path)
    return (frame.copy() for frame in ImageSequence.Iterator(im))

# フレーム毎に画像を保存する
def write_frames(frames, name_original, destination):
    path = Path(name_original)

    stem = path.stem
    extension = path.suffix

    dir_dest = Path(destination)
    if not dir_dest.is_dir():
        dir_dest.mkdir(0o700)
        if DEBUG_MODE:
            print('Destionation directory is created: "{}".'.format(destination))

    for i, f in enumerate(frames):
        name = '{}/{}-{}{}'.format(destination, stem, i + 1, extension)
        f.save(name)
        if DEBUG_MODE:
            print('A frame is saved as "{}".'.format(name))

if __name__ == '__main__':
    main()
```

# 実行
```
python3 gifStep1.py
```
分割した画像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/68320f7b-1ba6-b178-a3c7-e4958065bedd.png)


# 画像を加工
step2に分割された画像が保存されるので、加工した画像をstep3に入れる

# 画像をマージしてgitにするプログラム

```
from PIL import Image
import os

list_file_name = []
list_images = []
dir = 'step3/'
for file_name in os.listdir(dir):
    if file_name.endswith('png'):
        list_file_name.append(dir + file_name)

list_file_name.sort()
ratio = 0.25
for i in list_file_name:
    img = Image.open(i)
    list_images.append(img)
list_images[0].save('step4/output.gif',save_all=True, append_images=list_images[1:],
optimize=True, duration=200, loop=0)
```

# 実行する
今回は背景だけ透過した画像をgifにしました
```
python3 gifStep2.py
```
M1 Macでscrapy shellでfetchしたらMemory Error

タイトルの通り、Scrapyを使ってみようとしたら、こんなエラーが出た

```shell

In [1]: fetch('https://qiita.com/')
2024-05-01 16:50:02 [scrapy.core.engine] INFO: Spider opened
---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)
Cell In[1], line 1
----> 1 fetch('https://qiita.com/')

File /opt/anaconda3/envs/scrapy_env/lib/python3.8/site-packages/scrapy/shell.py:110, in Shell.fetch(self, request_or_url, spider, redirect, **kwargs)
    108 response = None
    109 try:
--> 110     response, spider = threads.blockingCallFromThread(
    111         reactor, self._schedule, request, spider)
    112 except IgnoreRequest:
    113     pass

File /opt/anaconda3/envs/scrapy_env/lib/python3.8/site-packages/twisted/internet/threads.py:120, in blockingCallFromThread(reactor, f, *a, **kw)
    118 result = queue.get()
    119 if isinstance(result, failure.Failure):
--> 120     result.raiseException()
    121 return result

File /opt/anaconda3/envs/scrapy_env/lib/python3.8/site-packages/twisted/python/failure.py:504, in Failure.raiseException(self)
    499 def raiseException(self) -> NoReturn:
    500     """
    501     raise the original exception, preserving traceback
    502     information if available.
    503     """
--> 504     raise self.value.with_traceback(self.tb)

MemoryError: Cannot allocate write+execute memory for ffi.callback(). You might be running on a system that prevents this. For more information, see https://cffi.readthedocs.io/en/latest/using.html#callbacks

```

M1 Macで起こるらしい、cffiのせいらしい

下記で解決
```shell
$ conda uninstall --force cffi
$ conda install cffi
```

参照URL
https://stackoverflow.com/questions/67556847/scrapy-on-m1-mac-memoryerror-cannot-allocate-writeexecute-memory-for-ffi-call
OpsRamp - アラート通知内容のカスタマイズ方法

本記事では、OpsRampのアラートメール通知内容のカスタマイズ方法について説明します。

# 概要
OpsRampでは、アラートを検知した際に、メールで通知する機能があります。(Alert Escalation)
このメールの内容をカスタマイズすることが可能です。

# 設定方法
アラート通知内容は、Setup > 通知 > アラート からカスタマイズすることができます。
![alert-template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/4e5d645e-7bf7-fe90-68f7-419846acd5d9.png)

メールの件名および内容をカスタマイズでき、トークンから環境にあった変数を使用することができます。
また、#if \/ #elseif \/ #else \/ #end を使用することができ、条件分岐を指定することが可能です。


---------------------------------------
[<img width = 250 height = 200 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/111de30a-4d33-aa33-5c7d-83d9015093e6.png">](https://www.vistanet.jp/knowledge-base/)
HoloLens 2でWebXR（8thwall）がEdgeからうまく起動できない時

# HoloLens 2のOpenXRのバージョン次第でうまく動作しないことがある(2024/04/30時点)

先日HoloLens 2で8thwallが動く話を記事にしました。

https://qiita.com/miyaura/items/02000ef65245d67c2663

この話をみた海外のエンジニアの人が同じように8thwallでやっていたようなのですが、うまく動かずに色々情報交換しながらやり取りをしていました。結果どうもHoloLens 2のOpenXRランタイムに問題があり、動かないパターンがあるようです。現在はMicrosoftには同様の症状が複数報告されているようで調査は行われているようです。

## 何が起きているのか

端的にいうとHoloLens 2の最新のOpenXR Runtime（といってもPreview版）では8thwall(WebXR)がうまく動きません。EdgeブラウザからWebXRのURLを入力してもARモードで起動しない状況に陥ります。この件に関するQAは以下に公開されています。

https://learn.microsoft.com/en-us/answers/questions/1657735/webxr-enter-ar-not-working-on-edge-on-hololens-2&wt.mc_id=WDIT-MVP-5003104

HoloLens用のOpenXR ランタイムについては通常版とPreview版が提供されています。今回問題になっているのはPreview版のOpenXRランタイムです。こちらのバージョンが入ってるHoloLens 2ではEdgeから8thwall(WebXR)のアプリを起動しても動作しません。

* 【動作しない】Preview版で提供されているOpenXRのバージョン 113.2403.5001  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/124e320c-eb8f-e1b0-b991-275d2c8002b2.png)
* 【動作する】OpenXRの安定した最新バージョン 112.2309.20006.1  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/308bb8e9-a8c3-181f-9def-bca969befff9.png)

少し厄介なのが、HoloLens 2のPreview版の利用を選択していないにも関わらずOpenXRのランタイムバージョンがPreview版にアップデートされ、動作しなくなるという状況が起きているようです。
ディスカッションしていたエンジニアとのやり取りでは、「Windows Holographic バージョン 23H2 - 2024 年 4 月の更新プログラム - ビルド 22621.1272」に影響を受けているように見えるとのこと（ただし、修正内容にOpenXR系のものはない）。

なお、現状ではOpenXRのバージョンを挙げてしまうとバージョンをもとに戻す手段がファクトリーリセットしかないようです。このため、OpenXR ランタイムバージョンが113系になっており、WebXRが起動しない不具合を修正したい場合は現状ではファクトリーリセットを行う必要があります。

## 対応方法（現状の暫定対応）
おそらく今後正式な対応方法が提供されると思いますが、現状この問題に対応する手段としては、次の手順でファクトリーリセットかけると動くようになったそうです。

1. Advanced Recovery Companionを使ってダウンロードしたv22621.1266でHoloLens 2をリセットする
2. その後最新のWindows Updateを実施する
3. OpenXRのRuntimeは更新しない<BR>→この状態でHoloLens用のOpenXRのランタイムバージョンが**112.2309.20006.1**になっていることを確認

:::note info
使用するROMバージョンはv22621.1272以外のものを当てる必要があります。
Advanced Recovery Companionで最新のバージョンv22621.1272で復元するとOpenXR ランタイムバージョンが113系になるようです。
:::
(java silver)オーバーライド

## JavaSilverでメモしたところ備忘録として残しておこうと思います。

# オーバーライド

* クラスを継承する際にスパークラスのメソッドをサブクラスで定義しなおすこと
* オーバーライドする際はシグニチャ(メソッド名・メソッドの引数の数・引数の順番)は同じにする必要がある

### 使用するメリット
* スーパークラスのメソッドを再利用することができ、記述量が減ること。変更がある際にも変更点が少なくなる

## オーバーライドとの違い
* オーバーロードは同じメソッド名で、引数の数・引数の順番が違うメソッドを定義すること

## super句

* super句を使うことでスパークラスのメソッドを使うことも可能

```java
// スーパークラス
class SuperClass {
    int num1;
    int num2;
 
    public SuperClass(int num1, int num2){
        this.num1 = num1;
        this.num2 = num2;
    }
 
    public void method(){
        System.out.println("num1 + num2 = " + (num1 + num2));
    }
}
// サブクラス
class SubClass extends SuperClass{
    public ClassSub(int num1, int num2) {
        super(num1, num2);//SuperClassのコンストラクタを呼び出す
    }
 
    @Override
    public void method(){// SuperClassのmethod()をオーバーライドし処理を変更
        System.out.println("num1 * num2 = " + (num1 * num2)); 
        super.method(); // スーパークラスと同じ処理
    }
}
 
public class Main {
 
    public static void main(String[] args) {
        SubClass s = new SubClass(3, 5);//SubClassのコンストラクタを呼び出す
        s.method();
    }
 
}
```
## Override (アノテーション)
* アノテーションはオーバーライドを宣言するときに使用する
* 記述しなくてもいいが記述した際はメソッドがオーバーライドしていないとコンパイルエラーが発生する


### オーバーライドできない
* staticメソッド
* final修飾子が付与されているメソッド
* throwsはスーパーメソッドのthrowsで指定した例外クラス以外
`サブクラスは除外`
`スーパークラスのメソッドにthrowsがあっても、サブクラス側でthrowsを記述しないことは可能`
::::

### privateなメソッドのオーバーライド
サブクラス側からprivateなメソッドは参照できないようになっているので単に別のメソッドとして解釈してコンパイルエラーも起こらない
仕事もプライベートも捗る！神Chrome拡張機能3選

私が仕事でもプライベートでも特に愛用しているChrome拡張機能を紹介します。
## Voice In
個人的にオススメな拡張機能です。
PCで気軽に音声入力ができる拡張機能です。なぜか私の周りではあまり使用している人がいませんが、近年の音声認識の進化には目を見張るものがあります。プログラミングコードを音声認識で入力するのは難しいですが、普通の文章であればキーボードでタイピングするより全然早いです。
何ならこの記事も音声認識で書いています。
音声認識のデメリットとして、周りに人がいる環境だと独り言をボソボソ言ってる感じになるのでちょっぴり恥ずかしいこと、また、周りにいる人の声を拾って認識してしまうことがあります。
在宅勤務が多い方の場合、そこら辺を気にしなくていいのでおすすめです！<br>
[Voice Inを入手](https://chromewebstore.google.com/detail/voice-in-speech-to-text-d/pjnefijmagpdjfhhkpljicbbpicelgko)
## Video Speed Controller
動画再生速度を簡単に変えられます。キーボード一つで1.1倍刻みでページスピードを変更できる。
本来再生速度を変更できないものでもこれを使えば変更できます。<br>
[Video Speed Controllerを入手](https://chromewebstore.google.com/detail/video-speed-controller/nffaoalbilbmmfgbnbgppjihopabppdk)
## Image Downloader
ページ内の画像を一覧表示し、ダウンロードできる優れものです。
画像保存されないよう対策されているサイトでも、この拡張機能があれば保存できます。
画像の著作権には注意しましょう。<br>
[Image Downloaderを入手](https://chromewebstore.google.com/detail/image-downloader/cnpniohnfphhjihaiiggeabnkjhpaldj)
## まとめ
次回はWeb業界者向けのChrome拡張機能を紹介予定です。
Stable Diffusion WebUI（Forege版）の日本語化

# はじめに
備忘録として、Stable Diffusion(SD)の日本語化のやり方を残しておく

# 環境
win 11
Stable Diffusion WebUI Forge

<a id="#Chapter2"></a>
# 日本語化の方法

SD WebUIを開いた後、右側になるExtensionsをクリック  
Avaliableのタブをクリック
localizationのクリックを外す
その後にLoad from:ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296388/9fdbe624-1932-6d81-da09-f96dff3dc024.png)

ja_JP Localization localizationを探して、installをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296388/3ba51e1e-c0c0-c251-4855-e32ef7a8cdd5.png)

Settingのタブをクリックして下線の無いUser interfaseをクリック。User interfaseが二つあるので注意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296388/8de76aed-5856-7a8d-e35b-babb50e084b0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296388/3f4807fd-1e5b-05ed-ed45-1ff14bf4ef9c.png)

Localizationをjp_JPに変更
(出てこない場合は、立ち上げなおす)
Apply Settingsをクリック
Reload UIをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296388/c6b1398e-5aed-7b65-fd4f-e80fe2102910.png)

表示が日本語になりました
更新で英語になった場合は、またjp_JPを選んでやり直せば日本語になります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296388/8f006097-c9d4-1875-ecff-101bd514d310.png)
初めてLT会に登壇したお話

### 注意事項
今回が初めて書く記事である。何かしら拙い部分があったり間違ったことが書かれているかもしれないので気を付けてくれ。

# まずなぜ参加しようと思ったのか
Twitter上で関係のある人から誘われたのがきっかけである。その誘いに乗って参加しようと思った。
このような技術について語る機会は今までなかったので少し迷ったが、
「せっかくやし参加しよ」
って感じの軽いノリで参加した。（軽すぎないですか）
# 登壇したLT会について
### 第1回広島ITイノベーションフェスタ
ひろぎんナレッジスクエアが運営しているプログラミング教室の中の人が主催したLT会である。

# 発表までの準備とか
どうでもいいかもだけど一応
### ～前日
発表スライドとかは前日に完成した。進捗の95%くらいは多分発表当日の2日前だと思う。
思ったよな…？遅い、遅すぎるって。多分真面目にLT参加してる人だったら舐めてるの？って思うかもしれないがこれが事実だ。こんな劇遅準備だったので発表時間の再設定できないんじゃないかって思って割とあきらめてた部分はある（もしかしたら言ったら調整してくれたかもしれないけど）。 ~~というかテーマ設定も結構遅かったなんで口が裂けても言えない。~~
### 当日
5時くらいに夜行バスで現地に到着し、早かったand全然眠れてなかったのでネカフェで仮眠and資料の細かい調整をした。その後は、少し観光して(?)現地にほぼ最速で到着した(主催者すら来てなくてやりすぎだわ)。
余裕をもって現地に到着するのは大事です()

実際に会場に来て、これ本当に発表できるのかってすごく不安だった。しかも私の前2人がレベル高すぎて私が霞んで見えるのではって直前に思ってたくらいである。

# 登壇して
### 発表本番
__「発表時間5分は足りない、10分にしとけ。」__

この一言に尽きる。私の要約力が終わっているだけかもしれないしテーマの問題なのか普通に足りない。めちゃくちゃ早口になってしまったし一部端折ってしまう部分もあった。
テーマは「現在制作中のアプリ」で内容として、
- 作っているプロダクツについて説明
- 使用しているUIフレームワークについて説明
- 通信の実装について(暗号化等も含めて)
- 今後の課題や苦しんでいる点
を挙げた。ただ発表後にUIフレームワークか通信の実装どちらかを省かない限りは5分以内に収まらないのではって思った ~~(発表前から懸念してたなんて言えない)~~ 。まあ準備不足感は否めないですよね()
でもなんだかんだ一応発表としての形…なのかはよくわからんけどそういうのは保ててたのでよかったと感じた。

### 発表後
すべての人の発表が終わってから交流会があった。雑談苦手な私はあまりほかの登壇者と話せないんじゃないかって心配していたが、意外と話を聞いたりある程度話に入り込めたりしたのでまあ話せたほうじゃないかなとは思う。
特定の思想(あえて言及はしない)を持った私含む集まりもできてて面白かった。
あとは何よりほかの登壇者に軽い質問をしたり話を聞いて刺激を受けることができたのは本当に良かったと思う。Twitterで話を聞くのとはまた違った感覚で本当に良い経験になったと思う。

# 結論
__これみた人は絶対に登壇するんだぞ！！！__
ガチで１回だけでいいからこのLT会じゃなくても全然いいので出てほしい。きっといい経験になるしたくさんの刺激を受けることもできる。
linuxでJarを実行する （kosekiメモNO1）

## JARファイル実行
```shell:linux: java -jar　①
java -jar ./xxxx.jar para01
```

## YML ＋ JARファイル実行
```shell:linux: java -jar　②
java -Dspring.config.additional-location=./application-local.yml -jar ./xxxx.jar para01
```

## server port + JARファイル実行
```shell:linux: java -jar　③
server_port=8081 java -Dspring.config.additional-location=./application-local.yml -jar ./xxxx.jar para01
```

## 複数JAR実行
```shell:linux: java -jar　④
java -Dspring.config.additional-location=./application-local.yml -jar ./xxx01.jar para01 & server_port=8081 java -Dspring.config.additional-location=./application-local.yml -jar ./xx02.jar para01
```
クリック可能な要素は div とかじゃなく、ちゃんと button とかにしよう

## 2024/5/1 (投稿日同日) 追記

本記事の関連記事に出てきて気付いたのですが、すでに同じような記事がありました。こちらでは、コードについてより詳しく扱っておられるようです。

https://qiita.com/sukoyakarizumu/items/978df93755c4720d5cdc

## 具体的には

たとえば、クリック可能な要素を用意したいとします。これは `div` タグでも実現可能です。

https://codesandbox.io/embed/xgmc68?view=split&module=%2Findex.html

でも、こういうのは `div` タグじゃなくて、ちゃんと `button` タグとかで書きましょう、という話です。

https://codesandbox.io/embed/4ywk5g?view=split&module=%2Findex.html

## div だと何がマズイ？

### アクセシビリティ

「アクセシビリティの配慮がなされている」を言い換えると、「環境 (デバイス) の違いや障がいの有無などに関わらず、誰でも利用しやすいように作られている」といったところ。

上の `<div>` のコードを例に考えてみます。本来「ボタンである」と示すべきところを、コード的には「特に意味を持たないコンテナ」となってしまいます。その結果、ボタンなのに**ボタンとして正確に認識されなくなり**･･･

- キーボードで当該要素を選択・決定できない
  - つまりキーボード操作が困難になる
- 自動読み上げをしたとき、ボタンがあると気づかれない

アクセシビリティについて、詳しくは MDN にあるのでこちらをどうぞ。(丸投げ)

https://developer.mozilla.org/ja/docs/Learn/Accessibility/HTML

### Vimium にて

アクセシビリティに関連して、[Vimium](https://vimium.github.io/) の例を挙げます。

Vimium はブラウザの拡張機能 (Chrome、Edge および Firefox 対応) で、ブラウザのあらゆる操作をキー操作可能にしてくれるものです。

その機能の一つに、ページ上のリンクなどを開けるというものがあります。`f` キーを押すと、ページ上にアルファベットが表示され、そのキーを打つことでリンクを開いたりオブジェクトを選択したりできる、というものです。

では、`<div>` のボタンと `<button>` のボタンを並べて試してみると？

![button-vs-div-preview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/2bb0b868-5794-c31d-ef0f-b538c46e4ef6.png)

この通り、`<div>` 要素はクリック可能として認識してくれませんでした。

適切なタグを使わないことが、障がい者どうこうだけの問題だけでなく、こういった形で影響を及ぼすこともあるわけです。

### コードの可読性

div は具体的な意味を持たないタグであるため、言ってしまえば**何にでも使えるタグ**ということになります。極端な話、全部 `<div>` タグ縛りで HTML を書くことも一応可能です。

ところで、HTML コードに `<button>` とあると、読んでいてどう感じるでしょう？「あ、ここはボタン、つまりクリック可能なんだ」となるはずです。

当然、意味を含まない `<div>` が並んでいるよりは、意味を含む `<input>` などが並んでいるコードの方が読みやすいわけです。何も考えず `<div>` を使うのは避け、むしろなるべく `<div>` が少なくなるように考えてコードを書いた方が良いでしょう。

## ちなみに - `input` vs `button`

`<input type=button>` でもできることは基本同じですが、CSS による装飾の観点で、`<button>` の方がよりモダンで好まれるようです。

> メモ: `<input>` 要素の `button` 型は完全に妥当な HTML ですが、より新しい `<button>` 要素が、ボタンの作成にはより好まれるようになりました。 `<button>` のラベル文字列は開始タグと終了タグの間に挿入され、ラベルに画像を含む HTML を含めることができます。

https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/button

## おわり

`<div>` を始めとした、具体的な意味を持たないタグを使う前に、**他に適切なタグが本当に無いか**をよく考えましょう。

例えば、文章の段落なら [`<p>` タグ](https://developer.mozilla.org/ja/docs/Web/HTML/Element/p)がより適切です。
【DB】【postgresql】index 確認、追加、削除（kosekiメモNO2）

## index確認
```sql:select
select indexname,indexdef from pg_indexes where schema.tablename = 'tablename'
```

## index追加
```sql:select
create index testix01 on schema.tablename(col01,col02,col03)
```

## index削除
```sql:select
drop index schema.testix01
```

:::note info
参照リンク
※postgresqlの「pg_indexes」 
https://www.postgresql.jp/docs/9.2/view-pg-indexes.html
:::