backstage

合唱音源の新着情報の舞台裏

ニンジャスレイヤーと2038年問題

f:id:s2terminal:20160615013707p:plain

ニンジャスレイヤー第3部最終章の予告が行われました。 それまでのエピソードからも日付を示唆する文言が度々含まれていましたが、最終章が 2038年1月18日 という日付になることが明言されました。

ninjaheads.hatenablog.jp

アガメムノンは2038年1月18日深夜に月面メガトリイ基地でアルゴス・システムのリブートを行う。インターネット再定義のためにアルゴスのタイピング速度が一時的に減じるこの夜だけが、ハッキングで攻撃しうる唯一のチャンスである。アマクダリが再定義を完了させれば、Y2K規模の災厄が再び地表を覆うだろう。その後、アマクダリが全てを支配するのだ。

2038年1月18日深夜にY2Kと同等の災厄が起きる とあります。

これは、「Y2K(2000年問題)」と「2038年問題」という、現実に起こりうる2つの年問題が元ネタになっています。

2000年問題

西暦の下2桁を使って年月を判定するシステムを組んでいると、1999年から2000年になった瞬間に、コンピュータは2000年を1900年を勘違いしてしまい、誤動作してしまうのではないか?という問題です。Y2Kとも呼ばれます。

実際の年月 データ コンピュータの認識
1999年11月 9911 1999年11月
1999年12月 9912 1999年12月
2000年1月 0001 1900年01月

くわしくは:2000年問題 - Wikipedia

ニンジャスレイヤーにおける2000年問題

西暦二千年を迎えた瞬間、世界中でUNIXが多数爆発し、優秀なUNIX技術者が大勢死んだ

(ニンジャスレイヤー第3部「ダークサイド・オブ・ザ・ムーン」より)

限られたIPと違法プロキシサーバ基地を巡り、暗黒メガコーポ群主導による論理物理両面での電子戦争が勃発した

(ニンジャスレイヤー第2部「キョート・ヘル・オン・アース」より)

ニンジャスレイヤーは近未来の日本を舞台としており、Y2Kは過去の出来事として語られます。 しかし、現実の世界とは異なる点があります。

  • ニンジャスレイヤーの世界では、2000年時点でIPv4枯渇問題が解決されていないようで、 固定IPを持つプロキシサーバ等は貴重な資源である
  • ニンジャスレイヤーにおけるコンピュータは、バッファオーバーフロー等の不具合が起きると 物理的に爆発する

そのため、以下のように現実世界における2000年問題とは大きく異なる結末を迎えます。

  1. 2000年問題世界中のUNIXが爆発
  2. 爆発の影響でUNIX技術者が多数犠牲となる
  3. 技術者が足りず、IPアドレス枯渇が深刻になる
  4. 残されたIP資源を巡って 戦争が勃発

この戦争の影響で日本は電子的に鎖国、独自の発展を遂げることになります。

何度読んでもこの設定を考えた作者は天才だと思います。

2038年問題

2000年問題と似たような問題なのですが、エンジニア以外には理解しづらく、影響範囲が大きいのが、この2038年問題です。

UNIXでは、UNIXTIMEというデータが広く使われています。 UNIXTIMEとは 1970年1月1日からの経過秒数で時刻を表したもの です。

たとえば、2016年6月14日23時30分10秒のUNIXTIMEは、「1465914610」となります。

$ ruby -e 'require "time";puts Time.parse("2016-06-14 23:30:10").to_i'
1465914610

現代のコンピュータは性能が良いので、とても大きな値を取り扱うことができます。 しかし過去のコンピュータでは、このUNIXTIMEを 符号付き32bit整数 で取り扱っていました。

この「符号付き32bit整数」というのは、約21億5千万が最大値となります。 21億5千万というのは大きな数字に見えますが、21億5千万秒は 約68年 です。

そのため、1970年1月1日から約21億5千万秒後、 2038年1月19日3時14分8秒以降、コンピュータが時刻を正しく扱うことができなくなる というのが、2038年問題です。

実際に、先ほどのUNIXTIMEを31桁2進数(符号付き32bit整数の仮数部)で表すと、以下のようになります。

$ ruby -e 'require "time";puts sprintf("%31b", Time.parse("2016-06-14 23:30:10").to_i)'
1010111011000000001010011110010

