OmniAICreator/Qiita-1.07M huggingface dataset:
sql_mode=only_full_group_byとは？

# Mysql2::Error: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column　'sample_test.parent.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by (ActiveRecord::StatementInvalid)

>Mysql2::Error： SELECT リストの式 #1 が GROUP BY 節になく、GROUP BY 節の列に機能的に依存しない非集約列 'sample_test.parent.id' を含んでいます。
 これは sql_mode=only_full_group_by (ActiveRecord::StatementInvalid) と互換性がありません。
 
出典　deepl

## 自分の訳
SELECTの表現リストはGROUP BY節はありません。そしてGROUP BY句において非集計のカラムparentテーブルのidはカラムの機能上の従属関係がないカラム'sample_test.parent.id'を含んでいます
これはsql_mode=only_full_group_byと両立し難い

Expression 表現(すること)、表われ、しるし、(言葉の)言い回し、語法、語句、辞句、(顔・目などの)表情、顔つき、表情豊かなこと
not in 不在にしております；席を外しております
functionally 機能上の
dependent 従属関係の、隷属的な、
incompatible 気性が合わない、相いれない、両立しがたい、(…と)両立しないで、矛盾して

出典　weblio
# ql_mode=only_full_group_byとは？
>MySQL は、関数従属性の検出を実装しています。 ONLY_FULL_GROUP_BY SQL モードが有効な場合 (デフォルト)、MySQL は、選択リスト、HAVING 条件または ORDER BY リストが GROUP BY 句で名前が付けられておらず、機能的に依存していない非集計カラムを参照するクエリーを拒否します。

https://dev.mysql.com/doc/refman/8.0/ja/group-by-handling.html#:~:text=MySQL%20%E3%81%AF%E3%80%81%E9%96%A2%E6%95%B0%E5%BE%93%E5%B1%9E%E6%80%A7%E3%81%AE%E6%A4%9C%E5%87%BA%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82%20ONLY_FULL_GROUP_BY%20SQL%20%E3%83%A2%E3%83%BC%E3%83%89%E3%81%8C%E6%9C%89%E5%8A%B9%E3%81%AA%E5%A0%B4%E5%90%88%20(%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88)%E3%80%81MySQL%20%E3%81%AF%E3%80%81%E9%81%B8%E6%8A%9E%E3%83%AA%E3%82%B9%E3%83%88%E3%80%81HAVING%20%E6%9D%A1%E4%BB%B6%E3%81%BE%E3%81%9F%E3%81%AF%20ORDER%20BY%20%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8C%20GROUP%20BY%20%E5%8F%A5%E3%81%A7%E5%90%8D%E5%89%8D%E3%81%8C%E4%BB%98%E3%81%91%E3%82%89%E3%82%8C%E3%81%A6%E3%81%8A%E3%82%89%E3%81%9A%E3%80%81%E6%A9%9F%E8%83%BD%E7%9A%84%E3%81%AB%E4%BE%9D%E5%AD%98%E3%81%97%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E9%9D%9E%E9%9B%86%E8%A8%88%E3%82%AB%E3%83%A9%E3%83%A0%E3%82%92%E5%8F%82%E7%85%A7%E3%81%99%E3%82%8B%E3%82%AF%E3%82%A8%E3%83%AA%E3%83%BC%E3%82%92%E6%8B%92%E5%90%A6%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

>選択リストの非集計 address カラムが GROUP BY 句で指定されていないため、ONLY_FULL_GROUP_BY が有効な場合、このクエリーは無効である可能性があります:
>SELECT name, address, MAX(age) FROM t GROUP BY name;
このクエリーは、name が t の主キーであるか、一意の NOT NULL カラムである場合に有効です。 このような場合、MySQL は、選択されたカラムが機能的にグループ化カラムに依存していることを認識します。 たとえば、name が主キーの場合、各グループには主キーの値が 1 つのみであるため、その値によって address の値が決まります。 そのため、グループ内の address 値の選択にランダム性はなく、クエリーを拒否する必要はありません。
>name が t の主キーまたは一意の NOT NULL カラムでない場合、クエリーは無効です。 この場合、関数従属性を推測できず、エラーが発生します:


>mysql> SELECT name, address, MAX(age) FROM t GROUP BY name;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP
BY clause and contains nonaggregated column 'mydb.t.address' which
is not functionally dependent on columns in GROUP BY clause; this
is incompatible with sql_mode=only_full_group_by

https://dev.mysql.com/doc/refman/8.0/ja/group-by-handling.html#:~:text=%E9%81%B8%E6%8A%9E%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E9%9D%9E%E9%9B%86%E8%A8%88%20address,this%0Ais%20incompatible%20with%20sql_mode%3Donly_full_group_by

# 感想
group　byするときはselectにも列を含めなければならない。
あと英語がズタボロ
Apptainer(旧 Singularity)を使って簡単にOllamaでローカルLLMを動かす方法

## はじめに
スパコンやクラスタ環境ではApptainerが標準的に使用されています。ApptainerとOllamaを使うことで簡単にローカルLLMを動かすことができたので、手順を残します。TSUBAMEなどのスパコンを使う場合はインタラクティブキューを使用しましょう。

## 準備
- Apptainerが導入されたマシンにログインします
- メモリ容量の多いGPUマシンがいいです
- 2セッション以上同時にログインできた方がいいです(tmuxでも可)

## 実行(Apptainerを使う場合)

1. Ollamaのコンテナをダウンロードして`ollama_latest.sif`を取得します
    ```bash
    cd /your/working/directory/
    apptainer pull docker://ollama/ollama
    ```
2. Ollamaのサーバーを起動します(GPUを使用する場合は--nvが必要です)
    ```bash
    apptainer run --nv ./ollama_latest.sif
    ```
3. 新しいセッションでログインして、Ollamaを実行します。[ここ](https://ollama.com/library)から好きなモデルを選びます
    ```bash
    cd /your/working/directory/
    ./ollama_latest.sif run llama3.1
    ```

## おわり
以上の手順でApptainerとOllamaを使って簡単にローカルLLMが実行できます。Ollamaは複数GPUに自動でモデルを分散してくれるので、8GPU環境などでllama3.1:405bを動かすことも簡単にできます。
メモ4

为了实现用户按下按钮后，由Java后台调用外部API获取一个新的URL，然后在新窗口中打开该URL，可以按照以下步骤进行：

	1.	前端：JSF页面：
	•	使用一个PrimeFaces的p:commandButton来触发一个后端的动作方法。
	•	使用p:remoteCommand来异步地从后端获取新的URL并在新窗口中打开。
	2.	后端：Java后台：
	•	创建一个Managed Bean，其中包含一个用于调用外部API的方法。
	•	该方法返回新的URL，并将其传递给前端。

前端：JSF页面

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui">
<h:head>
    <title>Redirect Example</title>
    <h:outputScript>
        function openNewWindow(url) {
            window.open(url, '_blank');
        }
    </h:outputScript>
</h:head>
<h:body>
    <h:form>
        <!-- 按钮点击触发后端方法 -->
        <p:commandButton value="获取并打开新页面" actionListener="#{myBean.getExternalUrl}" oncomplete="openNewWindow(xhr.responseText)" />
        <!-- 隐藏的remoteCommand用于获取新的URL -->
        <p:remoteCommand name="openNewWindow" action="#{myBean.getExternalUrl}" oncomplete="openNewWindow(xhr.responseText)" />
    </h:form>
</h:body>
</html>

后端：Java后台

import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import javax.faces.application.FacesMessage;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;

@ManagedBean
public class MyBean {

    // 方法用于调用外部API并返回新的URL
    public void getExternalUrl() {
        String apiUrl = "https://api.example.com/getUrl";
        String newUrl = "";

        try {
            // 创建URL对象
            URL url = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.connect();

            // 检查响应码
            int responseCode = conn.getResponseCode();
            if (responseCode != 200) {
                throw new RuntimeException("HTTP GET 请求不成功，响应码: " + responseCode);
            } else {
                // 读取响应
                Scanner sc = new Scanner(url.openStream());
                while (sc.hasNext()) {
                    newUrl += sc.nextLine();
                }
                sc.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 将新的URL写入响应以便前端JavaScript使用
        FacesContext.getCurrentInstance().getExternalContext().getResponseOutputWriter().write(newUrl);
        FacesContext.getCurrentInstance().responseComplete();
    }
}

解释

	1.	JSF页面：
	•	p:commandButton：点击按钮触发后端方法getExternalUrl。
	•	p:remoteCommand：隐藏的远程命令，用于从后端异步获取新的URL并在新窗口中打开。
	•	openNewWindow：JavaScript函数，用于在新窗口中打开传递过来的URL。
	2.	Java后台：
	•	getExternalUrl方法调用外部API获取新的URL，并将其写入响应，这样前端可以在oncomplete事件中获取到新的URL并在新窗口中打开。

这样，整个流程就实现了用户按下按钮后，Java后台调用外部API获取一个新的URL，并在新窗口中打开该URL。
【Git】 ファイル名を変更するとmainブランチに移動できない現象への対応方法

私の環境だとなぜか必ず起こる現象なのでここに記録しておきます。

:::note info
前提
commit前の変更なし＆すべてpush済
mainブランチにマージ済
:::

### 起きていること
mainブランチに移動しようと思うと下記のようなエラーが発生します。
変更がないから退避もできません。
ファイル名を変更しているときに必ず発生して困っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816029/a16e01be-64d8-205e-5043-98f55189b4ac.png)


### 対応策

一旦ファイル名を元に戻し、commitしてpushする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816029/4a5cd355-ceab-8083-f50b-d08b76c30336.png)

するとmainブランチに移動できる。

:::note warn
リモートリポジトリでこの変更を内容をmainにマージしない
:::

今度はリモートリポジトリの情報をローカル環境に反映させたいけど、普通にgit pullしようとしたら

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816029/28bcde31-b2ab-5291-b502-ec43fae00857.png)

