2010年6月29日火曜日

jQueryプラグイン:ロールショウ?

指定された要素の子供を、順番にshow&hideするだけのもの。
今日自作。拡張性ほとんどなし。

jquery.myslideshow.js:
(function($){

  $.fn.mySlideShow = function(options){
    var c = $.extend(
      {
        //opt1 : true
        duration: 3000
      },
      options
    );
    var o = this;
    var n = $(o).children().length;
    var curr = 0;
    var timerID;

    var f = function() {
      var tgt = $(o).children().get(curr);
      $(tgt).fadeIn('normal');
      $(tgt).siblings().hide();
      curr++;
      if(curr >= n) {
        curr = 0;
      }
    }

    f();
    if(timerID){
      clearInterval(timerID);
    }
    timerID = setInterval( f, c.duration );

    return o;
  };
})(jQuery);

MTにPerlモジュールを追加したいとき

参考:mtプラグインにおける Perl モジュール の配置 について - 左脳Script

CPANを使えない環境での話。
/インストールディレクトリ/lib/ に置くと動作するらしい。
Digest::SHA::PurePerl なら、/インストールディレクトリ/lib/Digest/SHA/

今回はとりあえず、バックアップ/復元に使う、
* Archive::Tar
* Archive::Zip
* IO::Compress::Gzip
* IO::Uncompress::Gunzip
が使えればOK.

2010年6月28日月曜日

[HOP] partition problemのコード

単独のreturnが参考になった。

use strict;
use warnings;
use Data::Dumper;

sub partition{
    my ($target, $treasures) = @_;

    return [] if $target == 0;     #anon. array ref
    return () if $target < 0 || @$treasures <= 0; # empty list
    # ここはPerlの作法に詳しくないと謎。
    # 一般的に、エラーケースではempty listを返すのが普通。
    # 空リストを明示的に書かずに、単独のreturnでよいかもしれない
    # (呼び出し元がリストコンテキストなら空リストになるから)

    my ($first, @rest) = @$treasures;
    my @solutions = partition($target - $first, \@rest);
    return ((map {[$first, @$_]} @solutions), partition($target, \@rest));
    # この文も実は難しい。mapの結果は、@solutionsがarray refならリスト、
    # empty listなら空リストになる性質がある。
}

print Dumper(partition(5, [1,2,3,4]));

2010年6月25日金曜日

クローラーの邪魔をしたい場合

.htaccess

BrowserMatchNoCase Googlebot     robot
BrowserMatchNoCase Slurp         robot
BrowserMatchNoCase msnbot        robot
BrowserMatchNoCase proodleBot    robot
BrowserMatchNoCase psbot         robot
BrowserMatchNoCase ScSpider      robot
BrowserMatchNoCase TutorGigBot   robot
BrowserMatchNoCase YottaShopping robot
BrowserMatchNoCase Faxobot       robot
BrowserMatchNoCase Gigabot       robot
BrowserMatchNoCase MJ12bot       robot
BrowserMatchNoCase Baidu         robot
deny from env=robot

確認(Perlモジュールを使う)

$ lwp-request -mHEAD -H 'User-Agent: slurp' http://sample.com/img/1.jpg
$ lwp-request -mHEAD -H 'User-Agent: slurp' http://user:password@testserver.com/img/1.jpg

2010年6月24日木曜日

PHP5のグローバル変数

グローバル変数は、globalキーワードを付けて宣言することになったらしい。
※以前のようにブロック内でglobal宣言しただけでは、参照できない。
茶々ラボ - Chacha Lab.: PHPでグローバル変数

しかも、global宣言と同時に初期化できないのが面倒。
※2つ文を書く必要がある。

global $category_tbl;
$category_tbl = array(
    '広告[  ]+総合広告' => array(1),
);
...
function(){
    global $category_tbl;
    print_r($category_tbl);
}

PHPでTSV処理

エクセルで出力されたTSVを想定。

CSVのほうが知名度はあるが、TSVが好ましい(区切りには制御文字のほうが適している、それこそ制御文字の本分でしょう、という気がする)。

エクセルでデータを作る人、つまり非プログラマー、非SEの人は普通TSVのことを知らないが、そこは事前に説明してTSVで出力するようお願いしておく。

