<commit_before>/**
 * @module ol/Geolocation
 */
import GeolocationProperty from './GeolocationProperty.js';
import BaseObject, {getChangeEventType} from './Object.js';
import {listen} from './events.js';
import EventType from './events/EventType.js';
import {circular as circularPolygon} from './geom/Polygon.js';
import {GEOLOCATION} from './has.js';
import {toRadians} from './math.js';
import {get as getProjection, getTransformFromProjections, identityTransform} from './proj.js';

/**
 * @typedef {Object} Options
 * @property {boolean} [tracking=false] Start Tracking right after
 * instantiation.
 * @property {GeolocationPositionOptions} [trackingOptions] Tracking options.
 * See {@link http://www.w3.org/TR/geolocation-API/#position_options_interface}.
 * @property {module:ol/proj~ProjectionLike} [projection] The projection the position
 * is reported in.
 */

/**
 * @classdesc
 * Helper class for providing HTML5 Geolocation capabilities.
 * The [Geolocation API](http://www.w3.org/TR/geolocation-API/)
 * is used to locate a user's position.
 *
 * To get notified of position changes, register a listener for the generic
 * `change` event on your instance of {@link module:ol/Geolocation~Geolocation}.
 *
 * Example:
 *
 *     var geolocation = new Geolocation({
 *       // take the projection to use from the map's view
 *       projection: view.getProjection()
 *     });
 *     // listen to changes in position
 *     geolocation.on('change', function(evt) {
 *       window.console.log(geolocation.getPosition());
 *     });
 *
 * @fires error
 * @api
 */
class Geolocation extends BaseObject {

  /**
   * @param {module:ol/Geolocation~Options=} opt_options Options.
   */
  constructor(opt_options) {

    BaseObject.call(this);

    const options = opt_options || {};

    /**
     * The unprojected (EPSG:4326) device position.
     * @private
     * @type {module:ol/coordinate~Coordinate}
     */
    this.position_ = null;

    /**
     * @private
     * @type {module:ol/proj~TransformFunction}
     */
    this.transform_ = identityTransform;

    /**
     * @private
     * @type {number|undefined}
     */
    this.watchId_ = undefined;

    listen(
      this, getChangeEventType(GeolocationProperty.PROJECTION),
      this.handleProjectionChanged_, this);
    listen(
      this, getChangeEventType(GeolocationProperty.TRACKING),
      this.handleTrackingChanged_, this);

    if (options.projection !== undefined) {
      this.setProjection(options.projection);
    }
    if (options.trackingOptions !== undefined) {
      this.setTrackingOptions(options.trackingOptions);
    }

    this.setTracking(options.tracking !== undefined ? options.tracking : false);

  }

  /**
   * @inheritDoc
   */
  disposeInternal() {
    this.setTracking(false);
    super.disposeInternal();
  }

  /**
   * @private
   */
  handleProjectionChanged_() {
    const projection = this.getProjection();
    if (projection) {
      this.transform_ = getTransformFromProjections(
        getProjection('EPSG:4326'), projection);
      if (this.position_) {
        this.set(GeolocationProperty.POSITION, this.transform_(this.position_));
      }
    }
  }

  /**
   * @private
   */
  handleTrackingChanged_() {
    if (GEOLOCATION) {
      const tracking = this.getTracking();
      if (tracking && this.watchId_ === undefined) {
        this.watchId_ = navigator.geolocation.watchPosition(
          this.positionChange_.bind(this),
          this.positionError_.bind(this),
          this.getTrackingOptions());
      } else if (!tracking && this.watchId_ !== undefined) {
        navigator.geolocation.clearWatch(this.watchId_);
        this.watchId_ = undefined;
      }
    }
  }

  /**
   * @private
   * @param {GeolocationPosition} position position event.
   */
  positionChange_(position) {
    const coords = position.coords;
    this.set(GeolocationProperty.ACCURACY, coords.accuracy);
    this.set(GeolocationProperty.ALTITUDE,
      coords.altitude === null ? undefined : coords.altitude);
    this.set(GeolocationProperty.ALTITUDE_ACCURACY,
      coords.altitudeAccuracy === null ?
        undefined : coords.altitudeAccuracy);
    this.set(GeolocationProperty.HEADING, coords.heading === null ?
      undefined : toRadians(coords.heading));
    if (!this.position_) {
      this.position_ = [coords.longitude, coords.latitude];
    } else {
      this.position_[0] = coords.longitude;
      this.position_[1] = coords.latitude;
    }
    const projectedPosition = this.transform_(this.position_);
    this.set(GeolocationProperty.POSITION, projectedPosition);
    this.set(GeolocationProperty.SPEED,
      coords.speed === null ? undefined : coords.speed);
    const geometry = circularPolygon(this.position_, coords.accuracy);
    geometry.applyTransform(this.transform_);
    this.set(GeolocationProperty.ACCURACY_GEOMETRY, geometry);
    this.changed();
  }

  /**
   * Triggered when the Geolocation returns an error.
   * @event error
   * @api
   */

  /**
   * @private
   * @param {GeolocationPositionError} error error object.
   */
  positionError_(error) {
    error.type = EventType.ERROR;
    this.setTracking(false);
    this.dispatchEvent(/** @type {{type: string, target: undefined}} */ (error));
  }

  /**
   * Get the accuracy of the position in meters.
   * @return {number|undefined} The accuracy of the position measurement in
   *     meters.
   * @observable
   * @api
   */
  getAccuracy() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.ACCURACY));
  }

  /**
   * Get a geometry of the position accuracy.
   * @return {?module:ol/geom/Polygon} A geometry of the position accuracy.
   * @observable
   * @api
   */
  getAccuracyGeometry() {
    return (
      /** @type {?module:ol/geom/Polygon} */ (this.get(GeolocationProperty.ACCURACY_GEOMETRY) || null)
    );
  }

  /**
   * Get the altitude associated with the position.
   * @return {number|undefined} The altitude of the position in meters above mean
   *     sea level.
   * @observable
   * @api
   */
  getAltitude() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE));
  }

  /**
   * Get the altitude accuracy of the position.
   * @return {number|undefined} The accuracy of the altitude measurement in
   *     meters.
   * @observable
   * @api
   */
  getAltitudeAccuracy() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE_ACCURACY));
  }

  /**
   * Get the heading as radians clockwise from North.
   * Note: depending on the browser, the heading is only defined if the `enableHighAccuracy`
   * is set to `true` in the tracking options.
   * @return {number|undefined} The heading of the device in radians from north.
   * @observable
   * @api
   */
  getHeading() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.HEADING));
  }

  /**
   * Get the position of the device.
   * @return {module:ol/coordinate~Coordinate|undefined} The current position of the device reported
   *     in the current projection.
   * @observable
   * @api
   */
  getPosition() {
    return (
      /** @type {module:ol/coordinate~Coordinate|undefined} */ (this.get(GeolocationProperty.POSITION))
    );
  }

  /**
   * Get the projection associated with the position.
   * @return {module:ol/proj/Projection|undefined} The projection the position is
   *     reported in.
   * @observable
   * @api
   */
  getProjection() {
    return (
      /** @type {module:ol/proj/Projection|undefined} */ (this.get(GeolocationProperty.PROJECTION))
    );
  }

  /**
   * Get the speed in meters per second.
   * @return {number|undefined} The instantaneous speed of the device in meters
   *     per second.
   * @observable
   * @api
   */
  getSpeed() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.SPEED));
  }

  /**
   * Determine if the device location is being tracked.
   * @return {boolean} The device location is being tracked.
   * @observable
   * @api
   */
  getTracking() {
    return /** @type {boolean} */ (this.get(GeolocationProperty.TRACKING));
  }

  /**
   * Get the tracking options.
   * @see http://www.w3.org/TR/geolocation-API/#position-options
   * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by
   *     the [HTML5 Geolocation spec
   *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
   * @observable
   * @api
   */
  getTrackingOptions() {
    return /** @type {GeolocationPositionOptions|undefined} */ (this.get(GeolocationProperty.TRACKING_OPTIONS));
  }

  /**
   * Set the projection to use for transforming the coordinates.
   * @param {module:ol/proj~ProjectionLike} projection The projection the position is
   *     reported in.
   * @observable
   * @api
   */
  setProjection(projection) {
    this.set(GeolocationProperty.PROJECTION, getProjection(projection));
  }

  /**
   * Enable or disable tracking.
   * @param {boolean} tracking Enable tracking.
   * @observable
   * @api
   */
  setTracking(tracking) {
    this.set(GeolocationProperty.TRACKING, tracking);
  }

  /**
   * Set the tracking options.
   * @see http://www.w3.org/TR/geolocation-API/#position-options
   * @param {GeolocationPositionOptions} options PositionOptions as defined by the
   *     [HTML5 Geolocation spec
   *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
   * @observable
   * @api
   */
  setTrackingOptions(options) {
    this.set(GeolocationProperty.TRACKING_OPTIONS, options);
  }
}

export default Geolocation;
<commit_msg>Call super instead of BaseObject<commit_after>/**
 * @module ol/Geolocation
 */
import GeolocationProperty from './GeolocationProperty.js';
import BaseObject, {getChangeEventType} from './Object.js';
import {listen} from './events.js';
import EventType from './events/EventType.js';
import {circular as circularPolygon} from './geom/Polygon.js';
import {GEOLOCATION} from './has.js';
import {toRadians} from './math.js';
import {get as getProjection, getTransformFromProjections, identityTransform} from './proj.js';

/**
 * @typedef {Object} Options
 * @property {boolean} [tracking=false] Start Tracking right after
 * instantiation.
 * @property {GeolocationPositionOptions} [trackingOptions] Tracking options.
 * See {@link http://www.w3.org/TR/geolocation-API/#position_options_interface}.
 * @property {module:ol/proj~ProjectionLike} [projection] The projection the position
 * is reported in.
 */

/**
 * @classdesc
 * Helper class for providing HTML5 Geolocation capabilities.
 * The [Geolocation API](http://www.w3.org/TR/geolocation-API/)
 * is used to locate a user's position.
 *
 * To get notified of position changes, register a listener for the generic
 * `change` event on your instance of {@link module:ol/Geolocation~Geolocation}.
 *
 * Example:
 *
 *     var geolocation = new Geolocation({
 *       // take the projection to use from the map's view
 *       projection: view.getProjection()
 *     });
 *     // listen to changes in position
 *     geolocation.on('change', function(evt) {
 *       window.console.log(geolocation.getPosition());
 *     });
 *
 * @fires error
 * @api
 */
class Geolocation extends BaseObject {

  /**
   * @param {module:ol/Geolocation~Options=} opt_options Options.
   */
  constructor(opt_options) {

    super();

    const options = opt_options || {};

    /**
     * The unprojected (EPSG:4326) device position.
     * @private
     * @type {module:ol/coordinate~Coordinate}
     */
    this.position_ = null;

    /**
     * @private
     * @type {module:ol/proj~TransformFunction}
     */
    this.transform_ = identityTransform;

    /**
     * @private
     * @type {number|undefined}
     */
    this.watchId_ = undefined;

    listen(
      this, getChangeEventType(GeolocationProperty.PROJECTION),
      this.handleProjectionChanged_, this);
    listen(
      this, getChangeEventType(GeolocationProperty.TRACKING),
      this.handleTrackingChanged_, this);

    if (options.projection !== undefined) {
      this.setProjection(options.projection);
    }
    if (options.trackingOptions !== undefined) {
      this.setTrackingOptions(options.trackingOptions);
    }

    this.setTracking(options.tracking !== undefined ? options.tracking : false);

  }

