<commit_before>var DockerIO = require('docker.io'),
    poolModule = require('generic-pool'),
    util = require('util'),
    fs = require('fs'),
    net = require('net');

// useLevel not currently used
var MAX_USE = 1000;

var STDOUT=1, STDERR=2;
var states = [];
var NEW = 0,
    RETRY = 1,
    WAITING = 2,
    ACCUMULATE = 3,
    FINISHED = 4,
    RECOVERY = 5,
    FAIL = 6;
var stateNames = ['NEW', 'RETRY', 'WAITING', 'ACCUMULATE', 'FINISHED', 'RECOVERY', 'FAIL'];

var ConfigureDocker = function(config){

    var docker = DockerIO(config.dockerOpts);

    function defaultCB(err, job) {
        var result = {
            statusCode: job.statusCode,
            exitCode: job.exitCode,
            stdout: job.stdout,
            stderr: job.stderr
        }
        console.log('Job '+job.id+' finished.  No callback provided');
        console.log('Result:\n', result);
    }

    function _makeRunner(runnerConfig) {

        var options = {
            Image: (config.repo+':'+runnerConfig.image),
            AttachStdin: true,
            AttachStdout: true,
            AttachStderr: true,
            OpenStdin: true,
            Tty: false,
            Env: ["RUNNER="+runnerConfig.language],
            StdinOnce: false,
            Cmd: runnerConfig.cmd
        };

        // Prototype chain is such that job shares all functionality
        var cw = function() {
            this.docker = docker;
        };

        // sets language/cmd/etc
        cw.prototype = runnerConfig;
        cw.prototype.runOpts = options;

        cw.prototype.test = function(finalCB) {
            var runnerThis = this;
            var testFilePath = 'test/'+this.language+'/test.'+this.extension;
            var codeStream = fs.createReadStream(testFilePath);
            fs.stat(testFilePath, function(err, stat) {
                if(err) throw err;
                codeStream.inputSize = stat.size;
                runnerThis.run(codeStream, finalCB);
            });
        };

        cw.prototype.run = function(codeStream, finalCB) {
            this.pool.acquire(function(err, job){
                if(err) throw err;
                job.initialTime = Date.now();
                job.finalCB = finalCB;
                job.injectCodeOrMonitor(codeStream, finalCB);
            });
        };

        // do not call this directly anymore if using pool
        cw.prototype.createJob = function() {

            var _cleanup = function(healthCheck) {
                var job = this;

                if(!!healthCheck) {
                    performHealthCheck(job);
                    return; // we will resume after inspect
                }

                if(job.useLevel < MAX_USE) {
                    job.report('releasing container...');
                    job.stdout = '';
                    job.stderr = '';
                    if(!!job.client) {
                        job.client.destroy();
                        delete job.client;
                    }

                    delete job.injectTime;
                    delete job.solutionTime;
                    delete job.finalCB;
                    delete job.duration;
                    delete job.responseTime;
                    delete job.exitCode;
                    delete job.partial;

                    job.statusCode = 200;
                    job.state = NEW;
                    job.retryCount = 0;
                    job.finalCB = job.defaultCB;

                    job.pool.release(this);
                } else {
                    job.report('removing container at use='+job.useLevel);
                    job.pool.destroy(this);
                }
            };

            var _instrument = function(optMessage) {
                var reportString = optMessage || '';
                if(!!this.initialTime) {
                    this.curTime = this.curTime || this.initialTime;
                    var now = Date.now();
                    var reportString = util.format('total=%d block=%d %s',
                            (now-this.initialTime), (now-this.curTime), reportString);
                    this.curTime = now;
                }

                this.report(reportString);
            }

            var _report = function(optMessage) {
                var state = this.state >= WAITING && this.retryCount > 0 ?
                    util.format('%s (RETRY #%d)', stateNames[this.state], this.retryCount) : stateNames[this.state];
                var id = !!this.id ? this.id.substring(0,13) : 'NONE';
                console.log('job %s: %s %s', id, state, optMessage);
            }

            var job = function(){

                // ==========
                // SOCKET FIX
                this.oClient = undefined;
                // change to iClient?
                this.Client = undefined;
                // ==========

                this.id = undefined;
                this.stdout = '';
                this.stderr = '';
                this.state = NEW;
                this.useLevel = 0;
                this.retryCount = 0;
                this.logBytes = 0;
                this.statusCode = 200;
                this.exitCode = undefined;
                this.duration = null;
                this.initialTime = undefined;
                this.curTime = undefined;
                this.injectCodeOrMonitor = _injectCodeOrMonitor;
                this.finalCB = defaultCB;
                this.instrument = _instrument;
                this.report = _report;
                this.cleanup = _cleanup;
            }
            job.prototype = this;

            return new job();
        }

        function attachStdListener(job) {

            var onData = function (data) {
                if(job.state === NEW) return;

                //job.report('oClient data received ' + data);
                data.toString(); // read from buffer
                job.report(util.format('%s data received - length: %d',
                        this.name, data.length));

                if(!job.partial || !job.partial.cur) {
                    job.report('checking header');
                    data = consumeHeader(job, data);
                } else job.report('ignoring header');

                job.state = ACCUMULATE;
                try {
                    var goodJSON = false;
                    var looksComplete = extractPayload(job, data);
                    if(looksComplete) {
                        if(!!job.partial.out) {
                            try {
                                goodJSON = parseJSON(job, job.partial.out)
                            } catch(ex) {
                                // more data is probably on the wire
                                job.report('parse failed: '+ex);
                                delete job.partial.cur;
                            }

                            if(goodJSON) {
                                job.duration = (Date.now() - job.injectTime);
                                job.state = FINISHED;
                                job.finalCB(null, job);
                            }

                        } else if(!!job.partial.stderr) {
                            job.statusCode = 500;
                            job.exitCode = -1;
                            job.state = FAIL;
                            job.stderr = job.partial.stderr;
                        }
                    }
                } catch(extractException){
                    job.statusCode = 500;
                    job.exitCode = -1;
                    job.state = FAIL;
                    job.report('Sending 500 to client: '+extractException);
                    job.finalCB(extractException, job);
                }
            };

            var oClient = getClientForContainer(job, true, { data: onData });
        }

        var thisRunner = new cw();
        if(!!runnerConfig.pool) {
            thisRunner.pool = poolModule.Pool({
                name: 'docker-' + thisRunner.image + '-pool',
                create: function(callback) {
                    var job = thisRunner.createJob();
                    thisRunner.docker.containers.create(thisRunner.runOpts, function(err, res) {
                        if(!err) {
                            if(!!res.Id) {
                                job.id = res.Id;
                                thisRunner.docker.containers.start(job.id, function(err, result) {
                                   if(err) throw err;
                                   attachStdListener(job);
                                   callback(job);
                                });
                            } else callback(new Error('No ID returned from docker create'), null);
                        } else callback(err, null);
                    });

                },
                destroy: function(job) {
                    job.report('self destruct');
                    // TODO make synchronous, but handle requests-in-progress
                    // try setTimeout so pool can get back to business
                    setTimeout(function() {
                        job.docker.containers.kill(job.id, function(err) {
                            if(err) {
                                job.report('Container could not be killed', err);
                                // Remote API v0.10 allows forced removal
                                delete job;
                            } else {
                                job.docker.containers.remove(job.id, function(err) {
                                    if(err) job.report('Container could not be removed', err);
                                    delete job;
                                });
                            }
                        });
                    }, 10);
                },
                //idleTimeoutMillis: 9000000,
                refreshIdle: false,
                max: 3,
                min: 1,
                log: false // can also be a function
            });

            // TODO remove all containers from separate list?
            function gracefulExit() {
                thisRunner.pool.drain(function() {
                    thisRunner.pool.destroyAllNow();
                });
            }

            process.on('SIGINT', gracefulExit)
                .on('SIGTERM', gracefulExit);
        }
        return thisRunner;
    }

    // perform health check after timeout
    function performHealthCheck(job) {
        job.instrument('Job failed, inspecting container');

        job.docker.containers.inspect(job.id, function(err, details) {
            if(err) job.report('Health check error', err);

            if(err || !details.State.Running) {
                errMsg = util.format('Health Check: %s', (err? err.message : 'container is not running/responding'));
                job.report(errMsg);
                job.useLevel = MAX_USE;
            }

            job.cleanup();
        });
    }

    function parseJSON(job, payload) {
        //job.report('Attempting to parse json:\n'+payload);
        var json = JSON.parse(payload);
        if(!!json.stdout) job.stdout = json.stdout;
        if(!!json.stderr) job.stderr = json.stderr;
        if(typeof json.exitCode !== 'undefined') job.exitCode = json.exitCode;
        return true;
    }

    // Has side effects!!
    function consumeHeader(job, data) {
        if(!job.partial) job.partial = {out: '', err: ''};
        var cur = {
            type: data.readUInt8(0),
            expected: data.readUInt32BE(4),
            size: 0
        }
        job.report('current type is : '+ cur.type);
        job.report('expected size is : '+ cur.expected);

        var prev = job.partial.cur;

        if(!!prev) {
            if(prev.type !== cur.type)
                job.report(util.format('Stream switching from %d to %d', prev.type, cur.type));

            //if(prev.size === 0 || cur.type > 2) {
            // This was a problem during double recur
            if(cur.type > 2) {
                job.report('Header seems to have been consumed... ignoring "header"');
                return;
            }
        }
        job.partial.cur = cur;
        return data.slice(8, data.length); // remove header
    }

    function extractPayload(job, data) {
        var looksComplete = false;
        var cutoff; // multiplex may cutoff inside a TCP chunk

        if(!job.partial || !job.partial.cur)
            throw new Error('Partial not set');
        var cur = job.partial.cur;

        // if not recur cur.size should be 0
        var L = data.length + cur.size;
        if(cur.expected == L) looksComplete = true;

        var payload = cur.expected >= L ? data.toString('utf8') :
            data.slice(0, cutoff=(cur.expected - cur.size)).toString();

        //job.report('payload set to: '+payload);

        if(cur.type === STDOUT) job.partial.out += payload;
        else if(cur.type === STDERR) job.partial.err += payload;
        else throw new Error('Bad stream type');

        if(cur.expected > L) cur.size += data.length;

        if(cur.expected < L) {
            data = data.slice(cutoff, data.length);
            job.report('recurring due to early payload cutoff');
            job.report('new length is '+data.length);
            data = consumeHeader(job, data);
            looksComplete = extractPayload(job, data); // recur
        }

        return looksComplete;
    }

    // Logs would require a smart extraction + placeholder if ongoing
    function recoverLogs(job, data) {
        var detailStr = util.format("data=%d pointer=%d", data.length, job.logBytes);
        job.instrument("Attempting log recovery: "+detailStr);

        if(data.length < job.logBytes+8) extractPayload(job, data);
        else extractPayload(job, data.slice(job.logBytes));
    }

    function getClientForContainer(job, isOutput, handlers) {
        var name = isOutput ? 'oClient' : 'client'; // for logs

        if(!handlers['data']) throw new Error('data handler not provided');

        var onData = handlers['data'];
        var onError = handlers['error'] || function(err) {
            job.report(util.format('%s socket error: %s', name, err));
        };
        var onRead = handlers['readable'] || function() {
            job.report(util.format('%s socket received readable', name));
        };
        var onFinish = handlers['finish'] || function() {
            job.report(util.format('%s socket finished', name));
        };
        var onEnd = handlers['end'] || function() {
            job.instrument(util.format('%s socket ended', name));
        }

        var newClient = net.connect(config.dockerOpts.port, config.dockerOpts.hostname, function() {
            // only until we verify clojure under load
            // earlier release had problems with gc
            if(isOutput) job.oClient = newClient;
            else job.client = newClient;

            newClient.name = name;

            newClient.on('error', onError);
            newClient.on('readable', onRead);
            newClient.on('data', onData);
            newClient.on('finish', onFinish);
            newClient.on('end', onEnd);

            var sin, sout, serr;
            sin = isOutput ? '0' : '1';
            sout = serr = isOutput ? '1' : '0';

            newClient.write('POST /'+config.dockerOpts.version+'/containers/' + job.id + '/attach?stdin='+sin+'&stdout='+sout+'&stderr='+serr+'&stream=1 HTTP/1.1\r\n' +
                'Content-Type: application/vnd.docker.raw-stream\r\n\r\n');
        });

        return newClient;
    }

    function _injectCodeOrMonitor(codeStream) {
        var self = this;

        var client = net.connect(config.dockerOpts.port, config.dockerOpts.hostname, function() {
            self.client = client;

            client.on('error', function(err) {
               self.finalCB(err, self);
            });

            client.on('data', function(data) {
                self.report('data received ' + data);
                switch(self.state) {
                    case NEW:
                        self.instrument('injecting code');
                        self.injectTime = Date.now();
                        codeStream.pipe(client);
                        break;
                    default:
                        self.
                        break;
                }
            });

            // code has been injected
            client.on('finish', function() {
                self.instrument('client socket finished');
                self.state = WAITING;
                self.client.destroy();
                delete self.client;
                delete client;
            });

            client.on('end', function() {
                self.instrument('client socket ended');
            });

            var sin, sout, serr;
            sin='1';
            sout = serr = '0';

            client.write('POST /'+config.dockerOpts.version+'/containers/' + self.id + '/attach?stdin='+sin+'&stdout='+sout+'&stderr='+serr+'&stream=1 HTTP/1.1\r\n' +
                'Content-Type: application/vnd.docker.raw-stream\r\n\r\n');
        });

        return client;
    }

    return { createRunner: _makeRunner }
};

