<commit_before>var FieldType = require('../Type');
var marked = require('marked');
var util = require('util');
var validators = require('../validators');

/**
 * Markdown FieldType Constructor
 * @extends Field
 * @api public
 */

function markdown (list, path, options) {
	this._defaultSize = 'full';

	this.toolbarOptions = options.toolbarOptions || {};
	this.markedOptions = options.markedOptions || {};
	this.height = options.height || 90;
	this.wysiwyg = ('wysiwyg' in options) ? options.wysiwyg : true;

	this._properties = ['wysiwyg', 'height', 'toolbarOptions'];
	markdown.super_.call(this, list, path, options);
}
util.inherits(markdown, FieldType);

/* Use text validators */
markdown.prototype.validateInput = validators.text.input;
markdown.prototype.validateRequiredInput = validators.text.required;

/**
 * Registers the field on the List's Mongoose Schema.
 *
 * Adds String properties for .md and .html markdown, and a setter for .md
 * that generates html when it is updated.
 *
 * @api public
 */
markdown.prototype.addToSchema = function () {

	var schema = this.list.schema;

	var paths = this.paths = {
		md: this._path.append('.md'),
		html: this._path.append('.html'),
	};

	var markedOptions = this.markedOptions;

	var setMarkdown = function (value) {
		if (value === this.get(paths.md)) {
			return value;
		}
		if (typeof value === 'string') {
			this.set(paths.html, marked(value, markedOptions));
			return value;
		} else {
			this.set(paths.html, undefined);
			return undefined;
		}
	};

	schema.nested[this.path] = true;
	schema.add({
		html: { type: String },
		md: { type: String, set: setMarkdown },
	}, this.path + '.');

	this.bindUnderscoreMethods();
};

/**
 * Formats the field value
 *
 * @api public
 */
markdown.prototype.format = function (item) {
	return item.get(this.paths.html);
};

/**
 * Validates that a value for this field has been provided in a data object
 *
 * Deprecated
 */
markdown.prototype.inputIsValid = function (data, required, item) {
	if (!(this.path in data) && item && item.get(this.paths.md)) {
		return true;
	}
	return (!required || data[this.path]) ? true : false;
};

/**
 * Detects whether the field has been modified
 *
 * @api public
 */
markdown.prototype.isModified = function (item) {
	return item.isModified(this.paths.md);
};

/**
 * Updates the value for this field in the item from a data object
 *
 * Will accept either the field path, or paths.md
 *
 * @api public
 */
markdown.prototype.updateItem = function (item, data, callback) {
	var value = this.getValueFromData(data);
	if (value !== undefined) {
		item.set(this.paths.md, value);
	}
	process.nextTick(callback);
};

/* Export Field Type */
module.exports = markdown;
<commit_msg>Fix #2368: markdown fields are not updated<commit_after>var FieldType = require('../Type');
var marked = require('marked');
var util = require('util');
var validators = require('../validators');

/**
 * Markdown FieldType Constructor
 * @extends Field
 * @api public
 */

function markdown (list, path, options) {
	this._defaultSize = 'full';

	this.toolbarOptions = options.toolbarOptions || {};
	this.markedOptions = options.markedOptions || {};
	this.height = options.height || 90;
	this.wysiwyg = ('wysiwyg' in options) ? options.wysiwyg : true;

	this._properties = ['wysiwyg', 'height', 'toolbarOptions'];
	markdown.super_.call(this, list, path, options);
}
util.inherits(markdown, FieldType);

/* Use text validators */
markdown.prototype.validateInput = validators.text.input;
markdown.prototype.validateRequiredInput = validators.text.required;

/**
 * Registers the field on the List's Mongoose Schema.
 *
 * Adds String properties for .md and .html markdown, and a setter for .md
 * that generates html when it is updated.
 *
 * @api public
 */
markdown.prototype.addToSchema = function () {

	var schema = this.list.schema;

	var paths = this.paths = {
		md: this._path.append('.md'),
		html: this._path.append('.html'),
	};

	var markedOptions = this.markedOptions;

	var setMarkdown = function (value) {
		if (value === this.get(paths.md)) {
			return value;
		}
		if (typeof value === 'string') {
			this.set(paths.html, marked(value, markedOptions));
			return value;
		} else {
			this.set(paths.html, undefined);
			return undefined;
		}
	};

	schema.nested[this.path] = true;
	schema.add({
		html: { type: String },
		md: { type: String, set: setMarkdown },
	}, this.path + '.');

	this.bindUnderscoreMethods();
};

/**
 * Formats the field value
 *
 * @api public
 */
markdown.prototype.format = function (item) {
	return item.get(this.paths.html);
};

/**
 * Validates that a value for this field has been provided in a data object
 *
 * Deprecated
 */
markdown.prototype.inputIsValid = function (data, required, item) {
	if (!(this.path in data) && item && item.get(this.paths.md)) {
		return true;
	}
	return (!required || data[this.path]) ? true : false;
};

/**
 * Detects whether the field has been modified
 *
 * @api public
 */
markdown.prototype.isModified = function (item) {
	return item.isModified(this.paths.md);
};

/**
 * Updates the value for this field in the item from a data object
 *
 * Will accept either the field path, or paths.md
 *
 * @api public
 */
markdown.prototype.updateItem = function (item, data, callback) {
	var value = this.getValueFromData(data);
	if (value !== undefined) {
		item.set(this.paths.md, value);
	}	else if (this.paths.md in data) {
			item.set(this.paths.md, data[this.paths.md]);
	}
	process.nextTick(callback);
};

/* Export Field Type */
module.exports = markdown;
<|endoftext|>


<commit_before>"use strict";

const qs = require('query-string'),
  OAuth2 = require('oauth').OAuth2;

const waigo = global.waigo,
  _ = waigo._,
  Q = waigo.load('support/promise'),
  OauthError = waigo.load('support/oauth/index').OauthError;

/**
 * Base class for OAuth providers.
 */
class GenericOauth {
  /**
   * @constructor
   * @param  {Object} context  Current request context.
   * @param  {String} provider Id of provider.
   * @param  {Object} [tokens]   Access tokens previously obtained.
   */
  constructor (context, provider, tokens) {
    this.context = context;
    this.provider = provider;
    this.app = this.context.app;
    this.logger = context.logger.create(`Oauth-${provider}`);

    this.config = _.get(this.app.config.oauth, this.provider, {});
    this.callbackURL = this.app.routeUrl('oauth_callback', {
      provider: provider,
    });

    this.oauth2 = new OAuth2(
      this.config.clientId,
      this.config.clientSecret,
      this.config.baseURL,
      this.config.authorizePath,
      this.config.accessTokenPath,
      {
        'Content-Type': 'application/json',
      }
    );

    this.tokens = tokens;

    if (this.tokens) {
      this.authHeader = {
        'Authorization': `Bearer ${this.tokens.access_token}`,
      };
    }
  }

  /**
   * Get OAuth authorization URL.
   * @return {String}
   */
  getAuthorizeUrl () {
    let params = this._buildBasicParams();

    let url = this.oauth2.getAuthorizeUrl(params);

    this.logger.debug('authorize url', url);

    return url;
  }

  /**
   * Get OAuth access token.
   * @param {String} code Code returned by OAuth provider.
   */
  * getAccessToken (code) {
    let user = this._user();

    this.logger.info(`Get access token: user=${user.id ? user.id : 'anon'} code=${code}`);

    try {
      return yield new Q(function(resolve, reject) {
        let params = this._buildAccessTokenParams();

        this.oauth2.getOAuthAccessToken(code, params, (err, access_token, refresh_token, result) => {
          if (err) {
            return reject(new OauthError('Get access token error', err.statusCode || 400, err));
          }

          // check that scope is still the same
          if (result.scope !== _.get(this.config, 'authorizeParams.scope')) {
            return reject(new OauthError('Scope mismatch'));
          }

          resolve({
            access_token: access_token,
            refresh_token: refresh_token,
            result: result,
          });
        });
      });

    } catch (err) {
      yield this._handleError(err, {
        method: 'getOAuthAccessToken',
      });
    }
  }

  * _get (url, queryParams) {
    return yield this._request('GET', url, queryParams);
  }

  * _post (url, queryParams, body) {
    return yield this._request('POST', url, queryParams, body);
  }

  _buildRequestUrl (url, queryParams) {
    let apiBaseUrl = this.config.apiBaseUrl;

    if (!_.get(apiBaseUrl, 'length')) {
      throw new OauthError(`${this.provider}: apiBaseUrl must be provided`);
    }

    url = this.config.apiBaseUrl + url;

    queryParams = qs.stringify(queryParams || {});

    if (queryParams.length) {
      url += '?' + queryParams;
    }

    return url;
  }

  * _request (method, url, queryParams, body) {
    url = this._buildRequestUrl(url, queryParams);

    this.logger.debug(method, url);

    if (body) {
      body = JSON.stringify(body);
    }

    try {
      return yield new Q(function(resolve, reject) {
        this.oauth2._request(method, url, this.authHeader, body, this.accessToken, (err, result) => {
          if (err) {
            return reject(new OauthError(method + ' error', err.statusCode || 400, err));
          }

          try {
            result = JSON.parse(result);
          } catch (e) {
            // nothing to do here
          }

          resolve(result);
        });
      });

    } catch (err) {
      yield this._handleError(err, {
        method: method,
        url: url,
        body: body,
      });
    }
  }

