つぶやき
技術系や雑感等は再編集して本文の記事にする事を前提としているので、こっちにLinkを張らないでください。
何がなにやら
今日は、なんか4つも同時に仕事をこなしてた。さすがに4本同時は無理があるようで、何が何だかちっとも判らなくなってしまった。
やっぱり同時に出来る仕事はせいぜい2つまでですね。
しかし、おかげで随分仕事は進んだので、今日の所はこのくらいで勘弁してやることにした(爆)
そろそろ帰って子供の顔がみたい。
のんびり
今日は一日子供の相手をして過ごした。とかいうと嫁さんが怒りますが。
明日でちょうど10ヶ月が過ぎるところだけど、子供って毎日毎日成長する。
今日は、家族で吉祥寺までお散歩に出かけましたが、風が吹けば喜び、建物に入れば暑がって泣き、まぁ、色々振り回してくれます。
そうそう、吉祥寺だけど、あそこは飽きない町ですなぁ。上野だの新宿だの渋谷だのに行かなくても吉祥寺でOKな気がしますね。
今度じっくり開拓せねば
しかし、やっぱり疲れが完全に取れたわけではない。この辺り、明日からが少し怖い。
お休み
まぁ、いつだって週末は休みなわけですが、特に今週は体調不良だったのもあって、昨日今日としっかり休みました。
まぁ、技術的コメントが多く出ているのは、休みすぎて寝られなくなったときのついでの作業という感じでしょうか。
実際、そんなに時間かけていないし。この程度は半分遊びだよね。ドキュメントもマニュアルも読まない範囲だもの。
しかし、それでもまだまだ疲労が抜けていない気がする…。というわけで、銭湯に行って一風呂浴びて寝ます。
Blikiを整理
Blikiの入力画面には特に何も記載されていないので、Templateが扱えるかどうかを確認してみた。
結論から言えば、このコードはそこまで考慮して書かれていないので、Templateを導入することは出来なかった。
そこまでの対応をするくらいなら1から書いた方が早いかもしれない。そんな時間はないので、今回はここで諦めよう。
しかし、最初からHeaderと末尾にTag位は入れたいなぁ。
そうそう、コードを読んでたらあまりにも整形されていなかったので、手で整形し直した。ついでに、無駄な判断分があったので、一部修正。
まぁ、あんまりにも小さな修正なので、影響は皆無だろう。ま、いいか。取りあえず貼り付けてみる。
$ cat ./syntax.php
<?php
/**
* bliki Plugin: Adds a simple blogging engine to your wiki
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Beau Lebens <beau@dentedreality.com.au>
* @author Anthony Caetano <Anthony.Caetano@Sanlam.co.za>
* @author HEO SeonMeyong <seirios.seirios.org>
*
*/
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
/**
* All DokuWiki plugins to extend the parser/rendering mechanism
* need to inherit from this class
*/
class syntax_plugin_bliki extends DokuWiki_Syntax_Plugin {
/**
* return some info
*/
function getInfo(){
return array(
'author' => 'Beau Lebens',
'email' => 'beau@dentedreality.com.au',
'date' => '2005-09-06',
'name' => 'Bliki: The Wiki Blog',
'desc' => 'Adds basic blogging functionality to any page of your wiki.',
'url' => 'http://www.dokuwiki.org/plugin:bliki',
);
}
/**
* What kind of syntax are we?
*/
function getType(){
return 'substition';
}
/**
* What kind of syntax do we allow (optional)
*/
function getAllowedTypes() {
return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
}
/**
* What about paragraphs? (optional)
*/
function getPType(){
return 'block';
}
/**
* Where to sort in?
*/
function getSort(){
return 400;
}
/**
* Connect pattern to lexer
*/
function connectTo($mode) {
$this->Lexer->addSpecialPattern('~~BLIKI~~', $mode, 'plugin_bliki');
}
/**
* Handle the match
*/
function handle($match, $state, $pos, &$handler){
return array();
}
/**
* @return Array
* @param String $ID
* @param Int $num
* @param Int $offset
* @desc Finds the full pathnames of the most recent $num posts, starting at the optional within the $ID blog/namespace.
*/
function getPosts($ID, $num, $offset = 0) {
global $conf;
$recents = array();
$counter = 0;
// fully-qaulify the ID that we're working with (to dig into the namespace)
$fp = wikiFN($ID);
$ID = substr($fp, 0, strrpos($fp, '.'));
// Only do it if the namespace exists
if (is_dir($ID . '/')) {
if ($conf['bliki']['structure'] == 'flat') {
$posts = $this->read_dir_to_array($ID . '/', 'file', '/^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}\.txt$/');
sort($posts);
while (sizeof($recents) < $num && sizeof($posts)) {
$post = array_pop($posts);
$counter++;
if ($counter > $offset) {
$recents[] = $ID . '/' . $post;
}
}
return $recents;
} else { // $conf['bliki']['structure'] == 'deep'
$years = $this->read_dir_to_array($ID . '/', 'dir');
sort($years);
// Now start working backwards through it all and get the most recent posts
while (sizeof($recents) < $num && sizeof($years)) {
$year = array_pop($years);
$months = $this->read_dir_to_array($ID . '/' . $year . '/', 'dir');
sort($months);
while (sizeof($recents) < $num && sizeof($months)) {
$month = array_pop($months);
$days = $this->read_dir_to_array($ID . '/' . $year . '/' . $month . '/', 'dir');
sort($days);
while (sizeof($recents) < $num && sizeof($days)) {
$day = array_pop($days);
$posts = $this->read_dir_to_array($ID . '/' . $year . '/' . $month . '/' . $day . '/',
'file',
'/^[0-9]{6}\.txt$/');
sort($posts);
while (sizeof($recents) < $num && sizeof($posts)) {
$post = array_pop($posts);
$counter++;
if ($counter > $offset) {
$recents[] = $ID . '/' . $year . '/' . $month . '/' . $day . '/' . $post;
}
}
}
}
}
return $recents;
}
}
}
/**
* @return String
* @param Array $list
* @desc Compiles the contents of all the files listed (as fully-qualified paths)
* in $list into a single string. Compiles in the order listed. Adds date headers
* where required and a footer after each post.
*/
function compilePosts($list) {
global $ID, $conf;
if (sizeof($list)) {
$last_date = false;
$str = '';
foreach ($list as $file) {
// Decide if we need to add a date divider
$file = str_replace('\\', '/', $file);
$ts = $this->getTimestampFromFile($file);
$date = date('Y-m-d', $ts);
if ($date != $last_date) {
$str .= $this->getDateHeader($ts);
$last_date = $date;
}
// Add this file's contents to the output
$str .= file_get_contents($file);
// And add a wiki-formatted footer of meta data as well, accounting for rewrites
$post_url = $this->getUrlPartFromTimestamp($ID, $ts);
$edit_url = $this->getRewriteUrl($post_url, 'do=edit', false);
$timestamp = date($conf['bliki']['datefooter'], $ts);
$str .= str_replace(array('{timestamp}', '{permalink}', '{edit}'), array($timestamp, $post_url, "this>$edit_url"), $conf['bliki']['footer']);
}
return $str;
} else {
return '';
}
}
/**
* @return String
* @param timestamp $ts
* @desc Returns a wiki-formatted date header for between posts.
*/
function getDateHeader($ts) {
global $conf;
$date = date($conf['bliki']['dateheader'], $ts);
return $date . "\n";
}
/**
* @return timestamp
* @param String $filename
* @desc Returns a timestamp based on the filename/namespace structure
*/
function getTimestampFromFile($file) {
global $conf;
if ($conf['bliki']['structure'] == 'flat') {
$parts = explode('-', basename($file));
$ts = mktime(substr($parts[3], 0, 2), substr($parts[3], 2, 2), substr($parts[3], 4, 2), $parts[1], $parts[2], $parts[0]);
} else { // $conf['bliki']['structure'] == 'deep'
$parts = explode('/', dirname($file));
$s = sizeof($parts);
$date = $parts[$s-3] . '-' . $parts[$s-2] . '-' . $parts[$s-1];
$filename = basename($file);
$ts = mktime(substr($filename, 0, 2), substr($filename, 2, 2), substr($filename, 4, 2), $parts[$s-2], $parts[$s-1], $parts[$s-3]);
}
return $ts;
}
/**
* @return String
* @param String $ID
* @param timestamp $ts
* @desc Returns a post url for a post based on the post's timestamp and the base ID
*/
function getUrlPartFromTimestamp($ID, $ts=0) {
global $conf;
if ($ts == 0) {
$ts = time();
}
if ($conf['userewrite'] > 0) {
$sep = ($conf['useslash'] == true ? '/' : ':');
} else {
$sep = ':';
}
if ($conf['bliki']['structure'] == 'flat') {
return $ID . $sep . date('Y-m-d-His', $ts);
} else { // $conf['bliki']['structure'] == 'deep'
return $ID . $sep . date('Y' . $sep . 'm' . $sep . 'd' . $sep . 'His', $ts);
}
}
/**
* @return String
* @param String $url
* @param String $query
* @desc Returns a url properly prefixed according to the $conf['rewrite'] option
* A $page is an appropriately constructed (namespace inclusive and considering $conf['useslash']) page reference
* A $query contains a query string parameters to append
*/
function getRewriteUrl($page, $query, $base = true) {
global $conf;
if ($base) {
$str = DOKU_BASE;
}
if ($conf['userewrite'] == 0) {
$str .= DOKU_SCRIPT . '?id=' . $page;
if ($query != '') {
$str .= '&' . $query;
}
} else if ($conf['userewrite'] == 1) {
$str .= idfilter($page, false);
if ($query != '') {
$str .= '?' . $query;
}
} else {
$str .= DOKU_SCRIPT . '/' . idfilter($page, false);
if ($query != '') {
$str .= '?' . $query;
}
}
return $str;
}
/**
* @return String
* @param String $label
* @desc Creates the HTML required for the "New Post" link, using the lable provided.
*/
function newPostLink($label) {
global $conf, $ID;
$sep = ($conf['useslash'] == true ? '/' : ':');
$html = '<div id="blognew"><a href="';
$html .= $this->getRewriteUrl($this->getUrlPartFromTimestamp($ID, time() + (isset($conf['bliki']['offset']) ? ($conf['bliki']['offset'] * 3600) : 0)), 'do=edit');
$html .= '">' . $label . '</a></div>';
return $html;
}
/**
* @return String
* @param Int $page
* @param String $label
* @desc Creates the HTML required for a link to an older/newer page of posts.
*/
function pagingLink($page, $label) {
global $conf, $ID;
$html = '<a href="';
$html .= $this->getRewriteUrl($ID, "page=$page");
$html .= '">' . $label . '</a>';
return $html;
}
/**
* @return Array
* @param String $dir
* @param String $select
* @param String $match
* @desc Reads all entries in a directory into an array, sorted alpha, dirs then files.
* $select is used to selects either only dir(ectories), file(s) or both
* If $match is supplied, it should be a / delimited regex to match the filename against
*/
function read_dir_to_array($dir, $select = 'both', $match = false) {
$files = array();
$dirs = array();
// Read all the entries in the directory specified
$handle = @opendir($dir);
if (!$handle) {
return false;
}
while ($file = @readdir($handle)) {
// Ignore self and parent references
if ($file != '.' && $file != '..') {
if (($select == 'both' || $select == 'dir') && is_dir($dir . $file)) {
$dirs[] = $file;
} else if (($select == 'both' || $select == 'file') && !is_dir($dir . $file)) {
if (is_string($match)) {
if (!preg_match($match, $file)) {
continue;
}
}
$files[] = $file;
}
}
}
@closedir($handle);
// Sort anything found alphabetically and combine the results (dirs->files)
if (sizeof($dirs) > 0) {
sort($dirs, SORT_STRING);
}
if (sizeof($files) > 0) {
sort($files, SORT_STRING);
}
// Put the directories and files back together and return them
return array_merge($dirs, $files);
}
/**
* Create output
*/
function render($mode, &$renderer, $data) {
global $ID, $conf;
// Set the page number (determines which posts we display)
if (isset($_REQUEST['page'])) {
$page = $_REQUEST['page'];
} else {
$page = 0;
}
if ($mode == 'xhtml') {
// Addlink for creating a new post
$renderer->doc .= $this->newPostLink($conf['bliki']['newlabel']);
// Go and get the required blog posts and compile them into one wikitext string
// FIXME $config var for how many? or inline directive?
$recents = $this->getPosts($ID, $conf['bliki']['numposts'], ($page * $conf['bliki']['numposts']));
$compiled = $this->compilePosts($recents);
// Disable section editing to avoid weird links
$conf['maxseclevel'] = 0;
// Disbale caching because we need to get new files always
$renderer->info['cache'] = false;
// Add the compiled blog posts after rendering them.
$renderer->doc .= p_render('xhtml', p_get_instructions($compiled), $info);
// Add a link to older entries if we filled the number per page (assuming there's more)
if (sizeof($recents) == $conf['bliki']['numposts']) {
$renderer->doc .= '<div id="blogolder">' . $this->pagingLink($page+1, $conf['bliki']['olderlabel']) . '</div>';
}
// And also a link to newer posts if we're not on page 0
if ($page != 0) {
$renderer->doc .= '<div id="blognewer">' . $this->pagingLink($page-1, $conf['bliki']['newerlabel']) . '</div>';
}
return true;
}
return false;
}
}
?>
$
DokuWiki 日本語強化
参照URL: http://www.higuchi.com/dokuwiki/dokuwiki:localize
- MailのEncodeをISO-2022-jpにする
- 今回、これを導入しなかった。だって、ja=iso2022-jpって言えないし。だからってiso2022-jpに固定するのもどうよ?
- 検索の日本語化
- pkgsrcからMecabを入れる
- /etc/mk.confにMECAB_CHARSET= utf-8 を忘れずに設定すること
- inc/indexer.phpに以下の変更を加える
$ diff -c ./indexer.php.orig ./indexer.php *** ./indexer.php.orig Sat Feb 7 21:48:34 2009 --- ./indexer.php Sat Feb 7 22:02:14 2009 *************** *** 6,11 **** --- 6,15 ---- * @author Andreas Gohr <andi@splitbrain.org> */ + /* for Japanese index search with Mecab */ + define ('PRE_TOKENIZER', '/usr/pkg/bin/mecab -O wakati'); + /* ------------------------------------ */ + if(!defined('DOKU_INC')) die('meh.'); require_once(DOKU_INC.'inc/io.php'); require_once(DOKU_INC.'inc/utf8.php'); *************** *** 55,62 **** --- 59,70 ---- $l = strlen($w); // If left alone, all chinese "words" will get put into w3.idx // So the "length" of a "word" is faked + /* for Japanese index search with Mecab */ + /* if(preg_match('/'.IDX_ASIAN2.'/u',$w)) $l += ord($w) - 0xE1; // Lead bytes from 0xE2-0xEF + */ + /* ------------------------------------ */ return $l; } *************** *** 220,225 **** --- 228,257 ---- list($page,$body) = $data; + /* for Japanese index search with Mecab */ + if(function_exists(proc_open) && defined('PRE_TOKENIZER')) { + $dspec = array( + 0 => array("pipe", "r"), + 1 => array("pipe", "w"), + 2 => array("file", "/dev/null", "w") + ); + $process = proc_open(PRE_TOKENIZER, $dspec, $pipes); + if(is_resource($process)) { + stream_set_blocking($pipes[0], FALSE); + stream_set_blocking($pipes[1], FALSE); + fwrite($pipes[0], $body . "\n"); + fclose($pipes[0]); + + $body = ''; + while(!feof($pipes[1])) { + $body .= fgets($pipes[1], 32768); + } + fclose($pipes[1]); + proc_close($process); + } + } + /* ------------------------------------ */ + $body = strtr($body, "\r\n\t", ' '); $tokens = explode(' ', $body); $tokens = array_count_values($tokens); // count the frequency of each token *************** *** 489,495 **** --- 521,532 ---- $wild |= 2; $wlen -= 1; } + /* for Japanese index search with Mecab */ + /* if ($wlen < IDX_MINWORDLENGTH && $wild == 0 && !is_numeric($xword)) continue; + */ + if (preg_match('/[^0-9A-Za-z]/u', $string) && $wlen < IDX_MINWORDLENGTH && $wild == 0 && !is_numeric($xword)) continue; + /* ------------------------------------ */ if(!isset($tokens[$xword])){ $tokenlength[$wlen][] = $xword; } *************** *** 628,639 **** --- 665,701 ---- */ function idx_tokenizer($string,&$stopwords,$wc=false){ $words = array(); + /* for Japanese index search with Mecab */ + if(function_exists(proc_open) && defined('PRE_TOKENIZER')) { + $dspec = array( + 0 => array("pipe", "r"), + 1 => array("pipe", "w"), + 2 => array("file", "/dev/null", "w") + ); + $process = proc_open(PRE_TOKENIZER, $dspec, $pipes); + if(is_resource($process)) { + stream_set_blocking($pipes[0], FALSE); + stream_set_blocking($pipes[1], FALSE); + fwrite($pipes[0], $string . "\n"); + fclose($pipes[0]); + $string = ''; + while(!feof($pipes[1])) { + $string .= fgets($pipes[1], 32768); + } + fclose($pipes[1]); + proc_close($process); + } + } + /* ------------------------------------ */ $wc = ($wc) ? '' : $wc = '\*'; if(preg_match('/[^0-9A-Za-z]/u', $string)){ + /* for Japanese index search with Mecab */ + /* // handle asian chars as single words (may fail on older PHP version) $asia = @preg_replace('/('.IDX_ASIAN.')/u',' \1 ',$string); if(!is_null($asia)) $string = $asia; //recover from regexp failure + */ $arr = explode(' ', utf8_stripspecials($string,' ','\._\-:'.$wc)); foreach ($arr as $w) {
こんなんでどうだろう…。
