<commit_before>/// Required Core Modules
var vm = require('vm');
var eventEmmiter = require('events').EventEmitter;
var util = require('util');
///
/// External Modules
var Deque = require('double-ended-queue');
var defaultsDeep = require('lodash.defaultsdeep');
///
/// Internal Modules
var ContextPermissions = require('./lib/ContextPermissions');
var TaskModel = require('./lib/TaskModel');
///
/// Predefined Types
// TYPES
var ST_LOCAL_TYPE = 0, ST_SHARED_TYPE = 1, ST_FOREIGN_TYPE = 2;
// PERMISSIONS
var ST_NONE = 0, ST_RESTRICTED = 1, ST_MINIMAL = 2, ST_UNRESTRICTED = 3;
///
// No Operation function
function noop() { return null; }

/**
 * Creates new instance.
 * @constructor
 * @example
 * var SuperTask = require('supertask');
 * var TaskManager = new SuperTask();
 *
 * @returns {Instance} Returns a new instance of the module.
 */
var SuperTask = function ST_INIT(size, strict) {
    this._busy_ = false;
    this.map = new Map();
    this.queue = new Deque(parseInt(size, 10) || 10000);
    this.concurrency = 1000;
    this.strict = (!!strict);

    eventEmmiter.call(this);
};

util.inherits(SuperTask, eventEmmiter);

SuperTask.prototype._createTask = TaskModel.create;
SuperTask.prototype._wrapTask = TaskModel.wrap;

SuperTask.prototype._extendContextFromPermissions = ContextPermissions;

SuperTask.prototype._next_ = function ST__QUEUE_NEXT() {
    // Allow _next_ to be called
    this._busy_ = false;

    /* At this point the source is fully compiled
    /* to a function or a function is resupplied
    /* from cache to be executed. Here we transfer
    /* the given function (task.func) to the queue
    /* after attaching the pre tracker */

    // Do a batch
    for (var i = 0; i < Math.min(this.queue.length, this.concurrency); i++) {
        // Get a task
        var task = this.queue.shift();

        // Call preTracker
        task.pre();
        // Push Callback to args
        task.args.push(task.callback);
        // If task is shared call handler
        if (task.shared && task.handler) {
            // Assign task name to argument[0] followed by context
            task.args.unshift(task.context);
            task.args.unshift(task.name);
            task.handler.apply(null, task.args);
        } else {
            // Call local/remote Function with context & args
            if (task.sandboxed) {
                try {
                    task.func.apply(task.context, task.args);
                } catch (error) {
                    task.callback(error);
                }
            } else {
                task.func.apply(task.context, task.args);
            }
        }
    }

    // Keep executing until Queue is empty
    if (this.queue.length > 0) {
        // Do after I/O & Tasks are cleared
        setImmediate(() => { this._next_(); });
    }
};

SuperTask.prototype._push_ = function ST__QUEUE_ADD(taskObject) {
    this.queue.push(taskObject);
    // Batch Queue items into one call
    if (!this._busy_) {
        this._busy_ = true;
        setImmediate(() => {
            this._next_();
        });
    }
};

SuperTask.prototype._addTask = function ST__ADD_TASK(name, func, handler, type, callback) {
    if (typeof callback !== 'function') callback = noop;

    // Make sure Map Key is not taken
    if (this.map.has(name)) {
        return callback(new Error('Enable to create new task. A Task with the given name already exists.'));
    }

    // Add ST_DO function to the back with current context
    // & Create task
    var task = this._createTask(this, name, func, handler, type);
    // Add Task's model to Map
    this.map.set(name, task.model);

    callback(null, task);
};

SuperTask.prototype._compile = function ST__VM_COMPILE(task, context) {
    // Check if script is not compiled
    if (typeof task.func === 'string') {
        // Compile script using VM
        task.func = new vm.Script(task.func);
    }
    // Make sure we can call run on the compiled script
    if (typeof task.func.runInContext !== 'function') {
        return new Error("Unknown Error Occurred. Function property of Task is invalid or failed to compile.");
    }
    // Define module.exports and exports in context
    if (!context) context = {};
    context.module = {};
    context.exports = context.module.exports = {};

    // Create VM Context from context object
    vm.createContext(context);
    // Run Compiled Script
    task.func.runInContext(context);

    if (task.isModule) {
        // Make sure module.exports is set to a function
        // after script is run. Similar to how require(...)
        // modules work.
        if (typeof context.module.exports === 'function') {
            // Cache and Call the function
            task.func = context.module.exports;
            // Set isCompiled property to prevent recompilation
            task.isCompiled = true;

            return task.func;
        } else {
            return new Error("Compiled Script is not a valid foreign task or module. Failed to identify module.exports as a function.");
        }
    } else {
        return task.func;
    }
};

/**
 * Creates a new local Task. A local task is a task that is not
 * shared by any outside entity and usually performs slightly
 * faster than shared or foreign tasks as there is no compilation
 * or try/catch involved.
 *
 * @param {String} name - A unique name for this Task.
 * @param {Function} taskFunction - The JS function of the Task.
 * @param {Function} callback - Called once the task is added with
 * parameters `error` and `task`.
 */
SuperTask.prototype.addLocal = function ST_ADD_LOCAL(name, func, callback) {
    return this._addTask(name, func, null, ST_LOCAL_TYPE, callback);
};

/**
 * Creates a new foreign Task. A local task is a task that is not
 * shared by any outside entity and usually performs slightly
 * faster than shared or foreign tasks as there is no compilation
 * or try/catch involved.
 *
 * @param {String} name - A unique name for this Task.
 * @param {Function} taskFunction - The JS function or source with
 * module.exports to be used as the function. Note that sources are compiled
 * to a function before use with about a 30ms overhead on the first call unless
 * precompile method of task is called beforehand.
 * @param {Function} callback - Called once the task is added with
 * parameters `error` and `task`.
 */
SuperTask.prototype.addForeign = function ST_ADD_FOREIGN(name, source, callback) {
    // VM requires a String source to compile
    // If given source is a function convert it to source (context is lost)
    if (typeof source === 'function') {
        source = 'module.exports = ' + source.toString();
    }
    return this._addTask(name, source, null, ST_FOREIGN_TYPE, callback);
};

/**
 * Creates a shared Task. By default this is merely a directive
 * but can be used with a function handler to build shared tasks
 * on top of this module.
 *
 * @param {String} name - A unique name for this Task.
 * @param {(String|Function)} taskFunction - The JS function or source with
 * module.exports to be used as the function.
 * @param {Function} handler - A function that is called to execute this Task.
 * @param {Function} callback - Called once the task is added with
 * parameters `error` and `task`.
 */
SuperTask.prototype.addShared = function ST_ADD_SHARED(name, source, handler, callback) {
    // VM requires a String source to compile
    // If given source is a function convert it to source (context is lost)
    if (typeof source === 'function') {
        source = 'module.exports = ' + source.toString();
    }
    return this._addTask(name, source, handler, ST_SHARED_TYPE, callback);
};

SuperTask.prototype.addRemote = function ST_ADD_REMOTE(name, handler, callback) {
    this._addTask(name, handler, null, ST_FOREIGN_TYPE, function ST_REMOTE_CREATOR(error, task) {
        if (error) return callback(error);
        // Attach handler
        task.remote(true, handler);

        callback(error, task);
    });
};

/**
 * Run a task with the given arguments
 *
 * @param {...*} arguments - Arguments that are passed to the Task.
 * You can call this function with any number of arguments so long
 * as the last argument is the callback.
 * @param {Function} callback - The callback that handles the response.
 * Note that the callback parameters are based on what the function calls
 * the callback with but will include `error` as the first parameter as
 * per usual NodeJS async calls.
 */
SuperTask.prototype.do = function ST_DO() {
    var args = Array.prototype.slice.call(arguments);
    var name = args.shift();
    var callback = (typeof args[args.length - 1] === 'function') ? args.pop() : null;
    // Check for callback
    // Note that we only throw if strict is set to true
    if ((typeof callback !== 'function') && (this.strict === true)) throw new Error("A callback is required to execute a task. Pass a noop function if errors are intended to be ignored.");
    else if (typeof callback !== 'function') {
        callback = noop;
    }

    // Check for mapped task
    if (!this.map.has(name)) {
        callback(new Error('Task not found!'));
        return;
    }

    var task = this.map.get(name);
    // Set Context to task's default
    var context = task.defaultContext;
    // Combine Permissions Context (SLOWS DOWN EXECUTION)
    if ((task.access) && (task.access !== ST_NONE)) {
        context = this._extendContextFromPermissions(context || {}, task.access);
    }
    // Function executed on queue execution
    var preTracker = function ST_DO_PRETRACKER() {
        task.lastStarted = process.hrtime();
    };
    var postTracker = function ST_DO_POSTTRACKER(error) {
        // Calculate High Resolution time it took to run the function
        task.lastFinished = process.hrtime(task.lastStarted);
        // Calculate Time Difference
        task.lastDiff = task.lastFinished[0] * 1e9 + task.lastFinished[1];
        // Calculate Average Execution Time
        if (task.averageExecutionTime === -1) {
            task.averageExecutionTime = task.lastDiff;
        } else {
            task.averageExecutionTime = ((task.averageExecutionTime * task.executionRounds) + task.lastDiff) / (task.executionRounds + 1);
        }
        // Bump execution rounds
        task.executionRounds++;

        callback.apply(task, arguments);
    };
    // Sanitize args
    args = (Array.isArray(args)) ? args : [];

    // Create a Queue-able Clone of Task
    var Task = {};
    Task.name = name;
    Task.func = task.func;
    Task.handler = task.handler;
    Task.sandboxed = task.sandboxed;
    Task.averageExecutionTime = task.averageExecutionTime;
    Task.executionRounds = task.executionRounds;
    Task.local = task.local;
    Task.shared = task.shared;
    Task.context = context;
    Task.args = args;
    Task.pre = preTracker;
    Task.callback = postTracker;
    //

    // Compile task if it is in source form
    if (typeof Task.func !== 'function') {
        var result = this._compile(task, context);
        if (typeof result === 'function') Task.func = result;
        else if (result === true) return callback();
        else if (typeof result === 'object') return callback(result);
        else return callback(new Error("Unknown error occurred. Failed to compile and execution was halted."));
    }
    // Push to Queue
    this._push_(Task);
};

/**
 * Remove a task.
 *
 * @param {String} name - Name of the task.
 * @returns {Boolean} - Returns true if task
 * existed and was removed or false if task did not exist
 */
SuperTask.prototype.remove = function ST_REMOVE(name) {
    return this.map.delete(name);
};

/**
 * Check if task exists.
 *
 * @param {String} name - Name of the task.
 * @returns {Boolean} exists
 */
SuperTask.prototype.has = function ST_HAS(name) {
    return !!this.map.has(name);
};

/**
 * Get a wrapped version of the task.
 *
 * @param {String} name - Name of the task.
 * @returns {Object} task
 */
SuperTask.prototype.get = function ST_GET(name) {
    return this._wrapTask(this, this.map.get(name));
};

/// EXTEND PREDEFINED VARS
SuperTask.ST_LOCAL_TYPE = ST_LOCAL_TYPE;
SuperTask.ST_SHARED_TYPE = ST_SHARED_TYPE;
SuperTask.ST_FOREIGN_TYPE = ST_FOREIGN_TYPE;

/** No permissions. Code runs JS only. */
SuperTask.ST_NONE = ST_NONE;
/** Some permissions. Allows streams, Buffer, setTimeout, setInterval only */
SuperTask.ST_RESTRICTED = ST_RESTRICTED;
/** Minimal permissions. Allows all restricted permissions and __dirname, __filename, console globals.
 * Includes a limited require('*') function with access to 'http', 'https', 'util', 'os', 'path', 'events', 'stream', 'string_decoder', 'url', 'zlib'
 */
SuperTask.ST_MINIMAL = ST_MINIMAL;
/** UNSAFE, All permissions. Copies global scope. */
SuperTask.ST_UNRESTRICTED = ST_UNRESTRICTED;

