OmniAICreator/Qiita-1.07M huggingface dataset:
大規模アプリのテスト案件参画してみて

大規模アプリケーションテスト案件に参加した経験を通じて、 テストの重要性と複雑さ、そしてチームとしての連携の大切さについて多くを学びました。

**テストとは何か？**

「テスト」とは、開発されたアプリケーションが正しく動作するか、不具合がないかを確かめる作業のことです。  大規模なアプリでは、多くの機能が複雑に絡み合っているため、テストのプロセスもまた複雑になります。

**テストドライバーの活用**

まず、テストドライバーの役割が非常に重要であることを学びました。テストドライバーは、アプリの一部分だけを取り出してテストするためのツールです。これにより、アプリの全体像を見ながらも、特定の部分に注目してテストを行うことができます。これは、複雑なアプリの中で特定の問題を見つけ出しやすくするために非常に有用です。 テストドライバーを効果的に利用することで、より効率的で正確なテストが可能になります。

**テストプロセスの多層性**

大規模プロジェクトでは、小さな単位から大きな単位へと段階的にテストを行います。各段階で異なる種類のテストが行われ、それぞれに特有の課題があります。たとえば、単体テストでは個々の部品を、結合テストでは部品同士がうまく連携しているかを確認します。

**チームワークの重要性**

このような大規模プロジェクトでは、多くの人々が関わります。異なる専門知識を持つチームメンバーとの密なコミュニケーションは、問題の迅速な特定と解決に不可欠でした。定期的なミーティングや進捗報告を通じて、チーム内の情報共有を強化することが重要です。

**問題解決へのアプローチ**

大規模なシステムでは、小さな問題が大きな影響を及ぼすことがあります。そのため、問題を迅速に特定し、効果的に対処する能力が求められます。具体的なバグの例とその解決策についての洞察を共有し、他のプロジェクトチームにも参考になるよう努めました。

**あとがき**

まだまだですが、今回でテストへの知見が深まったと感じています。今回の経験が今後に活かされるように努力していきたいと思います。
【オススメ】初学者がAWS環境構築するときの最小構成

# はじめに

2023 年から AWS エンジニアとしてのキャリアを開始した、3 年目エンジニアの Kyonaka です。

この記事では、実務で使う AWS 技術を個人で学習するなら『これだけで十分！』という **AWS 環境の最小構成** を紹介します。

# 前提

- AWS アカウントを持っていること（無料利用枠があること）

:::note info
AWS アカウントを持っていない人／無料利用期間をすぎてしまっている人は、以下 URL から新規アカウント作成しましょう。
:::
https://aws.amazon.com/jp/register-flow/

# AWS 環境の最小構成

私がオススメする AWS 環境の最小構成は以下の図のとおりです。

