<commit_before>// Copyright (c) 2014, Joyent, Inc. All rights reserved.

var Readable = require('stream').Readable;
var util = require('util');

var assert = require('assert-plus');
var ldap = require('ldapjs');

///--- Globals

var sprintf = util.format;

var CHANGELOG_DN = 'cn=changelog';
var FILTER = '(&(changenumber>=%d)' +
    '(|(targetdn=*ou=users*)' +
    '(targetdn=*ou=groups*))' +
    '(!(targetdn=vm*))' +
    '(!(targetdn=amon*))' +
    ')';

///--- API

function ChangeLogStream(opts) {
    assert.object(opts, 'opts');
    assert.object(opts.log, 'opts.log');
    assert.object(opts.ufds, 'opts.ufds');
    assert.number(opts.ufds.interval, 'opts.ufds.interval');
    assert.optionalNumber(opts.ufds.timeout, 'opts.ufds.timeout');
    assert.optionalNumber(opts.changenumber, 'opts.changenumber');

    var self = this;

    Readable.call(this, {
        objectMode: true
    });

    this.log = opts.log.child({component: 'ChangeLogReader'}, true);

    this.changenumber = opts.changenumber || 0;
    this.interval = opts.ufds.interval;
    this.timeout = opts.ufds.timeout || this.interval / 2;
    this.polling = true; // don't poll until client is connected

    var client = ldap.createClient({
        connectTimeout: opts.ufds.connectTimeout || 4000,
        reconnect: true,
        disableQueue: true,
        log: opts.ufds.log || this.log,
        tlsOptions: opts.ufds.tlsOptions,
        url: opts.ufds.url,
        bindDN: opts.ufds.bindDN,
        bindCredentials: opts.ufds.bindCredentials
    });
    this.client = client;
    var log = self.log;

    client.on('connect', function () {
        log.info('ufds: connected, starting poll');
        // Start running once connected
        self.polling = false;
        self._poll();
    });

    client.on('close', function () {
        log.warn('ufds: disconnected');
    });

    client.on('connectError', function (err) {
        log.info({err: err}, 'ufds: connection attempt failed');
    });

    client.on('error', function (err) {
        log.error(err, 'ldap client: had error');
    });
}
util.inherits(ChangeLogStream, Readable);
module.exports = ChangeLogStream;

ChangeLogStream.prototype.close = function close() {
    this.log.debug('close: entered');
    clearTimeout(this.timer);

    if (this.dead) {
        setImmediate(this.emit.bind(this, 'close'));
        return;
    }

    this.dead = true;
    this.client.destroy();
    this.push(null);
    this.emit('close');

    this.log.debug('close: done');
};

ChangeLogStream.prototype._read = function _read() {
    this._poll();
};

ChangeLogStream.prototype._poll = function _poll() {
    clearTimeout(this.timer);
    if (!this.client.connected || this.polling) {
        return;
    }

    var log = this.log;
    var opts = {
        scope: 'sub',
        filter: sprintf(FILTER, this.changenumber + 1),
        sizeLimit: 1000
    };
    var result;
    var self = this;
    var timer = setTimeout(function onTimeout() {
        if (self.dead) {
            return;
        }

        log.error('_poll: ldap_search timeout');
        if (result) {
            result.removeAllListeners('end');
            result.removeAllListeners('searchEntry');
        }

        self.timer = setTimeout(self._poll.bind(self), self.interval);
    }, this.timeout);

    log.debug('_poll: entered');

    this.polling = true;
    this.client.search(CHANGELOG_DN, opts, function onSearch(err, res) {
        if (err) {
            clearTimeout(timer);
            log.error(err, '_poll: ldap_search failed (start)');
            self.polling = false;
            self.timer = setTimeout(self._poll.bind(self), self.interval);
            return;
        }

        var found = false;

        res.once('error', function onSearchError(err2) {
            clearTimeout(timer);
            log.error(err2, '_poll: ldap_search failed');
            self.polling = false;
            self.timer = setTimeout(self._poll.bind(self), self.interval);
        });

        res.on('searchEntry', function onEntry(entry) {
            clearTimeout(timer);
            log.debug({
                entry: entry.object
            }, '_poll: ldap_search: entry received');

            found = true;
            var changenumber = parseInt(entry.object.changenumber, 10);
            if (changenumber > self.changenumber) {
                self.changenumber = changenumber;
            }

            // If the stream applied backpressure just abandon this request
            // and wait for _read to be called to initiate more
            if (!self.push(entry.object)) {
                self.polling = false;
                res.removeAllListeners();
            }
        });

        res.once('end', function onEnd(stats) {
            clearTimeout(timer);
            log.debug({
                status: stats.status
            }, '_poll: done, setting timer');
            self.polling = false;
            self.timer = setTimeout(self._poll.bind(self), self.interval);
            if (!found) {
                // emit 'fresh' when we poll and find no new entries
                // this is helpful to know when we are caught up
                self.emit('fresh');
            } else {
                // if we found new entries, there may be more
                self._poll();
            }
        });
    });
};

ChangeLogStream.prototype.toString = function toString() {
    var str = '[object ChangeLogStream <';
    str += 'changenumber=' + this.changenumber + ', ';
    str += 'interval=' + this.interval + ', ';
    str += 'url=' + this.client.url;
    str += '>]';

    return (str);
};

///--- Tests

function test() {
    var bunyan = require('bunyan');
    var dashdash = require('dashdash');
    var path = require('path');

    var options = [
        {
            names: ['help', 'h'],
            type: 'bool',
            help: 'Print this help and exit.'
        },
        {
            names: ['config', 'f'],
            type: 'string',
            env: 'MAHI_CONFIG',
            helpArg: 'PATH',
            default: path.resolve(__dirname, '../../etc/mahi.json'),
            help: 'configuration file with ufds and redis config settings'
        },
        {
            names: ['changenumber', 'c'],
            type: 'string',
            helpArg: 'CHANGENUMBER',
            default: 0,
            help: 'changenumber to start at'
        },
        {
            names: ['poll', 'p'],
            type: 'bool',
            help: 'continue polling after no new entries are found'
        },
        {
            names: ['ufds-url'],
            type: 'string',
            env: 'MAHI_UFDS_URL',
            helpArg: 'URL',
            help: 'ufds url (overrides config)'
        }
    ];

    var parser = dashdash.createParser({options: options});
    var opts;
    try {
        opts = parser.parse(process.argv);
    } catch (e) {
        console.error('error: %s', e.message);
        process.exit(1);
    }

    if (opts.help) {
        var help = parser.help().trimRight();
        console.log('usage: \n' + help);
        process.exit(0);
    }

    var config = require(path.resolve(opts.config));
    var ufdsConfig = config.ufds || {
        bindDN: 'cn=root',
        bindCredentials: 'secret',
        interval: 5000,
        maxConnections: 1,
        log: log,
        tlsOptions: {
            rejectUnauthorized: false
        },
        url: 'ldap://localhost:1389'
    };

    ufdsConfig.url = opts['ufds-url'] || ufdsConfig.url;

    var log = bunyan.createLogger({
        level: process.env.LOG_LEVEL || 'info',
        name: 'changelog_test',
        stream: process.stdout,
        src: true
    });

    var stream = new ChangeLogStream({
        log: log,
        ufds: ufdsConfig,
        changenumber: opts.changenumber
    });

    stream.on('data', function (obj) {
        console.log(JSON.stringify(obj));
    });

    stream.on('fresh', function () {
        if (opts.poll) {
            console.warn('no new entries (CTRL+C to exit)');
        } else {
            process.exit(0);
        }
    });
}

if (require.main === module) {
    test();
}
<commit_msg>MANTA-2385 mahi should fatal if it receives a change from the past<commit_after>// Copyright (c) 2014, Joyent, Inc. All rights reserved.

var Readable = require('stream').Readable;
var util = require('util');

var assert = require('assert-plus');
var ldap = require('ldapjs');

///--- Globals

var sprintf = util.format;

var CHANGELOG_DN = 'cn=changelog';
var FILTER = '(&(changenumber>=%d)' +
    '(|(targetdn=*ou=users*)' +
    '(targetdn=*ou=groups*))' +
    '(!(targetdn=vm*))' +
    '(!(targetdn=amon*))' +
    ')';

///--- API

function ChangeLogStream(opts) {
    assert.object(opts, 'opts');
    assert.object(opts.log, 'opts.log');
    assert.object(opts.ufds, 'opts.ufds');
    assert.number(opts.ufds.interval, 'opts.ufds.interval');
    assert.optionalNumber(opts.ufds.timeout, 'opts.ufds.timeout');
    assert.optionalNumber(opts.changenumber, 'opts.changenumber');

    var self = this;

    Readable.call(this, {
        objectMode: true
    });

    this.log = opts.log.child({component: 'ChangeLogReader'}, true);

    this.changenumber = opts.changenumber || 0;
    this.interval = opts.ufds.interval;
    this.timeout = opts.ufds.timeout || this.interval / 2;
    this.polling = true; // don't poll until client is connected

    var client = ldap.createClient({
        connectTimeout: opts.ufds.connectTimeout || 4000,
        reconnect: true,
        disableQueue: true,
        log: opts.ufds.log || this.log,
        tlsOptions: opts.ufds.tlsOptions,
        url: opts.ufds.url,
        bindDN: opts.ufds.bindDN,
        bindCredentials: opts.ufds.bindCredentials
    });
    this.client = client;
    var log = self.log;

    client.on('connect', function () {
        log.info('ufds: connected, starting poll');
        // Start running once connected
        self.polling = false;
        self._poll();
    });

    client.on('close', function () {
        log.warn('ufds: disconnected');
    });

    client.on('connectError', function (err) {
        log.info({err: err}, 'ufds: connection attempt failed');
    });

    client.on('error', function (err) {
        log.error(err, 'ldap client: had error');
    });
}
util.inherits(ChangeLogStream, Readable);
module.exports = ChangeLogStream;

ChangeLogStream.prototype.close = function close() {
    this.log.debug('close: entered');
    clearTimeout(this.timer);

    if (this.dead) {
        setImmediate(this.emit.bind(this, 'close'));
        return;
    }

    this.dead = true;
    this.client.destroy();
    this.push(null);
    this.emit('close');

    this.log.debug('close: done');
};

ChangeLogStream.prototype._read = function _read() {
    this._poll();
};

