<commit_before>import {
  filter as _filter,
  forEach as a_forEach,
  indexOf as _indexOf,
  map as _map
} from 'ember-metal/array';

var splice = Array.prototype.splice;

/**
 * Defines some convenience methods for working with Enumerables.
 * `Ember.EnumerableUtils` uses `Ember.ArrayPolyfills` when necessary.
 *
 * @class EnumerableUtils
 * @namespace Ember
 * @static
 * */

/**
 * Calls the map function on the passed object with a specified callback. This
 * uses `Ember.ArrayPolyfill`'s-map method when necessary.
 *
 * @method map
 * @param {Object} obj The object that should be mapped
 * @param {Function} callback The callback to execute
 * @param {Object} thisArg Value to use as this when executing *callback*
 *
 * @return {Array} An array of mapped values.
 */
export function map(obj, callback, thisArg) {
  return obj.map ? obj.map.call(obj, callback, thisArg) : _map.call(obj, callback, thisArg);
}

/**
 * Calls the forEach function on the passed object with a specified callback. This
 * uses `Ember.ArrayPolyfill`'s-forEach method when necessary.
 *
 * @method forEach
 * @param {Object} obj The object to call forEach on
 * @param {Function} callback The callback to execute
 * @param {Object} thisArg Value to use as this when executing *callback*
 *
 */
export function forEach(obj, callback, thisArg) {
  return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : a_forEach.call(obj, callback, thisArg);
}

/**
 * Calls the filter function on the passed object with a specified callback. This
 * uses `Ember.ArrayPolyfill`'s-filter method when necessary.
 *
 * @method filter
 * @param {Object} obj The object to call filter on
 * @param {Function} callback The callback to execute
 * @param {Object} thisArg Value to use as this when executing *callback*
 *
 * @return {Array} An array containing the filtered values
 * @since 1.4.0
 */
export function filter(obj, callback, thisArg) {
  return obj.filter ? obj.filter.call(obj, callback, thisArg) : _filter.call(obj, callback, thisArg);
}

/**
 * Calls the indexOf function on the passed object with a specified callback. This
 * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary.
 *
 * @method indexOf
 * @param {Object} obj The object to call indexOn on
 * @param {Function} callback The callback to execute
 * @param {Object} index The index to start searching from
 *
 */
export function indexOf(obj, element, index) {
  return obj.indexOf ? obj.indexOf.call(obj, element, index) : _indexOf.call(obj, element, index);
}

/**
 * Returns an array of indexes of the first occurrences of the passed elements
 * on the passed object.
 *
 * ```javascript
 *  var array = [1, 2, 3, 4, 5];
 *  Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4]
 *
 *  var fubar = "Fubarr";
 *  Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4]
 * ```
 *
 * @method indexesOf
 * @param {Object} obj The object to check for element indexes
 * @param {Array} elements The elements to search for on *obj*
 *
 * @return {Array} An array of indexes.
 *
 */
export function indexesOf(obj, elements) {
  return elements === undefined ? [] : map(elements, function(item) {
    return indexOf(obj, item);
  });
}

/**
 * Adds an object to an array. If the array already includes the object this
 * method has no effect.
 *
 * @method addObject
 * @param {Array} array The array the passed item should be added to
 * @param {Object} item The item to add to the passed array
 *
 * @return 'undefined'
 */
export function addObject(array, item) {
  var index = indexOf(array, item);
  if (index === -1) { array.push(item); }
}

/**
 * Removes an object from an array. If the array does not contain the passed
 * object this method has no effect.
 *
 * @method removeObject
 * @param {Array} array The array to remove the item from.
 * @param {Object} item The item to remove from the passed array.
 *
 * @return 'undefined'
 */
export function removeObject(array, item) {
  var index = indexOf(array, item);
  if (index !== -1) { array.splice(index, 1); }
}

export function _replace(array, idx, amt, objects) {
  var args = [].concat(objects);
  var ret = [];
  // https://code.google.com/p/chromium/issues/detail?id=56588
  var size = 60000;
  var start = idx;
  var ends = amt;
  var count, chunk;

  while (args.length) {
    count = ends > size ? size : ends;
    if (count <= 0) { count = 0; }

    chunk = args.splice(0, size);
    chunk = [start, count].concat(chunk);

    start += size;
    ends -= count;

    ret = ret.concat(splice.apply(array, chunk));
  }
  return ret;
}

/**
 * Replaces objects in an array with the passed objects.
 *
 * ```javascript
 *   var array = [1,2,3];
 *   Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5]
 *
 *   var array = [1,2,3];
 *   Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3]
 *
 *   var array = [1,2,3];
 *   Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5]
 * ```
 *
 * @method replace
 * @param {Array} array The array the objects should be inserted into.
 * @param {Number} idx Starting index in the array to replace. If *idx* >=
 * length, then append to the end of the array.
 * @param {Number} amt Number of elements that should be removed from the array,
 * starting at *idx*
 * @param {Array} objects An array of zero or more objects that should be
 * inserted into the array at *idx*
 *
 * @return {Array} The modified array.
 */
export function replace(array, idx, amt, objects) {
  if (array.replace) {
    return array.replace(idx, amt, objects);
  } else {
    return _replace(array, idx, amt, objects);
  }
}

/**
 * Calculates the intersection of two arrays. This method returns a new array
 * filled with the records that the two passed arrays share with each other.
 * If there is no intersection, an empty array will be returned.
 *
 * ```javascript
 * var array1 = [1, 2, 3, 4, 5];
 * var array2 = [1, 3, 5, 6, 7];
 *
 * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5]
 *
 * var array1 = [1, 2, 3];
 * var array2 = [4, 5, 6];
 *
 * Ember.EnumerableUtils.intersection(array1, array2); // []
 * ```
 *
 * @method intersection
 * @param {Array} array1 The first array
 * @param {Array} array2 The second array
 *
 * @return {Array} The intersection of the two passed arrays.
 */
export function intersection(array1, array2) {
  var result = [];
  forEach(array1, function(element) {
    if (indexOf(array2, element) >= 0) {
      result.push(element);
    }
  });

  return result;
}

// TODO: this only exists to maintain the existing api, as we move forward it
// should only be part of the "global build" via some shim
export default {
  _replace: _replace,
  addObject: addObject,
  filter: filter,
  forEach: forEach,
  indexOf: indexOf,
  indexesOf: indexesOf,
  intersection: intersection,
  map: map,
  removeObject: removeObject,
  replace: replace
};
<commit_msg>[Bugfix beta] if the obj already has the method, don’t bother using call<commit_after>import {
  filter as _filter,
  forEach as a_forEach,
  indexOf as _indexOf,
  map as _map
} from 'ember-metal/array';

var splice = Array.prototype.splice;

/**
 * Defines some convenience methods for working with Enumerables.
 * `Ember.EnumerableUtils` uses `Ember.ArrayPolyfills` when necessary.
 *
 * @class EnumerableUtils
 * @namespace Ember
 * @static
 * */

/**
 * Calls the map function on the passed object with a specified callback. This
 * uses `Ember.ArrayPolyfill`'s-map method when necessary.
 *
 * @method map
 * @param {Object} obj The object that should be mapped
 * @param {Function} callback The callback to execute
 * @param {Object} thisArg Value to use as this when executing *callback*
 *
 * @return {Array} An array of mapped values.
 */
export function map(obj, callback, thisArg) {
  return obj.map ? obj.map(callback, thisArg) : _map.call(obj, callback, thisArg);
}

/**
 * Calls the forEach function on the passed object with a specified callback. This
 * uses `Ember.ArrayPolyfill`'s-forEach method when necessary.
 *
 * @method forEach
 * @param {Object} obj The object to call forEach on
 * @param {Function} callback The callback to execute
 * @param {Object} thisArg Value to use as this when executing *callback*
 *
 */
export function forEach(obj, callback, thisArg) {
  return obj.forEach ? obj.forEach(callback, thisArg) : a_forEach.call(obj, callback, thisArg);
}

/**
 * Calls the filter function on the passed object with a specified callback. This
 * uses `Ember.ArrayPolyfill`'s-filter method when necessary.
 *
 * @method filter
 * @param {Object} obj The object to call filter on
 * @param {Function} callback The callback to execute
 * @param {Object} thisArg Value to use as this when executing *callback*
 *
 * @return {Array} An array containing the filtered values
 * @since 1.4.0
 */
export function filter(obj, callback, thisArg) {
  return obj.filter ? obj.filter(callback, thisArg) : _filter.call(obj, callback, thisArg);
}

/**
 * Calls the indexOf function on the passed object with a specified callback. This
 * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary.
 *
 * @method indexOf
 * @param {Object} obj The object to call indexOn on
 * @param {Function} callback The callback to execute
 * @param {Object} index The index to start searching from
 *
 */
export function indexOf(obj, element, index) {
  return obj.indexOf ? obj.indexOf(element, index) : _indexOf.call(obj, element, index);
}

/**
 * Returns an array of indexes of the first occurrences of the passed elements
 * on the passed object.
 *
 * ```javascript
 *  var array = [1, 2, 3, 4, 5];
 *  Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4]
 *
 *  var fubar = "Fubarr";
 *  Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4]
 * ```
 *
 * @method indexesOf
 * @param {Object} obj The object to check for element indexes
 * @param {Array} elements The elements to search for on *obj*
 *
 * @return {Array} An array of indexes.
 *
 */
export function indexesOf(obj, elements) {
  return elements === undefined ? [] : map(elements, function(item) {
    return indexOf(obj, item);
  });
}

/**
 * Adds an object to an array. If the array already includes the object this
 * method has no effect.
 *
 * @method addObject
 * @param {Array} array The array the passed item should be added to
 * @param {Object} item The item to add to the passed array
 *
 * @return 'undefined'
 */
export function addObject(array, item) {
  var index = indexOf(array, item);
  if (index === -1) { array.push(item); }
}

/**
 * Removes an object from an array. If the array does not contain the passed
 * object this method has no effect.
 *
 * @method removeObject
 * @param {Array} array The array to remove the item from.
 * @param {Object} item The item to remove from the passed array.
 *
 * @return 'undefined'
 */
