EDIDバイナリを作る

1360x768の解像度のEDIDバイナリを作りました。以下はUbuntu12.04LTSで行いました。

カーネルのソースをダウンロードする

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux

Documentation/EDID の中の Makefile以外を /usr/src/linux-headers-3.11.0-15/Documentation/EDID/ にコピーします。
その中の1280x1024.Sなどの、解像度がファイル名であるファイルのうちの一つをコピーして設定ファイルを作ります。今回は1360x768.Sを作りました。

.Sファイルの編集

$ cvt 1360 768 60 -r
# 1360x768 59.96 Hz (CVT) hsync: 47.37kHz; pclk: 72.00MHz
Modeline "1360x768R"   72.00  1360 1408 1440 1520  768 771 781 790 +hsync -vsync
                      (1)    (2)  (3)  (4)  (5)  (6) (7) (8) (9)  (10)   (11)

cvtコマンドの結果を参照しながら1360x768.Sを編集します。

/* Display */
#define CLOCK 72000 /* (1)を1000倍した値 */
#define XPIX 1360 /* (2) */
#define YPIX 768 /* (6) */
#define XY_RATIO XY_RATIO_16_9 /* XY_RATIO_16_10、XY_RATIO_4_3、XY_RATIO_5_4、XY_RATIO_16_9のいずれか */
#define XBLANK 160 /* (5)-(2) */
#define YBLANK 22 /* (9)-(6) */
#define XOFFSET 48 /* (3)-(2) */
#define XPULSE 32 /* (4)-(3) */
#define YOFFSET (63+1) /* 63+((7)-(6)) */
#define YPULSE (63+3) /* 63+((8)-(7)) */
#define DPI 72 /* 72 */
#define VFREQ 60 /* 60 */
#define TIMING_NAME "Linux WXGA" /* お好きに? */
#define ESTABLISHED_TIMINGS_BITS 0x00 /* 0x00に */
#define HSYNC_POL 1 /* (10)が+なら1、-なら0 */
#define VSYNC_POL 0 /* (10)が+なら1、-なら0 */
#define CRC 0xa0 /* ここは後で編集する */

編集が終わったらmake。

$ sudo make

1360x768.binが出来上がってます。CRCを調べるためにバイナリをedid-decodeにかけます。edid-decodeはapt-getでインストール可能です。(yumは調べてないので知りません)

$ edid-decode 1360x768.bin
(略)
Checksum: 0x1b (should be 0x7)

should beの後に書かれている値をCRCの所に記入してもう一度makeします。

#define CRC 0x7

$ sudo make

これでEDIDバイナリが完成しました。1360x768.binは /lib/firmware/edid に移動またはコピーします。

余談

本当は1366x768を作りたかったのですが、水平解像度は1360の次は1368でしか作れませんでした。1368版も作って使ってみましたが文字がにじむので、1360版を使うことにしました。

パーフェクトPHP 2〜5章自作問題集

今更ですがパーフェクトPHPを読了しました。オライリーの「プログラミングPHP」よりもこっちのほうが好きになりました。

パーフェクトPHP (PERFECT SERIES 3)

パーフェクトPHP (PERFECT SERIES 3)

2〜5章は理解を確実にするために問題集を作りながら読みました。その時につくった問題を公開します。

  • 解答は載せてません。パーフェクトPHPを読んで(なければ、ぜひお買いになって)ご確認下さい。
  • あまりにも簡単すぎると感じた事柄は出題していません。
  • 記述式の問題がほとんどなので多少難しく感じることもあるかもしれません。

2章 PHPの基本

  • PHP_EOLとは?
  • PHPブロックとは?
  • PHPブロックの終了タグを省略することができるのはどのような場合においてか?
  • ライブラリやHTMLを含まないファイルでは終了タグを記述することが推奨されているか?それとも記述しないことが推奨されているか?そして、それは何故か?
  • PHPにおいて文の途中での空白、タブ、改行はどのように扱われるか。
  • PHPでのコメントの記述方法3種類を挙げよ
  • echo文での出力の特徴は?
  • phpの識別子のルールは?
  • PHPのエラーを大きく分けるとどのような分類になるか?すべて挙げよ
  • 変数がセットされているか調べるにはどうすればいいか?
  • 可変変数とは?
  • スコープとは?
  • ローカルスコープ内でグローバルスコープに定義された変数を参照するにはどうするか?
  • 定義済み定数の例を1つ挙げよ
  • スーパーグローバル変数の特徴は?
  • スーパーグローバル変数の例を挙げよ
  • 定数を定義する方法を2つ挙げよ
  • 文字列から該当する定数を取得するには?
  • マジック定数とは?
  • マジック定数を全て挙げよ
  • 発生したエラーを表示させるかどうかを制御する設定項目は何か?

