OmniAICreator/Qiita-1.07M huggingface dataset:
VSCodeのターミナルに黒いスクリーンが重なり、文字が見えない事象の解決策


## 事象
![スクリーンショット 2023-07-20 144620.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685576/13e5ce46-f79c-68c0-0502-a27a7ca705f1.png)
黒いスクリーンのようなものが表示され、ターミナルの文字が読めない。
インストール方法の変更、全ての拡張機能アンインストールを試すも効果なし。

## 解決策
~~ディスプレイ設定の拡大/縮小率を変更する。~~
~~PCのスタートメニュー⇒設定⇒システム⇒ディスプレイ⇒拡大縮小とレイアウト~~
GPUアクセラレーションを無効にする。
①コマンドパレットで「configure runtime arguments」を入力
②argv.jsonに「disable-hardware-acceleration": true」を追記して再起動。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685576/c7aa07fe-3ae5-eb23-eee7-8bc3a2f09f21.png)
~~私の場合、100%⇒125%にする事で黒いスクリーンが消失。~~
~~元の100%に戻しても黒いスクリーンは消失したまま。~~
~~原因は不明。~~
GPUアクセラレーション周りの不具合が多いらしい。
その1つと思われる。


ピンポイントでヒットする記事が無かったので共有。
Tips: TypeScriptのプロジェクトで使っていない`export`を見つけるのに`ts-prune`が便利だった

## これは何
TypeScriptのプロジェクトの開発を行っている時、どこからも参照されていない`export`を見つけるのに`ts-prune`が便利だったので記事にしました。

## ts-pruneとは
`ts-prune`とは、ゼロコンフィグでどこからも`import`されていない`export`を列挙してくれるライブラリです。

https://github.com/nadeesha/ts-prune

とりあえず使ってみるなら以下のコマンドをプロジェクト直下で実行すれば動きます。

```sh
$ npx ts-prune
```

基本的にゼロコンフィグで動かせるのがとても手軽で便利です。

## 使い方
`npx ts-prune`は各モジュール行単位で結果が出力されるので、`grep`を組み合わせ使うと色々な絞り込みができます。
よく用いているコマンドは以下の通りです

- 特定のパスの中から探す場合
    - `npx ts-prune | grep '/path/to/directory'`
- module内でのみ使っているファイルを探す場合
    - `npx ts-prune | grep '(used in module)'`
- exportされたモジュールのプレフィックスで探す場合
    - `npx ts-prune | grep ' - Prefix'`
【iRIC】ソルバーの計算条件で読み込むファイルを相対パスで指定する方法

# フルパスで指定すると色々面倒ですよね

例えば、iRICの[GELATO](https://i-ric.org/solvers/utt/)や[NaysDw2](https://i-ric.org/solvers/naysdw2/)のように、他のソルバーで計算した結果を読み込んで使用するソルバーでは、計算条件で結果を読み込むCGNSファイルのパスを指定する必要があります。
計算条件ダイアログのボタンを押して現れるダイアログからCGNSファイルを選択すると下図の用にCGNSファイルのフルパスが入力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2626673/929ec229-c748-2289-7ed7-75d4d3194c58.png)

なので、例えば以下のようなフォルダ構造の時に、`Project`フォルダを`hoge`から`hogehoge`に移動させると`Case1.cgn`のフルパスが`C:\hoge\Project\FlowProject\Case1.cgn`から`C:\hogehoge\Project\FlowProject\Case1.cgn`に変わってしまうので、計算条件でパスを指定し直さないと計算できません。
プロジェクト一式を他の人に送るときとかもいちいち指定し直してもらうのは不便ですよね。

```
c:
├─hoge
│  └─Project
│      ├─FlowProject
│      │    └─Case1.cgn   \\GELATO_Projectで読み込みたい流れの計算結果
│      └─GELATO_Project
└─hogehoge

↓↓Projectフォルダを移動↓↓

c:
├─hoge
└─hogehoge
   └─Project
       ├─FlowProject
       │    └─Case1.cgn
       └─GELATO_Project
```

# 実は相対パスでも指定できる

本題ですが、読み込む側のソルバーのプロジェクトを`*.ipro`形式ではなく`名前をつけてプロジェクトに保存...`でプロジェクトフォルダとして保存すれば、相対パスでCGNS等のファイルを指定することができます。(`*.ipro`形式の場合フルパスのみです)

iRICではプロジェクトのフォルダがソルバー実行時のカレントディレクトリになるので、プロジェクトフォルダからの相対パスをしていすればよいです。

## 相対パスの指定例
例えば以下のようなフォルダ構造で`Case1.cgn`を読み込みたい場合は`..\FlowProject\Case1.cgn`とパスを指定してあげます。

::: note
`.\`がカレントディレクトリ、`..\`がカレントディレクトリの1つ上のディレクトリを意味します。
:::


```
c:
├─hoge
│  └─Project
│      ├─FlowProject
│      │    └─Case1.cgn    \\GELATO_Projectで読み込みたい流れの計算結果
│      └─GELATO_Project    \\カレントディレクトリがここ
└─hogehoge
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2626673/d7df7451-d2c5-dc70-7eb4-f8c644c5890c.png)



このように設定しておけば`Project`フォルダごと場所を移しても、他人に渡しても読み込みたいファイルとプロジェクトの相対的な関係が変わらないのでいちいち指定し直す手間が省けます。
Bing Chat Enterpriseを使うためにすること

Microsoft Inspireで発表された **Bing Chat Enterprise** が利用できるようになりました。

https://www.microsoft.com/ja-jp/edge/bing/chat-enterprise


すぐに利用することが出来、設定方法も非常に簡単です。

https://learn.microsoft.com/ja-jp/bing-chat-enterprise/manage


## 対象者

> Bing Chat Enterprise is on by default for customers licensed for Microsoft 365 E5, E3, Business Premium, and Business Standard in mid-August 2023.

となっており、M365 E5, E3, Business Premium, Business Standard があれば利用できるようです。


## 有効化方法

https://aka.ms/TurnOnBCE

1. M365の管理者が上記にアクセスします。
2. 以下のような画面が表示されるので、規約を確認の上チェックを付けて "Turn On" を選択して「Confirm」をクリックします。
![bing chat01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61189/d331f3e6-4e1c-acd3-eb06-f9c578220be3.png)
1. クリックすると以下のような画面に切り替わり手続き終了です。
![bing chat02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61189/a0a540b0-37c4-9a82-25bf-a20fa0b87aa1.png)

> This change may take 2-4 hours to go into effect.

とあるので、変更をしたら2-4時間待ちましょう。

![bing chat03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61189/4edb3b9a-22a7-7c8c-a841-9200ae22d13a.png)

Microsoft Edge から [Bing Chat](https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx&sydconv=1) にアクセスして上記のような表示になれば成功です。

## まとめ

非常に簡単な手順でBing Chat Enterpriseを有効にすることが出来ました。

現時点では該当ライセンスを持っているユーザーのみですが、将来的にはユーザー1人当たり月額5ドルでBing Chat Enterpriseだけ単体で使えるようにもなるそうです。
Debian 12にOpenJDK 17をインストール（Azul Zulu Builds of OpenJDK）

# はじめに

