✖
デザインの調整
ずっと中途半端なデザインだなと思っていたので、改めて全体を見直しました。
大きい画像は devicePixelRatio に基いて大きい画像をロードするようなスクリプトを書いていたのですが、面倒なので最近になって常に 2048px の画像を読みこむように変えました。
しかし画面の表示は 960px 程度を最大にしており、Retina でも若干の無駄があるのが気になってきました。ということで、まず 1024px を最大幅にできるようにしました。
しかし、意外ともう少し狭い幅で見ることも多い気がするので (特に開発ツールを横に開いていると結構画面が狭い)、その場合幅だけ変えたバージョンをメディアクエリでだしわけしています。
スマートフォン向けにはさらに狭い幅向けのバージョンをメディアクエリでだしわけていますが、これはほぼ今まで通りです。
また、大きい画面の場合、photo タグが設定されているエントリと、それ以外のエントリで画像の幅を変えるようにしました。tech カテゴリでも無駄に横幅が大きい画像になっていて一画面の情報量が少なかったので、これで見易くなった気がします。
しかし、テキストの幅を制限しつつ画像は大きく表示したいと思うと、自分のデザイン能力だと綺麗にいかず難しく感じます。
STM32F103 C8 T6 の安いボードでLチカ (platformio + mbed)
STM32F103 C8 T6 の安いボードが ebay で売っているので買ってみました。水晶が実装済み基板が 300円程度。届いたボードに実装済みの外部水晶は8MHz (内蔵RCと周波数は一緒) のようです。また 32.768k の水晶もついています。他に実装されているのはLDOやUSBコネクタぐらいです。
なお USB デバイスを作りたい場合 RC オシレータだとクロック精度が足りないので外部水晶は必須です。
買ったのはこれです: http://www.ebay.com/itm/201529768817
型番について
- STM32F103 シリーズ
- STM32F103C8
- リファレンスマニュアル
STM32F103 C8 T6 という型番の読みかた
- C: 48pins
- 8: 64kbytes Flash
- T: LQFP パッケージ
- 6: -40〜85°C
をあらわしています。STM32F103x8 (64k) や STM32F103xB (128k) はスペックシート共通になっています。 (ピン数とFlashのサイズの違いのみなので)
特徴
以下個人的に良さそうと思った点です。
- STM32F103 は USB 1.1 FS (フルスピード=12Mbps) に対応している
- ADC が2つある (チャンネル数は10)
- 同時サンプリングができそう
Cortex-M3 なので M0 よりはパフォーマンスが良さそうです。一方 FPU や DSP 関係の命令 (SIMDとか) は M0 同様ありません。
クロック
SYSCLK (システムクロック) は
- HSI
- High Speed Internal ?
- HSE
- High Speed External ?
- PLL
の3種類のクロックソースがあります。
HSE はさらに HSE バイパスと HSE クリスタルとに別れています。バイパスは発振器のクロックを直接入れるモードです。
PLL のクロックソースにはHSIとHSEがどちらも使えるようになっています。
このボードの場合
8MHz の外部水晶がついてるので、8MHz の HSE を PLL のクロックソースとして 72MHz にします。USB 用のクロックもここから作ることになっています。
- PLL 入力クロックソースは HSE、分周なし
- PLL逓倍を9倍に (8 * 9 = 72MHz)
- USBプリスケーラは1.5に (72MHz / 1.5 = 48MHz)
- APB1 は2分周 (72MHz / 2 = 36MHz)
みたいになりそうです。が、とりあえず mbed 環境で動かしてみるためクロック設定は無視します (mbed 側で 72MHz に適当に設定されます)
書きこみ (Lチカ)
例によって環境を整える部分は platformio でやります。
platformio.ini は以下のようにします。nucleo_f103rb は型番違いですが、ほぼほぼ互換性があります。nucleo_f103rb の外部水晶も 8MHz のようで、この場合 mbed の初期化コードは一切変更なしでいけそうです。
本来 boards の追加をもっと簡単にできたらいいのですが、現状の platfromio だとそういうことはできなそうです。
# platformio.ini # nucleo_f103rb は f103c8t6 とフラッシュサイズとピン数以外は互換 # 外部クロックも 8MHz で同じのためそのまま使える [env:stm32f103c8t6] platform = ststm32 framework = mbed board = nucleo_f103rb
Lチカはこのようにしました
#include "mbed.h"
DigitalOut led(PC_13);
// Serial serial(USBTX, USBRX);
int main() {
for (;;) {
led = 1;
wait(0.5);
led = 0;
wait(0.5);
}
} PC_13 はボード上のLEDに繋がっています。nucleo_f103rb だと LED1 は PA_5 のようなので、ジェネリック名ではなくピン名で直接指定しています。
書きこみはこれまた ebay で購入した st-link2 を使いました (約400円)。Mac の USB ポートに繋ぐと特に何もしなくても認識するようでした。
ボードと st-link を接続して、USB 接続すると、基板上にも電源供給されます (別途電源供給はいらないようです)
書きこむためまず st-util を起動します。platformio で ststm32 環境をセットアップしておくと st-util もインストール済みのため楽です。
$ ~/.platformio/packages/tool-stlink/st-util 2016-04-14T00:48:41 INFO src/stlink-common.c: Loading device parameters.... 2016-04-14T00:48:41 INFO src/stlink-common.c: Device connected is: F1 Medium-density device, id 0x20036410 2016-04-14T00:48:41 INFO src/stlink-common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes 2016-04-14T00:48:41 INFO gdbserver/gdb-server.c: Chip ID is 00000410, Core ID is 1ba01477. 2016-04-14T00:48:41 INFO gdbserver/gdb-server.c: Target voltage is 3254 mV. 2016-04-14T00:48:41 INFO gdbserver/gdb-server.c: Listening at *:4242...
こんな感じで gdb server として立ちあがります。
別のターミナルから gdb server に接続してバイナリを送りこみます。
$ ~/.platformio/packages/toolchain-gccarmnoneeabi/bin/arm-none-eabi-gdb .pioenvs/stm32f103c8t6/firmware.elf > target extended-remote localhost:4242 > load > cont
これでLチカできました。
ref
- USB サンプル
- mbed の初期化コード
- mbed-src/targets/cmsis/TARGET_STM/TARGET_STM32F1/TARGET_NUCLEO_F103RB
- mbed ピン名定義
- mbed/TARGET_NUCLEO_F103RB/TARGET_STM/TARGET_STM32F1/TARGET_NUCLEO_F103RB
体調不良
あいかわらず断続的に体調不良。一日会社を休んで寝てたら回復した気がしたが、また腹痛になった。吐き気はしないのでまだマシ。
ここ最近、夜中に子供がうんちしていることがあって、いざ寝ようと思うと寝室がめっちゃ臭い。子供もおそらく胃腸炎を完治してない気がする。食欲はかなりあるみたいだけど、本調子ではないのだろう。
基本的にストレスが多いのだけど、ストレスが多くなると些細なことにイライラしてさらにストレスを増やしてしまう。一方で捌け口が自分の場合ほとんどないので、どうしようもない。
直近で気が重かった仕事が一旦出て、それは良かったのだけど、出たは出たで次は何をするのかと考えると気が重いので、無限に気が重い。
「スケジュール」について考えると気がとても重くなるのだけど、実際に全体のスケジュールを決めてる人は不思議と前工程のスケジュールをさっぱり守らないので、自分が気を揉むようなことではないはずだと思う。一方スケジュールのことを無視して言われたベースでやってると「やってないんですか」みたいなことになって鬱陶しいし、なんかとにかく何をどうしても嫌な気持ちになるしかない感じがする。
保育園のナニカみたいなのが一年たってだいたい終わったんだけど、自分の役職だけまだ仕事があって、とてもだるい。なんか数秒喋るだけのために1時間か2時間拘束されるハメになる。これが終われば終わりだから我慢しよう。それにしても保育園関係のナニカは本当に不愉快だった…… これは本来「無償ボランティア」の範疇にあることだが、それは名ばかりで強制力がある。責任()というやつです。直接子供のためになるならまだしも、クソどうでもいいこと (進級時に先生にお礼をしましょう、みたいなの。個人的には心底どうでもいい) が実際殆どであった。「無償ボランティア」なうえ特にモチベーションもないので、必然的に優先順位は最下位なのだが、やたらごちゃごちゃ言われて本当に辛かった。得るものがほぼないのに時間がとられる、死にたくなるほど割に合わない。保育園のナニカと比べれば普段の仕事は大変良くて、周りの人は会話が通じるし、効率的なやりかたをしようという前提が共有されている。
✖
筋の悪さ
JS しか書いてないんだなって人は筋悪いものをありがたがっていたりする印象はある。しかし筋悪いものをありがたがるみたいなのはどこにでもいるので、JSがどうとかは直接は関係がないはずではあると思う。JSしか書いてない人とPHPしか書いてない人は似たようなもんで、単に広範囲の知識に興味がないだけな気がする。
それはともかく「これは筋悪そうだな」っていう感覚がどこからくるのかよくわかってないので、現時点で思いつく限り雑にメモしておく。
割の合わなさ
「これは何の問題を解決してるんだろう」と思ってドキュメント読んだりソース読んだりした結果、大したことを解決してなくて、その割に実装量が多いとか学習コストが高いと、筋悪いなあと思う。
フットプリントや学習コストに対して提供されるモノが「割に合わない」のは筋が悪く感じる。
将来性のなさ
「あ、これはただの流行だな」みたいな、5年後には消滅してるなというものは筋が悪い。
標準にそういう機能入るよ、みたいなのを全然違うインターフェイスで実装してたりするのとかがあてはまる。標準で議論されている機能なら、ポリフィルにするのが最も将来無駄にならない。
HTTP2 に向けてキャッシュフレンドリーなリソース構成にしていこうな、という昨今で、何でもかんでもパックや!みたいなのも、今はぎりぎりいいかもしれないけど、既に筋悪い感じがする。
プログラムの見方を変えないラッパー
たとえば Promise はコールバックのちょっとしたラッパーぐらいの機能しかないが、プログラムの見方を変えるという重要な役割を持っているので、意味がある。
しかし単にシンタックスシュガー的なものしか提供していないとかで、何もプログラムの見方が変わっていないのにラッパーがかぶさっているのは、ライブラリとしての意味がない。
「プログラムの理解を助ける」という役割はとても重要だけど、そういう視点で作られているライブラリかどうか、それが割に合うかは難しい。
しかし最悪なのは書き手にとってしかメリットがないというもの。特に実装を全て読まないと使えない系は要注意で、そういう書き手のオナニーで変なラッパーが挟まってるみたいなのは読み手がとても苦労する。これはメリットがないというよりも明確に将来にわたって害となる。
ただし実装を全て読まないといけないものが全てだめかというとそういうわけでもない。実装は読まないと危険だけど可読性はあがるので割に合うこともある。
フルスタック
フレームワークのレールから外れた瞬間アホみたいなマジカルコードを書くことになる。レールから脱線すると必ずハマる。そしてフレームワークの枠組み内で収まるようなアプリケーションはない 。
もし使う場合コピペで実装できる以外のことをしないことがポイントで、「ここはこう書きたいんだ!」という自我を捨ててコピペする機械として生きなければならない。
実際のフルスタックというのは検索して出てきたstackoverflowのコピペで全部やりますよという意味で、なんでもできるという意味ではない。
HTTP2 で何をサーバープッシュすべきか
意外と何をプッシュすべきか悩んだのでひとまず現時点での自分の結論をまとめました。
CSS は必ずプッシュ・JSは場合による
サイトの構成によりますが、ページの表示に必要なものは全てプッシュするべきのようです。
- CSS の全て
- ページの根幹に関わるJSの全て
サーバプッシュの目的
まずサーバプッシュの目的を改めて確認しておくと、これはクリティカルレンダリングパスを削減するためです。
クリティカルレンダリングパスについては クリティカル レンダリング パスのパフォーマンスを分析する | Web Fundamentals - Google Developers がわかりやすいです。
サーバープッシュなしの場合 HTML+CSS 構成のページはクリティカルレンダリングパスが必ず2以上になります。つまり最低でもRTTの2倍の時間がページ表示に加算されます。
これをサーバプッシュで行う場合、HTML+CSSを一度に送り返すので、クリティカルレンダリングパスは1になります。
イメージとしてはHTML内の外部CSSが全てインライン style 要素にしてある場合に似ています。ただしサーバプッシュの場合、適切なキャッシュを効かせることができるケースがあるので、インライン style 要素よりも効率的です。
JSをプッシュすべきか
これは場合によると思っています。JSがないとページの表示に致命的な不具合がある場合、サーバープッシュしないと意味がありません。
一方、JS がページのインターフェイスの向上のために使わていて、とりあえずの表示に関係がない場合、JS をプッシュした分、ファーストペイントが遅れます。
そういうわけでなので、JS をプッシュすべきかどうかは場合によるので簡単に決められない気がしています。
理想のサーバープッシュ
理想のサーバープッシュを考えるにあたって、ロードされるリソースの分類をしてみます。
クリティカルリソース (ブロッキングアセッツ)
ファーストペイントのために必要なリソース
- CSS
- ブロックする JS (async/defer のない script 要素)
- HTML
DOMContentLoaded リソース
DOMContentLoaded までに必要なリソース
- defer された script
onload リソース
onload までに必要なリソース
- 画像
- async された script
どうプッシュするか
最終的に必ずロードされるリソースなら、プッシュしてしまっていいはずです (初回ロードの場合)。
- クリティカルリソース
- DOMContentLoaded リソース
- onload リソース
の順に全てプッシュするのが理想そうです。ただ、現時点で任意の順番に優先順位を明確に決めて送信することはできないような気がしてます。
プルリクエストを送るときは大抵気が重い。
たとえ明かなバグ修正、すなわちマージされる公算が大きくても、些細なことでケチがついたりする。これがさらに機能追加みたいな「マージしてもしなくても本流には関係ないね」みたいなのは、マージされる公算がさらに低くてさらに気が重い。
まずプルリクエストを送るケースってのは、別にプルリクエストを送りたくてやってるわけではなく、そのプルリクエストに含まれるコードが自分に必要だからやってるに過ぎない。つまり最悪自分のレポジトリに置いておけばいいのだが、本流に取り込まれていれば今後のバージョンアップで機能が壊れることが減る (ついでに他に困ってる人がいたら助かるかもしれないね)。そういう保守的なモチベーションで動いていることであって、元気良くプルリクを送っているわけではない。
そういうわけで、大抵の場合プルリクエストを投げた時点で「XX だ! とか言われてDISられそうだ」とか「コードスタイルがあってない!!とか言われてリジェクトされないか」とか「オレのところだとテストが通らん!とか言われないか」とか気が滅入る妄想に支配され、燃えつきており、あとはもう勝手にしてくれ (コミュニケーションはしたくないぞ) という気分になっている。
最近良くあるのが、プルリクエスト送る前にコミュニケーションしろ!みたいなルールを強いているプロジェクトで、こういうのはほんとどうしようもない。死ぬほど困っているとか、仕事でやるとかじゃないならプルリク送る気がしない。コミュニケーションしたくないからコード書いてプルリクしてんのに、コミュニケーションを強要してくるのはどういうことなのか。かつて github に感じた居心地の良さはここにはない。
みいつけた!
サボさんいい
「ワンワンパッコロ!キャラともワールド」でワンワンとサボさんが共演する夢の回があって、サボさんがダンソン(バンビーノ)をやっていた。この番組、全体的に子供には難しいネタが多い。改めて見るとお笑いって常識(お約束)を裏切る形のパターンがよくあって、そもそも常識のない子供はいつから笑えるようになるのだろうと思った。
しょぼい個人サイトのキャッシュ
殆どアクセスがないサイトは、ファーストアクセスでキャッシュを作るようなサーバサイドキャッシュの戦略が全く意味がないので、バッチで予めキャッシュを作っておくみたいなことが必要そうだなと思い、そういうスクリプトを書いて流せるようにしました。
特にサイトのHTML頻繁に変えたりしているとしょっちゅうキャッシュの意味がなくなります。要はこれ、blosxom における静的なページ生成とか、MT におけるリビルドみたいなもんです。
✖
意外と http/1.1 のホストがない
このサイトのトップをロードするとこんな感じで、Google 系 (Adsense や Google Photo) は quic/1+spdy/3、このサイトは h2 となっていて、 http/1.1 となっているほうが少ないことに気付きました (はてなスターのみ)。Firefox では quic/1+spdy/3 の部分が全て h2 になってました。
バイポーラトランジスタによるRFアンプの覚書
こんな感じでシミュレーションしつつ、感覚をつかもうとしています。
今ところ感じたこと
- を十分に流すこと (データシートに のグラフがあることが多い)
- を流そうとすると負荷抵抗は大きくできない (大きな増幅率をとれない)
- そもそも高周波になると増幅率がとれない (ミラー効果)
- ぐらいが限界周波数になるらしい? このシミュレーションだと の20分の1ぐらいまでしか十分な増幅ができない
100MHz ぐらいまで増幅したい場合 は 1GHz〜2GHz が必要
負荷がコイルの場合は?
このシミュレーションの負荷は、伝送線路的トランスによる 4:1 (または9:1) のインピーダンス変換器になっている。出力側が50Ωになっているので、増幅器の負荷は200Ω (450Ω) になる。つまり増幅率があがる。
このシミュレーションの場合 450Ω 負荷だと頭うちになっていてあまり意味がないように見える。
なぜエミッタ接地なのか?
電圧増幅+エミッタフォロワみたいな形にしないのは、電圧増幅を伴なう場合エミッタフォロワの意味が薄いから?
を十分流す必要がある以上、負荷抵抗を大きくできない。逆にいうと出力インピーダンスは低くならざるを得ない。出力インピーダンスを直接50Ωとかにマッチングさせるなら、エミッタフォロワを使う意味はない。
ベース接地・エミッタフォロワ
いずれも電流増幅率が1だったり、電圧増幅率が1だったりするので電力増幅に向いてない。
カスコード接続
エミッタ接地の負荷にベース接地をつける形のもの。ミラー効果がなくなるので高い周波数まで増幅できるようになる。ただしトランジスタを2つ縦に繋げるので電源電圧をその分上げる必要がある。
✖
✖
先々週も先週も今週も、週末なぜかひたすら寝ていた。無限に疲れている。
サイトの最適化
HTTP2 化に伴なって、サイト全体の最適化を行ないました
依存の整理
もはや jQuery なしでも簡単に書けそうなスクリプト部分から jQuery 依存を抜きました。また、JSDeferred を Promise で置き換えました。
script 要素の async / defer
script 要素については必要に応じて async や defer をつけるようにし、基本的に外部スクリプトでブロックする可能性を排除しました。
async は script 要素同士で独立している場合無条件につけられます (非シーケンシャル)。defer はページのDOMが構築されたあとに実行されるように遅延されます (シーケンシャル)
defer は DOMContentLoaded 直前にまとめて呼ばれるようです。
外部ライブラリを自分でホスト
外部ライブラリをCDN経由でロードしている部分がありましたが、TLS セッションの無駄遣いな気がするので、自分でホストするように変えました。自分のホストであれば HTTP2 のセッションが生きているので無駄な処理が減りそうです。
動的圧縮から静的圧縮に
h2o で compress: ON とすると accept-encoding に応じて gzip か br で動的に圧縮してクライアントに返却してくれます。
しかし殆ど変更されないライブラリみたいなものは動的にやるのがもったいないので、静的に圧縮するようにしました。特に brotli は圧縮処理が遅い感じなので意味がありそうです。
h2o 的には file.send-compressed: ON にしって、filename.js.gz と filename.js.brを置くようにします。
.gz と .br をつくるスクリプト
以下のようなスクリプトを作っておくと、指定したファイルの .gz と .br を作れて便利です。
静的に作っておけば、特に VPS のスペックが非力だと相対的に効果が高いはずです。
#!/bin/sh
for f in "$@"
do
echo "$f"
gzip --best < "$f" > "$f".gz
bro --quality 10 --input "$f" --output "$f".br
done brotli について
h2o は brotli に対応していて、accept-encoding: br なときはオンデマンドも br を返すみたいです。
ただ、brotli は chrome に実装済みといっても flags で有効にしないとまだ使えないみたいです。
Firefox 45 は標準で accept-encoding: br を吐くようです。
ブログシステムでのキャッシュ
今まで表示のたびに DB からひいてきてテンプレート処理を行っていましたが、キャッシュするようにしました。もともとそこまで遅いわけではないのですが 、一応これも効果がありました。
ただ、キャッシュを入れるとキャッシュ無効化の処理のために考えることが大変増えます。今のところあまり筋の良い実装ではないのですが、一応動いています。
MathJax のサーバサイド化
[tech] サーバーサイド MathJax で数式表示を高速化する | Fri, Apr 8. 2016 - 氾濫原 別エントリにしました。
いろいろやった結果
キャッシュなしの状態でロードして、DOMContentLoaded まで 300ms を切るぐらいにできました。ただし onload までは2秒〜3秒かかっています。onload まで遅いのは画像のサイズが大きいというのと、あとは主にアドセンスのせいです。
同じ環境で www.google.co.jp のDOMContentLoaded を測ると 170ms ぐらいでしたので、要素数などを比較するといい線まできている気がします。
さらにできることは?
いわゆる minify をやっていないので、これをやる余地がまだあります。しかし結構面倒です。そしてたとえ削れても数kBなので、意味があるのか疑問を持っています。
サーバーサイド MathJax で数式表示を高速化する
このサイトでは数式を本文中に TeX 形式で書いて MathJax で処理させています。↓ こういうやつです。ベクターなので昨今の高解像度事情でもいい感じに綺麗に表示できます。
これはクライアントサイドで本文中の TeX フォーマットを探して全部 SVG とかに置き換えていくのですが、これがなかなか重い処理です。
特にスマートフォンの場合、数式がまともに表示されるまで5秒〜10秒ぐらいかかるので、それまでモヤモヤした感じになります。
さらにいえば、これは非同期で変換をかけているのでロード直後にリフローが頻発することになります。
ということで、これらの問題をなんとかしたいので、標題のようにサーバサイドで MathJax を使ってみるようにしてみました。
このサイトははてな記法で書いたエントリを保存時にHTMLに変換し、変換済みをDBにいれて、表示のときはそれを出しているだけです。なので、保存時に MathJax を通して本文中の数式を埋め込み SVG に変換するようにします。
HTML の断片をうけとって MathJax にかける HTTP サーバ
幸い MathJax-node という node.js 上で動かせる MathJax があったので、これをそのまま使い、http.Server でラップして、ブログシステムとは別に API サーバを立ち上げました。
#!/usr/bin/env node
var mjAPI = require("mathjax-node/lib/mj-page.js");
mjAPI.start();
mjAPI.config({
tex2jax: {
inlineMath: [["\\(","\\)"]],
displayMath: [ ["$$", "$$"] ]
},
extensions: ["tex2jax.js"]
});
var http = require('http');
http.createServer(function (req, res) {
var html = [];
req.on('readable', function () {
var chunk = req.read();
console.log('readable');
if (chunk) html.push(chunk.toString('utf8'));
});
req.on('end', function() {
console.log('end');
console.log('html', html);
mjAPI.typeset({
html: html.join(""),
renderer: "SVG",
inputs: ["TeX"],
ex: 6,
width: 40
}, function (result) {
console.log('typeset done');
console.log(result);
res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
res.end(result.html);
});
});
}).listen(13370, '127.0.0.1');
console.log('Server running at http://127.0.0.1:13370/'); ブログシステムからは保存時にこのAPIを呼んでHTMLをフィルタしてDBに保存するようにしました。
ハマりどころ
動的な MathJax だと、ページのコンテナサイズから適切な幅を計算してくれるのですが、サーバサイドだとそれができませんので、適切な横幅を自分で指定する必要がありました。
スマートフォンでの閲覧を考えると、width: 40 ぐらいにして、念のため CSS で svg { max-width: 100% } とかを入れておくとよさそうです。width が大きいと、数式ごとのフォントサイズが変わりまくって大変うっとおしいです。
MathJax-node の速度
MathJax-node はなぜかものすごく遅いです。ライブラリロード済みでも10秒ぐらいかかります。そもそも起動も遅いです。オンデマンドでやるのは無理そうなレベルです。
MathJax の JS のロードを抑制
これに伴なって、MathJax を使わなくても良さそうな場合、JSのロードすらやめるようにしました。
所感
MathJax の JS は2段階ぐらいでロードされるので RTT が長いほど不利になります。サーバサイドでやってしまえばJSを転送する必要も実行する必要もなくなるのでエコです。おかげでロードが結構早くなりました。
しかもページロード直後から数式が完全な形で表示されるので、ページに数式がある場合、体感的な速度は数倍に感じます。
h2o のログ設定 (logrotate.d)
ログの設定を stdout のままにしていたので rotate するように設定しました。(Ubuntu 12.04.5 LTS)
h2o の設定
sudo mkdir /var/log/h2o sudo chown www-data:adm /var/log/h2o/
YAML の参照を使うとログフォーマットを使いまわせてよいです。まず global に
access-log: &ACCESSLOG
path: /dev/null
format: "..." と書いて、あとは各ホストで path を上書きする形で設定します。
access-log:
<<: *ACCESSLOG
path: /var/log/h2o/host.access.log なおこのYAML参照は h2o 2.0.0 からのサポートのようです。
logrotate の設定
# /etc/logrotate.d/h2o
/var/log/h2o/*.log {
daily
missingok
rotate 90
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
svc -h /service/h2o
endscript
} h2o は daemontools で管理しているので、postrotate では svc を呼んで SIGHUP を送っています。
一旦状態を確認します
sudo logrotate -dv /etc/logrotate.d/h2o
全ログファイルが log does not need rotating になってるはずです。実際に一度実行します
sudo logrotate -v /etc/logrotate.d/h2o
/var/lib/logrotate/status を見ると該当するログファイルが記録されているはずです。日付を一日戻して再度実行するとローテートされることが確認できます。
Let's encrypt の自動更新
以下のようなスクリプトを置いて月イチの cron で更新するようにしました。証明書を更新したあと h2o を restart しています。
#!/bin/sh
# sudo crontab -e
# MAILTO = cho45
# PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# 25 14 6 * * /srv/www/renew-cert.sh
BIN=/home/cho45/project/letsencrypt/letsencrypt-auto
$BIN certonly --webroot -w /srv/www/www.lowreal.net --renew-by-default -d www.lowreal.net
$BIN certonly --webroot -w /srv/www/lowreal.net --renew-by-default -d lowreal.net
$BIN certonly --webroot -w /srv/www/cho45.stfuawsc.com --renew-by-default -d cho45.stfuawsc.com
svc -h /service/h2o
現在の h2o.conf.yaml
今のこのサイトの h2o.conf.yaml です。HTTPS (443) のみを処理しています。HTTP (80) は nginx で受けていて、HTTPS 対応ホストに関しては nginx からはリダイレクトしています。
- アクセスログフォーマットを LTSV に
- ログフォーマットを YAML の参照で全ホストで共有
- rewrite rule
- Strict-Transport-Security (HSTS)
- 一旦 https でアクセスしてきたクライアントに対して以後 http でのアクセスをさせない
- 本来はセキュリティのためだが、リダイレクトを一回減らせるのでパフォーマンス的にも一応得
- "/.well-known": をバインド
- letsencrypt のホスト検証に使われる
設定の際参考になれば幸いです。
user: www-data
access-log: &ACCESSLOG
path: /var/log/h2o/access.log
format: "time:%t\thost:%h\treq:%r\tstatus:%s\tsize:%b\treferer:%{Referer}i\tua:%{User-Agent}i\tcache:%{X-Cache}o\truntime:%{X-Runtime}o\tvhost:%{Host}i\tconnect-time:%{connect-time}x\trequest-header-time:%{request-header-time}x\trequest-body-time:%{request-body-time}x\tprocess-time:%{process-time}x\tresponse-time:%{response-time}x\tduration:%{duration}x\thttp2.stream-id:%{http2.stream-id}x\thttp2.priority:%{http2.priority.received}x"
error-log: /dev/stdout
http2-reprioritize-blocking-assets: ON
ssl-session-resumption:
mode: all
hosts:
"lowreal.net:443":
access-log:
<<: *ACCESSLOG
path: /var/log/h2o/lowreal.net.access.log
http2-casper: ON
compress: ON
listen:
port: 443
ssl:
certificate-file: /etc/letsencrypt/live/lowreal.net/fullchain.pem
key-file: /etc/letsencrypt/live/lowreal.net/privkey.pem
header.add: "Strict-Transport-Security: max-age=31536000"
header.add: "X-Content-Type-Options: nosniff"
header.add: "X-UA-Compatible: IE=Edge"
paths:
"/":
reproxy: ON
mruby.handler: |
require "/srv/www/rewrite_rules.rb"
lambda do |env|
RewriteRules.rewrite(env) do
rewrite '/favicon.ico', '/images/favicon.ico', :break
rewrite '/apple-touch-icon.png', '/images/apple-touch-icon.png', :break
rewrite %r{^/2005/colors-canvas\.xhtml$}, '/2005/colors-canvas.html', :permanent
rewrite %r{^/2005/colors-canvas$}, '/2005/colors-canvas.html', :permanent
rewrite %r{^/logs/latest$}, '/', :permanent
rewrite %r{^/logs/latest.rdf$}, '/feed', :permanent
rewrite %r{^/logs/latest.atom$}, '/feed', :permanent
rewrite %r{^/latest\.rdf$}, '/feed', :permanent
rewrite %r{^/blog/index\.(rdf|atom)$}, '/feed', :permanent
rewrite %r{^/logs(/.+?)(\.(rdf|atom))$}, '/feed', :permanent
rewrite %r{^/logs(/.+?)(\.(x?html|xml|txt))?$}, '\1', :permanent
rewrite %r{^/blog(/.+?)(\.(x?html|xml|txt))?$}, '\1', :permanent
rewrite %r{^/photo$}, '/photo/', :permanent
rewrite %r{^/(\d\d\d\d/\d\d(/\d\d)?)$}, '/\1/', :permanent
rewrite %r{^/\d\d\d\d/$}, '/', :redirect
rewrite %r{^/view-img(/.+?)$}, '\1', :permanent
rewrite %r{^/(\d\d\d\d/([^\d]|\d\d[^/]).*)}, '/files/\1', :break
end
end
proxy.reverse.url: http://localhost:5001
proxy.preserve-host: ON
"/files":
file.dir: /srv/www/lowreal.net/files
"/images":
file.dir: /srv/www/lowreal.net/Nogag/static/images
"/css":
file.dir: /srv/www/lowreal.net/Nogag/static/css
"/js":
file.dir: /srv/www/lowreal.net/Nogag/static/js
"/lib":
file.dir: /srv/www/lowreal.net/Nogag/static/lib
"/.well-known":
file.dir: /srv/www/lowreal.net/.well-known
"www.lowreal.net:443":
access-log:
<<: *ACCESSLOG
path: /var/log/h2o/www.lowreal.net.access.log
http2-casper: ON
compress: ON
listen:
port: 443
ssl:
certificate-file: /etc/letsencrypt/live/www.lowreal.net/fullchain.pem
key-file: /etc/letsencrypt/live/www.lowreal.net/privkey.pem
header.add: "Strict-Transport-Security: max-age=31536000"
header.add: "X-Content-Type-Options: nosniff"
header.add: "X-UA-Compatible: IE=Edge"
paths:
"/":
reproxy: ON
mruby.handler: |
lambda do |env|
link = [
'/styles/201002/201002.css',
'/js/site-script.js',
].map{|p| "<#{p}>; rel=preload"}.join("\n")
case env['PATH_INFO']
when "/"
if (env['HTTP_ACCEPT_LANGUAGE'] || '') =~ /ja/
return [307, {"x-reproxy-url" => "/index.ja.html", "link" => link }, []]
else
return [307, {"x-reproxy-url" => "/index.en.html", "link" => link }, []]
end
when "/index.ja.html", "/index.en.html"
return [399, {"link" => link }, []]
end
return [399, {}, []]
end
file.dir: /srv/www/www.lowreal.net
# file.index: [ index.en.html ]
"cho45.stfuawsc.com:443":
access-log:
<<: *ACCESSLOG
path: /var/log/h2o/cho45.stfuawsc.com.access.log
listen:
port: 443
ssl:
certificate-file: /etc/letsencrypt/live/cho45.stfuawsc.com/fullchain.pem
key-file: /etc/letsencrypt/live/cho45.stfuawsc.com/privkey.pem
header.add: "Strict-Transport-Security: max-age=31536000"
header.add: "X-Content-Type-Options: nosniff"
header.add: "X-UA-Compatible: IE=Edge"
paths:
"/":
file.dir: /srv/www/cho45.stfuawsc.com
redirect:
status: 301
url: "/niro/"
"/niro/":
proxy.reverse.url: http://localhost:5001/niro/
proxy.preserve-host: ON
"/tmp":
mruby.handler: |
require "htpasswd.rb"
Htpasswd.new("/srv/www/.htpasswd", "Restricted")
file.dir: /srv/www/cho45.stfuawsc.com/tmp
lowreal.net のHTTP2/HTTPS 化を実施
全部 HTTPS 対応にしてリダイレクトかけるようにしました。
cho45.stfuawsc.com は既に HTTPS にしてありました。こちらは nginx に letsencrypt の証明書を入れた構成だったのですが、これを機に HTTPS のフロントを h2o にして、nginx は HTTP だけを配信するようにしました。これで HTTPS は HTTP2 に対応になりました。
このサイトは割と複雑な URL の rewrite ルールをしいているので、バックエンドのアプリケーションに直接ディスパッチせず、一旦 HTTPS でも nginx を経由するようにして設定し、徐々に h2o で全リクエストを処理するように置き換えていきました。www.lowreal.net も同時に HTTPS 対応しましたがそれぞれのドメインの構成は以下の通りです
- cho45.stfuawsc.com
- h2o → static file
- h2o → backend
- lowreal.net
- h2o → static file
- h2o → backend
- www.lowreal.net
- h2o → static file (accept-language を mruby で見てる)
証明書以外にやったこと
一応 mixed content を回避したり、push してみたりしたくていろいろやりました
- はてなスターのスキーム変更
- スター画像のホスト元 (フォトライフ) のドメイン変更 (cdn-akナントカに)
- tumblr のスキーム変更
- facebook ボタン廃止
- twitter ボタンのスキーム変更
- Amazon 画像のドメイン変更 (過去に遡ってエントリ内の画像URLを変更)
- バックエンドアプリケーション (ブログシステム) へ Link: rel=preload を簡単に吐ける機能を追加
h2o での server push の確認方法
h2o は server push したコンテンツのヘッダに x-http2-push: pushed を含めてくれるので、ちゃんと push されてるか確認する一番簡単な方法はこれを見ることっぽいです。
nginx の rewrite ルールっぽく h2o の mruby でリクエストの rewrite を行う
このサイトのHTTPS化にあたって nginx で書いていた rewrite のルールを h2o の mruby で処理するように変える必要がありました。
しかしベタで書くのも面倒なので、そこそこ機械的な置換ですむような書きかたができるようなライブラリを書いてしのぎました。
mruby.handler
paths:
"/":
proxy.reverse.url: http://localhost:5001
proxy.preserve-host: ON
mruby.handler: |
require "/srv/www/rewrite_rules.rb"
lambda do |env|
RewriteRules.rewrite(env) do
rewrite '/favicon.ico', '/images/favicon.ico', :break
rewrite '/apple-touch-icon.png', '/images/apple-touch-icon.png', :break
rewrite %r{^/2005/colors-canvas\.xhtml$}, '/2005/colors-canvas.html', :permanent
rewrite %r{^/2005/colors-canvas$}, '/2005/colors-canvas.html', :permanent
rewrite %r{^/logs/latest$}, '/', :permanent
rewrite %r{^/logs/latest.rdf$}, '/feed', :permanent
rewrite %r{^/logs/latest.atom$}, '/feed', :permanent
rewrite %r{^/latest\.rdf$}, '/feed', :permanent
rewrite %r{^/blog/index\.(rdf|atom)$}, '/feed', :permanent
rewrite %r{^/logs(/.+?)(\.(rdf|atom))$}, '/feed', :permanent
rewrite %r{^/logs(/.+?)(\.(x?html|xml|txt))?$}, '\1', :permanent
rewrite %r{^/blog(/.+?)(\.(x?html|xml|txt))?$}, '\1', :permanent
rewrite %r{^/photo$}, '/photo/', :permanent
rewrite %r{^/(\d\d\d\d/\d\d(/\d\d)?)$}, '/\1/', :permanent
rewrite %r{^/\d\d\d\d/$}, '/', :redirect
rewrite %r{^/view-img(/.+?)$}, '\1', :permanent
end
end h2o の path はディレクトリの指定しかできないみたいなので (自動的に末尾スラッシュがついたりする)、rewrite で同時にパス決め打ちのディスパッチも行っています。
rewrite_rules.rb
class RewriteRules
class RewriteRulesException < Exception
attr_reader :response
def initialize(response)
@response = response
end
end
attr_reader :env
attr_reader :path
def self.rewrite(env, &block)
self.new(env).run(&block)
end
def initialize(env, &block)
@env = env
@path_orig = "#{env['SCRIPT_NAME']}#{env['PATH_INFO']}"
@path = @path_orig.dup
end
def run(&block)
begin
instance_eval(&block)
if @path != @path_orig
return [ 307, { 'x-reproxy-url' => path }, [ ] ]
else
return [ 399, {}, [ ] ]
end
rescue RewriteRulesException => e
return e.response
end
end
def rewrite(regexp, replace, flag=:continue)
if @path.gsub!(regexp, replace)
case flag
when :redirect
raise RewriteRulesException.new([ 302, { 'Location' => @path }, [ ] ])
when :permanent
raise RewriteRulesException.new([ 301, { 'Location' => @path }, [ ] ])
when :break
raise RewriteRulesException.new([ 307, { 'x-reproxy-url' => @path }, [ ] ])
when :continue
# nothing
else
raise "unsupported flag: #{flag}"
end
end
end
end
require 'rspec'
describe RewriteRules do
it "should treat :permanent as 302 redirect" do
env = {
'PATH_INFO' => '/logs/latest'
}
expect(RewriteRules.rewrite(env) {
rewrite %r{^/logs/latest$}, '/', :permanent
rewrite %r{^/logs(/.+?)(\.(x?html|xml|txt))?$}, '\1', :permanent
rewrite %r{^/foobar/}, '/bazbaz/'
}).to eq( [301, {"Location"=>"/"}, []])
end
it "should treat :redirect as 301 redirect" do
env = {
'PATH_INFO' => '/logs/piyo.html'
}
expect(RewriteRules.rewrite(env) {
rewrite %r{^/logs/latest$}, '/', :permanent
rewrite %r{^/logs(/.+?)(\.(x?html|xml|txt))?$}, '\1', :redirect
rewrite %r{^/foobar/}, '/bazbaz/'
}).to eq([302, {"Location"=>"/piyo"}, []])
end
it "should treat as internal proxy by default" do
env = {
'PATH_INFO' => '/foobar/baz'
}
expect(RewriteRules.rewrite(env) {
rewrite %r{^/logs/latest$}, '/', :permanent
rewrite %r{^/logs(/.+?)(\.(x?html|xml|txt))?$}, '\1', :permanent
rewrite %r{^/foobar/}, '/bazbaz/'
}).to eq([307, {"x-reproxy-url"=>"/bazbaz/baz"}, []])
end
it "can write logic in dsl" do
env = {
'PATH_INFO' => '/foobar/baz',
'XXX' => true,
}
expect(RewriteRules.rewrite(env) {
if env['XXX']
rewrite %r{^/foobar/}, '/bazbaz/'
end
}).to eq([307, {"x-reproxy-url"=>"/bazbaz/baz"}, []])
env = {
'PATH_INFO' => '/foobar/baz',
'XXX' => false
}
expect(RewriteRules.rewrite(env) {
if env['XXX']
rewrite %r{^/foobar/}, '/bazbaz/'
end
}).to eq([399, {}, []])
end
end ところで
rewrite ルールが ruby で書けるということは、すなわち自由にテスト可能であることを意味します。Apache の RewriteRule や nginx の rewrite をテストするのはかなり面倒なので、かなり強力で嬉しい感じがします。
「みいつけた」がおもしろい
NHK Eテレの番組はそれぞれ対象年齢が設定されていて、「いないいないばぁ」は0〜2歳、「おかあさんといっしょ」は2〜4歳、「みいつけた」は4〜5歳あたりらしい。
うちの子供はまだ2歳になっていないので「みいつけた」はまだ早いことになるが、見せてみると特に嫌がらずに見ていたりする (オフロスキーは嫌いみたいだけど)。「いしゅ、いしゅ」と言うぐらいには見る。
「いないいないばぁ」と「おかあさんといっしょ」は大人が見ても面白いとはいえない感じだけど (というか無駄に元気がよくて、疲れる)、「みいつけた」は大人が見てもゆるくて面白い。
- 害になるような人物が出てこない
- 不愉快ができことが起こらない
- 現実にはありえない日常を過ごす
- 説教臭い内容ではない
あたりを考えてみると、日常系アニメと似たようなジャンルに思える。
コッシー
椅子のキャラクターでコッシーというのがいて、スタジオ内で結構自由に動くんだけど、どうやって動いているのかさっぱりわからない。謎の技術。ひっくり返るシーンとかもあって、足の裏が見えたりするけど、車輪がついていたりするようにも見えない。謎
びっくりしたのが声をあててる声優で、高橋茂雄 (サバンナ) とクレジットされている。ブラジルの皆さんじゃないほうの人・ザッカーバーグに似てるほうの人だけど、アメトークとかにしか出てないイメージだったのでびっくりした。エンディングの作詞とかもやってて余計びっくりする。全然違和感がない (喋る椅子に対して違和感もクソもない気もするけど) し聞きやすい声質だし、謎の才能。
歌の作曲が星野源だったり、この番組に限らないけどEテレの子供向け番組は凝ったキャスティングされていることがあって面白い。「おかあさんといっしょ」でもつんく作曲の歌がちょいちょいある。
LTSpice で伝送線路トランス
「伝送線路トランス」という言葉が一般的な用語かどうかよくわからないのですが、トロイダル・コア活用百科ではこのような用語になっていました。一応 transmission-line transformer で検索すると使われており、Amidon のドキュメントでも出てきますが……
それはともかく、伝送線路トランスは一見奇妙な感じがして面白いです。とりあえず LTSpice で等価回路を書いて試してみました。
位相反転回路
GND のとりかたが入力側と出力側で逆なので位相が反転します。
この回路、L1 と L2 が結合しているため、これらで1つのコモンモードチョークとして働いてアイソレーションされるために位相反転ができているのですが、なんとかく不思議な感じがします。
自分の中では「コモンモードチョーク」はノーマルモードに影響を与えないイメージなのですが、「コモンモードチョーク」があるおかげでノーマルモードの位相反転ができているのです。ぱっと見だと結線されていない GND 経由 の電流 (すなわちコモンモード) が阻止されることを強くイメージする必要があります。
ところで、結合係数を減らすとどうなるか見てみます。
これはつまりコモンモードチョークとしての機能が失われている場合です。高い結合が得られていない限り機能しなくなくなることがわかりました。
インピーダンス変換器
1:4 のインピーダンス変換器もシミュレーションしてみました。
純伝送線路トランス
伝送線路トランスを2つ使い、入力を並列、出力を直列にすることで、出力電圧を倍にできる (出力電流は半分) という回路です。単純に、それぞれの入出力がアイソレーションされていると考えると動きそうだなというイメージはできます。
が、やはり一見奇妙に見えます。
伝送線路的トランス
入力信号にトランスの出力を重合する形で出力電圧を倍にする回路です。広域が犠牲になる代わりに純伝送線路トランスよりコアの数を減らせるメリットがあります。実際の回路だとこちらのほうが良く見ます。
ぱっと見だと完全に意味不明ですが「重ねあわせる」ことを意識すると理解できるようなできないような感じがします。
通常のトランスとの違い
通常のトランスは、一旦電気エネルギーを磁気エネルギーに変換して再度電気エネルギーに変換するという動作をします。なので、高い結合係数と低いコア損失を同時に実現できなければいけません。
伝送線路トランスはコモンモードのアイソレーションによって実現されており、磁気エネルギーはメインのエネルギー伝達に使われていないので、結合係数が高ければコア損失が多少あっても問題になりません。

















