Index: /lang/perl/MENTA/tags/release-0.01/app/controller/bbs_sqlite.pl
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/controller/bbs_sqlite.pl (revision 23962)
+++ /lang/perl/MENTA/tags/release-0.01/app/controller/bbs_sqlite.pl (revision 23962)
@@ -0,0 +1,24 @@
+load_plugin('sql');
+
+sub do_bbs_sqlite {
+    sql_prepare_exec(q{CREATE TABLE IF NOT EXISTS entries (id INTEGER PRIMARY KEY, body VARCHAR(255))});
+
+    if (is_post_request) {
+        my $body = param('body');
+        if ($body) {
+            sql_prepare_exec('INSERT INTO entries (body) VALUES (?)', $body);
+        }
+        redirect(docroot . 'bbs_sqlite'); # TODO: use uri_for
+    } else {
+        my ( $rows, $pager ) = sql_select_paginate(
+            'SELECT id, body FROM entries ORDER BY id DESC',
+            [],
+            {
+                page => param('page') || 1,
+                rows => 10,
+            }
+        );
+        render("bbs.html", $rows, $pager);
+    }
+}
+
Index: /lang/perl/MENTA/tags/release-0.01/app/controller/param.pl
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/controller/param.pl (revision 23706)
+++ /lang/perl/MENTA/tags/release-0.01/app/controller/param.pl (revision 23706)
@@ -0,0 +1,5 @@
+sub do_param {
+    my $foo = param('foo');
+    finalize("PARAM foo: $foo");
+}
+
Index: /lang/perl/MENTA/tags/release-0.01/app/controller/users.pl
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/controller/users.pl (revision 23776)
+++ /lang/perl/MENTA/tags/release-0.01/app/controller/users.pl (revision 23776)
@@ -0,0 +1,8 @@
+load_plugin("sql");
+
+sub do_users {
+    sql_dbh('DBI:CSV:f_dir=../app/data');
+    my $rows = sql_select_all('select * from users');
+    render('users.html', $rows);
+}
+
Index: /lang/perl/MENTA/tags/release-0.01/app/controller/mail.pl
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/controller/mail.pl (revision 23667)
+++ /lang/perl/MENTA/tags/release-0.01/app/controller/mail.pl (revision 23667)
@@ -0,0 +1,7 @@
+load_plugin("mail");
+
+sub do_mail {
+    mail_send('info@example.com', 'this is subject', 'hi!');
+    redirect('http://example.com');
+}
+
Index: /lang/perl/MENTA/tags/release-0.01/app/menta.cgi
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/menta.cgi (revision 23980)
+++ /lang/perl/MENTA/tags/release-0.01/app/menta.cgi (revision 23980)
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+use lib '../lib';
+use MENTA;
+# -- ここまではおまじない --
+
+run_menta({
+    # MENTA 自体の設定
+    menta => {
+        # エラー出力するか？
+        kcatch_mode => 1,
+        # 最大表示文字数
+        max_post_body => 1_024_000,
+        # コントローラーをいれるディレクトリ
+        controller_dir => 'controller/',
+        # テンプレートファイルディレクトリへのパス
+        tmpl_dir => 'tmpl/',
+        # テンプレートファイルのキャッシュディレクトリへのパス
+        tmpl_cache_dir => 'tmpl_cache/',
+    },
+    # あなたのアプリの設定
+    application => {
+        docroot => '',
+        title => 'MENTA サンプルアプリ',
+        sqlitefile => 'data/data.sqlite',
+        sql => {
+            dsn => 'dbi:SQLite:data/data.sqlite',
+        },
+        counter => {
+            file => 'data/counter.txt'
+        },
+    },
+});
+
+# 以下、あなたのプログラム
+
Index: /lang/perl/MENTA/tags/release-0.01/app/static/jquery.js
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/static/jquery.js (revision 23419)
+++ /lang/perl/MENTA/tags/release-0.01/app/static/jquery.js (revision 23419)
@@ -0,0 +1,32 @@
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
+ * $Rev: 5685 $
+ */
+(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
+return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
+return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
+selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
+return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
+this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
+return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
+jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
+script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
+for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
+for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
+jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
+ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
+while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
+while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
+for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
+jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
+xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
+jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
+for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
+s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
+e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})();
Index: /lang/perl/MENTA/tags/release-0.01/app/static/style-sites.css
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/static/style-sites.css (revision 23559)
+++ /lang/perl/MENTA/tags/release-0.01/app/static/style-sites.css (revision 23559)
@@ -0,0 +1,18 @@
+body { font-family: monospace }
+h1   { padding: 0.5em }
+
+table {
+    border-style: solid;
+    border-width: 1px 0;
+}
+
+th {
+    border-style: solid;
+    border-width: 0 0 1px;
+}
+
+td {
+    padding: .5em;
+    border-style: solid;
+    border-width: 0 1px;
+}
Index: /lang/perl/MENTA/tags/release-0.01/app/data/users
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/data/users (revision 23414)
+++ /lang/perl/MENTA/tags/release-0.01/app/data/users (revision 23414)
@@ -0,0 +1,7 @@
+id,name
+1,Tokuhiro Matsuno
+2,lestrrat
+3,mattn
+4,fujiwara
+5,drry
+6,hidek
Index: /lang/perl/MENTA/tags/release-0.01/app/data/counter.txt
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/data/counter.txt (revision 23981)
+++ /lang/perl/MENTA/tags/release-0.01/app/data/counter.txt (revision 23981)
@@ -0,0 +1,1 @@
+1078
Index: /lang/perl/MENTA/tags/release-0.01/app/.htaccess
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/.htaccess (revision 23510)
+++ /lang/perl/MENTA/tags/release-0.01/app/.htaccess (revision 23510)
@@ -0,0 +1,7 @@
+DirectoryIndex menta.cgi
+RewriteEngine on
+
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteCond %{REQUEST_URI} !^/static
+RewriteRule ^(.*)$ menta.cgi/$1 [L,QSA]
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/footer.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/footer.html (revision 23958)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/footer.html (revision 23958)
@@ -0,0 +1,1 @@
+<p><a href="<?= uri_for('index') ?>">トップにもどる</a></p>
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/pager.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/pager.html (revision 23973)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/pager.html (revision 23973)
@@ -0,0 +1,15 @@
+? my $pager = shift
+? my $action = shift
+? my $page_n = $pager->{page}
+? if ($pager->{page} == 1) {
+前
+? } else {
+<a href="<?= uri_for($action, { page => $page_n - 1 }) ?>" rel="prev">前</a>
+? }
+|
+? if ($pager->{has_next}) {
+<a href="<?= uri_for($action, { page => $page_n + 1 }) ?>" rel="next">次</a>
+? } else {
+次
+? }
+(現在: <?= $page_n ?>)
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/counter.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/counter.html (revision 23973)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/counter.html (revision 23973)
@@ -0,0 +1,6 @@
+? my $title = 'カウンターのデモ'
+? load_plugin('counter')
+?=r render_partial('header.html', $title)
+<h1><?= $title ?></h1>
+現在の訪問者数は: <?= counter_increment() ?>人です。
+?=r render_partial('footer.html')
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/die.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/die.html (revision 23977)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/die.html (revision 23977)
@@ -0,0 +1,1 @@
+? die "こういう風に死にます"
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/users.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/users.html (revision 23973)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/users.html (revision 23973)
@@ -0,0 +1,15 @@
+? my $title = 'DBI'
+?=r render_partial('header.html', $title)
+<h1><?= $title ?></h1>
+<table>
+ <caption>ユーザ</caption>
+ <thead>
+  <tr><th>ID</th><th>名前</th></tr>
+ </thead>
+ <tbody>
+? for my $c (@{$_[0]}) {
+  <tr><td><?= $c->{id} ?></td><td><?= $c->{name} ?></td></tr>
+? }
+ <tbody>
+</table>
+?=r render_partial('footer.html')
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/form.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/form.html (revision 23977)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/form.html (revision 23977)
@@ -0,0 +1,11 @@
+?=r render_partial('header.html', 'フォームを使った例')
+? my $r = param('r') || ''
+<h1>フォームを使った例</h1>
+<p>パラメータ r: "<?= $r ?>"</p>
+
+<h2>GET</h2>
+<form method="get" action="<?= uri_for('form') ?>"><input type="text" name="r"><input type="submit" value="送信"></form>
+
+<h2>POST</h2>
+<form method="post" action="<?= uri_for('form') ?>"><input type="text" name="r"><input type="submit" value="送信"></form>
+?=r render_partial('footer.html')
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/hello.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/hello.html (revision 23973)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/hello.html (revision 23973)
@@ -0,0 +1,3 @@
+?=r render_partial('header.html', "PHP style")
+Hello to <?= param('user') ?>
+?=r render_partial('footer.html')
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/bbs.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/bbs.html (revision 23973)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/bbs.html (revision 23973)
@@ -0,0 +1,16 @@
+? my ($entries, $pager) = @_
+? my $title = 'SQLite をつかった一行掲示板'
+?=r render_partial('header.html', $title)
+<h1><?= $title ?></h1>
+<form method="post" action="<?= uri_for('bbs_sqlite') ?>">
+ <input type="text" name="body">
+ <input type="submit" value="送信">
+</form>
+
+<ul>
+? for my $entry (@{$entries}) {
+ <li class="hentry"><?= $entry->{id} ?> <?= $entry->{body} ?></li>
+? }
+</ul>
+?=r render_partial('pager.html', $pager, 'bbs_sqlite')
+?=r render_partial('footer.html')
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/goto_wassr.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/goto_wassr.html (revision 23981)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/goto_wassr.html (revision 23981)
@@ -0,0 +1,1 @@
+? redirect('http://wassr.jp/')
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/index.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/index.html (revision 23973)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/index.html (revision 23973)
@@ -0,0 +1,35 @@
+? my $title = config()->{application}->{title}
+?=r render_partial('header.html')
+<script type="text/javascript" src="<?= docroot ?>static/jquery.js"></script>
+<script type="text/javascript"><!--
+$(function() {
+    var $this = $('h1');
+    $this.css({background : 'orange'})
+         .text($this.text().replace('MENTA', 'めんた'));
+});
+//--></script>
+
+<h1><?= $title ?></h1>
+<p><?= localtime time ?></p>
+
+<h2>MENTA ってなに?</h2>
+<p>MENTA は CGI で気軽につかえるウェブアプリケーションフレームワークです</p>
+<ul>
+    <li>CGI でも高速に動作</li>
+    <li>レンタルサーバーでもつかえます</li>
+    <li>Object 指向がわからなくてもつかえます</li>
+    <li>正しいプログラミングスタイルが自然と身につきます</li>
+</ul>
+
+<h2>デモ</h2>
+<ul>
+    <li><a href="<?= uri_for('form') ?>">フォーム</a></li>
+    <li><a href="<?= uri_for('goto_wassr') ?>">リダイレクト(Wassr にとびます)</a></li>
+    <li><a href="<?= uri_for('users') ?>">DBI(DBI および DBD::CSV がないとエラーになります)</a></li>
+    <li><a href="<?= uri_for('die') ?>">エラー画面</a></li>
+    <li><a href="<?= uri_for('mobile') ?>">モバイル</a></li>
+    <li><a href="<?= uri_for('bbs_sqlite') ?>">SQLite をつかった掲示板(DBD::SQLite が必要です)</a></li>
+    <li><a href="<?= uri_for('counter') ?>">簡単なカウンター</a></li>
+    <li><a href="<?= uri_for('hello', { user => 'kazuhooku' }) ?>">PHP っぽくそのままテンプレート表示しちゃう</a></li>
+</ul>
+?=r render_partial('footer.html')
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/mobile.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/mobile.html (revision 23958)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/mobile.html (revision 23958)
@@ -0,0 +1,5 @@
+? my $title = 'ケータイ対応'
+?=r render_partial('header.html', $title)
+<h1><?= $title ?></h1>
+<p>あなたのブラウザは <?= mobile_carrier_longname ?> です</p>
+?=r render_partial('footer.html')
Index: /lang/perl/MENTA/tags/release-0.01/app/tmpl/header.html
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/app/tmpl/header.html (revision 23958)
+++ /lang/perl/MENTA/tags/release-0.01/app/tmpl/header.html (revision 23958)
@@ -0,0 +1,4 @@
+? my $title = shift
+<!doctype html>
+<title><? if ($title) { ?><?= "$title - " ?><? } ?>MENTA</title>
+<link rel="stylesheet" type="text/css" href="<?= docroot ?>static/style-sites.css">
Index: /lang/perl/MENTA/tags/release-0.01/plugins/counter.pl
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/plugins/counter.pl (revision 23976)
+++ /lang/perl/MENTA/tags/release-0.01/plugins/counter.pl (revision 23976)
@@ -0,0 +1,21 @@
+use MENTA;
+use Fcntl ':flock';
+
+sub counter_increment {
+    my $fname = shift;
+    unless ($fname) {
+        $fname = config->{application}->{counter}->{file} or die "config.application.counter.file にデータファイル名が設定されていません";
+    }
+    my $mode = (-f $fname) ? '+<' : '+>';
+    open my $fh, $mode, $fname or die "$fname を開けません: $!";
+    flock $fh, LOCK_EX;
+    my $cnt = <$fh>;
+    $cnt++;
+    seek($fh, 0, SEEK_SET);
+    print $fh $cnt or die "$fname にかきこめません: $!";
+    flock $fh, LOCK_UN;
+    close $fh or die "$fname を閉じることができません: $!";
+    $cnt;
+}
+
+1;
Index: /lang/perl/MENTA/tags/release-0.01/plugins/sql.pl
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/plugins/sql.pl (revision 23776)
+++ /lang/perl/MENTA/tags/release-0.01/plugins/sql.pl (revision 23776)
@@ -0,0 +1,77 @@
+# AUTHOR: tokuhirom, mattn
+
+use strict;
+use warnings;
+use utf8;
+use DBI;
+
+sub sql_dbh {
+    if (@_) {
+        my @args = @_;
+        if ($MENTA::STASH->{sql_dbh}) {
+            $MENTA::STASH->{sql_dbh}->disconnect;
+            undef $MENTA::STASH->{sql_dbh};
+        }
+        my $dbh = DBI->connect(@args) or die "DBに接続できません: $DBI::errstr";
+        $MENTA::STASH->{sql_dbh} = $dbh;
+        $dbh;
+    } else {
+        $MENTA::STASH->{sql_dbh} ||= do {
+            my $dsn = config->{application}->{sql}->{dsn} or die "設定に application.sql.dsn がありません";
+            my $dbh = DBI->connect($dsn) or die "DBに接続できません: $DBI::errstr";
+            $dbh->{unicode}++;
+            $dbh;
+        };
+    }
+}
+
+sub sql_prepare_exec {
+    my ($sql, @params) = @_;
+    my $dbh = sql_dbh();
+    my $sth = $dbh->prepare($sql) or die "prepare できません: " . $dbh->errstr();
+    $sth->execute(@params) or die "exec できません: " . $dbh->errstr;
+    $sth->finish();
+    undef $sth;
+}
+
+sub sql_select_all {
+    my ($sql, @params) = @_;
+
+    my $dbh = sql_dbh();
+    my $sth = $dbh->prepare($sql) or die $dbh->errstr;
+    $sth->execute(@params);
+    my @res;
+    while (my $row = $sth->fetchrow_hashref) {
+        push @res, $row;
+    }
+    $sth->finish;
+    undef $sth;
+
+    return \@res;
+}
+
+sub sql_select_paginate {
+    my ($sql, $params, $paging) = @_;
+    $sql .= ' LIMIT ? OFFSET ?';
+
+    my $dbh = sql_dbh();
+    my $sth = $dbh->prepare($sql) or die $dbh->errstr;
+    $sth->execute(@$params, $paging->{rows}+1, ($paging->{page}-1)*$paging->{rows});
+
+    my @res;
+    while (my $row = $sth->fetchrow_hashref) {
+        push @res, $row;
+    }
+    $sth->finish;
+    undef $sth;
+
+    my $has_next = 0;
+    if ( @res == $paging->{rows} + 1 ) {
+        pop @res;
+        $has_next++;
+    }
+
+    return (\@res, {page => $paging->{page}, has_next => $has_next, has_prev => ($paging->{page} == 1) ? 1 : 0});
+}
+
+1;
Index: /lang/perl/MENTA/tags/release-0.01/plugins/mail.pl
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/plugins/mail.pl (revision 23559)
+++ /lang/perl/MENTA/tags/release-0.01/plugins/mail.pl (revision 23559)
@@ -0,0 +1,40 @@
+#   mb_send_mail('to@example.jp', 'サブジェクト', '本文', 'From: from@example.jp');
+# という風にして、送るとよい。
+# TODO: ヘッダの処理とかが甘いので、なんとかする
+# iso-2022-jp に MIME encode する？
+
+use utf8;
+use Symbol ();
+
+# XXX windows で動かないかな。
+my $find_sendmail = sub {
+    for my $dir ( split /:/, $ENV{PATH} ) {
+        if ( -x "$dir/sendmail" ) {
+            return "$dir/sendmail";
+        }
+    }
+    return;
+};
+
+sub mail_send {
+    my ($to, $subject, $body, $additional_headers) = @_;
+    die "To に改行を含めることはできません" if $to =~ /[\r\n]/;
+
+    local $SIG{CHLD} = "DEFAULT";
+
+    my $mailer = $find_sendmail->() or die "sendmail が見つかりません";
+
+    my $pipe = Symbol::gensym();
+    open $pipe, "| $mailer -t -oi" || die "$mailer を開けませんでした: $!";
+
+    my @lines;
+    push @lines, "To: $to\r\n";
+    push @lines, $additional_headers if $additional_headers;
+    push @lines, "\r\n";
+    push @lines, $body;
+    print $pipe join('', @lines) || die "$mailer に書き込めません: $!";
+
+    close $pipe || die "閉じれません: $mailer, $!";
+}
+
+1;
Index: /lang/perl/MENTA/tags/release-0.01/t/redirect.t
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/t/redirect.t (revision 23560)
+++ /lang/perl/MENTA/tags/release-0.01/t/redirect.t (revision 23560)
@@ -0,0 +1,10 @@
+use strict;
+use warnings;
+use Test::More tests => 1;
+use t::Utils;
+
+my $out = run_cgi(
+    PATH_INFO => '/goto_wassr'
+);
+is $out, join("\r\n", 'Status: 302', 'Location: http://wassr.jp/', '', '');
+
Index: /lang/perl/MENTA/tags/release-0.01/t/mobile.t
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/t/mobile.t (revision 23654)
+++ /lang/perl/MENTA/tags/release-0.01/t/mobile.t (revision 23654)
@@ -0,0 +1,10 @@
+use Test::More tests => 1;
+use t::Utils;
+
+my $out = run_cgi(
+    PATH_INFO      => '/mobile',
+    REQUEST_METHOD => 'GET',
+    HTTP_USER_AGENT => 'UP.Browser/3.04-TS13 UP.Link/3.4.4'
+);
+like $out, qr/あなたのブラウザは EZweb です/;
+
Index: /lang/perl/MENTA/tags/release-0.01/t/form_post.t
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/t/form_post.t (revision 23706)
+++ /lang/perl/MENTA/tags/release-0.01/t/form_post.t (revision 23706)
@@ -0,0 +1,12 @@
+use strict;
+use warnings;
+use Test::More tests => 1;
+use t::Utils;
+
+my $out = run_cgi(
+    PATH_INFO      => '/form',
+    REQUEST_METHOD => 'GET',
+    QUERY_STRING   => 'r=foo'
+);
+like $out, qr/\br\s*:\s*"foo"/;
+
Index: /lang/perl/MENTA/tags/release-0.01/t/Utils.pm
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/t/Utils.pm (revision 23654)
+++ /lang/perl/MENTA/tags/release-0.01/t/Utils.pm (revision 23654)
@@ -0,0 +1,72 @@
+package t::Utils;
+use strict;
+use warnings;
+
+sub import {
+    my $pkg = caller(0);
+    strict->import;
+    warnings->import;
+    no strict 'refs';
+    *{"$pkg\::run_cgi"} = \&run_cgi;
+}
+
+sub run_cgi {
+    my %args = @_;
+    $ENV{CONTENT_LENGTH} = $args{CONTENT_LENGTH} || 0;
+    $ENV{PATH_INFO} = $args{PATH_INFO} || '/';
+    $ENV{QUERY_STRING} = $args{QUERY_STRING} || '';
+    $ENV{HTTP_USER_AGENT} = $args{HTTP_USER_AGENT} || 'test';
+    $ENV{REQUEST_METHOD} = $args{REQUEST_METHOD} || 'GET';
+
+    chdir 'app';
+    my $out = bind_stdout(sub {
+        package main;
+        do './menta.cgi';
+        die $@ if $@;
+    });
+}
+
+{
+    package MENTA::BindSTDOUT::Tie;
+    require Tie::Handle;
+    use base qw/Tie::Handle/;
+    use Carp;
+
+    sub TIEHANDLE {
+        my ($class, $in, $outref) = @_;
+        bless {out => $outref, in => $in, pos => 0}, $class;
+    }
+
+    sub WRITE {
+        my $self = shift;
+        ${$self->{out}} .= shift;
+    }
+
+    # $self->READ(buf, len, offset);
+    # copy from IO::Scalar
+    sub READ {
+        my $self = $_[0];
+        my $n    = $_[2];
+        my $off  = $_[3] || 0;
+
+        my $read = substr( $self->{in}, $self->{pos}, $n );
+        $n = length($read);
+        $self->{pos} += $n;
+        ( $off ? substr( $_[1], $off ) : $_[1] ) = $read;
+        return $n;
+    }
+    sub CLOSE { }
+}
+
+sub bind_stdout {
+    my ($code, ) = @_;
+    my $in;
+    read(STDIN, $in, $ENV{CONTENT_LENGTH});
+    tie *STDOUT, 'MENTA::BindSTDOUT::Tie', $in, \my $out;
+    $code->();
+    untie *STDOUT;
+    $out;
+}
+
+
+1;
Index: /lang/perl/MENTA/tags/release-0.01/t/simple.t
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/t/simple.t (revision 23601)
+++ /lang/perl/MENTA/tags/release-0.01/t/simple.t (revision 23601)
@@ -0,0 +1,7 @@
+use strict;
+use warnings;
+use Test::More tests => 1;
+use t::Utils;
+
+my $out = run_cgi();
+like $out, qr!<title>MENTA</title>!;
Index: /lang/perl/MENTA/tags/release-0.01/AUTHORS
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/AUTHORS (revision 23360)
+++ /lang/perl/MENTA/tags/release-0.01/AUTHORS (revision 23360)
@@ -0,0 +1,6 @@
+Tokuhiro Matsuno
+lestrrat
+mattn
+fujiwara
+drry
+hidek
Index: /lang/perl/MENTA/tags/release-0.01/NOTE
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/NOTE (revision 23773)
+++ /lang/perl/MENTA/tags/release-0.01/NOTE (revision 23773)
@@ -0,0 +1,55 @@
+MENTA 設計メモ
+
+前提
+----
+
+    Perl 5.8.0 以後をサポート対象とする
+    CGI 環境でも高速である
+    use strict を強制して悪い習慣を身につけさせない
+    Windows でも動く
+    UTF-8 で書く
+    use strict; use warnings; use utf8; を強制する
+    テストを書く習慣を身につけさせる
+    Perl::Critic しまくる
+    スタンドアローンサーバーでも動く
+    HTML エスケープは自動でかける
+    ユーザが「自分はいい道具をつかっているんだ」とおもえるようにする
+    初心者は OOP とかわからないので、関数でひととおりできるようにする
+
+依存モジュール
+--------------
+
+    実行時、コンパイル時ともに標準添付モジュールのみを利用する
+    ただし、コンパイル時においては vendor/ 以下に小さなライブラリを保存してよい
+
+        HTTP::Server::Simple
+
+使い方
+------
+
+    app/ 以下をいじくって自分のアプリをつくる
+
+テスト
+-----
+
+    MENTA は十分に安定しているべきなので、テストを十分に書くべきだ。
+
+    % prove t/*.t
+    でテストが実行できるので、コミッタはテストを通すようにするとよい。
+
+TODO
+----
+
+    ソースに書いてあるものもろもろ
+    flock してファイルつくって云々みたいなのを簡単にできる仕組み
+    サンプルアプリを作ってみる
+    テストを十分に書く。安定したフレームワークにするためにはテストが必須だ。
+    mod_perl 対応。今の時点でも動くことはうごくとおもうけど、テストとか十分にしたい
+    携帯端末の場合に文字コードを適切に変換するべき?でも 3G なら utf8 表示できるんじゃなかったっけw
+    docroot は環境変数でうまくやれないかな
+    フックとかつける?
+    uri_with っぽいのもほしい。
+    documentation する
+    controller を分割ファイル形式にしている場合に、use strict とかオンになってる?
+    ファイルアップロードまわり
+
Index: /lang/perl/MENTA/tags/release-0.01/MANIFEST
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/MANIFEST (revision 23260)
+++ /lang/perl/MENTA/tags/release-0.01/MANIFEST (revision 23260)
@@ -0,0 +1,29 @@
+Changes
+inc/Module/Install.pm
+inc/Module/Install/AuthorTests.pm
+inc/Module/Install/Base.pm
+inc/Module/Install/Can.pm
+inc/Module/Install/Fetch.pm
+inc/Module/Install/Include.pm
+inc/Module/Install/Makefile.pm
+inc/Module/Install/Metadata.pm
+inc/Module/Install/TestBase.pm
+inc/Module/Install/Win32.pm
+inc/Module/Install/WriteAll.pm
+inc/Spiffy.pm
+inc/Test/Base.pm
+inc/Test/Base/Filter.pm
+inc/Test/Builder.pm
+inc/Test/Builder/Module.pm
+inc/Test/More.pm
+inc/YAML.pm
+lib/MENTA.pm
+Makefile.PL
+MANIFEST			This list of files
+META.yml
+README
+t/00_compile.t
+xt/01_podspell.t
+xt/02_perlcritic.t
+xt/03_pod.t
+xt/perlcriticrc
Index: /lang/perl/MENTA/tags/release-0.01/lib/MENTA.pm
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/lib/MENTA.pm (revision 23982)
+++ /lang/perl/MENTA/tags/release-0.01/lib/MENTA.pm (revision 23982)
@@ -0,0 +1,422 @@
+package MENTA;
+use strict;
+use warnings;
+use utf8;
+
+our $REQ;
+our $CONFIG;
+our $REQUIRED;
+our $MOBILEAGENTRE;
+our $CARRIER;
+our $STASH;
+our $BUILT = 0;
+BEGIN {
+    $REQUIRED = {};
+
+    {
+        # copied from HTTP::MobileAgent
+        my $DoCoMoRE = '^DoCoMo/\d\.\d[ /]';
+        my $JPhoneRE = '^(?i:J-PHONE/\d\.\d)';
+        my $VodafoneRE = '^Vodafone/\d\.\d';
+        my $VodafoneMotRE = '^MOT-';
+        my $SoftBankRE = '^SoftBank/\d\.\d';
+        my $SoftBankCrawlerRE = '^Nokia[^/]+/\d\.\d';
+        my $EZwebRE = '^(?:KDDI-[A-Z]+\d+[A-Z]? )?UP\.Browser\/';
+        my $AirHRE = '^Mozilla/3\.0\((?:WILLCOM|DDIPOCKET)\;';
+        $MOBILEAGENTRE = qr/(?:($DoCoMoRE)|($JPhoneRE|$VodafoneRE|$VodafoneMotRE|$SoftBankRE|$SoftBankCrawlerRE)|($EZwebRE)|($AirHRE))/;
+    }
+}
+
+sub import {
+    strict->import;
+    warnings->import;
+    utf8->import;
+}
+
+sub DEFAULT_MAX_POST_BODY () { 1_024_000 }
+
+package main;
+
+sub config () { $MENTA::CONFIG }
+
+sub run_menta {
+    my $config = shift @_;
+
+    local $MENTA::CONFIG;
+    local $MENTA::REQ;
+    local $MENTA::CARRIER;
+    local $MENTA::STASH;
+
+    {
+        $config->{menta}->{max_post_body} ||= MENTA::DEFAULT_MAX_POST_BODY;
+        $MENTA::CONFIG = $config;
+    }
+
+    local $SIG{__DIE__} = sub {
+        my $msg = shift;
+        warn $msg unless ref $msg;
+        return $msg if ref $msg && ref $msg eq 'HASH' && $msg->{finished};
+        my $i = 0;
+        my @trace;
+        while ( my ($package, $filename, $line,) = caller($i) ) {
+            last if $filename eq 'bin/cgi-server.pl';
+            my $context = sub {
+                my ( $file, $linenum ) = @_;
+                my $code;
+                if ( -f $file ) {
+                    my $start = $linenum - 3;
+                    my $end   = $linenum + 3;
+                    $start = $start < 1 ? 1 : $start;
+                    open my $fh, '<:utf8', $file or die "エラー画面表示用に ${file} を開こうとしたのに開けません: $!";
+                    my $cur_line = 0;
+                    while ( my $line = <$fh> ) {
+                        chomp $line;
+                        ++$cur_line;
+                        last if $cur_line > $end;
+                        next if $cur_line < $start;
+                        my @tag =
+                            $cur_line == $linenum
+                            ? ( '<strong>', '</strong>' )
+                            : ( '', '' );
+                        $code .= sprintf( "%s%5d: %s%s\n",
+                            $tag[0], $cur_line,
+                            escape_html($line),
+                            $tag[1], );
+                    }
+                    close $file;
+                    chomp $code;
+                }
+                return $code;
+            }->($filename, $line);
+            push @trace, +{ level => $i, package => $package, filename => $filename, line => $line, context => $context };
+            $i++;
+        }
+        die { message => $msg, trace => \@trace };
+    };
+
+    eval {
+        my $path = $ENV{PATH_INFO} || '/';
+        $path =~ s!^/+!!g;
+        if ($path =~ /^[a-z0-9_]*$/) {
+            my $mode = $path || 'index';
+            my $meth = "do_$mode";
+            if (my $cdir = config->{menta}->{controller_dir}) {
+                my $controller = "${cdir}/${path}.pl";
+                if (-f $controller) {
+                    package main;
+                    do $controller;
+                    if (my $e = $@) {
+                        if (ref $e) {
+                            die $e->{message};
+                        } else {
+                            die $e;
+                        }
+                    }
+                    die $@ if $@;
+                    if (my $code = main->can($meth)) {
+                        $code->();
+                        die "なにも出力してません";
+                    } else {
+                        die "「${mode}」というモードは存在しません!${controller} の中に ${meth} が定義されていないようです";
+                    }
+                } else {
+                    my $tmplfname = ($MENTA::BUILT ? config->{menta}->{tmpl_cache_dir} : config->{menta}->{tmpl_dir}) . "/${mode}.html";
+                    if (-f $tmplfname) {
+                        render("${mode}.html");
+                    } else {
+                        die "「${mode}」というモードは存在しません。別コントローラファイルもありません(${controller})。テンプレートファイルもありません(${tmplfname})";
+                    }
+                }
+            } else {
+                die "「${mode}」というモードは存在しません。別コントローラ用ディレクトリは設定されていません";
+            }
+        } elsif ($path ne 'menta.cgi' && -f $path) {
+            if (open my $fh, '<', $path) {
+                printf "Content-Type: %s\r\n\r\n", guess_mime_type($path);
+                print do { local $/; <$fh> };
+                close $fh;
+            } else {
+                die "ファイルが開きません";
+            }
+        } elsif ($path =~ /^(?:crossdomain\.xml|favicon\.ico|robots\.txt)$/) {
+            print "status: 404\r\ncontent-type: text/plain\r\n\r\n";
+        } else {
+            die "${path} を処理する方法がわかりません";
+        }
+    };
+    if (my $err = $@) {
+        die "エラー処理失敗: ${err}" unless ref $err eq 'HASH';
+        return if $err->{finished};
+
+        warn $err->{message};
+
+        print "Status: 500\r\n";
+        print "Content-type: text/html; charset=utf-8\r\n";
+        print "\r\n";
+
+        my $body = do {
+            if ($config->{menta}->{kcatch_mode}) {
+                my $msg = escape_html($err->{message});
+                chomp $msg;
+                my $out = qq{<!doctype html><head><title>500 Internal Server Error</title><style type="text/css">body { margin: 0; padding: 0; background: rgb(230, 230, 230); color: rgb(44, 44, 44); } h1 { margin: 0 0 .5em; padding: .25em .5em .1em 1.5em; border-bottom: thick solid rgb(0, 0, 15); background: rgb(63, 63, 63); color: rgb(239, 239, 239); font-size: x-large; } p { margin: .5em 1em; } li { font-size: small; } pre { background: rgb(255, 239, 239); color: rgb(47, 47, 47); font-size: medium; } pre code strong { color: rgb(0, 0, 0); background: rgb(255, 143, 143); } p.f { text-align: right; font-size: xx-small; } p.f span { font-size: medium; }</style></head><h1>500 Internal Server Error</h1><p>${msg}</p><ol>};
+                for my $stack (@{$err->{trace}}) {
+                    $out .= '<li>' . escape_html(join(', ', $stack->{package}, $stack->{filename}, $stack->{line}))
+                         . qq(<pre><code>$stack->{context}</code></pre></li>);
+                }
+                $out .= qq{</ol><p class="f"><span>Powered by <strong>MENTA</strong></span>, Web application framework</p>};
+                $out;
+            } else {
+                qq{<html><body><p style="color: red">500 Internal Server Error</p></body></html>\n};
+            }
+        };
+        utf8::encode($body);
+        print $body;
+    }
+}
+
+sub escape_html {
+    local $_ = shift;
+    return $_ unless $_;
+    s/&/&amp;/g;
+    s/>/&gt;/g;
+    s/</&lt;/g;
+    s/"/&quot;/g;
+    s/'/&#39;/g;
+    return $_;
+}
+
+sub unescape_html {
+    local $_ = shift;
+    return $_ unless $_;
+    s/&gt;/>/g;
+    s/&lt;/</g;
+    s/&quot;/"/g;
+    s/&#39;/'/g;
+    s/&amp;/&/g;
+    return $_;
+}
+
+sub guess_mime_type {
+    my $ext = shift;
+    $ext =~ s/.+\.(.+)$/$1/;
+
+    # TODO should be moved to other.
+    my $mime_map = {
+        css => 'text/css',
+        js  => 'application/javascript',
+        txt => 'text/plain',
+    };
+    $mime_map->{$ext} || 'application/octet-stream';
+}
+
+# TODO: ディレクトリトラバーサル対策
+sub render_partial {
+    my ($tmpl, @params) = @_;
+    my $conf = config()->{menta};
+    my $tmpldir = $conf->{tmpl_dir} or die "[menta] セクションに tmpl_dir が設定されていません";
+    my $cachedir = $conf->{tmpl_cache_dir} or die "[menta] セクションに tmpl_cache_dir が設定されていません";
+    mkdir $cachedir unless $MENTA::BUILT || -d $cachedir;
+    my $cachefname = "$cachedir/$tmpl";
+    my $tmplfname = "$tmpldir/$tmpl";
+    my $use_cache = $MENTA::BUILT || sub {
+        my @orig = stat $tmplfname or return 1;
+        my @cached = stat $cachefname or return;
+        return $orig[9] < $cached[9];
+    }->();
+    my $out;
+    if ($use_cache) {
+        my $tmplcode = do $cachefname;
+        die $@ if $@;
+        die "テンプレートキャッシュを読み込めませんでした: ${tmplfname}" unless $tmplcode;
+        $out = $tmplcode->(@params);
+    } else {
+        die "「${tmplfname}」という名前のテンプレートファイルは見つかりません" unless -f $tmplfname;
+        require_once('MENTA/Template.pm');
+        my $tmplsrc = read_file($tmplfname);
+        my $mt = MENTA::Template->new;
+        $mt->parse($tmplsrc);
+        $mt->build();
+        my $src = $mt->code();
+        my $tmplcode = eval $src;
+        die $@ if $@;
+        $out = $tmplcode->(@params);
+        write_file($cachefname, "package main; use utf8;\n${src}");
+    }
+    $out;
+}
+
+sub detach() {
+    die {finished => 1};
+}
+
+sub render {
+    my ($tmpl, @params) = @_;
+    my $out = render_partial($tmpl, @params);
+    utf8::encode($out);
+    print "Content-Type: text/html; charset=utf-8\r\n";
+    print "\r\n";
+    print $out;
+
+    detach;
+}
+
+sub redirect {
+    my ($location, ) = @_;
+    print "Status: 302\r\n";
+    print "Location: $location\r\n";
+    print "\r\n";
+
+    detach;
+}
+
+sub finalize {
+    my $str = shift;
+    my $content_type = shift || 'text/html; charset=utf-8';
+
+    print "Content-Type: $content_type\r\n";
+    print "\r\n";
+    print $str;
+
+    detach;
+}
+
+sub read_file {
+    my $fname = shift;
+    open my $fh, '<:utf8', $fname or die "${fname} を読み込み用に開けません: $!";
+    my $s = do { local $/; join '', <$fh> };
+    close $fh;
+    $s;
+}
+
+sub write_file {
+    my ($fname, $stuff) = @_;
+    open my $fh, '>:utf8', $fname or die "${fname} を書き込み用に開けません: $!";
+    print $fh $stuff;
+    close $fh;
+}
+
+sub parse_multipart {
+    my ($data, $boundary) = @_;
+
+    my @lines = split(/\n/, $data);
+    my ($val, $key, $step) = ('', '', 0);
+    for my $line (@lines) {
+        my $sline = $line;
+        $sline =~ s![\r\n]+!!msg;
+        if ($boundary eq $sline) {
+            if($step eq 2 && $key ne '') {
+                chop($val);
+                $MENTA::REQ->{$key} = $val;
+            }
+            $step = 1;
+            $key = '';
+            $val = '';
+        } elsif ("${boundary}--" eq $sline) {
+            if ($step eq 2 && $key ne '') {
+                chop($val);
+                $MENTA::REQ->{$key} = $val;
+            }
+            return 1;
+        } elsif ($step eq 2) {
+            $val .= "\n" if $val;
+            $val .= $line;
+        } elsif ($sline =~ /^(?i:Content-Disposition): *form-data; *name="((?:\\"|[^"])*)/ && $step eq 1) {
+            $key = $1;
+        } elsif ($sline eq '' && $step eq 1) {
+            $step = 2;
+        }
+    }
+    return 1;
+}
+
+sub param {
+    my $key = shift;
+
+    unless (defined $MENTA::REQ) {
+        my $input;
+        if ($ENV{'REQUEST_METHOD'} eq 'POST') {
+            my $max_post_body = config()->{menta}->{max_post_body};
+            if ($max_post_body > 0 && $ENV{CONTENT_LENGTH} > $max_post_body) {
+                die "投稿データが長すぎです";
+            } else {
+                read(STDIN, $input, $ENV{'CONTENT_LENGTH'});
+            }
+        } else {
+            $input = $ENV{QUERY_STRING};
+        }
+
+        my $type = $ENV{'CONTENT_TYPE'};
+        if ($type && $type =~ m{^multipart/form-data; *boundary=}) {
+            parse_multipart $input, '--'.substr($type, 30);
+        } else {
+            for (split /[&;]+/, $input) {
+                my ($key, $val) = split /=/, $_;
+                if ($val) {
+                    $val =~ tr/+/ /;
+                    $val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('H2', $1)/eg;
+                    utf8::decode($val);
+                }
+                $MENTA::REQ->{$key} = $val;
+            }
+        }
+    }
+
+    return $MENTA::REQ->{$key};
+}
+
+sub require_once {
+    my $path = shift;
+    return if $MENTA::REQUIRED->{$path};
+    require $path;
+    $MENTA::REQUIRED->{$path} = 1;
+}
+
+# これが返す文字は HTTP::MobileAgent と互換性がある
+sub mobile_carrier () {
+    if ($MENTA::CARRIER) { return $MENTA::CARRIER }
+
+    my $ua = $ENV{HTTP_USER_AGENT} || '';
+    my $ret = 'N';
+    if ($ua =~ /$MENTA::MOBILEAGENTRE/) {
+        $ret = $1 ? 'I' : $2 ? 'V' : $3 ? 'E' : 'H';
+    }
+    $MENTA::CARRIER = $ret;
+    $ret;
+}
+
+sub mobile_carrier_longname {
+    {
+        N => 'NonMobile',
+        I => 'DoCoMo',
+        E => 'EZweb',
+        V => 'Softbank',
+        H => 'AirH',
+    }->{ mobile_carrier() }
+}
+
+sub load_plugin {
+    my $plugin = shift;
+    require_once($MENTA::BUILT ? "plugins/${plugin}.pl" : "../plugins/${plugin}.pl");
+}
+
+sub is_post_request () {
+    my $method = $ENV{REQUEST_METHOD};
+    return $method eq 'POST';
+}
+
+# TODO: CGI にはこのための環境変数ってなかったっけ?
+sub docroot () {
+    config()->{application}->{docroot}
+}
+
+sub uri_for {
+    my ($path, $query) = @_;
+    my @q;
+    while (my ($key, $val) = each %$query) {
+        $val = join '', map { /^[a-zA-Z0-9_.!~*'()-]$/ ? $_ : '%' . uc(unpack('H2', $_)) } split //, $val;
+        push @q, "${key}=${val}";
+    }
+    docroot . $path . (scalar @q ? '?' . join('&', @q) : '');
+}
+
+1;
Index: /lang/perl/MENTA/tags/release-0.01/lib/MENTA/Packer.pm
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/lib/MENTA/Packer.pm (revision 23895)
+++ /lang/perl/MENTA/tags/release-0.01/lib/MENTA/Packer.pm (revision 23895)
@@ -0,0 +1,98 @@
+package MENTA::Packer;
+use MENTA;
+use MENTA::Template;
+use File::Copy;
+
+{
+    no strict 'refs';
+    *{"MENTA::Packer::read_file"}  = *{"main::read_file"};
+    *{"MENTA::Packer::write_file"} = *{"main::write_file"};
+}
+
+sub puts { print @_, "\n" };
+
+sub run {
+    my ($class, $srcdir, $outdir) = @_;
+
+    puts "出力先ディレクトリを作成します";
+    mkdir $outdir unless -d $outdir;
+    my $mode = 755; #TODO
+    puts "chmod $mode";
+    chmod oct($mode), $outdir;
+
+    puts "メインソースをコンパイルします";
+    generate_cgi($srcdir => $outdir);
+
+    puts "テンプレートファイルをコンパイルします";
+    generate_template_files($srcdir => $outdir);
+
+    puts "静的ファイルをコピーします";
+    copy_dir($srcdir => $outdir, 'static');
+
+    puts "コントローラファイルをコピーします";
+    copy_dir($srcdir => $outdir, 'controller');
+
+    puts "データをコピーします";
+    copy_dir($srcdir => $outdir, 'data');
+
+    puts "プラグインディレクトリをコピーします";
+    copy_dir_raw("plugins" => "$outdir/plugins");
+}
+
+sub generate_cgi {
+    my ($srcdir, $outdir) = @_;
+
+    puts "menta.cgi をつくりあげる";
+    my $menta = read_file("${srcdir}/menta.cgi");
+    my $menta_pm = read_file('lib/MENTA.pm');
+    $menta =~ s/use MENTA;/use strict;use warnings;use utf8;\n$menta_pm\n\$MENTA::BUILT++;\npackage main;/;
+    $menta =~ s!use lib '\..\/lib';!!;
+
+    puts "menta.cgi を出力します";
+    write_file("$outdir/menta.cgi" => $menta);
+    my $mode = 755; #TODO
+    puts "chmod $mode";
+    chmod oct($mode), "$outdir/menta.cgi";
+}
+
+sub generate_template_files {
+    my ($srcdir, $outdir) = @_;
+
+    my $outputdir = "$outdir/tmpl_cache/";
+    unless (-d $outputdir) {
+        mkdir $outputdir or die "キャッシュディレクトリを作成できません: $!";
+    }
+    opendir my $dir, "$srcdir/tmpl" or die "テンプレートファイル用ディレクトリを開けません: $!";
+    while (my $file = readdir $dir) {
+        my $fname = "$srcdir/tmpl/$file";
+        next unless -f $fname;
+        my $src = read_file($fname);
+        my $mt = MENTA::Template->new;
+        $mt->parse($src);
+        $mt->build();
+        my $code = $mt->code();
+        write_file("$outputdir/$file", "package main; use utf8;\n$code");
+    }
+    closedir $dir;
+}
+
+sub copy_dir {
+    my ($srcdir, $outdir, $dirname) = @_;
+    copy_dir_raw("$srcdir/$dirname" => "$outdir/$dirname");
+}
+
+sub copy_dir_raw {
+    my ($src, $dst) = @_;
+    unless (-d $dst) {
+        mkdir $dst or die "出力用ディレクトリ ${dst} を作成できません: $!";
+    }
+    opendir my $dir, $src or die "入力用ディレクトリ ${src} を開けません: $!";
+    while (my $file = readdir $dir) {
+        my $fname = "$src/$file";
+        next unless -f $fname;
+        copy($fname, "$dst/$file");
+    }
+    closedir $dir;
+}
+
+1;
Index: /lang/perl/MENTA/tags/release-0.01/lib/MENTA/Template.pm
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/lib/MENTA/Template.pm (revision 23957)
+++ /lang/perl/MENTA/tags/release-0.01/lib/MENTA/Template.pm (revision 23957)
@@ -0,0 +1,272 @@
+# based on Mojo::Template. Copyright (C) 2010, Sebastian Riedel.
+# some modified by tokuhirom
+
+package MENTA::Template;
+use strict;
+use warnings;
+use constant DEBUG => $ENV{MENTA_TEMPLATE_DEBUG} || 0;
+
+use Carp 'croak';
+
+sub new {
+    my $class = shift;
+    return bless {
+        code => '',
+        comment_mark => '#',
+        expression_mark => '=',
+        raw_expression_mark => '=r',
+        line_start => '?',
+        template => '',
+        tree => [],
+        tag_start => '<?',
+        tag_end => '?>',
+    }, $class;
+}
+
+sub code { shift->{code} }
+
+sub build {
+    my $self = shift;
+
+    # Compile
+    my @lines;
+    for my $line (@{$self->{tree}}) {
+
+        # New line
+        push @lines, '';
+        for (my $j = 0; $j < @{$line}; $j += 2) {
+            my $type  = $line->[$j];
+            my $value = $line->[$j + 1];
+
+            # Need to fix line ending?
+            my $newline = chomp $value;
+
+            # Text
+            if ($type eq 'text') {
+
+                # Quote and fix line ending
+                $value = quotemeta($value);
+                $value .= '\n' if $newline;
+
+                $lines[-1] .= "\$_MENTA .= \"" . $value . "\";";
+            }
+
+            # Code
+            if ($type eq 'code') {
+                $lines[-1] .= "$value;";
+            }
+
+            # Expression
+            if ($type eq 'expr') {
+                $lines[-1] .= "\$_MENTA .= escape_html(scalar $value);";
+            }
+
+            # Raw Expression
+            if ($type eq 'raw_expr') {
+                $lines[-1] .= "\$_MENTA .= $value;";
+            }
+        }
+    }
+
+    # Wrap
+    $lines[0] ||= '';
+    $lines[0]   = q/sub { my $_MENTA = '';/ . $lines[0];
+    $lines[-1] .= q/return $_MENTA; }/;
+
+    $self->{code} = join "\n", @lines;
+    return $self;
+}
+
+# I am so smart! I am so smart! S-M-R-T! I mean S-M-A-R-T...
+sub parse {
+    my ($self, $tmpl) = @_;
+    $self->{template} = $tmpl;
+
+    # Clean start
+    delete $self->{tree};
+
+    # Tags
+    my $line_start    = quotemeta $self->{line_start};
+    my $tag_start     = quotemeta $self->{tag_start};
+    my $tag_end       = quotemeta $self->{tag_end};
+    my $cmnt_mark     = quotemeta $self->{comment_mark};
+    my $expr_mark     = quotemeta $self->{expression_mark};
+    my $raw_expr_mark = quotemeta $self->{raw_expression_mark};
+
+    # Tokenize
+    my $state = 'text';
+    my $multiline_expression = 0;
+    for my $line (split /\n/, $tmpl) {
+
+        # Perl line without return value
+        if ($line =~ /^$line_start\s+(.+)$/) {
+            push @{$self->{tree}}, ['code', $1];
+            $multiline_expression = 0;
+            next;
+        }
+
+        # Perl line with return value
+        if ($line =~ /^$line_start$expr_mark\s+(.+)$/) {
+            push @{$self->{tree}}, ['expr', $1];
+            $multiline_expression = 0;
+            next;
+        }
+
+        # Perl line with raw return value
+        if ($line =~ /^$line_start$raw_expr_mark\s+(.+)$/) {
+            push @{$self->{tree}}, ['raw_expr', $1];
+            $multiline_expression = 0;
+            next;
+        }
+
+        # Comment line, dummy token needed for line count
+        if ($line =~ /^$line_start$cmnt_mark\s+(.+)$/) {
+            push @{$self->{tree}}, [];
+            $multiline_expression = 0;
+            next;
+        }
+
+        # Escaped line ending?
+        if ($line =~ /(\\+)$/) {
+            my $length = length $1;
+
+            # Newline escaped
+            if ($length == 1) {
+                $line =~ s/\\$//;
+            }
+
+            # Backslash escaped
+            if ($length >= 2) {
+                $line =~ s/\\\\$/\\/;
+                $line .= "\n";
+            }
+        }
+
+        # Normal line ending
+        else { $line .= "\n" }
+
+        # Mixed line
+        my @token;
+        for my $token (split /
+            (
+                $tag_start$raw_expr_mark # Raw Expression
+            |
+                $tag_start$expr_mark     # Expression
+            |
+                $tag_start$cmnt_mark     # Comment
+            |
+                $tag_start               # Code
+            |
+                $tag_end                 # End
+            )
+        /x, $line) {
+
+            # Garbage
+            next unless $token;
+
+            # End
+            if ($token =~ /^$tag_end$/) {
+                $state = 'text';
+                $multiline_expression = 0;
+            }
+
+            # Code
+            elsif ($token =~ /^$tag_start$/) { $state = 'code' }
+
+            # Comment
+            elsif ($token =~ /^$tag_start$cmnt_mark$/) { $state = 'cmnt' }
+
+            # Raw Expression
+            elsif ($token =~ /^$tag_start$raw_expr_mark$/) {
+                $state = 'raw_expr';
+            }
+
+            # Expression
+            elsif ($token =~ /^$tag_start$expr_mark$/) {
+                $state = 'expr';
+            }
+
+            # Value
+            else {
+
+                # Comments are ignored
+                next if $state eq 'cmnt';
+
+                # Multiline expressions are a bit complicated,
+                # only the first line can be compiled as 'expr'
+                $state = 'code' if $multiline_expression;
+                $multiline_expression = 1 if $state eq 'expr';
+
+                # Store value
+                push @token, $state, $token;
+            }
+        }
+        push @{$self->{tree}}, \@token;
+    }
+
+    return $self;
+}
+
+sub _context {
+    my ($self, $text, $line) = @_;
+
+    $line     -= 1;
+    my $nline  = $line + 1;
+    my $pline  = $line - 1;
+    my $nnline = $line + 2;
+    my $ppline = $line - 2;
+    my @lines  = split /\n/, $text;
+
+    # Context
+    my $context = (($line + 1) . ': ' . $lines[$line] . "\n");
+
+    # -1
+    $context = (($pline + 1) . ': ' . $lines[$pline] . "\n" . $context)
+      if $lines[$pline];
+
+    # -2
+    $context = (($ppline + 1) . ': ' . $lines[$ppline] . "\n" . $context)
+      if $lines[$ppline];
+
+    # +1
+    $context = ($context . ($nline + 1) . ': ' . $lines[$nline] . "\n")
+      if $lines[$nline];
+
+    # +2
+    $context = ($context . ($nnline + 1) . ': ' . $lines[$nnline] . "\n")
+      if $lines[$nnline];
+
+    return $context;
+}
+
+# Debug goodness
+sub _error {
+    my ($self, $error) = @_;
+
+    # No trace in production mode
+    return undef unless DEBUG;
+
+    # Line
+    if ($error =~ /at\s+\(eval\s+\d+\)\s+line\s+(\d+)/) {
+        my $line  = $1;
+        my $delim = '-' x 76;
+
+        my $report = "\nTemplate error around line $line.\n";
+        my $template = $self->_context($self->{template}, $line);
+        $report .= "$delim\n$template$delim\n";
+
+        # Advanced debugging
+        if (DEBUG >= 2) {
+            my $code = $self->_context($self->code, $line);
+            $report .= "$code$delim\n";
+        }
+
+        $report .= "$error\n";
+        return $report;
+    }
+
+    # No line found
+    return "Template error: $error";
+}
+
+1;
Index: /lang/perl/MENTA/tags/release-0.01/Changes
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/Changes (revision 23260)
+++ /lang/perl/MENTA/tags/release-0.01/Changes (revision 23260)
@@ -0,0 +1,4 @@
+Revision history for Perl extension MENTA
+
+0.01    Tue Nov 11 17:21:16 2008
+        - original version
Index: /lang/perl/MENTA/tags/release-0.01/bin/cgi-server.pl
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/bin/cgi-server.pl (revision 23566)
+++ /lang/perl/MENTA/tags/release-0.01/bin/cgi-server.pl (revision 23566)
@@ -0,0 +1,81 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use lib 'vendor/lib', 'lib';
+require HTTP::Server::Simple::CGI;
+use POSIX;
+use HTTP::Response;
+
+{
+    package MENTA::BindSTDOUT::Tie;
+    require Tie::Handle;
+    use base qw/Tie::Handle/;
+    use Carp;
+
+    sub TIEHANDLE {
+        my ($class, $in, $outref) = @_;
+        bless {out => $outref, in => $in, pos => 0}, $class;
+    }
+
+    sub WRITE {
+        my $self = shift;
+        ${$self->{out}} .= shift;
+    }
+
+    # $self->READ(buf, len, offset);
+    # copy from IO::Scalar
+    sub READ {
+        my $self = $_[0];
+        my $n    = $_[2];
+        my $off  = $_[3] || 0;
+
+        my $read = substr( $self->{in}, $self->{pos}, $n );
+        $n = length($read);
+        $self->{pos} += $n;
+        ( $off ? substr( $_[1], $off ) : $_[1] ) = $read;
+        return $n;
+    }
+    sub CLOSE { }
+}
+
+{
+    package MENTA::Server;
+    use base qw/HTTP::Server::Simple::CGI/;
+
+    sub bind_stdout {
+        my ($code, ) = @_;
+        my $in;
+        read(STDIN, $in, $ENV{CONTENT_LENGTH} || 0);
+        tie *STDOUT, 'MENTA::BindSTDOUT::Tie', $in, \my $out;
+        $code->();
+        untie *STDOUT;
+        $out;
+    }
+
+    sub handler {
+        my $pid = fork();
+        if ($pid) {
+            waitpid($pid, POSIX::WNOHANG);
+        } elsif ($pid == 0) {
+            chdir 'app';
+            my $out = bind_stdout(sub {
+                package main;
+                do './menta.cgi';
+                die $@ if $@;
+            });
+            my $res = HTTP::Response->parse("HTTP/1.0 200 OK\r\n$out");
+            if (my $status = $res->header('Status')) {
+                $res->code($status);
+                $res->message(HTTP::Status::status_message($status));
+            }
+            print $res->as_string;
+            exit;
+        } elsif (defined $pid) {
+            die $!;
+        }
+    }
+}
+
+my $server = MENTA::Server->new(5555);
+$server->run;
+
Index: /lang/perl/MENTA/tags/release-0.01/bin/menta-packer.pl
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/bin/menta-packer.pl (revision 23895)
+++ /lang/perl/MENTA/tags/release-0.01/bin/menta-packer.pl (revision 23895)
@@ -0,0 +1,11 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use utf8;
+use lib 'vendor/lib', 'lib';
+use MENTA::Packer;
+
+binmode STDOUT, ':utf8';
+
+MENTA::Packer->run( 'app' => 'out' );
+
Index: /lang/perl/MENTA/tags/release-0.01/.htaccess
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/.htaccess (revision 23980)
+++ /lang/perl/MENTA/tags/release-0.01/.htaccess (revision 23980)
@@ -0,0 +1,5 @@
+DirectoryIndex menta.cgi
+<FilesMatch "(?:\.p[lm]|~)$">
+    Order deny,allow
+    Deny from All
+</FilesMatch>
Index: /lang/perl/MENTA/tags/release-0.01/MANIFEST.SKIP
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/MANIFEST.SKIP (revision 23559)
+++ /lang/perl/MENTA/tags/release-0.01/MANIFEST.SKIP (revision 23559)
@@ -0,0 +1,20 @@
+\bRCS\b
+\bCVS\b
+^MANIFEST\.
+^Makefile$
+~$
+^#
+\.old$
+^blib/
+^pm_to_blib
+^MakeMaker-\d
+\.gz$
+\.cvsignore
+^t/perlcritic
+^tools/
+\.svn/
+^[^/]+\.yaml$
+^[^/]+\.pl$
+^\.shipit$
+\.sw[po]$
+out
Index: /lang/perl/MENTA/tags/release-0.01/README
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/README (revision 23575)
+++ /lang/perl/MENTA/tags/release-0.01/README (revision 23575)
@@ -0,0 +1,42 @@
+MENTA
+
+MENTA ってなに？
+----------------
+
+    プログラミング初心者がロリポや XREA などで気軽に使えるウェブアプリケーションフレームワーク。
+    高速に動作し、CGI でも軽快に動作します。
+
+    昔ながらの素の CGI と違い、MVC にもとづいた近代的なプログラミングが楽しめます。
+
+必要なもの
+----------
+
+    開発環境には LWP が必要です。
+    レンタルサーバー側には Perl 5.8.6 以上があれば問題なく動くはずです。
+
+使い方
+------
+
+    書庫を解凍してください。
+
+    % perl bin/menta.pl
+    を実行すると、out/ ディレクトリができあがります。
+
+    out/ の中のアレコレをまるっとレンタルサーバーなどに FTP でアップロードすれば動きます（の予定)。
+
+    カスタマイズしたい場合には、app/ ディレクトリの中身をいじってください。app/ 以下は下記のような
+    構成になっています。
+
+    app
+    |-- menta.cgi             コントローラ(あなたのプログラムを書く場所です)
+    `-- tmpl
+        `-- index.html        テンプレートファイルです
+
+    app/ ディレクトリの中身をいじった後は必ず
+    % perl bin/menta.pl
+    を実行してください。
+
+    FTP でいちいちアップロードするのが面倒な場合に、環境によっては付属の HTTP サーバーで試すこともできます。
+    % perl bin/cgi-server.pl
+    を実行すると URL が表示されますので、ウェブブラウザでアクセスしてください。
+
Index: /lang/perl/MENTA/tags/release-0.01/vendor/lib/HTTP/Server/Simple.pm
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/vendor/lib/HTTP/Server/Simple.pm (revision 23452)
+++ /lang/perl/MENTA/tags/release-0.01/vendor/lib/HTTP/Server/Simple.pm (revision 23452)
@@ -0,0 +1,762 @@
+use strict;
+use warnings;
+
+package HTTP::Server::Simple;
+use FileHandle;
+use Socket;
+use Carp;
+use URI::Escape;
+
+use vars qw($VERSION $bad_request_doc);
+$VERSION = '0.35';
+
+
+=head1 NAME
+
+HTTP::Server::Simple - Lightweight HTTP server
+
+
+=head1 SYNOPSIS
+
+ use warnings;
+ use strict;
+ 
+ use HTTP::Server::Simple;
+ 
+ my $server = HTTP::Server::Simple->new();
+ $server->run();
+
+However, normally you will sub-class the HTTP::Server::Simple::CGI
+module (see L<HTTP::Server::Simple::CGI>);
+
+ package Your::Web::Server;
+ use base qw(HTTP::Server::Simple::CGI);
+ 
+ sub handle_request {
+     my ($self, $cgi) = @_;
+
+     #... do something, print output to default
+     # selected filehandle...
+
+ }
+ 
+ 1;
+
+=head1 DESCRIPTION
+
+This is a simple standalone HTTP server. By default, it doesn't thread 
+or fork.
+
+It does, however, act as a simple frontend which can be used 
+to build a standalone web-based application or turn a CGI into one.
+
+(It's possible to use Net::Server to get threading, forking,
+preforking and so on. Autrijus Tang wrote the functionality and owes docs for that ;)
+
+By default, the server traps a few signals:
+
+=over
+
+=item HUP
+
+When you C<kill -HUP> the server, it lets the current request finish being
+processed, then uses the C<restart> method to re-exec itself. Please note that
+in order to provide restart-on-SIGHUP, HTTP::Server::Simple sets a SIGHUP
+handler during initialisation. If your request handling code forks you need to
+make sure you reset this or unexpected things will happen if somebody sends a
+HUP to all running processes spawned by your app (e.g. by "kill -HUP <script>")
+
+=item PIPE
+
+If the server detects a broken pipe while writing output to the client, 
+it ignores the signal. Otherwise, a client closing the connection early 
+could kill the server
+
+=back
+
+=head1 EXAMPLE
+ 
+ #!/usr/bin/perl
+ {
+ package MyWebServer;
+ 
+ use HTTP::Server::Simple::CGI;
+ use base qw(HTTP::Server::Simple::CGI);
+ 
+ my %dispatch = (
+     '/hello' => \&resp_hello,
+     # ...
+ );
+ 
+ sub handle_request {
+     my $self = shift;
+     my $cgi  = shift;
+   
+     my $path = $cgi->path_info();
+     my $handler = $dispatch{$path};
+ 
+     if (ref($handler) eq "CODE") {
+         print "HTTP/1.0 200 OK\r\n";
+         $handler->($cgi);
+         
+     } else {
+         print "HTTP/1.0 404 Not found\r\n";
+         print $cgi->header,
+               $cgi->start_html('Not found'),
+               $cgi->h1('Not found'),
+               $cgi->end_html;
+     }
+ }
+ 
+ sub resp_hello {
+     my $cgi  = shift;   # CGI.pm object
+     return if !ref $cgi;
+     
+     my $who = $cgi->param('name');
+     
+     print $cgi->header,
+           $cgi->start_html("Hello"),
+           $cgi->h1("Hello $who!"),
+           $cgi->end_html;
+ }
+ 
+ } 
+ 
+ # start the server on port 8080
+ my $pid = MyWebServer->new(8080)->background();
+ print "Use 'kill $pid' to stop server.\n";
+
+=head1 METHODS 
+
+=head2 HTTP::Server::Simple->new($port)
+
+API call to start a new server.  Does not actually start listening
+until you call C<-E<gt>run()>.
+
+=cut
+
+sub new {
+    my ( $proto, $port ) = @_;
+    my $class = ref($proto) || $proto;
+
+    if ( $class eq __PACKAGE__ ) {
+        require HTTP::Server::Simple::CGI;
+        return HTTP::Server::Simple::CGI->new( @_[ 1 .. $#_ ] );
+    }
+
+    my $self = {};
+    bless( $self, $class );
+    $self->port( $port || '8080' );
+
+
+
+    return $self;
+}
+
+
+=head2 lookup_localhost
+
+Looks up the local host's hostname and IP address.
+
+Stuffs them into
+
+$self->{'localname'} and $self->{'localaddr'}
+
+=cut
+
+sub lookup_localhost {
+    my $self = shift;
+
+    my $local_sockaddr = getsockname( $self->stdio_handle );
+    my ( undef, $localiaddr ) = sockaddr_in($local_sockaddr);
+    $self->host( gethostbyaddr( $localiaddr, AF_INET ) || "localhost");
+    $self->{'local_addr'} = inet_ntoa($localiaddr) || "127.0.0.1";
+}
+
+
+
+
+=head2 port [NUMBER]
+
+Takes an optional port number for this server to listen on.
+
+Returns this server's port. (Defaults to 8080)
+
+=cut
+
+sub port {
+    my $self = shift;
+    $self->{'port'} = shift if (@_);
+    return ( $self->{'port'} );
+
+}
+
+=head2 host [address]
+
+Takes an optional host address for this server to bind to.
+
+Returns this server's bound address (if any).  Defaults to C<undef>
+(bind to all interfaces).
+
+=cut
+
+sub host {
+    my $self = shift;
+    $self->{'host'} = shift if (@_);
+    return ( $self->{'host'} );
+
+}
+
+=head2 background
+
+Run the server in the background. returns pid.
+
+=cut
+
+sub background {
+    my $self  = shift;
+    my $child = fork;
+    die "Can't fork: $!" unless defined($child);
+    return $child if $child;
+
+    if ( $^O !~ /MSWin32/ ) {
+        require POSIX;
+        POSIX::setsid()
+            or die "Can't start a new session: $!";
+    }
+    $self->run(@_);
+}
+
+=head2 run
+
+Run the server.  If all goes well, this won't ever return, but it will
+start listening for http requests.
+
+=cut
+
+my $server_class_id = 0;
+
+use vars '$SERVER_SHOULD_RUN';
+$SERVER_SHOULD_RUN = 1;
+
+sub run {
+    my $self   = shift;
+    my $server = $self->net_server;
+
+    local $SIG{CHLD} = 'IGNORE';    # reap child processes
+
+    # $pkg is generated anew for each invocation to "run"
+    # Just so we can use different net_server() implementations
+    # in different runs.
+    my $pkg = join '::', ref($self), "NetServer" . $server_class_id++;
+
+    no strict 'refs';
+    *{"$pkg\::process_request"} = $self->_process_request;
+
+    if ($server) {
+        require join( '/', split /::/, $server ) . '.pm';
+        *{"$pkg\::ISA"} = [$server];
+
+        # clear the environment before every request
+        require HTTP::Server::Simple::CGI;
+        *{"$pkg\::post_accept"} = sub {
+            HTTP::Server::Simple::CGI::Environment->setup_environment;
+            # $self->SUPER::post_accept uses the wrong super package
+            $server->can('post_accept')->(@_);
+        };
+    }
+    else {
+        $self->setup_listener;
+	$self->after_setup_listener();
+        *{"$pkg\::run"} = $self->_default_run;
+    }
+
+    local $SIG{HUP} = sub { $SERVER_SHOULD_RUN = 0; };
+
+    $pkg->run( port => $self->port, @_ );
+}
+
+=head2 net_server
+
+User-overridable method. If you set it to a C<Net::Server> subclass,
+that subclass is used for the C<run> method.  Otherwise, a minimal 
+implementation is used as default.
+
+=cut
+
+sub net_server {undef}
+
+sub _default_run {
+    my $self = shift;
+
+    # Default "run" closure method for a stub, minimal Net::Server instance.
+    return sub {
+        my $pkg = shift;
+
+        $self->print_banner;
+
+        while ($SERVER_SHOULD_RUN) {
+            local $SIG{PIPE} = 'IGNORE';    # If we don't ignore SIGPIPE, a
+                 # client closing the connection before we
+                 # finish sending will cause the server to exit
+            while ( accept( my $remote = new FileHandle, HTTPDaemon ) ) {
+                $self->stdio_handle($remote);
+                $self->lookup_localhost() unless ($self->host);
+                $self->accept_hook if $self->can("accept_hook");
+
+
+                *STDIN  = $self->stdin_handle();
+                *STDOUT = $self->stdout_handle();
+                select STDOUT;   # required for HTTP::Server::Simple::Recorder
+                                 # XXX TODO glasser: why?
+                $pkg->process_request;
+                close $remote;
+            }
+        }
+
+        # Got here? Time to restart, due to SIGHUP
+        $self->restart;
+    };
+}
+
+=head2 restart
+
+Restarts the server. Usually called by a HUP signal, not directly.
+
+=cut
+
+sub restart {
+    my $self = shift;
+
+    close HTTPDaemon;
+
+    $SIG{CHLD} = 'DEFAULT';
+    wait;
+
+    ### if the standalone server was invoked with perl -I .. we will loose
+    ### those include dirs upon re-exec. So add them to PERL5LIB, so they
+    ### are available again for the exec'ed process --kane
+    use Config;
+    $ENV{PERL5LIB} .= join $Config{path_sep}, @INC;
+
+    # Server simple
+    # do the exec. if $0 is not executable, try running it with $^X.
+    exec {$0}( ( ( -x $0 ) ? () : ($^X) ), $0, @ARGV );
+}
+
+
+sub _process_request {
+    my $self = shift;
+
+    # Create a callback closure that is invoked for each incoming request;
+    # the $self above is bound into the closure.
+    sub {
+
+        $self->stdio_handle(*STDIN) unless $self->stdio_handle;
+
+ # Default to unencoded, raw data out.
+ # if you're sending utf8 and latin1 data mixed, you may need to override this
+        binmode STDIN,  ':raw';
+        binmode STDOUT, ':raw';
+
+        # The ternary operator below is to protect against a crash caused by IE
+        # Ported from Catalyst::Engine::HTTP (Originally by Jasper Krogh and Peter Edwards)
+        # ( http://dev.catalyst.perl.org/changeset/5195, 5221 )
+        
+        my $remote_sockaddr = getpeername( $self->stdio_handle );
+        my ( undef, $iaddr ) = $remote_sockaddr ? sockaddr_in($remote_sockaddr) : (undef,undef);
+        my $peeraddr = $iaddr ? ( inet_ntoa($iaddr) || "127.0.0.1" ) : '127.0.0.1';
+        
+        my ( $method, $request_uri, $proto ) = $self->parse_request;
+        
+        unless ($self->valid_http_method($method) ) {
+            $self->bad_request;
+            return;
+        }
+
+        $proto ||= "HTTP/0.9";
+
+        my ( $file, $query_string )
+            = ( $request_uri =~ /([^?]*)(?:\?(.*))?/s );    # split at ?
+
+        $self->setup(
+            method       => $method,
+            protocol     => $proto,
+            query_string => ( defined($query_string) ? $query_string : '' ),
+            request_uri  => $request_uri,
+            path         => $file,
+            localname    => $self->host,
+            localport    => $self->port,
+            peername     => $peeraddr,
+            peeraddr     => $peeraddr,
+        );
+
+        # HTTP/0.9 didn't have any headers (I think)
+        if ( $proto =~ m{HTTP/(\d(\.\d)?)$} and $1 >= 1 ) {
+
+            my $headers = $self->parse_headers
+                or do { $self->bad_request; return };
+
+            $self->headers($headers);
+
+        }
+
+        $self->post_setup_hook if $self->can("post_setup_hook");
+
+        $self->handler;
+        }
+}
+
+
+
+
+
+=head2 stdio_handle [FILEHANDLE]
+
+When called with an argument, sets the socket to the server to that arg.
+
+Returns the socket to the server; you should only use this for actual socket-related
+calls like C<getsockname>.  If all you want is to read or write to the socket,
+you should use C<stdin_handle> and C<stdout_handle> to get the in and out filehandles
+explicitly.
+
+=cut
+
+sub stdio_handle {
+    my $self = shift;
+    $self->{'_stdio_handle'} = shift if (@_);
+    return $self->{'_stdio_handle'};
+}
+
+=head2 stdin_handle
+
+Returns a filehandle used for input from the client.  By default, 
+returns whatever was set with C<stdio_handle>, but a subclass
+could do something interesting here (see L<HTTP::Server::Simple::Logger>).
+
+=cut
+
+sub stdin_handle {
+    my $self = shift;
+    return $self->stdio_handle;
+}
+
+=head2 stdout_handle
+
+Returns a filehandle used for output to the client.  By default, 
+returns whatever was set with C<stdio_handle>, but a subclass
+could do something interesting here (see L<HTTP::Server::Simple::Logger>).
+
+=cut
+
+sub stdout_handle {
+    my $self = shift;
+    return $self->stdio_handle;
+}
+
+=head1 IMPORTANT SUB-CLASS METHODS
+
+A selection of these methods should be provided by sub-classes of this
+module.
+
+=head2 handler
+
+This method is called after setup, with no parameters.  It should
+print a valid, I<full> HTTP response to the default selected
+filehandle.
+
+=cut
+
+sub handler {
+    my ($self) = @_;
+    if ( ref($self) ne __PACKAGE__ ) {
+        croak "do not call " . ref($self) . "::SUPER->handler";
+    }
+    else {
+        die "handler called out of context";
+    }
+}
+
+=head2 setup(name =E<gt> $value, ...)
+
+This method is called with a name =E<gt> value list of various things
+to do with the request.  This list is given below.
+
+The default setup handler simply tries to call methods with the names
+of keys of this list.
+
+  ITEM/METHOD   Set to                Example
+  -----------  ------------------    ------------------------
+  method       Request Method        "GET", "POST", "HEAD"
+  protocol     HTTP version          "HTTP/1.1"
+  request_uri  Complete Request URI  "/foobar/baz?foo=bar"
+  path         Path part of URI      "/foobar/baz"
+  query_string Query String          undef, "foo=bar"
+  port         Received Port         80, 8080
+  peername     Remote name           "200.2.4.5", "foo.com"
+  peeraddr     Remote address        "200.2.4.5", "::1"
+  localname    Local interface       "localhost", "myhost.com"
+
+=cut
+
+sub setup {
+    my $self = shift;
+    while ( my ( $item, $value ) = splice @_, 0, 2 ) {
+        $self->$item($value) if $self->can($item);
+    }
+}
+
+=head2 headers([Header =E<gt> $value, ...])
+
+Receives HTTP headers and does something useful with them.  This is
+called by the default C<setup()> method.
+
+You have lots of options when it comes to how you receive headers.
+
+You can, if you really want, define C<parse_headers()> and parse them
+raw yourself.
+
+Secondly, you can intercept them very slightly cooked via the
+C<setup()> method, above.
+
+Thirdly, you can leave the C<setup()> header as-is (or calling the
+superclass C<setup()> for unknown request items).  Then you can define
+C<headers()> in your sub-class and receive them all at once.
+
+Finally, you can define handlers to receive individual HTTP headers.
+This can be useful for very simple SOAP servers (to name a
+crack-fueled standard that defines its own special HTTP headers). 
+
+To do so, you'll want to define the C<header()> method in your subclass.
+That method will be handed a (key,value) pair of the header name and the value.
+
+
+=cut
+
+sub headers {
+    my $self    = shift;
+    my $headers = shift;
+
+    my $can_header = $self->can("header");
+    while ( my ( $header, $value ) = splice @$headers, 0, 2 ) {
+        if ($can_header) {
+            $self->header( $header => $value );
+        }
+    }
+}
+
+=head2 accept_hook
+
+If defined by a sub-class, this method is called directly after an
+accept happens.  An accept_hook to add SSL support might look like this:
+
+    sub accept_hook {
+        my $self = shift;
+        my $fh   = $self->stdio_handle;
+
+        $self->SUPER::accept_hook(@_);
+
+        my $newfh =
+        IO::Socket::SSL->start_SSL( $fh, 
+            SSL_server    => 1,
+            SSL_use_cert  => 1,
+            SSL_cert_file => 'myserver.crt',
+            SSL_key_file  => 'myserver.key',
+        )
+        or warn "problem setting up SSL socket: " . IO::Socket::SSL::errstr();
+
+        $self->stdio_handle($newfh) if $newfh;
+    }
+
+=head2 post_setup_hook
+
+If defined by a sub-class, this method is called after all setup has
+finished, before the handler method.
+
+=head2  print_banner
+
+This routine prints a banner before the server request-handling loop
+starts.
+
+Methods below this point are probably not terribly useful to define
+yourself in subclasses.
+
+=cut
+
+sub print_banner {
+    my $self = shift;
+
+    print(    __PACKAGE__
+            . ": You can connect to your server at "
+            . "http://localhost:"
+            . $self->port
+            . "/\n" );
+
+}
+
+=head2 parse_request
+
+Parse the HTTP request line.
+
+Returns three values, the request method, request URI and the protocol
+Sub-classed versions of this should return three values - request
+method, request URI and proto
+
+=cut
+
+sub parse_request {
+    my $self = shift;
+    my $chunk;
+    while ( sysread( STDIN, my $buff, 1 ) ) {
+        last if $buff eq "\n";
+        $chunk .= $buff;
+    }
+    defined($chunk) or return undef;
+    $_ = $chunk;
+
+    m/^(\w+)\s+(\S+)(?:\s+(\S+))?\r?$/;
+    my $method   = $1 || '';
+    my $uri      = $2 || '';
+    my $protocol = $3 || '';
+
+    return ( $method, $uri, $protocol );
+}
+
+=head2 parse_headers
+
+Parse incoming HTTP headers from STDIN.
+
+Remember, this is a B<simple> HTTP server, so nothing intelligent is
+done with them C<:-)>.
+
+This should return an ARRAY ref of C<(header =E<gt> value)> pairs
+inside the array.
+
+=cut
+
+sub parse_headers {
+    my $self = shift;
+
+    my @headers;
+
+    my $chunk = '';
+    while ( sysread( STDIN, my $buff, 1 ) ) {
+        if ( $buff eq "\n" ) {
+            $chunk =~ s/[\r\l\n\s]+$//;
+            if ( $chunk =~ /^([^()<>\@,;:\\"\/\[\]?={} \t]+):\s*(.*)/i ) {
+                push @headers, $1 => $2;
+            }
+            last if ( $chunk =~ /^$/ );
+            $chunk = '';
+        }
+        else { $chunk .= $buff }
+    }
+
+    return ( \@headers );
+}
+
+=head2 setup_listener
+
+This routine binds the server to a port and interface.
+
+=cut
+
+sub setup_listener {
+    my $self = shift;
+
+    my $tcp = getprotobyname('tcp');
+
+    socket( HTTPDaemon, PF_INET, SOCK_STREAM, $tcp ) or die "socket: $!";
+    setsockopt( HTTPDaemon, SOL_SOCKET, SO_REUSEADDR, pack( "l", 1 ) )
+        or warn "setsockopt: $!";
+    bind( HTTPDaemon,
+        sockaddr_in(
+            $self->port(),
+            (   $self->host
+                ? inet_aton( $self->host )
+                : INADDR_ANY
+            )
+        )
+        )
+        or die "bind: $!";
+    listen( HTTPDaemon, SOMAXCONN ) or die "listen: $!";
+
+}
+
+
+=head2 after_setup_listener
+
+This method is called immediately after setup_listener. It's here just for you to override.
+
+=cut
+
+sub after_setup_listener {
+}
+
+=head2 bad_request
+
+This method should print a valid HTTP response that says that the
+request was invalid.
+
+=cut
+
+$bad_request_doc = join "", <DATA>;
+
+sub bad_request {
+    my $self = shift;
+
+    print "HTTP/1.0 400 Bad request\r\n";    # probably OK by now
+    print "Content-Type: text/html\r\nContent-Length: ",
+        length($bad_request_doc), "\r\n\r\n", $bad_request_doc;
+}
+
+=head2 valid_http_method($method)
+
+Given a candidate HTTP method in $method, determine if it is valid.
+Override if, for example, you'd like to do some WebDAV.
+
+=cut 
+
+sub valid_http_method {
+    my $self   = shift;
+    my $method = shift or return 0;
+    return $method =~ /^(?:GET|POST|HEAD|PUT|DELETE)$/;
+}
+
+=head1 AUTHOR
+
+Copyright (c) 2004-2008 Jesse Vincent, <jesse@bestpractical.com>.
+All rights reserved.
+
+Marcus Ramberg <drave@thefeed.no> contributed tests, cleanup, etc
+
+Sam Vilain, <samv@cpan.org> contributed the CGI.pm split-out and
+header/setup API.
+
+Example section by almut on perlmonks, suggested by Mark Fuller.
+
+=head1 BUGS
+
+There certainly are some. Please report them via rt.cpan.org
+
+=head1 LICENSE
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;
+
+__DATA__
+<html>
+  <head>
+    <title>Bad Request</title>
+  </head>
+  <body>
+    <h1>Bad Request</h1>
+
+    <p>Your browser sent a request which this web server could not
+      grok.</p>
+  </body>
+</html>
Index: /lang/perl/MENTA/tags/release-0.01/vendor/lib/HTTP/Server/Simple/CGI/Environment.pm
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/vendor/lib/HTTP/Server/Simple/CGI/Environment.pm (revision 23260)
+++ /lang/perl/MENTA/tags/release-0.01/vendor/lib/HTTP/Server/Simple/CGI/Environment.pm (revision 23260)
@@ -0,0 +1,115 @@
+
+package HTTP::Server::Simple::CGI::Environment;
+
+use strict;
+use warnings;
+use HTTP::Server::Simple;
+
+use vars qw($VERSION %ENV_MAPPING);
+$VERSION = $HTTP::Server::Simple::VERSION;
+
+my %clean_env = %ENV;
+
+=head1 NAME
+
+HTTP::Server::Simple::CGI::Environment - a HTTP::Server::Simple mixin to provide the CGI protocol
+
+=head1 DESCRIPTION
+
+This mixin abstracts the CGI protocol out from HTTP::Server::Simple::CGI so that 
+it's easier to provide your own CGI handlers with HTTP::Server::Simple which 
+B<don't> use CGI.pm
+
+=head2 setup_environment
+
+C<setup_environemnt> is usually called in the superclass's accept_hook
+
+This routine in this sub-class clears the environment to the
+start-up state.
+
+=cut
+
+sub setup_environment {
+    %ENV = (
+        %clean_env,
+        SERVER_SOFTWARE   => "HTTP::Server::Simple/$VERSION",
+        GATEWAY_INTERFACE => 'CGI/1.1'
+    );
+}
+
+=head2 setup_server_url
+
+Sets up the SERVER_URL environment variable
+
+=cut
+
+sub setup_server_url {
+    $ENV{SERVER_URL}
+        ||= ( "http://" . ($ENV{SERVER_NAME} || 'localhost') . ":" . ( $ENV{SERVER_PORT}||80) . "/" );
+}
+
+=head2 setup_environment_from_metadata
+
+This method sets up CGI environment variables based on various
+meta-headers, like the protocol, remote host name, request path, etc.
+
+See the docs in L<HTTP::Server::Simple> for more detail.
+
+=cut
+
+%ENV_MAPPING = (
+    protocol     => "SERVER_PROTOCOL",
+    localport    => "SERVER_PORT",
+    localname    => "SERVER_NAME",
+    path         => "PATH_INFO",
+    request_uri  => "REQUEST_URI",
+    method       => "REQUEST_METHOD",
+    peeraddr     => "REMOTE_ADDR",
+    peername     => "REMOTE_HOST",
+    query_string => "QUERY_STRING",
+);
+
+sub setup_environment_from_metadata {
+    no warnings 'uninitialized';
+    my $self = shift;
+
+    # XXX TODO: rather than clone functionality from the base class,
+    # we should call super
+    #
+    while ( my ( $item, $value ) = splice @_, 0, 2 ) {
+        if ( my $k = $ENV_MAPPING{$item} ) {
+            $ENV{$k} = $value;
+        }
+    }
+
+    # Apache and lighttpd both do one layer of unescaping on
+    # path_info; we should duplicate that.
+    $ENV{PATH_INFO} = URI::Escape::uri_unescape($ENV{PATH_INFO});
+}
+
+=head2  header
+
+C<header> turns a single HTTP headers into CGI environment variables.
+
+=cut
+
+sub header {
+    my $self  = shift;
+    my $tag   = shift;
+    my $value = shift;
+
+    $tag = uc($tag);
+    $tag =~ s/^COOKIES$/COOKIE/;
+    $tag =~ s/-/_/g;
+    $tag = "HTTP_" . $tag
+        unless $tag =~ m/^(?:CONTENT_(?:LENGTH|TYPE)|COOKIE)$/;
+
+    if ( exists $ENV{$tag} ) {
+        $ENV{$tag} .= "; $value";
+    }
+    else {
+        $ENV{$tag} = $value;
+    }
+}
+
+1;
Index: /lang/perl/MENTA/tags/release-0.01/vendor/lib/HTTP/Server/Simple/CGI.pm
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/vendor/lib/HTTP/Server/Simple/CGI.pm (revision 23260)
+++ /lang/perl/MENTA/tags/release-0.01/vendor/lib/HTTP/Server/Simple/CGI.pm (revision 23260)
@@ -0,0 +1,117 @@
+
+package HTTP::Server::Simple::CGI;
+
+use base qw(HTTP::Server::Simple HTTP::Server::Simple::CGI::Environment);
+use strict;
+use warnings;
+
+use CGI ();
+
+use vars qw($VERSION $default_doc);
+$VERSION = $HTTP::Server::Simple::VERSION;
+
+=head1 NAME
+
+HTTP::Server::Simple::CGI - CGI.pm-style version of HTTP::Server::Simple
+
+=head1 DESCRIPTION
+
+HTTP::Server::Simple was already simple, but some smart-ass pointed
+out that there is no CGI in HTTP, and so this module was born to
+isolate the CGI.pm-related parts of this handler.
+
+
+=head2 accept_hook
+
+The accept_hook in this sub-class clears the environment to the
+start-up state.
+
+=cut
+
+sub accept_hook {
+    my $self = shift;
+    $self->setup_environment(@_);
+}
+
+=head2 post_setup_hook
+
+
+
+=cut
+
+sub post_setup_hook {
+    my $self = shift;
+    $self->setup_server_url;
+    CGI::initialize_globals();
+}
+
+=head2 setup
+
+This method sets up CGI environment variables based on various
+meta-headers, like the protocol, remote host name, request path, etc.
+
+See the docs in L<HTTP::Server::Simple> for more detail.
+
+=cut
+
+sub setup {
+    my $self = shift;
+    $self->setup_environment_from_metadata(@_);
+}
+
+=head2 handle_request CGI
+
+This routine is called whenever your server gets a request it can
+handle.
+
+It's called with a CGI object that's been pre-initialized.
+You want to override this method in your subclass
+
+
+=cut
+
+$default_doc = ( join "", <DATA> );
+
+sub handle_request {
+    my ( $self, $cgi ) = @_;
+
+    print "HTTP/1.0 200 OK\r\n";    # probably OK by now
+    print "Content-Type: text/html\r\nContent-Length: ", length($default_doc),
+        "\r\n\r\n", $default_doc;
+}
+
+=head2 handler
+
+Handler implemented as part of HTTP::Server::Simple API
+
+=cut
+
+sub handler {
+    my $self = shift;
+    my $cgi  = new CGI();
+    eval { $self->handle_request($cgi) };
+    if ($@) {
+        my $error = $@;
+        warn $error;
+    }
+}
+
+1;
+
+__DATA__
+<html>
+  <head>
+    <title>Hello!</title>
+  </head>
+  <body>
+    <h1>Congratulations!</h1>
+
+    <p>You now have a functional HTTP::Server::Simple::CGI running.
+      </p>
+
+    <p><i>(If you're seeing this page, it means you haven't subclassed
+      HTTP::Server::Simple::CGI, which you'll need to do to make it
+      useful.)</i>
+      </p>
+  </body>
+</html>
Index: /lang/perl/MENTA/tags/release-0.01/.shipit
===================================================================
--- /lang/perl/MENTA/tags/release-0.01/.shipit (revision 23260)
+++ /lang/perl/MENTA/tags/release-0.01/.shipit (revision 23260)
@@ -0,0 +1,2 @@
+steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN
+svk.tagpattern = release-%v