![](https://i.gyazo.com/775940c1165bd60b0ba17dd3705226ed.png)

- VPC の中に、一つのパブリックサブネット
- インターネットゲートウェイとルートテーブル
- パブリックサブネットの中に、一つの EC2 インスタンス(t2.micro)
- EC2 インスタンスへの SSH 接続のみを許可するセキュリティグループ

実際の現場では、パブリックサブネットに配置した踏み台サーバ経由でプライベートサブネット内の EC2 インスタンスへ接続することがほとんどですが、 そのために必要となる NAT ゲートウェイは **『無料利用枠の対象外』** となるため、今回の構成から除外しています。

https://aws.amazon.com/jp/vpc/pricing/

:::note info
EC2 インスタンスへ SSH 接続することで、以下のような技術を学ぶことができます。
- CLI での CloudWatch メトリクスの取得方法
- EBS ボリュームの拡張方法　など
:::

# さいごに

以前に独学で AWS の個人アカウントを作成して、無料枠内で色々触ってみたことがありました。

- VPC 作成から始まり、パブリックとプライベートのサブネット構成
- 踏み台サーバ経由でプライベートサブネット内の EC2 インスタンスへの接続
- RDS(リレーションデータベースサービス)のセットアップと接続
- ロードバランサーの構築

ただ、AWS エンジニアとしてのキャリアが始まってから感じたのは、 **『一から AWS 環境構築することはほとんどない』** ということです。

今まで学習したものが全く無駄だったということではなく、**『はじめてアサインされる現場は、「サービスの運用、監視、保守業務」がメインになる可能性が高い』** ということを想定した学習ができていませんでした。

AWS 環境を構築することが学習目的ではなく、あくまでも実務で必要な技術を学ぶために必要な手段であることに気付かされました。

今後は、AWS エンジニアを目指す人に向けて、実務で役立つ技術を発信していきたいと思っています。
ぜひ、参考になれば嬉しいです。
xサーバーのsmtpサーバーを使ってlaravelからメール送信

やりたい事。
xサーバーのsmtpサーバーを使ってメールを送信したい。


## xサーバーでメールアドレス作成

![スクリーンショット 2024-02-02 133110.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3686263/f6ec7e02-378c-3406-b78c-c3f217eb7967.jpeg)




![スクリーンショット 2024-02-02 133415.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3686263/e99491ab-ec81-5909-9eb4-781496d04d35.jpeg)


## .env編集
```
MAIL_MAILER=smtp
MAIL_HOST= ⓷ sv*****.xserver.jp
MAIL_PORT=465
MAIL_USERNAME= ⓶ ****@mail.com
MAIL_PASSWORD= ⓵ ****
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="⓶ ****@mail.com"
MAIL_FROM_NAME="送信者名"
```

MAIL_FROM_ADDRESSに他のアドレスを入れると偽装メールとしてGmailなどで弾かれる。


## コントローラー
```php
use Mail;

//...
        // 基本形
        Mail::raw('本文', function ($message) {
            $message
                ->to('atesaki@mail.com')
                ->bcc('bcc@mail.com')
                // ->from('sender@mail.com') //偽装メールとしてgmailで弾かれる
                ->subject('タイトル');
        });

        // functionの中で変数を使う
        $email = 'atesaki@mail.com';
        $title = 'タイトル';
        Mail::raw('本文', function ($message) use ($email, $title) {
            $message
                ->to($email)
                ->subject($title);
        });

        // bladeテンプレートを使う
        $paramToTemplate = ['item1'=>'apple', 'item2'=>'cat'];
        Mail::send('mail.template', $paramToTemplate, function ($message) {
            $message
                ->to('atesaki@mail.com')
                ->subject('タイトル');
        });
});

```

送信元（from）を変えると送信元偽装でGmailなどで弾かれます。
弾かれない為にはいろいろ設定が必要なのでまた別記事で。
2024年2月 AIOps 定点観測

# 概要
AIOps の動向や学習のため、Google で AIOps を検索した結果を記録している記事です。

# 2024年2月2日の検索結果 (リスティング広告)

![20240202_AIOps_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345504/0c51d7f8-9458-76a5-7867-f6b267b17898.png)

* ServiceNow
* Splunk
* IBM
* Dynatrace

ServiceNow がトップで Splunk と IBM が続いています。

先月の結果はこちら --> [2024年1月 AIOps 定点観測](https://qiita.com/mkodera/items/77fdfc6656fbbe336502)

# 2024年2月2日の検索結果 (広告以外)

![20240202_AIOps_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345504/28920c28-4142-a038-a105-04eecb86314d.png)

* HPE
* Splunk
* 日立製作所
* AWS
* IBM

HPE がトップで Splunk と日立製作所が続いています。AWS の記事が初めて登場しました。

先月の結果はこちら --> [2024年1月 AIOps 定点観測](https://qiita.com/mkodera/items/77fdfc6656fbbe336502)
[JetpackCompose] 何かを開始する前にカウントダウンするアニメーション

# はじめに
* 今回は簡単なJetpackComposeのサンプルコードになります

# どのような内容か
* 5秒前からカウントダウンし、最後にCallbackが呼ばれる
* 数字はアニメーションで表示→消えるを繰り返してカウントダウンを行う

# 表示例
| | |
---|---
![スクリーンショット 2024-02-02 13.45.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58367/68eda617-cb5c-596d-08b3-31d0e7531a9a.png)|![スクリーンショット 2024-02-02 13.45.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58367/d5ee48e9-f31b-2f2d-e6ae-ebd8f0bce755.png)

# コード

```CountDown.kt
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun CountDown(
    onFinishedCountDownTimer: () -> Unit,
    modifier: Modifier = Modifier,
) {
    var count by remember { mutableStateOf(5) }
    LaunchedEffect(Unit) {
        do {
            delay(1_000)
        } while (count-- > 0)
        onFinishedCountDownTimer()
    }
    AnimatedContent(
        modifier = modifier.fillMaxSize(),
        targetState = count,
        label = "countDown",
    ) {
        Box(
            modifier = modifier.fillMaxSize(),
            contentAlignment = Alignment.Center,
        ) {
            Text(
                text = "$it",
                fontSize = 64.sp,
                color = Color.Black,
            )
        }
    }
}
```
【2024Q1】libvipsをDebian 12にソースからインストールする

## 要件

- [libvips](https://github.com/libvips/libvips) 8.15.1 をソースからインストールする
    - PNGの読み書きに[libspng](https://libspng.org/)を使用する構成とする
- OSはDebian 12 (bookworm)
  - Python 3系がインストールされているものとする（手元では3.9）

## 依存関係の準備

```bash
apt-get update
apt-get install -y \
curl \
build-essential pkg-config libglib2.0-dev libexpat1-dev \
libspng-dev

pip install --upgrade pip
pip install --user ninja meson
```

- `curl`
    - ソースをダウンロードできればwgetその他なんでも構わない
- `build-essential` `pkg-config` `libglib2.0-dev` `libexpat1-dev`
    - [必須の依存関係](https://github.com/libvips/libvips?tab=readme-ov-file#building-from-source)
- `libspng-dev`
    - [任意の依存関係](https://github.com/libvips/libvips?tab=readme-ov-file#optional-dependencies)
    - 今回はlibspngのみ
- `ninja` `meson`
    - ビルドに使用する
    - ユーザーインストールのため標準で `~/.local` にインストールされる
    - 環境によっては実行ファイルにパスが通らないことがある
        - `which ninja` `which meson` で値が返ってくるか確認する
        - 実行ファイルの場所は `find ~ -name ninja` 等で探せる
    - 古いバージョンで構わなければ `apt-get install ninja-build meson` でも入れられる

## ビルドとインストール

公式GitHubの[Releases](https://github.com/libvips/libvips/releases)からソースをダウンロードして展開する。

```bash
curl -OL https://github.com/libvips/libvips/releases/download/v8.15.1/vips-8.15.1.tar.xz
tar xf vips-8.15.1.tar.xz
cd vips-8.15.1
```

`meson setup` を実行する。

```bash
$ meson setup build-dir --prefix=/usr

（中略）

PNG load/save with libspng        : YES
PNG load/save with libpng         : NO
```

- `build-dir` はビルドに使用する任意のディレクトリ、なければ作成される
- `--prefix=/usr` はインストール先の指定（通常は `/usr` や `/usr/local` ）
- `libspng` が使用される設定になっていることを確認する
- `meson setup` を再実行する場合は `--reconfigure` をつける

設定に問題がなければビルド→テスト→インストールと進める。

```bash
cd build-dir
ninja
ninja test
ninja install
```

インストールが正常に終了したら状態を確認する。

```bash
$ which vips
/usr/bin/vips

$ vips -v
vips-8.15.1
```
Next.jsでGoogle Adsenseを設定したのに広告がでない

# はじめに

Google Adsenseの申請をしたのですが、つまづいたことがありネットではわからなかったのでまとめておきます

# 問題

Google Adsenseの設定をしたけど表示されない問題がおきました

# 解決方法

まず、Google Adsenseは申請が通っていないと広告が表示されることはありません

**申請が通っているかを確認しましょう**

そして、広告の表示が端末によってまちまちだったりしますが、これは時間経過とともに徐々に表示されるようになります

Next.jsで広告用のコンポーネントを入れることもできましたが、最終的には自動で入れる方式にしました(広告コンポーネントはエラーでうまくいきませんでした)

# おわりに

この内容が実はネットにはないので、すこし記事にしてだすだけでも価値になるかなと考えたのでまとめました
DOM  

## DOM（Document Object Model）
HTMLドキュメントをオブジェクトのように扱える仕組み。



### DOM操作の仕組み

ブラウザがHTMLファイルを読み込むと、自動的にDOMツリーを生成する
↓
DOMツリーが生成されると、documentオブジェクトが使えるようになる
↓
documentオブジェクトを使うと、JavaScriptでDOM操作ができる


### 主なメソッド4種類

#### 1  `getElementById()`
：HTML要素をidで取得する
(idは同じHTML内で1回しか設定できない固有の値なので、取得できるHTML要素も当然1つ)
```javascript
// HTML要素をidで取得し、中身を出力する
console.log(document.getElementById('first-list'));
```
#### 2  `getElementsByClassName()`
：HTML要素をclassで取得する(一覧でHTMLcollectionとして配列風に表示されるので1つずつ取り出したい場合はfor文を使う)
```javascript
// 複数のHTML要素を取得し、定数に代入する
const headings = document.getElementsByClassName('heading');
 
// 複数のHTML要素を1つずつ取得し、中身を出力する
for (let i = 0; i < headings.length; i++) {
  console.log(headings[i]);
 }
 ```
 結果↓
 ![スクリーンショット 2024-02-02 11.49.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/1f0f648e-ed8b-8f72-ae88-758f634154e0.png)


#### 3  `querySelector()`
：HTML要素をCSSセレクタで取得する（指定したCSSセレクタに**最初に合致した**HTML要素を取得する。最初の１つだけを取得）
```javascript
// HTML要素をCSSセレクタで取得し、中身を出力する（最初の1つ）
console.log(document.querySelector('h1'));
console.log(document.querySelector('#first-heading'));
console.log(document.querySelector('.heading'));
```
#### 4  `querySelectorAll()`
：HTML要素をCSSセレクタで取得する（指定したCSSセレクタに合致したHTML要素すべてを取得する。必要に応じてfor文を使う。）
```javascript
// HTML要素をCSSセレクタで取得し、中身を出力する（すべて）
console.log(document.querySelectorAll('.heading'));
console.log(document.querySelectorAll('li'));
```
戻り値はNodeListなので、`getElementsByClassName()`の時と同じように必要に応じてfor文を使う。
![スクリーンショット 2024-02-02 11.59.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/c97c3e5e-357f-6e33-669a-1ef0c5bd07cb.png)


#### 《まとめ》
該当する複数の要素を一括で取得したいとき
`querySelectorAll()`
`getElementsByClassName()`

該当する要素を1つ(固有の要素を1つ)取得するとき
`getElementById()`
`querySelector()`

### HTMLへの追加
1. createElement()メソッド：HTML要素を新しく作成する
1. textContent / innerHTMLプロパティ：HTML要素にテキストを追加する
1. appendChild()メソッド：作成したHTML要素を子要素として末尾に追加する
```javascript
// 新しくli要素を作成し、定数に代入する
const li = document.createElement('li');
// 作成したli要素にテキストを追加する
li.textContent = 'JavaScriptで新しく作成したリスト3';
// li.innerHTML = '<a href="#">JavaScriptで新しく作成したリスト3</a>';
// ul要素の末尾にli要素を追加する
document.querySelector('ul').appendChild(li);
```
![スクリーンショット 2024-02-02 12.25.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/6beccd87-40c2-fea7-37fd-3a93aee85284.png)
Pico Inky Pac に JPEG 画像を表示する

## Pico Inky パック

Raspberry Pi Pico / Pico W 用の2.9インチのモノクロ電子ペーパーの「Pico Inky パック」を購入して、使ってみていた。
![421546622_18412568902040327_3750609281171663144_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16491/172ad5cb-54a8-fb12-aa90-bd504fe7c0aa.jpeg)

綺麗な日本語フォントを入れるのは、容量的に無理そうだったので、JPEG画像として作ったものを表示させようと思った。
ネットを調べると jpegdec というライブラリーが有って、[簡単にできそうだった](https://github.com/pimoroni/pimoroni-pico/blob/main/micropython/modules_py/inky_frame.md#images--jpegs) のだが、どっこい単純にはいかなかった。
　試行錯誤の結果、できるようになったので、備忘録として投稿しておくことにした。

## 引っかかったところ
　ここから紆余曲折をダラダラ書くので、動くコードを早くみたい人は飛ばしてみてください。
### GIMP で作ったJPEGはだめだった
私はMacなのでJPEG画像を作るのに、GIMPでJPEGファイルを作って、それを表示させようとしたら ```RuntimeError: JPEG: could not read file/buffer.``` というエラーが出た。
ファイルが読めないということは、ファイルの置き場所？名前？など調べても解らなかった。
エラーメッセージをネットでググるとラズパイのフォーラムの記事に、こんな記述があった。
```Well.... looks like the issue was the images. I made them in GIMP. When I took a picture that was created in MS Paint I had no issue.  :x```
しょうがないので、Windows の Paint アプリでモノクロの画像データを作成して読ませてみたら、読み込はできたようだった。
　```not read``` というエラーメッセージに惑わされた...
 
### サンプルのコードは別のデバイス用だった
ネットで見つけた jpegdec のサンプルコードは、他の電子ペーパー用のものだったらしく、Inky には合わないのだった。
Pico Inky で JPEG を表示するサンプルコードは見つからなかった。
あちこちのサンプルからそれらしい部分をコピペして、最終的に表示できた。
やったー！
![IMG_9699.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16491/9b99d303-968b-7bcc-cc98-60a1a9d7122b.png)

## うまく動作したソース
ちゃんと動作したソースコードはこちらです。
```python:DisplayJPEG.py
# Display an image on a pimoroni Pico Inky
# -ynomura.com 2024
from picographics import PicoGraphics, DISPLAY_INKY_PACK
import jpegdec

# Create instances fpr Inky
display = PicoGraphics(DISPLAY_INKY_PACK)

# Create a new JPEG decoder for our PicoGraphics
j = jpegdec.JPEG(display)

# Open the JPEG file
j.open_file("imf_logo.jpg")

# Decode the JPEG
j.decode(0, 0, jpegdec.JPEG_SCALE_FULL)

# Display the result
display.update()
```
できてしまえば、なぁんだこんなに簡単だったのか！でした。
![DJPEG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16491/39078305-b6ed-df95-bc3d-d606b3fee275.png)


### コメント、助言　大歓迎
試行錯誤の結果、とりあえず、動いた状態です。
誰かの参考になれば嬉しいのと、こんな方法もあるというコメントなどいただけると嬉しい。
pg_bigmをpostgres16系で使う

## 結論
パッケージには16対応版が入っていないが、masterブランチは16対応しているのでcloneして使う    

### 互換性確認
公式のニュース一覧を見ても16に対応している情報はない
https://pgbigm.github.io/pg_bigm/
16でのmakeを試みても失敗する

### PRを見てみる
https://github.com/pgbigm/pg_bigm/pull/5
https://github.com/pgbigm/pg_bigm/pull/6
上のPRでは16への対応がマージされている

### ソースをもってくる
パッケージからではなく、ソースをcloneしてビルドする方針で進める  
```
git clone https://github.com/pgbigm/pg_bigm.git
cd pg_bigm
make USE_PGXS=1 PG_CONFIG=/usr/local/pgsql-16.0/bin/pg_config 
make USE_PGXS=1 PG_CONFIG=/usr/local/pgsql-16.0/bin/pg_config install
```

make,make installまでできたのでcreate extensionできるか確認する
```
postgres=# select version();
                                                 version
----------------------------------------------------------------------------------------------------------
 PostgreSQL 16.0 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 11.4.1 20230605 (Red Hat 11.4.1-2), 64-bit
(1 row)

postgres=# CREATE EXTENSION IF NOT EXISTS pg_bigm;
CREATE EXTENSION
```
【Flutter】table_calendarウィジェットのヘッダーをカスタマイズする

table_calendarウィジェットのヘッダーをカスタマイズする方法について
あんまり情報が出てこなかったのでメモしておきます。

headerTitleBuilderを設定するだけで簡単に出来ました。

デフォルトUI：
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542326/6c337367-58c7-4708-d4c0-c2836a1180a0.png" width="450">

カスタマイズ後UI例：
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542326/8952e54d-6568-add0-7bfc-188c611db24b.png" width="450">


```dart:calendar_example.dart
TableCalendar(
    ...
    calendarBuilders: CalendarBuilders(
        headerTitleBuilder: (context, day) {
            // ここでカスタムヘッダータイトルを構築
            return Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  '${day.year}年${day.month}月',
                  style: TextStyle(
                    fontSize: 17.0,
                  ),
                ),
                const SizedBox(width: 8.0),
                Icon(Icons.list),
              ],
            );
          },
        ),
)
```
【Rails】namespaceで管理者と利用者ごとにcontrollerとviewをわけて処理を変える。

## はじめに
タイトルの通り、namespaceを使って管理者(admin)と利用者(user)でコントローラーとビューをわけたいと思います。
利用者に公開する画面と管理者に公開する画面は別々で、管理者だけがアクセスできる処理を作成するなどよくあることだと思います。
なのでこのような記事は調べれば沢山でてきますが、勉強のためアウトプットを兼ねて投稿したいと思います。
説明を省略する箇所が多いかもしれませんので、深く理解したいかたは他の記事をみることをおすすめします。

## namespaceとは
namespaceは名前空間とも呼ばれており、簡単に言うとコントローラーやモデル、ビュー、ルーティングなどをグループ化するために使用される仕組み。

## namespaceの使い方
商品一覧を表示するurl`/items`があるとします。
### ルーティング
~~~ruby
Rails.application.routes.draw do
  resources :items
end
~~~
通常だとこのようなルーティングを設定することが多いと思いますが、この状態だと管理者(admin)と利用者(user)が同じコントローラーやviewを使用することになります。
今回、管理者と利用者でコントローラーなどをわけたいのでnamespaceを使ってルーテイングをわけたいと思います。
~~~ruby
Rails.application.routes.draw do
  ## 利用者
  namespace :user do
    resources :items
  end

  ## 管理者
  namespace :admin do
    resources :items
  end
end
~~~
これでnamespaceによるルーテイングのグループ化が完成です。
urlは以下のような感じになります。
`user_items GET    /user/items(.:format)                                                                           user/items#index`
`admin_items GET    /admin/items(.:format)                                                                           admin/items#index`
`/items`の前にそれぞれ　`admin/`や`user/`がつくようになります。
adminとuserだけであればuserもグループ化する必要はないかもしれません。

## controllerとviewの作成
namespaceを使用する場合は、コントローラーやビューはurlと同じディレクトリ構成にする必要があります。
adminを例にすると、urlは
`admin/items#index`
のようになっているので、adminディレクトリの下にitemsコントローラーを作成する必要があります。
そこで以下のようにディレクトリを指定してコントローラーを作成すると、adminディレクトリの下にコントローラーやviewなど作成してくれます。
~~~:ターミナル
 $ rails g controller admin/items
~~~
同様にuserもコントローラーを作成して、これで管理者(admin)と利用者(user)によってcontrollerとviewをわけて処理を変えることができます。
注意点としてnamespaceを利用するとform_withやlink_toなどを使用する時は、namespaceを考慮する必要があります。説明は省略しますが調べると記事はたくさん出てくると思います。

## 参考させていただいた記事
https://zenn.dev/sudoukky/articles/731c87c9da80a5
https://ac-creative-lab.net/rails-divide-admin-and-public-using-namespace-and-module/
https://qiita.com/mmaumtjgj/items/77bef3b8ef0ee9a3cbee
https://qiita.com/haruki25596/items/3dec9ec57e4d34742022
【ChatGPT有＋DALL-E3】『面倒なことはChatGPTにやらせよう』という本の画像編集を使ってみた。


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

　今回は、新しい書籍『面倒なことはChatGPTにやらせよう』という本の中にあった画像編集を使ってみました。

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

　『面倒なことはChatGPTにやらせよう』という本を購入しました。

　その中の画像編集を
　　使ってみました。

　正確には
　　Advanced Data Analysis
　　　あるいは、
　　　　Code Interpreterの
　　　　　機能になります。

　また、
　　ここでは、
　　　ライブラリを
　　　　使うことになります。

　やり取りをどうぞ。
***
***user***
ロボットを描いてください。

***ChatGPT***
![1706839863732.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/1b64ee12-0a41-2ea2-8962-c7982eab8b1e.jpeg)

***user***
この画像をmatplotlibでモノクロにしてください。

***ChatGPT***
![grayscale_robot.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/6429ee1f-04ea-214f-8519-42bea15aec24.jpeg)

***user***
この画像をmatplotlibでドット表示してください。

***ChatGPT***
![corrected_dot_representation (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/07e94d8b-7569-6034-f215-ef3ba3817b66.jpeg)

***user***
画像をmatplotlibでエッジを表示してください。

***ChatGPT***
![robot_edges.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/8c01df89-a1bd-0315-7e4f-0bddac87df3d.jpeg)

***user***
エッジ画像を白黒反転してください。

***ChatGPT***
![inverted_edges_again.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/7d434e64-d39b-0a1e-8110-19fd14cc4af3.jpeg)
***

　ここまで
　　画像を出してきました。

　でも、出した画像を
　　ふつうには、
　　　ダウンロードできません。

　そこで
　　ChatGPTさんに
　　　指示して、JPEGファイルを
　　　　作成してもらいます。

```Text:画像をJPEGでダウンロードする
表示した画像をJPEGで出力してください。
```

　JPEGでの出力を
　　選択したのは、
　　　ファイルサイズの
　　　　縮小が目的です。

　Qiitaへの
　　アップロードも目的ですが、
　　　スマホの容量を
　　　　温存するためでもあります。
***
　『面倒なことは～』は
　　このほかにも
　　　さまざまなノウハウが
　　　　書かれています。

　背表紙は
　　あまり専門書的な感じは
　　　ありませんでした。

　手に取り、
　　中を見て、
　　　目が丸くなりました。

　それだけの
　　事柄が書かれています。

　この本が
　　みなさんの創作意欲の
　　　糧になれば幸いです。

　今回は、ここまで。
Proxyサーバ × 踏み台サーバー × FileZilla

## やりたいこと
- 以下の図のような環境で、ファイル操作を行いたい
![環境.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3468893/e6c0f9b3-f4fa-c951-992c-61e14361c4ae.png)

- Windows環境であればWinSCPで完結できるが、Mac環境ではWinSCPが使えないため、FileZillaで対応する方法のメモ

## Step1．ローカルフォワードの設定
自PCの任意のポートを解放し、そこにアクセスすることで
Proxy経由　→　踏み台サーバ経由　→　対象サーバ
にアクセスするルートを構築する
コンソールを開き、以下のコマンドを実行する
~~~sh
# コマンドフォーマット
ssh -o ProxyCommand='nc -x [ProxyサーバIP]:[ポート] %h %p' -i [踏み台サーバ 認証ファイルのパス] -L [自PC 解放ポート]:[対象サーバIP]:[ポート] [踏み台サーバ ユーザ名]@[踏み台サーバIP]

#図の構成であれば以下のようなコマンドとなる
#自PCの解放ポートはなんでもよい
ssh -o ProxyCommand='nc -x 192.168.1.1:8080 %h %p' -i /Users/hoge/.ssh/keyfile -L 123:10.1.1.1:22 hoge@100.1.1.1
~~~~
必要に応じて、Proxyのユーザ/パスワードも併せて設定することとなる

## Step2．自PC ポート開放状態を確認
自PCで指定したポートが待ち受け(LISTEN)であるかを、以下のコマンドで確認する
リストが表示されれば、ポート開放は成功している
~~~sh
# sudo権限が行使出来ない場合は、確認不可のため次Stepへ
# コマンドフォーマット
sudo lsof -i -P | grep "LISTEN" | grep [解放ポート]

#図の構成であれば以下のようなコマンドとなる
sudo lsof -i -P | grep "LISTEN" | grep 123
~~~~

## Step3．FileZillaで接続
#### サイトマネージャ
以下の設定を行う
|項目|設定概要|
|---|---|
|プロトコル|［SFTP］を選択|
|ホスト|［自PCのIPアドレス or localhost］を設定|
|ポート|［自PCの解放ポート］を設定|
|ユーザ|［対象サーバのIPアドレス or ドメイン］を設定|
|パスワード|［対象サーバのパスワード］を設定|

![Login.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3468893/1d538f11-4ab3-9705-b8bd-185b6dc47d58.jpeg)

#### 編集＞設定＞汎用プロキシ
以下の設定を行う
|項目|設定概要|
|---|---|
|汎用プロキシタイプ|使用するプロキシに合ったものを選択|
|プロキシ ホスト|［ProxyのIPアドレス or ドメイン］を設定|
|プロキシ ポート|［Proxyのポート］を設定|
|プロキシ ユーザ|必要に応じて［Proxyのユーザ］を設定|
|プロキシ パスワード|必要に応じて［Proxyのパスワード］を設定|

![Proxy.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3468893/b9de81a6-be61-a8b6-06c1-08a6941e6e21.jpeg)

## 最後に
- MAC版のWinSCPをリリースして頂ければ、こんな面倒なことをしなくてすむのに（笑
rex0220 プラグインのスペイン語対応

kintone がスペイン語対応したということで、プラグインのスペイン語対応をchatGPT で行ってみます。

# 概要

kintone が2023年12月に、スペイン語対応したということで、rex0220 プラグインのスペイン語対応を検討します。

>[2023年12月版 主なアップデート 言語設定 スペイン語を選択可能に](https://kintone.cybozu.co.jp/update/main/2023-12.html#point3)

charGPT で、rex0220 プラグインの多言語対応用メッセージにスペイン語を追加します。
JavaScript のコードに、スペイン語対応を追加してくれるので楽ですね。

# rex0220 プラグインの多言語対応

rex0220 プラグインの多言語対応は、下記のようにメッセージを定義しています。

```.js
        M15MSG01: {
            ja: '選択',
            en: 'Choice',
            zh: '选择',
        },
        M16MSG01: {
            ja: '検索',
            en: 'Search',
            zh: '搜寻',
        },
        M16MSG02: {
            ja: '取得件数',
            en: 'Max Records',
            zh: '最大记录',
        },
        M17MSG01: {
            ja: '検索文字',
            en: 'Search string',
            zh: '搜索字符串',
        },
```

# chatGPT(3.5) によるスペイン語対応
単純に、「スペイン語対応のコードを追加してください」で追加されました。
いちいちメッセージを翻訳しなくてもよいので楽ですね。

![2024-02-02_11h02_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/601bd252-4596-8f79-f662-e691c80443b2.png)

![2024-02-02_11h03_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/4b8c4cbf-51b3-2bf7-7d12-91939894a2a4.png)

# フランス語とドイツ語、ロシア語、ラテン語、ルーマニア語、アラビア語も追加
スペイン語対応が簡単にできたので、いろいろ言語を追加してみます。

![2024-02-02_11h09_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/70802ed3-a6be-3908-736d-7fbff7bebe28.png)

言語によっては、メッセージ内にアポストロフィーがあるので指摘するとエスケープを入れてくれます。

![2024-02-02_11h09_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/654a4243-2997-dcc9-1625-cd94e4c51069.png)

# 各言語のメッセージに日本語の翻訳を追加

各言語のメッセージがわからないので、日本語のコメントを入れてもらいます。
わかりやすく言語の注釈もつけてくれました。

![2024-02-02_11h12_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/82b5d7b5-1b58-1071-6f12-bf555d80d25d.png)

大丈夫そうなので、他のメッセージもコメントを追加してもらいます。

![2024-02-02_11h15_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/762c6651-b48e-0c00-6dee-517808616989.png)

# まとめ
chatGPT で、簡単に多言語対応のコードが生成できました。
ただし、言語によってはメッセージが長くなり表示時にデザインが崩れる場合もありそうですので、調整も必要です。
PowerShellでシリアルコンソール


```posh
# 作:mori-oh
# コードは以下の記事をベースにした。
# https://qiita.com/yapg57kon/items/58d7f47022b3e405b5f3

# 制御文字の内、今回使う分だけ定義。

[char]$ETX = 0x03
[char]$LF  = 0x09
[char]$CR  = 0x0a
[char]$NAK = 0x15
[char]$ESC = 0x1b
[char]$DEL = 0x7F

# 入力からVT100シーケンスや制御文字に変換
function InputKeyParser([System.ConsoleKeyInfo]$key) {
	if($key.Modifiers -eq 'Ctrl' -and $key.Key -eq 'C' ) { $return = $ETX }
	elseif($key.Key -eq 'UpArrow')    { $return = "${ESC}[A" }
	elseif($key.Key -eq 'DownArrow')  { $return = "${ESC}[B" }
	elseif($key.Key -eq 'RightArrow') { $return = "${ESC}[C" }
	elseif($key.Key -eq 'LeftArrow')  { $return = "${ESC}[D" }
	elseif($key.Key -eq 'Home')       { $return = "${ESC}[H" }
	elseif($key.Key -eq 'End')        { $return = "${ESC}[F" }
	elseif($key.Key -eq 'Insert')     { $return = "${ESC}[2~" }
	elseif($key.Key -eq 'Delete')     { $return = "${ESC}[3~" }
	elseif($key.Key -eq 'PageUp')     { $return = "${ESC}[5~" }
	elseif($key.Key -eq 'PageDown')   { $return = "${ESC}[6~" }
	else { $return = $key.KeyChar }
	return $return
}

# 各個人の設定を入れる
$PORT = "COM5"
$BAUDOT = 115200
$PARITY = [System.IO.Ports.Parity]::None
$ENCORDING = "UTF-8"
$DTR = $false
$RTS = $false
$NEWLINE_TX = $CR
$NEWLINE_RX = $CR
$NEWLINE_DISP = $CR
$HANDSHAKE = [System.IO.Ports.Handshake]::None

# Ctrl+Cの無効化
[Console]::TreatControlCAsInput = $true

# 設定の適用
$SerialPort = New-Object System.IO.Ports.SerialPort ( $PORT, $BAUDOT, $PARITY )
$SerialPort.DtrEnable = $DTR
$SerialPort.RtsEnable = $RTS
$SerialPort.Handshake = $HANDSHAKE
$SerialPort.NewLine = $NEWLINE_DISP
$SerialPort.Encoding = [System.Text.Encoding]::GetEncoding($ENCORDING)
$NlConverter = { 
	param([System.IO.Ports.SerialPort]$sender, [System.EventArgs]$e)
	Write-Host -NoNewline ($sender.ReadExisting()).Replace( $NEWLINE_RX, $NEWLINE_DISP )
}
$DispEvent = Register-ObjectEvent -InputObject $SerialPort -EventName "DataReceived" -Action $NlConverter

# コンソールを開く
Write-Host -NoNewline "Enter Console. Exit Command is [Alt+Q]"
$SerialPort.Open()
$SerialPort.Write($NAK)
$SerialPort.Write($NEWLINE_TX)

# メインループ
while ($true) {
	if ( -not [Console]::KeyAvailable ) { continue }
	$keyInput = [Console]::ReadKey($true)
	if ( $keyInput.Modifiers -eq 'Alt' -and $keyInput.Key -eq 'Q' ) { break }
	$sendChar = InputKeyParser( $keyInput )
	$SerialPort.Write( $sendChar )
}

# 終了処理
$SerialPort.Write($NAK)
$SerialPort.Close()
Unregister-Event $DispEvent.Name
Remove-Job $DispEvent.id
Write-Host "`nExit Console."
[Console]::TreatControlCAsInput = $false
```


# 参考にしたページ

https://qiita.com/yapg57kon/items/58d7f47022b3e405b5f3

https://e-words.jp/p/r-ascii.html

https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
複数のboolean型の処理

- [ ] isA
- [ ] isB
- [ ] isC
- [ ] isD

上記のような複数のチェックボックスの条件を組み合わせて複雑な条件分岐を組む必要があったので、個人的メモ。

```js
// boolean変数をビットに変換
var condition = 
(isA ? 1 : 0) << 3 | (isB ? 1 : 0) << 2 | (isC ? 1 : 0) << 1 | (isD ? 1 : 0);

switch (condition) {
    case 0b1000:
        // isA && !isB && !isC && !isD
        break;
    case 0b1010:
        // isA && !isB && isC && !isD
        break;
    default:
        // その他
}
```
ビット型に変換することで、複数の条件が`0bABCD`という見た目でもわかりやすい形にかわるため、条件の整理がしやすくなった。
命名規則（〇〇ケース）の一覧 キャメル？スネーク？トレイン？

# はじめに
命名規則とは、例えば`myscript`という名前のファイルを作るとき、
**どのように`my`と`script`を区別するか** ということです。
- ハイフン`-`で区切る：`my-script`
- 大文字で区切る：`myScript`
などがあります。

それぞれ、〇〇ケースという名前で呼ばれます。
# 一覧
※多くの場合、「ファイル名」と「関数・メソッド名」の命名規則は同じであることが多い。
フレームワークを導入する場合はその限りではない。

| 規則名                     | サンプル        | 言語                                         | 語源                                                      |
|----------------------------|-----------------|----------------------------------------------|-----------------------------------------------------------|
| キャメルケース<br>（ローワーキャメル） | `myScript`        | JavaScript (変数・関数)                      | 大文字をラクダのコブに見立てている                        |
| パスカルケース<br>（アッパーキャメル） | `MyScript`        | Java (クラス)<br>C# (クラス)                | Pascal 言語をリスペクトした命名                          |
| ケバブケース              | `my-script`       | HTML<br>CSS (ファイル・クラス)               | 単語がハイフンで区切られる様子が、「串刺し」を連想するため  |
| スネークケース             | `my_script`       | Python (変数・関数)<br>Ruby (ファイル)       | 単語がアンダースコアで区切られる様子が「蛇」を連想するため |
| トレインケース             | `My-Script`       | 非一般的                                     | 非一般的な用語。列車のように連結された様子からだろうか    |
| フラットケース             | `myscript`        | URL                                          | 単語間に区切りがない状態から                              |
| アッパーケース             | `MY_SCRIPT`       | C (定数)<br>Java (定数)<br>SQL               | 全て大文字                                                |
| ドットケース               | `my.script`       | ドメイン名<br>パッケージ名                   | 単語がドットで区切られる様子から                          |
| バッキーケース             | `MyScript`        | 一般的ではない                               | キャメルケースやパスカルケースの単語の大文字の使用を指す  |
| ダブルアンダースコアケース | `__my_script  __`   | Python (特別なメソッドや変数)                | 特別な用途のために前後にダブルアンダースコアを使用する    |
| ハンガリアンケース         | `strName`<br> `iCount` | 古いプログラミング言語 | 変数の型を示す接頭辞をつける命名規則                      |
# おわりに
おそらくこれで全部なはず（2024-02-01現在）
他にもあったら教えてください！
Add custom applications to GNOME (make log files openable by less -R with double-click)

1. Write ~/.local/share/applications/xyz.desktop
1. Run update-desktop-database

There are quite many websites how to write .desktop eg https://devicetests.com/add-custom-app-launchers-ubuntu-dock or https://fostips.com/add-app-start-menu-ubuntu-linux/ .

For example, in my case, I needed to have log files openable by less -R, hence I needed to do:

```sh:lessR.sh
cat <<EOM > ~/.local/share/applications/less-R.desktop
# Put to .local/share/applications/less-R.desktop

[Desktop Entry]
Name=less -R
Comment=less with ansi sequence interpreted
Exec=less -R %F
Type=Application
MimeType=text/plain;
Categories=Utility;
Terminal=true
EOM

update-desktop-database
```

It took 5 years to my issue resolved, by my own...

----

アプリケーションを追加する(ログファイルをダブルクリック時に`less -R`で開けるようにする)
httpsでlocalhostにアクセスする

[local-ssl-proxy](https://www.npmjs.com/package/local-ssl-proxy)を使う

## 手順

1. アプリを3000番ポートで起動
1. `local-ssl-proxy`を起動（一時的な利用なら`npx`でok）
1. `https://localhost:3001/`にアクセス

```zsh
# local-ssl-proxyを3001番ポートで起動して3000番ポートに向ける
npx local-ssl-proxy --source 3001 --target 3000
```

これで`localhost:3000`に起動しているアプリにhttpsでアクセスできる

## 参考
- https://qiita.com/cress_cc/items/ba3d7112d36035f88749#%E5%8B%95%E3%81%8F%E3%81%AB%E3%81%AF%E5%8B%95%E3%81%8F%E3%81%8C%E6%AF%8E%E5%9B%9Essl%E8%AD%A6%E5%91%8A%E3%81%8C%E5%87%BA%E3%82%8B
- https://zenn.dev/nbstsh/scraps/1d5d6b571eb05f
[Oracle Cloud] 監査のログでvolume backup開始終了処理をチェックする

## はじめに

監査のログでbackup開始終了をチェックする

## 監査の画面へ

コンソールトップ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/cb45ec1f-a5fb-6116-901e-cb726bbf3004.png)

監視及び管理
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/1d9bd51c-ae69-9027-c545-e3834dfa3ba4.png)

監査
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/3e1aa3ff-98e2-0d3f-93e6-9af8609a7fb3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/4b21df94-eb60-3e03-95fc-56987a9f1bd6.png)


## バックアップの仕込み

ブート・ボリュームのバックアップをいくつか仕込んでおいた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/774c1503-817f-beb4-0fdd-cb011f5391b8.png)

## 監査ログの確認

例えば下記の検索条件であれば、bootvolumeの参照履歴が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/e91a34e1-7759-9c43-2176-e6edc66cb544.png)

今度はある程度、開始日・終了日間隔を大きめにとって、
「bootvolumebackup」などと入力すると、
createやdeleteのbegin,endなどの候補が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/7801307a-031e-a285-e115-4f3b214f4cd6.png)

「createbootvolumebackup」とすれば、この通り
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/8b4cac93-835c-3edc-36f2-98f2405f96ad.png)

リソースで、
manual20240131
を選択、
イベント・タイプで
com.oraclecloud.BlockVolumes.CreateBootVolumeBackup.begin
com.oraclecloud.BlockVolumes.CreateBootVolumeBackup.end
を選択するとこんな感じ
manual20240131は、手動で作成したバックアップだ
なお、endの時は、ユーザー、アクションは空っぽのようだ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/6635d940-f58c-fb6a-5a7a-05ab4306ded8.png)

リソース枠を空にするとこんな感じ
手動バックアップのほかに、自動バックアップのログも表示された
これらを見ると、バックアップ処理にどれぐらいの時間を要しているかが分かる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/bd24f74b-3dbd-b4d4-5c35-c71d80e8c409.png)
パルワールドのwindows鯖データsavをjsonに変換して中身を確認する

:::note alert
今回のツールはv0.16.0を利用しています。
バージョンによって使用方法が異なる可能性があるのでご了承ください
:::

# Pythonをインストールする
該当のツールはPython3.9以降をインストールする必要と表記されています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/73603cad-cef2-a12a-fbf3-887355c065ab.png)

### 下記からダウンロードします
https://apps.microsoft.com/detail/9NCVDN91XZQP?hl=en-us&gl=US

### Downloadボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/2d4ad4ce-0150-eef7-e3e3-66656dacfaba.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/034dec4a-5fb9-41df-8414-41e694e63937.png)
勝手にダウンロードが始まる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/263906b0-6d6b-25d9-c15d-88dcca1d2528.png)

