目次: ゲーム
Steamで新たなゲームを買いました。2020年4月ローンチのSTATIONflow(開発: DMM GAMES)です。その名の通り地下鉄の駅を作るゲームです。
新宿や渋谷のようなモンスター駅の作り、使いづらさに憤慨したことはありませんか?「使いづらい!俺様に任せればスマートに作ってやる」と思う方はぜひチャレンジしてください。
私もそう思ってたのですが、ゲームをやってみて「思い上がりでした、ごめんなさい、JRさん尊敬してます。」反省しました。油断するとすぐに、客を何度も上り下りさせて、べらぼうに長距離歩かせて、挙句迷子になるクソ駅が爆誕します。
(気に入ったところ)
(気に入らないところ)
ゲームはまだ始めたばかりなので、主に操作性の面での感想です。
プレイ時間が10時間未満で、序盤しか体験してませんが、STATIONflowのシステム紹介もしておきます。システムはそんなに難しくないです。
マップには地下鉄の改札口と、電車の到着ホームが固定で置かれます。お客さんの行動は基本的に3つです。
他の交通系ゲームと大きく違う点は、客は「最適経路を知らない」ことです。客は「構内案内」を見て行動します。目的地への経路が存在しても、構内案内を間違えると客は目的地に行けなくて迷います。視界の広さがお客さんによって違い、遠いところに構内案内を置くと、客によっては構内案内を見失って迷います。
遠回りで変なシステムに見えますが、よく考えると、すべての客が駅構内の経路を知り尽くしていて、常に最短経路で移動するって変じゃないですか?そんなエスパーみたいな客いませんよね。
正直いって構内案内のメンテナンスはかなり面倒ですが、ゲームとして理不尽にならないレベル(※)で現実に寄せた、素敵なアイデアだと思います。
(※)実世界だと、構内案内をあえて無視して迷う、目の前の構内案内に気づかない、話の通じないクレーマー、など不条理ばかりですが、そんなの再現してもクソゲーにしかなりません。現実に寄せれば良いってものじゃない。
乗降客数が増えて、お客さんの不満が少ないとランクアップし、ホームと改札口が勝手に増えます。大抵は予想していない変なところにホームが勝手に増えるので、駅のレイアウトと合わなくなります。つじつま合わせが必要です。ここは腕の見せどころです。
ランクアップに伴い、トイレやレストランなどの構内施設の種類が増えます。エスカレーターしか乗らない高齢客、エレベーターしか乗らない車いす客、などお客さんのバリエーションも増えます。序盤は簡単で、ランクアップによって難易度が段々上がっていく設計に見えます。
ホームと改札の位置はマップにより固定のようです。最後まで進めて最初からやり直せば、綺麗な駅が作れるかもしれません(まだそこまで見てないので断言はできませんけど)。
メモ: 技術系の話はFacebookから転記しておくことにした。加筆&修正した。
Twitterで「収入ほぼゼロ」「来館者9割減」 危機に陥っている「航空科学博物館」がクラウドファンディングで支援募集 - ねとらぼ、の記事を目にしたので、微力ながら5,000円を支援しました。後で入場券が2枚送られてくるそうな。
100万円のコースはさすがに高すぎなのか支援者がまだ現れていませんが、30万円のコースは3人ほど支援者がいました。愛されていますね。
公営の博物館(公益財団法人 航空科学博物館)は、国や自治体が支援するのが筋だろう、という意見も目にしましたし、言い分はわかるんですが、うだうだ言っている間に潰れてしまっては元も子もないです。クラウドファンディングで助けを求めるのは良い手段だと思います。
目次: GCC
前回(2020年3月27日の日記参照)の調査により、targetm.vector_mode_supported_p() がfalseを返すことが原因だとわかりました。この関数ポインタが指す先は、アーキテクチャターゲット(ARMとかi386とかriscvとか)ごとに違います。RISC-Vの場合は下記のようにすれば良いです。
// gcc/config/riscv/riscv.c
static bool
riscv_vector_mode_supported_p (machine_mode mode)
{
if (TARGET_VECTOR) //★★本当はmodeの値を確認したほうが良いが、今回は手抜き
return true;
return false;
}
...
#undef TARGET_VECTOR_MODE_SUPPORTED_P
#define TARGET_VECTOR_MODE_SUPPORTED_P riscv_vector_mode_supported_p
このtargetmもやや魔界感があるので、何でこのdefineで実装が切り替わるのか、についても調べたいところですね。それはさておいて、上記の実装を追加すると無事ベクトル型が使えるようになります。
(insn 70 2 69 2 (set (reg:V64SI 105 [ v1 ]) ★★reg:V64SIになっている
(asm_operands/v:V64SI ("vlw.v %0, %1") ("=&v") 0 [
(mem/c:SI (plus:SI (reg/f:SI 99 virtual-stack-vars)
(const_int -360 [0xfffffffffffffe98])) [1 b+40 S4 A64])
]
[
(asm_input:SI ("A") b.c:7)
]
[] b.c:7)) "b.c":7:2 -1
(nil))
バイナリも正しく出力されます。sizeof(v1) も256が返されます。ちなみにアセンブルしなくても、オプション -Sでアセンブラを見てもほぼ同じです。
a.out: file format elf32-littleriscv Disassembly of section .text: 00010054 <_start>: 10054: 7165 addi sp,sp,-400 10056: 103c addi a5,sp,40 10058: 1207e007 vlw.v v0,(a5) 1005c: 6159 addi sp,sp,400 1005e: 8082 ret
良かった良かった。オプションO0の問題はまた今度です。
目次: GCC
以前(2020年3月27日の日記、2020年3月28日の日記、2020年3月29日の日記参照)ベクトルレジスタを扱えるようにした際に、下記の問題が残っていました。
前回(2020年5月12日の日記参照)はベクトル型に向けてマシンモードを追加しました。引き続き、1つ目の問題に取り組んでいきたいと思います。
ベクトル型は基本型(SI, DI, SF, DFなど)が複数連結されているデータ型です。個数は2のべき乗(2, 4, 8, 16, ...)でなければなりません、3個や10個はダメです。型は通常GCCの実装で定義します。ベクトル型も当然同じでGCCの実装で定義しますが、ベクトル型はやや特殊で、GCCのattributeでも定義することができます。今回はattributeを使ってみます。
typedef int __v64si __attribute__((__vector_size__(256)));
void _start()
{
int b[100];
__v64si v1;
__asm__ volatile ("vlw.v %0, %1\n"
: "=&v"(v1) : "A"(b[10]));
}
ベクトル型を使ってインラインアセンブラを書くとエラーが出ます。
$ riscv32-unknown-elf-gcc -Wall -march=rv32gcv b.c -O2 -nostdlib -S b.c: In function '_start': b.c:7:2: error: impossible constraint in 'asm' 7 | __asm__ volatile ("vlw.v %0, %1\n" | ^~~~~~~
このエラーは以前(2020年3月6日の日記参照)、register constraintに 'v' を追加したときに解析した部分で見ました。詳細は昔の日記を見ていただくとして、以前との差を示します。
// gcc/recog.c
int
asm_operand_ok (rtx op, const char *constraint, const char **constraints)
{
...
default:
cn = lookup_constraint (constraint);
switch (get_constraint_type (cn))
{
case CT_REGISTER:
if (!result
&& reg_class_for_constraint (cn) != NO_REGS //★★以前引っかかっていたのはこちら
&& GET_MODE (op) != BLKmode //★★今回はこちらの条件に引っかかる
&& register_operand (op, VOIDmode))
result = 1;
break;
新たなマシンモードV64SImodeを追加(2020年5月12日の日記参照)を追加したのに、どうしてBLKmodeが選択されてしまうのでしょう?
オプション --dump-tree-all --dump-rtl-allを付けて、BLKmodeが選ばれるタイミングを追うと、パスexpandが終わった時点でBLKmodeになっていました。
(insn 26 7 10 2 (set (mem/c:BLK (plus:SI (reg/f:SI 99 virtual-stack-vars) ★★mem/c:BLKになっている
(const_int -1168 [0xfffffffffffffb70])) [1 A128])
(asm_operands/v:BLK ("vlw.v %0, %1") ("=&v") 0 [
(mem/c:SI (plus:SI (reg/f:SI 99 virtual-stack-vars)
(const_int -872 [0xfffffffffffffc98])) [1 b+40 S4 A64])
]
[
(asm_input:SI ("A") b.c:7)
]
[] b.c:7)) "b.c":7:2 -1
(nil))
パスexpandはGIMPLEからRTLという中間表現に変換するパスです。RTLに変換した直後からBLKmodeですから、かなり最初の方からダメだってことがわかります。何が悪いかわからないのでexpand辺りのコードを探ってみます。
// gcc/cfgexpand.c
static void
expand_asm_stmt (gasm *stmt)
{
...
for (i = 0; i < noutputs; ++i)
{
tree val = output_tvec[i];
tree type = TREE_TYPE (val);
bool is_inout, allows_reg, allows_mem, ok;
rtx op;
...
if ((TREE_CODE (val) == INDIRECT_REF && allows_mem)
|| (DECL_P (val)
&& (allows_mem || REG_P (DECL_RTL (val)))
&& ! (REG_P (DECL_RTL (val))
&& GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
|| ! allows_reg
|| is_inout
|| TREE_ADDRESSABLE (type))
{
...
}
else
{
op = assign_temp (type, 0, 1); //★★これ
op = validize_mem (op);
if (!MEM_P (op) && TREE_CODE (val) == SSA_NAME)
set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (val), op);
generating_concat_p = old_generating_concat_p;
push_to_sequence2 (after_rtl_seq, after_rtl_end);
expand_assignment (val, make_tree (type, op), false);
after_rtl_seq = get_insns ();
after_rtl_end = get_last_insn ();
end_sequence ();
}
// gcc/function.c
rtx
assign_temp (tree type_or_decl, int memory_required,
int dont_promote ATTRIBUTE_UNUSED)
{
tree type, decl;
machine_mode mode;
#ifdef PROMOTE_MODE
int unsignedp;
#endif
if (DECL_P (type_or_decl))
decl = type_or_decl, type = TREE_TYPE (decl);
else
decl = NULL, type = type_or_decl;
mode = TYPE_MODE (type); //★★これ
// gcc/tree.h
#define TYPE_MODE(NODE) \
(VECTOR_TYPE_P (TYPE_CHECK (NODE)) \
? vector_type_mode (NODE) : (NODE)->type_common.mode) //★★これ
// gcc/tree.c
/* Vector types need to re-check the target flags each time we report
the machine mode. We need to do this because attribute target can
change the result of vector_mode_supported_p and have_regs_of_mode
on a per-function basis. Thus the TYPE_MODE of a VECTOR_TYPE can
change on a per-function basis. */
/* ??? Possibly a better solution is to run through all the types
referenced by a function and re-compute the TYPE_MODE once, rather
than make the TYPE_MODE macro call a function. */
machine_mode
vector_type_mode (const_tree t)
{
machine_mode mode;
gcc_assert (TREE_CODE (t) == VECTOR_TYPE);
mode = t->type_common.mode; //★★このモードはV64SImodeになる
if (VECTOR_MODE_P (mode)
&& (!targetm.vector_mode_supported_p (mode) //★★この判定文が偽になる
|| !have_regs_of_mode[mode]))
{
scalar_int_mode innermode;
/* For integers, try mapping it to a same-sized scalar mode. */
if (is_int_mode (TREE_TYPE (t)->type_common.mode, &innermode)) //★★256バイトのIntはないから、偽になる
{
poly_int64 size = (TYPE_VECTOR_SUBPARTS (t)
* GET_MODE_BITSIZE (innermode));
scalar_int_mode mode;
if (int_mode_for_size (size, 0).exists (&mode)
&& have_regs_of_mode[mode])
return mode;
}
return BLKmode; //★★BLKmodeになってしまう
}
return mode;
}
条件式にあるtargetm.vector_mode_supported_p() がfalseのため、BLKmodeになってしまうようです。
ノートPC(ThinkPad E480)の冷却ファンが回り続けていてうるさいです。特に何かしている訳でもないのに、良い勢いでファンが回ってます。
ここ最近、ノートPCを酷使(ゲーム、在宅勤務など)したため、ファンに埃が詰まって、冷却能力が下がったか?と予想して、頑張ってThinkPadの裏蓋を開けました。しかし思ったほど汚れていません。
どうしてファンが回りっぱなしなんでしょう?純粋に冷却能力が足りないだけなんだろうか??
ThinkPad E480の裏蓋はめちゃくちゃ開けにくいです。ネジ9か所と爪で止まっているので、ネジを緩めた後、マイナスドライバーでこじ開けるしかありません。
爪を外すとき、バキっ!ベキっ!というすごい嫌な音がします。案の定、ヒンジ付近(ノートPCとノートPCディスプレイが接続されている方)の爪が4か所ほど折れました。
せっかく裏蓋まで開けたにも関わらず、何も収穫がありませんでした。裏蓋を止める爪が4か所壊れただけです。相変わらずファンはうるせーし、嬉しくない結末です。目次: GCC
以前(2020年3月27日の日記、2020年3月28日の日記、2020年3月29日の日記参照)ベクトルレジスタを扱えるようにした際に、下記の問題が残っていました。
1つ目の問題に取り組んでいきたいと思います。RISC-V 32の場合、intの変数は32bit整数のデータ型として扱われます。GCC内部の表現(RTL)ではSImodeというマシンモード(※)で表されます。他の大きさのデータ型を示すマシンモードも当然存在していて8, 16, 64bit整数はそれぞれBImode, HImode, DImodeで表されます。
普通の型に対応するモードはGCCが定義済みですが、ベクトル型を表すモードは標準では存在しないため、自分で新規に定義する必要があります。
(※)マシンモード(Machine Mode)については、GCC Internalsの14.6 Machine Modesに簡単な説明と標準的なモードの一覧が載っています。これによればSIはSingle Integerの略らしいです。変な名前だなあ。
以前(2020年3月14日の日記参照)説明したとおりですが、軽くおさらいすると、標準的なマシンモードはgcc/machmode.def、アーキテクチャ固有のマシンモードはgcc/config/arch/arch-modes.defにあります。例えばRISC-Vならgcc/config/riscv/riscv-modes.defです。
現在のところRISC-V固有のマシンモードは1つしか定義されていません。
FLOAT_MODE (TF, 16, ieee_quad_format);
このファイルにベクトル型を表すマシンモードを追加します。
VECTOR_MODE (INT, SI, 8);
VECTOR_MODE (INT, SI, 16);
VECTOR_MODE (INT, SI, 32);
VECTOR_MODE (INT, SI, 64);
とりあえず整数(INT, SI)が8, 16, 32, 64(それぞれ32, 64, 128, 256バイト)個連結されているデータ型を想定して作りました。ベクトル型を語る上では浮動小数点型も大事ですが、とりあえず今回は整数型のみを定義しています。
マシンモードを正しく追加できたか確かめる方法は色々あるのでしょうけど、個人的に簡単だと思うのは一旦ビルドしてしまう方法です。
GCCをビルドするとビルド用のディレクトリ(以降build_gccと呼びます)に、モードが全部書いてあるヘッダinsn-modes.hが生成されます。生成されたヘッダを検索すれば一発です。
// gcc/build_gcc/insn-modes.h
enum machine_mode
{
E_VOIDmode, /* machmode.def:189 */
#define HAVE_VOIDmode
#ifdef USE_ENUM_MODES
#define VOIDmode E_VOIDmode
#else
#define VOIDmode ((void) 0, E_VOIDmode)
#endif
E_BLKmode, /* machmode.def:193 */
#define HAVE_BLKmode
#ifdef USE_ENUM_MODES
#define BLKmode E_BLKmode
#else
#define BLKmode ((void) 0, E_BLKmode)
#endif
...
E_V32SImode, /* config/riscv/riscv-modes.def:26 */
#define HAVE_V32SImode
#ifdef USE_ENUM_MODES
#define V32SImode E_V32SImode
#else
#define V32SImode ((void) 0, E_V32SImode)
#endif
E_V64SImode, /* config/riscv/riscv-modes.def:27 */
#define HAVE_V64SImode
#ifdef USE_ENUM_MODES
#define V64SImode E_V64SImode
#else
#define V64SImode ((void) 0, E_V64SImode)
#endif
...
新たなマシンモードV64SImode(SIが64個連結されたデータ型)が追加されたことがわかると思います。コメントにマシンモードの定義されている場所も書かれていて、とても親切です。
ほぼ全域に渡って意味不明コードだらけのGCCでは珍しい部類の、わかりやすさ&親切さです。自動生成コードには気を使っているんでしょうか?他のところもこれくらい親切だと嬉しいんですけどねえ。
今年のヤマザキ春のパン祭りは、2枚もゲットできました。
去年は品川勤務かつコンビニ昼飯がメインだったので、ヤマザキパンを買う機会がほぼなく、お皿をもらえるほど点がたまりませんでした。今年はCOVID-19による在宅勤務で、近所のスーパーでパンを買う機会が大幅に増えたため、2枚も手に入ったわけです。在宅勤務の意外な効果です。
コンビニに行かない人にとっては意外かもしれませんが、コンビニはヤマザキパンをほとんど置いていません。自社のプライベートブランドのパンばかりです。10年位前は他社のパンも置いていたんですが、今やコンビニは9割方がプライベートブランドのパンです。
コンビニのプライベートブランドのパンは、大手メーカー(ヤマザキパン、敷島製パン、フジパンなど)が作っていますが、コストの都合か何だか知りませんが、味に劣る気がします。好みの問題なのかな……?
パン祭りのお皿、裏側に何か書いてるなーと思って写真を撮ってみました。
ちょっと見づらいので文字に起こすと、
ARTICLE YAMAZAKI
MADE IN FRANCE
ZENMEN
BUTSURIKYOUKA
GARASU
「全面物理強化ガラス」ってローマ字で書いてありますね。フランス製なのに何でローマ字?フランス語で書かれても読めないから?
見ていて素朴な疑問が沸きました。あえて「全面」と強調する理由はなんでしょうね?皿のように厚みのない製品で「片面」物理強化ガラスにすることは可能?可能だったとしてもやる意味がある?
Pythonの文字列置換は "string".replace() ですが、正規表現ライブラリreだと、なぜかre.sub() です。同じ機能なのに、APIの名前も、引数の指定順序も違います。どうしてこうなった。
改定の度に魔界化するC/C++ に比べると、Pythonは明瞭に思えます。とはいえPythonも何だかんだ長い歴史ですし、祓いきれない闇があるんでしょうねえ。
メモ: 技術系の話はFacebookから転記しておくことにした。
目次: Kindle
KindleのアプリはKindle Fire版、Android版、PC版など、いくつか種類があります。普段使っているのはKindle FireとKindle for PCです。どうもKindle for PCのダウンロードが遅い気がします。
Kindle Fireも決して速いとは思いませんが、大抵はマンガ1冊が1〜2分でダウンロードできているので、5Mbpsくらいは出ているんじゃないかと思います。
Kindle for PCはかなり遅い(1〜2Mbpsくらい、日によって違う)です。同じネットワークを使っているのに、差が出るものですかね?PC向けだけ帯域ケチるとか、そんな面倒なことしないよなあ?うーん?
Kindle Fire HDのアプリはたまにアップデートされて動きが変わります。今年の頭くらいだったか?覚えてないですけど、また動作が変わりました。
新たなバグは再現率100%です。再現方法も簡単です。
この順に操作したとき、本来は本の一覧が出なければなりませんが、グループ化された本が再表示されてしまいます。明らかにバグってます。
このバグは、ユーザー側の操作で回避可能です。
ユーザーの操作に影響が出るバグですし、テスターに触らせたら数分で見つけそうなのにね?KindleってUIのテストしてないのかなあ??
目次: RISC-V
マクロの名前にTypoと思しきものがあったので、riscv-binutils-gdb(サイトへのリンク)にPull Requestをしてみました。
RISC-V向けのgasの実装では、命令に対応した名前のマクロがあります。
//opcodes/riscv-opc.c
//通常は命令の名前からドットを除いて、大文字にした名前
// vadd.vv -> MATCH_VADDVV
{"vadd.vv", 0, INSN_CLASS_V, "Vd,Vt,VsVm", MATCH_VADDVV, MASK_VADDVV, match_opcode, 0 },
{"vadd.vx", 0, INSN_CLASS_V, "Vd,Vt,sVm", MATCH_VADDVX, MASK_VADDVX, match_opcode, 0 },
{"vadd.vi", 0, INSN_CLASS_V, "Vd,Vt,ViVm", MATCH_VADDVI, MASK_VADDVI, match_opcode, 0 },
//Reduce系の命令だけ名前が違う
// vredsum.vs -> MATCH_VREDSUMV"S" のはずなのに、MATCH_VREDSUMV"V" になっている
{"vredsum.vs", 0, INSN_CLASS_V, "Vd,Vt,VsVm", MATCH_VREDSUMVV, MASK_VREDSUMVV, match_opcode, 0},
パッチの中身は簡単で、ベクトル命令の一部で、命令の名前とマクロの名前が違っていたので修正しただけです。この手の間違いがいくつあるか分からなかったので、ちょっとしたPythonスクリプトを書いてチェックしました。
#!/usr/bin/python
import re
import sys
fname = sys.argv[1]
f = open(fname, 'r')
line = f.readline()
while line:
if not line.startswith('{"'):
line = f.readline()
continue;
line = line.strip().replace('}', '')
line = re.sub('\{"([^,]*)",', r'\1,', line)
line = re.sub('".*",', '', line)
line = re.sub(' *', '', line)
items = line.split(',')
insnOrg = items[0]
insn = items[0].upper()
classInsn = items[2]
matchInsn = items[3]
maskInsn = items[4]
aliasInsn = items[6]
if not classInsn.startswith('INSN_CLASS_V'):
line = f.readline()
continue;
if not matchInsn.startswith('MATCH_') or not maskInsn.startswith('MASK_'):
line = f.readline()
continue;
if aliasInsn.startswith('INSN_ALIAS'):
line = f.readline()
continue;
insn = insn.replace('.', '')
matchInsn = matchInsn.replace('MATCH_', '')
maskInsn = maskInsn.replace('MASK_', '')
if matchInsn != maskInsn:
print("MATCH != MASK: {:s} != {:s}".format(matchInsn, maskInsn))
if insn != matchInsn:
print("INSN != MATCH: {:s} != {:s}".format(insnOrg, matchInsn))
line = f.readline()
条件を適当に継ぎ足して書いたのと、Pythonの経験値が低いのが相まって、エレガントさの欠片もないですね。仕方ない。実行結果はこんな感じです。
$ ../checker.py opcodes/riscv-opc.c INSN != MATCH: vzext.vf2 != VZEXT_VF2 INSN != MATCH: vsext.vf2 != VSEXT_VF2 INSN != MATCH: vzext.vf4 != VZEXT_VF4 INSN != MATCH: vsext.vf4 != VSEXT_VF4 INSN != MATCH: vzext.vf8 != VZEXT_VF8 INSN != MATCH: vsext.vf8 != VSEXT_VF8 INSN != MATCH: vredsum.vs != VREDSUMVV INSN != MATCH: vredmaxu.vs != VREDMAXUVV INSN != MATCH: vredmax.vs != VREDMAXVV INSN != MATCH: vredminu.vs != VREDMINUVV INSN != MATCH: vredmin.vs != VREDMINVV INSN != MATCH: vredand.vs != VREDANDVV INSN != MATCH: vredor.vs != VREDORVV INSN != MATCH: vredxor.vs != VREDXORVV INSN != MATCH: vwredsumu.vs != VWREDSUMUVV INSN != MATCH: vwredsum.vs != VWREDSUMVV INSN != MATCH: vfredosum.vs != VFREDOSUMV INSN != MATCH: vfredsum.vs != VFREDSUMV INSN != MATCH: vfredmax.vs != VFREDMAXV INSN != MATCH: vfredmin.vs != VFREDMINV INSN != MATCH: vfwredosum.vs != VFWREDOSUMV INSN != MATCH: vfwredsum.vs != VFWREDSUMV INSN != MATCH: vcompress.vm != VCOMPRESSV
明らかにTypoに見えるのはvred/vfred/vcompress系の命令で、vsとvvを取り違えています。
微妙なところなのはvzextです。他はドットを除いた名前なのに、vzextだけドットをアンダースコアに置換した名前です。ルールに一貫性が無いだけか、Typoか、どちらとも言い難いため、今回出したPull Requestでは修正していません。
リポジトリを見ていてちょっと気になったのはSiFiveの人以外、変更がほとんどないことです。著名プロジェクトでは珍しいです。もしかするとGitHubでPull Requestを受け付けてない(※1)可能性があります。
変更を提案するのはここじゃないとか、そもそも変更は受け付けてませんとか、何でも良いので反応があると嬉しいですね、週明けまで待ちましょうかね……。
(※1)本家および開発の場がGitHub以外に存在していて、GitHubをミラーにしているプロジェクトの場合、GitHub上で何か言っても無視されることがあるようです。
< | 2020 | > | ||||
<< | < | 05 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |
合計:
本日: