Facebookでソフトイーサ株式会社の登さんが「日付と曜日の関連に根拠法はあるのか?」というエントリを書かれていて、いつも面白いことに気づく方だなあと思いつつ、私も興味が沸いてきたので調べてみました。
適当にググってもわからなかったので、近代日本の暦の原点ともいえる、太陰暦→太陽暦の変換点から調べることにしました。
かつて太陰暦を使用していた日本ですが、明治6年1月1日をもって太陰暦から太陽暦に切り替え、以降現在に続くまで、太陽暦が使われています。
暦の切り替えについては、明治5年の詔書(国立公文書館 デジタルアーカイブ - 太政類典・第二編 - 太陰暦ヲ廃止太陽暦ヲ行フ附詔書)で頒布されています。
これは太政類典という書物でして、載っている文章を読むと「明治5年11月9日、第337号」と書いてあります。しかし法律という文字はなく、詔書と書いてあります。詔書とは、天皇が公務で意思表示をすること、らしいです。
さらに読み進めると「明治六年(神武紀元 二千五百三十三年)一月一日 水曜日」という記載もあります。
日付と曜日を結びつける法律は、この詔書にあるように思われます。しかし、
こんな疑問も沸いてきましたので、もう少し調べてみます。
国立国会図書館の明治前期法令の調べ方 1. 明治前期の法令の概要、によれば、明治時代初期(明治19年 公文式制定まで)の法律は、制定方法が定まっておらず、太政官や政府の各省から日誌という形で発令されていたようです。今から見れば考えられないフリーダム時代ですね…。
また、国立公文書館の説明によれば、
(引用) 太政類典は、慶応3年(1867)から明治14年(1881)までの太政官日記及び日誌、 公文録などから典例条規(先例・法令等)を採録・浄書し、制度、官制、官規、 儀制等19部門に分類し、年代順に編集したものです。 (引用終わり)
だそうです。ちなみに太政官 記録課 類典科の編纂とのことです。太政官はその後の内閣に相当する機関ですね。
従って、太政類典に記載の詔書は、明治初期の法律と見なして良さそうです。
それにしても国立公文書館のJPEG画像で太政類典を読むのは辛い…見づらくて目が死にそうです…。
明治5年の法律が今も有効なのか…?とお思いでしょうが、国立国会図書館 日本法令索引(明治前期編)によれば、
(引用) 太陰暦ヲ廃シ太陽暦ヲ頒行ス 明治5年11月9日 太政官第337号(布) 現在も効力を有する(平成18年現在) (引用終わり)
とのことなので、現在も有効な法律だと言えます。頒布が明治5年(西暦1872年)ですから、ざっと140年以上前の法律が今も生きているわけです。何だか気が遠くなる話です。
ちなみに太政類典には明治6年1月1日が水曜という表が載っていますが、別の文書である「法令全書」にはなぜか新暦の日付と曜日の対応表は載っていません(国立国会図書館 デジタルコレクション 法令全書を参照)でした。
法令全書と太政類典で載っている文章の長さが違う原因は、法令全書は別紙を省略していて、太政類典は別紙まで載せているから、と推測したのですが、何がどうなったら別紙扱いなのかが全くわかりません。
国立国会図書館のサイト曰く「布告全書」には「法令全書」で省略されることが多い別紙や別冊が掲載されている、とのことなのでぜひ見たかったのですが…、
「東京までマイクロフィルム見に来いやー!」(書誌情報 - 布告全書 慶応3年12月-明治18年12月)
って書いてあったので、これ以上調べるのは諦めました。
とりあえず、明治6年1月1日(1873年1月1日)は水曜日(詔書には、以降44日についても記載有り)であり、法律に定められていて、法律は現在も有効である、という結論にしておきたいと思います。
かれこれ5年以上が経過したCore2 Quadマシンにお別れを告げて、新しいPCを組みました。前回同様、部品だけ買って半年くらい放置してしまいましたが、今日やっと組み立て終わって、無事動いております…。
前回はIntel CPUでしたので、次はAMDにしようと思ったのですが、AMDはBulldozer以降CPUの性能がどうもパッとしないようで、AMD APUにすべきかAMD FXにすべきかで少し迷いました。
普段の使い方を思えばCPUの動作速度にはさほど困っていないので、とりあえずTDPが低め(50Wクラス)で一番速いA10-7800を選びました。
AMDのCPUは元々安目の価格ですし、APUを選べばグラフィックカード代まで浮きますので、非常にありがたいです。
そういえばA10-7800を買った直後に、次世代APUのA10-7870Kが発売されましたが、悔しいので見なかったことにします…。
AMD APUのおかげで浮いたグラフィックカード代と、SSDを流用したおかげで浮いたストレージ代(※)を全てメモリにぶち込みました。おかげでメモリが32GB搭載のマシンになりました。
メモリだけで34,000円くらいしました。APUが16,000円くらいなので、大体2倍くらいです。我ながらアホだと思いますが、欲を言えば、搭載上限まで載せたかったです…。
今回買ったマザーボードは16GBモジュールx 4=64GBが搭載上限でしたが、16GBモジュールが手に入らず諦めました。そりゃまあ16GBモジュールなんて誰が買いますか?って話ですよ。売ってないのも当然です。
一応、真面目な話もしておくと、元々16GBは積む予定でした。というのも、前のマシン(メモリ8GB搭載)は、開発用の仮想マシンと、統合開発環境と、ブラウザを同時に立ち上げて、ゴチャゴチャ作業していると、ときおりメモリが足りん!とお怒りになっていたからです。
仮想マシンと統合開発環境がGB級のメモリを使うのは、最近はもうそんなもんだよね、と思ってますが、なぜかブラウザも意外とメモリを使います。気づいたら1GB以上使っていることがあって油断なりません…。
(※)さすがに5年モノのHDDだけは、いつ壊れるかわからないので入れ替えました。いつもSeagateを使っていたのですが、SeagateはSamsungのHDD部門と合併してからというもの、あまり良い噂を聞かないので、今回はWestern DigitalのWD Blackを選びました。
ユーザをuseraddで追加するときに -mオプションを付けると、ユーザ追加と同時に、ホームディレクトリが自動的に生成されます。
生成されたホームディレクトリを見ると、特に何もしていないのに .bashrcや .profileなどが置かれています。これらのファイルはどこから来たのでしょう?
# useradd testuser -m # cd /home/testuser/ # ls -la total 12 drwxr-xr-x 2 testuser testuser 128 Oct 11 16:50 . drwxr-xr-x 8 root root 184 Oct 11 16:50 .. -rw-r--r-- 1 testuser testuser 220 Dec 12 2006 .bash_logout -rw-r--r-- 1 testuser testuser 3515 Nov 13 2014 .bashrc -rw-r--r-- 1 testuser testuser 675 May 13 2008 .profile
答えだけ言ってしまうと、Debianの場合 /etc/skelというディレクトリが、ホームディレクトリのひな型となります。
# ls -la /etc/skel total 21 drwxr-xr-x 2 root root 128 May 1 05:06 . drwxr-xr-x 173 root root 9128 Oct 11 16:50 .. -rw-r--r-- 1 root root 220 Dec 12 2006 .bash_logout -rw-r--r-- 1 root root 3515 Nov 13 2014 .bashrc -rw-r--r-- 1 root root 675 May 13 2008 .profile
Debian以外のディストリビューションでも、ひな型となるディレクトリがあるはずなので、探してみると面白いかもしれません。
目次: Linux
Linux用のデバイスドライバを書くときはmodule_init(関数名) と書いて、初期化関数を指定します。
ドライバをカーネルモジュール(*.ko)としてビルドしたときは、insmodした時に初期化関数が実行されます。これは想像に難くないですし、初期化関数にprintkでも入れておけば簡単に確認できます。
では…、ドライバをLinuxカーネルに組み込んだ時は、一体いつ初期化処理が実行されるのでしょうか?Linuxには他のドライバも含まれていますが、実行される順序に決まりはあるでしょうか?
わたくし恥ずかしながら、この辺の仕組みを全く理解していなかったので、コードを調べてみました。既に同じような事を調べている人がいる気がしてなりませんが…まあ良いや。
Linuxの初期化は、linux/init/main.cのstart_kernel() から始まります。start_kernel() は山のように初期化を実行していますが、我らがmodule_init() の実行に関係しているのは下記の部分です。
start_kernel()
rest_init()
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
ここでカーネルスレッドが作成され、スレッドのエントリ関数はkernel_init() です。で、続けて追いかけます。
kernel_init()
kernel_init_freeable()
do_basic_setup()
do_initcalls()
do_initcall_level()
do_one_initcall()
initcall_levels[level][n]()
このような順で呼ばれます。このinitcall_levelsが今回の話のキモとなります。initcall_levelsは下記のように定義されています。
typedef int (*initcall_t)(void);
extern initcall_t __initcall_start[];
extern initcall_t __initcall0_start[];
extern initcall_t __initcall1_start[];
extern initcall_t __initcall2_start[];
extern initcall_t __initcall3_start[];
extern initcall_t __initcall4_start[];
extern initcall_t __initcall5_start[];
extern initcall_t __initcall6_start[];
extern initcall_t __initcall7_start[];
extern initcall_t __initcall_end[];
static initcall_t *initcall_levels[] __initdata = {
__initcall0_start,
__initcall1_start,
__initcall2_start,
__initcall3_start,
__initcall4_start,
__initcall5_start,
__initcall6_start,
__initcall7_start,
__initcall_end,
};
コードを見る限り、二重配列 __initcall_levelsは __initcalln_startという配列を要素として持っていること、__initcall0_start[0], __initcall0_start[1], __initcall0_start[2], ... の順に関数ポインタが先に呼び出され、その後も同様に __initcall1_start, __initcall2_start, ... と続いて __initcall7_startに入っている関数ポインタは後に呼び出されることがわかります。
しかし肝心の __initcall0_startに何の関数ポインタが入るのか?はわかりません。それもそのはず、実はCのコード上に、これら __initcallx_start配列の定義はありません。別の方法で定義されているのです。
この __initcall0_start〜 __initcall7_start配列は、あるマクロで宣言された初期化関数のポインタを全て持つ配列となります。対応関係は下記の通りです。
なぜそうなるか?は後述しますので、とりあえずこんな関係があることだけ頭の隅に置いてください。
カーネルモジュールを作るとき、初期化関数を指定するためのおまじないとしてmodule_init(funcname) と書きますが、これは実はマクロでlinux/include/linux/module.hにて、下記のように定義されています。
/**
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
*
* module_init() will either be called during do_initcalls() (if
* builtin) or at module insertion time (if a module). There can only
* be one per module.
*/
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall(fn, 6)
マクロの定義はmodule_init = __initcall = device_initcallとなっていますので、module_init(funcname) はdevice_initcall(funcname) と書くのと同じです。
最後にmodule_init(funcname) は __define_init(funcname, 6) と定義されています。これもマクロでlinux/include/linux/init.hに下記のように定義されています。
#define __define_initcall(fn, id) \r static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn
何だか小難しいですが、簡単に言うとmodule_init(funcname) つまり __define_initcall(funcname, 6) と書いたら、初期化関数funcnameのポインタを値に持つ __initcall_funcname6という名前の変数を宣言し、セクション .initcall6.initに置け、という意味になります。
その変な名前の変数がどこに置かれるのか?は、リンカスクリプトlinux/arch/arm/kernel/vmlinux.ldsに書いてあります。全部は載せられませんので .initcall6.initセクションに言及しているところを見てみます。
.init.data : {
*(.init.data) *(.meminit.data) *(.init.rodata) *(.meminit.rodata) . = ALIGN(8);
__clk_of_table = .;
*(__clk_of_table) *(__clk_of_table_end) . = ALIGN(32);
__dtb_start = .;
*(.dtb.init.rodata) __dtb_end = .;
. = ALIGN(16);
__setup_start = .;
*(.init.setup) __setup_end = .;
__initcall_start = .;
*(.initcallearly.init) __initcall0_start = .;
*(.initcall0.init) *(.initcall0s.init) __initcall1_start = .;
*(.initcall1.init) *(.initcall1s.init) __initcall2_start = .;
*(.initcall2.init) *(.initcall2s.init) __initcall3_start = .;
*(.initcall3.init) *(.initcall3s.init) __initcall4_start = .;
*(.initcall4.init) *(.initcall4s.init) __initcall5_start = .;
*(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .;
*(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .;
*(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; ★★これ★★
*(.initcall7.init) *(.initcall7s.init) __initcall_end = .;
__con_initcall_start = .;
*(.con_initcall.init) __con_initcall_end = .;
__security_initcall_start = .;
security_initcall.init) __security_initcall_end = .;
...
※本来は改行が入っていませんが、見やすいように適宜改行を入れています。
私はリンカスクリプトに明るくないので、間違っていたらごめんなさいですが、基本的には書いた順でシンボル(変数や関数など)をオブジェクトファイル内に並べてくれる、という理解でこの辺りは大丈夫なはずです。
先ほどの __define_initcall() マクロの定義から __initcall_funcname6変数は、コンパイラが .initcall6.initというセクションに入れて、オブジェクトファイルを生成します。わかりにくいと思うので、例で説明します。
例えば、リンカが今までシンボルを並べてきた結果、現在のアドレスが0x10000になっていたとします。あと .initcall6.initセクションには __initcall_funcname6と __initcall_func2name6の2つのシンボルが含まれているとします。
リンカはまず「__initcall6_start = .;」を見て、現在のアドレス(ドットは現在のアドレスを表す)に0x10000: __initcall6_startを定義します。現在のアドレスは変わりません。
次に「*(.initcall6.init)」を見て、全オブジェクトファイルの .initcall6.initのシンボルを順番に並べ、現在のアドレスを進めます。つまり0x10000: __initcall_funcname6, 0x10004: __initcall_func2name6が並び、現在のアドレスは0x10008になります。「*(.initcall6s.init)」も同様ですが、何もシンボルが入っていないのでスルーします。
最後に「__initcall7_start = .;」を見て、0x10008: __initcall7_startを定義します。
すなわち下記のようなアドレス、シンボルの関係になります。
- Linuxカーネル - セクションA - セクションB - セクション .init.data - ... - 0x10000: __initcall6_start - .initcall6.init内の全シンボル (内訳) - 0x10000: __initcall_funcname6 = funcname() のポインタ - 0x10004: __initcall_func2name6 = func2name() のポインタ - 0x10008: .initcall6s.init内の全シンボル - __initcall7_start - .initcall7.init内の全シンボル - ... - セクションD ...
ここで、序盤の謎であった __initcall6_startの謎が解けます。思い出してほしいのですが、変数 __initcall_xxxx6はdevice_initcall(xxxx, 6) で指定した関数xxxxのポインタを値として持っていました。
リンカスクリプトによって、変数 __initcall_xxxx6の一群を __initcall_funcname6から「連続したアドレスに配置する」ので、C言語から見たときには、__initcall6_startはあたかも関数ポインタの値を持った配列に見えるわけです。
static initcall_t __initcall_funcname6 = funcname;
static initcall_t __initcall_func2name6 = func2name;
initcall_t __initcall6_start[] = {
__initcall_funcname6,
__initcall_func2name6,
...,
};
ただし、C言語ではこのような書き方はできないし、仮に書けたとしても、
&__initcall6_start[0] == &__initcall_funcname6
&__initcall6_start[1] == &__initcall_func2name6
が成り立たないので、厳密に同じことはできません。
この仕組みはC言語だけでは記述するのは恐らく不可能で、リンカとの連携の賜物と言えるでしょう。
論より証拠でLinuxカーネルをビルドして、生成されたvmlinuxをreadelfで調べましょう。
実験に使うカーネルは3.14.44でARM Versatile PBボード向けコンフィグでビルドしたものです。拙作のARM9エミュレータememu(emuemuについてはこちら)の動作確認用に実際に動作させていたバイナリです。
まずは -Sオプションでセクションの一覧を見ます。
$ arm-linux-gnueabihf-readelf -S vmlinux セクションヘッダ: [番] 名前 タイプ アドレスOff サイズES Flg Lk Inf Al ... [21] .init.pv_table PROGBITS c039b818 3a3818 0005cc 00 A 0 0 1 [22] .init.data PROGBITS c039bde8 3a3de8 003f6c 00 WA 0 0 8 [23] .data PROGBITS c03a0000 3a8000 027380 00 WA 0 0 32 ...
アドレスc039bde8からc039ffffまで、サイズ3f6c分のセクション .init.dataが居ることがわかります。vmlinuxをバイナリエディタなどで見る場合はOffの位置、つまり3a3de8を見ると .init.dataのバイナリデータが見られます。
Linuxはビルドしたときに全シンボルのアドレスと、シンボル名の対応表を作成してくれます。アドレスとシンボル名の対応はSystem.mapというファイルに出力されます。
$ grep initcall6 System.map c039fb08 T __initcall6_start $ grep initcall7 System.map c039fc94 T __initcall7_start c039fcb4 t __initcall_deferred_probe_initcall7
System.mapを見てもわかるように、__initcallx_startの軍団は .init.dataセクションの範囲内に全員収まっていることがわかります。
残りの疑問であるinitcall6内の呼び出し順はどうなるか?については、コンパイルされた順番になるようです。
System.mapの __initcall6_start付近を見ると、
c039fb08 T __initcall6_start ★★★arch/arm/ 以下 c039fb08 t __initcall_fpe_init6 ★★★kernel/ 以下 c039fb0c t __initcall_proc_execdomains_init6 c039fb10 t __initcall_ioresources_init6 ... c039fb50 t __initcall_pid_namespaces_init6 c039fb54 t __initcall_utsname_sysctl_init6 ★★★mm/ 以下 c039fb58 t __initcall_init_per_zone_wmark_min6 c039fb5c t __initcall_kswapd_init6 ... c039fb70 t __initcall_slab_proc_init6 c039fb74 t __initcall_cpucache_init6 ★★★fs/ 以下 c039fb78 t __initcall_fcntl_init6 c039fb7c t __initcall_proc_filesystems_init6 ... c039fbbc t __initcall_init_jffs2_fs6 c039fbc0 t __initcall_init_romfs_fs6 ★★★ipc/ 以下 c039fbc4 t __initcall_ipc_init6 c039fbc8 t __initcall_ipc_sysctl_init6 ★★★crypto/ 以下 c039fbcc t __initcall_crypto_algapi_init6 c039fbd0 t __initcall_aes_init6 ★★★block/ 以下 c039fbd4 t __initcall_proc_genhd_init6 c039fbd8 t __initcall_bsg_init6 c039fbdc t __initcall_noop_init6 c039fbe0 t __initcall_deadline_init6 c039fbe4 t __initcall_cfq_init6 ★★★drivers/ 以下 c039fbe8 t __initcall_pl061_gpio_init6 c039fbec t __initcall_fb_console_init6 ... c039fc68 t __initcall_ms_driver_init6 -> module_hid_driverが生成した関数 c039fc6c t __initcall_mr_driver_init6 -> module_hid_driverが生成した関数 ★★★net/ 以下 c039fc70 t __initcall_sock_diag_init6 c039fc74 t __initcall_flow_cache_init_global6 ... c039fc90 t __initcall_packet_init6 c039fc94 T __initcall7_start
このようになっています。linux/Makefileを見てみると、
ifeq ($(KBUILD_EXTMOD),) core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
このように同じ順で並んでいることがわかります。ざっと見た感じだと、サブディレクトリ内のモジュール達(fs, driversの下)も同様に、Makefileに書いた順で初期化されるようです。
要するに、モジュールBがモジュールAに依存している場合、MakefileにはA → Bの順で書かないとなりません。逆に書いてしまうと、モジュールBが先に初期化され、未初期化のモジュールAを呼び出し、カーネルがクラッシュする悲劇が起きます。
「うわ... 私のiPhone 6sバッテリーもたない?」CPU違いの6sでバッテリーベンチをしてみました を読んで。
元々の原価が低いのか、FinFETで首位に立つべく値引きしたか、事情は知りませんが、廉価版のiPhoneほどSamsung製の搭載比率が大きいところを見ると、TSMCよりSamsungの方がAppleの利ザヤがデカいのでしょう。おそらく。
そういえばQualcommはSnapdragon 810(TSMC 20nm)で発熱問題に泣いて、次のSnapdragon 820はSamsung製らしいですね。16nm世代を採用したら次も泣かされそう…。
メモ: 技術系の話はFacebookから転記しておくことにした。
今や映像の圧縮方式として当たり前となりつつあるMPEG4-AVC(※)には、2つの形式があります。
Byte Stream Formatは、俗に言うスタートコード形式(0x000001を目印としてNALUが始まる)で、コンテナを使わない場合、リアルタイム配信(RTSP)、放送系(MPEG2-TSをコンテナ)で良く使われているようです。
利点としては「欠け」に強いことです。何か問題が発生してデータが欠けてしまっても、スタートコードさえ見つかれば、その地点から処理を再開できます。その分、毎度スタートコードを探す処理が必要がある、先頭が欠けても再生できるように重複して情報を入れる必要があるなど、やや非効率的です。
NAL File Formatは、いわゆるサイズ指定形式(数バイトのサイズの後にNALUが始まる)です。ファイル形式(MP4など)に良く使われているようです。
利点としては「効率的」であることです。余分な情報はコンテナに持たせて、ビットストリームからは取り去りますのでサイズが小さくできます。NALUのサイズも予めわかりますから不要なNALUをスキップする際の負荷も低いです。その分、1バイトでも欠けてしまうと、デコードできなくなってしまう弱さもあります。
実はこの2つを変換するのは面倒で、サイズ指定をスタートコードに置き換えるだけではダメです。そんな単純な変換では、上記のような特徴が出せません…。
(※)AVCはAdvanced Video Codecの略です。この規格はISO/IECとITU-Tの共同規格なので、MPEG4-AVCではなくITU-Tの規格名であるH.264と呼ぶ人も多いですね。
でも、自分でそのような処理を書く必要はありません。世の中にはナイスガイ達が居て、変換が可能なツールを公開してくれています。ありがたいことです。
まずはffmpegを使う場合ですが、コーデックは変更しないのでcopyを指定して、普段の利用ではあまり見かけないbsfオプションを使って変換します。
なぜmp4toannexbという名前かと言うと、MPEG4-AVCの規格であるISO/IEC 14496-1 Annex BにByte Stream Formatの規格が示されているからではないか?と思われます。
avconv -i /path/to/hogehoge.mp4 -vcodec copy -bsf:v h264_mp4toannexb hogehoge.h264
Gstreamerを使う場合はh264parseエレメントを使います。ffmpegと比べるとかなり長く感じますが、大したことはしていないです。
例では、改行を入れていますが、実際には改行を入れずに1行で書いてください。もしGstreamer 1.0系を使う場合は、video_00のところをvideo_0と書く必要があったはずです。たぶん。
gst-launch filesrc location=/path/to/hogehoge.mp4 ! qtdemux name=dem dem.video_00 ! h264parse ! video/x-h264,stream-format=byte-stream,alignment=au ! filesink location=/path/to/es/hogehoge.h264
普通に動画を楽しんでいる人には、こんな変換は全く縁がありませんが、私にとっては便利なんです。こんなツール達がオープンソースで公開されているというのは、ありがたいことですなー…。
Visual Studio 2015のコンパイラは、未だにBOMを付けないとUTF-8を認識しません。なぜかShift-JISもコンパイルエラーになります(2013ではなりません)。
MSDNライブラリ(サイトへのリンク)でも「コンパイラおよびリンカーでのUnicodeのサポート(... 中略 ...)BOM付きのUTF-8」などと言いきる始末です。イマイチすぎる…。
Visual StudioのIDEはGitに対応したり、エディタがマルチプラットフォームになったり、コミュニティベース開発に力を入れたり、時代の流れに沿って進化していますが、
コンパイラはダメダメ感が漂います。C++0xの対応はllvm, gccの後塵を拝しワーストです。もはやMicrosoftですら単独でC/C++ コンパイラを開発するのは不可能なのかなあ…?
メモ: 技術系の話はFacebookから転記しておくことにした。
< | 2015 | > | ||||
<< | < | 10 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 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 |
合計:
本日: