UNPKG

internet-information-services

Version:

internet-information-services

1,567 lines (905 loc) 40.2 kB
"use strict"; var scopePath = {}; exports.setPath = function (path) { ReadOnly(scopePath, "wwwroot", path); }; exports.init = function (opt) { opt = opt || {}; opt.mime = opt.mime || {}; for (var mime in Mime) if (Mime.hasOwnProperty(mime) && !opt.mime.hasOwnProperty(mime)) opt.mime[mime] = Mime[mime]; opt.html = opt.html || '<!DOCTYPE html>\n<html lang="{lang}">\n<head>\n<meta charset="{charset}" />\n<title>{controller} - {action} {filter}</title>\n</head>\n<body>\n\n</body>\n</html>' .format({lang: opt.lang || "zh-cn", charset: opt.charset || "UTF-8"}); if (!fs.existsSync(scopePath.wwwroot + "/wwwroot")) fs.mkdirSync(scopePath.wwwroot + "/wwwroot"); if (!fs.existsSync(scopePath.wwwroot + "/wwwroot/index.html")) fs.appendFile(scopePath.wwwroot + "/wwwroot/index.html", '<!DOCTYPE html>\n<html lang="{lang}">\n<head>\n<meta charset="{charset}" />\n<title>Index</title>\n</head>\n<body>\nIndex\n</body>\n</html>' .format({lang: opt.lang || "zh-cn", charset: opt.charset || "UTF-8"}), function () { }); var tables = []; if (opt.project) buildProject.call(opt, opt.project, tables); if (opt.shared && typeof opt.shared.forEach === "function") buildShared(opt.shared); opt.db = opt.db || {}; createDBServer(opt, tables); opt.db.BreakCursor = {}; return function (request, response) { var scope = { Auth: {}, global: opt.global, isEnd: false }; if (request.headers.cookie) request.headers.cookie.split("; ").forEach(function (cookie) { var arr = cookie.split("="); scope.Auth[arr[0]] = arr[1]; }); scope.Auth.set = function (user, role, time) { setAuth(user, role, response, time); }; scope.Auth.clear = function () { clearAuth(response); }; scope.request = request; scope.response = response; response.headers = {}; var urlObj = url.parse(request.url, true); var routeList = urlObj.pathname.substring(1).toLowerCase().split("/"); scope.project = opt.project; scope.controller = routeList[0]; scope.action = routeList[1]; scope.filter = routeList[2]; scope.id = routeList[3]; scope.method = request.method.toLowerCase(); scope.redirect = function (url) { if (!scope.isEnd) { scope.isEnd = true; response.headers.Location = url; response.writeHead(302, response.headers); response.end(); } }; if (typeof opt.gateway === "function" && opt.gateway(scope) === false) { if (!scope.isEnd) { scope.isEnd = true; response.writeHead(400, response.headers); response.end(); } return; } if (opt.project.hasOwnProperty(scope.controller)) { scope.project = opt.project; scope.query = urlObj.query; switch (scope.method) { case "get": route(scope); break; case "put": case "delete": case "post": var chunks = []; var size = 0; request.on("data", function (chunk) { chunks.push(chunk); size += chunk.length; }); request.on("end", function () { scope.data = parsePost( request.headers["content-type"] || "application/x-www-form-urlencoded", Buffer.concat(chunks, size), scopePath.wwwroot ); route(scope); }); break; default: response.end(); break; } } else { var pathname = scopePath.wwwroot + "/wwwroot" + (urlObj.pathname.length === 1 ? "/index.html" : urlObj.pathname); if (fs.existsSync(pathname)) { var suffix = pathname.substr(pathname.lastIndexOf(".") + 1); response.writeHead(200, {"Content-Type": opt.mime[suffix] ? opt.mime[suffix] : "text/plain"}); fs.createReadStream(pathname).pipe(response); } else { response.writeHead(404, {"Content-Type": "text/html"}); if (fs.existsSync(scopePath.wwwroot + "/views/shared/404.html")) response.write(fs.readFileSync(scopePath.wwwroot + "/views/shared/404.html").toString().replaceAll("{pathname}", pathname.substring(scopePath.wwwroot.length))); } } }; }; function createDBServer(opt, tables) { if (typeof opt.localDB === "string") { var indexeddbjs = require("indexeddb-js"); var sqlite3 = require("sqlite3"); var engine = new sqlite3.Database(scopePath.wwwroot + "/" + opt.localDB + ".sqlite3", sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE); scope = indexeddbjs.makeScope('sqlite3', engine); return IDB(opt.db, opt.localDB, tables); } else if (typeof opt.mongoDB === "string") { return MDB(opt.db, opt.mongoDB, tables); } } var IDB, scope, MDB, ObjectId, database; (function () { var key = "_"; var recent = "-"; function fClone(source, update, target) { var obj = target || {}, timestamp = Date.now(); for (var attr in source) if (Object.hasOwnProperty.call(source, attr)) obj[attr] = source[attr]; obj[key] = source[key] || timestamp; obj[recent] = update ? timestamp : source[recent] || timestamp; return obj; } function fSuccess(target) { if (typeof target.onsuccess === "function") { var f = target.onsuccess; delete target.onsuccess; f.apply(target, [].splice.call(arguments, 1)); } } function fError(target) { console.error([].splice.call(arguments, 1)); if (typeof target.onerror === "function") { var f = target.onerror; delete target.onerror; f.apply(target, [].splice.call(arguments, 1)); } } function addTask(store, data, result) { var request = store.add(fClone(data.shift())); request.onsuccess = function (e) { if (data.length) addTask(store, data, result); else fSuccess(result, e); }; request.onerror = function (e) { fError(result, e); }; } function fStore(store) { return { add: function (data) { var result = {}; if (getType(data).toLowerCase() === "array") { if (data.length) addTask(store, data, result); else fSuccess(result); } else { var request = store.add(fClone(data)); request.onsuccess = function (e) { fSuccess(result, e); }; request.onerror = function (e) { fError(result, e); }; } return result; }, default: function (f) { var result = {}; if (typeof f === "function") { store.openCursor().onsuccess = function (event) { var cursor = event.target.result; if (cursor) { if (f(cursor.value)) { fClone(cursor.value, false, result); ReadOnly(result, "update", function () { var request = store.put(fClone(this, true)); request.onsuccess = function () { fSuccess(result, result); }; request.onerror = function (e) { fError(result, e); }; return this; }); ReadOnly(result, "delete", function () { var r = this; var request = store.delete(r[key]); request.onsuccess = function () { fSuccess(r, r); }; request.onerror = function (e) { fError(r, e); }; return r; }); fSuccess(result, result); } else cursor.continue(); } else fSuccess(result, null); }; } return result; }, where: function (f) { var request = store.openCursor(); var results = []; request.onsuccess = function (event) { var cursor = event.target.result; if (cursor) { var result; if (typeof f === "function") { if (f(cursor.value)) { result = fClone(cursor.value); ReadOnly(result, "update", function () { var request = store.put(fClone(this, true)); request.onsuccess = function () { fSuccess(result, result); }; request.onerror = function (e) { fError(result, e); }; return this; }); ReadOnly(result, "delete", function () { var r = this; var request = store.delete(r[key]); request.onsuccess = function () { fSuccess(r, r); }; request.onerror = function (e) { fError(r, e); }; return r; }); results.push(result); } cursor.continue(); } else { result = fClone(cursor.value); ReadOnly(result, "update", function () { var request = store.put(fClone(this, true)); request.onsuccess = function () { fSuccess(result, result); }; request.onerror = function (e) { fError(result, e); }; return this; }); ReadOnly(result, "delete", function () { var r = this; var request = store.delete(r[key]); request.onsuccess = function () { fSuccess(r, r); }; request.onerror = function (e) { fError(r, e); }; return r; }); results.push(result); cursor.continue(); } } else fSuccess(results, results); }; return results; }, page: function (page, count) { count = count || 20; var request = store.openCursor(); var results = []; var index = 0; request.onsuccess = function (event) { var cursor = event.target.result; var start = page * count; var end = start + count; if (cursor) { index++; if (index > start && index <= end) { var result = fClone(cursor.value); ReadOnly(result, "update", function () { var request = store.put(fClone(this, true)); request.onsuccess = function () { fSuccess(result, result); }; request.onerror = function (e) { fError(result, e); }; return this; }); ReadOnly(result, "delete", function () { var r = this; var request = store.delete(r[key]); request.onsuccess = function () { fSuccess(r, r); }; request.onerror = function (e) { fError(r, e); }; return r; }); results.push(result); } cursor.continue(); } else fSuccess(results, results, index); }; return results; }, count: function () { var request = store.openCursor(); var result = {}; var index = 0; request.onsuccess = function (event) { var cursor = event.target.result; if (cursor) { index++; cursor.continue(); } else fSuccess(result, index); }; return result; } }; } function fComplete(value, collection) { ReadOnly(value, "update", function () { collection.updateOne({_id: ObjectId(this._id)}, {$set: this}, function (err, result) { if (err) fError(value, err); else fSuccess(value, result); }); return this; }); ReadOnly(value, "delete", function () { var r = this; collection.deleteOne({_id: ObjectId(this._id)}, function (err, result) { if (err) fError(r, err); else fSuccess(r, result); }); return r; }); return value; } function fCursor(cursor, f, result, arr, collection) { if (cursor.hasNext() && !cursor.isClosed()) { cursor.next().then(function (value) { if (value === null) { fSuccess(result, arr); return; } var r; if (arr) { if (typeof f === "function") { r = f(value); if (r) { arr.push(fComplete(value, collection)); if (r === BreakCursor) { cursor.close(); fSuccess(result, arr); return; } } } else arr.push(fComplete(value, collection)); fCursor(cursor, f, result, arr, collection); } else { r = f(value); if (r) { cursor.close(); fSuccess(result, fComplete(value, collection)); } else fCursor(cursor, f, result, arr, collection); } }).catch(function (e) { cursor.close(); fError(result, e); }); } else fSuccess(result, arr); } function fCollection(collection) { return { add: function (data) { var result = {}; collection.insert(data, function (err, res) { if (err) fError(result, err); else fSuccess(result, res); }); return result; }, default: function (f) { var result = {}; if (typeof f === "function") { fCursor(collection.find(), f, result, null, collection); } return result; }, where: function (f) { var result = {}; fCursor(collection.find(), f, result, [], collection); return result; }, page: function (page, count) { var result = {}; count = count || 20; var cursor = collection.find(); cursor.skip(page * count).limit(count).toArray().then(function (arr) { cursor.count().then(function (count) { fSuccess(result, arr, count); }).catch(function (e) { fError(result, e); }); }).catch(function (reason) { }); return result; }, count: function () { var result = {}; collection.find().count().then(function (count) { fSuccess(result, count); }).catch(function (e) { fError(result, e); }); return result; } }; } function fContext(db, context) { var transaction = db.transaction(db.objectStoreNames, "readwrite"); [].forEach.call(db.objectStoreNames, function (store) { context[store] = fStore(transaction.objectStore(store)); }); fSuccess(context, db); } IDB = function (context, name, tables) { database = context; name = name || "idb"; var db; var request = scope.indexedDB.open(name), add = [], del = []; request.onsuccess = function () { db = request.result; if (tables && tables.constructor && tables.constructor.name === "Array") { tables.forEach(function (table) { if (db.objectStoreNames.indexOf(table) < 0) add.push(table); }); tables.forEach.call(db.objectStoreNames, function (table) { if (tables.indexOf(table) < 0) del.push(table); }); } else if (db.objectStoreNames.length === 0) { add.push("temp"); } if (add.length + del.length > 0) { db.close(); request = scope.indexedDB.open(name, db.version + 1); request.onsuccess = function (event) { db = event.target.result; fContext(db, context); }; request.onupgradeneeded = function (event) { db = event.target.result; add.forEach(function (store) { db.createObjectStore(store, {keyPath: key}) .createIndex(key, key, {unique: true}); }); del.forEach(function (store) { db.deleteObjectStore(store); }); }; } else fContext(db, context); }; }; MDB = function (context, connStr, tables) { database = context; var mongodb = require("mongodb"); var client = mongodb.MongoClient; ObjectId = mongodb.ObjectId; client.connect(connStr, function (err, client) { if (err) console.error("连接失败!", err); else { var db = client.db(); if (tables && tables.constructor && tables.constructor.name === "Array") { tables.forEach(function (collection) { context[collection] = fCollection(db.collection(collection)); }); } fSuccess(context, db, mongodb); } }); }; })(); function ReadOnly(target, key, value) { if (target !== null && target !== undefined) Object.defineProperty(target, key, { value: value, writable: false, configurable: false }); } function parsePost(enctype, data, staticDir) { var arr = enctype.split(";"); var obj = {}; switch (arr[0]) { case "text/plain": data.toString().split("\r\n").forEach(function (value) { if (value.length) { obj[value.substring(0, value.indexOf("="))] = value.substring(value.indexOf("=") + 1); } }); break; case "application/x-www-form-urlencoded": obj = querystring.parse(data.toString()); break; case "multipart/form-data": var boundary = new Buffer("--" + arr[1].substring(arr[1].indexOf("=") + 1)); var i = data.indexOf(boundary); while (data.indexOf(boundary, i + 1) >= 0) { parsePostData(data.slice(i + boundary.length + 2, data.indexOf(boundary, i + 1)), obj, staticDir); i = data.indexOf(boundary, i + 1); } break; } return obj; } function parsePostData(buffer, obj, staticDir) { var key = new Buffer("\r\n\r\n"); var head = buffer.slice(0, buffer.indexOf(key)).toString(); var body = buffer.slice(buffer.indexOf(key) + 4, buffer.length - 2); key = " name=\""; var i = head.indexOf(key) + key.length; var name = head.substring(i, head.indexOf("\"", i)); obj[name] = {name: name}; key = " filename=\""; if (head.indexOf(key, i) > 0) { i = head.indexOf(key) + key.length; obj[name].filename = head.substring(i, head.indexOf("\"", i)); } key = "Content-Type:"; if (head.indexOf(key, i) > 0) { i = head.indexOf(key) + key.length; obj[name].type = head.substring(i).trim(); } if (obj[name].filename && obj[name].type) { obj[name].data = body; obj[name].save = function (path, filename, sync) { path = String(path || "temp"); if (!fs.existsSync("{0}/wwwroot/{1}".format(staticDir, path))) fs.mkdirSync("{0}/wwwroot/{1}".format(staticDir, path)); if (!filename) { path = "{dir}/{name}.{suffix}" .format({ dir: path, name: this.name, suffix: this.filename.indexOf(".") >= 0 ? this.filename.substring(this.filename.lastIndexOf(".") + 1) : this.type.substring(this.type.indexOf("/") + 1) }) } else if (filename.indexOf(".") < 0) path = "{0}/{1}.{2}".format(path, filename, this.filename.indexOf(".") >= 0 ? this.filename.substring(this.filename.lastIndexOf(".") + 1) : this.type.substring(this.type.indexOf("/") + 1)); else path = "{0}/{1}".format(path, filename); if (sync) fs.writeFileSync("{0}/wwwroot/{1}".format(staticDir, path), this.data); else fs.writeFile("{0}/wwwroot/{1}".format(staticDir, path), this.data, function () { }); return "/" + path; }; } else obj[name] = body.toString(); } function route(scope) { scope.action = scope.action || "index"; scope.send = function (data) { if (!scope.isEnd) { scope.isEnd = true; scope.response.headers["Content-Type"] = scope.response.headers["Content-Type"] || "text/html"; scope.response.writeHead(200, scope.response.headers); scope.response.write(data); scope.response.end(); } }; if (typeof scope.project[scope.controller] === "function") { scope.fn = scope.project[scope.controller]; scope.path = scopePath.wwwroot + "/views/" + scope.controller + "/index.html"; view(scope); } else if (scope.project[scope.controller].hasOwnProperty(scope.action)) { if (typeof scope.project[scope.controller][scope.action] === "function") { scope.fn = scope.project[scope.controller][scope.action]; scope.path = scopePath.wwwroot + "/views/{0}/{1}.html".format(scope.controller, scope.action); view(scope); } else { scope.filter = scope.filter || "index"; if (scope.project[scope.controller][scope.action] && scope.project[scope.controller][scope.action].hasOwnProperty(scope.filter)) { scope.fn = scope.project[scope.controller][scope.action][scope.filter]; scope.path = scopePath.wwwroot + "/views/{0}/{1}/{2}.html".format(scope.controller, scope.action, scope.filter); view(scope); } else if (scope.project[scope.controller][scope.action] === null) { scope.path = scopePath.wwwroot + "/views/{0}/{1}.html".format(scope.controller, scope.action); view(scope); } else { notFound(scope.response, scope.controller + "/" + scope.action + "/" + scope.filter); } } } else { notFound(scope.response, scopePath.wwwroot + "/" + scope.controller + "/" + scope.action); } } function view(scope) { if (database) for (var method in database[scope.controller]) if (database[scope.controller].hasOwnProperty(method)) scope[method] = database[scope.controller][method]; var html = ""; if (fs.existsSync(scope.path)) html = fs.readFileSync(scope.path).toString(); while (html.indexOf("{/") >= 0) { var start = html.indexOf("{/"); var end = html.indexOf("}", start); if (start < end) { var value = html.substring(start, end + 1).trim(); if (value.length > 3) { var key = value.substring(1, value.length - 1); var partial = scopePath.wwwroot + "/views/shared{0}.html".format(key); if (fs.existsSync(partial)) html = html.replaceAll(value, fs.readFileSync(partial).toString()); else html = html.replaceAll(value, "<!-- 模板 {0} 不存在 -->".format(key)); } } } if (typeof scope.fn === "function") { scope.async = function (data, noHTML) { data = data || this; if (noHTML) scope.send(getType(data).toLowerCase() === "string" ? data : JSON.stringify(data)); else if (data) scope.send(script(html, data)); else scope.send(script(html)); return false; }; var result = scope.fn.call(scope, scope); if (result === false) { } else if (result === undefined) { scope.send(script(html, scope)); } else { scope.send(getType(result).toLowerCase() === "string" ? result : JSON.stringify(result)); } } else scope.send(script(html, scope)); } function clearAuth(response) { response.headers["Set-Cookie"] = [ "User=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; samesite=lax", "Role=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; samesite=lax" ]; } function setAuth(user, role, response, time) { time = time || 365; var date = new Date(); date.setTime(date.getTime() + time * 24 * 3600 * 1000); date = date.toGMTString(); var cookies = []; if (user) cookies.push("User={0}; expires={1}; path=/; samesite=lax; httponly".format(user, date)); if (role) cookies.push("Role={0}; expires={1}; path=/; samesite=lax; httponly".format(role, date)); response.headers["Set-Cookie"] = cookies; } function script(html, scope) { var start = "<script server>", end = "<\/script>"; var temp = html; while (temp.indexOf(start) >= 0) { var i = temp.indexOf(start); var code = temp.substring(temp.indexOf(start) + start.length, temp.indexOf(end, i)), oldCode = temp.substring(temp.indexOf(start), temp.indexOf(end, i) + end.length), newCode = ""; temp = temp.substr(temp.indexOf(end, i) + end.length); code.split("\n").forEach(function (line) { line = line.trim(); if (line.length) { switch (line[0]) { case "<": newCode += "scope.__str__+='" + line + "'\n"; break; case "\"": case "'": newCode += "scope.__str__+=" + line + "\n"; break; default: newCode += line + "\n"; break; } } }); scope.__str__ = ""; try { new Function("scope", "document", newCode)(scope, { write: function (str) { scope.__str__ += str; } }); } catch (e) { scope.__str__ = "<!--server script 代码有误:" + e + "-->"; } html = html.replace(oldCode, scope.__str__); delete scope.__str__; } return html.format(scope); } function notFound(response, pathname) { response.writeHead(404, {"Content-Type": "text/html"}); if (fs.existsSync(scopePath.wwwroot + "/views/shared/404.html")) response.write(fs.readFileSync(scopePath.wwwroot + "/views/shared/404.html").toString().replaceAll("{pathname}", pathname)); response.end(); } function buildShared(shared) { shared.push("404"); shared.push("500"); if (!fs.existsSync(scopePath.wwwroot + "/views/shared")) fs.mkdirSync(scopePath.wwwroot + "/views/shared"); shared.forEach(function (partial) { var path = scopePath.wwwroot + "/views/shared/{0}.html".format(partial); var dir = partial.substring(0, partial.lastIndexOf("/")); if (dir.length) { dir = dir.split("/"); var path2 = scopePath.wwwroot + "/views/shared"; for (var i = 0; i < dir.length; i++) { path2 += "/" + dir[i]; if (!fs.existsSync(path2)) fs.mkdirSync(path2); } } if (!fs.existsSync(path)) fs.appendFileSync(path, ""); }); } function buildProject(Project, tables) { var project = {}, controller, action, filter, dir, path; if (!fs.existsSync(scopePath.wwwroot + "/views")) fs.mkdirSync(scopePath.wwwroot + "/views"); for (var Controller in Project) if (Project.hasOwnProperty(Controller)) { controller = Controller.trim().toLowerCase(); tables.push(controller); dir = scopePath.wwwroot + "/views/" + controller; if (!fs.existsSync(dir)) fs.mkdirSync(dir); if (getLen(Project[Controller])) { project[controller] = {}; for (var Action in Project[Controller]) if (Project[Controller].hasOwnProperty(Action)) { action = Action.trim().toLowerCase(); if (getLen(Project[Controller][Action])) { path = "{0}/{1}".format(dir, action); if (!fs.existsSync(path)) fs.mkdirSync(path); project[controller][action] = {}; for (var Filter in Project[Controller][Action]) if (Project[Controller][Action].hasOwnProperty(Filter)) { filter = Filter.trim().toLowerCase(); project[controller][action][filter] = Project[Controller][Action][Filter]; if (!fs.existsSync("{0}/{1}.html".format(path, filter))) fs.appendFileSync("{0}/{1}.html".format(path, filter), this.html.format({ controller: controller, action: action, filter: filter })); } } else { project[controller][action] = Project[Controller][Action]; path = "{0}/{1}.html".format(dir, action); if (!fs.existsSync(path)) fs.appendFileSync(path, this.html.format({controller: controller, action: action})); } } } else { if (typeof Project[Controller] === "function") project[controller] = Project[Controller]; if (!fs.existsSync(dir + "/index.html")) fs.appendFileSync(dir + "/index.html", this.html.format({controller: controller, action: "index"})); } } this.project = project; } function getLen(obj) { var len = 0; for (var attr in obj) if (Object.hasOwnProperty.call(obj, attr)) len++; return len; } function getType(obj) { if (obj && obj.constructor && obj.constructor.name) return obj.constructor.name; var type = Object.prototype.toString.call(obj); return type.substring(type.indexOf(" ") + 1, type.length - 1); } function matchType(obj, type0, type1, type2) { return [].indexOf.call(arguments, getType(obj)) > 0; } function recursionFormat(str, key, obj, count) { if (count < 6) count++; else return str; if (getType(obj).toLowerCase() !== "string" && getLen(obj)) { for (var attr in obj) if (!(attr.length > 1 && attr[0] === "_") && Object.hasOwnProperty.call(obj, attr) && matchType(obj[attr], "String", "Object", "Boolean", "Number", "Array")) str = recursionFormat(str, key + "." + attr, obj[attr], count); } else if (obj !== undefined) str = str.replaceAll("{" + key + "}", obj); return str; } String.prototype.format = function () { if (this.constructor.name !== "String") return; var str = this; for (var i = 0; i < arguments.length; i++) { var obj = arguments[i]; if (getType(obj).toLowerCase() === "object") { for (var attr in obj) if (Object.hasOwnProperty.call(obj, attr) && matchType(obj[attr], "String", "Object", "Boolean", "Number", "Array")) str = recursionFormat(str, attr, obj[attr], 0); } else str = str.replaceAll("{" + i + "}", obj); } return str + ""; }; String.prototype.replaceAll = function (oldStr, newStr) { var str = this; try { oldStr = String(oldStr); newStr = String(newStr); if (newStr.indexOf(oldStr) < 0) while (str.indexOf(oldStr) >= 0) str = str.replace(oldStr, newStr); } catch (e) { return this; } return str; }; Date.prototype.format = function (fmt) { var o = { "M+": this.getMonth() + 1, "d+": this.getDate(), "h+": this.getHours(), "m+": this.getMinutes(), "s+": this.getSeconds(), "q+": Math.floor((this.getMonth() + 3) / 3), "S": this.getMilliseconds() }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return fmt; }; var fs = require("fs"); var url = require("url"); var querystring = require("querystring"); var Mime = { html: "text/html", js: "application/javascript", css: "text/css", json: "application/json", jpg: "image/jpeg", png: "image/png", gif: "image/gif", bmp: "image/bmp" };