module.exports = SuperTask;<commit_msg>Updated TaskModel & TaskObject references<commit_after>/// Required Core Modules
var vm = require('vm');
var eventEmmiter = require('events').EventEmitter;
var util = require('util');
///
/// External Modules
var Deque = require('double-ended-queue');
var defaultsDeep = require('lodash.defaultsdeep');
///
/// Internal Modules
var ContextPermissions = require('./lib/ContextPermissions');
var TaskObject = require('./lib/TaskObject');
///
/// Predefined Types
// TYPES
var ST_LOCAL_TYPE = 0, ST_SHARED_TYPE = 1, ST_FOREIGN_TYPE = 2;
// PERMISSIONS
var ST_NONE = 0, ST_RESTRICTED = 1, ST_MINIMAL = 2, ST_UNRESTRICTED = 3;
///
// No Operation function
function noop() { return null; }

/**
 * Creates new instance.
 * @constructor
 * @example
 * var SuperTask = require('supertask');
 * var TaskManager = new SuperTask();
 *
 * @returns {Instance} Returns a new instance of the module.
 */
var SuperTask = function ST_INIT(size, strict) {
    this._busy_ = false;
    this.map = new Map();
    this.queue = new Deque(parseInt(size, 10) || 10000);
    this.concurrency = 1000;
    this.strict = (!!strict);

    eventEmmiter.call(this);
};

util.inherits(SuperTask, eventEmmiter);

SuperTask.prototype._createTask = TaskObject.create;
SuperTask.prototype._wrapTask = TaskObject.wrap;

SuperTask.prototype._extendContextFromPermissions = ContextPermissions;

SuperTask.prototype._next_ = function ST__QUEUE_NEXT() {
    // Allow _next_ to be called
    this._busy_ = false;

    /* At this point the source is fully compiled
    /* to a function or a function is resupplied
    /* from cache to be executed. Here we transfer
    /* the given function (task.func) to the queue
    /* after attaching the pre tracker */

    // Do a batch
    for (var i = 0; i < Math.min(this.queue.length, this.concurrency); i++) {
        // Get a task
        var task = this.queue.shift();

        // Call preTracker
        task.pre();
        // Push Callback to args
        task.args.push(task.callback);
        // If task is shared call handler
        if (task.shared && task.handler) {
            // Assign task name to argument[0] followed by context
            task.args.unshift(task.context);
            task.args.unshift(task.name);
            task.handler.apply(null, task.args);
        } else {
            // Call local/remote Function with context & args
            if (task.sandboxed) {
                try {
                    task.func.apply(task.context, task.args);
                } catch (error) {
                    task.callback(error);
                }
            } else {
                task.func.apply(task.context, task.args);
            }
        }
    }

    // Keep executing until Queue is empty
    if (this.queue.length > 0) {
        // Do after I/O & Tasks are cleared
        setImmediate(() => { this._next_(); });
    }
};

SuperTask.prototype._push_ = function ST__QUEUE_ADD(taskObject) {
    this.queue.push(taskObject);
    // Batch Queue items into one call
    if (!this._busy_) {
        this._busy_ = true;
        setImmediate(() => {
            this._next_();
        });
    }
};

SuperTask.prototype._addTask = function ST__ADD_TASK(name, func, handler, type, callback) {
    if (typeof callback !== 'function') callback = noop;

    // Make sure Map Key is not taken
    if (this.map.has(name)) {
        return callback(new Error('Enable to create new task. A Task with the given name already exists.'));
    }

    // Add ST_DO function to the back with current context
    // & Create task
    var task = this._createTask(this, name, func, handler, type);
    // Add Task's model to Map
    this.map.set(name, task.model);

    callback(null, task);
};

SuperTask.prototype._compile = function ST__VM_COMPILE(task, context) {
    // Check if script is not compiled
    if (typeof task.func === 'string') {
        // Compile script using VM
        task.func = new vm.Script(task.func);
    }
    // Make sure we can call run on the compiled script
    if (typeof task.func.runInContext !== 'function') {
        return new Error("Unknown Error Occurred. Function property of Task is invalid or failed to compile.");
    }
    // Define module.exports and exports in context
    if (!context) context = {};
    context.module = {};
    context.exports = context.module.exports = {};

    // Create VM Context from context object
    vm.createContext(context);
    // Run Compiled Script
    task.func.runInContext(context);

    if (task.isModule) {
        // Make sure module.exports is set to a function
        // after script is run. Similar to how require(...)
        // modules work.
        if (typeof context.module.exports === 'function') {
            // Cache and Call the function
            task.func = context.module.exports;
            // Set isCompiled property to prevent recompilation
            task.isCompiled = true;

            return task.func;
        } else {
            return new Error("Compiled Script is not a valid foreign task or module. Failed to identify module.exports as a function.");
        }
    } else {
        return task.func;
    }
};

/**
 * Creates a new local Task. A local task is a task that is not
 * shared by any outside entity and usually performs slightly
 * faster than shared or foreign tasks as there is no compilation
 * or try/catch involved.
 *
 * @param {String} name - A unique name for this Task.
 * @param {Function} taskFunction - The JS function of the Task.
 * @param {Function} callback - Called once the task is added with
 * parameters `error` and `task`.
 */
SuperTask.prototype.addLocal = function ST_ADD_LOCAL(name, func, callback) {
    return this._addTask(name, func, null, ST_LOCAL_TYPE, callback);
};

/**
 * Creates a new foreign Task. A local task is a task that is not
 * shared by any outside entity and usually performs slightly
 * faster than shared or foreign tasks as there is no compilation
 * or try/catch involved.
 *
 * @param {String} name - A unique name for this Task.
 * @param {Function} taskFunction - The JS function or source with
 * module.exports to be used as the function. Note that sources are compiled
 * to a function before use with about a 30ms overhead on the first call unless
 * precompile method of task is called beforehand.
 * @param {Function} callback - Called once the task is added with
 * parameters `error` and `task`.
 */
SuperTask.prototype.addForeign = function ST_ADD_FOREIGN(name, source, callback) {
    // VM requires a String source to compile
    // If given source is a function convert it to source (context is lost)
    if (typeof source === 'function') {
        source = 'module.exports = ' + source.toString();
    }
    return this._addTask(name, source, null, ST_FOREIGN_TYPE, callback);
};

/**
 * Creates a shared Task. By default this is merely a directive
 * but can be used with a function handler to build shared tasks
 * on top of this module.
 *
 * @param {String} name - A unique name for this Task.
 * @param {(String|Function)} taskFunction - The JS function or source with
 * module.exports to be used as the function.
 * @param {Function} handler - A function that is called to execute this Task.
 * @param {Function} callback - Called once the task is added with
 * parameters `error` and `task`.
 */
SuperTask.prototype.addShared = function ST_ADD_SHARED(name, source, handler, callback) {
    // VM requires a String source to compile
    // If given source is a function convert it to source (context is lost)
    if (typeof source === 'function') {
        source = 'module.exports = ' + source.toString();
    }
    return this._addTask(name, source, handler, ST_SHARED_TYPE, callback);
};

SuperTask.prototype.addRemote = function ST_ADD_REMOTE(name, handler, callback) {
    this._addTask(name, handler, null, ST_FOREIGN_TYPE, function ST_REMOTE_CREATOR(error, task) {
        if (error) return callback(error);
        // Attach handler
        task.remote(true, handler);

        callback(error, task);
    });
};

/**
 * Run a task with the given arguments
 *
 * @param {...*} arguments - Arguments that are passed to the Task.
 * You can call this function with any number of arguments so long
 * as the last argument is the callback.
 * @param {Function} callback - The callback that handles the response.
 * Note that the callback parameters are based on what the function calls
 * the callback with but will include `error` as the first parameter as
 * per usual NodeJS async calls.
 */
SuperTask.prototype.do = function ST_DO() {
    var args = Array.prototype.slice.call(arguments);
    var name = args.shift();
    var callback = (typeof args[args.length - 1] === 'function') ? args.pop() : null;
    // Check for callback
    // Note that we only throw if strict is set to true
    if ((typeof callback !== 'function') && (this.strict === true)) throw new Error("A callback is required to execute a task. Pass a noop function if errors are intended to be ignored.");
    else if (typeof callback !== 'function') {
        callback = noop;
    }

    // Check for mapped task
    if (!this.map.has(name)) {
        callback(new Error('Task not found!'));
        return;
    }

    var task = this.map.get(name);
    // Set Context to task's default
    var context = task.defaultContext;
    // Combine Permissions Context (SLOWS DOWN EXECUTION)
    if ((task.access) && (task.access !== ST_NONE)) {
        context = this._extendContextFromPermissions(context || {}, task.access);
    }
    // Function executed on queue execution
    var preTracker = function ST_DO_PRETRACKER() {
        task.lastStarted = process.hrtime();
    };
    var postTracker = function ST_DO_POSTTRACKER(error) {
        // Calculate High Resolution time it took to run the function
        task.lastFinished = process.hrtime(task.lastStarted);
        // Calculate Time Difference
        task.lastDiff = task.lastFinished[0] * 1e9 + task.lastFinished[1];
        // Calculate Average Execution Time
        if (task.averageExecutionTime === -1) {
            task.averageExecutionTime = task.lastDiff;
        } else {
            task.averageExecutionTime = ((task.averageExecutionTime * task.executionRounds) + task.lastDiff) / (task.executionRounds + 1);
        }
        // Bump execution rounds
        task.executionRounds++;

        callback.apply(task, arguments);
    };
    // Sanitize args
    args = (Array.isArray(args)) ? args : [];

    // Create a Queue-able Clone of Task
    var Task = {};
    Task.name = name;
    Task.func = task.func;
    Task.handler = task.handler;
    Task.sandboxed = task.sandboxed;
    Task.averageExecutionTime = task.averageExecutionTime;
    Task.executionRounds = task.executionRounds;
    Task.local = task.local;
    Task.shared = task.shared;
    Task.context = context;
    Task.args = args;
    Task.pre = preTracker;
    Task.callback = postTracker;
    //

    // Compile task if it is in source form
    if (typeof Task.func !== 'function') {
        var result = this._compile(task, context);
        if (typeof result === 'function') Task.func = result;
        else if (result === true) return callback();
        else if (typeof result === 'object') return callback(result);
        else return callback(new Error("Unknown error occurred. Failed to compile and execution was halted."));
    }
    // Push to Queue
    this._push_(Task);
};

/**
 * Remove a task.
 *
 * @param {String} name - Name of the task.
 * @returns {Boolean} - Returns true if task
 * existed and was removed or false if task did not exist
 */
SuperTask.prototype.remove = function ST_REMOVE(name) {
    return this.map.delete(name);
};

/**
 * Check if task exists.
 *
 * @param {String} name - Name of the task.
 * @returns {Boolean} exists
 */
SuperTask.prototype.has = function ST_HAS(name) {
    return !!this.map.has(name);
};

/**
 * Get a wrapped version of the task.
 *
 * @param {String} name - Name of the task.
 * @returns {Object} task
 */
SuperTask.prototype.get = function ST_GET(name) {
    return this._wrapTask(this, this.map.get(name));
};

/// EXTEND PREDEFINED VARS
SuperTask.ST_LOCAL_TYPE = ST_LOCAL_TYPE;
SuperTask.ST_SHARED_TYPE = ST_SHARED_TYPE;
SuperTask.ST_FOREIGN_TYPE = ST_FOREIGN_TYPE;

/** No permissions. Code runs JS only. */
SuperTask.ST_NONE = ST_NONE;
/** Some permissions. Allows streams, Buffer, setTimeout, setInterval only */
SuperTask.ST_RESTRICTED = ST_RESTRICTED;
/** Minimal permissions. Allows all restricted permissions and __dirname, __filename, console globals.
 * Includes a limited require('*') function with access to 'http', 'https', 'util', 'os', 'path', 'events', 'stream', 'string_decoder', 'url', 'zlib'
 */
