OmniAICreator/Qiita-1.07M huggingface dataset:
Vue.js　Routerとは

### はじめに
最近Vue.jsの勉強を始めて、わかないことやつまずくことがたくさんあったので、学んだことを共有したいと思います。

### Vue Roter
Vue.jsのプラグインの一つで、SPAのルーティングをする為のもの。
Vue Routerを使用することで、ページ全体のリロードをすることなく画面遷移できるようになります。

・main.js
```javascript
import Vue from "vue";
import App from "./App.vue";
// ルーティング機能を実装しているディレクトリを宣言
import router from "./router"; 

Vue.config.productionTip = false;

new Vue({
  // Vueで使用できるようにしている
  router,
  render: (h) => h(App),
}).$mount("#app");
```

・App.vue
```vue
<template>
  <div id="app">
    <div id="nav">
      // ルーティングのパスを指定し、リンク押下でパスに紐づく画面が表示される
      <router-link to="/">Main</router-link>
      <router-link to="/edit">Edit</router-link>
    </div>
    // パスに紐づく画面が表示される場所
    <router-view />
  </div>
</template>
```

・index.js/router.js
└Vue Router使用宣言、ルーティング定義やその他設定するファイル
```javascript
import Vue from "vue";
// VueRouterを宣言
import VueRouter from "vue-router";
// ルーティングのパスと紐づける画面コンポーネントを宣言
import Home from "../views/Main.vue";

// VueRouterを使用する宣言
Vue.use(VueRouter);

const routes = [
  // パス　"/"　で表示するコンポーネントを設定
  {
    path: "/",
    name: "Main",
    component: Main,
  },
  {
    path: "/edit",
    name: "Edit",
    component: Edit,
];

// VueRouterにルーティング情報の設定、modeでは「hash」又は「history」から選択可、baseではルートURLの設定
const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

export default router;
```

上記コードで、Vue Routerを使用できました。
正規表現でマッチするログKQLでトランザクションＩＤごとに出力する

// 正規表現を使用して条件に一致するトランザクションIDを抽出
let relevant_transactions = message
| where column_name matches regex "正規表現"
| project TransactionId;

// 抽出したトランザクションIDに基づいてログを取得
trace
| where TransactionId in (relevant_transactions)
| order by TransactionId asc, Timestamp asc
| extend JST_Timestamp = Timestamp + 9h
| project JST_Timestamp, TransactionId, Message
A walkthrough for Android’s on-device GenAI solutionsを見るメモ

