<commit_before>var fs = require('fs'),
    sys = require('sys'),
    events = require('events'),
    buffer = require('buffer'),
    http = require('http'),
    url = require('url'),
    path = require('path');

this.version = [0, 4, 3];

var mime = require('./node-static/mime');
var util = require('./node-static/util');

var serverInfo = 'node-static/' + this.version.join('.');

// In-memory file store
this.store = {};
this.indexStore = {};

this.Server = function (root, options) {
    if (root && (typeof(root) === 'object')) { options = root, root = null }

    this.root    = path.normalize(root || '.');
    this.options = options || {};
    this.cache   = 3600;

    this.defaultHeaders  = {};
    this.options.headers = this.options.headers || {};

    if ('cache' in this.options) {
        if (typeof(this.options.cache) === 'number') {
            this.cache = this.options.cache;
        } else if (! this.options.cache) {
            this.cache = false;
        }
    }

    if (this.cache !== false) {
        this.defaultHeaders['Cache-Control'] = 'max-age=' + this.cache;
    }
    this.defaultHeaders['Server'] = serverInfo;

    for (var k in this.defaultHeaders) {
        this.options.headers[k] = this.options.headers[k] ||
                                  this.defaultHeaders[k];
    }
};

this.Server.prototype.serveFile = function (pathname, req, res, callback) {
    var that = this,
        promise = new(events.EventEmitter);

    process.nextTick(function () {
        // Only allow GET and HEAD requests
        if (req.method !== 'GET' && req.method !== 'HEAD') {
            return finish(405, { 'Allow': 'GET, HEAD' });
        }

        pathname = path.normalize(path.join(that.root, pathname));

        // Make sure we're not trying to access a
        // file outside of the root.
        if (new(RegExp)('^' + that.root).test(pathname)) {
            fs.stat(pathname, function (e, stat) {
                var htmlIndex = path.join(pathname, 'index.html');

                if (e) {
                    finish(404, {});
                } else if (stat.isFile()) {
                    // Stream a single file.
                    that.respond(null, [pathname], stat, req, res, finish);

                } else if (stat.isDirectory()) {
                    fs.stat(htmlIndex, function (e, stat) {
                        if (!e) {
                            that.respond(null, [htmlIndex], stat, req, res, finish);
                        } else {
                            if (pathname in exports.store) {
                                util.mstat(pathname, exports.indexStore[pathname].files, function (e, stat) {
                                    that.respond(pathname, exports.indexStore[pathname].files, stat, req, res, finish);
                                });
                            } else {
                                // Stream a directory of files as a single file.
                                fs.readFile(path.join(pathname, 'index.json'), function (e, contents) {
                                    if (e) { return finish(404, {}) }
                                    var index = JSON.parse(contents);

                                    exports.indexStore[pathname] = index;

                                    util.mstat(pathname, index.files, function (e, stat) {
                                        that.respond(pathname, index.files, stat, req, res, finish);
                                    });
                                });
                            }
                        }
                    });
                } else {
                    finish(400, {});
                }
            });
        } else {
            // Forbidden
            finish(403, {});
        }
    });

    return promise;

    function finish(status, headers) {
        var result = {
            status:  status,
            headers: headers,
            message: http.STATUS_CODES[status]
        };

        headers['Server'] = serverInfo;

        if (status >= 400) {
            if (callback) {
                callback(result);
            } else {
                if (promise.listeners('error').length > 0) {
                    promise.emit('error', result);
                }
                res.writeHead(status, headers);
                res.end();
            }
        } else {
            // Don't end the request here, if we're streaming;
            // it's taken care of in `prototype.stream`.
            if (status !== 200 || req.method !== 'GET') {
                res.writeHead(status, headers);
                res.end();
            }
            callback && callback(null, result);
            promise.emit('success', result);
        }
    }
};
this.Server.prototype.serve = function (req, res, callback) {
    var that = this,
        promise = new(events.EventEmitter);

    process.nextTick(function () {
        var file = url.parse(req.url).pathname;

        that.serveFile(file, req, res, callback).addListener('success', function (result) {
            promise.emit('success', result);
        }).addListener('error', function (result) {
            if (promise.listeners('error').length > 0) {
                promise.emit('error', result);
            }
        });
    });
    return promise;
};

this.Server.prototype.respond = function (pathname, files, stat, req, res, finish) {
    var mtime   = Date.parse(stat.mtime),
        key     = pathname || files[0],
        headers = {};

    // Copy default headers
    for (var k in this.options.headers) { headers[k] = this.options.headers[k] }

    headers['Etag']          = JSON.stringify([stat.ino, stat.size, mtime].join('-'));
    headers['Date']          = new(Date)().toUTCString();
    headers['Last-Modified'] = new(Date)(stat.mtime).toUTCString();

    // Conditional GET
    // If both the "If-Modified-Since" and "If-None-Match" headers
    // match the conditions, send a 304 Not Modified.
    if (req.headers['if-none-match'] === headers['Etag'] &&
        Date.parse(req.headers['if-modified-since']) >= mtime) {
        finish(304, headers);
    } else if (req.method === 'HEAD') {
        finish(200, headers);
    } else {
        headers['Content-Length'] = stat.size;
        headers['Content-Type']   = mime.contentTypes[path.extname(files[0]).slice(1)] ||
                                   'application/octet-stream';

        res.writeHead(200, headers);

        // If the file was cached and it's not older
        // than what's on disk, serve the cached version.
        if (this.cache && (key in exports.store) &&
            exports.store[key].stat.mtime >= stat.mtime) {
            res.end(exports.store[key].buffer);
            finish(200, {});
        } else {
            this.stream(pathname, files, new(buffer.Buffer)(stat.size), res, function (e, buffer) {
                if (e) { return finish(500, {}) }
                exports.store[key] = {
                    stat:      stat,
                    buffer:    buffer,
                    timestamp: Date.now()
                };
                finish(200, {});
            });
        }
    }
};

this.Server.prototype.stream = function (pathname, files, buffer, res, callback) {
    (function streamFile(files, offset) {
        var file = files.shift();

        if (file) {
            // Stream the file to the client
            fs.createReadStream(path.join(pathname || '.', file), {
                flags: 'r',
                encoding: 'binary',
                mode: 0666,
                bufferSize: 4096
            }).addListener('data', function (chunk) {
                chunk.copy (buffer, offset, 0);
                res.write  (chunk, 'binary');
                offset   += chunk.length;
            }).addListener('close', function () {
                streamFile(files, offset);
            }).addListener('error', function (err) {
                callback(err);
                sys.error(err);
            });
        } else {
            res.end();
            callback(null, buffer, offset);
        }
    })(files.slice(0), 0);
};
<commit_msg>(api) serveFile takes a status and headers now.<commit_after>var fs = require('fs'),
    sys = require('sys'),
    events = require('events'),
    buffer = require('buffer'),
    http = require('http'),
    url = require('url'),
    path = require('path');

this.version = [0, 4, 3];

var mime = require('./node-static/mime');
var util = require('./node-static/util');

var serverInfo = 'node-static/' + this.version.join('.');

// In-memory file store
this.store = {};
this.indexStore = {};

this.Server = function (root, options) {
    if (root && (typeof(root) === 'object')) { options = root, root = null }

    this.root    = path.normalize(root || '.');
    this.options = options || {};
    this.cache   = 3600;

    this.defaultHeaders  = {};
    this.options.headers = this.options.headers || {};

    if ('cache' in this.options) {
        if (typeof(this.options.cache) === 'number') {
            this.cache = this.options.cache;
        } else if (! this.options.cache) {
            this.cache = false;
        }
    }

    if (this.cache !== false) {
        this.defaultHeaders['Cache-Control'] = 'max-age=' + this.cache;
    }
    this.defaultHeaders['Server'] = serverInfo;

    for (var k in this.defaultHeaders) {
        this.options.headers[k] = this.options.headers[k] ||
                                  this.defaultHeaders[k];
    }
};

this.Server.prototype.serveDir = function (pathname, req, res, finish) {
    var htmlIndex = path.join(pathname, 'index.html'),
        that = this;

    fs.stat(htmlIndex, function (e, stat) {
        if (!e) {
            that.respond(null, 200, {}, [htmlIndex], stat, req, res, finish);
        } else {
            if (pathname in exports.store) {
                streamFiles(exports.indexStore[pathname].files);
            } else {
                // Stream a directory of files as a single file.
                fs.readFile(path.join(pathname, 'index.json'), function (e, contents) {
                    if (e) { return finish(404, {}) }
                    var index = JSON.parse(contents);
                    exports.indexStore[pathname] = index;
                    streamFiles(index.files);
                });
            }
        }
    });
    function streamFiles(files) {
        util.mstat(pathname, files, function (e, stat) {
            that.respond(pathname, 200, {}, files, stat, req, res, finish);
        });
    }
};
this.Server.prototype.serveFile = function (pathname, status, headers, req, res) {
    var that = this;
    var promise = new(events.EventEmitter);

    pathname = this.normalize(pathname);

    fs.stat(pathname, function (e, stat) {
        if (e) {
            return promise.emit('error', e);
        }
        that.respond(null, status, headers, [pathname], stat, req, res, function (status, headers) {
            that.finish(status, headers, req, res, promise);
        });
    });
    return promise;
};
this.Server.prototype.finish = function (status, headers, req, res, promise, callback) {
    var result = {
        status:  status,
        headers: headers,
        message: http.STATUS_CODES[status]
    };

    headers['Server'] = serverInfo;

    if (!status || status >= 400) {
        if (callback) {
            callback(result);
        } else {
            if (promise.listeners('error').length > 0) {
                promise.emit('error', result);
            }
            res.writeHead(status, headers);
            res.end();
        }
    } else {
        // Don't end the request here, if we're streaming;
        // it's taken care of in `prototype.stream`.
        if (status !== 200 || req.method !== 'GET') {
            res.writeHead(status, headers);
            res.end();
        }
        callback && callback(null, result);
        promise.emit('success', result);
    }
};