SuperTask.ST_MINIMAL = ST_MINIMAL;
/** UNSAFE, All permissions. Copies global scope. */
SuperTask.ST_UNRESTRICTED = ST_UNRESTRICTED;

module.exports = SuperTask;<|endoftext|>


<commit_before>import updateGeometry from '../update-geometry';
import { env } from '../lib/util';

export default function(i) {
  if (!env.supportsTouch && !env.supportsIePointer) {
    return;
  }

  const element = i.element;

  function shouldPrevent(deltaX, deltaY) {
    const scrollTop = element.scrollTop;
    const scrollLeft = element.scrollLeft;
    const magnitudeX = Math.abs(deltaX);
    const magnitudeY = Math.abs(deltaY);

    if (magnitudeY > magnitudeX) {
      // user is perhaps trying to swipe up/down the page

      if (
        (deltaY < 0 && scrollTop === i.contentHeight - i.containerHeight) ||
        (deltaY > 0 && scrollTop === 0)
      ) {
        // set prevent for mobile Chrome refresh
        return window.scrollY === 0 && deltaY > 0 && env.isChrome;
      }
    } else if (magnitudeX > magnitudeY) {
      // user is perhaps trying to swipe left/right across the page

      if (
        (deltaX < 0 && scrollLeft === i.contentWidth - i.containerWidth) ||
        (deltaX > 0 && scrollLeft === 0)
      ) {
        return true;
      }
    }

    return true;
  }

  function applyTouchMove(differenceX, differenceY) {
    element.scrollTop -= differenceY;
    element.scrollLeft -= differenceX;

    updateGeometry(i);
  }

  let startOffset = {};
  let startTime = 0;
  let speed = {};
  let easingLoop = null;

  function getTouch(e) {
    if (e.targetTouches) {
      return e.targetTouches[0];
    } else {
      // Maybe IE pointer
      return e;
    }
  }

  function shouldHandle(e) {
    if (e.pointerType && e.pointerType === 'pen' && e.buttons === 0) {
      return false;
    }
    if (e.targetTouches && e.targetTouches.length === 1) {
      return true;
    }
    if (
      e.pointerType &&
      e.pointerType !== 'mouse' &&
      e.pointerType !== e.MSPOINTER_TYPE_MOUSE
    ) {
      return true;
    }
    return false;
  }

  function touchStart(e) {
    if (!shouldHandle(e)) {
      return;
    }

    const touch = getTouch(e);

    startOffset.pageX = touch.pageX;
    startOffset.pageY = touch.pageY;

    startTime = new Date().getTime();

    if (easingLoop !== null) {
      clearInterval(easingLoop);
    }
  }

  function touchMove(e) {
    if (shouldHandle(e)) {
      const touch = getTouch(e);

      const currentOffset = { pageX: touch.pageX, pageY: touch.pageY };

      const differenceX = currentOffset.pageX - startOffset.pageX;
      const differenceY = currentOffset.pageY - startOffset.pageY;

      applyTouchMove(differenceX, differenceY);
      startOffset = currentOffset;

      const currentTime = new Date().getTime();

      const timeGap = currentTime - startTime;
      if (timeGap > 0) {
        speed.x = differenceX / timeGap;
        speed.y = differenceY / timeGap;
        startTime = currentTime;
      }

      if (shouldPrevent(differenceX, differenceY)) {
        e.preventDefault();
      }
    }
  }
  function touchEnd() {
    if (i.settings.swipeEasing) {
      clearInterval(easingLoop);
      easingLoop = setInterval(function() {
        if (i.isInitialized) {
          clearInterval(easingLoop);
          return;
        }

        if (!speed.x && !speed.y) {
          clearInterval(easingLoop);
          return;
        }

        if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
          clearInterval(easingLoop);
          return;
        }

        applyTouchMove(speed.x * 30, speed.y * 30);

        speed.x *= 0.8;
        speed.y *= 0.8;
      }, 10);
    }
  }

  if (env.supportsTouch) {
    i.event.bind(element, 'touchstart', touchStart);
    i.event.bind(element, 'touchmove', touchMove);
    i.event.bind(element, 'touchend', touchEnd);
  } else if (env.supportsIePointer) {
    if (window.PointerEvent) {
      i.event.bind(element, 'pointerdown', touchStart);
      i.event.bind(element, 'pointermove', touchMove);
      i.event.bind(element, 'pointerup', touchEnd);
    } else if (window.MSPointerEvent) {
      i.event.bind(element, 'MSPointerDown', touchStart);
      i.event.bind(element, 'MSPointerMove', touchMove);
      i.event.bind(element, 'MSPointerUp', touchEnd);
    }
  }
}
<commit_msg>Make nested scrolls work with touch<commit_after>import updateGeometry from '../update-geometry';
import cls from '../lib/class-names';
import * as CSS from '../lib/css';
import { env } from '../lib/util';

export default function(i) {
  if (!env.supportsTouch && !env.supportsIePointer) {
    return;
  }

  const element = i.element;

  function shouldPrevent(deltaX, deltaY) {
    const scrollTop = element.scrollTop;
    const scrollLeft = element.scrollLeft;
    const magnitudeX = Math.abs(deltaX);
    const magnitudeY = Math.abs(deltaY);

    if (magnitudeY > magnitudeX) {
      // user is perhaps trying to swipe up/down the page

      if (
        (deltaY < 0 && scrollTop === i.contentHeight - i.containerHeight) ||
        (deltaY > 0 && scrollTop === 0)
      ) {
        // set prevent for mobile Chrome refresh
        return window.scrollY === 0 && deltaY > 0 && env.isChrome;
      }
    } else if (magnitudeX > magnitudeY) {
      // user is perhaps trying to swipe left/right across the page

      if (
        (deltaX < 0 && scrollLeft === i.contentWidth - i.containerWidth) ||
        (deltaX > 0 && scrollLeft === 0)
      ) {
        return true;
      }
    }

    return true;
  }

  function applyTouchMove(differenceX, differenceY) {
    element.scrollTop -= differenceY;
    element.scrollLeft -= differenceX;

    updateGeometry(i);
  }

  let startOffset = {};
  let startTime = 0;
  let speed = {};
  let easingLoop = null;

  function getTouch(e) {
    if (e.targetTouches) {
      return e.targetTouches[0];
    } else {
      // Maybe IE pointer
      return e;
    }
  }

  function shouldHandle(e) {
    if (e.pointerType && e.pointerType === 'pen' && e.buttons === 0) {
      return false;
    }
    if (e.targetTouches && e.targetTouches.length === 1) {
      return true;
    }
    if (
      e.pointerType &&
      e.pointerType !== 'mouse' &&
      e.pointerType !== e.MSPOINTER_TYPE_MOUSE
    ) {
      return true;
    }
    return false;
  }

  function touchStart(e) {
    if (!shouldHandle(e)) {
      return;
    }

    const touch = getTouch(e);

    startOffset.pageX = touch.pageX;
    startOffset.pageY = touch.pageY;

    startTime = new Date().getTime();

    if (easingLoop !== null) {
      clearInterval(easingLoop);
    }
  }

  function shouldBeConsumedByChild(target, deltaX, deltaY) {
    if (!element.contains(target)) {
      return false;
    }

    let cursor = target;

    while (cursor && cursor !== element) {
      if (cursor.classList.contains(cls.element.consuming)) {
        return true;
      }

      const style = CSS.get(cursor);
      const overflow = [style.overflow, style.overflowX, style.overflowY].join(
        ''
      );

      // if scrollable
      if (overflow.match(/(scroll|auto)/)) {
        const maxScrollTop = cursor.scrollHeight - cursor.clientHeight;
        if (maxScrollTop > 0) {
          if (
            !(cursor.scrollTop === 0 && deltaY > 0) &&
            !(cursor.scrollTop === maxScrollTop && deltaY < 0)
          ) {
            return true;
          }
        }
        const maxScrollLeft = cursor.scrollLeft - cursor.clientWidth;
        if (maxScrollLeft > 0) {
          if (
            !(cursor.scrollLeft === 0 && deltaX < 0) &&
            !(cursor.scrollLeft === maxScrollLeft && deltaX > 0)
          ) {
            return true;
          }
        }
      }

      cursor = cursor.parentNode;
    }

    return false;
  }

  function touchMove(e) {
    if (shouldHandle(e)) {
      const touch = getTouch(e);

      const currentOffset = { pageX: touch.pageX, pageY: touch.pageY };

      const differenceX = currentOffset.pageX - startOffset.pageX;
      const differenceY = currentOffset.pageY - startOffset.pageY;

      if (shouldBeConsumedByChild(e.target, differenceX, differenceY)) {
        return;
      }

      applyTouchMove(differenceX, differenceY);
      startOffset = currentOffset;

      const currentTime = new Date().getTime();

      const timeGap = currentTime - startTime;
      if (timeGap > 0) {
        speed.x = differenceX / timeGap;
        speed.y = differenceY / timeGap;
        startTime = currentTime;
      }

      if (shouldPrevent(differenceX, differenceY)) {
        e.preventDefault();
      }
    }
  }
  function touchEnd() {
    if (i.settings.swipeEasing) {
      clearInterval(easingLoop);
      easingLoop = setInterval(function() {
        if (i.isInitialized) {
          clearInterval(easingLoop);
          return;
        }

        if (!speed.x && !speed.y) {
          clearInterval(easingLoop);
          return;
        }

        if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
          clearInterval(easingLoop);
          return;
        }

        applyTouchMove(speed.x * 30, speed.y * 30);

        speed.x *= 0.8;
        speed.y *= 0.8;
      }, 10);
    }
  }

  if (env.supportsTouch) {
    i.event.bind(element, 'touchstart', touchStart);
    i.event.bind(element, 'touchmove', touchMove);
    i.event.bind(element, 'touchend', touchEnd);
  } else if (env.supportsIePointer) {
    if (window.PointerEvent) {
      i.event.bind(element, 'pointerdown', touchStart);
      i.event.bind(element, 'pointermove', touchMove);
      i.event.bind(element, 'pointerup', touchEnd);
    } else if (window.MSPointerEvent) {
      i.event.bind(element, 'MSPointerDown', touchStart);
      i.event.bind(element, 'MSPointerMove', touchMove);
      i.event.bind(element, 'MSPointerUp', touchEnd);
    }
  }
}
<|endoftext|>


<commit_before>goog.provide('gmf.AbstractController');

goog.require('gmf');
/** @suppress {extraRequire} */
goog.require('gmf.authenticationDirective');
/** @suppress {extraRequire} */
goog.require('gmf.backgroundlayerselectorDirective');
/** @suppress {extraRequire} */
goog.require('gmf.QueryManager');
/** @suppress {extraRequire} */
goog.require('gmf.TreeManager');
/** @suppress {extraRequire} */
goog.require('gmf.Themes');
/** @suppress {extraRequire} */
goog.require('gmf.disclaimerDirective');
/** @suppress {extraRequire} */
goog.require('gmf.displayquerywindowDirective');
/** @suppress {extraRequire} */
goog.require('gmf.layertreeDirective');
/** @suppress {extraRequire} */
goog.require('gmf.mapDirective');
/** @suppress {extraRequire} */
goog.require('gmf.searchDirective');
/** @suppress {extraRequire} */
goog.require('gmf.themeselectorDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.BackgroundLayerMgr');
/** @suppress {extraRequire} */
goog.require('ngeo.filters');
/** @suppress {extraRequire} */
goog.require('ngeo.mapQueryDirective');
goog.require('ngeo.FeatureOverlayMgr');
goog.require('ngeo.GetBrowserLanguage');
goog.require('ngeo.Query');
goog.require('ngeo.StateManager');
goog.require('ngeo.ToolActivate');
goog.require('ngeo.ToolActivateMgr');
goog.require('ol.style.Circle');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');

gmf.module.value('ngeoExportFeatureFormats', [
  ngeo.FeatureHelper.FormatType.KML,
  ngeo.FeatureHelper.FormatType.GPX
]);

