<commit_before>'use strict';

function Bencher(karma, suite) {
  this.karma = karma;
  this.meta = suite.meta;

  var specs = this.specs = suite.specs;
  var opts = this.opts = suite.opts;

  this.pendingRuns = specs.length * opts.sampleSize;
  this.results = [];
  this.stack = [];
  this.index = 0;
}

Bencher.prototype.run = function() {
  this.karma.info({total: this.specs.length});

  for(var i=0; i < this.specs.length; i++) {
    this.stack.push(new BenchObj(this, this.specs[i], this.opts));
  }

  this.stack[this.index].run();
};

function BenchObj(bencher, spec, opts) {
  this.bencher = bencher;
  this.spec = spec;
  this.opts = opts;
  this.setupData = this.spec.setup(this);
  this.time0 = null;
  this.time1 = null;
  this.sample = [];
}

BenchObj.prototype.run = function() {
  this.spec.bench(this, this.setupData);
};

BenchObj.prototype.startTimer = function() {
  this.spec.beforeEach();
  this.time0 = performance.now();
};

BenchObj.prototype.stopTimer = function() {
  var bencher = this.bencher;
  var spec = this.spec;
  var sample = this.sample;

  this.time1 = performance.now();
  spec.afterEach();

  var delta = this.time1 - this.time0;
  this.sample.push(delta);

  if(!bencher.opts.hideLogOnCycle) {
    console.log(spec.name + ': ' + delta + ' ms');
  }

  if(sample.length === this.opts.sampleSize) {
    var benchmark = {
      name: spec.name,
      version: spec.getVersion(),
      mean: calcMean(sample),
      std: calcStd(sample),
      sample: sample
    };

    bencher.karma.result({
      success: true,
      benchmark: benchmark,
      meta: bencher.meta,
      opts: bencher.opts
    });
    bencher.results.push(benchmark);

    // TODO implement a teardown step?

    if(++bencher.index < bencher.stack.length) {
      bencher.stack[bencher.index].run();
    }
  }
  else this.run();

  if(!--bencher.pendingRuns) {
    bencher.karma.complete({});
  }
};

function calcMean(sample) {
  var n = sample.length;
  var sum = 0;

  for(var i=0; i<n; i++) {
    sum += sample[i];
  }

  return sum / n;
}

function calcStd(sample) {
  var n = sample.length;

  if(n === 1) return 0;

  var mean = calcMean(sample);
  var ssq = 0;

  for(var i=0; i<n; i++) {
    ssq += Math.pow(sample[i] - mean, 2);
  }

  return Math.sqrt(ssq / (n-1));
}

module.exports = function createBencher(karma, specs, opts) {
  return new Bencher(karma, specs, opts);
};
<commit_msg>make setup, beforeEach, afterEach and getVersion handlers optional<commit_after>'use strict';

function Bencher(karma, suite) {
  this.karma = karma;
  this.meta = suite.meta;

  var specs = this.specs = suite.specs;
  var opts = this.opts = suite.opts;

  this.pendingRuns = specs.length * opts.sampleSize;
  this.results = [];
  this.stack = [];
  this.index = 0;
}

Bencher.prototype.run = function() {
  this.karma.info({total: this.specs.length});

  for(var i=0; i < this.specs.length; i++) {
    this.stack.push(new BenchObj(this, this.specs[i], this.opts));
  }

  this.stack[this.index].run();
};

function BenchObj(bencher, spec, opts) {
  this.bencher = bencher;
  this.spec = spec;
  this.opts = opts;
  this.time0 = null;
  this.time1 = null;
  this.sample = [];

  if(isFunction(this.spec.setup)) {
    this.setupData = this.spec.setup(this);
  }
}

BenchObj.prototype.run = function() {
  this.spec.bench(this, this.setupData);
};

BenchObj.prototype.startTimer = function() {
  if(isFunction(this.spec.beforeEach)) {
    this.spec.beforeEach();
  }

  this.time0 = performance.now();
};

BenchObj.prototype.stopTimer = function() {
  var bencher = this.bencher;
  var spec = this.spec;
  var sample = this.sample;

  this.time1 = performance.now();

  if(isFunction(this.spec.afterEach)) {
    spec.afterEach();
  }

  var delta = this.time1 - this.time0;
  this.sample.push(delta);

  if(!bencher.opts.hideLogOnCycle) {
    console.log(spec.name + ': ' + delta + ' ms');
  }

  if(sample.length === this.opts.sampleSize) {
    var benchmark = {
      name: spec.name,
      version: isFunction(spec.getVersion) ? spec.getVersion() : '',
      mean: calcMean(sample),
      std: calcStd(sample),
      sample: sample
    };

    bencher.karma.result({
      success: true,
      benchmark: benchmark,
      meta: bencher.meta,
      opts: bencher.opts
    });
    bencher.results.push(benchmark);

    // TODO implement a teardown step?

    if(++bencher.index < bencher.stack.length) {
      bencher.stack[bencher.index].run();
    }
  }
  else this.run();

  if(!--bencher.pendingRuns) {
    bencher.karma.complete({});
  }
};

function calcMean(sample) {
  var n = sample.length;
  var sum = 0;

  for(var i=0; i<n; i++) {
    sum += sample[i];
  }

  return sum / n;
}

function calcStd(sample) {
  var n = sample.length;

  if(n === 1) return 0;

  var mean = calcMean(sample);
  var ssq = 0;

  for(var i=0; i<n; i++) {
    ssq += Math.pow(sample[i] - mean, 2);
  }

  return Math.sqrt(ssq / (n-1));
}

function isFunction(fn) {
   var getType = {};
   return fn && getType.toString.call(fn) === '[object Function]';
}

module.exports = function createBencher(karma, specs, opts) {
  return new Bencher(karma, specs, opts);
};
<|endoftext|>


<commit_before>var io = require('./io');
var modm = require('modm');

// TODO let the user define this configs
var config = {
    dbName: 'dms', // TODO handle with datasources
    templateId: modm.ObjectId('000000000000000000000000'), // TODO handle with datasources
    templateColName: 'd_templates', // TODO handle with datasources
    templateSchema: {
        _id: {type: 'objectid'},
        _tp: {type: 'objectid', required: true},
        _ln: [{
            _tp: {type: 'objectid'},
            _id: {type: 'objectid'}
        }],
        db: {type: 'string', required: true},
        collection: {type: 'string', required: true},
        name: {type: 'string', required: true},
        roles: {type: 'object', required: true},
        schema: {type: 'object', required: true}
    }
};

var templateSchema = new modm.Schema(config.templateSchema);

// template cache
var templateCache = {
    // template's template must be in the cache, otherwise
    // it's impossible to create the first template item
    '000000000000000000000000': {
        db: config.dbName,
        collection: config.templateColName,
        roles: {3: 1}, // 0 = no access, 1 = read, 2 = write
        schema: templateSchema,
        model: modm(config.dbName, {
            server: {pooSize: 3},
            db: {w: 1}
        })
    }
};
// init collection
templateCache[config.templateId].collection = templateCache[config.templateId].model(config.templateColName, templateSchema);

function ObjectId (id) {
    try {
        return modm.ObjectId(id);
    } catch (err) {
        return null;
    }
}

//TODO check access
function checkAccess (template, role, access) {
    /*if (template.roles[role] < access) {
        return false;
    }*/
    return true;
}

function initAndCache (template) {
    if (typeof template.db !== 'string') {
        return;
    };

    template.model = modm(template.db, {
        server: {pooSize: 3},
        db: {w: 1}
    });

    // add mandatory field _tp
    template.schema._tp = {
        type: 'objectid',
        required: true
    };

    // add mandatory field _id
    template.schema._id = {
        type: 'objectid',
        required: true
    };

    // add mandatory field _ln
    if (!template.schema._ln) {
        template.schema._ln = [{}];
    }

    // add mandatory field _ln._tp
    template.schema._ln[0]._tp = 'objectid';

    // add mandatory field _ln._id
    template.schema._ln[0]._id = 'objectid';

    template.schema = new modm.Schema(template.schema);
    template.collection = template.model(template.collection, template.schema);
    return templateCache[template._id] = template;
}

function getCachedTemplates (templates, role) {

    if (!templates || templates.length === 0) {
        return;
    }

    var resultTemplates = {};
    var queryTemplates = [];
    var addedTemplates = {};

    if (templates && templates.length > 0) {
        // check cached templates
        for (var i = 0, l = templates.length; i < l; ++i) {
            // add to result if role has access
            if (templateCache[templates[i]] && checkAccess(templateCache[templates[i]], role, 1)) {
                resultTemplates[templates[i]] = templateCache[templates[i]];
            } else if (!addedTemplates[templates[i]]) {
                addedTemplates[templates[i]] = true;
                queryTemplates.push(templates[i]);
            }
        }
    }

    return {
        query: queryTemplates,
        cached: resultTemplates
    }
}

// TODO check access
function fetchTemplatesFromDb (templates, role, fields, callback) {

    var tpls = getCachedTemplates(templates, role);
    var resultTemplates = {};

    // build query
    var dbReq = {
        query: {
            _tp: config.templateId
            //_ln: [{_tp: 'role'}]
        },
        options: {fields: fields || {}},
        template: templateCache[config.templateId]
    };

    if (tpls) {
        var templates = tpls.query;
        resultTemplates = tpls.cached;

        // check if role has write access
        //dbReq.query._ln[0]._id = {$gt: 0};

        if (templates.length > 1) {

            dbReq.query._id ={$in: []};
            dbReq.options.limit = templates.length;

            for (var i = 0, l = templates.length; i < l; ++i) {
                templates[i] = ObjectId(templates[i]);
                if (!templates[i]) {
                    var err = new Error('Invalid templates.');
                    err.statusCode = 400;
                    return callback(err);
                }

                dbReq.query._id.$in.push(templates[i]);
            }
        } else if (templates.length > 0) {

            if (templates[0] = ObjectId(templates[0])) {
                dbReq.options.limit = 1;
                dbReq.query._id = templates[0];
            } else {
                var err = new Error('Invalid templates.');
                err.statusCode = 400;
                return callback(err);
            }
        }
    }
    //console.log(dbReq.query);
    if (!tpls || tpls.query.length > 0) {
        io.find(null, dbReq, function (err, cursor) {

            if (err) {
                err.statusCode = 500;
                return callback(err);
            }

            if (!cursor) {
                var err = new Error('Templates not found.');
                err.statusCode = 404;
                return callback(err);
            }

            cursor.toArray(function (err, templates) {

                if (err) {
                    err.statusCode = 500;
                    return callback(err);
                }

                if (!templates || templates.length === 0) {
                    var err = new Error('Templates not found.');
                    err.statusCode = 404;
                    return callback(err);
                }

                for (var i = 0, l = templates.length; i < l; ++i) {
                    var temp = initAndCache(templates[i]);
                    if (temp) {
                        resultTemplates[templates[i]._id] = temp;
                    }
                }

                callback(null, resultTemplates);
            });
        });
    } else {
        callback(null, tpls.cached);
    }
}

