Hatena::ブログ(Diary)

eggshell blue

2014-04-06

広告枠

| 広告枠を含むブックマーク 広告枠のブックマークコメント

前々から気にはなっていたのですが、記事と脚注の間にぽっかり空隙があくことがあって、何なんだろうとは思ってたものの突き詰めていなかったのですが、あれ広告枠だったんですね。

プラスユーザーでもないので広告にどうのこうのはないのですが、デザイン的に不格好だったり、記事の末尾に埋め込まれるせいで変な広告がエントリの一部だと誤認されても嫌なので、デザインに一部手を入れ、広告枠だけボーダーで囲って明示するようにしました。

記事内容的にも、「ダウンロードリンク」のような手合いの広告が表示される可能性が十二分にある以上、放置するのもどうかと思いますしね。ただ、広告が読み込まれなかった場合に発生する空隙部分はそのままになってしまうので、その場合は微妙に変な感じになってしまうのですが、まぁ誤認されるよりはマシでしょう。

あと、正方形バナー広告が多いのは何なんでしょうね。デザイン的にも、長方形バナーの方が全体的に統一が取りやすいように思うのですが、あそこまで広告アピールした方がクリック率も高いのでしょうか。

2014-04-05

公衆Wifiの認証情報について

| 公衆Wifiの認証情報についてを含むブックマーク 公衆Wifiの認証情報についてのブックマークコメント

PyWispr での認証は、各サービスの認証ページが設置されているドメインをキーに、 secret.xml に記載された情報とマッチさせています。

kddi.com

au Wifi Spot の情報です。au ユーザーであれば、下記ページに接続端末のMACアドレスを投げてアクセスするとID/Passを取得できます( d:id:RobinEgg:20120617:p1 )。

https://auwifi-signup.auone.jp/su2/?{"mac_addrs":["***大文字MACアドレス***"],"manufacturer":"Windows","model":"7","request_type":"0"}

なお、ここで取得できたIDは、そのままでは使えないので、

{"code":"N22","device_num":"01","max_device_num":"02","passwd":"**PASS**","user_id":"**UID**"}

IDの末尾に「@au」を付け、「**UID**@au」のような形にする必要があります。

wi2.ne.jp

Wi2 / UQ Wifi 向け。契約時に割り振られたID/Passを入力します。au wifiローミングが可能ですので、上記で取得したID/Passを同じように設定すれば繋がります。

w-lan.jp

SoftBank Wifi Spot または mobilepoint 向けです。

両サービスの認証APIは同一ドメイン内に設置されているため、両サービスで情報を共用しています。サブドメインは異なるため、サブドメインまで含めた形で分割すると両サービスで別々のIDを使った運用が可能です。

SoftBank Wifi Spot(SWS)

SWS は UserAgent を利用して接続端末を判別している( d:id:RobinEgg:20120829:p1 )ことから、 uastring を記載しています。なお、最近では UA が iPhone でも WISPr コードを表示するようになったようです。

認証IDは契約電話番号11桁、パスワードネットワーク暗証番号4桁になります。なお、SWSの契約がなされていれば、契約上の端末が iPhone であれ Android であれ、電話番号で認証できるようです。

mobilepoint

契約時のID/Passが認証情報になります。

fon.com

FON向け。以前は Softbank と片側乗り入れをやっていたようで AP もよく見かけたのですが、そもそも現時点で WISPr 対応してるのかすら不明…。SoftbankのIDが通るのなら、電話番号と暗証番号で認証ができると思われます。通常の Linus アカウントであれば、メールアドレスパスワードを設定。

m-zone.jp

docomo Wi-Fi(旧m-zone)向け。いくつか契約方法がありますが、spモード付帯であれば、spモード各種設定から docomo ID でログイン後、docomo Wi-fi 設定で確認可能。

2014-04-04

PyWispr 更新

| PyWispr 更新を含むブックマーク PyWispr 更新のブックマークコメント

これまで微妙にバグを含んだまま放置していた PyWispr ( d:id:RobinEgg:20121104:p1 )ですが、このたびリファクタリングをして更新しました。Bitbucket のレポジトリを参照ください。なお、以前書いたとおり、使用に際しては自己責任SSL 証明書実在確認は仕様上不可、という点を念頭に置いてご使用ください。

機能的な変更点は特に無いのですが、今回のリファクタリングの主な目的は、「Android 上で動くネイティブ Python」こと QPython への対応です。以前は Android 上で Python を動かすには SL4A ベースでごにょごにょしないとなかなか難しかったですが、最近では Google Play からインストールするだけで動くというレベルに達していることもあり、それほど大きくない規模のコードであれば、コードベースをPC/スマートフォンで共用するのは非常に簡単になっているように思います。

