powered by nequal
Home » Net_KyotoTycoon » Timeline » 2237

Changeset 2237 -- 2010-11-09 22:39:03

Comment
[Package Release] Net_KyotoTycoon

Diffs

Net_KyotoTycoon/tags/release-0.0.1-20101109223903/HTTP/TsvRpc/Parser.php

@@ -0,0 +1,139 @@
+<?php
+/**
+ * TSV-RPC parser.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Shinya Ohyanagi nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use       HTTP\TsvRpc
+ * @category  HTTP
+ * @package   HTTP\TsvRpc
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+
+namespace HTTP\TsvRpc;
+use HTTP\TsvRpc;
+
+/**
+ * TSV-RPC parser.
+ *
+ * <pre>
+ *   This module is port from Perl TSVRPC::Parser
+ *   See also @link.
+ * </pre>
+ *
+ * @use       HTTP\TsvRpc
+ * @category  HTTP
+ * @package   HTTP\TsvRpc
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+class Parser
+{
+    /**
+     * Encode plain array to TSV with $encoding.
+     *
+     * @param  array $data Array data to encode
+     * @param  mixed $encoding Encode type
+     * @access public
+     * @return String Encoded string
+     */
+    public function encodeTsvrpc(array $data, $encoding = null)
+    {
+        $encoders = array(
+            'U' => function($value) { return urlencode($value); },
+            'Q' => function($value) { return quoted_printable_encode($value); },
+            'B' => function($value) { return base64_encode($value); }
+        );
+
+        if (isset($encoders[$encoding])) {
+            $encoder = $encoders[$encoding];
+        } else {
+            // When $encoding is not in $encoders, nothing to do.
+            $encoder = function($value) { return $value; };
+        }
+        $res = array();
+        foreach ($data as $k => $v) {
+            $res[] = $encoder($k) . "\t" . $encoder($v);
+        }
+
+        return implode("\n", $res);
+    }
+
+    /**
+     * Decode TSV to plain array.
+     *
+     * @param  mixed $data String data to decode
+     * @param  mixed $encoding Encode type
+     * @access public
+     * @return array Decoded data
+     */
+    public function decodeTsvrpc($data, $encoding = null)
+    {
+        $decoders = array(
+            'U' => function($value) { return urldecode($value); },
+            'Q' => function($value) { return quoted_printable_decode($value); },
+            'B' => function($value) { return base64_decode($value); }
+        );
+
+        if (isset($decoders[$encoding])) {
+            $decoder = $decoders[$encoding];
+        } else {
+            // When $encoding is not in $decoders, nothing to do.
+            $decoder = function($value) { return $value; };
+        }
+        $res = array();
+        if ($data === '') {
+            return $res;
+        }
+
+        $lines = explode("\n", $data);
+        foreach ($lines as $line) {
+            if ($line === '') {
+                continue;
+            }
+
+            list($k, $v) = array_map($decoder, explode("\t", $line));
+            $res[$k] = $v;
+        }
+
+        return $res;
+    }
+}

Net_KyotoTycoon/tags/release-0.0.1-20101109223903/HTTP/TsvRpc/Util.php

@@ -0,0 +1,86 @@
+<?php
+/**
+ * TSV-RPC util.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Shinya Ohyanagi nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use       HTTP\TsvRpc
+ * @category  HTTP
+ * @package   HTTP\TsvRpc
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+
+namespace HTTP\TsvRpc;
+use HTTP\TsvRpc;
+
+/**
+ * TSV-RPC util.
+ *
+ * <pre>
+ *   This module is port from Perl TSVRPC::Parser
+ *   See also @link.
+ * </pre>
+ *
+ * @use       HTTP\TsvRpc
+ * @category  HTTP
+ * @package   HTTP\TsvRpc
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+class Util
+{
+    /**
+     * Parse content-type.
+     *
+     * @param  mixed $contentType Content-type
+     * @access public
+     * @return mixed B|U|Q|'' or null
+     */
+    public static function parseContentType($contentType)
+    {
+        $pattern = '#text/tab-separated-values(?:; colenc=([BUQ]))?#';
+        if (preg_match_all($pattern, $contentType, $match)) {
+            return isset($match[1][0]) ? $match[1][0] : '';
+        }
+
+        return null;
+    }
+}

Net_KyotoTycoon/tags/release-0.0.1-20101109223903/HTTP/TsvRpc/Client.php