module.exports = ConfigureDocker;
<commit_msg>fully consolidated socket clients.<commit_after>var DockerIO = require('docker.io'),
    poolModule = require('generic-pool'),
    util = require('util'),
    fs = require('fs'),
    net = require('net');

// useLevel not currently used
var MAX_USE = 1000;

var STDOUT=1, STDERR=2;
var states = [];
var NEW = 0,
    RETRY = 1,
    WAITING = 2,
    ACCUMULATE = 3,
    FINISHED = 4,
    RECOVERY = 5,
    FAIL = 6;
var stateNames = ['NEW', 'RETRY', 'WAITING', 'ACCUMULATE', 'FINISHED', 'RECOVERY', 'FAIL'];

var ConfigureDocker = function(config){

    var docker = DockerIO(config.dockerOpts);

    function defaultCB(err, job) {
        var result = {
            statusCode: job.statusCode,
            exitCode: job.exitCode,
            stdout: job.stdout,
            stderr: job.stderr
        }
        console.log('Job '+job.id+' finished.  No callback provided');
        console.log('Result:\n', result);
    }

    function _makeRunner(runnerConfig) {

        var options = {
            Image: (config.repo+':'+runnerConfig.image),
            AttachStdin: true,
            AttachStdout: true,
            AttachStderr: true,
            OpenStdin: true,
            Tty: false,
            Env: ["RUNNER="+runnerConfig.language],
            StdinOnce: false,
            Cmd: runnerConfig.cmd
        };

        // Prototype chain is such that job shares all functionality
        var cw = function() {
            this.docker = docker;
        };

        // sets language/cmd/etc
        cw.prototype = runnerConfig;
        cw.prototype.runOpts = options;

        cw.prototype.test = function(finalCB) {
            var runnerThis = this;
            var testFilePath = 'test/'+this.language+'/test.'+this.extension;
            var codeStream = fs.createReadStream(testFilePath);
            fs.stat(testFilePath, function(err, stat) {
                if(err) throw err;
                codeStream.inputSize = stat.size;
                runnerThis.run(codeStream, finalCB);
            });
        };

        cw.prototype.run = function(codeStream, finalCB) {
            this.pool.acquire(function(err, job){
                if(err) throw err;
                job.initialTime = Date.now();
                job.finalCB = finalCB;
                job.injectCodeOrMonitor(codeStream, finalCB);
            });
        };

        // do not call this directly anymore if using pool
        cw.prototype.createJob = function() {

            var _cleanup = function(healthCheck) {
                var job = this;

                if(!!healthCheck) {
                    performHealthCheck(job);
                    return; // we will resume after inspect
                }

                if(job.useLevel < MAX_USE) {
                    job.report('releasing container...');
                    job.stdout = '';
                    job.stderr = '';
                    if(!!job.client) {
                        job.client.destroy();
                        delete job.client;
                    }

                    delete job.injectTime;
                    delete job.solutionTime;
                    delete job.finalCB;
                    delete job.duration;
                    delete job.responseTime;
                    delete job.exitCode;
                    delete job.partial;

                    job.statusCode = 200;
                    job.state = NEW;
                    job.retryCount = 0;
                    job.finalCB = job.defaultCB;

                    job.pool.release(this);
                } else {
                    job.report('removing container at use='+job.useLevel);
                    job.pool.destroy(this);
                }
            };

            var _instrument = function(optMessage) {
                var reportString = optMessage || '';
                if(!!this.initialTime) {
                    this.curTime = this.curTime || this.initialTime;
                    var now = Date.now();
                    var reportString = util.format('total=%d block=%d %s',
                            (now-this.initialTime), (now-this.curTime), reportString);
                    this.curTime = now;
                }

                this.report(reportString);
            }

            var _report = function(optMessage) {
                var state = this.state >= WAITING && this.retryCount > 0 ?
                    util.format('%s (RETRY #%d)', stateNames[this.state], this.retryCount) : stateNames[this.state];
                var id = !!this.id ? this.id.substring(0,13) : 'NONE';
                console.log('job %s: %s %s', id, state, optMessage);
            }

            var job = function(){

                // ==========
                // SOCKET FIX
                this.oClient = undefined;
                // change to iClient?
                this.Client = undefined;
                // ==========

                this.id = undefined;
                this.stdout = '';
                this.stderr = '';
                this.state = NEW;
                this.useLevel = 0;
                this.retryCount = 0;
                this.logBytes = 0;
                this.statusCode = 200;
                this.exitCode = undefined;
                this.duration = null;
                this.initialTime = undefined;
                this.curTime = undefined;
                this.injectCodeOrMonitor = _injectCodeOrMonitor;
                this.finalCB = defaultCB;
                this.instrument = _instrument;
                this.report = _report;
                this.cleanup = _cleanup;
            }
            job.prototype = this;

            return new job();
        }

        function attachStdListener(job) {

            var onData = function (data) {
                if(job.state === NEW) return;

                //job.report('oClient data received ' + data);
                data.toString(); // read from buffer
                job.report(util.format('%s data received - length: %d',
                        this.name, data.length));

                if(!job.partial || !job.partial.cur) {
                    job.report('checking header');
                    data = consumeHeader(job, data);
                } else job.report('ignoring header');

                job.state = ACCUMULATE;
                try {
                    var goodJSON = false;
                    var looksComplete = extractPayload(job, data);
                    if(looksComplete) {
                        if(!!job.partial.out) {
                            try {
                                goodJSON = parseJSON(job, job.partial.out)
                            } catch(ex) {
                                // more data is probably on the wire
                                job.report('parse failed: '+ex);
                                delete job.partial.cur;
                            }

                            if(goodJSON) {
                                job.duration = (Date.now() - job.injectTime);
                                job.state = FINISHED;
                                job.finalCB(null, job);
                            }

                        } else if(!!job.partial.stderr) {
                            job.statusCode = 500;
                            job.exitCode = -1;
                            job.state = FAIL;
                            job.stderr = job.partial.stderr;
                        }
                    }
                } catch(extractException){
                    job.statusCode = 500;
                    job.exitCode = -1;
                    job.state = FAIL;
                    job.report('Sending 500 to client: '+extractException);
                    job.finalCB(extractException, job);
                }
            };

            var oClient = getClientForContainer(job, true, { data: onData });
        }

        var thisRunner = new cw();
        if(!!runnerConfig.pool) {
            thisRunner.pool = poolModule.Pool({
                name: 'docker-' + thisRunner.image + '-pool',
                create: function(callback) {
                    var job = thisRunner.createJob();
                    thisRunner.docker.containers.create(thisRunner.runOpts, function(err, res) {
                        if(!err) {
                            if(!!res.Id) {
                                job.id = res.Id;
                                thisRunner.docker.containers.start(job.id, function(err, result) {
                                   if(err) throw err;
                                   attachStdListener(job);
                                   callback(job);
                                });
                            } else callback(new Error('No ID returned from docker create'), null);
                        } else callback(err, null);
                    });

                },
                destroy: function(job) {
                    job.report('self destruct');
                    // TODO make synchronous, but handle requests-in-progress
                    // try setTimeout so pool can get back to business
                    setTimeout(function() {
                        job.docker.containers.kill(job.id, function(err) {
                            if(err) {
                                job.report('Container could not be killed', err);
                                // Remote API v0.10 allows forced removal
                                delete job;
                            } else {
                                job.docker.containers.remove(job.id, function(err) {
                                    if(err) job.report('Container could not be removed', err);
                                    delete job;
                                });
                            }
                        });
                    }, 10);
                },
                //idleTimeoutMillis: 9000000,
                refreshIdle: false,
                max: 3,
                min: 1,
                log: false // can also be a function
            });

            // TODO remove all containers from separate list?
            function gracefulExit() {
                thisRunner.pool.drain(function() {
                    thisRunner.pool.destroyAllNow();
                });
            }

            process.on('SIGINT', gracefulExit)
                .on('SIGTERM', gracefulExit);
        }
        return thisRunner;
    }

    // perform health check after timeout
    function performHealthCheck(job) {
        job.instrument('Job failed, inspecting container');

        job.docker.containers.inspect(job.id, function(err, details) {
            if(err) job.report('Health check error', err);

            if(err || !details.State.Running) {
                errMsg = util.format('Health Check: %s', (err? err.message : 'container is not running/responding'));
                job.report(errMsg);
                job.useLevel = MAX_USE;
            }

            job.cleanup();
        });
    }

    function parseJSON(job, payload) {
        //job.report('Attempting to parse json:\n'+payload);
        var json = JSON.parse(payload);
        if(!!json.stdout) job.stdout = json.stdout;
        if(!!json.stderr) job.stderr = json.stderr;
        if(typeof json.exitCode !== 'undefined') job.exitCode = json.exitCode;
        return true;
    }

    // Has side effects!!
    function consumeHeader(job, data) {
        if(!job.partial) job.partial = {out: '', err: ''};
        var cur = {
            type: data.readUInt8(0),
            expected: data.readUInt32BE(4),
            size: 0
        }
        job.report('current type is : '+ cur.type);
        job.report('expected size is : '+ cur.expected);

        var prev = job.partial.cur;

        if(!!prev) {
            if(prev.type !== cur.type)
                job.report(util.format('Stream switching from %d to %d', prev.type, cur.type));

            //if(prev.size === 0 || cur.type > 2) {
            // This was a problem during double recur
            if(cur.type > 2) {
                job.report('Header seems to have been consumed... ignoring "header"');
                return;
            }
        }
        job.partial.cur = cur;
        return data.slice(8, data.length); // remove header
    }

    function extractPayload(job, data) {
        var looksComplete = false;
        var cutoff; // multiplex may cutoff inside a TCP chunk

        if(!job.partial || !job.partial.cur)
            throw new Error('Partial not set');
        var cur = job.partial.cur;

        // if not recur cur.size should be 0
        var L = data.length + cur.size;
        if(cur.expected == L) looksComplete = true;

        var payload = cur.expected >= L ? data.toString('utf8') :
            data.slice(0, cutoff=(cur.expected - cur.size)).toString();

        //job.report('payload set to: '+payload);

        if(cur.type === STDOUT) job.partial.out += payload;
        else if(cur.type === STDERR) job.partial.err += payload;
        else throw new Error('Bad stream type');

        if(cur.expected > L) cur.size += data.length;

        if(cur.expected < L) {
            data = data.slice(cutoff, data.length);
            job.report('recurring due to early payload cutoff');
            job.report('new length is '+data.length);
            data = consumeHeader(job, data);
            looksComplete = extractPayload(job, data); // recur
        }

        return looksComplete;
    }

    // Logs would require a smart extraction + placeholder if ongoing
    function recoverLogs(job, data) {
        var detailStr = util.format("data=%d pointer=%d", data.length, job.logBytes);
        job.instrument("Attempting log recovery: "+detailStr);

        if(data.length < job.logBytes+8) extractPayload(job, data);
        else extractPayload(job, data.slice(job.logBytes));
    }

    function getClientForContainer(job, isOutput, handlers) {
        var name = isOutput ? 'oClient' : 'client'; // for logs

        if(!handlers['data']) throw new Error('data handler not provided');

        var onData = handlers['data'];
        var onError = handlers['error'] || function(err) {
            job.report(util.format('%s socket error: %s', name, err));
        };
        var onRead = handlers['readable'] || function() {
            job.report(util.format('%s socket received readable', name));
        };
        var onFinish = handlers['finish'] || function() {
            job.report(util.format('%s socket finished', name));
        };
        var onEnd = handlers['end'] || function() {
            job.instrument(util.format('%s socket ended', name));
        }

        var newClient = net.connect(config.dockerOpts.port, config.dockerOpts.hostname, function() {
            // only until we verify clojure under load
            // earlier release had problems with gc
            if(isOutput) job.oClient = newClient;
            else job.client = newClient;

            newClient.name = name;

            newClient.on('error', onError);
            newClient.on('readable', onRead);
            newClient.on('data', onData);
            newClient.on('finish', onFinish);
            newClient.on('end', onEnd);

            var sin, sout, serr;
            sin = isOutput ? '0' : '1';
            sout = serr = isOutput ? '1' : '0';

            newClient.write('POST /'+config.dockerOpts.version+'/containers/' + job.id + '/attach?stdin='+sin+'&stdout='+sout+'&stderr='+serr+'&stream=1 HTTP/1.1\r\n' +
                'Content-Type: application/vnd.docker.raw-stream\r\n\r\n');
        });

        return newClient;
    }

    function _injectCodeOrMonitor(codeStream) {
        var self = this;

        var onError = function(err) {
            self.finalCB(err, self);
        };

        var onData = function(data) {
                self.report('data received ' + data);
                switch(self.state) {
                    case NEW:
                        self.instrument('injecting code');
                        self.injectTime = Date.now();
                        codeStream.pipe(self.client);
                        break;
                    default:
                        self.
                        break;
                }
        };

        // code has been injected
        var onFinish = function() {
            self.instrument('client socket finished');
            self.state = WAITING;
            self.client.destroy();
            delete self.client;
            delete client;
        };

        var injectHandlers = {
            error: onError,
            data: onData,
            finish: onFinish
        };

        var injectClient = getClientForContainer(self, false, injectHandlers);
    }

    return { createRunner: _makeRunner }
};