ChangeLogStream.prototype._poll = function _poll() {
    clearTimeout(this.timer);
    if (!this.client.connected || this.polling) {
        return;
    }

    var log = this.log;
    var opts = {
        scope: 'sub',
        filter: sprintf(FILTER, this.changenumber + 1),
        sizeLimit: 1000
    };
    var result;
    var self = this;
    var timer = setTimeout(function onTimeout() {
        if (self.dead) {
            return;
        }

        log.error('_poll: ldap_search timeout');
        if (result) {
            result.removeAllListeners('end');
            result.removeAllListeners('searchEntry');
        }

        self.timer = setTimeout(self._poll.bind(self), self.interval);
    }, this.timeout);

    log.debug('_poll: entered');

    this.polling = true;
    this.client.search(CHANGELOG_DN, opts, function onSearch(err, res) {
        if (err) {
            clearTimeout(timer);
            log.error(err, '_poll: ldap_search failed (start)');
            self.polling = false;
            self.timer = setTimeout(self._poll.bind(self), self.interval);
            return;
        }

        var found = false;

        res.once('error', function onSearchError(err2) {
            clearTimeout(timer);
            log.error(err2, '_poll: ldap_search failed');
            self.polling = false;
            self.timer = setTimeout(self._poll.bind(self), self.interval);
        });

        res.on('searchEntry', function onEntry(entry) {
            clearTimeout(timer);
            log.info({
                entry: entry.object
            }, '_poll: ldap_search: entry received');

            found = true;
            var changenumber = parseInt(entry.object.changenumber, 10);
            if (changenumber > self.changenumber) {
                self.changenumber = changenumber;
            } else {
                log.fatal('_poll: changenumber out of order. ' +
                    'expected changenumber > %s, but got %s',
                    self.changenumber, changenumber);
                process.exit(1);
            }

            // If the stream applied backpressure just abandon this request
            // and wait for _read to be called to initiate more
            if (!self.push(entry.object)) {
                self.polling = false;
                res.removeAllListeners();
            }
        });

        res.once('end', function onEnd(stats) {
            clearTimeout(timer);
            log.debug({
                status: stats.status
            }, '_poll: done, setting timer');
            self.polling = false;
            self.timer = setTimeout(self._poll.bind(self), self.interval);
            if (!found) {
                // emit 'fresh' when we poll and find no new entries
                // this is helpful to know when we are caught up
                self.emit('fresh');
            } else {
                // if we found new entries, there may be more
                self._poll();
            }
        });
    });
};

ChangeLogStream.prototype.toString = function toString() {
    var str = '[object ChangeLogStream <';
    str += 'changenumber=' + this.changenumber + ', ';
    str += 'interval=' + this.interval + ', ';
    str += 'url=' + this.client.url;
    str += '>]';

    return (str);
};

///--- Tests

function test() {
    var bunyan = require('bunyan');
    var dashdash = require('dashdash');
    var path = require('path');

    var options = [
        {
            names: ['help', 'h'],
            type: 'bool',
            help: 'Print this help and exit.'
        },
        {
            names: ['config', 'f'],
            type: 'string',
            env: 'MAHI_CONFIG',
            helpArg: 'PATH',
            default: path.resolve(__dirname, '../../etc/mahi.json'),
            help: 'configuration file with ufds and redis config settings'
        },
        {
            names: ['changenumber', 'c'],
            type: 'string',
            helpArg: 'CHANGENUMBER',
            default: 0,
            help: 'changenumber to start at'
        },
        {
            names: ['poll', 'p'],
            type: 'bool',
            help: 'continue polling after no new entries are found'
        },
        {
            names: ['ufds-url'],
            type: 'string',
            env: 'MAHI_UFDS_URL',
            helpArg: 'URL',
            help: 'ufds url (overrides config)'
        }
    ];

    var parser = dashdash.createParser({options: options});
    var opts;
    try {
        opts = parser.parse(process.argv);
    } catch (e) {
        console.error('error: %s', e.message);
        process.exit(1);
    }

    if (opts.help) {
        var help = parser.help().trimRight();
        console.log('usage: \n' + help);
        process.exit(0);
    }

    var config = require(path.resolve(opts.config));
    var ufdsConfig = config.ufds || {
        bindDN: 'cn=root',
        bindCredentials: 'secret',
        interval: 5000,
        maxConnections: 1,
        log: log,
        tlsOptions: {
            rejectUnauthorized: false
        },
        url: 'ldap://localhost:1389'
    };

    ufdsConfig.url = opts['ufds-url'] || ufdsConfig.url;

    var log = bunyan.createLogger({
        level: process.env.LOG_LEVEL || 'info',
        name: 'changelog_test',
        stream: process.stdout,
        src: true
    });

    var stream = new ChangeLogStream({
        log: log,
        ufds: ufdsConfig,
        changenumber: opts.changenumber
    });

    stream.on('data', function (obj) {
        console.log(JSON.stringify(obj));
    });

    stream.on('fresh', function () {
        if (opts.poll) {
            console.warn('no new entries (CTRL+C to exit)');
        } else {
            process.exit(0);
        }
    });
}

if (require.main === module) {
    test();
}
<|endoftext|>


<commit_before>var util = require('../lib/test-utils.js');
var expect = require('chai').expect;

describe('fs.lstat', function() {
  beforeEach(util.setup);
  afterEach(util.cleanup);

  it('should be a function', function() {
    var fs = util.fs();
    expect(typeof fs.lstat).to.equal('function');
  });

  it('should return an error if path does not exist', function(done) {
    var fs = util.fs();

    fs.lstat('/tmp', function(error, result) {
      expect(error).to.exist;
      expect(error.code).to.equal('ENOENT');
      expect(result).not.to.exist;
      done();
    });
  });

  it('should return a stat object if path is not a symbolic link', function(done) {
    var fs = util.fs();

    fs.lstat('/', function(error, result) {
      expect(error).not.to.exist;
      expect(result).to.exist;
      expect(result.isDirectory()).to.be.true;
      done();
    });
  });

  it('should return a stat object if path is a symbolic link', function(done) {
    var fs = util.fs();

    fs.symlink('/', '/mylink', function(error) {
      if(error) throw error;

      fs.lstat('/mylink', function(error, result) {
        expect(error).not.to.exist;
        expect(result).to.exist;
        expect(result.isSymbolicLink()).to.be.true;
        done();
      });
    });
  });
});

describe('fs.promises.lstat', ()=> {
  beforeEach(util.setup);
  afterEach(util.cleanup);

  it('should return an error if path does not exist', () => {
    var fsPromises = util.fs().promises;

    return fsPromises.lstat('/tmp')
      .catch( error => {
        expect(error).to.exist;
        expect(error.code).to.equal('ENOENT');
      });
  });
});

<commit_msg>Fix #514: add test for fsPromises.lstat with directory<commit_after>var util = require('../lib/test-utils.js');
var expect = require('chai').expect;

describe('fs.lstat', function() {
  beforeEach(util.setup);
  afterEach(util.cleanup);

  it('should be a function', function() {
    var fs = util.fs();
    expect(typeof fs.lstat).to.equal('function');
  });

  it('should return an error if path does not exist', function(done) {
    var fs = util.fs();

    fs.lstat('/tmp', function(error, result) {
      expect(error).to.exist;
      expect(error.code).to.equal('ENOENT');
      expect(result).not.to.exist;
      done();
    });
  });

  it('should return a stat object if path is not a symbolic link', function(done) {
    var fs = util.fs();

    fs.lstat('/', function(error, result) {
      expect(error).not.to.exist;
      expect(result).to.exist;
      expect(result.isDirectory()).to.be.true;
      done();
    });
  });

  it('should return a stat object if path is a symbolic link', function(done) {
    var fs = util.fs();

    fs.symlink('/', '/mylink', function(error) {
      if(error) throw error;

      fs.lstat('/mylink', function(error, result) {
        expect(error).not.to.exist;
        expect(result).to.exist;
        expect(result.isSymbolicLink()).to.be.true;
        done();
      });
    });
  });
});

describe('fs.promises.lstat', () => {
  beforeEach(util.setup);
  afterEach(util.cleanup);

  it('should return an error if path does not exist', () => {
    var fsPromises = util.fs().promises;

    return fsPromises.lstat('/tmp')
      .catch( error => {
        expect(error).to.exist;
        expect(error.code).to.equal('ENOENT');
      });
  });

  it('should return a stat object if path is not a symbolic link', () => {
    var fsPromises = util.fs().promises;

    return fsPromises.lstat('/')
      .then(result => {
        expect(result).to.exist;
        expect(result.isDirectory()).to.be.true;
      });
  });
});
<|endoftext|>


<commit_before>var util = require('../lib/test-utils.js');
var expect = require('chai').expect;

describe('fs.watch', function() {
  // Our watch infrastucture is dependent on document.localStorage
  // see lib/intercom.js. Bail if we don't have access to it.
  before(function() {
    if(typeof global.localStorage === 'undefined') {
      /* eslint no-console: 0 */
      console.log('Skipping fs.watch() tests--not supported in current environment.');
      this.skip();
    }
  });

  beforeEach(util.setup);
  afterEach(util.cleanup);

  it('should be a function', function() {
    var fs = util.fs();
    expect(typeof fs.watch).to.equal('function');
  });

  it('should get a change event when writing a file', function(done) {
    var fs = util.fs();

    var watcher = fs.watch('/myfile', function(event, filename) {
      expect(event).to.equal('change');
      expect(filename).to.equal('/myfile');
      watcher.close();
      done();
    });

    fs.writeFile('/myfile', 'data', function(error) {
      if(error) throw error;
    });
  });

  it('should get a change event when writing a file beneath root dir with recursive=true', function(done) {
    var fs = util.fs();

    var watcher = fs.watch('/', { recursive: true }, function(event, filename) {
      expect(event).to.equal('change');
      expect(filename).to.equal('/');
      watcher.close();
      done();
    });

    fs.writeFile('/myfile', 'data', function(error) {
      if(error) throw error;
    });
  });

  it('should get a change event when writing a file in a dir with recursive=true', function(done) {
    var fs = util.fs();

    fs.mkdir('/foo', function(err) {
      if(err) throw err;

      var watcher = fs.watch('/foo', { recursive: true }, function(event, filename) {
        expect(event).to.equal('change');
        expect(filename).to.equal('/foo');
        watcher.close();
        done();
      });

      // This shouldn't produce a change event
      fs.writeFile('/myfile-not-in-foo', 'data', function(error) {
        if(error) throw error;
      });

      // This should
      fs.writeFile('/foo/myfile', 'data', function(error) {
        if(error) throw error;
      });
    });
  });

  it('should get a change event when renaming a file', function(done) {
    var fs = util.fs();

    fs.writeFile('/myfile', 'data', function(error) {
      if(error) throw error;
    });

    //Normaly A 'rename' event should be thrown, but filer doesn't support that event at this time.
    //For now renaming a file will throw a change event.
    var watcher = fs.watch('/myfile', function(event, filename) {
      expect(event).to.equal('change');
      expect(filename).to.equal('/myfile');
      watcher.close();
      done();
    });

    fs.rename('/myfile', '/mynewfile', function(error) {
      if(error) throw error;
    });
  });
});
<commit_msg>Issue #158 - Added test to ensure that watchers monitoring hardlinks are notified when the original file is updated<commit_after>var util = require('../lib/test-utils.js');
var expect = require('chai').expect;