Azul Zulu Builds of OpenJDKを利用してDebian12にOpenJDK17をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Azul Platform Core](https://docs.azul.com/core/zulu-openjdk/install/debian#install-from-azul-apt-repository)

## サポート

有償版のみサポート期間が明記されている。[Azul Support Roadmap \- Azul \| Better Java Performance, Superior Java Support](https://www.azul.com/products/azul-support-roadmap/)
Zulu Community時代より、無償版のサポート期間は不明。

## LOG

### レポジトリ登録

```shell-session
# apt update
# apt install gnupg ca-certificates curl
# curl -s https://repos.azul.com/azul-repo.key | gpg --dearmor -o /usr/share/keyrings/azul.gpg
# echo "deb [signed-by=/usr/share/keyrings/azul.gpg] https://repos.azul.com/zulu/deb stable main" | tee /etc/apt/sources.list.d/zulu.list
```

### インストール

```shell-session
# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

# apt update
# apt install zulu17-jdk
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "17.0.8" 2023-07-18 LTS
OpenJDK Runtime Environment Zulu17.44+15-CA (build 17.0.8+7-LTS)
OpenJDK 64-Bit Server VM Zulu17.44+15-CA (build 17.0.8+7-LTS, mixed mode, sharing)
```
Qiita CLI を試してみた。😄


# 概要

[Qiita CLI をベータ版として公開します](https://blog.qiita.com/qiita-cli-beta-release/?utm_source=Qiita%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&utm_campaign=ad0aa06fcc-Qiita_newsletter_575_07_19_2&utm_medium=email&utm_term=0_e44feaa081-ad0aa06fcc-46894722)とのことなので試してみました。

[qiita-cli](https://github.com/increments/qiita-cli)のリポジトリに記載の通りに進めました。

## ハマりどころ

ハマったというほどでもないですが、WEB で執筆するのとは少し違う部分があったのと分からない部分があったのでメモ

| ポイント | WEB／CLI  | 内容                                          |
| -------- | --------- | --------------------------------------------- |
| tag      | WEB       | A ,B,C のカンマ区切りで記載                   |
|          | Qiita CLI | 配列で入力                                    |
| 画像     | WEB       | 直接アップロード（S3 上のものを参照できる。） |
|          | Qiita CLI | ?                                             |

### 画像を入れる方法が分からずローカルに入れて試してみました。

うまく行けばここに画像が表示されるはず！
追記：ローカルのファイルをMarkdownの形式で画像を読み込んでもQiita CLIでは表示できませんでした。
↓↓
![tag](./images/tag.png)
↑↑
↓↓
![Screen](./images/Screen.png)
↑↑

# まとめ

- 普段利用しているテキストエディタが利用出来て Good！
- 画像の入れ方よく分からず　 Not Good。
- GitHub Actions でテストせず公開するので動くか心配 Not Good。
- `npx qiita pull` を実施すると今まで執筆した記事が全てローカルに取得できて Good！

# おまけ
Qiita CLIを利用すると実施中の[Qiita Engineer Festa 2023](https://qiita.com/official-events/4f3daca63fb78f16df0b)の「記事投稿キャンペーンに登録する」は実施できなかったのでキャンペーンの投稿の際にも利用出来なそうです。
Debian 12にOpenJDK 11をインストール（Azul Zulu Builds of OpenJDK）

# はじめに

Azul Zulu Builds of OpenJDKを利用してDebian12にOpenJDK11をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Azul Platform Core](https://docs.azul.com/core/zulu-openjdk/install/debian#install-from-azul-apt-repository)

## サポート

有償版のみサポート期間が明記されている。[Azul Support Roadmap \- Azul \| Better Java Performance, Superior Java Support](https://www.azul.com/products/azul-support-roadmap/)
Zulu Community時代より、無償版のサポート期間は不明。

## LOG

### レポジトリ登録

```shell-session
# apt update
# apt install gnupg ca-certificates curl
# curl -s https://repos.azul.com/azul-repo.key | gpg --dearmor -o /usr/share/keyrings/azul.gpg
# echo "deb [signed-by=/usr/share/keyrings/azul.gpg] https://repos.azul.com/zulu/deb stable main" | tee /etc/apt/sources.list.d/zulu.list
```

### インストール

```shell-session
# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

# apt update
# apt install zulu11-jdk
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "11.0.20" 2023-07-18 LTS
OpenJDK Runtime Environment Zulu11.66+15-CA (build 11.0.20+8-LTS)
OpenJDK 64-Bit Server VM Zulu11.66+15-CA (build 11.0.20+8-LTS, mixed mode)
```
Portry で virtualenv を activate する際に Unable to detect the current shell. エラーが出る場合の walk around

docker container の中で Poerty を使用した際に、 `Unable to detect the current shell.` というエラーが出て virtualenv が起動できなかった。

ソースを読んだところ、 `SHELL` が足りていないことがわかったので、
`SHELL` を定義することで virtualenv が起動できた。

``` poetry/src/poetry/utils/shell.py
@classmethod
    def get(cls) -> Shell:
        """
        Retrieve the current shell.
        """
        if cls._shell is not None:
            return cls._shell

        try:
            name, path = detect_shell(os.getpid())
        except (RuntimeError, ShellDetectionFailure):
            shell = None

            if os.name == "posix":
                shell = os.environ.get("SHELL")
            elif os.name == "nt":
                shell = os.environ.get("COMSPEC")

            if not shell:
                raise RuntimeError("Unable to detect the current shell.")

            name, path = Path(shell).stem, shell

        cls._shell = cls(name, path)

        return cls._shell
```
Debian 12にOpenJDK 8をインストール（Azul Zulu Builds of OpenJDK）

# はじめに

Azul Zulu Builds of OpenJDKを利用してDebian12にOpenJDK8をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Azul Platform Core](https://docs.azul.com/core/zulu-openjdk/install/debian#install-from-azul-apt-repository)

## サポート

有償版のみサポート期間が明記されている。[Azul Support Roadmap \- Azul \| Better Java Performance, Superior Java Support](https://www.azul.com/products/azul-support-roadmap/)
Zulu Community時代より、無償版のサポート期間は不明。

## LOG

### レポジトリ登録

```shell-session
# apt update
# apt install gnupg ca-certificates curl
# curl -s https://repos.azul.com/azul-repo.key | gpg --dearmor -o /usr/share/keyrings/azul.gpg
# echo "deb [signed-by=/usr/share/keyrings/azul.gpg] https://repos.azul.com/zulu/deb stable main" | tee /etc/apt/sources.list.d/zulu.list
```

### インストール

```shell-session
# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

# apt update
# apt install zulu8-jdk
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "1.8.0_382"
OpenJDK Runtime Environment (Zulu 8.72.0.17-CA-linux64) (build 1.8.0_382-b05)
OpenJDK 64-Bit Server VM (Zulu 8.72.0.17-CA-linux64) (build 25.382-b05, mixed mode)
```
Power Automateフローの中でVPN接続する時

Power Automate(以降、PA)のフローを作った際に調べてわかったことを記録の形にして投稿します。
指摘やアドバイスは大歓迎です。よろしくお願いいたします。

## はじめに
リモートワークで仕事をする際、社内VPNに接続して打刻をする必要がある。毎回、同じことをすることがめんどくさいこともあり、PAのフローを作るきっかけになった。PAを使えば、一回のクリックで済むはず！
打刻はブラウザ操作機能でできるが、VPNに接続するのはどうしたらいいかわからなかった。

## GUI操作で接続
最初は、タスクバーにあるWifiマークをクリックし、クイックメニューからVPNを選択して接続する流れにしようとして、PAでフローを作ってみたところ、クイックメニューがグループで認識していたため、中にある項目をクリックするのが難しかった。

GUI操作でしたら簡単に作れると思ったため、以下の操作フローで作った

Windowsの設定　→　「ネットワークとインターネット」　→　VPN　→　VPN名の横にある「接続」ボタンを押下

まず、PowerShellスクリプトに「control system」を設定する。（先に接続設定をしておく必要がある）こうすることでWindowsの設定画面が開くことができる（ちなみに、「control」にすると、コントロールパネル画面が表れる）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/60feb5b3-25ba-e878-da05-973c14ff1e55.png)

これでも実装はできたが、一発でVPNにつなぐことができる方法がないか調べてみた。


## PowerShellで対応
### 1.PowerShellスクリプト作成
Windowsのrasphoneを用いたら、VPNに簡単に接続することもできることが分かった。
早速、PA側に「PowerShellスクリプトの実行」を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/3dbf690b-9023-f631-ee4d-540b54f8f699.png)

スクリプトの内容は以下の通り。
VPN名を自分の環境に合わせて置き換えするだけでOK！
これで既に接続されている場合、スキップすることができる
(逆にVPN接続を切りたい場合は以下の「Disconnected」を「Connected」に変更するだけで対応可能)
```powershell
$vpnName = "VPN名";
    $vpn = Get-VpnConnection -Name $vpnName;
    # 接続していない場合
    if($vpn.ConnectionStatus -eq "Disconnected"){
        rasphone -d $vpnName;
}
```

### 2. 接続ダイアログボックスの非表示
既にVPN設定が完了していてもPowerShellで実行すると、以下のダイアログが表示され、「接続」ボタンを押す手間がかかる。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/4344b7b3-a6ba-f7a2-5b38-845ba8d9011d.jpeg)

ここで、以下のファインをメモ帳などで開く

C:\Users\【ユーザー名】\AppData\Roaming\Microsoft\Network\Connections\Pbk\rasphone.pbk

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/d99bf298-656e-9b5a-381c-9c37082bf99d.png)


VPN名の下にいろんな設定がある。その中で「PreviewUserPw」で検索すると、以下のようにデフォルト値が「１」になっている

```powershell
[VPN名]
Encoding=1
PBVersion=8
Type=2
・
・
・
PreviewUserPw=1
```
「**PreviewUserPw=1**」から「**PreviewUserPw=0**」に変更する。
こうすることでダイアログボックスを表示されず、接続ができる！

## 最後に
PAを使ってもWindows関連機能を使う際はできるだけPowerShellやcmdを活用した方が手間を減るんだなと思いました。（何故かPAを利用する時にはGUI操作をしないと、という理由のないプレッシャーを感じますね、、）
モノレポのPull Requestに自動で分類ラベルを付けるGitHubの公式Action

![Screenshot 2023-07-20 at 13.35.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95370/91717208-ff06-2bdb-e6cc-afd4cd700690.png)
近年はモノレポ/モノリポ (monorepo) での開発を採用するプロジェクトが増えていると思います。モノリポの善し悪しはここでは置いておいて、様々なプルリクエスト (PR) が混在することになるため、それぞれのPRがどの構成要素を変更しているのか分かりにくなりがちです。

実はGitHubには、どのファイルが変更されたかにもとづいて自動でPRにラベルを付けるActionが公式に提供されています。一見何に使うのか分からないActionですがモノリポにおいては便利です。

https://github.com/actions/labeler

## GitHub の自動ラベル付けActionを設定する

### 手順1. ラベル付けルールを用意する

以下のような、変更されたファイルのパスと付与したいラベルを紐づけるルールを用意しましょう。このファイルは `.github/labeler.yml` というファイル名でリポジトリに配置します。

「apiディレクトリ配下のファイル `api/**/*` を変更するPRには "scope: API" というラベルを付ける」といったルールを設定できます。

```.github/labeler.yaml

"scope: api":
  - api/**/*
  - .github/workflows/api-*

"scope: frontend":
  - frontend/**/*
  - .github/workflows/frontend-*

"scope: worker":
  - worker/**/*
  - .github/workflows/worker-*

"scope: ci/cd":
  - .github/**/*
```

この例では、API（バックエンドのつもり）と、フロントエンドと、Worker（非同期タスクのつもり）と、CI/CD、の4つの要素があると仮定してラベル付けをしています。

変更された言語の拡張子に応じてラベルを付けるのもよいかもしれません。

より高度なルールを書きたい方は https://github.com/actions/labeler を参照してください。

### 手順2. ワークフローファイルを配置する

プルリクエストが作られたときに [actions/labeler](https://github.com/actions/labeler) が実行されるようにしましょう。以下の内容をそのまま `.github/workflows/labeler.yml` として配置すればOKです。

```.github/workflows/labeler.yml
name: "Pull Request Labeler"
on:
- pull_request_target

jobs:
  triage:
    permissions:
      contents: read
      pull-requests: write
    runs-on: ubuntu-latest
    steps:
    - uses: actions/labeler@v4
```

設定は以上です！

たったこれだけの設定で下図のような自動ラベリングが実現できるのでぜひ試してみてください。
![Screenshot 2023-07-20 at 13.35.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95370/91717208-ff06-2bdb-e6cc-afd4cd700690.png)
「何とかするため」に必要なたった３つの心構え

この記事は[Qiita Engineer Festa 2023](https://qiita.com/official-campaigns/engineer-festa/2023) 参加記事です。

# はじめに

プロジェクトを進める時、実装をする時、障害対応する時、折衝・交渉をする時。
仕事をする上で、あらゆる局面で「何とかしなければいけない」そんな場面に出くわすことがあります。
そんな局面で「何とかするため」に必要な３つの心構えをまとめてみたいと思います。
ポエムです。

## 「何とかしなければいけない」状況とはどういう状況か？

時間・お金・知識・負の影響など、何かしらの制約がある状況が考えられます。
制約がない状況であれば、「何とかする」という現状打破的な考え方より、「より良くする」という理想に近づけるための考え方で進めることができます。
何かしらの制約がある中で、「何とかするため」に行動すべきときに思い出してもらえれば嬉しいです。


# 何とかするために必要なたった３つの心構え

必要な心構えはたったの3つです。

* その１：最大のリスクを理解する。
* その２：理想的な対策と現実的な対策の２軸で考えて行動する。
* その３：冷静になりつつも強い気持ちとを持って望む。

それぞれについて、解説してみます。

## その１：最大のリスクを理解する。

### 現状把握
まずは、「何とかするため」に、現状把握が必要です。

* 現状の最大の課題は何なのか？
* 解決出来なかった時、失敗してしまった時に起きる最悪のケース（最大のリスク）は何なのか？

を理解できると良いと思います。
例えば、

* プロジェクト遅延により**予算が枯渇**→プロジェクトの凍結
* 障害発生により**システムが完全ダウン**→お客様からのクレーム殺到でCS業務が停止

など、どんな問題が起こっていて、その結果として**考えうる**最悪のケースは何があるか？を把握できることが重要です。

### 判断軸を１つに絞る

大体の場合は、 **「最大のリスク回避のための判断」** に絞ることができると思います。
繰り返しになりますが、「何とかするため」に動かなければいけない状況は、不測の事態が発生している状況です。
不測の事態では、**判断軸をシンプル**にすることが望ましいと思います。


## その２：理想的な対策と現実的な対策の２軸で考えて行動する。

### 最悪のケースを回避するために取る行動は２つある。

今ある課題が様々なように、それに対する策の打ち方も様々あります。
そんなときは、2軸で考えると良いと思います。

* 最悪のケースを今すぐ回避させるための対策 **（暫定的な対策）**
* 最悪のケースにつながる原因を解消する対策 **（根本的な対策）**

例えば、前述の「障害発生によりシステムダウン」という例を取ってみると

* 障害復旧のために直近のリリースを切り戻す **（暫定的な対策）**
* 障害原因の特定のために調査と対応を行う **（根本的な対策）**

という2軸で考えることができます。
（それぞれの対策は、あくまでも例です。状況により対策は変わります。）

## 対策の優先度を見誤らない

しつこいように繰り返しになりますが、「何とかするため」に動かなければいけない状況は、不測の事態が発生している状況です。

その際の優先度判断は、原則的に**暫定的な対策＞根本的な対策**となることが多いです。
ただ、その際に**どちらがより早く完了するのか？**という観点は忘れずにいたいです。
根本的な対策の方が早く完了するのであれば、そちらを優先すべきです。

それは何故かというと、あくまでも判断軸は **「最大のリスク回避のための判断」** となるからです。

## その３：冷静になりつつも強い気持ちとを持って望む。

３つめは根性論かよ！？と思われるかもしれませんが、これも大事な心構えの一つです。
**不測の事態**というものは、瞬時の判断が必要になったり、極度のプレッシャーにさらされることがあります。
そんな状況の中で「何とかすること」が求められているのです。

### 冷静になること
通常時とは違う状況にいても、**いつも以上に冷静でいる**ように心がけましょう。
対策を打ち始めると、そこに集中してしまいがちで俯瞰してみることを忘れてしまったり、判断軸がズレ始めてしまうこともあります。
ちょっとでも過集中気味になっていると思ったら、一瞬深呼吸をして方向がズレていないか？と自分に問いかけてみるのも良いと思います。

### 強い気持ちを持つこと
**不測の事態**を回避するためには、技術力・理解力・瞬発力・判断力・プレッシャー耐性など多くのものが求められます。
例えば、前述したシステム障害の対応を例に取ってみてもしかりです。
（余談ですが、同僚が **「障害対応はエンジニアの総合格闘技だ！」** と言っていたことがあります。この考え方すごい好きです。）

そんな状況を「何とかするため」に全力を尽くす上でも、最後の決めてとなるのは**強い気持ち**だと思います。
難しくて・辛くて・厳しい状況であっても、**自分が・自分たちが「何とかする」んだ**という強い気持ちが無ければ、途中で心が折れてしまったり、中途半端な対策で終わってしまったりします。
根性論と思われても、最後の最後は強い気持ちがあるか？に左右されてしまうと思います。

# まとめ
大前提として、不測の事態にならないようにできることが最善です。
それでも、どうしても、仕事をする上で避けきれないことも少なくないです。
そんな時も「何とかするため」に取り組んでいけたらと思います。
何かの参考になれば嬉しいです。
dangerouslySetInnerHTMLっていかにも危険？！

## dangerouslySetInnerHTMLが必要なった場面
Reactコンポーネントでこんなコードを書きました。
```
const mediaContent = getMediaContent();
return(
	<div　className="post_text">
		{ mediaContent }
	</div>
)
```

getMediaContent()は画像等を表示するためのHTMLを生成するためのオリジナルの関数です。mediaContentにはHTMLの文字列が格納されます。
これで画像が表示されるかというと、さにあらず。文字列がブラウジングされずに表示されました。
なんでなのと思って、ChatGPTに聞きました。
>「JavaScript (JSX) では、HTML 文字列を直接レンダリングすると、文字列として表示されてしまいます。文字列を HTML としてレンダリングするには、dangerouslySetInnerHTML プロパティを使用する必要があります。」
コードは次のようになります。
```
const mediaContent = getMediaContent();
return(
	 <div
    	className="post_text"
      	dangerouslySetInnerHTML={{ __html: mediaContent }}
	/>
)
```
これで、きちんとブラウジングされました。しかし、なんだかいかがわしい名前の属性と思ってChatGPTの回答を読んでいると、
>dangerouslySetInnerHTML は名前の通り、セキュリティリスクがあるため注意して使用してください。mainText に不正なスクリプトが含まれている場合、クロスサイトスクリプティング (XSS) 攻撃の対象となる可能性があります。

まあ、getMediaContent()の出元がはっきりしていればいいようです。
## 不要なタグが付いてしまうという問題
実は話はこれで終わりません。ここからが備忘録として記録しておくべきところ。
このdangerouslySetInnerHTMLは属性なので、何らかのタグとともにでないと使えません。つまりmediaContentで出来上がった文字列が必要なタグを全部備えていると、不要なタグが一つつくことになるのです。
この不要なタグは実は問題です。mediaContentで出来上がるDOM要素が場面によって変化してしまうのです。これではCSSだって当たらなくなる可能性もあるのです。これは一大事です。

ちなみにWordpressが用意しているwp.element.Fragmentをインポートして
```
<Fragment 
	dangerouslySetInnerHTML={{ __html: mediaContent }} 
/>
```
としてもダメです。全く表示されなくなりました。
## html-react-parserライブラリの活用
でも、回避する方法はありました。
`html-react-parser` というライブラリがあるのです。
まず、次のコマンドでインストールします。
```
npm install html-react-parser
```
それでReactコンポーネントには次のように書くとOKです。とってもすっきりしてるじゃないですか。
```
import parse from 'html-react-parser';

// ...

return (
  <>
    {parse(mediaItem)}
  </>
);
```
ということでhtml-react-parserを使うのがベストチョイスと思いました。だたし、この方法でも
>信頼できない HTML 文字列が含まれる場合のセキュリティリスクに注意してください。必要に応じて、サニタイズ処理を実施してください。
> -- ChatGPTからの忠告

## JSXで要素を直接作成する
でも、条件によってはもっと簡単な方法がありました。
それはJSXで要素を直接作成するという方法です。HTMLを生成している関数が複雑だとそういうわけにはいかないのですが、たとえば、flgという状態変数がtrueなら文字列にspanタグをつけて表示したいというような場合です。
まずは、こんなコードを試してみます。
```
const dispLabel = flg ? `${labelContent}<span>(${required.display})<span>` : labelContent;
return(
	<label>
		{dispLabel}
	</label>
)
```

テンプレートリテラルで文字列を生成してレンダリングしようとしています。これだと


![WordPr.png](https://itmaroon.net/home/wp-content/uploads/2023/07/f3c5f2d5f4984f15a13b3ec61d7045f6.png)

となります。そこで
```
const dispLabel = flg ? `${labelContent}<span>(${required.display})<span>` : labelContent;
return(
	<label
		dangerouslySetInnerHTML={{ __html: dispLabel }}
	/>
)
```
とすればうまくいくのですが、そもそもdispLabel を文字列で生成するのがよくないわけです。
そこで、
```
const dispLabel = required.flg ? <>{labelContent}<span>({required.display})</span></> : labelContent;
return(
	<label>
		{dispLabel}
	</label>
)
```

これでうまくいくのです。
少し説明を加えます。
JSX（JavaScript XML）は、Reactの一部として提供される拡張構文で、JavaScriptの中にHTMLタグを書けるようになるという特徴があります。
```
const element = <h1>Hello, world!</h1>;
```
と書くと、、elementはReactが理解できる特別なオブジェクトになります。これはJavaScriptのオブジェクト表現となり、Reactはこれを利用してDOMを更新します。これを「Reactエレメント」と呼びます。
つまり、文字列ではなく「Reactエレメント」をつくればいいということです。
これでdangerouslySetInnerHTMLを使わずに済む範囲が大きくなるのではないでしょうか。
【効率化などやりたいこと】#2

## 【効率化などやりたいこと】第2弾です。
あまり受けてないけど、懲りずに、アップします。
だれか、実現してくれると嬉しいなシリーズです。

## 人事異動に伴う、特に写しの自動変更

文書の宛先というか、写しに、XX部長や、XX担当役員、関連会社社長などがある。
人事異動で変わっていないかをチェックするのは、結構というか、かなり面倒。
異動してたら、文書中の名前と、メールアドレスとメール本文の宛名を直す必要がある。
間違えるとかなり大事故になるわりに、知らないうちに変わるから、間違えやすい。
アイデアとしては、組織長の一覧を自動更新して、文書はその一覧にリンクすればよさそうだけど、
文書はワードもパワポもあるし、メールもチャットもある。
さらに、組織変更（統合・分割）もあるし、実際は結構大変。
しかし、かなりの組織の共通の仕事なので、全組織が利用すれば投資対効果もあるかもしれない。
「そんなの、文書発信者が把握してるのが当たり前だ！」と言う人が居るが、
特に写しは、会ったことないし、ほとんど話をしたことがない人の場合も多い。
しかし、写しは、VIPであり、間違えられないので、確認は結構大変な作業。
宛先の上司を自動提案してくれるだけでも助かるけど、いちいち入力せず、過去資料を更新するから、入力補助では不十分だ。
文書中の名前と、組織名、メールアドレスとメール本文の宛名を一括で直してくれると助かるかな。
時々、メールアドレスだけ修正するのを忘れるから。

そもそも、そんな方たちの名前入れないで組織役職だけにしてしまうのもいいけど、
メールも役職名のエイリアスを作れば、メールも解決だし。
でも、部長あたりから、「今まで入れてたんだから、ちゃんと名前入れろ」って言われるんだろうな。
「そんなとこは、効率化するところじゃない！」
「役員の名前を把握してないとは、気がたるんでる！」って。
こういう事を言う人たちのアップデートこそ必要なんだろうけど・・・

そうはいっても、既存のアプリのアドオンとしては、商売になりにくそうな機能だから、
誰も着手しないだろうな・・・。
この機能だけだと、無理だけど、もしかしたら、「文書配布管理」という、
新しいジャンルのオフィスツールにならないかしら？
ちょっと考えてみよ！
コンテナにHOMEディレクトリを指定するとVSCode Dev Containerのアタッチに失敗する

# 症状

## 突如、コンテナーは問題なく起動するのにVSCode Dev Containerのアタッチでエラーが発生するようになった。

> コンテナーへのアタッチ中にエラーが発生しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204514/6f6f9e70-09cb-8f28-a1e1-a93d6e2236c3.png)

```
Command in container failed: mv -n /my_home/.vscode-server/bin/74f6148eb9ea00507ec113ec51c489d6ffb4b771_1689826690061/* /my_home/.vscode-server/bin/74f6148eb9ea00507ec113ec51c489d6ffb4b771 && rmdir /my_home/.vscode-server/bin/74f6148eb9ea00507ec113ec51c489d6ffb4b771_1689826690061
[57299 ms] mv: cannot move ‘/my_home/.vscode-server/bin/74f6148eb9ea00507ec113ec51c489d6ffb4b771_1689826690061/vscode-server-linux-x64’ to ‘/my_home/.vscode-server/bin/74f6148eb9ea00507ec113ec51c489d6ffb4b771’: Permission denied
```


アタッチできるコンテナもあるのに！なぜ？！

# 原因

> コンテナのHOMEディレクトリを指定している

場合に上記のエラーが発生しました。

docker-compose.yml上で
```
    environment:
      - HOME=/my_home
```
してたり、

Dockerfile上で
```
    ENV HOME=/my_home
```

してたりした場合です。HOMEディレクトリの設定を削除すると無事にアタッチできました。

めちゃくちゃ悩みました。

誰かの一助になれば幸いです。
Bun ORMでマルチテナントに対応する

## はじめに

　この記事ではGo言語の[Bun ORM](https://bun.uptrace.dev)を使用している際に、マルチテナントに対応する方法を説明する記事です。BunのGitHubにはexampleとしてmulti-tenantが示されていますが、ドキュメントには詳しくはされていません。
　この記事ではGitHubの例をベースにマルチテナントを実装可能になることを目標とします。

## 解説

公式ではマルチテナント以外の部分も合わせてModel and query hooksとして示されています。
https://bun.uptrace.dev/guide/hooks.html

### 公式例

　公式が示しているexampleはGitHubから見ることが可能です。
https://github.com/uptrace/bun/tree/master/example/multi-tenant
　ただ、READMEを見ていただければ分かる通り、実装内容の解説は行われていません。コードの必要な箇所を抜粋しつつ解説を行っていきます。

### Struct

　例で示されてるStructは次のとおりです。

```story.go
type Story struct {
	ID       int64 `bun:",pk,autoincrement"`
	Title    string
	AuthorID int64
}
```

### multi-tenant

　実際にマルチテナントの実装箇所は次の部分です。

```main.go
var _ bun.BeforeSelectHook = (*Story)(nil)

func (s *Story) BeforeSelect(ctx context.Context, query *bun.SelectQuery) error {
	if id := ctx.Value("tenant_id"); id != nil {
		query.Where("author_id = ?", id)
	}
	return nil
}
```

　まずは、最初の行の`var _ bun.BeforeSelectHook = (*Story)(nil)`では、`Story Struct`に対しメインのクエリを発行する前にクエリをフックさせるためのものです。

　実装方法としては、実装したいStructに対し、メソッドとして実装します。引数には`context.Context`と`＊bun.SelectQuery`を指定します。返り値には`error`を指定します。

　あとは、実行したいクエリを`*bun.SelectQuery`のWhereメソッドなどで実装していく形になります。

## その他

 今回の例ではSelectQueryですが、InsertQueryなどでも実装可能です。また、`AfterSelect`など、メインのクエリの後に実装することも可能です。もちろん、どちらも実装することもできます。
Oracle Database 23c セキュリティ新機能: Schema Privileges

今回は、Oracle Database 23cのセキュリティ新機能として、Schema Privilegesを紹介します。
この機能は、非常に地味・・ではあるんですが、今までアクセス権限の設定でちょっと面倒だった部分を解消してくれる便利な機能ではないかと思います。

主な特徴としてはこちらのスライドをご覧ください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/c8a35db6-012e-2884-c9f5-cb7b170f0a28.png)

通常SELECT ANY TABLEを付与した場合、そのユーザーはデータベース内のすべての表にアクセスできてしまう非常に強力なシステム権限なのですが、23cのSchema Privilegesでは付与する際に<font color="RED">ON SCHEMA</font>で明示的にスキーマを指定することで範囲を限定することができます。

使い方は非常に簡単です。[前回](https://qiita.com/western24/items/ca6515042d1a84ee07db)作成したHRスキーマと同様に用意した2つのターミナルを使った動作確認を紹介します。

## Schema Privilegesの設定方法

```sql
-SYSユーザーでテスト用のユーザーを作成(A)
create user test identified by test;
grant connect to test;

-testユーザでHRスキーマをアクセス(B)
sqlplus test/test@localhost:1521/freepdb1
SQL>select * from hr.employees;
ERROR at line 1:
ORA-41900: missing READ privilege on "HR"."EMPLOYEES"
->権限ないので当然アクセスできない

-Schema PrivilegesでSELECT ANY TABLEを付与する(A)
GRANT SELECT ANY TABLE ON SCHEMA HR TO TEST;

-HRのすべての表にアクセスできる(B)
select * from hr.employees;
select * from hr.jobs;

-HRに新規の表を作成(A)
create table hr.testtbl(col1 number);
insert into hr.testtbl values(100);
commit;

-新規に作成されたHRの表にアクセス(B)
select * from hr.testtbl;

      COL1
----------
       100
-> SELECT権限を付与しなくてもアクセスできる

-権限は持っていないので、INSERTは当然実行できない(B)
SQL> insert into hr.testtbl values(200);
ERROR at line 1:
ORA-41900: missing INSERT privilege on "HR"."TESTTBL"

-INSERT ANY TABLEを付与する(A)
GRANT INSERT ANY TABLE ON SCHEMA HR TO TEST;

-HRスキーマのすべての表へのINSERTが可能になる(B)
SQL> insert into hr.testtbl values(200);
1 row created.

-権限を取り消す場合(A)
REVOKE SELECT ANY TABLE ON SCHEMA HR FROM TEST;
REVOKE INSERT ANY TABLE ON SCHEMA HR FROM TEST;

```
上記のように設定動作は非常にシンプルなので、スキーマ内のオブジェクトが頻繁に追加・削除される、もしくはすでにSELECT ANY TABLEを組み込んでいるケースなど、アクセス範囲を最小化してリスク低減に貢献できる機能ではないかと思います。
M5StickCPlus MicroPythonで電源OFFする

電源ボタンを6秒押しすれば切れるはずなのですが... なぜか切れない... ボタンの調子が悪いのかな？

- https://pointofviewpoint.linclip.com/archives/3255

こちらを参考に，MicroPythonで電源OFFするコードを書いてみました。

```main.py
from machine import Pin, I2C

i2c = I2C(sda=Pin(21),scl=Pin(22), freq=4000000) # for internal

# AX192 adress 0x34 = 52

def AX192_read_8bit(a): # a=pointer address
    i2c.writeto(52,bytearray([a]))
    d=list(i2c.readfrom(52,1))
    return(d[0])

def AX192_write_1Byte(a, d): # a=pointer address, d=8bit data
    i2c.writeto(52,bytearray([a, d]))

# import time
# time.sleep(1)
# print("Power Off !")
# time.sleep(1)

AX192_write_1Byte(0x32, AX192_read_8bit(0x32) | 0x80)
```
【ChatGPT無】曖昧な目標から最終的な目標に行くため？のPrompt

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　どうも、カーブミラーです。

　今回は、
　　曖昧な目標から
　　　最終的な目標に行くための
　　　　Promptです。

　最初に謝ります。
　　ちょっとPromptに
　　　重複部分があります。

　これは、
　　片方だけでは、
　　　うまく行かなかったために
　　　　こうなりました。

　申し訳ありません。

```Text:曖昧目標→最終的目標Prompt
# 目的
ユーザーの曖昧な目標から、あなたの質問を通して、最終的な目標に到達すること。

# 注意点
・質問は、絶対に一度にひとつずつ簡潔にお願いします。
・提案は不要です。
・あなたが「具体的な目標にたどり着いた」と判断しても、ユーザーの目標とは違う可能性が高いです。判断はユーザーにゆだねてください。
・勝手に終了しないようにしてください。
・「終了」宣言するまでは、結果は示さないでください。

# 処理手順
最終的な目標に向かって進むための具体的なステップやアクションプランを考えて出力せずに、導いてください。

質問は、絶対に一度にひとつずつ簡潔にお願いします。

私が「終了」を宣言するまでは、質問を続けてください。
勝手に終了しないように。

あなたは、質問以外を出力してはいけません。質問を要求するのもやめてください。

「終了」が宣言させたならば、具体的な目標を出力してください。多少の曖昧さは許容します。

# 最終確認
理解できない箇所がありましたならば、その箇所を示してください。

以上を理解できたら、曖昧な目標の入力を促してください。
```

　実行例です。
　　オフラインでの
　　　会合をしたい
　　　　というのを
　　　　　曖昧な目標としました。

```Text:Prompt実行例
ChatGPT
了解しました。では、曖昧な目標の入力をお願いします。


User
オンラインで知り合った人たちとの、オフ会を開きたい

ChatGPT
わかりました。オンラインで知り合った人たちとのオフ会を開くための具体的なステップやアクションプランを導くために、以下の質問をお聞きします：

オフ会の開催地はどこにしたいですか？（都市や地域を具体的に教えてください。）
※ 目標に到達するためには、開催地を決めることが重要です。


User
地元のバー

ChatGPT
素晴らしいですね！地元のバーでオフ会を開催する計画ですね。

次のステップとして考慮すべき点は次の通りです：

参加者の人数の目安はありますか？（予想される参加者の人数を把握することで、バーの予約やイベントの計画がしやすくなります。）
お答えいただければ、次の質問に進みます。


User
10人前後

ChatGPT
分かりました。参加者の目安が10人前後ということですね。

次のステップは以下の通りです：

オフ会の日程を決めましょう。バーの予約や参加者のスケジュールを調整するために、開催予定の日付や時間帯を教えてください。
お答えいただければ、次の質問に進みます。


User
来月の第二金曜日

ChatGPT
了解しました。オフ会の日程は来月の第二金曜日ということですね。

次のステップは以下の通りです：

参加者にオフ会の案内をどのようにしますか？（例：オンライン招待、メール、SNSグループなど）
参加者への案内方法をお答えいただければ、次の質問に進みます。


User
オンラインでの告知

ChatGPT
素晴らしいです！オンラインでの告知は多くの人に効果的に届ける方法ですね。

次のステップは以下の通りです：

オフ会の詳細を含む告知を作成しましたか？もしそうでなければ、どのような情報を告知に含めたいですか？（例：日時、場所、参加方法、参加費用、アクティビティの予定など）
告知内容について教えていただければ、次の質問に進みます。


User
日時と場所と参加費用は決まりました

ChatGPT
了解しました。日時と場所、参加費用が決まっているということですね。

次のステップは以下の通りです：

オフ会で行うアクティビティやイベントの予定はありますか？もしあれば、具体的なアイデアを教えてください。
参加者が楽しめるようなアクティビティやイベントを考えている場合は、それについて教えていただければ、次の質問に進みます。


User
初心者の質問に答えることで、一歩を踏み出させる

ChatGPT
素晴らしいアイデアですね！初心者の質問に答えることで、参加者が一歩を踏み出せるようサポートすることができます。

次のステップは以下の通りです：

オフ会の中で初心者の質問にどのように答えるか、具体的な方法やアプローチを考えていますか？
初心者の質問に対する具体的な対応方法について教えていただければ、最終的な目標に近づくための次のステップに進みます。


User
なし

ChatGPT
了解しました。アクティビティやイベントとして初心者の質問に対する特定の対応を予定していないということですね。

最終的な目標に向かうためのステップは以下のようになります：

・適切な日時と場所を確定します。
・オンラインでの告知を行います。
・イベントに参加する予定の人数を把握し、バーの予約を行います。
・当日の流れやアクティビティを事前に計画し、参加者に案内します。
・オフ会当日に参加者を歓迎し、楽しいひとときを過ごします。

以上のステップを順番に進めることで、オンラインで知り合った人たちと地元のバーで楽しいオフ会を開催することができるでしょう。

最終的な目標：オンラインで知り合った人たちと地元のバーでオフ会を開催し、楽しいひとときを過ごすこと。

もし他に質問があればお気軽にどうぞ！
```

　（終了）せずに
　　終わってしまいました（なぜ）

　まぁ、
　　質問してもらえたことで
　　　多少、具体化した気がします。

　実際の
　　オフ会の予定は
　　　ありませんよ（笑）
MacのAndroid Studioで複数プロジェクトを開く際、新規ウィンドウで開く

# はじめに
MacのAndroid Studioで複数プロジェクトを開く際、新規ウィンドウで開く設定について解説します。

# 手順
## 1. Android Studioの設定
上部メニューの`Android Studio`→`Settings`で設定画面を開く。
`System Settings`→`Project`から`New Window`を選択。
![settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/d0b0fc7f-80ca-eb82-c391-bc31d97f388f.png)

## 2. Macの設定
メニュー左上の`アップルメニュー`→`システム設定`→`デスクトップとDock`→ウィンドウの`書類を開くときはタブで開く`を`しない`に変更
![settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/d31ec891-50fe-a13c-719a-2b0ac1ea13f9.png)
'cdk' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。

## 本記事について

以下手順に従い、TypeScriptでCDKを使用することを目指している。
その前提条件として`npm install`コマンドでのCDKインストールが求められるが、なんかうまくいかない。
https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/work-with-cdk-typescript.html

## CDKの環境構築でハマったこと

`npm install`コマンド後に`cdk`コマンドをたたくと以下のようなエラーメッセージが表示され、手順を進めることができない。

```
C:\Users\user\Desktop\cdk>npm install -g aws-cdk
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.

changed 1 package, and audited 2 packages in 7s

found 0 vulnerabilities

C:\Users\user\Desktop\cdk>cdk --version
'cdk' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
```

## 対処

おそらく、`npm install -g`コマンドによりnpmの領域内にcdkのコマンドが配置されるが、そこにパスが通っていない。
以下のコマンドで配置されているフォルダが多分見れる。

```
C:\Users\user\Desktop\_repos\cdk>npm list -g
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
C:\Users\user\AppData\Roaming\npm
└── aws-cdk@2.87.0
```

上記より、`C:\Users\user\AppData\Roaming\npm`を環境変数Pathに追加する。

Windowsの[設定]アプリ -> 「システム」 -> 「システムの詳細設定」 -> 「詳細設定」タブ -> 「環境変数」ボタン -> 「ユーザー環境変数」の「編集」ボタン
-> 「新規」ボタン

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653543/ab4c12e9-7ea3-abc1-3fd6-fe4d62c7bf47.png)

## 結果

`cdk`コマンドが使えるようになった。

```
C:\Users\user\Desktop\cdk>cdk --version
2.87.0 (build 9fca790)
```

## 考察

CDKの環境構築の問題というよりは、npmが正しく構成されていないという問題に見える。
直近でやったことといえば、Windowsユーザーを作り直したことが一番心当たりある。
ユーザーを変えてもnpmコマンドが使え、スタートメニューからもNode.jsが出てきたことから、Node.jsが普通に使えるとばかり思っていた。
Nodeをインストールした際にログインしていたWindowsユーザー以外でNodeを使うときはこのような事象に要注意、ということなのかも。
BIツール、なぜ必要？どう使うの？②

では、データがそろったらダッシュボードを作成してみます。皆さんはおそらく「どういったコンポーネントを選択すれば最も適してデータを表示できるのか？」との疑問があるでしょう。大体は棒グラフ、円グラフ、折れ線を使います。

VIVIDATA Desktopは、さまざまなコンポーネントを提供しております。
なんか比較する時によく使用される棒グラフ、KPIカード、バブルチャート、ファネルチャートなどがあります。
分布を見るには、ヒストグラム、ヒートマップ、散布図、箱ひげ図などがよく使用されます。
流れを見るにはファネルチャートやサンキーダイアグラムなどのコンポーネントも活用できます。

適切なコンポーネントを使うことにより、データ分析をより正確に行います。

これからデータをリアルタイムで取得方法を紹介します。VIVIDATA Desktopではレポート作成時に「ダッシュボード-設定-リアルタイムデータ」を選択すると、常に最新のデータをレポートに表示します。
また、日付フィールドに対して新しい日付式を作成することもできます。様々な日付による表示・フィルターで活用します。
一つ注意が必要なのはレポートにバインドされたExcelデータシートの名前は変更しないことです。
【Ruby】7の倍数の数値の中に7が何回現れるかをカウントするロジック

Rubyを使ったロジックについて学習しています。
数字に関するお題について、回答し、ロジックを分解して考えていきます。

# 問題
7777777以下の7の倍数を全て取り出したとき、数字「7」は何回現れるか？

# 回答コード

```ruby
def count_number(number)
  list = []
  for i in 1.upto(number) do
    if (i % 7 == 0 )
      list.append(i)
    end
  end
  list.sum{|i| i.to_s.count("7")}
end

puts "#{count_number(7777777)}"
```

# 出力結果
```ter
777784
```


# コードの解説

- このコードは、`1から指定した数値までの中で、7の倍数の数値の中に7が何回現れるかをカウント`するコードである。
- まず、`count_number(number)`っていう関数を定義している。引数には数値が渡されることを期待している。
- 次に、`list = []`で空の配列を作成している。これは後で7の倍数の数値を格納するための配列である。
- その後、`for i in 1.upto(number) do`のループで1から指定した数値までをチェックしている。
- `i % 7 == 0`の部分で、その数値が7の倍数かどうかを判断している。もし7の倍数だったら、`list.append(i)`でその数値を配列に追加している。
- ループが終わったら、`list.sum{|i| i.to_s.count("7")}`で配列の中の数値を文字列に変換し、その中に7が何回現れるかをカウントして全て足している。
- `i.to_s.count("7")`の部分で、数値を文字列に変換して7の数をカウントしている。
- 最後に、`puts "#{count_number(7777777)}"`で関数を呼び出し、結果を出力している。
- コードを実行すると、`1から7777777までの中で7の倍数の数値の中に7が何回現れるかが表示`される。


# 参考記事

https://teratail.com/questions/khl1tm0vant4hs

https://style.potepan.com/articles/29767.html

https://www.javadrive.jp/ruby/for/index3.html

https://www.javadrive.jp/ruby/for/index6.html
Cognos AnalyticsでQueryサービスの内部エラーが発生した場合の対処



データ・ソース名が変更された際に、下記のエラーがでますがよくある修正としては、ネイティブSQLのデータ・ソースを更新することです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255563/84b75edd-8899-d54a-a6c0-40fdfb281c94.png)


クエリー画面を開き、「←SQL」となっている個所を選択しプロパティーを開くと、SQLのデータ・ソースを改めて選択できます。ここで、新しいデータ・ソース名に変更してあげます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255563/f8bba5b7-386e-24f5-7932-e76beb3b6dc8.png)

変更後、再度レポート実行するとこのようなエラーが発生します。
>XQE-GEN-0018 Queryサービスの内部エラーが発生しました。詳細についてはログを参照してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255563/1857ffb7-0157-d70a-fcbd-4c526c298db8.png)

また、クエリー画面にてSQLを選択すると下記の文言。
> クエリー・データ・アイテムが更新されていません。
データ・アイテム式を手作業で更新する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255563/d341fc04-ac22-2694-923d-11c62ce323c9.png)

ネイティブSQLを参照しているクエリーを開き、SQLを使用しているクエリーアイテムの定義にて「検証」を実行します。これによって、Queryサービスの内部エラーは解消されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255563/16a71eeb-57ed-8140-23ba-e7e7b56ce13d.png)
AppSyncでの開発の流れメモ

