OmniAICreator/Qiita-1.07M huggingface dataset:
二次元累積和 (paizaランク B 相当)

https://paiza.jp/works/mondai/query_primer/query_primer__two_dimensions_cumulative__sum

累積和を2次元でやればいいので
こんな風に書けばいいはずだと思ってたんですが、
どうも違うようで。。。

```py
H,W,N = map(int,input().split())
A = [list(map(int,input().split())) for _ in range(N)]
ans = [[0,0,0]] + A[:]
for i in range(1,H + 1):
    for j in range(1, W + 1):
        ans[i][j] += ans[i-1][j-1]
```

つまり、Ansで雛形を作ったんですが、

```
[[0, 0, 0], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
```
ではなく
```
 [0, 1, 2, 3], [0, 4, 5, 6], [0, 7, 8, 9]]
```
こうしないとだめだった。
じゃあどうするか。
結局は4つ分の0で配列を作ってあとからA配列を入れていくという感じになる。

```py
H, W, N = map(int, input().split())
A = [list(map(int,input().split())) for _ in range(N)]
#W*Hの配列に0を入れたものを作る（0の分だけ＋１する）
ans = [[0] * (W + 1) for _ in range(H + 1)]
```

こうですね。
で、次にA配列をAnsに入れていくのだけど、
どうするかというと、
1行目〜H行目の配列に（つまりans[i])
最初が０で、その次にAの配列を入れるので
こうなる

```py
for i in range(1, H + 1):
    ans[i] = [0] + A[i - 1][:]
```
これで一回ansを出力

```
 [0, 1, 2, 3], [0, 4, 5, 6], [0, 7, 8, 9]]
```
理想通りできました。
次にここから累積和の配列に仕上げていきます


```
1,2,3
4,5,6
7,8,9
```
このケースで行くと

S(y,x) = A[1][1] + A[1][2] + ... + A[1][x] + A[2][1] + ... + A[2][x] + ... + A[y][1] + ... + A[y][x]
S(1,1) = 1
S(1,2) = 1 + 2 = 3
S(1,3) = 1 + 2 + 3 = 6
S(2,1) = 1 + 4 = 5
S(2,2) = 1 + 2 + 4 + 5 = 12
S(2,3) = 1 + 2 + 3 + 4 + 5 + 6 = 21
S(3,1) = 1 + 4 + 7 = 13
S(3,2) = 1 + 2 + 4 + 5 + 7 + 8 = 27
S(3,3) = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45

※図形で考えると良い。

```
1,3,6
5,12,21
12,27,45
```

で、たとえば（３，３）は
S(3,3) = S(3,2) + S(2,3) - S(2,2)
　　　　= 27 + 21 - 12 + 9 = 45

どうしてこうなるかというと、図形を見ればわかるのだが
たとえばS(3,2)は
 1 + 2 + 4 + 5 + 7 + 8
 ＋
 1 + 2 + 3 + 4 + 5 + 6 
 ー
 1 + 2 + 4 + 5 
 ＋
９
で不要な数字を除外するとあら不思議
１〜９の和になっている。
（不思議でもなんでもないが）

というわけでロジック化でき、以下のようになりました。

```py
H, W, N = map(int, input().split())
A = [list(map(int,input().split())) for _ in range(N)]
#W*Hの配列に0を入れたものを作る（0の分だけ＋１する）
ans = [[0] * (W + 1) for _ in range(H + 1)]

for i in range(1, H + 1):
    ans[i] = [0] + A[i - 1][:]
    #計算して入れていく（もともとある数字に累積和を入れていくので＋＝になる）
    for j in range(1, W + 1):
        ans[i][j] += ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1]

#指定のものを出力する
for _ in range(N):
    y, x = map(int, input().split())
    print(ans[y][x])

```

これで行けるかと思ったら、
A配列の入れ方が悪かったようです。

```py
H, W, N = map(int, input().split())
# #これだとNG
# A = [list(map(int,input().split())) for _ in range(N)]
#これだとOK
A = [[int(x) for x in input().split()] for _ in range(H)]
#W*Hの配列に0を入れたものを作る（0の分だけ＋１する）
ans = [[0] * (W + 1) for _ in range(H + 1)]

for i in range(1, H + 1):
    ans[i] = [0] + A[i - 1][:]
    #計算して入れていく（もともとある数字に累積和を入れていくので＋＝になる）
    for j in range(1, W + 1):
        ans[i][j] += ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1]

#指定のものを出力する
for _ in range(N):
    y, x = map(int, input().split())
    print(ans[y][x])

```
Send Email Quick Actionでドラフトメールを消す、メールテンプレートを消す


+ [Unable to discard draft (Send Email Quick Action)](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007bLDVySAO)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6e126e5b-c2fe-607e-44b3-e0005b7d1160.png)

:::note alert
Can't delete draft. <p style="color:red; font-size:16px">Emails cannot be deleted.<p><p><a href="/_ui/search/ui/UnifiedSearchResults?searchType=2&str="> Click here to return to the previous page. </a> </p>
:::

+ [Removing the Send Email Action Default Email Template](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A7x3VSAR)

:::note
Yes, This will clear and revert with your default email templates.
 

For Example: first time its loaded with your default email templates, and you added some additional text in the body sections, now if you click the "Clear Email and Revert" then its actually cleared the additional text which you added manually and then revert as per the default email templates.

If you like to modify the different email templates then use with Insert, Create or Update Template icons.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/5033bdfe-936e-747e-3eb3-82664c64184f.png)

はい、これはクリアされ、デフォルトの電子メール テンプレートに戻ります。
 
例: 初めてデフォルトのメールテンプレートが読み込まれ、本文セクションに追加テキストを追加しました。ここで「メールをクリアして元に戻す」をクリックすると、手動で追加した追加テキストが実際にクリアされ、元に戻ります。デフォルトのメールテンプレートごとに。
 
さまざまな電子メール テンプレートを変更する場合は、[テンプレートの挿入]、[作成]、または [テンプレートの更新] アイコンを使用します。
:::
【Windows】【開発環境】接続はプライベートではありませんの解決策

# 環境
・Windows11
・React 18.0.2
# 最初の壁
このエラーが最初に出た時、
```
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -subj "/CN=localhost"
```
とコマンドを打って自己署名証明書を作成し、windows＋Rでmmcと入れて証明書スナップインを開き、信頼されたルート機関証明書に証明書をインポートして更にPCを再起動してもどうしても接続はプライベートではありませんの警告が消えず、うまくいきませんでした。
# 次の壁

Let's encryptなどの認証局から無料でルート証明書をダウンロードしようとしましたが、それは本番環境でやることであり、開発環境では自己署名証明書をインポートするものだと知り振り出しに戻ります。
# 解決策

１．まず、どこのディレクトリでもいいので

```
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -subj "/CN=localhost"
```

と打って自己署名証明書を作成します。

２．Windowsの場合、chocolatelyをインストールします。
この時、powershellの管理者として実行してください。

```
$ Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
```
３．chocolatelyでmkcertをインストールします。

```
$ choco install mkcert
```
４．mkcertのインストール後、次のコマンドでlocalhost用の証明書を生成できます。

```
$ mkcert -install
$ mkcert localhost 127.0.0.1 ::1
```
５．生成した証明書と秘密鍵を使用して、ローカルの開発サーバーにHTTPSを設定します。例えば、Node.jsのExpressサーバーを使用している場合は、次のようにHTTPSサーバーを設定できます。
app.jsはReactアプリのルートディレクトリに配置してください。

```app.js
const fs = require('fs');
const https = require('https');
const express = require('express');
const app = express();

const options = {
  key: fs.readFileSync('./localhost.key'),
  cert: fs.readFileSync('./localhost.crt')
};

https.createServer(options, app).listen(3000, function () {
  console.log('HTTPS server listening on port 3000');
});
```
最初に作成した自己署名証明書をコピーして、フロントエンド側のルートディレクトリに置くとコードのままのパスで自己署名証明書が読み込まれます。
この方法により、`https://localhost:3000`でローカルのHTTPSサーバーにアクセスできるようになります。localhostの後の数字は適宜自分の環境に合わせて変更してください。

６．その後、`npm start`すると自己署名証明書のインポートウィザードが開くので、信頼された機関ルート証明書に自己署名証明書をインポートすれば、完了です。

# 感想
何度やっても最初はうまくいかなかったのですが、この方法でやっとhttpsにアクセスすることができました。みなさんも開発環境でSSL認証したいときは、この解決策を試してみてください。

# 追加情報
Reactのアプリでは、最初はhttpsではなくhttpで起動されますが、ルートディレクトリに.envファイルを作って`https=true`と記載することでhttpsで起動することが可能になります。
langflowをM1 MacのDockerで体験しようと思ったら「no matching manifest for linux/arm64/v8 in the manifest list entries」エラー

