<commit_before>'use strict'

var ref = require('../../util/get/reference')

exports.inject = require('./retrieve')

exports.define = {
  subscribe (path, type, val, key, fire, event) {
    let id = this.uid
    if (key) {
      id += key
    }
    // if (val instanceof Array) {
    //   id += '.' + val[1].uid
    // }
    let pathType = typeof path
    if (path === true) {
      path = [] // make faster
    } else if (pathType === 'string') {
      id += path
      path = path.split('.')
    } else if (pathType === 'number') {
      id += path
      path = [path]
    } else {
      id += path.join('.')
    }
    let index = 0
    let length = path.length

    // if (key) {
    //   id = key
    // }
    // on remove unsubscribe
    this.on('remove', function () {
      unsubscribe(this, path, index, length, id)
    }, id)

    return subscribe(this, path, index, length, type, val, id, fire, this, event)
  },

  unsubscribe (path, key) {
    let id = this.uid
    let pathType = typeof path
    if (pathType === 'string') {
      id += path
      path = path.split('.')
    } else if (pathType === 'number') {
      id += path
      path = [path]
    } else {
      id += path.join('.')
    }

    if (key) {
      id = key
    }

    let index = 0
    let length = path.length
    return unsubscribe(this, path, index, length, id)
  }
}

function subscribe (obs, path, index, length, type, val, id, fire, origin, event) {
  if (index === length) {
    obs.on('remove', function () {
      subscribe(origin, path, 0, length, type, val, id, false, origin)
    }, id)
    obs.on(type, val, id)
    if (fire) {
      obs.emit(type, void 0, event)
    }
    return obs
  } else {
    let key = path[index]
    let property = obs[key]
    let result

    if (property && property._input !== null) {
      result = subscribe(property, path, index + 1, length, type, val, id, fire, origin)
    } else {
      let listenerType = key === 'parent' ? key : 'property'
      let listener = function (data, event) {
        let property = obs[key]
        if (property) {
          obs.off(listenerType, id)
          subscribe(property, path, index + 1, length, type, val, id, true, origin)
        }
      }
      obs.on(listenerType, listener, id)
    }

    // if sub is not fulfilled look in the reference
    if (!result) {
      let reference = ref(obs)
      if (reference) {
        subscribe(reference, path, index, length, type, val, id, fire, origin)
      }
    }
  }
}

function unsubscribe (obs, path, index, length, id) {
  obs.off(void 0, id)
  let key = path[index]
  let property = obs[key]
  if (property) {
    unsubscribe(property, path, index + 1, length, id)
  }
  let reference = ref(obs)
  if (reference) {
    unsubscribe(obs, path, index, length, id)
  }
}
<commit_msg>update<commit_after>'use strict'

var ref = require('../../util/get/reference')

exports.inject = require('./retrieve')

exports.define = {
  subscribe (path, type, val, key, fire, event) {
    let id = this.uid
    if (key) {
      id += '.' + key
    }
    let pathType = typeof path
    if (path === true) {
      path = [] // make faster
    } else if (pathType === 'string') {
      id += path
      path = path.split('.')
    } else if (pathType === 'number') {
      id += path
      path = [path]
    } else {
      id += path.join('.')
    }
    let index = 0
    let length = path.length
    // unsubs will not work now
    this.on('remove', function () {
      unsubscribe(this, path, index, length, id)
    }, id)
    return subscribe(this, path, index, length, type, val, id, fire, this, event)
  },

  // test and make better -- the uid is crap now
  unsubscribe (path, key) {
    let id = this.uid
    if (key) {
      id += '.' + key
    }
    // make shared shit
    let pathType = typeof path
    if (path === true) {
      path = [] // make faster
    } else if (pathType === 'string') {
      id += path
      path = path.split('.')
    } else if (pathType === 'number') {
      id += path
      path = [path]
    } else {
      id += path.join('.')
    }

    let index = 0
    let length = path.length
    return unsubscribe(this, path, index, length, id)
  }
}

// subscriptions have to take care of references

function subscribe (obs, path, index, length, type, val, id, fire, origin, event) {
  if (index === length) {
    obs.on('remove', function () {
      subscribe(origin, path, 0, length, type, val, id, false, origin)
    }, id)
    obs.on(type, val, id)
    if (fire) {
      obs.emit(type, void 0, event)
    }
    return obs
  } else {
    let key = path[index]
    let property = obs[key]
    let result

    if (property && property._input !== null) {
      result = subscribe(property, path, index + 1, length, type, val, id, fire, origin)
    } else {
      let listenerType = key === 'parent' ? key : 'property'
      let listener = function (data, event) {
        let property = obs[key]
        if (property) {
          obs.off(listenerType, id)
          subscribe(property, path, index + 1, length, type, val, id, true, origin)
        }
      }
      obs.on(listenerType, listener, id)
    }

    // if sub is not fulfilled look in the reference
    if (!result) {
      let reference = ref(obs)
      if (reference) {
        subscribe(reference, path, index, length, type, val, id, fire, origin)
      }
    }
  }
}