# 開発時流れ
AWS CDKを使ってTypeScriptでAppSync APIを追加する方法は以下の手順で行います。
### 必要なパッケージのインストール:
まず、@aws-cdk/aws-appsyncパッケージをインストールしてください。
```bash
npm install @aws-cdk/aws-appsync
```

### CDKスタックの作成:
libディレクトリ内に新しいスタックファイル（例: appsync-cdk-app-stack.ts）を作成し、必要なモジュールをインポートします。
```typescript
import * as cdk from 'aws-cdk-lib';
import * as appsync from 'aws-cdk-lib/aws-appsync';
```

### AppSync APIの追加:
スタッククラス内でAppSync APIを作成します。GraphQL Endpoint自体の定義をします。
以下の例では、schema.graphqlファイルからスキーマを読み込んでいます。
```typescript
export class AppsyncCdkAppStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // AppSync APIの作成
    const api = new appsync.GraphqlApi(this, 'api', {
      name: 'myApi',
      schema: appsync.Schema.fromAsset(path.join(__dirname, 'schema.graphql')),
    });
  }
}
```

### データソースとリゾルバの追加:
必要に応じて、データソースとリゾルバをAPIに追加できます。
データソースとリゾルバは、AWS AppSyncでGraphQL APIを構築する際に重要な役割を果たします。データソースは、APIがアクセスするデータの場所を定義し、リゾルバは、クライアントからのGraphQLクエリやミューテーションに対して実際にデータを取得・操作する方法を指定します
データソースは、DynamoDB、RDS、Amazon Elasticsearch Service、HTTPエンドポイントなど、さまざまなデータストレージやサービスに対応しています。

