OmniAICreator/Qiita-1.07M huggingface dataset:
映画「Winny」を通じて学ぶものづくりの尊さとは

おはこんばんちは。

今回はお気持ち表明記事になりますので、技術的な内容は一切書かないつもりです。
あしからず。
とはいえ技術者としてQiitaに書いた方が良いのでは？と思い記事にしました。

映画「Winny」の情報はこちら
https://winny-movie.com/

ティーザーはこちら
<iframe width="560" height="315" src="https://www.youtube.com/embed/qGBtaIPNbuM?si=QOn5OsLK9gcp7S_p" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>


# Winnyとは？

今の若い世代の方はご存知ではない方も多いと思いますので、軽く説明。

従来のデータのやり取りというのはクライアントとサーバーでのやりとりが基本的でして、WinnyはPC同士を直接繋ぐというやり方のP2Pを採用しています。

この技術を応用して取引履歴をつけたのがブロックチェーンの技術でして、現在でもビットコインで使われているものとなります。

Winnyが特にすごかったのはファイルの真偽判定でして、間違ったものを自動的に排除していくというのが、特に優れていたと言われています。

(詳細はたくさんの文献が出ていますし、私もシンプルに伝えることが難しいので、この辺で割愛させてください。コメントお待ちしています。)

# Winnyを通じて何が起きたのか

要はその画期的な技術を作ったのが金子勇さんで、それを使用者に悪用されてしまい著作権侵害の幇助で逮捕されてしまった。というのが事件の発端となります。
詳細や事件の全容はWikipediaなどで詳細に説明されているので、ぜひ一読ください。

https://ja.wikipedia.org/wiki/Winny

https://ja.wikipedia.org/wiki/Winny%E4%BA%8B%E4%BB%B6


# 映画Winnyを見た上での感じたこと。

<font color="red">ネタバレになってしまうので、詳細は出来るだけ割愛しています</font>
とはいえ、内容を知った方でも楽しめる映画となっています！

### 金子さんという天才とそれが理解できなかった世間

当時私もネットを覚えたてのキッズでしたが、連日の報道で「Winnyってソフトは悪いソフトだ！」くらいにしか認識ありませんでしたが、当時の2chの意見と世間の評価は180度違いました。

世間では映画や音楽などのコンテンツを違法にアップロード出来るソフト。としか言われていませんでしたが、金子さんの思想は全く逆で

著作者（発言や表現したい著作物）を匿名という空間であれば攻撃されるリスクを防ぐことができる。という思想の元に着想を始めたというのが発端です。

なので著作権を侵害するわけではなくて、著作者を守るために始めたもの。というのが書かれていました。

ただしそれを悪用してしまった人が大勢いたために金子さんは様々なメディアや世間からバッシングを受けました。

これは世間がよくないのでしょうか。
それとも金子さんが制作した技術は時代に早すぎたのでしょうか。

技術自体はブロックチェーンなどの技術に利用されているので、
今となっては使用者側が悪いという所で結論が出ると思います。

最終的に金子さんは7年の時を経て無罪の判決を獲得しています。
ただし2003年からの7年間は世界中で大幅な技術革新が行われており、日本が遅れてしまった原因のひとつであることは過言ではないかと思います。

### 作りたくても作れない葛藤

何より7年という年月の中で裁判が不利になる為、新しいプログラミングは弁護側から一切止められていました。
それが何より辛かったというのが語られていますし、映画でもその演出がされています。
弁護士の檀さんも一審判定で敗訴し、控訴するか迷った理由は開発行為を止めないといけないのが最大の悩みだったそうです。

それくらい金子さんは技術に触れることが好きだったというのが分かります。

### 技術者としての自己表現

被告人の意見表明にてプログラミングは技術者としての自己表現であると金子さんは法廷で発言しています。
ここまでソフトウェアに対して純粋な心をもって、表現する人は今どれくらいいるのかなと疑問に思いました。それと同時にただ新しいものを作りたい。というピュアな心に目頭が熱くなりました。

もちろん、金子さんが商用のPGではないとも発言をしていますので、それを否定するつもりはありませんが、純粋にただ良いものを品質が高いものを作りたい。という金子さんのマインドは現代における技術者にとって大切な教えなのではないでしょうか。

### 自由にものを公開できる現代

金子さんは自身の開発よりも後世のプログラマーが自由に開発できる前例を作りたかったので、控訴して最終的には無罪を獲得しています。
一審で出た判決が罰金150万なので、裁判の結果を認めれば好きな開発ができたかもしれません。

現在はGithubやSNS、このQiitaですら開発者の技術表現が気軽に公開できる時代になりました。
当時の報道や警察の動きを鑑みるに

1. 言語やライブラリの使い方をWebサイトに載せる
1. それを見た人間が学習し、違法詐欺サイトを制作する
1. 警察や報道が犯罪の示唆をしたとして、使い方を教えたサイトが詐欺幇助の罪に問われる

などといった理不尽を問われた可能性もあったかもしれません。

映画でも語られていますが、包丁職人を罪に問えるのか？という議論がされています。
なのでこういった自由な現代であることに感謝して、のびのびと開発ができるという訳ですね。

### さいごに

今はエンジニアの給与の面とか、働き方とかそういった点にフォーカスがされていると思います。
もちろん働き方などで過去に理不尽な思いを受けた方がいるのは事実なので、否定はしませんが
今の世の中はそういった理不尽な思いを受けた方々のおかげで大幅に改善されています。

ただ、それだけで本当にいいのでしょうか。

日本がIT後進国と言われてしまったのはモノづくりに対して純粋な気持ちが失われてしまったことや、なんだこれ！　すげぇ！　みたいな芸術面みたいな側面が減ってしまったのではないかなとは感じています。

- どうしたら実現可能になるのかな
- これを実装したらユーザーはもっと便利になるな
- この問題はこういった手法で解決してみよう

みたいな純粋な探求心こそが、今の私を含めたIT技術職に求められることではないでしょうか。
私もより一層の勉強と鍛錬が必要なんだなと心に響きました。

駆け出し、ベテランの方、より多くのエンジニアの方に見て頂きたい映画でした。
Netflixやアマプラで観ることができますので、ぜひ！

### あとがき

一時停止して見てなかったのでリーディングはできませんでしたが、ちゃんとXP環境でWinnyの開発言語のC++で書かれていて感動しました（笑）
DBGridで列移動不可で列幅変更ができるようにする

## DBGridで列移動不可で列幅変更ができるようにする

標準のDBGridは、列幅変更ができるようにすると列移動もできるようになってしまうオプションしかない。
列移動はできないが、列幅変更だけしたいときの方法。
オリジナルのソースを弄ります。

１）
Vcl.DBGrids.pas(またはDBGrids.pas)を別のフォルダにコピー。

２）
TCustomDBGrid.SetOptions メソッドの以下の行を変更
dgColumnResize がTrueの時の設定処理
      NewGridOptions := NewGridOptions + [goColSizing, goColMoving];
から、goColMovingをコメントアウト
      NewGridOptions := NewGridOptions + [goColSizing{, goColMoving}];
（XE4だと、３９６５行）

３）
上記ファイルを、オリジナルより先に読むように、path等を設定、または、プロジェクトに追加。

（注意）
元ソースを変えるので、プロジェクト全体が変わることになる。
同一プロジェクトで画面によっては、列移動も可能にしたいという要望があるときはこの方法はＮＧ。

--
別のブログ(今はない)に書かれていたものをQiitaに再投稿したものです。
AWS LambdaをDocker化する際の注意点と学びの備忘録

## はじめに
AWS Lambdaを使ってデプロイするときに、
Dockerイメージを使って、デプロイしたいケースがありました。

すでに、動いているLambdaをLambda Dockerへ変更する際に、
つまずきポイントがあったので、備忘録として、残しておきます

## Lambdaでコンテナイメージを利用とは？

Lambdaには、通常のLambda(ソースコードのみを記述するタイプ)と
Dockerイメージを利用するパターンが存在する
※Dockerイメージは、ECRから参照し、Lambda上で実行が出来る

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747609/161d2b17-1359-8461-61be-afac9ba916b7.png)

### なぜDockerイメージを使うのか？
通常のLambdaとLambda Dockerには、仕様の一部に違う部分が存在している

今回、Lambda Dockerを利用したいと考えたのは、
通常のLambdaよりも、大きいパッケージを展開できる為

●Lambda
50 MB (圧縮、直接アップロード用)
250MB（解凍後）
3 MB (コンソールエディター)

●Lambda Docker
コンテナイメージコードのパッケージサイズ:
10GB

https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html

Lambdaに乗せられる容量が大きければ、
利用したいパッケージが多少大きくてデプロイが可能となる

## 今回Lambda Docker化したい内容

https://qiita.com/UniKawazoe/items/cd39629398b48fad0a25

以前、記事に書き起こしたLINEWORKS BOT用のLambdaに
LangChainを実装したかった為、Lambda Docker化する必要があった

## つまずきポイント1
**LambdaとLambda Dockerのhandlerの宣言方法が異なる**