// Filter to apply by default on all coordinates (such points in draw).
gmf.module.value('ngeoPointfilter', 'ngeoNumberCoordinates:0:{x} E, {y} N');

gmf.module.value('ngeoQueryOptions', {
  'limit': 20
});

/**
 * Application abstract controller.
 *
 * This file includes `goog.require` for base components/directives used
 * by the HTML page and the controller to provide the configuration.
 *
 * @param {gmfx.Config} config A part of the application config.
 * @param {angular.Scope} $scope Scope.
 * @param {angular.$injector} $injector Main injector.
 * @constructor
 * @ngInject
 * @export
 */
gmf.AbstractController = function(config, $scope, $injector) {

  /**
   * Location service
   * @type {ngeo.Location}
   */
  this.ngeoLocation = $injector.get('ngeoLocation');
  if (this.ngeoLocation.hasParam('debug')) {
    // make the injector globally available
    window.injector = $injector;
  }

  goog.asserts.assertInstanceof(this.map, ol.Map);

  /**
   * Ngeo FeatureHelper service
   * @type {ngeo.FeatureHelper}
   */
  var ngeoFeatureHelper = $injector.get('ngeoFeatureHelper');
  ngeoFeatureHelper.setProjection(this.map.getView().getProjection());

  var gmfTreeManager = $injector.get('gmfTreeManager');
  /**
   * A reference to the current theme
   * @type {GmfThemesNode}
   * @export
   */
  this.theme = gmfTreeManager.tree;

  /**
   * Themes service
   * @type {gmf.Themes}
   */
  var gmfThemes = $injector.get('gmfThemes');

  /**
   * Authentication service
   * @type {gmf.Authentication}
   */
  var gmfAuthentication = $injector.get('gmfAuthentication');

  var userChange = function(evt) {
    var roleId = (evt.user.username !== null) ? evt.user.role_id : undefined;
    // Reload background layer when login status changes.
    this.updateCurrentBackgroundLayer_(true);
    // Reload themes when login status changes.
    gmfThemes.loadThemes(roleId);
    this.updateHasEditableLayers_();
  }.bind(this);

  ol.events.listen(gmfAuthentication, gmf.AuthenticationEventType.READY, userChange);
  ol.events.listen(gmfAuthentication, gmf.AuthenticationEventType.LOGIN, userChange);
  ol.events.listen(gmfAuthentication, gmf.AuthenticationEventType.LOGOUT, userChange);

  /**
   * @type {Array.<gmfx.SearchDirectiveDatasource>}
   * @export
   */
  this.searchDatasources = [{
    labelKey: 'label',
    groupValues: /** @type {Array.<string>} **/ ($injector.get('gmfSearchGroups')),
    groupActions: /** @type {Array.<string>} **/ ($injector.get('gmfSearchActions')),
    projection: 'EPSG:' + (config.srid || 21781),
    url: /** @type {string} **/ ($injector.get('fulltextsearchUrl'))
  }];

  /**
   * @type {Object.<string, string>}
   * @export
   */
  this.dimensions = {};

  var permalink = $injector.get('gmfPermalink');

  // watch any change on dimensions object to refresh the url
  permalink.setDimensions(this.dimensions);

  if ($injector.has('gmfDefaultDimensions')) {
    // Set defaults
    var defaultDimensions = $injector.get('gmfDefaultDimensions');
    for (var dim in defaultDimensions) {
      if (this.dimensions[dim] === undefined) {
        this.dimensions[dim] = defaultDimensions[dim];
      }
    }
  }

  var backgroundLayerMgr = $injector.get('ngeoBackgroundLayerMgr');

  // watch any change on dimensions object to refresh the background layer
  $scope.$watchCollection(function() {
    return this.dimensions;
  }.bind(this), function() {
    backgroundLayerMgr.updateDimensions(this.map, this.dimensions);
  }.bind(this));

  /**
   * @type {boolean}
   * @export
   */
  this.leftNavVisible = false;

  /**
   * @type {boolean}
   * @export
   */
  this.rightNavVisible = false;

  // Not used in this file but the QueryManager must be injected to be watched.
  $injector.get('gmfQueryManager');

  var queryFill = new ol.style.Fill({color: [255, 170, 0, 0.6]});
  var queryStroke = new ol.style.Stroke({color: [255, 170, 0, 1], width: 2});

  /**
   * FeatureStyle used by the displayquerywindow directive
   * @type {ol.style.Style}
   * @export
   */
  this.queryFeatureStyle = new ol.style.Style({
    fill: queryFill,
    image: new ol.style.Circle({
      fill: queryFill,
      radius: 5,
      stroke: queryStroke
    }),
    stroke: queryStroke
  });

  /**
   * The active state of the ngeo query directive.
   * @type {boolean}
   * @export
   */
  this.queryActive = true;

  /**
   * Set the clearing of the ngeoQuery after the deactivation of the query
   * @type {boolean}
   * @export
   */
  this.queryAutoClear = true;

  /**
   * @type {boolean}
   * @export
   */
  this.printPanelActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.printActive = false;

  /**
   * @type {ngeo.Query}
   * @private
   */
  this.ngeoQuery_ = $injector.get('ngeoQuery');

  // Don't deactivate ngeoQuery on print activation
  $scope.$watch(function() {
    return this.printPanelActive;
  }.bind(this), function(newVal) {
    // Clear queries if another panel is open but not if user go back to the
    // map form the print.
    if (!newVal && !this.queryActive) {
      this.ngeoQuery_.clear();
    }
    this.queryAutoClear = !newVal;
    this.printActive = newVal;
  }.bind(this));

  /**
   * The active state of the directive responsible of point measurements.
   * @type {boolean}
   * @export
   */
  this.measurePointActive = false;

  /**
   * The active state of the directive responsible of length measurements.
   * @type {boolean}
   * @export
   */
  this.measureLengthActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.drawFeatureActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.drawProfilePanelActive = false;

  /**
   * @type {gmfx.User}
   * @export
   */
  this.gmfUser = $injector.get('gmfUser');

  // close right nave on successful login
  $scope.$watch(function() {
    return this.gmfUser.username;
  }.bind(this), function(newVal) {
    if (newVal !== null && this.navIsVisible) {
      this.rightNavVisible = false;
    }
  }.bind(this));

  /**
   * @type {ngeo.GetBrowserLanguage}
   */
  this.getBrowserLanguage = $injector.get('ngeoGetBrowserLanguage');

  /**
   * @type {ngeo.StateManager}
   */
  this.stateManager = $injector.get('ngeoStateManager');

  /**
   * @type {tmhDynamicLocale}
   */
  this.tmhDynamicLocale = $injector.get('tmhDynamicLocale');

  /**
   * @type {angular.Scope}
   */
  this.$scope = $scope;

  /**
   * Default language
   * @type {string}
   */
  this.defaultLang = $injector.get('defaultLang');

  /**
   * Languages URL
   * @type {!Object.<string, string>}
   */
  this.langUrls = $injector.get('langUrls');

  /**
   * The gettext catalog
   * @type {angularGettext.Catalog}
   */
  this.gettextCatalog = $injector.get('gettextCatalog');

  this.initLanguage();

  /**
   * The ngeo feature overlay manager service
   * @type {ngeo.FeatureOverlayMgr}
   */
  var ngeoFeatureOverlayMgr = $injector.get('ngeoFeatureOverlayMgr');
  ngeoFeatureOverlayMgr.init(this.map);

  /**
   * The ngeo ToolActivate manager service.
   * @type {ngeo.ToolActivateMgr}
   */
  var ngeoToolActivateMgr = $injector.get('ngeoToolActivateMgr');

  var queryToolActivate = new ngeo.ToolActivate(this, 'queryActive');
  ngeoToolActivateMgr.registerTool('mapTools', queryToolActivate, true);

  var measurePointActivate = new ngeo.ToolActivate(this, 'measurePointActive');
  ngeoToolActivateMgr.registerTool('mapTools', measurePointActivate, false);

  var measureLengthActivate = new ngeo.ToolActivate(this, 'measureLengthActive');
  ngeoToolActivateMgr.registerTool('mapTools', measureLengthActivate, false);

  var drawFeatureActivate = new ngeo.ToolActivate(this, 'drawFeatureActive');
  ngeoToolActivateMgr.registerTool('mapTools', drawFeatureActivate, false);

  var drawProfilePanelActivate = new ngeo.ToolActivate(this, 'drawProfilePanelActive');
  ngeoToolActivateMgr.registerTool('mapTools', drawProfilePanelActivate, false);

  var printPanelActivate = new ngeo.ToolActivate(this, 'printPanelActive');
  ngeoToolActivateMgr.registerTool('mapTools', printPanelActivate, false);

  $scope.$watch(function() {
    return this.theme.name;
  }.bind(this), function(name) {
    var map = this.map;
    gmfThemes.getThemeObject(name).then(function(theme) {
      if (theme) {
        var backgrounds = theme['functionalities']['default_basemap'];
        if (backgrounds && backgrounds.length > 0) {
          var background = backgrounds[0];
          gmfThemes.getBgLayers(this.dimensions).then(function(layers) {
            var layer = ol.array.find(layers, function(layer) {
              return layer.get('label') === background;
            });
            if (layer) {
              backgroundLayerMgr.set(map, layer);
            }
          });
        }
      }
    });
  }.bind(this));

  /**
   * @param {boolean} skipPermalink If True, don't use permalink
   * background layer.
   * @private
   */
  this.updateCurrentBackgroundLayer_ = function(skipPermalink) {
    gmfThemes.getBgLayers(this.dimensions).then(function(layers) {
      var background;
      if (!skipPermalink) {
        // get the background from the permalink
        background = permalink.getBackgroundLayer(layers);
      }
      if (!background) {
        // get the background from the user settings
        var functionalities = this.gmfUser.functionalities;
        if (functionalities) {
          var defaultBasemapArray = functionalities.default_basemap;
          if (defaultBasemapArray.length > 0) {
            var defaultBasemapLabel = defaultBasemapArray[0];
            background = ol.array.find(layers, function(layer) {
              return layer.get('label') === defaultBasemapLabel;
            });
          }
        }
      }
      if (!background && layers[1]) {
        // fallback to the layers list, use the second one because the first
        // is the blank layer
        background = layers[1];
      }

      if (background) {
        backgroundLayerMgr.set(this.map, background);
      }
    }.bind(this));
  };

  this.updateCurrentBackgroundLayer_(false);

  /**
   * @type {boolean}
   * @export
   */
  this.hasEditableLayers = true;

  /**
   * @private
   */
  this.updateHasEditableLayers_ = function() {
    gmfThemes.hasEditableLayers().then(function(hasEditableLayers) {
      this.hasEditableLayers = hasEditableLayers;
    }.bind(this));
  };
};

/**
 * @param {string} lang Language code.
 * @export
 */
gmf.AbstractController.prototype.switchLanguage = function(lang) {
  goog.asserts.assert(lang in this.langUrls);
  this.gettextCatalog.setCurrentLanguage(lang);
  this.gettextCatalog.loadRemote(this.langUrls[lang]);
  this.tmhDynamicLocale.set(lang);
  this['lang'] = lang;
};

/**
 */
gmf.AbstractController.prototype.initLanguage = function() {
  this.$scope.$watch(function() {
    return this['lang'];
  }.bind(this), function(newValue) {
    this.stateManager.updateState({
      'lang': newValue
    });
  }.bind(this));

  var browserLanguage = /** @type {string|undefined} */
      (this.getBrowserLanguage(Object.keys(this.langUrls)));
  var urlLanguage = /** @type {string|undefined} */
      (this.stateManager.getInitialValue('lang'));

  if (urlLanguage !== undefined && urlLanguage in this.langUrls) {
    this.switchLanguage(urlLanguage);
    return;
  } else if (browserLanguage !== undefined && browserLanguage in this.langUrls) {
    this.switchLanguage(browserLanguage);
    return;
  } else {
    // if there is no information about language preference,
    // fallback to default language

    this.switchLanguage(this.defaultLang);
    return;
  }
};