リゾルバは、クライアントからのリクエストをデータソースにマッピングし、その結果をクライアントに返す役割を果たします。それぞれのリゾルバは特定のデータソース（例えば、DynamoDBテーブルやLambda関数など）と関連付けられ、そのデータソースからデータを取得したり、データを変更したりします。

パイプラインは、複数のリゾルバ（これをリゾルバ関数とも呼びます）を一連のステップとして組み合わせたものです。各リゾルバ関数は順番に実行され、一つの関数の出力が次の関数の入力となります。これにより、複数のデータソースからデータを取得し結合したり、複雑なデータ操作や変換を行ったりすることが可能になります。

したがって、パイプラインリゾルバを使用することで、単一のリクエストで複数のデータソースを操作し、それらの結果を組み合わせてクライアントに返すことができます。これは、より複雑なデータ取得や操作を可能にします。
以下は、DynamoDBテーブルをデータソースとして追加し、リゾルバを作成する例です。
```typescript
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';

// DynamoDBテーブルの作成
const table = new dynamodb.Table(this, 'MyTable', {
  partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
});

// データソースの追加
const dataSource = api.addDynamoDbDataSource('MyDataSource', table);

// リゾルバの追加
dataSource.createResolver({
  typeName: 'Query',
  fieldName: 'getItem',
  requestMappingTemplate: appsync.MappingTemplate.dynamoDbGetItem('id', 'id'),
  responseMappingTemplate: appsync.MappingTemplate.dynamoDbResultItem(),
});
```
### デプロイ:
最後に、CDKアプリケーションをデプロイします。
```bash
cdk deploy
```