export function removeObject(array, item) {
  var index = indexOf(array, item);
  if (index !== -1) { array.splice(index, 1); }
}

export function _replace(array, idx, amt, objects) {
  var args = [].concat(objects);
  var ret = [];
  // https://code.google.com/p/chromium/issues/detail?id=56588
  var size = 60000;
  var start = idx;
  var ends = amt;
  var count, chunk;

  while (args.length) {
    count = ends > size ? size : ends;
    if (count <= 0) { count = 0; }

    chunk = args.splice(0, size);
    chunk = [start, count].concat(chunk);

    start += size;
    ends -= count;

    ret = ret.concat(splice.apply(array, chunk));
  }
  return ret;
}

/**
 * Replaces objects in an array with the passed objects.
 *
 * ```javascript
 *   var array = [1,2,3];
 *   Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5]
 *
 *   var array = [1,2,3];
 *   Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3]
 *
 *   var array = [1,2,3];
 *   Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5]
 * ```
 *
 * @method replace
 * @param {Array} array The array the objects should be inserted into.
 * @param {Number} idx Starting index in the array to replace. If *idx* >=
 * length, then append to the end of the array.
 * @param {Number} amt Number of elements that should be removed from the array,
 * starting at *idx*
 * @param {Array} objects An array of zero or more objects that should be
 * inserted into the array at *idx*
 *
 * @return {Array} The modified array.
 */
export function replace(array, idx, amt, objects) {
  if (array.replace) {
    return array.replace(idx, amt, objects);
  } else {
    return _replace(array, idx, amt, objects);
  }
}

/**
 * Calculates the intersection of two arrays. This method returns a new array
 * filled with the records that the two passed arrays share with each other.
 * If there is no intersection, an empty array will be returned.
 *
 * ```javascript
 * var array1 = [1, 2, 3, 4, 5];
 * var array2 = [1, 3, 5, 6, 7];
 *
 * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5]
 *
 * var array1 = [1, 2, 3];
 * var array2 = [4, 5, 6];
 *
 * Ember.EnumerableUtils.intersection(array1, array2); // []
 * ```
 *
 * @method intersection
 * @param {Array} array1 The first array
 * @param {Array} array2 The second array
 *
 * @return {Array} The intersection of the two passed arrays.
 */
export function intersection(array1, array2) {
  var result = [];
  forEach(array1, function(element) {
    if (indexOf(array2, element) >= 0) {
      result.push(element);
    }
  });

  return result;
}

// TODO: this only exists to maintain the existing api, as we move forward it
// should only be part of the "global build" via some shim
export default {
  _replace: _replace,
  addObject: addObject,
  filter: filter,
  forEach: forEach,
  indexOf: indexOf,
  indexesOf: indexesOf,
  intersection: intersection,
  map: map,
  removeObject: removeObject,
  replace: replace
};
<|endoftext|>


<commit_before>'use strict';

const retry = require('bluebird-retry');
const get = require('lodash/get');
const toString = require('lodash/toString');
const parseError = require('@terascope/error-parser');
const { makeLogger } = require('../helpers/terafoundation');
const { logOpStats } = require('../helpers/op-analytics');
const { prependErrorMsg } = require('../../utils/error_utils');

class Slice {
    constructor(context, executionContext) {
        this.context = context;
        this.events = context.apis.foundation.getSystemEvents();
        this.executionContext = executionContext;
    }

    async initialize(slice, stores) {
        const { slice_id: sliceId } = slice;

        this.stateStore = stores.stateStore;
        this.analyticsStore = stores.analyticsStore;
        this.slice = slice;
        this.logger = makeLogger(this.context, this.executionContext, 'slice', { slice_id: sliceId });

        this.events.emit('slice:initialize', slice);
        await this.executionContext.onSliceInitialized(sliceId);
    }

    async run() {
        if (this._isShutdown) throw new Error('Slice is already shutdown');

        const { slice } = this;
        const maxRetries = get(this.executionContext, 'config.max_retries', 3);
        const maxTries = maxRetries > 0 ? maxRetries + 1 : 0;
        const retryOptions = {
            max_tries: maxTries,
            throw_original: true,
            interval: 100,
            backoff: 2
        };

        let result;
        let remaining = maxTries;
        let sliceSuccess = false;

        try {
            result = await retry(() => {
                remaining -= 1;
                return this._runOnce(remaining > 0);
            }, retryOptions);

            sliceSuccess = true;
            await this._markCompleted();
        } catch (err) {
            // avoid incorrectly marking
            // the slice as failed when it fails
            // to mark it as "complete"
            if (!sliceSuccess) {
                await this._markFailed(err);
            }
            throw err;
        } finally {
            await this._logAnalytics(result && result.analytics);
            this.events.emit('slice:finalize', slice);
            await this.executionContext.onSliceFinalizing(slice.slice_id);
        }

        return result.results;
    }

    async shutdown() {
        this._isShutdown = true;
    }

    async _logAnalytics(analyticsData) {
        if (analyticsData == null) return;
        this.analyticsData = analyticsData;

        const {
            logger,
            slice,
            executionContext
        } = this;

        logOpStats(logger, slice, analyticsData);

        try {
            await this.analyticsStore.log(executionContext, slice, analyticsData);
        } catch (_err) {
            throw new Error(prependErrorMsg('Failure to update analytics', _err));
        }
    }

    async _markCompleted() {
        const { slice } = this;

        try {
            await this.stateStore.updateState(slice, 'completed');
        } catch (_err) {
            const err = new Error(prependErrorMsg('Failure to update success state', _err));
            err.fatalError = true;
            throw err;
        }

        this.events.emit('slice:success', slice);

        this.logger.trace(`completed slice for execution: ${this.executionContext.exId}`, slice);
    }

    async _markFailed(err) {
        const {
            stateStore,
            slice,
            logger
        } = this;

        const errMsg = err ? parseError(err) : new Error('Unknown error occurred');

        try {
            await stateStore.updateState(slice, 'error', errMsg);
        } catch (_err) {
            const error = new Error(prependErrorMsg('Failure to update failed state', _err));
            error.fatalError = true;
            throw error;
        }

        logger.error(err, `slice state for ${this.executionContext.exId} has been marked as error`);

        this.events.emit('slice:failure', slice);
        await this.executionContext.onSliceFailed(slice.slice_id);

        if (err instanceof retry.StopError) {
            const stopError = new Error(err.message);
            throw stopError;
        }

        const sliceError = new Error(prependErrorMsg('Slice failed processing', err, true));
        sliceError.alreadyLogged = true;
        throw sliceError;
    }

    async _runOnce(shouldRetry) {
        if (this._isShutdown) {
            throw new retry.StopError('Slice shutdown during slice execution');
        }

        try {
            return await this.executionContext.runSlice(this.slice);
        } catch (err) {
            this.logger.error(`An error has occurred: ${toString(err)}, slice:`, this.slice);

            if (shouldRetry) {
                try {
                    // for backwards compatibility
                    this.events.emit('slice:retry', this.slice);

                    await this.executionContext.onSliceRetry(this.slice.slice_id);
                } catch (retryErr) {
                    throw new retry.StopError(`Slice failed to retry: ${toString(retryErr)}, caused by: ${toString(err)}`);
                }
            }

            throw err;
        }
    }
}

module.exports = Slice;
<commit_msg>Disable fatalError on state updates<commit_after>'use strict';

const retry = require('bluebird-retry');
const get = require('lodash/get');
const toString = require('lodash/toString');
const parseError = require('@terascope/error-parser');
const { makeLogger } = require('../helpers/terafoundation');
const { logOpStats } = require('../helpers/op-analytics');
const { prependErrorMsg } = require('../../utils/error_utils');

class Slice {
    constructor(context, executionContext) {
        this.context = context;
        this.events = context.apis.foundation.getSystemEvents();
        this.executionContext = executionContext;
    }

    async initialize(slice, stores) {
        const { slice_id: sliceId } = slice;

        this.stateStore = stores.stateStore;
        this.analyticsStore = stores.analyticsStore;
        this.slice = slice;
        this.logger = makeLogger(this.context, this.executionContext, 'slice', { slice_id: sliceId });

        this.events.emit('slice:initialize', slice);
        await this.executionContext.onSliceInitialized(sliceId);
    }

    async run() {
        if (this._isShutdown) throw new Error('Slice is already shutdown');

        const { slice } = this;
        const maxRetries = get(this.executionContext, 'config.max_retries', 3);
        const maxTries = maxRetries > 0 ? maxRetries + 1 : 0;
        const retryOptions = {
            max_tries: maxTries,
            throw_original: true,
            interval: 100,
            backoff: 2
        };

        let result;
        let remaining = maxTries;
        let sliceSuccess = false;

        try {
            result = await retry(() => {
                remaining -= 1;
                return this._runOnce(remaining > 0);
            }, retryOptions);

            sliceSuccess = true;
            await this._markCompleted();
        } catch (err) {
            // avoid incorrectly marking
            // the slice as failed when it fails
            // to mark it as "complete"
            if (!sliceSuccess) {
                await this._markFailed(err);
            }
            throw err;
        } finally {
            await this._logAnalytics(result && result.analytics);
            this.events.emit('slice:finalize', slice);
            await this.executionContext.onSliceFinalizing(slice.slice_id);
        }

        return result.results;
    }

    async shutdown() {
        this._isShutdown = true;
    }

    async _logAnalytics(analyticsData) {
        if (analyticsData == null) return;
        this.analyticsData = analyticsData;

        const {
            logger,
            slice,
            executionContext
        } = this;

        logOpStats(logger, slice, analyticsData);

        try {
            await this.analyticsStore.log(executionContext, slice, analyticsData);
        } catch (_err) {
            throw new Error(prependErrorMsg('Failure to update analytics', _err));
        }
    }

    async _markCompleted() {
        const { slice } = this;

        try {
            await this.stateStore.updateState(slice, 'completed');
        } catch (_err) {
            const err = new Error(prependErrorMsg('Failure to update success state', _err));
            // set fatalError = true to shutdown worker
            // error.fatalError = true;
            throw err;
        }

        this.events.emit('slice:success', slice);

        this.logger.trace(`completed slice for execution: ${this.executionContext.exId}`, slice);
    }

