<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dongsheng&#039;s thoughts &#187; Programming</title>
	<atom:link href="http://log.dongsheng.org/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://log.dongsheng.org</link>
	<description></description>
	<lastBuildDate>Sat, 19 May 2012 13:25:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Understanding blocks in C</title>
		<link>http://log.dongsheng.org/2012/04/07/understanding-blocks-in-c/</link>
		<comments>http://log.dongsheng.org/2012/04/07/understanding-blocks-in-c/#comments</comments>
		<pubDate>Fri, 06 Apr 2012 17:19:41 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[blocks]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[ios]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=142</guid>
		<description><![CDATA[Blocks was introduced with grand central dispatch threading in iOS and Mac OS X, it&#8217;s like lambda in Python or [...]]]></description>
			<content:encoded><![CDATA[<p>Blocks was introduced with grand central dispatch threading in iOS and Mac OS X, it&#8217;s like lambda in Python or closure in JavaScript, it greatly improved the flexibility of objc. However, it&#8217;s not in C standard, Apple implemented it in clang compiler.</p>
<p>With blocks, developers can do some interesting stuffs in C, such as:</p>
<h4>Anonymous function</h4>
<pre>
^(void) {
    printf("This is a anonymous function call");
}();
</pre>
<p>We often see the technique in JavaScript framework or bookmarklet, to avoid return value or namespace collision, but not in C <img src='http://log.dongsheng.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  </p>
<h4>Nested function and inline function</h4>
<p>You can actually define a function in a function:</p>
<pre>
typedef int (^Block)(int);

Block block_generator() {
    return ^(int a) {
        return a;
    };
}

Block bb = block_generator();
bb(121);
</pre>
<p>This technique is quite useful to provide callback function, take qsort for example, on Mac, there are two qsort functions allowing devs to provide a compare callback:</p>
<pre>
void qsort_b(void *base, size_t nel, size_t width, int (^compar)(const void *, const void *));
void qsort_r(void *base, size_t nel, size_t width, void *thunk, int (*compar)(void *, const void *, const void *));
</pre>
<p>qsort_r takes a function pointer, so you have to create a function then assign the pointer here, but with blocks, developers can create compare callback inline. It&#8217;s more straight forward.</p>
<p>In Cocoa framework, blocks are being widely used in GCD, animation, error handing, enumeration, we will see more APIs make use of this powerful features soon, such as NSURLConnection, so we don&#8217;t need to use delegate methods any more, blocks are much better. (cannot wait? try <a href="https://github.com/zwaldowski/BlocksKit">this</a>)</p>
<h4>Blocks has access to other scope</h4>
<p>By adding __block to variable declaration, blocks will be able to change variables.</p>
<pre>
__block int statusCode = 0;
int anotherCode = 9;
^(void) {
    printf("Status code %d", statusCode);
    // Change variable in bock context
    statusCode = 10;
    // Cannot do this
    // anotherCode = 999;
    // but...
    printf("another code %d", anotherCode);
}();
printf("Changed status code %d", statusCode);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2012/04/07/understanding-blocks-in-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick start: TTPhotoViewController (three20)</title>
		<link>http://log.dongsheng.org/2012/04/06/quick-start-ttphotoviewcontroller-three20/</link>
		<comments>http://log.dongsheng.org/2012/04/06/quick-start-ttphotoviewcontroller-three20/#comments</comments>
		<pubDate>Fri, 06 Apr 2012 05:02:21 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[ios]]></category>
		<category><![CDATA[ipad]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[three20]]></category>
		<category><![CDATA[tornado]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=140</guid>
		<description><![CDATA[It&#8217;s hard to develop an iOS app quickly, so many details to be taken care of even a very simple [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s hard to develop an iOS app quickly, so many details to be taken care of even a very simple UITableView based app, for example: variable table height, asynchronous loading, model reloading&#8230;</p>
<p>Three20 is one of the answers to these problems, it has a lot of useful components: enhanced table view, text fields, labels, buttons, photo browsers and a lot helper classes, on the other hand it has some major cons, such as difficult to integrate and customise, tight couple&#8230;the worst one would be lacking documentations, a project like this without official documentation and tutorials is often a deal breaker. The samples comes with three20 is your best bet to understand how to use the components, but there is no inline comments, you have to figure out what are the classes by looking in to the source code&#8230;</p>
<p>Having said all the cons, it&#8217;s great time saver once you get to know it, lately, I decided to build an album app for iPad, so I can easily browse my family photos remotely, I quickly wrote a python script imported all photo path names in MongoDB, organised by directory names, then I created a simple <a href="http://www.tornadoweb.org/">tornado</a> application, which could list all photos in certain directory in JSON, it has other handlers to process thumbnails/file serving etc. This only took me an hour or so (thanks to Python). But when comes to develop an app to consume the contents, it&#8217;s not easy. Firstly, I need to write a class to fetch and parse photo list, easy, NSURLRequest and NSJSONSerialization can do the job, then I need to create a thumbnail browser and photo browser view, I will need to a high customised UITableView to display thumbnails in grid view, table cell has to be internet aware, it has to download images asynchronously. A customised UIScrollView to display large size photos and download them asynchronously, and data source must be easy to reload, so photo viewer and thumbnails browser can reflect the changes instantly. These requirements could easily consume me a week if only use native components, but come on, it&#8217;s just a small app I wouldn&#8217;t submit to apple store!</p>
<p>I remember there is a photo album view in TTCatalog project from three20, I probably should give it a try.</p>
<ol>
<li>I created an app called &#8220;AlbumHD&#8221;, to integrate with three20, I have to run &#8220;ttmodule.py&#8221; on my project file:
<pre>
three20/src/scripts/ttmodule.py -p AlbumHD/AlbumHD.xcodeproj:build_target_name Three20 --xcode-version=4
</pre>
<p>You will have to change build_target_name to the real project name
</li>
<li>
In AppDelegate.m, add three20 navigator after [self.window makeKeyAndVisible]; it should look like this:</p>
<pre>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self.window makeKeyAndVisible];
    TTNavigator *navigator = [TTNavigator navigator];
    navigator.persistenceMode = TTNavigatorPersistenceModeNone;
    [navigator.URLMap from:@"tt://album/"     toViewController:[AlbumViewController class]];
    [navigator openURLAction:[TTURLAction actionWithURLPath:@"tt://album/"]];
    return YES;
}
</pre>
<p>navigator is a three20 module to help easily switch between view controllers without push/pop from navigation controller, so you register your view controller to navigator.URLMap, then you can access it by a short url alike identifier.
</li>
<li>
The AlbumViewController class we referred above hasn&#8217;t been defined yet, now we create one:</p>
<pre>
@interface AlbumViewController : TTPhotoViewController <TTURLRequestDelegate>
@end
</pre>
<p>So this will be the main view controller in this app, TTPhotoViewController is the three20 photo browser components, it has all the UI elements and default actions we need, we just need to feed it with the photo list.
</li>
<li>
In AlbumViewController.m, we override -(void)viewDidLoad:</p>
<pre>
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.photoSource = [[PhotoSource alloc] init];
}
</pre>
<p>PhotoSource is a subclass of TTURLRequestModel, it takes of loading photo list and response request from TTPhotoViewController, TTPhotoViewController may asks questions like: how many photos in this data source? what&#8217;s the max index? what&#8217;s the photo in index X? These questions are defined in TTPhotoSource protocol. By subclass TTURLRequestModel, PhotoSource has ability to load remote resource, and it knows if the resource is being loaded or already loaded.</p>
<p>Here is list of PhotoSource implmentation code:</p>
<pre>
@implementation PhotoSource
@synthesize title = _title;
#pragma mark init
- (id)init {
    if (self = [super init]) {
        _type = PhotoSourceNormal;
        _title = @"";
        _photos = [NSMutableArray array];
    }
    return self;
}
- (void)loadPhotos {
    [_delegates perform:@selector(modelDidStartLoad:) withObject:self];
    _loadingRequest = [TTURLRequest requestWithURL: @"http://10.1.1.100/album/trip" delegate: self];
    _loadingRequest.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
    TTURLJSONResponse* response = [[TTURLJSONResponse alloc] init];
    _loadingRequest.response = response;
    [_loadingRequest send];
}
#pragma mark TTModel
- (void)load:(TTURLRequestCachePolicy)cachePolicy more:(BOOL)more {
    if (cachePolicy &#038; TTURLRequestCachePolicyNetwork) {
        [self loadPhotos];
    }
}
- (void)requestDidFinishLoad:(TTURLRequest*)request {
    TTURLJSONResponse* response = request.response;
    [_photos removeAllObjects];
    NSArray *list = response.rootObject;
    Photo *p;
    int i = 0;
    for (NSString *url in list) {
        p = [[Photo alloc] initWithURL:url];
        p.index = i;
        p.photoSource = self;
        [_photos addObject:p];
        i++;
    }
    [super requestDidFinishLoad:request];
    [_delegates perform:@selector(modelDidFinishLoad:) withObject:self];
}
#pragma mark TTPhotoSource
- (NSInteger)numberOfPhotos {
    return _photos.count;
}
- (NSInteger)maxPhotoIndex {
    return _photos.count-1;
}
- (id<TTPhoto>)photoAtIndex:(NSInteger)photoIndex {
    if (photoIndex < _photos.count) {
        id photo = [_photos objectAtIndex:photoIndex];
        if (photo == [NSNull null]) {
            return nil;
        } else {
            return photo;
        }
    } else {
        return nil;
    }
}
@end
</pre>
<p>Note, Photo class is conforming TTPhoto protocol.
</li>
<li>This is pretty much how to build a photo album app using Three20, the code is based on TTCatalog example, I made necessary changes to allow it reload list from my tornado app.</li>
</ol>
<p>There are other changes and tips, I listed a few here:</p>
<ul>
<li>For large photos, TTPhotoView uses UIViewContentModeScaleAspectFill contentMode, so photos are overlapped, by avoiding hacking three20 code, I cloned TTPhotoViewController to use my customised TTPhotoView, that's the problem of tight couple</li>
<li>To load another photo set, assign a new loading url to PhotoSource, and call [TTPhotoViewController reload]</li>
<li>There is a slide show button defined in TTPhotoViewController but not added to UIToolBar, don't why, in my cloned TTPhotoViewController, I added there, I added another button to choose album.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2012/04/06/quick-start-ttphotoviewcontroller-three20/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP 5.4 released</title>
		<link>http://log.dongsheng.org/2012/03/06/php-5-4-released/</link>
		<comments>http://log.dongsheng.org/2012/03/06/php-5-4-released/#comments</comments>
		<pubDate>Mon, 05 Mar 2012 16:00:49 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=136</guid>
		<description><![CDATA[PHP 5.4 just released a few days ago, it introduced new features I quite like: Short array syntax $langs = [...]]]></description>
			<content:encoded><![CDATA[<p>PHP 5.4 just released a few days ago, it introduced new features I quite like:</p>
<ol>
<li>Short array syntax
<pre>
$langs = ["php", "python", "lua"];
$person = ["firstname" => "Dongsheng", "lastname" => "Cai"];
</pre>
<p>I wish to see short class syntax, not sure how it will look like.
</li>
<li>&#8220;&lt;?=&#8221; is officially available all the time, there was an argument wether or not it should be used in project due to the short tag option in php.ini, now it&#8217;s out of question.</li>
<li><a href="http://www.php.net/manual/en/session.upload-progress.php">Session upload progress</a>, I will give it a try later</li>
<li><a href="http://au.php.net/traits">Traits</a> to ease the limitations of single-inheritance</li>
<li>Build-in web server! Start it using `php -S localhost:8080` command, this makes testing/debugging easier&#8230;a little bit</li>
<li>Massive performance improvement</li>
<li>No more safe mode, magic quotes, register_globals and allow call time pass reference</li>
</ol>
<p>I compiled it on Lion 10.7, my configure is here: <a href="https://gist.github.com/1978565">https://gist.github.com/1978565</a></p>
<p>Notes</p>
<p>- pcre library must be update-to-date, otherwise, some pattern modifiers won&#8217;t be available in php.<br />
- libjpeg isn&#8217;t installed on OS X, I installed it by <a href="https://github.com/mxcl/homebrew">homebrew</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2012/03/06/php-5-4-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iOS工程文件里的的Localizable.strings</title>
		<link>http://log.dongsheng.org/2012/01/19/localizable-strings/</link>
		<comments>http://log.dongsheng.org/2012/01/19/localizable-strings/#comments</comments>
		<pubDate>Thu, 19 Jan 2012 08:39:25 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=131</guid>
		<description><![CDATA[要写个自动化生成iOS语言文件的PHP脚本，用vim打开Localizable.strings发现全是乱码，还怀疑是苹果搞出来的特殊二进制文件，没想到用TextWrangler打开完全没有问题，这个文件是小头的UTF-16文件，带BOM头。这样问题就好解决了，用PHP生成文件内容，然后用mbstring转换成UTF-16加上个BOM头就成，但实验了一上午，生出来的文件总是乱码，怀疑是mbstring的问题，然后换成用iconv转码竟然就没问题了，上一小段代码： $bom = chr(255) . chr(254); $string = "\"" . $key . "\"" . " = \"" . $value . [...]]]></description>
			<content:encoded><![CDATA[<p>要写个自动化生成iOS语言文件的PHP脚本，用vim打开Localizable.strings发现全是乱码，还怀疑是苹果搞出来的特殊二进制文件，没想到用TextWrangler打开完全没有问题，这个文件是小头的UTF-16文件，带BOM头。这样问题就好解决了，用PHP生成文件内容，然后用mbstring转换成UTF-16加上个BOM头就成，但实验了一上午，生出来的文件总是乱码，怀疑是mbstring的问题，然后换成用iconv转码竟然就没问题了，上一小段代码：</p>
<pre>
    $bom = chr(255) . chr(254);
    $string = "\"" . $key . "\"" . " = \"" . $value . "\";\n";
    $text = iconv('UTF-8', 'UTF-16', $string);
    file_put_contents('Localizable.strings', $text);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2012/01/19/localizable-strings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tomcat6的PermGen space错误</title>
		<link>http://log.dongsheng.org/2011/07/22/tomcat6-outofmemoryerror-permgen-space/</link>
		<comments>http://log.dongsheng.org/2011/07/22/tomcat6-outofmemoryerror-permgen-space/#comments</comments>
		<pubDate>Fri, 22 Jul 2011 07:59:39 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[alfresco]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[tomcat]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=123</guid>
		<description><![CDATA[最近又要折腾Alfresco，我真服了这一坨坨Java软件了，一个安装包400M，核心包也100M，里面引用的jar就有将近200个，Java就是全球变暖的罪魁祸首。 每次安装Java软件必然要碰到各种各样麻烦问题，这次是4G内存也装不了Alfresco，反复报错：java.lang.OutOfMemoryError: PermGen space，我在终端翻了四五页才看到这个关键错误，前面报的全是反人类的不相关内容。解决办法是给tomcat传个参数进去，我得记下来，下次它肯定还得给我脸色看。 我的tomcat是用jsvc启动的加如下参数： -Xmx1024m \ -Xms1024m \ -XX:MaxPermSize=128M \ 感谢Java，你又浪费了我一个下午。]]></description>
			<content:encoded><![CDATA[<p>最近又要折腾Alfresco，我真服了这一坨坨Java软件了，一个安装包400M，核心包也100M，里面引用的jar就有将近200个，Java就是全球变暖的罪魁祸首。</p>
<p>每次安装Java软件必然要碰到各种各样麻烦问题，这次是4G内存也装不了Alfresco，反复报错：java.lang.OutOfMemoryError: PermGen space，我在终端翻了四五页才看到这个关键错误，前面报的全是反人类的不相关内容。解决办法是给tomcat传个参数进去，我得记下来，下次它肯定还得给我脸色看。</p>
<p>我的tomcat是用jsvc启动的加如下参数：</p>
<pre>
-Xmx1024m \
-Xms1024m \
-XX:MaxPermSize=128M \
</pre>
<p>感谢Java，你又浪费了我一个下午。</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2011/07/22/tomcat6-outofmemoryerror-permgen-space/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Moodle Moot 2011</title>
		<link>http://log.dongsheng.org/2011/07/19/mootau11/</link>
		<comments>http://log.dongsheng.org/2011/07/19/mootau11/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 04:56:49 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[ios]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[moodle]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=96</guid>
		<description><![CDATA[这个博克存在很久了，但很少涉及跟我工作相关的东西：我为一个叫Moodle的开源课程管理软件工作，可能很多人不知道Moodle是干什么的，跟我两年前参加布里斯班Moodle moot时的反应类似，当看到几百号人从世界各地赶到布里斯班参加会议，我非常惊讶，也挺自豪：我写的代码竟然有这么多人在使用，还是世界各地的。 两年后的今天再来悉尼Convention Center参加会议，发现使用Moodle的学校又大大壮大了，澳洲八大名校已有一半迁移到了Moodle（澳洲国立大学，新南威尔士大学，西澳大学和莫纳什大学），使用Moodle的TAFE和中小学更是不计其数，大约40%的学校是Moodle用户，还有个好消息是有更多的学校已经升级到2.0。比较有意思的是在会场还看到一个BlackBoard的展台，不过看上去不是很受欢迎 我来的一个目的是介绍正在开发中的Moodle for iPhone，这一个多月写的我死去活来的程序基本成型了，这个版本的功能不多，主要是Moodle端需要提供更多WebService，这个会在Moodle2.2发布的时候获得改善，做完Presentaion以后反响很热烈，有几个机构询问能否给大学提供定制版本，这对推销学校形象很有力。还有几家关心android版本的开发，可哥近期内可能不会碰android开发，cocoa touch够我喝一壶了。 还有件有意思的事，昨天参加一个session时presenter在facebook里搜索moodle，找到一本书讲解我去年写的一个核心组件 Moodle 2 The File Picker]]></description>
			<content:encoded><![CDATA[<p>这个博克存在很久了，但很少涉及跟我工作相关的东西：我为一个叫Moodle的开源课程管理软件工作，可能很多人不知道Moodle是干什么的，跟我两年前参加布里斯班Moodle moot时的反应类似，当看到几百号人从世界各地赶到布里斯班参加会议，我非常惊讶，也挺自豪：我写的代码竟然有这么多人在使用，还是世界各地的。</p>
<p>两年后的今天再来悉尼Convention Center参加会议，发现使用Moodle的学校又大大壮大了，澳洲八大名校已有一半迁移到了Moodle（澳洲国立大学，新南威尔士大学，西澳大学和莫纳什大学），使用Moodle的TAFE和中小学更是不计其数，大约40%的学校是Moodle用户，还有个好消息是有更多的学校已经升级到2.0。比较有意思的是在会场还看到一个BlackBoard的展台，不过看上去<a href="https://twitter.com/#!/dcai/status/92514578046533632" target="_blank">不是很受欢迎</a> <img src='http://log.dongsheng.org/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  </p>
<p>我来的一个目的是介绍正在开发中的Moodle for iPhone，这一个多月写的我死去活来的程序基本成型了，这个版本的功能不多，主要是Moodle端需要提供更多WebService，这个会在Moodle2.2发布的时候获得改善，做完Presentaion以后反响很热烈，有几个机构询问能否给大学提供定制版本，这对推销学校形象很有力。还有几家关心android版本的开发，可哥近期内可能不会碰android开发，cocoa touch够我喝一壶了。</p>
<p>还有件有意思的事，昨天参加一个session时presenter在facebook里搜索moodle，找到一本书讲解我去年写的一个核心组件 <img src='http://log.dongsheng.org/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  <a href="http://www.lulu.com/product/paperback/moodle-2-the-file-picker/16060624" target="_blank">Moodle 2 The File Picker</a></p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2011/07/19/mootau11/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>tig真好用</title>
		<link>http://log.dongsheng.org/2011/05/02/tig%e7%9c%9f%e5%a5%bd%e7%94%a8/</link>
		<comments>http://log.dongsheng.org/2011/05/02/tig%e7%9c%9f%e5%a5%bd%e7%94%a8/#comments</comments>
		<pubDate>Mon, 02 May 2011 07:20:47 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[tig]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=120</guid>
		<description><![CDATA[tig是git的浏览器，我一直用来看代码库的commits历史，今天仔细看了下manual发现很多有意思的功能， 视图切换： 在主界面按大写S可以察看当前分支的状态，按t打开文件树，在文件树上按B可以察看blame界面，按H显示本地分支，按l显示log summery，在commit上按d显示commit内容。 显示选项： 在察看commit的界面里按.可以切换行号。 在主界面按大写D可以调整commit日期显示。 主界面按A选择显示committer的方式 其他： 方便的cherry-pick，用H切换到别的分支，选中commit然后按大写C就能完成cherry-pick了！]]></description>
			<content:encoded><![CDATA[<p><a href="http://jonas.nitro.dk/tig/">tig</a>是git的浏览器，我一直用来看代码库的commits历史，今天仔细看了下manual发现很多有意思的功能，</p>
<p>视图切换：<br />
在主界面按大写S可以察看当前分支的状态，按t打开文件树，在文件树上按B可以察看blame界面，按H显示本地分支，按l显示log summery，在commit上按d显示commit内容。</p>
<p>显示选项：<br />
在察看commit的界面里按.可以切换行号。<br />
在主界面按大写D可以调整commit日期显示。<br />
主界面按A选择显示committer的方式</p>
<p>其他：<br />
方便的cherry-pick，用H切换到别的分支，选中commit然后按大写C就能完成cherry-pick了！</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2011/05/02/tig%e7%9c%9f%e5%a5%bd%e7%94%a8/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>修改Ｗordpress的Permalinks</title>
		<link>http://log.dongsheng.org/2010/11/25/change-wordpress-permalinks/</link>
		<comments>http://log.dongsheng.org/2010/11/25/change-wordpress-permalinks/#comments</comments>
		<pubDate>Thu, 25 Nov 2010 04:06:54 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Permalinks]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/archives/103</guid>
		<description><![CDATA[不知道有多少人跟我一样讨厌Wordpress的Revision和auto-save，这两个功能在Wordpress的posts表里创建大量垃圾记录，即使我在wp-config.php里设置了： define('WP_POST_REVISIONS', false); define('AUTOSAVE_INTERVAL', 60000); 还是无法彻底消灭垃圾记录。其实这对性能啥的没什么影响，主要是种程序员的洁癖，本来我的posts表是整整齐齐按ID排序的，但Wordpress这么整以后，本来连续的ID全打乱了，我的Permalinks就是依赖ID的。 所以我决定把Permalinks改成年月日+postname的形式，这样看起来就没那么乱了。在这么做之前最好设置301转向，不然apache的记录里就全是404了。这个可以用.htaccess来实现，在Wordpress目录的.htaccess里加上： RewriteEngine On RewriteBase / RewriteRule ^archives/([0-9]+)$ \?p=$1 [R] 这样原来http://log.dongsheng.org/archives/2重定向到http://log.dongsheng.org/?p=2，然后wordpress会把这个地址换成新的年月日形式。 更新：29/11/2010 还要再加一条规则重定向trackback： RewriteRule ^archives/([0-9]+)/trackback$ [...]]]></description>
			<content:encoded><![CDATA[<p>不知道有多少人跟我一样讨厌Wordpress的Revision和auto-save，这两个功能在Wordpress的posts表里创建大量垃圾记录，即使我在wp-config.php里设置了：</p>
<pre>define('WP_POST_REVISIONS', false);
define('AUTOSAVE_INTERVAL', 60000);</pre>
<p>还是无法彻底消灭垃圾记录。其实这对性能啥的没什么影响，主要是种程序员的洁癖，本来我的posts表是整整齐齐按ID排序的，但Wordpress这么整以后，本来连续的ID全打乱了，我的Permalinks就是依赖ID的。</p>
<p>所以我决定把Permalinks改成年月日+postname的形式，这样看起来就没那么乱了。在这么做之前最好设置301转向，不然apache的记录里就全是404了。这个可以用.htaccess来实现，在Wordpress目录的.htaccess里加上：</p>
<pre>RewriteEngine On
RewriteBase /
RewriteRule ^archives/([0-9]+)$ \?p=$1 [R]</pre>
<p>这样原来http://log.dongsheng.org/archives/2重定向到http://log.dongsheng.org/?p=2，然后wordpress会把这个地址换成新的年月日形式。</p>
<h4>更新：29/11/2010</h4>
<p>还要再加一条规则重定向trackback：</p>
<pre>RewriteRule ^archives/([0-9]+)/trackback$ wp_trackback.php\?p=$1 [R]</pre>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2010/11/25/change-wordpress-permalinks/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Moving to Git</title>
		<link>http://log.dongsheng.org/2010/11/23/moving-to-git/</link>
		<comments>http://log.dongsheng.org/2010/11/23/moving-to-git/#comments</comments>
		<pubDate>Tue, 23 Nov 2010 11:00:31 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[moodle]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/archives/86</guid>
		<description><![CDATA[如果一切顺利的话，Moodle会在这周把主代码库从cvs换到git，之前已经有几个子项目在用git协作了，这次迁移之后，标志着核心开发团队彻底抛弃了cvs。换版本管理工具绝对不是闲的蛋疼才干的事，工作将近三年实在是吃够了cvs的苦，缓慢的diff，古怪的$id:$，作为协作工具却没有解决团队开发的协作问题。 今天我们团队花了一整天研究git，发现迁移到git最大的难度是图形化工具的匮乏，Netbeans和Eclipse还没有正式发布的git插件，SmartGit算是最好的图形化工具的，但竟然不支持添加远程代码库（git remote），最后还是不得不通过命令行完成。对于初学者来说git那一大坨命令有点吓人，所以当我说用命令行做更快时，被人狠狠鄙视了，然后我用git命令，另一个同事用netbeans+smartgit比了下，任务是创建原始项目的clone，添加远程代码库，合并并推送。结果在他研究Netbeans测试版蹦出的那一坨Java异常的时候，命令行就搞定了，超级简单。虽然命令行的学习曲线比较陡，但利于开发人员彻底理解Git的工作方式，且不会被锁定到某个特定的GUI工具。]]></description>
			<content:encoded><![CDATA[<p>如果一切顺利的话，Moodle会在这周把主代码库从cvs换到git，<a href="http://log.dongsheng.org/archives/92">之前已经有几个子项目在用git协作了</a>，这次迁移之后，标志着核心开发团队彻底抛弃了cvs。换版本管理工具绝对不是闲的蛋疼才干的事，工作将近三年实在是吃够了cvs的苦，缓慢的diff，古怪的$id:$，作为协作工具却没有解决团队开发的协作问题。</p>
<p>今天我们团队花了一整天研究git，发现迁移到git最大的难度是图形化工具的匮乏，Netbeans和Eclipse还没有正式发布的git插件，SmartGit算是最好的图形化工具的，但竟然不支持添加远程代码库（git remote），最后还是不得不通过命令行完成。对于初学者来说git那一大坨命令有点吓人，所以当我说用命令行做更快时，被人狠狠鄙视了，然后我用git命令，另一个同事用netbeans+smartgit比了下，任务是创建原始项目的clone，添加远程代码库，合并并推送。结果在他研究Netbeans测试版蹦出的那一坨Java异常的时候，命令行就搞定了，超级简单。虽然命令行的学习曲线比较陡，但利于开发人员彻底理解Git的工作方式，且不会被锁定到某个特定的GUI工具。</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2010/11/23/moving-to-git/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>简单总结一下 Git 的使用</title>
		<link>http://log.dongsheng.org/2010/08/25/git-in-actoin/</link>
		<comments>http://log.dongsheng.org/2010/08/25/git-in-actoin/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 15:14:44 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[git]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=92</guid>
		<description><![CDATA[前段时间折腾Moodle的Quesion/Quiz模块，最大的难点不是开发，而是怎么跟另一个维护该模块的同事讨论，这哥们远在大不列颠，每次在tracker上留言都不得不等到第二天起床才能看到他的回复，更烦的是要review一个个patch，小点还好说，这动辄一万多行的大patch真不好一行行的解释。 然后决定把战线延伸到GitHub。对小项目来说Git相对CVS的优势不明显，徒增学习曲线，但对于Moodle这种庞大的开源软件，Git却是大大降低复杂程度，最重要的一点是创建分支的成本为零，我可以单独创建新分支以开发某特性，开发过程中可以方便的与上游代码合并，之前的cvs是无法享受这种便利的，我们不得不checkout多份拷贝进行测试。另一个很重要的特点是Git在本地保存全部改动历史，这样可以极其快捷的进行diff和blame 再说说GitHub，对于项目管理来说，GitHub肯定是不如Jira，但细化到编码这个层次，GitHub比Jira好很多，首先Jira没有官方的Git支持，无法追踪相关的Git提交，然后Jira不便于Code review（可能有好的插件会支持，说错了请指正）。GitHub在这方面做的很好，可以在git commit做inline note，代码浏览比viewvc强出一个世纪。 转到GitHub后，工作效率提高了很多，我白天把改动push到我的在GitHub的分支上，然后同事做Code review，提交改动，第二天我把他的改动合并到我的分支上，然后继续昨天的工作…… Git实际上是个新的开发模型，从编码到项目管理都不同于cvs时代。 简单总结一下Git的使用以 Moodle在GitHub的mirror为例。 打开 http://github.com/moodle/moodle，然后Fork，这个并不是必须的，之后可以通过git remote添加新的上游代码库 git clone 我自己的代码库 我不喜欢origin这个默认远程代码库名，所以重命名一下：git remote rename [...]]]></description>
			<content:encoded><![CDATA[<p>前段时间折腾Moodle的Quesion/Quiz模块，最大的难点不是开发，而是怎么跟另一个维护该模块的同事讨论，这哥们远在大不列颠，每次在tracker上留言都不得不等到第二天起床才能看到他的回复，更烦的是要review一个个patch，小点还好说，这动辄一万多行的大patch真不好一行行的解释。</p>
<p>然后决定把战线延伸到GitHub。对小项目来说Git相对CVS的优势不明显，徒增学习曲线，但对于Moodle这种庞大的开源软件，Git却是大大降低复杂程度，最重要的一点是创建分支的成本为零，我可以单独创建新分支以开发某特性，开发过程中可以方便的与上游代码合并，之前的cvs是无法享受这种便利的，我们不得不checkout多份拷贝进行测试。另一个很重要的特点是Git在本地保存全部改动历史，这样可以极其快捷的进行diff和blame <img src='http://log.dongsheng.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>再说说GitHub，对于项目管理来说，GitHub肯定是不如<a href="http://www.atlassian.com/software/jira/">Jira</a>，但细化到编码这个层次，GitHub比Jira好很多，首先Jira没有官方的Git支持，无法追踪相关的Git提交，然后Jira不便于Code review（可能有好的插件会支持，说错了请指正）。GitHub在这方面做的很好，可以在git commit做inline note，代码浏览比<a href="http://www.viewvc.org/">viewvc</a>强出一个世纪。</p>
<p>转到GitHub后，工作效率提高了很多，我白天把改动push到我的在GitHub的分支上，然后同事做Code review，提交改动，第二天我把他的改动合并到我的分支上，然后继续昨天的工作……</p>
<p>Git实际上是个新的开发模型，从编码到项目管理都不同于cvs时代。</p>
<p>简单总结一下Git的使用以 Moodle在GitHub的mirror为例。</p>
<ol>
<li> 打开 http://github.com/moodle/moodle，然后Fork，这个并不是必须的，之后可以通过git remote添加新的上游代码库</li>
<li> git clone 我自己的代码库</li>
<li> 我不喜欢origin这个默认远程代码库名，所以重命名一下：git remote rename origin github，运行一下 git branch -r 发现远程名字变了</li>
<li> 我之前fork的Moodle并不是官方的，换成官方的git源：git remote add upstream git://git.moodle.org/moodle.git，然后：git fetch upstream</li>
<li>  我要创建一个我自己的分支newfeature：git branch newfeature，切换到这个分支需运行：git checkout newfeature</li>
<li>这个时候newfeature是个本地分支，在github上是不存在的，我得把这个分支push到github上，同事才能看到我的改动，运行：git push github，打开.git/config
<pre>
[branch "newfeature"]
remote = github
merge = refs/heads/newfeature
</pre>
<p>如果没有就加上这段，有了这段，就可以git pull直接获取并合并，有个命令可以设置git checkout &#8211;track github/newfeature，但我觉的用配置文件更直观</p>
</li>
<li>如果上游更新了，我就需要合并：git merge upstream/cvshead</li>
<li>删除本地分支：git branch -d newfeature，删除远程分支：git push :newfeature</li>
<li>一般的提交就不多说了，跟cvs之流一样，不同的是提交完了要git push才能把你的改动推送到远程服务器上</li>
<li>git可以比较分支，这样你可以比较你的当前分支和主干，生成一个patch提交到cvs里</li>
</ol>
<p>在 ~/.gitconfig 上下点功夫，能提高工作效率，Stack overflow上有个讨论不错：<a href="http://stackoverflow.com/questions/267761/what-does-your-gitconfig-contain">What does your ~/.gitconfig contain?</a></p>
<p>最后推荐两个软件，GitX和tig，两个都是Git浏览器，前者是Mac的，后者是终端上的，对于常用ssh的人，后者有用，有效率的多。</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2010/08/25/git-in-actoin/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>WordPress 3</title>
		<link>http://log.dongsheng.org/2010/06/18/wordpress3/</link>
		<comments>http://log.dongsheng.org/2010/06/18/wordpress3/#comments</comments>
		<pubDate>Fri, 18 Jun 2010 09:00:30 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/archives/73</guid>
		<description><![CDATA[WordPress的SVN更新够快的，3.0刚刚发布，TRUNK的版本号就变成了3.1-ALPHA]]></description>
			<content:encoded><![CDATA[<p>WordPress的SVN更新够快的，3.0刚刚发布，TRUNK的版本号就变成了3.1-ALPHA</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2010/06/18/wordpress3/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP成员函数中竟然也能用static声明变量</title>
		<link>http://log.dongsheng.org/2010/04/07/using-static-variable-in-class-method/</link>
		<comments>http://log.dongsheng.org/2010/04/07/using-static-variable-in-class-method/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 02:08:57 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=84</guid>
		<description><![CDATA[又发现一个PHP Feature，PHP成员函数中竟然也能用static声明变量。怎么想怎么奇怪，你都创建新实例了，怎么static还是有效？不过有时候还蛮有用的。 class static_var { function __construct($name) { $this->name = $name; } function output() { static $counter; $counter++; echo $counter.'&#124;'.$this->name.'&#124;'; [...]]]></description>
			<content:encoded><![CDATA[<p>又发现一个PHP Feature，PHP成员函数中竟然也能用static声明变量。怎么想怎么奇怪，你都创建新实例了，怎么static还是有效？不过有时候还蛮有用的。</p>
<pre>
class static_var {
    function __construct($name) {
        $this->name = $name;
    }
    function output() {
        static $counter;
        $counter++;
        echo $counter.'|'.$this->name.'|';
    }
}
$t1 = new static_var('take 1');
$t1->output();
$t2 = new static_var('take 2');
$t2->output();
</pre>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2010/04/07/using-static-variable-in-class-method/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mercurial for Google Code 的几个小技巧</title>
		<link>http://log.dongsheng.org/2009/07/24/mercurial-for-google-code-tips/</link>
		<comments>http://log.dongsheng.org/2009/07/24/mercurial-for-google-code-tips/#comments</comments>
		<pubDate>Fri, 24 Jul 2009 14:31:22 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[hg]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[scm]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/archives/64</guid>
		<description><![CDATA[为了方便改本站主题，我把代码放在了 Google Code 上，一冲动把代码管理工具选成了 Mercurial 而不是熟悉的 SVN，Mercurial 操作起来跟 Git 差不多，但配置碰到一些小问题。 1. 无法象 SVN 一样记住登录密码 解决办法：打开 .hg/hgrc ，默认是这样的： [paths] default = [...]]]></description>
			<content:encoded><![CDATA[<p>为了方便改本站主题，我把代码放在了 Google Code 上，一冲动把代码管理工具选成了 Mercurial 而不是熟悉的 SVN，Mercurial 操作起来跟 Git 差不多，但配置碰到一些小问题。<br />
1. 无法象 SVN 一样记住登录密码<br />
解决办法：打开 .hg/hgrc ，默认是这样的：</p>
<pre>
[paths]
default = https://projectname.googlecode.com/hg
</pre>
<p>把密码和用户名填到 URL 里就行啦</p>
<pre>
[paths]
default = https://accountname:password@projectname.googlecode.com/hg
</pre>
<p>2. 提示没有设置用户名<br />
解决办法：在 .hg/hgrc 中添加</p>
<pre>
[ui]
username = Dongsheng Cai
</pre>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2009/07/24/mercurial-for-google-code-tips/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>在 Patch 中添加新文件</title>
		<link>http://log.dongsheng.org/2009/07/06/including-new-files-in-a-patch/</link>
		<comments>http://log.dongsheng.org/2009/07/06/including-new-files-in-a-patch/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 08:10:39 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[OS]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[cvs]]></category>
		<category><![CDATA[cvsdo]]></category>
		<category><![CDATA[patch]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/archives/49</guid>
		<description><![CDATA[我们的项目使用 CVS 托管代码，在把提交代码前，我们通常会创建一个 Patch，然后放到 Tracker 上做质量检查。 作为一个不会用 IDE 的程序员，Patch 一般是这样创建的： cvs diff file1.php > file1.patch 问题是，这个命令无法处理 CVS 中不存在的文件，即新文件，诸如 Netbeans 和 [...]]]></description>
			<content:encoded><![CDATA[<p>我们的项目使用 CVS 托管代码，在把提交代码前，我们通常会创建一个 Patch，然后放到 Tracker 上做质量检查。<br />
作为一个不会用 IDE 的程序员，Patch 一般是这样创建的：</p>
<pre>cvs diff file1.php > file1.patch</pre>
<p>问题是，这个命令无法处理 CVS 中不存在的文件，即新文件，诸如 Netbeans 和 Eclipse 等 IDE 都有办法为新建文件创建 Patch（因为我看到同事发的 Patch 里有 Eclipse 的标示），其实用命令行也是能实现这个功能的。</p>
<p>首先要下载一个叫 <a href="http://viper.haque.net/~timeless/redbean/cvsdo">cvsdo</a> 的工具，这是个 Perl 文件，下载到 /usr/bin/ 下，然后加上可执行权限就完事了。回到代码目录，执行 cvsdo add newfile.php，然后 cvs diff -uN newfile.php > newfile.patch，这样就能可以对新文件做 cvs diff 了。这个脚本的原理就是修改了 CVS/Entries，让 cvs 以为这个文件已经在 cvs 仓库里了。注意，要给 cvs diff 使用 -N 参数，这样才能输出新文件。如果嫌 cvs diff 后面跟参数麻烦，可以创建 ~/.cvsrc</p>
<pre>
cvs -q
update -dPA
diff -uN
</pre>
<p>这样每次执行 cvs diff 就会默认加上这些参数的。</p>
<p>参考：</p>
<ol>
<li><a href="http://http://viper.haque.net/~timeless/redbean/">CVSdo</a></li>
<li><a href="https://developer.mozilla.org/En/Creating_a_patch">Creating a patch</a></li>
</ol>
<p>Updated on 7th, July, 2009<br />
补充在 Netbeans 中创建 Patch 的方法，在左边的文件树中选中修改了的文件，然后 Team -> CVS -> Export Diff Patch</p>
<p>Updated on 16th, July, 2009<br />
做了一个 Archlinux 上的 PKGBUILD，名字 cvsutils，直接装上就都有啦</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2009/07/06/including-new-files-in-a-patch/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>在提交源码前检测调试代码</title>
		<link>http://log.dongsheng.org/2009/04/29/code-review-before-commit/</link>
		<comments>http://log.dongsheng.org/2009/04/29/code-review-before-commit/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 08:37:01 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[cvs]]></category>
		<category><![CDATA[firephp]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/archives/57</guid>
		<description><![CDATA[做 Ajax 开发最大的痛苦就是调试不易，尤其是 PHP 脚本跟远程服务器交互中的调试更是不易，还好有 FirePHP，有热心人做了 FirePHP 的 Moodle 绑定，目前这个补丁还没有提交到 CVS，所以一不小心我就把调式代码放在源码里忘了去掉，然后别的开发者 update 以后就会得到一个未定义函数错误，必须想办法避免这个错误了。 首先在 vim 配置文件中加入 match ErrorMsg /echo_fb/ 这将 [...]]]></description>
			<content:encoded><![CDATA[<p>做 Ajax 开发最大的痛苦就是调试不易，尤其是 PHP 脚本跟远程服务器交互中的调试更是不易，还好有 <a href="http://www.firephp.org/">FirePHP</a>，有热心人做了 FirePHP 的<a href="http://tracker.moodle.org/browse/MDL-16371"> Moodle 绑定</a>，目前这个补丁还没有提交到 CVS，所以一不小心我就把调式代码放在源码里忘了去掉，然后别的开发者 update 以后就会得到一个未定义函数错误，必须想办法避免这个错误了。</p>
<p>首先在 vim 配置文件中加入</p>
<pre>
match ErrorMsg /echo_fb/
</pre>
<p>这将 echo_fb 函数标记为错误，警醒我提交前要去掉。这招显然不够狠，我要是连看都不看就把 vim 关了怎么办？最有效的办法还是在提交前用 grep 搜索文件，所有有了这个 shell 脚本：</p>
<pre>
ci (){
    if [ $# -eq 0 ]; then
        echo "CVS CHECKIN: No arguments entered.";
        return 1
    else
        echo "Checking in file(s): ${@:2}";
        echo "Working ...";
        if [ "$(grep "echo_fb" ${@:2})" ]; then
            echo 'Remove debug code firstly';
        else
            cvs ci -m "\"$1\"" ${@:2}
        fi

    fi
}
</pre>
<p>这样基本就没问题了。</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2009/04/29/code-review-before-commit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Movable Type 4 installation notes</title>
		<link>http://log.dongsheng.org/2009/03/17/movable-type-4-installation-notes/</link>
		<comments>http://log.dongsheng.org/2009/03/17/movable-type-4-installation-notes/#comments</comments>
		<pubDate>Tue, 17 Mar 2009 00:55:30 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[movabletype]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=37</guid>
		<description><![CDATA[Installation 1. Uncompress movable type package, move mt-static folder to htdocs/ 2. Modify mt-config.cgi, choose your prefered DBI and remove [...]]]></description>
			<content:encoded><![CDATA[<p>Installation<br />
1. Uncompress movable type package, move mt-static folder to htdocs/<br />
2. Modify mt-config.cgi, choose your prefered DBI and remove the other chunk of code, add</p>
<pre>MailEncoding UTF-8</pre>
<p> to mt-config.pl<br />
3. Move all the other files to cgi-bin/mt/, assign executive right to cgi scripts<br />
4. Access http://localhost/cgi-bin/mt/mt.cgi</p>
<p>Theming<br />
1. Modify the css file which can be located at static/themes-base/blog.css<br />
2. Remove &#8220;powered by&#8221; widget<br />
3. Modify template in admin page<br />
4. To backup templates, every template should be linked with a local file, then you can modify the files on disk to customize looking.</p>
<p>Plugins<br />
Comming soon</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2009/03/17/movable-type-4-installation-notes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mac OS X 上构建 PHP5</title>
		<link>http://log.dongsheng.org/2009/02/28/build-php5-on-mac/</link>
		<comments>http://log.dongsheng.org/2009/02/28/build-php5-on-mac/#comments</comments>
		<pubDate>Sat, 28 Feb 2009 04:47:44 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[OS]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=36</guid>
		<description><![CDATA[在安装 PHP 前先安装 Mysql，Apache2 我用的是 Mac 内置的那个。下载 PHP 5.2.9 源码，然后执行： ./configure &#8211;prefix=/usr/local &#8211;with-iconv &#8211;with-gd &#8211;with-xmlrpc &#8211;enable-zip &#8211;with-openssl=/usr &#8211;enable-ftp &#8211;enable-sockets &#8211;enable-mbstring [...]]]></description>
			<content:encoded><![CDATA[<p>在安装 PHP 前先安装 Mysql，Apache2 我用的是 Mac 内置的那个。下载 PHP 5.2.9 源码，然后执行：<br />
./configure &#8211;prefix=/usr/local &#8211;with-iconv &#8211;with-gd<br />
&#8211;with-xmlrpc &#8211;enable-zip &#8211;with-openssl=/usr &#8211;enable-ftp &#8211;enable-sockets<br />
&#8211;enable-mbstring &#8211;enable-bcmath &#8211;with-curl &#8211;with-zlib-dir=/usr<br />
&#8211;with-mysqli=/usr/local/mysql/bin/mysql_config<br />
&#8211;with-mysql=/usr/local/mysql<br />
&#8211;with-config-file-path=/etc/php.ini &#8211;with-apxs2=/usr/sbin/apxs<br />
配置过程中会因为缺少某些开发包而出错，用 Mac port 安装一下就可以了</p>
<p>make &#038;&#038; sudo make install</p>
<p>这样创建的 libphp5.so 是无法被 Apache 载入的，需要用 lipo 处理一下 Apache 的二进制程序</p>
<p>/usr/sbin$ sudo cp httpd httpd-fat<br />
/usr/sbin$ sudo lipo httpd -thin i386 -output httpd</p>
<p>完了重启 Apache 就可以使用了：<br />
sudo apachectl restart</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2009/02/28/build-php5-on-mac/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>原来 Mac 自带了 PHP</title>
		<link>http://log.dongsheng.org/2009/01/11/buildin-php-on-mac/</link>
		<comments>http://log.dongsheng.org/2009/01/11/buildin-php-on-mac/#comments</comments>
		<pubDate>Sun, 11 Jan 2009 09:30:47 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=31</guid>
		<description><![CDATA[1. 启用 Apache，System Preferences -> Sharing -> Web Sharing 2. 编辑 /etc/apache2/httpd.conf，把启用 php5 的那一行，反注释掉，然后修改 DirectoryIndex，加上 index.php，然后创建 php 配置文件： mv /etc/php.ini.default [...]]]></description>
			<content:encoded><![CDATA[<p>1. 启用 Apache，System Preferences -> Sharing -> Web Sharing<br />
2. 编辑 /etc/apache2/httpd.conf，把启用 php5 的那一行，反注释掉，然后修改 DirectoryIndex，加上 index.php，然后创建 php 配置文件：</p>
<pre>
mv /etc/php.ini.default /etc/php.ini
</pre>
<p>重启 apache：</p>
<pre>
apachectl restart
</pre>
<p>3. 文档根目录在 /Library/WebServer/Documents，看了看 phpninfo 发现支持的扩展还不算太少 <img src='http://log.dongsheng.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2009/01/11/buildin-php-on-mac/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DSpace 安装笔记</title>
		<link>http://log.dongsheng.org/2008/12/10/dspace-installation-notes/</link>
		<comments>http://log.dongsheng.org/2008/12/10/dspace-installation-notes/#comments</comments>
		<pubDate>Wed, 10 Dec 2008 09:18:08 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[dspace]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=26</guid>
		<description><![CDATA[DSpace 是被学术，非盈利，商业组织广泛应用的数字仓库管理软件，它可以管理包括文本，图片，动画，视频等各种数据文件，它是 BSD 协议下的开源软件。 DSpace 可以从源码或二进制包安装，我选择下载了一个 1.9 M 的二进制包，心里挺高兴，心想 Java 软件怎么做的这么小了？ 但一解压就看到一个 pom.xml，心里一凉，说完了，这个包是想用 maven 下载第三方库啊！进到根目录下的 [dspace] 目录，然后运行 mvn install，这会自动下载运行 dspace [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.dspace.org/index.php/Introducing-DSpace/">DSpace</a> 是被学术，非盈利，商业组织广泛应用的数字仓库管理软件，它可以管理包括文本，图片，动画，视频等各种数据文件，它是 BSD 协议下的开源软件。</p>
<p>DSpace 可以从源码或二进制包安装，我选择下载了一个 1.9 M 的二进制包，心里挺高兴，心想 Java 软件怎么做的这么小了？<br />
但一解压就看到一个 pom.xml，心里一凉，说完了，这个包是想用 <a href="http://maven.apache.org/">maven</a> 下载第三方库啊！进到根目录下的 [dspace] 目录，然后运行 mvn install，这会自动下载运行 dspace 所需要的所有包，下载了半天，这个只有 1.9M 的安装包变成了近 400M 的庞然大物。在上面的步骤里 maven 只负责包依赖关系，然后要用 ant 把 dspace 安装到适当的位置，进入 [dspace]/target/dspace-{$version}-build.dir/，编辑 config/dspace.cfg，把 dspace.dir 设置成 /usr/share/dspace，其他选项都很简单，看看就明白了。<br />
运行 ant fresh_install 把 dspace 安装到目标位置，在我的例子里 /usr/share/dspace/webapps 是相关 web 文件。<br />
最后设置 [tomcat]/conf/server.xml 在 host 段中加入：</p>
<pre>
      &lt;Context path="/jspui" docBase="/usr/share/dspace/webapps/jspui" debug="1"
          reloadable="true" cachingAllowed="false"
          allowLinking="true"/&gt;
      &lt;!-- DEFINE A CONTEXT PATH FOR DSpace OAI User Interface --&gt;
      &lt;Context path="/oai" docBase="/usr/share/dspace/webapps/oai" debug="1"
          reloadable="true" cachingAllowed="false"
          allowLinking="true"/&gt;
</pre>
<p>启动 tomcat，然后浏览 http://localhost:8080/jspui。</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2008/12/10/dspace-installation-notes/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>编写 Nginx 启动脚本</title>
		<link>http://log.dongsheng.org/2008/12/07/nginx-boot-script/</link>
		<comments>http://log.dongsheng.org/2008/12/07/nginx-boot-script/#comments</comments>
		<pubDate>Sun, 07 Dec 2008 09:10:45 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[OS]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[nginx]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=25</guid>
		<description><![CDATA[今天试了一下直接使用 php-cgi 启用 fastcgi 的脚本竟然又可以使用了，真奇怪。 写了一个自动启动脚本，放到这里做个备份： #!/sbin/runscript # Copyright 1999-2004 Gentoo Foundation # Distributed under the terms of the GNU [...]]]></description>
			<content:encoded><![CDATA[<p>今天试了一下直接使用 php-cgi 启用 fastcgi 的脚本竟然又可以使用了，真奇怪。<br />
写了一个自动启动脚本，放到这里做个备份：</p>
<pre>
#!/sbin/runscript
# Copyright 1999-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License, v2 or
# later
# $Header:$

NGINX_EXEC=/usr/sbin/nginx
PHP_EXEC=/usr/bin/php-cgi

depend() {
need logger net
}

start () {
ebegin "Starting FCGI Service"
spawn-fcgi -a 127.0.0.1 -p 9000 -C 5 -f /usr/bin/php-cgi
eend $?
ebegin "Starting Nginx"
start-stop-daemon --start --exec ${NGINX_EXEC}
eend $?
}

stop() {
ebegin "Stopping FCGI Service"
killall php-cgi
eend $?
ebegin "Stopping Nginx"
killall nginx
start-stop-daemon --stop --quiet --pidfile /var/run/nginx.pid
--exec $NGINX_EXEC
eend $?
}
</pre>
<p>然后把这个文件保存为 /etc/init.d/httpd 并加上执行权限。<br />
然后运行 rc-config add httpd default</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2008/12/07/nginx-boot-script/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在 Gentoo 上安装 Nginx + php</title>
		<link>http://log.dongsheng.org/2008/12/06/nginx-php-gentoo/</link>
		<comments>http://log.dongsheng.org/2008/12/06/nginx-php-gentoo/#comments</comments>
		<pubDate>Sat, 06 Dec 2008 09:06:29 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[OS]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=23</guid>
		<description><![CDATA[从源码安装 Nginx ./configure --prefix=/usr --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx_error.log --http-log-path=/var/log/nginx_access.log --pid-path=/var/run/nginx.pid --http-client-body-temp-path=/var/tmp/nginx_client_body.tmp --http-proxy-temp-path=/var/tmp/nginx_proxy.tmp --http-fastcgi-temp-path=/var/tmp/nginx_fastcgi.tmp --with-http_stub_status_module --with-http_ssl_module --with-openssl=/usr/src/openssl （启用了监控和ssl模块，重新设置文件路径） make make install 注意，&#8211;with-openssl 指向的是 [...]]]></description>
			<content:encoded><![CDATA[<h4>从源码安装 Nginx</h4>
<pre>./configure --prefix=/usr --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx_error.log --http-log-path=/var/log/nginx_access.log --pid-path=/var/run/nginx.pid --http-client-body-temp-path=/var/tmp/nginx_client_body.tmp --http-proxy-temp-path=/var/tmp/nginx_proxy.tmp  --http-fastcgi-temp-path=/var/tmp/nginx_fastcgi.tmp --with-http_stub_status_module --with-http_ssl_module --with-openssl=/usr/src/openssl</pre>
<p>（启用了监控和ssl模块，重新设置文件路径）<br />
<code>make<br />
make install</code><br />
注意，&#8211;with-openssl 指向的是 openssl 的完整源码树。</p>
<h4>Nginx 的配置</h4>
<p>在 server 段中加入 root 指令，指向网站根目录，然后把 location / 段改为：</p>
<pre>location / {
  stub_status on;
  access_log off;
}</pre>
<p>这样就能在首页显示状态信息了，在这里用作测试。</p>
<h4>从源码安装 PHP 5.2.7</h4>
<pre>./configure --prefix=/usr --with-config-file-path=/etc/php --with-curl=shared --with-curlwrappers --enable-fastcgi --enable-force-cgi-redirect --with-openssl=shared --with-mysql=shared --with-mysqli=shared --enable-zip=shared --with-xmlrpc=shared --enable-mbstring --enable-pdo=shared --with-pdo-sqlite=shared --with-sqlite=shared --with-gd=shared --with-zlib
make
make install
cp php.ini-dist /etc/php/php.ini</pre>
<p>在这种情况下，模块会编译进 PHP 而不是作为模块动态加载，如果想要创建模块需要设置 shared 选项，比如我要把 PDO 作为模块加载：</p>
<pre>./configure --enable-pdo=shared --with-pdo-sqlite=shared --with-sqlite=shared</pre>
<p>如果是 apache 的话要加上  &#8211;with-apxs2 项以创建模块。</p>
<h4>设置 FASTCGI</h4>
<p>我尝试用 <a href="http://blog.kovyrin.net/2006/05/30/nginx-php-fastcgi-howto/">php-cgi 直接创建 FCGI 服务</a>，但无法成功，只好使用 lighttpd 的 spawn-fcgi 程序创建 FCGI 服务（这里偷懒用 emerge 装的 lighttpd）：</p>
<pre>spawn-fcgi -a 127.0.0.1 -p 9000 -C 5 -f /usr/bin/php-cgi</pre>
<p>最后修改 nginx 的配置文件使之调用 php FCGI 服务：</p>
<pre>location / {
 index index.php index.htm index.html;
}
location ~ .php$ {
 fastcgi_pass 127.0.0.1:9000;
 fastcgi_index index.php;
 include fastcgi_params;
 fastcgi_param SCRIPT_FILENAME /var/www$fastcgi_script_name;
}</pre>
<p>创建一个 phpinfo 页面测试一下吧！</p>
<h4>参考</h4>
<p><a href="http://wiki.codemongers.com/NginxInstallOptions">Nginx 编译参数说明</a><br />
<a href="http://php.mirrors.ilisys.com.au/manual/en/configure.php">PHP 编译参数说明</a><br />
<a href="http://blog.s135.com/post/366.htm">Nginx 0.7.x + PHP 5.2.6（FastCGI）搭建胜过Apache十倍的Web服务器（第4版）</a><br />
<a href="http://blog.kovyrin.net/2006/05/30/nginx-php-fastcgi-howto/">Nginx With PHP As FastCGI Howto</a></p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2008/12/06/nginx-php-gentoo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP 的 OpenSSL 库</title>
		<link>http://log.dongsheng.org/2008/09/27/php-openssl/</link>
		<comments>http://log.dongsheng.org/2008/09/27/php-openssl/#comments</comments>
		<pubDate>Sat, 27 Sep 2008 03:23:02 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[cryptography]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=17</guid>
		<description><![CDATA[书接上回，在研究 XML 签名之前先研究一下 OpenSSL 库。 签名和原理 PHP 签名的函数原型是： bool openssl_sign ( string $data , string &#038;$signature , mixed $priv_key_id [, [...]]]></description>
			<content:encoded><![CDATA[<p>书接<a href="http://log.dongsheng.org/archives/16">上回</a>，在研究 XML 签名之前先研究一下 OpenSSL 库。</p>
<h3>签名和原理</h3>
<p>PHP 签名的函数原型是：</p>
<pre>
bool openssl_sign ( string $data , string &#038;$signature , mixed $priv_key_id [, int $signature_alg ] )
</pre>
<p>大四时学的密码学全忘光了，用 Google CodeSearch 搜了一气 OpenSSL 的源代码才搞明白了签名的原理。</p>
<p>生成签名：</p>
<ol>
<li>对 $data 按照 $signature_alg 设置的算法（默认是OPENSSL_ALGO_SHA1）进行 hash 运算</li>
<li>用私钥加密（$priv_key_id）</li>
<li>$signature 就是产生的签名数据，连同 $data 发送给接收方</li>
</ol>
<p>可用的 hash 算法包括：</p>
<ul>
<li>OPENSSL_ALGO_SHA1</li>
<li>OPENSSL_ALGO_MD5</li>
<li>OPENSSL_ALGO_MD4</li>
<li>OPENSSL_ALGO_MD2</li>
</ul>
<p>验证：</p>
<ol>
<li>用公钥解密签名数据</li>
<li>解密后的结果是 $data 的 hash 值，接受方再生成 $data 的 hash 值与之对比</li>
</ol>
<h3>签名验证算法</h3>
<p>最常见的有两种：基于大数因子分解问题的数字签名（RSA），基于离散对数问题的数字签名（DSA），公私钥分别对应 ~/.ssh/id_rsa &#038; ~/.ssh/id_rsa.pub 和 ~/.ssh/id_dsa &#038; ~/.ssh/id_dsa.pub<br />
二者区别在于 RSA 还可以用于加密，而 DSA 只能用于签名验证，二者签名效率相近，但 RSA 的验证要远快于 DSA。</p>
<p>所以 PHP 中使用 RSA，公私钥可以用 OpenSSL 工具包生成：</p>
<pre>
openssl genrsa 512 >id_rsa
openssl rsa -pubout <id_rsa >id_rsa.pub
</pre>
<p>我在 .ssh 目录下的 RSA 公私钥是用 ssh-keygen 生成的，但在在这里做试验失败，可能于密钥长度有关系。</p>
<p>验证函数原型：</p>
<pre>
int openssl_verify  (  string $data  ,  string $signature  ,  mixed $pub_key_id  [,  int $signature_alg = OPENSSL_ALGO_SHA1  ] )
</pre>
<p>很好理解，$data 是接受方获取的数据，$signature 是一起发过来的签名，$pub_key_id 是校验用的公钥，$signature_alg 就是前面制定的 hash 算法了。</p>
<h3>加密</h3>
<p>函数原型：</p>
<pre>
int openssl_seal  ( string $data  , string &#038;$sealed_data  , array &#038;$env_keys  , array $pub_key_ids  )
</pre>
<ol>
<li>用随机字符串加密 data （ <a href="http://www.rsa.com/rsalabs/node.asp?id=2250">RC4</a> 加密算法）</li>
<li>用 pub_key_ids 里的公钥对共享密钥进行加密，将结果保存在 env_keys</li>
<li>将 env_keys 和 sealed_data 发送给接收方</li>
</ol>
<h3>解密</h3>
<p>函数原型：</p>
<pre>
bool openssl_open  ( string $sealed_data  , string &#038;$open_data  , string $env_key  , mixed $priv_key_id  )
</pre>
<ol>
<li>私钥揭开 env_key</li>
<li>用 env_key 打开加密消息</li>
</ol>
<h3>用 PHP 创建公私钥</h3>
<pre>
function get_key_pair() {
    $ret = array();
    $res = openssl_pkey_new();
    openssl_pkey_export($res, $ret['private_key']);
    $pub_key = openssl_pkey_get_details($res);
    $ret['public_key'] = $pub_key['key'];
    return $ret;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2008/09/27/php-openssl/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>在 PHP 中使用 XMLRPC</title>
		<link>http://log.dongsheng.org/2008/09/25/xmlrpc-php/</link>
		<comments>http://log.dongsheng.org/2008/09/25/xmlrpc-php/#comments</comments>
		<pubDate>Thu, 25 Sep 2008 13:22:03 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[xmlrpc]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=16</guid>
		<description><![CDATA[这几天在研究 Moodle Network 组件，通过这个模块，各个孤立的系统被连接到了一起，实现了单点登录和资源共享（对于 e-learning 有很大的意义），通信协议是 XML-RPC，信息安全不是依赖 SSL 的方案，而是在采用了 XML 签名（不对称加密算法），想法非常好，但实现的不太完整，因为这个模块的原作者离开了在新西兰的公司，整得像个半完成作品。 今天看了一下代码，打算在这上面解决多 Moodle 系统的资源共享问题（包含点对点和 HUB 模式），之前没用过 XMLRPC，所以现在开始学一下，我用的是 PHP 的 XMLRPC [...]]]></description>
			<content:encoded><![CDATA[<p>这几天在研究 Moodle Network 组件，通过这个模块，各个孤立的系统被连接到了一起，实现了单点登录和资源共享（对于 e-learning 有很大的意义），通信协议是 XML-RPC，信息安全不是依赖 SSL 的方案，而是在采用了 XML 签名（不对称加密算法），想法非常好，但实现的不太完整，因为这个模块的原作者离开了在新西兰的公司，整得像个半完成作品。</p>
<p>今天看了一下代码，打算在这上面解决多 Moodle 系统的资源共享问题（包含点对点和 HUB 模式），之前没用过 XMLRPC，所以现在开始学一下，我用的是 PHP 的 XMLRPC 模块（比纯 PHP 实现快了不少）。</p>
<p>首先实现一个 XMLRPC 服务，我封装了一个简单的类：</p>
<pre>
class xmlrpc_server {
    private $server;
    public function __construct() {
        $this->server = xmlrpc_server_create();
    }
    public function add($name, $func) {
        xmlrpc_server_register_method($this->server, $name, $func);
    }
    public function run() {
        $req = file_get_contents('php://input');
        $response = xmlrpc_server_call_method($this->server, $req, null);
        echo $response;
        xmlrpc_server_destroy($this->server);
    }
}
</pre>
<p>调用这个类创建一个服务：</p>
<pre>
header('Content-Type: text/xml');
function func_add($method, $params) {
    return $params[0]+$params[1];
}
$xmlrpc = new xmlrpc_server;
$xmlrpc->add('add', 'func_add');
$xmlrpc->run();
</pre>
<p>PHP 客户端的调用是通过 HTTP 的 POST 方法，我用的是 <a href="http://code.anbutu.com/n-342">cURL</a> 扩展：</p>
<pre>
require_once('curl.class.php');
class xmlrpc_client {
    public function __construct($url, $autoload = false) {
        $this->connection = null;
        $this->url = $url;
        $this->connection = new curl;
        $this->methods = array();
        if ($autoload) {
            $resp = $this->call('system.listMethods', null);
            $this->methods = $resp;
        }
    }
    public function call($method, $params = null) {
        $post = xmlrpc_encode_request($method, $params);
        return xmlrpc_decode($this->connection->post($this->url, $post));
    }
}
header('Content-Type: text/plain');
$rpc = "http://10.0.0.10/api.php";
$client = new xmlrpc_client($rpc, true);
print_r($client->call('add', array(199,2)));
</pre>
<p>待续，下一步优化代码并实现 XML 签名技术。</p>
<p>资料：</p>
<p><a href="http://www.w3.org/TR/xmldsig-core/">XML Signature Syntax and Processing</a><br />
<a href="http://au2.php.net/manual/en/book.openssl.php">OpenSSH</a><br />
<a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and Processing</a></p>
<p>== TO BE CONTINUED ==</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2008/09/25/xmlrpc-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Gentoo 上的 Python 没有 sqlite 支持</title>
		<link>http://log.dongsheng.org/2008/09/24/gentoo-python-sqlite/</link>
		<comments>http://log.dongsheng.org/2008/09/24/gentoo-python-sqlite/#comments</comments>
		<pubDate>Wed, 24 Sep 2008 12:20:00 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[OS]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[gentoo]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[sqlite]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=15</guid>
		<description><![CDATA[Sqlite 从 Python 2.5 以后就是标准模块了，但 Gentoo 上的 Python 竟然没有这个模块，开始以为需要一个额外的包，但安装 pysqlite 以后问题依旧（过后才想起来是没进入标准前的一个模块），于是使用 USE 标签重新编译 Python： USE="sqlite" emerge python 问题解决]]></description>
			<content:encoded><![CDATA[<p>Sqlite 从 Python 2.5 以后就是标准模块了，但 Gentoo 上的 Python 竟然没有这个模块，开始以为需要一个额外的包，但安装 pysqlite 以后问题依旧（过后才想起来是没进入标准前的一个模块），于是使用 USE 标签重新编译 Python：</p>
<pre>
USE="sqlite" emerge python
</pre>
<p>问题解决</p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2008/09/24/gentoo-python-sqlite/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>cURL 并发访问</title>
		<link>http://log.dongsheng.org/2008/07/16/curl-multiple-handlers/</link>
		<comments>http://log.dongsheng.org/2008/07/16/curl-multiple-handlers/#comments</comments>
		<pubDate>Wed, 16 Jul 2008 03:10:23 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=8</guid>
		<description><![CDATA[通常情况下 PHP 中的 cURL 是阻塞运行的，就是说创建一个 cURL 请求以后必须等它执行成功或者超时才会执行下一个请求，curl_multi_* 系列函数使并发访问成功可能，PHP 文档对这个函数的介绍不太详细，用法如下： $requests = array('http://zz.dongsheng.org', 'http://www.google.com'); $main = curl_multi_init(); $results = array(); $errors [...]]]></description>
			<content:encoded><![CDATA[<p>通常情况下 PHP 中的 cURL 是阻塞运行的，就是说创建一个 cURL 请求以后必须等它执行成功或者超时才会执行下一个请求，curl_multi_* 系列函数使并发访问成功可能，PHP 文档对这个函数的介绍不太详细，用法如下：</p>
<pre>$requests = array('http://zz.dongsheng.org', 'http://www.google.com');
$main    = curl_multi_init();
$results = array();
$errors  = array();
$info    = array();
$count   = count($requests);
for($i = 0; $i < $count; $i++) {
  $handles[$i] = curl_init($requests[$i]);
  var_dump($requests[$i]);
  curl_setopt($handles[$i], CURLOPT_URL, $requests[$i]);
  curl_setopt($handles[$i], CURLOPT_RETURNTRANSFER, 1);
  curl_multi_add_handle($main, $handles[$i]);
}
$running = 0;

do {
  curl_multi_exec($main, $running);
} while($running > 0);

for($i = 0; $i < $count; $i++)
{
  $results[] = curl_multi_getcontent($handles[$i]);
  $errors[]  = curl_error($handles[$i]);
  $info[]    = curl_getinfo($handles[$i]);
  curl_multi_remove_handle($main, $handles[$i]);
}
curl_multi_close($main);
var_dump($results);
var_dump($errors);
var_dump($info);
</pre>
<p>通过这种方式就可以实现多任务并发执行，更详细的用法看我写的这个类：<a href="http://code.anbutu.com/n-342">curl class</a></p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2008/07/16/curl-multiple-handlers/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>CVS Cheat Sheet</title>
		<link>http://log.dongsheng.org/2008/07/15/cvs-cheat-sheet/</link>
		<comments>http://log.dongsheng.org/2008/07/15/cvs-cheat-sheet/#comments</comments>
		<pubDate>Tue, 15 Jul 2008 11:07:08 +0000</pubDate>
		<dc:creator>Dongsheng Cai</dc:creator>
				<category><![CDATA[OS]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[cvs]]></category>

		<guid isPermaLink="false">http://log.dongsheng.org/?p=7</guid>
		<description><![CDATA[记住：cvs 的操作可以通过 cvs -H 来查看，比如： cvs -H diff CVS CHECKOUT d 输出目录 A 重设所有 sticky tags r 指定一个 tag CVS [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-weight:bold;">记住</span>：cvs 的操作可以通过 cvs -H 来查看，比如：<br />
<code>cvs -H diff</code><br />
CVS CHECKOUT<br />
d 输出目录<br />
A 重设所有 sticky tags<br />
r 指定一个 tag<br />
CVS UPDATE<br />
d 参数</p>
<p>CVS DIFF<br />
b 忽略行尾空格<br />
c 输出上下文<br />
p 显示所改变的函数名（或类名）<br />
u 使用 unified 输出格式<br />
r 标识 tag</p>
<p>CVS UPDATE<br />
p 重定向到标准输出<br />
r 标识tag</p>
<p>CVS 操作的默认参数可以写在 ~/.cvsrc 里，如<br />
<code>diff -bc<br />
update -dP</code><br />
USE CASE：<br />
1. 查看历史<br />
<code>cvs log xx.php<br />
cvs log -r1.5 xx.php</code><br />
2. 添加文件<br />
<code>cvs add xx.php<br />
cvs ci xx.php<br />
# 添加图片<br />
cvs add -kb xx.jpg<br />
cvs ci xx.jpg<br />
# 添加目录<br />
cvs add folder1<br />
# 不需要提交</code><br />
3. 删除<br />
<code>rm xx.php<br />
cvs remove xx.php<br />
cvs commit xx.php<br />
# cvs 无法彻底删除空目录，只能到服务端彻底删除</code><br />
4. 版本恢复<br />
<code>cvs update -p -r 1.6 xx.php > xx.php</code><br />
5. 代码更新<br />
<code>cvs update<br />
cvs update -dPA<br />
# 创建新目录（如果必要），清理空目录，重置锁定点</code><br />
6. diff<br />
<code>cvs diff -upc xx.php<br />
# 生成 patch<br />
cvs diff -up xx.php > xx.patch<br />
# 应用 patch<br />
patch -p0 < xx.patch<br />
# 测试 patch<br />
patch --dry-run -p0 < xx.path<br />
</code><br />
更多 CVS 操作：<a href="http://code.anbutu.com/n-462">.bashrc</a></p>
]]></content:encoded>
			<wfw:commentRss>http://log.dongsheng.org/2008/07/15/cvs-cheat-sheet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using apc
Database Caching 4/112 queries in 0.142 seconds using apc
Object Caching 1105/1384 objects using apc

Served from: log.dongsheng.org @ 2012-05-20 15:32:33 -->
