OmniAICreator/Qiita-1.07M huggingface dataset:
【365日後にPredictive Master】大企業の平社員がAlteryx Weekly Challengeに挑む #006

## はじめに
こんにちは、積立お兄さんです。
大企業新卒３年目のAlteryx初心者です。
ひょんなことから「**365日後にPredictive Masterになる！**」という目標を掲げて、公式のWeekly Challengeにコツコツ挑戦しています。

この記事では、Alteryx歴3か月の平社員が、実務で生かせそうなノーコード分析力をどうやって身につけていくかを記録＆共有していきます。

- 目標：ETLツールを自在に使いこなせるようになる
- 対象読者：Alteryxを始めたばかりの方/Weekly Challengeの解説が欲しい方

---

## 今回のチャレンジ：Weekly Challenge #006
- タイトル：[Weekly Challenge #001：4月のクリプトアナリティクス] [LINK](https://community.alteryx.com/t5/%E3%82%A6%E3%82%A3%E3%82%AF%E3%83%AA%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA/%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8-6-4%E6%9C%88%E3%81%AE%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%A2%E3%83%8A%E3%83%AA%E3%83%86%E3%82%A3%E3%82%AF%E3%82%B9/td-p/399941)
- レベル感：中級者向け
- ゴール：入力データの暗号？を解読する。
- 入力
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/a52f8d56-c48e-4fc6-937c-b709789a4f82.png
">

---

## 解いた流れと使用ツール

### ワークフロー全体

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/1fdaabdf-d489-45ff-bce6-15d76e688961.png
">

### 処理の手順と解説
data列の各値は同じ文字数であり、n文字目の文字を見て最頻の文字を採用していくことで、あるメッセージが浮かぶようになっている。それを解読するために以下の手順でフローを構築した。
1. **フォーミュラツール**　：各行の文字数をカウントする（後の処理で使用する）

1. **行生成ツール**　　　　：data列の各文字列に対して、文字数分の行を作成する。index列を作成することで、data列の各値に対して、indexのn番目ごとに最頻がどれかを確認するための準備を行った。（日本語下手）

1. **フォーミュラツール**　：substring()を使用して、data列の各値に対して一文字ずつ抽出を行う。
substring(対象の文字列, 開始位置, 長さ)
対象文字列：[data]
開始位置：[index]-1
長さ：1
対象文字列はいわずもがな。開始位置は0対象文字列の0番目から指定する。今回の場合は、indexが1からスタートしているので、[index]-1とすることで１文字目から順番に１文字ずつ抽出するようにしている。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/bfbf72a6-a59f-49d4-b510-865b8b898191.png
">

1. **集計ツール**　　　　　：indexとsubstringでグループ化し、substringでカウントを行う。
各indexごとに最頻の文字を選択するため、各indexごとに各文字数をカウントする。 
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/b8413c74-f47e-4133-92ad-5746acd2c573.png
">

1. **ソートツール**　　　　：indexで昇順、Countで降順ソート。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/59d86e3c-d661-4cae-9793-e2214f3a8933.png
">

1. **サンプリングツール**　：indexでグループ化し、最初の1行目のみをサンプリングする。こうすることで、各indexの最頻の文字を抽出することができる。

1. **集計ツール**　　　　　：substring列を連結させる。

---

## 詰まったポイントとその解決

- **問題１：ある文字列から１文字ずつ抽出する方法がわからない**
→ フォーミュラツールのsubstring()を使用することで、１文字ずつ抽出することができる。
- **問題２：最頻の文字を抽出する方法がわからない**
→ 初め、集計ツールを使用して、その中の最頻モードを使おうとしたが、それだと１文字ずつ設定する必要があり、汎用性が無かった。
→ カウントしてソートし、その１番上の行を抽出するようにしたことで、シンプルで簡単になった。
---

## 結果と出力確認
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/b3739f02-8ea2-4e12-aa30-fba560a01edd.png
">

→正しい出力フォーマットで、指定要件を満たしていました！

---

## 今日の学び・振り返り

- **新しく覚えたツール**：フォーミュラツールのSubstring関数
- **工夫ポイント**：最頻の抽出方法（↑で解説済み）
- **実務への応用**：正直実務で使用するかはわからないです。ただ、文字を抽出する方法を知れた。

---

## 次回予告
次は【Weekly Challenge #007】に挑戦予定！
さらっと進めましたが、実は005をスキップしております。問題の意味が頭の悪い私にはわかりませんでした...

---
## タグ
`Alteryx` `weekly Challenge` `データ分析` `Predictive Master` `365日チャレンジ` `ノーコード`
素因数分解を用いた約数の個数の求め方

# 求め方


素因数分解を用いた約数の個数の求め方を解説します。

約数の個数を求めるために、どのように素因数分解を用いるのかというところですが、以下のことを利用します。

:::note info
自然数Nを素因数分解した結果が、$N = p^aq^br^c ...$のとき、Nの正の約数の個数は$(a + 1)(b + 1)(c + 1)...$ 個である。
:::

なぜ上記のことが成り立つのかということですが、まず自然数Nは素因数pをa個,素因数qをb個,...もつ数と言えます。
なので、自然数Nの約数は、素因数pをa個以下、素因数qをb個以下持つ数であるということも言えます。
これらの組み合わせの数は、pの指数は$(a+1)$通り、qの指数は$(b+1)$通り、...となるので、これらをかけると約数の個数が求められます。





例として、60の約数の個数を求めるためにこの方法を使ってみましょう。
$60 = 2^2 \times 3 \times 5$ というように60は素因数分解できます。
素因数2,3,5の指数はそれぞれ2,1,1なので、約数の個数は$(2 + 1)(1 + 1)(1 + 1) = 12$個と求められます。
実際に、60の約数の個数は12個です。(1,2,3,4,5,6,10,12,15,20,30,60の12個)

ここまでの内容でわかることは、素因数分解した結果がわかっていれば、約数の個数もわかるということです。。
ここからは、このことを使った問題の解き方について紹介していきます。







# 例題1

https://atcoder.jp/contests/abc052/tasks/arc067_a

$N!$の約数の個数を数えるのは大変ですが、$N!$を素因数分解した結果は簡単に求められるので、それをつかって約数の個数を計算します。

~~~C++
#include <bits/stdc++.h>
using namespace std; using ll = long long;

signed main(void){
  int n;
  cin >> n;
  vector<int> prime(1001, 0); //素因数の個数を記録する配列
  for(int i = 2; i <= n; i++){
    int x = i;
    for(int j = 2; j * j <= n; j++){ //xを素因数分解する
      while(x % j == 0){ //割り切れるなら
        prime[j]++; //個数を加算
        x /= j;
      }
    }
    if(x != 1) prime[x]++;
  }
  
  ll ans = 1;
  for(int i = 1; i <= 1000; i++){
    cerr << prime[i] << endl;
    ans *= (prime[i] + 1);
    ans %= 1000000007;
  }
  cout << ans << endl;
}

~~~



# 例題2

https://atcoder.jp/contests/abc383/tasks/abc383_d

この問題では、約数の個数はわかっているので、約数の個数を活かして数を求めます。

約数が9個の数はどのように素因数分解されるかを考えてみます。
約数が9個ということは、言い換えると $N = p^aq^b$ と素因数分解されるとき、$(a + 1)(b + 1) = 9$　であるということです。(9は3つの2以上の整数の積では表せない。)
$(a + 1)(b + 1) = 9$を満たす$(a + 1)$と$(b+1)$の組み合わせを考えてみると、
$a + 1 = 3, b + 1 = 3$
$a + 1 = 9, b + 1 = 1$
$a + 1 = 1, b + 1 = 9$
の3つだとわかります。

このことから、Nを素因数分解したときの結果が次のように表せるとき、約数が9個であるといえます。
$N = p^2q^2, p^8, q^8$
p^8とq^8は同じようなことを意味しているので、$N = p^2q^2, p^8$　と表せると約数が9個といえます。

ここまでのことがわかれば、全探索で答えが求められます。


~~~C++
#include <bits/stdc++.h>
using namespace std; using ll = long long; using ld = long double;

signed main(void){
  ll n;
  cin >> n;
  
  vector<ll> prime; //素数を記録する配列
  prime.push_back(2);
  for(ll i = 3; i < 1000000; i++){　//素数を配列に追加
    bool ok = true; //素数かどうか
    for(ll j = 2; j * j <= i; j++){
      if(i % j == 0){ //割り切れるか判定
        ok = false;
        break;
      }
    }
    if(ok) prime.push_back(i);
  }
  
  ll ans = 0;
  //p^2q^2について
  for(ll p = 0; p < prime.size(); p++){ //(p < q)
    if(prime[p] > 1500) break; //prime[p] > 1500 ならp^2q^2 > N
    for(ll q = p + 1; q < prime.size(); q++){
      ll num = prime[p] * prime[p] * prime[q] * prime[q];
      //p^2q^2で表せる数を計算
      
      if(num <= n){ //N以下なら
        ans++;
      }
      else break;
    }
  }
  //p^8について
  for(ll i = 0; i < prime.size(); i++){
    if(prime[i] > 40) break;
    ll num = 1;
    for(int j = 0; j < 8; j++) num *= prime[i]; //p^8を計算
    if(num <= n){
      ans++;
    }
  }
  cout << ans << endl;
}
~~~
無知がSylpheedの開発版をソースコードからインストールした話

# はじめに
この記事は、Ubuntu等を全く知らないガチ初心者が、なんとかSylpheedの開発版をソースコードをコンパイルし、インストールする手順をまとめたものになります。

:::note warn
注意
初心者の拙い文章になります。
:::

(詳しい手順がどのサイトからも見つけられなかったため、記録を残そうと思った次第です。
アドバイスございましたら、コメントいただけますと幸いです。)

# 経緯
Sylpheedの開発版(3.8beta1)をインストールする必要がありました。
しかし、下記ページより[Windows 版 (開発版、Windows 8 / 10 対応)]のインストーラー版、zipアーカイブ版をダウンロードしようとしたところ、「503 Service Temporarily Unavailable」となりダウンロードできませんでした。

https://sylpheed.sraoss.jp/ja/download.html

その為、[ソースコード (開発版)]より唯一ダウンロード可能なソースパッケージ(tar.gz)である「sylpheed-3.8.0beta1.tar.gz」を用いてインストールを行うことになりました。

# 参考サイト

https://sylpheed.sraoss.jp/doc/manual/ja/sylpheed-5.html#ss5.3

上記ユーザーマニュアルの[5.3 基本的なインストール方法]を参考にして、コンパイル、インストールを行いました。

# 手順

## 環境構築

1\. 「sylpheed-3.8.0beta1.tar.gz」を解凍
2\. 解凍後のフォルダで、ターミナルを管理者権限で起動
3\. WSLのインストール(Ubuntuディストリビューションをインストール)
`wsl --install`
4\. Cコンパイラをインストール
`sudo apt update`
`sudo apt install build-essential`
5\. glibインストール
`sudo apt update`
`sudo apt install libglib2.0-dev`
6\. GTK+2インストール
`sudo apt update`
`sudo apt-get install libgtk2.0-dev`
7\.CURLインストール
`sudo apt update`
`sudo apt-get install libcurl-dev`
`sudo apt-get install curl`
`sudo apt install libcurl4-openssl-dev`

## コマンド実行

上記サイト参考に、以下コマンド実行
1\.`sudo ./configure`
2\.`make`
3\.`sudo make install`

## ライブラリ設定
コマンド実行だけでは、権限等において自環境の設定が不足していて起動できなかったため、以下実行
* libsylpheed-plugin-0.so.1 の存在確認
`find /usr/local/lib -name "libsylpheed-plugin-0.so.1"`
`find /usr/lib -name "libsylpheed-plugin-0.so.1"`

ライブラリが /usr/local/lib にあった場合、以下実行。
* システムレベルで ldconfig を実行
システムが /usr/local/lib を認識するよう設定する。
/etc/ld.so.conf に /usr/local/lib を追加：`echo "/usr/local/lib" | sudo tee -a /etc/ld.so.conf`
ldconfig を適用：`sudo ldconfig`

## Sylpheed起動

ここまでやって、`sylpheed`をコマンド入力し実行すると、sylpheed起動することができました。(日本語での表示を試行錯誤したのですが、解決できず英語での表示となっております。:sob:)

## おまけ
Sylpheed 3.8beta1 (開発版)はOAuth2認証に対応とのことだったので、恐らく設定画面だと思われる所までの操作が以下かもしれないです。
1\.ターミナル起動
Windows PowerShellを実行か、エクスプローラー内で右クリックよりターミナルを起動
2\.Ubuntu起動
`wsl`と入力し実行
3\.Sylpheed起動
`sylpheed`と入力し実行
4\.メニュー選択
上部のメニューバーより、以下選択
`Configuration`→`Preferences for current account...`
5\.Account preferences内
画面が開いたら、`Send`ページを選択。
`Authentication`部分の`SMTP Authentication(SMTP AUTH)`にチェックを入れると、`Authentication method`より`OAuth2`が選択可能になりました。

:::note info
OAuth2.0認証について
開発途中であり、リフレッシュトークン等の機能は未実装のようです。
(以下リンク参照)
:::

https://www.sraoss.jp/pipermail/sylpheed-jp/2022-September/001437.html
[初心者]Expressでバックエンド環境を作る

今回はExpressの環境構築について初心者向けにまとめます。

# Node.jsとExpress
**Node.js**とは、JavaScriptを使ってサーバーを動かせるようにしたものです。
元々ブラウザの中で使っていたJavaScriptを、パソコンやサーバーの中でも使えるようにしたのがNode.jsです。簡潔に言うと、**JavaScriptでバックエンドも使えるようにしたフレームワーク**です。
また、Node.jsには**Express**というフレームワークがあります。Node.jsを使ってもサーバーは作れますが、**コードを短く簡単に書ける**ようにしたのがExpressです。

# Node.jsをインストール
Expressを使うには、まず、Node.jsをインストールする必要があります。
1. [Node.js公式サイト](https://nodejs.org/ja)にアクセス
2. **Node.js(LTS)** をクリックしてダウンロード
3. ダウンロードしたファイルを開いて案内に従ってインストール
    →特にこだわりがなければすべて「Next」を押してインストールまで進めましょう
4. 正しくインストールされたか確認
    ターミナル（コマンドプロンプト）を開いて、以下のコマンドを入力
    ```bash:bash
    node -v
    npm -v
    ```

    バージョンが表示されればOKです。

# プロジェクトフォルダを作ろう
プロジェクトに使うフォルダを作りましょう。そのなかでExpressのインストールを行います。
```bash:bash
mkdir [プロジェクト名]
㏅ [プロジェクト名]
```
[プロジェクト名]には好きな名前を付けましょう。

以下のコマンドを実行して、プロジェクトに`package.json`を作成します。
```bash:bash
npm init -y
```
プロジェクトフォルダに`package.json`が作成されればOKです。

# Expressをインストール
次に、Expressをインストールします。
```bash:bash
npm install express
```
これで`node_modules`フォルダと`package-lock.json`が作成され。Express.jsが使えるようになります。

#サーバーファイルを作ってみよう
プロジェクトの中に、`index.js`というファイルを作りましょう。
そして、`index.js`に以下のコードを書いてみましょう！
```js:index.js
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hello Express!');
});

app.listen(3000, () => {
  console.log('サーバーが port 3000 で動いています');
});
```

# サーバーを起動してみよう
ターミナルで以下のコマンドを実行します。
```bash:bash
node index.js
```

コンソールで以下のように表示されたら成功です。
```console
サーバーが port 3000 で動いています
```
ブラウザで`http://localhost:3000`にアクセスすると
「Hello Express!」と表示されます。

# まとめ
Node.jsとExpressについてと環境構築についてまとめました。Expressの環境が整えばシンプルなコードでサーバーを立ち上げることができます。ぜひ。手を動かしてコードを書いてみましょう。
次回には詳しくExpressのコードの書き方についてまとめていこうと思います。
【VBA】別ファイルの指定したシートを取り込む

```
Dim SS1log As String
Dim wbMoto, wbSaki As Workbook
Worksheets("任意のシート").Activate '貼り付け先のシートを指定するとよい
Set wbSaki = ActiveWorkbook  'データの貼り付け先の変数

Application.DisplayAlerts = False
   
SS1log = ThisWorkbook.Path & "\" & "SS1ログ.xlsx"  '取り込むデータファイル

Workbooks.Open fileName:=SS1log, ReadOnly:=True, UpdateLinks:=0 '取り込むデータファイルを読み取り専用で開きます
Set wbMoto = Workbooks.Open(SS1log)


wbMoto.Worksheets("Sheet1").Range("A:CC").Copy  '取り込むデータファイルのSheetからセルA:CCの範囲をコピー
    
wbSaki.Worksheets("SS1ログ").Range("A1").PasteSpecial xlPasteFormulasAndNumberFormats  '取り込み元　シート名「項目」A1から貼り付け
    
Application.CutCopyMode = False  'コピー切り取りを解除
    
wbMoto.Close False  '取り込み元のファイルを閉じる

Application.DisplayAlerts = True
【Google Cloud】リージョン外部アプリケーションロードバランサーでマネージド証明書を使ってHTTPS化する方法

# TL;DR
- GCPの **リージョン外部アプリケーションロードバランサー（External Managed）** でマネージド証明書を利用してHTTPS対応をするには、Googleマネージド証明書の作成 + CLI操作が必要
- GUIではフロントエンド構成を作成する際に、マネージド証明書の選択ができない
- フロントエンド構成(転送ルール（Forwarding Rule）)をCLIで作成する必要がある
# 実現したい構成
```
[ クライアント ] 
    ↓ HTTPS(マネージド証明書を利用)
[ リージョン外部アプリケーションロードバランサー ]
    ↓ HTTP
[ VM / Cloud Run / GKE など ]
```

# 実現方法
## 基本構成の構築(HTTP)
基本的に以下手順に沿って実施すればOK

https://cloud.google.com/load-balancing/docs/https/setting-up-reg-ext-https-lb?hl=ja

### 構築されるもの

- ネットワーク
    - VPCネットワーク
    - バックエンド用サブネット
    - ロード バランシング用に予約されているプロキシ専用サブネット：ロードバランサーを利用する際は専用サブネットが必要
    - Firewallルール：LBからのヘルスチェック、LBからバックエンド通信許可の為のルール
- Compute Engine(バックエンド)
    - VMインスタンス
    - インスタンスグループ：ロードバランサーからバックエンドを指定するときに必要
- Load Brancer（フロントエンド）
    - 静的IPアドレス：LBのIP固定化で利用
    - リージョン外部アプリケーションロードバランサー
        - フロントエンド構成(転送ルール)
        - バックエンド構成
            - ヘルスチェック
:::note warn
注意事項
手順の中にロードバランサーのフロントエンド構成を構築する手順があるが、マネージド証明書を利用する場合、GUIでの**選択肢にはマネージド証明書は出てこないので一旦、HTTPでフロントエンドを構成して**、後からマネージド証明書を作成してHTTPSでのフロントエンド構成を構築する
※フロントエンド構成が最低1つないと、LBは作成できない
:::

## マネージド証明書を利用してHTTPS化
参照の公式ページは以下

https://cloud.google.com/certificate-manager/docs/deploy-google-managed-regional?hl=ja

- 上記手順でURLマップを指定する箇所があるが、基本的にはロードバランサーと同じ名前で自動で作成されている、もしくはCLIを実行して確認する
  - コマンド： `gcloud compute url-maps list`

- 上記手順を実施すればマネージド証明書の作成とターゲットプロキシの作成までは行えるが、フロントエンドの構成(転送ルール)の作成は行えない、そのため、CLIから転送ルールを作成する必要がある

:::note warn
注意事項
マネージド証明書はGUIでは選択できないのでCLIで作成する必要がある。
:::

転送ルール作成するためのCLIコマンドは以下

https://cloud.google.com/sdk/gcloud/reference/compute/forwarding-rules/create

コマンド例
```bash
gcloud compute forwarding-rules create 転送ルール名 \
  --load-balancing-scheme=EXTERNAL_MANAGED \
  --network-tier=STANDARD \
  --address=xxx.xxx.xxx.xxx \
  --region=asia-northeast1 \
  --target-https-proxy=ターゲットプロキシ名 \
  --target-https-proxy-region=asia-northeast1 \
  --ports=443 \
  --network=VPCネットワーク名
```

# その他/感想
転送ルールとターゲットプロキシの関係は以下を参照

https://cloud.google.com/load-balancing/docs/target-proxies?hl=ja
Mac+RDP環境でStream Deckからパスワード自動入力する決定版【Hammerspoon活用】

# Mac+RDP環境でStream Deckからパスワード自動入力する決定版【Hammerspoon活用】

## 📝 背景と課題

MacからMicrosoft Remote Desktop（RDP）でWindowsに接続し、Stream Deckを使って定型パスワードを入力しようとしたところ、次のような問題が発生しました：

- **テキストを貼り付けようとしても `v` しか入力されない**
- **Ctrl+Vが通らない**

Windowsへのリモート接続時にパスワード入力を自動化したい場面は多いのに、なぜかうまくいかないケースがあります。

## ❌ 試したがダメだった方法

* Stream Deckの「テキスト送信」や「クリップボード貼り付け」機能
* Clipboard Buddy / Super Macro（Macでは動作しない）
* `⌘V` や `Ctrl+V` のショートカット送信（RDPが変換できず失敗）

## ✅ 解決策：**Hammerspoonで1文字ずつ「タイプ」する！**

RDPの問題を分析した結果：

* Mac上で `Ctrl+V` などの仮想キーはRDPにうまく渡らないことが多い
* ならば「貼り付け」ではなく「タイプする」方が確実
* Hammerspoonを使えば、Stream DeckのホットキーでMacから**仮想キーストロークを自動送信**できる

## 🛠️ 必要なもの

* **Mac**
* **Stream Deck（＋公式アプリ）**
* **Microsoft Remote Desktop for Mac**
* **Hammerspoon（無料）** - [https://www.hammerspoon.org/](https://www.hammerspoon.org/)

## ⚙️ 設定ステップ

### ① Hammerspoon の `init.lua` 設定例

```lua
-- init.lua

-- 業務用パスワード1
function typePassword1()
    local text = "example_password1" -- 実際のパスワードに書き換え
    for i = 1, #text do
        local c = text:sub(i,i)
        hs.eventtap.keyStroke({}, c, 0)
        hs.timer.usleep(80000) -- 入力速度調整（ミリ秒）
    end
    hs.eventtap.keyStroke({}, "return", 0) -- Enterキー送信
    hs.alert.show("🔐 パスワード1送信完了")
end

hs.hotkey.bind({"cmd", "alt", "ctrl"}, "p", typePassword1)

-- 業務用パスワード2
function typePassword2()
    local text = "example_password2" -- 実際のパスワードに書き換え
    for i = 1, #text do
        local c = text:sub(i,i)
        hs.eventtap.keyStroke({}, c, 0)
        hs.timer.usleep(80000)
    end
    hs.eventtap.keyStroke({}, "return", 0)
    hs.alert.show("🔐 パスワード2送信完了")
end

hs.hotkey.bind({"cmd", "alt", "ctrl"}, "d", typePassword2)

-- 起動確認
hs.alert.show("✅ Hammerspoon: パスコード送信準備OK")
```

### ② Stream Deck 側の設定

* 「ホットキー」アクションを使って、
   * `⌘` + `⌥` + `⌃` + `P`（パスワード1用）
   * `⌘` + `⌥` + `⌃` + `D`（パスワード2用）
* をそれぞれ割り当てる

## 🎉 実行方法

1. MacでHammerspoonを起動（アクセシビリティ許可必要）
2. RDPでWindowsを開き、テキスト入力欄にフォーカス
3. Stream Deckボタンを押す
4. 定型パスワードが自動入力 → Enter送信まで完了！

## ✅ メリット

| 特徴 | 内容 |
|------|------|
| 💡 シンプル構成 | すべて無料・軽量なツールのみで完結 |
| ✅ RDPでも確実に通る | キーストローク入力なので貼り付け制限も回避 |
| 🎮 Stream Deck対応 | ワンボタンで完結できる運用性の高さ |

## 🔐 注意点・セキュリティ対策

* 当然ながら、**パスワードをスクリプトに平文で書くことはセキュリティリスク**です
* 実運用では以下のような対策を検討しましょう：
  * パスワードを暗号化して保存し、実行時に復号
  * キーチェーンから安全に読み取る仕組みを追加
  * 定期的なパスワード変更に対応できるよう設計

## 🧩 応用例

* 複数の入力パターンを分岐させる
* スニペットやJSONファイルから定型文を読み込む
* `hs.chooser` を使ってGUIメニューにする
* 入力前に確認ダイアログを表示する

### 応用例：入力前の確認を追加

```lua
function typeSecurePassword()
    local button, _ = hs.dialog.blockAlert(
        "パスワード送信確認", 
        "パスワードを送信しますか？", 
        "送信", "キャンセル"
    )
    
    if button == "送信" then
        -- パスワード入力処理（上記と同様）
    end
end
```

## 📦 まとめ

| 課題 | 解決策 |
|------|------|
| Stream DeckからRDPに貼り付けできない | Hammerspoonでキーストローク送信に切り替え |
| Ctrl+Vが無効 | `hs.eventtap.keyStroke()`で回避 |
| 定型文を毎回打つのが面倒 | ボタン一発で入力完了！ |

## あとがき

同じように「Mac + RDP + Stream Deck」で入力自動化に困っている人に、少しでも参考になれば嬉しいです！特にRDP接続での貼り付けトラブルは意外と多いので、キーストローク送信という原始的だけど確実な方法が役立つかもしれません。

セキュリティと利便性のバランスを考慮しつつ、ぜひ自分の環境に合わせたカスタマイズを試してみてください。

タグ: Stream Deck, Hammerspoon, RDP, Mac, 自動化

投稿者：もあい
更新日：2025年5月1日
RDP に Ctrl+V が通らない？Mac から自動入力する最適解【Hammerspoon × Stream Deck】


# Stream Deck × Mac × RDPでパスワードを自動入力する最小構成メモ【Hammerspoon活用】

## 📝 はじめに

MacからRDP（Remote Desktop Protocol）を使ってWindowsを操作している方、そしてStream Deckを併用して効率化したい方へ。  
**「Stream Deckのホットキーで定型文を送信したいのに、RDP先ではうまく入力されない」**という問題、経験ありませんか？

本記事では、その問題を**完全無料で安定解決できる構成**を紹介します。

---

## 🧨 よくある問題

Stream Deck で以下のような操作をしたくても、RDP環境では失敗します：

- 「テキストを入力」アクション → `aaaaaa` のように変換される
- クリップボード貼り付け（Ctrl+V） → `v` しか入力されない
- Macのショートカット（⌘V） → そもそも通らない

**原因：Macのキー送信がRDP経由で正しく解釈されない／貼り付けが制限されている**

---

## ✅ 解決アプローチ

### ✔️ Hammerspoon を使って「1文字ずつキーストローク入力」させる

- 「貼り付け（ペースト）」ではなく、「タイプ（打鍵）」させる方式
- `hs.eventtap.keyStroke()` を使ってキーボード入力を仮想的に送信
- Stream Deckのホットキーと連携して、ボタン一発で自動入力

---

## 🛠️ 必要なもの

| ツール | 説明 |
|--|--|
| Mac | 通常のmacOSでOK |
| Microsoft Remote Desktop | App Store版（最新版を推奨） |
| [Hammerspoon](https://www.hammerspoon.org) | 自動化スクリプトツール（無料） |
| Stream Deck | 任意のモデル＋公式アプリでOK |

---

## ⚙️ init.lua の設定例（Hammerspoon）

```lua
-- samplePass1 を送信（⌘⌥⌃ + P）
function typePassword1()
  local text = "samplePass1"
  for i = 1, #text do
    local c = text:sub(i,i)
    hs.eventtap.keyStroke({}, c, 0)
    hs.timer.usleep(80000)
  end
  hs.eventtap.keyStroke({}, "return", 0)
  hs.alert.show("🔐 サンプルパスワード1送信完了")
end
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "p", typePassword1)

-- example123 を送信（⌘⌥⌃ + D）
function typePassword2()
  local text = "example123"
  for i = 1, #text do
    local c = text:sub(i,i)
    hs.eventtap.keyStroke({}, c, 0)
    hs.timer.usleep(80000)
  end
  hs.eventtap.keyStroke({}, "return", 0)
  hs.alert.show("🔐 サンプルパスワード2送信完了")
end
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "d", typePassword2)