function unsubscribe (obs, path, index, length, id) {
  console.log('REMOVE!')
  obs.off(void 0, id)
  let key = path[index]
  let property = obs[key]
  if (property) {
    unsubscribe(property, path, index + 1, length, id)
  }
  let reference = ref(obs)
  if (reference) {
    unsubscribe(obs, path, index, length, id)
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration. All Rights Reserved.
 */
/**
 * @exports Color
 * @version $Id: Color.js 3017 2015-04-14 17:10:31Z dcollins $
 */
define([
        '../util/Logger'
    ],
    function (Logger) {
        "use strict";

        /**
         * Constructs a color from red, green, blue and alpha values.
         * @alias Color
         * @constructor
         * @classdesc Represents a red, green, blue, alpha, color.
         * @param {Number} red The red component, a number between 0 and 1.
         * @param {Number} green The green component, a number between 0 and 1.
         * @param {Number} blue The blue component, a number between 0 and 1.
         * @param {Number} alpha The alpha component, a number between 0 and 1.
         */
        var Color = function (red, green, blue, alpha) {

            /**
             * This color's red component, a number between 0 and 1.
             * @type {Number}
             */
            this.red = red;

            /**
             * This color's green component, a number between 0 and 1.
             * @type {Number}
             */
            this.green = green;

            /**
             * This color's blue component, a number between 0 and 1.
             * @type {Number}
             */
            this.blue = blue;

            /**
             * This color's alpha component, a number between 0 and 1.
             * @type {Number}
             */
            this.alpha = alpha;
        };

        /**
         * The color white.
         * @type {Color}
         * @constant
         */
        Color.WHITE = new Color(1, 1, 1, 1);

        /**
         * The color black.
         * @type {Color}
         * @constant
         */
        Color.BLACK = new Color(0, 0, 0, 1);

        /**
         * The color red.
         * @type {Color}
         * @constant
         */
        Color.RED = new Color(1, 0, 0, 1);

        /**
         * The color green.
         * @type {Color}
         * @constant
         */
        Color.GREEN = new Color(0, 1, 0, 1);

        /**
         * The color blue.
         * @type {Color}
         * @constant
         */
        Color.BLUE = new Color(0, 0, 1, 1);

        /**
         * The color cyan.
         * @type {Color}
         * @constant
         */
        Color.CYAN = new Color(0, 1, 1, 1);

        /**
         * The color yellow.
         * @type {Color}
         * @constant
         */
        Color.YELLOW = new Color(1, 1, 0, 1);

        /**
         * The color magenta.
         * @type {Color}
         * @constant
         */
        Color.MAGENTA = new Color(1, 0, 1, 1);

        /**
         * A light gray (75% white).
         * @type {Color}
         */
        Color.LIGHT_GRAY = new Color(0.75, 0.75, 0.75, 1);

        /**
         * A medium gray (50% white).
         * @type {Color}
         */
        Color.MEDIUM_GRAY = new Color(0.5, 0.5, 0.5, 1);

        /**
         * A dark gray (25% white).
         * @type {Color}
         */
        Color.DARK_GRAY = new Color(0.25, 0.25, 0.25, 1);

        /**
         * A transparent color.
         * @type {Color}
         */
        Color.TRANSPARENT = new Color(0, 0, 0, 0);

        /**
         * Assigns the components of this color.
         * @param {Number} red The red component, a number between 0 and 1.
         * @param {Number} green The green component, a number between 0 and 1.
         * @param {Number} blue The blue component, a number between 0 and 1.
         * @param {Number} alpha The alpha component, a number between 0 and 1.
         * @returns {Color} This color with the specified components assigned.
         */
        Color.prototype.set = function (red, green, blue, alpha) {
            this.red = red;
            this.green = green;
            this.blue = blue;
            this.alpha = alpha;

            return this;
        };

        /**
         * Copies the components of a specified color to this color.
         * @param {Color} color The color to copy.
         * @returns {Color} This color set to the red, green, blue and alpha values of the specified color.
         * @throws {ArgumentError} If the specified color is null or undefined.
         */
        Color.prototype.copy = function (color) {
            if (!color) {
                throw new ArgumentError(
                    Logger.logMessage(Logger.LEVEL_SEVERE, "Color", "copy", "missingColor"));
            }

            this.red = color.red;
            this.green = color.green;
            this.blue = color.blue;
            this.alpha = color.alpha;

            return this;
        };

        /**
         * Create a copy of this color.
         * @returns {Color} A new instance containing the color components of this color.
         */
        Color.prototype.clone = function () {
            return new Color(this.red, this.green, this.blue, this.alpha);
        };

        /**
         * Returns this color's components premultiplied by this color's alpha component.
         * @param {Float32Array} array A pre-allocated array in which to return the color components.
         * @returns {Float32Array} This colors premultiplied components as an array, in the order RGBA.
         */
        Color.prototype.premultipliedComponents = function (array) {
            var a = this.alpha;

            array[0] = this.red * a;
            array[1] = this.green * a;
            array[2] = this.blue * a;
            array[3] = a;

            return array;
        };

        /**
         * Construct a color from an array of color components expressed as byte values.
         * @param {Uint8Array} bytes A four-element array containing the red, green, blue and alpha color
         * components each in the range [0, 255];
         * @returns {Color} The constructed color.
         */
        Color.colorFromByteArray = function (bytes) {
            return new Color(bytes[0] / 255, bytes[1] / 255, bytes[2] / 255, bytes[3] / 255);
        };

        /**
         * Construct a color from specified color components expressed as byte values.
         * @param {number} redByte The red component in the range [0, 255].
         * @param {number} greenByte The green component in the range [0, 255].
         * @param {number} blueByte The blue component in the range [0, 255].
         * @param {number} alphaByte The alpha component in the range [0, 255].
         * @returns {Color} The constructed color.
         */
        Color.colorFromBytes = function (redByte, greenByte, blueByte, alphaByte) {
            return new Color(redByte / 255, greenByte / 255, blueByte / 255, alphaByte / 255);
        };

        Color.colorFromHex = function(color) {
            var red = parseInt(color.substring(0, 2), 16);
            var green = parseInt(color.substring(2,4), 16);
            var blue = parseInt(color.substring(4,6), 16);
            var alpha = parseInt(color.substring(6,8), 16);
            return Color.colorFromBytes(red, green, blue, alpha);
        };

        Color.colorFromKmlHex = function(color) {
            var alpha = parseInt(color.substring(0,2), 16);
            var blue = parseInt(color.substring(2,4), 16);
            var green = parseInt(color.substring(4,6), 16);
            var red = parseInt(color.substring(6, 8), 16);
            return Color.colorFromBytes(red, green, blue, alpha);
        };

        /**
         * Computes and sets this color to the next higher RBG color. If the color overflows, this color is set to
         * (1 / 255, 0, 0, *), where * indicates the current alpha value.
         * @returns {Color} This color, set to the next possible color.
         */
        Color.prototype.nextColor = function () {
            var rb = Math.round(this.red * 255),
                gb = Math.round(this.green * 255),
                bb = Math.round(this.blue * 255);

            if (rb < 255) {
                this.red = (rb + 1) / 255;
            } else if (gb < 255) {
                this.red = 0;
                this.green = (gb + 1) / 255;
            } else if (bb < 255) {
                this.red = 0;
                this.green = 0;
                this.blue = (bb + 1) / 255;
            } else {
                this.red = 1 / 255;
                this.green = 0;
                this.blue = 0;
            }

            return this;
        };

        /**
         * Indicates whether this color is equal to a specified color after converting the floating-point component
         * values of each color to byte values.
         * @param {Color} color The color to test,
         * @returns {Boolean} true if the colors are equal, otherwise false.
         */
        Color.prototype.equals = function (color) {
            var rbA = Math.round(this.red * 255),
                gbA = Math.round(this.green * 255),
                bbA = Math.round(this.blue * 255),
                abA = Math.round(this.alpha * 255),
                rbB = Math.round(color.red * 255),
                gbB = Math.round(color.green * 255),
                bbB = Math.round(color.blue * 255),
                abB = Math.round(color.alpha * 255);

            return rbA === rbB && gbA === gbB && bbA === bbB && abA === abB;
        };

        /**
         * Indicates whether this color is equal to another color expressed as an array of bytes.
         * @param {Uint8Array} bytes The red, green, blue and alpha color components.
         * @returns {Boolean} true if the colors are equal, otherwise false.
         */
        Color.prototype.equalsBytes = function (bytes) {
            var rb = Math.round(this.red * 255),
                gb = Math.round(this.green * 255),
                bb = Math.round(this.blue * 255),
                ab = Math.round(this.alpha * 255);

            return rb === bytes[0] && gb === bytes[1] && bb === bytes[2] && ab === bytes[3];
        };

        /**
         * Returns a string representation of this color, indicating the byte values corresponding to this color's
         * floating-point component values.
         * @returns {String}
         */
        Color.prototype.toByteString = function () {
            var rb = Math.round(this.red * 255),
                gb = Math.round(this.green * 255),
                bb = Math.round(this.blue * 255),
                ab = Math.round(this.alpha * 255);

            return "(" + rb + "," + gb + "," + bb + "," + ab + ")";
        };

        /**
         * Create a hex color string that CSS can use. Optionally, inhibit capturing alpha,
         * because some uses reject a four-component color specification.
         * @param {Boolean} isUsingAlpha Enable the use of an alpha component.
         * @returns {string} A color string suitable for CSS.
         */
        Color.prototype.toHexString = function(isUsingAlpha) {
            // Use Math.ceil() to get 0.75 to map to 0xc0. This is important if the display is dithering.
            var redHex = Math.ceil(this.red * 255).toString(16),
                greenHex = Math.ceil(this.green * 255).toString(16),
                blueHex = Math.ceil(this.blue * 255).toString(16),
                alphaHex = Math.ceil(this.alpha * 255).toString(16);

            var result = "#";
            result += (redHex.length < 2) ? ('0' + redHex) : redHex;
            result += (greenHex.length < 2) ? ('0' + greenHex) : greenHex;
            result += (blueHex.length < 2) ? ('0' + blueHex) : blueHex;
            if (isUsingAlpha) {
                result += (alphaHex.length < 2) ? ('0' + alphaHex) : alphaHex;
            }

            return result;
        };

        /**
         * Create a rgba color string that CSS can use.
         * @returns {string} A color string suitable for CSS.
         */
        Color.prototype.toRGBAString = function () {
            var red = Math.floor(this.red * 255),
                green = Math.floor(this.green * 255),
                blue = Math.floor(this.blue * 255);

            return 'rgba(' + red + ' ,' + green + ' ,' + blue + ' ,' + this.alpha + ')';
        };

        return Color;
    });<commit_msg>Spacing in Color.js<commit_after>/*
 * Copyright (C) 2014 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration. All Rights Reserved.
 */
/**
 * @exports Color
 * @version $Id: Color.js 3017 2015-04-14 17:10:31Z dcollins $
 */
define([
        '../util/Logger'
    ],
    function (Logger) {
        "use strict";

        /**
         * Constructs a color from red, green, blue and alpha values.
         * @alias Color
         * @constructor
         * @classdesc Represents a red, green, blue, alpha, color.
         * @param {Number} red The red component, a number between 0 and 1.
         * @param {Number} green The green component, a number between 0 and 1.
         * @param {Number} blue The blue component, a number between 0 and 1.
         * @param {Number} alpha The alpha component, a number between 0 and 1.
         */
        var Color = function (red, green, blue, alpha) {

            /**
             * This color's red component, a number between 0 and 1.
             * @type {Number}
             */
            this.red = red;

            /**
             * This color's green component, a number between 0 and 1.
             * @type {Number}
             */
            this.green = green;

            /**
             * This color's blue component, a number between 0 and 1.
             * @type {Number}
             */
            this.blue = blue;

            /**
             * This color's alpha component, a number between 0 and 1.
             * @type {Number}
             */
            this.alpha = alpha;
        };

        /**
         * The color white.
         * @type {Color}
         * @constant
         */
        Color.WHITE = new Color(1, 1, 1, 1);

        /**
         * The color black.
         * @type {Color}
         * @constant
         */
        Color.BLACK = new Color(0, 0, 0, 1);

        /**
         * The color red.
         * @type {Color}
         * @constant
         */
        Color.RED = new Color(1, 0, 0, 1);

        /**
         * The color green.
         * @type {Color}
         * @constant
         */
        Color.GREEN = new Color(0, 1, 0, 1);

        /**
         * The color blue.
         * @type {Color}
         * @constant
         */
        Color.BLUE = new Color(0, 0, 1, 1);

        /**
         * The color cyan.
         * @type {Color}
         * @constant
         */
        Color.CYAN = new Color(0, 1, 1, 1);

        /**
         * The color yellow.
         * @type {Color}
         * @constant
         */
        Color.YELLOW = new Color(1, 1, 0, 1);

        /**
         * The color magenta.
         * @type {Color}
         * @constant
         */
        Color.MAGENTA = new Color(1, 0, 1, 1);

        /**
         * A light gray (75% white).
         * @type {Color}
         */
        Color.LIGHT_GRAY = new Color(0.75, 0.75, 0.75, 1);

        /**
         * A medium gray (50% white).
         * @type {Color}
         */
        Color.MEDIUM_GRAY = new Color(0.5, 0.5, 0.5, 1);

        /**
         * A dark gray (25% white).
         * @type {Color}
         */
        Color.DARK_GRAY = new Color(0.25, 0.25, 0.25, 1);

        /**
         * A transparent color.
         * @type {Color}
         */
        Color.TRANSPARENT = new Color(0, 0, 0, 0);

        /**
         * Assigns the components of this color.
         * @param {Number} red The red component, a number between 0 and 1.
         * @param {Number} green The green component, a number between 0 and 1.
         * @param {Number} blue The blue component, a number between 0 and 1.
         * @param {Number} alpha The alpha component, a number between 0 and 1.
         * @returns {Color} This color with the specified components assigned.
         */
        Color.prototype.set = function (red, green, blue, alpha) {
            this.red = red;
            this.green = green;
            this.blue = blue;
            this.alpha = alpha;

            return this;
        };

        /**
         * Copies the components of a specified color to this color.
         * @param {Color} color The color to copy.
         * @returns {Color} This color set to the red, green, blue and alpha values of the specified color.
         * @throws {ArgumentError} If the specified color is null or undefined.
         */
        Color.prototype.copy = function (color) {
            if (!color) {
                throw new ArgumentError(
                    Logger.logMessage(Logger.LEVEL_SEVERE, "Color", "copy", "missingColor"));
            }

            this.red = color.red;
            this.green = color.green;
            this.blue = color.blue;
            this.alpha = color.alpha;

            return this;
        };

        /**
         * Create a copy of this color.
         * @returns {Color} A new instance containing the color components of this color.
         */
        Color.prototype.clone = function () {
            return new Color(this.red, this.green, this.blue, this.alpha);
        };

        /**
         * Returns this color's components premultiplied by this color's alpha component.
         * @param {Float32Array} array A pre-allocated array in which to return the color components.
         * @returns {Float32Array} This colors premultiplied components as an array, in the order RGBA.
         */
        Color.prototype.premultipliedComponents = function (array) {
            var a = this.alpha;

            array[0] = this.red * a;
            array[1] = this.green * a;
            array[2] = this.blue * a;
            array[3] = a;

            return array;
        };

        /**
         * Construct a color from an array of color components expressed as byte values.
         * @param {Uint8Array} bytes A four-element array containing the red, green, blue and alpha color
         * components each in the range [0, 255];
         * @returns {Color} The constructed color.
         */
        Color.colorFromByteArray = function (bytes) {
            return new Color(bytes[0] / 255, bytes[1] / 255, bytes[2] / 255, bytes[3] / 255);
        };

        /**
         * Construct a color from specified color components expressed as byte values.
         * @param {number} redByte The red component in the range [0, 255].
         * @param {number} greenByte The green component in the range [0, 255].
         * @param {number} blueByte The blue component in the range [0, 255].
         * @param {number} alphaByte The alpha component in the range [0, 255].
         * @returns {Color} The constructed color.
         */
        Color.colorFromBytes = function (redByte, greenByte, blueByte, alphaByte) {
            return new Color(redByte / 255, greenByte / 255, blueByte / 255, alphaByte / 255);
        };

        Color.colorFromHex = function(color) {
            var red = parseInt(color.substring(0, 2), 16);
            var green = parseInt(color.substring(2, 4), 16);
            var blue = parseInt(color.substring(4, 6), 16);
            var alpha = parseInt(color.substring(6, 8), 16);
            return Color.colorFromBytes(red, green, blue, alpha);
        };

        Color.colorFromKmlHex = function(color) {
            var alpha = parseInt(color.substring(0, 2), 16);
            var blue = parseInt(color.substring(2, 4), 16);
            var green = parseInt(color.substring(4, 6), 16);
            var red = parseInt(color.substring(6, 8), 16);
            return Color.colorFromBytes(red, green, blue, alpha);
        };

        /**
         * Computes and sets this color to the next higher RBG color. If the color overflows, this color is set to
         * (1 / 255, 0, 0, *), where * indicates the current alpha value.
         * @returns {Color} This color, set to the next possible color.
         */
        Color.prototype.nextColor = function () {
            var rb = Math.round(this.red * 255),
                gb = Math.round(this.green * 255),
                bb = Math.round(this.blue * 255);

            if (rb < 255) {
                this.red = (rb + 1) / 255;
            } else if (gb < 255) {
                this.red = 0;
                this.green = (gb + 1) / 255;
            } else if (bb < 255) {
                this.red = 0;
                this.green = 0;
                this.blue = (bb + 1) / 255;
            } else {
                this.red = 1 / 255;
                this.green = 0;
                this.blue = 0;
            }

            return this;
        };

        /**
         * Indicates whether this color is equal to a specified color after converting the floating-point component
         * values of each color to byte values.
         * @param {Color} color The color to test,
         * @returns {Boolean} true if the colors are equal, otherwise false.
         */
        Color.prototype.equals = function (color) {
            var rbA = Math.round(this.red * 255),
                gbA = Math.round(this.green * 255),
                bbA = Math.round(this.blue * 255),
                abA = Math.round(this.alpha * 255),
                rbB = Math.round(color.red * 255),
                gbB = Math.round(color.green * 255),
                bbB = Math.round(color.blue * 255),
                abB = Math.round(color.alpha * 255);

            return rbA === rbB && gbA === gbB && bbA === bbB && abA === abB;
        };

        /**
         * Indicates whether this color is equal to another color expressed as an array of bytes.
         * @param {Uint8Array} bytes The red, green, blue and alpha color components.
         * @returns {Boolean} true if the colors are equal, otherwise false.
         */
        Color.prototype.equalsBytes = function (bytes) {
            var rb = Math.round(this.red * 255),
                gb = Math.round(this.green * 255),
                bb = Math.round(this.blue * 255),
                ab = Math.round(this.alpha * 255);

            return rb === bytes[0] && gb === bytes[1] && bb === bytes[2] && ab === bytes[3];
        };

        /**
         * Returns a string representation of this color, indicating the byte values corresponding to this color's
         * floating-point component values.
         * @returns {String}
         */
        Color.prototype.toByteString = function () {
            var rb = Math.round(this.red * 255),
                gb = Math.round(this.green * 255),
                bb = Math.round(this.blue * 255),
                ab = Math.round(this.alpha * 255);

            return "(" + rb + "," + gb + "," + bb + "," + ab + ")";
        };

        /**
         * Create a hex color string that CSS can use. Optionally, inhibit capturing alpha,
         * because some uses reject a four-component color specification.
         * @param {Boolean} isUsingAlpha Enable the use of an alpha component.
         * @returns {string} A color string suitable for CSS.
         */
        Color.prototype.toHexString = function(isUsingAlpha) {
            // Use Math.ceil() to get 0.75 to map to 0xc0. This is important if the display is dithering.
            var redHex = Math.ceil(this.red * 255).toString(16),
                greenHex = Math.ceil(this.green * 255).toString(16),
                blueHex = Math.ceil(this.blue * 255).toString(16),
                alphaHex = Math.ceil(this.alpha * 255).toString(16);

            var result = "#";
            result += (redHex.length < 2) ? ('0' + redHex) : redHex;
            result += (greenHex.length < 2) ? ('0' + greenHex) : greenHex;
            result += (blueHex.length < 2) ? ('0' + blueHex) : blueHex;
            if (isUsingAlpha) {
                result += (alphaHex.length < 2) ? ('0' + alphaHex) : alphaHex;
            }

            return result;
        };

        /**
         * Create a rgba color string that CSS can use.
         * @returns {string} A color string suitable for CSS.
         */
        Color.prototype.toRGBAString = function () {
            var red = Math.floor(this.red * 255),
                green = Math.floor(this.green * 255),
                blue = Math.floor(this.blue * 255);

            return 'rgba(' + red + ' ,' + green + ' ,' + blue + ' ,' + this.alpha + ')';
        };

        return Color;
    });
<|endoftext|>


<commit_before>import { csv } from 'd3';
import uuid from 'uuid';

function _formatJSON(links) {
  const nodesByName = {};

  function assignNode(name) {
    if (!nodesByName[name]) {
      nodesByName[name] = { name };
    }
    return nodesByName[name];
  }

  function assignNodeWithAttributes(name, attributes) {
    if (!nodesByName[name]) {
      nodesByName[name] = {
        name,
        attributes,
      };
    }
    return nodesByName[name];
  }

  // Create nodes for each unique source and target.
  links.forEach((link) => {
    link.source = assignNode(link.parent);
    link.target = assignNodeWithAttributes(link.child, link.attributes);
    const parent = link.source;
    const child = link.target;

    parent.id = uuid.v4();
    child.id = uuid.v4();
    child.parent = parent.name || null;

    parent._collapsed = child._collapsed = false; // eslint-disable-line
    // NOTE We assign to a custom `_children` field instead of D3's reserved
    // `children` to avoid update anomalies when collapsing/re-expanding nodes.
    parent._children ? parent._children.push(child) : parent._children = [child];
  });

  return links;
}

function _extractRootNode(links) {
  // Locate all node relations where `source` has an undefined `parent` field.
  const rootLinks = links.filter((link) => !link.source.parent);
  return [rootLinks[0].source];
}

function parseCSV(csvFile) {
  return new Promise((resolve, reject) => {
    try {
      csv(csvFile, (json) => resolve(_extractRootNode(_formatJSON(json)))); // lol hello Lisp
    } catch (err) {
      reject(err);
    }
  });
}

export default {
  parseCSV,
};
<commit_msg>Combines `_extractRootNode` & `_formatJSON` into `_transformHierarchy`<commit_after>import { csv, json } from 'd3';
import uuid from 'uuid';

function _transformToHierarchy(links, attributeFields) {
  const nodesByName = {};

  const assignNode = (name) => {
    if (!nodesByName[name]) {
      nodesByName[name] = { name };
    }
    return nodesByName[name];
  };

  const assignNodeWithAttributes = (name, attributes) => {
    if (!nodesByName[name]) {
      nodesByName[name] = {
        name,
        attributes,
      };
    }
    return nodesByName[name];
  };

  // Create nodes for each unique source and target.
  links.forEach((link) => {
    // if `attributeFields` is defined, create/overwrite current `link.attributes`
    if (attributeFields) {
      const customAttributes = {};
      attributeFields.forEach((field) => {
        customAttributes[field] = link[field];
      });
      link.attributes = customAttributes;
    }

    link.source = assignNode(link.parent);
    link.target = assignNodeWithAttributes(link.child, link.attributes);
    const parent = link.source;
    const child = link.target;

    parent.id = uuid.v4();
    child.id = uuid.v4();
    child.parent = parent.name || null;

    parent._collapsed = child._collapsed = false; // eslint-disable-line
    // NOTE We assign to a custom `_children` field instead of D3's reserved
    // `children` to avoid update anomalies when collapsing/re-expanding nodes.
    parent._children ? parent._children.push(child) : parent._children = [child];
  });

  // Extract & return the root node
  const rootLinks = links.filter((link) => !link.source.parent);
  return [rootLinks[0].source];
}

function parseCSV(csvFile, attributeFields) {
  return new Promise((resolve, reject) => {
    try {
      csv(csvFile, (data) => resolve(_transformToHierarchy(data, attributeFields))); // lol hello Lisp
    } catch (err) {
      reject(err);
    }
  });
}

function parseJSON(jsonFile) {
  return new Promise((resolve, reject) => {
    try {
      json(jsonFile, (data) => resolve([data]));
    } catch (err) {
      reject(err);
    }
  });
}

function parseFlatJSON(jsonFile, attributeFields) {
  return new Promise((resolve, reject) => {
    try {
      json(jsonFile, (data) => resolve(_transformToHierarchy(data, attributeFields)));
    } catch (err) {
      reject(err);
    }
  });
}

export default {
  parseCSV,
  parseJSON,
  parseFlatJSON,
};
<|endoftext|>


<commit_before>import jQuery from 'jquery'

import { BaseView } from '../view/base-view'

export const Popup = {
  // Keeps track of unique IDs for popup-enabled elements, to allow closing
  // of the popup, in the event of a second click on the associated element
  _popupID:  -1,
  _popupIDs: 1,

  _detach: false,
  _clickAwayBound: false,

  // Keeps track of callback function to execute on closing the popup
  _closeCallback: null,

  _view: null,

  classNames: {
    root: 'popup',
    leftAligned: 'popup--left-aligned',
    rightAligned: 'popup--right-aligned',
    topAligned: 'popup--top-aligned',
    bottomAligned: 'popup--bottom-aligned',
    menu: 'popup__menu',
    menuItem: 'popup__menu-item',
    menuSeparator: 'popup__menu-separator',
    menuHr: 'popup__menu-hr',
    menuLink: 'popup__menu-link',
  },

  keyDown(key) {
    if (key === BaseView.VK_ESCAPE) {
      this.close();
      return true;
    }
  },

  close() {
    if (this._popupID) {
      const onClose = this._closeCallback;
      this._closeCallback = null;
      this._popupID = null;
      if (this._view) { this._view.returnKeyboardFocus(); }
      BaseView.method('returnKeyboardFocus').call(this);
      return jQuery(`.${this.classNames.root}`).removeAttr('id').stop().fadeOut(100, function() {
        if (onClose) { onClose(); }
        if (this._view) {
          this._view.release();
          this._view = null;
        }

        if (Popup._detach) {
          jQuery(this).children().detach();
        } else if (Popup._reattach) {
          jQuery(document.body).append(jQuery(this).children().hide());
        }

        return jQuery(this).remove();
      });
    }
  },

  nextId() {
    return this._popupIDs++;
  },

  show(element, id, display, options) {
    if (options == null) { options = {}; }
    if (this._popupID === id) { return this.close(); }
    this.close();

    if (!this._clickAwayBound) {
      this.bindClickAway()
    }

    this._popupID = id;
    this._detach = options.detach;
    this._reattach = options.reattach;

    const offset = element.offset();

    const popup = jQuery(`<div class="${this.classNames.root}"></div>`);

    this._closeCallback = function() {
      if (options.close) { return options.close.call(element, element); }
    };

    BaseView.method('takeKeyboardFocus').call(this);

    if (display instanceof BaseView) {
      this._view = display;
      display.load();
      display.takeKeyboardFocus();
      popup.append(display.element());
    } else if (display instanceof jQuery) {
      popup.append(display.show());
    } else {
      const ul = jQuery(`<ul class="${this.classNames.menu}"></ul>`);
      popup.append(ul);

      for (let item of Array.from(display)) {
        if (item === '-') {
          ul.append(`<li class="${this.classNames.menuSeparator}"><hr class="${this.classNames.menuHr}" /></li>`);
        } else {
          (item => {
            const li = jQuery(`<li class="${this.classNames.menuItem}"></li>`);
            if (item.className) { li.addClass(item.className); }
            const a = jQuery(`<a class="${this.classNames.menuLink}" href="javascript:;">${item.title || item[0]}</a>`);
            a.click(e => {
              this.close();
              if (item.action) { item.action(); }
              if (item[1]) { return item[1](); }
          });
            li.append(a);
            return ul.append(li);
          })(item);
        }
      }
    }

    popup.mousedown(e => e.stopPropagation());

    popup.appendTo(document.body);

    const css = {
      display:  'none',
      position: 'absolute'
    };

    if ((offset.left < (jQuery(window).width() - 150)) && !options.right) {
      css.left = Math.round(offset.left);
      popup.addClass(this.classNames.leftAligned);
    } else {
      css.right = Math.round(jQuery(window).width() - offset.left - element.outerWidth());
      popup.addClass(this.classNames.rightAligned);
    }

    if (!options.bottom) {
      css.top = Math.floor(offset.top + element.outerHeight());
      popup.addClass(this.classNames.topAligned);
    } else {
      css.top = Math.floor(offset.top - popup.outerHeight() - (options.offsetY || 0));
      popup.addClass(this.classNames.bottomAligned);
    }

    return popup.css(css).fadeIn(100);
  },

  toString() {
    return 'Popup';
  },

  bindClickAway() {
    jQuery(document.body).mousedown(() => Popup.close())
    this._clickAwayBound = true
  }
};

// Associates a popup menu with selected elements.
// items   Items for menu, see #popup
// open    Callback function to execute before opening the popup menu
// close   Callback function to execute after the popup menu is closed
export const makePopup = (element, items, open, close, options) => {
  const id = Popup.nextId();
  element.mousedown(e => e.stopPropagation());

  let el = null;

  options = jQuery.extend({}, options);
  options._close = options.close;
  options.close = function() {
    if (close) { close.call(element, element); }
    if (options._close) { return options._close.call(element, element); }
  };

  element.click(function(e) {
    e.preventDefault();
    if (Popup._popupID === id) {
      return Popup.close();
    } else {
      Popup.show(jQuery(this), id, (items.call ? items.call(element, e.altKey || e.shiftKey) : items), options);
      if (open) { open.call(element, element); }
      if (options.open) { return options.open.call(element, element); }
    }
  });
};
<commit_msg>feat: make it possible to access DOM event from dropdown item callbacks<commit_after>import jQuery from 'jquery'

import { BaseView } from '../view/base-view'

export const Popup = {
  // Keeps track of unique IDs for popup-enabled elements, to allow closing
  // of the popup, in the event of a second click on the associated element
  _popupID:  -1,
  _popupIDs: 1,

  _detach: false,
  _clickAwayBound: false,

  // Keeps track of callback function to execute on closing the popup
  _closeCallback: null,

  _view: null,

  classNames: {
    root: 'popup',
    leftAligned: 'popup--left-aligned',
    rightAligned: 'popup--right-aligned',
    topAligned: 'popup--top-aligned',
    bottomAligned: 'popup--bottom-aligned',
    menu: 'popup__menu',
    menuItem: 'popup__menu-item',
    menuSeparator: 'popup__menu-separator',
    menuHr: 'popup__menu-hr',
    menuLink: 'popup__menu-link',
  },

  keyDown(key) {
    if (key === BaseView.VK_ESCAPE) {
      this.close();
      return true;
    }
  },

  close() {
    if (this._popupID) {
      const onClose = this._closeCallback;
      this._closeCallback = null;
      this._popupID = null;
      if (this._view) { this._view.returnKeyboardFocus(); }
      BaseView.method('returnKeyboardFocus').call(this);
      return jQuery(`.${this.classNames.root}`).removeAttr('id').stop().fadeOut(100, function() {
        if (onClose) { onClose(); }
        if (this._view) {
          this._view.release();
          this._view = null;
        }

        if (Popup._detach) {
          jQuery(this).children().detach();
        } else if (Popup._reattach) {
          jQuery(document.body).append(jQuery(this).children().hide());
        }

        return jQuery(this).remove();
      });
    }
  },

  nextId() {
    return this._popupIDs++;
  },

  show(element, id, display, options) {
    if (options == null) { options = {}; }
    if (this._popupID === id) { return this.close(); }
    this.close();

    if (!this._clickAwayBound) {
      this.bindClickAway()
    }

    this._popupID = id;
    this._detach = options.detach;
    this._reattach = options.reattach;

    const offset = element.offset();

    const popup = jQuery(`<div class="${this.classNames.root}"></div>`);

    this._closeCallback = function() {
      if (options.close) { return options.close.call(element, element); }
    };

    BaseView.method('takeKeyboardFocus').call(this);

    if (display instanceof BaseView) {
      this._view = display;
      display.load();
      display.takeKeyboardFocus();
      popup.append(display.element());
    } else if (display instanceof jQuery) {
      popup.append(display.show());
    } else {
      const ul = jQuery(`<ul class="${this.classNames.menu}"></ul>`);
      popup.append(ul);

      for (let item of Array.from(display)) {
        if (item === '-') {
          ul.append(`<li class="${this.classNames.menuSeparator}"><hr class="${this.classNames.menuHr}" /></li>`);
        } else {
          (item => {
            const li = jQuery(`<li class="${this.classNames.menuItem}"></li>`);
            if (item.className) { li.addClass(item.className); }
            const a = jQuery(`<a class="${this.classNames.menuLink}" href="javascript:;">${item.title || item[0]}</a>`);
            a.click(e => {
              this.close();
              const action = item.action || item[1]
              if (action) action.call(item, e)
          });
            li.append(a);
            return ul.append(li);
          })(item);
        }
      }
    }

    popup.mousedown(e => e.stopPropagation());

    popup.appendTo(document.body);

    const css = {
      display:  'none',
      position: 'absolute'
    };

    if ((offset.left < (jQuery(window).width() - 150)) && !options.right) {
      css.left = Math.round(offset.left);
      popup.addClass(this.classNames.leftAligned);
    } else {
      css.right = Math.round(jQuery(window).width() - offset.left - element.outerWidth());
      popup.addClass(this.classNames.rightAligned);
    }

    if (!options.bottom) {
      css.top = Math.floor(offset.top + element.outerHeight());
      popup.addClass(this.classNames.topAligned);
    } else {
      css.top = Math.floor(offset.top - popup.outerHeight() - (options.offsetY || 0));
      popup.addClass(this.classNames.bottomAligned);
    }

    return popup.css(css).fadeIn(100);
  },

  toString() {
    return 'Popup';
  },

  bindClickAway() {
    jQuery(document.body).mousedown(() => Popup.close())
    this._clickAwayBound = true
  }
};

// Associates a popup menu with selected elements.
// items   Items for menu, see #popup
// open    Callback function to execute before opening the popup menu
// close   Callback function to execute after the popup menu is closed
export const makePopup = (element, items, open, close, options) => {
  const id = Popup.nextId();
  element.mousedown(e => e.stopPropagation());

  let el = null;

  options = jQuery.extend({}, options);
  options._close = options.close;
  options.close = function() {
    if (close) { close.call(element, element); }
    if (options._close) { return options._close.call(element, element); }
  };

  element.click(function(e) {
    e.preventDefault();
    if (Popup._popupID === id) {
      return Popup.close();
    } else {
      Popup.show(jQuery(this), id, (items.call ? items.call(element, e.altKey || e.shiftKey) : items), options);
      if (open) { open.call(element, element); }
      if (options.open) { return options.open.call(element, element); }
    }
  });
};
<|endoftext|>


<commit_before>import { createStore, combineReducers, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import { handleRequest } from './apiConnection'

import availableRolesReducer from '../containers/Role/services/availableRolesReducer'
import userReducer from '../containers/User/services/userReducer'
import agreementReducer from '../containers/Agreement/services/agreementReducer'
import attachmentReducer from '../containers/Attachment/services/attachmentReducer'
import councilmeetingReducer from '../containers/CouncilMeeting/services/councilmeetingReducer'
import thesisReducer from '../containers/Thesis/services/thesisReducer'
import studyfieldReducer from '../containers/Studyfield/services/studyfieldReducer'
import programmeReducer from '../containers/Unit/services/programmeReducer'
import emailReducer from '../containers/Email/services/emailReducer'
import personReducer from '../containers/Person/services/personReducer'
import roleReducer from '../containers/Role/services/roleReducer'
import notificationsReducer from '../containers/Notification/services/notificationsReducer'
import eventMessageReducer from '../containers/EventMessage/services/eventMessageReducer'
import inviteReducer from '../containers/Invite/services/inviteReducer'
import statisticsReducer from '../containers/Statistics/services/statisticsReducer'

const combinedReducers = combineReducers({
    agreements: agreementReducer,
    attachments: attachmentReducer,
    availableRoles: availableRolesReducer,
    user: userReducer,
    councilmeetings: councilmeetingReducer,
    roles: roleReducer,
    theses: thesisReducer,
    studyfields: studyfieldReducer,
    programmes: programmeReducer,
    emails: emailReducer,
    persons: personReducer,
    notifications: notificationsReducer,
    eventMessage: eventMessageReducer,
    invite: inviteReducer,
    statistics: statisticsReducer
})

const store = createStore(
    combinedReducers,
    compose(applyMiddleware(thunk, handleRequest)),
    // eslint-disable-next-line
    (process.env.NODE_ENV !== 'production' && window.__REDUX_DEVTOOLS_EXTENSION__) && window.__REDUX_DEVTOOLS_EXTENSION__()
)

export default store
<commit_msg>Fix store initialize<commit_after>import { createStore, combineReducers, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import { handleRequest } from './apiConnection'

import availableRolesReducer from '../containers/Role/services/availableRolesReducer'
import userReducer from '../containers/User/services/userReducer'
import agreementReducer from '../containers/Agreement/services/agreementReducer'
import attachmentReducer from '../containers/Attachment/services/attachmentReducer'
import councilmeetingReducer from '../containers/CouncilMeeting/services/councilmeetingReducer'
import thesisReducer from '../containers/Thesis/services/thesisReducer'
import studyfieldReducer from '../containers/Studyfield/services/studyfieldReducer'
import programmeReducer from '../containers/Unit/services/programmeReducer'
import emailReducer from '../containers/Email/services/emailReducer'
import personReducer from '../containers/Person/services/personReducer'
import roleReducer from '../containers/Role/services/roleReducer'
import notificationsReducer from '../containers/Notification/services/notificationsReducer'
import eventMessageReducer from '../containers/EventMessage/services/eventMessageReducer'
import inviteReducer from '../containers/Invite/services/inviteReducer'
import statisticsReducer from '../containers/Statistics/services/statisticsReducer'

const combinedReducers = combineReducers({
    agreements: agreementReducer,
    attachments: attachmentReducer,
    availableRoles: availableRolesReducer,
    user: userReducer,
    councilmeetings: councilmeetingReducer,
    roles: roleReducer,
    theses: thesisReducer,
    studyfields: studyfieldReducer,
    programmes: programmeReducer,
    emails: emailReducer,
    persons: personReducer,
    notifications: notificationsReducer,
    eventMessage: eventMessageReducer,
    invite: inviteReducer,
    statistics: statisticsReducer
})

// eslint-disable-next-line
const composeEnhancers = (process.env.NODE_ENV !== 'production' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;
const store = createStore(
    combinedReducers,
    composeEnhancers(applyMiddleware(thunk, handleRequest))
)

export default store
<|endoftext|>


<commit_before>THREE.EdgeSplitModifier = function () {

	var A = new THREE.Vector3();
	var B = new THREE.Vector3();
	var C = new THREE.Vector3();

	var positions, normals;
	var indexes;
	var pointToIndexMap, splitIndexes;

	function computeNormals() {

		normals = new Float32Array( indexes.length * 3 );

		for ( var i = 0; i < indexes.length; i += 3 ) {

			var index = indexes[ i ];

			A.set(
				positions[ 3 * index ],
				positions[ 3 * index + 1 ],
				positions[ 3 * index + 2 ] );

			index = indexes[ i + 1 ];
			B.set(
				positions[ 3 * index ],
				positions[ 3 * index + 1 ],
				positions[ 3 * index + 2 ] );

			index = indexes[ i + 2 ];
			C.set(
				positions[ 3 * index ],
				positions[ 3 * index + 1 ],
				positions[ 3 * index + 2 ] );

			C.sub( B );
			A.sub( B );

			var normal = C.cross( A ).normalize();

			for ( var j = 0; j < 3; j ++ ) {

				normals[ 3 * ( i + j ) ] = normal.x;
				normals[ 3 * ( i + j ) + 1 ] = normal.y;
				normals[ 3 * ( i + j ) + 2 ] = normal.z;

			}

		}

	}

	function mapPositionsToIndexes() {

		pointToIndexMap = Array( positions.length / 3 );

		for ( var i = 0; i < indexes.length; i ++ ) {

			var index = indexes[ i ];

			if ( pointToIndexMap[ index ] == null ) {

				pointToIndexMap[ index ] = [];

			}

			pointToIndexMap[ index ].push( i );

		}

	}

	function edgeSplitToGroups( indexes, cutOff, firstIndex ) {

		A.set( normals[ 3 * firstIndex ], normals[ 3 * firstIndex + 1 ], normals[ 3 * firstIndex + 2 ] ).normalize();

		var result = {
			splitGroup: [],
			currentGroup: [ firstIndex ]
		};

		for ( var j of indexes ) {

			if ( j !== firstIndex ) {

				B.set( normals[ 3 * j ], normals[ 3 * j + 1 ], normals[ 3 * j + 2 ] ).normalize();

				if ( B.dot( A ) < cutOff ) {

					result.splitGroup.push( j );

				} else {

					result.currentGroup.push( j );

				}

			}

		}

		return result;

	}

	function edgeSplit( indexes, cutOff, original = null ) {

		if ( indexes.length === 0 ) return;

		var groupResults = [];

		for ( var index of indexes ) {

			groupResults.push( edgeSplitToGroups( indexes, cutOff, index ) );

		}

		var result = groupResults[ 0 ];

		for ( var groupResult of groupResults ) {

			if ( groupResult.currentGroup.length > result.currentGroup.length ) {

				result = groupResult;

			}

		}

		if ( original != null ) {

			splitIndexes.push( {
				original: original,
				indexes: result.currentGroup
			} );

		}

		if ( result.splitGroup.length ) {

			edgeSplit( result.splitGroup, cutOff, original || result.currentGroup[ 0 ] );

		}

	}

	this.modify = function ( geometry, cutOffAngle ) {

		const wasNotBufferGeometry = geometry.isBufferGeometry === undefined;
		if ( ! geometry.isBufferGeometry ) {

			geometry = new THREE.BufferGeometry().fromGeometry( geometry );

		}

		let hadNormals = false;
		if ( geometry.attributes.normal ) {

			hadNormals = true;

			if ( wasNotBufferGeometry === false )
				geometry = geometry.clone();

			geometry.deleteAttribute( 'normal' );

		}

		if ( geometry.index == null ) {

			if ( THREE.BufferGeometryUtils === undefined ) {

			 	throw 'THREE.EdgeSplitModifier relies on THREE.BufferGeometryUtils';

			}

			geometry = THREE.BufferGeometryUtils.mergeVertices( geometry );

		}

		indexes = geometry.index.array;
		positions = geometry.getAttribute( 'position' ).array;

		computeNormals();
		mapPositionsToIndexes();

		splitIndexes = [];

		for ( var vertexIndexes of pointToIndexMap ) {

			edgeSplit( vertexIndexes, Math.cos( cutOffAngle ) - 0.001 );

		}

		const newAttributes = {};
		for ( const name of Object.keys( geometry.attributes ) ) {

			const oldAttribute = geometry.attributes[ name ];
			const newArray = new oldAttribute.array.constructor( ( indexes.length + splitIndexes.length ) * oldAttribute.itemSize );
			newArray.set( oldAttribute.array );
			newAttributes[ name ] = new THREE.BufferAttribute( newArray, oldAttribute.itemSize, oldAttribute.normalized );

		}

		var newIndexes = new Uint32Array( indexes.length );
		newIndexes.set( indexes );

		for ( var i = 0; i < splitIndexes.length; i ++ ) {

			var split = splitIndexes[ i ];
			var index = indexes[ split.original ];

			for ( const attribute of Object.values( newAttributes ) ) {

				for ( let j = 0; j < attribute.itemSize; j ++ ) {

					attribute.array[ ( indexes.length + i ) * attribute.itemSize + j ] =
						attribute.array[ index * attribute.itemSize + j ];

				}

			}

			for ( var j of split.indexes ) {

				newIndexes[ j ] = indexes.length + i;

			}

		}

		geometry = new THREE.BufferGeometry();
		geometry.setIndex( new THREE.BufferAttribute( newIndexes, 1 ) );

		for ( const name of Object.keys( newAttributes ) ) {

			geometry.setAttribute( name, newAttributes[ name ] );

		}

		if ( hadNormals ) {

			geometry.computeVertexNormals();

		}

		return geometry;

	};

};
<commit_msg>tryKeepNormals added to JS module<commit_after>THREE.EdgeSplitModifier = function () {

	var A = new THREE.Vector3();
	var B = new THREE.Vector3();
	var C = new THREE.Vector3();

	var positions, normals;
	var indexes;
	var pointToIndexMap, splitIndexes;
	let oldNormals;

	function computeNormals() {

		normals = new Float32Array( indexes.length * 3 );

		for ( var i = 0; i < indexes.length; i += 3 ) {

			var index = indexes[ i ];

			A.set(
				positions[ 3 * index ],
				positions[ 3 * index + 1 ],
				positions[ 3 * index + 2 ] );

			index = indexes[ i + 1 ];
			B.set(
				positions[ 3 * index ],
				positions[ 3 * index + 1 ],
				positions[ 3 * index + 2 ] );

			index = indexes[ i + 2 ];
			C.set(
				positions[ 3 * index ],
				positions[ 3 * index + 1 ],
				positions[ 3 * index + 2 ] );

			C.sub( B );
			A.sub( B );

			var normal = C.cross( A ).normalize();

			for ( var j = 0; j < 3; j ++ ) {

				normals[ 3 * ( i + j ) ] = normal.x;
				normals[ 3 * ( i + j ) + 1 ] = normal.y;
				normals[ 3 * ( i + j ) + 2 ] = normal.z;

			}

		}

	}

	function mapPositionsToIndexes() {

		pointToIndexMap = Array( positions.length / 3 );

		for ( var i = 0; i < indexes.length; i ++ ) {

			var index = indexes[ i ];

			if ( pointToIndexMap[ index ] == null ) {

				pointToIndexMap[ index ] = [];

			}

			pointToIndexMap[ index ].push( i );

		}

	}

	function edgeSplitToGroups( indexes, cutOff, firstIndex ) {

		A.set( normals[ 3 * firstIndex ], normals[ 3 * firstIndex + 1 ], normals[ 3 * firstIndex + 2 ] ).normalize();

		var result = {
			splitGroup: [],
			currentGroup: [ firstIndex ]
		};

		for ( var j of indexes ) {

			if ( j !== firstIndex ) {

				B.set( normals[ 3 * j ], normals[ 3 * j + 1 ], normals[ 3 * j + 2 ] ).normalize();

				if ( B.dot( A ) < cutOff ) {

					result.splitGroup.push( j );

				} else {

					result.currentGroup.push( j );

				}

			}

		}

		return result;

	}

	function edgeSplit( indexes, cutOff, original = null ) {

		if ( indexes.length === 0 ) return;

		var groupResults = [];

		for ( var index of indexes ) {

			groupResults.push( edgeSplitToGroups( indexes, cutOff, index ) );

		}

		var result = groupResults[ 0 ];

		for ( var groupResult of groupResults ) {

			if ( groupResult.currentGroup.length > result.currentGroup.length ) {

				result = groupResult;

			}

		}

		if ( original != null ) {

			splitIndexes.push( {
				original: original,
				indexes: result.currentGroup
			} );

		}

		if ( result.splitGroup.length ) {

			edgeSplit( result.splitGroup, cutOff, original || result.currentGroup[ 0 ] );

		}

	}

	this.modify = function ( geometry, cutOffAngle, tryKeepNormals = true ) {

		const wasNotBufferGeometry = geometry.isBufferGeometry === undefined;
		if ( ! geometry.isBufferGeometry ) {

			geometry = new THREE.BufferGeometry().fromGeometry( geometry );

		}

		let hadNormals = false;
		oldNormals = null;
		if ( geometry.attributes.normal ) {

			hadNormals = true;

			if ( wasNotBufferGeometry === false )
				geometry = geometry.clone();

			if ( tryKeepNormals && geometry.index )
				oldNormals = geometry.attributes.normal.array;

			geometry.deleteAttribute( 'normal' );

		}

		if ( geometry.index == null ) {

			if ( THREE.BufferGeometryUtils === undefined ) {

			 	throw 'THREE.EdgeSplitModifier relies on THREE.BufferGeometryUtils';

			}

			geometry = THREE.BufferGeometryUtils.mergeVertices( geometry );

		}

		indexes = geometry.index.array;
		positions = geometry.getAttribute( 'position' ).array;

		computeNormals();
		mapPositionsToIndexes();

		splitIndexes = [];

		for ( var vertexIndexes of pointToIndexMap ) {

			edgeSplit( vertexIndexes, Math.cos( cutOffAngle ) - 0.001 );

		}

		const newAttributes = {};
		for ( const name of Object.keys( geometry.attributes ) ) {

			const oldAttribute = geometry.attributes[ name ];
			const newArray = new oldAttribute.array.constructor( ( indexes.length + splitIndexes.length ) * oldAttribute.itemSize );
			newArray.set( oldAttribute.array );
			newAttributes[ name ] = new THREE.BufferAttribute( newArray, oldAttribute.itemSize, oldAttribute.normalized );

		}

		var newIndexes = new Uint32Array( indexes.length );
		newIndexes.set( indexes );

		for ( var i = 0; i < splitIndexes.length; i ++ ) {

			var split = splitIndexes[ i ];
			var index = indexes[ split.original ];

			for ( const attribute of Object.values( newAttributes ) ) {

				for ( let j = 0; j < attribute.itemSize; j ++ ) {

					attribute.array[ ( indexes.length + i ) * attribute.itemSize + j ] =
						attribute.array[ index * attribute.itemSize + j ];

				}

			}

			for ( var j of split.indexes ) {

				newIndexes[ j ] = indexes.length + i;

			}

		}

		geometry = new THREE.BufferGeometry();
		geometry.setIndex( new THREE.BufferAttribute( newIndexes, 1 ) );

		for ( const name of Object.keys( newAttributes ) ) {

			geometry.setAttribute( name, newAttributes[ name ] );

		}

		if ( hadNormals ) {

			geometry.computeVertexNormals();

			if ( oldNormals !== null ) {

				const changedNormals = new Array( oldNormals.length / 3 ).fill( false );

				for ( const splitData of splitIndexes )
					changedNormals[ splitData.original ] = true;

				for ( let i = 0; i < changedNormals.length; i ++ ) {

					if ( changedNormals[ i ] === false ) {

						for ( let j = 0; j < 3; j ++ )
							geometry.attributes.normal.array[ 3 * i + j ] = oldNormals[ 3 * i + j ];

					}

				}

			}

		}

		return geometry;

	};

};
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var levels = require('../levels');
var times = require('../times');

function init (ctx) {

  var translate = ctx.language.translate;

  var bwp = {
    name: 'bwp'
    , label: 'Bolus Wizard Preview'
    , pluginType: 'pill-minor'
  };

  function checkMissingInfo (sbx) {
    var errors = [];
    if (!sbx.data.profile || !sbx.data.profile.hasData()) {
      errors.push('Missing need a treatment profile');
    } else if (profileFieldsMissing(sbx)) {
      errors.push('Missing sens, target_high, or target_low treatment profile fields');
    }

    if (!sbx.properties.iob) {
      errors.push('Missing IOB property');
    }

    if (!isSGVOk(sbx)) {
      errors.push('Data isn\'t current');
    }

    return errors;
  }

  bwp.setProperties = function setProperties(sbx) {
    sbx.offerProperty('bwp', function setBWP ( ) {
      return bwp.calc(sbx);
    });
  };

  bwp.checkNotifications = function checkNotifications (sbx) {

    var prop = sbx.properties.bwp;
    if (prop === undefined) { return; }

    var settings = prepareSettings(sbx);

    if (bwp.highSnoozedByIOB(prop, settings, sbx)) {
      sbx.notifications.requestSnooze({
        level: levels.URGENT
        , title: translate('Snoozing high alarm since there is enough IOB')
        , message: [sbx.propertyLine('bwp'), sbx.propertyLine('iob')].join('\n')
        , lengthMills: settings.snoozeLength
        , debug: prop
      });
    } else if (prop.scaledSGV > sbx.data.profile.getHighBGTarget(sbx.time) && prop.bolusEstimate > settings.warnBWP) {
      var level = prop.bolusEstimate > settings.urgentBWP ? levels.URGENT : levels.WARN;
      var levelLabel = levels.toDisplay(level);
      var sound = level === levels.URGENT ? 'updown' : 'bike';

      sbx.notifications.requestNotify({
        level: level
        , title: levelLabel + ', ' + translate('Check BG, time to bolus?')
        , message: sbx.buildDefaultMessage()
        , eventName: 'bwp'
        , pushoverSound: sound
        , plugin: bwp
        , debug: prop
      });
    }
  };

  bwp.highSnoozedByIOB = function highSnoozedByIOB(prop, settings, sbx) {
    var ar2EventType = sbx.properties.ar2 && sbx.properties.ar2.eventType;
    var high = ar2EventType === 'high' || prop.scaledSGV >= sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop);

    return high && prop.bolusEstimate < settings.snoozeBWP;
  };

  bwp.updateVisualisation = function updateVisualisation (sbx) {

    var prop = sbx.properties.bwp;

    var info = [];
    pushInfo(prop, info, sbx);

    var value;
    if (prop && prop.bolusEstimateDisplay >= 0) {
      value = prop.bolusEstimateDisplay + 'U';
    } else if (prop && prop.bolusEstimateDisplay < 0) {
      value = '< 0U';
    }

    sbx.pluginBase.updatePillText(bwp, {
      value: value
      , label: translate('BWP')
      , info: info
    });
  };

  bwp.calc = function calc (sbx) {

    var results = {
      effect: 0
      , outcome: 0
      , bolusEstimate: 0.0
    };

    var scaled = sbx.lastScaledSGV();

    results.scaledSGV = scaled;

    var errors = checkMissingInfo(sbx);

    if (errors && errors.length > 0) {
      results.errors = errors;
      return results;
    }

    var profile = sbx.data.profile;
    var iob = results.iob = sbx.properties.iob.iob || 0;

    results.effect = iob * profile.getSensitivity(sbx.time);
    results.outcome = scaled - results.effect;
    var delta = 0;

    var recentCarbs = _.findLast(sbx.data.treatments, function eachTreatment (treatment) {
      return treatment.mills <= sbx.time &&
        sbx.time - treatment.mills < times.mins(60).msecs &&
        treatment.carbs > 0;
    });

    results.recentCarbs = recentCarbs;

    var target_high = profile.getHighBGTarget(sbx.time);
    var sens = profile.getSensitivity(sbx.time);

    if (results.outcome > target_high) {
      delta = results.outcome - target_high;
      results.bolusEstimate = delta / sens;
      results.aimTarget = target_high;
      results.aimTargetString = 'above high';
    }

    var target_low = profile.getLowBGTarget(sbx.time);

    results.belowLowTarget = false;
    if (scaled < target_low) {
      results.belowLowTarget = true;
    }

    if (results.outcome < target_low) {
      delta = Math.abs(results.outcome - target_low);
      results.bolusEstimate = delta / sens * -1;
      results.aimTarget = target_low;
      results.aimTargetString = 'below low';
    }

    if (results.bolusEstimate !== 0 && sbx.data.profile.getBasal(sbx.time)) {
      // Basal profile exists, calculate % change
      var basal = sbx.data.profile.getBasal(sbx.time);

      var thirtyMinAdjustment = Math.round((basal/2 + results.bolusEstimate) / (basal / 2) * 100);
      var oneHourAdjustment = Math.round((basal + results.bolusEstimate) / basal * 100);

      results.tempBasalAdjustment = {
        'thirtymin': thirtyMinAdjustment
        ,'onehour': oneHourAdjustment};
    }

    results.bolusEstimateDisplay = sbx.roundInsulinForDisplayFormat(results.bolusEstimate);
    results.outcomeDisplay = sbx.roundBGToDisplayFormat(results.outcome);
    results.displayIOB = sbx.roundInsulinForDisplayFormat(results.iob);
    results.effectDisplay = sbx.roundBGToDisplayFormat(results.effect);
    results.displayLine = translate('BWP') + ': ' + results.bolusEstimateDisplay + 'U';

    return results;
  };

  function prepareSettings (sbx) {
    return {
      snoozeBWP: Number(sbx.extendedSettings.snooze) || 0.10
    , warnBWP: Number(sbx.extendedSettings.warn) || 0.50
    , urgentBWP: Number(sbx.extendedSettings.urgent) || 1.00
    , snoozeLength: (sbx.extendedSettings.snoozeMins && Number(sbx.extendedSettings.snoozeMins) * 60 * 1000) || times.mins(10).msecs
    };
  }

  function isSGVOk (sbx) {
    var lastSGVEntry = sbx.lastSGVEntry();
    return lastSGVEntry && lastSGVEntry.mgdl >= 39 && sbx.isCurrent(lastSGVEntry);
  }

  function profileFieldsMissing (sbx) {
    return !sbx.data.profile.getSensitivity(sbx.time)
      || !sbx.data.profile.getHighBGTarget(sbx.time)
      || !sbx.data.profile.getLowBGTarget(sbx.time);
  }

  function pushInfo(prop, info, sbx) {
    if (prop && prop.errors) {
      info.push({label: translate('Notice'), value: translate('required info missing')});
      _.each(prop.errors, function pushError (error) {
        info.push({label: '  • ', value: error});
      });
    } else if (prop) {
      info.push({label: translate('Insulin on Board'), value: prop.displayIOB + 'U'});
      info.push({label: translate('Current target'), value: translate('Low') +': ' + sbx.data.profile.getLowBGTarget(sbx.time) + ' ' + translate('High') + ': ' + sbx.data.profile.getHighBGTarget(sbx.time)});
      info.push({label: translate('Sensitivity'), value: '-' + sbx.data.profile.getSensitivity(sbx.time) + ' ' + sbx.settings.units + '/U'});
      if(prop.displayIOB*sbx.data.profile.getSensitivity(sbx.time)<0)
        info.push({label: translate('Expected effect'), value: prop.displayIOB + ' x -' + sbx.data.profile.getSensitivity(sbx.time) + ' = -' + prop.effectDisplay + ' ' + sbx.settings.units});
      else
        info.push({label: translate('Expected effect'), value: prop.displayIOB + ' x -' + sbx.data.profile.getSensitivity(sbx.time) + ' = +' + prop.effectDisplay + ' ' + sbx.settings.units});
      info.push({label: translate('Expected outcome'), value: sbx.lastScaledSGV() + '-' + prop.effectDisplay + ' = ' + prop.outcomeDisplay + ' ' + sbx.settings.units});
      if (prop.bolusEstimateDisplay < 0) {
        info.unshift({label: '---------', value: ''});
        var carbEquivalent = Math.ceil(Math.abs(sbx.data.profile.getCarbRatio() * prop.bolusEstimateDisplay));
        info.unshift({label: translate('Carb Equivalent'), value: prop.bolusEstimateDisplay + 'U * ' + sbx.data.profile.getCarbRatio() + ' = ' + carbEquivalent + 'g'});
        info.unshift({label: translate('Current Carb Ratio'), value: '1U / ' + sbx.data.profile.getCarbRatio() + ' g'});

        if (prop.recentCarbs) {
          info.unshift({
            label: translate('Last Carbs')
            , value: prop.recentCarbs.carbs + 'g @ ' + new Date(prop.recentCarbs.mills).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})});
        }

        if (!prop.belowLowTarget) {
          info.unshift({
            label: '-' + translate('BWP')
            , value: translate('Excess insulin equivalent %1U more than needed to reach low target, not accounting for carbs', { params: [prop.bolusEstimateDisplay] })});
        }

        if (prop.belowLowTarget) {
          if (prop.iob > 0) {
            info.unshift({
              label: '-' + translate('BWP')
              , value: translate('Excess insulin equivalent %1U more than needed to reach low target, MAKE SURE IOB IS COVERED BY CARBS', { params: [prop.bolusEstimateDisplay] })});
          } else {
            info.unshift({
              label: '-' + translate('BWP')
              , value: translate('%1U reduction needed in active insulin to reach low target, too much basal?', { params: [prop.bolusEstimateDisplay] })});
          }
        }
      }
    } else {
      info.push({label: translate('Notice'), value: translate('required info missing')});
    }

    pushTempBasalAdjustments(prop, info, sbx);
  }

  function pushTempBasalAdjustments(prop, info, sbx) {
      if (prop && prop.tempBasalAdjustment) {
      var carbsOrBolusMessage = translate('basal adjustment out of range, give carbs?');
      var sign = '';
      if (prop.tempBasalAdjustment.thirtymin > 100) {
        carbsOrBolusMessage = translate('basal adjustment out of range, give bolus?');
        sign = '+';
      }

      info.push({label: '---------', value: ''});
      if (prop.aimTarget) {
        info.push({label: translate('Projected BG %1 target', { params: [translate(prop.aimTargetString)] }), value: translate('aiming at') + ' ' + prop.aimTarget + ' ' + sbx.settings.units});
      }

      if (prop.bolusEstimate > 0) {
        info.push({label: translate('Bolus %1 units', { params: [prop.bolusEstimateDisplay] }), value: translate('or adjust basal')});
        info.push({label: translate('Check BG using glucometer before correcting!'), value: ''});
        info.push({label: '---------', value: ''});
      } else {
        info.push({label: translate('Basal reduction to account %1 units:', { params: [prop.bolusEstimateDisplay] }), value: ''});
      }

      info.push({label: translate('Current basal'), value: sbx.data.profile.getBasal(sbx.time)});

      if (prop.tempBasalAdjustment.thirtymin >= 0 && prop.tempBasalAdjustment.thirtymin <= 200) {
        info.push({label: translate('30m temp basal'), value: '' + prop.tempBasalAdjustment.thirtymin + '% (' + sign + (prop.tempBasalAdjustment.thirtymin - 100) + '%)'});
      } else {
        info.push({label: translate('30m temp basal'), value: carbsOrBolusMessage});
      }
      if (prop.tempBasalAdjustment.onehour >= 0 && prop.tempBasalAdjustment.onehour <= 200) {
        info.push({label: translate('1h temp basal'), value: '' + prop.tempBasalAdjustment.onehour + '% (' + sign + (prop.tempBasalAdjustment.onehour - 100) + '%)'});
      } else {
        info.push({label: translate('1h temp basal'), value: carbsOrBolusMessage});
      }
    }
  }

  return bwp;

}

module.exports = init;
<commit_msg>fix expected outcome<commit_after>'use strict';

var _ = require('lodash');
var levels = require('../levels');
var times = require('../times');

function init (ctx) {

  var translate = ctx.language.translate;

  var bwp = {
    name: 'bwp'
    , label: 'Bolus Wizard Preview'
    , pluginType: 'pill-minor'
  };

  function checkMissingInfo (sbx) {
    var errors = [];
    if (!sbx.data.profile || !sbx.data.profile.hasData()) {
      errors.push('Missing need a treatment profile');
    } else if (profileFieldsMissing(sbx)) {
      errors.push('Missing sens, target_high, or target_low treatment profile fields');
    }

    if (!sbx.properties.iob) {
      errors.push('Missing IOB property');
    }

    if (!isSGVOk(sbx)) {
      errors.push('Data isn\'t current');
    }

    return errors;
  }

  bwp.setProperties = function setProperties(sbx) {
    sbx.offerProperty('bwp', function setBWP ( ) {
      return bwp.calc(sbx);
    });
  };

  bwp.checkNotifications = function checkNotifications (sbx) {

    var prop = sbx.properties.bwp;
    if (prop === undefined) { return; }

    var settings = prepareSettings(sbx);

    if (bwp.highSnoozedByIOB(prop, settings, sbx)) {
      sbx.notifications.requestSnooze({
        level: levels.URGENT
        , title: translate('Snoozing high alarm since there is enough IOB')
        , message: [sbx.propertyLine('bwp'), sbx.propertyLine('iob')].join('\n')
        , lengthMills: settings.snoozeLength
        , debug: prop
      });
    } else if (prop.scaledSGV > sbx.data.profile.getHighBGTarget(sbx.time) && prop.bolusEstimate > settings.warnBWP) {
      var level = prop.bolusEstimate > settings.urgentBWP ? levels.URGENT : levels.WARN;
      var levelLabel = levels.toDisplay(level);
      var sound = level === levels.URGENT ? 'updown' : 'bike';

      sbx.notifications.requestNotify({
        level: level
        , title: levelLabel + ', ' + translate('Check BG, time to bolus?')
        , message: sbx.buildDefaultMessage()
        , eventName: 'bwp'
        , pushoverSound: sound
        , plugin: bwp
        , debug: prop
      });
    }
  };

  bwp.highSnoozedByIOB = function highSnoozedByIOB(prop, settings, sbx) {
    var ar2EventType = sbx.properties.ar2 && sbx.properties.ar2.eventType;
    var high = ar2EventType === 'high' || prop.scaledSGV >= sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop);

    return high && prop.bolusEstimate < settings.snoozeBWP;
  };

  bwp.updateVisualisation = function updateVisualisation (sbx) {

    var prop = sbx.properties.bwp;

    var info = [];
    pushInfo(prop, info, sbx);

    var value;
    if (prop && prop.bolusEstimateDisplay >= 0) {
      value = prop.bolusEstimateDisplay + 'U';
    } else if (prop && prop.bolusEstimateDisplay < 0) {
      value = '< 0U';
    }

    sbx.pluginBase.updatePillText(bwp, {
      value: value
      , label: translate('BWP')
      , info: info
    });
  };

  bwp.calc = function calc (sbx) {

    var results = {
      effect: 0
      , outcome: 0
      , bolusEstimate: 0.0
    };

    var scaled = sbx.lastScaledSGV();

    results.scaledSGV = scaled;

    var errors = checkMissingInfo(sbx);

    if (errors && errors.length > 0) {
      results.errors = errors;
      return results;
    }

    var profile = sbx.data.profile;
    var iob = results.iob = sbx.properties.iob.iob || 0;

    results.effect = iob * profile.getSensitivity(sbx.time);
    results.outcome = scaled - results.effect;
    var delta = 0;

    var recentCarbs = _.findLast(sbx.data.treatments, function eachTreatment (treatment) {
      return treatment.mills <= sbx.time &&
        sbx.time - treatment.mills < times.mins(60).msecs &&
        treatment.carbs > 0;
    });

    results.recentCarbs = recentCarbs;

    var target_high = profile.getHighBGTarget(sbx.time);
    var sens = profile.getSensitivity(sbx.time);

    if (results.outcome > target_high) {
      delta = results.outcome - target_high;
      results.bolusEstimate = delta / sens;
      results.aimTarget = target_high;
      results.aimTargetString = 'above high';
    }

    var target_low = profile.getLowBGTarget(sbx.time);

    results.belowLowTarget = false;
    if (scaled < target_low) {
      results.belowLowTarget = true;
    }

    if (results.outcome < target_low) {
      delta = Math.abs(results.outcome - target_low);
      results.bolusEstimate = delta / sens * -1;
      results.aimTarget = target_low;
      results.aimTargetString = 'below low';
    }

    if (results.bolusEstimate !== 0 && sbx.data.profile.getBasal(sbx.time)) {
      // Basal profile exists, calculate % change
      var basal = sbx.data.profile.getBasal(sbx.time);

      var thirtyMinAdjustment = Math.round((basal/2 + results.bolusEstimate) / (basal / 2) * 100);
      var oneHourAdjustment = Math.round((basal + results.bolusEstimate) / basal * 100);

      results.tempBasalAdjustment = {
        'thirtymin': thirtyMinAdjustment
        ,'onehour': oneHourAdjustment};
    }

    results.bolusEstimateDisplay = sbx.roundInsulinForDisplayFormat(results.bolusEstimate);
    results.outcomeDisplay = sbx.roundBGToDisplayFormat(results.outcome);
    results.displayIOB = sbx.roundInsulinForDisplayFormat(results.iob);
    results.effectDisplay = sbx.roundBGToDisplayFormat(results.effect);
    results.displayLine = translate('BWP') + ': ' + results.bolusEstimateDisplay + 'U';

    return results;
  };

  function prepareSettings (sbx) {
    return {
      snoozeBWP: Number(sbx.extendedSettings.snooze) || 0.10
    , warnBWP: Number(sbx.extendedSettings.warn) || 0.50
    , urgentBWP: Number(sbx.extendedSettings.urgent) || 1.00
    , snoozeLength: (sbx.extendedSettings.snoozeMins && Number(sbx.extendedSettings.snoozeMins) * 60 * 1000) || times.mins(10).msecs
    };
  }

  function isSGVOk (sbx) {
    var lastSGVEntry = sbx.lastSGVEntry();
    return lastSGVEntry && lastSGVEntry.mgdl >= 39 && sbx.isCurrent(lastSGVEntry);
  }

  function profileFieldsMissing (sbx) {
    return !sbx.data.profile.getSensitivity(sbx.time)
      || !sbx.data.profile.getHighBGTarget(sbx.time)
      || !sbx.data.profile.getLowBGTarget(sbx.time);
  }

  function pushInfo(prop, info, sbx) {
    if (prop && prop.errors) {
      info.push({label: translate('Notice'), value: translate('required info missing')});
      _.each(prop.errors, function pushError (error) {
        info.push({label: '  • ', value: error});
      });
    } else if (prop) {
      info.push({label: translate('Insulin on Board'), value: prop.displayIOB + 'U'});
      info.push({label: translate('Current target'), value: translate('Low') +': ' + sbx.data.profile.getLowBGTarget(sbx.time) + ' ' + translate('High') + ': ' + sbx.data.profile.getHighBGTarget(sbx.time)});
      info.push({label: translate('Sensitivity'), value: '-' + sbx.data.profile.getSensitivity(sbx.time) + ' ' + sbx.settings.units + '/U'});
      if(prop.displayIOB*sbx.data.profile.getSensitivity(sbx.time)<0)
        info.push({label: translate('Expected effect'), value: prop.displayIOB + ' x -' + sbx.data.profile.getSensitivity(sbx.time) + ' = -' + prop.effectDisplay + ' ' + sbx.settings.units});
      else
        info.push({label: translate('Expected effect'), value: prop.displayIOB + ' x -' + sbx.data.profile.getSensitivity(sbx.time) + ' = ' + prop.effectDisplay + ' ' + sbx.settings.units});
      info.push({label: translate('Expected outcome'), value: sbx.lastScaledSGV() + '-' + prop.effectDisplay + ' = ' + prop.outcomeDisplay + ' ' + sbx.settings.units});
      if (prop.bolusEstimateDisplay < 0) {
        info.unshift({label: '---------', value: ''});
        var carbEquivalent = Math.ceil(Math.abs(sbx.data.profile.getCarbRatio() * prop.bolusEstimateDisplay));
        info.unshift({label: translate('Carb Equivalent'), value: prop.bolusEstimateDisplay + 'U * ' + sbx.data.profile.getCarbRatio() + ' = ' + carbEquivalent + 'g'});
        info.unshift({label: translate('Current Carb Ratio'), value: '1U / ' + sbx.data.profile.getCarbRatio() + ' g'});

        if (prop.recentCarbs) {
          info.unshift({
            label: translate('Last Carbs')
            , value: prop.recentCarbs.carbs + 'g @ ' + new Date(prop.recentCarbs.mills).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})});
        }

        if (!prop.belowLowTarget) {
          info.unshift({
            label: '-' + translate('BWP')
            , value: translate('Excess insulin equivalent %1U more than needed to reach low target, not accounting for carbs', { params: [prop.bolusEstimateDisplay] })});
        }

        if (prop.belowLowTarget) {
          if (prop.iob > 0) {
            info.unshift({
              label: '-' + translate('BWP')
              , value: translate('Excess insulin equivalent %1U more than needed to reach low target, MAKE SURE IOB IS COVERED BY CARBS', { params: [prop.bolusEstimateDisplay] })});
          } else {
            info.unshift({
              label: '-' + translate('BWP')
              , value: translate('%1U reduction needed in active insulin to reach low target, too much basal?', { params: [prop.bolusEstimateDisplay] })});
          }
        }
      }
    } else {
      info.push({label: translate('Notice'), value: translate('required info missing')});
    }

    pushTempBasalAdjustments(prop, info, sbx);
  }

  function pushTempBasalAdjustments(prop, info, sbx) {
      if (prop && prop.tempBasalAdjustment) {
      var carbsOrBolusMessage = translate('basal adjustment out of range, give carbs?');
      var sign = '';
      if (prop.tempBasalAdjustment.thirtymin > 100) {
        carbsOrBolusMessage = translate('basal adjustment out of range, give bolus?');
        sign = '+';
      }

      info.push({label: '---------', value: ''});
      if (prop.aimTarget) {
        info.push({label: translate('Projected BG %1 target', { params: [translate(prop.aimTargetString)] }), value: translate('aiming at') + ' ' + prop.aimTarget + ' ' + sbx.settings.units});
      }

      if (prop.bolusEstimate > 0) {
        info.push({label: translate('Bolus %1 units', { params: [prop.bolusEstimateDisplay] }), value: translate('or adjust basal')});
        info.push({label: translate('Check BG using glucometer before correcting!'), value: ''});
        info.push({label: '---------', value: ''});
      } else {
        info.push({label: translate('Basal reduction to account %1 units:', { params: [prop.bolusEstimateDisplay] }), value: ''});
      }

      info.push({label: translate('Current basal'), value: sbx.data.profile.getBasal(sbx.time)});

      if (prop.tempBasalAdjustment.thirtymin >= 0 && prop.tempBasalAdjustment.thirtymin <= 200) {
        info.push({label: translate('30m temp basal'), value: '' + prop.tempBasalAdjustment.thirtymin + '% (' + sign + (prop.tempBasalAdjustment.thirtymin - 100) + '%)'});
      } else {
        info.push({label: translate('30m temp basal'), value: carbsOrBolusMessage});
      }
      if (prop.tempBasalAdjustment.onehour >= 0 && prop.tempBasalAdjustment.onehour <= 200) {
        info.push({label: translate('1h temp basal'), value: '' + prop.tempBasalAdjustment.onehour + '% (' + sign + (prop.tempBasalAdjustment.onehour - 100) + '%)'});
      } else {
        info.push({label: translate('1h temp basal'), value: carbsOrBolusMessage});
      }
    }
  }

  return bwp;

}

