<commit_before>define(['jquery', 'lodash'], function ($, _) {
    'use strict';

    return {
        killParticle: function (particle) {
            $(particle).removeClass('elementalParticle');
        },
        setExistence: function(newVal, particle) {
            particle.existence = newVal;
            particle.isAlive = false;
            this.killParticle(particle);
        },
        deadCowntDown: function (particle) {
            // web worker
            var worker = new Worker('core/workers.js'),
                that = this;
            worker.addEventListener('message', function(e) {
                if (e.data === 0) {
                    that.setExistence(e.data, particle);
                }
            });
            worker.postMessage({ 'ex': particle.existence });
        },
        upLevel: function (self) {
            self.size = self.size * 2;
            self.strength = self.strength * 2;
            self.existence = self.existence + 30;
            self.speed = self.speed * 2;
        },
        detectDomElement: function (node, name, options) {
            _.map(node.childNodes, function(n) {
                if (n.tagName === 'SELECT') {
                    var nodeName = n.getAttribute('name');
                    if (nodeName === name) {
                        _.each(options, function(op, i) {
                            $(n).append('<option class="selectTableSize' + i + '">' + op + '</option>');
                        });
                    }
                }
            });
        },
        randomNumber: function (first, last) {
            return _.random(first, last);
        },
        detectSelect: function (node, name) {
            var newObj = null;
            _.each(node.childNodes, function(n) {
                if (n.tagName === 'SELECT') {
                    var nodeName = n.getAttribute('name');
                    if (nodeName === name) {
                        newObj = n;
                    }
                }
            });
            return newObj;
        },
        returnClasses: function (data) {
            var result = [];
            _.map(data, function(n) {
                if (n.tagName === 'TR' || n.tagName === 'TD') {
                    result.push(n.className);
                }
            });
            return result;
        },
        particlesFight: function(particle1, particle2) {
            var particle1Strength = particle1.strength,
                particle2Strength = particle2.strength,
                random1 = this.randomNumber(0,10),
                random2 = this.randomNumber(0,10);

                if (particle1Strength === particle2Strength) {
                    if (random1 > random2) {
                        this.killParticle(particle2);
                        this.removeOldParticle(particle2);
                        this.upLevel(particle1);
                        $(particle1).removeClass('elementParticle');
                        $(particle1).addClass('elementParticle1');
                    } else {
                        this.killParticle(particle1);
                        this.removeOldParticle(particle2);
                        this.upLevel(particle2);
                        $(particle2).removeClass('elementParticle');
                        $(particle2).addClass('elementParticle1');
                    }
                } else if (particle1Strength > particle2Strength) {
                    this.killParticle(particle2);
                    this.removeOldParticle(particle2);
                    this.upLevel(particle1);
                    $(particle1).removeClass('elementParticle1');
                    $(particle1).addClass('elementParticle2');
                } else {
                    this.killParticle(particle1);
                    this.removeOldParticle(particle1);
                    this.upLevel(particle2);
                    $(particle2).removeClass('elementParticle1');
                    $(particle2).addClass('elementParticle2');
                }
        },
        particlesCreated: false,
        movements: ['top', 'bottom', 'right', 'left'],
        sizeOptions: ['100 x 300', '300 x 600', '600 x 800', '800 x 1200', '1200 x 1400', '1400 x 1600'],
        particleOptions: ['Random', '10', '20', '30', '40', '50', '60', '70', '80', '90', '100', '200', '300', '400', '500', '600', '700', '800', '900', '1000'],
        removeOldParticle: function(particle) {
            particle.size = 0;
            particle.isAlive = false;
            particle.strength = 0;
            particle.existence = 0;
            particle.spin = false;
            particle.speed = 0;
            particle.countDown = null;
            particle.moves = null;
        },
        passProperties: function (oldParticle, newParticle) {
            newParticle.size = oldParticle.size;
            newParticle.isAlive = oldParticle.isAlive;
            newParticle.strength = oldParticle.strength;
            newParticle.existence = oldParticle.existence;
            newParticle.spin = oldParticle.spin;
            newParticle.speed = oldParticle.speed;
            newParticle.countDown = oldParticle.countDown;
            newParticle.moves = oldParticle.moves;
        },
        setClass: function(particle) {
            if ($(particle).hasClass('elementalParticle')) {
                $(particle).removeClass('elementalParticle');
                $(particle).addClass('elementalParticle1');
            } else if ($(particle).hasClass('elementalParticle1')) {
                $(particle).removeClass('elementalParticle1');
                $(particle).addClass('elementalParticle2');
            } else {
                $(particle).addClass('elementalParticle');
            }
        },
        moveTop: function(particle) {
            if (!_.isUndefined(particle.className)) {
                var self = this,
                    particleName = particle.getAttribute('name'),
                    particleParent = particle.parentNode,
                    particleParentData = particleParent.getAttribute('data'),
                    upTrNum = (_.parseInt(particleParentData) - 10) + '',
                    upTr = document.getElementsByClassName('tr' + upTrNum);

                    if (!_.isUndefined(upTr) && upTr.length > 0) {
                        _.map(upTr[0].childNodes, function(n) {
                            var nName = n.getAttribute('name');
                            if (n.tagName === 'TD' && nName === particleName) {
                                if (n.className === nName + ' elementalParticle'
                                || n.className === nName + ' elementalParticle1'
                                || n.className === nName + ' elementalParticle2') {
                                    self.particlesFight(particle, n);
                                } else {
                                    self.setClass(n);
                                    self.passProperties(particle, n);
                                    if(!_.isUndefined(n) && _.isFunction(n.moves)) {
                                        n.moves();
                                    }
                                }
                            }
                        });
                    }
            }
        },
        moveBottom: function(particle) {
            if (!_.isUndefined(particle.className)) {
                var self = this,
                    particleName = particle.getAttribute('name'),
                    particleParent = particle.parentNode,
                    particleParentData = particleParent.getAttribute('data'),
                    upTrNum = (_.parseInt(particleParentData) + 10) + '',
                    upTr = document.getElementsByClassName('tr' + upTrNum);

                    if (!_.isUndefined(upTr) && upTr.length > 0) {
                        _.map(upTr[0].childNodes, function(n) {
                            var nName = n.getAttribute('name');
                            if (n.tagName === 'TD' && nName === particleName) {
                                if (n.className === nName + ' elementalParticle'
                                || n.className === nName + ' elementalParticle1'
                                || n.className === nName + ' elementalParticle2') {
                                    self.particlesFight(particle, n);
                                } else {
                                    self.setClass(n);
                                    self.passProperties(particle, n);
                                    if(!_.isUndefined(n) && _.isFunction(n.moves)) {
                                        n.moves();
                                    }
                                }
                            }
                        });
                    }
            }
        },
        moveRight: function(particle) {
            if (!_.isUndefined(particle.className)) {
                var self = this,
                    particleParent = particle.parentNode,
                    particleName = particle.getAttribute('data'),
                    num = (_.parseInt(particleName) + 10) + '';

                if (!_.isUndefined(particleParent)) {
                    _.map(particleParent.childNodes, function(n) {
                        var newNum = n.getAttribute('data'),
                            nName = n.getAttribute('name');

                        if (newNum === num) {
                            if (n.className === nName + ' elementalParticle'
                            || n.className === nName + ' elementalParticle1'
                            || n.className === nName + ' elementalParticle2') {
                                self.particlesFight(particle, n);
                            } else {
                                self.setClass(n);
                                self.passProperties(particle, n);
                                if(!_.isUndefined(n) && _.isFunction(n.moves)) {
                                    n.moves();
                                }
                            }
                        }
                    });
                }
            }
        },
        moveLeft: function(particle) {
            if (!_.isUndefined(particle.className)) {
                var self = this,
                    particleParent = particle.parentNode,
                    particleName = particle.getAttribute('data'),
                    num = (_.parseInt(particleName) - 10) + '';

                if (!_.isUndefined(particleParent)) {
                    _.map(particleParent.childNodes, function(n) {
                        var newNum = n.getAttribute('data'),
                            nName = n.getAttribute('name');

                        if (newNum === num) {
                            if (n.className === nName + ' elementalParticle'
                            || n.className === nName + ' elementalParticle1'
                            || n.className === nName + ' elementalParticle2') {
                                self.particlesFight(particle, n);
                            } else {
                                self.setClass(n);
                                self.passProperties(particle, n);
                                if(!_.isUndefined(n) && _.isFunction(n.moves)) {
                                    n.moves();
                                }
                            }
                        }
                    });
                }
            }
        }
    };
});
<commit_msg>Improve api.js<commit_after>define(['jquery', 'lodash'], function ($, _) {
    'use strict';

    return {
        killParticle: function (particle) {
            $(particle).removeClass('elementalParticle');
        },
        setExistence: function(newVal, particle) {
            particle.existence = newVal;
            particle.isAlive = false;
            this.killParticle(particle);
        },
        deadCowntDown: function (particle) {
            // web worker
            var worker = new Worker('core/workers.js'),
                that = this;
            worker.addEventListener('message', function(e) {
                if (e.data === 0) {
                    that.setExistence(e.data, particle);
                }
            });
            worker.postMessage({ 'ex': particle.existence });
        },
        upLevel: function (self) {
            self.size = self.size * 2;
            self.strength = self.strength * 2;
            self.existence = self.existence + 30;
            self.speed = self.speed * 2;
        },
        detectDomElement: function (node, name, options) {
            _.map(node.childNodes, function(n) {
                if (n.tagName === 'SELECT') {
                    var nodeName = n.getAttribute('name');
                    if (nodeName === name) {
                        _.each(options, function(op, i) {
                            $(n).append('<option class="selectTableSize' + i + '">' + op + '</option>');
                        });
                    }
                }
            });
        },
        randomNumber: function (first, last) {
            return _.random(first, last);
        },
        detectSelect: function (node, name) {
            var newObj = null;
            _.each(node.childNodes, function(n) {
                if (n.tagName === 'SELECT') {
                    var nodeName = n.getAttribute('name');
                    if (nodeName === name) {
                        newObj = n;
                    }
                }
            });
            return newObj;
        },
        returnClasses: function (data) {
            var result = [];
            _.map(data, function(n) {
                if (n.tagName === 'TR' || n.tagName === 'TD') {
                    result.push(n.className);
                }
            });
            return result;
        },
        particlesFight: function(particle1, particle2) {
            var particle1Strength = particle1.strength,
                particle2Strength = particle2.strength,
                random1 = this.randomNumber(0,10),
                random2 = this.randomNumber(0,10);

                if (particle1Strength === particle2Strength) {
                    if (random1 > random2) {
                        this.killParticle(particle2);
                        this.removeOldParticle(particle2);
                        this.upLevel(particle1);
                        $(particle1).removeClass('elementParticle');
                        $(particle1).addClass('elementParticle1');
                    } else {
                        this.killParticle(particle1);
                        this.removeOldParticle(particle2);
                        this.upLevel(particle2);
                        $(particle2).removeClass('elementParticle');
                        $(particle2).addClass('elementParticle1');
                    }
                } else if (particle1Strength > particle2Strength) {
                    this.killParticle(particle2);
                    this.removeOldParticle(particle2);
                    this.upLevel(particle1);
                    $(particle1).removeClass('elementParticle1');
                    $(particle1).addClass('elementParticle2');
                } else {
                    this.killParticle(particle1);
                    this.removeOldParticle(particle1);
                    this.upLevel(particle2);
                    $(particle2).removeClass('elementParticle1');
                    $(particle2).addClass('elementParticle2');
                }
        },
        particlesCreated: false,
        movements: ['top', 'bottom', 'right', 'left'],
        sizeOptions: ['10 x 50', '50 x 100', '100 x 300', '300 x 600', '600 x 800', '800 x 1200', '1200 x 1400', '1400 x 1600'],
        particleOptions: ['Random', '5', '10', '20', '30', '40', '50', '60', '70', '80', '90', '100', '200', '300', '400', '500', '600', '700', '800', '900', '1000'],
        removeOldParticle: function(particle) {
            particle.size = 0;
            particle.isAlive = false;
            particle.strength = 0;
            particle.existence = 0;
            particle.spin = false;
            particle.speed = 0;
            particle.countDown = null;
            particle.moves = null;
        },
        passProperties: function (oldParticle, newParticle) {
            newParticle.size = oldParticle.size;
            newParticle.isAlive = oldParticle.isAlive;
            newParticle.strength = oldParticle.strength;
            newParticle.existence = oldParticle.existence;
            newParticle.spin = oldParticle.spin;
            newParticle.speed = oldParticle.speed;
            newParticle.countDown = oldParticle.countDown;
            newParticle.moves = oldParticle.moves;
        },
        setClass: function(particle) {
            if ($(particle).hasClass('elementalParticle')) {
                $(particle).removeClass('elementalParticle');
                $(particle).addClass('elementalParticle1');
            } else if ($(particle).hasClass('elementalParticle1')) {
                $(particle).removeClass('elementalParticle1');
                $(particle).addClass('elementalParticle2');
            } else {
                $(particle).addClass('elementalParticle');
            }
        },
        moveTop: function(particle) {
            if (!_.isUndefined(particle.className)) {
                var self = this,
                    particleName = particle.getAttribute('name'),
                    particleParent = particle.parentNode,
                    particleParentData = particleParent.getAttribute('data'),
                    upTrNum = (_.parseInt(particleParentData) - 10) + '',
                    upTr = document.getElementsByClassName('tr' + upTrNum);

                    if (!_.isUndefined(upTr) && upTr.length > 0) {
                        _.map(upTr[0].childNodes, function(n) {
                            var nName = n.getAttribute('name');
                            if (n.tagName === 'TD' && nName === particleName) {
                                if (n.className === nName + ' elementalParticle'
                                || n.className === nName + ' elementalParticle1'
                                || n.className === nName + ' elementalParticle2') {
                                    self.particlesFight(particle, n);
                                } else {
                                    self.setClass(n);
                                    self.passProperties(particle, n);
                                    if(!_.isUndefined(n) && _.isFunction(n.moves)) {
                                        n.moves();
                                    }
                                }
                            }
                        });
                    }
            }
        },
        moveBottom: function(particle) {
            if (!_.isUndefined(particle.className)) {
                var self = this,
                    particleName = particle.getAttribute('name'),
                    particleParent = particle.parentNode,
                    particleParentData = particleParent.getAttribute('data'),
                    upTrNum = (_.parseInt(particleParentData) + 10) + '',
                    upTr = document.getElementsByClassName('tr' + upTrNum);

                    if (!_.isUndefined(upTr) && upTr.length > 0) {
                        _.map(upTr[0].childNodes, function(n) {
                            var nName = n.getAttribute('name');
                            if (n.tagName === 'TD' && nName === particleName) {
                                if (n.className === nName + ' elementalParticle'
                                || n.className === nName + ' elementalParticle1'
                                || n.className === nName + ' elementalParticle2') {
                                    self.particlesFight(particle, n);
                                } else {
                                    self.setClass(n);
                                    self.passProperties(particle, n);
                                    if(!_.isUndefined(n) && _.isFunction(n.moves)) {
                                        n.moves();
                                    }
                                }
                            }
                        });
                    }
            }
        },
        moveRight: function(particle) {
            if (!_.isUndefined(particle.className)) {
                var self = this,
                    particleParent = particle.parentNode,
                    particleName = particle.getAttribute('data'),
                    num = (_.parseInt(particleName) + 10) + '';

                if (!_.isUndefined(particleParent)) {
                    _.map(particleParent.childNodes, function(n) {
                        var newNum = n.getAttribute('data'),
                            nName = n.getAttribute('name');

                        if (newNum === num) {
                            if (n.className === nName + ' elementalParticle'
                            || n.className === nName + ' elementalParticle1'
                            || n.className === nName + ' elementalParticle2') {
                                self.particlesFight(particle, n);
                            } else {
                                self.setClass(n);
                                self.passProperties(particle, n);
                                if(!_.isUndefined(n) && _.isFunction(n.moves)) {
                                    n.moves();
                                }
                            }
                        }
                    });
                }
            }
        },
        moveLeft: function(particle) {
            if (!_.isUndefined(particle.className)) {
                var self = this,
                    particleParent = particle.parentNode,
                    particleName = particle.getAttribute('data'),
                    num = (_.parseInt(particleName) - 10) + '';

                if (!_.isUndefined(particleParent)) {
                    _.map(particleParent.childNodes, function(n) {
                        var newNum = n.getAttribute('data'),
                            nName = n.getAttribute('name');

                        if (newNum === num) {
                            if (n.className === nName + ' elementalParticle'
                            || n.className === nName + ' elementalParticle1'
                            || n.className === nName + ' elementalParticle2') {
                                self.particlesFight(particle, n);
                            } else {
                                self.setClass(n);
                                self.passProperties(particle, n);
                                if(!_.isUndefined(n) && _.isFunction(n.moves)) {
                                    n.moves();
                                }
                            }
                        }
                    });
                }
            }
        }
    };
});
<|endoftext|>