hs.alert.show("✅ Hammerspoon: パスコード送信準備OK")
```

---

## 🎮 Stream Deck 側の設定

1. Stream Deck アプリで「ホットキー」アクションを選択
2. 例：
   - `⌘` + `⌥` + `⌃` + `P`（パスワード1）
   - `⌘` + `⌥` + `⌃` + `D`（パスワード2）

---

## 🚀 実行方法

1. `init.lua` を保存し、Hammerspoonを起動・Reload Config
2. macOSの「アクセシビリティ」許可を与える
3. RDPのWindows側でテキスト欄をアクティブにしておく
4. Stream Deckのボタンを押す
5. → パスワードが1文字ずつ入力 → Enterキーも自動送信！

---

## ✅ この構成のメリット

| 項目 | 内容 |
|--|--|
| 貼り付け失敗の回避 | Ctrl+Vが効かないRDPでも問題なし |
| シンプル＆無料 | すべてのツールが無料で導入可能 |
| セキュリティ意識 | パスワードは自動入力、ペースト履歴も残らない |
| カスタマイズ性高 | 複数の定型文、入力後にTab/Enterなど拡張も簡単 |

---

## 🧩 応用アイデア

- `hs.chooser` を使って GUI でパスワード選択
- スニペットを外部ファイルで管理
- 通知やログ保存も可能（セキュリティ用途で）

---

## 🧾 まとめ

| 困りごと | 解決策 |
|--|--|
| Stream DeckでCtrl+Vが効かない | Hammerspoonで1文字ずつタイプする |
| Mac→RDPで仮想キーが通らない | hs.eventtap で完全エミュレーション |
| 複数のパスワードを管理したい | 複数ホットキーで柔軟に対応可能 |

---

## 🙌 お役に立てれば！

同じ課題で悩んでいる方に届けば幸いです。  
「貼り付けできないならタイプすればいいじゃない」理論で、RDP環境でも快適入力を実現しましょう！  

投稿者：もあい  
投稿日：2025年5月1日
Tableauで別タブでリンク遷移をする方法について

はじめに
--

Tableauのリンク遷移の動作について、TabelauServerにアップロードしてからの動作で
別タブでリンク遷移できないことがあったので情報をまとめてみました。
※Tableauのバージョンは2023.3、データは[サンプル - スーパーストア]のデータを使用しています。

事象
--
下記画像のようにURL部分を押下した時に、
「URLに移動」のアクションで、リンク先のページを開くことができるダッシュボードを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3671775/863cd852-6485-4e18-b747-d041fc835926.png)

この時、遷移１押下⇒遷移２押下と操作するとTableauDesktopでは以下の動作をします。

①遷移１を押下で新しいタブに画面が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3671775/d1074040-b2d1-472b-881c-078ea715ce89.png)

②遷移２を押下で①と別タブに画面が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3671775/61e62c4f-f713-4ee6-9c5f-9aa7b3d0d061.png)

ところがTableauServerにアップロードした同じダッシュボードでは動作が変わり

①遷移１を押下で新しいタブに画面が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3671775/d1074040-b2d1-472b-881c-078ea715ce89.png)

②遷移２を押下で①の画面を上書きして画面が表示される
　※別タブで画面表示されない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3671775/a6bcba15-1040-4699-bc1f-00e5ab0d6bd2.png)

このように変化が見られます。

事象の原因
--
下記の記事で原因について記載があります。



・内容要約
Tableauの「URLに移動」アクションは、2回目以降の動作時に別タブで画面を開くことが不可です。
下記リンクの項目6に記載の注意書きに記載があります。
https://help.tableau.com/current/pro/desktop/ja-jp/actions_url.htm

>引用
>注: 新しいタブ オプションでは、アクションが初めて実行されると新しいタブが開きます。その後、アクションで追加のタブが開くのではなく、同じタブが開きます。


またコミュニティでは過去活発な議論があります。
その中にリンクの後ろに「&:linktarget=_blank」等をURLの後ろにつけると解決するとする
内容が散見されますが、TabelauServerにアップロードしたダッシュボードでは機能しませんでした。
https://community.tableau.com/s/question/0D54T00000C5cu5SAB/need-to-open-each-url-link-in-a-seperate-tab

解消方法
--
アクションからでは上記の制約があるため、
アクション以外でURLに移動できる機能を使う必要があります。
具体的な方法としては、画像にURLを埋め込む方法です。

①下図のイメージオブジェクトをダッシュボード上に配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3671775/207bc3a0-87d7-4c1f-80a1-82a6c9477dd7.png)

②配置すると下図のポップアップが表示される。
　この中で「イメージをクリックしたときに開くURL」に開きたいWebページのURLを記載する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3671775/9f945457-1f41-40dc-a91b-828265989d43.png)

手順としてはこちらで完了です。
このリンク遷移では常に別タブを開いて遷移することが可能です。

終わりに
--
Tableauでの動作がうまくいかないケースの一つについて解消方法を記載しました。
今後もTableau含むBIツールの問題解決の一助となるような記事を作成していこうと思います。
コンパイラ最適化　forループが消える？？

## 初めに

C言語をアセンブリ言語へコンパイルして最適化する場合としない場合の違いを確認します。

### C言語ソース
```
int sum() {
  int total = 0;
  for (int i = 1; i <= 100; i++) {
    total += i;
  }
  return total;
}
```

### 最適化の設定
```
最適化無し (-O0)
gcc -S -O0 -masm=intel sum.c -o sumO0.s

