OmniAICreator/Qiita-1.07M huggingface dataset:
M5StampS3 をI2Cデバイスとして認識させる

![SS 192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/a41cd967-f549-8677-1efa-2e99bf69518d.png) あくまで認識させるとこまでのメモ。

## やること
M5StampS3 をI2Cスレーブとして設定し、 Aruduino系（今回はESP32DevkitC）からI2Cデバイスとして認識させます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/3827183d-6137-b163-32ed-ce7cd5d82ef2.png" width=500>


## 準備物・実施環境
- M5StampS3
- ESP32DevkitC（ArduinoでももちろんOK）
- Arduino IDE

## 注意点
- 書き込みモードにするには、**本体のボタンを押しながらUSBを挿す**必要があります。
- M5StampS3では通常のシリアルモニタ命令は使えず、USBSerialとして指定する必要があります。

## スケッチ

#### メイン（マスター）側（ESP32DevkitC）

```JAVA:
#include <Wire.h>
#define PIN_SDA 21
#define PIN_SCL 22   

void setup()
{
  Wire.setPins(PIN_SDA, PIN_SCL);
  Wire.begin();
  Serial.begin(115200);
  while (!Serial);
  Serial.println("\nI2C Scanner");
}

void loop()
{
  byte error, address;
  int nDevices;
  Serial.println("Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; address++ )
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error == 4)
    {
      Serial.print("Unknown error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
  delay(3000);
}
```
<br>

#### サブ（スレーブ）側（M5StampS3）

今回はI2Cデバイスとして認識させる用なので、onRequestやonReceiveの通信の内容についてはまだデタラメです。

```JAVA:
#include "Wire.h"
#define PIN_SDA 13
#define PIN_SCL 15
#define I2C_DEV_ADDR 0x58

uint32_t i = 0;

void onRequest() {
  Wire.print(i++);
  Wire.print(" Packets.");
  USBSerial.println("onRequest");
}

void onReceive(int len) {
  USBSerial.printf("onReceive[%d]: ", len);
  while (Wire.available()) {
    USBSerial.write(Wire.read());
  }
  USBSerial.println();
}

void setup() {
  USBSerial.begin(115200);
  USBSerial.setDebugOutput(true);
  USBSerial.print("Start as I2C 0x");
  USBSerial.println(I2C_DEV_ADDR, HEX);

  Wire.setPins(PIN_SDA, PIN_SCL);
  Wire.onReceive(onReceive);
  Wire.onRequest(onRequest);
  Wire.begin((uint8_t)I2C_DEV_ADDR);
}

void loop() {
}
```

## 接続

|ESP32DevkitC|M5StampS3|
|:-:|:-:|
|GND|GND|
|5V|5V|
|21番ピン(SDA)|13番ピン(SDA)|
|22番ピン(SCL)|15番ピン(SCL)|

他のI2Cデバイスがある場合も同様に接続します。


## 実行結果
下記はESP32DevkitC（I2Cマスター）のシリアルモニタの表示例です。 I2CデバイスとしてのM5StampS3に加え、センサーのMPU6050, BNO055も同時に接続した場合の実行結果です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/86d7c17f-06a0-fdfb-e8ec-63c66261bc22.png" width=300>

オリジナルのI2Cデバイスのアドレスの選び方
下記が参考になりました。ありがとうございます。

http://yatsugatake.org/kodaira/devnote/hardware/list-of-i2c-address/


## 続き
配列のような一連のデータをM5StampS3から送信することもできました。
記事は以下になります。

https://qiita.com/Ninagawa123/items/9952b89183e9618a271f


## 課題感
ただし、S3のI2C通信速度がプルアップ抵抗を入れても100kまでしか対応しません。 下記のライブラリを使うことで400kに対応することができるかもしれません。

https://github.com/gutierrezps/ESP32_I2C_Slave
見たことある開発言語の命名規則まとめたぞオラッ！！！


-----------------------------------------------------------------------------------------------------------------
# Ruby

## 変数やメソッド:
スネークケースを使用。複数の単語はアンダースコア（_）で区切る。
### 例: my_variable, calculate_sum

## クラスやモジュール:
キャメルケースを使用。単語の先頭を大文字で始め、連結する単語の先頭も大文字。
### 例: MyClass, MyModule
-----------------------------------------------------------------------------------------------------------------
# Python

## 変数や関数
スネークケースを使用。複数の単語はアンダースコア（_）で区切る。
### 例: my_variable, calculate_sum

## クラス: 
キャメルケースを使用。単語の先頭を大文字で始め、連結する単語の先頭も大文字。
### 例: MyClass, MyModule

## モジュール：
スネークケースを使用（小文字）。複数の単語はアンダースコア（_）で区切る。
### 例: my_module, utility_functions

:::note
モジュールがパッケージ内のサブモジュールと関連している場合、モジュール名にドット（.）を使用して階層構造を表現することが可能。
例: my_package.submodule
:::


-----------------------------------------------------------------------------------------------------------------
# JavaScript

## 変数や関数: 
キャメルケースを使用。単語の先頭を小文字で始め、連結する単語の先頭を大文字。
### 例: myVariable, calculateSum

## クラスやコンストラクタ関数: 
キャメルケースを使用。単語の先頭を大文字で始め、連結する単語の先頭も大文字。
### 例: MyClass, MyConstructor

-----------------------------------------------------------------------------------------------------------------
# SQL

## テーブルやカラム: 
スネークケースを使用。複数の単語はアンダースコア（_）で区切る。
### 例: my_table, created_at

## キーワードや関数: 
大文字で表記。
### 例: SELECT, COUNT
-----------------------------------------------------------------------------------------------------------------
# React:
## コンポーネント: 
パスカルケースを使用。単語の先頭を大文字で始め、連結する単語の先頭も大文字。
### 例: MyComponent, HeaderSection
'I' の数 (paizaランク B 相当)

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

やってることは累積和の差し引きをして、その数を比較するだけのもの。
もうすこし累積和の特徴を知っておかなくては。。。

```py
N,K = map(int,input().split())
A = [int(input()) for _ in range(N)]
# 累積和を求める
ans = [0] + A[:]
for i in range(1,N+1):
    ans[i] += ans[i-1]

for _ in range(K):
    a_left,a_right,b_left,b_right = map(int,input().split())

    # 累積和の足し引きで可能。ただしleftは−1引く必要がある
    a = ans[a_right] - ans[a_left - 1]
    b = ans[b_right] - ans[b_left - 1]
    
    #ルール確認・相手も反則してなければ必ず負けるようにする
    if a_right - a_left + 1 >= N/3:
        a = -1 
    if b_right - b_left + 1 >= N/3:
        b = -1 
 
    #判定
    if a == b:
        print("DRAW")
    elif a > b:
        print("A")
    else:
        print("B")

```
Elixirで言語処理100本ノックやってみた！vol.6 ①和集合

こんにちは！
3ヶ月で、Elixir言語で開発できるようになるため、奮闘中のこーへーです！

