<commit_before>/***
 * Copyright (c) 2015, 2016 Alex Grant (@localnerve), LocalNerve LLC
 * Copyrights licensed under the BSD License. See the accompanying LICENSE file for terms.
 *
 * A simple mock for sw-toolbox.
 *
 * Intended for use via mockery (or equiv) as a configurable drop-in that loads
 * in-place of sw-toolbox so modules that use it can be tested in NodeJS unit
 * tests.
 *
 * Assumes NodeJS >= 4 (stable)
 *
 * After the mock substitution is setup, the test must also get a reference
 * to the mock (and prime the require cache) to call mockSetup. mockSetup must
 * be called at least once to create the sw-toolbox interface.
 * @see mockSetup
 *
 * Reuses sw-toolbox/lib/options, sw-toolbox/lib/router as-is.
 */
/* global Promise */
'use strict';

var urlLib = require('url');

var teardown = {
  self: false,
  url: false
};

var cleanOptions;
var mockCacheObject;
var mockCacheValue = 'dummy';

/**
 * A mock strategy to reject or resolve.
 *
 * @param {Object} response - A response to resolve to, must pre-bind.
 * @param {Any} request - ignored.
 * @param {Any} values - ignored.
 * @param {Object} options - The sw-toolbox options passed to strategy.
 * @param {Boolean} [options.emulateError] - Set to test reject path.
 */
function mockStrategy (response, request, values, options) {
  if (options.emulateError) {
    return Promise.reject(new Error('mock error'));
  }
  return Promise.resolve(response);
}

/**
 * Mock cache implementation.
 *
 * @param {String|Request} request - The item to cache.
 * @returns {Promise} Always resolves to undefined.
 */
function mockCache (request) {
  var urlString = typeof request === 'string' ? request : request.url;

  mockCacheObject[urlString] = mockCacheValue;

  return Promise.resolve();
}

/**
 * Mock uncache implementation.
 *
 * @param {String|Request} request - The item to delete from cache.
 * @returns {Promise} Resolves to true if the item was deleted, false otherwise.
 */
function mockUncache (request) {
  var urlString = typeof request === 'string' ? request : request.url;

  var hit = mockCacheObject[urlString] === mockCacheValue;

  if (hit) {
    delete mockCacheObject[urlString];
  }

  return Promise.resolve(hit);
}

/**
 * Simplified mock URL constructor for global mock purpose.
 *
 * @param {String} urlString - An absolute or relative url.
 * @param {String|Object} [base] - if urlString is relative, a string or url
 * object to resolve the urlString on.
 */
function MockURL (urlString, base) {
  var baseUrlString;

  if (!base || urlString.indexOf(':') !== -1) {
    baseUrlString = urlString;
    urlString = '';
  } else {
    baseUrlString = typeof base === 'string' ? base : base.href;
  }

  this.href = urlLib.resolve(baseUrlString, urlString);

  var urlObj = urlLib.parse(this.href, true, this.href.indexOf(':') === -1);

  this.pathname = urlObj.pathname;
  this.port = urlObj.port;
  this.protocol = urlObj.protocol || 'http:';
  this.hash = urlObj.hash;
  this.origin =
    this.protocol + (urlObj.slashes ? '//' : '') + urlObj.host;
}

/**
 * Setup global prerequisites for the re-used modules of sw-toolbox.
 *
 * @param {String} scope - The scope for sw-toolbox.
 */
function setupGlobals (scope) {
  // This is required to re-use sw-toolbox/lib/options
  global.self = global.self || (teardown.self = true, {});
  global.self.scope = scope || global.self.scope || 'http://localhost';

  // This is required to re-use sw-toolbox/lib/router
  global.URL = global.URL || (teardown.url = true, MockURL);
  global.self.location = global.self.location ||
    new global.URL('/', global.self.scope);
}

module.exports = {
  /**
   * Call to setup and configure the sw-toolbox mock interface.
   * MUST be called at least once to create the sw-toolbox mock interface.
   * Can be called repeatedly to change handler responses, scope, or options.
   *
   * @param {Object} [response] - The response any strategies will resolve to.
   * Actually can be any type/value of use to the test.
   * @param {String} [scope] - A scope to use for sw-toolbox purposes. defaults
   * to 'http://localhost'.
   * @param {Object} [options] - options to substitute in sw-toolbox options.
   */
  mockSetup: function mockSetup (response, scope, options) {
    setupGlobals(scope);

    // First time only, keep a clean copy of the global, mutable options.
    if (!cleanOptions) {
      cleanOptions = Object.assign({}, require('sw-toolbox/lib/options'));
    }

    // Reset the global toolbox options, mixin changes, expose the result
    var dirtyOptions = require('sw-toolbox/lib/options');
    options = Object.assign(
      Object.assign(dirtyOptions, cleanOptions), options || {}
    );

    // Clear the route map
    var router = require('sw-toolbox/lib/router');
    router.routes.clear();

    // Clear/create the mockCache
    mockCacheObject = Object.create(null);

    // Mock the sw-toolbox interface
    this.cacheFirst =
    this.cacheOnly =
    this.networkFirst =
    this.networkOnly =
    this.fastest =
      mockStrategy.bind(this, response);
    this.router = router;
    this.options = options;
    this.cache = mockCache;
    this.uncache = mockUncache;
    // Can't use orig b/c we can't load sw-toolbox main w/o mocking its deps.
    this.precache = function (items) {
      if (!Array.isArray(items)) {
        items = [items];
      }
      this.options.preCacheItems = this.options.preCacheItems.concat(items);
    };
  },

  /**
   * Cleanup globals created during setup (optional).
   */
  mockTeardown: function mockTeardown () {
    if (teardown.self) {
      delete global.self;
    }
    if (teardown.url) {
      delete global.URL;
    }
  },

  /**
   * Fetch driver. Must call mockSetup first.
   *
   * @param {String|Request} url - The url to use to drive a test.
   * @param {String} [method] - if url is a string, supply this method.
   * Defaults to 'any'.
   * @returns {Promise} resolves or rejects as configured. If no handler is
   * found, resolves to undefined.
   */
  mockFetch: function mockFetch (url, method) {
    if (!this.router) {
      throw new Error('Must call mockSetup before mockFetch');
    }

    var request = typeof url === 'string' ? {
      url: url,
      method: method || 'any'
    } : url;

    var response, handler = this.router.match(request);

    if (handler) {
      response = handler(request);
    } else if (this.router.default && request.method === 'GET') {
      response = this.router.default(request);
    }

    return response || Promise.resolve();
  }
};
<commit_msg>save teardown state<commit_after>/***
 * Copyright (c) 2015, 2016 Alex Grant (@localnerve), LocalNerve LLC
 * Copyrights licensed under the BSD License. See the accompanying LICENSE file for terms.
 *
 * A simple mock for sw-toolbox.
 *
 * Intended for use via mockery (or equiv) as a configurable drop-in that loads
 * in-place of sw-toolbox so modules that use it can be tested in NodeJS unit
 * tests.
 *
 * Assumes NodeJS >= 4 (stable)
 *
 * After the mock substitution is setup, the test must also get a reference
 * to the mock (and prime the require cache) to call mockSetup. mockSetup must
 * be called at least once to create the sw-toolbox interface.
 * @see mockSetup
 *
 * Reuses sw-toolbox/lib/options, sw-toolbox/lib/router as-is.
 */
/* global Promise */
'use strict';

var urlLib = require('url');

var teardown = {
  self: false,
  url: false
};

var cleanOptions;
var mockCacheObject;
var mockCacheValue = 'dummy';

/**
 * A mock strategy to reject or resolve.
 *
 * @param {Object} response - A response to resolve to, must pre-bind.
 * @param {Any} request - ignored.
 * @param {Any} values - ignored.
 * @param {Object} options - The sw-toolbox options passed to strategy.
 * @param {Boolean} [options.emulateError] - Set to test reject path.
 */
function mockStrategy (response, request, values, options) {
  if (options.emulateError) {
    return Promise.reject(new Error('mock error'));
  }
  return Promise.resolve(response);
}

/**
 * Mock cache implementation.
 *
 * @param {String|Request} request - The item to cache.
 * @returns {Promise} Always resolves to undefined.
 */
function mockCache (request) {
  var urlString = typeof request === 'string' ? request : request.url;

  mockCacheObject[urlString] = mockCacheValue;

  return Promise.resolve();
}

/**
 * Mock uncache implementation.
 *
 * @param {String|Request} request - The item to delete from cache.
 * @returns {Promise} Resolves to true if the item was deleted, false otherwise.
 */
function mockUncache (request) {
  var urlString = typeof request === 'string' ? request : request.url;

  var hit = mockCacheObject[urlString] === mockCacheValue;

  if (hit) {
    delete mockCacheObject[urlString];
  }

  return Promise.resolve(hit);
}

/**
 * Simplified mock URL constructor for global mock purpose.
 *
 * @param {String} urlString - An absolute or relative url.
 * @param {String|Object} [base] - if urlString is relative, a string or url
 * object to resolve the urlString on.
 */
function MockURL (urlString, base) {
  var baseUrlString;

  if (!base || urlString.indexOf(':') !== -1) {
    baseUrlString = urlString;
    urlString = '';
  } else {
    baseUrlString = typeof base === 'string' ? base : base.href;
  }

  this.href = urlLib.resolve(baseUrlString, urlString);

  var urlObj = urlLib.parse(this.href, true, this.href.indexOf(':') === -1);

  this.pathname = urlObj.pathname;
  this.port = urlObj.port;
  this.protocol = urlObj.protocol || 'http:';
  this.hash = urlObj.hash;
  this.origin =
    this.protocol + (urlObj.slashes ? '//' : '') + urlObj.host;
}

/**
 * Setup global prerequisites for the re-used modules of sw-toolbox.
 *
 * @param {String} scope - The scope for sw-toolbox.
 */
function setupGlobals (scope) {
  // This is required to re-use sw-toolbox/lib/options
  global.self = global.self || (teardown.self = true, {});
  global.self.scope = scope || global.self.scope || 'http://localhost';

  // This is required to re-use sw-toolbox/lib/router
  global.URL = global.URL || (teardown.url = true, MockURL);
  global.self.location = global.self.location ||
    new global.URL('/', global.self.scope);
}

