OmniAICreator/Qiita-1.07M huggingface dataset:
Gitアカウントを2つ使用して運用するには

#はじめに
会社で使用している設定ファイルの中には個人的に使ってる設定ファイルも含まれているので、
そーいうのは個人的なアカウントのリポジトリで管理している。
このままだと会社のアカウントでPushされてしまうので、
このリポジトリのファイルは個人アカウントでコミットしたい。
みたいな設定の仕方の忘却録。

##まずは個人用アカウントへ繋ぐ為の公開鍵・秘密鍵を作成&設定
```
$cd ~/.ssh/{$個人アカウント用}
$ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/(username)/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
```
今使用しているのとは別にしたいので、適当に名前つける。
一回目のタイミングで名前を指定する。
あとはEnter2回叩く。

生成された公開鍵をGitHubに設定する。
この辺とか参考: https://qiita.com/0ta2/items/25c27d447378b13a1ac3

## sshのconfig設定について
```
vim ~/.ssh/config
```
configが無ければ作成する。

```
Host {$社内用}
  HostName github.com
  IdentityFile ~/.ssh/{$社内用}/id_rsa
  User git 
  Port 22
  TCPKeepAlive yes 
  IdentitiesOnly yes 

Host {$個人用}
  HostName github.com
  IdentityFile ~/.ssh/{$個人用}/{$新しく作ったKey名}
  User git 
  Port 22
  TCPKeepAlive yes 
  IdentitiesOnly yes
```

Hostに適当に名前をつけて接続テスト。

```
ssh -T {$社内用}
Hi {$社内用アカウント名} You've successfully authenticated, but GitHub does not provide shell access.

ssh -T {$個人用}
Hi {$個人用アカウント名} You've successfully authenticated, but GitHub does not provide shell access.
```

テスト成功であればこんな感じにsuccessfullyと出る。
もし、接続失敗することがあれば、~/.ssh/known_hostsの中身を消して試してみる。

## gitconfigについて
まず、gitconfig設定には、システム全体`system`、ユーザー全体`global`、個別リポジトリ用`local`の3種類がある。
読み込み順は、`system`→`global`→`local` の順に読まれるのでlocal設定があればlocalの設定が反映される。
各設定の確認は下記で行える。

```
git config --system --list　// gitをinstalしたディレクトリ
git config --global --list // ~/.gitconfig
git config --local --list  // 対象リポジトリ内の .git/config
```

社内用で使用しているのはglobal設定なのでこれはそのままにしておいて、
個人用リポジトリ内でのlocalの設定をしていく。

```
// 任意の場所で
git clone {$該当のリポジトリ}
cd {$該当のリポジトリ}/.git
vim config
```
cloneしてきた`.git`内にある`config`がlocal設定ファイルになる。

```
[user]
    name  = 該当のユーザID
    email = 該当のメールアドレス
```
このlocal設定に個人用を追加しておく。

```
git config --local user.name "該当のユーザID"
git config --local user.email "該当のメールアドレス"
```
これでも名前とメールアドレスを追加出来る。

あと、このリポジトリのremoteの設定をしておかないとpush出来ないので設定する。

```
git config remote.origin.url
git@github.com:[該当のユーザID]/[リポジトリ].git
```
これで確認してみると@マーク以下が`github.com`になってので、
これだと`ssh config`で設定している`HostName`が2つ存在するので接続Errorになる。
`ssh config`で設定した情報を元に@マーク以下を修正。

```
git remote set-url origin git@[個人用ホスト名]>:[ユーザID]/[リポジトリ].git
```
一旦、pushする前に`git log`などで確認しておくと良い。
社内用でpushする時は会社のアドレスで、個人のファイルを修正した時は`local`で設定したものが反映される。
C++で正規表現を使う

C++で正規表現を使う方法を解説する。`std::regex`を使えば良いのだが、ここではあまり凝った使い方は説明せず、とりあえず最小限の手間で使い始めるまでの方法をまとめる。

# 参考

- https://cpprefjp.github.io/reference/regex.html
- https://cpprefjp.github.io/reference/regex/regex_match.html
- https://cpprefjp.github.io/reference/regex/match_results.html


# 最小限のコード

まずは最小限動作するコードをいかに示す。

```cpp
#include <string>
#include <regex>


int main() {

  std::string s1 = "1234";
  std::string s2 = "abc";

  std::regex re(R"(\d+)");  // raw string literal

  assert( std::regex_match(s1, re) );
  assert (!std::regex_match(s2, re) );

  return 0;
}
```

## 解説

- 正規表現を使うためのヘッダをインクルードする

```cpp
#include <regex>
```

- 正規表現オブジェクトを構築する。

```cpp
std::regex re(R"(\d+)");
```

