OmniAICreator/Qiita-1.07M huggingface dataset:
SQLAlchemyでデータを一部取得できない問題を解決した備忘録

自分のミスに気付くのにものすごく時間がかかったので、未来の自分用のメモです。ついでに誰かのためになれば。

# 状況
DBにあるはずのレコードが、超単純なクエリでも、どうしても一部抽出できなかったのです。エラーは起きない。再現性はある。（dockerでImageを作り直すところからやり直しても、まったく同じ状況）
SQLAlchemy 2.0.19で、ORMを使っています。DBはMySQL8.1です。

- [SQLAlchemy Documentation — SQLAlchemy 2.0 Documentation](https://docs.sqlalchemy.org/en/20/)
- [MySQL :: MySQL 8.0 リファレンスマニュアル](https://dev.mysql.com/doc/refman/8.0/ja/)

# 詳細
とあるテーブルをこんな風に定義してました。

```SQL:Create Table文とデータ
CREATE TABLE `my_table1` (
    `my_id`         INT         NOT NULL,
    `hoge_date`     DATE        NOT NULL,
    `fuga_date`     DATE,
    PRIMARY KEY (my_id, hoge_date)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

INSERT INTO `my_table1` VALUES
(1, "2023-01-01", "2023-01-31"),
(1, "2023-02-01", "2023-02-28"),
(1, "2023-03-01", NULL),
(2, "2023-01-01", "2023-01-31"),
・・・・（もっとある）・・・
;
```
```Python:ORMの定義
class MyTable1(Base):
    __tablename__ = "my_table1"
    
    my_id: Mapped[int] = mapped_column(Integer, primary_key=True)
    hoge_date: Mapped[date] = mapped_column(Date, nullable=False)
    fuga_date: Mapped[date] = mapped_column(Date)
```
`hoge_date`に、`primary_key=True`を入れ忘れているバグ。***これが原因***なんですが。。

この状態で、SQLAlchemyで`SELECT`すると・・・
```Python:Selectしてるところ
# 無条件で抽出
recs = session.query(
    MyTable1
).all()
# 件数確認
print(len(recs))
```
上のコードはただの`SELECT * FROM my_table1;`で、DBクライアントソフトでDBへ接続して全件調べると、DBクライアントでは146件、Pythonでは144件でした。

`my_id`ごとにカウントすると、3件ある`my_id`が全部で17個あったのですが、そのうち2個の`my_id`だけは2件しか抽出できず、それ以外の15個は3件ずつ抽出できました。つまりPython・SQLAlchemyからはこんな感じに見えている。最初の2個だけ、1件ずつ足りなかった。
```
SELECT my_id, COUNT(*) FROM my_table1
GROUP BY my_id HAVING COUNT(*)>1;

my_id count
    1     2
    2     2
    3     3
    4     3
  ... (省略)
   17     3
```
当然、DBクライアントからのクエリ結果は、全部3件。

# 原因
上にも書きましたが、原因は`primary_key=True`の書き忘れです。正誤の違いは`hoge_date`の`mapped_column`の引数です。
```Python:ORMの定義（誤り）
class MyTable1(DbBase):
    __tablename__ = "my_table1"
    
    my_id: Mapped[int] = mapped_column(Integer, primary_key=True)
    hoge_date: Mapped[date] = mapped_column(Date, nullable=False)
    fuga_date: Mapped[date] = mapped_column(Date)
```
```Python:ORMの定義（正しい）
class MyTable1(DbBase):
    __tablename__ = "my_table1"
    
    my_id: Mapped[int] = mapped_column(Integer, primary_key=True)
    hoge_date: Mapped[date] = mapped_column(Date, primary_key=True)
    fuga_date: Mapped[date] = mapped_column(Date)
```
※ `primary_key=True`を指定すると`nullable=False`(NOT NULL)がデフォルト、primary_keyでなければ`nullable=True`がデフォルト。([リファレンス](https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.mapped_column.params.nullable)より)


# おわりに（感想）
にらみっこしたり~~投げ出したり~~して、半日くらい詰まってましたよ。。ググっても、中途半端に抽出できちゃうなんて人いないし、そんな致命的でわかりやすいバグが残ってる気がしない。最終的には、PK関係か！？っていうところから自分でたどり着きました。PKの問題だったら、2件とか3件とか取れちゃわないで、全部1件しか取れなかったら、もう少し早く気付けたかもしれない。コロンブスの卵！

ちなみに今回の私のミスとは直接関係ないけど、SQLAlchemyは、
- 日本語の情報がちょっと少ない
- バージョンが1.4→2.0で大きく変わったから、1.x時代の記事によくはまる
- ORM的な使い方と、SQLを投げるように使う使い方がある(らしい)

なのでちょっと注意です。
tempfileモジュールによる生成先をpytestの一時ディレクトリの下にする方法

`tempfile`モジュールで生成される一時ファイル・ディレクトリを、pytestの`tmp_path`の下に作る方法です。

:::note info
`tempfile`モジュールを使っているプログラム（＝テスト対象）の中で生成される一時ファイル・ディレクトリの生成場所を切り替えたいというケースに対するanswerです。
単にユニットテストで使う一時ファイル・ディレクトリを準備するだけならpytestの`tmp_path`をそのまま使ってください。
::::

https://docs.pytest.org/en/7.1.x/how-to/tmp_path.html

## 間違った方法（予期しない副作用がある）

どこに一時ファイル・ディレクトリが生成されるかは環境変数TEMPDIRで決まりますが、その内容は`tempfile.gettempdir()`にキャッシュされているので`tempfile.tempdir = None`でキャッシュをクリアしないと（環境変数TMPDIRを書き換えても）切り替えられません。

https://docs.python.org/ja/3/library/tempfile.html#tempfile.tempdir

しかし、キャッシュされているので一度切り替えてしまうと、別のテスト関数でも切り替わった状態が反映されてしまいます。

```python: BAD CASE
import tempfile
from pathlib import Path
from _pytest.monkeypatch import MonkeyPatch

class TestBadCase:
    def test_foo(self, tmp_path: Path, monkeypatch: MonkeyPatch):
        # tempfileモジュールが一時ファイル・ディレクトリを生成するディレクトリを
        # pytestが生成する一時ディレクトリの下に切り替える
        monkeypatch.setenv("TMPDIR", str(tmp_path))
        tempfile.tempdir = None

        with tempfile.NamedTemporaryFile() as f:
            print(f.name)  # GOOD: tmp_pathの下に生成される

    def test_bar(self):
        with tempfile.NamedTemporaryFile() as f:
            print(f.name)  # NOT GOOD: "/tmp"では無く、test_foo()で設定されたディレクトリの下に生成される
```

## 解決方法

* テスト関数の入口で`tempfile.tempdir = None`して環境変数TMPDIRの設定が有効になるようにする。
* テスト関数の出口で`tempfile.tempdir = None`して、次に実行されるテスト関数で環境変数TMPDIRが再評価されるようにする。
* テスト関数の先頭と末尾でそれ（↑）をやると、テストが失敗した時に出口処理が実行されないのでtry-finallyで囲む、、、ぐらいならcontextmanagerを使おう。
    * `pytest.fixture`はcontextmanagerなのでteardown側に出口処理を書こう。

```python: GOOD CASE
import tempfile
from pathlib import Path
from _pytest.monkeypatch import MonkeyPatch

class TestGoodCase:
    @pytest.fixture(scope="function")
    def switch_tempdir(self, tmp_path: Path, monkeypatch: MonkeyPatch):
        # tempfileモジュールが一時ファイル・ディレクトリを生成するディレクトリを
        # pytestが生成する一時ディレクトリの下に切り替える
        monkeypatch.setenv("TMPDIR", str(tmp_path))
        tempfile.tempdir = None

        yield tmp_path

        tempfile.tempdir = None

    def test_foo(self, switch_tempdir: Path):
        with tempfile.NamedTemporaryFile() as f:
            assert Path(f.name).parent == switch_tempdir
            print(f.name)

    def test_bar(self, switch_tempdir: Path):
        with tempfile.NamedTemporaryFile() as f:
            assert Path(f.name).parent == switch_tempdir
            print(f.name)  # GOOD: test_foo()とは異なるディレクトリの下に生成される

    def test_baz(self):
        with tempfile.NamedTemporaryFile() as f:
            print(f.name)  # GOOD: "/tmp"の下に生成される
```
【メモ】CodeBuildがbuildspec.yml内でアーティファクトを見つけられないのを解決

CodeBuildのログで、ビルドステージでアーティファクトの作成は成功したのに、そのアーティファクトが見つからないとエラーが出た。

```yml:buildspec.yml
artifacts:
  files:
    - imagedefinitions.json
```

もし上記で`imagedefinitions.json`が見つからない場合、下記のパスの指定の仕方で解決できた。

```yml
artifacts:
  files:
    - "**/*" # ~といった感じで指定するとカレントディレクトリ全てが対象になる。
```

## 参考
https://open-groove.net/ci-cd/codedeploy-role-permissions-error/
A5SQLにてサーバー上のDBに接続する方法

### 概要

A5SQLにてサーバー上のDBにアクセス出来なかったため、接続方法を忘れないようにするために本記事を作成。

### 原因

A5SQLからさくらVPSのMysqlにログインするにはSSH2トンネルを経由しなければ

入ることが出来ない。※外部からのログインを受け付けていないため。

### 接続方法

**基本タブを選択し指定事項の入力**

ホスト名「localhost」

ユーザーID「mysqlのID」　パスワード「mysqlのパスワード」

**SSH2トンネルを選択し指定事項の入力**

SSH2トンネル経由で接続するにチェック✓

SSH2ホスト名「サーバーのホスト名」

ユーザーID「サーバーのユーザーID」

パスワード「サーバーのパスワード」
Composer.jsonについての検証

## 概要

Composer関係でcomposer.jsonのバージョンが違う事象が発生しており、理由の追求のために行います。

## 環境

Windows10

composer version 2.4.4

仕様エディタ　VSCode

## 前提

クローンして来たばかりで、Venderファイルが存在しないこと

## 検証内容

①両方ある状態でcomposer update

②両方ある状態でcomposer install

③composer.jsonがあり、composer.lockがない状態でcomposer update

④composer.jsonがあり、composer.lockがない状態でcomposer install

⑤composer.jsonがなく、composer.lockがある状態でcomposer update

⑥composer.jsonがなく、composer.lockがある状態でcomposer install

⑦両方ない状態でcomposer install

⑧両方ない状態でcomposer install

## 検証

①composer.jsonに書かれている内容で更新される

②Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Your lock file does not contain a compatible set of packages. Please run composer update.

ロックファイルからの依存関係のインストール (require-dev を含む)
現在のプラットフォームにロック ファイルの内容をインストールできることを確認しています。
ロック ファイルには、互換性のある一連のパッケージが含まれていません。 composer update を実行してください。

③composer.jsonに書かれている内容で更新される

④No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See [https://getcomposer.org/install](https://getcomposer.org/install) for more information.

composer.lock ファイルが存在しません。 ロック ファイルからインストールする代わりに、依存関係を最新のものに更新します。 詳細については、[https://getcomposer.org/install](https://getcomposer.org/install) を参照してください。

⑤⑥⑦⑧To initialize a project, please create a composer.json file. See [https://getcomposer.org/basic-usage](https://getcomposer.org/basic-usage)

プロジェクトを初期化するには、composer.json ファイルを作成してください。 [https://getcomposer.org/basic-usage](https://getcomposer.org/basic-usage) を参照してください

## 結果

インストール自体が上手くいったものは、

①両方ある状態でcomposer update

③composer.jsonがあり、composer.lockがない状態でcomposer update

④composer.jsonがあり、composer.lockがない状態でcomposer install

この結果から正しい挙動をするのは、composer.jsonがあるものだとわかりました。

なお、上記すべてでcomposer.jsonに書かれていたバージョンでインストールされることがわかりました。

現時点では、どうしてcomposer.jsonのバージョンが違うのかはわからなかった。
OSXでGtkWaveを使う

OS: OSX Ventura 13.4.1

論理シュミレーションの波形のチェックでGtkWaveはそこそこ便利ですが、OSXでGtkWaveを使おうとしたら、とらぶったので対処法をメモっておきます。

GtkWaveのインストールはBrewで一発です。

```
$ brew install --cask gtkwave
```

最初は開発者が信用できないと怒るので、一度MenuからOpenします。これでAppとしての起動はOK。
つぎにコマンドラインで起動すると下記のエラーで怒られます。

```
$ gtkwave
Can't locate Switch.pm in @INC (you may need to install the Switch module) (@INC contains: /Library/Perl/5.30/darwin-thread-multi-2level /Library/Perl/5.30 /Network/Library/Perl/5.30/darwin-thread-multi-2level /Network/Library/Perl/5.30 /Library/Perl/Updates/5.30.3 /System/Library/Perl/5.30/darwin-thread-multi-2level /System/Library/Perl/5.30 /System/Library/Perl/Extras/5.30/darwin-thread-multi-2level /System/Library/Perl/Extras/5.30) at /opt/homebrew/bin/gtkwave line 2.
BEGIN failed--compilation aborted at /opt/homebrew/bin/gtkwave line 2.
```

Gtkwaveは中でPerlなんか使ってるんですね、とりあえず下記でSwithを追加すれば上記エラーは回避できます。

```
$ cpan install Switch
$ sudo cp /Users/$USER/perl5/lib/perl5/Switch.pm /Library/Perl/5.30/
```

EDAするのにOSXはひと手間多くて色々不便です。嫌い。

## 参照

- https://formulae.brew.sh/cask/gtkwave
- https://ughe.github.io/2018/11/06/gtkwave-osx
    - PerlのSwitchについての記述
- https://gist.github.com/urbanij/ea2a4c355c1827ec9e52b5a3dfab9a74
    - ぐぐるとこの記事がHitしますが, わざわざPerlをBrewで入れる必要はない模様。
SFSafariViewControllerをUIKitと同じ挙動でSwiftUIで使用する方法

ネットの文献にはモーダルで表示する方法しか書かれておらず、push遷移の動作が実現できなかったので、今回はSwiftUIでSFSafariViewControllerをpush遷移のような動作で表示する方法を解説していきたいと思います。

## 実装

```Swift:SFSafariView.swift
import SwiftUI
import SafariServices

struct SFSafariViewControllerWrap: UIViewControllerRepresentable {
    @Environment(\.dismiss) var dismiss
    let url: URL

    func makeUIViewController(context: Context) -> SFSafariViewController {
        let viewController = SFSafariViewController(url: url)
        viewController.delegate = context.coordinator
        return viewController
    }

    func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) {
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    final class Coordinator: NSObject, SFSafariViewControllerDelegate {
        let parent: SFSafariViewControllerWrap

        fileprivate init(parent: SFSafariViewControllerWrap) {
            self.parent = parent
        }

        func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
            parent.dismiss()
        }
    }
}

struct SFSafariView: View {
    let url: URL

    var body: some View {
        SFSafariViewControllerWrap(url: url)
            .toolbar(.hidden, for: .navigationBar)
            .ignoresSafeArea(.all)
    }
}
```

## 使用方法
```Swift:HogeView.swift
struct HogeView: View {
    @State var isPresented = false

    var body: some View {
        FugaView()
            .navigationDestination(isPresented: $isPresented) {
                SFSafariView(url: URL(string: "https://google.com")!)
            }
    }
}
``` 
これでモーダル遷移ではなくpush遷移でSFSafariViewControllerを表示することができました。
IIO Command Line Toolsの使い方


[ADALM-PLUTO](https://wiki.analog.com/university/tools/pluto)をコマンドラインから使う方法の技術メモです。

本家はこちら->[IIO Command Line Tools](https://wiki.analog.com/resources/tools-software/linux-software/libiio/cmd_line)

## 解説
### iio_info
USBで接続したあと接続するURIを確認する。
```winbatch:接続可能なバックエンドを表示する
iio_info -s
```
Available contexts:
        0: 192.168.2.1 (Analog Devices PlutoSDR ... [ip:pluto.local]
        1: .... [usb:2.9.5]
などが出力される。以下これをURIに用いる。

```winbatch:情報出力
iio_info -u ip:pluto.local
```
### iio_attr
具体的な操作はこちらを使用する。

(ローカル周波数とフィルタの帯域幅の設定)
ローカル周波数は325MHzから3800MHzの間、帯域幅は20MHzまで
```winbatch:ローカル周波数とフィルタの帯域幅をセットする
#デバイスは"ad9361-phy"
#チャネルは"RX_LO"と"voltage0"
iio_attr -u ip:pluto.local -c ad9361-phy RX_LO frequency 82500000
iio_attr -u ip:pluto.local -c ad9361-phy voltage0 rf_bandwidth 300000
```
サンプリング周波数は521kspsから61.4Mspsで次のように設定する。しかし、低いサンプリング周波数はこれでは設定できず、ダウンサンプラーを設定する必要がある。
```winbatch:サンプリング周波数をセットする
#デバイスはad9361-phy
#チャネルはvoltage0
iio_attr -u ip:pluto.local -c ad9361-phy voltage0 sampling_frequency 705600
```
ダウンサンプラーを設定するには、次のようなコマンドで行えることになっている。しかしながら、コンパイル済みのiio_attrは、入力バッファが256バイトに制限されているため、コマンドラインツールでは、小さなタップのフィルタしか設定できない。このため、libiioを直接叩いて設定するしかない。
```winbatch:ダウンサンプルフィルタを設定する例
iio_attr -u ip:pluto.local -d ad9361-phy filter_fir_config
 RX 3 GAIN -6 DEC 4
 TX 3 GAIN 0 INT 4
 <FIR パラメータ>
```

データキャプチャーは、こんな感じでstd_outにバイナリデータで出力される。単発のデータでよければこれでキャプチャできる。コマンドラインツールではキャプチャしてデータを出力する処理に時間がかかり、連続して受信しようとするとギャップがあいてしまう。

```winbatch:データキャプチャ
#デバイスは"cf-ad9361-lpc"
#1024サンプルの(I,Q)を取り込む
iio_readdev -u ip:pluto.local -b 512 -s 1024 cf-ad9361-lpc
```

Juliaでデータを取り込むには、STDOUT出力を16bit signedのI,Qデータとして読み取ればよい。
```Julia:IIO Command Line Toolでデータを取り込む
dat=Array{Int16}(undef,1024*2)
open(`iio_readdev -u ip:pluto.local -b 512 -s 1024 cf-ad9361-lpc` )  do io
    read!(io,dat)
end
```
## 性能、残課題など
IIO Command Line ToolでPlutoを設定し、データを取り込む方法を解説しました。しかしながら、ダウンサンプルフィルタを設定したり、データを連続的に取り込むには、libiioを直接叩く必要があります。

関連記事)
KATU @0x20FE, [Julia ライブラリ呼び出し](https://qiita.com/0x20FE/items/0bd17d320af8cf04e249)
KATU @0x20FE, [ADALM PLUTOでFM受信(Julia版)](https://qiita.com/0x20FE/items/9b6498083ed52954aa42)
KATU @0x20FE, [ADALM PLUTOでFM受信してみる](https://qiita.com/0x20FE/items/0e229a4c31889903d019)(python版)
参考情報)
JA1SYK,http://www5.wind.ne.jp/ja1syk/pluto/pluto-index.html
JA1SYK,[ADALM-PLUTO（PlutoSDR)の設定マニュアル](http://www5.wind.ne.jp/ja1syk/pluto/PlutoSDRv5.pdf)
C#でワークシートを非表示にする

## はじめに
シートを非表示にすることは、スプレッドシートソフトウェアでよく使用される機能であり、ユーザーが特定のシートを非表示にし、ワークブック内で見えなくすることができます。シートを非表示にすることは、様々な目的に使用することができます。例えば、機密データの保護、ワークブックの構造の簡素化、または即座に表示する必要のない情報の非表示などです。以下に、詳細な手順をご紹介します。

## ツール
* Visual Studio 2022 
* [Free Spire.XLS for .NET](https://www.e-iceblue.com/Introduce/free-xls-component.html)

## インストール方法
1. [Free Spire.XLS for .NET](https://www.e-iceblue.com/Download/download-excel-for-net-free.html)をダウンロードします。
2. Visual Studioで新しいプロジェクトを作成します。
3. 「Solution Explorer」で「References」を右クリックし、「Add Reference」>「Browse」を選択します。
4. BINフォルダ内のdllファイルを見つけて、「OK」をクリックします。
## コード
```C#
using Spire.Xls;

namespace HideWorksheetsInExcel
{
    class Program
    {
        static void Main(string[] args)
        {
            //Workbookクラスのインスタンスを初期化する
            Workbook workbook = new Workbook();

            //Excelファイルをロードする
            workbook.LoadFromFile("Sample.xlsx");

            //最初のシートを取得する
            Worksheet sheet1 = workbook.Worksheets[0];

            //シートを非表示にする
            sheet1.Visibility = WorksheetVisibility.Hidden;

            //2番目のシートを取得する
            Worksheet sheet2 = workbook.Worksheets[1];

            //シートを非常に非表示に設定する
            sheet2.Visibility = WorksheetVisibility.StrongHidden;

            //結果ファイルを保存する
            workbook.SaveToFile("HideWorksheets.xlsx", ExcelVersion.Version2013);
        }
    }
}
```
以上のコードでは、Worksheet.VisibilityプロパティをWorksheetVisibility.HiddenまたはWorksheetVisibility.StrongHiddenに設定することで、シートを非表示にすることができます。また、ワークブックには少なくとも1つの表示可能なシートが必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/8e00a12b-981f-7210-6e97-0869d2e3e7e9.png)
その他、非表示になっているシートを表示したい場合は、以下のコードを参考にしてください。
```c#
            foreach (Worksheet sheet in workbook.Worksheets)
            {
                if (sheet.Visibility == WorksheetVisibility.Hidden)
                {
                    sheet.Visibility = WorksheetVisibility.Visible;
                }
                else if (sheet.Visibility == WorksheetVisibility.StrongHidden)
                {
                    sheet.Visibility = WorksheetVisibility.Visible;
                }
            }
```
Oracle Cloud Infrastructure Architect Associate 勉強メモ（セキュリティ）

# 概要
### 共有セキュリティモデル
オンプレ環境であれば顧客にすべての範囲の責任がある。
共有席にモデルであれば、物理的な範囲と仮想化の範囲はOracleが責任を持ち、その他を顧客が責任を持つ。
### 主なセキュリティ・サービス
- インフラ・ストラクチャーの保護
外部ネットワークから（パブリックから）のトラフィックを対策。
DDos Protection（DDos攻撃）
WAF（悪意のあるWEBトラフィックのフィルタリング）
Security List（パブリックからのトラフィック）
- OSとワークロードの保護
パッチ管理やワークロードの分離、要塞管理など。
Dedicated Host（専用ホスト、ほかのユーザとハードウェアを共有しないワークロード）
Bastion（要塞、重要なデータは内部に保持し要塞からアクセス）
OS Manager（OS管理）
- 検知と修復
セキュリティ・ポスチャー（クラウド環境精査）、セキュア・エンクレープ（システム上で実行されている他のプロセスから機密性の高いコードとデータを分離して保護）、自動セキュリティ診断、セキュリティ・アドバイザなど。
Cloud Guard
Max Security Zone
脆弱性Scanning
Security Advisor
- データ保護
保存中・転送中のデータ暗号化、鍵の保存・管理など。
Ecription（暗号化）
Key Management
Key Vault（ボールト）
Data Safe
- アイデンティティとアクセス管理
IAMによる管理。
# クラウド・ガード
セキュリティの問題の検出と対策（修正）の流れをクラウド・ガードを用いて構成する。
① ターゲット（調査対象）を決める。コンパートメントやサブコンパートメント。
② 問題点の検出。問題を検出した際に警告を発する（トリガーを発生させる）。
③ 問題として挙がる。
④ 措置を行う（自動または手動）。

# セキュリティ・ゾーンとセキュリティ・アドバイザ
### セキュリティ・ゾーン
セキュリティを無効にできない場所（コンパートメント）を作り出す。
コンパートメントにセキュリティ・ゾーンを設定すると、セキュリティ・レシピが作られる。
### セキュリティ・アドバイザ
セキュアなリソース作成のためのウィザード（テンプレートなどをもとに作成することができる）が用意されている。

# 脆弱性スキャン
潜在的脆弱性がないかCVE（脆弱性の情報を集めたデータベース、日々更新される）をもとに毎日または毎週検査する。
また、ポートのスキャン（不必要なポートが設定されていないかなど）をチェックする。脆弱性のレベルや適用すべきパッチなども教えてくれる。

# Vault（ボールト）
各キーをマスターキーで暗号化する。（マスターキーのみ守ればよい。各キーは対応するデータと同じバケットに保存）
キーのローテーションも可能。マスターキーのみをローテーションし、各キーは新しいキーで復号できる（暗号化はできない）。
対応する暗号鍵はAES、RSA、ECDSA（暗号化無し）
鍵はHSM（ハードウェア・セキュリティ・モジュール）かソフトウェアにてサーバー内に保存
HSMからエクスポートはできない。サーバーからエクスポート可能。

# WAFとDDoS

|機能|DDoS|WAF|
|:--:|:--:|:--:|
|保護対象|OCI|OCI、他クラウド、オンプレミス|
|監視レイヤー|3,4|3,4,7|
|保護ポリシー変更|なし|あり|
|アラート通知|なし|あり|
|有償|なし|あり|
【PHP】NULL 許容型の宣言方法

## 直面した問題
PHP7以降では関数・メソッドの引数に型を指定することができるようになりましたが、型を指定したところ、``null``が通らなくなりエラーが出てしまったので、その解決方法を備忘録として残したいと思います。

## 解決方法
この問題を解決するためには、引数に null 値を受け入れるために ``NULL 許容型（Nullable Type）`` を使用します。NULL 許容型を使用することで、通常の型と null を受け入れる型を指定することができます。

具体的には、引数に NULL 許容型を指定するには、引数の型名に ``?`` を付けます。以下は、具体的なコード例です。

```php
function exampleFunction(?string $text) {
    // $text は string 型または null を受け入れる
    // ここで引数の処理を行う
}
```
このようにすることで、引数に null 値を渡すことができ、エラーを回避することができます。
(Apple M2 Pro) Prophetエラーの解決

### 環境

```
% sw_vers
ProductName:            macOS
ProductVersion:         13.4
BuildVersion:           22F66

% system_profiler SPHardwareDataType
Hardware:
    Hardware Overview:
      Model Name: MacBook Pro
      Model Identifier: Mac14,9
      Model Number: Z17G000HJJ/A
      Chip: Apple M2 Pro
```

### エラー内容
prophetを使用している際に、fitメソッドを実行するとエラーが発生。
エラー内容はライブラリ libtbb.dylib が読み込まれていないことに関連。

```
dyld[81572]: Library not loaded: @rpath/libtbb.dylib
```

### 解決策
libtbb.dylibとその関連ファイルが適切な場所に存在しないため、以下の手順で解決：

1. /usr/local/lib ディレクトリを作成。

```
sudo mkdir /usr/local/lib
```

2. 以下のコマンドを実行して、必要なライブラリファイルへのシンボリックリンクを作成。

```
sudo ln -s $HOME/.pyenv/versions/3.11.4/lib/python3.11/site-packages/prophet/stan_model/cmdstan-2.31.0/stan/lib/stan_math/lib/tbb/libtbb.dylib /usr/local/lib/libtbb.dylib
sudo ln -s $HOME/.pyenv/versions/3.11.4/lib/python3.11/site-packages/prophet/stan_model/cmdstan-2.31.0/stan/lib/stan_math/lib/tbb/libtbbmalloc.dylib /usr/local/lib/libtbbmalloc.dylib
sudo ln -s $HOME/.pyenv/versions/3.11.4/lib/python3.11/site-packages/prophet/stan_model/cmdstan-2.31.0/stan/lib/stan_math/lib/tbb/libtbbmalloc_proxy.dylib /usr/local/lib/libtbbmalloc_proxy.dylib
```

上記のコマンドを実行した後、再度fitメソッドを実行してください。

### 注意点

* これらのコマンドはPythonのバージョン3.11.4に特定されています。必要に応じてPythonのバージョンを変更してください。

### 参考リンク
* https://github.com/facebook/prophet/issues/2250#issuecomment-1549802832
* https://stackoverflow.com/questions/73255165/library-not-loaded-rpath-libtbb-dylib-in-prophet-python/76264243#76264243
親要素からCSSのみで特定の子要素の有無を判別するセレクター:has()

## モーダルを表示する時の背景画面のスクロールを防ぐ際などに使用した。

・HTML
```
<body>
 <content>
 </content>
 <div class="modal_window">
 </div>
</body>
```

・CSS
`body:has(.modal_window){
  overflow: hidden;
}`

Jsでクリックイベントを監視して、overflow: hidden;を付与、削除するということもできるがユーザの予期せぬ操作が発生した際に、overflow: hidden;が適用されたままになってしまうこともあるのでこのやり方がいいと思った。
あと楽。
グリッドレイアウトでレイアウト組んだ話

普段はバックエンドエンジニアとしてコードを書いているのですが、最近マークアップも担当領域になりがCSSも担当することがあります。そこで、勉強になることがあったので、記事にまとめておこうと思い、執筆しました。

# 概要
みなさん、下のレイアウトを組む時ってどうしますか？

![スクリーンショット 2023-08-16 16.44.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/942467/c1baaf23-4c93-301f-2472-13acfa880dc1.png)
そこで役立つのがグリッドレイアウトです。

mdnにはこう書いてあります。
>グリッドは、列と行を定義する水平線と垂直線の集合が交差したものです。要素をグリッド上の行と列の中に配置することができます。

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout

正直これはめちゃくちゃ簡単にレイアウト組めます。
よっぽどのことがない限り、私はグリッドレイアウトでレイアウト組んでます。

# 完成形と解説
実際に私がグリッドレイアウトで組んだレイアウトがこんな感じです。
実際のコードは下に貼っておくので、気になる方は見てみてくださいください。

![スクリーンショット 2023-08-16 17.00.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/942467/0cb53ec5-20af-4693-33ac-f02e3f864f58.png)

htmlはulタグで作っています。
組み方はとても簡単です。
 
```
display: grid
grid-template-columns
```
だけです。笑

**grid-template-columns** は引数に取った分だけ横並びになるので、今回は

```
grid-template-columns: repeat(2, 75px);
```

のようにしてあげて75pxを2回繰り返してあげれば良さそうです。
縦と横の間隔は

```
row-gap: 24px;
column-gap: 32px;
```

で取ってあげればOKです。

# コード

```html:index.html
  <div>
    <ul class="bullet-points">
      <li class="bullet-point">
        <p>test1</p>
      </li>
      <li class="bullet-point">
        <p>test2</p>
      </li>
      <li class="bullet-point">
        <p>test3</p>
      </li>
      <li class="bullet-point">
        <p>test4</p>
      </li>
    </ul>
  </div
```

```css:styles.css
.bullet-points {
  display: grid;
  grid-template-columns: repeat(2, 75px);
  row-gap: 24px;
  column-gap: 32px;
}

.bullet-point {
  background-color: red;
  list-style: none;
}
```
java 配列重複値を唯一にする


```
package ATest;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Test4 {
	
	
	static ArrayList oAlArray = new ArrayList();
	
	static ArrayList oAlArray2 = new ArrayList();
	
//	
//	oAlArray.add("1");
	
	private static <T> boolean checkForDuplicates(T... array)
	{
	    //空のセットを作成します
	    Set<T> set = new HashSet<T>();
	 
	    //すべてのアレイ要素に対して実行
	    for (T e: array)
	    {
	        //重複が見つかった場合はtrueを返します
	        if (set.contains(e)) {
//	            return true;
	        	
	        	oAlArray.add(e);
	        	
	        	System.out.println("e=   "+e);
	        	
	        }
	 
	        //現在の要素をセットに挿入します
	        if (e != null) {
	            set.add(e);
	            
	        }
	    }
	 
	    //重複が見つかりません
	    return false;
	}
	

	public static void main(String[] args) {
		// TODO 自動生成されたメソッド・スタブ
		
		
		//一次作業配列生成
		String oStUsrNo[] = new String[9];
		//利用者識別番号リスト生成
		List oLiUsrNo = new ArrayList();

		//チェック対象利用者識別番号を取得し、一次作業配列に格納する
		oStUsrNo[0] = "333";
		oStUsrNo[1] = "111";;
		oStUsrNo[2] = "333";;
		oStUsrNo[3] = "111";;
		oStUsrNo[4] = "888";;
		oStUsrNo[5] = "666";;
		oStUsrNo[6] = "888";;
		oStUsrNo[7] = "333";;
		oStUsrNo[8] = "111";;
		
		
		System.out.println(checkForDuplicates(oStUsrNo));
		
		//重複値を唯一にする
		oAlArray2 = new ArrayList<String>(new HashSet<>(oAlArray));
		
		
		System.out.println(oAlArray2);
		
		System.out.println("\n重複以下です");
		
		for (int i=0;i<oAlArray2.size();i++) {
			
			System.out.println(oAlArray2.get(i));
		}
		
		

	}

}
【Postfix】バウンスしたメールアドレスを回数・理由とともに抽出する

## 概要
- メールログからバウンス情報を抽出し、回数が多い順にソートして出力する
- アドレスごとの直近のバウンスした理由の内容も含める

## 環境
- postfix 2.6

## シェルプログラム
```check-bounce.sh
#!/bin/bash

# バウンスログファイルのパス
BOUNCE_LOG="/var/log/maillog"

# バウンス情報を抽出し、回数が多い順にソートして出力する関数
extract_and_sort_bounces() {
    awk '
        BEGIN { FS = "[<>]" }
        /status=bounced/ {
            email = $2
            reason = $0
            gsub("^.*said: +", "", reason)
            bounces[email]++
            bounce_reasons[email] = reason
        }
        END {
            for (email in bounces) {
                print bounces[email], email, bounce_reasons[email]
            }
        }
    ' "${BOUNCE_LOG}" | sort -nr
}

# メインの処理
main() {
    bounce_info=$(extract_and_sort_bounces)
    if [[ -z ${bounce_info} ]]; then
        echo "No bounce found."
        exit 0
    fi

    echo "Bounce Count | Email Address | Latest Bounce Reason"
    echo "----------------------------------------------"

    while IFS= read -r line; do
        count=$(echo "${line}" | awk '{print $1}')
        email=$(echo "${line}" | awk '{print $2}')
        reason=$(echo "${line}" | awk '{$1="";$2="";print}' | sed -r "s/^\s+//g")
        echo "${count} | ${email} | ${reason}"
    done <<< "${bounce_info}"
}

main

```

以上、お疲れ様でした！
craft cmsで自作プラグインを作成できるか試す

# 概要
WordPress以外に良いcms無いかなと思って探す事がたまにあります。

craftcmsは有償のcmsな分？ドキュメントがしっかり書かれており、プラグイン機能もあるのでcmsの良いところを取り込みながら、モダンな開発ができるのでは？と思って触ってみました。

※プラグイン機能もcomposerで管理している


## craft cmsセットアップ

ddevからインストールする事を推奨しているようですが、直接zipからのダウンロードもできるようなので、今回はzipからセットアップします。

https://craftcms.com/docs/4.x/installation.html

解凍したzipを環境にアップしたらコマンドを打ちます。
対話形式で色々聞いてくるので、設定します。
終了するとインストール完了です。
```php
php craft setup
```


## プラグインの作成
プラグインの雛形作成コマンドが無いか調べたところ外部ライブラリとして提供しているようです。

https://craftcms.com/blog/craft-generator

```
composer require craftcms/generator --dev
```

composerからインストールしますと、どうやらzipからダウンロードしたcraft cmsのバージョンが古いためエラーが出てインストール出来ないと怒られたので、アップデートします。

コマンドからアップデートでも良いのですが、管理画面からでもcomposerで管理しているcraftcmsのバージョンをアップデートできるようなので管理画面からアップデートします。

※スクショは最新バージョンにアップデート済み

ユーティリティ→アップデート
![test1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280639/767bdaf8-ef55-4b19-de43-a52df5058f50.png)

### 雛形作成コマンドを試す
インストールできるようになったので「composer require craftcms/generator --dev」を実行します。

雛形作成コマンドを実行します。対話形式で聞かれているので、設定します。

```
php craft make plugin
```

設定が終わると、composerからインストールして有効化してねと出るのでコマンドを打つとインストールされます。


```
composer require 作成者/プラグイン名
php craft plugin/install _プラグイン名
```

有効化は「php craft plugin/install」だが管理画面からでも行える。
有効化すると空白の設定ページのviewができる。(twig)

![test2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280639/1dd82b3b-3c7c-ba21-57d4-62bff918fafd.png)



多分プラグインインストール時にmigrationsを定義して独自のテーブルなどを作成できると思いますが、まだ調べきれてない。

https://craftcms.com/docs/4.x/extend/migrations.html


## 感想
完全に独自のシステムを使うならlaravel backpackが良いですが、

未だにWordPress オープンソースと聞くと不安になるお客様も多いと思うので、cms機能も使ってモダン技術で開発したいならcraftcmsはありかなと思いました。

というかWordPressみたいにプラグインインストールしなくても基本機能だけで色々できそうな感じはします。
IBM Turbonomic で確認できるFinOps



ここで紹介されているサイトでTurbonomic の機能をUIを確認していきます。

https://qiita.com/YoHey/items/52bd8ec4464dbaa87a5f

Turbonmicの機能は、クラウド環境のFinOpsとアプリケーション監視です。
それぞれの画面は以下の通りで、統一的なビューになっています。

・Cloud Infrastructure FinOps
![Infra FinOps.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94200/acb24fcf-1365-4b1a-dc2f-16921efb4847.jpeg)

・Applicaition Monitoring
![Application.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94200/62ec63db-de74-8a54-4505-be116d7f5eca.jpeg)
【TCA】ViewStateを使っている時に@ObservedObjectでViewStoreを使用する

# はじめに
おととい、2種類のViewStoreの扱い方を記事にしました。

https://qiita.com/SNQ-2001/items/290cabf38b7ea2ed077f

# Reducerはこんな感じ
```swift
struct Feature: Reducer {
    struct State: Equatable {
        var text = "Hello, World!"
    }
    
    enum Action: Equatable {
        
    }
    
    func reduce(into state: inout State, action: Action) -> Effect<Action> {
        
    }
}
```

# 実装
```swift
import SwiftUI
import ComposableArchitecture

struct ContentView: View {
    @ObservedObject private var viewStore: ViewStore<ViewState, Feature.Action>

    let store: StoreOf<Feature>
    
    init(store: StoreOf<Feature>) {
        self.store = store
        self.viewStore = .init(store, observe: ViewState.init(state:))
    }

    struct ViewState: Equatable {
        let text: String
        
        init(state: Feature.State) {
            self.text = state.text
        }
    }

    var body: some View {
        Text(viewStore.text)
    }
}
```

# おわり
いろんな書き方があって難しい
MW WP formプラグインが誤作動する

### ● orijinal.jsに入れていた過去のformに関するjsが原因だった。
### ● name=""の""の中にnameという値を入れていた（Wordpressのシステム側で既に使用済みのため、お名前などはyour_name等に名前を変えること。他にも使用できないnameの値があるので注意が必要）

### ● php内に直接ショートコード呼び出しを書かず、固定ページにてショートコードをブロックエディターで入れる。
phpの方には、<?php the_content(); ?> をいれて呼び出し。
(備忘) AWS ECS - デプロイタイプを CodeDeploy に変えると terraform apply で ECSサービスに紐づくタスク定義の設定が更新できなくなる

![IMG_4401.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89618/33aa20e7-5c0f-80e5-ec83-e0fec1bdf34e.jpeg)
# 背景

CodepipelineでのECSのデプロイ方法をECS(ローリング)からCodeDeploy(blue/green)に変えたい

# エラー内容

ECSサービスの デプロイタイプを CODE_DEPLOY にするとタスク定義の更新ができなくなる

```
Unable to update task definition on services with a CODE_DEPLOY deployment controller.
Use AWS CodeDeploy to trigger a new deployment.
```

terraform appley 時にECSサービスに紐づくタスク定義の内容に差分があると上記エラーが発生するようだ。

# 概要

CODE DEPLOYで blue/greenデプロイをする場合はECSサービスでタスク定義を管理するのではなくCODE DEPLOY で管理するらしい。


かと言ってECSサービスのタスク定義を未設定にはできないようだ。(どうしろと)

```
 Error: creating ECS Service (***): InvalidParameterException: TaskDefinition can not be blank.
```

# TRY

試しにTerraformのコードで ECSサービスに紐づく task_definition の ARNを現在のものに固定してみる
(差分を無くす)

```
resource "aws_ecs_service" "default" {
  ...

  # task_definition                 = data.aws_ecs_task_definition.default.arn
  task_definition                   = "arn:aws:ecs:***************:task-definition/**********:111"
```

結果はapplyが出来るようになった

(だが「意味もなくECSにタスク定義をいちど紐づけておいて次からはエラー回避のためにバージョンを固定する」なんていうこの方法が良いはずはないのだが。引き続き調べる。ignore_changesでタスク定義を更新無効にしておいたら良いのだろうか)

## 問題

terraform apply は (とりあえずのとりあえずで) 通るようになったのだが、
問題として ECSサービスのサービス名を1文字変えるだけでもECSサービスを破棄(destory)してから作り直されるようになってしまった。
デプロイタイプをCodeDeployにした場合の制約なのだろうか。

恐らくこの影響で実際のWebサイトアクセスにもダウンタイムが発生してしまう。

<img width="777" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/a0f7527d-cad7-4de4-ad99-3dd0dfd2d08f">


次のような対応をしなければいけなさそう？

- Terraformは初期構成時にだけ利用するようにして ECSサービスへの変更は ignore_changes しておく (Terraformでの変更は反映しない)
- もしくはECSサービス設定をTerraformから変更する場合はダウンタイムを許容する


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
私的サーバー構築日誌：NTPクライアント

# 能書き

[私的サーバー構築日誌：仕切り直し](https://qiita.com/katz_engineer/items/1f21de2bd9072c260ae6)からの自宅サーバー構築の続きです。

時刻同期はサーバーのみならずクライアントでも必須です。テスト用には時刻をわざとずらせるようにした方が都合が良い事も多いんですが、それはまた別の話。

systemd-timesyncdが勝手に動いてるので放置しておけば良いのですけども。日本人が日本にサーバーを立てるなら、NTPサーバーはやはり`ntp.nict.jp`ではないかと考える次第です。

## 目標

と言う訳で、NTP サーバをデフォルトから変更し、`ntp.nict.jp`にします。

## 参考文献

- [NTP サーバー : NTP クライアントの設定 - ServerWorld](https://www.server-world.info/query?os=Ubuntu_20.04&p=ntp&f=3)
- [【NTP】日本から使える公開NTPサーバ - Qiita](https://qiita.com/keigo_kabutomori/items/945b543cbe2792dd8d80)
- [日本標準時 に直結した時刻サーバ - 公開ＮＴＰ - 日本標準時グループ](https://jjy.nict.go.jp/tsp/PubNtp/index.html)
- [[Q.1-7]	個人ユーザですが、stratum 1 にアクセスしても構いませんか？ - NICT公開NTP FAQ - 日本標準時グループ](https://jjy.nict.go.jp/tsp/PubNtp/qa.html#q1-7)

# 準備

今回は```/etc```の修正だけなので、スナップショットは不要でしょう。気になる方は撮って下さい。

NTP クライアントが動いている事を確認します。

```console
systemctl status systemd-timesyncd
```

または

```console
timedatectl timesync-status
```

# 設定

```console
sudo sed -i -e"/^#NTP=/c NTP=ntp.nict.jp" /etc/systemd/timesyncd.conf
```

```console
sudo systemctl restart systemd-timesyncd
```

# 確認

準備と同じコマンドを実行して確認します。

特に難しい事も無いので、一発で行けるでしょう。

# 仕舞い

`/etc`の修正をバージョン管理しておきます。

```console
cd /etc
sudo svn ci -m"setting NTP client"
```
PF作成：１５日目

１５日目。今日で中間地点。そろそろEC2の作業、作業の取捨選択などをして後半のテストに向けての準備をし始めないといけない。それにしてももう半月経ったのか。早いな。

## 進捗
- 現状で機能的問題がないか確認
- 管理者側やユーザーログイン後、ログイン前のページ閲覧許可機能を実装
-  ransackを使用したキーワード検索の着手

## 学習
- ログイン前の表示やコントローラーはuser側を使用しようと思っていて、if文を使用して表示、非表示にしていたのだが管理者側から閲覧すると非表示にできなくてリンクや画像などが二つ現れるという現象が起きた。原因はif文の使い方が違うということはわかっていたのだが、実際どうすればいいのかわからず質問。結果、elseを入れ込んであげたら解決した。adminがログインしていたらこのリンクを表示させて、それ以外だったらこっちを表示させるという分岐の仕方。elseはそれ以外という使い方ができるのを忘れていた。
- 部分テンプレートを使用しているビューで特定の１ページで１文だけ消したいと思い、IF文を使用すれば可能かなと思ったがどう記述すればいいのかわからなくて質問。<br>まずはapplication.html.erbの最後の方にに開発中にのみ現在のデータを確認できるコードを記述。
```ruby:app/views/layouts/application.html.erb
<!--現在のviewデータを表示-->
<%= debug params if Rails.env.development? %>
<!--ログインしているユーザーデータを表示-->
<%= current_user.inspect if Rails.env.development? %>
<!--ログインしている管理者データを表示-->
<%= current_admin.inspect if Rails.env.development? %>
  </body>
```
このコードにで表示したくないページのデータを確認してIF文を使用して表示させないことが可能。

```ruby:app/views/.erb
<!--この部分テンプレートを使用している特定のページにのみ寺社名を表示させないIf-->
<% if params[:controller] != 'user/places' && params[:action] != 'show' %>
```
今回の場合だったら投稿された御朱印がどこの寺社なのか分かり易いように寺社名を表示していたが、寺社詳細ページにもその寺社名を表示する必要はないと思ったのでこの記述となった。


## エラー
- 管理者側の寺社詳細ページのページネーションがうまく機能しなくて、メソッドエラーが起きた。原因がわからず質問してからもう一度見直したら、管理者側のコントローラーページネーションの記述をしていなかった。質問前に確認いていたコントローラーがユーザー側だったことが原因。よくやるミスなので再度注意しよう。
- JavaScriptの挙動がおかしい。クリックしたらセレクトボックスが開いて、スペースをクリックしたら閉じる仕組みなのにクリックしたら開いてすぐ閉じるという挙動をしてしまっている。原因はよくわからなかったが、今までの記述がJavaScriptを使用した正しい記述ではなかったので修正したら治った。

```ruby:app/javascript/packs/js
// セレクトボックスの中にチェックボックス
  // クリックしたら発火
  $('.checkbox-toggle').on('click', (e) => {
    const targetName = $(e.target).attr('id')
    $(`#${targetName}Checkboxes`).slideToggle();
    $(`#${targetName}Checkboxes`).css('display', 'flex');
  });
});
```
JavaScriptはバグの発見、修正が大変らしいので、丁寧に記述していく。consol logなどを使用してまず読み込まれているかの確認など。<br>下記一部抜粋

```ruby:app/views/.erb
<form>
    <!--   チェックボックスの表示切替ボタン   -->
    <div class="checkbox-toggle mt-3 ml-auto mr-auto" id="petButton">
      ペット連れ<br>
      <font color="gray">▼</font>
    </div>
    <!--   チェックボックス   -->
    <div class="checkboxes" id="petButtonCheckboxes" style="display: none;">
      選択してください
      <label>
        <input type="checkbox">
        <span>OK</span>
      </label>
      <label>
        <input type="checkbox">
        <span>NG</span>
      </label>
      <label>
        <input type="checkbox">
        <span>わからない</span>
      </label>
    </div>
  </form>
```
viewの記述も変更。前だとbootstrapの記述でJavaScriptのクラスを兼用していたりしたがそういうことはしてはダメ。
id=クラス名を指定してあげることでセレクトボックスの中身を入れることに成功。



## ヒント
- JavaScriptのイベントはイベントハンドラと言っていろいろ種類がある。<br>参考資料：https://phpjavascriptroom.com/?t=js&p=event
- JavaScriptを使用する動くWebデザイン<br>参考資料：https://coco-factory.jp/ugokuweb/


## 明日の予定
 ransackを使用した検索の着手に入れたので最低でもキーワード検索機能は完成させて、次の絞り込み検索に着手できるようにする。ただ明日は学習時間の確保が難しそうなので頑張らないといけない。
ELOコンペにトライ part4_予測モデルの構築

## これは何の記事？
ELO MERCHANT CATEGORY RECOMMENDATIONコンペの学習ログです
予測モデルを構築します（[▶前回の記事](https://qiita.com/kame_house_0828/items/78bc7dfeec48e72370a7)）

## 環境
VSCode

## 記事の流れ
- 必要なライブラリをインストール
- 重回帰モデル
- 学習結果
- ミニ考察
- submit

## 必要なライブラリをインストール
そもそも途中からVSCodeに変更したので、ライブラリをインストールできていない
```python
pip install statsmodels
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3179561/99c301d4-039c-fc67-45e1-3bbd2374d8a0.png)
```python
pip install scikit-learn
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3179561/af66d284-ea71-e5d6-1af0-bb288a4a726e.png)
```python
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import LabelEncoder
```

## 線形回帰モデルを用いる
```python
# 目的変数と説明変数を分割、並行して不要なカラムを削除
x = train_df.drop(["card_id", "first_active_month", "target"], axis=1)
y = train_df["target"]
x.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3179561/87809f8d-a2ba-1a88-bc8e-26b2793aa3d7.png)
```python
# "hist_category_3_freq"はA,B,Cと3種類あるから、LabelEncordingを実施
le = LabelEncoder()
le = le.fit(x["hist_category_3_freq"])
x["hist_category_3_freq"] = le.transform(x["hist_category_3_freq"])

x.head() # A=0,B=1,C=2で一列で作れる
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3179561/172ebc4b-4b41-b691-e931-1c2f8a163a4a.png)
```python
# データを訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)

# 線形回帰モデルを学習
model_linear = LinearRegression()
model_linear.fit(x, y)

# テストデータで予測を行う
y_pred = model_linear.predict(X_test)

# 二乗平均平方根誤差で評価
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print("Test Mean Squared Error:", rmse)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3179561/46c33f20-95ca-aebc-81de-e23e9a917995.png)
```python
import statsmodels.api as sm

# 決定係数、偏回帰係数などを求める
# add_constantを使用して切片の列を追加
X_train_with_constant = sm.add_constant(X_train)

# OLS（最小二乗法）モデルを作成
model_least_squares = sm.OLS(y_train, X_train_with_constant)

results = model_least_squares.fit()
print(results.summary())
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3179561/a86a8211-adb1-c6a3-095d-08102fdb6b26.png)

## 学習結果
targetの予測結果は以下。予測精度はかなり低い模様。

|評価指標|評価値|補足|
|---|---|---|
|RMSE|1.693|0に近いほど精度高い|
|決定係数|0.009|1に近いほど精度高い|
|自由度調整済み決定係数|0.009|決定係数の代わり|

## ミニ考察
95％信頼区間（[0.025 0.975]の箇所）を確認すると、p値が0.05より大きいカラムがいくつも存在している。これらはtargetの予測に対して関係性が極めて低い。

よって、targetに関係の高いカラムは以下…？
|targetとの関連性が高い？|
|---|
|feature_1|
|feature_2|
|merchant_variety|
|installments_mean|
|hist_purchase_date_term|
|hist_purchase_date_freq|
|hist_lag_mean|
|hist_lag_min|
|hist_lag_max|
|hist_lag_var|
|authorized_flag_Y|
|hist_category_1_ratio_N|

上記の特徴量がtargetに関連するので、施策時に参照するKPIとしておけそう

～part5に続く～
GitHub Actions でのブランチ名取得


# GitHub Actions でブランチ名を取得する方法
GitHub Actions でブランチ名を取得する際、push時とpull request時で取得方法が異なる。
そのためのメモを残しておく。

## 結論

|  |GITHUB_REF|GITHUB_HEAD_REF|GITHUB_BASE_REF|
| ---- | ---- | ---- | ---- |
| push時 | refs/heads/${branch_name} | 空 |  空 |
| Pull Request時 | refs/pull/${PR_number}/merge | pull request元ブランチ | pull request先ブランチ |

## 備考
echo GITHUB_REF で"refs/heads"部分が邪魔な場合は、
echo ${GITHUB_REF#refs/heads/}　のようにすればOK
```
echo GITHUB_REF 
refs/heads/testbranch
```
```
echo ${GITHUB_REF#refs/heads/}
testbranch
```
## 参考
https://qiita.com/shigeshigeshige/items/a4270cd696e36d96b085
pythonでimportしたモジュールのローカル場所を確認する

モジュールも`__file__`属性があります。当モジュールの`__init__.py`ファイルの場所を指します。

それを調べること。

```python
>>> import sklearn
>>> sklearn.__file__
'/Users/ユーザー名/.pyenv/versions/miniconda3-3.8-4.10.1/lib/python3.8/site-packages/sklearn/__init__.py'
```
Fetch APIを使う際のエラーハンドリング

## はじめに
Fetch APIを使った処理のエラーハンドリングはどうするのが正解なのか、色々調べながら試してみて、とりあえず下記のような形式で落ち着いたので紹介したいと思います。


## 実際のコード
今回はReactを使ったPOSTメソッドでの処理を例に挙げてみます。
バリデーションエラーメッセージがあることも考慮して作りました。

```javascript
// APIを叩く関数
export const post = async (apiEndpoint, token, dataBody) => {
  try {
    const res = await fetch(apiEndpoint, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(dataBody),
    });

    const data = await res.json();

    if (res.ok) {
      return data;
    }

    if (data.errors) {
      return data;
    }
    // catchの中で一緒に処理するために例外をスロー
    throw new Error(`${res.status} ${res.statusText}`);
  } catch (error) {
    console.error("Error:", error.message);
    console.log(error.stack);
    return {
      errors: ["予期しないエラーが発生しました"],
    };
  }
};

// 呼び出し側の処理
const handleSubmit = async (e) => {
    e.preventDefault();
    const result = await apiClient.post(apiEndpoint, token, {
      folder: { name: folderName, parent_id: parentId },
    });
    if (result.errors) {
      setErrorMessage(result.errors);
      return;
    }
    handleSuccess();
};
```
バリデーションエラーメッセージがある場合はそれを返して表示させて、コンソールには特に何も表示しないようにしています。
422以外のエラーでバリデーションメッセージが特にない場合や、例外が発生した場合は、catchで専用のエラーメッセージを返しています。

また、下記のようにcatchで2行で書いている箇所は1行で書くこともできます。
```javascript
// 変更前
console.error("Error:", error.message);
console.log(error.stack);
// 変更後
// これならスタックトレースも表示される
console.error("Error:", error);
```

しかし、`throw new Error("message")`のようにしてエラーオブジェクトを使って例外をスローし、エラーオブジェクトをそのまま出力すると、`Error:`というプレフィックスが付加されます。
なので、`console.error("Error:", error);`としていると、コンソールに`Error: Error: message`といった風に表示されてしまいます。
それならば`Error:`をわざわざつける必要は無いと思ったのですが、実際にネットワークエラーなどで例外がスローされた場合は`Error:`というプレフィックスはつかないみたいなので、なるべく形式を統一するために`console.error("Error:", error.message);`で`Error:`が付かない形式でメッセージだけを取り出して表示するようにしました。
その場合はスタックトレースは表示されないので、`console.log(error.stack);`のようにして表示させています。

## あとがき
改めてコードを見るとスマートじゃないですね。。POST以外にも対応した形式で作れた方がいいでしょうし、改善点がたくさんありそうです。。
間違っている点や改善点、もっといい方法がありましたら是非取り入れたいと思いますので、ご教授いただけますと幸いです。
【自分メモ】Udemy「【入門】システム要件定義と基本設計」のアウトプット4

## 背景

昨年から会社でWeb開発の手法を学んできましたが、開発技術面がある程度理解できてきたので、設計面での勉強を開始しました（開始させられました）。Udemy「【入門】システム要件定義と基本設計」を視聴して、理解したことをアウトプットしていこうと思います。

Udemyの講義はこちら
https://www.udemy.com/course/digisaku_requirements_definitio

## 基本設計の進め方

基本設計では、要件定義で定めた要件を満たすシステムの全体完成イメージをビジネス側に伝えることが求められます。実際の業務フローと合わせるために、ビジネス側との連携が重要です。

基本設計の成果物は以下の通りです。

- 画面設計
- 機能設計
- データ設計

要件定義から画面設計、機能設計、データ設計の順で進めますが、要件定義の不備が見つかった場合は都度修正し、１～３の流れも何度か繰り返してブラッシュアップしていきます。

画面設計を最初に作成し、ビジネス側に確認してもらうことで要件定義の検討漏れを発見できます。

### UI設計思想
はじめに、要件からタスク志向で作るべきかオブジェクト指向で作るべきかを検討する必要があります。
適切なものを選べないと無駄な動きが多くなります。
### 事前知識

#### タスク志向

ユーザーがやりたいことを起点に設計したUIです。
オブジェクトがメインで、操作手順（タスク）に意味があるときに有効です。
タスク志向は、動詞で表されるものに着目した設計思想です。

#### オブジェクト指向

ユーザーが知りたいことを起点にしたUIで、直観的で使いやすいUIです。
オブジェクトが豊富なパターンに多く、モノに着目した設計思想です。

#### データの種類
- マスタデータ
オブジェクト固有のデータ
- トランザクションデータ
ユーザー操作によって変化するデータ

### 画面設計の進め方

1. 項目の洗い出し
まずは画面に表示すべきオブジェクトとタスクを洗い出します。
オブジェクトを洗い出し、そのオブジェクトに対するタスク（メールに対しての送信、削除、送信など）が決まります。
2. 骨組み作り
オブジェクト指向かタスク志向かを決定し、画面遷移図を作成します。
3. 肉付け
洗い出したタスクを画面遷移図に当てはめ、すべてのタスクを網羅しているか確認します。
そして画面遷移図をもとにレイアウトを作成します。
このレイアウトをワイヤーフレームと呼びます。
ワイヤーフレームを使用してビジネス側とディスカッションを行い、ワイヤーフレームを作る中で気づいた必要なものも追加します。
※きれいなレイアウトはデザイナーの仕事であるため、大まかな要素と配置が分かればよいです。

### 機能設計の進め方

1. 変動項目の洗い出し
画面設計から変動する項目は、データベース(DB)に保存する必要があります。
どの情報のDBが必要かを洗い出します。
2. ユーザ操作の洗い出し
ユーザーが行う操作の処理内容、関連DB、トリガーを洗い出します。
例えば「初期表示」の処理、○○一覧のDB、ページアクセスのトリガーなどです。
3. 機能説明
洗い出した操作とDBから機能一覧を作成します。
ユーザー操作の対象ページ、トリガーに加えて詳細な処理内容、必要なDBのデータ、データの渡し先を記載します。
その後、画面遷移図と機能一覧を紐づけます。

### データ設計の進め方

機能設計で洗い出したDB情報からER図を作成します。

- データ構造
テーブルをマスタとトランザクションに分け、どのようなカラムが必要かを定義していきます。
- リレーション定義
テーブル間の参照関係を整理し、ER図に書き起こします。
- 全体の可視化
画面設計、機能設計、データ設計を紐づけます。
Make で define が使えるのを知らなかった

- `make` で複雑なことをやってはいけないことはわかっていたが，やりたかったのでやってしまった．
- とはいえ，どうやって書けばいいかわからなかった．
- `make -p` は覚えておいた方が良さそう

## foreach ファンクション

foreach できる

https://www.gnu.org/software/make/manual/make.html#Foreach-Function

## call ファンクション

variable を call できる．
変数だと `$(1)` みたいなものを展開するのに使える．
変数には，コマンド組み合わせも含まれる．

https://www.gnu.org/software/make/manual/make.html#Call-Function

## eval ファンクション

その場所で引数の値を評価することができる．

https://www.gnu.org/software/make/manual/make.html#Eval-Function

## define

`define` によって，複数行の定義を変数に割り当てることができる．

https://www.gnu.org/software/make/manual/make.html#Multi_002dLine

## テンプレ

```Makefile
define XXX_F
$(1):
    # body
endef

$(foreach yyy,list of args,\
  $(eval $(call XXX_F,$(yyy))))
```

:::note info
この使い方の define を使う場合，`$` は `call` で使うので，
普通に使うには `$$` のように書かないといけない．
:::

# おまけ

## wildcard

```makefile
FILES = $(wildcard */*/*.c)
```

## dir

```makefile
DIRS = $(dir lib/a.dylib include/a.h)
```

## patsubst

```makefile
NAMES = $(patsubst %/,%,$(dir lib/a.dylib include/a.h))
```

## Refs

https://www.gnu.org/software/make/manual/make.html

https://www.ecoop.net/coop/translated/GNUMake3.77/make_toc.jp.html

https://tex2e.github.io/blog/makefile/multi-dir-of-each-input-file

https://qiita.com/yetnone/items/e2e53b547562bf984aaa

### おまけ側

https://nao-bamboo.hatenablog.com/entry/2015/09/11/175832

https://tex2e.github.io/blog/makefile/functions
お久しぶりです。帰ってきそうです。

なぜか思うところがあってか戻ってくる宣言しそうなHiro_Matsunoです。　　
いることがいっぱいになってきてしまうので舞い戻る道を模索していますね。　　
なんかたのしくなってきちゃったんです。
　　
組むことが今年の2月までいやだったんです。　　
エンジニアなんかに戻るもんかって思っていました。　　
やっぱりいえる事はやっぱエンジニアは所詮同じ業種に戻っていくんだと思います。　　
わらっちゃったのは青島さんや瀬谷さんや俺の後釜に入れた三浦くんが思わず言った言葉が1年後まさかQiitaやハッカソンの世界に戻ってきてたりしてなんていわれました。　　
言い当たってました。　　
トッププレイヤーとしての俺を求める彼らの心の声が俺を支えてきましたね。　　
本当は戻るつもりがない俺と戻りたい俺と格闘しての上で結局はQiitaまで戻ってきましたが。　　
やっぱり訓練が必要になってくるので徐々にやっていこうかなと思います。
ハッカソンのトップコンテンターHiro_Matsunoの復活をみんなが求めているということが分かってきたので入院中に黙って参加しようと思います。
ハッカソンって結構サービスなどを考えていく面で必要なんですよね。
実は最後の最後にアイデアと切り抜け方が重要なんですよね。　　
それを意図も簡単にクリアしていく俺に期待している人いるんですよ。
伴野さんがｗ。　　
やっぱみんなに愛されているんだなと今思いましたのでこんなポラム書かせてもらいました。　　
ありがとうよ。相棒たち。　　
いつかはハッカソン復活するから待ってろよ。　　

Hiro_Matsunoでした。

では。
Javaで「ファイルかディレクトリかを判定する(Files.isDirectory)」の動作を確認してみた

# 概要
Javaで「ファイルかディレクトリかを判定する(Files.isDirectory)」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/start/file/index2.html

# 実装
以下のファイルを作成しました。
```JSample2_1.java
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;

class JSample2_1{
  public static void main(String[] args){
    Path p1 = Paths.get("doc/report");
    Path p2 = Paths.get("doc/manual");
    Path p3 = Paths.get("doc/memo");

    checkDirectory(p1);
    checkDirectory(p2);
    checkDirectory(p3);
  }

  private static void checkDirectory(Path p){
    System.out.print(p.getFileName() + "は");
    if (Files.isDirectory(p)){
      System.out.println("ディレクトリです");
    }else{
      if (Files.exists(p)){
        System.out.println("ファイルです");
      }else{
        System.out.println("存在しません");
      }
    }
  }
}
```
以下のコマンドを実行しました。
```
$ javac JSample2_1.java 
$ java JSample2_1 
reportはファイルです
manualはディレクトリです
memoは存在しません
```

# まとめ
何かの役に立てばと。
エンジニアにとっても重要なマーケティング知識

マーケティングの基礎やマーケティングに使う統計情報を知りたいなら![816EC124-F25A-4ADA-B15A-07E1F77D0BB6.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533469/3132bede-6582-9480-47d0-65f57c2e7092.jpeg)
MarkeTALEがおすすめです。

MarkeTALE（マーケテイル）は、現役マーケターが運営する情報メディアです。現役マーケターのリアルな声や、お仕事に必須な統計情報をまとめています。

データに基づく意思決定をしたい方、マーケティングの仕事を知りたい学生や会社員におすすめのメディアです。

メディア記事はこちら
▼MarkeTALE（マーケ小噺）
https://hitofude-neko.com

Twitterでも配信しています。 
▼BtoBmarketingBot
https://x.com/btobmarket79451
jQuery validationでエラーメッセージを入力欄の後にブロック要素として出したい

jQuery.validateでざっくりこんな感じのフォームがあったとします。
名前、IDに必須のバリデーションをかけ、それぞれ空欄だとエラーが出ます。

```html
<form method="POST" id="register">
  <input name="name" type="text" >
  <input name="id" type="text" >
  <button type="submit">送信</button>
</form>
```
```javascript
var validation = $('#register').validate({
    rules: {
      name: {
        required: true,
      },
      id: {
        required: true,
      },
    },
    messages: {
      name: {
        required: 'ユーザー名を入力してください',
      },
      id: {
        required: 'idを入力してください',
      },
    },
    
    errorPlacement: function (error, element) {
      error.insertAfter(element)
    },
  });

var result = validation.form();
```

これだと、実際に出るエラーメッセージは入力欄のすぐ横です。ちょっと格好悪い……。
改行させたい、ブロック要素として表示させたい場合は以下を追記します。

```javascript
var validation = $('#register').validate({
    rules: {
      name: {
        required: true,
      },
      id: {
        required: true,
      },
    },
    messages: {
      name: {
        required: 'ユーザー名を入力してください',
      },
      id: {
        required: 'idを入力してください',
      },
    },
    // 一行追加
    errorElement: 'div',
    errorPlacement: function (error, element) {
      error.insertAfter(element)
    },
  });

var result = validation.form();
```

これで入力欄のすぐ下に出るようになりました。
あとはcssでerrorクラスの値をよしなにいじってやれば完成。

## 余談
errorElementでdivを指定しないと、デフォルトではlabelになります。

デフォルトのままにしていると、一つの項目でエラーが出たときそれ以外の項目の下（エラーメッセージが出る位置）にもメッセージ分の余白ができてしまうという不具合がありました。

divにするとこちらも解決しました。


メモ代わりに共有します。
Realmを使ったデータ保存をしようとしたらGithubの差分がとんでもない量になってしまった

# はじめに
Realmを使ったデータ保存を実装し、Githubにデータをあげたところ以下のように差分がとんでもない量になってしました。通常は100以下のところ、今回は972,3871でした。
![スクリーンショット 2023-08-12 20.58.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3485517/c19db9fd-6d5e-a6cd-005e-cd8296b13f68.png)

# 原因
Realm関係の差分も一緒にあがってしまったことによるものでした。

# 対策
`git ignore`を使って必要のないファイルやフォルダをGitの差分監視対象から除外しました。

# 準備
1. プロジェクトファイルに`.gitignore`ファイルを作成。ターミナルで
    
    ```swift
    touch .gitignore
    ```
    
2. できても特に反応がないため、できたかどうかを確認するにはターミナルで
    
    ```swift
    ls -a
    ```
    
`.gitignore`があればOK
    
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3485517/67b38134-2db8-b940-c1e8-51d9e3a378ef.png)
    
3.　ファインダーで確認する場合、`.gitignore`ファイルは隠しファイルなので、通常は表示されません
    
![image-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3485517/df9add0a-0124-d421-d541-620aedaf6fcf.png)

    
shift + command + . で見れるようになります（半透明）。
![%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%202023-08-12%2021.19.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3485517/8db621bc-0215-abaf-e169-90da7f563f9c.png)

# 使う
1. ファインダー上の`.gitignore`をクリックして開き、`Pods/`と`.DS_Store`を書き、`Pods/`フォルダ配下の全てと`.DS_Store`をGitの差分監視対象から除外。
    
![image-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3485517/8dda9089-3e89-58f0-95d3-30312469e335.png)

    
2.　これでライブラリ関係は差分に出なくなりました。
![image-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3485517/8388cd15-6bcf-2354-81eb-d5b6c23e8042.png)

これをしないままgithubにあげてしまうと、膨大なライブラリのファイルが入ってしまうので、リポジトリが圧迫されてしまい、パンクしてしまいます。

# .gitignoreに記載しても正常に差分監視対象から除外されないケース
基本的には前述の`.gitignore`ファイルにファイルもしくはフォルダを記載するだけで差分監視対象からは除外されるようなのですが、過去にコミットしたことがあるファイルやフォルダの場合は`.gitignore`ファイルに記載しただけでは正常に除外されないようです。
これはGitの過去の記録の中に当該ファイルやフォルダの情報がキャッシュとして保存されてしまっているためです。
そのため、コレに該当する場合は下記のコマンドを使って対象ファイルやフォルダのキャッシュを削除するようにします。

```swift
$ git rm -r --cached ファイル名
```

上記のように`git rm -r --cached`に続いてファイル名(フォルダ名)を指定することによって、対象ファイル(フォルダ)のキャッシュを削除することができます。
正常にGitの差分監視対象から除外されない場合は、このキャッシュが残っていないか確認することが必要です。