$ ruby -e 'require "time";puts sprintf("%31b", Time.parse("2038-01-19 12:14:06").to_i)'
1111111111111111111111111111110
$ ruby -e 'require "time";puts sprintf("%31b", Time.parse("2038-01-19 12:14:07").to_i)'
1111111111111111111111111111111
$ ruby -e 'require "time";puts sprintf("%31b", Time.parse("2038-01-19 12:14:08").to_i)'
10000000000000000000000000000000
$ ruby -e 'require "time";puts sprintf("%31b", Time.parse("2038-01-19 12:14:09").to_i)'
10000000000000000000000000000001
$ ruby -e 'require "time";puts sprintf("%31b", Time.parse("2038-01-19 12:14:10").to_i)'
10000000000000000000000000000010

12時14分8秒に桁があふれたのがわかると思います。 (グリニッジ標準時で午前3時14分8秒なので、日本時間では12時となる)

2038年問題自体は、現実世界でも待ち受けている、私たちが立ち向かわなければならない問題です。

くわしくは:2038年問題 - Wikipedia

ニンジャスレイヤーにおける2038年問題

世界中のUNIXはオーバーフローを起こし、Y2Kにも比肩する爆発と災厄を引き起こすはずです

(ニンジャスレイヤー第3部「スルー・ザ・ゴールデン・レーン」より)

すでに 2038年問題の起きるまさにそのタイミングで、Y2K規模の爆発が起こる であろう事が劇中で指摘されています。

しかしこれが2038年問題による脆弱性なのか、敵組織による何らかの策略により故意に引き起こされる物であるのかはハッキリしていません。

確実なのは UNIXが爆発する ということです。

ルートDNSサーバ

2038年問題について語られると同時に、以下の様なセリフも見られます。

ヒエラルキー最上位に位置する神秘的なUNIXサーバがかつて地球全土に13個存在し、幾つかが滅びたという。その残されたひとつがジグラットなのだ

(ニンジャスレイヤー第3部「スルー・ザ・ゴールデン・レーン」より)

この「ヒエラルキー最上位に位置する神秘的なUNIXサーバ」とは、現実における ルートDNSサーバ が元ネタと思われます。 (ジグラットとはカスミガセキ・ジグラットのこと。ネオサイタマ市役所等を取り込んだ巨大建造物)

実際にルートDNSサーバというのは世界に13個のみ存在し、それを構成するうちのひとつは霞ヶ関から数kmの地点である東京大学にあるそうです。(※実際には地理冗長されているので、サーバ13個=13箇所ではないそうです)

ニンジャスレイヤー第3部の敵組織は、世界中のインターネットを支配するカギを握る何らかのサーバを持っており、2038年問題のタイミングを狙ってなんかするようです。

備えよう。

まとめ

  • IPv6移行は大切
  • 64bit整数は偉大
  • UNIXは爆発する

Pebble Timeのウォッチフェイスを作ってみた

先日Pebble Timeを購入しました。

f:id:s2terminal:20160612165635j:plain:w250

Microsoft BandやAppleWatch、AndroidWearも迷ったのですが、以下の理由でPebbleTimeを選びました。

Pebble Timeのソフトウェア開発

Pebbleのアプリとウォッチフェイスは、CloudPebbleを使えばブラウザ上で簡単に作ることができます。

最低限の機能を抑えたIDEエミュレータがブラウザ上で動作するので、SDKのインストールなどをせずともすぐに開発を始めることができます。 (SDKも公開されているので、UNIX上で開発もできるようです)

言語はCとJavaScriptが選べますが、JavaScriptはできる事が少ないようなのでC言語で開発します。

ウォッチフェイスの開発

ためしに、現在時刻としてUNIXTIMEを表示する簡単なウォッチフェイスを作ってみました。

公式のドキュメントが充実しており、チュートリアルに沿って適当にコードを書いていけば時刻を表示するウォッチフェイスを作ることができます。

developer.pebble.com

これに手を加えて行けば、簡単に開発を進めることができます。

また、時刻以外にもPebble側の情報にアクセスするためのAPIが用意されており、ドキュメントも充実しております。

たとえば歩数を取得するには以下のようにします。

health_service_sum_today(HealthMetricStepCount);

developer.pebble.com

CloudPebbleはGitHubと連携することができ、コードをGitHubで公開することができます。 今回作った物は以下です。

github.com

実際に書いたのはmain.cのみで、こんな感じです。