コンストラクタの引数に正規表現を文字列で渡せばよい。`R"( ... )"` という記法は見慣れないかもしれないが、これは[raw string literal](https://cpprefjp.github.io/lang/cpp11/raw_string_literals.html) という記法で`\`や`"`などの文字に対してエスケープする必要がなくなる。正規表現ではバックスラッシュを多用するのでこのリテラルが便利。

- 正規表現がマッチするかチェックする。

```cpp
std::regex_match(s1, re);
```

ちなみに`regex_match`は文字列全体が正規表現に一致するかを判定する。部分文字列に一致するか判定する場合は `regex_search` を代わりに使うと良い。
例は以下。

```cpp
std::string s2 = "abc 1234";
std::regex re(R"(\d+)");
std::regex_search(s2, re);    // => true
```

# マッチした結果を参照する

正規表現にマッチした文字列を取得したい場合には以下のようなコードを書く。

```cpp
    std::string s = "123-4567";
    std::smatch m;
    if ( std::regex_match(s, m, std::regex(R"((\d+)-(\d+))")) ) {
      std::cout << m[0].str() << std::endl;  // => 123-4567
      std::cout << m[1].str() << std::endl;  // => 123
      std::cout << m[2].str() << std::endl;  // => 4567
    }
```

- 正規表現によるマッチ結果を格納するコンテナ `std::smatch` 変数を用意する。

```cpp
std::smatch m;
```

ここで注意点として、判定する文字列が`std::string`の場合には`std::smatch`を使うが、もし`char*` だった場合 `std::cmatch` 型を利用しなければコンパイルエラーになる。つまり**判定したい文字列の型によってマッチ結果の型が異なる。**

ここで宣言した`m`という変数は実際には`std::regex_match` または `std::regex_search` が呼ばれるまでは、ほとんどのメソッドを利用することができない（空の結果が返ってくる）。参照して何か意味がある結果が得られるのは、これらのメソッドが呼ばれた後になる。

- マッチした文字列を取得する

```cpp
m[0].str()       // 123-4567
m[1].str()       // 123
m[2].str()       // 4567
```

コンテナの最初の要素には、マッチした文字列全体を表すサブマッチが格納され、以降に各キャプチャグループ（正規表現内の括弧で囲まれた部分に対応する）が続く。
ここで返る値は`sub_match`オブジェクトである。`.str()`を呼ぶと文字列が得られる。

(https://cpprefjp.github.io/reference/regex/match_results/op_at.html)

注意点として、マッチ結果オブジェクト`m`は検索対象文字列`s`へのイテレータを保持する。
このため、**検索対象文字列は`regex_match`または`regex_search`を呼び出した後も match_results オブジェクトを使用し終わるまで破棄されないようにする必要がある。**

例えば次のように`regex_search`の引数に一時オブジェクトを指定することはほぼ間違いなくプログラミング上のエラーを意味する。（このコードはC++14ではコンパイルエラー。C++11ではコンパイルできるが、結果は未定義）

```cpp
std::smatch m;
std::regex_match(std::string("123-4567"), m, std::regex(R"((\d+)-(\d+))"));
```
【Android】MediaPlayerでURLから再生するときの設定方法

#プログラミング勉強日記
2021年1月15日
[昨日の記事](https://qiita.com/mzmz__02/items/ac195d61e8614c684e67)でMediaPlayerで音楽を再生する方法について簡単に記述したが、URLから再生する場合には、マニフェストの宣言が必要なので、これも記事として残しておく。

#URLから音楽を再生する

```java:MainActivity.java
String url = "http://........";
MediaPlayer mp = new MediaPlayer();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setDataSource(url);
mp.prepare(); 
mp.start();
```

#マニフェストの宣言
　MediaPlayerを使用してネットワークの音楽を再生する場合には、ネットワークアクセスを許可する必要がある。

```xml:AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
```

 ただ、私の場合はこれだけではURLから再生することができなかった。これに加えて、アプリネットワーク設定を用意した。

#ネットワークセキュリティの構成
　ネットワークセキュリティ構成機能はxmlファイルを使用する。まず、アプリのマニュアルにこのxmlファイルを指すエントリを含める。

```xml:AndroidManifest.xml
    <manifest ... >
        <application android:networkSecurityConfig="@xml/network_security_config"
                        ... >
            ...
        </application>
    </manifest>
```

　次に構成ファイルを作成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/91786b9f-7369-9955-f848-9410f47a0ca7.png)

　
　Android 6.0（API レベル 23）以下を対象とするアプリのデフォルトの構成は以下のようになる。

```xml:network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
</network-security-config>
```

　ここまで設定して、やっとURLから音楽を再生することができた。(詳しくは[Android developersのネットワーク セキュリティ構成](https://developer.android.com/training/articles/security-config?hl=ja)に書かれている。)


#参考文献
[MediaPlayer の概要](https://developer.android.com/guide/topics/media/mediaplayer?hl=ja#java)
[ネットワーク セキュリティ構成](https://developer.android.com/training/articles/security-config?hl=ja)
MVCとMVP

## MVC

| 登場人物     | 役割                                                   |
| ---------- | ------------------------------------------------------ |
| Model      | データのCRUDをしたり、データの変更をViewに伝える |
| View       | Modelから伝えられたデータを可視化する                |
| Controller | Viewからのユーザー入力をModelに伝える                          |

## MVP

| 登場人物    | 役割                                                         |
| --------- | ------------------------------------------------------------ |
| Model     | データのCRUDをしたり、データの変更をPresenterに伝える  |
| View      | Presenterにユーザー操作を伝えたり、Presenterからの指示をもとに画面更新する|
| Presenter | ModelとViewの仲介をする。画面表示のロジックも担当する              |
[JavaScript] ヘッダ行のある２次元配列をMapの配列に変換

# 目的

GAS(Google Apps Script)でGoogleスプレッドシートのデータを`sheet.getDataRange().getValues()`で2次元配列として取り出し後、加工して`setValues()`で書き戻す、というのはよくあると思う。

2次元配列のままでは列の追加や削除、入れ替えなどの変更に対して弱いのでこれまではObjectに変換してから処理していたのだが、Objectではキー(プロパティ)の順序が保証されない(=スプレッドシートに書き戻したときに列の順序が変わってしまう可能性がある)、ということを知ったので、順序が保証されるMapに変換することに。

ということで、1行目がヘッダである2次元配列と、Mapの配列を相互に変換する関数を作成した(V8エンジン限定)。

# できたもの

~~~JavaScript
/**
 * 2次元配列(第1行はヘッダ)をMapの配列に変換
 * @param {Array<Array>} table 第1行をヘッダとする2次元配列
 * @return {Array<Map>} Mapの配列
 */
function tableToMaps(table){
  const headers = table[0];
  return table.slice(1).map((e) => e.reduce((i,n,a) => i.set(headers[a], n), new Map()));
}

/**
 * Mapの配列を2次元配列(第1行はヘッダ)に変換
 * @param {Array<Map>} maps Mapsの配列
 * @return {Array<Array>} 第1行をヘッダとする2次元配列
 */
function mapsToTable(maps){
  const headers = [...maps[0].keys()];
  return [headers, ...maps.map((e) => (headers.map((h) => e.get(h))))]
}
~~~

エラー処理等はしてないので適当に呼び出し側で😁


# 例

2次元配列 → Mapの配列

~~~JavaScript
const table = [
  ["col1", "col2", "col3", "col4"],
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  ["a", "b", "c", "d"]
];
const maps = tableToMaps(table);
~~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197772/c5447471-0b93-5456-d7f3-34c0d2480ae1.png)

Mapの配列 → 2次元配列

~~~JavaScript
mapsToTable(maps);
~~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197772/58645ffa-5dfe-a7af-87d7-4e543d8ddcab.png)

# 補足
##オブジェクトの配列との変換

ちなみにそれまで使っていたObjectの配列と2次元配列との相互変換は以下。

~~~javascript
/**
 * 2次元配列(第1行はヘッダ)をオブジェクトの配列に変換
 * @param {Array<Array>} table 第1行をヘッダとする2次元配列
 * @return {Array<Object>} オブジェクトの配列
 */
function tableToObjects(table){
  const headers = table[0];
  return table.slice(1).map((e) => e.reduce((i,n,a) => {i[headers[a]] = n; return i;}, {}));
}

/**
 * オブジェクトの配列を2次元配列(第1行はヘッダ)に変換
 * @param {Array<Object>} objects オブジェクトの配列
 * @return {Array<Array>} 第1行をヘッダとする2次元配列
 */
function objectsToTable(objects){
  const headers = Object.keys(objects[0]);
  return [headers, ...objects.map((e) => (headers.map((h) => e[h])))];
}
~~~

ちなみに`{i[headers[a]] = n; return i;}`を`({...i, [headers[a]]: n})`と書いたら速度が1/3程度まで落ちた。
納品物におけるフォーマットチェック（エクセル編）

#納品物を作成する上でこれだけは守って欲しいチェックリスト
<ol>
<li>変更履歴・更新者を書く
<li>エクセルは必ずA1セルに合わせて保存する
<li>罫線が切れている箇所がないかチェックする。
<li>印刷設定を統一する

##変更履歴を入れる
当たり前のことですが結構見落としがち。必ず以下のことは入れるようにしましょう。
履歴は納品のたびに項目を分けると見やすいです。

###変更するもの
・変更内容
・更新者

SVNで管理している場合でもエクセルは変更箇所を見える化できません。
変更内容や更新者を書いておくことはのちのプロジェクトの可視化に繋がります。

##エクセルは必ずA1セルに合わせて保存する
これもなかなかやる人は少ないですが
品質管理部等のある会社はチェックしていることが多いです。
場合によっては差し戻されることもあるのであらかじめ行って起きましょう
（心象もグッとよくなります。）

##罫線が切れている箇所がないかチェックする。
論外ですね。。。相手が見やすいように丁寧に書きましょう。
エクセルで切り取り＆ペースト等をすると罫線が消えることがあります。
コピペは注意して行いましょう。
私は”切り取り”ではなくコピー＆ペーストを使用して最後にコピー元をDeleteで消すようにしています。

##印刷設定を統一する
会社や内容によってまちまちだとは思いますが。
例えば以下のような設定にしておくと印刷時にも綺麗に印刷されます。

A4、横方向、全ての列を１ページに印刷、片面

また表示タブの中にある改ページプレビューを使用するのも見た目をよく見せる際に役に立ちます。
【PHP】 Laravel 8.X ソースページリスト

# ヘルパ関数
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/helpers.html)

# アクセス制限
- Gate
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/authorization.html?header=%25E3%2583%259D%25E3%2583%25AA%25E3%2582%25B7%25E3%2583%25BC%25E3%2581%25AE%25E7%2594%259F%25E6%2588%2590)

- Authorize
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/authorization.html?header=%25E3%2582%25B3%25E3%2583%25B3%25E3%2583%2588%25E3%2583%25AD%25E3%2583%25BC%25E3%2583%25A9%25E3%2583%2598%25E3%2583%25AB%25E3%2583%2591%25E3%2581%25AB%25E3%2582%2588%25E3%2582%258B%25E8%25AA%258D%25E5%258F%25AF)

- Middlewareの割り当て(authによる制限を前提とする)
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/middleware.html?header=%25E3%2583%259F%25E3%2583%2589%25E3%2583%25AB%25E3%2582%25A6%25E3%2582%25A7%25E3%2582%25A2%25E3%2582%2592%25E3%2583%25AB%25E3%2583%25BC%25E3%2583%2588%25E3%2581%25B8%25E7%2599%25BB%25E9%258C%25B2)


# 変数
- Bladeビューに渡す <br>
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/blade.html?header=%25E3%2583%2587%25E3%2583%25BC%25E3%2582%25BF%25E3%2581%25AE%25E8%25A1%25A8%25E7%25A4%25BA)

# auth関連
- ログインユーザー取得<br>
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/authentication.html)
    - コントローラー冒頭に`use Illuminate\Support\Facades\Auth;`を記述すること
        - 名前空間：ファイルの居場所を示す
        - use宣言：中で使うクラスを宣言する

# 条件分岐(if、elseif、else、endif)
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/blade.html?header=If%25E6%2596%2587)


# Migrateionカラム修飾子
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/migrations.html?header=%25E3%2582%25AB%25E3%2583%25A9%25E3%2583%25A0%25E4%25BF%25AE%25E9%25A3%25BE%25E5%25AD%2590)


# フォームメソッド・Store&Update処理・バリデーション・エラーメッセージ
- フォームメソッド <br>
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/routing.html?header=%25E7%2596%2591%25E4%25BC%25BC%25E3%2583%2595%25E3%2582%25A9%25E3%2583%25BC%25E3%2583%25A0%25E3%2583%25A1%25E3%2582%25BD%25E3%2583%2583%25E3%2583%2589)
- Store&Update処理 <br>
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/eloquent.html)
- バリデーション・エラーメッセージ <br>
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/validation.html?header=%25E3%2583%2590%25E3%2583%25AA%25E3%2583%2587%25E3%2583%25BC%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%25B3%25E3%2583%25AD%25E3%2582%25B8%25E3%2583%2583%25E3%2582%25AF)