  /**
   * @inheritDoc
   */
  disposeInternal() {
    this.setTracking(false);
    super.disposeInternal();
  }

  /**
   * @private
   */
  handleProjectionChanged_() {
    const projection = this.getProjection();
    if (projection) {
      this.transform_ = getTransformFromProjections(
        getProjection('EPSG:4326'), projection);
      if (this.position_) {
        this.set(GeolocationProperty.POSITION, this.transform_(this.position_));
      }
    }
  }

  /**
   * @private
   */
  handleTrackingChanged_() {
    if (GEOLOCATION) {
      const tracking = this.getTracking();
      if (tracking && this.watchId_ === undefined) {
        this.watchId_ = navigator.geolocation.watchPosition(
          this.positionChange_.bind(this),
          this.positionError_.bind(this),
          this.getTrackingOptions());
      } else if (!tracking && this.watchId_ !== undefined) {
        navigator.geolocation.clearWatch(this.watchId_);
        this.watchId_ = undefined;
      }
    }
  }

  /**
   * @private
   * @param {GeolocationPosition} position position event.
   */
  positionChange_(position) {
    const coords = position.coords;
    this.set(GeolocationProperty.ACCURACY, coords.accuracy);
    this.set(GeolocationProperty.ALTITUDE,
      coords.altitude === null ? undefined : coords.altitude);
    this.set(GeolocationProperty.ALTITUDE_ACCURACY,
      coords.altitudeAccuracy === null ?
        undefined : coords.altitudeAccuracy);
    this.set(GeolocationProperty.HEADING, coords.heading === null ?
      undefined : toRadians(coords.heading));
    if (!this.position_) {
      this.position_ = [coords.longitude, coords.latitude];
    } else {
      this.position_[0] = coords.longitude;
      this.position_[1] = coords.latitude;
    }
    const projectedPosition = this.transform_(this.position_);
    this.set(GeolocationProperty.POSITION, projectedPosition);
    this.set(GeolocationProperty.SPEED,
      coords.speed === null ? undefined : coords.speed);
    const geometry = circularPolygon(this.position_, coords.accuracy);
    geometry.applyTransform(this.transform_);
    this.set(GeolocationProperty.ACCURACY_GEOMETRY, geometry);
    this.changed();
  }

  /**
   * Triggered when the Geolocation returns an error.
   * @event error
   * @api
   */

  /**
   * @private
   * @param {GeolocationPositionError} error error object.
   */
  positionError_(error) {
    error.type = EventType.ERROR;
    this.setTracking(false);
    this.dispatchEvent(/** @type {{type: string, target: undefined}} */ (error));
  }

  /**
   * Get the accuracy of the position in meters.
   * @return {number|undefined} The accuracy of the position measurement in
   *     meters.
   * @observable
   * @api
   */
  getAccuracy() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.ACCURACY));
  }

  /**
   * Get a geometry of the position accuracy.
   * @return {?module:ol/geom/Polygon} A geometry of the position accuracy.
   * @observable
   * @api
   */
  getAccuracyGeometry() {
    return (
      /** @type {?module:ol/geom/Polygon} */ (this.get(GeolocationProperty.ACCURACY_GEOMETRY) || null)
    );
  }

  /**
   * Get the altitude associated with the position.
   * @return {number|undefined} The altitude of the position in meters above mean
   *     sea level.
   * @observable
   * @api
   */
  getAltitude() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE));
  }

  /**
   * Get the altitude accuracy of the position.
   * @return {number|undefined} The accuracy of the altitude measurement in
   *     meters.
   * @observable
   * @api
   */
  getAltitudeAccuracy() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE_ACCURACY));
  }

  /**
   * Get the heading as radians clockwise from North.
   * Note: depending on the browser, the heading is only defined if the `enableHighAccuracy`
   * is set to `true` in the tracking options.
   * @return {number|undefined} The heading of the device in radians from north.
   * @observable
   * @api
   */
  getHeading() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.HEADING));
  }

  /**
   * Get the position of the device.
   * @return {module:ol/coordinate~Coordinate|undefined} The current position of the device reported
   *     in the current projection.
   * @observable
   * @api
   */
  getPosition() {
    return (
      /** @type {module:ol/coordinate~Coordinate|undefined} */ (this.get(GeolocationProperty.POSITION))
    );
  }

  /**
   * Get the projection associated with the position.
   * @return {module:ol/proj/Projection|undefined} The projection the position is
   *     reported in.
   * @observable
   * @api
   */
  getProjection() {
    return (
      /** @type {module:ol/proj/Projection|undefined} */ (this.get(GeolocationProperty.PROJECTION))
    );
  }

  /**
   * Get the speed in meters per second.
   * @return {number|undefined} The instantaneous speed of the device in meters
   *     per second.
   * @observable
   * @api
   */
  getSpeed() {
    return /** @type {number|undefined} */ (this.get(GeolocationProperty.SPEED));
  }

  /**
   * Determine if the device location is being tracked.
   * @return {boolean} The device location is being tracked.
   * @observable
   * @api
   */
  getTracking() {
    return /** @type {boolean} */ (this.get(GeolocationProperty.TRACKING));
  }

  /**
   * Get the tracking options.
   * @see http://www.w3.org/TR/geolocation-API/#position-options
   * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by
   *     the [HTML5 Geolocation spec
   *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
   * @observable
   * @api
   */
  getTrackingOptions() {
    return /** @type {GeolocationPositionOptions|undefined} */ (this.get(GeolocationProperty.TRACKING_OPTIONS));
  }

  /**
   * Set the projection to use for transforming the coordinates.
   * @param {module:ol/proj~ProjectionLike} projection The projection the position is
   *     reported in.
   * @observable
   * @api
   */
  setProjection(projection) {
    this.set(GeolocationProperty.PROJECTION, getProjection(projection));
  }

  /**
   * Enable or disable tracking.
   * @param {boolean} tracking Enable tracking.
   * @observable
   * @api
   */
  setTracking(tracking) {
    this.set(GeolocationProperty.TRACKING, tracking);
  }

  /**
   * Set the tracking options.
   * @see http://www.w3.org/TR/geolocation-API/#position-options
   * @param {GeolocationPositionOptions} options PositionOptions as defined by the
   *     [HTML5 Geolocation spec
   *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
   * @observable
   * @api
   */
  setTrackingOptions(options) {
    this.set(GeolocationProperty.TRACKING_OPTIONS, options);
  }
}

export default Geolocation;
<|endoftext|>


<commit_before>// var
//   head = document.querySelector('head'),
//   array = document.createElement('script'),
//   number = document.createElement('script'),
//   math = document.createElement('script');

// array.src = 'https://rawgit.com/home-labs/do-rails/master/lib/assets/javascripts/do/array.js';
// number.src = 'https://rawgit.com/home-labs/do-calc-rails/master/lib/assets/javascripts/do_calc/number.js',
// math.src = 'https://rawgit.com/home-labs/do-calc-rails/master/lib/assets/javascripts/do_calc/math.js';

// head.appendChild(array);
// head.appendChild(number);
// head.appendChild(math);

// Para futuras implementações, como retorno de fatores primos de determinado valor, podemos usar um algorítmo determinístico como esses dois abaixo
// É interessante calcular somente os fatores primos que caberiam para determinado número, ao invés de testar com todo número natural até chegar a ele, e salvá-los em i como um array, e no if calcular o retorno 0 somente para estes. Devendo o próprio número ser retornado caso não haja quantidade de múltiplos maior que 1, pois 1 e ele mesmo não deverão entrar no vetor para ser calculado.
// Mas como calcular esse números primos? No braço?

// http://pt.wikipedia.org/wiki/Crivo_de_Erat%C3%B3stenes
// http://pt.wikipedia.org/wiki/Teste_de_primalidade_AKS

Number.prototype.primeFactors = function() {

}

Number.prototype.isPrime = function() {
  var
    count = 2,
    i = 2,
    n = this;

  n = parseInt(n);
  if(n < 0) { n *= -1; }
  if(n === 1) { return false; }
  if(n === 2) { return true; }

  while(true) {
    if(i === n || count > 2) { break; }
    if(n%i === 0) { count++; }
    i++;
  }

  if(count === 2) {
    return true;
  } else {
    return false;
  }
}

Number.prototype.rationalize = function() {
  var
    _d = parseFloat(this).toString().split('.'),
    decimal = _d[1],
    numerator = parseInt(_d[0]+_d[1]),
    denominator = '1',
    gcd = 1,
    i = 1
  ;

  while(true) {
    denominator += '0';
    if(i === decimal.toString().length) { break; }
    i++;
  }

  denominator = parseInt(denominator);
  gcd = Math.gcd(numerator, denominator);

  return (numerator/gcd).toString() + '/' + (denominator/gcd).toString();

}

Number.prototype.multiples = function() {
  var
    n = parseInt(this),
    i = 1,
    _multiples = []
  ;

  if(n === 0) { return ["∞"]; }

  if(n < 0) { n *= -1; }

  while(true) {
    if(n%i === 0) { _multiples.push(i); }
    if(i === n) { break; }
    i++;
  }

  return _multiples;
}

Number.firstMultiple = function(n) {
  return n.firstMultiple();
}

Number.prototype.firstMultiple = function() {
  var
    i = 1,
    count = 1,
    n = this,
    m = n
  ;

  if (n < 0) { n *= -1; }

  while(i <= n && count < 3) {
    if(n%i === 0) {
      count++;
      m = i;
    }
    i++;

  }

  return parseFloat(m);
}

Array.prototype.firstMultiple = function() {
  var
    _arr = this,
    _factors = []
  ;

  _arr.map(function(item) {
    if(item > 1) { _factors.push(item.firstMultiple()); }
  });

  return (_factors.sort())[0];
}
<commit_msg>ajusta identação<commit_after>// var
//   head = document.querySelector('head'),
//   array = document.createElement('script'),
//   number = document.createElement('script'),
//   math = document.createElement('script');

// array.src = 'https://rawgit.com/home-labs/do-rails/master/lib/assets/javascripts/do/array.js';
// number.src = 'https://rawgit.com/home-labs/do-calc-rails/master/lib/assets/javascripts/do_calc/number.js',
// math.src = 'https://rawgit.com/home-labs/do-calc-rails/master/lib/assets/javascripts/do_calc/math.js';

// head.appendChild(array);
// head.appendChild(number);
// head.appendChild(math);

// Para futuras implementações, como retorno de fatores primos de determinado valor, podemos usar um algorítmo determinístico como esses dois abaixo
// É interessante calcular somente os fatores primos que caberiam para determinado número, ao invés de testar com todo número natural até chegar a ele, e salvá-los em i como um array, e no if calcular o retorno 0 somente para estes. Devendo o próprio número ser retornado caso não haja quantidade de múltiplos maior que 1, pois 1 e ele mesmo não deverão entrar no vetor para ser calculado.
// Mas como calcular esse números primos? No braço?

// http://pt.wikipedia.org/wiki/Crivo_de_Erat%C3%B3stenes
// http://pt.wikipedia.org/wiki/Teste_de_primalidade_AKS

// Number.prototype.primeFactors = function() {
//     var
//         _factors = [],
//         // _allFactors = [],
//         n = parseInt(this),
//         i = 0,
//         factor = 2
//     ;