this.Server.prototype.servePath = function (pathname, status, headers, req, res, finish) {
    var that = this,
        promise = new(events.EventEmitter);

    pathname = this.normalize(pathname);

    // Only allow GET and HEAD requests
    if (req.method !== 'GET' && req.method !== 'HEAD') {
        finish(405, { 'Allow': 'GET, HEAD' });
        return promise;
    }

    // Make sure we're not trying to access a
    // file outside of the root.
    if (new(RegExp)('^' + that.root).test(pathname)) {
        fs.stat(pathname, function (e, stat) {
            if (e) {
                finish(404, {});
            } else if (stat.isFile()) {      // Stream a single file.
                that.respond(null, status, headers, [pathname], stat, req, res, finish);
            } else if (stat.isDirectory()) { // Stream a directory of files.
                that.serveDir(pathname, req, res, finish);
            } else {
                finish(400, {});
            }
        });
    } else {
        // Forbidden
        finish(403, {});
    }
    return promise;
};
this.Server.prototype.normalize = function (pathname) {
    return path.normalize(path.join(this.root, pathname));
};
this.Server.prototype.serve = function (req, res, callback) {
    var that = this,
        promise = new(events.EventEmitter);

    var pathname = url.parse(req.url).pathname;

    var finish = function (status, headers) {
        that.finish(status, headers, req, res, promise, callback);
    };

    process.nextTick(function () {
        that.servePath(pathname, 200, {}, req, res, finish).on('success', function (result) {
            promise.emit('success', result);
        }).on('error', function (err) {
            promise.emit('error');
        });
    });
    if (! callback) { return promise }
};

this.Server.prototype.respond = function (pathname, status, _headers, files, stat, req, res, finish) {
    var mtime   = Date.parse(stat.mtime),
        key     = pathname || files[0],
        headers = {};

    // Copy default headers
    for (var k in this.options.headers) {  headers[k] = this.options.headers[k] }

    headers['Etag']          = JSON.stringify([stat.ino, stat.size, mtime].join('-'));
    headers['Date']          = new(Date)().toUTCString();
    headers['Last-Modified'] = new(Date)(stat.mtime).toUTCString();

    // Conditional GET
    // If both the "If-Modified-Since" and "If-None-Match" headers
    // match the conditions, send a 304 Not Modified.
    if (req.headers['if-none-match'] === headers['Etag'] &&
        Date.parse(req.headers['if-modified-since']) >= mtime) {
        finish(304, headers);
    } else if (req.method === 'HEAD') {
        finish(200, headers);
    } else {
        headers['Content-Length'] = stat.size;
        headers['Content-Type']   = mime.contentTypes[path.extname(files[0]).slice(1)] ||
                                   'application/octet-stream';

        for (var k in headers) { _headers[k] = headers[k] }

        res.writeHead(status, _headers);

        // If the file was cached and it's not older
        // than what's on disk, serve the cached version.
        if (this.cache && (key in exports.store) &&
            exports.store[key].stat.mtime >= stat.mtime) {
            res.end(exports.store[key].buffer);
            finish(status, _headers);
        } else {
            this.stream(pathname, files, new(buffer.Buffer)(stat.size), res, function (e, buffer) {
                if (e) { return finish(null, {}) }
                exports.store[key] = {
                    stat:      stat,
                    buffer:    buffer,
                    timestamp: Date.now()
                };
                finish(status, _headers);
            });
        }
    }
};

this.Server.prototype.stream = function (pathname, files, buffer, res, callback) {
    (function streamFile(files, offset) {
        var file = files.shift();

        if (file) {
            // Stream the file to the client
            fs.createReadStream(path.join(pathname || '.', file), {
                flags: 'r',
                encoding: 'binary',
                mode: 0666,
                bufferSize: 4096
            }).addListener('data', function (chunk) {
                chunk.copy (buffer, offset, 0);
                res.write  (chunk, 'binary');
                offset   += chunk.length;
            }).addListener('close', function () {
                streamFile(files, offset);
            }).addListener('error', function (err) {
                callback(err);
                sys.error(err);
            });
        } else {
            res.end();
            callback(null, buffer, offset);
        }
    })(files.slice(0), 0);
};
<|endoftext|>


<commit_before>var models  = require(".."),
expect      = require("expect.js"),
Application = require("mojo-application");

describe("collection#", function () {

  var app = new Application();
  app.use(models);

  it("can create a new collection", function () {
    var c = new models.Collection(null, app);
    expect(c.application).to.be(app);
  });

  it("can set the source of a collection with data property", function () {
    var c = new models.Collection({data:[0,1,2]}, app);
    expect(c.data[0]).to.be(0);
    expect(c.at(0).data).to.be(0);
  });

  it("default id property is _id", function () {
    var c = new models.Collection({}, app);
    expect(c.idProperty).to.be("_id");
  })

  it("can dynamically change the data, and reset the source of a collection", function () {
    var c = new models.Collection(null, app);
    c.set("data", [0, 1, 2]);
    expect(c.data[0]).to.be(0);
    expect(c.at(0).data).to.be(0);
  });

  it("properly deserializes a collection", function () {
    var c = new models.Collection({
      deserialize: function (data) {
        return {
          value: data.map(function (n) { return n * 10 })
        }
      },
      data: [1, 2, 3]
    }, app);
    expect(c.at(0).data).to.be(10);
    expect(c.value[0]).to.be(10);
  });

  it("can override the createModel method", function () {
    var c = new models.Collection({
      createModel: function (options) {

        return new models.Base({ data: options.data * 10 }, this.application);
      },
      data: [1, 2, 3]
    }, app);
    expect(c.at(0).data).to.be(10);
  });

  it("maintains the same models for integers", function () {
    var c = new models.Collection({
      data: [1, 2, 3]
    }, app);
    expect(c.length).to.be(3);

    var m1 = c.at(1),
    m2     = c.at(2);

    c.set("data", [2, 3, 4]);
    expect(c.length).to.be(3);

    var m3 = c.at(2);

    expect(m1).to.be(c.at(0));
    expect(m2).to.be(c.at(1));

    c.set("data", [3, 4, 5]);

    expect(m2).to.be(c.at(0));
    expect(m3).to.be(c.at(1));
  });

  it("maintains the same models for objects", function () {

    var c = new models.Collection({
      data: [{_id: 1}, {_id:2}, { _id:3}]
    }, app);

    var m1 = c.at(1),
    m2     = c.at(2);

    c.set("data", [{_id: 2}, {_id:3}, { _id:4}]);

    expect(m1).to.be(c.at(0));
    expect(m2).to.be(c.at(1));

    c.set("data", [{_id: 3}, {_id:4}]);

    expect(m2).to.be(c.at(0));
    expect(c.length).to.be(2);
  });

  it("can customize the idproperty", function () {

    var c = new models.Collection({
      data: [{uid: 1}, {uid:2}, { uid:3}],
      idProperty: "uid"
    }, app);

    var m1 = c.at(1),
    m2     = c.at(2);

    c.set("data", [{uid: 2}, {uid:3}, { uid:4}]);

    expect(m1).to.be(c.at(0));
    expect(m2).to.be(c.at(1));

    c.set("data", [{uid:4}]);
    expect(c.length).to.be(1);

  });

  it("can create a model and push immediately to the collection", function () {
    var c = new models.Collection(null, app);
    var m = c.create({ data: 5 });
    expect(m.value).to.be(5);
    expect(c.length).to.be(1);
    expect(c.at(0)).to.be(m);
  });

  it("can create a model, and stop from pushing immediately to the collection", function () {
    var c = new models.Collection(null, app);
    var m = c.create({ data: 5, waitUntilSave: true });
    expect(m.value).to.be(5);
    expect(c.length).to.be(0);
  });

  it("can create a model, and push only after saving the model", function () {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    var model = c.create({ waitUntilSave: true });
    expect(c.length).to.be(0);
    model.save();
    expect(c.length).to.be(1);
    expect(c.at(0)).to.be(model);
  });

  it("emits create didUpdate if a model is created", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.once("didUpdate", function(data) {
      expect(data.create[0]).to.be(c.at(0));
      next();
    });

    c.create().save();
  });

  it("emits save didUpdate if a model already exists", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.once("didUpdate", function(data) {
      expect(data.save).to.be(c.at(0));
      next();
    });

    c.set("data", [{_id:"model"}]);

    c.at(0).save();

  });

  it("emits didUpdate when a model is removed", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        },
        remove: function(complete) {
          complete();
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    var m = c.create();
    m.save();

    c.once("didUpdate", function(data) {
      expect(data.remove[0]).to.be(m);
      next();
    });

    m.remove();
  });

  it("emits create didUpdate if model data is different", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        },
        remove: function(complete) {
          complete();
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.once("didUpdate", function(data) {
      expect(data.create[0]._id).to.be("model2");
      next();
    });

    c.set("data", [{_id:"model"}]);
    c.set("data", [{_id:"model"},{_id:"model2"}]);
  });

  it("emits remove didUpdate if model data is different", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        },
        remove: function(complete) {
          complete();
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.once("didUpdate", function(data) {
      expect(data.remove[0]._id).to.be("model");
      next();
    });

    c.set("data", [{_id:"model"}]);
    c.set("data", [{_id:"model2"},{_id:"model3"}]);
  });

  it("only emits didUpdate if data has changed", function (next) {

    var i = 0;

    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        },
        remove: function(complete) {
          complete();
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.on("didUpdate", function(data) {
      i++;
      next();
    });

    c.set("data", [{_id:"model"}]);
    c.set("data", [{_id:"model2"},{_id:"model3"}]);
    c.set("data", [{_id:"model2"},{_id:"model3"}]);
  });

  it("removes a model if .dispose() is called on a model", function () {
    var c = new models.Collection(null, app);
    var m = c.create();
    expect(c.length).to.be(1);
    m.dispose();
    expect(c.length).to.be(0);
  });

  it("can create a model from modelType string", function () {

    var Model = models.Base.extend();

    app.models.register("someModel", Model);
    var c = new models.Collection({
      modelType: "someModel"
    }, app);
    expect(c.create().constructor).to.be(Model);
  });

  it("can create a model from modelType class", function () {

    var Model = models.Base.extend();

    var c = new models.Collection({
      modelType: Model
    }, app);
    expect(c.create().constructor).to.be(Model);
  });

  it("calls dispose on models that aren't part of the collection anymore", function () {
    var c = new models.Collection({ data: [0,1,2,3]}, app);
    var m1 = c.at(0), m2 = c.at(1), i = 0;

    m1.on("dispose", function () {
      i++;
    });

    m2.on("dispose", function () {
      i++;
    });

    c.set("data", [2, 3])

    expect(i).to.be(2);

  })

});<commit_msg>add tests<commit_after>var models  = require(".."),
expect      = require("expect.js"),
Application = require("mojo-application");

