OmniAICreator/Qiita-1.07M huggingface dataset:
Redis で Lua を実行する

## はじめに

今回は Redis の公式ドキュメントにある [Scripting with Lua](https://redis.io/docs/interact/programmability/eval-intro/) について勉強する。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676183/81b72486-cd42-30cb-84d1-de8a3f8b3ea4.png" />

<small>※ 自分はよく混同してしまうのだが、今回は Redis のサーバー上で Lua を実行する方法について述べる。（Lua プログラムから Redis クライアントを利用する方法については述べない。）</small>

## Redis と Lua について

Redis では、**サーバー上で Lua スクリプトを実行させることができる**。 スクリプトによってプログラムによる制御をおこなうことができ、コマンドを使ってデータベースにアクセスできる。

- スクリプトはサーバー内で実行されるため、スクリプトからの**データの読み書きは非常に効率的になる** 。（[PostgreSQL の PL/pgSQL に似ている](https://www.postgresql.jp/document/14/html/plpgsql-overview.html#PLPGSQL-ADVANTAGES)）
- Redis ではスクリプトの実行には**アトミック性が保証される**。スクリプトの実行中、サーバーのアクティビティはブロックされる（スクリプトがすべて作用しているか、すべて作用していないかの状態になる）

## Redis で Lua を使うとできること

Lua を使用すると、アプリケーションのロジックの一部を Redis の内部で実行させることができる。例えば以下のようなことができる。

- 複数のキーを条件付きで更新する
- 複数の異なるデータ型を組み合わせて操作する

<small>※ スクリプトは Redis に組み込まれた実行エンジンによって実行される。（Lua 5.1 のみ）</small>
<small>※ EVAL するスクリプトはサーバー側ではなくクライアント側アプリケーションの一部とみなされ、永続化されない。スクリプトは（サーバーの再起動後などに）見つからなくなる場合がありアプリケーションから再読み込みさせる必要がある。Redis 7 以降、[Redis Functions](https://redis.io/docs/interact/programmability/functions-intro/) という別の方法でサーバー自体をプログラムされた追加ロジックで拡張できるようになった。</small>

## 例 1. Hello World 的なもの

```ruby
> EVAL "return 'Hello, scripting!'" 0
"Hello, scripting!"
```

この例では `EVAL` が 2 つの引数を受け取っている

- 第 1 引数: Lua のスクリプト（関数の定義ではなく、そのまま実行されるプログラムを書く）
- 第 2 引数: キーの数（今回はキーを与えていないので 0 を指定している）

## 例 2. スクリプトに引数を与える

以下のようなスクリプトを、

```ruby
redis> EVAL "return 'Hello'" 0
"Hello"
redis> EVAL "return 'Scripting!'" 0
"Scripting!"
```

引数を使って以下のようにできる

```ruby
redis> EVAL "return ARGV[1]" 0 Hello
"Hello"
redis> EVAL "return ARGV[1]" 0 Parameterization!
"Parameterization!"
```

- 第 1 引数: Lua のスクリプト
- 第 2 引数: キーの数が 0
- 第 3 引数: ARGV に入る値の 1 つ目（Lua のインデックスは 1 から始まる）

### 注意点:

上の例のような**微妙に異なる複数のスクリプトをアプリケーション側で生成して実行させることはアンチパターン**と言われている。

- `EVAL` で実行したスクリプトはサーバーの専用のキャッシュに保存されるので、さまざまなスクリプトの生成によりホストのメモリリソースを使い果たす可能性がある。

スクリプトは汎用的にして、引数を介して実行する内容をカスタマイズする必要がある。

## 例 3. スクリプトにキーを与える

```ruby
redis> EVAL "return { KEYS[1], KEYS[2], ARGV[1], ARGV[2], ARGV[3] }" 2 key1 key2 arg1 arg2 arg3
1) "key1"
2) "key2"
3) "arg1"
4) "arg2"
5) "arg3"
```

- 第 1 引数: Lua のスクリプト
- 第 2 引数: キーの数が 2
- 第 3、4 引数: キー（KEYS に入る値）
- 第 5、６、７ 引数: 引数（ARGV に入る値）

**KEYS と ARGV の使い分け:** KEYS に入る値は Redis の（キー・バリューのうちの）キーの値にする。それ以外の共通化できる引数には ARGV を利用する。

## 例 4. スクリプトで Redis とやりとりする

`redis.call()` もしくは `redis.pcall()` を利用して Redis のコマンドを実行することができる。

```ruby
> EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 foo bar
OK
```

このスクリプトを実行すると、SET コマンドが呼び出され、キー `foo` に値 "bar" が設定される。

### 注意点:

スクリプトを正しく実行するためには**スクリプトがアクセスするキーの名前をすべて入力キーの引数として明示的に指定する必要がある**。

（スクリプトがプログラムによって生成された名前のキーやデータベースに格納されているデータに基づくキーにアクセスするようにしてはいけない。）
【SwiftUI】端末を振ったことを検知する

# はじめに
端末を振ったことを検知するとランダムに色が変更されるアプリを作成します

# サンプルアプリ
端末を振ると色が変化します
![Simulator Screen Recording - iPhone 14 Pro - 2023-07-23 at 22.40.54.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/dfa251d0-b5ff-0d25-720f-b00c90d59781.gif)

# 実装
```swift
extension NSNotification.Name {
    public static let deviceDidShakeNotification = NSNotification.Name("DeviceDidShakeNotification")
}

extension UIWindow {
    open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        super.motionEnded(motion, with: event)
        NotificationCenter.default.post(name: .deviceDidShakeNotification, object: event)
    }
}
```

# 使い方
```diff_swift
import SwiftUI

struct ContentView: View {
    @State private var color: Color = .orange
    
    var body: some View {
        Text(color.description)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .ignoresSafeArea()
            .background(color.gradient)
+           .onReceive(NotificationCenter.default.publisher(for: .deviceDidShakeNotification)) { _ in
+               color = .init(red: Double.random(in: 0...1), green: Double.random(in: 0...1), blue: Double.random(in: 0...1))
+           }
    }
}
```

# おわり
シェイクを使った個人開発アプリをリリースしたいです

# 参考記事
https://ios-docs.dev/swift-shake/
画像をURLからダウンロードして、gzipで圧縮し、base85でエンコードして軽量化したのち、復元してnp.arraybufferで読み込んで表示

画像をPythonオブジェクトとして保持しておきたい場面があったので、メモ書きです。

## 画像の読み込み

- 必要なパッケージのインポート

```python
import requests
from PIL import Image
import numpy as np
from io import BytesIO
import matplotlib.pyplot as plt
import gzip
import base64
```

- 画像をダウンロードして表示

```python
url = "http://placekitten.com/600/400"

res = requests.get(url)
img = Image.open(BytesIO(res.content))

plt.imshow(img)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/297cf255-104a-790e-8b20-7540cdb68f43.png)

## 変換、圧縮

- ndarrayに変換

```
array = np.array(img)
array.shape
# (400, 600, 3)
```

- gzipで圧縮

```python
compressed = gzip.compress(array.tobytes())
compressed
# b'\x1f\x8b\x08\x00\xbc%\xbdd\x02\xff\xec\xbd\xe7w#\xd7\x99\xee\xfb\xfd\x9e\x99\xf18\xc9\n...'
```

- base85でエンコード

```python
encoded = base64.b85encode(compressed)
encoded
# b'ABzY8yd}M40{`s2=XWF5neO}jo|*AD$qKC;EeBbl)tMa`n>m046PN=)f?...'
```

## デコード

- デコード・解凍・読み込み

```python
img_array = np.frombuffer(gzip.decompress(base64.b85decode(encoded)), dtype=np.uint8)
img_array.shape
# (720000,)
```

- 1次元で読み込まれてしまうので、変換

```python
img_array = img_array.reshape(400, 600, 3)
img_array.shape
```

## 表示

```python
plt.imshow(img_array)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/bde6db31-cfd7-c210-4dc9-12d6e59f6839.png)
いいコード悪いコードまとめ16章設計を妨げる開発プロセスとの戦い

# チームメンバーとのコミュニケーションを密にとっているか
他のチームメンバーと同じ開発をしていた、やっていると思っていたらやっていなかったなどとならないように密にコミュニケーションを取る必要がある。
コンウェイの法則（コンウェイの法則とは、ソフトウェアシステムのアーキテクチャは開発チームの組織とよく似る）という法則から考えてもコミュニケーションは重要
# チームメンバーの心理的安全性は確保されているか
Gogoleが2012年に採用したことが脚光を浴びた概念。これは成功に導くチームを構築する上で重要で、意見や提案をする上で、冷笑されたり、煙たがられたり、聞く耳を持たれない状態ではうまくいかないということ。

# より早く実装完了することに気を取られていないか
# クラス設計と実装のフィードバックサイクルを回しているか
仕様変更の際には最低でもメモ書き程度のクラス図を書くこと。責務や凝集性などの観点から問題ないかをチームでレビューし、なさそうであれば実装に取り掛かる。取り掛かってから見落としに気づくことも多々あるので、それをクラス図にフィードバックすること。

# 厳密に設計しすぎていないか
厳密に設計しても見落としはあるもの。そのせいで設計をしても無意味だと判断するのではなく、こういうものだと割り切ってサイクルを回し続けることが大切。

# 設計ルールは設計スキルの高いメンバが中心となって作っているか
# 改善できる点に気がついた箇所を改善する意識を持っているか
# 既存コードを信用しすぎていないか
既存コードを一切信用しないくらいの心構えでコードを書くこと。
アンカリング効果に振り回されないように注意。
ジョシュアツリーの法則にも注意。

#　コーディング規約を利用しているか
色々あるみたいですね。
https://techracho.bpsinc.jp/hachi8833/2017_05_15/38869
https://github.com/cookpad/styleguide/blob/master/ruby.ja.md
https://qiita.com/tomoharutt/items/51254ae5dafba645dc6d

# 命名規約を利用しているか
https://qiita.com/TakeshiFukushima/items/647a652439b55525945f
https://techracho.bpsinc.jp/hachi8833/2017_02_13/35364

# 設計的な妥当性に重点を置いてレビューしているか 

# 敬意と礼儀を持ってレビューしているか
# レビューで理由を説明しているか
# レビューで不明瞭な点について理由を聞いているか
# レビューで徹底を追い求めて終わりを見つけているか
# 24時間以内にレビューしているか
# ポジティブな点を見つけようとしてレビューしているか
#　人を蔑めるようなレビューをしていないか
# どうでもいいことでレビュー上で決着をつけようとしていないか
# レビューで極端な言葉やネガティブな表現を使っていないか

# 定期的に改善タスクを棚卸しているか
Pyhon 辞書(dict)のループ処理(for)をするときのメソッド(keys(),values(),items())の使用例

# Pyhon 辞書(dict)のループ処理(for)をするときの要素関係

Pythonの辞書`dict`の中のシーケンス要素をfor文でループ処理をする時、`key()`,`value()`,`items()`を使用することで辞書に対して指定したキーや値の組み合わせで要素を取り出すことができる。

### そもそもPythonでいう辞書(dict)って？
簡単に説明すると、**Pythonコード内で定義できるデータの持ち方**の一つです。
他にもリスト(list)、タプル(tuple)があります。

※Pythonのデータの持ち方については、他記事で記載します。^^

辞書の例
`d = {'key1': 1, 'key2': 2, 'key3': 3}`
* `キー:値` の書き方で値を設定すること
　今回は`key1`がキー、`1`が値
* `｛｝`で囲むこと
* 辞書内に要素を複数入れたい場合は`,`で区切って設定すること

### そのまま辞書オブジェクトをfor文で実行すると、`key`が取得される
辞書作成

```
d = {'key1': 1, 'key2': 2, 'key3': 3}
```

実行コード
```
for k in d:
  print(k)
```

結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3389633/a0f03f00-3849-6ae9-368e-9704db864198.png)

### keys(): 各要素のキーに対してforループ処理
上述のように辞書要素に対して、ループ処理(for文)でそのまま実行すると`key`が取得できるが、
視覚的にわかりやすくするためにも`key()`メソッドを使用する

実行コード
```
for k in d.keys():
    print(k)
```

結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3389633/36972da6-2228-1414-f086-5b8f93fbf896.png)