module.exports = init;
<|endoftext|>


<commit_before>import logger from 'morgan';
import bodyParser from 'body-parser';
import path from 'path';
import indexRouter from './routes/index';
import usersRouter from './routes/users';
import authRouter from './routes/authorization';
import errorHandle from './errorHandle';
import { passport, serializeLogin } from './auth/local';

export default function middleware(app, express) {
  // use body-parser to format request and attach it to req objects.
  app.use(bodyParser.urlencoded({ extended: false }));
  app.use(bodyParser.json());

  // define where express should look for static assests
  app.use(express.static(path.join(__dirname, '../public/dist/src')));

  // use passport for authentication
  app.use(passport.initialize());

  // pass the router files for each route
  app.use('/users', usersRouter);
  app.use('/auth', authRouter);
  app.use('/', indexRouter);

  // pass the logger
  app.use(logger('dev'));

  serializeLogin(passport);

  // pass the
  app.use(errorHandle.catchForward);
  app.use(errorHandle.handleError);
}
<commit_msg>Fix static route in middleware.js<commit_after>import logger from 'morgan';
import bodyParser from 'body-parser';
import path from 'path';
import indexRouter from './routes/index';
import usersRouter from './routes/users';
import authRouter from './routes/authorization';
import errorHandle from './errorHandle';
import { passport, serializeLogin } from './auth/local';