describe("collection#", function () {

  var app = new Application();
  app.use(models);

  it("can create a new collection", function () {
    var c = new models.Collection(null, app);
    expect(c.application).to.be(app);
  });

  it("can set the source of a collection with data property", function () {
    var c = new models.Collection({data:[0,1,2]}, app);
    expect(c.data[0]).to.be(0);
    expect(c.at(0).data).to.be(0);
  });

  it("default id property is _id", function () {
    var c = new models.Collection({}, app);
    expect(c.idProperty).to.be("_id");
  })

  it("can dynamically change the data, and reset the source of a collection", function () {
    var c = new models.Collection(null, app);
    c.set("data", [0, 1, 2]);
    expect(c.data[0]).to.be(0);
    expect(c.at(0).data).to.be(0);
  });

  it("properly deserializes a collection", function () {
    var c = new models.Collection({
      deserialize: function (data) {
        return {
          value: data.map(function (n) { return n * 10 })
        }
      },
      data: [1, 2, 3]
    }, app);
    expect(c.at(0).data).to.be(10);
    expect(c.value[0]).to.be(10);
  });

  it("can override the createModel method", function () {
    var c = new models.Collection({
      createModel: function (options) {

        return new models.Base({ data: options.data * 10 }, this.application);
      },
      data: [1, 2, 3]
    }, app);
    expect(c.at(0).data).to.be(10);
  });

  it("maintains the same models for integers", function () {
    var c = new models.Collection({
      data: [1, 2, 3]
    }, app);
    expect(c.length).to.be(3);

    var m1 = c.at(1),
    m2     = c.at(2);

    c.set("data", [2, 3, 4]);
    expect(c.length).to.be(3);

    var m3 = c.at(2);

    expect(m1).to.be(c.at(0));
    expect(m2).to.be(c.at(1));

    c.set("data", [3, 4, 5]);

    expect(m2).to.be(c.at(0));
    expect(m3).to.be(c.at(1));
  });

  it("maintains the same models for objects", function () {

    var c = new models.Collection({
      data: [{_id: 1}, {_id:2}, { _id:3}]
    }, app);

    var m1 = c.at(1),
    m2     = c.at(2);

    c.set("data", [{_id: 2}, {_id:3}, { _id:4}]);

    expect(m1).to.be(c.at(0));
    expect(m2).to.be(c.at(1));

    c.set("data", [{_id: 3}, {_id:4}]);

    expect(m2).to.be(c.at(0));
    expect(c.length).to.be(2);
  });

  it("can customize the idproperty", function () {

    var c = new models.Collection({
      data: [{uid: 1}, {uid:2}, { uid:3}],
      idProperty: "uid"
    }, app);

    var m1 = c.at(1),
    m2     = c.at(2);

    c.set("data", [{uid: 2}, {uid:3}, { uid:4}]);

    expect(m1).to.be(c.at(0));
    expect(m2).to.be(c.at(1));

    c.set("data", [{uid:4}]);
    expect(c.length).to.be(1);

  });

  it("can create a model and push immediately to the collection", function () {
    var c = new models.Collection(null, app);
    var m = c.create({ data: 5 });
    expect(m.value).to.be(5);
    expect(c.length).to.be(1);
    expect(c.at(0)).to.be(m);
  });

  it("can create a model, and stop from pushing immediately to the collection", function () {
    var c = new models.Collection(null, app);
    var m = c.create({ data: 5, waitUntilSave: true });
    expect(m.value).to.be(5);
    expect(c.length).to.be(0);
  });

  it("can create a model, and push only after saving the model", function () {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    var model = c.create({ waitUntilSave: true });
    expect(c.length).to.be(0);
    model.save();
    expect(c.length).to.be(1);
    expect(c.at(0)).to.be(model);
  });

  it("emits create didUpdate if a model is created", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.once("didUpdate", function(data) {
      expect(data.create[0]).to.be(c.at(0));
      next();
    });

    c.create().save();
  });

  it("emits save didUpdate if a model already exists", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.once("didUpdate", function(data) {
      expect(data.save).to.be(c.at(0));
      next();
    });

    c.set("data", [{_id:"model"}]);

    c.at(0).save();

  });

  it("emits didUpdate when a model is removed", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        },
        remove: function(complete) {
          complete();
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    var m = c.create();
    m.save();

    c.once("didUpdate", function(data) {
      expect(data.remove[0]).to.be(m);
      next();
    });

    m.remove();
  });

  it("doesn't emit didUpdate if remove is not defined on model", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    var m = c.create();
    m.save();

    c.once("didUpdate", function(data) {

      // this will cause a double callback (what we want to validate this test)
      next();
    });

    m.remove();

    next();
  });

  it("emits create didUpdate if model data is different", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        },
        remove: function(complete) {
          complete();
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.once("didUpdate", function(data) {
      expect(data.create[0]._id).to.be("model2");
      next();
    });

    c.set("data", [{_id:"model"}]);
    c.set("data", [{_id:"model"},{_id:"model2"}]);
  });

  it("emits remove didUpdate if model data is different", function (next) {
    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        },
        remove: function(complete) {
          complete();
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.once("didUpdate", function(data) {
      expect(data.remove[0]._id).to.be("model");
      next();
    });

    c.set("data", [{_id:"model"}]);
    c.set("data", [{_id:"model2"},{_id:"model3"}]);
  });

  it("only emits didUpdate if data has changed", function (next) {

    var i = 0;

    var Model = models.Base.extend({
      persist: {
        save: function (complete) {
          complete(null, { _id: "blah" });
        },
        remove: function(complete) {
          complete();
        }
      }
    });
    var c = new models.Collection({
      createModel: function (options) {
        return new Model({ data: options.data }, this.application);
      }
    }, app);

    c.on("didUpdate", function(data) {
      i++;
      next();
    });

    c.set("data", [{_id:"model"}]);
    c.set("data", [{_id:"model2"},{_id:"model3"}]);
    c.set("data", [{_id:"model2"},{_id:"model3"}]);
  });

  it("removes a model if .dispose() is called on a model", function () {
    var c = new models.Collection(null, app);
    var m = c.create();
    expect(c.length).to.be(1);
    m.dispose();
    expect(c.length).to.be(0);
  });

  it("can create a model from modelType string", function () {

    var Model = models.Base.extend();

    app.models.register("someModel", Model);
    var c = new models.Collection({
      modelType: "someModel"
    }, app);
    expect(c.create().constructor).to.be(Model);
  });

  it("can create a model from modelType class", function () {

    var Model = models.Base.extend();

    var c = new models.Collection({
      modelType: Model
    }, app);
    expect(c.create().constructor).to.be(Model);
  });

  it("calls dispose on models that aren't part of the collection anymore", function () {
    var c = new models.Collection({ data: [0,1,2,3]}, app);
    var m1 = c.at(0), m2 = c.at(1), i = 0;

    m1.on("dispose", function () {
      i++;
    });

    m2.on("dispose", function () {
      i++;
    });

    c.set("data", [2, 3])

    expect(i).to.be(2);

  })

});<|endoftext|>


<commit_before>var workQueue = [];

function pageViewModel(gvm) {
    var self = this;

    // projecttitle
    gvm.projecttitle = ko.observable("");
    gvm.projectId = $("#projectHeader").data('value');
    gvm.lastIdFromDb = -1;
    gvm.lastId = -1;
    gvm.totalDocumentPercentage = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.projectCompletenessTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectCompletenessTitle");}, gvm);

    gvm.getProjectInfo = function() {
        $.getJSON('/api/project/' + gvm.projectId, function(data) {
            gvm.pageHeader(data[0].code + ' - ' + data[0].name);
            gvm.totalDocumentPercentage = data[0].document;
        });
    };

    gvm.documents = ko.observableArray([]);

    gvm.getDocuments = function() {
        $.getJSON('/api/project/' + gvm.projectId + '/documents', function(data) {
            data.forEach(function(entry) {
                gvm.addDocument(new Document(entry.id,entry.description,entry.amount_required,entry.weight,entry.locked));
            })
        });
    };

    gvm.addDocument = function(document) {
        gvm.documents.push(document)
    };

    gvm.removeDocument = function(document) {
        gvm.documents.remove(document);
    };

    gvm.saveDocuments = function() {
        $.ajax({
            type: "POST",
            url: "/api/project/" + gvm.projectId +  "/documenttype/add",
            data: gvm.documents,
            success: function(){
                // TODO make multilangual and with modals
                alert("Saved documents to server");
            },
            error: function()
            {
                console.log("Error::::::");
            }
        });
    }

}

function Document(id,description,amount_required,weight,locked)
{
    return {
        id: ko.observable(id || 0),
        description: ko.observable(description || ""),
        amount_required: ko.observable(amount_required || ""),
        weight: ko.observable(weight || ""),
        locked: ko.observable(locked || false),

        removeThis: function() {
            viewModel.removeDocument(this);
        },

        toggleLock: function(data,event) {
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
            }
            this.locked = !this.locked;
        }
    }
}

function initPage() {
    viewModel.getProjectInfo();
    viewModel.getDocuments();
}<commit_msg>Grade Documents<commit_after>var workQueue = [];

function pageViewModel(gvm) {
    var self = this;

    // projecttitle
    gvm.projecttitle = ko.observable("");
    gvm.projectId = $("#projectHeader").data('value');
    gvm.lastIdFromDb = -1;
    gvm.lastId = -1;
    gvm.totalDocumentPercentage = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.projectCompletenessTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectCompletenessTitle");}, gvm);

    gvm.getProjectInfo = function() {
        $.getJSON('/api/project/' + gvm.projectId, function(data) {
            gvm.pageHeader(data[0].code + ' - ' + data[0].name);
            gvm.totalDocumentPercentage = data[0].document;
        });
    };

    gvm.documents = ko.observableArray([]);

    gvm.getDocuments = function() {
        $.getJSON('/api/project/' + gvm.projectId + '/documents', function(data) {
            data.forEach(function(entry) {
                gvm.addDocument(new Document(entry.id,entry.description,entry.amount_required,entry.weight,entry.locked));
            })
        });
    };

    gvm.addDocument = function(document) {
        gvm.documents.push(document)
    };

    gvm.removeDocument = function(document) {
        gvm.documents.remove(document);
    };

    gvm.saveDocuments = function() {
        $.ajax({
            type: "POST",
            url: "/api/project/" + gvm.projectId +  "/documenttype/add",
            data: gvm.documents,
            success: function(){
                // TODO make multilangual and with modals
                alert("Saved documents to server");
            },
            error: function()
            {
                console.log("Error::::::");
            }
        });
    };
}

function Document(id,description,amount_required,weight,locked)
{
    return {
        id: ko.observable(id || 0),
        description: ko.observable(description || ""),
        amount_required: ko.observable(amount_required || ""),
        weight: ko.observable(weight || ""),
        locked: ko.observable(locked || false),

        removeThis: function() {
            viewModel.removeDocument(this);
        },

        toggleLock: function(data,event) {
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
            }
            this.locked = !this.locked;
        }
    }
}

function initPage() {
    viewModel.getProjectInfo();
    viewModel.getDocuments();
}<|endoftext|>


<commit_before><commit_msg>Change port back to 8080<commit_after><|endoftext|>


<commit_before>var _ = require('underscore'),
    Q = require('q'),
    QFS = require('q-fs'),
    INHERIT = require('inherit'),
    PATH = require('path'),
    CP = require('child_process'),
    VM = require('vm'),
    BEM = require('../coa').api,
    createLevel = require('../level').createLevel,
    Context = require('../context').Context,

    FileNode = require('./file').FileNode,
    GeneratedFileNode = require('./file').GeneratedFileNode,

    require = require('../util').requireWrapper(require);