### インストールされているか確認
ダウンロードが終わったら黒い画面が表示されるので閉じる
コマンドプロンプトで「python --version」と入力してインストールされていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/ad0b5ebf-6abc-604d-54d7-0a14fe6e9dac.png)

# ツールをダウンロード
下記のgithubからダウンロードします

:::note alert
今回は「v0.16.0」を使用しています。バージョンよって使用方法が異なる場合がございます
:::
https://github.com/cheahjs/palworld-save-tools

### 右のreleaseをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/d45895a0-4504-4610-d5ef-954690b01d80.png)

### 一番上の「palworld-save-tools-windows-v0.16.0.zip」をダウンロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/24bc7663-b2c7-21a4-99d8-db11af8df648.png)

### 解凍フォルダーの「convert.cmd」にjsonにしたいドラック＆ドロップする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/b24e638c-d4fb-7bfe-760f-9dd85c9e4f37.png)

同じフォルダーにjsonのファイルができているので、中身を確認する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/59e1f364-36db-7426-2b3b-99ceb5000509.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/84f6b06e-6e41-06a1-a3c5-9443892e66cf.png)


# 最後に
中身を変更してデータを修復する方法もあるようですが、検証できたら再度記事を書きたいと思います
ステージマネージャーを使いやすくする