//     if(n < 0) { n *= -1; }

//     // while(true) {
//     //     if(i === n) { break; }
//     //     if(i.isPrime()) {
//     //         if(n%i === 0) {
//     //             _factors.push(i);
//     //         }
//     //     }
//     //     i++;
//     // }

//     i = 0;

//     while(true) {
//         dividend = dividend/_factors[i];
//         if(dividend%_factors[i] === 0) {

//         } else {
//             i++;
//         }
//         if(dividend === 1) { break; }
//     }

//     return _allFactors;
// }

Number.prototype.isPrime = function() {
    var
        count = 2,
        i = 2,
        n = this
    ;

    n = parseInt(n);
    if(n < 0) { n *= -1; }
    if(n === 1) { return false; }
    if(n === 2) { return true; }

    while(true) {
        if(i === n || count > 2) { break; }
        if(n%i === 0) { count++; }
        i++;
    }

    if(count === 2) {
        return true;
    } else {
        return false;
    }
}

Number.prototype.rationalize = function() {
    var
        _d = parseFloat(this).toString().split('.'),
        decimal = _d[1],
        numerator = parseInt(_d[0]+_d[1]),
        denominator = '1',
        gcd = 1,
        i = 1
    ;

    while(true) {
        denominator += '0';
        if(i === decimal.toString().length) { break; }
        i++;
    }

    denominator = parseInt(denominator);
    gcd = Math.gcd(numerator, denominator);

    return (numerator/gcd).toString() + '/' + (denominator/gcd).toString();

}

Number.prototype.multiples = function() {
    var
        n = parseInt(this),
        i = 1,
        _multiples = []
    ;

    if(n === 0) { return ["∞"]; }

    if(n < 0) { n *= -1; }

    while(true) {
        if(n%i === 0) { _multiples.push(i); }
        if(i === n) { break; }
        i++;
    }

    return _multiples;
}

Number.firstMultiple = function(n) {
    return n.firstMultiple();
}

Number.prototype.firstMultiple = function() {
    var
        i = 1,
        count = 1,
        n = this,
        m = n
    ;

    if (n < 0) { n *= -1; }

    while(i <= n && count < 3) {
        if(n%i === 0) {
            count++;
            m = i;
        }
        i++;

    }

    return parseFloat(m);
}

Array.prototype.firstMultiple = function() {
    var
        _arr = this,
        _factors = []
    ;

    _arr.map(function(item) {
        if(item > 1) { _factors.push(item.firstMultiple()); }
    });

    return (_factors.sort())[0];
}
<|endoftext|>


<commit_before>import {
  forEach
} from 'min-dash';

import {
  closest as domClosest
} from 'min-dom';

var LOW_PRIORITY = 250;

/**
 * The tool manager acts as middle-man between the available tool's and the Palette,
 * it takes care of making sure that the correct active state is set.
 *
 * @param  {Object}    eventBus
 * @param  {Object}    dragging
 */
export default function ToolManager(eventBus, dragging) {
  this._eventBus = eventBus;
  this._dragging = dragging;

  this._tools = [];
  this._active = null;
}

ToolManager.$inject = [ 'eventBus', 'dragging' ];

ToolManager.prototype.registerTool = function(name, events) {
  var tools = this._tools;

  if (!events) {
    throw new Error('A tool has to be registered with it\'s "events"');
  }

  tools.push(name);

  this.bindEvents(name, events);
};

ToolManager.prototype.isActive = function(tool) {
  return tool && this._active === tool;
};

ToolManager.prototype.length = function(tool) {
  return this._tools.length;
};

ToolManager.prototype.setActive = function(tool) {
  var eventBus = this._eventBus;

  if (this._active !== tool) {
    this._active = tool;

    eventBus.fire('tool-manager.update', { tool: tool });
  }
};

ToolManager.prototype.bindEvents = function(name, events) {
  var eventBus = this._eventBus,
      dragging = this._dragging;

  var eventsToRegister = [];

  eventBus.on(events.tool + '.init', function(event) {
    var context = event.context;

    // Active tools that want to reactivate themselves must do this explicitly
    if (!context.reactivate && this.isActive(name)) {
      this.setActive(null);

      dragging.cancel();
      return;
    }

    this.setActive(name);

  }, this);

  // Todo[ricardo]: add test cases
  forEach(events, function(event) {
    eventsToRegister.push(event + '.ended');
    eventsToRegister.push(event + '.canceled');
  });

  eventBus.on(eventsToRegister, LOW_PRIORITY, function(event) {
    var originalEvent = event.originalEvent;

    // We defer the de-activation of the tool to the .activate phase,
    // so we're able to check if we want to toggle off the current
    // active tool or switch to a new one
    if (!this._active) {
      return;
    }

    if (originalEvent && domClosest(originalEvent.target, '.group[data-group="tools"]')) {
      return;
    }

    this.setActive(null);
  }, this);
};
<commit_msg>chore(tool-manager): make palette click detection fail safe<commit_after>import {
  forEach
} from 'min-dash';

import {
  closest as domClosest
} from 'min-dom';

var LOW_PRIORITY = 250;

/**
 * The tool manager acts as middle-man between the available tool's and the Palette,
 * it takes care of making sure that the correct active state is set.
 *
 * @param  {Object}    eventBus
 * @param  {Object}    dragging
 */
export default function ToolManager(eventBus, dragging) {
  this._eventBus = eventBus;
  this._dragging = dragging;

  this._tools = [];
  this._active = null;
}

ToolManager.$inject = [ 'eventBus', 'dragging' ];

ToolManager.prototype.registerTool = function(name, events) {
  var tools = this._tools;

  if (!events) {
    throw new Error('A tool has to be registered with it\'s "events"');
  }

  tools.push(name);

  this.bindEvents(name, events);
};

ToolManager.prototype.isActive = function(tool) {
  return tool && this._active === tool;
};

ToolManager.prototype.length = function(tool) {
  return this._tools.length;
};

ToolManager.prototype.setActive = function(tool) {
  var eventBus = this._eventBus;

  if (this._active !== tool) {
    this._active = tool;

    eventBus.fire('tool-manager.update', { tool: tool });
  }
};

ToolManager.prototype.bindEvents = function(name, events) {
  var eventBus = this._eventBus,
      dragging = this._dragging;

  var eventsToRegister = [];

  eventBus.on(events.tool + '.init', function(event) {
    var context = event.context;

    // Active tools that want to reactivate themselves must do this explicitly
    if (!context.reactivate && this.isActive(name)) {
      this.setActive(null);

      dragging.cancel();
      return;
    }

    this.setActive(name);

  }, this);

  // Todo[ricardo]: add test cases
  forEach(events, function(event) {
    eventsToRegister.push(event + '.ended');
    eventsToRegister.push(event + '.canceled');
  });

  eventBus.on(eventsToRegister, LOW_PRIORITY, function(event) {

    // We defer the de-activation of the tool to the .activate phase,
    // so we're able to check if we want to toggle off the current
    // active tool or switch to a new one
    if (!this._active) {
      return;
    }

    if (isPaletteClick(event)) {
      return;
    }

    this.setActive(null);
  }, this);

};

// helpers ///////////////

/**
 * Check if a given event is a palette click event.
 *
 * @param {EventBus.Event} event
 *
 * @return {boolean}
 */
function isPaletteClick(event) {
  var target = event.originalEvent && event.originalEvent.target;

  return target && domClosest(target, '.group[data-group="tools"]');
}<|endoftext|>


<commit_before>import React, { Component } from 'react'
import Shelf from './Shelf'

class Bookcase extends Component {

  render () {
    const { books, shelves, updateShelf } = this.props

    return (

        {shelves.map(s => (
          <Shelf key={s.key} books={books.filter(b => b.shelf === s.value)} shelves={shelves} shelfTitle={s.text} updateShelf={updateShelf} />
        )) }

    )
  }

}

export default Bookcase
<commit_msg>refactor: add link to search page<commit_after>import React, { Component } from 'react'
import { Link } from 'react-router-dom';
import { Segment, Grid } from 'semantic-ui-react'
import Shelf from './Shelf'

class Bookcase extends Component {

  render () {
    const { books, shelves, updateShelf } = this.props

    return (

        {shelves.map(s => (
          <Grid.Row key={s.key} style={{ marginTop: '10px', padding: '10px' }}>
            <Grid.Column>
              <Segment raised>

{s.text}

                <Shelf books={books.filter(b => b.shelf === s.value)} shelves={shelves} updateShelf={updateShelf} />
              </Segment>
            </Grid.Column>
          </Grid.Row>
        ))}

          <Link to="/search">
            Add a book
          </Link>

    )
  }

}

export default Bookcase
<|endoftext|>


<commit_before>import React from 'react'
import { graphql, Link } from 'gatsby'
import get from 'lodash/get'
import Helmet from 'react-helmet'
import Layout from '../components/Layout'
import Article from '../components/Article'

export default class extends React.Component {
  render() {
    const siteTitle = get(this, 'props.data.site.siteMetadata.title')
    const articles = get(this, 'props.data.allMarkdownRemark.edges')
    const cover = get(this, 'props.data.cover')

    return (
      <Layout
        location={this.props.location}
        title="Articles"
        description="Checkout all my articles about Scala, Kafka, ReactJS etc."
        cover={cover}
      >
        <Helmet title={siteTitle + ' | Articles'} />
        {articles.map(({ node }) => (
          <Article
            key={node.frontmatter.path}
            {...node.frontmatter}
            {...node}
          />
        ))}
      </Layout>
    )
  }
}

export const pageQuery = graphql`
  query IndexQuery {
    site {
      siteMetadata {
        title
      }
    }
    allMarkdownRemark(
      sort: { fields: [frontmatter___date], order: DESC }
      filter: { frontmatter: { is_blog: { eq: true } } }
    ) {
      edges {
        node {
          ...ArticleFrontmatter
        }
      }
    }

    cover: file(relativePath: { eq: "DSC00806.jpg" }) {
      childImageSharp {
        fluid(
          maxHeight: 220
          maxWidth: 1000
          cropFocus: CENTER
          quality: 90
          duotone: { highlight: "#0288d1", shadow: "#192550", opacity: 80 }
        ) {
          ...GatsbyImageSharpFluid
        }
      }
    }
  }
`
<commit_msg>Remove cover for articles<commit_after>import React from 'react'
import { graphql, Link } from 'gatsby'
import get from 'lodash/get'
import Helmet from 'react-helmet'
import Layout from '../components/Layout'
import Article from '../components/Article'

export default class extends React.Component {
  render() {
    const siteTitle = get(this, 'props.data.site.siteMetadata.title')
    const articles = get(this, 'props.data.allMarkdownRemark.edges')
    const cover = get(this, 'props.data.cover')

    return (
      <Layout
        location={this.props.location}
        title="Articles"
        description="Checkout all my articles about Scala, Kafka, ReactJS etc."
      >
        <Helmet title={siteTitle + ' | Articles'} />
        {articles.map(({ node }) => (
          <Article
            key={node.frontmatter.path}
            {...node.frontmatter}
            {...node}
          />
        ))}
      </Layout>
    )
  }
}

