Full Code of JacksonTian/ping for AI

master 01850fcb934e cached
32 files
46.6 KB
12.0k tokens
1 requests
Download .txt
Repository: JacksonTian/ping
Branch: master
Commit: 01850fcb934e
Files: 32
Total size: 46.6 KB

Directory structure:
gitextract_4ffgiy3b/

├── README.md
├── app.js
├── asset.js
├── assets/
│   ├── eventproxy.js
│   ├── index.html
│   ├── portal_client.js
│   └── post/
│       └── index.js
├── certs/
│   ├── ping-csr.pem
│   └── ping-key.pem
├── config.js
├── context.js
├── controllers/
│   └── index.js
├── cookie.js
├── framework.js
├── mime.js
├── model.js
├── models/
│   ├── index.js
│   └── post.js
├── package.json
├── partials/
│   ├── comments.view
│   ├── friends.view
│   └── recentPosts.view
├── ping.js
├── portal.js
├── portals/
│   ├── index.portal
│   └── post.portal
├── portalview.js
├── proxy.js
├── server.js
├── session.js
├── utils.js
└── views/
    └── index.html

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
# Hello, Ping.

## 静态文件服务器部分
[用Node.js打造你的静态文件服务器](http://cnodejs.org/blog/?p=3904)

## 动态文件服务器部分
[用Node.js构建动态服务器基础](http://cnodejs.org/blog/?p=4520)


================================================
FILE: app.js
================================================
var PORT = process.argv[2] || 8000;
var http = require("http");
var url = require("url");
var fs = require("fs");
var path = require("path");
var mime = require("./mime").types;
var config = require("./config");
var utils = require("./utils");
var zlib = require("zlib");

var server = http.createServer(function(request, response) {
    response.setHeader("Server", "Node/V5");
    response.setHeader('Accept-Ranges', 'bytes');
    var pathname = url.parse(request.url).pathname;
    if (pathname.slice(-1) === "/") {
        pathname = pathname + config.Welcome.file;
    }
    var realPath = path.join("assets", path.normalize(pathname.replace(/\.\./g, "")));

    var pathHandle = function (realPath) {
        fs.stat(realPath, function (err, stats) {
            if (err) {
                response.writeHead(404, "Not Found", {'Content-Type': 'text/plain'});
                response.write("This request URL " + pathname + " was not found on this server.");
                response.end();
            } else {
                if (stats.isDirectory()) {
                    realPath = path.join(realPath, "/", config.Welcome.file);
                    pathHandle(realPath);
                } else {
                    var ext = path.extname(realPath);
                    ext = ext ? ext.slice(1) : 'unknown';
                    var contentType = mime[ext] || "text/plain";
                    response.setHeader("Content-Type", contentType);

                    var lastModified = stats.mtime.toUTCString();
                    var ifModifiedSince = "If-Modified-Since".toLowerCase();
                    response.setHeader("Last-Modified", lastModified);

                    if (ext.match(config.Expires.fileMatch)) {
                        var expires = new Date();
                        expires.setTime(expires.getTime() + config.Expires.maxAge * 1000);
                        response.setHeader("Expires", expires.toUTCString());
                        response.setHeader("Cache-Control", "max-age=" + config.Expires.maxAge);
                    }

                    if (request.headers[ifModifiedSince] && lastModified == request.headers[ifModifiedSince]) {
                        response.writeHead(304, "Not Modified");
                        response.end();
                    } else {
                        var compressHandle = function (raw, statusCode, reasonPhrase,contentLength) {
                                var stream = raw;
                                var acceptEncoding = request.headers['accept-encoding'] || "";
                                var matched = ext.match(config.Compress.match);

                                if (matched && acceptEncoding.match(/\bgzip\b/)) {
                                    response.setHeader("Content-Encoding", "gzip");
                                    stream = raw.pipe(zlib.createGzip());
                                } else if (matched && acceptEncoding.match(/\bdeflate\b/)) {
                                    response.setHeader("Content-Encoding", "deflate");
                                    stream = raw.pipe(zlib.createDeflate());
                                }
                                else{
                                    response.setHeader('Content-Length',contentLength);
                                }
                                response.writeHead(statusCode, reasonPhrase);
                                stream.pipe(response);
                            };

                        if (request.headers["range"]) {
                            var range = utils.parseRange(request.headers["range"], stats.size);
                            if (range) {
                                response.setHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + stats.size);
                                var raw = fs.createReadStream(realPath, {"start": range.start, "end": range.end});
                                compressHandle(raw, 206, "Partial Content",(range.end - range.start + 1));
                            } else {
                                response.writeHead(416, "Request Range Not Satisfiable");
                                response.end();
                            }
                        } else {
                            var raw = fs.createReadStream(realPath);
                            compressHandle(raw, 200, "Ok",stats.size);
                        }
                    }
                }
            }
        });
    };

    pathHandle(realPath);
});

server.listen(PORT);
console.log("Server running at port: " + PORT + ".");


================================================
FILE: asset.js
================================================
var url = require("url");
var fs = require("fs");
var path = require("path");
var mime = require("./mime").types;
var config = require("./config");
var utils = require("./utils");
var zlib = require("zlib");

var Asset = function () {};

Asset.prototype.dispatch = function (request, response) {
    response.setHeader("Server", "Node/V5");
    response.setHeader('Accept-Ranges', 'bytes');
    var pathname = url.parse(request.url).pathname;
    if (pathname.slice(-1) === "/") {
        pathname = pathname + config.Welcome.file;
    }
    var realPath = path.join("assets", path.normalize(pathname.replace(/\.\./g, "")));

    var pathHandle = function (realPath) {
        fs.stat(realPath, function (err, stats) {
            if (err) {
                response.writeHead(404, "Not Found", {'Content-Type': 'text/plain'});
                response.write("This request URL " + pathname + " was not found on this server.");
                response.end();
            } else {
                if (stats.isDirectory()) {
                    realPath = path.join(realPath, "/", config.Welcome.file);
                    pathHandle(realPath);
                } else {
                    var ext = path.extname(realPath);
                    ext = ext ? ext.slice(1) : 'unknown';
                    var contentType = mime[ext] || "text/plain";
                    response.setHeader("Content-Type", contentType);
                    response.setHeader('Content-Length', stats.size);

                    var lastModified = stats.mtime.toUTCString();
                    var ifModifiedSince = "If-Modified-Since".toLowerCase();
                    response.setHeader("Last-Modified", lastModified);

                    if (ext.match(config.Expires.fileMatch)) {
                        var expires = new Date();
                        expires.setTime(expires.getTime() + config.Expires.maxAge * 1000);
                        response.setHeader("Expires", expires.toUTCString());
                        response.setHeader("Cache-Control", "max-age=" + config.Expires.maxAge);
                    }

                    if (request.headers[ifModifiedSince] && lastModified == request.headers[ifModifiedSince]) {
                        response.writeHead(304, "Not Modified");
                        response.end();
                    } else {
                        var compressHandle = function (raw, statusCode, reasonPhrase) {
                                var stream = raw;
                                var acceptEncoding = request.headers['accept-encoding'] || "";
                                var matched = ext.match(config.Compress.match);

                                if (matched && acceptEncoding.match(/\bgzip\b/)) {
                                    response.setHeader("Content-Encoding", "gzip");
                                    stream = raw.pipe(zlib.createGzip());
                                } else if (matched && acceptEncoding.match(/\bdeflate\b/)) {
                                    response.setHeader("Content-Encoding", "deflate");
                                    stream = raw.pipe(zlib.createDeflate());
                                }
                                response.writeHead(statusCode, reasonPhrase);
                                stream.pipe(response);
                            };

                        if (request.headers["range"]) {
                            var range = utils.parseRange(request.headers["range"], stats.size);
                            if (range) {
                                response.setHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + stats.size);
                                response.setHeader("Content-Length", (range.end - range.start + 1));
                                var raw = fs.createReadStream(realPath, {"start": range.start, "end": range.end});
                                compressHandle(raw, 206);
                            } else {
                                response.removeHeader("Content-Length");
                                response.writeHead(416);
                                response.end();
                            }
                        } else {
                            var raw = fs.createReadStream(realPath);
                            compressHandle(raw, 200);
                        }
                    }
                }
            }
        });
    };

    pathHandle(realPath);
};