# やったこと

## alt + ctrl + {1 ~ ５} でステージマネージャーのステージを切り替える

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184634/b499eeb5-66f2-71ab-4500-44a7bef2b694.png)

```
set currStageManagerMode to (do shell script "echo $(defaults read com.apple.WindowManager GloballyEnabled 2> /dev/null)") as integer
if currStageManagerMode is 0 then
	do shell script "defaults write com.apple.WindowManager GloballyEnabled -bool true"
else
	do shell script "defaults write com.apple.WindowManager GloballyEnabled -bool false"
end if
```

参考記事
https://zenn.dev/usagimaru/articles/1567803a51e812


## alt + ctrl + s でステージマネージャーの on offを切り替える

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184634/4a32792e-602e-ad65-efe4-0de42383bc29.png)

```
tell application "System Events" to tell process "WindowManager"
	tell list 1 of group 1
		-- 何番目か
		click button 1
	end tell
end tell
```

参考記事
https://forum.latenightsw.com/t/stage-manager-control-from-applescript/4303/3

# その他

ステージマネージャの設定はこんな感じにしています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184634/8bfcfc31-48c4-68c5-2ac6-7f9ac35dc8e7.png)


# 気になること

ショートカットを入力してからちょっとdelayがあるのが気になりますが、マウスで操作したりするよりは全然良いなと思うので、使ってみようと思います
CドライブにあるZIPファイルをDドライブに解凍するバッチファイル