gmf.module.controller('AbstractController', gmf.AbstractController);
<commit_msg>Bind this in some places<commit_after>goog.provide('gmf.AbstractController');

goog.require('gmf');
/** @suppress {extraRequire} */
goog.require('gmf.authenticationDirective');
/** @suppress {extraRequire} */
goog.require('gmf.backgroundlayerselectorDirective');
/** @suppress {extraRequire} */
goog.require('gmf.QueryManager');
/** @suppress {extraRequire} */
goog.require('gmf.TreeManager');
/** @suppress {extraRequire} */
goog.require('gmf.Themes');
/** @suppress {extraRequire} */
goog.require('gmf.disclaimerDirective');
/** @suppress {extraRequire} */
goog.require('gmf.displayquerywindowDirective');
/** @suppress {extraRequire} */
goog.require('gmf.layertreeDirective');
/** @suppress {extraRequire} */
goog.require('gmf.mapDirective');
/** @suppress {extraRequire} */
goog.require('gmf.searchDirective');
/** @suppress {extraRequire} */
goog.require('gmf.themeselectorDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.BackgroundLayerMgr');
/** @suppress {extraRequire} */
goog.require('ngeo.filters');
/** @suppress {extraRequire} */
goog.require('ngeo.mapQueryDirective');
goog.require('ngeo.FeatureOverlayMgr');
goog.require('ngeo.GetBrowserLanguage');
goog.require('ngeo.Query');
goog.require('ngeo.StateManager');
goog.require('ngeo.ToolActivate');
goog.require('ngeo.ToolActivateMgr');
goog.require('ol.style.Circle');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');

gmf.module.value('ngeoExportFeatureFormats', [
  ngeo.FeatureHelper.FormatType.KML,
  ngeo.FeatureHelper.FormatType.GPX
]);

// Filter to apply by default on all coordinates (such points in draw).
gmf.module.value('ngeoPointfilter', 'ngeoNumberCoordinates:0:{x} E, {y} N');

gmf.module.value('ngeoQueryOptions', {
  'limit': 20
});

/**
 * Application abstract controller.
 *
 * This file includes `goog.require` for base components/directives used
 * by the HTML page and the controller to provide the configuration.
 *
 * @param {gmfx.Config} config A part of the application config.
 * @param {angular.Scope} $scope Scope.
 * @param {angular.$injector} $injector Main injector.
 * @constructor
 * @ngInject
 * @export
 */
gmf.AbstractController = function(config, $scope, $injector) {

  /**
   * Location service
   * @type {ngeo.Location}
   */
  this.ngeoLocation = $injector.get('ngeoLocation');
  if (this.ngeoLocation.hasParam('debug')) {
    // make the injector globally available
    window.injector = $injector;
  }

  goog.asserts.assertInstanceof(this.map, ol.Map);

  /**
   * Ngeo FeatureHelper service
   * @type {ngeo.FeatureHelper}
   */
  var ngeoFeatureHelper = $injector.get('ngeoFeatureHelper');
  ngeoFeatureHelper.setProjection(this.map.getView().getProjection());

  var gmfTreeManager = $injector.get('gmfTreeManager');
  /**
   * A reference to the current theme
   * @type {GmfThemesNode}
   * @export
   */
  this.theme = gmfTreeManager.tree;

  /**
   * Themes service
   * @type {gmf.Themes}
   */
  var gmfThemes = $injector.get('gmfThemes');

  /**
   * Authentication service
   * @type {gmf.Authentication}
   */
  var gmfAuthentication = $injector.get('gmfAuthentication');

  var userChange = function(evt) {
    var roleId = (evt.user.username !== null) ? evt.user.role_id : undefined;
    // Reload background layer when login status changes.
    this.updateCurrentBackgroundLayer_(true);
    // Reload themes when login status changes.
    gmfThemes.loadThemes(roleId);
    this.updateHasEditableLayers_();
  }.bind(this);

  ol.events.listen(gmfAuthentication, gmf.AuthenticationEventType.READY, userChange);
  ol.events.listen(gmfAuthentication, gmf.AuthenticationEventType.LOGIN, userChange);
  ol.events.listen(gmfAuthentication, gmf.AuthenticationEventType.LOGOUT, userChange);

  /**
   * @type {Array.<gmfx.SearchDirectiveDatasource>}
   * @export
   */
  this.searchDatasources = [{
    labelKey: 'label',
    groupValues: /** @type {Array.<string>} **/ ($injector.get('gmfSearchGroups')),
    groupActions: /** @type {Array.<string>} **/ ($injector.get('gmfSearchActions')),
    projection: 'EPSG:' + (config.srid || 21781),
    url: /** @type {string} **/ ($injector.get('fulltextsearchUrl'))
  }];

  /**
   * @type {Object.<string, string>}
   * @export
   */
  this.dimensions = {};

  var permalink = $injector.get('gmfPermalink');

  // watch any change on dimensions object to refresh the url
  permalink.setDimensions(this.dimensions);

  if ($injector.has('gmfDefaultDimensions')) {
    // Set defaults
    var defaultDimensions = $injector.get('gmfDefaultDimensions');
    for (var dim in defaultDimensions) {
      if (this.dimensions[dim] === undefined) {
        this.dimensions[dim] = defaultDimensions[dim];
      }
    }
  }

  var backgroundLayerMgr = $injector.get('ngeoBackgroundLayerMgr');

  // watch any change on dimensions object to refresh the background layer
  $scope.$watchCollection(function() {
    return this.dimensions;
  }.bind(this), function() {
    backgroundLayerMgr.updateDimensions(this.map, this.dimensions);
  }.bind(this));

  /**
   * @type {boolean}
   * @export
   */
  this.leftNavVisible = false;

  /**
   * @type {boolean}
   * @export
   */
  this.rightNavVisible = false;

  // Not used in this file but the QueryManager must be injected to be watched.
  $injector.get('gmfQueryManager');

  var queryFill = new ol.style.Fill({color: [255, 170, 0, 0.6]});
  var queryStroke = new ol.style.Stroke({color: [255, 170, 0, 1], width: 2});

  /**
   * FeatureStyle used by the displayquerywindow directive
   * @type {ol.style.Style}
   * @export
   */
  this.queryFeatureStyle = new ol.style.Style({
    fill: queryFill,
    image: new ol.style.Circle({
      fill: queryFill,
      radius: 5,
      stroke: queryStroke
    }),
    stroke: queryStroke
  });

  /**
   * The active state of the ngeo query directive.
   * @type {boolean}
   * @export
   */
  this.queryActive = true;

  /**
   * Set the clearing of the ngeoQuery after the deactivation of the query
   * @type {boolean}
   * @export
   */
  this.queryAutoClear = true;

  /**
   * @type {boolean}
   * @export
   */
  this.printPanelActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.printActive = false;

  /**
   * @type {ngeo.Query}
   * @private
   */
  this.ngeoQuery_ = $injector.get('ngeoQuery');

  // Don't deactivate ngeoQuery on print activation
  $scope.$watch(function() {
    return this.printPanelActive;
  }.bind(this), function(newVal) {
    // Clear queries if another panel is open but not if user go back to the
    // map form the print.
    if (!newVal && !this.queryActive) {
      this.ngeoQuery_.clear();
    }
    this.queryAutoClear = !newVal;
    this.printActive = newVal;
  }.bind(this));

  /**
   * The active state of the directive responsible of point measurements.
   * @type {boolean}
   * @export
   */
  this.measurePointActive = false;

  /**
   * The active state of the directive responsible of length measurements.
   * @type {boolean}
   * @export
   */
  this.measureLengthActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.drawFeatureActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.drawProfilePanelActive = false;

  /**
   * @type {gmfx.User}
   * @export
   */
  this.gmfUser = $injector.get('gmfUser');

  // close right nave on successful login
  $scope.$watch(function() {
    return this.gmfUser.username;
  }.bind(this), function(newVal) {
    if (newVal !== null && this.navIsVisible) {
      this.rightNavVisible = false;
    }
  }.bind(this));

  /**
   * @type {ngeo.GetBrowserLanguage}
   */
  this.getBrowserLanguage = $injector.get('ngeoGetBrowserLanguage');

  /**
   * @type {ngeo.StateManager}
   */
  this.stateManager = $injector.get('ngeoStateManager');

  /**
   * @type {tmhDynamicLocale}
   */
  this.tmhDynamicLocale = $injector.get('tmhDynamicLocale');

  /**
   * @type {angular.Scope}
   */
  this.$scope = $scope;

  /**
   * Default language
   * @type {string}
   */
  this.defaultLang = $injector.get('defaultLang');

  /**
   * Languages URL
   * @type {!Object.<string, string>}
   */
  this.langUrls = $injector.get('langUrls');

  /**
   * The gettext catalog
   * @type {angularGettext.Catalog}
   */
  this.gettextCatalog = $injector.get('gettextCatalog');

  this.initLanguage();

  /**
   * The ngeo feature overlay manager service
   * @type {ngeo.FeatureOverlayMgr}
   */
  var ngeoFeatureOverlayMgr = $injector.get('ngeoFeatureOverlayMgr');
  ngeoFeatureOverlayMgr.init(this.map);

  /**
   * The ngeo ToolActivate manager service.
   * @type {ngeo.ToolActivateMgr}
   */
  var ngeoToolActivateMgr = $injector.get('ngeoToolActivateMgr');

  var queryToolActivate = new ngeo.ToolActivate(this, 'queryActive');
  ngeoToolActivateMgr.registerTool('mapTools', queryToolActivate, true);

  var measurePointActivate = new ngeo.ToolActivate(this, 'measurePointActive');
  ngeoToolActivateMgr.registerTool('mapTools', measurePointActivate, false);

  var measureLengthActivate = new ngeo.ToolActivate(this, 'measureLengthActive');
  ngeoToolActivateMgr.registerTool('mapTools', measureLengthActivate, false);

  var drawFeatureActivate = new ngeo.ToolActivate(this, 'drawFeatureActive');
  ngeoToolActivateMgr.registerTool('mapTools', drawFeatureActivate, false);

  var drawProfilePanelActivate = new ngeo.ToolActivate(this, 'drawProfilePanelActive');
  ngeoToolActivateMgr.registerTool('mapTools', drawProfilePanelActivate, false);

  var printPanelActivate = new ngeo.ToolActivate(this, 'printPanelActive');
  ngeoToolActivateMgr.registerTool('mapTools', printPanelActivate, false);

  $scope.$watch(function() {
    return this.theme.name;
  }.bind(this), function(name) {
    var map = this.map;
    gmfThemes.getThemeObject(name).then(function(theme) {
      if (theme) {
        var backgrounds = theme['functionalities']['default_basemap'];
        if (backgrounds && backgrounds.length > 0) {
          var background = backgrounds[0];
          gmfThemes.getBgLayers(this.dimensions).then(function(layers) {
            var layer = ol.array.find(layers, function(layer) {
              return layer.get('label') === background;
            });
            if (layer) {
              backgroundLayerMgr.set(map, layer);
            }
          });
        }
      }
    }.bind(this));
  }.bind(this));

  /**
   * @param {boolean} skipPermalink If True, don't use permalink
   * background layer.
   * @private
   */
  this.updateCurrentBackgroundLayer_ = function(skipPermalink) {
    gmfThemes.getBgLayers(this.dimensions).then(function(layers) {
      var background;
      if (!skipPermalink) {
        // get the background from the permalink
        background = permalink.getBackgroundLayer(layers);
      }
      if (!background) {
        // get the background from the user settings
        var functionalities = this.gmfUser.functionalities;
        if (functionalities) {
          var defaultBasemapArray = functionalities.default_basemap;
          if (defaultBasemapArray.length > 0) {
            var defaultBasemapLabel = defaultBasemapArray[0];
            background = ol.array.find(layers, function(layer) {
              return layer.get('label') === defaultBasemapLabel;
            });
          }
        }
      }
      if (!background && layers[1]) {
        // fallback to the layers list, use the second one because the first
        // is the blank layer
        background = layers[1];
      }

      if (background) {
        backgroundLayerMgr.set(this.map, background);
      }
    }.bind(this));
  }.bind(this);

  this.updateCurrentBackgroundLayer_(false);

  /**
   * @type {boolean}
   * @export
   */
  this.hasEditableLayers = true;

  /**
   * @private
   */
  this.updateHasEditableLayers_ = function() {
    gmfThemes.hasEditableLayers().then(function(hasEditableLayers) {
      this.hasEditableLayers = hasEditableLayers;
    }.bind(this));
  };
};