function getTemplate (request, callback) {

    fetchTemplatesFromDb([request.templateId], request.role, {}, function (err, template) {

        if (err) {
            err.statusCode = err.statusCode || 500;
            return callback(err);
        }

        request.template = template[request.templateId];

        if (!request.template) {
            err = new Error('Bad template object.');
            err.statusCode = 500;
            return callback(err);
        }

        callback(null, request);
    });
}

function getTemplates (link) {

    var templates = link.data;

    fetchTemplatesFromDb(templates, link.session._rid, {}, function (err, templates) {

        if (err) {
            return link.send(err.statusCode || 500, err.message);
        }

        var result = {};
        for (var template in templates) {
            result[template] = {
                id: templates[template]._id,
                name: templates[template].name,
                schema: templates[template].schema.paths
            };
        }

        link.send(200, result);
    });
}

exports.getTemplate = getTemplate;
exports.getTemplates = getTemplates;
<commit_msg>retrun also html path if exists<commit_after>var io = require('./io');
var modm = require('modm');

// TODO let the user define this configs
var config = {
    dbName: 'dms', // TODO handle with datasources
    templateId: modm.ObjectId('000000000000000000000000'), // TODO handle with datasources
    templateColName: 'd_templates', // TODO handle with datasources
    templateSchema: {
        _id: {type: 'objectid'},
        _tp: {type: 'objectid', required: true},
        _ln: [{
            _tp: {type: 'objectid'},
            _id: {type: 'objectid'}
        }],
        db: {type: 'string', required: true},
        collection: {type: 'string', required: true},
        name: {type: 'string', required: true},
        roles: {type: 'object', required: true},
        schema: {type: 'object', required: true}
    }
};

var templateSchema = new modm.Schema(config.templateSchema);

// template cache
var templateCache = {
    // template's template must be in the cache, otherwise
    // it's impossible to create the first template item
    '000000000000000000000000': {
        db: config.dbName,
        collection: config.templateColName,
        roles: {3: 1}, // 0 = no access, 1 = read, 2 = write
        schema: templateSchema,
        model: modm(config.dbName, {
            server: {pooSize: 3},
            db: {w: 1}
        })
    }
};
// init collection
templateCache[config.templateId].collection = templateCache[config.templateId].model(config.templateColName, templateSchema);

function ObjectId (id) {
    try {
        return modm.ObjectId(id);
    } catch (err) {
        return null;
    }
}

//TODO check access
function checkAccess (template, role, access) {
    /*if (template.roles[role] < access) {
        return false;
    }*/
    return true;
}

function initAndCache (template) {
    if (typeof template.db !== 'string') {
        return;
    };

    template.model = modm(template.db, {
        server: {pooSize: 3},
        db: {w: 1}
    });

    // add mandatory field _tp
    template.schema._tp = {
        type: 'objectid',
        required: true
    };

    // add mandatory field _id
    template.schema._id = {
        type: 'objectid',
        required: true
    };

    // add mandatory field _ln
    if (!template.schema._ln) {
        template.schema._ln = [{}];
    }

    // add mandatory field _ln._tp
    template.schema._ln[0]._tp = 'objectid';

    // add mandatory field _ln._id
    template.schema._ln[0]._id = 'objectid';

    template.schema = new modm.Schema(template.schema);
    template.collection = template.model(template.collection, template.schema);
    return templateCache[template._id] = template;
}

function getCachedTemplates (templates, role) {

    if (!templates || templates.length === 0) {
        return;
    }

    var resultTemplates = {};
    var queryTemplates = [];
    var addedTemplates = {};

    if (templates && templates.length > 0) {
        // check cached templates
        for (var i = 0, l = templates.length; i < l; ++i) {
            // add to result if role has access
            if (templateCache[templates[i]] && checkAccess(templateCache[templates[i]], role, 1)) {
                resultTemplates[templates[i]] = templateCache[templates[i]];
            } else if (!addedTemplates[templates[i]]) {
                addedTemplates[templates[i]] = true;
                queryTemplates.push(templates[i]);
            }
        }
    }

    return {
        query: queryTemplates,
        cached: resultTemplates
    }
}

// TODO check access
function fetchTemplatesFromDb (templates, role, fields, callback) {

    var tpls = getCachedTemplates(templates, role);
    var resultTemplates = {};

    // build query
    var dbReq = {
        query: {
            _tp: config.templateId
            //_ln: [{_tp: 'role'}]
        },
        options: {fields: fields || {}},
        template: templateCache[config.templateId]
    };

    if (tpls) {
        var templates = tpls.query;
        resultTemplates = tpls.cached;

        // check if role has write access
        //dbReq.query._ln[0]._id = {$gt: 0};

        if (templates.length > 1) {

            dbReq.query._id ={$in: []};
            dbReq.options.limit = templates.length;

            for (var i = 0, l = templates.length; i < l; ++i) {
                templates[i] = ObjectId(templates[i]);
                if (!templates[i]) {
                    var err = new Error('Invalid templates.');
                    err.statusCode = 400;
                    return callback(err);
                }

                dbReq.query._id.$in.push(templates[i]);
            }
        } else if (templates.length > 0) {

            if (templates[0] = ObjectId(templates[0])) {
                dbReq.options.limit = 1;
                dbReq.query._id = templates[0];
            } else {
                var err = new Error('Invalid templates.');
                err.statusCode = 400;
                return callback(err);
            }
        }
    }
    //console.log(dbReq.query);
    if (!tpls || tpls.query.length > 0) {
        io.find(null, dbReq, function (err, cursor) {

            if (err) {
                err.statusCode = 500;
                return callback(err);
            }

            if (!cursor) {
                var err = new Error('Templates not found.');
                err.statusCode = 404;
                return callback(err);
            }

            cursor.toArray(function (err, templates) {

                if (err) {
                    err.statusCode = 500;
                    return callback(err);
                }

                if (!templates || templates.length === 0) {
                    var err = new Error('Templates not found.');
                    err.statusCode = 404;
                    return callback(err);
                }

                for (var i = 0, l = templates.length; i < l; ++i) {
                    var temp = initAndCache(templates[i]);
                    if (temp) {
                        resultTemplates[templates[i]._id] = temp;
                    }
                }

                callback(null, resultTemplates);
            });
        });
    } else {
        callback(null, tpls.cached);
    }
}

function getTemplate (request, callback) {

    fetchTemplatesFromDb([request.templateId], request.role, {}, function (err, template) {

        if (err) {
            err.statusCode = err.statusCode || 500;
            return callback(err);
        }

        request.template = template[request.templateId];

        if (!request.template) {
            err = new Error('Bad template object.');
            err.statusCode = 500;
            return callback(err);
        }

        callback(null, request);
    });
}

function getTemplates (link) {

    var templates = link.data;

    fetchTemplatesFromDb(templates, link.session._rid, {}, function (err, templates) {

        if (err) {
            return link.send(err.statusCode || 500, err.message);
        }

        var result = {};
        for (var template in templates) {
            result[template] = {
                id: templates[template]._id,
                name: templates[template].name,
                schema: templates[template].schema.paths
            };

            if (templates[template].html) {
                result[template].html = templates[template].html;
            }
        }

        link.send(200, result);
    });
}

exports.getTemplate = getTemplate;
exports.getTemplates = getTemplates;
<|endoftext|>


<commit_before>window.genUID = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
};

require(["widgets/js/widget"], function(WidgetManager){

    var GraphView = IPython.DOMWidgetView.extend({
        render: function(){
            var that = this;

            var frameId = window.genUID();
            var loadingId = 'loading-'+frameId;

            var _graph_url = that.model.get('_graph_url');

            // variable plotly_domain in the case of enterprise
            var url_parts = _graph_url.split('/');
            var plotly_domain = url_parts[0] + '//' + url_parts[2];

            // Place IFrame in output cell div `$el`
            that.$el.css('width', '100%');
            that.$graph = $(['',
                             ''].join(' '));
            that.$graph.appendTo(that.$el);

            that.$loading = $('
Initializing...
')
                            .appendTo(that.$el);

            // initialize communication with the iframe
            if(!('pingers' in window)){
                window.pingers = {};
            }

            window.pingers[frameId] = setInterval(function() {
                that.graphContentWindow = $('#'+frameId)[0].contentWindow;
                that.graphContentWindow.postMessage({ping: true}, plotly_domain);
            }, 200);

            // Assign a message listener to the 'message' events
            // from iframe's postMessage protocol.
            // Filter the messages by iframe src so that the right message
            // gets passed to the right widget
            if(!('messageListeners' in window)){
                 window.messageListeners = {};
            }

            window.messageListeners[frameId] = function(e) {
                if(_graph_url.indexOf(e.origin)>-1) {
                    var frame = document.getElementById(frameId);

                    if(frame === null){
                        // frame doesn't exist in the dom anymore, clean up it's old event listener
                        window.removeEventListener('message', window.messageListeners[frameId]);
                        clearInterval(window.pingers[frameId]);
                    } else if(frame.contentWindow === e.source) {
                        // TODO: Stop event propagation, so each frame doesn't listen and filter
                        var frameContentWindow = $('#'+frameId)[0].contentWindow;
                        var message = e.data;

                        if(message==='pong') {
                            $('#loading-'+frameId).hide();
                            clearInterval(window.pingers[frameId]);
                            that.send({event: 'pong', graphId: frameId});
                        } else if (message.type==='hover' ||
                                   message.type==='zoom'  ||
                                   message.type==='click' ||
                                   message.type==='unhover') {
                            that.send({event: message.type, message: message, graphId: frameId});
                        }
                    }
                }
            };

            window.removeEventListener('message', window.messageListeners[frameId]);
            window.addEventListener('message', window.messageListeners[frameId]);

        },

        update: function() {
            // Listen for messages from the graph widget in python
            var jmessage = this.model.get('_message');

            var message = JSON.parse(jmessage);

            // check for duplicate messages
            if(!('messageIds' in window)){
                window.messageIds = {};
                window.messageIds[message.uid] = true;
            }

            if(!(message.uid in window.messageIds)){
                // message hsn't been received yet, do stuff
                window.messageIds[message.uid] = true;

                alert('gogogogo');

                var plot = $('#'+message.graphId)[0].contentWindow;
                plot.postMessage(message, message.plotlyDomain);
            }

            return GraphView.__super__.update.apply(this);
        }
    });

    // Register the GraphView with the widget manager.
    WidgetManager.register_widget_view('GraphView', GraphView);
});

//@ sourceURL=graphWidget.js
<commit_msg>rm debug info<commit_after>window.genUID = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
};