module.exports = {
  /**
   * Call to setup and configure the sw-toolbox mock interface.
   * MUST be called at least once to create the sw-toolbox mock interface.
   * Can be called repeatedly to change handler responses, scope, or options.
   *
   * @param {Object} [response] - The response any strategies will resolve to.
   * Actually can be any type/value of use to the test.
   * @param {String} [scope] - A scope to use for sw-toolbox purposes. defaults
   * to 'http://localhost'.
   * @param {Object} [options] - options to substitute in sw-toolbox options.
   */
  mockSetup: function mockSetup (response, scope, options) {
    setupGlobals(scope);

    // First time only, keep a clean copy of the global, mutable options.
    if (!cleanOptions) {
      cleanOptions = Object.assign({}, require('sw-toolbox/lib/options'));
    }

    // Reset the global toolbox options, mixin changes, expose the result
    var dirtyOptions = require('sw-toolbox/lib/options');
    options = Object.assign(
      Object.assign(dirtyOptions, cleanOptions), options || {}
    );

    // Clear the route map
    var router = require('sw-toolbox/lib/router');
    router.routes.clear();

    // Clear/create the mockCache
    mockCacheObject = Object.create(null);

    // Mock the sw-toolbox interface
    this.cacheFirst =
    this.cacheOnly =
    this.networkFirst =
    this.networkOnly =
    this.fastest =
      mockStrategy.bind(this, response);
    this.router = router;
    this.options = options;
    this.cache = mockCache;
    this.uncache = mockUncache;
    // Can't use orig b/c we can't load sw-toolbox main w/o mocking its deps.
    this.precache = function (items) {
      if (!Array.isArray(items)) {
        items = [items];
      }
      this.options.preCacheItems = this.options.preCacheItems.concat(items);
    };
  },

  /**
   * Cleanup globals created during setup (optional).
   */
  mockTeardown: function mockTeardown () {
    if (teardown.self) {
      teardown.self = false;
      delete global.self;
    }
    if (teardown.url) {
      teardown.url = false;
      delete global.URL;
    }
  },

  /**
   * Fetch driver. Must call mockSetup first.
   *
   * @param {String|Request} url - The url to use to drive a test.
   * @param {String} [method] - if url is a string, supply this method.
   * Defaults to 'any'.
   * @returns {Promise} resolves or rejects as configured. If no handler is
   * found, resolves to undefined.
   */
  mockFetch: function mockFetch (url, method) {
    if (!this.router) {
      throw new Error('Must call mockSetup before mockFetch');
    }

    var request = typeof url === 'string' ? {
      url: url,
      method: method || 'any'
    } : url;

    var response, handler = this.router.match(request);

    if (handler) {
      response = handler(request);
    } else if (this.router.default && request.method === 'GET') {
      response = this.router.default(request);
    }

    return response || Promise.resolve();
  }
};
<|endoftext|>


<commit_before>import SimpleSchema from 'simpl-schema';
import { getSetting } from '../modules/settings';

export const Strings = {};

export const Domains = {};

export const addStrings = (language, strings) => {
  if (typeof Strings[language] === 'undefined') {
    Strings[language] = {};
  }
  Strings[language] = {
    ...Strings[language],
    ...strings
  };
};

export const getString = ({id, values, defaultMessage, locale}) => {
  const messages = Strings[locale] || Strings[defaultLocale] || {};
  let message = messages[id] || defaultMessage;
  if (message && values) {
    Object.keys(values).forEach(key => {
      // note: see replaceAll definition in vulcan:lib/utils
      message = message.replaceAll(`{${key}}`, values[key]);
    });
  }
  return message;
};

export const registerDomain = (locale, domain) => {
  Domains[domain] = locale;
};

export const defaultLocale = getSetting('locale', 'en');

export const Locales = [];

export const registerLocale = locale => {
  Locales.push(locale);
};

/*

Look for type name in a few different places
Note: look into simplifying this

*/
export const isIntlField = fieldSchema => {
  return fieldSchema.intl;
};

/*

Generate custom IntlString SimpleSchema type

*/
export const getIntlString = () => {
  const schema = {
    locale: {
      type: String,
      optional: true
    },
    value: {
      type: String,
      optional: true
    }
  };

  const IntlString = new SimpleSchema(schema);
  IntlString.name = 'IntlString';
  return IntlString;
};

/*

Check if a schema has at least one intl field

*/
export const schemaHasIntlFields = schema => Object.keys(schema).some(fieldName => isIntlField(schema[fieldName]));

/*

Custom validation function to check for required locales

See https://github.com/aldeed/simple-schema-js#custom-field-validation

*/
export const validateIntlField = function() {
  let errors = [];

  // go through locales to check which one are required
  const requiredLocales = Locales.filter(locale => locale.required);

  requiredLocales.forEach((locale, index) => {
    const strings = this.value;
    const hasString = strings && Array.isArray(strings) && strings.some(s => s && s.locale === locale.id && s.value);
    if (!hasString) {
      const originalFieldName = this.key.replace('_intl', '');
      errors.push({
        id: 'errors.required',
        path: `${this.key}.${index}`,
        properties: { name: originalFieldName, locale: locale.id }
      });
    }
  });

  if (errors.length > 0) {
    // hack to work around the fact that custom validation function can only return a single string
    return `intlError|${JSON.stringify(errors)}`;
  }
};
<commit_msg>Add debug messages for missing strings.<commit_after>import SimpleSchema from 'simpl-schema';
import { getSetting } from '../modules/settings';
import { debug } from 'meteor/vulcan:lib';

export const Strings = {};

export const Domains = {};

export const addStrings = (language, strings) => {
  if (typeof Strings[language] === 'undefined') {
    Strings[language] = {};
  }
  Strings[language] = {
    ...Strings[language],
    ...strings
  };
};

export const getString = ({id, values, defaultMessage, locale}) => {
  const messages = Strings[locale] || {};
  let message = messages[id];

  // use default locale
  if(!message) {
    debug(`\x1b[32m>> INTL: No string found for id "${id}" in locale "${locale}".\x1b[0m`);
    message = Strings[defaultLocale] && Strings[defaultLocale][id];

    // if default locale hasn't got the message too
    if(!message && locale !== defaultLocale)
      debug(`\x1b[32m>> INTL: No string found for id "${id}" in the default locale ("${defaultLocale}").\x1b[0m`);
  }

  if (message && values) {
    Object.keys(values).forEach(key => {
      // note: see replaceAll definition in vulcan:lib/utils
      message = message.replaceAll(`{${key}}`, values[key]);
    });
  }
  return message;
};

export const registerDomain = (locale, domain) => {
  Domains[domain] = locale;
};

export const defaultLocale = getSetting('locale', 'en');

export const Locales = [];

export const registerLocale = locale => {
  Locales.push(locale);
};

/*

Look for type name in a few different places
Note: look into simplifying this

*/
export const isIntlField = fieldSchema => {
  return fieldSchema.intl;
};

/*

Generate custom IntlString SimpleSchema type

*/
export const getIntlString = () => {
  const schema = {
    locale: {
      type: String,
      optional: true
    },
    value: {
      type: String,
      optional: true
    }
  };

  const IntlString = new SimpleSchema(schema);
  IntlString.name = 'IntlString';
  return IntlString;
};

/*

Check if a schema has at least one intl field

*/
export const schemaHasIntlFields = schema => Object.keys(schema).some(fieldName => isIntlField(schema[fieldName]));

/*

Custom validation function to check for required locales

See https://github.com/aldeed/simple-schema-js#custom-field-validation

*/
export const validateIntlField = function() {
  let errors = [];

  // go through locales to check which one are required
  const requiredLocales = Locales.filter(locale => locale.required);

  requiredLocales.forEach((locale, index) => {
    const strings = this.value;
    const hasString = strings && Array.isArray(strings) && strings.some(s => s && s.locale === locale.id && s.value);
    if (!hasString) {
      const originalFieldName = this.key.replace('_intl', '');
      errors.push({
        id: 'errors.required',
        path: `${this.key}.${index}`,
        properties: { name: originalFieldName, locale: locale.id }
      });
    }
  });

  if (errors.length > 0) {
    // hack to work around the fact that custom validation function can only return a single string
    return `intlError|${JSON.stringify(errors)}`;
  }
};
<|endoftext|>


<commit_before>//a wrapper around leaflet that configures it as well
var map_config=require('../config/map-config');
var path=require('path');
var MapDraw=require('./models/MapDraw');
var MapMeasure=require('./models/MapMeasure');
var MapPath=require('./models/MapPath');

var Map=function(L){
  var leaflet=L;//reference to the window leaflet object
  var map=null;
  var mapPath= new MapPath(leaflet);

  //Set up paths
  var tiles_path=path.join(__dirname,'../assets/sat_tiles');
  var images_path=path.join(__dirname,'../assets/images');
  leaflet.Icon.Default.imagePath = path.join(__dirname,'../assets/leaflet');

  var base_layers={};
  var overlay_layers={};

  base_layers['Satellite']=leaflet.tileLayer(tiles_path+'/{z}/{x}/{y}.png', {
    maxZoom: 19
  });

  base_layers['Streets']=leaflet.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors'
  });

  base_layers['Google Satellite']=new leaflet.Google('SATELLITE');

  overlay_layers['Plane']=new leaflet.RotatedMarker(map_config.get('default_lat_lang'), {
    icon: leaflet.icon({
      iconUrl: images_path+'/plane.png',
      iconSize: [30, 30]
    })
  });

  overlay_layers['Plane Trail']=new leaflet.Polyline([], {
      color: '#190019',
      opacity: 0.6,
      weight: 5,
      clickable: true,
  });

  var centerToPlaneButton=L.easyButton( 'icon ion-pinpoint', function(){
    if (overlay_layers['Plane']) {
      map.panTo(overlay_layers['Plane'].getLatLng());
    }
  });

  this.createMap=function(id){
    map = leaflet.map(id,{
      center: map_config.get('default_lat_lang'),
      zoom: 17,
      layers: [base_layers['Satellite'], overlay_layers['Plane'],overlay_layers['Plane Trail']] //the default layers of the map
    });

    //allow the user to turn on and off specific layers
    leaflet.control.layers(base_layers, overlay_layers).addTo(map);
    leaflet.control.mousePosition().addTo(map); //displays lat and lon coordinates at bottom left of the map
    map.addControl(centerToPlaneButton);

    mapPath.addTo(map);
    MapMeasure(leaflet).addTo(map);
    new MapDraw(leaflet).addTo(map); //adds draw controls to map
  };

  this.movePlane=function(lat,lng, heading){
    overlay_layers['Plane'].setLatLng([lat,lng]);
    overlay_layers['Plane'].angle = heading;
    overlay_layers['Plane'].update();
  };

  this.expandPlaneTrail=function(lat,lng){
    overlay_layers['Plane Trail'].addLatLng([lat,lng]);
  };

  this.clearPlaneTrail=function(){
    overlay_layers['Plane Trail'].setLatLngs([]);
  };

};

module.exports=Map;<commit_msg>Set google satelite as the default layer<commit_after>//a wrapper around leaflet that configures it as well
var map_config=require('../config/map-config');
var path=require('path');
var MapDraw=require('./models/MapDraw');
var MapMeasure=require('./models/MapMeasure');
var MapPath=require('./models/MapPath');