### values(): 各要素の値に対してforループ処理
要素の値`value`に対してループ処理(for文)を実行するには、`value()`メソッドを使用する

実行コード
```
for v in d.values():
    print(v)
```

結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3389633/706258c0-c38f-adc5-fd6d-438998889636.png)

### items(): 各要素のキーと値に対してforループ処理
要素のキー`key`と値`value`の両方の値に対してループ処理(for文)を実行するには、`item()`メソッドを使用する

実行コード
```
for k, v in d.items():
    print(k, v)
```

結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3389633/d74d569c-8e7c-6865-c270-a2c6d04daca1.png)


辞書から抽出した値は、リスト化やタプル化が可能です。
そちらについては後日追記致します。(2023/07/23)
POSIX標準規格では compress, uncompress, zcat コマンドは.Z形式と.gz形式の両対応（gzip圧縮対応）

## はじめに

POSIX で標準化（XSI拡張）されている `compress`、`uncompress`、`zcat` コマンドは Issue 8 で .Z 形式に加えて .gz 形式対応になります。つまり `gzip`、`gunzip` コマンド相当の機能を備えるということです。

1. POSIX の範囲だけで実現したい！
2. POSIX には `gzip`、`gunzip` コマンドがない！
3. POSIX にあるのは `compress`、`uncompress` コマンドだけだ！
4. `compress`、`uncompress` が対応しているのは .Z 形式だけだ！
5. POSIX に準拠するなら圧縮ファイルは .Z 形式しか使えない！

という時代はもう終わりです。

詳細は [XCU.4. cksum, compress, uncompress, zcat](https://www.austingroupbugs.net/view.php?id=1041) へ

## もっとも

`compress` コマンドで gzip 圧縮を行うには `-g` オプションを指定するか `-m` オプションに `deflate` （別名 `gzip`） を指定するのですが、`-g` オプション（`-m gzip` と同じ）が実装されている `compress` コマンドは現時点でおそらく OpenBSD 版のみ（1997年の [OpenBSD 2.2](https://man.freebsd.org/cgi/man.cgi?query=compress&manpath=OpenBSD+2.2) で実装されたっぽい）で、`-m` オプションを実装しているコマンドはなさそうな気がします。

つまり gzip 圧縮を使いたいのであれば素直に `gzip` コマンドや `gunzip` コマンドを使いましょう。`compress`、`uncompress`、`zcat` コマンドは、POSIX で標準化されていると言っても、オプションの XSI 拡張機能なので実装されているとは限りませんし標準インストールされていない場合もあります。Issue 8 で標準化されるということの意味は、単にこれからは POSIX コマンド縛りをしていても .gz 形式を堂々と使えるというだけの話です。

ちなみに `uncompress` コマンドと `zcat` コマンドに関しては、gzip 圧縮に対応するためのオプションはありません。gzip 圧縮に対応しているかは実装によります。本来の `uncompress` コマンドと `zcat` コマンドは .Z 形式にしか対応していませんが、実際には gzip 圧縮を含むさまざまな圧縮形式に対応した実装がすでに使われています。この点に関しては遅れていた POSIX が現実の実装に追いついたといったところでしょう。`compress` コマンドの `-m` オプションの仕様は将来さらに多くの圧縮形式に対応可能であることを示唆しています。もちろん POSIX でもその他の実装定義の圧縮形式に対応しても良いと認められています。

## POSIXの `-m` オプションの説明に関する補足

POSIX Issue 8 では `-m algo` について以下のような説明の表が掲載されています。

| Algorithm           | algo    | Filename Suffix |
| ------------------- | ------- | --------------- |
| Adaptive LZW        | lzw     | .Z              |
| RFC1951 DEFLATE     | deflate | .gz             |
| Synonym for DEFLATE | gzip    | .gz             |

この表を見ると `deflate` と `gzip` の２つの圧縮アルゴリズムがあるように思えますが、圧縮アルゴリズム (RFC1951) が `deflate` で、`gzip` は圧縮ファイル形式の仕様 (RFC1952) で同じものを指しているはずです。次のようにするのが正しい気がします。

| algo          | Algorithm           | Filename Suffix |
| ------------- | ------------------- | --------------- |
| lzw           | Adaptive LZW        | .Z              |
| deflate, gzip | DEFLATE (RFC1951)   | .gz (RFC1952)   |

## さいごに

この件に関してあまり情報（議論）が見つからなく、 [メーリングリスト](https://www.mail-archive.com/austin-group-l@opengroup.org/msg01519.html)で `-g` は existing practice であるぐらいのことしか書かれていないんですよね。それ OpenBSD の話をしてるの？ 提案に対してすんなり「gzip に対応しましょう」で話が終わったの？ 釈然としませんが、まあどうでもいいかなと思います。
[Flutter] スネークケースのAPIレスポンスを自動でキャメルケースに変換する

## はじめに
APIレスポンスのJSONフィールドがスネークケースで返されることは珍しくありません。
一方で、クライアント側ではキャメルケースを使いたい場合が多いと思います。

通常、Dartでこれを解決するためには @JsonKey アノテーションを使用してJSONのキー名とプロパティ名を明示的にマッピングする必要があります。
しかし、大量のプロパティが存在する場合、それぞれにアノテーションをつけるのは大変ですし、つけ忘れる可能性も高まります。
そこで `json_serializable` パッケージの機能を利用し、自動でキャメルケースに変換する方法を見つけたので、それを共有します。

## 設定方法
設定は非常に簡単です。（パッケージをインストールしてない人は[こちら](https://pub.dev/packages/json_serializable/install)から）
プロジェクトのルートディレクトリに build.yaml ファイルを作成し、以下の内容を追記します。

```build.yaml
targets:
  $default:
    builders:
      json_serializable:
        options:
          field_rename: snake
```
デフォルトの設定は`field_rename: null` となっているので、`snake`を指定することで、スネークケースのキー名が自動的に対応するキャメルケースのプロパティにマッピングされます。便利ですね！

また、他にも細かい設定ができるので詳細は、json_serializableパッケージの[公式ドキュメント](https://pub.dev/packages/json_serializable#build-configuration)を参照してください。

## 参考資料
https://pub.dev/packages/json_serializable#build-configuration

https://zuma-lab.com/posts/flutter-search-github-json-serializable-build-yaml
日本の主要な交通オープンデータ一覧

近年様々な交通オープンデータが公開されていますが、複数の組織が別々に公開しているので、主なものを一覧にまとめました。交通そのものに限らず土地利用など関連するデータも含んでいます。

追加情報を随時募集しています。

# 様々なデータを横断検索できるサイト

|名称|整備主体|URL|その他|
|:----|:----|:----|:----|
|国土交通データプラットフォーム|国土交通省|https://www.mlit-data.jp/||
|国土数値情報|行政区域; 防災; 公共施設; 道路; 鉄道|国土交通省|https://nlftp.mlit.go.jp/ksj/| |
|公共交通オープンデータセンター|公共交通オープンデータ協議会|https://www.odpt.org/|APIを利用して動的データが多数提供されている|
|e-stat|総務省統計局|https://www.e-stat.go.jp/| |
|東京都オープンデータカタログサイト|東京都|https://portal.data.metro.tokyo.lg.jp/|地方自治体でオープンデータを公開しているところは大量にあるため省略します|
|DBJデータプラットフォーム|日本政策投資銀行|https://www.dbj.jp/investigate/dataplatform/|地物と紐づかない集計データが主|
|Wikipedia|Wikimedia Foundation|https://www.mediawiki.org/wiki/API:Main_page/ja|MediaWiki API を用いた利用を推奨。スクレイピングは不適切|

# 特定の分野のデータに特化したサイト

|名称|主な用途|整備主体|URL|その他|
|:----|:----|:----|:----|:----|
|位置参照情報|ジオコーディング|国土交通省|https://nlftp.mlit.go.jp/cgi-bin/isj/dls/_choose_method.cgi| |
|全国道路・街路交通情勢調査(道路交通センサス)|道路交通量|国土交通省|https://www.mlit.go.jp/road/ir/ir-data/ir-data.html| |
|交通量API(トラカンデータ)|道路交通量|国土交通省|https://www.jartic-open-traffic.org/|ビューア: https://view.xroad.mlit.go.jp/|
|plateau|都市3Dデータ|国土交通省|https://www.mlit.go.jp/plateau/open-data/| |
|都市計画決定GISデータ|都市計画; 用途地域|国土交通省|https://www.mlit.go.jp/toshi/tosiko/toshi_tosiko_tk_000087.html|GISビューア(試行版): https://toshikeikaku-info.jp/|
|道路施設点検データベース|道路|日本みち研究所|https://rirs.or.jp/tenken-db/|基礎DB(諸元・損傷判定区分など)のみ無料|
|地理院タイル|GISのベースマップ|国土地理院|https://maps.gsi.go.jp/development/ichiran.html| |
|OpenStreetMap|GISのベースマップ|OpenStreetMap Foundation|https://www.openstreetmap.org| |
|Overpass API|道路; 鉄道|OpenStreetMap Foundation|https://z.overpass-api.de/|OpenStreetMapから道路網など地物のベクターデータを得られる|
|GTFSデータリポジトリ|バス|社会基盤情報流通推進協議会, 日本バス情報協会|https://gtfs-data.jp/| |
|東京都市圏PT|PT|東京都市圏交通計画協議会|https://www.tokyo-pt.jp/person/02|近畿PTや中京PTなどは国土数値情報に断片的に存在|
|JARTIC|道路交通量; 交差点制御|JARTIC|https://www.jartic.or.jp/service/opendata/| |
|郵便番号データダウンロード|ジオコーディング|日本郵便|https://www.post.japanpost.jp/zipcode/download.html|1レコード1行のutf_all.csv(2023年6月公開)を使うと良い|
|日本歴史地名統合データベース|行政区域;地名|ROIS-DS CODH|https://geoshape.ex.nii.ac.jp/rekichime/||
|交通事故統計情報|道路|警察庁|https://www.npa.go.jp/publications/statistics/koutsuu/opendata/index_opendata.html||
いいコード悪いコードまとめ15章設計の意義と設計への向き合い方

# 課題を見据えているか
課題が見えないとそもそも設計する意識が生まれない

# メソッド10行以内、クラス100行以内か
RuboCopのデフォルトでは、コードの行数とクラスの行数が10と100だ。違反すると警告される。

#　サイロマティック複雑度が15以内に収まっているか
| 循環的複雑度 | 複雑さの状態 | バグ混入確率 |
|:-:|:-:|:-:|
| 10以下  |非常にいい構造  |25%   |
| 30以上  |構造的なリスクあり   |50%   |
| 50以上  |テスト不可能   |70%   |
| 75以上  |いかなる変更も誤修正を生む   |98%   |

#　クラス内部で取り扱う概念が4±1になっているか

#　コード分析をサポートする各種ツール
Code Climate Quality　
Understand 
VS Code シンタックスハイライト
c++のvector使うときのメモ


:::note warn
※「この記事は～」的な言い訳はめんどいので省略です。
正確な情報が必要な方は、ちゃんとした記事を参照ください。
:::

vector使うときのメモ。

# for文
```c++
vector<int> v = {1,2,3};
for (auto &itr : v) {
    printf("%d\n", itr);
}
```
### pairの場合
```c++
vector<pair<char, int>> v = {{'a',1}, {'b',2}, {'c',3}};
for (auto &[c, n] : v) {
    printf("%c %d\n", c, n);
}
```

# sort
### 昇順sort
```c++
vector<int> v = {3,1,2};
sort(v.begin(), v.end());
for (auto &itr : v) {
    printf("%d\n", itr); // 1, 2, 3
}
```

### 降順sort
```c++
vector<int> v = {3,1,2};
sort(v.begin(), v.end(), greater<int>{});
for (auto &itr : v) {
    printf("%d\n", itr); // 3, 2, 1
}
```
### 文字列もsortできる
```c++
vector<string> str = {"zac", "abc", "aaa", "zxx"};
sort(str.begin(), str.end());
for(auto i: str) {
    printf("%s\n", i.c_str()); // aaa, abc, zac, axx
}
```
### pairのsortはfirstを優先してsortする
```c++
vector<pair<char, int>> v = {{'a',2}, {'c',1}, {'a',1}};
sort(v.begin(), v.end());
for (auto &[c, n] : v) {
    printf("%c %d\n", c, n); // a 1, a 2, c 1
}
```
### ラムダ式でsortの条件を指定できる
```c++
vector<int> v = {3,1,2};
// trueを返すと x が左側になる
sort(v.begin(), v.end(), [](auto x, auto y){return (x > y);});
for (auto &itr : v) {
    printf("%d\n", itr); // 3, 2, 1
}
```

```c++
vector<pair<char, int>> v = {{'a',2}, {'c',1}, {'a',1}};

auto func = [](auto x, auto y) {
    if (x.second > y.second) {
        return true;
    }
    else if (x.second < y.second) {
        return false;
    }
    else if (x.first > y.first) {
        return true;
    }
    else {
        return false;
    }
}; // この例ではsecondで降順sortしたあと、firstで降順sortする

sort(v.begin(), v.end(), func);
for (auto &[c, n] : v) {
    printf("%c %d\n", c, n); // a 2, c 1, a 1
}
```
# 重複削除
```c++
vector<int> v = {5,2,9,6,1};
sort(v.begin(), v.end()); // sortは必要。

v.erase(std::unique(v.begin(), v.end()), v.end()); // uniqすると後ろにゴミが残るので、eraseも必要
```

# 連結
```c++
a.insert(a.end(), b.begin(), b.end()); // aのうしろにbを連結。
```


# 二分探索
### binary_search と lower_bound でだいたい足りる気がするけど
```c++
vector<int> v = {5,2,9,6,1};
sort(v.begin(), v.end()); // sortは必要。

// 2文探索して、見つかったらtrueを返す
bool result = binary_search(v.begin(), v.end(), 3);
printf("%s\n", result ? "ok" : "ng"); // ng

// 5以上の要素のうち、いちばん最初のイテレータを返す。
auto itr = lower_bound(v.begin(), v.end(), 5);
printf("%d\n", *itr); // 5

// イテレータから、配列で使うindexを求めたいなら、begin()とのdistanceをとる。
int i = distance(v.begin(), itr);
printf("%d\n", i); // 2
```
### たまにupper_boundを使いたいときもある
```c++
vector<int> v = {5,2,9,6,1};
sort(v.begin(), v.end()); // sortは必要。

// 5より大きい要素のうち、いちばん最初のイテレータをかえす。
auto itr = upper_bound(v.begin(), v.end(), 5);
printf("%d\n", *itr); // 6
```
【Excel】選択したCSVファイルを一括で読み込むだけ

・ログCSVを画面ぽちぽちして読み込むのが嫌すぎた
・見ればなんとなくわかるけどあまり書いたことない

## やりたいこと

- 指定したcsvファイル(複数選択可)のデータをほぼ加工なしでExcelに一括で1ファイル＝1シートで取り込む
- 値の前後に入る空白、および囲みのダブルクォートだけ削除
- シート名称＝取込CSVファイル名称
- 極力簡潔にしたい（業務で使用する際に長いと書くのが面倒）


## CSVファイル一括読み込みできた

```vb:ImportAllCSVFiles
Sub ImportAllCSVFiles()
    Dim ws As Worksheet
    Dim csvPath As Variant
    Dim csvFileName As String
    
    ' ファイルダイアログで複数のCSVファイルを選択
    csvPath = Application.GetOpenFilename("CSVファイル (*.csv), *.csv", , , , True)

    ' 選択されたファイルが配列の場合
    If IsArray(csvPath) Then
        For Each csvFile In csvPath
            csvFileName = Dir(csvFile)
            
            ' 新しいシートを作成
            Set ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
            
            Dim qtbl As QueryTable
            
            ' CSV を開く
            Set qtbl = ws.QueryTables.Add(Connection:="TEXT;" & csvFile, Destination:=ws.Range("A1")) 
            
            With qtbl
                .TextFilePlatform = 65001        ' 文字コード(UTF-8)
                .TextFileCommaDelimiter = True   ' カンマ区切り
                .TextFileTextQualifier = xlTextQualifierDoubleQuote ' ダブルクォートをテキスト限定子として設定
                .RefreshStyle = xlOverwriteCells ' 上書き
                .Refresh                         ' 表示する
                .Delete                          ' CSVの接続を解除
            End With
            
            ' 空白文字をトリムする
            TrimSpaceCells ws
            
            ' ダブルクォートを削除する
            RemoveDoubleQuotes ws
            
            ' シート名をCSV名に設定
            ws.Name = Left$(csvFileName, InStrRev(csvFileName, ".") - 1)
        Next csvFile
    End If
End Sub

Sub TrimSpaceCells(ws As Worksheet)
    Dim rng As Range
    For Each rng In ws.UsedRange
        ' セルの値から前後の空白を取り除く
        rng.Value = Trim(rng.Value)
    Next rng
End Sub

Sub RemoveDoubleQuotes(ws As Worksheet)
    Dim rng As Range
    For Each rng In ws.UsedRange
        ' セルの値がダブルクォートで囲まれている場合のみ処理
        If Left$(rng.Value, 1) = """" And Right$(rng.Value, 1) = """" Then
            ' ダブルクォートを削除
            rng.Value = Mid$(rng.Value, 2, Len(rng.Value) - 2) 
        End If
    Next rng
End Sub
```

---

## ざっくり解説

### ImportAllCSVFiles
CSVファイルをインポートして、ワークブック内に新しいシートとして追加。
ファイルダイアログから複数のCSVファイルを選択させ、選択されたファイルごとに新しいシートを作成。
各シートに対してCSVファイルを読み込み、後述の処理（空白トリム、ダブルクォート削除）を行う。

### RemoveDoubleQuotes
セルの値前後のダブルクォートを取り除く。

### TrimSpaceCells
全てのセルから前後の空白を取り除く。（テキストでの読込時に空白が残ってしまうため）


## 使用した主な関数

### Dir
指定したフォルダ内のファイル名やフォルダ名を取得するために使用。
引数にフォルダのパスを与えると、フォルダ内のファイル名やフォルダ名を取得可能。CSVファイルのファイル名を取得するために使用。

### QueryTables.Add
データクエリの実行で外部データをワークシートに取り込むために使用。
Connectionパラメータにファイルのパスを指定、Destinationパラメータに取り込んだデータの配置場所を指定する。そのほか、テーブルスタイルの指定や元データ自動更新の設定等も可能。

### Trim
文字列の前後から空白文字（スペースやタブ）を削除する。
例) ”  Hello  “では“Hello”という文字列に変換


## 参照
[VBA CSV ファイルの読み込み (QueryTables.Add 関数を使う)](https://www.tipsfound.com/vba/18014-vba)
[VBA入門：Excelのマクロを基礎から学習｜エクセルの神髄](https://excel-ubara.com/excelvba1/)


---
感覚的に「これ出来るよね？」と思ったことは大抵多少はどうにか出来る印象を受けました。
ただし拡張子や文字コード、データ内容によって扱いやすさにかなり差があるなとは思うので、わかりやすいところから手をつけていきたいですね。
AWS Certified Cloud Practitionerに合格したの色々まとめてみた

# 概要
部署でAWS認定試験の受験が五月蠅く言われています。業務に役立つという訳でもなく、試験の内容はしょっちゅう変更されるため、資格自体の取得の価値はそれほど高くなく、そして何より報奨金や成果評価の対象外。。。何ともモチベーションが出ない状況ですが、受験を強制されて、筆者の他の資格取得計画に影響が出ると困ります。先手を打とう！！とAWS Certified Cloud Practitioner(以下Cloud Practitioner)を受験し、:cherry_blossom:合格:cherry_blossom:したので記憶が薄れないうちに実際に実施した試験対策等の情報をDumpしておこうと思います。

# そもそもどんな試験?
AWS認定試験は全部で12種類存在します。Cloud Practitionerはその中で最も基礎的な知識を問う試験です。受験料は流石ベンダー試験。諭吉さんと数枚の英世さんが飛んでいきます。しょっちゅう試験の問題を改訂するのですから、良心的な価格設定にして貰いたいものです。ボッタクリ価格も良い所です。因みに筆者は勤務先がAWSとパートナーであるため、バウチャーコードが貰えました。よって自己負担は0円でした。

https://aws.amazon.com/jp/certification/exams/

https://aws.amazon.com/jp/certification/certified-cloud-practitioner/

# 実際の試験対策
以下のUdemyの模擬試験問題を繰り返し解きました。この模擬試験は実際の試験より難易度が少し高めであると思います。よって、逆に安心して試験に臨めると思います。

:warning: 模擬試験では100分で65問ですが、実際は前半5分と後半5分はアンケートに回答する時間となっています。よって実質試験時間は90分です。筆者は1通り回答して見直しを1回しても30分ぐらい時間が余りました。

https://www.udemy.com/course/aws-4260/

ハンズオンを通してAWSを理解しながら試験対策を行うという講座も有りますが、これは好みが分かれると思います。この講座は情報量が多く、あまり体系的でもありません。もう少し試験によく出る範囲に絞った内容の方が見やすいと思います。(あくまで個人の感想)試験に合格するだけであれば、模擬試験を繰り返す方が良いと思います。また、模擬試験の正答率が高くなるに従ってAWSの機能やサービスの内容について理解が進むと思います。筆者はAWSの実際の操作の理解はこれから上のレベルの受験対策をしながら進めていこうと思っています。

https://www.udemy.com/course/ok-aws-e/

# 受験時の備忘録
筆者はテストセンターで受験したため、テストセンターで受験する時の内容です。

## 身分証は2種類必要
通常身分証明は1種類(多くの場合、運転免許証)で良い場合が多いと思いますが、何故かこの試験では2種類必要です。筆者は免許証＋勤務先の社員証を持参しました。

https://www.pearsonvue.co.jp/Test-takers/Tutorial/Identification-1S.aspx

## テストセンターのページから予約すればポイントが貯まる
テストセンターでポイントカードを貰いました。試験センターのページから予約して試験を受けるとポイント(スタンプ)が貯まり、満点になると金券と交換して貰えるとのこと。次からはこの制度を利用することにします。

# 受験時のハプニング

* 試験時間が模擬試験と異なっていた。
    * これは上述の通りです。しかし、試験対策をしっかりやっていれば十分時間内に全問解答出来ます。

* 知らないサービス名が。。。
    * ハンズオン付き講座も一応やっていたのですが、矢張り試験範囲が広いためか知らないサービスの出題も有り、消去法で解答しました。

* 会場のPCのマウスが。。。
    * マウスの反応が悪く、クリックしても画面が前に進まないということが何度も有り、これは正直とても焦りました。。。

# まとめ
AWS認定試験の最初の関門は突破しました。お次はSolution Architect Associateを近々記憶が薄れないうちに受験しようと思っています。
コードの構造や複雑さを示すVScode拡張機能

良いコード悪いコードという著書の中に循環的複雑度（サイクロマティック複雑度）という言葉が出てきました。これはコードの構造的な複雑さを示していて、条件分岐やループ処理が増える、ネストが増えるなどの要因によって循環的複雑度が高い数値を示します。以下はその目安です。

| 循環的複雑度 | 複雑さの状態 | バグ混入確率 |
|:-:|:-:|:-:|
| 10以下  |非常にいい構造  |25%   |
| 30以上  |構造的なリスクあり   |50%   |
| 50以上  |テスト不可能   |70%   |
| 75以上  |いかなる変更も誤修正を生む   |98%   |

これらは早期リターンやストラテジパターンなどにより低減可能です。


で、調べてみるとVS Codeの拡張機能に
`Codalyze - Code Complexity Report Generator`というものがありました。

Updateは2020年の8月で止まっていますが、使ってみた感じは結構良さげでした。
ただ、詳細は見れないのでその辺りは他にいいのがあったら使ってみたいなという感じです。
https://marketplace.visualstudio.com/items?itemName=selcuk-usta.code-complexity-report-generator

試しにやってみたらレポートが作成されました。
実行は以下の通り
```
Run
Use Ctrl + Shift + P (Windows) / Shift + Command + P (MacOS) shortcut and write Codalyze. Finally, run it!
```

こんなレポートが作成される。
![スクリーンショット 2023-07-23 21.29.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324306/fde76073-7636-2cbe-5304-ca5569d40339.png)
MOD Dwarfを無料で使ってみよう(3)

### はじめに

前回、[『MOD Dwarfを無料で使ってみよう(2)』](https://qiita.com/Inqb8tr_jp/items/897432306eb404bd9a6b)では、mod-osをビルドした後、さまざまなプラグインをビルドし、mod-osを実際に使える環境にしました。

今回はこちら([https://github.com/moddevices/mod-live-usb](https://github.com/moddevices/mod-live-usb))の最後にも記載がある、```live-welcome```とよばれるもののビルドと、最後のisoファイルの作成、Neural Amp Modeler lv2に利用するNAMファイルの取得方法とmod-osへの渡し方など実際の使い方を説明していきます。

### live-welcome

上記の説明ではlive-welcomeのビルドは```make -C live-welcome```とだけ記載がありますが、その前に依存するパッケージをインストールする必要があります。その依存関係は```mod-live-usb/live-welcome/Makefile```に記載があり、下記となります。

```
$ sudo apt install pkg-config libasound2-dev libjack-jackd2-dev
$ sudo apt install libqt5x11extras5-dev libqt5websockets5-dev qtwebengine5-dev
$ sudo apt install breeze libkf5parts-dev kate konsole-kpart
```

続いてmod-live-usbディレクトリの中でコマンドを実行します。

```
$ make -C live-welcome
```

ビルドが完了したら、オーディオインターフェースの番号を調べた後、```./mod-os/start.sh hw:1 48000 128```を実行し次のコマンドを実行します。


```
$ ./live-welcome/mod-live-usb-welcome.local
```

そうすると次のような画面が表示されます。

![Screenshot from 2023-07-22 22-37-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129361/93e0c4f3-a372-430e-8772-535a499b7dc7.png)


### 使ってみよう

少し休憩して、実際に使ってみましょう。

わたし自身まだ使いはじめたばかりなので、mod-osについて詳しくないですし、まずギターもいまだ初心者で、エフェクターも持っていません。あるのはパソコンについないだオーディオインターフェース、モニタースピーカー、エレキギターなどです。

ですのではっきり言って、ペダルボードを一から設計する知識も経験も持ち合わせていません。

それでも上記のペダルボードを組めたのは、MOD Dwarfを作った会社であるMOD AUDIOがペダルボードを公開([https://pedalboards.moddevices.com/](https://pedalboards.moddevices.com/))していてくれるからです。

上記スクリーンショットはこちら([https://pedalboards.moddevices.com//pedalboards/647ad8c0725e7c37b4667119](https://pedalboards.moddevices.com//pedalboards/647ad8c0725e7c37b4667119))をコピーしたものです。(CalfのPhaserはplugins内のMakefileをいじらないとビルドできませんが...)音を聴けるペダルボードもあるので、最初は模倣からはじめるのがよいと思います。

また、mod-osの画面の左下からもペダルボードが選択できるようになっています。


### Neural Amp Modeler


ではAIDA-XをNeural Amp Modelerに置き換えてみましょう。

![Screenshot from 2023-07-23 09-38-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129361/072150b0-fa4b-9cd4-e480-e8facaecc900.png)

まず、Neural Amp Modelerとは何かということですが、オープンソースの機械学習でアンプやペダルを学習させたアンプ、ペダルシュミレーターでしょうか。

同じく機械学習を使ったAida-Xもありますが、Neural Amp Modelerの方が公開されている学習したモデル(namファイル)がはるかに多いです。

namファイルはToneHunt([https://tonehunt.org/](https://tonehunt.org/))からダウンロードできます。

mod-osにはnamファイルは用意されていませんので、ダウンロードして```mod-live-usb/rwdata/user-files/NAM Models```に保存してください。namファイルが使えるようになります。


### isoファイルを作ろう

最後に『MOD Dwarfを無料で使ってみよう(1)』で作成したisoファイルを今まで作成してきたイメージで作成してみましょう。

mod-live-usbディレクトリの中でコマンドを実行します。

```
$ make iso
```

また時間がかかりますが、ビルドが完了すると```mod-live-usb/archiso/output/mod-live-usb-v9-x86_64.iso```が作成されるので、Balena Etcherを使ってisoイメージをUSBメモリに書き込みます。

あとはUSBメモリを差し込んでパソコンを再起動したらmod-live-usbが動くはずですが、わたしがUbuntuとDebianで作成したisoファイルは、起動はするもののうまく動作しませんでした。

これはfalkTXさんから回答をいただいたのですが、今現在、isoファイルは動かないということで、isoファイルを使いたいなら、公開されているものを使いましょう。
タスク管理　スケジューラとディスパッチ、スケジューリングアルゴリズム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/236f0cbe-0950-dc3f-feac-fa9cfd8a3feb.png)
　スケジューラは、実行可能な状態のタスクを１つ選ぶ機構です。スケジューラによって選ばれたタスクは、実行状態に移されます。実行状態に移すことを「CPUを割り当てる」とか「ディスパッチする」といいます。

　スケジューラが実行可能状態のどのタスクを選ぶのかを決める手順をスケジューリングアルゴリズムといいます。
【Swift】大文字小文字を区別しない検索機能の作り方3選


# はじめに
Swiftで大文字小文字を区別しない検索機能を作る方法を紹介します。

# 作るもの
文字列の配列から、検索キーワードを含む文字列を抽出するプログラムを作ります。

# やり方
## #1
一つ目は、`StringProtocol`の`localizedCaseInsensitiveContains`メソッドを使う方法です。
このメソッドは大文字小文字を区別せずに、引数の文字列を含むかどうか判定します。

```swift
import Foundation

func search(_ keyword: String, in strings: [String]) -> [String] {
    strings.filter { $0.localizedCaseInsensitiveContains(keyword) }
}

let strings = ["Apple", "Banana", "Orange", "Grape", "Peach", "Pineapple"]
let keyword = "apple"

let result = search(keyword, in: strings)
print(result) // ["Apple", "Pineapple"]
```

## #2
二つ目は、`StringProtocol`の`range(of:options:)`メソッドを使う方法です。
このメソッドは、引数の文字列を含む場合はその範囲を、含まない場合は`nil`を返します。
optionsに`.caseInsensitive`を指定することで、大文字小文字の区別をなくせます。

```swift
import Foundation

func search(_ keyword: String, in strings: [String]) -> [String] {
    strings.filter { $0.range(of: keyword, options: .caseInsensitive) != nil }
}

let strings = ["Apple", "Banana", "Orange", "Grape", "Peach", "Pineapple"]
let keyword = "apple"

let result = search(keyword, in: strings)
print(result) // ["Apple", "Pineapple"]
```

## #3
三つ目は、`lowercased`を使って検索される文字列と検索キーワードを小文字に変換してから判定する方法です。
```swift
import Foundation

func search(_ keyword: String, in strings: [String]) -> [String] {
    strings.filter { $0.lowercased().contains(keyword.lowercased()) }
}

let strings = ["Apple", "Banana", "Orange", "Grape", "Peach", "Pineapple"]
let keyword = "apple"

let result = search(keyword, in: strings)
print(result) // ["Apple", "Pineapple"]
```

# まとめ
1番目の方法が一番簡単ですね。検索機能のあるアプリを作るときはぜひ試してみてください。この記事が参考になったという方は、いいねとフォローよろしくお願いします。

# 参考リンク
https://developer.apple.com/documentation/swift/stringprotocol/localizedcaseinsensitivecontains(_:)

https://developer.apple.com/documentation/swift/stringprotocol/range(of:options:range:locale:)

https://developer.apple.com/documentation/foundation/nsregularexpression/options/1417830-caseinsensitive

https://developer.apple.com/documentation/swift/stringprotocol/lowercased()
RAID01と10の違い【備忘録】

# なぜ今更？

　概念的に理解をしていても、どういうわけか01と10の特徴がなぜか頭に定着せず、一応、10のほうが良いとは感覚的にわかっていても、いざ説明しろと言われると自信がなくて毎回調べているのでキッパリ備忘録として書いておきます。
　また忘れるようなら印刷して醤油をつけて食べます。

## RAIDについて

　「ストレージ冗長化の技術」という理解で、RAID0はストライピング、RAID1はミラーリングで１台、RAID5はパリティを分散したストライピングで1台故障まで対応…みたいな感じで感覚的に覚えてます。
　あくまでRAIDは「ストレージの冗長化」であり、データを保全する「バックアップ」とは違うのでその認識は大事である。

## それぞれについて

### 共通

* 速度は同等
* 全体的に見ると冗長化はなされている

### RAID01

　ストライピングをしたものをミラーリングするRAID
* メリット
    * アクセスが比較的高速
    * 冗長構成が取れている
* デメリット
    * 全体では冗長化されているが、グループ単位での冗長化がされていないので、例えばHDD1が死んでしまうとHDD1と2で構成しているミラーリンググループは死んでしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238748/eac8cf91-24de-9618-759a-1e225a77651e.png)

### RAID10

　ミラーリングしたものをストライピングするRAID
* メリット
    * アクセスが比較的高速
    * 冗長構成が取れている
    * グループ単位での冗長化がされているため、グループ内で1台故障までは許容。グループを跨いで2台までの故障は許容する。
* デメリット
    * グループ内で2台故障したらアウト。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238748/1387e917-5ea3-d000-05e5-ec2242a02a71.png)

## 総評

　ストレージの必要台数はRAID10もRAID01も同じなので、どうせやるならグループ単位での冗長化もされているRAID10がおすすめ。RAID01は確かにできるけどやる意味はあまりない印象。
　RAID0を1する、RAID1を0する、で覚えると良いのかもしれない？
SwiftUI StepperのようなUIの実装方法


https://qiita.com/yuta317/items/4f9744d4dfc6202a3576

Stepperを実装してみたのですが、画像など見た目をカスタムしてみたかったので、今回はStepperのようなUIの実装方法です。

Xcode Version 14.2

```StepperSumpleView.swift
struct StepperSumpleView: View {
    @State var value: Double = Double(0)
    var step = 1.0/10
    var body: some View {
       HStack {
                Text("\(Int(value * 10.0))").font(.system(.caption, design: .rounded))
                Spacer()
                
                Button(action: {
                    if self.value > 0 {
                        self.value -= self.step
                    }
                }, label: {
                    Image(systemName: "minus.circle.fill")
                        .foregroundColor(value > 0 ? Color.blue : Color.gray)
                })

                Button(action: {
                    if self.value < 1 {
                        self.value += self.step
                    }
                }, label: {
                    Image(systemName: "plus.circle.fill")
                        .foregroundColor(value < 1 ? Color.blue : Color.gray)
                })
            }.frame(width: 250)
    }
}
```

![スクリーンショット 2023-07-23 20.31.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/5d149969-ff40-6d5f-9623-104229f17bcb.png)

このような実装してみました。
プラスボタンを押したら結果をプラスする。マイナスが押されたら値をマイナスにするので、さほど複雑な実装をしなくてもできそうですね。
【Android】一定時間毎に何かをする処理【Kotlin】

# 実践

```
 Timer().schedule(0, 1000) {
            // 繰り返し行いたい処理
        }
```

Timer().schedule()というものを使っていきます。
Android 公式では 
> 指定された遅延後に開始される、 指定されたタスクの繰り返し固定遅延実行をスケジュールします。
とあります。


第一引数に　何秒後に開始するか。（m秒）
第二引数に　何秒毎間隔で実行するか。（m秒）
処理を終わらせたい場合は　{}内に　　**this.cancel()** でTimer()をキャンセルすることで繰り返し処理をキャンセルできる。

# 終わりに
こういった時間を使う系のものは少し前に記事にした、Handlerなんかでもできるんだろうなと思いつつ、あえて違う方法でやってみました。
どちらが使いやすくて、どういったメリットデメリットがあるのか　イメージしながら実装していくためにもう少し知っていきたいですね。


# 参考

https://developer.android.com/reference/java/util/Timer
DockerちゃんにError response from daemon: driver failed programming external connectivity on endpointって怒られた💦

## Dockerちゃんと遊んでいたとき
Error response from daemon: driver failed programming external connectivity on endpoint　〜　Bind for 0.0.0.0:80 failed: port is already allocated

って怒られたwww

## 原因
他のサービスでこのポートを使っているから
## やってみたこと
停止中のコンテナを一括削除
```
$ docker image prune
```
まだ削除できない・・・。
docker psコマンドで一覧を表示して
```
$ docker ps 
```
ポートが被ってるコンテナIDを探して

```
$ docker rm --force コンテナID
```
で削除できた！

## おわりに
Dockerちゃんと仲直りできたー☺️
## 参考記事
[Docker一括削除コマンドまとめ](https://qiita.com/boiyama/items/9972601ffc240553e1f3)
[Dockerでコンテナの停止・削除ができなくなった時の対処法](https://qiita.com/musatarosu/items/31d6293a93e75ca6073e)
Zabbix6.0とGrafanaを連携する

# 環境
OS:CentOS8
zabbix6.0
Grafana10.0.2
PostgreSQL14

# インストール
公式ドキュメント通り

https://grafana.com/grafana/download?edition=enterprise&platform=linux

```bash
[admin@hostname ~]$ sudo yum install -y https://dl.grafana.com/enterprise/release/grafana-enterprise-10.0.2-1.x86_64.rpm
[admin@hostname ~]$ sudo systemctl start grafana-server.service
[admin@hostname ~]$ sudo systemctl enable grafana-server.service
```

# Zabbix連携プラグインインストール
ドキュメント通りインストール、完了後Grafanaの再起動

https://grafana.com/grafana/plugins/alexanderzobnin-zabbix-app/

```bash
[admin@hostname ~]$ sudo grafana-cli plugins install alexanderzobnin-zabbix-app
✔ Downloaded and extracted alexanderzobnin-zabbix-app v4.3.1 zip successfully to /var/lib/grafana/plugins/alexanderzobnin-zabbix-app

Please restart Grafana after installing or removing plugins. Refer to Grafana documentation for instructions if necessary.

[admin@hostname ~]$ sudo systemctl restart grafana-server.service
```

# 初期設定

## Grafanaへのアクセス
ブラウザからインストールしたサーバの3000番ポートへアクセス
```
http://<<IP ADDRESS>>:3000
```
下記ユーザ、パスワードでログイン後パスワード変更
user : admin
padd : admin

## プラグイン有効化
設定のプラグイン一覧からZabbixを選択し有効化
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242165/e9c54ae9-2e5b-9c15-a05c-7839d6291e6f.png)

## データソース設定(PostgreSQL)
ZabbixのDirect DB Connectionを使いたいのでPostgreSQLのデータソースを追加。
Direct DB Connectionを利用しない場合は設定不要。
HOME > Connections > Data sources > PpstgreSQL　に移動。
下記画像の赤枠で示した接続情報を入力。
完了後下部の「Save & test」を押下。
エラーが出なければ完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242165/cfbbf277-df28-23de-8ca7-a7d4c1885707.png)

## データソース設定(Zabbix)
HOME > Connections > Data sources > Zabbix　に移動。
パラメータを入力。
URLはZabbixサーバのURLを指定。今回は同じサーバにインストールしたため以下を入力。
```
http://localhost/zabbix/api_jsonrpc.php
```
Username, Password はZabbixのログイン時に使用する物を入力。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242165/04acc606-88d3-8138-b0b5-4d5a8141c653.png)
Direct DB Connectionを利用する場合は有効化し、先ほど作成したデータソースを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242165/1e8ba304-aed0-f263-e2e6-6a5bb6cd1238.png)

完了後下部の「Save & test」を押下。
エラーが出なければ完了。問題なければ下記メッセージが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242165/4ba0e562-4c4d-f583-37f8-425788d5317c.png)

# ダッシュボード作成
はよしなにやってください。
Unity　TopDown Engineのデモシーンをhdrp化

# 概要
TopDown Engine　3Dデモシーンのhdrp化の手順を記録に残します。

# 開発環境
OS:Windows10
Unity:2020 3 42(LTS)
TopDown Engine:3.2


# 手順

## 1.プロジェクト作成時にhdrpを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/ccd8788f-1dec-4e78-6482-06d897424724.png)



## 2.TopDown Engineをインポート　MinimalAI3Dを開く
以下画像　最初の状態
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/de95aa97-d2b3-af77-863d-c09d877a0304.png)



## 2.スクリプタブルレンダーパイプライン設定する
上部のメニューバーの編集タブ→プロジェクト設定を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/2394cbef-8f76-35ed-a933-99dffd997212.png)

グラフィックスの項目を選択肢、パイプラインを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/66a84551-3c11-dc6f-9045-df08ab0eeb56.png)


パイプライン設定後、シーン内のオブジェクトがピンクになります。
オブジェクトのマテリアルがbuildin対応になっているのが原因です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/26977c0f-49f3-684c-7636-97735ad7ed28.png)


## 3.マテリアルをBuildinからHDRP対応に変換
上部のメニューバー
→編集
→Render Pipeline 
→ HDR Render Pipeline
→Upgrade from buil
→Upgrade Project Materials to High Definition Materials

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/824683d4-ed73-d80f-c6de-a98c7328c65b.png)


マテリアル更新後の様子
UIと非UI共にhdrp化ができています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/ff666676-147c-e7c5-f58c-868e6fa2334d.png)



# 参考
## Unity公式ドキュメント

https://docs.unity3d.com/ja/Packages/com.unity.render-pipelines.high-definition@10.5/manual/Upgrading-To-HDRP.html

## TopDown Engine ドキュメント
BuildinからURP変換の方法が書かれてある。UIが表示されなくなる対処方法が書かれている。HDRP化の際には必要ない？

https://topdown-engine-docs.moremountains.com/install.html


## github コミット（private）

https://github.com/RYA234/unity-hdrp/commit/eccd36b94429c4fa4e966404e0e6c58115fe6e93
Jetpack Composeのテストで出てくるmerged tree、unmerged treeとは何か

かなり基本的なことなんですが、よく分かっていない方も多いのではと思い書いています。
Jetpack Composeで開発していて以下のようなエラーに遭遇しました。

Composeのコード

```kotlin
NavigationBarItem(
    selected = selected,
    onClick = {
        ...
    },
    icon = {
        Icon(
            imageVector = tab.icon,
            contentDescription = "Hoge",
        )
    },
)
```

テスト

```kotlin
composeTestRule
  .onNodeWithContentDescription("Hoge")
  .performClick()
```

エラー

```
java.lang.AssertionError: Failed to inject touch input.
Reason: Expected exactly '1' node but could not find any node that satisfies: (ContentDescription = 'Hoge' (ignoreCase: false))
However, the unmerged tree contains '1' node that matches. Are you missing `useUnmergedNode = true` in your finder?
```

訳: `Hoge = ContentDescription`を持つノードが見つからなかったよ。
でも、unmerged treeには見つかったから、`useUnmergedNode = true` 忘れていませんか？

さてさて、useUnmergedNode = trueにしたらいいのかな？


# ドキュメントを見る

https://developer.android.com/jetpack/compose/testing

`Using the unmerged tree` というドキュメントが普通に分かりやすいです。

ボタンとかいくつかのコンポーネントは子のコンポーネントをテストからデフォルトで見える木では勝手にマージしちゃうようです。

```kotlin
MyButton {
    Text("Hello")
    Text("World")
}
```

が以下のようになります。

```shell
Node #1 at (...)px
 |-Node #2 at (...)px
   Role = 'Button'
   // **２つあったテキストが一個になってまとまっている**
   Text = '[Hello, World]'
   Actions = [OnClick, GetTextLayoutResult]
   MergeDescendants = 'true'
```

useUnmergedNode = trueを使うと以下のようになります。 (ドキュメントに書いてあるとおりですが。)

```shell
Node #1 at (...)px
 |-Node #2 at (...)px
   OnClick = '...'
   // ここにMergeDescendants = 'true'がある
   MergeDescendants = 'true'
    |-Node #3 at (...)px
    // ちゃんとTextが分かれている
    | Text = '[Hello]'
    |-Node #5 at (83.0, 86.0, 191.0, 135.0)px
      Text = '[World]'
```

useUnmergedNode = trueを使うとwithTextなどで"Hello"などが探せる。というわけです。


# なぜこのまとめる現象が起こるのか

Modifierに.semantics()という関数が生えています。これに引数を`semantics(mergeDescendants = true)`のように渡すことで子孫がテストでマージされます。
これをButtonの中で使っています。
正確にはButtonの中でModifier.clickable()を使っていて、これを使うと `this.semantics(mergeDescendants = true)`が使われます。

**つまりクリックできる要素があるとだいたいmergeDescendants = trueされて、その子孫がまとめられる。** ということなので、テストを書くときに意識したほうが良さそうです。

# で、結論としてuseUnmergedNode = true使う？

多分今回に関してはuseUnmergedNode = trueにしてクリックするのでも動くんですが、クリックする要素などにTestTagなどをつけて、それをテストで使うほうがクリックしたいものとテストを関連付けする意図では良さそうに見えました。

# 参考

https://developer.android.com/jetpack/compose/testing

https://developer.android.com/jetpack/compose/semantics
AWS EC2 に Chromebook で SSH 接続するまで

<h2>勉強用のChromebook でも AWS 使いたくなったので接続できるまでの手順を確認

<h3>アーキテクチャ

![AWS_Architecture_20230723.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/ec3ab199-9110-8ec5-7f08-b7a2ba308e72.jpeg)

<h2>作業手順一覧
<h4>
    1: VPC 作成<br>
    2: サブネット 作成<br>
    3: インターネットゲートウェイ 作成<br>
    4: VPC にインターネットゲートウェイ をアタッチ<br>
    5: ルートテーブルに インターネットゲートウェイ を関連付け  <br>
    6: キーペア を作成<br>
    7: EC2 インスタンス作成<br>
    8: Linux ファイル フォルダに作成した キーを移動<br>
    9: ターミナルで SSH 接続設定<br>
    10: 設定したSSHで接続
<hr>
<h4>1: VPC 作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/84a0f056-d2bc-5e44-34b2-b8ebb21ef302.png)

<h4>2: サブネット 作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/6e93e1ec-a356-3ab9-e924-d75df95c22f8.png)

<h4>3: インターネットゲートウェイ 作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/51cd91ef-6578-5799-f855-47044cad1dcf.png)