/**
 * @param {string} lang Language code.
 * @export
 */
gmf.AbstractController.prototype.switchLanguage = function(lang) {
  goog.asserts.assert(lang in this.langUrls);
  this.gettextCatalog.setCurrentLanguage(lang);
  this.gettextCatalog.loadRemote(this.langUrls[lang]);
  this.tmhDynamicLocale.set(lang);
  this['lang'] = lang;
};

/**
 */
gmf.AbstractController.prototype.initLanguage = function() {
  this.$scope.$watch(function() {
    return this['lang'];
  }.bind(this), function(newValue) {
    this.stateManager.updateState({
      'lang': newValue
    });
  }.bind(this));

  var browserLanguage = /** @type {string|undefined} */
      (this.getBrowserLanguage(Object.keys(this.langUrls)));
  var urlLanguage = /** @type {string|undefined} */
      (this.stateManager.getInitialValue('lang'));

  if (urlLanguage !== undefined && urlLanguage in this.langUrls) {
    this.switchLanguage(urlLanguage);
    return;
  } else if (browserLanguage !== undefined && browserLanguage in this.langUrls) {
    this.switchLanguage(browserLanguage);
    return;
  } else {
    // if there is no information about language preference,
    // fallback to default language

    this.switchLanguage(this.defaultLang);
    return;
  }
};

gmf.module.controller('AbstractController', gmf.AbstractController);
<|endoftext|>


<commit_before><commit_msg>update build<commit_after><|endoftext|>


<commit_before>document.getElementById("id_logic_level_version").innerHTML = "Business level version: 2017.11.15.2";

addEventListener("touchstart", on_touch_start);

function on_touch_start(e)
{
	var touches = e.changedTouches;
	for (var i = 0; i < touches.length; i++){
		var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
		circle.setAttribute("cx", touches[i].pageX);
		circle.setAttribute("cy", touches[i].pageY);
		circle.setAttribute("r", 10);
		var svg = document.getElementById("id_svg");
		svg.appendChild(circle);
	}
}<commit_msg>correct location for svg<commit_after>document.getElementById("id_logic_level_version").innerHTML = "Business level version: 2017.11.15.4";

addEventListener("touchstart", on_touch_start);
var svg = document.getElementById("id_svg");
var rect_svg = svg.getBoundingClientRect();

function on_touch_start(e)
{
	var touches = e.changedTouches;
	for (var i = 0; i < touches.length; i++){
		var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
		circle.setAttribute("cx", touches[i].pageX - rect_svg.left);
		circle.setAttribute("cy", touches[i].pageY - rect_svg.top);
		circle.setAttribute("r", 10);
		svg.appendChild(circle);
	}
}<|endoftext|>


<commit_before>"use strict";
var Blob = function (x, y, radius) {
  this.x = x;
  this.y = y;
  this.radius = radius || 0.33;
}

Blob.prototype.hasHit = function ( checkX, checkY ) {
  // Distance between blob center and graph coordinate
  var pointDistance =
    Math.sqrt( Math.pow(checkX - this.x, 2) + Math.pow(checkY - this.y, 2) );

  return (pointDistance < this.radius);
};

var GameState = function (windowObj) {
  this._blobs = [];
  this.setWindow(windowObj);
};

GameState.prototype.createBlobs = function (coordinateList) {
  if (this._blobs.length > 0) throw "Blobs are already created.";
  if ( !(coordinateList instanceof Array) )
    throw "coordinateList must be array.";
  if (coordinateList.length === 0) throw "coordinateList must not be empty.";

  coordinateList.forEach(function(coordinate){
    // x, y in nested array
    this._blobs.push(new Blob(coordinate[0], coordinate[1]));
  }.bind(this));
};

GameState.prototype.destroyBlobs = function () {
  this._blobs = [];
};

GameState.prototype.getBlobs = function () {
  return this._blobs;
};

GameState.prototype.createRandomBlobs = function (blobsToCreate) {
  if (typeof blobsToCreate !== "number")
    throw "Number of blobs must be integer";

  if (blobsToCreate < 1) throw "Number of blobs must be non-zero";

  var coordinates = [];
  for (var i = 0; i < blobsToCreate; i++) {
    coordinates.push(
      [
        Math.random() *
        (
          this._graphWindow.maxX -
          this._graphWindow.minX
        ) + this._graphWindow.minX,
        Math.random() *
        (
          this._graphWindow.maxY -
          this._graphWindow.minY
        ) + this._graphWindow.minY,
      ]);
  }

  this.createBlobs(coordinates);
};

GameState.prototype.setWindow = function (windowObj) {
  var allNums;
  for(var name in windowObj){
    allNums = typeof windowObj[name] === "number";
    allNums = allNums && ["minX", "maxX", "minY", "maxY"].includes(name);
    if(!allNums) break;
  }

  if (!allNums)
    throw "Not correct properties on window object." +
    " Check types and that you have minX, maxX, minY, maxY.";

  if ((windowObj.minX >= windowObj.maxX) && (windowObj.minY >= windowObj.maxY))
    throw "minX must be less than maxX and minY must be less than maxY";
  if (windowObj.minX >= windowObj.maxX) throw "minX must be less than maxX";
  if (windowObj.minY >= windowObj.maxY) throw "minY must be less than maxY";

  this._graphWindow = windowObj;
};

var Graph = function (expression, xResolution, yResolution) {
  this._compileExpression(expression);
  this.xResolution = xResolution;
  this.yResolution = yResolution;
};

Graph.prototype._compileExpression =
function (expression) {
  // TODO: precompile expression for easy rendering.
  console.error("compileExpression() is not yet implemented");
};

Graph.prototype.hasPoint = function (x, y) {
  //dx is width of domain to check for point
  //dy is height of range to check for point
  if (typeof x === "object") {
    y = x.y; //Use y component of object as y
    x = x.x; //Use x component of object as x
  }
  //TODO: Implement evaluation for any equation.
  //console.error("hasPoint() not yet implemented.");
  var atLeastMinimum = (
    Math.pow(5, 2) >=
    Math.pow((x)- 3, 2) +
    Math.pow((y) + 3, 2)
  );
  var atMostMaximum = (
    Math.pow(5 - (this.xResolution + this.yResolution),2) <=
    Math.pow( (x) - 3, 2) +
    Math.pow( (y) + 3, 2)
  );
  /*var atLeastMinimum = (
    y >= -Math.pow(x, 2)
  );
  var atMostMaximum = (
    y - (this.xResolution + this.yResolution) <= -Math.pow(x, 2)
  );*/
  return  atLeastMinimum && atMostMaximum;
};

var Equation = function Equation(equationString) {
  if (typeof equationString !== "string")
    throw "Equation necessary for processing.";
  this._parseEquation(equationString);
  this._parseExpressions();

};

Equation.prototype._parseExpressions = function () {
  this.parsedExpressions = [];
  this.expressions.forEach(function (expression) {

  })
};

Equation.prototype._parseEquation = function (equationString) {
  equationString = equationString.toLowerCase();

  if (equationString.indexOf("x") == -1 || equationString.indexOf("y") == -1)
    throw "Equation must relate x and y."

  this.comparisonOperators = { "=" : [], "<": [], ">": [], "<=": [], ">=": []};
  //Dynamically add keys to the RegExp for matching.
  var comparisonOperatorsRegExp = new RegExp(
    //Sort comparison operators by length, then join them to match longest first
    Object.keys(this.comparisonOperators).sort(
      function compare(a, b){
        return Math.sign(b.length - a.length);
      }
    ).join("|")
  );
  var searchString = equationString;
  this.expressions = [];

  var lastMatchedLocation = -1;
  //While there is a comparison happening
  while ( (comparisonOperatorsRegExp).test(searchString) ) {
    //Grab the matched operator.
    var matchedOperator = searchString.match(comparisonOperatorsRegExp);
    //Add it's location in the string to the object, plus
    //the location of the current string in the general equation string
    //plus one because length is 1 based, while indices are 0 based.
    this.comparisonOperators[matchedOperator[0]].
    push(matchedOperator.index + lastMatchedLocation + 1);
    lastMatchedLocation = matchedOperator.index;
    //add the expression to the list of expressions to evaluate
    this.expressions.push(
      searchString.substring(0, matchedOperator.index).trim()
    );
    //reevaluate only the new part of the string
    searchString = searchString.substring(
      matchedOperator.index + matchedOperator[0].length
    );
  }
  //Push the last expression that has no comparisonOperators into expressions
  this.expressions.push(searchString.trim());

  //Make sure there's at least one comparison AND no expressions are blank
  if ( this.expressions.length < 2 ||
    this.expressions.reduce(
      function (accumulator, arrayValue) {
        //checks if previous string is empty or if current one is empty.
        return accumulator || (arrayValue.length == 0);
      },
      false
    )
  ) throw "Equation must pose either an equality or inequality";
};

var Expression = function Expression(expressionString) {
  if (typeof expressionString !== "string") throw "Expression must be specified";

  this._compiledExpression = [];

  this.orderOfBinaryOperations = {
    "^": function exponent(a, b) {
      Math.pow(b, a);
    },
    "*": function multiplication(a, b) {
      return b * a;
    },
    "/": function division(a, b) {
      return b / a;
    },
    "+": function addition(a, b) {
      return b + a;
    },
    "-": function subtraction(a, b) {
      return b - a;
    }
  };

  this.orderOfUnaryOperations = {
    "(": function parentheses() {
      throw "Parentheses not implemented";
    },
    "+": function (a) {
      return +a;
    },
    "-": function (a) {
      return -a;
    },
    "sin": function sine(a) {
      return Math.sin(a);
    },
    "cos": function cosine(a) {
      return Math.cos("a");
    }
  }

  //Base case for recursion: if there are no operations being applied to string,
  //return the number or letter in a trimmed string

if (
    Object.keys(this.orderOfUnaryOperations).reduce(
      function (collector, item) {
        return collector && (expressionString.indexOf(item) === -1);
      },
      true
    ) &&
  Object.keys(this.orderOfBinaryOperations).reduce(
    function (collector, item) {
      return collector && (expressionString.indexOf(item) === -1);
    },
    true
  )
) {
  this._compiledExpression.push(expressionString.trim());
  return;
}
  //Split so that right, ex the minus is evaluated first 2x + 3 - 2
  //That way when we break it apart the first term is evaluated first
  var indexOfSymbol = -1; //Keep scope here so I can check if symbol is found.
  var tempExpressionString = expressionString; //for processing string only
  while (indexOfSymbol === -1){
    indexOfSymbol = -1;

    //unary first
    .
    reverse().forEach(
      function (symbol) {

      }.bind(this)
    );

    // Do binary after unary
    Object.keys(this.orderOfBinaryOperations).
    concat(Object.keys(this.orderOfUnaryOperations)).
    reverse().forEach(function (symbol) {
      //detect if is truly a unary symbol by encountering either
      //the string boundary or a non-letter or non-number on the left
      //and it not being a space
      var isUnary = function (symbol, expressionString) {
        var regions = expressionString.split(symbol);
        //get one before last one
        var testStr = regions[regions.length - 2].trim();
        return testStr === "" || /[^A-z0-9]$/.test(expressionString);
      };

      currentIsUnary = isUnary(symbol, expressionString);
      if (currentIsUnary){
        //Don't execute of symbol is already found or isn't unary
        if (indexOfSymbol > -1) return;
        indexOfSymbol = tempExpressionString.lastIndexOf(symbol);
        if (indexOfSymbol > -1) { //symbol has to exist
          if (symbol === "(") {
            var indexOfEndParens = tempExpressionString.lastIndexOf(")");
            this._compiledExpression.concat(
              new Expression(
                tempExpressionString.substring(
                  indexOfSymbol + symbol.length,
                  indexOfEndParens
                )
              )._compiledExpression // Just evaluate stuff inside of parentheses
            );
            tempExpressionString = tempExpressionString.substring(indexOfSymbol);
          } else {
            this._compiledExpression.push("u" + symbol);
            afterText = tempExpressionString.
            split(symbol).pop().
            match(/[A-z0-9]+/)[0];
            this._compiledExpression.push(afterText);
          }
        }
      } else {

        if (indexOfSymbol > -1) return; //Don't execute of symbol is already found
        indexOfSymbol = tempExpressionString.lastIndexOf(symbol);
        if (indexOfSymbol > -1) { //symbol has to exist
          this._compiledExpression.push(symbol);
          this._compiledExpression.concat(
            new Expression(
              tempExpressionString.substring(indexOfSymbol + symbol.length)
            )._compiledExpression
          );
          tempExpressionString = tempExpressionString.substring(indexOfSymbol);
        }
      }

    }.bind(this));
  }

}
<commit_msg>All except for parens implemented<commit_after>"use strict";
var Blob = function (x, y, radius) {
  this.x = x;
  this.y = y;
  this.radius = radius || 0.33;
}