    async _markFailed(err) {
        const {
            stateStore,
            slice,
            logger
        } = this;

        const errMsg = err ? parseError(err) : new Error('Unknown error occurred');

        try {
            await stateStore.updateState(slice, 'error', errMsg);
        } catch (_err) {
            const error = new Error(prependErrorMsg('Failure to update failed state', _err));
            // set fatalError = true to shutdown worker
            // error.fatalError = true;
            throw error;
        }

        logger.error(err, `slice state for ${this.executionContext.exId} has been marked as error`);

        this.events.emit('slice:failure', slice);
        await this.executionContext.onSliceFailed(slice.slice_id);

        if (err instanceof retry.StopError) {
            const stopError = new Error(err.message);
            throw stopError;
        }

        const sliceError = new Error(prependErrorMsg('Slice failed processing', err, true));
        sliceError.alreadyLogged = true;
        throw sliceError;
    }

    async _runOnce(shouldRetry) {
        if (this._isShutdown) {
            throw new retry.StopError('Slice shutdown during slice execution');
        }

        try {
            return await this.executionContext.runSlice(this.slice);
        } catch (err) {
            this.logger.error(`An error has occurred: ${toString(err)}, slice:`, this.slice);

            if (shouldRetry) {
                try {
                    // for backwards compatibility
                    this.events.emit('slice:retry', this.slice);

                    await this.executionContext.onSliceRetry(this.slice.slice_id);
                } catch (retryErr) {
                    throw new retry.StopError(`Slice failed to retry: ${toString(retryErr)}, caused by: ${toString(err)}`);
                }
            }

            throw err;
        }
    }
}

module.exports = Slice;
<|endoftext|>


<commit_before>const {toGeometry, toFeatureCollection} = require('sepal/ee/aoi')
const {allScenes, hasImagery} = require('sepal/ee/optical/collection')
const {calculateIndex} = require('sepal/ee/optical/indexes')
const tile = require('sepal/ee/tile')
const {exportImageToSepal$} = require('root/ee/export/toSepal')
const {mkdirSafe$} = require('root/rxjs/fileSystem')
const {concat, forkJoin, from, of} = require('rx')
const Path = require('path')
const {map, mergeMap, scan, switchMap, tap} = require('rx/operators')
const {swallow} = require('sepal/rxjs/operators')
const {terminal$} = require('sepal/terminal')
const {sequence} = require('sepal/utils/array')
const moment = require('moment')
const ee = require('ee')
const {getConfig} = require('root/context')
const log = require('sepal/log').getLogger('task')

const TILE_DEGREES = 2
const EE_EXPORT_SHARD_SIZE = 256
const EE_EXPORT_FILE_DIMENSIONS = 1024
const DATE_DELTA = 2
const DATE_DELTA_UNIT = 'months'

const config = getConfig()

module.exports = {
    submit$: (id, recipe) => {
        const preferredDownloadDir = `${config.homeDir}/downloads/${recipe.description}/`
        return mkdirSafe$(preferredDownloadDir, {recursive: true}).pipe(
            switchMap(downloadDir =>
                export$(downloadDir, recipe)
            )
        )
    },
}

const export$ = (downloadDir, recipe) => {
    const {
        description, aoi, dataSets, surfaceReflectance, cloudMasking,
        cloudBuffer, snowMasking, calibrate, brdfCorrect, fromDate, toDate, indicator,
        scale
    } = recipe

    const geometry = toGeometry(aoi) // synchronous EE
    const reflectance = surfaceReflectance ? 'SR' : 'TOA'
    const dates = {
        seasonStart: fromDate,
        seasonEnd: toDate
    }

    const tiles = tile(toFeatureCollection(aoi), TILE_DEGREES) // synchronous EE

    const exportTiles$ = tileIds => {
        const totalTiles = tileIds.length
        const tile$ = from(
            tileIds.map((tileId, tileIndex) =>
                ({tileId, tileIndex})
            )
        )
        return concat(
            of({totalTiles}),
            tile$.pipe(
                mergeMap(tile => exportTile$(tile), 1)
            )
        )
    }
    const exportTile$ = ({tileId, tileIndex}) =>
        concat(
            of({tileIndex, chunks: 0}),
            exportChunks$(createChunks$({tileId, tileIndex})),
            postProcess$(Path.join(downloadDir, `${tileIndex}`))
        )

    const createChunks$ = ({tileId, tileIndex}) => {
        const tile = tiles.filterMetadata('system:index', 'equals', tileId).first()
        const from = moment(fromDate)
        const to = moment(toDate)
        const duration = moment(to).subtract(1, 'day').diff(from, DATE_DELTA_UNIT)
        const dateOffsets = sequence(0, duration, DATE_DELTA)
        const chunks$ = dateOffsets.map(dateOffset => {
            const start = moment(from).add(dateOffset, DATE_DELTA_UNIT)
            const end = moment.min(moment(start).add(DATE_DELTA, DATE_DELTA_UNIT), to)
            const timeSeries = createTimeSeries(tile, start, end)
            const dateRange = `${start.format('YYYY-MM-DD')}_${end.format('YYYY-MM-DD')}`
            const notEmpty$ = hasImagery$(
                ee.Date(start.format('YYYY-MM-DD')),
                ee.Date(end.format('YYYY-MM-DD'))
            )
            return notEmpty$.pipe(
                map(notEmpty => ({tileIndex, timeSeries, dateRange, notEmpty}))
            )
        })
        return forkJoin(chunks$)
    }

    const createTimeSeries = (feature, startDate, endDate) => {
        const images = allScenes({
            geometry: feature.geometry(),
            dataSets,
            reflectance,
            filters: [],
            cloudMasking,
            cloudBuffer,
            snowMasking,
            panSharpen: false,
            calibrate,
            brdfCorrect,
            dates: {
                seasonStart: startDate.format('YYYY-MM-DD'),
                seasonEnd: endDate.format('YYYY-MM-DD')
            }
        }).map(image =>
            calculateIndex(image, indicator)
                .set('date', image.date().format('yyyy-MM-dd'))
        )
        const distinctDateImages = images.distinct('date')
        const timeSeries = ee.ImageCollection(
            ee.Join.saveAll('images')
                .apply({
                    primary: distinctDateImages,
                    secondary: images,
                    condition: ee.Filter.equals({
                        leftField: 'date',
                        rightField: 'date'
                    })
                })
                .map(image => ee.ImageCollection(ee.List(image.get('images')))
                    .median()
                    .rename(image.getString('date'))
                ))
            .toBands()
            .regexpRename('.*(.{10})', '$1')
            .clip(feature.geometry())
        return timeSeries.select(timeSeries.bandNames().sort())
    }

    const hasImagery$ = (startDate, endDate) =>
        ee.getInfo$(hasImagery({dataSets, reflectance, geometry, startDate, endDate}), 'check if date range has imagery')

    const exportChunks$ = chunks$ =>
        chunks$.pipe(
            switchMap(chunks => {
                const nonEmptyChunks = chunks.filter(({notEmpty}) => notEmpty)
                const totalChunks = nonEmptyChunks.length
                return concat(
                    of({totalChunks}),
                    from(nonEmptyChunks).pipe(
                        mergeMap(chunk => exportChunk$(chunk))
                    )
                )
            })
        )

    const exportChunk$ = ({tileIndex, timeSeries, dateRange}) => {
        const chunkDescription = `${description}_${tileIndex}_${dateRange}`
        const chunkDownloadDir = `${downloadDir}/${tileIndex}/chunk-${dateRange}`
        const export$ = exportImageToSepal$({
            // imageDef,
            image: timeSeries,
            folder: chunkDescription,
            description: chunkDescription,
            downloadDir: chunkDownloadDir,
            scale,
            crs: 'EPSG:4326',
            shardSize: EE_EXPORT_SHARD_SIZE,
            fileDimensions: EE_EXPORT_FILE_DIMENSIONS
        }).pipe(swallow())
        return concat(
            export$,
            of({completedChunk: true})
        )
    }

    const tileIds$ = ee.getInfo$(tiles.aggregate_array('system:index'), 'time-series image ids')

    return tileIds$.pipe(
        switchMap(tileIds => exportTiles$(tileIds)),
        tap(progress => log.trace(`time-series: ${JSON.stringify(progress)}`)),
        scan(
            (acc, progress) => {
                return ({
                    ...acc,
                    ...progress,
                    chunks: progress.chunks === undefined
                        ? acc.chunks + (progress.completedChunk ? 1 : 0)
                        : progress.chunks
                })
            },
            {tileIndex: 0, chunks: 0}
        ),
        map(toProgress)
    )
}

const postProcess$ = downloadDir =>
    terminal$('sepal-stack-time-series', [downloadDir])
        .pipe(swallow())

const toProgress = ({totalTiles = 0, tileIndex = 0, totalChunks = 0, chunks = 0}) => {
    const currentTilePercent = totalChunks ? Math.round(100 * chunks / totalChunks) : 0
    const currentTile = tileIndex + 1
    return {
        totalChunks,
        chunks,
        totalTiles,
        tileIndex,
        defaultMessage: `Exported ${currentTilePercent}% of tile ${currentTile} out of ${totalTiles}.`,
        messageKey: 'tasks.retrieve.time_series_to_sepal.progress',
        messageArgs: {currentTilePercent, currentTile, totalTiles}
    }
}
<commit_msg>Made sure all time-series tiles get stacked.<commit_after>const {toGeometry, toFeatureCollection} = require('sepal/ee/aoi')
const {allScenes, hasImagery} = require('sepal/ee/optical/collection')
const {calculateIndex} = require('sepal/ee/optical/indexes')
const tile = require('sepal/ee/tile')
const {exportImageToSepal$} = require('root/ee/export/toSepal')
const {mkdirSafe$} = require('root/rxjs/fileSystem')
const {concat, forkJoin, from, of} = require('rx')
const Path = require('path')
const {map, mergeMap, scan, switchMap, tap} = require('rx/operators')
const {swallow} = require('sepal/rxjs/operators')
const {terminal$} = require('sepal/terminal')
const {sequence} = require('sepal/utils/array')
const moment = require('moment')
const ee = require('ee')
const {getConfig} = require('root/context')
const log = require('sepal/log').getLogger('task')