<h4>4: VPC に インターネットゲートウェイをアタッチ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/c3860cfe-6115-f326-adbf-2a56a735f70a.png)

<h4>5: ルートテーブル に インターネットゲートウェイ を関連付け

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/f741fda0-f7b6-0a7e-9ee9-f6de071a693f.png)

<h4>6: キーペアを作成

※タイプ:ED25519   形式:.prem を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/b3da7eb7-40d2-860b-8ba2-ac1358900821.png)

<h4>7: EC2 インスタンス作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/f5f1b710-6da3-5568-acce-4f3a42729165.png)
・作成したキーペアを選択
・VPC, サブネットは作成したものを選択
・パブリックIPの自動割り当て 有効化 を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/a2de36f3-d6af-7658-1e0c-0e71771ce5ca.png)

<h4>8: Linux ファイル フォルダに作成した キーを移動

※Linux ファイル 内であれば任意の場所でOK
![Screenshot 2023-07-23 17.45.49_edited.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/b7a69bfe-73fb-ae93-ef8b-66717b143507.jpeg)

<h4>9: SSH 接続設定

Chrome ターミナル から +SSHを追加 を選択して情報を入力
※ターミナルに関しては 設定>詳細設定>デベロッパーから Linux開発環境>オンにする を選択すれば表示されます
コマンド[ssh ユーザー@接続先]
・ユーザー: EC2 デフォルト[ec2-user]
・E接続先: C2 の パブリックIPv4 アドレスを参照
![Screenshot 2023-07-23 17.59.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/542ef84a-8591-0212-4e1c-75e6ed409dff.png)

