OmniAICreator/Qiita-1.07M huggingface dataset:
Hono + Cloudflare Workers で REST API を作ろう！超入門


## はじめに

この記事では Hono と Cloudflare Workers を使って REST API を作成する方法を紹介します。

## Hono とは

Hono は Cloudflare Workers / Pages だけではなく様々な環境で利用できる JavaScript / TypeScript のフレームワークです。

詳しくは様々な記事があるので省かさせていただきます。

## プロジェクトの作成・準備

Hono のテンプレートの中から cloudflare-workers テンプレートを選んでプロジェクトを新規作成します。

```shell-session
$ npm create hono@latest

create-hono version 0.6.3
? Target directory .
? Which template do you want to use? cloudflare-workers
✔ Cloning the template
? Do you want to install project dependencies? yes
? Which package manager do you want to use? npm
✔ Installing project dependencies
🎉 Copied project files
Get started with: cd .
```

次に Wrangler にログインしましょう。
Wrangler は Cloudflare Workers の CLI ツールです。

```shell-session
$ npx wrangler login

 ⛅️ wrangler 3.50.0
-------------------
Attempting to login via OAuth...
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth
Successfully logged in.
```

## 起動

プロジェクトのディレクトリに移動して、以下のコマンドを実行します。

```shell-session
$ npm run dev
```

`http://localhost:8787` にアクセスすると、`Hello Hono!` と表示されるはずです。

## REST API の作成

`src/index.ts` を以下のように編集します。

```typescript
import { Hono } from "hono";

const app = new Hono();

app.get("/", (c) => {
  return c.text("Hello Hono!");
});

// Add a new route
app.get("/api", (c) => {
  return c.json({ message: "Hello Hono!" });
});

// Add a new route with a parameter
app.get("/api/hello/:name", (c) => {
  const name = c.params.name;
  return c.text(`Hello, ${name}!`);
});

export default app;
```

`/api` にアクセスすると JSON データが返ってくるようになりました。

`/api/hello/:name` にアクセスすると、`:name` に指定した名前が表示されるようになります。

## デプロイ

以下のコマンドでデプロイします。

```shell-session
$ npm run deploy

> deploy
> wrangler deploy --minify src/index.ts

 ⛅️ wrangler 3.50.0
-------------------
✔ Select an account › Your Account
Total Upload: 19.15 KiB / gzip: 7.27 KiB
Uploaded hono-introduction (1.14 sec)
Published hono-introduction (5.03 sec)
  https://hono-introduction.your-account.workers.dev
Current Deployment ID: 00000000-0000-0000-0000-000000000000
```

デプロイが完了すると URL が表示されるので、アクセスしてみましょう。

## まとめ

Hono と Cloudflare Workers を使って REST API を作成する方法を紹介しました。

詳しくは公式ドキュメントを参照してください。