var Map=function(L){
  var leaflet=L;//reference to the window leaflet object
  var map=null;
  var mapPath= new MapPath(leaflet);

  //Set up paths
  var tiles_path=path.join(__dirname,'../assets/sat_tiles');
  var images_path=path.join(__dirname,'../assets/images');
  leaflet.Icon.Default.imagePath = path.join(__dirname,'../assets/leaflet');

  var base_layers={};
  var overlay_layers={};

  base_layers['Satellite']=leaflet.tileLayer(tiles_path+'/{z}/{x}/{y}.png', {
    maxZoom: 19
  });

  base_layers['Streets']=leaflet.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors'
  });

  base_layers['Google Satellite']=new leaflet.Google('SATELLITE');

  overlay_layers['Plane']=new leaflet.RotatedMarker(map_config.get('default_lat_lang'), {
    icon: leaflet.icon({
      iconUrl: images_path+'/plane.png',
      iconSize: [30, 30]
    })
  });

  overlay_layers['Plane Trail']=new leaflet.Polyline([], {
      color: '#190019',
      opacity: 0.6,
      weight: 5,
      clickable: true,
  });

  var centerToPlaneButton=L.easyButton( 'icon ion-pinpoint', function(){
    if (overlay_layers['Plane']) {
      map.panTo(overlay_layers['Plane'].getLatLng());
    }
  });

  this.createMap=function(id){
    map = leaflet.map(id,{
      center: map_config.get('default_lat_lang'),
      zoom: 17,
      layers: [base_layers['Google Satellite'], overlay_layers['Plane'],overlay_layers['Plane Trail']] //the default layers of the map
    });

    //allow the user to turn on and off specific layers
    leaflet.control.layers(base_layers, overlay_layers).addTo(map);
    leaflet.control.mousePosition().addTo(map); //displays lat and lon coordinates at bottom left of the map
    map.addControl(centerToPlaneButton);

    mapPath.addTo(map);
    MapMeasure(leaflet).addTo(map);
    new MapDraw(leaflet).addTo(map); //adds draw controls to map
  };

  this.movePlane=function(lat,lng, heading){
    overlay_layers['Plane'].setLatLng([lat,lng]);
    overlay_layers['Plane'].angle = heading;
    overlay_layers['Plane'].update();
  };

  this.expandPlaneTrail=function(lat,lng){
    overlay_layers['Plane Trail'].addLatLng([lat,lng]);
  };

  this.clearPlaneTrail=function(){
    overlay_layers['Plane Trail'].setLatLngs([]);
  };

};

module.exports=Map;<|endoftext|>


<commit_before>/*
 Copyright (c) 2012, Yahoo! Inc.  All rights reserved.
 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */

var util = require('util'),
    path = require('path'),
    os = require('os'),
    fs = require('fs'),
    mkdirp = require('mkdirp'),
    Store = require('./index');

function makeTempDir() {
    var dir = path.join(os.tmpDir ? os.tmpDir() : /* istanbul ignore next */ (process.env.TMPDIR || '/tmp'), 'ts' + new Date().getTime());
    mkdirp.sync(dir);
    return dir;
}
/**
 * a `Store` implementation using temporary files.
 *
 * Usage
 * -----
 *
 *      var store = require('istanbul').Store.create('tmp');
 *
 *
 * @class TmpStore
 * @extends Store
 * @module store
 * @param {Object} opts Optional.
 * @param {String} [opts.tmp] a pre-existing directory to use as the `tmp` directory. When not specified, a random directory
 *      is created under `os.tmpDir()`
 * @constructor
 */
function TmpStore(opts) {
    opts = opts || {};
    this.tmp = opts.tmp || makeTempDir();
    this.map = {};
    this.seq = 0;
    this.prefix = 't' + new Date().getTime() + '-';
}

TmpStore.TYPE = 'tmp';
util.inherits(TmpStore, Store);

Store.mix(TmpStore, {
    generateTmpFileName: function () {
        this.seq += 1;
        return this.prefix + this.seq + '.tmp';
    },

    set: function (key, contents) {
        var tmpFile = this.generateTmpFileName();
        fs.writeFileSync(tmpFile, contents, 'utf8');
        this.map[key] = tmpFile;
    },

    get: function (key) {
        var tmpFile = this.map[key];
        if (!tmpFile) { throw new Error('Unable to find tmp entry for [' + tmpFile + ']'); }
        return fs.readFileSync(tmpFile, 'utf8');
    },

    hasKey: function (key) {
        return !!this.map[key];
    },

    keys: function () {
        return Object.keys(this.map);
    },

    dispose: function () {
        var map = this.map;
        Object.keys(map).forEach(function (key) {
            fs.unlinkSync(map[key]);
        });
        this.map = {};
    }
});

module.exports = TmpStore;
<commit_msg>tmp dir setting was being ignored in TmpStore<commit_after>/*
 Copyright (c) 2012, Yahoo! Inc.  All rights reserved.
 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */

var util = require('util'),
    path = require('path'),
    os = require('os'),
    fs = require('fs'),
    mkdirp = require('mkdirp'),
    Store = require('./index');

function makeTempDir() {
    var dir = path.join(os.tmpDir ? os.tmpDir() : /* istanbul ignore next */ (process.env.TMPDIR || '/tmp'), 'ts' + new Date().getTime());
    mkdirp.sync(dir);
    return dir;
}
/**
 * a `Store` implementation using temporary files.
 *
 * Usage
 * -----
 *
 *      var store = require('istanbul').Store.create('tmp');
 *
 *
 * @class TmpStore
 * @extends Store
 * @module store
 * @param {Object} opts Optional.
 * @param {String} [opts.tmp] a pre-existing directory to use as the `tmp` directory. When not specified, a random directory
 *      is created under `os.tmpDir()`
 * @constructor
 */
function TmpStore(opts) {
    opts = opts || {};
    this.tmp = opts.tmp || makeTempDir();
    this.map = {};
    this.seq = 0;
    this.prefix = 't' + new Date().getTime() + '-';
}

TmpStore.TYPE = 'tmp';
util.inherits(TmpStore, Store);

Store.mix(TmpStore, {
    generateTmpFileName: function () {
        this.seq += 1;
        return path.join(this.tmp, this.prefix + this.seq + '.tmp');
    },

    set: function (key, contents) {
        var tmpFile = this.generateTmpFileName();
        fs.writeFileSync(tmpFile, contents, 'utf8');
        this.map[key] = tmpFile;
    },

    get: function (key) {
        var tmpFile = this.map[key];
        if (!tmpFile) { throw new Error('Unable to find tmp entry for [' + tmpFile + ']'); }
        return fs.readFileSync(tmpFile, 'utf8');
    },

    hasKey: function (key) {
        return !!this.map[key];
    },

    keys: function () {
        return Object.keys(this.map);
    },

    dispose: function () {
        var map = this.map;
        Object.keys(map).forEach(function (key) {
            fs.unlinkSync(map[key]);
        });
        this.map = {};
    }
});

module.exports = TmpStore;
<|endoftext|>


<commit_before>var Q = require('q');
var util = require('util');
var mout = require('mout');
var events = require('events');

var UnitOfWork = function (options) {
    // Ensure options defaults
    this._options = mout.object.mixIn({
        maxConcurrent: 5
    }, options);

    // Parse some of the options
    this._options.maxConcurrent = this._options.maxConcurrent > 0 ? this._options.maxConcurrent : 0;

    // Initialize some needed properties
    this._queue = [];
    this._beingResolved = [];
    this._beingResolvedEndpoints = {};
};

util.inherits(UnitOfWork, events.EventEmitter);

// -----------------

UnitOfWork.prototype.enqueue = function (resolver) {
    var deferred;

    if (this.has(resolver)) {
        throw new Error('Attempting to enqueue an already enqueued resolver');
    }

    deferred = Q.defer();

    // Add to the queue
    this._queue.push({
        resolver: resolver,
        deferred: deferred
    });

    // Process the queue shortly later so that handlers can be attached to the returned promise
    Q.fcall(this.doWork.bind(this));

    return deferred.promise;
};

UnitOfWork.prototype.has = function (resolver) {
    var index;

    // Check in the queue
    index = this._indexOf(this._queue, resolver);
    if (index !== -1) {
        return true;
    }

    // Check in the being resolved list
    index = this._indexOf(this._beingResolved, resolver);
    if (index !== -1) {
        return true;
    }

    return false;
};

UnitOfWork.prototype.abort = function () {
    var promises,
        emptyFunc = function () {};

    // Empty queue
    this._queue = [];

    // Wait for pending resolvers to resolve
    promises = this._beingResolved.map(function (entry) {
        // Please note that the promise resolution/fail is silenced
        return entry.deferred.promise.then(emptyFunc, emptyFunc);
    });

    return Q.all(promises);
};

// -----------------

UnitOfWork.prototype._doWork = function () {
    // Check if the number of allowed packages being resolved reached the maximum
    if (this._options.maxConcurrent && this._beingResolved.length >= this._options.maxConcurrent) {
        return;
    }

    // Find candidates for the free slots
    var freeSlots = this._options.maxConcurrent ? this._options.maxConcurrent - this._beingResolved.length : -1,
        entry,
        resolver,
        x;

    for (x = 0; x < this._queue.length && freeSlots; ++x) {
        entry = this._queue[x];
        resolver = entry.resolver;

        // Remove from the queue and
        this._queue.splice(x--, 1);

        // Put it in the being resolved list
        this._beingResolved.push(entry);
        freeSlots--;

        // Resolve it, waiting for it to be done
        this.emit('pre_resolve', resolver);
        resolver.resolve().then(this._onResolveSuccess.bind(this, entry), this._onResolveFailure.bind(this, entry));
    }
};

UnitOfWork.prototype._onResolveSuccess = function (entry, result) {
    var index;

    // Remove the package from the being resolved list
    index = this._beingResolved.indexOf(entry);
    this._beingResolved.splice(index, 1);

    entry.deferred.resolve(result);
    this.emit('post_resolve', entry.resolver, result);

    // A free spot became available, so let's do some more work
    this._doWork();
};

UnitOfWork.prototype._onResolveFailure = function (entry, err) {
    var index;

    // Remove the package from the being resolved list
    index = this._beingResolved.indexOf(entry);
    this._beingResolved.splice(index, 1);

    entry.deferred.reject(err);
    this.emit('fail', entry.resolver, err);

    // A free spot became available, so let's do some more work
    this._doWork();
};

UnitOfWork.prototype._indexOf = function (arr, pkg) {
    return mout.array.findIndex(arr, function (item) {
        return item.pkg === pkg;
    });
};

module.exports = UnitOfWork;<commit_msg>Unnecessary line.<commit_after>var Q = require('q');
var util = require('util');
var mout = require('mout');
var events = require('events');

var UnitOfWork = function (options) {
    // Ensure options defaults
    this._options = mout.object.mixIn({
        maxConcurrent: 5
    }, options);

    // Parse some of the options
    this._options.maxConcurrent = this._options.maxConcurrent > 0 ? this._options.maxConcurrent : 0;

    // Initialize some needed properties
    this._queue = [];
    this._beingResolved = [];
};

util.inherits(UnitOfWork, events.EventEmitter);

// -----------------

UnitOfWork.prototype.enqueue = function (resolver) {
    var deferred;

    if (this.has(resolver)) {
        throw new Error('Attempting to enqueue an already enqueued resolver');
    }

    deferred = Q.defer();

    // Add to the queue
    this._queue.push({
        resolver: resolver,
        deferred: deferred
    });

    // Process the queue shortly later so that handlers can be attached to the returned promise
    Q.fcall(this.doWork.bind(this));

    return deferred.promise;
};

UnitOfWork.prototype.has = function (resolver) {
    var index;

    // Check in the queue
    index = this._indexOf(this._queue, resolver);
    if (index !== -1) {
        return true;
    }

    // Check in the being resolved list
    index = this._indexOf(this._beingResolved, resolver);
    if (index !== -1) {
        return true;
    }

    return false;
};

UnitOfWork.prototype.abort = function () {
    var promises,
        emptyFunc = function () {};

    // Empty queue
    this._queue = [];

    // Wait for pending resolvers to resolve
    promises = this._beingResolved.map(function (entry) {
        // Please note that the promise resolution/fail is silenced
        return entry.deferred.promise.then(emptyFunc, emptyFunc);
    });

    return Q.all(promises);
};

// -----------------