・インポート から 作成した キーを選択
![Screenshot 2023-07-23 18.02.14_edited.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/36576c9b-1add-924f-74a4-b30a4d1f939c.jpeg)

<h4>10: 設定したSSHで接続

・接続の確認画面が表示されるので yes を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/e52f636a-a291-c91c-d4c2-8d27f49668aa.png)

・接続完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/90f453ae-3289-10df-a622-0287a446add8.png)

Chromebook だと一度SSH接続設定してしまえば何度も接続できるのは楽
EC2 起動する度にパブリックIPアドレスが変更になってしまうので、Elastic IP で静的にIP決めてしまえば完璧
ビットノート｜仮想通貨初心者のためのWebメディア

bitnote(ビットノート)は仮想通貨初心者のために作られたWebメディアです。仮想通貨投資歴6年でプロの金融マンの管理人が、おすすめの仮想通貨銘柄や取引所の情報を発信しています。

ここではビットノートのおすすめの記事を紹介します。

・ビットノート公式サイト
https://bitnote.jp/

・【厳選】おすすめの国内仮想通貨取引所3選！初心者向けに徹底比較ランキング
https://bitnote.jp/crypto-exchange-ranking/

・【厳選】海外仮想通貨取引所おすすめランキング3選！【日本語対応のみ】
https://bitnote.jp/crypto-exchange-ranking-overseas/