# パラメーターを用いたルーティング
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/controllers.html?header=%25E5%259F%25BA%25E6%259C%25AC%25E3%2581%25AE%25E3%2582%25B3%25E3%2583%25B3%25E3%2583%2588%25E3%2583%25AD%25E3%2583%25BC%25E3%2583%25A9)


# リレーション
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/eloquent-relationships.html)


# デバッグ
- dump<br>
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/http-tests.html?header=%25E3%2583%25AC%25E3%2582%25B9%25E3%2583%259D%25E3%2583%25B3%25E3%2582%25B9%25E3%2581%25AE%25E3%2583%2587%25E3%2583%2590%25E3%2583%2583%25E3%2582%25B0)


# ページネーション
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/pagination.html
)

# 非同期通信におけるCSRF
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/csrf.html?header)

# N+1問題の解消
- with
[Laravel 8.x](https://readouble.com/laravel/8.x/ja/helpers.html#method-with)
Laravel8→6系に変えたら色々苦戦した

## はじめに

私は現在、PHP/Laravelでポートフォリオ作成をしている学習中の者です。
もし間違っている箇所があればお知らせいただけたら幸いです。

ポートフォリオを作成中に、Laravelのバージョン8系では記述の仕方が変わっていたり、(新しいため)情報も少なく、長い目でみて時間ロスが多く発生すると思い、6系に変えてみようと思いました。

開発初期段階だったので、軽い気持ちで変えてみたら色々エラーが出たので記事にしました。

- こちらの記事よりDockerの環境構築をさせていただきました。Laravelのバージョンを指定して環境構築するやり方も載っています。
[最強のLaravel開発環境をDockerを使って構築する【新編集版】 - Qiita](https://qiita.com/ucan-lab/items/5fc1281cd8076c8ac9f4)


- Laravel8に関してはこちらの記事が参考になりました。
[Laravel8がリリースされました！新機能の翻訳 \| WEBコンサルティング・WEB制作のフリーランス uiuifree](https://uiuifree.com/blog/develop/laravel8/)


- Laravelのバージョンについてはこちらの記事が参考になりました。
[Laravelのバージョンのおすすめは？2020年から学び始めるなら - ネビ活 \| ネットビジネス生活](https://nebikatsu.com/5470.html/)


<br>

## Laravel6系に変更後
バージョン変更に関しては割愛します。
プロジェクト内のデータが8系の時のままだと以下のようなエラーが出ます。

## シーディング実行エラー

```:ターミナル
$ php artisan migrate:fresh --seed
//注意してお使いください。
//このコマンドはデータベースの中身を全部クリアにしてからシーディングデータを入れ直すものです。
```

このコマンドでデータベースにデータを入れようとしたところ以下のエラーが発生

```:エラー内容
Illuminate\Contracts\Container\BindingResolutionException  : Target class [PostTableSeeder] does not exist.
```

#### 解決法


8系と6系とでは記述が変わっていた為、`seederファイル`を修正

```:database/seeds/PostTableSeeder.php
<?php

//namespace Database\Seeders;←削除

use Illuminate\Database\Seeder;
//use Illuminate\Support\Facades\DB;←削除

class PostsTableSeeder extends Seeder
{
//~~
```


## Modelファイルエラー

```
$ php artisan serve
```

でlocalhostに繋ぎ確認してみると以下のエラーに


```
Trait 'Illuminate\Database\Eloquent\Factories\HasFactory' not found
```

#### 解決法

Laravel8ではHttp/Modelディレクトリの配下に入ってましたが、Laravel6ではHttpディレクトリの配下に直接入れるのがデフォルトのようです。
Httpディレクトリ配下に移し空になったModelディレクトリを削除。
Modelファイルを一部書き換えます。

```:app/Http/Post.php
<?php

//namespace App\Models;
//↓以下に修正
namespace App;

use Illuminate\Database\Eloquent\Factories\HasFactory;//削除
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;//削除
```


## Controllerエラー

Controllerファイルも書き換えます。

```:app/Http/Controllers/PostController.php
<?php

namespace App\Http\Controllers;

//use App\Models\Post;
//↓以下に修正
use App\Post;

use Illuminate\Http\Request;

class PostController extends Controller
{
```

## Routingエラー
Routingファイルも書き換えます

```:routes/web.php
<?php
use Illuminate\Support\Facades\Route;

//use App\Http\Controllers\TestController; //削除
//Route::get('/',[PostController::class, 'index']);
//↓以下のように修正
Route::get('/', 'PostController@index');
```

<br>
ひとまずこれにて無事に6系での開発が進めらる状態になりました。
特に初学者の方はLaravelで何か作り始める前にバージョンはよく考えて決めましょう(笑)
コンテナ入門

- コンテナとは
    - アプリを入れる箱
- VMに対する優位性
  - アプリの起動時間が短い
    - VMにアプリを入れる場合、VM上のOSにアプリが乗るため、アプリ起動時にOSの起動が必要
    - コンテナにアプリを入れる場合、Docker Engineというコンテナ管理アプリにコンテナが乗るため、Docker Engineさえ起動すれば良い（アプリなのでOS起動より時間はかからない）。また、1つのDocker Engineに複数コンテナを乗せることができるため、コンテナを増やす度にDocker Engineを起動する必要もない。
- コンテナの設計原則
  - コンテナ：アプリ＝１：１にする
  - コンテナのビルド時に必要なものはLinux Kernelのみとし、実行に必要なその他ライブラリはビルド時に追加する
  - コンテナの修正はビルド後に行わない。修正する場合はビルド前のイメージを修正してビルド後、既存コンテナと入れ替える
  - コンテナ内のアプリを監視/管理するAPIを用意する
  - コンテナは短命なため、停止時対策（例：graceful shutdown）を取る
  - リソース要件を考慮する
Acsm拡張子のebookをkindleに落とし込む


[Proquest](https://www.proquest.com/) など、数多くのebookストアがあるが、
それらでダウンロードしたacsmファイルをmobi形式のkindleに落とし込みたい

### 手順1
Adobe Digital Editionsをインストールし、ダウンロードしたacsmファイルをDigital editionsで開き、PDFファイルにする

### 手順2
[Calibre](https://calibre-ebook.com/download) をダウンロードする。
手順1で取得したPDFを、Calibreを使ってmobi形式に変換する

1. Add book
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557811/832bbf96-c5e4-47f8-e04e-ae86d73f155d.png)

2. Convert book

![スクリーンショット 2021-01-15 16.41.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557811/8c56ddfa-cd47-21bf-a485-f387e335b05c.png)

### 手順3
kindleをUSBにつなげて、mobi形式のファイルをDocuments フォルダにドラッグ&ドロップ

このとき、KindleとPCとの間で、USBの許可についてポップアップがくるので、Documen allowをする。



### Memo
変換するときに、こんなエラーが吐かれたら、
`Error: Couldn't find the 'EBX_HANDLER' security handler`

Adobe Digital Editionsでの認証IDがない状態であることを確認
![スクリーンショット 2021-01-15 16.45.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557811/4516ea89-758c-1df0-2459-8f289d941c7e.png)
Kubernetes入門

# Kubernetesの概要
- Kubernetesとは、コンテナオーケストレーションツールである。複数のコンテナを良い感じに管理してくれる（例：一部コンテナに負荷集中時に自動でスケールする）
- マスターとノードという2種類のサーバーが存在
  - マスターはコンテナの管理をする。また、外部から管理可能にするためのAPIを提供する
    - APIの認証情報は`~/.kube/config`に記載する
  - ノードはコンテナのホストをする
- 配備するリソース（例：コンテナ）やその設定は、マニフェストと呼ばれる設定ファイルで定義する
- リソース郡はKubernetesクラスタという箱に入る。さらにNamespaceで箱に仕切りをつけることができる
- マスターが提供するAPIはkubectlコマンドで実行する。基本的なコマンドは以下

|コマンド|説明|
|:-------|:--------|
| apply | リソース作成|
| delete | リソース削除|
| get| リソース情報参照|
| logs| ログの参照|
| exec |配備済コンテナ内でのコマンド実行|
| port-forward |ローカルのポートからコンテナのポートへのポートフォワード|

# 各種リソースの説明
- Kubernetesのリソースにはとても多くの種類がある

## Workloadsリソース

- Pod
  - 1つ以上のコンテナを持つ箱
  - 1つのPodにつき1つのIPを持つ
- ReplicaSet
  - Podを複製し、特定のラベルを持つPodの数を、マニフェストで定義した数で維持する
    - 例：replicas: 3, labels: labelA, labelBと定義した場合、labelA, labelBのpodの合計数を3で維持する
    - Podの増減履歴は`kubectl describe rs`で確認可能
- Deployment
  - 複数のReplicaSetを管理する。ローリングアップデートやロールバックを行う。
- DaemonSet
    - ノードの常駐プロセス。各ノードに1つずつ配備される
        - 使用例：Datadogを常駐させることで各ノードを監視する
- StatefulSet
  - ステートフルなもの（例：DB）を管理する
  - 再作成について
    - PersistentVolumeを使用している場合は、同じディスクを用いて再作成される
    - 再作成してもPod名は変わらない
- Job
  - バッチ処理をする
- CronJob
  - バッチ処理を定期実行する


## Discovery&LBリソース

### Service

- Podのセットに対するエンドポイント
    - セット内の特定のpodに通信したい場合はlabelで指定
    - エンドポイントの種類は下記を参照
        - [【オンプレ/AWS/GCP】 ClusterIP / NodePort / External IP / Loadbalancer / Ingress / Router の違いとその動き](https://blog.framinal.life/entry/2021/03/17/185546#External-IP                                           )

## Configリソース

- ConfigMap
  - 環境変数を管理
- Secret
  - 機密情報を管理。base64エンコードされる
    - 安全性を確保するには別途対策が必要

## Storageリソース

- Volume
  - 既存のボリュームをコンテナから使用できるようにする
- PersistentVolume
  - 永続ボリュームを提供する外部システムと連携して、ボリュームの新規作成や削除ができる
- PersistentVolumeClaim
  - PodとPersistentVolumeを紐づける

# その他

## Podのヘルスチェック
- Podのヘルスチェックには2種類ある

| 種類            | 役割                                                         | 失敗時の挙動                                |
| --------------- | ------------------------------------------------------------ | ------------------------------------------- |
| Liveness Probe  | Podの死活監視                                                | Podの再起動                                 |
| Readiness Probe | Podがサービスを開始可能か確認（例：バックエンドのDBと接続済か） | Podへの通信拒否 |



## Podの再起動ポリシー

- Pod停止時の再起動ポリシーには3種類ある

| 種類      | 説明                      |
| --------- | ------------------------- |
| Always    | 常に再起動                |
| OnFailure | 終了コード0を除き再起動 |
| Never     | 再起動しない              |



## Kubernetesと連携可能な著名サービス

| サービス   | 機能             |
| ---------- | ---------------- |
| Fluentd    | ログ管理         |
| Prometheus | 監視             |
| Istio      | サービスメッシュ |
-bash: 警告: command substitution: ignored null byte in input

なンか鬱陶しいメッセージ出る。消えない😠

```console
$ MODEL=`cat /proc/device-tree/model`
-bash: 警告: command substitution: ignored null byte in input
```

警告はbashバージョン4.4で導入された新機能のようです😮


```console
$ MODEL=`cat /proc/device-tree/model | tr -d "\0"`
```
変数に入れる前にヌルバイトを削除することで解決😁
Dynamics 365 のカスタマイズ～ロゴ・カラーの設定

向井です。

今回ご紹介するのは**Dynamics 365 のカスタマイズで上にある帯の色やロゴを変更する方法**をご紹介します。

#設定方法
歯車マーク＞詳細設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/ae3300e2-1f11-1b80-8e50-ed6d2079d97a.png)

設定＞カスタマイズ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/4ce929cc-3b85-de2b-2ebb-df7e8ab7f4ac.png)

テーマ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/c425674a-a876-d94c-2eb1-dfabfe1ccaa0.png)

新規
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/f6aa9d30-94d2-32ae-4d8a-eeba1fc70b9a.png)

ここから設定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/8b128853-910b-343d-c861-0737e10e32e2.png)
MongoDB Atlasのユーザー管理


MongoDB Atlasのユーザー管理に対する現時点の理解をまとめました。

# TL;DR

MongoDB Atlasには、 `Database User` と `Atlas User` の2種類があります。

# MongoDB Atlasについて

MongoDB, Inc. が管理するパブリッククラウドのアカウントでマネージドなMongoDBクラスターを利用できるサービスです。

MongoDBクラスターの作成や設定変更（オートスケーリング・バックアップ有効化・ストレージサイズ変更など）、ネットワーク設定、アラート設定等に加えて、コンソール上から `Collection` の中身に対してCRUD操作が可能な `Data Explorer`と、コンソール上での `Database User` の管理をサポートしています。

# Database User と Atlas User

Database User と Atlas Userの違いを表にまとめました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96286/091d2bda-55d9-7524-3ada-7bfc72482bc9.png)