var BemBuildNode = exports.BemBuildNode = INHERIT(GeneratedFileNode, {

    __constructor: function(levels, decl, techPath, techName, output, forked) {
        this.levelsPaths = levels;
        this.levels = levels.map(function(l) {
            return typeof l == 'string'? createLevel(l) : l;
        });
        this.declPath = decl;
        this.techPath = techPath;
        this.techName = techName;
        this.output = output;
        this.forked = !!forked;

        var ctx = new Context(this.levels);
        this.tech = ctx.getTech(techName, techPath);

        this.__base(this.tech.getPath(this.output));
    },

    isValid: function(ctx) {
        var _this = this;

        return Q.when(this.__base(ctx), function(valid){
            if (!valid) return false;

            var metaNodeId = _this.getMetaNode().getId();

            if (ctx.arch.hasNode(metaNodeId)) {

                return Q.all([QFS.read(PATH.resolve(metaNodeId)),
                              _this.lastModified(),
                              ctx.arch.getNode(metaNodeId).lastModified()])

                    .spread(function(meta, nodeLastModified, metaLastModified){

                        if (metaLastModified > nodeLastModified) return false;

                        var valid = true;

                        meta = VM.runInThisContext(meta);

                        return Q.all(meta.map(function(m){

                            return QFS.lastModified(m)
                                .then(function(d){
                                    if (d > nodeLastModified) valid = false;
                                })
                                .fail(function(err) {
                                    valid = false;
                                })
                        }))
                        .then(function() {
                            return valid;
                        });
                    });
            }

            return false;
        });
    },

    make: function(ctx) {
        var opts = {
            level: this.levelsPaths,
            declaration: this.declPath,
            tech: this.techPath,
            outputName: this.output
        };

        this.log('bem.build(forked=%j, %s)', this.forked, JSON.stringify(opts, null, 4));

        if (!this.forked) {
            opts.level = this.levels;
            return BEM.build(opts);
        }

        // TODO: generalize forking of bem commands
        var d = Q.defer(),
            worker = CP.fork(PATH.join(__dirname, 'workers', 'bembuild.js'), null, { env: process.env });

        worker.on('exit', function(code) {
            (code === 0)? d.resolve() : d.reject();
        });

        worker.on('message', function(m) {
            (m.code !== 0)? d.reject(m.msg) : d.resolve(m.msg);
        });

        worker.send(opts);

        return d.promise;
    },

    getMetaNode: function() {
        return (this.metaNode || (this.metaNode = new BemBuildMetaNode(
            this.levelsPaths,
            this.declPath,
            this.techPath,
            this.techName,
            this.output,
            this.forked)));
    },

    getBuildDependencies: function(ctx) {

        // TODO: use decl tech readContent()
        var decl = require(PATH.resolve(this.declPath), true),
            tech = this.tech,
            _this = this,
            relativize = function(p) {
                return PATH.relative(ctx.root, p);
            },
            prefixes = tech.getBuildPrefixes(tech.transformBuildDecl(decl), this.levels);

        return prefixes.then(function(prefixes) {
            return tech.getPaths(prefixes, tech.getSuffixes()).map(relativize);
        });
    },

    getCreateDependencies: function(ctx) {
        var _this = this,

        deps = this.tech.getDependencies().map(function(d){
            return _this.output + '.' + d;
        });

        deps.push(this.declPath);

        return deps;
    }
});

var BemBuildMetaNode = exports.BemBuildMetaNode = INHERIT(BemBuildNode, {

    getId: function() {
        return this.id + '.meta.js';
    },

    isValid: function(ctx) {

        if (ctx.method != 'make') {
            ctx.prefixes = Q.ref([]);
            ctx.filteredPaths = Q.ref([]);
            ctx.savedPaths = Q.ref([]);

            return false;
        }

        // TODO: use decl tech readContent()
        var decl = require(PATH.resolve(this.declPath), true),
            tech = this.tech,
            relativize = function(p) {
                return PATH.relative(ctx.root, p);
            },
            prefixes = tech.getBuildPrefixes(tech.transformBuildDecl(decl), this.levels),
            filteredPaths = tech.filterPrefixes(prefixes, tech.getSuffixes())
                .invoke('map', relativize),
            savedPaths = QFS.read(PATH.resolve(this.getId()))
                .then(function(c) {
                    // TODO: read relative to .meta.js file paths
                    return VM.runInThisContext(c);
                })
                .fail(function() {
                    return [];
                });

        ctx.prefixes = prefixes;
        ctx.filteredPaths = filteredPaths;
        ctx.savedPaths = savedPaths;

        return Q.all([filteredPaths, savedPaths])
            .spread(function(filteredPaths, savedPaths) {
                var diff = [].concat(_.difference(savedPaths, filteredPaths),
                    _.difference(filteredPaths, savedPaths));

                //console.log('*** isValid(%j)=%j', _this.getId(), !diff.length);
                //console.log('*** diff=%j', diff);

                return !diff.length;
            });
    },

    make: function(ctx) {
        var _this = this,
            tech = this.tech,
            arch = ctx.arch,
            relativize = function(p) {
                return PATH.relative(ctx.root, p);
            },
           allPaths = ctx.prefixes.then(function(prefixes) {
                        return tech.getPaths(prefixes).map(relativize);
                    });

        return Q.all([allPaths, ctx.filteredPaths, ctx.savedPaths])
            .spread(function(allPaths, filteredPaths, savedPaths) {
                return arch.withLock(_this.alterArch(ctx, allPaths, filteredPaths, savedPaths), _this)
                    .then(function() {
                        // write file list to .meta.js
                        // TODO: store relative to .meta.js file paths
                        return QFS.write(_this.getId(), '(' + JSON.stringify(filteredPaths, null, 4) + ')');
                    });
            });
    },

    alterArch: function(ctx, allPaths, filteredPaths, savedPaths) {

        return function() {

            var arch = ctx.arch,
                buildNodeId = this.id,
                buildNode = arch.nodes[buildNodeId];

            // find difference with array read from file and filteredPaths
            var obsolete = _.difference(savedPaths, filteredPaths);

            // clean obsolete dependencies then from arch
            obsolete.forEach(function(p) {
                if (arch.hasNode(p)) arch.unlink(p, buildNode);
                // TODO: when p has no other dependent nodes, remove it from arch
            });

            // create nodes for all paths: FileNode(path, true)
            // TODO: use replaceNode()?
            return Q.when(buildNode.getBuildDependencies(ctx), function(deps){
                deps.forEach(function(d) {
                    if (!arch.hasNode(d)) {
                        arch.setNode(new FileNode(d, true));
                    }
                    // link created nodes to BemBuildNode corresponding to this node
                    ctx.plan.link(d, buildNodeId);
                });
            });

            //console.log('=== Branch %j\n', buildNodeId, arch.nodeToString(buildNodeId));
        }
    }
});
<commit_msg>- fixed wrong behavior of isvalid method for meta.js nodes<commit_after>var _ = require('underscore'),
    Q = require('q'),
    QFS = require('q-fs'),
    INHERIT = require('inherit'),
    PATH = require('path'),
    CP = require('child_process'),
    VM = require('vm'),
    BEM = require('../coa').api,
    createLevel = require('../level').createLevel,
    Context = require('../context').Context,

    FileNode = require('./file').FileNode,
    GeneratedFileNode = require('./file').GeneratedFileNode,

    require = require('../util').requireWrapper(require);

var BemBuildNode = exports.BemBuildNode = INHERIT(GeneratedFileNode, {

    __constructor: function(levels, decl, techPath, techName, output, forked) {
        this.levelsPaths = levels;
        this.levels = levels.map(function(l) {
            return typeof l == 'string'? createLevel(l) : l;
        });
        this.declPath = decl;
        this.techPath = techPath;
        this.techName = techName;
        this.output = output;
        this.forked = !!forked;

        var ctx = new Context(this.levels);
        this.tech = ctx.getTech(techName, techPath);

        this.__base(this.tech.getPath(this.output));
    },

    isValid: function(ctx) {
        var _this = this;

        return Q.when(this.__base(ctx), function(valid){
            if (!valid) return false;

            var metaNodeId = _this.getMetaNode().getId();

            if (ctx.arch.hasNode(metaNodeId)) {

                return Q.all([QFS.read(PATH.resolve(metaNodeId)),
                              _this.lastModified(),
                              ctx.arch.getNode(metaNodeId).lastModified()])

                    .spread(function(meta, nodeLastModified, metaLastModified){

                        if (metaLastModified > nodeLastModified) return false;

                        var valid = true;

                        meta = VM.runInThisContext(meta);

                        return Q.all(meta.map(function(m){

                            return QFS.lastModified(m)
                                .then(function(d){
                                    if (d > nodeLastModified) valid = false;
                                })
                                .fail(function(err) {
                                    valid = false;
                                })
                        }))
                        .then(function() {
                            return valid;
                        });
                    });
            }

            return false;
        });
    },

    make: function(ctx) {
        var opts = {
            level: this.levelsPaths,
            declaration: this.declPath,
            tech: this.techPath,
            outputName: this.output
        };

        this.log('bem.build(forked=%j, %s)', this.forked, JSON.stringify(opts, null, 4));

        if (!this.forked) {
            opts.level = this.levels;
            return BEM.build(opts);
        }

        // TODO: generalize forking of bem commands
        var d = Q.defer(),
            worker = CP.fork(PATH.join(__dirname, 'workers', 'bembuild.js'), null, { env: process.env });

        worker.on('exit', function(code) {
            (code === 0)? d.resolve() : d.reject();
        });

        worker.on('message', function(m) {
            (m.code !== 0)? d.reject(m.msg) : d.resolve(m.msg);
        });

        worker.send(opts);

        return d.promise;
    },

    getMetaNode: function() {
        return (this.metaNode || (this.metaNode = new BemBuildMetaNode(
            this.levelsPaths,
            this.declPath,
            this.techPath,
            this.techName,
            this.output,
            this.forked)));
    },

    getBuildDependencies: function(ctx) {

        // TODO: use decl tech readContent()
        var decl = require(PATH.resolve(this.declPath), true),
            tech = this.tech,
            _this = this,
            relativize = function(p) {
                return PATH.relative(ctx.root, p);
            },
            prefixes = tech.getBuildPrefixes(tech.transformBuildDecl(decl), this.levels);

        return prefixes.then(function(prefixes) {
            return tech.getPaths(prefixes, tech.getSuffixes()).map(relativize);
        });
    },

    getCreateDependencies: function(ctx) {
        var _this = this,

        deps = this.tech.getDependencies().map(function(d){
            return _this.output + '.' + d;
        });

        deps.push(this.declPath);

        return deps;
    }
});

