OmniAICreator/Qiita-1.07M huggingface dataset:
Amazon VPC Latticeを使ってBlue/Green Deployを行う

# はじめに
本記事では、Amazon VPC Latticeを使ってBlue/Green Deployを行う方法についてまとめたものになります。アプリケーションのBlue/Green Deployにはいくつか方法がございますが、手札の一つとして持っておければと思います。
# 実現したいこと
+ アプリケーションやサービスの更新時に、できるだけダウンタイムを少なくBlue/Green Deployを行いたい
# 実施手順
## 事前の状態
+ クライアントVPC-サービスVPC間がVPC Latticeで接続されている状態
　→Latticeのそもそものサービスネットワークやターゲットグループの作成は[こちら](https://docs.aws.amazon.com/ja_jp/vpc-lattice/latest/ug/create-service-network.html "Lattice VPC サービスネットワークを作成する")
+ 新バージョンのアプリケーションが新しいVPCでデプロイされている状態
![before2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308706/cfa769de-70d7-c635-8c58-6bba889f18d3.png)
## 切り替え準備
### 新バージョンのVPCをVPC Latticeターゲットグループに追加
1\. VPC Latticeのターゲットグループを作成
2\. ターゲットタイプ（インスタンス or IPアドレス or Lambda or ALB）やプロトコル・ポートはアプリケーションに合わせて設定（HTTP or HTTPS or TCP）
3\. ターゲットを指定して作成
### Latticeサービスに追加
1\. 既存のサービスを選択しリスナールールを選択
2\. リスナーのアクションを選択し、ターゲットグループを追加。重みはOld Verを1、New Verを0にしておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308706/a242bb22-fe1c-fec1-a73d-479a515a8f15.png)

#### 切り替え前の状態
![blue.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308706/adac393f-828d-0c80-5e41-045158f03642.png)


## 切り替えの実施
1\. 既存のサービスを選択しリスナールールを選択
2\. リスナーのアクションを選択し、重みの値をold verを0、new verを1に入れ替える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308706/2bc42153-64a4-f07f-2be7-86e960c47894.png)

#### 切り替え後の状態
![green.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308706/be758420-df38-aedb-c563-6268deb973c2.png)

New Verのアプリケーションが問題ないことを確認できたら、Old VerのターゲットグループをLatticeサービスのリスナーから削除し、Latticeターゲットグループを削除した後、Old VerのVPCやアプリケーションを削除する

# ユースケース
+ アプリケーションの更新に伴いVPC内部の構成の更新（EC2ベースからECSベースへの更新など）やALBの入れ替えが必要で、VPCごと入れ替えをおこなう場合
+ アプリケーションごとにVPCの管理者が分かれており、なおかつIPアドレス設計の考慮をあまりしたくない場合
+ DNSのスワップによる一時的なダウンタイムを短くしたい場合
# 本方式のメリット・デメリット
### メリット
+ ネットワークやVPCの切り替え中の考慮を少なくでき、VPC内の設計を簡素化できる
+ アプリケーションやデータベースごとにVPCを作るため、全体的なワークロードの疎結合化が可能になる
+ DNSのスワップによるダウンタイムを回避できるため、切り替え時間が早い
### デメリット
+ クライアントーサービス間の通信が双方向になる場合は利用できない
+ 不特定多数がアクセスするVPCには適用できない（インターネットから直接接続されてくるVPC）
+ VPC Latticeを使ってサービス間の接続を行っていない場合は、サービス間接続の構成変更が必要になる
# まとめ
VPC Latticeの機能から一つユースケースを考えてみました。VPC Latticeを利用することでサービス間の疎結合化ができるため、普段からVPC Latticeを使っていくことをお勧めします。
[SwiftUI/MacOS]サイドバーの表示・非表示ボタンを明示的に作成する

作業メモです。

# TL;DR
- Buttonのaction:に`NSApp.sendAction(#selector(NSSplitViewController.toggleSidebar(_:)), to: nil, from: nil)`を追加するだけ
- メニューバーに「ツールバーの表示・非表示する」メニューアイテムを表示するには、`WindowGroup`の`.commands`コンテンツに`SidebarCommands()`を追加する

## Abstract
This article will summarize how to mitigate this problem by adding other options to toggle the sidebar. This article describes two ways to tackle this problem. Option 1 is to add Toggle Sidebar menu option add the desire command to a `.command` modifier with `SidebarCommands()`. The other option is to add a button to a toolbar that calls the `toggleSidebar` method.

# 各種バージョン
- XCode 16.2
- MacOS minimum development version: 14.0
- Swift 5

# やりたいこと
- `NavigationStack`や`NavigationView`でツールバーを作成したときに、ツールバーを表示するボタン[下図]を明示的に表示したい。（`NavigationLink`で画面遷移したときなどシステム的に自動で表示されないときがある）
![](/images/37963b069d41a0/sidebar.leading.png)


# 成果物

## ソースコード

```swift
import SwiftUI

struct MainView: View {    
    // MainView
    var body: some View {
        NavigationStack() {
            // Navigation area
            Text("Navigation area")
                .toolbar {
                    ToolbarItem(placement: .navigation) {
                        Button(action: toggleSidebar, label: { 
                            Image(systemName: "sidebar.leading")
                        })
                    }
                } 
            // Body area
            Text("Body area")
            // abbr.
        }  
    }

    private func toggleSidebar() {
#if os(macOS)
        NSApp.sendAction(#selector(NSSplitViewController.toggleSidebar(_:)), to: nil, from: nil)
#endif
    }
}
```

### メニューアイテムに追加する
`SidebarCommands()`を追加するだけ。

```swift
@main
struct SampleApp: App {
    var body: some Scene {
        WindowGroup {
            MainView()
        }
        .commands {
            SidebarCommands()
        }
    }
}

```