require(["widgets/js/widget"], function(WidgetManager){

    var GraphView = IPython.DOMWidgetView.extend({
        render: function(){
            var that = this;

            var frameId = window.genUID();
            var loadingId = 'loading-'+frameId;

            var _graph_url = that.model.get('_graph_url');

            // variable plotly_domain in the case of enterprise
            var url_parts = _graph_url.split('/');
            var plotly_domain = url_parts[0] + '//' + url_parts[2];

            // Place IFrame in output cell div `$el`
            that.$el.css('width', '100%');
            that.$graph = $(['',
                             ''].join(' '));
            that.$graph.appendTo(that.$el);

            that.$loading = $('
Initializing...
')
                            .appendTo(that.$el);

            // initialize communication with the iframe
            if(!('pingers' in window)){
                window.pingers = {};
            }

            window.pingers[frameId] = setInterval(function() {
                that.graphContentWindow = $('#'+frameId)[0].contentWindow;
                that.graphContentWindow.postMessage({ping: true}, plotly_domain);
            }, 200);

            // Assign a message listener to the 'message' events
            // from iframe's postMessage protocol.
            // Filter the messages by iframe src so that the right message
            // gets passed to the right widget
            if(!('messageListeners' in window)){
                 window.messageListeners = {};
            }

            window.messageListeners[frameId] = function(e) {
                if(_graph_url.indexOf(e.origin)>-1) {
                    var frame = document.getElementById(frameId);

                    if(frame === null){
                        // frame doesn't exist in the dom anymore, clean up it's old event listener
                        window.removeEventListener('message', window.messageListeners[frameId]);
                        clearInterval(window.pingers[frameId]);
                    } else if(frame.contentWindow === e.source) {
                        // TODO: Stop event propagation, so each frame doesn't listen and filter
                        var frameContentWindow = $('#'+frameId)[0].contentWindow;
                        var message = e.data;

                        if(message==='pong') {
                            $('#loading-'+frameId).hide();
                            clearInterval(window.pingers[frameId]);
                            that.send({event: 'pong', graphId: frameId});
                        } else if (message.type==='hover' ||
                                   message.type==='zoom'  ||
                                   message.type==='click' ||
                                   message.type==='unhover') {
                            that.send({event: message.type, message: message, graphId: frameId});
                        }
                    }
                }
            };

            window.removeEventListener('message', window.messageListeners[frameId]);
            window.addEventListener('message', window.messageListeners[frameId]);

        },

        update: function() {
            // Listen for messages from the graph widget in python
            var jmessage = this.model.get('_message');

            var message = JSON.parse(jmessage);

            // check for duplicate messages
            if(!('messageIds' in window)){
                window.messageIds = {};
                window.messageIds[message.uid] = true;
            }

            if(!(message.uid in window.messageIds)){
                // message hasn't been received yet, do stuff
                window.messageIds[message.uid] = true;

                var plot = $('#'+message.graphId)[0].contentWindow;
                plot.postMessage(message, message.plotlyDomain);
            }

            return GraphView.__super__.update.apply(this);
        }
    });

    // Register the GraphView with the widget manager.
    WidgetManager.register_widget_view('GraphView', GraphView);
});

//@ sourceURL=graphWidget.js
<|endoftext|>


<commit_before>module.exports = (function() {
   var request = require('request'),
      crypto = require('crypto'),
      moment = require('moment'),
      lastNonce;

   function bit2cPublicRequest(operation, currency, param, callback) {

      var url = 'https://www.bit2c.co.il/Exchanges/' + currency + '/' + operation;
      if (param) {
         url += '?'+ param.key + '=' + param.value;
      }

      request({
            method: 'GET',
            url: url
         }, function(error, response, bodyString) {

            var normalResponseCode = '200';

            if (error !== null || (typeof (bodyString) !== 'string') ||
                (response.statusCode + '' !== normalResponseCode)) {
               callback(new Error('cannot get response from bit2c. error: ' + error +
                                  ' reason: ' +
                                  (response?response.statusCode:'undefined')));
               return;
            }

            callback(undefined, JSON.parse(bodyString));
         });
   }

   function bit2cPrivateRequest(path, credentials, queryString, callback) {

      var url = 'https://www.bit2c.co.il/' + path,
         signature;

      signature = crypto.createHmac('sha512', credentials.secret.toUpperCase()).update(queryString).digest('base64');
      request({
         method: 'POST',
         url: url,
         headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'key': credentials.key,
            'sign': signature
         },
         body: queryString
      }, function(error, response, bodyString) {

         var normalResponseCode = '200';

         if (error !== null || (typeof (bodyString) !== 'string') ||
             (response.statusCode + '' !== normalResponseCode)) {
            callback(new Error('cannot get response from bit2c. error: ' + error +
                               ' reason: ' +
                            (response?response.statusCode:'undefined')));
            return;
         }

         callback(undefined, JSON.parse(bodyString));
      });
   }

   // This function will hopefully work - if runnnig the api from the same computer
   // running this from multiple computers will probably fail it since there
   // might be clock skews
   function getUniqueNonce() {
      // unix time diff ti 14/01/2014 / 250 - the min response time i assume,
      // this technique should be sufficient for the next few years...
      var result = parseInt(((new Date()).getTime() - 1389729146519)/250,10);

      // this is good if from the same process we run multiple parallel requests...
      if (result == lastNonce) {
         result +=1;
      }
      lastNonce = result;
      return result;
   }

   var that = {

      getTicker: function(currency, callback) {
         bit2cPublicRequest('Ticker.json', currency,  undefined, callback);
      },

      getTrades: function(currency, callback) {
         bit2cPublicRequest('trades.json', currency, undefined, callback);
      },

      getOrderBook: function(currency, since, callback) {
         var param;
         if (since) {
            param = {
               key: 'since',
               value: since
            };
         }
         bit2cPublicRequest('orderbook.json', currency, param, callback);
      },

      getBalance: function(credentials, callback) {
         bit2cPrivateRequest('Account/Balance', credentials,
                             'nonce=' + getUniqueNonce(),
                             callback);
      },

      getMyOrders: function(credentials, pair, callback) {

         var queryString = '';
         if (pair) {
            queryString = 'pair=' + pair + '&';
         }
         queryString +=  'nonce=' + getUniqueNonce();

         bit2cPrivateRequest('Order/MyOrders', credentials,
                             queryString,
                             callback);
      },

      cancelOrder: function(credentials, tid, callback) {
         var queryString = 'id=' + tid + '&';
         queryString +=  'nonce=' + getUniqueNonce();

         bit2cPrivateRequest('Order/CancelOrder', credentials,
                             queryString,
                             callback);
      },

      getAccountHistory: function(credentials, from, to, callback) {
         var queryString = '',
            fromStr,
            toStr;

         if (from) {
            fromStr = moment(from).format('DD/MM/YYYY HH:mm:ss.SSS');
            queryString += "from=" + (from?fromStr:null) + '&';
         }

         if (to) {
            toStr = moment(to).format('DD/MM/YYYY HH:mm:ss.SSS');
            queryString += "to=" + (to?toStr:null) + '&';
         }

         queryString +=  'nonce=' + getUniqueNonce();
         console.log(queryString);

        bit2cPrivateRequest('Order/AccountHistory', credentials,
                             queryString,
                             callback);
      }

   };
   return that;
})();
<commit_msg>tiny bug fix<commit_after>module.exports = (function() {
   var request = require('request'),
      crypto = require('crypto'),
      moment = require('moment'),
      lastNonce;

   function bit2cPublicRequest(operation, currency, param, callback) {

      var url = 'https://www.bit2c.co.il/Exchanges/' + currency + '/' + operation;
      if (param) {
         url += '?'+ param.key + '=' + param.value;
      }

      request({
            method: 'GET',
            url: url
         }, function(error, response, bodyString) {

            var normalResponseCode = '200';

            if (error !== null || (typeof (bodyString) !== 'string') ||
                (response.statusCode + '' !== normalResponseCode)) {
               callback(new Error('cannot get response from bit2c. error: ' + error +
                                  ' reason: ' +
                                  (response?response.statusCode:'undefined')));
               return;
            }

            callback(undefined, JSON.parse(bodyString));
         });
   }

   function bit2cPrivateRequest(path, credentials, queryString, callback) {

      var url = 'https://www.bit2c.co.il/' + path,
         signature;

      signature = crypto.createHmac('sha512', credentials.secret.toUpperCase()).update(queryString).digest('base64');
      request({
         method: 'POST',
         url: url,
         headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'key': credentials.key,
            'sign': signature
         },
         body: queryString
      }, function(error, response, bodyString) {

         var normalResponseCode = '200';

         if (error !== null || (typeof (bodyString) !== 'string') ||
             (response.statusCode + '' !== normalResponseCode)) {
            callback(new Error('cannot get response from bit2c. error: ' + error +
                               ' reason: ' +
                            (response?response.statusCode:'undefined')));
            return;
         }

         callback(undefined, JSON.parse(bodyString));
      });
   }

   // This function will hopefully work - if runnnig the api from the same computer
   // running this from multiple computers will probably fail it since there
   // might be clock skews
   function getUniqueNonce() {
      // unix time diff ti 14/01/2014 / 250 - the min response time i assume,
      // this technique should be sufficient for the next few years...
      var result = parseInt(((new Date()).getTime() - 1389729146519)/250,10);

      // this is good if from the same process we run multiple parallel requests...
      if (result == lastNonce) {
         result +=1;
      }
      lastNonce = result;
      return result;
   }

   var that = {

      getTicker: function(currency, callback) {
         bit2cPublicRequest('Ticker.json', currency,  undefined, callback);
      },

      getTrades: function(currency, callback) {
         bit2cPublicRequest('trades.json', currency, undefined, callback);
      },

      getOrderBook: function(currency, since, callback) {
         var param;
         if (since) {
            param = {
               key: 'since',
               value: since
            };
         }
         bit2cPublicRequest('orderbook.json', currency, param, callback);
      },

      getBalance: function(credentials, callback) {
         bit2cPrivateRequest('Account/Balance', credentials,
                             'nonce=' + getUniqueNonce(),
                             callback);
      },

      getMyOrders: function(credentials, pair, callback) {

         var queryString = '';
         if (pair) {
            queryString = 'pair=' + pair + '&';
         }
         queryString +=  'nonce=' + getUniqueNonce();

         bit2cPrivateRequest('Order/MyOrders', credentials,
                             queryString,
                             callback);
      },

      cancelOrder: function(credentials, tid, callback) {
         var queryString = 'id=' + tid + '&';
         queryString +=  'nonce=' + getUniqueNonce();

         bit2cPrivateRequest('Order/CancelOrder', credentials,
                             queryString,
                             callback);
      },

      getAccountHistory: function(credentials, from, to, callback) {
         var queryString = '',
            fromStr,
            toStr;

         if (from) {
            fromStr = moment(from).format('DD/MM/YYYY HH:mm:ss.SSS');
         }
         if (to) {
            toStr = moment(to).format('DD/MM/YYYY HH:mm:ss.SSS');
         }

         queryString += "from=" + (from?fromStr:null) + '&';
         queryString += "to=" + (to?toStr:null) + '&';
         queryString +=  'nonce=' + getUniqueNonce();
         console.log(queryString);

        bit2cPrivateRequest('Order/AccountHistory', credentials,
                             queryString,
                             callback);
      }

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


<commit_before>module.exports = {
    schema: true,

    attributes: {
        sectionNumber: {
            type: 'string'
        },
        professor:{
          model: 'Professor'
        },
        meets: {
            type: 'array',
            required: true
        },
        duration: {
            type: 'integer',
        },
        start: {
            type: 'integer'
        },
        end: {
            type: 'integer'
        },
        capacity: {
            type: 'integer'
        },
        available: {
            type: 'integer'
        },
        waitlist: {
            type: 'integer'
        },
        textbooks: {
            collection: 'textbook',
            via: 'sections'
        },
        course:{
          model: 'Course',
          required: true
        }
    },

  beforeCreate: function(values, callback){
    Section.findOne()
    .where({ sectionNumber: values.sectionNumber, course: values.course })
    .then(function(section){
      if(section) throw 'Error.Section.AlreadyExists'; //simple check on the name to see if section name exists already
      else{
        Course.findOne()
        .where({ id: values.course })
        .then(function(course){
          if(!course) callback('Error.Course.NotFound'); //because throws in nested promises don't get caught by outer catch
          callback();
        });
      }
    })
    .catch(function(err){
      console.log(err);
      callback(err);
    });

  }
}<commit_msg>Added location to section model. Closes #12<commit_after>module.exports = {
    schema: true,

    attributes: {
        sectionNumber: {
            type: 'string'
        },
        professor:{
          model: 'Professor'
        },
        meets: {
            type: 'array',
            required: true
        },
        duration: {
            type: 'integer',
        },
        start: {
            type: 'integer'
        },
        end: {
            type: 'integer'
        },
        capacity: {
            type: 'integer'
        },
        available: {
            type: 'integer'
        },
        waitlist: {
            type: 'integer'
        },
        textbooks: {
            collection: 'textbook',
            via: 'sections'
        },
        course:{
          model: 'Course',
          required: true
        },
        location: {
          type: 'string'
        }
    },

  beforeCreate: function(values, callback){
    Section.findOne()
    .where({ sectionNumber: values.sectionNumber, course: values.course })
    .then(function(section){
      if(section) throw 'Error.Section.AlreadyExists'; //simple check on the name to see if section name exists already
      else{
        Course.findOne()
        .where({ id: values.course })
        .then(function(course){
          if(!course) callback('Error.Course.NotFound'); //because throws in nested promises don't get caught by outer catch
          callback();
        });
      }
    })
    .catch(function(err){
      console.log(err);
      callback(err);
    });

  }
}<|endoftext|>


<commit_before>const util = require('./util')

const defaults = {
  imageLink: ref => ref,
  toUrl: ref => ref,
  protocols: []
}

const existingProtocols = ['http', 'https', 'ftp']
const additionalProtocols = ['data', 'dat', 'magnet']

let config = {}

// init
const md = require('markdown-it')({ linkify: true })
  .use(require('markdown-it-hashtag'), { hashtagRegExp: '[\\w+-]+' })
  .use(require('markdown-it-emoji'))

// hashtag
md.renderer.rules.hashtag_open = function (tokens, idx) {
  var tagName = tokens[idx].content.toLowerCase()
  const url = config.toUrl('#' + tagName)
  return ''
}

const oldEmojiRender = md.renderer.rules.emoji || function (tokens, idx, options, env, self) {
  return self.renderToken(tokens, idx, options)
}

// emoji
md.renderer.rules.emoji = function (tokens, idx) {
  if (config.emoji) {
    const emoji = tokens[idx].markup
    return config.emoji(emoji)
  } else {
    return oldEmojiRender(tokens, idx)
  }
}

// links
var oldLinkOpenRender = md.renderer.rules.link_open || function (tokens, idx, options, env, self) {
  return self.renderToken(tokens, idx, options)
}

md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
  const href = tokens[idx].attrs[0][1]
  if (href.indexOf('not-allowed-as-link') >= 0) {
    tokens[idx].attrs[0] = ['class', 'bad']
  } else if (!href.startsWith('#')) {
    tokens[idx].attrPush(['target', '_blank'])
  }

  const oldLinkOpenRenderResult = oldLinkOpenRender(tokens, idx, options, env, self)
  return oldLinkOpenRenderResult.replace('<a href="%25', ' {
  md.linkify.add(sigil, {
    validate: function (text, pos, self) {
      var tail = text.slice(pos)

      if (!self.re.sigil) {
        self.re.sigil = sigilRegExp
      }
      if (self.re.sigil.test(tail)) {
        return tail.match(self.re.sigil)[0].length
      }
      return 0
    },
    normalize: function (match) {
      match.text = util.formatSigilText(match.text)
      match.url = config.toUrl(match.raw)
      return match
    }
  })
})

// sigil @ and mention
md.linkify.add('@', {
  validate: function (text, pos, self) {
    var tail = text.slice(pos)

    if (!self.re.sigil) {
      self.re.sigil = sigilRegExp
    }
    if (!self.re.mention) {
      self.re.mention = new RegExp(
        /^[A-Za-z0-9._\-+=/]*[A-Za-z0-9_\-+=/]/
      )
    }

    if (self.re.sigil.test(tail)) {
      return tail.match(self.re.sigil)[0].length
    }
    if (self.re.mention.test(tail)) {
      const match = tail.match(self.re.mention)[0]
      const attempt = config.toUrl('@' + match)
      if (attempt.length) {
        return tail.match(self.re.mention)[0].length
      }
    }
    return 0
  },
  normalize: function (match) {
    match.url = config.toUrl(match.raw)
    if (sigilRegExp.test(match.raw)) {
      match.text = util.formatSigilText(match.text)
    }
  }
})

// image
md.renderer.rules.image = (tokens, idx) => {
  const token = tokens[idx]

  const text = token.attrs[0][1]
  const title = token.attrs[1][1]
  const alt = token.content
  const url = config.imageLink(text)
  const src = config.toUrl(text, true)

  const media = {
    src,
    alt,
    title
  }

  let properties = ''

  Object.keys(media).forEach(key => {
    const value = media[key]
    if (value.length) {
      properties += ` ${key}="${value}"`
    }
  })

  if (alt.startsWith('audio:')) {
    return `<video controls${properties}/>`
  } else if (alt.startsWith('video:')) {
    return `<video controls${properties}/>`
  } else {
    // XXX: do all images need to be wrapped in links?
    return `<a href="${url}"><img${properties}></a>`
  }
}

module.exports = (text, opts) => {
  config = Object.assign({}, defaults, opts)

  Object.values(config.protocols.concat(additionalProtocols)).forEach(protocol => {
    if (!existingProtocols.includes(protocol)) {
      existingProtocols.push(protocol)
      md.linkify.add(protocol + ':', 'http:')
    }
  })

  return md.render('' + (text || ''))
}
<commit_msg>Make audio tag actually output audio<commit_after>const util = require('./util')

const defaults = {
  imageLink: ref => ref,
  toUrl: ref => ref,
  protocols: []
}

const existingProtocols = ['http', 'https', 'ftp']
const additionalProtocols = ['data', 'dat']

let config = {}

// init
const md = require('markdown-it')({ linkify: true })
  .use(require('markdown-it-hashtag'), { hashtagRegExp: '[\\w+-]+' })
  .use(require('markdown-it-emoji'))

// hashtag
md.renderer.rules.hashtag_open = function (tokens, idx) {
  var tagName = tokens[idx].content.toLowerCase()
  const url = config.toUrl('#' + tagName)
  return ''
}

const oldEmojiRender = md.renderer.rules.emoji || function (tokens, idx, options, env, self) {
  return self.renderToken(tokens, idx, options)
}

// emoji
md.renderer.rules.emoji = function (tokens, idx) {
  if (config.emoji) {
    const emoji = tokens[idx].markup
    return config.emoji(emoji)
  } else {
    return oldEmojiRender(tokens, idx)
  }
}

// links
var oldLinkOpenRender = md.renderer.rules.link_open || function (tokens, idx, options, env, self) {
  return self.renderToken(tokens, idx, options)
}

md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
  const href = tokens[idx].attrs[0][1]
  if (href.indexOf('not-allowed-as-link') >= 0) {
    tokens[idx].attrs[0] = ['class', 'bad']
  } else if (!href.startsWith('#')) {
    tokens[idx].attrPush(['target', '_blank'])
  }

  const oldLinkOpenRenderResult = oldLinkOpenRender(tokens, idx, options, env, self)
  return oldLinkOpenRenderResult.replace('<a href="%25', ' {
  md.linkify.add(sigil, {
    validate: function (text, pos, self) {
      var tail = text.slice(pos)

      if (!self.re.sigil) {
        self.re.sigil = sigilRegExp
      }
      if (self.re.sigil.test(tail)) {
        return tail.match(self.re.sigil)[0].length
      }
      return 0
    },
    normalize: function (match) {
      match.text = util.formatSigilText(match.text)
      match.url = config.toUrl(match.raw)
      return match
    }
  })
})

// sigil @ and mention
md.linkify.add('@', {
  validate: function (text, pos, self) {
    var tail = text.slice(pos)

    if (!self.re.sigil) {
      self.re.sigil = sigilRegExp
    }
    if (!self.re.mention) {
      self.re.mention = new RegExp(
        /^[A-Za-z0-9._\-+=/]*[A-Za-z0-9_\-+=/]/
      )
    }

    if (self.re.sigil.test(tail)) {
      return tail.match(self.re.sigil)[0].length
    }
    if (self.re.mention.test(tail)) {
      const match = tail.match(self.re.mention)[0]
      const attempt = config.toUrl('@' + match)
      if (attempt.length) {
        return tail.match(self.re.mention)[0].length
      }
    }
    return 0
  },
  normalize: function (match) {
    match.url = config.toUrl(match.raw)
    if (sigilRegExp.test(match.raw)) {
      match.text = util.formatSigilText(match.text)
    }
  }
})

md.linkify.add('magnet:', {
  validate: function (text, pos, self) {
    var tail = text.slice(pos)
    if (!self.re.magnet) {
      self.re.magnet = new RegExp(
        /^\S*/
      )
    }
    if (self.re.magnet.test(tail)) {
      return tail.match(self.re.magnet)[0].length
    }
    return 0
  },
  normalize: function (match) {
    match.url = config.toUrl(match.raw)
  }
})