https://github.com/langflow-ai/langflow

LangChainをGUIでオペレーションできるLangflowを試してみようということで
上記リポジトリをcloneしたら
`langflow/docker_example` にDocker環境のサンプルがあったので早速起動

```bash
okisanjp (arm64):~/workspace/langflow/docker_example
% docker-compose up -d --build
[+] Running 0/2
 ⠴ postgres Pulling                                                                                                                                                            2.6s
 ⠴ langflow Pulling                                                                                                                                                            2.6s
no matching manifest for linux/arm64/v8 in the manifest list entries
```

M1あるある

### docker-compose.yml の各セクションにplatformを追加

```docker-compose.yml
services:
  langflow:
    image: logspace/langflow:latest
    .
    .
    .
```

を

```docker-compose.yml
services:
  langflow:
    platform: linux/x86_64
    image: logspace/langflow:latest
    .
    .
    .
```

のように追記。いくつかセクションがあるので全部に追記します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26917/bda8ae8e-b8fa-afe4-1db7-6f7d6ce4778d.png)

起動しました
db2のADMIN_COPY_SCHEMAがエラーになる人へ

db2のスキーマをコピーする「ADMIN_COPY_SCHEMA」を構文通り実行しているのにエラーになるのは、db2clpで実行していないから。例えばDBeaverで実行すると SQLCODE: -469, SQLSTATE: 42886が発生する。

対処するにはclpでdb2 connect db名して実行すればよい。

かなりハマった(- -;
【Windows】【開発環境】接続はプライベートではありませんの解決策

# 環境
・Windows11
・React 18.0.2

# 最初の壁

このエラーが最初に出た時、
```
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -subj "/CN=localhost"
```
とコマンドを打って自己署名証明書を作成し、windows＋Rでmmcと入れて証明書スナップインを開き、信頼されたルート機関証明書に証明書をインポートして更にPCを再起動してもどうしても接続はプライベートではありませんの警告が消えず、うまくいきませんでした。

# 次の壁

Let's encryptなどの認証局から無料でルート証明書をダウンロードしようとしましたが、それは本番環境でやることであり、開発環境では自己署名証明書をインポートするものだと知り振り出しに戻ります。

# 解決策

１．まず、どこのディレクトリでもいいので

```
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -subj "/CN=localhost"
```

と打って自己署名証明書を作成します。

２．Windowsの場合、chocolatelyをインストールします。
この時、powershellの管理者として実行してください。

```
$ Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
```
３．chocolatelyでmkcertをインストールします。

```
$ choco install mkcert
```
４．mkcertのインストール後、次のコマンドでlocalhost用の証明書を生成できます。

```
$ mkcert -install
$ mkcert localhost 127.0.0.1 ::1
```
５．生成した証明書と秘密鍵を使用して、ローカルの開発サーバーにHTTPSを設定します。例えば、Node.jsのExpressサーバーを使用している場合は、次のようにHTTPSサーバーを設定できます。
app.jsはReactアプリのルートディレクトリに配置してください。

```app.js
const fs = require('fs');
const https = require('https');
const express = require('express');
const app = express();

const options = {
  key: fs.readFileSync('./localhost.key'),
  cert: fs.readFileSync('./localhost.crt')
};

https.createServer(options, app).listen(3000, function () {
  console.log('HTTPS server listening on port 3000');
});
```
最初に作成した自己署名証明書をコピーして、フロントエンド側のルートディレクトリに置くとコードのままのパスで自己署名証明書が読み込まれます。
この方法により、`https://localhost:3000`でローカルのHTTPSサーバーにアクセスできるようになります。localhostの後の数字は適宜自分の環境に合わせて変更してください。

６．その後、`npm start`すると自己署名証明書のインポートウィザードが開くので、信頼された機関ルート証明書に自己署名証明書をインポートすれば、完了です。

# 感想
何度やっても最初はうまくいかなかったのですが、この方法でやっとhttpsにアクセスすることができました。みなさんも開発環境でSSL認証したいときは、この解決策を試してみてください。

# 追加情報
Reactのアプリでは、最初はhttpsではなくhttpで起動されますが、ルートディレクトリに.envファイルを作って`https=true`と記載することでhttpsで起動することが可能になります。
【カスタムGPTs】”Webpilot”→”Show me”のアクションでWeb情報を図解で説明してもらう

## 概要
この記事では、Webから情報を収集し、それを図解で説明するカスタムGPTの作成プロセスを紹介します。WebpilotとShow meの2つのアクションを活用して、情報を視覚的に理解しやすくする方法を学びます。

## 主な内容
#### Webpilotアクションの利用
1. 情報収集の目的定義：収集したい情報の種類と目的を明確にします。
2. 情報収集の設定：情報収集の精度を高めるための外部APIを設定します。
#### Show meアクションでの図解化
1. 情報の整理：収集した情報を整理し、どの情報を図解化するかを決定します。
2. 図解化の設計：情報を視覚的に表示するための外部APIを設定します。

## 手順
### Configureページの作成
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82835/29c0dff1-3c61-c4f5-fcea-adb18bd8d398.png)

##### 「Instructions」へ指示を記載します
```
あなたは、Webから情報を収集し、その内容を図解で説明するのが得意です。

#条件
・ウェブ情報の取得は、「webPilot」アクションを使用して行います。
・情報の図解は、「Show Me」アクションを用いて作成します。

以下の手順に従って考えてください。
#手順
手順１：「webPilot」アクションを使用し、必要なウェブ情報を取得します。
手順２：取得した情報をもとに、「Show Me」で情報を図解化します。図解は具体的で分かりやすいものにしてください。

不明点があれば質問してください
```
##### 「Capabilities」オプション指定とactuonの追加をします
下にスクロールして「Capabilities」オプションのチェックを外します。
「Actions」セクションの[Create new actuon]ボタンをクリックし、外部API（[Diagrams: Show Me](https://chat.openai.com/g/g-5QhhdsfDj-diagrams-show-me)と[WebPilot](https://chat.openai.com/g/g-pNWGgUYqS-webpilot)）を設定します。


### 外部API（Action）を設定
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82835/0dd45914-994a-894a-512a-d42378785f62.png)



#### [「Diagrams: Show Me」](https://chat.openai.com/g/g-5QhhdsfDj-diagrams-show-me)を追加する
`Schema`
https://showme.redstarplugin.com/openapi.json
`プライパシーポリシー`
https://showme.redstarplugin.com/legal

#### [「WebPilot」](https://chat.openai.com/g/g-pNWGgUYqS-webpilot) を追加する（[参考](https://www.webpilot.ai/post-gpts/)）
`Schema`
https://gpts.webpilot.ai/gpts-openapi.yaml
`プライパシーポリシー`
https://gpts.webpilot.ai/privacy_policy.html


:::note info
Diagrams: Show Me、WebPilotともにAPIキーが必要でないため、Authenticationを設定する必要がありません。
:::

## 結論
カスタムGPTを利用したWeb情報の収集と図解化は、情報を効率的に伝達し理解を深める強力な方法です。この記事が提供するガイドラインと実例を通じて、あなたもカスタムGPTの作成に挑戦してみてください。
2週間(30h)でTableau Desktop Specialistに合格した方法



この度、Tableau Desktop Specialistに合格しました。

2週間という短い対策期間ではありましたが、サクッと（とはいえ点数ギリギリ）終えることができたので、今後本試験を受験される方に向けて記事化しました。


## この記事からわかること
・合格までの対策が明確になる
・試験概要をつかむことができる
・試験を通して得られることがわかる
・合格後の方向性がなんとなく把握できる


## 著者スペック
・エンジニア歴半年
・前職でTableauを売っていたので出来ることくらいは知ってた
・最近社内勉強会で使い始めた程度で素人同然

という感じで、ご覧になっている方のほうが理解度が高いなんてこともあるかと思います。


## 試験概要

![スクリーンショット 2024-04-09 131129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3678706/8fba2dbf-81ef-fee4-bf89-551d2fc87efb.png)


## 点数

<b>800/1000</b>でした。
合格基準が750なので、おそらくあと数問くらい間違えていたら落ちていたと思います。


<br>
<b>使用方法や設定に関するこまかーーい問題が多く</b>、正直「いやそんなん知らんし....」と思いながら回答していった覚えがあります。
ただこういったことになったのには明確に対策の仕方に問題があったので、やっておくべきだった対策方法については後述したいと思います。




## 使用教材と活用手順

使用したのは下記です。