  _buildAuthorizeParams () {
    let params = _.extend({}, _.get(this.config, 'authorizeParams'));

    let callbackParamName = _.get(this.config, 'callbackParam', 'redirect_uri');

    params[callbackParamName] = this.callbackURL;

    return params;
  }

  _buildAccessTokenParams () {
    return _.extend({}, _.get(this.config, 'accessTokenParams'));
  }

  _user () {
    return _.get(this.context, 'currentUser', {});
  }

  * _handleError (err, attrs) {
    this.logger.error(err);

    yield this.context.record('oauth_request', this._user(), _.extend({}, attrs, {
      type: 'error',
      provider: this.provider,
      message: err.message,
      details: err.details,
    }));

    throw err;
  }

}

module.exports = GenericOauth;

<commit_msg>bugfix<commit_after>"use strict";

const qs = require('query-string'),
  OAuth2 = require('oauth').OAuth2;

const waigo = global.waigo,
  _ = waigo._,
  Q = waigo.load('support/promise'),
  OauthError = waigo.load('support/oauth/index').OauthError;

/**
 * Base class for OAuth providers.
 */
class GenericOauth {
  /**
   * @constructor
   * @param  {Object} context  Current request context.
   * @param  {String} provider Id of provider.
   * @param  {Object} [tokens]   Access tokens previously obtained.
   */
  constructor (context, provider, tokens) {
    this.context = context;
    this.provider = provider;
    this.app = this.context.app;
    this.logger = context.logger.create(`Oauth-${provider}`);

    this.config = _.get(this.app.config.oauth, this.provider, {});
    this.callbackURL = this.app.routeUrl('oauth_callback', {
      provider: provider,
    });

    this.oauth2 = new OAuth2(
      this.config.clientId,
      this.config.clientSecret,
      this.config.baseURL,
      this.config.authorizePath,
      this.config.accessTokenPath,
      {
        'Content-Type': 'application/json',
      }
    );

    this.tokens = tokens;

    if (this.tokens) {
      this.authHeader = {
        'Authorization': `Bearer ${this.tokens.access_token}`,
      };
    }
  }

  /**
   * Get OAuth authorization URL.
   * @return {String}
   */
  getAuthorizeUrl () {
    let params = this._buildAuthorizeParams();

    let url = this.oauth2.getAuthorizeUrl(params);

    this.logger.debug('authorize url', url);

    return url;
  }

  /**
   * Get OAuth access token.
   * @param {String} code Code returned by OAuth provider.
   */
  * getAccessToken (code) {
    let user = this._user();

    this.logger.info(`Get access token: user=${user.id ? user.id : 'anon'} code=${code}`);

    try {
      return yield new Q(function(resolve, reject) {
        let params = this._buildAccessTokenParams();

        this.oauth2.getOAuthAccessToken(code, params, (err, access_token, refresh_token, result) => {
          if (err) {
            return reject(new OauthError('Get access token error', err.statusCode || 400, err));
          }

          // check that scope is still the same
          if (result.scope !== _.get(this.config, 'authorizeParams.scope')) {
            return reject(new OauthError('Scope mismatch'));
          }

          resolve({
            access_token: access_token,
            refresh_token: refresh_token,
            result: result,
          });
        });
      });

    } catch (err) {
      yield this._handleError(err, {
        method: 'getOAuthAccessToken',
      });
    }
  }

  * _get (url, queryParams) {
    return yield this._request('GET', url, queryParams);
  }

  * _post (url, queryParams, body) {
    return yield this._request('POST', url, queryParams, body);
  }

  _buildRequestUrl (url, queryParams) {
    let apiBaseUrl = this.config.apiBaseUrl;

    if (!_.get(apiBaseUrl, 'length')) {
      throw new OauthError(`${this.provider}: apiBaseUrl must be provided`);
    }

    url = this.config.apiBaseUrl + url;

    queryParams = qs.stringify(queryParams || {});

    if (queryParams.length) {
      url += '?' + queryParams;
    }

    return url;
  }

  * _request (method, url, queryParams, body) {
    url = this._buildRequestUrl(url, queryParams);

    this.logger.debug(method, url);

    if (body) {
      body = JSON.stringify(body);
    }

    try {
      return yield new Q(function(resolve, reject) {
        this.oauth2._request(method, url, this.authHeader, body, this.accessToken, (err, result) => {
          if (err) {
            return reject(new OauthError(method + ' error', err.statusCode || 400, err));
          }

          try {
            result = JSON.parse(result);
          } catch (e) {
            // nothing to do here
          }

          resolve(result);
        });
      });

    } catch (err) {
      yield this._handleError(err, {
        method: method,
        url: url,
        body: body,
      });
    }
  }

  _buildAuthorizeParams () {
    let params = _.extend({}, _.get(this.config, 'authorizeParams'));

    let callbackParamName = _.get(this.config, 'callbackParam', 'redirect_uri');

    params[callbackParamName] = this.callbackURL;

    return params;
  }

  _buildAccessTokenParams () {
    return _.extend({}, _.get(this.config, 'accessTokenParams'));
  }

  _user () {
    return _.get(this.context, 'currentUser', {});
  }

  * _handleError (err, attrs) {
    this.logger.error(err);

    yield this.context.record('oauth_request', this._user(), _.extend({}, attrs, {
      type: 'error',
      provider: this.provider,
      message: err.message,
      details: err.details,
    }));

    throw err;
  }

}

module.exports = GenericOauth;

<|endoftext|>


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

var temperatureControlerObject = function() {
  var targetTemperature = 225;
  var actualTempurature = 0;

  var getTargetTemperature = function(){
    return targetTemperature;
  }

  var setTargetTemperature = function(newTargetTemp){
    targetTemperature = newTargetTemp;
  }
  var incrementTargetTemperature = function() {
    setTargetTemperature(++targetTemperature);
  }
  var decrementTargetTemperature = function() {
    setTargetTemperature(--targetTemperature);
  }

  var getActualTemperature = function(){
    //Run code to determine actual temperature
    adcinterface.read(0, function(thermValue){
      adcinterface.read(1, function(controlValue){
        var voltageDiff = ((controlValue - thermValue)* 5.0) / 1023;
        return voltageDiff;
      });
    });
  }

  return {
    //Pubic functions
    getTargetTemperature: getTargetTemperature,
    setTargetTemperature: setTargetTemperature,
    incrementTargetTemperature: incrementTargetTemperature,
    decrementTargetTemperature: decrementTargetTemperature,
    getActualTemperature: getActualTemperature
  }
}();

module.exports = temperatureControlerObject;
<commit_msg>Attempted bug fix<commit_after>var adcinterface = require('./adcinterface');

var temperatureControlerObject = function() {
  var targetTemperature = 225;
  var actualTempurature = 0;

  var getTargetTemperature = function(){
    return targetTemperature;
  }

  var setTargetTemperature = function(newTargetTemp){
    targetTemperature = newTargetTemp;
  }
  var incrementTargetTemperature = function() {
    setTargetTemperature(++targetTemperature);
  }
  var decrementTargetTemperature = function() {
    setTargetTemperature(--targetTemperature);
  }

  var getActualTemperature = function(){
    //Run code to determine actual temperature
    adcinterface.readChannel(0, function(thermValue){
      adcinterface.readChannel(1, function(controlValue){
        var voltageDiff = ((controlValue - thermValue)* 5.0) / 1023;
        return voltageDiff;
      });
    });
  }

  return {
    //Pubic functions
    getTargetTemperature: getTargetTemperature,
    setTargetTemperature: setTargetTemperature,
    incrementTargetTemperature: incrementTargetTemperature,
    decrementTargetTemperature: decrementTargetTemperature,
    getActualTemperature: getActualTemperature
  }
}();

module.exports = temperatureControlerObject;
<|endoftext|>


<commit_before>var DataService = require("logic/service/data-service").DataService,
    DataSelector = require("logic/service/data-selector").DataSelector,
    DataStream = require("logic/service/data-stream").DataStream;

/**
 * Provides data objects of certain types and manages changes to them based on
 * "raw" data obtained from or sent to one or more other services, typically
 * REST or other network services. Raw data services can therefore be considered
 * proxies for these REST or other services.
 *
 * Raw data services are usually the children of a
 * [data service]{@link DataService} that often is the application's
 * [main data service]{@link DataService.mainService}. All calls to raw data
 * services that have parent services must be routed through those parents.
 *
 * Raw data service subclasses that implement their own constructor should call
 * this class' constructor at the beginning of their constructor implementation
 * with code like the following:
 *
 *     RawDataService.call(this);
 *
 * @class
 * @extends DataService
 */