const TILE_DEGREES = 2
const EE_EXPORT_SHARD_SIZE = 256
const EE_EXPORT_FILE_DIMENSIONS = 1024
const DATE_DELTA = 2
const DATE_DELTA_UNIT = 'months'

const config = getConfig()

module.exports = {
    submit$: (id, recipe) => {
        const preferredDownloadDir = `${config.homeDir}/downloads/${recipe.description}/`
        return mkdirSafe$(preferredDownloadDir, {recursive: true}).pipe(
            switchMap(downloadDir =>
                export$(downloadDir, recipe)
            )
        )
    },
}

const export$ = (downloadDir, recipe) => {
    const {
        description, aoi, dataSets, surfaceReflectance, cloudMasking,
        cloudBuffer, snowMasking, calibrate, brdfCorrect, fromDate, toDate, indicator,
        scale
    } = recipe

    const geometry = toGeometry(aoi) // synchronous EE
    const reflectance = surfaceReflectance ? 'SR' : 'TOA'
    const dates = {
        seasonStart: fromDate,
        seasonEnd: toDate
    }

    const tiles = tile(toFeatureCollection(aoi), TILE_DEGREES) // synchronous EE

    const exportTiles$ = tileIds => {
        const totalTiles = tileIds.length
        const tile$ = from(
            tileIds.map((tileId, tileIndex) =>
                ({tileId, tileIndex})
            )
        )
        return concat(
            of({totalTiles}),
            tile$.pipe(
                mergeMap(tile => exportTile$(tile), 1)
            )
        )
    }
    const exportTile$ = ({tileId, tileIndex}) =>
        concat(
            of({tileIndex, chunks: 0}),
            exportChunks$(createChunks$({tileId, tileIndex})),
            postProcess$(Path.join(downloadDir, `${tileIndex}`))
        )

    const createChunks$ = ({tileId, tileIndex}) => {
        const tile = tiles.filterMetadata('system:index', 'equals', tileId).first()
        const from = moment(fromDate)
        const to = moment(toDate)
        const duration = moment(to).subtract(1, 'day').diff(from, DATE_DELTA_UNIT)
        const dateOffsets = sequence(0, duration, DATE_DELTA)
        const chunks$ = dateOffsets.map(dateOffset => {
            const start = moment(from).add(dateOffset, DATE_DELTA_UNIT)
            const end = moment.min(moment(start).add(DATE_DELTA, DATE_DELTA_UNIT), to)
            const timeSeries = createTimeSeries(tile, start, end)
            const dateRange = `${start.format('YYYY-MM-DD')}_${end.format('YYYY-MM-DD')}`
            const notEmpty$ = hasImagery$(
                ee.Date(start.format('YYYY-MM-DD')),
                ee.Date(end.format('YYYY-MM-DD'))
            )
            return notEmpty$.pipe(
                map(notEmpty => ({tileIndex, timeSeries, dateRange, notEmpty}))
            )
        })
        return forkJoin(chunks$)
    }

    const createTimeSeries = (feature, startDate, endDate) => {
        const images = allScenes({
            geometry: feature.geometry(),
            dataSets,
            reflectance,
            filters: [],
            cloudMasking,
            cloudBuffer,
            snowMasking,
            panSharpen: false,
            calibrate,
            brdfCorrect,
            dates: {
                seasonStart: startDate.format('YYYY-MM-DD'),
                seasonEnd: endDate.format('YYYY-MM-DD')
            }
        }).map(image =>
            calculateIndex(image, indicator)
                .set('date', image.date().format('yyyy-MM-dd'))
        )
        const distinctDateImages = images.distinct('date')
        const timeSeries = ee.ImageCollection(
            ee.Join.saveAll('images')
                .apply({
                    primary: distinctDateImages,
                    secondary: images,
                    condition: ee.Filter.equals({
                        leftField: 'date',
                        rightField: 'date'
                    })
                })
                .map(image => ee.ImageCollection(ee.List(image.get('images')))
                    .median()
                    .rename(image.getString('date'))
                ))
            .toBands()
            .regexpRename('.*(.{10})', '$1')
            .clip(feature.geometry())
        return timeSeries.select(timeSeries.bandNames().sort())
    }

    const hasImagery$ = (startDate, endDate) =>
        ee.getInfo$(hasImagery({dataSets, reflectance, geometry, startDate, endDate}), 'check if date range has imagery')

    const exportChunks$ = chunks$ =>
        chunks$.pipe(
            switchMap(chunks => {
                const nonEmptyChunks = chunks.filter(({notEmpty}) => notEmpty)
                const totalChunks = nonEmptyChunks.length
                return concat(
                    of({totalChunks}),
                    from(nonEmptyChunks).pipe(
                        mergeMap(chunk => exportChunk$(chunk))
                    )
                )
            })
        )

    const exportChunk$ = ({tileIndex, timeSeries, dateRange}) => {
        const chunkDescription = `${description}_${tileIndex}_${dateRange}`
        const chunkDownloadDir = `${downloadDir}/${tileIndex}/chunk-${dateRange}`
        const export$ = exportImageToSepal$({
            // imageDef,
            image: timeSeries,
            folder: chunkDescription,
            description: chunkDescription,
            downloadDir: chunkDownloadDir,
            scale,
            crs: 'EPSG:4326',
            shardSize: EE_EXPORT_SHARD_SIZE,
            fileDimensions: EE_EXPORT_FILE_DIMENSIONS
        }).pipe(swallow())
        return concat(
            export$,
            of({completedChunk: true})
        )
    }

    const tileIds$ = ee.getInfo$(tiles.aggregate_array('system:index'), 'time-series image ids')

    return tileIds$.pipe(
        switchMap(tileIds => exportTiles$(tileIds)),
        tap(progress => log.trace(`time-series: ${JSON.stringify(progress)}`)),
        scan(
            (acc, progress) => {
                return ({
                    ...acc,
                    ...progress,
                    chunks: progress.chunks === undefined
                        ? acc.chunks + (progress.completedChunk ? 1 : 0)
                        : progress.chunks
                })
            },
            {tileIndex: 0, chunks: 0}
        ),
        map(toProgress)
    )
}

const postProcess$ = downloadDir =>
    terminal$('sepal-stack-time-series', [Path.join(downloadDir, '*')])
        .pipe(swallow())

const toProgress = ({totalTiles = 0, tileIndex = 0, totalChunks = 0, chunks = 0}) => {
    const currentTilePercent = totalChunks ? Math.round(100 * chunks / totalChunks) : 0
    const currentTile = tileIndex + 1
    return {
        totalChunks,
        chunks,
        totalTiles,
        tileIndex,
        defaultMessage: `Exported ${currentTilePercent}% of tile ${currentTile} out of ${totalTiles}.`,
        messageKey: 'tasks.retrieve.time_series_to_sepal.progress',
        messageArgs: {currentTilePercent, currentTile, totalTiles}
    }
}
<|endoftext|>


<commit_before>var session = require("zed/session");
var config = require("zed/config");

module.exports = function(options, callback) {
    config.getPreference("trimEmptyLines", function getPrefs(err, trimEmpty) {
        var min = trimEmpty ? -1 : 0;

        session.getCursorPosition(options.path, function getCurrentLine(err, cursor) {
            var currentLine = cursor.row;

            session.getAllLines(options.path, function trimWhitespace(err, lines) {
                // Strip spaces from the ends of lines.
                for (var i = 0; i < lines.length; i++) {
                    // Preserve spaces on the line we're on.
                    if (i == currentLine) {
                        continue;
                    }

                    // Don't do the strip if the line contains only spaces
                    // and the preference to trimEmptyLines isn't set.
                    if (lines[i].search(/\s+$/) > min) {
                        lines[i] = lines[i].replace(/\s+$/, "");
                    }
                }

                // Strip newlines from the end of the file.
                while (lines[lines.length - 1] === "") {
                    lines.pop();
                }

                // Ensure that the file ends with one single newline.
                lines.push("");

                session.setText(options.path, lines.join("\n"), callback);
            });
        });
    });
};
<commit_msg>Break out of callback hell.<commit_after>var session = require("zed/session");
var config = require("zed/config");
var stuff = {};

module.exports = function (options, callback) {
    stuff.path = options.path;
    stuff.final_callback = callback;

    config.getPreference("trimEmptyLines", getPrefs);
};

function getPrefs(err, trimEmpty) {
    stuff.min = trimEmpty ? -1 : 0;

    session.getCursorPosition(stuff.path, getLine);
}

function getLine(err, cursor) {
    stuff.currentLine = cursor.row;

    session.getAllLines(stuff.path, strip);
}

function strip(err, lines) {
    // Strip spaces from the ends of lines.
    for (var i = 0; i < lines.length; i++) {
        // Preserve spaces on the line we're on.
        if (i == stuff.currentLine) {
            continue;
        }

        // Don't do the strip if the line contains only spaces
        // and the preference to trimEmptyLines isn't set.
        if (lines[i].search(/\s+$/) > stuff.min) {
            lines[i] = lines[i].replace(/\s+$/, "");
        }
    }

    // Strip newlines from the end of the file.
    while (lines[lines.length - 1] === "") {
        lines.pop();
    }

    // Ensure that the file ends with one single newline.
    lines.push("");

    session.setText(stuff.path, lines.join("\n"), stuff.final_callback);
}
<|endoftext|>


<commit_before>/**
@module ember
@submodule ember-routing
*/

var get = Ember.get, set = Ember.set;

require('ember-handlebars/helpers/view');