前回の記事で、作成したLambdaのソースコードをそのまま利用し、イメージを作成
デプロイし、動作確認をしたところ、以下のエラーが発生

```
[ERROR] Runtime.HandlerNotFound: Handler 'handler' missing on module 'lambda_function'
```

通常のLambdaだと、ランタイム設定の中のハンドラという部分で、宣言が可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747609/6f6ecae7-308f-6877-ca73-bf962c81cf25.png)

Lambda Dockerだと、GUI上に宣言部分が存在していない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747609/db4d0dbb-2381-f715-9fa9-5d9466c0bd29.png)


今回、Dockerイメージを作成する際、
AWSが準備しているPythonイメージを利用した

https://docs.aws.amazon.com/lambda/latest/dg/python-image.html#python-image-instructions

上記のドキュメントによれば、lambda_function.lambda_handlerではなく、
handlerと宣言する必要があった

なお、Dockerfile内の以下を調整することで、
lambda_function.lambda_handlerとすることも可能

```
CMD [ "lambda_function.handler" ]
```

:::note warn
Lambda Dockerで、ハンドラの宣言は、Dockerfileの中を確認しましょう
AWSドキュメントのまま、利用する場合は、handlerと宣言しよう
:::

## つまずきポイント2
ECR側で、latestを更新しても、Lambda側のイメージが変更されない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747609/734ea133-414b-fd84-ea22-95bd9dbbbd22.png)

イメージの調整が必要と分かり、再度ECRへpushするが、エラーログに変化が出てこない
なぜ？と試行錯誤し、Lambdaの[新しいイメージをデプロイ]を開き、
そのまま保存をすることで、ログに変化が出ていた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747609/136ef515-374e-b030-58f9-70fcf2cc0d5d.png)

latestとしているので、同じタグが付いているものを引っ張ってきてくれると思っていたが、
キャッシュ？ もしくは、latestと記載しているが、SHAで引っ張ってきているのか、
最新イメージで動作している状態ではなかった

なお、コンテナイメージのベストプラクティスでは、
latestは利用しない方がよいと記載されている

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/container-considerations.html

今回もlatestではなく、バージョンをきちんと振って、
都度デプロイすれば混乱しなかった

:::note warn
Dockerイメージを運用する場合は、latest運用はやめましょう
:::

## さいごに
初めてのLambda Dockerでつまずいたポイントでした
自分が利用するサービス仕様やベストプラクティスは、把握して利用していきたいですね！
それでは、また！
DatabricksノートブックにおけるSQLマジックコマンドの自動挿入

こちらのアップデートです。

https://docs.databricks.com/en/release-notes/product/2024/april.html#notebooks-now-automatically-detect-sql

> SQL以外のデフォルト言語に設定されたDatabricksノートブックでSQLを入力した際に、Databricksノートブックは自動で%sqlマジックコマンドを追加します。以前は、エラーを回避するために手動で%sqlマジックコマンドを追加する必要がありました。

やってみます。Pythonノートブックを作成します。
![Screenshot 2024-05-16 at 7.41.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0e98130b-0c5e-86b9-bbbb-75a444d89e51.png)

`CREATE TABLE`と入力していきます。と、マジックコマンドが挿入されました。便利。
![Screenshot 2024-05-16 at 7.41.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/84904980-276c-4e86-0b77-6c544d20dc26.png)

動画はこちら。
<iframe width="560" height="315" src="https://www.youtube.com/embed/4FXVkEVzcQo?si=IxO0CjDSZntjrHnt" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>



### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
(調査中)logback。java。JUnitでテストコードで、ログレベル変更

JUnitテストコードでLogbackのログレベルを変更することは可能です。Logbackの設定をプログラム内で変更することで、特定のテストケース内でログレベルを調整できます。以下は、その方法を示すサンプルコードです。

## 1. Logbackの依存関係を追加
まず、Mavenプロジェクトの場合は、pom.xmlにLogbackの依存関係を追加します。

```java
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
    <scope>test</scope>
</dependency>

```

## 2. テストコードでログレベルを変更

次に、JUnitテストコード内でLogbackのログレベルを変更する方法を示します。

```java
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.read.ListAppender;

public class LogbackTest {

    private static final Logger logger = LoggerFactory.getLogger(LogbackTest.class);

    @Test
    public void testLogLevelChange() {
        // LoggerContextの取得
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        
        // ルートロガーの取得
        ch.qos.logback.classic.Logger rootLogger = loggerContext.getLogger("ROOT");
        
        // ルートロガーのログレベルを変更
        rootLogger.setLevel(Level.DEBUG);

        // ListAppenderを追加してログをキャプチャする
        ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
        listAppender.start();
        rootLogger.addAppender((Appender<ILoggingEvent>) listAppender);

        // テスト対象のコード
        logger.info("This is an info log message");
        logger.debug("This is a debug log message");

        // ログメッセージの検証
        assertEquals(2, listAppender.list.size());
        assertTrue(listAppender.list.get(0).getFormattedMessage().contains("This is an info log message"));
        assertTrue(listAppender.list.get(1).getFormattedMessage().contains("This is a debug log message"));
    }
}

```

## 動作確認結果

(編集中)

## 解説

LoggerContextの取得

LoggerContextを取得し、Logbackの設定を操作できるようにします。

ルートロガーの取得

loggerContext.getLogger("ROOT")を使用してルートロガーを取得します。
ログレベルの設定: rootLogger.setLevel(Level.DEBUG)でログレベルを変更します。この例ではDEBUGレベルに設定しています。

ListAppenderの設定

ListAppenderを使用してログメッセージをキャプチャし、後で検証できるようにします。

ログメッセージの検証

assertEqualsやassertTrueを使用して、ログメッセージが期待通りに出力されていることを確認します。
この方法を使うことで、テストケースごとにLogbackのログレベルを自由に変更し、ログ出力を検証することができます。
(調査中)Spring MVC コンストラクタ内で例外が発生する状況のモック化

Mockitoを使用してコンストラクタ内で例外が発生する状況をテストすることができます。Mockito-inlineを利用することで、コンストラクタ内で特定の依存関係が例外をスローするようにモックし、その結果としてコンストラクタが適切に例外を処理するかどうかをテストできます。

以下に、例外処理をテストするための具体的な例を示します。

例: コンストラクタ内で例外が発生する状況のモック

---

## コントローラクラス
まず、例外処理を含むコントローラクラスを定義します。

```java
import org.springframework.stereotype.Controller;
import org.springframework.beans.factory.annotation.Autowired;

@Controller
public class MyController {

    private final MyService myService;
    private String message;

    @Autowired
    public MyController(MyService myService) {
        this.myService = myService;
        try {
            this.message = myService.greet();
        } catch (Exception e) {
            this.message = "Error occurred";
        }
    }

    public String getMessage() {
        return message;
    }
}
```
---

## サービスクラス
次に、サービスクラスを定義します。

```java
public class MyService {
    public String greet() throws Exception {
        return "Hello, World!";
    }
}

```
---

## テストクラス
最後に、例外処理をテストするためのテストクラスを作成します。

```java
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class MyControllerTest {

    @Mock
    private MyService myService;

    @InjectMocks
    private MyController myController;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testConstructorExceptionHandling() throws Exception {
        // モックの振る舞いを定義して例外をスローさせる
        when(myService.greet()).thenThrow(new Exception("Service error"));

        // コントローラのインスタンスを作成
        myController = new MyController(myService);

        // コンストラクタが例外を適切に処理しているかをテスト
        assertEquals("Error occurred", myController.getMessage());
    }
}
```

---

## 実行結果

(編集中)

---

## 説明

#### 依存関係の追加:

Mockito-inlineやSpring Testの依存関係は、前述の通りです。

#### コントローラの定義:

MyControllerはコンストラクタでMyServiceを受け取り、そのgreetメソッドを呼び出します。greetメソッドで例外がスローされた場合、クラス変数messageに"Error occurred"が設定されるようにしています。

#### サービスの定義:

MyServiceはgreetメソッドを持ち、例外をスローする可能性があります。

#### テストクラスの作成:

MyControllerTestでMockitoのアノテーション@Mockと@InjectMocksを使用して、サービスとコントローラのインスタンスを作成します。

@BeforeEachメソッドでMockitoAnnotations.openMocks(this);を使用してモックを初期化します。

when(myService.greet()).thenThrow(new Exception("Service error"));でモックの振る舞いを定義し、greetメソッドが呼ばれた際に例外をスローするようにします。

myController = new MyController(myService);でコントローラのインスタンスを作成し、コンストラクタが例外を適切に処理しているかを確認します。

assertEquals("Error occurred", myController.getMessage());で、クラス変数messageが正しく設定されているかをテストします。

これにより、コンストラクタ内で発生する可能性のある例外処理の動作を確認することができます。
robloxでassistant その48

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
マウスクリックしたら、得点を増やせ。

