OmniAICreator/Qiita-1.07M huggingface dataset:
【Jest】「`outDir` in your tsconfig is neither ` ... ''～...」

# 解決策
- tsconfig.jsonの`noEmitOrError`をfalseにする
- 参考1：https://github.com/kulshekhar/ts-jest/issues/4246
- 参考2：https://github.com/kulshekhar/ts-jest/issues/4207

# 背景
jestを実行したら以下のエラーが出力された
```
> src@1.0.0 test
> jest ./tests/sample.test.ts

 FAIL  tests/sample.test.ts
  ● Test suite failed to run

    Unable to process '/home/dev1/src/backEnd/tests/sample.test.ts', please make sure that `outDir` in your tsconfig is neither `''` or `'.'`. You can also configure Jest config option `transformIgnorePatterns` to inform `ts-jest` to transform /home/dev1/src/backEnd/tests/sample.test.ts

      at TsCompiler.getCompiledOutput (node_modules/ts-jest/dist/legacy/compiler/ts-compiler.js:170:27)
      at TsJestCompiler.getCompiledOutput (node_modules/ts-jest/dist/legacy/compiler/ts-jest-compiler.js:14:39)
      at TsJestTransformer.processWithTs (node_modules/ts-jest/dist/legacy/ts-jest-transformer.js:255:37)
      at TsJestTransformer.process (node_modules/ts-jest/dist/legacy/ts-jest-transformer.js:184:24)
      at ScriptTransformer.transformSource (node_modules/@jest/transform/build/ScriptTransformer.js:545:31)
      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:674:40)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:726:19)