<commit_before>angular.module('ui.tree')
  .directive('uiTreeActivable', ['$parse', function($parse) {
    return {
      restrict: 'A',
      compile: function(elem, attrs) {
        return function postLink(scope, elem, attrs) {
          var activeNodeGetter = $parse(attrs.activeNode);
          var activeNodeSetter = activeNodeGetter.assign;
          var activeNode = activeNodeGetter(scope);

          // Events:
          var onBeforeActive = $parse(attrs.onBeforeActive)(scope) || angular.noop;
          var onActive = $parse(attrs.onActive)(scope) || angular.noop;

          scope.$isActive = function(node) {
            return activeNode === node;
          };

          scope.$activate = function(nodeScope) {
            if (onBeforeActive(nodeScope) !== false) {
              activeNode = nodeScope.$modelValue;
              activeNodeSetter && activeNodeSetter(scope, activeNode);
              onActive(nodeScope);
            }
          };
        }
      }
    }
  }]);<commit_msg>Update events invoke style<commit_after>angular.module('ui.tree')
  .directive('uiTreeActivable', ['$parse', function($parse) {
    return {
      restrict: 'A',
      compile: function(elem, attrs) {
        return function postLink(scope, elem, attrs) {
          var activeNodeGetter = $parse(attrs.activeNode);
          var activeNodeSetter = activeNodeGetter.assign;
          var activeNode = activeNodeGetter(scope);

          // Events:
          var onBeforeActiveCallback = $parse(attrs.onBeforeActive);
          var onActiveCallback = $parse(attrs.onActive);

          scope.$isActive = function(node) {
            return activeNode === node;
          };

          scope.$activate = function(nodeScope) {
            if (onBeforeActiveCallback(scope, {$scope: nodeScope}) !== false) {
              activeNode = nodeScope.$modelValue;
              activeNodeSetter && activeNodeSetter(scope, activeNode);
              onActiveCallback(scope, {$scope: nodeScope});
            }
          };
        }
      }
    }
  }]);<|endoftext|>


<commit_before>module.exports = {
  model: function (params, transition) {
    transition.redirectTo("posts.show", 1);
  },
  activate: function () {},
  deactivate: function () {}
};<commit_msg>Fix the redirect in posts.index handler<commit_after>module.exports = {
  model: function (params, context, transition) {
    transition.redirectTo("posts.show", 1);
  },
  activate: function () {},
  deactivate: function () {}
};<|endoftext|>