var BemBuildMetaNode = exports.BemBuildMetaNode = INHERIT(BemBuildNode, {

    getId: function() {
        return this.id + '.meta.js';
    },

    isValid: function(ctx) {

        if ((ctx.method && ctx.method != 'make') || ctx.force) {
            ctx.prefixes = Q.ref([]);
            ctx.filteredPaths = Q.ref([]);
            ctx.savedPaths = Q.ref([]);

            return false;
        }

        // TODO: use decl tech readContent()
        var decl = require(PATH.resolve(this.declPath), true),
            tech = this.tech,
            relativize = function(p) {
                return PATH.relative(ctx.root, p);
            },
            prefixes = tech.getBuildPrefixes(tech.transformBuildDecl(decl), this.levels),
            filteredPaths = tech.filterPrefixes(prefixes, tech.getSuffixes())
                .invoke('map', relativize),
            savedPaths = QFS.read(PATH.resolve(this.getId()))
                .then(function(c) {
                    // TODO: read relative to .meta.js file paths
                    return VM.runInThisContext(c);
                })
                .fail(function() {
                    return [];
                });

        ctx.prefixes = prefixes;
        ctx.filteredPaths = filteredPaths;
        ctx.savedPaths = savedPaths;

        return Q.all([filteredPaths, savedPaths])
            .spread(function(filteredPaths, savedPaths) {
                var diff = [].concat(_.difference(savedPaths, filteredPaths),
                    _.difference(filteredPaths, savedPaths));

                //console.log('*** isValid(%j)=%j', _this.getId(), !diff.length);
                //console.log('*** diff=%j', diff);

                return !diff.length;
            });
    },

    make: function(ctx) {
        var _this = this,
            tech = this.tech,
            arch = ctx.arch,
            relativize = function(p) {
                return PATH.relative(ctx.root, p);
            },
           allPaths = ctx.prefixes.then(function(prefixes) {
                        return tech.getPaths(prefixes).map(relativize);
                    });

        return Q.all([allPaths, ctx.filteredPaths, ctx.savedPaths])
            .spread(function(allPaths, filteredPaths, savedPaths) {
                return arch.withLock(_this.alterArch(ctx, allPaths, filteredPaths, savedPaths), _this)
                    .then(function() {
                        // write file list to .meta.js
                        // TODO: store relative to .meta.js file paths
                        return QFS.write(_this.getId(), '(' + JSON.stringify(filteredPaths, null, 4) + ')');
                    });
            });
    },

    alterArch: function(ctx, allPaths, filteredPaths, savedPaths) {

        return function() {

            var arch = ctx.arch,
                buildNodeId = this.id,
                buildNode = arch.nodes[buildNodeId];

            // find difference with array read from file and filteredPaths
            var obsolete = _.difference(savedPaths, filteredPaths);

            // clean obsolete dependencies then from arch
            obsolete.forEach(function(p) {
                if (arch.hasNode(p)) arch.unlink(p, buildNode);
                // TODO: when p has no other dependent nodes, remove it from arch
            });

            // create nodes for all paths: FileNode(path, true)
            // TODO: use replaceNode()?
            return Q.when(buildNode.getBuildDependencies(ctx), function(deps){
                deps.forEach(function(d) {
                    if (!arch.hasNode(d)) {
                        arch.setNode(new FileNode(d, true));
                    }
                    // link created nodes to BemBuildNode corresponding to this node
                    ctx.plan.link(d, buildNodeId);
                });
            });

            //console.log('=== Branch %j\n', buildNodeId, arch.nodeToString(buildNodeId));
        }
    }
});
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
({
    handleClick : function(component, event, helper) {
    	var concrete = component.getConcreteComponent();
        var concreteHelper = concrete.getDef().getHelper();

        concreteHelper.handleClick(concrete);

        // Un-select the previously selected item
        helper.fireSelectEvent(component, event, {deselectSiblings: true, hideMenu: concrete.get("v.hideMenuAfterSelected")});
    }
})
<commit_msg>When selecting a ui:radioMenuItem and we're hiding the menu, place the focus back on the menu trigger. @rev rdewsbury@ @bug W-2678659@<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
({
    handleClick : function(component, event, helper) {
    	var concrete = component.getConcreteComponent();
        var concreteHelper = concrete.getDef().getHelper();

        concreteHelper.handleClick(concrete);

        // Un-select the previously selected item
        var hideMenu = $A.util.getBooleanValue(concrete.get("v.hideMenuAfterSelected"));
        helper.fireSelectEvent(component, event, {
            "deselectSiblings": true,
            "hideMenu": hideMenu,
            "focusTrigger": hideMenu
        });
    }
})
<|endoftext|>


<commit_before>

ReadiumSDK.Views.InternalLinksSupport = function(reader) {

    var self = this;

    function splitCfi(fullCfi) {

        var startIx = fullCfi.indexOf("(");
        var bungIx = fullCfi.indexOf("!");
        var endIx = fullCfi.indexOf(")");

        if(bungIx == -1) {
            return undefined;
        }

        if(endIx == -1) {
            endIx = fullCfi.length;
        }

        return {

            spineItemCfi: fullCfi.substring(startIx + 1, bungIx),
            elementCfi: fullCfi.substring(bungIx + 1, endIx)
        }
    }

    function getAbsoluteUriRelativeToSpineItem(hrefUri, spineItem) {

        var fullPath = reader.package().resolveRelativeUrl(spineItem.href);

        var absUrl = hrefUri.absoluteTo(fullPath);

        return absUrl;
    }

    function processDeepLink(hrefUri, spineItem) {

        var absoluteOpfUri = getAbsoluteUriRelativeToSpineItem(hrefUri, spineItem);

        if(!absoluteOpfUri) {
            console.error("Unable to resolve " + hrefUri.href())
            return;
        }

        var fullCfi = hrefUri.fragment();

        var absPath = absoluteOpfUri.toString();

        absPath = ReadiumSDK.Helpers.RemoveFromString(absPath, "#" +  fullCfi);

        readOpfFile(absPath, function(opfText) {

            if(!opfText) {
                return;
            }

            var parser = new window.DOMParser;
            var packageDom = parser.parseFromString(opfText, 'text/xml');
            var cfi = splitCfi(fullCfi);

            if(!cfi) {
                console.warn("Unable to split cfi:" + fullCfi);
                return;
            }

            var contentDocRef = EPUBcfi.Interpreter.getContentDocHref("epubcfi(" + cfi.spineItemCfi + ")", packageDom);

            if(contentDocRef) {

                var newSpineItem = reader.spine().getItemByHref(contentDocRef);
                if(newSpineItem) {

                    reader.openSpineItemElementCfi(newSpineItem.idref, cfi.elementCfi, self);
                }
                else {
                    console.warn("Unable to find spineItem with href=" + contentDocRef);
                }

            }
            else {
                console.warn("Unable to find document ref from " +  fullCfi +" cfi");
            }

        });

    }

    function readOpfFile(path, callback) {

        $.ajax({
            url: path,
            dataType: 'text',
            async: true,
            success: function (result) {
                callback(result);
            },
            error: function (xhr, status, errorThrown) {
                console.error('Error when AJAX fetching ' + path);
                console.error(status);
                console.error(errorThrown);
                callback();
            }
        });
    }

    //checks if href includes path to opf file and full cfi
    function isDeepLikHref(uri) {

        var fileName = uri.filename();
        return fileName && ReadiumSDK.Helpers.EndsWith(fileName, ".opf");
    }

    function processLinkWithHash(hrefUri, spineItem) {

        var normalizedUri = new URI(hrefUri, spineItem.href);
        var hashFrag = hrefUri.fragment();

        var newSpineItem = reader.spine().getItemByHref(normalizedUri.pathname());

        if(newSpineItem) {
            reader.openSpineItemElementId(newSpineItem.idref, hashFrag, self);
        }
        else {
            console.error("spine item with href=" + normalizedUri.pathname() + " not found");
        }
    }

    this.processLinkElements = function($iframe, spineItem) {

        var epubContentDocument = $iframe[0].contentDocument;

        $('a', epubContentDocument).click(function (clickEvent) {
            // Check for both href and xlink:href attribute and get value
            var href;
            if (clickEvent.currentTarget.attributes["xlink:href"]) {

                href = clickEvent.currentTarget.attributes["xlink:href"].value;
            }
            else {
                href = clickEvent.currentTarget.attributes["href"].value;
            }

            var overrideClickEvent = false;
            var hrefUri = new URI(href);
            var hrefIsRelative = hrefUri.is('relative');

            if (hrefIsRelative) {

                if(isDeepLikHref(hrefUri)) {
                    processDeepLink(hrefUri, spineItem);
                    overrideClickEvent = true;
                }
                else {

                    var hrefUriHasFilename = hrefUri.filename();

                    // TODO:
                    if (hrefUriHasFilename /* TODO: && check whether href actually resolves to a spine item */) {
                        processLinkWithHash(hrefUri, spineItem);
                        overrideClickEvent = true;
                    } // otherwise it's probably just a hash frag that needs to be handled by browser's default handling
                }

            } else {
                // It's an absolute URL to a remote site - open it in a separate window outside the reader
                window.open(href, '_blank');
                overrideClickEvent = true;
            }

            if (overrideClickEvent) {
                clickEvent.preventDefault();
                clickEvent.stopPropagation();
            }
        });

    }

};
<commit_msg>Fix Bug 50 - same document hush links didn't work properly<commit_after>

