Not only is the Internet dead, it's starting to smell really bad.:2021年05月21日分

2021/05/21(Fri)

[オレオレN6] もう何も以下略

libcのbm(3)呼んでる部分だけ自分で書いたBM法のコードに置き換えたらGNU configureもちゃんと完走するので、戦犯Keith Bosticじゃねえの疑惑が高まってきた、以下差分。

diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h
index 138ec66b8c3..8a53c765079 100644
--- a/lib/libc/include/namespace.h
+++ b/lib/libc/include/namespace.h
@@ -513,6 +513,9 @@
 #define regerror		_regerror
 #define regexec			_regexec
 #define regfree			_regfree
+#define re_bm_comp		_re_bm_comp
+#define re_bm_exec		_re_bm_exec
+#define re_bm_free		_re_bm_free
 #define registerrpc		_registerrpc
 #define res_init		_res_init
 #define res_mkquery		_res_mkquery
diff --git a/lib/libc/regex/Makefile.inc b/lib/libc/regex/Makefile.inc
index bf087c110b3..14fad6bcf6e 100644
--- a/lib/libc/regex/Makefile.inc
+++ b/lib/libc/regex/Makefile.inc
@@ -3,7 +3,7 @@
 
 CPPFLAGS+=-DPOSIX_MISTAKE
 
-SRCS+=	regcomp.c regerror.c regexec.c regfree.c
+SRCS+=	regcomp.c regerror.c regexec.c regfree.c regbm.c
 
 MAN+=	regex.3 re_format.7
 