export default function middleware(app, express) {
  // use body-parser to format request and attach it to req objects.
  app.use(bodyParser.urlencoded({ extended: false }));
  app.use(bodyParser.json());

  // define where express should look for static assests
  app.use(express.static(path.join(__dirname, '../../public/dist/src')));

  // use passport for authentication
  app.use(passport.initialize());

  // pass the router files for each route
  app.use('/users', usersRouter);
  app.use('/auth', authRouter);
  app.use('/', indexRouter);

  // pass the logger
  app.use(logger('dev'));

  serializeLogin(passport);

  // pass the
  app.use(errorHandle.catchForward);
  app.use(errorHandle.handleError);
}
<|endoftext|>


<commit_before>// TODO: Observable array?
// TODO: Binding on a widget
// TODO: Binding on nested widgets
// TODO: Binding on nested namespaces
define([
	"dojo/_base/declare",
	"dojo/dom-attr",
	"./_OwnMixin",
	"../util/array",
	"knockout/knockout-2.3.0"
], function (declare, domAttr, _OwnMixin, arrayUtil, ko) {
	return declare(_OwnMixin, {
		buildRendering: function () {
			var binder = /(text|value|attr)\:\s*/,
				model = {},
				bindee = this;

			this.inherited(arguments);

			function bind(/*Node*/ node) {
				// summary:
				//		Binds a node to the model.
				// node: Node
				//		Node to bind.
				var binding = domAttr.get(node, "data-bind"),
					key;

				if (binding) {
					key = binding.replace(binder, "");

					if (!model.hasOwnProperty(key)) {
						model[key] = ko.observable(bindee.get(key));

						// Two-way binding:
						// When the model changes, the widget is updated.
						// When the widget changes, the model is updated.
						bindee.own(
							model[key].subscribe(function (newValue) {
								bindee._set(key, newValue);
							}),
							bindee.watch(key, function (property, oldValue, newValue) {
								if (model[property]) {
									model[property](newValue);
								}
							})
						);
					}
				}
			}

			function applyBindings(/*Node*/ node) {
				// summary:
				//		Binds node and all child nodes.
				// node: Node
				//		Root node.
				var children = node.childNodes ? arrayUtil.create(node.childNodes) : null;

				bind(node);

				if (children) {
					children.forEach(applyBindings);
				}
			}

			applyBindings(this.domNode);
			ko.applyBindings(model, this.domNode);
		}
	});
});
<commit_msg>Use set() over _set() so that custom setters are not bypassed.<commit_after>// TODO: Observable array?
// TODO: Binding on a widget
// TODO: Binding on nested widgets
// TODO: Binding on nested namespaces
define([
	"dojo/_base/declare",
	"dojo/dom-attr",
	"./_OwnMixin",
	"../util/array",
	"knockout/knockout-2.3.0"
], function (declare, domAttr, _OwnMixin, arrayUtil, ko) {
	return declare(_OwnMixin, {
		buildRendering: function () {
			var binder = /(text|value|attr)\:\s*/,
				model = {},
				bindee = this;

			this.inherited(arguments);

			function bind(/*Node*/ node) {
				// summary:
				//		Binds a node to the model.
				// node: Node
				//		Node to bind.
				var binding = domAttr.get(node, "data-bind"),
					key;

				if (binding) {
					key = binding.replace(binder, "");

					if (!model.hasOwnProperty(key)) {
						model[key] = ko.observable(bindee.get(key));

						// Two-way binding:
						// When the model changes, the widget is updated.
						// When the widget changes, the model is updated.
						bindee.own(
							model[key].subscribe(function (newValue) {
								bindee.set(key, newValue);
							}),
							bindee.watch(key, function (property, oldValue, newValue) {
								if (model[property]) {
									model[property](newValue);
								}
							})
						);
					}
				}
			}

			function applyBindings(/*Node*/ node) {
				// summary:
				//		Binds node and all child nodes.
				// node: Node
				//		Root node.
				var children = node.childNodes ? arrayUtil.create(node.childNodes) : null;

				bind(node);

				if (children) {
					children.forEach(applyBindings);
				}
			}

			applyBindings(this.domNode);
			ko.applyBindings(model, this.domNode);
		}
	});
});
<|endoftext|>