# 手順
- workspaceに、partを追加。
- partに、clickdetectorを追加。
- partに、scriptを追加。
- スクリプトを書く。
```

local part = script.Parent
local clickdetector = part:WaitForChild("ClickDetector")
clickdetector.MouseClick:Connect(function(player)
	local leaderstats = player:FindFirstChild("leaderstats")
	if leaderstats then
		leaderstats.coin.Value += 1
	end
end)

```


以上。
robloxでassistant その47

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
leaderstatsを使え。

# 手順
- ServerScriptServiceに、scriptを追加。
- スクリプトを書く。
```

game.Players.PlayerAdded:Connect(function(player)
	print("入った")
	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"
	local coin = Instance.new("IntValue", leaderstats)
	coin.Name = "coin"
	coin.Value = 100
end)

game.Players.PlayerRemoving:Connect(function(player)
	print("出た")
end)


```

# 写真

![スクリーンショット 2024-05-16 064252.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/58d4c65f-652c-5103-b672-048f00df8cbd.png)


以上。
robloxでassistant その46

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
DataStoreServiceを使え。

# 手順
- ServerScriptServiceに、scriptを追加。
- スクリプトを書く。
```
local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData0")

local function saveData(key, val)
	local success, errorMessage = pcall(function()
		playerData:SetAsync(key, val)
	end)
	if success then
		print("Data saved successfully!")
	else
		warn("Cannot save data for player!")
	end
end

local function loadData(key)
	local val
	local success, errorMessage = pcall(function()
		val = playerData:GetAsync(key)
	end)
	return val
end

game.Players.PlayerAdded:Connect(function(player)
	print("入った")
	local v = loadData(player.UserId .. "-coin")
	print(v)
end)

game.Players.PlayerRemoving:Connect(function(player)
	print("出た")
	local v = loadData(player.UserId .. "-coin")
	if v == nil then
		v = 0 
	end
	v += 1
	saveData(player.UserId .. "-coin", v)
end)




```


以上。
John the Ripper - password crackerが見つからなかったので自分で探してシェルプロファイルに追加した

# 趣旨
Johnが見つからなかったので探してみました。インストールされてないならインストールしてもよかったんですが、インストールはされていたけど、ファイルの置き場がプロファイルに記載されてなくてターミナルから起動できなかったので、解決法を探してみました。

以下のBurp問題と同じ章だったので、この章読み終えるのにめちゃくちゃ時間かかってます。

https://qiita.com/danieltanaka/items/4f216dec76a201f7cd47

# 実行手順
まずは探してみます。
```
locate john | grep bin
```
見つからず。

Linux内でのファイル検索を円滑にするために以下のパッケージをインストールします。

```
sudo apt install mlocate
sudo updatedb
```

次に以下のコマンドでjohnの場所を調べます。
```
find / -name john 2>/dev/null
```

実行結果。
```
/etc/cron.d/john
/etc/john
/usr/lib/john
/usr/sbin/john # これが該当ファイル。
/usr/share/bash-completion/completions/john
/usr/share/doc/john
/usr/share/john
/usr/share/lintian/overrides/john
```

リストを見ただけでは断言できないので怪しいものを実際にターミナルで起動してみるのが良いです。
以下のような場所にあるのが怪しいです。
```
/usr/bin
/usr/local/bin
```

シェルプロファイルにPATHを追加します。
```
nano ~/.bashrc
```
一番下の行に以下の文を追加して閉じます。
```
export PATH=$PATH:/usr/sbin
```

シェルコンフィギュレーションをリロードします。
```
source ~/.bashrc
```
起動してみます。
```
john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
```

完了！

# おまけ
もしrockyou.txtが存在してなければ以下の2つの方法で解決できます。

1つ目。
```
sudo gzip -d /usr/share/wordlists/rockyou.txt.gz
```

2つ目：zipファイルがなければインストール。
```
sudo apt update
sudo apt install wordlists
sudo apt install rockyou
```
インストールされてるかどうか確認。
```
ls /usr/share/wordlists | grep rockyou
```
Laravel Sanctum + React（axios）+ Digest認証（Basic認証）でつまずいた話

# はじめに

表題の通りなのですが、Laravel Sanctum + React (axios)でログイン認証を実装しました。ローカルでは問題なかったのに、検証サーバにデプロイしてDigest認証をかけたところでつまずきました。その顛末を簡単にまとめます。

# 構成

- バックエンド
    - Laravel 11 + Sanctum
- フロントエンド
    - React + axios
- Webサーバ
    - Apache2 + Digest認証
- ブラウザ
    - Google Chrome

# 結論

Google Chromeは401エラーを受け取ると、Authorizationヘッダーの情報を忘れる（認証済み情報がリセットされる）ので、APIログインに失敗し401のレスポンスを受信するとDigest認証（もしくはBasic認証）の認証情報が消えてしまい、認証画面が再度表示される。

# なぜか？

Google Chromeの仕様らしいことを以下のページで知りました。そんな知らんがな。

https://genzouw.com/entry/2020/01/09/120048/1857/

# とりあえずの実装の逃げ

## バックエンド側

認証エラーで401を返していたのを418に変更。

```diff:LoginController
- throw new ActionRuntimeException("Unauthorized.", 401);
+ throw new ActionRuntimeException("Unauthorized.", 418);
```

## フロントエンド側

エラーステータス401のチェックを、418に変更。

ちなみに、エラーステータス418は`418 I'm a teapot`エラーです。詳細は以下をご覧下さい。

https://developer.mozilla.org/ja/docs/Web/HTTP/Status/418

# まとめ

401ステータスが利用出来ないので、401以外のステータスを使わないとGoogle Chromeでは認証情報が消えてしまうという問題によるものでした。他になにか良い対応方法があったら教えてください！
【超簡単】ミスと無駄な作業をこれで解決！毎日リマインドと上司の勤怠を教えてくれるLINE Botを作ってしまった！

## :robot:僕が最近感じたムリ・ムラ・ムダ！
ピチピチの社会人2年目！
小売業界でお仕事をしています、rukqと申します！


1年目の時は自分に必死でなかなか職場での
ムリ・ムダ・ムラに気づくことが少なかったのですが…
2年目を迎えた現在、改善したいことだらけです(笑)

今回改善するのはこの2つ！

+ __毎日の上司の勤怠をワースケに記入したくない！__
+ __今日がイベントのTシャツを着る日なのか分かりにくい！__

この点を改善するべくLINE Botを作ってみました！

## :robot:使用ツール！
+ Make
+ Googleスプレッドシート
+ LINE

## :robot:プレビュー！
https://x.com/oktk_R/status/1790808741061001516

日付を送るとこのように返ってきます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775363/d88cb229-e918-4a7b-88b4-97aad55c4680.png)
決まった時間になるとこのように日付と着るか着ないかを教えてくれます！


## :robot:Makeの構成！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775363/905c2f0b-30b8-7a3a-18cc-9739db96a06c.png)
__非常にシンプルで素晴らしい！！！！！__
上がTシャツを着るか着ないかを毎朝リマインドしてくれるモジュール
下が日付を送ると上司の勤怠が返ってくるモジュール
となっております！

## :robot:リマインドモジュール！
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775363/468aacfe-e3de-855f-32e3-503eb3e95634.png)

今回リマインドするのにあたりGoogleスプレッドシートに記載した内容を送ってもらうのが
一番早いなと感じたのでこのやり方を使用しました！


![タイトルなし1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775363/cef8ba3c-6894-414a-8dab-a5481e34c784.png)


スプレッドシートの中身もシンプルで、日付とTシャツを着るのか着ないのかを入力しました！
ただ、この入力を手打ちで行ったので、今後はこの入力の作業を自動化させていきたいです…

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775363/5dd29c9a-e405-1fe4-29b2-6c8bfa7d0838.png)

LINEの中身はこのような形です！
自分のLINE BotのID入力し、送るメッセージをスプレッドシートの中から選んでます！

## :robot:上司の勤怠を返してくれるモジュール！
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775363/95f4f65c-be12-0dda-ef1e-07d97b9df731.png)


![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775363/5508982e-64c1-1d4d-061a-c987a7a4d241.png)

こちらもGoogleスプレッドシートを利用してシンプルに作ってみました！
LINEで日付を送ることで、スプレッドシートから日付を見つけ出し
それに対応した内容を送り返してくれるようにしています！

![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775363/5e15d181-537e-ad4f-b650-189afdbec315.png)


## :robot:今回の振り返り
今回初めてMakeを利用してLINE Botを作ってみました！
最初はWebAPIを使って複雑な物に挑戦したかったのですが
上手くいかず悩んでいました…
ですが、夜中にシャワーを浴びながらふと気づいたのです！
もっとシンプルにできるということに！
作ってみたらほんとにシンプルになりすぎましたが…
途中でも記述しましたが、スプレッドシートへの記入を手打ちではなく
もっと楽な方法で記入できるようなモジュールを組んでみたいと思いました！

これからもたくさんチャレンジしてみようと思います！
ここまで読んでいただきありがとうございました！

## :robot:参考文献
https://www.youtube.com/live/LjN0VW1bg5w?si=N6sZ2Yel8fNH5vxG

https://qiita.com/88Eqv/items/9ca66d28599b9712b9b9
kintoneのwebhookで削除時もレコードの内容を取得したい