3章 型と演算子

  • PHPは符号なし整数をサポートしているか?それともサポートしていないか?
  • PHP_INT_MAXを超える整数はどうなるか?
  • 整数型に明示的にキャストする方法を2つ挙げよ
  • 浮動小数点型に明示的にキャストする方法を3つ挙げよ
  • 文字列において"(ダブルクォート)が'(シングルクォート)と比べて違うところは何か?
  • ヒアドキュメントとNowdoc、変数が展開されるのはどちらか?
  • ヒアドキュメントはどのように書く?
  • Nowdocはどのように書く?
  • 文字列型への明示的なキャストをする方法を2つ書け
  • 次の例はどのように出力されるか echo 22.0;
  • PHPがfalseと判断するものを挙げよ
  • リソース型を初期化する関数を一つあげよ
  • 変数の持つリソース型の種類を調べることのできる関数は?
  • 変数がnullになる場合3つを挙げよ
  • nullの代入された変数とunset()された変数とは何が違うか
  • 自動キャストはどんな場合に発生する?
  • なるべく===または!==を使って厳密な比較を行うべきであるが、それはなぜか?
  • ある変数が特定のクラスのインスタンスであることを調べるために用いる型演算子は何か?
  • 次の表記は複合演算子の表記である。これと等しい表記のPHPプログラムを書け

$i += 1;

  • 以下のプログラム文と同じ動作をする文を三項演算子の省略記法 ?: を使って書け

$result = func() ? func() : 'hoge';

  • 以下のプログラムは三項演算子を含むPHPプログラムである。このプログラムのの出力は?

$flag1 = true;
$flag2 = false;
echo $flag1 ? 1 : $flag2 ? 2 : 0;

  • PHPにおける三項演算子は右結合か左結合か?
  • 実行演算子``の機能について述べよ
  • 実行演算子``と同じ機能をもつ関数は何か?
  • PHPの配列の特徴を3つあげよ
  • 配列のキーがセットされているか調べる方法を2つのべよ

4章 制御構造と関数

  • グループ文とは?
  • $hoge = 3という式の評価は?
  • 以下のプログラムを:とendifを使って表現せよ

if ($bool) {
echo 'hoge';
}

  • forの括弧内の3番目の式(反復式)はいつ実行されるか?
  • foreachに渡す配列の各要素の値を変更するには?
  • 関数の返り値に参照を用いるには関数の定義においてどのようにすればいいか?
  • 関数に渡す引数を参照で受け取るにはどうすればいいか?
  • 引数を参照で受け取る関数には値を渡すことができる?それともできない?
  • 返り値に参照を用いている関数は値を返すことができる?それともできない?
  • 可変関数とは?
  • 可変関数と同じようなことを実現できる関数を2つ挙げよ
  • 無名関数の主な使い道は?
  • クロージャとは?
  • 無名関数を定義する際に、関数内で利用する変数を指定してクロージャを作るために使われる構文は?
  • 言語構造が関数と違うところは?
  • 関数と言語構造、可変関数やコールバックに指定できないのはどっち?

5章 クラスとオブジェクト

  • PHPにおけるクラス名の記法の主流は?
  • 名前空間を使わない場合、名前の衝突問題を解決するためにどのような名付け方をするか?
  • オブジェクト型とは?
  • new演算子を用いてインスタンス化されたオブジェクトを変数に代入したり関数の引数に指定したりする場合、値渡しになるかそれとも参照渡しになるか?
  • オブジェクトの参照を渡すのではなくコピーしたい場合はどうすればいいか?
  • 次のアクセス修飾子とその説明を正しく組み合わせよ。