ビルド

COMPILATIONから、エミュレータか実機のどちらにビルドするかを選ぶことができます。

エミュレータでの動作はこんな感じです。

f:id:s2terminal:20160612165056p:plain

実機の方はすこし時間がかかりますが、実機ビルドが完了するとPebble本体がぶるぶる震えますので、他事をしながら適当に待ちましょう。 この 「ビルド完了すると通知が来る」 って一見当たり前のような気もしますが、開発者としてはかなり快適です。

なお、「COMPILATION→PHONE→INSTALL AND RUN」でビルドするとPreparingのまま数十分待ってもなぜかビルドできないことがありました。 その時はSOURCE FILESから「SAVE, BUILD, INSTALL AND RUN」を押すとビルドできました。

まとめ

簡単にウォッチフェイスを開発することができました。

Twitterのフォロワー数とかRT数、ブログのPVのような、 毎日確認したいKPIをウォッチフェイスに表示させる ようにしたらアツいと思うのですが、認証とか非同期処理とか面倒くさいのでまた今度。

【機械学習】AzureMLで合唱音楽レコメンドシステムTwitter Librarian作ってみた

Microsoft Azure Machine Learning(Azure ML)を使って、

以上を組み合わせて、RTを評点としてAzure Match Box Recommender モジュールに突っ込むことで、おすすめのツイートを取得するシステムTwitter Librarianを作りました。

f:id:s2terminal:20160410194651p:plain

現在はサービスとして公開はしておりません。 ローカルで調整中の段階ですが、 約3,000件のリツイート情報、約800件のツイート投稿データ、約1,500件のツイート詳細データ(タグ情報)を用いることで、指定したTwitterユーザに対するおすすめツイートを取得できるようになっています。

作曲者や演奏者情報がツイート詳細データとして入力されて学習に用いられるので、好きな作曲家や合唱団の傾向が反映されるのではないかと思います。

APIを叩くソースコード

f:id:s2terminal:20160410203902p:plain

Azure ML上でWeb APIにデプロイすると C#PythonR言語の3種類のクライアント用サンプルコードを提供してもらえます。 しかしRubyは無かったので自前で書きました。

その他の技術的な詳細は多分そのうち書きます。

課題

f:id:s2terminal:20160410200810p:plain

RTが多いツイートのレコメンドに偏ってしまう

普段2,3RTしかされないアカウントの中に極稀に70RTとかの投稿があるので、誰に対してもそういう特定のツイートばかりレコメンドされてしまいます。言われてみればそうなのですが、人によって様々な結果が返ってこないと面白くありません。

知らない曲を発掘してくれるようなシステムでないとあまり意味がありません。 RT数が少ないツイートに対して高い評点を付けるよう調整することで対策を予定しています。

データを増やしたい

現状TwitterのRT情報しか取れていません。 いいね(お気に入り)も取りたいのですが、Twitter APIが存在しません。

Facebookのお気に入り/シェア情報も、数が増えてきたら付け加えようと思います。

料金が難解

azure.microsoft.com

上記によると、たとえばスタジオ実験時間で時間割り102円?とあります。 実験時間が何を指しているのか不明ですが万が一実験しっぱなしだったとして1日2,400円??1ヶ月で7万5千円???となると恐ろしいです。iPadが買えます。

しばらく運用してみないとよく分かりません。 課金アラートを厳重に設定して、あとは様子を見てみます。

blogs.msdn.microsoft.com

参考文献

追記

喋りました↓

www.slideshare.net

AMP対応に必要なschema.org構造化データ

先週、以下のような記事を書きました。

s2terminal.hatenablog.com

上記の対応をして、Fetch as Googleでラブコールを送って待つこと5日。 下記のお返事が届きました。

f:id:s2terminal:20160327173936p:plain

AMP ページへの必須構造化データの追加について

http://合唱音源の新着情報.com/ の所有者様

お客様の AMP ページの一部に、AMP 関連機能を搭載した Google 検索結果への表示に必要な構造化データがないことを Google のシステムが検出しました。以下のレポートにはこうしたエラー(およびその他のエラー)が発生しているページの例が記載されています。

どうやらAMPで何かエラーになってしまったようです。 とりあえず「スタイルシートもう少しマジメに書けよ」みたいなエラーではないようで少し安心です。

Google Search Consoleで確認してみると、下記のエラーが出ていました。