<commit_before>;

function coresChooser_OnReady() {

    $(".single-core-container").on("click", function (eventObject) {
        var target = $(eventObject.target);
        var button = target.is(".single-core-container") ? target : target.parents(".single-core-container");
        var coresNumber = button.attr("data-id");
        console.log("CORES CHOOSER: " + coresNumber + " core(s)");
        bind_OnlineCores(coresNumber);

        var postUri = "api/control/set-cores/" + coresNumber;
        var req = jQuery.ajax({
            url: postUri,
            method: "POST",
            dataType: "json"
        });

        forceRefreshBySomeClick(req);

        req.fail(function (jqXHR, textStatus) {
            // nothing to do
        });

    });

    if (h3context && h3context.DeviceInfo && h3context.DeviceInfo.OnlineCoresNumber) {
        // console.log("STARTUP: OnlineCoresNumber is " + h3context.DeviceInfo.OnlineCoresNumber);
        bind_OnlineCores(h3context.DeviceInfo.OnlineCoresNumber);
    }
}

function bind_OnlineCores(coresCount) {
    for (var i = 1; i <= 4; i++) {
        var container = $("#core-" + i);
        var suffix = i <= coresCount ? "on" : "off";
        var prefix = "single-core-";
        container.removeClass(prefix + "on");
        container.removeClass(prefix + "off");
        container.addClass(prefix + suffix);
    }
}

