OmniAICreator/Qiita-1.07M huggingface dataset:
Goでコマンドラインツールを作ってみた

## はじめに
コマンドラインツールを作るのは難しそうなイメージがありましたが、案外簡単に作れてしまいました。

## コード
```main.go
package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strings"
)

func main() {
	// コマンドライン引数の定義
	filename := flag.String("f", "", "検索対象のファイル名")
	word := flag.String("w", "", "検索する単語")
	flag.Parse()

	// 引数のバリデーション
	if *filename == "" || *word == "" {
		fmt.Println("使用方法: -f <ファイル名> -w <検索単語>")
		flag.PrintDefaults()
		os.Exit(1)
	}

	// ファイルを開く
	file, err := os.Open(*filename)
	if err != nil {
		fmt.Printf("ファイルを開けませんでした: %v\n", err)
		os.Exit(1)
	}
	defer file.Close()

	// 単語の出現回数をカウント
	scanner := bufio.NewScanner(file)
	count := 0
	for scanner.Scan() {
		count += strings.Count(strings.ToLower(scanner.Text()), strings.ToLower(*word))
	}

	if err := scanner.Err(); err != nil {
		fmt.Printf("ファイル読み込み中にエラーが発生しました: %v\n", err)
		os.Exit(1)
	}

	// 結果を表示
	fmt.Printf("ファイル '%s' 内の '%s' の出現回数: %d\n", *filename, *word, count)
}
```

## サンプルファイル
```test.txt
word
wordword
word&word
wrodword
```

## 動かしてみる

```zsh
go run main.go -f test.txt -w word

ファイル 'test.txt' 内の 'word' の出現回数: 6
```

## 引数が正しくない場合
コマンドラインの使用方法やオプションの説明が表示されます。

```zsh
go run main.go
                  
使用方法: program -f <ファイル名> -w <検索単語>
  -f string
        検索対象のファイル名
  -w string
        検索する単語
exit status 1
```
量子コンピューター方式 

主流(As of 2024)
---
- 超伝導 (Superconducting)
- イオントラップ (Trapped Ion)
- 冷却原子(中性原子) (Neutral Atom)


方式一覧
--
```mermaid
graph TD;
    D-1(超伝導)
    D-2(イオントラップ)
    D-3("冷却原子(中性原子)")
    D-4(半導体)
    D-5(光)
    D-1-1(IBM)
    D-2-1("IonQ(US)")
    D-2-2("Honeywell(US)")
    D-3-1("Atom computing(US)")
    D-3-2("QuEra Computing(US)")
    D-4-1(TBD)
    D-5-1(TBD)
    C-1(焼きなまし)
    C-1-1("D-Wave(Canada)")
    量子コンピューター-->B("ゲート型(Gate)");
    量子コンピューター-->C("アニーリング型(Annealing)");
    B --> D-1
    B --> D-2
    B --> D-3
    B --> D-4
    B --> D-5
    C --> C-1
    C-1 --> C-1-1
    D-1 --> D-1-1
    D-2 --> D-2-1
    D-2 --> D-2-2
    D-3 --> D-3-1
    D-3 --> D-3-2
    D-4 --> D-4-1
    D-5 --> D-5-1
```
クエリパラメーターの取得にはURLSearchParamsを使おう

クエリパラメーターを取得する時は、URLSearchParamsインタフェースを使用すると簡単に実装ができます。

# 実装例
```javascript
const searchParams = new URLSearchParams(window.location.search)

const param1 = searchParams.get('param1')
const param2 = searchParams.get('param2')
const param3 = searchParams.get('param3')
```

存在しないキーが指定されていると`null`が返ります。

# 参考
https://maku77.github.io/js/web/search-params.html
Javaで日付をインクリメンタルにフォーマットする方法：IncrementalDateFormatterクラスの使い方


# IncrementalDateFormatterの使い方

この記事では、Javaで日付をインクリメンタルにフォーマットするためのIncrementalDateFormatterクラスの使い方について説明します。このクラスは、指定した初期日付から特定の時間単位ごとに日付をインクリメントし、フォーマットされた日付文字列を生成します。

# クラスの概要
IncrementalDateFormatterクラスは、以下のパラメータを使用して初期化されます。

```
pattern：日付のフォーマットパターン（例："yyyyMMdd-HHmmss"）。
initialDate：初期の日付文字列。
calendarUnit：日付をインクリメントするカレンダーの単位（例：Calendar.HOUR_OF_DAY）。
amount：インクリメントする量。
repeat：インクリメントを繰り返す回数。
```

# 使用例

以下は、IncrementalDateFormatterクラスを使用して日付をインクリメントする方法を示すテストコードです。このテストでは、初期日付を「2024/1/1 0:00」とし、1時間ごとに3回インクリメントします。

```java
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import junit.framework.TestCase;
public class IncrementalDateFormatterTestCase extends TestCase {
    public void test001() throws Exception {
        // 2024/1/1 0:00 から 1時間追加を3回繰り返す
        List<String> expected = new ArrayList<>();
        expected.add("20240101-000000");
        expected.add("20240101-010000");
        expected.add("20240101-020000");
        expected.add("20240101-030000");

        String initialDate = "20240101-000000";
        int calendarUnit = Calendar.HOUR_OF_DAY;
        int amount = 1;
        int repeat = 3;
        IncrementalDateFormatter formatter = new IncrementalDateFormatter("yyyyMMdd-HHmmss", initialDate, calendarUnit, amount, repeat);
        String v;
        int idx = 0;
        while ((v = formatter.next()) != null) {
            System.err.println(v);
            assertEquals(expected.get(idx).trim(), v);
            idx++;
        }
    }
}
```

# コードの説明

## 初期設定

```java
String initialDate = "20240101-000000";
int calendarUnit = Calendar.HOUR_OF_DAY;
int amount = 1;
int repeat = 3;
```

initialDateは、フォーマッタが最初に生成する日付を表します。
calendarUnitは、日付をインクリメントする単位を指定します。ここでは1時間ごとにインクリメントします。
amountは、各インクリメントの量です。ここでは1時間です。
repeatは、インクリメントを繰り返す回数です。ここでは3回インクリメントします。

## インスタンス生成

```java
IncrementalDateFormatter formatter = new IncrementalDateFormatter("yyyyMMdd-HHmmss", initialDate, calendarUnit, amount, repeat);
```

## 日付のインクリメントと検証

```java
String v;
int idx = 0;
while ((v = formatter.next()) != null) {
    System.err.println(v);
    assertEquals(expected.get(idx).trim(), v);
    idx++;
}
```

formatter.next()を呼び出すたびに、次のインクリメントされた日付が返されます。インクリメントが完了するとnullが返されます。
このテストケースは、指定した初期日付から1時間ごとに3回インクリメントされた日付を生成し、期待される結果と比較して正しいことを確認します。

IncrementalDateFormatterクラスは、時間や日付のシミュレーション、テストデータの生成、ログのタイムスタンプ生成など、さまざまな用途に便利です。

# Maven

```xml
<!-- https://mvnrepository.com/artifact/org.nlp4j/nlp4j-core -->
<dependency>
    <groupId>org.nlp4j</groupId>
    <artifactId>nlp4j-core</artifactId>
    <version>1.3.7.12</version>
</dependency>
```


---

以上.
cakephp4 メモ