最大最適化 (-O3)
gcc -S -O3 -masm=intel sum.c -o sumO3.s
```

## 最適化の有無による差異

### 最適化しない場合
```sumO0.s
	.file	"sum.c"
	.intel_syntax noprefix
	.text
	.globl	_sum
	.def	_sum;	.scl	2;	.type	32;	.endef
_sum:
LFB0:
	.cfi_startproc
	push	ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	mov	ebp, esp
	.cfi_def_cfa_register 5
	sub	esp, 16
	mov	DWORD PTR [ebp-4], 0
	mov	DWORD PTR [ebp-8], 1
	jmp	L2
L3:
	mov	eax, DWORD PTR [ebp-8]
	add	DWORD PTR [ebp-4], eax
	add	DWORD PTR [ebp-8], 1
L2:
	cmp	DWORD PTR [ebp-8], 100
	jle	L3
	mov	eax, DWORD PTR [ebp-4]
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE0:
	.ident	"GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"
```

### 最適化する場合
```sumO3.s
	.file	"sum.c"
	.intel_syntax noprefix
	.text
	.p2align 4,,15
	.globl	_sum
	.def	_sum;	.scl	2;	.type	32;	.endef
_sum:
LFB0:
	.cfi_startproc
	mov	eax, 5050
	ret
	.cfi_endproc