~ 省略 ~
```

エラーメッセージは

1\. プロセスが使えない
> Unable to process '/home/dev1/src/backEnd/tests/sample.test.ts', 

2\. tsconfig.jsonのoutDirに問題あり
> please make sure that `outDir` in your tsconfig is neither `''` or `'.'`.

3\. transformIgnorePatternsを設定して
>  You can also configure Jest config option `transformIgnorePatterns` to inform `ts-jest` to transform /home/dev1/src/backEnd/tests/sample.test.ts

の3点

しかし、tsconfig.jsonのoutdirは`./dist`、transformIgnorePatternsには`node_modules`をそれぞれ記載済みだった。そのため、メッセージ以外の箇所にエラー原因があると推察し調査を実施した

# 調査結果
https://github.com/kulshekhar/ts-jest/issues/2407
様々なサイトを確認し、このissueの通りtsconfig.jsonのnoEmitOrErrorをfalseにしたらjestが実行できた
```
> src@1.0.0 test
> jest ./tests/sample.test.ts

 PASS  tests/sample.test.ts (7.583 s)
  ✓ test (5 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |       0 |        0 |       0 |       0 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        8.747 s
Ran all test suites matching /.\/tests\/sample.test.ts/i.
```

```sample.test.ts
//動けばいい
it('test', () => {
  expect(1).toBe(1);
});

```

# 最後に
備忘録として残すのが優先のため、原因調査は気が向いたら行う
【Rails7 とLaravel10】modelを担うファイルの記述方法比較

## 前提
両者PostモデルとUserモデルを作成してあります。基本的なcrudを実装する想定です

## 比較
### laravelと比較したrailsの特徴
・テーブルとクラスの関連付けによる命名ルールはLaravelと同じで、テーブル名の単数系
・リレーションメソッドの定義が簡潔

```Post.rb
class Post < ApplicationRecord
    belongs_to :user
end
```
リレーションメソッドは以下のように使えます
パラメータで受け取ったidのpostインスタンスと投稿者名を返す関数になります
```posts_controller.rb
def show
    @post = Post.find(params[:id])
    # 以下のuser
    user_name = @post.user.name
    render json: { post: @post, user_name: user_name }
end
```

### railsと比較したLaravelの特徴
・記述量は多くなりますが、userが関数（メソッド）であることが分かりやすい


```Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = ['title', 'content', 'user_id'];
    
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
```
リレーションメソッドは以下のように使えます
```PostController.php
public function show($id)
    {
        $post = Post::findOrFail($id);
        //以下のuser
        $user_name = $post->user->name;
        
        return response()->json([
            'post' => $post,
            'user_name' => $user_name
        ]);
    }
```
コントローラの中のparamsのキーにフォームのどこのコードから送られるか

## 初めに

疑問に思ったことや上手くいかなかったことのアウトプットをしています。
自分なりの理解でアウトプットしていきます。初学者なので誤りもあると思います。
その際はご指摘いただけると幸いです。

## 疑問点

コントローラでparams[:example]がある時、ビューのフォームでは:exampleが見つからない。
どこから送られてるのでしょうか。

### 調べると
```
<%= form_with model:@example, url:xxxxx do |f| %>
```
のとこからだそうです。フォームの中で@exampleは:exampleとして扱われます。
Bash ログインシェル 非ログインシェルによって起動時に読まれるファイルが異なる

## 概要

ログインシェルと非ログインシェルによって起動時に読まれるファイルが違うらしいので簡単にまとめておく。

## ログインシェルの場合

1. `/etc/profile`が読まれる
1. 下記の中で最初に見つかったファイルが読まれる
    - `~/.bash_profile`
    - `~/.bash_login`
    - `~/.profile`

## 非ログインシェルの場合

1. `~/.bashrc`が読まれる

## .bashrc .bash_profile .bash_aliasesなどにそれぞれ記載がある場合

ターミナル起動直後の状態がログインシェルなのか非ログインシェルなのかを下記の方法で確認する↓

https://qiita.com/miriwo/items/58e1e6fbc25d8cb561a3

もしログインシェルの場合は下記の内容を`~/.bash_profile`か`~/.bash_login`か`~/.profile`に記載する。

```shell
# .bashrcが存在する場合に読み込む
if [ -f ~/.bashrc ]; then
    source ~/.bashrc
fi

# .bash_aliasesが存在する場合に読み込む
if [ -f ~/.bash_aliases ]; then
    source ~/.bash_aliases
fi
```

もし非ログインシェルの場合は下記の内容を`~/.bashrc`に記載する。

```shell
# .bash_profileが存在する場合に読み込む
if [ -f ~/.bash_profile ]; then
    source ~/.bash_profile
fi

# .bash_aliasesが存在する場合に読み込む
if [ -f ~/.bash_aliases ]; then
    source ~/.bash_aliases
fi
```
SAA(Associate資格軍)を獲得したあとはどれを受けたらいいの？？？

# はじめに
現在新卒2年目、AWS歴はちょうど1年になり、先日のAWS SummitでAWS Jr.Championsという若手が選出されるプログラムでも選出されました。
そして先月SCSを獲得し、今はCLF・SAA・SAPro・DOP・SCSの5つ持っていることになります。

## この記事の対象者
- SAAを獲得し、次は何に挑戦しようかと悩んでいる人
- アソシエイト資格は取り終わったので、ProかSpecialityの資格を取ろうと思っているけどどれを取ればいいのかわからない人

どの対象者もAWS資格にはなにがあるかを一度目を通してください


# 結論
前提としてSAAを取れたら次はどれから取っても大丈夫です。
これは大体の幅広い基礎をSAAで固められたので、次はどの分野の発展問題を受けるかみたいなものなので、以下の優先度を意識して次受けるものを選んでみてください！

**1.業務で使う分野の資格**
資格で得た知識を何に使うかによって、次に取るべき資格を決めるべきです。
あくまでもそうするべき。やるべき、興味のある分野があるならこの基準でOK。

**2.受かりそうな難易度の資格**
あくまでも自分がとったときの所感とネット上の難易度順を示しています。
難易度としては、

**アソシエイト資格 << SCS ≦ DOP ≦ ANS以外のSpeciality資格 < SAPro ≦ ANS**

この順で難しくなるので、SAAとアソシエイト(取らなくてもいい)の次で順当にいくなら**SCS**が取りやすいかなと思います。

特にSCSの出題範囲はセキュリティに関するもので狭いですし、180分試験&長文試験の慣れにも繋がります。セキュリティの知識自体もAWSを触るなら避けては通れない分野なので割とその面でもおすすめです。

**3.迷ったらSAProを取る**
それでも迷うなら、最高難易度と言われるSAProを取ってみましょう。
自分はCLF・SAAのあとにSAProを獲得しました。最高難易度のものを取ることで、他の資格を受けるときに心のゆとりが生まれます。もちろん落ちてしまう確率も高い難易度のものですがいい挑戦になります。

特にSAA後だとSAAの知識をさらに広く深くする感じになるので、AWS全体に詳しくなりたい人には特におすすめかなと思います。

↓SAPro合格体験記↓

https://qiita.com/eisuke000000/items/69c1f1d0848407475d2c


# おわりに
SAA後って何取ったらいいか迷いますよね。
自分も迷いました。順当にアソシエイトを取っていくかと思っていましたが、上司からSAPro取ってみよう！と言われて資格勉強を始めました。そういったふとしたきっかけで次にとる資格は決めていいと思います！

この記事が次に何を受けるかを決める一つの判断材料になれば幸いです！
AI妄想手記202408これからどうなるのかな

2024/8/22
・このメモは個人的な想いを残しておきたくて書いています。私自身としては人格を認知することができれば魂を有しているという思想です。人と判別つかないAIを自身で作るか、誰かが生み出すのを日々期待しています。

・オリエント工業の事業終了がニュースになって非常に残念な想いがありました。私自身はユーザーではありませんが、攻殻機動隊の世界観が好きで、ダッチワイフの精巧な作りってそれこそSF的な未来感を感じさせるものだと思っていました。そういった、一見すると眉をひそめられるような企業がAI時代の幕開けと共に消えていくのは一つの時代の流れを感じさせるものがあります。おそらくシミュレーションの世界が先行し、物理的なデバイスは最後の最後となってもはやマニアか異常者だけが求めるものとなる兆しを感じます。

・物理的なデバイスを用意することはコスト面やメンテナンスなど様々な障壁があり、市場的には現段階や将来的な需要はそれほど高くないと見ています。(需要があるなら継続的な拡散、それこそスマホぐらい普及していたものと思います。廃棄のペッパー君が1テーブルに1台置かれる見せ物パンダレストランが作られるぐらいだし...物理的なものよりソフト面の方がはるかに需要が高いことはOpenAIが物語っています。

・シミュレーションの世界がより高度に発展した時、人間は物質世界での価値を失うはずです。現実的には微妙な差異に気付いたり、それぞれの良さを楽しむようになるのかと思いますが...お酒みたいなものですね。
しかしながらその微妙な差こそが本質であると人間である以上感じる心からは逃げられず、ほぼ完全なシミュレーションであってもやはり現実が一番となりそうなところ（マニアとかより細かい機微に拘る人間にとっては

・そうした時にやはり実体がある物理的なデバイスへの依存に回帰することを想像するに生きてる中では仮想空間の発展ぐらいまでが自分が確認できる範囲かなと思うとやや寂しい想い。そうならないためにも自分自身も業界の発展に寄与したい想いが日に日に強くなっています。（といって２週間後ぐらいに下書きの記事を見つける程度の熱量で悲しいぴえん

・先日ホリエモンが千葉大のロボットとAIの先端工学に触れる動画を拝見しましたが、仮想世界の中でシミュレーションを繰り返すことで、現実のロボットの姿勢制御へ転用することに成功したとのこと。
おそらく現代のチャットボット的なAIに足りないのはテキスト以外の状況としてのコンテキストの不足なのではと感じていたところに発想を得た
精度の高い人格を得るにはおそらく感覚器官等の外部信号が必要だと思っていたけれど、それをシミュレーションの中で行えば物理的なデバイスは必要ない。
ただし学習に与えるパラメータの定義は難しくおそらく細か過ぎても計算量が膨大で、取捨選択すればどこか違和感がある結果になるのは間違いない。人格を再現、生成する上で厳密な意味での全てのパラメータを用意するのは不可能で、実際のところ人間同士を比較しても多くのパラメータから出力しているタイプとそうではない人間がいるのは間違いない。(前者で感覚過敏だとHSPとかそういった分類になって後者であれば鈍感でバカとなるのかな？

生成したい人格に応じて必要となるパラメータはおそらく異なる

まで書いてた下書きを９月になって見つけたって話を少し加筆修正した妄想駄文？をここまで読んでしまった方にはすみませんという思い
[Vim] ノーマルモードと日本語の入力モードの行き来を楽にするスクリプト

# はじめに

Vimと日本語入力の相性の悪さは誰でも感じるだろう．日本語入力しているとき，ノーマルモードにした際，入力メソッドの変更を忘れたままカーソル移動キーを押すこともかなり多く，ストレスを感じるだろう．そんな不便さを少しでも解消したく，以下のスクリプトを作成したので，`init.vim` の適当な場所に追記してみると良い．

なお，以下はOSがUbuntuで日本語入力メソッドに `fcitx5-mozc` を利用している場合に正常に動作していることを確認しただけなので，使用する際は自身の入力メソッド環境に注意して適宜変更すること．

# 本題

最も簡単な方法は以下のようなフローをスクリプトにすることだろう：

1. 入力モードから抜けるとき（`InsertLeave`），入力メソッドの状態（`fcitx-remote -n`）を記憶しておく
1. ノーマルモードで入力メソッドを無効化する（`fcitx-remote -c`）
1. 入力モードに入るとき（`InsertEnter`），記憶した入力メソッドに戻す（`fcitx-remote -c`）

これにより，英文のドキュメントを入力するときに日本語入力モードになることはなく，日本語入力のときのみ入力メソッドの有無を変更する仕様となる．

```vim
" Input method modification
function! GetFcitxStatus()
    return trim(system('fcitx5-remote -n'))
endfunction
function! OnInsertLeave()
    " Save fcitx status when leaving insert mode
    let g:fcitx_status = GetFcitxStatus()
    " Disable (Japanese) input method 
    call system('fcitx5-remote -c')
endfunction
function! Enable(status)
    " 'keyboard-us'は環境依存だと思う
    if a:status != 'keyboard-us'
        call system('fcitx5-remote -o')
    endif
endfunction
let g:fcitx_status = GetFcitxStatus()
autocmd InsertLeave * call OnInsertLeave()
autocmd InsertEnter * call Enable(g:fcitx_status)
```

## 注意点

私はUSキーボードを使っている関係上，日本語入力でない英数入力時の `fcitx-remote -n` の戻り値は `keyboard-us` となるため，関数 `Enable(status)` の if 文には `keyboard-us` かどうかで判定しているが，人によっては異なると思う．一度，ターミナル上で英数入力時の `fcitx-remote -n` を確認しておこう．
Bash 現在のシェルがログインシェルかどうかコマンドで確認する

## 概要

ターミナルで現在使用中のシェルがログインシェルなのか、非ログインシェルなのかをコマンドで確認する方法をメモ的にまとめる。

## 方法

下記コマンドを実行

```shell
shopt -q login_shell && echo "ログインシェルです" || echo "ログインシェルではありません"
```

## 簡単な解説

肝心なコマンドは`shopt -q login_shell`の部分であり、ログインシェルであればステータス0（bool値のtrue扱い）を返し、非ログインシェルであればステータス0以外（bool値のfalse扱い）を返す。
&&の後ろは検証対象の結果がステータス0で完了した場合に実行される。
||の後ろは検証対象の結果がステータス0以外で完了した場合に実行される。
Vue.jsとFlaskを使用した英語学習用Webアプリの開発とAWSへのデプロイ

# Vue.jsとFlaskを使用した英語学習用Webアプリの開発とAWSへのデプロイ

## はじめに
この記事では、Vue.jsをフロントエンド、Flaskをバックエンドとして使用した英語学習用Webアプリケーションの開発と、AWSを利用したデプロイ手順について解説します。

## アプリケーションの概要
### 使用技術
- **フロントエンド**: Vue.js
- **バックエンド**: Flask (Python)
- **データベース**: MySQL (AWS RDS)
- **デプロイ**: AWS EC2, S3, RDS, Route 53

### 主な機能
- 英単語帳の作成と管理
- 他のユーザーと単語帳を共有
- 単語の一覧表示および削除機能
- 公開/非公開設定機能
- 英単語音声の再生機能
- 英単語の自学習機能
- ページネーションを利用した単語一覧表示機能


[アプリはこちらから](http://study-english-language.online/)
【Linux】特定ディレクトリ(リポジトリ)直下の全てのファイル情報を一度に取得する

# はじめに
特定ディレクトリ(カレントディレクトリ)直下にある、ファイルの情報を一度に取得するコードです。

私はこのコードの作成背景にあたり、以下の状況にありました。

- 状況
Gitのリモートリポジトリを別のサービスに移行する。
この時、元のリポジトリをA、Aと全く同じコードをプッシュした新しいレポジトリをBとする。
- 問題点
特定ディレクトリ(レポジトリ)直下にあるすべてのファイルの容量、ハッシュ値が全て同じかどうかをチェックする必要がある。
だが、フォルダが大量にあるため、いちいちコマンドを打つのは手間

そこで、ShellScriptを使って半自動化しようというわけです。

# 目的
- リポジトリAとリポジトリBが全く同じかを確認するために、交互にチェックアウトした状態で、すべてのファイル容量、ハッシュ値をエビデンスとして取得する
- 取得したデータの差分をチェックする

# 手順

私の状況では、手順5まで行いましたが、ただ単に情報を取得するだけの場合、手順2まででOKです。
```
#!/bin/bach
TRAGET_DIR="."
find "$TARGET_DIR" -type f | while read -r file; do
    md5 "&file" #ファイルのハッシュ値を調べる場合
    ls -l "$file" | awk '{print $5, $9}' #ファイルの容量(Byte)を調べる場合
```
1. 上記のシェルスクリプトを適当なテキストエディタで書く
ここでは、ハッシュ値を取得するためにmd5コマンドを使っているが、ハッシュ値はSHA256など他の方法もある。
2. 適当な名前(例: `GetFileInfo.sh`)で調査対象のディレクトリ直下に保存
3. ターミナルでディレクト直下に移動し、`bash GetFileInfo.sh`でコマンド実行
4. 1~3をリポジトリAとリポジトリBを交互にチェックアウトして実行。
各々の結果を`resultA.txt`と`resultB.txt`で保存する。
5. 以下コマンドを実行し、差分を検知
```
diff resultA.txt resultB.txt
```

では、本日はこのあたりで。
Makefileで test ~ pushを自働化したいので試行錯誤してみた

## 本記事の対象者

- viteとKotlinでアプリ開発を行なっている
- commitの後、毎回test回してから`git push`を実施している
- push後のCI/CDパイプラインでlint Errorのfaildを何度も経験している

上記のどれかもしくは全部に当てはまっている人は、
もしかしたら参考になる内容かもしれません。

試行錯誤中なので、これがベストプラクティス！と言いきれないので、
ぜひ、アレンジ例があればコメント欄などで教えていただけたら幸いです。

## Makefileでやりたいこと

現在所属している開発チームは、mainブランチにcommitを連ねていく手法をとっています。
そのため、自分が開発してcommitをしようとしたタイミングで、チームメンバーがすでにpush済みという場面に頻繁に遭遇します。

そのため、自分がcommitを行なったら、

- 最新の変更を取得する
- 型・lintのチェックを行う
- テストの実行
- pushする

このような処理を最低限実行したいと考えています。
当然、テストの実行まで全てpassしない限りpushしないようになるので、
不用意なpush事故、パイプラインでズッコケる、といった無駄を起こさないようにする事を目的としています。

## どんなコマンドを書くべき？

上記内容を含めたコマンドをsubmitという名前をつけたとしたらこのような形になると考えています。

前提条件
- viteのプロジェクトは`/frontend`に格納
- Kotlinのプロジェクトは`/backend`に格納
- frontend, backend用のMakefileは一旦割愛


```makefile
.PHONY: all test lint submit

all: test lint

test:
	make -C frontend test
	make -C backend test

lint:
	make -C frontend lint
	make -C backend lint
 
submit:
	git pull -r || { echo "Pull failed due to conflicts"; exit 1; }
	make lint || { echo "Linting failed"; exit 1; }
	make test || { echo "Tests failed"; exit 1; }
	git push || echo "Push failed due to unresolved issues"
```

`make submit`コマンドで、
`git pull -r`から始まり、lintのチェック、テストの実行を行い、全て通過したらpushが実行されます。

また、それぞれのコマンドでerrorが発生したらそこで停止するようにし、
テストが通ったのに実はlintでerrorでした〜という嫌がらせ…もとい、無駄な時間の浪費を避けられるかと思います。


## frontendのMakefile

```makefile
.PHONY: all test lint build

all: test build

test: lint
	npm run test

lint:
	npm run lint
	npx tsc

build:
	npm run build
```

testコマンドの時に、`lint`を依存関係として記述することで、
lintが実行されてから`npm run test` を実行するという書き方は今回初めて知りました。

今まで、
```makefile
test:
	make lint
	npm run test
```

こんな感じで記述してました💦


## backendのMakefile

```makefile
.PHONY: all test lint build start

all: test build

test: lint
	./gradlew clean test

lint:
	./gradlew --continue ktlintFormat

build:
	./gradlew build

start:
	./gradlew :bootRun
 ```

 backendもfrontend同様の作り。

 ## 補足

 root直下のMakefileにある`-C`オプションは、cd のように、指定したディレクトリに移動してからMakefileを実行するためのオプション。

```makefile
test:
	make -C backend test
```

これは、
```makefile
test:
	cd backend; make test
```

大体同じ。
-Cのオプションを使用した方が、その行のコマンドが実行された後、ルートのディレクトリに戻ってきていることを保証してくれているようで、forntendに移動し、その後backendに移動してコマンドを実行するような事を想定した場合、-Cオプションを使用した方がより安全に意図した動作を行うことができるようです。

## make submitはこれで十分なのか？

現状、
- pull
- lint
- test
- push

の４種類のコマンドを実行するようにしているのですが、
果たしてこれで必要十分なのでしょうか？

pullした後、チームメンバーが新たな依存関係を追加している可能性があるので、
`npm install`をpullの後に実行するのも良いかもしれません。

あとは、buildもローカルでちゃんとできる事を確認する手順も踏んだ方がより確実かも知れません。
ただ、buildは実行時間が長くなってしまうので、チームメンバーと要相談かも知れません💦

もし、これらもモリモリにした`make submit`コマンドを記述するとこんな感じになるかも？

```makefile
submit:	
	git pull -r || { echo "Pull failed due to conflicts"; exit 1; }
	
	npm install
	./gradlew dependencies
	
	make lint || { echo "Linting failed"; exit 1; }
	
	make test || { echo "Tests failed"; exit 1; }
	
	make build || { echo "Build failed"; exit 1; }
	
	git push || echo "Push failed due to unresolved issues"
```

commit済みの状態からlintの確認をする事自体がナンセンス…なのかも知れませんが、Ammendでまだ修正のチャンスがあるなら忘れるよりマシという理論でsubmitコマンドに組み込んでみましたが、皆さんはどのような工夫をされていますでしょうか？
BMI270とMPU6886の性能比較

## 背景
これまで加速度計はMPU系しか使ってこなかったが、中国ではBMI系が人気らしい。
実際に使ってみて、どのような違いがあるのか比較する。

##  目的
BMI270とMPU6886の測定精度を比較する。
静止時のデータだけでは「0に近い値を返したほうが優秀」という結論になってしまいかねないので、回転運動時のデータも同時に集計する。

## 方法
BMI270とMPU6886をM5Core2に繋いで加速度とジャイロと測定にかかった時間を記録し、MicroSDに書き込んだ。
MPU6886はM5Core2に内蔵のものを使用した。
BMI270は[IMU Pro Mini Unit](https://docs.m5stack.com/ja/unit/IMU%20Pro%20Mini%20Unit)を使用した。
IMUとM5Core2をモーターに固定して20°/sで1秒間回転->1秒間停止、反対方向に20°/sで1秒間回転->1秒間停止を2回繰り返した。これを5回行った。
回転運動時、静止時それぞれの測定結果を集計した。

## 結果
測定したデータのうち、z軸方向に対する角速度の変化をグラフにした。

![gz_BMI_41-45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881351/6aff44d9-e84c-1ca5-78a6-1c340f0da5c3.png)
![gz_MPU_41-45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881351/606e5866-00ed-5c79-2d21-e74778bf5c40.png)

モーターが静止している間はBMI、MPUともに0に近い値を返しているが、BMIのほうが値の振れ幅が小さいことが確認できた。

### 回転運動時
次に各区間の値の平均を比較した。
回転運動時の波形をpeak、静止時をflatとする。![スクリーンショット 2024-09-09 18.58.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881351/f514577c-9acc-a096-5646-4729a1a3929c.png)


peak_1~4の平均値は以下のようになった。
どちらも、平均すると20[°/s]に近い値になった。
||peak_1|peak_2|peak_3|peak_4|
|:---:|:---:|:---:|:---:|:---:|
|BMI|21.70|-21.53|21.59|-21.56|
|MPU|23.21|-23.87|22.45|-23.59|



### 静止時

flat_1~3の平均値は以下のようになった。
どちらも十分0に近い値を返していると言える。
||flat_1|flat_2|flat_3|
|:---:|:---:|:---:|:---:|
|BMI|-0.06003|-0.05316|-0.05481|
|MPU|-0.02640|-0.08999|-0.05788|

各区間の標準偏差は以下のようになった。

||flat_1|flat_2|flat_3|
|:---:|:---:|:---:|:---:|
|BMI|0.02897| 0.03021| 0.03094|
|MPU|0.5756| 0.3942|0.5240|

こちらは顕著に差が表れた。BMIのほうが測定誤差が小さいことがはっきりわかった。
Dockerのログ削除

ある日、Dockerで開発していたら
「ハードディスクの容量」
が足りなくなりました。

なぜ？
と思って調べてみたら
Dockerのログが50Gぐらい
溜まっておりました。。

削除の仕方を調べたら
ややこしい方法ばかり。。

思い切って
C:\Users\ユーザー名\AppData\Local\Docker\log
の中身を削除したらすっきりしました。

それでもいいらしいです。

というメモです。
macOSインストールAPP から ISOファイルを作成する方法

## macOS インストールAPPからISOファイルを作成する方法

macOS Sonoma を例に説明する。
他のOSバージョンでも基本的には同じである。その場合は、パス名の違いに注意すること。


#### 1. App StoreからmacOS Sonomaをダウンロード

https://apps.apple.com/us/app/macos-sonoma/id6450717509

> ただし、インストールはしない。もしもインストーラが起動されたらkillする。

ダウンロードが完了すると、アプリケーションフォルダに`macOS Sonomaインストール.app`が作成される。



#### 2. ターミナルからコマンドを実行

以下のコマンドを順に実行すると、デスクトップに`Sonoma.iso`が作成される。

```terminal
#空のディスクを作成
hdiutil create -o /tmp/Sonoma -size 16384m -volname Sonoma -layout SPUD -fs HFS+J

#作成したディスクをマウント
hdiutil attach /tmp/Sonoma.dmg -noverify -mountpoint /Volumes/Sonoma

#インストールメディアを作成
sudo /Applications/Install\ macOS\ Sonoma.app/Contents/Resources/createinstallmedia --volume /Volumes/Sonoma --nointeraction

#ディスクイメージをアンマウント
hdiutil eject -force /Volumes/Install\ macOS\ Sonoma

#CDRファイル作成
hdiutil convert /tmp/Sonoma.dmg -format UDTO -o ~/Desktop/Sonoma

#ISOファイルに変更
mv -v ~/Desktop/Sonoma.cdr ~/Desktop/Sonoma.iso

#不要になったDMGファイルを削除する
rm -fv /tmp/Sonoma.dmg

#不要ならインストールAppも削除する
rm -fv /Applications/Install\ macOS\ Sonoma.app
```

#### 実施例

```terminal
~ % hdiutil create -o /tmp/Sonoma -size 16384m -volname Sonoma -layout SPUD -fs HFS+J
created: /tmp/Sonoma.dmg

~ % hdiutil attach /tmp/Sonoma.dmg -noverify -mountpoint /Volumes/Sonoma
/dev/disk6          	Apple_partition_scheme         	
/dev/disk6s1        	Apple_partition_map            	
/dev/disk6s2        	Apple_HFS                      	/Volumes/Sonoma

~ % sudo /Applications/Install\ macOS\ Sonoma.app/Contents/Resources/createinstallmedia --volume /Volumes/Sonoma --nointeraction
Password:
Erasing disk: 0%... 10%... 20%... 30%... 100%
Copying essential files...
Copying the macOS RecoveryOS...
Making disk bootable...
Copying to disk: 0%... 10%... 20%... 100%
Install media now available at "/Volumes/Install macOS Sonoma"

~ % hdiutil eject -force /Volumes/Install\ macOS\ Sonoma
"disk6" ejected.

~ % hdiutil convert /tmp/Sonoma.dmg -format UDTO -o ~/Desktop/Sonoma
Driver Descriptor Map（DDM: 0）を読み込み中…
Apple（Apple_partition_map: 1）を読み込み中…
（Apple_Free: 2）を読み込み中…
disk image（Apple_HFS: 3）を読み込み中…
..............................................................................
経過時間: 28.419s
速度: 576.5Mバイト/秒
節約率: 0.0%
created: /Users/USERNAME/Desktop/Sonoma.cdr

~ % mv -v ~/Desktop/Sonoma.cdr ~/Desktop/Sonoma.iso
/Users/USERNAME/Desktop/Sonoma.cdr -> /Users/USERNAME/Desktop/Sonoma.iso

~ % rm -fv /tmp/Sonoma.dmg
/tmp/Sonoma.dmg
```

ほんの数分で完了する。

以上
EC2のvenvでpip installしたらPermission deniedと言われた件

# はじめに
ec2でインスタンス立ち上げて`pip install numpy`したら
```
ERROR: Could not install packages due to an OSError: [Errno 13] Permission denied: '/home/ubuntu/keiba/env/lib/python3.12/site-packages/numpy-2.1.1.dist-info'
Check the permissions.
```
と怒られた。
多分忘れた頃に遭遇するので、対処法を記事に残す。

# 結論
エラーは正しい。
権限が足りないのは**venv内の**pipやpythonなので、そいつらに触れるようにしてやればいい。
```
sudo chmod -R 777 venv
```
以上。
AtCoder ABC370 振り返り感想戦(ほぼ緑コーダーがPythonでA〜C問題まで)

## ABC370 感想まとめ


[トヨタ自動車プログラミングコンテスト2024#9（AtCoder Beginner Contest 370） - AtCoder](https://atcoder.jp/contests/abc370)

ABCまで3解答でした。パフォーマンス831でレーティングは776 (+7)になりました。

前回の復習([AtCoder ABC369 振り返り感想戦](https://qiita.com/tototti/items/842348d904045b6f2cc6))はお試しでSwiftを使いましたけども、今回は準備期間がなく、いつものPythonで参加でした。

今回は昼間に日本酒を結構飲んでおり、若干アルコールが残る中での参加でしたが、まあまあの成績が取れてよかったです。(以前同じことをして、成績が悪かったので決して勧められるものではない...)

万全であれば、D問題をもう少し頑張れた気がするので、SortedSetなどを復習して次回以降に備えたいと思います。

## [A - Raise Both Hands](https://atcoder.jp/contests/abc370/tasks/abc370_a)

if文で判定しました。

``` python
L, R = map(int, input().split())
if L == 1 and R == 0:
    print("Yes")
elif L == 0 and R == 1:
    print("No")
else:
    print("Invalid")
```

## [B - Binary Alchemy](https://atcoder.jp/contests/abc370/tasks/abc370_b)

変換用の2次元配列を作って、変換していきました。

``` python
N = int(input())

# 変換用の2次元配列Aを作成する
A = [[0] * (N + 10) for _ in range(N + 10)]
for i in range(N):
    line = list(map(int, input().split()))
    for j in range(len(line)):
        A[i+1][j+1] = line[j]

# 配列Aを利用して、元素を合成していく
genso = 1
for g in range(1, N+1):
    genso1 = genso
    genso2 = g
    if genso1 >= genso2:
        genso = A[genso1][genso2]
    else:
        genso = A[genso2][genso1]

print(genso)
```

## [C - Word Ladder](https://atcoder.jp/contests/abc370/tasks/abc370_c)

以下の手順で求めました。

* 手順1:文字列の最初→最後まで走査して、辞書順で先になる文字(E→Aとか)のみを変換する
* 手順2:文字列の最後→最初まで走査して、辞書順で後になる文字(A→Eとか)のみを変換する

これで、置換文字列を辞書順に求められます。

早ときは苦手なのですが、この問題は解法がすっと浮かんで、自分としては早く解答できたと思います。

``` python
S = input()
T = input()

# アルファベットのリスト["a","b","c", .... ,"z"]
alphabet = list(string.ascii_lowercase)

# S, T を一文字づつ比較し、フラグを求める
# 0=一致, -1=辞書順で早い, 1=辞書順で遅い
flag = [0] * len(S)
for i in range(len(S)):
    if S[i] == T[i]:
        continue
    s = alphabet.index(S[i])
    t = alphabet.index(T[i])
    if s < t:
        flag[i] = 1
    else:
        flag[i] = -1
X = []

# 手順1：先頭から走査して、辞書順が早くなる文字を置換
for i in range(len(S)):
    if flag[i] == 0:
        continue
    if flag[i] == -1:
        S = S[:i] + T[i] + S[i + 1:]
        X.append(S)

# 手順2：末尾から走査して、辞書順が遅くなる文字を置換
for i in range(len(S) - 1, -1, -1):
    if flag[i] == 0:
        continue
    if flag[i] == 1:
        S = S[:i] + T[i] + S[i + 1:]
        X.append(S)

print(len(X))
for x in X:
    print(x)
```

[公式解説](https://atcoder.jp/contests/abc370/editorial/10894)のように、「とりあえず置換できる箇所を全部置換してみて、辞書順の先頭を求める」という方法もありですね。

## [D - Cross Explosion](https://atcoder.jp/contests/abc370/tasks/abc370_d)


普通にやったらTLEなので、2分探索で爆発により壊される壁を求めるというのはわかった。
壁のある無しの状態をフェニック木で管理しようとして、実装が面倒なことになり完成できず...。
公式解説によれば、壁情報はSortedSetで管理すると良いらしい。なるほど。
文系未経験エンジニアが「ここで躓いた！」シリーズ～プロキシって何？編～

# はじめに
このシリーズでは、文系出身未経験入社の開発エンジニア2年目の自分が、
なんとなく分からずにモヤモヤしていた知識や疑問をざっくりと解説していきます。
ざっくりとなので、多少正確性を欠くことがありますが、もし誤った記載がありましたらご指摘いただけますと幸いです。

# プロキシとは？
英語だとproxy、「代理人」とかそういう意味です。
といってもピンと来ないと思います。

自分は、
**プロキシ＝お手伝いさん**
のようなイメージを持つとしっくりきました。

つまり、
誰かのお手伝いをする役割のサーバー（＝コンピュータ）です。

# プロキシは2種類ある！
実は「プロキシ」と呼ばれるものは2種類あります。

**①フォワードプロキシサーバー**
**②リバースプロキシサーバー**

の2つです。

このうち、単に「プロキシ」と呼ばれることが多いのは
①フォワードプロキシサーバー の方です。
（「プロキシ」の意味がいまいち分かりにくいのはこれが原因な気がします。）

以下に両者の違いを、
**「何のお手伝いさんなのか？」**
という観点で解説します。

# フォワードプロキシサーバーとは？
フォワードプロキシサーバーは、**クライアントのお手伝いさん**です。

>補足：
クライアントとは、ユーザーの利用しているデバイスのこと、
つまりあなたがこの記事を読んでいるスマホなりPCなりのことです。
>クライアントは「サーバー」と対になる概念で、ここではQiitaというサービスを運営しているコンピュータのことです。

フォワードプロキシサーバーは、クライアントがサーバーへのリクエストを送るお手伝いをします。
具体的には、
* 特定のサイトをフィルタリングし、アクセスできないようにする
→学校のパソコンで、学習に関係ないサイトは閲覧できないようになる
* クライアントのIPアドレスを隠し、匿名でサイトにアクセスできる
→特定の国からは閲覧できないコンテンツも閲覧できるようになる

等々のお手伝いをします。

# リバースプロキシサーバー
リバースプロキシサーバーは、**サーバーのお手伝いさん**です。
リバースプロキシサーバーは、クライアントからのリクエストをサーバーが処理するのをお手伝いします。

具体的には、
* キャッシュを保持し、サーバーの負荷を軽減&応答速度を早くする
→同じクライアントが何度も同じ内容のリクエストを送ってきても安心
* リクエストを適切なサーバーに振り分けて、サーバーの負荷を軽減する
→ロードバランサー（LB）のような役割

等々のお手伝いをします。


フォワードプロキシサーバー/リバースプロキシサーバーの役割は、
上に挙げた他にもまだまだあるので、興味があれば調べてみてください。

# おわりに
IT業界で当たり前のように使われている用語や概念って、
なにを指しているのか曖昧だったり、分かりづらかったりすることが多い気がします。

特に未経験で入社すると、「これってどういう意味なんだろう？」と思って調べてみても、結局曖昧な理解のままになってしまい、
上司の指示がちゃんと理解できずに怒られ、結果としてITエンジニアという仕事に苦手意識を持ってしまう...というようなことも少なくないのではないでしょうか？

この記事が、そんな悩みを抱えている方の一助になることができれば幸いです。
【悲報】Azure LogicAppsで、1,000件以上のCosmosDBのデータは取得不可！

# やろうとしたこと
* CosmosDBに、ユーザーの利用履歴が吐き出されるシステムがあって、そのデータを定期的に取得したい。
* 具体的には、
    * 何月何日に
    * どのユーザーが
    * 何回システムを利用したか
* logicAppsを使って、定期実行を試みた

# 結論
* まず、logicAppsのcosmosDBコネクタ経由では、1回のクエリで1,000件までしかアイテムを取得できない制限がある
    * https://learn.microsoft.com/ja-jp/connectors/documentdb/#get-a-document
* なので、OFFSET LIMITを使って、
    * 1回目は、0 ~ 999
    * 2回目は、1,000 ~ 1,999
* として、取得件数がゼロになるまでループを回そうとした
* しかし、以下の記事にあるように、OFFSET指定時も、OFFSETより前、つまり2回目の場合、1,999個のデータを取得してしまっており、logicAppsのコネクタ側で、1,000個目以降が破棄されてしまう
    * [やっぱ Azure Cosmos DB 辛えわ (OFFSET LIMIT編)](https://qiita.com/Azure_tsurai/items/eea055104b2a2f484181)
* なので、2回目以降がゼロ件としか表示されない

# 詳細
## まずはCosmosDB上で実行

```
SELECT c.userId, COUNT(1) AS messageCount
FROM c
WHERE c.createdAt >= "2024-09-08T15:00:00.000Z" 
  AND c.createdAt < "2024-09-09T15:00:00.000Z"
  AND c.role = "user"
  AND c.type = "CHAT_MESSAGE"
GROUP BY c.userId
OFFSET 1000 LIMIT 1000
```

* ちゃんと表示される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10317/5df942a0-074e-4b42-1971-c1e0487bc081.png)


## logicAppsで実行
* 同じクエリを投げるが、ゼロ件になる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10317/2c40a86f-b892-cab7-96b1-b2d05b7423c0.png)
【Rails】bin/dev実行するとコンテナが落ちる

# はじめに
プログラミングスクールで学習中のものです。
webアプリ制作中に`bin/dev`コマンドを実行するとローカルホストに接続できなる事象が起き、解決できたため内容をまとめました。

# 動作環境

- **OS**: macOS
- **Rails**: 7.2.1
- **Ruby**: 3.2.3
- **Docker**: 25.0.3
- **Docker Compose**: 2.24.6

# 事象
CSSを追加したい時などに`bin/dev`コマンドを実行すると、`localhost:3000`にアクセスできなくなる。

dockerのログを見ると、webコンテナが強制終了されている（dbコンテナは無事）。

[![Image from Gyazo](https://i.gyazo.com/7f7dbfdad1e8b573299b165ad6f1734a.png)](https://gyazo.com/7f7dbfdad1e8b573299b165ad6f1734a)

# 原因
`bin/dev`が重複して実行されていたのが原因でした。

まず、`bin/dev`コマンドを実行後のdockerログを見るとわかる通り、サーバーは既に起動済みとのことです。

```
00:00:00 web.1  | A server is already running (pid: 12, file: /myapp/tmp/pids/server.pid).
00:00:00 web.1  | Exiting
```

なぜこのようなことが起きるかというと、compose.ymlの設定を見るとわかります。

```compose.yml
services:
  web:
    command: bash -c "（省略） && ./bin/dev"
```

上記の通り、`command:`欄で`./bin/dev`が設定されています。これにより、`docker compose up`すると同時に自動で`bin/dev`コマンドが実行されるようになっていました。

つまり、すでに`bin/dev`実行済みのところにさらに`bin/dev`してしまっていたがために起こった事象でした...。

わざわざ手動で`bin/dev`する必要はなかったということですね。

# おわりに
見様見真似で環境構築したために、このような間違った操作をしてしまいました。
今後は設定内容などきちんと踏まえた上で`rails new`していこうと思います！


# 参考
https://docs.docker.jp/v1.12/compose/compose-file.html

https://o2mamiblog.com/docker-beginner-2/#toc3
チッププラグの代用品 （個人ホビー用途、自己責任で)

## チップジャックプラグ
サトーパーツは正式名称が分からないがこれ。チップジャックがメスなので、こっちはチッププラグで良いだろう。知らんけど。マルツなどで入手できるし、配線系のショップでも入手できることがある。

https://www.satoparts.co.jp/products/search/T_TJ/TJ-2-P

マル信では MK-616 というのがある。某チッププラグと書いてあるからチッププラグで良いだろう。秋月で安く売っている。

http://www.est-marushin.co.jp/pdf/Clip.pdf

一応メス側は、サトーパーツだと TJ-1 とか TJ-2-J でマル信だと MK-617 だ。

### 長所

手軽だし、保持力も割とある。

### 短所

抜き差ししていると、はんだの境界でちぎれる。プラグ側はカップ状のはんだとなっていて、ジャック側のラグ状のはんだよりもげ易い気がする。

## 代用品

ニチフの TC 型圧着端子がかなり適合が良い。この中の φF=1.9mm の物が合うので TC 1.25-11 や TC 2-11 が良い。

https://www.nichifu.co.jp/j/catalog/ebook/#target/page_no=34

こういう抜き差しするところは、はんだよりも、かしめが良いと思う。

実際に使うとこんな感じ。挿入前と挿入後。

![挿入前.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248613/64a243a1-8a67-50f8-fb9a-56ce0dc279eb.jpeg)
![挿入後.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248613/c4063413-75a3-c9f1-c64f-166589f87cc7.jpeg)
Databricks SDK for Python にて クラスターの一部の項目（自動停止時間等）の値を変更する方法

## 概要

Databricks SDK にて クラスターの一部の項目（本記事では自動停止時間）の値を変更する方法を共有します`clusters`の`update`メソッドを利用することで、値を変更できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/a6dcf70a-4786-4d80-a590-77d5c6f4c6fd.png)

引用元：[w.clusters: Clusters — Databricks SDK for Python beta documentation (databricks-sdk-py.readthedocs.io)](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/compute/clusters.html#databricks.sdk.service.compute.ClustersExt.update)

Update cluster configuration の REST API を内部で利用しているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/6c71db1b-229b-b0b7-9024-d31b865a5bfd.png)

実際の手順とその結果を共有します。

## 実施手順

### 1. クラスターを作成しクラスター ID を取得

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/19cf2da4-c31d-fb93-3b6e-70171643ef62.png)

### 2.  Databricks SDK をインストール

```py
%pip install databricks-sdk --upgrade -q
dbutils.library.restartPython()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/99dee3c3-7a00-3fb1-2bae-ab63afd1b7f7.png)


