ここ数年リモートワークが続き運動不足も甚だしいし2月にスキーに行くのでヒューマン準備体操位はしておかないと怪我やゲレンデで遭難の恐れがあるので先月、嫁の家族会員1600円/月でジェクサーに行ったところ、意外と自転車とルームランナーが良かったので、近所徒歩3分に出来たチョコザップに入った。
ジェクサーは高いしちょっと遠いので私の事だから使用頻度からして勿体ないからな。
いやー、やっぱジェクサーの後だと安普請で狭い。大きな風呂やプールが無いのは当然だが、自転車漕ぎマシンとかぎっちぎちに詰めてあって下手すると乗り降りする時に横の人にぶつかりそう。そしてトイレの個室のごとき「セルフエステ」部屋がいっぱいあるんだけどこちらは誰も使っておらず。これを潰してルームランナーとか増設しないかしら。
そして、ルームランナーと自転車漕ぎマシンにテレビが付いてない…ジェクサーのには付いていて「うむこれなら夜中に東京MXTVをみに行くのも良いかも…」と思ったのに。
ともあれ「安くて近所」なのでまぁ仕方あるまい。ルームランナー抜きに自分の意志の力だけで10km/時で30分休みなく走り続けるとか無理だしそれだけでも価値はあろう。
ちなみに昨日と本日、二日連続で行ったら結構ヘトヘトである。10kmで30分、早歩きか小走り、常人ならウォーミングアップの運動でこのザマとは流石は数年にわたる運動不足よ。
だがまだ2日目。2月までに休みの日は毎回、平日は何とか1回ずつ行けば、筋肉は付かなくとも根性は付くだろう。
あと、体重計とか時計とか貰えるらしいんだけどまだ貰ってない。どうやったら貰えるのか…。


このエントリーをはてなブックマークに追加 mixiチェック

年末に靴下脱ぐ時に机につま先をぶつけて痛がっていたけれど、それでも元気に12/29にはスポーツクラブで何かダンスを4本もやって一昨日は成田山へ行ったりしてたけれど、それにしても中々治らん、というか成田山から帰ってから悪化しているので病院行ったら、足の指の骨に綺麗にヒビが入っているそうな。
足の小指と薬指を石膏で固めたギブス付けてる。お風呂の時は取れるけれど、それ以外は二週間付けっぱなしだそうな。



このエントリーをはてなブックマークに追加 mixiチェック