<commit_before>(function (module, undefined) {

  function getStyle(element, property) {
    return window.getComputedStyle(element)[property];
  }

  function height(element) {
    return element.clientHeight - parseFloat(getStyle(element, 'paddingTop')) - parseFloat(getStyle(element, 'paddingBottom'));
  }

  function trim(str) {
    return (str || '').replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, ''); // from jQuery
  }

  function indexNotInRange(rangesExcluded, index) {
    var i, length, range, lower, upper, skip;
    for (i = 0, length = rangesExcluded.length; i < length; i++) {
      range = rangesExcluded[i];
      lower = range[0];
      upper = range[1];
      skip = range[2];
      if (range.length >= 2 && lower <= index && index <= upper) {
        if (skip) {
          // Skip over a comment node
          return upper;
        } else {
          // Find nearest cutoff point
          return ((index - lower) < (upper - index)) ? lower - 1 : upper + 1;
        }
      }
    }
    return index;
  }

  function findElementNodeRanges(nodeList) {
    var index,
        startIndex,
        endIndex = -1,
        node,
        ranges = [];

    for (var i = 0; i < nodeList.length++; i++) {
      node = nodeList[i];
      startIndex = endIndex + 1;

      var nodeType = node.nodeType;
      if (nodeType === window.Node.TEXT_NODE) {
        endIndex = startIndex + node.textContent.length - 1;
      } else if (nodeType === window.Node.COMMENT_NODE) {
        // length + 7 for HTML comment opening/closing tags
        // e.g.) <!--MY_COMMENT--> 10+7=17
        endIndex = startIndex + node.textContent.length + 7 - 1;
        ranges.push([startIndex, endIndex, true]);
      } else if (nodeType === window.Node.ELEMENT_NODE) {
        endIndex = startIndex + node.outerHTML.length - 1;
        ranges.push([startIndex, endIndex, false]);
      }
    }

    return ranges;
  }

  function Truncate(element, options) {
    this.options = options || {};
    options.showMore = typeof options.showMore !== 'undefined' ? options.showMore : '…';
    options.showLess = typeof options.showLess !== 'undefined' ? options.showLess : '';

    this.element = element;
    this.originalHTML = element.innerHTML;
    this.cached = '';
    this.maxHeight = options.lines * options.lineHeight;

    this.update();
  }

  Truncate.prototype.update = function (newHTML) {
    if (newHTML) {
      this.element.innerHTML = newHTML;
    }

    this.element.style.visibility = 'hidden';
    this.originalHTML = this.element.innerHTML;

    if (height(this.element) <= this.maxHeight) {
      this.element.style.visibility = 'visible';
      return;
    }

    var excludeRanges = findElementNodeRanges(this.element.childNodes);

    this._truncate(excludeRanges);

    this.element.style.visibility = 'visible';
  };

  Truncate.prototype.expand = function () {
    this.element.innerHTML = this.originalHTML + this.options.showLess;
  };

  Truncate.prototype.collapse = function () {
    this.element.innerHTML = this.cached;
  };

  Truncate.prototype._truncate = function (excludeRanges) {
    var mid,
        low = 0,
        high = this.originalHTML.length,
        maxChunk = '',
        chunk,
        chunkLength,
        prevChunkLength = 0;

    // Binary Search
    while (low <= high) {
      mid = low + ((high - low) >> 1); // Integer division
      chunkLength = indexNotInRange(excludeRanges, mid);

      if (prevChunkLength === chunkLength) {
        break; // Prevent infinite loop
      }
      prevChunkLength = chunkLength;

      chunk = trim(this.originalHTML.substr(0, chunkLength + 1)) + this.options.showMore;
      this.element.innerHTML = chunk;

      if (height(this.element) > this.maxHeight) {
        high = chunkLength - 1;
      } else {
        low = chunkLength + 1;

        maxChunk = maxChunk.length > chunk.length ? maxChunk : chunk;
      }
    }

    this.element.innerHTML = ''; // Reset scrollbar

    this.element.innerHTML = this.cached = maxChunk;
  };

  module.Truncate = Truncate;

})(this);
<commit_msg>Use length variable<commit_after>(function (module, undefined) {

  function getStyle(element, property) {
    return window.getComputedStyle(element)[property];
  }

  function height(element) {
    return element.clientHeight - parseFloat(getStyle(element, 'paddingTop')) - parseFloat(getStyle(element, 'paddingBottom'));
  }

  function trim(str) {
    return (str || '').replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, ''); // from jQuery
  }

  function indexNotInRange(rangesExcluded, index) {
    var i, length, range, lower, upper, skip;
    for (i = 0, length = rangesExcluded.length; i < length; i++) {
      range = rangesExcluded[i];
      lower = range[0];
      upper = range[1];
      skip = range[2];
      if (range.length >= 2 && lower <= index && index <= upper) {
        if (skip) {
          // Skip over a comment node
          return upper;
        } else {
          // Find nearest cutoff point
          return ((index - lower) < (upper - index)) ? lower - 1 : upper + 1;
        }
      }
    }
    return index;
  }

  function findElementNodeRanges(nodeList) {
    var index,
        length,
        startIndex,
        endIndex = -1,
        node,
        ranges = [];

    for (index = 0, length = nodeList.length; index < length; index++) {
      node = nodeList[index];
      startIndex = endIndex + 1;

      var nodeType = node.nodeType;
      if (nodeType === window.Node.TEXT_NODE) {
        endIndex = startIndex + node.textContent.length - 1;
      } else if (nodeType === window.Node.COMMENT_NODE) {
        // length + 7 for HTML comment opening/closing tags
        // e.g.) <!--MY_COMMENT--> 10+7=17
        endIndex = startIndex + node.textContent.length + 7 - 1;
        ranges.push([startIndex, endIndex, true]);
      } else if (nodeType === window.Node.ELEMENT_NODE) {
        endIndex = startIndex + node.outerHTML.length - 1;
        ranges.push([startIndex, endIndex, false]);
      }
    }

    return ranges;
  }

  function Truncate(element, options) {
    this.options = options || {};
    options.showMore = typeof options.showMore !== 'undefined' ? options.showMore : '…';
    options.showLess = typeof options.showLess !== 'undefined' ? options.showLess : '';

    this.element = element;
    this.originalHTML = element.innerHTML;
    this.cached = '';
    this.maxHeight = options.lines * options.lineHeight;

    this.update();
  }

  Truncate.prototype.update = function (newHTML) {
    if (newHTML) {
      this.element.innerHTML = newHTML;
    }

    this.element.style.visibility = 'hidden';
    this.originalHTML = this.element.innerHTML;

    if (height(this.element) <= this.maxHeight) {
      this.element.style.visibility = 'visible';
      return;
    }

    var excludeRanges = findElementNodeRanges(this.element.childNodes);

    this._truncate(excludeRanges);

    this.element.style.visibility = 'visible';
  };

  Truncate.prototype.expand = function () {
    this.element.innerHTML = this.originalHTML + this.options.showLess;
  };

  Truncate.prototype.collapse = function () {
    this.element.innerHTML = this.cached;
  };

  Truncate.prototype._truncate = function (excludeRanges) {
    var mid,
        low = 0,
        high = this.originalHTML.length,
        maxChunk = '',
        chunk,
        chunkLength,
        prevChunkLength = 0;

    // Binary Search
    while (low <= high) {
      mid = low + ((high - low) >> 1); // Integer division
      chunkLength = indexNotInRange(excludeRanges, mid);

      if (prevChunkLength === chunkLength) {
        break; // Prevent infinite loop
      }
      prevChunkLength = chunkLength;

      chunk = trim(this.originalHTML.substr(0, chunkLength + 1)) + this.options.showMore;
      this.element.innerHTML = chunk;

      if (height(this.element) > this.maxHeight) {
        high = chunkLength - 1;
      } else {
        low = chunkLength + 1;

        maxChunk = maxChunk.length > chunk.length ? maxChunk : chunk;
      }
    }

    this.element.innerHTML = ''; // Reset scrollbar

    this.element.innerHTML = this.cached = maxChunk;
  };

  module.Truncate = Truncate;

})(this);
<|endoftext|>


<commit_before>'use strict';

var assign                = require('es5-ext/object/assign')
  , callable              = require('es5-ext/object/valid-callable')
  , d                     = require('d/d')
  , lazy                  = require('d/lazy')
  , injectPrimitive       = require('../utils/inject-primitive')
  , injectPrimitiveNested = require('../utils/inject-primitive-nested')
  , Observable            = require('./observable')
  , Multiple              = require('./multiple')

  , call = Function.prototype.call
  , hasOwnProperty = Object.prototype.hasOwnProperty, create = Object.create
  , keys = Object.keys, defineProperties = Object.defineProperties;

module.exports = function (object, item) {
	defineProperties(object, assign({

		// Item
		__itemPrototype__: d('', item),
		__multiples__: d('', create(null)),
		_getMultipleItems_: d(function (pKey) {
			var multiples = this._multiples_;
			if (hasOwnProperty.call(multiples, pKey)) return multiples[pKey];
			return injectPrimitiveNested(this,
				multiples[pKey] = create(multiples[pKey] || null),
				'__multiples__', pKey);
		}),
		_getMultipleItem_: d(function (pKey, key, sKey) {
			var setData = this._getMultipleItems_(pKey);
			if (hasOwnProperty.call(setData, sKey)) return setData[sKey];
			if (setData[sKey]) return setData[sKey]._create_(this, setData);
			return item._create_(this, pKey, key, sKey, setData);
		}),

		// Observable
		_getMultipleItemObservable_: d(function (pKey, sKey, key) {
			var observables = this._observableMultipleItems_;
			if (observables[pKey]) observables = observables[pKey];
			else observables = observables[pKey] = create(null);
			if (observables[sKey]) return observables[sKey];
			return (observables[sKey] = new Observable(this, pKey, sKey, key));
		}),

		// Multiple
		_getMultiple_: d(function (sKey) {
			var sets = this._sets_;
			if (hasOwnProperty.call(sets, sKey)) return sets[sKey];
			return (sets[sKey] = new Multiple(this, sKey));
		}),

		// Iterator
		_getMultipleIterators_: d(function (sKey) {
			var iterators = this._multipleIterators_;
			if (hasOwnProperty.call(iterators, sKey)) return iterators[sKey];
			return (iterators[sKey] = []);
		}),

		_forEachOwnItem_: d(function (cb/*, thisArg*/) {
			var thisArg = arguments[1];
			callable(cb);
			if (!this.hasOwnProperty('__multiples__')) return;
			keys(this.__multiples__).forEach(function (sKey) {
				keys(this[sKey]).forEach(function (sKey) {
					call.call(cb, thisArg, this[sKey], sKey);
				}, this[sKey]);
			}, this.__multiples__);
		})

	}, lazy({

		// Item
		_multiples_: d(function () {
			return injectPrimitive(this, create(this.__multiples__),
				'__multiples__');
		},  { cacheName: '__multiples__', desc: '' }),

		// Observable
		_observableMultipleItems_: d(function () { return create(null); },
			{ cacheName: '__observableMultipleItems__', desc: '' }),

		// Multiple
		_sets_: d(function () { return create(null); },
			{ cacheName: '__sets__', desc: '' }),

		// Iterator
		_multipleIterators_: d(function () { return create(null); },
			{ cacheName: '__multipleIterators__', desc: '' })
	})));
};
<commit_msg>-- whitespace<commit_after>'use strict';