```
1 css読み込み----------------------------------------------------
C:\php-dev\cakephp\TestPro\webroot\css\admin\bootstrap.css

C:\php-dev\cakephp\TestPro\templates\Admin\index.php
場所：先頭
<?php
echo $this->Html->css("admin/bootstrap.css");
?>

2 javascript読み込み---------------------------------------------
C:\php-dev\cakephp\CiNet\webroot\js\admin\bootstrap.min.js

C:\php-dev\cakephp\TestPro\templates\Admin\index.php
場所：先頭
<?php
echo $this->Html->script("admin/bootstrap.min.js");
?>

3 CakePHPでjavaScriptとCSSファイルを指定した位置で読み込むようにする

以下のように記述すると、それを記述した位置でそのまま読み込まれてしまうため、思い通りの動きにならないことがあります。

 <?= $this->Html->script('mdl-selectfield.min.js') ?>
 <?= $this->Html->css('mdl-selectfield.min.css') ?>
そこで出力したい位置に以下のような指定をしておくことで、その場所に出力させることができます。

例：出力したい位置
<?= $this->fetch('head') ?>
例：出力させたい内容

<?= $this->Html->script('mdl-selectfield.min.js', array('inline' => false, 'block' => 'head')) ?>
<?= $this->Html->css('mdl-selectfield.min.css', array('inline' => false, 'block' => 'head')) ?>
VSCodeの設定どうしてる？

VSCodeユーザーの皆さんは設定はどのようにしていますか？

Macであれば`Cmd + ,`で、Windowsであれば`Ctrl + ,`で設定画面を開くことができます。

しかしVSCodeにはリッチな機能を有するため設定ファイルには大量の項目が存在します。

プライベートでも開発をする（強要はしていない）エンジニアの皆さんは業務用のPCもプライベートのPCも使っていて設定を共有したい時もありますよね。

そんなときに便利に共通の設定を使えるようにするのがこの記事の目的になります。

## 設定ファイルの場所

VSCodeの設定ファイルは、`settings.json`というファイルに記述されています。

このファイルは、どのワークスペースにも適用されるファイル（ユーザー）と各ワークスペース設定の両方をが存在します。

優先順位はユーザーよりもワークスペースの設定が優先されます。

### ユーザー設定

ユーザーの設定は`Cmd + Shift + P`でコマンドパレットを開き、`Preferences: Open Settings (JSON)`を選択すると開くことができます。

jsonなので各項目がkey-valueで記述されています。

ちなみに筆者の設定は以下の感じになっている。

```json
{
  "editor.minimap.enabled": false,
  "editor.wordSeparators": "`~!@#$%^&*()-=+[{]}\\|;:'\",.<>/?　、。！？「」【】『』（）",
  "swaggerViewer.previewInBrowser": true,
  "files.trimFinalNewlines": true,
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,
  "terminal.integrated.tabs.enabled": false,
  "[typescriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "go.toolsManagement.autoUpdate": true
}
```

こだわっている部分はさておいて、いくつか皆さんにも適用しておくと便利な設定を紹介します。

```
  "files.trimFinalNewlines": true,
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,
```

ここで設定しておくと、ファイル保存時に自動で改行や空白を削除してくれます。

ファイルの最後に改行がないとGitの更新時に差分として表れるので、変更したいファイル以外にも変更があるように見えてしまいます。

### ワークスペース設定

ワークスペース設定は、ワークスペースの`.vscode`ディレクトリ内に`settings.json`というファイルを作成することで設定を行うことができます。

ここでは例えば、プロジェクトごとに異なる設定を行いたい場合に使うことができます。

例えば、プロジェクトごとに異なるフォーマッタを使いたい場合などに使うことができます。

```json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}
```

このように設定することで、このワークスペース内でPrettierを使うことができます。

ついでに.vscodeディレクトリに使うextensionsを記述した`extensions.json`を作成しておくと、ワークスペースを開いたときに自動で拡張機能をインストールしてくれます。

```json
{
  "recommendations": [
    "esbenp.prettier-vscode"
  ]
}
```
## まとめ

統一した設定を使うことで、開発効率が上がりますので個人/チームで設定を共有することをおすすめします。
LINEで飲酒記録をつけるツール　【メッセージ⇒スプレッドシートに整理】

私けっこうお酒を飲むのですが、どれくらい飲んでいて、どれくらいお金を使っているのか全く管理できていないんですよね。
そこで、健康と貯蓄を手に入れるため、そろそろちゃんと管理してみようと思いました。

単純にスマホのメモ帳に飲んだ量などをメモっても管理できそうですが、後々分析することを視野にいれるとスプレッドシートに入力した方が良いかなと思います。
でも、スプレッドシートだといちいち開いたり、セルを選択したりするのがめんどくさい。

そこで、LINEからスプレッドシートに入力できるようにGASでツールを作りました。


## 使うとこんな感じ


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3770353/f7de8d2a-e268-0f75-21f1-e198bb2693db.png)

1行目にお酒の名前
2行目に金額
を入れて送信すると、スプレッドシートに記録を残せます。

実際飲み会があるの日に使ってみて気づいたのは、飲み会中にいちいち画面を開いて入力はしないということ。
なので、記録される時間はおかしくなってしまいますが、翌日に記憶がある分を入力して、前日のお酒を飲んだ記録を残す運用方法にしています。
いちいち時間を修正したりする機能をつけて厳密に管理すると面倒に感じるのでシンプル設計にしています。
一旦は1カ月で何を何杯飲んでいくら使ったかが分かれば十分ですからね。


## ソースコード

```js
const LINE_ACCESS_TOKEN = 'あなたのトークン';  // LINE Access Token

function doPost(e) {
  var contents = JSON.parse(e.postData.contents);
  var events = contents.events;
  
  for (var i = 0; i < events.length; i++) {
    var event = events[i];
    if (event.type == "message" && event.message.type == "text") {
      var messageText = event.message.text;
      var splitMessage = messageText.split("\n");

      if (splitMessage.length < 2) {
        sendReply(event.replyToken, "酔っているのですか？完璧な形で入力してください。\n■送信の形式\n1行目：お酒の名前\n2行目：金額(円はつけない)");
        continue;
      }

      var sake = splitMessage[0].trim();
      var price = splitMessage[1].trim();

      if (!isNaN(sake) || isNaN(price)) {
        sendReply(event.replyToken, "酔っているのですか？完璧な形で入力してください。\n■送信の形式\n1行目：お酒の名前\n2行目：金額(円はつけない)");
        continue;
      }
      
      var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("drinkingLog");
      var date = new Date();
      
      sheet.appendRow([Utilities.formatDate(date, Session.getScriptTimeZone(), 'yyyy/MM/dd'), 
                       Utilities.formatDate(date, Session.getScriptTimeZone(), 'HH:mm:ss'), 
                       sake, 
                       price]);
      
      var replyMessage = `${sake}　${price}円で記録しました`;
      sendReply(event.replyToken, replyMessage);
    }
  }
  
  return ContentService.createTextOutput(JSON.stringify({ content: 'post ok' })).setMimeType(ContentService.MimeType.JSON);
}

function sendReply(replyToken, message) {
  var url = 'https://api.line.me/v2/bot/message/reply';
  var payload = JSON.stringify({
    replyToken: replyToken,
    messages: [{
      type: 'text',
      text: message
    }]
  });
  
  var options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': 'Bearer ' + LINE_ACCESS_TOKEN,
    },
    payload: payload
  };
  
  UrlFetchApp.fetch(url, options);
}

```
GASの画面にこちらを貼付け、あたなのトークンを入力します。
そのあとスプレッドシートで「drinkingLog」というシートを作っておきます。
デプロイしてURLをLINE messagingAPIのWebhookの設定の所に入れたら使えます。

一応送信されてくるテキストのチェックはやっていて、規則通りに入れていない場合は「ちゃんと入れなさい」という旨のメッセージが返ってきます。
1行目にお酒の名前、2行目に金額を規則通りに入れて送信したらスプシに入力される仕組みなので、正しく入力してくださいね。


## これからやること
記録を残すツールはこれでできました！
まずは一カ月間使ってみてスプシに記録される情報を基に、今後のお酒への向き合い方を考えたいと思います！！


## （おまけ）過去に作成したお酒に関連するツール


https://qiita.com/YopiBee9/items/4e4db0bb00ff3bcc8c58

https://qiita.com/YopiBee9/items/6ea7a501715c26df6c14
Jetpack Compose の基本のメモ#3 ~コンポーザブルを再利用する~

### [コンポーザブルを再利用する](https://developer.android.com/codelabs/jetpack-compose-basics?hl=ja#4)
+ 再利用可能な小さいコンポーネントを作成すると、アプリで使用する UI 要素のライブラリを簡単に構築できる
+ ベストプラクティスは、デフォルトでは空の修飾子を割り当てた修飾子パラメータを関数に含めること
+ →とりあえず、引数にmodifierを持たせておく

そうですね。例えば、`Greeting("Android")`を何度も呼び出すことで同じ結果を得ることは可能です。しかし、これには以下のようなデメリットがあります。

### 再利用可能なコンポーザブルのメリット

1. **コードの冗長性を避ける**:
   - 毎回 `Greeting("Android", modifier = Modifier.padding(innerPadding))` のように同じコードを繰り返し書く必要がなくなります。再利用可能なコンポーザブルを作成することで、コードの重複を避け、メンテナンスを容易にします。

2. **可読性の向上**:
   - コンポーザブルを小さな部品に分割し、それを再利用することで、コードの可読性が向上します。例えば、`MyApp` コンポーザブル内に必要なロジックをまとめることで、メインのレイアウトコードが簡潔になります。

3. **一貫性の確保**:
   - 再利用可能なコンポーザブルを使用することで、同じUI要素の一貫性を保つことができます。全ての場所で同じコンポーネントを使用することで、アプリ全体のデザインが統一されます。

### 具体例

#### 1. `Greeting` を直接何度も呼び出す場合

```kotlin
@Composable
fun MainContent() {
    Column {
        Greeting(name = "Android", modifier = Modifier.padding(innerPadding))
        Greeting(name = "iOS", modifier = Modifier.padding(innerPadding))
        Greeting(name = "Windows", modifier = Modifier.padding(innerPadding))
    }
}
```

#### 2. `MyApp` を使用する場合

```kotlin
@Composable
fun MyApp(modifier: Modifier = Modifier) {
    Surface(
        modifier = modifier,
        color = MaterialTheme.colorScheme.background
    ) {
        Column {
            Greeting("Android")
            Greeting("iOS")
            Greeting("Windows")
        }
    }
}

@Composable
fun MainContent() {
    MyApp(modifier = Modifier.padding(innerPadding))
}
```

### 結論

`MyApp` を使用することで、コードが簡潔になり、再利用性が向上します。特に大規模なプロジェクトでは、再利用可能なコンポーザブルを作成することで、メンテナンスが容易になり、全体のコード品質が向上します。

例えば、`MyApp` の中で色やパディングの設定を一括して行い、各 `Greeting` コールの際に同じ設定を適用することができます。これにより、UIの一貫性を保ちつつ、コードをシンプルに保つことができます。

```kotlin
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(text = "Hello, $name!", modifier = modifier)
}

