OmniAICreator/Qiita-1.07M huggingface dataset:
Amazon EKSでKubernetesダッシュボードを利用する

# はじめに
Amazon EKSで [Kubernetes ダッシュボード](https://kubernetes.io/ja/docs/tasks/access-application-cluster/web-ui-dashboard/) を利用する方法をまとめます。
Mac環境を想定しています。

今回のバージョンは `v2.7.0` を想定しています。

最新のバージョンに関しては、[release](https://github.com/kubernetes/dashboard/releases) を確認してください。

# 実行環境の準備
1.  AWS CLIの設定
[AWS CloudFormationを動かすためのAWS CLIの設定](https://qiita.com/miyabiz/items/fed11796f0ea2b7608f4)を参考にしてください。

1.  EKSクラスタの構築
[Macでeksctlを利用してAmazon EKSのクラスターを構築する](https://qiita.com/miyabiz/items/75f83237795b0b7d52bd)を参考にしてください。

1.  EKSのコンテキストの設定
[MacにてAmazon EKSの設定をする](https://qiita.com/miyabiz/items/b98d145cedb35dab9524)を参考にしてください。

# 環境設定
1.  Kubernetesダッシュボードをクラスターに適用する
    ※事前にKubernetesクラスターのコンテキストの設定をします。

    ```sh
    kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
    ```

1.  `eks-admin-service-account.yaml` を作成する
    ※サービスアカウント（`eks-admin`）とクラスターロールバインディング(RBAC:Role Based Access Control)を作成する

    ```yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: eks-admin
      namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: eks-admin
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-admin
    subjects:
    - kind: ServiceAccount
      name: eks-admin
      namespace: kube-system
    ```

1.  クラスターに適用する

    ```sh
    kubectl apply -f eks-admin-service-account.yaml
    ```

1.  サービスアカウント（`eks-admin`）の認証トークンを取得する

    ```sh
    kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}')
    ```

1.  Kubernetesダッシュボードを起動する

    ```sh
    kubectl proxy
    ```

1.  Kubernetesダッシュボードにアクセスする

    ```sh
    open "http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/"
    ```

# クリーンアップ

1.  クラスターからで削除する

    ```sh
    kubectl delete -f eks-admin-service-account.yaml
    ```

1.  Kubernetesダッシュボードをクラスターから削除する

    ```sh
    kubectl delete -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
    ```

# 参考
- [Web UI (Dashboard)](https://kubernetes.io/ja/docs/tasks/access-application-cluster/web-ui-dashboard/)
- [チュートリアル: Kubernetes ダッシュボード (ウェブ UI) のデプロイ](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/dashboard-tutorial.html)
【React】API通信をaxiosで実装してみて

# API通信をaxiosで実装してみて
ReactでのAPI通信の備忘録として本記事を残すことにします
（コードとしては内容としては不十分な箇所多々あるかもしれません、、、）

## Axiosを使ってみた
「React API」と検索したところ多く利用されているのが[axios](https://github.com/axios/axios)。
実際に使ってみるとかなり便利かつコンパクト!

以下のコマンドでインストールができる
```bash
$ npm install axios
```

## APIを叩いてみる
それぞれのパターンごとに記述してみる
あえて、APIを叩くURLを以下のように記述する
```react
const url:string = 'https://********'
```
また、axiosのimportは忘れないように
```react
import axios from 'axios'
```

### GET(取得)

```react
const [res,setRes] = useState([])
const getAPI = axios.get(url).then(result => {
            setRes(result);
        })
```

### POST(登録)
POSTリクエストする場合は第1引数にURL、第2引数にデータが必要
```react
const [res,setRes] = useState([])
const postAPI = axios.post(url,data).then(result => {
            setRes(result);
        })
```
ちなみに、第3引数としてヘッダーを渡すことも可能
```react
const auth = headers: {
    Authorization: `****`,
  }
const [res,setRes] = useState([])
const postAPI = axios.post(url,data,{auth}).then(result => {
            setRes(result);
        })
```
詳しくは[ここ](https://github.com/axios/axios#request-method-aliases)らへん参照

## 実際に使うときはuseEffectと重ねて
axiosを使うときはuseEffectと併用すると使い勝手がいい
```react
const [res,setRes] = useState([])
useEffect(() => {
    const getAPI = axios.get(url).then(result => {
            setRes(result);
        })
  },[]) 
```
useEffectの第2引数が空配列の場合は初回のレンダリングの際のみAPI通信ができる
初回レンダリング時に認証情報をGETし、二次利用したい場合などに使える
また、第2引数にPropsを渡すことでPropsが変更のたびにAPI通信が動くような仕組みも作ることができる

便利。。

## 参考記事
 [[axios] axios の導入と簡単な使い方](https://qiita.com/ksh-fthr/items/2daaaf3a15c4c11956e9)
[React hooksを基礎から理解する (useEffect編)
](https://qiita.com/seira/items/e62890f11e91f6b9653f)
TypeScript版Propsの受け渡し

# TypeScript版Propsの受け渡し
React感覚でPropsの受け渡しをした際にうまくいかなかったので対処法をメモしてみた

## ReactでのPropsの受け渡し
親コンポーネント
```react:Main.jsx
import Child from "./Child";

export default function Main() {
  const text: string = "I'm Happy!";

  return <Child sendText={text} />;
}
```
子コンポーネント
```react:Children.jsx
export default function Child(props) {
  return <div>{props.sendText}</div>;
}
```

## TypeScriptで同様の実装をする

```ts:Main.tsx
return <Child sendText={text} />
```
`sendText`にて以下のエラーメッセージが発生する
```
Type '{ sendtext: string; }' is not assignable to type 'IntrinsicAttributes'.
  Property 'sendtext' does not exist on type 'IntrinsicAttributes'.
```

### エラー対処
これは型の定義が不十分のために起こる。
Reactは型推論が効いているためこのエラーは発生しない。

なのでPropsの型を定義してあげれば問題は解決する
```ts:Main.tsx
import Child from "./Child";

export default function Main() {
  const text: string = "I'm Happy!";

  return <Child sendText={text} />;
```
```ts:Children.tsx
import { PropsType } from "./PropsType"

export default function Child(props:PropsType) {
  return <div>{props.sendText}</div>;
}
```
```ts:PropsType.ts
export interface PropsType{
  type sendText:string;
}
```

Propsが複数ある場合は型定義の記述を増やせば問題なし

## おわり
`IntrinsicAttributes`この見慣れない単語にあそばれた、、、
ググってもそれっぽい記事なかったので備忘録として残します。

（間違いある場合はご指摘いただきたいです。）
【GitLab CI/CD】Default branchへのマージをトリガーとしてジョブを実行する

GitLabCI/CDを用いてDefault branchに設定されているブランチに変更がマージされた時のみジョブを実行する処理を実装します。

### やりたいこと

「Default branchに変更がマージされたら変更内容を自動で検証環境にデプロイする」みたいなことをするパイプラインを構築することが目的です。
(デプロイ先のサーバを用意するのが面倒なので、今回は文字列を標準出力に出力するだけにします。)



### 環境

- GitLab.com (オンプレミス版での動作確認はできていません)

### 実装例

```yml:.gitlab-ci.yml

# stageを定義(今回は無くてもよいです)
stages:
  - deploy

deploy_job:
  stage: deploy
  # 処理内容
  script:
   - echo "Hello, Wolrd"
   - echo "$CI_DEFAULT_BRANCH"
  # ジョブを実行する条件を記述
  rules:
   - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
```

### コード解説

- CI_COMMIT_BRANCH: コミットされたブランチ名を参照する環境変数です。GitLabであらかじめ定義されています。
- CI_DEFAULT_BRANCH: デフォルトブランチ名を参照する環境変数です。こちらもGitLabで定義されています。

「リモートリポジトリ上で変更をマージする」というアクションがコミットとして扱われることを理解するのに時間がかかり、マージをジョブの実行条件とする方法に悩みました。

「コミット = 変更内容を登録すること」と解釈するとマージもコミットとして扱われることは腑に落ちます。
pyenv で困ったこと

pyenvを使用したときに困ったことをメモとして残しておきます。

## Pythonのバージョンが切り替わらない

Pythonのバージョンを3.7.9から3.9.0を切り替えたかったため
```
nari@qiita $ pyenv global 3.9.0
```
と実行しましたが切り替わりませんでした.
```
nari@qiita $ pyenv versions
  system
* 3.7.9 (set by /Users/nari/Documents/qiita/.python-version)
  3.9.0
```
### 解決策 : pyenv localを使う
ディレクトリごとにPythonのバージョンを指定できるpyenv localを使用していたことを忘れていました.そこで使用したいディレクトリで再度pyenv localを使用しました.
```
nari@qiita $ pyenv local 3.9.0
```
実行したところ無事に切り替わりました.
```
nari@qiita $ pyenv versions
  system
  3.7.9 
* 3.9.0 (set by /Users/nari/Documents/qiita/.python-version)
```
## Pythonのバージョンが切り替わらない2
```
nari@qiita $ pyenv versions
  system
* 3.7.9 (set by PYENV_VERSION environment variable)
  3.9.0
```
Pythonのバージョンを示す数字の後に`set by PYENV_VERSION environment variable`と表示されていました.(本来はパスが表示されるはず)
環境変数になぜかバージョンを指定されていました.

### 解決策 : pyenv shell --unsetを実行する
環境変数を解除するために以下のコマンドを実行しました.
```
nari@qiita $ pyenv shell --unset
```
すると無事にPythonのパスが表示されるようになりました.
```
nari@qiita $ pyenv versions
  system
* 3.7.9 (set by /Users/nari/Documents/qiita/.python-version)
  3.9.0
```
ここまでくると上で実行した時と同じくPythonを指定すると無事にバージョンが切り替わりました.
```
nari@qiita $ pyenv local 3.9.0
nari@qiita $ pyenv versions
  system
  3.7.9 
* 3.9.0 (set by /Users/nari/Documents/qiita/.python-version)
```

---
Ref : https://qiita.com/morrr/items/cdd7d162a882ad2b2a59
[web3js]Metamaskのネットワーク変更を検知する

Metamaskはメインネットやテストネットの切り替えが自由にできますが、ネットワーク切り替え時にフロント側で自動で検知するサンプルを作成しました。

## サンプル
テストネットやアカウント変更時に表示を変えるサンプルです。
※Chrome拡張のMetamaskをインストールしないと起動しませんのでご注意ください

<p class="codepen" data-height="300" data-default-tab="js,result" data-slug-hash="qBKWOJv" data-user="kurokiri" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kurokiri/pen/qBKWOJv">
  web3 changed chain</a> by Kurokiri (<a href="https://codepen.io/kurokiri">@kurokiri</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


## 処理説明
過去はgetNetwork等でネットーワーク情報を取得できたみたいですが、現在（2022年10月）は`getChainId`が推奨されているので下記みたいにあらかじめ必要なチェーン情報を定義しておいてIDで取得する方法がよさそうです。

```js
const Chains = {
  1: "Mainnet",
  3: "Ropsten[Deprecate]",
  4: "Rinkeby[Deprecate]",
  5: "Goerli",
  11155111: "Sepolia",
};
```

また、過去はネットワーク切り替えタイミングで自動でブラウザリロードが走っていたみたいですが、現在は切り替えてもリロードされないのでsetIntervalで定期実行し、検知する必要があります。

```js
  // ネットワーク切り替えを検知
  setInterval(async function () {
    const web3 = new Web3(window.ethereum);
    const chengedNetwork = await web3.eth.getChainId();
    if (currentNetwork !== chengedNetwork) {
      currentNetwork = chengedNetwork;
      const networkTextArea = document.getElementById('network');
      networkTextArea.textContent = "選択しているネットワークは" + Chains[currentNetwork] + "です";
    }
  }, 1000);
```

## まとめ
Metamaskのネットワークやアカウントはユーザーが自由に切り替えられるため、切り替わったタイミングで何かしら処理を分岐させる必要がある場合の参考になったら嬉しいです。
また、現在このやり方は古いとか、こういうやり方もあるよ！みたいなコメントあればぜひお願いします！

## リファレンス
https://web3js.readthedocs.io/en/v1.8.0/
[AWS Lambda Powertools Python]パラメータ機能のtransform動作を確認

# 概要

[AWS Lambda Powertools Python](https://awslabs.github.io/aws-lambda-powertools-python/latest/) [^1] の機能のうち、[パラメータ機能(Parameters)](https://awslabs.github.io/aws-lambda-powertools-python/latest/utilities/parameters/) [^2] にはJSONとbase64を変換してくれる機能が含まれています。
簡単なサンプルで動作を確認します。

[^1]: [AWS Lambda Powertools Python](https://awslabs.github.io/aws-lambda-powertools-python/latest/)
[^2]: [Parameters](https://awslabs.github.io/aws-lambda-powertools-python/latest/utilities/parameters/)


# 確認手順

対象はSSM Parameter Storeとします。

## モジュール

```
aws-lambda-powertools 1.31.1
boto3                 1.24.96
botocore              1.27.96
```

## パラメータ設定

AWS CLIで設定しました。

**JSONテキストを設定**

```sh
$ aws ssm put-parameter \
    --name "/my/json-parameter" \
    --value "{\"name\": \"AWS Lambda Powertools\", \"language\": \"Python\"}" \
    --type String
```

**base64テキストを設定**

`Hello AWS Lambda Powertools!`をbase64コマンドでエンコードした結果を設定しています

```sh
$ aws ssm put-parameter \
    --name "/my/base64-parameter" \
    --value "`echo -n 'Hello AWS Lambda Powertools!' | base64`" \
    --type String
```


## ソースコード

`transform` 引数を指定しない場合と適切に指定した場合の結果を確認します。


```parameter_transform.py
from aws_lambda_powertools.utilities import parameters

# JSON
value_json_raw = parameters.get_parameter("/my/json-parameter")
value_json_dict = parameters.get_parameter("/my/json-parameter", transform='json')

print(f'{value_json_raw=}')
print(f'{value_json_dict=}')

# base64
value_base64_raw = parameters.get_parameter("/my/base64-parameter")
value_base64_bin = parameters.get_parameter("/my/base64-parameter", transform='binary')

print(f'{value_base64_raw=}')
print(f'{value_base64_bin=}')
```

## 実行結果

- value_json_raw...設定したJSONテキストそのままです
- value_json_dict...JSONテキストが辞書型に変換されています
- value_base64_raw...base64テキストそのままです
- value_base64_bin...base64デコード結果のバイナリに変換されています


```sh
$ python parameter_transform.py
value_json_raw='{"name": "AWS Lambda Powertools", "language": "Python"}'
value_json_dict={'name': 'AWS Lambda Powertools', 'language': 'Python'}
value_base64_raw='SGVsbG8gQVdTIExhbWJkYSBQb3dlcnRvb2xzIQ=='
value_base64_bin=b'Hello AWS Lambda Powertools!'
```


## 変換エラーの捕捉

`TransformParameterError` 例外で捕捉できます。

```parameter_transform_exception.py
from aws_lambda_powertools.utilities import parameters

try:
    value = parameters.get_parameter("/my/json-parameter", transform='binary')  # invalid transform
except parameters.exceptions.TransformParameterError as e:
    print(f'変換エラーです: {e=}')
```

```sh
$ python parameter_transform_exception.py
変換エラーです: e=TransformParameterError('Invalid base64-encoded string: number of data characters (37) cannot be 1 more than a multiple of 4')
```
MVC(Model View Controller)とは？

## はじめに
Ruby on Rails 等で使用される MVCについて書きたいと思います。

## MVCとは？
- Model View Controller の略称
- プログラムの処理を役割毎に分けて開発を行う考え方
    - Webシステムの開発で主に使用される
- 以下のフレームワークで使用されている
    - Ruby on Rails, Laravel, SpringBoot 等


## MVCの構成
- Model
    - ビジネスロジックを書く部分
        - データベースとのデータのやり取りを行う部分
- View
    - ユーザーが実際に見る画面
- Controller
    - リクエストやレスポンスを制御
    - ViewとModelの橋渡し


## 図

![MVC.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/0d506bc0-9156-ad22-c09e-11278e413164.png)



## 参考

https://www.udemy.com/course/the-ultimate-ruby-on-rails-bootcamp/

https://railstutorial.jp/chapters/beginning?version=6.0#sec-mvc

https://snome.jp/framework/mvc-model/
DatabricksノートブックでPythonセルのフォーマットをサポートしました

何のことかと思われるかもしれませんが、こちらです。

[Format code cells](https://docs.databricks.com/notebooks/notebooks-use.html#format-code-cells)

とりあえず、該当のセクションの翻訳を。後で下のマニュアルの翻訳にマージします。

# コードセルのフォーマット

Databricksでは、ノートブックのセルにあるPythonとSQLのコードをクイックかつ簡単にフォーマットするツールを提供しています。これらのツールによって、コードがフォーマットされた状態を維持し、どのノートブックにおいても同じコーディング規約を強制する助けとなります。

## Pythonセルのフォーマット

:::note
**プレビュー**
この機能は[パブリックプレビュー](https://docs.databricks.com/release-notes/release-types.html)です。
:::

Databricksランタイム11.2以降では、ノートブック内のコードをフォーマットするために[Black](https://black.readthedocs.io/en/stable/)を使用します。ノートブックはクラスターにアタッチされている必要があり、ノートブックがアタッチされているクラスター上でBlackが実行されます。

### PythonとSQLのセルをどの様にフォーマットするのか

コードをフォーマットするにはノートブックの[Can Edit権限](https://docs.databricks.com/security/access-control/workspace-acl.html#notebook-permissions)が必要となります。

以下の方法で、フォーマッターを起動することができます。

- **単一セルのフォーマット**
    - キーボードショートカット：**Cmd+Shift+F**を押します。
    - コマンドコンテキストメニュー
        - SQLセルのフォーマット：SQLセルのコマンドコンテキストドロップダウンメニューの**Format SQL**を選択します。このメニュー項目はSQLノートブックセルか`%sql`[言語マジック](https://qiita.com/taka_yayoi/items/dfb53f63aed2fbd344fc#%E3%83%9F%E3%83%83%E3%82%AF%E3%82%B9%E8%A8%80%E8%AA%9E)を持つセルでのみ表示されます。
        - Pythonセルのフォーマット：Pythonセルのコマンドコンテキストドロップダウンメニューの**Format Python**を選択します。このメニュー項目はPythonノートブックセルか`%python`[言語マジック](https://qiita.com/taka_yayoi/items/dfb53f63aed2fbd344fc#%E3%83%9F%E3%83%83%E3%82%AF%E3%82%B9%E8%A8%80%E8%AA%9E)を持つセルでのみ表示されます。
- **複数セルのフォーマット**

    [複数のセルを選択](https://qiita.com/taka_yayoi/items/dfb53f63aed2fbd344fc#%E8%A4%87%E6%95%B0%E3%81%82%E3%82%8B%E3%81%84%E3%81%AF%E5%85%A8%E3%81%A6%E3%81%AE%E3%82%BB%E3%83%AB%E3%82%92%E9%81%B8%E6%8A%9E)し、**Edit > Format Cell(s)** を選択します。1つ以上の言語のセルを選択した場合には、PythonとSQLのセルがフォーマットされます。これには`%sql`や`%python`を使用しているものも含まれます。

- **ノートブック内のすべてのPythonとSQLセルのフォーマット**

    **Edit > Format Notebook**を選択します。1つ以上の言語のセルが含まれている場合には、PythonとSQLのセルがフォーマットされます。これには`%sql`や`%python`を使用しているものも含まれます。

### 制限

- Blackは4スペースのインデントに対して[PEP 8](https://peps.python.org/pep-0008/)を強制します。インデントの設定はできません。
- SQL UDFの中に埋め込まれたPython文字列のフォーマットはサポートされていません。同様に、Python UDF内のSQL文字列のフォーマットもサポートされていません。

# 実際に試してみる

Databricksランタイム11.2以降のクラスターを起動して、ノートブックをアタッチします。
![Screen Shot 2022-10-23 at 17.16.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/db5216d3-fd45-b4d2-860e-0a82410fd584.png)

フォーマットしたいセルに移動してコンテキストメニューを展開します。**Pythonをフォーマット**を選択します。特に14行に注目していてください。個人的にはこの状態は耐えられません。
![Screen Shot 2022-10-23 at 17.17.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/298e887e-a00a-e3c8-0dbb-e1bba47dc8d5.png)

綺麗にフォーマットされました！
![Screen Shot 2022-10-23 at 17.18.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/2e220656-38cc-ae6d-f45e-bdd4f7fb4c0f.png)

ノートブック全体をフォーマットするには**編集 > ノートブックをフォーマット**を選択します。
![Screen Shot 2022-10-23 at 17.19.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/68dc1f9e-f385-cefc-b118-2e37b2c1ad2e.png)

フォーマッターを用いることで、共通のコード規約を強制できるとチーム間でのコード共有が捗ると思います。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
キャッシュで2度目以降の処理速度を上げる(SPSS Modeler データ加工逆引き9-5)

# キャッシュで2度目以降の処理速度を上げる

![スクリーンショット 2022-10-18 9.54.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/b7993fa1-5280-b897-b9c0-9876e84816be.png)

## 1.想定される利用目的

・大規模なCSVなどのフラットファイルを入力にした際のデータ加工速度の向上


## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/blob/main/cache.str?raw=true

## 3.サンプルストリームの説明

![スクリーンショット 2022-10-18 10.49.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/eb65d762-dfe1-92f9-c5b2-4862c1ccad30.png)

a.入力するデータのひとつ目です。6種類のカテゴリーと値が100万レコード（行）生成されます。
![スクリーンショット 2022-10-18 10.05.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/be9fdbf2-f656-cdca-ac85-3bf8928124e4.png)

b.入力ふたつ目はカテゴリの重みマスタです。
![スクリーンショット 2022-10-18 10.06.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/957618b4-011f-a7b0-c8a1-9cc041ec16cb.png)

c.[レコード結合]ノードを編集します。ふたつの入力データを[Cate]をキーに内部結合します。
![スクリーンショット 2022-10-18 10.07.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/1a3c6f16-6330-05c3-12b3-878b0a4fc158.png)

d.[フィールド作成]ノードを編集します。値に重みを掛けます。
![スクリーンショット 2022-10-18 10.07.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/099d9a89-954a-f054-5098-f7286679d3cf.png)

[プレビュー]します。
![スクリーンショット 2022-10-18 10.08.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/3677608c-1d08-ebac-4769-5b59d8c45e35.png)

e.[レコード集計]ノードを編集します。
![スクリーンショット 2022-10-18 10.08.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/f22d1524-3080-6a86-882f-9680d9b49ba9.png)

[レコード集計]ノードを右クリックして[キャッシュを使用する]を選択します。
![スクリーンショット 2022-10-18 10.09.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2cc0636c-59d2-99b7-176d-9e5b2723d6ad.png)

[レコード集計]ノードに白いバッジがつきました。
![スクリーンショット 2022-10-18 10.10.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/9ff23350-c876-d6bd-400c-983ef763df59.png)

f.[テーブル]を実行します。バッジが緑に点灯しました。
![スクリーンショット 2022-10-18 10.11.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/af2d78c4-6ce9-f5e7-8183-b54519d1b288.png)

メモリ16GBのMacで28秒処理に時間がかかりました。
![スクリーンショット 2022-10-18 10.12.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/0c546095-63d0-c1f4-5a6c-6e5b7a4d2db5.png)

もう一度[テーブル]実行します。レコード集計段階でキャッシュされているため1秒かからずテーブルが表示されます。後続処理が続く場合には時間の短縮が期待できます。
![スクリーンショット 2022-10-18 10.12.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/1189762c-f65e-b857-f5a0-39f6d211e20e.png)

#### 注意事項

後続でもキャッシュを利用すると全体としてメモリ超過になるため適宜不要なキャッシュは[キャッシュを使用しない]で解放します。またストリームが完成してバッチ化される際には全てキャッシュは不要です。
![スクリーンショット 2022-10-18 10.18.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/9d2b5e56-b14d-3321-2a1a-fe2e3363f404.png)

キャッシュを中間ファイルとして[保存]して、次回の作業で呼び出（[ロード]）して再利用することも可能です。SPSS形式であるため圧縮率が高いメリットがあります。もちろん明示的に中間ファイルを作成していただいても結構です。


## 4.参考情報

#### キャッシュを解説した記事

https://www.ibm.com/blogs/solutions/jp-ja/modeler-tips-01/

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
GithubPages（.github.io）にWindowsPCでReactを使ってデプロイする方法

↓このページを参考にして
デプロイしようとしていたんですがMacのようで、うまくいかなかったので、Windowsユーザーの場合を書いてみます。

https://qiita.com/tat_mae084/items/745761eee6cd1d42949d

　
　

##### 多分Macとはコマンドが違うんだろうと思います。

```React:package.json
"dependencies": {
    "homepage": "https://＜Githubアカウント名＞.github.io/＜リポジトリ名＞/"
},

"scripts": {
    "del": "del -rf docs",
    //"del": "cmd /c rd /s /q docs",　かもしれない?
    "move": "move build docs",
    "git": "git add . && git commit && git push origin master",
    "deploy": "npm run del && npm run build && npm run move && npm run git"
}
```

↑このように書き加えて
　

```Terminal:Terminal
npm run deploy
```

をするとアップロードはされてました。
　
でも、「-rfってなに？」みたいなエラーが出たりしていたので、違う書き方をしたほうがいいのかもしれませんがわかりません！！
　
わかる方教えてください。
　

## 追記

再度修正したものをデプロイしようとして上の方法で試していたら
編集結果が反映されなかったので追記します。

##### ▶前回は、
「npm run deploy」の前に、mainブランチに「npm build」で生成されたコードをアップロードしていました。
でも、サイトに反映されなかったので「おや？」となって上の方法にいきつき、「npm run deploy」後にサイトも反映されてやれやれってなっていました。

なぜ、再度上の方法でやって反映されなかったのかはわかりません。が、

##### ▶今回は、
リモートのmainブランチにbuildフォルダの中身を**手動アップデート**することで反映された。
ということがありましたので書いておきます！
　
　
結局mainブランチの情報が表示されるのだろうか・・・。
謎すぎる(;'∀')
【Docker】Rails 6系 x Docker x MySQL 8で環境構築してみた

## 条件
- docker-compose upでrails serverを起動できるようにすること
- ホストのファイルシステムとコンテナのファイルシステムを同期させること
## 1. 各種ファイル作成
任意のディレクトリファイル配下に以下のファイルを作成します。
```
$ mkdir docker-files
$ cd docker-files
```
- Dockerfile
- docker-compose.yml
- Gemfile
- Gemfile.lock

それぞれのファイルの中身を書いていきます。
### Dockerfile
```dockerfile
FROM ruby:2.6
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
    echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
    apt-get update -qq && apt-get install -y \
    build-essential \
    nodejs \
    yarn && \
    mkdir /docker-files

WORKDIR /docker-files
COPY Gemfile /docker-files/Gemfile
COPY Gemfile.lock /docker-files/Gemfile.lock
RUN bundle install
COPY . /docker-files

RUN rm -f tmp/pids/server.pid

CMD ["rails", "server", "-b", "0.0.0.0"]
```
【注意】rails 6.0 からデフォルトJavaScriptコンパイラが webpackerに変更されました。

### docker-compose.yml

```yml
version: '3'
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
    ports:
      - '3306:3306'
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - mysql-data:/var/lib/mysql
  web:
    build: .
    volumes:
      - .:/docker-files
    ports:
      - "3000:3000"
    depends_on:
      - db
    stdin_open: true
    tty: true
volumes:
  mysql-data:
    driver: local
```
デフォルトのドライバーのlocalは、その名の通り、ホストのローカルのファイルシステムに
ボリュームを作成するものです。
### Gemfile
```
source 'https://rubygems.org'
gem 'rails', '~>6'
```
### Gemfile.lock
空ファイルのまま。
## 2. rails newでフレーム作成
上記４つのファイルが作成できたら、以下のコマンドを実行します。
```
$ docker-compose run web rails new . --force --no-deps --database=mysql --webpacker
```
--webpacker オプションで webpacker をインストールします。
## 3. イメージのbuild
上記コマンドで各種ファイルの作成が完了したら、Gemfile が更新されているので、イメージをビルドします。
```
$ docker-compose build
```
## 4. config/database.ymlの変更
```yaml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch("MYSQL_USERNAME", "root") %>
  password: <%= ENV.fetch("MYSQL_PASSWORD", "password") %>
  host: <%= ENV.fetch("MYSQL_HOST", "db") %>

development:
  <<: *default
  database: docker-files_development

test:
  <<: *default
  database: docker-files_test

production:
  <<: *default
  database: docker-files_production
  username: docker-files
  password: <%= ENV['DOCKER-FILES_DATABASE_PASSWORD'] %>
```
## 5. データベース作成
```
$ docker-compose run web rake db:create
```
## 6. コンテナ起動
```
$ docker-compose up
```
localhost:3000 にアクセスします。
http://localhost:3000/
![スクリーンショット 2022-10-22 22.45.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1961802/3630f735-a5d1-6a34-32ad-7d607752afaf.png)
無事環境構築できました🎉🎉

## 7. githubで共有
こちらはおまけですが、githubにこのようなdockerで構築したディレクトリをpushしておくと、下記のコマンドで誰でも同じ環境を構築できます！
```
$ git clone https://github.com/[ユーザー名]/[リポジトリ名].git
$ cd [リポジトリ名] 
$ docker-compose run web rails db:create 
$ docker-compose up
```

## 最後に
dockerを学んで、誰でも同じ環境を構築できるという点に非常に感動を覚えました。これまで環境構築にかなりの時間を費やしていたため、非常に助けられることとなりました。とは言っても、まだまだdockerの修行が必要だなと感じます。見ていただきありがとうございました！
### 参考にしたサイト
- https://qiita.com/nsy_13/items/9fbc929f173984c30b5d
テーブル作成したのにphpMyAdminに表示されない

## 開発環境
Laravel 9.36.3
PHP 8.1.4
XAMPP 8.1.6
phpMyAdmin 5.1.1
MariaDB 10.4.21

## 状況
 1.phpMyAdmin上で任意のアプリ名のデータベース作成
 2.laravelでアプリ新規作成
 3.ターミナルでphp artisan migrate実施後、マイグレートできていることを確認
 4.phpMyAdminでテーブルができていないことを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365570/817bb87d-372a-7282-7b26-0f89c6f0ecd8.png)

## 対処法
1 .マイグレートは成功しているのにテーブルができていないということで、
XAMMPとアプリの連動ができていない（=XAMMPとソース上のポート番号が一致してない）可能性があるので、
まずはXAMMP側のMysqlのポート番号を確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365570/2dc50c53-5676-650f-30ec-b9f1d7cecabf.png)

2 .次に.envのデータベースのポート番号を確認。XAMPPに合わせる形で変更。
```.env
（変更前）
DB_PORT=3306

（変更後）
DB_PORT=3360

```
 3.再びターミナルでphp artisan migrate実施後、マイグレートできていることを確認

 4.phpMyAdminでテーブルができていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365570/1b93bc26-b95d-6cfc-bf97-7620871a206a.png)

## 参考資料
https://qiita.com/te-k/items/1f2deddb6808afca2f2b
https://stackoverflow.com/questions/31574722/how-to-connect-to-mysql-database-on-port-3308-using-laravel-framework-5-1
twitterアカウント作成時の認証(画像)について

Titterのアカウント(readonly=つぶやかずに見る/検索するだけ)を作成したのだが...

画像認証(botじゃないことの証明)がわけわからなかったので解説。

「同じアイコンが上を向いたサイコロのペアを選んでください」
E:「Pick the dice pair with the same icon facing up」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/48c5f3ba-9d93-8f53-c34c-50ff4087710d.png)
最初文章が何意味しているかが分からず、強制的に英語にしてみてもやはりわからなかった

で、どういうことかというと、
「1つの画像の中に、同じアイコンが複数入っている、画像を選ぶ」(上記の赤で囲ったもの)
ということ。
そもそも英語の時点でちょっとわかりにくい。ただ、冷静に考えてみると英語の方がちょっと意味を取りやすいか。「ダイスペアを選べ、同じアイコン(目)が上を向いている」という感じで。
これ、どうやらtwitterの他にdropboxやgithubでも出されている模様。「わからない」という声がtwitterそのもの以外でなかなか出てこない、というのがなんだかな。なお、「画像認証ができない」ではなく「私人間なのにわからない」といった文面でアップ/発言している例が多い模様。
あの、せっかくネットに乗せるならば他人にわかりやすい、検索で乗りやすい表現にしていただけると後発にとってわかりやすくありがたいのですが...



近年はググってもduckっても欲しい情報が出てこないことが多数、確かに検索エンジン側が糞サイトの排除に追いついていないというのもあるでしょうが、それとともに検索エンジン側が文面、単語から勝手に内容を推測して勝手に変えてしまうという側面もあるのでは。いや、そんなこと頼んでもないしはっきり言って迷惑ですし、情報操作か、とすら思ってしまう昨今です。
Springの @Scheduled について

# 概要

Springが提供している [@Scheduled](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html)について調べたので、そのメモを残す。

下記のversionで検証を行った。
- Java17(Corretto 17.0.5)
- SpringBoot2.7.5

検証コードは下記に格納している。
https://github.com/nannany/spring-scheduled

# `@Scheduled`とは？

`@Scheduled`アノテーションをメソッドに付与することで、メソッドの定期的な実行を行うことができる。
例えば、下記のようなメソッドは`fixedRate_withTimeUnit`という文言を1分ごとに標準出力する。
```java
    @Scheduled(fixedRate = 1, timeUnit = TimeUnit.MINUTES)
    public void fixedRate_withTimeUnit() {
        logger.info("fixedRate_withTimeUnit");
    }
```

# `@Scheduled`を有効にするには？

`@Scheduled`を有効にするには、下記のように`@Configuration`が付与されたクラスに、`@EnableScheduling`を付与してやれば良い。([参考](https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-enable-annotation-support))
```java
@Configuration
@EnableScheduling
@ComponentScan(basePackages = "com.example.demo.tasks")
public class EnableSchedulingConfig implements SchedulingConfigurer {
  ...
```

# `@Scheduled`の機能

`@Scheduled`でメソッドの定期的な実行を行うことができるが、実行タイミングの指定方法は複数ある。

## fixedRate

`fixRate`を用いた指定方法では、シンプルな定期実行が可能である。
下記のメソッドのように指定した場合、5秒ごとに `fixedRate`という文言がログに吐き出される。

```java
    @Scheduled(fixedRate = 5000)
    public void fixedRate() throws InterruptedException {
        Thread.sleep(1000);
        logger.info("fixedRate");
    }
```

fixedRateで指定する値はデフォルトでミリ秒であるが、timeUnitによって指定することが可能である。
```java
    @Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS)
    public void fixedRate_withTimeUnit() {
        logger.info("fixedRate_withTimeUnit");
    }
```

## fixedDelay

`fixedDelay`では、該当のメソッドが終了してから指定した時間経った後に再度メソッドが実行される。
例えば、下記の場合だと6秒ごとに `fixedDelay`という文言が出力される。
途中でsleepしているため、メソッドの実行には1秒かかり、その完了の後の5秒後にメソッドが再度実行されるため、6秒ごとのログ出力となる。

```java
    @Scheduled(fixedDelay = 5000)
    public void fixedDelay() throws InterruptedException {
        Thread.sleep(1000);
        logger.info("fixedDelay");
    }
```

## cron

`cron`ではいわゆるcron式による定義が可能となる。
下記の例だと、5秒ごとに `cron`　をログ出力する。ちなみにタイムゾーンの指定も可能である。(下記の例だと意味をなしていないが)
```java
    @Scheduled(cron = "*/5 * * * * *", zone = "Asia/Tokyo")
    public void cron() {
        logger.info("cron");
    }
```


# ランタイムで次回実行を決めたいとき

`@Scheduled`ではアプリケーションコンテキスト生成時に実行間隔が決定するため、ランタイム時に次回実行を決定したい時には `ScheduledTaskRegistrar` をいじってやる必要がある。

下記の例だと、 `cumstom scheduler`という文言が 1~5秒ごとにログ出力されるようになる。
```java
    @Bean
    public Executor taskExecutor() {
        return Executors.newSingleThreadScheduledExecutor();
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());

        taskRegistrar.addTriggerTask(
                () -> logger.info("custom scheduler"),
                triggerContext -> {
                    Random random = new Random();
                    Date date = new Date();
                    return Date.from(date.toInstant().plusSeconds(random.nextInt(5) + 1));
                }
        );

    }

```

# 参考

https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling
https://www.baeldung.com/spring-scheduled-tasks
E: Package 'libqt4-dev' has no installation candidate と E: Package 'ipython' has no installation candidate の問題を解決しちゃうわよ！

```
cd ~/torch; bash install-deps;
```
pix2pixをPytorchでやっちゃおうと思ってる人は、このコマンド打つと思うんだけど、あたしはこんなエラー出たのよ。
```
Hit:1 http://jp.archive.ubuntu.com/ubuntu focal InRelease
Hit:2 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64  InRelease                  
Hit:3 http://jp.archive.ubuntu.com/ubuntu focal-updates InRelease                                            
Hit:4 http://jp.archive.ubuntu.com/ubuntu focal-backports InRelease                                          
Hit:5 http://security.ubuntu.com/ubuntu focal-security InRelease                           
Hit:6 http://archive.canonical.com/ubuntu focal InRelease  
.
.
.
.
.
Reading state information... Done
Note, selecting 'git' instead of 'git-core'
Note, selecting 'libncurses-dev' instead of 'ncurses-dev'
Package libqt4-dev is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

Package ipython is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'libqt4-dev' has no installation candidate
E: Package 'ipython' has no installation candidate

```
まぁ瞬殺だわよ。
これして頂戴。ただし、Ubuntu20.04の人に限るわ。他のバージョンの人はこのサイト参照して頂戴ね。
https://ubuntuhandbook.org/index.php/2020/07/install-qt4-ubuntu-20-04/
```
sudo add-apt-repository ppa:rock-core/qt4

次に /etc/apt/sources.list の最後にこの３行を加えちゃいましょう。

'''
deb http://archive.ubuntu.com/ubuntu bionic main universe deb
http://archive.ubuntu.com/ubuntu bionic-security main universe
deb http://archive.ubuntu.com/ubuntu bionic-updates main universe
'''
```
書くときはお好きなエディタでいいわよ♡
あたしはViが好きだからViでやったわ。

さて、もう終わりよ。やっておしまいなさい！
```
cd ~/torch; bash install-deps;
```
終わり。
Pythonのpandas-datareaderを使って経済指標などの金融データを取得する方法

　基本的にJupiter Notebookを使うことを想定しています。専門家のような高度なプログラミングスキルはないのでご承知おきください。
# コードを書く前に…
## pandas-datareaderのインストール
　pandas-datareaderというライブラリをインストールします。pandasとは別ものなのでpandasをすでに持っている人も新たにインストールしてください。
```
pip install pandas-datareader
```

## 取得しにいくWebサイトについて
　FREDというサイトからデータを取得します。→ https://fred.stlouisfed.org/

# 米国の雇用統計を取得する
　まず必要なものをインポートして、
```py
import pandas as pd
import datetime as dt
import pandas_datareader.data as web
```
　今回は2013年1月から2022年1月までの米国非農業部門雇用者数をpandasのデータフレームで受け取るようにします。
```py
start = dt.date(2013,1,1)
stop = dt.date(2022,1,1)

df = web.DataReader('PAYEMS', 'fred', start, stop)
```
　実行して中身を確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/819fddb5-6acf-4569-7b77-2d0f50327281.png)
うまく取得できました。DataReader()の引数には、欲しいデータのシンボルコード、取得先(今回は'fred')、開始期間、終了期間を入れます。
　
　では次に取得したデータをグラフにします。グラフ作成のためのmatplotlibをインポートしておいてください。
```py
import matplotlib.pyplot as plt
%matplotlib inline
```
　データフレームのインデックスが日時データになっているので、そのままグラフの横軸にして…
```py
plt.plot(df.index, df['PAYEMS'])
plt.show()
```
　実行すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/ced00d9d-16ff-cf92-874f-e37c72c8c2b2.png)
　うまく表示できましたね。ちなみにグラフの途中に崖みたいな箇所があるのは「2020年のコロナショック」で大量に失業者がでたことを示しています。

# 雇用統計以外のデータを取得するには
　DataReader()の引数の「欲しいデータのシンボルコード」を変更すればFREDが提供してくれているデータなんでも引っ張ってこれます。

シンボルコードはここから調べられます。
https://fred.stlouisfed.org/categories
 
 
 
　ここから下、個人的によく使うシンボルコードを適当に書いておきます。
### 「株価」
ダウ平均:DJIA
S&P500:SP500
ナスダック:NASDAQ100
日経225:NIKKEI225

### 「金利」
米10年債利回り日足:DGS10
米10年債利回り月足:GS10
米10年債利回と米3ヶ月債利回の差:T10Y3M
米10年債利回と米2年債利回の差:T10Y2Y
米政策金利目標上限値:DFEDTARU
米政策金利目標下限値:DFEDTARL
フェデラルファンド実効金利:DFF

日本10年債利回り月足:IRLTLT01JPM156N
日本10年債利回り月足:IRLTLT01JPM156N

### 「経済指標」
米非農業部門雇用者数:PAYEMS
米失業率:UNRATE
米GDP成長率:A191RL1Q225SBEA
米名目GDP:GDP
米実質GDP:GDPC1
米消費者物価指数:CPALTT01USM659N
米新規失業保険申請件数:ICSA

日本実質GDP:JPNNGDP

### 「貿易」
米国対日輸出額:EXPJP
米国対日輸入額:IMPJP
日本向輸出:XTEXVA01JPM667S
日本向輸入:XTIMVA01JPM667S

### 「その他」
米M2マネーストック:M2REAL
RやDenoをPythonのオブジェクトのように使ってみた

※ この記事は、単なる遊びです。こんな事も出来るんだよーってことです。
# 何をしたのか
ある日、ふと「pythonでRを書きたい！」と思ったので一筆書いてみました。
下記のようなコードで動くように出来ると思いついて、実際にやってみました。

```python
from ninter import Deno, R, Bridge

r = Bridge(R())
deno = Bridge(Deno())

t_test = r['t.test']
deno.let.something = list(range(5))
a = deno.something.map(deno['x=>x*4'])
b = [2, 3, 4, 5]

result = t_test(a, b)['p.value']
print(result.to_python())
>>> 0.1892226
```

お分かり頂けただろうか？
DenoとRのオブジェクトがあたかもpythonのオブジェクトであるかのように振る舞っています。


# pyperじゃ駄目なんですか？
駄目じゃないです。むしろpythonでRを扱うならpyperは鉄板でしょう。だけど、pyperはRのコードをpythonの文字列として渡す必要があります。


# Pythonの暗黒面
Pythonを使っているので、例えば[]とか.とかの挙動は細かく設定できるのです。こういうのが僕のような素人にできてしまう。この自由度は暗黒面ですね。

# 公開しているの？
どうせ需要もないけれど、もう少し遊んだらするかも知れません。
Electron+Vite(Electron, React)でHMR環境を用意する。


# できたもの
https://github.com/satoc0629/ts_electron_on_vite_template
テンプレートプロジェクト。
一応、Windows、Macそれぞれでビルドもできた。
## 構成
### パッケージ管理
https://pnpm.io/ja/
### バンドル、ビルド
https://ja.vitejs.dev/

## 満足ポイント
ルートからpackage.jsonで1コマンド起動するだけで、Electron側と画面（React）側のViteによる[HMR](https://ja.vitejs.dev/guide/features.html#hot-module-replacement)を活用できるようにした。

## 参照サイト
https://zhuanlan.zhihu.com/p/377697508
https://zhuanlan.zhihu.com/p/497638546
こちらのサイトの記事をベースに作成

# 構成に至るまで
参照サイトを丸パクリした構成を用意する。
それで問題なく構築できる方もいるかも・・・。
## 参照サイトのアイディア
Renderer側は、React+Viteでポート固定で起動する。
Electron側は、これに対してloadURLを行う。
Electron側は、NodeJSのHMRは対応していないため、プラグインを自作し、処理を適用する。
### Electron HMR
インラインPlugin部分を以下のように記述。
```javascript
{
            name: 'vite-plugin-electron-main-starter',
            // 最初のコンパイル、リコンパイル後にトリガーされます。
            writeBundle() {
                if (electronProcess) {
                    // 現在実行中のエレクトロンプログラムを終了させてからリブートする。
                    electronProcess.kill()
                }
                // スタート、リスタートエレクトロン
                electronProcess = spawn(
                    // オフィシャルエレクトロンに相当する . 起動方法
                    electronPath,
                    ['../dist/main/main.cjs'],
                    {
                        stdio: 'inherit'
                    })
            },
        }
```
### watch.mjsでelectronの起動
参照サイトの記事では、viteのbuildおよびpluginで有効となる記述だが、うまく動かず原因究明も難しかったため、以下で代替した。
子プロセスを起動する部分は同じ。
watch.mjs内でviteのbuildを直接呼び出すのはやめた。
代わりに、コマンドベースでelectron_srcのpackage.jsonからviteのbuild(watch付き）を起動し、インラインpluginのelectronの起動につなげる形とした。

```javascript
import {spawn} from 'child_process'
import {createServer, build} from 'vite'

// ---- レンダリング処理部 ----
const server = await createServer({configFile: 'renderer/vite.config.ts'})
await server.listen()
console.log(`renderer process port:${server.config.server.port}`)

// ---- メインプロセス部 ----
const electronProcess = spawn("pnpm", ["--prefix", "electron_src/", "build"], {stdio: 'inherit'})
console.log(`electron process start.`)

electronProcess.on("open", () => {
    electronProcess.stderr.on('data', data => {
        console.error(data.toString())
    })
    electronProcess.stdout.on('data', data => {
        console.log(data.toString())
    })
})

```

## ディレクトリ構成
```console
.
├── LICENSE
├── README.md
├── dist
├── electron_src
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── src
│   │   ├── main.ts
│   │   └── vite-env.d.ts
│   ├── tsconfig.json
│   ├── vite.config.static_build.ts
│   └── vite.config.ts
├── package.json
├── pnpm-lock.yaml
├── renderer
│   ├── index.html
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── public
│   │   └── vite.svg
│   ├── src
│   │   ├── App.css
│   │   ├── App.tsx
│   │   ├── assets
│   │   │   └── react.svg
│   │   ├── index.css
│   │   ├── main.tsx
│   │   └── vite-env.d.ts
│   ├── tsconfig.json
│   ├── tsconfig.node.json
│   ├── vite.config.static_build.ts
│   └── vite.config.ts
└── scripts
    ├── build.mjs
    └── watch.mjs


```
Google Apps Scriptでblastengineを使ってメール送信を行う（テキストメール）

[blastengine](https://blastengine.jp/)はシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先に届くようになります。

今回は今開発中のGoogle Apps Script用SDK（以下GAS SDK）を使ってメール送信を行う方法を紹介します。

## コードについて

GAS SDKはMIT Licenseのオープンソース・ソフトウェアです。リポジトリは以下にあります。

[blastengineMania/blastengine-gas: Google Apps Script向けのblastengine SDKです](https://github.com/blastengineMania/blastengine-gas)

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。

![getting-started-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/5c6c8cb0-9ad1-0a6d-88fe-e24bc3ee7b17.jpeg)


## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/78a4eeb3-4649-149f-8246-44f83d03a0cf.jpeg)


そして設定の中で、APIキーを取得します。

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/d21fc4e3-36f0-6f5c-23e3-8c675e16f538.png)

## ライブラリIDについて

GASのライブラリIDは `1GvJKygDvrhoq9w1FIRepBo1kAB3yo1LucHtL6CIM-KqmaFaxLUbyBdim` になります。こちらをGoogle Apps Scriptのエディタにて、ライブラリとして登録してください。

```
1GvJKygDvrhoq9w1FIRepBo1kAB3yo1LucHtL6CIM-KqmaFaxLUbyBdim
```

![blastengine-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/cf753e3b-99e8-14c7-b745-80bf7b44c1b9.jpeg)


今回はIDを `Blastengine` として解説します。変更している場合はそれぞれ読み替えてください。

## 初回実行時の注意

初回実行時には外部URL（blastengineのAPI）にアクセスを許可するダイアログが出ます。なお、この時に以下のような怖いダイアログが出ます。

![blastengine-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/adda2f6e-6fe6-c8ee-d73e-d266f9343fb5.jpeg)


これはインストール数が増えると消えるらしいのですが、まだ作成したばかりのため表示されてしまうようです。左下にある詳細というリンクから許諾を続行できます。

## 初期化

先ほど取得したユーザー名とAPIキーを使って初期化します。

```js
Blastengine.init('YOUR_USER_NAME', 'YOUR_API_KEY');
```

## メールオブジェクトの用意

blastengineでは即時配信されるトランザクションメールと、一括配信のバルクメールがあります。執筆時点（2022年4月現在）では、SDKはトランザクションメールのみ対応してます。

```js
const transaction = Blastengine.transaction();
```

## 配信元、配信先を設定

件名や宛先などをセットします。

```js
transaction.fromEmail = 'info@example.com';
transaction.setTo('user@example.jp');
transaction.subject = 'Test subject';
transaction.setText('Test body');
```

## 送信する

送信を実行します。GASなのでネットワーク処理は同期になります。

```js
const res = transaction.send();
```

結果の `res` には、デリバリーIDが入ってきます。このIDを使って配信状況を確認できます。

```js
console.log(res);
// { delivery_id: 188 }
```

## まとめ

GAS SDKを使えばスプレッドシートからメールを一括配信したり、Googleフォームから個人ではないFromを使って返信できます。Gmailでは1日の配信件数に限界がありますが、blastengineを使えばそういった心配は無用です。

ぜひblastengineをお試しください！

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)
ServiceNow-Tokyoリリースの機能アップデート17選（記事記載は1－9のみ）

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/0f204545-8f78-4e47-6753-563ee37e02df.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/c83d1922-1cd4-336e-cbb1-13d6e9cb419c.png)

## 参考
上記のようなServiceNow関連や在学中の放送大学・情報工学コースでの学びを
[技術語り（自分のブログ）](https://tech-software-tokyo.blogspot.com/2022/10/servicenow-tokyo17.html)
内にて記載していますので’よければそちらもご確認ください。
ブランチ名を修正したい場合の対処法（ローカルの場合）

# はじめに
Git操作で、誤ったブランチ名で作成してしまった時に、正しいブランチ名へ修正する方法をまとめました。

# 背景
実装に入ろうと思って、ブランチを作成したときに、「あ、誤字でブランチを作ってしまった・・・」時があると思います。（自分もありました・・・）
その時に調べて修正した方法を、以下にまとめました。

:::note warn
今回はリモートにあげる前、つまりローカルのブランチ名を修正する作業となります。
リモートのブランチ名を修正する場合は別の方法が必要になります。
:::

# コマンド
```shell:ターミナル
% git branch -m 修正したいブランチ名 新しいブランチ名
```

上記のコマンドを実行すると、修正したいブランチ名が、新しいブランチ名へと変更になります。
既に修正したいブランチにいる場合は、以下のコマンドでも対応可能です。

```shell:ターミナル
% git branch -m 新しいブランチ名
```

# おわりに
ブランチ名の修正はコマンド1つで実行できるので、驚きでした。
これからもわからないことを、まとめていこうと思います。

記事をご覧いただき、ありがとうございました。
[Ruby]バイナリーサーチとは

ruby の問題を解いていたところ
躓きましたので備忘録として残します。

# バイナリーサーチとは？
ソート済みのリストや配列に入ったデータ（同一の値はないものとする）に対する検索を行うときに用いられる手法です。
まず、中央の値を確認し、検索したい値との大小関係を用いて、検索したい値が中央の値の右にあるか、左にあるかを判断します。
それを繰り返し、片側には存在しないことを確かめながら検索していく方法です。

・・・理屈ではわかります。ただ、それをコードでどのように記述すればよいのか？

# 回答
※配列の上限である32以上の値による検索は想定しないものとする
※検索はバイナリーサーチ（2分割検索）を使用して行う

```ruby
１回目のループ
def binary_search(array, right, target)　 #=> right=配列の数、target=26
  left = 0
  while left <= right
    center = (left + right) / 2
    if array[center] == target　#=> array[5]=10 なのでここには当てはまらない
      return center
    elsif array[center] < target　#=> 10<26　なのでここの処理が実行される
      left = center + 1　　#=> left=6　となり、２回目のループに入る
    else
      right = center - 1
    end
  end
  return -1 #=>何も当てはまらないときの返り値
end

array=[1,3,5,6,9,10,13,20,26,31]

target = 26
number_of_elements = array.length #=> 配列の数

result = binary_search(array, number_of_elements, target)
```
```ruby
２回目のループ
def binary_search(array, right, target)　 #=> right=配列の数、target=26
  left = 0　　#=> こちらに１回目の数字６が入ります。
  while left <= right
    center = (left + right) / 2 #=> （6+10）/2 = 8
    if array[center] == target　#=> array[8]=26 なのでここの処理が実行されます
      return center
    elsif array[center] < target　 
      left = center + 1　
    else
      right = center - 1
    end
  end
  return -1
end

array=[1,3,5,6,9,10,13,20,26,31]

target = 26
number_of_elements = array.length #=> 配列の数

result = binary_search(array, number_of_elements, target)

if result == -1
  puts "#{target}は配列内に存在しません"
else
  puts "#{target}は配列の#{result}番目に存在します "
end
```

よって、「26は配列の８番目に存在します」が表示されます。 
※配列は０からスタートします。

returnにたどりつくまで、繰り返します。
paiza.ioでelixir その4

# 概要
paiza.ioでelixirやってみた。
湯婆婆やってみた。

# サンプルコード

```
defmodule Main do
    def ybb(name) do
        IO.puts "契約書";
        IO.puts "甲は油屋当主として、乙を油屋に雇用することを契約し、";
        IO.puts "労働に伴う対価の支払いを右の通り、約定する。";
        IO.puts "なお、一日の労働の対価は金百円とする。";
        IO.puts "甲　油屋当主　湯婆婆";
        IO.puts "";
        IO.puts "乙";
        IO.puts "契約書だよ。そこに名前を書きな。"
        IO.puts "フン。#{name}というのかい。贅沢な名だねぇ。"
        index = :rand.uniform(String.length(name))
        new_name = String.slice(name, index - 1, 1)
        IO.puts  "今からお前の名前は#{new_name}だ。いいかい、#{new_name}だよ。分かったら返事をするんだ、#{new_name}!!"
    end
    def main do
        name = IO.read(:line) |> String.trim()
        ybb(name)
    end
end

Main.main
```

# 実行結果

```
契約書
甲は油屋当主として、乙を油屋に雇用することを契約し、
労働に伴う対価の支払いを右の通り、約定する。
なお、一日の労働の対価は金百円とする。
甲　油屋当主　湯婆婆

乙
契約書だよ。そこに名前を書きな。
フン。工藤静香というのかい。贅沢な名だねぇ。
今からお前の名前は工だ。いいかい、工だよ。分かったら返事をするんだ、工!!
```

# 成果物

https://paiza.io/projects/F6LpdtGnlVxb_-w12NJOnQ?language=elixir


以上。
Unityで保存したプレハブにショートカットで飛べる機能を作った

## ソースコード

```
using System;
using UnityEditor;
using UnityEngine;

public class SelectLastSavedPrefab
{
    private const string SavePrefabKey = "save_prefab_key";

    [MenuItem("SavePrefabPath/LoadAsset #&p")]
    private static void SelectLastSelectPrefab()
    {
        try
        {
            var loadAssetGUID = PlayerPrefs.GetString(SavePrefabKey);
            var assetPath = AssetDatabase.GUIDToAssetPath(loadAssetGUID);
            var TargetAssets =
                AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
            Selection.activeObject = TargetAssets;
        }
        catch (Exception e)
        {
            Debug.LogError(e);
        }
    }

    [MenuItem("SavePrefabPath/LoadAsset #&l")]
    private static void SaveLastSelectPrefab()
    {
        try
        {
            var selection = Selection.assetGUIDs[0];
            var assetPath = AssetDatabase.GUIDToAssetPath(selection);
            var TargetAssets =
                AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
            if (TargetAssets == null)
            {
                Debug.LogWarning($"{assetPath} is Not GameObject!");
                return;
            }

            PlayerPrefs.SetString(SavePrefabKey, Selection.assetGUIDs[0]);
            PlayerPrefs.Save();
        }
        catch (Exception e)
        {
            Debug.LogError(e);
        }
    }
}
```

## 使い方
- プレハブの参照のセーブ
  - mac
    - Shift + Option + L
  - windows
      - Shift + Alt + L

- プレハブの参照のロード
  - mac
    - Shift + Option + P
  - windows
      - Shift + Alt + P

もしくはメニューから開けます!
![メニュー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49946/dc4a0fd1-fbae-f128-9eac-482ba1954df9.png)



## これを使うシチュエーション
作業をしていてプレハブの更新をした後に、作業していたプレハブに戻るのがちょっとだけ楽になれます
SpringBoot × AWS SDK for Java v2 × kotlin × DynamoDBで詰まった色々まとめ

kotlinで公式サンプルがなく結構詰まったのでまとめてます。
そのうちサンプル書いて公開予定ですが、それまでの備忘メモも兼ねて投稿します

```
"java.lang.IllegalArgumentException: Class 'class xxxxxxxxxx' appears to have no default constructor thus cannot be used with the BeanTableSchema
```

`@DynamoDbBean`のアノテーションをつけたクラスにデフォルトコンストラクタがない。
デフォルト引数を設定して解消。

```
"java.lang.IllegalArgumentException: Attempt to execute an operation that requires a primary index without defining any primary key attributes in the table metadata.
```

上記のdata classにセッターがない。
`val`を`var`にして解消

```
software.amazon.awssdk.services.dynamodb.model.DynamoDbException: One of the required keys was not given a value (Service: DynamoDb, Status Code: 400, Request ID: xxxxxxxxxxxx)
```

@get:DynamoDbAttribute("カラム名")をつけて解消

```
java.lang.ClassCastException: class xxxxxxxxxx cannot be cast to class xxxxxxxxxxx 
(xxxxxxxxxx is in unnamed module of loader 'app'; 
```

spring-dev-toolsを無効化して解消。
どうやら、上記使用するとクラスローダが2つ起動するらしく、別のクラスローダで読み込まれていたため、クラスが見つからないと言われていたようでした。

https://stackoverflow.com/questions/61556638/springboot-java-aws-sdk-2-dynamodb-enhanced-client-and-devtools-problem/64350067#64350067

## BatchWriteで一部レコードがたまに欠損する

BatchWriteを用いる場合はレスポンスの`UnprocessedItems`を見て、対象レコードのリトライ機構を自前で実装する必要がある。(SDK側でよしなにはやってくれない)

ちなみに、PutItemなど一つのレコードに対する処理は8回までデフォルトでリトライしてくれる機構が入っているようでした。

https://github.com/aws/aws-sdk-java-v2/blob/master/services/dynamodb/src/main/java/software/amazon/awssdk/services/dynamodb/DynamoDbRetryPolicy.java#L39
【Java初心者向け①】Javaインストールから実行

## javaのインストールから実行までを簡単なコードを作成して試した際のメモ
## 環境
- Windows10,11
- Java 19.0.1

## 流れ
- Javaのインストール
- 環境変数の設定
- プログラム作成
- プログラム実行


## Javaのインストール

まずはJavaの「Java JDK」をダウンロードします。


#### 補足
- Java JDK（Java JREが含まれている）
プログラミング・開発に必要なもの
- Java JRE
Javaを実行時にひつようなもの

下記のダウンロードページにて、「x64 Installer」をインストールします。

ダウンロードページ
https://www.oracle.com/jp/java/technologies/downloads/#jdk19-windows

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1193125/1aa23861-2b36-10f0-e946-fde88f9fb9cf.png)


### インストーラーを起動
ダウンロードした「jdk-19_windows-x64_bin」を実行します。
後々に環境変数を設定するため、インストール先をメモしておきます。
その他の項目については「OK」で進め、インストーラーの実行を完了させます。

### メモ方法補足
インストーラー起動し、進めると下記の画面に進みます。
下記画面で「変更」をクリックし、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1193125/7d0047d4-ae31-f05a-7732-3a3aa13c8e51.png)

フォルダ名をメモしておきます。（今回の場合は「C:\Program Files\Java\jdk-19\」）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1193125/c3b9e4fd-55bf-3bac-f275-389cab41d280.png)


## 環境変数の設定
### 補足
環境変数とは、OSが設定値などを永続的に保存し、利用者や実行されるプログラムから設定・参照できるようにしたもの。

Windowsの設定→システム→詳細情報→システムの詳細設定まで移動します。
下記のシステムプロパティの設定画面で、「環境変数」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1193125/7be5e181-f7d9-db7a-2b21-1d0338c6d906.png)


新規ボタンをクリックし、インストーラー起動時にメモした、インストール先に「bin」を追加し保存します。
また、パスの優先順位上からなので出来るだけ上に移動させておきます。
環境変数を保存したら、設定を反映させるため再起動させます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1193125/8e7fbdfd-ae49-9c80-8e9f-50a009d551ac.png)

## プログラム作成

まずデスクトップ配下にフォルダを作成します。
次に、作成したフォルダ配下にファイルを作成します。
- フォルダ名：JAVA
- ファイル名：Test.java

作成したファイル「Test.java」に下記を記載し保存します。
　プログラムの内容：実行すると「HelloWorld!」と出力される簡単なものになります。
※「class TestJava」とありますが、今回実行するプログラム名は「TestJava」になります。
```
class TestJava{
    public static void main(String[] args){
        System.out.println("HelloWorld!");
    }
}

//記載内容の概要
// クラス名＝TestJava
// メソッド＝処理
// 定義部分　public static void main(String[] args){}
// public アクセス修飾子 どこからアクセス可能か 今回の場合は他の場合からアクセス可能なprivate
// static その他の修飾子                      今回の場合クラスをインスタンスかしなくても直接呼出し可能なstatic
// void 戻り値の型　今回の場合は戻り値がない場合のvoid
// main メソッド名 mainは必ず必要（自作のメソッドを使用する場合はそのメソッド名を記載する）
// String[] args 引数の型　main関数の場合「String[] args」が一般的

```


## プログラム実行
Javaのプログラムが作成できたので、実行に進みます。
ただ、Javaはコンパイル（コンパイラ）言語のため、コンパイルを実施しなければ実行が出来ません。
そのため、まずコンパイルを実施します。

### 補足
コンパイルとは、プログラミング言語をパソコン分かる言語に変換すること

コマンドプロンプトにて、先ほど作成したフォルダまで移動し、javaファイルがあることを確認します。
```
cd Desktop\JAVA　#フォルダへ移動
dir　#カレントディレクトリ配下のフォルダやファイルの一覧表示コマンド
→出力結果に「Test.java」があればOK！
```

コンパイルを実施します。
```
javac Test.java　#javac ファイル名
```

Javaプログラムを実行します。

```
java TestJava　#java プログラム名
```

プログラム実行後、下記の出力があればOKです。
```
HelloWorld!
```


NEXT
 --- 
https://qiita.com/kousueke/items/edde4e5696b1ed01e17f
paizaラーニング レベルアップ問題集 paizaの森練習問題コンテスト過去問題6 JavaScript 採点

採点 (paizaランク C 相当)

https://paiza.jp/works/mondai/forest_contest_006/forest_contest_006__d_scoring

ワンライナーで解いてみました。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

console.log(lines.slice(1).reduce((a, m) => 
  a += m === "correct" ? 2 : (m === "incorrect" ? -1 : 0), 0)
);
```