exports.RawDataService = DataService.specialize(/** @lends RawDataService.prototype */ {

    /***************************************************************************
     * Initializing
     */

    constructor: {
        value: function RawDataService() {
            DataService.call(this);
        }
    },

    /***************************************************************************
     * Basic Properties
     *
     * Private properties are defined where they are used, not here.
     */

    /**
     * If defined, used by
     * [mapRawDataToObject()]{@link RawDataService#mapRawDataToObject} and
     * [mapObjectToRawData()]{@link RawDataService#mapObjectToRawData} to map
     * between the raw data on which this service is based and the typed data
     * objects which this service provides and manages.
     *
     * @type {?DataMapping}
     */
    mapping: {
        value: undefined
    },

    /***************************************************************************
     * Tracking Data Object Changes
     */

    createdDataObjects: {
        get: function () {
            return this.rootService.createdDataObjects();
        }
    },

    changedDataObjects: {
        get: function () {
            return this.rootService.changedDataObjects();
        }
    },

    /***************************************************************************
     * Creating Data Objects
     */

    getDataObject: {
        value: function (type, record, context) {
            return this.rootService.getDataObject(type, record, context);
        }
    },

    createDataObject: {
        value: function (type) {
            return this.rootService.createDataObject(type);
        }
    },

    /***************************************************************************
     * Fetching Data Objects
     */

    /**
     * Fetch data from this service for its parent. This method should not be
     * called directly by anyone other than this service's parent. Calls to the
     * root service should be made to initiate data fetches.
     *
     * Subclasses should override this method to fetch the data objects
     * requested by:
     *
     * 1. Fetching the raw records needed to generate the data object.
     *
     * 2. Adding those records to the specified stream with calls to
     * [addRawData()]{@link RawDataService#addRawData}.
     *
     * 3. Indicating that the fetching is done with a call to
     * [rawDataDone()]{@link RawDataService#rawDataDone}.
     *
     * This method must be asynchronous and return as soon as possible even if
     * it takes a while to obtain the raw records needed to generate the
     * requested data objects. The data objects can be generated and added to
     * the specified stream at any point after this method is called with calls
     * to [addRawData()]{@link RawDataService#addRawData} and
     * [rawDataDone()]{@link RawDataService#rawDataDone}.
     *
     * When offline, [isOffline]{@link RawDataService#isOffline} can be used in
     * conjunction with an [OfflineService]{@link RawDataService#offlineService}
     * to fetch the raw records used ot generate the requested data objects.
     *
     * @method
     * @argument {DataSelector} selector - Defines what data should be fetched.
     * @argument {DataStream} stream     - A stream to which the fetched data
     *                                     can be added. Unlike for the
     *                                     [superclass]{@link DataService#fetchData}
     *                                     implementation of this method this
     *                                     stream is required for this class.
     * @returns {?DataStream} - The stream to which the fetched data objects
     * were or will be added. An `undefined` or `null` value may be returned, in
     * which case the calling parent should assume the fetched data objects were
     * or will be added to the passed in stream.
     */
    fetchData: {
        value: function (selector, stream) {
            this.fetchRawData(stream);
            return stream;
        }
    },

    /***************************************************************************
     * Saving Changed Data Objects
     */

    /**
     * Subclasses should override this method to delete a data object.
     *
     * The default implementation calls the deprecated
     * [deleteRawData()]{@link RawDataService#deleteRawData} method, which does
     * nothing by default.
     *
     * @method
     * @argument {Object} object   - The object whose data should be deleted.
     * @returns {external:Promise} - A promise fulfilled when the object has
     * been deleted.
     */
    deleteDataObject: {
        value: function (object) {
            var record = {};
            this.mapObjectToRawData(object, record);
            return this.deleteRawData(record, object);
        }
    },

    /**
     * Subclasses should override this method to save a data object.
     *
     * The default implementation calls the deprecated
     * [saveRawData()]{@link RawDataService#saveRawData} method, which does
     * nothing by default.
     *
     * @method
     * @argument {Object} object   - The object whose data should be saved.
     * @returns {external:Promise} - A promise fulfilled when all of the data in
     * the changed object has been saved.
     */
    saveDataObject: {
        value: function (object) {
            var record = {};
            this.mapObjectToRawData(object, record);
            return this.saveRawData(record, object);
        }
    },

    saveDataChanges: {
        value: function () {
            return this.rootService.saveDataChanges();
        }
    },

    /***************************************************************************
     * Managing Data Object Property Values
     */

    decacheObjectProperties: {
        value: function (object, propertyNames) {
            return this.rootService.decacheObjectProperties(object, propertyNames);
        }
    },

    getObjectProperties: {
        value: function (object, propertyNames) {
            return this.rootService.getObjectProperties(object, propertyNames);
        }
    },

    updateObjectProperties: {
        value: function (object, propertyNames) {
            return this.rootService.updateObjectProperties(object, propertyNames);
        }
    },

    /**
     * Fetch the value of a data object's property, possibly asynchronously.
     *
     * The default implementation of this method just return a fulfilled promise
     * for `null`. Subclasses should override this method to perform any fetch
     * or other operation required to get the requested data. The subclass
     * implementations should only use calls to their
     * [root service's]{@link DataService.rootService}
     * [fetchData()]{@link DataService#fetchData} to fetch data.
     */
    fetchObjectProperty: {
        value: function (object, propertyName) {
            return this.nullPromise;
        }
    },

    /***************************************************************************
     * Handling Offline
     */

    /*
     * Returns the [root service's offline status]{@link DataService#isOffline}.
     *
     * @type {boolean}
     */
    isOffline: {
        get: function () {
            return this.rootService.isOffline;
        }
    },

    /**
     * Called with all the data passed to
     * [addRawData()]{@link RawDataService#addRawData} to allow caching of that
     * data for offline use.
     *
     * The default implementation does nothing. This is appropriate for
     * subclasses that do not support offline operation or which operate the
     * same way when offline as when online.
     *
     * Other subclasses may override this method to cache data fetched when
     * online so [fetchOfflineData]{@link RawDataSource#fetchOfflineData} can
     * use that data when offline.
     *
     * @method
     * @argument {DataStream} stream   - The stream to which the fetched data is
     *                                   being added.
     * @argument {Object} records      - An array of objects whose properties'
     *                                   values hold the raw data.
     */
    writeOfflineData: {
        value: function (stream, records) {
            // Subclasses should override this to do something useful.
        }
    },

    /**
     * Subclasses that can benefit from [OfflineServices]{@link OfflineService}
     * should override this to create if necessary, cache, and return an
     * OfflineService configured for their needs.
     *
     * @type {OfflineService}
     */
    offlineService: {
        value: undefined
    },

    /***************************************************************************
     * Handling Raw Data
     */

    /**
     * Deprecated. Subclasses should override
     * [fetchData()]{@link RawDataService#fetchData} instead of this method.
     *
     * @deprecated
     * @method
     */
    fetchRawData: {
        value: function (stream) {
            this.rawDataDone(stream);
        }
    },

    /**
     * Deprecated. Subclasses should override
     * [saveDataObject()]{@link RawDataService#saveDataObject} instead of this
     * method.
     *
     * @deprecated
     * @method
     */
    saveRawData: {
        value: function (record, context) {
            // Subclasses must override this.
            return this.nullPromise;
        }
    },

    /**
     * Deprecated. Subclasses should override
     * [deleteDataObject()]{@link RawDataService#deleteDataObject} instead of
     * this method.
     *
     * @deprecated
     * @method
     */
    deleteRawData: {
        value: function (record, context) {
            // Subclasses must override this.
            return this.nullPromise;
        }
    },

    /**
     * To be called by [fetchData()]{@link RawDataService#fetchData} when raw
     * data records are received. This method should never be called directly.
     *
     * This method creates and registers the data objects that
     * will represent the raw records with repeated calls to
     * [getDataObject()]{@link DataService#getDataObject}, maps
     * the raw data to those objects with repeated calls to
     * [mapRawDataToObject()]{@link RawDataService#mapRawDataToObject},
     * and then adds those objects to the specified stream.
     *
     * Subclasses should not override this method and instead override their
     * [getDataObject()]{@link DataService#getDataObject} method, their
     * [mapRawDataToObject()]{@link RawDataService#mapRawDataToObject} method,
     * their [mapping]{@link RawDataService#mapping}'s
     * [mapRawDataToObject()]{@link RawDataMapping#mapRawDataToObject} method,
     * or several of these.
     *
     * @method
     * @argument {DataStream} stream   - The stream to which the data objects
     *                                   corresponding to the raw data should be
     *                                   added.
     * @argument {Array} records       - An array of objects whose properties'
     *                                   values hold the raw data. This array
     *                                   will be modified by this method.
     * @argument {?} context           - A value that will be passed to
     *                                   [getDataObject()]{@link DataMapping#getDataObject}
     *                                   and
     *                                   [mapRawDataToObject()]{@link DataMapping#mapRawDataToObject}
     *                                   if it is provided.
     */
    addRawData: {
        value: function (stream, records, context) {
            var offline, object, i, n;
            // Record fetched raw data for offline use if appropriate.
            offline = !this.isOffline && this._offlineRawData.get(stream);
            if (offline) {
                offline.push.apply(offline, records);
            } else if (!this.isOffline) {
                this._offlineRawData.set(stream, records.slice())
            }
            // Convert the raw data to appropriate data objects. The conversion
            // will be done in place to avoid creating any unnecessary array.
            for (i = 0, n = records ? records.length : 0; i < n; i += 1) {
                object = this.getDataObject(stream.selector.type, records[i], context);
                this.mapRawDataToObject(records[i], object, context);
                records[i] = object;
            }
            // Add the converted data to the stream.
            stream.addData(records);
        }
    },

    /**
     * Convert raw data to data objects of an appropriate type.
     *
     * Subclasses should override this method to map properties of the raw data
     * to data objects, as in the following:
     *
     *     mapRawDataToObject: {
     *         value: function (object, record) {
     *             object.firstName = record.GIVEN_NAME;
     *             object.lastName = record.FAMILY_NAME;
     *         }
     *     }
     *
     * Alternatively, subclasses can define a
     * [mapping]{@link DataService#mapping} to do this mapping.
     *
     * The default implementation of this method uses the service's mapping if
     * the service has one, and otherwise calls
     * [mapFromRawData()]{@link RawDataService#mapFromRawData], whose default
     * implementation does nothing.
     *
     * @todo Make this method overridable by type name with methods like
     * `mapRawDataToHazard()` and `mapRawDataToProduct()`.
     *
     * @method
     * @argument {Object} record - An object whose properties' values hold
     *                             the raw data.
     * @argument {Object} object - An object whose properties must be set or
     *                             modified to represent the raw data.
     * @argument {?} context     - A value that was passed in to the
     *                             [addRawData()]{@link RawDataService#addRawData}
     *                             call that invoked this method.
     */
    mapRawDataToObject: {
        value: function (record, object, context) {
            var keys, i, n;
            if (this.mapping) {
                this.mapping.mapRawDataToObject(record, object, context);
            } else if (record) {
                this.mapFromRawData(object, record, context);
            }
        }
    },

    /**
     * @todo Document.
     * @todo Make this method overridable by type name with methods like
     * `mapHazardToRawData()` and `mapProductToRawData()`.
     */
    mapObjectToRawData: {
        value: function (object, record) {
            this.mapToRawData(record, object);
        }
    },

    /**
     * To be called once for each
     * [fetchRawData()]{@link RawDataService#fetchRawData} call received to
     * indicate that all the raw data meant for the specified stream has been
     * added to that stream.
     *
     * Subclasses should not override this method.
     *
     * @method
     * @argument {DataStream} stream - The stream to which the data objects
     *                                 corresponding to the raw data have been
     *                                 added.
     */
    rawDataDone: {
        value: function (stream) {
            // Record fetched raw data for offline use if appropriate.
            var offline = this._offlineRawData.get(stream);
            if (offline) {
                this.writeOfflineData(stream, offline);
                this._offlineRawData.delete(stream);
            }
            // Notify the stream that it's got all the data it needs.
            stream.dataDone();
        }
    },

    /**
     * Records in the process of being written to streams (before
     * [rawDataDone()]{@link RawDataService#rawDataDone} is called), to be
     * stored for offline use.
     *
     * @private
     * @type {Object.<Stream, records>}
     */
    _offlineRawData: {
        get: function () {
            if (!this.__offlineRawData) {
                this.__offlineRawData = new WeakMap();
            }
            return this.__offlineRawData;
        }
    },

    __offlineRawData: {
        value: undefined
    },

    /***************************************************************************
     * Deprecated
     */

    /**
     * @todo Document deprecation in favor of
     * [mapRawDataToObject()]{@link RawDataService#mapRawDataToObject}
     */
    mapFromRawData: {
        value: function (object, record, context) {
            // Implemented by subclasses.
        }
    },

    /**
     * @todo Document deprecation in favor of
     * [mapObjectToRawData()]{@link RawDataService#mapObjectToRawData}
     */
    mapToRawData: {
        value: function (object, record) {
            // Implemented by subclasses.
        }
    }

});
<commit_msg>Make writeOfflineData() pass in a selector<commit_after>var DataService = require("logic/service/data-service").DataService,
    DataSelector = require("logic/service/data-selector").DataSelector,
    DataStream = require("logic/service/data-stream").DataStream;