# 現在試しているユーザー設定

上記を踏まえ、私が現在試しているユーザー設定です。
ご意見ご感想お待ちしております。

## Database User

- アプリケーションごとにユーザーを作成しています（例: app, data-ware-house）
- オペレーションで人間がデータベースにアクセスする場合、MongoDBクライアントを利用しています。その際、都度期限つきのDatabase Userを発行します。
- 開発用プロジェクトでは誰でもユーザーを発行してよい設定です（後述）

## Atlas User

AWSのようにスイッチロールの概念がないため、個人ユーザーと管理用ユーザーで分けています。

- 個人ユーザー: `Organization ReadOnly` かつ 開発用プロジェクトの `ProjectOwner`
- 管理用ユーザー: `Organization Owner`（ログインごとに通知する)

※ `Organiztion Member` と　`Organization ReadOnly` の違いですが、前者の場合自分が所属していないプロジェクトの存在を認識できなくなります。

上記設定により、以下のそれぞれの操作に制約を設けることができました。

- 開発用プロジェクトのAtlasの操作: 個人ユーザーが可能
- 開発用プロジェクトのMongoDBの操作: 個人ユーザーが可能
- 本番プロジェクトのMongoDBの操作: 管理用ユーザーのみ可能
- 本番プロジェクトのMongoDBの操作: 管理用ユーザーのみ払い出した `Database User` が可能（有効期限をつける）
node.jsでTCP通信 (serverからの送信内容をclientでエコーバックする)

node.jsでTCP通信をする方法を調べていると

1. cilent側で文字を入力して
2. それをserver側で折り返して
3. それをclient側でコンソールに表示

というサンプルが山ほど見つかるのですが、

1. server側で文字を入力して
2. それをclient側で折り返して
3. それをserver側でコンソールに表示

という例が見つからなかったので、書いてみました。

server.js

```javascript
var net = require('net');

var server = net.createServer(conn => {
    console.log('connected.');
    
    conn.on('data', data => {
        console.log('server-> ' + data);
    });
    
    conn.on('close', () => {
        console.log('closed');
    });
    
    process.stdin.resume()
    process.stdin.on('data', data => {
        conn.write(data)
    });

}).listen(3000);

console.log('listening on port 3000');
```

client.js

```javascript
var net = require('net');

var client = new net.Socket();
client.setEncoding('utf8');

client.connect('3000', 'localhost', () => {
    console.log('connected');
});

client.on('data', data => {
    console.log('client-> ' + data);
    client.write(data);
});

client.on('close', () => {
    console.log('closed');
});
```

以上です

参考
https://nodejs.org/api/net.html#net_net_createserver_options_connectionlistener
OCI コマンドライン（OCI CLI）で、仮想マシン（OCI Compute）の起動・停止・シェイプ変更

# はじめに
Oracle Cloud Infrastructure のコマンドライン（OCI CL）で、仮想マシンインスタンス（OCI Compute）の起動・停止・シェイプ変更を試します。

実行にあたって今回は、簡単にOCI CLIを利用できるクラウドシェルを利用しています。

## クラウドシェルとは

> クラウド・シェルは、Oracle CloudコンソールからアクセスできるWebブラウザ・ベースのターミナルで、Oracle Cloud Infrastructureの全ユーザーが無償利用可能です。
>
> 事前承認されたCLIにてLinuxのシェルにアクセスできます。クラウド・シェルは永続フレームとしてコンソールに表示されます。

各OSにてOCI CLIの設定が必要な場合は、

- Windows OS： https://qiita.com/hitsumabushi845/items/795fb8ca9be3add7b50c

- Linux OS： https://qiita.com/sugimount/items/63a8cfe1163030ae8804

の記事が非常に参考になります。



## コマンド例

事前に該当するComputeインスタンスのOCIDを確認しておきます。



### 起動のコマンド例

```
oci compute instance action --action start --instance-id <インスタンスのOCID>
```

### 停止のコマンド例

```
oci compute instance action --action softstop --instance-id <インスタンスのOCID>
```

Stop（電源OFF）とSOFTSTOP（OSのShutdown）があります。

### シェイプ変更のコマンド例

起動済みのインスタンスのシェイプ変更の際には、再起動がかかります。

（例）VM.Standard.E2.1 （OCPUは1）に変更

```
oci compute instance update --instance-id <インスタンスのOCID>  --shape VM.Standard.E2.1
```

（例）VM.Standard.E3.Flex（OCPUは1）に変更
FlexインスタンスのCPU数は、”Shape-config”パラメータで指定します。

```
oci compute instance update --instance-id <インスタンスのOCID> --shape VM.Standard.E3.Flex --shape-config '{"ocpus":"1.0"}'
```

変更可能なシェイプは、こちらも参照ください。
   https://docs.oracle.com/ja-jp/iaas/Content/Compute/Tasks/resizinginstances.htm



# 参照情報

『OCI CLI を使い倒す』Oracle Cloud Infrastructure (OCI) の CLI (Command Line Interface) の解説資料
（2019年9月27日のOCIスキルアップセミナー） 
   https://speakerdeck.com/mmarukaw/oci-cli-woshi-idao-su