できない。

なので、下記のようにします。


①リモートリポジトリの最新の状態を取得。
`git fetch origin`

②リモートリポジトリの内容でローカルリポジトリを上書きする
`git reset --hard origin/main`


これでOKです！！
正直毎回面倒くさいですが、これしか方法わからないので、根本的な解決方法があればぜひ知りたいです。
boxとは？


boxの備忘録。

## boxとは？
boxはクラウドストレージツールの一つ。オンラインでのファイル共有サービスですね。
boxはシンプルな操作感でありながら多くの機能を兼ね備えたツールです。

## 登録・プラン
boxは無料で登録、利用することができます。
大まかに個人・チーム向けプランとビジネスプランの二つあります。
有料プランになると利用できる機能が増えます。
ストレージ容量の上限、アップロードするファイルサイズの上限が変わってきます。
詳細な金額については、boxのページを参照してください。

https://www.box.com/ja-jp/pricing/individual

## boxでどんなことができるの？
boxではクラウド上のストレージにファイル、フォルダを格納することができます。
さらに文書ファイルのみならず、写真や動画、スライド、PDFなどさまざまなデータのアップロードが可能です。
管理者アカウントにてファイルやフォルダへのアクセス権限をユーザー単位で設定できるため、セキュリティ面の心配もありません。
MS Office 365やGoogle Workspace、salesforceなど、さまざまなアプリと連携しているので、業務の効率化が期待できます。

アクセス権は７段階まで付与が可能です。

|   |   |   |   |   |   |
|:-:|:-:|:-:|:-:|:-:|:-:|
|アクセス権|ファイルの編集|ダウンロード|アップロード|プレビュー|ユーザの招待|
|共同所有者| ◯ | ◯ | ◯ | ◯ | ◯ |
|編集者| ◯ | ◯ | ◯ | ◯ | ◯ 
|ビューアー/アップローダー| ◯ | ◯ | ◯ | ◯ | ✕ 
|プレビューアー/アップローダー| ✕ | ✕ | ◯ | ◯ | ✕ 
|ビューアー| ✕ | ◯ | ✕ | ◯ | ✕ 
|プレビュアー| ✕ | ✕ | ✕ | ◯ | ✕ 
|アップローダー| ✕ | ✕ | ◯ | ✕ | ✕ 

このように細かく権限を分けることができ、ユーザー自身に権限のないファイルやフォルダは画面に表示されない仕様なので、ここでもセキュリティ面での利点があります。

## boxの機能

#### ファイルやフォルダのアップロード・ダウンロード機能
Boxにはファイルやフォルダのアップロード・ダウンロード機能があります。
アップロード方法
・対象を選択して「アップロード」または、「開く」を押すだ。データを複数選択すれば、一括アップロードも可能。
ダウンロード方法
ダウンロードしたいファイルやフォルダを選択し、メニューから「ダウンロード」を選択。
アップロード操作と同様に、複数のファイルやフォルダーを選択すれば一括ダウンロードも可能。
ダウンロードしたファイルはzipファイルとして圧縮され、でダウンロードされるので、解凍して展開すると対象データを閲覧できます。

#### ユーザー間のファイル共有(方法は２つ)
Boxではユーザー間でのファイル共有が可能。ファイル共有の方法には次の2つ。

**1.ユーザーの招待**
**2.共有リンクの発行**

ユーザーの招待によって共有する場合は、アクセス権限などを細かく設定できます。権限の付与内容によっては、コメントやメンションなどを利用した共同作業も可能です。

共有リンクは対象ファイルのリンクを発行し、そのURLを相手に教えることで共有できます。リンクの共有方法は２つあります。

#### BoxDriveによる自動アップロード
「BoxDrive」とはBoxを高速に利用できるアプリ。
ブラウザを利用することなくBoxファイルへのアクセスを可能。アプリ上でのデータの編集や追加、削除も可能です。

同期していればファイル更新した際に自動的にアップロードしてくれるため、更新を忘れて更新データを喪失するといった状況も回避できます。

#### メールによるアクション通知
メールによるアクション通知を設定可能
Box内のファイルやフォルダに変更があった場合に、変更内容を自動でメールしてくれる機能。
フォルダごとに詳細に通知設定することも可能です。
編集や削除の履歴がリアルタイムで通知されるので、セキュリティ対策にもなります。

複数ユーザーとデータを共有している場合は設定しておくべき機能。

## まとめ
PJが大きくなる程、ファイルの最新化やセキュリティが重要になるので、PJの円滑な推進のためのツールがbox
個人・チーム、ビジネスでのプランが豊富なので、用途に応じたプランの選択が可能
事前知識を必要としない(ツール機能の理解はさておき)ので、導入が容易にできる。
【UiPath】AI Center におけるトレーニング結果（スコア）の見方

# はじめに

- 本記事では、AI Center におけるトレーニング結果（スコア）の見方を紹介します。
- 記事の内容は、個人の見解または確認結果であり、UiPath の公式見解ではありません。
- 製品仕様や参考画像は 2024年7月26日時点のもので構成しています。

# トレーニング結果はどこでみるの？

![スコアの見方1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/0dfc1327-4608-f75f-6dc8-d3453eae152b.jpeg)

AI Center でモデルの学習（トレーニング）は『パイプライン』画面でおこないます。
トレーニングの結果はパイプラインの処理単位の詳細画面で確認できます。

確認できるもの：
- トレーニング処理のログ
- 評価データ

前者は「パイプライン レポートをダウンロード」ボタンを押下して取得します。
後者は出力セクションの「artifacts」 ＞ 「eval_metrics」の順にクリックし、次の評価データを取得します。

- evaluation_{ドキュメント種類}.xlsx
- evaluation_F1_{ドキュメント種類}.txt
- evaluation_scores_{ドキュメント種類}.txt

（評価エクセルの取得手順例）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/08e37788-2cbb-e4e3-c250-758ed8887634.png)

## evaluation_F1_{ドキュメント種類}.txt

![スコアの見方2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/60d86257-50e1-1980-95d7-a66757894a6e.jpeg)

フィールド毎のF1スコアを含みます。
F1スコアは次の様な計算式で算出されるものです↓↓

- ***精度（accuracy）***：全データのうちの正解率。偏ったデータの場合信頼性低い
（TP＋TN）／（TP＋TN＋FP＋FN）
- ***適合率（precision）***：Positiveと予測されたものがどれだけ実際にPositiveだったか
TP／（TP＋FP）
- ***再現率（recall）***：本当にPositiveだったもののうち、Positiveと予測されたものの割合
TP／（TP＋FN）
- ***F-Score（fscore）***：適合率と再現率の調和平均。精度よりもいい基準といわれる
2＊（適合率＊再現率）／（適合率＋再現率）

![スコアの見方3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/f7c231d0-3ae4-525e-7a1f-e6640f735bf7.jpeg)

## evaluation_scores_{ドキュメント種類}.txt

![スコアの見方4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/d1d55918-6070-f830-06bc-6b6ed1d807d7.jpeg)

先に説明したF1スコア（fscore）と精度（accuracy）を含みます。
筆者がEXCELで実際の全体精度を確認した経験則からは、F1スコアの方が実際の傾向と相関関係があります。

## evaluation_{ドキュメント種類}.xlsx

### Summaryシート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/df173d96-1daf-9183-4312-ae33291a2920.png)

1. 上段（赤枠）の「Accuracy（正確性）」スコアを確認する。　※Batch列の最初のレコード（All 〇〇 ）が全体のスコアを現します。2行目以降はインポート毎の評価です。
1. 下段（青枠）の最初のレコード（All 〇〇）の各フィールドのスコアを確認する。
スコアを確認した結果：
    - 前回より、いずれのスコアも向上している　→　MLスキルのデプロイに進む
    - 全体スコアは上がったが、一部のフィールドでスコアが下がった　→　ラベリングが正しいか、また学習量の少ないレイアウト（10枚未満）の有無の確認。再学習の実施。
    - 全体および多くのフィールドでスコアが下がった　→　ラベリングや学習量に問題がない場合、再学習およびデプロイは実施しない。

### Regular & Classification Fieldsシート / Column Fieldsシート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/17dfc34c-1121-b2bf-88d3-4a599e9351a3.png)

1. 評価ファイル（※1）毎に各フィールドの「自動抽出結果」「正解値（ラベル付けした値）」「信頼度」「正確性スコア」が並びます。
1. 「信頼度」はUiPathの独自ロジックの判定結果も加味しますが、ラベル付けを正とし、「正確性スコア（赤枠）」を確認します。
1. 「正確性スコア（赤枠）」が「1」以外のものは、抽出結果に問題があるため、「正解値（青枠）」と値を比較します。（※2）
1. 「正解値（青枠）」に問題がない場合、同種のレイアウトを追加で投入し、再学習を実施します。

