OmniAICreator/Qiita-1.07M huggingface dataset:
Kusanagi9 で wp-login.php などの管理画面に Basic 認証を実装する(NGINX)

kusanagi9 のサイトに「ブルートフォース攻撃」を受けたので、ログインに関してBasic認証を実装したので、その内容を紹介します。
kusanagi8 とちょっと構成ファイルの場所などが違うので、備忘録までに。

## NGINX の構成ファイルの場所

各プロビジョン毎の構成ファイルがあり、その場所は以下のディレクトリ内に存在します。

`/etc/opt/kusanagi/nginx/conf.d/`

そこに二つの構成ファイルがあります。例えば、kusanagi-mainというプロビジョンがあった場合は以下のようなファイルになります。

`kusanagi-main.conf`
`kusanagi-main.wp.inc`

ここでは、WordPress の管理者ログイン等に Basic 認証を付けることを目的するので、`kusanagi-main.wp.inc`を修正する形で対応します。

## パスワードファイルの作成

`.htpasswd`というBasic認証のためのパスワードファイルを作る必要があります。このファイルの詳細の説明は割愛します。知らない方は別途調べてください。
ユーザー名を`user-name`として作る場合を以下は想定しています。また、デフォルの設定だと、全てのプロビジョンにて同じBasic認証が使われてしまいますので、プロビジョン毎に管理するためにパスワードファイルを各プロビジョン毎に変えるように、プロビジョンのフォルダの最上部に設定するようにここでは変更しています。もちろん、一つのプロビジョンしか使っていないような場合やステージングサイトと本番環境のみの場合は変更する必要はないと思います。
デフォルトでは設定場所が`/home/kusanagi/.htpasswd`となります。

```shell:command line
$ htpasswd -c /home/kusanagi/kusanagi-main/.htpasswd user-name
New password: 
Re-type new password: 
```
一番上のコマンドを実行すると上記のようにパスワードを入力するように表示されますので、2回同じパスワードを入力してください。
ここで設定したパスワードとユーザー名がBasic認証時に使うものとなります。

## 構成ファイルの変更
以下のviコマンドなどで設定ファイルを書き換えます。

```shell:command line
$ vi  /etc/opt/kusanagi/nginx/conf.d/kusanagi-main.wp.inc
```

2023年3月現時点でBasic認証の設定箇所は19行目から24行目となります。
デフォルトとの違いも含めての記載は以下の通りです。

```diff_conf:
18    location ~* /wp-login\.php|/wp-admin/((?!(admin-ajax\.php|images/)).)*$ {
-19   satisfy any;
+19         #satisfy any;
-20   allow 0.0.0.0/0;
+20         #allow 0.0.0.0/0;
-21   allow 127.0.0.1;
+21         #allow 127.0.0.1;
-22   deny all;
+22         #deny all;
23     auth_basic "basic authentication";
-24     auth_basic_user_file  "/home/kusanagi/.htpasswd";
+24     auth_basic_user_file  "/home/kusanagi/bb-main/.htpasswd";
```
この設定を変更して上書き保存をした上で、nginxを再起動します。kusanagi本体を再起動しても構いません。

```shell:command line
$ kusanagi nginx
nginx: the configuration file /etc/opt/kusanagi/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/opt/kusanagi/nginx/nginx.conf test is successful
nginx completed.
```

上記のように成功が表示されたら、問題なくnginxが再起動されています。
もし、エラーが出た場合はサイトが表示されていませんので、変更したファイルを元に戻すようにしてください。

以上で設定方法は完了です。
Spectralでパスが小文字英数字のみかをチェックするルール

この投稿では、[Spectral] を使って、OpenAPI パスのキーに小文字の英数字しか使われていないかどうかをチェックする方法を紹介します。

[Spectral]: https://github.com/stoplightio/spectral

## Spectral とは？

[Spectral]は、ルールベースのJSON/YAMLリンターです。どんなJSON/YAMLもチェックできますが、特にOpenAPI用に設計されています。

## 問題点

複数の単語を含むパスを表現する場合、キャメルケース、ケバブケース、アンダースコアなど、いくつかの形式の選択肢があります。

```
GET /pullRequests/{id}
GET /pull-requests/{id}
GET /pull_requests/{id}
GET /pullrequests/{id}
```

チームで共同作業を行う場合、API設計規約でどの形式を選択すべきかを定義しておく必要があります。

しかし、人々はしばしば間違いを犯します。規約を知らなかったり、注意深く読んでいなかったりします。

## 解決策 Spectralでパス規約をチェックする

この問題を解決するためには、Spectralでチェックを自動化することが有効です。

パスが全て小文字の英数字であるかどうかをチェックするための、Spectralのルールは次のようになります。これを.spectral.ymlに記述します。

```yaml
extends: spectral:oas
rules:
  path-keys-lower-case-alphanumeric:
    message: "Path must be lower case. Only lower case alphanumeric characters are allowed."
    given: "$.paths"
    then:
      field: "@key"
      function: pattern
      functionOptions:
        match: "^(?:\\{[^}]+\\}|[/a-z\\d])*$" # https://regex101.com/r/eHmZ29/1
```

このルールを追加することで、Spectralはパスに大文字やハイフンが含まれる場合に警告を出すようになります。

```sh
$ npx spectral lint openapi-spec.yaml
/path/to/my/openapi-spec.yaml
 17:15  warning  path-keys-lower-case-alphanumeric  Path must be lower case. Only lower case alphanumeric characters are allowed.  paths./pullRequests
 27:23  warning  path-keys-lower-case-alphanumeric  Path must be lower case. Only lower case alphanumeric characters are allowed.  paths./pull-requests

✖ 2 problems (0 errors, 2 warnings, 0 infos, 0 hints)
```

## ルールの詳細

上で紹介したルールは、Spectralのコア関数[pattern]を使用しています。この関数は、与えられたフィールドが正規表現にマッチするかどうかをチェックします。

[パターン]: https://meta.stoplight.io/docs/spectral/ZG9jOjExNg-core-functions#pattern

正規表現 `^(?:\{[^}]+\}|[/a-z\d])*$` は、パスが小文字の英数字のみを含むかどうかをチェックする正規表現です。この表現は以下の文字列にマッチします。

```
/
/foo
/123
/foobar
/foo123
/{foo}
/{fooBar}
/{foo_bar}
/{foo-bar}
/users
/users/{userId}
/users/{user-id}
/users/{userid}
/users/{user_id}
```

一方、以下の文字列は禁止されます。

```
/Foo
/fooBar
/foo-bar
/foo_bar
/temas/{teamId}/MEMBERS/{userId}
```
【GitHub Actions】ストレージの使用容量を削減する

## はじめに
GitHub Actions (GitHub Pages) を使ったリポジトリを**パブリック**から**プライベート**にした直後に次のようなメールが届いた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1946472/642e846c-b41b-8765-8b56-98080c7e136c.png)
```:メールの内容
You've used 100% of included services for the username account

Shared storage usage
 
Hello! We wanted to provide you with an update on your usage and spending.

Storage used   528MB of 512MB included

You've used 100% of included services for GitHub Storage (GitHub Actions and Packages)

To continue using Actions & Packages uninterrupted, update your spending limit.

Your usage will reset on May 01, 2022.

Update spending limit
```

`Update spending limit` ボタンをクリックすると、設定ページが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1946472/e9459a96-9a40-58d2-21f2-c33c39728316.png)

## 原因
リポジトリを**プライベート**に切り替えたことによって利用制限がかかってしまった。

## GitHub Actions の利用制限について
+ パブリックリポジトリ：無料
+ プライベートリポジトリ：ストレージ制限あり

https://docs.github.com/en/billing/managing-billing-for-github-actions/managing-your-spending-limit-for-github-actions#about-spending-limits-for-github-actions

## 解決策
対象のリポジトリはパブリックでも問題なかったため、パブリックに戻した。しかし、**使用容量が変わらない**ままだった。

そこで、いくつかの方法を試してみた。

### Remove artifacts
https://github.com/marketplace/actions/remove-artifacts

+ removes artifacts that are older than the specified age
+ has the option to keep release (tagged) artifacts
+ has the option to keep a number of recent artifacts
+ respects GitHub's rate limit

使い方は非常に簡単で、リポジトリに `.github/workflows` ディレクトリを作成し以下のファイルを追加、push するだけでよい。

```yml:remove-old-artifacts.yml
name: Remove old artifacts

on:
  schedule:
    # Every day at 1am
    - cron: '0 1 * * *'

jobs:
  remove-old-artifacts:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
    - name: Remove old artifacts
      uses: c-hive/gha-remove-artifacts@v1
      with:
        age: '1 month' # '<number> <unit>', e.g. 5 days, 2 years, 90 seconds, parsed by Moment.js
        # Optional inputs
        # skip-tags: true
        # skip-recent: 5
```

### purge-artifacts-action
https://github.com/Spendesk/purge-artifacts-action

+ deleting old artifacts by setting expire duration

```yml:delete-old-artifacts.yml
name: 'Delete old artifacts'
on:
  schedule:
    - cron: '0 * * * *' # every hour

jobs:
  delete-artifacts:
    runs-on: ubuntu-latest
    steps:
      - uses: kolpav/purge-artifacts-action@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          expire-in: 7days # Setting this to 0 will delete all artifacts
```

