<commit_before>/*#ifndef(UMD)*/
(function () { /* Begin of privacy scope */
    "use strict";
/*#endif*/

    /**
     * Process the options and dump the boot message
     *
     * @param {Object|String[]} options
     * @return {Object} The parsed options
     * @private
     */
    function _processOptions (options) {
        // Options parsing
        var
            name,
            maxLen;
        if (options instanceof Array) {
            options = gpf.Parameter.parse([{
                name: "port",
                type: "number",
                defaultValue: 80,
                prefix: "port"
            }, {
                name: "root",
                type: "string",
                defaultValue: ".",
                prefix: "root"
            }, {
                name: "chunkSize",
                type: "number",
                defaultValue: 65536,
                prefix: "chunk"
            }, gpf.Parameter.VERBOSE, gpf.Parameter.HELP], options);
        }
        // Server boot trace
        console.log("GPF " + gpf.version() + " web server");
        if (options.root === ".") {
            options.root = process.cwd();
        }
        if (options.verbose) {
            maxLen = 0;
            for (name in options) {
                if (options.hasOwnProperty(name)) {
                    if (name.length > maxLen) {
                        maxLen = name.length;
                    }
                }
            }
            ++maxLen;
            for (name in options) {
                if (options.hasOwnProperty(name)) {
                    console.log([
                        "\t",
                        name,
                        (new Array(maxLen - name.length + 1)).join(" "),
                        ": ",
                        options[name]
                    ].join(""));
                }
            }
        }
        return options;
    }

    var
        /**
         * NodeJS modules that will be loaded
         */
        _http = null,
        _url = null,
        _path = null,
        _fs = null,

        /**
         * Placeholder class to extend the NodeJS response class and provide
         * more context to it
         *
         * @class ResponseHandler
         * @private
         */
        ResponseHandler = gpf.define("ResponseHandler", {

            private: {

                /**
                 * Web server options
                 *
                 * @type {Object}
                 * @private
                 */
                _options: null,

                /**
                 * Request
                 *
                 * @type {NodeJS.http.IncomingMessage}
                 * @private
                 */
                _request: null,

                /**
                 * Response
                 *
                 * @type {NodeJS.http.ServerResponse}
                 * @private
                 */
                _response: null,

                /**
                 * Parsed URL object (see NodeJS url.parse documentation)
                 *
                 * @type {Object}
                 * @private
                 */
                _parsedUrl: null,

                /**
                 * Corresponding file path
                 *
                 * @type {String}
                 * @private
                 */
                _filePath: "",

                /**
                 * File extension (lowercase)
                 *
                 * @type {String}
                 * @private
                 */
                _extName: "",

                /**
                 * For performance reasons, I keep track of the time spent
                 *
                 * @type {Date}
                 * @private
                 */
                _startTimeStamp: null

            },

            public: {

                /**
                 * @param {Object} options Web server options
                 * @param {NodeJS.http.IncomingMessage} request
                 * @param {NodeJS.http.ServerResponse} response
                 * @constructor
                 */
                constructor: function (options, request, response) {
                    this._startTimeStamp = new Date();
                    this._options = options;
                    this._request = request;
                    this._response = response;
                    // Parse and analyse URL
                    this._parsedUrl = _url.parse(request.url);
                    this._filePath = _path.join(
                        this._options.root,
                        this._parsedUrl.pathname
                    );
                    this._extName = _path.extname(this._filePath).toLowerCase();
                    // Extend response
                    response._gpf = this;
                    response.plain = ResponseHandler._plain;
                },

                /**
                 * Process the request
                 */
                process: function () {
                    if (_fs.existsSync(this._filePath)) {
                        if (".jsp" === this._extName) {
                            this.plain(500, "JSP not handled yet");
                        } else {
                            this.fromFile(this._filePath);
                        }
                    } else {
                        this.plain(404, "No file found");
                    }
                },

                /**
                 * Generates a PLAIN response to the server
                 *
                 * @param {Number} statusCode
                 * @param {String} text
                 */
                plain: function (statusCode, text) {
                    var resp = this._response;
                    resp.writeHead(statusCode, {"Content-Type": "text/plain"});
                    resp.write([
                        "port    : " + this._options.port,
                        "method  : " + this._request.method,
                        "url     : " + this._request.url,
                        "root    : " + this._options.root,
                        "path    : " + this._filePath,
                        "headers : "
                        + JSON.stringify(this._request.headers, null, "\t\t"),
                        text
                    ].join("\n"));
                    resp.end();
                },

                /**
                 * Generates a response that contains the specified file
                 *
                 * @param {String} filePath
                 * @private
                 * @closure (a lot)
                 */
                fromFile: function (filePath) {
                    var
                        me = this,
                        extName = _path.extname(filePath).toLowerCase(),
                        chunkSize = me._options.chunkSize,
                        buffer,
                        pos = 0,
                        size,
                        fileDescriptor,
                        close,
                        read,
                        write;
                    close = function () {
                        if (fileDescriptor) {
                            _fs.close(fileDescriptor);
                        }
                        if (me._options.verbose) {
                            console.log("\tFile handle: " + fileDescriptor);
                            console.log("\tEnd      t+: "
                            + ((new Date()) - me._startTimeStamp)
                            + "ms");
                        }
                        me._response.end();
                    };
                    read = function () {
                        var len = size - pos;
                        if (0 === len) {
                            // Done
                            close();
                            return;
                        }
                        if (len > chunkSize) {
                            len = chunkSize;
                        }
                        _fs.read(fileDescriptor, buffer, 0, len, pos, write);
                    };
                    write = function (err, bytesRead, buffer) {
                        if (err) {
                            // Partly answered, close the answer and dump error
                            console.error([
                                "Error while sending '",
                                filePath,
                                "' (",
                                err,
                                ")"
                            ].join(""));
                            close();
                            return;
                        }
                        pos += bytesRead;
                        me._response.write(buffer, read);
                    };
                    _fs.stat(filePath, function (err, stats) {
                        var mimeType;
                        if (err) {
                            me._response.plain(500,
                                "Unable to access file (" + err + ")");
                            return;
                        }
                        if (stats.isDirectory()) {
                            me._response.plain(200, "Directory.");
                            return;
                        } else if (!stats.isFile()) {
                            me._response.plain(200, "Not a file.");
                            return;
                        }
                        size = stats.size;
                        mimeType = gpf.http.getMimeType(extName);
                        if (me._options.verbose) {
                            console.log("\tMime type  : " + mimeType);
                            console.log("\tFile size  : " + size);
                        }
                        _fs.open(filePath, "r", function (err, fd) {
                            if (err) {
                                me._response.plain(500,
                                    "Unable to open file (" + err + ")");
                                return;
                            }
                            me._response.writeHead(200, {
                                "Content-Type": mimeType,
                                "Content-Length": size
                            });
                            fileDescriptor = fd;
                            if (me._options.verbose) {
                                console.log("\tFile handle: " + fd);
                                console.log("\tStart    t+: "
                                    + ((new Date()) - me._startTimeStamp)
                                    + "ms");
                            }
                            buffer = new Buffer(chunkSize);
                            read();
                        });
                    });
                }

            },

            static: {

                /**
                 * Generates a PLAIN response to the server
                 *
                 * @param {Number} statusCode
                 * @param {String} text
                 * @private
                 */
                _plain: function (statusCode, text) {
                    return this._gpf.plain(statusCode, text);
                },

                /**
                 * Generates a response that contains the specified file
                 *
                 * @param {String} filePath
                 * @private
                 */
                _fromFile: function (filePath) {
                    return this._gpf.fromFile(filePath);
                }

            }
        });

    /**
     * Run the GPF web server
     *
     * @param {String[]|Object|undefined} options
     */
    gpf.runWebServer = function (options) {
        options = _processOptions(options);
        // Expose ExtJS require
        global.require = require;
        // Load the modules that are needed
        _http = require("http");
        _url = require("url");
        _path = require("path");
        _fs = require("fs");
        // Build the web server
        _http.createServer(function (request, response) {
            if (options.verbose) {
                console.log([
                    request.method,
                    "     ".substr(request.method.length),
                    request.url
                ].join(""));
            }
            var handler = new ResponseHandler(options, request, response);
            handler.process();
        }).on("close", function () {
            console.log("Closed.");
        }).listen(options.port);
        if (options.verbose) {
            console.log("Listening... (CTRL+C to stop)");
        }
    };

    /**
     * Detect if the library was run as a standalone file, in that case, run
     * the web server.
     */
    (function () {
        var
            path,
            scriptName;
        if ("nodejs" !== gpf.host()) {
            return; // Not inside nodejs
        }
        path = require("path");
        scriptName = path.basename(process.argv[1], ".js");
        if (scriptName === "boot"
            || scriptName === "gpf"
            || scriptName === "gpf-debug") {
            gpf.runWebServer(process.argv.slice(2));
        }
    }());

/*#ifndef(UMD)*/
}()); /* End of privacy scope */
/*#endif*/<commit_msg>Found the slowness reason<commit_after>/*#ifndef(UMD)*/
(function () { /* Begin of privacy scope */
    "use strict";
/*#endif*/

    /**
     * Process the options and dump the boot message
     *
     * @param {Object|String[]} options
     * @return {Object} The parsed options
     * @private
     */
    function _processOptions (options) {
        // Options parsing
        var
            name,
            maxLen;
        if (options instanceof Array) {
            options = gpf.Parameter.parse([{
                name: "port",
                type: "number",
                defaultValue: 80,
                prefix: "port"
            }, {
                name: "root",
                type: "string",
                defaultValue: ".",
                prefix: "root"
            }, {
                name: "chunkSize",
                type: "number",
                defaultValue: 65536,
                prefix: "chunk"
            }, gpf.Parameter.VERBOSE, gpf.Parameter.HELP], options);
        }
        // Server boot trace
        console.log("GPF " + gpf.version() + " web server");
        if (options.root === ".") {
            options.root = process.cwd();
        }
        if (options.verbose) {
            maxLen = 0;
            for (name in options) {
                if (options.hasOwnProperty(name)) {
                    if (name.length > maxLen) {
                        maxLen = name.length;
                    }
                }
            }
            ++maxLen;
            for (name in options) {
                if (options.hasOwnProperty(name)) {
                    console.log([
                        "\t",
                        name,
                        (new Array(maxLen - name.length + 1)).join(" "),
                        ": ",
                        options[name]
                    ].join(""));
                }
            }
        }
        return options;
    }

    var
        /**
         * NodeJS modules that will be loaded
         */
        _http = null,
        _url = null,
        _path = null,
        _fs = null,

        /**
         * Placeholder class to extend the NodeJS response class and provide
         * more context to it
         *
         * @class ResponseHandler
         * @private
         */
        ResponseHandler = gpf.define("ResponseHandler", {

            private: {

                /**
                 * Web server options
                 *
                 * @type {Object}
                 * @private
                 */
                _options: null,

                /**
                 * Request
                 *
                 * @type {NodeJS.http.IncomingMessage}
                 * @private
                 */
                _request: null,

                /**
                 * Response
                 *
                 * @type {NodeJS.http.ServerResponse}
                 * @private
                 */
                _response: null,

                /**
                 * Parsed URL object (see NodeJS url.parse documentation)
                 *
                 * @type {Object}
                 * @private
                 */
                _parsedUrl: null,

                /**
                 * Corresponding file path
                 *
                 * @type {String}
                 * @private
                 */
                _filePath: "",

                /**
                 * File extension (lowercase)
                 *
                 * @type {String}
                 * @private
                 */
                _extName: "",

                /**
                 * For performance reasons, I keep track of the time spent
                 *
                 * @type {Date}
                 * @private
                 */
                _startTimeStamp: null

            },

            public: {

                /**
                 * @param {Object} options Web server options
                 * @param {NodeJS.http.IncomingMessage} request
                 * @param {NodeJS.http.ServerResponse} response
                 * @constructor
                 */
                constructor: function (options, request, response) {
                    this._startTimeStamp = new Date();
                    this._options = options;
                    this._request = request;
                    this._response = response;
                    // Parse and analyse URL
                    this._parsedUrl = _url.parse(request.url);
                    this._filePath = _path.join(
                        this._options.root,
                        this._parsedUrl.pathname
                    );
                    this._extName = _path.extname(this._filePath).toLowerCase();
                    // Extend response
                    response._gpf = this;
                    response.plain = ResponseHandler._plain;
                },

                /**
                 * Process the request
                 */
                process: function () {
                    if (_fs.existsSync(this._filePath)) {
                        if (".jsp" === this._extName) {
                            this.plain(500, "JSP not handled yet");
                        } else {
                            this.fromFile(this._filePath);
                        }
                    } else {
                        this.plain(404, "No file found");
                    }
                },

                /**
                 * Generates a PLAIN response to the server
                 *
                 * @param {Number} statusCode
                 * @param {String} text
                 */
                plain: function (statusCode, text) {
                    var resp = this._response;
                    resp.writeHead(statusCode, {"Content-Type": "text/plain"});
                    resp.write([
                        "port    : " + this._options.port,
                        "method  : " + this._request.method,
                        "url     : " + this._request.url,
                        "root    : " + this._options.root,
                        "path    : " + this._filePath,
                        "headers : "
                        + JSON.stringify(this._request.headers, null, "\t\t"),
                        text
                    ].join("\n"));
                    resp.end();
                },

                /**
                 * Generates a response that contains the specified file
                 *
                 * @param {String} filePath
                 * @private
                 * @closure (a lot)
                 */
                fromFile: function (filePath) {
                    var
                        me = this,
                        extName = _path.extname(filePath).toLowerCase(),
                        chunkSize = me._options.chunkSize,
                        buffer,
                        pos = 0,
                        size,
                        fileDescriptor,
                        close,
                        read,
                        write,
                        waitForDrain,
                        drain;
                    close = function () {
                        if (fileDescriptor) {
                            _fs.close(fileDescriptor);
                        }
                        if (me._options.verbose) {
                            console.log("\tFile handle: " + fileDescriptor);
                            console.log("\tEnd      t+: "
                            + ((new Date()) - me._startTimeStamp)
                            + "ms");
                        }
                        me._response.end();
                    };
                    read = function () {
                        var len = size - pos;
                        if (0 === len) {
                            // Done
                            close();
                            return;
                        }
                        if (len > chunkSize) {
                            len = chunkSize;
                        }
                        _fs.read(fileDescriptor, buffer, 0, len, pos, write);
                    };
                    write = function (err, bytesRead, buffer) {
                        if (err) {
                            // Partly answered, close the answer and dump error
                            console.error([
                                "Error while sending '",
                                filePath,
                                "' (",
                                err,
                                ")"
                            ].join(""));
                            close();
                            return;
                        }
                        pos += bytesRead;
                        if (!me._response.write(buffer, drain)) {
                            waitForDrain = true;
                        }
                    };
                    drain = function () {
                        if (waitForDrain) {
                            console.warn("\tWaiting for drain");
                            me._response.once("drain", function () {
                                console.warn("\tDrained");
                                waitForDrain = false;
                                read();
                            });
                        } else {
                            read();
                        }
                    };
                    _fs.stat(filePath, function (err, stats) {
                        var mimeType;
                        if (err) {
                            me._response.plain(500,
                                "Unable to access file (" + err + ")");
                            return;
                        }
                        if (stats.isDirectory()) {
                            me._response.plain(200, "Directory.");
                            return;
                        } else if (!stats.isFile()) {
                            me._response.plain(200, "Not a file.");
                            return;
                        }
                        size = stats.size;
                        mimeType = gpf.http.getMimeType(extName);
                        if (me._options.verbose) {
                            console.log("\tMime type  : " + mimeType);
                            console.log("\tFile size  : " + size);
                        }

                        // Fastest implementation
                        if (false) {
                            me._response.writeHead(200, {
                                "content-type": mimeType,
                                "content-length": size
                            });
                            if (me._options.verbose) {
                                console.log("\tStart    t+: "
                                + ((new Date()) - me._startTimeStamp)
                                + "ms");
                            }
                            var stream = _fs.createReadStream(filePath);
                            stream.pipe(me._response);
                            stream.on("end", function () {
                                if (me._options.verbose) {
                                    console.log("\tEnd      t+: "
                                    + ((new Date()) - me._startTimeStamp)
                                    + "ms");
                                }
                                me._response.statusCode = 200;
                                me._response.end();
                            });
                            return;
                        }

                        // Slowest implementation
                        _fs.open(filePath, "r", function (err, fd) {
                            if (err) {
                                me._response.plain(500,
                                    "Unable to open file (" + err + ")");
                                return;
                            }
                            me._response.writeHead(200, {
                                "content-type": mimeType,
                                "content-length": size
                            });
                            fileDescriptor = fd;
                            if (me._options.verbose) {
                                console.log("\tFile handle: " + fd);
                                console.log("\tStart    t+: "
                                    + ((new Date()) - me._startTimeStamp)
                                    + "ms");
                            }
                            buffer = new Buffer(chunkSize);
                            read();
                        });
                    });
                }

            },

            static: {

                /**
                 * Generates a PLAIN response to the server
                 *
                 * @param {Number} statusCode
                 * @param {String} text
                 * @private
                 */
                _plain: function (statusCode, text) {
                    return this._gpf.plain(statusCode, text);
                },

                /**
                 * Generates a response that contains the specified file
                 *
                 * @param {String} filePath
                 * @private
                 */
                _fromFile: function (filePath) {
                    return this._gpf.fromFile(filePath);
                }

            }
        });

    /**
     * Run the GPF web server
     *
     * @param {String[]|Object|undefined} options
     */
    gpf.runWebServer = function (options) {
        options = _processOptions(options);
        // Expose ExtJS require
        global.require = require;
        // Load the modules that are needed
        _http = require("http");
        _url = require("url");
        _path = require("path");
        _fs = require("fs");
        // Build the web server
        _http.createServer(function (request, response) {
            if (options.verbose) {
                console.log([
                    request.method,
                    "     ".substr(request.method.length),
                    request.url
                ].join(""));
            }
            var handler = new ResponseHandler(options, request, response);
            handler.process();
        }).on("close", function () {
            console.log("Closed.");
        }).listen(options.port, function () {
            if (options.verbose) {
                console.log("Listening... (CTRL+C to stop)");
            }
        });
    };

    /**
     * Detect if the library was run as a standalone file, in that case, run
     * the web server.
     */
    (function () {
        var
            path,
            scriptName;
        if ("nodejs" !== gpf.host()) {
            return; // Not inside nodejs
        }
        path = require("path");
        scriptName = path.basename(process.argv[1], ".js");
        if (scriptName === "boot"
            || scriptName === "gpf"
            || scriptName === "gpf-debug") {
            gpf.runWebServer(process.argv.slice(2));
        }
    }());

/*#ifndef(UMD)*/
}()); /* End of privacy scope */
/*#endif*/<|endoftext|>