::: note
※1：再学習をおこなう際は、前回・前々回からのスコアの推移をみます。この際、異なるデータセットが評価ファイルに指定されることを避けるため、評価用のデータセットを別途用意してインポートしましょう。（ドキュメントをインポートする際に「これを評価セットにする」のチェックを入れましょう）なお、評価セットが未指定の場合、全体の2～3割のデータセットを自動選定してトレーニングが実施されます。

※2：「正解値（青枠）」はユーザーのアノテーション作業で指定された値のため、100%正解ではない可能性があります。このため、「正確性スコア（赤枠）」が「1」でない場合、まずはアノテーションが正しくおこなわれているかをご確認ください。
:::

# さいごに

いかがでしたでしょうか。
アクティブラーニングでは、フィールド毎の各種スコアは確認できるものの評価データの詳細を出力できません。（これがないとトレーニング後のスコアを分析できません。）
AI Center は初学者には内容や操作がわかりにくいつくりになっていますが機能は充実しています！AI Center の機能が早くアクティブラーニングに吸収されることを期待します！
最後までお読みいただきありがとうございます(・ω・)ノ
【Rails・slim】link_toについて

# 概要
link_toがわからない人に届いて欲しい　※slim記述
[ドキュメント](https://railsdoc.com/page/link_to)に大体書いてあります。

# link_toとは
`ハイパーリンク(hyperlink)`[^1]を生成するへルパーメソッド
RailsではHTMLのaタグを生成してくれる


[^1]:**ハイパーリンク(hyperlink)** 
    ・文書データに埋め込まれている他ページの参照情報
    
    **ハイパーテキスト(hypertext)**
    ・ハイパーリンクの情報を参照して別のページに移動する仕組み

    上記2つを合わせてWEBページに関係性をもたせる。
    HTMLは『**HyperText Markup Language(ハイパーテキスト・マークアップ・ランゲージ)**』の略
    <br>


# 使い方
以下のように記載します
~~~html
  <%= link_to "表示名", "URL or パス" %> 
~~~
・slimの場合
~~~slim
  = link_to "表示名", "URL or パス"
~~~

いろんな書き方
以下の書き方なら表示部分に図などを追加することも可能
~~~slim
  = link_to "URL or パス"
    | 表示部分
~~~
~~~slim
  = link_to "URL or パス"
    = "表示部分"
~~~
~~~slim
  = link_to "URL or パス"
    p 表示部分
~~~



# URLとパス
第二引数の部分には`URL、パスどちらでも可能`

・URLの場合
~~~slim
  = link_to "Googleへ行く", "https://www.google.co.jp/"  
~~~
[`Googleへ行く`](https://www.google.co.jp/)

・パス(PATH)の場合
~~~slim
  = link_to "Qiitaのタイムラインへ行く", "/timeline"  
~~~
[`Qiitaのタイムラインへ行く`](/timeline)
<br>
**※同じアプリケーション内ならルーティング[^2]を使用したほうがいい**
~~~slim
  = link_to "ユーザー一覧", "users#index"
~~~
~~~slim
  = link_to "ユーザー一覧", users_path
~~~

[^2]: ルーティングの確かめ方　
・**/config/routes.rb**  のファイルで確認
・エラー画面のルート一覧
・コマンドで【 $ rails routes 】





# class
以下のように記載する
~~~slim
  = link_to "表示名", "URL or パス", class: "クラス名"
~~~

# method
HTTPメソッドを指定していない場合、作成したリンクは`GET`となる。
他のHTTPメソッドを付与することも可能

以下のコードは`DELETE`(削除)を付与している
~~~slim
  = link_to "削除する", user_path(params[:id]), method: :delete
~~~

このリンクを作動させるとユーザー情報を消すことができる




# 参考サイト
https://railsdoc.com/page/link_to

https://developer.mozilla.org/ja/docs/Learn/Getting_started_with_the_web/HTML_basics
pyenvでshimsを使用せずにコマンドを利用する方法

`pyenv`は、Pythonのバージョン管理を容易にするためのツールですが、デフォルト設定ではシム（shims）ディレクトリを経由してコマンドを実行するようになっています。しかし、特定の状況ではシムを使用せずに、`pyenv`のコマンドのみを利用したい場合があります。本記事では、その設定方法について解説します。

---

# 目次

1. `pyenv`とは
2. シム（shims）ディレクトリとは
3. シムを使用せずに`pyenv`を利用する方法
4. 設定の確認方法
5. まとめ

---

# 1. `pyenv`とは

`pyenv`は、複数のPythonバージョンを簡単に切り替えられるツールです。これにより、プロジェクトごとに異なるPythonバージョンを使用することができます。

# 2. シム（shims）ディレクトリとは

`pyenv`は、インストールされたPythonバージョンを切り替えるためにシムディレクトリ（`$HOME/.pyenv/shims/`）を使用します。このディレクトリには、実行可能ファイルが含まれており、実行時に適切なPythonバージョンを選択します。

# 3. シムを使用せずに`pyenv`を利用する方法

シムを使用せずに`pyenv`のコマンドのみを利用するためには、シェルの設定ファイルを編集して`~/.pyenv/bin`をPATHに追加し、`~/.pyenv/shims`を除外します。以下にその手順を示します。

## 手順

1. **シェルの設定ファイルを編集する**:
   使用しているシェルに応じて、`.bashrc`や`.zshrc`などの設定ファイルを開きます。

   ```bash
   nano ~/.bashrc  # Bashの場合
   nano ~/.zshrc   # Zshの場合
   ```

2. **PATHの設定を調整する**:
   `pyenv`の初期化設定を変更して、`~/.pyenv/bin`をPATHに追加し、`~/.pyenv/shims`を除外します。

   ```bash
   # ~/.bashrc または ~/.zshrc
   export PYENV_ROOT="$HOME/.pyenv"
   export PATH="$PYENV_ROOT/bin:$PATH"

   # eval "$(pyenv init --path)" および eval "$(pyenv init -)" の行をコメントアウトまたは削除
   # eval "$(pyenv init --path)"
   # eval "$(pyenv init -)"
   ```

3. **シェルの設定を再読み込みする**:
   設定ファイルを保存して閉じた後、シェルの設定を再読み込みします。

   ```bash
   source ~/.bashrc  # Bashの場合
   source ~/.zshrc   # Zshの場合
   ```

## 実行例

以下は、`.bashrc`の一部を編集する具体的な例です。

```bash
# ~/.bashrc

# pyenvの設定
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"

# pyenvの初期化部分をコメントアウト
# eval "$(pyenv init --path)"
# eval "$(pyenv init -)"
```

# 4. 設定の確認方法

シェルを再読み込みした後、`pyenv`のバージョン確認コマンドを実行して、正しく設定されているか確認します。

```bash
which pyenv
# 出力が /home/your_username/.pyenv/bin/pyenv であることを確認

echo $PATH
# 出力に /home/your_username/.pyenv/shims が含まれていないことを確認
```

# 5. まとめ

この設定により、`pyenv`の`~/.pyenv/bin`内のコマンドは使用可能ですが、`~/.pyenv/shims`内のコマンドはPATHに含まれないため使用されません。これにより、特定の状況において`pyenv`をより柔軟に利用することが可能になります。

---
以上の記事は、ChatGPT4oにより執筆されました。
Workato：日付間より年数を計算する

# はじめに

社員データや顧客データWorkatoで扱う際、誕生日や勤続年数、サービス継続年数、法人の事業年数など、何らかの経過年数などを取得したい場合があるかと思います。

年数の計算は閏年を考慮しなければならず、閏年とそうでない年では日数が異なるため、単純に時間や日数をもとに計算を行うことはできません。

Workatoにおいて年数の計算方法は様々ありますが、Pythonコネクタを利用すると、コードを書く必要はあるものの、シンプルに年数計算のための処理を用意することができます。また、Recipe Functionとして作成して共通処理化（モジュール化）することで、様々なレシピで共通して活用する（再利用性を高める）ことができます。

今回は、再利用性の観点から、Recipe Functionで年数計算処理の実装を進めていきます。

# レシピ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/960d5c84-07fe-4d0b-1f0d-6a640557d01e.png)

## Step1（トリガー）
- Parameter schemaに `date_from` `date_to` をdate型で追加
- Result schemaに `year` を integer型で追加

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/1b0a4539-5204-1e86-660c-e1137c7e35c8.png)

## Step2

Pythonコネクタを追加し、次の通り設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/20e75f54-791c-953c-a53a-ed9ad96da782.png)

### Name
- 任意の値を入力します。

### Input fields
- `date_from` `date_to` をString型で追加します。
- Step1のParameter schemaのデータピル（`date_from` `date_to`）を、対応するフィールドへ追加します。
- 各フィールドを formulaモードに切り替え、それぞれのデータピルの後ろに `.strftime("%Y-%m-%d")` を追加します。

### Output fields
- `year` を `Integer`型で追加します。

### Code

```python
from datetime import datetime

def main(input):
    date_format = '%Y-%m-%d'

    date1 = datetime.strptime(input['date_from'], date_format)
    date2 = datetime.strptime(input['date_to'], date_format)
    
    years_difference = date2.year - date1.year
    
    if (date2.month, date2.day) < (date1.month, date1.day):
        years_difference -= 1
    
    return {'year': years_difference}
```

## Step 3

yearフィールドに、Step2の`year` データピルを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/3b9bc186-de40-0099-7e54-f74beeb4aba1.png)