var assign                = require('es5-ext/object/assign')
  , callable              = require('es5-ext/object/valid-callable')
  , d                     = require('d/d')
  , lazy                  = require('d/lazy')
  , injectPrimitive       = require('../utils/inject-primitive')
  , injectPrimitiveNested = require('../utils/inject-primitive-nested')
  , Observable            = require('./observable')
  , Multiple              = require('./multiple')

  , call = Function.prototype.call
  , hasOwnProperty = Object.prototype.hasOwnProperty, create = Object.create
  , keys = Object.keys, defineProperties = Object.defineProperties;

module.exports = function (object, item) {
	defineProperties(object, assign({

		// Item
		__itemPrototype__: d('', item),
		__multiples__: d('', create(null)),
		_getMultipleItems_: d(function (pKey) {
			var multiples = this._multiples_;
			if (hasOwnProperty.call(multiples, pKey)) return multiples[pKey];
			return injectPrimitiveNested(this,
				multiples[pKey] = create(multiples[pKey] || null),
				'__multiples__', pKey);
		}),
		_getMultipleItem_: d(function (pKey, key, sKey) {
			var setData = this._getMultipleItems_(pKey);
			if (hasOwnProperty.call(setData, sKey)) return setData[sKey];
			if (setData[sKey]) return setData[sKey]._create_(this, setData);
			return item._create_(this, pKey, key, sKey, setData);
		}),

		// Observable
		_getMultipleItemObservable_: d(function (pKey, sKey, key) {
			var observables = this._observableMultipleItems_;
			if (observables[pKey]) observables = observables[pKey];
			else observables = observables[pKey] = create(null);
			if (observables[sKey]) return observables[sKey];
			return (observables[sKey] = new Observable(this, pKey, sKey, key));
		}),

		// Multiple
		_getMultiple_: d(function (sKey) {
			var sets = this._sets_;
			if (hasOwnProperty.call(sets, sKey)) return sets[sKey];
			return (sets[sKey] = new Multiple(this, sKey));
		}),

		// Iterator
		_getMultipleIterators_: d(function (sKey) {
			var iterators = this._multipleIterators_;
			if (hasOwnProperty.call(iterators, sKey)) return iterators[sKey];
			return (iterators[sKey] = []);
		}),

		_forEachOwnItem_: d(function (cb/*, thisArg*/) {
			var thisArg = arguments[1];
			callable(cb);
			if (!this.hasOwnProperty('__multiples__')) return;
			keys(this.__multiples__).forEach(function (sKey) {
				keys(this[sKey]).forEach(function (sKey) {
					call.call(cb, thisArg, this[sKey], sKey);
				}, this[sKey]);
			}, this.__multiples__);
		})

	}, lazy({

		// Item
		_multiples_: d(function () {
			return injectPrimitive(this, create(this.__multiples__),
				'__multiples__');
		}, { cacheName: '__multiples__', desc: '' }),

		// Observable
		_observableMultipleItems_: d(function () { return create(null); },
			{ cacheName: '__observableMultipleItems__', desc: '' }),

		// Multiple
		_sets_: d(function () { return create(null); },
			{ cacheName: '__sets__', desc: '' }),

		// Iterator
		_multipleIterators_: d(function () { return create(null); },
			{ cacheName: '__multipleIterators__', desc: '' })
	})));
};
<|endoftext|>


<commit_before>import { compileLogger, runLogger } from "../cli.controller";
const MockExpressRequest = require("mock-express-request");
const MockExpressResponse = require("mock-express-response");
import mongoose from "mongoose";
import config from "../../../config/environment";
import { seedTestData, testLoggerMsgToBePrinted } from "../../../config/seed";
import Logger from "../../logger/logger.model";

beforeAll(() => {
  // Connect to database
  mongoose.Promise = global.Promise;
  mongoose.connect(config.mongo.uri, config.mongo.options);

  // Populate DB with sample data
  if (config.seedDB) {
    return seedTestData();
  }
});

const goodCodeCompileResponseJSON = {
  error: false,
  stdout: "",
  stderr: ""
};

const badCodeCompileResponseJSON = {
  error: true,
  stdout: "",
  stderr: expect.stringMatching(/users\/\w+\/\w+\/BadCode\.c:\d+:\d+: error: /)
};

const infiniteLoopCodeCompileResponseJSON = goodCodeCompileResponseJSON;

const goodCodeRunResponseJSON = {
  error: false,
  stdout: testLoggerMsgToBePrinted,
  stderr: ""
};

const badCodeRunResponseJSON = badCodeCompileResponseJSON;

const infiniteLoopCodeRunResponseJSON = {
  error: true,
  stdout: "",
  stderr: expect.stringMatching(/TimeoutError/)
};

function getMockExpressRequestForLogger(logger) {
  return new MockExpressRequest({
    user: {
      id: "testUserId"
    },
    params: {
      id: logger._id
    }
  });
}

test("Compile Logger with Good Code", async () => {
  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });

  let req = getMockExpressRequestForLogger(goodCodeLogger);
  let res = new MockExpressResponse();

  let response = await compileLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(goodCodeCompileResponseJSON);
});

test("Compile Logger with Bad Code", async () => {
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });

  let req = getMockExpressRequestForLogger(badCodeLogger);
  let res = new MockExpressResponse();

  let response = await compileLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(badCodeCompileResponseJSON);
});

test("Compile Logger with Infinite Loop Code", async () => {
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  let req = getMockExpressRequestForLogger(infiniteLoopCodeLogger);
  let res = new MockExpressResponse();

  let response = await compileLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject({
    error: false,
    stdout: "",
    stderr: ""
  });
});

test("Compile Logger Load Test", async () => {
  // Note: On average this test requires:
  // - 15 seconds to run with 2 simultaneous calls to `compileLogger`
  // - 30 seconds to run with 5 simultaneous calls to `compileLogger`
  // - 40 seconds to run with 10 simultaneous calls to `compileLogger`
  // - 100 seconds to run with 30 simultaneous calls to `compileLogger`
  // - 300 seconds to run with 100 simultaneous calls to `compileLogger`
  // Change `numberOfRequests` and `testRunTimeInSeconds` as desired.
  const numberOfRequests = 100;
  const testRunTimeInSeconds = 600;
  jest.setTimeout(testRunTimeInSeconds * 1000);

  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  const allLoggers = [goodCodeLogger, badCodeLogger, infiniteLoopCodeLogger];
  const allCompileResponseJSONs = [goodCodeCompileResponseJSON, badCodeCompileResponseJSON, infiniteLoopCodeCompileResponseJSON];

  const outputResponsePromises = [];

  expect.assertions(numberOfRequests);

  // execute a bunch of calls to compileLogger
  for (let i = 0; i < numberOfRequests; i++) {
    let randomIndex = Math.floor(Math.random() * 3);  // random integer between 0 and 2 inclusive
    let req = getMockExpressRequestForLogger(allLoggers[randomIndex]);
    let res = new MockExpressResponse();
    outputResponsePromises[i] = compileLogger(req, res).then(response => {
      let responseJson = response._getJSON();
      expect(responseJson).toMatchObject(allCompileResponseJSONs[randomIndex]);
    }).catch(err => {
      throw err;
    });
  }

  return Promise.all(outputResponsePromises);
});

test("Run Logger with Good Code", async () => {
  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });

  let req = getMockExpressRequestForLogger(goodCodeLogger);
  let res = new MockExpressResponse();

  let response = await runLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(goodCodeRunResponseJSON);
});

test("Run Logger with Bad Code", async () => {
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });

  let req = getMockExpressRequestForLogger(badCodeLogger);
  let res = new MockExpressResponse();

  let response = await runLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(badCodeRunResponseJSON);
});

test("Run Logger with Infinite Loop Code", async () => {
  jest.setTimeout(15000);
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  let req = getMockExpressRequestForLogger(infiniteLoopCodeLogger);
  let res = new MockExpressResponse();

  let response = await runLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(infiniteLoopCodeRunResponseJSON);
});

test("Run Logger Load Test", async () => {
  // Note: On average this test requires:
  // - 20 seconds to run with 2 simultaneous calls to `runLogger`
  // - 40 seconds to run with 5 simultaneous calls to `runLogger`
  // - 60 seconds to run with 10 simultaneous calls to `runLogger`
  // - 200 seconds to run with 30 simultaneous calls to `runLogger`
  // - 600 seconds to run with 100 simultaneous calls to `runLogger`
  // Change `numberOfRequests` and `testRunTimeInSeconds` as desired.
  const numberOfRequests = 100;
  const testRunTimeInSeconds = 600;
  jest.setTimeout(testRunTimeInSeconds * 1000);

  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  const allLoggers = [goodCodeLogger, badCodeLogger, infiniteLoopCodeLogger];
  const allRunResponseJSONs = [goodCodeRunResponseJSON, badCodeRunResponseJSON, infiniteLoopCodeRunResponseJSON];

  const outputResponsePromises = [];

  expect.assertions(numberOfRequests);

  // execute a bunch of calls to runLogger
  for (let i = 0; i < numberOfRequests; i++) {
    let randomIndex = Math.floor(Math.random() * 3);  // random integer between 0 and 2 inclusive
    let req = getMockExpressRequestForLogger(allLoggers[randomIndex]);
    let res = new MockExpressResponse();
    outputResponsePromises[i] = runLogger(req, res).then(response => {
      let responseJson = response._getJSON();
      expect(responseJson).toMatchObject(allRunResponseJSONs[randomIndex]);
    }).catch(err => {
      throw err;
    });
  }

  return Promise.all(outputResponsePromises);
});