Blob.prototype.hasHit = function ( checkX, checkY ) {
  // Distance between blob center and graph coordinate
  var pointDistance =
    Math.sqrt( Math.pow(checkX - this.x, 2) + Math.pow(checkY - this.y, 2) );

  return (pointDistance < this.radius);
};

var GameState = function (windowObj) {
  this._blobs = [];
  this.setWindow(windowObj);
};

GameState.prototype.createBlobs = function (coordinateList) {
  if (this._blobs.length > 0) throw "Blobs are already created.";
  if ( !(coordinateList instanceof Array) )
    throw "coordinateList must be array.";
  if (coordinateList.length === 0) throw "coordinateList must not be empty.";

  coordinateList.forEach(function(coordinate){
    // x, y in nested array
    this._blobs.push(new Blob(coordinate[0], coordinate[1]));
  }.bind(this));
};

GameState.prototype.destroyBlobs = function () {
  this._blobs = [];
};

GameState.prototype.getBlobs = function () {
  return this._blobs;
};

GameState.prototype.createRandomBlobs = function (blobsToCreate) {
  if (typeof blobsToCreate !== "number")
    throw "Number of blobs must be integer";

  if (blobsToCreate < 1) throw "Number of blobs must be non-zero";

  var coordinates = [];
  for (var i = 0; i < blobsToCreate; i++) {
    coordinates.push(
      [
        Math.random() *
        (
          this._graphWindow.maxX -
          this._graphWindow.minX
        ) + this._graphWindow.minX,
        Math.random() *
        (
          this._graphWindow.maxY -
          this._graphWindow.minY
        ) + this._graphWindow.minY,
      ]);
  }

  this.createBlobs(coordinates);
};

GameState.prototype.setWindow = function (windowObj) {
  var allNums;
  for(var name in windowObj){
    allNums = typeof windowObj[name] === "number";
    allNums = allNums && ["minX", "maxX", "minY", "maxY"].includes(name);
    if(!allNums) break;
  }

  if (!allNums)
    throw "Not correct properties on window object." +
    " Check types and that you have minX, maxX, minY, maxY.";

  if ((windowObj.minX >= windowObj.maxX) && (windowObj.minY >= windowObj.maxY))
    throw "minX must be less than maxX and minY must be less than maxY";
  if (windowObj.minX >= windowObj.maxX) throw "minX must be less than maxX";
  if (windowObj.minY >= windowObj.maxY) throw "minY must be less than maxY";

  this._graphWindow = windowObj;
};

var Graph = function (expression, xResolution, yResolution) {
  this._compileExpression(expression);
  this.xResolution = xResolution;
  this.yResolution = yResolution;
};

Graph.prototype._compileExpression =
function (expression) {
  // TODO: precompile expression for easy rendering.
  console.error("compileExpression() is not yet implemented");
};

Graph.prototype.hasPoint = function (x, y) {
  //dx is width of domain to check for point
  //dy is height of range to check for point
  if (typeof x === "object") {
    y = x.y; //Use y component of object as y
    x = x.x; //Use x component of object as x
  }
  //TODO: Implement evaluation for any equation.
  //console.error("hasPoint() not yet implemented.");
  var atLeastMinimum = (
    Math.pow(5, 2) >=
    Math.pow((x)- 3, 2) +
    Math.pow((y) + 3, 2)
  );
  var atMostMaximum = (
    Math.pow(5 - (this.xResolution + this.yResolution),2) <=
    Math.pow( (x) - 3, 2) +
    Math.pow( (y) + 3, 2)
  );
  /*var atLeastMinimum = (
    y >= -Math.pow(x, 2)
  );
  var atMostMaximum = (
    y - (this.xResolution + this.yResolution) <= -Math.pow(x, 2)
  );*/
  return  atLeastMinimum && atMostMaximum;
};

var Equation = function Equation(equationString) {
  if (typeof equationString !== "string")
    throw "Equation necessary for processing.";
  this._parseEquation(equationString);
  this._parseExpressions();

};

Equation.prototype._parseExpressions = function () {
  this.parsedExpressions = [];
  this.expressions.forEach(function (expression) {

  })
};

Equation.prototype._parseEquation = function (equationString) {
  equationString = equationString.toLowerCase();

  if (equationString.indexOf("x") == -1 || equationString.indexOf("y") == -1)
    throw "Equation must relate x and y."

  this.comparisonOperators = { "=" : [], "<": [], ">": [], "<=": [], ">=": []};
  //Dynamically add keys to the RegExp for matching.
  var comparisonOperatorsRegExp = new RegExp(
    //Sort comparison operators by length, then join them to match longest first
    Object.keys(this.comparisonOperators).sort(
      function compare(a, b){
        return Math.sign(b.length - a.length);
      }
    ).join("|")
  );
  var searchString = equationString;
  this.expressions = [];

  var lastMatchedLocation = -1;
  //While there is a comparison happening
  while ( (comparisonOperatorsRegExp).test(searchString) ) {
    //Grab the matched operator.
    var matchedOperator = searchString.match(comparisonOperatorsRegExp);
    //Add it's location in the string to the object, plus
    //the location of the current string in the general equation string
    //plus one because length is 1 based, while indices are 0 based.
    this.comparisonOperators[matchedOperator[0]].
    push(matchedOperator.index + lastMatchedLocation + 1);
    lastMatchedLocation = matchedOperator.index;
    //add the expression to the list of expressions to evaluate
    this.expressions.push(
      searchString.substring(0, matchedOperator.index).trim()
    );
    //reevaluate only the new part of the string
    searchString = searchString.substring(
      matchedOperator.index + matchedOperator[0].length
    );
  }
  //Push the last expression that has no comparisonOperators into expressions
  this.expressions.push(searchString.trim());

  //Make sure there's at least one comparison AND no expressions are blank
  if ( this.expressions.length < 2 ||
    this.expressions.reduce(
      function (accumulator, arrayValue) {
        //checks if previous string is empty or if current one is empty.
        return accumulator || (arrayValue.length == 0);
      },
      false
    )
  ) throw "Equation must pose either an equality or inequality";
};