@@ -0,0 +1,223 @@
+<?php
+/**
+ * TSV-RPC client library.
+ *
+ * This module is port from Perl Cache::KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Shinya Ohyanagi nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use       HTTP\TsvRpc\Parser
+ * @use       HTTP\TsvRpc\Util
+ * @category  HTTP
+ * @package   HTTP\TsvRpc
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace HTTP\TsvRpc;
+use HTTP\TsvRpc\Parser,
+    HTTP\TsvRpc\Util,
+    HTTP\TsvRpc\Exception;
+
+/**
+ * Client
+ *
+  * <pre>
+ *   This module is port from Perl Cache::KyotoTycoon.
+ *   See also @link.
+ * </pre>
+ *
+ * @use       HTTP\TsvRpc\Parser
+ * @use       HTTP\TsvRpc\Util
+ * @category  HTTP
+ * @package   HTTP\TsvRpc
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class Client
+{
+    /**
+     * Version.
+     */
+    const VERSION = '0.0.3';
+
+    /**
+     * Base url.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_base = null;
+
+    /**
+     * HTTP Client.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_client = null;
+
+    /**
+     * Content-Type parser.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_parser = null;
+
+    /**
+     * Last content data.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_lastContent = null;
+
+    /**
+     * Constructor
+     *
+     * @param  array $args
+     * @access public
+     * @return void
+     */
+    public function __construct(array $args)
+    {
+        spl_autoload_register(array(__CLASS__, 'autoload'));
+        $base = '';
+        if (isset($args['base'])) {
+            $base = $args['base'];
+        } else {
+            throw new Exception("Missing argument named 'base' for rpc base url.");
+        }
+        $base    = rtrim($base, '\//') . '/';
+        $timeout = isset($args['timeout']) ? $args['timeout'] : 1;
+        $agent   = isset($args['agent']) ?: __CLASS__ . '/' . self::VERSION;
+
+        $adapter = isset($args['adapter']) ?: 'HTTP_Request2_Adapter_Socket';
+        $config  = array('adapter' => $adapter, 'timeout' => $timeout);
+        $client  = new \HTTP_Request2(
+            null, \HTTP_Request2::METHOD_POST, $config
+        );
+        $client->setHeader('user-agent', $agent);
+
+        $this->_client = $client;
+        $this->_base   = $base;
+        $this->_parser = new Parser();
+    }
+
+    /**
+     * Send request.
+     *
+     * @param  mixed $method Rpc method
+     * @param  mixed $args Args
+     * @param  string $encoding B(base64), U(Urlencode), Q(Quoted printable)
+     * @access public
+     * @return mixed Status code and HTTP body
+     */
+    public function call($method, $args = array(), $encoding = 'B')
+    {
+        $content = $this->_parser->encodeTsvrpc($args, $encoding);
+        $client  = $this->_client;
+        $uri     = $this->_base . $method;
+        $headers = array(
+            'Content-Type'   => "text/tab-separated-values; colenc=$encoding",
+            'Content-Length' => strlen($content),
+            'Connection'     => 'Keep-Alive',
+            'Keep-Alive'     => 300,
+        );
+        $client->setHeader($headers)->setUrl($uri)->setBody($content);
+        $response = $client->send();
+        if ($response) {
+            $code            = $response->getStatus();
+            $responseHeaders = $response->getHeader();
+            $contentType     = $responseHeaders['content-type'];
+            $resEncoding     = Util::parseContentType($contentType);
+
+            // Decode by content-type B|Q|U
+            $body = $this->_parser->decodeTsvrpc(
+                $response->getBody(), $resEncoding
+            );
+            $this->_lastContent = $body;
+            return array('code' => $code, 'body' => $body);
+        }
+
+        throw new Exception('Fail to call ' . $uri);
+    }
+
+    /**
+     * Get last content.
+     *
+     * <pre>
+     *   This is a debug method.
+     * </pre>
+     *
+     * @access public
+     * @return mixed
+     */
+    public function getLastContent()
+    {
+        return $this->_lastContent;
+    }
+
+    /**
+     * Autoload class.
+     *
+     * @param  mixed $class
+     * @access public
+     * @return void
+     */
+    public static function autoload($className)
+    {
+        // Autoload class.
+        // http://groups.google.com/group/php-standards/web/psr-0-final-proposal
+        if (!class_exists($className, false)) {
+            $className = ltrim($className, '\\');
+            $fileName  = '';
+            $namespace = '';
+            if ($lastNsPos = strripos($className, '\\')) {
+                $namespace = substr($className, 0, $lastNsPos);
+                $className = substr($className, $lastNsPos + 1);
+                $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
+            }
+            $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
+            require_once $fileName;
+        }
+    }
+}