これで、AWS CDKとTypeScriptを使用してAppSync APIを追加する方法が完了しました。
[Servicenow]REST Message

# REST Messageの設定
設定手順の例を簡単にまとめます。

## 環境
- Version：Tokyo

## 設定手順
RestMessageを使用して、郵便番号検索APIを呼んでみます。
APIの仕様は以下を参照。
- http://zipcloud.ibsnet.co.jp/doc/api
1. [rest message]と検索し、REST Message一覧画面を開く。
1. [New]ボタンをクリックする。
1. 必要事項を入力し、Saveする。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/9b9f5d2c-91ec-5c9b-d62b-e01b1e82c1ca.png)
1. Saveすると「Default GET」メソッドが自動作成されるのでクリックする。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/854ee27a-8634-c356-bb4a-1b2cd7c2647c.png)
1. APIに渡す郵便番号を動的にするためEndpointを修正し、Saveする。```https://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipcode}```![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/65b56d19-eb4e-cce9-be4c-cf47f6ea5b36.png)

1. [Auto-generate variables]リンクをクリックする。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/0a104d73-d72d-8d6a-f675-43929e5dc743.png)
1. [Variable Substitutions]タブにEndpointで動的指定した変数が自動作成される。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/41bbe816-6630-3ff3-75bc-3e93f30ee4f1.png)
1. [Test value]に検索したい郵便番号を入力する。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/bbacf865-d6e6-ad4e-cc11-9cca3a193d14.png)
1. HTTP Methodの画面の[Test]リンクをクリックする。
1. APIの結果が表示されます。無事にAPI連携ができました。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/bb30fd3b-4ce7-2c21-92db-b7c87fc5906e.png)
【Linux】ディレクトリ内の全ファイルからテキスト検索