:: PowerShell のコマンドを呼び出して解凍する。
:: 解凍先フォルダが存在しない場合は新たに作成してくれる。
:: パスワード付ZIPは標準コマンドでは解凍できない（7zipなどを使う必要がある）。

```bat:ExpandZip.bat
@echo off

:: 解凍するZIPファイル
set zipPath=C:\temp\hogehoge.zip

:: ファイル名（拡張子除く）取り出し（解凍先フォルダ名にするため）
for %%F in (%zipPath%) do (
    set BASE_NAME=%%~nF
)

:: 解凍先フォルダ（フォルダは勝手に作ってくれる）
set expandPath=D:\temp\%BASE_NAME%

:: PowerShellのコマンドで解凍　※［-Force］上書き
powershell Expand-Archive -Path %zipPath% -DestinationPath %expandPath% -Force

:: 解凍先を指定しなかった場合は、
:: カレントディレクトリ（このバッチファイルのある場所）に
:: ZIPファイルと同じ名前のフォルダで解凍される。
:: powershell Expand-Archive -Path %zipPath% -Force

:: 実行結果を確認
if %errorlevel% == 0 (
    echo 正常終了しました。戻り値：%errorlevel%
) else (
    echo 異常終了しました。戻り値：%errorlevel%
)

pause
```
---
＜参考サイト＞
[【バッチファイル】ZIPファイルを解凍(展開)する](https://batch-file.net/2022/06/01/%E3%80%90%E3%83%90%E3%83%83%E3%83%81%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%80%91zip%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E8%A7%A3%E5%87%8D%E5%B1%95%E9%96%8B%E3%81%99%E3%82%8B/)
Ruby ワンライナー 入門

## 前置き

### ワンライナー

手元で何かしたいときに，スクリプトを書くことがある．
自分の基準だと，

1. ワンライナー
2. Make
    - make がデフォルトインストールされている場合
3. プログラミング言語のスクリプト
4. プロジェクト

みたいな優先順位になることが多い．
必要となる速度，妥当性検証，再利用性みたいな部分でもこの順序で考えていそう．

### Ruby

今まで，Perl でやっていたけど，Ruby か別の言語にしようと思ったので，
今回のステップでは Ruby にする．[^next][^why]
[^next]: ネクストステップだと，型ありがいいかも？
[^why]: Perl を書ける人が少ないなどの理由がある．

## 準備

### パイプ

```shell-session
$ ruby -lpe 'do something for $_'
```

よくあるパターン

```shell-session
$ ruby -lne 'do something for $_'
```

あとよく使うオプション

- `-a`
    - スプリット(`$F = $_.split`) する
- `-F`
    - `$;`
    - フィールド区切り文字指定．正規表現．
- `-0`
    - `$/`
    - 行区切り文字指定．指定しないとヌル文字(`\0`)になる．`find -print0` のやつ．
    - `-0777` で全部読み込み

### 変数

よく使う変数は，

- `$_`
    - `Kernel.gets` メソッドの戻り値が自動的に入る．`-n` / `-p` で使う．
- `$/`
    - `Kernel.gets` メソッドの引数のデフォルト値．`-0` で指定できる．
- `$;`
    - `String.split` メソッドの第一引数のデフォルト値 `-F` で指定できる．
- `ARGV` / `$*`
    - 引数を取り出せる．
- `ARGF`
    - 標準入力 or 指定されたファイルを自動判定する仮想ファイル．

```shell-session
$ ruby -e 'p ARGV' a b c
["a", "b", "c"]
```

### 制御構造

- `BEGIN` / `END`
    - 最初か最後に実行するブロックを指定できる．
    - `-n` オプションの `while get; end` の中に入れたくないような処理を入れるのに使ったりする．
    - > BEGIN ブロックは、独立したローカル変数のスコープを導入しません。つまり、 BEGIN ブロック内で定義したローカル変数は BEGIN ブロックを抜けた後も使用可能です。

## Refs

https://docs.ruby-lang.org/ja/3.3/doc/spec=2frubycmd.html

https://docs.ruby-lang.org/ja/latest/method/Kernel/m/gets.html

https://docs.ruby-lang.org/ja/latest/method/String/i/split.html

https://docs.ruby-lang.org/ja/3.3/method/Object/c/ARGV.html

https://docs.ruby-lang.org/ja/3.3/method/Object/c/ARGF.html

https://qiita.com/Fuyutsubaki/items/b07ad4fb537c8b042b6a
[GAS + Line Notify] 保育園の登園メールが来ないときにLINE通知する

# きっかけ
娘が通っている保育園では、毎朝登園したときに登園通知がきます。
（保護者が登園時にタブレットでボタンを押す -> 連携アプリからPUSH通知とメールが来る）
ただ、仮に車に置き去り…なんてことがあれば、通知が来ないわけで。 **通知が来ないことに気づく** って私には難しいと思っていたんです。

そんな時、こちらの素晴らしいNoteをみて、これを応用したら **通知が来ないことの通知** を作れそうだなと思ったので作ってみました。

https://note.com/m316jp2/n/n284e29688ffd?sub_rt=share_h

# 準備
このあたりの準備が必要ですが、上記のNoteに詳しく記載があったので、ここでは省略します。
異なるのはスクリプトと、実行時間(毎分ではなく毎朝9~10時)くらいです。

- Gmailで登園メールにラベルを付ける。（今回は「保育園入室」というラベル）
- Line Notifyでアクセストークンの発行してLINEグループに紐づける。
- GoogleDriveからGoogle Apps Scriptを立ち上げる。

# Script
```javascript
const accessToken = '******************'; // LINE Notifyのアクセストークン

// 平日9時になっても保育園入室の通知がない場合、LINEに通知を送信する。
function sendNotificationOfNoEntry() {

   // 最新1件のスレッドのメッセージを取得
  const label = GmailApp.getUserLabelByName('保育園入室'); // ラベル名を指定
  const message = label.getThreads(0, 1)[0].getMessages()[0];
  
  // 当日の入室通知が既に来ている場合は何もせず終了
  let today = new Date();
  today.setHours(0, 0, 0, 0);
  if (today < message.getDate()) {
    console.log('既に入室メールが来ています');
    return 0;
  }

  // 当日が土日祝日なら何もせず終了
  if (isWeekend(today) || isHoliday(today)) {
    console.log('本日は土日祝日のため対象外です');
    return 0;
  }

  // LINEへ通知
  const options = {
    'method' : 'post',
    'payload' : {'message': '【緊急！】本日まだ保育園に入室していません。至急保育園に確認してください。'},
    'headers' : {'Authorization': 'Bearer ' + accessToken}
  };
  const result = UrlFetchApp.fetch('https://notify-api.line.me/api/notify', options);
  if (result.getResponseCode() === 200) {
    console.log('LINE通知が送信されました。');
  } else {
    console.log('LINE通知送信に失敗しました。', result.toString());
  }
}

// 当日が週末か
function isWeekend(targetDate) {
  const day = targetDate.getDay();
  return (day === 0 || day === 6)
}

// 当日が祝日か
function isHoliday(targetDate) {
  const calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');
  const startDate = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate(), 0, 0, 0);
  const endDate = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate(), 23, 59, 59);
  const events = calendar.getEvents(startDate, endDate);
  return events.length > 0
}
```

# 実行
とりあえずテスト送信してみたところ無事LINEに送信されました。簡単！
![tmp_1706835872106.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179992/a9d06ca3-514f-73da-c182-98f0b9812140.jpeg)
BtoB 業界の分類例

::: note
この記事は「[業界分類の基本](https://qiita.com/drafts/0528ac54a6547b5a36d0/edit)」の続きの内容になります。
:::

## BtoB とは
B to B、B2B（読み方：ビートゥービー）は、「Business to Business」の略で、企業同士がビジネスを行う取引を指します。これは、ある企業が他の企業に対して商品やサービスを提供するビジネスモデルを指します。

例えば、製造業者が他の企業に製品を供給する場合、それはB2Bの取引です。同様に、技術サービスを提供する企業が他の企業に向けてそのサービスを販売する場合も B2B ビジネスと見なされます。

## 生産財について
生産財とは企業がサービスを生産するために購入・使用する原料や部品、設備を指します。生産財は総合メーカから専業メーカーまで多様な企業が各々の事業領域でビジネスを行っており、広く共有されている業界区分が見当たりません。

## 生産財業界の分類例
この記事では 生産財業界の分類例として「ひとめでわかる産業図鑑＆業界地図」の目次を紹介します

https://gihyo.jp/book/2021/978-4-297-12297-3

### 第1章 原料・素材
- 鉄鋼
- 非鉄金属
- 化学(基礎・石油化学)
- 化学(電子材料)
- 化学(ファインケミカル)
- 繊維
- ガラス・セラミックス
- セメント・耐火物
- 紙・パルプ
- インキ・塗料
- 肥料・飼料

### 第2章 部品・資材
- 自動車部品(車体・内装・電装)
- 自動車部品(エンジン・駆動・制御)
- 電子部品(能動)
- 電子部品(受動)
- 電子部品(機構)
- 建材・土木資材
- 包装資材・容器
- 電線・ケーブル
- 産業機械部品
- ベアリング
- 工業用ファスナー・ばね
- バルブ・継ぎ手

### 第3章 機械・設備
- 医療機器・器具
- ネットワーク・通信機器
- FA制御・計測機器
- 分析・試験機器
- OA機器・業務端末
- 工作機械
- ロボット・成形機
- 半導体製造装置
- 建設機械・重機
- 造船・車両
- 航空・宇宙
- 工場設備・機械
- 水処理・リサイクル設備
- 重電・プラント設備
- 厨房・調理機器
- 冷凍・冷蔵設備
- 防犯・防災機器
- エレベータ・エスカレータ
- オフィス空間・什器
- 工業用ミシン
- 産業印刷機・プリンタ
- 製鉄設備・機械
- 鉄道・交通機械
- 機械式駐車場・プレハブ
- 紙幣・貨幣処理機
- 充填・包装機械
- 食品・医薬品製造機械
- 映像・音響機器

## まとめ
この記事では生産財の業界例を紹介しました。

## 参考文献
- ひとめでわかる産業図鑑&業界地図 改訂新版
https://gihyo.jp/book/2021/978-4-297-12297-3
初めてのシェルスクリプト

# シェルスクリプトの基本
## 何をするか
Linux系で使うコマンドを複数まとめて実行する。


## スクリプトファイルの作成
テキストエディタを使用して、.sh 拡張子を持つファイルを作成します。

### 宣言: 
スクリプトの最初の行には通常、#!/bin/bash を記述します。これは、スクリプトを実行する際に使用するシェルを指定します。

### 実行権限の付与
スクリプトファイルに実行権限を付与するためには以下のコマンドを使用します。
```
$ chmod +x script.sh 
```

### スクリプトの実行 
```
$ ./script.sh 
```

#### シェルを利用する場合について
`./ファイル名`は直接ファイルを実行する(つまり実行権限がないと出来ない)

これに対して`sh ./ファイル名`や`bash ./ファイル名`のようなファイルの中身を直接シェルに流す際は実行権限は要らない(catなどで読むことが出来ればシェルスクリプトを実行できてしまう)

##### シェルとは
人からカーネルに色々な命令するもの。
カーネルはコンピュータを実質操作する存在なので、
シェルは人とコンピュータの仲介役をしている。

シェルとして有名なのは
- .sh
- .bash


## エクササイズ
### シンプルなスクリプトの作成

スクリプトファイルの作成:

```
touch myscript.sh
```
スクリプトにコマンドを追加:
スクリプトファイル myscript.sh を編集して以下の内容を追加します。

```
#!/bin/bash
echo "Today's date is: $(date)"
echo "Your username is: $(whoami)"

echo "your home directory is : $HOME"


for i in {1..10}
do
    echo "Number $i"
done
```


スクリプトに実行権限を付与:

```
chmod +x myscript.sh
```


スクリプトの実行:
```
./myscript.sh
```
Incus: Ubuntu 24.04 を使う

## コンテナーのインストール

```bash
incus launch images:ubuntu/noble/amd64 ubuntu2404
```

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

```text
$ incus list
+------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
|    NAME    |  STATE  |         IPV4         |                     IPV6                      |   TYPE    | SNAPSHOTS |
+------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| debian12   | RUNNING | 10.158.98.239 (eth0) | fd42:16ef:86e0:dbd7:216:3eff:fe9e:32c (eth0)  | CONTAINER | 0         |
+------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| first      | RUNNING | 10.158.98.219 (eth0) | fd42:16ef:86e0:dbd7:216:3eff:fe8f:9dcf (eth0) | CONTAINER | 0         |
+------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| ubuntu2404 | RUNNING | 10.158.98.56 (eth0)  | fd42:16ef:86e0:dbd7:216:3eff:fee7:7975 (eth0) | CONTAINER | 0         |
+------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
```

## root のパスワードを設定

```bash
incus exec ubuntu2404  -- bash
```

```text
$ incus exec ubuntu2404  -- bash
root@ubuntu2404:~#
```

## login

```bash
incus console ubuntu2404
```

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

ubuntu2404 login:
```

## Login 後の設定

ユーザーの作成

```bash
adduser --uid 1200 uchida
gpasswd -a uchida sudo
```

パスワードなしで sudo を実行できるようにする

```bash
sudo visudo
```

```text
（省略）
%sudo   ALL=(ALL:ALL) NOPASSWD:ALL
（省略）
```

sshd のインストール

```bash
sudo apt install openssh-server
```

sshd の設定

```text:/etc/ssh/sshd_config
（省略）
PasswordAuthentication yes
（省略）
```

タイムゾーンの設定

```bash
sudo timedatectl set-timezone Asia/Tokyo
```

## ip アドレスでログイン

```text
$ ssh 10.158.98.56
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-35-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro
Last login: Tue Jun  4 09:16:23 2024 from 10.158.98.1
uchida@ubuntu2404:~$
```

## avahi-daemon のインストール

```bash
sudo apt install avahi-daemon
```

次のようにログインできるようになります。

```bash
ssh ubuntu2404.local
```
Atomic Simulation Environmentの使い方: 表面の作成

## ASEによる表面モデルの作成方法
### fcc111など、典型的な表面の作成
```python
from ase.build import fcc111
surf = fcc111("Cu", size=[3,3,5], a=3.2, vacuum=10.0)
```
* fcc100, fcc110, bcc100, bcc110, bcc111, fcc111, hcp0001が使える

### 一般的な表面の作成
```python
from ase.build import bulk, surface
bulk = bulk("Cu", "fcc", a=3.2)
surf = surface(bulk, (1,1,1), 5, vacuum=10.0)  # lattice, Miller indices, layers
surf = surf*[3, 3, 1]  # if you want to replicate
surf = surf.translate([0, 0, -10]) # if you want to shift
```

### CIF/POSCARをロードして表面を作る例
```python
from ase import Atoms, Atom
from ase.build import surface
from ase.visualize import view
from ase.io import read
from ase.io import write
bulk = read("1000053.cif") # or read("oldPOSCAR")
surf = surface(lattice=bulk, indices=(1,1,1), layers=5, vacuum=10.0)
surf.translate([0,0,-10.0+0.1]) # shift slightly for easier to view
view(surf*[5,5,1])
write("POSCAR", surf)
```

### 原子・分子を表面に吸着させる
* add_adsorbateを使う
```python
from ase import Atoms
from ase.build import fcc111, add_adsorbate

surf = fcc111("Cu", size=[3,3,6], vacuum=10.0)
mol  = Atoms("CO", [(0,0,0),(0,0,1.2)])
add_adsorbate(surf, mol, 1.6, position="ontop")
# slab, adsorbate, height, position=(0,0), offset=None, mol_index=0)
```

* `offset`はfloatでよい(e.g. `offset=(1, 1)`, `offset=(0.5, 0)`)。unit cellのfractional coordinateになっている
* メジャーなsurfaceに対してはstringでの吸着位置がある

| surface | available adsorption sites             |
|:--------|:---------------------------------------|
| fcc100  | ontop, hollow, bridge                  |
| fcc110  | ontop, hollow, longbridge, shortbridge |
| bcc100  | ontop, hollow, bridge                  |
| fcc111  | ontop, bridge, fcc, hcp                |
| hcp0001 | ontop, bridge, fcc, hcp                |
| bcc110  | ontop, shortbridge, longbridge, hollow |
| bcc111  | ontop, hollow                          |

### 表面の一部を固定した計算
* Atomsの`constraint`を設定することでPOSCARに原子固定情報が追加される
* ASEで表面を構築した場合、tagが自動的に設定されるのでこれと`ase.constraint.FixAtoms`を用いてconstraint条件を設定する(下記スクリプトの`constraints`)
  + adsorbateはtag=0, 表面層はtag=1など。深いほどtagの値が増える

* スクリプトの例
```python
from ase.calculators.vasp import Vasp
from ase.optimize import QuasiNewton
from ase.constraints import FixAtoms
from ase.build import fcc111

surf = fcc111(symbol='Pd', size=[2, 2, 4], a=3.9, vacuum=10.0)
constraints = FixAtoms(indices=[atom.index for atom in surf if atom.tag >= 3])
surf.constraints = constraints

# using ASE optimizer
calc = Vasp(prec='Normal', xc='PBE', encut=400.0,
            ibrion=-1, nsw=0, kpts=[2, 2, 1], potim=0.5)
surf.set_calculator(calc)
dyn = QuasiNewton(surf, trajectory='pd-relax.traj')
dyn.run(fmax=0.05)

energy = surf.get_potential_energy()
printf("Energy after relaxation: {energy} eV")
```
typeormでjoinせずに外部キーのIDを取得する方法

# 内容
typeormでjoinせずに外部キーのIDを取得する方法について説明します。

# version
typerom:0.3.19
DB:postgres:14.10

# 困り事
typeormのドキュメント
[Many-to-one / one-to-many relations](https://orkhan.gitbook.io/typeorm/docs/many-to-one-one-to-many-relations)
を参考にリレーションを貼ると、selectしたときにテーブルをjoinしないと外部キーのIDが取得できませんでした。

## entity
```js
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm"
import { User } from "./User"

@Entity()
export class Photo {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    url: string

    @ManyToOne(() => User, (user) => user.photos)
    user: User
}
```

```js
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm"
import { Photo } from "./Photo"

@Entity()
export class User {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    name: string

    @OneToMany(() => Photo, (photo) => photo.user)
    photos: Photo[]
}
```
## 実行
```js
import { AppDataSource } from "./data-source";
import { Photo } from "./entity/Photo";
import { User } from "./entity/User";

AppDataSource.initialize().then(async () => {
  // Users
  const user = new User();
  user.name = `name`;
  await AppDataSource.manager.insert(User, user);

  const photo = new Photo();
  photo.url = `url`;
  await AppDataSource.manager.insert(Photo, photo);

  const photoRepository = AppDataSource.getRepository(Photo);
  const photos = await photoRepository.createQueryBuilder("photo").getMany();
  console.log(photos);
});
```

### コンソール出力(selectの結果)
外部キーがuserIdが取得できません。

```
[ Photo { id: 1, url: 'url' } ]
```

## Join
UserとPhotoをJoinすれば取得できます。
```js
import { AppDataSource } from "./data-source";
import { Photo } from "./entity/Photo";
import { User } from "./entity/User";

AppDataSource.initialize().then(async () => {
  // Users
  const user = new User();
  user.name = `name`;
  await AppDataSource.manager.insert(User, user);

  // Photos
  const photo = new Photo();
  photo.url = `url`;
  photo.user = user;
  await AppDataSource.manager.insert(Photo, photo);

  const photoRepository = AppDataSource.getRepository(Photo);
  const photos = await photoRepository.createQueryBuilder("photo").innerJoinAndSelect("photo.user", "user").getMany();
  console.log(photos);
});
```
## コンソール出力(selectの結果)
外部キーがuserIdがUserのidとして取得できる。

```
[ Photo { id: 43, url: 'url', user: User { id: 43, name: 'name' } } ]
```

# 解決方法
[View Entities](https://typeorm.io/view-entities#complete-example)
に記載のある方法でリレーションを貼るとjoinせずに外部キーが取得できました。


## entity
Photoを以下のように修正

```js
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from "typeorm";
import { User } from "./User";

@Entity()
export class Photo {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  url: string;

  @Column()
  userId: number

  @ManyToOne(() => User)
  @JoinColumn({ name: "userId" })
  user: User;
}
```

### コンソール出力(selectの結果)
外部キー(userId)が取得
```
[ Photo { id: 11, url: 'url', userId: 11 } ]
```