exports.Asset = Asset;


================================================
FILE: assets/eventproxy.js
================================================
/*global exports */
/**
 * @fileoverview This file is used for define the EventProxy library.
 * @author <a href="mailto:shyvo1987@gmail.com">Jackson Tian</a>
 * @version 0.1.0
 */
(function () {
    /**
     * @description EventProxy. A module that can be mixed in to *any object* in order to provide it with
     * custom events. You may `bind` or `unbind` a callback function to an event;
     * `trigger`-ing an event fires all callbacks in succession.
     * @constructor
     * @name EventProxy
     * @class EventProxy. An implementation of task/event based asynchronous pattern.
     * @example
     * var render = function (template, resources) {};
     * var proxy = new EventProxy();
     * proxy.assign("template", "l10n", render);
     * proxy.trigger("template", template);
     * proxy.trigger("l10n", resources);
     */
    var EventProxy = function () {
        if (!(this instanceof EventProxy)) {
            return new EventProxy();
        }
        this._callbacks = {};
        this._fired = {};
    };

    /**
     * @description Bind an event, specified by a string name, `ev`, to a `callback` function.
     * Passing `"all"` will bind the callback to all events fired.
     * @memberOf EventProxy#
     * @param {string} eventName Event name.
     * @param {function} callback Callback.
     */
    EventProxy.prototype.addListener = function (ev, callback) {
        this._callbacks = this._callbacks || {};
        this._callbacks[ev] = this._callbacks[ev] || [];
        this._callbacks[ev].push(callback);
        return this;
    };
    EventProxy.prototype.bind = EventProxy.prototype.addListener;
    EventProxy.prototype.on = EventProxy.prototype.addListener;
    EventProxy.prototype.await = EventProxy.prototype.addListener;

    /**
     * @description Remove one or many callbacks. If `callback` is null, removes all
     * callbacks for the event. If `ev` is null, removes all bound callbacks
     * for all events.
     * @memberOf EventProxy#
     * @param {string} eventName Event name.
     * @param {function} callback Callback.
     */
    EventProxy.prototype.removeListener = function (ev, callback) {
        var calls = this._callbacks, i, l;
        if (!ev) {
            this._callbacks = {};
        } else if (calls) {
            if (!callback) {
                calls[ev] = [];
            } else {
                var list = calls[ev];
                if (!list) {
                    return this;
                }
                l = list.length;
                for (i = 0; i < l; i++) {
                    if (callback === list[i]) {
                        list[i] = null;
                        break;
                    }
                }
            }
        }
        return this;
    };
    EventProxy.prototype.unbind = EventProxy.prototype.removeListener;

    /**
     * @description Remove all listeners.
     * It equals unbind(); Just add this API for as same as Event.Emitter.
     * @memberOf EventProxy#
     * @param {string} event Event name.
     */
    EventProxy.prototype.removeAllListeners = function (event) {
        return this.unbind(event);
    };

    /**
     * @description Trigger an event, firing all bound callbacks. Callbacks are passed the
     * same arguments as `trigger` is, apart from the event name.
     * Listening for `"all"` passes the true event name as the first argument.
     * @param {string} eventName Event name.
     * @param {mix} data Pass in data. 
     */
    EventProxy.prototype.trigger = function (eventName, data) {
        var list, calls, ev, callback, args, i, l;
        var both = 2;
        if (!(calls = this._callbacks)) {
            return this;
        }
        while (both--) {
            ev = both ? eventName : 'all';
            list = calls[ev];
            if (list) {
                for (i = 0, l = list.length; i < l; i++) {
                    if (!(callback = list[i])) {
                        list.splice(i, 1); i--; l--;
                    } else {
                        args = both ? Array.prototype.slice.call(arguments, 1) : arguments;
                        callback.apply(this, args);
                    }
                }
            }
        }
        return this;
    };
    EventProxy.prototype.emit = EventProxy.prototype.trigger;
    EventProxy.prototype.fire = EventProxy.prototype.trigger;

    /**
     * @description Bind an event like the bind method, but will remove the listener after it was fired.
     * @param {string} ev Event name.
     * @param {function} callback Callback.
     */
    EventProxy.prototype.once = function (ev, callback) {
        var self = this,
            wrapper = function () {
                callback.apply(self, arguments);
                self.unbind(ev, wrapper);
            };
        this.bind(ev, wrapper);
        return this;
    };
    
    /**
     * @description Bind an event, and trigger it immediately.
     * @param {string} ev Event name.
     * @param {function} callback Callback.
     * @param {mix} data The data that will be passed to calback as arguments.
     */
    EventProxy.prototype.immediate = function (ev, callback, data) {
        this.bind(ev, callback);
        this.trigger(ev, data);
        return this;
    };

    var _assign = function (eventname1, eventname2, cb, once) {
        var proxy = this, length, index = 0, argsLength = arguments.length,
            bind, _all,
            callback, events, isOnce, times = 0, flag = {};

        // Check the arguments length.
        if (argsLength < 3) {
            return this;
        }

        events = Array.prototype.slice.apply(arguments, [0, argsLength - 2]);
        callback = arguments[argsLength - 2];
        isOnce = arguments[argsLength - 1];

        // Check the callback type.
        if (typeof callback !== "function") {
            return this;
        }

        length = events.length;
        bind = function (key) {
            var method = isOnce ? "once" : "bind";
            proxy[method](key, function (data) {
                proxy._fired[key] = proxy._fired[key] || {};
                proxy._fired[key].data = data;
                if (!flag[key]) {
                    flag[key] = true;
                    times++;
                }
            });
        };

        for (index = 0; index < length; index++) {
            bind(events[index]);
        }

        _all = function () {
            if (times < length) {
                return;
            }
            var data = [];
            for (index = 0; index < length; index++) {
                data.push(proxy._fired[events[index]].data);
            }
            if (isOnce) {
                proxy.unbind("all", _all);
            }
            callback.apply(null, data);
        };
        proxy.bind("all", _all);
    };

    /**
     * @description Assign some events, after all events were fired, the callback will be executed once.
     * @example
     * proxy.all(ev1, ev2, callback);
     * proxy.all([ev1, ev2], callback);
     * proxy.all(ev1, [ev2, ev3], callback);
     * @param {string} eventName1 First event name.
     * @param {string} eventName2 Second event name.
     * @param {function} callback Callback, that will be called after predefined events were fired.
     */
    EventProxy.prototype.all = function (eventname1, eventname2, cb) {
        var args = Array.prototype.concat.apply([], arguments);
        args.push(true);
        _assign.apply(this, args);
        return this;
    };
    EventProxy.prototype.assign = EventProxy.prototype.all;

    /**
     * @description Assign some events, after all events were fired, the callback will be executed first time.
     * then any event that predefined be fired again, the callback will executed with the newest data.
     * @example
     * proxy.tail(ev1, ev2, callback);
     * proxy.tail([ev1, ev2], callback);
     * proxy.tail(ev1, [ev2, ev3], callback);
     * @memberOf EventProxy#
     * @param {string} eventName1 First event name.
     * @param {string} eventName2 Second event name.
     * @param {function} callback Callback, that will be called after predefined events were fired.
     */
    EventProxy.prototype.tail = function () {
        var args = Array.prototype.concat.apply([], arguments);
        args.push(false);
        _assign.apply(this, args);
        return this;
    };
    EventProxy.prototype.assignAll = EventProxy.prototype.tail;
    EventProxy.prototype.assignAlways = EventProxy.prototype.tail;

    /**
     * @description The callback will be executed after the event be fired N times.
     * @memberOf EventProxy#
     * @param {string} eventName Event name.
     * @param {number} times N times.
     * @param {function} callback Callback, that will be called after event was fired N times.
     */
    EventProxy.prototype.after = function (eventName, times, callback) {
        var proxy = this,
            firedData = [],
            all;
        all = function (name, data) {
            if (name === eventName) {
                times--;
                firedData.push(data);
                if (times < 1) {
                    proxy.unbind("all", all);
                    callback.apply(null, [firedData]);
                }
            }
        };
        proxy.bind("all", all);
        return this;
    };

    /**
     * @description The callback will be executed after any registered event was fired. It only executed once.
     * @memberOf EventProxy#
     * @param {string} eventName1 Event name.
     * @param {string} eventName2 Event name.
     * @param {function} callback The callback will get a map that has data and eventName attributes.
     */
    EventProxy.prototype.any = function () {
        var proxy = this,
            index,
            _bind,
            len = arguments.length,
            callback = arguments[len - 1],
            events = Array.prototype.slice.apply(arguments, [0, len - 1]),
            count = events.length,
            _eventName = events.join("_");

        proxy.once(_eventName, callback);

        _bind = function (key) {
            proxy.bind(key, function (data) {
                proxy.trigger(_eventName, {"data": data, eventName: key});
            });
        };

        for (index = 0; index < count; index++) {
            _bind(events[index]);
        }
    };

    /**
     * @description The callback will be executed when the evnet name not equals with assigned evnet.
     * @memberOf EventProxy#
     * @param {string} eventName Event name.
     * @param {function} callback Callback.
     */
    EventProxy.prototype.not = function (eventName, callback) {
        var proxy = this;
        proxy.bind("all", function (name, data) {
            if (name !== eventName) {
                callback(data);
            }
        });
    };
    
    /**
     * Create a new EventProxy
     * @example
     *     var ep = EventProxy.create();
     *     ep.assign('user', 'articles', function(user, articles) {
     *       // do something...
     *     });
     * 
     *     // or one line ways: Create EventProxy and Assign
     *     
     *     var ep = EventProxy.create('user', 'articles', function(user, articles) {
     *       // do something...
     *     });
     * 
     * @returns {EventProxy}
     */
    EventProxy.create = function () {
        var ep = new EventProxy();
        if (arguments.length) {
            ep.assign.apply(ep, Array.prototype.slice.call(arguments));
        }
        return ep;
    };

    // Event proxy can be used in browser and Nodejs both.
    if (typeof exports !== "undefined") {
        exports.EventProxy = EventProxy;
    } else {
        this.EventProxy = EventProxy;
    }

}());


================================================
FILE: assets/index.html
================================================
<html>
<body>
<h1>It works!</h1>
</body>
</html>


================================================
FILE: assets/portal_client.js
================================================
(function (global) {
    var Portal = new EventProxy();
    Portal.bigPipe = function (id, html) {
        document.getElementById(id).innerHTML = html;
    };

    global.Portal = Portal;
}(this));

================================================
FILE: assets/post/index.js
================================================
Portal.on("onlineUsers", function (data) {
    setTimeout(function () {
        document.getElementById("onlineUsers").innerHTML = "888人";
    }, 100);
});


================================================
FILE: certs/ping-csr.pem
================================================
-----BEGIN CERTIFICATE REQUEST-----
MIIB1TCCAT4CAQAwfjELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFNoYW5naGFpMREw
DwYDVQQHDAhTaGFuZ2hhaTEOMAwGA1UECgwFQ05vZGUxFTATBgNVBAMMDEphY2tz
b24gVGlhbjEiMCAGCSqGSIb3DQEJARYTc2h5dm8xOTg3QGdtYWlsLmNvbTCBnzAN
BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0mGIYebaRufKjh5sPbeAMi2Y8kuDUfsk
ue7KWdnjQd7ZPsUXEhDaN8uljXuHqMCE9cotjGoMK1uwlIsCiFrzv4zj03VABrkc
YHBIBW9LW7kssNfzM3Qs4smvqBwJ2+zVUN8itFf1PFGwEpyLV+JB6rO25q7Wbkq6
JEmHWAb1Un0CAwEAAaAXMBUGCSqGSIb3DQEJBzEIDAYxMjM0NTYwDQYJKoZIhvcN
AQEFBQADgYEAnkabG4W2k0F0TPAvJtezI/n9qt+2krBG8Zl91l30Ov7wKtv2dimF
K1ET00SxJCpj2ED6wXr2THw6GNHjfc8JcTbLxJtcsiUBbmtUhPt02J1SeRqJfYWm
ssmWlNGhP/JE/+bNvncEX2D0rwuB0wijxbllN8ULQFBJCxhNo6BpaMM=
-----END CERTIFICATE REQUEST-----


================================================
FILE: certs/ping-key.pem
================================================
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDSYYhh5tpG58qOHmw9t4AyLZjyS4NR+yS57spZ2eNB3tk+xRcS
ENo3y6WNe4eowIT1yi2MagwrW7CUiwKIWvO/jOPTdUAGuRxgcEgFb0tbuSyw1/Mz
dCziya+oHAnb7NVQ3yK0V/U8UbASnItX4kHqs7bmrtZuSrokSYdYBvVSfQIDAQAB
AoGBAJo7oq6Tfcapu9fA+f2s/7DJuO046wc5JU2igHqqwG7UH1RjTWyTKkfpZm94
9pWCvncrR4U/YbiPub7MwoiQlUytDdAwEu5i+ME0Pb0LCiSGA6XT+XMOaHXQu8Pp
o320FUUQ19jD4sIC4ZAYw9JIQqnrRRyL5Ldzz7QWWFEpaN5BAkEA/sKC0oCr0KOc
N4M7PmT54p67lCrjp2Q9D8XwGwnD5+dUeEPfa4vIGsoYN5VSkwH8QbbVBK4C7kKW
GbaApZKoZQJBANNnty7y0Ata2lbYy7itm18YQiR3jTa+VKq4FpVHBtUphzDei8zh
zD/UqrQjj5Od0xG5cGJxofkDy348Bs2XRDkCQErvUeWzHVawWUnm2u0+bFYhVJF/
kBjznhZepYJ+e9Zhr/H0HOqYYhKnMTpgPLqrEdUOf1fyC0Cj61zC1tJc8hUCQFQC
BAZRESFiAh++2P3TZ0mbvzT0mRYm/kg1DSxW5D0y2nkuBontNJgs74TUGMsFTYne
ke1c0Iu+2U+ZlO5/7OkCQDmCHHoZy2b2DUaweOdqNIkyqcNLAadJDlcZvN35tvj0
bPRvezY2G7LTcg9j/9jhEMGi9ELEQDzYvwIsNKXO2qk=
-----END RSA PRIVATE KEY-----


================================================
FILE: config.js
================================================
exports.Expires = {
    fileMatch: /^(gif|png|jpg|js|css)$/ig,
    maxAge: 60*60*24*365
};
exports.Compress = {
    match: /css|html/ig
};
exports.Welcome = {
    file: "index.html"
};
exports.Timeout = 20 * 60 * 1000;
exports.Secure = null;


================================================
FILE: context.js
================================================
var path = require("path");
var fs = require("fs");
var footprint = require("footprint");

var Context = function (request, response, session, framework) {
    this.request = request;
    this.response = response;
    this.session = session;
    this.framework = framework;
};
Context.prototype.none = function () {
    this.response.writeHead(204);
    this.response.end();
};
Context.prototype.renderJSON = function (jsonObj) {
    this.response.setHeader("Content-Type", "application/json");
    this.response.writeHead(200);
    this.response.end(JSON.stringify(jsonObj));
};
Context.prototype.redirect = function (url) {
    this.response.setHeader("Location", url);
    this.response.writeHead(301);
    this.response.end();
};
Context.prototype._renderView = function (viewEngine, template, data) {
    var framework = this.framework,
        request = this.request,
        response = this.response;

    try {
        response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
        response.write(viewEngine.template(template, data));
        response.end();
    } catch (ex) {
        console.log(ex.message);
        console.log(ex.stack);
        framework.handler500(request, response, "Parse template error.");
    }
};

Context.prototype.renderView = function (view, data) {
    var context = this,
        framework = context.framework,
        request = context.request,
        response = context.response;

    // Get engine.
    var viewEngine = footprint;

    // Check cache.
    viewEngine._cache = viewEngine._cache || {};
    var template = viewEngine._cache[view];
    if (template) {
        context._renderView(viewEngine, template, data);
    } else {
        var filePath = path.join(__dirname, "views/", view);

        path.exists(filePath, function (exists) {
            if(!exists) {
                framework.handler500(request, response, "This template file doesn't exist.");  
            } else {
                fs.readFile(filePath, "utf8", function(err, file) {  
                    if (err) {
                        framework.handler500(request, response, err);
                    } else {
                        viewEngine._cache[view] = file;
                        context._renderView(viewEngine, file, data);
                    }
                });
            }
        });
    }
};
Context.prototype.renderPartial = Context.prototype.renderView;

exports.Context = Context;

================================================
FILE: controllers/index.js
================================================
var get = exports.get = {};
get.index = function () {
    var response = this.response;
    response.setHeader("Content-Type", "text/html");
    response.writeHead("200");
    response.end("<h1>Hello NodeV5.</h1>\n");
};
get.none = function () {
    this.none();
};
get.json = function () {
    var obj = {"Hello": "world!"};
    this.renderJSON(obj);
};
get.redirect = function () {
    this.redirect("https://github.com/JacksonTian/nodev5");
};
get.render = function () {
    var obj = {"title": "NodeV5"};
    this.renderView("index.html", obj);
};


================================================
FILE: cookie.js
================================================
exports.parse = function (cookies) {
    var map = {};
    var pairs = cookies.split(";");
    pairs.forEach(function (pair) {
        var kv = pair.split("=");
        map[kv[0].trim()] = kv[1] || "";
    });
    return map;
};
exports.stringify = function (cookie) {
    var buffer = [cookie.key, "=", cookie.value];
    if (cookie.expires) {
        buffer.push("; expires=", (new Date(cookie.expires)).toUTCString());
    }
    if (cookie.path) {
        buffer.push("; path=", cookie.path);
    }
    if (cookie.domain) {
        buffer.push("; domain=", cookie.domain);
    }
    if (cookie.secure) {
        buffer.push("; secure");
    }
    if (cookie.httpOnly) {
        buffer.push("; httponly");
    }

    return buffer.join("");
};


================================================
FILE: framework.js
================================================
var http = require("http");
var url = require("url");
var cookie = require("./cookie");
var session = require("./session");
var config = require("./config");
var path = require("path");
var Context = require("./context").Context;

var Framework = function () {
    this.sessionManager = new session.SessionManager(config.Timeout);
};