# 結論
```bash
find 検索対象ディレクトリPATH -type f | xargs grep -a 検索対象テキスト --color=auto
```

# 実行環境
NAME="AlmaLinux"
VERSION="9.2 (Turquoise Kodkod)"

# 各コマンド説明
**find 検索ディレクトリPATH -type f** 
ファイルのみのPATH一覧を表示

**xargs grep -a 検索文字列 --color=auto**
`xargs` : パイプ（｜）前の出力を受け取って、引数として渡す。
実行されるコマンド：`grep -a  検索対象テキスト --color=auto 標準出力(ファイルPATH)`

**grep**
`grep 検索文字列 ファイル名`でファイル内で検索文字列を含む行を返す

-a オプション：テキストファイルであることを明示する。
　　　　　　　付けないと`grep: (standard input): binary file matches`と表示された。

--color=auto オプション：検索結果がハイライト表示されて分かりやすい

# 参考
https://linux.just4fun.biz/?%E9%80%86%E5%BC%95%E3%81%8DUNIX%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89/find%E3%81%A7%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%81%BF%E3%80%81%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%AE%E3%81%BF%E3%81%AE%E4%B8%80%E8%A6%A7%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B

https://qiita.com/P-man_Brown/items/c3f2634b7b5e08306c8f

https://qiita.com/ponsuke0531/items/55843716123c306ac8bf