Spotlight WeekというのでどうやってAndroidのアプリにAIを入れるかというのを紹介してくれているので、その一つの動画になります。
[﻿https://android-developers.googleblog.com/2024/09/welcome-to-ai-on-android-spotlight-week.html](https://android-developers.googleblog.com/2024/09/welcome-to-ai-on-android-spotlight-week.html) 



[﻿https://www.youtube.com/watch?v=EpKghZYqVW4](https://www.youtube.com/watch?v=EpKghZYqVW4) 



一旦Gemini Nanoは以下のブログで動かしてみました。

[﻿https://qiita.com/takahirom/items/1c5f133ae0cfeb9b9517](https://qiita.com/takahirom/items/1c5f133ae0cfeb9b9517) 

ちょっと知識を入れていきます。



この記事を元にAIに生成してもらった図はこちら。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/8aeacfbd-a476-09f7-8ab9-eef174f43cc0.png "")



## On device AIのメリット
- 外に送られるべきでないユーザーデータをデバイス内で処理できる
- インターネットにアクセスできなくても利用できる
- レイテンシーを改善できる
- 追加コストが発生しない
## Gemini Nano
https://goo.gle/nano-experimental

### Gemini Nanoとは

Gemini NanoはSystem ServiceのAI Coreによって動く。
Gemini NanoはGoogleの一番小さいGeminiのモデル。

### AI CoreとGemini Nano
AI CoreはアプリとGemini Nanoモデル、ハードウェアアクセラレーターのインタラクションを行う。

なので、アプリはGoogle AI Edge SDKを触るだけでOK

アプリコード <-> Google AI Edge SDK <-> AICore <-> ハードウェア

### 現状
text to textをAndroid開発者コミュニティに提供した。

Gemini Nano 2が来て、multi modalが可能になった。(つまり今公開されているtext to textのみのAPIは機能制限されているということっぽい)
Talk backやPixel screenshotはこれが使われている。
かなりGemini Nano 1と比べて色々良くなった。パラフレーズやスマートリプライなどで顕著に良くなった。



## Sample app
[﻿https://github.com/android/ai-samples](https://github.com/android/ai-samples) 

サンプルでModelダウンロードしたり色々できる。

またパラメーターをいじれる。
Templature, TopK, MaxOutputTokensがいじれる。
Templatureはランダムネス。多様なアウトプットが得られる。
TopKはトークンのランキングで何番目まで考慮するか。
MaxOutputTokensは返すトークン数。
色々いじって何がうまく動くのか見るのが良い。

```kotlin
val generationConfig = generationConfig {
...
  temperature = 0.2f
  topK = 16
  candidateCount = 1
  maxOutputTokens = 256
}
```
Download callbackで、ダウンロードが終わったことや、デバッグなどで使える。

複数行の場合にcontent objectを使うこともできる。(多分ここで画像とかも渡せるようになりそう)

```kotlin
content {
  text("xxxxxx")
  text("xxxxxx")
}
```


## Tips
- Gemini Nanoはスレートレスなので、前の回答とかは覚えていないので、そのコンテキストをpromptに与える必要がある。
- プロンプトでサンプルの回答を与えてそれを元に回答させて精度を高める。
- もっと要求を詳細に指定する。(通常のLLMよりかなり小さいため。)
## Media Pipe Tasks LLM Inference API
https://goo.gle/llm-inference-guide



Gemma-2B modelのようなOpen Modelも人気になってきている。


ちょっと以下で入門してきました。


﻿https://qiita.com/takahirom/items/bd41a215cdd8f8307331



MediaPipeはかなり抽象化してくれるのでシンプルに処理できて、Gemma-2B modelのようなOpen Modelを使うことができる。

TopKやTemperatureの他にModelのパスやLora weightのパスも設定できる。

もっとコントロールできるstarting tokenとend tokenなどがあるがここでは説明しない。



![image.png](https://eraser.imgix.net/workspaces/OhFypfa4AzR5dEOket22/ZdHEeTSqFAXowSBLaw8DfVp70Vs2/mSb1ca5IlyUAbAPIVinh6.png?ixlib=js-3.7.0 "image.png")

[﻿https://youtu.be/EpKghZYqVW4?t=531](https://youtu.be/EpKghZYqVW4?t=531) より

## まとめで、使い分けとして言われていたもの


### Gemini Nano
開発者にon device gen AIソリューションを提供する。モデルをダウンロードしたり、メンテナンスすることなしに可能になる。Androidの基盤でのモデルになる。

### Media Pipe Tasks LLM Inference API
オープンモデルを実験したいリサーチャー向けにMedia Pipe Tasks LLM Inference APIは良い。
オブジェクト指向とは何か

# オブジェクト指向とは何か

## はじめに
　はじめまして．Yasuと申します．プログラミング未経験（趣味レベルでVBAやPythonの経験はある）からWeb系エンジニアへの転職を目指して，学習しています．
　少なくとも２週間ごとに学習成果をアウトプットする目的で記事を作成します．自分のための記事にはなりますが，同じように学習している初学者の方にも参考になれば嬉しいです．

## 1. オブジェクト指向とは？
　オブジェクト指向は「現実の物事~~を~~のようにプログラムで表現する方法」と言えます．例えば「車」という**オブジェクト**には，色や**属性**（モデル），**メソッド**（走る・止まる）といった特徴があります．プログラムでも，このように物事をオブジェクトとして表現し，扱うことができます．

## 2. オブジェクト，クラス，メソッドについて
　オブジェクト指向では，まず**クラス**と呼ばれる設計図を作ることで，そこから具体的なオブジェクト（実態）を作り出します．クラスの中には，オブジェクトが持つ属性やメソッド（動作）が定義されます．
　クラスから生成された具体的なオブジェクトを**インスタンス**ともいいます．
``` ruby
class Car
  def initialize(model)
    @model = model
  end

  def drive
    puts "#{@model}が走ります．"
  end
end

car = Car.new("Toyota")
car.drive # => Toyotaが走ります．
```

　このコードでは，`Car`クラス（設計図）から「Toyota」というインスタンス（実際の車）を作って「drive」メソッドを実行して（走らせて）います．

## 3. カプセル化
　**カプセル化**とは，オブジェクトの内部の情報を隠すことを指します．例えば，車のエンジンの中身を知らなくても，アクセルを踏めば走るように，外部から操作できる部分だけを公開します．
``` ruby
class Car
  def initialize(model)
    @model = model
  end

  def drive
    start_engine
    puts "#{@model}が走ります．"
  end

  private

  def start_engine
    puts "エンジンを始動します．"
  end
end
```
　例えば，`start_engine`メソッドは外から直接呼び出せないように`private`で隠しています．
　こうすることで不必要な情報を公開したり，外部から不正にアクセスされたりすることを防ぐことができます．これを**隠蔽**といいます．

## 4. 単一責任の原則
　**単一責任の原則**は，クラスやメソッドが１つの役割だけを持つべきだという考え方です．１つのクラスにいろいろな機能を詰め込んでしまうと，そのクラスが何をしているのかわかりにくくなってしまうし，仕様変更が生じた際にどこを修正すればよいかわからなくなってしまいます．

``` ruby
class Engine
  def start
    puts "エンジンを始動します．"
  end
end

class Car
  def initialize(model)
    @model = model
    @engine = Engine.new
  end

  def drive
    @engine.start
    puts "#{@model}が走ります．"
  end
end
```
　これで，「車」と「エンジン」の役割が分かれ，それぞれの責任が明確になりました．

## 5. 継承
　**継承**とは，あるクラス（親クラス）から別のクラス（子クラス）が機能を引き継ぐことをいいます．例えば，車やバイクというクラスが共通して持つ動作を「乗り物」という親クラスにまとめることで，コードを再利用できます．

``` ruby
class Vehicle
  def initialize(model)
    @model = model
  end

  def drive
    puts "#{@model}が走ります．"
  end
end

class Car < Vehicle
end

class Bike < Vehicle
end
```
　こうすることで，`Car`や`Bike`はそれぞれが固有の機能を持ちつつ，`Vehicle`から共通の機能を継承できます．

## 6. ポリモーフィズム（多態性）
　**ポリモーフィズム**とは，同じメソッド名でも異なるクラスで異なる動作をさせることができる仕組みのことです．
``` ruby
class Car
  def drive
    puts "車が走ります．"
  end
end

class Bike
  def drive
    puts "バイクが走ります．"
  end
end

def start_vehicle(vehicle)
  vehicle.drive
end

start_vehicle(Car.new) # => 車が走ります．
start_vehicle(Bike.new) # => バイクが走ります．
```
　この例では，同じ`drive`メソッドでも，`Car`と`Bike`で異なる動作をしていることがわかります．

## 7. モジュールとミックスイン
　Rubyには**モジュール**という機能があり，これを使うとクラスに共通の機能を簡単に追加できます．Rubyでは複数の親クラスを持つことはできませんが，モジュールを使うことで多重継承（親クラスを複数持つ状態）のようなことができます．
``` ruby
module Wash
  def wash
    puts "洗濯します．"
  end
end

class Car
  include Wash
end

car = Car.new
car.wash # => 洗濯します．
```
　この例では，`Wash`というモジュールを`Car`クラスに**ミックスイン**して，車を洗濯しています．

## 8. DRY原則とオブジェクト指向
　同じコードを繰り返し書かないという，**DRY**（Don`t Repeat Yourself）原則という考え方があります．オブジェクト指向では，共通の動作をクラスやモジュールにまとめることで，コードの重複を避けることができます．
 
## 9. まとめ
　オブジェクト指向とは，現実の物事をプログラムで表現する方法です．クラスからオブジェクトを生成し，カプセル化や単一責任の原則を活用して保守性を高めます．また，継承やポリモーフィズムによりコードの再利用と柔軟性を実現し，モジュールを用いて共通の機能を追加することも可能だということがわかりました．
　大規模なプログラムになるほど，可読性や保守性，柔軟性が重要になってくるので，これからもオブジェクト指向を意識してプログラミングしていきます．
EFSアクセスポイントの制限について

# はじめに
公式ドキュメントに書いてあるものの、調べるのに少し時間がかかってしまったので、残しておこうかと思います。

## EFSアクセスポイントの作成に失敗した話
先日、仕事で`terraform`を使って階層深めのEFSアクセスポイントを作成しようとしたところ、以下のようなエラーが発生して、作成ができないことがありました。

```hcl
╷
│ Error: creating EFS Access Point for File System (fs-xxxxxxxxxxxxxxxxx): ValidationException: 1 validation error detected: Value '/one/two/three/four/five' at 'rootDirectory.path' failed to satisfy constraint: Member must satisfy regular expression pattern: ^(\/|(\/(?!\.)+[^$#<>;`|&?{}^*/\n]+){1,4})$
│ {
│   RespMetadata: {
│     StatusCode: 400,
│     RequestID: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
│   },
│   Message_: "1 validation error detected: Value '/one/two/three/four/five' at 'rootDirectory.path' failed to satisfy constraint: Member must satisfy regular expression pattern: ^(\\/|(\\/(?!\\.)+[^$#<>;`|&?{}^*/\\n]+){1,4})$"
│ }
│
╵
```

GUI画面から作成しようとした場合は以下のように表示されます。

![スクリーンショット 2024-10-19 14.14.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/025e0bed-c58c-955a-e4f9-051015c2ccc3.png)

## EFSアクセスポイントのルートディレクトリ制限
AWSのドキュメントには書かれておりますが、マウントさせるEFS側領域を設定するルートディレクトリの階層に制限があります。

:::note info
- ディレクトリ階層は4階層まで
- フルパスの長さは100文字以内
:::

今回の場合、ディレクトリ階層が5階層となっていたためエラーが発生したということでした。

- [アクセスポイントによるルートディレクトリの強制](https://docs.aws.amazon.com/efs/latest/ug/enforce-root-directory-access-point.html)

# おわりに
調べてみると文字数はともかく、階層数は今回の私のように引っかかる方が多いのではないかと思います。

まぁ、そもそもそんなに階層数深くするような設計にするなということなんでしょうね。
【Cコード解析】elseブロックを自動で追加する

コーディングの業務をやっていると静的解析ツールから受けた指摘を対処する仕事がある。今回はif文に対してelseブロックを自動追加するスクリプトを作成する。

## ifブロックをマッチさせるパターン
前回書いた記事をベースに考える。

https://qiita.com/name_ko/items/afa78577907dbd124acb

下記の正規表現でifブロックまたはelseブロックをマッチさせる。
``` regex
(?<=\n)\s*(?:\bif\b|\belse\b\s*\bif\b)\s*\([^()]*\)\s*(\{(?:[^{}]|(?1))*\})(?!\s*\belse\b\s*\bif\b|\s*\belse\b)
```
少々、長いパターンだが、`if`または`else if`から始まるブロックを探す正規表現である。
また、ブロックの後ろに`else if`または`else`がないことを保証する。正規表現の末尾の`(?!\s*\belse\b\s*\bif\b|\s*\belse\b)`で実現している。

これによって`else if`ブロックまたは`else`ブロックが続かない、`if`ブロックと`else if`ブロックを抜き出せる。つまり下記のようなif文のコード。
``` c
	if  (a < 10)
	{
		printf("a is small value");
	}

	if(b < 10)
	{
		printf("b is small value");
	}
	else if(c < 10)
	{
		printf("c is small value");
	}
```

## マッチさせたifブロックにelseブロックを追加する
`regex.sub`を使って`else`ブロックを追加する。コードは下記。
``` python
import regex

def elseblock_repl(match):
	elseblock = "\nelse\n{\n\t/* 処理なし */\n}"
	matchstr = match.group()

	# if文のインデントを取得する
	indent = regex.search(r"[\t ]*(?=\bif\b|\belse\b\s*\bif\b)", matchstr, regex.DOTALL).group()
	return matchstr + elseblock.replace("\n", "\n" + indent)

with open("test.c", "r", encoding="utf-8", errors="ignore") as file_obj:
	codetext = file_obj.read()
	ret = regex.sub(r"(?<=\n)\s*(?:\bif\b|\belse\b\s*\bif\b)\s*\([^()]*\)\s*(\{(?:[^{}]|(?1))*\})(?!\s*\belse\b\s*\bif\b|\s*\belse\b)", elseblock_repl, codetext, regex.DOTALL)
print(ret)
```

`regex.sub`で置換先の文字列は`elseblock_repl`関数を指定する。
まずは`if`文のインデントを図る。下記の正規表現を使うことで`if`または`else if`の前にあるスペースとタブを抽出できる。
```
[\t ]*(?=\bif\b|\belse\b\s*\bif\b
```
抽出したインデントを`else`ブロックのテンプレートである`elseblock`に対してインデントを追加させ、実際に追加する場所のインデントと合うようにする。

`elseblock_repl`関数の引数である`match`にはマッチ情報が入ってくるため、マッチした文字列にインデントを調整した`else`ブロックの文字列を加えたものを`return`する。すると、`else`がない`if`ブロックに対して`else`ブロックが追加される。

## まとめ
このスクリプトを考えた経緯は静的解析ツールの指摘に自動で対応したいから。プロジェクトの規模にもよるが「elseがありません！」という指摘が500件とか1000件になると、それを手動で直すだけで数日掛かるし指も痛める。こういった単調作業はどんどん自動化したい。:grin:
Comparatorを使って自在に並べ替える

# Comparatorとは？
Javaのインターフェースの一つ。Comparatorを実装することで、自分がカスタムした順番でソートすることができるようになります。
例えば、以下の場面で役に立ちます。
- 複数のフィールドでソートしたい場合
    - 例：顧客リストを年齢、購入額などの順にソート
- カスタム順序が必要な場合
    - 例：購入額が一定以上の顧客を上位に表示する、最近の購入者を優先的に表示するなど

# Comparatorを使ったソート
ここでは、顧客リストを例に出して、Comparatorを使った基本的なソート方法を提示します。

## Comparatorの実装
年齢順に並べ替える
```java
import java.util.Comparator;

public class Customer {
    private int age;

    // コンストラクタ、ゲッター、セッターは省略

    public static class AgeComparator implements Comparator<Customer> {
        @Override
        public int compare(Customer c1, Customer c2) {
            return Integer.compare(c1.getAge(), c2.getAge());
        }
   }
}
```

## ソートの実行

```java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Customer> customers = new ArrayList<>();
        customers.add(new Customer("Alice", 30, 500.0));
        customers.add(new Customer("Bob", 25, 600.0));
        customers.add(new Customer("Charlie", 35, 700.0));

        // 年齢でソート
        Collections.sort(customers, new Customer.AgeComparator());
        // [Customer("Bob", 25, 600.0), Customer("Alice", 30, 500.0), Customer("Charlie", 35, 700.0)]の順に並べ替えられる
    }
}
```
以下はソートの各ステップを視覚的に示したものです。compareメソッド内で逐一年齢を比較していきます。
```text
初期状態:
[ Alice(30) , Bob(25) , Charlie(35) ]

1. Alice(30)とBob(25)を比較:
   [Bob(25), Alice(30), Charlie(35)]
2. Alice(30)とCharlie(35)を比較:
   [Bob(25), Alice(30), Charlie(35)]
3. Bob(25)とAlice(30)を再度比較:
   [Bob(25) , Alice(30), Charlie(35)]

最終状態:
[ Bob(25) , Alice(30) , Charlie(35) ]
```
Community Staking Module (CSM) とは

参考記事↓
https://blog.lido.fi/lido-community-staking-an-overview/

## はじめに

Ethereum（イーサリアム）のステーキングプロトコルとして知られるLidoが、新たなモジュール「Community Staking Module (CSM)」の導入を計画しています。このCSMは、Lidoのエコシステムをより分散化し、個人や小規模グループがNode Operatorとして参加できる機会を提供します。

本記事では、CSMの概要、目的、主な特徴、そして今後の展望について詳しく解説していきます。

## Community Staking Module (CSM) とは？

Community Staking Module (CSM) は、Lido on Ethereumの3番目のモジュールとして計画されています。このモジュールの最大の特徴は、パーミッションレス（許可不要）な参加が可能なことです。つまり、個人のステーカーや小規模なグループが、ETHをボンド（担保）として提供することで、Lidoのバリデーター（検証者）として運用に参加できるようになります。

CSMは、以下のような順序でLidoに導入される予定です：

1. Curated Module（既存の厳選されたNode Operatorによるモジュール）
2. Simple DVT Module（分散型バリデーター技術を使用した小規模なモジュール）
3. Community Staking Module（パーミッションレスな参加が可能なモジュール）

## CSMの目標

CSMには、以下の2つの主要な目標があります：

1. Lido on EthereumのNode Operator setへのパーミッションレスな参加を可能にし、個人ステーカーのプロトコル参加を促進する
2. メインネットローンチ後数ヶ月以内に、Lido on Ethereumの独立したNode Operatorの総数を300以上に増やす

これらの目標は、Lidoのコミュニティステーキングマニフェストをより実践的に適用したものです。

## CSMの主な特徴

CSMをコミュニティステーカーにとってより魅力的なものにするため、以下の特徴が導入されています：

1. **報酬の平準化**: 実行層（EL）の報酬とMEV（Miner Extractable Value）が他のモジュール（例：Curated Module）と平準化されるため、CSM Node Operatorはより安定した報酬を得る可能性があります。

2. **低いボンド要件**: より多くの潜在的なオペレーターをカバーできるよう、Node Operatorに要求されるボンドは合理的に低く設定されています。

3. **ETH（stETH）のみを使用**: ボンドと報酬に使用される唯一のトークンはETH（stETH）で、他の資産は関与しません。

4. **ユーザーフレンドリーなUX**: Node Operatorには、より使いやすいUXが提供され、オンチェーン操作のガス代も低く抑えられています。

5. **高い報酬ポテンシャル**: Node Operatorは、通常の個人ステーキングよりも多くの報酬を得られる可能性があります。

## なぜCSMが必要なのか？

Lidoは、Ethereumの分散化を維持し、ステーキングへのアクセスを民主化するというミッションからスタートしました。現在のLidoには、DAOによって厳選された37の専門的なステーキングプロバイダーで構成される1つのNode Operatorモジュールしかありません。

プロトコルの分散化をさらに強化するため、Lido DAOはより広範なオペレーターを取り込むモジュールの開発を承認しました。これが、パーミッションレスなNode Operator参加を可能にするCSMの開発につながっています。

近い将来にリリースされる予定の2つのEthereum機能により、プロトコルがパーミッションレスアクセスを持続可能な方法で受け入れることがより実現可能になります：

1. **EIP-4788**: Lidoのスマートコントラクトが信頼を最小限に抑えた方法でデータ（例：バリデーターの残高）を取得することを可能にします。
2. **EIP-7002**: プロトコルのバリデーター引き出し資格情報を通じて、悪意のあるプロトコルバリデーターをオンチェーンで退出させることをLidoに許可します。

CSMでは、ボンドベースの設計を採用することが提案されています。ボンドは、不適切な行動（バリデーターのオフライン、スラッシング、MEVの盗用など）に対するカバーとして、またNode Operatorとステーカー間の利害調整メカニズムとして使用できます。

## 潜在的なパートナーシップ

パーミッションレスモジュールを成功させるには、コミュニティがバリデーターの運用やツールの構築に参加することが重要なステップとなります。そのため、Lido CSチームの貢献者たちは、CSMの利用を促進するツール開発のために、Ethereumエコシステムとのパートナーシップや協力関係を確立することに熱心です。

注目すべきツールの例としては、以下のようなものがあります：

- DappNode
- Avado
- Stereum
- Sedge
- eth-docker

これらのツールは、CSMの利用をより簡単かつ効率的にするために重要な役割を果たす可能性があります。

## まとめ

Community Staking Module (CSM) は、Lidoプロトコルの分散化をさらに促進し、個人や小規模なグループがEthereumのステーキングエコシステムに参加する機会を提供する画期的な取り組みです。

パーミッションレスな参加、低いボンド要件、使いやすいUXなど、CSMの特徴は多くのステーカーにとって魅力的なものとなっています。また、Ethereumの将来の機能改善と合わせて、CSMはより安全で効率的なステーキング環境を実現することが期待されています。

今後のテストネットデプロイやメインネットリリースに向けて、Lidoコミュニティの動向に注目が集まっています。Ethereumのステーキングに興味がある方や、すでに個人でステーキングを行っている方は、CSMの導入によってどのような新しい機会が生まれるか、ぜひ注目してみてください。
Simple DVT Moduleとは

参考記事↓
https://blog.lido.fi/simpledvt-new-phase-for-lido-on-ethereum/

## はじめに

2024年2月、Lidoプロトコルに新たなモジュールが追加されました。その名も「Simple DVT Module（sDVTm）」です。このモジュールは、個人や小規模なコミュニティのステーカーがLidoプロトコルを利用して検証者（バリデーター）を運用する機会を提供します。

今回は、このSimple DVT Moduleについて詳しく解説していきます。

## Simple DVT Moduleとは？

Simple DVT Module（sDVTm）は、Lidoプロトコルの2番目のメインネットモジュールです。このモジュールの主な特徴は以下の通りです：

1. 個人やコミュニティのステーカーが参加可能
2. Curated Operator Moduleの設計を活用
3. ObolとSSV Networkが提供するDVT（Distributed Validator Technology）ソリューションを利用
4. 初期上限はLido全体のステーク量の0.5%（DAO投票で増加可能）
5. 約250の新規Node Operatorの追加を想定
6. 3年以内の終了を予定（より拡張性の高いDVTモジュールへの移行を見込む）

## なぜSimple DVTが必要なのか？

Lidoプロトコルの分散化と運用の堅牢性を高めるための最速の方法として、DVTの採用が注目されています。Simple DVT Moduleの最初の2つのコホートだけでも、139の新規Node Operatorが参加する予定です。

その内訳は以下の通りです：

```mermaid
pie title Simple DVT Module参加者内訳
    "個人ステーカー" : 70
    "コミュニティステーカー" : 28
    "プロフェッショナルNode Operator" : 41
    "Lido on Ethereum Curated Setメンバー" : 22
```

DVTは、複数のNode Operatorが協力して1つの検証者を運用するシステムです。これにより以下のメリットがあります：

1. 検証者の耐障害性向上
2. ダウンタイムリスクの軽減
3. インフラ、地理的分散、クライアント多様性の促進
4. Distributed Key Generation（DKG）による安全性の向上

## Simple DVT Moduleのメカニズム

### Node Operatorの選択プロセス

1. テストネット後、Lido Node Operator Subgovernance Group（LNOSG）が評価を実施
2. アップタイム、検証者の義務遂行、応答時間、問題解決能力などを評価
3. 地理的位置、ホスティングタイプ、サポートするクライアントも考慮
4. LNOSGがDAOに提案を行い、1週間の議論期間を経てメインネットへの移行を決定

### Simple DVT Module Committee（SDVTMC）

運用の効率化のため、SDVTMCと呼ばれるマルチシグ委員会が設立されました。この委員会は、Simple DVTに関する以下の操作をEasy Track（最適化されたガバナンスプロセス）を通じて実行します：

- 新しいクラスターの作成
- 既存クラスターのアクティベーションと非アクティベーション
- クラスターの鍵制限の変更
- クラスターマネージャーと報酬アドレスの変更

### 経済モデルと報酬分配

Simple DVT Moduleは以下の手数料構造を採用しています：

- 2%のトレジャリー手数料
- 8%のモジュール手数料（Node OperatorとDVTプロバイダー間で共有）

報酬分配の詳細は以下の通りです：

1. 各参加者：ネットクラスター報酬の1%
2. Obol：Obolクラスター報酬の1%
3. SSV Network：SSVトークンで報酬を受け取る（初年度は0.5%、2年目は0.75%、3年目以降は1%）

報酬の請求プロセスを簡素化するため、以下の2つのスマートコントラクトが利用されます：

1. stETHをwstETHにラップし、手数料を差し引くObol開発のラッパー
2. 参加者間で報酬を分配する0xsplitsのスマートコントラクト

## 現在の状況と今後の展開

2024年4月16日時点で、Simple DVT Moduleはメインネットにデプロイされ、Obol Cohort 1の最初の12クラスターがオンボーディングを完了しています。各クラスターが5つのアクティブな検証者を持つと、30日間のパフォーマンス監視期間が始まります。

SSV Networkについても、テストネットが完了し、パフォーマンス監視期間が終了しています。参加者は現在、SSV Networkのスマートコントラクトから検証者を削除し、報酬請求フローをテストしている段階です。

今後、Simple DVT Moduleは以下のように拡大していく予定です：

1. 約250の新規Node Operatorの追加（Lido on Ethereum Curated Node Operatorの37に加えて676%の成長）
2. パフォーマンスが良好な場合、モジュールのシェア制限を1.5%〜2%に引き上げる提案の可能性
3. より洗練されたDVTモジュールへの移行準備

## まとめ

Simple DVT Moduleは、Lidoプロトコルの分散化と堅牢性を向上させる重要な一歩です。個人やコミュニティのステーカーがイーサリアムの検証者を運用する機会を提供し、DVTの採用によってより安全で分散化されたインフラストラクチャを実現します。

今後、Community Staking Module（CSM）など、よりオープンなモジュールの導入も予定されており、Lidoエコシステムの更なる発展が期待されます。
Pythonで画面をモニター中央に起動させる

## 変更前のコード

```Python
root = tk.Tk()
root.title("温湿度計")
root.geometry("586x329")
root.configure(bg="white")
```
表示される位置は左上
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/d4791efb-e87a-3150-9283-e8e3426e0f88.png)

## 表示位置の変更方法
表示する位置をgeometry()でサイズの後ろに指定する
```
root.geometry("横のサイズx縦のサイズ+左からのX軸の座標+上からのY軸の座標")
```

## 変更後のコード
下記に設定すると位置が変わる
```Python
root.geometry("586x329+1500+500")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/5d50b026-d8a2-e7e8-3faa-ca0ac7a67eeb.png)

## モニターの大きさを取得して座標を指定する

```Python
# ウィンドウサイズ
window_width = 586
window_height = 329

# モニターとウィンドウの中央から座標を取得
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
x_coordinate = (screen_width // 2) - (window_width // 2)   # モニター中央-ウィンドウ半分
y_coordinate = (screen_height // 2) - (window_height // 2) # モニター中央-ウィンドウ半分

root.geometry(f"{window_width}x{window_height}+{x_coordinate}+{y_coordinate}")
root.configure(bg="gray")
```

 モニターの中央に表示されたのでOK！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/05f36a05-b16e-1753-21c8-04f899f867e5.png)
【ChatGPT】原稿用紙（縦9横6）の画像（誤字あり）を読ませます。


　どうも、カーブミラーです。

　今回は、原稿用紙（縦9横6）の画像（誤字あり）を読ませます。それからそれをもとに、もとの文章を作成してもらいます。

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
あります。　あしからず。
:::
　まずは、ニュース。

　「OpenAI o1モデルによる
　　複雑な問題の解決」イベントが
　　　先日あり、その録画が
　　　　公開されました。

　下記が
　　そのポスト。
　　　[Tibor Blahoさんポスト](https://x.com/btibor91/status/1847351692259401860?t=aGSVzqk3HArPWmTIox9Ilw&s=19)

DeepL翻訳
>2024年10月17日に開催されたOpenAIのイベント「Solving complex problems with OpenAI o1 models」の録画が公開されました - ChatGPT EnterpriseでのOpenAI o1シリーズの紹介、ドメインをまたいだ推論の使用、ライブデモと「モデル機能」可視化の更新版について説明します。
>
>今後の予定 - 今後数ヶ月の間に、OpenAIはo1とGPTシリーズの両方で新しいモデルをリリースし、o1にウェブブラウジング、ファイルと画像のアップロードなどの機能を追加する予定です。

　録画はこちら。22:30ほどの長さ。
　　[OpenAI公式ＨＰ公開ビデオ](https://openai.com/business/solving-complex-problems-with-openai-o1-models/)

　これから見ます😅
***
　さて、本題に入ります。

　今回は、
　　原稿用紙（縦9横6）の
　　　画像を読ませます。

　この原稿用紙には
　　誤字が複数存在していますが、
　　　多くの日本人は、これを
　　　　スラスラと読めます。

　そのことを
　　示した原稿なのです。

　こちらが、その画像。
![20241019_130503.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/503d8f0a-01cc-85c1-427a-f2973150030a.jpeg)

　もとは、こちら。
　　[元気な子さんポスト](https://x.com/motokichi117117/status/1847041683739103533?t=rwGziK_DZtK4rc69LD_CrQ&s=19)

　今回は、この原稿用紙を
　　ChatGPTに読ませ、
　　　本来の文章にするまでを
　　　　やりますね。

　やり取りをどうぞ。
　　ちなみにGPT-4oです。
***
***●user***
（画像アップロード）
読み込んで

***ChatGPT***
（誤字を間違った字にした）

***●user***
再度読んでください。少なくとも11文字が間違っています。間違ったままで。

***ChatGPT***
悩には文字を単極として認識する機態があり、漢字が羊分くらい門違っていても舞時に内容を埋解することが出来ます。

***●user***
（読み直しを何度かさせたあと）
読み込んだ文章の誤字訂正をお願いします。
文章の意味がきちんと通るようにしてください。
誤字はどれかの文字が正しいとします。
存在しない単語にはしないでください。
字数を変えない。

***ChatGPT***
誤字を訂正し、文章の意味が通るように修正しました。以下が修正版です：

脳には文字を単語として認識する機能があり、漢字が半分くらい間違っていても瞬時に内容を理解することが出来ます。

これで文の意味が通るように修正されていますが、元の文字数は変えず、誤字に対応する正しい漢字や単語を当てはめました。

***●user***
OK。
では、読み込んだ文章との違いを具体的に表してください。

***ChatGPT***
以下に、読み込んだ文章と修正版の文章の違いを具体的に示します。

### 読み込んだ文章：
悩には文字を単栯として認識する機態があり、漢字が羊分くらい門違っていても舞時に内容を埋解することが出来ます。

### 修正版の文章：
脳には文字を単語として認識する機能があり、漢字が半分くらい間違っていても瞬時に内容を理解することが出来ます。

### 違いの詳細：

1. **悩 → 脳**  
   「悩」から「脳」に変更。意味が「悩み」ではなく「脳」として適切。

2. **単栯 → 単語**  
   「単栯」は存在しない語であり、「単語」が意味的に正しい。

3. **機態 → 機能**  
   「機態」ではなく「機能」に変更。正しい意味を持つ単語に訂正。

4. **羊分 → 半分**  
   「羊分」は不自然なので、「半分」に変更。

5. **門違 → 間違**  
   「門違」は誤字で、「間違」が正しい。

6. **舞時 → 瞬時**  
   「舞時」は誤りで、「瞬時」の方が意味的に正しい。

7. **埋解 → 理解**  
   「埋解」は存在しない単語のため、「理解」に訂正。

このように、読み込んだ文章の誤字や不自然な表現を適切に訂正し、意味の通る文章にしました。
***

　最初に読んだ段階で
　　いくつか直されてしまっています。

　「文宇」
　　「漢宇」
　　　「認職」
　　　　「肉容」
　　　　　「出末ます」が。

　区別がつかなかったのと
　　文章として勝手に直したことが
　　　その原因でしょう。


　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
この立体感を 効果的に利用しましょう

　立体視といえば、ゴーグルなどを使った本格的なＶＲ関係の話題で大いに盛り上がっています。しかし、この記事で紹介するのは、**メガネはもちろん、見るための何の道具も要らない、きわめて地味で簡素で原始的な、静止した線画の裸眼立体視の一例**です。

　非常に地味な存在ではありますが、理数系の記事に載せる**立体幾何的な説明図に利用すれば、説明内容への理解度が深まり極めて効果的**です。しかし、Qiitaでもそのような記事はあまり見かけることがありません。ここでは裸眼立体視図の活用促進を図るため、私の投稿記事（含・予定）から抜き出した何点かの図を披露させていただきます。
 
　すべて、**平行法の裸眼立体視図です。左右の図の中心の間隔が60～65mm程度になるように、ブラウザの画面の大きさや倍率を調整したうえで、目から25～30cmくらいに離してご覧ください**。


<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/90a8b1dc-87a4-e8cd-c678-010ee7e16bbc.png">


<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/8f8330ce-6a5a-4b4b-8b60-9d1ab3ffbe19.png">


<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/4aab42c5-b8df-90ae-daa6-61db30c3cfbd.png">


<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/7e300f0d-53a3-68ad-e1cf-4f9a40c57000.png">
正投影法
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/55cb5648-00da-a989-c326-62cb28c6a556.png">
透視投影法
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/1fc15510-1686-f965-253d-8c9bfb50817b.png">


<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/c2815e73-f23b-c7ac-ea21-c14daac44398.png">






　これらの図を描く基本的な方法は過去の記事（[MATLABで裸眼立体視](https://qiita.com/tsubolabo/items/6aeee504c5851277fe1f)）に書いておきました。しかし、実は、**以前に紹介していた方法には重大な欠陥がありました**。CameraViewAngleプロパティの存在を見落としていたことです。このプロパティを既定のautoのままにしてあると、視線の選び方によっては左右の図の大きさが微妙に異なる（<font Color="#aaa">詳しくは、[【MATLAB】今更ながら、三次元プロットの視線関連コマンドを探究してみた](https://qiita.com/tsubolabo/items/32fa8f3ac86f4aa24834)　の図２の左側の図</font>）ことがあり、これを立体視すると不快感を伴います。
 
　この問題は、manualモードに切り替えて、左右の図に同一のCameraViewAngle値を設定するだけで解決できます。**当記事で紹介した図ではこの設定が済んでいるため、安心してご覧いただくことができます**。これ以外の改善ノウハウも含めて、近いうちに「改良編」の記事として投稿したいと考えております、
【学習メモ】Ruby

# 経緯
初心者である私が２週間Rubyを学習し、学んだ知識をより確実に自分に定着させるために、アウトプット（本記事）するもの。

##  do ... endと{}
ブロック（＊）を使うときは、do ... end  と改行をいれて処理していたが、{}で囲ってブロックを作成することが可能。
＊コードの塊を「ブロック」として定義し、メソッドに渡して実行する仕組み

```ruby:title.rb
numbers = [1, 2, 3, 4]
sum = 0
numbers.each do |n|
  sum += n
end 
sum  #=> 10
```
を{}を使用して書くと

```ruby:title.rb
numbers = [1, 2, 3, 4]
sum = 0
numbers.each { |n| sum += n }
sum  #=> 10
```

##  $とシンボルを使って簡潔に書く
ブロックを使うメソッドは条件によってはかなりシンプルに書くことができる。以下の条件を満たしている必要がある。

1. ブロックのパラメーターが１個だけである。
1. ブロックの中で呼び出すメソッドには引数がない。
1. ブロックの中では、ブロックパラメーターに対してメソッドを１回呼び出す以外の処理がない。

```ruby:title.rb
#このコードは、
['ruby', 'java', 'python'].map { |s| s.upacase }  #=> ['RUBY', 'JAVA', 'PYTHON']
#こう書き換えられる
['ruby', 'java', 'python'].map ($:upacase)  #=> ['RUBY', 'JAVA', 'PYTHON']
```
## 比較の構文
演算子は二つの値を比較するため、連続して使うと意図した通りに評価されない。Ruby では x == y == true と書くと、最初に x == y が評価され、その結果（true または false）が次の比較に使われる。括弧 () を使うと、条件の評価の優先順位を明確にすることができる。

## ハッシュと配列とは
### 違い
要素のコレクションという概念は共通だが、その要素の格納方法とアクセス方法が異なる。
具体的には、**ハッシュ**は、キーと値のペアでデータを格納するコレクションであり、キーを使ってアクセスする。**配列**は、要素が順序つけられたコレクションであり、インデックスを使って要素にアクセスする。

### どのような用途に向いているのか
**配列**は、重複を許容するデータを扱う、要素の順序が重要な場合に使用する。
具体的例）　スケジュールの管理、投票結果等
**ハッシュ**は、キーと値のペアで管理し、特定のデータを迅速に検索する必要がある、または、あるデータが別のデータに関連つけられている場合に使用。
具体的例）　ユーザー情報等

## モジュール
関連するメソッドや定数などをまとめてグループ化したいだけのときに、手軽に使えて便利、コードを何回も書く必要がなくなる。また、モジュールを利用することで、大規模開発の際に名前の衝突を避けコードの組織や可読性を向上させることができる。これにより、開発者はより効率的に作業でき、保守性の高いコード、クリーンな設計を実現することができる。
```ruby:module.rb
# 動物園の名前空間
module Zoo
  class Orca
    def sound
      "シャー（動物園のシャチ）"
    end
  end
end

# 水族館の名前空間
module Aquarium
  class Orca
    def sound
      "クリック（水族館のシャチ）"
    end
  end
end

# Zooモジュールからオブジェクトを作成
zoo_orca = Zoo::Orca.new
puts zoo_orca.sound        #=> シャー（動物園のシャチ）

# Aquariumモジュールからオブジェクトを作成
aquarium_orca = Aquarium::Orca.new
puts aquarium_orca.sound   #=> クリック（水族館のシャチ）
```
# 最後に
他の言語と異なる挙動があり、例えば、returnがいらない（最後に評価された式がメソッドの戻り値となる）、改行に ; がいらない等々あるが、直感的に意味を理解しやすい。また、リファレンスが日本語なのも大変ありがたい。引き続き、継続的に学習をしたい。
JavaScript無効時のコンポーネントの動作とアクセシビリティに関する考え

何が一番いいのか考え中です…

## JavaScript無効

JavaScript（以下JS）が使えなくなっているユーザーに対してサイトやアプリケーションはどうなっているべきでしょうか？

- そもそもJSを無効にするユーザーはリテラシーが高いから動いてなかったら有効化するでしょ
- そもそも無効にしないでしょ

みたいな意見があるかもしれません。

___

僕の考えはこうです。

- JSを無効化なんか調べればすぐできる
- ブラウザバックのハックや広告だらけのサイトなどの出現によって無効化したい需要が増えた
- JSがバグって動かなくなってたらどうするの？
- JSってそもそもHTMLやCSSだけではできないような高度なユーザー体験の補助になるものじゃなかったか？

この辺を考えると、

1. じゃあJSなしでも最低限動いてた方がいいでしょ
2. JSのあるなしでブラウザやスクリーンリーダーから読み取れる情報に差があってもいいけど、それぞれ意味の違う情報をユーザーに与えてしまったらダメだよね

となりました。

2個目を少し補足します。

### タブ

例えばタブです。

[APG](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/)によるとタブは`role="tab"`のような属性や、キーボードによる操作が必要です。

つまりJSが必要で、JSありきのコンポーネントです。
ではJS無効時タブはどうあるべきでしょうか？

JS無効時を気にしなければおそらく以下のようなHTMLになるでしょう。

```html
<div role="tablist">
  <button id="tab1" role="tab" tabindex="0" aria-selected="true" aria-controls="panel1">タブ1</button>
  <button id="tab2" role="tab" tabindex="-1" aria-controls="panel2">タブ2</button>
  <button id="tab3" role="tab" tabindex="-1" aria-controls="panel3">タブ3</button>
</div>
<div id="panel1" tabindex="0" aria-labelledby="tab1">パネル1</div>
<div id="panel2" hidden="until-found" tabindex="-1" aria-labelledby="tab2">パネル2</div>
<div id="panel3" hidden="until-found" tabindex="-1" aria-labelledby="tab3">パネル3</div>
```

JS無効時これがどうなるかというと、ボタンは「タブ」として認識され、かつ`tabindex`が負であったり`hidden`がついたコンテンツにはアクセスできません。
（`hidden="until-found"`をつければ検索や`:target`時見えるようになりますが、サポートされているブラウザのバージョンが比較的新しいものに限られているため、現状「これで安心」ではなさそうです。）

また、スクリーンリーダーユーザーはこれをタブだとして認識するので、当然左右キーの押下などでタブを切り替えられると思うはずです。（リテラシーが高ければ動かないことを理解できているかもしれませんが…）

しかし、実際はJSが無効になっていれば動きません。
「あれ？動かないぞ」となってしまったらユーザーは混乱しますし、いい印象は受けないはずです。

僕はこれを良くない（最善ではない）と考えました。
できることはやっておきたいですが、何ができるでしょうか？

## JS無効時はアンカーリンクにしちゃおう！

`role="tab"`をやってしまうのは先ほどのセクションに書いた通り、よくなさそうです。
JS無効環境でタブはタブとして機能しないので、別のものを考える必要があります。

JSは「ユーザー体験の補助」として使う　という考えのもとで、タブをなんのために使いたいのか、そもそもなぜタブなのか考えてみました。

「多分ページが長く見にくくなるからシンプルに見せて本来ページの下の方に行ってしまうコンテンツも見せたい/見やすいようにしたいんだろうな」

わざわざ画面上に一つのタブパネルしか表示したくない理由はこれしか思いつきませんでした。

ページが長くなって後半のコンテンツが見られにくくなる問題は「タブのボタンをアンカーリンクにして、かつタブとパネルを`sticky`コンテナにしてボタンを追従させる」である程度解決できます。
JSは「ユーザー体験の補助」として使う　を考えると、JSが無効な時からJS有効化でアンカーリンクより少し便利になっているので良さそうです。

## JS無効時はセレクトボックスで切り替えられるようにしちゃおう！

もしくは、一つのタブパネルだけ見せたいという強い目的があるのであれば、以下のように書けば達成できるでしょう。（例が雑ですみません）

ただこれはインターネットが不安定などの原因でCSSファイルが読み込まれない場合
「セレクトボックスを変更するとパネルが切り替わります」が挙動と一致しなくなったりselectの用途とズレるのであまり良くなさそうです。（ただテキストで説明があるので混乱はしなさそうです。）


```html
<div class="c">
  <label for="message">セレクトボックスを変更するとパネルが切り替わります</p>
  <select id="message" name="tab">
    <option value="1" selected>1</option>
    <option value="2">2</option>
  </select>

  <div id="panel1" class="panel">panel1</div>
  <div id="panel2" class="panel">panel2</div>
</div>
```

```css
.panel {
  display: none;
}
.c:has(option[value="1"]:checked) #panel1 {
  display: block;
}
.c:has(option[value="2"]:checked) #panel2 {
  display: block;
}
```

## まとめ

- JSなしでも最低限動いてた方がいいでしょ
    - やるとしたら何ができるだろうか？
- JSのあるなしでブラウザやスクリーンリーダーから読み取れる情報に差があってもいいけど、それぞれ意味の違う情報をユーザーに与えてしまったらダメだよね
    - 混乱させたら良くない

最近アクセシビリティを意識したコンポーネントは増えてきたように思いますが、
JSがあることを前提にしたものも多いなぁと思っています。

工数や需要の問題があるので絶対やらないといけないとは思っていませんが、よりいいものが作れるなら自分は気にして作っていきたいなぁと思っています。
PostgreSql ログ出力設定

ログは、障害調査や状態確認に必要な情報です。
ただ、やみくもに保存すると容量がひっ迫したりリソースを消費するのでバランスが大事です。
以下は、私の基本設定例です

## 利用環境
MiracleLiux 9.2
PostgreSql 13
データディレクトリ：/var/lib/pgsql/data

## OS側の事前作業：/var/log配下にディレクトリ準備
postgresqlのデータディレクトリとOSの/var/log配下の両方から参照できると便利です。
ディレクt理

・ディレクトリ作成、権限付与
```
mkdir /var/log/psql
chmod 777 /var/log/psql
```

・シンボリックリンク作成
```
 ln -s /var/log/psql /var/lib/pgsql/data/log
```

## postgresql.confの設定

### 編集時の注意
・バックアップは取得しておきましょう
　誤った場合に元にもどせるように！
・変更する場合は
　元の値を残し、改行して記述するほうが良いです
 そうすると、既定値がわかるのでもとに戻す時や既定値が不明な場合に困りません。


### logging_collector
ログ出力可否です。
既定でonのため修正不要です。

logging_collector = on

### log_destination
ログ出力方法です。インストール環境により違いがあるようです。
syslogの場合、OS側に出力されます。※ジャーナルログ
stderrは、data/logに出力されるので、stderrを推奨。

log_destination = 'stderr'

### ログ出力先

作成したディレクトリを指定します

log_directory = '/var/log/psql'

### log_file_mode
ログファイルのパーミッションです。
通常だとpostgresユーザ限定になりますので他のユーザも閲覧できるようにします。
※利用環境やセキュリティ要件によって判断が必要。

log_file_mode = 0644

### log_filename
ログファイル名
改廃しないなら固定するほうが良いのですが、ログが肥大化するので１か月くらいがよいでしょう。
%dは日付です。

log_filename = 'postgresql-%d.log'


### log_rotation_age
ローテート周期です
既定で１日になっていると思います。

log_rotation_age = 1d

### log_connections
認証時のログです
セキュリティ上、認証時のログは取得したほうがよいです

log_connections = on

### log_disconnections
切断時のログです。こちらも取得しましょう

log_disconnections = on

# log_line_prefix
ログ出力内容です。既定値は情報が少ないので追加しましょう

log_line_prefix = '[%t]%u %d %p[%l]'

%t 時間
%u　ユーザ
%d　データベース名
%p　プロセスID
%l　セッションラインNo

### log_min_duration_statement
SQL遅延時の出力時間です
利用環境により設定しましょう
単位はミリ秒です

log_min_duration_statement = 30000


## 編集完了後
サービスを再起動して動作確認しましょう。
OOP概念学習#1 - 関連と多重度

# 初めに

今日からRecursionで習ったOOP(オブジェクト指向プログラミング）を定着するために記事を書きます。

## 関連について

### 関連 - 二つ以上の項が関係していることを示す。
単純に「クラスAはクラスBを知っている」という関係性になる

### ２つの関連
* 単方向関連 - クラスAはクラスBを知っているが、クラスBはクラスAを知らない関係性
* 双方向関連 - 両方のクラスが互いに関連している

## 多重度について

### 多重度 - クラス同士の関係で、「幾つかのオブジェクトが関係している」を示す。
「1対1」、「1対多」、「多対多」これらの関係性のことである。

これらの関係性を学校の中で表します。

### 「1対1」の多重
* 一人の生徒が1クラス受けている

### 「1対多」の多重
* 一人の生徒が複数の授業を持っている

### 「多対多」の多重
*　複数の生徒が複数の授業を登録できる

## 関連と多重の組み合わせ
関連と多重度を組み合わせると、システムの中でどのクラスがどのような関係を持ち、どれくらいのオブジェクトがその関係に含まれるかを定義することができます。

例えば、「会社と従業員」の関係を考えると、多重度が「1対多」であれば、1つの会社に複数の従業員がいることを意味します。これに対して、「顧客と注文」の関係が「多対多」であれば、1人の顧客が複数の注文を行い、1つの注文に複数の顧客が関与する可能性があると定義できます。


## 結論
OOPにおける「関連」と「多重度」は、クラス同士の関係をより細かく表現するシステム設計方法です。
関連はクラス間のつながりを定義し、多重度はそのつながりに関わるオブジェクトの数を制約する役割を果たします。これらを正しく使いこなすことで、システム設計がより洗練され、開発効率が向上します。
CloudFomationでCloudFrontとS3によるサイト構成にしたときのAccessDeniedになる罠

# 罠の概要

CloudFormationを用いて、以下のような構成でAWS上のインフラを構築した。

- CloudFront
    - HTTPS化・キャッシュ
- S3
    - 静的サイトホスティング

構築完了後、CloudFrontで生成されたディストリビューションドメインにアクセスすると`AccessDenied`で拒否された。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405090/6cccf8dd-b0da-4213-1d8f-00b6eb77741d.png)

調べると、CloudFrontのディストリビューションドメインにアクセスしたはずが、URLがS3オリジンのものになっている。ネットワークの状況を見ると307リダイレクトされていた。

以上の罠があったので備忘録をかねて記事にする。

# 解決策

今回の問題の解決策を手っ取り早く知りたい人のために、私が解決に至った方法を先に提示しておく。

この問題の原因は、CloudFrontとS3のリージョンにおける兼ね合いにある。どうやら、[**S3オリジンをデフォルトにした場合、CloudFrontはus-east-1のS3バケットを見に行き、そこにない場合は即座に反映してくれないようである。(最悪24時間程度かかるらしい)**](https://repost.aws/ja/knowledge-center/s3-http-307-response)

対策としては以下を行えば良い。

##  AWSコンソールから構築した場合

ディストリビューションの作成時にリージョン名を追加する。

参考：https://dev.classmethod.jp/articles/s3-cloudfront-redirect/ 

## CloudFormationを用いて構築した場合

テンプレート上でCloudFront.DistributionConfig.OriginsからS3オリジンを参照している箇所を以下のように書き換える。

### Before

```yml
  CloudFront:
    Properties:
      DistributionConfig:
        Origins:
          - DomainName: !GetAtt TargetBucket.DomainName
```

### After

```yml
  CloudFront:
    Properties:
      DistributionConfig:
        Origins:
          - DomainName: !Sub "${TargetBucket}.s3.${AWS::Region}.amazonaws.com"
```

# 自身がハマった現象について

自身も解決策で提示した[before]の設定でインフラ構築をしていた。
当然アクセスが拒否される中で、リージョン名が設定できていないことを疑いCloudFrontの設定を見に行ったのだが、以下の画像のようにしっかりとリージョン名は設定されていた。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405090/98411a02-16fb-695d-e3d5-d4629b746074.png)

しばらく沼にはまっていたが、ここであることに気づく。ページを開いてからオリジンドメインに`xxx.s3.ap-northeast-1.amazonaws.com`が表示されるまでに一瞬間がある。JavaScriptもしくはそれに準ずるもので書き換えがされていそうだった。

まさかと思い何も変更しないまま設定を保存すると、ちゃんとサイトへアクセスできるようになった。

**「設定画面上で操作した場合に限り、AWS側で良しなにリージョン名をつけてくれるので、コンソール上は正しく設定できているように見える」** がまさかの答えだとは...

なかなかどうしてAWSと気持ちを通じ合うのは難しい...（まぁ私の設定が悪いだけなのだが）
この記事で少しでも救われる人がいますように。

# 参考

- [S3+CloudFrontでS3のURLにリダイレクトされてしまう場合の対処法](https://dev.classmethod.jp/articles/s3-cloudfront-redirect/)
WebAuthnをざっくり理解する

# はじめに
お仕事でWebAuthnについて調査する機会があり、1からちゃんと理解したい。

# そもそもパスワードはリスクが高い。
パスワードによるID認証では、IDと対になるパスワードをユーザーに入力させ、送信することで受け取ったサーバーがあらかじめ登録されたものと一致するかを判定して、認証の可否を行います。

リスクとしては、簡単なパスワードの使用による第三者からの推測や、偽サイトへの入力・送信などがあり、パスワードを守ることが難しくなっているからです。

WebAuthn（正式名称：Web Authentication API）はより安全な認証を可能にしてくれます。

# WebAuthn
## 概要
WebAuthnとは、パスワードレス認証を実現するための仕組みです。
WebAuthnは、パスワードよりも格段に安全な認証方式として注目されており、その安全性の根幹には、公開鍵暗号方式の採用があります。

## 登録と認証

### 登録
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689023/3893de3e-7a21-21a5-e713-c3de0eb83fca.png)

⓪ ユーザーが登録をリクエストします。
① サーバーがチャレンジ・ユーザー情報などをJavaScriptアプリケーションに送信します。
② ブラウザがリクエストを認証器に送信します。
③ 認証器はユーザー確認を行い、新しい鍵ペアを生成する。
④ 認証器がブラウザに新しい公開鍵や認証データを返します。
⑤ ブラウザが最終的に送信するデータを作成し、JavaScriptアプリケーションがその返り値をサーバーに送信します。
⑥ サーバーが認証情報を公開鍵を使って検証して、情報が正しければ登録成功となります。

チャレンジとは、署名の正当性を検証するためのランダムな文字列のことで、⑥でチャレンジが送信時と同じものであるかを確認します。

### 認証
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689023/b0b65667-1c4d-c2e4-1872-943cc94aac12.png)
⓪ ユーザーが認証をリクエストします。
① サーバーが登録済みチェックを行なって、アプリケーションにチャレンジを送信する。
　送信するプロトコルに指定はなく、安全なプロトコルでさえあれば良い。
② ブラウザが認証器を呼び出します。
③ 認証器がユーザ確認を行い、Assertionを作成します。
　Assertionとは、認証器が署名した、チャレンジやRelyingPartyが含まれた情報のことです。
④ 認証器が認証情報をブラウザに返します。
⑤ アプリケーションが認証器から受信した認証情報を含めたリクエストを生成して、サーバーに送信する。
⑥ サーバーは認証情報を公開鍵を使って検証して、情報が正しければ認証が成功します。

## おわりに
概要レベルですが少しはWebAuthnのことについて知ることができたのではないかと思います。これから少しずつ理解を目指したいと思います。

## 参考
https://developer.mozilla.org/ja/docs/Web/API/Web_Authentication_API

https://engineering.mercari.com/blog/entry/2019-06-04-120000/
動的フォーム有効後にカスタム項目作成時について

動的フォームについてはこちら

https://qiita.com/Takaa/items/62195e5bbc6b44e75ea3



動的フォームを有効にした後項目作成時に

「項目の追加	Lightning レコードページの表示ラベル」

と表示されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/04013393-55a2-2236-a525-d05ef175c84f.png)



こちらをクリックして保存すると自動的にLightningページに項目が追加されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/82c82a99-22d5-3540-e825-6310f26fc200.png)



追加される場所は一番下部なので追加後にLightningページから項目位置を調整してください
Rails開発環境での時間操作を簡単に！Timecopと.envを使った時間固定方法

## 背景
Railsアプリケーションの開発中、特定の日時に基づいた機能やロジックをテストする必要がある場面はよくあります。例えば、イベントが特定の日に実行されるかどうかや、期限切れの処理が正しく行われるかなどです。

実際の時間に頼ってテストを行うのは手間がかかるため、時間を操作してアプリケーションの動作を確認する方法が求められます。今回は、Timecop と .env ファイルを利用して、開発環境で簡単に時間を操作する方法を紹介します。

## Timecopとは
Timecopは、Rubyアプリケーション内で時間を操作するためのライブラリです。これを使うことで、時間に依存したロジックを特定の日時に固定して検証することができます。Timecopを活用することで、期限付きタスクや日付に依存するシステムのテストやデバッグを効率化できます。

## 実装手順
ここからは、Timecopを利用してRails開発環境で時間を操作する具体的な手順を説明します。環境変数を .env.development ファイルで設定し、Railsの開発環境で自由に時間を操作する方法を見ていきます。

### Timecopのインストール
まずは、GemfileにTimecopを追加します。

```
# Gemfile
gem 'timecop'
```
次に、bundle installコマンドを実行してインストールします。

### dotenvのインストール
環境変数を管理するために、dotenv-railsを使います。Gemfileに追加します。

```
# Gemfile
gem 'dotenv-rails'
```
その後、bundle installを実行します。

### .env.developmentで環境変数を定義
TRAVEL_TO という環境変数を .env.development ファイルに定義し、操作したい日時を設定します。このファイルは config/application.rb で参照されます。
```
# .env.development
TRAVEL_TO="2024-12-25 12:00"
```
この設定により、開発環境でアプリケーションの時間を「2024年12月25日12時」に固定することができます。

## config/application.rbでのTimecop設定
次に、アプリケーション全体でこの TRAVEL_TO 環境変数を参照して時間を固定する設定を行います。

```
# config/application.rb
module YourAppName
  class Application < Rails::Application
    # その他の設定...

    config.after_initialize do
      # 本番環境以外で、TRAVEL_TOが設定されている場合に時間を固定
      if !Rails.env.production? && ENV['TRAVEL_TO']
        Timecop.freeze(Time.zone.parse(ENV['TRAVEL_TO']))
      end
    end
  end
end
```

設定のポイント：
dotenv-rails により、.env.development から環境変数が読み込まれ、ENV['TRAVEL_TO'] で指定した日時に時間を固定します。
after_initialize ブロックで、アプリケーションの初期化後に Timecop.freeze を使って時間を指定した日時に固定します。

## 動作確認
.env.development に設定された日時で時間が固定されているか確認するには、Railsサーバーを起動して Time.current の出力を確認します。

```
bin/dev
```
次に、コンソールやビューで Time.current を確認します。
```
Time.current # => 2024-12-25 12:00:00 +0900
```
これにより、指定した日時に時間が固定されていることを確認できます。

## まとめ
Timecopと.env.developmentファイルを利用することで、Railsの開発環境で簡単に時間を操作できるようになります。特定の日時に依存する機能の検証やテストに非常に便利です。今回は開発環境における設定でしたが、.env.test を使えばテスト環境でも同様の時間操作が可能です。

ぜひこの方法を活用して、時間に依存したロジックの確認を効率化してみてください。
[Unity] UIをドラッグで移動させる

ドラッグ処理を毎回調べながら書いている気がするので、さっき書いたものをまとめておきます。

移動させたい`GameObject`にこのスクリプトをアタッチすれば動くはず（ただしuGUI専用）。

```C#: RectTransformDragger.cs
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class RectTransformDragger : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
    // このコンポーネントがついているGameObjectのRectTransform
    [SerializeField]
    private RectTransform _myRectTransform;

    // ドラッグ中のときtrue
    public bool IsDragging { get; private set; } = false;

    // ドラッグ開始時/終了時の処理を他のスクリプトから登録できるようにする
    public UnityAction<PointerEventData> OnBeginDragAction { get; set; }
    public UnityAction<PointerEventData> OnEndDragAction { get; set; }

    public void OnValidate()
    {
        // RectTransformをあらかじめ取得しておく
        _myRectTransform = GetComponent<RectTransform>();
    }

    // ドラッグ開始時に呼ばれる関数
    public void OnBeginDrag(PointerEventData eventData)
    {
        IsDragging = true;
        OnBeginDragAction?.Invoke(eventData);
    }

    // ドラッグ中に呼ばれる関数
    public void OnDrag(PointerEventData eventData)
    {
        // オブジェクトの位置を更新
        _myRectTransform.localPosition = ScreenToLocalPosition(eventData.position);
    }

    // ドラッグ終了時に呼ばれる関数
    public void OnEndDrag(PointerEventData eventData)
    {
        OnEndDragAction?.Invoke(eventData);
        IsDragging = false;
    }

    // ScreenPositionをLocalPositionに変換する関数
    public Vector2 ScreenToLocalPosition(Vector2 screenPosition)
    {
        RectTransform parentRectTransfrom = _myRectTransform.parent as RectTransform;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRectTransfrom, screenPosition, Camera.main, out Vector2 result);
        return result;
    }
}
```
動的配列とは？

# 1. 動的配列とは？
動的配列は、要素の追加や削除に伴って、自動的にメモリ領域が拡張される配列です。

固定配列（静的配列）：サイズを宣言時に指定し、変更できません。
例：int[] arr = new int[5]; → サイズ5の配列を固定。

動的配列：サイズの上限がなく、実行中に要素の数を増減できます。

動的配列の特徴
サイズの自動拡張：容量を超えた要素を追加すると、自動で容量が2倍になる。
要素の削除も可能：必要に応じて要素を削除し、サイズを縮小できる。
配列の欠点を克服：配列のサイズを事前に考えなくても良い。
2. Javaでの動的配列の実装（ArrayList）
Javaでは、ArrayListが代表的な動的配列のクラスです。ArrayListは、要素の追加や削除が簡単にでき、配列サイズの管理を自動で行います。

# 2.1 ArrayListの基本的な使い方
```java
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        // 動的配列 ArrayList の作成
        ArrayList<Integer> list = new ArrayList<>();

        // 要素の追加
        list.add(10);
        list.add(20);
        list.add(30);

        // 要素の出力
        System.out.println("配列の内容: " + list);

        // 要素の取得
        System.out.println("2番目の要素: " + list.get(1)); // 出力: 20

        // 要素の削除
        list.remove(1); // インデックス1の要素を削除

        // 削除後の配列の内容
        System.out.println("削除後の内容: " + list);
    }
}
```
出力結果:

```makefile
配列の内容: [10, 20, 30]
2番目の要素: 20
削除後の内容: [10, 30]
```

# 3. 動的配列の内部動作
ArrayListの内部では、通常の配列が使われていますが、次のような動作が行われています。

**3.1 容量の自動拡張**
新しい要素を追加し、現在の容量を超えると、容量が自動的に拡張されます。
多くの場合、容量は2倍になります。
例：10要素の容量が満杯のとき、20要素の新しい配列が確保されます。

**3.2 データの再配置**
新しい配列が確保されると、元の配列の要素がすべて新しい配列にコピーされます。

# 4. 動的配列の応用例
4.1 文字列の動的配列
```java
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
        
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");

        // 全要素の出力
        for (String name : names) {
            System.out.println(name);
        }
    }
}
```

出力結果:

```
Alice
Bob
Charlie
```

**4.2 二次元の動的配列**
Javaで二次元の動的配列を使うには、ArrayListを入れ子にします。

```java
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<ArrayList<Integer>> matrix = new ArrayList<>();

        // 2次元配列の初期化
        for (int i = 0; i < 3; i++) {
            matrix.add(new ArrayList<>());
            for (int j = 0; j < 3; j++) {
                matrix.get(i).add(i + j);  // 例として i + j を追加
            }
        }

        // 配列の内容を出力
        for (ArrayList<Integer> row : matrix) {
            System.out.println(row);
        }
    }
}
```
出力結果:
```
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
```

# 5. 動的配列のメリットとデメリット
**5.1 メリット**
サイズ管理不要：プログラマーがサイズを気にする必要がない。
要素の追加・削除が容易：配列の長さが変わっても自動的に調整される。
便利なメソッドが豊富：ArrayListには要素の検索、ソート、クリアなどのメソッドが用意されている。
**5.2 デメリット**
パフォーマンスの低下：容量を超えるたびに新しい配列を確保するため、処理に時間がかかる場合がある。
メモリ消費が多い：内部で使用する配列は、多めにメモリを確保するため、メモリ消費が増える。
# 6. 動的配列を使うべき場面
要素数が事前に決まっていない場合のデータ管理（例：ユーザーの入力を受け付ける場合）。
頻繁な要素の追加・削除が必要な場合。
データのサイズが可変で、処理効率よりも柔軟性が求められる場合。
7. まとめ
動的配列は、プログラムの実行中に要素数が変化する場合に非常に便利なデータ構造です。Javaでは、**ArrayList**が動的配列をサポートし、簡単な操作で要素の追加・削除が可能です。

競技プログラミングや日常的な開発では、配列のサイズを予測できない場合がよくあります。そのような場面で、動的配列を活用することで、柔軟で効率的なプログラムを作成することができます。


**毎日更新していますので、@y-t0910をフォローしていただけると嬉しいです。**
AWS SAA S3あれこれ

SAAで出てくるストレージタイプ

IA＝Infrequently Accessの略。低頻度アクセスのこと。
　　取得自体は即時にできるが、その分課金が発生する

### One Zone-IA
非冗長化×低頻度アクセス
ユースケース：重要でないコピーファイルのアーカイブ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892426/78923609-c030-5e0c-88db-44233fa5fc0f.png)


### ストレージゲートウェイ
キャッシュ型＝オンプレ側をキャッシュサーバ、S3側をプライマリとして利用
保管型＝オンプレ側をプライマリとして利用、S3側をキャッシュとして利用

具体的な利用イメージ

### **全体のフロー**
1. **オンプレミスにゲートウェイアプライアンスをインストール**
   - AWSストレージゲートウェイは、**仮想マシン（VM）**または**ハードウェアアプライアンス**としてオンプレミスの環境にインストールされます。
   - これにより、オンプレミスのシステムとAWSクラウド間でデータをシームレスにやり取りできるようになります。
   - ゲートウェイアプライアンスは、オンプレミスのアプリケーションやサーバからのデータを処理し、AWSクラウドに送信する役割を担います。

2. **オンプレミスのアプリケーションがゲートウェイにデータを保存**
   - オンプレミスのアプリケーションは、AWSストレージゲートウェイを**ローカルストレージ**として認識します。たとえば、ファイルゲートウェイの場合、NFSまたはSMBプロトコルを使用してファイルサーバとしてアクセスします。
   - アプリケーションがデータを保存すると、**一時的にローカルキャッシュ**に保存されます。ボリュームゲートウェイやテープゲートウェイの場合、iSCSIインターフェースを使用してデータの読み書きを行います。

3. **データをAWSクラウドに送信**
   - ゲートウェイアプライアンスは、オンプレミスに一時的に保存されたデータをバックグラウンドで**Amazon S3**や**Glacier**に非同期的に送信します。この処理は、オンプレミスのネットワーク帯域を最適に利用しながら行われるため、アプリケーションのパフォーマンスに影響を与えません。
   - **データの圧縮と暗号化**が行われ、効率的かつ安全にクラウドに送信されます。これにより、ネットワーク帯域を節約しながら、データのセキュリティも確保されます。
   
4. **クラウド上でのデータ管理**
   - 送信されたデータは、クラウド上で**Amazon S3**や**Amazon Glacier**に保存され、バックアップ、アーカイブ、長期保存などの用途に利用されます。
   - クラウドに保存されたデータは、AWSのさまざまなサービス（データ分析、機械学習、データ復旧など）と連携して利用することが可能です。

5. **キャッシュ型と保管型の動作**
   - **キャッシュ型**（Cached Mode）の場合、オンプレミスには頻繁に使用されるデータだけが**ローカルキャッシュ**として保存され、メインのデータはすべてAWSクラウドに置かれます。これにより、大容量のデータを扱う場合でもオンプレミスのストレージリソースを最小限に抑えつつ、AWSのクラウドに格納されたデータにアクセスできます。
   - **保管型**（Stored Mode）の場合、データはまずオンプレミスに保存され、その後バックアップ目的でAWSクラウドにスナップショットとして送信されます。オンプレミスのシステムはローカルのデータを使用して高速なアクセスが可能でありながら、クラウドにバックアップを保存します。

6. **データの復元とアクセス**
   - データがクラウドに送信された後、オンプレミスのシステムやアプリケーションは必要に応じて**クラウドからデータを読み込む**ことができます。たとえば、キャッシュにないデータはクラウドから自動的に取得され、オンプレミスに再度キャッシュされます。
   - 災害復旧やデータのバックアップリストアが必要な場合には、クラウド上に保存されたデータをオンプレミスの環境に**迅速に復元**することが可能です。

---

### **システム全体の挙動のポイント**

1. **ローカルキャッシュの利用**: キャッシュ型モードでは、オンプレミスには必要なデータだけがキャッシュされるため、頻繁にアクセスされるデータはローカルで高速に処理されます。低遅延でのアクセスが可能です。

2. **ネットワークの効率的な使用**: データは圧縮され、バックグラウンドでクラウドに送信されるため、ネットワークの負荷を最小限に抑えながらデータの送信が行われます。また、オンプレミスのストレージが一杯になっても、クラウドへの非同期転送が行われるため、運用上の利便性が向上します。

3. **データのセキュリティ**: データは送信前に暗号化され、クラウド上での保存も暗号化されます。これにより、データの保護が確保され、セキュリティリスクを最小限に抑えます。

4. **AWSのスケーラビリティの活用**: AWSのクラウドストレージのスケーラビリティを活用することで、オンプレミスのストレージ容量の制限を気にせずにデータを管理できます。

5. **自動管理**: データの転送やキャッシュの管理は自動的に行われるため、ユーザーが手動で介入する必要はほとんどなく、運用の簡略化が実現されています。

---
### ランダムプレフィックス
何かS3バケットに対して大量にアクセスさせる場面がある場合は、バケットのキーのつけ方に注意！
バケット名/キー名/○○.jpg　というバケット構造があるとき、~~このキー名は日付などの連続した規則正しいものではなく、ランダムな文字列のほうがストレージに対する処理が軽くなるよーという話。~~
ランダムなプレフィックスではなく、日付でプレフィックスを構成するとS3に対するCRUD処理パフォーマンスが良くなるよーという話。（修正：2024/10/19）
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/using-prefixes.html

### クロスアカウントアクセス、リクエスタ支払い
S3バケットのクロスアカウントアクセスを有効化して、S3バケットのリクエスタ支払い機能を有効化することで、他AWSアカウントからのS3バケットへのアクセスを許可した上で、データ取得のコストをヨーロッパ企業側に支払わせることができます。

### ストレージクラス分析
任意のS3バケットに対してストレージの使い方をアクセスログから分析し、他ストレージクラスへの最適な移行プランを提案してくれる。
例　スタンダードクラスにおいてあるが、低頻度のアクセスしか実施されていないものについては、
　　スタンダード低頻度アクセスクラスに移行させるライフサイクルポリシーを提案してくれる
【エラー】you're importing a component that needs next/headers. that only works in a server component 

# はじめに
supabaseのログイン機能を公式ドキュメントに則って実装していたら以下のエラーが出ました。

```
you're importing a component that needs next/headers. that only works in a server component 
```

- 公式ドキュメント

https://supabase.com/docs/guides/auth/server-side/nextjs

# 問題
上記のエラーはsupabase clientをserver.tsファイルで設定をしている中で、cookiesをインポートしている箇所で出ています。


```:servert.ts (公式ドキュメントより)
import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { cookies } from 'next/headers'

export function createClient() {
  const cookieStore = cookies()

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll()
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options)
            )
          } catch {
            // The `setAll` method was called from a Server Component.
            // This can be ignored if you have middleware refreshing
            // user sessions.
          }
        },
      },
    }
  )
}

```


問題は上記で作成しているcreateClient()をHeaderコンポーネントで以下のように使用しようとしたことにあります。
```Header.tsx
export default async function Header() {
const supabase = await createClient();

 const {
     data: { user },
   } = await supabase.auth.getUser();

以下return文は省略
```

server.tsのcreateCilent関数からcookieに入っているUser情報を取得しようとしてきています。

## エラーの原因
エラーが発生しているのは、サーバーサイドでのみ動作するcreateClient関数のcookies()をクライアントコンポーネントで直接インポートして使用しようとしていることが原因だとわかりました。


# 解決法
以下の3ステップで解決をします。
① サーバー側の処理とクライアント側の処理を完全に分離
server.tsでgetUser()を作成し、user情報を返却するようにする。
```server.ts
...上記のserver.tsと同じため省略

export async function getUser() {
  const supabase = createClient()
  const { data: { user } } = await supabase.auth.getUser()
  return user
}

```

② サーバーアクション用のファイルを作成する
ファイルの中でserver.tsで作成したgetUser()を返却するようにする。

```action.ts
'use server'

import { getUser } from '../utils/supabase/server'

export async function getCurrentUser() {
  return getUser()
}
```

③ 最後にHeader.tsxを以下のように変更します。
```Header.tsx
'use client'
import React, { useEffect, useState } from "react";
import { getCurrentUser } from "../action";

export default function Header() {
  const [user, setUser] = useState<User | null>(null);

  useEffect(() => {
    getCurrentUser().then(setUser);
  }, []);

以下return文は省略
```

サーバーアクションで作成したgetCurrentUser()を使ってサーバー側で取得しているユーザー情報を取得します。

上記の変更によりサーバーとクライアントコンポーネントの役割を明確化させ使用することでエラーを解消することができました。

# おわりに
こちらのエラーはsupabaseのバグか？と色々なところで話題になっておりましたが、はっきりとした解決法がなく1時間近く調べまくっていました。

結局はsuapbaseのバグではなくコンポーネントの使い分けに問題があることがわかりました。
同じようなエラーが出た方の参考になれば幸いです！


# 参考資料

https://github.com/vercel/next.js/issues/56630

https://github.com/orgs/supabase/discussions/18086