/**
 * Provides data objects of certain types and manages changes to them based on
 * "raw" data obtained from or sent to one or more other services, typically
 * REST or other network services. Raw data services can therefore be considered
 * proxies for these REST or other services.
 *
 * Raw data services are usually the children of a
 * [data service]{@link DataService} that often is the application's
 * [main data service]{@link DataService.mainService}. All calls to raw data
 * services that have parent services must be routed through those parents.
 *
 * Raw data service subclasses that implement their own constructor should call
 * this class' constructor at the beginning of their constructor implementation
 * with code like the following:
 *
 *     RawDataService.call(this);
 *
 * @class
 * @extends DataService
 */
exports.RawDataService = DataService.specialize(/** @lends RawDataService.prototype */ {

    /***************************************************************************
     * Initializing
     */

    constructor: {
        value: function RawDataService() {
            DataService.call(this);
        }
    },

    /***************************************************************************
     * Basic Properties
     *
     * Private properties are defined where they are used, not here.
     */

    /**
     * If defined, used by
     * [mapRawDataToObject()]{@link RawDataService#mapRawDataToObject} and
     * [mapObjectToRawData()]{@link RawDataService#mapObjectToRawData} to map
     * between the raw data on which this service is based and the typed data
     * objects which this service provides and manages.
     *
     * @type {?DataMapping}
     */
    mapping: {
        value: undefined
    },

    /***************************************************************************
     * Tracking Data Object Changes
     */

    createdDataObjects: {
        get: function () {
            return this.rootService.createdDataObjects();
        }
    },

    changedDataObjects: {
        get: function () {
            return this.rootService.changedDataObjects();
        }
    },

    /***************************************************************************
     * Creating Data Objects
     */

    getDataObject: {
        value: function (type, record, context) {
            return this.rootService.getDataObject(type, record, context);
        }
    },

    createDataObject: {
        value: function (type) {
            return this.rootService.createDataObject(type);
        }
    },

    /***************************************************************************
     * Fetching Data Objects
     */

    /**
     * Fetch data from this service for its parent. This method should not be
     * called directly by anyone other than this service's parent. Calls to the
     * root service should be made to initiate data fetches.
     *
     * Subclasses should override this method to fetch the data objects
     * requested by:
     *
     * 1. Fetching the raw records needed to generate the data object.
     *
     * 2. Adding those records to the specified stream with calls to
     * [addRawData()]{@link RawDataService#addRawData}.
     *
     * 3. Indicating that the fetching is done with a call to
     * [rawDataDone()]{@link RawDataService#rawDataDone}.
     *
     * This method must be asynchronous and return as soon as possible even if
     * it takes a while to obtain the raw records needed to generate the
     * requested data objects. The data objects can be generated and added to
     * the specified stream at any point after this method is called with calls
     * to [addRawData()]{@link RawDataService#addRawData} and
     * [rawDataDone()]{@link RawDataService#rawDataDone}.
     *
     * When offline, [isOffline]{@link RawDataService#isOffline} can be used in
     * conjunction with an [OfflineService]{@link RawDataService#offlineService}
     * to fetch the raw records used ot generate the requested data objects.
     *
     * @method
     * @argument {DataSelector} selector - Defines what data should be fetched.
     * @argument {DataStream} stream     - A stream to which the fetched data
     *                                     can be added. Unlike for the
     *                                     [superclass]{@link DataService#fetchData}
     *                                     implementation of this method this
     *                                     stream is required for this class.
     * @returns {?DataStream} - The stream to which the fetched data objects
     * were or will be added. An `undefined` or `null` value may be returned, in
     * which case the calling parent should assume the fetched data objects were
     * or will be added to the passed in stream.
     */
    fetchData: {
        value: function (selector, stream) {
            this.fetchRawData(stream);
            return stream;
        }
    },

    /***************************************************************************
     * Saving Changed Data Objects
     */

    /**
     * Subclasses should override this method to delete a data object.
     *
     * The default implementation calls the deprecated
     * [deleteRawData()]{@link RawDataService#deleteRawData} method, which does
     * nothing by default.
     *
     * @method
     * @argument {Object} object   - The object whose data should be deleted.
     * @returns {external:Promise} - A promise fulfilled when the object has
     * been deleted.
     */
    deleteDataObject: {
        value: function (object) {
            var record = {};
            this.mapObjectToRawData(object, record);
            return this.deleteRawData(record, object);
        }
    },

    /**
     * Subclasses should override this method to save a data object.
     *
     * The default implementation calls the deprecated
     * [saveRawData()]{@link RawDataService#saveRawData} method, which does
     * nothing by default.
     *
     * @method
     * @argument {Object} object   - The object whose data should be saved.
     * @returns {external:Promise} - A promise fulfilled when all of the data in
     * the changed object has been saved.
     */
    saveDataObject: {
        value: function (object) {
            var record = {};
            this.mapObjectToRawData(object, record);
            return this.saveRawData(record, object);
        }
    },

    saveDataChanges: {
        value: function () {
            return this.rootService.saveDataChanges();
        }
    },

    /***************************************************************************
     * Managing Data Object Property Values
     */

    decacheObjectProperties: {
        value: function (object, propertyNames) {
            return this.rootService.decacheObjectProperties(object, propertyNames);
        }
    },

    getObjectProperties: {
        value: function (object, propertyNames) {
            return this.rootService.getObjectProperties(object, propertyNames);
        }
    },

    updateObjectProperties: {
        value: function (object, propertyNames) {
            return this.rootService.updateObjectProperties(object, propertyNames);
        }
    },

    /**
     * Fetch the value of a data object's property, possibly asynchronously.
     *
     * The default implementation of this method just return a fulfilled promise
     * for `null`. Subclasses should override this method to perform any fetch
     * or other operation required to get the requested data. The subclass
     * implementations should only use calls to their
     * [root service's]{@link DataService.rootService}
     * [fetchData()]{@link DataService#fetchData} to fetch data.
     */
    fetchObjectProperty: {
        value: function (object, propertyName) {
            return this.nullPromise;
        }
    },

    /***************************************************************************
     * Handling Offline
     */

    /*
     * Returns the [root service's offline status]{@link DataService#isOffline}.
     *
     * @type {boolean}
     */
    isOffline: {
        get: function () {
            return this.rootService.isOffline;
        }
    },

    /**
     * Called with all the data passed to
     * [addRawData()]{@link RawDataService#addRawData} to allow caching of that
     * data for offline use.
     *
     * The default implementation does nothing. This is appropriate for
     * subclasses that do not support offline operation or which operate the
     * same way when offline as when online.
     *
     * Other subclasses may override this method to cache data fetched when
     * online so [fetchOfflineData]{@link RawDataSource#fetchOfflineData} can
     * use that data when offline.
     *
     * @method
     * @argument {DataSelector} selector - Used to select the raw data.
     * @argument {Object} records        - An array of objects whose properties'
     *                                     values hold the raw data.
     */
    writeOfflineData: {
        value: function (selector, records) {
            // Subclasses should override this to do something useful.
        }
    },

    /**
     * Subclasses that can benefit from [OfflineServices]{@link OfflineService}
     * should override this to create if necessary, cache, and return an
     * OfflineService configured for their needs.
     *
     * @type {OfflineService}
     */
    offlineService: {
        value: undefined
    },

    /***************************************************************************
     * Handling Raw Data
     */

    /**
     * Deprecated. Subclasses should override
     * [fetchData()]{@link RawDataService#fetchData} instead of this method.
     *
     * @deprecated
     * @method
     */
    fetchRawData: {
        value: function (stream) {
            this.rawDataDone(stream);
        }
    },

    /**
     * Deprecated. Subclasses should override
     * [saveDataObject()]{@link RawDataService#saveDataObject} instead of this
     * method.
     *
     * @deprecated
     * @method
     */
    saveRawData: {
        value: function (record, context) {
            // Subclasses must override this.
            return this.nullPromise;
        }
    },

    /**
     * Deprecated. Subclasses should override
     * [deleteDataObject()]{@link RawDataService#deleteDataObject} instead of
     * this method.
     *
     * @deprecated
     * @method
     */
    deleteRawData: {
        value: function (record, context) {
            // Subclasses must override this.
            return this.nullPromise;
        }
    },

    /**
     * To be called by [fetchData()]{@link RawDataService#fetchData} when raw
     * data records are received. This method should never be called directly.
     *
     * This method creates and registers the data objects that
     * will represent the raw records with repeated calls to
     * [getDataObject()]{@link DataService#getDataObject}, maps
     * the raw data to those objects with repeated calls to
     * [mapRawDataToObject()]{@link RawDataService#mapRawDataToObject},
     * and then adds those objects to the specified stream.
     *
     * Subclasses should not override this method and instead override their
     * [getDataObject()]{@link DataService#getDataObject} method, their
     * [mapRawDataToObject()]{@link RawDataService#mapRawDataToObject} method,
     * their [mapping]{@link RawDataService#mapping}'s
     * [mapRawDataToObject()]{@link RawDataMapping#mapRawDataToObject} method,
     * or several of these.
     *
     * @method
     * @argument {DataStream} stream   - The stream to which the data objects
     *                                   corresponding to the raw data should be
     *                                   added.
     * @argument {Array} records       - An array of objects whose properties'
     *                                   values hold the raw data. This array
     *                                   will be modified by this method.
     * @argument {?} context           - A value that will be passed to
     *                                   [getDataObject()]{@link DataMapping#getDataObject}
     *                                   and
     *                                   [mapRawDataToObject()]{@link DataMapping#mapRawDataToObject}
     *                                   if it is provided.
     */
    addRawData: {
        value: function (stream, records, context) {
            var offline, object, i, n;
            // Record fetched raw data for offline use if appropriate.
            offline = !this.isOffline && this._offlineRawData.get(stream);
            if (offline) {
                offline.push.apply(offline, records);
            } else if (!this.isOffline) {
                this._offlineRawData.set(stream, records.slice())
            }
            // Convert the raw data to appropriate data objects. The conversion
            // will be done in place to avoid creating any unnecessary array.
            for (i = 0, n = records ? records.length : 0; i < n; i += 1) {
                object = this.getDataObject(stream.selector.type, records[i], context);
                this.mapRawDataToObject(records[i], object, context);
                records[i] = object;
            }
            // Add the converted data to the stream.
            stream.addData(records);
        }
    },

    /**
     * Convert raw data to data objects of an appropriate type.
     *
     * Subclasses should override this method to map properties of the raw data
     * to data objects, as in the following:
     *
     *     mapRawDataToObject: {
     *         value: function (object, record) {
     *             object.firstName = record.GIVEN_NAME;
     *             object.lastName = record.FAMILY_NAME;
     *         }
     *     }
     *
     * Alternatively, subclasses can define a
     * [mapping]{@link DataService#mapping} to do this mapping.
     *
     * The default implementation of this method uses the service's mapping if
     * the service has one, and otherwise calls
     * [mapFromRawData()]{@link RawDataService#mapFromRawData], whose default
     * implementation does nothing.
     *
     * @todo Make this method overridable by type name with methods like
     * `mapRawDataToHazard()` and `mapRawDataToProduct()`.
     *
     * @method
     * @argument {Object} record - An object whose properties' values hold
     *                             the raw data.
     * @argument {Object} object - An object whose properties must be set or
     *                             modified to represent the raw data.
     * @argument {?} context     - A value that was passed in to the
     *                             [addRawData()]{@link RawDataService#addRawData}
     *                             call that invoked this method.
     */
    mapRawDataToObject: {
        value: function (record, object, context) {
            var keys, i, n;
            if (this.mapping) {
                this.mapping.mapRawDataToObject(record, object, context);
            } else if (record) {
                this.mapFromRawData(object, record, context);
            }
        }
    },

    /**
     * @todo Document.
     * @todo Make this method overridable by type name with methods like
     * `mapHazardToRawData()` and `mapProductToRawData()`.
     */
    mapObjectToRawData: {
        value: function (object, record) {
            this.mapToRawData(record, object);
        }
    },

    /**
     * To be called once for each
     * [fetchRawData()]{@link RawDataService#fetchRawData} call received to
     * indicate that all the raw data meant for the specified stream has been
     * added to that stream.
     *
     * Subclasses should not override this method.
     *
     * @method
     * @argument {DataStream} stream - The stream to which the data objects
     *                                 corresponding to the raw data have been
     *                                 added.
     */
    rawDataDone: {
        value: function (stream) {
            // Record fetched raw data for offline use if appropriate.
            var offline = this._offlineRawData.get(stream);
            if (offline) {
                this.writeOfflineData(stream.selector, offline);
                this._offlineRawData.delete(stream);
            }
            // Notify the stream that it's got all the data it needs.
            stream.dataDone();
        }
    },

    /**
     * Records in the process of being written to streams (before
     * [rawDataDone()]{@link RawDataService#rawDataDone} is called), to be
     * stored for offline use.
     *
     * @private
     * @type {Object.<Stream, records>}
     */
    _offlineRawData: {
        get: function () {
            if (!this.__offlineRawData) {
                this.__offlineRawData = new WeakMap();
            }
            return this.__offlineRawData;
        }
    },

    __offlineRawData: {
        value: undefined
    },

    /***************************************************************************
     * Deprecated
     */

    /**
     * @todo Document deprecation in favor of
     * [mapRawDataToObject()]{@link RawDataService#mapRawDataToObject}
     */
    mapFromRawData: {
        value: function (object, record, context) {
            // Implemented by subclasses.
        }
    },

    /**
     * @todo Document deprecation in favor of
     * [mapObjectToRawData()]{@link RawDataService#mapObjectToRawData}
     */
    mapToRawData: {
        value: function (object, record) {
            // Implemented by subclasses.
        }
    }

});
<|endoftext|>


