暮らしの技術

暮らしを豊かにする技術や、特に暮らしを豊かにしない技術があります

Google App Engine で Parse.com を看取る

ところで皆さんは1年前の今日,2016年の1月の28日に何が起きたかを覚えていますか? 私は覚えています.そう,Parse.com が1年後にサービス終了する,と宣言したあの日です.*1

ということで死にゆく Parse.com への最後の手向けとして parse-shutdown-monitor というサービスを作りました.斎場とも言えます.*2

f:id:side_tana:20170128033635p:plain
Parse Shutdown Monitor

いわゆる外形監視になるんですかね? そういう意味では普通の外形監視使ってもよかったのですが,今回は Google App Engine氏に喪主をお願いしました.

監視しているのは

  • ParseObject の取得と書き込み
  • Query の実行
  • User のSign-in
  • File の取得/アップロード
  • ParseConfig の 取得
  • Hosting で設置した静的コンテンツ
  • CloudCode の Hello, World
  • Jobs による定期実行

の 8 種類 10 項目です.

CloudCodeって言うのは Google App Engine とか Heroku みたいな PaaS として使える機能ですね*3.Jobs は Parse.com 上で動作する cron というか,Google App Engine の cron を使ったことがある人にはおよそそのままの理解で良いんですが,CloudCodeとして登録した関数を定期的に実行してくれる君です.

基本的にはGoogle App Engine の urlfetch api を使って, Parse.com の REST API を叩き,帰ってくる http のステータスコードを監視する,というようなことをしています.Jobs については直接監視できないので, Parse.com の CloudCode 実行してる環境から毎分アウトバウンドリクエストを生成して,Google App Engine 側で受けとって保存,さらに Google App Engine の cron で新しいレコードが作成されていることを毎分監視し続ける,みたいなアーキテクチャになっています.*4

作ってた時の面白エピソードとしては,移行先として公開されている Parse.com のオープンソース実装であるところの parse-server にはJobs に相当する機能が無く,また公式ドキュメントは全て parse-server を基準としたものに置き換わっているため, 結果としてドキュメントがない状態で Jobs に関するあれこれをしなくてはいけない,みたいなことがあったこととかですね.

開発環境について

なんかいろいろやってて結構便利に開発出来たんですけど改めて書きます.

*1:先日1月30日に終了するという情報更新がありました.

*2:ひょっとしたら日本で最後にParseAppの新規作成をしたのは俺なのではないか,もしかしたら世界中で最後かもしれない.世界一短命なParseAppがParseの最期を見守るのだ

*3:DBへの書き込みと取得を繰り替えし実施する必要がある場合,USにあるParseのサーバとJPのアプリやサーバがちまちまやりとりすると累計のトランザクションタイムが10秒を軽く超えていくので,こういったDBに近いところで処理出来る環境は大層重宝するわけです

*4:この記事書き始めた時点では Jobs からのリクエストは記録だけだったんですけど,それはだめだよねってことでさっき監視を追加しました.




君は異体字セレクタを見たことがあるか

node v6.2.0

> var codePoints = [10548, 65039]
undefined
> var s1 = String.fromCharCode(...codePoints)
undefined
> var s2 = codePoints.map((p)=>{return String.fromCharCode(p)}).join()
undefined
> s1
'⤴️'
> s2
'⤴,️'
> s1 === s2
false
> s1.length
2
> s2.length
3
> s2.codePointAt(2)
> 44

65039異体字セレクタ (VS16) なので,これが単体で登場するというのはおかしい.

String.fromCharCode()65039 だけを与えると 44 が前に追加されて,それと 10548 を連結するので3 文字になる.ということらしい.

この 44 がどこから来たのかもうちょっと追ってみたいけど明日新幹線乗れなくなりそうなのでこの辺でやめておこうという感じ.

コメントで指摘していただいたとおり.上記のコードで .join() した時のデリミタとして , ,コードポイントでいうと 44 が入るは Array.prototype.join() の仕様でした.ということで

> var s2 = codePoints.map((p) => {return String.fromCharCode(p)}).join('')
undefined
> s2
'⤴️'

とすることで期待する挙動になりました! id:t_motooka さんありがとうございました!

参考

Variant form (Unicode) - Wikipedia

Miscellaneous Symbols and Arrows - Wikipedia

このページの一番下に,このブロックで異体字セレクタが用意されている記号について触れられている.

http://www.unicode.org/Public/UNIDATA/StandardizedVariants.txt

これは試験に出るので全部暗記しましょう.

3点リーダ偏り問題、あるいは「そしてまた。 次の縦書きがはじまるのです。 」

f:id:side_tana:20161020233436p:plain*1

ポプテピピックよくて,とくに「竹書房⁉︎ 破壊したはずでは……」が好きで,潰したはずのバグが発見されたときのissueなんかで貼っつけて遊んだりしてます.破壊したはずなのは竹書房ではないので,吹き出しの中身を適当に変更したりします.とはいえ業務中にそういったことをするわけにはいきませんから,昼休みなんかにやります.すると昼ご飯を食べる時間がなくなってしまいます.困りました.由々しき事態です.というわけで最初のスクリーンショットのようなツールを作りました.公開の予定はありません.

さて本題.

SVGにおける縦書きサポート

writing-mode: tb; でいけます.tb 古い記法でしょ vertical-rl では? とお思いになられるかと思いますが SVG1 では tb みたいです.
developer.mozilla.org

SVGにおける縦書きサポートの課題

縦書き界隈でしばしばあるのが,「この記号ちょっとずらしたい」みたいな需要で,具体的には上のスクリーンショットでいう三点リーダとか.