ReadiumSDK.Views.InternalLinksSupport = function(reader) {

    var self = this;

    function splitCfi(fullCfi) {

        var startIx = fullCfi.indexOf("(");
        var bungIx = fullCfi.indexOf("!");
        var endIx = fullCfi.indexOf(")");

        if(bungIx == -1) {
            return undefined;
        }

        if(endIx == -1) {
            endIx = fullCfi.length;
        }

        return {

            spineItemCfi: fullCfi.substring(startIx + 1, bungIx),
            elementCfi: fullCfi.substring(bungIx + 1, endIx)
        }
    }

    function getAbsoluteUriRelativeToSpineItem(hrefUri, spineItem) {

        var fullPath = reader.package().resolveRelativeUrl(spineItem.href);

        var absUrl = hrefUri.absoluteTo(fullPath);

        return absUrl;
    }

    function processDeepLink(hrefUri, spineItem) {

        var absoluteOpfUri = getAbsoluteUriRelativeToSpineItem(hrefUri, spineItem);

        if(!absoluteOpfUri) {
            console.error("Unable to resolve " + hrefUri.href())
            return;
        }

        var fullCfi = hrefUri.fragment();

        var absPath = absoluteOpfUri.toString();

        absPath = ReadiumSDK.Helpers.RemoveFromString(absPath, "#" +  fullCfi);

        readOpfFile(absPath, function(opfText) {

            if(!opfText) {
                return;
            }

            var parser = new window.DOMParser;
            var packageDom = parser.parseFromString(opfText, 'text/xml');
            var cfi = splitCfi(fullCfi);

            if(!cfi) {
                console.warn("Unable to split cfi:" + fullCfi);
                return;
            }

            var contentDocRef = EPUBcfi.Interpreter.getContentDocHref("epubcfi(" + cfi.spineItemCfi + ")", packageDom);

            if(contentDocRef) {

                var newSpineItem = reader.spine().getItemByHref(contentDocRef);
                if(newSpineItem) {

                    reader.openSpineItemElementCfi(newSpineItem.idref, cfi.elementCfi, self);
                }
                else {
                    console.warn("Unable to find spineItem with href=" + contentDocRef);
                }

            }
            else {
                console.warn("Unable to find document ref from " +  fullCfi +" cfi");
            }

        });

    }

    function readOpfFile(path, callback) {

        $.ajax({
            url: path,
            dataType: 'text',
            async: true,
            success: function (result) {
                callback(result);
            },
            error: function (xhr, status, errorThrown) {
                console.error('Error when AJAX fetching ' + path);
                console.error(status);
                console.error(errorThrown);
                callback();
            }
        });
    }

    //checks if href includes path to opf file and full cfi
    function isDeepLikHref(uri) {

        var fileName = uri.filename();
        return fileName && ReadiumSDK.Helpers.EndsWith(fileName, ".opf");
    }

    function processLinkWithHash(hrefUri, spineItem) {

        var fileName = hrefUri.filename();

        var idref;

        //reference to another file
        if(fileName) {
            var normalizedUri = new URI(hrefUri, spineItem.href);
            var newSpineItem = reader.spine().getItemByHref(normalizedUri.pathname());

            if(!newSpineItem) {
                console.error("spine item with href=" + normalizedUri.pathname() + " not found");
                return;
            }

            idref = newSpineItem.idref;
        }
        else { //hush in the same file
            idref = spineItem.idref;
        }

        var hashFrag = hrefUri.fragment();

        reader.openSpineItemElementId(idref, hashFrag, self);

    }

    this.processLinkElements = function($iframe, spineItem) {

        var epubContentDocument = $iframe[0].contentDocument;

        $('a', epubContentDocument).click(function (clickEvent) {
            // Check for both href and xlink:href attribute and get value
            var href;
            if (clickEvent.currentTarget.attributes["xlink:href"]) {

                href = clickEvent.currentTarget.attributes["xlink:href"].value;
            }
            else {
                href = clickEvent.currentTarget.attributes["href"].value;
            }

            var overrideClickEvent = false;
            var hrefUri = new URI(href);
            var hrefIsRelative = hrefUri.is('relative');

            if (hrefIsRelative) {

                if(isDeepLikHref(hrefUri)) {
                    processDeepLink(hrefUri, spineItem);
                    overrideClickEvent = true;
                }
                else {
                    processLinkWithHash(hrefUri, spineItem);
                    overrideClickEvent = true;
                }

            } else {
                // It's an absolute URL to a remote site - open it in a separate window outside the reader
                window.open(href, '_blank');
                overrideClickEvent = true;
            }

            if (overrideClickEvent) {
                clickEvent.preventDefault();
                clickEvent.stopPropagation();
            }
        });

    }

};
<|endoftext|>


<commit_before>/*jslint node: true */
"use strict";

var config = {
    // The timeout for each script run on the browser. This should be longer
    // than the maximum time your application needs to stabilize between tasks.
    allScriptsTimeout: 11000,

    // ----- What tests to run -----
    //
    // Spec patterns are relative to the location of this config.
    specs: ['../e2e/*_spec.js'],

    // ----- Capabilities to be passed to the webdriver instance ----
    //
    // For a full list of available capabilities, see
    // https://code.google.com/p/selenium/wiki/DesiredCapabilities
    // and
    // https://code.google.com/p/selenium/source/browse/javascript/webdriver/capabilities.js
    capabilities: {
        'browserName': 'chrome'
    },

    // ----- More information for your tests ----
    //
    // A base URL for your application under test. Calls to protractor.get()
    // with relative paths will be prepended with this.
    baseUrl: 'http://127.0.0.1:3102',

    // Selector for the element housing the angular app - this defaults to
    // body, but is necessary if ng-app is on a descendant of <body>
    rootElement: 'html',

    // A callback function called once protractor is ready and available, and
    // before the specs are executed
    // You can specify a file containing code to run by setting onPrepare to
    // the filename string.
    onPrepare: function () {
    // At this point, global 'protractor' object will be set up, and jasmine
    // will be available. For example, you can add a Jasmine reporter with:
    //     jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter(
    //         'outputdir/', true, true));
    }

};

if (process.env.SAUCE_USERNAME !== undefined) {
  // If sauceUser and sauceKey are specified, seleniumServerJar will be ignored.
  // The tests will be run remotely using SauceLabs.
    config.sauceUser = process.env.SAUCE_USERNAME;
    config.sauceKey = process.env.SAUCE_ACCESS_KEY;
} else {
    config.seleniumServerJar = './selenium/selenium-server-standalone-2.37.0.jar';
    config.seleniumPort = null;
    config.chromeDriver = '../../selenium/chromedriver';
    config.seleniumArgs = [];
    config.seleniumAddress = 'http://localhost:4444/wd/hub';
}

exports.config = config;
<commit_msg>Changed protractor conf<commit_after>/*jslint node: true */
"use strict";

var config = {
    // The timeout for each script run on the browser. This should be longer
    // than the maximum time your application needs to stabilize between tasks.
    allScriptsTimeout: 11000,

    // ----- What tests to run -----
    //
    // Spec patterns are relative to the location of this config.
    specs: ['../e2e/*_spec.js'],

    // ----- Capabilities to be passed to the webdriver instance ----
    //
    // For a full list of available capabilities, see
    // https://code.google.com/p/selenium/wiki/DesiredCapabilities
    // and
    // https://code.google.com/p/selenium/source/browse/javascript/webdriver/capabilities.js
    capabilities: {
        'browserName': 'chrome'
    },

    // ----- More information for your tests ----
    //
    // A base URL for your application under test. Calls to protractor.get()
    // with relative paths will be prepended with this.
    baseUrl: 'http://127.0.0.1:3102',

    // Selector for the element housing the angular app - this defaults to
    // body, but is necessary if ng-app is on a descendant of <body>
    rootElement: 'html',

    // A callback function called once protractor is ready and available, and
    // before the specs are executed
    // You can specify a file containing code to run by setting onPrepare to
    // the filename string.
    onPrepare: function () {
    // At this point, global 'protractor' object will be set up, and jasmine
    // will be available. For example, you can add a Jasmine reporter with:
    //     jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter(
    //         'outputdir/', true, true));
    }

};

if (process.env.SAUCE_USERNAME !== undefined) {
    console.log('Using Sauce Labs selenium server');
    // If sauceUser and sauceKey are specified, seleniumServerJar will be ignored.
    // The tests will be run remotely using SauceLabs.
    config.sauceUser = process.env.SAUCE_USERNAME;
    config.sauceKey = process.env.SAUCE_ACCESS_KEY;
    config.capabilities = {
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
        'build': process.env.TRAVIS_BUILD_NUMBER
    };
} else {
    console.log('Using local selenium server');
    config.seleniumServerJar = './selenium/selenium-server-standalone-2.37.0.jar';
    config.seleniumPort = null;
    config.chromeDriver = '../../selenium/chromedriver';
    config.seleniumArgs = [];
    config.seleniumAddress = 'http://localhost:4444/wd/hub';
}

exports.config = config;
<|endoftext|>


<commit_before>import path from 'path'
import webpack from 'webpack'

console.log('>>> config:env',process.env.NODE_ENV)
const __DEV__ = process.env.NODE_ENV === 'development'
const webpackConfig = {
  devtool: __DEV__ ? 'eval-cheap-module-source-map' : null,
  module: {},
}

webpackConfig.entry = {
  app: __DEV__ ? ['./example/index.js', 'webpack-hot-middleware/client'] : ['./example/index.js']
}

webpackConfig.output = {
  filename: 'bundle.js',
  path: path.join(__dirname, 'pages'),
  publicPath: '/static/'
}

webpackConfig.plugins = __DEV__
  ? [
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoErrorsPlugin()
]
  : [
  new webpack.optimize.OccurrenceOrderPlugin(),
  new webpack.optimize.DedupePlugin(),
  new webpack.optimize.UglifyJsPlugin({
    compress: {
      unused: true,
      dead_code: true,
      warnings: false
    }
  })
]

webpackConfig.module.loaders = [
  {
    test: /\.(js|jsx)$/,
    exclude: /node_modules/,
    loader: 'babel',
  },
  {
    test: /\.json$/,
    loader: 'json'
  },
  {
    test: /\.css$/,
    loader: 'css-loader'
  },
]

export default webpackConfig
<commit_msg>:smile:<commit_after>import path from 'path'
import webpack from 'webpack'

console.log('>>> config:env',process.env.NODE_ENV)
const __DEV__ = process.env.NODE_ENV === 'development'
const webpackConfig = {
  devtool: __DEV__ ? 'eval-cheap-module-source-map' : null,
  module: {},
}

webpackConfig.entry = {
  app: __DEV__ ? ['./example/index.js', 'webpack-hot-middleware/client'] : ['./example/index.js']
}

webpackConfig.output = {
  filename: 'bundle.js',
  path: path.join(__dirname, 'pages'),
  publicPath: '/static/'
}

webpackConfig.plugins = __DEV__
  ? [
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoErrorsPlugin()
]
  : [
  new webpack.optimize.OccurrenceOrderPlugin(),
  new webpack.optimize.DedupePlugin(),
  new webpack.optimize.UglifyJsPlugin({
    compress: {
      unused: true,
      dead_code: true,
      warnings: false
    }
  })
]

webpackConfig.module.loaders = [
  {
    test: /\.(js|jsx)$/,
    exclude: /node_modules/,
    loader: 'babel',
  },
  {
    test: /\.json$/,
    loader: 'json'
  }
]

export default webpackConfig
<|endoftext|>


<commit_before>
var features = require('../../config/features');

module.exports.tests = {};

// test exports
module.exports.tests.interface = function(test, common) {
  test('interface: features', function(t) {
    t.true(Array.isArray(features), 'valid taglist');
    t.end();
  });
};

module.exports.all = function (tape, common) {

  function test(name, testFunction) {
    return tape('features: ' + name, testFunction);
  }

  for( var testCase in module.exports.tests ){
    module.exports.tests[testCase](test, common);
  }
};<commit_msg>features: improved tests<commit_after>
var features = require('../../config/features');