f:id:s2terminal:20160327174000p:plain

どうやらAMP対応には、対応したテンプレートを用意するだけでなく schema.org構造化データ対応によるリッチスニペット有効化 が必要なようです。

詳しい仕様などは下記で紹介されていました。

www.suzukikenichi.com

Google公式のドキュメントにロゴの仕様などもありました。

https://developers.google.com/structured-data/carousels/top-stories

ロゴも必須ですが、仕様に対応するようなロゴ画像は持っていないのでテキストを適当にpng化して貼り付けてその場をしのぎます。

RailsでAMP用schema.org構造化データ対応

  • 110文字以下の 見出し
  • 画像
  • 投稿者情報
  • 著者情報
  • 投稿日
  • 更新日

上記データをschema.orgに沿った形で表示する必要があるようです。

こんな感じでモデルのインスタンスメソッドJSON情報を定義して

  # AMP用構造化データ
  def schema_org_news_article
    {
      "@context": "http://schema.org",
      "@type":    "NewsArticle",
      "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": self.url_for,
      },
      "headline":       self.title(110),
      "description":    self.tweet_text,
      "image":          self.thumbnail_json,
      "datePublished":  self.created_at.iso8601,
      "dateModified":   self.updated_at.iso8601,
      "publisher": {
        "@type": "Organization",
        "name":  "合唱音源の新着情報",
        "logo":  self.logo_json,
      },
      "author": {
        "@type": "Person",
        "name":  "suzuki.sh",
      },
    }
  end

テンプレートで呼び出しました。

    <script type="application/ld+json">
      <%= @tweet.schema_org_news_article.to_json.html_safe %>
    </script>

構造化データテストツールで確認します。

f:id:s2terminal:20160327174025p:plain

「問題ありません」と表示されたので、これでOKのはずです。

クロールエラーと異なり、エラーが解決したことを報告する機能は無いようなので、Fetch as Googleを送って気長に待ちます。

上手く行っていれば、数日の間にGoogle Search Console上に何らかの反応があると思います。

【Rails】AMP(Accelerated Mobile Pages)に合唱音源の新着情報.comを無理矢理対応させる

昨年、Google等によってAMP (Accelerated Mobile Pages)というプロジェクトが公開されました。

www.suzukikenichi.com

GoogleにWebページの情報をキャッシュさせて検索結果と一緒に返すことで、検索結果表示を高速化するというモノです。 特に合唱音源の新着情報.comのような弱小サーバ上に適当設定で動いており3ヶ月に1度くらい定期的にサービスダウンするようなWebサイトの管理者にとっては、Googleの強固なサーバ上で高速にキャッシュを返してくれる仕組みが提供されるのは朗報です。

以下に日本語の公式情報もあります。

googledevjp.blogspot.jp

詳細は上記のブログ等の方が詳しいので説明は置いておいて、さっそく対応してみたいと思いました。

前提条件

$ rails --version
Rails 4.2.1

http://合唱音源の新着情報.com/request/sound/615 というURLに対して
http://合唱音源の新着情報.com/request/sound/615.amp というURLでAMP版のテンプレートを表示させようと思います。

ampテンプレート追加対応

まず、Railsで .ampというテンプレートファイルを読み込むようにします。

コントローラに下記追加

    respond_to do |format|
      format.html
      format.amp{
        request.format = :amp
      }
    end

config/initializers/mime_types.rbに下記追加

Mime::Type.register "text/html", :amp

これで、sound.html.erbという普段使っているテンプレートファイルに対して、新たにsound.amp.erbというファイルでamp版テンプレートを表示できるようになりました。

AMPの仕様に沿ってコーディング

AMPはだいたい通常のHTMLに準拠していますが、ところどころ仕様が異なります。

まずはGitHubからサンプルテンプレートを持ってきて、なにも考えずにsound.amp.erbに貼り付けてみました。

https://github.com/ampproject/amphtml/tree/master/examples

GoogleChromeに搭載されているチェックツールを使って、文法をチェックできる ようなので、このツールが吐き出すログを見ながらコーディングしていきます。

URLの末尾に「#development=1」と付けて開発者ツールを起動すると、デバッグ情報が表示されます。

f:id:s2terminal:20160321233645p:plain

コンソール上に「AMP validation successful.」と出れば成功です。