test("Compile And Run Logger Load Test", async () => {
  // Note: On average this test requires:
  // - 20 seconds to run with 2 simultaneous calls to `runLogger`
  // - 40 seconds to run with 5 simultaneous calls to `runLogger`
  // - 60 seconds to run with 10 simultaneous calls to `runLogger`
  // - 200 seconds to run with 30 simultaneous calls to `runLogger`
  // - 600 seconds to run with 100 simultaneous calls to `runLogger`
  // Change `numberOfRequests` and `testRunTimeInSeconds` as desired.
  const numberOfRequests = 100;
  const testRunTimeInSeconds = 600;
  jest.setTimeout(testRunTimeInSeconds * 1000);

  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  const allLoggers = [goodCodeLogger, badCodeLogger, infiniteLoopCodeLogger, goodCodeLogger, badCodeLogger, infiniteLoopCodeLogger];
  const allResponseJSONs = [
    goodCodeCompileResponseJSON, badCodeCompileResponseJSON, infiniteLoopCodeCompileResponseJSON,
    goodCodeRunResponseJSON, badCodeRunResponseJSON, infiniteLoopCodeRunResponseJSON
  ];
  const runOrCompileFunctions = [compileLogger, runLogger];

  const outputResponsePromises = [];

  expect.assertions(numberOfRequests);

  // execute a bunch of calls to runLogger
  for (let i = 0; i < numberOfRequests; i++) {
    let randomIndex = Math.floor(Math.random() * 6);  // random integer between 0 and 5 inclusive
    let runOrCompileIndex = Math.floor(randomIndex / 3);  // random choice of 0 or 1
    let runOrCompile = runOrCompileFunctions[runOrCompileIndex];  // random choice of `compileLogger` or `runLogger`
    let req = getMockExpressRequestForLogger(allLoggers[randomIndex]);
    let res = new MockExpressResponse();
    outputResponsePromises[i] = runOrCompile(req, res).then(response => {
      let responseJson = response._getJSON();
      expect(responseJson).toMatchObject(allResponseJSONs[randomIndex]);
    }).catch(err => {
      throw err;
    });
  }

  return Promise.all(outputResponsePromises);
});
<commit_msg>Log how long the load test took to finish all the calls<commit_after>import { compileLogger, runLogger } from "../cli.controller";
const MockExpressRequest = require("mock-express-request");
const MockExpressResponse = require("mock-express-response");
import mongoose from "mongoose";
import config from "../../../config/environment";
import { seedTestData, testLoggerMsgToBePrinted } from "../../../config/seed";
import Logger from "../../logger/logger.model";

beforeAll(() => {
  // Connect to database
  mongoose.Promise = global.Promise;
  mongoose.connect(config.mongo.uri, config.mongo.options);

  // Populate DB with sample data
  if (config.seedDB) {
    return seedTestData();
  }
});

const goodCodeCompileResponseJSON = {
  error: false,
  stdout: "",
  stderr: ""
};

const badCodeCompileResponseJSON = {
  error: true,
  stdout: "",
  stderr: expect.stringMatching(/users\/\w+\/\w+\/BadCode\.c:\d+:\d+: error: /)
};

const infiniteLoopCodeCompileResponseJSON = goodCodeCompileResponseJSON;

const goodCodeRunResponseJSON = {
  error: false,
  stdout: testLoggerMsgToBePrinted,
  stderr: ""
};

const badCodeRunResponseJSON = badCodeCompileResponseJSON;

const infiniteLoopCodeRunResponseJSON = {
  error: true,
  stdout: "",
  stderr: expect.stringMatching(/TimeoutError/)
};

function getMockExpressRequestForLogger(logger) {
  return new MockExpressRequest({
    user: {
      id: "testUserId"
    },
    params: {
      id: logger._id
    }
  });
}

test("Compile Logger with Good Code", async () => {
  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });

  let req = getMockExpressRequestForLogger(goodCodeLogger);
  let res = new MockExpressResponse();

  let response = await compileLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(goodCodeCompileResponseJSON);
});

test("Compile Logger with Bad Code", async () => {
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });

  let req = getMockExpressRequestForLogger(badCodeLogger);
  let res = new MockExpressResponse();

  let response = await compileLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(badCodeCompileResponseJSON);
});

test("Compile Logger with Infinite Loop Code", async () => {
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  let req = getMockExpressRequestForLogger(infiniteLoopCodeLogger);
  let res = new MockExpressResponse();

  let response = await compileLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject({
    error: false,
    stdout: "",
    stderr: ""
  });
});

test("Compile Logger Load Test", async () => {
  // Note: On average this test requires:
  // - 15 seconds to run with 2 simultaneous calls to `compileLogger`
  // - 30 seconds to run with 5 simultaneous calls to `compileLogger`
  // - 40 seconds to run with 10 simultaneous calls to `compileLogger`
  // - 100 seconds to run with 30 simultaneous calls to `compileLogger`
  // - 300 seconds to run with 100 simultaneous calls to `compileLogger`
  // Change `numberOfRequests` and `testRunTimeInSeconds` as desired.
  const numberOfRequests = 100;
  const testRunTimeInSeconds = 600;
  jest.setTimeout(testRunTimeInSeconds * 1000);

  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  const allLoggers = [goodCodeLogger, badCodeLogger, infiniteLoopCodeLogger];
  const allCompileResponseJSONs = [goodCodeCompileResponseJSON, badCodeCompileResponseJSON, infiniteLoopCodeCompileResponseJSON];

  const outputResponsePromises = [];

  expect.assertions(numberOfRequests);

  // execute a bunch of calls to compileLogger
  for (let i = 0; i < numberOfRequests; i++) {
    let randomIndex = Math.floor(Math.random() * 3);  // random integer between 0 and 2 inclusive
    let req = getMockExpressRequestForLogger(allLoggers[randomIndex]);
    let res = new MockExpressResponse();
    outputResponsePromises[i] = compileLogger(req, res).then(response => {
      let responseJson = response._getJSON();
      expect(responseJson).toMatchObject(allCompileResponseJSONs[randomIndex]);
    }).catch(err => {
      throw err;
    });
  }

  return Promise.all(outputResponsePromises);
});

test("Run Logger with Good Code", async () => {
  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });

  let req = getMockExpressRequestForLogger(goodCodeLogger);
  let res = new MockExpressResponse();

  let response = await runLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(goodCodeRunResponseJSON);
});

test("Run Logger with Bad Code", async () => {
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });

  let req = getMockExpressRequestForLogger(badCodeLogger);
  let res = new MockExpressResponse();

  let response = await runLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(badCodeRunResponseJSON);
});

test("Run Logger with Infinite Loop Code", async () => {
  jest.setTimeout(15000);
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  let req = getMockExpressRequestForLogger(infiniteLoopCodeLogger);
  let res = new MockExpressResponse();

  let response = await runLogger(req, res);
  let responseJson = response._getJSON();
  expect(responseJson).toMatchObject(infiniteLoopCodeRunResponseJSON);
});

test("Run Logger Load Test", async () => {
  // Note: On average this test requires:
  // - 20 seconds to run with 2 simultaneous calls to `runLogger`
  // - 40 seconds to run with 5 simultaneous calls to `runLogger`
  // - 60 seconds to run with 10 simultaneous calls to `runLogger`
  // - 200 seconds to run with 30 simultaneous calls to `runLogger`
  // - 600 seconds to run with 100 simultaneous calls to `runLogger`
  // Change `numberOfRequests` and `testRunTimeInSeconds` as desired.
  const numberOfRequests = 100;
  const testRunTimeInSeconds = 600;
  jest.setTimeout(testRunTimeInSeconds * 1000);

  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  const allLoggers = [goodCodeLogger, badCodeLogger, infiniteLoopCodeLogger];
  const allRunResponseJSONs = [goodCodeRunResponseJSON, badCodeRunResponseJSON, infiniteLoopCodeRunResponseJSON];

  const outputResponsePromises = [];

  expect.assertions(numberOfRequests);

  // execute a bunch of calls to runLogger
  for (let i = 0; i < numberOfRequests; i++) {
    let randomIndex = Math.floor(Math.random() * 3);  // random integer between 0 and 2 inclusive
    let req = getMockExpressRequestForLogger(allLoggers[randomIndex]);
    let res = new MockExpressResponse();
    outputResponsePromises[i] = runLogger(req, res).then(response => {
      let responseJson = response._getJSON();
      expect(responseJson).toMatchObject(allRunResponseJSONs[randomIndex]);
    }).catch(err => {
      throw err;
    });
  }

  return Promise.all(outputResponsePromises);
});

test("Compile And Run Logger Load Test", async () => {
  // Note: On average this test requires:
  // - 20 seconds to run with 2 simultaneous calls to `runLogger`
  // - 40 seconds to run with 5 simultaneous calls to `runLogger`
  // - 60 seconds to run with 10 simultaneous calls to `runLogger`
  // - 200 seconds to run with 30 simultaneous calls to `runLogger`
  // - 600 seconds to run with 100 simultaneous calls to `runLogger`
  // Change `numberOfRequests` and `testRunTimeInSeconds` as desired.
  const numberOfRequests = 100;
  const testRunTimeInSeconds = 600;
  jest.setTimeout(testRunTimeInSeconds * 1000);

  let goodCodeLogger = await Logger.findOne({
    className: "GoodCode"
  });
  let badCodeLogger = await Logger.findOne({
    className: "BadCode"
  });
  let infiniteLoopCodeLogger = await Logger.findOne({
    className: "InfiniteLoopCode"
  });

  const allLoggers = [goodCodeLogger, badCodeLogger, infiniteLoopCodeLogger, goodCodeLogger, badCodeLogger, infiniteLoopCodeLogger];
  const allResponseJSONs = [
    goodCodeCompileResponseJSON, badCodeCompileResponseJSON, infiniteLoopCodeCompileResponseJSON,
    goodCodeRunResponseJSON, badCodeRunResponseJSON, infiniteLoopCodeRunResponseJSON
  ];
  const runOrCompileFunctions = [compileLogger, runLogger];

  const outputResponsePromises = [];

  expect.assertions(numberOfRequests);

  let startTime = Date.now();

  // execute a bunch of calls to runLogger
  for (let i = 0; i < numberOfRequests; i++) {
    let randomIndex = Math.floor(Math.random() * 6);  // random integer between 0 and 5 inclusive
    let runOrCompileIndex = Math.floor(randomIndex / 3);  // random choice of 0 or 1
    let runOrCompile = runOrCompileFunctions[runOrCompileIndex];  // random choice of `compileLogger` or `runLogger`
    let req = getMockExpressRequestForLogger(allLoggers[randomIndex]);
    let res = new MockExpressResponse();
    outputResponsePromises[i] = runOrCompile(req, res).then(response => {
      let responseJson = response._getJSON();
      expect(responseJson).toMatchObject(allResponseJSONs[randomIndex]);
    }).catch(err => {
      throw err;
    });
  }

  return Promise.all(outputResponsePromises).then(_ => {
    let endTime = Date.now();
    let timeElapsed = (endTime - startTime) / 1000;
    console.log(`We're done! It took ${timeElapsed} seconds to complete ${numberOfRequests} calls.`);
  });
});
<|endoftext|>