(アクセス修飾子)
private
protected
public
(説明)
自分のクラスの内側または自分のクラスを継承したクラスの内側からのみ参照・呼び出しができる
自分のクラスの内側からのみ参照・呼び出しができる
クラスの外側からでも参照・呼び出しができる

  • プロパティやメソッドの宣言時にstaticをつけるとどういうことができるか?
  • オブジェクト自身へアクセスするには何を用いるか?
  • クラス自身を表すキーワードは何か?
  • 親クラスを表すキーワードは何?
  • クラス定数を定義するためのキーワードは?
  • PHP5以降でのコンストラクタの定義の仕方は?
  • PHP4までのコンストラクタの定義の仕方は?
  • 継承に使われるキーワードは?
  • オーバーライドとは?
  • オーバーライドをできないようにするにはメソッドの宣言時にどのようにすればいいか?
  • 標準クラスとは何か?
  • 標準クラスを初期化するにはどうすればいいか?
  • 他の型からオブジェクト型にキャストするとstdClassのインスタンスになるか?
  • オブジェクト型に明示的にキャストするにはどうすればいいか?
  • 整数型や文字列型などのスカラー値をオブジェクト型にキャストしたあとに、その値にアクセスするにはどうすればいいか?
  • 配列型をオブジェクト型にキャストした場合は?
  • 抽象クラスを定義するにはなんというキーワードを使うか?
  • 抽象クラスの特徴は?
  • 抽象クラスはどのような場合に用いるか?
  • 抽象クラスを使うには?
  • 子クラスでabstructメソッドを実装する場合の条件を2つ述べよ
  • インターフェイスとは?
  • インターフェイスを定義するためには何というキーワードを使うか?
  • インターフェイスを実装しているかどうか調べる方法は?
  • マジックメソッドとは?
  • マジックメソッドにはどんなものがあるか?
  • PHPにおけるオーバーロードとは何か?
  • 遅延静的束縛とは?
  • オートロードとは?
  • __autoload()関数の欠点は?
  • 名前空間とは?
  • 名前空間の区切りにはどの文字を用いるか?
  • 名前空間を定義した場合において、グローバルな関数やクラスを参照するときには、それらをグローバルな名前空間から参照しなければならないが、どうすればいいか?
  • 非修飾名、修飾名、完全修飾名とは何か?
  • 名前空間を定義するために使うキーワードは?
  • 名前空間を定義する時に気を付けなければならないことは?
  • 名前空間の影響を受けるものを3つ挙げよ
  • 名前空間の影響を受けないものを2つ挙げよ
  • 1つのファイルに複数の名前空間を定義する方法は?
  • 別の名前空間やそれに属するクラスをインポートするには何というキーワードを使うか?
  • 別の名前空間から参照する場合やグローバルに定義されているクラスを参照する場合には、常に完全修飾名の指定をしなければならない。◯か×か?
  • グローバルな空間からは、修飾名による相対的な指定ができる。◯か×か?
  • インポートした名前空間に別名をつけるには何というキーワードを使うか?どのように使うか?
  • 動的な名前空間を使うにはどうすればいいか?
  • useによるエイリアスコンパイル時に変換される。◯か×か?
  • useによるエイリアスを動的な名前空間として利用することができないのはなぜか?
  • 例外を送出するためのキーワードは?
  • 例外を捕捉する対象の処理を指定するキーワードと例外処理の内容を指定するためのキーワードをそれぞれ答えよ
  • すべての例外の基底となるクラスは?
  • try文の途中で例外が発生した場合、以降の処理は実行されるか?それともされないか?
  • try-catch文の外部で例外が送出された場合はどういうことが起こるか?
  • PHPの標準のエラーを例外に変換するにはどうすればいいか?
  • PHP標準のエラーを例外に変換する際に用いられる例外クラスは何か?
  • PHPにおける参照(リファレンス)とは何か?
  • 参照変数に、もう一度別の変数への参照を代入した場合はどうなるか?
  • PHPでは、オブジェクトは参照でしか扱うことができない。◯か×か?
  • オブジェクトへの参照をもつ変数への参照を別の変数に代入したらどうなるか?
  • リファレンスカウントとは何か?
  • オブジェクトの寿命はいつまでか?
  • オブジェクトへの参照を持つ変数がunsetされたらどうなるか?
  • コピーオンライトとは?
  • コピーオンライトの長所とは?

Twitterのツイート取得3200件制限およびツイートの消去についてのメモ

基本

  • Twitterのツイートは3200件までさかのぼることができる。それより前へはさかのぼれない
  • 3200件より前にはさかのぼることはできないが、個別のツイートそのものは残っている
  • よって、URLを知っていれば(または、検索で見つけることができれば)個別のツイートのページへ直接アクセスすることが可能である