export const pageQuery = graphql`
  query IndexQuery {
    site {
      siteMetadata {
        title
      }
    }
    allMarkdownRemark(
      sort: { fields: [frontmatter___date], order: DESC }
      filter: { frontmatter: { is_blog: { eq: true } } }
    ) {
      edges {
        node {
          ...ArticleFrontmatter
        }
      }
    }

    cover: file(relativePath: { eq: "DSC00806.jpg" }) {
      childImageSharp {
        fluid(
          maxHeight: 220
          maxWidth: 1000
          cropFocus: CENTER
          quality: 90
          duotone: { highlight: "#0288d1", shadow: "#192550", opacity: 80 }
        ) {
          ...GatsbyImageSharpFluid
        }
      }
    }
  }
`
<|endoftext|>


<commit_before>import { Component } from '@angular/core';

import path from 'path';
import fs from 'fs';
import $ from 'jquery';
import { remote, app, shell } from 'electron'; // native electron module
import jetpack from 'fs-jetpack'; // module loaded from npm
import Docxtemplater from 'docxtemplater';
var Handsontable = require('./handsontablep/dist/handsontable.full.js');
import dataapi from '../stores/dataapi';
import schemas from '../schemas';
import { exportKeluarga } from '../helpers/exporter';
import { initializeTableSearch, initializeTableCount, initializeTableSelected } from '../helpers/table';
import expressions from 'angular-expressions';
import createPrintVars from '../helpers/printvars';
import diffProps from '../helpers/diff';

window.jQuery = $;
require('./node_modules/bootstrap/dist/js/bootstrap.js');

var app = remote.app;
var hot;
var sheetContainer;
var emptyContainer;
var resultBefore=[];

var init =  function () {
    sheetContainer = document.getElementById('sheet');
    emptyContainer = document.getElementById('empty');
    window.hot = hot = new Handsontable(sheetContainer, {
        data: [],
        topOverlay: 34,

        rowHeaders: true,
        colHeaders: schemas.getHeader(schemas.keluarga),
        columns: schemas.keluarga,

        colWidths: schemas.getColWidths(schemas.keluarga),
        rowHeights: 23,

        columnSorting: true,
        sortIndicator: true,
        hiddenColumns: {indicators: true},

        renderAllRows: false,
        outsideClickDeselects: false,
        autoColumnSize: false,

        search: true,
        filters: true,
        contextMenu: ['undo', 'redo', 'row_above', 'remove_row'],
        dropdownMenu: ['filter_by_condition', 'filter_action_bar']
    });

    var spanSelected = $("#span-selected")[0];
    initializeTableSelected(hot, 1, spanSelected);

    var spanCount = $("#span-count")[0];
    initializeTableCount(hot, spanCount);

    window.addEventListener('resize', function(e){
        hot.render();
    })
};

var showColumns = [
    [],
    ["no_kk","nama_kepala_keluarga","alamat","dusun","rt","rw"],
    ["no_kk","nama_kepala_keluarga","raskin","jamkesmas","pkh"]
]

var spliceArray = function(fields, showColumns){
    var result=[];
    for(var i=0;i!=fields.length;i++){
        var index = showColumns.indexOf(fields[i]);
        if (index == -1) result.push(i);
    }
    return result;
}

var allPenduduks = {};
var updateKeluarga = function(keluargas, penduduks){
    var existsKeluargas = {};
    var keluargaMap = {};
    for(var i = 0; i < keluargas.length; i++){
        var k = keluargas[i];
        existsKeluargas[k[0]] = true;
        keluargaMap[k[0]] = k;
    }

    for(var i = 0; i < penduduks.length; i++){
        var p = penduduks[i];
        var po = schemas.arrayToObj(p, schemas.penduduk);
        if(!po.no_kk)
            continue;

        if(!existsKeluargas[po.no_kk]){
            var ko = {no_kk: po.no_kk, dusun: po.dusun, rt: po.rt, rw: po.rw, alamat_jalan: po.alamat_jalan, raskin: null, bpjs: null, kip: null, pkh: null};
            var k = schemas.objToArray(ko, schemas.keluarga);
            keluargas.push(k);
            keluargaMap[po.no_kk] = k;
            existsKeluargas[po.no_kk] = true;
        }

        if(!allPenduduks[po.no_kk]){
            allPenduduks[po.no_kk] = [];
        }
        allPenduduks[po.no_kk].push(po)

        if(po.hubungan_keluarga == "Kepala Keluarga"){
            keluargaMap[po.no_kk][1] = po.nama_penduduk;
            keluargaMap[po.no_kk][2] = po.nik;
        }
    }

    for(var i = 0; i < keluargas.length; i++){
        var k = keluargas[i];
        var count = 0;
        if(allPenduduks[k[0]])
            count = allPenduduks[k[0]].length;
        k[3] = count;
    }

}

var KeluargaComponent = Component({
    selector: 'keluarga',
    templateUrl: 'templates/keluarga.html'
})
.Class(Object.assign(diffProps, {
    constructor: function() {
    },
    ngOnInit: function(){
        $("title").html("Data Keluarga - " +dataapi.getActiveAuth().desa_name);
        init();

        var inputSearch = document.getElementById("input-search");
        this.tableSearcher = initializeTableSearch(hot, document, inputSearch);

        this.hot = window.hot;
        var ctrl = this;

        function keyup(e) {
            //ctrl+s
            if (e.ctrlKey && e.keyCode == 83){
                ctrl.openSaveDiffDialog();
                e.preventDefault();
                e.stopPropagation();
            }
            //ctrl+p
            if (e.ctrlKey && e.keyCode == 80){
                ctrl.printKK();
                e.preventDefault();
                e.stopPropagation();
            }
        }
        document.addEventListener('keyup', keyup, false);

        dataapi.getContent("keluarga", null, [], schemas.keluarga, function(keluargaContent){
            dataapi.getContent("penduduk", null, [], schemas.penduduk, function(pendudukContent){
                updateKeluarga(keluargaContent, pendudukContent);
                ctrl.initialData = JSON.parse(JSON.stringify(keluargaContent));
                hot.loadData(keluargaContent);
                setTimeout(function(){
                    $(sheetContainer).removeClass("hidden");
                    hot.render();
                    ctrl.loaded = true;
                },500);
            })
        })
        this.initDiffComponent();
    },
    exportExcel: function(){
        var data = hot.getSourceData();
        exportKeluarga(data, "Data Keluarga");
    },
    filterContent: function(){
        var plugin = hot.getPlugin('hiddenColumns');
        var value = $('input[name=btn-filter]:checked').val();
        var fields = schemas.keluarga.map(c => c.field);
        var result = spliceArray(fields,showColumns[value]);

        plugin.showColumns(resultBefore);
        if(value==0) plugin.showColumns(result);
        else plugin.hideColumns(result);
        hot.render();
        resultBefore = result;
    },
    saveContent: function(){
        $("#modal-save-diff").modal("hide");
        var timestamp = new Date().getTime();
        var content = hot.getSourceData();
        this.savingMessage = "Menyimpan...";
        var that = this;
        dataapi.saveContent("keluarga", null, content, schemas.keluarga, function(err, response, body){
            that.savingMessage = "Penyimpanan "+ (err ? "gagal" : "berhasil");
            setTimeout(function(){
                if(!err){
                    that.initialData = JSON.parse(JSON.stringify(content));
                    that.afterSave();
                }
                that.savingMessage = null;
            }, 2000);
        });
        return false;
    },
    printKK: function(){
        var selected = hot.getSelected();
        if(!selected)
            return;

        var fileName = remote.dialog.showSaveDialog({
            filters: [
                {name: 'Word document', extensions: ['docx']},
            ]
        });
        if(fileName){
            if(!fileName.endsWith(".docx"))
                fileName = fileName+".docx";
            var angularParser= function(tag){
                var expr=expressions.compile(tag);
                return {get:expr};
            }
            var nullGetter = function(tag, props) {
                return "";
            };
            var keluarga = schemas.arrayToObj(hot.getDataAtRow(selected[0]), schemas.keluarga);
            var rawPenduduks = allPenduduks[keluarga.no_kk];
            var idx = 1;
            var penduduks = rawPenduduks.map(function(o){
                var res = Object.assign({}, o);
                res.no = idx;
                idx++;
                return res;
            });
            dataapi.getDesa(function(desas){
                var auth = dataapi.getActiveAuth();
                var desa = desas.filter(d => d.blog_id == auth.desa_id)[0];
                var printvars = createPrintVars(desa);

                var content = fs.readFileSync(path.join(app.getAppPath(), "docx_templates","kk.docx"),"binary");
                var doc=new Docxtemplater(content);
                doc.setOptions({parser:angularParser, nullGetter: nullGetter});
                doc.setData({penduduks: penduduks, vars: printvars, keluarga: keluarga});
                doc.render();

                var buf = doc.getZip().generate({type:"nodebuffer"});
                fs.writeFileSync(fileName, buf);
                shell.openItem(fileName);
            });
        }
    }
}));

export default KeluargaComponent;
<commit_msg>remove zero length keluarga<commit_after>import { Component } from '@angular/core';

import path from 'path';
import fs from 'fs';
import $ from 'jquery';
import { remote, app, shell } from 'electron'; // native electron module
import jetpack from 'fs-jetpack'; // module loaded from npm
import Docxtemplater from 'docxtemplater';
var Handsontable = require('./handsontablep/dist/handsontable.full.js');
import dataapi from '../stores/dataapi';
import schemas from '../schemas';
import { exportKeluarga } from '../helpers/exporter';
import { initializeTableSearch, initializeTableCount, initializeTableSelected } from '../helpers/table';
import expressions from 'angular-expressions';
import createPrintVars from '../helpers/printvars';
import diffProps from '../helpers/diff';

window.jQuery = $;
require('./node_modules/bootstrap/dist/js/bootstrap.js');

var app = remote.app;
var hot;
var sheetContainer;
var emptyContainer;
var resultBefore=[];

var init =  function () {
    sheetContainer = document.getElementById('sheet');
    emptyContainer = document.getElementById('empty');
    window.hot = hot = new Handsontable(sheetContainer, {
        data: [],
        topOverlay: 34,

        rowHeaders: true,
        colHeaders: schemas.getHeader(schemas.keluarga),
        columns: schemas.keluarga,

        colWidths: schemas.getColWidths(schemas.keluarga),
        rowHeights: 23,

        columnSorting: true,
        sortIndicator: true,
        hiddenColumns: {indicators: true},

        renderAllRows: false,
        outsideClickDeselects: false,
        autoColumnSize: false,

        search: true,
        filters: true,
        contextMenu: ['undo', 'redo', 'row_above', 'remove_row'],
        dropdownMenu: ['filter_by_condition', 'filter_action_bar']
    });

    var spanSelected = $("#span-selected")[0];
    initializeTableSelected(hot, 1, spanSelected);

    var spanCount = $("#span-count")[0];
    initializeTableCount(hot, spanCount);

    window.addEventListener('resize', function(e){
        hot.render();
    })
};

var showColumns = [
    [],
    ["no_kk","nama_kepala_keluarga","alamat","dusun","rt","rw"],
    ["no_kk","nama_kepala_keluarga","raskin","jamkesmas","pkh"]
]

var spliceArray = function(fields, showColumns){
    var result=[];
    for(var i=0;i!=fields.length;i++){
        var index = showColumns.indexOf(fields[i]);
        if (index == -1) result.push(i);
    }
    return result;
}