describe('fs.watch', function() {
  // Our watch infrastucture is dependent on document.localStorage
  // see lib/intercom.js. Bail if we don't have access to it.
  before(function() {
    if(typeof global.localStorage === 'undefined') {
      /* eslint no-console: 0 */
      console.log('Skipping fs.watch() tests--not supported in current environment.');
      this.skip();
    }
  });

  beforeEach(util.setup);
  afterEach(util.cleanup);

  it('should be a function', function() {
    var fs = util.fs();
    expect(typeof fs.watch).to.equal('function');
  });

  it('should get a change event when writing a file', function(done) {
    var fs = util.fs();

    var watcher = fs.watch('/myfile', function(event, filename) {
      expect(event).to.equal('change');
      expect(filename).to.equal('/myfile');
      watcher.close();
      done();
    });

    fs.writeFile('/myfile', 'data', function(error) {
      if(error) throw error;
    });
  });

  it('should get a change event when writing a file beneath root dir with recursive=true', function(done) {
    var fs = util.fs();

    var watcher = fs.watch('/', { recursive: true }, function(event, filename) {
      expect(event).to.equal('change');
      expect(filename).to.equal('/');
      watcher.close();
      done();
    });

    fs.writeFile('/myfile', 'data', function(error) {
      if(error) throw error;
    });
  });

  it('should get a change event when writing a file in a dir with recursive=true', function(done) {
    var fs = util.fs();

    fs.mkdir('/foo', function(err) {
      if(err) throw err;

      var watcher = fs.watch('/foo', { recursive: true }, function(event, filename) {
        expect(event).to.equal('change');
        expect(filename).to.equal('/foo');
        watcher.close();
        done();
      });

      // This shouldn't produce a change event
      fs.writeFile('/myfile-not-in-foo', 'data', function(error) {
        if(error) throw error;
      });

      // This should
      fs.writeFile('/foo/myfile', 'data', function(error) {
        if(error) throw error;
      });
    });

    it('should get a change event when a file hardlink is being watched and the original file is changed', function(done) {
      var fs = util.fs();

      fs.writeFile('/myfile', 'data', function(error) {
        if(error) throw error;

        fs.link('/myfile', '/hardlink', function(error) {
          if(error) throw error;

          var watcher = fs.watch('/hardlink', function(event, filename) {
            expect(event).to.equal('change');
            expect(filename).to.equal('/hardlink');
            watcher.close();
            done();
          });

          fs.appendFile('/myfile', '...more data', function(error) {
            if(error) throw error;

            fs.readFile('/hardlink', 'utf8', function(error, data) {
              if(error) throw error;

              expect(data).to.equal('data...more data')
            });
          });
        });
      });
    });
  });

  it('should get a change event when renaming a file', function(done) {
    var fs = util.fs();

    fs.writeFile('/myfile', 'data', function(error) {
      if(error) throw error;
    });

    //Normaly A 'rename' event should be thrown, but filer doesn't support that event at this time.
    //For now renaming a file will throw a change event.
    var watcher = fs.watch('/myfile', function(event, filename) {
      expect(event).to.equal('change');
      expect(filename).to.equal('/myfile');
      watcher.close();
      done();
    });

    fs.rename('/myfile', '/mynewfile', function(error) {
      if(error) throw error;
    });
  });
});
<|endoftext|>


<commit_before>
/*!
* is
* the definitive JavaScript type testing library
* Copyright(c) 2011 Enrico Marino <enrico.marino@email.com>
* MIT license
*/

!(function (exports) {

  var undefined
    , owns = {}.hasOwnProperty
    , toString = {}.toString
    , isFinite = isFinite
    , NON_HOST_TYPES = {
          'boolean': 1
        , 'number': 1
        , 'string': 1
        , 'undefined': 1
      }
    ;

  exports.is = {};

  /**
   * Library version.
   */

  is.version = 0.1.2;

  /**
   * Test if 'value' is a type of 'type'.
   *
   * @param value value to test
   * @param {String} type type
   * @return {Boolean} true if 'value' is an arguments object, false otherwise
   * @api public
   */

  is.a = function (value, type) {
    return typeof value === type;
  };

  /**
   * Test if 'value' is an arguments object.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an arguments object, false otherwise
   * @api public
   */

  is.arguments = function (value) {
    return '[object Arguments]' === toString.call(value);
  };

  /**
   * Test if 'value' is an array.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an array, false otherwise
   * @api public
   */

  is.array = function (value) {
    return '[object Array]' === toString.call(value);
  };

  /**
   * Test if 'value' is an empty array(like) object.
   *
   * @param {Array|Arguments} value value to test
   * @return {Boolean} true if 'value' is an empty array(like), false otherwise
   * @api public
   */

  is.array.empty = function (value) {
    return value.length === 0;
  };

  /**
   * Test if 'value' is an arraylike object.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an arguments object, false otherwise
   * @api public
   */

  is.arraylike = function (value) {
    return value !== undefined
      && owns.call(value, 'length')
      && isFinite(value.length);
  };

  /**
   * Test if 'value' is a boolean.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is a boolean, false otherwise
   * @api public
   */

  is.boolean = function (value) {
    return '[object Boolean]' === toString.call(value);
  };

  /**
   * Test if 'value' is a date.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is a date, false otherwise
   * @api public
   */

  is.date = function (value) {
    return '[object Date]' === toString.call(value);
  };

  /**
   * Test if 'value' is a decimal number.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is a decimal number, false otherwise
   * @api public
   */

  is.decimal = function (value) {
    return '[object Number]' === toString.call(value) && value % 1 !== 0;
  };

  /**
   * Test if 'value' is defined.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is defined, false otherwise
   * @api public
   */

  is.defined = function (value) {
    return value !== undefined;
  };

  /**
   * Test if 'value' is divisible by 'n'.
   *
   * @param {Number} value value to test
   * @param {Number} n dividend
   * @return {Boolean} true if 'value' is divisible by 'n', false otherwise
   * @api public
   */

  is.divisibleBy = function (value, n) {
    return '[object Number]' === toString.call(value)
      && n !== 0
      && value % n === 0;
  };

  /**
   * Test if 'value' is an html element.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an html element, false otherwise
   * @api public
   */

  is.element = function (value) {
    return value !== undefined
      && owns.call(value, nodeType)
      && value.nodeType === 1;
  };

  /**
   * Test if 'value' is empty.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is empty, false otherwise
   * @api public
   */

  is.empty = function (value) {
    var type = toString.call(value)
      , key
      ;

    if ('[object Array]' === type || '[object Arguments]' === type) {
      return value.length === 0;
    }

    if ('[object Object]' === type) {
      for (var key in value) if (owns.call(value, key)) return false;
      return true;
    }

    if ('[object String]' === type) {
      return value === '';
    }

    return false;
  };

  /**
   * Test if 'value' is an error object.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an error object, false otherwise
   * @api public
   */

  is.error = function (value) {
    return '[object Error]' === toString.call(value);
  };

  /**
   * Test if 'value' is equal to 'other'.
   *
   * @param value value
   * @param other value to compare with
   * @return {Boolean} true if 'value' is equal to 'other', false otherwise
   */

  is.equal = function (value, other) {
    var undefined
      , type = toString.call(value)
      , key
      ;

    if (type !== toString.call(other)) {
      return false;
    }

    if ('[object Object]' === type) {
      for (key in value) {
        if (!equiv(value[key], other[key])) {
          return false;
        }
      }
      return true;
    }

    if ('[object Array]' === type) {
      key = value.length;
      if (key !== other.length) {
        return false;
      }
      while (--key) {
        if (!equiv(value[key], other[key])) {
          return false;
        }
      }
      return true;
    }

    if ('[object Function]' === type) {
      return value.prototype === other.prototype;
    }

    if ('[object Date]' === type) {
      return value.getTime() === other.getTime();
    }

    return value === other;
  };

  /**
   * Test if 'value' is an even number.
   *
   * @param {Number} value to test
   * @return {Boolean} true if 'value' is an even number, false otherwise
   * @api public
   */

  is.even = function (value) {
    return '[object Number]' === toString.call(value) && value % 2 === 0;
  };

  /**
   * Test if 'value' is false.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is false, false otherwise
   * @api public
   */

  is.false = function (value) {
    return value === false;
  };

  /**
   * Test if 'value' is a function.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is a function, false otherwise
   * @api public
   */

  is.function = function(value) {
    return '[object Function]' === toString.call(value);
  };

  /**
   * Test if 'value' is hosted by 'host'.
   *
   * @param {String} value to test
   * @param host host
   * @return {Boolean} true if 'value' is hosted by 'host', false otherwise
   * @api public
   */

  is.hosted = function (value, host) {
    var type = typeof host[value];
    return type === 'object' ? !!host[value] : !NON_HOST_TYPES[type];
  };

  /**
   * Test if 'value' is greater than or equal to 'other'.
   *
   * @param {Number} value value to test
   * @param {Number} other value to compare with
   * @return {Boolean}
   * @api public
   */

  is.ge = function (value, other) {
    return value >= other;
  };

  /**
   * Test if 'value' is greater than 'other'.
   *
   * @param {Number} value value to test
   * @param {Number} other value to compare with
   * @return {Boolean}
   * @api public
   */

  is.gt = function (value, other) {
    return value > other;
  };

  /**
   * Test if 'value' is an instance of 'constructor'.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an instance of 'constructor'
   * @api public
   */

  is.instanceof = function (value, constructor) {
    return value instanceof constructor;
  };

  /**
   * Test if 'value' is an integer.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is an integer, false otherwise
   * @api public
   */

  is.int = function (value) {
    return '[object Number]' === toString.call(value) && value % 1 === 0;
  };

  /**
   * Test if 'value' is not a number.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is not a number, false otherwise
   * @api public
   */

  is.nan = function (value) {
    return value === null || value !== value;
  };

  /**
   * Test if 'value' is less than or equal to 'other'.
   *
   * @param {Number} value value to test
   * @param {Number} other value to compare with
   * @return {Boolean} if 'value' is less than or equal to 'other'
   * @api public
   */

  is.le = function (value, other) {
    return value <= other;
  };

  /**
   * Test if 'value' is less than 'other'.
   *
   * @param {Number} value value to test
   * @param {Number} other value to compare with
   * @return {Boolean} if 'value' is less than 'other'
   * @api public
   */

  is.lt = function (value, other) {
    return value < other;
  };

  /**
   * Test if 'value' is greater than 'others' values.
   *
   * @param {Number} value value to test
   * @param {Array} others values to compare with
   * @return {Boolean} true if 'value' is greater than 'others' values
   * @api public
   */

  is.maximum = function (value, others) {
    var len = others.length;

    while (--len) {
      if (value < others[len]) {
        return false;
      }
    }

    return true;
  };

  /**
   * Test if 'value' is less than 'others' values.
   *
   * @param {Number} value value to test
   * @param {Array} others values to compare with
   * @return {Boolean} true if 'value' is less than 'others' values
   * @api public
   */

  is.minimum = function (value, others) {
    var len = values.length;

    while (--len) {
      if (value > others[len]) {
        return false;
      }
    }

    return true;
  };

  /**
   * Test if 'value' is null.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is null, false otherwise
   * @api public
   */

  is.null = function (value) {
    return value === null;
  };

  /**
   * Test if 'value' is a number.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is a number, false otherwise
   * @api public
   */

  is.number = function (value) {
    return '[object Number]' === toString.call(value);
  };

  /**
   * Test if 'value' is an odd number.
   *
   * @param {Number} value to test
   * @return {Boolean} true if 'value' is an odd number, false otherwise
   * @api public
   */

  is.odd = function (value) {
    return '[object Number]' === toString.call(value) && value % 2 !== 0;
  };

  /**
   * Test if 'value' is an object.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is an object, false otherwise
   * @api public
   */

  is.object = function (value) {
    return '[object Object]' === toString.call(value);
  }

  /**
   * Test if 'value' is a regular expression.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is a regexp, false otherwise
   * @api public
   */

  is.regexp = function (value) {
    return '[object RegExp]' === toString.call(value);
  };

  /**
   * Test if 'value' is a string.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is a string, false otherwise
   * @api public
   */

  is.string = function (value) {
    return '[object String]' === toString.call(value);
  }

  /**
   * Test if 'value' is true.
   *
   * @param {Boolean} value to test
   * @return {Boolean} true if 'value' is true, false otherwise
   * @api public
   */

  is.true = function (value) {
    return value === true;
  };

  /**
   * Test if 'value' is undefined.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is undefined, false otherwise
   * @api public
   */

  is.undefined = function (value) {
    return value === undefined;
  };

  /**
   * Test if 'value' is within 'start' and 'finish'.
   *
   * @param {Number} value value to test
   * @param {Number} start lower bound
   * @param {Number} finish upper bound
   * @return {Boolean} true if 'value' is is within 'start' and 'finish'
   * @api public
   */
  is.within = function (value, start, finish) {
    return value >= start && value <= finish;
  }

}(this));
<commit_msg>added alias is.type for is.a<commit_after>
/*!
* is
* the definitive JavaScript type testing library
* Copyright(c) 2011 Enrico Marino <enrico.marino@email.com>
* MIT license
*/

