<commit_before>/**
 *
 * Fastly API client for promise based control flow.
 *
 * @package fastly-promise
 * @author Reid Mayo <reidmayo@gmail.com>
 *
 */

'use strict';

//Dependencies
var requestP = require('request-promise');
var ramda = require('ramda');
var Promise = require('bluebird');

/**
 *
 * Constructor
 *
 * @param {string} apiKey
 * @returns {FastlyPromise}
 * @constructor
 */
var FastlyPromise = function FastlyPromise(apiKey) {
  if(!(this instanceof FastlyPromise)) {
    if(!apiKey){
      throw new Error('Missing API key parameter.');
    }else {
      return new FastlyPromise(apiKey);
    }
  }

  this.apiKey = apiKey;
  this.endpoint = 'https://api.fastly.com';

}

/**
 *
 * Generic request method that all convenience request methods extend.
 *
 * Use this method if a convenience method does not already exist for your use case.
 *
 * @param {string} method - http method to use.
 * @param {string} url
 * @param {object} [options={}] - optional params
 * @returns {object|array|string} response from fastly.
 *
 * The following options are available
 * {boolean} options.softPurge - Make purge requests to fastly "soft purges".
 * {object} options.headers - Arbitrary headers to be sent with request.
 * {object} options.form - POST body data encoded as application/x-www-form-urlencoded to be sent with request.
 * {object} options.requestPromiseOptions - Allows you to directly set or overwrite request-promise options for edge cases.
 *
 */
FastlyPromise.prototype.request = function request(method, url, options) {

  //Validate params
  if (!method || !url) {
    throw new Error('Missing required request parameters.');
  }

  //Point relative urls to fastly endpoint
  if(!/^((http|https):\/\/)/.test(url)) {
    url = this.endpoint + url;
  }

  //Set default options
  options = options || {};
  options.softPurge = (typeof options.softPurge == "undefined") ? false : options.softPurge;

  //Set headers
  var headers = {'Fastly-Key': this.apiKey};
  if (options.softPurge){ headers['Fastly-Soft-Purge'] = 1; }
  if (options.headers) { headers = ramda.merge(headers, options.headers); }

  //Strip API key header if request is not pointed to fastly endpoint
  if(url.substring(0, this.endpoint.length) !== this.endpoint) {
    delete headers['Fastly-Key'];
  }

  //Build request-promise options
  var requestPromiseOptions = {
    method: method,
    uri: url,
    headers: headers,
    resolveWithFullResponse: true
  };

  //Attach form payload if exists
  if (options.form) { requestPromiseOptions.form = options.form; }

  //Set/Overwrite requestPromiseOptions
  if (options.requestPromiseOptions) { requestPromiseOptions = ramda.merge(requestPromiseOptions, options.requestPromiseOptions); }

  //Fire request, process response.
  return requestP(requestPromiseOptions)
    .then(function(response){
      return (response.headers['content-type'] == 'application/json') ? JSON.parse(response.body) : response.body;
    });

}

/**
 *
 * Purge a url.
 *
 * @param {string} url - Fully qualified url of resource you want to purge.
 * @param {boolean} [softPurge=false] - Soft purge instead of standard purge. Defaults to false.
 * @returns {object} - Fastly purge response.
 */
FastlyPromise.prototype.purge = function purge(url, softPurge) {

  //Purge request urls should be absolute
  if(!/^((http|https):\/\/)/.test(url)) {
    throw new Error('Standard purge requests should be absolute urls.');
  }

  softPurge = (typeof softPurge == 'undefined') ? false : softPurge;

  return this.request('PURGE', url, {softPurge: softPurge});

}

/**
 *
 * Hard purge all objects from a service.
 *
 * @param {string} serviceId - The fastly service id.
 * @returns {object} - Fastly purge response.
 */
FastlyPromise.prototype.purgeAll = function purgeAll(serviceId) {

  return this.request('POST', this.endpoint + '/service/' + serviceId + '/purge_all');

}

/**
 *
 * Purge a fastly surrogate key.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} key - The surrogate key you wish to purge.
 * @param {boolean} [softPurge=false] - Soft purge instead of standard purge. Defaults to false.
 * @returns {object} - Fastly purge response.
 */
FastlyPromise.prototype.purgeKey = function purgeKey(serviceId, surrogateKey, softPurge) {

  softPurge = (typeof softPurge == 'undefined') ? false : softPurge;

  return this.request('POST', this.endpoint + '/service/' + serviceId + '/purge/' +  surrogateKey, {softPurge: softPurge});

}

/**
 *
 * Get list of config versions for a service.
 *
 * @param {string} serviceId - The fastly service id.
 * @returns {array} - Array of config versions objects.
 */
FastlyPromise.prototype.getConfigVersions = function getConfigVersions(serviceId) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version');

}

/**
 *
 * Get config version for a service.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Config version object.
 */
FastlyPromise.prototype.getConfigVersion = function getConfigVersion(serviceId, configVersionNumber) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber);

}

/**
 *
 * Get active config version for a service.
 *
 * @param serviceId
 * @returns {object} - Active config version object.
 */
FastlyPromise.prototype.getActiveConfigVersion = function getActiveConfigVersion(serviceId) {

  return this.getConfigVersions(serviceId)
    .then(function(configVersions){

      return configVersions.find(function(configVersion){
        return configVersion.active;
      });

    });

}

/**
 *
 * Validate the config for a particular service and version.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Fastly validation response object
 */
FastlyPromise.prototype.validateConfigVersion = function validateConfigVersion(serviceId, configVersionNumber) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/validate');

}

/**
 *
 * Create a config version for a particular service.
 *
 * @param {string} serviceId - The fastly service id.
 * @returns {object} - New config version object.
 */
FastlyPromise.prototype.createConfigVersion = function createConfigVersion(serviceId) {

  return this.request('POST', this.endpoint + '/service/' + serviceId + '/version');

}

/**
 *
 * Activate a config version.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Config version object
 */
FastlyPromise.prototype.activateConfigVersion = function activateConfigVersion(serviceId, configVersionNumber) {

  return this.request('PUT', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/activate');

}

/**
 *
 * Deactivate a config version.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Config version object
 */
FastlyPromise.prototype.deactivateConfigVersion = function deactivateConfigVersion(serviceId, configVersionNumber) {

  return this.request('PUT', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/deactivate');

}

/**
 *
 * Clone a service configuration by config version number. Config number defaults to the number of the "active" configuration.
 *
 * @param serviceId
 * @param [configVersionNumber] - Defaults to active config version.
 * @returns {object} - Config version object
 */
FastlyPromise.prototype.cloneConfigVersion = function cloneConfigVersion(serviceId, configVersionNumber) {
  var self = this;

  //Set default config version number to active version if not explicitly defined.
  var configVersionNumberPromise = configVersionNumber ? Promise.resolve(configVersionNumber) : self.getActiveConfigVersion(serviceId).then(function(version){ return version.number });

  return configVersionNumberPromise.then(function(configVersionNumber){
    return self.request('PUT', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/clone');
  });

}

/**
 *
 * Lock a config version.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Config version object
 */
FastlyPromise.prototype.lockConfigVersion = function lockConfigVersion(serviceId, configVersionNumber) {

  return this.request('PUT', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/lock');

}

/**
 *
 * Get boilerplate VCL with the service's TTL from the settings.
 *
 * @param serviceId
 * @param configVersionNumber
 * @returns {string} - utf8 encoded text/html VCL string.
 */
FastlyPromise.prototype.getBoilerplateVcl = function getBoilerplateVcl(serviceId, configVersionNumber) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/boilerplate');

}

/**
 *
 * Get a list of service VCLs by config version.
 *
 * @param serviceId
 * @param configVersionNumber
 * @returns {array} - Array of VCL objects.
 */
FastlyPromise.prototype.getAllVcl = function getAllVcl(serviceId, configVersionNumber) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl');

}

/**
 *
 * Get a service VCL by config version and name.
 *
 * @param serviceId
 * @param configVersionNumber
 * @param vclName
 * @returns {object} - VCL object.
 */
FastlyPromise.prototype.getVcl = function getVcl(serviceId, configVersionNumber, vclName) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl/' + vclName);

}

/**
 *
 * Get the current "main" VCL for a service.
 *
 * @param {string} serviceId
 * @param {string} [configVersionNumber] - If no config version number is passed, defaults to active config version.
 * @returns {object} - VCL object.
 */
FastlyPromise.prototype.getMainVcl = function getMainVcl(serviceId, configVersionNumber) {
  var self = this;

  //Set default config version number to active version if not explicitly defined.
  var configVersionNumberPromise = configVersionNumber ? Promise.resolve(configVersionNumber) : self.getActiveConfigVersion(serviceId).then(function(version){ return version.number });

  return configVersionNumberPromise
    .then(function(configVersionNumber){
      return self.getAllVcl(serviceId, configVersionNumber);
  })
    .then(function(vclList){

      return vclList.find(function(vcl){
        return vcl.main;
      });

    });

}

/**
 *
 * Set the specified VCL as main
 *
 * @param {string} serviceId
 * @param {string} vclName
 * @param {string} [configVersionNumber] - If no config version number is passed, defaults to active config version.
 * @returns {object} - VCL object.
 */
FastlyPromise.prototype.setMainVcl = function setMainVcl(serviceId, vclName, configVersionNumber) {
  var self = this;

  //Set default config version number to active version if not explicitly defined.
  var configVersionNumberPromise = configVersionNumber ? Promise.resolve(configVersionNumber) : self.getActiveConfigVersion(serviceId).then(function(version){ return version.number });

  return configVersionNumberPromise
    .then(function(configVersionNumber){
      return self.request('PUT', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl/' + vclName + '/main');
    });

}

/**
 *
 * Upload new VCL to a service. Throws error if VCL with same name already exists.
 *
 * @param {string} serviceId
 * @param {string} configVersionNumber - Service config version number.
 * @param {string} vclName - Name of vcl file.
 * @param {string} vclContent - The VCL content to be uploaded.
 * @param {boolean} [setVclToMain=false] - Set the uploaded vcl to be the service's "main" vcl.
 * @returns {object} - VCL object.
 */
FastlyPromise.prototype.uploadNewVcl = function uploadNewVcl(serviceId, configVersionNumber, vclName, vclContent, setVclToMain) {
  var self = this;

  setVclToMain = setVclToMain || false;

  var validNamePromise = self.getVcl(serviceId, configVersionNumber, vclName)
    .then(function(response){

      return false; //Invalid if vcl with this name already exists

    })
    .catch(function(errorResponse){

      //If response code is 404 then new vcl name is valid.
      return (errorResponse.statusCode == 404) ? true : false;

    });

  return validNamePromise
    .then(function(validName){

      if (!validName){
        throw new Error('Error: ' + vclName + ' VCL file already exists.');
      }
      else{

        //Upload the VCL
        return self.request('POST', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl', {
          form: {
            name: vclName,
            content: vclContent
          }
        });

      }

    })
    .then(function(vclResponse){

      //Set VCL to "main" if flagged.
      if (setVclToMain){
        return self.setMainVcl(serviceId, vclName, configVersionNumber);
      }
      else{
        return vclResponse;
      }

    });

}

/**
 *
 * Update existing VCL file.
 *
 * @param {string} serviceId
 * @param {string} configVersionNumber - Service config version number.
 * @param {string} vclName - Name of vcl file.
 * @param {string} vclContent - The new VCL content.
 * @param {boolean} [setVclToMain=false] - Set the updated vcl to be the service's "main" vcl.
 * @returns {object} - VCL object.
 */
FastlyPromise.prototype.updateVcl = function updateVcl(serviceId, configVersionNumber, vclName, vclContent, setVclToMain) {
  var self = this;

  setVclToMain = setVclToMain || false;

  //Upload the VCL
  return self.request('PUT', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl/' + vclName, {
      form: {
        content: vclContent
      }
    })
    .then(function(vclResponse){

      //Set VCL to "main" if flagged.
      if (setVclToMain){
        return self.setMainVcl(serviceId, vclName, configVersionNumber);
      }
      else{
        return vclResponse;
      }

    });

}