# 実行結果

Test recipe で次の条件を設定してレシピをテスト実行すると、指定された日付間の年数が結果として返されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/39ddff55-e107-6bee-d339-c9927f71eaf5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/e09e1ded-6099-5729-ba19-16fa38bb1797.png)
家庭向けネットワーク器機のWindowsによる簡易死活管理

# アクセスポイントがたまーにフリーズ
自宅には数カ所Wi-Fiアクセスポイントを配置しています。そのひとつが、たまーに、だいたい２週間に一度くらい動作してないような状況に陥っていました。

電源を入れ直し再起動すれば当然復活。ですが、使い勝手は当然よろしくありません。しかし、この状況でサポートに連絡しても、当然、とりつく島もないわけです。
# サポートで問題点を把握してもらうには？
動作しなくなっているログをとるしかありません。
しかし、使っているネットワーク器機は仕事場で使っているような高機能なものではなく、量販店で販売しているような製品。超簡易的なログ機能はあるものの、syslog的な機能、特に外部に定期的に送信するような機能は無い製品でした。

## 死活監視を自宅ネットワーク内で実施する
では、外部からの死活監視！ということになるわけですが、インターネットに公開されている器機であれば、pingなりhttpアクセスなり、を特定IPアドレスに対して実施するサービスはあるわけですが、自宅内のネットワークの監視には使えません。ということで、別方法の模索しました。
## Windows機による定期的なping
24時間雨後かしっぱなしのWindows機が自宅内にあるので、そこからpingを定期的に実施してみるように計画しました。
Pingで監視だとlinuxなんかの方がやりやすいとも思いますので、最善の方法ではないですし、普段使いするような方法ではないですが、状況的にもっともやりやすかったのでWindowsを使っています。
## ping 結果をファイルに保存するバッチファイルを作る
今なら、Powershellで実装するんでしょうね。私自身が、オールドタイプなので、バッチファイルで対応しました。

``` ping.bat
echo ----------------------------------- >>ping.log
echo %time% >> ping.log
echo %date% >> ping.log
ping -n 1 192.168.XXX.XXX >> ping.log
```
かなり原始的な方法ですが、とりあえず、日時がわかるようにpingで死活監視をして結果をファイルに保存しています。正直、整形したかったのだけれども面倒くさかったのでそのままにしてます。

## Windowsタスクスケジューラーに登録
上記バッチをタスクスケジューラで起動するようにスタートアップと起動間隔を設定。これで一応ログを取得できるようになりました。

# ログを元にサポートセンターで問題解決
結果、フリーズするのを証明するのには十分だったようです。無事、機器交換になりました。

より洗練された、自宅内死活監視は方法はあるとは思いますが、自身の備忘録まで。
Visual Studio Code WSL のターミナル文字コード

# ターミナルの文字列コードが、en_US.UTF-8 になってしまう
WSLの設定では、localeの設定をしていて、Windows ターミナルから開くときの文字コードは、ja_JP.UTF8 になっているが、VSCode から開くターミナルでは、en_US.UTF-8 になってしまいます。
.bashrc の最後の行に、
```
export LANG=ja_JP.UTF-8
export LANGUAGE=ja
```
を追加します。
日付と時間の間の`T`について

## 疑問

日時を `20240726T09:00:00` や `2024-07-26T09:00:00` と表すとき、この日付と時間の間の`T`が何を意味しているのか気になりました。

## 調査結果

日時表現における"T"は、日付と時間の区切りを示す文字です。この形式はISO 8601規格に基づいており、標準的な方法で日付と時間を表現します。

具体的には：
- `20240726` は日付部分を表し、これは2024年7月26日を意味します。
- `T` は日付と時間の間の区切り記号です。
- `09:00:00` は時間部分を表し、これは午前9時0分0秒を意味します。

したがって、`20240726T09:00:00` は2024年7月26日の午前9時0分0秒を示しています。ISO 8601では、この`T`を使用することで日付と時間を明確に区切り、一つの文字列として一貫した形式で表現することができます。
Dockerでgoのマルチステージビルドでexisted(0)で落ちる件を解決した

## 初めに
筆者はDocker初心者であんまりDockerについて理解してません。ご了承ください

## 結論
必要なファイルは実行用コンテナにもコピーしよう
```dockerfile
COPY --from=builder /app/config ./config
```

## 経緯
- あるプロジェクトでgoの環境を作る必要があった
- 容量が1GB近くとかなり大きいイメージだった
- CI/CDを意識すると容量を削減したいと考えていました

## マルチステージビルド
調べていく中でマルチステージビルドというものがあるのを発見
これを使おうとしました
## existed(0)の症状
- マルチステージビルドを使わない環境だと立ち上がる
 ```dockerfile
FROM golang:1.20-alpine
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o /main ./cmd
 ```
- マルチステージビルド環境で立ち上がらない
```dockerfile
FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o /main ./cmd

FROM gcr.io/distroless/base-debian12
WORKDIR /app
COPY --from=builder /main .
EXPOSE 8080
CMD [ "./main" ]
```
## マルチステージビルド環境って実行ファイルしかないやんけ!!

そうです
ビルドステージ環境ではCOPY行で全てをコピーしてきてるので自分のpcのディレクトリ構造とまんま同じです
しかし、マルチステージ環境は言わばまっさらなのでコピーしてこないと存在しません
## 問題の箇所
- main.go内部でenvを読み込んでいた
```go:main.go
package main
func main() {
	
	err := godotenv.Load(fmt.Sprintf("config/%s.env", env))
	if err != nil {
		return
	}
 }
```
## 最終的なDockerファイル
```dockerfile
FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o /main ./cmd

FROM gcr.io/distroless/base-debian12
WORKDIR /app
COPY --from=builder /main .
COPY --from=builder /app/config ./config
EXPOSE 8080
CMD [ "./main" ]
```
## 所感
誰もenvを読み取り開発用と本番用で分けることをしていなかったのかなかなか真実にたどりつきませんでした
nginxのエラーログにSSL_read() failed (SSL: error:0A000126:SSL routines::unexpected eof while reading) while keepaliveが溢れているとき

## 解決策

nginxのversionを1.22にあげたら直ります。

https://github.com/openssl/openssl/issues/18866

open sslのバージョンが高くてnginxのバージョンが低いとなるっぽい？
ウェブサイト分析とSEO最適化のためにCharles Proxyを使用してreCAPTCHA v3ページアクションを特定する方法

## ウェブサイト分析とSEO最適化のためにCharles Proxyを使用してreCAPTCHA v3ページアクションを特定する方法
![recaptcha-v3-page-action.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3792743/9c1cef75-f93a-5d0c-aca3-0db305816f44.png)

Charles Proxyを使用してreCAPTCHA v3ページアクションを見つけるためには、以下の手順に従ってください：

