OmniAICreator/Qiita-1.07M huggingface dataset:
Haggingface Spacesを利用してブラウザのみでLangflowを実行する方法（またはローコード開発によるRAGパターンチャットアプリ構築体験）

# 2024年７月12日付の補足

以下の記事は、2024年４月に発表されました。ここでは、「ブラウザのみでLangflowを実行する方法」として、Haggingfaceの環境を利用しています。

現在では、（現時点ではプレビューの扱いですが）**DataStax Langflow**として（**Langflow**はオープンソースのテクノロジー、**DataStax Langflow**は、DataStax社のサービス）、より直接的に利用することが可能です。

https://www.datastax.com/blog/introducing-datastax-langflow-design-test-generative-ai-apps

とはいえ、いずれも操作性については共通しているところが多いと思いますので、適宜参考にしてください。

# 前提

- Astra DBのアカウント
　-　Astra DB上に、Vector Search DBを作成済み
　-　上記のデータベースへの認証・接続のための以下の情報
　 　 -　APIエンドポイントURL
　  　-　トークン
 - OpenAIのアカウント
　-　API Key

# 手順

## Haggingfaceアカウント作成

以下のURLにアクセス
https://huggingface.co/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/11b1326d-6914-19b2-53d0-8ca04fd697d9.png)

画面右上のSign UPをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/e99e73d3-59c7-a7e1-7800-db8e2bf59c42.png)

指示に従って、アカウントを作成

## Langflow

上記で作ったHaggingfaceのアカウントでHaggingfaceのサイトにログインしておく。

同じブラウザで、以下のURLにアクセスする
https://langflow-orcin.vercel.app/getting-started/rag-with-astradb

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/60be3b14-7534-ee37-eccd-ee7d8c54c9df.png)

上記画面の文言「Duplicate our Langflow 1.0 Space」の「Langflow 1.0 Space」をクリック

Hugging Faceにログインしているアカウント名（Owner）で以下のようなダイアログが表示されるので「Duplicate Space」ボタンを押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/b7d6aa04-010d-113d-9a22-f1e10aa30ead.png)

しばらく環境構築で待たされるが下記のような画面が表示される。
（左上やURLに自分のアカウント名が表示されていることに注目）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/85125b3d-9ca6-847a-182b-4f5498650db0.png)

上部右あたりの「＋New Project」ボタンを押下

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/8caffcbb-f6ac-da2c-ec8b-a13d67add929.png)

表示されたダイアログから「Vector Store RAG」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/e78023f2-8a8b-8f90-8471-1e26c812ed54.png)

こんな画面が表示される。

OpenAIのアイコンのボックス（3個）の「OpenAI API Key」の欄に自分のOpenAI API Keyを入力する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/f6f6c521-385c-378b-9d30-abaaefb4b94a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/b62a5db2-a72f-0d8c-6b54-1e8438c63970.png)


Astra DBと記載のあるボックス（2個）に自分のAstra DB環境のTokenとAPI Endpointを入力する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/318eb95d-5850-29c1-e59c-19b1ed8a9ee1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/29cc294a-1e04-b947-ac59-11c73e16a868.png)

最後に、下記のFileボックスに、RAG(検索拡張生成)の検索対象となる、つまりAstra DBに保存したい（自分のローカルの環境にある）ファイルを指定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/f9624b80-d023-d7a9-08fb-bd387fab62b6.png)

画面右下の「Run」を押せば、チャット画面が表示される。
【初心者】TypeScriptの文法を理解していくvol.1

## はじめに
2024年になって、気づいたらTypescritが主流になっていた。

不安になってきたので研修の時間に少しずつ学習を始めていく。

## 変数の宣言と代入

ES2015仕様になっている。`const`や`let`は必須なのかと思ってきた。

```.ts
const message = "Hello World!"

let breakfast = "toast"
```

## プリミティブ型
基本的な型。この3つ存在する。


```.ts
// 文字列
const lastName:string = "Saito";

// 数値
const age: number = 30;

// 真偽値
let bool: boolean = true;
```

### 特殊なプリミティティブ型
nullとany型が意外と特徴的

```.ts
// 存在しないことを表す型
const notExisted = null;

// 何にでもなり得る型
let slive: any;
slive = 1;
slive = "1";
slice = { name: "オブジェクト" };
```

## リテラル型
特定の値だけを代入可能にしてくれる。

```.ts
// Appleだけしか入れられない
let forbiddenFruit: "Apple" = "Apple";

forbiddenFruit = "Orange";
```
## ユニオン型
2つ以上の型をパイプ記号（|）で繋げてかける

```.ts
// 200か201か202か203か204かのいずれか
let successCode: 200 | 201 | 202 | 203 | 204;

// 文字列と数値を代入できる変数
let str_num: string | number;
str_num = 'こんにちは';
console.log(str_num); // こんにちは

str_num = 123;
console.log(str_num); // 123
```

## おわりに
変数を中心にぷりミィティブ型とリテラル型とユニオン型を学びました。
どんどん応用できるようにしていくぞ

## 参考
https://typescriptbook.jp/reference
https://zenn.dev/10000leaves/scraps/1cf028afd2cf71
poetry + pyenv

## 2024/04/11現在のpoetry install

https://python-poetry.org/docs/#installing-with-the-official-installer
```shell
curl -sSL https://install.python-poetry.org | python3 -
```
python じゃなくて python3 なのはもう受け入れる。

パスは自動で設定されなかったみたいなので、.bash_profile に追加
`export PATH="/home/{username}/.local/bin:$PATH"`
```shell
$ which poetry
/home/{username}/.local/bin/poetry
```

## poetry で特定のフォルダは以下に.venvを作って参照したい
```shell
$ poetry config --list
(略)
virtualenvs.in-project = null
(略)
```
こいつをtrueにしてから poetry install するのが良い
```shell
poetry config --local virtualenvs.in-project true
```
全てにおいてカレントに出すなら --local はいらない。それでいい気もする。
PHPで平方数であるかそうでないかを判別する方法

# はじめに
こんにちは! 中学3年生のWardHamamatsu67です! 今回は、PHPで平方数であるかどうかを判別する方法について説明したいと思います。
# 平方数とは?
まず、平方数について、説明したいと思います。平方数というのは、1,4,9,16のような、整数の二乗になる数のことをいいます。例えば、1は1,-1の二乗、4は2,‐2の二乗…となります。
# コード
```php
<?php
$nums = rand(1,90);
$numb = rand(1,8100);
echo($numb);
echo "<br/>";
for($nums=1;$nums<=90;$nums++){
    if  ($numb == $nums ** 2) {
        echo "{$numb}は{$nums}の二乗です。";
        break;
    }else {
        echo "{$numb}は{$nums}の二乗ではありません。<br/>";
    }
}
?>
```
まず、数の範囲を指定します。大きい方の数字は、1から8100まで、小さい方の数字は、1から90(8100の平方根)までに指定します。
次にfor文による繰り返し処理で、小さい方の数字を1から90まで1ずつ増やし、その途中で大きい方の数字の平方根が出てきたら、その大きい方の数字は平方数であるとします。そうでない場合は平方数ではないとします。
そして、大きい方の数字の平方根が出てきたときにfor文の繰り返し処理を終わりにするため、最後にbreakを入れます。
# 実行結果
![スクリーンショット 2024-04-11 171010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749972/ce8b6a2a-05a2-4402-cfaa-3940ce6c63ff.png)
大きい方の数字は484が出ました。484は22,‐22の二乗ですね。そして、その22が出てきたときにきちんと終了されています。
# おわりに
いかがでしたでしょうか。今回は、for文やif文を使わないといけないので少しだけ難しかったと思います。
この記事が良いと思った方はいいねとフォローをしてくれると嬉しいです。
VScodeのk8s拡張機能で、OCI上のk8s(OKE)と接続する

# 結論
kubectlなどはクライアントにインストールしておく。また、OCIコンソールでk8sクラスターへの接続方法が書いてあるので、その手順は実施しておく。
そのうえでsetting.jsonに、
```json
    "vs-kubernetes": {
        "vs-kubernetes.kubeconfig": <.kube/configのパス>
    }
```
を追加する。
Outlookで特定パブリックフォルダーの添付ファイルを全ダウンロードする。