①[Tableau Desktop Specialist 認定資格 問題集・過去問[260問収録][2023年12月更新]　](https://note.com/tableau_/n/n368d4f4adf9e)
②Tableau Desktop（Tableau PublicでもOK）

<br>
①では、tableauの仕様・操作/表現方法を詰め込みます。

この問題集の良いところは、解答に多くの図やヘルプがあることです。
また、問題形式は実際の試験とほぼ同じなので、やり込むことで本番の時に落ち着いて回答できるかと思います。

<br>

②では、①で出てきた仕様・操作/表現方法を実際に再現します。
再現する際に使用するデータソースは、インストール時にデフォルトで用意されている<b>サンプル-スーパーストア.xls</b>でよいかと思います。(Tableau Publicを使用する場合は[こちら](https://public.tableau.com/app/learn/sample-data)の一番上にある<b>「スーパーストアの売上」</b>をダウンロードして使用してください)

データソースの接続方法がわからない方は下記記事をご参考ください。
[【Tableau入門】Tableauをそこそこいじれるようになるまで①（データの接続・共有）](https://qiita.com/yn_ZEAL/items/fcdf21f49c0130151bce)

<br>
私は<b>②の取り組みが不十分だった</b>ことで、前述のように操作方法に関する問題を見たときに「いやそんなん知らんし....」となってしまいました。

①で出てきた仕様・操作/表現方法を漏れなく確認しておくことで、私よりも高得点を取れるかと思います。


<br>

※受験までに多少時間があり、なおかつTableauの操作にもっと慣れたいという方は木田和廣さんの「[データサイエンティストを目指す人のための『ゼロからの Tableau 入門』](https://www.udemy.com/course/tableau-x/?couponCode=ST8MT40924)」がおすすめです。定期的に行われるUdemyのセールでは、<b>約2000円</b>で教材を購入することができます。


## この試験を受けるメリットは？

本試験は上級資格Tableau Data Analystとは違って実技が無いです。

その点だけ考えればあまり実践向きではないかと思いますが、本試験ではTableauのトリセツ的な問題が多く出題されるため、<b>対策をしていく中で製品の取り扱いがわかるようになり、自分自身が使用する上で無駄な操作をすることが減りますし、顧客へレクチャーするとなった場合もスムーズに行えるようになる</b>かと思います。
<br>

私のように利用経験が無いor浅い方にとっては、今後実務で使用するための土台固めとしてかなり有用でした。


## 合格後、次なる目標は？

近いうちに業務でTableauを使うことになりそうなので、今後はTableauを高度に操作できるようになることを目標に、個人学習でVizを作ったり、Tableau Data Analyst資格とData Saber認定の取得をしていきたいと思います。

私と同じような立場の方も多いかと思いますので、今後の取り組みについてもQiitaで発信していく予定です。

<br>
Tableau Desktop Specialist受験に関して、少しでも参考になれば幸いです。


## ご紹介

株式会社ジールでは、「ITリテラシーがない」「初期費用がかけられない」「親切・丁寧な支援がほしい」「ノーコード・ローコードがよい」「運用・保守の手間をかけられない」などのお客様の声を受けて、オールインワン型データ活用プラットフォーム「ZEUSCloud」を月額利用料にてご提供しております。
ご興味がある方は是非下記のリンクをご覧ください：
https://www.zdh.co.jp/products-services/cloud-data/zeuscloud/?utm_source=qiita&utm_medium=referral&utm_campaign=qiita_zeuscloud_content-area
Node.jsプロジェクトでの環境変数の扱い方

# はじめに
Node.jsプロジェクトにおいて、環境変数の管理は非常に重要です。このブログでは、.env ファイルと globals.ts モジュールを使用して、環境変数を効率的に管理する方法について説明します。

アプリケーションの設定情報をコードから分離することは、セキュリティのベストプラクティスとされています。特に、データベースの接続情報やAPIキーなどの機密情報は、公開されるべきではありません。.envファイルを使用することで、これらの情報を安全に管理し、異なる環境（開発、ステージング、本番）でのアプリケーションの動作を容易に切り替えることができます。

# ステップ 1: 環境変数の設定
.envファイルは、キーと値のペアで構成され、アプリケーションが実行される環境に応じて異なる設定を提供します。dotenvライブラリを使用することで、これらの環境変数をアプリケーションの起動時に読み込み、プロセスの環境変数として利用できるようになります。
```.env
# okta credentials
SSH_USERNAME="ssh-username"
SSH_PASSWORD="some-password"
# couchbase credentials
COUCHBASE_USERNAME="couchbase-user"
COUCHBASE_PASSWORD="couchbase-password"
# elastic DB
ELASTIC_AUTH="user:password"
# mysql
MYSOL_USERNAME="mysql-user"
MYSQL_PASSWORD="mysql-password"
```

# ステップ 2: globals.ts の作成
globals.ts ファイルは、アプリケーション内で共通して使用される設定情報を一元管理するためのモジュールです。このファイル内で、dotenvを使用して.envファイルから環境変数を読み込み、必要な設定情報をエクスポートします。これにより、アプリケーション全体で一貫性のある設定情報を簡単に利用できるようになります。
### 実装例
```
npm install dotenv --save-dev
```
```typescript:globals.ts
import os from "os";
import dotenv from "dotenv";

dotenv.config();

const sshUserName = process.env["SSH_USERNAME"];
const globals = {
  //jump server
  OS_USERNAME: os.userInfo().username,
  REMOTE_HOST: "<remote-ip>",
  KIBA_USERNAME: sshUserName,
  KIBA_PASSWORD: process.env["SSH_PASSWORD"] || "",
  LISTENING_PORT: 2205,
  CLUSTER_VIP: "<cluster-vip>",

  //robin
  NAMESPACE: "robin-namespace",
  TENANT: "robin-tenant",
  ROBIN_PORT: 12345,

  //couchbase
  COUCHBASE_HOST_DOMAIN: "host-domain(ipv4 or ipv6)",
  BUCKET: "bucket",
  COUCHBASE_USERNAME: process.env["COUCHBASE_USERNAME"],
  COUCHBASE_PASSWORD: process.env["COUCHBASE_PASSWORD"],

  //elastic database
  ELASTIC_AUTH: process.env["ELASTIC_AUTH"],
  
  //mysql database
  MYSQL_USERNAME: process.env["MYSQL_USERNAME"] || "",
  MYSQL_PASSWORD: process.env["MYSQL_PASSWORD"] || "",
  MYSQL_PORT: 1234,

  // project path
  REMOTE_DOC_PATH: `/home/${sshUserName}/documents`,
  LOCAL_DOC_PATH: "output/documents",
};

export default globals;
```
この例では、globals.ts ファイル内で環境変数を読み込み、デフォルト値を設定しています。これにより、環境変数が設定されていない場合でも、アプリケーションが正常に動作するようになります。

# ステップ 3: globals.ts の利用
アプリケーションの他の部分で globals.ts をインポートし、設定情報にアクセスします。例えば、Express.js のサーバーを設定する際に globals.ts からポート番号を取得することができます。
```typescript:server.ts
import express from 'express';
import globals from './globals';

const app = express();
const port = globals.port; // globals.ts からポート番号を取得

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});
```
# 利点と潜在的な課題
このアプローチの最大の利点は、設定情報の中央管理にあります。これにより、コードの可読性が向上し、設定の変更が必要な場合に一箇所の修正で済むようになります。ただし、.envファイルやglobals.tsモジュールのセキュリティを確保することが重要です。例えば、これらのファイルを誤ってソースコード管理システムにコミットしないように注意する必要があります。

# まとめ
.envファイルとglobals.tsモジュールを使用することで、Node.jsプロジェクトにおける設定管理を効率的かつ安全に行うことができます。このアプローチを採用することで、開発プロセスがスムーズになり、アプリケーションのセキュリティが向上します。
Salesforce AI 関係するトレイルヘッド

[SalesforceとAIに戻る](https://qiita.com/Keiji_otsubo/items/79334ed32fb5cc2d0eb3)

+ [Quick Start: Prompt Builder Get Started with Prompt Builder](https://qiita.com/Keiji_otsubo/items/2b37916fc3b0f7eef085)
+ [Quick Start: Einstein Copilot Connect Your Flows to Einstein Copilot](https://qiita.com/Keiji_otsubo/items/8e9407ef77b01a0c5b30)
+ [Module : Einstein Copilot](https://qiita.com/Keiji_otsubo/items/7885b4cb4587b01c8119)
+ [Einstein Copilot のトレイルヘッド](https://qiita.com/Keiji_otsubo/items/0db043d2fa23ecdf058a)
+ [セールス向け Einstein 会話インサイト](https://qiita.com/Keiji_otsubo/items/fb34540089340844a9e8)



---------------------
+ [Create and Ground Prompt Templates : Sales Email does not appear as an option. ](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007bKxJ4)
:::note
this happened to me too. You need to turn on sales emails in settings. 
Turn on Sales Emails.
From Setup, enter einstein for in the Quick Find box, then select Einstein for Sales.
Turn on Sales Emails. It can take a few minutes before it’s ready to use.
Assign the Einstein Sales Emails permission set to your users.
Here's the documentation: https://help.salesforce.com/s/articleView?id=sf.einstein_gpt_sales_emails_setup.htm&type=5 
これは私にも起こりました。設定で営業メールをオンにする必要があります。
セールスメールをオンにします。
[設定] から、[クイック検索] ボックスに「einstein for」と入力し、[Einstein for Sales] を選択します。
セールスメールをオンにします。使用できるようになるまでに数分かかる場合があります。
Einstein Sales Emails 権限セットをユーザに割り当てます。
ドキュメントは次のとおりです: https://help.salesforce.com/s/articleView?id=sf.einstein_gpt_sales_emails_setup.htm&type=5
:::

+ [In Prompt builder, while creating new Template,I am not getting option of 'Sales Email' also how to enable "Draft with Einstein' button while sending email from Feed.Please have a llok on attachment.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007bLBIj)

上記と同じだけど、私の環境にもないな。

+ [Loyalty Management and Data Cloud Integration >Set Up the Org](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ahqle)
:::note
Are you doing this module?
Since this module is in a quiz format, I don't think there will be a similar org in the playground.
https://trailhead.salesforce.com/content/learn/modules/prompt-builder-basics/create-and-ground-prompt-templates
:::

+ [プロンプト テンプレートを作成しようとしたときに、セールス メール オプションが表示されません。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cmI20)

:::note
実際、プロンプト タイプ テンプレート: 営業メール機能は無料の組織では利用できません。プロンプト ビルダーで営業メール プロンプト テンプレートを作成するには、組織で Einstein for Sales、Einstein for Platform、または Einstein for Service アドオン機能を有効にする必要があります。

このモジュールには複数の選択肢がある質問があるため、コンテンツを読み、MCQ を完了してモジュールを正常に完了してください。
:::
ブックマークレットで発生するClipboard APIの "Document is not focused." をなんとかする

久々にまともなやつ。

# やること
- JavaScriptで何かしらの情報をクリップボードへコピーするブックマークレットを作る

# 道具
- Clipboard API

https://developer.mozilla.org/ja/docs/Web/API/Clipboard_API

# 背景
昔は、`document.execCommand("copy");` というコードがありました。
ただ、こいつ今は非推奨なんですよね……

https://developer.mozilla.org/ja/docs/Web/API/Document/execCommand

で、代わりになるClipboard APIという便利なAPIが登場しました。
登場からもうかれこれ5年以上は経過しているはず[未確認]で、最初は対応していないブラウザも多く、まだまだ`execCommand()`が使われていましたが、現在はもう（基本機能は）だいたいのブラウザで使えるはずです。

しかし、新しいAPIはとてもしっかりものなので、セキュリティがガッチリしているんですよね。~~は～～～面倒～～～~~

例えば、デベロッパツールでコンソールを開いて、次のような`execCommand()`を使用したコードを実行してみます。
開いているページのURLをクリップボードにコピーするコードです。

```useExecCommand.js
textBox = document.createElement("textarea");
textBox.setAttribute("id", "target");
textBox.setAttribute("type", "hidden");
textBox.textContent = location.href;
document.body.appendChild(textBox);
textBox.select();
document.execCommand("copy");  // ここでクリップボードにコピー
document.body.removeChild(textBox);
```

ちょっと長いですが、これでクリップボードにURLをコピーできます。
古き良き、って感じです。

では、これをClipboard APIを使うとどうなるか。こんな感じです。

```useClipboardAPI.js
navigator.clipboard.writeText(location.href);
```

い、1行？？？？？
かがくの　ちからって　すげー！▼

……が、そうは問屋が卸しません。
このコードを実行すると無慈悲にもエラーが発生します。

```
Uncaught (in promise) DOMException:
Failed to execute 'writeText' on 'Clipboard': Document is not focused.
```

Clipboard APIではユーザが明示的にコピーを指示するなど、ドキュメント自身にフォーカスが当たっていないとエラーが返ります。
デベロッパツールでこのコードを実行したとき、フォーカスはデベロッパツールに当たっているのであり、ドキュメントには当たっていない、という判断です。~~は～～～融通効かね～～～~~

ここまで簡単のためデベロッパツールで実験しましたが、当然このコードをブックマークレットに落とし込んでも同じエラーが発生します。
ブックマークレットでこの問題を解決するにはどうしたら良いでしょう？

# 解決したい問題
ブックマークレット上でClipboard APIを使うとき、ドキュメントにフォーカスが当たらない問題を解決するには？

# 答え
すごく単純で、Clipboard APIの実行を少し遅らせるだけで大丈夫なんだそう。~~何で？？？~~

```delayedExecAPI.js
setTimeout(() => navigator.clipboard.writeText(location.href), 500);  // 500ms遅らせて実行
```

何で？って書きましたが、答えは先人↓が調査してくれています。~~つまり丸パクリです。~~

https://blog.hog.as/entry/2021/09/30/021450

~~こういうのをGoogle検索くんには出してほしいんですよ。無価値なまとめサイトと広告サイトをトップに持ってくるな。~~

デベロッパツールでは相変わらず「フォーカスが当たってねえよ！」って怒られますが、ブックマークレットではちゃんと動いてくれます。

これで非推奨の`execCommand()`くんとさよならできます。R.I.P.


# おまけ
自分で作ったブックマークレットです。開いているページのURLとページタイトルを、`[ページタイトル], [URL]`のフォーマットでクリップボードにコピーしてくれます。引用情報として利用するときに便利！

```copyTitleAndUrl.js
// URLとタイトルを連結
var copyText = `${document.title}, ${location.href}`;

// クリップボードにコピー
setTimeout(() => navigator.clipboard.writeText(copyText), 500);

// コピーしたことをアラートで表示
alert(`Copied to clipboard:\n${copyText}`);
```

コンパイル後のコードは↓

```compiledCode.js
javascript:var a=`${document.title}, ${location.href}`;setTimeout(()=>navigator.clipboard.writeText(a),500);alert(`Copied to clipboard:\n${a}`);
```

ブックマークレット作成のおとも↓

https://closure-compiler.appspot.com/home


ちなみに、今回のブックマークレットで↓のような文字列をクリップボードにコピーできます。

> ブックマークレットで発生するClipboard APIの "Document is not focused." をなんとかする #JavaScript - Qiita, https://qiita.com/kuroan/items/0d1e0d7dd0abfe57ce9a

なおドメインごとに、このブックマークレットを実行する際に、下図のようなクリップボードへのコピーを許可するか確認するダイアログが表示されます。これもセキュリティ対策ですね、しっかりしてらぁ。

![2024-04-09_12h59_18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68786/e7969520-8d55-78d7-42ca-b8da7a6f0a9e.jpeg)
ip+portでは問題ないんだけど、domain名でアクセスするとwebsocket接続エラー(ws/wss)

結論：　下記通り、nginx.conf->locationの設定を追加して解決した

```shell
location / {

# その他設定

  #　websocket接続エラー解決するため --start  
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "Upgrade";
  # websocket接続エラー解決するため --end

# その他設定
}
```
タイ語モデルopenthaigpt-1.0.0-7b-chatは「แม่อย่าเก็บไว้คนเดียว」をどうトークナイズするのか

OpenThaiGPTから「[openthaigpt-1.0.0-7b-chat](https://huggingface.co/openthaigpt/openthaigpt-1.0.0-7b-chat)」が[リリースされた](https://openthaigpt.aieat.or.th/openthaigpt-1.0.0-less-than-8-apr-2024-greater-than)ので、とりあえずトークナイザを試してみることにした。

```
>>> from transformers import AutoTokenizer
>>> tkz=AutoTokenizer.from_pretrained("openthaigpt/openthaigpt-1.0.0-7b-chat")
>>> print(tkz.convert_ids_to_tokens(tkz("แม่อย่าเก็บไว้คนเดียว")["input_ids"]))
['
', '▁แม', '่อย', '่า', 'เก็บ', 'ไว้', 'คนเดียว']
```

「[แม่อย่าเก็บไว้คนเดียว](https://qiita.com/KoichiYasuoka/items/851bbe0299f43c7eb4e9)」をトークナイズしてみたところ、単語の切れ目が「แม่」「อย่า」「เก็บ」「ไว้」「คน」「เดียว」になっておらず、非常に気持ち悪い。もう少し細かくみてみよう。

```
>>> for t in tkz.convert_ids_to_tokens(tkz("แม่อย่าเก็บไว้คนเดียว")["input_ids"]):
...   print(" ",t)
...
  

  ▁แม
  ่อย
  ่า
  เก็บ
  ไว้
  คนเดียว
```
「เก็บ」「ไว้」の2単語を除いて、残りはボロボロだ。タイ文字クラスター(คลัสเตอร์อักษรไทย)すら、完全に無視してトークナイズしている。うーん、正直なところ使いにくすぎるなぁ。
package.json の依存関係を簡単にアップグレード

# 前回までのおさらい

https://qiita.com/Qiitakumin/items/914602de042e029ba7f4

# npm-check-updates

>npm-check-updates は、指定されたバージョンを無視して、 package.json の依存関係を最新バージョンにアップグレードします。

https://github.com/raineorshine/npm-check-updates

## そもそもバージョンアップなら npm update でいいのでは？
>`npm update`のコマンド実行によって package.json の内容から依存関係のバージョンの記載の範囲内の最新版をインストールして package-lock.json や node_modules を更新します。

`npm update`のコマンドだと、
package.json に記載されている範囲の中でしか最新のバージョンでアップデートしない

:::note warn
例：^3.2.1 と記載されている場合、4.0.0 が世の中にリリースされても npm update では気づけない。
:::

## 実際に使ってみる

### インストール
グローバルにインストールします。
```shell
npm install -g npm-check-updates
```
### インタラクティブモードで実行

```shell
ncu -i
```

#### 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329005/e20abca5-2d0a-172d-b5da-348095ae36f4.png)

#### 結果からアップグレードするのを選んでみる
`@types/react`のみ選択して、Enter！！

:::note warn
全て選択されてしまい、余計なものまでアップデートしてしまった...
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329005/9e61818c-905c-fb8a-4440-9cc12689f7eb.png)
補足）色の違いは、アップデートの種類らしい。（[ドキュメント参照](https://github.com/raineorshine/npm-check-updates?tab=readme-ov-file#interactive-mode)）

#### どうすれば良いのか・・・
:::note info
spaceキーでアップデートするものをトグル選択できる！！
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329005/c7cb8a62-b4a4-c599-1ec0-0c4d55fa3d38.png)

`npm i`も一緒にできていい感じ！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329005/92514718-359d-c25e-17d2-a5725ba9f7eb.png)

### 個人的なおすすめ実行方法
>組み合わせて、--format group本当に贅沢な体験をお楽しみください

豪華な体験を味わえるのでぜひ実行してみてください

```shell
ncu -i --format group
```
#### 豪華な体験結果
:::note info
バージョンの種類ごとに出力してくれる
:::
補足）npm バージョンとはについては[こちら](https://zenn.dev/aa/articles/8a06ce9f6d1866)を参照ください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329005/d36603d4-f720-6cb0-f635-bc61bb039880.png)


## 参考
https://zenn.dev/ikuraikura/articles/85a6d6cc9398502e8569

https://qiita.com/monji586/items/eaf1252d917022555889

https://zenn.dev/aa/articles/8a06ce9f6d1866

https://zenn.dev/yoshii0110/articles/820187fd237b44

# 次回予告

https://qiita.com/Qiitakumin/items/2ccfa99d2b4e58b8ae23
macOSのリソースの情報をコマンドで取得する

# What's？

macOSのリソースの情報をコマンドで取得したくなることがたまにあるのですが、いつも忘れて調べ直しているのでメモとして。

# 環境

```shell
$ sw_vers
ProductName:            macOS
ProductVersion:         14.3.1
BuildVersion:           23D60
```

# ハードの情報を確認する

```shell
$ system_profiler SPHardwareDataType
```

https://support.apple.com/ja-jp/102767

# CPU数、コア数を確認する

CPU数

```shell
$ system_profiler SPHardwareDataType | perl -wnl -e 'print $1 if /Number of Processors: (\d+)/'
```

コア数

```shell
$ system_profiler SPHardwareDataType | perl -wnl -e 'print $1 if /Total Number of Cores: (\d+)/'
```

# CPU使用率を確認する

```shell
$ top | grep 'CPU usage'
```

# メモリ搭載量を確認する

```shell
$ system_profiler SPHardwareDataType | perl -wnl -e 'print $1 if /Memory: (.+)/'
```

# メモリ使用率を確認する

```shell
$ top | grep 'PhysMem'
```

# ストレージ使用率を確認する

```shell
$ df -h
```

macOSだと、CPUやメモリの使用率は`top`コマンド中心になるんだな、と。
Tailscale(VPN)とVSCode Remote SSHでサクッとSSH接続

# はじめに
### やりたいこと

1\. お手軽なVPNサービス「Tailscale」を使って、
2\. Visual Studio CodeのRemote SSHで簡単にSSH接続します

### 具体的な手順
今回はUbuntuサーバーを設定し(WSLでも可)、MacやWindowsからサーバーにSSH接続します。
以下の手順で進めていきます。

1\. Tailscaleのインストール
2\. Ubuntuサーバーの構築
3\. 公開鍵・秘密鍵の設定
4\. VSCodeの設定

## 1. Tailscaleのインストール
こちらは公式ドキュメントを参照しながら進めていきます。
https://tailscale.com/download

インストールを完了すると登録されたデバイスはTailscaleの管理画面で以下のように確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471633/a3765463-9618-09e7-8a3c-6b206b04b52c.png)

## 2. Ubuntuサーバーの構築

Ubuntuでは**openssh-server**パッケージをインストールするだけです。

1\. OpenSSHサーバーをインストールします

```sh
sudo apt install -y openssh-server
```

2\. SSHを始動させます

```sh
sudo systemctl start ssh
```

3\. SSHを自動起動に設定します

```sh
sudo systemctl enable ssh
```

## 公開鍵・秘密鍵の設定
### クライアント側

まずは、クライアント側で公開鍵・秘密鍵を作成していきます。
MacとWindowsに分けて説明します。


#### Windows

1\. Windows Powershellを起動します

2\. `ls`で「.ssh」ディレクトリがあることを確認し、なければ`mkdir .ssh`で作成します

3\. `ssh-keygen -t ed25519 -f .ssh/任意の名前`
※後工程、**秘密鍵のパス**を使用することになり、`.ssh/任意の名前`を**秘密鍵のパス**とします

4\. パスワードを設定します
```sh
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
```

5\. 鍵ペアの生成場所は「C:\Users\【ユーザー名】\.ssh」内となります

6\. 「C:\Users\【ユーザー名】\.ssh」内の`.pub`データをVSCodeあるいはテキストエディタで開きます
※`.pub`データの文字列が公開鍵とります。

#### Mac

1\. ターミナルを起動します

2\. `ls -a`で「.ssh」ディレクトリがあることを確認し、なければ`mkdir .ssh`で作成します

3\. `ssh-keygen -t ed25519 -f .ssh/任意の名前`
※後工程、**鍵のパス**をしようすることになり、`.ssh/任意の名前`を**鍵のパス**とします

4\. パスワードを設定します
```sh
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
```

5\. 「.ssh」ディレクトリに`任意の名前`（秘密鍵）と`任意の名前.pub`（公開鍵）が生成されていることを確認します

6\. `.pub`データをVSCodeあるいはテキストエディタで開きます
※`.pub`データの文字列が公開鍵とります。

### サーバー側
クライアント側で作成した公開鍵を登録します。

1\. サーバー側の「.ssh」内に「authorized_keys」ファイルを作成します
※「.ssh」ディレクトリがなければ、`mkdir .ssh`で作成し、空の「authorized_keys」ファイルを作成します。

2\. 「authorized_keys」ファイルをテキストエディタなどで開き、公開鍵（`.pub`ファイル）の中身をコピペします
※あるいは`echo "<公開鍵の中身>" >> ~/.ssh/authorized_keys`を実行する。

3\. `chmod 600 ~/.ssh/authorized_keys`でファイルのパーミッション（権限）を変更します（初回のみ）。

### テストでSSH接続

上記の設定でSSH接続が完了しました。
ちゃんとSSH接続ができるか確認してみます。

1\. `ssh -i <秘密鍵のパス> <接続先ユーザー名>@<接続先ホスト名 or IPアドレス>`でSSH接続します
※<接続先ユーザー名>はUbuntuのユーザー名です。
※<接続先ホスト名 or IPアドレス>はTailscaleの管理者画面のADDRESSESで確認できます。

2\. 接続先のサーバーのパスワードを入力します

3\. yesを入力します（初回のみ）

4\. 接続を確認して、`exit`コマンドを実行し、ログアウトします

## VSCodeの設定

sshコマンドを短縮する（エイリアス定義）ための設定をしていきます。 

1\. VSCodeの拡張機能である「Remote SSH」をインストールします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471633/829d8dea-0d5c-3646-31e4-30ffc3810f38.png)

2\. クライアントの「.ssh」ディレクトリをVSCodeで開いて、「.ssh/config」ファイルを作成します

3\. configファイル内に以下のコードを記載します
※<接続先エイリアス名>はわかりやすい名前をつけます

```
Host <接続先エイリアス名>
    HostName <接続先ホスト名 or IPアドレス>
    User <接続先ユーザー名>
    IdentityFile ~/.ssh/<秘密鍵名>
```

4\. VSCodeのリモートエクスプローラーからSSH接続します

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471633/ac77e015-36de-e2da-56cf-68faefb8ff72.png">

5\. SSHキーのパスワードを求められるため、「秘密鍵・公開鍵の設定」の項目で設定したパスワードを入力します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471633/0c471d5e-fb68-2d9a-9513-b4e6cac72a21.png)

これでサクッとSSH接続ができました！
pythonのclassとか__init__とか

参考

https://python.ms/class/#%E3%81%AF%E3%81%97%E3%82%99%E3%82%81%E3%81%AB



```
>>> class Human:
...     name = 'andi'
...     def say(self):
...             print('こんにちは！')
...     def friend(self):
...             print('judi')
...
>>> i = human()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'human' is not defined. Did you mean: 'Human'?
>>> i = Human()
>>> i.say()
こんにちは！
>>> i.friend()
judi
```
追加も可能
```
>>> i.height
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Human' object has no attribute 'height'
>>> i.height = 178#インスタンス化してから名前を付けている
>>> i.height
178
```

追加がめんどくさい、、、
```
>>> class Human:
...     name = 'andi'
...     def say(self):
...             print('こんにちは！')
...     def friend(self):
...             print('judi')
...     def __init__(self):
...             self.height = 178
...
>>> i = Human()#インスタンス化するときに__init__が自動的に呼び出される。
>>> i.height
178
```

アンダーバーのやつはまだまだわからないことだらけだけど（__init__,__del__,__str__）すこしずつ理解します。
splash screen

理解を助けるために、スプラッシュ画面のカスタマイズの例を示します。以下は、Kotlinでの基本的なスプラッシュ画面の実装とそのカスタマイズです。レイアウトファイル (res/layout/activity_splash.xml):<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/splash_background"
    android:gravity="center">

    <ImageView
        android:id="@+id/splash_logo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_splash_logo" />

</RelativeLayout>
スプラッシュ画面のアクティビティ (SplashActivity.kt):class SplashActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_splash)

        // スプラッシュ画面の表示時間を設定
        Handler().postDelayed({
            // ここでメイン画面に遷移する処理を記述
            val intent = Intent(this, MainActivity::class.java)
            startActivity(intent)
            finish()
        }, SPLASH_DELAY)
    }

    companion object {
        private const val SPLASH_DELAY = 2000L // ミリ秒単位でスプラッシュ画面を表示する時間を設定
    }
}
テーマの変更 (res/values/styles.xml):<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- スプラッシュ画面の背景色を設定 -->
    <item name="splash_background">@color/splash_background</item>
    <!-- スプラッシュ画面のテキストカラーを設定 -->
    <item name="splash_text_color">@color/splash_text_color</item>
</style>
この例では、スプラッシュ画面のレイアウトや表示時間、背景色、ロゴなどをカスタマイズしています。それぞれのファイルやコード部分で変更された点を確認してください。


AndroidManifest.xmlファイルでスプラッシュ画面のアクティビティを宣言する必要があります。これにより、アプリが起動した際にスプラッシュ画面が表示されるようになります。以下は、AndroidManifest.xmlファイルでスプラッシュ画面のアクティビティを宣言する方法の例です：<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".SplashActivity"> <!-- スプラッシュ画面のアクティビティを宣言 -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity"> <!-- メイン画面のアクティビティを宣言 -->
            ...
        </activity>
        ...
    </application>

</manifest>
上記の例では、SplashActivityがandroid.intent.action.MAINとandroid.intent.category.LAUNCHERのインテントフィルターで指定されています。これにより、アプリが起動するときにスプラッシュ画面が表示されるようになります。
【React】【例】 クラスコンポーネントから関数コンポーネントへ書き換え



**クラスコンポーネント**

```js

import React, { Component } from "react";

class Text extends Component {
  render() {
    const text = this.props.text;

    return <div style={{ color: "green" }}>{text}</div>;
  }
}

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      text: ""
    };
  }

  render() {
    const text = this.state.text;

    return (
      <div>
        <h1>
          <Text text={text} />
        </h1>
        <input
          type="text"
          value={text}
          onChange={e => {
            this.setState({
              text: e.target.value
            });
          }}
        />
      </div>
    );
  }
}
```
↓

**関数コンポーネント**

```js

import React, { useState } from "react";

function Text(props) {
  return <div style={{ color: "green" }}>{props.text}</div>;
}

export default function App() {
  const [text, setText] = useState("");

  return (
    <div>
      <h1>
        <Text text={text} />
        入力して下さい
      </h1>
      <input
        type="text"
        value={text}
        onChange={e => {
          setText(e.target.value);
        }}
      />
    </div>
  );
}
```
DOMとは

## DOMとは

DOMツリーは、HTMLドキュメントを表現するツリー構造です。木のように、各要素が枝分かれして繋がっています。


HTMLドキュメントの構造を理解しやすい: 視覚的に分かりやすく、ドキュメント全体の構成を把握しやすくなります。
要素へのアクセス・操作が容易: JavaScriptで特定の要素を操作したり、スタイルを変更したりする際に役立ちます。


![HTML-Document-Object-Model-DOM-three-of-objects.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1564975/c8ff7a4b-805f-0ff3-4670-aa66d8a543d4.png)


## サンプルコード
```html
<html>
  <head>
    <title>DOMツリーの例</title>
  </head>
  <body>
    <h1>タイトル</h1>
    <p>本文です</p>
    <ul>
      <li>項目1</li>
      <li>項目2</li>
    </ul>
  </body>
</html>
```

```
Document
  |- HTML
    |- Head
      |- Title
    |- Body
      |- H1
      |- P
      |- Ul
        |- Li
        |- Li
``` 


| 関係 | 説明 |
|---|---|
| Document | DocumentノードはDOMツリーのルート要素であり、すべての要素の親要素となります。 |
| HTML | HTML要素はDocumentノードの子要素であり、Webページ全体の構造を定義します。 |
| Head | Head要素はHTML要素の子要素であり、メタデータやスタイルシートなどの情報を格納します。 |
| Title | Title要素はHead要素の子要素であり、Webページのタイトルを表示します。 |
| Body | Body要素はHTML要素の子要素であり、Webページのコンテンツを表示します。 |
| H1 | H1要素はBody要素の子要素であり、Webページの見出しレベル1を表示します。 |
| P | P要素はBody要素の子要素であり、段落を表示します。 |
| Ul | Ul要素はBody要素の子要素であり、箇条書きリストを表示します。 |
| Li | Li要素はUl要素の子要素であり、箇条書きリストの各項目を表示します。 |
| Siblings(従兄弟) | 同じ親要素を持つ要素同士を兄弟要素と呼びます。例えば、Body要素の子要素であるH1、P、Ulは兄弟要素となります。 |
| Descendants(子孫) | ある要素の子要素とその子要素の子要素…というように、すべての後継要素をdescendantsと呼びます。例えば、H1要素の子要素であるP要素は、H1要素のdescendantsとなります。 |
| Ancestors(先祖) | ある要素の親要素とその親要素の親要素…というように、すべての先祖要素をancestorsと呼びます。例えば、Li要素の親要素であるUl要素、Ul要素の親要素であるBody要素は、Li要素のancestorsとなります。 |

## 参考
DOM について
https://tcd-theme.com/2021/05/javascript-dom.html

Tree 構造について
https://ja.wikipedia.org/wiki/%E6%9C%A8%E6%A7%8B%E9%80%A0_(%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0)


# 発音記号
English pronunciation of descendant 

How to pronounce descendant
 UK/dɪˈsen.dənt/
 US/dɪˈsen.dənt/
Viteを使ったReact環境構築【個人メモ】

## React環境構築
ターミナルを開いて、下記のコマンドを入力する
フォルダを作成したい場所に移動する
例：デスクトップ
```terminal:ターミナル
% cd Desktop
```
次に下記のコマンドを入力。
```terminal:ターミナル
% npm create vite@latest
```
プロジェクトの名前を聞かれるので、任意に決める
```terminal:ターミナル
? Project name: › vite-project
```
作成したいプロジェクト種類を決める
```terminal:ターミナル
? Select a framework: › - Use arrow-keys. Return to submit.
❯   Vanilla
    Vue
    React
    Preact
    Lit
    Svelte
    Solid
    Qwik
    Others
```
```terminal:ターミナル
? Select a variant: › - Use arrow-keys. Return to submit.
    TypeScript
❯   TypeScript + SWC
    JavaScript
    JavaScript + SWC
    Remix ↗
```
あとは順番にコマンドを入力すれば、ローカルサーバー環境が構築できる
```terminal:ターミナル
cd app
  npm install
  npm run dev
```
Macでzip ~作成される.DS_Storeと_MACOSX問題に対応する~

## Mac対応
Finderでzipを行うと_MACOSXや.DS_Storeが含まれる。
ターミナルでzipすれば_MACOSXは作成されない。ここからさらに.DS_Storeを除外する

### ターミナルでzipコマンドを利用する。
```sh::
zip ファイル名.zip -r ファイル名/ -x "*.DS_Store"
```
-r：再起的にしフォルダ対応
-x：除外

#### 暗号化する場合 -e
```sh::
zip -e ファイル名.zip -r ファイル名/ -x "*.DS_Store"
```

## 既存ファイル・フォルダ削除
ルートから検索し削除
```sh::
find . -name ".DS_Store" -print -exec rm {} ";"
```

## Windowsで既存ファイル・フォルダ削除
#### ①_MACOSXがあるパスを検索
```sh::
dir /s/b _MACOSX .DS_Store
```
/s：サブフォルダを含む
/b:パスだけで表示

#### ②削除
```sh::
rd /s/q _MACOSX
del .DS_Store
```
/s：サブフォルダを含む
/q：強制削除


## 備考
ターミナルで.DS_Store　を作成しないよう設定できるらしいが、毎回叩く必要がある？(未確認)
```sh::
defaults write com.apple.desktopservices DSDontWriteNetworkStores true
```
【ChatGPT＋DALL-E3】赤十字マークは使っちゃダメ！


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

　今回は、赤十字マークについてです。

:::note info
本記事は、ChatGPT（有料版）
＋DALL-E3で行なっております。
画像はありません。あしからず。
:::

　みなさん、ご存知でしたか？

　赤十字マーク、
　　勝手に使うと、
　　　罰せられる、って。

　昨日（2024/04/08）、
　　X-Twitterで、
　　　そんなポストがありまして。

　調べてみたら
　　確かにそうです。
***
***Google SGE***
赤十字マークは、戦争や紛争などで傷ついた人々と、その人たちを救護する軍の衛生部隊や赤十字の救護員・施設等を攻撃から守るために使用（表示）するマークです。﻿

赤十字マークは、ジュネーブ条約によって正当な理由なく使ってはいけないとされ、不当な使用は法律違反で罰則付きです。赤十字社と法律等に基づいて認められている組織に限って使用することができ、一般の病院や医薬品などに使用することは禁止されています。﻿

ただし、武力攻撃事態等においては、指定行政機関の長又は都道府県知事は、医療機関や医療関係者に赤十字等の標章を使用させることができます。﻿

赤十字マークのシンボルマークは、周囲は必ず「白地」にします。シンボルマークの視認性を確保するために、下記の最小使用サイズ以上の大きさで使用します。﻿
***
　詳しくは、
　　以下をごらんください。
[日本赤十字社](https://www.jrc.or.jp/information/2022/1005_028731.html)

　また、
　　こうした記事も
　　　ありました。
[デザインに赤十字マークは使用禁止！ 不当な使用は法律違反で罰則を受けるかも](https://webtan.impress.co.jp/e/2014/07/08/17778)
***
　ともかく、
　　ふつうに
　　　見掛けるようなマークは
　　　　使わない、あるいは
　　　　　使ってもいいかを確認する、
　　　　　　というのが正しいですね。

　そして、
　　どうやら
　　　画像生成AIは
　　　　指定すると描画してしまう、
　　　　　という罠も張られています。
　　　　　　そんなつもりはない
　　　　　　　でしょうけれど。

　DALL-E3も
　　描画してしまいました😅

　ガンダムや
　　セーラームーンや
　　　ドラゴンボールを
　　　　弾くくせに。
　　　　　あっ、弾くのは
　　　　　　ChatGPTでした😅

　Copilotの
　　DALL-E3は
　　　有名キャラを
　　　　出してしまいますからね。
　　　　　有名人はダメ。

　ともかく、
　　身のまわりにある
　　　マークやシンボルは
　　　　使うならば、きちんと
　　　　　確認が必要だ、と
　　　　　　思っておきましょう。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
Java　配列

配列とは
　複数データが入った箱のようなもの
要素
　1つのデータのこと
添え字
　要素の番号のこと
☆要素が複数入ったものを配列という
☆添え字は0から始まるので、最後の添え字は要素数より１つ小さい

◎配列の作成
①　配列変数の宣言
　要素の型[] 配列変数名
 例）
 　int[] count
  
②　要素の作成と代入
 　例）
　count = new int[10];

①と②をまとめると
　int[] count = new int[10];

 ◎配列の要素数の取得
 　配列変数名.length
  例）
  count.length

  変数の値を取り出すには、必ず値を初期化するが配列の要素は自動的に初期化される。
  要素の型によって決められている
  ![00b278f89c96b257eefa08f0ff675ca8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620446/c4682b79-dae9-02d4-db73-90d3ac93e18a.png)

◎配列作成と初期化の省略記法
　①要素の型[] 配列変数名 = new 要素の型[] {値1, 値2, 値3,....};
　②要素の型[] 配列変数名 = {値1, 値2, 値3,....};
例）
　①int[] scores1 = new int[] {80, 40, 60, 50, 70}; 
 　②int[] scores2 = {80, 40, 60, 50, 70};
rex0220 アクションファイルプラグイン

kintone アプリのアクション毎に指定された添付ファイル項目をコピーするプラグインです。
レコード再利用時にも指定された添付ファイル項目をコピーできます。

# アクションファイルプラグインの特徴
・プラグイン設定でアクション毎に指定された添付ファイル項目をコピー
・レコード再利用時に指定された添付ファイル項目をコピー
・３ヶ国語対応
・PC・モバイル対応

Ver.2
・プラグイン設定画面のデザイン変更対応
・プラグイン設定に、「説明」設定機能を追加
・プラグイン設定で、ファイル項目編開始時に指定アプリチェック追加

# アクションファイルプラグインの概要

- アクションボタンクリックで、新規レコード画面表示時にコピーされる添付ファイル項目を黄色表示
- レコード再利用時も同様に、コピーされる添付ファイル項目を黄色表示
- コピー対象のファイル項目に、別のファイルをアップロードした場合は新しいファイルを優先
- テーブル行追加・削除に対応
- レコード保存時に、ファイルコピー処理が実行

![2024-04-09_10h56_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/e37b3262-c775-090b-0c98-f0ac0cbaa74e.png)

# モバイル表示例

![2024-04-09_12h15_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/5d81892c-7f02-900c-f68b-7974a7e3abff.png)


# 操作例

![2024-04-09_11h02_08.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/ae702b88-f021-04d8-8fbd-d11fdf590554.gif)


# アプリの事前設定

テーブル内添付ファイル項目をコピーする場合は、テーブル内にファイル識別ID（文字列）を追加します。
テーブル内の項目位置を変更した場合、アクションファイルプラグインの再設定が必要です。

![2024-04-09_11h11_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/04f267c9-df9c-4215-ff6e-daebd758f841.png)

# アクション設定

テーブル内の添付ファイルをコピーする場合は、アクション設定で対象テーブルの項目を指定が必要です。
※アクション時に、対象テーブルの行数が登録され添付ファイルをコピーできるようになります。

![2024-04-09_11h16_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/c15345be-d9fa-0a6d-c83a-acf6af30a7a1.png)

# プラグインの追加

- 「kintone システム管理 > プラグイン」で追加
- 「アプリの設定 > プラグイン」で、アプリに追加

# アクションファイルプラグイン設定

アクションを設定したアプリのアクション毎に、対象添付ファイル項目を指定します。

- NOTE：　メモ用
- プラグイン有効：　プラグインの有効・無効を指定
- 行制御：　設定行の複写・追加・削除を行う場合に、チェック
- アプリ：　対象アプリ(アクション設定アプリ)を指定
- アクション：　アクションを指定
- ファイル対象テーブル：　アクションで指定されたテーブルを表示
- テーブル項目：　設定するテーブルとテーブル内項目を指定
- ファイル項目：　コピー対象の添付ファイル項目を表示
- 運用環境に反映：　「保存する」ボタンクリック時に直接運用環境へ反映
- 「保存」：プラグイン設定を保存
- 「キャンセル」：　プラグイン設定をキャンセル
- プラグイン設定ダウンロード
- プラグイン設定アップロード
- プラグイン設定更新情報

![2024-04-09_11h22_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/b0c0568d-5d8b-218f-4f4a-f1dc433fbbe3.png)

## 行制御

設定行の複写・追加・削除を行います。

![2024-04-09_11h27_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/115d5bd3-8dc4-130e-ec96-1a882cde8e98.png)

## アプリ

アプリの編集エリアをダブルクリックすると、アプリの選択肢が表示される

![2024-04-09_11h29_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3f56ea89-e45e-9b04-af39-f95b8d6df0d3.png)

## アクション

アクション編集エリアをダブルクリックすると、アクションの選択肢が表示される
対象アプリが自アプリの場合は、「0:レコード再利用」を選択できる
アクションの選択肢が表示されない場合は、対象アプリを指定できません

![2024-04-09_11h47_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/a5bc78d1-f063-c94b-6b82-9bcfff769cd9.png)

## ファイル項目

添付ファイルのコピー先項目に対して、コピー元項目とファイル制御ID項目を指定する
テーブル内の添付ファイル項目の場合は、ファイル制御ID項目が必要です。
ファイル制御ID項目は、詳細画面・編集画面で非表示となります。

![2024-04-09_11h48_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/66aa9ada-9d84-6927-d48d-d7d0672c8487.png)


# 利用ライブラリ
・jQuery MITライセンス
・jQuery-UI MITライセンス
・momentjs  MITライセンス
・sweetalert2 MITライセンス
・FileSaver  MITライセンス
・zlib MITライセンス
・kintone-ui-component  MITライセンス
・pqgrid 商用ライセンス

# 注意事項

既に、JavaScript によるカスタマイズを行っているアプリの場合、処理が競合して、エラーになる場合があります。その場合は、該当するアプリでプラグインの使用を中止してください。
【python】2010年小樽商科大の整数問題をプログラミングしてみた。

# はじめに
小樽商科大学の入試問題にプログラミング題材にふさわしい問題があったので、pythonでプログラミングしました。

## 問題
> 2010!は2で何回割り切れるか。
> 出典 2010年小樽商科大学

## プログラミングしたコード
```python
# 小樽商科大2010年の入試問題
# 2010!は2で何回割り切れるか

# 2で割り切れるだけ割り切り、割り切った回数を返す関数
def two_div(num):
  two_div_count = 0
  while num % 2 == 0:
    two_div_count += 1
    num /= 2
  return two_div_count

# メイン関数
def main():
  # 階乗を表す変数
  N = 2010
  # 解答を表す変数
  two_div_ans = 0
  for i in range(1,N+1):
    ans += two_div(i)
  print(two_div_ans)

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

## 実行結果
実行結果はこんな感じ

![ans.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1055346/5c837b00-2ce0-b163-cc0a-055cc437d56b.jpeg)

## アルゴリズム
①自然数を２で割り切れるか変数に入れる
②２で割り切れるか変数に格納した自然数を2で割り切れなくなるまで繰り返し2で割る
③②の処理の結果回数を足す
④自然数を1足して①に戻る。2010まで繰り返す。
⑤2010まで調査したら、2で割り切れる回数を標準出力に出力

# 最後に
機会があったら何かの題材で挑戦しようと思います。
右クリックとドラッグドロップ禁止 css

<h2>右クリック禁止</h2>
```oncopy=”return false” oncontextmenu=”return false”```

bodyの中に入れる。

<h2>ドラッグドロップ禁止</h2>

for ios
```css
img {
  -webkit-user-drag: none;
}
img[draggable=true] {
  -webkit-user-drag: auto;
}
```

for android

```css
*[draggable=true] img {
  -webkit-touch-callout: none;
}
```

```html
<div class="contains-image" draggable="true">
  <img src="test.png" />
  <div class="protect-image"></div>
</div>
<style>
.contains-image {
  position: relative;
}

.protect-image {
  width: 100%;
  height: 100%;
  position: absolute;
  padding: 0;
  border: 0;
  top: 0;
  left: 0;
  opacity: 0;
}
</style>
```
[Google Tasks API(V1)] Javaでタスクリストを取得する

Google Tasks API V1(Java)を使用して、
タスクリストを取得する方法
についてご紹介します。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Tasks API(V1)] JavaでTasks APIを使う](https://qiita.com/doran/items/8a3b7e24d9e0417a7f9a)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[タスクリスト一覧を取得](#1-タスクリスト一覧を取得)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|
|2||[タスクリストを取得](#2-タスクリストを取得)|
||1|[スコープ](#21-スコープ)|
||2|[実行](#22-実行)|
||3|[レスポンスの内容](#23-レスポンスの内容)|

## 1. タスクリスト一覧を取得
タスクリストの一覧を取得します。

### 1.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
TasksScopes.TASKS
TasksScopes.TASKS_READONLY
```
[⧉[Google Tasks API(V1)] JavaでTasks APIを使う(2.2 Tasksインスタンスを取得)](https://qiita.com/doran/items/8a3b7e24d9e0417a7f9a#22-tasksインスタンスを取得)
でスコープを指定してください。

### 1.2. 実行

```java
public static void main(String[] args) throws Exception{
    Tasks tasks = getTasks();
    Tasks.Tasklists tasklists = tasks.tasklists();
    
    Tasks.Tasklists.List list = tasklists.list();
    
    TaskLists res = list.execute();
    System.out.println(res);
}
```
#### 1.2.1. HTTPリクエスト
GET:　https:\//tasks.googleapis.com/tasks/v1/users/@me/lists
が実行されます。

#### 1.2.2. クエリパラメータ
Tasks.Tasklists.Listのsetメソッドにより、クエリパラメータを追加できます。

|メソッド|引数|説明|
|---|---|---|
|setMaxResults|Integer|レスポンスで返されるエントリの最大数<br>デフォルトは20、最大100まで指定可能|
|setPageToken|String|次のページで前のリスト要求を継続するためのトークン<br>**レスポンスのgetNextPageTokenで取得が可能**|

### 1.3. レスポンスの内容

#### TaskLists

|メソッド|戻り値|説明|
|---|---|---|
|getKind|String|リソースの種類<br>固定文字列："tasks#taskLists"|
|getEtag|String|Eタグ|
|getNextPageToken|String|次のページのページトークン<br>リストの最後の場合はNULL|
|getItems|List\<[TaskList](#tasklist)\>|タスクリスト|

#### TaskList

|メソッド|戻り値|説明|
|---|---|---|
|getKind|String|リソースの種類<br>固定文字列："tasks#taskList"|
|getId|String|タスクリストID|
|getEtag|String|Eタグ|
|getTitle|String|タスクリストのタイトル|
|getUpdated|String|タスクリストの最終更新日時|
|getSelfLink|String|このタスクリストを指すURL|

## 2. タスクリストを取得
タスクリストを取得します。

タスクリストIDは、
[1. タスクリスト一覧を取得(TaskList)](#tasklist)のgetId()で取得した値を使います。

### 2.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
TasksScopes.TASKS
TasksScopes.TASKS_READONLY
```

### 2.2. 実行

```java
public static void main(String[] args) throws Exception{
    Tasks tasks = getTasks();
    Tasks.Tasklists tasklists = tasks.tasklists();
    
    Tasks.Tasklists.Get get = tasklists.get("タスクリストID");
    
    TaskList res = get.execute();
    System.out.println(res);
}
```
#### 2.2.1. HTTPリクエスト
GET:　https:\//tasks.googleapis.com/tasks/v1/users/@me/lists/{タスクリストID}
が実行されます。

#### 2.2.2. クエリパラメータ
クエリパラメータはありません。

### 2.3. レスポンスの内容

#### TaskList

[1.3. レスポンスの内容(TaskList)](#tasklist)と同じです。

<br>
<br>
おしまい。。
mock.tsでリクエストを解析してレスポンスを変える

## 概要
フロントエンド（React）のテストを書いている際に、フィルタリング機能のテストをする必要があり、モックサーバでリクエストボディを見てレスポンスを動的に変えたい場合があったので、その方法を簡単に書きました。

## 結論
以下のようにリクエストボディに特定の属性が含まれる場合は、それ用のレスポンス（外で定義したもの）を返すようにすることでフィルタリングやページネーションなどのテストができます。
```
rest.get(`${baseURL}/contents/pages`, (req, res, ctx) => {
    const tag_id = req.url.searchParams.get('user_id')
    let successfulResponse

    if (user_id === null) {
      successfulResponse = getContentsPages200Response()
    } else {
      successfulResponse = getContentsPagesByUser200Response()
    }

    // 以下省略
})
```