var allPenduduks = {};
var updateKeluarga = function(keluargas, penduduks){
    var existsKeluargas = {};
    var keluargaMap = {};
    for(var i = 0; i < keluargas.length; i++){
        var k = keluargas[i];
        existsKeluargas[k[0]] = true;
        keluargaMap[k[0]] = k;
    }

    for(var i = 0; i < penduduks.length; i++){
        var p = penduduks[i];
        var po = schemas.arrayToObj(p, schemas.penduduk);
        if(!po.no_kk)
            continue;

        if(!existsKeluargas[po.no_kk]){
            var ko = {no_kk: po.no_kk, dusun: po.dusun, rt: po.rt, rw: po.rw, alamat_jalan: po.alamat_jalan, raskin: null, bpjs: null, kip: null, pkh: null};
            var k = schemas.objToArray(ko, schemas.keluarga);
            keluargas.push(k);
            keluargaMap[po.no_kk] = k;
            existsKeluargas[po.no_kk] = true;
        }

        if(!allPenduduks[po.no_kk]){
            allPenduduks[po.no_kk] = [];
        }
        allPenduduks[po.no_kk].push(po)

        if(po.hubungan_keluarga == "Kepala Keluarga"){
            keluargaMap[po.no_kk][1] = po.nama_penduduk;
            keluargaMap[po.no_kk][2] = po.nik;
        }
    }

    for(var i = keluargas.length - 1; i >= 0; i--){
        var k = keluargas[i];
        var count = 0;
        if(allPenduduks[k[0]])
            count = allPenduduks[k[0]].length;
        k[3] = count;
        if(count == 0){
            keluargas.splice(i, 1);
        }
    }

}

var KeluargaComponent = Component({
    selector: 'keluarga',
    templateUrl: 'templates/keluarga.html'
})
.Class(Object.assign(diffProps, {
    constructor: function() {
    },
    ngOnInit: function(){
        $("title").html("Data Keluarga - " +dataapi.getActiveAuth().desa_name);
        init();

        var inputSearch = document.getElementById("input-search");
        this.tableSearcher = initializeTableSearch(hot, document, inputSearch);

        this.hot = window.hot;
        var ctrl = this;

        function keyup(e) {
            //ctrl+s
            if (e.ctrlKey && e.keyCode == 83){
                ctrl.openSaveDiffDialog();
                e.preventDefault();
                e.stopPropagation();
            }
            //ctrl+p
            if (e.ctrlKey && e.keyCode == 80){
                ctrl.printKK();
                e.preventDefault();
                e.stopPropagation();
            }
        }
        document.addEventListener('keyup', keyup, false);

        dataapi.getContent("keluarga", null, [], schemas.keluarga, function(keluargaContent){
            dataapi.getContent("penduduk", null, [], schemas.penduduk, function(pendudukContent){
                updateKeluarga(keluargaContent, pendudukContent);
                ctrl.initialData = JSON.parse(JSON.stringify(keluargaContent));
                hot.loadData(keluargaContent);
                setTimeout(function(){
                    $(sheetContainer).removeClass("hidden");
                    hot.render();
                    ctrl.loaded = true;
                },500);
            })
        })
        this.initDiffComponent();
    },
    exportExcel: function(){
        var data = hot.getSourceData();
        exportKeluarga(data, "Data Keluarga");
    },
    filterContent: function(){
        var plugin = hot.getPlugin('hiddenColumns');
        var value = $('input[name=btn-filter]:checked').val();
        var fields = schemas.keluarga.map(c => c.field);
        var result = spliceArray(fields,showColumns[value]);

        plugin.showColumns(resultBefore);
        if(value==0) plugin.showColumns(result);
        else plugin.hideColumns(result);
        hot.render();
        resultBefore = result;
    },
    saveContent: function(){
        $("#modal-save-diff").modal("hide");
        var timestamp = new Date().getTime();
        var content = hot.getSourceData();
        this.savingMessage = "Menyimpan...";
        var that = this;
        dataapi.saveContent("keluarga", null, content, schemas.keluarga, function(err, response, body){
            that.savingMessage = "Penyimpanan "+ (err ? "gagal" : "berhasil");
            setTimeout(function(){
                if(!err){
                    that.initialData = JSON.parse(JSON.stringify(content));
                    that.afterSave();
                }
                that.savingMessage = null;
            }, 2000);
        });
        return false;
    },
    printKK: function(){
        var selected = hot.getSelected();
        if(!selected)
            return;

        var fileName = remote.dialog.showSaveDialog({
            filters: [
                {name: 'Word document', extensions: ['docx']},
            ]
        });
        if(fileName){
            if(!fileName.endsWith(".docx"))
                fileName = fileName+".docx";
            var angularParser= function(tag){
                var expr=expressions.compile(tag);
                return {get:expr};
            }
            var nullGetter = function(tag, props) {
                return "";
            };
            var keluarga = schemas.arrayToObj(hot.getDataAtRow(selected[0]), schemas.keluarga);
            var rawPenduduks = allPenduduks[keluarga.no_kk];
            var idx = 1;
            var penduduks = rawPenduduks.map(function(o){
                var res = Object.assign({}, o);
                res.no = idx;
                idx++;
                return res;
            });
            dataapi.getDesa(function(desas){
                var auth = dataapi.getActiveAuth();
                var desa = desas.filter(d => d.blog_id == auth.desa_id)[0];
                var printvars = createPrintVars(desa);

                var content = fs.readFileSync(path.join(app.getAppPath(), "docx_templates","kk.docx"),"binary");
                var doc=new Docxtemplater(content);
                doc.setOptions({parser:angularParser, nullGetter: nullGetter});
                doc.setData({penduduks: penduduks, vars: printvars, keluarga: keluarga});
                doc.render();

                var buf = doc.getZip().generate({type:"nodebuffer"});
                fs.writeFileSync(fileName, buf);
                shell.openItem(fileName);
            });
        }
    }
}));

export default KeluargaComponent;
<|endoftext|>