Ember.onLoad('Ember.Handlebars', function(Handlebars) {

  /**
    Calling ``{{render}}`` from within a template will insert another
    template that matches the provided name. The inserted template will
    access its properties on its own controller (rather than the controller
    of the parent template).

    If a view class with the same name exists, the view class also will be used.

    Note: A given controller may only be used *once* in your app in this manner.
    A singleton instance of the controller will be created for you.

    Example:

    ```javascript
    App.NavigationController = Ember.Controller.extend({
      who: "world"
    });
    ```

    ```handelbars
    <!-- navigation.hbs -->
    Hello, {{who}}.
    ```

    ```handelbars
    <!-- applications.hbs -->
    <h1>My great app</h1>
    {{render navigaton}}
    ```

    ```html
    <h1>My great app</h1>
    <div class='ember-view'>
      Hello, world.
    </div>
    ```

    Optionally you may provide a  second argument: a property path
    that will be bound to the `model` property of the controller.

    If a `model` property path is specified, then a new instance of the
    controller will be created and `{{render}}` can be used multiple times
    with the same name.

   For example if you had this `author` template.

   ```handlebars
<div class="author">
  Written by {{firstName}} {{lastName}}.
  Total Posts: {{postCount}}
</div>
  ```

  You could render it inside the `post` template using the `render` helper.

  ```handlebars
<div class="post">
  <h1>{{title}}</h1>
  <div>{{body}}</div>
  {{render "author" author}}
</div>
   ```

    @method render
    @for Ember.Handlebars.helpers
    @param {String} name
    @param {Object?} contextString
    @param {Hash} options
    @return {String} HTML string
  */
  Ember.Handlebars.registerHelper('render', function(name, contextString, options) {
    Ember.assert("You must pass a template to render", arguments.length >= 2);
    var contextProvided = arguments.length === 3,
        container, router, controller, view, context, lookupOptions;

    if (arguments.length === 2) {
      options = contextString;
      contextString = undefined;
    }

    if (typeof contextString === 'string') {
      context = Ember.Handlebars.get(options.contexts[1], contextString, options);
      lookupOptions = { singleton: false };
    }

    name = name.replace(/\//g, '.');
    container = options.data.keywords.controller.container;
    router = container.lookup('router:main');

    Ember.assert("You can only use the {{render}} helper once without a model object as its second argument, as in {{render \"post\" post}}.", contextProvided || !router || !router._lookupActiveView(name));

    view = container.lookup('view:' + name) || container.lookup('view:default');

    var controllerName = options.hash.controller;

    // Look up the controller by name, if provided.
    if (controllerName) {
      controller = container.lookup('controller:' + controllerName, lookupOptions);
      Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", !!controller);
    } else {
      controller = container.lookup('controller:' + name, lookupOptions) ||
                      Ember.generateController(container, name, context);
    }

    if (controller && contextProvided) {
      controller.set('model', context);
    }

    var root = options.contexts[1];

    if (root) {
      view.registerObserver(root, contextString, function() {
        controller.set('model', Ember.Handlebars.get(root, contextString, options));
      });
    }

    controller.set('target', options.data.keywords.controller);

    options.hash.viewName = Ember.String.camelize(name);
    options.hash.template = container.lookup('template:' + name);
    options.hash.controller = controller;

    if (router && !context) {
      router._connectActiveView(name, view);
    }

    Ember.Handlebars.helpers.view.call(this, view, options);
  });

});
<commit_msg>Render typos<commit_after>/**
@module ember
@submodule ember-routing
*/

var get = Ember.get, set = Ember.set;

require('ember-handlebars/helpers/view');

Ember.onLoad('Ember.Handlebars', function(Handlebars) {

  /**
    Calling ``{{render}}`` from within a template will insert another
    template that matches the provided name. The inserted template will
    access its properties on its own controller (rather than the controller
    of the parent template).

    If a view class with the same name exists, the view class also will be used.

    Note: A given controller may only be used *once* in your app in this manner.
    A singleton instance of the controller will be created for you.

    Example:

    ```javascript
    App.NavigationController = Ember.Controller.extend({
      who: "world"
    });
    ```

    ```handlebars
    <!-- navigation.hbs -->
    Hello, {{who}}.
    ```

    ```handelbars
    <!-- application.hbs -->
    <h1>My great app</h1>
    {{render navigation}}
    ```

    ```html
    <h1>My great app</h1>
    <div class='ember-view'>
      Hello, world.
    </div>
    ```

    Optionally you may provide a second argument: a property path
    that will be bound to the `model` property of the controller.

    If a `model` property path is specified, then a new instance of the
    controller will be created and `{{render}}` can be used multiple times
    with the same name.

   For example if you had this `author` template.

   ```handlebars
<div class="author">
  Written by {{firstName}} {{lastName}}.
  Total Posts: {{postCount}}
</div>
  ```

  You could render it inside the `post` template using the `render` helper.

  ```handlebars
<div class="post">
  <h1>{{title}}</h1>
  <div>{{body}}</div>
  {{render "author" author}}
</div>
   ```

    @method render
    @for Ember.Handlebars.helpers
    @param {String} name
    @param {Object?} contextString
    @param {Hash} options
    @return {String} HTML string
  */
  Ember.Handlebars.registerHelper('render', function(name, contextString, options) {
    Ember.assert("You must pass a template to render", arguments.length >= 2);
    var contextProvided = arguments.length === 3,
        container, router, controller, view, context, lookupOptions;

    if (arguments.length === 2) {
      options = contextString;
      contextString = undefined;
    }

    if (typeof contextString === 'string') {
      context = Ember.Handlebars.get(options.contexts[1], contextString, options);
      lookupOptions = { singleton: false };
    }

    name = name.replace(/\//g, '.');
    container = options.data.keywords.controller.container;
    router = container.lookup('router:main');

    Ember.assert("You can only use the {{render}} helper once without a model object as its second argument, as in {{render \"post\" post}}.", contextProvided || !router || !router._lookupActiveView(name));

    view = container.lookup('view:' + name) || container.lookup('view:default');

    var controllerName = options.hash.controller;

    // Look up the controller by name, if provided.
    if (controllerName) {
      controller = container.lookup('controller:' + controllerName, lookupOptions);
      Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", !!controller);
    } else {
      controller = container.lookup('controller:' + name, lookupOptions) ||
                      Ember.generateController(container, name, context);
    }

    if (controller && contextProvided) {
      controller.set('model', context);
    }

    var root = options.contexts[1];

    if (root) {
      view.registerObserver(root, contextString, function() {
        controller.set('model', Ember.Handlebars.get(root, contextString, options));
      });
    }

    controller.set('target', options.data.keywords.controller);

    options.hash.viewName = Ember.String.camelize(name);
    options.hash.template = container.lookup('template:' + name);
    options.hash.controller = controller;

    if (router && !context) {
      router._connectActiveView(name, view);
    }

    Ember.Handlebars.helpers.view.call(this, view, options);
  });

});
<|endoftext|>


<commit_before>/*
 Copyright 2016 - 2016 by Jan Dockx

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
"use strict";

var ContractConditionMetaError = require("./ContractConditionMetaError");
var ContractConditionViolation = require("./ContractConditionViolation");

var tc = {
  /**
   * A better type then Object.toString() or typeof.
   * - toType(undefined); //"undefined"
   * - toType(new); //"null"
   * - toType({a: 4}); //"object"
   * - toType([1, 2, 3]); //"array"
   * - (function() {console.log(toType(arguments))})(); //arguments
   * - toType(new ReferenceError); //"error"
   * - toType(new Date); //"date"
   * - toType(/a-z/); //"regexp"
   * - toType(Math); //"math"
   * - toType(JSON); //"json"
   * - toType(new Number(4)); //"number"
   * - toType(new String("abc")); //"string"
   * - toType(new Boolean(true)); //"boolean"
   *
   * Based on
   * http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
   */
  typeOf: function(obj) {
    if (obj === null) { // workaround for some weird implementations
      return "null";
    }
    var result = Object.prototype.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
    // on some browsers, the main window returns as "global" (WebKit) or "window" (FF), but this is an object too
    if (result === "global" || result === "window") {
      result = "object";
    }
    return result; // return String
  }
};

function Contract(pre, post) {
  this.pre = pre ? pre.slice() : [];
  this.post = post ? post.slice() : [];
  // MUDO seal freeze
}

Contract.prototype = {
  constructor: Contract,
  pre: [],
  post: [],
  isImplementedBy: function(f) {
    return Contract.isAContractFunction(f) && f.contract === this;
  },
  verifyOne: function(condition, self, args) {
    var conditionResult;
    try {
      conditionResult = condition.apply(self, args);
    }
    catch (err) {
      throw new ContractConditionMetaError(condition, self, args, err);
    }
    if (!conditionResult) {
      throw new ContractConditionViolation(condition, self, args);
    }
  },
  verifyAll: function(conditions, self, args) {
    if (conditions) {
      conditions.forEach(function(condition) {this.verifyOne(condition, self, args);}, this);
    }
  },
  implementation: function(implFunction) {
    var contract = this;

    function contractFunction() {
      contract.verify(contract.pre, this, arguments);
      var extendedArgs;
      try {
        var result = implFunction.apply(this, arguments);
        extendedArgs = Array.prototype.concat(arguments, [result]);
        contract.verify(contract.post, this, extendedArgs);
        return result;
      }
      catch(exception) {
        // TODO this should be dealt with better
        extendedArgs = Array.prototype.concat(arguments, [exception]);
        contract.verify(contract.post, this, extendedArgs);
        throw exception;
      }
    }

    contractFunction.contract = contract;
    contractFunction.implementation = implFunction;

    return contractFunction;
  }
};

Contract.isAContractFunction = function(f) {
  return tc.typeOf(f) === "function" && f.contract instanceof Contract && tc.typeOf(f.implementation) === "function";
};

module.exports = Contract;
<commit_msg>First implementation test<commit_after>/*
 Copyright 2016 - 2016 by Jan Dockx

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
"use strict";

var ContractConditionMetaError = require("./ContractConditionMetaError");
var ContractConditionViolation = require("./ContractConditionViolation");

var tc = {
  /**
   * A better type then Object.toString() or typeof.
   * - toType(undefined); //"undefined"
   * - toType(new); //"null"
   * - toType({a: 4}); //"object"
   * - toType([1, 2, 3]); //"array"
   * - (function() {console.log(toType(arguments))})(); //arguments
   * - toType(new ReferenceError); //"error"
   * - toType(new Date); //"date"
   * - toType(/a-z/); //"regexp"
   * - toType(Math); //"math"
   * - toType(JSON); //"json"
   * - toType(new Number(4)); //"number"
   * - toType(new String("abc")); //"string"
   * - toType(new Boolean(true)); //"boolean"
   *
   * Based on
   * http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
   */
  typeOf: function(obj) {
    if (obj === null) { // workaround for some weird implementations
      return "null";
    }
    var result = Object.prototype.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
    // on some browsers, the main window returns as "global" (WebKit) or "window" (FF), but this is an object too
    if (result === "global" || result === "window") {
      result = "object";
    }
    return result; // return String
  }
};