!(function (exports) {

  var undefined
    , owns = {}.hasOwnProperty
    , toString = {}.toString
    , isFinite = isFinite
    , NON_HOST_TYPES = {
          'boolean': 1
        , 'number': 1
        , 'string': 1
        , 'undefined': 1
      }
    ;

  exports.is = {};

  /**
   * Library version.
   */

  is.version = 0.1.2;

  /**
   * Test if 'value' is a type of 'type'.
   *
   * @param value value to test
   * @param {String} type type
   * @return {Boolean} true if 'value' is an arguments object, false otherwise
   * @api public
   */

  is.a =
  is.type = function (value, type) {
    return typeof value === type;
  };

  /**
   * Test if 'value' is an arguments object.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an arguments object, false otherwise
   * @api public
   */

  is.arguments = function (value) {
    return '[object Arguments]' === toString.call(value);
  };

  /**
   * Test if 'value' is an array.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an array, false otherwise
   * @api public
   */

  is.array = function (value) {
    return '[object Array]' === toString.call(value);
  };

  /**
   * Test if 'value' is an empty array(like) object.
   *
   * @param {Array|Arguments} value value to test
   * @return {Boolean} true if 'value' is an empty array(like), false otherwise
   * @api public
   */

  is.array.empty = function (value) {
    return value.length === 0;
  };

  /**
   * Test if 'value' is an arraylike object.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an arguments object, false otherwise
   * @api public
   */

  is.arraylike = function (value) {
    return value !== undefined
      && owns.call(value, 'length')
      && isFinite(value.length);
  };

  /**
   * Test if 'value' is a boolean.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is a boolean, false otherwise
   * @api public
   */

  is.boolean = function (value) {
    return '[object Boolean]' === toString.call(value);
  };

  /**
   * Test if 'value' is a date.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is a date, false otherwise
   * @api public
   */

  is.date = function (value) {
    return '[object Date]' === toString.call(value);
  };

  /**
   * Test if 'value' is a decimal number.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is a decimal number, false otherwise
   * @api public
   */

  is.decimal = function (value) {
    return '[object Number]' === toString.call(value) && value % 1 !== 0;
  };

  /**
   * Test if 'value' is defined.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is defined, false otherwise
   * @api public
   */

  is.defined = function (value) {
    return value !== undefined;
  };

  /**
   * Test if 'value' is divisible by 'n'.
   *
   * @param {Number} value value to test
   * @param {Number} n dividend
   * @return {Boolean} true if 'value' is divisible by 'n', false otherwise
   * @api public
   */

  is.divisibleBy = function (value, n) {
    return '[object Number]' === toString.call(value)
      && n !== 0
      && value % n === 0;
  };

  /**
   * Test if 'value' is an html element.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an html element, false otherwise
   * @api public
   */

  is.element = function (value) {
    return value !== undefined
      && owns.call(value, nodeType)
      && value.nodeType === 1;
  };

  /**
   * Test if 'value' is empty.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is empty, false otherwise
   * @api public
   */

  is.empty = function (value) {
    var type = toString.call(value)
      , key
      ;

    if ('[object Array]' === type || '[object Arguments]' === type) {
      return value.length === 0;
    }

    if ('[object Object]' === type) {
      for (var key in value) if (owns.call(value, key)) return false;
      return true;
    }

    if ('[object String]' === type) {
      return value === '';
    }

    return false;
  };

  /**
   * Test if 'value' is an error object.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an error object, false otherwise
   * @api public
   */

  is.error = function (value) {
    return '[object Error]' === toString.call(value);
  };

  /**
   * Test if 'value' is equal to 'other'.
   *
   * @param value value
   * @param other value to compare with
   * @return {Boolean} true if 'value' is equal to 'other', false otherwise
   */

  is.equal = function (value, other) {
    var undefined
      , type = toString.call(value)
      , key
      ;

    if (type !== toString.call(other)) {
      return false;
    }

    if ('[object Object]' === type) {
      for (key in value) {
        if (!equiv(value[key], other[key])) {
          return false;
        }
      }
      return true;
    }

    if ('[object Array]' === type) {
      key = value.length;
      if (key !== other.length) {
        return false;
      }
      while (--key) {
        if (!equiv(value[key], other[key])) {
          return false;
        }
      }
      return true;
    }

    if ('[object Function]' === type) {
      return value.prototype === other.prototype;
    }

    if ('[object Date]' === type) {
      return value.getTime() === other.getTime();
    }

    return value === other;
  };

  /**
   * Test if 'value' is an even number.
   *
   * @param {Number} value to test
   * @return {Boolean} true if 'value' is an even number, false otherwise
   * @api public
   */

  is.even = function (value) {
    return '[object Number]' === toString.call(value) && value % 2 === 0;
  };

  /**
   * Test if 'value' is false.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is false, false otherwise
   * @api public
   */

  is.false = function (value) {
    return value === false;
  };

  /**
   * Test if 'value' is a function.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is a function, false otherwise
   * @api public
   */

  is.function = function(value) {
    return '[object Function]' === toString.call(value);
  };

  /**
   * Test if 'value' is hosted by 'host'.
   *
   * @param {String} value to test
   * @param host host
   * @return {Boolean} true if 'value' is hosted by 'host', false otherwise
   * @api public
   */

  is.hosted = function (value, host) {
    var type = typeof host[value];
    return type === 'object' ? !!host[value] : !NON_HOST_TYPES[type];
  };

  /**
   * Test if 'value' is greater than or equal to 'other'.
   *
   * @param {Number} value value to test
   * @param {Number} other value to compare with
   * @return {Boolean}
   * @api public
   */

  is.ge = function (value, other) {
    return value >= other;
  };

  /**
   * Test if 'value' is greater than 'other'.
   *
   * @param {Number} value value to test
   * @param {Number} other value to compare with
   * @return {Boolean}
   * @api public
   */

  is.gt = function (value, other) {
    return value > other;
  };

  /**
   * Test if 'value' is an instance of 'constructor'.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is an instance of 'constructor'
   * @api public
   */

  is.instanceof = function (value, constructor) {
    return value instanceof constructor;
  };

  /**
   * Test if 'value' is an integer.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is an integer, false otherwise
   * @api public
   */

  is.int = function (value) {
    return '[object Number]' === toString.call(value) && value % 1 === 0;
  };

  /**
   * Test if 'value' is not a number.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is not a number, false otherwise
   * @api public
   */

  is.nan = function (value) {
    return value === null || value !== value;
  };

  /**
   * Test if 'value' is less than or equal to 'other'.
   *
   * @param {Number} value value to test
   * @param {Number} other value to compare with
   * @return {Boolean} if 'value' is less than or equal to 'other'
   * @api public
   */

  is.le = function (value, other) {
    return value <= other;
  };

  /**
   * Test if 'value' is less than 'other'.
   *
   * @param {Number} value value to test
   * @param {Number} other value to compare with
   * @return {Boolean} if 'value' is less than 'other'
   * @api public
   */

  is.lt = function (value, other) {
    return value < other;
  };

  /**
   * Test if 'value' is greater than 'others' values.
   *
   * @param {Number} value value to test
   * @param {Array} others values to compare with
   * @return {Boolean} true if 'value' is greater than 'others' values
   * @api public
   */

  is.maximum = function (value, others) {
    var len = others.length;

    while (--len) {
      if (value < others[len]) {
        return false;
      }
    }

    return true;
  };

  /**
   * Test if 'value' is less than 'others' values.
   *
   * @param {Number} value value to test
   * @param {Array} others values to compare with
   * @return {Boolean} true if 'value' is less than 'others' values
   * @api public
   */

  is.minimum = function (value, others) {
    var len = values.length;

    while (--len) {
      if (value > others[len]) {
        return false;
      }
    }

    return true;
  };

  /**
   * Test if 'value' is null.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is null, false otherwise
   * @api public
   */

  is.null = function (value) {
    return value === null;
  };

  /**
   * Test if 'value' is a number.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is a number, false otherwise
   * @api public
   */

  is.number = function (value) {
    return '[object Number]' === toString.call(value);
  };

  /**
   * Test if 'value' is an odd number.
   *
   * @param {Number} value to test
   * @return {Boolean} true if 'value' is an odd number, false otherwise
   * @api public
   */

  is.odd = function (value) {
    return '[object Number]' === toString.call(value) && value % 2 !== 0;
  };

  /**
   * Test if 'value' is an object.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is an object, false otherwise
   * @api public
   */

  is.object = function (value) {
    return '[object Object]' === toString.call(value);
  }

  /**
   * Test if 'value' is a regular expression.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is a regexp, false otherwise
   * @api public
   */

  is.regexp = function (value) {
    return '[object RegExp]' === toString.call(value);
  };

  /**
   * Test if 'value' is a string.
   *
   * @param value to test
   * @return {Boolean} true if 'value' is a string, false otherwise
   * @api public
   */

  is.string = function (value) {
    return '[object String]' === toString.call(value);
  }

  /**
   * Test if 'value' is true.
   *
   * @param {Boolean} value to test
   * @return {Boolean} true if 'value' is true, false otherwise
   * @api public
   */

  is.true = function (value) {
    return value === true;
  };

  /**
   * Test if 'value' is undefined.
   *
   * @param value value to test
   * @return {Boolean} true if 'value' is undefined, false otherwise
   * @api public
   */

  is.undefined = function (value) {
    return value === undefined;
  };

  /**
   * Test if 'value' is within 'start' and 'finish'.
   *
   * @param {Number} value value to test
   * @param {Number} start lower bound
   * @param {Number} finish upper bound
   * @return {Boolean} true if 'value' is is within 'start' and 'finish'
   * @api public
   */
  is.within = function (value, start, finish) {
    return value >= start && value <= finish;
  }

}(this));
<|endoftext|>