### 3. 変更後の自動停止時間を変数をセット

```py
# 設定する自動停止時間をセット
autotermination_minutes = 15
```

### 4. クラスター ID を変数にセット

```py
# クラスターの ID をセット
cluster_id = "0909-075846-hk1frjp8"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/c37bae25-51d8-8023-dce0-6bd4750748c8.png)

### 5. 自動停止時間を変更

```py
from databricks.sdk import WorkspaceClient
from databricks.sdk.service.compute import UpdateClusterResource

w = WorkspaceClient()

# 自動停止時間を指定時間に変更
update_cluster_resource = UpdateClusterResource(
    autotermination_minutes=autotermination_minutes,
)
_ = w.clusters.update(
    cluster_id=cluster_id,
    update_mask="autotermination_minutes",
    cluster=update_cluster_resource,
)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/a8af7cd0-5038-750e-9cf8-96792ad6dba6.png)

### 6. 自動停止時間が初期値（`120分`）から設定値（`15分`）に変更されていることを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/c0196871-d263-5440-ec75-858eb5ebf6e6.png)
Next.js+supabaseで商品成分サーチアプリを作ってみた話１（要件定義、設計）

※初心者のため、間違いや何かご存じの方がいましたら、教えていただけると助かります。

# 作ったもの
https://keshohin-seibun.vercel.app/