・【スマホで完了】Bybit(バイビット)の登録・口座開設方法を画像付きで解説
https://bitnote.jp/bybit-register/

・【スマホで完了】MEXC(エムイーエックスシー)の登録・口座開設方法を画像付きで解説
https://bitnote.jp/mexc-register/

・【スマホで完了】Gate.io(ゲートアイオー)の登録・口座開設方法を画像付きで解説
https://bitnote.jp/gateio-register/

・【スマホで完了】Coincheck(コインチェック)の登録・口座開設方法を画像付きで解説
https://bitnote.jp/coincheck-register/

・【スマホで完了】bitFlyer(ビットフライヤー)の登録・口座開設方法を画像付きで解説
https://bitnote.jp/bitflyer-register/

・【スマホで完了】bitbank(ビットバンク)の登録・口座開設方法を画像付きで解説
https://bitnote.jp/bitbank-register/
Web技術について

# リクエスト・レスポンス

⚪︎登場するもの
+ PC
+ Webサーバ

(例)
PCでChromeで『天気』と検索したとする。

1.PC(クライアント)から天気という情報をくださいとWebサーバにリクエスト(要求)を送る
2.Webサーバが天気の情報をPCに返す(応答)

下記の画像のイメージ↓
![http-get-post1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510594/c9f8f229-b83a-ebde-8e56-1658e0a479e8.jpeg)