// image
md.renderer.rules.image = (tokens, idx) => {
  const token = tokens[idx]

  const text = token.attrs[0][1]
  const title = token.attrs[1][1]
  const alt = token.content
  const url = config.imageLink(text)
  const src = config.toUrl(text, true)

  const media = {
    src,
    alt,
    title
  }

  let properties = ''

  Object.keys(media).forEach(key => {
    const value = media[key]
    if (value.length) {
      properties += ` ${key}="${value}"`
    }
  })

  if (alt.startsWith('audio:')) {
    return `<audio controls${properties}/>`
  } else if (alt.startsWith('video:')) {
    return `<video controls${properties}/>`
  } else {
    // XXX: do all images need to be wrapped in links?
    return `<a href="${url}"><img${properties}></a>`
  }
}

module.exports = (text, opts) => {
  config = Object.assign({}, defaults, opts)

  Object.values(config.protocols.concat(additionalProtocols)).forEach(protocol => {
    if (!existingProtocols.includes(protocol)) {
      console.log('ADDING', protocol)
      existingProtocols.push(protocol)
      md.linkify.add(protocol + ':', 'http:')
    }
  })

  return md.render('' + (text || ''))
}
<|endoftext|>


<commit_before>/* global module require define */
; // eslint-disable-line
(function (global, factory) {
	'use strict';

	// Support CommonJS, AMD, and global script loading.
	if (typeof exports === 'object' && typeof module !== 'undefined') {
		module.exports = factory(require('brixx'));
	} else if (typeof define === 'function' && define.amd) {
		define(['brixx'], factory);
	} else {
		global.BLOXX = factory(global.BRIXX);
	}
})(this, function (BRIXX) {
	'use strict';

	var BLOXX = Object.create(null);

	function indexOf(list, attr, val) {
		var i = 0;
		for (i; i < list.length; i += 1) {
			if (list[i][attr] === val) {
				return i;
			}
		}
		return -1;
	}

	BLOXX.uniqueId = (function () {
		var counter = 0;
		var prefix = 'bloxx_';

		return function uniqueId() {
			counter += 1;
			return prefix + counter;
		};
	})();

	BLOXX.BaseModel = BRIXX.Model;

	BLOXX.Model = {
		initialize: function initialize(spec) {
			if (!this.type || typeof this.type !== 'string') {
				throw new Error('The .type property must be a defined String');
			}
			if (!this.defaults || typeof this.defaults !== 'object') {
				throw new Error('The .defaults property must be a defined Object');
			}

			var self = this;

			// Make a copy of defaults, because we don't want to
			// mess with the prototype.defaults.
			var defaults = Object.keys(this.defaults).reduce(function (defaults, k) {
				defaults[k] = self.defaults[k];
				return defaults;
			}, Object.create(null));

			defaults.type = this.type;
			defaults.name = this.type;
			defaults.id = null;
			defaults.relationships = null;

			this.defaults = defaults;

			// Typecast relationship definitions.
			if (!Array.isArray(this.relationshipDefinitions)) {
				if (typeof this.relationshipDefinitions === 'string') {
					this.relationshipDefinitions =
						this.relationshipDefinitions.split(' ');
				} else {
					this.relationshipDefinitions = [];
				}
			}

			var relationships = {
				has: {},
				belongsTo: {}
			};

			spec.relationships = spec.relationships || {};
			spec.relationships.has = spec.relationships.has || {};
			spec.relationships.belongsTo = spec.relationships.belongsTo || {};

			// Set spec.relationships based on relationship definitions.
			this.relationshipDefinitions.reduce(function (relationships, def) {
				var type;
				var direction;

				if (def.indexOf('has') === 0) {
					type = def.replace(/^has/, '');
					direction = 'has';
				}
				if (def.indexOf('belongsTo') === 0) {
					type = def.replace(/^belongsTo/, '');
					direction = 'belongsTo';
				}

				var list = spec.relationships[direction][type] || [];
				var constructor = self.getConstructorFor(type);
				if (typeof constructor !== 'function') {
					throw new Error('No constructor available for type "' + type + '"');
				}

				relationships[direction][type] = list.map(function (item) {
					if (item && typeof item === 'object') {
						if (!(item.id || typeof item.id === 'number')) {
							throw new Error(
								'An id attribute is required in relationships data');
						}
						return constructor(item);
					}
					return constructor({id: item});
				});

				return relationships;
			}, relationships);

			spec.relationships = BRIXX.deepFreeze(relationships);

			Object.defineProperties(this, {
				relationshipUpdates: {
					value: this.relationshipUpdates || []
				}
			});
			return this;
		},

		isNew: function isNew() {
			return !this.hasId();
		},

		generateId: BLOXX.uniqueId,

		hasRelationships: function () {
			var relationships = this.relationships;
			var types = Object.keys(relationships.belongsTo).map(function (type) {
				return relationships.belongsTo[type];
			});

			types = types.concat(Object.keys(relationships.has).map(function (type) {
				return relationships.has[type];
			}));

			var i;
			for (i = 0; i < types.length; i += 1) {
				if (types[i].length) {
					return true;
				}
			}
			return false;
		},

		fetch: function fetch(options) {
			options = options || Object.create(null);

			if (!this.hasId()) {
				throw new Error(
					'The .id property must be present for .fetch()');
			}

			var self = this;

			options.include = (options.include || '').split(' ').map(function (def) {
				if (self.relationshipDefinitions.indexOf(def) === -1) {
					throw new Error('Relationship ' + def + ' not defined on ' + self.type);
				}
				if (def.indexOf('has') === 0) {
					return {
						direction: 'has',
						type: def.replace(/^has/, '')
					};
				}
				if (def.indexOf('belongsTo') === 0) {
					return {
						direction: 'belongsTo',
						type: def.replace(/^belongsTo/, '')
					};
				}
			});

			return this._getRecord(options);
		},

		save: function save(options) {
			options = options || Object.create(null);

			return this.isNew() ?
				this._createRecord(options) :
				this._updateRecord(options);
		},

		remove: function remove(options) {
			if (!this.hasId()) {
				throw new Error(
					'The .id property must be present for .remove()');
			}

			options = options || Object.create(null);

			return this._removeRecord();
		},

		addItem: function (item) {
			item = item || Object.create(null);
			if (!item.type || typeof item.type !== 'string') {
				throw new Error('The .type property must be present on an item');
			}
			if (!(item.id || typeof item.id === 'number')) {
				throw new Error('The .id property must be present on an item');
			}

			this.relationshipUpdates.push({
				action: 'create',
				direction: 'has',
				type: item.type,
				item: item
			});

			var newInstance = Object.create(this);
			newInstance.initialize(this.toJSON());
			return newInstance;
		},

		removeItem: function (item) {
			item = item || Object.create(null);
			if (!item.type || typeof item.type !== 'string') {
				throw new Error('The .type property must be present on an item');
			}
			if (!(item.id || typeof item.id === 'number')) {
				throw new Error('The .id property must be present on an item');
			}

			this.relationshipUpdates.push({
				action: 'remove',
				direction: 'has',
				type: item.type,
				item: item
			});

			var newInstance = Object.create(this);
			newInstance.initialize(this.toJSON());
			return newInstance;
		},

		connectTo: function (item) {
			item = item || Object.create(null);
			if (!item.type || typeof item.type !== 'string') {
				throw new Error('The .type property must be present on an item');
			}
			if (!(item.id || typeof item.id === 'number')) {
				throw new Error('The .id property must be present on an item');
			}

			this.relationshipUpdates.push({
				action: 'create',
				direction: 'belongsTo',
				type: item.type,
				item: item
			});

			var newInstance = Object.create(this);
			newInstance.initialize(this.toJSON());
			return newInstance;
		},

		removeFrom: function (item) {
			item = item || Object.create(null);
			if (!item.type || typeof item.type !== 'string') {
				throw new Error('The .type property must be present on an item');
			}
			if (!(item.id || typeof item.id === 'number')) {
				throw new Error('The .id property must be present on an item');
			}

			this.relationshipUpdates.push({
				action: 'remove',
				direction: 'belongsTo',
				type: item.type,
				item: item
			});

			var newInstance = Object.create(this);
			newInstance.initialize(this.toJSON());
			return newInstance;
		},

		_createRecord: function createRecord(options) {
			var attrs = this.toJSON();
			attrs.id = this.generateId();

			var rUpdates = this.relationshipUpdates.filter(function (update) {
				return update.action === 'create';
			});

			var relationships = attrs.relationships;

			// Concatenate all the relationship updates.
			Object.keys(relationships).forEach(function (direction) {
				Object.keys(relationships[direction]).forEach(function (type) {
					var list = relationships[direction][type];
					rUpdates = rUpdates.concat(list.map(function (item) {
						return {
							action: 'create',
							direction: direction,
							type: type,
							item: item
						};
					}));
				});
			});

			// Set relationships hash for the new instance.
			if (rUpdates.length) {
				options.relationshipUpdates = rUpdates;
				rUpdates.reduce(function (relationships, update) {
					var list = relationships[update.direction][update.type] || [];
					list.push(update.item);
					relationships[update.direction][update.type] = list;
					return relationships;
				}, attrs.relationships);
			} else {
				options.relationshipUpdates = null;
			}

			var newInstance = Object.create(this);

			return this.createRecord(attrs, options).then(function () {
				newInstance.updateRelationships.length = 0;
				newInstance.initialize(attrs);
				return newInstance;
			});
		},

		_updateRecord: function updateRecord(options) {
			var attrs = this.toJSON();
			var relationshipUpdates = this.relationshipUpdates.length ?
				this.relationshipUpdates : null;

			options.relationshipUpdates = relationshipUpdates;

			var newInstance = Object.create(this);

			return this.updateRecord(attrs, options).then(function () {
				// Set relationships hash for the new instance.
				relationshipUpdates.reduce(function (relationships, update) {
					var list = relationships[update.direction][update.type] || [];
					var i = indexOf(list, 'id', update.item.id);
					if (i === -1) {
						list.push(update.item);
					} else if (update.action === 'remove') {
						list.splice(i, 1);
					} else {
						list[i] = update.item;
					}
					relationships[update.direction][update.type] = list;
					return relationships;
				}, attrs.relationships);

				newInstance.updateRelationships.length = 0;
				newInstance.initialize(attrs);
				return newInstance;
			});
		},

		_getRecord: function getRecord(options) {
			var attrs = this.toJSON();
			var newInstance = Object.create(this);

			return this.getRecord(attrs, options).then(function (data) {
				var relationships = {
					has: {},
					belongsTo: {}
				};

				data.relationships.reduce(function (relationships, rel) {
					relationships[rel.direction][rel.type] = rel.items;
					return relationships;
				}, relationships);

				data.relationships = relationships;
				newInstance.initialize(data);
				return newInstance;
			});
		},

		_removeRecord: function removeRecord(options) {
			var attrs = this.toJSON();
			var relationships = attrs.relationships;
			var rUpdates = [];

			// Concatenate all the relationship updates.
			Object.keys(relationships).forEach(function (direction) {
				Object.keys(relationships[direction]).forEach(function (type) {
					var list = relationships[direction][type];
					rUpdates = rUpdates.concat(list.map(function (item) {
						return {
							action: 'remove',
							direction: direction,
							type: type,
							item: item
						};
					}));
				});
			});

			options.relationshipUpdates = rUpdates;
			var newInstance = Object.create(this);

			return this.removeRecord(attrs, options).then(function () {
				newInstance.updateRelationships.length = 0;
				delete attrs.relationships;
				newInstance.initialize(attrs);
				return newInstance;
			});
		},

		toJSON: function toJSON() {
			var self = this;

			var relationships = Object.create(null);
			relationships.has = Object.create(null);
			relationships.belongsTo = Object.create(null);

			return this._keys.reduce(function (attrs, k) {
				var v = self[k];

				if (k === 'relationships') {
					attrs.relationships = self.relationshipDefinitions
						.reduce(function (relationships, def) {
							var type;
							var direction;

							if (def.indexOf('has') === 0) {
								type = def.replace(/^has/, '');
								direction = 'has';
							}
							if (def.indexOf('belongsTo') === 0) {
								type = def.replace(/^belongsTo/, '');
								direction = 'belongsTo';
							}

							var list = self.relationships[direction][type] || [];

							relationships[direction][type] = list.map(function (item) {
								if (item && typeof item === 'object') {
									return item;
								}
								return {id: item};
							});

							return relationships;
						}, relationships);

				} else if (k !== 'name') {
					attrs[k] = typeof v.toJSON === 'function' ? v.toJSON() : v;
				}

				return attrs;
			}, Object.create(null));
		}
	};

	return BLOXX;
});
<commit_msg>Adds registry object.<commit_after>/* global module require define */
; // eslint-disable-line
(function (global, factory) {
	'use strict';

	// Support CommonJS, AMD, and global script loading.
	if (typeof exports === 'object' && typeof module !== 'undefined') {
		module.exports = factory(require('brixx'));
	} else if (typeof define === 'function' && define.amd) {
		define(['brixx'], factory);
	} else {
		global.BLOXX = factory(global.BRIXX);
	}
})(this, function (BRIXX) {
	'use strict';

	var BLOXX = {
		factory: BRIXX.factory,
		BaseModel: BRIXX.Model
	};

	function indexOf(list, attr, val) {
		var i = 0;
		for (i; i < list.length; i += 1) {
			if (list[i][attr] === val) {
				return i;
			}
		}
		return -1;
	}

	BLOXX.uniqueId = (function () {
		var counter = 0;
		var prefix = 'bloxx_';

		return function uniqueId() {
			counter += 1;
			return prefix + counter;
		};
	})();

	BLOXX.Model = {
		initialize: function initialize(spec) {
			if (!this.type || typeof this.type !== 'string') {
				throw new Error('The .type property must be a defined String');
			}
			if (!this.defaults || typeof this.defaults !== 'object') {
				throw new Error('The .defaults property must be a defined Object');
			}

			var self = this;

			// Make a copy of defaults, because we don't want to
			// mess with the prototype.defaults.
			var defaults = Object.keys(this.defaults).reduce(function (defaults, k) {
				defaults[k] = self.defaults[k];
				return defaults;
			}, Object.create(null));

			defaults.type = this.type;
			defaults.name = this.type;
			defaults.id = null;
			defaults.relationships = null;

			this.defaults = defaults;

			// Typecast relationship definitions.
			if (!Array.isArray(this.relationshipDefinitions)) {
				if (typeof this.relationshipDefinitions === 'string') {
					this.relationshipDefinitions =
						this.relationshipDefinitions.split(' ');
				} else {
					this.relationshipDefinitions = [];
				}
			}

			var relationships = {
				has: {},
				belongsTo: {}
			};

			spec.relationships = spec.relationships || {};
			spec.relationships.has = spec.relationships.has || {};
			spec.relationships.belongsTo = spec.relationships.belongsTo || {};

			// Set spec.relationships based on relationship definitions.
			this.relationshipDefinitions.reduce(function (relationships, def) {
				var type;
				var direction;

				if (def.indexOf('has') === 0) {
					type = def.replace(/^has/, '');
					direction = 'has';
				}
				if (def.indexOf('belongsTo') === 0) {
					type = def.replace(/^belongsTo/, '');
					direction = 'belongsTo';
				}

				var list = spec.relationships[direction][type] || [];
				var constructor = self.getConstructorFor(type);
				if (typeof constructor !== 'function') {
					throw new Error('No constructor available for type "' + type + '"');
				}

				relationships[direction][type] = list.map(function (item) {
					if (item && typeof item === 'object') {
						if (!(item.id || typeof item.id === 'number')) {
							throw new Error(
								'An id attribute is required in relationships data');
						}
						return constructor(item);
					}
					return constructor({id: item});
				});

				return relationships;
			}, relationships);

			spec.relationships = BRIXX.deepFreeze(relationships);

			Object.defineProperties(this, {
				relationshipUpdates: {
					value: this.relationshipUpdates || []
				}
			});
			return this;
		},

		isNew: function isNew() {
			return !this.hasId();
		},

		generateId: BLOXX.uniqueId,

		hasRelationships: function () {
			var relationships = this.relationships;
			var types = Object.keys(relationships.belongsTo).map(function (type) {
				return relationships.belongsTo[type];
			});

			types = types.concat(Object.keys(relationships.has).map(function (type) {
				return relationships.has[type];
			}));

			var i;
			for (i = 0; i < types.length; i += 1) {
				if (types[i].length) {
					return true;
				}
			}
			return false;
		},

		fetch: function fetch(options) {
			options = options || Object.create(null);

			if (!this.hasId()) {
				throw new Error(
					'The .id property must be present for .fetch()');
			}

			var self = this;

			if (options.include) {
				options.include = options.include.split(' ').map(function (def) {
					if (self.relationshipDefinitions.indexOf(def) === -1) {
						throw new Error('Relationship ' + def +
							' not defined on ' + self.type);
					}
					if (def.indexOf('has') === 0) {
						return {
							direction: 'has',
							type: def.replace(/^has/, '')
						};
					}
					if (def.indexOf('belongsTo') === 0) {
						return {
							direction: 'belongsTo',
							type: def.replace(/^belongsTo/, '')
						};
					}
				});
			}

			return this._getRecord(options);
		},

		save: function save(options) {
			options = options || Object.create(null);

			return this.isNew() ?
				this._createRecord(options) :
				this._updateRecord(options);
		},

		remove: function remove(options) {
			if (!this.hasId()) {
				throw new Error(
					'The .id property must be present for .remove()');
			}

			options = options || Object.create(null);

			return this._removeRecord();
		},

		addItem: function (item) {
			item = item || Object.create(null);
			if (!item.type || typeof item.type !== 'string') {
				throw new Error('The .type property must be present on an item');
			}
			if (!(item.id || typeof item.id === 'number')) {
				throw new Error('The .id property must be present on an item');
			}

			this.relationshipUpdates.push({
				action: 'create',
				direction: 'has',
				type: item.type,
				item: item
			});

			var newInstance = Object.create(this);
			newInstance.initialize(this.toJSON());
			return newInstance;
		},

		removeItem: function (item) {
			item = item || Object.create(null);
			if (!item.type || typeof item.type !== 'string') {
				throw new Error('The .type property must be present on an item');
			}
			if (!(item.id || typeof item.id === 'number')) {
				throw new Error('The .id property must be present on an item');
			}

			this.relationshipUpdates.push({
				action: 'remove',
				direction: 'has',
				type: item.type,
				item: item
			});

			var newInstance = Object.create(this);
			newInstance.initialize(this.toJSON());
			return newInstance;
		},

		connectTo: function (item) {
			item = item || Object.create(null);
			if (!item.type || typeof item.type !== 'string') {
				throw new Error('The .type property must be present on an item');
			}
			if (!(item.id || typeof item.id === 'number')) {
				throw new Error('The .id property must be present on an item');
			}

			this.relationshipUpdates.push({
				action: 'create',
				direction: 'belongsTo',
				type: item.type,
				item: item
			});

			var newInstance = Object.create(this);
			newInstance.initialize(this.toJSON());
			return newInstance;
		},

		removeFrom: function (item) {
			item = item || Object.create(null);
			if (!item.type || typeof item.type !== 'string') {
				throw new Error('The .type property must be present on an item');
			}
			if (!(item.id || typeof item.id === 'number')) {
				throw new Error('The .id property must be present on an item');
			}

			this.relationshipUpdates.push({
				action: 'remove',
				direction: 'belongsTo',
				type: item.type,
				item: item
			});

			var newInstance = Object.create(this);
			newInstance.initialize(this.toJSON());
			return newInstance;
		},

		_createRecord: function createRecord(options) {
			var attrs = this.toJSON();
			attrs.id = this.generateId();

			var rUpdates = this.relationshipUpdates.filter(function (update) {
				return update.action === 'create';
			});

			var relationships = attrs.relationships;

			// Concatenate all the relationship updates.
			Object.keys(relationships).forEach(function (direction) {
				Object.keys(relationships[direction]).forEach(function (type) {
					var list = relationships[direction][type];
					rUpdates = rUpdates.concat(list.map(function (item) {
						return {
							action: 'create',
							direction: direction,
							type: type,
							item: item
						};
					}));
				});
			});

			// Set relationships hash for the new instance.
			if (rUpdates.length) {
				options.relationshipUpdates = rUpdates;
				rUpdates.reduce(function (relationships, update) {
					var list = relationships[update.direction][update.type] || [];
					list.push(update.item);
					relationships[update.direction][update.type] = list;
					return relationships;
				}, attrs.relationships);
			} else {
				options.relationshipUpdates = null;
			}

			var newInstance = Object.create(this);

			return this.createRecord(attrs, options).then(function () {
				newInstance.updateRelationships.length = 0;
				newInstance.initialize(attrs);
				return newInstance;
			});
		},

		_updateRecord: function updateRecord(options) {
			var attrs = this.toJSON();
			var relationshipUpdates = this.relationshipUpdates.length ?
				this.relationshipUpdates : null;

			options.relationshipUpdates = relationshipUpdates;

			var newInstance = Object.create(this);

			return this.updateRecord(attrs, options).then(function () {
				// Set relationships hash for the new instance.
				relationshipUpdates.reduce(function (relationships, update) {
					var list = relationships[update.direction][update.type] || [];
					var i = indexOf(list, 'id', update.item.id);
					if (i === -1) {
						list.push(update.item);
					} else if (update.action === 'remove') {
						list.splice(i, 1);
					} else {
						list[i] = update.item;
					}
					relationships[update.direction][update.type] = list;
					return relationships;
				}, attrs.relationships);

				newInstance.updateRelationships.length = 0;
				newInstance.initialize(attrs);
				return newInstance;
			});
		},

		_getRecord: function getRecord(options) {
			var attrs = this.toJSON();
			var newInstance = Object.create(this);

			return this.getRecord(attrs, options).then(function (data) {
				var relationships = {
					has: {},
					belongsTo: {}
				};

				if (data.relationships) {
					data.relationships.reduce(function (relationships, rel) {
						relationships[rel.direction][rel.type] = rel.items;
						return relationships;
					}, relationships);

					data.relationships = relationships;
				}
				newInstance.initialize(data);
				return newInstance;
			});
		},

		_removeRecord: function removeRecord(options) {
			var attrs = this.toJSON();
			var relationships = attrs.relationships;
			var rUpdates = [];

			// Concatenate all the relationship updates.
			Object.keys(relationships).forEach(function (direction) {
				Object.keys(relationships[direction]).forEach(function (type) {
					var list = relationships[direction][type];
					rUpdates = rUpdates.concat(list.map(function (item) {
						return {
							action: 'remove',
							direction: direction,
							type: type,
							item: item
						};
					}));
				});
			});

			options.relationshipUpdates = rUpdates;
			var newInstance = Object.create(this);

			return this.removeRecord(attrs, options).then(function () {
				newInstance.updateRelationships.length = 0;
				delete attrs.relationships;
				newInstance.initialize(attrs);
				return newInstance;
			});
		},

		toJSON: function toJSON() {
			var self = this;

			var relationships = Object.create(null);
			relationships.has = Object.create(null);
			relationships.belongsTo = Object.create(null);

			return this._keys.reduce(function (attrs, k) {
				var v = self[k];

				if (k === 'relationships') {
					attrs.relationships = self.relationshipDefinitions
						.reduce(function (relationships, def) {
							var type;
							var direction;

							if (def.indexOf('has') === 0) {
								type = def.replace(/^has/, '');
								direction = 'has';
							}
							if (def.indexOf('belongsTo') === 0) {
								type = def.replace(/^belongsTo/, '');
								direction = 'belongsTo';
							}

							var list = self.relationships[direction][type] || [];

							relationships[direction][type] = list.map(function (item) {
								if (item && typeof item === 'object') {
									return item;
								}
								return {id: item};
							});

							return relationships;
						}, relationships);

				} else if (k !== 'name') {
					attrs[k] = typeof v.toJSON === 'function' ? v.toJSON() : v;
				}

				return attrs;
			}, Object.create(null));
		}
	};

	BLOXX.Registry = {
		initialize: function () {
			this.constructors = Object.create(null);
		},

		createConstructor: function (mixin) {
			return BLOXX.factory([BLOXX.BaseModel, BLOXX.Model], mixin);
		},

		register: function (constructor) {
			var type = constructor.prototype.type;
			if (!type) {
				throw new Error('constructor.prototype must have a .type property');
			}

			this.constructors[type] = constructor;

			var self = this;
			constructor.prototype.getConstructorFor = function (type) {
				return self.constructors[type];
			};

			return this;
		}
	};

	return BLOXX;
});
<|endoftext|>