LFE0:
	.ident	"GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"
```

### 分析
最適化しない場合は、C言語の書き方通りに100回繰り返して計算しているが、この書き方だとtotalは毎回5050となる。最適化した場合は直接5050を代入している。
```
	mov	DWORD PTR [ebp-4], 0
	mov	DWORD PTR [ebp-8], 1
	jmp	L2
L3:
	mov	eax, DWORD PTR [ebp-8]
	add	DWORD PTR [ebp-4], eax
	add	DWORD PTR [ebp-8], 1
L2:
	cmp	DWORD PTR [ebp-8], 100
	jle	L3
```
この10行が1行に短縮された。
```
mov	eax, 5050
```

## 動作環境

windows7 Version6.1.7601
GCC-6.3.0-1
（帰省中につき一時的に昔のパソコンを使用している。windows7が懐かしい。。。）
Google AppScriptを使ってスプレッドシートに自動で日付を入れる方法

![ChatGPT Image 2025年5月1日 11_48_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4053067/fa97ed93-f99a-42ed-a9e9-2704dcfa0103.png)

Googleスプレッドシートをネタ帳代わりにする時などに
追加しておくと便利な方法をご紹介。

私の場合、電車で移動中の時とか思いついた事をメモするのに、スマホのメモ帳やLINEなどにメモを取っていました。
ただその時によって書く場所がバラバラで、あとで見返す時、どこへ書いたかわからなくなってしまう事もしばしば。

そこで、Googleスプレッドシートに箇条書きしていく事にしました。
スプレッドシートに書くことで、スマホからもPCからも閲覧、編集ができるので
iPhone & Windowsやandoroid & Macの組み合わせでも情報共有ができます。

B列に思い付いた内容を書き出していき、
A列にその日の日付を自動で入力する方法があったので、ご紹介いたします。

# 手順
1. スプレッドシート上部にあるメニューから「拡張機能」→「Apps Script」を選択。

2. 下記のコードを貼り付けて保存。

```ruby:Apps Script
function onEdit(e) {
  var sheet = e.source.getActiveSheet();
  var range = e.range;

  // B列に入力があった場合
  if (range.getColumn() == 2) {
    var row = range.getRow();
    var dateCell = sheet.getRange(row, 1);

    // A列が空欄の場合にのみ日付を入力（上書き防止）
    if (!dateCell.getValue()) {
      dateCell.setValue(new Date());
    }
  }
}
```

**注意**
Scriptの記述画面で「Run」を実行すると、

`TypeError: Cannot read properties of undefined (reading 'source')
onEdit	@ Code.gs:2`
というエラーが出ますが、このエラーはGoogle Apps Script の「onEdit」関数をスクリプトエディタ内で直接実行したときによく発生するもの。

確認するときはスクリプトエディタ内ではなく、元にスプレッドシートのB列に値を入れてA列に日付が入るか確認してみてください。

うまくいかない時はChatGPTに聞くと教えてくれます。
Stripeで決済情報に独自データを埋め込む方法（payment_intent_data.metadata）

### はじめに

Stripeで決済処理を行う中で、「誰がどの注文をしたか」など、独自の情報を埋め込みたい場面ってありますよね？
そんなときに便利なのが metadata 機能です。

この記事では、Checkout Session作成時にpayment_intent_data.metadataを使って独自情報を渡す方法を紹介します。

### 使い方

たとえば、会員番号を決済情報に紐づけたい場合、以下のように記述します。

```php
\Stripe\Stripe::setApiKey('sk_test_...');