function Contract(pre, post) {
  this.pre = pre ? pre.slice() : [];
  this.post = post ? post.slice() : [];
  // MUDO seal freeze
}

Contract.prototype = {
  constructor: Contract,
  pre: [],
  post: [],
  isImplementedBy: function(f) {
    return Contract.isAContractFunction(f) && f.contract === this;
  },
  verifyOne: function(condition, self, args) {
    var conditionResult;
    try {
      conditionResult = condition.apply(self, args);
    }
    catch (err) {
      throw new ContractConditionMetaError(condition, self, args, err);
    }
    if (!conditionResult) {
      throw new ContractConditionViolation(condition, self, args);
    }
  },
  verifyAll: function(conditions, self, args) {
    if (conditions) {
      conditions.forEach(function(condition) {this.verifyOne(condition, self, args);}, this);
    }
  },
  implementation: function(implFunction) {
    var contract = this;

    function contractFunction() {
      contract.verify(contract.pre, this, arguments);
      var extendedArgs;
      try {
        var result = implFunction.apply(this, arguments);
        extendedArgs = Array.prototype.concat(arguments, [result]);
        contract.verify(contract.post, this, extendedArgs);
        return result;
      }
      catch(exception) {
        // TODO this should be dealt with better
        extendedArgs = Array.prototype.concat(arguments, [exception]);
        contract.verify(contract.post, this, extendedArgs);
        throw exception;
      }
    }

    contractFunction.contract = contract;
    contractFunction.implementation = implFunction;
    // MUDO freeze seal

    return contractFunction;
  }
};

Contract.isAContractFunction = function(f) {
  return tc.typeOf(f) === "function" && f.contract instanceof Contract && tc.typeOf(f.implementation) === "function";
};

module.exports = Contract;
<|endoftext|>


<commit_before>var Test = artifacts.require('Test')

contract('Example', function(accounts) {
  it("should assert true", function(done) {
    var example = Example.deployed();
    assert.isTrue(true);
    done();
  });
});
<commit_msg>change 'Test' to 'Example' & add ;<commit_after>var Example = artifacts.require('Example');

contract('Example', function(accounts) {
  it("should assert true", function(done) {
    var example = Example.deployed();
    assert.isTrue(true);
    done();
  });
});
<|endoftext|>


<commit_before>import prefix from '../../mixins/prefix'
import { get, noop } from 'lodash'

export const CUSTOM_GUTTER = '--dls-carousel-slide-gutter'
export const FALLBACK_GUTTER = '24px'

export default {
  mixins: [prefix],
  props: {
    slideAspectRatio: [String, Number],
    options: Object,
    preloadRange: Array,
    datasource: Array,
    index: Number
  },
  created () {
    // 过渡完成后重置视频时间
    this.willReset = []
  },
  computed: {
    aspectRatioStyle () {
      if (this.slideAspectRatio) {
        return { 'padding-top': `${getRatio(this.slideAspectRatio) * 100}%` }
      }
      return null
    },
    isAutoplay () {
      return !!get(this.options, 'video.autoplay')
    },
    realDatasource () {
      return this.datasource
    }
  },
  methods: {
    resetVideos () {
      if (this.willReset.length) {
        this.willReset.forEach(ref => {
          // video 都是在循环里面
          if (this.$refs[ref] && this.$refs[ref][0]) {
            this.$refs[ref][0].currentTime = 0
          }
        })
        this.willReset = []
      }
    },
    pauseVideos (range) {
      if (typeof range === 'number') {
        range = [range, range + 1]
      }
      let [start, end] = range
      while (start < end) {
        const current = this.realDatasource[start]
        const ref = `video#${start}`
        if (isVideo(current) && this.$refs[ref] && this.$refs[ref][0]) {
          this.$refs[ref][0].pause()
          this.willReset.push(ref)
        }
        start++
      }
    },
    playVideos (range) {
      if (typeof range === 'number') {
        range = [range, range + 1]
      }
      let [start, end] = range
      while (start < end) {
        const current = this.realDatasource[start]
        if (isVideo(current)) {
          const video = this.$refs[`video#${start}`]
          if (video && video[0] && this.isAutoplay) {
            const playPro = video[0].play()
            if (playPro.catch) {
              // play 可能会报错（被 pause 中断等？）先 ignore，DOMException？
              playPro.catch(noop)
            }
          }
        }
        start++
      }
    },
    isPreload (index) {
      let [start, end] = this.preloadRange
      return start <= end
        ? index >= start && index <= end
        : index >= start || index <= end
    }
  }
}

export function isVideo ({ type, raw }) {
  return type === 'video' || (!!raw && raw.type === 'video')
}

export function getRatio (ratio) {
  if (typeof ratio === 'string') {
    const [w, h] = ratio.split('/').map(Number)
    ratio = h / w
  } else {
    ratio = 1 / ratio
  }
  return ratio
}
<commit_msg>fix: fix isVideo bug for carousel mixin<commit_after>import prefix from '../../mixins/prefix'
import { get, noop } from 'lodash'

export const CUSTOM_GUTTER = '--dls-carousel-slide-gutter'
export const FALLBACK_GUTTER = '24px'

export default {
  mixins: [prefix],
  props: {
    slideAspectRatio: [String, Number],
    options: Object,
    preloadRange: Array,
    datasource: Array,
    index: Number
  },
  created () {
    // 过渡完成后重置视频时间
    this.willReset = []
  },
  computed: {
    aspectRatioStyle () {
      if (this.slideAspectRatio) {
        return { 'padding-top': `${getRatio(this.slideAspectRatio) * 100}%` }
      }
      return null
    },
    isAutoplay () {
      return !!get(this.options, 'video.autoplay')
    },
    realDatasource () {
      return this.datasource
    }
  },
  methods: {
    resetVideos () {
      if (this.willReset.length) {
        this.willReset.forEach(ref => {
          // video 都是在循环里面
          if (this.$refs[ref] && this.$refs[ref][0]) {
            this.$refs[ref][0].currentTime = 0
          }
        })
        this.willReset = []
      }
    },
    pauseVideos (range) {
      if (typeof range === 'number') {
        range = [range, range + 1]
      }
      let [start, end] = range
      while (start < end) {
        const current = this.realDatasource[start]
        const ref = `video#${start}`
        if (isVideo(current) && this.$refs[ref] && this.$refs[ref][0]) {
          this.$refs[ref][0].pause()
          this.willReset.push(ref)
        }
        start++
      }
    },
    playVideos (range) {
      if (typeof range === 'number') {
        range = [range, range + 1]
      }
      let [start, end] = range
      while (start < end) {
        const current = this.realDatasource[start]
        if (isVideo(current)) {
          const video = this.$refs[`video#${start}`]
          if (video && video[0] && this.isAutoplay) {
            const playPro = video[0].play()
            if (playPro.catch) {
              // play 可能会报错（被 pause 中断等？）先 ignore，DOMException？
              playPro.catch(noop)
            }
          }
        }
        start++
      }
    },
    isPreload (index) {
      let [start, end] = this.preloadRange
      return start <= end
        ? index >= start && index <= end
        : index >= start || index <= end
    }
  }
}

export function isVideo ({ type, raw } = {}) {
  return type === 'video' || (!!raw && raw.type === 'video')
}

export function getRatio (ratio) {
  if (typeof ratio === 'string') {
    const [w, h] = ratio.split('/').map(Number)
    ratio = h / w
  } else {
    ratio = 1 / ratio
  }
  return ratio
}
<|endoftext|>


<commit_before>const buttonSlow = document.getElementById("slow");
const buttonFast = document.getElementById("fast");
const buttonEasy = document.getElementById("easy");
const buttonHard = document.getElementById("hard");
const timeOut = 15000;

let socket = io();
socket.emit('join', {'course_id': courseID });

function enableAllButtons() {
        buttonSlow.disabled = false;
        buttonFast.disabled = false;
        buttonEasy.disabled = false;
        buttonHard.disabled = false;
}

function disableAllButtons() {
        buttonSlow.disabled = true;
        buttonFast.disabled = true;
        buttonEasy.disabled = true;
        buttonHard.disabled = true;
}

socket.on('student_recv', function (msg) {
    console.log(msg['active']);
    if(msg.hasOwnProperty('active')) {
        if(msg['active']) {
            enableAllButtons();
        }else {
            disableAllButtons();
        }
    }
});

function timeOutPace(){
    buttonSlow.disabled = true;
    buttonFast.disabled = true;
    setTimeout(function() {
        buttonSlow.disabled = false;
        buttonFast.disabled = false;
    }, timeOut);
}
buttonSlow.addEventListener("click", timeOutPace);
buttonFast.addEventListener("click", timeOutPace);

function timeOutDifficulty(){
    buttonEasy.disabled = true;
    buttonHard.disabled = true;
    setTimeout(function() {
        buttonEasy.disabled = false;
        buttonHard.disabled = false;
    }, timeOut);
}
buttonEasy.addEventListener("click", timeOutDifficulty);
buttonHard.addEventListener("click", timeOutDifficulty);

$('.action_button').click(function (eventObj) {
    console.log(eventObj['currentTarget']['id']);
    let data = {'action': eventObj['currentTarget']['id'], 'course_id': courseID};
    socket.emit('student_send', data);
});
<commit_msg>Added check for disabling student buttons when session not active<commit_after>const buttonSlow = document.getElementById("slow");
const buttonFast = document.getElementById("fast");
const buttonEasy = document.getElementById("easy");
const buttonHard = document.getElementById("hard");
const timeOut = 15000;

let socket = io();
socket.emit('join', {'course_id': courseID });