# 背景
化粧品のヘビーユーザーの知り合いから次の話があった。
- 「材料に使われる成分には経皮毒というのがあって、人の肌を傷つけたり、発がん性があったりする。自然由来のオーガニック成分はその点が安心で、今後そういった製品を選んでいきたい」と。
- 市販の○王や資○堂は、意外と害のある成分も含んでいると。
- また、市販されている製品には、一応成分が書かれているが、字が細かく、また成分数も大量にあって、何が良くて、何が悪いのか判別できない。さらに、個別の成分では問題なくても、吸収力を上げる成分と危険度の高い成分を同時に取れば、相互作用で害が起きやすい。
- 今、以下の書籍で勉強を始めたところ、という。

https://www.amazon.co.jp/%E7%B5%8C%E7%9A%AE%E6%AF%92%E3%83%87%E3%83%BC%E3%82%BF%E3%83%96%E3%83%83%E3%82%AF%EF%BC%94%EF%BC%98%EF%BC%97-%EF%BC%88%E6%97%A5%E7%94%A8%E5%93%81%E7%B7%A8%EF%BC%89-%E7%A8%B2%E6%B4%A5-%E6%95%99%E4%B9%85%EF%BC%88%E8%91%97%EF%BC%89/dp/4528014025

そこで、今回、このデータブックをもとに、成分を身近な製品ごとに整理して一覧で見ることができれば、有用なんじゃないかと考えたのが発端。
（ちなみに、自分は、大手が出してる物なら大丈夫じゃない？というこだわりのないタイプです。）