<commit_before>// Basic dates in dd/mm/yy or dd-mm-yy format.
// Years can be 4 digits. Days and Months can be 1 or 2 digits.
(function(){
  var parseDate = function(date) {
    date = date.replace(/\-/g, '/');
    date = date.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, '$1/$2/$3'); // format before getTime

    return new Date(date).getTime() || -1;
  };

  Tablesort.extend('date', function(item) {
    return (
      item.search(/(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\.?\,?\s*/i) !== -1 ||
      item.search(/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/) !== -1 ||
      item.search(/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/i) !== -1
    ) && !isNaN(parseDate(item));
  }, function(a, b) {
    a = a.toLowerCase();
    b = b.toLowerCase();

    return parseDate(b) - parseDate(a);
  });
}());
<commit_msg>Fix date sorting<commit_after>// Basic dates in dd/mm/yy or dd-mm-yy format.
// Years can be 4 digits. Days and Months can be 1 or 2 digits.
(function(){
  var parseDate = function(date) {
    date = date.replace(/\-/g, '/');
    date = date.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2,4})/, '$3-$2-$1'); // format before getTime

    return new Date(date).getTime() || -1;
  };

  Tablesort.extend('date', function(item) {
    return (
      item.search(/(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\.?\,?\s*/i) !== -1 ||
      item.search(/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/) !== -1 ||
      item.search(/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/i) !== -1
    ) && !isNaN(parseDate(item));
  }, function(a, b) {
    a = a.toLowerCase();
    b = b.toLowerCase();

    return parseDate(b) - parseDate(a);
  });
}());
<|endoftext|>