Framework.prototype.dispatch = function (request, response) {
    if (request.url == "/favicon.ico") {
        response.writeHead(404, "Not Found");
        response.end();
        return;
    }

    var routeInfo = this.route(request.url);
    var controller;
    try {
        controller = require('./controllers/' + routeInfo.controller);
        var method = request.method.toLowerCase() || 'get';
        var action = controller[method] ? controller[method][routeInfo.action] : null;
        if (action) {
            this.enableGet(request, response);
            this.enableCookie(request, response);
            this.enablePost(request, response);
            var curSession = this.enableSession(request, response);
            // Pass request response session and framework into context object.
            var context = new Context(request, response, curSession, this);
            request.on("end", function () {
                action.apply(context, routeInfo.args);
            });
        } else {
            this.handler500(request, response, 'Error: Controller "' + routeInfo.controller + '" without action "' + routeInfo.action + '" for "' + request.method + '" request.');
        }
    } catch (ex) {
        console.log(ex.message);
        console.log(ex.stack);
        this.handler500(request, response, 'Error: Controller "' + routeInfo.controller + '" dosen\'t exsit.');
    }
};


// Add get parse supports
Framework.prototype.enableGet = function () {
    http.IncomingMessage.prototype.get = function (key) {
        if (!this._urlMap) {
            this._urlMap = url.parse(this.url, true);
        }
        return this._urlMap.query[key];
    };
};

// Add cookie parse and set supports
Framework.prototype.enableCookie = function (request, response) {
    http.IncomingMessage.prototype.cookie = function () {
        this.cookie = function (key) {
            if (!this._cookieMap) {
                this._cookieMap = cookie.parse(this.headers.cookie || "");
            }
            return this._cookieMap[key];
        };
    };

    http.ServerResponse.prototype.setCookie = function (cookieObj) {
        if (!this._setCookieMap) {
            this._setCookieMap = {};
        }
        this._setCookieMap[cookieObj.key] = cookie.stringify(cookieObj);
        var returnVal = [];
        for(var key in this._setCookieMap) {
            returnVal.push(this._setCookieMap[key]);
        }

        this.setHeader("Set-Cookie", returnVal.join(", "));
    };
};

// Add post parse supports
Framework.prototype.enablePost = function () {
    http.IncomingMessage.prototype.post = function () {
        if (!this._postMap) {
            this._postMap = qs.parse(this.postData);
        }
        return this._postMap[key];
    };
};

// Recept post body.
Framework.prototype.recept = function (request) {
    if (request.method === "POST") {
        var _postData = "";

        this.on('data', function (chunk) {
            _postData += chunk;
        })
        .on("end", function () {
            request.postData = _postData;
        });
    }
};

// Add session supports
Framework.prototype.enableSession = function (request, response) {
    var sessionManager = this.sessionManager;
    var sessionId = request.cookie(session.SESSIONID_KEY);

    var curSession;
    if (sessionId && (curSession = sessionManager.get(sessionId))) {
        if (sessionManager.isTimeout(curSession)) {
            sessionManager.remove(sessionId);
            curSession = sessionManager.renew(response);
        } else {
            curSession.updateTime();
        }
    } else {
        curSession = sessionManager.renew(response);
    }

    return curSession;
};

Framework.prototype.handler500 = function (request, response, err) {
    response.writeHead(500, {'Content-Type': 'text/plain'});
    response.end(err);
};

Framework.prototype.route = function (requestUrl) {
    // /controller/action/parameter1/parameter2
    var pathname = url.parse(requestUrl).pathname;

    var path = pathname.split("/");
    path.shift(); // Remove the first "/"

    return {
        controller: path[0] || "index",
        action: path[1] || "index",
        args: path.slice(2) || [],
    };
};

exports.Framework = Framework;


================================================
FILE: mime.js
================================================
exports.types =  {
  "css": "text/css",
  "gif": "image/gif",
  "html": "text/html",
  "ico": "image/x-icon",
  "jpeg": "image/jpeg",
  "jpg": "image/jpeg",
  "js": "text/javascript",
  "json": "application/json",
  "pdf": "application/pdf",
  "png": "image/png",
  "svg": "image/svg+xml",
  "swf": "application/x-shockwave-flash",
  "tiff": "image/tiff",
  "txt": "text/plain",
  "wav": "audio/x-wav",
  "wma": "audio/x-ms-wma",
  "wmv": "video/x-ms-wmv",
  "xml": "text/xml"
};


================================================
FILE: model.js
================================================
var Model = function () {
    this.keys = {};
};
Model.prototype.get = function (key, callback) {
    var val = this.keys[key];
    if (val) {
        
    } else {
        if (this.state[key] === "pending") {
            this.on(key, callback);
        } else {
            this.state[key] = "pending";
            // TODO get it.
            this.state[key] = "gotit";
        }
    }
};
Model.prototype.register = function (key, callback) {
    this.keys[key] = callback;
};


================================================
FILE: models/index.js
================================================
module.exports = model = function () {};
model.before = function (callback) {
    setTimeout(function () {
        var data = {
            "title": "用Nodejs打造你的静态文件服务器",
            "content": 'The concept is come from <a href="http://weibo.com/otakustay">otakustay</a>. You can find it <a href="http://weibo.com/2087024342/xADWZc3eX">here</a>.',
            "author": "Jackson Tian",
            "time": "2011-12-12"
        };
        callback(data);
    }, 100);
};


================================================
FILE: models/post.js
================================================
module.exports = model = function () {};
model.before = function (callback) {
    setTimeout(function () {
        var data = {
            "title": "用Nodejs打造你的静态文件服务器",
            "content": '<p>在《The Node Beginner Book》的中文版(<a href="http://nodebeginner.org/index-zh-cn.html">http://nodebeginner.org/index-zh-cn.html</a>)发布之后,获得国内的好评。也有同学觉得这本书略薄,没有包含进阶式的例子。<a href="http://www.weibo.com/n/otakustay">@otakustay</a>同学说:“确实,我的想法是在这之上补一个简单的MVC框架和一个StaticFile+Mimetype+CacheControl机制,可以成为一个更全面的教程”。正巧的是目前我手里的V5项目有一些特殊性:</p>',
            "author": "Jackson",
            "time": '<abbr title="星期五, 十一月 11th, 2011, 5:03 下午">2011 年 11 月 11 日</abbr>',
            "who": "Jackson Tian",
            "user": {"name": "Jackson Tian", "email": "shyvo1987@gmail.com"}
        };
        callback(data);
    }, 100);
};
model.pipe = function (data, callback) {
    setTimeout(function () {
        callback(data.viewName + "'s Pipe Content " + Math.random());
    }, Math.random() * 1000);
};


================================================
FILE: package.json
================================================
{
  "author": "Jackson Tian <shyvo1987@gmail.com> (http://weibo.com/shyvo)",
  "name": "node-ping",
  "description": "Web Framework based on Nodejs.",
  "version": "0.1.0",
  "homepage": "https://github.com/JacksonTian/ping",
  "repository": {
    "type": "git",
    "url": "git://github.com/JacksonTian/ping.git"
  },
  "main": "server.js",
  "scripts": {
    "test": "expresso test/test.js"
  },
  "engines": {
    "node": "0.6.6"
  },
  "dependencies": {},
  "devDependencies": {}
}