module.exports.tests = {};

// test exports
module.exports.tests.interface = function(test, common) {
  test('interface: features', function(t) {
    t.true(Array.isArray(features), 'valid taglist');
    t.end();
  });
};

// ensure some tags are excluded
module.exports.tests.blacklist = function(test, common) {
  test('blacklist', function(t) {
    // see: https://github.com/pelias/openstreetmap/pull/280
    t.true( features.indexOf('aeroway+name') <0 );
    t.true( features.indexOf('aeroway~gate+name') <0 );
    t.end();
  });
};

// ensure some tags are included
module.exports.tests.whitelist = function(test, common) {
  test('whitelist', function(t) {
    t.false( features.indexOf('addr:housenumber+addr:street') <0 );
    t.false( features.indexOf('amenity+name') <0 );
    t.false( features.indexOf('building+name') <0 );
    t.false( features.indexOf('shop+name') <0 );
    t.false( features.indexOf('office+name') <0 );
    t.false( features.indexOf('public_transport+name') <0 );
    t.false( features.indexOf('cuisine+name') <0 );
    t.false( features.indexOf('railway+name') <0 );
    t.false( features.indexOf('sport+name') <0 );
    t.false( features.indexOf('natural+name') <0 );
    t.false( features.indexOf('tourism+name') <0 );
    t.false( features.indexOf('leisure+name') <0 );
    t.false( features.indexOf('historic+name') <0 );
    t.false( features.indexOf('man_made+name') <0 );
    t.false( features.indexOf('landuse+name') <0 );
    t.false( features.indexOf('waterway+name') <0 );
    t.false( features.indexOf('aerialway+name') <0 );
    t.false( features.indexOf('craft+name') <0 );
    t.false( features.indexOf('military+name') <0 );
    t.false( features.indexOf('aeroway~terminal+name') <0 );
    t.false( features.indexOf('aeroway~aerodrome+name') <0 );
    t.false( features.indexOf('aeroway~helipad+name') <0 );
    t.false( features.indexOf('aeroway~airstrip+name') <0 );
    t.false( features.indexOf('aeroway~heliport+name') <0 );
    t.false( features.indexOf('aeroway~areodrome+name') <0 );
    t.false( features.indexOf('aeroway~spaceport+name') <0 );
    t.false( features.indexOf('aeroway~landing_strip+name') <0 );
    t.false( features.indexOf('aeroway~airfield+name') <0 );
    t.false( features.indexOf('aeroway~airport+name') <0 );
    t.end();
  });
};

module.exports.all = function (tape, common) {

  function test(name, testFunction) {
    return tape('features: ' + name, testFunction);
  }

  for( var testCase in module.exports.tests ){
    module.exports.tests[testCase](test, common);
  }
};
<|endoftext|>


<commit_before>'use strict';

const MetaInspector = require('node-metainspector');

module.exports.description = "Show metadata from URLs in messages";

module.exports.main = function(irc_client){
  irc_client.addListener('message#', function(nick,to,text,message) {
    if(text.indexOf('http://') + text.indexOf('https://') !== -2){
      const urls = text.match(/http(s)?:\/\/[^ ]+/ig);
      console.log('seen ' + urls.length + ' urls');
      if(urls.length > 3) {
        //too many URLs, ignoring them
        return;
      }
      for(let u of urls){
        if (u.match(/.(jpg|png|gifv|mp3|mp4)$/i) !== null){
          console.log('skipping the image URL ' + u);
          continue;
        }
        console.log('analyzing URL ' + u);
        let client = new MetaInspector(u, { timeout: 5000,
          limit: 1024*1024*1,
          headers: {
            'User-Agent': 'ircbotjs - Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0'
          } });
          client.on("fetch", function(){
            console.log('fetched ' + u + ' -- ' + client);
            let shortDes = client.title;
            if (client.author) shortDes += ' by ' + client.author;
            if (client.description) shortDes += ' ' + client.description.substr(0,100) + '...';
            irc_client.notice(to, shortDes + ' - ' + u + ' [otr]');
          });

          client.on("error", function(err){
            console.log('error: ', err)
            irc_client.notice(to, err);
          });
          client.fetch();
        }
      }
    });
  };
<commit_msg>[otr] not needed with notice<commit_after>'use strict';

const MetaInspector = require('node-metainspector');

module.exports.description = "Show metadata from URLs in messages";

module.exports.main = function(irc_client){
  irc_client.addListener('message#', function(nick,to,text,message) {
    if(text.indexOf('http://') + text.indexOf('https://') !== -2){
      const urls = text.match(/http(s)?:\/\/[^ ]+/ig);
      console.log('seen ' + urls.length + ' urls');
      if(urls.length > 3) {
        //too many URLs, ignoring them
        return;
      }
      for(let u of urls){
        if (u.match(/.(jpg|png|gifv|mp3|mp4)$/i) !== null){
          console.log('skipping the image URL ' + u);
          continue;
        }
        console.log('analyzing URL ' + u);
        let client = new MetaInspector(u, { timeout: 5000,
          limit: 1024*1024*1,
          headers: {
            'User-Agent': 'ircbotjs - Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0'
          } });
          client.on("fetch", function(){
            console.log('fetched ' + u + ' -- ' + client);
            let shortDes = client.title;
            if (client.author) shortDes += ' by ' + client.author;
            if (client.description) shortDes += ' ' + client.description.substr(0,100) + '...';
            irc_client.notice(to, shortDes + ' - ' + u );
          });

          client.on("error", function(err){
            console.log('error: ', err)
            irc_client.notice(to, err);
          });
          client.fetch();
        }
      }
    });
  };
<|endoftext|>


<commit_before>import express from 'express';

import * as User from '../../controllers/users';
import * as Recipe from '../../controllers/recipes';
import * as Favorite from '../../controllers/favorites';

import * as Auth from '../../middleware/auth';

const user = express.Router();

const newUser = new User.default();
const newRecipe = new Recipe.default();
const newFavorite = new Favorite.default();
const newAuth = new Auth.default();

user.post('/signup', newUser.signUp);
user.post('/signin', newUser.signIn);

user.use('*', newAuth.verify);
user.get('/myRecipes', newRecipe.getUserRecipes);

user.route('/:userId/recipes/:recipeId')
  .post(newFavorite.addToFavorite)
  .delete(newFavorite.removeFromFavorites);

user.get('/:userId/recipes', newFavorite.getFavRecipes);

export default user;
<commit_msg>Add get profile feature to backend<commit_after>import express from 'express';

import * as User from '../../controllers/users';
import * as Recipe from '../../controllers/recipes';
import * as Favorite from '../../controllers/favorites';

import * as Auth from '../../middleware/auth';

const user = express.Router();

const newUser = new User.default();
const newRecipe = new Recipe.default();
const newFavorite = new Favorite.default();
const newAuth = new Auth.default();

user.post('/signup', newUser.signUp);
user.post('/signin', newUser.signIn);

user.use('*', newAuth.verify);
user.get('/myRecipes', newRecipe.getUserRecipes);

user.route('/:userId/profile')
  .get(newUser.getUser)

// TODO update user details and password routes
  .patch(newUser.getUser);
user.patch('/:userId/password', newUser.getUser);

user.route('/:userId/recipes/:recipeId')
  .post(newFavorite.addToFavorite)
  .delete(newFavorite.removeFromFavorites);

user.get('/:userId/recipes', newFavorite.getFavRecipes);

export default user;
<|endoftext|>


<commit_before><commit_msg>remove purify-css plugin from webpack<commit_after><|endoftext|>


<commit_before>'use strict';
const openEditor = require('open-editor');

const sortResults = (a, b) => a.errorCount + b.errorCount > 0 ? (a.errorCount - b.errorCount) : (a.warningCount - b.warningCount);

const resultToFile = result => {
	const [message] = result.messages
		.sort((a, b) => {
			if (a.severity < b.severity) {
				return 1;
			}

			if (a.severity > b.severity) {
				return -1;
			}

			if (a.line < b.line) {
				return -1;
			}

			if (a.line > b.line) {
				return 1;
			}

			return 0;
		});

	return {
		file: result.filePath,
		line: message.line,
		column: message.column
	};
};

const files = (report, predicate) => report.results
	.filter(result => predicate(result))
	.sort(sortResults)
	.map(result => resultToFile(result));