@Composable
fun MyApp(modifier: Modifier = Modifier) {
    Surface(
        modifier = modifier,
        color = MaterialTheme.colorScheme.background
    ) {
        Column {
            Greeting("Android", Modifier.padding(8.dp))
            Greeting("iOS", Modifier.padding(8.dp))
            Greeting("Windows", Modifier.padding(8.dp))
        }
    }
}
```

このように、`MyApp` コンポーザブルを使用することで、全ての `Greeting` に同じスタイルを適用し、コードの重複を避けることができます。
TCP/IPの知見を深める④MACアドレス編

MACアドレスについて
--
前回紹介した通り、宛先MACアドレスと送信元MACアドレスがイーサネットにはフィールドとして存在していて、
二つの存在はイーサネットにおいて最も重要なフィールドになっている

構成されているMACアドレスはイーサネットネットワークに接続している端末の識別IDの役割を担っており、ハイフンやコロンで区切られている6バイト(48ビット)で16進数で表記されている

**書き込み**
=
物理アプライアンスであれば、物理ＮＩＣの製造の際にＲＯＭに書き込まれ、仮想アプライアンスであればデフォルトからハイパーバイザーから仮想ＮＩＣに対して割り当てられる

https://www.cman.jp/network/term/mac/

3種類のMACアドレス
--
通信の宛先によってイーサネットネットワークの通信が3種類に分けられる
その際宛先MACアドレスにセットされるMACアドレスが異なる

ユニキャスト
-----
WEBやメール送信の際、つまり1:1の場合はユニキャストに分類される
送受信するMACアドレスはそれぞれのMACアドレスに設定される

ブロードキャスト
---
同じイーサネットネットワークに接続している端末の全てに送信するつまり1:nの場合
このような同じイーサネットネットワークの全ての端末が受信する範囲の事をブロードキャストドメインと呼ばれる
**ARP**(address Resolution Protocol)のようにネットワーク上の全ての端末に問い合わせが出来るプロトコルを使用している
ブロードキャストの場合、送信元のmacアドレスは送信端末のMACアドレスではあるが、宛先には６バイトがすべて１という特別なもの使用している

マルチキャスト
--
マルチキャストの場合、1:nをシチュエーションをもとに設計されているが、ブロードキャストとは違い特定のグループにのみ送信される仕組みになっている。
ブロードキャストの場合、範囲内の端末すべてに送信してしまうが、マルチキャストはグループに入っているという特定の端末にのみ一斉送信できる強みがあり、トラフィックの効率が良い
送信元は送信端末のMACアドレスを使用し、宛先のMACアドレスはネットワーク層で使用しているIPアドレスによって変わる


:::note warn
youtubeはマルチキャストではなくユニキャストらしい
参考サイト👇

https://nw.seeeko.com/archives/multicast

:::
ざっくりAmazon ElastiCacheについて

# Amazon ElastiCacheとは

## 概要
Amazon ElastiCacheは、Amazon Web Services（AWS）が提供するインメモリデータストアおよびキャッシュサービスです。高スループット、低レイテンシのデータアクセスを実現するために、RedisおよびMemcachedの2つのオープンソースエンジンをサポートしています。

## 主な機能
1. **インメモリキャッシング**: データをメモリ内にキャッシュすることで、データベースやアプリケーションのパフォーマンスを向上させます。
2. **高可用性**: マルチAZ（アベイラビリティゾーン）配置や自動フェイルオーバーにより、高可用性を実現します。
3. **スケーラビリティ**: クラスターのスケールアウトおよびスケールインが容易で、需要に応じてリソースを調整できます。
4. **セキュリティ**: VPC（Virtual Private Cloud）内でのデプロイメント、暗号化、IAM（Identity and Access Management）によるアクセス制御が可能です。
5. **自動バックアップ**: 自動スナップショットや手動スナップショットをサポートし、データのバックアップとリストアが容易です。

## メリット
1. **パフォーマンス向上**: インメモリキャッシングにより、データベースのクエリやアプリケーションのレスポンス時間を大幅に短縮できます。
2. **管理の簡素化**: AWSがインフラストラクチャの管理を行うため、ユーザーはキャッシュの設定や運用に集中できます。
3. **高可用性と耐障害性**: 自動フェイルオーバーやマルチAZ配置により、システムの可用性が向上します。
4. **スケーラビリティ**: クラスターのサイズを動的に変更できるため、トラフィックの増減に柔軟に対応できます。
5. **セキュリティ**: データの暗号化やアクセス制御により、セキュリティが強化されています。

## デメリット
1. **コスト**: 高性能なインメモリキャッシュのため、使用量に応じてコストが増加する可能性があります。
2. **学習コスト**: RedisやMemcachedの知識が必要であり、設定や運用に関する学習コストが発生します。
3. **データ永続性の欠如**: インメモリキャッシュの特性上、データの永続性が保証されないため、重要なデータの保存には適していません。

## 使い方の例
### Redisクラスターの作成
以下は、AWS CLIを使用してRedisクラスターを作成する例です。
```bash:例
aws elasticache create-replication-group \
    --replication-group-id my-redis-cluster \
    --replication-group-description "My Redis Cluster" \
    --engine redis \
    --cache-node-type cache.t2.micro \
    --num-node-groups 1 \
    --replicas-per-node-group 1 \
    --automatic-failover-enabled
    
```


### Memcachedクラスターの作成
以下は、AWS CLIを使用してMemcachedクラスターを作成する例です。
```bash:例
aws elasticache create-cache-cluster \
    --cache-cluster-id my-memcached-cluster \
    --engine memcached \
    --cache-node-type cache.t2.micro \
    --num-cache-nodes 1

```

## まとめ
Amazon ElastiCacheは、高性能なインメモリキャッシュサービスとして、アプリケーションのパフォーマンス向上やデータベースの負荷軽減に役立ちます。高可用性、スケーラビリティ、セキュリティなどの特長を持ち、AWSの他のサービスとシームレスに統合できるため、現代のクラウドベースのアプリケーションにおいて重要な役割を果たしているということが分かった。
AppIntentsでインテントを実行する前にユーザーに尋ねる



## requestConfirmation()とは
この関数を使うとPerform()の前にDialogなどを出してユーザーに尋ねることができる。
https://developer.apple.com/documentation/appintents/appintent/requestconfirmation()

以下のビデオで例として紹介されていていたのは、本を買うというインテントの途中で値段や本の情報のView,Dialogとともに、注文するかを決定するボタンを表示するものだった。(26:23)
https://developer.apple.com/jp/videos/play/wwdc2022/10032

## 内容
#### iOS18からはrequestConfirmation(conditions:actionName:dialog:)の形で書く必要がある。

### conditions


### actionName
ボタンの名前を指定する。名前はStringで自由に決められるのではなく、テンプレートのようなものの中から選ぶ。
https://developer.apple.com/documentation/appintents/confirmationactionname

### dialog
表示、読み上げられる文章を指定する。
【Python】tkinterでText領域にJPEG画像をアップロードする方法

## はじめに
tkinterにてPillowを使用してText領域にJPEG画像をアップロードする方法を紹介します。
Canvas領域に画像をアップロードする記事は既に投稿されていましたが、Text領域に画像をアップロードする記事は見つからなかったので、Text領域に画像をアップロードする際の参考になれば幸いです。


#### 開発環境
・WSL2/Ubuntu環境
・Python: 3.10.12

## Pillowを使用しText領域にJPEG画像をアップロードする方法

```Sample_Uploadimagefortext.py:
import tkinter as tk
from tkinter import Text, filedialog
from PIL import Image, ImageTk  # type: ignore


# upload image for text area
def Sample_Upload_Imagefile():
    filepath = filedialog.askopenfilename(filetypes=[("Image files", ".jpg")])
    if filepath:
        image_jpeg = Image.open(filepath)
        image_jpeg.thumbnail((400, 400))
        image_for_tkinter = ImageTk.PhotoImage(image_jpeg)
        area_text.image_create(tk.END, image=image_for_tkinter)
        area_text.image = image_for_tkinter


# configure root
root = tk.Tk()
root.title("ColorText")
root.geometry("800x600")

# configure menu
bar_menu = tk.Menu(root)
list_upload = tk.Menu(bar_menu, tearoff=0)
bar_menu.add_cascade(label="Upload", menu=list_upload)
list_upload.add_command(label="Image", command=Sample_Upload_Imagefile)
root.config(menu=bar_menu)

# make text
area_text = Text(root, wrap="word", undo=True)
area_text.pack(fill="both", expand=True)

# display window
root.mainloop()