/**
 *
 * Delete the specified VCL file.
 *
 * @param {string} serviceId
 * @param {string} vclName
 * @param {string} [configVersionNumber] - If no config version number is passed, defaults to active config version.
 * @returns {object} - Fastly VCL delete status object.
 */
FastlyPromise.prototype.deleteVcl = function deleteVcl(serviceId, vclName, configVersionNumber) {
  var self = this;

  //Set default config version number to active version if not explicitly defined.
  var configVersionNumberPromise = configVersionNumber ? Promise.resolve(configVersionNumber) : self.getActiveConfigVersion(serviceId).then(function(version){ return version.number });

  return configVersionNumberPromise
    .then(function(configVersionNumber){
      return self.request('DELETE', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl/' + vclName);
    });

}

module.exports = FastlyPromise;<commit_msg>Adding throws documentation where appropriate.<commit_after>/**
 *
 * Fastly API client for promise based control flow.
 *
 * @package fastly-promise
 * @author Reid Mayo <reidmayo@gmail.com>
 *
 */

'use strict';

//Dependencies
var requestP = require('request-promise');
var ramda = require('ramda');
var Promise = require('bluebird');

/**
 *
 * Constructor
 *
 * @param {string} apiKey
 * @returns {FastlyPromise}
 * @constructor
 */
var FastlyPromise = function FastlyPromise(apiKey) {
  if(!(this instanceof FastlyPromise)) {
    if(!apiKey){
      throw new Error('Missing API key parameter.');
    }else {
      return new FastlyPromise(apiKey);
    }
  }

  this.apiKey = apiKey;
  this.endpoint = 'https://api.fastly.com';

}

/**
 *
 * Generic request method that all convenience request methods extend.
 *
 * Use this method if a convenience method does not already exist for your use case.
 *
 * @param {string} method - http method to use.
 * @param {string} url
 * @param {object} [options={}] - optional params
 * @returns {object|array|string} response from fastly.
 * @throws Will throw error if missing required method or url params.
 *
 * The following options are available
 * {boolean} options.softPurge - Make purge requests to fastly "soft purges".
 * {object} options.headers - Arbitrary headers to be sent with request.
 * {object} options.form - POST body data encoded as application/x-www-form-urlencoded to be sent with request.
 * {object} options.requestPromiseOptions - Allows you to directly set or overwrite request-promise options for edge cases.
 *
 */
FastlyPromise.prototype.request = function request(method, url, options) {

  //Validate params
  if (!method || !url) {
    throw new Error('Missing required request parameters.');
  }

  //Point relative urls to fastly endpoint
  if(!/^((http|https):\/\/)/.test(url)) {
    url = this.endpoint + url;
  }

  //Set default options
  options = options || {};
  options.softPurge = (typeof options.softPurge == "undefined") ? false : options.softPurge;

  //Set headers
  var headers = {'Fastly-Key': this.apiKey};
  if (options.softPurge){ headers['Fastly-Soft-Purge'] = 1; }
  if (options.headers) { headers = ramda.merge(headers, options.headers); }

  //Strip API key header if request is not pointed to fastly endpoint
  if(url.substring(0, this.endpoint.length) !== this.endpoint) {
    delete headers['Fastly-Key'];
  }

  //Build request-promise options
  var requestPromiseOptions = {
    method: method,
    uri: url,
    headers: headers,
    resolveWithFullResponse: true
  };

  //Attach form payload if exists
  if (options.form) { requestPromiseOptions.form = options.form; }

  //Set/Overwrite requestPromiseOptions
  if (options.requestPromiseOptions) { requestPromiseOptions = ramda.merge(requestPromiseOptions, options.requestPromiseOptions); }

  //Fire request, process response.
  return requestP(requestPromiseOptions)
    .then(function(response){
      return (response.headers['content-type'] == 'application/json') ? JSON.parse(response.body) : response.body;
    });

}

/**
 *
 * Purge a url.
 *
 * @param {string} url - Fully qualified url of resource you want to purge.
 * @param {boolean} [softPurge=false] - Soft purge instead of standard purge. Defaults to false.
 * @returns {object} - Fastly purge response.
 * @throws Will throw error if url param is not absolute.
 */
FastlyPromise.prototype.purge = function purge(url, softPurge) {

  //Purge request urls should be absolute
  if(!/^((http|https):\/\/)/.test(url)) {
    throw new Error('Standard purge requests should be absolute urls.');
  }

  softPurge = (typeof softPurge == 'undefined') ? false : softPurge;

  return this.request('PURGE', url, {softPurge: softPurge});

}

/**
 *
 * Hard purge all objects from a service.
 *
 * @param {string} serviceId - The fastly service id.
 * @returns {object} - Fastly purge response.
 */
FastlyPromise.prototype.purgeAll = function purgeAll(serviceId) {

  return this.request('POST', this.endpoint + '/service/' + serviceId + '/purge_all');

}

/**
 *
 * Purge a fastly surrogate key.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} key - The surrogate key you wish to purge.
 * @param {boolean} [softPurge=false] - Soft purge instead of standard purge. Defaults to false.
 * @returns {object} - Fastly purge response.
 */
FastlyPromise.prototype.purgeKey = function purgeKey(serviceId, surrogateKey, softPurge) {

  softPurge = (typeof softPurge == 'undefined') ? false : softPurge;

  return this.request('POST', this.endpoint + '/service/' + serviceId + '/purge/' +  surrogateKey, {softPurge: softPurge});

}

/**
 *
 * Get list of config versions for a service.
 *
 * @param {string} serviceId - The fastly service id.
 * @returns {array} - Array of config versions objects.
 */
FastlyPromise.prototype.getConfigVersions = function getConfigVersions(serviceId) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version');

}

/**
 *
 * Get config version for a service.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Config version object.
 */
FastlyPromise.prototype.getConfigVersion = function getConfigVersion(serviceId, configVersionNumber) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber);

}

/**
 *
 * Get active config version for a service.
 *
 * @param serviceId
 * @returns {object} - Active config version object.
 */
FastlyPromise.prototype.getActiveConfigVersion = function getActiveConfigVersion(serviceId) {

  return this.getConfigVersions(serviceId)
    .then(function(configVersions){

      return configVersions.find(function(configVersion){
        return configVersion.active;
      });

    });

}

/**
 *
 * Validate the config for a particular service and version.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Fastly validation response object
 */
FastlyPromise.prototype.validateConfigVersion = function validateConfigVersion(serviceId, configVersionNumber) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/validate');

}

/**
 *
 * Create a config version for a particular service.
 *
 * @param {string} serviceId - The fastly service id.
 * @returns {object} - New config version object.
 */
FastlyPromise.prototype.createConfigVersion = function createConfigVersion(serviceId) {

  return this.request('POST', this.endpoint + '/service/' + serviceId + '/version');

}

/**
 *
 * Activate a config version.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Config version object
 */