$session = \Stripe\Checkout\Session::create([
    'payment_method_types' => ['card'],
    'mode' => 'payment',
    'line_items' => [[
        'price' => 'price_XXXXXXX',
        'quantity' => 1,
    ]],
    'payment_intent_data' => [
        'metadata' => [
            'member_entry_no' => $memberNo, // ここに独自データを追加
        ],
    ],
    'success_url' => 'https://example.com/success',
    'cancel_url' => 'https://example.com/cancel',
]);
```

### できること

このようにして渡したデータは、以下の場所から確認・取得できます。
	•	Stripeの管理画面（支払い詳細のメタデータ欄）
	•	Webhookの payment_intent.succeeded イベント内
	•	API経由で PaymentIntent を取得したとき

### 便利な活用例
	•	ユーザーID、会員番号の紐づけ
	•	注文番号のトラッキング
	•	アフィリエイトタグなどマーケティング用途
	•	マルチテナントシステムでのテナントID伝播

### 注意点
	•	metadataの値は最大50個のキー、各キー・値は最大500文字です。
	•	センシティブな情報（個人情報など）は入れないようにしましょう。

### まとめ

Stripeのmetadataは、決済情報に独自データを安全かつ簡単に埋め込める非常に便利な機能です。
Webhookと組み合わせることで、外部システムとの連携もスムーズになります。
PowerShell をCUIで簡単にアップデートする方法

### はじめに

PowerShell 7 を使用していると、起動時に次のようなメッセージが出ることがあります

```plaintext
A new PowerShell stable release is available: v7.5.1
Upgrade now, or check out the release page at:
https://aka.ms/PowerShell-Release?tag=v7.5.1
```

今回は、**winget** を使って簡単に PowerShell を最新版へアップデートする方法を紹介します

---

### 前提条件

- Windows 10 or 11
- `winget` が使える状態（PowerShell 7.1+ または Windows Terminal など）
- 管理者権限なしでも可能ですが、環境によってはインストーラーの実行時に管理者許可を求められる場合があります

---

### 実行コマンド

以下のコマンドを PowerShell 上で実行します

```powershell
winget upgrade --id Microsoft.PowerShell
```

初回実行時は、以下のような確認が表示されるようです

```plaintext
'msstore' ソースでは、使用する前に次の契約を表示する必要があります
[Y] はい  [N] いいえ: Y
```

**[Y] を入力して続行**してください

---

### アップデート手順の流れ

上記のコマンドを実行すると以下を自動で行ってくれます
1. 最新バージョンの検出
2. インストーラーのダウンロード（GitHubから）
3. インストーラーハッシュの検証
4. インストール開始
5. PowerShellを再起動すれば最新版に切り替わります

```powershell
PS C:\Users\hogehoge> winget upgrade --id Microsoft.PowerShell
'msstore' ソースでは、使用する前に次の契約を表示する必要があります。
Terms of Transaction: https://aka.ms/microsoft-store-terms-of-transaction
ソースが正常に機能するには、現在のマシンの 2 文字の地理的リージョンをバックエンド サービスに送信する必要があります (例: "US")。

すべてのソース契約条件に同意しますか?
[Y] はい  [N] いいえ: Y
見つかりました PowerShell [Microsoft.PowerShell] バージョン 7.5.1.0
このアプリケーションは所有者からライセンス供与されます。
Microsoft はサードパーティのパッケージに対して責任を負わず、ライセンスも付与しません。
ダウンロード中 https://github.com/PowerShell/PowerShell/releases/download/v7.5.1/PowerShell-7.5.1-win-x64.msi
  ██████████████████████████████   108 MB /  108 MB
インストーラーハッシュが正常に検証されました
パッケージのインストールを開始しています...
インストールが破棄されました
```

---

### 注意点：インストールが破棄された？

私の環境では最後に以下が出力されました
```plaintext
インストールが破棄されました
```

**実際には問題なくアップデートが完了していました**

PowerShellを再起動し、以下のコマンドでバージョンを確認します

```powershell
PS C:\Users\hogehoge> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.5.1
PSEdition                      Core
GitCommitId                    7.5.1
OS                             Microsoft Windows 10.0.19045
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
```
アップデートが完了していることが確認できました
C言語 switch及びifelseの違いをアセンブリ上で確認

## switch
### Cソース
```switch.c
int main(){
	int a=0;
	int b=0;
	
	switch(a){
		case 1:
			b=4;
			break;
		case 2:
			b=5;
			break;
		case 3:
			b=6;
			break;
		
		default:
			b=7;
	}
	return 0;
}
```

### アセンブリ
<details>
<summary>switch.s</summary>

```switch.s
		.file	"switch.c"
	.intel_syntax noprefix
	.def	___main;	.scl	2;	.type	32;	.endef
	.text
	.globl	_main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
LFB0:
	.cfi_startproc
	push	ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	mov	ebp, esp
	.cfi_def_cfa_register 5
	and	esp, -16
	sub	esp, 16
	call	___main
	mov	DWORD PTR [esp+12], 0
	mov	DWORD PTR [esp+8], 0
	mov	eax, DWORD PTR [esp+12]
	cmp	eax, 2
	je	L3
	cmp	eax, 3
	je	L4
	cmp	eax, 1
	jne	L8
	mov	DWORD PTR [esp+8], 4
	jmp	L6
L3:
	mov	DWORD PTR [esp+8], 5
	jmp	L6
L4:
	mov	DWORD PTR [esp+8], 6
	jmp	L6
L8:
	mov	DWORD PTR [esp+8], 7
L6:
	mov	eax, 0
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE0:
	.ident	"GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"

```
</details>


## if else
### Cソース
```ifelse.c
int main(){
	int a=0;
	int b=0;
	
	if(a==1){
		b=4;
	}else if(a==2){
		b=5;
	}else if(a==3){
		b=6;
	}else{
		b=7;
	}
	
	return 0;
}
```

### アセンブリ
<details>
<summary>ifelse.s</summary>

```ifelse.s
	.file	"ifelse.c"
	.intel_syntax noprefix
	.def	___main;	.scl	2;	.type	32;	.endef
	.text
	.globl	_main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
LFB0:
	.cfi_startproc
	push	ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	mov	ebp, esp
	.cfi_def_cfa_register 5
	and	esp, -16
	sub	esp, 16
	call	___main
	mov	DWORD PTR [esp+12], 0
	mov	DWORD PTR [esp+8], 0
	cmp	DWORD PTR [esp+12], 1
	jne	L2
	mov	DWORD PTR [esp+8], 4
	jmp	L3
L2:
	cmp	DWORD PTR [esp+12], 2
	jne	L4
	mov	DWORD PTR [esp+8], 5
	jmp	L3
L4:
	cmp	DWORD PTR [esp+12], 3
	jne	L5
	mov	DWORD PTR [esp+8], 6
	jmp	L3
L5:
	mov	DWORD PTR [esp+8], 7
L3:
	mov	eax, 0
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE0:
	.ident	"GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"

```
</details>

## 比較
### winmergi
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4054974/9b8534b5-8620-4a1b-a83b-b155b68e8b0a.png)

### switchの関連部分
```
	call	___main
	mov	DWORD PTR [esp+12], 0
	mov	DWORD PTR [esp+8], 0
	mov	eax, DWORD PTR [esp+12]
	cmp	eax, 2
	je	L3
	cmp	eax, 3
	je	L4
	cmp	eax, 1
	jne	L8
	mov	DWORD PTR [esp+8], 4
	jmp	L6
L3:
	mov	DWORD PTR [esp+8], 5
	jmp	L6
L4:
	mov	DWORD PTR [esp+8], 6
	jmp	L6
L8:
	mov	DWORD PTR [esp+8], 7
```
### ifelseの関連部分
```
	call	___main
	mov	DWORD PTR [esp+12], 0
	mov	DWORD PTR [esp+8], 0
	cmp	DWORD PTR [esp+12], 1
	jne	L2
	mov	DWORD PTR [esp+8], 4
	jmp	L3
L2:
	cmp	DWORD PTR [esp+12], 2
	jne	L4
	mov	DWORD PTR [esp+8], 5
	jmp	L3
L4:
	cmp	DWORD PTR [esp+12], 3
	jne	L5
	mov	DWORD PTR [esp+8], 6
	jmp	L3
L5:
	mov	DWORD PTR [esp+8], 7