function enableAllButtons() {
        buttonSlow.disabled = false;
        buttonFast.disabled = false;
        buttonEasy.disabled = false;
        buttonHard.disabled = false;
}

function disableAllButtons() {
        buttonSlow.disabled = true;
        buttonFast.disabled = true;
        buttonEasy.disabled = true;
        buttonHard.disabled = true;
}

if(sessionActive){
    enableAllButtons();
}else{
    disableAllButtons();
}

socket.on('student_recv', function (msg) {
    console.log(msg['active']);
    if(msg.hasOwnProperty('active')) {
        if(msg['active']) {
            enableAllButtons();
        }else {
            disableAllButtons();
        }
    }
});

function timeOutPace(){
    buttonSlow.disabled = true;
    buttonFast.disabled = true;
    setTimeout(function() {
        buttonSlow.disabled = false;
        buttonFast.disabled = false;
    }, timeOut);
}
buttonSlow.addEventListener("click", timeOutPace);
buttonFast.addEventListener("click", timeOutPace);

function timeOutDifficulty(){
    buttonEasy.disabled = true;
    buttonHard.disabled = true;
    setTimeout(function() {
        buttonEasy.disabled = false;
        buttonHard.disabled = false;
    }, timeOut);
}
buttonEasy.addEventListener("click", timeOutDifficulty);
buttonHard.addEventListener("click", timeOutDifficulty);

$('.action_button').click(function (eventObj) {
    console.log(eventObj['currentTarget']['id']);
    let data = {'action': eventObj['currentTarget']['id'], 'course_id': courseID};
    socket.emit('student_send', data);
});
<|endoftext|>


<commit_before>/**
 * @var mixed doc
 * @var null type_null
 */

var Global = {
    initialization: true,
    instances: [],
    countries: [] // коды стран которые необходимо дополнительно подключить
};

var plugin = function (options) {
    var self        = this;
    self.elements   = [];
    self.options    = {
        lang:       MConf('lang'),
        country:    MConf('country')
    };

    self.init(options);

    if(typeof MaskedReady.use === type_undefined) {
        alternativeReady.init();
    }

    return self;
};

/**
 * После отгрузки всех масок проинициализируем все еще раз с доп масками если есть
 */
plugin.postload = function () {
    var i,
        c,
        object,
        country,
        pc = phoneCodes,
        g = Global,
        ge = g.instances,
        gc = g.countries;

    for(i in gc) {
        if(gc.hasOwnProperty(i)) {
            country = gc[i];
            if (isset(pc[country.iso_code]) && empty(pc[country.iso_code])) {
                pc.loadMasks(country.iso_code, country.lang, function () {
                    for (i in ge) {
                        if(ge.hasOwnProperty(i)) {
                            object = ge[i];
                            c = {'iso_code': object.opt.country, 'lang': object.opt.lang };

                            if(languageIsset(gc, c)) {
                                object.maskFinder(object.opt.phone, object.opt.country);
                            }

                        }
                    }
                });
            }
        }
    }

    g.initialization = false;
};

/**
 * Получить инстанс
 * @param e
 * @returns {*}
 */
plugin.getInst = function (e) {
    return Global.instances[e.className.match(new RegExp(MConf('prefix') + '[0-9a-zA-Z]+'))];
};

/**
 * Открываем доступ из вне для обращения к Masked.phoneCodes
 */
plugin.phoneCodes = phoneCodes;

plugin.getById = function (id) {
    var el = document.getElementById(id);
    if(el !== null){
        return this.getInst(el);
    }
    return false;
};

plugin.getPhone = function (value) {
    return value ? plugin.prototype.getPhone(value) : false;
};

plugin.isValid = function (value) {
    return value ? plugin.prototype.isValid(value) : false;
};

/**
 * Переключение статуса
 * @param e Элемент или класс
 */
plugin.toggle = function(e) {
    var self = this.getInst(e),
        opt  = self.opt;

    if (!empty(e.parentNode) && e.parentNode.className === 'CBH-masks') {
        e.parentNode.outerHTML = opt.oldState;
    } else {
        opt.element = e;
        self.setTemplate();
        opt.element.value       = opt.value;
        self.addActions(opt.element);
    }
};

plugin.prototype = {
    init:  function(options) {
        var self      = this;

        if (options) {
            if (typeof options === 'string') {
                options = {
                    selector: options
                };
            }
            self.options = generalMaskedFn.extend(self.options, options);
        }

        if (typeof options.selector !== type_undefined) {

            /**
             * Вернет массив елементов
             *
             * @param options
             */
            function select(options) {
                var i,
                    elem,
                    first_digit,
                    elements = [],
                    selector = options.selector;

                if ( typeof selector === 'string' ) {
                    first_digit = selector[0];

                    if ( (first_digit === '.') || (first_digit === '#') ) {
                        selector = selector.substr(1);
                    }

                    if (first_digit === '.') {
                        elem = doc.getElementsByClassName( selector );
                        for(i in elem) {
                            if (elem.hasOwnProperty(i) && elem[i] !== type_null) {
                                elements[elem[i].id||i] = elem[i];
                            }
                        }
                    } else if (first_digit === '#') {
                        elem = doc.getElementById( selector );
                        if (elem !== type_null) {
                            elements.push(elem);
                        }
                    } else {
                        console.log('selector finder empty');
                    }
                } else if (selector.nodeType) {
                    if (selector !== type_null) {
                        elements.push(selector);
                    }
                }
                return elements;
            }

            self.elements = select(options);
        }

        if (Object.keys(self.elements).length) {
            MaskedObserver.add(self);
        }

        return self;
    },

    start: function () {
        var i,
            el,
            opt,
            object,
            self     = this,
            elements = self.elements;

        for(i in elements) {
            if (elements.hasOwnProperty(i)) {
                el   = elements[i];
                if (el && !el.className.match(new RegExp(MConf('prefix') + '[0-9a-zA-Z]+'))) {
                    opt = generalMaskedFn.extend(generalMaskedFn.extend({}, self.options), el.dataset);

                    object = new Mask(el, opt);
                    Global.instances[object.opt.instId] = object;
                }
            }
        }
    },

    setPhone: function (value) {
        var elements = this.elements;
        for(var i in elements) {
            if (elements.hasOwnProperty(i)) {
                if (!empty(plugin.getInst(elements[i]))) {
                    plugin.getInst(elements[i]).maskFinder(value);
                }
            }
        }
    },

    /**
     * Получить форматированную маску по номеру телефона, или объекту/объектам макси
     * вернет строку или массив, можно вернуть номер без маски
     * @param value
     * @param _with_mask
     * @returns {string}|{object}
     */
    getPhone: function (value, _with_mask) {
        var phone,
            inst,
            phones   = [],
            elements   = [],
            hs         = hardSearch,
            with_mask  = _with_mask || true;

        console.log(this);

        if (value) {
            phone = getNewMaskValue(getPhone(value), hs(value).mask);
            if (!with_mask) {
                phone = getPhone(phone);
            }
            phones.push(phone);
        } else {
            elements = this.elements;

            for(var i in elements) {
                if (elements.hasOwnProperty(i)) {
                    if (!empty(plugin.getInst(elements[i]))) {
                        phone = plugin.getInst(elements[i]).opt.value;

                        phone = getNewMaskValue(phone, hs(getPhone(phone)).mask);
                        if (!with_mask) {
                            phone = getPhone(phone);
                        }
                        phones.push(phone);
                    }
                }
            }
        }

        return (
            value || !value && (Object.keys(elements).length == 1)
        ) ? phones[0] : phones;
    },

    isValid: function (value) {
        var phone,
            valid = false,
            hs         = hardSearch,
            elements   = [];

        if (value) {
            valid = getNewMaskValue(getPhone(value), hs(getPhone(value)).mask).indexOf('_') === -1;
        } else {
             elements = this.elements;

             if (Object.keys(elements).length) {
                 phone = plugin.getInst(elements[0]).opt.value;

                 valid = getNewMaskValue(getPhone(phone), hs(getPhone(phone)).mask).indexOf('_') === -1;
             } else {
                 valid = false;
             }
        }
        return valid;
    },

};
<commit_msg>поправил метод getPhone<commit_after>/**
 * @var mixed doc
 * @var null type_null
 */

var Global = {
    initialization: true,
    instances: [],
    countries: [] // коды стран которые необходимо дополнительно подключить
};

var plugin = function (options) {
    var self        = this;
    self.elements   = [];
    self.options    = {
        lang:       MConf('lang'),
        country:    MConf('country')
    };

    self.init(options);

    if(typeof MaskedReady.use === type_undefined) {
        alternativeReady.init();
    }

    return self;
};

/**
 * После отгрузки всех масок проинициализируем все еще раз с доп масками если есть
 */
plugin.postload = function () {
    var i,
        c,
        object,
        country,
        pc = phoneCodes,
        g = Global,
        ge = g.instances,
        gc = g.countries;

    for(i in gc) {
        if(gc.hasOwnProperty(i)) {
            country = gc[i];
            if (isset(pc[country.iso_code]) && empty(pc[country.iso_code])) {
                pc.loadMasks(country.iso_code, country.lang, function () {
                    for (i in ge) {
                        if(ge.hasOwnProperty(i)) {
                            object = ge[i];
                            c = {'iso_code': object.opt.country, 'lang': object.opt.lang };

                            if(languageIsset(gc, c)) {
                                object.maskFinder(object.opt.phone, object.opt.country);
                            }

                        }
                    }
                });
            }
        }
    }

    g.initialization = false;
};

/**
 * Получить инстанс
 * @param e
 * @returns {*}
 */
plugin.getInst = function (e) {
    return Global.instances[e.className.match(new RegExp(MConf('prefix') + '[0-9a-zA-Z]+'))];
};

/**
 * Открываем доступ из вне для обращения к Masked.phoneCodes
 */
plugin.phoneCodes = phoneCodes;

plugin.getById = function (id) {
    var el = document.getElementById(id);
    if(el !== null){
        return this.getInst(el);
    }
    return false;
};

plugin.getPhone = function (value) {
    return value ? plugin.prototype.getPhone(value) : false;
};

plugin.isValid = function (value) {
    return value ? plugin.prototype.isValid(value) : false;
};