FastlyPromise.prototype.activateConfigVersion = function activateConfigVersion(serviceId, configVersionNumber) {

  return this.request('PUT', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/activate');

}

/**
 *
 * Deactivate a config version.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Config version object
 */
FastlyPromise.prototype.deactivateConfigVersion = function deactivateConfigVersion(serviceId, configVersionNumber) {

  return this.request('PUT', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/deactivate');

}

/**
 *
 * Clone a service configuration by config version number. Config number defaults to the number of the "active" configuration.
 *
 * @param serviceId
 * @param [configVersionNumber] - Defaults to active config version.
 * @returns {object} - Config version object
 */
FastlyPromise.prototype.cloneConfigVersion = function cloneConfigVersion(serviceId, configVersionNumber) {
  var self = this;

  //Set default config version number to active version if not explicitly defined.
  var configVersionNumberPromise = configVersionNumber ? Promise.resolve(configVersionNumber) : self.getActiveConfigVersion(serviceId).then(function(version){ return version.number });

  return configVersionNumberPromise.then(function(configVersionNumber){
    return self.request('PUT', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/clone');
  });

}

/**
 *
 * Lock a config version.
 *
 * @param {string} serviceId - The fastly service id.
 * @param {string} configVersionNumber
 * @returns {object} - Config version object
 */
FastlyPromise.prototype.lockConfigVersion = function lockConfigVersion(serviceId, configVersionNumber) {

  return this.request('PUT', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/lock');

}

/**
 *
 * Get boilerplate VCL with the service's TTL from the settings.
 *
 * @param serviceId
 * @param configVersionNumber
 * @returns {string} - utf8 encoded text/html VCL string.
 */
FastlyPromise.prototype.getBoilerplateVcl = function getBoilerplateVcl(serviceId, configVersionNumber) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/boilerplate');

}

/**
 *
 * Get a list of service VCLs by config version.
 *
 * @param serviceId
 * @param configVersionNumber
 * @returns {array} - Array of VCL objects.
 */
FastlyPromise.prototype.getAllVcl = function getAllVcl(serviceId, configVersionNumber) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl');

}

/**
 *
 * Get a service VCL by config version and name.
 *
 * @param serviceId
 * @param configVersionNumber
 * @param vclName
 * @returns {object} - VCL object.
 */
FastlyPromise.prototype.getVcl = function getVcl(serviceId, configVersionNumber, vclName) {

  return this.request('GET', this.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl/' + vclName);

}

/**
 *
 * Get the current "main" VCL for a service.
 *
 * @param {string} serviceId
 * @param {string} [configVersionNumber] - If no config version number is passed, defaults to active config version.
 * @returns {object} - VCL object.
 */
FastlyPromise.prototype.getMainVcl = function getMainVcl(serviceId, configVersionNumber) {
  var self = this;

  //Set default config version number to active version if not explicitly defined.
  var configVersionNumberPromise = configVersionNumber ? Promise.resolve(configVersionNumber) : self.getActiveConfigVersion(serviceId).then(function(version){ return version.number });

  return configVersionNumberPromise
    .then(function(configVersionNumber){
      return self.getAllVcl(serviceId, configVersionNumber);
  })
    .then(function(vclList){

      return vclList.find(function(vcl){
        return vcl.main;
      });

    });

}

/**
 *
 * Set the specified VCL as main
 *
 * @param {string} serviceId
 * @param {string} vclName
 * @param {string} [configVersionNumber] - If no config version number is passed, defaults to active config version.
 * @returns {object} - VCL object.
 */
FastlyPromise.prototype.setMainVcl = function setMainVcl(serviceId, vclName, configVersionNumber) {
  var self = this;

  //Set default config version number to active version if not explicitly defined.
  var configVersionNumberPromise = configVersionNumber ? Promise.resolve(configVersionNumber) : self.getActiveConfigVersion(serviceId).then(function(version){ return version.number });

  return configVersionNumberPromise
    .then(function(configVersionNumber){
      return self.request('PUT', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl/' + vclName + '/main');
    });

}

/**
 *
 * Upload new VCL to a service.
 *
 * @param {string} serviceId
 * @param {string} configVersionNumber - Service config version number.
 * @param {string} vclName - Name of vcl file.
 * @param {string} vclContent - The VCL content to be uploaded.
 * @param {boolean} [setVclToMain=false] - Set the uploaded vcl to be the service's "main" vcl.
 * @returns {object} - VCL object.
 * @throws Will throw error if VCL with same name already exists.
 */
FastlyPromise.prototype.uploadNewVcl = function uploadNewVcl(serviceId, configVersionNumber, vclName, vclContent, setVclToMain) {
  var self = this;

  setVclToMain = setVclToMain || false;

  var validNamePromise = self.getVcl(serviceId, configVersionNumber, vclName)
    .then(function(response){

      return false; //Invalid if vcl with this name already exists

    })
    .catch(function(errorResponse){

      //If response code is 404 then new vcl name is valid.
      return (errorResponse.statusCode == 404) ? true : false;

    });

  return validNamePromise
    .then(function(validName){

      if (!validName){
        throw new Error('Error: ' + vclName + ' VCL file already exists.');
      }
      else{

        //Upload the VCL
        return self.request('POST', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl', {
          form: {
            name: vclName,
            content: vclContent
          }
        });

      }

    })
    .then(function(vclResponse){

      //Set VCL to "main" if flagged.
      if (setVclToMain){
        return self.setMainVcl(serviceId, vclName, configVersionNumber);
      }
      else{
        return vclResponse;
      }

    });

}

/**
 *
 * Update existing VCL file.
 *
 * @param {string} serviceId
 * @param {string} configVersionNumber - Service config version number.
 * @param {string} vclName - Name of vcl file.
 * @param {string} vclContent - The new VCL content.
 * @param {boolean} [setVclToMain=false] - Set the updated vcl to be the service's "main" vcl.
 * @returns {object} - VCL object.
 */
FastlyPromise.prototype.updateVcl = function updateVcl(serviceId, configVersionNumber, vclName, vclContent, setVclToMain) {
  var self = this;

  setVclToMain = setVclToMain || false;

  //Upload the VCL
  return self.request('PUT', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl/' + vclName, {
      form: {
        content: vclContent
      }
    })
    .then(function(vclResponse){

      //Set VCL to "main" if flagged.
      if (setVclToMain){
        return self.setMainVcl(serviceId, vclName, configVersionNumber);
      }
      else{
        return vclResponse;
      }

    });

}

/**
 *
 * Delete the specified VCL file.
 *
 * @param {string} serviceId
 * @param {string} vclName
 * @param {string} [configVersionNumber] - If no config version number is passed, defaults to active config version.
 * @returns {object} - Fastly VCL delete status object.
 */
FastlyPromise.prototype.deleteVcl = function deleteVcl(serviceId, vclName, configVersionNumber) {
  var self = this;

  //Set default config version number to active version if not explicitly defined.
  var configVersionNumberPromise = configVersionNumber ? Promise.resolve(configVersionNumber) : self.getActiveConfigVersion(serviceId).then(function(version){ return version.number });

  return configVersionNumberPromise
    .then(function(configVersionNumber){
      return self.request('DELETE', self.endpoint + '/service/' + serviceId + '/version/' + configVersionNumber + '/vcl/' + vclName);
    });

}

module.exports = FastlyPromise;<|endoftext|>


<commit_before>/**
 * To retrieve TFA -- Today's featured article -- for a given date.
 */

'use strict';

var preq = require('preq');
var api = require('../api-util');
var mwapi = require('../mwapi');
var dateUtil = require('../dateUtil');
var sUtil = require('../util');
var BBPromise = require('bluebird');
var HTTPError = sUtil.HTTPError;

/**
 * Builds the request to get the Featured article of a given date.
 *
 * @param {Object} app the application object
 * @param {String} domain the requested domain, e.g. 'de.wikipedia.org'
 * @param {Date} date for which day the featured article is requested
 * @return {Promise} a promise resolving as an JSON object containing the response
 */
function requestFeaturedArticleTitle(app, domain, date) {
    var formattedDateString = dateUtil.formatDateEnglish(date);
    return api.mwApiGet(app, domain, {
        action: 'query',
        format: 'json',
        formatversion: 2,
        exchars: 255,
        explaintext: '',
        titles: `Template:TFA_title/${formattedDateString}`,
        prop: 'extracts'
    });
}

// -- functions dealing with responses:

function getPageObject(response, dontThrow) {
    if (response.body.query && response.body.query.pages[0]) {
        var page = response.body.query.pages[0];
        if (!page.extract || !page.pageid || page.missing === true) {
            throw new HTTPError({
                status: 404,
                type: 'not_found',
                title: 'No featured article for this date',
                detail: 'There is no featured article for this date.'
            });
        }
        return page;
    } else {
        if (!dontThrow) {
            throw new HTTPError({
                status: 500,
                type: 'unknown_backend_response',
                title: 'Unexpected backend response',
                detail: 'The backend responded with gibberish.'
            });
        }
    }
}

/**
 * HAX: TextExtracts extension will (sometimes) add "..." to the extract.  In this particular case, we don't
 * want it, so we remove it if present.
 */
function removeEllipsis(extract) {
    if (extract.endsWith('...')) {
        return extract.slice(0, -3);
    }
    return extract;
}

function promise(app, req) {
    dateUtil.validate(dateUtil.hyphenDelimitedDateString(req));
    var aggregated = !!req.query.aggregated;
    if (req.params.domain.indexOf('en') !== 0) {
        if (aggregated) {
            return BBPromise.resolve({});
        } else {
            throw new HTTPError({
                status: 501,
                type: 'unsupported_language',
                title: 'Language not supported',
                detail: 'The language you have requested is not yet supported.'
            });
        }
    }

    var tfaPageObj, pageTitle;

    return requestFeaturedArticleTitle(app, req.params.domain, dateUtil.getRequestedDate(req))
    .then(function (response) {
        mwapi.checkForQueryPagesInResponse(req, response);
        tfaPageObj = getPageObject(response);
        pageTitle = removeEllipsis(tfaPageObj.extract);
        req.params.title = pageTitle;
        return mwapi.requestExtractAndDescription(app, req);
    }).then(function (extractResponse) {
        mwapi.checkForQueryPagesInResponse(req, extractResponse);
        var extractPageObj = getPageObject(extractResponse, true);
        return BBPromise.props({
            page: extractPageObj,
            dbTitle: mwapi.getDbTitle(app, req, extractPageObj.title)
        });
    }).then(function (res) {
        return {
            payload: mwapi.buildSummaryResponse(res.page, res.dbTitle),
            meta: {
                etag: tfaPageObj.pageid + '/' + mwapi.getRevisionFromExtract(res.page)
            }
        };
    });
}

module.exports = {
    promise: promise
};
<commit_msg>Make aggregated feed work on Beta Cluster<commit_after>/**
 * To retrieve TFA -- Today's featured article -- for a given date.
 */

'use strict';

var preq = require('preq');
var api = require('../api-util');
var mwapi = require('../mwapi');
var dateUtil = require('../dateUtil');
var sUtil = require('../util');
var BBPromise = require('bluebird');
var HTTPError = sUtil.HTTPError;

/**
 * Builds the request to get the Featured article of a given date.
 *
 * @param {Object} app the application object
 * @param {String} domain the requested domain, e.g. 'de.wikipedia.org'
 * @param {Date} date for which day the featured article is requested
 * @return {Promise} a promise resolving as an JSON object containing the response
 */
function requestFeaturedArticleTitle(app, domain, date) {
    var formattedDateString = dateUtil.formatDateEnglish(date);
    return api.mwApiGet(app, domain, {
        action: 'query',
        format: 'json',
        formatversion: 2,
        exchars: 255,
        explaintext: '',
        titles: `Template:TFA_title/${formattedDateString}`,
        prop: 'extracts'
    });
}

// -- functions dealing with responses:

function getPageObject(response, dontThrow) {
    if (response.body.query && response.body.query.pages[0]) {
        var page = response.body.query.pages[0];
        if (!page.extract || !page.pageid || page.missing === true) {
            throw new HTTPError({
                status: 404,
                type: 'not_found',
                title: 'No featured article for this date',
                detail: 'There is no featured article for this date.'
            });
        }
        return page;
    } else {
        if (!dontThrow) {
            throw new HTTPError({
                status: 500,
                type: 'unknown_backend_response',
                title: 'Unexpected backend response',
                detail: 'The backend responded with gibberish.'
            });
        }
    }
}

/**
 * HAX: TextExtracts extension will (sometimes) add "..." to the extract.  In this particular case, we don't
 * want it, so we remove it if present.
 */
function removeEllipsis(extract) {
    if (extract.endsWith('...')) {
        return extract.slice(0, -3);
    }
    return extract;
}

function promise(app, req) {
    dateUtil.validate(dateUtil.hyphenDelimitedDateString(req));
    var aggregated = !!req.query.aggregated;
    if (req.params.domain.indexOf('en') !== 0 || req.params.domain.indexOf('beta.wmflabs.org') > 0) {
        if (aggregated) {
            return BBPromise.resolve({});
        } else {
            throw new HTTPError({
                status: 501,
                type: 'unsupported_language',
                title: 'Language not supported',
                detail: 'The language you have requested is not yet supported.'
            });
        }
    }

    var tfaPageObj, pageTitle;

    return requestFeaturedArticleTitle(app, req.params.domain, dateUtil.getRequestedDate(req))
    .then(function (response) {
        mwapi.checkForQueryPagesInResponse(req, response);
        tfaPageObj = getPageObject(response);
        pageTitle = removeEllipsis(tfaPageObj.extract);
        req.params.title = pageTitle;
        return mwapi.requestExtractAndDescription(app, req);
    }).then(function (extractResponse) {
        mwapi.checkForQueryPagesInResponse(req, extractResponse);
        var extractPageObj = getPageObject(extractResponse, true);
        return BBPromise.props({
            page: extractPageObj,
            dbTitle: mwapi.getDbTitle(app, req, extractPageObj.title)
        });
    }).then(function (res) {
        return {
            payload: mwapi.buildSummaryResponse(res.page, res.dbTitle),
            meta: {
                etag: tfaPageObj.pageid + '/' + mwapi.getRevisionFromExtract(res.page)
            }
        };
    });
}

module.exports = {
    promise: promise
};
<|endoftext|>


<commit_before>(function($) {

  $.declare('imageUploader', {
    defaults: {
      action: window.location.href,
      method: 'POST',
      postKey: 'image',
      progressTemplate: '
Uploading...
',
      completeTemplateImage: '',
      completeTemplateOther: '
The file has been uploaded ✔
',
      images: ['jpg', 'png', 'bmp', 'gif', 'jpeg'],
      allow: [],
      processData: null,
      zIndex: 2,
      dropZone: 'this',
      updateProgress: function(event) {}
    },

    init: function() {
      this.supportsFileApi = (typeof window.FileReader !== 'undefined');

      this.el.css('cursor', 'pointer');

      this.setupFramejax();

      if (this.supportsFileApi) {
        this.setupFileApi();
      }
    },

    setupFramejax: function() {
      var self = this;

      var form = $('<form/>')
        .attr({
          action: this.action,
          method: this.method,
          enctype: 'multipart/form-data'
        })
        .appendTo('body');

      var input = $('<input/>')
        .attr({
          name: this.postKey,
          type: 'file'
        })
        .css({
          opacity: '0',
          cursor: 'pointer',
          position: 'absolute',
          zIndex: this.zIndex
        })
        .on('change', function(e) {
          var filename = e.target.value;

          if (!this.checkType(filename)) {
            alert('Please select a file with a ' + self.allow.join(', ') + ' extension');
            return;
          }

          self.el.trigger('fileSelect');
          self.showProgress();
          form.submit();
        })
        .appendTo(form);

      this.el.on('mousemove', function(e) {
        var h = input.height();
        var w = input.width();

        if (typeof e.pageY == 'undefined' && typeof e.clientX == 'number' && document.documentElement) {
          e.pageX = e.clientX + document.documentElement.scrollLeft;
          e.pageY = e.clientY + document.documentElement.scrollTop;
        }

        input.css({
          top: e.pageY - (h / 2),
          left: e.pageX - (w - 30)
        });
      });

      form
        .framejax()
        .on('complete', function(e, results) {
          self.showComplete(results);
          self.el.trigger('complete', results);
        });
    },

    checkType: function(file) {
      return !this.allow.length || $.inArray(this.getExtension(file), this.allow) !== -1;
    },

    setupFileApi: function() {
      var self = this;

      if (self.dropZone === 'this') {
        self.dropZone = self.el;
      } else {
        self.dropZone = $(self.dropZone);
      }

      self.dropZone.bind('dragenter, dragover', function(event){
        event.stopPropagation();
        event.preventDefault();
        event.originalEvent.dataTransfer.dropEffect = 'copy';
        self.emit('over');
      });

      self.dropZone.bind('dragleave', function() {
        self.emit('out');
      });

      self.dropZone.bind('drop', function(event) {
        event.stopPropagation();
        event.preventDefault();

        var file = event.originalEvent.dataTransfer.files[0];

        if (!self.checkType(file.name)) {
          //Probably some messaging here about filetype
          return;
        }

        self.upload(file);
      });
    },

    showProgress: function() {
      this.el.html(this.progressTemplate);
    },

    getExtension: function(file) {
      return file.split('.').pop().toLowerCase();
    },

    showComplete: function(data) {
      var extension = this.getExtension(data);
      var file = (this.processData) ? this.processData(data) : data;
      var isImage = $.inArray(extension, this.images) > -1;

      if (file) {
        if (isImage) {
          this.el
            .html(this.completeTemplateImage)
            .find('img')
            .attr('src', file);
        }
        else {
          this.el.html(this.completeTemplateOther);
        }
      }
    },

    upload: function(file) {
      var formData = new FormData();
      var self = this;
      var xhr = new XMLHttpRequest();

      formData.append('image', file);

      self.showProgress();

      xhr.open('POST', self.action, true);
      xhr.upload.onprogress = self.updateProgress;
      xhr.onload = function(event) {
        self.showComplete(this.responseText, this, event);
        self.el.trigger('complete', this.responseText);
      };

      xhr.send(formData);
    }
  });
})(window.jQuery);
<commit_msg>renamed plugin to fileUploader<commit_after>(function($) {

  $.declare('fileUploader', {
    defaults: {
      action: window.location.href,
      method: 'POST',
      postKey: 'image',
      progressTemplate: '
Uploading...
',
      completeTemplateImage: '',
      completeTemplateOther: '
The file has been uploaded ✔
',
      images: ['jpg', 'png', 'bmp', 'gif', 'jpeg'],
      allow: [],
      processData: null,
      zIndex: 2,
      dropZone: 'this',
      updateProgress: function(event) {}
    },

    init: function() {
      this.supportsFileApi = (typeof window.FileReader !== 'undefined');

      this.el.css('cursor', 'pointer');

      this.setupFramejax();

      if (this.supportsFileApi) {
        this.setupFileApi();
      }
    },

    setupFramejax: function() {
      var self = this;

      var form = $('<form/>')
        .attr({
          action: this.action,
          method: this.method,
          enctype: 'multipart/form-data'
        })
        .appendTo('body');

      var input = $('<input/>')
        .attr({
          name: this.postKey,
          type: 'file'
        })
        .css({
          opacity: '0',
          cursor: 'pointer',
          position: 'absolute',
          zIndex: this.zIndex
        })
        .on('change', function(e) {
          var filename = e.target.value;

          if (!this.checkType(filename)) {
            alert('Please select a file with a ' + self.allow.join(', ') + ' extension');
            return;
          }

          self.el.trigger('fileSelect');
          self.showProgress();
          form.submit();
        })
        .appendTo(form);

      this.el.on('mousemove', function(e) {
        var h = input.height();
        var w = input.width();

        if (typeof e.pageY == 'undefined' && typeof e.clientX == 'number' && document.documentElement) {
          e.pageX = e.clientX + document.documentElement.scrollLeft;
          e.pageY = e.clientY + document.documentElement.scrollTop;
        }

        input.css({
          top: e.pageY - (h / 2),
          left: e.pageX - (w - 30)
        });
      });

      form
        .framejax()
        .on('complete', function(e, results) {
          self.showComplete(results);
          self.el.trigger('complete', results);
        });
    },

    checkType: function(file) {
      return !this.allow.length || $.inArray(this.getExtension(file), this.allow) !== -1;
    },

    setupFileApi: function() {
      var self = this;

      if (self.dropZone === 'this') {
        self.dropZone = self.el;
      } else {
        self.dropZone = $(self.dropZone);
      }

      self.dropZone.bind('dragenter, dragover', function(event){
        event.stopPropagation();
        event.preventDefault();
        event.originalEvent.dataTransfer.dropEffect = 'copy';
        self.emit('over');
      });

      self.dropZone.bind('dragleave', function() {
        self.emit('out');
      });

      self.dropZone.bind('drop', function(event) {
        event.stopPropagation();
        event.preventDefault();

        var file = event.originalEvent.dataTransfer.files[0];

        if (!self.checkType(file.name)) {
          //Probably some messaging here about filetype
          return;
        }

        self.upload(file);
      });
    },

    showProgress: function() {
      this.el.html(this.progressTemplate);
    },

    getExtension: function(file) {
      return file.split('.').pop().toLowerCase();
    },

    showComplete: function(data) {
      var extension = this.getExtension(data);
      var file = (this.processData) ? this.processData(data) : data;
      var isImage = $.inArray(extension, this.images) > -1;

      if (file) {
        if (isImage) {
          this.el
            .html(this.completeTemplateImage)
            .find('img')
            .attr('src', file);
        }
        else {
          this.el.html(this.completeTemplateOther);
        }
      }
    },

    upload: function(file) {
      var formData = new FormData();
      var self = this;
      var xhr = new XMLHttpRequest();

      formData.append('image', file);

      self.showProgress();

      xhr.open('POST', self.action, true);
      xhr.upload.onprogress = self.updateProgress;
      xhr.onload = function(event) {
        self.showComplete(this.responseText, this, event);
        self.el.trigger('complete', this.responseText);
      };

      xhr.send(formData);
    }
  });
})(window.jQuery);
<|endoftext|>


<commit_before>'use strict';
var debug = require('debug')('fileprocessor');
var File = require('./file');
var _ = require('lodash');

var _defaultPatterns = {
	'html': [
      /*jshint regexp:false */
      [ /<script.+src=['"]([^"']+)["']/gm,
      'Update the HTML to reference our concat/min/revved script files'
      ],
      [ /<link[^\>]+href=['"]([^"']+)["']/gm,
      'Update the HTML with the new css filenames'
      ],
      [ /<img[^\>]+src=['"]([^"']+)["']/gm,
      'Update the HTML with the new img filenames'
      ],
      [ /data-main\s*=['"]([^"']+)['"]/gm,
      'Update the HTML with data-main tags',
      function (m) { return m.match(/\.js$/) ? m : m + '.js'; },
      function (m) { return m.replace('.js', ''); }
      ],
      [ /data-(?!main).[^=]+=['"]([^'"]+)['"]/gm,
      'Update the HTML with data-* tags'
      ],
      [ /url\(\s*['"]([^"']+)["']\s*\)/gm,
      'Update the HTML with background imgs, case there is some inline style'
      ],
      [ /<a[^\>]+href=['"]([^"']+)["']/gm,
      'Update the HTML with anchors images'
      ],
      [/<input[^\>]+src=['"]([^"']+)["']/gm,
      'Update the HTML with reference in input'
      ]
    ],
	  'css': [
      /*jshint regexp:false */
      [ /(?:src=|url\(\s*)['"]?([^'"\)\?]+)['"]?\s*\)?/gm,
      'Update the CSS to reference our revved images'
      ]
    ]
  };

_defaultPatterns.jade = require('usemin-patters').jade;

var FileProcessor = module.exports = function(patterns, finder, logcb) {
	if (!patterns) {
		throw new Error('No pattern given');
	}

	if (typeof patterns  === 'string' || patterns instanceof String) {
		if (!_.contains(_.keys(_defaultPatterns), patterns)) {
			throw new Error('Unsupported pattern: ' + patterns);
		}
		this.patterns = _defaultPatterns[patterns];
	}else {
		// FIXME: check the pattern format
		this.patterns = patterns;
	}

	this.log = logcb || function(){};

	if (!finder) {
		throw new Error('Missing parameter: finder');
	}
	this.finder = finder;
};

//
// Replace blocks by their target
//
FileProcessor.prototype.replaceBlocks = function replaceBlocks(file) {
  var result = file.content;
  var linefeed = /\r\n/g.test(result) ? '\r\n' : '\n';
  file.blocks.forEach(function (block) {
    var blockLine = block.raw.join(linefeed);
    result = result.replace(blockLine, this.replaceWith(block));
  }, this);
  return result;
};

FileProcessor.prototype.replaceWith = function replaceWith(block) {
  var result;
  var dest = block.dest;
  var conditionalStart = block.conditionalStart ? block.conditionalStart + '\n' + block.indent : '';
  var conditionalEnd = block.conditionalEnd ? '\n' + block.indent + block.conditionalEnd : '';
  if (block.type === 'css') {
    var media = block.media ? ' media="' + block.media + '"' : '';
    result = block.indent + conditionalStart + '<link rel="stylesheet" href="' + dest + '"' + media + '/>' + conditionalEnd;
  } else if (block.defer) {
    result = block.indent + conditionalStart + '<script defer src="' + dest + '"><\/script>' + conditionalEnd;
  } else if (block.type === 'js') {
    result = block.indent + conditionalStart + '<script src="' + dest + '"><\/script>' + conditionalEnd;
  } /*else {
    result = '';
  }*/
  return result;
};

//
// Replace reference to scripts, css, images, .. in +lines+ with their revved version
// If +lines+ is not furnished used instead the cached version (i.e. stored at constructor time)
//
FileProcessor.prototype.replaceWithRevved = function replaceWithRevved(lines, assetSearchPath) {
    // Replace script sources
    var self = this;
    var content = lines;
    var regexps = this.patterns;
    var identity = function (m) { return m; };

    // Replace reference to script with the actual name of the revved script
    regexps.forEach(function (rxl) {
      var filterIn = rxl[2] || identity;
      var filterOut = rxl[3] || identity;

      self.log(rxl[1]);
      content = content.replace(rxl[0], function (match, src) {
        // Consider reference from site root
        var srcfile = filterIn(src);

        debug('Let\'s replace ' + src);

        debug('Looking for revved version of ' + srcfile + ' in ', assetSearchPath);

        var file = self.finder.find(srcfile, assetSearchPath);

        debug('Found file \'%s\'', file);

        var res = match.replace(src, filterOut(file));
        if (srcfile !== file) {
          self.log(match + ' changed to ' + res);
        }
        return res;
      });
    });

    return content;
  };

FileProcessor.prototype.process = function(filename, assetSearchPath) {
  debug('processing file %s', filename, assetSearchPath);

  if (typeof filename  === 'string' || filename instanceof String) {
    this.file = new File(filename);
  } else {
    // filename is an object and should conform to lib/file.js API
    this.file = filename;
  }

  if (assetSearchPath && assetSearchPath.length !== 0) {
    this.file.searchPath = assetSearchPath;
  }

	var content = this.replaceWithRevved(this.replaceBlocks(this.file), this.file.searchPath);

	return content;
};
<commit_msg>updated fileprocessor's replaceWith method for jade<commit_after>'use strict';
var debug = require('debug')('fileprocessor');
var File = require('./file');
var _ = require('lodash');

var _defaultPatterns = {
	'html': [
      /*jshint regexp:false */
      [ /<script.+src=['"]([^"']+)["']/gm,
      'Update the HTML to reference our concat/min/revved script files'
      ],
      [ /<link[^\>]+href=['"]([^"']+)["']/gm,
      'Update the HTML with the new css filenames'
      ],
      [ /<img[^\>]+src=['"]([^"']+)["']/gm,
      'Update the HTML with the new img filenames'
      ],
      [ /data-main\s*=['"]([^"']+)['"]/gm,
      'Update the HTML with data-main tags',
      function (m) { return m.match(/\.js$/) ? m : m + '.js'; },
      function (m) { return m.replace('.js', ''); }
      ],
      [ /data-(?!main).[^=]+=['"]([^'"]+)['"]/gm,
      'Update the HTML with data-* tags'
      ],
      [ /url\(\s*['"]([^"']+)["']\s*\)/gm,
      'Update the HTML with background imgs, case there is some inline style'
      ],
      [ /<a[^\>]+href=['"]([^"']+)["']/gm,
      'Update the HTML with anchors images'
      ],
      [/<input[^\>]+src=['"]([^"']+)["']/gm,
      'Update the HTML with reference in input'
      ]
    ],
	  'css': [
      /*jshint regexp:false */
      [ /(?:src=|url\(\s*)['"]?([^'"\)\?]+)['"]?\s*\)?/gm,
      'Update the CSS to reference our revved images'
      ]
    ]
  };

_defaultPatterns.jade = require('usemin-patters').jade;

var FileProcessor = module.exports = function(patterns, finder, logcb) {
	if (!patterns) {
		throw new Error('No pattern given');
	}

	if (typeof patterns  === 'string' || patterns instanceof String) {
		if (!_.contains(_.keys(_defaultPatterns), patterns)) {
			throw new Error('Unsupported pattern: ' + patterns);
		}
		this.patterns = _defaultPatterns[patterns];
	}else {
		// FIXME: check the pattern format
		this.patterns = patterns;
	}

	this.log = logcb || function(){};

	if (!finder) {
		throw new Error('Missing parameter: finder');
	}
	this.finder = finder;
};

//
// Replace blocks by their target
//
FileProcessor.prototype.replaceBlocks = function replaceBlocks(file) {
  var result = file.content;
  var linefeed = /\r\n/g.test(result) ? '\r\n' : '\n';
  file.blocks.forEach(function (block) {
    var blockLine = block.raw.join(linefeed);
    result = result.replace(blockLine, this.replaceWith(block));
  }, this);
  return result;
};

FileProcessor.prototype.replaceWith = function replaceWith(block) {
  var result;
  var dest = block.dest;
  var conditionalStart = block.conditionalStart ? block.conditionalStart + '\n' + block.indent : '';
  var conditionalEnd = block.conditionalEnd ? '\n' + block.indent + block.conditionalEnd : '';
  if (block.type === 'css') {
    var media = block.media ? ' media="' + block.media + '"' : '';
    result = block.indent + conditionalStart + 'link(rel=\'stylesheet\', href=\'' + dest + '\'' + media + ')' + conditionalEnd;
  } else if (block.defer || block.type === 'js') {
    result = block.indent + conditionalStart + 'script(src=\'' + dest + '\')' + conditionalEnd;
  } /*else {
    result = '';
  }*/
  return result;
};

//
// Replace reference to scripts, css, images, .. in +lines+ with their revved version
// If +lines+ is not furnished used instead the cached version (i.e. stored at constructor time)
//
FileProcessor.prototype.replaceWithRevved = function replaceWithRevved(lines, assetSearchPath) {
    // Replace script sources
    var self = this;
    var content = lines;
    var regexps = this.patterns;
    var identity = function (m) { return m; };

    // Replace reference to script with the actual name of the revved script
    regexps.forEach(function (rxl) {
      var filterIn = rxl[2] || identity;
      var filterOut = rxl[3] || identity;

      self.log(rxl[1]);
      content = content.replace(rxl[0], function (match, src) {
        // Consider reference from site root
        var srcfile = filterIn(src);

        debug('Let\'s replace ' + src);

        debug('Looking for revved version of ' + srcfile + ' in ', assetSearchPath);

        var file = self.finder.find(srcfile, assetSearchPath);

        debug('Found file \'%s\'', file);

        var res = match.replace(src, filterOut(file));
        if (srcfile !== file) {
          self.log(match + ' changed to ' + res);
        }
        return res;
      });
    });

    return content;
  };

FileProcessor.prototype.process = function(filename, assetSearchPath) {
  debug('processing file %s', filename, assetSearchPath);

  if (typeof filename  === 'string' || filename instanceof String) {
    this.file = new File(filename);
  } else {
    // filename is an object and should conform to lib/file.js API
    this.file = filename;
  }

  if (assetSearchPath && assetSearchPath.length !== 0) {
    this.file.searchPath = assetSearchPath;
  }

	var content = this.replaceWithRevved(this.replaceBlocks(this.file), this.file.searchPath);

	return content;
};
<|endoftext|>


<commit_before>import babel from "rollup-plugin-babel"

const classicPreset = [ "latest", {
  es2015: {
    modules: false
  }
}]

const modernPreset = [ "babel-preset-env", {
  targets: {
    node: 6,
    browsers: [
      "Safari 10",
      "iOS 10",
      "Edge 14",
      "Chrome 54",
      "ChromeAndroid 54",
      "Firefox 50",
      "FirefoxAndroid 50"
    ]
  },

  modules: false,
  debug: false,
  useBuiltIns: true
}]

export function createHelper(modern, presets = [], plugins = []) {
  return babel({
    // Don't try to find .babelrc because we want to force this configuration.
    babelrc: false,

    // Allow usage of transform-runtime for referencing to a common library of polyfills
    runtimeHelpers: true,

    exclude: "node_modules/**",

    presets: [
      modern ? modernPreset : classicPreset,

      ...presets
    ],

    plugins: [
      // Improve some ES3 edge case to make code parseable by older clients
      // e.g. when using reserved words as keys like "catch"
      "transform-es3-property-literals",
      "transform-es3-member-expression-literals",

      // Using centralized helpers but require generic Polyfills being loaded separately
      // e.g. via Babel-Runtime or via services like polyfill.io.
      [ "transform-runtime", {
        polyfill: false
      }],

      // class { handleClick = () => { } }
      "transform-class-properties",

      // { ...todo, completed: true }
      [ "transform-object-rest-spread", { useBuiltIns: true }],

      ...plugins
    ]
  })
}

export default function createLatestConfig() {
  return {
    classic: createHelper(false),
    modern: createHelper(true)
  }
}
<commit_msg>Added default values + docs<commit_after>import babel from "rollup-plugin-babel"

const classicPreset = [ "latest", {
  es2015: {
    modules: false
  }
}]

const modernPreset = [ "babel-preset-env", {
  targets: {
    node: 6,
    browsers: [
      "Safari 10",
      "iOS 10",
      "Edge 14",
      "Chrome 54",
      "ChromeAndroid 54",
      "Firefox 50",
      "FirefoxAndroid 50"
    ]
  },

  modules: false,
  debug: false,
  useBuiltIns: true
}]

export function createHelper(modern, presets = [], plugins = []) {
  return babel({
    // Don't try to find .babelrc because we want to force this configuration.
    babelrc: false,

    // Allow usage of transform-runtime for referencing to a common library of polyfills
    runtimeHelpers: true,

    exclude: "node_modules/**",

    presets: [
      modern ? modernPreset : classicPreset,

      ...presets
    ],

    plugins: [
      // Improve some ES3 edge case to make code parseable by older clients
      // e.g. when using reserved words as keys like "catch"
      "transform-es3-property-literals",
      "transform-es3-member-expression-literals",

      // Using centralized helpers but require generic Polyfills being loaded separately
      // e.g. via Babel-Runtime or via services like polyfill.io.
      // See also: https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-runtime
      [ "transform-runtime", {
        // default
        helpers: true,

        // default
        regenerator: true,

        // changed from default. More efficient to use real polyfills.
        polyfill: false
      }],

      // class { handleClick = () => { } }
      "transform-class-properties",

      // { ...todo, completed: true }
      [ "transform-object-rest-spread", { useBuiltIns: true }],

      ...plugins
    ]
  })
}

export default function createLatestConfig() {
  return {
    classic: createHelper(false),
    modern: createHelper(true)
  }
}
<|endoftext|>


<commit_before>define(function(require, exports, module) {
    var mvc = require("splunkjs/mvc/mvc");

    require("bootstrap-tagsinput");

    var FilterComponent = {
        initialize: function() {
            var defaultTokens = mvc.Components.getInstance("default");
            var submittedTokens = mvc.Components.getInstance("submitted");

            // Facade that reads & writes to both the "default" and "submitted" token
            // models. This is necessary to send token values to both searches and to
            // other attributes.
            var tokens = {
                get: function(tokenName) {
                    return defaultTokens.get(tokenName);
                },

                set: function(tokenName, tokenValue) {
                    defaultTokens.set(tokenName, tokenValue);
                    submittedTokens.set(tokenName, tokenValue);
                }
            };

            //set default for filters
            tokens.set("filter", "");
            tokens.set("exclude", "");

            //initalize time picker and radio controls
            var timerange = mvc.Components.get("timerange");

            $(document).on("click:menu", function(e) {
                action = e.action;
                if (e.drilldown_search != "") {
                    base_search = e.drilldown_search;
                    earliest = timerange.val().earliest_time;
                    latest = timerange.val().latest_time;
                }
                else {
                    // TODO: Looks like private API usage. Rewrite to avoid.
                    base_search = e.splunk_data.component.manager.search.attributes.search + " | " + e.splunk_data.component.manager.settings.attributes.search
                    earliest = e.splunk_data.component.manager.search.attributes.data.searchEarliestTime;
                    latest = e.splunk_data.component.manager.search.attributes.data.searchLatestTime;
                }

                if (e.splunk_data.data) {
                    name = e.splunk_data.data["click.name"];
                    value = e.splunk_data.data["click.value"];
                }
                else {
                    name = e.splunk_data.name;
                    value = e.splunk_data.value;
                    //timechart check
                    if (name == "_time") {
                        name = "command";
                        value = e.splunk_data.name2;
                    }
                }

                if (action == "include") {
                    FilterComponent._filter(tokens, name, value);
                }
                if (action == "exclude") {
                    FilterComponent._exclude(tokens, name, value);
                }
                if (action == "drilldown") {
                    FilterComponent._drilldown(tokens, base_search, name, value, earliest, latest);
                }
            });

            $("#filter_tags_input").tagsinput({
                itemText: 'text',
                itemValue: 'field_value',
                tagClass: function(item) {
                    return (item.action == "filter" ? 'label filter' : 'label exclude');
                },
                freeInput: false
            });

            $('#filter_tags_input').on('itemRemoved', function(event) {
                if (event.item.action == "filter") {
                    filter_string = tokens.get("filter")
                    filter_string = filter_string.replace("FILTER " + event.item.field_name + " is \"" + event.item.field_value + "\"", "")
                    tokens.set("filter", filter_string);
                }
                else {
                    filter_string = tokens.get("exclude")
                    filter_string = filter_string.replace("FILTER " + event.item.field_name + " isNot \"" + event.item.field_value + "\"", "")
                    tokens.set("exclude", filter_string);
                }
            });
        },

        _filter: function(tokens, field_name, field_value) {
            var filter_search = "";
            var terms = "FILTER " + field_name + " is \"" + field_value + "\""
            filter_search = tokens.get("filter");
            filter_search += terms;
            tokens.set("filter", filter_search);
            $("#filter_tags_input").tagsinput('add', {
                "action": "filter",
                "field_name": field_name,
                "field_value": field_value,
                "text": terms
            });
        },

        _exclude: function(tokens, field_name, field_value) {
            var exclude_search = "";
            var terms = "FILTER " + field_name + " isNot \"" + field_value + "\" ";
            exclude_search = tokens.get("exclude");
            if (exclude_search == "*") exclude_search = "";
            exclude_search += terms;
            tokens.set("exclude", exclude_search)
            $("#filter_tags_input").tagsinput('add', {
                "action": "exclude",
                "field_name": field_name,
                "field_value": field_value,
                "text": terms
            });
        },

        _drilldown: function(tokens, base_search, field_name, field_value, earliest, latest) {
            var page;
            if (field_name == "user") {
                page = "user_activity";
            }
            if (field_name == "object") {
                page = "document_details";
            }

            var exclude = tokens.get("exclude");
            var include = tokens.get("filter");
            exclude = exclude.replace("Channel=\"", "eventtype=\"egress:");
            include = include.replace("Channel=\"", "eventtype=\"egress:");
            var terms = field_name + "=\"" + field_value + "\""
            var search = base_search.replace("$criteria$", terms + " " + include + " " + exclude);

            var queryParams = {
                "form.time.earliest": earliest,
                "form.time.latest": latest
            };
            queryParams["form." + field_name] = field_value;
            window.open(page + "?" + $.param(queryParams), "_blank");
        }
    };

    return FilterComponent;
});
<commit_msg>Summary: Fix search error when filtering by user and document simultaneously. (DVPL-5946)<commit_after>define(function(require, exports, module) {
    var mvc = require("splunkjs/mvc/mvc");

    require("bootstrap-tagsinput");

    var FilterComponent = {
        initialize: function() {
            var defaultTokens = mvc.Components.getInstance("default");
            var submittedTokens = mvc.Components.getInstance("submitted");

            // Facade that reads & writes to both the "default" and "submitted" token
            // models. This is necessary to send token values to both searches and to
            // other attributes.
            var tokens = {
                get: function(tokenName) {
                    return defaultTokens.get(tokenName);
                },

                set: function(tokenName, tokenValue) {
                    defaultTokens.set(tokenName, tokenValue);
                    submittedTokens.set(tokenName, tokenValue);
                }
            };

            //set default for filters
            tokens.set("filter", "");
            tokens.set("exclude", "");

            //initalize time picker and radio controls
            var timerange = mvc.Components.get("timerange");

            $(document).on("click:menu", function(e) {
                action = e.action;
                if (e.drilldown_search != "") {
                    base_search = e.drilldown_search;
                    earliest = timerange.val().earliest_time;
                    latest = timerange.val().latest_time;
                }
                else {
                    // TODO: Looks like private API usage. Rewrite to avoid.
                    base_search = e.splunk_data.component.manager.search.attributes.search + " | " + e.splunk_data.component.manager.settings.attributes.search
                    earliest = e.splunk_data.component.manager.search.attributes.data.searchEarliestTime;
                    latest = e.splunk_data.component.manager.search.attributes.data.searchLatestTime;
                }

                if (e.splunk_data.data) {
                    name = e.splunk_data.data["click.name"];
                    value = e.splunk_data.data["click.value"];
                }
                else {
                    name = e.splunk_data.name;
                    value = e.splunk_data.value;
                    //timechart check
                    if (name == "_time") {
                        name = "command";
                        value = e.splunk_data.name2;
                    }
                }

                if (action == "include") {
                    FilterComponent._filter(tokens, name, value);
                }
                if (action == "exclude") {
                    FilterComponent._exclude(tokens, name, value);
                }
                if (action == "drilldown") {
                    FilterComponent._drilldown(tokens, base_search, name, value, earliest, latest);
                }
            });

            $("#filter_tags_input").tagsinput({
                itemText: 'text',
                itemValue: 'field_value',
                tagClass: function(item) {
                    return (item.action == "filter" ? 'label filter' : 'label exclude');
                },
                freeInput: false
            });

            $('#filter_tags_input').on('itemRemoved', function(event) {
                if (event.item.action == "filter") {
                    filter_string = tokens.get("filter")
                    filter_string = filter_string.replace("FILTER " + event.item.field_name + " is \"" + event.item.field_value + "\"", "")
                    tokens.set("filter", filter_string);
                }
                else {
                    filter_string = tokens.get("exclude")
                    filter_string = filter_string.replace("FILTER " + event.item.field_name + " isNot \"" + event.item.field_value + "\"", "")
                    tokens.set("exclude", filter_string);
                }
            });
        },

        _filter: function(tokens, field_name, field_value) {
            var filter_search = "";
            var terms = "FILTER " + field_name + " is \"" + field_value + "\""
            filter_search = tokens.get("filter");
            filter_search = filter_search + " " + terms;
            tokens.set("filter", filter_search);
            $("#filter_tags_input").tagsinput('add', {
                "action": "filter",
                "field_name": field_name,
                "field_value": field_value,
                "text": terms
            });
        },

        _exclude: function(tokens, field_name, field_value) {
            var exclude_search = "";
            var terms = "FILTER " + field_name + " isNot \"" + field_value + "\"";
            exclude_search = tokens.get("exclude");
            if (exclude_search == "*") exclude_search = "";
            exclude_search = exclude_search + " " + terms;
            tokens.set("exclude", exclude_search)
            $("#filter_tags_input").tagsinput('add', {
                "action": "exclude",
                "field_name": field_name,
                "field_value": field_value,
                "text": terms
            });
        },

        _drilldown: function(tokens, base_search, field_name, field_value, earliest, latest) {
            var page;
            if (field_name == "user") {
                page = "user_activity";
            }
            if (field_name == "object") {
                page = "document_details";
            }

            var queryParams = {
                "form.time.earliest": earliest,
                "form.time.latest": latest
            };
            queryParams["form." + field_name] = field_value;
            window.open(page + "?" + $.param(queryParams), "_blank");
        }
    };

    return FilterComponent;
});
<|endoftext|>


<commit_before>$(document).ready(function() {
    "use strict";

    $("body").tooltip({
        selector: "[data-toggle=tooltip]"
    });

    $("body").popover({
        selector: "[data-toggle=popover]"
    });

    /**
     * Navbar
     */
    var minWidth = 768,
        navbar = $('#change-navbar'),
        offset = navbar.offset(),
        width = window.innerWidth;

    if (navbar.length && width >= minWidth){
        $(document).scroll(function() {
            var scrollStart = $(this).scrollTop();
            if (scrollStart > (offset.top - 60)) {
                $('.navbar').attr('style', 'background-color: #fff !important; border-bottom: 4px solid #506a85;');
                $('.navbar-hello-text').removeClass('text-white').attr('style', 'color: #506a85 !important;');
                $('.navbar-brand').removeClass('text-white').attr('style', 'color: #506a85 !important;');
                $('.btn-header-register-login').removeClass('btn-outline-primary-inverse').addClass('btn-outline-primary');
            } else {
                $('.navbar').attr('style', 'background-color: transparent !important; border-bottom: none;');
                $('.navbar-hello-text').addClass('text-white').removeAttr('style');
                $('.navbar-brand').addClass('text-white').removeAttr('style');
                $('.btn-header-register-login').removeClass('btn-outline-primary').addClass('btn-outline-primary-inverse');
            }
        });
    }

    /**
     * User Profile
     */
    var minWidth = 992,
        sidebar = $('.sidebar-profile');

    if (sidebar.length && width >= minWidth) {
        var sidebarTop = sidebar.offset().top,
            bottom = $(".footer").outerHeight(!0);

        $(document).scroll(function() {
            var navbarHeight = $(".navbar").height() + 10,
                scrollStart = $(this).scrollTop();
            var top = sidebarTop - navbarHeight;

            if(scrollStart > top && !sidebar.hasClass('fixed')) {
                sidebar.addClass('fixed');
            }
            if (scrollStart < top && sidebar.hasClass('fixed')) {
                sidebar.removeClass('fixed');
            }
        });
    }
});
<commit_msg>Added messages to the console<commit_after>$(document).ready(function() {
    "use strict";

    $("body").tooltip({
        selector: "[data-toggle=tooltip]"
    });

    $("body").popover({
        selector: "[data-toggle=popover]"
    });

    /**
     * Custom messages in the Browser Console.
     */
    var width = "padding:5px 0;",
        infoPrimaryBackground = "background:#5ccc5c;",
        infoCornerBackground = "background:#a3f5a3;",
        infoTitle = "color:#5ccc5c;background:#2f4052;font-weight:bold;",
        messageInfo = [
            "\n %c  %c HELLO ! %c  %c  Don't forget that this website is open-source ! https://github.com/XetaIO/Xetaravel  %c  \n\n",
            infoPrimaryBackground + width,
            infoTitle + width,
            infoCornerBackground + width,
            "color:#fff;" + infoPrimaryBackground + width,
            infoCornerBackground + width
        ];

    var warnPrimaryBackground = "background:#c22;",
        warnCornerBackground = "background:#e44;",
        warnTitle = "color:#e44;background:#2f4052;font-weight:bold;",
        messageWarn = [
            "\n %c  %c ATTENTION %c  %c  DONT RUN ANY SCRIPT HERE ! IT WILL HAVE FULL ACCESS TO YOUR BROWSER AND YOUR ACCOUNT ! https://en.wikipedia.org/wiki/Self-XSS  %c  \n\n",
            warnPrimaryBackground + width,
            warnTitle + width,
            warnCornerBackground + width,
            "color:#fff;" + warnPrimaryBackground + width,
            warnCornerBackground + width
        ];
    console.log.apply(console, messageInfo);
    console.log.apply(console, messageWarn);

    /**
     * Navbar
     */
    var minWidth = 768,
        navbar = $('#change-navbar'),
        offset = navbar.offset(),
        width = window.innerWidth;

    if (navbar.length && width >= minWidth){
        $(document).scroll(function() {
            var scrollStart = $(this).scrollTop();
            if (scrollStart > (offset.top - 60)) {
                $('.navbar').attr('style', 'background-color: #fff !important; border-bottom: 4px solid #506a85;');
                $('.navbar-hello-text').removeClass('text-white').attr('style', 'color: #506a85 !important;');
                $('.navbar-brand').removeClass('text-white').attr('style', 'color: #506a85 !important;');
                $('.btn-header-register-login').removeClass('btn-outline-primary-inverse').addClass('btn-outline-primary');
            } else {
                $('.navbar').attr('style', 'background-color: transparent !important; border-bottom: none;');
                $('.navbar-hello-text').addClass('text-white').removeAttr('style');
                $('.navbar-brand').addClass('text-white').removeAttr('style');
                $('.btn-header-register-login').removeClass('btn-outline-primary').addClass('btn-outline-primary-inverse');
            }
        });
    }

    /**
     * User Profile
     */
    var minWidth = 992,
        sidebar = $('.sidebar-profile');

    if (sidebar.length && width >= minWidth) {
        var sidebarTop = sidebar.offset().top,
            bottom = $(".footer").outerHeight(!0);

        $(document).scroll(function() {
            var navbarHeight = $(".navbar").height() + 10,
                scrollStart = $(this).scrollTop();
            var top = sidebarTop - navbarHeight;

            if(scrollStart > top && !sidebar.hasClass('fixed')) {
                sidebar.addClass('fixed');
            }
            if (scrollStart < top && sidebar.hasClass('fixed')) {
                sidebar.removeClass('fixed');
            }
        });
    }
});
<|endoftext|>


<commit_before>var _ = require('underscore');
var request = require('request');
var cheerio = require('cheerio');

var models = require('../models');

var Scrape = models.Scrape;

var makerPage = function(req, res) {

    Scrape.ScrapeModel.findByOwner(req.session.account._id, function(err, docs) {

        if(err) {
            console.log(err);
            return res.status(400).json({error:'An error occurred'});
        }

        res.render('gallery', {scrapes: docs});
    });
};

function getTestResults(){
    var x = [];
    request('http://forum.miata.net/vb/forumdisplay.php?f=124', function (error, response, html) {
        if (!error && response.statusCode == 200) {
            var $ = cheerio.load(html);
            console.log('zxcvbnm');
            var tRes= $("a:contains('wheels')").each(function(){
                x.push($(this).href());
            });
            console.log(x);
        }
    });

    return [{url:'http://www.example.com/'}];
}

var testResults = getTestResults();

var makeScrape = function(req, res) {
    if(!req.body.url || !req.body.query) {
        return res.status(400).json({error: "Both URL and Query are required"});
    }

    var scrapeData = {
        url: req.body.url,
        query: req.body.query,
        results: testResults,
        owner: req.session.account._id
    };

    var newScrape = new Scrape.ScrapeModel(scrapeData);

    newScrape.save(function(err) {
        if(err) {
            console.log(err);
            return res.status(400).json({error:'An error occurred'});
        }

        res.json({redirect: '/gallery'});
    });

};

module.exports.makerPage = makerPage;
module.exports.make = makeScrape;<commit_msg>added request and cheerio, wrote a hard coded test query to get all of the links on a page<commit_after>var _ = require('underscore');
var request = require('request');
var cheerio = require('cheerio');

var models = require('../models');

var Scrape = models.Scrape;

var makerPage = function(req, res) {

    Scrape.ScrapeModel.findByOwner(req.session.account._id, function(err, docs) {

        if(err) {
            console.log(err);
            return res.status(400).json({error:'An error occurred'});
        }

        res.render('gallery', {scrapes: docs});
    });
};

function getTestResults(){
    request('http://forum.miata.net/vb/forumdisplay.php?f=124', function (error, response, html) {
        if (!error && response.statusCode == 200) {
            var $ = cheerio.load(html);
            console.log('zxcvbnm');
            var tRes= $("a:contains('wheels')").each(function(){
                console.log($(this).href());
            });
        }
    });

    return [{url:'http://www.example.com/'},{url:'http://www.example.com/'}];
}

var testResults = getTestResults();

var makeScrape = function(req, res) {
    if(!req.body.url || !req.body.query) {
        return res.status(400).json({error: "Both URL and Query are required"});
    }

    var scrapeData = {
        url: req.body.url,
        query: req.body.query,
        results: testResults,
        owner: req.session.account._id
    };

    var newScrape = new Scrape.ScrapeModel(scrapeData);

    newScrape.save(function(err) {
        if(err) {
            console.log(err);
            return res.status(400).json({error:'An error occurred'});
        }

        res.json({redirect: '/gallery'});
    });

};

module.exports.makerPage = makerPage;
module.exports.make = makeScrape;<|endoftext|>


<commit_before>import _ from 'lodash'

export function normalizeModelProperty (object) {
  if (Array.isArray(object)) {
    return object
      .map((item) => {
        return normalizeModelProperty(item)
      })
  }

  if (!_.isPlainObject(object)) {
    return object
  }

  Object.keys(object)
    .forEach((key) => {
      const isModelProperty = key === 'model' && _.isString(object[key])

      if (!isModelProperty) {
        object[key] = normalizeModelProperty(object[key])
        return
      }

      // Convert foo[0].bar to foo.0.bar
      object[key] = object[key].replace(/\[/g, '.').replace(/]/g, '')
    })

  return object
}

function normalizeView (bunsenView) {
  if (bunsenView.cellDefinitions) {
    normalizeModelProperty(bunsenView.cellDefinitions)
  }

  if (bunsenView.cells) {
    normalizeModelProperty(bunsenView.cells)
  }

  return bunsenView
}

export default normalizeView
<commit_msg>Add JSDoc<commit_after>import _ from 'lodash'

/**
 * Ensure model property in bunsen view partial uses dot notation for
 * referning array items by converting square brackets format to dot notation.
 * @param {Object} object - bunsen view partial
 * @returns {Object} normalized bunsen view partial
 */
export function normalizeModelProperty (object) {
  if (Array.isArray(object)) {
    return object
      .map((item) => {
        return normalizeModelProperty(item)
      })
  }

  if (!_.isPlainObject(object)) {
    return object
  }

  Object.keys(object)
    .forEach((key) => {
      const isModelProperty = key === 'model' && _.isString(object[key])

      if (!isModelProperty) {
        object[key] = normalizeModelProperty(object[key])
        return
      }

      // Convert foo[0].bar to foo.0.bar
      object[key] = object[key].replace(/\[/g, '.').replace(/]/g, '')
    })

  return object
}

/**
 * Normalize bunsen view to be more strict (ie. cleaning up model properties)
 * @param {Object} bunsenView - bunsen view
 * @returns {Object} normalized bunsen view
 */
function normalizeView (bunsenView) {
  if (bunsenView.cellDefinitions) {
    normalizeModelProperty(bunsenView.cellDefinitions)
  }

  if (bunsenView.cells) {
    normalizeModelProperty(bunsenView.cells)
  }

  return bunsenView
}

export default normalizeView
<|endoftext|>


<commit_before>var UI = require('ui');
var Vector2 = require('vector2');

var wind = new UI.Window();
var textfield = new UI.Text({
  position:   new Vector2(0, 50),
  size:       new Vector2(144, 30),
  font:       'gothic-24-bold',
  text:       'Wait bitch...',
  textAlign:  'center'
});
wind.add(textfield);
wind.show();

function locationSuccess(pos) {
  var coordinates = pos.coords;
  console.log(pos.coords);
  // fetchWeather(coordinates.latitude, coordinates.longitude);
}

function locationError(err) {
  console.warn('location error (' + err.code + '): ' + err.message);
  Pebble.sendAppMessage({
    "city":"Loc Unavailable",
    "temperature":"N/A"
  });
}

var locationOptions = { "timeout": 15000, "maximumAge": 60000 };

Pebble.addEventListener("ready", function(e) {
  console.log("connect!" + e.ready);
  locationWatcher = window.navigator.geolocation.watchPosition(locationSuccess, locationError, locationOptions);
  console.log(e.type);
});<commit_msg>functionally ready, time for ux<commit_after>var UI = require('ui');
var Vector2 = require('vector2');

var textfield = new UI.Text({
  position:   new Vector2(0, 50),
  size:       new Vector2(144, 30),
  font:       'gothic-24-bold',
  text:       'Bitch wait...',
  textAlign:  'center'
});

var wind = new UI.Window();
wind.add(textfield);
wind.show();

function locationSuccess(pos) {
  var coordinates = pos.coords;
  fetchWeather(coordinates.latitude, coordinates.longitude);
}

function locationError(err) {
  console.warn('location error (' + err.code + '): ' + err.message);
  textfield.text('GPS broke yo');
}

var locationOptions = { "timeout": 15000, "maximumAge": 60000 };

window.navigator.geolocation.watchPosition(locationSuccess, locationError, locationOptions);

function fetchWeather(latitude, longitude) {
  var response, temperature, city;
  var req = new XMLHttpRequest();
  req.open('GET', "http://api.openweathermap.org/data/2.1/find/city?" + "lat=" + latitude + "&lon=" + longitude + "&cnt=1", true);

  req.onload = function(e) {
    if (req.readyState == 4) {
      if(req.status == 200) {
        response = JSON.parse(req.responseText);

        if (response && response.list && response.list.length > 0) {
          var weatherResult = response.list[0];

          temperature = convertToFahrenheit(Math.round(weatherResult.main.temp - 273.15));
          city = weatherResult.name;

          console.log(temperature);
          console.log(city);
          textfield.text('It is ' + temperature + "\u00B0F" + ' in ' + city);
        }

      } else {
        console.log("Error");
      }
    }
  }
  req.send(null);
}

function convertToFahrenheit(celcius) {
  return celcius * 1.8 + 32;
}<|endoftext|>


<commit_before>import { Component } from "react";
import _ from "lodash";
import { connect } from "react-redux";
import {loadScript, loadStyle} from "../../utils/utils";
import { screenLoaded } from "../screen/action";

const __development = process.env.NODE_ENV === "development";

@connect (state => {
  return {
    screen: state.screen
  };
})
export default class CoreRoot extends Component {

  async loadPreloadCSS() {
    let linksPromise = [];
    if (typeof window !== "undefined" && typeof window.document !== "undefined") {
      _.forEach(window.document.querySelectorAll("link[rel=preload]"), link => {
        linksPromise.push(loadStyle(link.href));
      });
      if (linksPromise.length) {
        await Promise.all(linksPromise);
      }
    }
    return Promise.resolve();
  }
  loadGoogleAnalytics() {
    if(typeof window === "undefined") return;
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      "gtm.start": new Date().getTime(),
      event: "gtm.js"
    });
    loadScript("https://www.googletagmanager.com/gtm.js?id=GTM-TW9PBND").catch();
  }

  componentDidMount() {
    // Trigger screenLoaded once all the preload-css are loaded
    this.loadPreloadCSS().then(() => {
      this.props.dispatch(screenLoaded());
    });
    // Load google analytics
    !__development && this.loadGoogleAnalytics();
  }
  render() {
    return this.props.children || null;
  }
}<commit_msg>Deploy new GTM<commit_after>import { Component } from "react";
import _ from "lodash";
import { connect } from "react-redux";
import {loadScript, loadStyle} from "../../utils/utils";
import { screenLoaded } from "../screen/action";

const __development = process.env.NODE_ENV === "development";

@connect (state => {
  return {
    screen: state.screen
  };
})
export default class CoreRoot extends Component {

  async loadPreloadCSS() {
    let linksPromise = [];
    if (typeof window !== "undefined" && typeof window.document !== "undefined") {
      _.forEach(window.document.querySelectorAll("link[rel=preload]"), link => {
        linksPromise.push(loadStyle(link.href));
      });
      if (linksPromise.length) {
        await Promise.all(linksPromise);
      }
    }
    return Promise.resolve();
  }
  loadGoogleAnalytics() {
    if(typeof window === "undefined") return;
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      "gtm.start": new Date().getTime(),
      event: "gtm.js"
    });
    // change gtm
    loadScript("https://www.googletagmanager.com/gtm.js?id=GTM-TW9PBND").catch();
  }

  componentDidMount() {
    // Trigger screenLoaded once all the preload-css are loaded
    this.loadPreloadCSS().then(() => {
      this.props.dispatch(screenLoaded());
    });
    // Load google analytics
    !__development && this.loadGoogleAnalytics();
  }
  render() {
    return this.props.children || null;
  }
}<|endoftext|>


