OmniAICreator/Qiita-1.07M huggingface dataset:
【Web】Cookie、セッション、キャッシュとは

どれもサイトを閲覧したときの情報を保存するものですが、仕組みやデータの内容が異なります。

[Cookie](#Cookie誰が)
[セッション](#セッション何をしたか)
[キャッシュ](#キャッシュページの情報)

# Cookie「誰が」
Cookie（クッキー）は、Webサーバーがユーザーのブラウザに保存させる小さなデータのことです。

**形式**：テキストファイル（.txt）
**保存先**：ユーザーのPC
**役割**：ユーザーの識別や設定の保持

* **ユーザーの識別**：「ユーザーのID」や「ログイン情報」を保持するために使われます
* **ユーザー設定の保持**：ユーザーが選択した言語やテーマ（ダークモードなど）の設定を保存し、次回アクセス時にも反映します
* **トラッキング**：Webサイトの閲覧状況や行動を記録して、ユーザーの興味や行動を分析するために利用されます。これにより、パーソナライズされた広告やコンテンツが表示されるようになります

## 仕組み

①ユーザーが初めてWebサイトにアクセスすると、サーバーがCookieを生成します。サーバーはこのCookieをレスポンスの一部としてユーザーのブラウザに送信します。
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816632/7cd66ef5-f073-2ec0-f2ee-446e04dcc1b0.png)

②ユーザーのブラウザは送信されたCookieを保存します。
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816632/fc6022f3-de49-c1d7-b585-09bb82b460ea.png)


③ユーザーが次回以降、同じWebサイトにアクセスすると、ブラウザは保存していたCookieをリクエストに含めてサーバーに送信します。サーバーはその情報を基に、ユーザーを識別したり、前回の状態を引き継いだりします。
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816632/4507dde2-3f97-a958-85a6-0376a61cf5ae.png)

個人情報などは入力されていないものを残すことはできません。
誤解されがちですが、サーバーがユーザーの個人情報を保持しているのではなく、ユーザーのハードディスク内にある情報を読み取っているだけなのです。

# セッション「何をしたか」
「セッション」は、Webサイトにアクセスしている間の「一連の流れ」や「やり取り」を一時的に保存しておく仕組みです。

**形式**：プログラムのデータ形式(文字、数値、配列…)のまま保存される
**保存先**：サーバー
**役割**：サーバー内に情報を保存し、ページ移動や操作をしても一貫して情報を維持する

* **ログイン状態の管理**：ユーザーがページを移動しても、ログイン状態を保持します
* **一時的な情報の保持**：ショッピングカートの内容やフォーム入力中のデータなど、セッション内で一時的なデータを管理し、必要な間だけ保持します


## 仕組み
①ユーザーがサイトにアクセスしサーバーにリクエストが送信されると、サーバーはユーザーを識別するための一時的なID(セッションID)を生成します。そしてユーザーのブラウザに「Cookie」という形で送ります。
サーバーはセッションIDをキーとして、ユーザーのログイン状態、カートの中身などの情報をサーバー上のメモリやデータベースに保存します。
![画像5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816632/cfe59694-eb0d-0efa-5991-f20e3dbdb9bf.png)

②ユーザーがサイト内でページを移動するたびに、ブラウザは保存したセッションIDをリクエストと一緒に送信します。サーバーはセッションIDを確認して「このIDはさっきアクセスした人だ」と判断し、情報をスムーズに引き継いで表示します。
![画像6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816632/478f1e08-c2bc-35ae-a73a-4866bfacd11d.png)

③ユーザーがブラウザを閉じる、または一定時間何も操作しないなどで「セッション」が終了すると、サーバー上のセッションIDは無効化されます。再度アクセスした際には、新しいセッションIDが生成されます。
![画像7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816632/a064dbc2-a8d9-b56d-12e9-0c039fa44738.png)

## セッションの保存方法
**サーバーサイドセッション**
セッション情報がすべてサーバー側で管理される方式です。

**クライアントサイドセッション**
セッション情報がユーザー側（クライアント）で管理される方式です。

※後日追記予定


## セッションとCookieの違い
セッションはそのときだけの一時的な情報を管理し、アクセスが終わると消えます。
一方、Cookieはある程度長い期間保存されることが多いです。
|| セッション | Cookie |
|:-:|:-|:-|
|保存場所|サーバー側|クライアント側<br>（ユーザーのブラウザ）
|用途|ログイン状態や一時的なデータ管理|設定保持やユーザーの利便性向上
|有効期限|通常はブラウザを閉じると終了|設定した期限まで有効
|セキュリティ|比較的高い|管理が必要<br>暗号化やSecure設定が推奨
|情報のサイズ|大量のデータも管理可能|1つ約4KBまで<br>最低限の情報のみ保存


# キャッシュ「ページの情報」
キャッシュとは、データを一時的に保存しておき、再度同じデータが必要になったときに素早く取り出せるようにする仕組みです。



### ブラウザキャッシュ

**形式**：画像やCSS、JavaScriptなどのWebページを構成する要素
**保存先**：ユーザーのPC
**役割**：Webページで使われる画像やスタイルシートなどを一時保存し、次回同じサイトにアクセスした際に再読み込みを省略します

* **ブラウザバック**：ブラウザの戻るボタンを押すと前のページに遷移します

### サーバーキャッシュ


**保存先**：サーバー
**役割**：サーバー側でデータベースから取り出した情報を一時的に保存し、次回同じリクエストがあったときにデータベースを再度呼び出さなくてもデータを返せるようにします

※後日追記予定
C#でraylibを使う

元々raylibはC言語向けのライブラリなのですが、~~環境構築が絶望的にできなかった~~のと、C#の方が慣れているので、C#で使ってみようと思いました。

# 開発環境
- Visual Studio 2022
- .NET 6.0
- Windows 11

# 入れ方
NuGetに[Raylib-cs](https://www.nuget.org/packages/Raylib-cs/)というC#用のraylibがあるらしいので、それを入れていきます。

## Visual Studioの場合

ソリューションを右クリックしてNuGetパッケージの管理を押します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3886798/1603111e-f986-d738-da51-cdfe1d832706.png)

参照を押してraylib-csで調べて出てきたパッケージを入れます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3886798/c550707e-c7b0-cf33-8ec3-71992ad99749.png)

## .NET CLIで入れる場合

```sh
dotnet add package Raylib-cs
```

バージョンを指定する場合：
```sh
dotnet add package Raylib-cs --version 4.0.0
```

# 使い方

```cs
using Raylib_cs;
```
これを書けばあとはraylibのAPIを呼ぶときは頭に`Raylib`とつけるだけでよさそうです。

raylibの[サンプルコード](https://github.com/raysan5/raylib?tab=readme-ov-file#basic-example)をC#用にしてみました
```cs
using Raylib_cs;

class Program
{
    public static int Main()
    {
        Raylib.InitWindow(800, 450, "raylib [core] example - basic window");

        while (!Raylib.WindowShouldClose())
        {
            Raylib.BeginDrawing();
            Raylib.ClearBackground(Color.RayWhite);
            Raylib.DrawText("Congrats! You created your first window!", 190, 200, 20, Color.LightGray);
            Raylib.EndDrawing();
        }

        Raylib.CloseWindow();

        return 0;
    }
}
```

:::note info
色を指定するときは `Raylib` ではなく `Color` を使います。
```diff_c_sharp
- Raylib.ClearBackground(Raylib.RAYWHITE);
+ Raylib.ClearBackground(Color.RayWhite);
```
:::

# Escキーを使えるようにする

raylibはデフォルトだとEscキーを押すとゲームが落ちます。
これは仕様なので`SetExitKey`を使って無効化したりキーを変えたりできます。

```cs
Raylib.SetExitKey(0); //無効化
Raylib.SetExitKey(KeyboardKey.Backspace); //バックスペースに割り当て
```
dbtのチートシート


本記事では、dbtで使うコマンドを紹介します。
dbt Core, dbt Cloud IDE, dbt Cloud CLIそれぞれで対応しているコマンドが違うため、覚えておこうと思いました。
使うコマンドは限られるので、「よく使うコマンド」を参照ください。

今後もアップデートしていく予定です。
使い方とか要望があれば、随時更新します。

## コマンド一覧

### すべてにサポート（dbt Core/dbt Cloud CLI/dbt Cloud IDE)
| コマンド | 説明文 |
| --- | --- |
| `dbt build` | 選択されたすべてのリソース（model, seed, snapshot, test)をビルドおよびテストする |
| `dbt clean`|dbtプロジェクト内のdbt_packagesおよびtargetフォルダを削除します。dbt_project.yml内の`clean-targets`に指定したフォルダが削除されます。
|`dbt clone`|指定された状態から選択されたモデルをクローンする
|`dbt compile`|プロジェクト内のモデルをコンパイルする（実行はしない）
|`dbt deps`|プロジェクトの依存関係をダウンロードする
|`dbt docs`|プロジェクトのドキュメントを生成する
|`dbt list`|dbtプロジェクトで定義されたリソースを一覧表示する
|`dbt run`|プロジェクト内のモデルを実行する
|`dbt parse`|プロジェクトを解析し、詳細なタイミング情報を書き込む
|`dbt retry`|最後に実行したdbtコマンドを失敗したポイントから再試行する
|`dbt run-operation`|マクロを呼び出し、データベースに対して任意のメンテナンスSQLを実行する
|`dbt seed`|CSVファイルをデータベースにロードする
|`dbt show`|変換後のテーブル行をプレビューする
|`dbt snapshot`|プロジェクト内で定義された「スナップショット」ジョブを実行する
|`dbt source`|ソースデータを扱うためのツールを提供する（ソースが「新鮮」であることを検証するなど）
|`dbt test`|プロジェクト内で定義されたテストを実行する

### dbt Coreのみ
| コマンド | 説明文 |
| --- | --- |
| `dbt init` | 新しいdbtプロジェクトを初期化する | 

