<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity=60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]

----
Also see [[AdvancedOptions]]
<<importTiddlers>>
<<toolbar permalink>>

[>img[agentzh.jpg]] I'm a happy programmer living in San Francisco, CA. My real name is Yichun Zhang, or 章亦春 in Chinese. I usually use the nick {{{agentzh}}} on the web.

I'm currently working as a systems engineer for [[CloudFlare|http://www.cloudflare.com]] and my main focus is on Nginx and OpenResty development.

I used to work for [[Yahoo! China|http://cn.yahoo.com]] and [[Taobao, Alibaba|http://www.taobao.com]] while working in Beijing, China.
This is site is powered by the excellent [[TiddlyWiki|http://www.tiddlywiki.com/]].

The site's source is hosted on ~GitHub: https://github.com/agentzh/agentzh.org
<<toolbar permalink>>

I'm posting nginx related stuffs and other things to my blog site on Blogger: http://agentzh.blogspot.com/

I'm also posting Nginx tutorials for both users and developers in Chinese at Sina Blog here: http://blog.sina.com.cn/openresty
<<toolbar permalink>>

You're welcome to mail me via {{{agentzh@gmail.com}}}. This mail address is also my MSN account.

I'm quite active in the [[nginx|http://nginx.org/mailman/listinfo/nginx]] and [[nginx-devel|http://nginx.org/mailman/listinfo/nginx-devel]] mailing lists. I'm also keeping an eye on the ~PerlChina, lua-l and erlang-questions mailing lists as well ;)

If you want to ask me questions about my Nginx or OpenResty related work, please join the [[OpenResty community|http://openresty.org/#Community]] and post there.
[[AboutMe]] [[ContactMe]]
<<toolbar permalink>>
! Source listing
!! reader.erl
Here's the Erlang implementation A, not using Erlang binaries:
{{{
-module(reader).
-export([main/0]).

main() ->
    {ok, File} = file:open("data.log", [read]),
    Lines = count_lines(File, 0),
    io:format("Found ~w lines.~n", [Lines]),
    halt().

count_lines(File, Count) ->
    case file:read_line(File) of
        {ok, _Line} ->
            count_lines(File, Count + 1);
        eof ->
            Count
    end.
}}}
!! reader-bin.erl
Here's the Erlang implementation B, using Erlang binaries:
{{{
-module(reader).
-export([main/0]).

main() ->
    {ok, File} = file:open("data.log", [read, binary]),
    Lines = count_lines(File, 0),
    io:format("Found ~w lines.~n", [Lines]),
    halt().

count_lines(File, Count) ->
    case file:read_line(File) of
        {ok, _Line} ->
            count_lines(File, Count + 1);
        eof ->
            Count
    end.
}}}
!! reader-bin-raw.erl
Here's the Erlang implementation C, using Erlang binaries, raw file mode, and big read_ahead:
{{{
-module(reader).
-export([main/0]).

main() ->
    {ok, File} = file:open("data.log", [read, binary, raw, {read_ahead, 1024 * 1024}]),
    Lines = count_lines(File, 0),
    io:format("Found ~w lines.~n", [Lines]),
    halt().

count_lines(File, Count) ->
    case file:read_line(File) of
        {ok, _Line} ->
            count_lines(File, Count + 1);
        eof ->
            Count
    end.
}}}
! reader.pl
Here's the Perl 5 implementation:
{{{
open my $in, "data.log" or die;
my $n;
while (<$in>) {
    $n++;
}
print "Found $n lines.\n";
}}}
! Test data file
The data file is from a real nginx error.log file snapshot in our production environment. Here's its basic information:
{{{
$ wc data.log
    412003  12957676 197733977 data.log
$ ls -lh data.log
-rw-r--r-- 1 agentz users 189M 2011-06-28 15:08 data.log
}}}
! Benchmark
To help OS cache the disk data, we only take the time of the programs' second runs.
!! Results on Slackware Linux x86_64
Linux Kernel: 2.6.33.1
CPU: Intel ~Core2Duo T9600
Hard disk: SATA 7200'
Erlang OTP: ~R14B01 (erts-5.8.2)
Perl: 5.12.1

!!! The Erlang program A compiled in bytecode
{{{
$ erlc reader.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m14.023s
user	0m13.237s
sys	0m0.742s
}}}
!!! The Erlang program A compiled in native code
{{{
$ erlc +native reader.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m14.007s
user	0m13.233s
sys	0m0.739s
}}}
!!! The Erlang program B compiled in bytecode
{{{
$ erlc reader-bin.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m4.451s
user	0m4.322s
sys	0m0.104s
}}}
!!! The Erlang program B compiled in native code
{{{
$ erlc +native reader-bin.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m4.531s
user	0m4.417s
sys	0m0.095s
}}}
!!! The Erlang program C compiled in bytecode
{{{
$ erlc reader-bin-raw.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m10.001s
user	0m8.520s
sys	0m1.386s
}}}
!!! The Erlang program C compiled in native code
{{{
$ erlc +native reader-bin-raw.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m10.398s
user	0m8.673s
sys	0m1.359s
}}}
!!! The Perl 5 program
{{{
$ time perl reader.pl
Found 412003 lines.

real	0m0.332s
user	0m0.271s
sys	0m0.061s
}}}
!! Results on Mac OS X 10.6.7
CPU: Intel ~Core2Duo 1.86GHz
Hard disk: SSD
Erlang OTP: ~R14B02 (erts-5.8.3)
Perl: 5.12.3
!!! The Erlang program A compiled in bytecode
{{{
$ erlc reader.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m32.254s
user	0m27.532s
sys	0m4.681s
}}}
!!! The Erlang program A compiled in native code
{{{
$ erlc +native reader.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m32.043s
user	0m27.356s
sys	0m4.646s
}}}
!!! The Erlang program B compiled in bytecode
{{{
$ erlc reader-bin.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m6.700s
user	0m6.447s
sys	0m0.212s
}}}
!!! The Erlang program B compiled in native code
{{{
$ erlc +native reader-bin.erl
$ time erl -noshell -s reader main
Found 412003 lines.

real	0m6.721s
user	0m6.461s
sys	0m0.218s
}}}
!!! The Perl 5 program
{{{
$ time perl reader.pl
Found 412003 lines.

real	0m0.677s
user	0m0.480s
sys	0m0.182s
}}}
! Conclusion
Erlang's {{{file:read_line/1}}} is painfully slow on both Linux and Mac OS X, as of the latest version R14. It's more than one order of magnitude slower than plain Perl 5. Enabling native code generation can make the Erlang version a little faster.

Update: Excluding the time involved in beam startup and quit only makes the result <100ms faster according to my tests on the Linux box.
<<toolbar permalink>>

I'm quite active in Sina Weibo (A twitter clone very popular in China): http://weibo.com/agentzh

I do own a twitter account, [[@agentzh|http://twitter.com/agentzh]].

If you're interested in my opensource development work, go follow me on ~GitHub! http://github.com/agentzh/
[[About me|AboutMe]]
[[Blogs]]
[[Follow me|FollowMe]]
[[Presentations]]
[[Projects]]
[[Contact me|ContactMe]]
[[About this site|AboutThisSite]]
[img[feed-icon-14x14.png]] [[RSS feed|RSSFeed]]
<p/> <p/>
<script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-24724974-1']);
  _gaq.push(['_setDomainName', 'agentzh.org']);
  _gaq.push(['_trackPageview']);

  var _gaf = (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  });
  setTimeout(_gaf, 0);

</script>

OpenResty is a software bundle for various useful Nginx addons, ~LuaJIT/Lua, and the Nginx core that helps constructing high-performance web applications. See

    http://openresty.org
<<toolbar permalink>>

Here goes a list of slides that I used in various opensource events and school lectures.

These slides are powered by the [[slides.htm|https://github.com/kindy61/slides.htm]] slide-making engine based on AJAX.

''//Note: Please use the arrow keys or pageup/pagedown keys on your keyboard to switch slides.//''
! Year 2014
!! NGINX, Lua, and beyond
This talk was given at NGINX Inc's [[NGINX User Summit 2014|https://www.eventbrite.com/e/nginx-user-summit-and-training-tickets-10393173261]] on 25 February 2014.

View slides in your web browser: http://agentzh.org/misc/slides/nginx-user-summit-2014/

Download the slides as PDF: http://agentzh.org/misc/slides/nginx-lua-and-beyond.pdf

! Year 2013
!! The Way of Optimizing and Troubleshooting Our Lua Waf
This talk was given at ~CloudFlare's Beer Meeting on 19 April 2013.

View slides in your web browser: http://agentzh.org/misc/slides/beer-meeting-2013-04-19/

Download the slides as PDF: http://agentzh.org/misc/slides/beer-meeting-2013-04-19.pdf

!! sregex: matching Perl 5 regexes on data streams
This talk was given at [[YAPC::NA 2013|http://www.yapcna.org/yn2013/]] in Austin, TX, USA.

Talk summary: http://www.yapcna.org/yn2013/talk/4762

View slides in your web browser: http://agentzh.org/misc/slides/yapc-na-2013-sregex/

Download the slides as PDF: http://agentzh.org/misc/slides/yapc-na-2013-sregex.pdf

!! Flame Graphs for online performance profiling
This talk was given at [[YAPC::NA 2013|http://www.yapcna.org/yn2013/]] in Austin, TX, USA.

Talk summary: http://www.yapcna.org/yn2013/talk/4579

View slides in your web browser: http://agentzh.org/misc/slides/yapc-na-2013-flame-graphs/

Download the slides as PDF: http://agentzh.org/misc/slides/yapc-na-2013-flame-graphs.pdf

!! Introduction to off-CPU Time Flame Graphs
This talk was given at the ~CloudFlare Beer Meeting on 23 August 2013.

View slides in your web browser: http://agentzh.org/misc/slides/off-cpu-flame-graphs/

Download the slides as PDF: http://agentzh.org/misc/slides/off-cpu-flame-graphs.pdf

! Year 2012
!! ngx_openresty: an Nginx ecosystem glued by Lua
This talk was given at [[Tech-Club Technical Salon|http://event.weibo.com/351359]] held in the Xiamen city, China.

View slides in your web browser: http://agentzh.org/misc/slides/ngx-openresty-ecosystem/

Download the slides as PDF: http://agentzh.org/misc/slides/ngx-openresty-ecosystem.pdf

!! Scripting libdrizzle with Lua inside Nginx
This presentation was given at [[Percona Live MySQL Conference 2012|http://www.percona.com/live/mysql-conference-2012/sessions/scripting-mysql-lua-and-libdrizzle-inside-nginx]] held in Santa Clara, CA, USA.

View slides in your web browser: http://agentzh.org/misc/slides/libdrizzle-lua-nginx/#2

Download the slides as PDF: http://agentzh.org/misc/slides/libdrizzle-lua-nginx.pdf

! Year 2011
!! Applications of ngx_openresty and perl in lz.taobao.com

This talk was given at [[Beijing Perl Workshop 2011|http://conference.perlchina.org/bjpw2011/talks]].

Watch the video online: http://v.ku6.com/show/TY8Vre59guTE_C8o.html

View slides in your web browser: http://agentzh.org/misc/slides/perl-lz-apps/

Download the slides as PDF: http://agentzh.org/misc/slides/perl-lz-apps.pdf

! Year 2010
!! Introduction to nginx.conf scripting
This talk was given at the [[Beijing Perl Workshop|http://conference.perlchina.org]] 2010 April meeting and the [[Beijing OpenParty 2010 June event|http://www.beijing-open-party.org/event/2]].

View slides in your web browser: http://agentzh.org/misc/slides/nginx-conf-scripting/

Download the slides as PDF: http://agentzh.org/misc/slides/nginx-conf-scripting.pdf

Please note that ngx_eval module is no longer recommended because we're in more favor of ngx_lua nowadays.

!! Recent developments in nginx.conf scripting
This talk was given at the [[Beijing OpenParty 2010 June event|http://www.beijing-open-party.org/event/2]].

View slides in your web browser: http://agentzh.org/misc/slides/recent-dev-nginx-conf/

Download the slides as PDF: http://agentzh.org/misc/slides/recent-dev-nginx-conf.pdf

!! The state of the art of nginx.conf scripting
This talk was given at the [[ECUG 2010 event|http://agentzh.org/misc/slides/nginx-state-of-the-art/]].

Watch the (Chinese-speech) video online: http://v.ku6.com/show/D00rqtnRwKzJdIsB.html

View the (English) slides in your web browser: http://agentzh.org/misc/slides/nginx-state-of-the-art/

Download the slides as PDF: http://agentzh.org/misc/slides/nginx-state-of-the-art.pdf

! Year 2009
!! A Firefox cluster driven by ~JavaScript, Perl, & PL/~PgSQL
This talk was given at the Beijing Perl Workshop 2009 Feb Meetup and [[Beijing OpenParty 2009 Feb event|http://www.beijing-open-party.org/post/beijing-open-party-2009-02-fox-event-begin]].

View the slides in your web browser: http://agentzh.org/misc/slides/BJPW200902/ffcluster.html

Download the slides as PDF: http://agentzh.org/misc/slides/bjpw200902-ffcluster.pdf

!! Introduction to our VDOM.pm & vdom-webkit cluster
Use vision information to do intelligent web scraping by rendering pages via a ~WebKit & VDOM cluster.

This talk was given at [[Beijing Perl Workshop 2009|http://conference.perlchina.org/bjpw2009/talks]] and a meetup with Taobao.com's front-end engineers in the Hangzhou city.

View the slides in your browser: http://agentzh.org/misc/slides/taobao-fe/vdomwebkit.html

Download the slides as PDF: http://agentzh.org/misc/slides/taobao-fe-vdomwebkit.pdf

!! A Tour of Perl Testing
This talk was given at the [[Beijing Perl Workshop 2009|http://conference.perlchina.org/bjpw2009/talks]] event.

View slides in your web browser: http://agentzh.org/misc/slides/BJPW2009/perl-testing.html

Download the slides as PDF: http://agentzh.org/misc/slides/bjpw2009-perl-testing.pdf

! Year 2008
!! Nifty web apps on an ~OpenResty
This talk was given at the D2 Frontend Technology event organized by Yahoo! China.

View slides in your web browser: http://agentzh.org/misc/slides/openresty-d2/

Download the slides as PDF: http://agentzh.org/misc/slides/openresty-d2.pdf

!! ~OpenResty: Your Relational Cloud
~OpenResty.pm is a general-purpose ~RESTful web service platform. In this talk I explained its origin, REST API, and its unusual applications.

This talk was given at the [[Beijing Perl Workshop 2008|http://conference.perlchina.org/bjpw2008/talks]] event and the Yahoo! China Engineer Tech. Salon.

View slides in your web browser: http://agentzh.org/misc/slides/openresty-yes/

Download the slides as PDF: http://agentzh.org/misc/slides/openresty-yes.pdf

! Year 2007
!! XUL::App - Jifty way of doing XUL
XUL::App is a nifty Firefox extension development framework based on Perl. It has a lot of parallels with Jifty. In particular, this framework allows you to build real-world modern Firefox extensions using Perl.

In this talk, I demonstrated how to use this framework to write a "hello, world" Firefox extension with ~I18N support in lines. 

This talk was given at the [[Beijing Perl Workshop 2008|http://conference.perlchina.org/bjpw2008/talks]] event.

View slides in your web browser: http://agentzh.org/misc/slides/xulapp/

Download the slides as PDF: http://agentzh.org/misc/slides/xulapp.pdf

!! Contribute to Pugs
Pugs is a Perl 6 compiler written in Haskell. In this talk, I introduced the Pugs project as well as my involvement in the automated testing work of the Perl 6 language to the ~PerlChina folks and encouraged people to contribute Pugs.

This talk was given at the Beijing Perl Workshop 2007 event.

View slides in your web browser: http://agentzh.org/misc/slides/contr_pugs/

Download the slides as PDF: http://agentzh.org/misc/slides/contr_pugs.pdf

!! Use UML::Class::Simple to generate simple UML class diagrams
UML::Class::Simple is my Perl CPAN module that can generate UML class diagrams automatically from arbitrary real-world Perl OO libraries.

This talk was given at the Beijing Perl Workshop 2007 event.

View slides in your web browser: http://agentzh.org/misc/slides/umlclass/

Download the slides as PDF: http://agentzh.org/misc/slides/umlclass.pdf

! Year 2006
!! Introduction to ~XClips
~XClips is an expert system development language designed by myself, which is implemented atop NASA's [[CLIPS|http://clipsrules.sourceforge.net/]]. This talk explains the appearance of the language and some details of its implementation and applications.

This talk was given as a lecture at the [[Jiangsu University|http://www.ujs.edu.cn/]].

View slides in your web browser: http://agentzh.org/misc/slides/xclips/

Download the slides as PDF: http://agentzh.org/misc/slides/xclips.pdf

!! The Art of Naming
This talk teaches the art of naming for programmers, using lots of examples from Perl 6, C/C++, Java, and other programming languages.

This talk was given as a lecture at the [[Jiangsu University|http://www.ujs.edu.cn/]].

View slides in your web browser:
* http://agentzh.org/misc/slides/naming/
* http://agentzh.org/misc/slides/naming/naming_recap.html

Or download the slides as PDF files:
* http://agentzh.org/misc/slides/naming.pdf
* http://agentzh.org/misc/slides/naming_recap.pdf

!! XML in the real world
This talk shows various interesting applications of XML in the real world. It also introduces some of my web scraping tools based on Perl 5.

This talk was given as a lecture at the [[Jiangsu University|http://www.ujs.edu.cn/]].

View slides in your web browser: http://agentzh.org/misc/slides/xmlapp/

Download the slides as PDF: http://agentzh.org/misc/slides/xmlapp.pdf

!! Functions and Methods
This lecture discusses functions and methods in ~Object-Oriented Programming (OOP). This is one of my series of lectures on OOP given at the [[Jiangsu University|http://www.ujs.edu.cn/]].

View slides in your web browser: http://agentzh.org/misc/slides/func/

Download the slides as PDF: http://agentzh.org/misc/slides/func.pdf

!! Design Patterns - Using FAST
This talk explains the design patterns used in the construction process of the FAST (Flowchart Abstract Syntax Tree transformer) program, which can convert a program described by a flowchart into a structural program.

This talk was given as a lecture at the [[Jiangsu University|http://www.ujs.edu.cn/]].

View slides in your web browser: http://agentzh.org/misc/slides/patterns/

Download the slides as PDF: http://agentzh.org/misc/slides/patterns.pdf
<<toolbar permalink>>

The most important opensource project that I've been working on for years is [[OpenResty|http://openresty.org]].

You can find most of my opensource projects on my ~GitHub homepage:

    https://github.com/agentzh

!Nginx

I've started or participated in the development of a bunch of nginx modules:

    http://wiki.nginx.org/3rdPartyModules

!Perl

I'm a Perl programmer that writes dozens of [[CPAN modules|http://search.cpan.org/~agent/]].
<<toolbar permalink>>

This site's RSS  feed is available at http://agentzh.org/index.xml [img[feed-icon-28x28.png]].
yet another idiot who loves programming
agentzh's home
http://agentzh.org/
body {
    font-size: 1.2em;
}
The owner of this site. He loves the nick agentzh though. But please do //not// capitalize the nick!