<commit_before>/*eslint-disable no-var*/
/*!
    Feature Filter by

    (c) mapbox 2016
    www.mapbox.com
    License: MIT, header required.
*/
var types = ['Unknown', 'Point', 'LineString', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection'];

/**
 * Given a filter expressed as nested arrays, return a new function
 * that evaluates whether a given feature (with a .properties or .tags property)
 * passes its test.
 *
 * @param {Array} filter mapbox gl filter
 * @returns {Function} filter-evaluating function
 * @memberOf MapboxUtil
 */
export function createFilter(filter) {
    return new Function('f', 'var p = (f && f.properties || {}); return ' + compile(filter));
}

function compile(filter) {
    if (!filter) return 'true';
    var op = filter[0];
    if (filter.length <= 1) return op === 'any' ? 'false' : 'true';
    var str =
        op === '==' ? compileComparisonOp(filter[1], filter[2], '===', false) :
            op === '!=' ? compileComparisonOp(filter[1], filter[2], '!==', false) :
                op === '<' ||
        op === '>' ||
        op === '<=' ||
        op === '>=' ? compileComparisonOp(filter[1], filter[2], op, true) :
                    op === 'any' ? compileLogicalOp(filter.slice(1), '||') :
                        op === 'all' ? compileLogicalOp(filter.slice(1), '&&') :
                            op === 'none' ? compileNegation(compileLogicalOp(filter.slice(1), '||')) :
                                op === 'in' ? compileInOp(filter[1], filter.slice(2)) :
                                    op === '!in' ? compileNegation(compileInOp(filter[1], filter.slice(2))) :
                                        op === 'has' ? compileHasOp(filter[1]) :
                                            op === '!has' ? compileNegation(compileHasOp([filter[1]])) :
                                                'true';
    return '(' + str + ')';
}

function compilePropertyReference(property) {
    return property[0] === '$' ? 'f.' + property.substring(1) : 'p[' + JSON.stringify(property) + ']';
}

function compileComparisonOp(property, value, op, checkType) {
    var left = compilePropertyReference(property);
    var right = property === '$type' ? types.indexOf(value) : JSON.stringify(value);
    return (checkType ? 'typeof ' + left + '=== typeof ' + right + '&&' : '') + left + op + right;
}

function compileLogicalOp(expressions, op) {
    return expressions.map(compile).join(op);
}

function compileInOp(property, values) {
    if (property === '$type') values = values.map(function (value) { return types.indexOf(value); });
    var left = JSON.stringify(values.sort(compare));
    var right = compilePropertyReference(property);

    if (values.length <= 200) return left + '.indexOf(' + right + ') !== -1';
    return 'function(v, a, i, j) {' +
        'while (i <= j) { var m = (i + j) >> 1;' +
        '    if (a[m] === v) return true; if (a[m] > v) j = m - 1; else i = m + 1;' +
        '}' +
    'return false; }(' + right + ', ' + left + ',0,' + (values.length - 1) + ')';
}

function compileHasOp(property) {
    return JSON.stringify(property) + ' in p';
}

function compileNegation(expression) {
    return '!(' + expression + ')';
}

// Comparison function to sort numbers and strings
function compare(a, b) {
    return a  b ? 1 : 0;
}

/**
 * Get feature object from a geometry for filter functions.
 * @param  {Geometry} geometry geometry
 * @return {Object}          feature for filter functions
 * @memberOf MapboxUtil
 */
export function getFilterFeature(geometry) {
    const json = geometry._toJSON(),
        g = json['feature'];
    g['type'] = types.indexOf(g['geometry']['type']);
    g['subType'] = json['subType'];
    return g;
}

/**
 * Compile layer's style, styles to symbolize layer's geometries, e.g.

 *

 * [
 *   {
 *     'filter' : ['==', 'foo', 'val'],
 *     'symbol' : {'markerFile':'foo.png'}
 *   }
 * ]
 *

 * @param  {Object|Object[]} styles - style to compile
 * @return {Object[]}       compiled styles
 * @memberOf MapboxUtil
 */
export function compileStyle(styles) {
    if (!Array.isArray(styles)) {
        return compileStyle([styles]);
    }
    const compiled = [];
    for (let i = 0; i < styles.length; i++) {
        if (styles[i]['filter'] === true) {
            compiled.push({
                filter: function () {
                    return true;
                },
                symbol: styles[i].symbol
            });
        } else {
            compiled.push({
                filter: createFilter(styles[i]['filter']),
                symbol: styles[i].symbol
            });
        }
    }
    return compiled;
}
/*eslint-enable no-var*/
<commit_msg>update FeatureFilter<commit_after>/*eslint-disable no-var*/
/*!
    Feature Filter by

    (c) mapbox 2016
    www.mapbox.com
    License: MIT, header required.
*/
const types = ['Unknown', 'Point', 'LineString', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection'];

/**
 * Given a filter expressed as nested arrays, return a new function
 * that evaluates whether a given feature (with a .properties or .tags property)
 * passes its test.
 *
 * @private
 * @param {Array} filter mapbox gl filter
 * @returns {Function} filter-evaluating function
 * @memberOf MapboxUtil
 */
export function createFilter(filter) {
    return new Function('f', `var p = (f && f.properties || {}); return ${compile(filter)}`);
}

function compile(filter) {
    if (!filter) return 'true';
    const op = filter[0];
    if (filter.length <= 1) return op === 'any' ? 'false' : 'true';
    const str =
        op === '==' ? compileComparisonOp(filter[1], filter[2], '===', false) :
            op === '!=' ? compileComparisonOp(filter[1], filter[2], '!==', false) :
                op === '<' ||
                    op === '>' ||
        op === '<=' ||
        op === '>=' ? compileComparisonOp(filter[1], filter[2], op, true) :
                    op === 'any' ? compileLogicalOp(filter.slice(1), '||') :
                        op === 'all' ? compileLogicalOp(filter.slice(1), '&&') :
                            op === 'none' ? compileNegation(compileLogicalOp(filter.slice(1), '||')) :
                                op === 'in' ? compileInOp(filter[1], filter.slice(2)) :
                                    op === '!in' ? compileNegation(compileInOp(filter[1], filter.slice(2))) :
                                        op === 'has' ? compileHasOp(filter[1]) :
                                            op === '!has' ? compileNegation(compileHasOp(filter[1])) :
                                                'true';
    return `(${str})`;
}

function compilePropertyReference(property) {
    // const ref =
    //     property === '$type' ? 'f.type' :
    //         property === '$id' ? 'f.id' : `p[${JSON.stringify(property)}]`;
    // return ref;
    return property[0] === '$' ? 'f.' + property.substring(1) : 'p[' + JSON.stringify(property) + ']';
}

function compileComparisonOp(property, value, op, checkType) {
    const left = compilePropertyReference(property);
    const right = property === '$type' ? types.indexOf(value) : JSON.stringify(value);
    return (checkType ? `typeof ${left}=== typeof ${right}&&` : '') + left + op + right;
}

function compileLogicalOp(expressions, op) {
    return expressions.map(compile).join(op);
}

function compileInOp(property, values) {
    if (property === '$type') values = values.map((value) => {
        return types.indexOf(value);
    });
    const left = JSON.stringify(values.sort(compare));
    const right = compilePropertyReference(property);

    if (values.length <= 200) return `${left}.indexOf(${right}) !== -1`;

    return `${'function(v, a, i, j) {' +
        'while (i <= j) { var m = (i + j) >> 1;' +
        '    if (a[m] === v) return true; if (a[m] > v) j = m - 1; else i = m + 1;' +
        '}' +
    'return false; }('}${right}, ${left},0,${values.length - 1})`;
}

function compileHasOp(property) {
    return property === '$id' ? '"id" in f' : `${JSON.stringify(property)} in p`;
}

function compileNegation(expression) {
    return `!(${expression})`;
}

// Comparison function to sort numbers and strings
function compare(a, b) {
    return a  b ? 1 : 0;
}

/**
 * Get feature object from a geometry for filter functions.
 * @param  {Geometry} geometry geometry
 * @return {Object}          feature for filter functions
 * @memberOf MapboxUtil
 */
export function getFilterFeature(geometry) {
    const json = geometry._toJSON(),
        g = json['feature'];
    g['type'] = types.indexOf(g['geometry']['type']);
    g['subType'] = json['subType'];
    return g;
}

/**
 * Compile layer's style, styles to symbolize layer's geometries, e.g.

 *

 * [
 *   {
 *     'filter' : ['==', 'foo', 'val'],
 *     'symbol' : {'markerFile':'foo.png'}
 *   }
 * ]
 *

 * @param  {Object|Object[]} styles - style to compile
 * @return {Object[]}       compiled styles
 * @memberOf MapboxUtil
 */
export function compileStyle(styles) {
    if (!Array.isArray(styles)) {
        return compileStyle([styles]);
    }
    const compiled = [];
    for (let i = 0; i < styles.length; i++) {
        if (styles[i]['filter'] === true) {
            compiled.push({
                filter: function () {
                    return true;
                },
                symbol: styles[i].symbol
            });
        } else {
            compiled.push({
                filter: createFilter(styles[i]['filter']),
                symbol: styles[i].symbol
            });
        }
    }
    return compiled;
}
/*eslint-enable no-var*/
<|endoftext|>