```

#### JPEG画像をText領域にアップロードする流れ
①UploadタブのImageをクリック
②fileを選択するdialogが表示されるので、何らかのJPEGファイル(拡張子が.jpg)を選択
③Text領域に選択したJPEGファイルが出力

## 参考文献
本記事は以下情報を参考にして執筆しました。

https://mulberrytassel.com/python-practice-pil-2/
ざっくりNGINXについて

# NGINXとは

## 概要
NGINX（エンジンエックス）は、高性能なHTTPサーバーおよびリバースプロキシサーバーとして広く使用されているオープンソースソフトウェアです。もともとはロシアのエンジニア、Igor Sysoevによって開発されました。

## 主な機能
1. **HTTPサーバー**: 静的コンテンツの配信や動的コンテンツの処理を行います。
2. **リバースプロキシ**: クライアントからのリクエストをバックエンドサーバーに転送し、レスポンスをクライアントに返します。
3. **ロードバランシング**: 複数のバックエンドサーバーにトラフィックを分散させ、システムの負荷を均等にします。
4. **SSL/TLSターミネーション**: SSL/TLS暗号化通信の終端処理を行い、セキュアな通信を実現します。
5. **キャッシング**: 静的および動的コンテンツのキャッシュを行い、レスポンス時間を短縮します。

## メリット
1. **高性能**: 非同期イベント駆動アーキテクチャにより、高いパフォーマンスとスケーラビリティを実現します。
2. **軽量**: メモリ使用量が少なく、リソース効率が高いです。
3. **柔軟な設定**: 設定ファイルがシンプルで、柔軟にカスタマイズ可能です。
4. **モジュール性**: 必要な機能をモジュールとして追加でき、拡張性が高いです。
5. **広範なサポート**: 多くのオペレーティングシステムで動作し、コミュニティと商用サポートが充実しています。

## デメリット
1. **学習コスト**: 高度な設定やチューニングには専門知識が必要です。
2. **動的コンテンツの処理**: 動的コンテンツの処理はバックエンドサーバーに依存するため、設定が複雑になることがあります。

## 使い方の例
### 基本的な設定
以下は、NGINXの基本的な設定例です。
``` NGINX:例
server {
    listen 80;
    server_name example.com;
    location / {
        root /var/www/html;
        index index.html index.htm;
    }
    location /api/ {
        proxy_pass http://backend_server;
    }
}
```

### SSL/TLSの設定
SSL/TLSを使用する場合の設定例です。
```NGINX:例
server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    location / {
        root /var/www/html;
        index index.html index.htm;
    }
}
```

## まとめ
NGINXは、高性能で柔軟なHTTPサーバーおよびリバースプロキシサーバーとして、多くのウェブサイトやアプリケーションで利用されている。状況に応じてカスタマイズができる。
リュカ数を求めるプログラム

リュカ数を求めるプログラムをC++で実装します。実行環境はVisual Studio Community 2022バージョン17.10.1とC++20です。

# リュカ数の定義
リュカ数とは、初項を2、2項目を1とし、それ以降の項が直前の2つの項の和になっている数列の項と定義されています。$n$を正の整数とすると以下の数式で表すことが出来ます。
```math
\displaylines{
L_1 = 2\\
L_2 = 1\\
L_{n+2} = L_n + L_{n+1}
}
```

# リュカ数を計算するプログラム
リュカ数を求めるプログラムを以下に示します。
```C++:Lucas.cpp
#include <iostream>
#include <vector>

int main()
{
	int n; //出力する項数
	std::cin >> n;

	if (n == 1)
	{
		std::cout << 2 << std::endl;
	}
	else if (n == 2)
	{
		std::cout << 2 << std::endl;
		std::cout << 1 << std::endl;
	}
	else if (n >= 3)
	{
		std::vector<long long> lucas(n);
		lucas.at(0) = 2; //初項に2を設定
		lucas.at(1) = 1; //2項目に1を設定

		for (int i = 2; i < n; i++)
		{
			lucas.at(i) = lucas.at(i - 1) + lucas.at(i - 2); //直前の2項の和を計算する
		}

		for (auto x : lucas)
		{
			std::cout << x << std::endl;
		}
	}
	else
	{
		return 0; //入力された値が正の整数でなければプログラムを終了する
	}
}
```
実行すると整数$n$の入力が求められるので、正の整数を入力します。$n$を入力したら$n$項目までのリュカ数が表示されます。

# リュカ数と黄金比
リュカ数の性質として、$n$が大きくなると、リュカ数の隣接する2項の比$L_{n+1}/L_n$は黄金比に収束することが知られています。この性質をプログラムで確認してみます。なお、C++では標準ライブラリのnumbersを用いて黄金比の値を取得できます。黄金比の値は1.61803のようです。

C++における黄金比の値の定義
```C++:GoldenRatio.cpp
#include <iostream>
#include <numbers>

int main()
{
	std::cout << std::numbers::phi;
    //1.61803
}
```

リュカ数列における隣接項の比の推移

```C++:Lucas.cpp
#include <iostream>
#include <vector>

int main()
{
	std::vector<long long> lucas(21); //21項のリュカ数列を格納するための配列
	lucas.at(0) = 2;
	lucas.at(1) = 1;

	for (int i = 2; i <= 20; i++)
	{
		lucas.at(i) = lucas.at(i - 1) + lucas.at(i - 2);
	}

	for (int i = 1; i <= 20; i++)
	{
		std::cout << double(lucas.at(i)) / lucas.at(i - 1) << std::endl; //リュカ数列の隣接する2項を求める
	}
}
```

出力
```
0.5
3
1.33333
1.75
1.57143
1.63636
1.61111
1.62069
1.61702
1.61842
1.61789
1.61809
1.61801
1.61804
1.61803
1.61804
1.61803
1.61803
1.61803
1.61803
```
1.61803に収束していくことがわかります。

# 参考
https://ja.wikipedia.org/wiki/%E3%83%AA%E3%83%A5%E3%82%AB%E6%95%B0
Goのジェネリクスを試してみた

## はじめに
Goのジェネリクスがよく理解できていなかったので、調べてみました。

## ジェネリクス導入前

int型、float64型のそれぞれで同じ処理をする関数を定義しています。
型が異なるので、両者を一緒に計算したり、戻り値で返したりすることができません。

```go
package main

import "fmt"

// intスライスの合計を計算する関数
func sumIntSlice(slice []int) int {
	sum := 0
	for _, v := range slice {
		sum += v
	}
	return sum
}

// float64スライスの合計を計算する関数
func sumFloat64Slice(slice []float64) float64 {
	sum := 0.0
	for _, v := range slice {
		sum += v
	}
	return sum
}

func main() {
	intSlice := []int{1, 2, 3, 4, 5}
	floatSlice := []float64{1.1, 2.2, 3.3, 4.4, 5.5}

	fmt.Println("Sum of int slice:", sumIntSlice(intSlice))
	fmt.Println("Sum of float64 slice:", sumFloat64Slice(floatSlice))
}
```

## ジェネリクス導入後

Addable型を定義して、それをsumSlice関数の型パラメータとして指定しています。
引数もAddable型のスライス、戻り値もAddable型とします。
こうすることで、int型・float64型どちらも1つの関数で処理することができ、コードの再利用性が向上します。

```go
package main

import "fmt"

// 制約として、加算が可能な型を指定
type Addable interface {
	int | float64
}

// ジェネリクスを使ったスライスの合計を計算する関数
func sumSlice[T Addable](slice []T) T {
	var sum T
	for _, v := range slice {
		sum += v
	}
	return sum
}

func main() {
	intSlice := []int{1, 2, 3, 4, 5}
	floatSlice := []float64{1.1, 2.2, 3.3, 4.4, 5.5}

	fmt.Println("Sum of int slice:", sumSlice(intSlice))
	fmt.Println("Sum of float64 slice:", sumSlice(floatSlice))
}
```

## 動かしてみる

```zsh
go run main.go

Sum of int slice: 15
Sum of float64 slice: 16.5
```
Power Automateで子フローを使わずに複数のフローを値渡ししながら連続で動作させる

## こんな方むけの記事です
毎日一連のフローを順番に動作させたり、複雑な処理は別の子フローにまとめたいようなシチュエーションで、DLPポリシーで利用できないような方にいかがでしょう？
子フローはHTTPコネクターがDLPポリシーで使用できないと使えないので、意外とふさがれてしまっている会社さんは多いかもしれません。フローのエラー記録もついでに行おうと思います。

このアイディアは、子フローを使わず、順番に実行できない？というQ&Aが掲載されているのを見て試してみたくなりました。

https://qiita.com/yamaxzira/questions/bef88c435fa1c6e8627c

### SPOリストを使う
まず、flowControlというSPOリストを用意しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/6d5de811-8e33-ef6e-fc0b-1bfa79ecab88.png)
タイトル列は隠し、ID、更新日時、登録日時を表示させました。
status列は数値型で。value1、value2、err列はテキスト型で新たに追加しました。

### 動作のイメージ
最初のトリガーは定期実行でキックフローにSPOリストへ新規行を作るところから。その後リストの更新をきっかけに自分の番が来たら実際に処理を実行するイメージです。

1. キックフロー0　➡ リストにstatus 0を行追加

2. Flow1がリスト更新を検知　➡処理をして結果をvalue1に更新、status1に更新

3. Flow2がリスト更新を検知　➡処理をしてvalue1を使い結果をvalue2に更新、status2に更新


## とにかくやってみよう。
### キックフロー0
何か適当な値を渡していくほうが面白いので、「タイトル」にyamada と入れてみました。後続のフローにこの私を受け渡しつつ加工してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/6a7c5845-ed7c-f9fc-936f-0dfa9696add2.png)

### フロー1
トリガーは「項目が作成されたとき」を使いました。
errに値が入っていればそこで終了。これは無限ループ防止です。
エラーがなければ処理をして、その結果をvalue1に入れます。処理が進んだことを示すためにstatus列を1に更新します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/1294c6f2-ae97-243d-2590-49c779a98111.png)

### フロー２
フロー２のトリガーは、「アイテムが作成または変更されたとき」に変更してあります。あとは結果をvalue2に入れる部分だけ変更してあります。条件部分は無限ループ防止です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/51661a35-0d51-5435-be06-d80d7d621d36.png)
ちなみに、このフローを保存しようとすると、このような警告が出ます。
フローの中でトリガーと同じSPOリストを更新しようとしているからですね。条件部分はこの無限トリガーループを防止しようとしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/27e75814-3643-e075-c9c3-0c29fd2ee8f7.png)


## いちかばちかの実行だ！
。うまく動いてくれるかどうか。トリガー0を実行してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/8e60391a-4140-251a-cf8e-6c2502e70876.png)

あれ？フロー１でエラー判定が空なら続行のはずが、「いいえ」にわたって止まってました。リストの空のカラムは何も入れないのとは違うらしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/d3fa12d5-8199-6f8c-c7ef-d5dd9f9f3e71.png)
フロー１とフロー２の条件部分に、空ではなく「null」と等しいという条件を追加しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/40a0eff6-7f52-cdf0-a1fa-34b1b2ec8d75.png)
そういえば、フロー２のほうは、statusが1の時だけ動いてくれないとこまるので、and条件でstatusの部分を加えました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/12129db1-d4f2-8d48-9106-3e00cc2a16a9.png)

### 気を取り直して、再度チャレンジ
気を取り直して、キックフロー0を実行します。
SPOリストにID2が追加。最初のステータスは0。しばらく待ってSPOリストを更新してみると、ステータスが2まで進んで、value1、value2にも処理結果が入っています。value2の値は、value1を使ったものなので、最初にトリガーに与えた値が順番に渡されたことを意味します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/832b7352-9b25-5a7d-b59e-73250f247812.png)

## まとめ
というわけで、子フローを使えない場合に、SPOリストの更新をトリガーにして似たようなことが実現できることがわかりました。結果の記録や実行時間もSPOリストに記録しておけるので、意外と良い使い方なのかもしれません。

SPOリストの空の値を条件にする場合には、式でnullを与えてやらないと比較できないことも発見でした。
いろいろ応用が利きそうなので、よかったら使ってやってください。
クエリパラメーターの作成にはURLSearchParamsを使おう

クエリパラメーター付きのURLパスを作成する時はどのように実装していますか？
まさか、文字列結合で作成しているということはありませんよね？

以前このような実装に出会したことがありますが、クエリパラメーターの数も多く非常に読みにくかった思い出があります。

```javascript:sample1.js
const param1 = value1 !== undefined ? `param1=${value1}` : ''
const param2 = value2 !== undefined ? `param2=${value2}` : ''
const param3 = value3 !== undefined ? `param3=${value3}` : ''