================================================
FILE: partials/comments.view
================================================
Comments View
<%=who%>

================================================
FILE: partials/friends.view
================================================
Friends view.

================================================
FILE: partials/recentPosts.view
================================================
Recent Posts view.

================================================
FILE: ping.js
================================================
var http = require("http");
var https = require("https");
var config = require("./config");

exports.createServer = function (framework, options) {
    options = options || config.secure;
    var server = options ? https.createServer(options) : http.createServer();
    server.on("request", function (request, response) {
        framework.dispatch(request, response);
    });

    return server;
};


================================================
FILE: portal.js
================================================
var url = require("url");
var path = require("path");
var fs = require("fs");
var vm = require("vm");
var PortalView = require("./portalview").PortalView;

var Portal = function () {
};
Portal.extension = ".portal";
Portal.templateSettings = {
    evaluate    : /<%([\s\S]+?)%>/g,
    interpolate : /<%=([\s\S]+?)%>/g
};

Portal.preprocess = function (str, sandbox, settings) {
    var c  = settings || Portal.templateSettings;
    try {
        var temp = str.replace(c.interpolate, function (match, code) {
            var script = "view.viewData." + code;
            return vm.runInNewContext(script, sandbox);
            //return sandbox.view.viewData[code] ? sandbox.view.viewData[code] : "The key " + code + " is undefined.";
        }).replace(c.evaluate, function (match, code) {
            console.log(code);
            var result = vm.runInNewContext(code, sandbox);
            //console.log(result);
            return result;
        });
    } catch (ex) {
        return ex.stack;
    }

    return temp;
};

Portal.postprocess = function (str, sandbox, settings) {
    var c  = settings || Portal.templateSettings;
    var temp = str.replace(c.interpolate, function (match, code) {
        return sandbox[code] ? sandbox[code] : "The key " + code + " is undefined.";
    });

    return temp;
};
Portal.prototype.route = function (requestUrl) {
    var portal = requestUrl.split("/")[1];
    var pathname = portal + Portal.extension;
    var realPath = path.join("portals", path.normalize(pathname.replace(/\.\./g, "")));
    return {
        "portal": portal,
        "path": realPath
    };
};
Portal.prototype.dispatch = function (request, response) {
    if (request.url == "/favicon.ico") {
        response.writeHead(404);
        response.end();
        return;
    }

    var routeInfo = this.route(request.url);

    var portalView = new PortalView();
    portalView.all("before", "file", function (viewData, file) {
        console.log("Portal ready.");
        portalView.viewData = viewData;
        var sandbox = {
                "view": portalView
            };

        var preprocessed = Portal.preprocess(file, sandbox);

        portalView.after("partial_end", portalView.partialSeq.length, function () {
            response.writeHead(200);
            response.write(Portal.postprocess(preprocessed, portalView.partialViews));
            console.log("Postprocess done.");
            portalView.fire("postprocess_done");
        });

        portalView.getPartials();
        portalView.getPipes();

        console.log("Preprocess done.");
    });

    portalView.on("postprocess_done", function () {
        portalView.processAjax(response);
        portalView.processPipes(response);
    });

    try {
        var model = new require("./models/" + routeInfo.portal);
        portalView.model = model;
        model.before(function (viewData) {
            portalView.fire("before", viewData);
        });
    } catch (ex) {
        response.writeHead(500);
        response.write(ex.stack);
        response.end("\n");
    }

    fs.readFile(routeInfo.path, function (err, file) {
        if (err) {
            response.writeHead(404, {'Content-Type': 'text/plain'});
            response.write("This request URL " + pathname + " was not found on this server.\n");
            response.end();
        } else {
            portalView.fire("file", file.toString("utf-8"));
        }
    });

};

exports.Portal = Portal;


================================================
FILE: portals/index.portal
================================================
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title><%=title%></title>
</head>
<body>
    <div id="main">
        <h2><%=title%></h2>
        <section>
            <%=content%>
        </section>
        <aside><%=author%> posted on <%=time%></aside>
        <div id="comments">
            <%view.partial("comments");%>
        </div>
    </div>
    <aside id="sidebar">
        <h3>好友</h3>
        <div id="friends">
            <%view.partial("friends");%>
        </div>
        <h3>最近博客</h3>
        <div id="posts">
            <%view.partial("recentPosts");%>
        </div>
        <h3>最近访客</h3>
        <div id="visitors">
            <%view.bigPipe("recentVisitors");%>
        </div>
    </aside>
    <footer>
        当前在线: <%view.ajax("onlineUsers");%>
    </footer>
</body>
</html>


================================================
FILE: portals/post.portal
================================================
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title><%=title%></title>
    <script src="http://localhost:8001/eventproxy.js"></script>
    <script src="http://localhost:8001/portal_client.js"></script>
    <script src="http://localhost:8001/post/index.js"></script>
</head>
<body>
    <div id="main">
        <h2><%=title%></h2>
        <section>
            <%=user.name%>
            <%=user.email%>
            <%=content%>
        </section>
        <aside>By <%=author%> on <%=time%></aside>
        <div id="comments">
            <%view.partial("comments");%>
        </div>
    </div>
    <aside id="sidebar">
        <h3>好友</h3>
        <div id="friends">
            <%view.partial("friends");%>
        </div>
        <h3>最近博客</h3>
        <div id="recentPosts">
            <%view.bigPipe("recentPosts");%>
        </div>
        <h3>最近访客</h3>
        <div id="visitors">
            <%view.bigPipe("visitors");%>
        </div>
    </aside>
    <footer>
        当前在线: <%view.ajax("onlineUsers");%><span id="onlineUsers">loading</span>
    </footer>
</body>
</html>


================================================
FILE: portalview.js
================================================
var util = require("util");
var path = require("path");
var fs = require("fs");
var EventProxy = require("eventproxy").EventProxy;
var footprint = require("footprint");

var PortalView = function () {
    EventProxy.call(this);
    this.ajaxSeq = [];
    this.partialViews = {};
    this.partialSeq = [];
    this.pipeSeq = [];
    this.pipes = [];
};
util.inherits(PortalView, EventProxy);

/**
 * Put partial view into sequence. Replace call with view name in template.
 * After preprocess phase, portal will get all partial views through this sequence.
 * The view name will be replaced in postprocess phase.
 */
PortalView.prototype.partial = function (viewName, data) {
    data = data || this.viewData;
    this.partialSeq.push({"viewName": viewName, "viewData": data});
    return "<%=" + viewName + "%>";
};

/**
 * Put ajax call into sequence. These scripts will were outputed after all partial views outputed.
 */
PortalView.prototype.ajax = function (viewName, data) {
    var script = '<script>\nPortal.fire("' + viewName + '", ' + JSON.stringify(data) + ');\n</script>';
    this.ajaxSeq.push(script);
    return "";
};