<commit_before>$( function() {
	$.widget( "d2l.accordion", {

		options: {},

		_create: function() {

			var me = this;

			var $accordion = $( this.element );

			$accordion
				.attr( 'role', 'tablist' )
				.attr(
					'aria-multiselectable',
					this._getDisplayMode( $accordion ) !== 'accordion'
				);

			$.each(
				$accordion.find( '.d2l-accordion-header' ),
				function( index, headerNode ) {
					me._initializePanel(
						$accordion,
						$( headerNode ),
						( index === 0 )
					);
				}
			);

		},

		collapseAll: function() {

			var me = this;

			$.each(
				$( this.element ).find( '.d2l-accordion-header' ),
				function( index, headerNode ) {
					me._collapsePanel( $( headerNode ) );
				}
			);

		},

		_collapsePanel: function( $header ) {

			if ( !$header.hasClass( 'd2l-accordion-panel-expanded' ) ) {
				return;
			}

			$( this.element ).trigger(
				'collapsePanel', {
				    header: $header.get(0)
				}
			);

			$header.attr( 'aria-expanded', 'false' )
				.removeClass( 'd2l-accordion-panel-expanded' );

			var contentId = $header.attr( 'data-content-id' );

			var contentNode = document.getElementById( contentId );
			if ( contentNode == null ) {
				return;
			}

			$( contentNode )
				.attr( 'aria-hidden', 'true' )
				.animate( {
					height: [ 'hide', 'swing' ]
				}, 250 );

		},

		_expandPanel: function( $header ) {

			var $accordion = $( this.element );

			if ( this._getDisplayMode( $accordion ) === 'accordion' ) {
				$accordion.accordion( 'collapseAll' );
			}

			$accordion.trigger(
				'expandPanel', {
					header: $header.get( 0 ),
					isFirstExpand: !$header.data( 'hasExpanded' )
				}
			);

			$header.attr( 'aria-expanded', 'true' )
				.addClass( 'd2l-accordion-panel-expanded' );

			var contentId = $header.attr( 'data-content-id' );

			var contentNode = document.getElementById( contentId );
			if ( contentNode == null ) {
				return;
			}

			$( contentNode )
				.attr( 'aria-hidden', 'false' )
				.animate( {
					height: [ 'show', 'swing' ]
				}, 250 );

		},

		_getDisplayMode: function( $node ) {
			return $node.attr( 'data-display-mode' );
		},

		_initializePanel: function( $accordion, $header, isFocusable ) {

			var contentId = $header.attr( 'data-content-id' );
			if ( contentId == null ) {
				return;
			}

			var contentNode = document.getElementById( contentId );
			if ( contentNode == null ) {
				return;
			}

			var me = this;

			var isExpanded = ( $header.attr( 'data-expanded' ) === 'true' );
			var labelledById = $header.attr( 'data-content-labelledby' );

			var togglePanel = function() {
				if ( $header.hasClass( 'd2l-accordion-panel-expanded' ) ) {
					me._collapsePanel( $header );
				} else {
					me._expandPanel( $header );
				}
			};

			var $content = $( contentNode );

			var isEnabled = !$content.is( ':empty' );

			$header
				.attr( 'role', 'tab' )
				.attr( 'aria-controls', contentId )
				.attr( 'aria-expanded', isExpanded )
				.attr( 'aria-selected', isFocusable ? 'true' : 'false' )
				.attr( 'tabindex', isFocusable ? '0' : '-1' )
				.data( 'hasExpanded', isExpanded )
				.removeAttr( 'data-expanded' )
				.click( function( e ) {

					if ( !isEnabled ) {
						return;
					}

					var eventTarget = e.target;

					while ( eventTarget !== $header.get( 0 ) && eventTarget !== null ) {
						if ( $( eventTarget ).is( ':focusable' ) ) {
							return;
						}
						eventTarget = eventTarget.parentNode;
					}

					togglePanel();

				} ).focus( function( e ) {

					$header.addClass( 'd2l-accordion-header-active' );

				} ).blur( function( e ) {

					$header.removeClass( 'd2l-accordion-header-active' );

				} ).keydown( function( e ) {

					// prevent scrolling page when arrow keys, home, or end are pressed
					if ( e.keyCode >=35 && e.keyCode <=40 ) {
						e.preventDefault();
						return false;
					}

				} ).keyup( function( e ) {

					if ( e.keyCode === 13 || e.keyCode === 32 ) {
						// enter/space
						if ( !isEnabled ) {
							return;
						}
						togglePanel();
					} else if ( e.keyCode === 39 || e.keyCode === 40 ) {
						// down/right
						me._focusPanel( $header, me._tryGetNextPanel( $header ) );
					} else if ( e.keyCode === 37 || e.keyCode === 38 ) {
						// up/left
						me._focusPanel( $header, me._tryGetPreviousPanel( $header ) );
					} else if ( e.keyCode === 35 ) {
						// end - last panel
						me._focusPanel( $header, me._getLastPanelHeader() );
					} else if ( e.keyCode === 36 ) {
						// home - first panel
						me._focusPanel( $header, me._getFirstPanelHeader() );
					}

				} );

			if ( !isEnabled ) {
				$header
					.attr( 'aria-disabled', 'true' )
					.addClass( 'd2l-accordion-header-disabled' );
			}

			$content
				.attr( 'role', 'tabpanel' )
				.attr( 'aria-labelledby', labelledById )
				.attr( 'aria-hidden', 'true' )
				.hide();

			if ( isExpanded ) {

				if ( this._getDisplayMode( $accordion ) === 'accordion' ) {
					$.each(
						$accordion.find( '.d2l-accordion-panel-expanded' ),
						function( index, panelNode ) {
							me._collapsePanel( $( panelNode ) );
						}
					);
				}

				$header.addClass( 'd2l-accordion-panel-expanded' );

				setTimeout( function() {
					$accordion.trigger(
						'expandPanel', {
							header: $header.get( 0 ),
							isFirstExpand: true
						}
					);
				}, 0 );

				$content
					.attr( 'aria-hidden', 'false' )
					.show();

			}

		},

		_focusPanel: function( $currentHeader, $header ) {

			if ( $header === null ) {
				return;
			}

			$currentHeader
				.attr( 'tabindex', '-1' )
				.attr( 'aria-selected', 'false' );

			$header
				.attr( 'tabindex', '0' )
				.attr( 'aria-selected', 'true' )
				.focus();

		},

		_getFirstPanelHeader: function() {
			var $headers = $( this.element )
				.find( '.d2l-accordion-header');
			return $( $headers[ 0 ] );
		},

		_getLastPanelHeader: function() {
			var $headers = $( this.element )
				.find( '.d2l-accordion-header');
			return $( $headers[ $headers.length - 1 ] );
		},

		_tryGetPreviousPanel: function( $header ) {

			var $previousElement = $header.prev();

			if ( $previousElement.length === 0 ) {
				return this._getLastPanelHeader();
			} else if ( $previousElement.hasClass( 'd2l-accordion-header' ) ) {
				return $previousElement;
			} else {
				return this._tryGetPreviousPanel( $previousElement );
			}

		},

		_tryGetNextPanel: function( $header ) {

			var $nextElement = $header.next();

			if ( $nextElement.length === 0 ) {
				return this._getFirstPanelHeader();
			} else if ( $nextElement.hasClass( 'd2l-accordion-header' ) ) {
				return $nextElement;
			} else {
				return this._tryGetNextPanel( $nextElement );
			}

		}

	} );

	$( '.d2l-accordion' ).accordion();

	$( document )
		.on(
			'vui-viewrender',
			function( evt ) {
				$( evt.target ).find( '.d2l-accordion' ).accordion();
				// TODO: handle case where evt.target needs to be applied
			}
		);

} );<commit_msg>Backed out changeset: 7e2fe4fa422c<commit_after>$( function() {
	$.widget( "d2l.accordion", {

		options: {},

		_create: function() {

			var me = this;

			var $accordion = $( this.element );

			$accordion
				.attr( 'role', 'tablist' )
				.attr(
					'aria-multiselectable',
					this._getDisplayMode( $accordion ) !== 'accordion'
				);

			$.each(
				$accordion.find( '.d2l-accordion-header' ),
				function( index, headerNode ) {
					me._initializePanel(
						$accordion,
						$( headerNode ),
						( index === 0 )
					);
				}
			);

		},

		collapseAll: function() {

			var me = this;

			$.each(
				$( this.element ).find( '.d2l-accordion-header' ),
				function( index, headerNode ) {
					me._collapsePanel( $( headerNode ) );
				}
			);

		},

		_collapsePanel: function( $header ) {

			if ( !$header.hasClass( 'd2l-accordion-panel-expanded' ) ) {
				return;
			}

			$( this.element ).trigger(
				'collapsePanel', {
				    header: $header.get(0)
				}
			);

			$header.attr( 'aria-expanded', 'false' )
				.removeClass( 'd2l-accordion-panel-expanded' );

			var contentId = $header.attr( 'data-content-id' );

			var contentNode = document.getElementById( contentId );
			if ( contentNode == null ) {
				return;
			}

			$( contentNode )
				.attr( 'aria-hidden', 'true' )
				.animate( {
					height: [ 'hide', 'swing' ]
				}, 250 );

		},

		_expandPanel: function( $header ) {

			var $accordion = $( this.element );

			if ( this._getDisplayMode( $accordion ) === 'accordion' ) {
				$accordion.accordion( 'collapseAll' );
			}

			$accordion.trigger(
				'expandPanel', {
					header: $header.get( 0 ),
					isFirstExpand: !$header.data( 'hasExpanded' )
				}
			);

			$header.attr( 'aria-expanded', 'true' )
				.addClass( 'd2l-accordion-panel-expanded' );

			var contentId = $header.attr( 'data-content-id' );

			var contentNode = document.getElementById( contentId );
			if ( contentNode == null ) {
				return;
			}

			$( contentNode )
				.attr( 'aria-hidden', 'false' )
				.animate( {
					height: [ 'show', 'swing' ]
				}, 250 );

		},

		_getDisplayMode: function( $node ) {
			return $node.attr( 'data-display-mode' );
		},

		_initializePanel: function( $accordion, $header, isFocusable ) {

			var contentId = $header.attr( 'data-content-id' );
			if ( contentId == null ) {
				return;
			}

			var contentNode = document.getElementById( contentId );
			if ( contentNode == null ) {
				return;
			}

			var me = this;

			var isExpanded = ( $header.attr( 'data-expanded' ) === 'true' );
			var labelledById = $header.attr( 'data-content-labelledby' );

			var togglePanel = function() {
				if ( $header.hasClass( 'd2l-accordion-panel-expanded' ) ) {
					me._collapsePanel( $header );
				} else {
					me._expandPanel( $header );
				}
			};

			var $content = $( contentNode );

			var isEnabled = !$content.is( ':empty' );

			$header
				.attr( 'role', 'tab' )
				.attr( 'aria-controls', contentId )
				.attr( 'aria-expanded', isExpanded )
				.attr( 'aria-selected', isFocusable ? 'true' : 'false' )
				.attr( 'tabindex', isFocusable ? '0' : '-1' )
				.data( 'hasExpanded', isExpanded )
				.removeAttr( 'data-expanded' )
				.click( function( e ) {

					if ( !isEnabled ) {
						return;
					}

					var eventTarget = e.target;

					while ( eventTarget !== $header.get( 0 ) && eventTarget !== null ) {
						if ( $( eventTarget ).is( ':focusable' ) ) {
							return;
						}
						eventTarget = eventTarget.parentNode;
					}

					togglePanel();

				} ).focus( function( e ) {

					$header.addClass( 'd2l-accordion-header-active' );

				} ).blur( function( e ) {

					$header.removeClass( 'd2l-accordion-header-active' );

				} ).keydown( function( e ) {

					// prevent scrolling page when arrow keys, home, or end are pressed
					if ( e.keyCode >=35 && e.keyCode <=40 ) {
						e.preventDefault();
						return false;
					}

				} ).keyup( function( e ) {

					if ( e.keyCode === 13 || e.keyCode === 32 ) {
						// enter/space
						if ( !isEnabled ) {
							return;
						}
						togglePanel();
					} else if ( e.keyCode === 39 || e.keyCode === 40 ) {
						// down/right
						me._focusPanel( $header, me._tryGetNextPanel( $header ) );
					} else if ( e.keyCode === 37 || e.keyCode === 38 ) {
						// up/left
						me._focusPanel( $header, me._tryGetPreviousPanel( $header ) );
					} else if ( e.keyCode === 35 ) {
						// end - last panel
						me._focusPanel( $header, me._getLastPanelHeader() );
					} else if ( e.keyCode === 36 ) {
						// home - first panel
						me._focusPanel( $header, me._getFirstPanelHeader() );
					}

				} );

			if ( !isEnabled ) {
				$header
					.attr( 'aria-disabled', 'true' )
					.addClass( 'd2l-accordion-header-disabled' );
			}

			$content
				.attr( 'role', 'tabpanel' )
				.attr( 'aria-labelledby', labelledById )
				.attr( 'aria-hidden', 'true' );

			if ( isExpanded ) {

				if ( this._getDisplayMode( $accordion ) === 'accordion' ) {
					$.each(
						$accordion.find( '.d2l-accordion-panel-expanded' ),
						function( index, panelNode ) {
							me._collapsePanel( $( panelNode ) );
						}
					);
				}

				$header.addClass( 'd2l-accordion-panel-expanded' );

				setTimeout( function() {
					$accordion.trigger(
						'expandPanel', {
							header: $header.get( 0 ),
							isFirstExpand: true
						}
					);
				}, 0 );

				$content
					.attr( 'aria-hidden', 'false' )
					.show();

			}

		},

		_focusPanel: function( $currentHeader, $header ) {

			if ( $header === null ) {
				return;
			}

			$currentHeader
				.attr( 'tabindex', '-1' )
				.attr( 'aria-selected', 'false' );

			$header
				.attr( 'tabindex', '0' )
				.attr( 'aria-selected', 'true' )
				.focus();

		},

		_getFirstPanelHeader: function() {
			var $headers = $( this.element )
				.find( '.d2l-accordion-header');
			return $( $headers[ 0 ] );
		},

		_getLastPanelHeader: function() {
			var $headers = $( this.element )
				.find( '.d2l-accordion-header');
			return $( $headers[ $headers.length - 1 ] );
		},

		_tryGetPreviousPanel: function( $header ) {

			var $previousElement = $header.prev();

			if ( $previousElement.length === 0 ) {
				return this._getLastPanelHeader();
			} else if ( $previousElement.hasClass( 'd2l-accordion-header' ) ) {
				return $previousElement;
			} else {
				return this._tryGetPreviousPanel( $previousElement );
			}

		},

		_tryGetNextPanel: function( $header ) {

			var $nextElement = $header.next();

			if ( $nextElement.length === 0 ) {
				return this._getFirstPanelHeader();
			} else if ( $nextElement.hasClass( 'd2l-accordion-header' ) ) {
				return $nextElement;
			} else {
				return this._tryGetNextPanel( $nextElement );
			}

		}

	} );

	$( '.d2l-accordion' ).accordion();

	$( document )
		.on(
			'vui-viewrender',
			function( evt ) {
				$( evt.target ).find( '.d2l-accordion' ).accordion();
				// TODO: handle case where evt.target needs to be applied
			}
		);

} );<|endoftext|>


<commit_before>import React from 'react';
import Layout from '../components/Layout';
import Header from '../components/Header';

export default () => (
  <Layout>

Projects

      Tamen iis do velit ingeniis. Cupidatat illum nescius, qui quamquam praesentibus.
      Eu nisi enim aliqua possumus, anim ubi senserit an labore.Ex dolor mandaremus
      excepteur. Qui export incididunt adipisicing est se anim reprehenderit. Quid
      ingeniis ex illum illum et senserit fore ea cernantur cohaerescant se aliquip eu
      iudicem ea enim arbitror instituendarum, est quae quem eram nescius, iis
      deserunt exercitation, ubi quid veniam labore nescius ita noster cernantur ita
      illum dolor.

  </Layout>
)<commit_msg>generate a basic preview of each project on the /projects page<commit_after>import React from 'react';
import Link from 'gatsby-link';
import Layout from '../components/Layout';
import Header from '../components/Header';

export default ({ data }) => (
  <Layout>

Projects

      Tamen iis do velit ingeniis. Cupidatat illum nescius, qui quamquam praesentibus.
      Eu nisi enim aliqua possumus, anim ubi senserit an labore.Ex dolor mandaremus
      excepteur. Qui export incididunt adipisicing est se anim reprehenderit. Quid
      ingeniis ex illum illum et senserit fore ea cernantur cohaerescant se aliquip eu
      iudicem ea enim arbitror instituendarum, est quae quem eram nescius, iis
      deserunt exercitation, ubi quid veniam labore nescius ita noster cernantur ita
      illum dolor.

    {
      data.allMarkdownRemark.edges
      .map(({ node: { frontmatter, fields: { slug }} }, i) => (
        <div className='project' key={`project-${i}`}>
          <Link to={`/${slug}`}>

{frontmatter.title}

          </Link>
          <Link to={`/${slug}`}>
            <img
              src={frontmatter.cover.publicURL}
              alt={`Screenshot of ${frontmatter.title}`}
            />
          </Link>

{frontmatter.description}

      ))
    }
  </Layout>
)