<commit_before>import createReducer from '../utils/create-reducer'

import {
  EMPTY_STACK,
  FETCH_STACK_SUCCESS,
  VIEW_WEBENTITY
} from '../actions/stacks'
import { SELECT_CORPUS } from '../actions/corpora'

// methods and args → for API calls
const initialState = {
  selected: null,
  lastRefresh: null,
  webentities: [],
  list: [
    {
      name: 'PROSPECT',
      description: 'PROSPECT description',
      method: 'store.advanced_search_webentities',
      args: [[], [['status', 'DISCOVERED']], ['-indegree', 'name'], 50, 0, false, false, true],
      condition: 'DISCOVERED'
    },
    {
      name: 'IN',
      description: 'IN description',
      method: 'store.get_webentities_by_status',
      args: ['IN', 'name', -1, 0],
      condition: 'IN'
    },
    {
      name: 'UNDECIDED',
      description: 'UNDECIDED description',
      method: 'store.get_webentities_by_status',
      args: ['UNDECIDED', 'name', -1, 0],
      condition: 'UNDECIDED'
    },
    {
      name: 'OUT',
      description: 'OUT description',
      method: 'store.get_webentities_by_status',
      args: ['OUT', 'name', -1, 0],
      condition: 'OUT'
    }
    // {
    //   name: 'TOTAG',
    //   description: 'TOTAG description',
    //   method: 'unwritten_yet',
    //   args: ['COMING...']
    // }
  ]
}

export default createReducer(initialState, {
  // reset
  [SELECT_CORPUS]: (state) => ({
    ...state,
    selected: null,
    lastRefresh: null,
    webentities: []
  }),

  [EMPTY_STACK]: (state) => ({
    ...state,
    selected: null
  }),

  [FETCH_STACK_SUCCESS]: (state, { stack, webentities }) => ({
    ...state,
    selected: stack,
    lastRefresh: Date.now(),
    webentities
  }),

  [VIEW_WEBENTITY]: (state, { webentity }) => ({
    ...state,
    webentities: state.webentities.map((w) => {
      if (w.id === webentity.id) {
        w.viewed = true
      }
      return w
    })
  })
})
<commit_msg>include list of webentites to tag in HyBro's stacklist<commit_after>import createReducer from '../utils/create-reducer'

import {
  EMPTY_STACK,
  FETCH_STACK_SUCCESS,
  VIEW_WEBENTITY
} from '../actions/stacks'
import { SELECT_CORPUS } from '../actions/corpora'