### dbt Cloud CLIのみ
| コマンド | 説明文 |
| --- | --- |
| `dbt cancal`| 最新の呼び出しをキャンセルする
| `dbt environment`| dbt Cloud環境と対話する機能を提供する
| `dbt reattach`| 最新の呼び出しに再接続し、ログやアーティファクトを取得する

### dbt Cloud IDE, dbt Coreに対応
| コマンド | 説明文 |
| --- | --- |
| `dbt debug`| dbtの接続およびプロジェクトをデバッグする |

### dbt Core / dbt Cloud CLI
| コマンド | 説明文 |
| --- | --- |
| `dbt help`| 任意のコマンドに関するヘルプ情報を表示する |

## よく使うコマンド
| コマンド | 説明文 |
| --- | --- |
| `dbt run --select tag:{タグ名}[,tag:{タグ名}]`| タグを指定してモデルを生成（カンマ区切りで複数）  
| `dbt run --select {モデル名}`|モデル名を直接指定して実行する
| `dbt test`|モデルのテストを行う
| `dbt docs generate`|`dbt docs generate`の後に`dbt docs serve`を実行することでドキュメントを閲覧できる。
| `dbt seed` | dbt_project.yml内に定義したseedsのフォルダにあるファイルを読み取りデータベースに書き込みます。固定値を持つデータ等と取り込みたい場合に便利 |
| `dbt build` | モデルの実行,テストの実行,スナップショットの取得,seedの実行を一括で行ってくれます。運用時はこれを設定しておくとテストも実行してくれるので便利ですね |
|
バタバタした状況でも `やらか` さない。融けるチェックリスト導入のすゝめ

## はじめに

先週、稼働中のロボットがエラーで停止しました。

Kapplets 経由で運用しているロボットなので実行のタイミングは不定期。
前回の実行は３週間近く前。

その後、2週間前ぐらいにロボットの更新が行われており、その際にパスワードストアのアクセストークンを更新し忘れたことが原因のようだ。

通常は「ロボットの更新」→「アクセストークンの更新」と一連の流れとして実施しており、別に難しいことは何もない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/beddafa6-58e0-b05c-33a7-deaa46d9543d.png)

ゆえに、手順が抜けてしまったのではないか？と感じます。

## みなさん、チェックリスト使ってますか？

運用管理の「基本だろ！」という突っ込みが返ってきそうですが、意外と`慣れてしまったこと`や`細かい（他人と共有しない）タスク`については「わざわざ作らない」ことの方が多いんじゃないでしょうか。

言い換えると`結構規模が大きかったり複雑なタスク` についてはチェックリストで管理するものの、基本「面倒くさいから積極的には作りたくない」という気持ちもありそうです。

つくるだけであれば勢いでやりますが、管理・運用がね。。。

## できるだけ自然に、流れの中に組み込む

さて、ロボットの本番アップロード作業を失敗しないように、チェックリストを作りましょう。

Excelでフォーマットを作成し、漏れの無いように項目を洗い出しましょう。

ファイルはロボット管理台帳にリンクを記入して、ファイル自体はサーバーにおきましょう。

みたいにやってくと長続きしない、定着しない、なんかよくわからないファイルだけがサーバー上に残る、、という結果になりそうです。

`チェックシート` を敢えて意識しなくても自然と存在に気づき、ロボットを本番に上げる際には目に入る。そして面倒くさくない。

というのが重要な気がします。

## Design Studio内のメモ機能を使う
マイナーな機能ですが、Design Studioにはテキストエディタの機能が組み込まれています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/c63ea5c3-6982-7642-8215-1a8acfd8f7c7.png)

管理しているロボットが所属するプロジェクト内で `新規作成` -> `テキスト ファイル` を選択しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/f5f200ad-1945-6a78-c2cc-fc36a4f9b764.png)

デコレーション機能のないシンプルなメモ帳ですが、十分でしょう。本番リリース時のチェックリストを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/edf4e045-e30c-c2d4-d87a-5ec6f9ac46e9.png)

ロボットファイルを Design Studio 経由でそのまま MC にアップロードする場合、同一プロジェクト内のチェックリストも一緒に同期されます。

プロジェクト自体を `シェア プロジェクト` にしておくことで、複数人で管理しているロボットであっても、自動的に同期対象となるので便利です。

## まとめ

ちょっとしたことや当たり前のことこそ、少し時間が空いてしまったりスポットで他人に依頼するとなると、手こずります。

とはいえ、そんな稀なことに十分な準備で備える、というのも現実的には難しい。

小さな仕組みで習慣化、習慣の共有化をしていくのがいいですよね。

## 融けるチェックリスト？

使用するのに意識する必要がない。そんなデザインを「融けるデザイン」というようです。

チェックリストはどこまで行っても目的にはなりません。であれば、自然となじむ融けるチェックリストがいいよね。ということで。。。

https://bnn.co.jp/products/9784861009389
[Unity]非同期処理　UniRxを理解したい

# はじめに
　聞き覚えのある非同期処理たちを、改めて理解を深めるべくここにまとめていきたいと思います。
 （2024/10/28最終更新）

# 歴史

# 用語集
+ Task
+ UniTask
+ UniRx
+ await/async
+ coroutine
    + IEnumerator
    + yield return
    + startCoroutine

# Coroutine
　通常のコードでは１フレーム分でメソッドを完了してしまうが、不便な時がある。Coroutineは１フレーム分の呼び出しで作業を完了させず、複数のフレームにまたがって処理をすることができる[^1]。
 
 　脚注のUnity公式の例がすごくわかりやすかったので参考にしましょう。
  　複数フレームにわたってフェードアウトさせたいオブジェクトがあったとします。UpDate関数を使わず、Start関数などから呼び出す場合はFor文でフェードを回していても１フレームで完了してしまうため、すぐに消えてしまいます。
  Coroutineを使って複数フレームで処理すれば、１フレームで部分的にフェードさせることができ、徐々にフェードさせることができます。

　制約としてコルーチンを「含む」関数には”IEnumerator”を先頭にかき、”yield return”を中断させる部分に含ませます。
 　その関数を「呼び出す」ときに”StartCoroutine()”関数を使って関数を呼び出します。
  
　単語の意味としてはCo + routineで　協調+ルーティン　複数のフレームで協調して処理をするイメージ。


[^1]:[Unity Documentation　コルーチン](URL "https://docs.unity3d.com/ja/2022.3/Manual/Coroutines.html")
Javaのメモリ管理とガベージコレクションの仕組みについて

<br>

## ■ はじめに
<br>

初めに**GarbageCollection**とい言葉について。

**garbage（ガベージ）** ： 「ごみ」や「くず」、「がらくた」などのこと。
**collection（コレクション）** ：「収集」や「回収」、「収集物」などのこと。

garbage + collection = GarbageCollection （ガベージコレクション）
つまりガベージコレクションは直訳で**ごみの収集** といった意味合いになります。

Javaでいうガベージコレクションとは**プログラムで使用していないメモリを開放すること**です。
またガベージコレクタというものが、定期的にメモリの開放を行います。

このガベージコレクションはメモリリーク[^1]の発生を防ぎ、
アプリケーションを効率よく動作させるための最適化に役立ちます。

この記事ではJavaのメモリ構造やガベージコレクションの役割、
ガベージコレクションチューニングの基礎知識について解説していこうとおもいます。

## ■ 目次
<br>