また、 WISPr 1.0 の仕様書を配布していたサイトがドメイン失効→別人に取られる、というどうしようもない醜態を晒していることもあり、 Bitbucket の当該プロジェクト上で仕様書の再配布をはじめました(特に規制するような文言はないことを確認していますが、問題ありそうなら止めます)。


しかしアレですね、数年前の自分が書いたコードは理解不能なクソコード、という格言IT 業界に広く敷衍した真理の一つだと思いますが、なかなかどうして、こんなコードを書いたのは誰だ!あ、俺か、という一人コントはいい加減止めにしたいものです。

余談

コードを書き換えてる最中に気づいたのですが、 d:id:RobinEgg:20120617:p1 で書いた、 KDDIwifi について、

許容台数
4台までに拡張
MACアドレス
登録必須なのは変わらないけど、実際に登録した端末以外からでも、発行済みの認証情報を使って接続可

という仕様に微妙に変更されているようですね。そうすると、いよいよもって何のための MAC アドレス登録なんだ、という話になりそうですが(そもそも登録不要?)。

2014-03-11

Graphite のインストールについて

| Graphite のインストールについてを含むブックマーク Graphite のインストールについてのブックマークコメント

先日、ちょっとしたログを表示するのに Graphite の導入を検討していて、試しに走らせてみたのでそのときの記録をメモしておきます。

Graphite とは

日本語の情報が少ないのでアレですが、高機能版の rrdtool といえば当たらずとも遠からず、という感じ。rrdtool といえば munin や MRTG、あるいは GrowthForecast などでおなじみの Perl 系グラフ表示ミドルウェアですが、ユーザー側でグラフの表示期間やスケールの変更を行ったりすることはちょっと難しいのが難点でした。

また、これは個人的に盲点だったのですが、 rrdtool が扱うデータのタイムスタンプは、原則としてAPIにデータが投入された時刻になってしまうんですね(API への引数として別途時刻を指定できない)。従って、 on-time で投入可能なアクセスログや、逐次投入が可能な HW メトリクスなどの推移を見る用途には向いているものの、過去数時間分のデータを一度に処理したりするような、過去のデータを投入して時系列で表示するという用途には使えません。

この2つの問題を解決するのが Graphite で、元々は非常に大規模なスケール(1分間に数万オーダーのデータ投入があるような環境)での使用を想定しているようなので今回検討した用途には正直オーバースペックかなという感じもしましたが、実際に使ってみるとデータ収集部とグラフ表示部が分離されていること、データ投入が非常にカジュアルにできること、収集データを API を通じて簡単に取得できること、などから、 rrdtool で辟易しているなら一度は試してみた方が良いよという感じです。

準備

Graphite のコアは

Carbon
データ収集
Whisper
回収データの保存管理
Graphite-web
webフロントエンド

の3ユニットから構成されており、いずれも Python 製です。web側のプラットフォームは django で、 WSGI 経由で動くことになります。なお、フロントエンドについてはいくつか Ruby 製の代替があります。

インストールした環境は Ubuntu Server 12.04(Apache 2.2) / 14.04(Apache 2.4) どちらも LTS です。なお、Pythonは両環境とも 2.7 を用いました。

導入

すべて pip でインストールが可能です。標準的な手順だと、インストールディレクトリ

/opt/graphite

になります。まずは関連する依存モジュールから入れていきます。

# apt-get install python-pip python-cairo python-dev libapache2-mod-wsgi build-essential