```
cmpで比較→該当処理のラベルへ跳ぶ→代入処理
とやっていることは変わらないがswitch文を使用した場合の方がすっきりとしたコードが出力された。
理由は分からない。

## 動作環境
windows7 Version6.1.7601
GCC-6.3.0-1
（帰省中につき一時的に昔のパソコンを使用している。windows7が懐かしい。。。）
```
gcc -S -masm=intel switch.c -o switch.s
```
[Prometheus] Created Timestamps Zero Injection

## はじめに

この記事は Prometheus の Created Timestamps Zero Injection がどういった機能なのかを理解するために自分なりに情報を整理した内容になっています。正確な情報を知りたい方は参考資料をご参照ください。

## Created Timestamps Zero Injection とは？

メトリクスのメタデータで提供される 0 値の開始時間 (リセット時間) を元に、Counter、Summary、Classic Histogram メトリクスに 0 値の合成サンプルを注入する機能です。

現時点では Prometheus Protobuf フォーマットのメトリクスのみがサポートされていて、[他フォーマット](https://prometheus.io/docs/instrumenting/exposition_formats/)のサポートは WIP となっています。

![chunk-with-created-timestamps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49924/9e0c854b-3b2a-4708-8604-f9484ce8db35.png)

上図でいうと、T-1 と T と T+2 の3サンプルが収集されていて T+2 でリセットが発生している場合に、メトリクスが持つ開始時間 (リセット時間) を元に Prometheus が T-5 と T+1 に 0 値の合成サンプルが注入するイメージです。

ちなみに [OpenMetrics](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md) や [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.44.0/specification/metrics/data-model.md) も Counter の開始時間を提供する仕様になっていますが、Prometheus 側でパーサーが実装されておらず現在は未サポートという状態です。

> #OpenMetrics
> A MetricPoint in a Metric with the type Counter SHOULD have a Timestamp value called Created. This can help ingestors discern between new metrics and long-running ones it did not see before.

> #OpenTelemetry
> Every OTLP metric data point has two associated timestamps. The first, mandatory timestamp is the one associated with the observation, the moment when the measurement became current or took effect, and is referred to as `TimeUnixNano`. The second, optional timestamp is used to indicate when a sequence of points is unbroken, and is referred to as `StartTimeUnixNano`.

## 導入された背景

以下のような Counter メトリクスのエッジケースに対応するために導入されました。

- 初期化されていない Counter はインクリメントされた値でメトリクスが開始するため、0 値がいつ開始したのか分からず可視化やアラートに影響する可能性がある (レート計算など)
- 値のリセット後すぐにインクリメントされてその値が最後に収集した値より大きい場合、Counter のリセットを検出できない可能性がある

なお、Summary や Classic Histogram のメトリクスも Counter で表現されるので同じ問題が発生します。

## 有効にする方法

### Prometheus 側

まだ実験的な機能という位置付けでデフォルト無効なので Feature Flag での有効化が必要です ([公式ドキュメント](https://github.com/prometheus/prometheus/blob/v3.3.0/docs/feature_flags.md#created-timestamps-zero-injection))。ちなみに [v2.50.0](https://github.com/prometheus/prometheus/releases/tag/v2.50.0) から導入された機能なので、それ以前のバージョンを使用している場合はバージョンアップが必要です。

```
--enable-feature=created-timestamp-zero-ingestion
```

この機能は Prometheus Protobuf プロトコルのみをサポートしている兼ね合いで、この機能を有効にすると [scrape_config.scrape_protocols](https://prometheus.io/docs/prometheus/latest/configuration/configuration/) のデフォルト値が変わり、Exporter とのネゴシエーションで Prometheus Protobuf プロトコルが優先されるようになります。

### Exporters 側

prometheus/client_golang の [v1.17.0](https://github.com/prometheus/client_golang/releases/tag/v1.17.0) 以降を利用している場合は、Content Negotiation で Prometheus Protobuf が使用されると Created Timestamp の公開がデフォルトで有効になっています。Exporter の実装では基本的にこのライブラリを使用すると思うのでバージョンアップ以外に特別な作業は不要かと思われます。


## 参考資料

- https://github.com/prometheus/proposals/blob/main/proposals/2023-06-13_created-timestamp.md
- https://www.arthursens.dev/posts/created-timestamps
- https://promcon.io/2023-berlin/talks/when-my-counter-restarted-addressing-decade-old-counter-limitation-with-created-timestamps/
zshの履歴に日時を表示する（備忘録）

実務中に「あの人が問題対応のときに打ったコマンド、何だったっけ？」
と思う場面が度々あったので、備忘としてメモしておきます

# 環境
pc：MacBook Pro（2019）
os：macos Sequoia
shell ver：zsh 5.9

# コマンド
## （1）zshである事を確認
```terminal
echo $SHELL
```

## （2）.zshrcに設定追加
```terminal
echo "setopt extended_history" >> ~/.zshrc
echo "alias history='history -i'" >> ~/.zshrc
```
setopt extended_history を設定することで、zsh のコマンド履歴に 実行日時（タイムスタンプ） が記録されるようになります。

## （3）追加できている事を確認
```terminal
tail ~/.zshrc
```
## （4）変更を適用
```terminal
source ~/.zshrc
```
## （5）historyコマンド実行
`2025-05-01 10:41`といった表記で日付が確認できるようになります
```terminal
history
```
実行結果の例：
```yaml
・
・
 1009  2025-05-01 10:41  tail ~/.zshrc
 1010  2025-05-01 10:47  hisotry
```
DatabuttonでFirestoreに接続してみた！ノーコードでAPIアプリを構築


# DatabuttonでFirestoreに接続してみた！ノーコードでAPIアプリを構築

[Databutton](https://www.databutton.com)は、Pythonベースで簡単にアプリを作れるノーコード／ローコードプラットフォームです。この記事では、Firestore（Google CloudのNoSQL DB）に接続し、API経由でデータを読み書きできるシンプルなアプリの作成方法を紹介します。

## 🎯 この記事でできること

- Firestoreに接続するDatabuttonアプリの作成
- Firestoreからのデータ取得・書き込み
- Databutton上でのAPIエンドポイントの作成

---

## 🧩 必要な準備

### 1. Firestoreのプロジェクト作成
Google Cloud Consoleで以下を設定します：

- プロジェクト作成
- Firestoreを有効化（ネイティブモード）
- サービスアカウント作成（JSONキーをダウンロード）

### 2. Databuttonで新しいアプリを作成
- https://www.databutton.com にアクセスし、アカウントを作成
- 「New App」からアプリを開始

---

## 🔧 コアコード（接続・取得・登録・API定義）

```python
from google.cloud import firestore
import json
from databutton import api

# Firestore接続
with open("service_account.json") as f:
    service_account_info = json.load(f)
db = firestore.Client.from_service_account_info(service_account_info)

# データ取得
def get_data():
    docs = db.collection("users").stream()
    return [doc.to_dict() for doc in docs]

# データ追加
def add_user(name, email):
    doc_ref = db.collection("users").document()
    doc_ref.set({"name": name, "email": email})
    return {"status": "ok"}

# API定義
@api
def get_users():
    return get_data()

@api
def create_user(name, email):
    return add_user(name, email)