export const query = graphql`
  query ProjectsQuery {
    allMarkdownRemark(
      filter: { collection: { eq: "projects" } }
      sort: { fields: [frontmatter___date], order: DESC }
    ) {
      totalCount
      edges {
        node {
          frontmatter {
            date(formatString: "MMMM DD, YYYY")
            path
            title
            cover {
              publicURL
            }
            thumb
            github
            link
            description
            stack
          }
          fields {
            slug
          }
          excerpt
          collection
        }
      }
    }
  }
`;<|endoftext|>


<commit_before>'use strict';

const helpers = require('../../../helpers');
const logger = require('../../../logger');

module.exports.hasDeliveryMetadata = function hasDeliveryMetadata(body) {
  return body.metadata && body.metadata.delivery;
};

module.exports.parseDeliveryMetadataProperties = function parseDeliveryMetadataProperties(req) {
  const { queuedAt, deliveredAt, failedAt, failureData } = req.body.metadata.delivery;
  req.deliveryStatusUpdate = !!(queuedAt || deliveredAt || failedAt);
  req.deliveryFailureData = failureData;

  if (req.deliveryFailureData && req.deliveryFailureData.code) {
    // TODO: Move to request helper so it sets this prop consistent w/ other middleware
    req.undeliverableError = helpers.twilio.isUndeliverableError(req.deliveryFailureData.code);
    helpers.analytics.addCustomAttributes({
      failureData,
      undeliverableError: req.undeliverableError,
    });
    // Expose to monitor message delivery failures
    logger.info('Outbound message delivery failure', {
      code: req.deliveryFailureData.code,
      messageId: req.messageId,
    });
  }
};

module.exports.middleware = function middleware() {
  return (req, res, next) => {
    const messageId = req.params.messageId;
    req.messageId = messageId;

    if (exports.hasDeliveryMetadata(req.body)) {
      exports.parseDeliveryMetadataProperties(req);
    }

    helpers.analytics.addCustomAttributes({ messageId });
    return next();
  };
};
<commit_msg>chore (logging): log request id when logging Twilio outbound message delivery failures<commit_after>'use strict';

const helpers = require('../../../helpers');
const logger = require('../../../logger');

module.exports.hasDeliveryMetadata = function hasDeliveryMetadata(body) {
  return body.metadata && body.metadata.delivery;
};

module.exports.parseDeliveryMetadataProperties = function parseDeliveryMetadataProperties(req) {
  const { queuedAt, deliveredAt, failedAt, failureData } = req.body.metadata.delivery;
  req.deliveryStatusUpdate = !!(queuedAt || deliveredAt || failedAt);
  req.deliveryFailureData = failureData;

  if (req.deliveryFailureData && req.deliveryFailureData.code) {
    // TODO: Move to request helper so it sets this prop consistent w/ other middleware
    req.undeliverableError = helpers.twilio.isUndeliverableError(req.deliveryFailureData.code);
    helpers.analytics.addCustomAttributes({
      failureData,
      undeliverableError: req.undeliverableError,
    });
    // Expose to monitor message delivery failures
    logger.info('Outbound message delivery failure', {
      code: req.deliveryFailureData.code,
      messageId: req.messageId,
    }, req);
  }
};

module.exports.middleware = function middleware() {
  return (req, res, next) => {
    const messageId = req.params.messageId;
    req.messageId = messageId;

    if (exports.hasDeliveryMetadata(req.body)) {
      exports.parseDeliveryMetadataProperties(req);
    }

    helpers.analytics.addCustomAttributes({ messageId });
    return next();
  };
};
<|endoftext|>


<commit_before>define([
    "jquery",
    "../core/logger",
    "../registry",
    "../utils",
    "./modal"
], function($, logger, registry, utils, modal) {
    var log = logger.getLogger("form-state");

    var _ = {
        name: "form-state",
        trigger: "form.pat-form-state",
        init: function($form) {
            if ($form.length > 1)
                return $form.each(function() { _.init($(this)); });

            // XXX: hide reset buttons until we have proper handling for them
            $form.find("[type=reset]").hide();

            _.setReset.call($form);

            return $form;
        },
        setModified: function() {
            var $form = $(this);

            $form.find("[type=reset]").prop("disabled", false);
            $form.find("[type=submit]").prop("disabled", false);

            $form.addClass("modified")
                .off(".pat-form-state")
                .one("reset.pat-form-state", _.setReset)
                .one("pat-ajax-error.pat-form-state", _.setError)
                .one("pat-ajax-success.pat-form-state", _.setSaved);
            log.debug("modified");
        },
        setReset: function() {
            var $form = $(this);

            $form.find("[type=reset]").prop("disabled", true);
            $form.find("[type=submit]").prop("disabled", true);

            $form
                .removeClass("modified")
                .off(".pat-form-state")
                .one("change.pat-form-state textchange.pat-form-state",
                     _.setModified);
            log.debug("reset");
        },
        setError: function(event) {
            var msg = [event.jqxhr.status, event.jqxhr.statusText].join(" ");
            modal.init($(
                "
" +
                    "
Error
" +
                    "
" +
                    "
" +
                    "
A server error has occured.
" +
                    "
The error message is: " + msg + ".
" +
                    "
" +
                    "
" +
                    "<button class='close-panel'>Ok</button>" +
                    "
" +
                    "
" +
                    "
"
            ).appendTo($("body")));
        },
        setSaved: function(event) {
            if (event.target !== this)
                return;

            var $form = $(this);
            _.setReset.call($form);

            var time = new Date(),
                timestr = time.getHours() + ":" +
                    time.getMinutes() + ":" +
                    time.getSeconds();
            $form.find("time.last-saved").remove();
            $form.prepend(
                "<time class='last-saved' datetime='" + timestr + "'>" +
                    timestr + "</time>"
            );

            $form.addClass("saved");
        }
    };
    registry.register(_);
});
<commit_msg>Switch to input-change events.<commit_after>define([
    "jquery",
    "../core/logger",
    "../registry",
    "../utils",
    "./modal",
    "../lib/input-change-events"
], function($, logger, registry, utils, modal, input_change_events) {
    var log = logger.getLogger("form-state");

    var _ = {
        name: "form-state",
        trigger: "form.pat-form-state",
        init: function($form) {
            if ($form.length > 1)
                return $form.each(function() { _.init($(this)); });

            input_change_events.setup($form, name);

            // XXX: hide reset buttons until we have proper handling for them
            $form.find("[type=reset]").hide();

            _.setReset.call($form);

            return $form;
        },
        setModified: function() {
            var $form = $(this);

            $form.find("[type=reset]").prop("disabled", false);
            $form.find("[type=submit]").prop("disabled", false);

            $form.addClass("modified")
                .off(".pat-form-state")
                .one("reset.pat-form-state", _.setReset)
                .one("pat-ajax-error.pat-form-state", _.setError)
                .one("pat-ajax-success.pat-form-state", _.setSaved);
            log.debug("modified");
        },
        setReset: function() {
            var $form = $(this);

            $form.find("[type=reset]").prop("disabled", true);
            $form.find("[type=submit]").prop("disabled", true);

            $form
                .removeClass("modified")
                .off(".pat-form-state")
                .one("input-change.pat-form-state", _.setModified);
            log.debug("reset");
        },
        setError: function(event) {
            var msg = [event.jqxhr.status, event.jqxhr.statusText].join(" ");
            modal.init($(
                "
" +
                    "
Error
" +
                    "
" +
                    "
" +
                    "
A server error has occured.
" +
                    "
The error message is: " + msg + ".
" +
                    "
" +
                    "
" +
                    "<button class='close-panel'>Ok</button>" +
                    "
" +
                    "
" +
                    "
"
            ).appendTo($("body")));
        },
        setSaved: function(event) {
            if (event.target !== this)
                return;

            var $form = $(this);
            _.setReset.call($form);

            var time = new Date(),
                timestr = time.getHours() + ":" +
                    time.getMinutes() + ":" +
                    time.getSeconds();
            $form.find("time.last-saved").remove();
            $form.prepend(
                "<time class='last-saved' datetime='" + timestr + "'>" +
                    timestr + "</time>"
            );

            $form.addClass("saved");
        }
    };
    registry.register(_);
});
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';

foam.CLASS({
  package: 'org.chromium.webidl.ast',
  name: 'Operation',
  extends: 'org.chromium.webidl.ast.MemberData',
  implements: [
    'org.chromium.webidl.ast.Named',
    'org.chromium.webidl.ast.Returner',
    'org.chromium.webidl.ast.Parameterized',
  ],

  properties: [
    {
      class: 'FObjectArray',
      of: 'org.chromium.webidl.ast.OperationQualifier',
      name: 'qualifiers',
    },
  ],

  methods: [
    function getId() {
      return this.name ? this.name.literal : 'TEMP: REPLACE ME';
    },
    function outputWebIDL(o) {
      for (var i = 0; i < this.qualifiers.length; i++) {
        o.outputStrs(this.qualifiers[i].label, ' ');
      }
      o.outputObj(this.returnType).outputStrs(' ');
      if (this.name) o.outputObj(this.name);
      o.forEach(
        this.args, '(', ')', ','
      ).outputStrs(';');
    },
  ],
});
<commit_msg>Changes to how to handle ID for non-named Operation nodes<commit_after>// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';

foam.CLASS({
  package: 'org.chromium.webidl.ast',
  name: 'Operation',
  extends: 'org.chromium.webidl.ast.MemberData',
  implements: [
    'org.chromium.webidl.ast.Named',
    'org.chromium.webidl.ast.Returner',
    'org.chromium.webidl.ast.Parameterized',
  ],

  properties: [
    {
      class: 'FObjectArray',
      of: 'org.chromium.webidl.ast.OperationQualifier',
      name: 'qualifiers',
    },
  ],

  methods: [
    function getId() {
      // Constructor-like declarations (e.g. serializer Example()) do not have
      // names. Instead, it is set as type. Similarly, declarations with
      // qualifiers (e.g. getter, setter) do not have names either. However,
      // since IDs are not currently used at the Operation level, we return null
      return this.name ? this.name.literal : null;
    },
    function outputWebIDL(o) {
      for (var i = 0; i < this.qualifiers.length; i++) {
        o.outputStrs(this.qualifiers[i].label, ' ');
      }
      o.outputObj(this.returnType).outputStrs(' ');
      if (this.name) o.outputObj(this.name);
      o.forEach(
        this.args, '(', ')', ','
      ).outputStrs(';');
    },
  ],
});
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var util = require('util')
  , Strategy = require('passport-strategy')
  , request = require('request')
  , googleIdToken = require('google-id-token');

/**
 * Return the google certificates that will be used for signature validation.
 *
 * A custom function can be used instead when passed as an option in the Strategy
 * constructor. It can be interesting e.g. if caching is needed.
 *
 * @param {String} kid The key id specified in the token
 * @param {Function} callback
 * @api protected
 */