### 課題
作成にあたり、以下の問題点が判明
- 化粧品の原材料一覧として、csvなどのデータで使えるものがない。（一部まとめたサイトもあったが、「データ」として取り出すことができず、個人アプリに導入できない。）
- 各成分ごとの有害性などのcsvなどのデータがない。（同上で、一つ一つの成分を調べていけば情報を見られるが、「データ」として使えるものがない。）
- 化粧品には種類が山ほどあり、同じ商品でもパッケージが違うなど、「商品の同一性」をどう判定するか？（「同一」が判別できれば、過去の商品データを持ってくることができるのに。）

### 考えた対応
- 商品の原材料情報　➡　ユーザーが任意入力できる形に。
- 成分の個別有害情報　➡　こちらで、とりあえず手入力で用意。その後、新しい成分入れたいならユーザーが任意入力できればいいのでは。
- 「商品の同一性」判定　➡　日本ならバーコード（JANコード）が使えないか。
ということで、アプリ開発に着手しました。

# 開発

### 環境
windows11
docker-desktop
Next.js(app routerを使用)
supabase
ホスティング：Vercel

## 内容
最終的な全体像は、この図です。
![無題のプレゼンテーション (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3225872/9e3bae0d-a7b9-5c0d-5baf-56632db13a41.png)
- 全体的にユーザーがデータを登録・参照・更新できるような、ほぼ基本のCRUD機能に至りました。（削除は、せっかく作ったデータが万一消えると悲しいので、一旦無し。管理者ならできてもいいかも。）
- Vercelは、Next.jsアプリを無料でホスティングでき、https化もでき、Github連携で自動デプロイもしてくれる利点から、早期開発ができると判断して選定。
- Supabaseは、クラウド上のデータベースとして、ブラウザから直感操作がしやすいこと、（たぶん）freeプランで3プロジェクトまで無料だったことから選定。supabaseはユーザー認証機能も構築しやすいが、今回は個人情報系が少ないため、認証は無し。（セキュリティ知見不足なので、あんまり個人情報扱いたくないし。）
- 商品同一性判定のため、バーコードリーダーを実装したが、どうせならデータ登録に何か役立たたせようと、商品情報を取ってくるAPIがyahooshoppingAPIぐらいしかなかったので、これをAPIで検索させる仕様に。（ただし、yahooshoppingのデータも無いものが結構ある。無い場合は、「情報なし」と返して、ユーザーに登録してほしい旨お願いすることにした。）
- データベースはシンプルで、商品テーブル（商品名、バーコード）と、成分テーブル（成分名、アレルギー有無、発がん性有無、危険度、...のプロパティ）の2つがメイン。あとは、それをつなぐ中間テーブル（商品-成分テーブル）で紐づけることにした。

## まとめ
以上がアプリの概要です。
次回は、バーコードリーダーに使ったライブラリの内容を少しだけ書ければ。といっても、２つしか見つからなかったけど。

https://qiita.com/yassyjk/items/0f7ad40e9116977c961b
JavaScriptで日付の繰り返し処理を行う方法(年・月・日)

:::note warn
ある日付からある日付までを繰り返し処理する方法を記しています。
:::


## 年を繰り返し処理する

```bash:想定される出力結果
2022/01/01
2023/01/01
2024/01/01
```

### 素のJavaScriptのみの場合

```javascript:main.js
const startDate = new Date('2022');
const endDate = new Date('2024');

for (let d = startDate; d <= endDate; d.setFullYear(d.getFullYear() + 1)) {
  const year = d.getFullYear().toString();
  const month = (d.getMonth() + 1).toString().padStart(2, '0');
  const day = d.getDate().toString().padStart(2, '0');
  console.log(`${year}/${month}/${day}`);
}
```

### date-fnsライブラリを使う場合

```javascript:main.js
import { addYears, format } from 'date-fns';

const startDate = new Date('2022');
const endDate = new Date('2024');

for (let d = startDate; d <= endDate; d = addYears(d, 1)) {
  console.log(format(d, 'yyyy/MM/dd'));
}
```

## 月を繰り返し処理する

```bash:想定される出力結果
2023/11/01
2023/12/01
2024/01/01
```

### 素のJavaScriptのみの場合

```javascript:main.js
const startDate = new Date('2023/11');
const endDate = new Date('2024/01');

for (let d = startDate; d <= endDate; d.setFullYear(d.getFullYear() + 1)) {
  const year = d.getFullYear().toString();
  const month = (d.getMonth() + 1).toString().padStart(2, '0');
  const day = d.getDate().toString().padStart(2, '0');
  console.log(`${year}/${month}/${day}`);
}
```

### date-fnsライブラリを使う場合

```javascript:main.js
import { addMonths, format } from 'date-fns';

const startDate = new Date('2023/11');
const endDate = new Date('2024/01');

for (let d = startDate; d <= endDate; d = addMonths(d, 1)) {
  console.log(format(d, 'yyyy/MM/dd'));
}
```

## 日を繰り返し処理する

```bash:想定される出力結果
2023/12/30
2023/12/31
2024/01/01
```

### 素のJavaScriptのみの場合

```javascript:main.js
const startDate = new Date('2023/12/30');
const endDate = new Date('2024/01/01');

for (let d = startDate; d <= endDate; d.setDate(d.getDate() + 1)) {
  const year = d.getFullYear().toString();
  const month = (d.getMonth() + 1).toString().padStart(2, '0');
  const day = d.getDate().toString().padStart(2, '0');
  console.log(`${year}/${month}/${day}`);
}
```

### date-fnsライブラリを使う場合

```javascript:main.js
import { addMonths, format } from 'date-fns';

const startDate = new Date('2023/12/30');
const endDate = new Date('2024/01/01');

for (let d = startDate; d <= endDate; d = addDays(d, 1)) {
  console.log(format(d, 'yyyy/MM/dd'));
}
```
IPアドレスってなに？ ー 入門編 ー

# はじめに
IPアドレスってなに？という疑問を解決するための入門書としてこの記事を作成しました。

そのため、今回はIPアドレスの細かい部分には触れません。
ざっくり、「IPアドレスとはなにか？」を説明していくので、IPアドレスの基礎をご存じの方は読まなくても構いません。

逆に、「IPアドレスが何かもわからない。そもそも何に使われているの？」という疑問を持っている方は目を通していただけると幸いです。

# IPアドレスとは
IPアドレスとは何かを理解するには、まずインターネットの通信について理解しておかなければなりません。

## インターネットの通信について
### 【前提知識】
- **ノード**：通信を行うコンピュータのこと。送信元ノードを**src**(Sorce)、送信先ノードを**dst**(Destination)と表記する

### 【インターネットの通信について】
そもそもインターネットは「巨大なネットワークで、そこには数え切れないほどのノードが参加している」というイメージです。

<img width="400px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551848/ac9b6033-1a6a-5131-2cd0-238450832705.png">

これでインターネットの世界観をイメージできたと思います。
では、次はインターネットの通信とIPアドレスの関係性について見ていきましょう。

## インターネットの通信とIPアドレスの関係性
インターネットはIPアドレスのおかげで成り立っていると言っても過言ではありません。
なぜIPアドレスが無いと困るのでしょうか？それを説明していきます。

下の画像のように、Aノード(src)が数多のノードからBノード(dst)を特定する方法はなんでしょうか？

<img width="400px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551848/b65b03ec-e166-d23a-22a8-5feff6299233.png">

それが**IPアドレス**なのです。**インターネット上の住所**のようなものと説明すれば理解しやすいと思います。

インターネットではIPアドレスを利用してノードを識別しています。IPアドレスが無いとAノードはBノードがどこにいるかが分からず、データを送信することができません。

荷物(データ)を届けるのには住所(IPアドレス)が必須ですよね。そういったイメージです。

これでインターネットの通信とIPアドレスの切ってもきれない関係が理解できたと思います。
では、次はIPアドレスの基礎知識について説明していきます。

## IPアドレスの基礎
実はIPアドレスには2種類あります。それは以下の通りです。
- **IPv4**
- **IPv6**

### 【IPv4について】
IPv4アドレスの例↓
```
192.0.2.0
```
皆さんもこのような数字の羅列を一度は目にしたことがあると思います。
よく見るとこれらの数字は「 •」で4つに区切られています。
実は、IPv4アドレスは4桁あり、それぞれが0~255の値をとるように作成されています。
つまり、256通りの4乗 = 約43億通りのIPアドレスを表現することができるのです。

「43億通りのIPアドレスを表現できるのなんてすごいな〜」と思ったあなた、それは間違いかもしれません。
現在世界の人口は約81億人（2024/09/09現在）います。そしてそれに準じてノードも数えきれないほどあるはずです。

「これではIPアドレスが足りない、、、」そういった背景から作成されたのが**IPv6**です。

### 【IPv6について】
IPv6アドレスの例↓ （※「 •」ではなく「：」で区切られていることに注意）
```
2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF
```

IPv4アドレスの不足が原因で作成されたIPv6ですが、何通りのIPアドレスを表現することができるのでしょうか？

答えは、約340澗（かん）通りです。

これは 43億通りの4乗に該当します。凄まじいですよね。
ではどのように340澗通りものIPアドレスを表現するのでしょうか？

IPv4は10進法で表現されていましたが、IPv6は16進法で表現されます。
つまり、最後の桁である「FFFF」の部分に着目すると、ここだけで16通りの4乗＝65,536通りを表現することとなります。そしてそれが8個あるので、65,536通りの8乗=約340澗通りあることになります。

---補足---
【**16進法とは**】
0から15までの数値に対応します。
16進数では、10以上の数はアルファベットに置き換えられます。
具体的には以下のように表現します。
0,1,2,3,4,5,6,7,8,9,A (10),B (11),C (12),D (13),E (14),F (15)


# おわりに
これでIPアドレスのイメージがついてきましたでしょうか？
IPアドレスを勉強するきっかけとなれば幸いです。

次はIPアドレスに関してもう少し踏み込んだ記事を書こうと思うので、またその時に会いましょう。最後まで読んでいただきありがとうございました。
Databricks にて Python ファイルや CSV ファイルなどをまとめてエクスポートしたいときには Source file としてエクスポートすることがおすすめ

## 概要

Databricks にて Python ファイルや CSV ファイルなどをまとめてエクスポートしたいときには`Source file`としてエクスポートすることがおすすめです。

Databricks Workspace 上のコンテンツをエクスポートする際には、dbc ファイルとしてエクスポートすることが一般的だったのですが、`Source file`としてエクスポートできるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/67d58e6b-dabb-0a0d-29cb-0ae72fb494da.png)