module.exports = report => {
	if (report.errorCount > 0) {
		openEditor(files(report, result => result.errorCount > 0));
	} else if (report.warningCount > 0) {
		openEditor(files(report, result => result.warningCount > 0));
	}
};
<commit_msg>Minor code refactor (#397)<commit_after>'use strict';
const openEditor = require('open-editor');

const sortResults = (a, b) => a.errorCount + b.errorCount > 0 ? (a.errorCount - b.errorCount) : (a.warningCount - b.warningCount);

const resultToFile = result => {
	const [message] = result.messages
		.sort((a, b) => {
			if (a.severity < b.severity) {
				return 1;
			}

			if (a.severity > b.severity) {
				return -1;
			}

			if (a.line < b.line) {
				return -1;
			}

			if (a.line > b.line) {
				return 1;
			}

			return 0;
		});

	return {
		file: result.filePath,
		line: message.line,
		column: message.column
	};
};

const files = (report, predicate) => report.results
	.filter(result => predicate(result))
	.sort(sortResults)
	.map(result => resultToFile(result));

module.exports = report => {
	const count = report.errorCount > 0 ? 'errorCount' : 'warningCount';
	openEditor(files(report, result => result[count] > 0));
};
<|endoftext|>


<commit_before>(function(){

if (!window.qx) window.qx = {};

qx.$$start = new Date().valueOf();
qx.$$build = 1298881400925;
qx.$$type = "source";

if (!window.qxsettings) qxsettings = {};
var settings = {"qx.application":"widgets.Application","qx.version":"1.3.0-unify","unify.root":"/widgets"};
for (var k in settings) qxsettings[k] = settings[k];

if (!window.qxvariants) qxvariants = {};
var variants = {"qx.debug":"on"};
for (var k in variants) qxvariants[k] = variants[k];

if (!qx.$$libraries) qx.$$libraries = {};
var libinfo = {"__out__":{"sourceUri":"script"},"qx":{"resourceUri":"../../../../qooxdoo/qooxdoo/framework/source/resource","sourceUri":"../../../../qooxdoo/qooxdoo/framework/source/class","version":"1.4-pre"},"unify":{"resourceUri":"../../../framework/source/resource","sourceUri":"../../../framework/source/class","version":"trunk"},"widgets":{"resourceUri":"../source/resource","sourceUri":"../source/class","version":"trunk"}};
for (var k in libinfo) qx.$$libraries[k] = libinfo[k];

qx.$$resources = {"widgets/favicon.ico":"widgets","widgets/icons/icon_128x128.png":[128,128,"png","widgets"],"widgets/icons/icon_16x16.png":[16,16,"png","widgets"],"widgets/icons/icon_32x32.png":[32,32,"png","widgets"],"widgets/icons/icon_48x48.png":[48,48,"png","widgets"],"widgets/icons/icon_57x57.png":[57,57,"png","widgets"],"widgets/icons/readme.txt":"widgets","widgets/style.css":"widgets","widgets/style.sass":"widgets"};
qx.$$translations = {};
qx.$$locales = {};
qx.$$packageData = {};

qx.$$loader = {
  parts : {"boot":[0]},
  uris : [["qx:qx/Bootstrap.js","qx:qx/core/property/Util.js","qx:qx/core/Setting.js","qx:qx/bom/client/Engine.js","qx:qx/core/Variant.js","qx:qx/core/property/Debug.js","qx:qx/Mixin.js","qx:qx/Interface.js","qx:qx/Class.js","qx:qx/dev/StackTrace.js","qx:qx/core/ObjectRegistry.js","qx:qx/lang/Type.js","qx:qx/lang/Array.js","qx:qx/lang/Function.js","qx:qx/lang/String.js","qx:qx/type/BaseError.js","qx:qx/core/AssertionError.js","qx:qx/core/Assert.js","qx:qx/lang/JsonImpl.js","qx:qx/core/GlobalError.js","qx:qx/event/GlobalError.js","qx:qx/lang/Json.js","qx:qx/event/IEventHandler.js","qx:qx/dom/Node.js","qx:qx/bom/Event.js","qx:qx/event/Manager.js","qx:qx/event/Registration.js","qx:qx/core/ValidationError.js","qx:qx/core/property/Core.js","qx:qx/core/property/Multi.js","qx:qx/core/property/Group.js","qx:qx/core/MAssert.js","qx:qx/core/property/Simple.js","qx:qx/core/Object.js","unify:unify/event/handler/Transition.js","qx:qx/bom/client/Platform.js","qx:qx/bom/client/System.js","qx:qx/event/handler/UserAction.js","qx:qx/event/handler/Mouse.js","qx:qx/bom/client/Feature.js","qx:qx/lang/Object.js","qx:qx/bom/element/Class.js","unify:unify/bom/client/System.js","qx:qx/lang/RingBuffer.js","qx:qx/log/appender/RingBuffer.js","qx:qx/log/Logger.js","qx:qx/log/appender/Util.js","qx:qx/log/appender/Native.js","qx:qx/application/IApplication.js","qx:qx/event/handler/Application.js","qx:qx/event/IEventDispatcher.js","qx:qx/event/dispatch/Direct.js","qx:qx/event/handler/Window.js","qx:qx/core/Init.js","qx:qx/application/Native.js","unify:unify/event/handler/Orientation.js","qx:qx/event/dispatch/AbstractBubbling.js","qx:qx/event/dispatch/DomBubbling.js","unify:unify/event/handler/Touch.js","unify:unify/Application.js","widgets:widgets/Application.js","qx:qx/core/WindowError.js","qx:qx/lang/Date.js","qx:qx/core/Type.js","qx:qx/lang/Core.js","qx:qx/event/type/Event.js","qx:qx/event/handler/Object.js","qx:qx/event/type/Data.js","qx:qx/util/DisposeUtil.js","qx:qx/util/ObjectPool.js","qx:qx/event/Pool.js","qx:qx/event/type/Native.js","qx:qx/event/type/Dom.js","qx:qx/event/type/Mouse.js","qx:qx/event/type/MouseWheel.js","qx:qx/bom/Viewport.js","qx:qx/bom/Document.js","qx:qx/bom/client/Browser.js","qx:qx/dom/Hierarchy.js","qx:qx/bom/Selector.js","unify:unify/event/type/Orientation.js","unify:unify/event/type/Touch.js","unify:unify/bom/client/Extension.js","unify:unify/view/ViewManager.js","qx:qx/type/BaseArray.js","unify:unify/view/Path.js","unify:unify/view/PopOverManager.js","unify:unify/view/Navigation.js","unify:unify/bom/History.js","unify:unify/event/type/History.js","unify:unify/bom/Storage.js","qx:qx/bom/Cookie.js","qx:qx/bom/element2/Class.js","qx:qx/bom/element2/Style.js","qx:qx/locale/MTranslation.js","unify:unify/view/StaticView.js","widgets:widgets/view/Start.js","unify:unify/ui/Abstract.js","unify:unify/ui/Container.js","unify:unify/ui/Layer.js","qx:qx/bom/Html.js","qx:qx/ui/core/MChildrenHandling.js","unify:unify/ui/widget/qx/LayoutItem.js","unify:unify/ui/widget/core/Widget.js","unify:unify/ui/widget/core/Layer.js","unify:unify/ui/widget/qx/queue/Layout.js","qx:qx/util/DeferredCallManager.js","qx:qx/util/DeferredCall.js","qx:qx/event/handler/Element.js","qx:qx/html/Element.js","unify:unify/ui/widget/qx/queue/Manager.js","qx:qx/event/dispatch/MouseCapture.js","qx:qx/event/handler/Focus.js","qx:qx/bom/Selection.js","qx:qx/bom/Range.js","qx:qx/util/StringSplit.js","qx:qx/bom/Element.js","qx:qx/bom/element/Attribute.js","qx:qx/xml/Document.js","qx:qx/event/type/Focus.js","qx:qx/event/handler/Capture.js","qx:qx/bom/element/Scroll.js","qx:qx/bom/element/Overflow.js","qx:qx/bom/element/Clip.js","qx:qx/bom/element/Opacity.js","qx:qx/bom/element/Cursor.js","qx:qx/bom/element/BoxSizing.js","qx:qx/bom/element/Style.js","qx:qx/bom/element/Location.js","qx:qx/event/handler/Appear.js","unify:unify/ui/widget/qx/queue/Widget.js","unify:unify/ui/widget/qx/queue/Visibility.js","unify:unify/ui/widget/qx/queue/Appearance.js","unify:unify/ui/widget/qx/queue/Dispose.js","qx:qx/ui/layout/Abstract.js","qx:qx/ui/core/LayoutItem.js","qx:qx/ui/core/queue/Layout.js","qx:qx/ui/core/queue/Manager.js","qx:qx/ui/core/queue/Widget.js","qx:qx/ui/core/queue/Visibility.js","qx:qx/ui/core/queue/Appearance.js","qx:qx/ui/core/queue/Dispose.js","qx:qx/ui/layout/Basic.js","qx:qx/bom/element2/Dimension.js","unify:unify/ui/widget/basic/Label.js","unify:unify/view/TabViewManager.js"]],
  urisBefore : [],
  packageHashes : {"0":"0"},
  boot : "boot",
  closureParts : {},
  bootIsInline : false,

  decodeUris : function(compressedUris)
  {
    var libs = qx.$$libraries;
    var uris = [];
    for (var i=0; i<compressedUris.length; i++)
    {
      var uri = compressedUris[i].split(":");
      var euri;
      if (uri.length==2 && uri[0] in libs) {
        var prefix = libs[uri[0]].sourceUri;
        euri = prefix + "/" + uri[1];
      } else {
        euri = compressedUris[i];
      }

      uris.push(euri);
    }
    return uris;
  }
};

function loadScript(uri, callback) {
  var elem = document.createElement("script");
  elem.charset = "utf-8";
  elem.onreadystatechange = elem.onload = function()
  {
    if (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")
    {
      elem.onreadystatechange = elem.onload = null;
      callback();
    }
  };

  if (qx.$$type === "source") {
    elem.src = uri + "?r=" + qx.$$start;
  } else {
    elem.src = uri + "?r=" + qx.$$build;
  }

  var head = document.getElementsByTagName("head")[0];
  head.appendChild(elem);
}

var isWebkit = /AppleWebKit\/([^ ]+)/.test(navigator.userAgent);

function loadScriptList(list, callback) {
  if (list.length == 0) {
    callback();
    return;
  }
  loadScript(list.shift(), function() {
    if (isWebkit) {
      // force asynchronous load
      // Safari fails with an "maximum recursion depth exceeded" error if it is
      // called sync.
      window.setTimeout(function() {
        loadScriptList(list, callback);
      }, 0);
    } else {
      loadScriptList(list, callback);
    }
  });
}

var fireContentLoadedEvent = function() {
  qx.$$domReady = true;
  document.removeEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
};
if (document.addEventListener) {
  document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
}

qx.$$loader.importPackageData = function (dataMap) {
  if (dataMap["resources"]){
    var resMap = dataMap["resources"];
    for (var k in resMap) qx.$$resources[k] = resMap[k];
  }
  if (dataMap["locales"]){
    var locMap = dataMap["locales"];
    var qxlocs = qx.$$locales;
    for (var lang in locMap){
      if (!qxlocs[lang]) qxlocs[lang] = locMap[lang];
      else
        for (var k in locMap[lang]) qxlocs[lang][k] = locMap[lang][k];
    }
  }
  if (dataMap["translations"]){
    var trMap   = dataMap["translations"];
    var qxtrans = qx.$$translations;
    for (var lang in trMap){
      if (!qxtrans[lang]) qxtrans[lang] = trMap[lang];
      else
        for (var k in trMap[lang]) qxtrans[lang][k] = trMap[lang][k];
    }
  }
}

qx.$$loader.signalStartup = function ()
{
  qx.$$loader.scriptLoaded = true;
  if (window.qx && qx.event && qx.event.handler && qx.event.handler.Application) {
    qx.event.handler.Application.onScriptLoaded();
    qx.$$loader.applicationHandlerReady = true;
  } else {
    qx.$$loader.applicationHandlerReady = false;
  }
}

qx.$$loader.init = function(){
  var l=qx.$$loader;
  if (l.urisBefore.length>0){
    loadScriptList(l.urisBefore, function(){
      l.initUris();
    });
  } else {
    l.initUris();
  }
}

qx.$$loader.initUris = function(){
  var l=qx.$$loader;
  var bootPackageHash=l.packageHashes[l.parts[l.boot][0]];
  if (l.bootIsInline){
    l.importPackageData(qx.$$packageData[bootPackageHash]);
    l.signalStartup();
  } else {
    loadScriptList(l.decodeUris(l.uris[l.parts[l.boot]]), function(){
      // Opera needs this extra time to parse the scripts
      window.setTimeout(function(){
        l.importPackageData(qx.$$packageData[bootPackageHash] || {});
        l.signalStartup();
      }, 0);
    });
  }
}
})();

qx.$$packageData['0']={};

qx.$$loader.init();

<commit_msg>Remove generated code<commit_after><|endoftext|>