- [Hono](https://hono.dev/)
- [Cloudflare Workers](https://workers.cloudflare.com/)
【CSS】list-style: と list-style-type: どう使う？

## 提起：
- css の list-style と list-style-type , 普段なんとなく併用していることが多い.
- ul / ol / dl に指定することもあるし, その子要素 li に指定してもなんとなく使える.
ホントはなんか推奨される書き方があるんじゃないの？

## 結論： どっちを使ってもいい
list-style と list-style-type どちらも ul / ol / dl に指定しても良いし, li に指定しても良い.
ul / ol / dl に指定するとスタイルが子要素に継承され, リスト全体に適用することができる.

## 背景: もうちょっと掘り下げたい人向け
MDN web docs の `list-style` の項には以下の記述がある.

> このプロパティは以下の CSS プロパティの一括指定です。
> * list-style-image
> * list-style-position
> * list-style-type


要はリストの行頭に使う記号（disc: 黒丸 とか circle: 白丸 etcetc.）, 画像, 行頭の記号の配置（リストの内か外か）なんかをまるっと指定できるプロパティらしい. 

　.

これらのスタイルを指定する順番は
`list-style : 記号 画像 配置;`

cf:
`ul { list-style: disc url('~/assets/img/maru.svg') inside; }`


## 補遺： 参考リンク
- list-style | MDN web docs 
https://developer.mozilla.org/ja/docs/Web/CSS/list-style
- list-style - リストに関して一括して指定する | 日経クロステック（xTECH）
https://xtech.nikkei.com/it/article/Reference/20091124/340996/
WordPressでページごとにインデックスの設定をする

ページごとに任意でインデックスの設定をできるようにする方法です。
元のコードは以下のサイトです。header.phpが複数あった場合に、1つ1つに記述しなくてもいいよう、functions.phpにまとめる形で変更しました。元のコード + 一番下の関数を追加すれば、OK。


https://tcd-theme.com/2021/07/wordpress-noindex.html


```php
// 元コード
function add_noindex_metabox() {
    add_meta_box( 'custom_noindex', 'インデックス設定', 'create_noindex', array('post', 'page'), 'side' );
}
add_action('admin_menu', 'add_noindex_metabox');

function create_noindex() {
    $keyname = 'noindex';
    global $post;
    $get_value = get_post_meta($post->ID, $keyname, true);
    wp_nonce_field('action_' . $keyname, 'nonce_' . $keyname);
    $value = 'noindex';
    $checked = '';
    if ($value === $get_value) $checked = ' checked';
    echo '<label><input type="checkbox" name="' . $keyname . '" value="' . $value . '"' . $checked . '>' . $keyname . '</label>';
}

function save_custom_noindex($post_id) {
    $keyname = 'noindex';
    if (isset($_POST['nonce_' . $keyname])) {
        if (check_admin_referer('action_' . $keyname, 'nonce_' . $keyname)) {
            if (isset($_POST[$keyname])) {
                update_post_meta($post_id, $keyname, $_POST[$keyname]);
            } else {
                delete_post_meta($post_id, $keyname, get_post_meta($post_id, $keyname, true));
            }
        }
    }
}
add_action('save_post', 'save_custom_noindex');

// 追加するコード↓
function add_tag() {
    global $post;

    if (is_singular() && get_post_meta($post->ID, 'noindex', true)) {
        echo '<meta name="robots" content="noindex, nofollow" />';
    }
}
add_action('wp_head', 'add_tag');

```
Oracle CloudでNVIDIA GPUインスタンスを使う場合のドライバってどうなるの？？

# はじめに
Oracle Cloud Infrastructure(OCI)においてNVIDIA GPUのインスタンスを利用する際のイメージ選択について公式ドキュメントからでは読み取れない部分もありますので、ここでまとめたいと思います。

基本的には利用用途（グラフィックス処理または、コンピュート処理）により選択するイメージが変わります。

# イメージの選択について
以下の表を参考にしてください。

## OS別の利用用途によるOSイメージ選択
まずは、利用するOSから利用用途を選択し、どのOSイメージを使えば良いかを確認してください。
| OS種類 | 利用用途 | 利用するOSイメージ | 追加作業 | 注意事項 |
|:-:|:-:|:-:|:-:|:-:|
| Windows Server   | グラフィックス利用  | MarketplaceのNVIDIA RTX Virtual Workstation  | ドライバ、ライセンス込みなので不要。  | 特定のverしかリリースされていない。  |
|  | グラフィックス利用  | Platform Image  | NVIDIAの有償vGPUライセンスの購入、ドライバ・ライセンスのインストール  | 特殊なケース。基本的には上記のイメージの利用が推奨。  |
|   | コンピュート利用 | MarketplaceのNVIDIA RTX Virtual Workstation   | ドライバ、ライセンス込みなので不要。  | 特定のverしかリリースされていない。  |
|   | コンピュート利用  | Platform Image  |  適切なドライバをダウンロードしてインストールが必要 | WDDMモードでは利用不可。  |
| Oracle Linux  | グラフィックス利用  | GPU Platform Image | ドライバインストール済みなので不要。  |   |
|   | コンピュート利用  | GPU Platform Image | ドライバインストール済みなので不要。  |   |
| Ubuntu  | グラフィックス利用  | Platform Image  | 適切なドライバをダウンロードしてインストールが必要  |   |
|   | コンピュート利用  | Platform ImageまたはNGC Image | 適切なドライバをダウンロードしてインストールが必要 |   |
| CentOS  | グラフィックス利用  |  CentOS の Platform Image | 適切なドライバをダウンロードしてインストールが必要  |   |
|   | コンピュート利用  |  CentOS の Platform Image | 適切なドライバをダウンロードしてインストールが必要  |   |

- ドライバインストールはNVIDIA社の以下URLから適切なものをインストールしてください
    - ドライバのダウンロード: https://www.nvidia.co.jp/Download/index.aspx?lang=jp
    - ドライバとCUDA SDKのダウンロード: https://developer.nvidia.com/cuda-downloads


## OSイメージとShapeの組み合わせ
利用するOSイメージが決まったら、そのOSイメージが利用したいShapeに対応しているか確認してください。
|GPU Type| Shape | RTXvWS(Win2019/2022) | OL7/8 GPU | Ubuntu 22.04 | CentOS7/8 | Win2019/2022 STD | Win2019/2022 DC |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|V100|VM.GPU3.1| ○  | ○  | ○  | ○  | ○  | ✖️  |
|   |VM.GPU3.2| ○  | ○  | ○  | ○  | ○  | ✖️  |
|   |VM.GPU3.4| ○  | ○  | ○  | ○  | ○  | ✖️  |
|   |BM.GPU3.8|✖️  | ○  | ○  | ○  | ✖️  | ✖️  |
|A100|BM.GPU4.8| ✖️  | ○  | ○ | ○  |✖️   | ✖️  |
|A10|VM.GPU.A10.1| ○  | ○  | ○  | ○  | ○  | ✖️  |
|   |VM.GPU.A10.2| ○  | ○  | ○  | ○  | ○  | ✖️  |
|   |BM.GPU.A10.4| ✖️  | ○  | ○  | ○  | ✖️  | ○  |

- 2024年4月14日現在の最新イメージでの確認状況です
- Shapeの詳細なスペックについては　https://docs.oracle.com/ja-jp/iaas/Content/Compute/References/computeshapes.htm をご確認ください

# 補足情報
## Platform Image とは？
https://docs.oracle.com/ja-jp/iaas/Content/Compute/References/images.htm

## Marketplace Image とは？
https://docs.oracle.com/ja-jp/iaas/Content/Marketplace/Concepts/marketoverview.htm
AtCoder Beginner Contest 349 振り返り

ひさしぶりのAtCoderの振り返りです。
前回が345なので、4回ぶりの記事になります。

## 今回の結果

A,B,C 3完でした。かなり久しぶりの3完です。

![スクリーンショット 2024-04-14 0.21.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/6e041d09-ab90-1114-26f7-72606397c2ec.png)
![スクリーンショット 2024-04-14 0.24.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/c25fa3f4-bc50-07ce-6e9a-ab88eb150822.png)

## 各問題の振り返り

### A - Zero Sum Game

- [問題](https://atcoder.jp/contests/abc349/tasks/abc349_a)
- [自分の回答](https://atcoder.jp/contests/abc349/submissions/52301465)

問題を見た瞬間、これA問題に持ってきていいレベルじゃなくない？と一瞬焦りました。
しかし、よく問題を読むと、`各ゲームでは勝者の持ち点が1増え、敗者の持ち点が1減ります`と書いてあることから、全プレイヤーの総得点は0になることがわかります。

ここから、`N-1`までのプレイヤーの総得点を計算して、正負を逆転すると答えになることがわかります。

```haskell
main :: IO ()
main = do
  _ <- readLn @Int
  ns <- readInputInts

  print $ -1 * L.sum ns
```

### B - Commencement

- [問題](https://atcoder.jp/contests/abc349/tasks/abc349_b)
- [自分の回答](https://atcoder.jp/contests/abc349/submissions/52333721)

問題文から、`ある一定回数現れる文字の種類が2つある or 存在しない`ことを確認すれば良さそうだなとなります。

これを元により具体的な解法を考えると以下の様です。

1. 文字列をsortしてグルーピングし、グループごとに配列の長さを求める。これが各文字の出現回数の配列になる
2. 1.で求めた配列をまたsortしてグルーピングし、長さを求める。これが出現回数毎の文字の種類になる. 
3. 最後に配列の値が全て2になっていることを確認する(出現回数が0の文字については、そもそも配列に含まれないので考慮する必要がない)

これをコードに起こすと以下の通りになります。

```haskell
main :: IO ()
main = do
  ss <- getLine
  putStrLn $ if (all ((== 2) . length) . L.group . L.sort . L.map length . L.group . L.sort) ss || null ss then "Yes" else "No"
```

余談ですが、ここは`all`にしないといけないのですが誤って`any`にして2ペナをくらってしまいました。`any`だと"いずれかひとつの要素がTrueになるとTrueを返す"ので答えが違ってしまいます。なのに普通に`all`にしたと勘違いしてしまいました。凡ミス。。

### C - Airport Code

- [問題](https://atcoder.jp/contests/abc349/tasks/abc349_c)
- [自分の回答](https://atcoder.jp/contests/abc349/submissions/52348502)

ある3文字が部分文字列(連続しなくて良い)に含まれてることを確認すればよいので、一つずつ`elemIndex`でindexを取得し`drop`で落とせばよいです。
3文字なので、計算量も高々`O(3*n)`でしかないのでACできると判断しました。(`n`は探索対象の文字数)

実装は問題なかったのですが、`drop`する時に失敗して、`drop (i + j) s` にしてしまったせいで1ペナをくらってしまいました。
`drop`は指定した**要素数**を除外するのにたいして、`elemIndex`で取得するのは**0はじまりの配列の位置**なので、**2文字目以降で`drop`する時は`elemIndex`の結果に1を足さなければなりません。**

また、2文字目の探索(`elemIndex`)では、1文字目の位置を`drop`した後の点が始点になっているので
3文字目の探索の時に
`(1文字目のelemIndexの結果 + 1) + (2文字目のelemIndexの結果 + 1)`
を`drop`しなければいけませんでした。

`drop`する時はミスりがちなところなので気をつけないとですね。

```haskell
main :: IO ()
main = do
  s <- getLine
  t <- L.map toLower <$> getLine
  let l = L.elemIndex (head t) s
  let m = (\i -> L.elemIndex (t !! 1) (L.drop (i + 1) s)) =<< l
  let res = maybe False (\(i, j) -> (t !! 2 == 'x') || L.elem (t !! 2) (L.drop ((i + j) + 2) s)) $ liftM2 (,) l m
  putStrLn $ if res then "Yes" else "No"
```

## 全体を振り返って

今回割と調子良かったので、次回もこれくらい解けるといいなと感じました。
あとは、もう少しarrayを使うのに慣れたいと思っています。使える様になると色々応用が効きそうなので。
[Python] 回帰分析の実装 statsmodels.formula.api

# はじめに
パッケージ`statsmodels`を用いて各種回帰分析を実装します。この記事では、R-ライクな構文で記述できる`statsmodels.formula.api`を用います。

公式ドキュメント
https://www.statsmodels.org/stable/
https://www.statsmodels.org/stable/example_formulas.html#fitting-models-using-r-style-formulas

# コード
## インポート
```python
import pandas as pd
import numpy as np
import statsmodels.formula.api as smf
```

## データの読み込み
```python
df = pd.read_csv('./Data.csv', index_col=0)
```

## 回帰分析

代表的な回帰分析の実装コードを示しますが、どれも基本的な構文は同じです。
`(formula='目的変数 ~ 説明変数1 + 説明変数2 + 説明変数3 + ....', data=df)`

#### OLS
最小二乗法(Ordinary least squares)による回帰分析。
```python
model = smf.ols(formula='BW ~ height + age + sex', data=df)
result = model.fit()
```
#### GLS
一般化最小二乗法(Generalized least squares)による回帰分析。
```python
model = smf.gls(formula='BW ~ height + age + sex', data=df)
result = model.fit()
```
#### ロジスティック回帰
```python
model = smf.logit(formula='BW ~ height + age + sex', data=df)
result = model.fit()
```

<br>
他にも様々な回帰が実装可能で、公式ドキュメントに書かれています。

https://www.statsmodels.org/stable/api.html#statsmodels-formula-api

## 結果の出力
決定係数や回帰係数を含むサマリーが出力されます。
```python
result.summary()
```

## 回帰モデルによる予測
`.predict()`を用います。
下の例では、元データをそのままモデルに適用しています。
```python
prediction = result.predict(df[['height', 'age', 'sex']])
```
[構築・初期設定] Apache + cgi を繋ぐ (動作確認のスクリプトあるよ)

今回はapache とcgi を繋げてみて、動作確認まで実施していきます。今更cgi かよ！！とか思わず、最後まで見ていただけますと幸いです。apache はデフォルトでcgi-bin の設定ができている状態なので、vhost を立てて、cgi を通していきます。


# apache と cgi を繋ぐ

DocuemntRoot は任意で作成してください。私はテストでここに作成しました。
```
# DocumentRoot 作成
mkdir -p /var/www/example.com/public_html/

# conf ファイル作成
touch /etc/httpd/conf.d/example.com.conf
```

とりあえずファイル作成してみたら、vhost の設定していきます。
以下のconf の内容を貼り付けます。ここで一番重要なのが、Options のExecCGI とAddHandler cgi-script .pl .cgi になります。この設定をいれることによって、cgi の実行を明示的に許可することができます。
```
<VirtualHost *:80>
   ServerName example.com
   DocumentRoot "/var/www/example.com/public_html/"
   DirectoryIndex index.php index.html index.xml
   <Directory /var/www/example.com/public_html/ >
           Options FollowSymLinks ExecCGI
           AllowOverride all
           AddHandler cgi-script .pl .cgi
   </Directory>
   CustomLog "/var/log/httpd/example.com-access_log" combined
   ErrorLog "/var/log/httpd/example.com-error_log"
</Virtualhost>
```


この設定をいれたら、保存して、設定反映のためにapache の再起動を実施してください。そして、cgi のプログラムを配置していきます。cgi のプログラム自体は、public_html などのDocumentRoot におく必要はなく、/var/www/cgi-bin/ 配下にcgi のプログラム配置ファイルをおく必要があります。

public_html に置かなくても、cgi のプログラムを許可してるので、cgi の実行は外部ディレクトリから参照してくれて、実行することが可能です。便利ですね。ちょっとわかりづらいですが。

cgi-bin のディレクトリの権限と、cgiのファイルに実行権限を与えて上げます。
```
# 権限変更
chmod 2775 /var/www/cgi-bin/

# ファイル作成
touch /var/www/cgi-bin/test.cgi

簡単なプログラム内容

~~~~~~~~~~~~~~~~~~
#!/usr/bin/perl --

print "Content-Type: text/html\n\n";
print "test";
exit;
~~~~~~~~~~~~~~~~~~

# 実行権限付与
chmod +x /var/www/cgi-bin/test.cgi


```

そして、自分のドメインで以下のようにアクセスしてください。そうするとcgi が動作していると思います。

http://example.com/cgi-bin/test.cgi


# まとめ
cgi の構築とかあまりしたことがないので、仕組みがよくわかりませんでしたが、cgiを知るとfastcgi の理解もしやすいだろうと思い、少し勉強してみました。cgiのセキュリティ対策にはお気を付けて、良いcgi ライフを！！
AndroidStudioの新しいDiffViewによってPRの差分をGithubライクに見れるようになった

IntelliJ IDEA 2023.3にて、「オールインワンの差分ビューアー」というDiffViewの新機能が登場しました。

https://www.jetbrains.com/ja-jp/idea/whatsnew/2023-3/

これによって、PRの差分をGithubのfiles changedとかなり近い体験で確認できるようになります。
- 複数ファイルの差分をスクロールによって確認できる
- 差分とその付近の行のみ表示できる

■ Githubとの比較
| Github | AndroidStudio |
| :---: | :---: |
|![スクリーンショット 2024-04-13 22.39.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762653/13165d76-d179-e46f-07a9-dd7e445fb7e5.png)|![スクリーンショット 2024-04-13 22.39.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762653/de2fd6f3-6763-983f-c896-00ec825bfef0.png)|

Split表示
| Github | AndroidStudio |
| :---: | :---: |
|![スクリーンショット 2024-04-13 22.25.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762653/61456487-44b5-b01f-b2e3-05ea17573b56.png)|![スクリーンショット 2024-04-13 22.43.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762653/900d60a8-ab9a-1ca3-cb60-17a56dfc34ab.png)|

## 動作環境
本記事では、AndroidStudio Koala | 2024.1.1 Canary3 を使用しています。

Koalaより古いバージョンも見てみましたが、これらでは有効にするオプションを見つけられませんでした。
- JellyFish 2023.3.1 RC2
- Iguana 2023.2.1 Canary18
- HedgeHog 2023.1.1 Patch2

## セットアップ方法
まずは「オールインワンの差分ビューアー」を有効にしましょう。
AndroidStudioのPullRequestタブにて変更されたファイルをクリックしDiffViewを開きます。
DiffViewの設定に「Show All files in One Diff View」があるのでクリックします。

![スクリーンショット 2024-04-13 23.54.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762653/8ff5d9a5-8745-50f3-5d19-a7c475e5f768.png)

これにて「オールインワンの差分ビューアー」が有効になりますが、デフォルトでは次のようにファイルの全ての行が表示されてしまいます。
![スクリーンショット 2024-04-14 0.04.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762653/afa28e80-9515-2d82-fa67-6321df43590a.png)

差分とその付近の行のみ表示したいので、DiffViewの設定から「Collapse Unchanged Fragments」を有効にしましょう。
これで、下記のようにGithubライクな表示にすることができました。
![スクリーンショット 2024-04-13 22.25.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762653/eb77591d-5828-3c9e-be4a-8788b09ba014.png)

波線をクリックすることで、差分付近の行の表示範囲を広げることもできます。

## その他のオプション
DiffViewの設定から、さらに表示をカスタマイズすることができます。
私のおすすめはIgnoreChangesの「Ignore whitespaces and empty lines」です。

これを有効にすると、スペースや空行が増えただけの差分を表示しないようにできます。

## おわりに
DiffViewの進化によって、AndroidStudio内でのPRレビューがさらに便利になりました。
ぜひ活用して素敵なAndroidStudioライフを送りましょう
手持ちの体重csvファイルからgoogle fitへインポートする方法

忘備録として書く。

# 背景

私はスマートフォンに毎日体重を記録しており、それをgoogle fitへと連携しようと考えた。

体重記録アプリから直接google fitへ出力する機能があればよいのだが、そのような機能はアプリにはなかった。

なので、アプリから体重を記録したcsvを出力させ、google fit のAPIを経由して、保存することにした。

# 手法

1：githubにエクスポートのためのスクリプトがあるので、それをクローンする。

```script
git clone https://github.com/okainov/weight-csv-to-gfit
```

2：api keyとfitness apiのOAuth 2.0 クライアント IDの2つを作成し、ダウンロードする。

- 両者ともgoogle cloudのアカウントが必要なので、作成しておく。
- api key
    - google cloudの「APIとサービス」の「認証情報」の「APIキー」から、「＋認証情報を作成」ボタンがあるのでそこから作成し、記録する。
- OAuth 2.0 クライアント ID
    - Fitness APIページの「管理」の「認証情報」タブから、「＋認証情報を作成」ボタンがあるのでそこから作成。jsonを`client_secret.json`として保存。

３：csvを加工。アプリからcsvをエクスポートし、以下のような形式に直す。

```csvs
datetime,weight
2024-01-01 08:00:00,70.5kg
2024-01-02 08:00:00,71.2kg
2024-01-03 08:00:00,69.8kg
```

4：スクリプトから仮想環境構築する。venvコマンドがあるので、それを実行。また、コードのタイムゾーンを変更する。

```python
# read_weight_csv.py
# TIME_ZONE = zoneinfo.gettz("Europe/Berlin")
TIME_ZONE = zoneinfo.gettz("Asia/Tokyo")
```

５：`weight-csv-to-gfit/weight`に以下のファイルを置く。

- client_secret.json
    - これは先ほどのOAuth 2.0 クライアント IDで作成したファイル。
- secrets.yml
    - project_idはclient_secret.jsonにある`client_id`から取得する。ただし、`123456-何らかの文字列`という形式なので、`123456`だけを書く。

```yaml
fitness_api_key: "ここに先ほど作成したapi keyを置く。"
project_id: "上を参照。"
```

６：`python import_weight_to_gfit.py`を実行。ブラウザでログイン画面が出るので全部OKを押す。

７：インポートに成功すれば、ターミナルでは以下のような出力が出る。google fitに反映されるまで1時間程度かかる。

# その他

私は5年分のデータを一度に入れようとしたら、途中までのデータしか反映されていなかった。5カ月を単位にデータを分割して、インポートした。

# 参考文献

- https://gen.fukatani.org/2020/08/Import-weight-data-in-CSV-onto-Google-Fit.html
- https://github.com/okainov/weight-csv-to-gfit
Next.js を使ってみる

仕事で、`Next.js`を使いたいという要望があったので、個人的にさらった内容を備忘録として書き留めておきます。
（正直、根っこの部分は`React`とあまり変わらないので、`React`でやったことを`Next.js`様に置き換えればいいだけな感じですが）

## プロジェクトの作成

以下コマンドで、プロジェクトを作成します。
プロジェクト名や、どのライブラリを使用するかとかは、よしなに。
```
npx create-next-app@latest
```

作ったプロジェクトのディレクトリに移動して`npm start`を実行して起動！
と思ったのですが、以下の様なエラーが出てきました。
```
Error: Could not find a production build in the '.next' directory.
Try building your app with 'next build' before starting the production server.
https://nextjs.org/docs/messages/production-start-no-build-id
```

ググったら、`npm run build` を実行しないと、`.next`ディレクトリが作成されないのだとか。（わかりづら...）
ビルドしてから、`npm start`で起動しました！
（ホットリロードを有効にするには、`npm run dev`での起動が必要そう）
<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/0c619621-9772-9edb-d02f-b2d0f99a7025.png">

## 複数ページ化
`Next.js`でサブディレクトリのページを作るには、`src/pages`フォルダ下に、`JSX.Element`が戻り値の`export default`関数のコードを配置してあげるだけで動きます！
（あとは、ほぼ`React`と同じなので、`html`の`DOM`的にデザインを作ってあげればいいだけですね）

サンプルとしては、以下の実装をしてみました。
```
src
　- pages
　　- index.tsx
　　- test
　　　- index.tsx
```

<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/742bd573-85fc-8fb4-74fb-d26d01bc42a0.png">
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/20a951d8-3dd4-94b1-1370-9d3a16a0d125.png">

サンプルコードは以下、格納しておきましたm(_ _)m

https://github.com/NagaJun1/sample_next_js_app

## 終わりに
デザイン面は、`React`使えるなら、問題無しって感じなので、そんなに難しい感じでもないですね。
`React`だと、サブディレクトリのページ作るのに、`router`用のライブラリを入れて、調整してあげないといけないので、それに比べると楽ですね！
SpringBootでApachePOIを使ったxlsxに列幅と行高さ設定

# この記事はこれの続きです

https://qiita.com/waokitsune/items/4bb38434e398dde52e7b

# 概要

xlsxの生成とダウンロードは以前の記事でやってるので説明は省略。
列幅と行高さの設定がメインです。

# Controllerクラス

```java:DemoController.java
package com.example.demo;


import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;


@Controller
public class DemoController {
	
	
	@GetMapping("/")
	public void getIndex(HttpServletResponse response) throws IOException {
		
		
		//---------------------------------------------------------------------------------------------
		//エクセルファイル生成。
		Workbook workbook_ = new XSSFWorkbook();
		Sheet sheet_ = workbook_.createSheet("ふーたお");
		Row row_ = sheet_.createRow(1);
		Cell cell_1_ = row_.createCell(CellReference.convertColStringToIndex("B"));
		cell_1_.setCellValue("私とお茶しない？");
		
		
		//---------------------------------------------------------------------------------------------
		//今回のメインはここ！
		
		//列幅。
		//スマートなやり方がどうしてもできなかったです。
		//設定 ⇒ 試しに出力 ⇒ 調整　を繰り返してくしかなさそう。
		sheet_.setColumnWidth(cell_1_.getColumnIndex(), (short) 3000);
		
		//行高さ。
		//設定はsetHeight()とsetHeightInPoints()の二種類。
		//setHeightInPoints()ならエクセルの画面で設定する『行の高さ』と同じ値で設定できます。
		row_.setHeightInPoints(40.5f);
		
		
		//---------------------------------------------------------------------------------------------
		//ダウンロード。
		response.addHeader(
				"Content-Disposition", 
				"attachment; filename*=UTF-8''" + URLEncoder.encode("胡桃.xlsx", StandardCharsets.UTF_8.name()));
		
		ServletOutputStream stream_ = response.getOutputStream();
		workbook_.write(stream_);
		stream_.close();
		
		workbook_.close();
		
		
	}
	
	
}
```

# 実行結果

ブラウザーでhttp:\//localhost:8080にアクセスすると、下記のようなxlsxがダウンロードされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/861fa6af-0d75-af03-1a44-94d84aa293cb.png)

列幅はJAVAで『3000』にするとエクセルだと『11.13』。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/5685e7ae-f6f7-df8d-c4aa-f33f06c11668.png)

単位は1文字の1/256らしいです…。
でも1文字の幅って環境によって変わるのでは…？と思ったりします…。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/3a81a0ab-4644-0014-7d1e-a7b827dbe228.png)

『JAVAで設定した値』がそのまま『エクセルで設定する値』にしたいけど、上手い方法が無かったです。

行高さは『JAVAで設定した値』がそのまま『エクセルで設定する値』になるので楽。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/407c01c5-c5f4-625b-7a8f-3ef6f4ebc8f7.png)

# この記事の続き

https://qiita.com/waokitsune/items/a6b2f281b99135cbc5b8

# 参考サイトさん

https://www.javadrive.jp/poi/sheet/index6.html

https://www.javadrive.jp/poi/row/index4.html

# バージョン

Microsoft Windows [Version 10.0.22631.3447]
JAVA 17.0.8.1
Spring Boot v3.1.10
ApachePOI 5.2.5
Google Colab + LightGBM (GPU) で遭遇したエラーと解決策

# 概要

- LightGBMの4.0.0のメジャーアップデートからGPU (CUDA)で実行できるようになった
- しかし、Google Colaboratory環境から実行しようとすると、学習段階で以下のエラーが出て詰んだ

```
LightGBMError: No OpenCL device found
```

いろいろ調べた結果、以下のコマンドを一発打てば解決した。

``` python
!mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd
```

以下で詳細について述べる。

# 環境

2024.04.14時点でのGolab環境で回している
- LightGBMのバージョン: 4.1.0

今回の問題と直接関係あるかはわからないが、他には
- polars==0.20.05
- pandas==2.2.0
- numpy==1.26

のバージョンを使っている。

Golab環境ではCPUに加えてランタイムからV100, A100, T4などのGPUを選ぶことができる。
Pro, Pro+などに課金することでより良いGPUを長い時間使うことができる。
自分の場合はPro+を使っている。

# どんなエラーが出たか

ランタイムから適当なGPU選択してlightGBMをimportする。
gpuを使うためにパラメータの設定を
- "device": "gpu"

と指定しいざ学習を回そうと思ったら最初に書いたエラーに遭遇した。
必要な設定は全部できてそうだけどなぜ？

# 原因と解決策

エラーメッセージの通り、OpenCLの設定がうまくできておらず、GPUを正常に認識できていないのが問題のようだ。

調べたところ、似たようなエラーに対処している記事が複数あった。

https://an-engineer-note.com/?p=996

↑LightGBMをアンインストールしてビルドし直している。

https://qiita.com/syoka4156/items/959f4fe967c1d635a2dc

↑Dockerfileを書いて環境構築

どっちもめんどくさそうだなーと思っていたところ、以下の公式リポジトリのissueを見つけた。

https://github.com/microsoft/LightGBM/issues/5914#issuecomment-1713129547

↑最初に貼ったコマンドを一行実行すれば良いと書いてあったので、それで解決。

一応実行した後にnotebookを起動し直す必要があったものの、面倒なビルドや環境構築などは特にやらずに済んだ。

# まとめ

- 結局公式のissueが一番役にたった
- こういう環境構築的な部分って思わぬところで詰まりがち。。
- とりあえず実行できるようになってよかった
pandas: dtypeが`object`のSeriesで`replace()`を実行すると、`pandas.NA`,`numpy.na`, `None`を同じ値だとみなして置換する

# 環境
* Python 3.12.1
* pandas 2.2.2


# はじめに
`pandas.Series`には`pandas.NA`, `numpy.nan`, `None`が含まれています。dtypeは`object`です。
どの要素に`pandas.NA`が含まれているかを調べたいです。

`Series.to_csv()`で出力すると、`pandas.NA`,`numpy.na`, `None`はすべて空文字で出力されて、区別できません。したがって、`pandas.NA`を`"???"`などの目立つ文字列に`replace()`で置換してから、`Series.to_csv`で出力してみました。しかしCSVの中身は、`pandas.NA`だけでなく`numpy.na`や`None`も`"???"`に変換されていました。



# `Series.replace`の動作を確認する

[pandas.Series.replace](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.replace.html
)の動作を確認しました。

```
In [132]: import pandas as pd
In [132]: import numpy as np

In [133]: s = pd.Series(["a", pd.NA, np.nan, None], dtype="object")

In [121]: s.replace({pd.NA: "???"})
Out[121]:
0      a
1    ???
2    ???
3    ???
dtype: object

In [124]: s.replace({np.nan: "???"})
Out[124]:
0      a
1    ???
2    ???
3    ???
dtype: object

In [122]: s.replace({None: "???"})
Out[122]:
0      a
1    ???
2    ???
3    ???
dtype: object
```

`replace()`では、`pandas.NA`,`numpy.na`, `None`は同じ値として、置換されるようです。


# 補足: dtypeが`string`や`Float64`,`Int64`ならば、`pandas.NA`を`numpy.nan`や`None`に置換できない

dtypeが`string`や`Float64`,`Int64`などでは、`pandas.NA`を`numpy.nan`や`None`に置換できません。dtypeが`string`や`Float64`,`Int64`の`Series`では、欠損値は`pandas.NA`に変換されます。


```
In [135]: s2 = pd.Series(["a",pd.NA], dtype="string")

In [136]: s2.replace({pd.NA:np.nan})
Out[136]:
0       a
1    <NA>
dtype: string

In [137]: s2.replace({pd.NA: None})
Out[137]:
0       a
1    None
dtype: object
```

`replace()`に限らず、直接設定するときも同様です。

```
In [140]: s2[1]=np.nan

In [141]: s2
Out[141]:
0       a
1    <NA>
dtype: string

In [142]: s2[1]=None

In [143]: s2
Out[143]:
0       a
1    <NA>
dtype: string

```
VSCode + Git Graph で Git をもうちょっと快適に操作する

:::note warn
ここで紹介するのは GUI 操作になります。キーショートカットガチ勢からすると全く快適にならないので注意。
:::

## Git Graph とは

VSCode の拡張の一つ。

![git-graph-extension.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/2e0c862f-e154-1f5d-1c7b-b2728c1dd639.png)

Git リポジトリのツリーをグラフィカルに表示してくれます。

![git-graph-graph-view.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/a92d906c-3a7b-27af-94da-a074b7663201.png)

行をクリックすれば、そのコミットでの変更の詳細が出ます。

![git-graph-commit-detail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/7e4a5bd3-4208-0d41-df57-56a6d2fa1443.png)

さらによく触ってみたら、これだけでなく他にも使えそうな機能があることに気が付きました。そこで、これ以外の機能を紹介します。

## ダブルクリックでブランチ切り替え

「ブランチ名コマンドで打つの地味に面倒･･･グラフ見てマウスでココ！が早くて良い」と感じる僕には便利なものです。

太字になっているのが操作先ブランチです。

![git-graph-branch-checkout.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/aae0da52-71f8-9fb9-4623-45e897567c9e.gif)

## ブランチの各種操作

これもまたブランチ名入力が地味に面倒ということで愛用しています。特に push と delete はよく使っています。

操作するブランチを右クリックし、出てきたメニューから操作を選択します。

![git-graph-branch-push.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/9d59232e-0687-b6d7-3ea2-45ca1b3478d5.gif)

![git-graph-branch-delete.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/e91348d7-e7f4-5a5c-93db-edf52292f1a1.gif)

上の絵には映っていませんが、操作確定前にダイアログが出てきます。

![git-graph-branch-push-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/bbaa47a7-243a-f9f0-1121-b85b5921eece.png)

![git-graph-branch-delete-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/6b58a473-e970-e6c3-7e02-2aef065c65d8.png)

初期状態で Yes にフォーカスがあるので、そのまま Enter で操作を適用できます。

## コミットメッセージの #n を Issue/PR のリンクにする

~~リンクを使っているかというと、実は #n に色付けしたいだけだったり･･･。~~

Git Graph の Repository Settings を開き、Issue Linking を設定します。

![git-graph-config-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/9107c1c8-2e41-d76f-83d3-20ef695f35a1.png)

![git-graph-config-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/5d317a0c-d7f6-6fe1-68a5-18c2cea2ea87.png)

- `#n` と番号が示されている箇所をリンクにすると指示
  - 適用したい書式によって `#` を任意の文字にする
- Issue 番号を `$1` と書く形でリンクを指定
  - GitHub は Issue ページが `https://github.com/<user>/<repo>/issues/<issue_number>` という形式

入力欄の上にある入力サンプル通り入力すれば OK。

![git-graph-issue-linking-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/035268f3-57c8-116b-a1dc-eec8136933df.png)

メッセージに #n を含むコミットを見てみると？

![git-graph-issue-linking-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/970a6b1d-63c7-a7d3-8707-79968185dd8e.png)

左: 設定前, 右: 設定後

`#n` がリンクになっているのが分かります。もちろん、クリックすれば当該 Issue に飛びます。

## おわり

グラフを見ながら操作すると、どこにどうコミットをくっつけているかとか、また `git reset` とかした際どこに居るのかとか、ツリー上の現在位置を把握しつつ操作できるところに安心感があります。
Conventional Commits - コミットメッセージ仕様

お疲れ様です。

今日は「Conventional Commits - コミットメッセージ仕様」について部分いたします。

こんな形式のコミットメッセージ見たことないでしょうか。

chore(deps): update all non-major dependencies

これは[Conventional Commits](https://qiita.com/kins/items/304d0011d7020ee12923)に従ったものです。

# 結論

多くのOSSや開発現場は、（明確に宣言していないものの）Conventional Commitsに影響を受け、PRタイトルやコミットメッセージを設定しています。

シンプルな仕様ですので、チームで開発する上で知っておくと良いと思います。

# 仕様/用途編

## 本家仕様

Conventional Commitsは、Gitのコミットメッセージの形式に関する仕様。
シンプルでドキュメントも分かりやすく、こちらのサマリと例から大体つかめる。

### コミットメッセージに含める情報

1. commit type：コミットの種別を表現する
    - fix：バグ修正
    - feat：機能追加
    - 上記以外の種別もチームで決めて使ってOK（※標準的な仕様は後述）
1. optional scope：commit typeに付け加えて、コミットが対象とするコードベース内の領域を補足する。省略可
1. description：概要。一般的にコミットメッセージの1行目に記載する内容
1. optional body：本文。一般的にコミットメッセージの1行目の後、空白行を空けて、3行目以降の記載する内容。（一般的慣習に従い）省略可
1. optional footer(s)：フッタ。一般的にコミットメッセージの本文の後、空白行を空けて、最後に記載する内容。（一般的慣習に従い）複数指定可、省略可
    - BREAKING CHANGE: <description>：破壊的変更を表すフッタ。commit type（scopeがある場合はscope）の後ろに!をつけることでも表現可。両方の指定も可。

### コミットメッセージの構成方法

```
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
```

### シミュレーション
コミットメッセージに含める情報が、

- commit type： fix
- scope： api
- description： prevent racing of requests
- optional body： Introduce a request id, and add request id to any log message.
- footer(s)：
    - BREAKING CHANGE: drop support for Node 6
    - Refs: #123（※一般的なフッタ）

だとすると、以下のようになる。

```
fix(api)!: prevent racing of requests

Introduce a request id, and add request id to any log message.

BREAKING CHANGE: drop support for Node 6
Refs: #123
```

## 周辺仕様

commit typeは、前述のとおり、fixとfeat以外も使うことができる。
一般には、commitlintというツールの定義が普及している。

```
[
  'build',
  'chore',
  'ci',
  'docs',
  'feat',
  'fix',
  'perf',
  'refactor',
  'revert',
  'style',
  'test'
]
```

https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional#type-enum

## 用途

特徴として、commit typeやfooterのBREAKING CHANGEが、SemVerと対応している。

- BREAKING CHANGE：MAJOR
- feat：MINOR
- fix：PATCH

そのため、

1. 人にとって理解しやすい
    - コミットの意図や対象とする機能について、コンテキストをひと目で共有できる
1. 自動化しやすい
    - 例1：CHANGELOGの自動生成
        - https://github.com/conventional-changelog/conventional-changelog
    - 例2：ビルドやライブラリリリースの自動化
        - https://github.com/semantic-release/commit-analyzer

# 採用状況編

多くのOSSや開発現場は、明確に宣言していないものの、Conventional Commitsに影響を受け、PRタイトルやコミットメッセージを設定しています。

実際にJS界隈のOSSリポジトリを無作為に10個ほど調べたところ、7個がConventional Commits形式に従っていました。

以下に3つの例をまとめます。

## 例1. Nuxt

Nuxtは、コントリビュータに対して、PRタイトルをConventional Commits形式で書くように明確に求めている。

実際にこのルールは守られている模様。

https://github.com/nuxt/framework/pulls

一方で、上記ガイドラインにコミットメッセージについての言及はない。

実際にリポジトリをみてみると、PRはSquash & Mergeされている。Squash & Merge時、PRタイトルがコミットメッセージになるため、PRタイトルに関するルールだけで、ツリーがConventional Commitsに保たれているようである。

## 例2. Fastify

Fastifyは、明確にはConventional Commits採用を宣言していない模様。

しかし、実際は大半のコントリビュータがConventional Commitsに倣っている。

https://github.com/fastify/fastify/pulls?q=is%3Apr+is%3Aclosed

## 例3. React

Reactは、明確にはConventional Commits採用を宣言しておらず、Conventional Commitsに意図的に従っていない模様。
コントリビュータが作成するPRタイトルに一貫性がないように見える。

https://github.com/facebook/react/pulls?q=is%3Apr+fix%3A+is%3Aclosed

今日は以上です。

ありがとうございました。
よろしくお願いいたします。
【firebase storage emulator】 resource: the server responded with a status of 403 (Forbidden)

```
resource: the server responded with a status of 403 (Forbidden)
```
というエラーが出てfirebase emulator のstorage にアクセスできない
→ storageのrulesによって制限がかかっているから

firebase.jsonと同じディレクトリにある storage.rules の allow read , write: if false; の false を true に書き換える
```
rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}
```
これで解決

storage.rulesがない場合は
```
firebase init storage
```
でstorageを初期化してください、追加されるはずです
コンテナから作成したLambdaで、「Phase: init Status: timeout」になったことと解決方法

# 0. はじめに
こんにちは、yuzu_juiceです🥂
最近、Lambdaをコンテナで動かせることを知り、いろいろ遊んでいました。

# 1. 発生した事象
コンテナからデプロイしたLambdaを実行したところ、CloudWatchのログに以下のエラーが出ました。
```
INIT_REPORT Init Duration: 10028.26 ms Phase: init Status: timeout
```
# 2. 正しかった対応方法
Lambdaのコンソールから、環境変数を設定しました。
ローカルでテストしていた際はコードがDockerfileに設定した環境変数を参照していたため、Lambdaにデプロイ後もDockerfileに書いた環境変数が参照されるだろう、と思っていました。
実際は、コンテナからデプロイされたLambda関数は、Dockerfileの環境変数を読まず、Lambda側の環境変数を読み込むようです。

# 3. 試したけどうまくいかなかったこと
## Lambdaタイムアウト値の変更
Lambdaがタイムアウトしているのだと思い、「Lambda関数→設定→一般設定→タイムアウト」からタイムアウト値を変更して対応しようとしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086592/5950d14c-072e-617e-03fb-b5c8d65c254b.png)

タイムアウト値はデフォルトで3秒になっているので、エラーログに出力されていた10028.26 ms(約10秒)以上に設定してみます。

## 結果
変わらず、タイムアウトのエラーが解消されませんでした。

## タイムアウトの変更では何がダメだったか
Lambdaの実行には、以下4つのフェーズがあります。
1. Init phase (初期化フェーズ)
1. Restore phase (復元フェーズ)
1. Invoke phase (呼び出しフェーズ)
1. Shudown phase (シャットダウンフェーズ)

参考ドキュメント：[Lambda 実行環境のライフサイクル](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtime-environment.html#runtimes-lifecycle)

今回は、このInit phaseでタイムアウトが発生していたようです。
そして、上で試したタイムアウト時間の延長は、Invoke phaseでのタイムリミットを設定するものであり、Init phaseのタイムアウト時間には関係がないようです。

# 4. 最後に
一見エラーログを見ただけでは根本原因がつかみにくい事象だったのでかなり焦りましたが、解決できたことでまた少しAWSの力が付いたと思います💪
この記事が同じ事象で困った人の助けになれば幸いです！
[備忘録]Cursor + WSL + condaでカーネルを追加

<h2>初めに</h2>
<p>・Cursor: すごいエディタ
<p>・WSL: Windows上でLinuxを動かせるやつ
<p>・conda: 仮想環境つくるやつ

<h2>環境
<p>・Windows 11
<p>・Ubuntu 22.04
<p>・Anaconda3-2024.02-1-Linux

<h2>方法</h2>
<h3>1. WSLを導入してUbuntuをインストール．省略．</h3>
<h3>2. Cursor上でWSLにリモート接続する．省略(拡張機能入れるだけ)．</h3>
<h3>3. UbuntuにAnacondaをインストールする．</h3>
<a href="https://www.anaconda.com/download">公式サイト</a>から最新版をインストールする．

```terminal:zsh
$ wget https://repo.anaconda.com/archive/Anaconda3-2024.02-1-Linux-x86_64.sh
```
上記コードを実行すると，カレントディレクトリにAnaconda3-2024.02-1-Linux-x86_64.shがダウンロードされる．これを以下のコマンドでインストールする(zsh部分はお使いのshellで)．

```terminal:zsh
$ zsh Anaconda3-2024.02-1-Linux-x86_64.sh
```

途中でyesを入力し，最後にインストールするディレクトリを確認する．変更しないのならそのままEnter．
ここでは/home/usernameディレクトリ下にインストールした．
以下のコマンドでバージョン確認できれば成功．

```terminal:zsh
$ conda --version
conda 24.1.2
```
一応ターミナルを再起動しておく．
<h3>4. 仮想環境を作りCursorにカーネルを追加する．</h3>

最初はbaseのみしかないことを確認．

```terminal:zsh
$ conda info -e
# conda environments:
#
base                     /home/<username>/anaconda3
```


以下のコマンドで仮想環境を作る．

```terminal:zsh
$ conda create -n py3.11 python=3.11
```

続いて起動する．

```terminal:zsh
$ conda activte py3.11
```

以下のようになっていれば成功．現在py3.11という仮想環境にいることがわかる．
```terminal:zsh
$ conda info -e
# conda environments:
#
base                     /home/username/anaconda3
py311                 *  /home/username/anaconda3/envs/py.311
```

※※※ここで，conda activateの前にconda initしろ，みたいなエラーがでたら，

```terminal:zsh
$ conda init zsh
```
とすればOK(zshの場合)．※※※
最後に，以下のコマンドでJupyterカーネルに仮想環境を追加する．

```terminal:zsh
$ pip install ipykernel
$ python -m ipykernel install --user --name=py.311 
```

あとは.ipynbファイルを開き，"カーネルの選択"→"別のカーネル"→"Python環境..."→"py.311"を選択すればよし．

<h3>5. condaにモジュールをインストールする．</h3>
仮想環境を作っただけではデータ分析などに必要なモジュール(numpu, pandas)が入っていないので，Anacondaをインストールしてまとめて導入する．

```terminal:zsh
$ conda install anaconda
...
Proceed ([y]/n)? y
...
done
```

これで，notebookでモジュールが使用可能になる．
【Next.js】SSRを回避する方法

Next.jsにおいてSSRを回避し、`useLayoutEffect`などを正常に使用する方法について記載します。

## `dynamic`を使用する

`dynamic`で`{ssr: false}`を指定することでSSRを回避できます。

```jsx
const Sample = dynamic(() => import('../components/Sample'), { ssr: false })
```

https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading#skipping-ssr

## `Suspense`を使用する

以下のように記述するとクライアント側で

```jsx

<Suspense fallback={<Loading />}>
  <Sample />
</Suspense>

function Sample() {
  if (typeof window === 'undefined') {
    throw Error('Sample should only render on the client.');
  }
  // ...
}

```

SSRではエラーとなり、最も近い`Suspense`の`fallback`に指定した`Loading`が表示されます。
クライアントで正常に処理が完了すると`Sample`が表示されます。


https://ja.react.dev/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content

## `isMounted` stateを使用する

以下のように記述するとコンポーネントがハイドレーションの後にのみレンダリングされます。

```jsx
export function Sample() {
  const [isMounted, setIsMounted] = useState(false)

  useEffect(() => {
    setIsMounted(true)
  }, [])

  return isMounted ? <RealContent /> : <FallbackContent />
}

```
`useEffect`はクライアントでのみ実行されるため、SSRでは`FallbackContent`がレンダリングされ、`useEffect`が実行されると`RealContent`が表示されます。
弥生会計のインポートデータ作成メモ

# はじめに
自宅にとっても古い弥生会計がある。税制が変わってしまっているため、事業に用いることはできないが家計簿を管理することはできる。しかし、手動で入力するのはめんどくさいのが正直なところである。

# インポート
データ入力の手間を省きたいのでデータをインポートしたい。マネーフォワードのデータをもとに仕訳日記帳のデータを生成したい。生成形式を調査する。

# 生成形式
エクセルで生成する場合の形式は下記の通り。一行目はレコードとして仮に入れたもので、取り込み時のデータには入れないこと。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/3a53c7b5-3bde-2bb3-d119-52fe340b43df.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/7ddc240e-1e23-d548-cf20-396e199045bc.png)

# 詳しい解説
本家の解説はこちら
https://support.yayoi-kk.co.jp/faq_Subcontents.html?page_id=27183&grade_id=Blue
UBUNTU　devファイルをインストールする方法

UBUNTUでダウンロードした「.dev」ファイルをもっと楽にインストールする方法を見つけたので投稿


1.sudo apt-get install gnome-softwareを実行

2.「ダウンロード」ディレクトリに移動して右クリック

3.「ソフトウェアのインストール……」的な言葉が表示されるのでクリック

4.「インストール」ボタンが表示されるのでクリックして完了。
※全部のファイルがこれに当てはまるかは不明
llama-3-youko-8bでのFew-Shot Promptingによる日本語品詞付与

[llama-3-youko-8b](https://huggingface.co/rinna/llama-3-youko-8b)は、[Meta-Llama-3-8B](https://huggingface.co/meta-llama/Meta-Llama-3-8B)を日本語に拡張したモデルらしいのだが、拡張に際してトークナイザの日本語化を[おこなっていない](https://qiita.com/KoichiYasuoka/items/8213a3e5e8cc9bf45b7f)。これがどういう問題を引き起こすか、国語研短単位でのUPOS (Universal Part-Of-Speech)品詞付与をFew-Shot Promptingで挑戦してみよう。5つの例文は、[この記事と全く同じもの](https://qiita.com/KoichiYasuoka/items/8b63a42dc730d8141dea)を選んだ。

```
>>> class TextUPOSList(list):
...   __str__=lambda self:"\n".join("###text:"+"".join(t for t,u in s)+"\n###UPOS:"+"|".join(t+"_"+u for t,u in s) for s in self)+"\n"
...
>>> ex=TextUPOSList()
>>> ex.append([("一","NUM"),("直線","NOUN"),("に","ADP"),("伸びる","VERB"),("電撃","NOUN"),("を","ADP"),("放ち","VERB"),("、","PUNCT"),("電撃","NOUN"),("ダメージ","NOUN"),("を","ADP"),("与える","VERB"),("。","PUNCT")])
>>> ex.append([("色々","ADV"),("と","ADP"),("面白い","ADJ"),("メニュー","NOUN"),("の","ADP"),("ある","VERB"),("店","NOUN"),("。","PUNCT")])
>>> ex.append([("しかも","CCONJ"),("、","PUNCT"),("ここ","PRON"),("は","ADP"),("コース","NOUN"),("が","ADP"),("リーズナブル","ADJ"),("な","AUX"),("の","SCONJ"),("です","AUX"),("。","PUNCT")])
>>> ex.append([("彼","PRON"),("は","ADP"),("コンピュータ","NOUN"),("を","ADP"),("個人","NOUN"),("の","ADP"),("持ち物","NOUN"),("に","ADP"),("し","VERB"),("まし","AUX"),("た","AUX"),("。","PUNCT")])
>>> ex.append([("2007","NUM"),("年","NOUN"),("9","NUM"),("月","NOUN"),("現在","ADV"),("、","PUNCT"),("以下","NOUN"),("の","ADP"),("メーカー","NOUN"),("から","ADP"),("対応","NOUN"),("製品","NOUN"),("が","ADP"),("発売","VERB"),("さ","AUX"),("れ","AUX"),("て","SCONJ"),("いる","VERB"),("。","PUNCT")])
>>> from transformers import pipeline
>>> tgn=pipeline("text-generation","rinna/llama-3-youko-8b",max_new_tokens=128)
>>> print("\n".join(tgn(str(ex)+"###text:国境の長いトンネルを抜けると雪国であった。\n###UPOS:")[0]["generated_text"].split("\n")[len(ex)*2:len(ex)*2+2]))
###text:国境の長いトンネルを抜けると雪国であった。
###UPOS:国境_NOUN|の_ADP|長い_ADJ|トンネル_NOUN|を_ADP|抜け_VERB|ると_SCONJ|雪国_NOUN|であ_AUX|た_AUX|。_PUNCT
```

『雪国』の冒頭文に品詞付与させてみたところ、私(安岡孝一)の手元では、llama-3-youko-8bは「`抜ける_VERB|と_ADP|雪国_NOUN|で_AUX|あっ_AUX|た_AUX`」を正しくトークナイズできず、結果として「っ」がどこかに消えてしまっている。もう一度やってみよう。

```
>>> print("\n".join(tgn(str(ex)+"###text:国境の長いトンネルを抜けると雪国であった。\n###UPOS:")[0]["generated_text"].split("\n")[len(ex)*2:len(ex)*2+2]))
###text:国境の長いトンネルを抜けると雪国であった。
###UPOS:国境_NOUN|の_ADP|長い_ADJ|トンネル_NOUN|を_ADP|抜け_VERB|ると_SCONJ|雪国_NOUN|であ_AUX|た_AUX|。_PUNCT
```

どうやら同じ結果だ。ならば「予想に反して品詞付与の精度がイマイチ」という文はどうだろう。

```
>>> print("\n".join(tgn(str(ex)+"###text:予想に反して品詞付与の精度がイマイチ\n###UPOS:")[0]["generated_text"].split("\n")[len(ex)*2:len(ex)*2+2]))
###text:予想に反して品詞付与の精度がイマイチ
###UPOS:予想_NOUN|に_ADP|反_VERB|して_ADP|品詞_NOUN|付与_NOUN|の_ADP|精度_NOUN|が_ADP|イマイチ_ADJ|。_PUNCT
```

「`反し_VERB|て_SCONJ`」がうまくトークナイズできていない上に「`。_PUNCT`」が勝手に追加されている。[4月20日](https://qiita.com/KoichiYasuoka/items/de33b591232b6f87c147)や[4月26日](https://qiita.com/KoichiYasuoka/items/2265b06f245ea3bd57a0)の記事にも書いたとおり、現時点のLLaMA-3は日本語対応が未熟で、まずはトークナイザを改良しなければいけない、ということだ。困ったなあ。
form_withについて

form_withについてまとめます。

### form_withとは
Ruby on Railsで入力フォームを簡単に作成することができるヘルパーメソッドである。

### 書き方例
```ruby:html.erb
<%= form_with (model: @post, local: true) do |f| %>
  <div class="field">
    <%= f.label :title, "タイトル" %><br />
    <%= f.text_field :title %>
  </div>

  <div class="field">
    <%= f.label :content, "内容" %><br />
    <%= f.text_area :content %>
  </div>

  <div class="field">
    <%= f.label :image, "画像" %><br />
    <%= f.file_field :image %>
  </div>

  <div class="actions">
    <%= f.submit "保存する", class: :form__btn  %>
  </div>
<% end %>
```
### 解説
```ruby:
<%= form_with (model: @post, local: true) do |f| %>
```
model:モデルのインスタンスを指定する。
つまり、保存したいテーブルのクラスのインスタンスのこと。

```ruby:posts_controller
def new
  @post = Post.new # 新規投稿
end
```
コントローラーに定義した@postを指定する。

|f|はフォームビルダーと呼ばれる。
ラベルやテキストフィールドなどのフォームの要素を作るためにそのビルダーオブジェクトを使う。

```ruby
f.label #ラベル
f.text_field #テキスト入力欄（複数行の内容などの場合）
f.text_field #一行入力欄（名前、タイトルなど一行の場合）
f.submit #送信ボタン
```

このまとめにより、一つ一つの役割が明確になりました！
プログラミング支援AIサービスのリンク集

プログラミング支援AIサービスを昔ながらのGoogle検索で探して自分用のリンク集を作ってみた。検索前はGithub CopilotとGitlab、AWS CodeWhispererの３択かと思ったが、ネット上のリンクでは、Github Copilot一強。そして、個人は無料で使えるAWS CodeWhispererが次点だった。企業利用だとまた違うと思われるけど、予想と違ったのでちょっとびっくり。また調べたらコメントを追記する。

■まとめ記事
プログラミング支援AIサービスが主要各社から出そろう　各サービスのまとめ　GitHub／AWS／Google／GitLab／JetBrains
https://www.itmedia.co.jp/news/articles/2312/18/news093.html

【2024年4月版】コード生成AIサービス 比較
https://qiita.com/zutoasa/items/81fd68fb1a2fde7e8692

■GitHub Copilot
サクッと始めるAIネイティブ開発【GitHub Copilot / ChatGPT】
https://zenn.dev/umi_mori/books/ai-native-programming

GitHub Copilot
https://docs.github.com/ja/copilot

GitHub Copilotとは？
利用可能な開発環境・導入方法・活用事例を紹介
https://logmi.jp/tech/articles/330037
>・GitHub Copilot Individual10米ドル/月、もしくは100米ドル/年
>・GitHub Copilot Business1ユーザーあたり19米ドル/月
>・GitHub Copilot Enterprise1ユーザーあたり39米ドル/月

>GitHub Copilot Enterpriseプランは、2024年2月より新しく運用が開始される、エンタープライズ向けプランです。導入組織で使われているコードを学習させ、ファインチューニングした独自AIを利用できるのが最大の特徴です。

■GitHub Copilot Workspace
GitHub Copilot Workspace：GitHub Copilotネイティブの開発環境へようこそ
https://github.blog/jp/2024-04-30-github-copilot-workspace/
開発者必見！GitHub Copilot Workspaceの使用で開発効率を最大化
https://www.multifverse.com/blog-posts/github-copilot-workspace-introduction


■GitLab Duo Code Suggestions/Duo Chat
GitLabのAI支援によるコードの提案
https://about.gitlab.com/ja-jp/solutions/code-suggestions/
https://docs.gitlab.com/ee/user/project/repository/code_suggestions/index.html

GitLab DuoのCode Suggestionsを使ってみよう #GitLab #GitLabDuo #AI #プログラミング
https://www.creationline.com/tech-blog/63645


■Gemini Code Assist
Gemini Code Assist
https://cloud.google.com/products/gemini/code-assist?hl=ja

開発者のための生成 AI ツール『Duet AI for Developers』を触ってみた
https://zenn.dev/cloud_ace/articles/usage-duet-ai-for-developers

Google Cloud プロジェクトで Duet AI が使えるようにする
https://zenn.dev/google_cloud_jp/articles/duetai-vscode

VS Code で Gemini Code Assist を使う
https://qiita.com/kanuazut/items/a71a6cd5bb47b2efdd7f


■Amazon CodeWhisperer
Amazon CodeWhisperer
https://aws.amazon.com/jp/codewhisperer/

GAされたAmazon CodeWhispererを試してみる
https://zenn.dev/yuta28/articles/codewhisperer-tutorial

5分で理解するAmazon CodeWhisperer
https://qiita.com/Brutus/items/a1bf6022079af98c98b0

Amazon CodeWhispererの特徴とは？VSCodeへの導入方法と合わせて解説
https://envader.plus/article/139

CodeWhisperer の基本的な使い方やプロンプトについて学べるワークショップに参加しました（DOP307） #AWSreInvent
https://dev.classmethod.jp/articles/reinvent-2023-dop307/

Amazon CodeWhispererを使用する方法(VSCode)
https://qiita.com/k-o233/items/a3983af68d2debffe9a4
Windows11　ネットワークの応答速度とセキュリティ向上

Windows11やWindows10用にネットワークの応答速度を上げるための備忘録
また、セキュリティ面の向上にもつながるため推奨

1.「コントロールパネル」を起動。

2.「ネットワークと共有センター」をクリック

3.現在接続中のネットワークをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772884/7666b44c-b5f4-91a4-831e-a7355b04c172.png)

4.「プロパティ」をクリック

5.「インターネットプロトコルバージョン(TCP/IPv4)」を選択し右下「プロパティ」をクリック

6.DNSの設定を下記の数値にして「OK」⇒「OK」をクリックして設定完了。
※DNSを「CloudFlare」に設定


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772884/6c6c34dd-dfae-2f77-70bb-bdecc9f9a878.png)
Render_DBをA5m2で使えるようにする

## 宣伝
[作成した大喜利アプリリンク](https://hello-4m00.onrender.com/)
ユーザ作成が面倒な人は、「ユーザ：test,パス:test」でログインできます
それすら面倒な人は、ゲストログインできます
*無料プランのため、初期サイト表示に時間がかかります。

## 目次
1. はじめに
1. 接続方法

## はじめに
WEBアプリを作成し、デプロイ先にRenderを選択した。そこでpostgresDBもRenderで実現した。DBの状態を確認するためにA5M2で表示したかったので、その時の設定方法をまとめる

[Webアプリ作成の記事１](https://qiita.com/ssatoshi_117117/items/ec18bcdd039461afae43)
[Webアプリ作成の記事２](https://qiita.com/ssatoshi_117117/items/b5fe92d85dd44283b86f)

## 接続方法
RenderのDachbord/Infoの「External Database URL」と「Password」を使う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781864/e8ef1052-7da8-daa4-9afd-c9a3257eaed3.png)


```text:External Database URL

postgres://「Username」:Z2LS2U8Eq47RSBL0RIUkoGVe99NQRTjO@dpg-co72rcmd3nmc73e35tog-a.singapore-postgres.render.com/mydb_c9r8

```

以下A5M2のデータベース追加
画像のように設定する。サバー名の設定にすこし手こずった。
私は、本番Verにしてそれっぽくした。これは好み
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781864/86f036be-95b4-905a-7418-2e3c6f9efe2e.png)

設定後は、ローカル等と同様に、データを確認したり、SQLを実行したりできるよ！
【React環境構築編】個人開発ログ #1

# 動作環境
OS: macOS
CPU: Apple M1チップ

# Reactの環境構築
まずは、Node.jsをインストール
以下のサイトから行いました。
[nodejsインストールサイト](https://nodejs.org/en/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3783289/b5dd8599-d684-e004-b967-3e1a1a82e222.png)
「Download Node.js(LTS)」というボタンをクリックするとダウンロードされます。

ダウンロードされたインストラーを起動するとインストールが始まったので
全てデフォルトで進めてインストールを完了しました。

```sh
node -v
v20.12.2
```
上記のように表示されたのでインストール完了

# テストプロジェクトを作成
任意のフォルダで以下のコマンドを実行

```sh
npx create-react-app test-app
```

上記でReactプロジェクトができたら、そのプロジェクトに移動
```sh
cd test-app
```

Reactプロジェクトを起動

```sh
 npm start
```

このような画面が表示されればOK！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3783289/9dbd79fb-940e-ba6a-cf12-c14a8a75527f.png)
エラーが出たら喜べ。エラーをちゃんと出せ。

どうもエラーを出すもしくはエラーが出るのが怖いという人がいるみたい。例えば改修を行うときに既存部分でエラーが出ないことを最優先にして増築を行いいびつな構造を生み出すとか、単純に例外を全然使わないとか。エラーが出ると、「うわ、エラーになった。手間かけさせやがって面倒だなぁ…」みたいな感覚があって、とにかく自分がコードを書くときも一切例外を投げないというスタンスをとりがちなのかもしれない。

私はここで、適切にエラーが出てくれるのはむしろ喜ばしいことであり、自分がコードを書くときも積極的にエラーを出すようにすべきだ、という主張をする。

# 関数定義のドキュメンテーションの一部
ある関数の中身で一番最初に書くべき処理は何か、それは引数のチェックをして条件を満たさなければエラーを出すことである。例えば文字列は特定の形式になってなければならないとか、数値に最大値最小値があるとか、これらは関数の入力の前提条件としてよくあることだが、それをちゃんとチェックする。

```typescript
function f(s: string, o: { isHoge: boolean, fuga?: number }) {
  if(!/A-\d{4,8}/.test(s)) {
    throw new Error('"s" の形式が不正です');
  }

  if(o.isHoge && o.fuga == null) {
    throw new Error('"o.isHoge" が真の場合は "o.fuga" は必須です');
  }
  // 処理本体が続く…
}
```

引数の前提条件は余すところなく関数冒頭で表現しなければならない。型で表現できることは引数の型で、型で表現できないことはチェック処理を書く。こうすることで関数の役割および使い方が明確になる。関数定義の上の方を読むだけで、この関数は入力としてどんなデータを取るのかが理解できるようになっているべきである。

![エラーが出たら喜べ。エラーをもっと出せ。.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2354612/2470025f-2090-95eb-a2f3-3f20df7ca92d.png)

この関数を使うとき、引数の型が間違っていればコンパイル時にエラーになり、型で表現できない詳細な前提条件が間違っているときは、コードの実行時にその旨が正しくエラーとして返ってくる。チェック処理で適切なエラーを返すことによって、コンパイル時には劣るが、高確率でミスに気づくことができる。

# 本当に怖いのはエラーが出ることではない、エラーが出ないまま実はおかしな挙動になっている場合である
適切なエラーが出てくれるいうのは実に素晴らしいことだ。なぜならエラーが出てくれればミスに気づけるからである。エラーが出ると処理が完全に中断される、中断されれば何かがおかしいという事は嫌でも気づける。

本当に怖いのはエラーが出ないまま、実は想定外のおかしな処理をしている時である。この状態では実はバグが含まれているということに気づけないまま時間が経過し、後になって重大な影響を及ぼすということが起こりえる。

例えば以下のコード、

```javascript
function paymentMethodLabel(paymentMethod) {
    if(paymentMethod === 'creditCard') {
        return 'クレジット―カード払い';
    } else {
        return '口座振替';
    }
}
```

ここに第3の決済方法「コンビニ支払い」を追加する機能改修が入ったとする。これは大きな改修なのでコードベースの様々な部分で変更が必要になる中、この`paymentMethodLabel`の改修を忘れてしまった！この関数はコンビニ支払いの場合でも「口座振替」が返り、気づかずにそのままリリースしてしまったという事もあり得るだろう。

どうすれば防げたか、ちゃんとエラーを投げていればよかった。

```javascript
function paymentMethodLabel(paymentMethod) {
    if(paymentMethod === 'creditCard') {
        return 'クレジット―カード払い';
    } else if(paymentMethod === 'directDebit') {
        return '口座振替';
    } else {
        throw new TypeError('paymentMethod must be "creditCard" or "directDebit"');
    }
}
```

最初からこのように書いておけば`paymentMethod`に第三の値が来た場合に即座にエラーが投げられ処理が停止する。そうすればこの関数の改修を忘れていることに自然と気づけるだろう。

バグに気づけないという最悪の状況に比べればエラーが出るというのはその何倍もましである。**エラーを投げるというのは気づけないバグを減らすという観点からとても重要なことである**。

# 関数型プログラミングに関する補足
関数型プログラミングの考え方（特に直和型）を使うと、例外のような実行時エラーをコンパイル時エラーにすることができる場面が多い。当該部分のコードが実行されるされないに関わらずコンパイル時にエラーが出るのでより安心安全になる。

```typescript
// 引数 o を直和型を使った表現に変更
function f(s: string, o: { isHoge: true, fuga: number } | { isHoge: false }) {
  // 以下の実行時チェックが不要
  // if(o.isHoge && o.fuga == null) {
  //   throw new Error('"o.isHoge" が真の場合は "o.fuga" は必須です');
  // }

  // 処理本体が続く…
}

f('A-0000', { isHoge: true }); // コンパイル時エラー!
```

```javascript
// 引数を直和型で表現
function paymentMethodLabel(paymentMethod: 'creditCard' | 'directDebit') {
    if(paymentMethod === 'creditCard') {
        return 'クレジット―カード払い';
    } else if(paymentMethod === 'directDebit') {
        return '口座振替';
    } else {
        throw new TypeError('paymentMethod must be "creditCard" or "directDebit"');
    }
}

paymentMethodLabel('convenienceStore'); // コンパイル時エラー!
```