```

---

## ✅ 実行例

- `GET /get_users` → ユーザー一覧を取得
- `POST /create_user`（JSONボディに`name`と`email`）→ 新しいユーザーを登録

Databuttonの「API Tester」や「Playground」から実行して確認できます。

---

## 🧭 まとめ

Databuttonを使えば、Google Cloud Firestoreとの連携も非常に簡単です。PythonベースでAPIを公開でき、UIや管理画面も統合可能なので、スタートアップや個人開発にも最適です。

---

## 🔗 参考リンク

- [Databutton公式サイト](https://databutton.com?via=takahiro19)
- [Google Cloud Firestore公式](https://cloud.google.com/firestore)
- [Ronbun.AI](https://ronbun-ai.org/)
---

🔥 気に入ったらLGTM・コメントお願いします！



⸻
記事投稿のヒントの見直し案

Qiitaを投稿しようとすると、右の画面に次のような記述が現れます。

>記事投稿のヒント
コミュニティガイドライン
ガイドラインの内容を理解し、エンジニアにとって再利用性・汎用性の高い内容を投稿しよう
例えば、以下のような記事はやめましょう
テスト投稿、日記など（限定共有投稿をご活用ください）
文章として成立していないメモや走り書き
自己紹介記事（プロフィールをご活用ください）
AIが生成した内容で正しいかどうかを検証していないもの

誤解をまねきやすい表現の羅列は、Qiitaの質を低下させるような気がしました。
上記文章は、エンジニアにとって再利用性・汎用性の高い内容ではなく、再現性も乏しいかもしれません。

言語理論、工学、法律、規格、特許などに基づいて、文章の見直しをお勧めします。

プログラマが知っていると良い「公序良俗」
https://qiita.com/kaizen_nagoya/items/9fe7c0dfac2fbd77a945

公序良俗との関係が説明できない計画・規則は有効か
https://qiita.com/kaizen_nagoya/items/7356189bf1644c4b6313

以下は、Qiitaから依頼があった場合の想定した意見として記録します。

# エンジニアにとって再利用性・汎用性の高い内容
再利用性と汎用性は同時に成立するとは限りません。
再利用性が高いかどうかよりも、具体的な再現性が高いかどうかが大事ではないでしょうか。

再利用性が高いと主張しても、再現性のない事象は議論の対象になることが困難です。
再現性を確保するためには、個別、具体的な条件の記載が必要な場合があります。

汎用性が高ければ高いほど、矛盾が生じる可能性があるかもしれません。

立場か違えば、汎用性が成り立たないかもしれません。
一つの立場の汎用性だと思っている実態は、実はその立場の利権に依存しているかもしれないと考えたことがあるでしょうか。

逆も真：社会人が最初に確かめるとよいこと
https://qiita.com/kaizen_nagoya/items/39afe4a728a31b903ddc
# テスト投稿
Qiitaの投稿の仕組みを理解するためのテスト投稿は、限定共有投稿をご活用いただければよいという趣旨は理解できます。

テスト投稿には、
特定の分野の投稿に対する反応を見る目的。
特定のMarkdownおよびそれ以外の記述方法に対する反応を見る目的。
特定の言語（自然言語、プログラミング言語を含む）に対する反応を見る目的。
など、さまざまな目的の記述があります。

「Qiitaの投稿の仕組みを理解するためのテスト投稿」と限定した表現なら誤解を招きにくいかもしれません。

# 日記
プログラミングと関係ないと書いている本人が思っている日記は、限定共有投稿でよいかもしれません。

エンジニアにとって再利用性・汎用性の高い内容の日記であれば、なんの問題もないはずです。
「日記」という言葉だけで説明した気になっているQiita側の姿勢はいただけないかもしれません。

「プログラミングと関係ないと思っている日記」と限定する表現すれば誤解を招きにくいかもしれません。

# 文章
文章として成立していないメモや走り書きは、プログラムの原点そのものです。

文章として成立してない言葉の羅列を、コンパイラにかければ、文法誤り、意味誤りなどを指摘してくれて改善できていきます。

プログラムを書き始める最初の段階として推奨できます。

文章として成立していないかもしれないメモや走り書きは、コンパイラ、言語処理ソフトにかけた結果とその後の改良とともに掲載してもらえればよいのではないでしょうか。

文章として成立していないかもしれないメモや走り書きを軽視する姿勢は、プログラマとしてはあり得ません。

「文章として成立していないかもしれないメモや走り書きは、言語処理システムを通してその後の改良とともに掲載してください」と表現すれば誤解を招きにくいでしょう。

# 自己紹介記事
すべての自著の文章は、自己紹介記事にすぎません。
他人の紹介ばかりを書くより、自分の頭で考えたこと、自分が経験したことを書いてもらった方が、いいかもしれないと思います。

自己紹介記事のうち、プロフィールに書いてあった方が、読者のためになることはプロフィールに書くように勧めてはいかがでしょうか。

「【カジュアル面談企画】他社のエンジニアと話してみよう!」に参加する前に 
https://qiita.com/kaizen_nagoya/items/0bdd5f52c4627e11703e

すべての自著記事は、自己紹介記事として読ませていただいています。

# AIが生成
正しいかどうかの前に、著作権などの権利関係を明確にすることが大切です。
たとえば、自分の書き物を学習データとして使い、自分の権利の範囲内で生成したものであれば、正しいかどうかが問題ではなく、価値があるかどうかが問題です。

正しい文章は、しばしば価値がありません。世の中には、立場によって正しいという集合は可変です。すべての立場で正しいという集合は、しばしば空集合かもしれません。

「自己が保有する著作権データなどに基づかないAIが生成した内容で、知的所有権があるかどうかを検証していないもの」と表現すれば誤解を招きにくいでしょう。

# まとめに代えて
Qiitaの記事で、法律、特許、規格などにもとづかずに、著者の経験や、著者の属する組織の経験などを前提として、かつ、その前提を記載せずに描写している記述をみかけることがあります。

会社名で忖度しろという態度の記述もしばしば見かけます。

「記事投稿のヒント案」
コミュニティガイドライン
ガイドラインの内容を理解し、エンジニアにとって再利用性・汎用性の高いだけでなく再現性の高い内容を投稿しよう
例えば、以下のような記事はやめましょう
Qiitaの投稿の仕組みを理解するためのテスト投稿、プログラミングと関係ないと思っている日記など（限定共有投稿をご活用ください）
文章として成立していないメモや走り書きで言語処理システムを通してその後の改良を図ろうとしていない記述
自己紹介記事のうちプロフィールに書いてある方が便利な内容。
AIが生成した内容で知的所有権の検証していないもの

## 参考資料
@kazuo_reve 私が効果を確認した「小川メソッド」
https://qiita.com/kazuo_reve/items/a3ea1d9171deeccc04da

今日Xpathを覚えた
https://qiita.com/kaizen_nagoya/items/b3d9a3aca9643e5d243a

Webアプリケーションを学ぶ
https://qiita.com/kaizen_nagoya/items/f1c9b063317003cddff9

<!---
Qiitaに入ったばかりで、Qiitaの組織の属するグループの経験や、人材のつながりを理解せずに、特定のWebサービスの規則などに基づいて、特定の知財の人たちの考えだけで判断した措置に何度も遭遇した気がします。
---!>
クソデカいCSVのレコード抽出をコマンドプロンプトで行う

VBAのSQLが使えないほどフィールドが多く(256以上)、数万レコードある場合など

findstr "見出し行フィールド名" "クソデカいCSV.csv" > "resultCSV.csv"
findstr "検索ID01" "クソデカいCSV.csv" >> "resultCSV.csv"
findstr "検索ID02" "クソデカいCSV.csv" >> "resultCSV.csv"
Azure Functions × Playwrightで実現するサーバーレス自動化バッチ

## プロジェクトの概要

本プロジェクトは、Azure Functions（Linux Consumptionプラン）上でPlaywrightと@sparticuz/chromiumを活用し、とあるWebサイトの自動取得・差分検出・CSV保存を行うバッチを構築したものです。HTTPトリガーで実行し、サーバーレスによる自動化と省力化を目指しました。

## システム構成と技術選定

- Azure Functions（Node.js 20.x, TypeScript, Linux Consumption）
- Playwright＋@sparticuz/chromiumによるヘッドレスブラウザ自動化
- データやデバッグファイルはAzure Blob Storageに保存

クラウド上での自動化を実現するため、Node.jsとTypeScriptをベースに、軽量なChromium環境を@sparticuz/chromiumで構築。取得データやデバッグ用ファイルはすべてBlob Storageに集約し、運用の効率化を図りました。

## 実装内容と工夫

- TypeScript、Playwright、Chromium、Azure Functionsのセットアップ
- HTTPトリガーFunction（HTTPTrigger01）の実装とデプロイ
- Playwright/PuppeteerのwaitForSelector挙動差やUser-Agent設定、タイムアウト対応
- 取得データの保存先をAzure Blob Storageに変更
- デバッグ用HTML/PNG/JSONファイルのアップロードと外部確認対応
- APIデータ取得・保存処理のリファクタリング
- ドキュメント・CSVデータの更新
- npm install & build、Azure Functionsへのデプロイ

とくに、PlaywrightのwaitForSelectorの挙動やUser-Agentの調整、タイムアウト対策など、クラウド環境特有の課題に細かく対応しました。デバッグファイルをBlob Storageに保存することで、外部からも動作状況を確認できるようにしています。

## 得られた成果

- Azure Functions上でPlaywright/Chromiumによる自動化バッチの構築・運用に成功
- HTTPリクエストで最新の店舗情報や差分を即時取得可能
- 取得データのCSV自動保存と過去データ比較が容易に
- デバッグファイルをBlob Storage経由で外部から確認可能

サーバーレス環境での自動化により、運用コストの削減と作業効率の向上を実現しました。

## 直面した課題とその対応

最大の課題は、Azure FunctionsのIPアドレスがAPI側で許可されておらず、API経由でのデータ取得ができなかった点です（現状プロジェクトは凍結中）。

### 問題解決までのプロセス

1. エンドポイントの動作確認  
　Azure Functions（HTTPTrigger01）をデプロイ後、HTTPリクエストで動作確認。ローカルでは正常に取得できたが、Azure上では失敗。

2. エラー内容の調査  
　実行ログやレスポンス内容を確認し、タイムアウトやネットワークエラー（ECONNREFUSED/ECONNRESET等）を特定。PlaywrightのデバッグファイルをBlob Storageに保存し、外部から内容を確認。

3. コード・設定の再点検  
　User-Agentやタイムアウト、APIエンドポイントURL、リクエストヘッダー等を再確認。ローカルとAzure Functionsの環境差異も洗い出し。

4. ネットワーク経路の仮説検証  
　Azure Functionsから外部APIへのアクセス制限を想定し、IPアドレス帯やAPI側のアクセス制御（IPホワイトリスト等）を調査。

5. API提供元への問い合わせ・検証  
　**Azure Functions App Service上のSSHでcurlコマンドを実行し、APIエンドポイントに直接アクセス。API側でAzure FunctionsのIPアドレスが許可されていないことが判明。**

6. 結論と今後の対応  
　クラウド上（Azure Functions）からのAPIアクセスがブロックされているため、現状は自動取得不可と判断。API側でIP許可が得られれば、クラウド上での完全自動化が実現可能です。

## 今後の展望

API側でAzure FunctionsのIP許可が得られれば、クラウド上での完全自動化が実現できます。今後もサーバーレス技術とヘッドレスブラウザの活用による業務効率化に挑戦していきたいと考えています。
進化したスライド生成AIのGamma 2.0を試してみた

最近リリースされたスライド生成AI「Gamma」のバージョン2.0を試してみました。

https://www.aibase.com/ja/news/17192

正直な感想としては「これは実用レベルでは？」という驚きです。



以下に、使ってみた印象と気づいたポイントをまとめていきます。

## ✨ 要点整理の精度がかなり上がっている
テーマとして「クラウドサーバーの基礎」といった技術系の内容を指定してみましたが、
出てきたスライドが初心者向けにしっかり要点を絞った構成になっており、非常にわかりやすいものでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/14d3c2d7-ff75-4a60-a2d8-6aa2e24acfe4.png)


文章のトーンも「ですます調」「である調」が選択可能で、
プレゼンの場面に合わせた表現スタイルを選べるのがとても便利です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/0ebf0f53-f13f-461a-ba12-d53695a9ffaa.png)



## 🖼️ 図のセンスが大幅に向上
驚いたのは、スライド内に使われる図のクオリティの高さ。
たとえば「SaaS・PaaS・IaaS」の説明では、初心者にも直感的に理解できる図が生成され、非常に良い印象でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/3e82634b-d293-4b80-a005-f15ab3dcb937.png)



一方で、「クラウドサーバーの構成図」のようなやや複雑な内容になると、まだ少し分かりにくい部分もあると感じました。図解全体の情報整理には今後の改善に期待です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/4cd98417-7dcc-4294-bbfb-18a044a2cb14.png)



## 🎨 図の雰囲気がプレゼン向きになった
旧バージョンでは、テーマによっては「SF感の強いロボット」が出てきて、現実の業務プレゼンに使うのが難しい印象でした。

(以下は旧バージョンで作成した「生成AIの活用」スライド)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/40357d91-3dfd-4394-b813-d0d607f494d9.png)


しかし、2.0ではそのセンスが大幅に改善され、実用的で自然なビジュアル構成に近づいていると感じます。
スライド全体で画像のトーンが揃っています。
（以前は写真画像とイラスト画像が混在していた）


## 📹 図の編集幅がすごい
何とスライド中の画像を動画化できる！うらでLumaとかが動いているのかも。
これで一気に目を引くスライドになりますね。

![gamma_animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/b2861916-07fc-411f-a031-12c39e5dc98f.gif)


## ⚠️ 無料プランの限界もある
ただし、無料プランではいくつか制限があります。

スライドの一括AI編集ができないようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/f5eb571f-8721-463d-bde2-3d0b02d8113f.png)


このあたりは、継続利用する場合にはプロプランの検討が必要になるかもしれません。

# 有料版でできることと料金プラン

PlusとProプランがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/f5f76ec0-1c44-4280-8e39-e1454244f0b1.png)



# 📝 総評
Gamma 2.0は、プレゼン資料の自動生成AIとして明らかに一段階進化しています。
技術の勉強会資料や、社内説明用のドラフト作成など、「まずはたたき台を作りたい」というニーズには十分応えてくれるツールになってきました。

# Gammaをお得に始める方法

この記事を読んで「Gammaを使ってみたい」と思った方へ、
新規登録で200クレジットがもらえる招待リンクをご用意しました。

ぜひこちらから登録して、スライド作成の新しい体験を試してみてください👇

https://gamma.app/signup?r=laxias1wgkdtai0


参考までにGammaで必要なクレジットの目安は以下の通り。

- AIで作成： 作成するgammaごとに40クレジット。
- AIでカードを追加： 5 作成したカード1枚につき、1クレジット。
- AIとチャット： AIの提案ごとに10クレジット（例：画像検索、コンテンツの書き換え）。エラーや説明に対して料金はかかりません。
- AI画像： 画像プロンプトごとに10クレジット。
- AIで続行： /continueまたは+++を使用するたびに2クレジット。
OSEK/VDX OS, COM and NM

AUTOSARの基本技術には、通信のCAN、OSのOSEK/VDX OS, COM, NM、診断のDoCAN, USDがある。
これらは、WTO/TBT協定に基づいた国際取引の原則に対応できる国際規格である。

CANは、CAN FDを含むISOの改訂、追加を行なっている。
診断は、SAEの規定を含む、ISOの改訂、追加を行なっている。
OSEK/VDX OS, COM, NMは、ISOの改訂、追加を行っていない。

AUTOSAR３つの源泉
https://qiita.com/kaizen_nagoya/items/de9cbc9549c74fecc7f1

# ISO改訂

OSEK/VDX OS改訂提案を作る
https://qiita.com/kaizen_nagoya/items/4229a8ac0baec836261a

改訂の方針として、Cの精神、Cの原則に基づき、OSEK/VDX OSの精神を提案する。

Cの精神とCの原則：C言語がわかるとは
https://qiita.com/kaizen_nagoya/items/d2a24a41f00c939c5e70

C言語(C++)が必要な人と必要ない人
https://qiita.com/kaizen_nagoya/items/2afe9e846b55b24cb6f1

C言語を習得する３つの方法
https://qiita.com/kaizen_nagoya/items/84cab0888c193bba429b
## OSの精神
Cの精神の最初の廃止になった"Trust the programmer."は除外している。

• Don’t prevent the programmer from doing what needs to be done.
• Keep the operating system small and simple.
• Provide only one way to do an operating system.
• Make it fast, even if it is not guaranteed OS to be portable.
仮訳
• プログラマが必要なことをするのを妨げないでください。
• OSを小さく単純にしてください。
• 一つのOSで実行する方法は１つだけにしてください。
• OSの可搬性を保証できなくても、高速にしてください。

アプリの可搬性を確保する。

## open source
osekをuploadした。https://qiita.com/kaizen_nagoya/items/6bc7eb2ec635e88afd5a
osek/vdx os open source https://qiita.com/kaizen_nagoya/items/59a4202bcb68e2dfd2b5
osek/vdx os open source, config, h8tiny-renesas, header file https://qiita.com/kaizen_nagoya/items/b4816501832bc0ad5a1e
osek autosar oil https://qiita.com/kaizen_nagoya/items/2df939e15e6282d5c380
osek/vdx os open source, sg/oil https://qiita.com/kaizen_nagoya/items/0b7f64c0e7bb3474b5f3
osek/vdx os open source, sample https://qiita.com/kaizen_nagoya/items/98ef0c547b60f114a9f9
osek/vdx os open source, kernel https://qiita.com/kaizen_nagoya/items/df48f89c281933b323cf
osek/vdx os open source, kernel, ECC2  https://qiita.com/kaizen_nagoya/items/2140339711df20181130

## github
github 入り口 https://qiita.com/kaizen_nagoya/items/a5d8dc24acb1ba43f7b6
github youtube https://qiita.com/kaizen_nagoya/items/019bd8541453d3362fdd
github memo https://qiita.com/kaizen_nagoya/items/3eff7691205b1d7c8d50
github 操作記録 https://qiita.com/kaizen_nagoya/items/1f67b745510ba3c0c7a6
CSS　::before / ::after　疑似要素とcontentプロパティの使い方完全整理

# はじめに
CSSの疑似要素`::before`と`::after`を使えば、HTMLを変更せずに視覚効果を追加できます。

#　①疑似要素とは？
`::before`　/　`::after`は、ある要素の**前後に追加の内容を表示**できるCSSの機能です。
主に**装飾**や**視覚的な演出**に使われます。

## ::beforeの例
```CSS
.element::before {
    content: '*';
    color: gold;
}
```

→要素の**先頭**に★が追加されます。

## ::afterの例
```CSS
.element::after {
    content: '→';
    color: red;
}
```

→要素の**末尾**に矢印が追加されます。

# ②contentプロパティの使い方と注意点

**基本**
```CSS
content: '';
```

- 疑似要素を表示させるには**contentの指定が必須**
- 空文字``でもＯＫ。主に**装飾だけ表示**したいときに使います。

**contentに文字列や記号を指定する**
```CSS
.item::before {
    content: 'New!';
    color: green;
}
```

→「New!」という文字が追加されます。

**contentに数字を指定したいときの注意点**

```CSS
.item::before {
    content: '1.';
}
```
→「1.」がそのまま表示されます。
- ポイントは必ずクォート('や")で囲んで文字列として扱う!

```CSS
content: 1; /*　←これはNG(無効) */
```

# ③よく使う実例

**1.下線アニメーション付きリンク**
```CSS
.readmore a {
    position: relative;
}