TSVに関する大まかな仕様

  • 改行を含む列は"で始まり"で終わる
  • タブ、二重引用符を含んでもいい
  • SJIS(PHPプログラム内ではUTF8に変換して処理する)

TSVファイルを読み込んで連想配列の配列に変換(PHP)

/*
 * TSVファイルを読み込んで連想配列の配列に変換
 * 引数:処理結果(参照渡し)、TSVファイルのパス
 */
function parseTSV(&$records, $path){
    $fp = fopen($path, 'r');
    if($fp===FALSE){
        return FALSE;
    }

    $records = array();
    $errors = array();
    //$cnt = 0; // これはデバッグ専用のリミット(後で削除)
    //    while(!feof($fp) && $cnt < 10){
    while(!feof($fp)){

        $line = fgets($fp);
        $line = mb_convert_encoding($line, 'UTF-8', 'SJIS-win');
        $line = str_replace(array("\r\n","\r"), "\n", $line);
        $len = mb_strlen($line, 'UTF-8');

        $state = 'START';
        $flg = 0;
        $buf = '';
        $fields = array();
        //        $cnt++;

        for($i=0; $i<$len; $i++){
            $char = mb_substr($line, $i, 1, 'UTF-8');
            if($state=='START'){
                if($char === '"' && $flg == 0) {
                    $flg = 1;
                    $state = 'MID';
                } elseif($char === "\n" && $flg == 0) {
                    break;
                } elseif($char === "\t") {
                    $state = 'END';
                } else {
                    $buf .= $char;
                    $state = 'MID';
                }
            } elseif($state == 'MID') {
                if($char === "\t") {
                    if($flg){
                        $buflen = mb_strlen($buf, 'UTF-8');
                        if($buflen && mb_substr($buf, $buflen - 1, 1, 'UTF-8') == '"') {
                            $state = 'END';
                        } else {
                            $char = ' ';
                        }
                    } else {
                        $state = 'END';
                    }
                } elseif($char === "\n"){
                    if($flg){
                        $buf .= $char;
                        // データが次の行に続いている場合
                        $line = fgets($fp);
                        $line = mb_convert_encoding($line, 'UTF-8', 'SJIS-win');
                        $line = str_replace(array("\r\n","\r"), "\n", $line);
                        $len = mb_strlen($line, 'UTF-8');
                        $i = -1; // ここは強引
                    } else {
                        $state = 'END';
                    }
                } else {
                    $buf .= $char;
                }
            }
            if($state == 'END') {
                if($flg){
                    $buf = mb_substr($buf, 0, mb_strlen($buf, 'UTF-8') - 1, 'UTF-8');
                }
                $buf = mb_ereg_replace('""', '"', $buf); // 連続したダブルクォートは1つに

                // 連想配列に追加して、初期化
                $fields[] = $buf;
                $state = 'START';
                $flg = 0;
                $buf = '';
            }
        }
        // 1レコード読み込み終了
        if(count($fields) > 0) {
            $records[] = $fields;
        }
    }
    fclose($fp);

    return TRUE;
}

2010年6月23日水曜日

CSSでsubmitの装飾(IE6以外)

buttonでもinput(submit)でもOK。hover, focusで画像ロールオーバーさせる。

WebTecNote - [css] フォームのボタンをスタイルシートで画像ボタンに変更する

しかし、IE6以下の場合は動作しない(hover疑似クラスが機能しないため)。必要なら JavaScriptを加える必要がある。

grep(シェルコマンド)での論理和

egrep にして"|"を使えばOK。

postfixのログを検索している。

$ egrep "726D9220181|DDDEC220181|A9A91220181|8F6FF22071E|96A0522071D|D85A622074C|81E5822074B|8A89422074C|34A27220750|3883C22074E|AD2FD220750|B1A9F22074E|2288A22074F|2B57122074E|98C5322074E" /var/log/maillog.*

参考

3.6 Basic vs Extended Regular Expressions