const params = [
  param1,
  param2,
  param3
].filter((param: string) => param != '').join('&')

const pathWithParams = `/search?${params}` 
```

さらに、予期せぬ値がパラメーターのバリューに入る可能性もあり、脆弱なコードにもなっているため推奨できる実装ではありません。例えば、`value1`が`null`であるとき、`param1=null`になる可能性があります。

そのため、クエリパラメーター付きのURLを作成するときは、URLSearchParamsインタフェースを使って実装することをおすすめします。

sample1.jsのコードを使って表現すると、このようになります。

```javascript
const params = {}
if(value1) params[param1] = value1
if(value2) params[param2] = value2
if(value3) params[param3] = value3

const urlSearchParams =  new URLSearchParams(params).toString()
const pathWithParams = `/search?${urlSearchParams}` 
```

三項演算子でなくif文に変更したことと、`filter`と`join`を取り除き`URLSearchParams`を採用したことで読みやすくなったのではないでしょうか。
`param1=null`となることもなくなったので、元のコードより安全になりました。
ざっくりgRPCとREST APIの違いとメリット・デメリット

## gRPCとは
gRPCはGoogleが開発した高性能なRPC（Remote Procedure Call）フレームワークです。Protocol Buffers（protobuf）というシリアライズフォーマットを使用して、効率的な通信を実現します。

## REST APIとは
REST（Representational State Transfer）は、HTTPプロトコルを基盤としたアーキテクチャスタイルです。リソースをURLで指定し、HTTPメソッド（GET、POST、PUT、DELETEなど）を使用して操作を行います。

## gRPCのメリット
1. **高性能**: バイナリフォーマットのProtocol Buffersを使用するため、データのシリアライズとデシリアライズが高速です。
2. **双方向ストリーミング**: クライアントとサーバー間でリアルタイムにデータをストリーミングできます。
3. **多言語サポート**: gRPCは多くのプログラミング言語をサポートしています。
4. **強力な型システム**: Protocol Buffersにより、厳密な型チェックが可能です。

## gRPCのデメリット
1. **学習コスト**: Protocol BuffersやgRPCの概念を理解するための学習コストが高いです。
2. **ブラウザサポートの制限**: gRPCは直接ブラウザから利用するのが難しく、通常はgRPC-Webを使用する必要がある。
3. **デバッグの難しさ**: バイナリフォーマットのため、デバッグが難しい場合がある。

## REST APIのメリット
1. **シンプルで理解しやすい**: HTTPプロトコルを基盤としているため、広く理解されています。
2. **広範なサポート**: ほとんどのプログラミング言語とフレームワークでサポートされています。
3. **デバッグが容易**: テキストベースのJSONを使用するため、デバッグが容易です。
4. **ブラウザとの互換性**: 直接ブラウザから利用可能です。

## REST APIのデメリット
1. **パフォーマンスの制約**: テキストベースのJSONを使用するため、データのシリアライズとデシリアライズが遅くなることがあります。
2. **リアルタイム通信の制限**: HTTP/1.1では双方向通信が難しく、WebSocketなどの別の技術が必要です。
3. **スキーマの柔軟性**: JSONはスキーマレスであるため、型の厳密なチェックが難しいです。

## まとめ
gRPCとREST APIはそれぞれ異なる用途に適しています。高性能でリアルタイム通信が必要な場合はgRPCが適しており、シンプルで広くサポートされているAPIが必要な場合はREST APIが適しています。gRPC極めたいな。
Typescriptの関数の引数optionalになりがち問題

# Typescriptの関数の引数optionalになりがち問題

## 読者の問題提起と解決策の提案

TypeScriptで関数を定義する時、引数をオプショナル（optional）にすることが多いですよね。便利な機能ですが、場合によっては予期しない動作を引き起こすことがあります。この記事では、この問題を解決する方法を具体例を通じて紹介します。

## 概要

### 関数の引数をオプショナルにする問題

TypeScriptでは、関数の引数をオプショナルにできます。しかし、これによって関数が予期しない動作をしたり、不正な引数が渡されたりすることがあります。

### 使用技術

- TypeScript

## 具体例と詳細説明

### 例1: 単純なSMS送信関数

まず、単純なSMS送信関数を見てみましょう。

```typescript
const greatToSms = ({ me, to, toSms, text }: { me: string; to: string; toSms: PhoneNumber; text: string }) => {
    sendToSms({ to: toSms, text: `Hi ${to}, ${me} says: ${text}` })
}

