OmniAICreator/Qiita-1.07M huggingface dataset:
バッチのコマンドについて

今回はバッチを使用する際に覚えておくと便利なコマンドをいくつかご紹介いたします。

1　＠echo off
2　%変数%
3　call
4　rem


1 @echo off
バッチの先頭行に必ずと言っていいほど記述されているものです。
このコマンドの意味は「コマンドの画面表示を消す」というものです。
バッチファイルを実行したあとに、バッチファイルに書いたコマンドが表示されなくなるというもので、
たいていのバッチファイルを使用する際はコマンド表示が冗長で不必要と感じるため「＠echo off」を用いてスッキリさせます。
また、offをonに変えるとコマンド自体やそのテキスト全部表示させるといったコマンドになります。


2 %変数%
バッチファイルのほとんどは変数が使われています。
その変数の中身を参照したいときに両端を％で囲むことによって引っ張ってくることができます。


3 call
バッチファイル内から別のバッチファイルを呼び出す際に使うコマンドです。
下記が使用例となります。
　call　｛呼び出したいバッチファイル名｝


4 rem
バッチファイルの変数を補足する際などに使用されるコマンドです。
意味合いとしてはコメントアウトさせるコマンドになります。
下記が使用例となります。
　rem｛コメント｝
コメントアウトする用途としては主に二点あり
　・プログラムのメモを書きたいとき
　・一時的に特定の行を実行したくないとき
バッチファイルを作成するのが自分だけであっても後から確認する人や自分がいなくなったとき、この変数は何の変数なのかなどわかりやすくさせる意味でもこのコマンドは必要不可欠なものだと思います。


今回は初めて触るひとに覚えておくと便利なコマンドをいくつか紹介していきました。
しかし、こんなのはほんの一部でしかないので調べて自分で触ってみるのが一番面白いと思います。
まだまだバッチのコマンドについては私もこれから勉強していきます。
文系ENTPが社会不適合者すぎてアプリ作るけど全く知識ないから勉強する

<h3>この記事で知れること
<p>・特になし
<h3>この記事で知れないこと
<p>・プログラミングについて
<br><br>


三日坊主なので、すぐ辞めると思います。
気にしないでください。メモというか日記です。

アプリ開発について学ぼうと思ったきっかけは、BtoBマーケティング系の仕事を行なっているのですが
全くもってつまらなくて、ただこの先長い人生の中で仕事の占める割合は大きいから、
なんとかしてやる気が出たり楽しめたりするものを探している中で、自分でサービスを作ることがこれまでも何回かあり、その瞬間は楽しかったので自力でアプリとか作れるようになったら、仕事楽しめるのかなと。。

キャリアステップとしては下記
①まずは自分でアプリもしくはツールを作り、売るなり稼ぐなりを行う
②その後、開発に割く時間を減らし、PdM的な役割に専念する
③サービスを何個もリリースし続ける

みたいなことができれば、飽き性でアイディアが溢れてくるENTPの自分でも仕事を楽しめる気がします。。。

現在のスキルは
HTMLを気持ち程度触れるくらいで、プログラミングに関してはからっきし。

学ぼうと思っている言語はFlutterおよびDartだけど、
その前にJava scriptのReactとかを学んでた方がすんなり入るのかなとか考えています。
（Flutterは教材が少ないらしいので）

作りたいサービスがBtoBtoCみたいなのが多いから、何を学べばいいんだと悩んでいます。
管理画面はクラウドで、サービス画面はスマホアプリみたいなものを作りたい。

教材は、基本的にはGPTとネットで調べたものにしようかと考えております。

どの言語で学べばいいかわからないから、まずはそれを決めて
①その言語での簡単なアプリを作る（最終的に作りたいアプリと類似性があるやつ）
②他の言語やPFのスキルも必要であれば、同じく作るなり、まずは形にする
③んで持って開発する

って出来たら理想。明後日には辞めてるかもだけど悪しからず。
Cloudflare で管理するドメインの WHOIS protection を無効にしたい


## はじめに

Cloudflare で管理するドメイン の WHOIS protection を無効化したかったが Cloudflare の Dashboard から変更することができませんでした。
Dashboard ではなく API 経由で変更する必要があったので方法を簡単にまとめた。

## 事前準備

WHOIS protection を無効に変更するには API 経由で実行します。
実行するために Account identifier (アカウント ID) と API Key、 Account Email が必要です。

Account identifier (アカウント ID) は Websites (Web サイト) から、API Key は My Profile から取得できます。
Account Email は Cloudflare のログインに用いているメールアドレスです。

https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/

https://developers.cloudflare.com/fundamentals/api/get-started/create-token/

## WHOIS protection を無効にする

WHOIS protection を無効にするには Update domain API に対してリクエストを送信します。

> Update domain
> PUT `https://api.cloudflare.com/client/v4
/accounts/{account_identifier}/registrar/domains/{domain_name}`

https://developers.cloudflare.com/api/operations/registrar-domains-update-domain

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/5a62863d-bae3-c166-86f2-b8335709967d.png)

API ドキュメントの右にリクエスト送信例があるのでお好きな環境で実行してください。
私は、 cURL でリクエスト送信しました。

事前準備で用意した Account identifier (アカウント ID) と API Key 及び Cloudflare の Account Email に置き換えてください。

```sh
curl --request PUT \
  --url https://api.cloudflare.com/client/v4/accounts/_YOUR_ACCOUNT_IDENTIER_/registrar/domains/_YOUR_DOMAIN_ \
  --header 'Content-Type: application/json' \
  --header 'X-Auth-Email: _ACCOUNT_EMAIL_' \
  --header 'X-Auth-Key: _ACCOUNT_API_KEY_' \
  --data '{
  "privacy": false
}'
```

リクエスト送信後、以下のようなレスポンスが返ってくれば成功です。

```sh
{"result":{"message":"Domain updates complete!"},"success":true,"errors":[],"messages":[]}
```

## References

https://community.cloudflare.com/t/how-do-we-temporarily-remove-whois-privacy-protection/381560/6
【SwiftUI】マップ上に範囲を表す円を表示する（iOS17）

# はじめに
昨日に引き続きiOS17で大型アップデートの入ったMapKitに関する記事です。

https://qiita.com/SNQ-2001/items/ae0fd2ff2a415d7e0713

今回はタップした位置に範囲を表す円を表示してみます。

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 - 2023-11-29 at 21.07.52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/d9e951c0-88c6-691a-dd74-f66eafaf1558.gif)

# 実装
```swift
import SwiftUI
import MapKit

struct ContentView: View {
    // 東京駅の座標
    @State private var position: MapCameraPosition = .region(.init(
        center: .init(latitude: 35.681236, longitude: 139.767125),
        span: .init(latitudeDelta: 0.005, longitudeDelta: 0.005)
    ))

    // マップ上の円の位置
    @State private var mapCircleLocation: CLLocationCoordinate2D = .init()

    var body: some View {
        MapReader { mapProxy in
            Map(position: $position) {
                MapCircle(center: mapCircleLocation, radius: 100)
                    .foregroundStyle(.green.opacity(0.5))
            }
            .onTapGesture { location in
                guard let selectedLocation = mapProxy.convert(location, from: .local) else { return }
                mapCircleLocation = selectedLocation
            }
        }
    }
}
```

# 解説
円を表示している箇所は`MapCircle`です。
`center`が円の表示する位置です。今回はタップした位置を`center`に渡しています。
`radius`は円の大きさです。
```swift
MapCircle(center: mapCircleLocation, radius: 100)
```

`foregroundStyle`で円の色を変更する事ができます。
```diff_swift
MapCircle(center: mapCircleLocation, radius: 100)
+   .foregroundStyle(.green.opacity(0.5))
```

円に枠線を付けたい時は`stroke`を使用します。
```diff_swift
MapCircle(center: mapCircleLocation, radius: 100)
    .foregroundStyle(.green.opacity(0.5))
    .stroke(.black, style: .init(lineWidth: 3))
```
![スクリーンショット 2023-11-29 21.13.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/7c98c143-ccc7-3b20-4154-5f264bf7f8f8.png)

# おわり
ほぼUIKitを使わずにマップを使えるようになりました。

# 公式ドキュメント
https://developer.apple.com/documentation/mapkit/mapcircle
WorldのTickで毎フレーム実行されるデリゲートについて。