## 参考リンク
- Toggle Sidebar in SwiftUI NavigationView on macOS - [Stackoverflow](https://stackoverflow.com/questions/61771591/toggle-sidebar-in-swiftui-navigationview-on-macos)
- `sendAction(_:to:from:)` - [Apple Developer Documentation](https://developer.apple.com/documentation/appkit/nsapplication/sendaction(_:to:from:))
型アサーション

### 型アサーション

```i```が具体的な型```T```を保持し、基になる```T```の値を変数```t```に代入する。

```
t := i.(T)
```

```i```が```T```を保持していない場合、この文はpanicを引き起こす。

型アサーションは2つの値(基になる値とアサーションが成功したかどうかを報告するブール値)を返すことができる。

```i```が```T```を保持していれば、```t```は基になる値になり、```ok```は真(```true```)になる。
そうでなければ、```ok```は偽(```alse```)になり、 ```t```は型```T```のゼロ値になり panic は起きない。

```Go
package main

import "fmt"

func main() {
	var i interface{} = "hello"

	s := i.(string)
	fmt.Println(s)

	s, ok := i.(string)
	fmt.Println(s, ok)

	f, ok := i.(float64)
	fmt.Println(f, ok)

	f = i.(float64) // panic
	fmt.Println(f)
}
// hello
// hello true
// 0 false
// panic: interface conversion: interface {} is string, not float64

// goroutine 1 [running]:
// main.main()
// 	/tmp/sandbox3611871940/prog.go:17 +0x14f
```
勉強日誌、データ型、for, while文

UdemyのPython for Data Science and Machine Learning Bootcampについて
セクション４を受講、今日はデータの型、for, while文の書き方について。

データ型は配列がリスト、タプル、辞書、セットの４つある事を学んだ。
それぞれ特徴は
リスト：Cでいう配列。複数のデータを格納する
タプル：リストと同様に複数のデータを格納するが書き換え不可
辞書：pythonオリジナルの様で詳しいイメージが湧きにくかったが、データにキーワードを関連付けられる？？
セット：重複を許さない配列

タプルと辞書についてはあれば便利なんだろうなとは思うけど、ぜひ使いたいというシーンがいまのところは想像できない。経験を積んで使いこなせるようになっていきたい。

for文は記述方法が直感的にピンとこない。
例題で書かれたコードが

x = [1,2,3,4]

out = []
for item in x:
    out.append(item**2)
print(out)

実行結果は
[1, 4, 9, 16]

なのですが、xの値を2乗しようとしてitemを2乗しているのがなぜだろう。
しかもitemって変数宣言してなくて突然現れたのも違和感。
これってpython界では一般的？？それとも特殊な記述例？？

これをCで記述しようとすると
int x[] = {1, 2, 3, 4}; 
int out[4]; 
int i;
for (i = 0; i < 4; i++) {
     out[i] = x[i] * x[i]; 
}
なので
下のように書く方が違和感なく入ってくる。

x = [1, 2, 3, 4]
out = []
for i in range(len(x)): 
    out.append(x[i] ** 2)

もちろんどっちじゃないとダメってことはないんだろうけど
なるべく一般的な見方に慣れていきたい。

あとでこの日誌を見返したときは講義の記述に慣れていて
あぁ、この時はこんなこと思ってたんだなあってなるんだろうか。
本当に突然Raspberry Piの解像度が変わった話

# ある瞬間、突然ラズパイの解像度が変わる
私はとある利用方法 ~~（Cookie Clicker24時間起動装置）~~ のため、ラズパイを常に起動しています。
※もっといい活用方法をずーーーっと探し中

メインPCの2枚目のモニタにラズパイのHDMIも差し、気づいたとき（数時間程度）に入力を切り替え、結構頻繁にラズパイの画面を覗いています。
そんなある時、事件は起こった・・・

# 突然、解像度が1024×768になる
本当に突然でした。最後に見てからおよそ2時間後ぐらいだったと思います。
HDMIの抜き差しや再起動、```sudo apt update```＆```sudo apt upgrade```などを行いましたが、そもそもラズパイの設定の```Screen Configuration```に1920×1080がない状況。
ブラウザが見づらくてしょうがないので非常に困りました。

# 解決方法
御託はいいから早く解決方法を、ということで以下手順。

### 環境
環境確認方法：https://qiita.com/keigo_kabutomori/items/41c7719faef9dd3f5510
- 本体：Raspberry Pi 5
- OS：Raspberry Pi OS（Debian version 12.9）

### 手順
- ```/boot/firmware/config.txt```の最後に下記を追記。vimでもnanoでも何でもいいですが、**必ずsudoで編集**してください。
  ```
  hdmi_ignore_edid=0xa5000080
  hdmi_force_hotplug=1
  hdmi_group=1
  hdmi_mode=16
  ```
- 再起動
- 起動後、ラズパイの設定の```Screen Configuration```にたくさんの解像度があるはず。そこから好きな解像度をお選びください。

# 余談
めちゃくちゃググって色んな方法試しましたが、ことごとく失敗。
```config.txt```の配置場所や記載内容がどれもちょっとずつ違い、どれも上手く行かず・・・
最終的にChatGPTに聞きました。ので、詳しいところはよく分かってないです。
以下の説明もChatGPTほぼそのまま。

### 設定値の意味
- ```hdmi_ignore_edid=0xa5000080```
  - モニターからのEDIDを無視。
  - EDID：モニターの解像度やリフレッシュレートの情報。
    - ~~これやってよかったのか？~~
- ```hdmi_force_hotplug=1```
  - HDMI接続がなくても、強制的にHDMIを有効化。
- ```hdmi_group=1```
  - HDMIのモードらしい。これはおそらく```hdmi_group=2```でもいいと思います。
  - 詳しくはhttps://nekopom.jp/raspberrypi_setting08/#index_id4
- ```hdmi_mode=16```
  - 1920×1080の60Hzモードです。上記リンクにグループごとのモードも記載してありました。

# 最後に
未だ原因不明。
これ根本的解決になってなくね？
Linux ホストへのリモート接続【LinuC 101 試験対策】

## Linux ホストへの接続方法

ssh プロトコルを利用して接続を行います。
ssh 接続の流れは以下の通りです。

1. ホスト認証
2. ユーザ認証

#### ホスト認証

ホスト認証は、接続先のサーバがなりすましではないことを認証します。ホストへの初回接続時に下記のメッセージが出て、ホストの公開鍵を記録するか確認されます。

```log
Are you sure you want to continue connecting (yes/no/[fingerprint])?
```

「yes」と入力すると、~/.ssh/known_hosts ファイルに登録されます。その後、以下の流れで暗号化通信を確立します。

1. 接続元のホストは共通鍵を生成し、接続先の公開鍵で暗号化する。
2. 接続先のホストは送られてきた共通鍵を、自身の秘密鍵で復号する。
3. 以降の通信は共通鍵を用いる。

接続先のサーバがなりすましであれば、接続先ホストの鍵ペアが異なるため、上記 2 の復号ができません。この仕組みによって、悪意あるユーザが接続先ホストになりすますことを防いでいます。

#### ユーザ認証

ユーザ認証は、接続先のホストが接続元のユーザを確認します。認証方法は下記２つがあります。

- ユーザ名とパスワードによる認証
- 公開鍵暗号方式による認証

以下の例では、ホスト「aaa.bbb.ccc.xxx」のユーザー「user」に対して接続を行っています。コマンド実行後はパスワード入力が求められます。

```bash
ssh user@aaa.bbb.ccc.xxx
```

ホストの IP アドレスは以下のコマンドで調べられます。実行したマシンに割り当てられている IP アドレスなどの情報を表示します。

```bash
ip a
```

公開鍵暗号方式による認証では、接続元ホストの公開鍵を事前に接続先ホストの「~/.ssh/authorized_keys」ファイルに登録しておき、鍵のペアで認証します。

まず、接続元で公開鍵ペアを作成します。-C オプションでコメントを付与できます。

```bash
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
```

次に、生成した公開鍵を接続先ホストに登録します。以下の例では、ホスト「aaa.bbb.ccc.xxx」のユーザー「user」の「~/.ssh/authorized_keys」に登録されます。

```bash
ssh-copy-id user@aaa.bbb.ccc.xxx
```

登録後、パスワードなしでログインできれば認証成功です。

```bash
ssh user@aaa.bbb.ccc.xxx
```

## 接続の切断

ホストからの切断は、以下の方法があります。

- logout コマンド
- exit コマンド
- Ctrl + d 押下

## ホストのシャットダウン

ホストの停止や再起動は、shutdown コマンドを使用します。

```bash
# 1分後にシャットダウン（オプション、引数省略）
shutdown

# 今すぐシャットダウン
shutdown -h now

# 5分後にシャットダウン
shutdown -h +5

# 5分後に再起動
shutdown -r +5

# 12時に再起動
shutdown -r 12:00

# シャットダウン、再起動の予約をキャンセル
shutdown -c
```

なお、以下のコマンドでもシャットダウンや再起動が可能です。

（シャットダウン）

- halt
- poweroff
- systemctl poweroff

（再起動）

- reboot
- systemctl reboot
M2チップ搭載MacのDocker+Lima環境でAMD64用MySQL5系のコンテナを動かす方法（2025年度版）

## この記事の目的
M2チップ搭載のMac上でDocker+Lima環境を用いてMySQL5系を動かそうとした際、
ちょっと躓いた点があったので、備忘録として

## 動作環境
PC: MacBook Air (M2, 2022) 
OS: macOS Ventura 13.7.2

## 躓いた点その1
brewコマンドでLimaをインストール後、
LimaのGithubから[docker用の起動テンプレート](https://github.com/lima-vm/lima/blob/master/templates/docker.yaml)を入手して、
Limaの起動には成功。

ところが、dockerで`--platform`オプションを付けてもエラーが出て、AMD64用のMySQL5.6コンテナが起動しません。
[公式ドキュメント](https://lima-vm.io/docs/config/multi-arch/)を確認したところ、docker.yamlの記述では、デフォルトでRosettaが有効になっていないため、明示的にRosettaを有効にする必要があります。

以下の記載をyamlファイルに追記すればOKです。
```
vmType: "vz"
rosetta:
  enabled: true
  binfmt: true
```

## 躓いた点その2
2025年1月現在、Limaのdocker.yamlテンプレートではOSがUbuntu24.04になっていますが、
こちらのバージョンに搭載されているカーネルのバージョンとMacOS 13に搭載されているRossettaの相性の問題で、Dockerコンテナが動かない現象が報告されているようです。（こちらソース元リンクを紛失したので後で追記します）

既にApple側で対応済とのことですので、MacOSを14以上にアップデートするか、どうしてもOSを更新できない場合は、古いカーネルであれば問題なく動くらしいので、古いカーネルを使用しているUbuntu22.04あたりを使用するよう、docker.yaml内の記述を修正すれば解決するようです。（自分はやむなく後者で対応しました）
```
images:
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"
  arch: "aarch64"
```

## さいごに
ある程度古い環境を最新版の端末、OSで動かす必要性というのはたまに出てきますが、数年前、場合によっては数ヶ月前に出来た方法がミドルウェアのサポート切れなどによって再現できなくなる状況というのは、やはりどうしても出てきます。私が躓いたこの備忘録が誰かの一助となれば幸いです。
【Unity】AudioSource の PlayOneShot で同じ音を多重再生する際の違和感を軽減する手法

# 概要
AudioSource.PlayOneShot() を使えば多重再生できますが、同じ音を何度も再生すると単調で違和感が生まれます。
音にバリエーションを用意しランダム再生すれば改善しますが、メモリを食います。

再生時にピッチをランダムな値に変更する手法ならより少ないバリエーションで違和感を軽減できます。しかし再生中の音のピッチが急に変わるので、別の違和感が発生する恐れもあります。

# 手法紹介

そこで私は **AudioSource のピッチを PerlinNoise でランダムかつ滑らかに変動させ続ける手法**を考えました。
1つの音に限らず、複数種類の音を多重再生しても自然に聞こえると思います。

```
    public void UpdatePitch()
    {
        audioSource.pitch = Pitch - PitchRange / 2 + PitchRange * Mathf.PerlinNoise1D(Time.time * NoiseFrequency);
    }
```

# 実装例

``` AudioSourcePitchNoisier.cs
using UnityEngine;

[RequireComponent (typeof(AudioSource))]
public class AudioSourcePitchNoisier : MonoBehaviour
{
    [SerializeField] public float Pitch = 1f;
    [SerializeField] public float PitchRange = 0.1f;
    [SerializeField] public float NoiseFrequency = 1f;

    private AudioSource audioSource;

    private void Awake()
    {
        audioSource = GetComponent<AudioSource>();
    }

    private void Update()
    {
        UpdatePitch();
    }

    public void UpdatePitch()
    {
        audioSource.pitch = Pitch - PitchRange / 2 + PitchRange * Mathf.PerlinNoise1D(Time.time * NoiseFrequency);
    }
}
```
螺旋状に参照する【Python】

競技プログラミングで螺旋状（スパイラル状）にデータを読み取るという問題が時々出てきます。その問題の解き方です。
# 考え方
螺旋状に読み取るべきデータは２次元リストに入っているものとします。具体的には
```py
testdate=
[1, 2, 3],
[8, 9, 4],
[7, 6, 5,]
```
のような感じです。　これを1→2→3...のように読み取ることを目指します。
![Screenshot 2025-01-12 9.44.19 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3873438/946aee9d-607b-9538-8098-d77fb34a7395.png)
## 案1.ループを使う
```py
result=[]
top_row,bottom_row,left_col,right_col=0,len(testdate),0,len(testdate[0])

while top_row<bottom_row and left_col<right_col:
    #上辺（右から左）
    for col in range(left_col,right_col):
        result.append(testdate[top_row][col])
    top_row+=1
        
    #右辺（上から下）
    for row in range(top_row,bottom_row):
        result.append(testdate[row][right_col-1])
    right_col-=1
    if not (top_row<bottom_row and left_col<right_col):
        break
        
    #下辺(左から右）
    for col in range(right_col-1,left_col-1,-1):
        result.append(testdate[bottom_row-1][col])
    bottom_row-=1

        
    #左辺（下から上）
    for row in range(bottom_row-1,top_row-1,-1):
        result.append(testdate[row][left_col])
    left_col+=1
```
処理の順は、上端→右端→下端→左端→...です。```***_col```を1ずつ変えることで範囲を狭めています。
# 案2.回しながら消す
これは自分では思いつけませんでした。ChatGPTが教えてくれて、いいなって思ったので紹介します。
```py
result=[]

while testdate:
    result+=testdate.pop(0)  #上辺を取得して削除
    if testdate:#残りがある場合
        testdate=list(zip(*grid))[::-1]  # 残りを回転（列を行として扱う）
```
これすごいですよね。さっきのコードを見てからはびっくりするぐらい簡潔です。一番上にある行を削除&取得して、回すという方法です。回すと右端が一番上の行になるし、削除するので範囲の制限もいらないという出来すぎているコードだと思います(もしかしてこれぐらいが社会では普通だったりします？実務をしたことがないのでわかりません)。
GolangでValueObjectの実装



### ValueObjectの学習をしたので、そのアウトプットとして記載します。

#### 1.ValueObjectとは
　・日本語では、値オブジェクトとか記載されいてる。
　・システムで利用される項目の条件を1つのオブジェクトにまとめたもの
　・イミュータブル（変更不可）である。

#### 2.なぜ必要なのか
##### なぜこのような面倒なことをする必要があるのか？普通にGetter／Setterを使えばいいじゃないか。と思ってしまいます。ちゃんと意味があり、ValueObjectが実装されています。その意味を以下に記載します。
##### ①：型安全
　各業務、各機能で利用されている項目は、全て入力される条件が存在しています。
 その条件を無視して実装してしまえば、当然バグとなってしまいます。
 その条件を１つにまとめ、データが生成される段階で、入力条件は全てクリアしている状態で作成されると、そのデータは、間違いなく正しいと言えます。
 それが型安全となります。
 ※条件を他のコード（例えばServiceとか）に書けばいいじゃんと思うかもしれませんが、そうした場合、入力条件の判定分が、いろいろなコードに散らばってしまい、コードを変更しようとした場合、思わぬところでエラーが発生する可能性が出てきます。そうなると、品質が低下していしまいます。
　
###### ②：データの不変性
　各処理で作成されるデータは、すべて目的を持って作成されます。
  データが変更される場合、作成された目的が異なるという事になります。
  そのため、同じ変数を使い回すと、作成された目的が何か分からなくなってしまいます。
  また、どこでそのデータが更新されたか、調査にも時間がかかるようになります。

#### 3.実装
```main.go
　package main

import (
	domain "VALUEOBJECT/domain"
	"fmt"
)

func main() {

	usercd, _ := domain.NewUsercd("TEST")

	fmt.Println(usercd.Value())

}

```
```usercd.go
package domain

import "errors"

type Usercd struct {
	usercd string
}

// NewUsercdはUsercdのコンストラクタ
// データを登録する際は、この関数を使ってUsercdを生成する
func NewUsercd(usercd string) (Usercd, error) {
	// ユーザーCDが空の場合はエラーを返す
	if usercd == "" {
		return Usercd{}, errors.New("usercd is required")
	}

	// ユーザーCDに禁則文字が含まれている場合はエラーを返す
	if !check_forbidden_char(usercd) {
		return Usercd{}, errors.New("usercd is required")
	}

	return Usercd{usercd: usercd}, nil
}

// UsercdはユーザーCDを返す
// Constructorで生成したUsercdの値を取得する
func (n Usercd) Value() string {
	return n.usercd
}

// 禁則文字チェック
func check_forbidden_char(usercd string) bool {
	if usercd == "***" {
		return false
	}
	return true
}

```
※ちなみに、main.go内の変数：usercdに別の値を設定しようとすると、エラーとなります。

 
#### 4.結果
実行した結果、以下のような回答がありました。
```
　$ go run main.go
 TEST
```


　
#### 5.実行したコード
https://github.com/NoriStock1983/GO_ValueObject/tree/main/ValueObject


#### 6.参考にしたサイト
https://zenn.dev/devkono/articles/20231201_ddd_943df624fbf004#%E3%83%87%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88%E3%81%AF%E3%81%AA%E3%81%84%E3%81%AE%E3%81%8B%EF%BC%9F

https://zenn.dev/jy8752/articles/757f37b3a7c7cd
創世記2章:ポンコツの神様二人目のアダム作り大混乱

#### **第一幕：完璧な設計図のはずが…**
神様が「楽園（エデン）」を創ることにした。計画は完璧で、まずは美しい庭を生成し、データベースに「楽園_DB」を立ち上げた。  
  
```sql
CREATE TABLE Garden (
    ID INT PRIMARY KEY,
    Name VARCHAR(255),
    Description TEXT
);
```

「これで完璧だ！」と神様は満足げにSQLを実行。しかし、ここで問題が発生する。神様は「最適化のために」という理由で、**過去のログを残さない設計**にしていた。

```sql
SET GLOBAL log_output = 'NONE';
SET GLOBAL general_log = 'OFF';
```

これにより、楽園で何が行われたのか記録されない状態に。神様は「ログなんていらない！私の記憶は完璧だ！」と豪語しつつも、早速アダムを生成するのを忘れてしまう。

---

#### **第二幕：エラー、エラー、エラー！**
神様はアダムを手動で追加することに。

```sql
INSERT INTO Garden (ID, Name, Description) VALUES (1, 'Adam', 'The first man');
```

しかし翌日、「アダムがいない！」と騒ぎ出す。  
原因を探るためにログを見ようとするが、ログが無効化されているため原因がわからない。神様は仕方なく再びアダムを生成。

```sql
INSERT INTO Garden (ID, Name, Description) VALUES (2, 'Adam', 'Duplicate Adam');
```

こうして「アダム2号」が誕生。さらに、「記憶」に頼り過ぎた結果、神様は**アダム1号とアダム2号を区別できない**状況に陥る。  
ここでイヴを生成しようとするが、「どのアダムからイヴを作るべきか」混乱し始め、最終的に複数のイヴが誕生してしまう。

```sql
INSERT INTO Garden (ID, Name, Description) VALUES (3, 'Eve', 'The first woman');
INSERT INTO Garden (ID, Name, Description) VALUES (4, 'Eve', 'Duplicate Eve');
```

楽園はアダム2人、イヴ2人のカオス状態に。

---

#### **第三幕：カオスの果てに**
神様はなんとか楽園の混乱を収めようと、「アダムとイヴのリレーション」を記録するテーブルを作成。

```sql
CREATE TABLE Relationships (
    AdamID INT,
    EveID INT,
    PRIMARY KEY (AdamID, EveID)
);
```

だが、ここでも**過去のログを残さない設定**が問題に。「アダム1号とイヴ1号はカップルだったのか、それともアダム2号とイヴ2号だったのか？」誰も記憶していない。神様は仕方なくランダムに組み合わせて楽園を運営するが、不満を持つアダムとイヴが次々と脱出してしまう。  

最終的に楽園には何も残らず、神様はデータベースに直接書き込むことすら諦める。  
「次はNoSQLでやってみるか…」とつぶやく神様の背中が哀愁に満ちていた。

---

### **解説：過去のログを残さない問題**
この物語の核となる問題は「データベースにログを残さないこと」。ログを無効化することで次のような弊害が発生した：

1. **トラブルの原因特定が困難**
   - アダムやイヴが消えた原因を調べる手段がないため、同じミスを繰り返してしまう。

2. **履歴の欠如による混乱**
   - アダムやイヴのリレーションを正しく管理できず、楽園全体がカオスに陥った。

3. **透明性と信頼性の低下**
   - 「誰がどの操作をしたのか」記録がないため、運営に一貫性が欠けてしまった。

現実のデータベース運用では、過去のログはトラブルシューティングや運用の最適化に不可欠。ログを無効化する選択は、短期的なパフォーマンス向上に見えるが、長期的な視点で見ると致命的な失敗を招く可能性がある。
SQL処理速度改善 学習走り書き

DB設計・SQL作成をする際の注意点。
個人の学習メモとして走り書きで書いていく。

# 1. ビュー作成の注意点
ビューを使用したSQLを実行すると、まずビューのSQLを実行。
そのため、パフォーマンスは悪くなる。

使えるSQLの命令にも制限がある(以下参考)。
https://qiita.com/0511hideya/items/d3635778fc4cfc625462
・どうやってビューを作ったか
・どの命令が使えないか
この2つを確認。

# 2. インデックスが使用可能な所
サブクエリは使えない。
GroupByで使えるケースなどもあるので、設計時に確認。
インデックスが使えないケースも要確認。

# 3. join
以下の2つで検索結果が同じになる場合。
①. joinして最後に条件を指定
②. join内でテーブルの条件を指定

①の方が可読性は高い。
処理速度を取るなら②がよい。

# 4. 小技参考
使わせて頂きます。
https://qiita.com/babashoya/items/2e634954d5a2d68a6523

# 5. 参考
ありがとうございました。
https://qiita.com/mounntainn/items/2c5a568c98b7e9c38c6f
【JS】アロー関数でオブジェクトを返す方法

## Overview

アロー関数でオブジェクトを返す際は、`()`でラップする必要があります。
```js
() => ( { key: value } )

() => { key: value } // これはダメ
```

---
ここからはすべて蛇足ですが、経緯を書きます。

---

通常のアロー関数は、`() => { return }`という構文です。

```js
const func = () => {
  // 処理
  return 
}
```

ただし単行のアロー関数は、`{}`と`return`句を使わずとも値を返すことができます。

```js
const sum = (a, b) => a + b

console.log(sum(1, 2)) // 3
```

JSのオブジェクトは`{}`で囲って表します。

```js
{ key: value }
```

オブジェクトを返したい場合は、以下のように書けば・・・あれ？

```js
const func = () => { key: 'value' }

console.log(func()) // undefined
```

`{}`がオブジェクトではなく、処理をラップするものとして解釈されてしまうのですね。

ということで、`()`でラップする必要があるのでした。

```js
const func = () => ( { key: 'value' } )

console.log(func()) // { key: 'value' }
```
コード影響範囲を自動で特定したい

# はじめに
ノベルワークスでエンジニアをしているりょうちん（[ryotech34](https://x.com/ryotech34)）です。

今回は、生成AIを使用してコードから依存関係マップを作成し、変更箇所をマップから辿ることで影響範囲を出力させようというものです。試験的にバックエンドに焦点を当てて実装してみました。

[browser-use](https://github.com/browser-use/browser-use) などブラウザを操作可能なAIエージェントが公開され、ゆくゆくはインプットとして機能したらいいなというのも狙いとしてあります。

# 対象読者
- テストに時間が取られてしまっている方
- 生成AIが実際に実務に使えるのか迷っている方

# 今回話さないこと
依存関係マップを作成するにあたり、Userに関連したコードを読ませました。
設計にはドメイン駆動設計（以下DDD）を採用し、少しアレンジを加えています。設計の詳細については今回はお話ししません。

# 結果
## 依存関係マップ
今回はワークフローを独自に作成し、DDDとして表現される各レイヤーごとに依存関係を特定して、依存関係をマッピングしていきました。
使用したモデルは`Claude 3.5 Sonnet`です。
![](https://storage.googleapis.com/zenn-user-upload/7ed22322498b-20250112.png)
## フロー
1. Controller層の特にエンドポイントを始点とし、依存関係をグラフデータとして格納する
2. UseCase層の依存関係をグラフデータとして格納する
3. Infrastructure層の依存関係をグラフデータとして格納する
4. domain層の依存関係をグラフデータとして格納する
5. グラフデータから依存関係マップを出力する
6. 依存関係マップをもとに変更箇所から影響範囲を特定する
## コード
今回インプットした一部コードです。
添付画像のようにimportに使用しているクラスまたはライブラリを依存先として解釈させ、グラフデータを作成しました。
![](https://storage.googleapis.com/zenn-user-upload/8cb191351720-20250112.png)
## 出力
CreateUserUseCaseを変更した場合は、userを作るエンドポイントが影響範囲であることが出力されました。
![](https://storage.googleapis.com/zenn-user-upload/2dfb627a22dd-20250112.png)

# Cursorに聞いてみた
完璧ですね。特に言うことはありません。。
![](https://storage.googleapis.com/zenn-user-upload/71364ed40f1f-20250112.png)

# おわりに
どうでしたでしょうか？
最近CursorやClineなどコーディングエージェントツールが話題として上がっており、関心の多い分野かと思います。
今回アップロードしたファイルは10ファイルほどで、3分弱ほどで今回の依存関係マップが作成できました。DIなど直接依存はしていないものの間接的に影響のあるものに関しては、これから検討していきたいと考えています。

今後の展望として
1. コードの修正
2. 影響範囲の特定
3. AIエージェントによるE2Eテストの自動実行

を考えており、今回は1から2までをワークフローで実行しました。
最後に記載したCursorの出力から見ると、1から3までをエージェントにお任せも出来そうです👀
【瓦変】40過ぎたおっさんが 9ヶ月半で Atcoder レート1000以上になった

入緑から4ヶ月半、AtCoderを始めて9ヶ月半。2025/01/11 開催の AtCoder Beginner Contest 388 でレートが 1000 を越えて緑の瓦が 3 枚になりました。色変は難しいでしょうから今回は瓦変で記事を書きます。刻みます。入緑記事はこちら。https://qiita.com/omakasessan/items/51af39959ba0b54ac0af 

![20250112_瓦変記事.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3876620/7b54fe6f-c511-ae26-6fd5-0122839c634b.png)


## 前回からやったこと
ABC200番台の C, D, E 問題を解いています。前と同じように 250 から 300 、その後は 249 から下に降りていってます。現在 226 まで終わりました。

[]![20250112_瓦変記事03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3876620/225440b5-ebb4-fe16-b75c-547db4ac5624.png)
![20250112_瓦変記事04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3876620/dc3f157d-8017-37fd-6d01-086d6a06be72.png)


見ればわかりますがE問題はだいぶ歯抜けになっています。解説を読んでもなお解けない問題が多すぎるのが原因です。CとDは前回述べたようにほぼ解き終えているのですがもう一度やっています。これは

* まだ解けていない難しい問題を解かないと成長できない
* 解けた爽快感を味わいたい

これらを両立するためです。同時に復習にもなります。解説を見ながら解いた問題も多いので、今度は解説を見ずに解けるかどうかを試します。自分の力だけで解けるようになった問題、前回も解けたけど今回はもっと簡潔なコードが書けた問題などがあり数ヶ月前に比べて自分の成長を実感できました。復習しながらなので総ACはあまり増えていません（前回までに740、今回までに898）が、この数値だけでは計れない復習の効果が出ているはずです。

![20250112_瓦変記事_05解法パターン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3876620/4455f139-d71e-d965-f0ed-6b93f78e3c52.png)


また、解きながらその問題が何を要求しているのか、自分が何に気づけなかったのかなど簡単なメモを問題ごとに残しました。なおそれぞれのコードにはもっと細かくコメントを残しています。

### C-D問題の復習の効果
C-D問題の復習によりコードを書く速さが上がり、またミスをすることが減りました。コンテストでは速度を争うのでこれはかなり大事です。また、今までなんとなく書いていた基本的なアルゴリズムについて振り返るきっかけになりました。具体的には以前記事にした尺取り法、DFS などです。とにかく何度も何度も使ってみて手が勝手にコードを書くぐらいにまで馴染ませるのが大事だと思いました。

前回のコンテスト（ABC388）では何度も二分探索を使ったのですが、添字のずれが気になって何度も書き直す場面がありました。これにはまると無駄に時間を浪費してしまいますから、次はこれを復習する必要がありますね。bisect_left, bisect_right の違い、0-index と 1-index の区別などライブラリ整理が必要そうです。


### E問題への挑戦、実装面に難
E問題はわずかながら自分でも解けた問題はありましたが、大半の問題は解説を見ながらのACです。さらに言えば解説を読んでもなおわからない問題が多数ありました。解説の内容が理解できない問題もありましたが、多くの問題は実装でつまづいています。これは競技プログラミングが下手というよりそもそもプログラミングが下手なんですね。実装を上手にやれてこそプログラマーだと思うので自分としてはAtCoderとは関係なく克服したい課題と捉えています。

## レート上昇
グラフを見ればわかるように、ここ2回は運良く一気に伸びましたがそれまでは緩やかに直線的に伸びています。月ごとに平均パフォーマンスを求めてみると以下の通りでした。

* 8月	947.75 （レート745～829）
* 9月	917.0 （レート819～859）
* 10月 1053.0 （レート890～916）
* 11月 885.25 （レート889～914）
* 12月 1040.0 （レート921～951）

11月など一部落ち込んだ場面もありましたが、多くの回で現在のレートよりも少し高いパフォーマンスが出て少しずつレートが上がっていきました。レートこそ上がっているもののパフォーマンスが伸び悩んでいるため、いずれ頭打ちになることが予想されました。レートが追いつく前に自分の実力を上げないと停滞してしまいます。

その後1月にいきなり2回連続の水パフォが出てレートを大きく上げています。上振れしたことでこの先にちょっと希望が持てました。

## 今後レートを上げるには
過去の傾向を見ていると多くの人が解けた問題は僕も解けて多くの人が解けない問題はやっぱり僕も解けないことがわかります。ざっと見た感じでは水diffの問題が解けたのは2回だけ、それも水の中では低い方です。少しずつ難しい問題も解けるようにしていきたいですが、先に書いたようにE問題を解き進めるのは容易なことではないので進行はゆっくりです。

逆に茶色などdiffの低い問題が解けなかったり、解けても非常に時間がかかってしまったりと直すべき点も見られます。解く速度はかなり大事で、ABC388ではすぐに答えを思いついたおかげで自分としては異様なほど高いパフォーマンスが出ました。ですから、難しい問題を解けるようにする一方で基礎をしっかり固め、簡単な問題を素早く確実に解けるようにすることが大事だと思いました。ちなみにこれは僕の中学受験や大学受験を思い出しても同じ傾向です。自分だけが都合良く答えを思いつける難問なんてそうそうないんですよね。

水になれたらいいなあと淡い期待を抱きつつ、今年も競技プログラミングを楽しんでいきたいと思います。
メモリ/磁気ディスク/フラッシュ/SSDの価格推移を可視化してみた（Makeover Monday 2025/W1）

[Makeover Monday](https://makeovermonday.co.uk/)の2025年第1週のお題 "Historical price of computer memory and storage" に挑戦してみたいと思います。

https://ourworldindata.org/grapher/historical-cost-of-computer-memory-and-storage

コンピューターの記憶デバイスのうち

- メモリ
- 磁気ディスク
- フラッシュ & SSD

のTBあたりの価格のデータ（1956-2023 年）を元にチャートを作ってみようという取り組みです。

# 1. 記憶デバイスの容量単価の推移

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388675/49f4839b-9245-b5b6-8492-d7123a3aa59f.png)

[記憶デバイスの容量単価の推移 - Tableau Public](https://public.tableau.com/views/2025W1_/sheet0?:language=ja-JP&:sid=&:redirect=auth&:display_count=n&:origin=viz_share_link)

まずは概要を把握する目的で、価格推移をシンプルに線グラフで表現します。この類の指標は指数関数的に減少するため、縦軸は対数を取っています。

- メモリと磁気ディスクは 1980 年前後から価格低下のペースが大きくなっているように見えます。
    - メモリは 1975 年ごろから。これは SRAM → DRAM の移行が影響しているのでしょうか。
    - 磁気ディスクは 1985 年ごろから。このあたりから PC での磁気ディスク採用が広がったようなので、その影響かもしれません。
- ただし、メモリ / 磁気ディスクの価格低下のスピードは 2010 年ごろから落ちているように見えます。
    - 価格低下に寄与する技術革新のペースが遅くなった、需要が増えて価格下げ止まり圧力があったなど理由は考えられますが、よく分かりません。
- 2020 年を超えたあたりで、メモリと SSD は大きく価格が下がっています。
    - コロナによる影響もあるかと思いますが、半導体不足と言われている中で差がているのは意外でした。


# 2. 磁気ディスクとSSDの今後の価格予測

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388675/0aaa3bb1-c9e6-25f2-098f-b2764e036ff5.png)

[磁気ディスクとSSDの今後の価格予測 - Tableau Public](https://public.tableau.com/views/2025W1_/SSD?:language=ja-JP&:sid=&:redirect=auth&:display_count=n&:origin=viz_share_link)

磁気ディスクと SSD の価格逆転はあるのか？というのはちょくちょく聞く話題です。2013-2023 年の価格推移から Tableau の予測機能を使って、今後の価格推移を予測し、いつ頃に価格が逆転するか探ってみました。

- Tableau のカスタム予測モデル（傾向 = 乗算 ＆ 季節 = なし）を用いました。
- 結果として 2036 年ごろに価格が逆転するという予測が出力されました。
    - 磁気ディスクの方は 2013-2023 年の間の傾向が安定しているので、予測も納得感があります。
    - SSD に関しては、予測区間（今回は 95%）が広がっているので、ちょっと難しい予測ですね。
- まぁ、あくまで今の傾向がそのまま続いた場合の参考値として捉えるのが良いかなと。

# 3. メモリと磁気ディスクの価格比

![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388675/8ed4297e-216c-8468-d154-296641215b43.png)

[メモリと磁気ディスクの価格比 - Tabluau Public](https://public.tableau.com/views/2025W1_/sheet2?:language=ja-JP&:sid=&:redirect=auth&:display_count=n&:origin=viz_share_link)

元データベース屋さんとしては、メモリ追加という札束によるパフォーマンス改善はやっぱり魅力的なので、メモリと磁気ディスクの価格比というのは気になります。なので、それを可視化してみました。（今どきの DB は SSD なので、メモリと SSD の価格比を本当は見たかったのですが、SSD のデータが少ないので今回は磁気ディスクとの比較です）

- 一時期でメモリ / 磁気ディスクの価格比がスパイク的に上昇（メモリが相対的に高い）した時期があります。
    - 1995年
    - 2000年
    - 2006年
    - 2010年
- スパイク的な上昇の理由はよく分かりません。
    - 2010年は DDR3 移行直後で それまでの DDR2 に比べ一時的に高くなったからかもしれません。（勝手な想像）
    - その他の時期については、需要の増大やメーカーの生産能力の停滞など色々考えらえますが、よく分かりません。（これだけスパイクしているので、一過性の原因である気もするのですが）
- スパイク的な上昇を除外しても、メモリ / 磁気ディスクの価格比は上昇傾向にあります。（メモリが高いのか、磁気ディスクが安すぎるのかは判断難しいところですが）

# おわりに

ことしは月１ぐらいのペースで Makeover Monday に取り組んでみようと思っていて、その第１弾でした。

長いこと Tableau 触っておらずにいろいろ忘れているので、ちょっとリハビリが必要かなと思いました。

また、可視化してみることでいろいろ興味深い事実は見えてくるのですが、その背景を探るために色々ググったり ChatGPT に聞いたりしても分からないことが多いですね。やはり業界知識が不足 ＆ 片手間だと難しいですね。

あと、2036 年は遠すぎだろ…
VSCodeのショートカットキーまとめ【Mac版】

## はじめに
暇すぎてVSCodeの公式リファレンスに載っているショートカットキーをまとめました。（Mac版のみ）
キーが多すぎてトラックパッド使った方が早そうなやつとか、使い所がよくわからないものもあって面白かったです。

## 参考文献

https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf

## ショートカットキー一覧
### 一般操作
- コマンドパレットを表示
`⇧` `⌘` `P`
<br>

- クイックオープン（別ファイルへ移動）
`⌘` `P`
<br>

- 新しいウィンドウを作成
`⌘` `N`
<br/>

- ウィンドウ/インスタンスを閉じる
`⌘` `W`
<br/>

- ユーザー設定画面を開く
`⌘` `,`
<br/>

- ショートカットキー一覧を開く
`⌘` `K` `⌘` `S`
<br/>

### 基本的な編集
- 1行まるっと切り取り
`⌘` `X`
<br/>

- 1行まるっとコピー
`⌘` `C`
<br/>

- 行を下/上に移動
`⌥` `↓` / `↑`
<br/>

- 行を下/上にコピー
`⇧` `⌥` `↓` / `↑`
<br/>

- 行を削除
`⇧` `⌘` `K`
<br/>

- 下/上に行を挿入
`⌘` `Enter` / `⇧` `⌘` `Enter`
<br/>

- 対応する括弧にジャンプ
`⌘` `⇧` `¥`
<br/>

- 行をインデント/インデント解除
`⌘` `]` / `[`
<br/>

- 行の先頭/末尾に移動
`⌘` `←` / `→`
<br/>

- ファイルの先頭/末尾に移動
`⌘` `↑` / `↓`
<br/>

- 1行上/下にスクロール
`Ctrl` `Fn` `↑` / `↓`
<br/>

- 1ページ上/下にスクロール
`Fn` `↑` / `↓`
<br/>

- 範囲を折りたたむ/展開
`⌥` `⌘` `[` / `]`
<br/>

- すべてのサブ範囲を折りたたむ/展開
`⌘K` `⌘` `[` / `]`
<br/>

- すべての範囲を折りたたむ/展開
`⌘` `K` `⌘` `0` / `⌘` `K` `⌘` `J`
<br/>

- 行コメントを追加（行コメントが既にある状態でのみ機能します）
`⌘` `K` `⌘` `C`
<br/>

- 行コメントを削除
`⌘` `K` `⌘` `U`
<br/>

- 行コメントの切り替え
`⌘` `/`
<br/>

- ブロックコメントの切り替え
`⇧` `⌥` `A`
<br/>

- ワードラップの切り替え
（長い行のテキストをウィンドウの幅に合わせて折り返して表示する機能）
`⌥` `Z`
<br/>

### マルチカーソルと選択
- クリックした場所にマルチカーソルを挿入
`⌥` `+` クリック
<br/>

- 上/下にカーソルを挿入
`⌥` `⌘` `↑` / `↓`
<br/>

- 最後のカーソル操作を取り消し
`⌘` `U`
<br/>

- 範囲選択した各行の末尾にカーソルを挿入
（範囲選択を行なってからでないと機能しません）
`⇧` `⌥` `I`
<br/>

- 現在の行を選択
`⌘` `L`
<br/>

- 現在の選択のすべての発生箇所を選択
（任意のエリアを選択した状態でこれを実行すると、選択したエリアの全ての発生箇所が選択されます）
`⇧` `⌘` `L`
<br/>

- 現在の単語のすべての発生箇所を選択
`⌘` `F2`
（うまくいかない場合は`⌘` `Fn` `F2`）
<br/>

- 選択範囲を拡大/縮小
`⌃` `⇧` `⌘` `→` / `←`
<br/>

- カラム（ボックス）選択
`⇧` `⌥` `+` ドラッグ
<br/>

- カラム選択を上/下に拡大
`⇧` `⌥` `⌘` `↑` / `↓`
<br/>

- カラム選択を左/右に拡大
`⇧` `⌥` `⌘` `←` / `→`
<br/>

- ページ単位でカラム選択
`⇧` `⌥` `⌘` `Fn` `↑` / `↓`
<br/>

### 検索と置換
- 検索
`⌘` `F`
<br/>

- 置換
`⌥` `⌘` `F`
<br/>

- 次/前の検索結果へ移動
`⌘` `G` / `⇧` `⌘` `G`
<br/>

- 検索一致箇所をすべて選択
`⌥` `Enter`
<br/>

- 次の検索一致箇所を選択に追加
`⌘` `D`
<br/>

- 最後の選択を次の検索一致箇所に移動
`⌘` `K` `⌘` `D`
<br/>

### リッチ言語編集
- サジェストをトリガー
`⌘` `I` もしくは `⌃` `Space`
<br/>

- パラメータヒントをトリガー
`⇧` `⌘` `Space`
<br/>

- ドキュメントのフォーマット
`⇧` `⌥` `F`
<br/>

- 選択範囲のフォーマット
`⌘` `K` `⌘` `F`
<br/>

- 変数や関数にカーソルを当てて、定義に移動
`F12`
（うまく動かない場合は`Fn` `F12`）
<br/>

- 定義をプレビュー
`⌥` `F12`
（うまく動かない場合は`⌥` `Fn` `F12`）
<br/>

- 定義をサイドで開く
`⌘` `K` `F12`
（うまく動かない場合は`⌘` `K` `Fn` `F12`）
<br/>

- クイックフィックス
（エラーが発生している箇所にジャンプ）
`⌘` `.`
<br/>

- 参照を表示
`⇧` `F12`
（うまく動かない場合は`⇧` `Fn` `F12`）
<br/>

- シンボルのリネーム
（変数名、関数名、クラス名などを一括で変更する）
`F2`
（うまく動かない場合は`Fn` `F2`）
<br/>

- 末尾の空白を削除
`⌘` `K` `⌘` `X`
<br/>

- ファイル言語を変更
`⌘` `K` `M`
<br/>

## まとめ
テキストだけだと具体的にどんな動きをするかイメージしづらいものもあると思うので、時間があればそのうち動画も追加したいなーと思ってます！
フォルダ構成を一から作るの面倒じゃないですか？

# きっかけ
ツールの検証作業や勉強の時にプロジェクトのファイルを一から構成作成するのがめんどくさくないですか？
そんなあなたに朗報です。自動化スクリプト作成しました。

:::note warn
あまりちゃんと検証していません。ファイルツリーの中に含むことができない禁則文字列やタブに設定されたスペースの数などでエラーが発生することがあるかもしれません。サクッと(chatGPTが)作ったものなのでこの辺りはご容赦ください。
:::

# 環境
- window10
- python 3.10 ... だったはず


# フォルダツリーから自動でフォルダとファイルを生成するスクリプト

## 概要
このスクリプトは、フォルダ構造を記述したテキストファイルを読み込み、その構造に基づいてフォルダと空のファイルを自動で生成します。

---

## スクリプト

```python
import os

def create_structure_from_text(file_path):
    """
    フォルダツリーのテキストファイルを読み込んで、フォルダ・ファイルを作成する
    """
    with open(file_path, 'r') as file:
        lines = file.readlines()

    # カレントディレクトリを基準にフォルダ構造を作成
    current_path = os.getcwd()
    path_stack = [current_path]
    i = 0
    for line in lines:
        # インデントの深さを計算 (タブまたはスペースでインデント)
        depth = len(line) - len(line.lstrip())
        name = line.strip()
        # 初期depthを記録
        if i == 1:
            initial_depth = depth

        # path_stackの3つ目の要素に含まれる"\"を数える
        if i > 0:
            count = path_stack[-1].count("\\") - path_stack[0].count("\\")
            print("count", count)
            if depth / initial_depth < count:
                # 現在の深さに応じてスタックを調整
                while depth / initial_depth < (path_stack[-1].count("\\") - path_stack[0].count("\\")):
                    path_stack.pop()

        # 新しいフォルダまたはファイルのパスを構築
        new_path = os.path.join(path_stack[-1], name)

        # フォルダまたは空のファイルを作成
        if "." in name:  # ファイルの場合
            with open(new_path, 'w') as f:
                pass
        else:  # フォルダの場合
            os.makedirs(new_path, exist_ok=True)

        # スタックに追加
        if "." not in name:  # フォルダのみ追加
            path_stack.append(new_path)
            i += 1
    print("フォルダとファイルが正常に作成されました。")

# 使用例: フォルダツリーファイルを指定
text_file_path = "folder_structure.txt"  # フォルダ構造が記述されたテキストファイル
create_structure_from_text(text_file_path)
```

---

## フォルダツリーの記述方法

スクリプトが読み込むテキストファイル（例: `folder_structure.txt`）には、以下のようにフォルダやファイルをインデント付きで記述します。

```plaintext
map_app
    app.py
    templates
        index.html
    static
        css
            styles.css
        js
            scripts.js
    requirements.txt
```

- **フォルダ**は拡張子がない名前で記述します。
- **ファイル**は拡張子付きで記述します。
- インデントは**スペースまたはタブ**で表現します。

---

## 実行方法

1. 上記のようなフォルダツリーファイル（例: `folder_structure.txt`）を作成します。
2. スクリプトを保存して、`create_structure.py` という名前にします。
3. 必要なフォルダツリーファイルを用意してスクリプトを実行します。

```bash
python create_structure.py
```

---

## 実行例

`folder_structure.txt` の内容:

```plaintext
project
    main.py
    src
        module.py
    tests
        test_module.py
    README.md
```

スクリプトを実行後、以下のようなフォルダとファイルが作成されます。

```plaintext
project/
├── main.py
├── src/
│   └── module.py
├── tests/
│   └── test_module.py
└── README.md
```

---

## 注意事項

- ファイルの中身は空の状態で作成されます。
- 既存のファイルやフォルダがある場合、上書きはされません。

---
【JS / TS】"??" と 三項演算子 "? :" の比較

## Overview
null 合体演算子 `??` は、三項演算子`? :`と比較し以下の2点に違いがあります。
- 無駄のない構文
- `null` / `undefined` のみを判定条件とする


## null 合体演算子 `??` とは
null 合体演算子 `??` は、`null` / `undefined` の値にデフォルト値をあてる演算子です。

ES2020で追加されました。

### 直感的な使い方
以下の例からわかるように、スマートかつ直感的な構文です。
```js
const foo = null
const bar = undefined

console.log(foo ?? 'default') // 'default'
console.log(bar ?? 'default') // 'default'
```

## 三項演算子 `? :` との違い

### 無駄のない構文
三項演算子では、同じ記述を繰り返す場合があります。

```js
// foo を2度記述している
foo ? foo : 'falsy'

// 簡潔
foo ?? 'default'
```


### `0` / `false` / `''` の扱い
null 合体演算子では、`null` / `undefined` に対しデフォルト値をあてます。
一方、三項演算子では `falsy` (`0` / `false` / `''` など) も `false` として扱います。

```js
const foo = 0
const bar = false
const baz = ''

console.log(foo ?? 'default') // 0
console.log(bar ?? 'default') // false
console.log(baz ?? 'default') // ''

console.log(foo ? foo : 'falsy') // 'falsy'
console.log(bar ? bar : 'falsy') // 'falsy'
console.log(baz ? baz : 'falsy') // 'falsy'
```

### `??` と `? :` の役割は異なる
これまで見てきたように、`??` は **デフォルト値を扱う** ことを目的としています。
`? :` は `falsy` / `truthy` を扱う演算子であり、役割は異なります。

しかし、両者がオーバーラップしているのも事実です。

## まとめなど
`??` には以下の利点があると言えます。
- 無駄がない構文
- `0` / `''` をそのまま扱える
- `falsy`を扱わないことによる、隙のない実装


### 判定条件と返り値が同一
`??` を使うことで、無駄のないコードになります。

```js
// foo を2度記述している
const bar = foo ? foo : 'falsy'

// 簡潔
const bar = foo ?? 'default'
```

### `Object` のプロパティ
三項演算子に加え、オプショナルチェイニングとも比較しました。
デフォルト値を簡潔に設定できます。

```js
obj.title ??= 'Untitled'

// 冗長
obj.title = obj.title ? obj.title : 'Untitled'

// デフォルト値を設定できない
obj.title?
```

### `0` / `''` をそのまま扱える
具体例が思いつきませんでした。
何かあれば教えてください。
Tableau Desktopの「既定のプロパティ」がやっかい

## はじめに
先日Tableauでデータソースを変更したら、せっかく設定したプロパティが初期化されてしまったのか指摘され修正しました。しかしうまくいかず他に原因があるのではと調べたことを記載します。

## プロパティの設定方法、実は3通りあります
Tableauで項目の並び順や表示形式、書式を設定する方法は、大きく分けて3つあります：

1. ワークブックのデータペインから「既定のプロパティ」を設定（Desktop限定）
2. データソースのデータペインから「既定のプロパティ」を設定（これもDesktop限定）
3. シェルフに配置した項目から「書式設定」や「並び替え」を設定（Desktop・Cloudどちらでも可能）

## それぞれの特徴を比較

### 1. ワークブックの既定のプロパティ
* **使える環境**: Desktop
* **ファイル形式**: twb/twbx
* **いいところ**: ワークブック全体の設定が一発でできる
* **イマイチなところ**: データソース変更したら設定が消えちゃう...

### 2. データソースの既定のプロパティ
* **使える環境**: Desktop
* **ファイル形式**: tds/tdsx
* **いいところ**: 接続したワークブック全体に一括で設定できる
* **イマイチなところ**: データソースごとに設定が必要

### 3. シェルフからの設定
* **使える環境**: Cloud・Desktop両方OK
* **ファイル形式**: twb/twbx
* **いいところ**: データソースを変更しても設定が残る！
* **イマイチなところ**: シートごとに設定が必要で、ちょっと面倒

## 既定のプロパティってそもそも何？
簡単に言うと、項目の並び順とか表示形式、書式をワークブック全体に一発で設定できる便利機能です。
ただし要注意なのが、ワークブックで設定した場合。データソースを変更すると設定が消えてしまう。

### 設定方法（Desktopだけ）
データペインで設定したい項目を右クリック→既定のプロパティ→設定内容を選択、という流れです。

## じゃあ、どうすれば設定が消えないの？

### データソースの既定のプロパティを使う
データソース側で設定しておけば、ワークブックの接続先が変わっても設定は引き継がれます。フローで出力を上書きしても大丈夫！ただし、項目名が一致してないとダメなのでそこは注意。

### シェルフから設定する
こっちの方法なら、データソース変更しても設定は残ります。
ただ、シートごとに設定しないといけないので、シートが多いと面倒に。

## 結論：こう使うのがおすすめ！
**重要ポイント**: データソースを変更する可能性があるなら、ワークブックの既定のプロパティは使わない方がいいと思いました！別の方法（今回はデータソースの規定のプロパティで設定）

## 補足：会計年度の設定について
これがまた厄介な問題なんですが、
パブリッシュされたデータソースを使ってるワークブックで会計年度の設定をすると、
パブリッシュ後に設定が消えちゃうことがあります。

### なんで消えるの？
結論、これは仕様みたいです。
データソース側の設定が優先されちゃうんですよね。

### 対処法は2つ！

#### 1. 日付フィールドを複製する
1. データペインで日付フィールドを右クリック
2. 「複製...」を選んで
3. 複製したフィールドで会計年度の開始月を設定

**注意**: ここ重要：チェック入れないと、データソースの設定が使われちゃいますよ。

#### 2. データソースのローカルコピーを作る
1. データソースのローカルコピーを作って
2. それを元のデータソースと置き換えて
3. 会計年度の設定をし直す

**注意**: これ使う場合は、設定後に再パブリッシュするの忘れずに！

## まとめ
結局のところ、どの方法を使うかは状況次第になります。
データソースの変更があり得るなら、それを考慮した方法を選びましょう。
機能と運用提案を含めた説明をした後に、実はできませんとか最悪なので…。

もし他に解決策等ご存知の方は指摘いただければ嬉しいです！
Nano KVM Liteの試食

# NanoKVMとは？
PiKVMに継ぐ次世代のKVMツールである。高価なサーバについているIPMI（リモートコンソール、物理スイッチ操作、ISOマウント）を提供する。（以下、Nano KVM FullをFull、NanoKVM LiteをLiteと表記する。）

NanoKVMにはLiteとFull版が存在しており、Lite版では下記の機能が去勢されている。

* 外部電源供給
    * 電源供給とマウス・KBが同じUSBポートで兼用になる。PCを再起動するとLiteがリセットされてしまい、UEFI画面などが操作できない。
* ATX電源操作
    * Fullではマザーボードのピンヘッダーを直接操作して電源ONできる。LiteではIOボードが付属しないので自分で何とかする必要がある。
* 液晶
    * IPアドレスなどを表示するOLEDがついていない。


Full版を購入された方のレビューはたくさん上がっている。

https://blog.masa23.jp/posts/2024/10/04/nanokvm/


FullとLiteのHWは共通となっている。そこで、とりあえず格安のLite版を購入し、Full版との違いを確認する。

# ハードウエア
LicheeRV Nanoがベースとなっている。マイコンボードの詳しい資料は
https://wiki.sipeed.com/hardware/zh/lichee/RV_Nano/1_intro.html
より確認できる。

## ピン配
https://github.com/sipeed/NanoKVM?tab=readme-ov-file

# ファームウエア
https://github.com/sipeed/NanoKVM/releases
からダウンロードする。最新版をWin32DiskimagerなどでMicroSDへ書き込む。今回は、**20241120_NanoKVM_Rev1_3_0.img**を使用。

# IPアドレス探索
何らかの方法でIPアドレスを特定する。公式の手順は下記を参照すること。
https://wiki.sipeed.com/hardware/zh/kvm/NanoKVM/system/updating.html#%E8%8E%B7%E5%8F%96-IP

# 初期パスワード
WEB UIの初期パスワードは
* admin / admin

SSHの初期パスワードは
* root / root

どちらも脆弱なので、落ち着いたら直しておくのがよさそう。

# 外部電源
まず外部電源を供給できるようにする。適当なUSBケーブルを切って、VSYSとGND間に5VをつなげばOK。

PoEを用いる場合は、PoEスプリッタがアマゾンで手に入るのでそれを使う（5V版を選択すること）

VBUSとVSYS間には0オーム抵抗でショートされている。もしかすると0オーム抵抗は取ったほうがいいのかも？とりあえず取らずに動作している様子。

![IMG_4568.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/87d2cdfc-7f37-ddca-c808-09c5b001c989.jpeg)
![IMG_4570.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/1b6b060f-9f77-de9f-a465-7d0519d41fc3.jpeg)



# ATX電源操作機能
ファームウエア上は生きている。GUIより操作すると、ATX PWRやRST出力がHIGHになる。しかし、ピン配列が微妙に誤っているようで（？）、公式情報でRSTとなっている端子がPWR、GPIOA22として未使用になっているポートがRSTになっているように見える。

テスター当ててみた感じ、おそらくこんな感じ？（ファームによって異なる？。利用は自己責任で、必ずテスターを当ててから行ってください。）



![{F75F8273-36D7-4DBE-81D6-A7F84159A93F}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/0b8699a1-e21b-b70d-08f3-25620547cdea.png)




電源短押しの場合、約800ms、信号がHIGHになる。
![{2CF73BFB-4B49-4523-983C-425B9CE1503C}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/e3908b66-d410-e1bb-da71-39acd3e33b4c.png)


電源長押しの場合、約8s、信号がHIGHになる。
![{134231E4-0B39-4A90-AFC4-14019B9A9466}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/400266d3-e36b-8037-c087-8dabb461fb5b.png)

周辺回路を作れば、ATX電源も使えそう。

# UART
UART0は、デバッグ出力か何かに使われている。
* UART1が、内部Linuxの/dev/ttyS1へ割り当てられている
* UART2が、内部Linuxの/dev/ttyS2に割り当てられている

ttys1,s2は、WEB UIから

# OLED
OLEDの動作は未確認。OLEDまでつなげるならFull版買えばいいのでは....。

# ISOアップロード
ISOは、WinSCPでSSH SCP転送するのがよい。適当なPCにUSBケーブルをつなぐと、マスストレージとして認識するが、動作が安定しなかったため。イーサネット経由の転送であれば安定する。WinWCPでroot / rootでログインし、/dataへISOを転送する。2MB/secくらいしか出ないので気長に待つのが良い。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/a2c61f70-7759-faef-5e11-1d155a860264.png)


# 所管
Lite版でも十分楽しめそう。

結局、PoEスプリッターとUSB TypeCスプリッターを組み合わせてこんな感じになった。
![IMG_4571.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/fa505955-93bc-549d-af29-6592e80318ae.jpeg)
John the Ripper とはなんぞや 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3981736/41e16220-e50b-56a6-09ca-352f1e601af0.png)

## John the Ripper とはなんぞや
言葉を選ばなければ、_パスワードハッキングツール_。
ハッシュ化されて保存されたパスワードや情報を元のテキストに変換できるツールで、
使い方によっては簡単に悪用できる危ういツールでもある。

ホームページはこちら：https://www.openwall.com/john/
ちなみに、GUI 版の [Johnny](https://openwall.info/wiki/john/johnny) なるものもある。

### 基本のコマンド
いろいろなモードはあるものの、一番スタンダードは：
`john --format={format_type} --wordlist={wordlist_path} {file path}`

このコマンドによって特定の hash テキストを特定のフォーマットとワードリストを使って解析する。例えばこんな感じ：

`john --wordlist=/usr/share/wordlists/rockyou.txt hash_to_crack.txt`

有名な rockyou.txt (詳細は[コチラ](https://appguard.aisel.ne.jp/blog/2024/03/13795/#:~:text=RockYou.txt%E3%81%AF%E3%80%812009%E5%B9%B4,%E3%81%BE%E3%81%9F%E3%80%81%E3%80%8C%E4%BD%BF%E3%81%86%E3%81%A8%E5%8D%B1%E9%99%BA%EF%BC%81)。リストは[こちら](https://github.com/brannondorsey/naive-hashcat/releases))をつかって hash_to_crack.txt を解析。

ただこれだと、ハッシュのフォーマットを指定していないので、分析に時間がかかってしまう。それ故に以下のフォーマットが最適である：

`john --format={format_type} --wordlist={wordlist_path} {file}`

フォーマットがわからない！そんなときは [Hashes.com](https://hashes.com/en/decrypt/hash) のようなツールを用いたり、[Hash Identifier .py](https://github.com/blackploit/hash-identifier/tree/master) を用いたハッシュ分析を併用することも良いと思う。

Hash Identifier を使う場合は通常の Python コードの利用通り。

`python3 hash-id.py`

### モードもろもろ
- Automatic Cracking : 

`john --wordlist={wordlist_path} {file}`
John the ripper が自動的にフォーマットを検知してクラックする。これだと誤検知の可能性や時間が長く掛かる可能性があるので。推奨ではない。

- Format Specific Cracking : 

フォーマットを指定してのクラック。無難で簡単
 
- Unshadow Cracking : 

`unshadow {/etc/passwd} {/etc/shadow} > {export_file_name.txt}`
/etc/shadow は Linux 上のハッシュ化されたパスワードやその記録が残っている箇所。([参照記事](https://www.cyberciti.biz/faq/understanding-etcshadow-file/))

/etc/passwd はユーザーのアカウント情報が記録されている。このファイルの中にはパスワードの記載があるが、xxxx で隠されており、実際のパスワードは /etc/shadow に存在する。([参照記事](https://www.cyberciti.biz/faq/understanding-etcpasswd-file-format/))

unshadow コマンドはその passwd と shadow ファイルを使って必要な情報を John the Ripper が読める形式に変換する。変換したファイルを今度 John コマンドで解析するという手順。

`john --format={format_type_optional} --wordlist={wordlist_path} {file}`

-  Single Crack Mode: 

`john --single --format={format} {file}`
username:hash値 というファイルがあった際に username を word mangling してくれるクラックモード mark というユーザーに対して Mark, mArk , MArk など... 様々なパターンでハッシュ解析する際に適応。利用頻度は低そうだが便利。

- Custom Rule (上級）: 

john.conf というファイルに特定のルールなどを指定することでカスタマイズ化したクラックが可能になる。


-  パスワード保護されている Zip/ rar の Cracking : 

`zip2john {zip_file} > {output_file}`
`john --wordlist={wordlist_path} {output_file}`

パスワード保護されている zip ファイルを zip2john というコマンドでまず John で読み込める形式に変更。
変更した後に通常の john コマンドでワードリストを指定した上でパスワードを抽出が可能。このパスワードを用いて zip を解凍できる。

ちなみに、rar ファイルの場合は rar2john というコマンドで同じパターンで解析可能。
rar ファイルを解凍する場合は unrar e コマンドで。
その他便利なページ
1. https://countuponsecurity.com/wp-content/uploads/2016/09/jtr-cheat-sheet.pdf : John The Ripper Cheat Sheet 

2. https://denizhalil.com/2023/11/02/john-the-ripper-usage-guide/ : John the Ripper Usage Cheat Sheet A Quick Guide
スモールステップ法を用いた、初心者によるAI学習プランの考案

# はじめに
私はAIについて知識がほぼありませんが、AIに関する知識を身に着けて今後のIT業界で生き残っていく力を身に着けたいと思っています。AIを学ぶ上で「はじめてのパターン認識」をおすすめされて半分ほど読み進めましたが、これを学んで実際何に役立つのかが現状では理解できずに学習が止まってしまっています（挫折中）。そこで、年末年始に心機一転、**スモールステップ法を意識して学習方法を模索しプランを立てたい**と思います。

# 対象読者
・AIに興味はあるが、学習ハードルが高くて進めていない方
・AIを学ぼうとしている初心者の考えを知りたい方。

# スモールステップ法とは？
スモールステップ法とは、心理学者スキナーが提唱した「プログラム学習」の5つの原則のうちの一つです。いきなり大きな目標を掲げると、難易度が高く挫折してしまう...といった課題を解決するために、**目標を細分化して段階的に学習していく**方法です。
一度に大きなステップを乗り越えるのではなく、小さなステップを次々に乗り越えていくことで学習に対する心理的ハードルを下げられるということですね。

# 考案したステップ（前半）
ひとまず、「AIの知識を身に着け、実践的な領域に到達すると共に、社内のAI案件に関われるようになる」という大きな目標を達成するために、その目標を小さなステップに分けていきたいと思います。
前半ステップでは、主に**知ることに集中**しています。

### ステップ１：AIエンジニアとはどういったものか知る
現在のAIのエンジニアにはどのような種類・仕事があるのか詳しく知らないため、まずはそこから知っていこうと思います。

### ステップ２：私の会社で、どのようなことをしているのかを知る
そもそも私の会社で何をしているか、なんとなくしか知らないため、前ステップで学んだAIエンジニアにも当てはめて知っていこうと思います。

### ステップ３：私の会社でAIエンジニアになるとして、必要な基礎知識を調べる
AIエンジニアになるためには、数学や機械学習の知識が必要だろうなとなんとなく思っていますが、詳しくは知りません。そこを明確にして、知識を身に着けるべき理由を理解したいと思います。

### ステップ１～３の結果
ステップ１～３を行った結果を極簡単に記します。
##### [ステップ１]　
まずAIエンジニアとは、機械学習やディープラーニングなどの技術を用いて課題解決手順を考え、様々な業務システムにAIの技術を応用する人で、AIエンジニアの仕事としては、「開発」「学習」「分析」の３つに大別されるようです。また、AIエンジニアの職種としても５つに分けられるようでした（省略）。
##### [ステップ２]　
私の会社では上記３種をすべて行っているようで、全てに関わるには幅広く学ぶ必要がありそうです。ただ、現状ではあまりやっていることを理解できず、結局はまず基礎知識を固めていかないと厳しそうだなという結論に至りました。
##### [ステップ３]　
必要な知識は主に４つありそうでした。
・機械学習の際などに使用する「数学（確率・統計・微分積分・線形代数　等）の知識」。
・データ加工等で使用する「プログラミング知識」
・機械学習やディープラーニングの知識
・データベースの知識

# 考案したステップ（後半）
前半では、AIに関する理解を深め、必要な知識を調べました。
私の場合、やはり**まずは基礎知識を学ぼうという結論に落ち着いた**ため、後半ではその必要な知識を学ぶステップを考案したいと思います。
以降のステップに関しては、各ステップで更に細かいステップを作成して取り組むことで学習達成を目指したいと思います（長くなってしまうため、今回はそこまでは記載しません）。

### ステップ４：数学や統計学の知識を学ぶ
[主要な基礎知識]
・確率
・統計
・微分積分
・線形代数
機械学習等を学んだり使用する際に必要となるため、高校レベルの数学の知識はまずある程度は学び直して思い出しておこうと思いました。機械学習を学びながらでもいいのでは？という問いに対しては、分からない部分が多すぎるのに分からない度に調べていくのは大変だと「はじめてのパターン認識」で機械学習をなんとなく学んでいた際に思ったからです。

### ステップ５：機械学習・アルゴリズムの知識を学ぶ
[主要な基礎知識]
・機械学習に関して
最低限数学を学んだら、それを活かして機械学習に関して学んでいこうと思います。これは紹介していただいた「はじめてのパターン認識」が網羅しているため、今度こそは学びきろうと思います。自分なりに学んだ手順をまとめていくことで、アウトプットしつつ学んでいけたらなと考えています。

### ステップ６：プログラミング知識(Python)を学ぶ
[主要な基礎知識]
・Pythonの文法等、基礎部分
・機械学習に使用されるPythonライブラリについて
AIのプログラミングにおいて、Pythonはもっとも一般的な言語のようです。ここは基本的なことを学びつつ、実際のAIのコードを見たり書いたりして学んでいけたらなと考えています。

### ステップ７：データベースの知識を学ぶ
[主要な基礎知識]
・SQLやNoSQLについて
こちらは、データを効率的に扱う上で必要なようですが、ステップ6までの知識を身に着けたうえで、なぜ必要なのか？というところから詳しく学んでいきたいと思います。

### ステップ８：実践（的な学習）
以降のステップは保留として、まずはステップ７までの基礎知識を身に着けて実践領域に踏み入れるようにしたいと考えています。

# あとがき
今後は後半ステップを進めつつ、箸休めにAIに関する情報を適宜調べていきたいなと思っています。AIについて理解を深めた結果、状況が変わったら適宜ステップを更新していきます。学習が終わった際には、結果としてどうだったかも追記できたらと思います。

**(ステップは状況により適宜更新していくのが望ましいです。)**
Tableauのリビジョン管理の対処法

## はじめに

先日、Tableauのワークブックを更新する際にミスをしてしまい、急いで元の状態に戻す必要が出てきました。
Tableauにはリビジョン管理機能があることを知り、無事解決できました。
その時の内容を記事にします。

## 環境

- Tableau Cloud
- Tableau Desktop

## 戻し方の手順

1. Tableau Cloudで問題のワークブックを開く
2. アクションメニュー（「...」）から「リビジョン履歴」を選択
 ![ribi1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/975576/06d138f4-7da5-eaa5-4403-16194201b7fe.png)

3. 履歴一覧から日時を見て、戻したい時点のものを探す
4. 見つけたら「プレビュー」で内容を確認
5. 間違いなければ「復元」をクリック

![ribi2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/975576/9bd088f3-a03e-b862-df95-640ac612b995.png)


## ハマりポイント

タブ付きワークブックを使っている場合、少し厄介な問題があります。プレビューではタブが見えているのに、復元後にタブが表示されないんです。

自分の場合は以下の手順で対処しました：

1. Tableau Desktopで復元したバージョンを開く
2. 「シートをタブとして表示」にチェックを入れる
3. 再度パブリッシュ
![ribi3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/975576/db71ed19-f6b8-8bb0-e766-32c23d9a4415.png)

もっと良い方法があるかもしれません。知っている方がいれば、ぜひコメントで教えてください。

## サポートに問い合わせてみた

この問題について、Tableauサポートに確認を取ってみました。
特に気をつけるべき点として、以下の設定は復元後に再確認が必要とのことです。
残念ながら問い合わせ時点では具体的な作業を纏めた資料は公開されておらず、
それぞれについて調べて対処しました。

- 抽出更新
- メトリクス
- サブスクリプション
- カスタム ビュー
- データ主導アラート

各設定項目の詳細については[公式ドキュメント](https://help.tableau.com/)を参照してください。

## まとめ

今回はバックアップも無い状態だったのでこの方法で修正することができ助かりました。

ただし、復元後の設定確認など注意点も多いので、最新情報を調べたうえで実行することをお勧めします。
GitHubをUbuntuで使おうとしてcloneがドハマりした話

## 目的

Windows10が入ってた中古PCにUbuntuを入れたので、その環境で開発したものをGitHubで管理したくPrivateのリポジトリをgit cloneしようとしてどハマリしました。その備忘録です。

## 環境

参考までに使用しているPCのスペック残します。もとはWindows10機でした。

| 項目 | 詳細 |
|----|----|
| HW | Lenovo ThinkPad-X270 |
| OS | Ubuntu 24.04.1 LTS |
| Processor | Intel Core i5-7200U x4 |

## どハマリした内容

まずはGitHubアカウントでPrivateリポジトリ作成

![GitHub画面1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/9bf2ddfd-96f7-e693-d0b5-796746cb85eb.png)

とりあえずは公開したくないので、Privateのリポジトリを作成。
問題なさそう。。

![GitHub画面2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/dea9f4ef-07ce-b94a-7c13-100e7b1ccc1b.png)

この「Quick setup」をやればいいんだな？とコピーボタン押してtarminalでgit cloneすることに。

↓入力して失敗したコード
```
$> git clone  https://github.com/Username/usernamePrivate.git github
```
「github」という名前のディレクトリ作成してそこにリポジトリクローンしようとしました。
これについては以下通りエラー。。。
```
remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/AnzaiC/chihiroPrivate.git/'
```
Windowsではないからでしょうか。うまく行かない。
GitHubで二段階認証（Autenticator）登録してトークン発行してもうまく行かない。はて。

## 試した内容

HTTPSで接続するのがなんかうまく行かないので、とりあえずSSH接続試すことに。
.sshのディレクトリに入っている鍵を一旦削除して、SSHに必要な鍵生成し直しました。
まずはcdで.sshのディレクトリに移動、以下コマンド実行。

```
$> ssh-keygen -t rsa
```
コマンドのオプションの説明は割愛します。
いろいろ聞かれますがなにもせずそのままEnter。キーペア作成されます（id_rsa  id_rsa.pub）。

その後GitHubのページにもどり、右上の自分のアイコンをクリック、SettingsからSSH and GPG keyをクリック。Authentication Keysに公開鍵（id_rsa.pub）のファイルの中にあるキーをコピーして貼り付け、登録します。

その後はPrivateリポジトリの画面にもどり、「...or create a new repository on the command line」の手順に従ってコマンドを打ち込む。

![GitHub画面2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/dea9f4ef-07ce-b94a-7c13-100e7b1ccc1b.png)

これで！なんとか！
接続できました！！！

別のやり方もあると思うのですが、まずは参考まで。。
アジャイル開発：全体概要とリリース計画について

# はじめに
アジャイル開発をプロジェクトに導入するため、少しずつアジャイル開発のイロハを学んでいる。
現状のプロジェクトに導入するための足がかりとして、学んだことを少しずつ残していこうと思う。

まずは、全体概要と最初のリリース計画について記載していく。

# 概要
アジャイル開発の基本的な流れ
1.	リリース計画 
まず、プロジェクトの大まかな目標と要求を決定します。
 ここでは詳細な仕様は決めず、柔軟性を持たせます。
2.	開発チームの結成
開発チームの結成 通常、プロダクトオーナー、スクラムマスター、開発者といった役割を決めてチームを構成します。
3.	イテレーション（スプリント） 
開発の中心となる反復的なサイクルです。
以下の手順を繰り返します：　
　a. スプリントプランニング：次のサイクルで何を開発するか計画を立てます。 
　b. 実装：計画に基づいて機能を開発します。
　 c. デイリースクラム：毎日短時間のミーティングを行い、進捗を共有します。
　 d. テスト：開発した機能をテストします。
　 e. スプリントレビュー：成果を確認し、フィードバックを得ます。
　 f. レトロスペクティブ（振り返り）：プロセスを改善するための議論を行います。
　　※状況手順は、それぞれ別記事に詳細に記載していこうと思う
4.	継続的な改善 
各イテレーションの終わりに、製品とプロセスの両方を見直し、必要に応じて調整します

# リリース計画
アジャイル開発のリリース計画において、以下の重要なポイントがあります：

1.	柔軟性を持たせる: 
厳密な仕様を決めずに、大まかな仕様と要求のみを決定します。
これにより、開発途中の変更に柔軟に対応できます。
2.	プロジェクトのゴールを設定: 
リリース計画では、プロジェクトで実現したいこと（目標やゴール）を明確にします。
3.	イテレーションの長さを決定:
 開発サイクルの期間を1〜4週間程度で設定します。
4.	ユーザーストーリーの優先順位付け: 
機能や要求の優先順位を決め、重要な機能から着手できるようにします。
5.	スコープの柔軟性を確保: 
リリース日を固定し、スコープに柔軟性を持たせます。
これにより、限られた時間と予算の中で価値を最大化できます。
6.	継続的な更新と共有: 
先々の見通しを常にアップデートし、関係者と共有します3。これにより、プロジェクトの透明性を保ちます。
7.	初期見積もりの位置づけ: 
初期の見積もりを確定的なものとせず、不確実性があることを関係者と共有します。
8.	バッファマネジメントの導入: 
予期せぬ事態に備えて、計画にバッファを組み込みます。
これらのポイントを押さえることで、アジャイル開発の特性を活かしたリリース計画を立てることができます。
9.  チームの構成：
特定されたチームメンバーと関係者（いわゆるステイクホルダー）を明確にします

以上