OmniAICreator/Qiita-1.07M huggingface dataset:
ReactとViteを使ってGitHub Pagesでサイトを公開する方法

## アジェンダ
ReactとViteでGitHub Pagesにサイトを公開するための手順をまとめます。ReactとViteの手順は基本的に同じですが、異なる場合は別途記述しています。

## 手順

### 1. プロジェクトの作成
まずは、以下のコマンドで、プロジェクトを作成します。

**React:**
```sh
npx create-react-app my-app
cd my-app
```

**Vite:**
```sh
npm create vite@latest my-project --template react
cd my-project
npm install
```

### 2. `gh-pages` パッケージのインストール

React、ViteでGitHub Pagesにサイトを公開するためには、`gh-pages`パッケージをインストールする必要があるので、以下のコマンドでインストールします。

```sh
npm install gh-pages --save-dev
```

### 3. `package.json`の編集

`package.json`に以下を追加します。

```json:package.json
{
  "homepage": "https://ユーザー名.github.io/リポジトリ名",
  "scripts": {
    "predeploy": "npm run build",
    "deploy": "gh-pages -d build" // Reactの場合
    "deploy": "gh-pages -d dist"  // Viteの場合
  }
}
```
### 4. React Routerの設定
続いて、React Routerの設定で、basenameを追加いたします。

**React:**
```jsx:main
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <Router basename="/リポジトリ名">
      <App />
    </Router>
  </React.StrictMode>,
  document.getElementById('root')
);
```

**Vite:**
```tsx:main
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { BrowserRouter as Router } from "react-router-dom";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <Router basename="/リポジトリ名">
      <App />
    </Router>
  </React.StrictMode>,
);
```

Viteの場合は別途`vite.config.ts`の設定も追加しなくてはいけません。

**`vite.config.ts`の設定:**
```typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  base: '/リポジトリ名/', /* 追加 */
});
```

### 5. デプロイ

以下のコマンドでサイトをデプロイします。

```sh
npm run deploy
```

### 6. GitHub Pages の設定

GitHubリポジトリの `Settings` -> `Pages` で `Source` を `gh-pages` ブランチに設定します。

これで、`https://ユーザー名.github.io/リポジトリ名/` でサイトが公開されます。