<commit_before>/**
 * Created by José Miguel on 13/01/2016.
 */

/*Faço blabla so para ver se dá muahaha*/<commit_msg>Delete js.js<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Narciso Jaramillo. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4,
maxerr: 50, browser: true */
/*global $, define, brackets */

define(function (require, exports, module) {
    "use strict";

    var QuickOpen      = brackets.getModule("search/QuickOpen"),
        StringMatch    = brackets.getModule("utils/StringMatch"),
        StringUtils    = brackets.getModule("utils/StringUtils"),
        ProjectManager = brackets.getModule("project/ProjectManager"),
        FileSystem     = brackets.getModule("filesystem/FileSystem");

    var StatusDisplay = require("src/StatusDisplay"),
        Bower         = require("src/bower/Bower"),
        Strings       = require("strings");

    var queue = [],
        failed = [],
        packages,
        packageListPromise,
        installPromise,
        latestQuery,
        lastFetchTime,
        status = StatusDisplay.create();

    function _installNext() {
        if (installPromise || queue.length === 0) {
            return;
        }

        var rootPath = ProjectManager.getProjectRoot().fullPath,
            pkgName = queue.shift();

        status.showStatusInfo(StringUtils.format(Strings.STATUS_INSTALLING_PKG, pkgName), true);

        installPromise = Bower.install(rootPath, pkgName);

        installPromise.done(function (installationPath) {
            status.showStatusInfo(StringUtils.format(Strings.STATUS_PKG_INSTALLED, pkgName), false);

            window.setTimeout(function () {
                ProjectManager.showInTree(FileSystem.getDirectoryForPath(installationPath));
            }, 1000);

        }).fail(function (error) {
            // Make sure the user sees the error even if other packages get installed.
            failed.push(pkgName);
        }).always(function () {
            installPromise = null;

            if (queue.length === 0) {
                if (failed.length > 0) {
                    var errorMessage = StringUtils.format(Strings.STATUS_ERROR_INSTALLING, failed.join(", "));
                    status.showStatusInfo(errorMessage, false);
                    failed = [];
                }
                status.hideStatusInfo();
            } else {
                _installNext();
            }
        });
    }

    function _addToQueue(pkgName) {
        queue.push(pkgName);

        _installNext();
    }

    function quickOpenBower() {
        QuickOpen.beginSearch("+", "");
    }

    function _match(query) {
        // TODO: doesn't seem to work if no file is open. Bug in Quick Open?
        return (query.length > 0 && query.charAt(0) === "+");
    }

    function _resetFetchStatusIfNeeded() {
        var curTime = Date.now(),
            maxTime = 1000 * 60 * 10; // 10 minutes

        if (packages && (lastFetchTime === undefined || curTime - lastFetchTime > maxTime)) {
            // Packages were fetched more than ten minutes ago. Force a refetch.
            packages = null;
        }

        if (lastFetchTime === undefined || curTime - lastFetchTime > maxTime) {
            // Re-fetch the list of packages if it's been more than 10 minutes since the last time we fetched them.
            packages = null;
            packageListPromise = null;
            lastFetchTime = curTime;
        }
    }

    function _getSortedPackages (pkgs) {
        pkgs.sort(function (pkg1, pkg2) {
            var name1 = pkg1.name.toLowerCase(),
                name2 = pkg2.name.toLowerCase();

            return (name1 < name2 ? -1 : (name1 === name2 ? 0 : 1));
        });

        return pkgs;
    }

    function _fetchPackageList() {
        var result = new $.Deferred();

        Bower.listCache().then(function (pkgs) {
            if(pkgs.length !== 0) {
                packages = _getSortedPackages(pkgs);
            }

            return Bower.search();
        })
        .done(function (pkgs) {
            packages = _getSortedPackages(pkgs);

            result.resolve();
        })
        .fail(result.reject);

        return result;
    }

    function _search(query, matcher) {
        // Remove initial "+"
        query = query.slice(1);

        latestQuery = query;

        _resetFetchStatusIfNeeded();

        if (!packages) {
            // Packages haven't yet been fetched. If we haven't started fetching them yet, go ahead and do so.
            if (!packageListPromise) {
                var displayMessage = Strings.STATUS_BOWER_LOADING;

                packageListPromise = new $.Deferred();

                status.showQuickSearchSpinner();
                status.showStatusInfo(displayMessage, true);

                _fetchPackageList()
                    .done(function () {
                        displayMessage = Strings.STATUS_BOWER_READY;

                        packageListPromise.resolve();
                    })
                    .fail(function () {
                        displayMessage = Strings.STATUS_BOWER_NOT_LOADED;

                        packageListPromise.reject();
                    })
                    .always(function () {
                        status.hideQuickSearchSpinner();
                        status.showStatusInfo(displayMessage, false);
                        status.hideStatusInfo();

                        packageListPromise = null;
                    });
            }

            // Due to bugs in smart autocomplete, we have to return separate promises for each call
            // to _search, but make sure to only resolve the last one.
            var result = new $.Deferred();

            packageListPromise.done(function () {
                // validate for an empty string avoids an exception in smart autocomplete
                if (query === latestQuery && query.trim() !== "") {
                    result.resolve(_search(latestQuery, matcher));
                } else {
                    result.reject();
                }
            });

            return result.promise();
        }

        // Filter and rank how good each match is
        var filteredList = $.map(packages, function (pkg) {
            var searchResult = matcher.match(pkg.name, query);

            if (searchResult) {
                searchResult.pkg = pkg;
            }
            return searchResult;
        });

        // Sort based on ranking & basic alphabetical order
        StringMatch.basicMatchSort(filteredList);

        return filteredList;
    }

    function _itemSelect(result) {
        if (result) {
            _addToQueue(result.pkg.name);
        }
    }

    function init(domainPath) {
        QuickOpen.addQuickOpenPlugin({
            name: "installFromBower",
            languageIds: [],
            search: _search,
            match: _match,
            itemSelect: _itemSelect,
            label: Strings.TITLE_QUICK_OPEN
        });
    }

    exports.init           = init;
    exports.quickOpenBower = quickOpenBower;
});
<commit_msg>Fixing validation to determine when to re-fetch packages.<commit_after>/*
 * Copyright (c) 2014 Narciso Jaramillo. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4,
maxerr: 50, browser: true */
/*global $, define, brackets */