var Expression = function Expression(expressionString) {
  if (typeof expressionString !== "string") throw "Expression must be specified";

  if (expressionString.trim() === "") {
    this.entryPoint = function(){return 0;}
    return;
  }

  this._compiledExpression = [];

  this._compiledUnaryExpressions = [];

  this.orderOfBinaryOperations = {
    "^": function exponent(a, b) {
      return Math.pow(a, b);
    },
    "*": function multiplication(a, b) {
      return b * a;
    },
    "/": function division(a, b) {
      return b / a;
    },
    "+": function addition(a, b) {
      return b + a;
    },
    "-": function subtraction(a, b) {
      return b - a;
    }
  };

  this.orderOfUnaryOperations = {
    "(": function parentheses() {
      throw "Parentheses not implemented";
    },
    "+": function (a) {
      return +a;
    },
    "-": function (a) {
      return -a;
    },
    "sin": function sine(a) {
      return Math.sin(a);
    },
    "cos": function cosine(a) {
      return Math.cos(a);
    }
  }

  //remove single pair of parens if they are on the ends and end matches beginning as they don't matter.
  expressionString = expressionString.trim();
  if (/^\(.*\)$/.test(expressionString)) {
    var leftUnmatched = 0; //error if goes below 0
    var endIndex = [];
    //Only two scenarios (()) and ()() to disambiguate bc recursion takes care of rest
    expressionString.split("").forEach(function (char, index) {
      if (char === "(") leftUnmatched++;
      if (char === ")") leftUnmatched--;
      if (leftUnmatched === 0) endIndex.push(index);
    })
    //get the first completed closure of () after beginning
    if (endIndex[0] === expressionString.length - 1)
    expressionString = expressionString.substring(1, expressionString.length - 1);
  }

  //Base case for recursion: if there are no operations being applied to string,
  //return the number in a function that returns that number
  // or letter in a function that takes a value for that variable as a parameter

if (
    Object.keys(this.orderOfUnaryOperations).reduce(
      function (collector, item) {
        return collector && (expressionString.indexOf(item) === -1);
      },
      true
    ) &&
  Object.keys(this.orderOfBinaryOperations).reduce(
    function (collector, item) {
      return collector && (expressionString.indexOf(item) === -1);
    },
    true
  )
) {
  expressionString = expressionString.trim();
  if (/[A-z]/.test(expressionString)){
    this.entryPoint = function (variablesObj) {
      return variablesObj[expressionString];
    }
  } else {
    this.entryPoint = function () {
      return parseFloat(expressionString);
    }
  }
  return;
}
  //Split so that right, ex the minus is evaluated first 2x + 3 - 2
  //That way when we break it apart the first term is evaluated first
//  var indexOfSymbol = -1; //Keep scope here so I can check if symbol is found.
  var tempExpressionString = expressionString; //for processing string only
  var isUnary = function (symbol, expressionString) {
    var regions = expressionString.split(symbol);
    //Regions will be <2 only if it's not found, so it's not unary.
    if (regions.length < 2) return false;
    //get one before last one
    var testStr = regions[regions.length - 2].trim();
    return testStr === "" || /[^A-z0-9()]$/.test(expressionString);
  };

  var isInParens = function (indexOfLocation, expressionString) {
    var openParensBefore = 0;
    var openParensAfter = 0;
    var before = expressionString.substring(0, indexOfLocation - 1);
    var after = expressionString.substring(indexOfLocation + 1);
    before.split("").forEach(function (letter) {
      if (letter === "(") ++openParensBefore;
      if (letter === ")") --openParensBefore;
    });
    after.split("").forEach(function (letter) {
      if (letter === "(") ++openParensAfter;
      if (letter === ")") --openParensAfter;
    });

    return !(openParensBefore === 0 && openParensAfter === 0);
  }

  this.entryPoint = null; //will hold first function to call in stack.
  // Do binary after unary
  Object.keys(this.orderOfBinaryOperations).
  concat(Object.keys(this.orderOfUnaryOperations)).
  reverse().forEach(function (symbol) {
  var indexOfSymbol = expressionString.lastIndexOf(symbol);
  //Don't eval any symbols in parens, the parens op. will do that!

  if (indexOfSymbol > -1)
  if (isInParens(indexOfSymbol, expressionString)) return;
    if (isUnary(symbol, expressionString)) {
      if (/\(/.test(symbol)){
        this.entryPoint = function (variablesObj) {
          return (new Expression(
            expressionString.substring(
              expressionString.indexOf("(") + 1,
              expressionString.indexOf(")")
            )).evaluate(variablesObj)) +
            (new Expression(
              expressionString.substring(
                expressionString.indexOf(")") + 1
              )
            ).evaluate(variablesObj));
        }
      } else {
        this.entryPoint = function (variablesObj) {
          return this.orderOfUnaryOperations[symbol](
            (new Expression(
            expressionString.substring(indexOfSymbol + symbol.length)
          )).evaluate(variablesObj));
        };
      }
    } else {
      this.entryPoint = function(variablesObj) {
        return this.orderOfBinaryOperations[symbol](
          (new Expression(
            expressionString.substring(0, indexOfSymbol)
          )).evaluate(variablesObj),
          (new Expression(
            expressionString.substring(indexOfSymbol + symbol.length)
          )).evaluate(variablesObj)
        );
      };
    }
    return;
  }.bind(this));

  // console.log(this.entryPoint);

  /*while (indexOfSymbol === -1){
    indexOfSymbol = -1;

    var isInParens = function (indexOfLocation, expressionString) {
      return indexOfLocation > expressionString.indexOf("(") &&
        indexOfLocation < expressionString.lastIndexOf(")");
    }
    // Do binary after unary
    Object.keys(this.orderOfBinaryOperations).
    concat(Object.keys(this.orderOfUnaryOperations)).
    reverse().forEach(function (symbol) {

      //detect if is truly a unary symbol by encountering either
      //the string boundary or a non-letter or non-number on the left
      //and it not being a space
      this.unaryCount = 0;
      var currentIsUnary = isUnary(symbol, expressionString);
      //Don't execute of symbol is already found
      if (indexOfSymbol > -1) return;
      indexOfSymbol = tempExpressionString.lastIndexOf(symbol);
      //Symbol will be evaluated in nested expression, so not now
      if (isInParens(indexOfSymbol, expressionString)) {
        indexOfSymbol = -1;
        return;
      }

      if (currentIsUnary){
        if (indexOfSymbol > -1) { //symbol has to exist
          if (symbol === "(") {
            var indexOfEndParens = tempExpressionString.lastIndexOf(")");
            this._compiledExpression.concat(
              new Expression(
                tempExpressionString.substring(
                  indexOfSymbol + symbol.length,
                  indexOfEndParens
                )
              )._compiledExpression // Just evaluate stuff inside of parentheses
            );
            tempExpressionString = tempExpressionString.substring(indexOfSymbol);
          } else {
            //Increment unary count and push the value as a symbol.
            this._compiledExpression.push("u" + ++this.unaryCount);
            afterText = tempExpressionString.
            split(symbol).pop().
            match(/[A-z0-9]+/)[0];

            this._compiledUnaryExpressions.push(new Expression(afterText));
          }
        }
      } else {
        if (indexOfSymbol > -1) { //symbol has to exist
          this._compiledExpression.push(symbol);
          this._compiledExpression.concat(
            new Expression(
              tempExpressionString.substring(indexOfSymbol + symbol.length)
            )._compiledExpression
          );
          tempExpressionString = tempExpressionString.substring(indexOfSymbol);
        }
      }

    }.bind(this));
  }*/

}

Expression.prototype.evaluate = function (variablesObj) {
  return this.entryPoint(variablesObj);
};
<|endoftext|>


<commit_before>var config = require('config');
var express = require('express');
var router = express.Router();
var predictionService = require('services/prediction.service');
var topPointsCache = null;

// routes
router.post('/predictMatch', predictMatch);
router.get('/predictions/:username', getPredictions);
router.get('/getPoint/:username', getPoint);

module.exports = router;

function predictMatch(req, res) {
    if (req.body.username !== req.user.un)
        return res.status(401).send('Sadece kendi hesabınız için tahmin girebilirsiniz!');

    predictionService.predictMatch(req.body)
        .then(function () {
            res.sendStatus(200);
        })
        .catch(function (err) {
            res.status(400).send(err);
        });
}

function getPredictions(req, res) {
    if (req.params.username !== req.user.un)
        return res.status(401).send('Sadece kendi hesabınız için tahminleri görebilirsiniz!');

    predictionService.getPredictions(req.params.username)
        .then(function (result) {
            if (result) {
                res.send(result);
            } else {
                res.sendStatus(404);
            }
        })
        .catch(function (err) {
            res.status(400).send(err);
        });
}

function getPoint(req, res) {
    if (req.params.username !== req.user.un)
        return res.status(401).send('Sadece kendi hesabınız için sonuçları görebilirsiniz!');

    predictionService.getPoint(req.params.username)
        .then(function (result) {
            if (result) {
                if(topPointsCache !== null){
                    console.log(topPointsCache);
                    topPointsCache.yourPoint = result;
                    res.send(topPointsCache);
                }
                else{
                    predictionService.getPoints()
                        .then(function (topPoints) {
                            if (topPoints) {
                                topPointsCache = topPoints;
                                topPointsCache.yourPoint = result;
                                res.send(topPointsCache);
                            } else {
                                res.sendStatus(404);
                            }
                        })
                        .catch(function (err) {
                            res.status(400).send(err);
                        });
                }

            } else {
                res.sendStatus(404);
            }
        })
        .catch(function (err) {
            res.status(400).send(err);
        });
}<commit_msg>unnecessary debug log is removed<commit_after>var config = require('config');
var express = require('express');
var router = express.Router();
var predictionService = require('services/prediction.service');
var topPointsCache = null;

// routes
router.post('/predictMatch', predictMatch);
router.get('/predictions/:username', getPredictions);
router.get('/getPoint/:username', getPoint);

module.exports = router;

function predictMatch(req, res) {
    if (req.body.username !== req.user.un)
        return res.status(401).send('Sadece kendi hesabınız için tahmin girebilirsiniz!');

    predictionService.predictMatch(req.body)
        .then(function () {
            res.sendStatus(200);
        })
        .catch(function (err) {
            res.status(400).send(err);
        });
}

function getPredictions(req, res) {
    if (req.params.username !== req.user.un)
        return res.status(401).send('Sadece kendi hesabınız için tahminleri görebilirsiniz!');

    predictionService.getPredictions(req.params.username)
        .then(function (result) {
            if (result) {
                res.send(result);
            } else {
                res.sendStatus(404);
            }
        })
        .catch(function (err) {
            res.status(400).send(err);
        });
}

function getPoint(req, res) {
    if (req.params.username !== req.user.un)
        return res.status(401).send('Sadece kendi hesabınız için sonuçları görebilirsiniz!');

    predictionService.getPoint(req.params.username)
        .then(function (result) {
            if (result) {
                if(topPointsCache !== null){
                    topPointsCache.yourPoint = result;
                    res.send(topPointsCache);
                }
                else{
                    predictionService.getPoints()
                        .then(function (topPoints) {
                            if (topPoints) {
                                topPointsCache = topPoints;
                                topPointsCache.yourPoint = result;
                                res.send(topPointsCache);
                            } else {
                                res.sendStatus(404);
                            }
                        })
                        .catch(function (err) {
                            res.status(400).send(err);
                        });
                }

            } else {
                res.sendStatus(404);
            }
        })
        .catch(function (err) {
            res.status(400).send(err);
        });
}<|endoftext|>


<commit_before>'use strict';

/*!
 * Snakeskin
 * https://github.com/SnakeskinTpl/Snakeskin
 *
 * Released under the MIT license
 * https://github.com/SnakeskinTpl/Snakeskin/blob/master/LICENSE
 */

import { any } from './gcc';
import { isString } from './types';

const
	wsRgxp = /^\s+|[\r\n]+/mg;

/**
 * String tag (for ES6 string templates) for truncate starting whitespaces and eol-s
 *
 * @param {!Array.<string>} strings
 * @param {...string} expr
 * @return {string}
 */
export function ws(strings, expr) {
	expr = [].slice.call(arguments, 1);

	let
		res = '';

	for (let i = 0; i < strings.length; i++) {
		res += strings[i].replace(wsRgxp, ' ') + (i in expr ? expr[i] : '');
	}

	return res;
}

const
	rRgxp = /([\\\/'*+?|()\[\]{}.^$-])/g;

/**
 * Escapes RegExp characters in a string
 *
 * @param {string} str - source string
 * @return {string}
 */
export function r(str) {
	return str.replace(rRgxp, '\\$1');
}
<commit_msg>:wrench:<commit_after>'use strict';

/*!
 * Snakeskin
 * https://github.com/SnakeskinTpl/Snakeskin
 *
 * Released under the MIT license
 * https://github.com/SnakeskinTpl/Snakeskin/blob/master/LICENSE
 */

const
	wsRgxp = /^\s+|[\r\n]+/mg;

/**
 * String tag (for ES6 string templates) for truncate starting whitespaces and eol-s
 *
 * @param {!Array.<string>} strings
 * @param {...string} expr
 * @return {string}
 */
export function ws(strings, expr) {
	expr = [].slice.call(arguments, 1);

	let
		res = '';

	for (let i = 0; i < strings.length; i++) {
		res += strings[i].replace(wsRgxp, ' ') + (i in expr ? expr[i] : '');
	}

	return res;
}

const
	rRgxp = /([\\\/'*+?|()\[\]{}.^$-])/g;

/**
 * Escapes RegExp characters in a string
 *
 * @param {string} str - source string
 * @return {string}
 */
export function r(str) {
	return str.replace(rRgxp, '\\$1');
}
<|endoftext|>


<commit_before>const capitalize = require('capitalize');
const constructorParamsKeys = require('../data/constructorParamsKeys');
const audioParamProperties = require('../data/audioParamProperties');
const setters = require('../data/setters');

const values = obj => Object.keys(obj).map(key => obj[key]);

module.exports = function update (virtualNode, params = {}) {
  if (virtualNode.isCustomVirtualNode) {
    const audioGraphParamsFactoryValues = values(virtualNode.audioGraphParamsFactory(params));
    values(virtualNode.virtualNodes)
      .forEach((childVirtualNode, i) =>
        update(childVirtualNode, audioGraphParamsFactoryValues[i].params));
  } else {
    Object.keys(params)
      .forEach(key => {
        if (constructorParamsKeys.indexOf(key) !== -1) {
          return;
        }
        const param = params[key];
        if (virtualNode.params && virtualNode.params[key] === param) {
          return;
        }
        if (audioParamProperties.indexOf(key) !== -1) {
          virtualNode.audioNode[key].value = param;
          return;
        }
        if (setters.indexOf(key) !== -1) {
          virtualNode.audioNode[`set${capitalize(key)}`].apply(virtualNode.audioNode, param);
          return;
        }
        virtualNode.audioNode[key] = param;
      });
  }
  virtualNode.params = params;
  return virtualNode;
};
<commit_msg>tiny optimization<commit_after>const capitalize = require('capitalize');
const constructorParamsKeys = require('../data/constructorParamsKeys');
const audioParamProperties = require('../data/audioParamProperties');
const setters = require('../data/setters');

const values = obj => Object.keys(obj).map(key => obj[key]);

module.exports = function update (virtualNode, params = {}) {
  if (virtualNode.isCustomVirtualNode) {
    const audioGraphParamsFactoryValues = values(virtualNode.audioGraphParamsFactory(params));
    Object.keys(virtualNode.virtualNodes)
      .forEach((key, i) => {
        const childVirtualNode = virtualNode.virtualNodes[key];
        update(childVirtualNode, audioGraphParamsFactoryValues[i].params);
      });
  } else {
    Object.keys(params)
      .forEach(key => {
        if (constructorParamsKeys.indexOf(key) !== -1) {
          return;
        }
        const param = params[key];
        if (virtualNode.params && virtualNode.params[key] === param) {
          return;
        }
        if (audioParamProperties.indexOf(key) !== -1) {
          virtualNode.audioNode[key].value = param;
          return;
        }
        if (setters.indexOf(key) !== -1) {
          virtualNode.audioNode[`set${capitalize(key)}`].apply(virtualNode.audioNode, param);
          return;
        }
        virtualNode.audioNode[key] = param;
      });
  }
  virtualNode.params = params;
  return virtualNode;
};
<|endoftext|>