const sendToSms = ({ to, text }: { to: string; text: string }) => {
  console.log(`Sending SMS to ${to} with text: ${text}`)
}
```

この関数は正しく動作しますが、仕様変更に対応する必要が出てくることがあります。

### 例2: SMSまたはEmail送信関数

次に、SMSだけでなくEmailにも対応するように仕様変更があったとしましょう。

```typescript
const greatToSmsOrEmail = ({
  me,
  to,
  sms,
  email,
  text,
}: { me: string; to: string; sms?: PhoneNumber; email?: Email; text: string }) => {
  if (sms) {
    sendToSms({ to: sms, text: `Hi ${to}, ${me} says: ${text}` })
  }
  if (email) {
    sendToEmail({ to: email, text: `Hi ${to}, ${me} says: ${text}` })
  }
}
```

この実装でも動作しますが、予期しない動作や不正な引数が発生する可能性があります。

:::note alert


実際のプロダクトでは実装が楽だからといって、このように書かれることが多いですが、かなり危険です。筆者は実務で、このコードのように`sms`と`email`が両方nullになってしまい、想定された動作をせず機能が動かないというケースを見てきました。
:::

### 解決方法

以下のコードでは、引数をより厳密に定義しています。

```typescript
const greatToSmsOrEmail = ({
  me,
  to,
  sms,
  email,
  text,
}: { me: string; to: string; text: string } & ({ sms: PhoneNumber; email?: never } | { email: Email; sms?: never })) => {
  if (sms) {
    sendToSms({ to: sms, text: `Hi ${to}, ${me} says: ${text}` })
  }
  if (email) {
    sendToEmail({ to: email, text: `Hi ${to}, ${me} says: ${text}` })
  }
}
```

この方法により、関数の引数が厳密に管理され、予期しない動作を防ぐことができます。

:::note info


このように実装することで、以下のような実装ミスが発生した場合でも、TypeScriptの型エラーで防ぐことができます。
:::

```typescript
if (sms) {
  sendToSms({ to: sms, text: `Hi ${to}, ${me} says: ${text}` })
}
if (email) {
  sendToEmail({ to: sms, text: `Hi ${to}, ${me} says: ${text}` }) // 型エラーが発生
}
```

## メリット・デメリット

### メリット

- 厳密な型定義により、予期しない動作を防止
- 不正な引数の代入を防ぐ

### デメリット

- コードが少し複雑になる

## 総括と結論

TypeScriptの関数において引数をオプショナルにすることは便利ですが、仕様変更や予期しない動作を防ぐために、引数を厳密に定義する方法も検討する価値があります。型定義をしっかり行いましょう！

## 参考記事

- [TypeScript公式ドキュメント](https://www.typescriptlang.org/docs/)
- [TypeScriptの型システムについて](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html)

この記事を通して、TypeScriptの関数引数をより適切に扱う方法を学び、プロジェクトでの活用を目指しましょう。
Arc 入門

# はじめに

普段はChromeを使っているのですが、動作が重くて...というときにArcというブラウザがあるのを知り、試してみました。

https://arc.net/downloaded

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/d822ea96-c6c9-0afe-9e25-ab3f4fb70b1f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/508eb7ea-3899-bf85-5c1e-7b1477ba3f01.png)

# Arc

ひとまず、使ってみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/d0c5f519-4ed2-993e-8575-e2fca07ea4af.png)

Chromeと比較すると、動作が軽く良さそうでした。
- Tabが無駄に増えない
- 作業ごとにSpaceという単位で区切ることができる
- Split Viewで左右に表示できて見やすい
- 動作が軽い
- 複数アカウントの切り替えが簡単
AWS IoT Enterprise Buttonの歴史を軽く振り返る

## はじめに
初めまして。10月にドラゴンボールの新作のゲームが発売するので今からワクワクしている [yakiniku0220](https://twitter.com/yakiniku040220)です。

去年の年末にこのような記事が公開されました。

https://zenn.dev/showm001/articles/2023-12-22-01

> AWS will discontinue AWS IoT 1-Click service from December 16, 2024 onwards.

なん・・・だと・・・

ここまで衝撃を受けている理由としては、上記記事が公開される前に私自身がAWS IoT Enterprise Buttonの記事を書いていたからです。

https://qiita.com/yakiniku0220/items/ecb89f7bb72fa07a76b0

なので最後に何か作ろうと思っていましたが記事をよく見てみると。

> Firstly, your access to AWS IoT 1-Click service from the AWS Management Console will be retained until May 15, 2024. On May 16, 2024, AWS will discontinue access to AWS IoT 1-Click service from the AWS Management Console.

あ、AWS IoT 1-clickがすでに使えなくなっている。。。

ということで今回はAWS IoT Enterprise Buttonの歴史を軽く振り返ればと思います。

## 2015年
### Amazon Dash Button発売の発表
2015年3月31日（現地時間）に1プッシュで日用品が発注できるAmazon Dash Buttonの発表がされました。
前年4月からAmazonFresh会員向けに提供している、音声あるいはバーコードの読み取りで商品を発注するAmazon Dashを手軽にしたものになっています。

### 正式販売開始
2015年7月ごろからAmazon Dash Buttonが一般消費者向けに正式に販売開始されました。 洗剤、ペットフード、紙製品などの日用雑貨が対象でした。

## 2016年
### 日本でも発売
2016年12月に日本でもAmazon Dash Buttonが発売されました。

## 2017年
### AWS IoT Enterprise Buttonの登場
AWS IoT Enterprise ButtonがAmazon re:Invent 2017で発表されました。

### AWS IoT 1-Click
上記イベントのKeynoteで新サービスであるAWS IoT 1-Clickの発表もありました。
AWS IoT 1-Clickの特徴として、複数のデバイスのAWS Lambdaトリガーをワンクリックで作成可能にすることができました。

### 新ブランドの追加
マルちゃんや、ハッピーターンなど新ブランドが74種追加されました。
これにより100種類以上のブランドがDash Buttonひとつで注文できるようになりました。

## 2018年
### 拡張機能の追加
AmazonはDash Buttonの機能を拡張し、複数の商品を設定できるモデルや、スマートフォンアプリを通じてカスタマイズできる機能を追加しました。
さらに、Dash Replenishment Service (DRS)を導入し、他のスマートデバイスにも自動補充機能を提供しました。

## 2019年
### Amazon Dash Buttonのサービスが終了
AmazonはDash Buttonの販売を終了すると発表しました。

## 2023年
AWS IoT 1-Clickが2024年12月16日にサービスが終了すると発表がありました。
2024年の5月ごろにはAWSのコンソールからアクセスできないようになるとのことです。

## まとめ
軽くAWS IoT Enterprise Button（Amazon Dash Button）の歴史を振り返ってみましたが、個人的に前職の勤怠をAWS IoT Enterprise Buttonでやっていたこともあり、サービス終了するのが残念です。
開発コストも低かったので、個人的にはいろんなものを作ってみたかったなという後悔が少しあります。

## 最後に
株式会社HRBrainでは新しいメンバーを募集中です。
興味がある方は下記のリンクから宜しくお願い致します。

https://www.hrbrain.co.jp/recruit

## 参考文献
https://www.itmedia.co.jp/news/articles/1504/01/news076.html
https://dev.classmethod.jp/articles/re-invent-2017-news-iot-1-click/
https://dev.classmethod.jp/articles/aws-reinvent-aws-iot-button/
https://gigazine.net/news/20161219-amazon-dash-button-teardown/
https://hackaday.com/2019/08/27/the-amazon-dash-button-a-retrospective/
https://d3.harvard.edu/platform-rctom/submission/dashing-into-a-digital-future-with-the-amazon-dash/
https://www.gizmodo.jp/2017/06/amazon-dash-button-new.html
https://www.businessinsider.jp/post-186439
https://dev.classmethod.jp/articles/aws-end-of-service-2024/
[Excel]エクセル簡単計算書のいい書き方

# はじめに
JTC中心に、Excelでメカ系の設計計算を使うことは多い。
引き継ぎしやすい計算書、後で見返しやすい計算書をつくるにあたっての私が意識しているルールを紹介していく。

エンジニアに嫌われ者のExcelであるが、操作の簡単さと普及率の高さ故にある意味最適ツールでもある。

# ルール
## 単位と値・数式の根拠を書け
以下のキャプチャは設計書の例である。
A列にパラメータの名前、B列に数値、C列に単位、D列の備考欄で計算値と数式の根拠や、計算式に用いた仮定を記載している。

ものづくりで単位を間違えると大惨事になることはいうまでもない。
さらに根拠を書いておかないと、設計変更の際に見直しが必要かどうかがわからなくなってしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/abed0d9b-c4ab-fbb9-a3df-e10d13682d2f.png)


## 上から下に計算が流れるように書け
計算は上から下に流れるように書き進めていく。
数式セルは自分より上のセルだけ参照し、自分より下のセルは使わない。
計算の流れが上に行ったり下に行ったりするとわかりづらい。

逆算はゴールシークやソルバーにまかせればいい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/561c37c6-aafd-f988-d18a-3684d2b14dda.png)

## 定数セルを強調せよ
定数入力しているパラメータは、比較的変更しやすい値(が多い)。
どこが変えられる値で、どこが変えられない値なのか一目瞭然になる。

また、設計変更の際に見直すべき値も基本的にこのセルになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/10d62b01-3fdb-4d45-8944-a94a2e7e8426.png)


<details><summary>定数セルをまとめて着色する方法</summary> 

B列を選択し
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/a8a0c487-9cd0-e42a-7180-b57e52321b41.png)
「条件を選択してジャンプ」へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/9f2bd9dc-9d60-a21d-1634-1c2a1a5ecf72.png)
「定数」にチェックを入れ、「OK」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/813ee185-efd3-f9f1-860c-dd7cf4be221b.png)
定数セルがまとめて選択される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/41d5a34f-82c1-b53b-4d78-beeecbd531ee.png)
この状態でセルの色を変えればまとめて着色できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/3a282a5a-26c6-e9e2-37d1-6c07a2c923fd.png)

</details>



## 重要な計算結果(アウトプット)を強調しろ
下の例では。計算結果が問題ないか確認する際にオレンジ色で強調したセルのみ確認すればよいことになる。
単なる計算過程の値を無視して、主要な計算結果だけに着目できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/8dd85ac4-49ad-7452-9f60-feea6540e695.png)

## シートをまたぐ参照は「参照だけするセル」をつくれ
複数のシートにまたがって計算する場合、他のセルを参照するだけのセルをつくるとよい。
下の例では「基本計算」シートで計算した値を用いて「軌道計算」シートで軌道を計算している。
将来的に基本計算シートのセルをずらしたりなどした際に、NG例では計算セル全てを適切に参照変更する必要がある。よい例ではB1,B2セルのみ参照変更すれば適切に計算される。
シートを抜粋して別の計算書に流用する際も、この手法だと最小範囲の書き換えで済む。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/6a12e341-ddb9-256e-4608-25a9c4b13913.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681099/b7fdcd22-65e9-471c-2ea9-ea06f01aec35.png)

また、他シートへのアウトプットがわかりきっている場合は、アウトプット専用のセルもあるといい。


# おわりに
ここまで紹介したのはあくまで自己流なので、他の考えなどがあったらご指摘いただきたいです。

⇖いいね👍️いただけると励みになります！
　あなたの1タップで救われる命があります！
「Jetpack Compose の基本」のメモ#2

https://qiita.com/tiger98/items/6862f1b546b7f9e8da90

の続き

### [UIを微調整する](https://developer.android.com/codelabs/jetpack-compose-basics?hl=ja#3)
+ Surfaceコンポーザブルでラップ(内包)することにより、背景に色を設定できるようになる
+ Surfaceはレイアウトコンポーザブル（またはコンテナコンポーザブル）であり、UI要素（Textやボタン）を内包し、レイアウトやスタイルを適用する関数
+ MaterialTheme.colorSchemeはTheme.ktで指定されている、アプリケーション全体のカラーパレットを定義するオブジェクト
+ Surface内にあるコンポーザブルはSurfaceで設定した背景色の上に描画される
+ 自動的にテキストが白くなるが、これはandroidx.compose.material3.Surface などのマテリアル コンポーネントが自動的に変更している

#### 修飾子（modifier）
+ ほとんどの Compose UI 要素は、省略可能な modifier パラメータを受け入れる
+ UI 要素に対して親レイアウト内での配置、表示、動作を指示する
+ パディング修飾子は Modifier.padding() で作成できる
+ さまざまな修飾子がある
    + 位置揃え
    + アニメーション化
    + 配置
    + 変換
    + クリック可能 / スクロール可能
    + [Compose 修飾子のリスト](https://developer.android.com/develop/ui/compose/modifiers-list?hl=ja)に詳細が記載されている
    +
(個人メモ)TypeScriptがなぜ必要か改めて整理してみた

# はじめに

現在業務でTypeScriptを使うことが多いのですが、改めて新人に向けてJavaScriptとTypeScriptの違いや、TypeScriptを使う理由について、すぐに言語化できなかったので以下の動画を参考にまとめてみました。

https://www.youtube.com/watch?v=7awfmOOeJDI

## 新人に向けて言う謳い文句
- TypeScriptはスマホ、JavaScriptはガラケー
- コンパイルがあるおかげでエラーに気づける
- Type＝型があるおかげでコーディングする際に色々分かりやすくなる

## TypeScriptはなぜ必要か

### 1. コンパイルの重要性

TypeScriptはJavaScriptと違い**コンパイルが必要です。** 
なぜなら、ブラウザはTypeScriptを直接実行できないからです。GoogleChromeの開発者ツールで直接TypeScriptを記述しても動きません。
Node.jsなども同様で、TypeScriptをJavaScriptに変換して実行するという動きを取っています。

このコンパイルプロセスには**未然にバグを防ぐことができるという大きな利点があります。**
コンパイル時にエラーが出てくれるので、リリース前にバグを見つけることができます。
反面JavaScriptではコンパイルのプロセスがなく、バグが混入したままリリースされる可能性があります。

### 2. 型の存在

TypeScriptには型があり、この型はドキュメント的な役割を果たしてくれます。ある種型定義は簡易的な仕様書とも言えるのです。また、ライブラリを使う際にもインプットとアウトプットがはっきりとわかります。
新人の頃は「型があると何がいいの？」と思うことも多かったですが、型を事前に決めておくことでコーディング時点でエラーに気付けるのが個人的には一番大きいかなと感じています。
また、関数やオブジェクトに対してインプットとアウトプットがはっきり分かるところも良い点だと感じています

逆にJavaScriptでは型が緩いため、エラー込みのコードもすんなり書けてしまいます。。。

## 参考文献

- [最も将来性が高いプログラミング言語「TypeScript」の必要性を熱弁する](https://www.youtube.com/watch?v=7awfmOOeJDI)
- [銀の弾丸ではないTypeScriptを、何故使うべきなのか](https://qiita.com/hariNEzuMI928/items/2b10773a016dff9d0dc0)
- [TypeScript公式ドキュメント](https://typescriptbook.jp/)
教育運用の中の数学的思考

教育では統計的手法が良く使われますが(平均値，偏差値など)
ちょっと違う数学的思考として，群論にも応用があります。

# 問題
受講者数60名，会場収容数30名のとき，どのように出社ローテーションを組むか。ただし，受講者は3人1チームを基本とする。受講者の会場出席率はできるだけ均等にし，かつ様々なチームの組み合わせで出席できるようにする。

# 解法の例
問題を単純化します。
A,B,C,Dの4チームのうち，2チームがローテーションで出社すると考えます。
このとき，できるだけ均等に出社するローテーションの例を考えます。
(X,Y)はX,Yが出社することを表します。すると，

(A,B),(A,C),(A,D),(B,C),(B,D),(C,D)

の6パターンが出社の組み合わせの全てです。
これをできるだけ均等に出社させる(連続出社数を平均化する)ので，

(A,B),(C,D),(A,C),(B,D),(B,C),(A,D)

などが例として考えられます。
ローテーションの基本ルールとしてはここまで考えれば十分です。

4チームより多い編成を考えるときに，新しいチームE,F,H,Gを加えて上記のローテーションを考え直す必要はありません。

A={A,E}
B={B,F}
C={C,G}
D={D,H}

として，これまでチームとして考えていた要素を複数の要素のグループと考えれば，
チームが増えても大枠のローテーションルールを変更する必要がありません。
これは，群論でいう剰余類の考え方です。

あとは，各グループ(同値類)をどう編成するかを考えれば，効率良く出社のローテーションを組むことができます。

たとえば，上記のローテーションの次に，

A={A,F}
B={B,G}
C={C,H}
D={D,E}

のように後ろのグループをひとつづつ別の同値類に変換していく案が考えられます。

# まとめ
今回は，教育の現場でよくあるチーム編成を例に，数学的思考がどのように応用できるかを示しました。
もちろん教育の現場は数学的に綺麗であれば良いというわけではありません。受講者同士の相性や，編成の目的などの条件によって編成にさらなるアレンジが必要です。ですが，数学的に編成の方針を示せれば，考えることを限定することができます。
Oracle Golden Gate システム無停止での初期同期方法

Oracle超初心者が仕事でOracle環境の構築を頑張っている様子をおおくりします。

## 前提構成
- Oracle Database 19c（ソースDB/ターゲットDBの両方）
- Oracle Golden Gate 19c
- ソースとターゲットの両方にGolden Gateをインストール済。
- 初期同期の方法として、Oracle Data Pumpユーティリティ（EXPDP/IMPDPコマンド）を使用する。


## 初期同期のときシステム停めなくても大丈夫なの…？
Oracle Golden Gateで同期をスタートするには、まず初期同期を行ってソースとターゲットの状態を同じ状態に揃えなくてはならないことまでは理解しました。

初めてGGの同期に成功して以来、数日間上手く稼働していたのに急にプロセスが停止し、初期同期をやり直すことが何度かありました。この時は本格稼働前でアプリケーションからのDBアクセスも無いので特に何事もなく復旧できましたが、本格稼働後に同じことが起こったらどうしよう？と不安がよぎりました。

GGが止まるたびに昼夜問わず日々動き続けるソースDBへの更新を止めてもらうなんてことは非現実的。どうすればシステムを停止させずに初期同期ができるのでしょうか？

## システム無停止で初期同期する方法（ざっくり仕組み）

調べると、GGでは割と簡単にシステム無停止で初期同期できる機能を備えていることが分かりました。

https://www.slideshare.net/slideshow/oraclegoldengate19cv10/239489964

ソース側とターゲット側のそれぞれに以下のような仕組みがあるようです。

### ソース側
ソース側では、初期同期のためにEXPDBコマンドを使ってダンプデータを作成しますが、それがいつ時点の断面なのかをGGが判断できる情報「インスタンス化CSN」をダンプデータ内に含めるように、GGSCIで予め設定することができます。
なのでExtract（CaptureプロセスとPumpプロセス）を稼働させたままの状態で、変更を記録・転送しながらダンプデータを作成してOKです。

### ターゲット側
ターゲット側では、Replicatプロセスを停止した状態でダンプデータをインポートし、その後Replicatプロセスを再起動させますが、この間にソース側で起こった変更情報がTrailファイルにたんまりと溜まっています。このうちいつ以降の変更を反映すればよいのかを、Replicatが「インスタンス化CSN」を見て判断するように設定することができます。Replicatプロセスのパラメータファイルに予めとあるオプションを記述しておきます。

### 雑にまとめると…
**ダンプデータ**
「俺はいついつ時点のデータだぜ、よろしくな！」
**Replicat**
「了解だぜ、その時点より前に起こった変更情報は無視して、それより後に起こった変更情報だけを反映させていくぜ！」

こういうわけで、システムを止めずに上手く同期ができる仕組みなんですね。


## システム無停止で初期同期する方法（詳細）

仕組みが分かったところで、具体的にどんな設定をすればよいのかを書きます。
ソース側とターゲット側のそれぞれに、予め以下の設定をしておきます。

## ソース側
インスタンス化CSNをダンプデータに含めるように設定します。
具体的には、GGSCIでサプリメンタルログを設定するときに以下のオプションを指定します。
`[PREPARECSN {WAIT | LOCK | NOWAIT | NONE}]`

ただしこのオプションを省略すると、`PREPARECSN NOWAIT`がデフォルトで設定されます。つまりNOWAITでよいなら特に何も指定する必要がありません。
なので、

(A) テーブルレベルでサプリメンタルログを設定する場合
`ADD TRANDATA {表名}`

(B) スキーマレベルでサプリメンタルログを設定する場合
`ADD SCHEMATRANDATA {スキーマ名}`

を実行するだけでよいです。

#### 現在の設定を確認する方法
SQL*PlusでCDB$rootに管理者権限でログインし、以下SQLを実行します。
`select TABLE_NAME,TIMESTAMP from ALL_CAPTURE_PREPARED_TABLES
where table_owner = '{スキーマ名大文字}';`

これでEXPDPコマンドで作成するダンプファイルにインスタンス化CSNが記録されるように設定できました。

## ターゲット側
Replicatプロセスを停止し、Replicatパラメータファイルに以下の1行を追記します。
`DBOPTIONS ENABLE_INSTANTIATION_FILTERING`

これでReplicatがインスタンス化CSNを見て変更適用範囲を判断するように設定できました。

## (余談)SCNとCSNの違い
記事によって「インスタンス化CSN」だったり「インスタンス化SCN」だったりするのですが、正しくは「インスタンス化CSN」のようです。
どちらもいつの変更かを判断するためのタイムスタンプ的な番号という点では同じですが、
SCNはOracle Databaseの用語、CSNはOracle Golden Gateの用語だそうです。
DBかGGかで使われる場面は異なりますが、根本的な用途も同じのようですね。

**SCN(System Change Number)**
使用者…Oracle Database
性質…タイムスタンプ
用途…コミット時点を識別する
> システム変更番号(SCN)は、Oracle Databaseで使用される論理的な内部タイムスタンプです。SCNを使用して、トランザクションのACIDプロパティに準拠する必要があるデータベース内で発生するイベントに順序を付けます。Oracle DatabaseではSCNを使用して、すべての変更がディスク上に存在することが認識される前のSCNをマークし、リカバリで不要なREDOが適用されないようにします。さらに、データの集合に対するREDOが存在しない時点のマークにもSCNを使用し、リカバリを停止できるようにします。


**CSN(Commit Sequence Number)**
使用者…Oracle Golden Gate
性質…タイムスタンプ
用途…コミット時点の判断

> Oracle GoldenGateの操作時には、コミット順序番号(CSN)を参照する必要がある場合があります。CSNは、トランザクション一貫性とデータ整合性を維持する目的でトランザクションを識別するためにOracle GoldenGateが作成する識別子です。これにより、トランザクションがデータベースにコミットされた時点を一意に識別します。
「AWS認定クラウドプラクティショナー」試験結果

Y子です。

[前回](https://qiita.com/koiwaiwaiko/items/1277ae830f1502c9f85c "「AWS認定クラウドプラクティショナー」受験")受験したクラウドプラクティショナー試験の、試験結果が届いていたので、その感想です。

# 「試験結果のお知らせ」
結果は「5営業日以内」に届くと聞いていましたが、試験終了の6時間後、当日のうちにメールで届きました。早い！
正確には、「スコアレポートができたからAWSからダウンロードしてね」という英文メールが届いたので、AWSにログインして確認した、ということです。

![20240630_AWS01_加工.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265690/5722a3c3-9c74-93a3-562b-25f7db457316.png)

1000点満点で、700点で合格のところ、679点！
めちゃくちゃおしい！あと21点！
1000点 ÷ 65問 ＝ 約15.4点 だから、2問届かなかったってことでしょうか？

次回に向けて、準備の励みになります。

![20240630_AWS02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265690/eed722fd-4f1e-431c-349b-0905285d0ff7.png)

苦手分野を分析してくれるんですね。おやさしい。

![20240630_AWS03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265690/a23a804e-6192-ae54-ddbe-d278d97ced25.png)

表の文字詰めを少し変えれば、改ページせずに済むのでは…（モゴモゴ）


勉強します！
ITパスポート マーケティング戦略

・マーケティング戦略
市場を調査することによりターゲットとする市場を絞り込み、顧客ニーズに合致した製品やサービスを創出し提供することで、継続的に売れる仕組みを作る一連の戦略

・STP分析
セグメンテーション・ターゲティング・ポジショニングの三つの視点から分析すること

・ターゲットマーケティング
細分化した市場から特定の顧客層を絞り込んで行うマーケティング
・ペルソナ分析
ターゲットとなる顧客層を構成する仮想的な人物（ペルソナ）を定義し、それに合わせた商品やサービスを開発・販売する手法

・コトラーの競争戦略
リーダ・チャレンジャ・フォロア・ニッチャの四つに分類し、競争上の地位に応じた戦略をとるポジショニング戦略

・マーケティングミックス
製品（Product）・価格（Price）・流通（Place）・販売促進（Promotion）の要素を組み合わせてマーケティングを展開する手法

・製品戦略
・プロダクトライフサイクル
商品が市場に導入されて衰退するまでの期間を、導入期・成長期・成熟期・衰退期の四つのカテゴリに分類し、各段階に応じた戦略を設定する手法

・ブランド戦略
企業や商品、サービスのブランドイメージを利用して差別化を図る戦略
・ブランドエクステンション
現行商品とは異なるカテゴリに、同一ブランド名で参入する戦略

・ニーズ志向
顧客ニーズの視点から開発される
・シーズ志向
自社独自の技術はノウハウ、アイディアを活かして開発される

・RFM分析
最終購買日（Recency）・購買頻度（Frequency）・購買金額（Monetary）の指標を使って、顧客の購買行動を分析する手法

・イノベータ理論
イノベータ・アーリーアダプタ・アーリーマジョリティ・レイトマジョリティ・ラガード
アーリーアダプタからアーリーマジョリティへはハードルが最も高く、大きな溝（キャズム）があるとされる

・価格戦略
・スキミングプライシング
高価格による販売で高利益を得る戦略

・ペネトレーションプライシング
低価格による販売で市場のシェアを得る戦略

・ダイナミックプライシング
需要と供給に合わせて価格を変動させる戦略

・流通戦略と販売促進戦略
・マスマーケティング
全ての顧客を対象に大量生産・大量流通させる手法
・ワントゥワンマーケティング
個々の顧客ニーズに個別に対応する手法
・レコメンデーション
顧客がアクセスしたWebページの閲覧履歴や商品の購入履歴を分析し、関連商品を表示することで購入を促す手法
・マスカスタマイゼーション
大量生産・大量販売のメリットを活かしながら、個々の顧客の好みに対応する手法

・ダイレクトマーケティング
流通業者を通さずに、企業が直接顧客に対して商品やサービスを販売する手法

・プッシュ戦略
顧客に積極的に売り込む戦略
・プル戦略
顧客が購入したくなるように促す戦略

・インバウンドマーケティング
情報を探している見込み客を最終的に顧客に転換させることを目標とする手法

・クロスメディアマーケティング
複数のメディアを融合させてマーケティング上の相乗効果を図る手法

・マーチャンダイジング
顧客ニーズに合致した適切な商品を、適切な場所、適切な時期、適切な数量、適切な価格で提供するために行う一連の活動のこと

・カニバリゼーション
自社内の商品やサービスが競合し、売上を食い合うこと
PowerShellのテスト Pesterのインストール

PowerShellのテスト用フレームワーク、Pesterをインストールする。

Quick Start
https://pester.dev/docs/quick-start

今回のインストール先はMacのPowerShell。
```
$ pwsh
PowerShell 7.4.2
PS /mogemoge> Install-Module -Name Pester
PS /mogemoge> Import-Module Pester -PassThru                                 