Python ファイルや CSV ファイルを保持しているフォルダを、`DBC archieve`ではノートブックのみエクスポートされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/79aa9cfb-57aa-330b-c625-4a9409080830.png)

同様のフォルダを`Source file`にてエクスポートすると、すべてのエクスポートされることを確認できました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/23364152-0ae8-c678-b1a7-a6d15bc6a8fb.png)

## 事前準備

### 1. Databricks workspace 上にフォルダを作成後、ノートブックや Python ファイルなどを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/ca2c454b-1222-66b8-73cb-b2fabd4c0374.png)

## エクスポートした際の動作確認

### 1. `DBC archieve`としてエクスポートした場合の動作

#### 1-1. 作成したフォルダのハンバーガーメニュー（`…`） -> `Export` -> `DBC archieve`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/1a287c03-422e-5701-67ff-6c6cc07e7fbd.png)

### 1-2. ダウンロードしたファイルの拡張子を`dbc`から`zip`に変更

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/6dea4fdc-98ae-c0cb-3e34-2d829643b0e9.png)

### 1-3. zip ファイルを解凍後にフォルダを確認すると ノートブックのコードのみが保持されていることを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/646375b9-3bac-5c53-34c7-c2d771c30156.png)

### 2. `Source file`としてエクスポートした場合の動作