libapache2-mod-wsgi ですが、 Python 3 の場合は libapache2-mod-wsgi-py3 になります(動くかどうかは未確認。

次いで、 Graphite のコアと django を入れます。

# pip install graphite-web whisper carbon django django-tagging daemonize

正常にインストールされれば、設定ファイルを書き換えていきます。

$ cp /opt/graphite/conf/carbon.conf.example /opt/graphite/conf/carbon.conf
$ cp /opt/graphite/conf/graphite.wsgi.example /opt/graphite/conf/graphite.wsgi
$ cp /opt/graphite/conf/storage-schemas.conf.example /opt/graphite/conf/storage-schemas.conf
$ vi storage-schemas.conf

storage-schemas.conf では、収集したデータをどの程度の粒度・期間で保存しておくか、というルールを決めます。デフォルトでは、1分間隔で24時間しか保存しないようになっているので、必要に応じて変更します。

Whisper のストレージは固定長になっているため、データ収集前に保存期間を決めておく必要があり、また一度データ収集が行われ、データベースが作成されてからこの粒度・期間を変更する場合は別途スクリプト(/usr/local/bin/whisper-resize.py)を走らせる必要があります。

[sensor]
pattern = sensor.*
retentions = 120s:365d

基本的な書式は上記の通りで、この例では2分ごとに取得されるデータを365日間保存します。 pattern 項はデータの名前空間とのマッチングを指定します(正規表現可)。 Graphite が扱う各データはドットで区切られた階層型の名前空間を有しており、たとえば

sensor.cpu.temp
sensor.cpu.fanspeed

などという形になりますので、漏れのないように指定します。設定が終われば、web側の設定を行います。

$ cp /opt/graphite/webapp/graphite/local-settings.py.example /opt/graphite/webapp/graphite/local-settings.py
$ vi /opt/graphite/webapp/graphite/local-settings.py

local-settings.py では、タイムゾーンに Asia/Tokyo を、秘密鍵は必要に応じて指定します。この後、管理用の DB を作成します。

$ sudo python /opt/graphite/webapp/graphite/manage.py syncdb

web 周りのスクリプトの所有者を www-data に変更します。

$ sudo chown www-data:www-data /opt/graphite/storage -R
$ sudo chown www-data:www-data /opt/graphite/webapp -R

ここから Apache の設定です。Virtual Host 用の conf ファイルの見本が用意されているので、apacheの設定フォルダにコピーします。

$ sudo cp /opt/graphite/examples/example-graphite-vhost.conf /etc/apache2/sites-available/graphite.conf
$ sudo ln -s /etc/apache2/sites-available/graphite.conf /etc/apache2/sites-enabled/graphite.conf
$ sudo vi /etc/apache2/sites-enabled/graphite.conf

触るところはほとんどありませんが、

Alias /media/ "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/media/"

djangoインストールされているフォルダに書き替えが必要です。また、

<Location "/content/">

節と

<Directory /opt/graphite/conf/>

節はアクセス許可が必要です。既にリリースから2年近く経過した Apache 2.4 系ではアクセス制限に Allow/Deny ではなく Require を用いるようになっているので、2.4系を使う場合は間違えないように。

  <IfVersion < 2.3 >
   Order allow,deny
   Allow from all
  </IfVersion>
  <IfVersion >= 2.3>
   Require all granted
  </IfVersion>

で書いておいてくれれば良いのですけどね。

さて、ここからは一部のスクリプトを改修する必要があります。

/opt/graphite/webapp/graphite
  ./urls.py
  ./events/urls.py
  ./metrics/urls.py
  ./dashboard/urls.py
  ./render/urls.py
  ./version/urls.py
  ./cli/urls.py
  ./graphlot/urls.py
  ./browser/urls.py
  ./composer/urls.py
  ./whitelist/urls.py
  ./account/urls.py

で、

from django.conf.urls.defaults import *

となっているのを

from django.conf.urls import *

に書き換えます。これは、

django.conf.urls.defaults will be removed. The functions include(), patterns() and url() plus handler404, handler500, are now available through django.conf.urls .

Django Deprecation Timeline | Django documentation | Django

となっているように Django 側のバージョンアップで更新されたものの残り物です。また、

/opt/graphite/lib/carbon/util.py

from twisted.scripts._twistd_unix import daemonize

import daemonize

に書き換えます。これでやっと準備が整いました。

$ cd /opt/graphite
$ sudo service apache2 restart
$ sudo ./bin/carbon-cache.py start

で走らせると、Graphite のトップページにアクセスできるはずです。

2014-01-18

ぱすわーどじぇねれーたー

| ぱすわーどじぇねれーたーを含むブックマーク ぱすわーどじぇねれーたーのブックマークコメント

随分前に d:id:RobinEgg:20111217:p1 で書いたパスワードジェネレーターですが、奇を衒いすぎて意味不明なコードになっていたことと、大元の Crypt-JS が更新されていたのでシンプルに書き直し、ついでに使用するハッシュアルゴリズムも SHA3 に変更して最大で64文字まで算出できるようにしました。

今時の web サービスでパスワード記号使用不可とか64文字未満で文字数制限とかちょっとあり得ないんですが、往々にしてそういうサービスが跋扈している現状、適宜コードを書き換えるとかしてください(需要あんのか凄く疑問だけど。

javascript: (function(){
  var salt = prompt('Salt?') || 'ますたーぱすわーど';
  if ( !document.getElementById('cryptojs-sha-hmac') ){
    var s = document.createElement('script');
      s.id = 'cryptojs-sha-hmac';
      s.src = 'https://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha3.js';
      void(document.body.appendChild(s));
  }

  var genPass = function(binArray){
    var Ascii = ''; for(var i=33; i<127; i++){ Ascii += String.fromCharCode(i); }
    var passPhrase = '';
    for( var i = 0; i < binArray.length; i++){
      passPhrase += Ascii.charAt(parseInt(binArray[i], 10) % Ascii.length);
    }
    return passPhrase;
  };

  setTimeout(function(){
    var hmacBytes = CryptoJS.HmacSHA3(document.domain, salt);
    var u = new Uint8Array(hmacBytes.sigBytes);
    for (var i=0; i<hmacBytes.sigBytes; i++) {
      u[i] = (hmacBytes.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
    }
    window.prompt('Pass phrase:', genPass(u));
  }, 1000);

})();