/**
 * Put pipe call into sequence. Trigger these calls after preprocess phase.
 */
PortalView.prototype.bigPipe = function (viewName, data) {
    this.pipeSeq.push({"viewName": viewName, "viewData": data});
    return "";
};

/**
 * 
 */
PortalView.prototype.getPartial = function (data) {
    var that = this;
    var viewPath = path.join("partials", data.viewName + ".view");
    fs.readFile(viewPath, function (err, view) {
        if (err) {
            throw err;
        } else {
            console.log(data.viewData);
            var html = footprint.template(view.toString("utf-8"), data.viewData);
            that.partialViews[data.viewName] = html;
            that.fire("partial_end", html);
        }
    });
};

PortalView.prototype.getPartials = function () {
    var that = this;
    this.partialSeq.forEach(function (val) {
        that.getPartial(val);
    });
};


PortalView.prototype.getPipe = function (data) {
    var that = this;
    this.model.pipe(data, function (content) {
        var script = '<script>\nPortal.bigPipe("' + data.viewName + '", "' + content + '");\n</script>';
        that.pipes.push(script);
        that.fire("pipe_end", script);
    });
};

PortalView.prototype.getPipes = function () {
    var that = this;
    this.pipeSeq.forEach(function (val) {
        that.getPipe(val);
    });
};

PortalView.prototype.processAjax = function (response) {
    this.ajaxSeq.forEach(function (script) {
        response.write(script);
    });
};
/**
 * @description 
 */
PortalView.prototype.processPipes = function (response) {
    // Process sequnences
    this.pipes.forEach(function (script) {
        response.write(script);
    });

    // Process coming pipes.
    var times = this.pipeSeq.length - this.pipes.length;
    this.on("pipe_end", function (script) {
        response.write(script);
    });

    this.after("pipe_end", times, function () {
        console.log("Complete.");
        response.end();
    });
};

exports.PortalView = PortalView;

================================================
FILE: proxy.js
================================================
var http = require("http");
var cp = require("child_process");

var map = {
    "www.nodev5.com": "www",
    "assets.nodev5.com": "assets"
};

var fork = function () {
    var worker = cp.fork.apply(cp, arguments);
    worker.on('message', function (message) {
        
    });
    return worker;
};

var workers = {
    www: cp.fork(__dirname + "/asset_app.js", [8001]),
    assets: cp.fork(__dirname + "/v5_app.js", [8002]),
};

var server = http.createServer(function(request, response) {
    // TODO
    switch()
        
    var worker = workers[map[request.headers.host]] || workers["assets"];
    //worker.send("", server._handle);
    // console.log(server);

    // response.writeHead(200);
    // response.end();
});

server.on("connection", function (socket) {
    console.log(socket);
});

server.listen(8080);
console.log("Server runing at port: 80.");


================================================
FILE: server.js
================================================
var http = require("http");
var ping = require("./ping");
var Framework = require("./framework").Framework;
var Asset = require("./asset").Asset;
var Portal = require("./portal").Portal;

var portal = new Portal();
ping.createServer(portal).listen(8000);
console.log("Portal server is running at 8000 port.");

// Static file server.
var asset = new Asset();
ping.createServer(asset).listen(8001);
console.log("Static file server is running at 8001 port.");

// Dynamic handle.
var framework = new Framework();
ping.createServer(framework).listen(8002);
console.log("Dynamic server is running at 8002 port.");

================================================
FILE: session.js
================================================
var Session = function (sessionId) {
    this.sessionId = sessionId;
    this._map = {};
};
Session.prototype.set = function (name, value) {
    this._map[name] = value;
};
Session.prototype.get = function (name) {
    return this._map[name];
};
Session.prototype.remove = function (key) {
    delete this._map[key];
};
Session.prototype.removeAll = function () {
    delete this._map;
    this._map = {};
};
Session.prototype.updateTime = function () {
    this._updateTime = new Date().getTime();
};

var SESSIONID_KEY = exports.SESSIONID_KEY = "session_id";

var SessionManager = function (timeout) {
    this.timeout = timeout;
    this._sessions = {};
};
SessionManager.prototype.renew = function (response) {
    var that = this;
    var sessionId = [new Date().getTime(), Math.round(Math.random() * 1000)].join("");
    var session = new Session(sessionId);
    session.updateTime();
    this._sessions[sessionId] = session;
    var clientTimeout = 30 * 24 * 60 * 60 * 1000;
    var cookie = {key: SESSIONID_KEY, value: sessionId, path: "/", expires: new Date().getTime() + clientTimeout};
    response.setCookie(cookie);
    return session;
};
SessionManager.prototype.get = function (sessionId) {
    return this._sessions[sessionId];
};
SessionManager.prototype.remove = function (sessionId) {
    delete this._sessions[sessionId];
};
SessionManager.prototype.isTimeout = function (session) {
    return (session._updateTime + this.timeout) < new Date().getTime();
};
exports.Session = Session;
exports.SessionManager = SessionManager;


================================================
FILE: utils.js
================================================
exports.parseRange = function (str, size) {
    if (str.indexOf(",") != -1) {
        return;
    }

    var range = str.split("-"),
        start = parseInt(range[0].match(/\d+/)[0], 10),
        end = parseInt(range[1], 10);

    // Case: 100-
    if (isNaN(end)) {
        end = size - 1;
    }

    // Invalid
    if (isNaN(start) || isNaN(end) || start > end || end > size) {
        return;
    }

    return {start: start, end: end};
};


================================================
FILE: views/index.html
================================================
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title><%=title%></title>
</head>
<body>
<h1><%=title%></h1>
</body>
</html>

Download .txt
gitextract_4ffgiy3b/