In basic regular expressions the meta-characters ‘?’, ‘+’, ‘{’, ‘|’, ‘(’, and ‘)’ lose their special meaning; instead use the backslashed versions ‘\?’, ‘\+’, ‘\{’, ‘\|’, ‘\(’, and ‘\)’.

"grep"ではメタキャラクタの前に"\"が必要だが、"egrep"つまり "extended grep" なら不要、と。

2010年6月18日金曜日

autopair, paredit

職場のWindowsに導入してみた。

ついでに、選択範囲を上書きする (delete-selection-mode 1) も。

参考

  • http://trey-jackson.blogspot.com/2009/09/emacs-tip-33-paredit.html
  • http://emacs-fu.blogspot.com/2010/06/automatic-pairing-of-brackets-and.html
  • http://www.emacswiki.org/emacs/AutoPairs

課題

  • skkでの入力中は無効にしたい(カッコ/コッカが入力できないため) ← adviceで対応
(defadvice skk-mode (around disable-autopairs-around (arg))
  "Disable autopairs mode when skk-mode is on"
  ad-do-it
  (if skk-mode
      (autopair-mode 0)
    (autopair-mode 1)
    ))
(ad-activate 'skk-mode)

2010年6月7日月曜日

BOM の存在を消去する(Perlの場合)

BOM存在のチェックと、その除去を行うプログラム(Perl)

一口にBOMと言っても、エンコードに応じて実体は様々あるらしい(utf8なら 0xEF 0xBB 0xBF)

1. BOMチェックスクリプト

#!/usr/bin/perl
@bom = (
  chr(0x00).chr(0x00).chr(0xFE).chr(0xFF),
  chr(0xFF).chr(0xFE).chr(0x00).chr(0x00),
  chr(0x00).chr(0x00).chr(0xFF).chr(0xFE),
  chr(0xFE).chr(0xFF).chr(0x00).chr(0x00),
  chr(0xFE).chr(0xFF),
  chr(0xFF).chr(0xFE),
  chr(0xEF).chr(0xBB).chr(0xBF)
);

if(-f $ARGV[0]){
  open(FILE, $ARGV[0]) or die;
  $dat = <FILE>;
  for(my $i = 0; $i <= $#bom; $i++){
    if(index($dat, $bom[$i]) == 0){
      print "$ARGV[0]\n";
      last;
    }
  }
  close(FILE);
}

2. BOM除去スクリプト(いちおうバックアップを取る仕様)

#!/usr/bin/perl
if(-f $ARGV[0]){
    my $f = $ARGV[0];
    my $new = $f . '.new';
    my $flg = 1;
    open(OLD, $f) or die;
    open(NEW, "> $new")         or die "can't open $new: $!";
    while (<OLD>) {
        if($flg) {
            print NEW substr($_, 3) or die "can't write $new: $!";
            $flg = 0;
        } else {
            print NEW $_            or die "can't write $new: $!";
        }
    }
    close(OLD)                  or die "can't close $old: $!";
    close(NEW)                  or die "can't close $new: $!";
    rename($f, "$f.orig")       or die "can't rename $old to $old.orig: $!";
    rename($new, $f)            or die "can't rename $new to $old: $!";
} else {
    die 'no argument';
}

PHPのレアな関数

* error_get_last()
(PHP 5 >= 5.2.0)
error_get_last — 最後に発生したエラーを取得する。

* simplexml_load_file()
(PHP 5)
simplexml_load_file — XMLファイルをパースし、オブジェクトに代入する

* PHPバージョン5以上だとini_set()、.htaccessでallow_url_fopenを有効にできない
管理者にphp.iniを変更してもらわなければ file_get_contents() や simplexml_load_file() が使えない。
↓こんな感じのエラーが発生(failed to open steream

Array ( [type] => 2 [message] => file_get_contents(http://twitter.com/statuses/user_timeline/138673716.rss) [function.file-get-contents]: failed to open stream: no suitable wrapper could be found [file] => /virtual/www/2012/lib/twjson.php [line] => 12 )

2010年6月6日日曜日

Caching and Memoization

Higher Order Perl.

inline caching
memoization
marshalling
orcish maneuver ( || and cache 戦略、||= 演算子)
semipredicate problem

memoizationではsymbol tableも書き換えないといけない(再帰関数の場合に、内部で古い関数定義が呼び出されてしまうから)

"Partition problem" - 面白い例題。Chapter1, 3, 4 で徐々に改善されていく。NP-complete problem らしい(Nondeterministic Polynomial)

2010年6月3日木曜日

ul要素内のliをランダムに並び替えるJavaScript

  // random image
  if($('body#home').length){
    var ul = $('div.category > ul');
    if(!ul) return;

    var chi = ul.children();
    for(var i = 0, n = chi.length; i < n; i++){
      var r = Math.floor( i + Math.random() * (n - i) );
      var tmp = chi[i];
      chi[i] = chi[r];
      chi[r] = tmp;
    }

    ul.html(chi);
  }

htmlタグを除いてマルチバイト150文字にtruncateする関数

htmlタグを除き、さらにマルチバイト文字150文字を取り出す。


/********************************************************************************************
myTruncate() : 
- 用途 : truncate string considering HTML tag.
- 引数 : html string, maxlength, url
- 戻値 : truncated string
********************************************************************************************/
function myTruncate($html, $maxLength, $url) {
    $printedLength = 0;
    $position = 0;
    $tags = array();
    $printstr = '';

    mb_internal_encoding("UTF-8");

    // while ($printedLength < $maxLength && preg_match('{</?([a-z]+)[^>]*>|&#?[a-zA-Z0-9]+;}', $html, $match, PREG_OFFSET_CAPTURE, $position))
    // ここの preg_match を等価なマルチバイト処理に変更すればうまくいく(たぶん)
    while ($printedLength < $maxLength && $this->mb_preg_match('{</?([^>]+)>|&#?[a-zA-Z0-9]+;}', $html, $match, PREG_OFFSET_CAPTURE, $position))
        {
            list($tag, $tagPosition) = $match[0];

            // Print text leading up to the tag.
            $str = mb_substr($html, $position, $tagPosition - $position);
            if ($printedLength + mb_strlen($str) > $maxLength)
                {
                    //print(mb_substr($str, 0, $maxLength - $printedLength));
                    $printstr .= mb_substr($str, 0, $maxLength - $printedLength);
                    $printedLength = $maxLength;
                    break;
                }

            //print($str);
            $printstr .= $str;
            $printedLength += mb_strlen($str);

            if ($tag[0] == '&')
                {
                    // Handle the entity.
                    //print($tag);
                    $printstr .= $tag;
                    $printedLength++;
                }
            else
                {
                    // Handle the tag.
                    $tagName = $match[1][0];
                    $tagName = mb_ereg_replace(' .*', '', $tagName);
                    if ($tag[1] == '/')
                        {
                            // This is a closing tag.

                            $openingTag = array_pop($tags);
                            if($openingTag != $tagName) die;
                            assert($openingTag == $tagName); // check that tags are properly nested.

                            //print($tag);
                            $printstr .= $tag;
                        }
                    else if ($tag[mb_strlen($tag) - 2] == '/')
                        {
                            // Self-closing tag.
                            //print($tag);
                            $printstr .= $tag;
                        }
                    else
                        {
                            // Opening tag.
                            //print($tag);
                            $printstr .= $tag;
                            $tags[] = $tagName;
                        }
                }

            // Continue after the tag.
            $position = $tagPosition + mb_strlen($tag);
        }

    // Print any remaining text.
    if ($printedLength < $maxLength && $position < mb_strlen($html))
        //print(mb_substr($html, $position, $maxLength - $printedLength));
        $printstr .= mb_substr($html, $position, $maxLength - $printedLength);

    // Close any open tags.
    while (!empty($tags)) //printf('</%s>', array_pop($tags));
        $printstr .= sprintf('</%s>', array_pop($tags));

    if(mb_strlen($html) > mb_strlen($printstr)){
        $readmore = '<p class="nav"><a href="' . $url . '" title="続きを読む">続きを読む</a></p>';
    } else {
        $readmore = '';
    }

    return '<p>' . $printstr . '</p>' . $readmore;
}

2010年6月2日水曜日

Smarty反復構文での制御変数参照方法

for文のような、制御変数を明示的に利用する反復構文がない。

1. sectionを使う

{section name=cnt start=0 loop=10}
{$smarty.section.cnt.index}
{/section}

2. foreachのプロパティを使う

{foreach from=emps item=emp name=emploop}
{$smarty.foreach.emploop.index}
{/section}

どちらの場合も、breakとcontinueに相当するものはない。