ツイートの消去が取得に及ぼす影響

  • たとえば、APIで3101件前〜3200件前を指定して取得(http://api.twitter.com/1/statuses/user_timeline.json?count=100&page=32)し、100件が返ってきたとする
  • ここで、3150件前のツイートを消す。この後3101〜3200件目を取得し直そうと試みても99件しか返ってこない
  • このことより、3200件前より新しいツイートを消したとしても、3201件目を取得することはできないと思われる
  • イメージとしては3200件前までのデータを管理するテーブルがあって、新しいツイートがなされると古いツイートが一つ消える、ツイートが消されるとそこは詰められずに空白になる、という感じのものが想像できる

HTTP_OAuthでアクセストークンを取得するときにユーザIDとスクリーン名を取得できるようにするための修正

Twitter API 仕様書*1によると、アクセストークンを取得するための認証に成功すると、アクセストークン、アクセストークンシークレットの他にユーザID、スクリーン名が返ってくることになっています。
PEARのHTTP_OAuthのバージョン0.1.18では認証成功時にアクセストークンとアクセストークンシークレットは取得できます。しかし、ユーザIDおよびスクリーン名を取得することはできないようです。
なので、これらを取得できるように修正してみました。
修正の対象となるのは、Consumer.php内のクラスHTTP_OAuth_Consumerです。

クラス変数を追加する

<?php
    protected $userId = null;
    protected $screenName = null;
?>

既存のメソッドに書き加える

<?
    public function getAccessToken($url, $verifier = '',
        array $additional = array(), $method = 'POST'
    )
    {
        if ($this->getToken() === null || $this->getTokenSecret() === null) {
            throw new HTTP_OAuth_Exception('No token or token_secret');
        }

        $this->debug('Getting access token from ' . $url);
        $additional['oauth_verifier'] = $verifier;

        $this->debug('verifier: ' . $verifier);
        $response = $this->sendRequest($url, $additional, $method);
        $data     = $response->getDataFromBody();
        if (empty($data['oauth_token']) || empty($data['oauth_token_secret'])) {
            throw new HTTP_OAuth_Consumer_Exception_InvalidResponse(
                'Failed getting token and token secret from response', $response
            );
        }

        $this->setToken($data['oauth_token']);
        $this->setTokenSecret($data['oauth_token_secret']);
        
        /* 
         * ここから追加
         */
            $this->setUserId($data['user_id']);
            $this->setScreenName($data['screen_name']);
        /* 
         * 追加ここまで
         */
    }
?>

メソッドを新たに追加する

<?
    public function getUserId()
    {
        return $this->userId;
    }
    
    public function setUserId($userId)
    {
        $this->userId = $userId;
    }

    public function getScreenName()
    {
        return $this->screenName;
    }
    
    public function setScreenName($screenName)
    {
        $this->screenName = $screenName;
    }
?>

使い方

スクリーン名、ユーザIDを取得するときはアクセストークン等を取得するときに、以下のようにすれば取得できます。

<?php
$screenName = $consumer->getScreenName();
$userId = $consumer->getUserId();
?>

Services_Twitterで返信対象のつぶやきを指定するには

<?php
require_once 'Services/Twitter.php';

$username = 'Your_Username';
$password = 'Your_Password';

$args = array('status' => "@YBahn お疲れ様です!",
              'in_reply_to_status_id' => "4466621967"
              );
try {
    $twitter = new Services_Twitter($username, $password);
    $msg = $twitter->statuses->update($args);
    print_r($msg);
} catch (Services_Twitter_Exception $e) {
    echo $e->getMessage(); 
}
?>

Services_Twitter0.4.0を日本語で使うための修正

PEARTwitterライブラリであるServices_Twitterのバージョン0.4.0を使ってTwitterに投稿をしようとすると「statuses/update: status must not exceed 140 chars」とのエラーが出ることがあります。これはつぶやきが140字を超えてはいけないという意味ですが、つぶやきが日本語である場合、140字を超えていないにもかかわらずこのエラーが発生することがあります。
この現象が起こる原因は、Services_Twitter0.4.0が文字列の長さの判定にstrlen関数を使っていることです。strlen関数は日本語をはじめとするマルチバイト文字の文字数を正確に数えることができず、実際の文字数より大きい数字が返ってくるからです。
マルチバイト文字列の文字数を正確に数えるにはマルチバイト文字列に対応したmb_strlen関数を使います。
修正前のソースコードと修正後のコードを以下に示します。修正後のコードではstrlen関数をmb_strlen関数に変更しています。ここではつぶやきの文字コードUTF-8であるものとします。

修正前

<?php
    protected function validateArg($name, &$val, $type, $maxLength = null)
    {
        // check length if necessary
        if ($maxLength !== null && strlen($val) > $maxLength) {
            throw new Exception(
                $name . ' must not exceed ' . $maxLength . ' chars',
                self::ERROR_PARAMS
            );
        }
?>

修正後

<?php
    protected function validateArg($name, &$val, $type, $maxLength = null)
    {
        // check length if necessary
        if ($maxLength !== null && mb_strlen($val,"UTF-8") > $maxLength) {
            throw new Exception(
                $name . ' must not exceed ' . $maxLength . ' chars',
                self::ERROR_PARAMS
            );
        }
?>

XML_Feed_Parserで簡易フィードリーダー(RSSリーダー)を作る

フィードリーダー(RSSリーダー)のPHPスクリプトを書いてみました。機能は以下の通りです。

  • フィードのタイトル、記事のタイトル、記事の作成日時、要約(もしくは、本文の始めの部分)を表示する
  • RSS1.0、同2.0、Atom1.0に対応
  • 新しいものから順に表示する


XMLを読み込む等の処理にはフィードパーサと呼ばれる、XMLの構造を解析してくれるプログラムを使うと便利です。今回はPEARのライブラリの一つである、XML_Feed_Parserを使ってみました。

以下のスクリプトでの重要な部分は、対象となるフィードに含まれた記事をすべて配列に取り込んでから、記事の作成日時でソート(並び替え)する部分です。フィードの形式によって日時の表示形式は異なっているので、異なる形式のフィードが混じっていると、日時で正しく並び替えることはできないのですが、XML_Feed_Parserはフィードに記載されている日時をすべてタイムスタンプ(1970年1月1日0時0分0秒からの経過秒数)に変換してくれます。そのおかげで、タイムスタンプを使って記事を正しく並び替えられるようになります。

<?php
$feeds = array(
              "http://hogehoge.com/index.rdf",
              "http://fugafuga.net/atom.xml",
             );
//-------------------------------------
require_once 'XML/Feed/Parser.php';

$entries = array(); //記事を1件ごとに格納する配列

foreach ($feeds as $url) {
  //フィードの読み込み
  $source = file_get_contents($url);
  try{
    $feed = new XML_Feed_Parser($source,false,true);
  } catch (XML_Feed_Parser_Exception $e) {
    die("Invalid Feed : $url". $e->getMessage());
  }

  $feed_title = $feed->title;   //各フィードのタイトル

  foreach ($feed as $entry) {
    //フィードのフォーマットによって処理を変える
    if ($feed->version() == "RSS 1.0") {
      $timestamp = $entry->date;
      $description = $entry->description;
      }
    if ($feed->version() == "RSS 2.0") {
      $timestamp = $entry->pubDate;
      $description = $entry->description;
    }
    if ($feed->version() == "Atom 1.0") {
      $timestamp = $entry->published;
      $description = $entry->summary;
    }
    //記事の内容を配列に格納
    $entries[] = array(
                    "feed_title"     => $feed_title,
                    "entry_title" => $entry->title,
                    "link"     => $entry->link,
                    "timestamp" => $timestamp,
                    "description" => $description,
                    );
  }
}
//並べ替え
uasort($entries,"cmp_desc");

//並べ替え用の比較関数
function cmp_desc($a, $b) {
  if($a['timestamp'] >= $b['timestamp']) return -1;
  if($a['timestamp'] == $b['timestamp']) return 0;
  if($a['timestamp'] <= $b['timestamp']) return 1;
}
?>
<html>
<head><title>RSS Reader</title></head>
<body>
<ul>
<?php
//表示する
foreach ($entries as $entry) {
  if (preg_match('/^(https?)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)$/',$entry['link'])) {
  echo '<li>';
  echo '<a href="' . $entry['link'] . '">';
  echo htmlspecialchars($entry['entry_title'],ENT_QUOTES);
  echo '</a>';
  echo ' ' . strftime("%Y-%m-%d %H:%M",$entry['timestamp']);   //タイムスタンプを分かりやすい形式に変換
  echo ' (' . htmlspecialchars($entry['feed_title'],ENT_QUOTES) . ')';
  echo ' <br>' . mb_substr(strip_tags($entry['description']), 0, 120, 'UTF-8');   //要約は120字まで表示する
  echo '</li>';
  }
}
?>
</ul>
</body>
</html>