さてここから本来のページにあるコンテンツを持って来ます。 適当にコピペしてChromeのチェックツールを調べると色々とエラー箇所を教えてくれますので、それに沿ってコーディングしていきます。

合唱音源の新着情報は大した情報のないペラペラなWebページですので、簡単に移植できるはずです。

twitterを埋め込む

AMPではJavaScriptを使えないようですが、サンプルテンプレートのtwitter.amp.htmlにある通り、AMPは <amp-twitter> という独自タグによるtwitter埋め込みをサポートしています。 合唱音源の新着情報はtwitterに過度に依存したWebサービスであるため、これを使わない手は無さそうです。

<amp-twitter width=390 height=330 layout="responsive" data-tweetid=<%= @tweet.tweet_id %>></amp-twitter>

これだけの記述でtwitterを埋め込むことができます。

CSSを埋め込む

AMPは外部CSSを使うことができず、テンプレート内 <style> タグに記述しなければなりません。 ガラケーを思い出すような仕様です。

AssetPipelineを使っているので、コンパイル済みのアセットファイルの中身だけをうまくテンプレート内に吐き出したかったのですが、どうにもスマートな方法がありそうで見当たりません。 なので AssetPipelineを通して配信されたCSSファイルのURLをhttpクライアントでぶっ叩いてダウンロードする という力技を使います。

Rails標準のstylesheet_link_tagヘルパー の実装を参考に、下記のようなヘルパーを作って読み込ませてみます。 (ホスト名ベタ打ちな所とか良い子は真似しないように)

  def css_tag_amp(*sources)
    options = sources.extract_options!.stringify_keys
    path_options = options.extract!('protocol').symbolize_keys

    sources.uniq.map { |source|
      require 'open-uri'
      host = '合唱音源の新着情報.com'
      path = path_to_stylesheet(source, {host: host}.merge!(path_options))
      content_tag(:style, URI(path).read.encode("UTF-8"), options)
    }.join("\n").html_safe
  end

これでCSSファイルの内容をテンプレート内に表示できました。

が、下記のエラーが出てしまいます。

f:id:s2terminal:20160321234456p:plain

The author stylesheet specified in tag 'style amp-custom' is too long - we saw 254121 bytes whereas the limit is 50000 bytes. (see https://www.ampproject.org/docs/reference/spec.html#maximum-size)

とのことで、CSSファイルは50KBまでだそうですが、254KBもあるそうです。 そりゃ、bootstrapの本体まるごと突っ込んでまとめてコンパイルなどしていればそうなると思います。

面倒だったのでとりあえず CSSは無し で行きます。 AMP用の軽量CSSの手配は今後の課題ということで...

そんなこんなで色々やって、エラーをひとつずつ処理していきます。 細かいところだと、bullet の画面下部に出るエラーメッセージもAMPにおいてはエラーとなってしまうため、AMPのデバッグ時には消したりしました。

  Bullet.add_footer   = false

必要なコンテンツを盛り込んだ上でコンソール上に「AMP validation successful.」と出れば成功です。

f:id:s2terminal:20160321234710p:plain

CSSが無いせいで ◯知県合唱連盟の公式サイトのような 20世紀のホームページのような見た目になってしまいましたが、これが2016年の最新のトレンドであるAMP用Webページです。

忘れずに、元のページからAMPページヘlink rel=amphtml を貼るようにして完成です。

まとめ

いくつか課題はありますが、無事にAMP対応のページを公開できました。 例:今年を歌おうプロジェクト 松下耕『今年』の合唱動画 - 合唱音源の新着情報.com

実際にGoogle検索結果へAMPはまだ対応されていませんので、このページを検索結果上で確認することはできません。正しく対応できているのかどうかは不明です。(上手く行っていれば、数日の間にGoogle Search Console上に何らかの反応があると思います)

課題としてはCSSファイルをなんとかスマートな方法で用意したいのですが、AMPと通常Webページのダブルメンテになるとつらいです。 RSS配信のように極力AMP側の装飾を薄くするか、AMP版と通常WebページとでうまくCSSを共有する仕組みを作っておきたいと思いました。

本格的に導入するならばAMPのバリデーションは自動テストもしたい所です。 GoogleによるとChromeの開発者ツールだけでなくバリデーション用のAPIが公開される予定のようですので、そちらに期待です。

追記

追加で 構造化データマークアップが必要だった ので、対応しました。

s2terminal.hatenablog.com

参考文献