```
Sub DownloadAttachmentsFromSpecificDateRangeWithUniqueName()
    '---------------------------------------------------------------------------
    ' 設定可能な変数
    '---------------------------------------------------------------------------
    Dim publicFolderRootPath As String
    publicFolderRootPath = "パブリック フォルダー - xxxxx"
    
    Dim startDate As Date
    startDate = DateSerial(Year:=2023, Month:=1, Day:=1) ' 開始日
    Dim endDate As Date
    endDate = DateSerial(Year:=2023, Month:=12, Day:=31) ' 終了日
    '---------------------------------------------------------------------------
    'プログラム
    '---------------------------------------------------------------------------
    Dim startTime As Double
    Dim endTime As Double
    ' 実行開始時刻を記録
    startTime = Timer

    Dim subFolderPath As String
    subFolderPath = "すべてのパブリック フォルダー\01 共用メール\xxxx"
    
    ' 以下、メインのスクリプト
    Dim ns As NameSpace
    Set ns = Application.GetNamespace("MAPI")
    
    ' パブリックフォルダーとサブフォルダーへのパスを構築
    Dim currentFolder As Folder
    Set currentFolder = ns.Folders(publicFolderRootPath)
    For Each folderName In Split(subFolderPath, "\")
        Set currentFolder = currentFolder.Folders(folderName)
    Next
    
    ' ダウンロードするファイルの保存先
    Dim desktopPath As String
    desktopPath = CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\MyAttachments\"
    
    ' フォルダが存在しない場合は作成
    If Len(Dir(desktopPath, vbDirectory)) = 0 Then
        MkDir desktopPath
    End If
    
    ' 日付範囲に基づいてアイテムを絞り込む
    Dim filter As String
    filter = "[SentOn] >= '" & Format(startDate, "yyyy/mm/dd") & " 00:00 AM' AND [SentOn] < '" & Format(endDate, "yyyy/mm/dd") & " 00:00 AM'"
    Dim restrictedItems As Items
    Set restrictedItems = currentFolder.Items.Restrict(filter)
    
    Dim item As Object
    Dim att As Attachment
    Dim fileName As String
    Dim saveFileName As String
    Dim counter As Integer
    
    ' 絞り込まれたアイテムをループして添付ファイルを保存
    For Each item In restrictedItems
        If item.Attachments.Count > 0 Then
            For Each att In item.Attachments
                fileName = att.FileName
                saveFileName = desktopPath & fileName
                counter = 1
                ' ファイル名が重複している場合は、別の名前を生成
                Do While Dir(saveFileName) <> ""
                    saveFileName = desktopPath & Left(fileName, InStrRev(fileName, ".") - 1) & "_" & counter & Mid(fileName, InStrRev(fileName, "."))
                    counter = counter + 1
                Loop
                att.SaveAsFile saveFileName
            Next att
        End If
    Next item

    ' 実行終了時刻を記録
    endTime = Timer
    
    ' 実行時間を計算して表示
    Debug.Print "実行時間: "; Format$(endTime - startTime, "0.00") & " 秒"
End Sub
```
JSでAPI作ってみた！

## 初めに
JavaScriptでAPIを作成してみましたので、
備忘録として残しておきます。
(ブログ投稿アプリ作成)

## 概要
ORMとしてprismaを使用。
DBはMySQL。
VScodeを使用して記述。

## 実装
①prismaクライアントを生成して、使用できる状態にする。
```javascript:api.js
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
```

②新規作成用APIを作成
| 変数      | 内容       |
|:--------:|:----------:|
| title    | ブログタイトル |
| content  | ブログ内容   |
| createdAt| 投稿日      |
| user     | 投稿者      |
```javascript:api.js
app.post('/api/posts', async (req, res) => {
  try {
    const { title, content, user } = req.body;

    const newBlog = await prisma.blog.create({
      data: {
        title: title,
        content: content,
        createdAt: new Date(),
        user: user
      }
    });
    res.status(200).json({ message: '成功しました', data: newBlog });
  } catch (error) {
    console.error('保存中にエラーが発生しました', error);
    res.status(500).json({ error: '500エラーが発生しています' });
  }
});
```
・asyncで非同期処理。
・API実行に成功した場合メッセージが出力されるように実装。
・エラー発生時もメッセージが出力される。

![スクリーンショット 2024-04-11 17.12.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744656/e889bd3d-e56d-51f0-aab5-62f563cb639d.png)

Insomniaを使用して、APIが実装出来ているのか確認

###### 　その他API

:star:取得用API
```javascript:api.js
app.get('/api/posts', async (req, res) => {
  try {
    // すべての投稿を取得
    const posts = await prisma.blog.findMany();

    res.status(200).json({ message: '投稿の取得に成功しました', data: posts });
  } catch (error) {
    console.error('投稿の取得中にエラーが発生しました', error);
    res.status(500).json({ error: '500エラーが発生しています' });
  }
});
```
:star:更新用API
```javascript:api.js
app.put('/api/posts/:postId', async (req, res) => {
  const postId = req.params.postId;
  const { title, content, user } = req.body;

  try {
    // 特定の投稿を更新
    const updatedPost = await prisma.blog.update({
      where: { id: parseInt(postId) }, //指定した投稿IDの内容を更新
      data: {
        title: title,
        content: content,
        user: user
      }
    });

    res.status(200).json({ message: '投稿の更新に成功しました', data: updatedPost });
  } catch (error) {
    console.error('投稿の更新中にエラーが発生しました', error);
    res.status(500).json({ error: '500エラーが発生しています' });
  }
});
```
:star:削除用API
```javascript:api.js
app.delete('/api/posts/:postId', async (req, res) => {
  const postId = req.params.postId;

  try {
    // 特定の投稿を削除
    await prisma.blog.delete({
      where: { id: parseInt(postId) }, // 指定した投稿 ID の内容を削除
    });

    res.status(200).json({ message: '投稿の削除に成功しました' });
  } catch (error) {
    console.error('投稿の削除中にエラーが発生しました', error);
    res.status(500).json({ error: '500エラーが発生しています' });
  }
});
```

## やってみて
調べながら作成をしましたが、スムーズに作成する事が出来ました。
どちらかというと、呼び出す側(React)でエラーが起きて時間がかかりました。

prismaを使用することにより、SQL文を記述しなくてもデータの取得や更新をする事が出来るのでとても便利だと感じました。

## 最後に
今回、ブログ投稿アプリを作成しました。
その中でAPIを作成したのですが、よかったら参考になればと思います。
Accessのデザインビューでグリッド線やルーラーを非表示に

# 概要

これ非表示に。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/1423e7fa-8e02-bbee-c0e0-f410174b29bd.png)

# やり方

背景の上で右クリック ⇒ 下記。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/7790b22a-e086-0406-ee7e-7085ab13a55a.png)

この設定はグローバルなものなので、全フォームや別Accessファイルを開いた時にも適用されます。

# 参考サイトさん

https://hamachan.info/win7/access/grid.html

# バージョン

Microsoft Windows [Version 10.0.22631.3447]
Microsoft Access for Microsoft 365 MSO (バージョン 2403 ビルド 16.0.17425.20176) 32 ビット
Table data



SELECT table_name
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'pg_catalog') -- 排除系统模式
AND EXISTS (
    SELECT 1
    FROM pg_stat_user_tables
    WHERE relname = table_name
)
AND EXISTS (
    SELECT 1
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = table_name
    AND COLUMN_NAME = 'your_date_column'
)
AND EXISTS (
    SELECT 1
    FROM (SELECT 1 FROM table_name WHERE your_date_column < NOW() - INTERVAL '3 years' LIMIT 1) AS subquery
);
なんでわざわざ "コード生成AI" なんて仰々しい名前で呼ぶの？

最近生成AIが言うまでもなく話題ですが、**コード生成AI**という言葉ももちらほら聞くようになりました。
どうやらお遊びくらいの感じではなく、普通に企業が案件としてやろうとするくらいには研究が進んでいるようです。
私もコード生成AI関連の案件に携わりそうなので、これから定期的に調査し情報共有していこうとしている次第です。

で、正直、**コード生成AI**という言葉を初めて聞いた時、
**そんな仰々しい名前をわざわざつけなくても、ただの生成AIの出力の一種では？**
と思いました。
せっかく思ったので、周りの生成AIに携わっている方々にちょっと聞いて意見をまとめて記事にしてみました。

私のような新しい技術に好奇心で飛びつきつつ、猜疑心も捨てきれない方にはちょっと面白い感じかもです。

# 一種のプロモーションでは？

特段新しいことでもないのに新しい言葉をつけることで、なんかすごそうなやつに見せるあれですね。出会い系をマッチングアプリって読んだり、借金をキャッシングとかローンって呼んでみたりするやつです。
生成AIは文字列を入力として文字列を出力するだけで、コードも文字列の一種だし、特段新しくないよねっていう立場の意見でした。

# インターフェースが割と違うからでは？