ModuleType Version    PreRelease Name                                ExportedCo
                                                                     mmands
---------- -------    ---------- ----                                ----------
Script     5.6.0                 Pester                              {Add-Shou…
```


インストールが成功したので、ドキュメントの導入部分を触ってみる。
https://pester.dev/docs/quick-start

ドキュメントを「Splitting to tests and function」まで読み進めて、テストとテスト対象のスクリプトを分けて作成し、テストを走らせる。

``` Get-Planet.ps1
function Get-Planet ([string]$Name = '*') {
    $planets = @(
        @{ Name = 'Mercury' }
        @{ Name = 'Venus'   }
        @{ Name = 'Earth'   }
        @{ Name = 'Mars'    }
        @{ Name = 'Jupiter' }
        @{ Name = 'Saturn'  }
        @{ Name = 'Uranus'  }
        @{ Name = 'Neptune' }
    ) | ForEach-Object { [PSCustomObject] $_ }

    $planets | Where-Object { $_.Name -like $Name }
}
```
```Get-Planet.Tests.ps1

BeforeAll {
    . $PSScriptRoot/Get-Planet.ps1
}

Describe 'Get-Planet' {
    It 'Given no parameters, it lists all 8 planets' {
        $allPlanets = Get-Planet
        $allPlanets.Count | Should -Be 8
    }
}
```

```
PS /Users/xxx/powershell> Invoke-Pester -Output Detailed Get-Planet.Tests.ps1
Pester v5.6.0

Starting discovery in 1 files.
Discovery found 1 tests in 2ms.
Running tests.

Running tests from '/Users/xxx/powershell/Get-Planet.Tests.ps1'
Describing Get-Planet
  [+] Given no parameters, it lists all 8 planets 4ms (3ms|1ms)
Tests completed in 18ms
Tests Passed: 1, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0
```

テストは成功。
新しいフォントが追加できるバッチファイル

## ダブルクリックすればフォントは追加できるけど

こんにちは。今回はダブルクリックすれば追加できるフォントについて
無駄にバッチファイルを作ったので共有します。

## 管理者としてCMDを実行する必要があります

こちらがそのコードになります。ぜひ使ってみましょう

```batch
@echo off
setlocal enabledelayedexpansion

:: Set the path to the Windows Fonts folder
set "FONTS_FOLDER=%SystemRoot%\Fonts"

:: Prompt the user for the font file name
set /p "FONT_FILE=Enter the full path and name of the TTF font file: "

:: Check if the file exists
if not exist "%FONT_FILE%" (
    echo Font file not found. Please check the path and try again.
    goto :EOF
)

:: Extract the file name from the full path
for %%F in ("%FONT_FILE%") do set "FONT_NAME=%%~nxF"

:: Copy the font file to the Windows Fonts folder
copy "%FONT_FILE%" "%FONTS_FOLDER%"
if errorlevel 1 (
    echo Failed to copy the font file. Make sure you have administrator privileges.
    goto :EOF
)

:: Register the font
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" /v "%FONT_NAME% (TrueType)" /t REG_SZ /d "%FONT_NAME%" /f

:: Notify the user
echo Font "%FONT_NAME%" has been successfully added and registered.

:: Prompt to restart applications
echo Please restart any open applications to use the new font.

endlocal
```