.readmore a::after {
    content: '';
    position: absolute;
    height: 1px;
    width: 100%;
    left: 0;
    bottom: 0;
    background: #333;
    transition: all 200ms ease;
}

.readmore a:hover::after {
    opacity: 0;
    transform: translateY(3px);
}
```

**2.三角形の矢印を表示する(borderで作る)**
```CSS
.arrow:before {
    content: '';
    border-style: solid;
    border-width: 6px 0 6px 8px;
    border-color: transparent transparent transparent #333;
    position: absolute;
    top: 50%;
    left: 0;
    margin-top: -6px;
}
```

**3.番号付きリスト風の表示**
```CSS
.step::before {
    content: '1. ';
    font-weight: bold;
}
```

# ④補足: 関連プロパティの役割まとめ
![IMG_7868.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2246240/f9dd6c43-13cc-4896-a5ab-505e5bca66d8.jpeg)

# ⑤まとめ
- ::before / ::after を使えば**HTMLをいじらずに装飾できる**
- content の指定がなければ**疑似要素は表示されない**
- 数字や記号を表示する場合も**クォートで囲む必要あり**
- 実務では下線・矢印・ラベルなど**装飾演出に頻出**
【Docker】ボリューム vs バインドマウント ⚔️

## はじめに

コンテナを削除すると、基本的にはコンテナ内のデータも削除されます。
データを残したい場合は、以下のいずれかの方法を選択します。

- ボリューム
- バインドマウント

compose.yaml の書き方がごっちゃになりがちなのでメモ ✍️

## ボリューム

Docker が管理する記憶領域にデータを永続化する仕組み

- バインドマウントよりデータの移行やバックアップが容易
- データを変更する際は、データを直接操作するのではなく、コンテナを通して行う
- 直接変更することがないデータに向いている
  - ex. データベースのデータ

### compose.yaml の書き方

```yaml:compose.yaml
services:
  <container_name>:
    image: <image_name>
    volumes:
      - <volume_name>:path/to/container_dir

volumes: <volume_name>
```

## バインドマウント

ホスト OS のディレクトリやファイルをマウントする仕組み

- データを変更する際は、ホスト OS のファイルを直接変更する
  - コンテナ内にも自動で反映される
- 変更の頻度が高いデータに向いている
  - ex. 開発中のプログラムのソースファイル

### compose.yaml の書き方

```yaml:compose.yaml
services:
  <container_name>:
    image: <image_name>
    volumes:
      - path/to/host_dir:path/to/container_dir
```

:::note alert
「仮想環境だから」と無邪気にバルス `rm -rf /` するとマウントしているホストのファイルも吹き飛びます。
:::

## 結局どっち使えばいいの？

迷ったら **ボリューム**

公式でもボリュームの使用が推奨されています。

https://matsuand.github.io/docs.docker.jp.onthefly/storage/volumes/

データを直接変更するする必要がある場合のみ、バインドマウントを選択するのがよいです。

## おわりに

用途に応じて使い分けが大事。
どっちがどっちか分からなくなったら、ここを見にくる。