<commit_before>/** Generic class for sending non-upload ajax requests and handling the associated responses **/
/*globals qq, XMLHttpRequest*/
qq.AjaxRequestor = function (o) {
    "use strict";

    var log, shouldParamsBeInQueryString,
        queue = [],
        requestState = [],
        options = {
            method: 'POST',
            maxConnections: 3,
            customHeaders: {},
            endpointStore: {},
            paramsStore: {},
            mandatedParams: {},
            successfulResponseCodes: {
                "DELETE": [200, 202, 204],
                "POST": [200, 204]
            },
            cors: {
                expected: false,
                sendCredentials: false
            },
            log: function (str, level) {},
            onSend: function (id) {},
            onComplete: function (id, xhrOrXdr, isError) {},
            onCancel: function (id) {}
        };

    qq.extend(options, o);
    log = options.log;
    shouldParamsBeInQueryString = options.method === 'GET' || options.method === 'DELETE';

    // [Simple methods](http://www.w3.org/TR/cors/#simple-method)
    // are defined by the W3C in the CORS spec as a list of methods that, in part,
    // make a CORS request eligible to be exempt from preflighting.
    function isSimpleMethod() {
        return qq.indexOf(["GET", "POST", "HEAD"], options.method) >= 0;
    }

    // [Simple headers](http://www.w3.org/TR/cors/#simple-header)
    // are defined by the W3C in the CORS spec as a list of headers that, in part,
    // make a CORS request eligible to be exempt from preflighting.
    function containsNonSimpleHeaders(headers) {
        var containsNonSimple = false;

        qq.each(containsNonSimple, function(idx, header) {
            if (qq.indexOf(["Accept", "Accept-Language", "Content-Language", "Content-Type"], header) < 0) {
                containsNonSimple = true;
                return false;
            }
        });

        return containsNonSimple;
    }

    function isXdr(xhr) {
        //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.
        return options.cors.expected && xhr.withCredentials === undefined;
    }

    // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.
    function getCorsAjaxTransport() {
        var xhrOrXdr;

        if (window.XMLHttpRequest) {
            xhrOrXdr = new XMLHttpRequest();

            if (xhrOrXdr.withCredentials === undefined) {
                xhrOrXdr = new XDomainRequest();
            }
        }

        return xhrOrXdr;
    }

    // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.
    function getXhrOrXdr(id, dontCreateIfNotExist) {
        var xhrOrXdr = requestState[id].xhr;

        if (!xhrOrXdr && !dontCreateIfNotExist) {
            if (options.cors.expected) {
                xhrOrXdr = getCorsAjaxTransport();
            }
            else {
                xhrOrXdr = new XMLHttpRequest();
            }

            requestState[id].xhr = xhrOrXdr;
        }

        return xhrOrXdr;
    }

    // Removes element from queue, sends next request
    function dequeue(id) {
        var i = qq.indexOf(queue, id),
            max = options.maxConnections,
            nextId;

        delete requestState[id];
        queue.splice(i, 1);

        if (queue.length >= max && i < max) {
            nextId = queue[max - 1];
            sendRequest(nextId);
        }
    }

    function onComplete(id, xdrError) {
        var xhr = getXhrOrXdr(id),
            method = options.method,
            isError = xdrError === false;

        dequeue(id);

        if (isError) {
            log(method + " request for " + id + " has failed", "error");
        }
        else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {
            isError = true;
            log(method + " request for " + id + " has failed - response code " + xhr.status, "error");
        }

        options.onComplete(id, xhr, isError);
    }

    function getParams(id) {
        var params = {},
            additionalParams = requestState[id].additionalParams,
            mandatedParams = options.mandatedParams;

        if (options.paramsStore.getParams) {
            params = options.paramsStore.getParams(id);
        }

        if (additionalParams) {
            qq.each(additionalParams, function (name, val) {
                params[name] = val;
            });
        }

        if (mandatedParams) {
            qq.each(mandatedParams, function (name, val) {
                params[name] = val;
            });
        }

        return params;
    }

    function sendRequest(id) {
        var xhr = getXhrOrXdr(id),
            method = options.method,
            params = getParams(id),
            url;

        options.onSend(id);

        url = createUrl(id, params);

        // XDR and XHR status detection APIs differ a bit.
        if (isXdr(xhr)) {
            xhr.onload = getXdrLoadHandler(id);
            xhr.onerror = getXdrErrorHandler(id);
        }
        else {
            xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);
        }

        // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.
        xhr.open(method, url, true);

        // Instruct the transport to send cookies along with the CORS request,
        // unless we are using `XDomainRequest`, which is not capable of this.
        if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {
            xhr.withCredentials = true;
        }

        setHeaders(id);

        log('Sending ' + method + " request for " + id);
        if (!shouldParamsBeInQueryString && params) {
            xhr.send(qq.obj2url(params, ""));
        }
        else {
            xhr.send();
        }
    }

    function createUrl(id, params) {
        var endpoint = options.endpointStore.getEndpoint(id),
            addToPath = requestState[id].addToPath;

        if (addToPath != undefined) {
            endpoint += "/" + addToPath;
        }

        if (shouldParamsBeInQueryString && params) {
            return qq.obj2url(params, endpoint);
        }
        else {
            return endpoint;
        }
    }

    // Invoked by the UA to indicate a number of possible states that describe
    // a live `XMLHttpRequest` transport.
    function getXhrReadyStateChangeHandler(id) {
        return function () {
            if (getXhrOrXdr(id).readyState === 4) {
                onComplete(id);
            }
        };
    }

    // This will be called by IE to indicate **success** for an associated
    // `XDomainRequest` transported request.
    function getXdrLoadHandler(id) {
        return function () {
            onComplete(id);
        }
    }

    // This will be called by IE to indicate **failure** for an associated
    // `XDomainRequest` transported request.
    function getXdrErrorHandler(id) {
        return function () {
            onComplete(id, true);
        }
    }

    function setHeaders(id) {
        var xhr = getXhrOrXdr(id),
            customHeaders = options.customHeaders;

        // If this is a CORS request and a simple method with simple headers are used
        // on an `XMLHttpRequest`, exclude these specific non-simple headers
        // in an attempt to prevent preflighting.
        if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {
            xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
            xhr.setRequestHeader("Cache-Control", "no-cache");
        }

        // Assuming that all POST and PUT requests will need to be URL encoded.
        // The payload of a POST `XDomainRequest` also needs to be URL encoded, but we
        // can't set the Content-Type when using this transport.
        if ((options.method === "POST" || options.method === "PUT") && !isXdr(xhr)) {
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        }

        // `XDomainRequest` doesn't allow you to set any headers.
        if (!isXdr(xhr)) {
            qq.each(customHeaders, function (name, val) {
                xhr.setRequestHeader(name, val);
            });
        }
    }

    function cancelRequest(id) {
        var xhr = getXhrOrXdr(id, true),
            method = options.method;

        if (xhr) {
            // The event handlers we remove/unregister is dependant on whether we are
            // using `XDomainRequest` or `XMLHttpRequest`.
            if (isXdr(xhr)) {
                xhr.onerror = null;
                xhr.onload = null;
            }
            else {
                xhr.onreadystatechange = null;
            }

            xhr.abort();
            dequeue(id);

            log('Cancelled ' + method + " for " + id);
            options.onCancel(id);

            return true;
        }

        return false;
    }

    function isResponseSuccessful(responseCode) {
        return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;
    }

    return {
        send: function (id, addToPath, additionalParams) {
            requestState[id] = {
                addToPath: addToPath,
                additionalParams: additionalParams
            };

            var len = queue.push(id);

            // if too many active connections, wait...
            if (len <= options.maxConnections) {
                sendRequest(id);
            }
        },
        cancel: function (id) {
            return cancelRequest(id);
        }
    };
};
<commit_msg>#801 - prevent calls to setRequestHeader if XDR is used<commit_after>/** Generic class for sending non-upload ajax requests and handling the associated responses **/
/*globals qq, XMLHttpRequest*/
qq.AjaxRequestor = function (o) {
    "use strict";

    var log, shouldParamsBeInQueryString,
        queue = [],
        requestState = [],
        options = {
            method: 'POST',
            maxConnections: 3,
            customHeaders: {},
            endpointStore: {},
            paramsStore: {},
            mandatedParams: {},
            successfulResponseCodes: {
                "DELETE": [200, 202, 204],
                "POST": [200, 204]
            },
            cors: {
                expected: false,
                sendCredentials: false
            },
            log: function (str, level) {},
            onSend: function (id) {},
            onComplete: function (id, xhrOrXdr, isError) {},
            onCancel: function (id) {}
        };

    qq.extend(options, o);
    log = options.log;
    shouldParamsBeInQueryString = options.method === 'GET' || options.method === 'DELETE';

    // [Simple methods](http://www.w3.org/TR/cors/#simple-method)
    // are defined by the W3C in the CORS spec as a list of methods that, in part,
    // make a CORS request eligible to be exempt from preflighting.
    function isSimpleMethod() {
        return qq.indexOf(["GET", "POST", "HEAD"], options.method) >= 0;
    }

    // [Simple headers](http://www.w3.org/TR/cors/#simple-header)
    // are defined by the W3C in the CORS spec as a list of headers that, in part,
    // make a CORS request eligible to be exempt from preflighting.
    function containsNonSimpleHeaders(headers) {
        var containsNonSimple = false;

        qq.each(containsNonSimple, function(idx, header) {
            if (qq.indexOf(["Accept", "Accept-Language", "Content-Language", "Content-Type"], header) < 0) {
                containsNonSimple = true;
                return false;
            }
        });

        return containsNonSimple;
    }

    function isXdr(xhr) {
        //The `withCredentials` test is a commonly accepted way to determine if XHR supports CORS.
        return options.cors.expected && xhr.withCredentials === undefined;
    }

    // Returns either a new `XMLHttpRequest` or `XDomainRequest` instance.
    function getCorsAjaxTransport() {
        var xhrOrXdr;

        if (window.XMLHttpRequest) {
            xhrOrXdr = new XMLHttpRequest();

            if (xhrOrXdr.withCredentials === undefined) {
                xhrOrXdr = new XDomainRequest();
            }
        }

        return xhrOrXdr;
    }

    // Returns either a new XHR/XDR instance, or an existing one for the associated `File` or `Blob`.
    function getXhrOrXdr(id, dontCreateIfNotExist) {
        var xhrOrXdr = requestState[id].xhr;

        if (!xhrOrXdr && !dontCreateIfNotExist) {
            if (options.cors.expected) {
                xhrOrXdr = getCorsAjaxTransport();
            }
            else {
                xhrOrXdr = new XMLHttpRequest();
            }

            requestState[id].xhr = xhrOrXdr;
        }

        return xhrOrXdr;
    }

    // Removes element from queue, sends next request
    function dequeue(id) {
        var i = qq.indexOf(queue, id),
            max = options.maxConnections,
            nextId;

        delete requestState[id];
        queue.splice(i, 1);

        if (queue.length >= max && i < max) {
            nextId = queue[max - 1];
            sendRequest(nextId);
        }
    }

    function onComplete(id, xdrError) {
        var xhr = getXhrOrXdr(id),
            method = options.method,
            isError = xdrError === false;

        dequeue(id);

        if (isError) {
            log(method + " request for " + id + " has failed", "error");
        }
        else if (!isXdr(xhr) && !isResponseSuccessful(xhr.status)) {
            isError = true;
            log(method + " request for " + id + " has failed - response code " + xhr.status, "error");
        }

        options.onComplete(id, xhr, isError);
    }

    function getParams(id) {
        var params = {},
            additionalParams = requestState[id].additionalParams,
            mandatedParams = options.mandatedParams;

        if (options.paramsStore.getParams) {
            params = options.paramsStore.getParams(id);
        }

        if (additionalParams) {
            qq.each(additionalParams, function (name, val) {
                params[name] = val;
            });
        }

        if (mandatedParams) {
            qq.each(mandatedParams, function (name, val) {
                params[name] = val;
            });
        }

        return params;
    }

    function sendRequest(id) {
        var xhr = getXhrOrXdr(id),
            method = options.method,
            params = getParams(id),
            url;

        options.onSend(id);

        url = createUrl(id, params);

        // XDR and XHR status detection APIs differ a bit.
        if (isXdr(xhr)) {
            xhr.onload = getXdrLoadHandler(id);
            xhr.onerror = getXdrErrorHandler(id);
        }
        else {
            xhr.onreadystatechange = getXhrReadyStateChangeHandler(id);
        }

        // The last parameter is assumed to be ignored if we are actually using `XDomainRequest`.
        xhr.open(method, url, true);

        // Instruct the transport to send cookies along with the CORS request,
        // unless we are using `XDomainRequest`, which is not capable of this.
        if (options.cors.expected && options.cors.sendCredentials && !isXdr(xhr)) {
            xhr.withCredentials = true;
        }

        setHeaders(id);

        log('Sending ' + method + " request for " + id);
        if (!shouldParamsBeInQueryString && params) {
            xhr.send(qq.obj2url(params, ""));
        }
        else {
            xhr.send();
        }
    }

    function createUrl(id, params) {
        var endpoint = options.endpointStore.getEndpoint(id),
            addToPath = requestState[id].addToPath;

        if (addToPath != undefined) {
            endpoint += "/" + addToPath;
        }

        if (shouldParamsBeInQueryString && params) {
            return qq.obj2url(params, endpoint);
        }
        else {
            return endpoint;
        }
    }

    // Invoked by the UA to indicate a number of possible states that describe
    // a live `XMLHttpRequest` transport.
    function getXhrReadyStateChangeHandler(id) {
        return function () {
            if (getXhrOrXdr(id).readyState === 4) {
                onComplete(id);
            }
        };
    }

    // This will be called by IE to indicate **success** for an associated
    // `XDomainRequest` transported request.
    function getXdrLoadHandler(id) {
        return function () {
            onComplete(id);
        }
    }

    // This will be called by IE to indicate **failure** for an associated
    // `XDomainRequest` transported request.
    function getXdrErrorHandler(id) {
        return function () {
            onComplete(id, true);
        }
    }

    function setHeaders(id) {
        var xhr = getXhrOrXdr(id),
            customHeaders = options.customHeaders;

        // If this is a CORS request and a simple method with simple headers are used
        // on an `XMLHttpRequest`, exclude these specific non-simple headers
        // in an attempt to prevent preflighting.  `XDomainRequest` does not support setting
        // request headers, so we will take this into account as well.
        if (isXdr(xhr)) {
            if (!options.cors.expected || (!isSimpleMethod() || containsNonSimpleHeaders(customHeaders))) {
                xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
                xhr.setRequestHeader("Cache-Control", "no-cache");
            }
        }

        // Assuming that all POST and PUT requests will need to be URL encoded.
        // The payload of a POST `XDomainRequest` also needs to be URL encoded, but we
        // can't set the Content-Type when using this transport.
        if ((options.method === "POST" || options.method === "PUT") && !isXdr(xhr)) {
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        }

        // `XDomainRequest` doesn't allow you to set any headers.
        if (!isXdr(xhr)) {
            qq.each(customHeaders, function (name, val) {
                xhr.setRequestHeader(name, val);
            });
        }
    }

    function cancelRequest(id) {
        var xhr = getXhrOrXdr(id, true),
            method = options.method;

        if (xhr) {
            // The event handlers we remove/unregister is dependant on whether we are
            // using `XDomainRequest` or `XMLHttpRequest`.
            if (isXdr(xhr)) {
                xhr.onerror = null;
                xhr.onload = null;
            }
            else {
                xhr.onreadystatechange = null;
            }

            xhr.abort();
            dequeue(id);

            log('Cancelled ' + method + " for " + id);
            options.onCancel(id);

            return true;
        }

        return false;
    }

    function isResponseSuccessful(responseCode) {
        return qq.indexOf(options.successfulResponseCodes[options.method], responseCode) >= 0;
    }

    return {
        send: function (id, addToPath, additionalParams) {
            requestState[id] = {
                addToPath: addToPath,
                additionalParams: additionalParams
            };

            var len = queue.push(id);

            // if too many active connections, wait...
            if (len <= options.maxConnections) {
                sendRequest(id);
            }
        },
        cancel: function (id) {
            return cancelRequest(id);
        }
    };
};
<|endoftext|>