<commit_msg>single time warning in case the kernel does not allow to manage online cores<commit_after>;

var _CanNotManageOnlineCores_WarningShowed = false;
function coresChooser_OnReady() {

    $(".single-core-container").on("click", function (eventObject) {
        var target = $(eventObject.target);
        var button = target.is(".single-core-container") ? target : target.parents(".single-core-container");
        var coresNumber = button.attr("data-id");
        console.log("CORES CHOOSER: " + coresNumber + " core(s)");
        bind_OnlineCores(coresNumber);

        if (!h3context.DeviceInfo.CanManageOnlineCores) {
            if (!_CanNotManageOnlineCores_WarningShowed) {
                _CanNotManageOnlineCores_WarningShowed = true;
                alert("The kernel of the '" + h3context.DeviceInfo.Host + "' does not allow to manage online cores");
            }
        }

        var postUri = "api/control/set-cores/" + coresNumber;
        var req = jQuery.ajax({
            url: postUri,
            method: "POST",
            dataType: "json"
        });

        forceRefreshBySomeClick(req);

        req.fail(function (jqXHR, textStatus) {
            // nothing to do
        });

    });

    if (h3context && h3context.DeviceInfo && h3context.DeviceInfo.OnlineCoresNumber) {
        // console.log("STARTUP: OnlineCoresNumber is " + h3context.DeviceInfo.OnlineCoresNumber);
        bind_OnlineCores(h3context.DeviceInfo.OnlineCoresNumber);
    }
}