vol.6は、一つの問題の中に複数問題が含まれている感じの形式なので、今回はvol.6①でやっていきたいと思います。
では、やっていきたいと思います。
[100本ノックの記事はこちら](https://nlp100.github.io/ja/ch01.html)

### 06. 和集合
*“paraparaparadise”と”paragraph”に含まれる文字bi-gramの集合を，それぞれ, XとYとして求め，XとYの和集合，積集合，差集合を求めよ．さらに，’se’というbi-gramがXおよびYに含まれるかどうかを調べよ．*

まずは、和集合から。

**和集合とは、2つの集合の少なくともどちらか1つに含まれる要素の集合のことです**

つまり、「paraparaparadise」とparagraphを文字のbigramにしたのち、どちらか1つに含まれる要素を抜き出すという内容になります。

#### Comprehensiveモジュール、union関数の作成
```
defmodule Comprehensive do
  def union(x, y) do
    String.codepoints(x <> y)
    |> Enum.chunk_every(2, 1, :discard)
    |> Enum.map(fn x -> Enum.join(x) end)
    |> Enum.uniq
  end
end
```

####  Comprehensive.union("paraparaparadise", "paragraph")の実行結果
```
 iex> Comprehensive.union("paraparaparadise", "paragraph")
 
["pa", "ar", "ra", "ap", "ad", "di", "is", "se", "ep", "ag", "gr", "ph"]
```

### まとめ
今回意外と苦戦したのは、bigramにするところです。Enum.mapの中で、Enum.joinを使っていますが、その発想が出ず苦労しました。

これも関数の使い方のレパートリーが増えればさくさく解いていけそうな問題なので、引き続き頑張ります。

次回は②積集合を解きます。
Google Cloudアップデート (4/11-4/17/2024)

### GKE: [Apr 10, 2024](https://cloud.google.com/kubernetes-engine/docs/release-notes#April_10_2024)
- N4マシンファミリが1.29以降で使えるようになったよ！

### Cloud Composer: [Apr 11, 2024](https://cloud.google.com/composer/docs/release-notes#April_11_2024)
- 6/15/2024からコンソールからComposer1が作成できなくなるよ

### Cloud Pub/Sub: [Apr 11, 2024](https://cloud.google.com/pubsub/docs/release-notes#April_11_2024)
- Pub/Subのメトリクスを元にオートスケールしている場合の[ベストプラクティス](https://cloud.google.com/pubsub/docs/metrics-autoscaling-best-practices)のドキュメントが追加されたよ！

### Cloud Billing: [Apr 5, 2024](https://cloud.google.com/billing/docs/release-notes#April_05_2024)
- 過去の利用を元にレコメンデーションをしてくれる[FinOps hub](https://cloud.google.com/billing/docs/how-to/finops-hub)がGAになったよ！

### Bigtable: [Apr 11, 2024](https://cloud.google.com/bigtable/docs/release-notes#April_11_2024)
- LangChainとの統合がプレビューになったよ！

### Cloud Healthcare API: [Apr 4, 2024](https://cloud.google.com/healthcare-api/docs/release-notes#April_04_2024)
- v1beta1, v1, v1alpha2:
  - 新しいバージョンのお知らせ

### GKE: [Apr 12, 2024](https://cloud.google.com/kubernetes-engine/docs/release-notes#April_12_2024)
- 1.27以降で[NVIDIAのGPUのレスポンスを向上させるGPUDirect-TCPX](https://cloud.google.com/kubernetes-engine/docs/how-to/gpu-bandwidth-gpudirect-tcpx)が使えるようになったよ！

### AlloyDB: [Apr 12, 2024](https://cloud.google.com/alloydb/docs/release-notes#April_12_2024)
- Omni 15.5.2が使えるようになったよ！
  - Kubernetesのメモリ問題の修正

### Cloud Run: [Apr 15, 2024](https://cloud.google.com/run/docs/release-notes#April_15_2024)
- Direct VPC egressがすべてのリージョンで使えるようになったよ！

### Apigee: [Apr 15, 2024](https://cloud.google.com/apigee/docs/release/release-notes#April_15_2024)
- 新しいバージョンリリースのお知らせ

### Cloud Pub/Sub: [Apr 15, 2024](https://cloud.google.com/pubsub/docs/release-notes#April_15_2024)
- クライアントライブラリ更新

### Vertex AI: [Apr 15, 2024](https://cloud.google.com/vertex-ai/docs/release-notes#April_15_2024)
- カスタムトレーニングで長時間実行されるトレーニングジョブを実行できる[persistent resource](https://cloud.google.com/vertex-ai/docs/training/persistent-resource-overview)がプレビューになったよ！

### Identity Platform: [Apr 15, 2024](https://cloud.google.com/identity-platform/docs/release-notes#April_15_2024)
- 設定を有効化している場合に30日以上古いanonymousアカウントを自動で削除するようになったよ！

### Vertex AI: [Apr 11, 2024](https://cloud.google.com/vertex-ai/docs/release-notes#April_11_2024)
- Anthropic Claude 3.0 Opusモデルがプレビューになったよ！

### Compute Engine: [Apr 16, 2024](https://cloud.google.com/compute/docs/release-notes#April_16_2024)
- Z3 VMがGAになったよ！
  - 日本ではまだ使えない
- M1/M2でHyperdisk BalancedがGAになったよ！

### Bigtable: [Apr 16, 2024](https://cloud.google.com/bigtable/docs/release-notes#April_16_2024)
- Javaのクライアントライブラリ2.38.0以降でクライアントサイドのメトリクスがデフォルトで有効化されるようになったよ！

### GKE: [Apr 16, 2024](https://cloud.google.com/kubernetes-engine/docs/release-notes#April_16_2024)
- 1.25以降でZ3マシンタイプが使えるようになったよ！

### Cloud KMS: [Apr 4, 2024](https://cloud.google.com/kms/docs/release-notes#April_04_2024)
- Bare Metal Rack HSMがGAになったよ！
  - PCI対応用にラック単位で管理してくれて、一部リージョンのみで利用可能


### ディスクレーマ
- アップデートの内容はあくまでも個人の理解していることを書いています。正しい内容はリリースノート等を確認下さい。
- リリース内容できるだけ拾うようにしているのですが、抜けていそうなリリースノートは追加するのでぜひ教えて下さい！(一覧[ここ](https://qiita.com/kenzkenz/items/ac18a359b803dbb6b490)で更新してます。)
githubに草が生えていない！？時の対処法

## 問題
githubにpushしているのに草が生えていなくて困った。
生やしたい。

これ↓
![スクリーンショット 2024-04-18 19.18.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726068/5e9976d7-c2b9-63b4-29f3-aa5b68adb919.png)

## 解決法
### 結論
自前の開発環境(ローカル)とGitHub(リモート)で登録しているメールアドレスを一致させないと草が生えないらしい。
一致させる手順は以下↓

### 手順
↓これ読めばOK

https://techgamelife.net/2021/01/29/github-kusa-haenai/

↓下2つでも良い

https://qiita.com/ryosuketter/items/2f0152b32007ac8351f3

https://docs.github.com/ja/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/setting-your-commit-email-address
ChatGPTと学ぶBFFについて

どうもこんにちは、たくびー(@takubii)です。

BFFという単語を聞いたことはありますか？
Backend For Frontendの略で、直訳してフロントエンドのためのバックエンドという意味です。

単語はたまに見かけるけど、内容がイマイチわからないなと感じたのでChatGPTに質問しながらどういったものか調べてみました。

# ChatGPTに聞いてみた

まずは手始めにBFFについて質問してみました。

![スクリーンショット 2024-04-17 17.26.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557065/886d818a-51ff-e9c1-5ca2-715e1559b77c.png)

なるほど、フロントエンドとバックエンドの中間に挟む別のAPI呼び出しポイントらしいですね。
パフォーマンス・セキュリティ向上や複雑性の分離などがメリットみたいです。

次はなぜ必要なのか聞いてみました。
フロントエンドから直接バックエンドのAPIを呼び出せばいいと感じたので以下のように質問してみました。

![スクリーンショット 2024-04-17 17.26.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557065/09eb2de5-49a2-eb56-7554-ac00f92c4ecc.png)

大規模なサービスになってくると複数のエンドポイントからAPIを呼び出し、それらをフロント側でまとめるということがあるようです。
そういったシチュエーションを避けるためにBFF層を作ることで複数のバックエンドの結果を整理し、フロントエンドに新たなAPIとして提供できるというわけですね。

では、どのようなチームで導入すると効果的なのか気になったのでその部分について質問してみましょう。

![スクリーンショット 2024-04-17 17.27.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557065/596a0baa-9a36-6b8b-b050-8cee803b2c89.png)

全体的に見るとモダンなチーム構成だと効果的なように見えますね。
特に各分野が専門的なチームで独立している場合、変更や修正などに強くなりそうです。

さて、では誰が実装を担当するのかという部分を聞いてみます。

![スクリーンショット 2024-04-17 17.27.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557065/84df8705-a55f-a28b-6d2d-1a15aec98696.png)

この回答だと専門チームがない場合はフロントエンドチーム、バックエンドチームどちらも実装する可能性はありそうですね。
ただ、バックエンドチームの方が実装する際の考慮事項は少なさそうに読めますね。

# 終わりに

ChatGPTを使って認識が甘い単語について調べてみました。
特にプロンプトなど気にせず質問していますが回答の精度もよく、わからないところを深掘りしてくだけでほしい情報が得られますね。

この記事を読んでいる皆様も何かわからないことがあればChatGPTに聞いてみましょう！
よほど最近のことでなければ、きっとほしい情報が得られると思います。

それでは今回はこのあたりで締めたいと思います。
ここまで読んでいただきありがとうございます。
また機会があればお会いしましょう。
M5AtomS3でシリアル出力ができない!?

# 最初M5AtomS3をArduinoIDEを使ってプログラムしようとしたらprintfとかができなかった。

~解決策~
"ツール"→"USB CDC On Boot"→"Enabled"
と選択するだけ!!
これでシリアルで出力されるようになったはず。おめでとう!
はじめまして！

はじめまして！
ひとつかと申します。
アウトプットをしたくQiitaをはじめました！
後から見たときに役立つ、そしてどこかにいる誰かの役に立つ記事を書ければと思います。

### 簡単な自己紹介
1989年生まれ 社会人13年目です。
前職は楽天で戦略系の仕事をしてバリバリ働いていました。
現在は家庭の事情で地元に戻り、派遣社員として働いています。

### 得意なこと・好きなこと
・業務の効率化 / 自動化
・プロジェクトマネジメント

### スキル
・英語(TOEIC 900)
・Python
・VBA
・SQL
・RPA

### やりたいこと
また、正社員としてバリバリ働きたいです。
楽天時代は毎日が目まぐるしく過ぎて行って、大変だけれどもとても充実した日々でした。
尊敬できる上司の元で必死に追いつこうと頑張って、成長を感じられる日々でした。
そんな日々に戻りたいです。

年齢を重ねてきて最近本当に感じるのは今が一番若くて、残された時間というのはどんどん減っていくということ！
20代の時は何でも挑戦できた気がします。やり直しもできたと思います。
でも、これからはどんどん選択肢というのが狭まっていくのではないのかなと思います。
なので、後悔しないように日々学び、成長していきたいです。
Nodeのバージョンを変更したい

## はじめに
Nodeのバージョンを変更したい。
まずはNodeのバージョンを確認。
```
$ node -v
```
すると
```
v18.15.0
```
これが現在のバージョンです。
今回は `v12.9.1` に変更していきます。

## 1.ダウンロード可能なバージョンを確認
下記コマンドをターミナルで入力。
```
$ nodebrew ls-remote
```
しかし、
```
zsh: command not found: nodebrew
```
と怒られてしまいました🥲

### nodebrew のインストールができているか確認
```
$ which nodebrew
```
すると
```
nodebrew not found
```
と表示されました。
どうやら nodebrew がインストールされていなかったようです。

### nodebrew をインストールする
(Homebrewがインストールされている前提)
```
$ brew install nodebrew
```
上記コマンドを入力できたら、次にパスを設定する必要があります。

#### .zshrc ファイルを開く
ターミナルで以下のコマンドを入力
```
$ nano ~/.zshrc
```
.zshrc ファイルが開いたら、ファイルの末尾に次の行を追加
```
export PATH=$HOME/.nodebrew/current/bin:$PATH
```
追加できたら、`Ctrl+O`(WriteOut)を押して、Enterで保存。
`Ctrl+X`を押してnanoエディタを終了する。

このコマンドは nodebrew の実行可能ファイルがあるディレクトリをシステムのパスに追加します。これにより、任意の場所から nodebrew コマンドを実行できるようになります。

#### .zshrc ファイルの変更を有効にする
ターミナルに戻り、以下のコマンドを実行します。
```
$ source ~/.zshrc
```
これにより、新しいパス設定が有効になリます。

#### 設定の確認
以下のコマンドを入力
```
$ which nodebrew
```
これにより、nodebrew のインストールパスが表示されるはずです。
何も表示されない場合は、パス設定に問題がある可能性があります。

これで nodebrew のインストールが完了しました！

再度コマンドを入力してみる。
```
$ nodebrew ls-remote
```
すると
```
v0.0.1    v0.0.2    v0.0.3    v0.0.4    v0.0.5    v0.0.6    

v0.1.0    v0.1.1    v0.1.2    v0.1.3    v0.1.4    v0.1.5    v0.1.6    v0.1.7
v0.1.8    v0.1.9    v0.1.10   v0.1.11   v0.1.12   v0.1.13   v0.1.14   v0.1.15
v0.1.16   v0.1.17   v0.1.18   v0.1.19   v0.1.20   v0.1.21   v0.1.22   v0.1.23
v0.1.24   v0.1.25   v0.1.26   v0.1.27   v0.1.28   v0.1.29   v0.1.30   v0.1.31
v0.1.32   v0.1.33   v0.1.90   v0.1.91   v0.1.92   v0.1.93   v0.1.94   v0.1.95
v0.1.96   v0.1.97   v0.1.98   v0.1.99   v0.1.100  v0.1.101  v0.1.102  v0.1.103
v0.1.104

以下省略
```
ダウンロード可能なバージョン一覧が表示されました。

## 2.指定のバージョンをインストールする
まずは下記のコマンドを入力して、nodebrew が使用するディレクトリ構造をセットアップします。
```
$ nodebrew setup
```
次に、ダウンロード可能なバージョン一覧から、指定のバージョンをインストールする。
下記のコマンドを入力してください(今回は v12.9.1をインストール)。
```
$ nodebrew install-binary v12.9.1
```
### 使用したいバージョンに変更する
下記コマンドを入力してください。
```
$ nodebrew use v12.9.1
```
コマンド入力後 `use v12.9.1` と表示される.

## 3.バージョンが切り替わっているか確認
下記コマンドを入力してください。
```
$ node -v
```
 指定したバージョンに切り替わっていればOK（ここではv12.9.1）

 これで、Nodeのバージョン変更ができました！

## まとめ
### Nodeのバージョンを変更するには
#### 1.ダウンロード可能なバージョンを確認
```
$ nodebrew ls-remote
```
#### 2.指定のバージョンをインストールする
※`v12.9.1`の場合
```
$ nodebrew install-binary v12.9.1
```
#### 3.使用したいバージョンに変更する
```
$ nodebrew use v12.9.1
```
#### 4.バージョンが切り替わっているか確認
```
$ node -v
```
これでいつでもバージョンの切り替えができます！
【Walkthrough】TryHackMe:Linux Fundamentals Part 2

# 概要

# Task3

## **Q2**.*What directional arrow key would we use to navigate down the manual page?*

**A**.**down**

## **Q3**.*What flag would we use to display the output in a "human-readable" way?*

`human-readable`などの文字列で`man`コマンドの結果を抽出すると分かる。

```bash
$ man ls | grep "human-readable"
       -h, --human-readable
```

**A**.**-h**

# Task4

## **Q1**.*How would you create the file named "newnote"?*

**Hint**.*Look at the answer formatting - we're not expecting quotation marks for this*

**A**.**touch newnote**

## **Q2**.*On the deployable machine, what is the file type of "unknown1" in "tryhackme's" home directory?*

`file`コマンドで対象のファイルを確認します。

```bash
$ file unknown1 
unknown1: ASCII text
```

**A**.**ASCII text**

## **Q3**.*How would we move the file "myfile" to the directory "myfolder"*

**A**.**mv myfile myfolder**

## **Q4**.*What are the contents of this file?*

`cat`コマンドで対象ファイルの中身を確認します。

```bash
$ cat ./myfolder/myfile 
THM{FILESYSTEM}
```

**A**.**THM{FILESYSTEM}**

# Task5

## **Q1**.*On the deployable machine, who is the owner of "important"?*

`ls -l`コマンドを使用し対象ファイルのオーナーを確認します。

```bash
$ ls -l
total 12
-rw-r--r-- 1 user2     user2       14 May  5  2021 important
drwxr-xr-x 2 tryhackme tryhackme 4096 Apr 15 13:08 myfolder
-rw-r--r-- 1 tryhackme tryhackme   17 May  4  2021 unknown1
```

**A**.**user2**

## **Q2**.*What would the command be to switch to the user "user2"?*

**A**.**su user2**

## **Q4**.*Output the contents of "important", what is the flag?*

`su user2`コマンドを使用し`user2`にユーザー変更後、`cat`コマンドを使用し対象ファイルの内容を確認します。

```bash
$ cat ./important 
THM{SU_USER2}
```

**A**.**THM{SU_USER2}**

# Task6

## **Q2**.*What is the directory path that would we expect logs to be stored in?*

**A**.**/var/log**

## **Q3**.*What root directory is similar to how RAM on a computer works?*

**Hint**.*The contents of this root directory do not persist after reboot*

**A**.**/tmp**

## **Q4**.*Name the home directory of the root user*

**A**.**/root**
【css】画像をアイコンで表示する方法

##　問題
SNSなどによくある円形のアイコン画像を表示したい

## 方法
### 最終結果(ヘッダーの右側)
![スクリーンショット 2024-04-18 19.06.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726068/1e867128-0df9-17bd-b0c6-4cd5434efb16.png)

### コード
```index.html
<div class="header-right">
    <button class="btn btn-success">予算</button>
    <button class="btn btn-success ml-1">予算登録</button>
    <button class="btn btn-success ml-1">支出登録</button>
    <div class="profile-picture profile-picture-header ml-1">
        <img class="img-fluid cursor_pointer" src="/assets/sample.jpg" alt="Profile Picture">
    </div>
</div>
```
```style.scss
.profile-picture {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  overflow: hidden;
  // ⭐️アイコンを円形にリサイズして配置
  display: flex;
  justify-content: center;
  align-items: center;

  @media screen and (max-width: 430px) {
    width: 75px;
    height: 75px;
  }

  // ヘッダーアイコン
  &.profile-picture-header {
    width: 40px;
    height: 40px;
    vertical-align: middle;
    @media screen and (max-width: 430px) {
      width: 30px;
      height: 30px;
    }
  }

  img {
    // ⭐️アイコンを円形にリサイズして配置
    object-fit: cover;
  }
}
```

### 参考サイト

https://kingsite.jp/blog/0193#09
ReactのMaterilaUIでレコードを追加する

### 成果物
![Apr-18-2024 18-55-20.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/098cc0f8-d0d1-eba8-21ff-df1d25758094.gif)

### ソースコード
```tsx:App.tsx
import React, { useState } from 'react';
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Button, TextField } from '@material-ui/core';

interface TableRowData {
  id: number;
  name: string;
  age: number;
}

const initialRows: TableRowData[] = [
  { id: 1, name: '田中 太郎', age: 20 },
  { id: 2, name: '山田 花子', age: 22 },
];

const DynamicTable: React.FC = () => {
  const [rows, setRows] = useState<TableRowData[]>(initialRows);

  const handleAddRow = () => {
    const newRow: TableRowData = {
      id: rows.length + 1,
      name: '',  // 新しい行の名前も空文字で初期化
      age: 20 + rows.length,
    };
    setRows([...rows, newRow]);
  };

  const handleSave = () => {
    console.log('保存されたデータ:', rows);
  };

  const handleChangeName = (id: number, newName: string) => {
    const updatedRows = rows.map(row => {
      if (row.id === id) {
        return { ...row, name: newName };
      }
      return row;
    });
    setRows(updatedRows);
  };

  // 名前がすべて入力されているかどうかを確認する関数
  const isSaveButtonDisabled = () => {
    return rows.some(row => row.name.trim() === '');
  };

  return (
    <TableContainer component={Paper}>
      <Table>
        <TableHead>
          <TableRow>
            <TableCell>ID</TableCell>
            <TableCell>名前</TableCell>
            <TableCell>年齢</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map((row) => (
            <TableRow key={row.id}>
              <TableCell>{row.id}</TableCell>
              <TableCell>
                <TextField
                  value={row.name}
                  onChange={(e) => handleChangeName(row.id, e.target.value)}
                  variant="outlined"
                  size="small"
                  style={{ width: '100%' }}
                />
              </TableCell>
              <TableCell>{row.age}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
      <Button onClick={handleAddRow} color="primary" variant="contained" style={{ marginTop: 20, marginRight: 10 }}>
        行を追加
      </Button>
      <Button 
        onClick={handleSave} 
        color="secondary" 
        variant="contained" 
        style={{ marginTop: 20 }}
        disabled={isSaveButtonDisabled()} // 保存ボタンの有効/無効を制御
      >
        保存
      </Button>
    </TableContainer>
  );
};

export default DynamicTable;

```
ProxmoxのVMでpingが通らなかった話

proxmoxでubuntu-23.04のVMを立てて、いざ使おう！となって
```bash:qiita.rb
OOO~# apt update
```
を行ってたら、
```
W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/jammy/InRelease  Temporary failure resolving 'archive.ubuntu.com'
```
ってBashに怒られました...
試行錯誤したら、ゲートウェイが不完全だったみたいで、編集でゲートウェイにルーターのIPアドレス入れたら直りました...
![pve1 - Proxmox Virtual Environment - Google Chrome 2024_04_18 18_51_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726617/3cb74172-9818-498d-2f38-bfce5c226d40.png)

短いですがこれで
俺の二時間返せ...(;m;)
supabase Self-Hosting OTPメールのタイトルが文字化けするのを解決する

supabaseはワンタイムパスワード（OTP）をメールに送ることができます。
self-hostingのときは`docker-compose.yml`の`auth`のenvironmentを変更します。

このとき、メールのタイトルを変更したいときは` GOTRUE_MAILER_SUBJECTS_MAGIC_LINK`を変更します。
本文のHTMLを変えたいときは`GOTRUE_MAILER_TEMPLATES_MAGIC_LINK`でhtmlへのURLを貼ります。(supaase stroageにhtmlを置いて、そのURLをLINKに入れるのが簡単でよろしい。s3とかでもいいけど）

本題。
メールタイトルに日本語が含まれている場合、yamlをutf-8で編集しようがlaten-1で編集しようが、docker-composeがうまく動かないときがあります。無理やり保存してメールを送ってみたら文字化けをしているとか。

対策として、ISO-2022-JPのBase64へエンコードするとうまくいきました。
`=?ISO-2022-JP?B?ここにbase64文字列?=`
こんな感じですね。

ちなみにauthに渡せるenvは以下。

https://github.com/supabase/auth/blob/master/example.env

いろいろあって面白いですね。
Djangoにおけるカスタムユーザーの作り方

# 1. Djangoにおけるユーザーの種類
DjangoはPythonを用いたWebフレームワークであり、デフォルトでユーザー認証に関する機能を備えています。大きく分けて次の2つのユーザーの種類がDjangoにはあります。

### 1.1. デフォルトのユーザーモデル
Djangoが提供するデフォルトのUserモデルは、django.contrib.auth.models内で定義されており、ユーザーネーム、パスワード、メールアドレス、名前（名前と姓）などの一般的なフィールドを含んでいます。

https://docs.djangoproject.com/ja/5.0/ref/contrib/auth/

### 1.2. カスタムユーザーモデル
デフォルトのユーザーモデルは基本的なユーザー機能を備えていますが、すべてのプロジェクトのニーズを完全に満たすわけではありません。例えば、ユーザー名の代わりにメールアドレスを識別情報として使用したい場合や、ユーザー情報に追加のデータフィールド（社住所やプロフィール画像など）を含めたい場合などには、カスタムユーザーモデルが必要になります。

# 2. カスタムユーザーモデルにおける継承元
カスタムユーザーモデルを作成する際も、０から自分でユーザーモデルを作成するわけではありません。Djangoが標準で提供している抽象的なユーザーモデルを継承することで、標準の認証機能をカスタムユーザーでも利用することができます。継承元は次の2つから選択可能です。

### 2.1. AbstractUser
AbstractUserはDjangoが提供する抽象基底クラスで、デフォルトのUserモデルが持つ全てのフィールドとメソッド（ユーザーネーム、メールアドレス、パスワード、アクティブ状態など）を継承しています。AbstractUserは、デフォルトの認証フレームワークを大きく変更することなく、ユーザーモデルにいくつかのカスタムフィールドを追加したい場合や、特定のメソッドの動作をカスタマイズしたいが、基本的な構造は保持したい場合などに適しています。

### 2.2. AbstractBaseUser
AbstractBaseUserは、AbstractUserよりも柔軟な抽象基底クラスで、最も基本的な認証フレームワークのみを提供します。AbstractBaseUserは、携帯電話番号を主な認証手段として使用したい場合など、アプリケーションに特化した認証プロセスやユーザー属性を設計したい場合に適しています。

# 3. カスタムユーザーモデルの実装方法
具体的な実装方法を簡単に紹介します。

### 3.1. カスタムユーザーモデルの定義
models.py ファイルにカスタムユーザーモデルを定義します。`CustomUser(AbstractUser)`というように、AbstractUserを継承し、phone_numberやprofile_imagというフィールドを追加します。
``` python
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    phone_number = models.CharField(max_length=15, unique=True, null=True)
    profile_image = models.ImageField(upload_to='profile_images/', null=True, blank=True)
```

### 3.2. 設定の更新
Djangoプロジェクトの settings.py で、AUTH_USER_MODEL をカスタムユーザーモデルに設定します。

```python
AUTH_USER_MODEL = 'your_app_name.CustomUser'
```

### 3.3. ユーザーマネージャのカスタマイズ
AbstractBaseUser を継承している場合、カスタムユーザーマネージャも必要になります。下記の例では、ユーザーの作成と認証のロジックをカスタマイズします。

```python
from django.contrib.auth.models import BaseUserManager

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('The Email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self.create_user(email, password, **extra_fields)
```

# まとめ

Djangoでは必要に応じて、カスタムユーザーを定義することで、標準で提供されている認証機能や管理機能を使用しながら、ユーザーに関する機能を拡張することができます。詳しくは公式ドキュメントをご覧ください。

https://docs.djangoproject.com/ja/5.0/ref/contrib/auth/
ReactのMaterialUIでTableにレコードを追加する

## はじめに
![Apr-18-2024 18-40-52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/63ae96ba-2123-f26c-7e25-3ee0f47cb427.gif)


## ソースコード
```tsx:App.tsx
import React, { useState } from 'react';
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Button } from '@material-ui/core';

interface TableRowData {
  id: number;
  name: string;
  age: number;
}

const initialRows: TableRowData[] = [
  { id: 1, name: '田中 太郎', age: 20 },
  { id: 2, name: '山田 花子', age: 22 },
];

const DynamicTable: React.FC = () => {
  const [rows, setRows] = useState<TableRowData[]>(initialRows);

  const handleAddRow = () => {
    const newRow: TableRowData = {
      id: rows.length + 1,
      name: `新しい名前 ${rows.length + 1}`,
      age: 20 + rows.length,
    };
    setRows([...rows, newRow]);
  };

  return (
    <TableContainer component={Paper}>
      <Table>
        <TableHead>
          <TableRow>
            <TableCell>ID</TableCell>
            <TableCell>名前</TableCell>
            <TableCell>年齢</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map((row) => (
            <TableRow key={row.id}>
              <TableCell>{row.id}</TableCell>
              <TableCell>{row.name}</TableCell>
              <TableCell>{row.age}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
      <Button onClick={handleAddRow} color="primary" variant="contained" style={{ marginTop: 20 }}>
        行を追加
      </Button>
    </TableContainer>
  );
};

export default DynamicTable;
```
opamではインストールしたのにduneで見つからないと言われたときの対処法

opamでインストールしたはずなのに、dune buildとかで

```
Error: Library "foo" not found.
```

のように言われることがある。そんなとき確認すること。

## まずは現状どうなっているのか確認する

### opamにインストール済みか確認

`foo` が本当に現在のopam switchでインストール済みか確認する

```
opam list
```

そもそもこの一覧にないなら今回のこの文書の対象外。opamでのインストール方法を確認しよう。

### duneで見えてるライブラリ一覧を確認する

```
dune installed-libraries
```

### チェックポイント1: duneでのpublic_nameを確認

該当バージョンの `foo` ライブラリのソースコードを探して、プロジェクトディレクトリのどこかにあるduneファイルの中に `(public_name foo)` っていうのがないか確認する。
これがないとduneから見えない。たまにopamでの名前と違うことあるかも。

### チェックポイント2: install方法を確認

該当バージョンの `foo` の opamファイル (foo.opamなど) を確認してインストール時にちゃんとインストールされんのか確認する。

## 参考
- https://github.com/ocaml/dune/issues/1873
CLIでVirtualBoxのインストール (on Ubuntu)

## Install

```
$ sudo apt install virtualbox
$ sudo apt install virtualbox-ext-pack
$ sudo modprobe vboxdrv
```

Secure Boot のため起動しない
```
$ systemctl status virtualbox
Apr 05 07:14:48 ubuntu kernel: Lockdown: modprobe: unsigned module loading is restricted; see man kernel_lockdown.7
Apr 05 07:14:48 ubuntu virtualbox[45582]:  * modprobe vboxdrv failed. Please use 'dmesg' to find out why
Apr 05 07:14:48 ubuntu virtualbox[45582]:    ...fail!
Apr 05 07:14:48 ubuntu systemd[1]: virtualbox.service: Control process exited, code=exited, status=1/FAILURE
Apr 05 07:14:48 ubuntu systemd[1]: virtualbox.service: Failed with result 'exit-code'.
```

Secure Bootを無効化して再起動すると、virtualbox のサービスが立ち上がる。
```
$ sudo mokutil --disable-validation
$ sudo reboot
```

[Disable Secure Boot in shim-signed](https://wiki.ubuntu.com/UEFI/SecureBoot/DKMS)により詳細が記載されている
主にOSSでラジオ番組作るメモ

# 使用ツール
- 動画から音声抽出：hugflash
- 音声編集：Audacity
- 動画編集：kdenlive

# やる順メモ
1. お好みのMTGツールで録画をする。
1. MP4ファイルからhugflashを使って音声を抽出
1. Audacityで編集（音声）
    - ラウドネスノーマライズを行う。（デジベルの具体値は忘れた）
1. AudacityでBGM追加
    - BGMは切替のために2トラックを交互に使う。
    - 曲はフェードイン/フェードアウトで繋げとクロスフェードっぽくなる。
    - それぞれの曲ごとの設定
        - ノーマライズを行う。（デジベルの具体値は忘れたが音声より小さめ）
        - 音量は多少大きくても後からトラックで小さくするので細かいことは気にしない。
    - 最後の曲は、曲のお尻に合わせて、入りは曲の途中からフェードで置く。
    - 書き出しのビットレートは最大でおｋ。
1. 聴きながらパワポか何かでスライドショーを作る→各スライドを画像にする
    - 1回PDFとかにしてから画像にしないと帯が入ったりする場合があってダサくなる場合がある。
1. 動画編集
    - スライドショー形式にする。
    - 画像はクロスフェードにする。
        - 動画トラックを2使って交互に使って切り替える。
        - 切替ははクロスフェード(Dissolve Transitionを使用する)
        - 切替時間（Duration）は0.3秒だとちょっと長いかなー。0.2秒ぐらいがいいかも。

# 細かい話
- 字幕つけるのはすごく大変。まぁそこそこサクサクできるっちゃできるけど、魂を捧げる覚悟がいる。
- ピー音は生成がめんどくさいので、ピー入れるぐらいだったらカットの方が簡単。
- マシンスペックにもよるが、音声は音声で完成させて動画編集をしないと音ズレがすごくなる。
lftpを使ったプロキシ経由のサーバへの接続

# 


## 概要

- いつもはFileZillaを利用してFTPを使っているが、コマンドで操作する必要ができた
- 下記の設定は、つまりFTPSを利用しているということ

<img width="600" alt="image" src="https://i.imgur.com/uQkIJgd.png">

- ただftpコマンドはFTPSに対応していない
- FTPSを使うには下記の通りcurlを使う方法がある
    - https://gist.github.com/keijiro/4015735

```sh
curl -u username:password --ftp-ssl ftp://example.com
```

- または`lftps`を使う方法があり、今回はそちらを利用する

## 参考
- [【lftp】FTPサーバに接続してファイルを転送する](https://xtech.nikkei.com/it/article/COLUMN/20140310/542302/)
- [lftpでproxyを使う](https://blog.rutake.com/techmemo/2015/06/15/lftp%E3%81%A7proxy%E3%82%92%E4%BD%BF%E3%81%86/)
- [FileZilla設定方法と、FTP・FTPSについての覚書](https://atomicbox.tank.jp/developer/1393/)

## lftpコマンドによる接続

- Homebrewで`nmap`をインストールして、開いているポートを確認できる

```
nmap <IPアドレス>

...
Host is up (0.010s latency).
Not shown: 997 filtered tcp ports (no-response)
PORT     STATE SERVICE
xx/tcp   open  http
yyy/tcp  open  https
zzzz/tcp open  http
```

 - Homebrewで`lftp`をインストールして、下記の通り接続できる

```shell
lftp
lftp :~> set ftp:proxy <プロキシホスト>:<プロキシポート>
lftp :~> open -u <username>,<password> <IPアドレス>
lftp <username>@<IPアドレス>:~> ls
```

- 上記をシェルスクリプトに落とし込むと以下の通り

```sh
lftp -c '
  set ftp:proxy <プロキシホスト>:<プロキシポート>
  open -u <username>,<password> <IPアドレス>
  ls
'
```

- プロキシが必要なく、FTP接続しかできない場合は以下の通り(イントラのためFTPでもOKな場合)

```sh
lftp -c '
  open -u <username>,<password> <IPアドレス>  -e "set ftp:ssl-allow no"
  ls
'
```
【MySQL】ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (38)」や ERROR! The server quit without updating PID file の解決方法

## はじめに
今回の記事は自分への備忘録用なので説明が省略されていたり、正しくない情報が記載されている可能性もあるため、参考にする際は気をつけてください。
また、可能であればMySQLのバックアップをとっておいたほうがいいです。

### エラー内容
~~~
「ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (38)」
~~~
や
~~~
ERROR! The server quit without updating PID file
~~~

### 試したこと
調べるとよく出てくる記事にはプロセスをkillするなど、pidファイルをtouchコマンドで作成するなど、どれを試しても解決しなかった。
pidファイルは作成してもすぐに消えてしまう。
homebrewでmysqlをアンインストール後再インストールしても解決しない。

### 実際に解決したコマンド
~~~
$ cd /usr/local/var/mysql/
~~~
上記ディレクトリに移動すると、`XXXXXXX.local.err`のようなエラーログのファイルがあると思います。
lessコマンドで確認する。
~~~ 
$ less XXXXXXX.local.err
~~~
すると以下のようなエラーログを発見。
`[ERROR] [MY-010270] [Server] Can't start server : Bind on unix socket: Address already in use`
`[ERROR] [MY-010258] [Server] Do you already have another mysqld server running on socket: /tmp/mysql.sock ?`
`[ERROR] [MY-010119] [Server] Aborting`

`socket: Address already in use`と書いてあるので、rmで削除する。
~~~
$ sudo rm /tmp/mysql.sock
~~~
これでMysqlを起動することができ解決しました。
blastengineでメールを時間指定して送信する

一般的にメールは即時送信されるものですが、メールマガジンやマーケティング系のメールは時間を指定して送られます。Gmailでも、日時を指定して送信する機能があります。

blastengineでも、同様に日時を指定して送信する機能があります。各SDK毎に、実装方法を紹介します。

## JavaScript SDKの場合

JavaScript SDKを使ってメール送信日時を指定する場合は、以下のようにします。

```javascript
import { BlastEngine, Mail } from 'blastengine';
new BlastEngine('USER_ID', 'API_KEY');
const mail = new Mail;
mail
	.setFrom('admin@example.com', 'Admin')
	.setSubject('Test subject')
	.addTo('user@example.jp')
	.setText('メールの本文');
await mail.send(new Date("2024-05-10 12:00:00")); // 2024年5月10日12時に送信
```

## PHP SDKの場合

PHP SDKを使ってメール送信日時を指定する場合は、以下のようにします。

```php
use Blastengine\Client;
Blastengine\Client::initialize('USER_ID', 'API_KEY');

$mail = new Blastengine\Mail();
$mail
	->to('user@example.jp', array("name1" => "Test"))
	->from('admin@example.com')
	->subject('Test subject')
	->text_part('This is test email to __name1__');
$mail->send(new DateTime("2024-05-10 12:00:00")); // 2024年5月10日12時に送信
```

## Ruby SDKの場合

Ruby SDKを使ってメール送信日時を指定する場合は、以下のようにします。

```ruby
require 'blastengine'
Blastengine.initialize api_key: 'API_KEY', user_name: 'USER_ID'
mail = Blastengine::Mail.new
mail.from email: 'admin@example.com', name: 'Admin'
mail.addTo email: 'user@example.jp', insert_code: { name1: "name 1" }
mail.subject = "Test email"
mail.text_part = "This is a test email __name1__"
mail.html_part = "<html><body>This is a test email __name1__</body></html>"
mail.send Time.new(2024, 5, 10, 12, 0, 0) # 2024年5月10日12時に送信
```

## Python SDKの場合

Python SDKを使ってメール送信日時を指定する場合は、以下のようにします。

```python
client = Blastengine("USER_ID", "API_KEY")
mail = Mail()
mail.subject('メールの件名')
mail.text_part('テキスト本文 __name__')
mail.from_address("admin@example.com", "Admin")
mail.to('user@example.jp', {'name': 'name 2', 'hash': 'bbbbb'})
mail.send(datetime.datetime(2024, 5, 10, 12, 0, 0)) # 2024年5月10日12時に送信
```

## Java SDKの場合

Java SDKを使ってメール送信日時を指定する場合は、以下のようにします。

```java
BEClient.initialize("USER_ID", "API_KEY");
BEMail mail = new BEMail();
mail.subject ="Test mail from blastengine";
mail.text = "Mail body";
mail.html = "<h1>Hello, from blastengine</h1>";
BEMailAddress fromAddress = new BEMailAddress("admin@example.com", "Admin");
mail.setFrom(fromAddress);
mail.addTo("user@example.jp");
try {
	mail.send(new Date(2024, 5, 10, 12, 0, 0)); // 2024年5月10日12時に送信
} catch (BEError e) {
}
```

## Google Apps Script SDKの場合

Google Apps Script SDKを使ってメール送信をキャンセルするには、以下のようにします。

```javascript
new BlastEngine('API_USER', 'API_KEY');
const mail = new Mail;
mail
	.setSubject('テストメール')
	.setText('本文 __name1__')
	.setFrom('admin@example.com')
	.addAttachment(Utilities.newBlob('Hire me!', 'text/plain', 'resume.txt'))
	.addTo('user@example.jp', {name1: 'Atsushi'});
mail.send(new Date("2024-05-10 12:00")); // 2024年5月10日12時に送信
```

## 使い方

使い方としては、各SDKともにMailクラスを利用します。そして、 `send` メソッドの引数に送信日時を指定します。そうすると、メールがバルクオブジェクトになり、送信時のステータスが `RESERVE` になります。後は指定日時になれば、メールが自動的に送信されます。

## まとめ

blastengineを使えば、メール送信日時を指定してメールを送信できます。これにより、メールマガジンやマーケティングメールの配信を効率化できます。ぜひお試しください。

[エンジニア向けメール配信システム「ブラストエンジン（blastengine）」](https://blastengine.jp/)
[Google Photos Library API] JavaでGoogleフォトのアルバム内のメディアアイテム(写真や動画)を削除する

Google Photos Library APIを使用して、
Googleフォトのアルバム内のメディアアイテム(写真や動画)を削除する方法
についてご紹介します。

削除可能なメディアアイテム(写真や動画)は
同じGCP認証、かつGoogle Docs API V1で作成したメディアアイテムのみです。

メデイアアイテムの作成方法は
[⧉[Google Photos Library API] JavaでGoogleフォトのアルバムを作成・更新する](https://qiita.com/doran/items/b5ecc7005f19fbf0a35a)
を参照ください。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Photos Library API(V1)] JavaでPhotos Library APIを使う](https://qiita.com/doran/items/8695e6007765ab5b382c)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[メディアアイテムを削除](#1-メディアアイテムを削除)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|

## 1. メディアアイテムを削除
指定したアルバムからメディアアイテム(写真や動画)を削除します。

### 1.1. スコープ
このAPIを実行するには、以下のスコープを指定してください。
```
https://www.googleapis.com/auth/photoslibrary
```
[⧉[Google Photos Library API(V1)] JavaでPhotos Library APIを使う(2.2. PhotosLibraryClientインスタンスを取得)](https://qiita.com/doran/items/8695e6007765ab5b382c#22-photoslibraryclientインスタンスを取得)
でスコープを指定してください。

### 1.2. 実行

```java
public static void main(String[] args) throws Exception{
    try(PhotosLibraryClient client = getPhotosLibraryClient()){
        client.batchRemoveMediaItemsFromAlbum("アルバムID",Arrays.asList("メディアアイテムID"));
    }
}
```
#### 1.2.1. HTTPリクエスト
POST:　https:\//photoslibrary.googleapis.com/v1/albums/{アルバムID}:batchRemoveMediaItems
が実行されます。

#### 1.2.2. クエリパラメータ
クエリパラメータはありません。

#### 2.2.2. リクエストボディ
リクエストボディはありません。

### 1.3. レスポンスの内容
成功した場合は何も返しません。
失敗した場合は例外を出力します。

<br>
<br>
おしまい。。
elasticsearchとopensearchの基本的な相違点

時々エンジニアからopensearchとは何か、elasticsearchとどのような関係があるのかと聞かれることがあります。[srest](https://srest.io)サービスためのデータ検索・ソリューションを調査中ので私の考えを伝えたい。
elasticsearchは、使ったことのない人の間でも広く知られている。一方、opensearchはあまり知られていない。
両方とも、大量の非構造化データの保存と検索機能を提供されてます。

### 歴史
elasticsearchは2010年に開発されたが、2021年にライセンスがオープンソースからより制限されたSSPLライセンスに変更された。

コミュニティを維持するために、AWSはelasticsearchをフォークし、opensearchというプロジェクトを作ることにした。

opensearchはバージョン7.10でフォークされ、それまでは完全な互換性がある。
2年経った今(この記事が書かれた時点で）、両システムには異なるAPIがいくつか存在する。

### ライセンス
フォークの主な理由はライセンスだった。
SSPLはオープンソースと言われているが、コードの使用方法に厳しい制限を設けているため、完全にオープンというわけではない。

### 管理社
両社ともよく知られている。AWSはクラウド・サービスのインフラ・エコシステムをすべて持っているので、もしあなたがAWSのサービスを利用しているなら、opensearchを利用するのは理にかなっているかもしれない。

### データ検索ツール
どちらも視覚化とデータ探索のためのツールである。あるものは別のものからフォークされたものなので、かなり似ている。主な違いは、elasticsearchの方が優れているプラグインの量である。

### インデックス管理
詳細は省くが、どちらもインデックスの包括的な管理方法を提供し、タスクの自動化も行っている。 違いは実装にある。

### パーフォーマンス
[最も信頼できる情報](https://www.elastic.co/blog/elasticsearch-opensearch-performance-gap)ではないかもしれないが、elasticsearchはかなり高性能のようです。経験では、どちらのプラットフォームもほぼ即座にパフォーマンスを発揮するので、それほど重要ではないかもしれない。

### コミュニティ支援
opensearchの方がコミュニティからの支持は厚いはずだが、コミット数やフォーク数、その他の指標を見るとelasticsearchの方が支持されている。
https://github.com/opensearch-project/OpenSearch
https://github.com/elastic/elasticsearch


### まとめて
同じ点を表にまとめたら

|| Elasticsearch | Opensearch |
| ---- | ---- | ---- |
|ライセンス| Server Side Public License (SSPL) | Apache 2.0 |
|管理社| Elastic NV  | Amazon Web Services (AWS) |
|データ探索ツール|Kibana|Dashboard|
|インデックス管理|Index Lifecycle Management (ILM)|Index State Management (ISM)|
|パーフォーマンス|さらに速い|超高速|
|コミュニティ支援|より優れたサポート|elasticsearchより少ない|

これは個人的な知識に基づいており、100％正確ではないかもしれない。技術的な違いもあるはずで、それは皆さんの使用ケースによって重要になるかもしれない。
【Python】pandasを利用してCSV列にあるJSON構造の中から、指定データを新規列へ取得する方法

# 概要
Pythonのpandasを利用して、CSVファイルの列にあるJSON構造のデータから、指定したものを取り出すコードを実装しました。

# サンプルコード
前提として、`sample_body`列の中にJSON構造のデータがあるとします。また、その中のデータは以下のようになっています。

```json
{
	"information": {
		"sample_no": "123456789",
        # ...略...
```

CSVファイルの一番左の列に、新規に`sample_no`という列を作成し、それに紐づく`123456789`という値を入れるコードが以下です。

pandasライブラリを利用して、`DataFrame`の各行からデータを抽出し、その値を新しい列としてDataFrameに追加しています。

```py
import pandas as pd
import json


def get_sample_no(row):
    sample_body = json.loads(row['sample_body'])
    return sample_body['information']['sample_no']

df_temp = df.apply(get_sample_no, axis=1)
df_temp.name = 'sample_no'

df = pd.concat([df_temp, df], axis=1)

df.to_csv(xxxx_csv_path_xxxx, index=False)
```

## 詳細

- `df.apply(get_sample_no, axis=1)`で、DataFrame（＝表のようなもの。後述）の各行に`get_sample_no`関数を適用します
    - `axis=1`は、関数を各行に適用、`axis=0`だと各列に適用することを意味します
    - 結果は、`df_temp`という新しいPandas Series（＝1列分のデータのようなもの。後述）に格納されます
- `pd.concat([df_temp, df], axis=1)`で、`concat`関数を使用して、2つのDataFrame（またはSeries）を列方向（`axis=1`）に結合しています
    - `axis=1`の指定により、`df_temp`は`df`の左側、つまり新しいDataFrameの最初の列に追加されます。これにより、CSVファイルの一番左の列に新規列を追加することができます。`concat`関数は、引数として与えられたリストの順序を保持したまま結合する関数
- `df.to_csv(xxxx_csv_path_xxxx, index=False)`で、CSVファイルに出力します
    - `to_csv`は、DataFrameの内容をCSVファイルとして出力するメソッド。出力するCSVファイルのパス名を指定します。また、`index=False`によりDataFrameのインデックス（行ラベル）をCSVファイルに出力しないように指定できます。デフォルトでは`True`なのでインデックスが表示される設定になっています

## 参考
上述のPandas Seriesについて。

> pandas でよく使われるデータ構造として1次元の Series（シリーズ）、2次元の DataFrame（データフレーム）があります。
> 表のようなものが DataFrame 、表の1列分のデータを抜き出したものが Seriesです。
> 引用元：https://docs.pyq.jp/python/pydata/pandas/series.html

こちらがより詳細に解説されています。

https://ai-inter1.com/python-series/

Pandasドキュメントはこちら

https://pandas.pydata.org/pandas-docs/stable/
Copilot for Microsoft 365で具体的に何ができるのか試してみる ～Word編～

# はじめに
Copilot for Microsoft 365がすごいらしい…ということで、具体的にどんなことができるのか試してみたので共有します。<b>～Word編～<b>

## この記事の対象者
- Copilot for Microsoft 365がWordで出来ることを知りたい人

<b>👇Power Pointで出来ることを知りたい人はこっち<b>

https://qiita.com/matoia/items/edf48f2fa8be51618360

## Copilot for Microsoft 365とは
- GPT-4をTeams、Word、Excel、PowerPoint、Outlookに組み込んで利用できる
- 生産性と創造性が高まる＆作業時間を節約できる（下図参照）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/75b309ca-2ad4-04f2-1e4d-4d8b31710f9a.png)
※ 上図は下記サイトから引用

https://news.microsoft.com/ja-jp/features/231124-copilots-earliest-users-teach-us-about-generative-ai-at-work/

# Copilot for Microsoft 365がWordで出来ること
大きく分けて下記の３つが出来ます。
①ドキュメントを作成する
②ドキュメントを編集する
③ドキュメントについて理解する（サイドバー）

## ① ドキュメントを作成する
### A. ユーザー指示だけ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/6b333aa3-a822-355b-c3f8-457f0ac57277.png)

### B. 別ファイルを参照
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/5b56e5e1-ac71-ac5d-516e-93b18dfad32f.png)

:::note warn
別ファイルはOne Driveの中に保存してください。ローカルだと参照できません。
:::

### C. 下書き直後の変更指示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/ecc830e5-5419-032b-b2c1-c54f2cf44b8a.png)

## ② ドキュメントを編集する
### A. 書き換え
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/b3445cee-e613-5d16-0c96-67ad3603be63.png)

### B. 表で可視化
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/c59d8278-0929-8e39-a22b-b94d8b123ffe.png)

## ③ ドキュメントについて理解する（サイドバー）
### A. 要約する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/ede55743-0479-80b9-b5bd-ff3e0a7d577b.png)

### B. 質問する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/be17686c-da59-d1ef-a6d6-39c5a6e59e30.png)

### C. テンプレを使う
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/740fdccb-39ea-0753-e2bc-49e0c73eb2c4.png)

### D. 補足
:::note info
サイドバーは確認しかできません（サイドバーを使って本文修正は出来ません）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/dc9236bf-8a0e-9e7e-68be-5cd27f34bfe7.png)
:::

# おわりに
WordのCopilotは使い方次第では使えるとは思いますが、もうちょっとこうなってくれたらなぁ・・・みたいなところがあるから、業務効率が大幅に改善するかというと、まだそうでもない気はします。

ただ、最近のMicrosoftのアップデートの勢いはすごいので、近いうちに改善されると期待して、ボチボチ使い続けてみます。
DirectConnectに直結していないVPCへ、オンプレサーバからアクセスする

# 1. はじめに

- 先日、[「DirectConnectに直結していないVPCからオンプレサーバへアクセスする」](https://qiita.com/mksamba/items/2fdba4154dc85be7a7f9)という記事にて、VPCからオンプレサーバ方向の通信(VPC-A内のOriginサーバ -> VPC-B -> DirectConnect -> オンプレのTargetサーバ)を実現する検証を行った。
- 追加の要件として、逆方向となるオンプレサーバからVPCへの通信(オンプレのOriginサーバ -> DirectConnect -> VPC1 -> VPC2(Targetサーバ)が発生したため、改めて構成を検証した。

:::note 
- 検討した構成は全て実機検証しているが、今回の記事は考え方をまとめるもので、具体的な手順のキャプチャなどは記載しない。
- もしかしたらよりよい接続方法などあるかもしれない。。
:::

# 2. 今回のネットワーク要件

- VPC-Aに接続されているVGWがDXGWに接続されている。
- オンプレに存在するOriginサーバから、DX及びVPC-Aを経由し、VPC-B内のTargetサーバにhttpアクセスしたい。(DXGWと直結しているVPC-AはCIDRが小さく、そこにはTargetサーバを立てられない、という制約あり)
- VPC-BのCIDRをDX網側に広報できない。(VPC-Bと重複するCIDRがDX網に接続されている別拠点に既に存在する、という制約あり)
- DXはホスト型であるため、TransitVifなどは使用できない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/6453c4ab-1a1b-3a82-f8e3-a0fac4994712.png)

# 3. 構成検討

- NLB及びPrivateLinkを用いて上記の要件を実現した(他の構成は思いつかず)。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/32c3ac63-5c31-fcb4-03bc-c562c98542d6.png)

## 設定内容
- VPC-B内にInternal NLBを作成。
    - NLBのIPは10.20.0.218。
    - TARGETのnginxインスタンス(10.20.0.196)のみを含むTargetGroupを作成しNLBに設定。
- Privatelinkを作成。
    - VPC-B内にInternal NLBに紐づくEndpoint Serviceを作成。
    - VPC-A内に上記のEndpoint Serviceと接続するEndpointを作成。EndpointのIPは10.10.0.11。
- VPC-AのSubnet(10.10.0.0/24)には dst: 10.0.0.0/24 target: VGW のRouteTableがある状態。

## 確認内容
- オンプレにあるOriginサーバから「curl 10.10.0.11」で、VPC Endpointを宛先とし、Privatelink及びNLBを経由して、Target(10.20.0.196)のnginxにhttpアクセスできることを確認。
- Targetのnginxのaccesslogで、アクセス元IPがNLBのIP(10.20.0.218)になっていることを確認。
- 留意点として、Privatelink経由でのNLBへのアクセスの場合、TargetGroupにおける「クライアントIPアドレスの保持」設定のON/OFFに関わらず、全てTargetサーバから見るとアクセス元IPはNLBのIPになり、OriginサーバのIPを判別することはできない。詳しくはこちらの記事「[Network Load Balancer (NLB) のソースIPアドレスに思いを馳せてみた](https://dev.classmethod.jp/articles/pondering-source-ip-address-of-network-load-balancer/)」を参照。
バリデーション

半角のみの入力を制限するバリデータ
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class HalfWidthValidator implements ConstraintValidator<HalfWidthOnly, String> {
    @Override
    public void initialize(HalfWidthOnly constraintAnnotation) {
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true; // null値は許可
        }
        return value.matches("[\\x00-\\x7F]+"); // ASCII文字のみを許可
    }
}

半角のみの入力を制限するアノテーション
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Constraint(validatedBy = HalfWidthValidator.class)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface HalfWidthOnly {
    String message() default "半角文字のみを入力してください";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

全角のみの入力を制限するバリデータ
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class FullWidthValidator implements ConstraintValidator<FullWidthOnly, String> {
    @Override
    public void initialize(FullWidthOnly constraintAnnotation) {
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true; // null値は許可
        }
        return !value.matches("[\\x00-\\x7F]+"); // ASCII文字以外を許可
    }
}
全角のみの入力を制限するアノテーション
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Constraint(validatedBy = FullWidthValidator.class)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface FullWidthOnly {
    String message() default "全角文字のみを入力してください";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
eXplainable AI (XAI): An introduction to the XAI landscape with practical examples (2020)

### eXplainable AI (XAI): An introduction to the XAI landscape with practical examples  (Rowan, 2020)

xAIに関するサーベイ．
なんというか当たり前のことばかりで、gistAIが返した内容が論文ンお内容に合っているのかなんとも。

https://dl.acm.org/doi/10.1145/3415263.3419166


#### Q:この論文の概要を教えてください
#### A:
この論文は、eXplainable AI（XAI）に関する包括的な紹介を提供しています。XAIは、人工知能システムがその行動や意思決定を合理化し説明できる能力を指します。論文では、XAIの重要性が強調されており、AIシステムが透明性と解釈可能性を持つことがなぜ重要なのかが述べられています。さらに、人間の知能と人工知能の間の主な違いや、AI技術の進化がどのように進行しているかについても言及されています。AI革命の中で機械知能がどのように進化しているか、そしてXAIがなぜ重要なのかについて、この論文は詳細に解説しています。


#### Q:この論文の主な貢献を3つ挙げてください．1500文字くらいで答えてください
#### A:
この論文の主な貢献を以下に示します：

**XAIの重要性の強調と普及促進**: この論文は、eXplainable AI（XAI）の重要性を強調し、AIシステムがその意思決定や行動を説明できる能力がなぜ重要かを明確に示しています。XAIの普及により、ユーザーはAIシステムの動作を理解しやすくなり、透明性と信頼性が向上します。さらに、XAIの普及は、AI技術の受容を促進し、法的および倫理的な懸念を軽減するのに役立ちます。

**人間とAIの知能の比較と相補性の強調**: 論文は、人間の知能と人工知能の間の主な違いを明確に示し、両者の相補的な性質を強調しています。人間の知能は直感、常識、判断力、創造性、信念、効果的なコミュニケーション能力に基づいており、一方、人工知能は高速な情報処理と大量のデータの迅速な理解能力を持っています。この比較により、人間とAIの両方が異なる強みと限界を持ち、さまざまなアプリケーションや領域で相補的に活用されることが示されています。

**AI技術の進化と将来展望の提示**: 論文は、AI技術の進化がどのように進行しているかを詳細に説明し、Deep Learningアルゴリズムなどの進歩がAIシステムの能力向上にどのように貢献しているかを示しています。さらに、AI技術の将来展望についても言及し、AI革命がどのように進化し、問題解決能力をどのように拡大しているかを読者に示唆しています。これにより、読者はAI技術の進化についてより深く理解し、将来のAIの可能性について洞察を得ることができます。

これらの貢献により、この論文はXAIの重要性、人間とAIの知能の比較、AI技術の進化と将来展望に関する洞察を提供し、AI分野における理解と進歩に貢献しています。


#### Q:この論文に書かれているXAIの限界と今後の課題はなんですか．
#### A:
この論文において、XAIの限界と今後の課題について以下のような内容が述べられています：

**モデルに依存しないアプローチの構築**: XAIの限界の1つは、モデルに依存しないアプローチの構築が必要であるとされています。現在のXAI技術は、特定のモデルやアルゴリズムに依存している場合があり、異なる種類のAIシステムに適用する際に課題が生じる可能性があります。したがって、モデルに依存しないXAIアプローチの開発が重要な課題となっています。

**説明の定義と生成**: XAIのもう1つの課題は、説明の定義と生成に関する問題です。説明は、人間が理解しやすく、解釈可能な形式で提供される必要があります。しかし、どのように説明を定義し、生成するかについては明確な基準が不足している場合があります。したがって、説明の定義と生成方法に関する研究が今後の重要な課題となります。

**人間が理解しやすい説明の生成**: XAIの課題の1つは、人間が理解しやすい説明を生成することです。AIシステムが生成する説明は、専門家と一般の人々の両方が理解しやすい形式で提供される必要があります。さらに、AIシステムにクエリを行うためのインターフェースや言語の開発も重要な課題となります。

**説明の効果の評価**: XAIの課題の1つに、説明の効果をどのように評価するかという問題があります。説明の効果を測定し、説明がユーザーの理解や信頼性にどの程度影響を与えるかを評価するための適切な指標や方法が必要です。説明の効果を評価するための基準やフレームワークの開発が今後の課題となります。

これらの限界と課題を克服するために、XAIの研究者や開発者はモデルに依存しないアプローチの構築、説明の定義と生成方法の改善、人間が理解しやすい説明の生成、説明の効果の評価方法の開発などに取り組む必要があります。これにより、XAI技術の進化と普及が促進され、AIシステムの透明性と信頼性が向上することが期待されます。

#### Q:今日のAI革命において、機械知能はどのように進歩しているのか？
#### A:
今日のAI革命において、機械知能は急速に進歩している。膨大なデータを活用してニューラルネットワークのような複雑なプログラムを学習させるディープラーニング・アルゴリズムの進歩が、その原動力となっている。これらのAIシステムは、顔の認識、会話文の書き起こし、金融詐欺の検出、囲碁やチェスのようなゲームでの人間棋士の敗北、自動運転車の実現、がん診断の支援など、目覚ましい能力を発揮している。AI技術の進化は、計算知能や問題解決能力において可能なことの限界を押し広げ続けている。

#### Q:この文書で強調されている人間の知能と人工知能の主な違いは何ですか？
この文書では、人間の知能と人工知能の主な違いをいくつか取り上げている：

**人間の知性**：
直感、常識、判断力、創造力、信念、効果的なコミュニケーション能力。
もっともらしい推論と批判的思考に頼る。
人間は誤りを犯しやすく、知識ベースも限られている。
脳内の情報処理は直列的で、コンピュータに比べて遅い。
人間は大量のデータを記憶保持するのに苦労する。

**人工知能**：
人間の行動や認知プロセスをシミュレートすることを目的とする。
人間の専門知識を取り込み、保存することに重点を置く。
速い応答時間と大量のデータを素早く理解する能力を提供。
常識」に欠け、「混合」知識の取り扱いに苦戦する可能性がある。
AIシステムの開発には高いコストがかかり、法的・倫理的な懸念が生じる可能性がある。
これらの区別は、人間と人工知能の双方に固有の長所と限界があることを強調し、様々な用途や領域において、これら2つの形態の知能が補完的な性質を持つことを強調している。