Net_KyotoTycoon/tags/release-0.0.1-20101109223903/HTTP/TsvRpc/Exception.php

@@ -0,0 +1,62 @@
+<?php
+/**
+ * Exception for \HTTP\TsvRpc.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Shinya Ohyanagi nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use       HTTP\TsvRpc
+ * @category  HTTP
+ * @package   HTTP\TsvRpc
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ */
+
+namespace HTTP\TsvRpc;
+
+/**
+ * Exception.
+ *
+ * @use       HTTP\TsvRpc
+ * @category  HTTP
+ * @package   HTTP\TsvRpc
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ */
+class Exception extends \Exception
+{
+}

Net_KyotoTycoon/tags/release-0.0.1-20101109223903/Net/KyotoTycoon/Cursor.php

@@ -0,0 +1,399 @@
+<?php
+/**
+ * Cursor class for KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Shinya Ohyanagi nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use       Net\KyotoTycoon
+ * @category  Net
+ * @package   Net\KyotoTycoon
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace Net\KyotoTycoon;
+use Net\KyotoTycoon;
+
+/**
+ * Cursor class for KyotoTycoon.
+ *
+ * <pre>
+ *   This module is port from Perl Cache::KyotoTycoon.
+ *   See also @link.
+ * </pre>
+ *
+ * @use       Net\KyotoTycoon
+ * @category  Net
+ * @package   Net\KyotoTycoon
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+
+ */
+class Cursor
+{
+    /**
+     * Db.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_db = null;
+
+    /**
+     * Cursor.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_cursor = null;
+
+    /**
+     * Client.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_client = null;
+
+    /**
+     * Status Code.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_statusCode = null;
+
+    /**
+     * Construct.
+     *
+     * @param  mixed $id
+     * @param  mixed $db
+     * @param  mixed $client
+     * @access public
+     * @return void
+     */
+    public function __construct($id, $db, $client)
+    {
+        $this->_db     = $db;
+        $this->_client = $client;
+        $this->_cursor = $id;
+
+        // Status code.
+        $this->_statusCode = new StatusCode();
+    }
+
+    /**
+     * Get error message.
+     *
+     * @param  mixed $code Status code
+     * @access private
+     * @return String Error message
+     */
+    private function _errmsg($code)
+    {
+        return $this->_statusCode->errmsg($code);
+    }
+
+    /**
+     * Call jump.
+     *
+     * <pre>
+     *   Jump the cursor to the first record for forward scan.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @access public
+     * @return mixed
+     */
+    public function jump($key = null)
+    {
+        $args = array('DB' => $this->_db, 'CUR' => $this->_cursor);
+        if (!is_null($key)) {
+            $args['key'] = $key;
+        }
+        $response = $this->_client->call('cur_jump', $args);
+
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call jump_back.
+     *
+     * <pre>
+     *   Jump the cursor to the last record for backward scan.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @access public
+     * @return mixed
+     */
+    public function jumpBack($key = null)
+    {
+        $args = array('DB' => $this->_db, 'CUR' => $this->_cursor);
+        if (!is_null($key)) {
+            $args['key'] = $key;
+        }
+        $response = $this->_client->call('cur_jump_back', $args);
+
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call step.
+     *
+     * <pre>
+     *   Step the cursor to the next record.
+     * </pre>
+     *
+     * @access public
+     * @return mixed
+     */
+    public function step()
+    {
+        $args     = array('CUR' => $this->_cursor);
+        $response = $this->_client->call('cur_step', $args);
+
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call step_back.
+     *
+     * <pre>
+     *   Step the cursor to the previous record.
+     * </pre>
+     *
+     * @access public
+     * @return mixed
+     */
+    public function stepBack()
+    {
+        $args     = array('CUR' => $this->_cursor);
+        $response = array('code' => 0, 'body' => null);
+        $response = $this->_client->call('cur_step_back', $args);
+
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call set_value.
+     *
+     * <pre>
+     *   Set the value of the current record.
+     * </pre>
+     *
+     * @param  mixed $value
+     * @param  mixed $xt
+     * @param  mixed $step
+     * @access public
+     * @return mixed
+     */
+    public function setValue($value, $xt = null, $step = null)
+    {
+        $args = array('CUR' => $this->_cursor, 'value' => $value);
+        if (!is_null($xt)) {
+            $args['xt'] = $xt;
+        }
+        if (!is_null($step)) {
+            $args['step'] = '';
+        }
+
+        $response = $this->_client->call('cur_set_value', $args);
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call remove.
+     *
+     * <pre>
+     *   Remove the current record.
+     * </pre>
+     *
+     * @access public
+     * @return mixed
+     */
+    public function remove()
+    {
+        $args     = array('CUR' => $this->_cursor);
+        $response = $this->_client->call('cur_remove', $args);
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call get_key.
+     *
+     * <pre>
+     *   Get the key of the current record.
+     * </pre>
+     *
+     * @param  mixed $step
+     * @access public
+     * @return mixed
+     */
+    public function getKey($step = null)
+    {
+        $args = array('CUR' => $this->_cursor);
+        if (!is_null($step)) {
+            $args['step'] = '';
+        }
+        $response = $this->_client->call('cur_get_key', $args);
+
+        if ($response['code'] === 200) {
+            return $response['body']['key'];
+        } else if ($response['code'] === 450) {
+            return null;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call get_value.
+     *
+     * <pre>
+     *   Get the value of the current record.
+     * </pre>
+     *
+     * @param  mixed $step
+     * @access public
+     * @return mixed
+     */
+    public function getValue($step = null)
+    {
+        $args = array('CUR' => $this->_cursor);
+        if (!is_null($step)) {
+            $args['step'] = '';
+        }
+        $response = $this->_client->call('cur_get_value', $args);
+
+        if ($response['code'] === 200) {
+            return $response['body']['value'];
+        } else if ($response['code'] === 450) {
+            return null;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call get.
+     *
+     * <pre>
+     *   Get a pair of the key and the value of the current record.
+     * </pre>
+     *
+     * @param  mixed $step
+     * @access public
+     * @return mixed
+     */
+    public function get($step = null)
+    {
+        $args = array('CUR' => $this->_cursor);
+        if (!is_null($step)) {
+            $args['step'] = '';
+        }
+
+        $response = $this->_client->call('cur_get', $args);
+        if ($response['code'] === 200) {
+            return array($response['body']['key'], $response['body']['value']);
+        } else if ($response['code'] === 450) {
+            return null;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call delete.
+     *
+     * <pre>
+     *   Delete the cursor immidiately.
+     * </pre>
+     *
+     * @access public
+     * @return mixed Fluent interface or error message.
+     */
+    public function delete()
+    {
+        $args     = array('CUR' => $this->_cursor);
+        $response = $this->_client->call('cur_delete', $args);
+        if ($response['code'] === 200) {
+            return $this;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+}

Net_KyotoTycoon/tags/release-0.0.1-20101109223903/Net/KyotoTycoon/Exception.php

@@ -0,0 +1,66 @@
+<?php
+/**
+ * Exception for \Net\KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Shinya Ohyanagi nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use       Net
+ * @use       KyotoTycoon
+ * @category  Net
+ * @package   \Net\KyotoTycoon
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ */
+
+namespace Net\KyotoTycoon;
+use Net,
+    KyotoTycoon;
+
+/**
+ * Exception.
+ *
+ * @use       Net
+ * @use       KyotoTycoon
+ * @category  Net
+ * @package   \Net\KyotoTycoon
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ */
+class Exception extends \Exception
+{
+}

Net_KyotoTycoon/tags/release-0.0.1-20101109223903/Net/KyotoTycoon/StatusCode.php

@@ -0,0 +1,140 @@
+<?php
+/**
+ * Status code for \Net\KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Shinya Ohyanagi nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use       Net\KyotoTycoon
+ * @category  Net
+ * @package   Net\KyotoTycoon
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace Net\KyotoTycoon;
+use Net\KyotoTycoon;
+
+/**
+ * StatusCode
+ *
+ * @use       Net\KyotoTycoon
+ * @category  Net
+ * @package   Net\KyotoTycoon
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class StatusCode
+{
+    /**
+     * Status code.
+     *
+     * @var    array
+     * @access private
+     */
+    private $_statusCode = array(
+        100 => 'Continue',
+        101 => 'Switching Protocols',
+        102 => 'Processing',                      // RFC 2518 (WebDAV)
+        200 => 'OK',
+        201 => 'Created',
+        202 => 'Accepted',
+        203 => 'Non-Authoritative Information',
+        204 => 'No Content',
+        205 => 'Reset Content',
+        206 => 'Partial Content',
+        207 => 'Multi-Status',                    // RFC 2518 (WebDAV)
+        300 => 'Multiple Choices',
+        301 => 'Moved Permanently',
+        302 => 'Found',
+        303 => 'See Other',
+        304 => 'Not Modified',
+        305 => 'Use Proxy',
+        307 => 'Temporary Redirect',
+        400 => 'Bad Request',
+        401 => 'Unauthorized',
+        402 => 'Payment Required',
+        403 => 'Forbidden',
+        404 => 'Not Found',
+        405 => 'Method Not Allowed',
+        406 => 'Not Acceptable',
+        407 => 'Proxy Authentication Required',
+        408 => 'Request Timeout',
+        409 => 'Conflict',
+        410 => 'Gone',
+        411 => 'Length Required',
+        412 => 'Precondition Failed',
+        413 => 'Request Entity Too Large',
+        414 => 'Request-URI Too Large',
+        415 => 'Unsupported Media Type',
+        416 => 'Request Range Not Satisfiable',
+        417 => 'Expectation Failed',
+        422 => 'Unprocessable Entity',            // RFC 2518 (WebDAV)
+        423 => 'Locked',                          // RFC 2518 (WebDAV)
+        424 => 'Failed Dependency',               // RFC 2518 (WebDAV)
+        425 => 'No code',                         // WebDAV Advanced Collections
+        426 => 'Upgrade Required',                // RFC 2817
+        449 => 'Retry with',                      // unofficial Microsoft
+        500 => 'Internal Server Error',
+        501 => 'Not Implemented',
+        502 => 'Bad Gateway',
+        503 => 'Service Unavailable',
+        504 => 'Gateway Timeout',
+        505 => 'HTTP Version Not Supported',
+        506 => 'Variant Also Negotiates',         // RFC 2295
+        507 => 'Insufficient Storage',            // RFC 2518 (WebDAV)
+        509 => 'Bandwidth Limit Exceeded',        // unofficial
+        510 => 'Not Extended',                    // RFC 2774
+    );
+
+    /**
+     * Error message.
+     *
+     * @param  mixed $code Status code
+     * @access private
+     * @return String Error message
+     */
+    public function errmsg($code)
+    {
+        $msg = isset($this->_statusCode[$code]) ?: 'Unknown';
+        return sprintf(
+            'Net\KyotoTycoon unexpected response code: %s %s', $code, $msg
+        );
+    }
+}

Net_KyotoTycoon/tags/release-0.0.1-20101109223903/Net/KyotoTycoon.php

@@ -0,0 +1,735 @@
+<?php
+/**
+ * KyotoTycoon client library.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Shinya Ohyanagi nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use       Net
+ * @category  Net
+ * @package   Net\KyotoTycoon
+ * @version   $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://fallabs.com/kyototycoon/
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+namespace Net;
+use Net\KyotoTycoon\StatusCode,
+    Net\KyotoTycoon\Exception,
+    Net\KyotoTycoon\Cursor,
+    HTTP\TsvRpc\Client;
+
+/**
+ * KyotoTycoon
+ *
+ * <pre>
+ *   This module is port from Perl Cache::KyotoTycoon.
+ *   See also @link.
+ * </pre>
+ *
+ * @use       Net
+ * @category  Net
+ * @package   Net\KyotoTycoon
+ * @version   $id$
+ * @copyright 2010 Shinya Ohyanagi
+ * @author    Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license   New BSD License
+ * @link      http://fallabs.com/kyototycoon/
+ * @link      http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class KyotoTycoon
+{
+    /**
+     * Version.
+     */
+    const VERSION = '0.0.1';
+
+    /**
+     * Status code.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_statusCode = null;
+
+    /**
+     * Client.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_client = null;
+
+    /**
+     * Db.
+     *
+     * @var    mixed
+     * @access private
+     */
+    private $_db = null;
+
+    /**
+     * Error message.
+     *
+     * @param  mixed $code Status code.
+     * @access private
+     * @return String Error message.
+     */
+    private function _errmsg($code)
+    {
+        return $this->_statusCode->errmsg($code);
+    }
+
+    /**
+     * Create client to access KyotoTycoon.
+     *
+     * @param  array $args
+     * @access public
+     * @return void
+     */
+    public function __construct(array $args = array())
+    {
+        spl_autoload_register(array(__CLASS__, 'autoload'));
+        $host    = isset($args['host']) ? $args['host'] : '127.0.0.1';
+        $port    = isset($args['port']) ? $args['port'] : 1978;
+        $base    = "http://$host:$port/rpc/";
+        $timeout = isset($args['timeout']) ? $args['timeout'] : 1;
+        $client  = new Client(
+            array(
+                'timeout' => $timeout,
+                'base'    => $base
+            )
+        );
+
+        $this->_db         = 0;
+        $this->_client     = $client;
+        $this->_statusCode = new StatusCode();
+    }
+
+    /**
+     * Set TSV-RPC client.
+     *
+     * @param  mixed $client TSV-RPC client
+     * @access public
+     * @return \Net\KyotoTycoon Fluent interface
+     */
+    public function setClient($client)
+    {
+        $this->_client = $client;
+        return $this;
+    }
+
+    /**
+     * Set db.
+     *
+     * @param  mixed $db
+     * @access public
+     * @return \Net\KyotoTycoon Fluent interface.
+     */
+    public function db($db)
+    {
+        $this->_db = $db;
+        return $this;
+    }
+
+    /**
+     * Make cursor
+     *
+     * @param  mixed $id
+     * @access public
+     * @return \Net\KyotoTycoon\Cursor
+     */
+    public function makeCursor($id)
+    {
+        $cursor = new Cursor($id, $this->_db, $this->_client);
+        return $cursor;
+    }
+
+    /**
+     * Call echo.
+     *
+     * <pre>
+     *   Echo back the input data as the output data
+     *   echo() is reserved name in PHP. This method is same as echo().
+     * </pre>
+     *
+     * @param  mixed $args
+     * @access public
+     * @return mixed Response of RPC call
+     */
+    public function echoBack($args)
+    {
+        $response = $this->_client->call('echo', $args);
+        if ($response['code'] !== 200) {
+            return $this->_errmsg($response['code']);
+        }
+
+        return $response['body'];
+    }
+
+    /**
+     * Call report.
+     *
+     * <pre>
+     *   Get the report of the server information.
+     * </pre>
+     *
+     * @access public
+     * @return mixed Response of RPC call
+     */
+    public function report()
+    {
+        $response = $this->_client->call('report');
+        if ($response['code'] !== 200) {
+            return $this->_errmsg($response['code']);
+        }
+
+        return $response['body'];
+    }
+
+    /**
+     * Call play_script.
+     *
+     * <pre>
+     *   Call a procedure of the scripting extension.
+     * </pre>
+     *
+     * @param  mixed $name
+     * @param  array $input
+     * @access public
+     * @return mixed Response of RPC call
+     */
+    public function playScript($name, array $input)
+    {
+        $args = array('name' => $name);
+        foreach ($input as $k => $v) {
+            $args["_$k"] = $v;
+        }
+        $response = $this->_client->call('play_script', $args);
+        if ($response['code'] !== 200) {
+            return $this->_errmsg($response['code']);
+        }
+        $body = $response['body'];
+        $res  = array();
+        foreach ($body as $k => $v) {
+            $res[ltrim($k, '_')] = $v;
+        }
+
+        return $res;
+    }
+
+    /**
+     * Call status.
+     *
+     * <pre>
+     *   Get the miscellaneous status information.
+     * </pre>
+     *
+     * @access public
+     * @return mixed Response of RPC call
+     */
+    public function status()
+    {
+        $response = $this->_client->call('status', array('DB' => $this->_db));
+        if ($response['code'] !== 200) {
+            return $this->_errmsg($response['code']);
+        }
+
+        return $response['body'];
+    }
+
+    /**
+     * Call clear
+     *
+     * <pre>
+     *   Remove all records.
+     * </pre>
+     *
+     * @access public
+     * @return mixed Fluent interface when clear success or error message.
+     */
+    public function clear()
+    {
+        $response = $this->_client->call('clear', array('DB' => $this->_db));
+        if ($response['code'] !== 200) {
+            return $this->_errmsg($response['code']);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Call synchronize
+     *
+     * <pre>
+     *   Synchronize updated contents with the file and the device.
+     * </pre>
+     *
+     * @param  mixed $hard
+     * @param  mixed $command
+     * @access public
+     * @return mixed Status 200 return true, status 450 return false
+     */
+    public function synchronize($hard = null, $command = null)
+    {
+        $args = array('DB' => $this->_db);
+        $args['hard'] = $hard;
+        if (!is_null($command)) {
+            $args['command'] = $command;
+        }
+
+        $response = $this->_client->call('synchronize', $args);
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call set.
+     *
+     * <pre>
+     *   Set the value of a record.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @param  mixed $value
+     * @param  mixed $xt
+     * @access public
+     * @return mixed Fluent interface or error message
+     */
+    public function set($key, $value, $xt = null)
+    {
+        $args = array('DB' => $this->_db, 'key' => $key, 'value' => $value);
+        if (!is_null($xt)) {
+            $args['xt'] = $xt;
+        }
+
+        $response = $this->_client->call('set', $args);
+        if ($response['code'] !== 200) {
+            return $this->_errmsg($response['code']);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Call add.
+     *
+     * <pre>
+     *   Add a record.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @param  mixed $value
+     * @param  mixed $xt
+     * @access public
+     * @return mixed true:Success to add, false: Fail to add or error message
+     */
+    public function add($key, $value, $xt = null)
+    {
+        $args = array('DB' => $this->_db, 'key' => $key, 'value' => $value);
+        if (!is_null($xt)) {
+            $args['xt'] = $xt;
+        }
+
+        $response = $this->_client->call('add', $args);
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call replace.
+     *
+     * <pre>
+     *   Replace a record.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @param  mixed $value
+     * @param  mixed $xt
+     * @access public
+     * @return mixed True:success, False:fail or error message.
+     */
+    public function replace($key, $value, $xt = null)
+    {
+        $args = array('DB' => $this->_db, 'key' => $key, 'value' => $value);
+        if (!is_null($xt)) {
+            $args['xt'] = $xt;
+        }
+
+        $response = $this->_client->call('replace', $args);
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        return $this->_errmsg($response['code']);
+    }
+
+    /**
+     * Call append.
+     *
+     * <pre>
+     *   Set the value of a record.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @param  mixed $value
+     * @param  mixed $xt
+     * @access public
+     * @return mixed Fluent interface or error message
+     */
+    public function append($key, $value, $xt = null)
+    {
+        $args = array('DB' => $this->_db, 'key' => $key, 'value' => $value);
+        if (!is_null($xt)) {
+            $args['xt'] = $xt;
+        }
+        $response = $this->_client->call('append', $args);
+        if ($response['code'] !== 200) {
+            return $this->_errmsg($response['code']);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Call increment.
+     *
+     * <pre>
+     *   Add a number to the numeric integer value of a record.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @param  mixed $num
+     * @param  mixed $xt
+     * @access public
+     * @return mixed Response of RPC call
+     */
+    public function increment($key, $num, $xt = null)
+    {
+        $args = array('DB' => $this->_db, 'key' => $key, 'num' => $num);
+        if (!is_null($xt)) {
+            $args['xt'] = $xt;
+        }
+        $response = $this->_client->call('increment', $args);
+        if ($response['code'] !== 200) {
+            return $this->_errmsg($response['code']);
+        }
+
+        return intval($response['body']['num']);
+    }
+
+    /**
+     * Call incrementDouble.
+     *
+     * <pre>
+     *   Add a number to the numeric double value of a record.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @param  mixed $num
+     * @param  mixed $xt
+     * @access public
+     * @return mixed Response of RPC call
+     */
+    public function incrementDouble($key, $num, $xt = null)
+    {
+        $args = array('DB' => $this->_db, 'key' => $key, 'num' => $num);
+        if (!is_null($xt)) {
+            $args['xt'] = $xt;
+        }
+        $response = $this->_client->call('increment_double', $args);
+        if ($response['code'] !== 200) {
+            return $this->_errmsg($response['code']);
+        }
+
+        return doubleval($response['body']['num']);
+    }
+
+    /**
+     * Call cas.
+     *
+     * <pre>
+     *   Perform compare-and-swap.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @param  mixed $oval
+     * @param  mixed $nval
+     * @param  mixed $xt
+     * @access public
+     * @throws \Net\KyotoTycoon\Exception
+     * @return Bool True: Status code is 200, False: Status code is 450
+     */
+    public function cas($key, $oval = null, $nval = null, $xt = null)
+    {
+        $args = array('DB' => $this->_db, 'key' => $key);
+        $list = array('oval' => $oval, 'nval' => $nval, 'xt' => $xt);
+
+        foreach ($list as $k => $v) {
+            if (!is_null($v)) {
+                $args[$k] = $v;
+            }
+        }
+        $response = $this->_client->call('cas', $args);
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        throw new Exception($this->_errmsg($response['code']));
+    }
+
+    /**
+     * Call remove.
+     *
+     * <pre>
+     *   Remove a record.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @access public
+     * @throws \Net\KyotoTycoon\Exception
+     * @return Bool True: Status code is 200, False: Status code is 450.
+     */
+    public function remove($key)
+    {
+        $args = array('DB' => $this->_db, 'key' => $key);
+        $response = $this->_client->call('remove', $args);
+
+        if ($response['code'] === 200) {
+            return true;
+        } else if ($response['code'] === 450) {
+            return false;
+        }
+
+        throw new Exception($this->_errmsg($response['code']));
+    }
+
+    /**
+     * Call get.
+     *
+     * <pre>
+     *   Retrieve the value of a record.
+     * </pre>
+     *
+     * @param  mixed $key
+     * @access public
+     * @throws \Net\KyotoTycoon\Exception
+     * @return mixed Response of RPC call
+     */
+    public function get($key)
+    {
+        $args = array('DB' => $this->_db, 'key' => $key);
+        $response = $this->_client->call('get', $args);
+
+        if ($response['code'] === 200) {
+            return $response['body']['value'];
+        } else if ($response['code'] === 450) {
+            return null;
+        }
+
+        throw new Exception($this->_errmsg($response['code']));
+    }
+
+    /**
+     * Call set_bulk.
+     *
+     * <pre>
+     *   Store records at once.
+     * </pre>
+     *
+     * @param  array $vals
+     * @param  mixed $xt
+     * @access public
+     * @throws \Net\KyotoTycoon\Exception
+     * @return mixed Response of RPC call
+     */
+    public function setBulk(array $vals, $xt = null)
+    {
+        $args = array('DB' => $this->_db);
+        foreach ($vals as $k => $v) {
+            $args["_$k"] = $v;
+        }
+        if (!is_null($xt)) {
+            $args['xt'] = $xt;
+        }
+        $response = $this->_client->call('set_bulk', $args);
+        if ($response['code'] !== 200) {
+            throw new Exception($this->_errmsg($response['code']));
+        }
+
+        return intval($response['body']['num']);
+    }
+
+    /**
+     * Call remove_bulk.
+     *
+     * <pre>
+     *   Store records at once.
+     * </pre>
+     *
+     * @param  mixed $keys
+     * @access public
+     * @throws \Net\KyotoTycoon\Exception
+     * @return mixed
+     */
+    public function removeBulk($keys)
+    {
+        $args = array('DB' => $this->_db);
+        foreach ($keys as $k => $v) {
+            $args["_$k"] = '';
+        }
+
+        $response = $this->_client->call('remove_bulk', $args);
+        if ($response['code'] !== 200) {
+            throw new Exception($this->_errmsg($response['code']));
+        }
+
+        return intval($response['body']['num']);
+    }
+
+    /**
+     * Call get_bulk.
+     *
+     * <pre>
+     *   Retrieve records at once.
+     * </pre>
+     *
+     * @param  array $keys
+     * @access public
+     * @throws \Net\KyotoTycoon\Exception
+     * @return mixed Response of RPC call
+     */
+    public function getBulk(array $keys)
+    {
+        $args = array('DB' => $this->_db);
+        foreach ($keys as $k) {
+            $args["_$k"] = '';
+        }
+
+        $response = $this->_client->call('get_bulk', $args);
+        if ($response['code'] !== 200) {
+            throw new Exception($this->_errmsg($response['code']));
+        }
+        $body = $response['body'];
+        $ret  = array();
+        foreach ($body as $k => $v) {
+            if (preg_match('/^_(.+)$/', $k, $match)) {
+                $ret[$match[1]] = $v;
+            }
+        }
+
+        if (intval($body['num']) !== count($ret)) {
+            throw new Exception('Fatal error');
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Call vacuum.
+     *
+     * <pre>
+     *   Scan the database and eliminate regions of expired records.
+     * </pre>
+     *
+     * @param  mixed $step
+     * @access public
+     * @return \Net\KyotoTycoon Fluent interface.
+     */
+    public function vacuum($step = null)
+    {
+        $args = array('DB' => $this->_db);
+        if (!is_null($step)) {
+            $args['step'] = $step;
+        }
+        $response = $this->_client->call('vacuum', $args);
+        if ($response['code'] !== 200) {
+            throw new Exception($this->_errmsg($response['code']));
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get last content.
+     *
+     * @access public
+     * @return mixed Last content or null
+     */
+    public function getLastContent()
+    {
+        return $this->_client->getLastContent();
+    }
+
+    /**
+     * Autoload class.
+     *
+     * @param  mixed $class
+     * @access public
+     * @return void
+     */
+    public static function autoload($className)
+    {
+        // Autoload class.
+        // http://groups.google.com/group/php-standards/web/psr-0-final-proposal
+        if (!class_exists($className, false)) {
+            $className = ltrim($className, '\\');
+            $fileName  = '';
+            $namespace = '';
+            if ($lastNsPos = strripos($className, '\\')) {
+                $namespace = substr($className, 0, $lastNsPos);
+                $className = substr($className, $lastNsPos + 1);
+                $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
+            }
+            $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
+
+            require_once $fileName;
+        }
+    }
+}