おそらくコード生成AIサービスでもっとも有名なのは[GitHub Copilot](https://github.com/features/copilot)ですが、VSCode等のエディタに導入するタイプのものが多い印象です。
このようにインターフェースがChatGPTのようなチャットUIでなく、コード生成AIはエディタに依存する感じが他と違うから別の名前で呼ぶ価値があるというわけですね。これはたしかにそうかもと思いました。


---

今後も引き続きコード生成AIについて調査して記事を書いたりしていきます。
来週は「[AlphaCodium](https://github.com/Codium-ai/AlphaCodium)使ってみた」的な記事を書こうと思います。
スプレッド構文について学習してみた

## スプレッド構文の基本
```ruby:JavaScript

const obj = {
    id: '0001',
    name: 'Taro',
    age: '25',
    from: 'Japan',
};

const copyObj = { ...obj };

console.log(obj);
console.log(copyObj);

```

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/71ea4b4a-77eb-0d7a-ac30-db55925ad6a8.png)


## コピー元を更新してみる
```ruby:JavaScript

const obj = {
    id: '0001',
    name: 'Taro',
    age: '25',
    from: 'Japan',
};

const copyObj = { ...obj };
obj.id = '0002';

console.log(obj);
console.log(copyObj);
```

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/a1cad5eb-4a0d-7e40-93a2-813eaffcd511.png)
コピー元のみ更新される　※上部


## コピー元を更新してみる(入れ子の場合)
```ruby:JavaScript

const obj = {
    1: {
        id: '0001',
        name: 'Taro',
        age: '25',
        from: 'Japan',
    },
    2: {
        id: '0002',
        name: 'Ayaka',
        age: '23',
        from: 'USA',
    },
    3: {
        id: '0003',
        name: 'Yuki',
        age: '20',
        from: 'Japan',
    },

};

const copyObj = { ...obj };
obj[3].name = 'Risa';

console.log(obj);
console.log(copyObj);

```

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/3d58e9dc-6d1f-f78f-e594-ef061f19a109.png)

入れ子の場合は、子供のオブジェクトのは一緒に変更されてしまう、、、
上記を避けたいとき



```ruby:JavaScript

const obj = {
    1: {
        id: '0001',
        name: 'Taro',
        age: '25',
        from: 'Japan',
    },
    2: {
        id: '0002',
        name: 'Ayaka',
        age: '23',
        from: 'USA',
    },
    3: {
        id: '0003',
        name: 'Yuki',
        age: '20',
        from: 'Japan',
    },

};

const copyObj = JSON.parse(JSON.stringify(obj));
obj[3].name = 'Risa';

console.log(obj);
console.log(copyObj);


```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/0a8a0fa1-e949-1a53-0b56-23833e5706bb.png)

JSON.stringify() でオブジェクトを文字列に変換し、 JSON.parse() で文字列をオブジェクトに変換することでcopyObj は obj とは別のオブジェクトを参照しているのでobj の変更がcopyObj には反映されない。
TeraTerm ver.5でファイル送信がうまくできない対処(CK-RX65N)

# はじめに

業務にて __Renesas社の[IoT Edge開発キットのCK-RX65N](https://www.renesas.com/jp/ja/products/microcontrollers-microprocessors/rx-32-bit-performance-efficiency-mcus/ck-rx65n-cloud-kit-based-rx65n-mcu-group)というキット__ を入手した。

本キットはRenesas RXファミリ用 FreeRTOS-LTSサンプルプログラム ([iot-reference-rx](https://github.com/renesas/iot-reference-rx))を使用することでAWS IoT Coreに接続できる。

サンプルコードはGitHub上に公開されておりWi-Fi,Cellular、EthernetにてAWS IoT CoreにMQTTメッセージを送ることができる。

今回Teraterm v5を使用した際、”解決した課題”に記載した問題があったので解決方法を記載する。

# 解決した課題

上記サンプルコードではCLI(コマンドライン)でクレデンシャル情報をデバイスに書き込む。

このとき、__最近リリースされたTeraterm ver5を使うとガイド通りの手順でうまくCLIが動作しない__。

具体的にはTeraTermにてCA証明書や秘密鍵ファイルをドラッグ＆ドロップするとファイルの中身が1行ずつに分かれて送信されてしまう問題が起こる。改行により別データのInputとなるため正しいクレデンシャル情報をInputできない。
(補足：TeraTerm v4ではこの手順で問題が無かった)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233064/ce32e074-8455-c3b8-d555-fcda688648bb.png)
---
# 解決方法

__ファイルのドラッグ＆ドロップ時にポップアップウインドに表示される`バイナリ`にチェックをつけることで回避できることが分かった__

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233064/09eccd17-e141-7716-4440-7645307d1f80.png)

以下のように改行が入らない状態でファイル(ファイルの中身)をCLIで入力することができた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233064/f762bc67-9234-55b2-ca98-04b886e2d9d9.png)


# 参考URL

https://qiita.com/nizuki926/items/e9fddef08852494fca87

https://www.renesas.com/jp/ja/products/microcontrollers-microprocessors/rx-32-bit-performance-efficiency-mcus/ck-rx65n-cloud-kit-based-rx65n-mcu-group

https://github.com/renesas/iot-reference-rx
Cursor(VsCode)のフォント「こいつ」の色を変更する。

こいつの色を変えたいという時のやり方。例えばクラス、変数・・・

ctrl + shift + P
Developer: Inspect TM Scopesで検索

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/de5f7d4e-0579-d357-f421-e7b2bc7b4b71.png)

変えたいものをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/fe8751fd-805b-9fb6-424f-68cccc3b96d8.png)

scopesを覚えておく

Settings.json
```
    "editor.semanticHighlighting.enabled": false,
```
他のテーマで上書きされないように設定
スコープと色を設定。

```
    "editor.tokenColorCustomizations": {
        "textMateRules": [
            {
                "scope": [
                    "entity.name.type.cs", // C# のクラス名に使用されるスコープ
                    "source.cs",
                ],
                "settings": {
                    "foreground": "#0de2a2" // GameObjectで使われている色
                }
            },
        ]
    },
```

色の変更完了。やったね。

追記、私の設定を貼り付ける

```
    "editor.semanticHighlighting.enabled": false,

    "editor.tokenColorCustomizations": {
        "textMateRules": [
            {
                "scope": [
                    "entity.name.type.cs", // C# のクラス宣言
                ],
                "settings": {
                    "foreground": "#0de2a2" 
                }
            },
            {
                "scope": [
                    "entity.name.type.class.cs", // C# のクラス名に使用されるスコープ
                ],
                "settings": {
                    "foreground": "#1bfbf3" 
                }
            },
            {
                "scope": [
                    "variable.other.object.property.cs", // 変数
                    "entity.name.variable.local.cs", //ローカル変数
                    "punctuation.squarebracket.open.cs",
                    "variable.other.readwrite.cs", //メンバ　使用箇所
                    "variable.other.object.cs", //メンバ　引数
                    "entity.name.variable.parameter.cs",//関数引数
                ],
                "settings": {
                    "foreground": "#d4d4d4" 
                }
            },
            {
                "scope": [
                    "keyword.operator.logical.cs", // &&
                    "keyword.operator.arithmetic.cs", // + -
                    "keyword.operator.relational.cs",// <>
                    "keyword.operator.assignment.cs", //=
                    "keyword.operator.comparison.cs",// ==
                    "keyword.operator.increment.cs",// ++
                    "keyword.operator.conditional.question-mark.cs",// ?
                    "keyword.operator.conditional.colon.cs",// :
                ],
                "settings": {
                    "foreground": "#c694ff"
                }
            },
        ]
    },
```
Table

DO $$
DECLARE
    table_name TEXT;
    query_text TEXT;
    has_old_data BOOLEAN;