# はじめに

kintoneはアプリの設定で、以下のイベント時にwebhookのURLを叩いてもらうことが可能

- レコードの追加
- レコードの編集
- レコードの削除
- コメントの書き込み
- ステータスの更新

しかし、レコードの編集や削除の際は、変更前・削除前のレコード情報を返してくれないので非常に困る...

https://jp.cybozu.help/k/ja/user/app_settings/set_webhook/webhook_notification.html


# 代替案

同じ内容で困っている人の記事を見つけた。

https://ict4small.com/kintone-webhook-update-delete/

上記を参考に、更新時のwebhookであればレコード情報を返すことを利用できないかと考えた。

# 解決方法

フィールド内に「delete_flag」というフィールドIDでチェックボックスがある想定。

updateのwebhookを削除だけで使えるのであれば不要だけど、そうもいかない状況だったのでフラグで解決することにした。

触られたくないものなのでグループで囲み、初期表示は折りたたんだ状態にしておくスタイル。
（ユーザーの眼に見える箇所へ置くことになるけど、仕方がない...）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116677/a47ed531-d595-18e2-3d31-aaa06ae04c08.png)


そしてjavascriptでカスタマイズ

削除時のイベントの発生時、削除よりも前に更新イベントを発生させて、成功したら後続の処理へ進ませることに成功した。

```javascript
(() => {
  'use strict';

  kintone.events.on(['app.record.index.delete.submit', 'app.record.detail.delete.submit'], function(event){
    return kintone.api(kintone.api.url('/k/v1/record.json', true), 'PUT', {
      "app": kintone.app.getId(),
      "id": event.recordId,
      "record": {
          "delete_flag": { "value": ["ok"] } 
      }
    }).then((resp) => {
      return event;
    }).catch((err) => {
      console.error(err);
    });
  });

})();
```

あとはwebhook側で削除フラグが立っているかを判断して、更新か削除かを切り分ければ良い。

...というゴリ押し方法(´･ω･`)


# おわりに

今回は削除だけ対応すればよかったが、更新時の変更前後を一緒に取る方法はまた別途考えてみたい。

変更前の情報をどこかに持っておくようにフィールドを作成しておけば、「前後で何も変わってない＝削除のイベント」みたいな判断もできそうな気がする。
-no-pieオプション

# ASLRによるセキュリティ強化
ASLRというセキュリティ機能に関係しています。プログラムを実行するたびに各セクションを異なるアドレスにマップするという機能です。これのおかげで、攻撃対象のコードやデータが特定のアドレスに存在することを前提とした攻撃が困難になります。

```-no-pie```オプションを使えばPIEを無効化できます。
PIEを無効化しなかったとすると、/proc/<pid>/mapsの値が実行ファイルに書いてある通りにならなかったり、毎回異なったりしてしまいます。
# 出典
https://gihyo.jp/book/2022/978-4-297-13148-7
# -no-pieがある場合
```
root@***********# ./pause &
[1] 2452
root@***********# cat /proc/2452/maps
00400000-00401000 r--p 00000000 08:05 262192                             *********************************
00401000-00402000 r-xp 00001000 08:05 262192                             *********************************
00402000-00403000 r--p 00002000 08:05 262192                             *********************************
00403000-00404000 r--p 00002000 08:05 262192                             *********************************
00404000-00405000 rw-p 00003000 08:05 262192                             *********************************
....
```
アドレス領域
```00400000-00401000```

# -no-pieを外した場合
```
root@***********# cc -o pause pause.c
root@***********# ./pause &
[2] 2470
root@***********# kill 2452
root@***********# cat /proc/2470/maps
55d554fb5000-55d554fb6000 r--p 00000000 08:05 283952                     *********************************
55d554fb6000-55d554fb7000 r-xp 00001000 08:05 283952                     *********************************
55d554fb7000-55d554fb8000 r--p 00002000 08:05 283952                     *********************************
55d554fb8000-55d554fb9000 r--p 00002000 08:05 283952                     *********************************
55d554fb9000-55d554fba000 rw-p 00003000 08:05 283952                     *********************************
...
```
```55d554fb6000-55d554fb7000```の間のアドレス領域にある
```
root@***********# kill 2470
[2]+  Terminated              ./pause
root@***********# ./pause &
[1] 2943
root@***********# cat /proc/2943/maps
55726ea91000-55726ea92000 r--p 00000000 08:05 283952                     *********************************
55726ea92000-55726ea93000 r-xp 00001000 08:05 283952                     *********************************
55726ea93000-55726ea94000 r--p 00002000 08:05 283952                     *********************************
55726ea94000-55726ea95000 r--p 00002000 08:05 283952                     *********************************
55726ea95000-55726ea96000 rw-p 00003000 08:05 283952                     *********************************
...
root@******# kill 2943
```
```55726ea92000-55726ea93000```の間のアドレス領域にある

# 気づき
確かにアドレスが変わっている。
営業セミナー動画を是非エンジニアにも見せてください

:::note
概要
ユーザ（顧客）に実際に登壇してもらう対話型の営業セミナー動画を視聴しました。
`まるで実際に自分がその現場にいるかのような気持ち`になり、業務理解に繋げることができました！
:::

# 背景

プロダクトのこと、顧客の業務理解ができればもっと良い設計、実装ができるのではと思っていました。

しかしエンジニアが実際に現場に出向きユーザの声を聞くのは難しいのが実情です。

そんな中先日、弊社の営業を統括されている方から営業のセミナー動画を共有して頂きました！
これを視聴した所、顧客の業務理解向上に繋がったのでここにセミナーの概要をまとめます✨

# セミナーの形式
顧客と弊社の営業担当の対話形式でした

# セミナー概要
1時間ほどのボリューム
- 業界における成果を出すための共通のポイント
- 顧客によってプロダクトの使い方、目的が変わるということ
- 顧客の戦略、体制の例
- プロダクト導入前
    - 業務の進め方、そこから出た課題
    - 顧客が実施した改善策
- プロダクト導入後
    - 実際の定量的な効果
    - プラスでできるようになったこと

# コーポレートサイトにある「お客様の声」とセミナー動画で感じた違い

- 勿論コーポレートサイトにも「お客様の声」はあり、プロダクトの効果、ユーザの業務については理解はできます
- 今回のユーザの生の声が聞けるセミナー動画は`まるで実際に自分がその現場にいるかのような気持ち`になり、さらに業務理解に繋がりました
- ユーザの現場の実情、プロダクトの貢献度がよりリアルに伝わる内容でした
- セミナー中に出た質問も実際の現場の悩み等の内容で本当に新鮮でした

# 最後に
- ユーザ（顧客）に実際に登壇してもらう対話型の営業セミナー動画は自社のエンジニアの方にも展開するときっと業務理解に繋がると思います！
- ユーザの戦略、プロダクトの使い方を知れるとよりユーザに寄り添った実装ができると思いました
- セミナー動画を共有してくださった営業の方には感謝したいです✨

本記事を読んで頂き、ありがとうございました。
いいねいただけると記事執筆の励みになりますので、参考になったと思われた方は是非よろしくお願い致します🙏
なにもやってないのにgcloud run deployが通らなくなった

何もやってないっていうときは何かやってんだよなぁー

## エラー概要(読む必要なし)

今までずっと`gcloud run deploy --source`でデプロイが通っていたnode.js環境で、
ある日突然エラーが出て通らなくなった。
リポジトリ上のソースは一切変更なし。

```
ERROR: (gcloud.run.deploy) Revision 'イメージ名' is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information.
```

ポートが開いてないといわれているが、この手のエラーの場合大体ポートは関係ない。

**ログを見に行こう**
⇒何の情報もない同じような以下のログがあるだけ
```
Default STARTUP TCP probe failed 1 time consecutively for container "コンテナ名" on port 8080. The instance was not started.
```

**き・・・きっとビルドのほうでエラーが出てるのさ！**
⇒成功してる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/611b63df-e8f0-8f06-952d-44be2e638905.png)
OMG...

**gcloud run deployの公式ドキュメントを確認する**
https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-nodejs-service?hl=ja
うーん・・・package.jsonの書き方も大体同じだよなぁ・・・
↓公式のpackage.json例
```
{
  "name": "helloworld",
  "description": "Simple hello world sample in Node",
  "version": "1.0.0",
  "private": true,
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "node index.js"
  },
  "engines": {
    "node": ">=16.0.0"
  },
  "author": "Google LLC",
  "license": "Apache-2.0",
  "dependencies": {
    "express": "^4.17.1"
  }
}
```

--snip--
ネット情報や色々彷徨うこと1時間・・・
StackOverflowに同エラー報告あるものの別原因か未解決
--snip--

**ビルダーのドキュメントも見る**
https://cloud.google.com/docs/buildpacks/builders?hl=ja
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/01d16433-0810-d8df-e4ec-432c4cb9b044.png)
ん・・・まさか？
いや、でも公式のpackage.jsonと公式のビルダーでそんなはずは？

**ビルドのログを見直す**

成功時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/a692f0f1-045b-4f1c-de43-ff0c798d6c75.png)


失敗時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/935ea5ad-21ef-80ee-b838-580f682136ac.png)

！！！

## 解決策

package.jsonのnodeのバージョン指定部分をビルダー対応バージョンに変更
```
  "engines": {
    "node": "20.x"
  },