1. **Charles Proxyをインストール**:
   - [ここ](https://www.charlesproxy.com/download/)からCharles Proxyをダウンロードしてインストールします。

2. **Charles Proxyを設定**:
   - Charles Proxyを起動します。
   - `Proxy` > `Proxy Settings` に移動します。
   - 通常ポート `8888`でプロキシ設定を行います。

3. **SSLプロキシの設定**:
   - `Proxy` > `SSL Proxying Settings` に移動します。
   - `Add`をクリックし、すべてのSSLトラフィックをキャプチャするために `*` を入力します。あるいは、`google.com`や`recaptcha.net`などの特定のドメインを指定することもできます。
   - `Help` > `SSL Proxying` > `Install Charles Root Certificate`からCharlesのSSL証明書をマシンとブラウザにインストールします。

4. **トラフィックをキャプチャ**:
   - ウェブブラウザを開き、Charlesをプロキシとして使用するように設定します（通常、Charlesブラウザ拡張機能を使うか、ブラウザのプロキシ設定で手動で行います）。
   - reCAPTCHA v3が実装されているウェブページに移動します。

5. **reCAPTCHAリクエストをフィルタリングして見つける**:
   - Charlesで`recaptcha.net`や`google.com/recaptcha`へのリクエストを探します。
   - reCAPTCHAリクエストには通常、`action`や`token`などのパラメータが含まれます。
   - これらのリクエストをクリックして詳細を確認します。

6. **ページアクションを特定する**:
   - リクエストペイロードの中で`action`パラメータを探します。このパラメータは、reCAPTCHA v3リクエストのアクション名を示し、ウェブページで指定されたアクション（例：`login`、`signup`、`checkout`）に対応します。

特定のリクエストを調査するための手順は以下の通りです：

1. **リクエストを見つける**:
   - Charlesのメインウィンドウで、すべてのキャプチャされたリクエストのリストが表示されます。
   - `recaptcha.net`または`google.com/recaptcha/api2`へのリクエストを見つけます。

2. **リクエストを調査**:
   - 関連するリクエストをクリックして詳細を展開します。
   - `Request`タブに切り替えて、送信されるパラメータを確認します。

3. **`action`パラメータを見つける**:
   - リクエストボディまたはクエリ文字列で`action`という名前のパラメータを探します。
   - このパラメータの値は、reCAPTCHA v3実装で定義されたアクション名を表します。

### 結論

これらの手順に従うことで、reCAPTCHA v3リクエストをキャプチャして調査し、サイトで使用されているページアクションを特定することができます。この情報は、ウェブサイト分析やSEO最適化にとって有用です。reCAPTCHA v3の実装方法を理解することで、ユーザーインタラクションを評価し、サイトの機能性を向上させることができます。

自動化されたキャプチャ解決には、[NextCaptcha](https://nextcaptcha.com/)を検討してください。NextCaptchaは、reCAPTCHA v2、reCAPTCHA v2 Enterprise、reCAPTCHA v3、CAPTCHA Mobile、FunCaptchaなど、さまざまなタイプのキャプチャをサポートする強力なキャプチャ解決サービスです。NextCaptchaを使用すれば、自動スクリプトやプログラムでさまざまなキャプチャチャレンジを簡単に解決できるため、ウェブ自動化タスクの効率化に最適なソリューションです。
Crowdstrikeブルースクリーン問題を振り返っておく

情シス目線で起きていたことと、今回の改善方法の整理をする。

概要はCS社のブログ記事に任せる。
　https://www.crowdstrike.jp/technical-details-on-todays-outage/

## 技術概要
7/19 13:09(JTC) ～ 7/19 14:27(JTC) の間にFalconセンサーをインストールしたWindows端末に何が起きていたのか。
Falconセンサーはインターネット上にあるCrowdstrikeのサーバーと定期的な通信をしており、チャネルファイルの更新を行っているものと思われる。
今回問題になった削除しろと指示されているファイル「C-00000291*.sys」の詳細はこんな感じ。

　C-00000291-00000000-00000025.sys
　　→やばいファイル第一弾
　C-00000291-00000000-00000026.sys
　　→やばいファイル第二弾
　C-00000291-00000000-00000027.sys
　　→修正版ファイル

それぞれ末尾がバージョンのようで、7/19 13:09(JTC) に ～25.sys が配信された。
この 25.sys でチャネルファイルを更新してしまった端末はブルスク状態に陥る。
同様に14:00くらいに 26.sys が配信されていたようだが、これも問題解決には至っておらず 26.sys で更新された端末もブルスクになる。
14:27以降に配信されたのが 27.sys になっており、最終的にこのチャネルファイルになっていればブルスクを回避できる。


## 復旧手順概要
直接的な内容としては上に書いた通り、何らかの手段にて問題となっているチャネルファイルを削除すればよい。
`del C-00000291-00000000-00000025.sys`
 `del C-00000291-00000000-00000026.sys`
または
 `del C-00000291*.sys`

が、エンタープライズ環境においてはこれをするためのハードルが高くなるケースが多い。


## ハードルが高い理由＝Bitlocker回復キー問題
エンタープライズ環境である場合、ActiveDirectoryで管理しているケースが多い。
Bitlockerで保護された端末はセーフモード立ち上げ時にBitlocker回復キーを要求されるのだが、オンプレミスADにBitlocker回復キーが格納されており、通常はユーザー側がそれを参照する権限を持つことは無いので何らかの対応が必要となる。

1. Bitlocker回復キーを出力しユーザー側へアナウンスする
2. Microsoft署名済のMicrosoft Recovery Toolを使いUSBブートから復旧する
3. Intune管理端末の場合、マイアカウントからBitlocker回復キーを参照させる


### 1. Bitlocker回復キーを出力しユーザー側へアナウンスする。
即効性があり簡単ではあるものの、Bitlocker回復キーをユーザーに周知させる形となってしまいセキュリティとしては良い状態ではない。
Bitlocker回復キーの再発行を行う必要があるが、ドメインコントローラーではなく端末側からのコマンド実行が必要になるため、実行方法を考えなければならなくなる。

### 2. Microsoft署名済のMicrosoft Recovery Toolを使いUSBブートから復旧する。
ツールを使うとBitlocker回復キーの入力することなく復旧することが可能。
ただし物理的にその端末の前に行ってUSBブートしないといけないので、マンパワーによる人海戦術が必要となる。
オフィス内にある端末はすぐ対応は可能だが、リモートワーク中の端末は持ちこみor別対応が必要となる。

### 3. Intune管理端末の場合、マイアカウントからBitlocker回復キーを参照させる。
https://myaccount.microsoft.com/device-list
端末がIntune管理されている場合、M365のマイデバイスの一覧にデバイス名がありBitlocker回復キーが表示されているのでこれを利用する。
ただしポータルへのアクセスを条件付きアクセスなどで「Intune端末のみ」としている場合、手元のPCがブルースクリーンになっているため、正規端末でのアクセスができないという状態になってしまっているはずなので、一時的に条件付きアクセスを緩くするなどの対応が必要。

## まとめ
どの復旧方法を使うかは、各環境における端末台数や業務形態によると思うのでこれといった正解は無い。
どれも一時的に何かを緩くしたり、対応のための人員を多く用意するなどのデメリットがあるので、それぞれ組織でマッチする方法を考える必要がある。
【Git】すでにコミット済みの内容に修正を入れたい場合【Fork】


# はじめに
普段Forkを利用しているのですが、インタラクティブリベースについての記事がなかったようなので、よく使いそうな機能についてまとめました

:::note warn
注意

複数人で開発を行っている場合、すでにプッシュ済みのコミットに対して行うと、他社の作業に影響を及ぼす恐れがあるため行わないようにしてください。
https://www.atlassian.com/ja/git/tutorials/rewriting-history/git-rebase
:::

# 環境
- Fork Version 2.43.1

## コメントの修正
例えばtest3.txtというファイルを追加したのにコメントは「test4.txtを追加」となっていて、
「test3.txtを追加」というコメントに変えたい場合
![スクリーンショット 2024-06-12 15.58.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2125059/966a52a3-2aa4-92f7-b19c-a9b9706a7dcf.png)

対象のブランチを右クリックして 「**Reword Message...**」を押下
![スクリーンショット 2024-06-12 15.59.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2125059/53c32ebb-7ce2-62dd-be2c-7ded91c13750.png)

任意のコメントに変更して、「**OK**」、右下の「**Rebase**」を押下でコメントが変更されます
![スクリーンショット 2024-06-12 16.13.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2125059/ac377b15-aff9-4595-2696-4fe3d1b37bb0.png)


## 不要なコミットの削除
対象のブランチを右クリックして 「**Drop...**」を押下
![スクリーンショット 2024-06-12 16.20.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2125059/c104ff1b-e2be-1dff-3c7b-2d9eb121f68f.png)

対象のコミットに打ち消し線が出ていることを確認したら、右下の「**Rebase**」を押下で削除されます
![スクリーンショット 2024-06-12 16.20.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2125059/6c05f909-1602-f1e7-5f6b-1f746c474ec9.png)

## ファイルの追加を忘れてしまった、変更したい
対象のブランチを右クリックして 「**Edit...**」を押下
![スクリーンショット 2024-06-12 16.38.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2125059/c3953174-c3c4-9805-2aa7-ef5667997250.png)

対象のコミットに打ち消し線が出ていることを確認したら、右下の「**Rebase**」を押下で、指定のコミットの編集できる状態になります
![スクリーンショット 2024-06-12 16.39.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2125059/73d62a9a-101e-acc7-e5b7-fc7e2daa6e22.png)

今回は、以下の作業を追加でしてみます
- ファイルの追加
- test2.txtを編集
- コミットメッセージの編集

![スクリーンショット 2024-06-12 16.40.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2125059/5e565735-b590-93b7-ab5f-8e1a37ed3b7d.png)
編集が終わったら、「**Amend Last Commit**」を押下

移行のコミットは変更がないので、「**Continue Rebase**」を押下していく


# 終わりに
インタラクティブリベースを行うと、修正のためだけのコミットを行うことなく修正を入れられるため、コミット履歴をきれいに保つことができます
危険性を理解したうえで使用していくといいですね
SdustをCrystalに移植してみた

## はじめに

sdustとは、低複雑度領域を見つけるコマンドラインツールです。
オリジナルの [symmetric DUST algorithm](https://pubmed.ncbi.nlm.nih.gov/16796549/)は2006年にAleksandr Morgulisさんによって発表されました。これによりNCBIの[DustMasker](https://www.ncbi.nlm.nih.gov/IEB/ToolBox/CPP_DOC/lxr/source/src/app/dustmasker/) というツールが公開されました。Heng Liさんが、minimapおよびminimap2の一部として[sdust](https://github.com/lh3/sdust)を公開しました。

今回、お正月の時間を使って、このツールをCrystal言語に移植してみました。

## sdust.cr

作成したものはGitHubにアップロードしました。

https://github.com/kojix2/sdust.cr

今回はアルゴリズムについてはほとんど理解せず写経になってしまいました。
（お正月中に仕上げるためにはアルゴリズムの理解までは無理だと判断しました。
Discourseの議論をテキスト形式でダウンロードする

## はじめに

海外のITフォーラムで、[Discourse](https://www.discourse.org/)が利用されていることがよくあります。

私は英語が苦手なので、ChatGPTやDeepLなどに頼り切って、これららのフォーラムの内容を読んだり書いたりしています。

## データを取得する方法

そういうとき、有益だけど長いトピックの本文を取得して、ChatGPTに投げたい場合があります。実はこれ、めちゃくちゃ簡単な方法があります！

https://meta.discourse.org/t/export-topic-as-markdown/152185

アドレスに raw を指定するだけです！
例えば、上のトピックをMarkdownで取得する場合は、次のようにすればいいだけです。

```
wget https://meta.discourse.org/raw/152185
```

この記事は以上です。
ランサムウェア対策講座 メモ

# ランサムウェアとは？
Ransom（身代金）＋Softwere（ソフトウェア）を組み合わせた造語。
端末に特定の制限をかけ、その制限の解除と引き換えに金銭を要求する不正なプログラム（＝マルウエア）
※2015年あたりから、かなり多くの被害が発生している。


# ランサムウェアの流れ
1. 何らかの方法で端末に侵入
2. ランサムウェアを端末に設置
3. ランサムウェア実行→感染した端末上のファイルを暗号化する
4. 端末に脅迫メッセージを表示、複合の代わりに金銭を支払うように要求する
5. 内部データの操作ができる状況なので、データも盗みだされる


# 感染経路
- 無差別一斉送信のメール
ランサムウェア事態をコピーして他の端末にも感染拡大
- ネットワークを介して感染
脆弱性を悪用して、何らかの方法で侵入、侵入した端末から他の端末にも感染拡大


# 攻撃者のフロー
1. ネットワークスキャン：攻撃対象の調査
2. 脆弱性の調査と悪用
3. ランサムウェアの設置
4. ランサムウェアがシステム上で動作→攻撃者のサーバとの通信経路確立・感染拡大
5. 情報の窃盗・暗号化を実施→金銭の要求

つまるところ、脆弱性を利用した**標準的なサイバー攻撃**の一つ


# 標準的なサイバー攻撃の対策について
- NIST CyberSecurity Framework (CSF)　サイバー攻撃対策のためのフレームワーク
1. 識別（保持しているIT資産を管理）
2. 防御（対応策を実施）
3. 検知（攻撃を検知する）
4. 対応（マルウェアへの対応）
5. 復旧（ビジネスが継続できる元の状態に戻す）

1-5のそれぞれの手順は統治されている必要がある
フレームワークを実際に当てはめると
これらのフローを回していくことになる
1. 攻撃対象を理解する Inspector,Macie,SecurityHub など
1. 脅威の検出　GurdDutyなど
1. セキュリティ問題の調査・関連付け Cloudwatchなど
1. 対応と修復　backupなど



# データを保護するために大事なポイント
- 重要なデータを特定
- データへのアクセスを管理・制御
データの暗号化導入
自動化されたデータ保護の仕組みを導入する
- データガバナンスとコンプライアンスの実践
モニタリングとアラートの導入
- バックアップと復旧手段の計画
DR・BCPのプランを策定
- ランサムウェア復旧手段の計画

# 実際にAWSで使える機能に置き換えると・・・

識別
- AmazonVPCNetworkAccessAnalyzer
意図しないネットワークアクセスを特定する機能
インターネットへの疎通確認・パスの確認・アクセスの確認

- AWS Inspector
パッケージの脆弱性の検出、ネットワークパスの確認


防御・検知
- Amazon GuardDuty
AWSのAPI実行ログを見て、AWS側で脅威検出のメカニズムでリスクを検知する
マルウェアを検知する機能もある。EC2、S3、EKSなど

- Route53
マルウェアからの通信経路を検知する

- NetworkFirewall
フルマネージドなFirewallサービス。FirewallはAWS側で自動アップデートされる

対応・復旧
- AWS System Manager
脆弱性のあるソフトウェアに対して、自動でパッチを適用する

- AWS Backup
Vaultという論理的な箱の単位ででバックアップを保護する
VaultLock機能で削除保護、更新の保護を行う


# バックアップに対する考え方
**多層防御する**
- IAMポリシーによるアクセス制限
- MFAの有効化
- WORM・クロスアカウントでのバックアップ
- AWS KMSを用いたデータ暗号化
- ロール毎のバックアップへのアクセス制限
- 監査ログの有効化

# 「統治」について
ベストプラクティスをもとにシステムを構築する。
Incus: Arch Linux を使う

## インストール

```bash
incus launch images:archlinux arch
```

インストールされたことを確認

```text
$ incus list
+------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
|    NAME    |  STATE  |         IPV4         |                     IPV6                      |   TYPE    | SNAPSHOTS |
+------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| arch       | RUNNING | 10.158.98.226 (eth0) | fd42:16ef:86e0:dbd7:216:3eff:fe02:84ea (eth0) | CONTAINER | 0         |
+------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
```

## 設定

ルートのパスワードの設定

```bash
incus exec arch bash
```

login

```text
$ incus console arch
To detach from the console, press: <ctrl>+a q

arch login:
```

## login 後のインストールと設定

ユーザー、パスワードの設定

```bash
useradd -u 1200 -m -g wheel uchida
passwd uchida
```

sudo のインストール

```bash
pacman -S sudo
```

visudo で設定

```text
%wheel ALL=(ALL:ALL) ALL
%wheel ALL=(ALL:ALL) NOPASSWD: ALL
%sudo   ALL=(ALL:ALL) ALL
```

sshd のインストール

```bash
sudo  pacman -S openssh
sudo systemctl start sshd
sudo systemctl enable sshd
```

avahi のインストール

```bash
sudo pacman -S avahi
sudo systemctl start avahi-daemon
sudo systemctl enable avahi-daemon
```

## 参考ページ

[LXD で Arch Linux を使う](https://qiita.com/ekzemplaro/items/aa4fd7d9ea99afb4980e)
【ChatGPT＋Code Interpreter】複数枚の画像を一枚の画像にします。


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

　今回は、複数枚の画像を一枚の画像にします。X-Twitterなどにアップするのを目的にしています。

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

　まずは、ニュース。

　以前から
　　話題になっていた
　　　中国の企業Kuaishou Technologyが出している
　　　　動画生成AI　Kling AIの
　　　　　International Version1.0が
　　　　　　一昨日（2024/07/23）
　　　　　　　公開されました。

　メールアドレスで
　　入れます。

　[Kling AI](https://klingai.com/)

　昨日初めてアクセスしましたが、
　　スマホ対応していなかったので
　　　ログインすらしていません。
　　　　ほら、私、スマホオンリー😅

　それでも気になる方は、
　　YouTuberのKEITOさんが
　　　動画をアップされていますので、
　　　　そちらをごらんください。
　　　　　まだ触ったばかりみたい。
[話題の中国版Sora！Kling AIの画像→動画生成が超リアルらしいので検証【正直レビュー】](https://youtu.be/M7gXTx3oJx8?si=pU6YtFWg9BWxwl3p)

　KEITOさんは
　　辛口批評ですね。

　まぁ、初めての操作ですから、
　　こんなもんでしょうね😅
***
　さて、本題です。

　今回は、
　　複数枚の画像を
　　　一枚の画像にします。

　一枚にすれば、
　　X-Twitterへのポストも
　　　楽になる？かと思います。

　手間がかかるから
　　余計なお世話かしら😅

　まぁ、専用ツールを使わずに、
　　“ChatGPTでできる”と考えれば、
　　　良き？😅
***
　ここでは
　　四枚の画像を
　　　一枚にします。

　ただ、ふつうに一枚にすると、
　　画素数が倍✕倍の四倍に
　　　なってしまいます。
　　　　ファイルサイズも
　　　　　四倍です😅

　そこで、
　　最終的に
　　　1024×1024に
　　　　なるように指定します。

　では手順です。
　❶GPT-4oであることを確認
　❷四枚の画像をアップロード
　❸Prompt入力
```Text:四枚画像を一枚にPrompt
CodeInterpreterで、この四枚の画像を一枚の画像にしてください。ただし、まとめる際に1024×1024になるようにしてください。
```
　❹送信
　❺ダウンロードリンクが表示

　Promptを
　　使った結果が
　　　こちらになります。
![combined_image_1024x1024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/b7ee4544-46a5-1d4f-01fc-f0d642b5fbbc.png)

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

　今回は、ここまで。
React hooksを使って、ページ遷移の制御をする

react hooksを使って、ページ遷移（たぶ切り替え）の制御をした。
hashTagキーでurlの末尾に#~~と記述して、そのページに遷移できるようになる。
```javascript:javascript
const setHashTag = (hashTag: string) => {
    navigate(`#${hashTag}`);
    setVal(hashTag);
  };
```
ここで、react hookの登場。useEffectを使う。
urlが変更されたときに起こる副作用をconst以下に記述。[location.hash, val]の配列が更新されるたびにEffect内の関数が実行される。
```javascript:javascript
useEffect(() => {
    const currentHash = location.hash.replace('#', '');
    if (currentHash && currentHash !== val) {
      setVal(currentHash);
    }
  }, [location.hash, val]);
  ```
「DockerでDBの初期化ができない」の解決策

## 背景
### 使用したファイル
以下の`docker-compose.yaml`と`init.sql`でdockerでDBを起動する際にテーブルの作成と初期データの挿入を試みた。
```yaml:docker-compose.yaml
version: '3.9'

services:
  db:
    image: postgres:16
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=mydatabase
    volumes:
      - ./data:/var/lib/postgresql/data
      - ./init:/docker-entrypoint-initdb.d
volumes:
  data:
```
```sql:init/init.sql
CREATE TABLE IF NOT EXISTS pets (
    pet_id INTEGER,
    pet_type INTEGER,
    pet_name VARCHAR(10)
);

INSERT INTO pets (pet_id, pet_type, pet_name) VALUES (1, 1, 'Pet1');
INSERT INTO pets (pet_id, pet_type, pet_name) VALUES (2, 2, 'Pet2');
```
### 実行内容
`docker compose up -d`をした上で、以下コマンドでコンテナに入りDBの中身を確認した。
```bash
$ docker-compose exec -it db psql -U user -d mydatabase
```
```sql
mydatabase# \dt;
mydatabase# select * from pets;
```
過去にコンテナに入ってDB操作を試したデータがそのまま残っており、`init.sql`の初期化が実行されていなさそう。
### 実行ログ
dbコンテナのログには以下のように、`Skipping initialization`となっている。
```
2024-07-26 00:00:00 
2024-07-26 00:00:00 PostgreSQL Database directory appears to contain a database; Skipping initialization
2024-07-26 00:00:00 
2024-07-26 00:00:00 2024-07-26 02:18:33.974 UTC [1] LOG:  starting PostgreSQL 16.3 (Debian 16.3-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
2024-07-26 00:00:00 2024-07-26 02:18:33.974 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
2024-07-26 11:18:33 2024-07-26 02:18:33.974 UTC [1] LOG:  listening on IPv6 address "::", port 5432
2024-07-26 11:18:33 2024-07-26 02:18:33.977 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2024-07-26 11:18:33 2024-07-26 02:18:33.993 UTC [30] LOG:  database system was shut down at 2024-07-26 02:18:31 UTC
2024-07-26 11:18:33 2024-07-26 02:18:33.998 UTC [1] LOG:  database system is ready to accept connections
```

## 解決策
`docker volume ls`でも何も表示されないのに何故だろう...と困ったが、`docker-compose.yaml`で以下のように指定していることが原因だった。
```yaml:docker-compose.yaml
volumes:
      - ./data:/var/lib/postgresql/data
```
dockerを起動するたびに過去のデータをそのまま利用したいときにこれを指定すると、ローカルの`data/`内を参照するため、`init/init.sql`は実行されない。

もしvolumeを削除して、何もない状態からDBの初期化を試したければ、過去の実行で生成された`data`ディレクトリを削除してあげれば良い。

`data`ディレクトリを削除した状態で`docker-compose up -d`を行えば、真っ新なDBで`init.sql`が実行される。

## 補足
今回やりたかったことは以上で実現されたが、composeファイル内で正しくvolumeが設定されていれば、以下で解決できるはず。

```bash
$ docker volume ls
DRIVER   VOLUME NAME
local    {volume_name}
$ docker volume rm {volume_name}
```
「RailsでさくっとWebsocketする」を実践してつまずいたとこまとめてみた

# 経緯
[Rails7でさくっとWebSocketする](https://zenn.dev/seita1996/articles/rails7-actioncable#controller%E3%81%A8view%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B)を実践している中で躓いたところがいくつかあったので、まとめてみました。
# localhostアクセスできない問題
- 原因
データベースに接続できていなかった
- 解決法
接続する前にコンテナに入り（`docker-compose run app sh`)、以下を実行することでアクセスできるようになった
```sh
rails db:migrate
```
# チャットがリアルタイムで更新されない。
- 原因
broadcastメソッドの引数指定がおかしかった。
```Ruby
# 間違い
ActionCable.server.broadcast 'room_channel', message: render_message(message)
# 正解
ActionCable.server.broadcast 'room_channel', { message: render_message(message) }
# 第二引数の指定方法が異なる。broadcastメソッドはキーワード引数を受け付けておらず。第二引数では
# データ（ハッシュ）を受け取る。
```
# コンテナ（Rails）のステータスがrestartingになってる問題
- 8/7追記分
- 以下のサイトが参考になりました！
- [【Docker】 Restarting xxxx が繰り返してコンテナが立ち上がらない場合 #React - Qiita](https://qiita.com/NaokiHaba/items/f21b3a5e2691890ddf99)
# 最後に
サーバーのログを見てやっと気づく場面もあり、ログを見ることの重要性を再認識させられました😅
GitHub Pull Requests プラグインで vscode 内でレビューを完結

vscode 内でレビューを完結出来る…？何て素晴らしそうな拡張機能でしょう


https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github

ちょっとだけ評価が低いのが気になってましたが、レビュー読んでみるとどうやらエンタープライズ版で認証が上手く出来ない問題があってそこで評価が落ちているようですね。

弊社は使ってないので気にしないで良さそう。

# 使い方

拡張機能をインストールして、vscode 左下の方にあるアカウントでログインするだけ。

インストール後、左端のアクティビティバーに GitHub Pull Requests アイコンが表示され、現在開いているリポジトリの Pull Requests と issue にアクセス出来るようになります。

:::note info
最新情報と差異がある場合、上の更新ボタンを押せば最新情報に更新されます
:::

:::note warn
vscode でログインしている GitHub アカウントが、現在開いているリポジトリに対してアクセス権限を持っていないと何も表示されません。当然と言えば当然ですが…。
:::


![スクリーンショット 2024-07-26 111916.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/c3d71b1c-6b49-5f89-58b6-56aaca2a590f.png)


あとはエンジニアでしたら直感的に利用できるとは思いますが、左側でレビューしたいプルリクエストを開き、変更されたファイルを選択すれば右側に GitHub 上と似たようなレビュー画面が開きますので、あとは普通にレビューを行うだけです。めっちゃ簡単。


![スクリーンショット 2024-07-26 113001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/ded1b80d-c5d6-e29a-3d52-2985d0116298.png)


以上
paiza の問題でコードゴルフをしてみた part1 @uni928

paiza×Qiita記事投稿キャンペーンで
「プログラミング問題をやってみて書いたコードを投稿しよう！」
というお題が出ているのを見て
ふと皆でコードゴルフをしてみたくなり
投稿してみる事にしました。

コードゴルフとは問題文に対して
「より短いコード」を目指す遊びです。
正常に動作するならば
35 文字のコードより
34 文字のコードが優れているという事です。

「もっと短くできるよ！」
というのがあればコメント頂けると幸いです。

対戦よろしくお願いします。

***

条件

項目「一番小さい値 (paizaランク D 相当)」で最短のコードを探す。
使用する言語「paiza で使える任意の言語(なるべく短く済む言語を使用する)」
成功条件「paiza が用意しているチェックに全て通過する(paiza が用意していない入力で正常に動作しない分にはかまいません)(理論上 95% 以上の確率で、全てのチェックを通過するコードである必要があります。)」

改行と空白文字は 1 文字相当でお願いします。
cシャープの Main メソッドや php の "＜？php ？＞ も文字数にカウントして下さい。

問題文の URL 
https://paiza.jp/works/mondai/d_rank_skillcheck_sample/min_num

***

問題文

## 下記の問題をプログラミングしてみよう！

5 つの正の整数が入力されるので、最も小さい数字を出力して下さい。

### ▼ 下記解答欄にコードを記入してみよう

#### 入力される値
入力は以下のフォーマットで与えられます。

```
n_1
n_2
n_3
n_4
n_5
```

1 行目から 5 行目に正の整数 `n_1, n_2, n_3, n_4, n_5` が与えられます。

入力値最終行の末尾に改行が１つ入ります。  
文字列は標準入力から渡されます。 [標準入力からの値取得方法はこちらをご確認ください](https://paiza.jp/guide/samplecode.html)

#### 期待する出力
`n_1, n_2, n_3, n_4, n_5` のうち最も小さい数字を出力して下さい。

#### 条件
すべてのテストケースにおいて、以下の条件をみたします。

```
1 ≦ n_1, n_2, n_3, n_4, n_5 ≦ 100
```

#### 入力例1
```
10
12
4
8
46
```

#### 出力例1
```
4
```

#### 入力例2
```
1
2
3
2
1
```

#### 出力例2
```
1
```

***

私の回答(Ruby)

```ruby:私の回答(Ruby)
a=[]
5.times{a<<gets.to_i}
p a.min
```

***

私の回答はいかがでしたか？

私は頑張っても 34 文字かかりました。

空の配列を用意するのに 
改行を含めて 5 文字かかっているのと
5 回繰り返す方法と
数値変換が短縮出来そうで出来ませんでした。

私は色んな言語を使ってみて
34 文字より短くすることが出来ませんでした。

paiza で使えるならば
どんな言語でも良いため
もっと短くできるという意見があれば
コメント頂けると幸いです。

個人的にコードゴルフの記事は大好物なので
paiza×Qiita記事投稿キャンペーンを機に
コードゴルフのゴルフの記事が増えたら嬉しいです。

皆でこのお題を楽しんでいきましょう。

この記事が皆さんの暇つぶしになりますように。
閲覧ありがとうございました。
Ubuntu から LAN 内のプリンターに印刷

Ubuntu 24.04 で LAN 内の Epson の EW-M754TW に印刷してみました。

## 設定

Show Apps をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/d7d164a0-4a20-3263-9808-7b93f2685fd4.png)

設定をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/90707d9f-c3d9-7ff2-85d0-f880da83c899.png)

プリンターをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/58ff2467-fa84-14ca-37a7-cb4eaf544d49.png)

LAN に接続されたプリンターを確認
　私の場合は、　Epson の　EW-M754TW

## 印刷のテスト

ブラウザーで、、印刷のメニューをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/17ef2523-8af9-de7e-0878-2ea220674ab1.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/96661b01-42d7-af67-a181-a0af1fb970cb.png)

印刷をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/8fb9f67d-40e4-25d6-b51a-710f7344d538.png)
サポートが終了したCentOS環境で、yumコマンドを利用する

2024年6月末で、ついにCentOS7のサポートが終わってしまいましたが、学習環境などとして利用する分には、vaultリポジトリを利用するように構成して、引き続き環境を利用することができます。
valutリポジトリ（vault.centos.org）は、標準リポジトリのアーカイブであり、サポート終了後もこれらのリポジトリを利用して、yumコマンドによるパッケージ管理を行うことができます。

:::note info
CentOSプロジェクトがvaultリポジトリを提供してくれる限りは・・ですが。
:::

yumの設定ファイルで、以下の内容を修正します。
1. 標準利用するmirrorlist設定を無効化する
標準で利用されるmirrorlist設定は利用できないので、行頭に「#」を挿入し、無効化します。
1. baseurl設定を有効化し、参照先のサーバーをvaultに書き換える
既定ではbaseurlが無効になっていますが（コメントとして設定）、行頭の「#」を削除し、有効化し、参照先をvaultリポジトリのものに書き換えます。

これらの作業を標準で利用するリポジトリの設定が記述されているCentOS-Base.repoファイルに対して行います。
なお、以下の構文を実行していただくことで、これらの処理を実行することができます。

```bash
[root@www ~]# sed -i 's/^mirrorlist=http/#mirrorlist=http/g' /etc/yum.repos.d/CentOS-Base.repo
[root@www ~]# sed -i 's/^#.*baseurl=http/baseurl=http/g' /etc/yum.repos.d/CentOS-Base.repo
[root@www ~]# sed -i 's/mirror.centos.org/vault.centos.org/g' /etc/yum.repos.d/CentOS-Base.repo
```

設定変更が完了すると、CentOS7環境でも以下のようにyumコマンドが利用できるようになります。
```bash
[root@www ~]# yum search mod_ssl
読み込んだプラグイン:fastestmirror, langpacks, product-id, search-disabled-repos,
                   : subscription-manager

This system is not registered with an entitlement server. You can use subscription-manager to register.

Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
Loading mirror speeds from cached hostfile
 * epel: ftp.iij.ad.jp
============================= N/S matched: mod_ssl =============================
mod_ssl.x86_64 : SSL/TLS module for the Apache HTTP Server

  Name and summary matches only, use "search all" for everything.
```

ただし、vaultリポジトリはあくまでもアーカイブですので、今後新しいバージョンのパッケージが配置されることはありません。そのため実用環境では、サポートされているバージョンのディストリビューションを使うべきです。

:::note info
この手順で、CentOS Stream 8など、ほかのサポート切れのCentOSでもyumコマンドを利用できるようになります・・と書いていたのですが、CentOS Stream 8だと設定ファイルのパス等が違ったので、後ほど追記します。
:::
streamlitで愛媛県の新型コロナウイルスの患者報告数を可視化

こちらでデータ取得ができたのでstreamlitで可視化する

https://qiita.com/barobaro/items/1c825ad8133bf1c393b4

完成品

https://ehime-covid19.streamlit.app/

```python
from io import StringIO

import pandas as pd
import requests
from bs4 import BeautifulSoup

import streamlit as st

option = ["愛媛県", "四国中央", "西条", "今治", "松山市", "中予", "八幡浜", "宇和島"]


@st.cache_data(ttl=3600)
def load_data():
    url = "https://www.pref.ehime.jp/site/kanjyo/39800.html"

    r = requests.get(url)
    r.raise_for_status()

    soup = BeautifulSoup(r.content, "html.parser")

    tag_table = soup.find("p", string="患者報告数の週推移").find_parent("table")

    # th colspan 2
    tag_table.select_one('th[colspan="37"]')["colspan"] = "2"

    # td colspan del
    for td in tag_table.select('td[colspan="36"]'):
        del td["colspan"]

    html = tag_table.prettify()

    df0 = pd.read_html(StringIO(html))[0]

    df0.columns = df0.columns.str.replace(r"\s", "", regex=True)
    df0.rename(columns={"保健所名": "月", "保健所名.1": "週"}, inplace=True)

    df0["月"] = pd.to_numeric(df0["月"].str.rstrip("月"), errors="coerce")
    df0["週"] = pd.to_numeric(df0["週"].str.strip("第週"), errors="coerce")

    df_weeks = pd.date_range("2024-01-01", "2025-01-8", freq="W-SUN").isocalendar()
    df_weeks = df_weeks[df_weeks["year"] == 2024]
    df_weeks.index.name = "date"
    df_weeks.reset_index(inplace=True)

    df1 = pd.merge(df0, df_weeks, how="left", left_on="週", right_on="week").set_index("date").sort_index()

    df2 = df1.reindex(columns=option).copy()

    return df2


st.set_page_config(page_title="愛媛県新型コロナウイルス2024")
st.title("新型コロナウイルス")


df = load_data()

# ストリームリットセレクトボックスの作成
chois = st.multiselect("保健所を選択", option, default="今治")

if chois:
    filterd_df = df.reindex(columns=chois)

    st.line_chart(filterd_df)
    st.dataframe(filterd_df, width=700)
```
【Java】レコードクラスとは

## はじめに

  資格勉強を進める中で、レコードクラスを学ぶ機会がありました。

  研修の中で学ぶ機会はなかったものの、結構便利なので今後も使う機会があるかと思い、備忘録としてまとめてみようと思います。
  
  ※誤りありましたら、ご指摘いただけますと幸いです。

## 想定読者
  初学者の方  
  普段Javaを使用している方

## レコードクラスとは  
  Java16より正式に追加された、簡潔かつイミュータブルにデータを保持できるクラスです。

  従来は、データを保持する目的においてもクラスを新たに作成し、似通ったクラスを作成していましたが、レコードクラスはこれらボイラープレートコードの作成を軽減してくれます。

  **※ボイラープレートコード**  
  →定型的で冗長な記述のこと。


## 実際の使い方
  実際の使い方を見ていきましょう。
  今回は名前（name）と年齢（age）のみの簡潔なレコードクラスを作成してみます。

```java
public record Person(String name, int age) {}
```

  これだけで完了です。
  レコードクラスで保持したいデータをコンポーネントと呼び、ヘッダー内に変数宣言と同様の形で指定すればOKです。（今回はnameとage）

  しかしこれだけでは、レコードクラスを用いることで何がなされているのか分からないので、下にレコードクラスで実際に定義されている内容を記述してみます。

```java
public class Person　{

    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public boolean equals(Object o) {
        //等価性判定を行うメソッド
    }

    public int hashCode() {
        //ハッシュ値を生成して返すメソッド
    }

    public String toString() {
        //オブジェクトの文字列情報を返すメソッド
    }
}

```

  たったあれだけの簡潔な記述で、  

  ①private finalなメンバ変数  
  ②標準コンストラクタ  
  ③アクセサメソッド（イメージはgetter）  
  ④equals()・hashCode()・toString()メソッド  
    
  これらが作成されていることが分かります。

  ちなみに、レコードクラス内に新たにメソッドを追加することも可能です。

## レコードクラスの特徴

レコードクラスの特徴は、大きく2つあります。

### ①イミュータブル

  コンポーネントの値はfinalが付き、定数として管理されます。よって後から値の変更はできない、**イミュータブルなオブジェクト**となります。

  getterの役割を担うアクセサメソッドは存在しますが、setterがないのは、定数であるが故に後から値の変更がなされないためです。
  

### ②継承不可
  レコードクラスは、java.lang.Recordクラスを継承しておらず、かつ暗黙的にfinalとして扱われるため、**他のクラスを継承することはできず、そして他クラスでレコードクラスを継承することもできません。**

  ちなみに、レコードクラスのスーパークラスであるjava.lang.Recordクラスでは、equals()、hashCode()、toString()がメソッドとして存在しています。

  レコードクラスを定義するだけで、上記3メソッド
を使用できるのはそういうわけだったんですね。

※ちなみに、これらのメソッドはオーバーライド可能です。

Recordクラスの公式ドキュメントは[コチラ](https://docs.oracle.com/javase/jp/15/docs/api/java.base/java/lang/Record.html)から。


## レコードクラスのコンストラクタ
  レコードクラスを扱う上でもう一つ取り上げたいのがコンストラクタについて。

  レコードクラスには、レコードクラスでしか使用できない**コンパクトコンストラクタ**というものがあります。



## 比較

#### 1, 標準コンストラクタ
```java
public record Person(String name, int age) {
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
```

  こちらは通常のコンストラクタ。
  メンバ変数に値をセットしています。


#### 2, コンパクトコンストラクタ

```java
public record Person(String name, int age) {
    
    public Person {
        age = age > 0 ? age : 0;
    }
}
```

  こちらがコンパクトコンストラクタになります。

  通常のコンストラクタとの違いとして、まず**引数が不要**となっています。

  そして、特別な初期化処理以外は自動で初期化処理をしてくれるので、**初期化処理が不要**となっています。今回はageに特別な初期化処理を行うため記述していますが、nameの記述がありません。nameは自動でメンバ変数に値がセットされます。
  
  今回コンポーネントが2つしか指定していないので良さが伝わりづらいですが、もしもコンポーネントが10個20個と多く存在し、その中の一つだけ特別な初期化処理を施したい、そんなときにコンパクトコンストラクタが活躍します。

## まとめ
  まだ登場したばかりのレコードクラスですが、記述量が格段に減るため、今後活用されることも増えるのではないかと勝手ながら感じました。

  少し知っているだけでもキャッチアップも楽になると思うので、この記事が少しでも参考になれば幸いです！