diff --git a/lib/libc/regex/engine.c b/lib/libc/regex/engine.c
index 06d9c251eeb..9485ab3b03f 100644
--- a/lib/libc/regex/engine.c
+++ b/lib/libc/regex/engine.c
@@ -130,13 +130,6 @@ matcher(struct re_guts *g, const char *string, size_t nmatch,
 	const char *start;
 	const char *stop;
 	int error = 0;
-	/* Boyer-Moore algorithms variables */
-	const char *pp;
-	size_t cj, mj;
-	const char *mustfirst;
-	const char *mustlast;
-	size_t *matchjump;
-	size_t *charjump;
 
 	_DIAGASSERT(g != NULL);
 	_DIAGASSERT(string != NULL);
@@ -158,46 +151,12 @@ matcher(struct re_guts *g, const char *string, size_t nmatch,
 
 	/* prescreening; this does wonders for this rather slow code */
 	if (g->must != NULL) {
-		if (g->charjump != NULL && g->matchjump != NULL) {
-			mustfirst = g->must;
-			mustlast = g->must + g->mlen - 1;
-			charjump = g->charjump;
-			matchjump = g->matchjump;
-			pp = mustlast;
-			for (dp = start+g->mlen-1; dp < stop;) {
-				/* Fast skip non-matches */
-				while (dp < stop && charjump[(int)*dp])
-					dp += charjump[(int)*dp];
-
-				if (dp >= stop)
-					break;
-
-				/* Greedy matcher */
-				/* We depend on not being used for
-				 * for strings of length 1
-				 */
-				while (*--dp == *--pp && pp != mustfirst);
-
-				if (*dp == *pp)
-					break;
-
-				/* Jump to next possible match */
-				mj = matchjump[pp - mustfirst];
-				cj = charjump[(int)*dp];
-				dp += (cj < mj ? mj : cj);
-				pp = mustlast;
-			}
-			if (pp != mustfirst)
-				return REG_NOMATCH;
-		} else {
-			for (dp = start; dp < stop; dp++)
-				if (*dp == g->must[0] &&
-				    (size_t)(stop - dp) >= g->mlen &&
-				    memcmp(dp, g->must, (size_t)g->mlen) == 0)
-					break;
-			if (dp == stop)		/* we didn't find g->must */
-				return REG_NOMATCH;
-		}
+		if (g->bmpat != NULL)
+			dp = re_bm_exec(g->bmpat, start, (size_t)(stop - start));
+		else
+			dp = memmem(start, (size_t)(stop - start), g->must, g->mlen);
+		if (dp == NULL)
+			return REG_NOMATCH;
 	}
 
 	/* match struct setup */
diff --git a/lib/libc/regex/regbm.c b/lib/libc/regex/regbm.c
new file mode 100644
index 00000000000..8b4f455a818
--- /dev/null
+++ b/lib/libc/regex/regbm.c
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c)2021 Takehiko NOZAKI,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <assert.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "regbm.h"
+
+struct re_bmpat {
+	const char *pat;
+	size_t patlen;
+	size_t cjump[UCHAR_MAX+1];
+	size_t mjump[];
+};
+
+#ifndef MAX
+#define MAX(a, b)	(((a) > (b)) ? (a) : (b))
+#endif
+
+re_bmpat_t
+re_bm_comp(const char *pat, size_t patlen)
+{
+	re_bmpat_t b;
+	size_t lastp, i, n, suffix;
+
+	lastp = patlen - 1;
+	if (patlen > SIZE_MAX / sizeof(b->mjump[0]) - sizeof(*b) ||
+	    (b = malloc(sizeof(*b) + patlen * sizeof(b->mjump[0]))) == NULL)
+		return NULL;
+	for (i = 0; i < __arraycount(b->cjump); ++i)
+		b->cjump[i] = patlen;
+	for (i = 0; i < patlen; ++i)
+		b->cjump[(unsigned char)pat[i]] = lastp - i;
+	for (i = patlen; i-- > 0; /**/) {
+		n = i + 1;
+		b->mjump[i] = (!memcmp(pat, &pat[n], patlen - n))
+		    ? lastp + n - i : lastp * 2 - i;
+	}
+	for (i = 0; i < lastp; ++i) {
+		for (suffix = 0; suffix < i; ++suffix) {
+			n = lastp - suffix;
+			if (pat[i - suffix] != pat[n]) {
+				b->mjump[n] = lastp + suffix - i;
+				break;
+			}
+		}
+	}
+	b->pat = pat;
+	b->patlen = patlen;
+	return b;
+}
+
+const char *
+re_bm_exec(re_bmpat_t b, const char *s, size_t slen)
+{
+	size_t lastp, si, pi, jump;
+
+	if (slen >= b->patlen) {
+		lastp = b->patlen - 1;
+		for (si = lastp; /**/; si += jump) {
+			while ((jump = b->cjump[(unsigned char)s[si]]) > 0) {
+				if (si > slen - jump)
+					return NULL;
+				si += jump;
+			}
+			for (pi = lastp; s[--si] == b->pat[--pi]; /**/) {
+				if (pi == 0)
+					return s + si;
+			}
+			jump = MAX(b->cjump[(unsigned char)s[si]], b->mjump[pi]);
+			if (si > slen - jump)
+				break;
+		}
+	}
+	return NULL;
+}
+
+void
+re_bm_free(re_bmpat_t b)
+{
+	free(b);
+}
diff --git a/lib/libc/regex/regbm.h b/lib/libc/regex/regbm.h
new file mode 100644
index 00000000000..b9260c9ad82
--- /dev/null
+++ b/lib/libc/regex/regbm.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c)2021 Takehiko NOZAKI,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef REGBM_H_
+#define REGBM_H_
+
+typedef struct re_bmpat *re_bmpat_t;
+
+re_bmpat_t re_bm_comp(const char *, size_t);
+const char *re_bm_exec(re_bmpat_t, const char *, size_t);
+void re_bm_free(re_bmpat_t);
+
+#endif
diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c
index 8b2101db2a1..ebc4a041550 100644
--- a/lib/libc/regex/regcomp.c
+++ b/lib/libc/regex/regcomp.c
@@ -50,6 +50,7 @@ __weak_alias(regcomp,_regcomp)
 #endif
 
 #include "utils.h"
+#include "regbm.h"
 #include "regex2.h"
 
 #include "cclass.h"
@@ -105,8 +106,6 @@ static int enlarge(struct parse *, sopno);
 static void stripsnug(struct parse *, struct re_guts *);
 static void findmust(struct parse *, struct re_guts *);
 static int altoffset(sop *, int);
-static void computejumps(struct parse *, struct re_guts *);
-static void computematchjumps(struct parse *, struct re_guts *);
 static sopno pluscount(struct parse *, struct re_guts *);
 
 static char nuls[10];		/* place to point scanner in event of error */
@@ -144,9 +143,6 @@ static int never = 0;		/* for use in asserts; shuts lint up */
 #define	never	0		/* some <assert.h>s have bugs too */
 #endif
 