/**
 * Переключение статуса
 * @param e Элемент или класс
 */
plugin.toggle = function(e) {
    var self = this.getInst(e),
        opt  = self.opt;

    if (!empty(e.parentNode) && e.parentNode.className === 'CBH-masks') {
        e.parentNode.outerHTML = opt.oldState;
    } else {
        opt.element = e;
        self.setTemplate();
        opt.element.value       = opt.value;
        self.addActions(opt.element);
    }
};

plugin.prototype = {
    init:  function(options) {
        var self      = this;

        if (options) {
            if (typeof options === 'string') {
                options = {
                    selector: options
                };
            }
            self.options = generalMaskedFn.extend(self.options, options);
        }

        if (typeof options.selector !== type_undefined) {

            /**
             * Вернет массив елементов
             *
             * @param options
             */
            function select(options) {
                var i,
                    elem,
                    first_digit,
                    elements = [],
                    selector = options.selector;

                if ( typeof selector === 'string' ) {
                    first_digit = selector[0];

                    if ( (first_digit === '.') || (first_digit === '#') ) {
                        selector = selector.substr(1);
                    }

                    if (first_digit === '.') {
                        elem = doc.getElementsByClassName( selector );
                        for(i in elem) {
                            if (elem.hasOwnProperty(i) && elem[i] !== type_null) {
                                elements[elem[i].id||i] = elem[i];
                            }
                        }
                    } else if (first_digit === '#') {
                        elem = doc.getElementById( selector );
                        if (elem !== type_null) {
                            elements.push(elem);
                        }
                    } else {
                        console.log('selector finder empty');
                    }
                } else if (selector.nodeType) {
                    if (selector !== type_null) {
                        elements.push(selector);
                    }
                }
                return elements;
            }

            self.elements = select(options);
        }

        if (Object.keys(self.elements).length) {
            MaskedObserver.add(self);
        }

        return self;
    },

    start: function () {
        var i,
            el,
            opt,
            object,
            self     = this,
            elements = self.elements;

        for(i in elements) {
            if (elements.hasOwnProperty(i)) {
                el   = elements[i];
                if (el && !el.className.match(new RegExp(MConf('prefix') + '[0-9a-zA-Z]+'))) {
                    opt = generalMaskedFn.extend(generalMaskedFn.extend({}, self.options), el.dataset);

                    object = new Mask(el, opt);
                    Global.instances[object.opt.instId] = object;
                }
            }
        }
    },

    setPhone: function (value) {
        var elements = this.elements;
        for(var i in elements) {
            if (elements.hasOwnProperty(i)) {
                if (!empty(plugin.getInst(elements[i]))) {
                    plugin.getInst(elements[i]).maskFinder(value);
                }
            }
        }
    },

    /**
     * Получить форматированную маску по номеру телефона, или объекту/объектам макси
     * вернет строку или массив, можно вернуть номер без маски
     * @param value
     * @param _with_mask
     * @returns {string}|{object}
     */
    getPhone: function (value, _with_mask) {
        var phone,
            inst,
            phones   = [],
            elements   = [],
            hs         = hardSearch,
            with_mask  = _with_mask || true;

        if (value) {
            phone = getNewMaskValue(getPhone(value), hs(getPhone(value)).mask);
            if (!with_mask) {
                phone = getPhone(phone);
            }
            phones.push(phone);
        } else {
            elements = this.elements;

            for(var i in elements) {
                if (elements.hasOwnProperty(i)) {
                    if (!empty(plugin.getInst(elements[i]))) {
                        phone = plugin.getInst(elements[i]).opt.value;

                        phone = getNewMaskValue(phone, hs(getPhone(phone)).mask);
                        if (!with_mask) {
                            phone = getPhone(phone);
                        }
                        phones.push(phone);
                    }
                }
            }
        }

        return (
            value || !value && (Object.keys(elements).length == 1)
        ) ? phones[0] : phones;
    },

    isValid: function (value) {
        var phone,
            valid = false,
            hs         = hardSearch,
            elements   = [];

        if (value) {
            valid = getNewMaskValue(getPhone(value), hs(getPhone(value)).mask).indexOf('_') === -1;
        } else {
             elements = this.elements;

             if (Object.keys(elements).length) {
                 phone = plugin.getInst(elements[0]).opt.value;

                 valid = getNewMaskValue(getPhone(phone), hs(getPhone(phone)).mask).indexOf('_') === -1;
             } else {
                 valid = false;
             }
        }
        return valid;
    },

};
<|endoftext|>


<commit_before>import r2frida from "./plugin.js";
import config from "./config.js";
'use strict';
let cachedRanges = [];
function read(params) {
    const { offset, count, fast } = params;
    if (typeof r2frida.hookedRead === 'function') {
        return r2frida.hookedRead(offset, count);
    }
    if (r2frida.safeio) {
        try {
            if (cachedRanges.length === 0) {
                cachedRanges = Process.enumerateRanges('').map((map) => [map.base, ptr(map.base).add(map.size)]);
            }
            // TODO: invalidate ranges at some point to refresh
            // process.nextTick(() => { cachedRanges = null; }
            const o = ptr(offset);
            for (const map of cachedRanges) {
                if (o.compare(map[0]) >= 0 && o.compare(map[1]) < 0) {
                    let left = count;
                    if (o.add(count).compare(map[1]) > 0) {
                        const rest = o.add(count).sub(map[1]);
                        left = left.sub(rest);
                    }
                    const bytes = Memory.readByteArray(o, left);
                    return [{}, (bytes !== null) ? bytes : []];
                }
            }
            return [{}, []];
        }
        catch (e) {
            console.error('safeio-read', e);
        }
    }
    if (offset < 0) {
        return [{}, []];
    }
    try {
        const bytes = Memory.readByteArray(ptr(offset), count);
        // console.log("FAST", offset);
        return [{}, (bytes !== null) ? bytes : []];
    }
    catch (e) {
        if (!fast) {
            try {
                // console.log("SLOW", offset);
                const readStarts = ptr(offset);
                const readEnds = readStarts.add(count);
                const currentRange = Process.getRangeByAddress(readStarts); // this is very slow
                const moduleEnds = currentRange.base.add(currentRange.size);
                const left = (readEnds.compare(moduleEnds) > 0
                    ? readEnds
                    : moduleEnds).sub(offset);
                const bytes = Memory.readByteArray(ptr(offset), +left);
                return [{}, (bytes !== null) ? bytes : []];
            }
            catch (e) {
                // do nothing
            }
        }
    }
    return [{}, []];
}
function isExecutable(address) {
    const currentRange = Process.getRangeByAddress(address);
    return currentRange.protection.indexOf('x') !== -1;
}
function write(params, data) {
    if (typeof r2frida.hookedWrite === 'function') {
        return r2frida.hookedWrite(params.offset, data);
    }
    if (config.getBoolean('patch.code') && isExecutable(ptr(params.offset))) {
        if (typeof Memory.patchCode === 'function') {
            Memory.patchCode(ptr(params.offset), 1, function (ptr) {
                Memory.writeByteArray(ptr, data);
            });
        }
        else {
            Memory.writeByteArray(ptr(params.offset), data);
        }
    }
    else {
        Memory.writeByteArray(ptr(params.offset), data);
    }
    return [{}, null];
}
export { read };
export { write };
export default {
    read: read,
    write: write
};
<commit_msg>Reindent io module<commit_after>import r2frida from './plugin.js';
import config from './config.js';
'use strict';

let cachedRanges = [];

function read (params) {
  const { offset, count, fast } = params;
  if (typeof r2frida.hookedRead === 'function') {
    return r2frida.hookedRead(offset, count);
  }
  if (r2frida.safeio) {
    try {
      if (cachedRanges.length === 0) {
        cachedRanges = Process.enumerateRanges('').map((map) => [map.base, ptr(map.base).add(map.size)]);
      }
      // TODO: invalidate ranges at some point to refresh
      // process.nextTick(() => { cachedRanges = null; }
      const o = ptr(offset);
      for (const map of cachedRanges) {
        if (o.compare(map[0]) >= 0 && o.compare(map[1]) < 0) {
          let left = count;
          if (o.add(count).compare(map[1]) > 0) {
            const rest = o.add(count).sub(map[1]);
            left = left.sub(rest);
          }
          const bytes = Memory.readByteArray(o, left);
          return [{}, (bytes !== null) ? bytes : []];
        }
      }
      return [{}, []];
    } catch (e) {
      console.error('safeio-read', e);
    }
  }
  if (offset < 0) {
    return [{}, []];
  }
  try {
    const bytes = Memory.readByteArray(ptr(offset), count);
    // console.log("FAST", offset);
    return [{}, (bytes !== null) ? bytes : []];
  } catch (e) {
    if (!fast) {
      try {
        // console.log("SLOW", offset);
        const readStarts = ptr(offset);
        const readEnds = readStarts.add(count);
        const currentRange = Process.getRangeByAddress(readStarts); // this is very slow
        const moduleEnds = currentRange.base.add(currentRange.size);
        const left = (readEnds.compare(moduleEnds) > 0
          ? readEnds
          : moduleEnds).sub(offset);
        const bytes = Memory.readByteArray(ptr(offset), +left);
        return [{}, (bytes !== null) ? bytes : []];
      } catch (e) {
        // do nothing
      }
    }
  }
  return [{}, []];
}

function isExecutable (address) {
  const currentRange = Process.getRangeByAddress(address);
  return currentRange.protection.indexOf('x') !== -1;
}

function write (params, data) {
  if (typeof r2frida.hookedWrite === 'function') {
    return r2frida.hookedWrite(params.offset, data);
  }
  if (config.getBoolean('patch.code') && isExecutable(ptr(params.offset))) {
    if (typeof Memory.patchCode === 'function') {
      Memory.patchCode(ptr(params.offset), 1, function (ptr) {
        Memory.writeByteArray(ptr, data);
      });
    } else {
      Memory.writeByteArray(ptr(params.offset), data);
    }
  } else {
    Memory.writeByteArray(ptr(params.offset), data);
  }
  return [{}, null];
}

export { read };
export { write };
export default {
  read: read,
  write: write
};
<|endoftext|>