## 参考
- [GitHub Pages サイトの公開元を設定する - GitHub Docs](https://docs.github.com/ja/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site)
- [GitHub PagesにReactアプリをデプロイする方法 #JavaScript - Qiita](https://qiita.com/yuitnnn/items/11375ea29ec023d19fdf)
AWS クラウドプラクティショナー CLF-C02の合格方法（非エンジニア向け）

# 前提情報
- **この投稿の想定メイン読者**
    - 非エンジニア
    - 楽して合格したい人
- **受験者情報**
    - IT企業所属の人事
    - AWSのサービス名称は聞く程度
- **受験時期**
    - 2024年6月
- **受験結果(スコア)**
    - 821（もっとハイスコアを狙っていました）
- **この投稿で一番言いたいこと**
    - 最短の勉強方法、CLF-C01からCLF-C02への移行によって変わった？

-------------------
# 勉強方法
### 購入物
- Udemy
    - [【CLF-C02版】この問題だけで合格可能！AWS 認定クラウドプラクティショナー 模擬試験問題集（6回分390問）](https://www.udemy.com/course/aws-4260/learn/quiz/4705310#content)
    - 書籍
        - ["AWS認定資格試験テキスト　AWS認定 クラウドプラクティショナー　改訂第3版"](https://read.amazon.com/kp/kshare?asin=B0CTM7C47Q&id=bd6342d4g5ezfn34qqabzq4nee&reshareId=WF25XCRXPRAZQ2JPWXP5&reshareChannel=system)
        - ["徹底対策 AWS認定 クラウドプラクティショナー（CLF-C02 対応）: 65問×5セット 375問（CLF-C02 対応） クラウド試験徹底対策シリーズ"](https://read.amazon.com/kp/kshare?asin=B0CSYJ8W85&id=mbmggve5jrhgxljxaoa7vovwja&reshareId=S7YK3HQ3PYQFPP8WPTFB&reshareChannel=system)

 
### 実績と解釈
#### 使った時間比率
- 本（上記の教科書）: 1
- AWS Skillビルダーの動画（一番最初に推奨されるやつ）: 1
- Udemy: 3
- 本（上記の問題集）: 5
 
#### 感想
- **"AWS認定資格試験テキスト　AWS認定 クラウドプラクティショナー　改訂第3版"**
    - 予想通り時間がかかるので途中でやめた
    - 翻訳に違和感残る
- **スキルビルダーの動画**
    - 非エンジニアの自分にはとても良かった
    - クセ強キャラが1人いて、クセになる
    - 6時間程度必要
    - 1番最初に見るべき
    - ちなみに自分が好きなサービスはAWS Application Discovery ServiceとMigration Evaluatorです（AWSの人って賢いなー）
- **Udemyの問題集**
    - 序盤にかなりやった
    - 3周して最後の回以外は8割の正答率に留めた
    - 出題と回答ともに翻訳がおかしい箇所あり
    - 全部を鵜呑みにするのは危険
- **"徹底対策 AWS認定 クラウドプラクティショナー（CLF-C02 対応）: 65問×5セット 375問（CLF-C02 対応） クラウド試験徹底対策シリーズ"**
    - 終盤1番やった
    - 誤訳と回答の誤り（CAFやWell～あたり）あるので要注意
    - 一問一答モード？で回答すると無限に問題がある感じがする
    - 受験タイミングでは正答率100%程度にした
    - 試験結果スコアが821なので、きっとこの問題集だけでは不足がある
    

### その他
- トータルの勉強時間
    - 平均といわれている50-60時間は余裕で超えた
    - 100時間程度？（お恥ずかしい）


-------------------
# この試験勉強で一番考えるべきこと
**Udemyのレベルと他の教材レベルどちらに合わせるべきなのか**


-------------------
# 最適と思う勉強方法
```
あくまでも個人的な解釈です
```
 
### ノートを作成する
- なんだかんだノート化は自分にはフィットした
- 「あ、これはアプリケーション用のセキュリティ。これはネットワークのもの。」と理解するのはノート化したものを"注意深く見る余裕が出来た時"だった


### Udemyに合わせない
評価が高いので不安になるかもしれないけど…

- Udemyの問題集不要かもしれない
    - やって損はない
    - 確かに序盤いっぱいやった
    - 解説文をベースにノートも作った
- でも、CLF02向けではないのでは？
    - あくまでも個人の考えです
        - この問題集は01時に作られ、後から02にも対応したもの
        - 01→02でサービス範囲は倍（65→130位？）になっている
        - 02の今、01時点の深い理解は求められないはず
    - 受験前に違和感が強くなり、Udemyベースの勉強をやめました（結果大正解）

### 今時間を巻き戻すなら
- Udemyの教材は購入しない
- ハイスコアを狙いたい場合
    - 購入した書籍の問題集以外の問題集も2冊位購入
        - 結局はどれだけの設問の言い回しに耐えられるのかが大事なので
    - 違和感を感じる部分はホワイトペーパーを見る
        - ホワイトペーパーの翻訳もおかしいけど
    - エンジニアに聞く
        - 継承される統制とか絶対意味わからなくなるので

# 最後に
良い資格なので、いい受験体験になりますように！！
Rocky Linux mysql　導入メモ

Rocky Linuxでは、Mysqlはデフォルトのリポジトリから入手できる
sudo dnf install mysql-server

sudo systemctl start mysqld.service #mysqlの起動

sudo systemctl status mysqld

sudo systemctl enable mysqld　#LInux起動時に自動的に立ち上げる

sudo systemctl disable mysqld #自動起動を無効にしたいとき
S3のストレージクラス

# はじめに
この記事はAWS SAA試験勉強のための、S3のストレージクラスに関する知識のまとめです。

# Standard

名前の割に、一番高価。
東京リージョン(ap-northeast-1)のS3標準を使用している場合、ファイルがPUTされるとap-northeast-1の複数のAZに複製されます。


# Standard-IA(Infrequency Access)

低頻度アクセスデータ用のStandardよりも安価なストレージ。
Standardと異なるのはS3 One Zone-IAやStandard IAはデータ取得されないことを前提としているため、データ取得時には課金が発生することです。
また、<font color="red">**データは1つのAZのみに保存**</font>されます。

# One Zone-IA
ログファイルのコピーを保存するためのストレージというのはS3 One Zone-IAを利用する典型例となっています。


# S3 Intelligent-Tiering
S3 Intelligent-Tiering は、アクセスパターンが変化するときに 2 つのアクセス階層間 (高頻度アクセスと低頻度アクセス) でデータを自動的に移動してコスト最適化を達成するストレージクラスです。
例えば、アクセスパターンをモニタリングし、30日間アクセスされてないデータを低頻度のアクセス階層に自動で移動させます。

## Amazon S3 Glacier 
Amazon S3 GlacierはS3のストレージクラスに位置付けられているものの、Amazon S3 Glacierというアーカイブ用のストレージとして機能や仕組みがAmazon S3のストレージクラスとは異なっています。
GlacierのファイルはRedShiftなどを使っても解析できません。

## Glacier Deep Archive
アーカイブデータを取り出す際は**12時間**以内となっています。

## Glacier Flexible Retrieval
標準取り出しでは、 **3〜5 時間**以内にすべてのアーカイブにアクセスできます。
**迅速読取を利用することで1分～5分ほどでデータを取得することができます。**

## Glacier Instant Retrieval
滅多にアクセスがされないアーカイブ用データの中でもデータ取得時には**即時に**アクセス可能な特殊なストレージ。
実践低レベル Symbol -ファイナライズ統計-

## ファイナライズ統計格納クラス
以下は、ファイナライズ情報を格納するクラスです。
前回のチェーン統計が `/chain/info` に近いフォーマットでしたが、ファイナライズ情報の一部が無い状態でしたが、これで無い部分が補え `/chain/info` と同じ物が作れるようになります。
```FinalizationStatistics.ts
export class FinalizationStatistics {
  constructor(
    public readonly epoch: number,
    public readonly point: number,
    public readonly height: string,
    public readonly hash: string
  ) {}
}
```

## ノード情報取得クラス
`Catpult.ts` を編集します。
```Catpult.ts
import { NodeInfo } from './NodeInfo.js';
import { PacketBuffer } from './PacketBuffer.js';
import { SslSocket } from './SslSocket.js';

export class Catpult extends SslSocket {
  /** パケットタイプ */
  private PacketType = {
    CHAIN_STATISTICS: 5,
    NODE_DISCOVERY_PULL_PING: 0x111,
    FINALIZATION_STATISTICS: 0x132,
  };

  /**
   * FinalizationStatistics取得
   * @returns 成功: FinalizationStatistics, 失敗: undefined
   */
  async getFinalizationStatistics() {
    let finalizationStatistics: FinalizationStatistics | undefined = undefined;
    try {
      const socketData = await this.requestSocket(
        this.PacketType.FINALIZATION_STATISTICS
      );
      if (!socketData) return undefined;
      const bufferView = new PacketBuffer(Buffer.from(socketData));
      const epoch = bufferView.readUInt32LE();
      const point = bufferView.readUInt32LE();
      const height = bufferView.readBigUInt64LE();
      const hash = bufferView.readHexString(32).toUpperCase();
      finalizationStatistics = new FinalizationStatistics(
        epoch,
        point,
        height.toString(),
        hash
      );
    } catch (e) {
      finalizationStatistics = undefined;
    }
    return finalizationStatistics;
  }

  // 略...
  
}
```

## メイン
`Catpult` のインスタンスを生成して呼び出すだけです。
```main.ts
import { Catpult } from './Catpult.js';

const catpult = new Catpult('sakia.harvestasya.com');
const result = await catpult.getFinalizationStatistics();
console.log(result);
```


## 実行
```
> yarn tsx ./src/main.ts
FinalizationStatistics {
  epoch: 2070,
  point: 19,
  height: '1489228',
  hash: '288FA2159F61364FCD75ADABF92BB47E0E08AB783F5ACA6ECE8E5BB2C5CD6F26'
}
```
rocky linux GUI 導入

レポジトリ「EPEL」をセット
$ sudo dnf install epel-release
$ sudo dnf --enablerepo=epel group

デスクトップパッケージをインストール
$ sudo dnf groupinstall "Server with GUI"

起動時に自動的にGUIになるように設定
$ sudo echo "exec /usr/bin/xfce4-session" >> ~/.xinitrc
$ sudo systemctl set-default graphical

確認はcat ~/.xinitrc


ibus-anthyをインストール
$ sudo dnf install -y ibus-anthy

GUIで起動後
起動時のGUI言語を日本語に変えていく

$ echo 'export LANG=ja_JP.UTF-8' >> ~/.bashrc

日本語入力を出来るようにする
$ ibus-setup 
入力したらInput Methodのタブを選択して、Addボタンでjapanese-Anthyを追加する
その後に本体設定のキーボードにAnthyを追加する

そして再起動すると日本語入力が可能となっている

sudo reboot　で再起動

GUIログイン時にアカウントを選択出来てroot　管理者権限で入ることも出来る
su - 
これで素早くrootに移動できるからもう一度設定する
その場合ユーザごとに言語設定をする必要があるため再設定をやる
【Unity】metaファイルを全て削除する

**カレントディレクトリ**内の`*.meta`ファイルを全て削除するには

## Windowsなら
PowerShellで
```
Get-ChildItem  -Recurse -Filter *.meta | Remove-Item -Force
```

## Unix系統なら
Bashで
```
find -type f -name "*.meta" -exec rm -f {} \;
```

## おわり
[簡潔の王、簡潔キング](https://qiita.com/uts1_6/items/11e348ead4bae71571b8)
flutterfire configureがERROR: Package name for Android app cannot be emptyとなる場合の対処法

## 環境
- OS
    - windows
- IDE
    - AndroidStuido
## 対象コマンド
```powershell
flutterFire configure
```
## 対象エラー
```
 Which Android application id (or package name) do you want to use for this configuration, e.g. 'com.example.app'?
 
 i Firebase android app  is not registered on Firebase project your_project.
⠼ Registering new Firebase android app on Firebase project your_project.
FirebaseCommandException: An error occured on the Firebase CLI when attempting to run a command.
COMMAND: firebase apps:create android your_project (android) --package-name= --json --project=your_project
ERROR: Package name for Android app cannot be empty
```
### エラー詳細
`ERROR: Package name for Android app cannot be empty`
どうやらパッケージ名が空らしい。

# 確認箇所
### 1. android/app/src/main/AndroidManifest.xml

- 私はmanifestタグにpackage名がなかったので追加
- android:labelをパッケージ名とそろえる

```android/app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.orgname.my_app_name"> // 追加

    <application
        android:label="com.your.orgname.my_app_name"
```

### 2. android/app/src/debug/AndroidManifest.xml

- manifestタグにpackageを追加

```android/app/src/debug/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.orgname.my_app_name">
```

### 3. android/app/src/profile/AndroidManifest.xml

- manifestタグにpackageを追加

```android/app/src/profile/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.orgname.my_app_name">
```

### 4. android/app/build.gradle

- namespace
- applicationId

```android/app/build.gradle
android {
    namespace = "com.your.orgname.my_app_name"

    
    defaultConfig {
        applicationId = "com.your.orgname.my_app_name"
```

### 5.  android/app/src/main/kotlin/com.your.orgname.my_app_name/MainActivity.kt

- package インポート

```android/app/src/main/kotlin/com.your.orgname.my_app_name/MainActivity.kt
package com.your.orgname.my_app_name
import io.flutter.embedding.android.FlutterActivity

class MainActivity: FlutterActivity()
```

## 参考
[Flutterでパッケージ名がcom.exampleになっているのをiOS/Androidで修正する箇所まとめ](https://qiita.com/osamu1203/items/6adfab47e562f5e7d03b)
【Next.js】仮想環境でnext devしたときにホストマシンから見られるようにする方法

VMwareなどで構築した仮想環境上で`next dev`を実行し、意気揚々と`localhost:3000`にアクセスしたところ、接続できずに「あれ？」と思うことがありますよね。

## `--hostname`オプションを使用する

```bash
pnpm dev --hostname 0.0.0.0
```

こうすれば、`http://{仮想環境のipアドレス}:3000`で見られるようになります。

## 仮想環境のIPアドレスってどうやって確認するんだっけ？

```bash
hostname -I
```

これで確認できます。

ん？

```json:package.json
{
  "scripts": {
    "dev": "next dev --hostname $(hostname -I)",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "check": "pnpm biome check --write ."
  },
}
```

じゃあもうこれでいいっすね。
こうすると`next dev`したときにちゃんとURLが表示されて楽です。
【Raycast拡張機能開発】`Error: Created by must exist` 解決

# はじめに
今回は、Raycastの拡張機能を公開する上で若干詰まった部分があったのでその解決法を紹介したいと思います。

# 問題
`npm run publish`をした際、以下のようなエラーが出て正常に実行できなかった。

```
> publish
> npx @raycast/api@latest publish

ready -  validate git repository
ready -  validate owner
info  -  entry points [src/index.tsx src/create.tsx src/list.tsx]
info  -  compiled entry points
info  -  generated extension's TypeScript definitions
info  -  checked TypeScript
ready -  built extension successfully
info  -  archived extension
info  -  prepared upload
info  -  uploaded extension
publishing failed (Error: Created by must exist (RequestID: *********-*****-****-***********))
```

# 解決方法
`package.json`に記載する`auther`および`owner`の値が間違っていた。

- `author`はRaycastに登録されている自分のアカウント名でなければいけない
   - 確認方法: [Raycastのマイページから確認](https://www.raycast.com/settings/account)

- `owner`は作成したTeamsの名前でなければいけない
  - 確認方法: Raycast > setting > Organizations から確認できます

# おわりに
地味なところですが、エラー文ググっても全然出てこなかったのでこれで誰かが助かるといいなあと思ってこの記事を書きました。

Raycast拡張機能開発は日本語の情報が全然ない所は残念ですが、React/typeScripyで書けるので楽しいですね。
nginxでデプロイスロットをつくる

# まえがき
nginxでクラウドのようにデプロイスロットを構築できないかなぁ、と思って調べたのでその備忘録  

# 前提
動かすのは以下の環境
- Windows 11
- nginx 1.26.1

スロット1と2をつくり、それぞれ以下のAPIサーバーにつなぐ想定  

サーバー1: localhost:5000
サーバー2: localhost:5001

# nginx.confを設定する、だけ

```nginx
http {
    # スロット1のサーバーグループを定義
    upstream slot1 {
        server localhost:5000;
    }
    # スロット2のサーバーグループを定義
    upstream slot2 {
        server localhost:5001;
    }

    server {
        listen      localhost:80;
        server_name localhost;

        # 接続先切り替え用の変数（なくてもいい）
        set $slot slot1;

        location / {
            # 指定のスロットに転送
            proxy_pass http://$slot;
        }
    }
}
```

# 使い方

1. `$slot`変数に`slot1`か`slot2`を設定
    ```nginx
    # 例：slot2に切り替える場合
    set $slot slot2 
    ```
2. nginxの設定を読み込みなおす
    ```powershell
    ./nginx -s reload
    ```

# あとがき
以上、これだけとなります
設定ファイルをちょびっと書くだけでこういったことが実現できるのはすごい楽ですね✌️
Amazon Macie

# はじめに
この記事はAWS SAA試験勉強のための、AWS Macieに関する知識のまとめです。

# Amazon Macie(メーシー)とは

Amazon S3に保存データを機械学習によって自動的に検出、分類、保護するセキュリティサービス。

RDSなどの他のデータストアに存在する機密データを一時的に S3 に移動させることで、RDSの機密データの保護も可能。

2023/05時点では、日本語は対応してない。(ユーザーが個々に登録することは可能。)

また、Amazon Macieと[Amazon EventBridge](https://qiita.com/naoya_ok/items/08b6e048853e4e1030b7)を統合することで、機密データの検出をトリガーにAmazon SNSサブスクリプションを用いてメッセージを通知することができます。
AndroidでHTMLコードの変換時のあれこれのメモ

# HTMLコードの変換（装飾）
androidのAPI Lvevl が23以下なら
```
Html.FromHtml(text)
```
androidのAPI Lvevl が24からは　↑の方法は非推奨とされているので、　**HtmlCompat**を使う

```
HtmlCompat.FromHtml(text, HtmlCompat.FromHtmlModeCompact)
```

# 正規表現で一部のHTMLタグを非表示にする
imageタグを非表示にする
```
text.replaceAll("<img [^>]*>", "")
```

# 正規表現で一部のHTMLタグを他の文字に変換する
```
text.replaceAll("<video [^>]*>", "ビデオ").replaceAll("</video>", "")
```

# 正規表現で特定のタグがいくつあるか数える
```
  private fun countTags(string: String): Int {
        val pattern = "<img [^>]*>"
        val pattern2 = "<video [^>]*>"
        
        val matcherImage = Pattern.compile(pattern).matcher(string)
        val matcherVideo = Pattern.compile(pattern2).matcher(string)
        
        var count = 0
        while (matcherImage.find()) {
            count++
        }
        while (matcherVideo.find()) {
            count++
        }
        return count
    }
```

タグにこだわらなくても、特定の文字列の数を数えられる...
# 参考

https://qiita.com/ikemura23/items/d4546ace79bf1a204d94

https://qiita.com/grrrr/items/7c8811b5cf37d700adc4

https://atsum.in/android/regex-find-match-entire/
CSSのスタイリングガイドについて

# 概要
今まで、CSSを食わず嫌いしていましたが、最近CSSの学習を始めました。
恥ずかしながら今まで適当にcssを決めていたのですが、
CSS設計ガイドに、htmlとcssの命名規則についての記載があったため、
命名規則が記載されているページについてメモを残します。

# CSSの命名規則について
[Google Html/css style guide](https://google.github.io/styleguide/htmlcssguide.html)
英語で拒否反応が出そうになりますが、
[こちらの記事](https://qiita.com/tsunogai/items/05b944debbcac35fbc18)で日本語訳して頂いているので、一度、日本語訳を読んでから、google日本語翻訳を使用して読むと、意外と簡単に読めると思います。

[idiomatic-css](https://github.com/necolas/idiomatic-css)
こちらも英語かと思い、うっ・・・となりますが、
公式で日本語訳があります。
[日本語訳](https://github.com/necolas/idiomatic-css/tree/master/translations/ja-JP)

# おわり
初投稿でした。
今回は自分用のメモでしたが、これから実践的なCSSのスタイリングについてまとめていけたらと思います。
REST API 



# RESTful APIの主要なHTTPメソッド

| メソッド | 説明 | 用途 |
|----------|------|------|
| **GET**    | サーバーからリソースを取得する。 | Read |
| **POST**   | サーバーに新しいリソースを作成する。 | Create |
| **PUT**    | サーバー上の既存リソースを更新する。 | Update |
| **DELETE** | サーバーからリソースを削除する。 | Delete |


## GET
- **用途**: データの読み取り。
- **例**: `GET /users/123` はユーザーID 123の情報を取得します。

## POST
- **用途**: 新規リソースの作成。
- **例**: `POST /users` に新しいユーザー情報を送信し、新しいユーザーを作成します。

## PUT
- **用途**: データの完全な更新。
- **例**: `PUT /users/123` でユーザーID 123の情報を更新します。

## DELETE
- **用途**: リソースの削除。
- **例**: `DELETE /users/123` でユーザーID 123の情報を削除します。


# REST APIのベストプラクティス

1. **エンドポイントに名詞を使用**:
    - リクエストの形成が直感的になります。
    - 例: `GET /datasource` や `POST /articles`
    - NG例: `GET /datasource` や `POST /GetArticles`

2. **確立されたデータ形式の使用**:
    - JSONが最も一般的で人気のあるデータ形式です。

3. **エラーハンドリングの実施**:
    - 完全なエラーハンドリングと標準HTTP応答コードの使用が重要です。
    - 404,500等  詳しくは[こちら](https://restfulapi.net/http-status-codes/)をご覧ください。


## おすすめ教材
[LEARN REST API DESIGN](https://www.restapitutorial.com/)
[How do we design effective and safe APIs?](https://github.com/ByteByteGoHq/system-design-101?tab=readme-ov-file#how-do-we-design-effective-and-safe-apis) も分かりやすい
Arduino プログラミング on ブラウザ

Arduino をお手軽簡単にブラウザでできたら便利
と思って、ちょっと検索して試したみた

１．https://ardublockly.pitsco.com/
　　TETRIX Ardublockly

  ![Screenshot 2024-06-09 7.35.23 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/876188d6-8a6a-04a9-5454-8ed9d177d4bc.png)

２．使ってみる
　　メニューからブロックを選んで直感的に使える
![Screenshot02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/c9135ae4-1791-2cd0-087d-3d776ff8e94b.png)
![Screenshot03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/9df800d2-fcf7-bd5e-d785-39632d48d359.png)

　　13番ピンのLチカ
![Screenshot04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/9e471dbd-5c6d-2ede-b8a9-70f77a380ef7.png)
　　再度使うときは、右クリックでDuplicateで複製できる
![Screenshot05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/2bdab936-a674-2976-caca-723e8a259fcb.png)
ピン番号の指定も選ぶだけ今回は13番ピン（オンボードLED）を指定
![Screenshot06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/9ca6895d-311f-6c75-428b-99228ea61797.png)
プログラム完成！右のウィンドウにソーズコードがリアルタイムで表示される
USBでArduinoを接続して書き込む、今回の環境は、LifeBook U にChrome OS Flex をインストールしたPCにArduino互換のKUMAN UNO を接続・・・完全にだめそうな環境です
でも、
![Screenshot07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/46b8568e-6e54-7a38-d4a0-70bf9975dfe8.png)
しっかり認識されて
![Screenshot08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/a825319d-f707-5ea8-4d7f-c39301fed257.png)
接続すると、ダウンロード完了です
![Screenshot09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/53281dd3-56ed-7491-ad5d-d4edb546b3a0.png)
KUMAN UNOのオンボードLEDが点滅しました
エンジニアは Audible の代わりに Audify + O'Reilly Learning Platform で技術書を聴こう

最近健康のためにたくさん歩いているのですが、せっかくなのでオーディオブックで技術書を聴きながら歩くことにしました。

定番のオーディオブックといえば Amazon の Audible だと思いますが、技術書が少ないためあまり読みたい本がありませんでした。

代わりの方法を探していい感じにできたので記事にしました。

## 記事の対象者

- iPhone を使っている人
- 歩きながら技術書の読み上げを聴きたい人

## やり方

### O'Reilly Learning Platform のサブスク登録
まず [O'Reilly Learning Platform](https://www.oreilly.co.jp/online-learning/) に登録していることが前提となります。
Audify はブラウザのテキストを読み上げることが可能なため、ブラウザから書籍を読める O'Reilly Learning Platform の書籍を読み上げることが可能です。

年間購読料が約500ドルと高いのが難点ですが、数万冊に及ぶ技術書を読むことが可能で、アーリーアクセスもできるためエンジニアにおすすめです。
僕の場合は会社がサブスク登録してくれているので自己負担無しで使えています。

### Audify のインストール

iOS 版は[App Store](https://apps.apple.com/jp/app/audify-%E8%AA%AD%E3%81%BF%E4%B8%8A%E3%81%92web-%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6-tts/id1551265244)、 Android 版は [Google Play](https://play.google.com/store/apps/details?id=com.tangerinesoftwarehouse.audify&hl=ja) からインストールします。

### 読み上げ方

Audify で読みたい書籍の URL を入力して再生するだけです（Audify 経由で O'Reilly にログインする必要があります）。

### 気に入っている点
- 操作がシンプルなこと
    - 見れば誰でもわかるくらい簡単です。
- 再生スピードを変更できること
    - 0.33 倍から 3.00 倍まで細かく調節することが可能です。
- ピッチを変更できること
    - そのままの声の高さにもできるし高くしたり低くしたりの調節が可能です。
- 声を変更可能なこと
    - 男性の声や女性の声をいくつかの選択肢の中から選べます。
    - 個人的にはデフォルトが聞き取りにくかったので男性の声の Hattori(ja-JP) に設定しました。
- バックグラウンド再生できること
    - スマホをスリープ状態にしていても再生できます。画面がついたままだとポケットに入れっぱなしにしてご操作されてしまうことがあるのが懸念ですがその心配がいりません。
- 読み上げ中のテキストがハイライトされること
    - 聞き逃したり図を見ないとわからない部分については一度立ち止まって読むのですが、このときにどこを読み上げているのかすぐに分かります。
- URL など読み上げるかどうかを選べること
    - URL, カッコ内, 上付き文字などをスキップする設定が可能です。


### 使い勝手が悪いと思っている点

- 図が見れないこと
    - オーディオブックなので当たり前ですが図は見れません。図が多い技術書だとこの方法で聞くのは難しいと思います。
- 表の読み上げが分かりにくいこと
    - 文中に表が出てくる場合、左上から右に順に読み上げていきます。正直何を言っているかわからなくなるため、一度立ち止まってスキップするか、我慢して聞き流す必要があります。
- 発音が時々分かりにくいこと
    - 機械音声なので発音やイントネーションが時々おかしいです。


上記のような使い勝手の悪さは感じていますが、オーディオブックのように使う以上はしょうがないと思っています。

### 他の使い方

技術書を読むために O'Reilly Learning Platform を前提としましたが、Web ブラウザから見れるテキストならなんでも読み上げられます。
公式ドキュメントや技術ブログを読み上げるのも技術力向上に良さそうだと思いました。

また僕はまだ試していませんが PDF や ePUB もいける（Audify 経由でダウンロードする）ようなので、そのフォーマットで手に入る本は Audify で読み上げることができます。

実は翻訳機能がついていますが、 O'Reilly Learning Platform においては URL が変わった結果、ログインを要求されてしまい、実質使うことができませんでした。
英語のリスニングが苦手な僕にとって日本語訳したうえで読み上げてくれたら楽だったのでその点は惜しかったです。
英語の記事には使えそうです。

### 他のアプリの読み上げについて

Safari や google アプリから読み上げられるという情報を見かけたのですが、読み上げ機能を使うことができませんでした。
また Android なら別の方法があるかもしれません。

参考になりましたら幸いです。
Swift Package Managerでライブラリーを導入してみる

普段はAndroidエンジニアをしているのですが、Xcodeを久々に使用し、ライブラリーの導入について調べていたところ`Swift Package Manager`というのを知りました。

Xcodeにライブラリーを導入するために`CocoaPods`を使用していましたが、AndroidStudioと比べて、少しハードルがあると感じてました。
ですが`Swift Package Manager`では簡単にライブラリーを導入が可能になりました。

https://www.swift.org/documentation/package-manager/



# 導入方法
今回は導入方法のみです。

`PROJECT → Packge Dependencies → ＋　`のアイコンをクリック


![スクリーンショット 2024-06-09 19.22.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/fc7003dc-ec66-8338-6ffa-89a8d342535d.png)


導入したいリポジトリーのURLを右上の`Search or Enter Package URL `に入力します。
`Add Packge`をクリック

![スクリーンショット 2024-06-09 19.32.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/b734378f-d2df-f165-27d9-c8a05690a126.png)
![スクリーンショット 2024-06-09 19.31.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/dbc802fd-f90a-a1df-fd1c-40a9ed7a0da0.png)

`Add to Target` に導入したい`Target`を選択し、`Add Packge`をクリック

![スクリーンショット 2024-06-09 19.35.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/497b86b8-f3a9-8925-a8d9-c63b8b517041.png)


![スクリーンショット 2024-06-09 19.36.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/9289a58d-f46d-5b93-f539-6197544b632c.png)

こちらの方法で導入することができました。
フラッシュカード-画像版

```
function insertImagesAndFileNamesFromFolder() {
  var folderId = ""; // フォルダのIDを指定
  var folder = DriveApp.getFolderById(folderId);
  var files = folder.getFiles(); // すべてのファイルを取得

  var presentation = SlidesApp.getActivePresentation();
  var slides = presentation.getSlides();
  var slideWidth = presentation.getPageWidth();
  var slideHeight = presentation.getPageHeight();
  
  // フォントサイズをインプットボックスから取得
  var fontSize = parseInt(SlidesApp.getUi().prompt('フォントサイズを入力してください。').getResponseText());

  while (files.hasNext()) {
    var file = files.next();
    var blob = file.getBlob();
    
    // ファイルが画像であるかを確認
    if (blob.getContentType().indexOf('image') !== -1) {
      // 画像を挿入するスライドを追加
      var imageSlide = presentation.appendSlide();
      var image = imageSlide.insertImage(blob); // 画像を挿入
      alignObjectInCenter_image(image, slideWidth, slideHeight); // 画像を中央に配置
      
      // 画像のファイル名を挿入するスライドを追加
      var fileNameSlide = presentation.appendSlide();
      var textBox = fileNameSlide.insertShape(SlidesApp.ShapeType.TEXT_BOX); // テキストボックスを挿入
      var textRange = textBox.getText(); // テキストボックスからテキストを取得
      textRange.setText(file.getName()); // ファイル名をテキストボックスに挿入
      
      // テキストボックスのサイズを調整する
      var textBoxWidth = 400; // テキストボックスの幅
      var textBoxHeight = 50; // テキストボックスの高さ
      textBox.setWidth(textBoxWidth).setHeight(textBoxHeight); // テキストボックスのサイズを設定
      
      // テキストスタイルを変更する
      var textStyle = {};
      textStyle.fontSize = fontSize; // フォントサイズを設定
      textRange.getTextStyle().setFontSize(textStyle.fontSize); // フォントサイズを適用
      
      alignObjectInCenter_text(textBox, slideWidth, slideHeight); // テキストボックスを中央に配置
    }
  }
}

function alignObjectInCenter_text(object, slideWidth, slideHeight) {
  var objectWidth = object.getWidth();
  var objectHeight = object.getHeight();
  
  var xPosition = (slideWidth - objectWidth) / 2;
  var yPosition = (slideHeight - objectHeight * 5) ;
  
  object.setLeft(xPosition).setTop(yPosition);
}

function alignObjectInCenter_image(object, slideWidth, slideHeight) {
  var objectWidth = object.getWidth();
  var objectHeight = object.getHeight();
  
  var xPosition = (slideWidth - objectWidth) / 2;
  var yPosition = (slideHeight - objectHeight * 2) ;
  
  object.setLeft(xPosition).setTop(yPosition);
}
sharp の「Could not load the "sharp" module using the win32-x64 runtime」エラーの解決方法

## エラー状況
netlifyにビルド後、サイトページにアクセスしたところ、以下のように表示された。

```ruby:Error
ERROR  Unhandled Promise Rejection
```

そのためFunction logを確認すると以下のように出力されていた。
```
ERROR  Unhandled Promise Rejection
{"errorType":
"Runtime.UnhandledPromiseRejection",
"errorMessage":
"Error: Could not load the \"sharp\" module using the linux-x64 runtime

... 略
```

## 解決方法

[このサイト](https://github.com/lovell/sharp/issues/4056)でも書いてある通り、plaiceholderはsharpのv0.32.1までしか対応していないとのこと。というわけで、package.jsonのsharpのバージョンを修正します。

```json:package.json
  "dependencies": {
    "next": "14.2.2",
    "plaiceholder": "^3.0.0",
    "react": "^18",
    "react-dom": "^18",
    "sass": "^1.75.0",
-   "sharp": "^0.33.3"
+   "sharp": "^0.32.1"
  }
```

これでサイトページが正しく表示されるようになりました。
保育士特定登録取消者管理システムにおける犯歴情報の流れ

『[保育士特定登録取消者管理システム概要](https://www.cfa.go.jp/assets/contents/node/basic_page/field_ref_resources/7bd2fbc8-98ab-4cfc-87c5-0c4330d8ea9d/965f8065/20240513_policies_hoiku_tokuteihoiku_09.pdf)』(こども家庭庁、2024年5月13日)の10ページには

> なお、施設・事業所の採用責任者が本データベースで採用内定予定者等の情報を検索することは、個人情報保護法第20条第2項第1号に定める「法令に基づく場合」に該当し、本人の同意は不要であるが、本データベースでの検索の結果に照らして採用しないとの判断をすることがあり得ることを踏まえ、採用公募等の段階において、保育士としての採用を希望するものに対して、採用内定前にデータベースの検索を行うことや、検索の結果、特定登録取消者に該当することが判明した場合は採用しない場合があることを書面等により提示するとともに、特定登録取消者に該当する場合はあらかじめその旨を申告するよう求めることが望ましい。

と書かれている。さて、この「法令に基づく場合」に該当するというのは、本当だろうか。このシステムまわりにおける犯歴情報の流れを、ざっとGraphvizで可視化してみよう。Google Colaboratoryだと、こんな感じ。

```
g="""digraph{
  node[shape=box,fontname=Helvetica]
  地方裁判所->地方検察庁[label="刑事訴訟記録　　",penwidth=2]
  地方検察庁->地方裁判所[label="刑執行猶予言渡し取消請求　　",penwidth=2]
  地方検察庁->本籍地市区町村[label="既決犯罪通知書\l既決犯罪通知撤回通知書\l刑執行猶予言渡し取消通知書　　\l財産刑執行終了通知書\l犯歴事項訂正通知書\l",style=dotted]
  刑事施設->地方更生保護委員会[label="仮釈放申出\l不定期刑終了申出　　\l",penwidth=2]
  地方更生保護委員会->刑事施設[label="仮釈放決定通知書\l仮釈放取消決定通知書\l不定期刑終了決定通知書　　\l",penwidth=2]
  刑事施設->保護観察所[label="身上関係事項　　"]
  刑事施設->地方検察庁[label="釈放通知書\l自由刑等執行終了通知書\l犯歴事項訂正通知書\l",style=dotted]
  刑事施設->本籍地市区町村[label="自由刑等執行終了通知書　　\l犯歴事項訂正通知書\l",style=dotted]
  地方更生保護委員会->保護観察所[label="仮釈放取消決定通知書　　",penwidth=2]
  地方更生保護委員会->地方検察庁[label="仮釈放決定通知書\l仮釈放取消決定通知書\l不定期刑終了決定通知書　　\l",style=dotted]
  地方更生保護委員会->本籍地市区町村[label="不定期刑終了決定通知書　　",style=dotted]
  保護観察所->地方更生保護委員会[label="仮釈放取消申出　　",penwidth=2]
  保護観察所->地方検察庁[label="刑執行猶予言渡し取消申出　　",penwidth=2]
  保護観察所->本籍地市区町村[label="仮釈放等期間満了通知書　　",style=dotted]
  本籍地市区町村->市町村選挙管理委員会[label="選挙資格失効情報　　",penwidth=2]
  戸籍の附票ネットワーク[shape=cylinder]
  戸籍の附票ネットワーク->都道府県知事[label="附票本人確認情報　　",penwidth=2]
  都道府県知事->本籍地市区町村[label="附票本人確認情報　　"]
  本籍地市区町村->都道府県知事[label="犯歴情報　　",penwidth=1]
  保育士特定登録取消者管理システム[shape=cylinder]
  都道府県知事->保育士特定登録取消者管理システム[label="登録取消者情報　　",penwidth=2]
  保育士特定登録取消者管理システム->保育士の採用責任者[label="登録取消者情報　　",penwidth=2]
  保育士の採用責任者->都道府県知事[label="児童生徒性暴力情報　　",penwidth=2]
}
digraph{
  rankdir=LR
  node[shape=record,penwidth=0,margin=0.05]
  x[label="<1>|<2>"]
  y[label="<1>法律に基づく個人情報の提供|<2>省令に基づく個人情報の提供"]
  x:1:e->y:1:w[penwidth=2]
  x:2:e->y:2:w
}"""
import graphviz
graphviz.Source(g)
```

私(安岡孝一)の手元では、以下の図が出力された。

![hoikushiDB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428317/a7b0f0a4-4a56-8171-39ad-c64b72e92051.png)

「法令に基づく場合」を実線で書いてみたところ、保育士特定登録取消者管理システムのまわりは確かに実線になっているものの、本籍地市区町村の上で実線が途切れたままになっている。[2023年7月19日の日記](https://srad.jp/~yasuoka/journal/662992/)にも書いたが、『犯歴事務規程』や『犯罪をした者及び非行のある少年に対する社会内における処遇に関する事務規程』や『被収容者等の釈放に関する訓令』は、あくまで訓令に過ぎず、ここで言う「法令」にはあたらない(cf.『[個人情報の保護に関する法律についてのガイドライン(行政機関等編)](https://www.ppc.go.jp/personalinfo/legal/guidelines_administrative/)』)。まあ、こども家庭庁も、このあたりを理解しているので、「本人の同意は不要である」としながらも「申告するよう求めることが望ましい」などと、何とか違法性を取り繕おうとしているわけだ。もう、保育士特定登録取消者管理システムの運用が始まっちゃったらしいんだけど、さて、困ったな。
Flutter/Dartプロジェクトのテストファイルはtestフォルダに置くこと

## 簡単にまとめると？

- テスト用のパッケージを `import 'package:test/test.dart'` した時に [depend_on_referenced_packaeges](https://dart.dev/tools/linter-rules/depend_on_referenced_packages) というエラーが出た
- 要約すると 「dev_dependenciesにあるパッケージをimportする場合はlibなどに置かない」ということ
- つまり Flutter/Dart のテストファイルはtestフォルダに置こう！

## 背景

FlutterやDartでのTDDをやってみるために[TDD本](https://shop.ohmsha.co.jp/shopdetail/000000004967/)をDartで実装することにした。

Dartプロジェクトを `dart create tdd_project` みたいな感じで作った。  
テストを書きたかったので `pubspec.yaml` の dev_dependencies に `test: ^1.25.7` を追加した。  
早速テストを実装したところ `import 'package:test/test.dart';` の部分で以下のようなエラーが出た。 

> The imported package 'test' isn't a dependency of the importing package.
Try adding a dependency for 'test' in the 'pubspec.yaml' file. dart [depend_on_referenced_packaeges](https://dart.dev/tools/linter-rules/depend_on_referenced_packages) 

## どんなエラー？

このエラーを率直に翻訳すると、以下のようになる

> インポートされたパッケージ 'test' は、インポートするパッケージの依存関係ではありません。
pubspec.yaml' ファイルに 'test' の依存関係を追加してみてください。

？？？？？？？

testパッケージは`pubspec.yaml`のdev_dependenciesに追加されてるけどどういうこと？  
さらに[公式ドキュメント](https://dart.dev/tools/linter-rules/depend_on_referenced_packages)から深掘りしてみると、以下の部分が引っかかった。

> Whether this should be a regular dependency or dev_dependency depends on if it is referenced from a public file (one under either lib or bin), or some other private file.  
(訳：これが通常の依存関係であるべきかdev_dependencyであるべきかは、それがパブリックファイル（libまたはbin配下のファイル）から参照されるのか、その他のプライベートファイルから参照されるのかによって決まる。)

なるほど、原因はプロジェクトのフォルダ構造にあった。  
プロジェクトのフォルダ構成は、以下のようになっている

```
.
├── .dart_tool
│   └── package_config.json
├── .vscode
│   └── launch.json
├── bin
│   ├── money_test.dart
│   └── money.dart
├── .gitignore
├── analysis_options.yaml
├── CHANGELOG.md
├── pubspec.lock
├── pubspec.yaml
├── README.md
└── todo.md
```

ここで注目してほしいのがbinフォルダにテストファイルが置かれていること。  
テストファイルがimportするtestパッケージはdev_dependenciesに依存関係が記述されている。一方、binフォルダ配下にあるファイルはパブリックファイルでありdev_dependenciesの依存関係を参照するべきでない。ということである。これは上記のエラーメッセージから読み取れる範囲内での話だ。

## なぜdev_dependenciesをbinフォルダないから呼び出してはいけないか。

Flutter/Dartでをpubspec.yamlを記述するとき、dependenciesかdev_dependenciesかのどちらかに分けられる。これらの違いを認識していれば、上記のような問題の背景を理解することができる。絶対にダメというわけではないがFlutter/Dartのお作法として従っておいた方がいい内容である。

dependenciesとdev_dependenciesの違いはざっくりと以下の通りである。

- dependencies
    - lib や bin ディレクトリからインポートされる場合に使用する
    - パッケージが依存するパッケージとそのすべての依存関係を取得する
- dev_dependencies
    - test、example、などのディレクトリからのみインポートされる場合に使用する
    - パッケージの開発に必要なパッケージを指定するが、依存するパッケージの dev_dependencies は無視される

詳しくは[公式ドキュメント](https://dart.dev/tools/pub/dependencies#dev-dependencies)を確認してほしい。

## まとめ

再掲になるが、要点をまとめると以下の通り。

- テスト用のパッケージを `import 'package:test/test.dart'` した時に [depend_on_referenced_packaeges](https://dart.dev/tools/linter-rules/depend_on_referenced_packages) というエラーが出た
- 要約すると 「dev_dependenciesにあるパッケージをimportする場合はlibなどに置かない」ということ
- つまり Flutter/Dart のテストファイルはtestフォルダに置こう！

これまでの内容がわかると当たり前のようだが、他のフレームワークだと一般用途と開発用途との依存関係の区別があっても、importのされ方まで区別する必要がなかったので、今回調べてみて勉強になった気がする。
カウントダウンアプリ

Reactでカウントダウンアプリの作成
```tsx
import React, { useState } from 'react';

const Timer: React.FC = () => {
  const [seconds, setSeconds] = useState(120);
  const [isActive, setIsActive] = useState(false);
  const [intervalId, setIntervalId] = useState<NodeJS.Timer | number | null>(null); // 型を `NodeJS.Timer | number | null` に設定

  const handleStartStop = () => {
    if (isActive) {
      // タイマーがアクティブな場合、停止する
      if (intervalId !== null) {
        clearInterval(intervalId as number); // 型キャストを使用
        setIntervalId(null);
      }
    } else {
      // タイマーが非アクティブな場合、開始する
      const id = setInterval(() => {
        setSeconds(prevSeconds => {
          if (prevSeconds <= 1) {
            // タイマーを停止する
            clearInterval(id);
            setIsActive(false);
            return 0; // 時間を0に設定
          }
          return prevSeconds - 1; // 1秒ずつ減らす
        });
      }, 1000);
      setIntervalId(id as unknown as NodeJS.Timer); // 型キャストを使用
    }
    setIsActive(!isActive);
  };

  const handleReset = () => {
    // タイマーをリセット
    if (intervalId !== null) {
      clearInterval(intervalId as number); // 型キャストを使用
      setIntervalId(null);
    }
    setSeconds(0);
    setIsActive(false);
  };

  const formatTime = (seconds: number) => {
    const minutes = Math.floor(seconds / 60);
    const remainingSeconds = seconds % 60;
    return `${minutes}:${remainingSeconds < 10 ? '0' : ''}${remainingSeconds}`;
  };

  return (
    <div>
      <h1>{formatTime(seconds)}</h1>
      <button onClick={handleStartStop}>{isActive ? '停止' : '開始'}</button>
      <button onClick={handleReset} disabled={isActive}>リセット</button>
    </div>
  );
};

export default Timer;
```
なでしこ3で「✕」で掛け算させる

# はじめに
なでしこ3はWEB上（ブラウザ上）で動作する日本語プログラミング言語である。これをChromebookで利用している際に、なぜか動作しないことがあった。問題のコードがこちら。

<blockquote><font color="blue">３✕５</font><font color="black">を</font><font color="#7f00ff">表示</font></blockquote>

エラーメッセージは以下のとおりである。

<blockquote>[エラー]NakoError: [字句解析エラー]main.nako3(1行目): 未知の語句: ✕5を...</blockquote>

# 原因
原因は、非常に単純で文字が違うのだ。つまり、掛け算の記号が「✕」（U+2715）ではなく、「×」（U+00D7）もしくは「✖」（U+2716）を利用しなければならない、ということである。一方で、私が所持しているChromebookの環境では、U+00D7よりもU+2715が先に変換候補となる。加えて、乗算を表す記号は様々あるものの、フォントによっては非常に似通っており、目で判別することが難しい。

https://ja.wikipedia.org/wiki/%C3%97#%E7%AC%A6%E5%8F%B7%E4%BD%8D%E7%BD%AE

# 解決法
```js
navigator.nako3.prepare.convertTable.set(10005,"*");
```
上記コードを実行すればU+2715（10005）を「*」として利用することが出来る。Wikipediaに掲載されている他の掛け算記号も、事前に登録しておきたい場合は、以下のコードを実行する。

```js
navigator.nako3.prepare.convertTable.set(10005,"*");
navigator.nako3.prepare.convertTable.set(10007,"*");
navigator.nako3.prepare.convertTable.set(10008,"*");
navigator.nako3.prepare.convertTable.set(10060,"*");
navigator.nako3.prepare.convertTable.set(10062,"*");
```

なお、このコードは、こちらのページを参考とした。

https://github.com/kujirahand/nadesiko3core/blob/b6dece610e293a72df7ae9954b1421c2233199de/src/nako_prepare.mts#L93

# おわりに
これを応用すると、任意の1文字に、別の意味を持たせることが出来てしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197285/9db1645a-973d-7598-d2d4-ad6fbb247ede.png)

ただし、あまり変なもの登録すると、訳が分からなくなるので気を付けよう。
あと、ChromebookのIME、どうなってるんだ......。

　

以上
【TO DO ＋ 感想】「世界一流エンジニアの思考法」（牛尾剛 文藝春秋 2023） を読んで

## 概要

[https://www.amazon.co.jp/世界一流エンジニアの思考法-牛尾-剛/dp/4163917683](https://www.amazon.co.jp/世界一流エンジニアの思考法-牛尾-剛/dp/4163917683)
エンジニア一年目にこの本を読んで「おもしれ〜」で終わっていたが、エンジニア二年目にしてこの本を上司に勧められたで再読。そしてさっき再読了。

学んだことをブログにまとめると良い、とこの本に書かれていたので即実践。  
Qiita初投稿です。

## TO DO

読了後、まずやってみようと思ったことを箇条書きで紙に書き出し、その内容を以下にまとめ直した。  
（私の曲解を含みます。）

- 日常
    - 瞑想
    - 掃除（ = 物事を未完了のまま放置しない）
    - 学んだことをブログに書く（now!）
- 仕事全般
    - タスクに優先順位を付けて、１位以外はとりあえず無視。
    - ミーティングでは頭の中のみで構造化して整理する。（単純なメモはあり。）
    - 「相手が欲しい情報は何か？」を常に意識する。
    - クイックコールする/される。
    - 定時で上がる。
- コーディング関連
    - バグ発見時、いきなり手を動かさない。仮説を立てて、それから手を動かす。
    - コードを書く前に小さなドキュメントを書く。
    - コードを読み物として扱う。

## 感想

世界一流エンジニアの思考法が一般peopleの実践可能なレベルにまで噛み砕かれていて、読んでいてやってみようと思える内容だった。にも関わらず一回目読んだ時には全く実践していなかったので反省中。
MyBatis ネストしたオブジェクト マッピング 自分用メモ

<h2>ネストしたオブジェクトのマッピング</h2>

１対多の関係のマッピング



```java
@Data
public class Student {

	private String studentId;
	
	private String roomId;
	
	private String name;
	
	private String age;
}
```


```java
@Data
public class Teacher {

	private String teacherId;
	
	private String roomId;
	
	private String name;
	
	private String age;
	
	private String subject;
}
```

```java
@Data
public class ClassRoomDto {

	private String teacherId;
	
	private String roomId;
	
	private Teacher teacher;
	
	private List<Student> studentList;
}
```

<h2>マッパー</h2>



```java
@Mapper
public interface PracticeDao {

    List<ClassRoomDto> selectClassRoomList(@Param("teacherId") String teacherId);
    
}
```
<h2>xml</h2>

```xml
	<resultMap id="BaseMap" type="com.example.practice.dto.ClassRoomDto">
	    <id column="TEACHER_ID" jdbcType="CHAR" property="teacherId" />
	    <id column="ROOM_ID" jdbcType="CHAR" property="roomId" />
	    <association property="teacher" javaType="com.example.practice.entity.Teacher">
	        <id column="TEACHER_ID" jdbcType="CHAR" property="teacherId" />
	        <id column="ROOM_ID" jdbcType="CHAR" property="roomId" />
	        <result column="NAME" jdbcType="CHAR" property="name" />
	        <result column="AGE" jdbcType="CHAR" property="age" />
	        <result column="SUBJECT" jdbcType="CHAR" property="subject" />
	    </association>
	    <collection property="studentList" ofType="com.example.practice.entity.Student">
	        <id column="STUDENT_ID" jdbcType="CHAR" property="studentId" />
	        <id column="ROOM_ID" jdbcType="CHAR" property="roomId" />
	        <result column="S_NAME" jdbcType="CHAR" property="name" />
	        <result column="S_AGE" jdbcType="CHAR" property="age"/>
	    </collection>
	</resultMap>
	
	<select id="selectClassRoomList" parameterType="map" resultMap="BaseMap">
	    SELECT
	        T.TEACHER_ID
	        , T.ROOM_ID
	        , T.NAME
	        , T.AGE
	        , T.SUBJECT
	        , S.STUDENT_ID
	        , S.ROOM_ID
	        , S.NAME AS S_NAME
	        , S.AGE AS S_AGE
	    FROM
	        TEACHER T
	    INNER JOIN
	        STUDENT S
	        ON T.ROOM_ID = S.ROOM_ID
	    WHERE
	        T.TEACHER_ID = #{teacherId, jdbcType=CHAR}
	</select>
```

<h2>結果</h2>

```txt
[ClassRoomDto(teacherId=T001, roomId=A01, 
teacher=Teacher(teacherId=T001, roomId=A01, name=田中 一郎, age=40, subject=数学), 
studentList=[
  Student(studentId=S001, roomId=A01, name=山田 太郎, age=15), 
  Student(studentId=S004, roomId=A01, name=佐藤 次郎, age=15), 
  Student(studentId=S005, roomId=A01, name=高橋 花子, age=14)])]
```
フラッシュカード

```
function myFunction() {
  
  const fontSize = Browser.inputBox('フォントサイズを入力してください:', Browser.Buttons.OK_CANCEL);

  if (fontSize === 'cancel' || fontSize === '') {
    return;
  }

  const spreadsheetId = '';
  const slideDeckId = '';

  const sheet = SpreadsheetApp.openById(spreadsheetId).getSheets()[0];
  const data = sheet.getDataRange().getValues();

  const slideDeck = SlidesApp.openById(slideDeckId);

  const templateSlide = slideDeck.getSlides()[0];

  const pairs = [];
  for (let i = 1; i < data.length; i++) {
    const question = data[i][0];
    const answer = data[i][1];
    pairs.push([question, answer]);
  }

  pairs.sort(() => Math.random() - 0.5);

  pairs.forEach(pair => {
    const question = pair[0];
    const answer = pair[1];

    const questionSlide = slideDeck.appendSlide(templateSlide.getLayout());
    const questionTextBox = questionSlide.getShapes()[0].getText();
    questionTextBox.setText(question);
    questionTextBox.getTextStyle().setFontSize(Number(fontSize));

    const answerSlide = slideDeck.appendSlide(templateSlide.getLayout());
    const answerTextBox = answerSlide.getShapes()[0].getText();
    answerTextBox.setText(answer);
    answerTextBox.getTextStyle().setFontSize(Number(fontSize));
  });

  templateSlide.remove();
}
攻撃されがちなユーザー名

# 自分のsshサーバーの攻撃を可視化
sshのブルートフォースアタックで使われているユーザー名上位50位がわかるコマンドを試してみた。
パスワードも簡単なものにしていると乗っ取られるので要注意。

```
$ sudo lastb | awk '{print $1}' | sort | uniq -c | sort -nr | head -50
   1198 admin
   1079 ubuntu
    824 user
    786 test
    497 postgres
    411 oracle
    373 git
    250 hadoop
    241 debian
    233 ftpuser
    144 dell
    140 dev
    139 guest
    130 testuser
    125 steam
    120 lenovo
    106 es
    106 Antminer
    101 minecraf
     98 user1
     94 deploy
     87 jenkins
     76 www
     75 tomcat
     74 grid
     72 zabbix
     72 ubnt
     72 ansible
     69 test1
     69 odoo
     69 cloud
     64 centos
     63 baikal
     63 administ
     61 teste
     59 uftp
     59 elastic
     57 sysadmin
     56 ftp
     56 docker
     55 demo
     53 nagios
     53 deployer
     52 test2
     51 kafka
     50 student
     48 username
     48 server
     48 elastics
     47 prueba
```

# 参考資料
http://programingx.blog.fc2.com/blog-entry-24.html
ORDS21と22以降のディレクトリ構造の違い

# はじめに
以前Oracle APEX23.2/ORDS23.4のインストールメモを記載しましたが、ORDSのディレクトリ構造が以前のバージョンと大きく異なっていましたのでまとめました

https://qiita.com/fujid/items/15f6a77cc1c6a0cb1f66

## ORDS21の場合

構成フォルダのディレクトリ構造

```
./ords
|
+-defaults.xml      ・・・ データベース共通の設定
+-url-mapping.xml   ・・・　各DBとURLのマッピング
|
+conf/
  |      
  +-apex.xml         ・・・ 他のDBにマッピングされていないルート(URL)で使用される設定
  +-(db-name).xml    ・・・ 各DB用の設定
  +-(db-name).xml    ・・・ 各DB用の設定
```

* 「defaults.xml」に全てのデータベース共通の設定を記載し、「(db-name).xml」に各DB固有の設定を記載します
* 「url-mapping.xml」に各DBへルーティングするルール(URL)を記載します
  (例）
  ```<pool name="db1" base-path="/path1" />```
  ```<pool name="db2" base-path="/path2" />```



https://docs.oracle.com/cd/F58638_01/aelig/about-REST-configuration-files.html#GUID-21CE5541-568A-4BCB-969C-7E3217E924C2

# ORDS22以降の場合

構成フォルダのディレクトリ構造

```
+- global/
    +- settings.xml   ・・・ ポート番号やルートパスなど
+- databases/
    +- default/
        +- pool.xml  ・・・ 他のDBにマッピングされていないルート(URL)で使用される設定
        +- wallet/
    +- (pool-name)/
         +- pool.xml ・・・ 各DB用の設定
         +- wallet/
    +- (pool-name)/
         +- pool.xml ・・・ 各DB用の設定
         +- wallet/
```

* globalディレクトリには、ORDSインスタンス全体に適用される設定が含まれます
* databasesディレクトリには、データベース・プール構成が含まれます
* (pool-name)/pool.xml にDB固有の設定を記載します
* URLとDBのマッピングは、(pool-name)の名前でマッピングされます。例えば、(pool-name)がdb1だった場合、「http://servername:port/ords/db1 」でアクセスした場合、db1にマッピングされます
* 他のDBにマッピングされていないルート(URL)の場合、defaultが使用されます（旧バージョンのapex.xmlに相当します）

https://docs.oracle.com/cd/F94475_01/ordig/about-REST-configuration-files.html#GUID-FE96042C-AD0E-4008-B02C-5C1360C94505
権限セット・権限セットグループ付与のユーザ一覧を表示する方法

本橋孝昭です。

Salesforceのユーザ一覧はレポートタイプ「ユーザー」で表示可能です



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/90449583-2cad-61dc-06c2-157846ac1c6e.png)


しかしながらレポートタイプ「ユーザー」ではそのユーザーが付与する権限セット・権限セットグループの確認することができません


ユーザーが付与する権限セット・権限セットグループ一覧を表示させるには、少し前までは何かしらのApp Exchange（権限セットスコープ）などが必要で標準機能では対応できませんでした

https://qiita.com/Takaa/items/c7633d7d689e995138f6


しかしながら、2023年からユーザーが付与する権限セット・権限セットグループ一覧をレポートで表示することが可能になりました

ここではユーザーが付与する権限セット・権限セットグループ一覧をレポートで表示する方法とその注意点について解説します

## ステップ1 レポートタイプを作成しよう

まずはユーザーが付与する権限セット・権限セットグループ一覧をレポートを表示するためのレポートタイプを作成します

レポートタイプの設定は以下画像の通りです

>ユーザー (A)
 関連レコードが存在する/しない: 権限セットの割り当て (ユーザー) (B)

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/e8a7a7db-bb38-c23b-abaf-a94f28f68048.png)


## ステップ2 ステップ1で作成したレポートタイプでレポートを作成しよう


次にステップ1で作成したレポートタイプを使うことでレポート作成をすることでユーザ一覧およびそのユーザに紐づく権限セット・権限セットグループ一覧を表示することができます


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/31888fb7-52b1-aa9e-4cef-5fb76df1af52.png)


なお、こちらのレポートタイプでレポートを作成する際は以下の注意が必要です

## 注意点1 ユーザに紐づいている権限が権限セットか権限セットグループかパッと見て分かりにくい

例えば、今回はユーザーMotohashi Takaakiに対して以下のように
権限セットグループ:Group001（内訳、権限セットSet001と権限セットSet002が付与されたもの）
権限セット：Set002とSet003
が付与されていたとします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/5daf8cb2-9f3c-c609-a47c-b83eac51c2c5.png)

この場合、下記画像のように
・権限セット：権限セット名

に権限セットも権限セットグループも出てしますので、どれが権限セットグループか。どれが権限セットか分かりにくいですね。

回避策として
・権限セットグループ：API参照名
を表示させることにより、権限セットグループの場合は
・権限セットグループ：API参照名
に表示があるため、権限セットグループか権限セットかがレポート上で見分けられることが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/31888fb7-52b1-aa9e-4cef-5fb76df1af52.png)


## 注意点2 権限セットグループの内訳が分からない
権限セットグループにはどのような権限セットが付与されているかはこの一覧では分かりません

回避策としては権限セットグループに説明書きで「どの権限セットグループにどの権限セットが含まれているか」を記載しておいて、それをレポート上に表示でしょうか

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/857bc2db-a8ec-12cc-d364-4be8638812d3.png)

なお、冒頭説明した権限セットスコープではどの権限セットグループにどの権限セットが付与されているか分かりやすいです

https://qiita.com/Takaa/items/c7633d7d689e995138f6
Cosmos DB (MongoDB API) の Kotlin/jvmクライアント - Azure - Memo

# 概要
(日記) Azure CosmosDB MongoDB API に、Kotlin(jvm)で接続検証。

[総目次](https://qiita.com/shokkaa/private/7a1633dbf58ddc81f894)
[目次: Azure Development](https://qiita.com/search?sort=&q=tag%3AAzure+tag%3Adevelopment+user%3Ashokkaa)

# 前提

https://qiita.com/shokkaa/items/e38803a481b9df33ee7a

https://qiita.com/shokkaa/items/9593cf1b5794104271f6

[Azureクラウド上のリソース確保](https://qiita.com/shokkaa/items/9593cf1b5794104271f6#azure%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E4%B8%8A%E3%81%AE%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E7%A2%BA%E4%BF%9D)まで実施

CosmosDB → クイック スタート → Java → プライマリ接続文字列を取得
※CLIでやるなら[→こちら](https://qiita.com/shokkaa/items/9593cf1b5794104271f6#%E3%83%93%E3%83%AB%E3%83%89%E3%81%A8%E5%AE%9F%E8%A1%8C)

# サンプルコード
```build.gradle.kts
plugins {
    kotlin("jvm") version "1.9.21"
    application
}
repositories{mavenCentral()}
application{mainClass="MainKt"}
dependencies {
    implementation("org.mongodb:mongo-java-driver:3.12.14")
    // https://mvnrepository.com/artifact/org.mongodb/mongo-java-driver
}
```
```src/main/kotlin/Main.kt
import com.mongodb.MongoClient
import com.mongodb.MongoClientURI
import com.mongodb.client.model.Filters
import org.bson.Document

fun main(args: Array<String>) {
    MongoClient(MongoClientURI(args[0])).use { client ->
        client.getDatabase("db").getCollection("coll").apply {
            insertOne(Document("fruit", "apple"))
            insertOne(Document("fruit", "mango"))
            find(Filters.eq("fruit", "apple")).forEach { println(it.toJson()) }
        }
    }
}
```
[→GitHub](https://github.com/kyoya-p/samples/tree/8f06bc38e2c2f03f123a44472186a2af6e7021bc/2024/Azure/cosmosdbJava)


```
# ビルド/実行
```sh
COSMOS_CONNECTION_STRING="プライマリ接続文字列"
sh gradlew run --args "$COSMOS_CONNECTION_STRING"
```
```:結果
{"_id": {"$oid": "666565a11689f2692a8df769"}, "fruit": "apple"}
...
```

# (参考)Coroutinで
```src/main/kotlin/Main2.kt
suspend fun main(args: Array<String>) = callbackFlow {
    MongoClient(MongoClientURI(args[0])).use { client ->
        client.getDatabase("db").getCollection("coll").apply {
            insertOne(Document("fruit", "apple"))
            insertOne(Document("fruit", "mango"))
            find(Filters.eq("fruit", "apple")).forEach { doc -> trySendBlocking(doc!!) }
        }
        close()
    }
    awaitClose()
}.collect { println(it.toJson()) }
```
GitHub Actions VS Code extension をインストールしたときのメモ

# 背景・目的
GitHub Actions VS Code extensionをインストールしたときのメモ書きです

# 概要
[こちら](https://marketplace.visualstudio.com/items?itemName=github.vscode-github-actions
)のドキュメントによると、下記の特徴があります

- ワークフローと実行を管理する
- 編集ワークフロー（構文の強調表示、自動補完、ホバー、検証）
- CIビルドとデプロイメントを追跡する
- 障害を調査してログを表示する
- 環境、シークレット、変数などの設定を変更する


# 実践
## 環境構築
1. VSCodeで拡張機能をクリックします
1. Github Actionsで検索します
1. GitHub Actionsが表示されるので、「インストール」をクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/8e91f610-ef50-0657-ccd5-48e984c89c73.png)
1. 「Sign in to GitHub」をクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/1dc5cbcc-bf02-e210-e39b-d80d0322a200.png)
1. ブラウザが立ち上がるので、「VIsual Studio Codeを開く」をクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/8ef68212-a46c-cae6-1e2c-504069a11bb0.png)
1. GitHub Actionsのタブをクリックし、「Refresh」をクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/c95292c5-2ff5-a808-af36-7ed40cb92758.png)
1. Workflowの一覧が見えました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/b7702b7b-428e-1337-6b32-59e7a88447b4.png)

## Workflowの履歴を確認
1. Workflowでは、履歴が確認できます。ブラウザマークが表示されますので、クリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/ed705d76-c620-e622-458a-be8306e586b0.png)
1. ブラウザが表示され、確認できました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/91d6c792-90a3-5f48-beaa-39ba15e2ad3d.png)

## ジョブの確認
1. ジョブを開きます
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/d5e74a89-9cc4-c807-4a64-b1b966e535d5.png)

1. VSCodeで確認できました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/5d9253e5-97d2-96a2-d3c5-90ceeb2cbb4e.png)

## コード補完機能
1. VSCodeでエラーが表示されるようになりました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/e8d30d1e-d1fb-37e3-c793-097ca3fb481f.png)

1. サジェストが出る　ようになりました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/c69aab70-bf23-d40a-86cf-55a29b32dd9d.png)

# 考察
今回は、GitHub ActionsのVS Code extensionをインストールしました。特にエラーが、表示されるのが良いですね。もっと使い込んでいこうと思います。

# 参考
https://marketplace.visualstudio.com/items?itemName=github.vscode-github-actions