// methods and args → for API calls
const initialState = {
  selected: null,
  lastRefresh: null,
  webentities: [],
  list: [
    {
      name: 'PROSPECT',
      description: 'PROSPECT description',
      method: 'store.advanced_search_webentities',
      args: [[], [['status', 'DISCOVERED']], ['-indegree', 'name'], 50, 0, false, false, true],
      condition: 'DISCOVERED'
    },
    {
      name: 'TOTAG',
      description: 'TOTAG description',
      method: 'store.get_webentities_mistagged',
      args: ['IN', true, false, 'name', -1, 0],
      condition: 'IN'
    },
    {
      name: 'IN',
      description: 'IN description',
      method: 'store.get_webentities_by_status',
      args: ['IN', 'name', -1, 0],
      condition: 'IN'
    },
    {
      name: 'UNDECIDED',
      description: 'UNDECIDED description',
      method: 'store.get_webentities_by_status',
      args: ['UNDECIDED', 'name', -1, 0],
      condition: 'UNDECIDED'
    },
    {
      name: 'OUT',
      description: 'OUT description',
      method: 'store.get_webentities_by_status',
      args: ['OUT', 'name', -1, 0],
      condition: 'OUT'
    }
  ]
}

export default createReducer(initialState, {
  // reset
  [SELECT_CORPUS]: (state) => ({
    ...state,
    selected: null,
    lastRefresh: null,
    webentities: []
  }),

  [EMPTY_STACK]: (state) => ({
    ...state,
    selected: null
  }),

  [FETCH_STACK_SUCCESS]: (state, { stack, webentities }) => ({
    ...state,
    selected: stack,
    lastRefresh: Date.now(),
    webentities
  }),

  [VIEW_WEBENTITY]: (state, { webentity }) => ({
    ...state,
    webentities: state.webentities.map((w) => {
      if (w.id === webentity.id) {
        w.viewed = true
      }
      return w
    })
  })
})
<|endoftext|>


<commit_before>import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class MeIndexRoute extends Route {
  @service router;

  redirect() {
    this.router.replaceWith('settings');
  }
}
<commit_msg>Adjust `/me` redirections to `/settings/tokens`<commit_after>import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class MeIndexRoute extends Route {
  @service router;

  redirect() {
    // `cargo login` is showing links to https://crates.io/me to access the API tokens,
    // so we need to keep this route and redirect the user to the API tokens settings page.
    this.router.replaceWith('settings.tokens');
  }
}
<|endoftext|>


<commit_before>import { fireEvent } from 'ascesis';

const default_options = {
  root: ''
}

export default class Router {
  get root(){
    return this._root || this.options.root;
  }
  set root(value){
    this._root = value;
  }

  get prev_path(){
    return this._prev_path;
  }
  set prev_path(value){
    this._prev_path = value;
  }

  get global_path(){
    return window.location.pathname;
  }

  get path(){
    return this.root_matches ? this.global_path.replace(this.root, '') : false;
  }

  get root_matches(){
    return this.global_path.indexOf(this.root) === 0;
  }

  constructor(options = {}){

    this.options = Object.assign({}, default_options, options);
    this.listeners = [];
    this.subrouters = [];

    console.log('router init', this.options);

    window.addEventListener('popstate', () => this.resolve());
    window.addEventListener('load', () => this.resolve());
    window.addEventListener('url-changed', () => this.resolve());
  }

  add(route = /(.*)/, callback = () => {}){
    this.listeners.push({ route, callback });
  }

  notify_listeners(){
    this.listeners.forEach(({ route, callback }) => {
      let match = this.path.match(route);
      if(match){
        callback.apply(this, match);
      }
    })
  }

  trigger(){
    fireEvent('url-changed', window);
  }

  resolve(){
    if(!this.root_matches || this.prev_path === this.path){
      return false;
    }
    this.prev_path = this.path;
    this.notify_listeners();
  }

  navigate(url){
    if(!this.root_matches){
      return false;
    }
    history.pushState(null, null, this.root + url);
    this.trigger('url-changed');
  }

  destroy(){
    this.listeners = [];
    window.removeEventListener('popstate', () => this.resolve());
    window.removeEventListener('load', () => this.resolve());
    window.removeEventListener('url-changed', (e) => this.resolve());
  }

  mount(path, router){
    router.root = path;
    this.subrouters.push(router);
  }

}
<commit_msg>router fix<commit_after>import { fireEvent } from 'ascesis';

const default_options = {
  root: ''
}

export default class Router {
  get root(){
    return this._root || this.options.root;
  }
  set root(value){
    this._root = value;
  }

  get prev_path(){
    return this._prev_path;
  }
  set prev_path(value){
    this._prev_path = value;
  }

  get global_path(){
    return window.location.pathname;
  }

  get path(){
    return this.root_matches ? this.global_path.replace(this.root, '') : false;
  }

  get root_matches(){
    return this.global_path.indexOf(this.root) === 0;
  }

  constructor(options = {}){

    this.options = Object.assign({}, default_options, options);
    this.listeners = [];
    this.subrouters = [];

    console.log('router init', this.options);

    window.addEventListener('popstate', () => this.resolve());
    window.addEventListener('load', () => this.resolve());
    window.addEventListener('url-changed', () => this.resolve());
  }

  add(route = /(.*)/, callback = () => {}){
    this.listeners.push({ route, callback });
  }

  notify_listeners(){
    this.listeners.forEach(({ route, callback }) => {
      let match = this.path.match(route);
      if(match){
        callback.apply(this, match);
      }
    })
  }

  trigger(){
    fireEvent('url-changed', window);
  }

  resolve(){
    if(!this.root_matches || this.prev_path === this.path){
      return false;
    }
    //do not notify own listeners if subrouter matches root
    //should be checker here
    if(this.subrouters.length){
      for(let subrouter of this.subrouters){
        if(subrouter.root_matches && subrouter.prevent){
          return false;
        }
      }
    }
    this.prev_path = this.path;
    this.notify_listeners();
  }

  navigate(url){
    if(!this.root_matches){
      return false;
    }
    history.pushState(null, null, this.root + url);
    this.trigger('url-changed');
  }

  destroy(){
    this.listeners = [];
    window.removeEventListener('popstate', () => this.resolve());
    window.removeEventListener('load', () => this.resolve());
    window.removeEventListener('url-changed', (e) => this.resolve());
  }

  mount(path, router, prevent = true){
    router.root = this.root + path;
    router.prevent = prevent;
    this.subrouters.push(router);
  }

}
<|endoftext|>


<commit_before>"use strict"

/*
*  Communicate with receiver
**/
var MessageChannel = function(wsURL){
    var self = this;
    var wsServer = wsURL;
    self.closeSignal = false;

    console.info("-------------------------------------------> sender channel wsServer: ", wsServer);
    var ws = new WebSocket(wsServer);
    ws.onopen = function (evt) {
        console.info("-------------------------------------> sender channel onopen");
        ("onopened" in self)&&(self.onopened());
    };
    ws.onclose = function (evt) {
        if(self.closeSignal){
            console.info("-------------------------------------> sender channel onclose");
        }else{
            setTimeout(function(){
                ws = new WebSocket(wsServer);
                console.info("-------------------------------------> sender channel reconnect");
            },50);
        }
    };
    ws.onmessage = function (evt) {
        console.info("-------------------------------------> sender channel onmessage evt.data : ", evt.data);
        if(evt.data){
            try{
                var msg = JSON.parse(evt.data);
                ("onmessage" in self)&&(msg)&&self.onmessage(msg);
            }catch(e){
                console.info("----------------------------> sender channel mesage error");
            }
        }
    };
    ws.onerror = function (evt) {
        console.info("-------------------------------------> sender channel onerror");
    };

    /*
    * Send message to sender
    * @param {String}
    * @param {String} sender id default is broadcast(*:*)
    **/
    self.send = function(data){
        if(ws&& ws.readyState==1){
            ws.send(data);
        }else if(ws&& ws.readyState==0){
            setTimeout(function(){
                self.send(data);
            }, 50);
        }else{
            throw Error("Underlying websocket is not open");
        }
    };

    self.close = function(){
        self.closeSignal = true;
        ws.close();
    };

    self.on = function(type, func){
        self["on"+type] = func;
    }
};