使い方は先程の [Remove artifacts](#remove-artifacts) と同じ。今回は `expire-in: 0` と設定し、すべてのアーティファクトを削除。

### 効果
使用容量が少なくなりアラートが消えた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1946472/dbc74d0c-9f31-75ef-fef8-4d881e568254.png)

### 支払制限を設定
アラートが消えない場合に [Limit spending](https://github.com/settings/billing/spending_limit)  に `$1` を設定すると解決するという報告もある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1946472/28f5b8bc-256e-b596-72d2-c58f1f199020.png)

https://stackoverflow.com/a/65966234
個人的おすすめツール(随時更新)

# はじめに

自分が使っている便利なツールやサイトを紹介します。
Windowsのツールをメインに紹介します。
随時更新予定です。


# メモ系

## Notion

https://www.notion.so/ja-jp/product

- Web上で動くメモアプリ
    - マークダウン等の記述方法で階層的にデータを管理できる
- 競合としてEvernote等
- 基本使用は無料

### Save to Notion

https://chrome.google.com/webstore/detail/save-to-notion/ldmmifpegigmeammaeckplhnjbbpccmm

- Chrome拡張機能のSave to Notionを使えばWebスクラップ的に後で読みたいサイトや読み返したいサイトを登録できるので便利！


## Obsidian

https://obsidian.md/

- ローカルで動くメモアプリ
    - マークダウンで記述する
    - ファイル同士のリンクを可視化して表示してくれる
    - マークダウンで記述する上で　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　
- 基本使用は無料


# 画像系

## ScreenPresso

https://www.screenpresso.com/ja/

- 基本使用は無料
    - 画像の再編集や動画のウォーターマークを消したりするには課金が必要なので課金推奨
        - 約4,000円で1ユーザ5台まで使用可能なライセンス

# ターミナルソフト

## RLogin

https://kmiya-culti.github.io/RLogin/

- 分割表示ができるターミナルソフト
- 背景やタブに接続先情報を表示できる点も便利

→
2022/07/18
Tips等記事化しましたので良ければご参照ください

https://qiita.com/g-iki/items/5d15247b9154bf2e3b17

## Windowsターミナル

https://docs.microsoft.com/ja-jp/windows/terminal/

- Powershellやコマンドプロンプト、WSL等で使用
- 通常のPowershellやコマンドプロンプトではできないタブ表示やカスタマイズ性もあるので便利！

# DB系

## DBeaver

https://dbeaver.io/

- 様々なDBに対応しているクライアント
    - MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Apache Hive, Phoenix, Presto...など
- リレーションを辿って行ける機能やER図を表示してくれる機能が便利
- (見た目的にはEclipseのような見た目をしている)

## NoSQLBooster

https://nosqlbooster.com/home

- mongoDB用のクライアント
- 基本的な機能はフリーライセンスで十分使えるが、インポート・エクスポート・フィルター等の機能を使うにはライセンスが必要(結構お高め・・・)
- JSON表示だけでなく、Tree表示やテーブル表示ができるので視覚的にわかりやすく表示できる

# ユーティリティ系

## PowerToys

https://docs.microsoft.com/ja-jp/windows/powertoys/install

- Microsoft製の「なぜそれを標準機能としなかった！？」というような機能が盛り込まれたツール群
    - ファイル、フォルダの一括リネーム
    - ウィンドウの常に手前表示
    - 画面上のカラーコードを取得するスポイト
    - ウィンドウの自動配置
    - ...など

## DevToys

https://devtoys.app/

- 文字列のエンコード・デコード、整形、ランダム文字列の生成など、ちょっと欲しかった機能が盛り込まれたツール群
- オフラインで動作するので、Web上でやりたくないデータの整形や編集にも使用可
- エンジニアのスイスナイフ(十徳ナイフ)と呼ばれている

# 情報収集系

## Inoreader

https://www.inoreader.com/

- RSSリーダー
- よく見るサイトを登録しておいてまとめて管理できる

# エディタ

## VSCode

https://azure.microsoft.com/ja-jp/products/visual-studio-code/

- 言わずとしれたエディタ(IDE)
- そのままでも十分な機能はあるが、拡張機能を入れることで大概のことはできてしまう

## サクラエディタ

https://sakura-editor.github.io/

- VSCodeとは別でちょっとしたメモに使ったり。。。
- 矩形選択と正規表現を使った検索や置換はVSCodeよりも使いやすい(気がする、VSCodeで慣れれば不要かも)

# 開発支援

## SourceTree

https://www.sourcetreeapp.com/

- git操作をGUIでできるもの
- gitflowでの操作もGUIでできるので便利

## WSL

https://docs.microsoft.com/ja-jp/windows/wsl/install

- Windowsをメインで使っていてLinux系(主にUbuntu)を触りたくなったとき用
- VMやDockerで環境を作るよりも手軽に起動することができる

# 他

## Biscuit

https://eatbiscuit.com/ja

- Webアプリをまとめて管理できるブラウザ
- セッションを共有しないグループを作ることで、Microsoft Teamsのようなアプリをログアウトせず管理できる
【iTerm2】単語単位の移動や削除を可能にする方法

## はじめに
本記事はプログラミング初学者が学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。  
そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。  
間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。  

## 単語単位の移動
単語単位の移動は`Esc + b`や`Esc + y`で可能ですが、連続で移動しようとすると`b`や`y`が入力されます。  
任意のキーかつ連続で移動できる設定方法を以下に記載します。

### 設定画面を開く
iTerm2を開いて`cmd + ,`で`Preferences`を開きます。  
そして`Preferences`の`Keys`を開きます。
![image220427_003532.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/db56ab7a-24ef-e29b-1a26-2f40049ca8f5.png)


### 設定する
`Keys`の中の`Key Bindings`を開き、右下の`+`をクリックします。
![image220427_003907.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/f0a5a062-5a8a-9228-0bc0-20da16120075.png)


`Keyboard Shortcut`に任意のキー、`Action`に`Send Escape Sequence`を選択、`Esc +`に`b`を入力し、`OK`をクリックします。
![image220427_004414.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/3cf3b380-5cf1-ecfb-5cfc-a3fb2754c529.png)


すると、任意のキー（上記の例では`cmd + ←`）で単語単位の移動ができるようになります。  
`Esc + f`は上記の`Esc +`の箇所に`y`を入力することで設定可能です。

### コマンドの先頭、末尾に移動する
コマンドの先頭、末尾に移動するにはデフォルトでは`ctl + a`、`ctl + e`です。
これも単語移動と同様に設定することで任意のキーで実行できます。

`Keyboard Shortcut`に任意のキー、`Action`に`Send Hex Code`を選択、入力欄に`0x01`を入力し、`OK`をクリックします。
![image220427_010727.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/7b9e33cf-bdce-47bd-0008-3eb4af9fba5f.png)


これで任意のキーでコマンドの先頭に移動できます。  
`ctl + e`は上記の入力欄に`0x05`を入力することで設定可能です。

## 単語単位の削除
デフォルトでは`Ctr + w`で単語削除ができますが、以下のように設定することで任意のキーで単語単位の削除ができます。  

### 設定方法
「設定画面を開く」までは移動と同様です。  
`Keyboard Shortcut`に任意のキー、`Action`に`Send Hex Code`を選択、入力欄に`0x1b 0x08`を入力し、`OK`をクリックします。
![image220427_012849.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/85e0c419-06e5-f81a-0e40-e38ed7d9f7a0.png)


上記の設定をすると任意のキーで単語単位の削除ができます。
[Python] list, tuple, dict, bitへのアクセス速度比較

# 概要
Pythonで数億回の単位のループの中で何度も読み込まれる情報の取り扱いに際して、list, tuple, dict, bitシフトのうち、listを使うと一番良いことがわかったため、その結果をまとめる。なお、Pythonのバージョンは3.9.12を用いた。
**追記: 環境依存でlistとtupleの実行速度が逆転したり、同じになったりする場合があるようです。
ただ、他の方からも指摘を受けましたが、この程度の差なら可読性を優先すればよいと思います(とはいえlistでよいですが)。
また、この差が影響するレベルのプログラムなら、そもそもPythonを使うべきではないかと思います。**

# 結果
後述するプログラムで各処理に1億回アクセスした際の実行結果を先に示す。

~~~
list 2.5855608 s
tuple 2.8783302 s
dict 3.002389400000001 s
bit shift 4.6369679999999995 s
~~~~

このように、listを用いた場合において、最も早い結果を示した。
実際に実行したプログラムが下記で、bit shiftの場合は
~~~
test = (b >> 2) & 0b11
~~~
と書くのが正確だが、速度比較の観点から省略している。

~~~speed_test.py
import time

def main():
    i_max = 100000000
    l = [1, 2, 3]
    t = (1, 2, 3)
    d = {0: 1, 1: 2, 2: 3}
    b = 0b111001

    start_time = time.perf_counter()
    for _ in range(i_max):
        test = l[1]
    end_time = time.perf_counter()
    print("list", end_time - start_time, "s")

    start_time = time.perf_counter()
    for _ in range(i_max):
        test = t[1]
    end_time = time.perf_counter()
    print("tuple", end_time - start_time, "s")
    
    start_time = time.perf_counter()
    for _ in range(i_max):
        test = d[1]
    end_time = time.perf_counter()
    print("dict", end_time - start_time, "s")
    
    start_time = time.perf_counter()
    for _ in range(i_max):
        test = b >> 2
    end_time = time.perf_counter()
    print("bit shift", end_time - start_time, "s")

main()
~~~

# 考察
意外なことに、処理的には同じと思われるtupleとlistで速度差が生じた。
パフォーマンスの観点から、tupleを使うといい、とよく言われているが、それは生成時の話である。
しかも、生成時に巨大なlistやtupleを生成することはまずないため、実質的にtupleを用いる必要はないと思われる。
なお、メモリの観点からすると、tupleの方が優秀ではあるが、メモリを気にするサイズのtupleを生成することも少ないため、listを使うのが無難だろう。
個人的に知らなかったことであるが、bit shiftの計算は意外と遅いようで、dictへのアクセスよりも遅い結果となった。

# 結論
本ページでは膨大な繰り返しの中で使用するに適した複数要素を持つオブジェクトがlistであることを示した。

# 筆者が実施した他の速度比較
[[Python] 各種変数へのアクセス速度比較](https://qiita.com/KYUPHD/items/e62fd6955b59b812400a)
Azure Functions で 認証ユーザー情報にアクセスする

リクエストヘッダに、`X-MS-CLIENT-PRINCIPAL-NAME` および `X-MS-CLIENT-PRINCIPAL-ID`などのキーで含まれている。

***ただし*** 
> Different language frameworks may present these headers to the app code in different formats, such as lowercase or title case.

https://docs.microsoft.com/en-us/azure/app-service/configure-authentication-user-identities#access-user-claims-in-app-code

`JavaScript` の場合小文字でした。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/6becb15e-c073-6be2-5284-b4399bfd0a8c.png)
ARRAYFORMULAで、カスタム関数を使うには、二重配列処理が必要だった

Google Spreadsheetでは、ARRAYFORMULAが大変便利ですが、
ユーザー定義関数（カスタム関数）をGASで作った際に、
ユーザー定義関数を

```
=ARRAYFORMULA(someFunc(A:A))
```

のように適用しようとしてerrorに見舞われました。
someFunc() is not a function的な。

暫し考えて、spreadsheetは
```
[[],[],[]]
```
といった二重配列の構造であることを思い出し、
mapを二重に実行して処理することで、無事望んだ結果を得ました。
以下のような感じです。

```js
function arrayformulaFunc(arr) {
  //arrayformulaに対しては、二重のmapを使わないと処理されないことの対処
  return arr.map(a => {
      return a.map(b => someFunc(b))
    })
}

function someFunc(str) {
  return str.length//何かの単体処理
}
```

ARRAYFORMULAは最高に便利なので、カスタム関数と組み合わせるなら、こんな感じでやれるのだな、と学びがあったのでシェア。
【SpringBoot】JasperReportでJSONデータの出力

JasperReportのインストールなどは色々調べれば情報が出てきますので今回はプログラム側のみです。JSONデータを扱う方法をまとめておきます。

## プログラムの設定
JasperReportとJSONライブラリをビルド
```gradle:build.gradle
	implementation 'net.sf.jasperreports:jasperreports:6.19.1'
	implementation 'org.json:json:20220320'
```

以下ソースを追加。何をやっているかはコメントの通り
```java:JasperService
public void getPdf() {
	    try {
	    	
	    	//データソース作成
	    	JSONObject json = new JSONObject();
	    	json.put("test_field", "テストデータ");
	    	JsonDataSource datasource = new JsonDataSource(new ByteArrayInputStream(json.toString().getBytes()));

	        //パラメータ作成
	        Map<String, Object> params = new HashMap<>();
	    	
	        //テンプレート作成
	        Resource resource = new UrlResource("classpath:jasperTemplates/pdfTemplate.jasper");
	        InputStream in = resource.getInputStream();
	        JasperReport report = (JasperReport) JRLoader.loadObject(in);
	        //jrxmlをコンパイルしレポート作成する場合は以下の処理
	        //JasperReport report = JasperCompileManager.compileReport(in);

	        //「データソース」「パラメータ」「テンプレート」をもとにレポート作成
	        JasperPrint print = JasperFillManager.fillReport(report, params, datasource);
	        
	        //「レポート」をPDFとして出力
	        JasperExportManager.exportReportToPdfFile(print,"jasper.pdf");
	      } catch (IOException | JRException e) {
	        //エラー処理
	      }	
	}
```
マルチメディア

復習回数1
## 静止画・動画
これらは容量が大きくなる為、データのサイズを小さくする必要がある。
<b>ある決まり事に従い、データのサイズを小さくすることを<font color=blue>圧縮</font>という。
逆に元に戻すことを<font color=blue>解凍（伸長）</font>という。
圧縮した画像を完全に復元できる<font color=blue>可逆圧縮方式</font>と完全に復元できない<font color=blue>非可逆圧縮方式</font>がある。

### ファイル形式
#### -静止画
<b><font color=blue>BMP</font> - Microsoft(windows)標準。フルカラー(約1677万色)。壁紙などに使用。
<font color=blue>GIF</font> - 256色。可逆圧縮。イラストやアイコン。
<font color=blue>PNG</font> - 256色(PNG-8)とフルカラー(PNG-24)の2種類。可逆圧縮。部分的に透明になる。Web用の画像に使われる。
<font color=blue>JPEG</font> - 国際標準規格。フルカラー。不可逆圧縮。写真など。
#### -動画
<b><font color=blue>MPEG</font> - 国際標準規格。不可逆圧縮。MPEG-1はビデオCD用。MPEG-2はDVDやディジタル放送用。MPEG-4はMPEG-2よりも圧縮効率が高く、ビデオカメラやワンセグ放送で用いられている。<font color=blue>H.264/MPEG-4AVC</font> として規格化されている。<font color=blue>MP3</font>はMPEG1の音声部分の圧縮アルゴリズムを使用した音声データの圧縮方式。

### 画像データの種類
<b>ピクセルの集まりで画像を表現する<font color=blue>ラスタデータ</font>と、座標の位置や線分の長さなどを演算で表現する<font color=blue>ベクタデータ</font>の2種類がある。
<font color=blue>ラスタデータ</font>は色の種類や明るさがピクセルごとに調節できる。
例：BMP・GIF・PNG・JPEGなど
<font color=blue>ベクタデータ</font>は拡大しても図形の縁にギザギザ(ジャギー)が生じない。
<font color=blue>フォント</font>は文字の形を表すデータである。ビットマップフォントはラスタデータ。アウトラインフォントはベクタデータ。

### SVG
<b>図形オブジェクトをXMLで記述し、Webページでの図形描画にも使うことができる画像フォーマット。

## マルチメディアの応用
### CG
<b><font color=blue>コンピュータグラフィックス(CG)</font>はコンピュータを使って画像を処理・生成する技術、またその画像のこと。
### 用語
<font color=blue>アンチエイリアシング</font> - 斜め線や曲線などに発生するギザギザーを目立たなくする。

<font color=blue>テクスチャマッピング</font> - 物体の表面に柄や模様などを貼り付け、質感を与える。

<font color=blue>シェーディング</font> - 物体の表面に影付けをし、立体感を出す。

<font color=blue>レイトレーシング</font> - 光源からの光線の反射や透過をシミュレートし、物体の形状を描写する。

<font color=blue>クリッピング</font> - 画像表示領域にウィンドウを定義し、その内の見える部分だけを取り出す。

<font color=blue>モーフィング</font> - ある画像から別の画像へ、滑らかに変形させるために、中間に補う画像を作成する。

<font color=blue>レンダリング</font> - 物体のデータとして与えられた情報を計算によって映像化。

<font color=blue>ポリゴン</font> - 立体の形状を表現するときに使用する基本的な要素。三角形や四角形などが用いられている。

<font color=blue>モーションキャプチャ</font> - センサやビデオカメラなどを用いて人間や動物の自然な動きを取り込む。

<font color=blue>ソリッドモデル</font> - 物体を、中身の詰まった固形物として表現する。

<font color=blue>ワイヤーフレーム</font> - 物体を、頂点と頂点を結び、針金で構成されているように表現する。

<font color=blue>サーフェスモデル</font> - 物体を、面や曲面の集まりとして表現する。

<font color=blue>陰線消去</font> - 物体の裏側で見えていない線を描画しないようにする。

<font color=blue>メタボール</font> - 物体を球や、だ円形の集合として擬似的にモデル化する。

<font color=blue>ラジオシティ</font> - 物体同士の相互反射も考慮して物体の明るさを決定する。

### バーチャルリアリティ(VR)
<b><font color=blue>VR</font>は仮想の空間に入り込んだような効果を生み出す技術。仮想現実

### AR
<b>目の前にある現実の情景や風景の映像をコンピュータに取り込み、現実には存在しない仮想の情報を合成して映し出す技術。拡張現実。


参考文献：イメージ&クレバー方式でよくわかる 栢木先生の基本情報技術者教室
UIImageを正方形にリサイズする


まずは好きなサイズにカットしてみる。

```
UIImage *inImage = [UIImage imageNamed:@"image.png"];
CGRect rect = CGRectMake(0,0,100,100);

CGImageRef cgImage = CGImageCreateWithImageInRect(image.CGImage, rect);
UIImage *outImage = [UIImage imageWithCGImage:cgImage];
```

rectで好きな大きさを指定すれば良い。
Git クライアント Fork の基本

# 当記事の目的
* Git クライアント Fork について、簡単に紹介する。
    * Git の用語や仕組みそのものについては述べないため、別途お調べください。 


# Fork とは
https://git-fork.com/home
* Git クライアントの一種。
* Git 周りの一連の操作を直感的に行える便利ツール。


# 基本操作
## リポジトリを開く
`File` → `Open` からリポジトリを選択して開く。

## ブランチ作成
1. 作成するブランチの生やし元となるブランチに移動。
2. `New branch` を押下し、作成するブランチ名を入力。

※ `checkout after create` にチェックを入れると、作成後そのままそのブランチに移動してくれる。

## ブランチ移動
`All Commit` 画面左側にあるブランチ一覧部分にて、移動したい先のローカルブランチをダブルクリック。

※元々いたブランチにて、変更点が一切ない状態でのみ移動が可能。（変更点がある場合は、それをコミット or スタッシュ or 破棄することで、変更点をなくす必要がある。）

## ブランチ削除
1. 削除対象ブランチとは別のブランチに移動。
2. 削除対象ブランチを右クリックして `Delete [ブランチ名]` を押下。

## stage, unstage
1. 左上 `Local Changes` からコミット画面に移行。
2. stage したい場合、 `Unstaged` の中にあるファイルのうち stage したいものをクリックしてから `stage` を押下。
3. unstage したい場合、 `Unstage` ボタンを押下。

※ ファイルの一部分のみ stage または unstage したい場合は、 `Local Changes` 画面右側にて差分を表示している箇所から該当部分を選択の上、右クリックしてから `Stage` または `Unstage` を実行するとよい。

## commit
1. 左上 `Local Changes` からコミット画面に移行。
2. commit したいファイルを `stage` した状態でコミットメッセージを書く。
3. `Commit` ボタンを押下。

## push
1. push したいブランチに移動。
2. `All Commits` 画面にて、真ん中上辺りにある `Push` ボタンを押下。
3. プッシュ先のリモートブランチを選択して実行。

※ `Force Push` にチェックを入れると、強制的に push される。

## discard
（変更を破棄したい場合）
1. `Local Changes` 画面に移動。
2. 変更を破棄したいファイルの上で右クリックし、 `Discard Changes` を押下。

※ ファイルの一部分のみ変更を破棄したい場合は、 `Local Changes` 画面右側にて差分を表示している箇所から該当部分を選択の上、右クリックしてから `Discard Changes` を実行するとよい。

## reset
1. reset したいブランチに移動。
2. 戻りたい先のコミットを右クリック。
3. `Reset [ブランチ名] to Here` を押下。

## merge
（A ブランチを B ブランチに merge したい場合）
1. A ブランチに移動。
2. `All Commit` 画面左側のブランチ一覧部分にて、A ブランチを B ブランチに向かってドラッグ & ドロップ。
3. `Merge A into B` を押下。

## rebase
（A ブランチを B ブランチに rebase したい場合）
1. A ブランチに移動。
2. `All Commit` 画面左側のブランチ一覧部分にて、A ブランチを B ブランチに向かってドラッグ & ドロップ。
3. `Rebase A on B` を押下。
a. コンフリクトが起こらなかった場合、ここで rebase は完了。
4. コンフリクトが起こった場合、その旨が知らされるので、解消する。
5. コンフリクトを解消したファイルを、 `Local Changes` 画面の `Stage` ボタンから stage し、 右下の `Resolve Conflicts` を押下。
6. rebase をなかったことにしたい場合は `Local Changes` 画面右上の `Abort` ボタンを押下。

## stash
1. `All Commits` 画面真ん中上辺りにある `Stash` ボタンをクリック。
2. スタッシュの名前を入力し、実行。

※一部ファイルのみ stash したい場合は、`Local Changes` 画面にて該当ファイルの上で右クリックし、 `Stash Changes` を押下するとよい。

## stash を適用
1. `All Commits` 画面左下にある stash 一覧にて、適用したい stash の上で右クリック。
2. `Apply Changes` を選択して実行。
    a. コンフリクトが起こらなかった場合、ここで終了。
3. コンフリクトが起こった場合、その旨が知らされるので、解消する。
4. コンフリクトを解消したファイルを、 `Local Changes` 画面の `Stage` ボタンから stage し、 右下の `Resolve Conflicts` を押下。
4. コンフリクトの解消を含めた stash の適用をなかったことにしたい場合は `Local Changes` 画面右上の `Abort` ボタンを押下。

※ `Delete Stash After Applying` にチェックを入れると、適用された stash が stash 一覧から削除される。

## pull
### リモートリポジトリにあるブランチを、新規にローカルに pull してきたい場合
1. `All Commits` 画面左側のブランチ一覧部分にて、 `Remotes` 内にあるリモートブランチをダブルクリック。
2. `Track Remote Branch` とのダイアログが出てくるので、 `Track` を押下。

### 既存のローカルブランチに向かって、リモートブランチの状態を pull したい場合
1. pull したい先のブランチに移動。
2. `All Commits` 画面真ん中上辺りにある `pull` ボタン を押下。

## fetch
`All Commits` 画面真ん中上辺りにある `Fetch` ボタンを押下。

※リモートブランチの状況を「取得」するだけなので、どのブランチにいても OK。

# まとめ
Fork は使いやすいのですが、使い方を詳細に解説したドキュメントがあれば便利かと思い書いてみました。少しでもお役に立てれば幸いです。
【Git】Git cloneしようとするとfatal: remote errorになる

# 経緯
普通に[いつも通りclone](https://qiita.com/nmwkhl/items/fab5a72e13626b804f11)しようとしたら

```terminal:terminal
fatal: remote error: 
   is not a valid repository name
  Visit https://support.github.com/ for help
```
と出てきてcloneできませんでした。

## 結論
今回の原因としてはcloneしてくる際の、
SSHキーと新しいリポジトリ名の間にきちんと<b>スペースが入っていない</b>ことでした。
（しょうもなくてすみません！）

どうやら全角スペースを入れていたようです。
ターミナルでの全角は半角スペースの半分のサイズになるので気が付きませんでした。

```terminal:terminal
git clone 元のSSH 新しい名前
　　　　　　　　　　　　　　　　　　↑　　　　　　　　　　　　　↑
        ここ  と  ここ　　　に全角スペースが入ってた
```

## 調べたこと
原因が分からず調べてみると普段はGitの認証ができていないと出てくるエラーだそうです。
⚠何一つ試していないため自己責任でお願いします
・[remote: Repository not found.となった時の対応方法](https://qiita.com/ponsuke0531/items/4fe191b7bed03342cff2)
・[Nishii's Notebook
](http://bcl.sci.yamaguchi-u.ac.jp/~jun/notebook/git/faq/)

## まとめ
プログラミング経験が浅いので調べた結果をすぐ試したくなりますが、
色々試す前に本当に今の記述が合っているのかチェックすることがとても大事だと感じました。

おそらく今回の事で上の記事通りに試してたら今頃苦戦してただろうなと思います。

かなりしょうもないミスでしたが健忘録も兼ねて記事にしています。
ご覧頂きありがとうございました！
顔に対するDeepSortでの追跡

先にyolov4の検出に対するDeepSortでの追跡の紹介記事を書いた。

[DeepSort とYolov4の組み合わせの実装を調査中](https://qiita.com/nonbiri15/items/54949e179302353deea5)

それ以外の検出対象として、顔検出結果に対するDeepSortの実装があった。

https://github.com/wansook0316/Multi_Face_Tracker_Using_Deepsort


動画入力に対して、顔検出の結果を理解するためには、ただ単に、各フレームの検出位置がわかればいいわけではないことが多い。
- 動画入力の中で、顔の位置がどのように移動しているのかが、人の動きを理解することが必要だったりする。
    - 人数カウントの場合、シーンに登場して、視野の外に移動していく人の数をカウントしようとすると人の追跡は必須である。
- また、その顔が誰なのかを理解するために、全部のフレームで顔照合をするのも実際的ではない。
    - 顔照合を実施するフレームを減らすこと。
    - 顔照合困難な顔向きの顔であっても、その前の追跡情報で、正面顔での顔照合が有効であれば、その結果を利用したい。


### Multi_Face_Tracker_Using_Deepsort　にある動作結果の例

![2 (online-video-cutter com) (1)](https://user-images.githubusercontent.com/37871541/119682508-e6f5f400-be7d-11eb-9623-dadf082302e7.gif)

上記のgithub のページではREADEが多くの人に読みなれない言葉で書いてあるので戸惑うかもしれないが、勇気を持って、git  clone して動作させてみる価値がある。

コンピュータ分野の記事は、google translate でかなり翻訳できるので、顔に対して追跡を試して見たい人は、ぜひ試してみよう。

## git clone 後に自分のPCで動作させる際の留意点
- requirements.txt は、github の該当リポジトリの作者の動作環境を示したものです。
- このリポジトリで本当に必要なモジュールだけを記載したものではありません。
- また、モジュールのバージョンの指定も、作者の動作環境を再現するものになっています。
- 本当に必要なものだけを、step by step でインストールしていきながら、目的のスクリプトが動作するようにしていくのをおすすめします。

## ソースコードを読み解く
DeepSortでは、複数の対象物をtrackingする際に、追跡中の対象物の特徴を使って、trackingを行っている（らしい）。そのため、追跡中の対象物から特徴量を算出する部分がある。

```
# arcface_weights.h5 顔照合の特徴量を取り出すためのモデルファイル
model_filename = os.path.join(home, "weights", "arcface_weights.h5")
encoder = gdet.create_box_encoder(model_filename, batch_size=128)

# imgの各検出枠に対する特徴量を得る。
features = encoder(img, converted_boxes)
```

この特徴量をも利用し、フレーム間の検出での対応関係をつけている。

## deep_sort フォルダのコード
以下のフォルダにある`deep_sort` と`Multi_Face_Tracker_Using_Deepsort`　のコードは、差異がある。顔照合の`face_db` を`deep_sort` の下のモジュールで利用している。

https://github.com/theAIGuysCode/yolov4-deepsort/tree/master/deep_sort

---
## 参考
顔の追跡の別事例
https://github.com/Linzaer/Face-Track-Detect-Extract
既存laravelプロジェクトをsailでdockerに移行

<span>composer.jsonに以下の記載があればsailはインストール済み</span>
<pre>
    "require-dev": {
        "facade/ignition": "^2.5",
        "fakerphp/faker": "^1.9.1",
        "laravel/sail": "^1.0.1",
        "mockery/mockery": "^1.4.4",
        "nunomaduro/collision": "^5.10",
        "phpunit/phpunit": "^9.5.10"
    },
</pre>
<span>記載なければ以下のコマンドでインストール bashで実行</span>
<pre>composer require laravel/sail --dev</pre>

<pre>
php artisan sail:install

Which services would you like to install? [mysql]:
  [0] mysql
  [1] pgsql
  [2] mariadb
  [3] redis
  [4] memcached
  [5] meilisearch
  [6] minio
  [7] mailhog
  [8] selenium
</pre>
<span>コンテナ環境に何をインストールするか選択する</span>
<pre>0
または
0,3,4 //複数でも選択可能

Sail scaffolding installed successfully.//無事に実行されたら出る</pre>

<span>以下WSL(ubntu)で実行</span>
<pre>./vendor/bin/sail up -d</pre>
<span>または</span>
<pre>docker-compose up</pre>
<span>「docker-compose up」と「./vendor/bin/sail up -d」は同義</span>
http://localhost/ で動作確認

<p>動作確認後に起きたエラー</p>
<span>The stream or file "/var/www/html/storage/logs/laravel.log" could not be opened in append mode: Failed to open stream: Permission denied The exception occurred while attempting to log: The stream or file......</span>
<pre>sudo chmod -R 777 storage</pre>

<span>laravel\bootstrap\cache directory must be present and writable.</span>
<pre>chmod 777 bootstrap/cache -R </pre>
PrometheuでWindowsのSQLServerサービス状態監視

### PrometheuでWindowsのSQLServerのサービス状態を監視する手順となります。

++++++++++++++++++++++++++++++++
[環境]
prometheus : Ver.2.23.0
prometheus-alertmanager : Ver.0.15.3
++++++++++++++++++++++++++++++++


#### 監視ルールを設定するymlファイル(デフォルトではrules.yml)にSQLserverのサービス監視のルールを記載します。

###### 今回はSQLServerサービスの状態が "起動" 以外の場合にアラートを出すという設定を記載します。

```
    - alert: SQLServer-ServiceDown
      expr: windows_service_state{job="[ジョブ名]", name="[対象のインスタンスのサービス名]", state="running"} == 0   #1はrunning　0はrunning以外 
      for: 7m   #この時間を超えたらアラートWarningからCriticalに変更します。 s(秒) m(分)
      labels:
          AlertGp: [アラートグループ名]　#ここの名前は任意です。アラートに任意のグループラベルを設定できます。このラベルはalertmanager.ymlで利用することができます。
```

参考：
https://github.com/prometheus-community/windows_exporter/blob/master/docs/collector.service.md
Rubyの基本的な知識(備忘録)

プログラム言語「Ruby」とは？
①入力する文字数が少ない。
②初心者でもわかりやすく、理解しやすい言語である。
③日本人により開発された言語であるため、日本語の情報が豊富に存在する。
④Ruby On　Railsと言われる補助言語(フレームワーク)のようなものがあり、いろんな機能を素早く実装できる。
⑤スタートアップ等の企業で採用されることが多い。(とのこと。)

【主観】
個人的に他の言語「Python、Java」等の言語を調べたが確かに、Rubyの方が記述量は少なく理解しやすかった。

今後も学んだことを発信していきたいと思います。
Vercel上で1つのGitHub repoについて設定を変えて複数デプロイする

###### (An English translation is available [here](https://dev.to/tomoyukiaota/creating-multiple-vercel-deployments-with-different-configurations-from-a-single-github-repo-49cf).)

Vercel上で、１つのGitHub repoについて、設定を変えて複数ビルド＆デプロイしたいケースがありました。

具体的なケースとしては、私が開発しているアプリとして、[Photo Data Viewer](https://photo-data-viewer.vercel.app/)というものがあります。これは写真のExifデータを表示するためのアプリです。これを、web browser上で単体で動作するweb appとして公開した上で、[Photo Location Map](https://tomoyukiaota.github.io/photo-location-map/)というElectron appにも組み込みたいというものです。

コード的には、[photo-data-viewer](https://github.com/TomoyukiAota/photo-data-viewer)というGitHub repoにおいて、webpackのtargetをデプロイ先ごとに変更する必要があります。

 - [単体で動作するWeb app](https://photo-data-viewer.vercel.app/)用の設定
   - webpackのtargetは、`'web'`（デフォルト）
 - [Photo Location Map](https://tomoyukiaota.github.io/photo-location-map/)というElectron appに組み込むための設定
   - webpackのtargetは、`'electron-renderer'` 



# 設定方法

設定方法は、

 1. photo-data-viewer repoに対して、２つのVercel projectを作成する。
    - 最初は、１つのGitHub repoについて、１つのVercel projectしか作成できないと思いこんでいたので、これが盲点でした・・・

 1. Vercel projectごとに環境変数を設定する。
 1. photo-data-viewerのコード中で、環境変数を参照する。
    - `next.config.js`で`PDV_IN_PLM`という環境変数が`'True'`の場合、`config.target = 'electron-renderer'`としています。
    - [実際のコード](https://github.com/TomoyukiAota/photo-data-viewer/blob/07bfc5f09184468fa4368c692a7ad023122880d3/next.config.js#L29-L31)


# デプロイ先

Vercel projectごとのデプロイ先は次のとおりです。



| Vercel project              | URL                                                                                                                |
| :---------------------- | :------------------------------------------------------------------------------------------------------------------ |
| Web app              | https://photo-data-viewer.vercel.app                                     |
| Photo Location Map | https://pdv-in-plm.vercel.app  |

※ https://pdv-in-plm.vercel.app は、Electron renderer process用の設定でビルドしているので、Web browserで開いても正しく動作しません。Photo Location Map上で開くと、Electron renderer processで動作するので、正しく動作します。



以上、参考になれば幸いです。

# 参考

https://github.com/vercel/vercel/discussions/4879#discussioncomment-356114
BetterTouchTool を利用してmac の USキーボードで英数／かな キーを利用する

# USキーボードで英数／かな キーを利用する
## Mac USキーボードでの入力切り替え
Mac の USキーボードの入力切り替えは

+ ctrl+space
+ 英かなアプリ
+ BetterTouchTool に入力文字種のショートカットキー割り当て

といった方法がよく利用されます。
ctrl+spaceは、新しいアプリの導入が必要ないので、一番シンプルです。
英かなアプリも、導入が簡単なのでおすすめです。
ただ、BetterTouchToolをすでに利用している場合、余分なアプリを利用したくないと考えると、BetterTouchToolだけで完結したいです。

BetterTouchToolを利用する方法としては、左右のcommandキーに、それぞれの文字種へのショートカットキー割り当てる方法がよく紹介されています。
ですが、ショートカットキー割り当てる方法は、苦肉の策だと感じます。
アプリによっては機能しないこともあるので、本当は日本語キーボードにある英数／かなキーを割り当てたいはずです。ですが、USキーボードには、英数／かなキーがないので、BetterTouchToolへキーを割り当てることができないように見えます。

この記事では、USキーボードでも、英数／かなキーを入力して、BetterTouchToolのキーシーケンスに割り当てる方法を紹介します。

## USキーボードでの英数／かなキー入力
物理キーボード上には、英数／かなキーはいくら探しても出てきません。
USキーボードで英数／かなキーを入力する方法を端的に言うと、

アクセシビリティキーボードで、JISキーボードを作成して入力する

ということです。
詳しい手順は以降で説明します。

### アクセシビリティキーボード
Mac では、画面上にソフトウェアキーボードを表示することができます。
物理的に英数／かなキーがないのであれば、ソフトウェア上では入力できないでしょうか。

![keyboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950964/61b619a4-ff80-7ccd-004b-60be2b11747b.png)

### アクセシビリティキーボードの表示
まず、アクセシビリティキーボードを利用するには、
システム環境設定 > アクセシビリティ > キーボード > ビューア の アクセシビリティキーボードを有効にするのチェックを有効にしてください。
有効にするとソフトウェアキーボードが表示されます。

![access.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950964/e7a0f239-6a75-a46f-06af-7b37546f2232.png)
![enable_keyboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950964/c77552fc-7de3-f3ed-c3db-699d22900e94.png)



### JISキーボードの追加
USキーボードを利用している方は、はじめはUSキーボードが画面に表示されていると思います。
このソフトウェアキーボードに、日本語配列（JIS）キーボードを追加しましょう。

追加方法は、まずソフトウェアキーボードの右上の...を押して、カスタマイズを選択してください。
そうすると、パネル（ソフトウェアキーボード）のカスタマイズ画面が表示されます。
左の方の新規パネルを押すと、自分でカスタマイズするための新しい環境が用意されます。
上のアイコンにある「パネルの追加」 から「キーボード - JIS」を選択することで日本語キーボードを追加することができます。
このソフトウェアキーボードを利用すれば、クリックするだけで英数／かなキーを入力することできます。

![custom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950964/e1e80d43-5b15-cbbb-06bc-40fcf3ad274e.png)
![add_jis.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950964/a7d4bca5-7c24-0bb9-1a6c-20a3269efff8.png)

これで、英数／かなの表示を押すと、英数／かなキーの入力が可能となりました。

# BetterTouchToolへ英数／かなキーを割り当て
BetterTouchToolへ英数／かなキーを割り当てるには、
キーシーケンスを利用します。

キーシーケンスとして、左コマンドへはソフトウェアキーボードの英数をクリックして割り当てて、右コマンドへはかなキーを割り当てるだけです。


左のコマンドに英数キーを割り当てる場合、まず、キーシーケンスに左コマンドを設定します。

![left_commnad.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950964/bbfd5bb6-87a9-28a7-564e-11f4d4e5fdb9.png)

次に、キーシーケンスへのアクションの割り当てとして、英数キーを入力します。
![スクリーンショット 2022-04-27 0.01.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950964/b88dcba5-e94f-e748-4f10-780865ad3cb1.png)

![shortcut.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950964/4757e22d-0410-513d-2cfb-a4198bbe1fcb.png)

ここでキーの入力として、ソフトウェアキーボード上の英数キーをクリックします。


一つ注意点として、
英数／かなキーはなぜか割り当てられたキーとして何も表示されません。スペースのような扱いということでしょうか。
私は、割り当てがわかりやすいように、ノートにそれぞれeisuuとkanaを入力しています。

![btt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950964/73617b7d-5941-25ef-d1ce-090b34d5b4f8.png)

# まとめ
USキーボードには、英数／かなキーが物理的にないので、割り当てることができないと思っていました。
ネット上を探しても、文字種切り替えのショートカットを割り当てる方法が紹介されていることが多かったです。
知っている人は知っていると思いますが、どなたかの目に触れて、より便利にUSキーボードを利用できるようになればと思います。
USキーボードを利用する人がもっと増えますように。
「マイクロサービスパターン」の復習 8章 APIゲートウェイ

## 8章 外部APIパターン

- 外部APIを公開する際の問題点
- APIゲートウェイパターン
- BFFパターン
- GraphQL

などが紹介されています。

## 外部APIを公開する際の問題点

仮に個々のサービスのAPIを外部APIとして公開してしまった場合の問題点

- マイクロサービスアーキテクチャだとサービスの粒度が細かいので、結果的にAPIの粒度も外部APIとしては細かくなりすぎる。
    - Order情報を取得するのにも、数回のAPIを呼ばないといけない
- サービスの粒度や、内部APIを変えられなくなる
- 内部APIはそもそもhttpを喋れないかもしれない
- クライアントの種類によっては、APIの要件が変わってくる
    - それを各マイクロサービスが吸収するのか？

というわけで、内部APIをそのまま公開しても良いことはあまりないので、フロントにAPIゲートウェイを立てます

## APIゲートウェイパターン

マイクロサービスベースのアプリケーションへのエントリポイントとなるサービス

以下のようなことを行う

- リクエストのルーティング
    - httpを転送すればいいだけの場合
- API合成
    - 粒度の細かいバックエンドAPIの結果を集約して、クライアントに使いやすい形にして返す
- プロトコル変換
    - バックエンドがメッセージングなどhttp以外のAPIを持つ場合は、外部に対してhttpベースのAPIを公開する
- エッジ機能
    - 認証、認可、流量制御、キャッシング、メトリクス収集、リクエストロギング
    - 11章では上記のうち、認可に関してはパスベースの簡単なものならいいが、それ以上のものはサービスの詳細に深く関わるので、各サービスで実装して方がいいとしている

一応、欠点としては、メンテナンスが必要なサーバーが増えるというのがあるけど、欠点を補ってあまりあると言って良いでしょう

## BFFパターン

- BFF(Backend for Frontend）パターン
- 一口に外部APIといっても、クライアントの種類（Webであったり、モバイルであったり）によって、API要件が違う場合がある
- 要件が大きく違うのであれば、いっそクライアントの種類ごとにAPIゲートウェイを別立てにして、クライアント開発チームが、自身向けのAPIゲートウェイの開発と運用をするというのがBFFパターン
- アプリロジックの役割分担という観点から言えば合理的
- 一方で、要求されるテクノロジーやスキルが大きく違うので実際はそれほどうまくはいかないと思う
    - 特に運用の部分は11章で説明されている横断的関心事を一通りこなさないと行けないので、クライアントチームがサーバーの運用に深く関わるのはあまりよろしくないと思う

## APIゲートウェイの要件

- リクエストルーティング
- API合成
- エッジ機能
- プロトコル変換

ルーティングに関しては、パスベースだけでなく、メソッドベースもできないと7章のCQRSパターンを実現できない（GETとそれ以外で、転送先を変える必要がある）

## 既製のAPIゲートウェイ

- 以下が挙げられている
    - AWS API Gateway
    - AWS ロードバランサ
    - kong
    - Traefik
- どれも先に上げた要件をすべて満たすわけではない
- 特にAPI合成は、個別に実装が必要なので、できあいのもので実現するのは難しい

## APIゲートウェイを作る

- 作者のおすすめフレームワークはSpring Cloud Gateway
- メソッドベースのルーティングも含めて、先に上げた要件は一通り満たせるらしい
- ただしhttpリクエストを、kafkaベースのメッセージングにプロトコル変換しながらルーティングできるのかは本文からは分からなかった
- 実装も典型的なSpring風のものなので、経験者にはとっつきやすそう

## GraphQL を使った API ゲートウェイの実装

- API GatewayをGraph QLで実現する話
- クライアント側でqueryの内容を変えられるので、graph qlのエンドポイントを一つ作るだけで様々な用途に対応できる
- rest apiだと、多少はパラメータ化できるものの、普通はいくつものapiをつくることになる
- GraphQL スキーマ

```
type Query {
  orders(consumerId : Int): [Order]
  order(orderId : Int): Order
  consumer(consumerId : Int): Consumer
}


type Order {
  orderId: ID,
  consumerId : Int,
  consumer: Consumer
  restaurant: Restaurant
  deliveryInfo : DeliveryInfo
  ...
}
```

- エンドポイントのところでtype Queryで定義されたクエリーを投げられる
- エンドポイントがリクエストを受けたあとは、バックエンドのマイクロサービス群に、必要なクエリーを発行して、情報をあつめてレスポンスを返す
- この例では、Order、Consumer、Restaurant、DeliveryInfoはそれぞれ別のマイクロサービスが担当している
- node.jsのApollo GraphQLというExpress上で動かせるフレームワークでの実装例が書いてある
約数の総和の逆関数を作った

何言ってるのかよくわからないので例を挙げます。

たとえば、自然数 $60$ の約数を列挙すると、 $1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60$ です。この総和は $168$ ですね。
この関係を表す関数に約数関数 https://ja.wikipedia.org/wiki/%E7%B4%84%E6%95%B0%E9%96%A2%E6%95%B0 というものがあって、 $σ_1(60)=168$ と書いたり、あるいは単に $σ(60)=168$ と書いたりします。
この逆関数 $σ^{-1}$　は複数の値をとります。 $σ^{-1}(168)=60, 78, 92, 123, 143, 167$ など。

この値を全て列挙してみようという試みです。

```python: python
from sympy import sieve
import copy


def sum_primes(n: int, primes: list):
    mydict = {}
    for p in primes:
        p_now = 1
        p_sum = 1
        mylist = []
        while True:
            p_now *= p
            p_sum += p_now
            if p_sum > n:
                break
            mylist.append(p_sum)
        mydict[p] = mylist
    return mydict


def sum_divisor_inverse(n: int):
    primes = list(sieve.primerange(n))
    spdict = sum_primes(n, primes)
    ans, _ = sdi(n, spdict)
    for s in ans:
        t = ""
        p = 1
        for ss in s:
            t = " * " + t
            if t == " * ":
                t = ""
            t = str(ss[0])+"^"+str(ss[1]) + t
            p *= ss[0]**ss[1]
        print(t, "=", p)
    return ans


def sdi(n: int, spdict: dict):
    if n == 1:
        return [[]], True
    f = False
    mylist = []
    divs = divisors(n)
    spdict_loop = copy.deepcopy(spdict)
    for k, v in spdict_loop.items():
        for i in range(len(v)):
            if v[i] in divs:
                spdict_cp = copy.deepcopy(spdict)
                del spdict_cp[k]
                s, flag = sdi(n // v[i], spdict_cp)
                if flag:
                    f = True
                    for ss in s:
                        ss.append([k, i+1, v[i]])
                        mylist.append(ss)
        del spdict[k]
    return mylist, f


def divisors(n: int):
    # https://qiita.com/LorseKudos/items/9eb560494862c8b4eb56 を参考にした。O(√N)
    lower_divisors, upper_divisors = [], []
    i = 1
    while i * i <= n:
        if n % i == 0:
            lower_divisors.append(i)
            if i != n // i:
                upper_divisors.append(n // i)
        i += 1
    return lower_divisors + upper_divisors[::-1]

```

$n=100000$ でも数秒かかるので、あんまり $n$ が大きいと使い物にならなそう。

```sum_divisor_inverse(1680)```を実行すると、以下のように print されます。たとえば、 $540 = 2^2・3^3・5^1$ の正の約数の和は $1680$ です。

```terminal:output
2^1 * 3^1 * 139^1 = 834
2^1 * 3^3 * 13^1 = 702
2^2 * 3^1 * 59^1 = 708
2^2 * 3^3 * 5^1 = 540
2^2 * 7^1 * 29^1 = 812
2^2 * 11^1 * 19^1 = 836
2^2 * 239^1 = 956
2^3 * 7^1 * 13^1 = 728
3^1 * 13^1 * 29^1 = 1131
3^1 * 419^1 = 1257
3^3 * 41^1 = 1107
5^1 * 13^1 * 19^1 = 1235
11^1 * 139^1 = 1529
19^1 * 83^1 = 1577
```
TypeScript + Node.jsの簡易プロジェクトセットアップ

## はじめに
スクリプトを作成しようとする際、毎回手順が曖昧になってしまうためまとめておこうと思います。
TypeScriptとNode.jsを用いたプロジェクトの設定手順を記載します。

## 環境
Mac OSを用います。 Node.jsとnpmはインストール済みのものとします。

## 手順
### 1. 作業ディレクトリの作成
```bash:./
$ mkdir typescript-node-setup
$ cd typescript-node-setup
```
### 2. npm初期化
```bash:./typescript-node-setup
$ npm init
```
### 3. TypeScript インストール
```bash:./typescript-node-setup
$ npm i --save typescript
```
### 4. Node.js型定義の追加
```bash:./typescript-node-setup
$ npm i -D @types/node
```
### 5. tsconfig.json設定
```bash:./typescript-node-setup
$ tsc  --init
```
'tsconfig.json' の中身は下記を設定する。詳細は割愛。
```bash:./typescript-node-setup/tsconfig.json
...
"sourceMap": true, 
"outDir": "./dist",
...
  },
  "include": ["src/**/*" ]
}
```
### 6. ts-nodeパッケージをインストール
```bash:./typescript-node-setup
$ npm i -D ts-node
```
package.jsonにscriptsを追加しておく
```json:./typescript-node-setup/package.json
...
"scripts": {
   "dev": "ts-node src/index.ts",
...
```
### 7. (任意) ts-node-devパッケージをインストール
```bash:./typescript-node-setup
$ npm i -D ts-node-dev
```
package.jsonへの追加。
watchモードの意味で"dev-w"としてみる。
```json:./typescript-node-setup/package.json
...
"scripts": {
   "dev": "ts-node src/index.ts",
   "dev-w": "ts-node-dev --respawn src/index.ts",   
...
```

## 試してみる
```bash:./typescript-node-setup
$ mkdir src
$ touch src/index.ts
```
```ts:./typescript-node-setup/src/index.ts
console.log('Hello, World!');
```
```bash:./typescript-node-setup
$ npm run dev-w
```
こんな感じで環境設定する。スクリプト作成する際に。
【Pega】標準のエラー表示に沿って、カスタマイズしたエラーメッセージを表示する

## １．はじめに
本記事では、Pegaの標準のエラー表示に沿って、カスタマイズしたエラーメッセージを表示する実装を紹介します。

## ２．事象説明
カスタマイズしたエラーメッセージ（図１）は図２のように表示します。

・図１
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258181/ed7ebd6b-c507-3ff2-ecd3-d369484d8fc9.png)
・図２
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258181/e581c5ca-0a87-f4f5-09c0-286f137c7f87.png)

## ３．修正前の実装説明
Dynamic layoutの設定は下図のように実装しました。
・Container format は Other ⇒ Errors
<img width=70% alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258181/add8933b-4727-ae27-61da-5e323eb8fd6e.png">
<img width=50% alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258181/a2c29819-22f7-cac0-124c-138a8efa53c5.png">

## ４．修正後の実装説明
Container format は デフォルト設定で、
Display advanced presentaion options をチェックし、Content CSS class は banner banner-urgentで設定します。
<img width=50% alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258181/a8eeca1b-5cf4-f539-e5f6-0ead4ff0be83.png">
<img width=50% alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258181/f1b98657-0acf-c13d-a7af-6d23a2e28540.png">

#### ・Pega環境
　Pega 8.6.1

#### ・キーワード
　Display custom error message in Pega

#### ・参考資料
　[Pega COSMOS Banner](https://design.pega.com/develop/banner/)
【Linuxコマンド】特定のファイルを絞り込んでそれ以外を削除する

### ディレクトリ内のファイルを絞り込んでそれ以外を削除したい


```:例
linux % ls -la
total 0
drwxr-xr-x   9 user  group   288  4 26 22:51 .
drwxr-xr-x+ 63 user  group  2016  4 26 23:05 ..
drwxr-xr-x   2 user  group    64  4 26 22:44 dir1
drwxr-xr-x   2 user  group    64  4 26 22:44 dir2
drwxr-xr-x   2 user  group    64  4 26 22:44 dir3
-rw-r--r--   1 user  group     0  4 26 22:44 file1.txt
-rw-r--r--   1 user  group     0  4 26 22:44 file2.txt
-rw-r--r--   1 user  group     0  4 26 22:44 file3.txt
-rw-r--r--   1 user  group     0  4 26 22:45 file4.txt
```

## 手順
grepで''内のファイルを絞り込み
echoで絞り込まれている内容を確認

```ls | grep -i -v -E '残したいディレクトリ名|ファイル名' | xargs -n 1 echo```
```-n 1```とすることで標準入力から受け取るパラメータを1つずつに


```:例
linux % ls | grep -i -v -E 'dir1|dir2|file2.txt' | xargs -n 1 echo
dir1
dir2
file2.txt
```
絞り込んだ以外のファイル以外をechoから```rm -fr```に書き換えて削除  
```ls | grep -i -v -E 'dir1|dir2|file2.txt' | xargs rm -rf```
```
linux % ls -la
total 0
drwxr-xr-x   5 user  group   160  4 26 23:21 .
drwxr-xr-x+ 63 user  group  2016  4 26 23:21 ..
drwxr-xr-x   2 user  group    64  4 26 22:44 dir1
drwxr-xr-x   2 user  group    64  4 26 22:44 dir2
-rw-r--r--   1 user  group     0  4 26 22:44 file2.txt
```

[参考](https://genzouw.com/entry/2019/06/28/140010/1634/)

メモ書き
シェルコマンドライン　初心者

## シェルコマンド
 今日はシェルコマンドについてメモ程度にまとめておこうかなと思います。(Macで実行しています。)
- **`printenv`** ：環境変数の一覧が表示される。
（環境変数とは、OSが設定値などを永続的に保存し、利用者や実行されるプログラムから設定・参照できるようにしたもの）
- **`cat /etc/shells`**：インストールされているシェルの確認ができる。/etc/shellsに格納されています。
- **`cd`**：ディレクトリ移動（change directoryの略）
- **`type　コマンド`**：そのコマンドがどこのコマンドかわかる(**`which`** コマンドと似てる)
- **`man コマンド名`**：コマンドのマニュアルを開くことができる（コマンドを右クリックして開くこことも可能）


### おまけ
- コマンドラインにて行頭に移動したい場合：`cotrol + A`,行末：`cotrol + E`
- コマンド履歴：`↑`または`control+P`で履歴を遡れる。
- 補完機能：`tabキー`または`control+I`で補完される。
- ファイルをまとめて指定：`ファイル名+＊/?`*,?などのワイルドカードが使える。
- `clear`:画面がクリアされ、プロンプトが一番上に来る（`control+K`）



初歩的な部分ばかりでした。

今日もお疲れ様でした。

＊あくまで個人用のメモ程度です＊
私だけがずっと困っていたphpbrew+mysqlのコンパイル

Phpbrewでphpのバージョン管理をしているのですが、もろもろコンパイルに苦労したときの話。

## 私のmacの環境
* homebrewにてmysql5.7と8.0がインストールされており稼働中。
* PHP7.4とPHP8.0が必要

## phpとmysqlの対応表
|PHP | mysql |
|:-----------|------------:|
| 7.4     | 5.7      |
| 8.0       | 8.0        |

### phpbrewでphpのインストール

8.0に関してはあんまり苦労しなかった。
```
phpbrew install 8.1.0 
+mysql="$(brew --prefix mysql)" 
+pdo= +gd="$(brew --prefix gd)" 
+bz2="$(brew --prefix bzip2)" +apxs2= +json= +phar= 
+xml= +curl="$(brew --prefix curl)" +zip= 
-- --with-mysqli=/usr/local/opt/mysql/bin/mysql_config 
--with-openssl-dir=/usr/local/Cellar/openssl@1.1  
--with-zlib-dir=/usr/local/opt/zlib
```
これでなんとなく入った

7.4.2をインストールしようとして、mysqlのインストールディレクトリの指定などを変更して
sockをmysql5.7が動いているものを指定。あとは8.0とほぼおんなじ。
```
phpbrew install 7.4.2 
+mysql="$(brew --prefix mysql@5.7)" +pdo= 
+gd="$(brew --prefix gd)" 
+bz2="$(brew --prefix bzip2)" +apxs2= +json= +phar= +xml= 
+curl="$(brew --prefix curl)" +zip= 
-- --with-mysqli=/usr/local/opt/mysql@5.7/bin/mysql_config 
--with-openssl-dir=/usr/local/Cellar/openssl@1.1  
--with-mysql-sock=/tmp/mysql2.sock 
--with-zlib-dir=/usr/local/opt/zlib
```
**エラー発生**
なんでよ。

発生したエラーはmysqlのライブラリーがちがいますよとのこと。

```
configure: error: wrong mysql library version or lib not found. Check config.log for more information.
```

いろいろ調べた結果
```
phpbrew install 7.4.2 
+mysql="$(brew --prefix mysql@5.7)" +pdo= 
+gd="$(brew --prefix gd)" 
+bz2="$(brew --prefix bzip2)" 
+apxs2= +json= +phar= +xml= +curl="$(brew --prefix curl)" 
+zip= -- --with-mysqli=mysqlnd 
--with-openssl-dir=/usr/local/Cellar/openssl@1.1  
--with-mysql-sock=/tmp/mysql2.sock --with-zlib-dir=/usr/local/opt/zlib
```


--with-mysqliにmysql_configを指定していたのをmysqlndに変更したら入りました。
理由はよくわかりません。8.0のときはmysql_configを設定していても問題なかったのに
5.7を指定してphpをコンパイルしようとするとエラーが出る謎。

[参考:どのライブラリを選ぶか](https://man.plustar.jp/php/mysqlinfo.library.choosing.html)

誰かの参考になれば
Web 技術について

### 基本
* URI : URI(Uniform Resource Identifier)：
Webページを指定する方式。Webページのアドレスである「URL」もURIの一種。
- スキーム：「https」通信手順を指定
- ドメイン名：「www.example.com」ネット上のサーバを指定
- ポート番号：「:80」Webサーバのリソースにアクセスする技術的な出入口
- パス：「/path/to/myfile.html」Webサーバ内のリソースの位置を階層的に記述
- クエリ：「key1=value1&key2=value2」Webサーバに提供する追加パラメータ
- フラグメント：「#SomewhereInTheDocument」リソース自体の特定の場所へのアンカー(ページの特定の場所を開ける）
ニフクラを使ってみた。

### はじめに
AWSやOracle CloudやMicrosoft Azureは使ったことがあるが、富士通のニフクラはどうなんだろうと使ってみた。一番良く使うであろう仮想サーバの構築手順を確認する。

### ログイン
ニフクラを契約すると管理用のコントロールパネルのURL,ユーザID,パスワードが届く。
![ログイン.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466195/2a29365b-773d-3f04-9936-baa643cedeab.jpeg)

### メニュー表示
ログインすると、全体のメニューが表示される。
他のクラウドに比べるとサービスメニューは少ないが、他のクラウドを使ったことがあれば、マニュアルを見なくても直感的に操作できる感じ。
![メニュー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466195/764988a0-0485-9155-aae3-cd1caaf1e06a.jpeg)

### 仮想サーバの構築
メニューから「コンピューティング」を選択する。
まずはOSを選択する。Windows, Linuxから選択できる。画面では３種類しか表示されていないがスクロールするとメジャーな数十種類から選択できる。
![OSイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466195/d424ce83-74b3-6767-df78-a30728360fe5.jpeg)

### サーバタイプの選択
ゾーン：「リージョン＋データセンター」的な意味。
　　　　データセンター障害に備えて冗長化するなら、ソーンを別々にする。
　　　　国内リージョンは大きく分けて（west:西日本、east:東日本の２つ）
サーバのスペックを選択する。時間単価・月額費用が書かれている。金額がわかりやすいのでちょっと安心。
![サーバタイプ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466195/c1f41b64-9366-71bc-b534-dc8e8b3e9daa.jpeg)

### サーバ設定
料金プランは、「月額」か「従量（時間）」の選択
SSHキーは、サーバ側でキーが発行されて秘密鍵がダウンロードされるタイプ。
複数のサーバを立ち上げることを考慮すると、クライアントで持っている公開鍵をアップロードするタイプにして欲しかった。
ネットワークは、こだわりがなければグローバルIPもプライベートIPも「自動割当」で。
プライベートネットワークは、デフォルトの「共通ネットワーク」になっているが、他のクラウド同様、仮想ネットワークを作成しそれを割り当てることも可能。
「確認」ボタンを押して、次の画面へ
![サーバ設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466195/13c55df2-d03e-c154-47e1-34e4372cadde.jpeg)

### 確認
ここまでで設定した内容の確認画面が表示される。
設定内容に問題がなければ「作成する」ボタンを押す。
![4_確認.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466195/6e11f055-4ab8-37bf-1eee-854563418a9e.jpeg)

### コンソール画面
コンソール画面に戻ると、サーバのステータスが確認できる。
Linuxの場合、グローバルIPが表示されていれば証明書を使ってSSHでアクセスできる。
![5_コンソール.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466195/5a5dc149-4562-e1ed-9187-b5d620f3405a.jpeg)

### 感想
サービスや設定項目が他のクラウドに比べて少ないので、クラウド初心者でも抵抗が少ないと思う。ほぼすべての項目が日本語で書かれており、操作の順序も日本人向きな表現なので操作していて不安になる点が少なく感じます。

以上
# ssh 公開鍵　秘密鍵とは

# sshとは
- コマンドラインを使ってサーバーを遠隔で操作するための仕組み
- 公開鍵、秘密鍵を利用して、ローカルpc(自分のpc)とサーバーの接続を行う

## 公開鍵とは
- ssh接続する際に、接続したいサーバーに渡しておく鍵
- 鍵っていってるけど、ドアノブみたいなもの
- 誰でも公開鍵の内容をみることができる

## 秘密鍵とは
- 秘密鍵を使用して、公開鍵(ドアノブ)をあける
- 他の人から見れない。というかセキュリティ的に見られてはいけない。
[python] Key-Value 形式の dict を階層構造の dict に

# やりたいこと

記事タイトルはちょっとわかりづらいというか不正確な気がしますが、やりたいことはコレ。

```python
# ↓これを
src = {
    "aaa": "A",
    "bbb.ccc": "BC",
    "bbb.ddd": "BD",
}

# ↓こうしたい
{
  "aaa": "A",
  "bbb": {
    "ccc": "BC",
    "ddd": "BD"
  }
}
```

# コードスニペット

とりあえず下記の function で実現できた。
もっとキレイに書けそうな気がするし、探せばライブラリもありそうだけど。

```python
def kv_to_stare(kv, path_delimiter=".", base_path=""):
    result = {}
    for k, v in kv.items():
        if len(base_path) > 0 and not k.startswith(f"{base_path}{path_delimiter}"):
            continue
        base_path_len = len(base_path)
        path = k[base_path_len:].strip(path_delimiter)
        paths = path.split(path_delimiter)
        current_path = paths[0]
        if len(paths) == 1:
            result[current_path] = v
        else:
            next_base_path = f"{base_path}.{current_path}".strip(path_delimiter)
            result[current_path] = kv_to_stare(kv, path_delimiter, next_base_path)
    return result
```

## 使用例

```python
import json

# Inputデータ
src = {
    "aaaa": "AAA",
    "bbbb": "BBB",
    "cccc.dddd": "CCCDDD",
    "cccc.eeee": "CCCEEE",
    "ffff.gggg.gggg": "FGG",
    "ffff.gggg.hhhh": "FGH",
    "ffff.iii.aaa": "FIA",
    "cccc.kkkk": "CCCKKK",
}

# 実行＆表示
result = kv_to_stare(src)
print(json.dumps(result, indent=2))

### ▼結果 ###
{
  "aaaa": "AAA",
  "bbbb": "BBB",
  "cccc": {
    "dddd": "CCCDDD",
    "eeee": "CCCEEE",
    "kkkk": "CCCKKK"
  },
  "ffff": {
    "gggg": {
      "gggg": "FGG",
      "hhhh": "FGH"
    },
    "iii": {
      "aaa": "FIA"
    }
  }
}
```