# ステートフル・ステートフル

### ステートフル
簡単に言えば状態を保存できる。

(例)行ったことがある病院に通院したのをイメージしてほしい
自分:先月よりも風の調子が良くなりました。
医者:こないだよりも良くなりましたねー。

前回の診療内容と照らし合わせているので会話が簡略化している。

### ステートレス
こちらは状態が保存できない

(例)初めて病院に通院する場合
自分:昨日から風邪を引いてしまって...
医者:鼻水出ますか？咳出ますか？頭痛いですか？痰が絡みますか？熱何度ですか？

↑初めて通院した際は細かく聞かれる。
実際に通信の際にもこのように何回も通信しなくていけないので手間がかかるというデメリットがある。

# Cookie
簡単に言えばブラウザに保存する機能
(例)
ECサイトで買い物にした時にカートに入れて実際に購入する。
このカートに入れたデータはブラウザ(Cookie)に保存することによって他のページに飛んだとしてもカートに入れた商品の情報は
そのまま残すことができる。

:::note alert
※注意
個人情報をCookieに保存するのはNG
:::

# プロトコル
簡単に通信をする際のルール

(例)
+ モール信号
+ 手信号
+ 道路の信号

↑上記の信号はルールが存在する。

道路の信号では
赤:止まれ
黄色：止まれるなら止まれ
緑:通行OK

この通信でのルールがプロトコルである。

# ポート番号
ポート=港と言う意味がある。

これは、実際に通信する際に届け先で複数のアプリケーションが動いてた場合、どれに通信を届けたらいいか分からない。
これを解消するためにポート番号を指定して具体的にどのアプリケーションに届けるかを指定できる。