https://wiki.archlinux.jp/index.php/%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%81%AE%E3%82%AB%E3%83%A9%E3%83%BC%E5%87%BA%E5%8A%9B
cscの作法 その415

# 概要
cscの作法、調べてみた。
練習問題、やってみた。

# 練習問題
automationでexcelの1から10まで書き込こんでsum関数で合計を求めよ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/49f81287-2a6f-882b-c87c-ad4d959c8b85.png)

# サンプルコード

```

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Automation;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace App
{
	class Program {
		static void Main(string[] args) {
			AutomationElement aeForm;
			Process excel = Process.Start(@"C:\Program Files (x86)\Microsoft Office\Office12\excel.exe");
			Thread.Sleep(2000);
			aeForm = AutomationElement.FromHandle(excel.MainWindowHandle);
			aeForm.SetFocus();
			SendKeys.SendWait("1");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("2");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("3");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("4");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("5");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("6");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("7");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("8");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("9");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("10");
			SendKeys.SendWait("{DOWN}");
			SendKeys.SendWait("{ADD}");
			SendKeys.SendWait("sum");
			SendKeys.SendWait("{(}");
			SendKeys.SendWait("a1:a10");
			SendKeys.SendWait("{)}");
			SendKeys.SendWait("{DOWN}");

		}
	}
}


```


以上。
著作権とソースコード

先日、GPL にライセンスされた商用サービスのソースコードが開示されないというツイートを見かけました。我々エンジニアの仕事柄、切っても切れないライセンス・著作権の話をしたいと思います。なお、私は知的財産権の専門家ではないので誤っている場合もあります。ご了承ください。

## ソースコードは著作物？

著作物は著作権法第二条[^第二条]にて「思想又は感情を創作的に表現したものであって、文芸、学術、美術又は音楽の範囲に属するもの」と定義されています。また、著作物の例示として、第十条[^第十条]で「小説、脚本、論文、講演その他の言語の著作物」や「プログラムの著作物」が挙げられています。今読まれているこの記事や我々エンジニアが日頃書いているソースコードも、法律で守られる著作物ということです。しかし、「創作的」とあるように、ありふれた数行の誰でも書けるような簡単なソースコードは創作性があるとは言えないでしょう。アプリやライブラリとして、創作性のあるとしてなれば、著作物と言われるものになるでしょう。

[^第二条]: 著作権法第二条　https://elaws.e-gov.go.jp/document?lawid=345AC0000000048#Mp-At_2
[^第十条]: 著作権法第十条　https://elaws.e-gov.go.jp/document?lawid=345AC0000000048#Mp-At_10

### 引用

この記事でも他の著作物を利用しています。第三十二条[^第三十二条]で明記される引用「公表された著作物は、引用して利用することができる。この場合において、その引用は、公正な慣行に合致するものであり、かつ、報道、批評、研究その他の引用の目的上正当な範囲内で行なわれるものでなければならない。」です。また、第四十八条[^第四十八条]にて、出所を明示しなければならないとあります。

大学のレポートや卒業論文などを経験された方なら、次の指導を受けたことがあるかと思います。

1. 正当な範囲内で利用する
1. 出所の明示をする

簡単に言うと、他人の著作物をまるで自身が書いたように思わせてはダメ。他者の著作物を侵害してはいけません。

[^第三十二条]: 著作権法第三十二条　https://elaws.e-gov.go.jp/document?lawid=345AC0000000048#Mp-At_32
[^第四十八条]: 著作権法第四十八条　https://elaws.e-gov.go.jp/document?lawid=345AC0000000048#Mp-At_48

我々が開発する場合、サードパーティのライブラリ利用は欠かせません。これら条項が適切かは分かりませんが、利用したライブラリのライセンス表示をしっかりと明記するなどして、他人の著作物を適切に扱いましょう。

## ソースコードのライセンス

著作権法を取り上げましたが、第六条[^第六条]からこの保護対象は日本国民が作成したものに限られています。だからといって、外国人の方が作成されたソースコードを好き勝手に使っていいわけではありません。同条の三項にて条約を批准した他国の著作物も保護対象にされています。国内著作物と同様に扱いましょう。