UnitOfWork.prototype._doWork = function () {
    // Check if the number of allowed packages being resolved reached the maximum
    if (this._options.maxConcurrent && this._beingResolved.length >= this._options.maxConcurrent) {
        return;
    }

    // Find candidates for the free slots
    var freeSlots = this._options.maxConcurrent ? this._options.maxConcurrent - this._beingResolved.length : -1,
        entry,
        resolver,
        x;

    for (x = 0; x < this._queue.length && freeSlots; ++x) {
        entry = this._queue[x];
        resolver = entry.resolver;

        // Remove from the queue and
        this._queue.splice(x--, 1);

        // Put it in the being resolved list
        this._beingResolved.push(entry);
        freeSlots--;

        // Resolve it, waiting for it to be done
        this.emit('pre_resolve', resolver);
        resolver.resolve().then(this._onResolveSuccess.bind(this, entry), this._onResolveFailure.bind(this, entry));
    }
};

UnitOfWork.prototype._onResolveSuccess = function (entry, result) {
    var index;

    // Remove the package from the being resolved list
    index = this._beingResolved.indexOf(entry);
    this._beingResolved.splice(index, 1);

    entry.deferred.resolve(result);
    this.emit('post_resolve', entry.resolver, result);

    // A free spot became available, so let's do some more work
    this._doWork();
};

UnitOfWork.prototype._onResolveFailure = function (entry, err) {
    var index;

    // Remove the package from the being resolved list
    index = this._beingResolved.indexOf(entry);
    this._beingResolved.splice(index, 1);

    entry.deferred.reject(err);
    this.emit('fail', entry.resolver, err);

    // A free spot became available, so let's do some more work
    this._doWork();
};

UnitOfWork.prototype._indexOf = function (arr, pkg) {
    return mout.array.findIndex(arr, function (item) {
        return item.pkg === pkg;
    });
};

module.exports = UnitOfWork;<|endoftext|>


<commit_before>import { Job as KueJob } from 'kue'

export class Job {
	static jobName = null
	static priority = 'normal'
	static removeOnComplete = true
	static attempts = 1
	static concurrency = 1

	$kueJob = null
	$queue = null

	constructor(data = { }, $kueJob = null) {
		Object.assign(this, data)
		this.$kueJob = $kueJob || (() => {
			const job = new KueJob
			job.attempts(this.constructor.attempts)
			job.priority(this.constructor.priority)
			job.removeOnComplete(this.constructor.removeOnComplete)
			job.events(false)
			return job
		})()
	}

	get id() {
		return this.$kueJob.id
	}

	// eslint-disable-next-line no-unused-vars
	$handle(app, queue) {
		//
	}

	$priority(...args) {
		this.$kueJob.priority(...args)
		return this
	}

	$delay(...args) {
		this.$kueJob.delay(...args)
		return this
	}

	$attempts(...args) {
		this.$kueJob.attempts(...args)
		return this
	}

	$backoff(...args) {
		this.$kueJob.backoff(...args)
		return this
	}

	$ttl(...args) {
		this.$kueJob.ttl(...args)
		return this
	}

	$progress(...args) {
		this.$kueJob.progress(...args)
		return this
	}

	$log(...args) {
		this.$kueJob.log(...args)
		return this
	}

	$save(queue) {
		if(this.id.isNil) {
			if(queue.isNil) {
				throw new Error('Calling $save on new jobs requires a queue parameter.')
			}

			const jobName = this.constructor.jobName

			if(jobName.isNil) {
				throw new Error('Invalid Job, must have `jobName` set.')
			}

			if(queue.jobs[jobName].isNil) {
				throw new Error('This job is not yet registered with the target queue.')
			}

			this.$kueJob.type = jobName
			this.$kueJob.client = queue.kue.client
		}

		this.$kueJob.data = this.toJSON()

		return new Promise((resolve, reject) => {
			let resolved = false

			this.$kueJob.save(err => {
				if(resolved) {
					return
				}

				resolved = true

				if(!err.isNil) {
					return reject(err)
				}

				resolved = true
				return resolve(this)
			})
		})
	}

	toJSON() {
		return this.$toJson()
	}

	$toJson() {
		const json = Object.assign({ }, this)

		for(const key of Object.keys(json)) {
			if(key.substring(0, 1) !== '$') {
				continue
			}

			delete json[key]
		}

		return json
	}

}
<commit_msg>Added Job.backoff to work with Job.attempts in default settings<commit_after>import { Job as KueJob } from 'kue'

export class Job {
	static jobName = null
	static priority = 'normal'
	static removeOnComplete = true
	static attempts = 1
	static backoff = null
	static concurrency = 1

	$kueJob = null
	$queue = null

	constructor(data = { }, $kueJob = null) {
		Object.assign(this, data)
		this.$kueJob = $kueJob || (() => {
			const job = new KueJob
			job.attempts(this.constructor.attempts)
			job.priority(this.constructor.priority)
			job.removeOnComplete(this.constructor.removeOnComplete)
			job.backoff(this.constructor.backoff)
			job.events(false)
			return job
		})()
	}

	get id() {
		return this.$kueJob.id
	}

	// eslint-disable-next-line no-unused-vars
	$handle(app, queue) {
		//
	}

	$priority(...args) {
		this.$kueJob.priority(...args)
		return this
	}

	$delay(...args) {
		this.$kueJob.delay(...args)
		return this
	}

	$attempts(...args) {
		this.$kueJob.attempts(...args)
		return this
	}

	$backoff(...args) {
		this.$kueJob.backoff(...args)
		return this
	}

	$ttl(...args) {
		this.$kueJob.ttl(...args)
		return this
	}

	$progress(...args) {
		this.$kueJob.progress(...args)
		return this
	}

	$log(...args) {
		this.$kueJob.log(...args)
		return this
	}

	$save(queue) {
		if(this.id.isNil) {
			if(queue.isNil) {
				throw new Error('Calling $save on new jobs requires a queue parameter.')
			}

			const jobName = this.constructor.jobName

			if(jobName.isNil) {
				throw new Error('Invalid Job, must have `jobName` set.')
			}

			if(queue.jobs[jobName].isNil) {
				throw new Error('This job is not yet registered with the target queue.')
			}

			this.$kueJob.type = jobName
			this.$kueJob.client = queue.kue.client
		}

		this.$kueJob.data = this.toJSON()

		return new Promise((resolve, reject) => {
			let resolved = false

			this.$kueJob.save(err => {
				if(resolved) {
					return
				}

				resolved = true

				if(!err.isNil) {
					return reject(err)
				}

				resolved = true
				return resolve(this)
			})
		})
	}

	toJSON() {
		return this.$toJson()
	}

	$toJson() {
		const json = Object.assign({ }, this)

		for(const key of Object.keys(json)) {
			if(key.substring(0, 1) !== '$') {
				continue
			}

			delete json[key]
		}

		return json
	}

}
<|endoftext|>