define(function (require, exports, module) {
    "use strict";

    var QuickOpen      = brackets.getModule("search/QuickOpen"),
        StringMatch    = brackets.getModule("utils/StringMatch"),
        StringUtils    = brackets.getModule("utils/StringUtils"),
        ProjectManager = brackets.getModule("project/ProjectManager"),
        FileSystem     = brackets.getModule("filesystem/FileSystem");

    var StatusDisplay = require("src/StatusDisplay"),
        Bower         = require("src/bower/Bower"),
        Strings       = require("strings");

    var queue = [],
        failed = [],
        packages,
        packageListPromise,
        installPromise,
        latestQuery,
        lastFetchTime,
        status = StatusDisplay.create();

    var MAX_TIME_FETCH = 1000 * 60 * 10; // 10 minutes

    function _installNext() {
        if (installPromise || queue.length === 0) {
            return;
        }

        var rootPath = ProjectManager.getProjectRoot().fullPath,
            pkgName = queue.shift();

        status.showStatusInfo(StringUtils.format(Strings.STATUS_INSTALLING_PKG, pkgName), true);

        installPromise = Bower.install(rootPath, pkgName);

        installPromise.done(function (installationPath) {
            status.showStatusInfo(StringUtils.format(Strings.STATUS_PKG_INSTALLED, pkgName), false);

            window.setTimeout(function () {
                ProjectManager.showInTree(FileSystem.getDirectoryForPath(installationPath));
            }, 1000);

        }).fail(function (error) {
            // Make sure the user sees the error even if other packages get installed.
            failed.push(pkgName);
        }).always(function () {
            installPromise = null;

            if (queue.length === 0) {
                if (failed.length > 0) {
                    var errorMessage = StringUtils.format(Strings.STATUS_ERROR_INSTALLING, failed.join(", "));
                    status.showStatusInfo(errorMessage, false);
                    failed = [];
                }
                status.hideStatusInfo();
            } else {
                _installNext();
            }
        });
    }

    function _addToQueue(pkgName) {
        queue.push(pkgName);

        _installNext();
    }

    function quickOpenBower() {
        QuickOpen.beginSearch("+", "");
    }

    function _match(query) {
        // TODO: doesn't seem to work if no file is open. Bug in Quick Open?
        return (query.length > 0 && query.charAt(0) === "+");
    }

    function _resetFetchStatusIfNeeded() {
        var curTime = Date.now();

        if (lastFetchTime === undefined || (curTime - lastFetchTime > MAX_TIME_FETCH)) {
            // Re-fetch the list of packages if it's been more than 10 minutes since the last time we fetched them.
            packages = null;
            packageListPromise = null;
            lastFetchTime = curTime;
        }
    }

    function _getSortedPackages (pkgs) {
        pkgs.sort(function (pkg1, pkg2) {
            var name1 = pkg1.name.toLowerCase(),
                name2 = pkg2.name.toLowerCase();

            return (name1 < name2 ? -1 : (name1 === name2 ? 0 : 1));
        });

        return pkgs;
    }

    function _fetchPackageList() {
        var result = new $.Deferred();

        Bower.listCache().then(function (pkgs) {
            if(pkgs.length !== 0) {
                packages = _getSortedPackages(pkgs);
            }

            return Bower.search();
        })
        .done(function (pkgs) {
            packages = _getSortedPackages(pkgs);

            result.resolve();
        })
        .fail(result.reject);

        return result;
    }

    function _search(query, matcher) {
        // Remove initial "+"
        query = query.slice(1);

        latestQuery = query;

        _resetFetchStatusIfNeeded();

        if (!packages) {
            // Packages haven't yet been fetched. If we haven't started fetching them yet, go ahead and do so.
            if (!packageListPromise) {
                var displayMessage = Strings.STATUS_BOWER_LOADING;

                packageListPromise = new $.Deferred();

                status.showQuickSearchSpinner();
                status.showStatusInfo(displayMessage, true);

                _fetchPackageList()
                    .done(function () {
                        displayMessage = Strings.STATUS_BOWER_READY;

                        packageListPromise.resolve();
                    })
                    .fail(function () {
                        displayMessage = Strings.STATUS_BOWER_NOT_LOADED;

                        packageListPromise.reject();
                    })
                    .always(function () {
                        status.hideQuickSearchSpinner();
                        status.showStatusInfo(displayMessage, false);
                        status.hideStatusInfo();

                        packageListPromise = null;
                    });
            }

            // Due to bugs in smart autocomplete, we have to return separate promises for each call
            // to _search, but make sure to only resolve the last one.
            var result = new $.Deferred();

            packageListPromise.done(function () {
                // validate for an empty string avoids an exception in smart autocomplete
                if (query === latestQuery && query.trim() !== "") {
                    result.resolve(_search(latestQuery, matcher));
                } else {
                    result.reject();
                }
            });

            return result.promise();
        }

        // Filter and rank how good each match is
        var filteredList = $.map(packages, function (pkg) {
            var searchResult = matcher.match(pkg.name, query);

            if (searchResult) {
                searchResult.pkg = pkg;
            }
            return searchResult;
        });

        // Sort based on ranking & basic alphabetical order
        StringMatch.basicMatchSort(filteredList);

        return filteredList;
    }

    function _itemSelect(result) {
        if (result) {
            _addToQueue(result.pkg.name);
        }
    }

    function init(domainPath) {
        QuickOpen.addQuickOpenPlugin({
            name: "installFromBower",
            languageIds: [],
            search: _search,
            match: _match,
            itemSelect: _itemSelect,
            label: Strings.TITLE_QUICK_OPEN
        });
    }

    exports.init           = init;
    exports.quickOpenBower = quickOpenBower;
});
<|endoftext|>


<commit_before>/*
 * React FitText v0.0.3
 * https://github.com/gianu/react-fittext
 *
 * A port of the jQuery plugin: http://github.com/davatron5000/FitText.js
 *
 * Copyright 2014, Sergio Rafael Gianazza http://softwarepsychonaut.com
 *
 * Released under the MIT license
 * http://gianu.mit-license.org
 */
'use strict';

var React = require('react');
var ReactPropTypes = React.PropTypes;

module.exports = React.createClass({
  displayName: 'ReactFitText',

  propTypes: {
    compressor: ReactPropTypes.number,
    minFontSize: ReactPropTypes.number,
    maxFontSize: ReactPropTypes.number
  },

  getDefaultProps: function() {
    return {
      compressor: 1.0,
      minFontSize: Number.NEGATIVE_INFINITY,
      maxFontSize: Number.POSITIVE_INFINITY
    };
  },

  componentDidMount: function() {
    window.addEventListener("resize", this._onBodyResize);
    this._onBodyResize();
  },

  _onBodyResize: function() {
    var element = this.getDOMNode();
    var width = element.offsetWidth;
    var fontSize = Math.max(Math.min((width / (this.props.compressor*10)), parseFloat(this.props.maxFontSize)), parseFloat(this.props.minFontSize)) + 'px';
    element.style.fontSize = fontSize;
  },

  render: function() {
    return this.props.children;
  }
});
<commit_msg>Remove listener on unmount<commit_after>/*
 * React FitText v0.0.3
 * https://github.com/gianu/react-fittext
 *
 * A port of the jQuery plugin: http://github.com/davatron5000/FitText.js
 *
 * Copyright 2014, Sergio Rafael Gianazza http://softwarepsychonaut.com
 *
 * Released under the MIT license
 * http://gianu.mit-license.org
 */
'use strict';

var React = require('react');
var ReactPropTypes = React.PropTypes;