[Unreal Engine (UE) Advent Calendar 2023](https://qiita.com/advent-calendar/2023/ue) シリーズ2一日目の記事です。

仕事で[FWorldDelegates](https://docs.unrealengine.com/4.26/en-US/API/Runtime/Engine/Engine/FWorldDelegates/)の一部を利用したので、簡潔に調べた内容を記載します。
FWorldDelegatesに色々なデリゲートがありますが、全部調査する時間が取れなかったため、UWorldのTick処理中に呼ばれるDelegateに絞って紹介します。

# 使い方

以下のようにデリゲートを登録します。

	// Worldから実行されるデリゲートを登録
	FDelegateHandle OnPreTickHandle = FWorldDelegates::OnWorldPreActorTick.AddSP(this, &AMyActor::OnPreTick);
	FDelegateHandle OnPostTickHandle = FWorldDelegates::OnWorldPostActorTick.AddSP(this, &AMyActor::OnPostTick);

※Blueprintでは使用できません。

## 何が便利か

C++限定の機能になりますが、レベルに配置された全ActorのTick実行前に何かしらの処理を挟みたい、逆に全ActorのTick実行後に何かしらの処理を挟みたい、という実装をしなければいけない場合に利用します。

かなり大雑把な例ですがネットワークを自前で実装したい場合、配置した全Actorの移動処理実行前に受信した座標をネットワークから取得して同期したい、全Actorの移動処理終了後に確定した位置情報をネットワークに送る等にFWorldDelegates::OnWorldPreActorTick、FWorldDelegates::OnWorldPostActorTickを利用すると要件を満たせます。

エンジン内部でも様々なモジュール、プラグインでOnWorldPreActorTick、OnWorldPostActorTick等を使用しているのでエンジンのソースコードを見ると結構面白い使い方を思いつくかもしれません。

# Tickで呼ばれるデリゲート一覧

WorldのTickで呼ばれるデリゲート一覧です。

## FWorldDelegates::OnWorldTickStart
エディターも含めて、配置された全ActorのTick処理実施前

エディターも含めた上でTickによる処理を実施する前に何かしらの処理を行いたい場合に使用します。

## FWorldDelegates::OnWorldPreActorTick
配置された全ActorのTick処理実施前

ゲームプレイ時のみBroadcastが実行されます。全ActorのTick処理前に何かしらの処理を行いたい場合に使用します。

## FWorldDelegates::OnWorldPostActorTick
配置された全ActorのTick処理終了後

ゲームプレイ時のみBroadcastが実行されます。全ActorのTick処理終了後に何かしらの処理を行いたい場合に使用します。

## FWorldDelegates::OnWorldTickEnd
エディターも含めて、配置された全ActorのTick処理実施後

エディターも含めた全ActorのTick処理終了後に何かしらの処理を行いたい場合に使用します。

# WorldのTickで呼ばれるデリゲートのタイミングを理解するために必須な資料

「UE4プログラマー勉強会 in 大阪 -エンジンの内部挙動について」の17ページから読むのを強くお勧めします。
Tick周りはUE5になった今でも非常に役に立つスライドです。

https://www.slideshare.net/com044/ue4-in#17

上記に加えてFWorldDelegatesのBroadcastが呼ばれるタイミングを理解すると、Tickが完全に理解できる...かもしれません。
特にActorのTickがどのように呼ばれているのか、をある程度理解できるかと思います。
（ここら辺読むとTick内で下手に組むと重くなると言われている理由も理解できる...かも）

※21ページにUWorld::Tickについて記載されています。

# 参考資料

今回記載したデリゲートのBroadcastが実行されているエンジンソースコードの場所
・LevelTick.cpp内のUWorld::Tick（1309行目あたり）

UE4プログラマー勉強会 in 大阪 -エンジンの内部挙動について

https://www.slideshare.net/com044/ue4-in

第005回 Tick関数がどう処理されているかUnrealC++を追ってみよう!

https://www.cc2.co.jp/blog/?p=17912

# ドキュメント

https://docs.unrealengine.com/5.3/en-US/API/Runtime/Engine/Engine/FWorldDelegates/OnWorldPreActorTick/

https://docs.unrealengine.com/5.3/en-US/API/Runtime/Engine/Engine/FWorldDelegates/OnWorldPostActorTick/

https://docs.unrealengine.com/5.3/en-US/API/Runtime/Engine/Engine/FWorldDelegates/OnWorldTickStart/

https://docs.unrealengine.com/5.3/en-US/API/Runtime/Engine/Engine/FWorldDelegates/OnWorldTickEnd/
Nonlinear Ray Tracing for Displacement and Shell Mapping


これは[レイトレ(Raytracing) Advent Calendar 2023](https://qiita.com/advent-calendar/2023/raytracing)の記事です。

Siggraph Asia 2023でアクセプトされた論文の短い補足です。

[Tessellation Free Displacement Mapping](https://perso.telecom-paristech.fr/boubek/papers/TFDM/TFDM_lowres.pdf) は事前分割なしにDisplacement Mappingが適用されたメッシュのレンダリングを行う手法で、注目を集めました。Adobeからは後続の研究 [RMIP: Displacement ray-tracing via inversion and oblong bounding](https://perso.telecom-paristech.fr/boubek/papers/RMIP/RMIP.pdf) が出ています。これらの論文ではAffine Arithmeticを使ってConservativeなBounding Boxを計算します。レイと三角形の交差判定はWorld空間で行われるため、Watertightな手法を用いることができるという利点があります。

しかし、デメリットもあって、(1)テクスチャ空間で三角形が縮退している場合(例えば、２つの頂点が同じUVを持っている場合や、３つの頂点が同じUVを持っている場合)ではUV座標からWorld座標への変換が定まらないため、交差判定が行えません。エンジニアはこういったことが起きても原因が分かりますが、アーティストはそうではありません。なぜレンダリングされないケースがあるのか悩む、原因が分かってもアセットを一部用意し直す必要が生じるなど、作業効率が落ちてしまいます。また、(2)変異されたメッシュの定式化において、スムース法線のノルム|Ns|で割り算を行っている箇所がありますが、これも0になるケースが存在するため、問題が起きたときに頭を悩ませることになります。

私の論文ではこれらのデメリットが一切ありません。RMIPの論文のように変位方向からUV座標を求めるための3次方程式を解く必要もありません(RMIPの論文ではNewton Raphsonを用いています)。Affine Arithmeticも使いません。レイを2次の有理関数で表すため、Bounding Boxとの交差は２次方程式を解くことで安定して行えます。トラバーサルは完全にテクスチャ空間で行われるため、Displacement Mappingの場合はBounding Box同士が重なることもありません。更にUV平面だけではなく、高さ方向も加味しているため、Shell Mappingにも問題なく対応できる上位互換の手法となっています。RMIPでは、与えられた任意の矩形のMinMax値を一定コストで求める非常に興味深い方法が使われていますが、それも不要であり(もちろん勉強して実装する価値は大いにあり!)、コードのメンテナンスが非常に楽です。論文中では精度の問題について書いてありますが、レイと三角形の交差判定だけWorld空間で行うこともできます(このときテクスチャ空間で縮退した三角形は扱えなくなるので、トレードオフです)。テクスチャ空間での縮退は別の方法でなんとかする、交差判定の精度を上げたい、といった方はトラバーサルにだけ私の論文の手法を使うハイブリッドなアプローチが良いのでは、と思います。

パフォーマンスについては、論文執筆時点で十分に最適化ができていませんでしたが、それでも毛のような高周波な信号を持つものでは事前分割したジオメトリをObject SplittingのBVHでレンダリングしたよりも高速になるケースがあります。これはテクスチャ空間でのBounding BoxがOriented Boundになっているためです。

Adobeファンの方はAdobeの論文に飛びつくかもしれませんが、Nonlinear Ray Tracingの論文もお勧めしたいと思います:wink:
【SwiftUI】画像の元のアスペクト比を保ちつつ、Viewのアスペクト比を変えたい！In LazyVGrud！

# はじめに
SwiftUI楽しいです！[むらお](https://twitter.com/ymurao2)です！
LazyVGrid内で、画像のアスペクト比を保ったまま画像のViewの比率を指定したい！ただ、frameモディファイアは使いたくない！という状況に陥り、実装に手こずったので備忘録として残しておきます！

# 想定する画面
以下のようなデザインを想定しています。
* 画像のアスペクト比は1:1
* 画像の枠のアスペクト比は2:1（横：縦 = ２：１）
* 見切れるのは構わない → scaleはfill
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529173/ee33e96a-9b7d-b8b5-5f04-a71384503ad7.png" width=500>

* 使用する画像はこちら
* かわいい
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529173/e4e0673b-d58a-f27d-bb7b-0e1d54e8f85c.jpeg" width=500>


# 案１（ボツ）
#### Imageに`aspectRatio`を指定し、frameモディファイアで無理やり縛る
```swift
LazyVGrid(
    columns: .init(repeating: .init(.flexible()), count: 2),
    spacing: 12
){
    ForEach(1...10, id: \.self) { _ in
        VStack(alignment: .leading, spacing: 4) {
            Text("画像")
            Image("catImage")
                .resizable()
                .aspectRatio(1, contentMode: .fill)
                .frame(width: 140, height: 70)
                .clipShape(RoundedRectangle(cornerRadius: 4))
        }
        .padding()
        .border(Color.gray)
    }
}
```
一見上手くいくように見えますが、`frame`を指定しているので端末によって見え方が異なってしまいます。
例えば、iPadで見るとかなり小さく見えます。（`frame`指定なしだと画像がはみ出てしまいます）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529173/15a6e54f-db6f-d416-cf34-ecfe85696db0.png" width=500>

これを回避するためには`GeometryReader`を使ってセルの幅や高さを計算することになりそうです。
（めんどくさいのでなし）
**う〜〜ん、不採用！**


# 案２（採用）
```swift
LazyVGrid(
    columns: .init(repeating: .init(.flexible()), count: 2),
    spacing: 12
){
    ForEach(1...10, id: \.self) { _ in
        VStack(alignment: .leading, spacing: 4) {
            Text("画像")
            RoundedRectangle(cornerRadius: 4)
                .aspectRatio(2, contentMode: .fit)
                .overlay {
                    Image("catImage")
                        .resizable()
                        .scaledToFill()
                }
                .clipShape(RoundedRectangle(cornerRadius: 4))
        }
        .padding()
        .border(Color.gray)
    }
}
```
`RoundedRectangle`にアスペクトを指定し、`overlay`で`Image`を重ね、はみ出た部分をカットする方法でうまく行きました。
`clipShape`や`clipped`を使うことではみ出た部分をカットできますね。`overlay`につけるのがミソです。（`Image`の下につけると上手くいかない）
今回は`RoundedRectangle`を使用しましたが、`Color`でも同じことが可能だと思います。

今回の実装だと、`columns`のcountを変えるだけで色々レイアウトを変更できるので、かなり良く見えるのではないでしょうか
**採用！**

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529173/18d6752c-c9a5-6b0f-28c0-b5d0e42976f9.png" width=500>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529173/2d42c8e0-4abc-4569-c053-33da7f7e20ae.png" width=500>


# 参考記事
[【SwiftUI】LazyVGrid内の画像を正方形にする【ワークアラウンド】](https://qiita.com/tsuzuki817/items/cc9364089cee3a763084)
スプレッドシートでリンクを貼るマクロを作ってみた

Redmine のチケットをスプレッドシートで整理したときに、実際のチケットへのリンクを貼りたいと思い、マクロを作成することにしました。

# 仕様

選択したセル範囲のセルをすべて走査し、セル内の値が数字であれば、その数字をチケット番号として所定の Redmine へのリンクを貼る、という仕様にしました。

選択したセル範囲をすべて走査するために、

1. 選択された複数の矩形のセル範囲 (Range)
2. 矩形セル範囲の列
3. 矩形セル範囲の行

という形で 3段階のループを回しています。

# ソース

Google スプレッドシートでマクロを作る方法は、以下を参照してください。

https://support.google.com/docs/answer/7665004?hl=ja

スクリプトを編集して、作成したマクロは最終的に以下のようになりました。
リンクは HYPERLINK 関数ではなく、RichTextでリンクを貼る方法をとっています。

```javascript:マクロ.gs
function link_redmine() {
  // ベースとなるURL
  let baseUrl = 'https://redmine.example.com/issues/';
  // 選択範囲の取得
  let selection = SpreadsheetApp.getSelection();
  let rangeList = selection.getActiveRangeList();
  let ranges = rangeList.getRanges();
  // 矩形セル範囲
  for (let i in ranges) {
    let col = ranges[i].getNumColumns();
    let row = ranges[i].getNumRows();
    // 列
    for (let j = 0; j < col; j++) {
      // 行
      for (let k = 0; k < row; k++) {
        let cell = ranges[i].getCell(k + 1, j + 1);
        let issueNumber = cell.getValue();
        // 数字だけに適用
        if (!isNaN(issueNumber) && issueNumber > 0) {
          // リンクを設定
          let link = baseUrl + issueNumber;
          let richText = SpreadsheetApp.newRichTextValue()
          .setText(issueNumber)
          .setLinkUrl(0, issueNumber.toString().length - 1, link)
          .setTextStyle(SpreadsheetApp.newTextStyle().setUnderline(true).build()) // 下線
          .build();
          cell.setRichTextValue(richText);
        }
      }
    }
  }
}
```

選択したセル範囲のセルすべてに何かを実行する場合、 3段階のループは常套句のように使えると思います。


# 実行した様子

リンクを貼りたいセルを選択して、マクロを実行。

![実行前2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/926617/c5508234-948b-093b-4890-c9bdde201df1.png)

選択した数字に Redmine チケットの URL が設定されます。

![実行後2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/926617/fe2e9175-aa9f-e928-322c-e7c901526863.png)

今回は Redmine チケットへのリンクを貼るようにしましたが、スプレッドシートのセル内の値をパラメータとしてリンクできるので、応用範囲は広いと思います。
Vagrant / debian で作成した仮想マシンのディスクを拡張する

VagrantでUbuntuのboxを使って仮想マシンを作成し, ディスクサイズを指定する場合は次のような内容のVagrantfileを用意する.

```ruby:Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"
  config.vm.disk :disk, size: "40GB", primary: true
end
```

ところで, UbuntuではなくDebianで仮想マシンを作成した場合, 認識されるディスクサイズが変わらない.

```
vagrant@bullseye:~$ df -text4 -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        20G  816M   18G   5% /
```

dfコマンドではなくfdiskで調べると, ちゃんと指定したサイズのパーティションになっている.

この原因がよくわからず, とりあえずUbuntuを使っていたけど, ふと気になってChatGPTに聞いてみたらあっさり解決した.

`resize2fs` コマンドをパーティションに実行してやると期待したディスクサイズになるらしい.

```
vagrant@bullseye:~$ sudo resize2fs /dev/sda1
resize2fs 1.46.2 (28-Feb-2021)
Filesystem at /dev/sda1 is mounted on /; on-line resizing required
old_desc_blocks = 3, new_desc_blocks = 5
The filesystem on /dev/sda1 is now 10485499 (4k) blocks long.

vagrant@bullseye:~$ df -text4 -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        40G  864M   37G   3% /
```

Vagrantfile にはインラインスクリプトで指定しておけばよさそう.

```ruby:Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "debian/bullseye64"
  config.vm.disk :disk, size: "40GB", primary: true

  config.vm.provision "shell", inline: <<-SHELL
  resize2fs /dev/sda1
  SHELL
end
```
Qiita Advent Calendar 2023 投稿記事一覧

# Qiita Advent Calendar 2023 に今年は参加するぞ！

こんにちは、テラりんです。
さて、今年のAdvent Calendarは完走賞を狙って「個人的なまとめ Advent Calendar 2023」というカレンダーに毎日投稿していこうと考えています。

https://qiita.com/advent-calendar/2023/0_terarin_0-individualrun

その記事一覧を毎日以下に追加していきますので、全ての記事にご一読いただけると幸いです。

## 現役高校生が水泳記録管理サービスを作った話/その0：思い立ち編

投稿日：12/01・1日目

https://qiita.com/0_terarin_0/items/5113003971aa5fe065b3

## 現役高校生が水泳記録管理サービスを作った話/その1：バックエンド編

投稿日：12/02・2日目

https://qiita.com/0_terarin_0/items/b92cfbc56853dc981f33

## 現役高校生が水泳記録管理サービスを作った話/その2：フロントエンド編

投稿日：12/03・3日目

https://qiita.com/0_terarin_0/items/daed1262a16e9c8cd0c1

## 現役高校生が水泳記録管理サービスを作った話/その3：Google Cloud編

投稿日：12/04・4日目

https://qiita.com/0_terarin_0/items/2ccfdba178c2a9308394

## 現役高校生が水泳記録管理サービスを作った話/その4：その他身の回りの環境編

投稿日：12/05・5日目

https://qiita.com/0_terarin_0/items/1a6f0df21458d98dce49

## 現役高校生が水泳記録管理サービスを作った話/その5：今後の展望編

投稿日：12/06・6日目

https://qiita.com/0_terarin_0/items/c4781880515d69fee82f

## 水泳部マネージャーがFINAポイントの計算用APIを公開した話

投稿日：12/07・7日目

https://qiita.com/0_terarin_0/items/a5b2062489213cc930b6

## FlutterをUTM上のDebianで動かしてみた

投稿日：12/08・8日目

https://qiita.com/0_terarin_0/items/5e2b42bab6942ba55014

## Arm Browserを使ってみたら便利すぎた話

投稿日：12/09・9日目

https://qiita.com/0_terarin_0/items/261f5c8df9b7e50ad19d

## 文化祭での物品管理を自動化した話

投稿日：12/10・10日目

https://qiita.com/0_terarin_0/items/be177a67f648fb952dea

## 生徒・生徒会目線での学校現場におけるDX

投稿日：12/11・11日目

https://qiita.com/0_terarin_0/items/059f1c0ee7000e851d1c


## 自分のMacの環境（2023年末編）

投稿日：12/12・12日目

https://qiita.com/0_terarin_0/items/9f885315f4531aadb6b2


## GitHub Student Developer Packを利用している話

投稿日：12/13・13日目

https://qiita.com/0_terarin_0/items/198d638f1d70eaec9917

## 自分が運営している団体WebをプレーンからNext.jsに変えた話

投稿日：12/14・14日目

https://qiita.com/0_terarin_0/items/bb6f21e12b8f76275d62

## 年末のMac大整理/その1：ターミナル

投稿日：12/15・15日目

https://qiita.com/0_terarin_0/items/13ca262b6b720b39bd16

## 年末のMac大整理/その2：ドットファイル整理

投稿日：12/16・16日目

## .onionドメインにTorブラウザを使わずにアクセスする方法

投稿日：12/17・17日目

https://qiita.com/0_terarin_0/items/c0a8fb9bc00f89f527f8

## Azure ADをIdPにしてGppgle Workspaceにログインしてみた

投稿日：12/18・18日目

https://qiita.com/0_terarin_0/items/fa84cd4500138080b492

（以下は後ほど追記します。）

## 個人的Webで使うファイルの種類/その1：画像

投稿日：12/19・19日目

https://qiita.com/0_terarin_0/items/b0f90f179afb9401f707

## 個人的Webで使うファイルの種類/その2：動画

投稿日：12/20・20日目

https://qiita.com/0_terarin_0/items/5c94d339f3c9aa2bb334

## 個人的Webで使うファイルの種類/その3：音声

投稿日：12/21・21日目

https://qiita.com/0_terarin_0/items/c9784b81ef3e8490c215

## 企業の方に勧めるGoogle Workspaceの普及

投稿日：12/22・22日目

https://qiita.com/0_terarin_0/items/61de6fc2b3fb6c3c1d8e

## Ruby on Railsを触ってみた

投稿日：12/23・23日目

https://qiita.com/0_terarin_0/items/ce6a14c306f4bc5ab990

## 高校生が開発するということ

投稿日：12/24・24日目

https://qiita.com/0_terarin_0/items/5c2780041caf31f39b35

## 今年の総括と来年以降に向けて（2023年度編）

投稿日：12/25・25日目

https://qiita.com/0_terarin_0/items/db33a2dbdeb5f9af010e
RenovateがPRを出してくれない場合の対処法

個人開発しているアプリにRenovateを導入しましたが、なぜかOnboardingのPRが作成されませんでした。そこで今回は、RenovateがPRを出してくれない場合の対処法についてご紹介します。

# 対処法

https://developer.mend.io/

にアクセスし、Renovateを有効にしたいオーガナイゼーションを指定します。

![スクリーンショット 2023-11-29 20.42.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/f577457c-4158-e805-65cf-e3c92d355423.png)

次に、設定をクリックします。

![スクリーンショット 2023-11-29 20.45.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/69668146-5208-00d4-c1ed-cac57c26c871.png)

そしたらModeをInteractiveに、Repository OnboardingをOnboarding pull requestにします。

![スクリーンショット 2023-11-29 20.46.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/ad0dd446-3d51-8bcd-3c80-35fcded2ee08.png)

次にこの画面に戻り、Renovateを設定しているリポジトリを選択します。

![スクリーンショット 2023-11-29 20.44.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/94819191-6d78-aef0-806b-a86da666f50d.png)

そして、設定をクリックします。
![スクリーンショット 2023-11-29 20.48.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/48c5d86a-356f-ced1-6e63-1f44c32205d2.png)

モードをこのようにInteractiveに変更してください。

![スクリーンショット 2023-11-29 20.49.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/05921acc-2c00-a7ec-27c4-4e44688d9e6f.png)

# まとめ
ずっとOnboarding PRがでなかったのでずっとRenovateの導入を諦めていましたが、やり方がようやく分かってよかったです。ネットには載ってなくて地味に苦労しました。
現役高校生が水泳記録管理サービスを作った話/その0：思い立ち編


# はじめに

この記事は、Qiita Advent Calendar １日目の記事です。
以下の記事より、すべての記事をご覧になれます。

https://qiita.com/0_terarin_0/items/0f367210e2465f7772c9

# 筆者について

- 現在高校２年生
- 水泳部マネージャー
- 生徒会長
- とある団体の代表

# 本編

## どんなサービス？

以下にリンクを貼り付けておきます。

https://www.sokfi.net/

水泳選手向けの記録管理サービスとなります。

![Alt text](https://www.sokfi.net/images/pdimg01.png)
引用：https://www.sokfi.net/images/pdimg01.png

## サービスを稼働させようと思った気っかけ

筆者はただいま現役高校生で、いろいろな成り行きがあって水泳部マネージャーをしております。その中で、選手のタイムの管理ができていなかったという経緯があって、選手のタイムを自動管理、そして自動である程度の記録の分析をしてくれるようなサービスを展開したいと思いローンチしました。

## 計画について

### 必要なユーザー情報

サービスをローンチするにあたってどのような情報を管理する必要があるかについて整理しました。そして、ユーザーから集めなければいけない情報を以下のように整理がつきました。

- 登録する記録を出した日
- 記録の概要（タイム・泳法・[^1]タイプ・その他）

### 技術および利用サービス

こちらに関してはすごく悩みました。というのも、自分自身当時は素の HTML と CSS と JavaScript、他は Python と GAS が少し触ったことがあるというレベルでした。ですので、どの技術を利用するにしろどちみち新しく学習することになるのです。できるだけ早く、しかしきちんと今後も使えるようなものを選ぶ必要がありました。そして、以下のような技術を選定させていただきました。

- React（フロントエンド/メイン）
- Bootstrap（フロントエンド/見た目）
- Django（バックエンド/とりあえずゲートウェイ的な）
- Firebase Authnication（バックエンド/認証）
- Firebase Database （バックエンド/ユーザーデータ管理）
- Google Cloud Compute Engine（サーバーサイド/Cloud Computing）
- [^2]Nginx (サーバーサイド/Web Server Application)
- [^2]Express (サーバーサイド/Server Framework)
- [^2]Gunicoorn (サーバーサイド/WSGI)

### 開発スケジュール

この計画を思い浮かんだのが2023年の3月ごろ、そして最初はサービスのローンチを6月ごろに考えていました。しかし、やはり高校生というものは日を増すごとに時間がなくなるもので、実際のリリースは8月にもつれ込みました。

|時期|予定|実際の経過|
|----|----|----|
|3月|計画|-|
|4月|フロントエンドの開発|フロントエンドの開発|
|5月|バックエンドの開発|開発できず|
|6月|サービスのローンチ|フロントエンドの開発|
|7月|機能追加|バックエンドの開発|
|8月|-|最終調整・ローンチ|

### サービス名の問題

このサービスの名称を考える上で、次のようなことを考えていました。

- より多くの学生にとって使いやすいものであって欲しい
- できるだけ覚えやすく語呂がいい
- 覚えられるレベルのURLであってほしい

以上のことから考えた結果、「So Kindness system that you can Fall In love」の略からSOKFIという文字を取りました。（無理矢理なのはご勘弁）

これに合わせてドメイン「sokfi.net」というドメインも取得しました。ちなみにこのドメインはGoogle Domainsで取得したのですが、どうやら事業売却がなされるということで今後が少し心配なところです。

https://support.google.com/domains/answer/13689670?hl=ja


## 後からきづいた、あの時やっとけばよかったこと

### 法令関係を全く考えてなかった

この先の記事で詳しい内容については記載しますが、恥ずかしながらも今回のこの取り組みで初めてGDRPなるものを知ったり、あるいは日本の個人情報の取り扱いに関する話を知ったりと、無知で危うく法令を無視してサービスをローンチするところでした。やはり事前に自分をかなり疑って余分に調べることが大切ですね。

https://www.ppc.go.jp/enforcement/infoprovision/EU/

### テスト環境を作らなかった

これについては本当になぜ当時思い浮かばなかったのかが不思議ですが、当初Conmpute Engineを使用していた際に全くスペックについて考えず、とりあえず安いものをという考えでした。これは本当に甘かったです。これも今後の記事で書きますが、結果的にはマシンの性能を格上げするに至りました。

### もっと綿密なスケジュール管理

スケジュール管理が無茶苦茶でした。自分自身ができるだろうと考えていたことが絶対進まないものでした。よく「予定はあくまで予定であり未定」と言われますが、それにしてもこれはかなりの問題です。経験値不足もあるとは思いますが、今後の開発では気を付けていきたいところです。

# 最後に

この計画段階から分かるように、かなり不安要素だらけでこの計画はスタートしました。一高校生が空き時間で始めたサービスに適当さが滲み出ていますが、果たしてこの後どのような道を辿ることになるのでしょうか。今後のアドカレ23の記事をお楽しみにしてください。

https://qiita.com/0_terarin_0/items/0f367210e2465f7772c9

[^1]: ここで言う「タイプ」とはその水泳がどのような種類のアクティビティとなるかです。本サービスでは「練習」・「レース」・「その他」の３種類を用意しています。

[^2]: 実は計画の時点では Apache を使って、Express など使うつもりもありませんでした。というか、Gunicorn って何？って感じです。これについては後ほど記述しますが、当時の自分には全くもってこれらのものに対する知識がありませんでした。後から勉強して悔やんだ覚えがあります。
【AIがコーディングを支援】AIを活用した最新コードエディタ「Cursor」の紹介

# この記事について
※こちらは、アイレット株式会社Advent Calendar2023 13日目の記事になります！

https://qiita.com/advent-calendar/2023/iret

今回は、今かなりホットな生成AIを搭載したコードエディタ<strong>「[Cursor](https://cursor.sh)」</strong>をご紹介します！
５分ほどでお読みいただける内容となっておりますので、ぜひ最後までご覧ください(_ _)

> 1. 個人的なCursorの特徴３選 (実際の使用例)
> 2. プランごとの違い
> 3. インストール方法
> 4. 使ってみた感想
> 5. 最後に　

## 1. 個人的なCursorの特徴３選
### 1-1. AIがコードを自動作成
cursorはOpenAIのGPT(3.5, 4)を実行できるため、
自分が実装したい処理の詳細を伝えることで自動でコードの生成を行ってくれます。


試しに「入力された数値が、偶数か奇数かを判定するコードを作成して」とお願いしてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629182/ca03f33b-2bfe-76c7-548f-3f7169e9d1ee.png)
↓↓↓

数秒後・・・


↓↓↓


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629182/e0beb186-9aed-6ff5-da30-aedd9908afeb.png)
自動的にコードを作成してくれました！:raised_hands:
英語ではなく、日本語でお願いしても普通に通じることにも感動です。


※一応、実行結果です↓
```
数値を入力してください: 1 
奇数です
```

### 1-2. 処理やエラーについて質問できる
先ほど作成してもらったコードを少し変更し、エラーが起こるようにしてみました。
試しに「エラーの原因は何か」質問してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629182/13dd4330-967f-1776-5fca-81d074c8893b.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629182/d748ca45-7285-d069-37ad-9c830fabe13f.png)

「エラーがなぜ起こっているのか」だけでなく「エラーの改善策」まで提示してくれました・・・
しかも説明がかなり分かりやすいですね（凄すぎる。。
あと、ChatGPT(ブラウザ)とエディタを行き来する必要がないのも便利だと思いました！


### 1-3. VSCodeの拡張機能が使える
cursorはVisual Studio Code(通称: VSCode)をフォークして作られているため、
<strong>VSCodeの拡張機能をそのまま使うことができます。</strong>
また、既にVSCodeを使用している場合、拡張機能を<strong>全て一括で移行</strong>することもできます！
いちいち拡張機能を再インストールする手間が発生しないので、個人的にはかなりありがたいポイントです。



## 2. プランごとの違い
|プラン名| 値段 | GPT3.5の使用回数 | GPT4の使用回数 |AIコーディング|プライバシーモードの強制|
|:-:|:-:|:-:|:-:|:-:|:-:|
|Basic|無料|200回 /月|50回(slow GPT4)|〇|✖|
|Pro|$20 /月 (2023/12/09現在、約2900円)|無制限|無制限(slow GPT4) <br> 500回/ 月(fast GPT4)|〇|✖|
|Business|$40 /1人/月 (2023/12/09現在、約5800円)|無制限|無制限(slow GPT4) <br> 500回/ 月 or 無制限？(fast GPT4)|〇|〇|

プランごとによる大きな違いは「GPT3.5, GPT4(slow/fast) の使用回数の制限」となりそうですね。
（ビジネスプランは企業/組織向けのため、一括請求やプライバシーモードの強制などの機能が追加されるそうです）
詳しくは[公式ページ(プラン)](https://cursor.sh/pricing)をご参照ください！

:::note warn
※プランの違い、値段は2023/12/09 現在の情報になります。
:::

## 3. インストール方法(Windows)
1. [公式サイト](https://cursor.sh)からダウンロードし、インストール
2. 起動後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629182/7d2de447-85d9-1e23-d1ae-8913bb318f22.png)
・Languageに「日本語」と入力
・右下のInstall "cursor"をクリック
↓↓↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629182/dcfeb620-5d0c-be18-25bd-c858f1d3b573.png)
・Continueをクリック
3. ログイン
アカウントを新規で作成する場合は「Sign Up」から作成を行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629182/0f12c3b3-205e-d6e5-6dae-8806d91d32df.png)

以上！


## 4. 使ってみた感想
元々VSCodeに慣れていることもあると思いますが、個人的にはこれからも使っていきたいと思えるほどに使いやすかったです！
・簡単な処理の実装や、Enumの作成など…難易度は低いが、時間がかかる作業をエディタ上でAIに任せられる点。
・デバッグ機能が充実 & VSCodeの拡張機能がそのまま使える。など
VSCodeからの移行が楽な上、開発の効率化→生産性を向上できるのが最大の魅力ですね。

## 5. 最後に
最後までお読みいただきありがとうございました！
今回はAI搭載コードエディタ「Cursor」についてご紹介させて頂きました。
少しでも興味を持っていただけたなら幸いです！

## 参考サイト(公式)

https://cursor.sh
【備忘録】Web脆弱性診断結果の報告会で学んだこと

<!--
■執筆時の注意
・階層を深くなりすぎない
・表題以外のことを書かない、各場合は別記事で

■登校前チェック
・誤字脱字
・プレビューで体裁を確認
・インデックスに誤りはないか
・余計なコメントは残っていないか
・リンク誤りはないか
・ハッシュタグは設定されているか
-->

# 目次
[1. はじめに](#1-はじめに)
[2. 学んだこと](#2-学んだこと)
[3. 最後に](#3-最後に)
[4. 参考資料](#4-参考資料)

# 1. はじめに
Web脆弱性診断士になってから2か月目の私が、報告会に参加した際に学んだことを備忘録として残します

報告会という特殊なケースに関係なく、ビジネスの場で当たり前である項目も多いと思いますが、そこはご容赦を...！(笑)

# 2. 学んだこと
## 2-1. 診断対象がどんなシステムかを把握する
報告会というか、診断時に把握しておくべきことと思いますが...

把握しておくとビジネスへの影響レベルがある程度想定でき、お客様の層を推し量ることが可能かと思います。

## 2-2. 相手のレベル感に合わせた説明を準備しておく
報告会時にお客様からの質問があって、その時に初めてお客様のレベル感を理解することが多いです。

事前にお客様の情報を知れるなら聞いておくに越したことはありませんが、難しい場合もあるので...。

相手のレベル感に合わせた説明が出来ると臨機応変に対応できます。

## 2-3. 脆弱性に紐づく攻撃手法、対処方法の具体例を提示すると分かりやすい
報告書に脆弱性の概要を記載しているかと思いますが、補足情報として最近ニュースになったセキュリティインシデントや具体的な対処方法をお伝えすると、より伝わります

## 2-4. 説明用の図を用意しておくと良い
脆弱性について言葉だけで説明するのは難しいです。
図を用意していると時間をかけずに理解してもらえます。

## 2-5. NWやPFに関する情報がある場合は一応確認しておく
例えば「ミドルウェアレベルで対策するので、アプリケーションでは対応しなくても良い？」と言った質問をされる場合があるので、事前に情報が見れる場合は確認しておくと良いです。

## 2-6. 初歩的なことも質問されることがある。日頃から技術理解をあやふやにせず学習し、説明できるようになる
脆弱性に関わらず、初歩的な質問をされることがります。
例えば「HTTPとHTTPSの違いって？」「APIって何ですか？」「JSONって何ですか？」などなど

私の場合は「概念は知っているけど、言葉で説明できるレベルまでは理解できていない」ということが多いので、なあなあにせず言葉で説明できるように復習しなければ...

## 2-7. 相手の理解の細かい部分がずれていても、細かい部分を訂正して行ったらキリがない。「こちらの説明は間違っていなかった」といえるレベルの妥協点を見極める
時間が限られていますし、細かい部分を正していったらキリがないので...。

とは言え、あまりにも誤った認識のままでは問題ですし、「こういった説明をしていました。こちらの説明は間違っていません」と自信をもって言えるレベルの妥協点を、自分自身の中で定め置くと良いです。

## 2-8. 説明に詰まってしまっても堂々としている。分からないことは良くないが、なよなよした態度をとってしまうとより不安を与えてしまう
例え経験が浅くても、お客様からしたら知ったこっちゃないし、プロフェッショナルとして見られています。

どうしても分からない、言葉に詰まってしまうことはあります。せめてそういった場面でも慌てず堂々とすることによって、お客様に不安を与えないことが大事です。

## 2-9. 相手の立場を考えた内容を伝える
例えば管理者で開発者でない立場の方は「どう開発者に伝えればよいか」という点に重きを置いている印象を受けます。

言葉尻や質問の内容から立場を察して、「開発者の方には〇〇と言えば伝わりやすいと思います」という言い回しが出来ると良いと思いました。

## 2-10. 「これは対処しなくても問題ないか？」という聞き方をされることがある。主観や経験則を交えず、あくまで客観的に返答する
断言しすぎると診断側の責任問題になってくるし、かといってあまりにも濁した返答をしてしまうと印象が悪いです。

主観や経験則に基づいた回答は避け、客観的・中立的な意見を述べると良いです。

## 2-11. 「他社はこの脆弱性の対処しているのか？」といった趣旨の質問にも対処できるようになると良い
意外とこれを気にされているお客様は多い印象です。

普段から情報収集を心掛ける、再診断の依頼があった場合は前回と比べてどう修正されたのか？という観点で確認しておくと良いです。

## 2-12. 対応の優先度
TODO

## 2-13. 診断対象のシステムのセキュリティインシデント発生状況について知る
特に直近でセキュリティインシデントが発生している場合は、通常より細かくお客様に質問されるようです。こちらの対応を変える訳ではありませんが、心の準備を...

# 3. 最後に
今後も報告会で学んだことがあれば追記していく予定です。
メモ書きレベルで文章が汚いので、こちらも追々修正しなければ...

# 4. 参考資料
なし
milk-v duoとは何か？

# 製品の概要

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22905/5373a886-123f-3d44-3992-308fd46279a4.png)

https://milkv.io/docs/duo/overview

CVITEK社のCV1800Bが実装されたLinux評価ボードです。スペックについては公式ページを見てもらうとして、結局何が新しいのかが伝わってない印象をうけるのでそれについて説明していこうと思います。

milk-v duoは基本的に監視カメラ向けのハードウェアが実装されていますが、有線LANのインターフェイスも持っているため、ネットワーク系のアクセサリ開発にも使えます。

# 価格

評価ボードの価格は9ドルです。Linuxが動く割にはすごく安いと思うかもしれませんが、実はこれに搭載されているMCU（CV1800B）は量産価格で3ドルを大幅に下回るので、そっちの方が驚きです。

CVITEK社は中国の企業でシャオミ社が出資していますが、調達に関しては日本に代理店はなく、CV1800Bは中国で調達する必要があります。「自社製品で採用したい」というチャレンジャーがいれば中国調達がんばりましょう。色々障害が多そうですが...。

# アーキテクチャ

CV1800Bについては価格を抑えるためにアーキテクチャがすごい割り切りで作られているので、あまり高機能ではないです。逆にシンプルで使いやすい印象は受けます。

milk-v duo単体でCV1800Bの機能はほぼすべて使えるので、製品開発の先行評価には十分です。この価格で評価可能な環境が整うのは魅力的ですね。

CV1800Bのアーキテクチャの基本的なところは以下の通りです。

| Item | Spec |
| ---- | ---- |
| プロセッサ  |  CVITEK CV1800B (C906@1Ghz + C906@700MHz) |
| アクセラレータ | TPU (AIアクセラレータ) |
| メモリ | DDR2-SDRAM （SoCに内蔵） |
| ストレージ	| MicroSD or 外付けNAND/NORフラッシュ |
| USB | Type-C |
| カメラ | MIPI-CSI2 (2レーン) |
| ネットワーク | 有線イーサネット (100Base-TX) |

# コミュニティの状況

実はまだ盛り上がっていないです。これからといったところ。中国でもそんなに濃密なやりとりがされている感じではないです。

結局のところ、流行るかはやらないかはコミュニティの力、個人の意思と偶然の産物です。良いデバイスなので何とか盛り上げたいなあと思っています。

# 開発における勝負どころ

「milk-v duo回路図」

https://github.com/milkv-duo/duo-files/blob/main/hardware/duo/duo-schematic-v1.2.pdf

外付け部品（電源のDCDCコンバータと水晶、フラッシュメモリぐらい）が少なく、回路設計がめちゃくちゃ簡単なところがいいところです。SDRAMが内蔵なのが大きいです。

SDRAMが64MBというのがこの価格を実現する上で重要なポイントです。メモリ64MBでLinuxを動かすのは大変ですが、buildrootによるユーザランドがとても小さいため、単一のアプリケーションを動かすだけであれば何とかなります。色々動かそうとすると無理になるので単機能の製品を作るのがポイントです。

「メジャーなAIアルゴリズムYOLO」

https://qiita.com/cv_carnavi/items/68dcda71e90321574a2b

iPhoneですらAIのソフトウェアを動かすにはメモリが足りないことがあるぐらいなので、かなりの最適化が必要です。ぶっちゃけ監視カメラで使うAIのアルゴリズムはYoloと相場が決まっているのでYoloを動かすかだけに注力しましょう。ちなみに自分はまだ動かせていません。

TPUに関する情報は2023年10月に公開されたばかりです。またカメラのサンプルソフトウェアがソースコードが公開されていないため、個人でカメラの開発を行うのは現状困難です。待っていれば新しい情報が順に公開されているので気長に待ちましょう。

# アプリケーション

想定されるアプリケーションは監視カメラが最大のものですが、ネットワークにも対応しているため、いろいろなものが考えられます。これを考えるのも重要なことですね。

- カメラによるセンシング
    - 特定の何かが映ったらログを採ったり、照明を付けたりなどのリアクションしたり、物理的な自動化ができます
- オートリブーター
    - ネットワークが疎通しなくなったら電源を再起動する装置が作れます
- DHCP/DNSサーバ
    - ネットワークが100Base-TXで速度が遅いですが、DHCP/DNSならさばけます
NGINXのローカル環境の作成 下準備編

# /var/www/aaaaa/の配下に必要なディレクトリをローカルに事前に持ってくる
```javascript
/var/www/aaaaaa/application
/var/www/aaaaaa/cache
/var/www/aaaaaa/logs
/var/www/aaaaaa/system
/var/www/aaaaaa/www
```


https://qiita.com/panda-chibi/items/5cca2fb6d49816393246
よく使ってたコマンド（awk）

みなさんこんにちは！

最近、クラウドの発達によって、以前よりオンプレでの開発機会が少なくなってきましたね。

元々UnixやLinuxでガリガリ開発していた身としては、少々寂しさもありつつ、便利な世の中になったな、と思うところもあります。

初心に返る意味も込めて、昔よく使ってたコマンドの記事を書こうと思います。

## awkコマンド
今回は、awkコマンドです。
IT業界に入って最初のプロジェクトがインフラだったので、とてもお世話になりました。
先輩方と一緒にターミナルに向かいながらしのぎを削ってたのは、今となっては懐かしい思い出です。

## awsコマンドとは
テキスト処理のためのプログラミング言語で、シェルスクリプトと組み合わせて使われることが多いです。私がよく利用していたケースには以下のものがあります。
- **ログファイルの解析**
システムログやアプリケーションログなど、定形フォーマットのログファイルを解析し、情報を抽出。

今回は、最もよく利用したアクセスログの解析について書こうと思います。

## アクセスログ
以下は、Webサーバのアクセスログの例です。各行は一つのリクエストを表し、IPアドレス、日時、リクエストメソッド、URL、ステータスコード、応答サイズなどの情報が含まれています。
```bash
192.168.1.1 [01/Jan/2023:10:00:00 +0000] "GET /index.html HTTP/1.1" 200 512
192.168.1.2 [01/Jan/2023:10:05:00 +0000] "POST /login.php HTTP/1.1" 200 244
192.168.1.1 [01/Jan/2023:10:10:00 +0000] "GET /about.html HTTP/1.1" 200 768
192.168.1.3 [01/Jan/2023:10:15:00 +0000] "GET /aaa.html HTTP/1.1" 404 0
```
ここで、200は正常、404はNot Foundですね。

## awkとシェルを使った簡易的な集計
先ほどのアクセスログから、IPアドレスとリクエストURLを抽出し、それぞれのIPアドレスからのリクエスト数を集計してみましょう。

```bash
awk '{print $1, $7}' access.log | sort | uniq -c | sort -nr
```
このコマンドを順番に見ていきましょう。
```bash
awk '{print $1, $7}' access.log
```
各行からIPアドレス（1つめのフィールド）とリクエストURL（7つめのフィールド）を抽出。
```
| sort
```
抽出したデータをソートします。
ここで「|」はパイプと呼ばれ、前の結果をキャッシュして次のコマンドに渡す。
```bash
| uniq -c
```
重複する行（同じIPとURLの組み合わせ）をカウント。
```bash
| sort -nr
```
リクエストの多い順に並び替えます。

## 実行結果
```bash
$ awk '{print $1, $7}' access.log | sort | uniq -c | sort -nr
   2 192.168.1.1 200
   1 192.168.1.3 404
   1 192.168.1.2 200
```
192.168.1.1からのリクエストは2件、それ以外は1件という結果になりました。

ちゃんと集計できていましたね！

このように、コマンドをうまく組み合わせることで、簡単に集計ができます。
今でもたまに利用しているので、みなさんもぜひ、コマンドの楽しさを体験してください！
Multipassで仮想環境を作成する際において、特定のネットワーク設定が適用されているとlaunchに失敗する現象の解決方法

## MultipassでUbuntu 22.04 LTSを起動しようとすると、エラーが出る。
<dt>【エラー文】</dt>
<dd>「launch failed: Could not start VM: VBoxManage.exe: error: UUID {93c4b138-8354-4f94-a906-9e039d73a4a8} of the medium 'C:\ProgramData\Multipass\data\virtualbox\vault\instances\linux-study\ubuntu-22.04-server-cloudimg-amd64.vdi' does not match the value {0dcf5f73-87f6-4160-baae-64e601103e25} stored in the media registry ('C:\Windows\system32\config\systemprofile\.VirtualBox\VirtualBox.xml')
VBoxManage.exe: error: Details: code E_FAIL (0x80004005), component MediumWrap, interface IMedium
Waiting for VM "linux-study" to power on...」や</dd><p>
<dd>「launch failed: Could not generate a new UUID: Process operation timed out」</dd>
などのエラーが確認できました。
<br>
<br>
<br>

## 解決方法

### 【手順1】

![スクリーンショット (53).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631159/1c086592-1f79-e5eb-0343-43be8c067815.png)
`タスクバー上のネットワークを表示する項目から、接続しているネットワークを選択してください。`
<br>
<br>
<br>

### 【手順2】
![スクリーンショット (54).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631159/2705ade0-91c7-b0a5-7484-c69a7482b94e.png)

`「関連設定」→「アダプターのオプションを変更する」を選択します。`
<br>
<br>
<br>

### 【手順3】
![スクリーンショット (55).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631159/1f2e521d-261d-cddc-803e-bd46f871a4da.png)

`使用しているネットワークを右クリックし、プロパティを開きます。`
<br>
<br>
<br>

### 【手順4】
![スクリーンショット (56).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631159/11a53faa-d140-5408-dd53-81ca3f405f7c.png)

`「共有タブ」から「インターネット接続の共有」にある「ネットワークのほかのユーザーに、このコンピューターのインターネット接続をとおしての接続を許可する(N)」のチェックボックスを外します。`

以上で終了となります。

ネットワーク共有を切っておかないと、同一ネットワークからの接続と判定されて、独立した環境とみなされないのでしょうか。。。？

私もまだまだ勉強中の身ですので、教えていただけると幸いです。
VSCodeでJavaの開発環境をサクッと構築する

:::note info
本記事は新人向け社内研修資料の一部として作成したものです。
一部冗長な説明をしている箇所がありますがあしからず。
:::

## はじめに
javaの開発には、**テキストエディタ**と**javaのコンパイラ**と**javaの実行環境**が必要です。

どういうことかというと、例えばあなたが知らない国の舞台の脚本を任されたとします。そのとき、まずはあなたは自国語で台本を作成する必要がありますね。そして台本を作成したら、それを通訳に翻訳してもらって翻訳版の台本ができあがります。そして翻訳版の台本を知らない国の劇団に渡せば、知らない国で舞台が行われます。[^1]
上記の
- 自国語で台本を作成
- 通訳に翻訳してもらう
- 翻訳された台本をもとに舞台が行われる

がそれぞれ

- テキストエディタでソースコード作成
- コンパイラでソースコードをコンパイル
- コンパイルされたファイルを実行環境で実行

にあたります。

軽くそれぞれについて説明をすると、

テキストエディタはjavaのソースコードを作成するのに使います。
windowsユーザはメモ帳、macユーザはテキストエディットを思い浮かべていただくとわかりやすいと思います。
今回はおそらくエンジニア界隈でトップシェアを誇るであろうVSCodeというエディタを使います。

そしてjavaのコンパイラとjavaの実行環境として今回はopenJDKというオープンソースを使います。openJDKをインストールすればコンパイラと実行環境がついてくるのでopenJDKだけインストールすればokです。

## やること
1. インストーラの準備
2.  vscのインストール
3.  openJDKのインストール

## for windows
### 1. インストーラの準備
今回はwindowsで最近主流な[scoop](https://scoop.sh/)を使います。
powerShellを開いて以下を実行します。
```powershell
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser # Optional: Needed to run a remote script the first time
irm get.scoop.sh | iex
```

### 2. vscのインストール
scoopを使ってvscをインストールします。
```powershell
scoop install git
scoop bucket add extras
scoop install vscode
```

### 3. openJDKのインストール
scoopを使ってopenJDKをインストールします。
```powershell
scoop bucket add java
scoop install openjdk
```

## for mac
### 1. インストーラの準備
今回はmacのインストーラといえばの[homebrew](https://brew.sh/ja/)を使います。
ターミナルを立ち上げて以下をコピペして実行します。
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

### 2. vscのインストール
homebrewを使ってvscをインストールします。
```bash
brew install --cask visual-studio-code
```

### 3. openJDKのインストール
homebrewを使ってopenJDKをインストールします。
```bash
brew install openjdk
```

※macOS>=10.15の場合はinstall直後に以下を実行してください。
```bash
sudo ln -sfn $(brew --prefix)/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk
```

 ## 動作確認
 1. VSCodeを立ち上げます。
 ![スクリーンショット 2023-12-01 9.20.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2947418/97c4d5e5-b4ee-2dac-9370-0b88a2d24168.png)

2. 左上のメニューから「Terminal」->「New Terminal」を選択肢します。
![スクリーンショット 2023-12-01 9.21.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2947418/b924ba4b-f391-d209-2049-e26c435e807a.png)

3. 画面下部にターミナルが開くので「javac --version」と実行します。
画像のようになればOK(細かい数字が違っててもNPです)
![スクリーンショット 2023-12-01 9.23.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2947418/77eef68b-f84b-aab8-b6fb-d722b786b15b.png)

4. ターミナルで「java --version」と実行します。
画像のようになればOK(細かい数字が違っててもNPです)
![スクリーンショット 2023-12-01 9.25.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2947418/9340db34-dd39-68bf-962d-4150a22186d3.png)

[^1]:こんな簡単に舞台できるわけないです。
Reactで状態管理を利用する(jotai)

## はじめに
[前回記事](https://qiita.com/koji0705/items/c1d2e9d4a5c4399e35c7)の続きです。Providerを利用せず状態管理のjotaiを利用して作成します。

## 成果物
![スクリーンショット 2023-11-29 11.57.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/f5065654-0a7e-3670-e5c1-bb7b6df8039c.png)

## ソースコード

```tsx: src/App.tsx
import { Content } from "./Content";
import { Header } from "./Header";
import { Provider } from "jotai";

const App: React.FC = () => {
  return (
    <Provider>
      <Header />
      <Content />
    </Provider>
  );
};

export default App;
```

```tsx:src/Header.tsx
import { useAtom } from "jotai";
import { activeTabAtom } from "./state";

const TABS = ["Tab1", "Tab2", "Tab3", "Tab4"];

export const Header: React.FC = () => {
  const [, setActiveTab] = useAtom(activeTabAtom);

  return (
    <div>
      {TABS.map((tab, index) => (
        <button key={index} onClick={() => setActiveTab(index)}>
          {tab}
        </button>
      ))}
    </div>
  );
};

```

```tsx:src/Content.tsx
import { useAtom } from "jotai";
import { activeTabAtom } from "./state";

export const Content: React.FC = () => {
  const [activeTab] = useAtom(activeTabAtom);

  return (
    <div>
      {activeTab === 0 && <div>Content for Tab 1</div>}
      {activeTab === 1 && <div>Content for Tab 2</div>}
      {activeTab === 2 && <div>Content for Tab 3</div>}
      {activeTab === 3 && <div>Content for Tab 4</div>}
    </div>
  );
};
```

```ts:src/state.ts
import { atom } from "jotai";

// タブの状態を保持するアトムを定義
export const activeTabAtom = atom(0);

```
ReactでProviderを利用する

## はじめに
表題通り、ReactでProviderを利用します。

### 成果物

![スクリーンショット 2023-11-29 11.57.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/f5065654-0a7e-3670-e5c1-bb7b6df8039c.png)

### 設計
![IMG_0827.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/9dd38017-6921-0eb4-d40f-a9f16ca5149a.jpeg)

・親コンポーネント以下では、Tabの情報が更新可能にする
・子コンポーネントのHeaderでは、Tab情報の更新
・子コンポーネントのContentでは、Tab情報を取得し表示を切り替える

### ソースコード
```tsx:App.tsx
import { Content } from "./Content";
import { Header } from "./Header";
import { TabProvider } from "./TabContext";

const App: React.FC = () => {
  return (
    <TabProvider>
      <Header />
      <Content />
    </TabProvider>
  );
};

export default App;

```

```tsx:TabContext.tsx
import React, { useState, createContext, useContext, ReactNode } from "react";

export interface TabContextType {
  activeTab: number;
  setActiveTab: (index: number) => void;
}

export const TabContext = createContext<TabContextType | undefined>(undefined);

export interface TabProviderProps {
  children: ReactNode;
}

export const TabProvider: React.FC<TabProviderProps> = ({ children }) => {
  const [activeTab, setActiveTab] = useState(0);

  return (
    <TabContext.Provider value={{ activeTab, setActiveTab }}>
      {children}
    </TabContext.Provider>
  );
};
```

```tsx:Header.tsx
import { useContext } from "react";
import { TabContext } from "./TabContext";

const TABS = ["Tab1", "Tab2", "Tab3", "Tab4"];

export const Header: React.FC = () => {
  const context = useContext(TabContext);
  if (!context) {
    throw new Error("Header must be used within a TabProvider");
  }
  const { activeTab, setActiveTab } = context;

  return (
    <div>
      {TABS.map((tab, index) => (
        <button key={index} onClick={() => setActiveTab(index)}>
          {tab}
        </button>
      ))}
    </div>
  );
};

```

```tsx:Content.tsx
import { useContext } from "react";
import { TabContext } from "./TabContext";

export const Content: React.FC = () => {
  const context = useContext(TabContext);
  if (!context) {
    throw new Error("Content must be used within a TabProvider");
  }
  const { activeTab } = context;

  return (
    <div>
      {activeTab === 0 && <div>Content for Tab 1</div>}
      {activeTab === 1 && <div>Content for Tab 2</div>}
      {activeTab === 2 && <div>Content for Tab 3</div>}
      {activeTab === 3 && <div>Content for Tab 4</div>}
    </div>
  );
};

```
TypeScriptとsdk client-s3のv3を使ってs3にオブジェクトをアップロードする方法

## 概要

aws-sdk/client-s3 の v3 を使って s3 にアップロードをするにあたって、特に s3 との認証周りで少し苦労したので、ここに方法を書き残しておきます。

## 動作確認環境

- TypeScript 5.3.2
- ts-node 10.9.1
- aws-sdk/client-s3 3.461.0
- aws-sdk/credential-providers 3.461.0

## 前提条件

AWS に接続先の s3 バケットを用意していること
s3 を操作できる iam を用意していること

## コード例

最終的にこんな感じでアップロードできました。（環境変数の読み込みは next.js のお作法に則っています）

```ts
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { fromIni, fromContainerMetadata } from "@aws-sdk/credential-providers";

class MyS3Client {
  private client: S3Client;

  constructor() {
    this.client = new S3Client({
      region: "ap-northeast-1",
      credentials: this.createCredentials(),
    });
  }

  async putObject() {
    const params = {
      Bucket: process.env.BUCKET_NAME,
      Key: "hello.txt",
      Body: "hello from mys3client",
    };

    await this.client.send(new PutObjectCommand(params));
  }

  private createCredentials() {
    if (process.env.NEXT_PUBLIC_APP_ENV === "local") {
      return fromIni({
        profile: "your-aws-profile",
      });
    } else {
      return fromContainerMetadata();
    }
  }
}

const s3Client = new MyS3Client();
s3Client.putObject();
```

## 解説

こちらの S3Client の初期化については[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html)にあるように region や credentials を設定してあげなくても、デフォルトの profile を使って接続をしてくれます。

```ts
this.client = new S3Client({
  // region: "ap-northeast-1",
  // credentials: this.createCredentials(),
});
```

ですが、profile を指定したい場合や、本番環境では別の認証方法にしたい場合には特別に credentials も指定してあげる必要があります。
そのために、aws-sdk/credential-providers を使って credentials 情報を付与します。

今回はローカルの環境では profile を使い、デプロイ先では ECS のタスクロールの権限を利用したかったため、分岐させています。

```ts
 private createCredentials() {
    if (process.env.NEXT_PUBLIC_APP_ENV === "local") {
      return fromIni({
        profile: "your-aws-profile",
      });
    } else {
      return fromContainerMetadata();
    }
  }
```

環境変数を認証に利用する場合やデプロイ先が EC2 の場合などにはユースケースに応じて利用するメソッドが異なります。
[こちら](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html)にそれぞれのユースケースがまとめられています。

## 苦労した箇所

一番よく出していたエラーは

```
AccessDenied: Access Denied
```

でした。なぜ拒否されるのかのフィードバックが少なくて困っていました。
私の場合このエラーは 「credential の設定自体は読み込めているものの、接続しようとしているバケットにオブジェクトをアップロードする権限がない。」
という理由で起きていました。
なのでこのエラーの解消において確認すべきはコード側ではなく、iam の権限設定や s3 バケットのバケットポリシーです。

よくある間違いとしては iam 側の設定でアクセスするバケットのオブジェクトの指定が s3 バケットの arn のみが書かれているパターンではないでしょうか。

```sh
# よくない例
arn:aws:s3:::your-bucket-name
```

このままではそのバケット配下にオブジェクトを入れることができません。
末尾に`/*`をつけるようにしてください。

```sh
# よい例
arn:aws:s3:::your-bucket-name/*
```

## まとめ

v2 から v3 になって credentials 情報をコードの中になるべく書かずに実装できるようになりました。
これまで環境変数を使って割り当てていたりしましたが、（v3 でもその方法はあります）credential-providers を使うと何かと便利でした。

どなたかの助けになれば幸いです。
【Laravelキュー】Dockerコンテナでのキューワーカー自動起動

記事が参考になったが、`entry-point`では動かなかった。

### 解決

PHPコンテナのコピーコンテナ内でキューワーカーを起動させる
* `volumes`が大事。
* コピーコンテナとPHPコンテナをちゃんと繋げないと、「`artisan`コマンドが実行できないです」と、怒られてしまう。

```yml:docker-compose.yml
#...
services:
    php:
        build:
            context: .
            dockerfile: ./docker/php/Dockerfile
        volumes:
            - ./src:/var/www
        restart: always

    container_worker:
        build:
            context: .
            dockerfile: ./docker/php/Dockerfile
        restart: always
        volumes:
            - ./src:/var/www
        working_dir: /var/www/php-dir
        command: php artisan queue:listen --timeout=1000

#...
```

### 参考記事

https://footloose-engineer.com/docker-compose-working-dir/

https://www.aska-ltd.jp/jp/blog/203
【Jetpack Compose】特定の文字だけ色を変える

# はじめに

この記事は[and factory.inc Advent Calendar 2023](https://qiita.com/advent-calendar/2023/andfactory) 1日目の記事です。

and factoryでandroidエンジニアをやっていますが、
今年学んだ小さいチップスを共有したいと思います。

# 特定の文字だけ色を変えるComposable

Jetpack Composeネタです。
こういうことしたいケースは稀ですが検索候補でヒットした文字列だけ色を変えるとかで使えそうですね。

![スクリーンショット 2023-07-06 10.54.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193770/617c6dff-918b-cbf0-459b-2c72cfe5633d.png)

# とりあえずコピペしよう

サンプルは赤色ですが、上記のプレビュー画像はオレンジ色の独自のカラーを指定しています。

```kotlin
// 指定文字列を指定色に変える拡張関数
fun String.colorize(colorizeString: String, color: Color): AnnotatedString {
    val modifiedString = this.replace(colorizeString, "|||$colorizeString|||")
    val resultArrayIncludingSplit = modifiedString.split("|||").filter { it.isNotEmpty() }
    return buildAnnotatedString {
        resultArrayIncludingSplit.forEach {
            if (it == colorizeString) {
                withStyle(
                    style = SpanStyle(color = color),
                ) {
                    append(it)
                }
            } else {
                append(it)
            }
        }
    }
}


// 使用例
@Composable
fun TextColorizer(text: String, filterString: String) {
    Text(
        text.colorize(colorizeString = filterString, color = Color.Red), // 好きな色に変えてください
    )
}

@Preview
@Composable
fun TextColorlizerPreview() {
    TextColorizer("風の谷のナウシカ", "の")
}
```

# 具体的には

以下のような流れが実現できるコードです。

1. 文字列をパースできる形に変換する（この場合｜｜｜を入れている）
2. 文字列｜｜｜区切りで配列にパースする
3. 配列を回して文字列一致するもののスタイルを変更する

# おわりに

力技ですが実際に弊社で開発しているマンガアプリで使われています。
ぜひご利用とともに探してみてください。（ヒントはオレンジ色）

明日の[Advent Calendar](https://qiita.com/advent-calendar/2023/andfactory)の記事もお楽しみに:santa:
ついに JavaScript に groupBy が実装されたぞ！！！

JavaScript標準でgroupBy関数が実装されています。2023年11月現在Safari以外の主要なブラウザで実装済みで、SafariもTechnology Previewのようです。
（~~現在MDNの日本語の記事は古い情報のままになっており、現行と異なるので注意！~~ →更新していただきました。ありがとうございます！）

Proposal の Stage はすでに 4 / Finished なので規格として確定済みです。

https://caniuse.com/mdn-javascript_builtins_object_groupby

https://caniuse.com/mdn-javascript_builtins_map_groupby

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy

# 基本的な使い方
よくあるgroupByです。配列（Iterable）とキーを抽出する関数の二つを指定すると、キーで配列をグループ化します。

```javascript
const ret = Object.groupBy([
  { name: '山田太郎', address: '東京' },
  { name: '山田次郎', address: '愛知' },
  { name: '山田三郎', address: '大阪' },
  { name: '山田四郎', address: '東京' },
], x => x.address);
// ret = {
//   "東京": [
//     { "name": "山田太郎", "address": "東京" },
//     { "name": "山田四郎", "address": "東京" }
//   ],
//   "愛知": [
//     { "name": "山田次郎", "address": "愛知" }
//   ],
//   "大阪": [
//     { "name": "山田三郎", "address": "大阪" }
//   ]
// }
```

# 2つある
JavaScriptのgroupByは2つあります。`Object.groupBy()` と `Map.groupBy()` です。`Object.groupBy()` はプレーンなオブジェクトで返し、`Map.groupBy()` は [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) 型で返します。

プレーンなオブジェクトのキー（プロパティ）になれるのは文字列だけなので、文字列以外をキーにしたい場合は `Map.groupBy()` を使うという事です。

```javascript
Map.groupBy([{ hoge: 3 }, { hoge: 4 }, { hoge: 3 }], x => x.hoge);
```

# 配列のメソッドではない
groupByは配列のメソッドになるのが直感的と思いますが、`Object` と `Map` の静的メソッドになっています。これはライブラリの中には配列のプロトタイプを書き換えてgroupByを挿入するものがあるのでそれの互換性を崩さないようにした結果のようです。

正直 `Array` に入れた方が自然でよい気がしますがね。今後もこういうみんなほしいと思っているメソッドは全部不自然な形でしか標準には入れられないという事になっちゃうのかな…そこは残念。