<commit_before>$NetworkMap.Utils = {};
$NetworkMap.Views = {};
$NetworkMap.Debug = {};
$NetworkMap.Json = {};

$NetworkMap.Json = (function() {

  return {
    setStartPositions: function(json, positions) {
      jQuery.each(positions, function(index, val1) {
        jQuery.each(json, function(index, val2) {
          if (val2.id == val1.id) {
            val2.data.pos = { x: Number(val1.x), y: Number(val1.y) };
          }
        });
      });
    }
  };
})();

$NetworkMap.Debug = (function() {

  return {
    GraphicalOutput: function(viz) {
      var _enabled = false;
      var _redraw = true;
      var _container = jQuery(viz.canvas.getElement());
      var _debugBox = jQuery('

');
      var _c = viz.canvas;
      var _frames = 0.0;
      var _fps = 0;
      var _lastTime = new Date();
      var _log = '';

      // redraw debugging information
      _container.bind('redraw', function() {
        _redraw = true;
        output();
      });

      var output = function() {
        var html = '
** Debugging Information **
';
        var table = jQuery('

');
        var str = '';
        var _preventDefault = function(evt) { evt.preventDefault(); };

        if (!_enabled) return;

        // setup styles
        jQuery("")
          .appendTo('head');

        // disable selection on div
        _debugBox.bind("dragstart", _preventDefault).bind("selectstart", _preventDefault);

        // output performance info
        table.append('
Performance
');
        table.append('
Frame Rate:	' + _fps + '
');

        table.append('

');

        // output viz info
        table.append('
State	');
        table.append('
Busy: 	' + viz.busy + '
');
        table.append('
Div id: 	' + viz.config.injectInto + '
');

        table.append('

');

        // output navigational info
        table.append('
Navigation	');
        table.append('
Scale Offset X:	' + _c.scaleOffsetX + '
');
        table.append('
Scale Offset Y:	' + _c.scaleOffsetY + '
');
        table.append('
Translate Offset X:	' + _c.translateOffsetX + '
');
        table.append('
Translate Offset Y:	' + _c.translateOffsetY + '
');

        table.append('

');

        // output depth info
        table.append('
Groups
');
        table.append('
Current Depth:	' + viz.detailLevel(_c.scaleOffsetX, viz.config.groupLvls) + '
');

        _debugBox.html(html).append('
' + _log + '

');
        _debugBox.append(table);

        // draw things onto the canvas
        if (_redraw) {
          // draw node boxes
          viz.graph.eachNode(function(n) {
            var dim = n.getData('dim');
            var pos = n.getPos();
            var canvas = viz.canvas, ctx = canvas.getCtx();

            ctx.save();
            ctx.strokeStyle = 'rgb(255,0,0)';
            ctx.lineWidth = 1 / canvas.scaleOffsetX;
            ctx.strokeRect(pos.x - dim, pos.y - dim, dim * 2, dim * 2);
            ctx.restore();
          });

          _redraw = false;
        }
      };

      var init = function() {
        var o = _container.offset();
        var ms = 10;

        _debugBox.css({
          position: 'relative',
          top: o.top,
          left: o.left,
          color: 'rgb(255,0,0)'
        });

        _container.append(_debugBox);

        _container.bind('redraw', function() {
          var nowTime = new Date();
          var diffTime = Math.ceil((nowTime.getTime() - _lastTime.getTime()));

          if (diffTime >= 1000) {
            _fps = _frames;
            _frames = 0.0;
            _lastTime = nowTime;
            output();
          }

          _frames++;
        });
      };

      init();

      return {
        enable: function() { _enabled = true; output(); },
        disable: function() { _enabled = false; },
        isEnabled: function() { return _enabled; },
        logWrite: function(text) { _log = 'Log: ' + text; output(); }
      };
    }
  };
})();

$NetworkMap.Views = (function() {

  return {
    Overview: function(viz, mapOpts, level) {
      var _opts = jQuery.extend(true, {
        Node: {
          overridable: true,
          dim: 20,
          lineWidth: 5
        },
        Edge: {
          overridable: true,
          color: '#23A4FF',
          lineWidth: 3,
          type: 'line'
        },
        Label: {
          type: 'SVG'
        }
      }, mapOpts);

      var _over = new $jit.NetworkMap(_opts),
          _container = jQuery('#' + _opts.injectInto).css({ position: 'relative' }),
          _svg, _rect,
          _mouse = null;

      // redraw the rectangle
      var redraw = function() {
        var size = viz.canvas.getSize(),
            p1 = _over.p2c(viz.c2p({ x: 0, y: 0 })),
            p2 = _over.p2c(viz.c2p({ x: size.width, y: size.height }));

        if (!_rect) {
          _rect = _svg.rect(0, 0, 0, 0).attr({ stroke: 'rgb(255,255,0)' });
        }

        _rect.attr({ x: p1.x, y: p1.y, width: Math.abs(p2.x - p1.x), height: Math.abs(p2.y - p1.y) });
        _over.loadPositions(viz.getPositions());
      };

      // translate a main canvas in sync with overview box
      var _moveBox = function(e) {
        var o = _container.offset(),
            x = e.pageX - o.left, y = e.pageY - o.top,
            canvas = viz.canvas,
            size = canvas.getSize(),
            pt1 = _over.c2p({ x: x, y: y }),
            pt2 = viz.c2p({ x: size.width / 2, y: size.height / 2 });

        canvas.translate(pt2.x - pt1.x, pt2.y - pt1.y);
      };

      // setup overview visualisation
      var init = function() {
        var o = _container.offset(),
            vizSize = viz.canvas.getSize(),
            overSize = { width: _over.canvas.getSize().width, height: _over.canvas.getSize().height },
            json = jQuery.extend(true, [], viz.json),
            svgcont = jQuery('

')
              .css({ top: 0, left: 0, position: 'absolute' })
              .appendTo(_container);

        _svg = Raphael(svgcont.get(0), overSize.width, overSize.height);

        // remove position data from nodes
        viz.config.layout != 'Static' && jQuery.each(json, function(index, n) {
            n.data && n.data.pos && delete n.data.pos;
        });

        _over.loadJSON(json);
        _over.canvas.resize(overSize.width, overSize.height);
        _over.canvas.scale(overSize.width / vizSize.width, overSize.width / vizSize.width);

        jQuery(viz.canvas.getElement()).bind('redraw', function() {
          redraw();
        });

        // setup mouse events
        svgcont.mousedown(function(e) {
          _moveBox(e);
          _mouse = e;
        });
        svgcont.mouseup(function() {
          _mouse = null;
        });
        svgcont.mousemove(function(e) {
          if (_mouse != null) _moveBox(e);
        });

        redraw();
        _over.refresh();
      };

      init();

      return {
        level: function() { return level; },
        hide: function() { hideOver(); },
        show: function() { showOver(); }
      };
    },

    OverviewManager: function(viz, container) {
      var _overviews = {};

      var createOverview = function(level) {
        var id = viz.config.injectInto + '-overviewManager-over' + Math.round(level);

        jQuery('

').css({ width: 50, height: 50 }).appendTo(container);
        return new $NetworkMap.Views.Overview(viz, { injectInto: id }, 0);
      }

      jQuery(viz.canvas.getElement()).bind('redraw', function() {
        // TODO: implement

        // check level
        jQuery.each(viz.config.groupLvls, function(index, level) {
          if (!_overviews[level]) _overviews[level] = createOverview(level);
        });

        // do we need to hide any overviews

        // do we need to add any overviews
      });
    }
  };
})({});

$NetworkMap.Utils.Links = (function() {
  return {
    link: function(nf, nt, id, m) {
      this.nodeFrom = nf;
      this.nodeTo = nt;
      this.id = id;
      this.metrics = m;
    }
  }
})();

$NetworkMap.Utils.Metrics = (function() {
  return {
    data: function(bandwidth, capacity, loss, latency) {
      this.bandwidth = bandwidth;
      this.capacity = capacity;
      this.loss = loss;
      this.latency = latency;
    },

    initJSON: function(json) {
      // create links in both ways
      jQuery.each(json, function(index, n) {
        if (!n.adjacencies) return;
        jQuery.each(n.adjacencies, function(index, adj) {
          if (!adj.data) adj.data = {};
          adj.data.links = [
            new $NetworkMap.Utils.Links.link(n.id, adj.nodeTo, '1'),
            new $NetworkMap.Utils.Links.link(adj.nodeTo, n.id, '1')
          ];
        });
      });
    },

    updateMetrics: function(viz, callback) {
      //TODO: get real data?
      var that = this;

      // update graph metrics
      viz.graph.eachNode(function(n) {
        n.eachAdjacency(function(adj) {

          jQuery.each(adj.data.links, function(index, link) {
            // callback(adj.fromNode, adj.toNode);
            var metrics = new that.data(),
                opts = [ 500, 1000, 2000 ],
                group = Math.random() * 100,
                band;

            if (!adj.data.metrics) metrics.capacity = opts[Math.round(Math.random() * (opts.length - 1))];
            else metrics.capacity = adj.data.metrics.capacity;

            // green
            if (group <= 80) {
              band = 10 + Math.random() * metrics.capacity * 0.20 - 10;

            // yellow
            } else if (group <= 95) {
              band = 10 + Math.random() * metrics.capacity * 0.75 - 10;

            //red
            } else {
              band = 10 + Math.random() * metrics.capacity - 10;
            }

            metrics.bandwidth = band;

            // fill in metrics
            link.data = { metrics: metrics };
          });
        });
      });
    }
  };

})();
<commit_msg>Finished implementing multiple overviews for zooming. TODO: still need to change overview detail as zoom in too.<commit_after>$NetworkMap.Utils = {};
$NetworkMap.Views = {};
$NetworkMap.Debug = {};
$NetworkMap.Json = {};

$NetworkMap.Json = (function() {

  return {
    setStartPositions: function(json, positions) {
      jQuery.each(positions, function(index, val1) {
        jQuery.each(json, function(index, val2) {
          if (val2.id == val1.id) {
            val2.data.pos = { x: Number(val1.x), y: Number(val1.y) };
          }
        });
      });
    }
  };
})();

$NetworkMap.Debug = (function() {

  return {
    GraphicalOutput: function(viz) {
      var _enabled = false;
      var _redraw = true;
      var _container = jQuery(viz.canvas.getElement());
      var _debugBox = jQuery('

');
      var _c = viz.canvas;
      var _frames = 0.0;
      var _fps = 0;
      var _lastTime = new Date();
      var _log = '';

      // redraw debugging information
      _container.bind('redraw', function() {
        _redraw = true;
        output();
      });

      var output = function() {
        var html = '
** Debugging Information **
';
        var table = jQuery('

');
        var str = '';
        var _preventDefault = function(evt) { evt.preventDefault(); };

        if (!_enabled) return;

        // setup styles
        jQuery("")
          .appendTo('head');

        // disable selection on div
        _debugBox.bind("dragstart", _preventDefault).bind("selectstart", _preventDefault);

        // output performance info
        table.append('
Performance
');
        table.append('
Frame Rate:	' + _fps + '
');

        table.append('

');

        // output viz info
        table.append('
State	');
        table.append('
Busy: 	' + viz.busy + '
');
        table.append('
Div id: 	' + viz.config.injectInto + '
');

        table.append('

');

        // output navigational info
        table.append('
Navigation	');
        table.append('
Scale Offset X:	' + _c.scaleOffsetX + '
');
        table.append('
Scale Offset Y:	' + _c.scaleOffsetY + '
');
        table.append('
Translate Offset X:	' + _c.translateOffsetX + '
');
        table.append('
Translate Offset Y:	' + _c.translateOffsetY + '
');

        table.append('

');

        // output depth info
        table.append('
Groups
');
        table.append('
Current Depth:	' + viz.detailLevel(_c.scaleOffsetX, viz.config.groupLvls) + '
');

        _debugBox.html(html).append('
' + _log + '

');
        _debugBox.append(table);

        // draw things onto the canvas
        if (_redraw) {
          // draw node boxes
          viz.graph.eachNode(function(n) {
            var dim = n.getData('dim');
            var pos = n.getPos();
            var canvas = viz.canvas, ctx = canvas.getCtx();

            ctx.save();
            ctx.strokeStyle = 'rgb(255,0,0)';
            ctx.lineWidth = 1 / canvas.scaleOffsetX;
            ctx.strokeRect(pos.x - dim, pos.y - dim, dim * 2, dim * 2);
            ctx.restore();
          });

          _redraw = false;
        }
      };

      var init = function() {
        var o = _container.offset();
        var ms = 10;

        _debugBox.css({
          position: 'relative',
          top: o.top,
          left: o.left,
          color: 'rgb(255,0,0)'
        });

        _container.append(_debugBox);

        _container.bind('redraw', function() {
          var nowTime = new Date();
          var diffTime = Math.ceil((nowTime.getTime() - _lastTime.getTime()));

          if (diffTime >= 1000) {
            _fps = _frames;
            _frames = 0.0;
            _lastTime = nowTime;
            output();
          }

          _frames++;
        });
      };

      init();

      return {
        enable: function() { _enabled = true; output(); },
        disable: function() { _enabled = false; },
        isEnabled: function() { return _enabled; },
        logWrite: function(text) { _log = 'Log: ' + text; output(); }
      };
    }
  };
})();

$NetworkMap.Views = (function() {

  return {
    Overview: function(viz, mapOpts, level) {
      var _opts = jQuery.extend(true, {
        Node: {
          overridable: true,
          dim: 20,
          lineWidth: 5
        },
        Edge: {
          overridable: true,
          color: '#23A4FF',
          lineWidth: 3,
          type: 'line'
        },
        Label: {
          type: 'SVG'
        }
      }, mapOpts);

      var _over = new $jit.NetworkMap(_opts),
          _container = jQuery('#' + _opts.injectInto).css({ position: 'relative' }),
          _svg, _rect,
          _mouse = null,
          _level = level || 0;

      // redraw the rectangle
      var redraw = function() {
        var size = viz.canvas.getSize(),
            p1 = _over.p2c(viz.c2p({ x: 0, y: 0 })),
            p2 = _over.p2c(viz.c2p({ x: size.width, y: size.height }));

        if (!_rect) {
          _rect = _svg.rect(0, 0, 0, 0).attr({ stroke: 'rgb(255,255,0)' });
        }

        _rect.attr({ x: p1.x, y: p1.y, width: Math.abs(p2.x - p1.x), height: Math.abs(p2.y - p1.y) });
        _over.loadPositions(viz.getPositions());
      };

      // translate a main canvas in sync with overview box
      var _moveBox = function(e) {
        var o = _container.offset(),
            x = e.pageX - o.left, y = e.pageY - o.top,
            canvas = viz.canvas,
            size = canvas.getSize(),
            pt1 = _over.c2p({ x: x, y: y }),
            pt2 = viz.c2p({ x: size.width / 2, y: size.height / 2 });

        canvas.translate(pt2.x - pt1.x, pt2.y - pt1.y);
      };

      var hideOver = function() {
        _container.hide();
      };

      var showOver = function() {
        _container.show();
      };

      // setup overview visualisation
      var init = function() {
        var o = _container.offset(),
            vizSize = viz.canvas.getSize(),
            overSize = _over.canvas.getSize(),
            json = jQuery.extend(true, [], viz.json),
            levelScale = viz.config.groupLvls[_level],
            svgcont = jQuery('

')
              .css({ top: 0, left: 0, position: 'absolute' })
              .appendTo(_container);

        _svg = Raphael(svgcont.get(0), overSize.width, overSize.height);

        // remove position data from nodes
        viz.config.layout != 'Static' && jQuery.each(json, function(index, n) {
            n.data && n.data.pos && delete n.data.pos;
        });

        _over.loadJSON(json);
        _over.canvas.resize(overSize.width, overSize.height);
        _over.canvas.scale(overSize.width / vizSize.width, overSize.width / vizSize.width);

        // adjust zoom offset to match the level
        if (_level != 0) {
          _over.canvas.scale(levelScale, levelScale);
        }

        jQuery(viz.canvas.getElement()).bind('redraw', function() {
          var vizSize = viz.canvas.getSize(), overSize = _over.canvas.getSize(),
              vizCp = viz.c2p({ x: vizSize.width / 2, y: vizSize.height / 2 }),
              overCp = _over.c2p({ x: overSize.width / 2, y: overSize.height / 2});

          if (_level != 0 && _mouse == null) {
            _over.canvas.translate(overCp.x - vizCp.x, overCp.y - vizCp.y);
          }

          redraw();
        });

        // setup mouse events
        svgcont.mousedown(function(e) {
          _mouse = e;
          _moveBox(e);
        });
        svgcont.mouseup(function() {
          _mouse = null;
        });
        svgcont.mousemove(function(e) {
          if (_mouse != null) _moveBox(e);
        });

        redraw();
        _over.refresh();
      };

      init();

      return {
        level: function() { return _level; },
        hide: function() { hideOver(); },
        show: function() { showOver(); }
      };
    },

    OverviewManager: function(viz, container, width, height) {
      var _overviews = {};

      var createOverview = function(level) {
        var id = viz.config.injectInto + '-overviewManager-over' + Math.round(level);

        jQuery('

').css({ width: width, height: height }).appendTo(container);
        return new $NetworkMap.Views.Overview(viz, { injectInto: id }, level);
      }

      var updateLevel = function() {
        jQuery.each(_overviews, function(l, over) {
          if (viz.showAtLevel(viz.canvas.scaleOffsetX, over.level(), viz.config.groupLvls)) {
            over.show();
          } else {
            over.hide();
          }
        });
      };

      var init = function() {
        // initialy create and hide overviews
        for (var l = viz.config.groupLvls.length - 1; l >= 0; l--) {
          _overviews[l] = createOverview(l);
          _overviews[l].hide();
        };

        jQuery(viz.canvas.getElement()).bind('redraw', function() {
          updateLevel();
        });

        updateLevel();
      };

      init();
    }
  };
})({});

$NetworkMap.Utils.Links = (function() {
  return {
    link: function(nf, nt, id, m) {
      this.nodeFrom = nf;
      this.nodeTo = nt;
      this.id = id;
      this.metrics = m;
    }
  }
})();

$NetworkMap.Utils.Metrics = (function() {
  return {
    data: function(bandwidth, capacity, loss, latency) {
      this.bandwidth = bandwidth;
      this.capacity = capacity;
      this.loss = loss;
      this.latency = latency;
    },

    initJSON: function(json) {
      // create links in both ways
      jQuery.each(json, function(index, n) {
        if (!n.adjacencies) return;
        jQuery.each(n.adjacencies, function(index, adj) {
          if (!adj.data) adj.data = {};
          adj.data.links = [
            new $NetworkMap.Utils.Links.link(n.id, adj.nodeTo, '1'),
            new $NetworkMap.Utils.Links.link(adj.nodeTo, n.id, '1')
          ];
        });
      });
    },

    updateMetrics: function(viz, callback) {
      //TODO: get real data?
      var that = this;

      // update graph metrics
      viz.graph.eachNode(function(n) {
        n.eachAdjacency(function(adj) {

          jQuery.each(adj.data.links, function(index, link) {
            // callback(adj.fromNode, adj.toNode);
            var metrics = new that.data(),
                opts = [ 500, 1000, 2000 ],
                group = Math.random() * 100,
                band;

            if (!adj.data.metrics) metrics.capacity = opts[Math.round(Math.random() * (opts.length - 1))];
            else metrics.capacity = adj.data.metrics.capacity;

            // green
            if (group <= 80) {
              band = 10 + Math.random() * metrics.capacity * 0.20 - 10;

            // yellow
            } else if (group <= 95) {
              band = 10 + Math.random() * metrics.capacity * 0.75 - 10;

            //red
            } else {
              band = 10 + Math.random() * metrics.capacity - 10;
            }

            metrics.bandwidth = band;

            // fill in metrics
            link.data = { metrics: metrics };
          });
        });
      });
    }
  };

})();
<|endoftext|>


<commit_before>import jiff from 'jiff';
import moment from 'moment';

import clone from 'lodash.clone';
import pluck from 'lodash.pluck';

import angular from 'angular';

var hiddenKeyRegex = /^\$+/;

var TIMESTAMP_RE = /^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d)$/;

export function convertJsonDates(jsonData) {
  var outObj;
  if (Array.isArray(jsonData)) {
    outObj = [];
  } else {
    outObj = {};
  }
  for (var key in jsonData) {
    var val = jsonData[key];
    var res = val;
    if (angular.isString(val)) {
      // The value is a string - does it match any of our things we want to convert
      if (TIMESTAMP_RE.test(val)) {
        // We're probably a timestamp
        var dt = moment(val);
        if (dt.isValid()) {
          res = dt.toDate();
        }
      }
    } else if (Array.isArray(val) || angular.isObject(val)) {
      res = convertJsonDates(val);
    }

    outObj[key] = res;
  }

  return outObj;
}

export function toJSON(obj) {
  return JSON.parse(JSON.stringify(obj));
}

export function diff(obj1, obj2) {
  obj1 = toJSON(obj1);
  obj2 = toJSON(obj2);

  return jiff.diff(obj1, obj2);
}

export function applyPatch(res, patch) {
  // Go to JSON - don't do anything with dates
  var obj = JSON.parse(JSON.stringify(res, toJsonReplacer));
  obj = jiff.patch(patch, obj);

  // Go back to dates etc
  obj = convertJsonDates(obj);

  removeResValues(res);
  setResValues(res, obj);
}

export function mergeObjects(mine, old, yours) {

  // Make copies - we might modify the objects if ids dont exist
  mine = clone(mine);
  old = clone(old);

  // First sort out _id's. We could have a new id if one doesn't exist on mine and old
  if (!mine._id && !old._id && yours._id) {
    mine._id = yours._id;
    old._id = yours._id;
  }

  // We also need to convert into and out of dates
  mine = toJSON(mine);
  old = toJSON(old);
  yours = toJSON(yours);

  var yourpatch = jiff.diff(old, yours);
  var mypatch = jiff.diff(old, mine);

  var mypaths = pluck(mypatch, 'path');
  var patch = yourpatch.filter(function(patchval) {
    return !~mypaths.indexOf(patchval.path);
  });

  var patched = jiff.patch(patch, mine);
  return convertJsonDates(patched);
}

export function forEachVal(res, cb) {
  for (var key in res) {
    if (!hiddenKeyRegex.test(key)) {
      if (!cb(res, key)) {
        break;
      }
    }
  }
}

export function toJsonReplacer(key, value) {
  var val = value;
  if (angular.isString(key) && key.charAt(0) === '$') {
    val = undefined;
  }

  return val;
}

export function fromJsonReviver(key, value) {
  var val = value;
  if (angular.isString(value) && TIMESTAMP_RE.test(value)) {
    var dt = moment(value);
    if (dt.isValid()) {
      val = dt.toDate();
    }
  }

  return val;
}

export function toObject(res) {
  // The toJsonReplacer gets rid of attributes beginning with $ and the fromJsonReviver
  // converts date strings back into dates
  var str = JSON.stringify(res, toJsonReplacer);

  try {
    return JSON.parse(str, fromJsonReviver);
  } catch (err) {
    // Older versions of IE8 throw 'Out of stack space' errors if we use a reviver function
    // due to the bug described here: http://support.microsoft.com/kb/976662. Everyone hates
    // IE
    if (err.message === 'Out of stack space') {
      return convertJsonDates(JSON.parse(str));
    }

    throw(err);
  }
}

export function removeResValues(res) {
  forEachVal(res, function(val, key) {
    delete res[key];
  });
}

export function setResValues(res, vals){
  for (var key in vals) {
    res[key] = vals[key];
  }
}

export function persistentStorageKey(url) {
  return 'or2ws:' + url;
}

export function advancedStorage($localForage) {
  return $localForage.driver() !== 'localStorageWrapper';
}

// lifted from here -> http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
export function uuid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}
<commit_msg>dont break out of loop early<commit_after>import jiff from 'jiff';
import moment from 'moment';

import clone from 'lodash.clone';
import pluck from 'lodash.pluck';

import angular from 'angular';

var hiddenKeyRegex = /^\$+/;

var TIMESTAMP_RE = /^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d)$/;

export function convertJsonDates(jsonData) {
  var outObj;
  if (Array.isArray(jsonData)) {
    outObj = [];
  } else {
    outObj = {};
  }
  for (var key in jsonData) {
    var val = jsonData[key];
    var res = val;
    if (angular.isString(val)) {
      // The value is a string - does it match any of our things we want to convert
      if (TIMESTAMP_RE.test(val)) {
        // We're probably a timestamp
        var dt = moment(val);
        if (dt.isValid()) {
          res = dt.toDate();
        }
      }
    } else if (Array.isArray(val) || angular.isObject(val)) {
      res = convertJsonDates(val);
    }

    outObj[key] = res;
  }

  return outObj;
}

export function toJSON(obj) {
  return JSON.parse(JSON.stringify(obj));
}

export function diff(obj1, obj2) {
  obj1 = toJSON(obj1);
  obj2 = toJSON(obj2);

  return jiff.diff(obj1, obj2);
}

export function applyPatch(res, patch) {
  // Go to JSON - don't do anything with dates
  var obj = JSON.parse(JSON.stringify(res, toJsonReplacer));
  obj = jiff.patch(patch, obj);

  // Go back to dates etc
  obj = convertJsonDates(obj);

  removeResValues(res);
  setResValues(res, obj);
}

export function mergeObjects(mine, old, yours) {

  // Make copies - we might modify the objects if ids dont exist
  mine = clone(mine);
  old = clone(old);

  // First sort out _id's. We could have a new id if one doesn't exist on mine and old
  if (!mine._id && !old._id && yours._id) {
    mine._id = yours._id;
    old._id = yours._id;
  }

  // We also need to convert into and out of dates
  mine = toJSON(mine);
  old = toJSON(old);
  yours = toJSON(yours);

  var yourpatch = jiff.diff(old, yours);
  var mypatch = jiff.diff(old, mine);

  var mypaths = pluck(mypatch, 'path');
  var patch = yourpatch.filter(function(patchval) {
    return !~mypaths.indexOf(patchval.path);
  });

  var patched = jiff.patch(patch, mine);
  return convertJsonDates(patched);
}

export function forEachVal(res, cb) {
  for (var key in res) {
    if (!hiddenKeyRegex.test(key)) {
      cb(res, key);
    }
  }
}

export function toJsonReplacer(key, value) {
  var val = value;
  if (angular.isString(key) && key.charAt(0) === '$') {
    val = undefined;
  }

  return val;
}

export function fromJsonReviver(key, value) {
  var val = value;
  if (angular.isString(value) && TIMESTAMP_RE.test(value)) {
    var dt = moment(value);
    if (dt.isValid()) {
      val = dt.toDate();
    }
  }

  return val;
}

export function toObject(res) {
  // The toJsonReplacer gets rid of attributes beginning with $ and the fromJsonReviver
  // converts date strings back into dates
  var str = JSON.stringify(res, toJsonReplacer);

  try {
    return JSON.parse(str, fromJsonReviver);
  } catch (err) {
    // Older versions of IE8 throw 'Out of stack space' errors if we use a reviver function
    // due to the bug described here: http://support.microsoft.com/kb/976662. Everyone hates
    // IE
    if (err.message === 'Out of stack space') {
      return convertJsonDates(JSON.parse(str));
    }

    throw(err);
  }
}

export function removeResValues(res) {
  forEachVal(res, function(val, key) {
    delete res[key];
  });
}

export function setResValues(res, vals){
  for (var key in vals) {
    res[key] = vals[key];
  }
}

export function persistentStorageKey(url) {
  return 'or2ws:' + url;
}

export function advancedStorage($localForage) {
  return $localForage.driver() !== 'localStorageWrapper';
}

// lifted from here -> http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
export function uuid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}
<|endoftext|>


<commit_before>export const checkFields = function checkFields(data, res, fields = [], types = []) {
  const errors = [];
  const fieldLen = fields.length;
  let typeLen = 0;

  // this will avoid redundancy when you have an array of fields of the same type
  if (Array.isArray(types)) {
    typeLen = types.length;
  } else if (typeof types === 'string') {
    typeLen = -1;
  }

  for (let i = 0; i < fieldLen; i++) {
    if (typeof data[fields[i]] === 'undefined') {
      errors.push(`${fields[i]} is not set`);
      continue;
    }

    if (typeLen > i) {
      if (typeof data[fields[i]] !== types[i]) {
        errors.push(`${data[fields[i]]} has to be of type ${types[i]}`);
      }
    } else if (typeLen === -1) {
      if (typeof data[fields[i]] !== types) {
        errors.push(`${data[fields[i]]} has to be of type ${types}`);
      }
    }
  }

  if (errors.length > 0) {
    res.status(422).json(errors.join(', '));
    return false;
  }
  return true;
};

export const escape = function escape(str) {
  if (str) return str.replace('$', '\uFF04').replace('.', '\uFF0E');
  return null;
};

export const handleDuplicate = function handleDuplicate(res, str, fields) {
  for (let i = fields.length - 1; i >= 0; i--) {
    if (str.includes(fields[i])) {
      res.status(422).json(`${fields[i]} is already in use`);
      return true;
    }
  }
  return false;
};

export const split = function split(arr, size) {
  if (!Array.isArray(arr)) return [];

  const length = arr.length;
  const chunks = [];

  for (let i = 0; i < length; i += size) {
    chunks.push(arr.slice(i, size));
  }

  return chunks;
};

export default checkFields;
<commit_msg>add paginate function<commit_after>export const checkFields = function checkFields(data, res, fields = [], types = []) {
  const errors = [];
  const fieldLen = fields.length;
  let typeLen = 0;

  // this will avoid redundancy when you have an array of fields of the same type
  if (Array.isArray(types)) {
    typeLen = types.length;
  } else if (typeof types === 'string') {
    typeLen = -1;
  }

  for (let i = 0; i < fieldLen; i++) {
    if (typeof data[fields[i]] === 'undefined') {
      errors.push(`${fields[i]} is not set`);
      continue;
    }

    if (typeLen > i) {
      if (typeof data[fields[i]] !== types[i]) {
        errors.push(`${data[fields[i]]} has to be of type ${types[i]}`);
      }
    } else if (typeLen === -1) {
      if (typeof data[fields[i]] !== types) {
        errors.push(`${data[fields[i]]} has to be of type ${types}`);
      }
    }
  }

  if (errors.length > 0) {
    res.status(422).json(errors.join(', '));
    return false;
  }
  return true;
};

export const escape = function escape(str) {
  if (str) return str.replace('$', '\uFF04').replace('.', '\uFF0E');
  return null;
};

export const handleDuplicate = function handleDuplicate(res, str, fields) {
  for (let i = fields.length - 1; i >= 0; i--) {
    if (str.includes(fields[i])) {
      res.status(422).json(`${fields[i]} is already in use`);
      return true;
    }
  }
  return false;
};

export const split = function split(arr, size) {
  if (!Array.isArray(arr)) return [];

  const length = arr.length;
  const chunks = [];

  for (let i = 0; i < length; i += size) {
    chunks.push(arr.slice(i, size));
  }

  return chunks;
};

export const paginate = function paginate(page, size, data, err = null) {
  return {
    'page': page,
    'size': size,
    'result': data,
    'error': err
  };
};

export default checkFields;
<|endoftext|>


<commit_before>import { defaultColumn, emptyRenderer } from './publicUtils'

// Find the depth of the columns
export function findMaxDepth(columns, depth = 0) {
  return columns.reduce((prev, curr) => {
    if (curr.columns) {
      return Math.max(prev, findMaxDepth(curr.columns, depth + 1))
    }
    return depth
  }, 0)
}

// Build the visible columns, headers and flat column list
export function linkColumnStructure(columns, parent, depth = 0) {
  return columns.map(column => {
    column = {
      ...column,
      parent,
      depth,
    }

    assignColumnAccessor(column)

    if (column.columns) {
      column.columns = linkColumnStructure(column.columns, column, depth + 1)
    }
    return column
  })
}

export function flattenColumns(columns) {
  return flattenBy(columns, 'columns')
}

export function assignColumnAccessor(column) {
  // First check for string accessor
  let { id, accessor, Header } = column

  if (typeof accessor === 'string') {
    id = id || accessor
    const accessorPath = accessor.split('.')
    accessor = row => getBy(row, accessorPath)
  }

  if (!id && typeof Header === 'string' && Header) {
    id = Header
  }

  if (!id && column.columns) {
    console.error(column)
    throw new Error('A column ID (or unique "Header" value) is required!')
  }

  if (!id) {
    console.error(column)
    throw new Error('A column ID (or string accessor) is required!')
  }

  Object.assign(column, {
    id,
    accessor,
  })

  return column
}

export function decorateColumn(column, userDefaultColumn) {
  if (!userDefaultColumn) {
    throw new Error()
  }
  Object.assign(column, {
    // Make sure there is a fallback header, just in case
    Header: emptyRenderer,
    Footer: emptyRenderer,
    ...defaultColumn,
    ...userDefaultColumn,
    ...column,
  })

  Object.assign(column, {
    originalWidth: column.width,
  })

  return column
}

// Build the header groups from the bottom up
export function makeHeaderGroups(
  allColumns,
  defaultColumn,
  additionalHeaderProperties = () => ({})
) {
  const headerGroups = []

  let scanColumns = allColumns

  let uid = 0
  const getUID = () => uid++

  while (scanColumns.length) {
    // The header group we are creating
    const headerGroup = {
      headers: [],
    }

    // The parent columns we're going to scan next
    const parentColumns = []

    const hasParents = scanColumns.some(d => d.parent)

    // Scan each column for parents
    scanColumns.forEach(column => {
      // What is the latest (last) parent column?
      let latestParentColumn = [...parentColumns].reverse()[0]

      let newParent

      if (hasParents) {
        // If the column has a parent, add it if necessary
        if (column.parent) {
          newParent = {
            ...column.parent,
            originalId: column.parent.id,
            id: `${column.parent.id}_${getUID()}`,
            headers: [column],
            ...additionalHeaderProperties(column),
          }
        } else {
          // If other columns have parents, we'll need to add a place holder if necessary
          const originalId = `${column.id}_placeholder`
          newParent = decorateColumn(
            {
              originalId,
              id: `${column.id}_placeholder_${getUID()}`,
              placeholderOf: column,
              headers: [column],
              ...additionalHeaderProperties(column),
            },
            defaultColumn
          )
        }

        // If the resulting parent columns are the same, just add
        // the column and increment the header span
        if (
          latestParentColumn &&
          latestParentColumn.originalId === newParent.originalId
        ) {
          latestParentColumn.headers.push(column)
        } else {
          parentColumns.push(newParent)
        }
      }

      headerGroup.headers.push(column)
    })

    headerGroups.push(headerGroup)

    // Start scanning the parent columns
    scanColumns = parentColumns
  }

  return headerGroups.reverse()
}

const pathObjCache = new Map()

export function getBy(obj, path, def) {
  if (!path) {
    return obj
  }
  const cacheKey = typeof path === 'function' ? path : JSON.stringify(path)

  const pathObj =
    pathObjCache.get(cacheKey) ||
    (() => {
      const pathObj = makePathArray(path)
      pathObjCache.set(cacheKey, pathObj)
      return pathObj
    })()

  let val

  try {
    val = pathObj.reduce((cursor, pathPart) => cursor[pathPart], obj)
  } catch (e) {
    // continue regardless of error
  }
  return typeof val !== 'undefined' ? val : def
}

export function getFirstDefined(...args) {
  for (let i = 0; i < args.length; i += 1) {
    if (typeof args[i] !== 'undefined') {
      return args[i]
    }
  }
}

export function getElementDimensions(element) {
  const rect = element.getBoundingClientRect()
  const style = window.getComputedStyle(element)
  const margins = {
    left: parseInt(style.marginLeft),
    right: parseInt(style.marginRight),
  }
  const padding = {
    left: parseInt(style.paddingLeft),
    right: parseInt(style.paddingRight),
  }
  return {
    left: Math.ceil(rect.left),
    width: Math.ceil(rect.width),
    outerWidth: Math.ceil(
      rect.width + margins.left + margins.right + padding.left + padding.right
    ),
    marginLeft: margins.left,
    marginRight: margins.right,
    paddingLeft: padding.left,
    paddingRight: padding.right,
    scrollWidth: element.scrollWidth,
  }
}

export function isFunction(a) {
  if (typeof a === 'function') {
    return a
  }
}

export function flattenBy(arr, key) {
  const flat = []

  const recurse = arr => {
    arr.forEach(d => {
      if (!d[key]) {
        flat.push(d)
      } else {
        recurse(d[key])
      }
    })
  }

  recurse(arr)

  return flat
}

function expandRows(
	rows,
	{ manualExpandedKey, expanded, expandSubRows = true }
) {
	const expandedRows = [];

	const handleRow = (row, addToExpandedRows = true) => {
		row.isExpanded =
			(row.original && row.original[manualExpandedKey]) || expanded[row.id];

		row.canExpand = row.subRows && !!row.subRows.length;

		if (addToExpandedRows) {
			expandedRows.push(row);
		}

		if (row.subRows && row.subRows.length && row.isExpanded) {
			row.subRows.forEach((row) => handleRow(row, expandSubRows));
		}
	};

	rows.forEach((row) => handleRow(row));

	console.log("foidn");
	rows.forEach((row) => console.log("---row", row));
	return expandedRows;
}

export function getFilterMethod(filter, userFilterTypes, filterTypes) {
  return (
    isFunction(filter) ||
    userFilterTypes[filter] ||
    filterTypes[filter] ||
    filterTypes.text
  )
}

export function shouldAutoRemoveFilter(autoRemove, value, column) {
  return autoRemove ? autoRemove(value, column) : typeof value === 'undefined'
}

export function unpreparedAccessWarning() {
  throw new Error(
    'React-Table: You have not called prepareRow(row) one or more rows you are attempting to render.'
  )
}

let passiveSupported = null
export function passiveEventSupported() {
  // memoize support to avoid adding multiple test events
  if (typeof passiveSupported === 'boolean') return passiveSupported

  let supported = false
  try {
    const options = {
      get passive() {
        supported = true
        return false
      },
    }

    window.addEventListener('test', null, options)
    window.removeEventListener('test', null, options)
  } catch (err) {
    supported = false
  }
  passiveSupported = supported
  return passiveSupported
}

//

const reOpenBracket = /\[/g
const reCloseBracket = /\]/g

function makePathArray(obj) {
  return (
    flattenDeep(obj)
      // remove all periods in parts
      .map(d => String(d).replace('.', '_'))
      // join parts using period
      .join('.')
      // replace brackets with periods
      .replace(reOpenBracket, '.')
      .replace(reCloseBracket, '')
      // split it back out on periods
      .split('.')
  )
}

function flattenDeep(arr, newArr = []) {
  if (!Array.isArray(arr)) {
    newArr.push(arr)
  } else {
    for (let i = 0; i < arr.length; i += 1) {
      flattenDeep(arr[i], newArr)
    }
  }
  return newArr
}
<commit_msg>fix(utils): Add recently removed export statement (#2764)<commit_after>import { defaultColumn, emptyRenderer } from './publicUtils'

// Find the depth of the columns
export function findMaxDepth(columns, depth = 0) {
  return columns.reduce((prev, curr) => {
    if (curr.columns) {
      return Math.max(prev, findMaxDepth(curr.columns, depth + 1))
    }
    return depth
  }, 0)
}

// Build the visible columns, headers and flat column list
export function linkColumnStructure(columns, parent, depth = 0) {
  return columns.map(column => {
    column = {
      ...column,
      parent,
      depth,
    }

    assignColumnAccessor(column)

    if (column.columns) {
      column.columns = linkColumnStructure(column.columns, column, depth + 1)
    }
    return column
  })
}

export function flattenColumns(columns) {
  return flattenBy(columns, 'columns')
}

export function assignColumnAccessor(column) {
  // First check for string accessor
  let { id, accessor, Header } = column

  if (typeof accessor === 'string') {
    id = id || accessor
    const accessorPath = accessor.split('.')
    accessor = row => getBy(row, accessorPath)
  }

  if (!id && typeof Header === 'string' && Header) {
    id = Header
  }

  if (!id && column.columns) {
    console.error(column)
    throw new Error('A column ID (or unique "Header" value) is required!')
  }

  if (!id) {
    console.error(column)
    throw new Error('A column ID (or string accessor) is required!')
  }

  Object.assign(column, {
    id,
    accessor,
  })

  return column
}

export function decorateColumn(column, userDefaultColumn) {
  if (!userDefaultColumn) {
    throw new Error()
  }
  Object.assign(column, {
    // Make sure there is a fallback header, just in case
    Header: emptyRenderer,
    Footer: emptyRenderer,
    ...defaultColumn,
    ...userDefaultColumn,
    ...column,
  })

  Object.assign(column, {
    originalWidth: column.width,
  })

  return column
}

// Build the header groups from the bottom up
export function makeHeaderGroups(
  allColumns,
  defaultColumn,
  additionalHeaderProperties = () => ({})
) {
  const headerGroups = []

  let scanColumns = allColumns

  let uid = 0
  const getUID = () => uid++

  while (scanColumns.length) {
    // The header group we are creating
    const headerGroup = {
      headers: [],
    }

    // The parent columns we're going to scan next
    const parentColumns = []

    const hasParents = scanColumns.some(d => d.parent)

    // Scan each column for parents
    scanColumns.forEach(column => {
      // What is the latest (last) parent column?
      let latestParentColumn = [...parentColumns].reverse()[0]

      let newParent

      if (hasParents) {
        // If the column has a parent, add it if necessary
        if (column.parent) {
          newParent = {
            ...column.parent,
            originalId: column.parent.id,
            id: `${column.parent.id}_${getUID()}`,
            headers: [column],
            ...additionalHeaderProperties(column),
          }
        } else {
          // If other columns have parents, we'll need to add a place holder if necessary
          const originalId = `${column.id}_placeholder`
          newParent = decorateColumn(
            {
              originalId,
              id: `${column.id}_placeholder_${getUID()}`,
              placeholderOf: column,
              headers: [column],
              ...additionalHeaderProperties(column),
            },
            defaultColumn
          )
        }

        // If the resulting parent columns are the same, just add
        // the column and increment the header span
        if (
          latestParentColumn &&
          latestParentColumn.originalId === newParent.originalId
        ) {
          latestParentColumn.headers.push(column)
        } else {
          parentColumns.push(newParent)
        }
      }

      headerGroup.headers.push(column)
    })

    headerGroups.push(headerGroup)

    // Start scanning the parent columns
    scanColumns = parentColumns
  }

  return headerGroups.reverse()
}

const pathObjCache = new Map()

export function getBy(obj, path, def) {
  if (!path) {
    return obj
  }
  const cacheKey = typeof path === 'function' ? path : JSON.stringify(path)

  const pathObj =
    pathObjCache.get(cacheKey) ||
    (() => {
      const pathObj = makePathArray(path)
      pathObjCache.set(cacheKey, pathObj)
      return pathObj
    })()

  let val

  try {
    val = pathObj.reduce((cursor, pathPart) => cursor[pathPart], obj)
  } catch (e) {
    // continue regardless of error
  }
  return typeof val !== 'undefined' ? val : def
}

export function getFirstDefined(...args) {
  for (let i = 0; i < args.length; i += 1) {
    if (typeof args[i] !== 'undefined') {
      return args[i]
    }
  }
}

export function getElementDimensions(element) {
  const rect = element.getBoundingClientRect()
  const style = window.getComputedStyle(element)
  const margins = {
    left: parseInt(style.marginLeft),
    right: parseInt(style.marginRight),
  }
  const padding = {
    left: parseInt(style.paddingLeft),
    right: parseInt(style.paddingRight),
  }
  return {
    left: Math.ceil(rect.left),
    width: Math.ceil(rect.width),
    outerWidth: Math.ceil(
      rect.width + margins.left + margins.right + padding.left + padding.right
    ),
    marginLeft: margins.left,
    marginRight: margins.right,
    paddingLeft: padding.left,
    paddingRight: padding.right,
    scrollWidth: element.scrollWidth,
  }
}

export function isFunction(a) {
  if (typeof a === 'function') {
    return a
  }
}

export function flattenBy(arr, key) {
  const flat = []

  const recurse = arr => {
    arr.forEach(d => {
      if (!d[key]) {
        flat.push(d)
      } else {
        recurse(d[key])
      }
    })
  }

  recurse(arr)

  return flat
}

export function expandRows(
  rows,
  { manualExpandedKey, expanded, expandSubRows = true }
) {
  const expandedRows = []

  const handleRow = (row, addToExpandedRows = true) => {
    row.isExpanded =
      (row.original && row.original[manualExpandedKey]) || expanded[row.id]

    row.canExpand = row.subRows && !!row.subRows.length

    if (addToExpandedRows) {
      expandedRows.push(row)
    }

    if (row.subRows && row.subRows.length && row.isExpanded) {
      row.subRows.forEach(row => handleRow(row, expandSubRows))
    }
  }

  rows.forEach(row => handleRow(row))

  return expandedRows
}

export function getFilterMethod(filter, userFilterTypes, filterTypes) {
  return (
    isFunction(filter) ||
    userFilterTypes[filter] ||
    filterTypes[filter] ||
    filterTypes.text
  )
}

export function shouldAutoRemoveFilter(autoRemove, value, column) {
  return autoRemove ? autoRemove(value, column) : typeof value === 'undefined'
}

export function unpreparedAccessWarning() {
  throw new Error(
    'React-Table: You have not called prepareRow(row) one or more rows you are attempting to render.'
  )
}

let passiveSupported = null
export function passiveEventSupported() {
  // memoize support to avoid adding multiple test events
  if (typeof passiveSupported === 'boolean') return passiveSupported

  let supported = false
  try {
    const options = {
      get passive() {
        supported = true
        return false
      },
    }

    window.addEventListener('test', null, options)
    window.removeEventListener('test', null, options)
  } catch (err) {
    supported = false
  }
  passiveSupported = supported
  return passiveSupported
}

//

const reOpenBracket = /\[/g
const reCloseBracket = /\]/g

function makePathArray(obj) {
  return (
    flattenDeep(obj)
      // remove all periods in parts
      .map(d => String(d).replace('.', '_'))
      // join parts using period
      .join('.')
      // replace brackets with periods
      .replace(reOpenBracket, '.')
      .replace(reCloseBracket, '')
      // split it back out on periods
      .split('.')
  )
}

function flattenDeep(arr, newArr = []) {
  if (!Array.isArray(arr)) {
    newArr.push(arr)
  } else {
    for (let i = 0; i < arr.length; i += 1) {
      flattenDeep(arr[i], newArr)
    }
  }
  return newArr
}
<|endoftext|>


<commit_before>define([
    "jquery"
], function($) {
    var jquery_plugin = function(pattern) {
        var plugin = function(method) {
            var $this = this;
            if ($this.length === 0)
                return $this;
            if (!method || typeof method === "object") {
                pattern.init.apply(
                    $this,
                    [$this].concat(Array.prototype.slice.call(arguments)));
            } else if (pattern[method]) {
                return pattern[method].apply(
                    $this,
                    [$this].concat(Array.prototype.slice.call(arguments, 1))
                );
            } else {
                $.error("Method " + method +
                        " does not exist on jQuery." + pattern.name);
            }
            return $this;
        };
        return plugin;
    };

    //     Underscore.js 1.3.1
    //     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
    //     Underscore is freely distributable under the MIT license.
    //     Portions of Underscore are inspired or borrowed from Prototype,
    //     Oliver Steele's Functional, and John Resig's Micro-Templating.
    //     For all details and documentation:
    //     http://documentcloud.github.com/underscore
    //
    // Returns a function, that, as long as it continues to be invoked, will not
    // be triggered. The function will be called after it stops being called for
    // N milliseconds.
    var debounce = function(func, wait) {
        var timeout;
        return function() {
            var context = this, args = arguments;
            var later = function() {
                timeout = null;
                func.apply(context, args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    };

    var rebaseURL = function(base, url) {
        if (url.indexOf("://")!==-1 || url[0]==="/")
            return url;
        return base.slice(0, base.lastIndexOf("/")+1) + url;
    };

    function findLabel(input) {
        for (var label=input.parentNode; label && label.nodeType!==11; label=label.parentNode)
            if (label.tagName==="LABEL")
                return label;

        var $label;

        if (input.id)
            $label = $("label[for="+input.id+"]");
        if ($label && $label.length===0 && input.form)
            $label = $("label[for="+input.name+"]", input.form);
        if ($label && $label.length)
            return $label[0];
        else
            return null;
    }

    // Taken from http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
    var escapeRegExp = function(str) {
        return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    };

    var utils = {
        // pattern pimping - own module?
        jquery_plugin: jquery_plugin,
        debounce: debounce,
        escapeRegExp: escapeRegExp,
        rebaseURL: rebaseURL,
        findLabel: findLabel
    };

    return utils;
});
<commit_msg>No need for the odd variable here.<commit_after>define([
    "jquery"
], function($) {
    var jquery_plugin = function(pattern) {
        var plugin = function(method) {
            var $this = this;
            if ($this.length === 0)
                return $this;
            if (!method || typeof method === "object") {
                pattern.init.apply(
                    $this,
                    [$this].concat(Array.prototype.slice.call(arguments)));
            } else if (pattern[method]) {
                return pattern[method].apply(
                    $this,
                    [$this].concat(Array.prototype.slice.call(arguments, 1))
                );
            } else {
                $.error("Method " + method +
                        " does not exist on jQuery." + pattern.name);
            }
            return $this;
        };
        return plugin;
    };

    //     Underscore.js 1.3.1
    //     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
    //     Underscore is freely distributable under the MIT license.
    //     Portions of Underscore are inspired or borrowed from Prototype,
    //     Oliver Steele's Functional, and John Resig's Micro-Templating.
    //     For all details and documentation:
    //     http://documentcloud.github.com/underscore
    //
    // Returns a function, that, as long as it continues to be invoked, will not
    // be triggered. The function will be called after it stops being called for
    // N milliseconds.
    var debounce = function(func, wait) {
        var timeout;
        return function() {
            var context = this, args = arguments;
            var later = function() {
                timeout = null;
                func.apply(context, args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    };

    var rebaseURL = function(base, url) {
        if (url.indexOf("://")!==-1 || url[0]==="/")
            return url;
        return base.slice(0, base.lastIndexOf("/")+1) + url;
    };

    function findLabel(input) {
        for (var label=input.parentNode; label && label.nodeType!==11; label=label.parentNode)
            if (label.tagName==="LABEL")
                return label;

        var $label;

        if (input.id)
            $label = $("label[for="+input.id+"]");
        if ($label && $label.length===0 && input.form)
            $label = $("label[for="+input.name+"]", input.form);
        if ($label && $label.length)
            return $label[0];
        else
            return null;
    }

    // Taken from http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
    function escapeRegExp(str) {
        return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    }

    var utils = {
        // pattern pimping - own module?
        jquery_plugin: jquery_plugin,
        debounce: debounce,
        escapeRegExp: escapeRegExp,
        rebaseURL: rebaseURL,
        findLabel: findLabel
    };

    return utils;
});
<|endoftext|>


<commit_before>import isPlainObject from 'lodash/isPlainObject'
import Vue from 'vue'

const ObjProto = Object.prototype
const toString = ObjProto.toString
export const hasOwn = ObjProto.hasOwnProperty

const FN_MATCH_REGEXP = /^\s*function (\w+)/

// https://github.com/vuejs/vue/blob/dev/src/core/util/props.js#L177
export const getType = (fn) => {
  const type = fn !== null && fn !== undefined ? (fn.type ? fn.type : fn) : null
  const match = type && type.toString().match(FN_MATCH_REGEXP)
  return match && match[1]
}

export const getNativeType = (value) => {
  if (value === null || value === undefined) return null
  const match = value.constructor.toString().match(FN_MATCH_REGEXP)
  return match && match[1]
}

/**
 * No-op function
 */
export const noop = () => {}

/**
 * Checks for a own property in an object
 *
 * @param {object} obj - Object
 * @param {string} prop - Property to check
 */
export const has = (obj, prop) => hasOwn.call(obj, prop)

/**
 * Determines whether the passed value is an integer. Uses `Number.isInteger` if available
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
 * @param {*} value - The value to be tested for being an integer.
 * @returns {boolean}
 */
export const isInteger =
  Number.isInteger ||
  function(value) {
    return (
      typeof value === 'number' &&
      isFinite(value) &&
      Math.floor(value) === value
    )
  }

/**
 * Determines whether the passed value is an Array.
 *
 * @param {*} value - The value to be tested for being an array.
 * @returns {boolean}
 */
export const isArray =
  Array.isArray ||
  function(value) {
    return toString.call(value) === '[object Array]'
  }

/**
 * Checks if a value is a function
 *
 * @param {any} value - Value to check
 * @returns {boolean}
 */
export const isFunction = (value) =>
  toString.call(value) === '[object Function]'

/**
 * Adds a `def` method to the object returning a new object with passed in argument as `default` property
 *
 * @param {object} type - Object to enhance
 * @returns {object} the passed-in prop type
 */
export const withDefault = function(type) {
  return Object.defineProperty(type, 'def', {
    value(def) {
      if (def === undefined && !this.default) {
        return this
      }
      if (!isFunction(def) && !validateType(this, def)) {
        warn(`${this._vueTypes_name} - invalid default value: "${def}"`, def)
        return this
      }
      if (isArray(def)) {
        this.default = () => [...def]
      } else if (isPlainObject(def)) {
        this.default = () => Object.assign({}, def)
      } else {
        this.default = def
      }
      return this
    },
    enumerable: false,
    writable: false,
  })
}

/**
 * Adds a `isRequired` getter returning a new object with `required: true` key-value
 *
 * @param {object} type - Object to enhance
 * @returns {object} the passed-in prop type
 */
export const withRequired = function(type) {
  return Object.defineProperty(type, 'isRequired', {
    get() {
      this.required = true
      return this
    },
    enumerable: false,
  })
}

/**
 * Adds a validate method useful to set the prop `validator` function.
 *
 * @param {object} type Prop type to extend
 * @returns {object} the passed-in prop type
 */
export const withValidate = function(type) {
  return Object.defineProperty(type, 'validate', {
    value(fn) {
      this.validator = fn.bind(this)
      return this
    },
    enumerable: false,
  })
}

/**
 * Adds `isRequired` and `def` modifiers to an object
 *
 * @param {string} name - Type internal name
 * @param {object} obj - Object to enhance
 * @returns {object}
 */
export const toType = (name, obj, validateFn = false) => {
  Object.defineProperty(obj, '_vueTypes_name', {
    enumerable: false,
    writable: false,
    value: name,
  })

  withDefault(withRequired(obj))

  if (validateFn) {
    withValidate(obj)
  }

  if (isFunction(obj.validator)) {
    obj.validator = obj.validator.bind(obj)
  }
  return obj
}

/**
 * Validates a given value against a prop type object
 *
 * @param {Object|*} type - Type to use for validation. Either a type object or a constructor
 * @param {*} value - Value to check
 * @param {boolean} silent - Silence warnings
 * @returns {boolean}
 */
export const validateType = (type, value, silent = false) => {
  let typeToCheck = type
  let valid = true
  let expectedType
  if (!isPlainObject(type)) {
    typeToCheck = { type }
  }
  const namePrefix = typeToCheck._vueTypes_name
    ? typeToCheck._vueTypes_name + ' - '
    : ''

  if (hasOwn.call(typeToCheck, 'type') && typeToCheck.type !== null) {
    if (isArray(typeToCheck.type)) {
      valid = typeToCheck.type.some((type) => validateType(type, value, true))
      expectedType = typeToCheck.type.map((type) => getType(type)).join(' or ')
    } else {
      expectedType = getType(typeToCheck)

      if (expectedType === 'Array') {
        valid = isArray(value)
      } else if (expectedType === 'Object') {
        valid = isPlainObject(value)
      } else if (
        expectedType === 'String' ||
        expectedType === 'Number' ||
        expectedType === 'Boolean' ||
        expectedType === 'Function'
      ) {
        valid = getNativeType(value) === expectedType
      } else {
        valid = value instanceof typeToCheck.type
      }
    }
  }

  if (!valid) {
    silent === false &&
      warn(`${namePrefix}value "${value}" should be of type "${expectedType}"`)
    return false
  }

  if (
    hasOwn.call(typeToCheck, 'validator') &&
    isFunction(typeToCheck.validator)
  ) {
    // swallow warn
    let oldWarn
    if (silent) {
      oldWarn = warn
      warn = noop
    }

    valid = typeToCheck.validator(value)
    oldWarn && (warn = oldWarn)

    if (!valid && silent === false)
      warn(`${namePrefix}custom validation failed`)
    return valid
  }
  return valid
}

let warn = noop

if (process.env.NODE_ENV !== 'production') {
  const hasConsole = typeof console !== 'undefined'
  warn = hasConsole
    ? (msg) => {
        // eslint-disable-next-line no-console
        Vue.config.silent === false && console.warn(`[VueTypes warn]: ${msg}`)
      }
    : noop
}

export { warn }
<commit_msg>refactor<commit_after>import isPlainObject from 'lodash/isPlainObject'
import Vue from 'vue'

const ObjProto = Object.prototype
const toString = ObjProto.toString
export const hasOwn = ObjProto.hasOwnProperty

const FN_MATCH_REGEXP = /^\s*function (\w+)/

// https://github.com/vuejs/vue/blob/dev/src/core/util/props.js#L177
export function getType(fn) {
  const type = fn !== null && fn !== undefined ? (fn.type ? fn.type : fn) : null
  const match = type && type.toString().match(FN_MATCH_REGEXP)
  return match && match[1]
}

export function getNativeType(value) {
  if (value === null || value === undefined) return null
  const match = value.constructor.toString().match(FN_MATCH_REGEXP)
  return match && match[1]
}

/**
 * No-op function
 */
export function noop() {}

/**
 * Checks for a own property in an object
 *
 * @param {object} obj - Object
 * @param {string} prop - Property to check
 * @returns {boolean}
 */
export const has = (obj, prop) => hasOwn.call(obj, prop)

/**
 * Determines whether the passed value is an integer. Uses `Number.isInteger` if available
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
 * @param {*} value - The value to be tested for being an integer.
 * @returns {boolean}
 */
export const isInteger =
  Number.isInteger ||
  function isInteger(value) {
    return (
      typeof value === 'number' &&
      isFinite(value) &&
      Math.floor(value) === value
    )
  }

/**
 * Determines whether the passed value is an Array.
 *
 * @param {*} value - The value to be tested for being an array.
 * @returns {boolean}
 */
export const isArray =
  Array.isArray ||
  function isArray(value) {
    return toString.call(value) === '[object Array]'
  }

/**
 * Checks if a value is a function
 *
 * @param {any} value - Value to check
 * @returns {boolean}
 */
export const isFunction = (value) =>
  toString.call(value) === '[object Function]'

/**
 * Adds a `def` method to the object returning a new object with passed in argument as `default` property
 *
 * @param {object} type - Object to enhance
 * @returns {object} the passed-in prop type
 */
export function withDefault(type) {
  return Object.defineProperty(type, 'def', {
    value(def) {
      if (def === undefined && !this.default) {
        return this
      }
      if (!isFunction(def) && !validateType(this, def)) {
        warn(`${this._vueTypes_name} - invalid default value: "${def}"`, def)
        return this
      }
      if (isArray(def)) {
        this.default = () => [...def]
      } else if (isPlainObject(def)) {
        this.default = () => Object.assign({}, def)
      } else {
        this.default = def
      }
      return this
    },
    enumerable: false,
    writable: false,
  })
}

/**
 * Adds a `isRequired` getter returning a new object with `required: true` key-value
 *
 * @param {object} type - Object to enhance
 * @returns {object} the passed-in prop type
 */
export function withRequired(type) {
  return Object.defineProperty(type, 'isRequired', {
    get() {
      this.required = true
      return this
    },
    enumerable: false,
  })
}

/**
 * Adds a validate method useful to set the prop `validator` function.
 *
 * @param {object} type Prop type to extend
 * @returns {object} the passed-in prop type
 */
export function withValidate(type) {
  return Object.defineProperty(type, 'validate', {
    value(fn) {
      this.validator = fn.bind(this)
      return this
    },
    enumerable: false,
  })
}

/**
 * Adds `isRequired` and `def` modifiers to an object
 *
 * @param {string} name - Type internal name
 * @param {object} obj - Object to enhance
 * @returns {object}
 */
export function toType(name, obj, validateFn = false) {
  Object.defineProperty(obj, '_vueTypes_name', {
    enumerable: false,
    writable: false,
    value: name,
  })

  withDefault(withRequired(obj))

  if (validateFn) {
    withValidate(obj)
  }

  if (isFunction(obj.validator)) {
    obj.validator = obj.validator.bind(obj)
  }
  return obj
}

/**
 * Validates a given value against a prop type object
 *
 * @param {Object|*} type - Type to use for validation. Either a type object or a constructor
 * @param {*} value - Value to check
 * @param {boolean} silent - Silence warnings
 * @returns {boolean}
 */
export function validateType(type, value, silent = false) {
  let typeToCheck = type
  let valid = true
  let expectedType
  if (!isPlainObject(type)) {
    typeToCheck = { type }
  }
  const namePrefix = typeToCheck._vueTypes_name
    ? typeToCheck._vueTypes_name + ' - '
    : ''

  if (hasOwn.call(typeToCheck, 'type') && typeToCheck.type !== null) {
    if (isArray(typeToCheck.type)) {
      valid = typeToCheck.type.some((type) => validateType(type, value, true))
      expectedType = typeToCheck.type.map((type) => getType(type)).join(' or ')
    } else {
      expectedType = getType(typeToCheck)

      if (expectedType === 'Array') {
        valid = isArray(value)
      } else if (expectedType === 'Object') {
        valid = isPlainObject(value)
      } else if (
        expectedType === 'String' ||
        expectedType === 'Number' ||
        expectedType === 'Boolean' ||
        expectedType === 'Function'
      ) {
        valid = getNativeType(value) === expectedType
      } else {
        valid = value instanceof typeToCheck.type
      }
    }
  }

  if (!valid) {
    silent === false &&
      warn(`${namePrefix}value "${value}" should be of type "${expectedType}"`)
    return false
  }

  if (
    hasOwn.call(typeToCheck, 'validator') &&
    isFunction(typeToCheck.validator)
  ) {
    // swallow warn
    let oldWarn
    if (silent) {
      oldWarn = warn
      warn = noop
    }

    valid = typeToCheck.validator(value)
    oldWarn && (warn = oldWarn)

    if (!valid && silent === false)
      warn(`${namePrefix}custom validation failed`)
    return valid
  }
  return valid
}

let warn = noop

if (process.env.NODE_ENV !== 'production') {
  const hasConsole = typeof console !== 'undefined'
  warn = hasConsole
    ? (msg) => {
        // eslint-disable-next-line no-console
        Vue.config.silent === false && console.warn(`[VueTypes warn]: ${msg}`)
      }
    : noop
}

export { warn }
<|endoftext|>


<commit_before>var u = {};

(function () {
    // TODO benchmark it.
    /**
     * A faster version of Function.prototype.bind.
     *
     * @param {Function} fn  Function to be bound.
     * @param thisArg
     * @returns {Function}
     */
    u.bind = function bind(fn, thisArg) {
        var boundArgs = [].slice.call(arguments, 2);
        return function () {
            var args = [].slice.call(arguments);
            args.unshift.apply(args, boundArgs);
            return fn.apply(thisArg, args);
        };
    };
    /**
     * A faster version of u.bind when only this binding is needed (i.e. no arguments).
     *
     * @param {Function} fn  Function to be bound.
     * @param thisArg
     * @returns {Function}
     */
    u.bindThis = function bindThis(fn, thisArg) {
        return function () {
            return fn.apply(thisArg, arguments);
        };
    };

    u.forEach = function forEach(array, callback) {
        var element;
        for (var i = 0, length = array.length; i < length; i++) {
            element = array[i];
            if (element !== undefined) { // omit empty parameters, emulates Array.prototype.forEach
                callback(element, i);
            }
        }
    };
})();
<commit_msg>documented u.forEach<commit_after>var u = {};

(function () {
    // TODO benchmark it.
    /**
     * A faster version of Function.prototype.bind.
     *
     * @param {Function} fn  Function to be bound.
     * @param thisArg
     * @returns {Function}
     */
    u.bind = function bind(fn, thisArg) {
        var boundArgs = [].slice.call(arguments, 2);
        return function () {
            var args = [].slice.call(arguments);
            args.unshift.apply(args, boundArgs);
            return fn.apply(thisArg, args);
        };
    };
    /**
     * A faster version of u.bind when only this binding is needed (i.e. no arguments).
     *
     * @param {Function} fn  Function to be bound.
     * @param thisArg
     * @returns {Function}
     */
    u.bindThis = function bindThis(fn, thisArg) {
        return function () {
            return fn.apply(thisArg, arguments);
        };
    };

    /**
     * A faster version of Array.prototype.forEach. Applies callback to each member of
     * array not strictly equal to undefined.
     *
     * @param {Array} array
     * @param {Function} callback  A function applied on every element; takes element as the first parameter
     *                             and its index in array as the second one.
     */
    u.forEach = function forEach(array, callback) {
        var element;
        for (var i = 0, length = array.length; i < length; i++) {
            element = array[i];
            if (element !== undefined) { // omit empty parameters, emulates Array.prototype.forEach
                callback(element, i);
            }
        }
    };
})();
<|endoftext|>


<commit_before>module.exports = {

    /**
    * Parse second to 00:00 format
    *
    * @param {Number} second
    * @return {String} 00:00 format
    */
    secondToTime: (second) => {
        const add0 = (num) => num < 10 ? '0' + num : '' + num;
        const min = parseInt(second / 60);
        const sec = parseInt(second - min * 60);
        return add0(min) + ':' + add0(sec);
    },

    /**
     * control play progress
     */
    // get element's view position
    getElementViewLeft: (element) => {
        let actualLeft = element.offsetLeft;
        let current = element.offsetParent;
        const elementScrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft;
        if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement) {
            while (current !== null) {
                actualLeft += current.offsetLeft;
                current = current.offsetParent;
            }
        }
        else {
            while (current !== null && current !== this.element) {
                actualLeft += current.offsetLeft;
                current = current.offsetParent;
            }
        }
        return actualLeft - elementScrollLeft;
    },
};<commit_msg>fixed #85<commit_after>module.exports = {

    /**
    * Parse second to 00:00 format
    *
    * @param {Number} second
    * @return {String} 00:00 format
    */
    secondToTime: (second) => {
        const add0 = (num) => num < 10 ? '0' + num : '' + num;
        const min = parseInt(second / 60);
        const sec = parseInt(second - min * 60);
        return add0(min) + ':' + add0(sec);
    },

    /**
     * control play progress
     */
    // get element's view position
    getElementViewLeft: (element) => {
        let actualLeft = element.offsetLeft;
        let current = element.offsetParent;
        const elementScrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft;
        if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement) {
            while (current !== null) {
                actualLeft += current.offsetLeft;
                current = current.offsetParent;
            }
        }
        else {
            while (current !== null && current !== element) {
                actualLeft += current.offsetLeft;
                current = current.offsetParent;
            }
        }
        return actualLeft - elementScrollLeft;
    },
};
<|endoftext|>


<commit_before>import url from 'url';

import upath from 'upath';
import { URL } from 'whatwg-url';
import Jed from 'jed';
import semver from 'semver';
import { oneLine } from 'common-tags';

import { PACKAGE_TYPES, LOCAL_PROTOCOLS } from 'const';

const locale = process.env.LOCALE_LANG || 'en-US';

var i18ndata = require(`./locale/${locale}/messages.js`)

const SOURCE_MAP_RE = new RegExp(/\/\/[#@]\s(source(?:Mapping)?URL)=\s*(\S+)/);

export function normalizePath(iconPath) {
  // Convert the icon path to a URL so we can strip any fragments and resolve
  // . and .. automatically. We need an absolute URL to use as a base so we're
  // using https://example.com/.
  const { pathname } = new URL(iconPath, 'https://example.com/');

  // Convert filename to unix path separator (as the ones stored
  // into the scanned files map).
  return upath.toUnix(decodeURIComponent(pathname).slice(1));
}

/*
 * Takes an AST node and returns the root property.
 *
 * example: foo().bar.baz() will return the AST node for foo.
 */
export function getRootExpression(node) {
  let root = node.callee;

  // If we encounter a member, grab the parent
  if (node.callee.type === 'MemberExpression') {
    let parent = node.callee.object;
    while (parent.type !== 'Identifier') {
      if (parent.callee.type === 'MemberExpression') {
        parent = parent.callee.object;
      } else {
        parent = parent.callee;
      }
    }
    root = parent;
  }

  return root;
}

/*
 * Returns the name of the reference node passed.
 *
 * example: var foo = document;
 *  The node for foo will return 'document'
 */
export function getNodeReference(context, node) {
  const { variables } = context.getScope();
  let scopeVar;

  // Just return the value if the node passed in is a reference to a literal.
  if (typeof node === 'undefined' || node.type === 'Literal') {
    return node;
  }

  // Finds variable reference in current scope.
  for (let i = 0; i < variables.length; i++) {
    const variable = variables[i];
    if (variable.name === node.name) {
      scopeVar = variable;
      break;
    }
  }

  if (scopeVar && scopeVar.defs && scopeVar.defs[0] &&
      scopeVar.defs[0].parent && scopeVar.defs[0].parent.parent &&
      scopeVar.defs[0].parent.parent.body) {
    // This represents all occurrences of the variable
    const occurances = scopeVar.defs[0].parent.parent.body;
    let lastAssignment;

    if (occurances instanceof Array) {
      occurances.forEach((occurance) => {
        if (occurance.type === 'VariableDeclaration' &&
            occurance.declarations[0].init !== null) {
          // Get what the name of what it was assigned to or the raw
          // value depending on the initalization
          lastAssignment = occurance.declarations[0].init;
        } else if (occurance.type === 'ExpressionStatement' &&
                   occurance.expression.type === 'AssignmentExpression') {
          // Get the right hand side of the assignment
          lastAssignment = occurance.expression.right;
        }
      });
    }

    // Return the name of the first definition of the variable which
    // corresponds to the node passed in.
    if (lastAssignment) {
      return lastAssignment;
    }
  }

  // If that variable doesn't exist in scope, then just return the node's
  // name.
  return node;
}

/*
 * Get a variable from a eslint context object if it exists, otherwise
 * undefined.
 */
export function getVariable(context, name) {
  const { variables } = context.getScope();
  let result;
  variables.forEach((variable) => {
    if (variable.name === name && variable.defs && variable.defs[0] &&
      variable.defs[0].name && variable.defs[0].name.parent) {
      result = variable.defs[0].name.parent.init;
    }
  });
  return result;
}

/*
 * Gettext utils. No-op until we have proper
 * a proper l10n solution.
 *
 */
export function gettext(str) {
  const jed = new Jed(i18ndata);
  return jed.gettext(str);
}

/*
 * An sprintf to use with gettext. Imported from Jed for when we have a proper
 * l10n solution.
 */
export const { sprintf } = Jed;

/*
 * Check the minimum node version is met
 */
export async function checkMinNodeVersion(minVersion, _process = process) {
  // eslint-disable-next-line no-param-reassign
  minVersion = minVersion || '0.12.0';
  if (!semver.gte(_process.version, minVersion)) {
    throw new Error(oneLine`Node version must be ${minVersion} or
                    greater. You are using ${_process.version}.`);
  }
}

export function getPackageTypeAsString(numericPackageType) {
  const packageKeys = Object.keys(PACKAGE_TYPES);
  for (let i = 0; i < packageKeys.length; i++) {
    const packageType = packageKeys[i];
    if (parseInt(numericPackageType, 10) === PACKAGE_TYPES[packageType]) {
      return packageType;
    }
  }
  throw new Error(`Invalid package type constant "${numericPackageType}"`);
}

/*
 * Looks through all exported functions and returns only
 * "public" *functions* that aren't prefixed with an _
 *
 * Used for ignoring private functions and constants in rules files.
 * Rules can have private functions we don't run; anything that
 * starts with an "_" shouldn't be returned.
 *
 * This exists because we export private functions in rule files
 * for testing.
 */
export function ignorePrivateFunctions(list) {
  const filteredList = {};

  Object.keys(list).forEach((functionName) => {
    if (functionName.startsWith('_') === false &&
        typeof list[functionName] === 'function') {
      filteredList[functionName] = list[functionName];
    }
  });

  return filteredList;
}

/*
 * Check a filename to make sure it's valid; used by scanners so we never
 * accept new scanners that don't specify which file they're referencing.
 */
export function ensureFilenameExists(filename) {
  if (typeof filename !== 'string' || filename.length < 1) {
    throw new Error('Filename is required');
  }
}

export function isLocalUrl(urlInput) {
  const parsedUrl = url.parse(urlInput);
  const { protocol, path } = parsedUrl;

  // Check protocol is chrome: or resource: if set.
  // Details on the chrome protocol are here: https://goo.gl/W52T0Q
  // Details on resource protocol are here: https://goo.gl/HHqeJA
  if (protocol && !LOCAL_PROTOCOLS.includes(protocol)) {
    return false;
  }
  // Disallow protocol-free remote urls.
  if (path.startsWith('//')) {
    return false;
  }
  return true;
}

export function apiToMessage(string) {
  return string
    .replace(/^extension/, 'ext')
    .replace(/\./g, '_')
    .toUpperCase()
    .substr(0, 25);
}

export function isBrowserNamespace(string) {
  return ['browser', 'chrome'].includes(string);
}

export function parseCspPolicy(policy) {
  if (!policy) {
    return {};
  }

  // eslint-disable-next-line no-param-reassign
  policy = policy.toLowerCase();

  const parsedPolicy = {};
  const directives = policy.split(';');

  directives.forEach((directive) => {
    // eslint-disable-next-line no-param-reassign
    directive = directive.trim();
    const tokens = directive.split(/\s+/);

    const name = tokens[0];

    if (name) {
      parsedPolicy[name] = tokens.slice(1, tokens.length);
    }
  });

  return parsedPolicy;
}

export function getLineAndColumnFromMatch(match) {
  const matchedLines = match.input
    .substr(0, match.index)
    .split('\n');
  const matchedColumn = matchedLines.slice(-1)[0].length + 1;
  const matchedLine = matchedLines.length;

  return { matchedLine, matchedColumn };
}

/**
 * Determines if the source text is minified.
 * Using the percentage no. of the indented lines from a sample set of lines
 * to determine if the js file is minified.
 * Inspired by code for the Firefox Developer Toolbar.
 */
export function couldBeMinifiedCode(code) {
  // Fast exit if `code` is empty. Could happen in tests, but also in real
  // files.
  if (!code) {
    return false;
  }

  // If there's a source map reference it's very certainly minified code.
  if (SOURCE_MAP_RE.test(code)) {
    return true;
  }

  // Number of lines to look at, taken from the head of the code.
  const sampleSize = 30;

  // Threshold in percent of indented lines to mark a file as not
  // minified.
  const indentCountThreshold = 20; // percentage

  // Length of a line that looks suspicious of being minified
  const hugeLinesLength = 500;

  // Number of huge lines to also mark a file as potentially minified
  // Hint: Minified AngularJS has 12 lines, jQuery 4
  const hugeLinesThreshold = 4;

  let lineEndIndex = 0;
  let lineStartIndex = 0;
  let lines = 1;
  let indentCount = 0;
  let hugeLinesCount = 0;

  // Strip comments.
  const normalizedCode = code.replace(/\/\*[\S\s]*?\*\/|\/\/.+/g, '');

  while (lines < sampleSize) {
    lineEndIndex = normalizedCode.indexOf('\n', lineStartIndex);

    if (lineEndIndex === -1) {
      break;
    }

    const currentLine = normalizedCode.slice(lineStartIndex, lineEndIndex);

    if (/^\s+/.test(currentLine)) {
      indentCount++;
    }

    if (currentLine.length >= hugeLinesLength) {
      hugeLinesCount++;
    }

    lineStartIndex = lineEndIndex + 1;
    lines++;
  }

  return (
    ((indentCount / lines) * 100) < indentCountThreshold ||
    hugeLinesCount > hugeLinesThreshold
  );
}
<commit_msg>Added multiple env variables<commit_after>import url from 'url';

import upath from 'upath';
import { URL } from 'whatwg-url';
import Jed from 'jed';
import semver from 'semver';
import { oneLine } from 'common-tags';

import { PACKAGE_TYPES, LOCAL_PROTOCOLS } from 'const';

const env = process.env
const locale = env.LANG || env.LANGUAGE || env.LC_ALL || env.LC_MESSAGES;

var i18ndata = require(`./locale/${locale}/messages.js`)

const SOURCE_MAP_RE = new RegExp(/\/\/[#@]\s(source(?:Mapping)?URL)=\s*(\S+)/);

export function normalizePath(iconPath) {
  // Convert the icon path to a URL so we can strip any fragments and resolve
  // . and .. automatically. We need an absolute URL to use as a base so we're
  // using https://example.com/.
  const { pathname } = new URL(iconPath, 'https://example.com/');

  // Convert filename to unix path separator (as the ones stored
  // into the scanned files map).
  return upath.toUnix(decodeURIComponent(pathname).slice(1));
}

/*
 * Takes an AST node and returns the root property.
 *
 * example: foo().bar.baz() will return the AST node for foo.
 */
export function getRootExpression(node) {
  let root = node.callee;

  // If we encounter a member, grab the parent
  if (node.callee.type === 'MemberExpression') {
    let parent = node.callee.object;
    while (parent.type !== 'Identifier') {
      if (parent.callee.type === 'MemberExpression') {
        parent = parent.callee.object;
      } else {
        parent = parent.callee;
      }
    }
    root = parent;
  }

  return root;
}

/*
 * Returns the name of the reference node passed.
 *
 * example: var foo = document;
 *  The node for foo will return 'document'
 */
export function getNodeReference(context, node) {
  const { variables } = context.getScope();
  let scopeVar;

  // Just return the value if the node passed in is a reference to a literal.
  if (typeof node === 'undefined' || node.type === 'Literal') {
    return node;
  }

  // Finds variable reference in current scope.
  for (let i = 0; i < variables.length; i++) {
    const variable = variables[i];
    if (variable.name === node.name) {
      scopeVar = variable;
      break;
    }
  }

  if (scopeVar && scopeVar.defs && scopeVar.defs[0] &&
      scopeVar.defs[0].parent && scopeVar.defs[0].parent.parent &&
      scopeVar.defs[0].parent.parent.body) {
    // This represents all occurrences of the variable
    const occurances = scopeVar.defs[0].parent.parent.body;
    let lastAssignment;

    if (occurances instanceof Array) {
      occurances.forEach((occurance) => {
        if (occurance.type === 'VariableDeclaration' &&
            occurance.declarations[0].init !== null) {
          // Get what the name of what it was assigned to or the raw
          // value depending on the initalization
          lastAssignment = occurance.declarations[0].init;
        } else if (occurance.type === 'ExpressionStatement' &&
                   occurance.expression.type === 'AssignmentExpression') {
          // Get the right hand side of the assignment
          lastAssignment = occurance.expression.right;
        }
      });
    }

    // Return the name of the first definition of the variable which
    // corresponds to the node passed in.
    if (lastAssignment) {
      return lastAssignment;
    }
  }

  // If that variable doesn't exist in scope, then just return the node's
  // name.
  return node;
}

/*
 * Get a variable from a eslint context object if it exists, otherwise
 * undefined.
 */
export function getVariable(context, name) {
  const { variables } = context.getScope();
  let result;
  variables.forEach((variable) => {
    if (variable.name === name && variable.defs && variable.defs[0] &&
      variable.defs[0].name && variable.defs[0].name.parent) {
      result = variable.defs[0].name.parent.init;
    }
  });
  return result;
}

/*
 * Gettext utils. No-op until we have proper
 * a proper l10n solution.
 *
 */
export function gettext(str) {
  const jed = new Jed(i18ndata);
  return jed.gettext(str);
}

/*
 * An sprintf to use with gettext. Imported from Jed for when we have a proper
 * l10n solution.
 */
export const { sprintf } = Jed;

/*
 * Check the minimum node version is met
 */
export async function checkMinNodeVersion(minVersion, _process = process) {
  // eslint-disable-next-line no-param-reassign
  minVersion = minVersion || '0.12.0';
  if (!semver.gte(_process.version, minVersion)) {
    throw new Error(oneLine`Node version must be ${minVersion} or
                    greater. You are using ${_process.version}.`);
  }
}

export function getPackageTypeAsString(numericPackageType) {
  const packageKeys = Object.keys(PACKAGE_TYPES);
  for (let i = 0; i < packageKeys.length; i++) {
    const packageType = packageKeys[i];
    if (parseInt(numericPackageType, 10) === PACKAGE_TYPES[packageType]) {
      return packageType;
    }
  }
  throw new Error(`Invalid package type constant "${numericPackageType}"`);
}

/*
 * Looks through all exported functions and returns only
 * "public" *functions* that aren't prefixed with an _
 *
 * Used for ignoring private functions and constants in rules files.
 * Rules can have private functions we don't run; anything that
 * starts with an "_" shouldn't be returned.
 *
 * This exists because we export private functions in rule files
 * for testing.
 */
export function ignorePrivateFunctions(list) {
  const filteredList = {};

  Object.keys(list).forEach((functionName) => {
    if (functionName.startsWith('_') === false &&
        typeof list[functionName] === 'function') {
      filteredList[functionName] = list[functionName];
    }
  });

  return filteredList;
}

/*
 * Check a filename to make sure it's valid; used by scanners so we never
 * accept new scanners that don't specify which file they're referencing.
 */
export function ensureFilenameExists(filename) {
  if (typeof filename !== 'string' || filename.length < 1) {
    throw new Error('Filename is required');
  }
}

export function isLocalUrl(urlInput) {
  const parsedUrl = url.parse(urlInput);
  const { protocol, path } = parsedUrl;

  // Check protocol is chrome: or resource: if set.
  // Details on the chrome protocol are here: https://goo.gl/W52T0Q
  // Details on resource protocol are here: https://goo.gl/HHqeJA
  if (protocol && !LOCAL_PROTOCOLS.includes(protocol)) {
    return false;
  }
  // Disallow protocol-free remote urls.
  if (path.startsWith('//')) {
    return false;
  }
  return true;
}

export function apiToMessage(string) {
  return string
    .replace(/^extension/, 'ext')
    .replace(/\./g, '_')
    .toUpperCase()
    .substr(0, 25);
}

export function isBrowserNamespace(string) {
  return ['browser', 'chrome'].includes(string);
}

export function parseCspPolicy(policy) {
  if (!policy) {
    return {};
  }

  // eslint-disable-next-line no-param-reassign
  policy = policy.toLowerCase();

  const parsedPolicy = {};
  const directives = policy.split(';');

  directives.forEach((directive) => {
    // eslint-disable-next-line no-param-reassign
    directive = directive.trim();
    const tokens = directive.split(/\s+/);

    const name = tokens[0];

    if (name) {
      parsedPolicy[name] = tokens.slice(1, tokens.length);
    }
  });

  return parsedPolicy;
}

export function getLineAndColumnFromMatch(match) {
  const matchedLines = match.input
    .substr(0, match.index)
    .split('\n');
  const matchedColumn = matchedLines.slice(-1)[0].length + 1;
  const matchedLine = matchedLines.length;

  return { matchedLine, matchedColumn };
}

/**
 * Determines if the source text is minified.
 * Using the percentage no. of the indented lines from a sample set of lines
 * to determine if the js file is minified.
 * Inspired by code for the Firefox Developer Toolbar.
 */
export function couldBeMinifiedCode(code) {
  // Fast exit if `code` is empty. Could happen in tests, but also in real
  // files.
  if (!code) {
    return false;
  }

  // If there's a source map reference it's very certainly minified code.
  if (SOURCE_MAP_RE.test(code)) {
    return true;
  }

  // Number of lines to look at, taken from the head of the code.
  const sampleSize = 30;

  // Threshold in percent of indented lines to mark a file as not
  // minified.
  const indentCountThreshold = 20; // percentage

  // Length of a line that looks suspicious of being minified
  const hugeLinesLength = 500;

  // Number of huge lines to also mark a file as potentially minified
  // Hint: Minified AngularJS has 12 lines, jQuery 4
  const hugeLinesThreshold = 4;

  let lineEndIndex = 0;
  let lineStartIndex = 0;
  let lines = 1;
  let indentCount = 0;
  let hugeLinesCount = 0;

  // Strip comments.
  const normalizedCode = code.replace(/\/\*[\S\s]*?\*\/|\/\/.+/g, '');

  while (lines < sampleSize) {
    lineEndIndex = normalizedCode.indexOf('\n', lineStartIndex);

    if (lineEndIndex === -1) {
      break;
    }

    const currentLine = normalizedCode.slice(lineStartIndex, lineEndIndex);

    if (/^\s+/.test(currentLine)) {
      indentCount++;
    }

    if (currentLine.length >= hugeLinesLength) {
      hugeLinesCount++;
    }

    lineStartIndex = lineEndIndex + 1;
    lines++;
  }

  return (
    ((indentCount / lines) * 100) < indentCountThreshold ||
    hugeLinesCount > hugeLinesThreshold
  );
}
<|endoftext|>