『OCI CLI Command Reference』-compute
   https://docs.cloud.oracle.com/iaas/tools/oci-cli/latest/oci_cli_docs/cmdref/compute.html
jQueryでselectやradioで選択した数のテキストボックスを動的に増減させる方法

セレクトボックスやラジオボタンに1～10の数字があって、選択するとテキスト入力欄を増減したい場合など（人数を選択すると、氏名を入力する欄が増減する）。

検索方法が悪いのか検索しても出てこなかったので残しておきます。

![jquery add remove textbox](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20132/93d467b6-c8c4-2288-0c5d-73115b9431fa.png)


## html
例ではradioですが、selectでも同じです。

```html
<form id="form">
  <input type="radio" name="choice_no" value="1">1
  <input type="radio" name="choice_no" value="2">2
  <input type="radio" name="choice_no" value="3">3

  <div id="input_text">
     <!-- ここにテキストボックスが足さられる -->
  </div>
</form>
```

## jQuery
### 当初は何も考えずにこうした
ただ、これだと入力してから数値を変えると、入力済みのテキストが消えてしまう。

```javascript
$('form#form input:radio[name="choice_no"]').change(function(){
    // 数を取得
    var choice_no = $('input:radio[name="choice_no"]:checked').val();

    // #input_textの中身を消して入れる
    var inner_html = "";
    for (var i = 0; i < choice_no; i++) {
        inner_html +=  '<div class="form-group"><input class="form-control" type="text" name="sample[]" required></div>';
    }
    $('#input_text').html(inner_html);
});
```

### こうすると最後に追加/最後を消す

```javascript
$('form#form input:radio[name="choice_no"]').change(function(){
    // 数を取得
    var choice_no = $('input:radio[name="choice_no"]:checked').val();

    // 現在追加済の要素を数える
    var len = $('#input_text div').length;
    // 差を数える
    var loop_count = (choice_no - len);

    // 差がプラスならフォームを足す、マイナスならフォームを削除
    if (loop_count > 0) {
        for (var i=0; i < loop_count; i++){
            // 最後に追加
            $('#input_text').append('<div class="form-group"><input class="form-control" type="text" name="sample[]" required></div>');
        }
    } else if(loop_count < 0) {
        loop_count *= -1;
        for (var i=0; i < loop_count; i++){
            // 最後の要素を削除
            $('#input_text div:last').remove();
        }
    }
});
```

でも、もっとシンプルに書ける気もする。
【AT Command】ターミナルは何使う?

# INTRODUCTION
Tera Termでもいいけど、ATCommandを送信しやすいターミナルエミュレータが用意されているかも。

## ターミナルエミュレータ
### u-blox