<commit_before>// Strict mode enforces cleaner syntax, scoping, etc.
'use strict';

function drawTile (location, color) {
	var tileWidth = Globals.tileWidth;
	var tileHeight = Globals.tileHeight;
	var tileSpace = Globals.tileSpace;
	var boardX = Globals.boardX;
	var boardY = Globals.boardY;

	var x = location.x * (tileWidth + tileSpace) + boardX;
	var y = location.y * (tileHeight + tileSpace) + ((tileHeight / 2) * (location.x % 2)) + boardY;
	Globals.ctx.fillStyle=color;
	Globals.ctx.fillRect(x, y, tileWidth, tileHeight);
	Globals.ctx.font="35px Garamond";
	Globals.ctx.fillStyle="#000000";
	Globals.ctx.rect(x, y, tileWidth, tileHeight);
	var text = Globals.ctx.measureText(gameState.gameboard[location.y][location.x]);
	var xOffset = (tileWidth - text.width) / 2;
	var yOffset = (tileHeight - text.height) / 2;

	Globals.ctx.fillText(gameState.gameboard[location.y][location.x], x + xOffset, y + 35);
}

function renderBoard () {
	Globals.ctx.fillStyle="#8F3931";
	Globals.ctx.fillRect(0, 0, Globals.c.width, Globals.c.height);

	// Draw a box with character for each tile
	for (var j = 0; j < 8; j++) {
		for (var i = 0; i < 7; i++) {
			drawTile({x: i, y: j}, "#800000");
		}
	}

	// Draw the selection chain
	if (gameState.selection.x > -1 && gameState.selection.y > -1) {
		// First the head
		drawTile(gameState.selection, "#FFA319");
		// Then each member of the list
		for (var i = 0; i < gameState.selectionChain.length; i++) {
			drawTile(gameState.selectionChain[i], "#FFB547");
		}
	}

	Globals.ctx.stroke();
	showScore();
}

// Returns the index in the column of the next selected tile, and -1 if the column contains none
function nextSelectedTileInColumn(i) {
	var colIndex = -1;

	for (var j = 0; j < 8 && colIndex < 0; j++) {
		// Check if it's the selection
		if (gameState.selection.x == i && gameState.selection.y == j) {
			colIndex = j;
			//alert("Found the selection at (" + i + ", j" + ").");
		}
		// Check if it's in the chain of selected tiles
		else {
			for (var k = 0; k < gameState.selectionChain.length && colIndex < 0; k++)
			{
				if (gameState.selectionChain[k].x == i && gameState.selectionChain[k].y == j) {
					colIndex = j;
				}
			}
		}
	}
	return colIndex;
}

// Gets the index of the (i, j)th tile within the chain of selected tiles
function getChainIndex(i, j) {
	var chainIndex = -1;
	for (var k = 0; k < gameState.selectionChain.length && chainIndex < 0; k++) {
		if (gameState.selectionChain[k].x == i && gameState.selectionChain[k].y == j) {
			chainIndex = k;
		}
	}
	return chainIndex;
}

function cleanUp(i, j) {
	if (j > -1) {
		var chainIndex = getChainIndex(i, j);
		if (chainIndex > -1) {
			gameState.selectionChain.splice(chainIndex, 1);
		}
		else {
			gameState.selection.x = -9001;
			gameState.selection.y = -9001;
		}
	}
}

function adjustGameboard() {
	// Get the list of columns hit by the chain
	var columns = [false, false, false, false, false, false, false];

	for (var i = 0; i < gameState.selectionChain.length; i++) {
		columns[gameState.selectionChain[i].x] = true;
	}
	columns[gameState.selection.x] = true;

	// For each column
	for (var i = 0; i < columns.length; i++) {
		if (columns[i]) {
			// Find the next instance in the column
			var colIndex = nextSelectedTileInColumn(i);

			// If there's a selected tile in the column, remove it from the list of selected tiles
			cleanUp(i,	colIndex);

			// Move the column down as long as there remain instances of the chain in it
			while (colIndex > -1) {
				for (var j = colIndex; j > 0; j--) {
					//alert("Replacing " + gameboard[j][i] + " at (" + i + ", " + j + ") with " + gameboard[j - 1][i]);
					gameState.gameboard[j][i] = gameState.gameboard[j - 1][i];
				}
				gameState.gameboard[0][i] = randchar();

				// Reset and look for another instance
				colIndex = nextSelectedTileInColumn();
				//alert("The next selected tile in the column is at index " + colIndex);

				// If there's a selected tile in the column, remove it from the list of selected tiles
				cleanUp(i, colIndex);
			}
		}
	}

	// For good measure
	gameState.selection = {x: -9001, y: -9001};
	gameState.selectionChain = [];
}

function selectedWord() {
	var candidate = "" + gameState.gameboard[gameState.selection.y][gameState.selection.x];
	for (var i = 0; i < gameState.selectionChain.length; i++){
		candidate += gameState.gameboard[gameState.selectionChain[i].y][gameState.selectionChain[i].x];
	}
	return candidate;
}

function getMousePos(canvas, evt) {
	var rect = canvas.getBoundingClientRect();
	return {
		x: evt.clientX - rect.left,
		y: evt.clientY - rect.top
	};
}

function boardClicked(selpos) {
	// If there's no chain of selected tiles
	if (gameState.selectionChain.length == 0) {
		// Clicking the selection does nothing
		if (gameState.selection.x == selpos.x && gameState.selection.y == selpos.y) {
			gameState.selection = selpos;
			gameState.selectionChain = [];
		}
		// Clicking adjacent to the selection adds to the chain
		else if (isAdjacent(selpos, gameState.selection)) {
			gameState.selectionChain.push({x: selpos.x, y : selpos.y});
		}
		// Clicking elsewhere moves the selection
		else {
			gameState.selection = selpos;
			gameState.selectionChain = [];
		}
	}
	// If there is a chain of selected tiles
	else {
		// Clicking the selection kills the chain
		if (gameState.selection.x == selpos.x && gameState.selection.y == selpos.y) {
			gameState.selection = selpos;
			gameState.selectionChain = [];
		}
		// If we didn't click on the selection, determine if we clicked on a tile in the chain
		else
		{
			// Collision Handling
			var collides = gameState.selectionCollides(selpos);
			if (collides) {
				while (gameState.selectionCollides(selpos)) {
					gameState.popFromSelectionChain(1);
				}
				return;
			}

			// No Collision
			// If we clicked on the last member of the chain, determine if we can submit the word
			if (isWord(selectedWord()) && selpos.x == gameState.selectionChain[gameState.selectionChain.length - 1].x && selpos.y == gameState.selectionChain[gameState.selectionChain.length - 1].y) {
				showWord(selectedWord());
				gameState.addSubmittedWord(selectedWord());
				adjustGameboard();
			}
			// If we clicked adjacent the most recent member of the chain, add to it
			else if (isAdjacent(selpos, gameState.selectionChain[gameState.selectionChain.length - 1])) {
				gameState.selectionChain.push({x: selpos.x, y : selpos.y});
			}
			// Otherwise, kill the chain and move the selection
			else {
				gameState.clearSelection();
				gameState.selection = selpos;
			}
		}
	}
	return;
}

// Main entry point after intial setup
function clickHandling(evt) {
	var mousePos = getMousePos(Globals.c, evt);
	var selpos = pickTile(mousePos.x, mousePos.y);
	// If we're on the gamemboard itself
	if (selpos.x < 7 && selpos.x > -1 && selpos.y < 8 && selpos.y > -1) {
		boardClicked(selpos);
	} else {
		Globals.selection = {x: -9001, y: -9001};
	}
	renderBoard();
}

function showScore() {
	document.getElementById("score").innerHTML = "Score: " + gameState.score;
}

function showWord(word) {
	document.getElementById("words").innerHTML = word + "
" + document.getElementById("words").innerHTML
}

function setup() {
	// Init c and ctx
	Globals.c = document.getElementById("myCanvas");
	Globals.ctx = Globals.c.getContext("2d");

	gameState.initGameboard();

	Globals.c.addEventListener('mouseup', clickHandling, false);

	renderBoard();
}