<commit_before>(function (enyo, scope) {
	/**
	* A light-weight panels implementation that has basic support for side-to-side transitions
	* between child components.
	*
	* @class enyo.LightPanels
	* @extends enyo.Control
	* @ui
	* @public
	*/
	enyo.kind(
		/** @lends enyo.LightPanels.prototype */ {

		/**
		* @private
		*/
		name: 'enyo.LightPanels',

		/**
		* @private
		*/
		kind: 'enyo.Control',

		/**
		* @private
		*/
		classes: 'enyo-light-panels',

		/**
		* @private
		* @lends enyo.LightPanels.prototype
		*/
		published: {

			/**
			* The index of the active panel.
			*
			* @type {Number}
			* @default 0
			* @public
			*/
			index: 0,

			/**
			* Indicates whether the panels animate when transitioning.
			*
			* @type {Boolean}
			* @default true
			* @public
			*/
			animate: true,

			/**
			* Indicates whether panels "wrap around" when moving past the end.
			* The actual effect depends upon the arranger in use.
			*
			* @type {Boolean}
			* @default false
			* @public
			*/
			wrap: false,

			/**
			* When `true`, panels are automatically popped when the user moves back.
			*
			* @type {Boolean}
			* @default true
			* @public
			*/
			popOnBack: true,

			/**
			* The amount of time, in milliseconds, to run the transition animation between panels.
			*
			* @type {Number}
			* @default 350
			* @public
			*/
			duration: 350,

			/**
			* The orientation of the scrolling. Possible values are 'vertical' and 'horizontal'.
			*
			* @type {String}
			* @default 'horizontal'
			* @public
			*/
			orientation: 'horizontal'
		},

		/**
		* @private
		*/
		handlers: {
			ontransitionend: 'transitionFinished'
		},

		/**
		* @method
		* @private
		*/
		create: enyo.inherit(function (sup) {
			return function () {
				sup.apply(this, arguments);
				this.init();
				this.indexChanged();
			};
		}),

		/**
		* @private
		*/
		init: function () {
			this.addClass(this.orientation);
		},

		/**
		* @private
		*/
		indexChanged: function (previousIndex) {
			var panels = this.getPanels(),
				nextPanel = panels[this.index];

			this._direction = (this.index - previousIndex < 0 ? -1 : 1);

			if (nextPanel) {
				// only animate transition if there is more than one panel and/or we're animating
				if (!this.shouldAnimate()) {
					nextPanel.applyStyle('-webkit-transition-duration', '0s');
					nextPanel.applyStyle('transition-duration', '0s');
				} else {
					nextPanel.applyStyle('-webkit-transition', enyo.format('-webkit-transform %.ms linear', this.duration));
					nextPanel.applyStyle('transition', enyo.format('transform %.ms linear', this.duration));
					if (this._currentPanel) {
						this._currentPanel.addClass('transitioning');
						this._currentPanel.applyStyle('-webkit-transition', enyo.format('-webkit-transform %.ms linear', this.duration));
						this._currentPanel.applyStyle('transition', enyo.format('-webkit-transform %.ms linear', this.duration));
					}
				}
				var axis = this.orientation == 'horizontal' ? 'X' : 'Y';
				setTimeout(this.bindSafely(function () {
					var nextTransition = {};
					nextTransition['translate' + axis] = '-100%';
					enyo.dom.transform(nextPanel, nextTransition);
					enyo.dom.transform(nextPanel, {translateZ: 0});
					if (this._currentPanel) {
						var currentTransition = {};
						currentTransition['translate' + axis] = this._direction > 0 ? '-200%' : '0%';
						enyo.dom.transform(this._currentPanel, currentTransition);
						enyo.dom.transform(this._currentPanel, {translateZ: 0});
					}

					this._previousPanel = this._currentPanel;
					this._currentPanel = nextPanel;
					if (!this.shouldAnimate() && this._currentPanel.shouldSkipPostTransition && !this._currentPanel.shouldSkipPostTransition()) {
						this.transitionFinished(this._currentPanel, {originator: this._currentPanel});
					}

				}), 16);
			}
		},

		/**
		* Determines whether or not we should animate the panel transition.
		*
		* @return {Boolean} If `true`, the panels should animate.
		* @public
		*/
		shouldAnimate: function () {
			return this.getPanels().length > 1 && this.animate;
		},

		/**
		* Retrieves the currently displayed panel.
		*
		* @return {Object} The currently displayed panel.
		* @public
		*/
		getActivePanel: function () {
			return this._currentPanel;
		},

		/**
		* Transitions to the previous panel--i.e., the panel whose index value is one
		* less than that of the current active panel.
		*
		* @public
		*/
		previous: function () {
			var prevIndex = this.index - 1;
			if (this.wrap && prevIndex < 0) {
				prevIndex = this.getPanels().length - 1;
			}
			if (prevIndex >= 0) {
				this.set('index', prevIndex);
			}
		},

		/**
		* Transitions to the next panel--i.e., the panel whose index value is one
		* greater than that of the current active panel.
		*
		* @public
		*/
		next: function () {
			var nextIndex = this.index + 1;
			if (this.wrap && nextIndex >= this.getPanels().length) {
				nextIndex = 0;
			}
			if (nextIndex < this.getPanels().length) {
				this.set('index', nextIndex);
			}
		},

		/**
		* Creates a panel on top of the stack and increments index to select that component.
		*
		* @param {Object} info - The declarative {@glossary kind} definition.
		* @param {Object} moreInfo - Additional properties to be applied (defaults).
		* @param {Object} opts - Additional options to be used during panel pushing.
		* @return {Object} The instance of the panel that was created on top of the stack.
		* @public
		*/
		pushPanel: function (info, moreInfo, opts) {
			if (opts && opts.purge) {
				this.purge();
			}

			var lastIndex = this.getPanels().length - 1,
				nextPanel = this.createComponent(info, moreInfo);
			nextPanel.render();
			this.set('index', lastIndex + 1, true);

			// TODO: When pushing panels after we have gone back (but have not popped), we need to
			// adjust the position of the panels after the previous index before our push.
			return nextPanel;
		},

		/**
		* Creates multiple panels on top of the stack and updates index to select the last one
		* created. Supports an optional `options` object as the third parameter.
		*
		* @param {Object[]} info - The declarative {@glossary kind} definitions.
		* @param {Object} commonInfo - Additional properties to be applied (defaults).
		* @param {Object} options - Additional options for pushPanels.
		* @return {null|Object[]} Array of the panels that were created on top of the stack, or
		*	`null` if panels could not be created.
		* @public
		*/
		pushPanels: function (info, commonInfo, options) {
			var lastIndex = this.getPanels().length,
				newPanels = this.createComponents(info, commonInfo),
				idx;

			for (idx = 0; idx < newPanels.length; ++idx) {
				newPanels[idx].render();
			}

			this.set('index', lastIndex, true);

			return newPanels;
		},

		/**
		* @private
		*/
		getPanels: function () {
			/*jshint -W093 */
			return (this._panels = this._panels || (this.controlParent || this).children);
		},

		/**
		* Destroys panels whose index is greater than or equal to a specified value.
		*
		* @param {Number} index - Index at which to start destroying panels.
		* @public
		*/
		popPanels: function (index) {
			var panels = this.getPanels();
			index = index || panels.length - 1;
			while (panels.length > index && index >= 0) {
				panels[panels.length - 1].destroy();
			}
		},

		/**
		* Destroys all panels. These will be queued for destruction after the next panel has loaded.
		*
		* @private
		*/
		purge: function () {
			var panels = this.getPanels();
			this._garbagePanels = panels.slice();
			panels.length = 0;
		},

		/**
		* Clean-up any panels queued for destruction.
		*
		* @private
		*/
		finalizePurge: function () {
			var panels = this._garbagePanels;
			for (var idx = 0; idx < panels.length; idx++) {
				panels[idx].destroy();
			}
		},

		/**
		* @private
		*/
		transitionFinished: function (sender, ev) {
			if (ev.originator === this._currentPanel) {
				if (this._previousPanel) {
					this._previousPanel.removeClass('transitioning');
				}
				if (this.popOnBack && this._direction < 0 && this.index < this.getPanels().length - 1) {
					this.popPanels(this.index + 1);
				}
				if (this._currentPanel.shouldSkipPostTransition && !this._currentPanel.shouldSkipPostTransition()) {
					this._currentPanel.postTransition();
				}
				if (this._garbagePanels && this._garbagePanels.length) {
					this.finalizePurge();
				}
			}
		}

	});

})(enyo, this);
<commit_msg>Adding support for specifying timing function, changing defaults<commit_after>(function (enyo, scope) {
	/**
	* A light-weight panels implementation that has basic support for side-to-side transitions
	* between child components.
	*
	* @class enyo.LightPanels
	* @extends enyo.Control
	* @ui
	* @public
	*/
	enyo.kind(
		/** @lends enyo.LightPanels.prototype */ {

		/**
		* @private
		*/
		name: 'enyo.LightPanels',

		/**
		* @private
		*/
		kind: 'enyo.Control',

		/**
		* @private
		*/
		classes: 'enyo-light-panels',

		/**
		* @private
		* @lends enyo.LightPanels.prototype
		*/
		published: {

			/**
			* The index of the active panel.
			*
			* @type {Number}
			* @default 0
			* @public
			*/
			index: 0,

			/**
			* Indicates whether the panels animate when transitioning.
			*
			* @type {Boolean}
			* @default true
			* @public
			*/
			animate: true,

			/**
			* Indicates whether panels "wrap around" when moving past the end.
			* The actual effect depends upon the arranger in use.
			*
			* @type {Boolean}
			* @default false
			* @public
			*/
			wrap: false,

			/**
			* When `true`, panels are automatically popped when the user moves back.
			*
			* @type {Boolean}
			* @default true
			* @public
			*/
			popOnBack: true,

			/**
			* The amount of time, in milliseconds, to run the transition animation between panels.
			*
			* @type {Number}
			* @default 250
			* @public
			*/
			duration: 250,

			/**
			* The timing function to be applied to the transition animation between panels.
			*
			* @type {String}
			* @default 'ease-out'
			* @public
			*/
			timingFunction: 'ease-out',

			/**
			* The orientation of the scrolling. Possible values are 'vertical' and 'horizontal'.
			*
			* @type {String}
			* @default 'horizontal'
			* @public
			*/
			orientation: 'horizontal'
		},

		/**
		* @private
		*/
		handlers: {
			ontransitionend: 'transitionFinished'
		},

		/**
		* @method
		* @private
		*/
		create: enyo.inherit(function (sup) {
			return function () {
				sup.apply(this, arguments);
				this.init();
				this.indexChanged();
			};
		}),

		/**
		* @private
		*/
		init: function () {
			this.addClass(this.orientation);
		},

		/**
		* @private
		*/
		indexChanged: function (previousIndex) {
			var panels = this.getPanels(),
				nextPanel = panels[this.index],
				trans, wTrans;

			this._direction = (this.index - previousIndex < 0 ? -1 : 1);

			if (nextPanel) {
				// only animate transition if there is more than one panel and/or we're animating
				if (!this.shouldAnimate()) {
					nextPanel.applyStyle('-webkit-transition-duration', '0s');
					nextPanel.applyStyle('transition-duration', '0s');
				} else {
					trans = enyo.format('transform %.ms %.', this.duration, this.timingFunction);
					wTrans = '-webkit-' + trans;
					nextPanel.applyStyle('-webkit-transition', wTrans);
					nextPanel.applyStyle('transition', trans);
					if (this._currentPanel) {
						this._currentPanel.addClass('transitioning');
						this._currentPanel.applyStyle('-webkit-transition', wTrans);
						this._currentPanel.applyStyle('transition', trans);
					}
				}
				var axis = this.orientation == 'horizontal' ? 'X' : 'Y';
				setTimeout(this.bindSafely(function () {
					var nextTransition = {};
					nextTransition['translate' + axis] = '-100%';
					enyo.dom.transform(nextPanel, nextTransition);
					enyo.dom.transform(nextPanel, {translateZ: 0});
					if (this._currentPanel) {
						var currentTransition = {};
						currentTransition['translate' + axis] = this._direction > 0 ? '-200%' : '0%';
						enyo.dom.transform(this._currentPanel, currentTransition);
						enyo.dom.transform(this._currentPanel, {translateZ: 0});
					}

					this._previousPanel = this._currentPanel;
					this._currentPanel = nextPanel;
					if (!this.shouldAnimate() && this._currentPanel.shouldSkipPostTransition && !this._currentPanel.shouldSkipPostTransition()) {
						this.transitionFinished(this._currentPanel, {originator: this._currentPanel});
					}

				}), 16);
			}
		},

		/**
		* Determines whether or not we should animate the panel transition.
		*
		* @return {Boolean} If `true`, the panels should animate.
		* @public
		*/
		shouldAnimate: function () {
			return this.getPanels().length > 1 && this.animate;
		},

		/**
		* Retrieves the currently displayed panel.
		*
		* @return {Object} The currently displayed panel.
		* @public
		*/
		getActivePanel: function () {
			return this._currentPanel;
		},

		/**
		* Transitions to the previous panel--i.e., the panel whose index value is one
		* less than that of the current active panel.
		*
		* @public
		*/
		previous: function () {
			var prevIndex = this.index - 1;
			if (this.wrap && prevIndex < 0) {
				prevIndex = this.getPanels().length - 1;
			}
			if (prevIndex >= 0) {
				this.set('index', prevIndex);
			}
		},

		/**
		* Transitions to the next panel--i.e., the panel whose index value is one
		* greater than that of the current active panel.
		*
		* @public
		*/
		next: function () {
			var nextIndex = this.index + 1;
			if (this.wrap && nextIndex >= this.getPanels().length) {
				nextIndex = 0;
			}
			if (nextIndex < this.getPanels().length) {
				this.set('index', nextIndex);
			}
		},

		/**
		* Creates a panel on top of the stack and increments index to select that component.
		*
		* @param {Object} info - The declarative {@glossary kind} definition.
		* @param {Object} moreInfo - Additional properties to be applied (defaults).
		* @param {Object} opts - Additional options to be used during panel pushing.
		* @return {Object} The instance of the panel that was created on top of the stack.
		* @public
		*/
		pushPanel: function (info, moreInfo, opts) {
			if (opts && opts.purge) {
				this.purge();
			}

			var lastIndex = this.getPanels().length - 1,
				nextPanel = this.createComponent(info, moreInfo);
			nextPanel.render();
			this.set('index', lastIndex + 1, true);

			// TODO: When pushing panels after we have gone back (but have not popped), we need to
			// adjust the position of the panels after the previous index before our push.
			return nextPanel;
		},

		/**
		* Creates multiple panels on top of the stack and updates index to select the last one
		* created. Supports an optional `options` object as the third parameter.
		*
		* @param {Object[]} info - The declarative {@glossary kind} definitions.
		* @param {Object} commonInfo - Additional properties to be applied (defaults).
		* @param {Object} options - Additional options for pushPanels.
		* @return {null|Object[]} Array of the panels that were created on top of the stack, or
		*	`null` if panels could not be created.
		* @public
		*/
		pushPanels: function (info, commonInfo, options) {
			var lastIndex = this.getPanels().length,
				newPanels = this.createComponents(info, commonInfo),
				idx;

			for (idx = 0; idx < newPanels.length; ++idx) {
				newPanels[idx].render();
			}

			this.set('index', lastIndex, true);

			return newPanels;
		},

		/**
		* @private
		*/
		getPanels: function () {
			/*jshint -W093 */
			return (this._panels = this._panels || (this.controlParent || this).children);
		},

		/**
		* Destroys panels whose index is greater than or equal to a specified value.
		*
		* @param {Number} index - Index at which to start destroying panels.
		* @public
		*/
		popPanels: function (index) {
			var panels = this.getPanels();
			index = index || panels.length - 1;
			while (panels.length > index && index >= 0) {
				panels[panels.length - 1].destroy();
			}
		},

		/**
		* Destroys all panels. These will be queued for destruction after the next panel has loaded.
		*
		* @private
		*/
		purge: function () {
			var panels = this.getPanels();
			this._garbagePanels = panels.slice();
			panels.length = 0;
		},

		/**
		* Clean-up any panels queued for destruction.
		*
		* @private
		*/
		finalizePurge: function () {
			var panels = this._garbagePanels;
			for (var idx = 0; idx < panels.length; idx++) {
				panels[idx].destroy();
			}
		},

		/**
		* @private
		*/
		transitionFinished: function (sender, ev) {
			if (ev.originator === this._currentPanel) {
				if (this._previousPanel) {
					this._previousPanel.removeClass('transitioning');
				}
				if (this.popOnBack && this._direction < 0 && this.index < this.getPanels().length - 1) {
					this.popPanels(this.index + 1);
				}
				if (this._currentPanel.shouldSkipPostTransition && !this._currentPanel.shouldSkipPostTransition()) {
					this._currentPanel.postTransition();
				}
				if (this._garbagePanels && this._garbagePanels.length) {
					this.finalizePurge();
				}
			}
		}

	});

})(enyo, this);
<|endoftext|>