Java製のクライアントを作ってNostrに投稿したい(既存のJava製のボットにNostr投稿機能を追加したいので調べた。
一応動作したのでNostrのJava製クライアントに関する日本語情報が少ない事だしここに記す。ちなみにエラー対応不足のため書き込みに失敗すると子スレッドが残ってしまう。
■1.nostr-javaのClientクラス
やれ~/.nostr-java配下にプロパティファイルを作れだのハンドラを作れだのmodule-info.javaを作れと喧しい上に実行したら
Exception in thread "main" java.lang.NoClassDefFoundError: org/bouncycastle/jce/provider/BouncyCastleProvider
と言われhttps://www.bouncycastle.org/latest_releases.htmlからjarをダウンロードして入れたり
java.util.concurrent.ExecutionException: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested targetr
と言われ実行時に
-Djavax.net.ssl.trustStore=C:\Program Files\Java\jdk-21.0.1\lib\security\cacerts
を入れたはいいがその後もトラブルが起きて解決できず。

■2.JavaでNostrのリレーに1件だけテキストイベントを投稿するコードを書いてみた
…nostr-javaのサンプルよりは分かりやすいけれど、まずビルドが通らない。多分JettyのWebSocketのライブラリとHTTPClientのライブラリのバージョンの不一致あたりだと思うけどそもそもimport文も省略されているので想像で入れたりしたけれど結局通らず。

■3.Jetty 12.x のWebSocketClientのサンプルコードを育てて自作
2番はビルドできないとは言え大いに参考にしつつ、まずはビルドや実行が通るように慎重に本家Jettyのサンプルから育てていく。
とりあえず最後まで動作して相手リレーサーバから
["OK","fdf83a3115ae12c3331acd6390641a2ab075b85bf21a44d7e10ce4d0379b0dc6",true,""]
なる電文が返って来たしNostterにも表示されたので動作はした模様
0103c

ちなみにWebSocketのクローズの辺りは少々あやしい。
NostrSendMain.java
/**
 * Nostr書き込み処理サンプル。
 */
package nekora.nostr;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.websocket.api.Callback;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.client.WebSocketClient;

import nostr.base.PrivateKey;
import nostr.base.PublicKey;
import nostr.crypto.schnorr.Schnorr;
import nostr.util.NostrUtil;

/**
 * 
 */
public class NostrSendMain {
	//final String RELAY_URL = "wss://relay.nostr.wirednet.jp";
	final String RELAY_URL = "wss://relay-jp.nostr.wirednet.jp";
	final String CONTENT = "初カキコ…ども…from My Java Client";

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		NostrSendMain my = new NostrSendMain();
		my.exec(args);
	}

	private void exec(String[] args) {
		// Use a standard, HTTP/1.1, HttpClient.
		HttpClient httpClient = new HttpClient();

		// Create and start WebSocketClient.
		WebSocketClient webSocketClient = new WebSocketClient(httpClient);
		try {
			webSocketClient.start();
			// The client-side WebSocket EndPoint that
			// receives WebSocket messages from the server.
			MyAutoDemandListenerEndPoint myendp = new MyAutoDemandListenerEndPoint();
			// The server URI to connect to.
			URI serverURI = URI.create(RELAY_URL);

			// クライアントエンドポイントをサーバーに接続.
			CompletableFuture clientSessionPromise = webSocketClient.connect(myendp, serverURI);

			// 接続処理完了を待つ
			// Thread.sleep(1500); // これ要らない気がするので削除してみた

			// セッションを取得
			try (Session session = clientSessionPromise.join()) {
				if (!session.isOpen()) {
					System.err.println("接続できませんでした");
					return;
				}
				System.out.println("接続OK…" + session);

				// Nonstr特化通信
				nostrExec(session);
				System.out.println("Nostrに送信完了");

			} catch (Exception e) {
				throw e;
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// クローズ
			try {
				webSocketClient.stop();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		System.out.println("すべて完了");
	}

	/**
	 * Nostrリレーサーバと通信 https://zenn.dev/memory_of_snow/articles/1f0ddd964c5f83 参考
	 * 
	 * @param webSocketClient
	 * @param session
	 */
	private void nostrExec(Session session) {
		// テスト用秘密鍵(=アカウント)をランダムに作成。
		PrivateKey secKey = new PrivateKey(Schnorr.generatePrivateKey());
		//PrivateKey secKey = new PrivateKey("アカウント固定する場合はエンコードされた秘密鍵文字列");

		try {
			// 秘密鍵から公開鍵を作成
			PublicKey publicKey = new PublicKey(Schnorr.genPubKey(secKey.getRawData()));
			String publicKeyHex = publicKey.toString();

			System.out.println("SecKey(HEX) = " + secKey);
			System.out.println("publicKey(HEX) = " + publicKey);

			long created_at = Instant.now().getEpochSecond();
			int kind = 1;
			List> tags = new ArrayList<>();

			// id計算に使う要素を集める
			// [0,"公開鍵(HEX)",投稿時間,kind(プレーンテキスト投稿は1),タグ群,"投稿内容"]
			String partsForId = "[0,\"" + publicKeyHex + "\"," + created_at + "," + kind + "," + tags + ",\"" + CONTENT
					+ "\"]";
			byte[] idSourceBytes = partsForId.getBytes(StandardCharsets.UTF_8);
			String id = NostrUtil.bytesToHex(NostrUtil.sha256(idSourceBytes));
			byte[] signedHashedSerializedEvent = Schnorr.sign(NostrUtil.sha256(idSourceBytes), secKey.getRawData(),
					NostrUtil.createRandomByteArray(32));
			String sig = NostrUtil.bytesToHex(signedHashedSerializedEvent);

			// メッセージは["EVENT",{
			// "id":"id",
			// "pubkey":"公開鍵(Hex)",
			// "created_at":作成時間(UnixTimeStamp),
			// "kind":kind(プレーンテキストは1),
			// "tags":[],
			// "content":"投稿内容",
			// "sig":"署名"
			// }]
			String message = "[\"EVENT\",{\"id\":\"" + id + "\",\"pubkey\":\"" + publicKeyHex + "\","
					+ "\"created_at\":" + created_at + ",\"kind\":" + kind + ",\"tags\":" + tags + ","
					+ "\"content\":\"" + CONTENT + "\",\"sig\":\"" + sig + "\"}]";

			String displayMessage = message.replace(",", ",\n");
			System.out.println("組み立てたメッセージ:\n" + displayMessage);

			// session.getRemote().sendString(message); // こんなメソッドは無いと言われる
			MySendCallBack calbak = new MySendCallBack(message);
			session.sendText(message, calbak);

			// 受信時間稼ぎ
			Thread.sleep(1500); // これ必要なのか分からないがサンプルに従い残す。

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
MyAutoDemandListenerEndPoint.java
package nekora.nostr;

import org.eclipse.jetty.websocket.api.Session;

/**
 * 接続用エンドポイント 以下をコピペ
 * https://eclipse.dev/jetty/documentation/jetty-12/programming-guide/index.html#pg-client-http
 */

public class MyAutoDemandListenerEndPoint implements Session.Listener.AutoDemanding {
	private Session session;

	@Override
	public void onWebSocketOpen(Session session) {
		this.session = session;
		// No need to demand here, because this endpoint is auto-demanding.
	}

	@Override
	public void onWebSocketText(String message) {
		System.out.println("受信メッセージ=" + message);
		// No need to demand here, because this endpoint is auto-demanding.
	}

}
MySendCallBack.java
package nekora.nostr;

import org.eclipse.jetty.websocket.api.Callback;

/**
 * 送信用コールバック
 * https://eclipse.dev/jetty/documentation/jetty-12/programming-guide/index.html#pg-websocket-session-send
 */
public class MySendCallBack implements Callback {
	private String message;

	public MySendCallBack(String message) {
		this.message = message;
	}

	@Override
	public void succeed() {
		System.out.println("テキスト送信成功." + message);
	}

	@Override
	public void fail(Throwable x) {
		// No need to rethrow or close the session.
		System.out.println("テキスト送信失敗." + message + " エラー=" + x.getMessage());
	}

}
ビルド時にIvy.xmlに指定するのは以下のみ(Mavenならpom.xml)。
dependency org="org.eclipse.jetty.websocket" name="jetty-websocket-jetty-client" rev="12.0.5"
あと、nostr-javaも使っているので事前にimportして、参照させる必要がある。
0104

自分の秘密鍵をhexにしたい時は下記を使う
https://nak.nostr.com/



このエントリーをはてなブックマークに追加 mixiチェック

「成田山のアミュレット」で名高い成田山は新勝寺に初めて行ってきた。
結構でかい。多分高幡不動よりでかい。
そしてお守りの有名どころだけあってお守りの売店の数と規模が物凄くて、こんなにお守りを売ってるお寺は他に知らない…。
とりあえず正月なので破魔矢を買ったんだが、よく見ると破魔矢ではなく守護矢だった。
割と遠くの駐車場に車を停めててくてく歩いて何となく「こちら近道」と書いてある→に従って行ったら観音堂の裏あたりから入れたんだけど、正門は全然別の所にあった。そしてそちらには大群衆が待機しており警官たちが交通整理ならぬ混雑整理を…まぁいいか。
参道が非常に長く大規模でうなぎ屋と奈良漬け屋が多かった。そしてこちらにも大行列が。もしやこの参道から正門を通って入るのが正道では…おそらく数時間かかるだろうけれど。
帰りに成田山近くのビッグボーイへ寄ったら正月なので人手不足なのであろう、店内はガラガラなのに入口では7組が待機、全然動く様子が無いので諦めてそのまた近所のびっくりドンキーへ。こちらは人手が足りているのか割とすぐ入れた…。ちなみにここのハンバーグは余り肉の味がしないふわふわした…肉のハナマサで売ってるアレと同じ系統のパン粉が主成分の代物だった。サイゼリヤだってもう少しひき肉感があるというのに…。




このエントリーをはてなブックマークに追加 mixiチェック

本日になって年賀状を書き始めたが、まぁ3日までに出せばセーフ!


このエントリーをはてなブックマークに追加 mixiチェック

今年は個人的にはこれと言って大きな出来事は無かったが、そうだな…投信がめっちゃ儲かったな。
いや私が活躍したからではなく主に日興証券のお兄さんと米連邦準備制度理事会と政府日銀のお陰ではあるが増えたのは私の資産なのでまぁヨシ。


このエントリーをはてなブックマークに追加 mixiチェック

嫁が会員で、今月(のみ)は家族会員として1650円/月で利用できるため3回行って本日が最終日。
結局レッスンはやらなかったものの、自転車漕ぐやつとルームランナー二種類。1回30分だからそれだけで1時間半、風呂入ると2時間かかる。
風呂もプールも付いていて申し分ないんだが、本当に入ると月謝が1万数千円、私は精々週一なので元が取れないよな。新川崎まで行くのも地味に面倒だし。
平日は定時で終わる仕事に付いてて体を動かすのが好きな人には良いかもしれぬ。嫁とか。
ただ、確かに在宅勤務数年目で運動不足なのは確かで体も非常に硬くなっているし2月にはスキー行くので体をほぐしてはおきたい。近所だとゴールドジムとチョコザップがあるな。ゴールドジムはJEXER以上に高いからチョコザップかね。

ジェクシー! スマホを変えただけなのに [DVD]
ローズ・バーン
インターフィルム
2020-12-23

このエントリーをはてなブックマークに追加 mixiチェック

↑このページのトップヘ