function GameState() {
	// Variables with default initials
	this.gameboard = [];
	this.selection = {x: -9001, y: -9001};
	this.selectionChain = [];
	this.score = 0;
	this.moveCounter = 0;
	this.submittedWords = [];
	this.wordQualityIndex = 0;

	// Readonly Methods
	this.selectionCollides = function(selpos) {
		var collides = false;

		// For each tile, check
		for (var i = 0; i < this.selectionChain.length - 1; i++) {
			// If we did hit it, delete from the chain all tiles ahead of the selected one
			if (selpos.x == this.selectionChain[i].x && selpos.y == this.selectionChain[i].y) {
				collides = true;
				break;
			}
		}
		return collides;
	}

	// Mutating Methods
	this.popFromSelectionChain = function(n) {
		var k = this.selectionChain.length - n - 1;
		for (var j = 0; j < k; j++){
			this.selectionChain.pop();
		}
	}

	this.clearSelection = function() {
		this.selection = {x: -9001, y: -9001};
		this.selectionChain = [];
	}
	this.shuffleBoard = function() {
		// TODO
		return;
	};
	this.addSubmittedWord = function(word) {
		this.submittedWords.push(word);
		this.score += baseWordScore(word);
		return;
	}
	this.initGameboard = function() {
		for (var j = 0; j < 8; j++) {
			var row = new Array(7).fill(undefined).map(weightedChar);
			this.gameboard.push(row);
		}
		return;
	}
}

// Global vars and Calls
var Globals = {
                c: undefined,
                ctx: undefined,
				boardX: 10,
				boardY: 10,
				tileWidth: 50,
				tileHeight: 50,
				tileSpace: 3 }

var gameState = new GameState();
setup();

<commit_msg>Combined selected and selectionChain.  Cleaned boardClicked<commit_after>// Strict mode enforces cleaner syntax, scoping, etc.
'use strict';

function drawTile (location, color) {
	var tileWidth = Globals.tileWidth;
	var tileHeight = Globals.tileHeight;
	var tileSpace = Globals.tileSpace;
	var boardX = Globals.boardX;
	var boardY = Globals.boardY;

	var x = location.x * (tileWidth + tileSpace) + boardX;
	var y = location.y * (tileHeight + tileSpace) + ((tileHeight / 2) * (location.x % 2)) + boardY;
	Globals.ctx.fillStyle=color;
	Globals.ctx.fillRect(x, y, tileWidth, tileHeight);
	Globals.ctx.font="35px Garamond";
	Globals.ctx.fillStyle="#000000";
	Globals.ctx.rect(x, y, tileWidth, tileHeight);
	var text = Globals.ctx.measureText(gameState.gameboard[location.y][location.x]);
	var xOffset = (tileWidth - text.width) / 2;
	var yOffset = (tileHeight - text.height) / 2;

	Globals.ctx.fillText(gameState.gameboard[location.y][location.x], x + xOffset, y + 35);
}

function renderBoard () {
	Globals.ctx.fillStyle="#8F3931";
	Globals.ctx.fillRect(0, 0, Globals.c.width, Globals.c.height);

	// Draw a box with character for each tile
	for (var j = 0; j < 8; j++) {
		for (var i = 0; i < 7; i++) {
			drawTile({x: i, y: j}, "#800000");
		}
	}

	// Draw the selection chain (or don't if empty)
	for (var i = 0; i < gameState.selectionChain.length; i++) {
		// Special case for first to please James
		if (i == 0) {
			drawTile(gameState.selectionChain[0], "#FFA319");
			continue;
		}
		// All non-first tiles:
		drawTile(gameState.selectionChain[i], "#FFB547");
	}

	Globals.ctx.stroke();
	showScore();
}

// Returns the index in the column of the next selected tile, and -1 if the column contains none
function nextSelectedTileInColumn(i) {
	var colIndex = -1;

	// For each column:
	for (var j = 0; j < 8 && colIndex < 0; j++) {
		// Check if it's in the chain of selected tiles
		for (var k = 0; k < gameState.selectionChain.length && colIndex < 0; k++) {
			if (gameState.selectionChain[k].x == i && gameState.selectionChain[k].y == j) {
				colIndex = j;
			}
		}
	}
	return colIndex;
}

// Gets the index of the (i, j)th tile within the chain of selected tiles
function getChainIndex(i, j) {
	for (var k = 0; k < gameState.selectionChain.length; k++) {
		if (gameState.selectionChain[k].x == i && gameState.selectionChain[k].y == j) {
			var chainIndex = k;
			break;
		}
	}
	return chainIndex;
}

function cleanUp(i, j) {
	if (j > -1) {
		var chainIndex = getChainIndex(i, j);
		if (chainIndex > -1) {
			gameState.selectionChain.splice(chainIndex, 1);
		}
		else {
			gameState.clearSelectionChain();
		}
	}
}

function adjustGameboard() {
	// Get the list of columns hit by the chain
	var columns = [false, false, false, false, false, false, false];

	for (var i = 0; i < gameState.selectionChain.length; i++) {
		columns[gameState.selectionChain[i].x] = true;
	}

	// For each column
	for (var i = 0; i < columns.length; i++) {
		if (columns[i]) {
			// Find the next instance in the column
			var colIndex = nextSelectedTileInColumn(i);

			// If there's a selected tile in the column, remove it from the list of selected tiles
			cleanUp(i,	colIndex);

			// Move the column down as long as there remain instances of the chain in it
			while (colIndex > -1) {
				for (var j = colIndex; j > 0; j--) {
					//alert("Replacing " + gameboard[j][i] + " at (" + i + ", " + j + ") with " + gameboard[j - 1][i]);
					gameState.gameboard[j][i] = gameState.gameboard[j - 1][i];
				}
				gameState.gameboard[0][i] = weightedChar();

				// Reset and look for another instance
				colIndex = nextSelectedTileInColumn();
				//alert("The next selected tile in the column is at index " + colIndex);

				// If there's a selected tile in the column, remove it from the list of selected tiles
				cleanUp(i, colIndex);
			}
		}
	}

	// For good measure
	gameState.clearSelectionChain();
}

function getMousePos(canvas, evt) {
	var rect = canvas.getBoundingClientRect();
	return {
		x: evt.clientX - rect.left,
		y: evt.clientY - rect.top
	};
}

function boardClicked(selpos) {
	// Helper vars:
	var collides = gameState.selectionCollides(selpos);
	var lenSelChain = gameState.selectionChain.length;

	// If empty chain:
	if (gameState.selectionChain.length == 0) {
		gameState.clearSelectionChain();
		gameState.pushToSelectionChain(selpos);
		return;
	}

	// Collision Handling
	else if (collides) {
		while (gameState.selectionCollides(selpos)) {
			gameState.popFromSelectionChain(1);
		}
		gameState.pushToSelectionChain(selpos);
		return;
	}

	// If we clicked on the last member of the chain, determine if we can submit the word
	else if (isWord(gameState.selectedWord()) &&
		     selpos.x == gameState.selectionChain[lenSelChain - 1].x &&
		     selpos.y == gameState.selectionChain[lenSelChain - 1].y) {
		showWord(gameState.selectedWord());
		gameState.addSubmittedWord(gameState.selectedWord());
		adjustGameboard();
		return;
	}

	// If we clicked adjacent the most recent member of the chain, add to it
	else if (isAdjacent(selpos, gameState.selectionChain[gameState.selectionChain.length - 1])) {
		gameState.pushToSelectionChain({x: selpos.x, y : selpos.y});
		return;
	}

	// Otherwise, kill the chain and move the selection
	else {
		gameState.clearSelectionChain();
		gameState.pushToSelectionChain(selpos);
		return;
	}
}

// Main entry point after intial setup
function clickHandling(evt) {
	var mousePos = getMousePos(Globals.c, evt);
	var selpos = pickTile(mousePos.x, mousePos.y);
	// If we're on the gamemboard itself
	if (selpos.x < 7 && selpos.x > -1 && selpos.y < 8 && selpos.y > -1) {
		boardClicked(selpos);
	}

	renderBoard();
}

function showScore() {
	document.getElementById("score").innerHTML = "Score: " + gameState.score;
}

function showWord(word) {
	document.getElementById("words").innerHTML = word + "
" + document.getElementById("words").innerHTML
}

function setup() {
	// Init c and ctx
	Globals.c = document.getElementById("myCanvas");
	Globals.ctx = Globals.c.getContext("2d");

	gameState.initGameboard();

	Globals.c.addEventListener('mouseup', clickHandling, false);

	renderBoard();
}

function GameState() {
	// Variables with default initials
	this.gameboard = [];
	this.selectionChain = [];
	this.score = 0;
	this.moveCounter = 0;
	this.submittedWords = [];
	this.wordQualityIndex = 0;

	// Readonly Methods
	this.selectedWord = function() {
		var candidate = "";
		for (var i = 0; i < this.selectionChain.length; i++){
			candidate += this.gameboard[this.selectionChain[i].y][this.selectionChain[i].x];
		}
		return candidate;
	}
	this.selectionCollides = function(selpos) {
		var collides = false;

		// For each tile, check
		for (var i = 0; i < this.selectionChain.length - 1; i++) {
			// If we did hit it, delete from the chain all tiles ahead of the selected one
			if (selpos.x == this.selectionChain[i].x && selpos.y == this.selectionChain[i].y) {
				collides = true;
				break;
			}
		}
		return collides;
	}

	// Mutating Methods
	this.pushToSelectionChain = function(coords) {
		this.selectionChain.push(coords);
	}
	this.popFromSelectionChain = function(n) {
		var k = this.selectionChain.length - n - 1;
		for (var j = 0; j < k; j++){
			this.selectionChain.pop();
		}
	}

	this.clearSelectionChain = function() {
		this.selectionChain = [];
	}
	this.shuffleBoard = function() {
		// TODO
		return;
	};
	this.addSubmittedWord = function(word) {
		this.submittedWords.push(word);
		this.score += baseWordScore(word);
		return;
	}
	this.initGameboard = function() {
		for (var j = 0; j < 8; j++) {
			var row = new Array(7).fill(undefined).map(weightedChar);
			this.gameboard.push(row);
		}
		return;
	}
}

// Global vars and Calls
var Globals = {
                c: undefined,
                ctx: undefined,
				boardX: 10,
				boardY: 10,
				tileWidth: 50,
				tileHeight: 50,
				tileSpace: 3 }

var gameState = new GameState();
setup();

<|endoftext|>


