content, so we need to fix that:\n\t\t\tbq = bq.replace(\n\t\t\t\t\t/(\\s*[^\\r]+?<\\/pre>)/gm,\n\t\t\t\tfunction(wholeMatch,m1) {\n\t\t\t\t\tvar pre = m1;\n\t\t\t\t\t// attacklab: hack around Konqueror 3.5.4 bug:\n\t\t\t\t\tpre = pre.replace(/^ /mg,\"~0\");\n\t\t\t\t\tpre = pre.replace(/~0/g,\"\");\n\t\t\t\t\treturn pre;\n\t\t\t\t});\n\t\t\t\n\t\t\treturn hashBlock(\"\\n\" + bq + \"\\n
\");\n\t\t});\n\treturn text;\n}\n\n\nvar _FormParagraphs = function(text) {\n//\n// Params:\n// $text - string to process with html tags\n//\n\n\t// Strip leading and trailing lines:\n\ttext = text.replace(/^\\n+/g,\"\");\n\ttext = text.replace(/\\n+$/g,\"\");\n\n\tvar grafs = text.split(/\\n{2,}/g);\n\tvar grafsOut = new Array();\n\n\t//\n\t// Wrap
tags.\n\t//\n\tvar end = grafs.length;\n\tfor (var i=0; i= 0) {\n\t\t\tgrafsOut.push(str);\n\t\t}\n\t\telse if (str.search(/\\S/) >= 0) {\n\t\t\tstr = _RunSpanGamut(str);\n\t\t\tstr = str.replace(/^([ \\t]*)/g,\"\");\n\t\t\tstr += \"
\"\n\t\t\tgrafsOut.push(str);\n\t\t}\n\n\t}\n\n\t//\n\t// Unhashify HTML blocks\n\t//\n\tend = grafsOut.length;\n\tfor (var i=0; i= 0) {\n\t\t\tvar blockText = g_html_blocks[RegExp.$1];\n\t\t\tblockText = blockText.replace(/\\$/g,\"$$$$\"); // Escape any dollar signs\n\t\t\tgrafsOut[i] = grafsOut[i].replace(/~K\\d+K/,blockText);\n\t\t}\n\t}\n\n\treturn grafsOut.join(\"\\n\\n\");\n}\n\n\nvar _EncodeAmpsAndAngles = function(text) {\n// Smart processing for ampersands and angle brackets that need to be encoded.\n\t\n\t// Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:\n\t// http://bumppo.net/projects/amputator/\n\ttext = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\\w+);)/g,\"&\");\n\t\n\t// Encode naked <'s\n\ttext = text.replace(/<(?![a-z\\/?\\$!])/gi,\"<\");\n\t\n\treturn text;\n}\n\n\nvar _EncodeBackslashEscapes = function(text) {\n//\n// Parameter: String.\n// Returns:\tThe string, with after processing the following backslash\n//\t\t\t escape sequences.\n//\n\n\t// attacklab: The polite way to do this is with the new\n\t// escapeCharacters() function:\n\t//\n\t// \ttext = escapeCharacters(text,\"\\\\\",true);\n\t// \ttext = escapeCharacters(text,\"`*_{}[]()>#+-.!\",true);\n\t//\n\t// ...but we're sidestepping its use of the (slow) RegExp constructor\n\t// as an optimization for Firefox. This function gets called a LOT.\n\n\ttext = text.replace(/\\\\(\\\\)/g,escapeCharacters_callback);\n\ttext = text.replace(/\\\\([`*_{}\\[\\]()>#+-.!])/g,escapeCharacters_callback);\n\treturn text;\n}\n\n\nvar _DoAutoLinks = function(text) {\n\n\ttext = text.replace(/<((https?|ftp|dict):[^'\">\\s]+)>/gi,\"$1\");\n\n\t// Email addresses: \n\n\t/*\n\t\ttext = text.replace(/\n\t\t\t<\n\t\t\t(?:mailto:)?\n\t\t\t(\n\t\t\t\t[-.\\w]+\n\t\t\t\t\\@\n\t\t\t\t[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+\n\t\t\t)\n\t\t\t>\n\t\t/gi, _DoAutoLinks_callback());\n\t*/\n\ttext = text.replace(/<(?:mailto:)?([-.\\w]+\\@[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+)>/gi,\n\t\tfunction(wholeMatch,m1) {\n\t\t\treturn _EncodeEmailAddress( _UnescapeSpecialChars(m1) );\n\t\t}\n\t);\n\n\treturn text;\n}\n\n\nvar _EncodeEmailAddress = function(addr) {\n//\n// Input: an email address, e.g. \"foo@example.com\"\n//\n// Output: the email address as a mailto link, with each character\n//\tof the address encoded as either a decimal or hex entity, in\n//\tthe hopes of foiling most address harvesting spam bots. E.g.:\n//\n//\tfoo\n//\t @example.com\n//\n// Based on a filter by Matthew Wickline, posted to the BBEdit-Talk\n// mailing list: \n//\n\n\t// attacklab: why can't javascript speak hex?\n\tfunction char2hex(ch) {\n\t\tvar hexDigits = '0123456789ABCDEF';\n\t\tvar dec = ch.charCodeAt(0);\n\t\treturn(hexDigits.charAt(dec>>4) + hexDigits.charAt(dec&15));\n\t}\n\n\tvar encode = [\n\t\tfunction(ch){return \"\"+ch.charCodeAt(0)+\";\";},\n\t\tfunction(ch){return \"\"+char2hex(ch)+\";\";},\n\t\tfunction(ch){return ch;}\n\t];\n\n\taddr = \"mailto:\" + addr;\n\n\taddr = addr.replace(/./g, function(ch) {\n\t\tif (ch == \"@\") {\n\t\t \t// this *must* be encoded. I insist.\n\t\t\tch = encode[Math.floor(Math.random()*2)](ch);\n\t\t} else if (ch !=\":\") {\n\t\t\t// leave ':' alone (to spot mailto: later)\n\t\t\tvar r = Math.random();\n\t\t\t// roughly 10% raw, 45% hex, 45% dec\n\t\t\tch = (\n\t\t\t\t\tr > .9 ?\tencode[2](ch) :\n\t\t\t\t\tr > .45 ?\tencode[1](ch) :\n\t\t\t\t\t\t\t\tencode[0](ch)\n\t\t\t\t);\n\t\t}\n\t\treturn ch;\n\t});\n\n\taddr = \"\" + addr + \"\";\n\taddr = addr.replace(/\">.+:/g,\"\\\">\"); // strip the mailto: from the visible part\n\n\treturn addr;\n}\n\n\nvar _UnescapeSpecialChars = function(text) {\n//\n// Swap back in all the special characters we've hidden.\n//\n\ttext = text.replace(/~E(\\d+)E/g,\n\t\tfunction(wholeMatch,m1) {\n\t\t\tvar charCodeToReplace = parseInt(m1);\n\t\t\treturn String.fromCharCode(charCodeToReplace);\n\t\t}\n\t);\n\treturn text;\n}\n\n\nvar _Outdent = function(text) {\n//\n// Remove one level of line-leading tabs or spaces\n//\n\n\t// attacklab: hack around Konqueror 3.5.4 bug:\n\t// \"----------bug\".replace(/^-/g,\"\") == \"bug\"\n\n\ttext = text.replace(/^(\\t|[ ]{1,4})/gm,\"~0\"); // attacklab: g_tab_width\n\n\t// attacklab: clean up hack\n\ttext = text.replace(/~0/g,\"\")\n\n\treturn text;\n}\n\nvar _Detab = function(text) {\n// attacklab: Detab's completely rewritten for speed.\n// In perl we could fix it by anchoring the regexp with \\G.\n// In javascript we're less fortunate.\n\n\t// expand first n-1 tabs\n\ttext = text.replace(/\\t(?=\\t)/g,\" \"); // attacklab: g_tab_width\n\n\t// replace the nth with two sentinels\n\ttext = text.replace(/\\t/g,\"~A~B\");\n\n\t// use the sentinel to anchor our regex so it doesn't explode\n\ttext = text.replace(/~B(.+?)~A/g,\n\t\tfunction(wholeMatch,m1,m2) {\n\t\t\tvar leadingText = m1;\n\t\t\tvar numSpaces = 4 - leadingText.length % 4; // attacklab: g_tab_width\n\n\t\t\t// there *must* be a better way to do this:\n\t\t\tfor (var i=0; i;\n f.title = data.title;\n f.id = data.feed_id;\n f.link.@href = data.feed_link;\n f.link.@rel = \"self\";\n f.generator = \"CouchApp on CouchDB\";\n f.updated = rfc3339(data.updated);\n return f.toXMLString().replace(/\\<\\/feed\\>/,'');\n};\n\nexports.entry = function(data) {\n var entry = ;\n entry.id = data.entry_id;\n entry.title = data.title;\n entry.content = data.content;\n entry.content.@type = (data.content_type || 'html');\n entry.updated = rfc3339(data.updated);\n entry.author = {data.author};\n entry.link.@href = data.alternate;\n entry.link.@rel = \"alternate\";\n return entry;\n}","linkup":"// this code makes http://example.com into a link, \n// and also handles @name and #hashtag\n\n// todo add [[wiki_links]]\n\nvar mustache = require(\"vendor/couchapp/lib/mustache\");\nexports.encode = function(body, person_prefix, tag_prefix) {\n body = mustache.escape(body);\n person_prefix = person_prefix || \"http://twitter.com/\";\n tag_prefix = tag_prefix || \"http://delicious.com/tag/\";\n return body.replace(/((ftp|http|https):\\/\\/(\\w+:{0,1}\\w*@)?(\\S+)(:[0-9]+)?(\\/|\\/([\\w#!:.?+=&%@!\\-\\/]))?)/gi,function(a) {\n return ''+a+'';\n }).replace(/\\@([\\w\\-]+)/g,function(user,name) {\n return ''+user+'';\n }).replace(/\\#([\\w\\-\\.]+)/g,function(word,tag) {\n return ''+word+'';\n });\n};","path":"// from couch.js\nfunction encodeOptions(options) {\n var buf = [];\n if (typeof(options) == \"object\" && options !== null) {\n for (var name in options) {\n if (!options.hasOwnProperty(name)) {continue;}\n var value = options[name];\n if (name == \"key\" || name == \"startkey\" || name == \"endkey\") {\n value = JSON.stringify(value);\n }\n buf.push(encodeURIComponent(name) + \"=\" + encodeURIComponent(value));\n }\n }\n if (!buf.length) {\n return \"\";\n }\n return \"?\" + buf.join(\"&\");\n}\n\nfunction concatArgs(array, args) {\n for (var i=0; i < args.length; i++) {\n array.push(args[i]);\n };\n return array;\n};\n\nfunction makePath(array) {\n var options, path;\n \n if (typeof array[array.length - 1] != \"string\") {\n // it's a params hash\n options = array.pop();\n }\n path = array.map(function(item) {return encodeURIComponent(item)}).join('/');\n if (options) {\n return path + encodeOptions(options);\n } else {\n return path; \n }\n};\n\nexports.init = function(req) {\n return {\n asset : function() {\n var p = req.path, parts = ['', p[0], p[1] , p[2]];\n return makePath(concatArgs(parts, arguments));\n },\n show : function() {\n var p = req.path, parts = ['', p[0], p[1] , p[2], '_show'];\n return makePath(concatArgs(parts, arguments));\n },\n list : function() {\n var p = req.path, parts = ['', p[0], p[1] , p[2], '_list'];\n return makePath(concatArgs(parts, arguments));\n },\n update : function() {\n var p = req.path, parts = ['', p[0], p[1] , p[2], '_update'];\n return makePath(concatArgs(parts, arguments));\n },\n limit : function(limit) {\n var query = req.query;\n var l = query.limit;\n query.limit = limit;\n var view = req.path[req.path.length - 1];\n var list = req.path[req.path.length - 2];\n var link = this.list(list, view, query);\n query.limit = l;\n return link;\n },\n older : function(key) {\n if (!typeof key == \"undefined\") return null;\n var query = req.query;\n query.startkey = key;\n query.skip=1;\n var view = req.path[req.path.length - 1];\n var list = req.path[req.path.length - 2];\n return this.list(list, view, query);\n },\n absolute : function(path) {\n return 'http://' + req.headers.Host + path;\n }\n }\n};","md5":"/*\n * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message\n * Digest Algorithm, as defined in RFC 1321.\n * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.\n * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n * Distributed under the BSD License\n * See http://pajhome.org.uk/crypt/md5 for more info.\n */\n\n/*\n * Configurable variables. You may need to tweak these to be compatible with\n * the server-side, but the defaults work in most cases.\n */\nvar hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */\nvar b64pad = \"\"; /* base-64 pad character. \"=\" for strict RFC compliance */\nvar chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */\n\n/*\n * These are the functions you'll usually want to call\n * They take string arguments and return either hex or base-64 encoded strings\n */\nfunction hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}\nfunction b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}\nfunction str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}\nfunction hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }\nfunction b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }\nfunction str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }\n\n/*\n * Perform a simple self-test to see if the VM is working\n */\nfunction md5_vm_test()\n{\n return hex_md5(\"abc\") == \"900150983cd24fb0d6963f7d28e17f72\";\n}\n\n/*\n * Calculate the MD5 of an array of little-endian words, and a bit length\n keep\n */\nfunction core_md5(x, len)\n{\n /* append padding */\n x[len >> 5] |= 0x80 << ((len) % 32);\n x[(((len + 64) >>> 9) << 4) + 14] = len;\n\n var a = 1732584193;\n var b = -271733879;\n var c = -1732584194;\n var d = 271733878;\n\n for(var i = 0; i < x.length; i += 16)\n {\n var olda = a;\n var oldb = b;\n var oldc = c;\n var oldd = d;\n\n a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);\n d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);\n c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);\n b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);\n a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);\n d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);\n c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);\n b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);\n a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);\n d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);\n c = md5_ff(c, d, a, b, x[i+10], 17, -42063);\n b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);\n a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);\n d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);\n c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);\n b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);\n\n a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);\n d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);\n c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);\n b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);\n a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);\n d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);\n c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);\n b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);\n a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);\n d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);\n c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);\n b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);\n a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);\n d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);\n c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);\n b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);\n\n a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);\n d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);\n c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);\n b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);\n a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);\n d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);\n c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);\n b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);\n a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);\n d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);\n c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);\n b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);\n a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);\n d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);\n c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);\n b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);\n\n a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);\n d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);\n c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);\n b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);\n a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);\n d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);\n c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);\n b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);\n a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);\n d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);\n c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);\n b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);\n a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);\n d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);\n c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);\n b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);\n\n a = safe_add(a, olda);\n b = safe_add(b, oldb);\n c = safe_add(c, oldc);\n d = safe_add(d, oldd);\n }\n return Array(a, b, c, d);\n\n}\n\n/*\n * These functions implement the four basic operations the algorithm uses.\n */\nfunction md5_cmn(q, a, b, x, s, t)\n{\n return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);\n}\nfunction md5_ff(a, b, c, d, x, s, t)\n{\n return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);\n}\nfunction md5_gg(a, b, c, d, x, s, t)\n{\n return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);\n}\nfunction md5_hh(a, b, c, d, x, s, t)\n{\n return md5_cmn(b ^ c ^ d, a, b, x, s, t);\n}\nfunction md5_ii(a, b, c, d, x, s, t)\n{\n return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);\n}\n\n/*\n * Calculate the HMAC-MD5, of a key and some data\n */\nfunction core_hmac_md5(key, data)\n{\n var bkey = str2binl(key);\n if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);\n\n var ipad = Array(16), opad = Array(16);\n for(var i = 0; i < 16; i++)\n {\n ipad[i] = bkey[i] ^ 0x36363636;\n opad[i] = bkey[i] ^ 0x5C5C5C5C;\n }\n\n var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);\n return core_md5(opad.concat(hash), 512 + 128);\n}\n\n/*\n * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n * to work around bugs in some JS interpreters.\n */\nfunction safe_add(x, y)\n{\n var lsw = (x & 0xFFFF) + (y & 0xFFFF);\n var msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n return (msw << 16) | (lsw & 0xFFFF);\n}\n\n/*\n * Bitwise rotate a 32-bit number to the left.\n */\nfunction bit_rol(num, cnt)\n{\n return (num << cnt) | (num >>> (32 - cnt));\n}\n\n/*\n * Convert a string to an array of little-endian words\n * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.\n keep\n */\nfunction str2binl(str)\n{\n var bin = Array();\n var mask = (1 << chrsz) - 1;\n for(var i = 0; i < str.length * chrsz; i += chrsz)\n bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);\n return bin;\n}\n\n/*\n * Convert an array of little-endian words to a string\n */\nfunction binl2str(bin)\n{\n var str = \"\";\n var mask = (1 << chrsz) - 1;\n for(var i = 0; i < bin.length * 32; i += chrsz)\n str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);\n return str;\n}\n\n/*\n * Convert an array of little-endian words to a hex string.\n keep\n */\nfunction binl2hex(binarray)\n{\n var hex_tab = hexcase ? \"0123456789ABCDEF\" : \"0123456789abcdef\";\n var str = \"\";\n for(var i = 0; i < binarray.length * 4; i++)\n {\n str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +\n hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);\n }\n return str;\n}\n\n/*\n * Convert an array of little-endian words to a base-64 string\n */\nfunction binl2b64(binarray)\n{\n var tab = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n var str = \"\";\n for(var i = 0; i < binarray.length * 4; i += 3)\n {\n var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)\n | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )\n | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);\n for(var j = 0; j < 4; j++)\n {\n if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;\n else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);\n }\n }\n return str;\n}\n\nexports.hex = hex_md5;","validate":"// a library for validations\n// over time we expect to extract more helpers and move them here.\nexports.init = function(newDoc, oldDoc, userCtx, secObj) {\n var v = {};\n \n v.forbidden = function(message) { \n throw({forbidden : message});\n };\n\n v.unauthorized = function(message) {\n throw({unauthorized : message});\n };\n\n v.assert = function(should, message) {\n if (!should) v.forbidden(message);\n }\n \n v.isAdmin = function() {\n return userCtx.roles.indexOf('_admin') != -1\n };\n \n v.isRole = function(role) {\n return userCtx.roles.indexOf(role) != -1\n };\n\n v.require = function() {\n for (var i=0; i < arguments.length; i++) {\n var field = arguments[i];\n message = \"The '\"+field+\"' field is required.\";\n if (typeof newDoc[field] == \"undefined\") v.forbidden(message);\n };\n };\n\n v.unchanged = function(field) {\n if (oldDoc && oldDoc[field] != newDoc[field]) \n v.forbidden(\"You may not change the '\"+field+\"' field.\");\n };\n\n v.matches = function(field, regex, message) {\n if (!newDoc[field].match(regex)) {\n message = message || \"Format of '\"+field+\"' field is invalid.\";\n v.forbidden(message); \n }\n };\n\n // this ensures that the date will be UTC, parseable, and collate correctly\n v.dateFormat = function(field) {\n message = \"Sorry, '\"+field+\"' is not a valid date format. Try: 2010-02-24T17:00:03.432Z\";\n v.matches(field, /\\d{4}\\-\\d{2}\\-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d*)?Z/, message);\n }\n \n return v;\n};","mustache":"/*\n * CommonJS-compatible mustache.js module\n *\n * See http://github.com/janl/mustache.js for more info.\n */\n\n/*\n mustache.js \u2014 Logic-less templates in JavaScript\n\n See http://mustache.github.com/ for more info.\n*/\n\nvar Mustache = function() {\n var Renderer = function() {};\n\n Renderer.prototype = {\n otag: \"{{\",\n ctag: \"}}\",\n pragmas: {},\n buffer: [],\n pragmas_implemented: {\n \"IMPLICIT-ITERATOR\": true\n },\n context: {},\n\n render: function(template, context, partials, in_recursion) {\n // reset buffer & set context\n if(!in_recursion) {\n this.context = context;\n this.buffer = []; // TODO: make this non-lazy\n }\n\n // fail fast\n if(!this.includes(\"\", template)) {\n if(in_recursion) {\n return template;\n } else {\n this.send(template);\n return;\n }\n }\n\n template = this.render_pragmas(template);\n var html = this.render_section(template, context, partials);\n if(in_recursion) {\n return this.render_tags(html, context, partials, in_recursion);\n }\n\n this.render_tags(html, context, partials, in_recursion);\n },\n\n /*\n Sends parsed lines\n */\n send: function(line) {\n if(line != \"\") {\n this.buffer.push(line);\n }\n },\n\n /*\n Looks for %PRAGMAS\n */\n render_pragmas: function(template) {\n // no pragmas\n if(!this.includes(\"%\", template)) {\n return template;\n }\n\n var that = this;\n var regex = new RegExp(this.otag + \"%([\\\\w-]+) ?([\\\\w]+=[\\\\w]+)?\" +\n this.ctag);\n return template.replace(regex, function(match, pragma, options) {\n if(!that.pragmas_implemented[pragma]) {\n throw({message: \n \"This implementation of mustache doesn't understand the '\" +\n pragma + \"' pragma\"});\n }\n that.pragmas[pragma] = {};\n if(options) {\n var opts = options.split(\"=\");\n that.pragmas[pragma][opts[0]] = opts[1];\n }\n return \"\";\n // ignore unknown pragmas silently\n });\n },\n\n /*\n Tries to find a partial in the curent scope and render it\n */\n render_partial: function(name, context, partials) {\n name = this.trim(name);\n if(!partials || partials[name] === undefined) {\n throw({message: \"unknown_partial '\" + name + \"'\"});\n }\n if(typeof(context[name]) != \"object\") {\n return this.render(partials[name], context, partials, true);\n }\n return this.render(partials[name], context[name], partials, true);\n },\n\n /*\n Renders inverted (^) and normal (#) sections\n */\n render_section: function(template, context, partials) {\n if(!this.includes(\"#\", template) && !this.includes(\"^\", template)) {\n return template;\n }\n\n var that = this;\n // CSW - Added \"+?\" so it finds the tighest bound, not the widest\n var regex = new RegExp(this.otag + \"(\\\\^|\\\\#)\\\\s*(.+)\\\\s*\" + this.ctag +\n \"\\n*([\\\\s\\\\S]+?)\" + this.otag + \"\\\\/\\\\s*\\\\2\\\\s*\" + this.ctag +\n \"\\\\s*\", \"mg\");\n\n // for each {{#foo}}{{/foo}} section do...\n return template.replace(regex, function(match, type, name, content) {\n var value = that.find(name, context);\n if(type == \"^\") { // inverted section\n if(!value || that.is_array(value) && value.length === 0) {\n // false or empty list, render it\n return that.render(content, context, partials, true);\n } else {\n return \"\";\n }\n } else if(type == \"#\") { // normal section\n if(that.is_array(value)) { // Enumerable, Let's loop!\n return that.map(value, function(row) {\n return that.render(content, that.create_context(row),\n partials, true);\n }).join(\"\");\n } else if(that.is_object(value)) { // Object, Use it as subcontext!\n return that.render(content, that.create_context(value),\n partials, true);\n } else if(typeof value === \"function\") {\n // higher order section\n return value.call(context, content, function(text) {\n return that.render(text, context, partials, true);\n });\n } else if(value) { // boolean section\n return that.render(content, context, partials, true);\n } else {\n return \"\";\n }\n }\n });\n },\n\n /*\n Replace {{foo}} and friends with values from our view\n */\n render_tags: function(template, context, partials, in_recursion) {\n // tit for tat\n var that = this;\n\n var new_regex = function() {\n return new RegExp(that.otag + \"(=|!|>|\\\\{|%)?([^\\\\/#\\\\^]+?)\\\\1?\" +\n that.ctag + \"+\", \"g\");\n };\n\n var regex = new_regex();\n var tag_replace_callback = function(match, operator, name) {\n switch(operator) {\n case \"!\": // ignore comments\n return \"\";\n case \"=\": // set new delimiters, rebuild the replace regexp\n that.set_delimiters(name);\n regex = new_regex();\n return \"\";\n case \">\": // render partial\n return that.render_partial(name, context, partials);\n case \"{\": // the triple mustache is unescaped\n return that.find(name, context);\n default: // escape the value\n return that.escape(that.find(name, context));\n }\n };\n var lines = template.split(\"\\n\");\n for(var i = 0; i < lines.length; i++) {\n lines[i] = lines[i].replace(regex, tag_replace_callback, this);\n if(!in_recursion) {\n this.send(lines[i]);\n }\n }\n\n if(in_recursion) {\n return lines.join(\"\\n\");\n }\n },\n\n set_delimiters: function(delimiters) {\n var dels = delimiters.split(\" \");\n this.otag = this.escape_regex(dels[0]);\n this.ctag = this.escape_regex(dels[1]);\n },\n\n escape_regex: function(text) {\n // thank you Simon Willison\n if(!arguments.callee.sRE) {\n var specials = [\n '/', '.', '*', '+', '?', '|',\n '(', ')', '[', ']', '{', '}', '\\\\'\n ];\n arguments.callee.sRE = new RegExp(\n '(\\\\' + specials.join('|\\\\') + ')', 'g'\n );\n }\n return text.replace(arguments.callee.sRE, '\\\\$1');\n },\n\n /*\n find `name` in current `context`. That is find me a value\n from the view object\n */\n find: function(name, context) {\n name = this.trim(name);\n\n // Checks whether a value is thruthy or false or 0\n function is_kinda_truthy(bool) {\n return bool === false || bool === 0 || bool;\n }\n\n var value;\n if(is_kinda_truthy(context[name])) {\n value = context[name];\n } else if(is_kinda_truthy(this.context[name])) {\n value = this.context[name];\n }\n\n if(typeof value === \"function\") {\n return value.apply(context);\n }\n if(value !== undefined) {\n return value;\n }\n // silently ignore unkown variables\n return \"\";\n },\n\n // Utility methods\n\n /* includes tag */\n includes: function(needle, haystack) {\n return haystack.indexOf(this.otag + needle) != -1;\n },\n\n /*\n Does away with nasty characters\n */\n escape: function(s) {\n s = String(s === null ? \"\" : s);\n return s.replace(/&(?!\\w+;)|[\"<>\\\\]/g, function(s) {\n switch(s) {\n case \"&\": return \"&\";\n case \"\\\\\": return \"\\\\\\\\\";\n case '\"': return '\\\"';\n case \"<\": return \"<\";\n case \">\": return \">\";\n default: return s;\n }\n });\n },\n\n // by @langalex, support for arrays of strings\n create_context: function(_context) {\n if(this.is_object(_context)) {\n return _context;\n } else {\n var iterator = \".\";\n if(this.pragmas[\"IMPLICIT-ITERATOR\"]) {\n iterator = this.pragmas[\"IMPLICIT-ITERATOR\"].iterator;\n }\n var ctx = {};\n ctx[iterator] = _context;\n return ctx;\n }\n },\n\n is_object: function(a) {\n return a && typeof a == \"object\";\n },\n\n is_array: function(a) {\n return Object.prototype.toString.call(a) === '[object Array]';\n },\n\n /*\n Gets rid of leading and trailing whitespace\n */\n trim: function(s) {\n return s.replace(/^\\s*|\\s*$/g, \"\");\n },\n\n /*\n Why, why, why? Because IE. Cry, cry cry.\n */\n map: function(array, fn) {\n if (typeof array.map == \"function\") {\n return array.map(fn);\n } else {\n var r = [];\n var l = array.length;\n for(var i = 0; i < l; i++) {\n r.push(fn(array[i]));\n }\n return r;\n }\n }\n };\n\n return({\n name: \"mustache.js\",\n version: \"0.3.1-dev\",\n\n /*\n Turns a template and view into HTML\n */\n to_html: function(template, view, partials, send_fun) {\n var renderer = new Renderer();\n if(send_fun) {\n renderer.send = send_fun;\n }\n renderer.render(template, view, partials);\n if(!send_fun) {\n return renderer.buffer.join(\"\\n\");\n }\n },\n escape : function(text) {\n return new Renderer().escape(text);\n }\n });\n}();\n\nexports.name = Mustache.name;\nexports.version = Mustache.version;\n\nexports.to_html = Mustache.to_html;\nexports.escape = Mustache.escape;","docform":"// Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n// use this file except in compliance with the License. You may obtain a copy\n// of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n// License for the specific language governing permissions and limitations under\n// the License.\n\n// turn the form into deep json\n// field names like 'author-email' get turned into json like\n// {\"author\":{\"email\":\"quentin@example.com\"}}\n// acts on doc by reference, so you can safely pass non-form fields through\n\nfunction docForm(formSelector, opts) {\n var localFormDoc = {};\n opts = opts || {};\n opts.fields = opts.fields || [];\n\n // turn the form into deep json\n // field names like 'author-email' get turned into json like\n // {\"author\":{\"email\":\"quentin@example.com\"}}\n function formToDeepJSON(form, fields, doc) {\n form = $(form);\n fields.forEach(function(field) {\n var element = form.find(\"[name=\"+field+\"]\");\n if (element.attr('type') === 'checkbox') {\n var val = element.attr('checked');\n } else {\n var val = element.val();\n if (!val) return;\n }\n var parts = field.split('-');\n var frontObj = doc, frontName = parts.shift();\n while (parts.length > 0) {\n frontObj[frontName] = frontObj[frontName] || {};\n frontObj = frontObj[frontName];\n frontName = parts.shift();\n }\n frontObj[frontName] = val;\n });\n }\n \n // Apply the behavior\n $(formSelector).submit(function(e) {\n e.preventDefault();\n if (opts.validate && opts.validate() == false) { return false;}\n // formToDeepJSON acts on localFormDoc by reference\n formToDeepJSON(this, opts.fields, localFormDoc);\n if (opts.beforeSave) {opts.beforeSave(localFormDoc);}\n db.saveDoc(localFormDoc, {\n success : function(resp) {\n if (opts.success) {opts.success(resp, localFormDoc);}\n }\n });\n \n return false;\n });\n\n // populate form from an existing doc\n function docToForm(doc) {\n var form = $(formSelector);\n // fills in forms\n opts.fields.forEach(function(field) {\n var parts = field.split('-');\n var run = true, frontObj = doc, frontName = parts.shift();\n while (frontObj && parts.length > 0) { \n frontObj = frontObj[frontName];\n frontName = parts.shift();\n }\n if (frontObj && frontObj[frontName]) {\n var element = form.find(\"[name=\"+field+\"]\");\n if (element.attr('type') === 'checkbox') {\n element.attr('checked', frontObj[frontName]);\n } else {\n element.val(frontObj[frontName]);\n }\n }\n });\n }\n \n if (opts.id) {\n db.openDoc(opts.id, {\n attachPrevRev : opts.attachPrevRev,\n error: function() {\n if (opts.error) {opts.error.apply(opts, arguments);}\n },\n success: function(doc) {\n if (opts.load || opts.onLoad) {(opts.load || opts.onLoad)(doc);}\n localFormDoc = doc;\n docToForm(doc);\n }});\n } else if (opts.template) {\n if (opts.load || opts.onLoad) {(opts.load || opts.onLoad)(opts.template);}\n localFormDoc = opts.template;\n docToForm(localFormDoc);\n }\n var instance = {\n deleteDoc : function(opts) {\n opts = opts || {};\n if (confirm(\"Really delete this document?\")) { \n db.removeDoc(localFormDoc, opts);\n }\n },\n localDoc : function() {\n formToDeepJSON(formSelector, opts.fields, localFormDoc);\n return localFormDoc;\n }\n };\n return instance;\n}"},"metadata":{"name":"couchapp","fetch_uri":"git://github.com/couchapp/couchapp.git","description":"official couchapp vendor"}}},"views":{"recent-posts":{"map":"function(doc) {\n if (doc.type == \"post\") {\n emit(new Date(doc.created_at), doc);\n }\n};"},"post-page":{"map":"function(doc) {\n // todo make commonjs\n /*\n * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message\n * Digest Algorithm, as defined in RFC 1321.\n * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.\n * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n * Distributed under the BSD License\n * See http://pajhome.org.uk/crypt/md5 for more info.\n */\n\n/*\n * Configurable variables. You may need to tweak these to be compatible with\n * the server-side, but the defaults work in most cases.\n */\nvar hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */\nvar b64pad = \"\"; /* base-64 pad character. \"=\" for strict RFC compliance */\nvar chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */\n\n/*\n * These are the functions you'll usually want to call\n * They take string arguments and return either hex or base-64 encoded strings\n */\nfunction hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}\nfunction b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}\nfunction str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}\nfunction hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }\nfunction b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }\nfunction str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }\n\n/*\n * Perform a simple self-test to see if the VM is working\n */\nfunction md5_vm_test()\n{\n return hex_md5(\"abc\") == \"900150983cd24fb0d6963f7d28e17f72\";\n}\n\n/*\n * Calculate the MD5 of an array of little-endian words, and a bit length\n keep\n */\nfunction core_md5(x, len)\n{\n /* append padding */\n x[len >> 5] |= 0x80 << ((len) % 32);\n x[(((len + 64) >>> 9) << 4) + 14] = len;\n\n var a = 1732584193;\n var b = -271733879;\n var c = -1732584194;\n var d = 271733878;\n\n for(var i = 0; i < x.length; i += 16)\n {\n var olda = a;\n var oldb = b;\n var oldc = c;\n var oldd = d;\n\n a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);\n d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);\n c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);\n b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);\n a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);\n d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);\n c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);\n b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);\n a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);\n d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);\n c = md5_ff(c, d, a, b, x[i+10], 17, -42063);\n b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);\n a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);\n d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);\n c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);\n b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);\n\n a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);\n d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);\n c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);\n b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);\n a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);\n d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);\n c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);\n b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);\n a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);\n d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);\n c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);\n b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);\n a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);\n d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);\n c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);\n b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);\n\n a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);\n d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);\n c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);\n b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);\n a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);\n d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);\n c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);\n b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);\n a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);\n d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);\n c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);\n b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);\n a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);\n d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);\n c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);\n b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);\n\n a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);\n d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);\n c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);\n b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);\n a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);\n d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);\n c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);\n b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);\n a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);\n d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);\n c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);\n b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);\n a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);\n d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);\n c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);\n b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);\n\n a = safe_add(a, olda);\n b = safe_add(b, oldb);\n c = safe_add(c, oldc);\n d = safe_add(d, oldd);\n }\n return Array(a, b, c, d);\n\n}\n\n/*\n * These functions implement the four basic operations the algorithm uses.\n */\nfunction md5_cmn(q, a, b, x, s, t)\n{\n return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);\n}\nfunction md5_ff(a, b, c, d, x, s, t)\n{\n return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);\n}\nfunction md5_gg(a, b, c, d, x, s, t)\n{\n return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);\n}\nfunction md5_hh(a, b, c, d, x, s, t)\n{\n return md5_cmn(b ^ c ^ d, a, b, x, s, t);\n}\nfunction md5_ii(a, b, c, d, x, s, t)\n{\n return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);\n}\n\n/*\n * Calculate the HMAC-MD5, of a key and some data\n */\nfunction core_hmac_md5(key, data)\n{\n var bkey = str2binl(key);\n if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);\n\n var ipad = Array(16), opad = Array(16);\n for(var i = 0; i < 16; i++)\n {\n ipad[i] = bkey[i] ^ 0x36363636;\n opad[i] = bkey[i] ^ 0x5C5C5C5C;\n }\n\n var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);\n return core_md5(opad.concat(hash), 512 + 128);\n}\n\n/*\n * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n * to work around bugs in some JS interpreters.\n */\nfunction safe_add(x, y)\n{\n var lsw = (x & 0xFFFF) + (y & 0xFFFF);\n var msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n return (msw << 16) | (lsw & 0xFFFF);\n}\n\n/*\n * Bitwise rotate a 32-bit number to the left.\n */\nfunction bit_rol(num, cnt)\n{\n return (num << cnt) | (num >>> (32 - cnt));\n}\n\n/*\n * Convert a string to an array of little-endian words\n * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.\n keep\n */\nfunction str2binl(str)\n{\n var bin = Array();\n var mask = (1 << chrsz) - 1;\n for(var i = 0; i < str.length * chrsz; i += chrsz)\n bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);\n return bin;\n}\n\n/*\n * Convert an array of little-endian words to a string\n */\nfunction binl2str(bin)\n{\n var str = \"\";\n var mask = (1 << chrsz) - 1;\n for(var i = 0; i < bin.length * 32; i += chrsz)\n str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);\n return str;\n}\n\n/*\n * Convert an array of little-endian words to a hex string.\n keep\n */\nfunction binl2hex(binarray)\n{\n var hex_tab = hexcase ? \"0123456789ABCDEF\" : \"0123456789abcdef\";\n var str = \"\";\n for(var i = 0; i < binarray.length * 4; i++)\n {\n str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +\n hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);\n }\n return str;\n}\n\n/*\n * Convert an array of little-endian words to a base-64 string\n */\nfunction binl2b64(binarray)\n{\n var tab = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n var str = \"\";\n for(var i = 0; i < binarray.length * 4; i += 3)\n {\n var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)\n | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )\n | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);\n for(var j = 0; j < 4; j++)\n {\n if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;\n else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);\n }\n }\n return str;\n}\n \n if (doc.type == \"post\") {\n emit([doc._id], doc);\n } else if (doc.type == \"comment\") {\n if (doc.commenter && doc.commenter.email && !doc.commenter.gravatar_url) {\n doc.commenter.gravatar = hex_md5(doc.commenter.email); \n }\n emit([doc.post_id, doc.created_at], doc);\n }\n};"},"comments":{"map":"function(doc) {\n /*\n * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message\n * Digest Algorithm, as defined in RFC 1321.\n * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.\n * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n * Distributed under the BSD License\n * See http://pajhome.org.uk/crypt/md5 for more info.\n */\n\n/*\n * Configurable variables. You may need to tweak these to be compatible with\n * the server-side, but the defaults work in most cases.\n */\nvar hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */\nvar b64pad = \"\"; /* base-64 pad character. \"=\" for strict RFC compliance */\nvar chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */\n\n/*\n * These are the functions you'll usually want to call\n * They take string arguments and return either hex or base-64 encoded strings\n */\nfunction hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}\nfunction b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}\nfunction str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}\nfunction hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }\nfunction b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }\nfunction str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }\n\n/*\n * Perform a simple self-test to see if the VM is working\n */\nfunction md5_vm_test()\n{\n return hex_md5(\"abc\") == \"900150983cd24fb0d6963f7d28e17f72\";\n}\n\n/*\n * Calculate the MD5 of an array of little-endian words, and a bit length\n keep\n */\nfunction core_md5(x, len)\n{\n /* append padding */\n x[len >> 5] |= 0x80 << ((len) % 32);\n x[(((len + 64) >>> 9) << 4) + 14] = len;\n\n var a = 1732584193;\n var b = -271733879;\n var c = -1732584194;\n var d = 271733878;\n\n for(var i = 0; i < x.length; i += 16)\n {\n var olda = a;\n var oldb = b;\n var oldc = c;\n var oldd = d;\n\n a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);\n d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);\n c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);\n b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);\n a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);\n d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);\n c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);\n b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);\n a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);\n d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);\n c = md5_ff(c, d, a, b, x[i+10], 17, -42063);\n b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);\n a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);\n d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);\n c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);\n b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);\n\n a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);\n d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);\n c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);\n b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);\n a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);\n d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);\n c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);\n b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);\n a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);\n d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);\n c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);\n b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);\n a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);\n d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);\n c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);\n b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);\n\n a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);\n d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);\n c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);\n b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);\n a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);\n d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);\n c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);\n b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);\n a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);\n d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);\n c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);\n b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);\n a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);\n d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);\n c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);\n b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);\n\n a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);\n d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);\n c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);\n b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);\n a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);\n d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);\n c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);\n b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);\n a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);\n d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);\n c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);\n b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);\n a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);\n d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);\n c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);\n b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);\n\n a = safe_add(a, olda);\n b = safe_add(b, oldb);\n c = safe_add(c, oldc);\n d = safe_add(d, oldd);\n }\n return Array(a, b, c, d);\n\n}\n\n/*\n * These functions implement the four basic operations the algorithm uses.\n */\nfunction md5_cmn(q, a, b, x, s, t)\n{\n return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);\n}\nfunction md5_ff(a, b, c, d, x, s, t)\n{\n return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);\n}\nfunction md5_gg(a, b, c, d, x, s, t)\n{\n return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);\n}\nfunction md5_hh(a, b, c, d, x, s, t)\n{\n return md5_cmn(b ^ c ^ d, a, b, x, s, t);\n}\nfunction md5_ii(a, b, c, d, x, s, t)\n{\n return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);\n}\n\n/*\n * Calculate the HMAC-MD5, of a key and some data\n */\nfunction core_hmac_md5(key, data)\n{\n var bkey = str2binl(key);\n if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);\n\n var ipad = Array(16), opad = Array(16);\n for(var i = 0; i < 16; i++)\n {\n ipad[i] = bkey[i] ^ 0x36363636;\n opad[i] = bkey[i] ^ 0x5C5C5C5C;\n }\n\n var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);\n return core_md5(opad.concat(hash), 512 + 128);\n}\n\n/*\n * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n * to work around bugs in some JS interpreters.\n */\nfunction safe_add(x, y)\n{\n var lsw = (x & 0xFFFF) + (y & 0xFFFF);\n var msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n return (msw << 16) | (lsw & 0xFFFF);\n}\n\n/*\n * Bitwise rotate a 32-bit number to the left.\n */\nfunction bit_rol(num, cnt)\n{\n return (num << cnt) | (num >>> (32 - cnt));\n}\n\n/*\n * Convert a string to an array of little-endian words\n * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.\n keep\n */\nfunction str2binl(str)\n{\n var bin = Array();\n var mask = (1 << chrsz) - 1;\n for(var i = 0; i < str.length * chrsz; i += chrsz)\n bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);\n return bin;\n}\n\n/*\n * Convert an array of little-endian words to a string\n */\nfunction binl2str(bin)\n{\n var str = \"\";\n var mask = (1 << chrsz) - 1;\n for(var i = 0; i < bin.length * 32; i += chrsz)\n str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);\n return str;\n}\n\n/*\n * Convert an array of little-endian words to a hex string.\n keep\n */\nfunction binl2hex(binarray)\n{\n var hex_tab = hexcase ? \"0123456789ABCDEF\" : \"0123456789abcdef\";\n var str = \"\";\n for(var i = 0; i < binarray.length * 4; i++)\n {\n str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +\n hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);\n }\n return str;\n}\n\n/*\n * Convert an array of little-endian words to a base-64 string\n */\nfunction binl2b64(binarray)\n{\n var tab = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n var str = \"\";\n for(var i = 0; i < binarray.length * 4; i += 3)\n {\n var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)\n | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )\n | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);\n for(var j = 0; j < 4; j++)\n {\n if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;\n else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);\n }\n }\n return str;\n}\n if (doc.type == \"comment\") {\n if (doc.commenter && doc.commenter.email && !doc.commenter.gravatar_url) {\n // todo normalize this schema-ness\n doc.commenter.gravatar = hex_md5(doc.commenter.email); \n }\n emit(new Date(doc.created_at), doc);\n }\n};"},"tags":{"map":"function(doc) {\n if(doc.type == \"post\" && doc.tags && doc.tags.length) {\n for(var idx in doc.tags) {\n if (doc.tags[idx]){ \n emit([doc.tags[idx].toLowerCase(), doc.created_at], doc);\n }\n }\n }\n}","reduce":"_count"}},"lists":{"index":"function(head, req) {\n var ddoc = this;\n var Mustache = require(\"lib/mustache\");\n var List = require(\"vendor/couchapp/lib/list\");\n var path = require(\"vendor/couchapp/lib/path\").init(req);\n var Atom = require(\"vendor/couchapp/lib/atom\");\n\n var indexPath = path.list('index','recent-posts',{descending:true, limit:10});\n var feedPath = path.list('index','recent-posts',{descending:true, limit:10, format:\"atom\"});\n var commentsFeed = path.list('comments','comments',{descending:true, limit:10, format:\"atom\"});\n\n var path_parts = req.path;\n // The provides function serves the format the client requests.\n // The first matching format is sent, so reordering functions changes \n // thier priority. In this case HTML is the preferred format, so it comes first.\n provides(\"html\", function() {\n var key = \"\";\n // render the html head using a template\n var stash = {\n header : {\n index : indexPath,\n blogName : ddoc.blog.title,\n feedPath : feedPath,\n commentsFeed : commentsFeed\n },\n scripts : {},\n db : req.path[0],\n design : req.path[2],\n feedPath : feedPath,\n newPostPath : path.show(\"edit\"),\n assets : path.asset(),\n posts : List.withRows(function(row) {\n var post = row.value;\n key = row.key;\n return {\n title : post.title,\n author : post.author,\n date : post.created_at,\n link : path.list('post','post-page', {startkey : [row.id]}),\n has_tags : post.tags ? true : false,\n tags : post.tags && post.tags.map ? post.tags.map(function(tag) {\n var t = tag.toLowerCase();\n return {\n tag : tag,\n link : path.list(\"index\", \"tags\", {\n descending : true, \n reduce : false, \n startkey : [t, {}], \n endkey : [t]\n })\n }\n }) : []\n };\n }),\n older : function() {\n return path.older(key);\n },\n \"5\" : path.limit(5),\n \"10\" : path.limit(10),\n \"25\" : path.limit(25)\n };\n return Mustache.to_html(ddoc.templates.index, stash, ddoc.templates.partials, List.send);\n });\n\n // if the client requests an atom feed and not html, \n // we run this function to generate the feed.\n provides(\"atom\", function() { \n var path = require(\"vendor/couchapp/lib/path\").init(req);\n var markdown = require(\"vendor/couchapp/lib/markdown\");\n var textile = require(\"vendor/textile/textile\");\n\n // we load the first row to find the most recent change date\n var row = getRow();\n \n // generate the feed header\n var feedHeader = Atom.header({\n updated : (row ? new Date(row.value.created_at) : new Date()),\n title : ddoc.blog.title,\n feed_id : path.absolute(indexPath),\n feed_link : path.absolute(feedPath),\n });\n \n // send the header to the client\n send(feedHeader);\n\n // loop over all rows\n if (row) {\n do {\n if (row.value.format == \"markdown\") {\n var html = markdown.encode(row.value.body);\n } else if (row.value.format == \"textile\") {\n var html = textile.encode(row.value.body);\n } else {\n var html = Mustache.escape(row.value.html);\n }\n // generate the entry for this row\n var feedEntry = Atom.entry({\n entry_id : path.absolute('/'+encodeURIComponent(req.info.db_name)+'/'+encodeURIComponent(row.id)),\n title : row.value.title,\n content : html,\n updated : new Date(row.value.created_at),\n author : row.value.author,\n alternate : path.absolute(path.show('post', row.id))\n });\n // send the entry to client\n send(feedEntry);\n } while (row = getRow());\n }\n\n // close the loop after all rows are rendered\n return \"\";\n });\n};","post":"function(head, req) {\n var Mustache = require(\"lib/mustache\");\n var ddoc = this;\n var List = require(\"vendor/couchapp/lib/list\");\n var path = require(\"vendor/couchapp/lib/path\").init(req);\n var markdown = require(\"vendor/couchapp/lib/markdown\");\n var textile = require(\"vendor/textile/textile\");\n\n var indexPath = path.list('index','recent-posts',{descending:true, limit:10});\n var feedPath = path.list('index','recent-posts',{descending:true, limit:10, format:\"atom\"});\n var commentsFeed = path.list('comments','comments',{descending:true, limit:10, format:\"atom\"});\n \n provides(\"html\", function() {\n // get the first row and make sure it's a post\n var post = getRow().value;\n if (post.type != \"post\") {\n throw([\"error\", \"not_found\", \"not a post\"]);\n } else {\n if (post.format == \"markdown\") {\n var html = markdown.encode(post.body);\n } else if (post.format == \"textile\") {\n var html = textile.encode(post.body);\n } else {\n var html = Mustache.escape(post.html);\n }\n\n var stash = {\n header : {\n index : indexPath,\n blogName : ddoc.blog.title,\n feedPath : feedPath,\n commentsFeed : commentsFeed\n },\n scripts : {},\n title : post.title,\n post_id : post._id,\n date : post.created_at,\n html : html,\n comments : List.withRows(function(row) {\n var v = row.value;\n if (v.type != \"comment\") {\n return;\n }\n // keep getting comments until we get to the next post...\n return {\n comment : {\n name : v.commenter.nickname || v.commenter.name,\n url : v.commenter.url,\n avatar : v.commenter.gravatar_url || 'http://www.gravatar.com/avatar/'+v.commenter.gravatar+'.jpg?s=40&d=identicon',\n html : markdown.encode(Mustache.escape(v.comment)),\n created_at : v.created_at\n }\n };\n })\n };\n return Mustache.to_html(ddoc.templates.post, stash, ddoc.templates.partials, List.send); \n }\n });\n}","comments":"function(head, req) {\n var ddoc = this;\n var Mustache = require(\"lib/mustache\");\n var List = require(\"vendor/couchapp/lib/list\");\n var path = require(\"vendor/couchapp/lib/path\").init(req);\n var Atom = require(\"vendor/couchapp/lib/atom\");\n\n var indexPath = path.list('index','recent-posts',{descending:true, limit:10});\n var feedPath = path.list('index','recent-posts',{descending:true, limit:10, format:\"atom\"});\n var commentsFeed = path.list('comments','comments',{descending:true, limit:10, format:\"atom\"});\n\n // if the client requests an atom feed and not html, \n // we run this function to generate the feed.\n provides(\"atom\", function() { \n var path = require(\"vendor/couchapp/lib/path\").init(req);\n var markdown = require(\"vendor/couchapp/lib/markdown\");\n var textile = require(\"vendor/textile/textile\");\n\n // we load the first row to find the most recent change date\n var row = getRow();\n \n // generate the feed header\n var feedHeader = Atom.header({\n updated : (row ? new Date(row.value.created_at) : new Date()),\n title : ddoc.blog.title + \" comments\",\n feed_id : path.absolute(indexPath),\n feed_link : path.absolute(commentsFeed)\n });\n \n // send the header to the client\n send(feedHeader);\n\n // loop over all rows\n if (row) {\n do {\n var v = row.value;\n \n // generate the entry for this row\n var feedEntry = Atom.entry({\n entry_id : path.absolute('/'+encodeURIComponent(req.info.db_name)+'/'+encodeURIComponent(row.id)),\n title : \"comment on \"+v.post_id,\n content : markdown.encode(Mustache.escape(v.comment)),\n updated : new Date(v.created_at),\n author : v.commenter.nickname || v.commenter.name,\n alternate : path.absolute(path.list('post','post-page', {startkey:[v.post_id]}))\n });\n // send the entry to client\n send(feedEntry);\n } while (row = getRow());\n }\n\n // close the loop after all rows are rendered\n return \"\";\n });\n}"},"evently":{"profile":{"profileReady":{"mustache":"\n","selectors":{"#preview":{"click":"function() {\n var f = $(this), app = $$(this).app;\n var Mustache = app.require(\"lib/mustache\");\n var markdown = app.require(\"vendor/couchapp/lib/markdown\");\n\n var c = {\n name : $$(\"#profile\").profile.nickname,\n url : $$(\"#profile\").profile.url,\n avatar : $$(\"#profile\").profile.gravatar_url,\n html : markdown.encode(Mustache.escape($(\"[name=comment]\", f).val())),\n created_at : JSON.parse(JSON.stringify(new Date()))\n };\n \n $(\"#comment-preview\").html(Mustache.to_html(app.ddoc.templates.partials.comment, c));\n};"},"form":{"submit":"function() {\n var f = $(this), app = $$(this).app;\n var newComment = {\n type : \"comment\",\n post_id : app.post_id,\n format : \"markdown\",\n comment : $(\"[name=comment]\", f).val(),\n commenter : $$(\"#profile\").profile,\n created_at : new Date()\n };\n app.db.saveDoc(newComment, {\n success : function(resp) {\n $(\"#new-comment\").html('Success! Your comment has posted.
Refresh the page to see it.
');\n }\n });\n \n return false;\n};"}}},"loggedOut":{"mustache":""}},"account":{"loggedIn":{"data":"function(e, r) {\n var app = $$(this).app;\n var path = app.require(\"vendor/couchapp/lib/path\").init(app.req);\n var data = {\n name : r.userCtx.name,\n uri_name : encodeURIComponent(r.userCtx.name),\n auth_db : encodeURIComponent(r.info.authentication_db) \n };\n if (r.userCtx.roles.indexOf(\"_admin\") != -1 || r.userCtx.roles.indexOf(\"author\") != -1) {\n if (app.req.path.indexOf(\"post-page\") == -1) {\n data.postPath = path.show(\"edit\")+\"/\";\n data.postMessage = \"New post.\";\n } else {\n data.postPath = path.show(\"edit\", app.req.query.startkey[0]);\n data.postMessage = \"Edit this post.\";\n } \n }\n return data;\n}","mustache":"Welcome \n{{name}}! \nLogout?\n{{#postPath}}\n {{postMessage}}\n{{/postPath}}\n"}},"tagcloud":{"_init":{"query":{"group_level":1,"view":"tags"},"data":"function(resp) {\n var app = $$(this).app;\n var path = app.require(\"vendor/couchapp/lib/path\").init(app.req);\n var tags = [];\n resp.rows.forEach(function(r) {\n var tag = r.key[0];\n // todo remove duplication of link definitions\n var link = path.list(\"index\",\"tags\",{\n descending : true, \n reduce : false,\n limit : 10,\n startkey : [tag, {}], \n endkey : [tag]});\n tags.push({\n tag : tag,\n link : link,\n size : (r.value * 2) + 10\n });\n });\n return {\n tags : tags.sort(function(a, b) {\n return a.size < b.size;\n })\n };\n}","mustache":"{{#tags}}\n {{tag}}\n{{/tags}}"}}},"THANKS":"Sofa THANKS\n=====================\n\nA number of people have contributed to Sofa by reporting problems,\nsuggesting improvements, submitting changes or asking hard questions.\n\nSome of these people are:\n\n* Andy Wenk \n* Jan Lehnardt\n* You","validate_doc_update":"function (newDoc, oldDoc, userCtx, secObj) {\n var v = require(\"lib/validate\").init(newDoc, oldDoc, userCtx, secObj);\n\n v.isAuthor = function() {\n return v.isAdmin() || userCtx.roles.indexOf(\"author\") != -1;\n };\n\n // admins or owner can always delete\n if (v.isAdmin()) return true;\n if (((oldDoc && (oldDoc.author == userCtx.name))) && newDoc._deleted) return true;\n\n v.unchanged(\"type\");\n v.unchanged(\"author\");\n v.unchanged(\"created_at\");\n \n if (newDoc.created_at) v.dateFormat(\"created_at\");\n\n // docs with authors can only be saved by their author\n // admin can author anything...\n if (!v.isAdmin() && newDoc.author && newDoc.author != userCtx.name) { \n v.unauthorized(\"Only \"+newDoc.author+\" may edit this document.\");\n }\n \n if (newDoc.type == 'post') {\n if (!v.isAuthor()) {\n v.unauthorized(\"Only authors may edit posts.\");\n }\n v.require(\"created_at\", \"author\", \"body\", \"format\", \"title\");\n } else if (newDoc.type == 'comment') {\n v.require(\"created_at\", \"post_id\", \"comment\", \"format\", \"commenter\");\n v.assert((newDoc.commenter.name || newDoc.commenter.nickname) && (typeof newDoc.commenter.email != \"undefined\"), \n \"Comments must include name and email.\");\n if (newDoc.commenter.url) {\n v.assert(newDoc.commenter.url.match(/^https?:\\/\\/[^.]*\\..*/), \n \"Commenter URL must start with http://.\"); \n }\n }\n}","blog":{"title":"Daytime Running Lights"},"rewrites":[{"to":"_list/index/recent-posts","from":"","query":{"limit":10,"descending":true}},{"to":"script/*","from":"script/*"},{"to":"style/*","from":"style/*"},{"to":"vendor/*","from":"vendor/*"},{"to":"../../*","from":":db/*"}],"lib":{"blog":"exports.slugifyString = function(string) {\n return string.replace(/\\W/g,'-').\n replace(/\\-*$/,'').replace(/^\\-*/,'').\n replace(/\\-{2,}/,'-');\n}","validate":"// a library for validations\n// over time we expect to extract more helpers and move them here.\nexports.init = function(newDoc, oldDoc, userCtx, secObj) {\n var v = {};\n \n v.forbidden = function(message) { \n throw({forbidden : message});\n };\n\n v.unauthorized = function(message) {\n throw({unauthorized : message});\n };\n\n v.assert = function(should, message) {\n if (!should) v.forbidden(message);\n }\n \n v.isAdmin = function() {\n return userCtx.roles.indexOf('_admin') != -1\n };\n\n v.require = function() {\n for (var i=0; i < arguments.length; i++) {\n var field = arguments[i];\n message = \"The '\"+field+\"' field is required.\";\n if (typeof newDoc[field] == \"undefined\") v.forbidden(message);\n };\n };\n\n v.unchanged = function(field) {\n if (oldDoc && oldDoc[field] != newDoc[field]) \n v.forbidden(\"You may not change the '\"+field+\"' field.\");\n };\n\n v.matches = function(field, regex, message) {\n if (!newDoc[field].match(regex)) {\n message = message || \"Format of '\"+field+\"' field is invalid.\";\n v.forbidden(message); \n }\n };\n\n // this ensures that the date will be UTC, parseable, and collate correctly\n v.dateFormat = function(field) {\n message = \"Sorry, '\"+field+\"' is not a valid date format. Try: 2010-02-24T17:00:03.432Z\";\n v.matches(field, /\\d{4}\\-\\d{2}\\-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d*)?Z/, message);\n }\n \n return v;\n};","mustache":"/*\n Shameless port of http://github.com/defunkt/mustache\n by Jan Lehnardt , \n Alexander Lang ,\n Sebastian Cohnen \n\n Thanks @defunkt for the awesome code.\n\n See http://github.com/defunkt/mustache for more info.\n*/\n\nvar Mustache = function() {\n var Renderer = function() {};\n\n Renderer.prototype = {\n otag: \"{{\",\n ctag: \"}}\",\n pragmas: {},\n buffer: [],\n pragmas_parsed: false,\n\n render: function(template, context, partials, in_recursion) {\n // fail fast\n if(template.indexOf(this.otag) == -1) {\n if(in_recursion) {\n return template;\n } else {\n this.send(template);\n }\n }\n\n if(!in_recursion) {\n this.buffer = [];\n }\n\n if(!this.pragmas_parsed) {\n template = this.render_pragmas(template);\n }\n var html = this.render_section(template, context, partials);\n if(in_recursion) {\n return this.render_tags(html, context, partials, in_recursion);\n }\n\n this.render_tags(html, context, partials, in_recursion);\n },\n\n /*\n Sends parsed lines\n */\n send: function(line) {\n if(line != \"\") {\n this.buffer.push(line);\n }\n },\n\n /*\n Looks for %PRAGMAS\n */\n render_pragmas: function(template) {\n this.pragmas_parsed = true;\n // no pragmas\n if(template.indexOf(this.otag + \"%\") == -1) {\n return template;\n }\n\n var that = this;\n var regex = new RegExp(this.otag + \"%([\\\\w_-]+) ?([\\\\w]+=[\\\\w]+)?\"\n + this.ctag);\n return template.replace(regex, function(match, pragma, options) {\n that.pragmas[pragma] = {};\n if(options) {\n var opts = options.split(\"=\");\n that.pragmas[pragma][opts[0]] = opts[1];\n }\n return \"\";\n // ignore unknown pragmas silently\n });\n },\n\n /*\n Tries to find a partial in the global scope and render it\n */\n render_partial: function(name, context, partials) {\n if(typeof(context[name]) != \"object\") {\n throw({message: \"subcontext for '\" + name + \"' is not an object\"});\n }\n if(!partials || !partials[name]) {\n throw({message: \"unknown_partial '\" + name + \"'\"});\n }\n return this.render(partials[name], context[name], partials, true);\n },\n\n /*\n Renders boolean and enumerable sections\n */\n render_section: function(template, context, partials) {\n if(template.indexOf(this.otag + \"#\") == -1) {\n return template;\n }\n var that = this;\n // CSW - Added \"+?\" so it finds the tighest bound, not the widest\n var regex = new RegExp(this.otag + \"\\\\#(.+)\" + this.ctag +\n \"\\\\s*([\\\\s\\\\S]+?)\" + this.otag + \"\\\\/\\\\1\" + this.ctag + \"\\\\s*\", \"mg\");\n\n // for each {{#foo}}{{/foo}} section do...\n return template.replace(regex, function(match, name, content) {\n var value = that.find(name, context);\n if(that.is_array(value)) { // Enumerable, Let's loop!\n return that.map(value, function(row) {\n return that.render(content, that.merge(context,\n that.create_context(row)), partials, true);\n }).join(\"\");\n } else if (that.is_iterator(value)) {\n var result = [];\n var row;\n while (row = value()) {\n result.push(that.render(content, that.merge(context,\n that.create_context(row)), partials, true));\n } // fuck buffering, works for now though.\n return result.join('');\n } else if(value) { // boolean section\n return that.render(content, context, partials, true);\n } else {\n return \"\";\n }\n });\n },\n\n /*\n Replace {{foo}} and friends with values from our view\n */\n render_tags: function(template, context, partials, in_recursion) {\n // tit for tat\n var that = this;\n\n var new_regex = function() {\n return new RegExp(that.otag + \"(=|!|>|\\\\{|%)?([^\\/#]+?)\\\\1?\" +\n that.ctag + \"+\", \"g\");\n };\n\n var regex = new_regex();\n var lines = template.split(\"\\n\");\n for (var i=0; i < lines.length; i++) {\n lines[i] = lines[i].replace(regex, function(match, operator, name) {\n switch(operator) {\n case \"!\": // ignore comments\n return match;\n case \"=\": // set new delimiters, rebuild the replace regexp\n that.set_delimiters(name);\n regex = new_regex();\n return \"\";\n case \">\": // render partial\n return that.render_partial(name, context, partials);\n case \"{\": // the triple mustache is unescaped\n return that.find(name, context);\n default: // escape the value\n return that.escape(that.find(name, context));\n }\n }, this);\n if(!in_recursion) {\n this.send(lines[i]);\n }\n }\n return lines.join(\"\\n\");\n },\n\n set_delimiters: function(delimiters) {\n var dels = delimiters.split(\" \");\n this.otag = this.escape_regex(dels[0]);\n this.ctag = this.escape_regex(dels[1]);\n },\n\n escape_regex: function(text) {\n // thank you Simon Willison\n if(!arguments.callee.sRE) {\n var specials = [\n '/', '.', '*', '+', '?', '|',\n '(', ')', '[', ']', '{', '}', '\\\\'\n ];\n arguments.callee.sRE = new RegExp(\n '(\\\\' + specials.join('|\\\\') + ')', 'g'\n );\n }\n return text.replace(arguments.callee.sRE, '\\\\$1');\n },\n\n /*\n find `name` in current `context`. That is find me a value\n from the view object\n */\n find: function(name, context) {\n name = this.trim(name);\n if(typeof context[name] === \"function\" && !context[name].iterator) {\n return context[name].apply(context);\n }\n if(context[name] !== undefined) {\n return context[name];\n }\n // silently ignore unkown variables\n return \"\";\n },\n\n // Utility methods\n\n /*\n Does away with nasty characters\n */\n escape: function(s) {\n return ((s == null) ? \"\" : s).toString().replace(/[&\"<>\\\\]/g, function(s) {\n switch(s) {\n case \"&\": return \"&\";\n case \"\\\\\": return \"\\\\\\\\\";;\n case '\"': return '\\\"';;\n case \"<\": return \"<\";\n case \">\": return \">\";\n default: return s;\n }\n });\n },\n\n /*\n Merges all properties of object `b` into object `a`.\n `b.property` overwrites a.property`\n */\n merge: function(a, b) {\n var _new = {};\n for(var name in a) {\n if(a.hasOwnProperty(name)) {\n _new[name] = a[name];\n }\n };\n for(var name in b) {\n if(b.hasOwnProperty(name)) {\n _new[name] = b[name];\n }\n };\n return _new;\n },\n\n // by @langalex, support for arrays of strings\n create_context: function(_context) {\n if(this.is_object(_context)) {\n return _context;\n } else if(this.pragmas[\"IMPLICIT-ITERATOR\"]) {\n var iterator = this.pragmas[\"IMPLICIT-ITERATOR\"].iterator || \".\";\n var ctx = {};\n ctx[iterator] = _context\n return ctx;\n }\n },\n\n is_object: function(a) {\n return a && typeof a == \"object\";\n },\n\n is_array: function(a) {\n return Object.prototype.toString.call(a) === '[object Array]';\n },\n\n is_iterator : function(f) {\n return (typeof f === 'function' && f.iterator);\n },\n\n /*\n Gets rid of leading and trailing whitespace\n */\n trim: function(s) {\n return s.replace(/^\\s*|\\s*$/g, \"\");\n },\n\n /*\n Why, why, why? Because IE. Cry, cry cry.\n */\n map: function(array, fn) {\n if (typeof array.map == \"function\") {\n return array.map(fn)\n } else {\n var r = [];\n var l = array.length;\n for(i=0;i\n urls for links (sammy.js)\n login / logout\n (test suite report?)\n couchapp github project","helpers":{"md5":"/*\n * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message\n * Digest Algorithm, as defined in RFC 1321.\n * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.\n * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n * Distributed under the BSD License\n * See http://pajhome.org.uk/crypt/md5 for more info.\n */\n\n/*\n * Configurable variables. You may need to tweak these to be compatible with\n * the server-side, but the defaults work in most cases.\n */\nvar hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */\nvar b64pad = \"\"; /* base-64 pad character. \"=\" for strict RFC compliance */\nvar chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */\n\n/*\n * These are the functions you'll usually want to call\n * They take string arguments and return either hex or base-64 encoded strings\n */\nfunction hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}\nfunction b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}\nfunction str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}\nfunction hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }\nfunction b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }\nfunction str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }\n\n/*\n * Perform a simple self-test to see if the VM is working\n */\nfunction md5_vm_test()\n{\n return hex_md5(\"abc\") == \"900150983cd24fb0d6963f7d28e17f72\";\n}\n\n/*\n * Calculate the MD5 of an array of little-endian words, and a bit length\n keep\n */\nfunction core_md5(x, len)\n{\n /* append padding */\n x[len >> 5] |= 0x80 << ((len) % 32);\n x[(((len + 64) >>> 9) << 4) + 14] = len;\n\n var a = 1732584193;\n var b = -271733879;\n var c = -1732584194;\n var d = 271733878;\n\n for(var i = 0; i < x.length; i += 16)\n {\n var olda = a;\n var oldb = b;\n var oldc = c;\n var oldd = d;\n\n a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);\n d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);\n c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);\n b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);\n a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);\n d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);\n c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);\n b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);\n a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);\n d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);\n c = md5_ff(c, d, a, b, x[i+10], 17, -42063);\n b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);\n a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);\n d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);\n c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);\n b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);\n\n a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);\n d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);\n c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);\n b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);\n a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);\n d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);\n c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);\n b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);\n a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);\n d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);\n c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);\n b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);\n a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);\n d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);\n c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);\n b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);\n\n a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);\n d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);\n c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);\n b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);\n a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);\n d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);\n c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);\n b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);\n a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);\n d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);\n c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);\n b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);\n a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);\n d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);\n c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);\n b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);\n\n a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);\n d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);\n c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);\n b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);\n a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);\n d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);\n c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);\n b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);\n a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);\n d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);\n c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);\n b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);\n a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);\n d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);\n c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);\n b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);\n\n a = safe_add(a, olda);\n b = safe_add(b, oldb);\n c = safe_add(c, oldc);\n d = safe_add(d, oldd);\n }\n return Array(a, b, c, d);\n\n}\n\n/*\n * These functions implement the four basic operations the algorithm uses.\n */\nfunction md5_cmn(q, a, b, x, s, t)\n{\n return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);\n}\nfunction md5_ff(a, b, c, d, x, s, t)\n{\n return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);\n}\nfunction md5_gg(a, b, c, d, x, s, t)\n{\n return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);\n}\nfunction md5_hh(a, b, c, d, x, s, t)\n{\n return md5_cmn(b ^ c ^ d, a, b, x, s, t);\n}\nfunction md5_ii(a, b, c, d, x, s, t)\n{\n return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);\n}\n\n/*\n * Calculate the HMAC-MD5, of a key and some data\n */\nfunction core_hmac_md5(key, data)\n{\n var bkey = str2binl(key);\n if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);\n\n var ipad = Array(16), opad = Array(16);\n for(var i = 0; i < 16; i++)\n {\n ipad[i] = bkey[i] ^ 0x36363636;\n opad[i] = bkey[i] ^ 0x5C5C5C5C;\n }\n\n var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);\n return core_md5(opad.concat(hash), 512 + 128);\n}\n\n/*\n * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n * to work around bugs in some JS interpreters.\n */\nfunction safe_add(x, y)\n{\n var lsw = (x & 0xFFFF) + (y & 0xFFFF);\n var msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n return (msw << 16) | (lsw & 0xFFFF);\n}\n\n/*\n * Bitwise rotate a 32-bit number to the left.\n */\nfunction bit_rol(num, cnt)\n{\n return (num << cnt) | (num >>> (32 - cnt));\n}\n\n/*\n * Convert a string to an array of little-endian words\n * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.\n keep\n */\nfunction str2binl(str)\n{\n var bin = Array();\n var mask = (1 << chrsz) - 1;\n for(var i = 0; i < str.length * chrsz; i += chrsz)\n bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);\n return bin;\n}\n\n/*\n * Convert an array of little-endian words to a string\n */\nfunction binl2str(bin)\n{\n var str = \"\";\n var mask = (1 << chrsz) - 1;\n for(var i = 0; i < bin.length * 32; i += chrsz)\n str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);\n return str;\n}\n\n/*\n * Convert an array of little-endian words to a hex string.\n keep\n */\nfunction binl2hex(binarray)\n{\n var hex_tab = hexcase ? \"0123456789ABCDEF\" : \"0123456789abcdef\";\n var str = \"\";\n for(var i = 0; i < binarray.length * 4; i++)\n {\n str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +\n hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);\n }\n return str;\n}\n\n/*\n * Convert an array of little-endian words to a base-64 string\n */\nfunction binl2b64(binarray)\n{\n var tab = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n var str = \"\";\n for(var i = 0; i < binarray.length * 4; i += 3)\n {\n var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)\n | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )\n | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);\n for(var j = 0; j < 4; j++)\n {\n if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;\n else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);\n }\n }\n return str;\n}"},"couchapp":{"index":"_list/index/recent-posts?descending=true&limit=10","signatures":{"images/icon.png":"8ea16a9f573a8ccf73b9ec3eb4f45710","vendor/couchapp/loader.js":"5c771689c7faebedd7be76f2e1638c6f","script/md5.js":"6d03025f455869185b57b5c138fd1c01","vendor/couchapp/jquery.pathbinder.js":"65ecfa230f539d62f36938aaebed4ac1","script/app.js":"6afed8455f0a6e6c2066bbe10455befc","style/screen.css":"45fdf6d1ee5960f49eed867d02f313f6","script/jquery.scrollTo.js":"14b1a91ee2cf52628dd77a14091fee67","vendor/couchapp/jquery.mustache.js":"0bfbc929b6d5500aacfa860c783550d8","vendor/couchapp/jquery.couch.app.js":"97772894d3feb4310e886c47c34506ca","vendor/couchapp/jquery.evently.js":"428bcff5d4894bb4c2362ecd788f580a","LICENSE.txt":"36d3d5c76a09d7c71d21ba9d8699aebd","vendor/couchapp/jquery.couch.app.util.js":"3dcb7ba87d7eb3bf9dad48acd85355a8","THANKS.txt":"9c68e1f58b9627e92bd16c8cdecc8a0b"},"objects":{"0b16b6ea9e221c0cc407c12e5a2730be":"function(doc) {\n // !code helpers/md5.js\n if (doc.type == \"comment\") {\n if (doc.commenter && doc.commenter.email && !doc.commenter.gravatar_url) {\n // todo normalize this schema-ness\n doc.commenter.gravatar = hex_md5(doc.commenter.email); \n }\n emit(new Date(doc.created_at), doc);\n }\n};","f744f815b2f5e2a06cfd06e4d6f5cd90":"function(doc) {\n // todo make commonjs\n // !code helpers/md5.js\n \n if (doc.type == \"post\") {\n emit([doc._id], doc);\n } else if (doc.type == \"comment\") {\n if (doc.commenter && doc.commenter.email && !doc.commenter.gravatar_url) {\n doc.commenter.gravatar = hex_md5(doc.commenter.email); \n }\n emit([doc.post_id, doc.created_at], doc);\n }\n};"},"manifest":["blog.json","couchapp.json","evently/","evently/account/","evently/account/loggedIn/","evently/account/loggedIn/data.js","evently/account/loggedIn/mustache.html","evently/profile/","evently/profile/loggedOut/","evently/profile/loggedOut/mustache.html","evently/profile/profileReady/","evently/profile/profileReady/mustache.html","evently/profile/profileReady/selectors/","evently/profile/profileReady/selectors/#preview/","evently/profile/profileReady/selectors/#preview/click.js","evently/profile/profileReady/selectors/form/","evently/profile/profileReady/selectors/form/submit.js","evently/tagcloud/","evently/tagcloud/_init/","evently/tagcloud/_init/data.js","evently/tagcloud/_init/mustache.html","evently/tagcloud/_init/query.json","helpers/","helpers/md5.js","lib/","lib/blog.js","lib/mustache.js","lib/validate.js","lists/","lists/comments.js","lists/index.js","lists/post.js","README.md","rewrites.json","shows/","shows/edit.js","shows/post.js","sofa2.txt","templates/","templates/edit.html","templates/index.html","templates/partials/","templates/partials/comment.html","templates/partials/header.html","templates/partials/scripts.html","templates/post.html","THANKS.txt","validate_doc_update.js","vendor/","vendor/couchapp/","vendor/couchapp/evently/","vendor/couchapp/evently/account/","vendor/couchapp/evently/account/_init.js","vendor/couchapp/evently/account/adminParty/","vendor/couchapp/evently/account/adminParty/mustache.html","vendor/couchapp/evently/account/doLogin.js","vendor/couchapp/evently/account/doLogout.js","vendor/couchapp/evently/account/doSignup.js","vendor/couchapp/evently/account/loggedIn/","vendor/couchapp/evently/account/loggedIn/after.js","vendor/couchapp/evently/account/loggedIn/data.js","vendor/couchapp/evently/account/loggedIn/mustache.html","vendor/couchapp/evently/account/loggedIn/selectors.json","vendor/couchapp/evently/account/loggedOut/","vendor/couchapp/evently/account/loggedOut/mustache.html","vendor/couchapp/evently/account/loggedOut/selectors.json","vendor/couchapp/evently/account/loginForm/","vendor/couchapp/evently/account/loginForm/after.js","vendor/couchapp/evently/account/loginForm/mustache.html","vendor/couchapp/evently/account/loginForm/selectors/","vendor/couchapp/evently/account/loginForm/selectors/a[href=#signup].json","vendor/couchapp/evently/account/loginForm/selectors/form/","vendor/couchapp/evently/account/loginForm/selectors/form/submit.js","vendor/couchapp/evently/account/signupForm/","vendor/couchapp/evently/account/signupForm/after.js","vendor/couchapp/evently/account/signupForm/mustache.html","vendor/couchapp/evently/account/signupForm/selectors/","vendor/couchapp/evently/account/signupForm/selectors/a[href=#login].json","vendor/couchapp/evently/account/signupForm/selectors/form/","vendor/couchapp/evently/account/signupForm/selectors/form/submit.js","vendor/couchapp/evently/profile/","vendor/couchapp/evently/profile/loggedIn.js","vendor/couchapp/evently/profile/loggedOut/","vendor/couchapp/evently/profile/loggedOut/after.js","vendor/couchapp/evently/profile/loggedOut/mustache.html","vendor/couchapp/evently/profile/noProfile/","vendor/couchapp/evently/profile/noProfile/data.js","vendor/couchapp/evently/profile/noProfile/mustache.html","vendor/couchapp/evently/profile/noProfile/selectors/","vendor/couchapp/evently/profile/noProfile/selectors/form/","vendor/couchapp/evently/profile/noProfile/selectors/form/submit.js","vendor/couchapp/evently/profile/profileReady/","vendor/couchapp/evently/profile/profileReady/after.js","vendor/couchapp/evently/profile/profileReady/data.js","vendor/couchapp/evently/profile/profileReady/mustache.html","vendor/couchapp/evently/README.md","vendor/couchapp/lib/","vendor/couchapp/lib/atom.js","vendor/couchapp/lib/cache.js","vendor/couchapp/lib/code.js","vendor/couchapp/lib/docform.js","vendor/couchapp/lib/linkup.js","vendor/couchapp/lib/list.js","vendor/couchapp/lib/markdown.js","vendor/couchapp/lib/md5.js","vendor/couchapp/lib/mustache.js","vendor/couchapp/lib/path.js","vendor/couchapp/lib/redirect.js","vendor/couchapp/lib/validate.js","vendor/couchapp/metadata.json","vendor/markdown/","vendor/markdown/lib/","vendor/textile/","vendor/textile/textile.js","views/","views/comments/","views/comments/map.js","views/post-page/","views/post-page/map.js","views/recent-posts/","views/recent-posts/map.js","views/tags/","views/tags/map.js","views/tags/reduce.js"]},"README":"# Sofa: Standalone CouchDB Blog\n\nSofa showcases the [potential of pure CouchDB applications](http://jchris.mfdz.com/code/2008/10/standalone_applications_with_co). It should provide an easy way for people to put thier thoughts online, anywhere there's a running Couch. It's just HTML, JavaScript and the magic of CouchDB.\n\nCurrently supports authoring by anyone with the proper roles, and comments from anyone with a user account.\n\n## Current News\n\nThings are moving crazy fast around here right now as I bring this stuff up to ship-shape for the [CouchDB book](http://books.couchdb.org). I'll be renaming methods and stuff (if I find the time), any API feedback will be appreciated.\n\n## Install CouchDB\n\nYou'll also need CouchDB (verion 0.11 or newer). Once you have that installed and the tests passing, you can install CouchApp\nand the blog software. \n\n## Install CouchApp\n\nCouchApp makes it easy to edit application that are hosted in CouchDB, by keeping a correspondence between a set of files, and a CouchDB design document. You'll use CouchApp to install Sofa in your CouchDB instance.\n\n sudo easy_install couchapp\n\nCouchApp is a set of utilities for developing standalone CouchDB applications You can [learn more about the CouchApp project here](http://github.com/couchapp/couchapp/). Also, [`easy_install` has an unpleasant bug on OSX](http://mail.python.org/pipermail/pythonmac-sig/2008-October/020567.html), so you might end up having to work from git source.\n\n\n### Setup Admin Access\n\nIf you are going to put your blog in public, you'll want to [set up an Admin account (screencast)](http://www.youtube.com/watch?v=oHKvV3Nh-CI).\n\n\n## Install Sofa\n\n git clone git://github.com/jchris/sofa.git\n cd sofa\n couchapp push . http://user:pass@127.0.0.1:5984/myblogdb \n \nYou'll want to edit the HTML and CSS to personalize your site. Don't worry, the markup is pretty basic, so it's easy to rework. Adding new features is just a few lines of JavaScript away.\n\nAnytime you make edits to the on-disk version of Sofa, and want to see them in your browser, just run `couchapp push . http://127.0.0.1:5984/blogdb` again. **You probably want to setup your `.couchapprc` file.** You should read the CouchApp readme to learn about that.\n\nYou can customize the blog title and other stuff in the `blog.json` file.\n\n# Relax\n\n[Visit your new blog.](http://127.0.0.1:5984/blogdb/_design/sofa/_list/index/recent-posts?descending=true&limit=5)","shows":{"edit":"function(doc, req) { \n var ddoc = this;\n var Mustache = require(\"lib/mustache\");\n var path = require(\"vendor/couchapp/lib/path\").init(req);\n\n var indexPath = path.list('index','recent-posts',{descending:true, limit:10});\n var feedPath = path.list('index','recent-posts',{descending:true, limit:10, format:\"atom\"});\n var commentsFeed = path.list('comments','comments',{descending:true, limit:10, format:\"atom\"});\n\n return Mustache.to_html(ddoc.templates.edit, {\n header : {\n index : indexPath,\n blogName : ddoc.blog.title,\n feedPath : feedPath,\n commentsFeed : commentsFeed\n },\n scripts : {},\n doc : doc,\n docid : JSON.stringify((doc && doc._id) || null),\n pageTitle : doc ? \"Edit: \"+doc.title : \"Create a new post\",\n assets : path.asset()\n }, ddoc.templates.partials);\n}","post":"function(doc, req) { \n var path = require(\"vendor/couchapp/lib/path\").init(req);\n var redirect = require(\"vendor/couchapp/lib/redirect\");\n return redirect.permanent(path.list('post','post-page', {startkey : [doc._id]}));\n}"},"_attachments":{"images/icon.png":{"content_type":"image/png","revpos":45,"length":154642,"stub":true},"script/md5.js":{"content_type":"application/javascript","revpos":45,"length":8571,"stub":true},"vendor/couchapp/jquery.pathbinder.js":{"content_type":"application/javascript","revpos":46,"length":4879,"stub":true},"script/app.js":{"content_type":"application/javascript","revpos":45,"length":183,"stub":true},"style/screen.css":{"content_type":"text/css","revpos":45,"length":2134,"stub":true},"vendor/couchapp/loader.js":{"content_type":"application/javascript","revpos":46,"length":457,"stub":true},"vendor/couchapp/jquery.mustache.js":{"content_type":"application/javascript","revpos":46,"length":9466,"stub":true},"vendor/couchapp/jquery.couch.app.js":{"content_type":"application/javascript","revpos":46,"length":7320,"stub":true},"vendor/couchapp/jquery.evently.js":{"content_type":"application/javascript","revpos":46,"length":10851,"stub":true},"script/jquery.scrollTo.js":{"content_type":"application/javascript","revpos":45,"length":2005,"stub":true},"LICENSE.txt":{"content_type":"text/plain","revpos":45,"length":9722,"stub":true},"vendor/couchapp/jquery.couch.app.util.js":{"content_type":"application/javascript","revpos":46,"length":2893,"stub":true},"THANKS.txt":{"content_type":"text/plain","revpos":45,"length":236,"stub":true}}}