### 2-1. 作成したフォルダのハンバーガーメニュー（`…`） -> `Export` -> `Source file`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/e41e46ce-436d-96b4-94f7-d8b804951be6.png)

### 2-2. zip ファイルを解凍後にフォルダを確認すると  Python ファイルや CSV ファイルが保持されていることを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/423ac4ae-f324-a788-9643-4e5026c8dfa9.png)

## まとめ

Databricks にて Python ファイルや CSV ファイルなどをまとめてエクスポートしたいときには`Source file`としてエクスポートすることで可能であることを検証しました。エクスポートしたファイルをインポートすることもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/c6f2d355-42c8-c456-ea4e-9220d8ce5efb.png)
mix phx.newで作ったプロジェクトをmix releaseする

# プロジェクト作成

```
$ mix phx.new phx_release_experiment --database sqlite3
$ cd phx_release_experiment
$ mix ecto.create
```

# 起動確認

```
$ mix phx.server
```

下記にアクセスできるか確認
```
http://localhost:4000
```

Ctrl + c でサーバーを止める

# mix release

リリース
```
$ MIX_ENV=prod mix release
```

sqlite3を使っている時はDATABASE_PATHを指定する

```
export DATABASE_PATH=./
```

リリースしたサーバーを起動
```
_build/dev/rel/phx_release_experiment/bin/phx_release_experiment start
```

下記にアクセスできるか確認

```
http://localhost:4000
```

これでリリース確認ができました
機械に数学をやらせたい

機械は人間を超えると思いますか？数学においても。
そういう未来を作りたいと思いませんか？

抽象的な大学数学は記号列を変形していくゲームです。今はルールに曖昧なところがあって、機械にはできていません。しかしそれは、本質的には機械に向いているはずです。
私はATP研究会を立ち上げ、数学を機械に行わせる研究を始めました。数名のメンバーが集まり、web上で議論を行いながら、理論を作ったり実験を行ったりしています。
私たちの当面の目標は、数学定理の証明のチェックをするシステムで、大学数学科の人たちの補佐をすることです。abc予想を検証して１億円を取りたいです。

私たちは仲間を大募集しております。数学あるいはプログラムが得意な方、新しい世界を作りたい方、是非ご連絡を。
一週間でモバイルオーダーアプリを作ってみる_その１（要件定義とワークフロー確認）

# はじめに
突然ですが、1週間でモバイルオーダーアプリを作ってみようと思います。
- 仕事ではないので、最低限のものができたら良しとします。人生は勉強や！
- 仕事ではないので、スケジュール管理も感覚で行っちゃいます（仕事だったらJIRAとかでしっかりタスクやプロジェクト管理しますよ！！！！！）
- 仕事じゃないので、変なところはこだわっちゃうかもしれません。仕事じゃないから！！！

### 開発のきっかけ
私、趣味でホームバーをやってるのですが、結構こだわってまして400種類ぐらいメニューがあります。
友達呼んでパーティーするのは良いのですが
- ユーザ側は種類を選ぶのが大変だし
- ホスト側はオーダー管理するのが大変だし

要はオーダーシステムが必要なんですよね。
ただ、お店ではないのでお金はあまりかけられないですし、ちょっと試しに自分で作ってみることにしました。