<commit_before>define([
    'angular',
    'models/game',
    'models/word'
], function (angular) {
    "use strict";
    angular.module('myApp.services.game',[]).service('GameService', function (Game, Word) {
        var game = new Game();
        var gameService = {
          game:game,
          acceptableDie: function (die) {
            var lastDie = game.currentWord[game.currentWord.length-1];
            var horzDiff = Math.abs(die.row - lastDie.row);
            var vertDiff = Math.abs(die.column - lastDie.column);
            if( (horzDiff + vertDiff == 1) && _.indexOf(game.currentWord) == -1){
              return true;
            }
            return false;
          },
          addWord : function(){
            if(game.currentWord.length > 0 && game.hasWord()){
              game.words.push(new Word(game.currentWord))
              _.each(game.currentWord, function (die) {
                die.active = false;
              })
              game.currentWord = [];
            }
          },
          score : function () {
            var totalScore = 0;
            _.each(game.words, function(word){
              totalScore += word.score;
            });
            return totalScore
          }
        };

        gameService.toggleDie = function(die){
          if(game.currentWord.length == 0){
            game.currentWord.push(die)
            die.active = !die.active;
          }
          else {
            if (die === game.currentWord[game.currentWord.length-1]){
              die.active = !die.active;
              game.currentWord.pop();
            }
            else if(!die.active && gameService.acceptableDie(die)){
              die.active = true;
              game.currentWord.push(die);
            }
          }
        };

        return gameService;
    });
});
<commit_msg>adding a few comments<commit_after>define([
    'angular',
    'models/game',
    'models/word'
], function (angular) {
    "use strict";
    angular.module('myApp.services.game',[]).service('GameService', function (Game, Word) {
        var game = new Game();
        var gameService = {
          game:game,

          // Test if die is adjacent to last added die
          adjacentDie: function (die) {
            var lastDie = game.currentWord[game.currentWord.length-1];
            var horzDiff = Math.abs(die.row - lastDie.row);
            var vertDiff = Math.abs(die.column - lastDie.column);
            if( (horzDiff + vertDiff == 1) && _.indexOf(game.currentWord) == -1){
              return true;
            }
            return false;
          },

          // Add the currentWord to the games list of words
          addWord : function(){
            if(game.currentWord.length > 0 && game.hasWord()){
              game.words.push(new Word(game.currentWord))
              _.each(game.currentWord, function (die) {
                die.active = false;
              })
              game.currentWord = [];
            }
          },

          //calculate the score of the game
          score : function () {
            var totalScore = 0;
            _.each(game.words, function(word){
              totalScore += word.score;
            });
            return totalScore
          }
        };

        // handle die toggle action
        gameService.toggleDie = function(die){
          if(game.currentWord.length == 0){
            game.currentWord.push(die)
            die.active = !die.active;
          }
          else {
            if (die === game.currentWord[game.currentWord.length-1]){
              die.active = !die.active;
              game.currentWord.pop();
            }
            else if(!die.active && gameService.adjacentDie(die)){
              die.active = true;
              game.currentWord.push(die);
            }
          }
        };

        return gameService;
    });
});
<|endoftext|>


<commit_before>/* @flow */

import React, { Component, PropTypes } from 'react';
import ReactNative from 'react-native';
import shallowEqual from 'shallowequal';
import template from 'lodash/template';
import Card from './Card';
import Share from '../../modules/Share';
import type { Room, User } from '../../../lib/schemaTypes';

const {
	Image,
	Linking,
	StyleSheet,
	TouchableOpacity,
} = ReactNative;

const styles = StyleSheet.create({
	container: {
		flex: 1,
	},
	cover: {
		height: 180,
		resizeMode: 'cover',
	},
});

type State = {
	image: ?string;
}

type Props = {
	user: User;
	room: ?Room;
	data: ?{
		id: string;
		image: string;
		title: string;
		content: ?string;
		url: ?string;
		type: 'share' | 'view';
	}
}

export default class CTACard extends Component<void, Props, State> {
	static propTypes = {
		room: PropTypes.object,
		user: PropTypes.object.isRequired,
		data: PropTypes.shape({
			id: PropTypes.string.isRequired,
			image: PropTypes.string.isRequired,
			title: PropTypes.string.isRequired,
			content: PropTypes.string,
			url: PropTypes.string,
			type: PropTypes.oneOf([ 'share', 'view' ]),
		}),
	};

	state: State = {
		image: null,
	};

	componentWillMount() {
		this._setImage(this.props);
	}

	componentWillReceiveProps(nextProps: Props) {
		this._setImage(nextProps);
	}

	shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
		return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
	}

	_checkImageExists: Function = (url: string): Promise<boolean> => {
		return new Promise(resolve => {
			const req = new XMLHttpRequest();

			req.open('HEAD', url, true); // Avoid doing a GET request to prevent OOM
			req.onreadystatechange = () => {
				if (req.readyState === req.DONE) {
					resolve(req.status === 200);
				}
			};
			req.send();
		});
	};

	_setImage: Function = async (props: Props) => {
		const {
			data,
			room,
			user,
		} = props;

		if (data && data.image) {
			const link = template(data.image)({ room, user });
			const exists = await this._checkImageExists(link);

			if (exists) {
				this.setState({
					image: link,
				});
			}
		}
	};

	_handleShare: Function = () => {
		const {
			data,
			room,
			user,
		} = this.props;

		if (data && data.content) {
			try {
				Share.shareItem(data.title || '', template(data.content)({ room, user }));
			} catch (e) {
				// ignore
			}
		}
	};

	_handleView: Function = async () => {
		const {
			room,
			user,
			data,
		} = this.props;

		if (data && data.url) {
			const link = template(data.url)({ room, user });

			try {
				const canOpen = await Linking.canOpenURL(link);

				if (canOpen) {
					await Linking.openURL(link);
				}
			} catch (e) {
				// ignore
			}
		}
	};

	_handlePress: Function = () => {
		const {
			data,
		} = this.props;

		if (data) {
			switch (data.type) {
			case 'share':
				this._handleShare();
				break;
			case 'view':
				this._handleView();
				break;
			}
		}
	};

	render() {
		if (!this.state.image) {
			return null;
		}

		return (
			<Card {...this.props}>
				<TouchableOpacity style={styles.container} onPress={this._handlePress}>
					<Image
						style={styles.cover}
						source={{ uri: this.state.image }}
					/>
				</TouchableOpacity>
			</Card>
		);
	}
}
<commit_msg>feat(ui): support specifying an array of images for CTA card<commit_after>/* @flow */

import React, { Component, PropTypes } from 'react';
import ReactNative from 'react-native';
import shallowEqual from 'shallowequal';
import template from 'lodash/template';
import Card from './Card';
import Share from '../../modules/Share';
import type { Room, User } from '../../../lib/schemaTypes';

const {
	Image,
	Linking,
	StyleSheet,
	TouchableOpacity,
} = ReactNative;

const styles = StyleSheet.create({
	container: {
		flex: 1,
	},
	cover: {
		height: 180,
		resizeMode: 'cover',
	},
});

type State = {
	image: ?string;
}

type Props = {
	user: User;
	room: ?Room;
	data: ?{
		id: string;
		image?: string;
		images?: Array<string>;
		title: string;
		content: ?string;
		url: ?string;
		type: 'share' | 'view';
	}
}

export default class CTACard extends Component<void, Props, State> {
	static propTypes = {
		room: PropTypes.object,
		user: PropTypes.object.isRequired,
		data: PropTypes.shape({
			id: PropTypes.string.isRequired,
			image: PropTypes.string,
			images: PropTypes.arrayOf(PropTypes.string),
			title: PropTypes.string.isRequired,
			content: PropTypes.string,
			url: PropTypes.string,
			type: PropTypes.oneOf([ 'share', 'view' ]),
		}),
	};

	state: State = {
		image: null,
	};

	componentWillMount() {
		this._setImage(this.props);
	}

	componentWillReceiveProps(nextProps: Props) {
		this._setImage(nextProps);
	}

	shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
		return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
	}

	_checkImageExists: Function = (url: string): Promise<boolean> => {
		return new Promise(resolve => {
			const req = new XMLHttpRequest();

			req.open('HEAD', url, true); // Avoid doing a GET request to prevent OOM
			req.onreadystatechange = () => {
				if (req.readyState === req.DONE) {
					resolve(req.status === 200);
				}
			};
			req.send();
		});
	};

	_checkImageList: Function = function(urls: Array<string>): Observable {
		return new Observable(observer => {
			const promises = urls.map(async url => {
				const exists = await this._checkImageExists(url);
				return {
					url,
					exists,
				};
			});

			Promise
				.all(promises)
				.then(
					results => {
						results.forEach(result => {
							if (result.exists) {
								observer.next(result.url);
							}
						});
						observer.complete();
					},
					e => observer.error(e)
				);
		});
	}

	_setImage: Function = (props: Props) => {
		const {
			data,
		} = props;

		if (data) {
			let images;

			if (data.images) {
				images = data.images;
			} else if (data.image) {
				images = [ data.image ];
			} else {
				images = [];
			}

			let done;

			this._checkImageList(images).forEach(image => {
				if (done) {
					return;
				}
				done = true;
				this.setState({
					image,
				});
			});
		}
	};

	_handleShare: Function = () => {
		const {
			data,
			room,
			user,
		} = this.props;

		if (data && data.content) {
			try {
				Share.shareItem(data.title || '', template(data.content)({ room, user }));
			} catch (e) {
				// ignore
			}
		}
	};

	_handleView: Function = async () => {
		const {
			room,
			user,
			data,
		} = this.props;

		if (data && data.url) {
			const link = template(data.url)({ room, user });

			try {
				const canOpen = await Linking.canOpenURL(link);

				if (canOpen) {
					await Linking.openURL(link);
				}
			} catch (e) {
				// ignore
			}
		}
	};

	_handlePress: Function = () => {
		const {
			data,
		} = this.props;

		if (data) {
			switch (data.type) {
			case 'share':
				this._handleShare();
				break;
			case 'view':
				this._handleView();
				break;
			}
		}
	};

	render() {
		if (!this.state.image) {
			return null;
		}

		return (
			<Card {...this.props}>
				<TouchableOpacity style={styles.container} onPress={this._handlePress}>
					<Image
						style={styles.cover}
						source={{ uri: this.state.image }}
					/>
				</TouchableOpacity>
			</Card>
		);
	}
}
<|endoftext|>