function getGoogleCerts(kid, callback) {
  request({uri: 'https://www.googleapis.com/oauth2/v1/certs'}, function(err, response, body) {
    if (err || !response || response.statusCode != 200) {
      err = err || 'error while retrieving the google certs';
      callback(err, {});
    } else {
      var keys = JSON.parse(body);
      callback(null, keys[kid]);
    }
  });
}

/**
 * `Strategy` constructor.
 *
 * The Google authentication strategy authenticates requests by verifying the
 * signature and fields of the token.
 *
 * Applications must supply a `verify` callback which accepts the `idToken`
 * coming from the user to be authenticated, and then calls the `done` callback
 * supplying a `parsedToken` (with all its information in visible form) and the
 * `googleId`.
 *
 * Options:
 * - `clientID` your Google application's client id
 * - `getGoogleCerts` optional custom function that returns the Google certificates
 *
 * Examples:
 *
 * passport.use(new GoogleTokenStrategy({
 *     clientID: '123-456-789',
 *     getGoogleCerts: customGetGoogleCerts
 *   },
 *   function(parsedToken, googleId, done) {
 *     User.findOrCreate(..., function (err, user) {
 *       done(err, user);
 *     });
 *   }
 * ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function GoogleTokenStrategy(options, verify) {
  if (typeof options == 'function') {
    verify = options;
    options = {};
  }

  if (!verify) throw new Error('GoogleTokenStrategy requires a verify function');

  this._passReqToCallback = options.passReqToCallback;

  this._clientID = options.clientID;
  this._getGoogleCerts = options.getGoogleCerts || getGoogleCerts;

  Strategy.call(this);
  this.name = 'google-id-token';
  this._verify = verify;
}

/**
 * Inherit from `Strategy`.
 */
util.inherits(GoogleTokenStrategy, Strategy);

/**
 * Authenticate request by verifying the token
 *
 * @param {Object} req
 * @api protected
 */
GoogleTokenStrategy.prototype.authenticate = function(req, options) {
  options = options || {};
  var self = this;

  if (req.query && req.query.error) {
    // TODO: Error information pertaining to OAuth 2.0 flows is encoded in the
    //       query parameters, and should be propagated to the application.
    return this.fail();
  }

  var idToken;

  if(req.body) {
    idToken = req.body.id_token || req.body.access_token;
  }

  idToken = idToken || req.query.id_token || req.query.access_token || req.get('id_token') || req.get('access_token');

  if (!idToken) {
    return this.fail();
  }

  var parser = new googleIdToken({ getKeys: self._getGoogleCerts });

  self._verifyGoogleToken(parser, idToken, self._clientID, function(err, parsedToken, info) {
    if (err) return self.fail(err);

    if (!parsedToken) return self.fail(info);

    function verified(err, user, info) {
      if (err) return self.error(err);
      if (!user) return self.fail(info);
      self.success(user, info);
    }

    if (self._passReqToCallback) {
      self._verify(req, parsedToken, parsedToken.data.sub, verified);
    } else {
      self._verify(parsedToken, parsedToken.data.sub, verified);
    }
  });
}

/**
 * Verify signature and token fields
 *
 * @param {String} idToken
 * @param {String} clientID
 * @param {Function} done
 * @api protected
 */
GoogleTokenStrategy.prototype._verifyGoogleToken = function(parser, idToken, clientID, done) {
  parser.decode(idToken, function(err, token) {
    if(err) {
      done(err);
    } else {
      var aud_valid = (token.data.aud === clientID);

      var exp = parseInt(token.data.exp, 10);
      var now = new Date().getTime() / 1000;

      var expired = now > exp;

      if (expired) {
        done(null, false, {message: "id_token expired"});
      } else if (!aud_valid) {
        done(null, false, {message: "id_token clientID mismatch"});
      } else {
        done(null, token);
      }
    }
  });
}

/**
 * Expose `GoogleTokenStrategy`.
 */
module.exports = GoogleTokenStrategy;
<commit_msg>Add missing check for token authenticity, pass info message for all fail cases<commit_after>/**
 * Module dependencies.
 */
var util = require('util')
  , Strategy = require('passport-strategy')
  , request = require('request')
  , googleIdToken = require('google-id-token');

/**
 * Return the google certificates that will be used for signature validation.
 *
 * A custom function can be used instead when passed as an option in the Strategy
 * constructor. It can be interesting e.g. if caching is needed.
 *
 * @param {String} kid The key id specified in the token
 * @param {Function} callback
 * @api protected
 */
function getGoogleCerts(kid, callback) {
  request({uri: 'https://www.googleapis.com/oauth2/v1/certs'}, function(err, response, body) {
    if (err || !response || response.statusCode != 200) {
      err = err || 'error while retrieving the google certs';
      callback(err, {});
    } else {
      var keys = JSON.parse(body);
      callback(null, keys[kid]);
    }
  });
}

/**
 * `Strategy` constructor.
 *
 * The Google authentication strategy authenticates requests by verifying the
 * signature and fields of the token.
 *
 * Applications must supply a `verify` callback which accepts the `idToken`
 * coming from the user to be authenticated, and then calls the `done` callback
 * supplying a `parsedToken` (with all its information in visible form) and the
 * `googleId`.
 *
 * Options:
 * - `clientID` your Google application's client id
 * - `getGoogleCerts` optional custom function that returns the Google certificates
 *
 * Examples:
 *
 * passport.use(new GoogleTokenStrategy({
 *     clientID: '123-456-789',
 *     getGoogleCerts: customGetGoogleCerts
 *   },
 *   function(parsedToken, googleId, done) {
 *     User.findOrCreate(..., function (err, user) {
 *       done(err, user);
 *     });
 *   }
 * ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function GoogleTokenStrategy(options, verify) {
  if (typeof options == 'function') {
    verify = options;
    options = {};
  }

  if (!verify) throw new Error('GoogleTokenStrategy requires a verify function');

  this._passReqToCallback = options.passReqToCallback;

  this._clientID = options.clientID;
  this._getGoogleCerts = options.getGoogleCerts || getGoogleCerts;

  Strategy.call(this);
  this.name = 'google-id-token';
  this._verify = verify;
}

/**
 * Inherit from `Strategy`.
 */
util.inherits(GoogleTokenStrategy, Strategy);

/**
 * Authenticate request by verifying the token
 *
 * @param {Object} req
 * @api protected
 */
GoogleTokenStrategy.prototype.authenticate = function(req, options) {
  options = options || {};
  var self = this;

  var idToken = (req.body && (req.body.id_token || req.body.access_token))
    || (req.query && (req.query.id_token || req.query.access_token));

  if (!idToken) {
    return self.fail({ message: "No ID token" });
  }

  var parser = new googleIdToken({ getKeys: self._getGoogleCerts });

  self._verifyGoogleToken(parser, idToken, self._clientID, function(err, parsedToken, info) {
    if (err) return self.fail({ message: err.message });

    if (!parsedToken) return self.fail(info);

    function verified(err, user, info) {
      if (err) return self.error(err);
      if (!user) return self.fail(info);
      self.success(user, info);
    }

    if (self._passReqToCallback) {
      self._verify(req, parsedToken, parsedToken.data.sub, verified);
    } else {
      self._verify(parsedToken, parsedToken.data.sub, verified);
    }
  });
}

/**
 * Verify signature and token fields
 *
 * @param {String} idToken
 * @param {String} clientID
 * @param {Function} done
 * @api protected
 */
GoogleTokenStrategy.prototype._verifyGoogleToken = function(parser, idToken, clientID, done) {
  parser.decode(idToken, function(err, token) {
    if(err) {
      done(err);
    } else {
      var aud_valid = (token.data.aud === clientID);

      var exp = parseInt(token.data.exp, 10);
      var now = new Date().getTime() / 1000;

      var expired = now > exp;

      if (!token.isAuthentic) {
        done(null, false, {message: "id_token not signed with a Google public key"});
      } else if (expired) {
        done(null, false, {message: "id_token expired"});
      } else if (!aud_valid) {
        done(null, false, {message: "id_token clientID mismatch"});
      } else {
        done(null, token);
      }
    }
  });
}

/**
 * Expose `GoogleTokenStrategy`.
 */
module.exports = GoogleTokenStrategy;
<|endoftext|>


<commit_before>define(['pex/utils/Log'], function(Log) {
  var Time = {
    now: 0,
    prev: 0,
    delta: 0,
    seconds: 0,
    frameNumber: 0,
    fpsFrames: 0,
    fpsTime: 0,
    fps: 0,
    fpsFrequency: 3,
    paused: false
  }

  Time.update = function(delta) {
    if (Time.paused) return;

    if (Time.prev == 0) {
      Time.prev = Date.now();
    }
    Time.now = Date.now();
    Time.delta = (delta !== undefined) ? delta : (Time.now - Time.prev)/1000;
    Time.prev = Time.now;
    Time.seconds += Time.delta;
    Time.fpsTime += Time.delta;
    Time.frameNumber++;
    Time.fpsFrames++;
    if (Time.fpsTime > Time.fpsFrequency) {
      Time.fps = Time.fpsFrames / Time.fpsTime;
      Time.fpsTime = 0;
      Time.fpsFrames = 0;
      Log.message('FPS: ' + Time.fps);
    }
    return Time.seconds;
  }

  var startOfMeasuredTime = 0;
  Time.startMeasuringTime = function() {
    startOfMeasuredTime = Date.now();
  }

  Time.stopMeasuringTime = function(msg) {
    var now = Date.now();

    var seconds = (now - startOfMeasuredTime)/1000;

    if (msg) {
      Log.message(msg + seconds)
    }
    return seconds;
  }

  Time.pause = function() {
    Time.paused = true;
  }

  Time.togglePause = function() {
    Time.paused = !Time.paused;
  }

  return Time;
});
<commit_msg>Disabled Timer console logs by default<commit_after>define(['pex/utils/Log'], function(Log) {
  var Time = {
    now: 0,
    prev: 0,
    delta: 0,
    seconds: 0,
    frameNumber: 0,
    fpsFrames: 0,
    fpsTime: 0,
    fps: 0,
    fpsFrequency: 3,
    paused: false,
    verbose: false
  }

  Time.update = function(delta) {
    if (Time.paused) return;

    if (Time.prev == 0) {
      Time.prev = Date.now();
    }
    Time.now = Date.now();
    Time.delta = (delta !== undefined) ? delta : (Time.now - Time.prev)/1000;
    Time.prev = Time.now;
    Time.seconds += Time.delta;
    Time.fpsTime += Time.delta;
    Time.frameNumber++;
    Time.fpsFrames++;
    if (Time.fpsTime > Time.fpsFrequency) {
      Time.fps = Time.fpsFrames / Time.fpsTime;
      Time.fpsTime = 0;
      Time.fpsFrames = 0;
      if (this.verbose) Log.message('FPS: ' + Time.fps);
    }
    return Time.seconds;
  }

  var startOfMeasuredTime = 0;
  Time.startMeasuringTime = function() {
    startOfMeasuredTime = Date.now();
  }

  Time.stopMeasuringTime = function(msg) {
    var now = Date.now();

    var seconds = (now - startOfMeasuredTime)/1000;

    if (msg) {
      Log.message(msg + seconds)
    }
    return seconds;
  }

  Time.pause = function() {
    Time.paused = true;
  }

  Time.togglePause = function() {
    Time.paused = !Time.paused;
  }

  return Time;
});
<|endoftext|>