module.exports = React.createClass({
  displayName: 'ReactFitText',

  propTypes: {
    compressor: ReactPropTypes.number,
    minFontSize: ReactPropTypes.number,
    maxFontSize: ReactPropTypes.number
  },

  getDefaultProps: function() {
    return {
      compressor: 1.0,
      minFontSize: Number.NEGATIVE_INFINITY,
      maxFontSize: Number.POSITIVE_INFINITY
    };
  },

  componentDidMount: function() {
    window.addEventListener("resize", this._onBodyResize);
    this._onBodyResize();
  },

  componentWillUnmount: function() {
    window.removeEventListener("resize", this._onBodyResize);
  },

  _onBodyResize: function() {
    var element = this.getDOMNode();
    var width = element.offsetWidth;
    var fontSize = Math.max(Math.min((width / (this.props.compressor*10)), parseFloat(this.props.maxFontSize)), parseFloat(this.props.minFontSize)) + 'px';
    element.style.fontSize = fontSize;
  },

  render: function() {
    return this.props.children;
  }
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Router from 'react-router-dom/Router';
import Route from 'react-router-dom/Route';
import Switch from 'react-router-dom/Switch';
import { Provider } from 'react-redux';
import { CookiesProvider } from 'react-cookie';
import { HotKeys } from '@folio/stripes-components/lib/HotKeys';
import { intlShape } from 'react-intl';

import MainContainer from './components/MainContainer';
import MainNav from './components/MainNav';
import ModuleContainer from './components/ModuleContainer';
import Front from './components/Front';
import About from './components/About';
import SSOLanding from './components/SSOLanding';
import Settings from './components/Settings/Settings';
import LoginCtrl from './components/Login';
import getModuleRoutes from './moduleRoutes';
import { stripesShape } from './Stripes';

class RootWithIntl extends Component {
  static contextTypes = {
    intl: intlShape.isRequired,
  };
  static propTypes = {
    stripes: stripesShape.isRequired,
    token: PropTypes.string,
    disableAuth: PropTypes.bool.isRequired,
    history: PropTypes.shape({}),
  };

  render() {
    const intl = this.context.intl;
    const stripes = this.props.stripes.clone({ intl });
    const { token, disableAuth, history } = this.props;

    return (
      <HotKeys keyMap={stripes.bindings} noWrapper>
        <Provider store={stripes.store}>
          <Router history={history}>
            { token || disableAuth ?
              <MainContainer>
                <MainNav stripes={stripes} />
                <ModuleContainer id="content">
                  <Switch>
                    <Route exact path="/" component={() => <Front stripes={stripes} />} key="root" />
                    <Route path="/sso-landing" component={() => <Front stripes={stripes} />} key="sso-landing" />
                    <Route path="/about" component={() => <About stripes={stripes} />} key="about" />
                    <Route path="/settings" render={() => <Settings stripes={stripes} />} />
                    {getModuleRoutes(stripes)}
                    <Route
                      component={() =>

Uh-oh!

This route does not exist.

}
                    />
                  </Switch>
                </ModuleContainer>
              </MainContainer> :
              <Switch>
                <Route exact path="/sso-landing" component={() => <CookiesProvider><SSOLanding stripes={stripes} /></CookiesProvider>} key="sso-landing" />
                <Route component={() => <LoginCtrl autoLogin={stripes.config.autoLogin} />} />
              </Switch>
            }
          </Router>
        </Provider>
      </HotKeys>
    );
  }
}

export default RootWithIntl;
<commit_msg>Switch to functional form. Last part of STCOR-52<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import Router from 'react-router-dom/Router';
import Route from 'react-router-dom/Route';
import Switch from 'react-router-dom/Switch';
import { Provider } from 'react-redux';
import { CookiesProvider } from 'react-cookie';
import { HotKeys } from '@folio/stripes-components/lib/HotKeys';
import { intlShape } from 'react-intl';

import MainContainer from './components/MainContainer';
import MainNav from './components/MainNav';
import ModuleContainer from './components/ModuleContainer';
import Front from './components/Front';
import About from './components/About';
import SSOLanding from './components/SSOLanding';
import Settings from './components/Settings/Settings';
import LoginCtrl from './components/Login';
import getModuleRoutes from './moduleRoutes';
import { stripesShape } from './Stripes';

const RootWithIntl = (props, context) => {
  const intl = context.intl;
  const stripes = props.stripes.clone({ intl });
  const { token, disableAuth, history } = props;

  return (
    <HotKeys keyMap={stripes.bindings} noWrapper>
      <Provider store={stripes.store}>
        <Router history={history}>
          { token || disableAuth ?
            <MainContainer>
              <MainNav stripes={stripes} />
              <ModuleContainer id="content">
                <Switch>
                  <Route exact path="/" component={() => <Front stripes={stripes} />} key="root" />
                  <Route path="/sso-landing" component={() => <Front stripes={stripes} />} key="sso-landing" />
                  <Route path="/about" component={() => <About stripes={stripes} />} key="about" />
                  <Route path="/settings" render={() => <Settings stripes={stripes} />} />
                  {getModuleRoutes(stripes)}
                  <Route
                    component={() =>

Uh-oh!

This route does not exist.

}
                  />
                </Switch>
              </ModuleContainer>
            </MainContainer> :
            <Switch>
              <Route exact path="/sso-landing" component={() => <CookiesProvider><SSOLanding stripes={stripes} /></CookiesProvider>} key="sso-landing" />
              <Route component={() => <LoginCtrl autoLogin={stripes.config.autoLogin} />} />
            </Switch>
          }
        </Router>
      </Provider>
    </HotKeys>
  );
};

RootWithIntl.contextTypes = {
  intl: intlShape.isRequired,
};

RootWithIntl.propTypes = {
  stripes: stripesShape.isRequired,
  token: PropTypes.string,
  disableAuth: PropTypes.bool.isRequired,
  history: PropTypes.shape({}),
};

export default RootWithIntl;
<|endoftext|>


<commit_before>define([
	'esri/units',
	'esri/geometry/Extent',
	'esri/config',
	'esri/tasks/GeometryService',
	'esri/layers/ImageParameters'
], function(units, Extent, esriConfig, GeometryService, ImageParameters) {

	// url to your proxy page, must be on same machine hosting you app. See proxy folder for readme.
	esriConfig.defaults.io.proxyUrl = 'proxy/proxy.ashx';
	esriConfig.defaults.io.alwaysUseProxy = false;
	// url to your geometry server.
	esriConfig.defaults.geometryService = new GeometryService('http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer');

	//image parameters for dynamic services, set to png32 for higher quality exports.
	var imageParameters = new ImageParameters();
	imageParameters.format = 'png32';

	return {
		//default mapClick mode, mapClickMode lets widgets know what mode the map is in to avoid multipult map click actions from taking place (ie identify while drawing).
		defaultMapClickMode: 'identify',
		// map options, passed to map constructor. see: https://developers.arcgis.com/javascript/jsapi/map-amd.html#map1
		mapOptions: {
			basemap: 'streets',
			center: [-96.59179687497497, 39.09596293629694],
			zoom: 5,
			sliderStyle: 'small'
		},
		// panes: {
		// 	left: {
		// 		splitter: true
		// 	},
		// 	right: {
		// 		id: 'sidebarRight',
		// 		placeAt: 'outer',
		// 		region: 'right',
		// 		splitter: true,
		// 		collapsible: true
		// 	},
		// 	bottom: {
		// 		id: 'sidebarBottom',
		// 		placeAt: 'outer',
		// 		splitter: true,
		// 		collapsible: true,
		// 		region: 'bottom'
		// 	},
		// 	top: {
		// 		id: 'sidebarTop',
		// 		placeAt: 'outer',
		// 		collapsible: true,
		// 		splitter: true,
		// 		region: 'top'
		// 	}
		// },
		// collapseButtonsPane: 'center', //center or outer

		// operationalLayers: Array of Layers to load on top of the basemap: valid 'type' options: 'dynamic', 'tiled', 'feature'.
		// The 'options' object is passed as the layers options for constructor. Title will be used in the legend only. id's must be unique and have no spaces.
		// 3 'mode' options: MODE_SNAPSHOT = 0, MODE_ONDEMAND = 1, MODE_SELECTION = 2
		operationalLayers: [{
			type: 'feature',
			url: 'http://services1.arcgis.com/g2TonOxuRkIqSOFx/arcgis/rest/services/MeetUpHomeTowns/FeatureServer/0',
			title: 'STLJS Meetup Home Towns',
			options: {
				id: 'meetupHometowns',
				opacity: 1.0,
				visible: true,
				outFields: ['*'],
				mode: 0
			},
			editorLayerInfos: {
				disableGeometryUpdate: false
			}
		}, {
			type: 'feature',
			url: 'http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0',
			title: 'San Francisco 311 Incidents',
			options: {
				id: 'sf311Incidents',
				opacity: 1.0,
				visible: true,
				outFields: ['req_type', 'req_date', 'req_time', 'address', 'district'],
				mode: 0
			}
		}, {
			type: 'dynamic',
			url: 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyOperationalLayers/MapServer',
			title: 'Louisville Public Safety',
			slider: true,
			noLegend: false,
			collapsed: false,
			sublayerToggle: false, //true to automatically turn on sublayers
			options: {
				id: 'louisvillePubSafety',
				opacity: 1.0,
				visible: true,
				imageParameters: imageParameters
			},
			identifyLayerInfos: {
				layerIds: [2, 4, 5, 8, 12, 21]
			}
		}, {
			type: 'dynamic',
			url: 'http://sampleserver6.arcgisonline.com/arcgis/rest/services/DamageAssessment/MapServer',
			title: 'Damage Assessment',
			slider: true,
			noLegend: false,
			collapsed: false,
			options: {
				id: 'DamageAssessment',
				opacity: 1.0,
				visible: true,
				imageParameters: imageParameters
			}
		}],
		// set include:true to load. For titlePane type set position the the desired order in the sidebar
		widgets: {
			growler: {
				include: true,
				id: 'growler',
				type: 'domNode',
				path: 'gis/dijit/Growler',
				srcNodeRef: 'growlerDijit',
				options: {}
			},
			geocoder: {
				include: true,
				id: 'geocoder',
				type: 'domNode',
				path: 'gis/dijit/Geocoder',
				srcNodeRef: 'geocodeDijit',
				options: {
					map: true,
					mapRightClickMenu: true,
					geocoderOptions: {
						autoComplete: true,
						arcgisGeocoder: {
							placeholder: 'Enter an address or place'
						}
					}
				}
			},
			identify: {
				include: true,
				id: 'identify',
				type: 'titlePane',
				path: 'gis/dijit/Identify',
				title: 'Identify',
				open: false,
				position: 3,
				options: 'config/identify'
			},
			basemaps: {
				include: true,
				id: 'basemaps',
				type: 'domNode',
				path: 'gis/dijit/Basemaps',
				srcNodeRef: 'basemapsDijit',
				options: 'config/basemaps'
			},
			mapInfo: {
				include: false,
				id: 'mapInfo',
				type: 'domNode',
				path: 'gis/dijit/MapInfo',
				srcNodeRef: 'mapInfoDijit',
				options: {
					map: true,
					mode: 'dms',
					firstCoord: 'y',
					unitScale: 3,
					showScale: true,
					xLabel: '',
					yLabel: '',
					minWidth: 286
				}
			},
			scalebar: {
				include: true,
				id: 'scalebar',
				type: 'map',
				path: 'esri/dijit/Scalebar',
				options: {
					map: true,
					attachTo: 'bottom-left',
					scalebarStyle: 'line',
					scalebarUnit: 'dual'
				}
			},
			locateButton: {
				include: true,
				id: 'locateButton',
				type: 'domNode',
				path: 'gis/dijit/LocateButton',
				srcNodeRef: 'locateButton',
				options: {
					map: true,
					publishGPSPosition: true,
					highlightLocation: true,
					useTracking: true,
					geolocationOptions: {
						maximumAge: 0,
						timeout: 15000,
						enableHighAccuracy: true
					}
				}
			},
			overviewMap: {
				include: true,
				id: 'overviewMap',
				type: 'map',
				path: 'esri/dijit/OverviewMap',
				options: {
					map: true,
					attachTo: 'bottom-right',
					color: '#0000CC',
					height: 100,
					width: 125,
					opacity: 0.30,
					visible: false
				}
			},
			homeButton: {
				include: true,
				id: 'homeButton',
				type: 'domNode',
				path: 'esri/dijit/HomeButton',
				srcNodeRef: 'homeButton',
				options: {
					map: true,
					extent: new Extent({
						xmin: -180,
						ymin: -85,
						xmax: 180,
						ymax: 85,
						spatialReference: {
							wkid: 4326
						}
					})
				}
			},
			legend: {
				include: true,
				id: 'legend',
				type: 'titlePane',
				path: 'esri/dijit/Legend',
				title: 'Legend',
				open: false,
				position: 0,
				options: {
					map: true,
					legendLayerInfos: true
				}
			},
			TOC: {
				include: true,
				id: 'toc',
				type: 'titlePane',
				path: 'gis/dijit/TOC',
				title: 'Layers',
				open: false,
				position: 1,
				options: {
					map: true,
					tocLayerInfos: true
				}
			},
			bookmarks: {
				include: true,
				id: 'bookmarks',
				type: 'titlePane',
				path: 'gis/dijit/Bookmarks',
				title: 'Bookmarks',
				open: false,
				position: 2,
				options: 'config/bookmarks'
			},
			find: {
				include: true,
				id: 'find',
				type: 'titlePane',
				canFloat: true,
				path: 'gis/dijit/Find',
				title: 'Find',
				open: false,
				position: 3,
				options: 'config/find'
			},
			draw: {
				include: true,
				id: 'draw',
				type: 'titlePane',
				canFloat: true,
				path: 'gis/dijit/Draw',
				title: 'Draw',
				open: false,
				position: 4,
				options: {
					map: true,
					mapClickMode: true
				}
			},
			measure: {
				include: true,
				id: 'measurement',
				type: 'titlePane',
				canFloat: true,
				path: 'gis/dijit/Measurement',
				title: 'Measurement',
				open: false,
				position: 5,
				options: {
					map: true,
					mapClickMode: true,
					defaultAreaUnit: units.SQUARE_MILES,
					defaultLengthUnit: units.MILES
				}
			},
			print: {
				include: true,
				id: 'print',
				type: 'titlePane',
				canFloat: true,
				path: 'gis/dijit/Print',
				title: 'Print',
				open: false,
				position: 6,
				options: {
					map: true,
					printTaskURL: 'http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task',
					copyrightText: 'Copyright 2014',
					authorText: 'Me',
					defaultTitle: 'Viewer Map',
					defaultFormat: 'PDF',
					defaultLayout: 'Letter ANSI A Landscape'
				}
			},
			directions: {
				include: true,
				id: 'directions',
				type: 'titlePane',
				path: 'gis/dijit/Directions',
				title: 'Directions',
				open: false,
				position: 7,
				options: {
					map: true,
					mapRightClickMenu: true,
					options: {
						routeTaskUrl: 'http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Network/USA/NAServer/Route',
						routeParams: {
							directionsLanguage: 'en-US',
							directionsLengthUnits: units.MILES
						}
					}
				}
			},
			editor: {
				include: true,
				id: 'editor',
				type: 'titlePane',
				path: 'gis/dijit/Editor',
				title: 'Editor',
				open: false,
				position: 8,
				options: {
					map: true,
					mapClickMode: true,
					editorLayerInfos: true,
					settings: {
						toolbarVisible: true,
						showAttributesOnClick: true,
						enableUndoRedo: true,
						createOptions: {
							polygonDrawTools: ['freehandpolygon', 'autocomplete']
						},
						toolbarOptions: {
							reshapeVisible: true,
							cutVisible: true,
							mergeVisible: true
						}
					}
				}
			},
			streetview: {
				include: true,
				id: 'streetview',
				type: 'titlePane',
				canFloat: true,
				position: 9,
				path: 'gis/dijit/StreetView',
				title: 'Google Street View',
				options: {
					map: true,
					mapClickMode: true,
					openOnStartup: true,
					mapRightClickMenu: true
				}
			},
			help: {
				include: true,
				id: 'help',
				type: 'floating',
				path: 'gis/dijit/Help',
				title: 'Help',
				options: {}
			}

		}
	};
});<commit_msg>Pointed print widget at prod arcgis online print service.<commit_after>define([
	'esri/units',
	'esri/geometry/Extent',
	'esri/config',
	'esri/tasks/GeometryService',
	'esri/layers/ImageParameters'
], function(units, Extent, esriConfig, GeometryService, ImageParameters) {

	// url to your proxy page, must be on same machine hosting you app. See proxy folder for readme.
	esriConfig.defaults.io.proxyUrl = 'proxy/proxy.ashx';
	esriConfig.defaults.io.alwaysUseProxy = false;
	// url to your geometry server.
	esriConfig.defaults.geometryService = new GeometryService('http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer');

	//image parameters for dynamic services, set to png32 for higher quality exports.
	var imageParameters = new ImageParameters();
	imageParameters.format = 'png32';

	return {
		//default mapClick mode, mapClickMode lets widgets know what mode the map is in to avoid multipult map click actions from taking place (ie identify while drawing).
		defaultMapClickMode: 'identify',
		// map options, passed to map constructor. see: https://developers.arcgis.com/javascript/jsapi/map-amd.html#map1
		mapOptions: {
			basemap: 'streets',
			center: [-96.59179687497497, 39.09596293629694],
			zoom: 5,
			sliderStyle: 'small'
		},
		// panes: {
		// 	left: {
		// 		splitter: true
		// 	},
		// 	right: {
		// 		id: 'sidebarRight',
		// 		placeAt: 'outer',
		// 		region: 'right',
		// 		splitter: true,
		// 		collapsible: true
		// 	},
		// 	bottom: {
		// 		id: 'sidebarBottom',
		// 		placeAt: 'outer',
		// 		splitter: true,
		// 		collapsible: true,
		// 		region: 'bottom'
		// 	},
		// 	top: {
		// 		id: 'sidebarTop',
		// 		placeAt: 'outer',
		// 		collapsible: true,
		// 		splitter: true,
		// 		region: 'top'
		// 	}
		// },
		// collapseButtonsPane: 'center', //center or outer

		// operationalLayers: Array of Layers to load on top of the basemap: valid 'type' options: 'dynamic', 'tiled', 'feature'.
		// The 'options' object is passed as the layers options for constructor. Title will be used in the legend only. id's must be unique and have no spaces.
		// 3 'mode' options: MODE_SNAPSHOT = 0, MODE_ONDEMAND = 1, MODE_SELECTION = 2
		operationalLayers: [{
			type: 'feature',
			url: 'http://services1.arcgis.com/g2TonOxuRkIqSOFx/arcgis/rest/services/MeetUpHomeTowns/FeatureServer/0',
			title: 'STLJS Meetup Home Towns',
			options: {
				id: 'meetupHometowns',
				opacity: 1.0,
				visible: true,
				outFields: ['*'],
				mode: 0
			},
			editorLayerInfos: {
				disableGeometryUpdate: false
			}
		}, {
			type: 'feature',
			url: 'http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0',
			title: 'San Francisco 311 Incidents',
			options: {
				id: 'sf311Incidents',
				opacity: 1.0,
				visible: true,
				outFields: ['req_type', 'req_date', 'req_time', 'address', 'district'],
				mode: 0
			}
		}, {
			type: 'dynamic',
			url: 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyOperationalLayers/MapServer',
			title: 'Louisville Public Safety',
			slider: true,
			noLegend: false,
			collapsed: false,
			sublayerToggle: false, //true to automatically turn on sublayers
			options: {
				id: 'louisvillePubSafety',
				opacity: 1.0,
				visible: true,
				imageParameters: imageParameters
			},
			identifyLayerInfos: {
				layerIds: [2, 4, 5, 8, 12, 21]
			}
		}, {
			type: 'dynamic',
			url: 'http://sampleserver6.arcgisonline.com/arcgis/rest/services/DamageAssessment/MapServer',
			title: 'Damage Assessment',
			slider: true,
			noLegend: false,
			collapsed: false,
			options: {
				id: 'DamageAssessment',
				opacity: 1.0,
				visible: true,
				imageParameters: imageParameters
			}
		}],
		// set include:true to load. For titlePane type set position the the desired order in the sidebar
		widgets: {
			growler: {
				include: true,
				id: 'growler',
				type: 'domNode',
				path: 'gis/dijit/Growler',
				srcNodeRef: 'growlerDijit',
				options: {}
			},
			geocoder: {
				include: true,
				id: 'geocoder',
				type: 'domNode',
				path: 'gis/dijit/Geocoder',
				srcNodeRef: 'geocodeDijit',
				options: {
					map: true,
					mapRightClickMenu: true,
					geocoderOptions: {
						autoComplete: true,
						arcgisGeocoder: {
							placeholder: 'Enter an address or place'
						}
					}
				}
			},
			identify: {
				include: true,
				id: 'identify',
				type: 'titlePane',
				path: 'gis/dijit/Identify',
				title: 'Identify',
				open: false,
				position: 3,
				options: 'config/identify'
			},
			basemaps: {
				include: true,
				id: 'basemaps',
				type: 'domNode',
				path: 'gis/dijit/Basemaps',
				srcNodeRef: 'basemapsDijit',
				options: 'config/basemaps'
			},
			mapInfo: {
				include: false,
				id: 'mapInfo',
				type: 'domNode',
				path: 'gis/dijit/MapInfo',
				srcNodeRef: 'mapInfoDijit',
				options: {
					map: true,
					mode: 'dms',
					firstCoord: 'y',
					unitScale: 3,
					showScale: true,
					xLabel: '',
					yLabel: '',
					minWidth: 286
				}
			},
			scalebar: {
				include: true,
				id: 'scalebar',
				type: 'map',
				path: 'esri/dijit/Scalebar',
				options: {
					map: true,
					attachTo: 'bottom-left',
					scalebarStyle: 'line',
					scalebarUnit: 'dual'
				}
			},
			locateButton: {
				include: true,
				id: 'locateButton',
				type: 'domNode',
				path: 'gis/dijit/LocateButton',
				srcNodeRef: 'locateButton',
				options: {
					map: true,
					publishGPSPosition: true,
					highlightLocation: true,
					useTracking: true,
					geolocationOptions: {
						maximumAge: 0,
						timeout: 15000,
						enableHighAccuracy: true
					}
				}
			},
			overviewMap: {
				include: true,
				id: 'overviewMap',
				type: 'map',
				path: 'esri/dijit/OverviewMap',
				options: {
					map: true,
					attachTo: 'bottom-right',
					color: '#0000CC',
					height: 100,
					width: 125,
					opacity: 0.30,
					visible: false
				}
			},
			homeButton: {
				include: true,
				id: 'homeButton',
				type: 'domNode',
				path: 'esri/dijit/HomeButton',
				srcNodeRef: 'homeButton',
				options: {
					map: true,
					extent: new Extent({
						xmin: -180,
						ymin: -85,
						xmax: 180,
						ymax: 85,
						spatialReference: {
							wkid: 4326
						}
					})
				}
			},
			legend: {
				include: true,
				id: 'legend',
				type: 'titlePane',
				path: 'esri/dijit/Legend',
				title: 'Legend',
				open: false,
				position: 0,
				options: {
					map: true,
					legendLayerInfos: true
				}
			},
			TOC: {
				include: true,
				id: 'toc',
				type: 'titlePane',
				path: 'gis/dijit/TOC',
				title: 'Layers',
				open: false,
				position: 1,
				options: {
					map: true,
					tocLayerInfos: true
				}
			},
			bookmarks: {
				include: true,
				id: 'bookmarks',
				type: 'titlePane',
				path: 'gis/dijit/Bookmarks',
				title: 'Bookmarks',
				open: false,
				position: 2,
				options: 'config/bookmarks'
			},
			find: {
				include: true,
				id: 'find',
				type: 'titlePane',
				canFloat: true,
				path: 'gis/dijit/Find',
				title: 'Find',
				open: false,
				position: 3,
				options: 'config/find'
			},
			draw: {
				include: true,
				id: 'draw',
				type: 'titlePane',
				canFloat: true,
				path: 'gis/dijit/Draw',
				title: 'Draw',
				open: false,
				position: 4,
				options: {
					map: true,
					mapClickMode: true
				}
			},
			measure: {
				include: true,
				id: 'measurement',
				type: 'titlePane',
				canFloat: true,
				path: 'gis/dijit/Measurement',
				title: 'Measurement',
				open: false,
				position: 5,
				options: {
					map: true,
					mapClickMode: true,
					defaultAreaUnit: units.SQUARE_MILES,
					defaultLengthUnit: units.MILES
				}
			},
			print: {
				include: true,
				id: 'print',
				type: 'titlePane',
				canFloat: true,
				path: 'gis/dijit/Print',
				title: 'Print',
				open: false,
				position: 6,
				options: {
					map: true,
					printTaskURL: 'https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task',
					copyrightText: 'Copyright 2014',
					authorText: 'Me',
					defaultTitle: 'Viewer Map',
					defaultFormat: 'PDF',
					defaultLayout: 'Letter ANSI A Landscape'
				}
			},
			directions: {
				include: true,
				id: 'directions',
				type: 'titlePane',
				path: 'gis/dijit/Directions',
				title: 'Directions',
				open: false,
				position: 7,
				options: {
					map: true,
					mapRightClickMenu: true,
					options: {
						routeTaskUrl: 'http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Network/USA/NAServer/Route',
						routeParams: {
							directionsLanguage: 'en-US',
							directionsLengthUnits: units.MILES
						}
					}
				}
			},
			editor: {
				include: true,
				id: 'editor',
				type: 'titlePane',
				path: 'gis/dijit/Editor',
				title: 'Editor',
				open: false,
				position: 8,
				options: {
					map: true,
					mapClickMode: true,
					editorLayerInfos: true,
					settings: {
						toolbarVisible: true,
						showAttributesOnClick: true,
						enableUndoRedo: true,
						createOptions: {
							polygonDrawTools: ['freehandpolygon', 'autocomplete']
						},
						toolbarOptions: {
							reshapeVisible: true,
							cutVisible: true,
							mergeVisible: true
						}
					}
				}
			},
			streetview: {
				include: true,
				id: 'streetview',
				type: 'titlePane',
				canFloat: true,
				position: 9,
				path: 'gis/dijit/StreetView',
				title: 'Google Street View',
				options: {
					map: true,
					mapClickMode: true,
					openOnStartup: true,
					mapRightClickMenu: true
				}
			},
			help: {
				include: true,
				id: 'help',
				type: 'floating',
				path: 'gis/dijit/Help',
				title: 'Help',
				options: {}
			}

		}
	};
});<|endoftext|>