-/* Macro used by computejump()/computematchjump() */
-#define MIN(a,b)	((a)<(b)?(a):(b))
-
 #define	RECLIMIT	256
 
 /*
@@ -213,8 +209,7 @@ regcomp(regex_t *preg, const char *pattern, int cflags)
 	g->neol = 0;
 	g->must = NULL;
 	g->moffset = -1;
-	g->charjump = NULL;
-	g->matchjump = NULL;
+	g->bmpat = NULL;
 	g->mlen = 0;
 	g->nsub = 0;
 	g->backrefs = 0;
@@ -237,14 +232,8 @@ regcomp(regex_t *preg, const char *pattern, int cflags)
 	/* only use Boyer-Moore algorithm if the pattern is bigger
 	 * than three characters
 	 */
-	if (g->mlen > 3) {
-		computejumps(p, g);
-		computematchjumps(p, g);
-		if (g->matchjump == NULL) {
-			free(g->charjump);
-			g->charjump = NULL;
-		}
-	}
+	if (g->mlen > 3)
+		g->bmpat = re_bm_comp(g->must, g->mlen);
 	g->nplus = pluscount(p, g);
 	g->magic = MAGIC2;
 	preg->re_nsub = g->nsub;
@@ -1725,138 +1714,6 @@ altoffset(sop *scan, int offset)
 	return largest+offset;
 }
 
-/*
- - computejumps - compute char jumps for BM scan
- *
- * This algorithm assumes g->must exists and is has size greater than
- * zero. It's based on the algorithm found on Computer Algorithms by
- * Sara Baase.
- *
- * A char jump is the number of characters one needs to jump based on
- * the value of the character from the text that was mismatched.
- */
-static void
-computejumps(struct parse *p, struct re_guts *g)
-{
-	int ch;
-	size_t mindex;
-
-	_DIAGASSERT(p != NULL);
-	_DIAGASSERT(g != NULL);
-
-	/* Avoid making errors worse */
-	if (p->error != 0)
-		return;
-
-	assert(NC < MEMLIMIT(*g->charjump));
-	g->charjump = malloc((NC + 1) * sizeof(*g->charjump));
-	if (g->charjump == NULL)	/* Not a fatal error */
-		return;
-	/* Adjust for signed chars, if necessary */
-	g->charjump = &g->charjump[-(CHAR_MIN)];
-
-	/* If the character does not exist in the pattern, the jump
-	 * is equal to the number of characters in the pattern.
-	 */
-	for (ch = CHAR_MIN; ch < (CHAR_MAX + 1); ch++)
-		g->charjump[ch] = g->mlen;
-
-	/* If the character does exist, compute the jump that would
-	 * take us to the last character in the pattern equal to it
-	 * (notice that we match right to left, so that last character
-	 * is the first one that would be matched).
-	 */
-	for (mindex = 0; mindex < g->mlen; mindex++)
-		g->charjump[(int)g->must[mindex]] = g->mlen - mindex - 1;
-}
-
-/*
- - computematchjumps - compute match jumps for BM scan
- *
- * This algorithm assumes g->must exists and is has size greater than
- * zero. It's based on the algorithm found on Computer Algorithms by
- * Sara Baase.
- *
- * A match jump is the number of characters one needs to advance based
- * on the already-matched suffix.
- * Notice that all values here are minus (g->mlen-1), because of the way
- * the search algorithm works.
- */
-static void
-computematchjumps(struct parse *p, struct re_guts *g)
-{
-	size_t mindex;		/* General "must" iterator */
-	size_t suffix;		/* Keeps track of matching suffix */
-	size_t ssuffix;		/* Keeps track of suffixes' suffix */
-	size_t *pmatches;	/* pmatches[k] points to the next i
-				 * such that i+1...mlen is a substring
-				 * of k+1...k+mlen-i-1
-				 */
-
-	_DIAGASSERT(p != NULL);
-	_DIAGASSERT(g != NULL);
-
-	/* Avoid making errors worse */
-	if (p->error != 0)
-		return;
-
-	if (g->mlen > MEMLIMIT(*pmatches) ||
-	    (pmatches = malloc(g->mlen * sizeof(*pmatches))) == NULL) {
-		g->matchjump = NULL;
-		return;
-	}
-
-	if (g->mlen > MEMLIMIT(*g->matchjump) ||
-	    (g->matchjump = malloc(g->mlen * sizeof(*g->matchjump))) == NULL) {
-		/* Not a fatal error */
-		free(pmatches);
-		return;
-	}
-
-	/* Set maximum possible jump for each character in the pattern */
-	for (mindex = 0; mindex < g->mlen; mindex++)
-		g->matchjump[mindex] = 2 * g->mlen - mindex - 1;
-
-	/* Compute pmatches[] */
-	for (suffix = mindex = g->mlen; mindex-- > 0; suffix--) {
-		pmatches[mindex] = suffix;
-
-		/* If a mismatch is found, interrupting the substring,
-		 * compute the matchjump for that position. If no
-		 * mismatch is found, then a text substring mismatched
-		 * against the suffix will also mismatch against the
-		 * substring.
-		 */
-		while (suffix < g->mlen
-		    && g->must[mindex] != g->must[suffix]) {
-			g->matchjump[suffix] = MIN(g->matchjump[suffix],
-			    g->mlen - mindex - 1);
-			suffix = pmatches[suffix];
-		}
-	}
-
-	/* Compute the matchjump up to the last substring found to jump
-	 * to the beginning of the largest must pattern prefix matching
-	 * it's own suffix.
-	 */
-	for (mindex = 0; mindex <= suffix; mindex++)
-		g->matchjump[mindex] = MIN(g->matchjump[mindex],
-		    g->mlen + suffix - mindex);
-
-	ssuffix = pmatches[suffix];
-	while (suffix < g->mlen) {
-		while (suffix <= ssuffix && suffix < g->mlen) {
-			g->matchjump[suffix] = MIN(g->matchjump[suffix],
-			    g->mlen + ssuffix - suffix);
-			suffix++;
-		}
-		if (suffix < g->mlen)
-			ssuffix = pmatches[ssuffix];
-	}
-
-	free(pmatches);
-}
-
 /*
  - pluscount - count + nesting
  */