<commit_before>/*
 * Helper class for cleaning nedb state
 */
"use strict";
var Promise = require("bluebird");
var promiseutil = require("../../lib/promiseutil");
var Datastore = require("nedb");

/**
 * Reset the database, wiping all data.
 * @param {String} databaseUri : The database URI to wipe all data from.
 * @return {Promise} Which is resolved when the database has been cleared.
 */
module.exports._reset = function(databaseUri) {
    if (databaseUri.indexOf("nedb://") !== 0) {
        return Promise.reject("Must be nedb:// URI");
    }
    var baseDbName = databaseUri.substring("nedb://".length);

    function delDatabase(name) {
        var d = promiseutil.defer();
        var db = new Datastore({
            filename: baseDbName + name,
            autoload: true,
            onload: function() {
                db.remove({}, {multi: true}, function(err, docs) {
                    if (err) {
                        console.error("db-helper %s Failed to delete: %s", name, err);
                        console.error(err.stack);
                        d.reject(err);
                        return;
                    }
                    d.resolve(docs);
                });
            }
        });
        return d.promise;
    }

    return Promise.all([
        delDatabase("/rooms.db"),
        delDatabase("/users.db"),
    ]);
};
<commit_msg>Delete the databases between tests rather than nuking all entries since that doesn't remove indexes<commit_after>/*
 * Helper class for cleaning nedb state
 */
"use strict";
var Promise = require("bluebird");
var fs = require("fs");
var promiseutil = require("../../lib/promiseutil");
var Datastore = require("nedb");

/**
 * Reset the database, wiping all data.
 * @param {String} databaseUri : The database URI to wipe all data from.
 * @return {Promise} Which is resolved when the database has been cleared.
 */
module.exports._reset = function(databaseUri) {
    if (databaseUri.indexOf("nedb://") !== 0) {
        return Promise.reject("Must be nedb:// URI");
    }
    var baseDbName = databaseUri.substring("nedb://".length);

    function delDatabase(name) {
        var dbPath = baseDbName + name;
        return new Promise(function(resolve, reject) {
            // nuke the world
            fs.unlink(dbPath, function(err) {
                if (err) {
                    if (err.code == "ENOENT") { // already deleted
                        resolve();
                    }
                    else {
                        reject(err);
                    }
                }
                else {
                    resolve();
                }
            });

        });
    }

    return Promise.all([
        delDatabase("/rooms.db"),
        delDatabase("/users.db"),
    ]);
};
<|endoftext|>