(代表の使用例)
+ TCP 20 : FTP (データ)
+ TCP 21 : FTP (制御)
+ TCP 22 : SSH
+ TCP 23 : Telnet
+ TCP 25 : SMTP
+ UDP 53 : DNS
+ UDP 67 : DHCP（サーバ）
+ UDP 68 : DHCP（クライアント）
+ TCP 80 : HTTP
+ TCP 110 : POP3
+ UDP 123 : NTP
+ TCP 443 : HTTPS
クレジットカードの決済方法

# MS

MS(Magnetic Stripe)磁気ストライプによる売上決済。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559029/7aea1d40-4a29-4e2f-8724-a580e6236ae8.png)

こんなやつですね。
日本政府はIC決済１００％を目指しているようで、どんどん少なくなっていくやつ。
不正利用されやすいようです。

# IC

ICチップでの売上決済。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559029/a1758f20-e0e2-f934-420f-ac48d85db13b.png)

# CL

コンタクトレス売上決済。別名NFC Pay。非接触での決済です。タッチ決済とも言うかも。
iDサービスや鉄道会社などで利用されています。
新人エンジニアが抑えておきたい必読書　リーダブルコードを読んで要点をまとめる

## はじめに
今回はエンジニアの必読書とされている「リーダブルコード」を読んでいく中で要点を整理し、実際の現場でコードを書いたりレビューをする際どのように活用していけば良いかを自分なりにざっくりとまとめました。

## 私について
未経験から独学でプログラミング学習し5ヶ月でLaravelでポートフォリオを作成しました。そして現在は自社開発企業に入社し、新人WEBエンジニアとして開発に携わっています。

### この記事を書いた理由
リーダブルコードは、コードを書く人全員が読むべき書籍とも謳われている名本です。
特に駆け出しエンジニア向けによくおすすめされており、
自分の知識定着の為アウトプットとして残しておきたいのと、実際に読んでみて未経験エンジニアや既に実務で活躍されている方々にも共有すべき内容と判断したため、この記事を書きました。(既に読んでいる方々は多いと思いますが💦)

## 記事の流れ
1. 優れたコードってなに？
2. 名前に情報を詰め込む
3. コメントの目的を理解する
4. ロジックを単純化する
5. コードに思いを込めよう
6. とにかくやってみよう

## 1.優れたコードってなに？

リーダブルコードで優れたコードとは「他の人が読んだ時に、コードの意味を理解するまでの時間を短くできるコード」と定義されています。

:::note info
大事なポイント！

・コードは他の人が最短時間で理解できるように書かなければならない

・コードは短く書いたほうがよいが「理解するまでの時間が短くなる」ほうが優先度は高いと挙げられてます。
:::
コードを短く書くことは大切だが、短く書くことによって他の人が読んだ時に理解に苦しむ(理解に時間がかかる)ようなコードでは本末転倒になってしまう！

これを防ぐ為、リーダブルコードを読むことで`「他の人が読んだ時に理解されやすいコードの書き方」`を学ぶことができます。

ここまで話を聞いて、つまりどうすればいいんだってばよ...！となったと思います。
次から解説していきます！！

## 2.名前に情報を詰め込む
例えば関数に「getPage」という命名をした場合、この関数getPageは何かしらのページ情報を取得してくることは名前から推測できますよね。

しかしgetPageという命名だと、下記のような疑問が出てくる可能性がある。

ページ情報はキャッシュから取得するのか
ページ情報はデータベースから取得するのか
ページ情報はインターネットから取得するのか

具体的にインターネットからデータを取得するのであれば「fetchPage」「DownLoadPage」といった命名の方が理解しやすい名前になります。

以上のことから、関数等を命名するときは「気取った言い回しよりも、明確で正確なほうを意識する」ことが重要になってくる。

:::note info
大事なポイント！

短さよりも意味の明確さの方が大事。
読み手に疑問を抱かせない。
:::

## 3. コメントの目的を理解する
全てにコメントを書けばわかりやすくなるものではありません！
コメントを書く前に、ソースコードをきれいにすることが第一。
下手なコードの不備を補うコメントは害にしかならないです。

:::note warn
価値のないコメント　→　コードを見たらすぐにわかる内容。
:::

:::note info
価値のあるコメント　→　自分の考えの記録。（なぜこのやり方にしたのか、定数の値にまつわる背景　etc...）
:::

どうすればいいか？



そもそもコメントの目的は書き手の意図を読み手に知らせること！
コメントの先頭で意味がわかるようにするとさらに読み手にわかりやすくなります。


例	
- TODO:	あとで手を付ける
- FIXME:	既知の不具合があるコード
- HACK:	あまり綺麗ではない解決策をしている
- XXX:	危険！大きな問題あり

:::note info
大事なポイント！

全体像のコメントと機能要約コメントをする。
コメントの先頭で意味がわかるようにする。
:::


## 4. ロジックを単純化する
コードの式は大きくなればなるほど理解が難しく、読み解くのに時間がかかってしまいます。
そこで、巨大な式を分割すると読みやすくなります。

どうすればいいの？

:::note info
大事なポイント！
巨大な式を分割するために一番簡単な方法は、「説明変数」を導入しよう。
メリット
・巨大な式を分割できる
・簡潔な名前で式を説明することで、コードを文章化できる
・コードの主要な「概念」を読み手が認識しやすくなる
:::

例
```php:index.php
if (trim(explode(':', $line)[0]) === "root")

↓分割すると

$username = trim(explode(':', $line)[0]);
if ($username === "root")

```

## 5. コードに思いを込めよう

`おばあちゃんに説明できなければ、理解したとは言えない。`
アルバート・アインシュタインの発言です。コードはそれくらい易しく書くべきですね。

複雑なロジックを説明するときに、詳しく話しすぎるとかえって相手を混乱させてしまいます。
自分よりも知識が少ない人でも理解できるような「簡単な言葉」で説明する能力が大切です。

:::note info
大事なポイント！

コードを「簡単な言葉」で書く手順は

コードの動作を簡単な言葉で同僚にもわかるように説明する
その説明の中で使っているキーワードやフレーズに注目する
その説明に合わせてコードを書く
:::


## 6. とにかくやってみよう

本やこの記事を見て、まずは実際にやってみるのが一番です。
先輩エンジニアや同僚エンジニアの方にコードを読んでもらい、改善していきましょう！

私が今現在とても足りないところなのですが、改善していきたいです。

自分より知識が少ない人でも理解できる簡単な言葉で説明する能力やコードを書く技術
簡単な言葉でロジックを明確に説明できるようになる。
問題や設計をうまく言語化できない場合は、自分の中で詳細が明確になっていないのでしっかりと理解する。

最後までお読みいただきありがとうございました。
早いうちから習慣化しておけばそれはきっと財産になります！共に頑張りましょう！
Ubuntuでdocker-compose

rails7 Ubuntuを使っています。

Gemfile
```
gem "rails", "~> 7.0.6"
```

Dockerfile
```
FROM ruby:3.1
# 公式→https://hub.docker.com/_/ruby

# Rails 7ではWebpackerが標準では組み込まれなくなったので、yarnやnodejsのインストールが不要

# ruby3.1のイメージがBundler version 2.3.7で失敗するので、gemのバージョンを追記
ARG RUBYGEMS_VERSION=3.3.20

# RUN：任意のコマンド実行
RUN mkdir /myapp

# WORKDIR：作業ディレクトリを指定
WORKDIR /myapp

# COPY：コピー元とコピー先を指定
# ローカルのGemfileをコンテナ内の/app/Gemfileに
COPY Gemfile /myapp/Gemfile

COPY Gemfile.lock /myapp/Gemfile.lock

# RubyGemsをアップデート
RUN gem update --system ${RUBYGEMS_VERSION} && \
    bundle install

COPY . /myapp
```

docker-compose.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: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
    stdin_open: true
    tty: true
volumes:
  mysql-data:
    driver: local
```

コマンド
```
docker-compose run --rm web rails new . --force --database=mysql
```
【VBA】AIに聞いてみたことメモ

VBAでの処理時間を計測する方法

~~~時間計測.
Sub MeasureExecutionTime()
    ' 開始時刻の取得
    Dim startTime As Double
    startTime = Timer
    
    ' 実行したい処理
    ' ...
    
    ' 実行時間の計算
    Dim executionTime As Double
    executionTime = Timer - startTime
    
    ' 結果の表示
    MsgBox "実行時間: " & Format(executionTime \ 60, "0") & "分" & Format(executionTime Mod 60, "00") & "秒"
End Sub

~~~



~~~画像枚数チェック.
Sub CheckImageCount()
    ' フォルダパスと画像枚数の指定
    Const folderPath As String = "C:\Images"
    Const imageCount As Long = 5
    
    ' フォルダ内の画像ファイルを検索
    Dim fileCount As Long
    fileCount = 0
    Dim fileName As String
    fileName = Dir(folderPath & "\*.jpg")
    Do While fileName <> ""
        fileCount = fileCount + 1
        fileName = Dir
    Loop
    
    ' 画像枚数の確認
    If fileCount < imageCount Then
        Stop ' 画像枚数が指定枚数未満の場合、実行を一時停止
    End If
    
    ' その他の処理
    ' ...
End Sub
~~~