/*
* Receiver Application state manager. This Class wrapper DIAL protocol.
**/
var SenderDaemon = function(deviceIp, appid){
    var self = this;
    var appUrl = "",
        maxInactive = -1;
    self.flingDConnected = false;
    self.token = null;
    self.useIpc = false;
    self.appHeartbeatInterval = null;
    self.appName = null;
    self.appState = null;
    self.appHref = null;
    self.additionalDatas = {};

    var wsServer = "ws://"+deviceIp+":9431/receiver/"+appid,
        ws = null,
        sender = {
            "count":0,
            "list":{}
        };

    self.simpleHttpRequest = function(method, headers, url, data, callback){
        console.info("url: ", url);
        var xhr = new XMLHttpRequest({mozSystem: true});
        xhr.open(method, url, true);
        if(headers){
            for (var i = headers.length - 1; i >= 0; i--) {
                xhr.setRequestHeader(headers[i][0], headers[i][1]);
            };
        }
        xhr.onreadystatechange = function() {
            if(xhr.readyState==4){
                if(xhr.status==200||xhr.status==201){
                    // console.info("--------------------------------->flingd resp: ", xhr.responseText);
                    if(callback){
                        callback(xhr.responseText);
                    }
                }else{
                    console.info("XmlHttpRequest Error", xhr.readyState, xhr.status);
                }
            }
        }
        xhr.onerror = function() {
            console.info('error');
        };
        xhr.timeout = 2000;
        if(data){
            xhr.send(JSON.stringify(data));
        }else{
            xhr.send();
        }
    };

    self.heartBeatLocked = false;
    /*
    * Private method, keep token alive.
    **/
    self._heartbeat = function(){
        if(self.flingDConnected&&self.useIpc&&!self.heartBeatLocked){
            self.heartBeatLocked = true;
            setTimeout(function(){
                var serverAddress = "http://"+deviceIp+":9431/apps/"+appid,
                    headers = [
                        ["Accept", "application/xml; charset=utf8"],
                        ["Authorization", self.token]
                    ];
                self.simpleHttpRequest("GET", headers, serverAddress, null, function(responseText){
                    self.heartBeatLocked = false;
                    self._heartbeat();
                });
            }, self.appHeartbeatInterval-100);
        }
    };
    /*
    * Launch receiver application
    * @param {String} receiver application url
    * @param {Integer} receiver running time. If maxInactive=-1 means forever
    * @param {Boolean} true means receive need connet to FlingService
    * @param {String} you can set launch/relaunch or join.
    **/
    self.launchApp = function(appUrl, maxInactive, useIpc, type){
        var serverAddress = "http://"+deviceIp+":9431/apps/"+appid,
            headers = [
                ["Content-Type","application/json"]
            ];
        if(!maxInactive){
            maxInactive = -1;
        }
        if(typeof(useIpc)=="undefined"){
            self.useIpc = true;
        }else{
            self.useIpc = useIpc;
        }
        if(typeof(type)=="undefined"){
            type = "launch";
        }
        var data = {
                type: type,
                app_info: {
                    url: appUrl,
                    useIpc: self.useIpc,
                    maxInactive: maxInactive
                }
            };
        self.flingDConnected = true;
        self.simpleHttpRequest("POST", headers, serverAddress, data, function(responseText){
            var resp = JSON.parse(responseText);
            self.token = resp["token"];
            self.appHeartbeatInterval = resp["interval"];
            ("onapplaunched" in self)&&(self.onapplaunched(resp));
        });
    };

    /*
    * Get Receiver Application status
    **/
    self.getState = function(){
        var serverAddress = "http://"+deviceIp+":9431/apps/"+appid,
            headers = [
                ["Accept", "application/xml; charset=utf8"],
                ["Authorization", self.token]
            ];

        self.simpleHttpRequest("GET", headers, serverAddress, null, function(responseText){
            console.info("----------------------------------responseText: ", responseText);
            var lines = responseText.split('\n');
            lines.splice(0,1);
            responseText = lines.join('');
            var parser = new DOMParser();
            var doc = parser.parseFromString(responseText,"text/xml");
            var additionalData = doc.getElementsByTagName("additionalData");
            if(additionalData.length==0){
                setTimeout(function(){
                    self.getState();
                }, 1000);
            }else{
                self.appName = doc.getElementsByTagName("name")[0].innerHTML;
                self.appState = doc.getElementsByTagName("state")[0].innerHTML;

                var link = doc.getElementsByTagName("link");
                if(link){
                    link = link[0];
                    self.appHref = link.getAttribute("href");
                }
                var items = additionalData[0].childNodes;
                if(items){
                    for(var i=0;i<items.length;i++){
                        if(items[i].tagName){
                            if(typeof(items[i].innerHTML)=="undefined"){
                                self.additionalDatas[items[i].tagName] = items[i].textContent;
                            }else{
                                self.additionalDatas[items[i].tagName] = items[i].innerHTML;
                            }
                        }
                    }
                }
            }
            ("onstatereceived" in self)&&(self.onstatereceived(self));
        });
    };

    /*
    * Disconnect with fling service
    **/
    self.disconnect = function(){
        var serverAddress = "http://"+deviceIp+":9431/apps/"+appid;
        self.simpleHttpRequest("DELETE", null, serverAddress, null, function(responseText){
            self.flingDConnected = false;
            ("onstoped" in self)&&(self.onstoped(self));
        });
    };

    /*
    * Stop the Receiver application
    **/
    self.closeApp = function(){
        if(self.appHref == null){
            self.appHref = "run";
        }
        var serverAddress = "http://"+deviceIp+":9431/apps/"+appid+"/"+self.appHref,
            headers = [
                    ["Accept", "application/xml; charset=utf8"],
                    ["Authorization", self.token]
                ];
        self.simpleHttpRequest("DELETE", headers, serverAddress, null, function(responseText){
            self.flingDConnected = false;
            ("onclosed" in self)&&(self.onstoped(self));
        });
    };

    self.systemControl = function(data){
        var serverAddress = "http://"+deviceIp+":9431/system/control";
        self.simpleHttpRequest("POST", null, serverAddress, data, function(responseText){
            if(callback){
                ("onsystemcontrol" in self)&&(self.onsystemcontrol(JSON.parse(responseText)));
            }
        });
    };

    //heigh level launch app interface
    self.openApp = function(appUrl, maxInactive, useIpc){
        self.on("applaunched", function(res){
            self.on("statereceived", function(data){
                if("additionalDatas" in data && "serverId" in data["additionalDatas"]){
                    var channel = new MessageChannel(data["additionalDatas"]["serverId"]+"/senders/"+self.token);
                    channel.on("opened",function(){
                        ("onappopened" in self)&&(self.onappopened(channel));
                    });
                }
                self._heartbeat();
            });
            self.getState();
        });
        self.launchApp(appUrl, maxInactive, useIpc);
    };

    self.on = function(type, func){
        self["on"+type] = func;
    }
};<commit_msg>Remove unused script<commit_after><|endoftext|>


<commit_before>'use strict';

var ayBaseUrl;
var moduleInformationPromise, moduleListPromise;
var moduleCodes;

module.exports = {
  getAllModules: function () {
    return moduleCodes;
  },
  generateModuleCodes: function () {
    moduleListPromise = moduleListPromise || $.getJSON(ayBaseUrl + 'moduleList.json');
    moduleListPromise.then(function () {
      moduleCodes = moduleListPromise.responseJSON;
    });
  },
  getLastModified: function (callback) {
    return $.ajax(ayBaseUrl + 'modules.json', {
      type: 'HEAD'
    }).then(function (data, textStatus, jqXHR) {
      var lastModified = jqXHR.getResponseHeader('Last-Modified');
      if (callback) {
        callback(lastModified);
      }
      return lastModified;
    });
  },
  getMod: function (code, callback) {
    return $.getJSON(ayBaseUrl + 'modules/' + code + '.json', callback);
  },
  getModIndex: function (code, callback) {
    return $.getJSON(ayBaseUrl + 'modules/' + code + '/index.json', callback);
  },
  getMods: function (callback) {
    moduleInformationPromise = moduleInformationPromise || $.getJSON(ayBaseUrl + 'moduleInformation.json');
    return moduleInformationPromise.then(callback);
  },
  getTimetable: function (semester, code, callback) {
    return $.getJSON(ayBaseUrl + semester + '/modules/' + code + '/timetable.json', callback);
  },
  getCodesAndTitles: function (callback) {
    moduleListPromise = moduleListPromise || $.getJSON(ayBaseUrl + 'moduleList.json');
    return moduleListPromise.then(callback);
  },
  setConfig: function (config) {
    ayBaseUrl = config.baseUrl + config.academicYear.replace('/', '-') + '/';
  }
};
<commit_msg>Convert jQuery thenables to bluebird promises in nusmods.js<commit_after>'use strict';

var Promise = require('bluebird');

var ayBaseUrl;
var moduleInformationPromise, moduleListPromise;
var moduleCodes;

module.exports = {
  getAllModules: function () {
    return moduleCodes;
  },
  generateModuleCodes: function () {
    moduleListPromise = moduleListPromise || Promise.resolve($.getJSON(ayBaseUrl + 'moduleList.json'));
    moduleListPromise.then(function (data) {
      moduleCodes = data;
    });
  },
  getLastModified: function (callback) {
    return Promise.resolve($.ajax(ayBaseUrl + 'modules.json', {
      type: 'HEAD'
    }).then(function (data, textStatus, jqXHR) {
      var lastModified = jqXHR.getResponseHeader('Last-Modified');
      if (callback) {
        callback(lastModified);
      }
      return lastModified;
    }));
  },
  getMod: function (code, callback) {
    return Promise.resolve($.getJSON(ayBaseUrl + 'modules/' + code + '.json', callback));
  },
  getModIndex: function (code, callback) {
    return Promise.resolve($.getJSON(ayBaseUrl + 'modules/' + code + '/index.json', callback));
  },
  getMods: function (callback) {
    moduleInformationPromise = moduleInformationPromise || Promise.resolve($.getJSON(ayBaseUrl + 'moduleInformation.json'));
    return moduleInformationPromise.then(callback);
  },
  getTimetable: function (semester, code, callback) {
    return Promise.resolve($.getJSON(ayBaseUrl + semester + '/modules/' + code + '/timetable.json', callback));
  },
  getCodesAndTitles: function (callback) {
    moduleListPromise = moduleListPromise || Promise.resolve($.getJSON(ayBaseUrl + 'moduleList.json'));
    return moduleListPromise.then(callback);
  },
  setConfig: function (config) {
    ayBaseUrl = config.baseUrl + config.academicYear.replace('/', '-') + '/';
  }
};
<|endoftext|>


<commit_before>'use strict';