伝統的な縦書き技法に「一文字一文字を真心込めて SPAN でくるみ配置していく」みたいなのがあるんですが,それに近いことを部分的にしたくなるわけです.SVG の TEXT には 部分テキストを表す TSPAN が定義されていますが,変形するための transform 属性は定義されていません.実際にAdobe Illustrator なんかでひと文字だけ回転させたアートボードをSVGとして吐き出すとこんな具合です.

f:id:side_tana:20161021013203p:plain
これを書き出しました.獰悪の獰の字だけ時計回りに90度回転しています.なぜこんな分かりにくい文字を選んだのか.

f:id:side_tana:20161021013338p:plain
「という人間中で一番」のところで TSPAN が一度閉じられ,さらに TEXT も閉じられ,あたらしい TEXT では transform にrotateが指定されていて,そのあとに最後の「悪な種族であったそうだ」だけが入った TEXT 要素があるのがわかると思います.どんな文章が来るかわからず,動的に制御したい場合,このような仕様だとなかなかやっかいです.

つらいですね.なんとかなりたい.なんとかなりませんか? 似た問題に「2桁数字横並び配置問題」というのがあります.

f:id:side_tana:20161020233830p:plain
*2

縦書きだ,漢数字を使えといった声もあるかと思います.私もそう思う.ちなみにここからの派生コンボで「一桁の数字も縦にしたいしその場合はセンタリングで」に繋げることができます.

あ,あと普通に忘れてたんですけど TEXT 自動改行(?) 表示スペース似合わせていい感じに表示するみたいなのないっぽくて,今回は気合いでTSPAN並べていきました.ましな方法知りたい.

書き出し時の問題

こういったツールの場合画像をダウンロードしたくなります.戦略を考えてみますと

1. SVG を HTML の IMG で読み込む
2. canvas 要素を作り drawImage で上記の IMG を読み込む
3. a 要素を作り, href 属性に canvas.toDataURL() で吐いた文字列を指定する
4. a 要素に加工した上でクリックイベントを送る

みたいな感じになります.簡単そうですね.でも実際にやるとハマる.

ハマりどころ

imageエレメントで外部リソースを指定しているとimgタグに食わせた場合に表示されない

なんかどうせCORSまわりでcanvasが汚染されたんでしょとかいって雑にdata URI schemaでデータを埋め込んだら回避できた.今回,オリジンは同じだったので冷静に考えるとおかしい.imgのsrcにsvgを指定した場合はimageエレメントのロードやってくれないんだったっけ*3
f:id:side_tana:20161021005745p:plain
SVGの xlinkHref に外部のリソースを指定した場合
f:id:side_tana:20161021005715p:plain 
SVGの xlinkHref にdata URI を指定した場合

font が反映されない

imgがフォントの反映してくれない問題.今回それっぽさを出すためにちゃんとアンチック体を使っているのですが*4,上記の方法で吐き出した画像だとフォント指定が無視されている.画像の時と同じパターン? SVGにフォント埋め込む方法あるのかな,あったら解決できそう.

戦略を変える

canvgによる回避

canvgってのはsvgをパースしてcanvasゴリゴリ書けばええやんけっていう男気溢れるプロジェクト.
f:id:side_tana:20161021010147p:plain
フォントはちゃんと反映されてるっぽいですが縦書きまわりが破滅してますね,これどうなってるんだろ,ちょっと興味出てきた.

大変ですね

大変ですね.ダウンロードの件はスクリーンショットでいいと思います.はやいしノーコスト.

*1:破壊してません

*2:10 を水平に並べたいという自然な欲求が沸き立ちます

*3:この文章普通に意味わかんないですね.SVGには外部画像を読み込む IMAGE 要素が用意されていて,HTML で画像表示に使われる IMG 要素とは名前が違います

*4:漢字がゴシックでかなが明朝体のやつ.一番最初のスクリーンショットをみてくれ!

influxdb へ時系列データを突っ込んで chronograf で可視化する

時系列データをうまいこと取り回す方法をいろいろと検討していて,今日はinfluxdbとchronografを試してた.これは2010年の為替の様子です.

f:id:side_tana:20160925030341p:plain

dbの中身はこんなクエリでこんな結果が返ってくる状況

> select MEAN("OpenBid") from candle where '2016-09-23T00:00:00+09:00' < time AND time < '2016-09-24T00:00:00+09:00' GROUP BY "instrument", time(1d)
name: candle
tags: instrument=CAD_JPY
time			mean
----			----
2016-09-22T00:00:00Z
2016-09-23T00:00:00Z	77.28651111988425

name: candle
tags: instrument=EUR_JPY
time			mean
----			----
2016-09-22T00:00:00Z
2016-09-23T00:00:00Z	113.13053859380965

name: candle
tags: instrument=USD_JPY
time			mean
----			----
2016-09-22T00:00:00Z
2016-09-23T00:00:00Z	100.96978221722053

なんか秒間2000〜4000データポイントぐらいのペースで打ち込んでいたのだけれど(過去のデータなので,最短5秒間隔で保存されたものを6時間分ぐらいまとめてbulkインサートしてる),4GB/2コアのVMを2013年のMacBookPro(物理2コア) で動かしてると結構な勢いでoom-killerが走って,基本的にはSystemdによって復活するのだけれど,その間のデータを取り逃がしたりしがちなので大変.

今回はメトリクスの収集ツールというよりは時系列データの学習と検証につかうデータセットを作るために使いたいと思っていて,aggregationが強力なので便利そう〜っとおもってガッとやってみたけれど,本当にこんなことでいいのか,という気持ちになってきた.

というか,そういう目的なので RQ とか CQ 使っていい感じにデータを減らしとくとかもやらないし,もったいないな〜って気持ちになってきています.