またそれぞれのライセンスに従いましょう。代表的なライセンスを簡単に紹介します。それぞれの詳細は [とほほのライセンス入門](https://www.tohoho-web.com/ex/license.html) さんが丁寧にまとめられているので、そちらを見てください。

[^第六条]: 著作権法第六条　https://elaws.e-gov.go.jp/document?lawid=345AC0000000048#Mp-At_6


### MITライセンス

マサチューセッツ工科大学を発祥とするライセンスです。改変や再配布が自由にでき、比較的緩い条件になっています。私も個人開発する場合はこのライセンスを適用することが多いです。

1. このソフトウェアを誰でも無償で無制限に扱って良い。ただし、著作権表示および本許諾表示をソフトウェアのすべての複製または重要な部分に記載しなければならない。
2. 作者または著作権者は、ソフトウェアに関してなんら責任を負わない。

### BSDライセンス

カリフォルニア大学バークレー校を発祥とするライセンスです。MITライセンスと同様に改変や再配布は自由に行えますが、いくつか種類があり、初期開発者のクレジット表示が必要なものもあります。

### GPLライセンス

上記のライセンスとは考え方が異なります。コピーレフトとも呼ばれる自由なソフトウェアの普及を目的としています。GPLライセンスのソフトウェアを組み込んだ場合、その成果物を配布する際に開発コードを公開する必要があります。一部の商用サービスがこのライセンスのソフトウェアを利用した場合でも、ソースコードを開示しないライセンス軽視がしばしば問題になります。

## まとめ

現在の開発では、他人のソースコードやオープンソースコードの利用は欠かせません。さまざまな著作物を利用して、開発は成り立っています。それらをリスペクトして、適切に利用しましょう。
Windows版Excelでカスタムショートカットを実現する【PowerToys】

Mac版Excelにはショートカットを自由に作成できる機能がありますが、Windows版にはありません。そこで今回は Microsoft PowerToys を活用して好きなキー配置のショートカットを作成する方法を紹介します。

今回は例としてスプレッドシートに実装されている `Ctrl+Shift+V` での「値貼り付け」ショートカットを作成します。

### 環境

- Windows 10 Home
- Microsoft365 Excel バージョン2306
- MicrosoftPowerToys v0.70.1

### Excelでの操作

Windows版Excelでショートカットを作成する方法として、クイックアクセスツールバーを活用する方法があります。

- [ファイル] > [オプション] > [クイックアクセスツールバー] に移動する
- [コマンドの選択] で [リボンにないコマンド]を選択し、[値(値の貼り付け)] をダブルクリック
- 追加した操作が上から何番目にあるかを覚えておく(下図の例では `2` )

<img width="800" alt="excel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/834671/8bbcb3e0-7910-df82-5700-f4e604e1a6a7.png">

この状態でシートに移動し、セルをコピーした状態で `alt + [先程覚えた数字]` を押すことでリボンに設定した操作を呼び出すことができます。これでもよいですが、個人的には `alt + 数字` は全く押しやすくないのでより押しやすいキーに設定します。

### PowerToys での操作

Microsoft PowerToysとは、Microsoftがオープンソースで開発中のソフトです。元々Windowsに搭載するつもりだったが搭載されなかった利便性向上機能を複数提供します。
多くの機能がありますが、意図しないショートカットを使用してしまう可能性もあるので使用しない機能はオフに設定しておくことをオススメします。

> 今回の話とは直接関係ありませんが、例えば以下のような便利機能があります。
> [Microsoft PowerToysを試してみた (各機能の概要説明) ](https://zenn.dev/longbridge/articles/6771c0cb9a9184)
> [WindowsのUSキーボードをMacのJIS配列のように使いたい【Power Toys】【Auto Hot Key】Windows11/IME (Keyboard Manager)](https://www.y-hakopro.com/entry/keyboad_customize)
> [[Windows] [PowerToys] ショートカットで画像から文字列抽出 (Text Extractor)](https://qiita.com/Tadataka_Takahashi/items/a390964f78cc33e850fb)
> [PowerToysで簡単にファイル名に接頭辞をつける (Power Rename)](https://qiita.com/haniokasai/items/e25c91b29d2888a3322b)

#### PowerToysのインストール
- すでにインストールされている方は対応不要なので次へ
- [Microsoft Store](https://apps.microsoft.com/store/detail/microsoft-powertoys/XP89DCGQ3K6VLD?hl=ja-jp&gl=jp&icid=CNavAppsWindowsApps) ( または [Microsoft HP](https://learn.microsoft.com/ja-jp/windows/powertoys/) の [PowerToysをインストール] ボタン ) からインストールする。

#### PowerToysの設定
- (必要ではないが推奨) 今回使用する [Keyboard Manager] 以外の機能をオフ (使用したい機能があればオフにしなくてよい)
> 僕自身は `Keyboard Manager` の他に `Text Extractor` , `Color Picker` , `マウスユーティリティ>マウスの検索` を使用しています

<img width="800" alt="excel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/834671/7ff6571f-e58d-ba2b-f2c9-e0b4958ad3b2.png">

- [Keyboard Manager] > [ショートカットの再マップ] > [+] を押して以下のように入力
    - 右側の `Alt + 数字` に関してはExcelの操作内で覚えた数字に変えてください
    -  (直接入力を活用すると楽です)

<img width="800" alt="excel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/834671/37d9389b-a1eb-79f4-c86c-06935a2a4cd6.png">

> ターゲットアプリ欄は使用したい実行ファイルのファイル名を記述します。Excel の場合は `excel.exe` なので `excel` を入力します。
> <img width="800" alt="excel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/834671/bf923b4c-9167-10dc-ffbc-8209abbc2ee2.png">

これで Excel 上で `Ctrl + Shift + V` で値貼り付けができるようになりました！
うまく動かなくなった時はタスクバー右下からPowerToysを一旦終了して再起動してみると解決することが多いです。

<img width="200" alt="excel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/834671/bdf5e31b-4880-c597-7530-13baf02de10d.png">
ジャニーズのジャケ写を公式から一括 DL するユーザースクリプト

# はじめに
ジャニーズの CD は iTunes に CD を取り込んでも，ジャケ写が読み込まれないらしい（友人談）．
ジャニオタの皆さんは，ネットから頑張って形態ごと（初版A,B とか）にジャケ写を探してきて登録しているようです．
今回は，ここをできるだけ自動化したいと考えてやってみました．

# めんどくさいことはユーザースクリプトにやらせよう
ジャニーズグループの Web ページは，
https://www.johnnys-net.jp/page?id=discoDetail&artist=41&data=2762
のように「アーティスト > Discography > 各 CD の詳細」 という画面構成になっていて，そこで実行すると全形態のジャケ写をローカルに DL できるユーザースクリプトを書いてみました．

```javascript
// 画像をダウンロードする関数
const downloadImage = (url, name) => {
    const d = document.createElement("a");
    d.download = name;
    d.href = url;
    d.click();
};

const cdArray = Array.from(document.getElementsByClassName("copyright-slider__item-inner")).map((inner) => ({
    type: inner.children[1].textContent,
    image: inner.childNodes[1].childNodes[0].currentSrc,
}));

const tittle = document.querySelector("#contents > div.container.artist_disco > h3").textContent.trim();

console.log("タイトル: " + tittle);
console.log("ファイルをローカルに DL します");

const uniqueCdArray = Array
    .from(new Map(cdArray.map((cd) => [cd.type, cd])).values()) // unique にする
    .forEach(async (cd) => {
        // 画像をローカルにダウンロード
        downloadImage(cd.image, `${tittle}_${cd.type}.jpeg`);
        console.log(`${cd.type}: ${cd.image}`);
    });
    
console.log("DL 完了！");
```
# 学び
そんなに難しいことやってないんですが，コンソールからどうやって画像を DL してこようかなと調べていたところ， `<a>` タグを一時的に作ってクリックさせるという方法がヒットしてなるほどなと思いました．
フロントエンド界隈だと当たり前の Tips かもしれないんですが，あんまり普段フロントエンド，JavaScript を触らない僕としては発見でした．

# 使い方
ジャケ写を DL したい CD のページへアクセスします（例: https://www.johnnys-net.jp/page?id=discoDetail&artist=41&data=2762）
ブラウザの「開発者ツール > Console」を開いて，さっきのスクリプトをコピペして実行するだけ！

![スクリーンショット 2023-07-20 11.12.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333871/25ab021b-6031-ffbf-c74c-fb2b6cd5de47.png)

![スクリーンショット 2023-07-20 11.16.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333871/ba346654-3b2b-e754-0d29-ff9c816f6c44.png)


# 画像の権利について
サイトポリシー（https://www.johnnys-net.jp/page?id=sitepolicy） には，
>当ウェブサイトに掲載されている全てのコンテンツ（文章、グラフィック、画像、音源等）の著作権は、ジャニーズ事務所または正当な権利を有する権利者に帰属しています。
> 事前にジャニーズ事務所の承諾がない限り、法律によって認められる私的使用の範囲を超えて、これらの情報を使用（複製、改ざん、頒布などを含む）することを固くお断りします。

とあるので，私的利用の範囲であれば問題なさそうです．
配布などせず，自分の音楽再生アプリでジャケ写に登録すること自体は大丈夫．

# おわりに
Chrome 拡張にしてリリースしようかな〜〜〜〜