console.log('\'Allo \'Allo! Option');
<commit_msg>Moved the JS from the old extensions options.html script tags into its own file<commit_after>'use strict';

var postcodeTextbox;
var saveButton;

init();

function init() {
  postcodeTextbox = document.getElementById("postcode");
  saveButton = document.getElementById("save-button");

  postcodeTextbox.value = localStorage.postcode || "";
  markClean();
}

function save() {
  localStorage.postcode = postcodeTextbox.value;
  markClean();
}

function markDirty() {
  saveButton.disabled = false;
}

function markClean() {
  saveButton.disabled = true;
}
<|endoftext|>


<commit_before>const octonode = require('octonode');
const $ = require('../util');
const config = require('./config');
const isDev = require('electron-is-dev');

const token = config.get('ghToken');
let apiUrl = config.get('baseUrl') + 'api/v3';
let hostname = isDev ? 'api.github.com' : apiUrl.replace('https://', '');
let client = null;

const DEBUG = false;

function github (api, { id, repo, participating }) {
	const isPreviewApi = (api === 'projects');

	init(isPreviewApi);
	return new Promise(resolve => {
		if (!client) return resolve(null);
		const cb = (err, resp) => {
			if (err && DEBUG) console.error(api.toUpperCase(), err);
			resolve(err ? null : resp);
		};

		if (api === 'notifications') return client.me().notifications({ participating }, cb);
		if (api === 'user') return client.user(id).info(cb);
		if (api === 'pr') return client.pr(repo, id).info(cb);
		if (api === 'projects') return client.repo(repo).projects(cb);
		if (api === 'issue-comments') return client.issue(repo, id).comments(cb);
	});
}

function getUserByIdFromPublicApi (id) {
	return new Promise (resolve => {
		$.get(`${apiUrl}/users/${id}`).then(resolve).catch(() => resolve());
	});
}

function getUserById (id) {
	const fn = token ? github('user', { id }) : getUserByIdFromPublicApi(id);
	return fn.then(res => res ? { id, name: res.name } : { id });
}

function getNotificationsCount (participating = true) {
	return github('notifications', { participating }).then(res => res.length || 0);
}

function getPR (repo, id) {
	return github('pr', { repo, id });
}

function getProjects () {
	return github('projects', { repo: config.get('repoToSearch') });
}

function getCIjobUrl (statuses) {
	if (!statuses || !statuses.length) return '';
	const ci_url = config.get('ciUrl');
	if (ci_url) statuses = statuses.filter(s => s.target_url.indexOf(ci_url) > -1);
	const url = statuses && statuses.length ? statuses[0].target_url : '';
	return url;

}

function getBuildUrl (pr) {
	return getPR(pr.repo, pr.id).then(resp => resp && $.get(resp.statuses_url)).then(getCIjobUrl);
}

function getLastIssueComment (issue, comments) {
	if (!comments || !comments.length) return issue;
	const lastComment = comments.pop();
	issue.lastCommentDate = +new Date(lastComment.updated_at);

	if (issue.updated_at && issue.lastCommentDate > issue.updated_at) issue.unread = true;
	return issue;
}

function getIssueLastUpdateDate (issue) {
	return github('issue-comments', { repo: issue.repo, id: issue.id })
		.then(comments => getLastIssueComment(issue, comments));
}

function checkIssuesForUpdates (issues) {
	issues = issues
		.filter(i => i.type in { pr: 1, issue: 1 })
		.filter(i => !i.unread)
		.map(getIssueLastUpdateDate);

	return Promise.all(issues).then(res => res.filter(i => i.unread));
}

function init (isPreview) {
	if (!client) {
		if (!token) return;
		client = octonode.client(token, { hostname });
	}
	client.requestDefaults.strictSSL = false;

	if (isPreview) client.requestDefaults.headers.Accept = 'application/vnd.github.inertia-preview+json';
	else delete client.requestDefaults.headers.Accept;
}

module.exports = {
	getNotificationsCount,
	getBuildUrl,
	getPR,
	getProjects,
	getUserById,
	checkIssuesForUpdates,
};
<commit_msg>twksn<commit_after>const octonode = require('octonode');
const $ = require('../util');
const config = require('./config');
const isDev = require('electron-is-dev');

const token = config.get('ghToken');
let apiUrl = config.get('baseUrl') + 'api/v3';
let hostname = isDev ? 'api.github.com' : apiUrl.replace('https://', '');
let client = null;

const DEBUG = false;

function github (api, { id, repo, participating }) {
	const isPreviewApi = (api === 'projects');

	init(isPreviewApi);
	return new Promise(resolve => {
		if (!client) return resolve(null);
		const cb = (err, resp) => {
			if (err && DEBUG) console.error(api.toUpperCase(), err);
			resolve(err ? null : resp);
		};

		if (api === 'notifications') return client.me().notifications({ participating }, cb);
		if (api === 'user') return client.user(id).info(cb);
		if (api === 'pr') return client.pr(repo, id).info(cb);
		if (api === 'projects') return client.repo(repo).projects(cb);
		if (api === 'issue-comments') return client.issue(repo, id).comments(cb);
	});
}

function getUserByIdFromPublicApi (id) {
	return new Promise (resolve => {
		$.get(`${apiUrl}/users/${id}`).then(resolve).catch(() => resolve());
	});
}

function getUserById (id) {
	const fn = token ? github('user', { id }) : getUserByIdFromPublicApi(id);
	return fn.then(res => res ? { id, name: res.name } : { id });
}

function getNotificationsCount (participating = true) {
	return github('notifications', { participating }).then(res => res.length || 0);
}

function getPR (repo, id) {
	return github('pr', { repo, id });
}

function getProjects () {
	return github('projects', { repo: config.get('repoToSearch') });
}

function getCIjobUrl (statuses) {
	if (!statuses || !statuses.length) return '';
	const ci_url = config.get('ciUrl');
	if (ci_url) statuses = statuses.filter(s => s.target_url.indexOf(ci_url) > -1);
	const url = statuses && statuses.length ? statuses[0].target_url : '';
	return url;

}

function getBuildUrl (pr) {
	return getPR(pr.repo, pr.id).then(resp => resp && $.get(resp.statuses_url)).then(getCIjobUrl);
}

function checkIfLastCommentIsUnread (issue, comments) {
	if (!comments || !comments.length) return issue;
	const lastComment = comments.pop();
	issue.lastCommentDate = +new Date(lastComment.updated_at);

	if (issue.updated_at && issue.lastCommentDate > issue.updated_at) issue.unread = true;
	return issue;
}

function checkForUnreadComments (issue) {
	return github('issue-comments', { repo: issue.repo, id: issue.id })
		.then(comments => checkIfLastCommentIsUnread(issue, comments));
}

function checkIssuesForUpdates (issues) {
	issues = issues
		.filter(i => i.type in { pr: 1, issue: 1 })
		.filter(i => !i.unread)								// ignore when already marked as unread
		.map(checkForUnreadComments);

	return Promise.all(issues).then(res => res.filter(i => i.unread));
}

function init (isPreview) {
	if (!client) {
		if (!token) return;
		client = octonode.client(token, { hostname });
	}
	client.requestDefaults.strictSSL = false;

	if (isPreview) client.requestDefaults.headers.Accept = 'application/vnd.github.inertia-preview+json';
	else delete client.requestDefaults.headers.Accept;
}

module.exports = {
	getNotificationsCount,
	getBuildUrl,
	getPR,
	getProjects,
	getUserById,
	checkIssuesForUpdates,
};
<|endoftext|>


<commit_before>import Ember from "ember";
import config from "../config/environment";

export default Ember.Service.extend({
  session: Ember.inject.service(),

  error: function(reason) {
    if (reason.status === 0) {
      return;
    }
    console.info(reason);
    if (config.environment === "production" || config.staging) {
      var userName = this.get("session.currentUser.fullName");
      var userId = this.get("session.currentUser.id");
      var error = reason instanceof Error || typeof reason != "object" ?
          reason : JSON.stringify(reason);

      var airbrake = new airbrakeJs.Client();
      airbrake.setHost(config.APP.AIRBRAKE_HOST);
      airbrake.setProject(config.APP.AIRBRAKE_PROJECT_ID, config.APP.AIRBRAKE_PROJECT_KEY);
      airbrake.setEnvironmentName(config.staging ? "staging" : config.environment);

      airbrake.push({
        error: error,
        context: { userId: userId, userName: userName }
      });
    }
  }
});
<commit_msg>Update errbit calls to use non-deprecated methods, and add app version<commit_after>import Ember from "ember";
import config from "../config/environment";

export default Ember.Service.extend({
  session: Ember.inject.service(),

  error: function(reason) {
    if (reason.status === 0) {
      return;
    }
    console.info(reason);
    if (config.environment === "production" || config.staging) {
      var userName = this.get("session.currentUser.fullName");
      var userId = this.get("session.currentUser.id");
      var error = reason instanceof Error || typeof reason != "object" ?
          reason : JSON.stringify(reason);
      var environment = config.staging ? "staging" : config.environment;
      var version = `${config.APP.SHA} (shared ${config.APP.SHARED_SHA})`;

      var airbrake = new airbrakeJs.Client({
        projectId: config.APP.AIRBRAKE_PROJECT_ID,
        projectKey: config.APP.AIRBRAKE_PROJECT_KEY
      });
      airbrake.setHost(config.APP.AIRBRAKE_HOST);
      airbrake.notify({ error, context: { userId, userName, environment, version } });
    }
  }
});
<|endoftext|>