- [m-center](https://www.u-blox.com/en/product/m-center?lang=ja)

これが無料で一番おすすめ。
スタートアップのコマンドでエラーするところもあるが、他のメーカーのセルラー通信モジュールでも使える。

### SIMCOM

- [SSCOM](https://github.com/m2mlorawan/sscom5/blob/master/sscom5.zip)

中国語できるならいいかも。
文字化けしやすい。

### その他

- [AT Command Tester](https://m2msupport.net/m2msupport/download-at-command-tester/)

有料のテスター。
1週間の試用版が試せる。
私の環境ではフリーズしまくったので、正直微妙。
style.cssとfunctions.phpを設定してテーマとして認識させる

#style.cssとfunctions.phpを設定してテーマとして認識させる

※これをする前にいくつかしないといけない事はある。

index.phpと同階層にあるテーマ認識用のstyle.cssに以下を記述。

style.css

```
@charset "utf-8";
/---------------------------------
テーマとしてWPに認識させるための記述↓
---------------------------------/
/*
theme Name:hoge
Author: hoge
Description: 自作テーマ
version： 1.0.0
*/
```

functions.php

```
<?php
/**
 * テーマのセットアップ
 * 参考：https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/add_theme_support#HTML5
 **/
function my_setup()
{
  add_theme_support('post-thumbnails'); // アイキャッチ画像を有効化
  add_theme_support('automatic-feed-links'); // 投稿とコメントのRSSフィードのリンクを有効化
  add_theme_support('title-tag'); // タイトルタグ自動生成
  add_theme_support(
    'html5',
    array( //HTML5でマークアップ
      'search-form',
      'comment-form',
      'comment-list',
      'gallery',
      'caption',
    )
  );
}

add_action('after_setup_theme', 'my_setup');
// セットアップの書き方の型
// function custom_theme_setup() {
// add_theme_support( $feature, $arguments );
// }
// add_action( 'after_setup_theme', 'custom_theme_setup' );
```

上記のコードを記述し、
WordPressのadminの管理画面で、「外観 > テーマ」で認識されている。
lightlineでvim-lspのdiagnosticを表示させる

ちょっと前にこの記事を見つけて、タイトルの内容を実現していました。
https://kitagry.github.io/blog/programmings/2020/08/lightline-vim-lsp/

でもなんか気づいたら表示されなくなってて、なんでかなぁってヘルプを漁ってもそもそも lsp#ui#vim#get_buffer_diagnostics_counts() なんて関数が見当たらないんですよね。困った。

それでもにらめっこして、ようやくそれっぽい関数見つけて、なんやかんやちゃんと出たので困ってる人向けに役立てばいいなぁと思い下にコード載せときます。
なんか関数が lsp#get_buffer_diagnostics_counts() に変わってただけだった。いつの間にか。

```vim
let g:lightline = {
              \ 'active': {
              \   'right': [ ['lsp_errors', 'lsp_warnings'],
              \   },
              \ 'component_expand': {
              \   'lsp_errors': 'LightlineLSPErrors',
              \   'lsp_warnings': 'LightlineLSPWarnings',
              \   },
              \ 'component_type': {
              \   'lsp_errors': 'error',
              \   'lsp_warnings': 'warning',
              \   },
              \ }

  function! LightlineLSPWarnings() abort
      let l:counts = lsp#get_buffer_diagnostics_counts()
      return l:counts.warning == 0 ? '' : printf('W:%d', l:counts.warning)
  endfunction

  function! LightlineLSPErrors() abort
      let l:counts = lsp#get_buffer_diagnostics_counts()
      return l:counts.error == 0 ? '' : printf('E:%d', l:counts.error)
  endfunction

  augroup lightlineAutocmd
      autocmd!
      autocmd User lsp_diagnostics_updated call lightline#update()
  augroup END
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265914/a39dc177-7166-d1ea-e3ab-378778991645.png)

細かいことは参考元を見てください。
でもいつから変わったんだろう？それすら気づいてないからそもそもいらないんじゃねぇかと思い始めてきた。
他のコンピューターにリモート接続したい、そしてnautilusコマンド

コマンド

ssh ログイン先のユーザー名@ログイン先のIPアドレス

例 ユーザーrunのパソコンからユーザーpome,IP:12.23.23.23のパソコンにssh接続する
　　ssh pome@12.23.23.23

Xを飛ばして、ssh接続をする。そしてnautilusコマンドでフォルダを表示

例　ssh -Y -C pome@12.23.23.23
-Y:Xの転送指定
-C:通信内容の圧縮(応答性が良くなる)


nautilusコマンドとは？
　「Nautilus」（ノーチラス）は、GNOMEデスクトップ環境を構成するグラフィカルシェルです。端末から「nautilus」コマンドを実行すると、GNOMEの「ファイル」画面を開きます。


目次に戻る


nautilusコマンドの書式
nautilus [オプション] [場所（URI）]

※[ ]は省略可能な引数を示しています。


目次に戻る



nautilusの主なオプション
短いオプション	長いオプション	意味
-w	--new-window	指定した場所（URI）を、常に新しいウィンドウで開く
-n	--no-default-window	明示的に指定した場所のウィンドウだけを表示する
--no-desktop	デスクトップを管理しない（GSettingsの設定を無視する、※1）
--force-desktop	デスクトップを管理する（GSettingsの設定を無視する、※2）
-q	--quit	実行中のNautilusを強制終了する
-s	--select	指定した場所を選択する（ディレクトリを指定した場合は親フォルダを表示する）
※1 GSettingsはGNOMEデスクトップの設定情報。gsettingsコマンドとdconfコマンドで内容を確認、変更できる。
※2 Ubuntu 18.04 LTSでは--forcedesktopオプションを利用できない。
AWSのlamdaでfirebaseを使う時に沼った話

ハッカソンに出場するためのプロダクトを開発している時に、大沼にハマったので、記事にしてみようと思います。
半年ほど前の記憶を辿りながらですので、ところどころ抜けてるかもしれません。
また、awsのアカウント作成や、aws cliのインストールなど、細かい部分に関しては、記載しませんので、ご了承ください。

#環境
・MacOS Catalina


```
$ sw_vers
ProductName:	macOS
ProductVersion:	11.1
BuildVersion:	20C69
```

#やろうとしていたこと
iosのカメラで表情を認識した時に、写真を撮影し、AWSのS3にアップロード。アップロードが完了したことをトリガーに、lmada関数が走り出し、AWS Recognitionという表情認識APIにアップロードされた画像を渡す。そして、APIから帰ってきた表情の数値をfirebaseに保存する。保存された情報をブラウザが取得し、グラフとして表示するというプロダクトを作ろうとしていた。

※今回は、私自信がs3に画像がアップロードされてからfirebaseに保存するまでを担当したので、その部分のみの記述になります。

#手順
①AWS confing の設定
はじめてのAWSだったので、最初のこの部分の設定がなかなか鬼門でした。
ただ、一度理解すればここはなんなくいけます。

```
$ aws configure --profile user1
AWS Access Key ID [None]: {アクセスキー(各自)}
AWS Secret Access Key [None]: {シークレットアクセスキー(各自)}
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

-----------
②lamda関数の記述　※ソースコードは割愛させていただきます。
ここでまさかの大沼ポイントがありました。APIを叩いて、表情を数値化したデータは取れているのですが、firebase admin SDKがうまく反映されておらず、データを保存することができていませんでした。

数時間にも及ぶ死闘。（数時間で死闘とかゆうなってゆうのは、やめてください。こちらも理解した上で書いております。）その末に判明したのは、原因がlamda関数において、pythonランタイム（lamda関数をpythonで記述していたため）しか設定していなかった。しかし、firebase admin SDKは、一部C言語でのコードも存在するため、ランタイムエラーが起こり、うまく走っていなかったのです。

最終的には、lamda関数にカスタムランタイムでC言語を設定することで解決することができました。

----

ここまでくれば、あとはブラウザからfirestoreに保存されているデータを取得するだけなので、簡単です。

**と思いきや、**ここからもAPI関係で沼にハマったらしく（担当してくれていたチームメイトが）、相当きつかったです。

#感想
APIとか外部ライブラリとかは一見魔法のようなものですが、実際に使ってみると得体のしれないものなので、結構沼にはまる可能性があると思います。（現役のエンジニアの方などにとっては常識かもしれませんが、未経験の僕からしたら魔法のようなものでした）恩師の方がよく、「外部ライブラリとかを自分で作れるレベルにならないと使いこなせないよ」とおっしゃっていたのは、今思い出しても本当にその通りで、githubとかソースコード見て仕様を理解して、エラーの原因を考えられるようになる必要があるなと思いました。

また今回初めてAWSを触ってみて、自分的には「AWS触れます」とかゆってしまいそうな気持ちになったのですが、恩師の方に「君はおそらくまだAWSの1%も理解できていないよ」と。恐るべし、という感じですね。

結論、楽しかったからもっとAWSで遊んで見たいと思います。

ご覧いただきありがとうございました。
(自分用)Flask_メモ

#項目
1. `session`の内容削除
2. テンプレート内での変数フィルター(再定義)
3. `form`に入ってるのか入ってないのか
3. `url_for`を用いてリンク生成
3. リダイレクト処理
4. etc

#1.`session`の内容削除
- `session.pop("消すやつ",None)`で取り敢えず消せる
- 第２引数は既に中身がない場合に何か値を入れるかについて、取り敢えずは`None`で

```python:python
session["test"] = "入ってる"
print(session["test"])

session.pop("test",None)
if "test" not in session:
 print("入ってない")

#入ってる
#入ってない
```

#2.テンプレート内での変数フィルター(再定義)
- テンプレートに渡した変数はテンプレート内で再定義出来る
- 例は以下

```python:テンプレート
#これを使う
{% 変数 | フィルター %}

#ex
#hello_woに<h1>Hello World</h1>が入っている
#普通に書いた場合
{{hello_wo}}
#フィルターを通した場合
{{hello_wo | safe}}

#<h1>Hello World</h1>
#(h1の仕様で)Hello World
```
- フィルター色々リスト

- `~~|upper`：大文字にする
- `~~|lower`：￥小文字にする
- `~~|capitalize`：頭文字を大文字にする
- `~~|abs`：絶対値取得
- `~~|length`：文字数カウント(スペースも)
- `~~|wordcount`：単語カウント
- `~~|default(値)`：未定義の変数を決定する
- `~~|escape`or`~~|e`：値をエスケープする
- `~~|safe`：変数をエスケープしない(HTMLやスクリプトがタグとしてブラウザ認識される)
- `~~|format`：Pythonのフォーマットを適用
- `~~|trim`：先頭と末尾の空白を削除
- `~~|urlencode`：URLをエンコード
- `~~|replace(検索値, 置換値)`：値を置換する

#3.`form`に入ってるのか入ってないのか
```python:python
#pdf_idという名前のformを受け取れているかを判断
if("pdf_id" in request.form):
  aiu = request.form["pdf_id"]
```

#4.`url_for`を用いてリンク生成
```python:バックエンド
@app.context_processor
def override_url_for():
    return dict(url_for=dated_url_for)

def dated_url_for(endpoint, **values):
    if endpoint == 'static':
        filename = values.get('filename', None)
        if filename:
            file_path = os.path.join(app.root_path,
                                 endpoint, filename)
            values['q'] = int(os.stat(file_path).st_mtime)
    return url_for(endpoint, **values)

# これによりバックエンド側では
url_for('Login')
# この様にurl_for("関数名")で指定したルーティングへのリンクを作成出来る
```

```html:templates
<!-- フロントエンド側では、静的なファイルを呼び出したい場合は -->
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/index.css') }}">
<img src="{{ url_for('static', filename='img/icon.png') }}" style="width: 25px;">
<!-- こんな感じで、またルーティングへのリンクを指定したい場合は -->
<a href="{{ url_for('index') }}"></a>
<!-- こんな感じ -->
```

#5.リダイレクト処理
```python:バックエンド
# 単純に下記の様な形でリダイレクトが出来る
return redirect(url_for('Login')) # 上記のurl_forを用いた場合
```
機械学習と深層学習とは結局何だったのか

今更すぎて書くの恥ずかしいのですが，機械学習と深層学習とはそもそも一体何だったのか改めて考えたのでメモ．

# きっかけ
「画像認識と音声認識は似ている」と言われて混乱した．意味としては，音声は波形やMFCCなどの形で画像に変換することができ，結局，音声を画像にしてしまえば画像認識と一緒ではないか，ということ．
自分としては，画像は結局のところピクセルごとの数字の集合体であり，また音声も周波数などの数字の集合体であるため，どちらもディープラーニングの強みを活かしやすいため，画像も音声もディープニューラルネットワークを用いるという点で似ていると思った．
このとき，そういえばKaggleなどで回帰問題を解くときにディープラーニングを用いることは稀で，普通はlightgbmなどのランダムフォレストを用いるが，なぜディープニューラルネットワークを用いないのだろうか？　と思い，機械学習と深層学習の意味を改めて考えてみることにした．

# 機械学習
- ロジスティクス回帰やSVM, ランダムフォレストなど．
- 個々の手法で，数式が確立しており，内部でどのような計算が行われているのかが分かる．（数学的な意味を理解すると分かりやすい）
- 特徴量エンジニアリング（人手で重要と思われる特徴を抽出）する必要がある．
- 売上予測や株価予測など，人間がデータの意味を理解しやすく，特徴抽出しやすい分野で優秀であり，以前として深層学習よりもよく用いられる．
- いわゆるデータサイエンティストや機械学習エンジニアの職業がこれにあたる．

# 深層学習
- DNN, CNNやRNNなど．
- 入力層と出力層の間に複数の隠れ層を追加したもの．ネットワークを深くするとは，隠れ層を増やすことにあたる．
- この隠れ層では入力に対して非線形の活性化関数を合成し，より複雑な関数を表現しようとしている．
- 誤差逆伝播法により深い隠れ層でもパラメータ更新できるようにする．
- 隠れ層における計算は，人間が理解するには意味のない数字の羅列となり，いわゆるブラックボックス化が生じる（コンピュータには理解できるかもしれないが，人間には難しすぎる）．
- 説明可能なAIのトレンドはこのブラックボックス問題を解消せんとするものであり，古典的な統計・機械学習手法と組み合わせることで説明を試みるものが多い．
- かつては勾配消失や過学習の問題が深刻だったが，ビッグデータが手に入るようになったり，ReLU関数などの発明により特に画像認識において高いパフォーマンスを発揮できるようになった．
- ディープニューラルネットワークでは，注目すべき特徴を自動で抽出するため（隠れ層で勝手に計算しているため），人手で特徴を抽出する必要がない．
- すなわち，人間が特徴を抽出しづらい分野ほどインパクトが大きいはずで，特に画像・音声・言語処理は特徴を人間が理解しづらい（数字の羅列なので）ため，これらの分野においてブレイクスルーとなった．
- 一般的に画像・音声・自然言語処理に従事する人たちが最も深層学習を利用しているだろう．

# 共通項
- 初期のパーセプトロンの思想から発展している．
- 損失関数を設定し，それを最小化するように重みを更新する．
- 勾配降下法によりパラメータ更新する．

# 今後
- 画像は比較的理解しやすいが，音声における深層学習の応用はどのように行っているのか．End-To-Endという枠組みが流行しており，これはLSTMのみで音声認識を行う試みであるが，このEnd-To-Endとは詳しくは何なのか．
- 最近流行のTransformerとは何なのか．上記のメリットがある深層学習や従来の機械学習とは何が異なるのか．
Oculus Quest2  設定まわりメモ

## 無線でPCVRやる方法

### Virtual DesktopのPC側の設定
1. SteamVRインストール
2. Virtual Desktop（無料）インストール
3. インストールしたVirtual Desktop Streamerを起動

### OculusQuest2側の設定
1. Virtual Desktopアプリを購入し、インストール
2. SideQuestアプリをインストールし、起動
3. Oculus開発者ページからADBドライバーのダウンロードし、インストール
4. スマホのOculusのアプリを開いてOculusの開発者モードをON
5. Oculus QuestとPCをUSBケーブルで接続
6. PCのSideQuestの検索からVirtual Desktopを探し、“INSTALL LATEST”を選択。APKファイルをQuest本体にインストール

## 実際にPCVRアプリを無線で遊ぶ
1. PCでVirtual Desktop Streamer起動し、oculusのUsernameを入力しておく
2. SteamVR起動
3. QuestでVirtual Desktop起動
4. Virtual Desktopのメインメニューの”GAME”からPC版VRアプリを選択

### ADBドライバー
- Oculus QuestとPCをつなげるためのドライバー

### SideQuest
- Oculus Quest向けのサイドローディングアプリ
- サイドローディング：正規のアプリストア以外から、アプリを入手しインストールすること

### virtual desktop
- 購入時の状態ではPCVRゲームをプレイできず、SideQuestを通じてパッチファイルを導入し、SteamVR対応機能を復活させる必要がある

## 有線でPCVRをやる方法

### Oculus link
- USB3.0以上必要（USB2.0だと警告文が出るらしい。）

### その他
- Oculusホーム画面のアプリ一覧からSteamVRの「アプリを終了する」を押しても終了できないとき、PC側でタスクマネージャーを開き、先頭にSteamとついたプロセスを終了させる

- PC向けOculus公式設定アプリでデバイス登録する際、デバイスが認識されないとき、Oculus Air Linkをオフにすると認識されるようになる。（Oculusボタンを押してユニバーサルメニューを開き、設定 → テスト機能でAir Linkの横をクリックしてオフにする。）
Gradle testでリモートデバッグ

## 問題

Eclipseからjunitのテストクラスを実行すると以下のようなエラーがでるとき、ググるとたいていクラスパスがどうのといわれる。

```
エラー： メイン・クラスorg.eclipse.jdt.internal.junit.runner.RemoteTestRunnerを検出およびロードできませんでした
原因: java.lang.ClassNotFountException: org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
```

いろいろな解決策を試すも一向に治らないので（仕事で時間かけてるのもアホらしいので）、Gradleテストでリモートデバッグできないのかと調べたらあった。


## リモートデバッグ

「--debug-jvm」オプションをつけて実行すると5005ポートで待受になるので、Eclipseからリモートデバッグで接続することが可能。

```
$ ./gradlew test --tests "*XxxxTest" --info --debug-jvm
```

* オプション
    * --tests "*XxxxTest": 実行したいテストクラスのFQCN
    * --info: Gradle実行のログレベルをINFOに（好みで）

## まとめ

今までできないものだと思ってたが、Gradleにもリモートデバッグが可能になるオプションがあった。
dartのMockitoで特定のHTTPリクエストのみモックする

## はじめに
FlutterのIntegration testをする際に、特定のAPIリクエストのみレスポンスをモックしたい場合があります。
モック対象でないその他のリクエストは、通常通りサーバーと通信させたいです。

この記事では、上記のような挙動を実現するためのコードを紹介します。

## 早速、コード例
下記のコードで、先の挙動を実現できます。

```dart:コード例

import 'package:mockito/mockito.dart';
import 'package:http/http.dart' as http;

void main() {
  final realClient = http.Client();
  final mockClient = MockClient();
  
  when(mockClient.get(any, headers: anyNamed("headers"))).thenAnswer((i) async {
    return await realClient.get(
      i.positionalArguments[0], 
      headers: i.namedArguments[Symbol('headers')],
    );
  });
  
  when(mockClient.post(any, headers: anyNamed("headers"), body: anyNamed("body"))).thenAnswer((i) async {
    return await realClient.post(
      i.positionalArguments[0],
      headers: i.namedArguments[Symbol('headers')],
      body: i.namedArguments[Symbol('body')],
    );
  });
  
  when(mockClient.get('https://example.com/items', headers: anyNamed("headers")))
      .thenAnswer((_) async => http.Response('[]', 200));
  
  // テスト内では mockClient を利用してAPIリクエストするようにする
  ApiClient.client = mockClient;
}
```

## ポイント
### `any`によるモック
引数を `any` としてモックすることで、引数によらず `thenAnswer` に渡すことができます。
また、名前付き引数については `anyNamed` というメソッドを利用します([参考](https://pub.dev/packages/mockito#named-arguments))。

```dart
when(mockClient.get(any, headers: anyNamed("headers")))
```

### `thenAnswer` 内での引数の取得
[Invocation オブジェクト](https://api.flutter.dev/flutter/dart-core/Invocation-class.html) から、Mockでマッチした引数を取得することができます。
これで取得した値を用いて、本物の`http.Client`のHTTPメソッドを呼び出して、レスポンスを取得します。

```dart
.thenAnswer((invocation) async {
    return await realClient.post(
      invocation.positionalArguments[0],
      headers: invocation.namedArguments[Symbol('headers')],
      body: invocation.namedArguments[Symbol('body')],
    );
  }
```

### 特定APIへのMockは最後に追加する
モックを呼ぶ順番が重要なようです。
例えば、下記を最初に追加すると、`https://example.com/items` も実際のリクエストが飛ぶようになります。

```dart
  when(mockClient.get('https://example.com/items', headers: anyNamed("headers")))
      .thenAnswer((_) async => http.Response('[]', 200));
```

これはMockitoの内部実装による挙動と思われますが、今のところはMockを宣言する順番を考慮することで、所望の動作を実現できます。

## まとめ
上記のコードで、特定APIのみMockし、その他のリクエストは通常通りの挙動とすることができました。
例では `get` と `post` のみモックしていますが、必要に応じて他のHTTPメソッドを追加しても良いでしょう。

以上です。
Jestで同一ファイル内で異なる振る舞いのモックを使用したい場合（axios）

##初めに

メモ書きようです。
ざっくりと書いていますのでご了承ください。

##同一ファイル内で異なる振る舞いのモックを使用したい場合

例えば以下のようなAPIがあったとします。

```test.ts
async hoge(): Promise<Hoge> {
    const res = await $axios.$get('/hoge');
}

async fuga(): Promise<Fuga> {
    const res = await $axios.$get('/fuga');
}

```

異なる振る舞いのモックを作成する場合は以下のように書けます。

```test.spec.ts
import { $axios } from '@/store/utils/api.ts';

jest.mock('@/store/utils/api.ts', () => ({
  $axios: {
    $get: jest.fn(),
  }
}));

describe('Test', () => {
  test('hoge', async () => {
    ($axios.$get as jest.Mock).mockImplementation(() =>
      Promise.resolve({
        ~
    }));
  });
  await hoge()
});

describe('Test', () => {
  test('fuga', async () => {
    ($axios.$get as jest.Mock).mockImplementation(() =>
      Promise.resolve({
        ~
    }));
  });
  await fuga()
});


```
Laravel/uiのインストールの注意

自分が出会ったエラーと解決法を書いています。
#環境
laravel:7.30.2
php:7.4

※ php8だとlaravel/uiは使えない
laravel8ならjetstream??使うのがいいのかな？
#laravel/ui インストールでエラー
```composer require laravel/ui```とコマンドを叩いた際に下記のエラーが出た。

```
Installation failed, reverting ./composer.json to its original content.
```
どうやらバージョンの重複が...という感じらしくこれを回避するコマンドを叩かないといけない。

```
composer require laravel/ui:3.*
``` 
自分は```composer require laravel/ui:2.*```で動いた。

#web.phpでのエラー
インストールはできたけどweb.phpで新たなエラーが出ていた。
原因はlaravel/uiをインストールしたときにweb.phpに```Auth::routes();```が生成されるが、namespaceの問題みたい。
てことで、```use Illuminate\Support\Facades\Auth;```を記述すると解決する。
pageとcomponentのやりとり

# $emit

componentからpageへ値を渡す

```vue:pages/index.vue
<template>
  <div>
    <div>
      {{ count }}
    </div>
    <child @eventName="parentMethod" />
  </div>
</template>

<script>
import Child from '@/components/child'

export default {
  components: {
    Child
  },
  data: () => ({
    count: 0
  }),
  methods: {
    parentMethod(count) {
      this.count = count
    }
  }
}
</script>
```

```vue:components/child.vue
<template>
  <div>
    <button @click="sendParent">送信</button>
  </div>
</template>

<script>
export default {
  data: () => ({
    clickCount: 0
  }),
  methods: {
    sendParent() {
      this.$emit('eventName', ++this.clickCount)
    }
  }
}
</script>
```

# $refs

pageでcomponentの関数を呼ぶ

```vue:pages/index.vue
<template>
  <div>
    <div>
      <button @click="doChildMethod">実行</button>
    </div>
    <child ref="child" />
  </div>
</template>

<script>
import Child from '@/components/child'

export default {
  components: {
    Child
  },
  methods: {
    doChildMethod() {
      this.$refs.child.countUp()
    }
  }
}
</script>
```

```vue:components/child.vue
<template>
  <div>
    {{ clickCount }}
  </div>
</template>

<script>
export default {
  data: () => ({
    clickCount: 0
  }),
  methods: {
    countUp() {
      this.clickCount++
    }
  }
}
</script>
```
iOSからMacのRailsアプリをlocalhostでデバッグする時の設定

なんども忘れるので備忘録として
## 流れ
- MacとiOSを同じWiFiネットワークに接続
- Macの接続IPアドレスを確認
- iOSで接続しているネットワークにプロキシを設定
- iOSのプログラムソースの修正
- サーバーをローカル起動

## MacとiOSを同じWiFiネットワークに接続
MacとiOSは同じWiFiネットワークに接続。
## Macの接続IPアドレスを確認
システム環境設定⇨ネットワーク⇨WifiからIPアドレスを確認。
![networking1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143374/5ea8ff3b-abcc-641d-bcf5-7108caa79f3e.png)

![networking.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143374/5b155a76-eb55-1e83-c326-d1f644a9b489.png)

## iOSで接続しているネットワークにプロキシを設定
設定アプリ⇨Wifi⇨iマーク⇨HTTPプロキシ⇨手動でサーバーとポートを指定。
![networking5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143374/304d87e4-8686-450d-e7f1-90c5572ba83c.png)
![networking4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143374/af36219c-4ede-3db7-c469-6cb932a874a3.png)
![networking3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143374/1a6d0b41-3688-f1f5-223e-0f089585a9f6.png)

## iOSのプログラムソースの修正
```
static let v1Url: String = {
        #if DEBUG
        return "http://192.xxx.xxx.2/api/v1/"
        #endif
        return "https://xxxxxxxx.com/api/v1/"
    }()
```
## サーバーをローカル起動
` bundle exec rails s -b 0.0.0.0 ` 

` -b 0.0.0.0 `
を指定しないとlocalhost以外からだとアクセスができない
同一ネットーワークでかつIPが分かれば、どの端末でも誰でもアクセスできるので、漫画喫茶などのネットワークでやる際は注意は必要
Ubuntu20にArudinoIDEをインストールする

ダウンロードとインストールと権限の追加

````
wget https://downloads.arduino.cc/arduino-1.8.13-linux64.tar.xz ;
cd ~/Downloads/ ;
tar xvf arduino-1.8.13-linux64.tar.xz ;
cd arduino-1.8.13/ ;
sudo ./install.sh ;
sudo usermod -aG dialout $(whoami) ;
arduino ;
````

もし、スケッチファイルをボードへ転送する際に権限のエラーが出る場合は以下を試します。

usbシリアルポートを書き込みできるようにします。

````
sudo chmod a+rw /dev/ttyUSB0 ;
````

ただ、これは毎回コマンドを打つのが面倒なのでudevにルールを記載します。

````
sudo gedit /lib/udev/rules.d/50-udev-default.rules;

# serial
KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout", MODE="0666"
````
Windows10でlzhフォルダを復活させる

# Windows10でlzhフォルダを復活させる

Windows10のどこかのバージョンからlzhフォルダ機能が削除されたが、それを復活させるHack。

いまさら感あるけど、、、メモとして記録を残しておく。

# ライセンスなど法的な話

よく分からん。
このページの内容は、ライセンス上の問題が(もしあれば)クリアしているわけではなく、技術的にこうすればできる。というHack内容であるので、読者諸氏は注意してほしい。

# 主旨

## 基本方針

lzhフォルダに対応しているライセンスを有するWindowsからdllをコピーする。というもの。

## 用意するもの

- lzhフォルダに対応しているライセンスを有しているWindows7/8/10
- lzhフォルダに対応していないライセンスを有しているWindows10

## 具体的な手順

以下のDLLをコピーする。そして、以下のレジストリをエクスポート&amp;インポートすれば、Windows10でも(自分が確認したのはWindows8.1⇒Windows10 ver2004)lzhフォルダが使える

### dll のコピー

コピー対象のdllは以下

- %windir%\system32\lzhfldr2.dll

コピーする場合は、Bitを合わせること。
例えば、32Bit Windowsのlzhfldr2.dllを64Bit Windowsへコピーしても動作しないようだ。

コピーには、管理者権限が必要でしょう。

### レジストリのコピー

エクスポート&amp;インポートする対象のレジストリは以下

- 32bit Windows
 - HKEY_CLASSES_ROOT\LzhCompressedFolder2 以下
 - HKEY_CLASSES_ROOT\\.lzh 以下
 - HKEY_CLASSES_ROOT\Applications\lzhfldr2.dll 以下
 - HKEY_CLASSES_ROOT\CLSID\{4F289A46-2BBB-4AE8-9EDA-E5E034707A71} 以下
 - HKEY_CLASSES_ROOT\CLSID\{58001B57-DC1F-4FAC-AC66-79E214C1A782} 以下
 - HKEY_CLASSES_ROOT\CLSID\{E5BA42A9-BF3F-40B3-978A-CCD306F381A7} 以下
- 64bit Windows
 - 32BitWindows のレジストリに加えて以下をエクスポート&amp;インポート 
 - HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{E5BA42A9-BF3F-40B3-978A-CCD306F381A7} 以下
 - HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{58001B57-DC1F-4FAC-AC66-79E214C1A782} 以下
 - HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{4F289A46-2BBB-4AE8-9EDA-E5E034707A71} 以下

HKEY_CLASSES_ROOT ⇒ HKCR と書く場合があるね。

### 最後に・・・

Windowsを再起動して、lzhフォルダとして動作するかを確認して、終了

## dllのビット(どうでもいいつぶやき)

lzhfldr2.dllって、32bitなんですかね!? ⇒ 64Bit WindowsでWoW32のレジストリをいじっているので・・・

# 参考

[Win7編: 圧縮フォルダ機能を無効にし、無駄な機能を削る(後編)](https://news.mynavi.jp/article/windows-70/)

# 以上
React(TypeScript)のlabelタグにnameやvalue属性の代替え属性をいれる

結論としてカスタム属性を使います。

JSX上でinputタグ(type="radio")とlabelの擬似要素を組み合わせた際に実際にクリックされる方であるlabelタグの属性にnameやvalueを使えずつまづいたので代替え方法のTIPSです。

##背景
ご存知のようにinput + labelのスタイル制御はJSを使わずに選択されたラベルのスタイルを変更するHTML/CSSでこれまで使われきた手法です。

わざわざReactでこのテクニックを使ってしまったところlabelクリック時に状態を保存したいのですがlabelタグにnameやvalueといった属性は使えないためlabeタグに必要な情報を埋め込めなくなりました。

素直にJSオンリーでスタイル制御すべきだった...
nameやvalueをlabelタグへそのまま使うと当然のようにそんな属性の型はねえぞと怒られる。

```
Type '{ children: string; onClick: (e: MouseEvent<HTMLLabelElement, MouseEvent>) => void; value: string | number; id: string; htmlFor: string; }' is not assignable to type 'DetailedHTMLProps<LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>'.
  Property 'value' does not exist on type 'DetailedHTMLProps<LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>'.ts(2322)
```

もうCSSでスタイルを当ててしまったあとだし作り変えるための優先順位はそこまで高くないしということでこのままlabelで使えるようにしました。同じような人はどうぞ。

## 解決策：カスタム属性を使う

といっても解決策は単純でnameやvalueに変わる属性を付与します。

```
<label data-{任意の名前} >Hello 沼!</label>
```

というようにカスタム属性を使います。

```sample.tsx
<label onClick={e => handleClickChange(e)} data-name={name} data-value={value} 
 htmlFor={idName} >Hello 沼!</label>
```

引っ張る際には e.currentTarget.dataset.{任意のカスタムデータ名} で引っ張れます。接頭辞のdata-は不要ですが。
そしてTypeScriptとしてアサーションを使うのは御行儀がよくないのですが下のような形で引っ張ってこれました。

```sample.tsx
  const handleClickChange = (e: MouseEvent): void => { 
    const name = (e.currentTarget as HTMLInputElement).dataset.name as string;
    const value = (e.currentTarget as HTMLInputElement).dataset.value;
    setProfile(currentValue => ({
      ...currentValue,
      [name]: value
    }));
  }

```