diff --git a/lib/libc/regex/regex2.h b/lib/libc/regex/regex2.h
index 3d2fb692407..88709de210d 100644
--- a/lib/libc/regex/regex2.h
+++ b/lib/libc/regex/regex2.h
@@ -149,8 +149,7 @@ struct re_guts {
 	size_t neol;		/* number of $ used */
 	char *must;		/* match must contain this string */
 	int moffset;		/* latest point at which must may be located */
-	size_t *charjump;	/* Boyer-Moore char jump table */
-	size_t *matchjump;	/* Boyer-Moore match jump table */
+	re_bmpat_t bmpat;
 	size_t mlen;		/* length of must */
 	size_t nsub;		/* copy of re_nsub */
 	int backrefs;		/* does it use back references? */
diff --git a/lib/libc/regex/regexec.c b/lib/libc/regex/regexec.c
index 9aa0a14bf5f..5cac2663025 100644
--- a/lib/libc/regex/regexec.c
+++ b/lib/libc/regex/regexec.c
@@ -57,6 +57,7 @@ __weak_alias(regexec,_regexec)
 #endif
 
 #include "utils.h"
+#include "regbm.h"
 #include "regex2.h"
 
 /* macros for manipulating states, small version */
diff --git a/lib/libc/regex/regfree.c b/lib/libc/regex/regfree.c
index 4e9ef361786..2b1c8978fa6 100644
--- a/lib/libc/regex/regfree.c
+++ b/lib/libc/regex/regfree.c
@@ -47,6 +47,7 @@ __weak_alias(regfree,_regfree)
 #endif
 
 #include "utils.h"
+#include "regbm.h"
 #include "regex2.h"
 
 /*
@@ -72,6 +73,8 @@ regfree(regex_t *preg)
 	free(g->strip);
 	free(g->sets);
 	free(g->setbits);
+	if (g->bmpat != NULL)
+		re_bm_free(g->bmpat);
 	free(g->must);
 	free(g);
 }

できる限りはbm(3)を使う方向性でいきたいのでbm(3)のバグ調査せんとならない、もう何もわからない…

[WWW] IE11終了

命日決まってJava Appletが動くブラウザが無くなるわけだがどうしたもんかね(古いネットワーク機器なんかで困る)。 まぁJREも脆弱性のある古いバージョンじゃないとJava Plugin自体含まれてないわけで、IE使い続けたところで何の問題も無いという話はある。

誰かAppletタグ横取りしてJavaバイトコードをJavaScriptに変換して実行するブラウザ拡張作ってくだち! Shockwave Flashの場合はその手のプロジェクトがポコポコ生まれては死んでるというのにどうしてこう人気ないかね。

興味本位でJavaScriptで書かれたJava Bytecode to JavaScript Transpilerなんて酔狂なものあるか探したが、エンゼルスの中継ぎ投手並みに見つからんな。 まぁJavaで書かれたものなら Java bytecode to JavaScript/WebAssembly Transpilerとかいくらでも存在するのだけど、ネイティブだしbytecode弄る系のライブラリ豊富だから作りやすいわけで、それをわざわざJavaScriptでなんて考えるのはそれこそ異常者なんやな。

これの作者のページに、Javaで書かれたソースをJavaScriptに変換する GWT(Google Web Toolkit)という昔あった(今もあるってば)フレームワークへの言及があってちょっと懐かしくなったゾ。

あれなぁGUIウィジェットクラスがAWT/Swingではなく独自のものだし、既存のApplet/Swingアプリケーションを書き直さずに変換するって事ができなかったので流行らなかったな。 要するに時代遅れのJava屋(新時代のCOBOLerなんやな)を再教育することなくHTML5アプリケーション書かせなきゃならないという亡者のあえぐ辺獄にしか需要のないシロモノだったんだな *1

それと変換にかかる時間が遅すぎてな、どれくらい遅いかというと工数の見積もりを大幅に見誤って納期延ばすために焼き土下座する羽目になったくらいで。 まぁあれは開発環境が拷問級低スペックのノートPC(Vista Readyだぞ)だったせいも大きい、予算の権限がなくただ上流から貸与されたお古のマシンしか無い最下層SIerの悲哀なんやな、ほんと理不尽。

ワイは素のGWTはいろいろとクソ過ぎたので、SmartClientというAjaxフレームワークをGWTでラップした SmartGWTというものを選んだのだが、そのSmartGWTもEclipse Pluginがクッソ不安定でな、結局サポート打ち切りでGUIビルダーとして使えるものが無くなってしまったのが痛かった。

こいつにはとてもよく出来た 商用のGUIビルダーがちゃんと存在するのだけど、前述のとおり予算の権限なぞ一切無い奴隷だったので買ってもらえず、仕方なしに最新版では動かなくなった古いEclipse Pluginにバージョン誤魔化すパッチ当てて開発してた思い出。

もはやモバイルアプリの時代でAjax自体がオワコンな気もするし最近の流行とか追ってないから(育毛剤っぽい名のReactとか鹿島っぽいAngularJSとか?)比較対象が古くなるけど、AjaxフレームワークとしてもExtJSやjQuery UIなんかよりよっぽどSmartClientはよくできてるんだよな、なんでこんなに知名度が無いのだろうな。

まぁ「よくできてる」の基準がワイの考えるもっとも優れたGUIアプリケーション開発環境がDelphi5というあたりで若い人と致命的な感覚のズレがあるかもしれん、いやですね老いるのはなるべくはやくポックリ逝きたいですね。

あ、SmartClientはモバイル対応と国際化(特にBiDiの絡むRTLな言語圏)で遅れてる感はあるな、今の時代致命的ですかねこれ…

いろいろ調べるとGWTと同じコンセプトのやつは TeamVMとか JSweetとかあるけど、TypeScriptみたいになんでもっと流行らないんだろうな、ああ「Javaだから」か…経歴書にJavaなんてあったらろくでもない現場ばっかり回されるもんな…

そういえばTcl/Tk版のAppletであるTclet Pluginも動かなくなるわけだけど、あれまったく流行りませんでしたね記憶ではNASAが業務で使ってるとかなんとかいってたはずだがまだ使ってるのかな。

あと一度仕事で使わされたことのある国内企業で地味に使われてるBiz/BrowserってRIAフレームワークも終わるなと思ったら、Biz/Browser DTというJava WebStart的なものが再発明されてたのでまだ死なない模様。 あれも変な言語だったなぁ、だいぶ昔の話だけど言語パーサーにバグがようけあって構文エラーでも動き続けてデバッグに苦労した記憶。

*1:そもそもJavaすら怪しいのだから何で書かせても結果は同じという話もあるが、スキル高くないのに型安全でない言語書かせるのはガソリン被るようなものでな、主に修正する俺が。