module.exports = ConfigureDocker;
<|endoftext|>


<commit_before>var $ = jQuery = require("jquery");
require("../node_modules/bootstrap-sass/assets/javascripts/bootstrap/affix.js");
require("../node_modules/bootstrap-sass/assets/javascripts/bootstrap/scrollspy.js");

$(document).ready(function() {
  //get the latest hosted version
  if ($("#cdnDownload").length > 0) {
    var name = "yasqe";
    //only draw when we've got some place to print this info (might not be on all pages where we include this js file)
    $.get("http://api.jsdelivr.com/v1/jsdelivr/libraries?name=" + name + "&fields=lastversion", function(data) {
      if (data.length > 0) {
        var version = data[0].lastversion;
        $("#" + name + "Css").text(
          "<link href='//cdn.jsdelivr.net/" +
            name +
            "/" +
            version +
            "/" +
            name +
            ".min.css' rel='stylesheet' type='text/css'/>"
        );
        $("#" + name + "JsBundled").text(
          ""
        );
        $("#" + name + "Js").text(
          ""
        );
      } else {
        console.log("failed accessing jsdelivr api");
        $("#cdnDownload").hide();
      }
    }).fail(function() {
      console.log("failed accessing jsdelivr api");
      $("#cdnDownload").hide();
    });
  }
  var gistContainer = $("#gistContainer");
  if (gistContainer.length > 0) {
    $.get("https://api.github.com/users/LaurensRietveld/gists", function(data) {
      var processLabel = function(origLabel) {
        var label = origLabel.replace("#YASQE", "YASQE");
        label = label.replace("#YASR", "YASR");
        var splitted = label.split(" ");
        if (splitted.length > 0) {
          if ((splitted[0].indexOf("YASQE") == 0 || splitted[0].indexOf("YASR") == 0) && splitted[0].slice(-1) == ":") {
            //we want to change "#YASQE: some gist" into "some gist". So, remove the first item
            return splitted.splice(1).join(" ");
          } else {
            return splitted.join(" ");
          }
        } else {
          return label;
        }
      };
      data.forEach(function(gist) {
        if (gist.description.indexOf("#YASQE") >= 0) {
          var gistDiv = $("
").addClass("gist").addClass("well").appendTo(gistContainer);
          $("
").text(processLabel(gist.description)).appendTo(gistDiv);
          if (gist.files["README.md"]) {
            var description = $("
").appendTo(gistDiv);
            $.get(gist.url, function(gistFile) {
              description.text(gistFile.files["README.md"].content);
            });
          }
          var buttonContainer = $("
").appendTo(gistDiv);
          $("Demo")
            .attr("href", "http://bl.ocks.org/LaurensRietveld/raw/" + gist.id)
            .appendTo(buttonContainer);
          $(
            "Code "
          )
            .attr("href", gist["html_url"])
            .appendTo(buttonContainer);
        }
      });
    });
  }
});
<commit_msg>updated use of jsdelivr api so we render the proper include link in our docs<commit_after>var $ = jQuery = require("jquery");
require("../node_modules/bootstrap-sass/assets/javascripts/bootstrap/affix.js");
require("../node_modules/bootstrap-sass/assets/javascripts/bootstrap/scrollspy.js");

$(document).ready(function() {
  //get the latest hosted version
  if ($("#cdnDownload").length > 0) {
    var name = "yasqe";
    var npmName = "yasgui-" + name;
    //only draw when we've got some place to print this info (might not be on all pages where we include this js file)
    $.get("https://data.jsdelivr.com/v1/package/npm/" + npmName, function(data) {
      var version = data.tags.latest;
      if (version) {
        $("#" + name + "Css").text(
          "<link href='//cdn.jsdelivr.net/npm/" +
            npmName +
            "@" +
            version +
            "/dist/" +
            name +
            ".min.css' rel='stylesheet' type='text/css'/>"
        );
        $("#" + name + "JsBundled").text(
          ""
        );
        $("#" + name + "Js").text(
          ""
        );
      } else {
        console.log("failed accessing jsdelivr api");
        $("#cdnDownload").hide();
      }
    }).fail(function() {
      console.log("failed accessing jsdelivr api");
      $("#cdnDownload").hide();
    });
  }
  var gistContainer = $("#gistContainer");
  if (gistContainer.length > 0) {
    $.get("https://api.github.com/users/LaurensRietveld/gists", function(data) {
      var processLabel = function(origLabel) {
        var label = origLabel.replace("#YASQE", "YASQE");
        label = label.replace("#YASR", "YASR");
        var splitted = label.split(" ");
        if (splitted.length > 0) {
          if ((splitted[0].indexOf("YASQE") == 0 || splitted[0].indexOf("YASR") == 0) && splitted[0].slice(-1) == ":") {
            //we want to change "#YASQE: some gist" into "some gist". So, remove the first item
            return splitted.splice(1).join(" ");
          } else {
            return splitted.join(" ");
          }
        } else {
          return label;
        }
      };
      data.forEach(function(gist) {
        if (gist.description.indexOf("#YASQE") >= 0) {
          var gistDiv = $("
").addClass("gist").addClass("well").appendTo(gistContainer);
          $("
").text(processLabel(gist.description)).appendTo(gistDiv);
          if (gist.files["README.md"]) {
            var description = $("
").appendTo(gistDiv);
            $.get(gist.url, function(gistFile) {
              description.text(gistFile.files["README.md"].content);
            });
          }
          var buttonContainer = $("
").appendTo(gistDiv);
          $("Demo")
            .attr("href", "http://bl.ocks.org/LaurensRietveld/raw/" + gist.id)
            .appendTo(buttonContainer);
          $(
            "Code "
          )
            .attr("href", gist["html_url"])
            .appendTo(buttonContainer);
        }
      });
    });
  }
});
<|endoftext|>


<commit_before>var $ = jQuery = require("jquery");
require("../node_modules/bootstrap-sass/assets/javascripts/bootstrap/affix.js");
require("../node_modules/bootstrap-sass/assets/javascripts/bootstrap/scrollspy.js");

$(document).ready(function() {
	//get the latest hosted version
	if ($("#cdnDownload").length > 0) {
		var name = "yasr";
		//only draw when we've got some place to print this info (might not be on all pages where we include this js file)
		$.get("http://api.jsdelivr.com/v1/jsdelivr/libraries?name=" + name + "&fields=lastversion", function(data) {
			if (data.length > 0) {
				var version = data[0].lastversion;
				$("#" + name + "Css").text("<link href='//cdn.jsdelivr.net/" + name + "/" + version + "/" + name + ".min.css' rel='stylesheet' type='text/css'/>");
				$("#" + name + "JsBundled").text("");
				$("#" + name + "Js").text("");
			} else {
				console.log("failed accessing jsdelivr api");
				$("#cdnDownload").hide();
			}
		}).fail(function() {
			console.log("failed accessing jsdelivr api");
			$("#cdnDownload").hide();
		});
	}
	var gistContainer = $("#gistContainer");
	if (gistContainer.length > 0) {
		$.get("https://api.github.com/users/LaurensRietveld/gists", function(data) {
			var processLabel = function(origLabel) {
				var label = origLabel.replace("#YASQE", "YASQE");
				label = label.replace("#YASR", "YASR");
				var splitted = label.split(" ");
				if (splitted.length > 0) {
					if ((splitted[0].indexOf("YASQE") == 0 || splitted[0].indexOf("YASR") == 0) && splitted[0].slice(-1) == ":") {
						//we want to change "#YASQE: some gist" into "some gist". So, remove the first item
						return splitted.splice(1).join(" ");
					} else {
						return splitted.join(" ");
					}
				} else {
					return label;
				}
			};
			data.forEach(function(gist) {
				if (gist.description.indexOf("#YASR") >= 0) {
					var gistDiv = $("
").addClass("gist").addClass("well").appendTo(gistContainer);
					$("
").text(processLabel(gist.description)).appendTo(gistDiv);
					if (gist.files["README.md"]) {
						var description = $("
").appendTo(gistDiv);
						$.get(gist.url, function(gistFile) {
							description.text(gistFile.files["README.md"].content);
						});
					}
					var buttonContainer = $("
").appendTo(gistDiv);
					$("Demo").attr('href', 'http://bl.ocks.org/LaurensRietveld/raw/' + gist.id).appendTo(buttonContainer);
					$("Code ").attr('href', gist["html_url"]).appendTo(buttonContainer);
				}
			});
		});
	}
});
<commit_msg>prettified doc js<commit_after>var $ = jQuery = require("jquery");
require("../node_modules/bootstrap-sass/assets/javascripts/bootstrap/affix.js");
require("../node_modules/bootstrap-sass/assets/javascripts/bootstrap/scrollspy.js");

$(document).ready(function() {
  //get the latest hosted version
  if ($("#cdnDownload").length > 0) {
    var name = "yasr";
    //only draw when we've got some place to print this info (might not be on all pages where we include this js file)
    $.get("http://api.jsdelivr.com/v1/jsdelivr/libraries?name=" + name + "&fields=lastversion", function(data) {
      if (data.length > 0) {
        var version = data[0].lastversion;
        $("#" + name + "Css").text(
          "<link href='//cdn.jsdelivr.net/" +
            name +
            "/" +
            version +
            "/" +
            name +
            ".min.css' rel='stylesheet' type='text/css'/>"
        );
        $("#" + name + "JsBundled").text(
          ""
        );
        $("#" + name + "Js").text(
          ""
        );
      } else {
        console.log("failed accessing jsdelivr api");
        $("#cdnDownload").hide();
      }
    }).fail(function() {
      console.log("failed accessing jsdelivr api");
      $("#cdnDownload").hide();
    });
  }
  var gistContainer = $("#gistContainer");
  if (gistContainer.length > 0) {
    $.get("https://api.github.com/users/LaurensRietveld/gists", function(data) {
      var processLabel = function(origLabel) {
        var label = origLabel.replace("#YASQE", "YASQE");
        label = label.replace("#YASR", "YASR");
        var splitted = label.split(" ");
        if (splitted.length > 0) {
          if ((splitted[0].indexOf("YASQE") == 0 || splitted[0].indexOf("YASR") == 0) && splitted[0].slice(-1) == ":") {
            //we want to change "#YASQE: some gist" into "some gist". So, remove the first item
            return splitted.splice(1).join(" ");
          } else {
            return splitted.join(" ");
          }
        } else {
          return label;
        }
      };
      data.forEach(function(gist) {
        if (gist.description.indexOf("#YASR") >= 0) {
          var gistDiv = $("
").addClass("gist").addClass("well").appendTo(gistContainer);
          $("
").text(processLabel(gist.description)).appendTo(gistDiv);
          if (gist.files["README.md"]) {
            var description = $("
").appendTo(gistDiv);
            $.get(gist.url, function(gistFile) {
              description.text(gistFile.files["README.md"].content);
            });
          }
          var buttonContainer = $("
").appendTo(gistDiv);
          $("Demo")
            .attr("href", "http://bl.ocks.org/LaurensRietveld/raw/" + gist.id)
            .appendTo(buttonContainer);
          $(
            "Code "
          )
            .attr("href", gist["html_url"])
            .appendTo(buttonContainer);
        }
      });
    });
  }
});
<|endoftext|>


<commit_before>document.write(' \
\

 \
	Main | Reference | Tutorials | Download | Contact \

 \
\

 \
	hAxe is an open source programming language for the web. \

 \
\
');<commit_msg>fixed X<commit_after>document.write(' \
\

 \
	Main | Reference | Tutorials | Download | Contact \

 \
\

 \
	haXe is an open source programming language for the web. \

 \
\
');<|endoftext|>


<commit_before>import { Actions } from 'thundercats';
import { Observable } from 'rx';

export default Actions({
  shouldBindMethods: true,
  refs: { displayName: 'AppActions' },

  setTitle(title = 'Learn To Code') {
    return { title: title + ' | Free Code Camp' };
  },

  getUser() {
    return this.readService$('user', null, null)
      .map(({
        username,
        picture,
        progressTimestamps = [],
        isFrontEndCert,
        isBackEndCert,
        isFullStackCert
      }) => {
        return {
          username,
          picture,
          points: progressTimestamps.length,
          isFrontEndCert,
          isBackEndCert,
          isFullStackCert
        };
      })
      .catch(err => Observable.just({ err }));
  },

  // routing
  // goTo(path: String) => path
  goTo: null,

  // goBack(arg?) => arg?
  goBack: null,

  // toast(args: { type?: String, message: String, title: String }) => args
  toast(args) {
    return {
      transform(state) {
        const id = state.toast && state.toast.id ? state.toast.id : 0;
        const toast = { ...args, id: id + 1 };
        return { ...state, toast };
      }
    };
  },

  // updateLocation(location: { pathname: String }) => location
  updateLocation(location) {
    return {
      transform(state) {
        return { ...state, location };
      }
    };
  }
});
<commit_msg>Clean up toast logic in AppActions<commit_after>import { Actions } from 'thundercats';
import { Observable } from 'rx';

export default Actions({
  shouldBindMethods: true,
  refs: { displayName: 'AppActions' },

  setTitle(title = 'Learn To Code') {
    return { title: title + ' | Free Code Camp' };
  },

  getUser() {
    return this.readService$('user', null, null)
      .map(({
        username,
        picture,
        progressTimestamps = [],
        isFrontEndCert,
        isBackEndCert,
        isFullStackCert
      }) => {
        return {
          username,
          picture,
          points: progressTimestamps.length,
          isFrontEndCert,
          isBackEndCert,
          isFullStackCert
        };
      })
      .catch(err => Observable.just({ err }));
  },

  // routing
  // goTo(path: String) => path
  goTo: null,

  // goBack(arg?) => arg?
  goBack: null,

  // toast(args: { type?: String, message: String, title: String }) => args
  toast(args) {
    return {
      transform(state) {
        return {
          ...state,
          toast: {
            ...args,
            id: state.toast && state.toast.id ? state.toast.id : 1
          }
        };
      }
    };
  },

  // updateLocation(location: { pathname: String }) => location
  updateLocation(location) {
    return {
      transform(state) {
        return { ...state, location };
      }
    };
  }
});
<|endoftext|>


<commit_before>export Sidebar from './Sidebar'
export Header from './Header'
export Footer from './Footer'
export Root from './Root'
export RouteAuth from './RouteAuth'
<commit_msg>add export Logo from components<commit_after>export Sidebar from './Sidebar'
export Header from './Header'
export Footer from './Footer'
export Root from './Root'
export RouteAuth from './RouteAuth'
export Logo from './Logo'
<|endoftext|>


<commit_before>const template = {
    add: function add(a, b) a + b,
    join: function join(c) function (a, b) a + c + b,

    map: function map(iter, fn, sep, interruptable)
    {
        if (iter.length) /* Kludge? */
            iter = util.Array.iterator(iter);
        let ret = <></>;
        let n = 0;
        for each (let i in Iterator(iter))
        {
            let val = fn(i);
            if (val == undefined)
                continue;
            if (sep && n++)
                ret += sep;
            if (interruptable && n % interruptable == 0)
                liberator.threadYield(true, true);
            ret += val;
        }
        return ret;
    },

    maybeXML: function maybeXML(xml)
    {
        if (typeof xml == "xml")
            return xml;
        try
        {
            return new XMLList(xml);
        }
        catch (e) {}
        return <>{xml}</>;
    },

    completionRow: function completionRow(item, class)
    {
        if (typeof icon == "function")
            icon = icon();

        if (class)
        {
            var text = item[0] || "";
            var desc = item[1] || "";
        }
        else
        {
            var text = this.process[0].call(this, item, item.text || this.getKey(item, "text"));
            var desc = this.process[1].call(this, item, this.getKey(item, "description"));
        }

        return

{text}

{desc}

;
    },

    bookmarkDescription: function (item, text)
    {
        let extra = this.getKey(item, "extra");
        return <>
            {text}
            {
                !(extra && extra.length) ? "" :

                    ({
                        template.map(extra, function (e)
                        <>{e[0]}: {e[1]}</>,
                        <> </>/* Non-breaking space */)
                    })

            }
        </>
    },

    icon: function (item, text)
    {
        let icon = this.getKey(item, "icon");
        return <>{icon ?  : <></>}{text}</>
    },

    filter: function (str) {str},

    gradient: function (left, right)

                    { template.map(util.range(0, 100), function (i)
                      ) }

,

    // if "processStrings" is true, any passed strings will be surrounded by " and
    // any line breaks are displayed as \n
    highlight: function highlight(arg, processStrings, clip)
    {
        // some objects like window.JSON or getBrowsers()._browsers need the try/catch
        let str = clip ? util.clip(String(arg), clip) : String(arg);
        try
        {
            switch (arg == null ? "undefined" : typeof arg)
            {
                case "number":
                    return {str};
                case "string":
                    if (processStrings)
                        str = str.quote();
                    return {str};
                case "boolean":
                    return {str};
                case "function":
                    // Vim generally doesn't like /foo*/, because */ looks like a comment terminator.
                    // Using /foo*(:?)/ instead.
                    if (processStrings)
                        return {str.replace(/\{(.|\n)*(?:)/g, "{ ... }")};
                    return <>{arg}</>;
                case "undefined":
                    return {arg};
                case "object":
                    // for java packages value.toString() would crash so badly
                    // that we cannot even try/catch it
                    if (/^\[JavaPackage.*\]$/.test(arg))
                        return <>[JavaPackage]</>;
                    if (processStrings && false)
                        str = template.highlightFilter(str, "\n", function () ^J);
                    return {str};
                case "xml":
                    return arg;
                default:
                    return <![CDATA[<unknown type>]]>;
            }
        }
        catch (e)
        {
            return<![CDATA[<unknown>]]>;
        }
    },

    highlightFilter: function highlightFilter(str, filter, highlight)
    {
        return this.highlightSubstrings(str, (function ()
        {
            if (filter.length == 0)
                return;
            let lcstr = String.toLowerCase(str);
            let lcfilter = filter.toLowerCase();
            let start = 0;
            while ((start = lcstr.indexOf(lcfilter, start)) > -1)
            {
                yield [start, filter.length];
                start += filter.length;
            }
        })(), highlight || template.filter);
    },

    highlightRegexp: function highlightRegexp(str, re, highlight)
    {
        return this.highlightSubstrings(str, (function ()
        {
            let res;
            while ((res = re.exec(str)) && res[0].length)
                yield [res.index, res[0].length];
        })(), highlight || template.filter);
    },

    highlightSubstrings: function highlightSubstrings(str, iter, highlight)
    {
        if (typeof str == "xml")
            return str;
        if (str == "")
            return <>{str}</>;

        str = String(str).replace(" ", "\u00a0");
        let s = <></>;
        let start = 0;
        let n = 0;
        for (let [i, length] in iter)
        {
            if (n++ > 50) // Prevent infinite loops.
                return s + <>{str.substr(start)}</>;
            XML.ignoreWhitespace = false;
            s += <>{str.substring(start, i)}</>;
            s += highlight(str.substr(i, length));
            start = i + length;
        }
        return s + <>{str.substr(start)}</>;
    },

    highlightURL: function highlightURL(str, force)
    {
        if (force || /^[a-zA-Z]+:\/\//.test(str))
            return {str};
        else
            return str;
    },

    commandOutput: function generic(xml)
    {
        return <>:{commandline.command}
{xml}</>;
    },

    // every item must have a .xml property which defines how to draw itself
    // @param headers is an array of strings, the text for the header columns
    genericTable: function genericTable(items, format)
    {
        this.listCompleter(function (context) {
            context.filterFunc = null;
            if (format)
                context.format = format;
            context.completions = items;
        });
    },

    jumps: function jumps(index, elems)
    {
        return this.generic(

                    jump	title	URI

                {
                    this.map(Iterator(elems), function ([idx, val])

                        {idx == index ? ">" : ""}
                        {Math.abs(idx - index)}
                        {val.title}
                        {val.URI.spec}

)
                }

);
    },

    options: function options(title, opts)
    {
        return this.generic(

                    --- {title} ---

                {
                    this.map(opts, function (opt)

                            {opt.pre}{opt.name}{opt.value}
                            {opt.isDefault || opt.default == null ? "" :  (default: {opt.default})}

)
                }

);
    },

    table: function table(title, data, indent)
    {
        let table =

                    {title}

                {
                    this.map(data, function (datum)

                       {datum[0]}
                       {template.maybeXML(datum[1])}

)
                }

;
        if (table.tr.length() > 1)
            return table;
    },

    tabular: function tabular(headings, style, iter)
    {
        /* This might be mind-bogglingly slow. We'll see. */
        return this.generic(

                {
                    this.map(headings, function (h)
                    {h}	)
                }

                {
                    this.map(iter, function (row)

                    {
                        template.map(Iterator(row), function ([i, d])
                        {d}	)
                    }

)
                }

);
    },

    usage: function usage(iter)
    {
        return this.generic(

            {
                this.map(iter, function (item)

                    {item.name || item.names[0]}
                    {item.description}

)
            }

);
    }
};

// vim: set fdm=marker sw=4 ts=4 et:
<commit_msg>Fix occurances of this.generic in completion.js<commit_after>const template = {
    add: function add(a, b) a + b,
    join: function join(c) function (a, b) a + c + b,

    map: function map(iter, fn, sep, interruptable)
    {
        if (iter.length) /* Kludge? */
            iter = util.Array.iterator(iter);
        let ret = <></>;
        let n = 0;
        for each (let i in Iterator(iter))
        {
            let val = fn(i);
            if (val == undefined)
                continue;
            if (sep && n++)
                ret += sep;
            if (interruptable && n % interruptable == 0)
                liberator.threadYield(true, true);
            ret += val;
        }
        return ret;
    },

    maybeXML: function maybeXML(xml)
    {
        if (typeof xml == "xml")
            return xml;
        try
        {
            return new XMLList(xml);
        }
        catch (e) {}
        return <>{xml}</>;
    },

    completionRow: function completionRow(item, class)
    {
        if (typeof icon == "function")
            icon = icon();

        if (class)
        {
            var text = item[0] || "";
            var desc = item[1] || "";
        }
        else
        {
            var text = this.process[0].call(this, item, item.text || this.getKey(item, "text"));
            var desc = this.process[1].call(this, item, this.getKey(item, "description"));
        }

        return

{text}

{desc}

;
    },

    bookmarkDescription: function (item, text)
    {
        let extra = this.getKey(item, "extra");
        return <>
            {text}
            {
                !(extra && extra.length) ? "" :

                    ({
                        template.map(extra, function (e)
                        <>{e[0]}: {e[1]}</>,
                        <> </>/* Non-breaking space */)
                    })

            }
        </>
    },

    icon: function (item, text)
    {
        let icon = this.getKey(item, "icon");
        return <>{icon ?  : <></>}{text}</>
    },

    filter: function (str) {str},

    gradient: function (left, right)

                    { template.map(util.range(0, 100), function (i)
                      ) }

,

    // if "processStrings" is true, any passed strings will be surrounded by " and
    // any line breaks are displayed as \n
    highlight: function highlight(arg, processStrings, clip)
    {
        // some objects like window.JSON or getBrowsers()._browsers need the try/catch
        let str = clip ? util.clip(String(arg), clip) : String(arg);
        try
        {
            switch (arg == null ? "undefined" : typeof arg)
            {
                case "number":
                    return {str};
                case "string":
                    if (processStrings)
                        str = str.quote();
                    return {str};
                case "boolean":
                    return {str};
                case "function":
                    // Vim generally doesn't like /foo*/, because */ looks like a comment terminator.
                    // Using /foo*(:?)/ instead.
                    if (processStrings)
                        return {str.replace(/\{(.|\n)*(?:)/g, "{ ... }")};
                    return <>{arg}</>;
                case "undefined":
                    return {arg};
                case "object":
                    // for java packages value.toString() would crash so badly
                    // that we cannot even try/catch it
                    if (/^\[JavaPackage.*\]$/.test(arg))
                        return <>[JavaPackage]</>;
                    if (processStrings && false)
                        str = template.highlightFilter(str, "\n", function () ^J);
                    return {str};
                case "xml":
                    return arg;
                default:
                    return <![CDATA[<unknown type>]]>;
            }
        }
        catch (e)
        {
            return<![CDATA[<unknown>]]>;
        }
    },

    highlightFilter: function highlightFilter(str, filter, highlight)
    {
        return this.highlightSubstrings(str, (function ()
        {
            if (filter.length == 0)
                return;
            let lcstr = String.toLowerCase(str);
            let lcfilter = filter.toLowerCase();
            let start = 0;
            while ((start = lcstr.indexOf(lcfilter, start)) > -1)
            {
                yield [start, filter.length];
                start += filter.length;
            }
        })(), highlight || template.filter);
    },

    highlightRegexp: function highlightRegexp(str, re, highlight)
    {
        return this.highlightSubstrings(str, (function ()
        {
            let res;
            while ((res = re.exec(str)) && res[0].length)
                yield [res.index, res[0].length];
        })(), highlight || template.filter);
    },

    highlightSubstrings: function highlightSubstrings(str, iter, highlight)
    {
        if (typeof str == "xml")
            return str;
        if (str == "")
            return <>{str}</>;

        str = String(str).replace(" ", "\u00a0");
        let s = <></>;
        let start = 0;
        let n = 0;
        for (let [i, length] in iter)
        {
            if (n++ > 50) // Prevent infinite loops.
                return s + <>{str.substr(start)}</>;
            XML.ignoreWhitespace = false;
            s += <>{str.substring(start, i)}</>;
            s += highlight(str.substr(i, length));
            start = i + length;
        }
        return s + <>{str.substr(start)}</>;
    },

    highlightURL: function highlightURL(str, force)
    {
        if (force || /^[a-zA-Z]+:\/\//.test(str))
            return {str};
        else
            return str;
    },

    commandOutput: function generic(xml)
    {
        return <>:{commandline.command}
{xml}</>;
    },

    // every item must have a .xml property which defines how to draw itself
    // @param headers is an array of strings, the text for the header columns
    genericTable: function genericTable(items, format)
    {
        this.listCompleter(function (context) {
            context.filterFunc = null;
            if (format)
                context.format = format;
            context.completions = items;
        });
    },

    jumps: function jumps(index, elems)
    {
        return this.commandOutput(

                    jump	title	URI

                {
                    this.map(Iterator(elems), function ([idx, val])

                        {idx == index ? ">" : ""}
                        {Math.abs(idx - index)}
                        {val.title}
                        {val.URI.spec}

)
                }

);
    },

    options: function options(title, opts)
    {
        return this.commandOutput(

                    --- {title} ---

                {
                    this.map(opts, function (opt)

                            {opt.pre}{opt.name}{opt.value}
                            {opt.isDefault || opt.default == null ? "" :  (default: {opt.default})}

)
                }

);
    },

    table: function table(title, data, indent)
    {
        let table =

                    {title}

                {
                    this.map(data, function (datum)

                       {datum[0]}
                       {template.maybeXML(datum[1])}

)
                }

;
        if (table.tr.length() > 1)
            return table;
    },

    tabular: function tabular(headings, style, iter)
    {
        /* This might be mind-bogglingly slow. We'll see. */
        return this.commandOutput(

                {
                    this.map(headings, function (h)
                    {h}	)
                }

                {
                    this.map(iter, function (row)

                    {
                        template.map(Iterator(row), function ([i, d])
                        {d}	)
                    }

)
                }

);
    },

    usage: function usage(iter)
    {
        return this.commandOutput(

            {
                this.map(iter, function (item)

                    {item.name || item.names[0]}
                    {item.description}

)
            }

);
    }
};

// vim: set fdm=marker sw=4 ts=4 et:
<|endoftext|>


<commit_before>$('.loading').hide();
$('#extractText').on('click',function(e){
	try{
		$('.loading').show();
		setTimeout(function(){
			var obj={};
			for(i=0;i<sessionStorage.length;i++){
				if(sessionStorage.key(i).indexOf('_smry')<0){
					var data = new FormData();
					data.append('data', sessionStorage.getItem(sessionStorage.key(i)));

					var ourRequest = new XMLHttpRequest();
					ourRequest.open('POST', "/extractKeywords", false);

					ourRequest.onreadystatechange = function() {
						if (this.readyState == 4 && this.status == 200) {
							obj[sessionStorage.key(i)]=ourRequest.responseText;
						}
					};
					ourRequest.send(data);
				}

			}
			$('.loading').hide();

			$('.list-group').empty();

			var mainString = [];
			for (var key in obj) {
				$('.list-group').append('

' + key + '

')
				mainString = obj[key];
				var subString = mainString.split('@#$%^&');
				for(var line in subString) {
					var keyWords;
					if(subString[line]!=''){
						var categoryAndKeywords = subString[line].split('&');
						var categories = categoryAndKeywords[0];
						cat = categories.split('/')[1]; //higest category level
						if(!(cat == "book" || cat == "people")) {
							cat  = categories.split('/')[2]; //lower category level
							var keyWordsList = categoryAndKeywords[1];

							keyWords = keyWordsList.split(':');

							var clickableKeywords = "";
							for(var keyword in keyWords) {
								if ((keyword % 5) == 4){
									var temp = ''+ ' &#9702' + ' ' + keyWords[keyword].replace(/ *\([^)]*\) */g, '')  + '
';
								} else {
									var temp = ''+ ' &#9702' + ' ' + keyWords[keyword].replace(/ *\([^)]*\) */g, '')  + ' ';
								}
								clickableKeywords += temp;
							}
							$('.list-group').append('
' + cat + '
' + clickableKeywords + '
')
						}
					}
				}

				/*$('.list-group').append('
' + key.substring(0,key.lastIndexOf("_kywrd")) + '
' + obj[key] + '
')*/
			}

		},15);

	}catch(err){
		console.log('An error occured ' + err);
	}

});

$(document).on("click", '.containedKeywords', function(event) {
	var globalExtractObj=searchWithKeywords($(this).text().replace(/^\s+|\s+$/g, ""));
	var kword = $(this).text();

	sessionStorage.setItem('extractVar','true');
	sessionStorage.setItem('keyword', kword);
	sessionStorage.setItem('extractVarObj',JSON.stringify(globalExtractObj));
	window.location.href='/keywordsearch';
});

function searchWithKeywords(keywords){
	var obj={};
	for(i=0;i<sessionStorage.length;i++){
		if(sessionStorage.key(i).indexOf('_smry')<0 && sessionStorage.key(i).indexOf('extractVar')<0){
			var data = new FormData();
			data.append('data', sessionStorage.getItem(sessionStorage.key(i)));
			data.append('keywords', keywords);

			var ourRequest = new XMLHttpRequest();
			ourRequest.open('POST', "/fetchFilteredSummaries", false);

			ourRequest.onreadystatechange = function() {
				if (this.readyState == 4 && this.status == 200) {
					if(ourRequest.responseText!='Empty File')
						obj[sessionStorage.key(i) + "_smry"]=ourRequest.responseText;

				}else{

				}

			};
			ourRequest.send(data);
		}
	}
	return obj;
}
<commit_msg>further refine keyword display<commit_after>$('.loading').hide();
$('#extractText').on('click',function(e){
	try{
		$('.loading').show();
		setTimeout(function(){
			var obj={};
			for(i=0;i<sessionStorage.length;i++){
				if(sessionStorage.key(i).indexOf('_smry')<0){
					var data = new FormData();
					data.append('data', sessionStorage.getItem(sessionStorage.key(i)));

					var ourRequest = new XMLHttpRequest();
					ourRequest.open('POST', "/extractKeywords", false);

					ourRequest.onreadystatechange = function() {
						if (this.readyState == 4 && this.status == 200) {
							obj[sessionStorage.key(i)]=ourRequest.responseText;
						}
					};
					ourRequest.send(data);
				}

			}
			$('.loading').hide();

			$('.list-group').empty();

			var mainString = [];
			for (var key in obj) {
				$('.list-group').append('

' + key + '

')
				mainString = obj[key];
				var subString = mainString.split('@#$%^&');
				for(var line in subString) {
					var keyWords;
					if(subString[line]!=''){
						var categoryAndKeywords = subString[line].split('&');
						var categories = categoryAndKeywords[0];
						cat = categories.split('/')[1]; //higest category level
						if(!(cat == "book" || cat == "people")) {
							cat  = categories.split('/')[2]; //lower category level
							var keyWordsList = categoryAndKeywords[1];

							keyWords = keyWordsList.split(':');
							if(keyWords.length != 1) {
								var clickableKeywords = "";
								for(var keyword in keyWords) {
									if ((keyword % 5) == 4){
										var temp = ''+ ' &#9702' + ' ' + keyWords[keyword].replace(/ *\([^)]*\) */g, '')  + '
';
									} else {
										var temp = ''+ ' &#9702' + ' ' + keyWords[keyword].replace(/ *\([^)]*\) */g, '')  + ' ';
									}
									clickableKeywords += temp;
								}
								$('.list-group').append('
' + cat + '
' + clickableKeywords + '
')
							}
						}
					}
				}

				/*$('.list-group').append('
' + key.substring(0,key.lastIndexOf("_kywrd")) + '
' + obj[key] + '
')*/
			}

		},15);

	}catch(err){
		console.log('An error occured ' + err);
	}

});

$(document).on("click", '.containedKeywords', function(event) {
	var globalExtractObj=searchWithKeywords($(this).text().replace(/^\s+|\s+$/g, ""));
	var kword = $(this).text();

	sessionStorage.setItem('extractVar','true');
	sessionStorage.setItem('keyword', kword);
	sessionStorage.setItem('extractVarObj',JSON.stringify(globalExtractObj));
	window.location.href='/keywordsearch';
});

function searchWithKeywords(keywords){
	var obj={};
	for(i=0;i<sessionStorage.length;i++){
		if(sessionStorage.key(i).indexOf('_smry')<0 && sessionStorage.key(i).indexOf('extractVar')<0){
			var data = new FormData();
			data.append('data', sessionStorage.getItem(sessionStorage.key(i)));
			data.append('keywords', keywords);

			var ourRequest = new XMLHttpRequest();
			ourRequest.open('POST', "/fetchFilteredSummaries", false);

			ourRequest.onreadystatechange = function() {
				if (this.readyState == 4 && this.status == 200) {
					if(ourRequest.responseText!='Empty File')
						obj[sessionStorage.key(i) + "_smry"]=ourRequest.responseText;

				}else{

				}

			};
			ourRequest.send(data);
		}
	}
	return obj;
}
<|endoftext|>


<commit_before>$('.loading').hide();
checkFileCount();
sessionStorage.removeItem('extractVar');
sessionStorage.removeItem('extractVarObj');
if (sessionStorage.length) {
	if ($('#filesUploadedStatus').text() == 'No Files Uploaded') {
		$('#filesUploadedStatus').text('Files Uploaded');
	}

	for(i = 0; i < sessionStorage.length; i++){
		if(sessionStorage.key(i).indexOf('_smry') < 0 && sessionStorage.key(i).indexOf('_keyword') < 0){
		$('.list-group').append('
' + sessionStorage.key(i) + '<button type="button" class="close" aria-label="Close">×</button>
');
		}
	}
}
setActiveFile();

function snackbar(text) {

	var snackbar = document.getElementById("snackbar")

	// Add the "show" class to DIV
	snackbar.innerHTML = text;
	snackbar.className = "show";

	// After 3 seconds, remove the show class from DIV
	setTimeout(function() {
		snackbar.className = snackbar.className.replace("show", "");
	}, 3000);
	console.log("function called");
}

/**
 * Sends request to the server side to get the text of the file(s)
 */
$('#buttonSubmit').on('click', function(e) {

	//Get the selected files
	var input = document.getElementById('UploadCV');

	//Check if the user has actually selected file(s)
	if (input.files.length == 0) {
		snackbar("No files uploaded...");
		return;
	}

	//Check if the file type is correct.
	// for (var x = 0; x < input.files.length; x++) {
	// 	var fileName = input.files[x].name;
	// 	var fileExt = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length);

			// Initially clear previous errors if present
			$('#errorText').text('');
			$('.loading').show();
			setTimeout(function(){
				var count = 0;
				for (var x = 0; x < input.files.length; x++) {
					var isDuplicateFile = false;
					var fileName = input.files[x].name;
					var fileExt = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length);

					if('undefined'!=fileExt && ''!=fileExt && isCorrectType(fileExt)){

					var data = new FormData();
					data.append('myFile', input.files[x]);
					var ourRequest = new XMLHttpRequest();
					ourRequest.open('POST', "/result", false);

					//Listener for request
					ourRequest.onreadystatechange = function() {
						if (this.readyState == 4 && this.status == 200) { //Successful response
							sessionStorage.setItem(fileName,ourRequest.responseText); //Stores the text into the  current session
							count++;
							checkDuplicateAndAddFile(fileName);
						} else { //Unsuccessful response
							sessionStorage.setItem(fileName, 'Empty File');
							count++;
						}
					};
					//Send the file
					console.log(count);
					ourRequest.send(data);
					checkFileCount();

					if (count == input.files.length) {
						$('.loading').hide();
					}

				}else {
					$('.loading').hide();
					snackbar("Invalid file type..." + fileName);
					continue;
				}

			}
			},15);

	//}
});

/**
 * Checks duplication and adds the given file to the list group
 * @param fileName
 * @returns
 */
function checkDuplicateAndAddFile(fileName){
	var isDuplicateFile = false;
	isDuplicateFile = checkDuplicateFile(isDuplicateFile,fileName);
	if (!isDuplicateFile && !$('#errorText').text()) {
		if ($('#filesUploadedStatus').text() == 'No Files Uploaded') {
			$('#filesUploadedStatus').text('Files Uploaded');
		}
		$('.list-group').append('
'
							+ fileName
							+ '<button type="button" class="close" aria-label="Close">×</button>
');
	}
	setActiveFile();
}

function isCorrectType(fileExt) {
	if('pdf'==fileExt || 'pptx'==fileExt || 'docx'==fileExt || 'ppt'==fileExt || 'doc'==fileExt || 'txt'==fileExt) {
		return true;
	} else {
		return false;
	}
}

function setActiveFile() {

	$('.list-group-item').on('mouseover',function() {
		$('.list-group-item').removeClass('active');
		$('.list-group-item[customId='+ $(this).attr('customId') + ']').addClass('active');
	});

	$('.list-group-item').on('mouseout', function() {
		$(this).removeClass('active');
	});
}

function checkDuplicateFile(param, fileName) {
	$('.list-group').find('.list-group-item').each(function() {
		var listItem = $(this).text().substring(0, $(this).text().length - 1);
		if (listItem == fileName) {
			param = true;
			return false; //returns from JQuery function
		}
	});

	return param;
}
$('#buttonSummarize').on('click',function(e){

	var obj={};
	var iterationLength=sessionStorage.length;
	if(iterationLength == 0){
		snackbar("No files uploaded...");
		return;
	}

	for(i = 0; i < iterationLength; i++){
		if(sessionStorage.key(i).indexOf('_smry') < 0 && sessionStorage.key(i).indexOf('_keyword')){
			var data = new FormData();
			data.append('data', sessionStorage.getItem(sessionStorage.key(i)));
			data.append('keywords', '');
			var ourRequest = new XMLHttpRequest();
			ourRequest.open('POST', "/fetchFilteredSummaries", false);

			ourRequest.onreadystatechange = function() {
				if (this.readyState == 4 && this.status == 200) {
					obj[sessionStorage.key(i) + "_smry"]=ourRequest.responseText;
				}else{
					obj[sessionStorage.key(i) + "_smry"]="The file is empty";
				}
			};
			ourRequest.send(data);
		}
	}
	for (var key in obj) {
		sessionStorage.setItem(key, obj[key]);
	}
	window.location.href='/keywordsearch';
});

$(document).on("click", '.close', function(event) {  //delete file
		var fileToRemove=$(this).parents('p').text();
		fileToRemove=fileToRemove.substring(0,fileToRemove.length-1); //x button text also appears
		sessionStorage.removeItem(fileToRemove);
		sessionStorage.removeItem(fileToRemove + "_smry");
		sessionStorage.removeItem(fileToRemove + "_keyword");
		$(this).parents('p').remove();
		checkFileCount();
		if(!$('.list-group-item').length){
			$('#filesUploadedStatus').text('No Files Uploaded');
		}
	});

function checkFileCount() {
	if(sessionStorage.length == 0) {
		$('#buttonSummarize').hide()
	} else {
		$('#buttonSummarize').show()
	}
}
<commit_msg>commenting for the upload.js file<commit_after>//Hide Spinner on loading the extract page
$('.loading').hide();
checkFileCount();
sessionStorage.removeItem('extractVar');
sessionStorage.removeItem('extractVarObj');
//when there is a file uploaded update the UI to let the user know which files have been uploaded
if (sessionStorage.length) {
	if ($('#filesUploadedStatus').text() == 'No Files Uploaded') {
		$('#filesUploadedStatus').text('Files Uploaded');
	}
	for(i = 0; i < sessionStorage.length; i++){
		if(sessionStorage.key(i).indexOf('_smry') < 0 && sessionStorage.key(i).indexOf('_keyword') < 0){
		$('.list-group').append('
' + sessionStorage.key(i) + '<button type="button" class="close" aria-label="Close">×</button>
');
		}
	}
}

setActiveFile();

function snackbar(text) {

	var snackbar = document.getElementById("snackbar")

	// Add the "show" class to DIV
	snackbar.innerHTML = text;
	snackbar.className = "show";

	// After 3 seconds, remove the show class from DIV
	setTimeout(function() {
		snackbar.className = snackbar.className.replace("show", "");
	}, 3000);
	console.log("function called");
}

/**
 * Sends request to the server side to get the text of the file(s)
 */
$('#buttonSubmit').on('click', function(e) {

	//Get the selected files
	var input = document.getElementById('UploadCV');

	//Check if the user has actually selected file(s)
	if (input.files.length == 0) {
		snackbar("No files uploaded...");
		return;
	}

			// Initially clear previous errors if present
			$('#errorText').text('');
			$('.loading').show();
			setTimeout(function(){
				var count = 0;
				for (var x = 0; x < input.files.length; x++) {
					var isDuplicateFile = false;
					var fileName = input.files[x].name;
					var fileExt = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length);

					if('undefined'!=fileExt && ''!=fileExt && isCorrectType(fileExt)){

					var data = new FormData();
					data.append('myFile', input.files[x]);
					var ourRequest = new XMLHttpRequest();
					ourRequest.open('POST', "/result", false);

					//Listener for request
					ourRequest.onreadystatechange = function() {
						if (this.readyState == 4 && this.status == 200) { //Successful response
							sessionStorage.setItem(fileName,ourRequest.responseText); //Stores the text into the  current session
							count++;
							checkDuplicateAndAddFile(fileName);
						} else { //Unsuccessful response
							sessionStorage.setItem(fileName, 'Empty File');
							count++;
						}
					};
					//Send the file
					console.log(count);
					ourRequest.send(data);
					checkFileCount();

					if (count == input.files.length) {
						$('.loading').hide();
					}

				}else {
					$('.loading').hide();
					snackbar("Invalid file type..." + fileName);
					continue;
				}

			}
			},15);

	//}
});

/**
 * Checks duplication and adds the given file to the list group
 * @param fileName
 * @returns
 */
function checkDuplicateAndAddFile(fileName){
	var isDuplicateFile = false;
	isDuplicateFile = checkDuplicateFile(isDuplicateFile,fileName);
	if (!isDuplicateFile && !$('#errorText').text()) {
		if ($('#filesUploadedStatus').text() == 'No Files Uploaded') {
			$('#filesUploadedStatus').text('Files Uploaded');
		}
		$('.list-group').append('
'
							+ fileName
							+ '<button type="button" class="close" aria-label="Close">×</button>
');
	}
	setActiveFile();
}

//checks to see if the file uploaded by the user is compatable with our web app.
function isCorrectType(fileExt) {
	if('pdf'==fileExt || 'pptx'==fileExt || 'docx'==fileExt || 'ppt'==fileExt || 'doc'==fileExt || 'txt'==fileExt) {
		return true;
	} else {
		return false;
	}
}

function setActiveFile() {
//When the mouse moves over a uploaded file name, that file is set to the active file
	$('.list-group-item').on('mouseover',function() {
		$('.list-group-item').removeClass('active');
		$('.list-group-item[customId='+ $(this).attr('customId') + ']').addClass('active');
	});

	$('.list-group-item').on('mouseout', function() {
		$(this).removeClass('active');
	});
}

//checks for duplicate file names and sets a flag if it finds a duplicate
function checkDuplicateFile(param, fileName) {
	$('.list-group').find('.list-group-item').each(function() {
		var listItem = $(this).text().substring(0, $(this).text().length - 1);
		if (listItem == fileName) {
			param = true;
			return false; //returns from JQuery function
		}
	});

	return param;
}

$('#buttonSummarize').on('click',function(e){

    //if there are no files uploaded a pop up in the UI will say ther are no files uploaded
	var obj={};
	var iterationLength=sessionStorage.length;
	if(iterationLength == 0){
		snackbar("No files uploaded...");
		return;
	}

    //store the content of the files uploaded in the session storage and send them to pyteaser to be summarised
	for(i = 0; i < iterationLength; i++){
		if(sessionStorage.key(i).indexOf('_smry') < 0 && sessionStorage.key(i).indexOf('_keyword')){
			var data = new FormData();
			data.append('data', sessionStorage.getItem(sessionStorage.key(i)));
			data.append('keywords', '');
			var ourRequest = new XMLHttpRequest();
			ourRequest.open('POST', "/fetchFilteredSummaries", false);

			ourRequest.onreadystatechange = function() {
				if (this.readyState == 4 && this.status == 200) {
					obj[sessionStorage.key(i) + "_smry"]=ourRequest.responseText;
				}else{
					obj[sessionStorage.key(i) + "_smry"]="The file is empty";
				}
			};
			ourRequest.send(data);
		}
	}
    //once the files have been sent to pyteaser sucessfully automatically go to the summary page
	for (var key in obj) {
		sessionStorage.setItem(key, obj[key]);
	}
	window.location.href='/keywordsearch';
});

// when the 'X' button (close button) is clicked, remove the corresponding file form the session storage
$(document).on("click", '.close', function(event) {  //delete file
		var fileToRemove=$(this).parents('p').text();
		fileToRemove=fileToRemove.substring(0,fileToRemove.length-1); //x button text also appears
		sessionStorage.removeItem(fileToRemove);
		sessionStorage.removeItem(fileToRemove + "_smry");
		sessionStorage.removeItem(fileToRemove + "_keyword");
		$(this).parents('p').remove();
		checkFileCount();
		if(!$('.list-group-item').length){
			$('#filesUploadedStatus').text('No Files Uploaded');
		}
	});

//If there are no files in the session storage, then don not display the summarize button
function checkFileCount() {
	if(sessionStorage.length == 0) {
		$('#buttonSummarize').hide()
	} else {
		$('#buttonSummarize').show()
	}
}
<|endoftext|>


<commit_before>/**
 * Users resource controller
 *
 * @see
 * - https://www.mongodb.com/blog/post/password-authentication-with-mongoose-part-1
 * - pick es6 https://gist.github.com/bisubus/2da8af7e801ffd813fab7ac221aa7afc
 */

const { pick } = require('lodash')
const assert = require('http-assert')
const createError = require('http-errors')
const { User } = require('../../../models')

// alloweds
const allowedFields = ['id', 'slug', 'username', 'email', 'mobile', 'nickname', 'avatar', 'status', 'created_at', 'updated_at', 'roles', 'meta']
const allowedInclude = ['posts']

/**
 * GET /users
 *
 * @todo include, filter
 */
exports.index = async ctx => {
  console.log(ctx.parameters)
  const { filter, fields, options, include } = ctx.parameters

  // // exec query
  const total = await User.count(filter)
  const entities = await User.find(filter, fields, options).populate(include)

  ctx.state.pagination = { page: options.page, limit: options.limit, total }
  ctx.state.data = entities.map(item => pick(item, allowedFields.concat(allowedInclude)))
}

/**
 * GET /users/new
 */
exports.new = async ctx => {
  return {}
}

/**
 * POST /users
 * @param  {Object} body input data
 * @return {Object}      output data
 */
exports.create = async ctx => {
  let { slug, username, email, mobile, password, nickname, avatar, status, roles = ['subscriber'], meta } = body

  // params validate
  assert(username, 400, 'Missing required parameter: username.')
  assert(email, 400, 'Missing required parameter: email.')
  assert(password, 400, 'Missing required parameter: password.')

  // roles
  if (typeof roles === 'string') {
    roles = roles.split(',')
  }

  try {
    const entity = await User.create({ slug, username, email, mobile, password, nickname, avatar, status, roles, meta })
    return { status: 201, data: pick(entity, allowedFields) }
  } catch (e) {
    throw createError(422, e)
  }
}

/**
 * GET /users/:id
 * @param  {Object} options input parameters
 * @return {Object}         output data
 */
exports.show = async ctx => {
  const { id, fields = allowedFields } = options
  const entity = await User.findById(id).select(getSelect(fields))
  assert(entity, 404, 'This user does not exist.')
  return { data: pick(entity, allowedFields) }
}

/**
 * GET /users/:id/edit
 * @param  {Object} options input parameters
 * @return {Object}         output data
 */
exports.edit = async ctx => {
  return {}
}

/**
 * PUT /users/:id
 * @param  {Object} body    input data
 * @param  {Object} options input parameters
 * @return {Object}         output data
 */
exports.update = async ctx => {
  const { id } = options
  const { slug, username, email, mobile, password, nickname, avatar, status, roles, meta } = body

  // find exist user
  const exist = await User.findById(id)
  assert(exist, 404, 'This user does not exist.')

  // patch user info

  // exists validate
  if (slug && slug !== exist.slug) {
    const slugExists = await User.findOne({ slug, id: { $ne: exist.id } })
    assert(!slugExists, 422, 'The slug has already existed.')
    exist.slug = slug
  }

  if (username && username !== exist.username) {
    const usernameExists = await User.findOne({ username, id: { $ne: exist.id } })
    assert(!usernameExists, 422, 'The username has already existed.')
    exist.username = username
  }

  if (email && email !== exist.email) {
    const emailExists = await User.findOne({ email, id: { $ne: exist.id } })
    assert(!emailExists, 422, 'The email has already existed.')
    exist.email = email
  }

  if (mobile && mobile !== exist.mobile) {
    const mobileExists = await User.findOne({ mobile, id: { $ne: exist.id } })
    assert(!mobileExists, 422, 'The mobile has already existed.')
    exist.mobile = mobile
  }

  const entity = await exist.save()
  return { data: pick(entity, allowedFields) }
}

/**
 * DELETE /users/:id
 * @param  {Object} options input parameters
 * @return {Object}         output data
 */
exports.destroy = async ctx => {
  const { id } = options
  return { status: 204, data: User.findByIdAndRemove(id) }
}
<commit_msg>:tada: Initial commit<commit_after>/**
 * Users resource controller
 *
 * @see
 * - https://www.mongodb.com/blog/post/password-authentication-with-mongoose-part-1
 * - pick es6 https://gist.github.com/bisubus/2da8af7e801ffd813fab7ac221aa7afc
 */

const { pick } = require('lodash')
const assert = require('http-assert')
const createError = require('http-errors')
const { User } = require('../../../models')

// alloweds
const allowedFields = ['id', 'slug', 'username', 'email', 'mobile', 'nickname', 'avatar', 'status', 'created_at', 'updated_at', 'roles', 'meta']
const allowedInclude = ['posts']

/**
 * GET /users
 *
 * @todo include, filter
 */
exports.index = async ctx => {
  const { filter, fields, options, include } = ctx.parameters

  // // exec query
  const total = await User.count(filter)
  const entities = await User.find(filter, fields, options).populate(include)

  ctx.state.pagination = { page: options.page, limit: options.limit, total }
  ctx.state.data = entities.map(item => pick(item, allowedFields.concat(allowedInclude)))
}

/**
 * GET /users/new
 */
exports.new = async ctx => {
  return {}
}

/**
 * POST /users
 * @param  {Object} body input data
 * @return {Object}      output data
 */
exports.create = async ctx => {
  let { slug, username, email, mobile, password, nickname, avatar, status, roles = ['subscriber'], meta } = body

  // params validate
  assert(username, 400, 'Missing required parameter: username.')
  assert(email, 400, 'Missing required parameter: email.')
  assert(password, 400, 'Missing required parameter: password.')

  // roles
  if (typeof roles === 'string') {
    roles = roles.split(',')
  }

  try {
    const entity = await User.create({ slug, username, email, mobile, password, nickname, avatar, status, roles, meta })
    return { status: 201, data: pick(entity, allowedFields) }
  } catch (e) {
    throw createError(422, e)
  }
}

/**
 * GET /users/:id
 * @param  {Object} options input parameters
 * @return {Object}         output data
 */
exports.show = async ctx => {
  const { id, fields = allowedFields } = options
  const entity = await User.findById(id).select(getSelect(fields))
  assert(entity, 404, 'This user does not exist.')
  return { data: pick(entity, allowedFields) }
}

/**
 * GET /users/:id/edit
 * @param  {Object} options input parameters
 * @return {Object}         output data
 */
exports.edit = async ctx => {
  return {}
}

/**
 * PUT /users/:id
 * @param  {Object} body    input data
 * @param  {Object} options input parameters
 * @return {Object}         output data
 */
exports.update = async ctx => {
  const { id } = options
  const { slug, username, email, mobile, password, nickname, avatar, status, roles, meta } = body

  // find exist user
  const exist = await User.findById(id)
  assert(exist, 404, 'This user does not exist.')

  // patch user info

  // exists validate
  if (slug && slug !== exist.slug) {
    const slugExists = await User.findOne({ slug, id: { $ne: exist.id } })
    assert(!slugExists, 422, 'The slug has already existed.')
    exist.slug = slug
  }

  if (username && username !== exist.username) {
    const usernameExists = await User.findOne({ username, id: { $ne: exist.id } })
    assert(!usernameExists, 422, 'The username has already existed.')
    exist.username = username
  }

  if (email && email !== exist.email) {
    const emailExists = await User.findOne({ email, id: { $ne: exist.id } })
    assert(!emailExists, 422, 'The email has already existed.')
    exist.email = email
  }

  if (mobile && mobile !== exist.mobile) {
    const mobileExists = await User.findOne({ mobile, id: { $ne: exist.id } })
    assert(!mobileExists, 422, 'The mobile has already existed.')
    exist.mobile = mobile
  }

  const entity = await exist.save()
  return { data: pick(entity, allowedFields) }
}

/**
 * DELETE /users/:id
 * @param  {Object} options input parameters
 * @return {Object}         output data
 */
exports.destroy = async ctx => {
  const { id } = options
  return { status: 204, data: User.findByIdAndRemove(id) }
}
<|endoftext|>


<commit_before>/*
---

name: Class.PatternMutators

description: Pattern-Based Mutation for MooTools 1.3

license: MIT-style license.

copyright: Mark Obcena

requires: Class

provides: [Class.defineMutator, Class.define]

...
*/

(function(){

var matchers = [];

var lookup = function(key){
	var i = matchers.length;
	while (i--){
		var matcher = matchers[i],
			match = key.match(matcher);
		if (match) return ['$mutator:' + matcher, match.slice(1)];
	}
	return null;
};

Class.defineMutator = function(key, fn){
	if (typeOf(key) == 'regexp'){
		matchers.push(key);
		key = '$mutator:' + key;
		var _fn = fn;
		fn = function(values){
			return _fn.apply(this, values);
		};
	}
	Class.Mutators[key] = fn;
	return this;
};

var define = Class.prototype.implement;
Class.implement('define', define);

var implement = Class.prototype.implement = function(key, value, retain){
	var mutator = lookup(key);
	if (mutator){
		key = mutator.shift();
		mutator[0].unshift(value);
		value = mutator.shift();
	}
	return define.call(this, key, value, retain);
}.overloadSetter();

// Default Mutators
Class.defineMutator(/^protected\s(\w+)/, function(fn, name){
	this.define(name, fn.protect());
});

Class.defineMutator(/^linked\s(\w+)/, function(value, name){
	this.prototype[name] = value;
});

Class.defineMutator(/^static\s(\w+)/, function(fn, name){
	this.extend(name, fn);
});

// Reimplement "implement" in all classes..
for (var i in window){
	try{
		var klass = window[i];
		if (klass instanceof Function && typeOf(klass) == 'class'){
			klass.implement = implement;
			klass.define = define;
		}
	}catch(x){
	}
}

})();
<commit_msg>* Style fix.<commit_after>/*
---

name: Class.PatternMutators

description: Pattern-Based Mutation for MooTools 1.3

license: MIT-style license.

copyright: Mark Obcena

requires: Class

provides: [Class.defineMutator, Class.define]

...
*/

(function(){

var matchers = [];

var lookup = function(key){
	var i = matchers.length;
	while (i--){
		var matcher = matchers[i],
			match = key.match(matcher);
		if (match) return ['$mutator:' + matcher, match.slice(1)];
	}
	return null;
};

Class.defineMutator = function(key, fn){
	if (typeOf(key) == 'regexp'){
		matchers.push(key);
		key = '$mutator:' + key;
		var _fn = fn;
		fn = function(values){
			return _fn.apply(this, values);
		};
	}
	Class.Mutators[key] = fn;
	return this;
};

var define = Class.prototype.implement;
Class.implement('define', define);

var implement = Class.prototype.implement = function(key, value, retain){
	var mutator = lookup(key);
	if (mutator){
		key = mutator.shift();
		mutator[0].unshift(value);
		value = mutator.shift();
	}
	return define.call(this, key, value, retain);
}.overloadSetter();

// Default Mutators
Class.defineMutator(/^protected\s(\w+)/, function(fn, name){
	this.define(name, fn.protect());
});

Class.defineMutator(/^linked\s(\w+)/, function(value, name){
	this.prototype[name] = value;
});

Class.defineMutator(/^static\s(\w+)/, function(fn, name){
	this.extend(name, fn);
});

// Reimplement "implement" in all classes..
for (var i in window){
	try {
		var klass = window[i];
		if (klass instanceof Function && typeOf(klass) == 'class'){
			klass.implement = implement;
			klass.define = define;
		}
	} catch(e){}
}

})();
<|endoftext|>