```

## 敗因と言い訳(読む必要なし)

1. 「なにもやってない」はなんかやっている。
(リポジトリのソースは変わらなくてもnpm installでnodeバージョン上がっている)
2. 特にちゃんとしたPJじゃなかったのでdockerfileサボって`--source`オプションでやっていたこと
(でもそれって僕が悪いんですかね！)
3. 公式のpakage.jsonが">="でバージョン指定してるから・・・
4. ビルダーのほうで自分の対応バージョンくらい見てなんかしてくれてもいいじゃん・・・せめてエラーログとかをさ・・・
PHP ぼやき日記 2024-05-15

- [前回](https://qiita.com/sj-i/items/c41f72009d8036b2c43b)

不定期に誰に向けるでもなく PHP に関する雑な殴り書きをしている。気がつけばもう 5 月、そうか、もう 5 月だったか……。

# krakjoe の旦那の生存を確認した
- https://www.reddit.com/r/PHP/comments/1cjlvmd/comment/l3gtj3m/
- PHP コア開発者で apcu や pcov、uopz、parallel の開発者 krakjoe のひとが具合悪くなってしばらく見かけなかったけど、生存が確認された
- ただやはりまだ具合悪いようで、強い鎮痛剤使ってて頭が回らないのでかつてのようには OSS 活動やってくぞという感じでないもよう
- parallel については https://github.com/krakjoe/parallel/issues/290 で [Florian のひと](https://github.com/realFlowControl) にメンテ権限を渡したようなので、PR とか送ると取り込まれると思う

# Property Hooks の提案が通ってた
- https://wiki.php.net/rfc/property-hooks
- 投票はじまってみれば圧勝だった
- PHP 8.4 からはプロパティアクセッサが使えて↓みたいなコードが合法になるし interface にプロパティが生やせる
```php
class Foo
{
    public string $bar;
 
    public string $baz {
        get => $this->baz;
        set => strtoupper($value);
    }
}
```
- hooks の地味にむずいところは readonly 付けたプロパティへ子で hooks 付けたりはできないところ
- まあ大抵の場合[継承なんか使わないほうがいい](https://qiita.com/sj-i/items/2c3d548079522da1b0e9)けど
- 今のところ [Assymmetric Visibility](https://wiki.php.net/rfc/asymmetric-visibility) は含まれてないので、他言語の類似機能を見てる人的には超微妙な物足りなさを感じるかもしれない

# 武田さんが pg_result_memory_size を追加してた
- https://github.com/php/php-src/pull/14214
- pg_ 系のクエリ結果用リソースの消費メモリ量を教えてくれるやつ
- 高町さんとの会話からすると PDO 側にも入れる気があるもよう
    - https://twitter.com/KentarouTakeda/status/1790168364679385561
    - なお高町さんは PHP 8.4 の RM の 1 人で PHP Foundation の雇うコア開発者の 1 人で歌手で声優でこないだ AMPHP のチャットで「複数人が 1 つの名で活動しているのでは？」と疑われていた人

# 俺の PHP プロファイラの近況
- コアダンプの読み取り機能を実装した
    - https://github.com/reliforp/reli-prof/pull/432
    - https://speakerdeck.com/sji/php-dedu-mule-siikoadanpu
    - kubectl debug で k8s クラスタ上で稼働中の pod にアタッチして gcore でプロセス生かしたままコアダンプとって kubectl cp でダウンロードしたやつを解析、みたいなワークフローが個人的には死ぬほど便利
    - もはやこれなしに long running な PHP プロセスとどう付き合っていけばよいのか分からないくらいには役立っている
    - いまの master のコード微妙にバグってるので余裕出たら直したい（手元では修正した版を使っている）
- strip された ZTS バイナリでもブルートフォースで _tsrm_ls_cache をとるコードの PoC が動いた
    - https://github.com/reliforp/reli-prof/pull/451
    - ZTS 環境で各スレッドの EG のアドレスを解決するには TLS シンボル _tsrm_ls_cache のアドレスを解決する必要があり、これは公開シンボルではないため、strip された ZTS バイナリはこれまで Reli で対応してなかった
    - docker 公式の ZTS 版とか frankenphp とかでは strip されたバイナリが使われてる
    - strip されてても使えると便利だけど無理だよなー、と思いながら処理系バイナリのプログラムヘッダを漫然と眺めていたら、TLS ブロックが全体で 0x13c バイトとかしかないのに気づいた
    - それで「これしかないなら 8 バイトずつズラしてブルートフォースで _tsrm_ls_cache と仮定して試しに EG 解決して良い感じに情報取れるか試すだけでシンボル解決しないで見つかるじゃん！しかも一度見つけたらそのバイナリについてはファイルキャッシュできるじゃん！」まで思いついた
    - もはやプロファイラを作っているのかマルウェアを作っているのか分からないが、PoC を実装すると実際に動くので、次のバージョン(0.12.0)に入れたい
ベータテスト - 自分だけのAIニュースレターを作成

皆さん、こんにちは。

私たちのチームは、カスタマイズ可能なAI搭載のニュースダイジェストツール「[TidyRead](https://tidyread.ai?utm_source=qiita)」を開発しました。お好きなRSSフィードを購読し、毎日指定した時間にパーソナライズされたダイジェストを受け取ることができます。さらに、サマリープロンプトをカスタマイズして、AIが高品質なコンテンツサマリーを生成できるようにします。今月中に不要なコンテンツをフィルタリングするAIフィルターのサポートを予定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3793311/258201e7-400d-b0d1-2429-4c164204a996.png)

さらに、TidyReadはグループ機能をサポートしており、各グループごとに異なるRSSフィードとサマリープロンプトを購読し、配信時間を設定することができます。😇

ご興味のある方は、2分ほどで記入できるアンケートにご協力ください：[リンク](https://tally.so/r/3qdLZd?utm_campaign=beta_testing_1) 。今週中にベータテストの招待メールを送信し、1,000,000トークンをプレゼントします。

チームメンバーと近距離で接触し、高品質な情報を愛する仲間と交流したい方は、ぜひ私たちのDiscordにご参加ください：https://discord.com/invite/W6SBpcYmAw

ご質問やご意見がありましたら、コメント欄でお知らせください！！
iOS Simulator で Loaded CoreSimulatorService is no longer valid for this process のエラーが出た時の解決方法

# これなに
CoreSimulatorService がも使えないよと言われた時の対応方法

# エラー内容
Simulator 起動しようと思ったらこんなエラーが
```zsh
Loaded CoreSimulatorService is no longer valid for this process.
Simulator services will no longer be available.
Error=Error Domain=NSPOSIXErrorDomain Code=61 "Connection refused" 
UserInfo={NSLocalizedDescription=CoreSimulator.framework was changed while the process was running.
This is not a supported configuration and can occur if Xcode.app was updated while the process was running.
Service version (947.17) does not match expected service version (947.13).}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819748/9ec845b1-75bd-3901-870e-6d3eb2f4f07d.png)