function bind_OnlineCores(coresCount) {
    for (var i = 1; i <= 4; i++) {
        var container = $("#core-" + i);
        var suffix = i <= coresCount ? "on" : "off";
        var prefix = "single-core-";
        container.removeClass(prefix + "on");
        container.removeClass(prefix + "off");
        container.addClass(prefix + suffix);
    }
}

<|endoftext|>


<commit_before>var projectPath = process.cwd();
var we = require('../lib');
var pluginManager = require('../lib/pluginManager');
var deleteDir = require('rimraf');
var path = require('path');

before(function(callback) {
  we.bootstrap({
    port: 9800,
    hostname: 'http://localhost:9800',
    i18n: {
      directory: path.join(__dirname, 'locales'),
      updateFiles: true
    },
    passport: {
      accessTokenTime: 300000000,
      cookieDomain: null,
      cookieName: 'weoauth',
      cookieSecure: false
    }
  } , function(err, we) {
    we.startServer(function(err) {
      if (err) return console.error(err);
      callback();
    })
  })
})

// after all tests
after(function (callback) {

  we.db.defaultConnection.close();

  // delete temp dir
  deleteDir( projectPath + '/files' , function(err) {
    if (err) console.error('Error on delete temp dir: ', err);
    callback();
  });
})<commit_msg>update delete temp folder after tests run<commit_after>var projectPath = process.cwd();
var we = require('../lib');
var deleteDir = require('rimraf');
var path = require('path');
var async = require('async');