1. [Javaのメモリ構造](#1-javaのメモリ構造)
2. [ガベージコレクションの基本](#2-ガベージコレクションの基本)
3. [代表的なガベージコレクションアルゴリズム](#3-代表的なガベージコレクションアルゴリズム)
4. [ガベージコレクションチューニングの基礎](#4-ガベージコレクションチューニングの基礎)
5. [まとめ](#5-まとめ)

## 1. Javaのメモリ構造
<br>

Javaプログラムが動作するメモリ領域は主に「**ヒープ領域**」「**スタック領域**」「**メタスペース**」
に分かれていて、それぞれが以下のような異なる役割を持っています。

- **ヒープ領域**
	- Javaオブジェクトが生成される領域で、ガベージコレクションの対象となる。
	- Young領域とOld領域に分かれ、短命なオブジェクトはYoung領域、長命なオブジェクトはOld領域に配置される。

    更にはYoung領域内で Eden と Survivor スペースに分かれていて、新しいオブジェクトがまずEdenに配置され、
    サイクルごとに生き残ったものがSurvivorスペースに移動されます。
<br>

- **スタック領域**
	- メソッドの呼び出しやローカル変数が管理される領域。
	- メモリの割り当てや解放が自動で行われる。
<br>

- **メタスペース**
	- Java 8以降で導入された領域で、クラスメタデータが保存される場所。
	- ヒープの外側に配置されており、必要に応じて拡張される。

このメタスペースはJava 8以前は「Permanent Generation」として扱われていた領域で、
Java 8からメタスペースが導入されたことでヒープ外にクラスメタデータが格納され、メモリリークの問題が改善されています。

## 2. ガベージコレクションの基本
<br>

Javaのガベージコレクションは不要になったオブジェクト（ガベージ）を自動的に回収する仕組みのことです。
この仕組みによりメモリの解放が自動化されプログラマが手動で管理する必要がなくなるため、メモリリークが起きにくい設計になっています。

ガベージコレクションはヒープメモリが一杯になってしまったり、特定のメモリ使用状況やアプリケーションのアイドル状態、設定された条件下などで自動的にトリガーされる際に発生します。


## 3. 代表的なガベージコレクションアルゴリズム
<br>

Javaには以下のような代表的なガベージコレクションのアルゴリズムが存在しており、用途に応じて選択されます。

|種類|説明|
|:---:|:---:|
|Serial GC|単一スレッドで動作し、スループットには不向き<br>開発用環境や少量メモリの環境で使用|
|Parallel GC|複数スレッドで並列に動作し、効率的にメモリを解放<br>高スループットが求められるアプリケーションに適している|
|G1 GC|複雑なメモリレイアウトに対応して遅延を最小限に抑える<br>大量のメモリを使用する大規模なアプリケーションに適している|

...など

### ガベージコレクション アルゴリズムの指定方法

例えばG1 GCを使用する場合には、JVMオプション[^2]で以下のように指定します。

```bash
-XX:+UseG1GC
```

## 4. ガベージコレクションチューニングの基礎
<br>

ガベージコレクションのチューニングはアプリケーションのパフォーマンスを向上させるために行います。
ガベージコレクションが発生する頻度やその際の遅延を調整することで、
パフォーマンスに影響を与えるガベージコレクションの影響を最小限に抑える目的があります。







### チューニングの基本手法

-   **ヒープサイズの設定**
	- ヒープサイズの上限を適切に設定しガベージコレクションが頻発するのを防ぐため、
	- 以下のように 最大サイズ（Xmx） と 初期サイズ（Xms）を設定します。
（具体的な値はマシンや環境のメモリよって適宜変更します。）
	
```bash
-Xmx2g -Xms2g
```
<br>

**ガベージコレクションログの有効化**
	以下の設定でガベージコレクションの動作状況をログとして出力してパフォーマンスの確認に役立てます。

```bash
-Xlog:gc*:file=gc.log:tags,time,uptime
```
<br>

-   **アプリケーションのメモリ使用状況のモニタリング**
	- Java Mission Controlなどのツールでメモリの使用状況を可視化、
	- 適切なガベージコレクションのタイミングやメモリ割り当ての改善を行います。

    最新のJVMではZGC[^3]やShenandoah[^4]といった低遅延ガベージコレクションも利用可能で、
    上記は特にリアルタイムアプリケーションやレスポンスが重要なシステムで有効です。
    ZGCはヒープサイズに影響を受けにくく、数TBのメモリでも遅延が1ミリ秒以内になるように設計されているようです。

## 5. まとめ
<br>

-   Javaのメモリ構造を理解することで、メモリ効率や最適化が可能
    -   **ヒープ領域**、**スタック領域**、**メタスペース**の役割を把握
-   ガベージコレクションは不要なオブジェクトの自動回収を行い、メモリリークを防ぐ
    -   Serial、Parallel、G1など、環境に応じてGCアルゴリズムを選択
-   ガベージコレクションチューニングで、アプリケーションパフォーマンスの向上が可能
    -   ヒープサイズの設定や**ログの活用が有効な手法

[^1]:使用していないメモリを開放することなく確保し続けてしまう現象
[^2]:Java 仮想マシン (JVM) の振る舞いを変更する値
[^3]:Zガベージ・コレクタの略でスケーラブルな低レイテンシのガベージ・コレクタ
[^4]:実行中のプログラムと同時にガべージコレクションを実行することで、ガベージコレクションの一時停止時間が短縮するガベージ・コレクタ
【個人メモ】Ruby on Rails チュートリアル 第3章

Ruby on Railsチュートリアルで学んだ内容を個人的なメモとして簡単にまとめたものです
# 個人メモ
- コントローラの生成コマンド
rails g controller コントローラ名 アクション名
- マイグレーションの変更を元に戻す
rails db:rollback
- テスト駆動開発（TDD: 
最初に「正しいコードがないと失敗するテスト」を書き、次に本編のコードを書いてそのテストがパスするようにする
- assertion（アサーション）
アクションをgetして正常に動作することを確認するテスト手法
- テストの実行
rails test
- provideメソッド
引数にてページのタイトルをviewごとに変更
- yeildメソッド
記述箇所に実際にタイトルが挿入される
義肢・装具業界における3Dスキャナーの活用

### 義肢・装具業界における3Dスキャナーの活用

義肢や装具業界において、**3Dスキャナー**は技術革新を促進する重要なツールとなっています。従来の手作業による測定や型取りと比べて、3Dスキャンは精度が高く、個別にカスタマイズできる可能性をもたらし、義肢や装具の快適さと機能性を大幅に向上させています。

https://www.revopoint3d.jp/collections/3d-scanners

### 精密な測定で快適性を向上

3Dスキャナーは、患者の体の形状を迅速かつ正確に捉えることができます。非接触型のスキャンにより、肢体の形や細部を精密に記録し、手作業測定で発生しがちな誤差を回避します。わずかな誤差でも義肢のフィット感や快適性に影響するため、義肢設計においてこの精度は重要です。スキャナーで得られたデータは三次元モデルに直接変換され、デザイナーがモデリングソフトでさらに調整・設計しやすくなります。
![c9d65f52e4825e1cb80d7baa31fb7ad1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/e885ce7c-606a-f624-bf81-a312dd090509.png)


### カスタマイズで患者のニーズに応える

3Dスキャンにより、**義肢や装具の個別カスタマイズ**がより容易になりました。体型は人それぞれ異なりますが、3Dスキャン技術はこれらの違いを正確に捉え、義肢や装具が患者の体に完全に適合するようにします。これにより患者のニーズによりよく応えることができ、製作期間も大幅に短縮されます。従来の方法では、何度も試着と調整が必要でしたが、3Dスキャン技術を活用することでこれらの工程を効率化できます。
![f1546a7a4cd481e59fd43d90e26e7d2a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/dbe1e1fd-2b9f-d75b-f0c4-301cfd4fd4bf.png)

### 装具製作工程の最適化

装具製作においても、3Dスキャナーは大幅に工程を簡素化しています。例えば、脊柱側弯症用の装具の製作では、3Dスキャンにより背中の形状と姿勢を素早く捉え、精確な3Dモデルを形成します。その後、装具の設計および製作段階に入ることができ、患者の負担を軽減すると同時に、装具の精度と快適性を高めます。

### デザインの革新を促進

また、3Dスキャナーは義肢や装具のデザイナーにとって、革新的な設計プロセスを加速させる助けとなります。3Dモデリングや3Dプリンター技術と組み合わせることで、デザイナーは新たなデザインのアイデアをより自由に探求でき、製作過程でリアルタイムに調整することが可能です。このデジタルプロセスは設計と製作を一体化し、特別なニーズを持つ患者への対応スピードを向上させ、義肢装具業界の発展をさらに促進します。

### 結論

総じて、3Dスキャナーは義肢と装具の個別対応、快適性、効率性の向上に大きく貢献しています。3Dスキャン技術がさらに進化するにつれて、このツールは今後、義肢装具業界においてますます重要な役割を果たし、患者の生活の質を向上させることが期待されます。
argparseの使い方　ささっと確認したい編

# この記事の対象
argparseの存在を知っているけど使ったことがない人。
python初心者の方

最近改めてまた勉強したので、まとめます。

# argparseとは
argparseを使うと、pythonの実行の時にコマンドラインから引数を渡すことができるようになります。

```python
# sample.pyの関数にファイル名を渡すとその名前でファイルを作っているようなイメージ
python sample.py --name sample.csv
```
みたいな感じで渡せます。

やろうと思えば
```python
arg = input('filename->')
sample(arg)

# 実行結果
# filename ->  # ここにファイル名(sample.csv)を入れる
```
という感じでinputでもできますが、より充実した機能をargparseは提供してくれます。

# 使い方
今回は
・ディレクトリと期間(月)とファイル形式を渡すと該当のファイル名を列挙するようなプログラムを想定
・引数はディレクトリ(dir)、月(month)、ファイル形式(format)
・オプション引数として列挙する個数(l)を指定

例を先に出します。
```python
import argparse

# パーサーの設定
parser = argparse.ArgumentParser(
        description='指定されたディレクトリから特定の月のファイルを検索するプログラム',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='''
使用例:
  %(prog)s dir /path/to/directory month 3 format txt
  %(prog)s dir /path/to/directory month 3 format csv --l 5
''')

# 引数の指定
parser.add_argument('dir', help="対象ディレクトリ")
parser.add_argument('month', help="データ取り込み対象月")
parser.add_argument('format', help="ファイルフォーマット")
parser.add_argument('--l', type=int, help="表示する列数")

args = parser.parse_args()
 
```

順番に内容を見ていきます。

## パーサーの設定

```python
parser = argparse.ArgumentParser(
        description='指定されたディレクトリから特定の月のファイルを検索するプログラム',
        formatter_class=argparse.RawDescriptionHelpFormatter)
        epilog='''
使用例:
  %(prog)s dir /path/to/directory month 3 format txt
  %(prog)s dir /path/to/directory month 3 format csv --l 5
''')
```

引数について
description
プログラムの説明を記載します。あってもなくてもいいです。

formatter_class
ヘルプのフォーマットをカスタマイズできるようになります。
RawDescriptionHelpFormatterを定義するとdescriptionとepilogはすでに整形済みのものとして改行されないようになります。

epilog
プログラムの説明の追加を記載できます。
例えば上の例だと
```
usage: test.py [-h] [--l L] dir month format

指定されたディレクトリから特定の月のファイルを検索するプログラム

positional arguments:
  dir         対象ディレクトリ
  month       データ取り込み対象月
  format      ファイルフォーマット

options:
  -h, --help  show this help message and exit
  --l L       表示する列数

使用例:
  test.py dir /path/to/directory month 3 format txt
  test.py dir /path/to/directory month 3 format csv --l 5
```
という感じでヘルプを見られるんですが、使用例なんかはdescriptionに書いてpositional argumentsの前に書いてしまうよりは引数の後に書いたほうが見やすさの観点から良いです。


## 引数の指定
```python
parser.add_argument('dir', help="対象ディレクトリ")
parser.add_argument('month', help="データ取り込み対象月")
parser.add_argument('format', help="ファイルフォーマット")
parser.add_argument('--l', type=int, help="表示する列数")
```

引数の指定は```.add_argument('引数名'、help='説明')```で行うことができます。
オプション引数は宣言の仕方が変わります。
オプション引数は実行の際に宣言しなくてもいい引数のことで、今回の例では列挙する個数(l)が該当します。
この時は引数の前に--をつけて指定をします。

また、typeを指定することができて、オプション変数--lでは引数をintで受け取るように設定しています。
逆に**デフォルトでは文字列型**なので気をつけましょう。

# 参考資料

[argparse --- Parser for command-line options, arguments and subcommands¶
](https://docs.python.org/ja/3/library/argparse.html)
Pythonにおけるイテレータ

Pythonでは、イテレータはコンテナ（例えばリスト、タプル、辞書、集合、文字列など）内の要素を一度にメモリにロードせずに逐一訪問できるオブジェクトです。イテレータオブジェクトは2つの特殊メソッド、`__iter__()`と`__next__()`を実装します。`__iter__()`メソッドはイテレータオブジェクト自身を返し、`__next__()`メソッドはコンテナ内の次の要素を返します。イテレータに返す要素がなくなった場合、`__next__()`メソッドは`StopIteration`例外を発生させてイテレーションの終了を通知します。

#### イテレータの利点

1. **メモリの節約**：イテレータは要素を逐一処理できるため、一度にすべての要素をメモリにロードする必要はありません。
2. **柔軟性**：イテレータは複雑なデータ構造を処理するためにカスタマイズしたり、遅延評価（必要に応じて計算）を実装したりできます。
3. **簡潔性**：イテレータを使用すると、コードをより簡潔で理解しやすくすることができます。

#### イテレータの作成

イテレータを作成するには、クラスを定義し、`__iter__()`と`__next__()`メソッドを実装する必要があります。また、`collections.abc.Iterator`を基底クラスとして使用することで、イテレータの実装が正しいかどうかを確認できます。

#### サンプルコード

以下は、指定範囲内の数字をイテレートするカスタムイテレータクラスを作成する簡単な例です。

```python
from collections.abc import Iterator

class MyRange(Iterator):
    def __init__(self, start, end):
        self.current = start
        self.end = end

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.end:
            num = self.current
            self.current += 1
            return num
        else:
            raise StopIteration

# カスタムイテレータを使用
my_range = MyRange(1, 5)

for num in my_range:
    print(num)
```

#### コードの説明

1. **`Iterator`基底クラスのインポート**：`collections.abc`モジュールから`Iterator`基底クラスをインポートし、標準のイテレータインタフェースを実装することを確認します。

2. **`MyRange`クラスの定義**：
   - `__init__`メソッドで開始値`start`、終了値`end`、および現在の値`current`を初期化します。
   - `__iter__`メソッドでイテレータオブジェクト自身（この例では`self`）を返します。
   - `__next__`メソッドで現在の値が終了値より小さいかどうかをチェックします。小さい場合、現在の値を返し、現在の値を1増やします。そうでない場合、`StopIteration`例外を発生させます。

3. **カスタムイテレータの使用**：
   - 指定した開始値と終了値で`MyRange`オブジェクトを作成します。
   - `for`ループで`MyRange`オブジェクトをイテレートし、各値を印刷します。

#### 実行結果

```
1
2
3
4
```

この例は、指定範囲内の数字をイテレートする簡単なイテレータを作成する方法を示しています。`__iter__()`と`__next__()`メソッドを実装することで、より複雑なデータ構造を処理するための独自のイテレータクラスを作成したり、特定のイテレーションロジックを実装したりできます。
mongoDBのcountDocuments()でエラー（TypeError: db.hogecollections.countDocuments is not a function）

MongoDBで特定の条件に合致する件数を知りたい場合は、countDocuments()メソッドを使うことができる。今回countDocuments()を使おうとすると以下のエラーとなった。

## 事象
```bash
E QUERY    [thread1] TypeError: db.hogecollections.countDocuments is not a function :
@(shell):1:1
```

実行したクエリはこちら
```bash
db.users.countDocuments({ age: { $gt: 18 } }); // 年齢が18歳以上のユーザーをカウント
```

## 原因
主に、countDocuments()メソッドが存在しないMongoDBのバージョンを使っているか、MongoDBのドライバーが適切に設定されていない場合があるが、今回はMongoDBのバージョンが古すぎるのが原因だった。
```bash
MongoDB Enterprise > db.version(); //バージョンを確認
3.6.23
```
countDocuments()メソッドはMongoDB 4.0以降で使用可能なもよう。

## 代替案
find()メソッドとcount()メソッドを組み合わせて件数を取得する
※ただし、`count()`メソッドは非推奨とされており、将来的に削除される可能性があるため、素直にMongoDBのバージョンアップを行うことをおすすめ！！
```bash
db.users.find({ age: { $gt: 18 } }).count(); // 年齢が18歳以上のユーザーをカウント
```
セキュリティ攻撃一覧【応用情報】 

応用情報で学習するセキュリティ攻撃について、自分の理解&整理のために一覧化してみました。


![Security_01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/630776e1-f582-a0ff-bcaf-a58eb5265baf.png)

![Security_02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/961ba89f-ac92-9947-ed34-c7439f3e5c1b.png)

![Security_03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/58110a8a-9f8e-e4fd-3021-05f9e7d09ec4.png)
データベース設計について【応用情報】

普段業務の中でデータベースを扱わないため、応用情報で取り扱うデータベース設計について簡単にまとめてみました。

# データベースとは

データを整理して保存し、必要なときに取り出せるようにしたシステムのこと
データベース作成の際には下記フレームワークがある


# データベース設計
データベースでデータ管理を行うために、**現実世界の情報を抽象化を行い、どのような情報をどういった構造でデータベース化するのかを設計する**こと

データベース設計には3段階のプロセスがある

* 概念設計
* 論理設計
* 物理設計

![oracle_6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/8a9a0cab-4653-79d9-8e2c-5397ab60436d.png)

# 概念設計
データベース設計の対象となる業務プロセスに必要なデータを抽出し、情報構造を抽象化して表現した「概念データモデル」の作成を目的としている

※下記が構成要素
### エンティティ
データベース内で扱う対象 (顧客、商品、注文などの実体)
図では四角で表現される


### 属性
エンティティの特性や情報 (名前、住所、電話番号など)
エンティティの内部に書かれる or 楕円で表現


### リレーションシップ
エンティティ間の関係を示す (「顧客が注文をする」や「商品がカテゴリに属する」といった関係)
エンティティ間にやじるし線で結ぶことで表現

E-R図は上記の構成要素を図にしたもの
![oracle_8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/ef8e13af-d3fc-5696-c234-4a206d30d359.png)

# 論理設計
論理データモデルは関係データベースを取り扱う関係データベースについて記載

### 関係モデル
データをテーブル（関係）として表現するデータベースの理論的なフレームワーク
各テーブルは行（レコード）と列（属性）で構成され、行は特定のデータを、列はそのデータの特性を表す

![oracle_9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/4721e089-dd82-5049-7df5-dc63cbf399dd.png)

# 物理設計
応用情報ではほとんど扱っていないため割愛
Oracle ユーザーについてまとめてみました【初心者】

Oracle初心者である自分がユーザーについて理解するために整理してみました。

# ユーザー
データベースにアクセスするためのアカウントのこと
各ユーザーには、特定の権限や役割が与えられ、データベース内のデータに対する操作が制御される

スーパーユーザー
データベース内で特別な権限を持つユーザーのこと
主に以下の2つのユーザーがスーパーユーザーとして機能している


### SYS
Oracleデータベースの管理や設定を行うための**最も強力なユーザー**
すべてのシステム権限を持ち、データベースの内部構造に直接アクセス可能
(データベースの作成、削除、ユーザーの管理、バックアップなど、すべての管理作業が可能)

### SYSTEM
一般的なデータベース管理作業を行うためのユーザー
アプリケーションユーザーの管理など、日常的な管理作業に使用される
(ユーザーの管理やロールの設定、権限の付与などが可能)


またスーパーユーザー以外では一般ユーザーがある

### 一般ユーザー
特定の権限を持ち、データベース内のオブジェクト（テーブルやビューなど）にアクセスできるアカウントのこと
スーパーユーザーとは異なり、**通常は限られた権限しか持っていない**


# スキーマ
データベースオブジェクト（テーブル、ビュー、インデックスなど）を整理するため**名前空間**のこと
スキーマは**特定のユーザーが持つデータベースオブジェクトの集合を指す**
(所有者の明確化と他のユーザーからのアクセスを制御することが目的)

![oracle_4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/28fb2648-34c1-b5f3-4c60-a5893e526ac0.png)

例えば、上記の構成の場合、テーブル(BBB)の完全修飾名は **AAA.BBB** となる


# 権限
Oracle の権限については、下記 2種類ある

### システム権限
**データベース全体**に対する権限　(SYS、SYSTEMユーザーが所持) 
例 ) データベースオブジェクトの作成、変更、削除など

### オブジェクト権限
**スキーマオブジェクト**に対する権限
※下記に代表的な権限を記載
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/793726f2-33ed-5bf3-bcfa-c4ad68bf843e.png)

# ロール
**特定の権限をグループ化して管理する**ための機能
システム権限やオブジェクト権限を組み合わせて作成する

デフォルトで存在するロール(事前定義済みロール)
* CONNECTロール：データベースに接続するためのロール
* DBAロール：データベースの管理に必要な権限をまとめたロール

※イメージ図
![oracle_5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/4ccf2ee9-79ff-0847-1a4d-2facbeb38573.png)

※参考
* 「図解入門よくわかる 最新Oracleデータベースの基本と仕組み」(秀和システム)
* [今さら聞けない!? Oracle入門～アーキテクチャ編～](https://www.oracle.com/jp/a/tech/docs/technical-resources/0420-1330-oracle-architecture.pdf)
Oracleの構成についてまとめてみました【初心者】

業務の中でoracleを触る機会があったのですが、Oracleで使われる用語の理解が不十分だったため、こちらで図解することで整理し理解を深める目的で投稿してみました。

# Oracleの構成図

![oracle_10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/98bb3575-af5f-abd6-a94d-0eff305f0798.png)

下記説明です。

# インスタンス

データベースに接続して操作を行うための環境
主にメモリとプロセスから構成されている

**メモリ**
インスタンスは、データベースのデータや情報を一時的に保存するためのメモリ
（バッファキャッシュや共有プールなど）

**プロセス**
インスタンスは、データベースに対するリクエストを処理するためのさまざまなプロセス
（ユーザーからのクエリを処理するプロセスなど）

インスタンスの役割は以下です。

* データ管理 : データの読み書きや更新を効率的に行う
* ユーザー接続の管理 : ユーザーがデータベースにアクセスする際の接続を管理
* トランザクションの処理 : データの整合性を保ちながら、複数の操作をまとめて処理

# プロセス

**リスナープロセス**
Oracleデータベースにおいて、クライアントからの接続リクエストを受け付ける役割を担っているプロセス

* 接続の受付
リスナープロセスは特定のポートで待機しており、クライアントからの接続要求を受け取って適切なデータベースインスタンスに接続を確立する

* サービス名の管理
データベースのサービス名やホスト名、ポート番号を用いて、クライアントにデータベースの位置情報を提供する

* トラフィックの管理
複数のデータベースインスタンスがある場合、リスナープロセスは接続要求を適切に分散させ、各インスタンスの負荷を均等にする

* アクセス制御
クライアントがどのようにデータベースに接続するかを管理し、不正な接続を防ぐ役割も果たす


**サーバープロセス**
ユーザープロセスと直接のやり取りを行うプロセス
ユーザ毎に起動され、リクエストされた処理を実行する
"フォアグラウンド・プロセス"ともいう


# システムグローバル領域（SGA）

System Global Area の略
Oracleデータベースが動作するために必要な**メモリ領域**のこと
データベースインスタンスが使用するために予約され、さまざまなデータや情報を格納する

※構成図

![oracle_02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/a6f1d729-a740-b3d6-4393-afb08debb086.png)

**データバッファキャッシュ**
データベースのテーブルやインデックスのデータを一時的に格納する場所
ディスクへのアクセスを減らし、データの読み込み速度を向上させる


**共有プール**
SQL文やPL/SQLプログラムの解析結果、実行計画、カーソル情報などを保存
同じSQL文が複数回実行される際に、再解析の必要がなくなることでパフォーマンスが向上


**REDOログバッファ**
データベースの変更を記録するための領域
トランザクションの整合性を保つために、変更内容が書き込まれる前にこちらに保存される


**JAVA プール**
Javaプログラムを実行するために必要なリソースを管理するためのメモリ領域


**ラージ プール**
特に大きなメモリを必要とする処理(バックアップ&リストア)に使われる

SGAの全体としての役割は以下です。

* データのキャッシュ : データベースのデータやインデックスをキャッシュすることで、データアクセスを高速化する
(SQL文の結果やメタデータなど)

* 共有情報の格納 : 複数のプロセスが共有するための情報（データベースの構造や状態など）を格納することにより、複数のユーザーからのリクエストを効率的に処理げできる

* トランザクション管理 : トランザクションの処理に必要な情報や制御構造保存されることで、データの整合性を保ちながらトランザクションを処理する

* バッファキャッシュ : データブロックを一時的に保存することで最近使用されたデータに迅速にアクセスが可能

# プログラムグローバル領域（PGA）
Program Global Area の略
Oracleデータベースの各サーバ・プロセス起動時に自動的に割り当てられる**メモリ領域**のこと
プロセスが特定のプログラムやセッションに必要な情報を保持するために使用される
※PGAはサーバープロセスとバックグラウンドプロセスに割り当てられる

:::note info
SGAとPGAの違いについて
:::

**SGA** → **データベース全体で共有**されるメモリ領域であり、複数のサーバ・プロセス間で共有されるデータや情報を格納する
**PGA** → **各サーバ・プロセスに専用**で利用されるメモリ領域であり、個別のセッションやプロセスに関連するデータを保持する


※構成図

![oracle_03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513259/2de27c54-bd80-4c1f-17ef-e0366a079d57.png)

**スタック空間**
各プロセスの実行時に使用されるメモリの領域のこと
局所変数や戻りアドレスが保存される


**セッション情報**
各セッションに特有の情報（ユーザー名、ログイン情報、接続情報など）が保存される


**カーソル状態情報**
SQL文の実行に関する情報や、実行計画がここに保存される。これにより、効率的なクエリ処理が可能


**ソート領域**
データをソートする際に使用されるメモリ領域のこと。大きなデータセットを扱う場合、この領域が重要

※参考
* 「図解入門よくわかる 最新Oracleデータベースの基本と仕組み」(秀和システム)
* [今さら聞けない!? Oracle入門～アーキテクチャ編～](https://www.oracle.com/jp/a/tech/docs/technical-resources/0420-1330-oracle-architecture.pdf)
ActiveAdminでの`NoMethodError`解決: `undefined method 'delete' for :ok:Symbol`エラー


## はじめに
Railsで管理画面を実装している際に、以下のようなエラーに遭遇することがあります。

```
NoMethodError at /admin/items
undefined method `delete' for :ok:Symbol
```

この記事では、このエラーの原因とその解決方法について詳しく解説します。

## エラーメッセージの詳細
エラーが発生するのは、`app/admin/item.rb`ファイルの以下の部分です。

```ruby
column :name
column "ステータス" do |item|
  if item.is_active
    status_tag "アクティブ", :ok
  else
    status_tag "非アクティブ"
  end
end
```

このコードで`status_tag`に渡している`:ok`が原因で、エラーが発生しています。

## エラーの原因
### `status_tag`の仕様
- `status_tag`メソッドの第2引数には、`class`オプションを含む文字列またはハッシュを渡す必要があります。
- `:ok`というシンボルがそのまま渡されると、`status_tag`メソッドはそのシンボルを扱いきれず、`undefined method 'delete' for :ok:Symbol`というエラーを引き起こします。

### `:ok`シンボルの誤用
`:ok`をシンボルとして渡してしまっているため、`status_tag`メソッドが期待する形になっていません。その結果、メソッド内部でオプションを扱おうとした際にエラーが発生しています。

## 解決方法
エラーを解消するには、`status_tag`の第2引数を文字列またはクラスオプションを指定したハッシュに変更します。

### 修正前のコード
```ruby
column :name
column "ステータス" do |item|
  if item.is_active
    status_tag "アクティブ", :ok
  else
    status_tag "非アクティブ"
  end
end
```

### 修正後のコード
以下のように、`:ok`を`class: "ok"`に変更します。

```ruby
column :name
column "ステータス" do |item|
  if item.is_active
    status_tag "アクティブ", class: "ok"
  else
    status_tag "非アクティブ"
  end
end
```

### 修正ポイント
- `status_tag "アクティブ", :ok`を`status_tag "アクティブ", class: "ok"`に変更しました。
- これにより、`:ok`シンボルを直接渡すのではなく、HTMLクラス名として`class: "ok"`を指定する形になります。

## 実装後の確認
1. 修正を`app/admin/item.rb`に反映させます。
2. Railsサーバーを再起動します。
3. `/admin/items`ページにアクセスして、ステータスが正しく表示されるかを確認します。

## まとめ
Rails 6.1以降の変更や管理画面のカスタマイズに伴い、`status_tag`のオプション指定方法に誤りがあると、`NoMethodError`が発生することがあります。このエラーは、シンボルをクラス名として渡す際に文字列に変更することで解消できます。

### ポイント
- `status_tag`のオプションにはハッシュを使用して、`class`やその他の属性を指定することが重要です。
- これにより、`NoMethodError`を解消し、ステータス表示のカスタマイズが正しく行えるようになります。

この記事が同様の問題で困っている方の助けになれば幸いです。参考になった方はぜひ「いいね」や「ストック」をお願いします。

## 参考リンク
- [Railsガイド: ActiveAdminでのカスタムビューヘルパー](https://activeadmin.info/)
- [Rails 6.1のリリースノート](https://edgeguides.rubyonrails.org/6_1_release_notes.html)

## 最後に
他にもご質問やご意見があれば、コメントでお気軽にお知らせください！
LaspyException: No LazBackend selected, cannot decompress data

## 起きたこと
- laspyを用いてlazファイルを読み込もうとした所，詰んだ．

## 解決方法
明示的にlazers, lazzipを入れる．
今回はcargoも入っていなかったので，インストールした．
~~~
    apt update
    apt install curl
    curl https://sh.rustup.rs -sSf | sh
    cargo --version
    source $HOME/.cargo/env
    cargo --version
    pip install laspy[lazrs,laszip]
~~~

確認方法
~~~
import laspy
available_backends = laspy.compression.LazBackend.detect_available()
print(available_backends)
~~~


## Tips
jupyterで使うときにpathエラーが出ることがある．
明示的に読み込むことで使えるようになる．
~~~
import os
os.environ['PATH'] = f"{os.environ['HOME']}/.cargo/bin:{os.environ['PATH']}"

! cargo --version
! pip install laspy[lazrs,laszip]
~~~
【Rails】sort_byメソッド,sortメソッド　【本日の積み上げ】

本日の学習記録を、記録します。


### sort_byメソッド, sortメソッド
指定した条件に基づいて、並び替えができる。

### 使い方
sort_byメソッド

数値配列の並び替え
```rb:example.rb
numbers = [3, 4, 5, 1, 2]
sorted_numbers = numbers.sort_by{ |number| numbers }
#任意の変数名(この中に並び替えられた配列が入る) = 配列が入っている変数名.sort_by{|ブロック変数|条件}
#デフォルトが昇順並び替え、降順にする際は{ |number| numbers }.reverseとする
p sorted_numbers # [1, 2, 3, 4, 5]
```
文字数の長さによって並び替え
```rb:example.rb
words = ["apple", "strawberry", "banana"]
sorted_words = words.sort_by{|word| word.length}

p sorted_words #["apple", "banana", "strawberry"]
```
ハッシュの配列を属性で並べ替える
```rb:example.rb
people = [
    {name: "太郎", age: 20},
    {name: "次郎", age: 18},
    {name: "三郎", age: 16}
]
sorted_people = people.sort_by{|person| person[:age]}

p sorted_people # [{name: "三郎", age: 16}, {name: "次郎", age: 18}, {name: "太郎", age: 20}]
```
sortメソッド

数値配列の並び替え
```rb:example.rb
numbers = [3, 4, 5, 1, 2]
sorted_numbers = numbers.sort#変数名.sort
#数字の昇順に並び替え
p sorted_numbers # [1, 2, 3, 4, 5]
```
文字数の長さによって並び替え
```rb:example.rb
words = ["apple", "strawberry", "banana"]
sorted_words = words.sort
#アルファベットの昇順
p sorted_words #["apple", "banana", "strawberry"]
```
シンプルに降順にしたい場合は、reserveを指定する
```rb
変数名 = 配列が入っている変数名.sort.reserve
```
条件指定したい時は、<=>演算子を利用する
```rb
#文字の長さで並び替えの場合
変数名 = 配列が入っている変数名.sort{ |a,b| a.length <=> b.length }#昇順
変数名 = 配列が入っている変数名.sort{ |a,b| b.length <=> a.length }#降順
```

| 特徴　| sort_by | sort |
|:-:|:-:|:-:|
| **目的** | 特定の属性や計算結果に基づいて並び替え  |  配列全体の並び替え |
| **使用方法** |  そのまま使うか、比較ブロックを渡す |  並び替え基準をブロックで指定 |
|  **速度** | sort は全体の比較を行うため、要素数が多いと遅くなることがある  |  sort_by は並び替え基準を先に計算するため、比較的高速 |

### 使い分けのポイント

・並び替えが簡単な場合（例：数値やアルファベット順）：sort を使う
・特定の基準で並び替えたい場合（例：オブジェクトのプロパティに基づく並び替え）：sort_by の方が効率的

たとえば、文字列の長さで並び替える場合、sort_by が適していますが、通常の昇順で並び替えたいだけであれば sort がシンプルで良い選択です。
Rails undefined method 'keys' for #<ActiveModel::Errors []>

## はじめに
RailsアプリケーションでActiveAdminを使用している際に、次のようなエラーに遭遇することがあります。

```
NoMethodError at /admin/columns/new
undefined method `keys' for #<ActiveModel::Errors []>
```

この記事では、このエラーの原因と解決方法について説明します。

## エラー内容の詳細
このエラーは、`app/admin/column.rb`ファイル内でフォーム定義を行う際に発生します。具体的には、以下のコードが原因です。

```ruby
f.semantic_errors *f.object.errors.keys
```

`f.object.errors`が`ActiveModel::Errors`のインスタンスであるにもかかわらず、その中で`keys`メソッドが利用できないという問題が発生します。

## エラーの原因
### ActiveModel::Errorsの変更点
- Rails 6以前では、`ActiveModel::Errors`はハッシュのように扱うことができ、エラーが発生した属性名を取得する`keys`メソッドが利用できました。
- Rails 6.1以降では、`ActiveModel::Errors`はハッシュのようなインターフェースを持たなくなり、`keys`メソッドが削除されました。その代わりに、`attribute_names`や`messages`メソッドを使用する必要があります。

## 解決方法
Rails 6.1以降のバージョンを使用している場合、以下のようにコードを修正します。

### 修正前のコード
```ruby
f.semantic_errors *f.object.errors.keys
```

### 修正後のコード
```ruby
f.semantic_errors *f.object.errors.attribute_names
```

`attribute_names`メソッドは、エラーが発生している属性の名前を配列として返してくれるので、以前の`keys`メソッドと同様の用途に使用できます。

## 解決手順
1. `app/admin/column.rb`ファイルを開き、該当部分のコードを修正します。
2. 修正した後、Railsサーバーを再起動します。
3. `/admin/columns/new`のページにアクセスして、フォームが正常に動作するかを確認します。

## まとめ
Rails 6.1以降では、`ActiveModel::Errors`の変更により、以前使用していた`keys`メソッドが利用できなくなりました。そのため、`attribute_names`を使用することで、問題を解決できます。

この修正を行うことで、`NoMethodError`を解消し、フォームのエラーメッセージが正しく表示されるようになります。同じエラーで困っている方の参考になれば幸いです。

## 参考リンク
- [Railsガイド: ActiveModel::Errors](https://guides.rubyonrails.org/active_model_basics.html)
- [Rails 6.1のリリースノート](https://edgeguides.rubyonrails.org/6_1_release_notes.html)

## 最後に
この記事が役に立ったら、ぜひ「いいね」や「ストック」をお願いします。また、他にもご質問があればコメントでお知らせください！
ネットワーク層とは

>インターネットワーキング、つまり、`複数のネットワークを繋いで、相互にパケットをやり取りする機能を実現`します。下位にあるネットワークインターフェース層は、直接繋がったコンピュータ同士の通信を提供しますが、その範囲を超えて通信する機能はありません。インターネット層が加わることで、`直接繋がっていないコンピュータ同士でも、相互に通信ができる`ようになります。`この層で大きな役割を果たすのがパケットの中継機能`です。パケットを中継し、`所定の方向に転送することをルーティング`と呼びます。このルーティングが行われることより、ネットワークインターフェース層だけでは届けることができない、任意の相手に、データを届けることが可能です。

https://www.sbcr.jp/product/4797386677/

ネットワークインターフェイス層とは？

https://qiita.com/masatom86650860/items/a9c3ea4030a4f46feb6e#:~:text=%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82-,%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%E5%B1%A4,%E8%BB%A2%E9%80%81%E9%80%9F%E5%BA%A6%E3%81%AE%E9%81%95%E3%81%84%E3%80%8D%E3%81%AA%E3%81%A9%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E7%B4%B0%E5%88%86%E5%8C%96%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82,-%E6%84%9F%E6%83%B3

交換方式の中継する機能がここにあるのか。

https://qiita.com/masatom86650860/items/982dec33dd638226cca2#:~:text=%E9%80%94%E4%B8%AD%E3%81%AB%E6%95%85%E9%9A%9C%E3%81%97%E3%81%9F%E5%9B%9E%E7%B7%9A%E3%82%84%E4%B8%AD%E7%B6%99%E6%A9%9F(%E3%83%8E%E3%83%BC%E3%83%89)%E3%81%8C%E3%81%82%E3%81%A3%E3%81%A6%E3%82%82%E3%80%81%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8C%E3%81%9D%E3%81%AE%E3%83%91%E3%82%B1%E3%83%83%E3%83%88%E3%82%92%E8%BF%82%E5%9B%9E%E3%81%95%E3%81%9B%E3%81%A6%E5%AE%9B%E5%85%88%E3%81%BE%E3%81%A7%E5%B1%8A%E3%81%91%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82

どのようにパケットは転送されるのか？

https://qiita.com/masatom86650860/items/2bc3bd7d525c546e6600

>ネットワークアドレス(MACアドレスとは異なる)が定義され、`通信経路の選択が可能`になります。イーサネットスイッチなどを使用してデータを送受信する際には、`ネットワーク層で経路が決定されて転送`されます。

https://www.keyence.co.jp/ss/products/controls/network/basics/hierarchy.jsp#:~:text=%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9(MAC%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%A8%E3%81%AF%E7%95%B0%E3%81%AA%E3%82%8B)%E3%81%8C%E5%AE%9A%E7%BE%A9%E3%81%95%E3%82%8C%E3%80%81%E9%80%9A%E4%BF%A1%E7%B5%8C%E8%B7%AF%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%8C%E5%8F%AF%E8%83%BD%E3%81%AB%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82%E3%82%A4%E3%83%BC%E3%82%B5%E3%83%8D%E3%83%83%E3%83%88%E3%82%B9%E3%82%A4%E3%83%83%E3%83%81%E3%81%AA%E3%81%A9%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E9%80%81%E5%8F%97%E4%BF%A1%E3%81%99%E3%82%8B%E9%9A%9B%E3%81%AB%E3%81%AF%E3%80%81%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E5%B1%A4%E3%81%A7%E7%B5%8C%E8%B7%AF%E3%81%8C%E6%B1%BA%E5%AE%9A%E3%81%95%E3%82%8C%E3%81%A6%E8%BB%A2%E9%80%81%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82

通信経路はどのように選択されるのか。
ReactにおけるGoogle Analyticsの実装手順

# ReactアプリにGoogle Analyticsを導入する手順

以前の記事で、Reactを使ったWebサービスを個人開発しました。その際、アクセス解析のためにGoogle Analyticsを導入したので、手順を備忘録として残しておきます。

---

## 手順

1. [Google Analyticsの開発者サイト](https://developers.google.com/analytics?hl=ja)にアクセスします。

2. 「測定を開始」をクリックします。
   ![測定を開始](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/a89eeaa1-e443-3976-d5c4-717ac646f545.png)

3. 任意の「アカウント名」を入力し、「次へ」をクリックします。
   ![アカウント名の入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/03b674f3-a2eb-73b4-bf6d-08b6828e1761.png)

4. 任意の「プロパティ名」を入力し、タイムゾーンと通貨を選択して「次へ」をクリックします。
   ![プロパティ設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/38e19449-6d3b-6aa5-a763-cddf337d4e7b.png)

5. 各質問に回答します。
   ![質問への回答](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/94523d25-4573-2680-37da-f7b0cd73f43b.png)
   ![質問への回答2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/105e96e0-dd82-aa2f-a5d3-11e324a63f31.png)

6. 利用規約を確認し、同意します。
   ![利用規約](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/2fb279b9-5825-b4f9-84aa-dc75e9cb5d93.png)

7. 「ウェブ」をクリックします。
   ![ウェブの選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/1c93daed-2311-e7c2-478f-adb606d06791.png)

8. 分析したいサイトの「URL」と「ストリーム名」を入力します。
   ![サイト情報の入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/663f2dbc-b645-6594-f77c-1036dbe4303e.png)

9. 作成されたストリームをクリックします。
   ![ストリームの選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/b8bfb9a1-9e34-80d2-fdfc-0e2d1e8f60a4.png)

10. 表示された「測定ID」を確認します。
    ![測定IDの確認](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892822/70014530-b348-8d36-7e29-6fc2381dcf3a.png)

11. Reactの `public` フォルダ内にある `index.html` ファイルに、以下のスクリプトを追加します。

    ```html
    <script async src="https://www.googletagmanager.com/gtag/js?id=(10で確認した測定ID)"></script>
    ```


### 以下が個人開発したwebサービスになります。
みなさんよければアクセスしていろいろなFBをいただけると嬉しいです。

1.海外からの旅行者が、日本に関するさまざまなトピックについて、不特定多数の人とリアルタイムで自由に情報を共有できるWebサービス

https://travel-class.com

2.申請方法や入手方法に関するマニュアルを作成・共有するWebサービス

https://manualshare.net
BSODを回避して古いサーバへWindows Server 2022をインストール

# 概要
Windows Server 2022を古いサーバへ入れるという機会もなかなか無く、海外フォーラムで直接的な事例を探すのに手間取ったので備忘録。
Fujitsu PRIMERGY TX140といったLSI MegaRAID系コントローラ使用のRAIDカードを含むデバイスへWindows Server 2022をインストールしようとすると、アップグレードではsafe_osエラー、クリーンではstorport.sysでDRIVER_IRQL_NOT_LESS_OR_EQUALが発生してインストールできない。
![error.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111226/530bae1e-3abe-9d5e-cc4e-b78e750f2ea3.jpeg)
### 参考
[LSI Raid card BSOD issues? : r/homelab | reddit](https://www.reddit.com/r/homelab/comments/s5o39w/lsi_raid_card_bsod_issues/)
[Windows 10 (2004) and LSI 9271-8i | Microsoft Q&A](https://learn.microsoft.com/en-us/answers/questions/108425/windows-10-(2004)-and-lsi-9271-8i)

# 原因
Windows10 2004(20H1)から古いRAIDカードを含む一部デバイスの標準サポートを打ち切ったため、古いドライバでは動作しなくなった。
Windows Server 2019はWindows10 1809をベースとしているため起動するが、Windows Server 2022からはBSODのためインストールすらできない。

# 準備するもの
+ 最新ドライバ
 [Support Documents and Downloads | Broadcom.com](https://www.broadcom.com/support/download-search?pg=Legacy+Products&pf=Legacy+RAID+Controllers&pn=MegaRAID+SAS+9271-8i&pa=Driver&po=&dk=&pl=) から「[MR Windows Driver - 06.714.18.00](https://docs.broadcom.com/docs/MR_WINDOWS_DRIVER_6.14-6.714.05.00-WHQL.zip)」をダウンロード
+ Windows Server 2022 ISO
+ Windows Server 2019 ISO

# インストール
<dl>
  <dt>方法１　ISOにドライバを組み込む</dt>
  <dd> クリーンインストールが必須要件であれば、組み込み以外でインストーラを起動させられない。<br>install.wimとboot.wimにドライバを適用し、起動ディスクへ書き戻す。<br>試してないけど<a href="https://forums.servethehome.com/index.php?threads/lsi-raid-controllers-pcie2-6gbps-windows-server-2022.39492/post-421142">ここ</a>とか参考になりそう。 </dd>
  <dt>方法２　標準で動くOSバージョンから更新</dt>
  <dd>クリーンではないけど簡単。<br> Windows Server 2019をインストールし、ドライバを適用してからWindows Server 2022へアップグレードする。</dd>
</dl>

# おわりに
予算があるならサーバ本体を新しくするべきだけど、動くなら使わざるを得ないよね。常用でなくともバックアップ機くらいには使えるし。:money_with_wings:
[JavaScript] 変数

# 環境
MacBook Pro (2.3 GHz 8コアIntel Core i9)
macOS 14.0（23A344）
Homebrew 4.3.8
gh 2.52.0

# まとめ
||再代入(上書き)|再宣言|
|:--|:-:|:-:|
|`var`|Yes|Yes|
|`let`|Yes|No|
|`const`|No|No|

# 目次
- [`var`](#var)
- [`let`](#let)
- [`const`](#const)

# `var`
**略:** Variable（変数）の略
**再代入（上書き）:** Yes
**再宣言:** Yes
~~~JS:index.js
var val1 = "var変数";
console.log(val1);

// var変数は上書きが可能
val1 = "var変数は上書き";
console.log(val1);

// var変数は再宣言可能
var val1 = "var変数を再宣言";
console.log(val1);
~~~

# `let`
**略:** 特に略ではない
**再代入（上書き）:** Yes
**再宣言:** No
~~~JS:index.js
let val2 = "let変数";
console.log(val2);

// let変数は上書きが可能
val2 = "let変数を上書き";
console.log(val2);

// let変数は再宣言不可能
let val2 = "let変数を再宣言";
~~~

# `const`
**略:** Constant（定数）の略
**再代入（上書き）:** No
**再宣言:** No
~~~JS:index.js
const val3 = "const変数";
console.log(val3);

// const変数は上書きが不可能
val3 = "const変数を上書き";
console.log(val3);

// const変数は再宣言不可能
const val3 = "const変数を再宣言";
console.log(val3);
~~~

# 参考リンク
- [モダンJavaScriptの基礎から始める挫折しないためのReact入門
](https://www.udemy.com/course/modern_javascipt_react_beginner)
- [Var, Let, and Const – What's the Difference?](https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/)
Djangoトラブル対処法めも

## CSRF検証に失敗したため、リクエストは中断されました。
- {% csrf_token %}がない
- settings.pyのCSRF_TRUSTED_ORIGINSの値が間違っている

参考URL:https://noauto-nolife.com/post/django-csrf-trusted-origins/

## 特定のアプリのマイグレーションをリセット
```python
python manage.py migrate アプリ名 zero
```

## migration＆データベースなどすべてリセット
1.データベースを削除して再作成
2.migrationsフォルダの__init__.py以外のファイルを削除
3.python manage.py makemigrationsを実行
4.python manage.py migrateを実行

## 画像が表示されない
- config/settings.py
```python
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = '/media/'
```
- config/urls.pyに「static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)」を記述
```python
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('products/', include('products.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
```
- 管理画面で画像を一度削除してから登録しなおす。
- mediaフォルダに画像がアップされているか確認。

## 管理者の登録を手動で行う
```python
python manage.py shell
from django.contrib.auth import get_user_model

User = get_user_model()
User.objects.create_superuser(username='ユーザ名', email='メールアドレス', password='パスワード')
```

Youtube
https://youtube.com/@codek2_studio

Twitter
[https://twitter.com/kunchan2_](https://twitter.com/kunchan2_)

Zenn
https://zenn.dev/codek2

note
https://note.com/codek2
Red Hat - Setup Log Housekeeping

Step 1. Modified logrotate configuration 

```shell
johnny$ sudo vim /etc/logrotate.d/nginx
```

```
/var/log/nginx/*.log {
    create 0664 nginx johnny # 產生檔案時的使用者及權限
    daily                    # 每天執行一次 (預設執行時間會在凌晨的 03:00 左右，若有指定時間執行請使用 crontab 方式)
    rotate 30                # 保留30天
    dateext                  # 使用日期當作檔案名稱
    dateyesterday            # 使用昨天的日期當作今天的檔名
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
    endscript
}
```

Setp 2. Test configuration
```
johnny$ sudo logrotate -vd /etc/logrotate.d/nginx
```


Ref：
---
https://wsgzao.github.io/post/logrotate/
debrideというRailsのGemを使ってコードのお掃除をした話。

# デッドコードがもたらす弊害

皆さんはこんな経験ありませんか？

:::note info
この処理どこで呼ばれてるんだろう→ちょっと調査→呼ばれてないんかい！
:::

:::note info
似ているメソッドがあるけどどっちを使えば良いんだ。このメソッド使っていいのかな？
:::

デッドコード(到達不能コード)は、存在しても決して実行されることのないコードを指します。

これらのコードがあると、使っていないとは分かっていても少し脳のメモリを割かれる感じがしますよね。
使っていないコードが残っているとファイルの行数が単純に増えて、ちょっと気も重くなります。

気分的な問題だけでなく、デッドコードを残しておくと、誤って呼び出されてしまってバグを引き起こしてしまうなど、残しておいて良いことはひとつもありません。

テストコードに関しても、使っていないメソッドをテストするのは時間の無駄ですよね。

# 不要なコードをお掃除しよう！
そこで私の所属していたチームではGemを使ってのリストアップをおこなってデッドコードのお掃除を進めました！

どんな感じで進めたかをざっくりとご紹介できればと思います。

## 不要コードの洗い出し
不要コードの候補を洗い出すために、今回は[debride](https://github.com/seattlerb/debride "debride")というGemを使用しました。

debrideは静的解析によって **「使用されていない可能性のあるメソッド一覧を取得する」** というGemになっています。

サンプルにもあるとおり、コマンド一つでお手軽に可能性のあるメソッドを抽出することができます。

``` s
% debride lib

These methods MIGHT not be called:

MyClass
  good_method                         lib/some/file.rb:16
  bad_method                          lib/some/file.rb:20
```




他にも[coverband](https://github.com/danmayer/coverband "coverband"), [rubycritic](https://github.com/whitesmith/rubycritic "rubycritic") などのGemも候補に上がっていたのですが、コードに変更を加えずにコマンド一つで気軽に実行できて、導入しやすそうだったので、debrideを選択するに至りました。


[他社の事例](https://texta.pixta.jp/entry/2017/05/25/123845)を見ると、debride(静的解析) + [okuribito_rails(動的解析)](https://github.com/shakemurasan/okuribito_rails)で抽出するということもやっていたのですが、本番環境に影響を与えずに、手っ取り早く始めるためにdebrideのみで候補を抽出するという方法を取りました。

後は単純に計測のために毎回呼ばれてオーバーヘッドによる影響が怖かった。(oneshot coverageとか検討しても良かったかも？)

## とりあえずdebrideを試す
デフォルトの状態でdebrideを実行すると、routingで紐づけられているコントローラーのメソッドも未使用としてリストアップされてしまうため、意図的に候補から除外してあげる必要があります。

rails c してroutingに紐づくメソッドを下記で抽出しました。

``` rb
routes = Rails.application.routes.routes
methods = []

routes.each do |route|
  controller = route.defaults[:controller]
  action = route.defaults[:action]

  next unless controller && action

  controller_class = "#{controller.camelize}Controller".constantize

  if controller_class.method_defined?(action.to_sym)
    methods << action.to_s
  end
end
```

抽出したメソッドをwhitelist.txt に貼り付け。

optionでこちらのwhitelistを指定してあげることで、ルーティングに紐づくメソッドを除外した結果を取得できます。

``` 
debride --rails --whitelist whitelist.txt app  
```
   
実行した結果149箇所、約2000行のコードが消せる可能性ありということが検出されました。

## リストアップしてひたすら削除
これらの検出結果をリストアップして、後はチームで分担してせかせかとお掃除していきました。

使用されていない可能性のあるものが検出されているだけなので、再度該当箇所でGrepをかけて、本当に使用されていないかを実装者+レビュアー2人の3回チェックしてからリリースを行いました。

特に下記のケースに注意してました。

:::note warn
・after_commit などのコールバックで使用されていないか
・sendなどで呼び出されていないか
・ありがちなメソッド名。例えばsumという名前のメソッドみたいに、Grepすると複数箇所でてくるみたいなメソッドは簡単に判別するのが難しかったので、一旦消すのを避けました。
:::


などなど

不要テストも併せて消せたので、結果として**2153行**を消すことができました！

# 感想
「問題なければ後で消す」「これは使わないでください」みたいなコメント付きの使用されていないコードがいくつかあって、当時は消すことがタスクに積まれていたけど段々と忘れられていったんだろうなという痕跡がいくつか見つかりました。「後で戻すかも。」みたいコメントついたコードも5年前とかだったりしたので容赦なく消しました。

リストアップ後の作業自体は簡単でサクサク行くのですが、やはりまとめてやると単純作業なので、ちょっとしんどい感があります。
案件で自分が触っているファイルだけでもdebrideをかけて、ボーイスカウト・ルールに則ってちょっとずつお掃除していった方が後々楽なんだろうなと思いました。

皆さんもぜひプロジェクトの隙間で手が空いたりしたらコードのお掃除をしてみてください！ちょっと気持ちがスッキリするかも...??

追記)クックパッドなんかは「お台場プロジェクト」という名前をつけて不要コードだったりGemの削除なんかを進めていたみたいです。
https://logmi.jp/tech/articles/319343
npm testについて　npm run testとの違い

# npm testとは
npm testとはnode.js環境でよく使用するコマンドである。
- どのようなコマンド動作にするかは開発者側で決められる
- testには任意のコマンドを指定できる（任意のコマンドをnpm testに置き換えられる）
- 指定せずにこのコマンドを使っても何も返ってこない

### npm testを動作させるために何をする？
1. package.jsonをアクティブ化し
1. 必要なパッケージをインストールし
1. package.jsonの内容を一部（test）を定義する部分を書き換える

**実際の流れ**
（今回は"cowsay"というかわいい馬を表示するコマンドを用いるけど、任意のコマンドで大丈夫だよ）
1. "npm init"をコマンドラインに入力、実行
英文がたくさん表示されるが無視してEnterキーを押しまくる
1. "npm install cowsay --save-dev"を実行
1. package.jsonを
```:before
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  ```
  ```:after
"scripts": {
    "test": "cowsay"
  },
  ```
  このように変更する
なお、"test"以外にも任意のスクリプトを指定することができる。
が、任意のスクリプトを使用する際は注意が必要である（後述）。

  

 コマンドラインに"npm test hello"と入力すると...？

  ```
 _______
< hello >
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
```
このようにかわいい馬が表示される！

## npm testとnpm run testの違い

基本的にはこの2つのコマンドに大きな差異はない。
しかし、以降のことはしっかり頭に入れておく必要がある。

"test"と"start"は**特別なスクリプト**である。
"npm test"や"npm start"とコマンド入力すると動く。

しかし、"tests"や"star"と設定すると
"npm tests", "npm star"は動かない。

これらの通常のスクリプトを使う場合は、
"npm run tests", "npm run star"
と記述する必要がある。

つまり、基本的には"npm run （スクリプト名）"
と記述する必要があるのだ。

なお、"npm test"と"npm run test"は同じ出力結果を示す。
PythonでPDFのページをコピーする

PDF文書を操作する際、特定のページをコピーすることで、テキストや図表、データなどの特定の情報を抽出し、他の文書で使用することができます。また、PDFのページをコピーすることで、異なる文書内のページを抽出して新しい統合文書を作成することもできます。
この記事では、Pythonを使って同じ文書内のPDFページをコピーしたり、別のPDF文書にページをコピーしたりする方法を紹介します。

* [Pythonで同じPDF内のページをコピーする](#pythonで同じpdf内のページをコピーする) 
* [Pythonでページを別のPDFにコピー](#pythonでページを別のpdfにコピー)

>**必要なPythonライブラリ** – [**Spire.PDF for Python**](https://www.e-iceblue.com/Introduce/pdf-for-python.html)。以下のpipコマンドで直接インストールできます：
> `pip install Spire.Pdf`


## Pythonで同じPDF内のページをコピーする
Spire.PDF for Pythonライブラリは、PDF文書に新しいページを追加し、指定されたページの内容を新しいページに描画することにより、PDFページをコピーする操作をサポートします。

***主な手順：***
1.	`LoadFromFile()` メソッドで PDF 文書を読み込みます。
2.	PDF 内の指定 さ れたページ を取得 し 、 そのページ内容に基づ く テ ンプ レー ト を **`CreateTemplate()`** メ ソ ッ ド を用いて作成。
3.	**`Insert()`** メ ソ ッ ド を使っ て、 指定 し た イ ンデ ッ ク ス位置に空白の新 し いページ を挿入 し ます （あ る いは、 **`Add()`** メ ソ ッ ド を使っ て、 文書の末尾に新 し いページ を直接追加す る こ と も で き ます）。
4.	**`PdfPageBase.Canvas.DrawTemplate()`** メ ソ ッ ド を使っ て、 テ ンプ レー ト を新 し いページに描 き ます。
5.	`SaveToFile()` メソッドを使用してPDF文書を保存します。

***Pythonのコード：***
```python
from spire.pdf.common import *
from spire.pdf import *

# PDF文書を読み込む
pdf = PdfDocument()
pdf.LoadFromFile("input.pdf")

# 最初のページを取得する
page = pdf.Pages[0]

# ページに基づいてテンプレートを作成する
template = page.CreateTemplate()

# 2番目の位置に新しいページを挿入する
page = pdf.Pages.Insert(1, page.Size, PdfMargins(0.0))
# 最後に新しいページを追加する
#page = pdf.Pages.Add(page.Size, PdfMargins(0.0))

# 新しく追加されたページにテンプレートを描画する
page.Canvas.DrawTemplate(template, PointF(0.0, 0.0))

# PDF文書を保存する
pdf.SaveToFile("CopyPDFPage.pdf");
pdf.Close()
```
![CopyPDFpage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/1b6af12e-271a-449b-dcb0-f3e9ba03b2a2.png)


## Pythonでページを別のPDFにコピー
また、PDF文書から別のPDF文書に指定されたページをコピーすることができます。

***主な手順：***
1.	`LoadFromFile()` メ ソ ッ ド を使っ て 2 個の PDF 文書を読み込みます。
2.	文書 1 内の指定 し たページ を取得 し 、 そのページ内容に基づ く テ ンプ レー ト を **`CreateTemplate()`** メ ソ ッ ド を使っ て作成 し ます。
3.	**`Insert()`** メ ソ ッ ド を使っ て、 文書 2 内の指定 し た イ ンデ ッ ク ス位置に空白の新 し いページ を挿入 し ます。
4.	**`PdfPageBase.Canvas.DrawTemplate()`** メソッドを使用して、新しいページにテンプレートを描画します。
5.	`SaveToFile()` メソッドを使用してドキュメント 2 を保存します。

***Pythonのコード：***
```python
from spire.pdf.common import *
from spire.pdf import *

# ドキュメント1を読み込む
pdf1 = PdfDocument()
pdf1.LoadFromFile("日記.pdf")

# ドキュメント2を読み込む
pdf2 = PdfDocument()
pdf2.LoadFromFile("input日.pdf")

# ドキュメント1の最初のページを取得
page = pdf1.Pages[0]

# このページの内容に基づいてテンプレートを作成する
template = page.CreateTemplate()

# 文書2の指定された位置に空白の新規ページを挿入する
newPage = pdf2.Pages.Insert(0, page.Size, PdfMargins(0.0))

# 新しいページにテンプレートを描く
newPage.Canvas.DrawTemplate(template, PointF(0.0, 0.0))

# PDF文書を保存する
pdf2.SaveToFile("CopyPageToAnotherPDF.pdf")
pdf2.Close()
```
![CopyToAnotherPDF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/1c6e0139-1f98-a894-c380-ee6c3164c805.png)
* * *

生成されたドキュメントの赤いウォーターマークについては、以下のリンクをクリックして、それを削除するための1ヶ月の無料ライセンスをリクエストしてください。

https://www.e-iceblue.com/TemLicense.html