<commit_before>/***
|''Requires''|TiddlySpaceConfig|
***/
//{{{
(function($) {

if(config.options.chkBackstage === undefined) {
	config.options.chkBackstage = true;
}

config.backstageTasks = [];

config.tasks.login = {
	text: "login",
	tooltip: "TiddlySpace login",
	content: "<<tiddler BackstageLogin>>"
};
config.backstageTasks.push("login");

config.tasks.user = {
	text: "user: ",
	tooltip: "user control panel",
	content: "<<tiddler BackstageUser>>"
};
config.backstageTasks.push("user");

config.tasks.space = {
	text: "space: " + config.extensions.tiddlyspace.currentSpace.name,
	tooltip: "space control panel",
	content: "<<tiddler BackstageSpace>>",
	className: "right"
};
config.backstageTasks.push("space");

config.messages.backstage.prompt = "";
// initialize state
var _show = backstage.show;
backstage.show = function() {
	// selectively hide backstage tasks based on user status
	var tasks = $("#backstageToolbar .backstageTask").show();
	config.extensions.tiddlyweb.getUserInfo(function(user) {
		if(user.anon) {
			tasks.slice(1, 2).hide();
		} else {
			tasks.eq(0).hide();
		}
	});
	// display backstage
	return _show.apply(this, arguments);
};

var _init = backstage.init;
backstage.init = function(){
	_init.apply(this, arguments);

	var backstageArea = $("#backstageArea");

	// update usernames
	var userBtn = $(".backstageTask[task=user]").
		html('%0%1'.format([
			config.tasks.user.text, glyph("downTriangle")]));
	config.macros.option.handler($(".txtUserName", userBtn)[0], null, ["txtUserName"]);

	// make the backstage become visible when you mouseover it
	var _revealBackstageArea;
	$("#backstageButton").mouseover(function(ev) { // when mouseover the button set a timeout to show backstage
		if(!backstage.isVisible()){
			_revealBackstageArea = window.setTimeout(function() {
				if(!backstage.isVisible()) {
					backstage.show();
				}
			},"600");}
		}
	).
	mouseout(function(ev){ // on a mouseout we prevent showing of the backstage.
		if(_revealBackstageArea) {
			window.clearTimeout(_revealBackstageArea);
		}
	});

	// override show button with an svg image
	var showBtn = $("#backstageShow")[0];
	var altText = $(showBtn).text();
	$(showBtn).empty();
	invokeMacro(showBtn, "image", "backstage.svg 60 60 alt:%0".format([altText]), null);

	// override hide button
	var hideBtn = $("#backstageHide")[0];
	altText = $(hideBtn).text();
	$(hideBtn).empty();
	invokeMacro(hideBtn, "image", "close.svg 25 25 alt:%0".format([altText]), null);

	var backstageToolbar = $("#backstageToolbar")[0];
	$("
").prependTo(backstageToolbar);
	wikify("<<image tiddlyspace.svg 16 16>> ''{{privateLightText{tiddly}}}{{publicLightText{space}}}''",
		$("#backstageLogo", backstageToolbar)[0]); // XXX: macro invocation is evil

	var siteIcon = store.getTiddler("SiteIcon");
	if(siteIcon) {
		var btn = $("[task=space]", backstageArea);
		var existing = btn.text();
		btn.empty();
		$('').
			attr("src", "SiteIcon").appendTo(btn);
		$("").text(existing).appendTo(btn);

	}

	var tiddlyweb = config.extensions.tiddlyweb;
	tiddlyweb.getStatus(function(status) { // XXX: partial duplication of TiddlySpaceVisualization:getAvatar
		var server_host = status.server_host;
		var tsHost = server_host.scheme + "://" + server_host.host;
		if(server_host.port && server_host.port != "80" &&
			server_host.port != "443") {
			tsHost += ":" + server_host.port;
		}

		tiddlyweb.getUserInfo(function(user) {
			// show avatar in the users public bag
			if(!user.anon) {
				var src = "%0/recipes/%1_public/tiddlers/SiteIcon".
					format([tsHost, user.name]);
				$("").attr("src", src).appendTo("").
					appendTo("[task=user]", backstageArea);
			}
		});

		// show default avatar for the login button
		var loginBtn = $("[task=login]", backstageArea);
		var existing = loginBtn.text();
		loginBtn.html('%0'.
			format([existing]));

		var tasks = $(".backstageTask");
		for(var i = 0; i < tasks.length; i++) {
			var btn = $(tasks[i]);
			var taskName = btn.attr("task");
			btn.addClass("task_%0".format([taskName]));
		}
	});
};

})(jQuery);
//}}}
<commit_msg>turned off backstage hover effect<commit_after>/***
|''Requires''|TiddlySpaceConfig|
***/
//{{{
(function($) {

if(config.options.chkBackstage === undefined) {
	config.options.chkBackstage = true;
}

config.backstageTasks = [];

config.tasks.login = {
	text: "login",
	tooltip: "TiddlySpace login",
	content: "<<tiddler BackstageLogin>>"
};
config.backstageTasks.push("login");

config.tasks.user = {
	text: "user: ",
	tooltip: "user control panel",
	content: "<<tiddler BackstageUser>>"
};
config.backstageTasks.push("user");

config.tasks.space = {
	text: "space: " + config.extensions.tiddlyspace.currentSpace.name,
	tooltip: "space control panel",
	content: "<<tiddler BackstageSpace>>",
	className: "right"
};
config.backstageTasks.push("space");

config.messages.backstage.prompt = "";
// initialize state
var _show = backstage.show;
backstage.show = function() {
	// selectively hide backstage tasks based on user status
	var tasks = $("#backstageToolbar .backstageTask").show();
	config.extensions.tiddlyweb.getUserInfo(function(user) {
		if(user.anon) {
			tasks.slice(1, 2).hide();
		} else {
			tasks.eq(0).hide();
		}
	});
	// display backstage
	return _show.apply(this, arguments);
};

var _init = backstage.init;
backstage.init = function(){
	_init.apply(this, arguments);

	var backstageArea = $("#backstageArea");

	// update usernames
	var userBtn = $(".backstageTask[task=user]").
		html('%0%1'.format([
			config.tasks.user.text, glyph("downTriangle")]));
	config.macros.option.handler($(".txtUserName", userBtn)[0], null, ["txtUserName"]);

	// override show button with an svg image
	var showBtn = $("#backstageShow")[0];
	var altText = $(showBtn).text();
	$(showBtn).empty();
	invokeMacro(showBtn, "image", "backstage.svg 60 60 alt:%0".format([altText]), null);

	// override hide button
	var hideBtn = $("#backstageHide")[0];
	altText = $(hideBtn).text();
	$(hideBtn).empty();
	invokeMacro(hideBtn, "image", "close.svg 25 25 alt:%0".format([altText]), null);

	var backstageToolbar = $("#backstageToolbar")[0];
	$("
").prependTo(backstageToolbar);
	wikify("<<image tiddlyspace.svg 16 16>> ''{{privateLightText{tiddly}}}{{publicLightText{space}}}''",
		$("#backstageLogo", backstageToolbar)[0]); // XXX: macro invocation is evil

	var siteIcon = store.getTiddler("SiteIcon");
	if(siteIcon) {
		var btn = $("[task=space]", backstageArea);
		var existing = btn.text();
		btn.empty();
		$('').
			attr("src", "SiteIcon").appendTo(btn);
		$("").text(existing).appendTo(btn);

	}

	var tiddlyweb = config.extensions.tiddlyweb;
	tiddlyweb.getStatus(function(status) { // XXX: partial duplication of TiddlySpaceVisualization:getAvatar
		var server_host = status.server_host;
		var tsHost = server_host.scheme + "://" + server_host.host;
		if(server_host.port && server_host.port != "80" &&
			server_host.port != "443") {
			tsHost += ":" + server_host.port;
		}

		tiddlyweb.getUserInfo(function(user) {
			// show avatar in the users public bag
			if(!user.anon) {
				var src = "%0/recipes/%1_public/tiddlers/SiteIcon".
					format([tsHost, user.name]);
				$("").attr("src", src).appendTo("").
					appendTo("[task=user]", backstageArea);
			}
		});

		// show default avatar for the login button
		var loginBtn = $("[task=login]", backstageArea);
		var existing = loginBtn.text();
		loginBtn.html('%0'.
			format([existing]));

		var tasks = $(".backstageTask");
		for(var i = 0; i < tasks.length; i++) {
			var btn = $(tasks[i]);
			var taskName = btn.attr("task");
			btn.addClass("task_%0".format([taskName]));
		}
	});
};

})(jQuery);
//}}}
<|endoftext|>


<commit_before>/**!
 * AngularJS class extender
 * @author  Roy  <peled.roy@gmail.com>
 * @version 1.0.0
 */
(function() {
    var angularExtender = angular.module('ngExtender', []);

    angularExtender.factory('$extend', ['$injector', function($injector) {
        return function(currentScope){

            var abstracts = {};
            var bindedHandlers = [];
            currentScope.$super = {};

            currentScope.$abstract = function(name){
                abstracts[name] = true;
            }

            currentScope.$binded = function(handler){
                bindedHandlers.push(handler);
            }

            return {
                with: function(){
                    var klasses = arguments;
                    for(var i=0; i<klasses.length; i++){
                        $injector.instantiate(klasses[i], {$scope: currentScope});
                        for(var func in currentScope){
                            if(!/^(\$|this)/.test(func)){
                                currentScope.$super[func] = currentScope[func];
                            }
                        }
                    }

                    setTimeout(function(){
                        for(var func in abstracts){
                            if(!currentScope[func]){

                                // Uh-oh! It looks like someone declared an abstract but did not implement the method!

                                var allNodes = document.querySelectorAll("*");
                                var ctrl;
                                for(var i=0; i<allNodes.length; i++){
                                    var el = angular.element(allNodes[i]);
                                    ctrl = el.attr("ng-controller") || el.attr("ng:controller") || el.attr("data-ng-controller");
                                    var scope = el.scope();
                                    if(scope == currentScope)
                                        break;
                                }
                                throw new Error("Abstract method " + func + " must be overriden in "+ ctrl + "!");
                            }
                        }

                        while(bindedHandlers.length)
                            bindedHandlers.pop()();

                        currentScope.$digest();
                    }, 5);
                }
            }
        }
    }]);
})();<commit_msg>modified super methods to be returned from the extend method<commit_after>/**!
 * AngularJS class extender
 * @author  Roy  <peled.roy@gmail.com>
 * @version 1.0.0
 */
(function() {
    var angularExtender = angular.module('ngExtender', []);

    angularExtender.factory('$extend', ['$injector', function($injector) {
        return function(currentScope){

            var abstracts = {};
            var bindedHandlers = [];

            currentScope.$abstract = function(name){
                abstracts[name] = true;
            }

            currentScope.$binded = function(handler){
                bindedHandlers.push(handler);
            }

            return {
                with: function(){
                    var klasses = arguments;
                    var $super = {};

                    for(var i=0; i<klasses.length; i++){
                        $injector.instantiate(klasses[i], {$scope: currentScope});
                        for(var func in currentScope){
                            if(!/^(\$|this)/.test(func)){
                                $super[func] = currentScope[func];
                                currentScope.$super[func] = currentScope[func];
                            }
                        }
                    }

                    setTimeout(function(){
                        for(var func in abstracts){
                            if(!currentScope[func]){

                                // Uh-oh! It looks like someone declared an abstract but did not implement the method!

                                var allNodes = document.querySelectorAll("*");
                                var ctrl;
                                for(var i=0; i<allNodes.length; i++){
                                    var el = angular.element(allNodes[i]);
                                    ctrl = el.attr("ng-controller") || el.attr("ng:controller") || el.attr("data-ng-controller");
                                    var scope = el.scope();
                                    if(scope == currentScope)
                                        break;
                                }
                                throw new Error("Abstract method " + func + " must be overriden in "+ ctrl + "!");
                            }
                        }

                        while(bindedHandlers.length)
                            bindedHandlers.pop()();

                        currentScope.$digest();
                    }, 5);

                    return $super;
                }
            }
        }
    }]);
})();<|endoftext|>


<commit_before>"use strict";

var requireUser = require('../../lib/apps/auth').requireUser;
var format = require('util').format;
var config = require('config');
var Error404 = require('../../lib/errors').Error404;
var _ = require('underscore');
var PopIt = require('../../lib/popit');
var async = require('async');

exports.route = function (app) {

  app.get('/', function(req, res){
    // Redirect production site to the documentation site for now.
    // TODO: Undo this once we're happy with the homepage.
    if (req.host === 'popit.mysociety.org') {
      res.redirect('http://popit.poplus.org/');
    } else {
      res.render('index.html');
    }
  });

  app.get('/instances/new', requireUser, function(req, res, next) {
    res.locals.errors = {};
    res.locals.slug = '';
    res.render('instance_new.html');
  });

  app.post('/instances/new', requireUser, function(req, res, next) {
    var slug = res.locals.slug = req.param('slug', '').trim();
    var Instance = req.popit.model('Instance');
    var Permission = req.popit.permissions();
    var instance = new Instance();
    instance.slug = slug;
    instance.email = req.user.email;
    instance.status = 'active';
    instance.save(function(err, newInstance) {
      if (err) {
        res.locals.errors = err.errors;
        res.locals.existing_instance_url = instance.base_url;
        return res.render('instance_new.html');
      }
      // Make the user owner of the instance
      Permission.create({
        account: req.user._id,
        instance: newInstance._id,
        role: 'owner',
      }, function(err) {
        if (err) {
          return next(err);
        }
        res.redirect('/instances/' + slug);
      });
    });
  });

  app.get('/instances/:slug', function(req, res) {
    res.redirect(format(config.instance_server.base_url_format, req.param('slug')));
  });

  function findInstances(req, res, next) {
    req.instances = res.locals.instances = [];
    req.popit.model('Instance').find(function(err, instances) {
      if (err) {
        return next(err);
      }
      req.all_instances = res.locals.all_instances = instances;
      if (!req.user) {
        return next();
      }

      req.popit.permissions().find({ account: req.user.id }).populate('instance').exec(function(err, permissions) {
        if (err) {
          return next(err);
        }
        req.instances = res.locals.instances = permissions.map(function(permission) {
          return permission.instance;
        });

        next();
      });
    });
  }

  app.get('/instances', findInstances, function(req, res, next){
    res.render('instances.html');
  });

  app.get('/instances.json', findInstances, function(req, res, next) {
    if (!req.user) {
      return res.status(401).jsonp({ errors: ["You are not authenticated"] });
    }
    async.map(req.instances, function(instance, done) {
      var details = _.pick(instance, 'slug', 'created_date', 'base_url');
      var popit = new PopIt();
      popit.set_instance(instance.slug);
      popit.load_settings(function(err) {
        if (err) {
          return done(err);
        }
        _.extend(details, popit._get_cached_settings());
        done(null, details);
      });
    }, function(err, result) {
      if (err) {
        return next(err);
      }
      res.jsonp({ result: result });
    });
  });

  // Throw a 404 error
  app.all('/*', function(req, res, next) {
    next(new Error404());
  });
};
<commit_msg>Filter out false values from instance settings<commit_after>"use strict";

var requireUser = require('../../lib/apps/auth').requireUser;
var format = require('util').format;
var config = require('config');
var Error404 = require('../../lib/errors').Error404;
var _ = require('underscore');
var PopIt = require('../../lib/popit');
var async = require('async');

exports.route = function (app) {

  app.get('/', function(req, res){
    // Redirect production site to the documentation site for now.
    // TODO: Undo this once we're happy with the homepage.
    if (req.host === 'popit.mysociety.org') {
      res.redirect('http://popit.poplus.org/');
    } else {
      res.render('index.html');
    }
  });

  app.get('/instances/new', requireUser, function(req, res, next) {
    res.locals.errors = {};
    res.locals.slug = '';
    res.render('instance_new.html');
  });

  app.post('/instances/new', requireUser, function(req, res, next) {
    var slug = res.locals.slug = req.param('slug', '').trim();
    var Instance = req.popit.model('Instance');
    var Permission = req.popit.permissions();
    var instance = new Instance();
    instance.slug = slug;
    instance.email = req.user.email;
    instance.status = 'active';
    instance.save(function(err, newInstance) {
      if (err) {
        res.locals.errors = err.errors;
        res.locals.existing_instance_url = instance.base_url;
        return res.render('instance_new.html');
      }
      // Make the user owner of the instance
      Permission.create({
        account: req.user._id,
        instance: newInstance._id,
        role: 'owner',
      }, function(err) {
        if (err) {
          return next(err);
        }
        res.redirect('/instances/' + slug);
      });
    });
  });

  app.get('/instances/:slug', function(req, res) {
    res.redirect(format(config.instance_server.base_url_format, req.param('slug')));
  });

  function findInstances(req, res, next) {
    req.instances = res.locals.instances = [];
    req.popit.model('Instance').find(function(err, instances) {
      if (err) {
        return next(err);
      }
      req.all_instances = res.locals.all_instances = instances;
      if (!req.user) {
        return next();
      }

      req.popit.permissions().find({ account: req.user.id }).populate('instance').exec(function(err, permissions) {
        if (err) {
          return next(err);
        }
        req.instances = res.locals.instances = permissions.map(function(permission) {
          return permission.instance;
        });

        next();
      });
    });
  }

  app.get('/instances', findInstances, function(req, res, next){
    res.render('instances.html');
  });

  app.get('/instances.json', findInstances, function(req, res, next) {
    if (!req.user) {
      return res.status(401).jsonp({ errors: ["You are not authenticated"] });
    }
    async.map(req.instances, function(instance, done) {
      var details = _.pick(instance, 'slug', 'created_date', 'base_url');
      var popit = new PopIt();
      popit.set_instance(instance.slug);
      popit.load_settings(function(err) {
        if (err) {
          return done(err);
        }
        var settings = popit._get_cached_settings();
        _.each(settings, function(value, key) {
          // Check that value is truth-y
          if (value) {
            details[key] = value;
          }
        });
        done(null, details);
      });
    }, function(err, result) {
      if (err) {
        return next(err);
      }
      res.jsonp({ result: result });
    });
  });

  // Throw a 404 error
  app.all('/*', function(req, res, next) {
    next(new Error404());
  });
};
<|endoftext|>


<commit_before>/*global $, emojify: true, escapeHTML:true, nw, autosize, twemoji */
var fs = nw.require('fs');
var async = nw.require('async');
/* var; TODO: use it */ escapeHTML = nw.require('lodash.escape');
var iconv = nw.require('iconv-lite');

/* var; TODO: use it */ emojify = () => {
   if( twemoji ) twemoji.parse( $('body')[0] );
};

var errorCLI = errHTML => $('.purposeMain').html([
   '
',
   errHTML, '
'
].join(''));

var convertFileToText = (filePath, fileDone) => async.waterfall([
   callback => fs.readFile(filePath, callback),
   (fileBuf, callback) => callback(null,
      iconv.decode(fileBuf, 'cp866')
   )
], fileDone);

$(() => {
   var paramsCLI = nw.App.argv;

   var msgFilePath = paramsCLI.find( param => param.startsWith('--file=') );
   if( typeof msgFilePath === 'undefined') return errorCLI(
      'Filename has not been given.'
   );
   msgFilePath = msgFilePath.slice( '--file='.length );

   var lineNum = paramsCLI.find( param => param.startsWith('--line=') );
   if( typeof lineNum === 'undefined') return errorCLI(
      'Line number has not been given.'
   );
   lineNum = lineNum.slice( '--line='.length );

   convertFileToText(msgFilePath, (err, fileText) => {
      if( err ) return errorCLI(`Error reading «${msgFilePath}».`);

      $('.purposeMain').html(`<textarea>${fileText}</textarea>`);
      autosize($('.purposeMain textarea'));
   });
});
<commit_msg>enter fullscreen mode when things are understood to be alright<commit_after>/*global $, emojify: true, escapeHTML:true, nw, autosize, twemoji */
var fs = nw.require('fs');
var async = nw.require('async');
/* var; TODO: use it */ escapeHTML = nw.require('lodash.escape');
var iconv = nw.require('iconv-lite');

/* var; TODO: use it */ emojify = () => {
   if( twemoji ) twemoji.parse( $('body')[0] );
};

var errorCLI = errHTML => $('.purposeMain').html([
   '
',
   errHTML, '
'
].join(''));

var convertFileToText = (filePath, fileDone) => async.waterfall([
   callback => fs.readFile(filePath, callback),
   (fileBuf, callback) => callback(null,
      iconv.decode(fileBuf, 'cp866')
   )
], fileDone);

$(() => {
   var paramsCLI = nw.App.argv;

   var msgFilePath = paramsCLI.find( param => param.startsWith('--file=') );
   if( typeof msgFilePath === 'undefined') return errorCLI(
      'Filename has not been given.'
   );
   msgFilePath = msgFilePath.slice( '--file='.length );

   var lineNum = paramsCLI.find( param => param.startsWith('--line=') );
   if( typeof lineNum === 'undefined') return errorCLI(
      'Line number has not been given.'
   );
   lineNum = lineNum.slice( '--line='.length );

   convertFileToText(msgFilePath, (err, fileText) => {
      if( err ) return errorCLI(`Error reading «${msgFilePath}».`);

      nw.Window.get().maximize();

      $('.purposeMain').html(`<textarea>${fileText}</textarea>`);
      autosize($('.purposeMain textarea'));
   });
});
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

// Provides class sap.ui.core.util.File
sap.ui.define(['jquery.sap.global', 'sap/ui/Device'],
	function(jQuery, Device) {
	'use strict';

	/**
	 * Utility class to handle files.
	 *
	 * @class Utility class to handle files
	 * @author SAP SE
	 * @version ${version}
	 * @static
	 *
	 * @public
	 * @since 1.22.0
	 * @alias sap.ui.core.util.File
	 */
	var File = {

		/**
		 *
Triggers a download / save action of the given file.

		 *
		 *
There are limitations for this feature in some browsers:

		 *
		 *
Internet Explorer 8 / 9

		 * Some file extensions on some operating systems are not working due to a bug in IE.
		 * Therefore 'txt' will be used as file extension if the problem is occurring.

		 *
		 *
Safari (OS X / iOS)

		 * A new window/tab will be opened. In OS X the user has to manually save the file (CMD + S), choose "page source" and specify a filename.
		 * In iOS the content can be opened in another app (Mail, Notes, ...) or copied to the clipboard.
		 * In case the popup blocker prevents this action, an error will be thrown which can be used to notify the user to disable it.

		 *
		 *
Android Browser

		 * Not supported

		 *
		 * @param {string} sData file content
		 * @param {string} sFileName file name
		 * @param {string} sFileExtension file extension
		 * @param {string} sMimeType file mime-type
		 * @param {string} sCharset file charset
		 *
		 * @public
		 */
		save: function(sData, sFileName, sFileExtension, sMimeType, sCharset) {
			var sFullFileName = sFileName + '.' + sFileExtension;

			// prepend utf-8 byte-order-mark (BOM) to prevent encoding issues in .csv files
			if (sCharset === 'utf-8' && sFileExtension === 'csv') {
				sData = '\ufeff' + sData;
			}

			if (window.Blob) {
				var sType = 'data:' + sMimeType;
				if (sCharset) {
					sType += ';charset=' + sCharset;
				}
				var oBlob = new window.Blob([ sData ], { type: sType });

				// IE 10+ (native saveAs FileAPI)
				if (window.navigator.msSaveOrOpenBlob) {
					window.navigator.msSaveOrOpenBlob(oBlob, sFullFileName);
				} else {
					var oURL = window.URL || window.webkitURL;
					var sBlobUrl = oURL.createObjectURL(oBlob);

					var oLink = window.document.createElement('a');
					if ('download' in oLink) {
						// use an anchor link with download attribute for download
						var $body = jQuery(document.body);
						var $link = jQuery(oLink).attr({
							download: sFullFileName,
							href: sBlobUrl,
							style: 'display:none'
						});
						$body.append($link);
						$link.get(0).click();

						$link.remove();
					} else {
						// Make sure to encode the data to be used in data-uri
						sData = encodeURI(sData);

						// Safari (user has to save the file manually)
						var oWindow = window.open(sType + ";" + sData);
						if (!oWindow) {
							throw new Error("Could not download file. A popup blocker might be active.");
						}
					}
				}
			} else if (Device.browser.internet_explorer && Device.browser.version === 9) {
				// iframe fallback for IE9
				var $body = jQuery(document.body);
				var $iframe = jQuery('', {
					style: 'display:none'
				});
				$body.append($iframe);
				var oDocument = $iframe.get(0).contentWindow.document;
				// open the document to be able to modify it
				oDocument.open(sMimeType, 'replace');
				// set charset (e.g. utf-8) if given
				if (sCharset) {
					oDocument.charset = sCharset;
				}
				// write content to iframe
				oDocument.write(sData);
				oDocument.close();

				// open the file-save dialog
				// measure the time that the execCommand takes to detect an
				// IE bug with some file extensions on some OS (e.g. Windows Server 2008 E2 Enterprise SP1) in all IE versions:
				// http://stackoverflow.com/questions/2515791/execcommandsaveas-null-file-csv-is-not-working-in-ie8
				var oTime = new Date();
				var bSuccess = oDocument.execCommand('SaveAs', false, sFullFileName);
				if (!bSuccess && new Date() - oTime < 10) {
					// execCommand returns false either when the user clicks on cancel or
					// when the bug mentioned above is occurring, so the time is measured
					// to detect the cancel action

					// .txt as file extension will work on all systems
					oDocument.execCommand('SaveAs', false, sFullFileName + '.txt');
				}

				// cleanup
				$iframe.remove();
			}
		}
	};

	return File;
}, /* bExport= */ true);
<commit_msg>[FIX] sap.ui.core.util.File: Wrong data-url delimiter<commit_after>/*!
 * ${copyright}
 */

// Provides class sap.ui.core.util.File
sap.ui.define(['jquery.sap.global', 'sap/ui/Device'],
	function(jQuery, Device) {
	'use strict';

	/**
	 * Utility class to handle files.
	 *
	 * @class Utility class to handle files
	 * @author SAP SE
	 * @version ${version}
	 * @static
	 *
	 * @public
	 * @since 1.22.0
	 * @alias sap.ui.core.util.File
	 */
	var File = {

		/**
		 *
Triggers a download / save action of the given file.

		 *
		 *
There are limitations for this feature in some browsers:

		 *
		 *
Internet Explorer 8 / 9

		 * Some file extensions on some operating systems are not working due to a bug in IE.
		 * Therefore 'txt' will be used as file extension if the problem is occurring.

		 *
		 *
Safari (OS X / iOS)

		 * A new window/tab will be opened. In OS X the user has to manually save the file (CMD + S), choose "page source" and specify a filename.
		 * In iOS the content can be opened in another app (Mail, Notes, ...) or copied to the clipboard.
		 * In case the popup blocker prevents this action, an error will be thrown which can be used to notify the user to disable it.

		 *
		 *
Android Browser

		 * Not supported

		 *
		 * @param {string} sData file content
		 * @param {string} sFileName file name
		 * @param {string} sFileExtension file extension
		 * @param {string} sMimeType file mime-type
		 * @param {string} sCharset file charset
		 *
		 * @public
		 */
		save: function(sData, sFileName, sFileExtension, sMimeType, sCharset) {
			var sFullFileName = sFileName + '.' + sFileExtension;

			// prepend utf-8 byte-order-mark (BOM) to prevent encoding issues in .csv files
			if (sCharset === 'utf-8' && sFileExtension === 'csv') {
				sData = '\ufeff' + sData;
			}

			if (window.Blob) {
				var sType = 'data:' + sMimeType;
				if (sCharset) {
					sType += ';charset=' + sCharset;
				}
				var oBlob = new window.Blob([ sData ], { type: sType });

				// IE 10+ (native saveAs FileAPI)
				if (window.navigator.msSaveOrOpenBlob) {
					window.navigator.msSaveOrOpenBlob(oBlob, sFullFileName);
				} else {
					var oURL = window.URL || window.webkitURL;
					var sBlobUrl = oURL.createObjectURL(oBlob);

					var oLink = window.document.createElement('a');
					if ('download' in oLink) {
						// use an anchor link with download attribute for download
						var $body = jQuery(document.body);
						var $link = jQuery(oLink).attr({
							download: sFullFileName,
							href: sBlobUrl,
							style: 'display:none'
						});
						$body.append($link);
						$link.get(0).click();

						$link.remove();
					} else {
						// Make sure to encode the data to be used in data-uri
						sData = encodeURI(sData);

						// Safari (user has to save the file manually)
						var oWindow = window.open(sType + "," + sData);
						if (!oWindow) {
							throw new Error("Could not download file. A popup blocker might be active.");
						}
					}
				}
			} else if (Device.browser.internet_explorer && Device.browser.version === 9) {
				// iframe fallback for IE9
				var $body = jQuery(document.body);
				var $iframe = jQuery('', {
					style: 'display:none'
				});
				$body.append($iframe);
				var oDocument = $iframe.get(0).contentWindow.document;
				// open the document to be able to modify it
				oDocument.open(sMimeType, 'replace');
				// set charset (e.g. utf-8) if given
				if (sCharset) {
					oDocument.charset = sCharset;
				}
				// write content to iframe
				oDocument.write(sData);
				oDocument.close();

				// open the file-save dialog
				// measure the time that the execCommand takes to detect an
				// IE bug with some file extensions on some OS (e.g. Windows Server 2008 E2 Enterprise SP1) in all IE versions:
				// http://stackoverflow.com/questions/2515791/execcommandsaveas-null-file-csv-is-not-working-in-ie8
				var oTime = new Date();
				var bSuccess = oDocument.execCommand('SaveAs', false, sFullFileName);
				if (!bSuccess && new Date() - oTime < 10) {
					// execCommand returns false either when the user clicks on cancel or
					// when the bug mentioned above is occurring, so the time is measured
					// to detect the cancel action

					// .txt as file extension will work on all systems
					oDocument.execCommand('SaveAs', false, sFullFileName + '.txt');
				}

				// cleanup
				$iframe.remove();
			}
		}
	};

	return File;
}, /* bExport= */ true);
<|endoftext|>