├── README.md
├── app.js
├── asset.js
├── assets/
│   ├── eventproxy.js
│   ├── index.html
│   ├── portal_client.js
│   └── post/
│       └── index.js
├── certs/
│   ├── ping-csr.pem
│   └── ping-key.pem
├── config.js
├── context.js
├── controllers/
│   └── index.js
├── cookie.js
├── framework.js
├── mime.js
├── model.js
├── models/
│   ├── index.js
│   └── post.js
├── package.json
├── partials/
│   ├── comments.view
│   ├── friends.view
│   └── recentPosts.view
├── ping.js
├── portal.js
├── portals/
│   ├── index.portal
│   └── post.portal
├── portalview.js
├── proxy.js
├── server.js
├── session.js
├── utils.js
└── views/
    └── index.html
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (52K chars).
[
  {
    "path": "README.md",
    "chars": 151,
    "preview": "# Hello, Ping.\n\n## 静态文件服务器部分\n[用Node.js打造你的静态文件服务器](http://cnodejs.org/blog/?p=3904)\n\n## 动态文件服务器部分\n[用Node.js构建动态服务器基础](ht"
  },
  {
    "path": "app.js",
    "chars": 4630,
    "preview": "var PORT = process.argv[2] || 8000;\nvar http = require(\"http\");\nvar url = require(\"url\");\nvar fs = require(\"fs\");\nvar pa"
  },
  {
    "path": "asset.js",
    "chars": 4510,
    "preview": "var url = require(\"url\");\nvar fs = require(\"fs\");\nvar path = require(\"path\");\nvar mime = require(\"./mime\").types;\nvar co"
  },
  {
    "path": "assets/eventproxy.js",
    "chars": 11735,
    "preview": "/*global exports */\n/**\n * @fileoverview This file is used for define the EventProxy library.\n * @author <a href=\"mailto"
  },
  {
    "path": "assets/index.html",
    "chars": 54,
    "preview": "<html>\r\n<body>\r\n<h1>It works!</h1>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "assets/portal_client.js",
    "chars": 205,
    "preview": "(function (global) {\r\n    var Portal = new EventProxy();\r\n    Portal.bigPipe = function (id, html) {\r\n        document.g"
  },
  {
    "path": "assets/post/index.js",
    "chars": 161,
    "preview": "Portal.on(\"onlineUsers\", function (data) {\r\n    setTimeout(function () {\r\n        document.getElementById(\"onlineUsers\")"
  },
  {
    "path": "certs/ping-csr.pem",
    "chars": 712,
    "preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIIB1TCCAT4CAQAwfjELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFNoYW5naGFpMREw\nDwYDVQQHDAhTaGFuZ2h"
  },
  {
    "path": "certs/ping-key.pem",
    "chars": 887,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQDSYYhh5tpG58qOHmw9t4AyLZjyS4NR+yS57spZ2eNB3tk+xRcS\nENo3y6WNe4eowIT1yi2Magw"
  },
  {
    "path": "config.js",
    "chars": 242,
    "preview": "exports.Expires = {\n    fileMatch: /^(gif|png|jpg|js|css)$/ig,\n    maxAge: 60*60*24*365\n};\nexports.Compress = {\n    matc"
  },
  {
    "path": "context.js",
    "chars": 2519,
    "preview": "var path = require(\"path\");\r\nvar fs = require(\"fs\");\r\nvar footprint = require(\"footprint\");\r\n\r\nvar Context = function (r"
  },
  {
    "path": "controllers/index.js",
    "chars": 573,
    "preview": "var get = exports.get = {};\r\nget.index = function () {\r\n    var response = this.response;\r\n    response.setHeader(\"Conte"
  },
  {
    "path": "cookie.js",
    "chars": 746,
    "preview": "exports.parse = function (cookies) {\n    var map = {};\n    var pairs = cookies.split(\";\");\n    pairs.forEach(function (p"
  },
  {
    "path": "framework.js",
    "chars": 4727,
    "preview": "var http = require(\"http\");\r\nvar url = require(\"url\");\r\nvar cookie = require(\"./cookie\");\r\nvar session = require(\"./sess"
  },
  {
    "path": "mime.js",
    "chars": 480,
    "preview": "exports.types =  {\n  \"css\": \"text/css\",\n  \"gif\": \"image/gif\",\n  \"html\": \"text/html\",\n  \"ico\": \"image/x-icon\",\n  \"jpeg\": "
  },
  {
    "path": "model.js",
    "chars": 498,
    "preview": "var Model = function () {\r\n    this.keys = {};\r\n};\r\nModel.prototype.get = function (key, callback) {\r\n    var val = this"
  },
  {
    "path": "models/index.js",
    "chars": 482,
    "preview": "module.exports = model = function () {};\r\nmodel.before = function (callback) {\r\n    setTimeout(function () {\r\n        va"
  },
  {
    "path": "models/post.js",
    "chars": 1003,
    "preview": "module.exports = model = function () {};\r\nmodel.before = function (callback) {\r\n    setTimeout(function () {\r\n        va"
  },
  {
    "path": "package.json",
    "chars": 486,
    "preview": "{\n  \"author\": \"Jackson Tian <shyvo1987@gmail.com> (http://weibo.com/shyvo)\",\n  \"name\": \"node-ping\",\n  \"description\": \"We"
  },
  {
    "path": "partials/comments.view",
    "chars": 22,
    "preview": "Comments View\n<%=who%>"
  },
  {
    "path": "partials/friends.view",
    "chars": 13,
    "preview": "Friends view."
  },
  {
    "path": "partials/recentPosts.view",
    "chars": 18,
    "preview": "Recent Posts view."
  },
  {
    "path": "ping.js",
    "chars": 413,
    "preview": "var http = require(\"http\");\r\nvar https = require(\"https\");\r\nvar config = require(\"./config\");\r\n\r\nexports.createServer = "
  },
  {
    "path": "portal.js",
    "chars": 3579,
    "preview": "var url = require(\"url\");\r\nvar path = require(\"path\");\r\nvar fs = require(\"fs\");\r\nvar vm = require(\"vm\");\r\nvar PortalView"
  },
  {
    "path": "portals/index.portal",
    "chars": 849,
    "preview": "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n    <meta charset=\"utf-8\" />\r\n    <title><%=title%></title>\r\n</head>\r\n<body>\r\n    <div "
  },
  {
    "path": "portals/post.portal",
    "chars": 1137,
    "preview": "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n    <meta charset=\"utf-8\" />\r\n    <title><%=title%></title>\r\n    <script src=\"http://lo"
  },
  {
    "path": "portalview.js",
    "chars": 3245,
    "preview": "var util = require(\"util\");\r\nvar path = require(\"path\");\r\nvar fs = require(\"fs\");\r\nvar EventProxy = require(\"eventproxy\""
  },
  {
    "path": "proxy.js",
    "chars": 866,
    "preview": "var http = require(\"http\");\nvar cp = require(\"child_process\");\n\nvar map = {\n    \"www.nodev5.com\": \"www\",\n    \"assets.nod"
  },
  {
    "path": "server.js",
    "chars": 609,
    "preview": "var http = require(\"http\");\nvar ping = require(\"./ping\");\nvar Framework = require(\"./framework\").Framework;\nvar Asset = "
  },
  {
    "path": "session.js",
    "chars": 1546,
    "preview": "var Session = function (sessionId) {\n    this.sessionId = sessionId;\n    this._map = {};\n};\nSession.prototype.set = func"
  },
  {
    "path": "utils.js",
    "chars": 465,
    "preview": "exports.parseRange = function (str, size) {\r\n    if (str.indexOf(\",\") != -1) {\r\n        return;\r\n    }\r\n\r\n    var range "
  },
  {
    "path": "views/index.html",
    "chars": 141,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\" />\n    <title><%=title%></title>\n</head>\n<body>\n<h1><%=title%></"
  }
]

About this extraction

This page contains the full source code of the JacksonTian/ping GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (46.6 KB), approximately 12.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!