BEGIN
    FOR table_name IN
        SELECT table_name
        FROM information_schema.tables
        WHERE table_schema NOT IN ('information_schema', 'pg_catalog') -- 排除系统模式
    LOOP
        query_text := format('
            SELECT EXISTS (
                SELECT 1
                FROM %I
                WHERE your_date_column < NOW() - INTERVAL ''3 years''
            )', table_name);

        EXECUTE query_text INTO has_old_data;

        IF has_old_data THEN
            RAISE NOTICE 'Table % has data older than three years.', table_name;
        END IF;
    END LOOP;
END $$;
Git Clone時にすべてのブランチを同期して表示するスクリプト


```powershell
$repoUrl = "リポジトリのURL" # ここにはクローンしたいリポジトリのURLを指定します

# リポジトリをクローンします
git clone $repoUrl

# リポジトリ名を取得します
$repoName = $repoUrl.Split("/")[-1].Replace(".git", "")

# クローンしたディレクトリに移動します
cd $repoName

# リモートリポジトリの全てのブランチを取得します
git fetch --all

# リモートブランチのリストを取得します
$remoteBranches = git branch -r | foreach { $_.trim() -replace "origin/", "" }

# 各リモートブランチに対してローカルブランチを作成します
foreach ($branch in $remoteBranches) {
    git checkout -b $branch origin/$branch
}

# ブランチと最新更新時間を表形式で表示します
$branchInfo = @()
foreach ($branch in $remoteBranches) {
    git checkout $branch
    $lastCommitTime = git log -1 --pretty=format:"%cd" --date=iso
    $branchInfo += New-Object PSObject -Property @{
        Branch = $branch
        LastCommitTime = $lastCommitTime
    }
}
$branchInfo | Format-Table -AutoSize
```

## Gitのブランチ履歴を表形式で表示する
```
    # リモートブランチのリストを取得します
    $remoteBranches = git branch -r | foreach { $_.trim() -replace "origin/", "" }

    # ブランチと最新更新時間を表形式で表示します
    $branchInfo = @()
    foreach ($branch in $remoteBranches) {
        $lastCommitTime = git show -s --format=%ci origin/$branch
        $branchInfo += New-Object PSObject -Property @{
            Branch = $branch
            LastCommitTime = $lastCommitTime
        }
    }
    $branchInfo | Sort-Object LastCommitTime -Descending | Format-Table -AutoSize
```
Command R+ で elixir を学ぶ (その2）ピタゴラス数

ピタゴラス数を計算する Python のプログラムを変換してみます。

## Python のプログラム

```py:pythagoras.py
#! /usr/bin/python
#
#	pythagoras.py
#
#					Apr/11/2024
#
# ------------------------------------------------------------------
import	sys
import	math
# ------------------------------------------------------------------
def add_proc(it,jt,zz,aax,ratios):
	vv = [it,jt,zz]
	ratio = float(it) / float(jt)
	if len(aax) == 0:
		aax.append(vv)
		ratios.append(ratio)
	elif (not ratio in ratios):
		aax.append(vv)
		ratios.append(ratio)
#
# ------------------------------------------------------------------
def calc_proc(nn_max):
	aax = []
	ratios = []
	xx_min = 1
	for it in range (xx_min,nn_max):
		xx2 = it * it
		for jt in range(it+1,nn_max):
			yy2 = jt * jt
			xxyy2 = xx2 + yy2
			dz = math.sqrt(xxyy2)
			zz = int(dz)
			zz2 = zz * zz
			if (xxyy2 == zz2):
				add_proc (it,jt,zz,aax,ratios)
	return aax
# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
#
nn_max = 50
results = calc_proc (nn_max)

count = len(results)
print("count = %d" % count)

for it in range(count):
	print("%d\t%d\t%d" % (results[it][0],results[it][1],results[it][2]))

sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```

実行結果

```text
$ ./pythagoras.py 
*** 開始 ***
count = 8
3	4	5
5	12	13
7	24	25
8	15	17
9	40	41
12	35	37
20	21	29
28	45	53
*** 終了 ***
```

## Command R+ で変換した結果

```elixir:pythagoras01.exs
#! /usr/bin/elixir
#
#       pythagoras.ex
#
#                                       Apr/11/2024
#
# ------------------------------------------------------------------
IO.puts "*** 開始 ***"

defmodule Pythagoras do
  def add_proc(it, jt, zz, aax, ratios) do
    vv = [it, jt, zz]
    ratio = it / jt

    if Enum.empty?(aax) do
      aax ++ [vv]
      ratios ++ [ratio]
    else
      if not Enum.member?(ratios, ratio) do
        aax ++ [vv]
        ratios ++ [ratio]
      end
    end
  end

  def calc_proc(nn_max) do
    aax = []
    ratios = []
    xx_min = 1

    for it <- xx_min..nn_max do
      xx2 = it * it

      for jt <- it + 1..nn_max do
        yy2 = jt * jt
        xxyy2 = xx2 + yy2
        dz = :math.sqrt(xxyy2)
        zz = round(dz)
        zz2 = zz * zz

        if xxyy2 == zz2 do
          add_proc(it, jt, zz, aax, ratios)
        end
      end
    end

    aax
  end
end

# ------------------------------------------------------------------
nn_max = 50
results = Pythagoras.calc_proc(nn_max)

count = Enum.count(results)
IO.puts("count = #{count}")

for i <- 0..count-1 do
  IO.inspect(Enum.at(results, i))
end

IO.puts "*** 終了 ***"
```

実行結果

```text
$ ./pythagoras01.exs 
*** 開始 ***
warning: the result of evaluating operator '++'/2 is ignored (suppress the warning by assigning the expression to the _ variable)
  pythagoras01.exs:16

warning: the result of evaluating operator '++'/2 is ignored (suppress the warning by assigning the expression to the _ variable)
  pythagoras01.exs:20

count = 0
nil
nil
*** 終了 ***
```
TypeScriptで、オブジェクトに対して動的にキーアクセスしたい

## はじめに

JavaScript→TypeScriptへ移行する際に、オブジェクトに対するアクセスで型チェックエラーが出て困っていました。
```ts
const obj = {
    key1: "hoge",
    key2: "fuga",
    key3 : ""
}
// →
// const obj: {
//     key1: string;
//     key2: string;
//     key3: string;
// }
// が型推論される

const objArray: string[] = [];

// 型チェックエラーが発生する
for (let i = 1; i <= 3; i++) {
    if (obj[`key${i}`]) {
        objArray.push(obj[`key${i}`]);
    }
}
console.log(objArray);
```

objにはkey1, key2, key3のキーしか存在しないため、``obj[`key${i}`]``という形でアクセスしようとすると、コンパイルエラーになります。

:::note alert
error TS7053: Element implicitly has an 'any' type because expression of type '`key${number}`' can't be used to index type '{ key1: string; key2: string; key3: string; }'.
:::

上記の場合では　for文中でiは1, 2, 3のいずれかに限られますが、TypeScriptではそこまで反映しての型チェックはできないです。
今回に限らず、TypeScriptの型チェックは必ずしも完璧ではないことに留意しましょう。
今回も、存在しないプロパティにアクセスする可能性があるためにエラーが発生しています。


## 対策1
```ts
type Obj = {
    [key: `key${number}`]: string;
}
const obj: Obj = {
    key1: "hoge",
    key2: "fuga",
    key3 : ""
}

const objArray: string[] = [];
for (let i = 0; i <= 3; i++) {
    if (obj[`key${i}`]) {
        objArray.push(obj[`key${i}`]);
    }
}
console.log(objArray);
```

``[key: `key${number}`]: string;``といった[インデックス型](https://typescriptbook.jp/reference/values-types-variables/object/index-signature)を用いて、型定義してあげればいいのではないかと思い、上記コードを書きました。

型チェックは問題なく突破できるものの、
- 型定義をしなければいけないのでコード量が増えてしまう
- 実際には存在しないキー(key4など)へのアクセスも型定義上できてしまう
```ts
// TypeScriptでの型チェックは通るがランタイムエラーが発生する
console.log(obj.key4);
```
といったデメリットがあり、ベストな回答とは言えない気がします。


## 対策2
悩んだ結果、下記コードに辿り着きました。
Object.keys()やObject.values()を用いることで、オブジェクトに対する安全な動的アクセスが可能です。
型チェックに引っ掛かることも、型安全性が破壊されランタイムエラーが発生することもないです。
```ts
const obj = {
    key1: "hoge",
    key2: "fuga",
    key3 : ""
}

const objArray = Object.values(obj).filter(value => value);
console.log(objArray);
```


## 参考文献

https://typescriptbook.jp/reference/values-types-variables/object/index-signature

 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/values
maven-compiler-plugin を 3.13.0 にバージョン上げるとJitPackにおこられる

## これまでのあらすじ
gitHubもmavenもよく理解してないよわよわだったので、いろいろいじってたらなんかJitPackでビルド失敗した。つらい。

## わかったこと
maven-compiler-plugin3.13.0 は Marven3.6.3 が必須になってるのだけれど、JitPack内部で動いてるmavenのversionでは対応してないみたい。

## けつろん
dependabot さんがプルリクエスト送ってくるけど maven-compiler-plugin は3.12.1までにしておこう。
「print_r」、「 var_dump」、「 echo」の違いを復習してみた

ようやく今月でエンジニア歴1年になりました。
1年目は簡単な個人開発ばかりやって基礎固めをさぼってしまい、最近の業務で色々躓くことが多くなってきたので今年は基礎固め、応用全部頑張りたいと思います。

## print_r、var_dump、echoの違い
それぞれ出力したい値によって使い分ける。
それは分かってるんだけどもどうやって分けるんだ…と言う感じだったので後で見返せるように自分用に、それぞれの特徴と用途をまとめてみました。

## print_r()
- 配列やオブジェクトの内容を出力する
- デバッグ時に変数の内容を確認したいに使う
- 型情報は提供されないので、bool値やnullのような型は出力されない場合がある
- 配列やオブジェクトの構造を確認したいときに使うと良い

```
$num = [10,20,30,40,50];
$print_r($num);
```
print_r()はvar_dump()が使えなかったデバッグ環境で重宝していた気がします。
個人的推し。:crab:

実際に書いてたコード↓
```
$serializedData = serialize($param);
file_put_contents("./debug.log", $serializedData);
```

## var_dump()
- 変数の情報を詳細に出力する
- 配列やオブジェクトのネストも出力できる
- デバッグや複雑なデータ構造を表示したいときに使う

```
$num = [10,20,30,40,50];
$var_dump($num);
```
デバッグと言えばvar_dump()を使う方が大半なのではないでしょうか？
様々な値を細部まで出力できるので大変便利です。

## echo
- .を使い、文字を連結できる
- 文字列など単純な値を出力するために使う
```
$name = "marin";
echo "私の名前は, ", $name, "です。";
```
チュートリアルでたくさん見てきたecho。(笑)
何かとお世話になった気がします。:eye:

## まとめ
ざっくりまとめてみましたが、こんなに違いがあると思っていませんでした。
こういった基礎的なことが自分はどうしてもアウトプットが抜けがちなので、こういったアウトプットも今後は増やしていきたいです。
2次元区間和

https://paiza.jp/works/mondai/query_primer/query_primer__two_dimensions_interval_sum


常識的に考えたらこんな感じではいかないなと思うのだけど一応

```py
H, W, N = map(int, input().split())
A = [[int(x) for x in input().split()] for _ in range(H)]
#W*Hの配列に0を入れたものを作る（0の分だけ＋１する）
ans = [[0] * (W + 1) for _ in range(H + 1)]

for i in range(1, H + 1):
    ans[i] = [0] + A[i - 1][:]
    #計算して入れていく（もともとある数字に累積和を入れていくので＋＝になる）
    for j in range(1, W + 1):
        ans[i][j] += ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1]

print(ans)

#指定のものを出力する
for _ in range(N):
    a, b, c, d = map(int, input().split())
    print(ans[c][d] - ans[a-1][b-1])

```

まあ、ケース１の1番目のように1,1と3,3と、左端から右端なら全部なのでうまくいくけど、
そうでもないところからだとうまくいかない。

とりあえず累積和を出力しておくと

```
[
[0, 0, 0, 0],
[0, 1, 3, 6],
[0, 5, 12, 21],
[0, 12, 27, 45]
]
```
なので、
ans(1,1) ans(3,3)の区間だと、図形でいうと全部なので
ans(3,3)＝45になってしまう。
しかし、
ans(1,2)＝３ ans(2,3)＝21だと、２と６の間、つまり２＋３＋５＋６＝16が答えになるのだが
さてどうやって足すか。
。。。と図形を見ながらにらめっこしたが、うまくロジックが取り出せる
図形の引き算ができず、時間がきてギブ。
結論からすると
S({a,b},{c,d}) = S(c,d) - S(a-1,d) - S(c,b-1) + S(a-1,b-1)という関係になるらしい。
実際にやってみると
S(1,1),(3,3) = S(3,3) - S(0,3) - S(3,0) + S(0,0) = 45 - 0 - 0 = 0
S(1,2),(2,3) = S(2,3) - S(0,2) - S(2,1) + S(0,1) = 21 - 5 - 0 = 16
2番目の計算は不思議だけど、
1＋2＋3＋4＋5＋6 - (1 + 2) - (1 + 4) ＋ 1 = 2＋3＋5＋6＝16となるので
不思議ではない。１は−1になるが、結局あとで＋１となり相殺され、1が消える。

```py
H, W, N = map(int, input().split())
A = [[int(x) for x in input().split()] for _ in range(H)]
#W*Hの配列に0を入れたものを作る（0の分だけ＋１する）
ans = [[0] * (W + 1) for _ in range(H + 1)]

for i in range(1, H + 1):
    ans[i] = [0] + A[i - 1][:]
    #計算して入れていく（もともとある数字に累積和を入れていくので＋＝になる）
    for j in range(1, W + 1):
        ans[i][j] += ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1]
    
for _ in range(N):
    a, b, c, d = map(int, input().split())

    val = ans[c][d]
    if 0 < a and 0 < b:
        val += ans[a - 1][b - 1]
    if 0 < a:
        val -= ans[a - 1][d]
    if 0 < b:
        val -= ans[c][b - 1]

    print(val)    

```
非SOLID特性

# はじめに

SOLIDの逆をChatGPTに考えてもらった

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


# 単一責任の原則 (Single Responsibility Principle) の逆

あるクラスやモジュールが複数の責任を持ち、複数の異なる目的や機能を担当するような設計になっている場合、単一責任の原則に反しています。
# オープン/クローズドの原則 (Open/Closed Principle) の逆

システムの変更や拡張に対して閉じておらず、変更が必要な場合に既存のコードを変更する必要がある設計になっている場合、オープン/クローズドの原則に反しています。
# リスコフの置換原則 (Liskov Substitution Principle) の逆

サブクラスが親クラスの代わりに正しく動作しない、あるいはサブクラスで追加された振る舞いが親クラスの予想外の動作を引き起こす場合、リスコフの置換原則に反しています。
# インターフェース分離の原則 (Interface Segregation Principle) の逆

インターフェースが大きくて太い、あるいはクライアントが不必要なメソッドやプロパティに依存している場合、インターフェース分離の原則に反しています。
# 依存性逆転の原則 (Dependency Inversion Principle) の逆

高レベルのモジュールが低レベルのモジュールに直接依存し、具象クラスに依存している場合、依存性逆転の原則に反しています。


# 感想
まとめると、機能と責任があらゆるところに散らばっていて、拡張や変更や分離が難しく、コードからは予想外のふるまいをして、無駄が多くて中止するべき箇所が不明で、些細な変更でも影響範囲が不明なためすべてを再ビルドと再テストを行う必要がある。
頭の中がごちゃごちゃするね。くそコードとはこういうことさ。

筆者はリスコフの置換原則の逆はあんまり実感わかない。そもそもサブクラスをあまり使わない方針にしているから。
非ACID特性

# はじめに

ACIDがなぜ大事なのかを整理するために、ChatGPTに逆の状態を考えてもらった。

ACID (コンピュータ科学)
https://ja.wikipedia.org/wiki/ACID_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E7%A7%91%E5%AD%A6)

# 非原子性 (Non-Atomicity)

トランザクションの操作が部分的にしか適用されない状態を指します。つまり、トランザクションの一部が実行された後にエラーが発生し、その結果、一部の操作はロールバックされないまま残される可能性があります。
# 非一貫性 (Inconsistency)

トランザクションが完了した後、データベースが一貫性を保持しない状態を指します。つまり、トランザクションの実行中にデータの整合性が失われ、異なるデータソース間で矛盾が生じる可能性があります。
# 非独立性 (Non-Isolation)

複数のトランザクションが同時に実行される場合に、トランザクション間の干渉が発生し、データの整合性が損なわれる状態を指します。つまり、トランザクションが互いに影響を与え、互いの操作を邪魔し合う可能性があります。
# 非永続性 (Non-Durability)

データベースシステムが正常にシャットダウンされた場合でも、トランザクションの変更が失われる可能性がある状態を指します。つまり、データの永続性が保証されず、システムの再起動や障害発生時にデータが失われる可能性があります。

# 感想
非ACIDとは、トランザクションが中途半端に反映されて、データが矛盾して、整合性を信用できなくて、データが気まぐれにロストする。
ちゃんと使えばちゃんとやってくれるRDBはありがたいですね。
AWS-SAA 認定試験における SSE-KMS、SSE-S3、SSE-C、CloudHSM の比較

### なぜこの記事を書いたのか
AWS の暗号化に使われるサービスをはっきりと選択できませんでした。SSE-KMS 、SSE-S3 やSSE-C 、CloudHSM の違いをはっきりさせました。

#### それぞれの名前
- SSE-KMS ：AWS KMS キー によるサーバー側の暗号
- SSE-S3 ：Amazon S3 マネージド キーによるサーバー側の暗号化
- SSE-C ：顧客提供のキーによるサーバー側の暗号化
- CloudHSM ：法令遵守のためのハードウェアベースキーストレージ

#### AWS-SAA 認定試験における SSE-KMS、SSE-S3、SSE-C、CloudHSM の比較
|項目|SSE-KMS|SSE-S3|SSE-C|CloudHSM|
|:-:|:-:|:-:|:-:|:-:|
|暗号化キーの管理|ユーザー|AWS|ユーザー|ユーザー|
|暗号化アルゴリズム|AES-256 (デフォルト)|AES-256|AES-256 (推奨)|RSA 2048 (デフォルト)|
|データの保存場所|ユーザーが選択した KMS キーの場所|S3 リージョン|ユーザーが選択した場所|HSM クラスタ|
|費用|KMS の使用量に基づいて課金|無料|無料|HSM クラスタの使用量に基づいて課金|
|監査|ユーザー|AWS|ユーザー|ユーザー|
|コンプライアンス|ユーザーが KMS キーのコンプライアンス証明書を管理|AWS が提供するコンプライアンス証明書|ユーザー|ユーザー|
|ユースケース|より高度な制御が必要な場合|S3 オブジェクトの暗号化に適している|コスト重視の場合|機密性の高いデータの暗号化に適している|

#### 問題文中の取捨選択
- SSE-KMS は、要件に対して2択に絞られる確率が高いです。キーローテーションを手動/自動の設定可能で、キーの管理とローテーションの作業を削減したい企業に大人気です
- SSE-S3 はキー管理をAWS に任せて無料で利用できる暗号化サービスですが、SSE-KMS に比べると機能が劣ります。そのため、コスト重視であったり、機密性の低いデータの保護に用いられることがあります。
    - また、S3 バケットを複数のリージョンに複製するクロスリージョンレプリケーション(CRR)を使い、双方のS3 で同じKMS キーを使う「マルチリージョンキー」の要件がない限り、SSE-S3 のほうが運用上のオーバーヘッドが最小限になります
- SSE-C はSSE-KMS と同じユーザー管理のサーバー側暗号化ですが、機能も少なく、コストを重視するとき以外は選択肢に入りません
- CloudHSM はKMS より高価で、機密性の高いデータの暗号化に用いられることが多いので、あまり正解になりません。ただし、ユーザー側からキーマテリアルを即時に削除したり、AWS CloudTrail とは関係のない独自の監査ログを提供できることから、要件に合致することがあります。


#### 閑話休題、CloudHSM のディザスタリカバリー(DR)
CloudHSM がハードウェアなら、DR 戦略が必要で、バックアップ計画も立てられるのでしょうか？

Amazon 公式の説明では、できると書かれています。HSM バックアップでは、HSM は暗号化されてS3 に保存されます。S3 に保存されるHSM バックアップデータは、AWS-KMS によって暗号化されます。復元は、同じ製造元の AWS HSM にのみ可能です。とはいえ、CloudHSM 自体が個人で使うには高額なので、DR テストは企業や団体のプロジェクトに組み込んだとき1度試しておきたいです。

Security of cluster backups
https://docs.aws.amazon.com/cloudhsm/latest/userguide/data-protection-backup-security.html

>	AWS CloudHSM が HSM からバックアップを作成する際、HSM はすべてのデータを暗号化してから AWS CloudHSM に送信します。データは平文形式で HSM を出ることがありません。さらに、AWS はバックアップを復号化できません。なぜなら、AWS はバックアップの復号化に使用されるキーにアクセスできないからです。
>
>	HSM は、データを暗号化するために、一時的で固有の暗号化キーである「Ephemeral Backup Key (EBK)」を使用します。EBK は、AWS CloudHSM がバックアップを作成する際に HSM 内で生成される AES 256 ビットの暗号化キーです。HSM は EBK を生成してから、FIPS 承認済み AES キーラップ メソッド (NIST 特殊出版物 800-38F 準拠) を使用して HSM のデータを暗号化します。その後、HSM は暗号化されたデータを AWS CloudHSM に渡します。暗号化されたデータには、暗号化された EBK のコピーも含まれます。
>
>	EBK を暗号化するために、HSM は別の暗号化キーである「Persistent Backup Key (PBK)」を使用します。PBK も AES 256 ビットの暗号化キーです。HSM は、PBK を生成するために、FIPS 承認済みキー導出関数 (KDF) をカウンターモードで使用します (NIST 特殊出版物 800-108 準拠)。この KDF の入力には以下が含まれます。
>
>	ハードウェア製造元によって HSM ハードウェアに永続的に組み込まれている「Manufacturer Key Backup Key (MKBK)」
>
>	最初に AWS CloudHSM によって設定されたときに HSM に安全にインストールされる「AWS Key Backup Key (AKBK)」
>
>	暗号化処理は、以下の図にまとめています。この図では、バックアップ暗号化キーは、PBK (Persistent Backup Key) と EBK (Ephemeral Backup Key) を表しています。
>
>	AWS CloudHSM のバックアップ復元と暗号化
>	AWS CloudHSM は、同じ製造元が作成した AWS 所有の HSM にのみバックアップを復元できます。すべてのバックアップには、すべてのユーザー、キー、およびオリジナルの HSM からの構成が含まれているため、復元された HSM はオリジナルと同じ保護とアクセス制御を含みます。復元されたデータは、復元前に HSM にあった可能性がある他のデータをすべて上書きします。
>
>	バックアップは暗号化されたデータのみで構成されます。サービスはバックアップを Amazon S3 に保存する前に、AWS Key Management Service (AWS KMS) を使用してバックアップを再度暗号化します。
>
>	ポイントまとめ:
>	復元は、同じ製造元の AWS HSM にのみ可能
>	バックアップには、オリジナル HSM の全情報が含まれる
>	復元は、既存のデータを上書きする
>	バックアップ自体も、Amazon S3 に保存前に AWS KMS で暗号化される
Laravel9でTailwind CSSを利用するまでの手順

## はじめに
Laravel9でTailwind CSSを利用するまでの手順をまとめます。
実行環境はmacOS Monterey（12.1）です。

## 手順
まずはターミナルで作業します。

`composer create-project laravel/laravel [プロジェクト名]`で作ったLaravelのプロジェクト配下に移動します。

そして以下のコマンドを実行します。

```
> npm install -D tailwindcss postcss autoprefixer
> npx tailwindcss init -p
```

すると`tailwind.config.js`と`postcss.config.js`がプロジェクト配下に作られます。

次に`tailwind.config.js`を以下のように編集します。

```diff_javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
+    './resources/**/*.blade.php',
+    './resources/**/*.js',
+    './resources/**/*.vue',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```

ちなみにTailwindと互換性のあるペジネーションを実装する場合は、contentキーにさらに`'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',`を追記します。

次に`/resources/css/app.css`を以下のように編集します。

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

そしてターミナルに戻り以下のコマンドを実行します。

```
> npm run dev
```

最後に`/resources/views/layouts/app.blade.php`の`<head></head>`内に以下を追記します。

```html
<head>
・・・
    @vite([・・・, 'resources/css/app.css'])
・・・
</head>
```

以上でTailwind CSSを利用するまでの準備は完了です。
最後まで読んでいただきありがとうございました。

## 参考
https://tailwindcss.com/docs/guides/laravel#vite

https://readouble.com/laravel/9.x/ja/pagination.html#tailwind-jit
ITパスポート リスクマネジメント

・リスクマネジメント
想定されるリスクを組織的に管理しながら、その損失を最小限に抑えるための経営管理手法

・リスクアセスメント
リスクを分析、評価して、あらかじめ設定しておいたリスク受容基準に照らして対応が必要かどうかを判断していくこと
リスク特定、リスク分析、リスク評価

・リスク対応
リスク共有、リスク回避、リスク保有、リスク低減
Next.jsにおけるフォントの使い方

Next.js App RouterでWebフォント（Google Fonts）を設定する方法をざっくりご紹介します。さらに詳しく知りたい方はドキュメントをご覧ください。

https://nextjs.org/docs/app/building-your-application/optimizing/fonts

### ディレクトリ構成
```
myApp/
├── src/
│   └── app/
│       ├── layout.tsx
│       └── page.tsx
└── utils/
    └── fonts.ts
```
※必要な箇所のみ表示しています。

<br>

まずは使いたいフォントを定義しましょう。今回はNext.jsでデフォルトになっているInterを使います。どのようなスタイルでフォントを使いたいのかを指定します。

```typescript:fonts.ts
import { Inter } from "next/font/google";

export const inter = Inter({
  // フォントスタイルを指定するためのオブジェクトを渡す
  subsets: ["latin"],
  display: "swap",
});
```

ちなみにフォントごとに指定できるスタイルを知りたい方は`node_modules/next/dist/compiled/@next/font/dist/google/index.d.ts`を見てみてください。現在Next.jsで使用できるフォントが書いてあります。

<br>

次にフォントを適用させたい要素の `className` に先ほど定義したフォントを指定します。実は暗黙的に`className`というプロパティが作られているんですね。興味がある方は`inter`の中身を覗いてみてください。
```tsx:layout.tsx
import { inter } from "@/utils/fonts";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="ja" className={`${inter.className}`}>
      <body>
        {children}
      </body>
    </html>
  );
}
```
フォントは、適用した要素の全ての子要素に継承されます。アプリケーション全体に適用したければ、`<html>`もしくは`<body>`に付与すればokです。

<br>

以下のようにすれば全体は`inter`、`h1`だけ別のフォントにできます。
```tsx:layout.tsx
import { inter, otherFont } from "@/app/fonts";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="ja" className={`${inter.className}`}>
      <body>
        <h1 className={`${otherFont.className}`}>MyApp</h1>
        {children}
      </body>
    </html>
  );
}
```

<br>

以上、Webフォントの設定方法でした。

もし好みのフォントがない場合、使いたいフォントデータをダウンロードしてきてプロジェクト内に配置すればlocalフォントとして使う事もできます。また、データ最適化などについても書かれていますので是非公式ドキュメントをご覧ください。

https://nextjs.org/docs/app/building-your-application/optimizing/fonts

<br>

最後までお読みいただき、ありがとうございました!
Lakeviewでクイックにダッシュボードを作成

Databricksのカタログエクスプローラでテーブルを表示します。右上の**作成**ボタンをクリックし、**Lakeviewダッシュボード**をクリックします。

![Screenshot 2024-04-11 at 14.59.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/ef74fa3a-d144-708d-9ff6-00ab77103da5.png)

説明文とテーブルの中身が表示され、右上に未作成のウィジェットが表示された状態でLakeviewが開きます。
![Screenshot 2024-04-11 at 15.00.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e402eea8-5687-9062-5eda-caf53b2d1957.png)

プロンプトボックスの下にいくつかのボタンが並んでいます。テーブルの情報から自動でプロンプトが生成されています。ここでは`Show Cases by Area`(地方別の感染者数を見せて)をクリックします。

地方ごとの感染者数の棒グラフが作成されます。必要に応じて、ウィジェットの位置やサイズを変更します。さらにウィジェットを追加するには画面下のメニューのグラフボタンをクリックします。
![Screenshot 2024-04-11 at 15.05.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/3609d19e-260d-0e4a-5943-77ef5943f4fb.png)

次にプロンプトボックスで`What is the trend of Cases over date_timestamp?`(date_timestampにおけるCasesのトレンドは何？)をクリックします。可視化を確定するには**Accept**をクリックします。
![Screenshot 2024-04-11 at 15.07.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/881d05e9-4bdc-d7bc-bec9-a2b724d2524b.png)

一度もキーボードを触らずにここまで作成できました！是非ご活用ください！

### はじめてのDatabricks

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

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
Windowsのタスクバーを完全非表示

Windowsで業務用アプリを全画面で表示しているが、マウスが最下部にあるとタスクバーが表示されてしまうのが問題である場合などで使用。（**タスクバーを自動的に隠す**の設定だけではダメな場合）

:::note warn
ここ（[Windows のタスクバーを完全に消す](https://edvakf.hatenadiary.org/entry/20110310/1299742842 "C#版")）を参考に、exeを作成したがSymantecに消されてしまうのでPowerShell版を作成
:::

# 手順
## スクリプト保存

以下のコードをテキストエディターで任意の場所に保存

```PowerShell:TaskBarHandler.ps1
Add-Type @"
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;

    public class TaskBarHandler
    {
        [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
        [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow); 
    
        public static bool restore(string className, string windowName)
        {
            IntPtr hwnd = FindWindow(className, windowName);
            return ShowWindow(hwnd, 9);
        }

        public static bool hide(string className, string windowName)
        {
            IntPtr hwnd = FindWindow(className, windowName);
            return ShowWindow(hwnd, 0);
        }
    }
"@
$task_bar_status = [TaskBarHandler]::hide("Shell_TrayWnd", $null)
if (-Not ($task_bar_status)) {
    [TaskBarHandler]::restore("Shell_TrayWnd", $null)
}
```

## PowerShell起動
Windowsキー ＋ R 押下
`powershell -ExecutionPolicy RemoteSigned`
## スクリプト実行
`PS C:\> C:\[任意の場所]\TaskBarHandler.ps1`

最初の実行で、タスクバーが消える。
もう一度実行すると、復活！
MySQLのインストールでGPG キーによるエラー解消

MySQLのインストールで下記のエラーがでてつまずいたためメモ程度に解消法を記載しておきます。

下記を実行する事でMySQLをインストールすることができるのですが、

```php
sudo yum install -y mysql-community-server
```


下記のエラーがでてしまっていました。

```php
Failing package is: mysql-community-client-8.0.36-1.el7.x86_64
 GPG Keys are configured as: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql
 ```
これはMySQLのバージョンに対応したGPGキーへ更新することで解消されます。

```php
rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2023
```

 MYsqLのバージョンによって違いがありそうですが、
 MySQlの公式ページ( https://dev.mysql.com/doc/refman/8.3/en/checking-rpm-signature.html)
 に記載があるので、インストールしようとしているバージョンにあったコマンドで更新しましょう。
フローで　月曜日　18:00〜　火曜日　5:00 に作成されたレコードを対象外にする


+ [フローで特定曜日の時間帯を除外したい](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007aihPbSAI)

時間についてはHour関数を使って取得すればと思ったのですが... フローには何故か時間の関数がないんですよね。
仕方ないので、時間をテキスト型にして切り取って使うことにします。


作成時刻でということなのでCreatedDate項目をと思ったけど、これって保存前には分かりません。よってちょっとズレがあるかもしれませんが　{!$Flow.CurrentDate})を使います。


MID(TEXT({!$Flow.CurrentDateTime} + 9/24), 12, 9) を使うと自国の部分だけ切り出せます。

```
05:00:00Z
```

TEXT変換するとGMTに変換されるので + 9/24（9時間プラス）を使って日本時間にしておきます。

また、曜日についてはWEEKDAY({!$Flow.CurrentDate}) が使えます。

戻り値は以下です

1:日曜日
2:月曜日
3:火曜日
4:水曜日
5:木曜日
6:金曜日
7:土曜日

月 18:00〜 火 5:00 の場合
```
OR(
AND(WEEKDAY({!$Flow.CurrentDate})  = 2,MID(TEXT({!$Flow.CurrentDateTime} + 9/24), 12, 9) >= "18:00:00Z"),
AND(WEEKDAY({!$Flow.CurrentDate})  = 3,MID(TEXT({!$Flow.CurrentDateTime} + 9/24), 12, 9) <= "08:00:00Z")
)
```

月 18:00〜 水 5:00 の場合

```
OR(
AND(WEEKDAY({!$Flow.CurrentDate})  = 2 ,MID(TEXT({!$Flow.CurrentDateTime} + 9/24), 12, 9) >= "18:00:00Z"),
WEEKDAY({!$Flow.CurrentDate}) = 3 ,
AND(WEEKDAY({!$Flow.CurrentDate})  = 4,MID(TEXT({!$Flow.CurrentDateTime} + 9/24), 12, 9) <= "08:00:00Z")
)
```

今回はこれらが対象でないので、判定でfalseの時に処理できればいいと思います。

全体の構成は以下です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/9229081f-775c-8551-3115-6546f272f18b.png)
MySQL と PostgreSQLの比較

俺的、雑な比較

# MySQL 良き
	AuroraServerlessで省メモリ。0.5ACUで収まりやすい
	カラム追加時、追加する場所を選べる
	接続コストが安い。aws-lamdaでコネクションプールを使わない場合有利、たぶん。
	MySQL Workbenchが使いやすい
	
# PostgreSQL　良き
	DDLをrollback出来る、マイグレーション系で便利
	マテリアライズドビューがある
	複雑なクエリの実行計画が強い、速い
	ライセンスで悩まない
[PHP] 条件演算子 - 三項演算子とnull合体演算子


## この記事の目的
条件演算子である**三項演算子**と**null合体演算子**の使い方を理解する。

## 本題
### 1. 三項演算子
早速ですが、以下の簡単な if 文を見て下さい。

 ```php
// テスト結果が合格が不合格かを取得する関数
function get_exam_result($point)
{
    if ($point >= 60) {
        return "合格です";
    } else {
        return "不合格です";
    }
}

echo get_exam_result(78);   // "合格です"
echo get_exam_result(40);   // "不合格です"
 ```

 このような単純なif文は、**三項演算子**を使ってもっとシンプルに記述できます。
```php
// 三項演算子を使ってシンプルに記述
// テスト結果が合格が不合格か取得する関数
function get_exam_result($point)
{
    return $point >= 60 ? "合格です" : "不合格です";
}

echo get_exam_result(78);   // "合格です"
echo get_exam_result(40);   // "不合格です"
```

このように、「 if文の結果に応じて 値A または 値B を選ぶ」というような場合には、三項演算子を使うことができます。
三項演算子の使い方をまとめると、
```
[条件式] ? [条件式が true だった時に選ばれる値（値A）] : [条件式が false だった時に選ばれる値（値B）];
```
ということになります。

::: note info
**三項演算子の省略形 `?:`**
三項演算子の真ん中（値A の部分）は省略することもできます。その場合、以下のような形になります。
```
[変数] ?: [値B]
```
変数の値が true と同等の場合は その値自身が、 それ以外の場合は 値B が選ばれます。
 ```php
 // 例
 $hoge = 1;
 echo $hoge ?: 'a';  // 1 が出力される。（1 は true と同等なため）

 $moge = 0;
 echo $moge ?: 'a';  // a が出力される。（0 は true と同等ではないため）
 ```
:::

<br>

### 2. null合体演算子
**null合体演算子**は、三項演算子の「条件式」の部分が「$hoge === null」のような null かどうかを判別する条件であった場合に使うことができます。

例えば、以下のコードを見て下さい。
```php
// あいさつのメッセージを取得する関数
function get_greet_msg($name)
{
    if ($name === null) {
        $name = "No Name"
    }
    
    return "{$name} さん、こんちには";
}

$name = null;
echo get_greet_msg($name);  // "No Name さん、こんにちは"

$name = 'Tom';
echo get_greet_msg($name);  // "Tom さん、こんにちは"
```

`get_greet_msg()` 関数に渡す引数 `$name`が null だった場合には "No Name"を代入するという条件式が書かれています。
これは、null合体演算子を使ってこのようにシンプルに記述することができます。
```php
// null合体演算子を使ってシンプルに記述
// あいさつのメッセージを取得する関数
function get_greet_msg($name)
{
    $name = $name ?? "No Name";  // $name が null なら "No Name"を、null でなければその値自身を $name に代入する
    return "{$name} さん、こんちには";
}

$name = null;
echo get_greet_msg($name);  // "No Name さん、こんにちは"

$name = 'Tom';
echo get_greet_msg($name);  // "Tom さん、こんにちは"
```

null合体演算子の使い方をまとめると、
```
[nullであるか調べたい変数] ?? [nullだった場合に選ばれる値];
```
ということになります（変数が null でなかった場合はその変数の値が選ばれます）。

## 最後に
ちなみに、三項演算子やnull合体演算子のように、条件式の比較結果に応じて値を選ぶ演算子をまとめて**条件演算子**と呼びます。
条件演算子を使って記述できる際は積極的に使うようにしましょう。
ゼロから始めるLLMの開発とプロダクト化までの全過程について説明します

LLMが具体的にどのように作られているのかについて、一つの文章でまとめているものはなかなかないようですので、LLMの開発からプロダクト化までの全過程を詳しく説明したいと思います。

LLMをゼロから開発する際には、大きく分けて以下の3つのステップがあります。
①Pre-train（事前学習）
②SFT（Supervised Fine-Tuning：教師ありファインチューニング）
③RLHF（Reinforcement Learning from Human Feedback：人間のフィードバックによる強化学習）

# 1.Pre-train（事前学習）
Pre-trainでは、モデルに次の単語を予測させる作業を繰り返し行います。

現在のLLMは、ほとんどがTransformerアーキテクチャに基づいて設計されています。そのため、Transformerの構造を理解していれば、Pre-trainを行うことはできます。

Transformerアーキテクチャには、主に2種類のモデル構成があります。
1つは、「Denseモデル」と呼ばれるものです。GPTやLlamaなどがこのタイプに当てはまります。Denseモデルでは、1つの大きなモデルのみ学習させます。
もう1つは、**MoE**（Mixture of Experts）と呼ばれるモデルです。MoEでは、複数の小さなモデルを組み合わせて学習させます。これらの小さなモデルを「エキスパート」と呼びます。それぞれのエキスパートが得意な分野を持っていて、問題によって適切なエキスパートを使って回答を生成します。一つの大きなモデルよりも高い性能を発揮できます。

現在主流の学習方法は、MicrosoftのDeepSpeed（分散学習）＋FlashAttention（速度向上）＋VLLM（推理速度向上）を組み合わせて、モデルの事前学習を行います。


# 2.SFT（教師ありファインチューニング）

SFTでは、LLMが人間の質問にどのように答えることをトレーニングします。
質問応答形式（QA）のデータをモデルに提供し、人間との対話方法を学習させます。（モデル名の後ろに"-instruct"が付いているのはSFT実施済みということです。）

# 3.RLHF (人間のフィードバックによる強化学習)
RLHFでは、LLMに人間が好むoutputを生成させるようにトレーニングします。（RLHFは、不適切なアウトプットを生成しないようにするためのセキュリティ対策の一環でもあります。）

手法としては、主に**DPO**と**PPO**があります。DPOは、並列処理が可能なため、より大規模なトレーニングに適しています。

具体的な手順は、まず同じプロンプトに対する回答を人手で順位を付けて、報酬モデル（Reward Model）に学習させます。次に、この報酬モデルを用いて元のモデルを監督し、生成された結果の良し悪しを評価します。これによってモデルは人間が好む結果を生成するようになります。


# 4.LLMの精度について
モデルの精度に影響を与える主な要因は3つあります。
1つ目はデータです。
データの量、分布（領域や言語の割合分布）、品質などは最も重要なポイントです。

2つ目は、モデルの構成です。
GPTやLlamaのDenseモデルにするか、MoEにするか、それともTransformerではなく全く新しいアーキテクチャにするか、どちらでもトレーニング結果に影響します（例えば、最近Transformerとは異なる新しいアーキテクチャ”Mamba”やMamabaとTransformerを組み合わせたJambaも登場しています）。

最後はモデルトレーニングスキル（loss変化によって，パラメータをチューニングしたり）も重要です。

# 5.ファインチューニングとRAG
モデルを構築した後は、ユースケースに応じて、ファインチューニングやRAGを行うか、あるいは両方を行うかを検討します。

特定のタスク（例えば、特定の業界に関する質問に答えること）にモデルを特化させたい場合は、**ファインチューニング**を実施します。ファインチューニングとSFTは非常に似ており、コードもほとんどSFTのコードをそのまま使用します。
一般的な手法としては、GPUリソースを節約できるLoRAがあります。

GPUリソースを使用せずにモデルの精度を向上させたい場合や、既存のLLMに新しい知識を追加したい場合は、**RAG**を検討します。外部データベースを接続することで、モデルの回答精度を向上させ、未知の内容にも対応できるようになります。


# 6.AI-Agentとプロンプトエンジニアリング
最終的に、これらをパッケージ化してプロダクト化したものがAI-Agentです。Agentの中身は、大量のプロンプトによって構成されており、それらのプロンプトからモデルの動作をステップごとに定義しています。Agentのパフォーマンスをさらに向上させるためには、**Multi-Agent**（マルチエージェント）などの技術もあります。
このプロダクト化のステップを簡単に実行するためには、**langchain**や**Llamaindex**などのフレームワークを使用します。

プロンプトエンジニアリングとは、モデルに入力する指示を調整することでモデルの出力を向上させる方法です。**few-shot**（In-context learningとも呼ばれます）などの手法がよく使用されています。


以上が、私の理解に基づくLLMの開発からプロダクト化までの全過程です。細かい理解の誤りがあるかもしれませんが、全体的には正しいかと思います。認識相違があればぜひ教えていただきたいです。
ITパスポート 情報セキュリティマネジメント

・情報セキュリティマネジメントシステム
組織における情報資産のセキュリティを適切に管理していく仕組み
国際規格のISO/IEC 27000
国内規格のJIS Q 27000
・機密性
許可された者だけが使用できること
・完全性
情報が正確であり完全であること
・可用性
必要なときに使用できること
・真正性、信頼性、責任追跡性、否認防止
・アクセス権
ディレクトリやファイルなどを利用する権限

・ISMS適合評価制度
ISMSに対する取り組みを第三者機関が評価、認定する制度
・ISMSクラウドセキュリティ認証
クラウドサービスの提供、利用に関するセキュリティ基準

・情報セキュリティポリシ
組織における情報セキュリティ対策の方針や行動指針
基本方針、対策基準、実施手順
・情報セキュリティ基本方針
組織の長が、情報セキュリティに対する考え方や取り組む姿勢を組織内外に宣言する文書
・SECURITY ACTION
中小企業の情報セキュリティ対策を促進するために、IPAが創設した制度

・情報セキュリティの組織、機関
CSIRT（シーサート）、情報セキュリティ委員会、JPCERT/CC、J-CRAT、NOTICE