before(function(callback) {
  we.bootstrap({
    port: 9800,
    hostname: 'http://localhost:9800',
    i18n: {
      directory: path.join(__dirname, 'locales'),
      updateFiles: true
    },
    passport: {
      accessTokenTime: 300000000,
      cookieDomain: null,
      cookieName: 'weoauth',
      cookieSecure: false
    }
  } , function(err, we) {
    we.startServer(function(err) {
      if (err) return console.error(err);
      callback();
    })
  })
})

// after all tests
after(function (callback) {
  we.db.defaultConnection.close();

  var tempFolders = [
    projectPath + '/files/tmp',
    projectPath + '/files/uploads',
    projectPath + '/files/config',
    projectPath + '/files/sqlite',

    projectPath + '/files/public/min',

    projectPath + '/files/public/tpls.hbs.js',
    projectPath + '/files/public/admin.tpls.hbs.js',
    projectPath + '/files/public/project.css',
    projectPath + '/files/public/project.js'
  ];

  async.each(tempFolders, function(folder, next){
    deleteDir( folder, next);
  }, function(err) {
    if (err) throw new Error(err);
    callback();
  })

})<|endoftext|>


<commit_before>window.RelatedUsersView = Backbone.View.extend({

  el: $("#right-column .related-users"),

  initialize: function() {
  },

  setChannel: function(channel) {
    this.channel = channel;

    return this;
  },

  render: function() {
    var self = this;

    if ( this.channel ) {
      $.ajax({
        url: this.channel.url() + '/related_users',
        method: "GET",
        success: function( data ) {
          self.el.html(data);
        }
      });
    }
  }
});
<commit_msg>Moved related to left<commit_after>window.RelatedUsersView = Backbone.View.extend({

  el: $("#left-column .related-users"),

  initialize: function() {
  },

  setChannel: function(channel) {
    this.channel = channel;

    return this;
  },

  render: function() {
    var self = this;

    if ( this.channel ) {
      $.ajax({
        url: this.channel.url() + '/related_users',
        method: "GET",
        success: function( data ) {
          self.el.html(data);
        }
      });
    }
  }
});
<|endoftext|>