# 解決方法
とりあえずキャッシュ吹っ飛ばしたら解決しました。
[以前書いた記事](https://qiita.com/su3-hokkaido/items/dd4e44a4680140e6d49b)と同様に以下のコマンドを実行して解決。
```zsh
rm -rf ~/Library/Developer/CoreSimulator/Caches/*
```
アクセルキャンプ復習動画５－１５　Roblox Lua ブロックを大量に複製しよう

皆さんこんにちは

今回は大量にブロックがふってくるスクリプトを組みます。

クローンという英語を知ってますか？そう、クローン人間とかのあれです、コピーです。


```lua
local original = script.Parent.original_block

while true do
	wait()
	local clone = original:Clone()
	clone.Parent = workspace
end
```

workspace家の養子にしてあげましょう。

whileという繰り返し構文を使って無限に出しちゃいましょう。

ここでwait()を入れないと、パソコンによっては大変なことになるので、必ず入れましょう。
スクラムフェス新潟2024に現地参加してきた！

2024年5月10日～11日の間開催されたスクラムフェス新潟2024に現地参加してきました！参加した感想を残します。

◇目次  
[参加した背景](#参加した背景)  
[目的](#目的)  
[目当ての講演](#目当ての講演)  
[参加した感想](#参加した感想)  
[最後に](#最後に)


<a id="参加した背景"></a>
#### ◇参加した背景
・昨年オンラインで参加して、次は現地参加してみたいと思ったため  
・いろんな人と交流して、心の栄養補給をしたかったため

<a id="目的"></a>
#### ◇目的
・自分のモチベーションアップの種を得る  
・仕事への還元できる何かを得る（今年の業務に活かす）  
・チームについての学びを得る  

<a id="目当ての講演"></a>
#### ◇目当ての講演
・[The Boundaries of Testing / テストの境界](https://confengine.com/conferences/scrum-fest-niigata-2024/schedule/rich#session-31801-info)  
・[バリュープロポジションキャンバスを使って、しごとの「もやもや」を「ほっと」にするワークショップ](https://confengine.com/conferences/scrum-fest-niigata-2024/schedule/rich#session-31794-info)  
・[固い組織文化の中で、２年間で組織的に学習/発信する文化を根付かせたアジャイルトランスフォーメーションの方法について](https://confengine.com/conferences/scrum-fest-niigata-2024/schedule/rich#session-31806-info)  

<a id="参加した感想"></a>
#### ◇参加した感想
オフラインで参加し、現地の雰囲気や熱量を肌で感じて思ったことがたくさんあります。  
自分は、何も持ってないエンジニアなのだなと、痛感しました。組み込み業界の大きな事業会社の製品づくりの一部に組み込まれた、歯車でしかないと、特に感じました。  
半径２メートルくらいの人たちと、アジャイル開発みたいなことをやっているけど・・・  
お客様に価値を届けられたか？、ペインを取り除けていたか？と問われると、お客にアクセスすらしていなかったので何も解決できていませんでした。  
所詮は、イテレーティブな開発をして、うまくできたことを自分たちで満足しているだけだと気づかされました。

自分が何を成したか、どんなことができたかを話せるまでは、現地参加は控えようかなと思いました・・・

いろんな人と話したいと思いましたが、相手から学んでばかりでは、相手の時間を奪ってしまう行為だなと気づいてから、話しけるのが申し訳なくなってしまいました。

Give & takeできるように、自分たちの経験値（挑戦と失敗）をもっともっと、積まないといけないと思いました。
もっと仕事頑張ります・・・！

ただ、ワークショップに参加して、本当にとてもよかったです。  
本当にもやもやを解消するためのきっかけになりそうだなと思いました。  
今回の参加で感じた個人のもやもやを晴らすのに、タイムリーに使えるの、やってみようと思います。  
Piroさん、さてぃさん、ありがとうございます！

<a id="最後に"></a>
#### ◇最後に
泊りのオフラインのイベントに、送り出してくれた家族（特に妻）に感謝です。**本当にありがとう**！  
とても良い学びを得られたので、日々の業務で**ユーザーの価値**を求めて、努力し**Outcome**を求めていきたいと思います！
Perlプログラムによるperplexity.ai利用

つい数十時間前に、[chatGPT](https://openai.com/chatgpt/)のバージョンが[上がり](https://openai.com/index/hello-gpt-4o/)、世間が賑わっているようだ。
そんなわけで、私もその賑わいに参加すべく、Perl言語を手に取った。
APIを叩いて音楽を奏でようと思う。

# [www.perplexity.ai](https://www.perplexity.ai)利用。
久しぶりのPerl言語を触るのだが、騒ぎに乗じないのもどうかと思うため、APIを発行して、動かした。

## 想定と結果
APIを使った結果と普通に検索した結果が同じ結果と思っていた。
しかし、違った。

以下、通常の検索結果。
![www.perplexity.aiでの検索結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425551/6916a9be-2fba-51f6-6a15-68e5b24e5248.png)

以下、APIを叩いた結果。
![apiを叩いた結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425551/e90a19de-1d54-a654-395f-cfdbfa60b9c8.png)

APIを叩く方法は、openAI用のAPIなのか分からないが、インターネットを検索した結果のように見えない。
かなり簡素なのはさみしい。
せっかくなけなしのクレジットカードを登録しているのに、こんな結果になってしまうのか・・・。

## Perlプログラム。
選んだモデル(**llama-3-8b-instruct**)が原因か？

```perl
use strict;
use warnings;
use LWP::UserAgent;
use JSON;
use utf8;

binmode STDOUT, ':encoding(UTF-8)';

my $url = "https://api.perplexity.ai/chat/completions";

my $payload = {
	"model" => "llama-3-8b-instruct",
	"messages" => [
		{
			"role" => "system",
			"content" => "日本語での返答は日本語を使うこと。"
		},
		{
			"role" => "user",
			"content" => "日本語で自己紹介をしてください。"
		},
	],
	"temperature" => 0,
	"top_k" => 50,
	"return_citations" => 1,	# true
	"return_images" => 1,	# true
	"stream" => 0,	# false
	"presence_penalty" => 2,
};

my $json_payload = encode_json($payload);

my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(POST => $url);
$req->header('accept' => 'application/json');
$req->header('content-type' => 'application/json');
$req->header('authorization' => "Bearer $ENV{'PERPLEXITYAI_API'}");
$req->content($json_payload);

my $response = $ua->request($req);

if ($response->is_success) {
	my $content = $response->decoded_content;
	my $json = decode_json($content);
	my $message_content = $json->{choices}[0]->{message}->{content};

	print $message_content;
} else {
	print "HTTP POST error: ", $response->status_line, "\n", $response->content;
}
```

上記のプログラムで、APIキーを設定する箇所は、`'authorization' => "Bearer $ENV{'PERPLEXITYAI_API'}"`にある環境変数(**PERPLEXITYAI_API**)から取得させている行が該当箇所になる。
当然のことだが、APIキーは、さらすものではないため、プログラムにべた書きしないこと(今回のように、プログラムを公開するときなどに削除作業が不要なので便利と言うこと)。


## 支払い金額。
クレジットカードを登録するだけでは使えず、チャージする必要がある。
そのチャージ額がなくなったときに支払いが止まるため、懐ぐらいの寂しい私にはうれしい仕様だと思う。

![pay.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425551/5d94e042-dfe3-e26a-1384-c4982c5e9389.png)

1時間以上APIを叩きまくったが、1ドルどころか、~~1セントにもならない~~ようだ(現在6セントだよ)。
[Pricing](https://docs.perplexity.ai/docs/pricing)ページを確認するが、**1M tokens**で20セントかかるため、今回の3倍APIを叩く必要があるようだ。
私としては結構な回数叩いたつもりだったが、文字数が少なかったため、今回の金額で収まっているはず。
使いこなす場合は、跳ね上がるだろう。

## 余談
プログラム実行後の文字列末尾に`%`記号がしがみついている。

![パーセント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425551/93c5d8d8-4b4d-4465-2e2a-44a90ba53767.png)

これは何？


何にせよ、同じ阿呆なら踊らにゃ損損。
以上。
開発担当者がチームリーダーに任命されたときに行ったこと

## 背景

新卒で今の会社に入社して半年ほどは、担当者としてOJTで仕事を進めていました。
OJTが終わると、サブリーダー兼開発担当者として、システムの設計、開発・改修、テストなどを行ってきました。
また、サブリーダーとして要件定義やユーザー、他チームとの打ち合わせでリーダーの補佐をしていました。
5年ほどサブリーダーとして働いていましたが、部長主導の下で部の人員の役割変更が行われ、チームリーダーはシステム担当から部やグループ全体のシステム管理を担当する立場になり、若い世代（20代後半から30代）の人がチームリーダーになる世代交代が行われました。

## チームリーダーとしての役割

チームリーダーに任命された後、私に課せられた役割は以下の通りです。

- 担当システムの最終責任者
- 担当システムに割り当てられている人員の管理
- 他チームやユーザーとの打ち合わせ
- システム改修・開発の要件定義や見積もりなどの担当システムに関する事務作業

## 課題

チームリーダーの役割を果たすにあたり、私には以下の課題がありました。

- 人員管理の経験がない
- コミュニケーション能力が不十分

人員管理は、今までの開発時と同様にタスク管理を自分だけでなくチームメンバーの工数も含めて管理することで、
最初は時間がかかりましたが、すぐに対応できるようになりました。

ただし、私はコミュニケーション能力が低いという問題がありました。
人見知りしやすく話すのが苦手なので、ユーザーヒアリングやチームメンバーへの指示で誤解が生まれないように次のことを行いました。

## チームリーダーになって行ったこと

### Team Geekの読書

チームリーダーになってまず行ったことは、「Team Geek」を読むことでした。
先輩や友人に相談すると、「Team Geek」を読んでHRT（謙虚・尊敬・信頼）の原則を意識すれば何とかなると言われました。
そして、HRTを意識したコミュニケーションをとるようにしました。
また、自分がサブリーダーの時よりもチームとの打ち合わせでは、話せる範囲で情報を共有し、より透明性があるようにしました。

### 透明性のあるコミュニケーション

透明性のあるコミュニケーションを心がけるために、以下のことを行っています。

- 共有できる情報は、なるべく公開する（ただし、情報の取捨選択は行う）
- 話を遮らずにメンバーの話を聞き、その後に意見を言う
- 重大な案件や難しい案件の場合、メンバー全員で意見を出し合ってまとめる。一回で決まらない場合、時間を区切って各自で考え、再度集まって議論する
- 複数の意見が出た場合、それぞれのメリット・デメリット・コストを出し合い、最終的にリーダーとして私が決める

一言で言えば、メンバーと話してメンバーの前でリーダーが決定したことを強調するようにしています。
リーダーが決定したことを示すことで、メンバー間でリーダーが知っているのかや、リーダーと違う動きをしているのではないかといった疑問や確認のコストを減らすようにしました。
また、リーダーがその決定をしたプロセスも見えるようにしました。

## 現状

HRTや先輩の意見を聞きながらチームリーダーの仕事をすることで、時間はかかるもののユーザーとの打ち合わせも主導して行えるようになりました。
最先任のメンバーに補助されながらですが、チーム管理もできるようになりました。
Universal Dependencies 2.14リリース

[Universal Dependencies 2.14](http://hdl.handle.net/11234/1-5502)がリリースされた、との連絡をいただいた。[半年前のUniversal Dependencies 2.13](https://srad.jp/~yasuoka/journal/665185/)と較べて、Abkhazian、Azerbaijani、Bavarian、Cappadocian Greek、Egyptian (Ancient)、Gujarati、Hausa、Latgalian、Luxembourgish、Maghrebi Arabic French、Ottoman Turkish、Paumarí、Tswanaが増えており、161の言語にまたがるツリーバンクとなった。[古典中国語(漢文)](https://universaldependencies.org/lzh/)に関しては、私(安岡孝一)のグループが製作している[UD_Classical_Chinese-Kyoto](https://github.com/UniversalDependencies/UD_Classical_Chinese-Kyoto)に加え、テュービンゲン大学のグループが[UD_Classical_Chinese-TueCL](https://github.com/UniversalDependencies/UD_Classical_Chinese-TueCL)の製作を開始した。

![TueCL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428317/a144a46b-4d09-2c99-ed00-de3a67829201.png)


なお、先月時点での係り受け解析ツールの状況を『[Universal DependenciesとBERT/RoBERTa/DeBERTaモデルによる多言語情報処理](http://kanji.zinbun.kyoto-u.ac.jp/~yasuoka/publications/2024-04-30.pdf)』(2024年4月版)にざっとまとめておいたので、参考にしてほしい。
【VSCode】Jupyterノートでセルを実行するショートカットが効かない

# 何に困ったのか？
VSCodeでJupyterノートを実行できるようにした。
その後、キーボードショートカットで実行しようとしても、実行されなかった。

# 原因
セルを実行するためのショートカットが2種類あり、古いほうのショートカットを押していた。

# 環境
OS: Zorin OS 17.1

Zorin OS = ubuntuをベースにしたLinux distribution
他のLinuxでも同様の現象が発生すると思われる

# 詳細
### 最初に試みたこと
キーボードショートカットの設定画面をVSCode上で開いて、 "jupyter.runcurrentcell"の項目を見た。
Ctrl+Enterが登録されていたので、試してみるが実行されない。
普通に改行が入力されるだけ。

### 解決方法
情報を見つけた。
https://github.com/microsoft/vscode-jupyter/issues/4377

この記事によると、"jupyter.runcurrentcell"は古い項目らしい。
"notebook.cell.execute"が新しいらしく、見てみると、デフォルトでSuper+Enterとなっていた。
Ctrl+Enterを登録してやると、その通りに動いた。

操作については、キーボードショートカットの設定画面は、コマンドパレットでそれっぽいのを開くか、Ctrl+K,Ctrl+Sを押す。
"notebook.cell.execute"を検索すると早い。項目を見つけたらダブルクリックして設定したいキーを登録する。
**古い**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627213/d7aabfca-2142-ef28-964d-c352b3362eb2.png)
**新しい**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627213/bf7546db-d380-c6a7-040c-eb588833a3c1.png)

(※記事を書いてるのがWindows環境なのでWindows版VSCodeのスクショを使用しています。)


**keybindings.json用のJSON形式↓**
```json
    {
        "key": "ctrl+enter",
        "command": "notebook.cell.execute",
        "when": "notebookCellListFocused"
    },
    {
        "key": "ctrl+alt+enter",
        "command": "-notebook.cell.execute",
        "when": "notebookCellListFocused"
    }
```
(ちなみに自分は"-notebook.cell.execute"がなぜ必要かよくわかっていません。助けて詳しい人)

### なぜ最初に気づけなかったのか
"notebook.cell.execute"に当たる項目は、キーボードショートカットの設定画面では日本語名でのみ表示されていたから。
英語で適当に"jupyter"やら"notebook"で検索しても出てこなかった。
最初からkeybindings.jsonを開いていたらもっと早く気づけたかもしれない。


# 蛇足
始めてQiitaの記事を書いたので、分かりにくかったらごめんなさい。
ただ、この情報はネットを見てもあまり見つからなかったので、書いておこうと思いました。
せっかくVSCodeの環境を整えたのに思ったように動かなくてモチベが下がってしまった、自分のような人間がこれ以上生まれませんように・・・。
【React】記述量によって高さが変動するtextarea

以下のように記述することで内容に合わせてtextareaの高さを自動で変更できます。

```tsx:Textarea.tsx

export default function TextArea() {
  return (
    <textarea
        onChange={(ev) => {
          ev.currentTarget.style.height = 'auto'
          ev.currentTarget.style.height = `${ev.currentTarget.scrollHeight}px`
        }}
    />
  )
}

```
CISCO機器でのインターフェースエラーの対応について

### はじめに
CISCOのNW機器でインターフェースエラーが発生した際の原因と対処について簡単ですがまとめました。
障害切り分け時の参考となれば幸いです。
### 前提
 Ciscoルータやスイッチ
 

### インターフェースエラー時の対処について
まず対処方法の一つとして、対象のインターフェースを手動でshutdwon(閉塞)、no shutdown(解放)としすることでエラーを解消させる方法について記載します。

まずインターフェースの状態を確認します。
インターフェースの状態を確認するコマンドはいくつかありますが、今回は「show interface status」で確認します。
```
  Switch# show interface status
```
※コマンドの省略が可能です「sh int status」など

出力されるログの「Status」欄に「err-disabled」という表示があればそのインターフェースは
エラー状態にありインターフェースがshutdown(閉塞)している状態となります。

この「err-disabled」を解除するには以下の手順を行います。
ここではGigabitethernet0/1がerr-disabledとなっている状態とします。
以下の手順では特権モード(configer terminal)に入り、さらにインターフェース設定モードに入って操作します。
※以下の手順は一時的に対象のポートをshutdown(閉塞)しますので、対象ポートを間違えないように注意してください。
```
  Switch#configuer terminal
  Switch(config)# interface Gigabitethernet0/1
  Switch(config-if)# shutdown
  Switch(config-if)# no shutdown
  ※設定後はexitで各モードを抜けてください
```
再度「show interface status」でインターフェースの状態を確認して、先ほど「err-disabled」となっていたインターフェースが「connect」となっていれば正常の状態に戻っています。

### インターフェースエラーの原因について
一時的なエラーであれば上記の手順で復旧できると思いますが、エラーによっては上記の手順を行うだけではまたすぐに「err-disabled」の状態に戻ってしまうことがあります。
その際にはエラーとなる原因の切り分けを行う必要があります。
以下にいくつかインターフェースがエラーとなる原因を記載します。
・ケーブルの不良
・インターフェースの不良
・BPDUガード
・UDLD（単方向リンク検出）
・EtherChannelの設定ミス
・speed/duplexのミスマッチ
など

各エラーの見分け方としては、機器のログの確認やステータスを確認する必要があります。
・EtherChannelの設定ミス
・speed/duplexのミスマッチ
こちらは設定のミスによるものですので、インターフェースの設定(channel設定やspeed/duplex)が対向のインターフェースの設定と揃っているか確認する必要があります。

また、フラッピングのログやFCSエラーが増えている場合は、物理的な不良やネットワークデバイスに不良が生じている可能性があるので、以下が原因である可能性があります。
・ケーブルの不良
・インターフェースの不良
ケーブルの差し替えや、インターフェースの差し替えを行い原因個所を切り分ける必要があります。

BPDUやUDLDによってポートがerr-disabledにされた場合はログが出力されています。
ログを確認し、物理接続や設定を確認してください。
・BPDUガード
・UDLD（単方向リンク検出）
### まとめ
インターフェースのエラー原因は今回記載した以外にもあり、ログやステータスを確認しそれぞれ適切に対処する必要があります。
今後、各エラーの確認手順や復旧手順についても記載できればと思います。

### 参考サイト

https://www.infraexpert.com/study/catalyst27.html#google_vignette

https://www.cisco.com/c/ja_jp/td/docs/sw/lanswt-access/cat4500swt/cg/006/confg-gd-book/connect.pdf
how to load nginx module

## Install
```shell
nginx -V 2>&1 | tr -- - '\n' | grep _module
sudo apt install libnginx-mod-http-image-filter
ls /etc/nginx/modules-*
```

## Load module

```conf
# nginx.conf
load_module modules/ngx_http_image_filter_module.so; 

```

## conf

```conf
# app.conf

location /img/ {
  image_filter resize 240 360;
  image_filter rotate 180;
  image_filter_buffer 16M;
}
```

---

Ref:

https://ubuntu.com/server/docs/how-to-use-nginx-modules

https://packages.ubuntu.com/search?keywords=libnginx-mod-http-geoip

http://nginx.org/en/docs/http/ngx_http_image_filter_module.html

http://nginx.org/en/docs/http/ngx_http_geoip_module.html

https://juejin.cn/post/7270871863162044472
アルゴリズムをはじめようを読んで

## 読書理由
・計算量を意識した実装ができるようになるため

## 学んだアルゴリズム
#### 二分探索法
データを探す探索あるアルゴリズムの1つ。昇順か降順に整列されているデータを対象に、探索する範囲を半分に絞りながら探索を進める。

#### クイックソート
データを並べ替える整列アルゴリズムの一つ。データを大小のグループ2つに分割ながら全体を整列させる。実行速度が速い。

#### エラトステネスふるい
素数を見つけるアルゴリズム。ある数の平方根より小さい素数の倍数を削除していき、残った数が素数になることを利用している。

#### ユークリッドの互除法等
2つの数の最大公約数を求めるアルゴリズム

## PHPでの利用
・PHPの標準関数のsort()は内部ではクイックソートのアルゴリズムが使用されているとのこと。
https://www.php.net/manual/ja/function.sort

## 感想
・基本的なアルゴリズムのうち、いくつかを流れ図と疑似言語で学び、イメージを掴むことができた
・今後は自分で実装する時も、言語で用意されている標準関数を利用する時も、内部でどのようなアルゴリズムが使われているを意識していく
Android用のiperf3

## About this

Android用のiperfバイナリを作成する機会があったので手順を記載したもの。

## Prerequisites

- Docker
- adb

## Build

Dockerfileを作ってビルドを実施した。
作成したイメージの中にiperf3のバイナリファイルができているので、イメージ作成後、docker cpで取得する。

```shell: コマンド
$ mkdir work
$ cd work
$ vi Dokerfile ## 下のほうに記載している内容のファイルを作成する
$ docker buildx build --no-cache -t iperf:3.17.1 --load 3.17.1
$ docker run -d -t --name iperf3 iperf:3.17.1
$ docker cp iperf3:/iperf/src/iperf3 .
$ docker rm -f iperf3
$ docker rmi iperf:3.17.1
```


## Usage

作成したiperf3バイナリファイルは、adbコマンドでandroid端末に転送し、adb shellコマンドで端末にログインしすることで操作できる。

```powershell: コマンド
PS> adb push iperf3 /data/local/tmp/
PS> adb shell
(Android)# cd /data/local/tmp
(Android)# chmod 777 /data/local/tmp/iperf3
(Android)# ./iperf3 -version
```

:::note info
adbコマンドがない場合は、インストールする

```powershell: コマンド
PS> winget install Google.PlatformTools
```
:::


## Dockerfile

```Dockerfile: Dockerfile
FROM ubuntu:24.04

RUN apt update
# for Android NDK
RUN apt install -y unzip binutils wget
# for iperf build
RUN apt install -y git make file wget

# Install Android NDK
# 
# Please specify the optimal NDK version from following URL.
# https://developer.android.com/ndk/downloads
WORKDIR /
RUN wget -q https://dl.google.com/android/repository/android-ndk-r26d-linux.zip && \
    unzip android-ndk-r26d-linux.zip

# Clone iperf
WORKDIR /
RUN git clone https://github.com/esnet/iperf && \
    cd iperf/ && \
    git checkout -b 3.17.1 refs/tags/3.17.1

# Patch
# https://github.com/esnet/iperf/pull/1687
WORKDIR /iperf/
RUN git remote add patch https://github.com/tqfx/iperf && \
    git fetch patch && \
    git cherry-pick -n 6f1e96ffe230b38efcf92856bfd9535279c93586

# Build
WORKDIR /iperf/
ENV PATH="${PATH}:/android-ndk-r26d/:/android-ndk-r26d/toolchains/llvm/prebuilt/linux-x86_64/bin/"
# Please check API level.
# https://developer.android.com/guide/topics/manifest/uses-sdk-element?hl=ja#api-level-table
RUN ./configure --host=aarch64-linux-android CC=aarch64-linux-android30-clang CXX=aarch64-linux-android30-clang++ CFLAGS=-static CXXFLAGS=-static
RUN make
RUN file src/iperf3
```

:::note info
**Android NDK Version**
- android-ndk-r26d-linux.zipを使用したが、下記から適切なversionを指定する
- https://developer.android.com/ndk/downloads
:::

:::note info
**API level**
- 使用するデバイスに対応したものを使用する(今回はandroid30を使用した)
- https://developer.android.com/guide/topics/manifest/uses-sdk-element?hl=ja#api-level-table
:::

:::note info
**patch**
- Commit: 6f1e96ffe230b38efcf92856bfd9535279c93586
- iper v3.16から-P/--parallelオプションがサポートされた([PR#1591](https://github.com/esnet/iperf/pull/1591))影響で、build時にpthreadsが必要となったが、Android NDKを使ったbuildに失敗する事象([Issue#1641](https://github.com/esnet/iperf/issues/1641))が出ていた
- [PR#1651](https://github.com/esnet/iperf/pull/1651)で修正コミットがマージされているが、この修正でもエラーが解消されてないようで、追加の[PR#1687](https://github.com/esnet/iperf/pull/1687)がでており、v3.17.1にはマージされていなかったためcherry-pickした
:::
フォルダの階層構造の図をテキストで表現するツールのメモ

こういうフォルダの階層をテキストで表現しているやつをよく見かけるので、記事を書く際に同じように書く方法を調べた備忘録として残す
```
.
└── simplechatpage/
    ├── static/
    │   └── logo.png
    ├── templates/
    │   └── index.html
    └── app.py
```

# VSCodeの拡張機能
Ascii Tree Generatorという拡張機能

https://marketplace.visualstudio.com/items?itemName=aprilandjan.ascii-tree-generator

こういうテキストを書けば一発変換してくれるツール
```
# simplechatpage/
## static/
### logo.png
## templates/
### index.html
## app.py
```

VSCodeの中で完結させたい場合はこっちがよさそう

# tree.nathanfriend.io
Web上のサービス

https://tree.nathanfriend.io/

タブでインデントを調整しながら書くタイプ。シンプルで使いやすいです。
VSCodeにごちゃごちゃ混ぜたくないって人はこっちがよさそう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/c3e947f9-7341-62fa-b763-3242f5026760.png)
.gitignoreファイルに記載のファイルが除外されない

## 本日のお悩み
既に作成済みの.gitignoreファイルに記載したファイルが、除外されない

## 本日の処方箋
**コマンドラインのVimで修正する**
詳しいやり方は長くなりそうなので割愛。下記参考記事に全て記載。超わかりやすいです。

https://ticklecode.com/gitignoreupdate/#%E6%89%8B%E9%A0%862%E7%B7%A8%E9%9B%86%E3%83%A2%E3%83%BC%E3%83%89%E3%81%AB%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88%E3%82%8B
【Laravel】timestampとdatetimeの違い

# 型の違い
`timestamp`と`datetime`は両者とも日付と時刻を扱うデータ型だが、用途に違いがある。

〇結論
`timestamp`：UTCベースの一貫性が重要な場合に最適。
`datetime`：特定のローカルタイムをそのまま保存する必要がある場合に最適。

## 1.格納方法と範囲
✧timestamp
・範囲
`1970-01-01 00:00:01 UTC`～`2038-01-19 03:14:07 UTC`
・格納方法
UTC（協定世界時）に基づいて格納され、DBのタイムゾーン設定に応じて表示される。
・自動更新
MySQLでは`timestamp`型のカラムはでデフォルトで自動的に現在のタイムスタンプを設定したり、更新できる。

✧datetime
・範囲
`1000-01-01 00:00:00`～`9999-12-31 23:59:59`
・格納方法
ローカルタイムゾーンで格納され、データベースのタイムゾーン設定に影響されない。
・自動更新
MySQLのdatetime型はデフォルトでは自動的に現在の日時を設定したり更新したりすることはできないが、トリガーやアプリケーションロジックを使って同様の動作を実現することは可能。

## 2.タイムゾーンの取り扱い
✧timestamp
・タイムゾーンを持たない環境でもUTCとして扱われる
・DBが異なるタイムゾーンに移動しても、同じUTC時刻を保持し、クエリを実行する環境のタイムゾーンに合わせて変換される。

✧datetime
・タイムゾーンに非依存で、格納された値がそのまま表示される。
・タイムゾーン情報を持たないため、異なるタイムゾーンに移動しても格納時のローカルタイムとして解釈。

## 3.使用ケース
✧timestamp
・DBのサーバータイムゾーン設定に基づいて時刻が変わる可能性があるため、グローバルに一貫した時刻を保持したい場合に使用。
・ログやイベント記録、トランザクションのタイムスタンプなど、UTCに基づいた時刻管理が重要な場合に適している。
✧datetime
・固定された時刻を保持したい場合に使用。特定のタイムゾーンの日時をそのまま保存する必要がある場合に適していいる。
・将来のイベント予定やスケジュール管理など、具体的な日時をそのまま保持する必要がある場合に使用される。