<commit_before>(function () {

  var scriptName = 'widget.js';
  var jqueryPath = 'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.3/jquery.min.js';
  var jqueryVersion = '1.12.3';
  var scriptTag;
  var pathLocal = './app/';
  var pathCDN = 'https://s3.amazonaws.com/campaign-zero-widget/';
  var elementName = 'campaign-zero-widget';
  var loadedCSS = false;
  var loadedJS = false;
  var version = '1.0.3';

  /** Get reference to self (scriptTag) */
  var allScripts = document.getElementsByTagName('script');
  var targetScripts = [];

  /** Helper function to load external scripts */
  function loadScript(src, onLoad) {
    var script_tag = document.createElement('script');
        script_tag.setAttribute('type', 'text/javascript');
        script_tag.setAttribute('src', src);

    if (script_tag.readyState) {
      script_tag.onreadystatechange = function () {
        if (this.readyState == 'complete' || this.readyState == 'loaded') {
          onLoad();
        }
      };
    } else {
      script_tag.onload = onLoad;
    }

    // append loaded script to head
    (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(script_tag);
  }

  /** Helper function to load external css  */
  function loadCss(href, onLoad) {
    var link_tag = document.createElement('link');
        link_tag.setAttribute('type', 'text/css');
        link_tag.setAttribute('rel', 'stylesheet');
        link_tag.setAttribute('href', href);

    if (link_tag.readyState) {
      link_tag.onreadystatechange = function () {
        if (this.readyState == 'complete' || this.readyState == 'loaded') {
          onLoad();
        }
      };
    } else {
      link_tag.onload = onLoad;
    }

    // append loaded style sheet to head
    (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(link_tag);
  }

  /** Check if jQuery is already on page, otherwise load it */
  if (window.jQuery === undefined || window.jQuery.fn.jquery !== jqueryVersion) {
    loadScript(jqueryPath, init);
  } else {
    init();
  }

  /** Initialize widget */
  function init() {

    // figure out scripts on the page
    for (var i in allScripts) {
      var name = allScripts[i].src;
      if(name && name.indexOf(scriptName) > 0) {
        targetScripts.push(allScripts[i]);
      }
    }

    // reference scripts position on the page
    scriptTag = targetScripts[targetScripts.length - 1];

    // check if this is production
    var assets = (scriptTag.src && scriptTag.src === 'https://embed.joincampaignzero.org/widget.js') ? pathCDN : pathLocal;

    // load widget css before DOM ready
    loadCss(assets + 'style.css?v=' + version, function(){
      loadedCSS = true;
      if(typeof appWidget !== 'undefined' && loadedCSS && loadedJS){
        appWidget.init();
      }
    });

    // wait for DOM ready to load other script to prevent page blocking
    jQuery(document).ready(function ($) {

      // check for existing element, otherwise create it
      if(jQuery('#' + elementName).length === 0){
        jQuery('

').insertBefore(scriptTag);
      }

      // Load Required Libraries first then init widget
      loadScript('https://www.google-analytics.com/analytics.js', function(){
        if(typeof window.ga !== 'undefined'){
          ga('create', 'UA-77948909-1', 'auto', 'campaignZeroWidget');
          ga('campaignZeroWidget.send', 'pageview');
        }

        // load widgets main app's script file
        loadScript(assets + 'app.js?v=' + version, function(){
          loadedJS = true;
          if(typeof appWidget !== 'undefined' && loadedCSS && loadedJS){
            appWidget.init();
          }
        });
      });
    });
  }
})();
<commit_msg>Forgot to update version number<commit_after>(function () {

  var scriptName = 'widget.js';
  var jqueryPath = 'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.3/jquery.min.js';
  var jqueryVersion = '1.12.3';
  var scriptTag;
  var pathLocal = './app/';
  var pathCDN = 'https://s3.amazonaws.com/campaign-zero-widget/';
  var elementName = 'campaign-zero-widget';
  var loadedCSS = false;
  var loadedJS = false;
  var version = '1.0.4';

  /** Get reference to self (scriptTag) */
  var allScripts = document.getElementsByTagName('script');
  var targetScripts = [];

  /** Helper function to load external scripts */
  function loadScript(src, onLoad) {
    var script_tag = document.createElement('script');
        script_tag.setAttribute('type', 'text/javascript');
        script_tag.setAttribute('src', src);

    if (script_tag.readyState) {
      script_tag.onreadystatechange = function () {
        if (this.readyState == 'complete' || this.readyState == 'loaded') {
          onLoad();
        }
      };
    } else {
      script_tag.onload = onLoad;
    }

    // append loaded script to head
    (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(script_tag);
  }

  /** Helper function to load external css  */
  function loadCss(href, onLoad) {
    var link_tag = document.createElement('link');
        link_tag.setAttribute('type', 'text/css');
        link_tag.setAttribute('rel', 'stylesheet');
        link_tag.setAttribute('href', href);

    if (link_tag.readyState) {
      link_tag.onreadystatechange = function () {
        if (this.readyState == 'complete' || this.readyState == 'loaded') {
          onLoad();
        }
      };
    } else {
      link_tag.onload = onLoad;
    }

    // append loaded style sheet to head
    (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(link_tag);
  }

  /** Check if jQuery is already on page, otherwise load it */
  if (window.jQuery === undefined || window.jQuery.fn.jquery !== jqueryVersion) {
    loadScript(jqueryPath, init);
  } else {
    init();
  }

  /** Initialize widget */
  function init() {

    // figure out scripts on the page
    for (var i in allScripts) {
      var name = allScripts[i].src;
      if(name && name.indexOf(scriptName) > 0) {
        targetScripts.push(allScripts[i]);
      }
    }

    // reference scripts position on the page
    scriptTag = targetScripts[targetScripts.length - 1];

    // check if this is production
    var assets = (scriptTag.src && scriptTag.src === 'https://embed.joincampaignzero.org/widget.js') ? pathCDN : pathLocal;

    // load widget css before DOM ready
    loadCss(assets + 'style.css?v=' + version, function(){
      loadedCSS = true;
      if(typeof appWidget !== 'undefined' && loadedCSS && loadedJS){
        appWidget.init();
      }
    });

    // wait for DOM ready to load other script to prevent page blocking
    jQuery(document).ready(function ($) {

      // check for existing element, otherwise create it
      if(jQuery('#' + elementName).length === 0){
        jQuery('

').insertBefore(scriptTag);
      }

      // Load Required Libraries first then init widget
      loadScript('https://www.google-analytics.com/analytics.js', function(){
        if(typeof window.ga !== 'undefined'){
          ga('create', 'UA-77948909-1', 'auto', 'campaignZeroWidget');
          ga('campaignZeroWidget.send', 'pageview');
        }

        // load widgets main app's script file
        loadScript(assets + 'app.js?v=' + version, function(){
          loadedJS = true;
          if(typeof appWidget !== 'undefined' && loadedCSS && loadedJS){
            appWidget.init();
          }
        });
      });
    });
  }
})();
<|endoftext|>


<commit_before>/*
  Taskforce Widget
  A generic widget include script which we will use to show further campaigns etc
  <thomasalwyndavis@gmail.com> for support
/*

/* <script type="text/javascript">
    window._idl = {};
    _idl.variant = "modal";
    _idl.campaign = "defundnsa";
    (function() {
        var idl = document.createElement('script');
        idl.type = 'text/javascript';
        idl.async = true;
        idl.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'members.internetdefenseleague.org/include/?url=' + (_idl.url || '') + '&_idl_test=1&campaign=' + (_idl.campaign || '') + '&variant=' + (_idl.variant || 'banner');
        document.getElementsByTagName('body')[0].appendChild(idl);
    })();
</script>

*/

var causes = {
  stopwatchingus: {

  }
}

<commit_msg>removing master branch<commit_after>/*
  Taskforce Widget
  A generic widget include script which we will use to show further campaigns etc
  <thomasalwyndavis@gmail.com> for support
/*

/* <script type="text/javascript">
    window._idl = {};
    _idl.variant = "modal";
    _idl.campaign = "defundnsa";
    (function() {
        var idl = document.createElement('script');
        idl.type = 'text/javascript';
        idl.async = true;
        idl.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'members.internetdefenseleague.org/include/?url=' + (_idl.url || '') + '&_idl_test=1&campaign=' + (_idl.campaign || '') + '&variant=' + (_idl.variant || 'banner');
        document.getElementsByTagName('body')[0].appendChild(idl);
    })();
</script>

http://geoip.taskforce.is/64.64.64.64

*/

var causes = {
  stopwatchingus: {

  }
}

<|endoftext|>


<commit_before>// UI code.
"use strict";

var textarea = document.querySelector('textarea');
var errlog = document.querySelector('#errlog');

function toArray(nodeList) {
  return Array.prototype.slice.call(nodeList);
}

function showError(err) {
  console.error(err, err.stack);
  errlog.textContent += err + '\n';
}

///////////
// Dirty //
///////////

var dirtMonitor = (function() {
  var isDirty = false;
  var titlebar = document.querySelector('.titlebar');
  var setDirty = function() {
    if (!isDirty) {
      isDirty = true;
      titlebar.classList.add('dirty');
    }
  };
  var setClean = function() {
    if (isDirty) {
      isDirty = false;
      titlebar.classList.remove('dirty');
    }
  };
  return {
    isDirty: function() { return isDirty; },
    setDirty: setDirty,
    setClean: setClean
  };
})();

////////////
// Search //
////////////

var search = (function() {

  var index;
  var listItems;
  var selected = null;

  function createIndex() {
    index = lunr(function() {
      this.field('title', {boost: 10});
      this.field('text');
      this.ref('id');
    });
    DB.getNotes().forEach(function(n) { index.add(n); });
  }

  function setSelected(opt_index) {
    // Calling setSelected without an index just persists any textarea changes.
    var i = (typeof opt_index === 'number') ? opt_index : selected;

    if (typeof selected === "number") {
      // Store any edits before switching note.
      DB.getNotes()[selected] = DB.parseNote(textarea.value);  // HACK
      var listItem = document.querySelector('#noteList ul').children[selected];
      fillListItem(listItem, DB.getNotes()[selected]);
      listItem.classList.remove('selected');
    }
    selected = i;
    document.querySelector('#noteList ul')
        .children[selected]
        .classList.add('selected');
    // Set textarea to current note.
    updateTextArea(DB.getNotes()[i].text);
  }

  function showAll() {
    listItems.forEach(function(item) { item.style.display = ''; });
  }

  function hideAll() {
    listItems.forEach(function(item) { item.style.display = 'none'; });
  }

  function onInput(e) {
    var q = e.target.value;
    if (!q.length) {
      showAll();
      return;
    }

    var results = index.search(q);
    hideAll();
    results.forEach(function(r) {
      var i = parseInt(r.ref, 10);
      listItems[i].style.display = '';
    });
    // TOOD(wdm) Something with score?
  }

  function fillListItem(li, note) {
    li.children[0].textContent = note.title;
    li.children[1].textContent = note.summary;
  }

  function updateNoteList() {
    listItems = [];
    var ul = document.createElement('ul');
    DB.getNotes().forEach(function(note) {
      var li = document.createElement('li');
      li.innerHTML = '';
      fillListItem(li, note);
      ul.appendChild(li);
      listItems.push(li);
    });
    document.querySelector('#noteList').appendChild(ul);
    setSelected(0);  // HACK?
  }

  function onClickList(e) {
    var target = e.target;
    // This is a nasty hack to move clicks on the  tags up to their
.
    if (target.parentNode.nodeName == 'LI') {
      target = target.parentNode;
    }
    if (target.nodeName !== 'LI') {
      return;
    }
    var list = toArray(document.querySelector('#noteList ul').children);
    var i = list.indexOf(target);
    setSelected(i);
  }

  function init() {
    updateNoteList();
    createIndex();
  }

  return {
    onInput: onInput,
    onClickList: onClickList,
    setSelected: setSelected,
    init: init
  };
})();

////////
// DB //
////////

var DB = (function() {

  // TODO(wdm) Check that SEPERATOR does not appear in notes.
  var SEPERATOR = '\n[//]: # (NVC: Do not edit this line)\n\n';

  // In memory note objects.
  var notes = [];

  function parseDB(rawText) {
    var rawNotes = rawText.split(SEPERATOR);
    notes = rawNotes.map(parseNote);
    search.init();
  }

  function parseNote(rawNote, i) {
    var firstLine = rawNote.indexOf('\n');
    return {
      id: i,
      title: rawNote.substring(0, firstLine),
      summary: rawNote.substring(firstLine + 1, 50),
      text: rawNote
    };
  }

  // TODO(wdm) Better name!
  function notesAsBlob() {
    search.setSelected();  // Grabs any changes in textarea.
    var texts = notes.map(function(note) { return note.text; });
    var rawText = texts.join(SEPERATOR);
    return new Blob([rawText], {
      type:
        'text/plain'
    });
  }
  return {
    parseDB: parseDB,
    parseNote: parseNote,
    notesAsBlob: notesAsBlob,
    getNotes: function() { return notes; }
  };
})();

//////////////
// TextArea //
//////////////

function updateTextArea(text) {
  textarea.value = text;
  // textarea.focus();
  // TODO(wdm) Restore actual previous position.
  // textarea.setSelectionRange(0, 0);
  // textarea.scrollTop = 0;
}

function setCaret(elem, pos) {
  var range = elem.createTextRange();
  range.collapse(true);
  range.moveEnd('character', pos);
  range.moveStart('character', pos);
  range.select();
}

///////////////
/// File UI ///
///////////////

var fileEntry;

function onChooseFile() {
  chooseFile().then(showFilename).catch(showError);
}

function showFilename(fileEntry_) {
  fileEntry = fileEntry_;
  document.querySelector('#filename').textContent = fileEntry.name;
  return fileEntry;
}

function doSave() {
  if (!dirtMonitor.isDirty) {
    console.log('save skipped: not dirty');
    return Promise.resolve();
  }
  var blob = DB.notesAsBlob();
  return writeFileEntry(fileEntry, blob)
      .then(dirtMonitor.setClean)
      .catch(showError);
}

function doClose() {
  doSave().then(window.close);
}

//////////////////
// Key Handling //
//////////////////

var CODE_W = 'W'.charCodeAt(0);
var CODE_S = 'S'.charCodeAt(0);
var CODE_1 = '1'.charCodeAt(0);
var CODE_ESC = 27;
var CODE_ENTER = 13;

function onKeydown(e) {
  // Dismiss (with save): ESCAPE, Alt-1, Ctrl-W
  if ((e.keyCode === CODE_ESC) || (e.altKey && e.keyCode === CODE_1) ||
      (e.ctrlKey && e.keyCode === CODE_W)) {
    e.preventDefault();
    doClose();
    return;
  }

  // Save: Ctrl-S
  if (e.ctrlKey && e.keyCode === CODE_S) {
    e.preventDefault();
    doSave();
    return;
  }

  // New note (press enter in the search box)
  if (e.keyCode == CODE_ENTER && e.target.id === "search") {
    // TODO(wdm) doNewNote();
  }
}

function init() {
  restoreChosenFile()
      .then(showFilename)
      .then(loadFileEntry)
      .then(DB.parseDB)
      .catch(showError);

  window.addEventListener('keydown', onKeydown);
  textarea.addEventListener('input', dirtMonitor.setDirty);
  document.querySelector('#chooseFile').addEventListener('click', onChooseFile);
  document.querySelector('#noteList')
      .addEventListener('click', search.onClickList);
  document.querySelector('#search').addEventListener('input', search.onInput);
}

init();
<commit_msg>moved notes from DB to model.<commit_after>// UI code.
"use strict";

var textarea = document.querySelector('textarea');
var errlog = document.querySelector('#errlog');

function toArray(nodeList) {
  return Array.prototype.slice.call(nodeList);
}

function showError(err) {
  console.error(err, err.stack);
  errlog.textContent += err + '\n';
}

///////////
// Dirty //
///////////

var dirtMonitor = (function() {
  var isDirty = false;
  var titlebar = document.querySelector('.titlebar');
  var setDirty = function() {
    if (!isDirty) {
      isDirty = true;
      titlebar.classList.add('dirty');
    }
  };
  var setClean = function() {
    if (isDirty) {
      isDirty = false;
      titlebar.classList.remove('dirty');
    }
  };
  return {
    isDirty: function() { return isDirty; },
    setDirty: setDirty,
    setClean: setClean
  };
})();

////////////
// Search //
////////////

var search = (function() {

  var index;
  var listItems;
  var selected = null;

  function createIndex(notes) {
    index = lunr(function() {
      this.field('title', {boost: 10});
      this.field('text');
      this.ref('id');
    });
    notes.forEach(function(n) { index.add(n); });
  }

  function setSelected(opt_index) {
    // Calling setSelected without an index just persists any textarea changes.
    var i = (typeof opt_index === 'number') ? opt_index : selected;

    if (typeof selected === "number") {
      // Store any edits before switching note.
      var updatedNote = DB.parseNote(textarea.value);
      model.setNote(selected, updatedNote);
      var listItem = document.querySelector('#noteList ul').children[selected];
      fillListItem(listItem, updatedNote);
      listItem.classList.remove('selected');
    }
    selected = i;
    var listItem = document.querySelector('#noteList ul').children[selected];
    if (!listItem) {
      console.warn('selected invalid', selected);
      return;
    }
    listItem.classList.add('selected');
    // Set textarea to current note.
    updateTextArea(model.getNote(selected));
  }

  function showAll() {
    listItems.forEach(function(item) { item.style.display = ''; });
  }

  function hideAll() {
    listItems.forEach(function(item) { item.style.display = 'none'; });
  }

  function onInput(e) {
    var q = e.target.value;
    if (!q.length) {
      showAll();
      return;
    }

    var results = index.search(q);
    hideAll();
    results.forEach(function(r) {
      var i = parseInt(r.ref, 10);
      listItems[i].style.display = '';
    });
    // TOOD(wdm) Something with score?
  }

  function fillListItem(li, note) {
    li.children[0].textContent = note.title;
    li.children[1].textContent = note.summary;
  }

  function createListItems(notes) {
    listItems = [];
    var ul = document.createElement('ul');
    model.getNotes().forEach(function(note) {
      var li = document.createElement('li');
      li.innerHTML = '';
      fillListItem(li, note);
      ul.appendChild(li);
      listItems.push(li);
    });
    document.querySelector('#noteList').appendChild(ul);
    if (listItems.length) {
      setSelected(0);  // TODO(wdm) Always select the first note?
    }
  }

  function onClickList(e) {
    var target = e.target;
    // This is a nasty hack to move clicks on the  tags up to their
.
    if (target.parentNode.nodeName == 'LI') {
      target = target.parentNode;
    }
    if (target.nodeName !== 'LI') {
      return;
    }
    var list = toArray(document.querySelector('#noteList ul').children);
    var i = list.indexOf(target);
    setSelected(i);
  }

  function init(notes) {
    createListItems(notes);
    createIndex(notes);
    return notes;
  }

  return {
    onInput: onInput,
    onClickList: onClickList,
    setSelected: setSelected,
    init: init
  };
})();

// TODO(wdm) Does this actually buy us anything over a global 'notes'?
var model = (function() {

  // In memory note objects.
  var notes = [];

  return {
    init: function init(notes_) {
      notes = notes_;
      return notes;
    },
    setNote: function setNote(i, note) { notes[i] = note; },
    getNote: function getNote(i) { return notes[i]; },
    getNotes: function getNotes() { return notes; }
  };

})();

////////
// DB //
////////

var DB = (function() {

  // TODO(wdm) Check that SEPERATOR does not appear in notes.
  var SEPERATOR = '\n[//]: # (NVC: Do not edit this line)\n\n';

  function parse(rawText) {
    var rawNotes = rawText.split(SEPERATOR);
    var notes = rawNotes.map(parseNote);
    return notes;
  }

  function parseNote(rawNote, i) {
    var firstLine = rawNote.indexOf('\n');
    return {
      id: i,
      title: rawNote.substring(0, firstLine),
      summary: rawNote.substring(firstLine + 1, 50),
      text: rawNote
    };
  }

  // TODO(wdm) Better name!
  function notesAsBlob() {
    search.setSelected();  // Grabs any changes in textarea.
    var texts = model.getNotes().map(function(note) { return note.text; });
    var rawText = texts.join(SEPERATOR);
    return new Blob([rawText], {
      type:
        'text/plain'
    });
  }
  return {
    parse: parse,
    parseNote: parseNote,
    notesAsBlob: notesAsBlob,
  };
})();

//////////////
// TextArea //
//////////////

function updateTextArea(note) {
  textarea.value = note.text;
  // textarea.focus();
  // TODO(wdm) Restore actual previous position.
  // textarea.setSelectionRange(0, 0);
  // textarea.scrollTop = 0;
}

function setCaret(elem, pos) {
  var range = elem.createTextRange();
  range.collapse(true);
  range.moveEnd('character', pos);
  range.moveStart('character', pos);
  range.select();
}

///////////////
/// File UI ///
///////////////

var fileEntry;

function onChooseFile() {
  chooseFile().then(showFilename).catch(showError);
}

function showFilename(fileEntry_) {
  fileEntry = fileEntry_;
  document.querySelector('#filename').textContent = fileEntry.name;
  return fileEntry;
}

function doSave() {
  if (!dirtMonitor.isDirty) {
    console.log('save skipped: not dirty');
    return Promise.resolve();
  }
  var blob = DB.notesAsBlob();
  return writeFileEntry(fileEntry, blob)
      .then(dirtMonitor.setClean)
      .catch(showError);
}

function doClose() {
  doSave().then(window.close);
}

//////////////////
// Key Handling //
//////////////////

var CODE_W = 'W'.charCodeAt(0);
var CODE_S = 'S'.charCodeAt(0);
var CODE_1 = '1'.charCodeAt(0);
var CODE_ESC = 27;
var CODE_ENTER = 13;

function onKeydown(e) {
  // Dismiss (with save): ESCAPE, Alt-1, Ctrl-W
  if ((e.keyCode === CODE_ESC) || (e.altKey && e.keyCode === CODE_1) ||
      (e.ctrlKey && e.keyCode === CODE_W)) {
    e.preventDefault();
    doClose();
    return;
  }

  // Save: Ctrl-S
  if (e.ctrlKey && e.keyCode === CODE_S) {
    e.preventDefault();
    doSave();
    return;
  }

  // New note (press enter in the search box)
  if (e.keyCode == CODE_ENTER && e.target.id === "search") {
    // TODO(wdm) doNewNote();
  }
}

function init() {
  restoreChosenFile()
      .then(showFilename)
      .then(loadFileEntry)
      .then(DB.parse)
      .then(model.init)
      .then(search.init)
      .catch(showError);

  window.addEventListener('keydown', onKeydown);
  textarea.addEventListener('input', dirtMonitor.setDirty);
  document.querySelector('#chooseFile').addEventListener('click', onChooseFile);
  document.querySelector('#noteList')
      .addEventListener('click', search.onClickList);
  document.querySelector('#search').addEventListener('input', search.onInput);
}

init();
<|endoftext|>


<commit_before>//
// Strider Worker extension for Sauce Labs tests
//

var fs = require('fs')
var path = require('path')
var request = require('request')

// # of tries for application-under-test webserver to start up on specified port
// We test once per second
var HTTP_CHECK_RETRIES = 10

// Interval in between HTTP checks in ms
var HTTP_CHECK_INTERVAL = 1000

// Port on which the application-under-test webserver should bind to on localhost.
// Sauce Connector will tunnel from this to Sauce Cloud for Selenium tests
var HTTP_PORT = 8031

// Read & parse a JSON file
function getJson(filename, cb) {
  fs.readFile(filename, function(err, data) {
    if (err) return cb(err, null)
    try {
      var json = JSON.parse(data)
      cb(null, json)
    } catch(e) {
      cb(e, null)
    }
  })
}

// `npm install` has succeeded at this point.
// We run `npm test` and assuming that has passed,
// then we start the Sauce test process.
// If `npm test` fails, we don't bother with the overhead of running the Sauce tests.
function test(ctx, cb) {
  var sauceAccessKey = ctx.jobData.repo_config.sauce_access_key
  var sauceUsername = ctx.jobData.repo_config.sauce_username
  var sauceBrowsers = ctx.jobData.repo_config.sauce_browsers
  if (sauceBrowsers === undefined || sauceBrowsers.length === 0) {
    // Default to latest chrome on Windows Vista
    sauceBrowsers = [
      {
        browserName:"chrome",
        version:"",
        platform:"Windows 2008"
      }
    ]
  }
  if (sauceAccessKey === undefined || sauceUsername === undefined) {
    ctx.striderMessage(("Sauce tests detected but Sauce credentials have not been configured!\n"
      + "  Please visit project config page to enter them"))
    return cb(1)
  }
  var startPhaseDone = false
  var tsh = ctx.shellWrap(ctx.npmCmd + " test")
  // Run
  ctx.forkProc(ctx.workingDir, tsh.cmd, tsh.args, function(exitCode) {
    if (exitCode !== 0) {
      return cb(exitCode)
    } else {
      ctx.striderMessage("npm test success - trying Sauce tests...")
      // Parse package.json so we can run the start script directly.
      // This is important because `npm start` will fork a subprocess a la shell
      // which means we cannot track the PID and shut it down later.
      getJson(path.join(ctx.workingDir, "package.json"), npmTestPassed)
    }
  })
  function npmTestPassed(err, packageJson) {
    if (err || packageJson.scripts === undefined || packageJson.scripts.start === undefined) {
      striderMessage("could not read package.json to find start command - failing test")
      return cb(1)
    }
    // `npm test` succeeded, so we go through the Sauce tests.

    // Start the app, suggesting a port via PORT environment variable
    var tsh = ctx.shellWrap("exec " + packageJson.scripts.start)
    var serverProc = ctx.forkProc({
      args:tsh.args,
      cmd:tsh.cmd,
      cwd:ctx.workingDir,
      env:{PORT:HTTP_PORT},
    }, function(exitCode) {
      // Could perhaps be backgrounding itself. This should be avoided.
      if (exitCode !== 0 && !startPhaseDone) {
        // If we haven't already called back with completion,
        // and `npm start` exits with non-zero exit code,
        // call back with error and mark done.
        ctx.striderMessage("npm start failed - failing test")
        startPhaseDone = true
        return cb(exitCode)
      }
    })

    // The project webserver should be available via HTTP once started.
    // This section implements a check which will attempt to make a HTTP request for /
    // expecting a 200 response code. It will try HTTP_CHECK_RETRIES times, waiting 1 second
    // between checks. If it fails after HTTP_CHECK_RETRIES times, the server process will be killed
    // and the test failed.
    var tries = 0
    ctx.striderMessage("Waiting for webserver to come up on localhost:" + HTTP_PORT)
    var intervalId = setInterval(function() {
      // Check for http status 200 on http://localhost:HTTP_PORT/
      request("http://localhost:"+HTTP_PORT+"/", function(err, response) {
        if (startPhaseDone) {
          clearInterval(intervalId)
          return
        }
        if (!err && response.statusCode == 200) {
          ctx.striderMessage("Got HTTP 200 on localhost:" + HTTP_PORT + " indicating server is up")
          startPhaseDone = true
          clearInterval(intervalId)
          serverUp()
        } else {
          tries++
          console.log("Error on localhost:%d: %s", HTTP_PORT, err)
          if (tries >= HTTP_CHECK_RETRIES) {
            var msg = ("HTTP 200 check on localhost:" + HTTP_PORT + " failed after " + tries
              + " retries, server not up - failing test")
            ctx.striderMessage(msg)
            clearInterval(intervalId)
            startPhaseDone = true
            return cb(1)
          }
        }
      })
    }, HTTP_CHECK_INTERVAL)

    // Start the Sauce Connector. Returns childProcess object.
    function startConnector(username, apiKey, cb) {
      var jarPath = path.join(__dirname, "thirdparty", "Sauce-Connect.jar")
      var jsh = ctx.shellWrap("exec java -Xmx64m -jar " + jarPath + " " + username + " " + apiKey)

      ctx.striderMessage("Starting Sauce Connector")
      return ctx.forkProc(__dirname, jsh.cmd, jsh.args, cb)
    }

    // Server is up, start Sauce Connector and run the tests via `npm sauce` invocations
    function serverUp() {
      var done = false
      var connectorProc = startConnector(sauceUsername, sauceAccessKey,
        function(exitCode) {
        console.log("Connector exited with code: %d", exitCode)
        serverProc.kill("SIGKILL")
        if (!done) {
          console.log("Killing connector")
          ctx.striderMessage("Error starting Sauce Connector - failing test")
          ctx.striderMessage("Shutting down server")
          done = true
          return cb(1)
        }
      })

      // Wait until connector outputs "You may start your tests"
      // before executing Sauce tests
      connectorProc.stdout.on('data', function(data) {
        if (/Connected! You may start your tests./.exec(data) !== null) {
          var saucesh = ctx.shellWrap(ctx.npmCmd + " run-script sauce")
          var sauceDoneCount = 0
          var finaleStatusCode = 0
          sauceBrowsers.forEach(function(o) {
            ctx.striderMessage("Starting: SAUCE_BROWSER="+o.browserName
              +" SAUCE_OS="+o.platform+" SAUCE_BROWSER_VERSION="+o.version+" npm run-script sauce")
            var sauceProc = ctx.forkProc({
              args: saucesh.args,
              cmd: saucesh.cmd,
              cwd: ctx.workingDir,
              env: {
                SAUCE_USERNAME:sauceUsername,
                SAUCE_ACCESS_KEY:sauceAccessKey,
                SAUCE_OS:o.platform,
                SAUCE_BROWSER_VERSION:o.version || '',
                SAUCE_BROWSER:o.browserName,
              }
            }, function(code) {
              ctx.striderMessage("Exit code "+code
                +" for: SAUCE_BROWSER="+o.browserName +" SAUCE_OS="+o.platform+" SAUCE_BROWSER_VERSION="+o.version+" npm run-script sauce")
              sauceDoneCount++
              // If a single test fails, the whole test job fails.
              if (finaleStatusCode === 0 && code !== 0) {
                finaleStatusCode = 1
              }
              if (!done && sauceDoneCount === sauceBrowsers.length) {
                done = true
                ctx.striderMessage("Shutting down Sauce Connector")
                connectorProc.kill("SIGINT")
                ctx.striderMessage("Shutting down server")
                serverProc.kill()
                // Give Sauce Connector & server 5 seconds to gracefully stop before sending SIGKILL
                setTimeout(function() {
                  connectorProc.kill("SIGKILL")
                  serverProc.kill("SIGKILL")
                  return cb(finaleStatusCode)
                }, 5000)
              }
            })
          })
        }
      })
    }
  }
}

module.exports = function(ctx, cb) {

  ctx.addDetectionRule({
    filename:"package.json",
    jsonKeyExists:"scripts.sauce",
    language:"node.js",
    framework:null,
    hasSauce:true,
    prepare:ctx.npmCmd + " install",
    test:test
  })

  console.log("strider-sauce worker extension loaded")
  cb(null, null)
}
<commit_msg>use cwd inside workingDir for writeability reasons<commit_after>//
// Strider Worker extension for Sauce Labs tests
//

var fs = require('fs')
var path = require('path')
var request = require('request')

// # of tries for application-under-test webserver to start up on specified port
// We test once per second
var HTTP_CHECK_RETRIES = 10

// Interval in between HTTP checks in ms
var HTTP_CHECK_INTERVAL = 1000

// Port on which the application-under-test webserver should bind to on localhost.
// Sauce Connector will tunnel from this to Sauce Cloud for Selenium tests
var HTTP_PORT = 8031

// Read & parse a JSON file
function getJson(filename, cb) {
  fs.readFile(filename, function(err, data) {
    if (err) return cb(err, null)
    try {
      var json = JSON.parse(data)
      cb(null, json)
    } catch(e) {
      cb(e, null)
    }
  })
}

// `npm install` has succeeded at this point.
// We run `npm test` and assuming that has passed,
// then we start the Sauce test process.
// If `npm test` fails, we don't bother with the overhead of running the Sauce tests.
function test(ctx, cb) {
  var sauceAccessKey = ctx.jobData.repo_config.sauce_access_key
  var sauceUsername = ctx.jobData.repo_config.sauce_username
  var sauceBrowsers = ctx.jobData.repo_config.sauce_browsers
  if (sauceBrowsers === undefined || sauceBrowsers.length === 0) {
    // Default to latest chrome on Windows Vista
    sauceBrowsers = [
      {
        browserName:"chrome",
        version:"",
        platform:"Windows 2008"
      }
    ]
  }
  if (sauceAccessKey === undefined || sauceUsername === undefined) {
    ctx.striderMessage(("Sauce tests detected but Sauce credentials have not been configured!\n"
      + "  Please visit project config page to enter them"))
    return cb(1)
  }
  var startPhaseDone = false
  var tsh = ctx.shellWrap(ctx.npmCmd + " test")
  // Run
  ctx.forkProc(ctx.workingDir, tsh.cmd, tsh.args, function(exitCode) {
    if (exitCode !== 0) {
      return cb(exitCode)
    } else {
      ctx.striderMessage("npm test success - trying Sauce tests...")
      // Parse package.json so we can run the start script directly.
      // This is important because `npm start` will fork a subprocess a la shell
      // which means we cannot track the PID and shut it down later.
      getJson(path.join(ctx.workingDir, "package.json"), npmTestPassed)
    }
  })
  function npmTestPassed(err, packageJson) {
    if (err || packageJson.scripts === undefined || packageJson.scripts.start === undefined) {
      striderMessage("could not read package.json to find start command - failing test")
      return cb(1)
    }
    // `npm test` succeeded, so we go through the Sauce tests.

    // Start the app, suggesting a port via PORT environment variable
    var tsh = ctx.shellWrap("exec " + packageJson.scripts.start)
    var serverProc = ctx.forkProc({
      args:tsh.args,
      cmd:tsh.cmd,
      cwd:ctx.workingDir,
      env:{PORT:HTTP_PORT},
    }, function(exitCode) {
      // Could perhaps be backgrounding itself. This should be avoided.
      if (exitCode !== 0 && !startPhaseDone) {
        // If we haven't already called back with completion,
        // and `npm start` exits with non-zero exit code,
        // call back with error and mark done.
        ctx.striderMessage("npm start failed - failing test")
        startPhaseDone = true
        return cb(exitCode)
      }
    })

    // The project webserver should be available via HTTP once started.
    // This section implements a check which will attempt to make a HTTP request for /
    // expecting a 200 response code. It will try HTTP_CHECK_RETRIES times, waiting 1 second
    // between checks. If it fails after HTTP_CHECK_RETRIES times, the server process will be killed
    // and the test failed.
    var tries = 0
    ctx.striderMessage("Waiting for webserver to come up on localhost:" + HTTP_PORT)
    var intervalId = setInterval(function() {
      // Check for http status 200 on http://localhost:HTTP_PORT/
      request("http://localhost:"+HTTP_PORT+"/", function(err, response) {
        if (startPhaseDone) {
          clearInterval(intervalId)
          return
        }
        if (!err && response.statusCode == 200) {
          ctx.striderMessage("Got HTTP 200 on localhost:" + HTTP_PORT + " indicating server is up")
          startPhaseDone = true
          clearInterval(intervalId)
          serverUp()
        } else {
          tries++
          console.log("Error on localhost:%d: %s", HTTP_PORT, err)
          if (tries >= HTTP_CHECK_RETRIES) {
            var msg = ("HTTP 200 check on localhost:" + HTTP_PORT + " failed after " + tries
              + " retries, server not up - failing test")
            ctx.striderMessage(msg)
            clearInterval(intervalId)
            startPhaseDone = true
            return cb(1)
          }
        }
      })
    }, HTTP_CHECK_INTERVAL)

    // Start the Sauce Connector. Returns childProcess object.
    function startConnector(username, apiKey, cb) {
      var jarPath = path.join(__dirname, "thirdparty", "Sauce-Connect.jar")
      var jsh = ctx.shellWrap("exec java -Xmx64m -jar " + jarPath + " " + username + " " + apiKey)

      ctx.striderMessage("Starting Sauce Connector")
      return ctx.forkProc(ctx.workingDir, jsh.cmd, jsh.args, cb)
    }

    // Server is up, start Sauce Connector and run the tests via `npm sauce` invocations
    function serverUp() {
      var done = false
      var connectorProc = startConnector(sauceUsername, sauceAccessKey,
        function(exitCode) {
        console.log("Connector exited with code: %d", exitCode)
        serverProc.kill("SIGKILL")
        if (!done) {
          console.log("Killing connector")
          ctx.striderMessage("Error starting Sauce Connector - failing test")
          ctx.striderMessage("Shutting down server")
          done = true
          return cb(1)
        }
      })

      // Wait until connector outputs "You may start your tests"
      // before executing Sauce tests
      connectorProc.stdout.on('data', function(data) {
        if (/Connected! You may start your tests./.exec(data) !== null) {
          var saucesh = ctx.shellWrap(ctx.npmCmd + " run-script sauce")
          var sauceDoneCount = 0
          var finaleStatusCode = 0
          sauceBrowsers.forEach(function(o) {
            ctx.striderMessage("Starting: SAUCE_BROWSER="+o.browserName
              +" SAUCE_OS="+o.platform+" SAUCE_BROWSER_VERSION="+o.version+" npm run-script sauce")
            var sauceProc = ctx.forkProc({
              args: saucesh.args,
              cmd: saucesh.cmd,
              cwd: ctx.workingDir,
              env: {
                SAUCE_USERNAME:sauceUsername,
                SAUCE_ACCESS_KEY:sauceAccessKey,
                SAUCE_OS:o.platform,
                SAUCE_BROWSER_VERSION:o.version || '',
                SAUCE_BROWSER:o.browserName,
              }
            }, function(code) {
              ctx.striderMessage("Exit code "+code
                +" for: SAUCE_BROWSER="+o.browserName +" SAUCE_OS="+o.platform+" SAUCE_BROWSER_VERSION="+o.version+" npm run-script sauce")
              sauceDoneCount++
              // If a single test fails, the whole test job fails.
              if (finaleStatusCode === 0 && code !== 0) {
                finaleStatusCode = 1
              }
              if (!done && sauceDoneCount === sauceBrowsers.length) {
                done = true
                ctx.striderMessage("Shutting down Sauce Connector")
                connectorProc.kill("SIGINT")
                ctx.striderMessage("Shutting down server")
                serverProc.kill()
                // Give Sauce Connector & server 5 seconds to gracefully stop before sending SIGKILL
                setTimeout(function() {
                  connectorProc.kill("SIGKILL")
                  serverProc.kill("SIGKILL")
                  return cb(finaleStatusCode)
                }, 5000)
              }
            })
          })
        }
      })
    }
  }
}

module.exports = function(ctx, cb) {

  ctx.addDetectionRule({
    filename:"package.json",
    jsonKeyExists:"scripts.sauce",
    language:"node.js",
    framework:null,
    hasSauce:true,
    prepare:ctx.npmCmd + " install",
    test:test
  })

  console.log("strider-sauce worker extension loaded")
  cb(null, null)
}
<|endoftext|>


<commit_before>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */

'use strict';

var WorkerPage = (function() {
  function constructor(workerPDF, page) {
    this.workerPDF = workerPDF;
    this.page = page;

    this.ref = page.ref;
  }

  constructor.prototype = {
    get width() {
      return this.page.width;
    },

    get height() {
      return this.page.height;
    },

    get stats() {
      return this.page.stats;
    },

    startRendering: function(ctx, callback, errback)  {
      this.ctx = ctx;
      this.callback = callback;
      // TODO: Place the worker magic HERE.
      // this.page.startRendering(ctx, callback, errback);

      this.workerPDF.startRendering(this)
    },

    startRenderingFromPreCompilation: function(preCompilation, fonts, images) {
      var gfx = new CanvasGraphics(this.ctx);

      // TODO: Add proper handling for images loaded by the worker.
      var images = new ImagesLoader();

      this.page.startRenderingFromPreCompilation(gfx, preCompilation, fonts, images, this.callback);
    },

    getLinks: function() {
      return this.page.getLinks();
    }
  };

  return constructor;
})();

var WorkerPDFDoc = (function() {
  function constructor(data) {
    this.data = data;
    this.stream = new Stream(data);
    this.pdf = new PDFDoc(this.stream);

    this.catalog = this.pdf.catalog;

    this.pageCache = [];

    var useWorker = false;

    if (useWorker) {
      var worker = new Worker("../worker/boot.js");
    } else {
      // If we don't use a worker, just post/sendMessage to the main thread.
      var worker = {
        postMessage: function(obj) {
          worker.onmessage({data: obj});
        }
      }
    }

    var handler = this.handler = new MessageHandler("main", worker);
    handler.on("page", function(data) {
      var pageNum = data.pageNum;
      var page = this.pageCache[pageNum];

      // Add necessary shape back to fonts.
      var fonts = data.fonts;
      for (var i = 0; i < fonts.length; i++) {
        var font = fonts[i];

        var fontFileDict = new Dict();
        fontFileDict.map = font.file.dict.map;

        var fontFile = new Stream(font.file.bytes, font.file.start,
                                  font.file.end - font.file.start, fontFileDict);
        font.file = new FlateStream(fontFile);
      }

      console.log("startRenderingFromPreCompilation:", "numberOfFonts", fonts.length);
      page.startRenderingFromPreCompilation(data.preCompilation, data.fonts, data.images);
    }, this);

    if (!useWorker) {
      // If the main thread is our worker, setup the handling for the messages
      // the main thread sends to it self.
      WorkerHandler.setup(handler);
    }

    handler.send("doc", data);
  }

  constructor.prototype = {
    get numPages() {
      return this.pdf.numPages;
    },

    startRendering: function(page) {
      this.handler.send("page_request", page.page.pageNumber + 1);
    },

    getPage: function(n) {
      if (this.pageCache[n]) {
        return this.pageCache[n];
      }

      var page = this.pdf.getPage(n);
      return this.pageCache[n] = new WorkerPage(this, page);
    }
  };

  return constructor;
})();
<commit_msg>Use the worker<commit_after>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */

'use strict';

var WorkerPage = (function() {
  function constructor(workerPDF, page) {
    this.workerPDF = workerPDF;
    this.page = page;

    this.ref = page.ref;
  }

  constructor.prototype = {
    get width() {
      return this.page.width;
    },

    get height() {
      return this.page.height;
    },

    get stats() {
      return this.page.stats;
    },

    startRendering: function(ctx, callback, errback)  {
      this.ctx = ctx;
      this.callback = callback;
      // TODO: Place the worker magic HERE.
      // this.page.startRendering(ctx, callback, errback);

      this.workerPDF.startRendering(this)
    },

    startRenderingFromPreCompilation: function(preCompilation, fonts, images) {
      var gfx = new CanvasGraphics(this.ctx);

      // TODO: Add proper handling for images loaded by the worker.
      var images = new ImagesLoader();

      this.page.startRenderingFromPreCompilation(gfx, preCompilation, fonts, images, this.callback);
    },

    getLinks: function() {
      return this.page.getLinks();
    }
  };

  return constructor;
})();

var WorkerPDFDoc = (function() {
  function constructor(data) {
    this.data = data;
    this.stream = new Stream(data);
    this.pdf = new PDFDoc(this.stream);

    this.catalog = this.pdf.catalog;

    this.pageCache = [];

    var useWorker = true;

    if (useWorker) {
      var worker = new Worker("../worker/boot.js");
    } else {
      // If we don't use a worker, just post/sendMessage to the main thread.
      var worker = {
        postMessage: function(obj) {
          worker.onmessage({data: obj});
        }
      }
    }

    var handler = this.handler = new MessageHandler("main", worker);
    handler.on("page", function(data) {
      var pageNum = data.pageNum;
      var page = this.pageCache[pageNum];

      // Add necessary shape back to fonts.
      var fonts = data.fonts;
      for (var i = 0; i < fonts.length; i++) {
        var font = fonts[i];

        var fontFileDict = new Dict();
        fontFileDict.map = font.file.dict.map;

        var fontFile = new Stream(font.file.bytes, font.file.start,
                                  font.file.end - font.file.start, fontFileDict);
        font.file = new FlateStream(fontFile);
      }

      console.log("startRenderingFromPreCompilation:", "numberOfFonts", fonts.length);
      page.startRenderingFromPreCompilation(data.preCompilation, data.fonts, data.images);
    }, this);

    if (!useWorker) {
      // If the main thread is our worker, setup the handling for the messages
      // the main thread sends to it self.
      WorkerHandler.setup(handler);
    }

    handler.send("doc", data);
  }

  constructor.prototype = {
    get numPages() {
      return this.pdf.numPages;
    },

    startRendering: function(page) {
      this.handler.send("page_request", page.page.pageNumber + 1);
    },

    getPage: function(n) {
      if (this.pageCache[n]) {
        return this.pageCache[n];
      }

      var page = this.pdf.getPage(n);
      return this.pageCache[n] = new WorkerPage(this, page);
    }
  };

  return constructor;
})();
<|endoftext|>


<commit_before>/*
	A jQuery plugin to predict and prevent "x-clicks" events.
	Version 1.0 - Released on 2013-11-18
	More info and discussion at : https://github.com/louisameline/XClick
	Released under MIT license
*/
;(function($){

	var defaultOptions = {
			// if for some reason you want to deal with x-clicks triggered only in a given branch of your DOM tree
			delegate: '',
			// to put the plugin to sleep (stops listening to mouse events)
			enable: true,
			// we do not want to waist time in browsers that do not generate x-clicks anyway. This option is mainly for debugging purposes.
			enableForAllBrowsers: false,
			// you may change the names of the silent custom event types we'll be listening to
			silentEventName_mousedown: 'mousedownSilent',
			silentEventName_mouseup: 'mouseupSilent',
			// callback function called when an x-click was just triggered. If the function does not return true, the event propagation is immediately stopped (default behavior).
			// the callback will be called in the context of the common ancestor element which triggered the click event, and receives this click event as first parameter.
			onTriggered: function(){ return false; }
		},
		lastElements = {};

	// we have to know if the browser generates x-clicks. Not sure if there is another way than browser detection (script-triggered mouse events do not trigger an x-click), suggestions are welcome.
	var xclickSupport = false;
	// look for MSIE or rv:11 (IE11)
	if(navigator.userAgent.indexOf('MSIE') !== -1 || navigator.userAgent.indexOf('rv:11') !== -1) xclickSupport = true;

	// a function to set a function as a first handler, in order to stop the x-click event before any other handler can fire
	// warning: this binds on the internals of jQuery as there is no proper method to do this. Be careful to test everytime you upgrade to a new version of jQuery.
	$.fn.xcBindFirst = function(name, fn) {
		// bind as you normally would
		this.on(name, fn);
		return this.each(function() {
			var handlers = $._data(this, 'events')[name.split('.')[0]];
			// take out the handler we just inserted from the end
			var handler = handlers.pop();
			// move it at the beginning
			handlers.splice(0, 0, handler);
		});
	};

	// set the parameter to true
	$.XClick = function(options){

		options = $.extend({}, defaultOptions, options || {});

		if(xclickSupport || options.enableForAllBrowsers){

			// enforcing the prevention system
			if(options.enable === true){

				// bind on body to track mousedown and mouseup events, it will allow us to be ready to catch the x-click
				$('body')
					// if for some reason you have to stop your mousedown/up events from bubbling up to body, trigger a custom "silentMouseup" or "silentMousedown" instead
					.on('mousedown.xc ' + options.silentEventName_mousedown + '.xc', options.delegate, function(e){ lastElements.mousedown = e.target; })
					.on('mouseup.xc ' + options.silentEventName_mouseup + '.xc', options.delegate, function(e){

						lastElements.mouseup = e.target;

						// compare with the mousedown element
						if(
							// if one of the elements is not defined, we let the event go. It happens when one of the mouse events was not triggered or not caught by our listeners and that a .click() call is made afterwards
							lastElements.mousedown && lastElements.mouseup
							// make sure the elements are different
							&& lastElements.mousedown !== lastElements.mouseup
						){
							// we determine which element is the closest ancestor
							var mdElParents = $(lastElements.mousedown).parents(),
								muElParents = $(lastElements.mouseup).parents(),
								$closestCommonAncestor = null;

							$.each(mdElParents, function(i, el){
								$.each(muElParents, function(j, el2){

									if(el === el2 || $(el).has(el2).length > 0){
										$closestCommonAncestor = $(el);
										return false;
									}
								});
								if($closestCommonAncestor) return false;
							});

							// we bind on the closest ancestor to catch the x-click
							$closestCommonAncestor.xcBindFirst('click.xc', function(event){

								// unbind itself first, in case the callback function wants to trigger click events
								$(this).off('click.xc');

								// make sure the click was triggered on this element (as an x-click would be), not bubbling from children. This reduces the risk to catch a wrong click event (edge case)
								if(event.target === this){

									// callback
									var letGo = options.onTriggered.call(this, {
										event: event,
										mousedownElement: lastElements.mousedown,
										mouseupElement: lastElements.mouseup
									});

									// stop the event unless the callback function returned true
									if(letGo !== true) event.stopImmediatePropagation();
								}
							});

							// if the browser does not produce x-clicks, the handler we just bound will never be called and must be unbound before it catches a click it was not supposed to catch
							setTimeout(function(){
								$closestCommonAncestor.off('click.xc');
							}, 0);
						}
					});
			}
			// canceling the prevention system
			else {
				$('body').off('.xc');
			}
		}
	}
})(jQuery);<commit_msg>Updated a comment about onTriggered<commit_after>/*
	A jQuery plugin to predict and prevent "x-clicks" events.
	Version 1.0 - Released on 2013-11-18
	More info and discussion at : https://github.com/louisameline/XClick
	Released under MIT license
*/
;(function($){

	var defaultOptions = {
			// if for some reason you want to deal with x-clicks triggered only in a given branch of your DOM tree
			delegate: '',
			// to put the plugin to sleep (stops listening to mouse events)
			enable: true,
			// we do not want to waist time in browsers that do not generate x-clicks anyway. This option is mainly for debugging purposes.
			enableForAllBrowsers: false,
			// you may change the names of the silent custom event types we'll be listening to
			silentEventName_mousedown: 'mousedownSilent',
			silentEventName_mouseup: 'mouseupSilent',
			// callback function called when an x-click was just triggered. If the function does not return true, the event propagation is immediately stopped (default behavior).
			// the callback will be called in the context of the common ancestor element which triggered the click event, and receives a data object as first parameter, having 'event', 'mousedownElement' and 'mouseupElement' properties.
			onTriggered: function(){ return false; }
		},
		lastElements = {};

	// we have to know if the browser generates x-clicks. Not sure if there is another way than browser detection (script-triggered mouse events do not trigger an x-click), suggestions are welcome.
	var xclickSupport = false;
	// look for MSIE or rv:11 (IE11)
	if(navigator.userAgent.indexOf('MSIE') !== -1 || navigator.userAgent.indexOf('rv:11') !== -1) xclickSupport = true;

	// a function to set a function as a first handler, in order to stop the x-click event before any other handler can fire
	// warning: this binds on the internals of jQuery as there is no proper method to do this. Be careful to test everytime you upgrade to a new version of jQuery.
	$.fn.xcBindFirst = function(name, fn) {
		// bind as you normally would
		this.on(name, fn);
		return this.each(function() {
			var handlers = $._data(this, 'events')[name.split('.')[0]];
			// take out the handler we just inserted from the end
			var handler = handlers.pop();
			// move it at the beginning
			handlers.splice(0, 0, handler);
		});
	};

	// set the parameter to true
	$.XClick = function(options){

		options = $.extend({}, defaultOptions, options || {});

		if(xclickSupport || options.enableForAllBrowsers){

			// enforcing the prevention system
			if(options.enable === true){

				// bind on body to track mousedown and mouseup events, it will allow us to be ready to catch the x-click
				$('body')
					// if for some reason you have to stop your mousedown/up events from bubbling up to body, trigger a custom "silentMouseup" or "silentMousedown" instead
					.on('mousedown.xc ' + options.silentEventName_mousedown + '.xc', options.delegate, function(e){ lastElements.mousedown = e.target; })
					.on('mouseup.xc ' + options.silentEventName_mouseup + '.xc', options.delegate, function(e){

						lastElements.mouseup = e.target;

						// compare with the mousedown element
						if(
							// if one of the elements is not defined, we let the event go. It happens when one of the mouse events was not triggered or not caught by our listeners and that a .click() call is made afterwards
							lastElements.mousedown && lastElements.mouseup
							// make sure the elements are different
							&& lastElements.mousedown !== lastElements.mouseup
						){
							// we determine which element is the closest ancestor
							var mdElParents = $(lastElements.mousedown).parents(),
								muElParents = $(lastElements.mouseup).parents(),
								$closestCommonAncestor = null;

							$.each(mdElParents, function(i, el){
								$.each(muElParents, function(j, el2){

									if(el === el2 || $(el).has(el2).length > 0){
										$closestCommonAncestor = $(el);
										return false;
									}
								});
								if($closestCommonAncestor) return false;
							});

							// we bind on the closest ancestor to catch the x-click
							$closestCommonAncestor.xcBindFirst('click.xc', function(event){

								// unbind itself first, in case the callback function wants to trigger click events
								$(this).off('click.xc');

								// make sure the click was triggered on this element (as an x-click would be), not bubbling from children. This reduces the risk to catch a wrong click event (edge case)
								if(event.target === this){

									// callback
									var letGo = options.onTriggered.call(this, {
										event: event,
										mousedownElement: lastElements.mousedown,
										mouseupElement: lastElements.mouseup
									});

									// stop the event unless the callback function returned true
									if(letGo !== true) event.stopImmediatePropagation();
								}
							});

							// if the browser does not produce x-clicks, the handler we just bound will never be called and must be unbound before it catches a click it was not supposed to catch
							setTimeout(function(){
								$closestCommonAncestor.off('click.xc');
							}, 0);
						}
					});
			}
			// canceling the prevention system
			else {
				$('body').off('.xc');
			}
		}
	}
})(jQuery);<|endoftext|>


<commit_before>const apiRouter = require('express').Router();
const getMatches = require('../db/controllers/getMatchesGivenSelfAndOffset.js');
const addToRequests = require('../db/controllers/moveMatchIntoRequests.js');
const addToRejects = require('../db/controllers/moveMatchIntoRejects.js');
const changeToConnectionFromRequest = require('../db/controllers/moveRequestIntoConnectionsGivenSelfIdAndRequestId.js');
const changeToRejectFromRequest = require('../db/controllers/moveRequestIntoRejectsGivenSelfIdAndRequestId.js');
const changeToRejectFromConnection = require('../db/controllers/moveConnectionIntoRejectsGivenSelfIdAndConnectionId.js');

apiRouter.route('/matches')
  .get((req, res) => { // get matches
    getMatches(req.body.id, req.body.offset)
    .then(matches => {
      res.json = matches;
    });
  });

apiRouter.route('/relationships')
  .post((req, res) => {

  }) // post to rejects and requests
  .put((req, res) => {

  });  // change relationship type

apiRouter.route('/profile/:id')
  .put((req, res) => {

  }); // update profile

module.exports = apiRouter;
<commit_msg>Handle post to /api/relationships<commit_after>const apiRouter = require('express').Router();
const getMatches = require('../db/controllers/getMatchesGivenSelfAndOffset.js');
const addToRequests = require('../db/controllers/moveMatchIntoRequests.js');
const addToRejects = require('../db/controllers/moveMatchIntoRejects.js');
const changeToConnectionFromRequest = require('../db/controllers/moveRequestIntoConnectionsGivenSelfIdAndRequestId.js');
const changeToRejectFromRequest = require('../db/controllers/moveRequestIntoRejectsGivenSelfIdAndRequestId.js');
const changeToRejectFromConnection = require('../db/controllers/moveConnectionIntoRejectsGivenSelfIdAndConnectionId.js');

apiRouter.route('/matches')
  .get((req, res) => { // get matches
    getMatches(req.body.id, req.body.offset)
    .then(matches => {
      res.json(matches);
    });
  });

apiRouter.route('/relationships')
  .post((req, res) => {
    if (req.body.newType === 'request') {
      return addToRequests(req.body.selfId, req.body.matchId)
      .then(() => {
        res.sendStatus(201);
      });
    }
    if (req.body.newType === 'reject') {
      return addToRejects(req.body.selfId, req.body.matchId)
      .then(() => {
        res.sendStatus(201);
      });
    }
    return res.sendStatus(404);
  }) // post to rejects and requests
  .put((req, res) => {

  });  // change relationship type

apiRouter.route('/profile/:id')
  .put((req, res) => {

  }); // update profile

module.exports = apiRouter;
<|endoftext|>


<commit_before>/* Parses uploaded sqm files for units. Returns JSON*/

import armaClassParser from 'arma-class-parser'
import _ from 'lodash'

const SIDE_TRANSLATE_MAP = {
  WEST: 'blufor',
  EAST: 'opfor',
  GUER: 'greenfor',
  CIV: 'civilian'
}
const ALLOWED_SIDES = _.keys(SIDE_TRANSLATE_MAP)
const PLAYABLE_TYPES = ['PLAY CDG', 'PLAYER COMMANDER']

let isAllowedSide = str => _.includes(ALLOWED_SIDES, (str + '').toUpperCase())
let isPlayerSlot = str => _.includes(PLAYABLE_TYPES, (str + '').toUpperCase())
let translateSide = str => SIDE_TRANSLATE_MAP[(str + '').toUpperCase()] || null
let parseGroupName = str => {
  str = str + ''
  let ret = ''
  // might be better with a regexp here
  let match = str.substr(str.toLowerCase().lastIndexOf('setgroupid'))
  if (match) {
    // semicolon could be missing if last command
    let semi = match.indexOf(';')
    match = match.substr(match.indexOf('[') + 1, (semi !== -1 ? semi : match.length))
    match = match.substr(0, match.lastIndexOf(']'))
    ret = match.replace(/['"]+/g, '')
  }

  return _.capitalize(ret.toLowerCase().trim())
}

export default function (sqmFileString, callback) {
  if (!_.isString(sqmFileString)) {
    return callback(new Error('Expected SQM in string format'))
  }
  callback = callback || function () {}
  let ret = []
  let parsed

  try {
    parsed = armaClassParser(sqmFileString)
  } catch (e) {
    return callback(new Error('SQM file could not be parsed'))
  }

  // empty sqm?
  if (!parsed.Mission || !parsed.Mission.Groups) {
    return callback(new Error('Could not find any groups'))
  }

  process.nextTick(() => {
    _.forOwn(parsed.Mission.Groups, val => {
      if (_.isEmpty(val.Vehicles) || !isAllowedSide(val.side)) return

      let grp = {units: []}
      _.forOwn(val.Vehicles, unit => {
        if (_.isEmpty(unit) || !isAllowedSide(unit.side)) return

        if (unit.leader) {
          grp.side = translateSide(unit.side)
          grp.name = _.escape(parseGroupName(unit.init) || '')
        }

        if (!isPlayerSlot(unit.player)) return

        grp.units.push({
          description: _.escape(unit.description).trim()
        })
      })

      if (grp.units.length) {
        if (grp.name) {
          let grpNameReg = new RegExp(grp.name, 'i')
          grp.units.forEach(unit => {
            let orig = unit.description
            if (!orig.toLowerCase().indexOf(grp.name.toLowerCase())) {
              let desc = orig.replace(grpNameReg, '').trim()
              // OR orig because we don't want to replace unit desc if it's only the grpname e.g actual
              unit.description = desc || orig
            }
          })
        }
        ret.push(grp)
      }
    })

    callback(null, ret)
  })
}
<commit_msg>small fix<commit_after>/* Parses uploaded sqm files for units. Returns JSON*/

import armaClassParser from 'arma-class-parser'
import _ from 'lodash'

const SIDE_TRANSLATE_MAP = {
  WEST: 'blufor',
  EAST: 'opfor',
  GUER: 'greenfor',
  CIV: 'civilian'
}
const ALLOWED_SIDES = _.keys(SIDE_TRANSLATE_MAP)
const PLAYABLE_TYPES = ['PLAY CDG', 'PLAYER COMMANDER']

let isAllowedSide = str => _.includes(ALLOWED_SIDES, (str + '').toUpperCase())
let isPlayerSlot = str => _.includes(PLAYABLE_TYPES, (str + '').toUpperCase())
let translateSide = str => SIDE_TRANSLATE_MAP[(str + '').toUpperCase()] || null
let parseGroupName = str => {
  str = str + ''
  let ret = ''
  // might be better with a regexp here
  let match = str.substr(str.toLowerCase().lastIndexOf('setgroupid'))
  if (match) {
    // semicolon could be missing if last command
    let semi = match.indexOf(';')
    match = match.substr(match.indexOf('[') + 1, (semi !== -1 ? semi : match.length))
    match = match.substr(0, match.lastIndexOf(']'))
    ret = match.replace(/['"]+/g, '')
  }

  return _.capitalize(ret.toLowerCase().trim())
}

export default function (sqmFileString, callback) {
  if (!_.isString(sqmFileString)) {
    return callback(new Error('Expected SQM in string format'))
  }
  callback = callback || function () {}
  let ret = []
  let parsed

  try {
    parsed = armaClassParser(sqmFileString)
  } catch (e) {
    return callback(new Error('SQM file could not be parsed'))
  }

  // empty sqm?
  if (!parsed.Mission || !parsed.Mission.Groups) {
    return callback(new Error('Could not find any groups'))
  }

  process.nextTick(() => {
    _.forOwn(parsed.Mission.Groups, val => {
      if (_.isEmpty(val.Vehicles) || !isAllowedSide(val.side)) return

      let grp = {units: []}
      _.forOwn(val.Vehicles, unit => {
        if (_.isEmpty(unit) || !isAllowedSide(unit.side)) return

        if (unit.leader) {
          grp.side = translateSide(unit.side)
          grp.name = _.escape(parseGroupName(unit.init) || '')
        }

        if (!isPlayerSlot(unit.player)) return

        grp.units.push({
          description: _.escape(unit.description).trim()
        })
      })

      if (grp.units.length) {
        if (grp.name) {
          let grpNameReg = new RegExp(grp.name, 'i')
          grp.units.forEach(unit => {
            let orig = unit.description
            if (!orig.toLowerCase().indexOf(grp.name.toLowerCase())) {
              let desc = orig.replace(grpNameReg, '').trim()
              // don't want to replace unit desc if it's only the grpname e.g actual
              // and if it starts with parenthesis, keep the original
              unit.description = desc.indexOf('(') === 0 ? orig : (desc || orig)
            }
          })
        }
        ret.push(grp)
      }
    })

    callback(null, ret)
  })
}
<|endoftext|>


<commit_before>var http=require("http");

global.logError=require("./lib/error.js")();

/* Your default stack */
var routes=[];

/* route produces new routes, and pushes them to a stack */
var route=function(patt,f,opts){
  opts=opts||{}; // you don't have to provide options
  // make sure the discriminator is defined
  opts.disc=opts.disc||'url'; // your router parses by url by default
  opts.stack=opts.stack||routes; // you can provide an alternate stack

  // push your new route to the stack in question
  opts.stack.push(function(req,res,Next){
    // encapsulate Next so that we don't always have to pass req and res
    var next=function(){Next(req,res);};
    if(patt.test(req[opts.disc])){
      f(req,res,next);
    }else{
      next(req,res);
    }
  });
};

// now push some routes!

/* Cache static files */
route(/.*/,require("./lib/cache"));

/* Enable CORS */
route(/.*/,require("./lib/cors.js"));

/* Logger */
route(/.*/,require("./lib/logger.js")({path:process.env.PWD+'/log/'}));

/* Accept post requests */
route(/.*/,require("./lib/posted.js")());

/* koan */
route(/.*/,require("./lib/koan.js")({
  error:logError
}));

/* Route static files */
route(/.*/,require("./lib/fixed")(process.env.PWD+"/static","index.html"));

/* blag */
route(/.*/,require("./lib/blag.js")({path:process.env.PWD+"/md/",title:" "}));

/* last resort */
route(/.*/,require("./lib/parcel.js")(process.env.PWD+"/static/html/404.html"));

var makeRouter=function(stack){
  return stack.reduceRight(function(b,a,i,z){
    return function(req,res){
      a(req,res,b);
    };
  });
};

var router=makeRouter(routes)

global.thisServersPort=8083;
var addresses=[''];

(function(){
  global.thisServersIPV6=require("./lib/fc.js")();
  if(thisServersIPV6)
    addresses.push(thisServersIPV6[0]);
})();

var servers=addresses.map(function(addy){
  var server=http.createServer(router);
  server.listen(thisServersPort,addy,function(){
    console.log("unmon is running on %s:%s",addy,thisServersPort);
  });
  return server;
});
<commit_msg>unmon.js can now be used as a module or a standalone server. documentation to follow<commit_after>var http=require("http");
var unmon={};

/* Your default stack */
var routes=unmon.routes=[];

/* route produces new routes, and pushes them to a stack */
var route=unmon.route=function(patt,f,opts){
  opts=opts||{}; // you don't have to provide options
  // make sure the discriminator is defined
  opts.disc=opts.disc||'url'; // your router parses by url by default
  opts.stack=opts.stack||routes; // you can provide an alternate stack

  // push your new route to the stack in question
  opts.stack.push(function(req,res,Next){
    // encapsulate Next so that we don't always have to pass req and res
    var next=function(){Next(req,res);};
    if(patt.test(req[opts.disc])){
      f(req,res,next);
    }else{
      next();
    }
  });
};

/*  makeRouter accepts a stack of routes and collapses it into a single function
    which is compatible with the NodeJS http api
    of the form function(request,response)  */
var makeRouter=unmon.makeRouter=function(stack){
  return stack.reduceRight(function(b,a,i,z){
    return function(req,res){
      a(req,res,b);
    };
  });
};

/* If being run as a standalone server, load routes and launch a server */

if(require.main === module){
  console.log("Running unmon as standalone script");

  /* instantiate error logging behaviour
    this catches ALL uncaught exceptions
    which is possibly a security risk if your server SHOULD crash */
  global.logError=require("./lib/error.js")();

  /* This is where you add your routes */

  /* infer appropriate caching behaviour from requested urls */
  route(/.*/,require("./lib/cache"));

  /* Enable CORS headers for api access */
  route(/.*/,require("./lib/cors.js"));

  /* Log all requests to file */
  route(/.*/,require("./lib/logger.js")({path:process.env.PWD+'/log/'}));

  /* Process post requests and export them as req.postdata */
  route(/.*/,require("./lib/posted.js")());

  /* Templating and serverside scripting */
  route(/.*/,require("./lib/koan.js")({
    error:logError
  }));

  /* find and serve static files */
  route(/.*/,require("./lib/fixed")(process.env.PWD+"/static","index.html"));

  /* load the blag plugin for serving templated markdown files */
  route(/.*/,require("./lib/blag.js")({path:process.env.PWD+"/md/",title:" "}));

  /* 404 as a last resort */
  route(/.*/,require("./lib/parcel.js")(process.env.PWD+"/static/html/404.html"));

  // produce a new router
  var router=makeRouter(routes)

  // make the port known globally for other scripts
  global.thisServersPort=8083;

  // bind to all ipv4 addresses by default
  var addresses=[''];

  // check if you have a unique local ipv6 address
  (function(){
    global.thisServersIPV6=require("./lib/fc.js")();
    if(thisServersIPV6)
      addresses.push(thisServersIPV6[0]);
  })();

  // instantiate and launch a server for each address in addresses
  var servers=addresses.map(function(addy){
    var server=http.createServer(router);
    server.listen(thisServersPort,addy,function(){
      console.log("unmon is running on %s:%s",addy,thisServersPort);
    });
    return server;
  });

}else{
  /*  If this module is being loaded as a library by another file
      just export the router functions */
  console.log("Exporting unmon as a library.");
  module.exports=unmon;
}
<|endoftext|>