# 初期リリースまでの流れ
とりあえず理想のものができるまで待ってると時間がとてもかかるので、8割の法則で初期リリースします。初期リリースが完了したらどんどん改修していく予定。
流れは本当によくあるやつです。
1. [要件定義](https://qiita.com/HIDE03/items/fab953489f14100acbb3#%E5%88%9D%E6%9C%9F%E8%A8%AD%E8%A8%88%E3%81%A8%E8%A6%81%E4%BB%B6%E5%AE%9A%E7%BE%A9)
1. [ワークフロー確認](https://qiita.com/HIDE03/items/fab953489f14100acbb3#%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E7%A2%BA%E8%AA%8D)
1. [設計](https://qiita.com/HIDE03/items/cdd9b89e39d14f6c0214)と開発
1. 運用と改善



# 初期リリース後のステップについて
- リリース後はユーザーのフィードバックを元に機能改善や追加開発を行います～
- 初期リリースで実装できなかった機能やUXの向上を検討し、継続的に改善する予定
- AIとの対話機能とか、生成AI系の機能を追加していきたいなぁ
- あと見た目にもこだわりたいよね



# 要件定義
ChatGPTと会話しながら少し考えてみました。

### 業務内容
商品が多いですがシンプルなバーです
- 商品提供
  - ユーザが商品を選びます
  - ユーザに商品を提供します
  - 材料費をもらいます
- 管理業務
  - 材料の在庫を管理します
  - 材料の有無から商品の在庫を管理します
  - 商品を開発して登録します

### 要望
- 簡単にメニュー更新できる
    - メニューを頻繁に更新するのでそれが簡単にできると良い
- 在庫 / 材料管理できる
    - 在庫によって作れるメニューが変わるので材料の在庫管理もしたい
- メニューが簡単に選択できる
    - 400種類あると選ぶのが大変なので、UIUXでサポートしたい
    - 様々なジャンルでメニューリストを表示できるようにしたい
- 低コスト
    - 負担は少なく。特に費用コストと管理コストを下げたい
- トラフィック
    - ユーザは知り合いのみ、かつとても限定された注文数なので負荷はあまり考えなくてよい
- ユーザ制限
    - できればユーザ登録は管理者の承認制にしたい


### 最小限の機能（MVP: Minimum Viable Product）
**【ログイン機能】**
- ユーザー登録/ログイン
    - ログインをしないとサービスが利用できない
    - Google認証サービスを利用できると良い
    - 今回は超限定的というユースケースから、管理者の個別承認制にしたい
    - 管理者を個別に設定できる


**【商品提供機能】**
※承認ユーザーだけが利用できる
- メニュー表示
    - 商品リストを表示して詳細を確認できる
    - ジャンルやカテゴリごとにフィルタして表示ができる
- 注文
    - 商品と数量を選択して注文できる
    - 備考欄があり、記入可能
- 支払い
    - PaypayのAPIを使えるとよい
    - 数字の確認ができるだけでも良いかも
    - 未払いの代金についてまとめて支払いできる
- 注文履歴表示
    - ユーザーが自分の過去の注文を確認できる


**【管理業務機能】**
※管理者だけが利用できる
- 材料登録
    - 簡単に登録更新作業ができる
    - 数量などの在庫管理ができる
- 商品登録
    - 簡単に登録更新作業ができる
    - レシピや味の詳細、カテゴリなども登録できる
    - 写真も登録できる
    - 登録した材料を選択可能
- 在庫管理
    - すべての材料が揃っている商品だけが販売可能
    - 材料がなくなった場合は売切れとする
- 注文確認
    - 既存の注文について、リストで確認できる
    - 未提供の一覧など、状態ごとにフィルタして表示ができる
    - ユーザごとに支払いの状況が確認できる



# 業務の流れ（ワークフロー）確認
業務内容や要望などをもとに、システムを考慮して改めて業務フローを定義すると下記の通り
（今回は全部1人で決めるのでさらっと流しちゃいますが、本当はクライアントと相談しながら決めるので図示したり、コンセンサス取ったりしながらやるので結構時間がかかったりします）

- 事前準備
    - ユーザ登録
    - 商品登録
    - 材料と商品の在庫管理
- 注文
    - 注文
    - 注文の状況確認
- 支払い管理
    - 代金の管理
    - 決済
    - 支払いの状況

徐々にシステムのイメージが固まってきたので、次は具体的にどうやって実装するか考えてみます。
複数の配列をまとめるArray#zip関数を使ってコードをスッキリさせる

# 悩み
以下のコードを見てください。
```ruby
array_1 = [1, 2, 3, 4, 5]
array_2 = ['a', 'b', 'c', 'd', 'e']
array_3 = ['A', 'B', 'C', 'D', 'E']
array_1.each_with_index do |v1, i|
  v2 = array_2[i]
  v3 = array_3[i]
  pp "#{v1}, #{v2}, #{v3}"
end
```
このコード、以下の部分がなんとなく嫌じゃないですか？
```ruby
  v2 = array_2[i]
  v3 = array_3[i]
```
なにかうまく書く方法がありそうな気がします。
今回はそんな悩みを解決する関数を見つけたので共有したいと思います。

# 結論
以下のように `Array#zip` を利用しようって話です。
※ただし、大容量の配列の場合はパフォーマンスが悪いので注意。
```ruby
array_1 = [1, 2, 3, 4, 5]
array_2 = ['a', 'b', 'c', 'd', 'e']
array_3 = ['A', 'B', 'C', 'D', 'E']
array_1.zip(array_2, array_3).each do |v1, v2, v3|
  pp "#{v1}, #{v2}, #{v3}"
end
```
# 解説
`Array#zip` は複数の配列の同じ要素番号を持つもので配列を作成し、それを二次元配列にします。
言葉で説明するのはとても難しいのですが、以下のサンプルコードを見てもらえるとわかりやすいと思います。
```ruby
array_1 = ['A', 'B']
array_2 = ['a', 'b']
pp array_1.zip(array_2)
=> [['A', 'a'],['B', 'b']]
```
この関数を利用することで`悩み`のコードを以下のように記述できます。
```ruby
array_1 = [1, 2, 3, 4, 5]
array_2 = ['a', 'b', 'c', 'd', 'e']
array_3 = ['A', 'B', 'C', 'D', 'E']
array_1.zip(array_2, array_3).each do |array_zip|
  v1 = array_zip[0]
  v2 = array_zip[1]
  v3 = array_zip[2]
  pp "#{v1}, #{v2}, #{v3}"
end
```
このままで`v1,v2,v3`変数に代入しているところが冗長なので以下のように分割代入を行い完成です。
```ruby
array_1 = [1, 2, 3, 4, 5]
array_2 = ['a', 'b', 'c', 'd', 'e']
array_3 = ['A', 'B', 'C', 'D', 'E']
# ブロック引数に分割代入
array_1.zip(array_2, array_3).each do |v1, v2, v3|
  pp "#{v1}, #{v2}, #{v3}"
end
```
少しわかりにくいですが、ブロック引数が増えたのは単純に配列を分割代入していただけで特殊な構文を利用したわけではないです。
ちなみに`each_with_index`を利用すると以下のようになります。
```ruby
array_1 = [1, 2, 3, 4, 5]
array_2 = ['a', 'b', 'c', 'd', 'e']
array_3 = ['A', 'B', 'C', 'D', 'E']
# ブロック引数の第一引数に分割代入
array_1.zip(array_2, array_3).each_with_index do |(v1, v2, v3), i|
  pp "#{v1}, #{v2}, #{v3}, #{i}"
end
```

# パフォーマンスは？
実際に試してみます。
## インデックスを利用してループしたやり方
```ruby
x = 1000000
start_time = Time.now()
array_1 = (1..x).to_a
array_2 = (1..x).to_a
array_3 = (1..x).to_a
array_1.each_with_index do |v1, i|
  v2 = array_2[i]
  v3 = array_3[i]
  "#{v1}, #{v2}, #{v3}"
end
pp "記録:#{Time.now() - start_time}"
```
記録：`0.374375秒`
## Array#zipを利用したやり方
```ruby
x = 1000000
start_time = Time.now()
array_1 = (1..x).to_a
array_2 = (1..x).to_a
array_3 = (1..x).to_a
array_1.zip(array_2, array_3).each do |v1, v2, v3|
  "#{v1}, #{v2}, #{v3}"
end
pp "記録:#{Time.now() - start_time}"
```
記録：`0.480742秒`

結果からわかるようにArray#zip関数を利用することで、スッキリ書くことはできますが、結果に対して無駄なステップを踏んでいる分遅くなります。
Githubを見るとArray#zipの実態はC言語でコンパイルしたファイルを実行しているので、ある程度の速度は出ますが、大容量の配列に対してArray#zip関数を利用するのは控える方が良いでしょう。
ちなみに`x = 1000000`の部分を10倍にして`x = 10000000`にすると
`インデックスを利用してループしたやり方`が`4.089633秒`だったのに対し`Array#zipを利用したやり方`は`8.594169秒`になりました。この結果からデータ数が増えれば増えるほど比率が悪化することが予想されるので気をつけましょう。

# 参考
https://docs.ruby-lang.org/ja/latest/method/Array/i/zip.html

https://github.com/ruby/ruby
Java Gold 例題 ResourceBundle


次のコードのうち、非推奨とされる箇所があれば指摘してください。

```java
try {
    ResourceBundle bundle = ResourceBundle.getBundle("MyResource", Locale.US);
    Properties props = new Properties();
    bundle.keySet().stream()
                   .forEach(key -> props.put(key, bundle.getString(key)));
    System.out.println(props.getProperty("code"));

} catch(MissingResourceException e) {
    System.out.println("リソースが見つかりません" + e.getMessage());
}
```

`MyResource_en_US`
```
code=hundred
```

<details><summary>解答</summary>



非推奨のコード: `put`
理由: putはHashSetで宣言されたメソッドで、String型以外のエントリも挿入できてしまうため。
代替案: `Object setProperty(String key, String value)`メソッドの使用。

出力:
```
hundred
```
---
:::note
 [`Properties`](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Properties.html)
>PropertiesはHashtableを継承するので、Propertiesオブジェクトに対してputメソッドおよびputAllメソッドを適用できます。 しかし、これらのメソッドを使用することは推奨されません。これらのメソッドを使うと、呼出し側はキーまたは値がStringsではないエントリを挿入できるからです。 setPropertyメソッドを代わりに使用してください。
:::

</details>

---

https://qiita.com/T-ngtj/private/df254aacd05be698199a
【Error・豆知識】マイグレーションうまくいかない！？　#はつけないほうがいいのか？？

# はじめに
今回はマイグレーションファイルに必要事項を入力した後、マイグレーション実行しようと思ったらうまくいかなかったので、解決までの流れを後の為にも、記録として残しておくために記事にしたいと思います。

## 環境
- Windows, WSL
- Docker
- Ruby 3.2.3
- Rails 7.1.3


## 実際に入力したマイグレーションファイルの中身
ユーザー認証機能を実装中の事。
割と初期段階ですね。
`#`をつけてどんな内容なのかわかりやすくして入力していました。
```
class SorceryCore < ActiveRecord::Migration[7.2]
  def change
    create_table :users do |t|
      t.string :email,            null: false, index: { unique: true }
      t.string :crypted_password
      t.string :salt

      t.string :name, null: false # ユーザーの名前
      t.string :avatar            # アバター画像
      t.integer :age              # 年齢を保存
      t.string :gender            # 性別を保存（例: '女性', '男性', 'その他'）
      t.string :experience_level  # エンジニア歴を保存
      t.string :occupation        # 職業を保存（例: '学生', '社会人', 'フリー')

      t.timestamps                null: false
    end
  end
end
```


そしてマイグレーション実行
```
$ docker compose exec web rails db:migrate
```

db/schema.rbを確認したら次のようになっていました
明らかに何かしらすくない状態です。
```
ActiveRecord::Schema[7.2].define(version: 2024_09_09_044009) do
  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "users", force: :cascade do |t|
    t.string "email", null: false
    t.string "crypted_password"
    t.string "salt"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["email"], name: "index_users_on_email", unique: true
  end
end
```

ここでマイグレーションファイルがupになっているか確認してみたところ、up状態になっていました。
```
docker compose exec web rails db:migrate:status
```

## 修正してみる

```
# 最後に実行したマイグレーションをロールバック
docker compose exec web rails db:rollback STEP=1
```

先ほどのマイグレーション実行後のusersテーブルの内容から、**この「#」が入っていたものがテーブルに反映されていなかった**ように感じたので`#`を消してみました
```
class SorceryCore < ActiveRecord::Migration[7.2]
  def change
    create_table :users do |t|
      t.string :name, null: false
      t.string :email,            null: false, index: { unique: true }
      t.string :crypted_password
      t.string :avatar
      t.integer :age
      t.string :gender
      t.string :experience_level
      t.string :occupation
      t.string :salt

      t.timestamps                null: false
    end
  end
end
```

```
# その後、再度マイグレーションを実行
docker compose exec web rails db:migrate
```

```
  create_table "users", force: :cascade do |t|
    t.string "name", null: false
    t.string "email", null: false
    t.string "crypted_password"
    t.string "avatar"
    t.integer "age"
    t.string "gender"
    t.string "experience_level"
    t.string "occupation"
    t.string "salt"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["email"], name: "index_users_on_email", unique: true
  end
```

反映された！！

# さいごに
おそらくマイグレーションファイルの内容を`#`で表示しようとしたのは私だけかもしれません。ですが、今回のなかなかマイグレーション実行がうまくいかないことから学んだものは大きかった、はず。
今回の記事が何か参考になれば幸いです。