<commit_before>// an assert module that returns tappable data for each assertion.

module.exports = assert

var syns = {}
  , id = 1

function assert (ok, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)

  //console.error("assert %j", [ok, message, extra])
  //if (extra && extra.skip) return assert.skip(message, extra)
  //console.error("assert", [ok, message, extra])
  ok = !!ok
  var res = { id : id ++, ok: ok }

  var caller = getCaller(extra && extra.error)
  if (extra && extra.error) {
    res.type = extra.error.name
    res.message = extra.error.message
    res.code = extra.error.code
             || extra.error.type
    res.errno = extra.error.errno
    delete extra.error
  }
  if (caller.file) {
    res.file = caller.file
    res.line = +caller.line
    res.column = +caller.column
  }
  res.stack = caller.stack

  res.name = message || "(unnamed assert)"

  if (extra) Object.keys(extra).forEach(function (k) {
    if (!res.hasOwnProperty(k)) res[k] = extra[k]
  })

  // strings and objects are hard to diff by eye
  if (!ok &&
      res.hasOwnProperty("found") &&
      res.hasOwnProperty("wanted") &&
      res.found !== res.wanted) {
    if (typeof res.wanted !== typeof res.found ||
        typeof res.wanted === "object" && (!res.found || !res.wanted)) {
      res.type = { found: typeof found
                 , wanted: typeof wanted }
    } else if (typeof res.wanted === "string") {
      res.diff = diffString(res.found, res.wanted)
    } else if (typeof res.wanted === "object") {
      res.diff = diffObject(res.found, res.wanted)
    }
  }

  //console.error("assert return", res)

  return res
}
assert.ok = assert
syns.ok = [ "true", "assert" ]

function notOk (ok, message, extra) {
  return assert(!ok, message, extra)
}
assert.notOk = notOk
syns.notOk = [ "false", "notok" ]

function error (er, message, extra) {
  if (!er) {
    // just like notOk(er)
    return assert(!er, message, extra)
  }
  message = message || er.message
  extra = extra || {}
  extra.error = er
  return assert.fail(message, extra)
}
assert.error = error
syns.error = [ "ifError", "ifErr", "iferror" ]

function pass (message, extra) {
  return assert(true, message, extra)
}
assert.pass = pass

function fail (message, extra) {
  //console.error("assert.fail", [message, extra])
  //if (extra && extra.skip) return assert.skip(message, extra)
  return assert(false, message, extra)
}
assert.fail = fail

function skip (message, extra) {
  //console.error("assert.skip", message, extra)
  if (!extra) extra = {}
  return { id: id ++, skip: true, name: message || "" }
}
assert.skip = skip

function throws (fn, wanted, message, extra) {
  if (typeof wanted === "string") {
    extra = message
    message = wanted
    wanted = null
  }

  if (extra && extra.skip) return assert.skip(message, extra)

  var found = null
  try {
    fn()
  } catch (e) {
    found = { name: e.name, message: e.message }
  }

  extra = extra || {}

  extra.found = found
  if (wanted) {
    wanted = { name: wanted.name, message: wanted.message }
    extra.wanted = wanted
  }

  if (!message) {
    message = "Expected to throw"
    if (wanted) message += ": "+wanted.name + " " + wanted.message
  }

  return (wanted) ? assert.similar(found, wanted, message, extra)
                  : assert.ok(found, message, extra)
}
assert.throws = throws

function doesNotThrow (fn, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  var found = null
  try {
    fn()
  } catch (e) {
    found = {name: e.name, message: e.message}
  }
  message = message || "Should not throw"

  return assert.equal(found, null, message, extra)
}
assert.doesNotThrow = doesNotThrow

function equal (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  extra = extra || {}
  message = message || "should be equal"
  extra.found = a
  extra.wanted = b
  return assert(a === b, message, extra)
}
assert.equal = equal
syns.equal = ["equals"
             ,"isEqual"
             ,"is"
             ,"strictEqual"
             ,"strictEquals"]

function equivalent (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  var extra = extra || {}
  message = message || "should be equivalent"
  extra.found = a
  extra.wanted = b
  return assert(stringify(a) === stringify(b), message, extra)
}
assert.equivalent = equivalent
syns.equivalent = ["isEquivalent"
                  ,"looseEqual"
                  ,"looseEquals"
                  ,"isDeeply"
                  ,"same"
                  ,"deepEqual"
                  ,"deepEquals"]

function inequal (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  extra = extra || {}
  message = message || "should not be equal"
  extra.found = a
  extra.doNotWant = b
  return assert(a !== b, message, extra)
}
assert.inequal = inequal
syns.inequal = ["notEqual"
               ,"notEquals"
               ,"isNotEqual"
               ,"isNot"
               ,"not"
               ,"doesNotEqual"
               ,"isInequal"]

function inequivalent (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  extra = extra || {}
  message = message || "should not be equivalent"
  extra.found = a
  extra.doNotWant = b
  return assert(stringify(a) !== stringify(b), message, extra)
}
assert.inequivalent = inequivalent
syns.inequivalent = ["notEquivalent"
                    ,"notDeepEqual"
                    ,"notDeeply"
                    ,"isNotDeepEqual"
                    ,"isNotDeeply"
                    ,"isNotEquivalent"
                    ,"isInequivalent"]

function similar (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  // test that a has all the fields in b
  message = message || "should be similar"
  return equivalent(selectFields(a, b), b, message, extra)
}
assert.similar = similar
syns.similar = ["isSimilar"
               ,"has"
               ,"hasFields"
               ,"like"
               ,"isLike"]

function dissimilar (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  // test that a has all the fields in b
  message = message || "should be dissimilar"
  return inequivalent(selectFields(a, b), b, message, extra)
}
assert.dissimilar = dissimilar
syns.dissimilar = ["unsimilar"
                  ,"notSimilar"
                  ,"unlike"
                  ,"isUnlike"
                  ,"notLike"
                  ,"isNotLike"
                  ,"doesNotHave"
                  ,"isNotSimilar"
                  ,"isDissimilar"]

function type (thing, t, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  var name = t
  if (typeof name === "function") name = name.name || "(anonymous ctor)"
  //console.error("name=%s", name)
  message = message || "type is "+name
  var type = typeof thing
  //console.error("type=%s", type)
  if (!thing && type === "object") type = "null"
  if (type === "object" && t !== "object") {
    if (typeof t === "function") {
      //console.error("it is a function!")
      extra = extra || {}
      extra.found = Object.getPrototypeOf(thing).constructor.name
      extra.wanted = name
      //console.error(thing instanceof t, name)
      return assert.ok(thing instanceof t, message, extra)
    }

    //console.error("check prototype chain")
    // check against classnames or objects in prototype chain, as well.
    // type(new Error("asdf"), "Error")
    // type(Object.create(foo), foo)
    var p = thing
    while (p = Object.getPrototypeOf(p)) {
      if (p === t || p.constructor && p.constructor.name === t) {
        type = name
        break
      }
    }
  }
  //console.error(type, name, type === name)
  return assert.equal(type, name, message, extra)
}
assert.type = type
syns.type = ["isa"]

// synonyms are helpful.
Object.keys(syns).forEach(function (c) {
  syns[c].forEach(function (s) {
    Object.defineProperty(assert, s, { value: assert[c], enumerable: false })
  })
})

// helpers below

function selectFields (a, b) {
  // get the values in A of the fields in B
  var ret = Array.isArray(b) ? [] : {}
  Object.keys(b).forEach(function (k) {
    if (!a.hasOwnProperty(k)) return
    var v = b[k]
      , av = a[k]
    if (v && av && typeof v === "object" && typeof av === "object") {
      ret[k] = selectFields(av, v)
    } else ret[k] = av
  })
  return ret
}

function stringify (a) {
  return JSON.stringify(a, (function () {
    var seen = []
      , keys = []
    return function (key, val) {
      var s = seen.indexOf(val)
      if (s !== -1) {
        return "[Circular: "+keys[s]+"]"
      }
      if (val && typeof val === "object" || typeof val === "function") {
        seen.push(val)
        keys.push(val["!"] || val.name || key || "<root>")
        if (typeof val === "function") {
          return val.toString().split(/\n/)[0]
        } else if (val.toUTCString) {
          return val.toUTCString()
        }
      }
      return val
  }})())
}

function diffString (f, w) {
  if (w === f) return null
  var p = 0
    , l = w.length
  while (p < l && w.charAt(p) === f.charAt(p)) p ++
  w = stringify(w).substr(1).replace(/"$/, "")
  f = stringify(f).substr(1).replace(/"$/, "")
  return diff(f, w, p)
}

function diffObject (f, w) {
  var f = stringify(f)
    , w = stringify(w)
    , l = w.length
  if (f === w) return null
  var p = 0
  while (p < l && f.charAt(p) === w.charAt(p)) p ++
  return diff(f, w, p)
}

function diff (f, w, p) {
  if (w === f) return null
  var i = p || 0 // it's going to be at least p. JSON can only be bigger.
    , l = w.length
  while (i < l && w.charAt(i) === f.charAt(i)) i ++
  var pos = Math.max(0, i - 20)
  w = w.substr(pos, 40)
  f = f.substr(pos, 40)
  var pointer = i - pos
  return "FOUND:  "+f+"\n"
       + "WANTED: "+w+"\n"
       + (new Array(pointer + 9).join(" "))
       + "^ (at position = "+p+")"
}

function getCaller (er) {
  // get the first file/line that isn't this file.
  if (!er) er = new Error
  var stack = er.stack || ""
  stack = stack.split(/\n/)
  for (var i = 1, l = stack.length; i < l; i ++) {
    var s = stack[i].match(/\(([^):]+):([0-9]+):([0-9]+)\)$/)
    if (!s) continue
    var file = s[1]
      , line = +s[2]
      , col = +s[3]
    if (file.indexOf(__dirname) === 0) continue
    if (file.match(/tap-test\/test.js$/)) continue
    else break
  }
  var res = {}
  if (file && file !== __filename && !file.match(/tap-test\/test.js$/)) {
    res.file = file
    res.line = line
    res.column = col
  }

  res.stack = stack.slice(1).map(function (s) {
    return s.replace(/^\s*at\s*/, "")
  })

  return res
}

<commit_msg>Handle errors better in stringify<commit_after>// an assert module that returns tappable data for each assertion.

module.exports = assert

var syns = {}
  , id = 1

function assert (ok, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)

  //console.error("assert %j", [ok, message, extra])
  //if (extra && extra.skip) return assert.skip(message, extra)
  //console.error("assert", [ok, message, extra])
  ok = !!ok
  var res = { id : id ++, ok: ok }

  var caller = getCaller(extra && extra.error)
  if (extra && extra.error) {
    res.type = extra.error.name
    res.message = extra.error.message
    res.code = extra.error.code
             || extra.error.type
    res.errno = extra.error.errno
    delete extra.error
  }
  if (caller.file) {
    res.file = caller.file
    res.line = +caller.line
    res.column = +caller.column
  }
  res.stack = caller.stack

  res.name = message || "(unnamed assert)"

  if (extra) Object.keys(extra).forEach(function (k) {
    if (!res.hasOwnProperty(k)) res[k] = extra[k]
  })

  // strings and objects are hard to diff by eye
  if (!ok &&
      res.hasOwnProperty("found") &&
      res.hasOwnProperty("wanted") &&
      res.found !== res.wanted) {
    if (typeof res.wanted !== typeof res.found ||
        typeof res.wanted === "object" && (!res.found || !res.wanted)) {
      res.type = { found: typeof found
                 , wanted: typeof wanted }
    } else if (typeof res.wanted === "string") {
      res.diff = diffString(res.found, res.wanted)
    } else if (typeof res.wanted === "object") {
      res.diff = diffObject(res.found, res.wanted)
    }
  }

  //console.error("assert return", res)

  return res
}
assert.ok = assert
syns.ok = [ "true", "assert" ]

function notOk (ok, message, extra) {
  return assert(!ok, message, extra)
}
assert.notOk = notOk
syns.notOk = [ "false", "notok" ]

function error (er, message, extra) {
  if (!er) {
    // just like notOk(er)
    return assert(!er, message, extra)
  }
  message = message || er.message
  extra = extra || {}
  extra.error = er
  return assert.fail(message, extra)
}
assert.error = error
syns.error = [ "ifError", "ifErr", "iferror" ]

function pass (message, extra) {
  return assert(true, message, extra)
}
assert.pass = pass

function fail (message, extra) {
  //console.error("assert.fail", [message, extra])
  //if (extra && extra.skip) return assert.skip(message, extra)
  return assert(false, message, extra)
}
assert.fail = fail

function skip (message, extra) {
  //console.error("assert.skip", message, extra)
  if (!extra) extra = {}
  return { id: id ++, skip: true, name: message || "" }
}
assert.skip = skip

function throws (fn, wanted, message, extra) {
  if (typeof wanted === "string") {
    extra = message
    message = wanted
    wanted = null
  }

  if (extra && extra.skip) return assert.skip(message, extra)

  var found = null
  try {
    fn()
  } catch (e) {
    found = { name: e.name, message: e.message }
  }

  extra = extra || {}

  extra.found = found
  if (wanted) {
    wanted = { name: wanted.name, message: wanted.message }
    extra.wanted = wanted
  }

  if (!message) {
    message = "Expected to throw"
    if (wanted) message += ": "+wanted.name + " " + wanted.message
  }

  return (wanted) ? assert.similar(found, wanted, message, extra)
                  : assert.ok(found, message, extra)
}
assert.throws = throws

function doesNotThrow (fn, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  var found = null
  try {
    fn()
  } catch (e) {
    found = {name: e.name, message: e.message}
  }
  message = message || "Should not throw"

  return assert.equal(found, null, message, extra)
}
assert.doesNotThrow = doesNotThrow

function equal (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  extra = extra || {}
  message = message || "should be equal"
  extra.found = a
  extra.wanted = b
  return assert(a === b, message, extra)
}
assert.equal = equal
syns.equal = ["equals"
             ,"isEqual"
             ,"is"
             ,"strictEqual"
             ,"strictEquals"]

function equivalent (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  var extra = extra || {}
  message = message || "should be equivalent"
  extra.found = a
  extra.wanted = b
  return assert(stringify(a) === stringify(b), message, extra)
}
assert.equivalent = equivalent
syns.equivalent = ["isEquivalent"
                  ,"looseEqual"
                  ,"looseEquals"
                  ,"isDeeply"
                  ,"same"
                  ,"deepEqual"
                  ,"deepEquals"]

function inequal (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  extra = extra || {}
  message = message || "should not be equal"
  extra.found = a
  extra.doNotWant = b
  return assert(a !== b, message, extra)
}
assert.inequal = inequal
syns.inequal = ["notEqual"
               ,"notEquals"
               ,"isNotEqual"
               ,"isNot"
               ,"not"
               ,"doesNotEqual"
               ,"isInequal"]

function inequivalent (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  extra = extra || {}
  message = message || "should not be equivalent"
  extra.found = a
  extra.doNotWant = b
  return assert(stringify(a) !== stringify(b), message, extra)
}
assert.inequivalent = inequivalent
syns.inequivalent = ["notEquivalent"
                    ,"notDeepEqual"
                    ,"notDeeply"
                    ,"isNotDeepEqual"
                    ,"isNotDeeply"
                    ,"isNotEquivalent"
                    ,"isInequivalent"]

function similar (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  // test that a has all the fields in b
  message = message || "should be similar"
  return equivalent(selectFields(a, b), b, message, extra)
}
assert.similar = similar
syns.similar = ["isSimilar"
               ,"has"
               ,"hasFields"
               ,"like"
               ,"isLike"]

function dissimilar (a, b, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  // test that a has all the fields in b
  message = message || "should be dissimilar"
  return inequivalent(selectFields(a, b), b, message, extra)
}
assert.dissimilar = dissimilar
syns.dissimilar = ["unsimilar"
                  ,"notSimilar"
                  ,"unlike"
                  ,"isUnlike"
                  ,"notLike"
                  ,"isNotLike"
                  ,"doesNotHave"
                  ,"isNotSimilar"
                  ,"isDissimilar"]

function type (thing, t, message, extra) {
  if (extra && extra.skip) return assert.skip(message, extra)
  var name = t
  if (typeof name === "function") name = name.name || "(anonymous ctor)"
  //console.error("name=%s", name)
  message = message || "type is "+name
  var type = typeof thing
  //console.error("type=%s", type)
  if (!thing && type === "object") type = "null"
  if (type === "object" && t !== "object") {
    if (typeof t === "function") {
      //console.error("it is a function!")
      extra = extra || {}
      extra.found = Object.getPrototypeOf(thing).constructor.name
      extra.wanted = name
      //console.error(thing instanceof t, name)
      return assert.ok(thing instanceof t, message, extra)
    }

    //console.error("check prototype chain")
    // check against classnames or objects in prototype chain, as well.
    // type(new Error("asdf"), "Error")
    // type(Object.create(foo), foo)
    var p = thing
    while (p = Object.getPrototypeOf(p)) {
      if (p === t || p.constructor && p.constructor.name === t) {
        type = name
        break
      }
    }
  }
  //console.error(type, name, type === name)
  return assert.equal(type, name, message, extra)
}
assert.type = type
syns.type = ["isa"]

// synonyms are helpful.
Object.keys(syns).forEach(function (c) {
  syns[c].forEach(function (s) {
    Object.defineProperty(assert, s, { value: assert[c], enumerable: false })
  })
})

// helpers below

function selectFields (a, b) {
  // get the values in A of the fields in B
  var ret = Array.isArray(b) ? [] : {}
  Object.keys(b).forEach(function (k) {
    if (!a.hasOwnProperty(k)) return
    var v = b[k]
      , av = a[k]
    if (v && av && typeof v === "object" && typeof av === "object"
       && !(v instanceof Date)
       && !(v instanceof RegExp)
       && !(v instanceof String)
       && !(v instanceof Boolean)
       && !(v instanceof Number)
       && !(Array.isArray(v))) {
      ret[k] = selectFields(av, v)
    } else ret[k] = av
  })
  return ret
}

function stringify (a) {
  return JSON.stringify(a, (function () {
    var seen = []
      , keys = []
    return function (key, val) {
      var s = seen.indexOf(val)
      if (s !== -1) {
        return "[Circular: "+keys[s]+"]"
      }
      if (val && typeof val === "object" || typeof val === "function") {
        seen.push(val)
        keys.push(val["!"] || val.name || key || "<root>")
        if (typeof val === "function") {
          return val.toString().split(/\n/)[0]
        } else if (typeof val.toUTCString === "function") {
          return val.toUTCString()
        }
      }
      return val
  }})())
}

function diffString (f, w) {
  if (w === f) return null
  var p = 0
    , l = w.length
  while (p < l && w.charAt(p) === f.charAt(p)) p ++
  w = stringify(w).substr(1).replace(/"$/, "")
  f = stringify(f).substr(1).replace(/"$/, "")
  return diff(f, w, p)
}

function diffObject (f, w) {
  var f = stringify(f)
    , w = stringify(w)
    , l = w.length
  if (f === w) return null
  var p = 0
  while (p < l && f.charAt(p) === w.charAt(p)) p ++
  return diff(f, w, p)
}

function diff (f, w, p) {
  if (w === f) return null
  var i = p || 0 // it's going to be at least p. JSON can only be bigger.
    , l = w.length
  while (i < l && w.charAt(i) === f.charAt(i)) i ++
  var pos = Math.max(0, i - 20)
  w = w.substr(pos, 40)
  f = f.substr(pos, 40)
  var pointer = i - pos
  return "FOUND:  "+f+"\n"
       + "WANTED: "+w+"\n"
       + (new Array(pointer + 9).join(" "))
       + "^ (at position = "+p+")"
}

function getCaller (er) {
  // get the first file/line that isn't this file.
  if (!er) er = new Error
  var stack = er.stack || ""
  stack = stack.split(/\n/)
  for (var i = 1, l = stack.length; i < l; i ++) {
    var s = stack[i].match(/\(([^):]+):([0-9]+):([0-9]+)\)$/)
    if (!s) continue
    var file = s[1]
      , line = +s[2]
      , col = +s[3]
    if (file.indexOf(__dirname) === 0) continue
    if (file.match(/tap-test\/test.js$/)) continue
    else break
  }
  var res = {}
  if (file && file !== __filename && !file.match(/tap-test\/test.js$/)) {
    res.file = file
    res.line = line
    res.column = col
  }

  res.stack = stack.slice(1).map(function (s) {
    return s.replace(/^\s*at\s*/, "")
  })

  return res
}

<|endoftext|>


<commit_before>(function(window, angular){
	'use strict';

	// DESCRIPTION:
	// vsRepeat directive stands for Virtual Scroll Repeat. It turns a standard ngRepeated set of elements in a scrollable container
	// into a component, where the user thinks he has all the elements rendered and all he needs to do is scroll (without any kind of
	// pagination - which most users loath) and at the same time the browser isn't overloaded by that many elements/angular bindings etc.
	// The directive renders only so many elements that can fit into current container's clientHeight.

	// LIMITATIONS:
	// - current version works only for vertically stacked elements
	// - current version only supports an Array as a right-hand-side object for ngRepeat
	// - all rendered elements must have the same predefined height

	// USAGE:
	// In order to use the vsRepeat directive you need to measure the single element's height (including all paddings and margins).
	// You can use any kind of developer tools you like. Let's say that that height is 50px.
	// example:
	//

	//

	//
	//

	//

	//
	// - the vsRepeat directive must be applied to a direct parent of an element with ngRepeat
	// - the value of vsRepeat attribute is the single element's height measured in pixels

	// OPTIONAL PARAMETERS (attributes):
	// vs-scroll-parent="selector" - selector to the scrollable container. The directive will look for a closest parent matching
	// 								 the given selector (defaults to the current element)
	// vs-top-offset="value" - top offset in pixels (defaults to 0)
	// vs-excess="value" - an integer number representing the number of elements to be rendered outside of the current container's viewport
	// 					   (defaults to 2)

	// EVENTS:
	// - 'vsRepeatTrigger' - an event the directive listens for to manually trigger reinitialization
	// - 'vsRepeatReinitialized' - an event the directive emits upon reinitialization done

	var isMacOS = navigator.appVersion.indexOf("Mac") != -1;
	angular.module('vs-repeat', []).directive('vsRepeat', ['$compile', function($compile){
		return {
			restrict: 'A',
			scope: true,
			compile: function($element, $attrs){
				var childClone = $element.children().eq(0).clone(),
					ngRepeatExpression = childClone.attr('ng-repeat'),
					expressionMatches = /^\s*(\S+)\s+in\s+(\S+)\s*(track\s+by\s+\S+)?/.exec(ngRepeatExpression),
					lhs = expressionMatches[1],
					rhs = expressionMatches[2],
					rhsSuffix = expressionMatches[3],
					collectionName = '$vs_' + rhs,
					originalCollection = [],
					originalLength,
					$wheelHelper,
					$fillElement;

				$element.empty();
				if(!window.getComputedStyle || window.getComputedStyle($element[0]).position !== 'absolute')
					$element.css('position', 'relative');
				return {
					pre: function($scope, $element, $attrs){
						$scope.elementHeight = parseInt($attrs.vsRepeat, 10);
						var $scrollParent = $attrs.vsScrollParent ? $element.closest($attrs.vsScrollParent) : $element;
						$scope.topOffset = $attrs.vsTopOffset ? parseInt($attrs.vsTopOffset, 10) : 0;
						$scope.excess = $attrs.vsExcess ? parseInt($attrs.vsExcess, 10) : 2;

						$scope.$watchCollection(rhs, function(coll){
							originalCollection = coll || [];
							if(!originalCollection || originalCollection.length < 1){
								$scope[collectionName] = [];
								originalLength = 0;
								return;
							}
							else{
								originalLength = originalCollection.length;
							}
							reinitialize();
						});

						childClone.attr('ng-repeat', lhs + ' in ' + collectionName + (rhsSuffix ? ' ' + rhsSuffix : ''))
								.attr('ng-style', '{top: ($index + startIndex) * elementHeight + topOffset}')
								.attr('style', 'position: absolute;');
						$compile(childClone)($scope);
						$element.append(childClone);

						$fillElement = $('

')
							.prependTo($element)
							.css({'position':'relative'});

						var _prevMouse = {};
						if(isMacOS){
							$wheelHelper = $('

')
								.appendTo($fillElement)
								.on('wheel', function(e){
									e.preventDefault();
									e.stopPropagation();
									$scrollParent[0].scrollTop += e.originalEvent.deltaY;
								}).on('mousemove', function(e){
									if(_prevMouse.x !== e.clientX || _prevMouse.y !== e.clientY)
										$(this).hide();
									_prevMouse = {
										x: e.clientX,
										y: e.clientY
									};
								}).hide();
						}

						$scope.startIndex = 0;
						$scope.endIndex = 0;

						$scrollParent.on('scroll.vs-repeat', function scrollHandler(e){
							if(updateInnerCollection())
								$scope.$apply();
						});

						if(isMacOS){
							$scrollParent.on('wheel.vs-repeat', wheelHandler);
						}
						function wheelHandler(e){
							e.preventDefault();
							$wheelHelper.show();
						}

						function onWindowResize(){
							if(updateInnerCollection())
								$scope.$apply();
						}

						$(window).on('resize', onWindowResize);

						$scope.$on('$destroy', function(){
							$(window).off('resize', onWindowResize);
						});

						$scope.$on('vsRepeatTrigger', reinitialize);
						var _prevStartIndex,
							_prevEndIndex;
						function reinitialize(){
							_prevStartIndex = void 0;
							_prevEndIndex = void 0;
							updateInnerCollection();
							$fillElement.css({'height': $scope.elementHeight*originalLength});
							$scope.$emit('vsRepeatReinitialized');
						}

						var _prevClientHeight;
						function reinitOnClientHeightChange(){
							var ch = $scrollParent[0].clientHeight;
							if(ch !== _prevClientHeight){
								reinitialize();
								if(!$scope.$root.$$phase)
									$scope.$digest();
							}
							_prevClientHeight = ch;
						}

						$scope.$watch(function(){
							if(typeof window.requestAnimationFrame === "function")
								window.requestAnimationFrame(reinitOnClientHeightChange);
							else
								reinitOnClientHeightChange();
						});

						function updateInnerCollection(){
							$scope.startIndex = Math.max(
								Math.floor(
									($scrollParent[0].scrollTop) / $scope.elementHeight + $scope.excess/2
								) - $scope.excess,
								0
							);
							$scope.endIndex = Math.min(
								$scope.startIndex + Math.ceil(
									$scrollParent[0].clientHeight / $scope.elementHeight
								) + $scope.excess,
								originalLength
							);

							var digestRequired = $scope.startIndex !== _prevStartIndex || $scope.endIndex !== _prevEndIndex;

							if(digestRequired)
								$scope[collectionName] = originalCollection.slice($scope.startIndex, $scope.endIndex);

							_prevStartIndex = $scope.startIndex;
							_prevEndIndex = $scope.endIndex;

							return digestRequired;
						}
					}
				};
			}
		};
	}]);

	$('head').append([
		''
	].join(''));
})(window, window.angular);<commit_msg>mac os wheel helper bugfix<commit_after>(function(window, angular){
	'use strict';

	// DESCRIPTION:
	// vsRepeat directive stands for Virtual Scroll Repeat. It turns a standard ngRepeated set of elements in a scrollable container
	// into a component, where the user thinks he has all the elements rendered and all he needs to do is scroll (without any kind of
	// pagination - which most users loath) and at the same time the browser isn't overloaded by that many elements/angular bindings etc.
	// The directive renders only so many elements that can fit into current container's clientHeight.

	// LIMITATIONS:
	// - current version works only for vertically stacked elements
	// - current version only supports an Array as a right-hand-side object for ngRepeat
	// - all rendered elements must have the same predefined height

	// USAGE:
	// In order to use the vsRepeat directive you need to measure the single element's height (including all paddings and margins).
	// You can use any kind of developer tools you like. Let's say that that height is 50px.
	// example:
	//

	//

	//
	//

	//

	//
	// - the vsRepeat directive must be applied to a direct parent of an element with ngRepeat
	// - the value of vsRepeat attribute is the single element's height measured in pixels

	// OPTIONAL PARAMETERS (attributes):
	// vs-scroll-parent="selector" - selector to the scrollable container. The directive will look for a closest parent matching
	// 								 the given selector (defaults to the current element)
	// vs-top-offset="value" - top offset in pixels (defaults to 0)
	// vs-excess="value" - an integer number representing the number of elements to be rendered outside of the current container's viewport
	// 					   (defaults to 2)

	// EVENTS:
	// - 'vsRepeatTrigger' - an event the directive listens for to manually trigger reinitialization
	// - 'vsRepeatReinitialized' - an event the directive emits upon reinitialization done

	var isMacOS = navigator.appVersion.indexOf("Mac") != -1;
	angular.module('vs-repeat', []).directive('vsRepeat', ['$compile', function($compile){
		return {
			restrict: 'A',
			scope: true,
			compile: function($element, $attrs){
				var childClone = $element.children().eq(0).clone(),
					ngRepeatExpression = childClone.attr('ng-repeat'),
					expressionMatches = /^\s*(\S+)\s+in\s+(\S+)\s*(track\s+by\s+\S+)?/.exec(ngRepeatExpression),
					lhs = expressionMatches[1],
					rhs = expressionMatches[2],
					rhsSuffix = expressionMatches[3],
					collectionName = '$vs_' + rhs,
					originalCollection = [],
					originalLength,
					$wheelHelper,
					$fillElement;

				$element.empty();
				if(!window.getComputedStyle || window.getComputedStyle($element[0]).position !== 'absolute')
					$element.css('position', 'relative');
				return {
					pre: function($scope, $element, $attrs){
						$scope.elementHeight = parseInt($attrs.vsRepeat, 10);
						var $scrollParent = $attrs.vsScrollParent ? $element.closest($attrs.vsScrollParent) : $element;
						$scope.topOffset = $attrs.vsTopOffset ? parseInt($attrs.vsTopOffset, 10) : 0;
						$scope.excess = $attrs.vsExcess ? parseInt($attrs.vsExcess, 10) : 2;

						$scope.$watchCollection(rhs, function(coll){
							originalCollection = coll || [];
							if(!originalCollection || originalCollection.length < 1){
								$scope[collectionName] = [];
								originalLength = 0;
								$fillElement.css({'height': 0});
								return;
							}
							else{
								originalLength = originalCollection.length;
							}
							reinitialize();
						});

						childClone.attr('ng-repeat', lhs + ' in ' + collectionName + (rhsSuffix ? ' ' + rhsSuffix : ''))
								.attr('ng-style', '{top: ($index + startIndex) * elementHeight + topOffset}')
								.attr('style', 'position: absolute;');
						$compile(childClone)($scope);
						$element.append(childClone);

						$fillElement = $('

')
							.prependTo($element)
							.css({'position':'relative'});

						var _prevMouse = {};
						if(isMacOS){
							$wheelHelper = $('

')
								.appendTo($fillElement)
								.on('wheel', function(e){
									e.preventDefault();
									e.stopPropagation();
									$scrollParent[0].scrollTop += e.originalEvent.deltaY;
								}).on('mousemove', function(e){
									if(_prevMouse.x !== e.clientX || _prevMouse.y !== e.clientY)
										$(this).hide();
									_prevMouse = {
										x: e.clientX,
										y: e.clientY
									};
								}).hide();
						}

						$scope.startIndex = 0;
						$scope.endIndex = 0;

						$scrollParent.on('scroll.vs-repeat', function scrollHandler(e){
							if(updateInnerCollection())
								$scope.$apply();
						});

						if(isMacOS){
							$scrollParent.on('wheel.vs-repeat', wheelHandler);
						}
						function wheelHandler(e){
							e.preventDefault();
							$wheelHelper.show();
						}

						function onWindowResize(){
							if(updateInnerCollection())
								$scope.$apply();
						}

						$(window).on('resize', onWindowResize);

						$scope.$on('$destroy', function(){
							$(window).off('resize', onWindowResize);
						});

						$scope.$on('vsRepeatTrigger', reinitialize);
						var _prevStartIndex,
							_prevEndIndex;
						function reinitialize(){
							_prevStartIndex = void 0;
							_prevEndIndex = void 0;
							updateInnerCollection();
							$fillElement.css({'height': $scope.elementHeight*originalLength});
							$scope.$emit('vsRepeatReinitialized');
						}

						var _prevClientHeight;
						function reinitOnClientHeightChange(){
							var ch = $scrollParent[0].clientHeight;
							if(ch !== _prevClientHeight){
								reinitialize();
								if(!$scope.$root.$$phase)
									$scope.$digest();
							}
							_prevClientHeight = ch;
						}

						$scope.$watch(function(){
							if(typeof window.requestAnimationFrame === "function")
								window.requestAnimationFrame(reinitOnClientHeightChange);
							else
								reinitOnClientHeightChange();
						});

						function updateInnerCollection(){
							$scope.startIndex = Math.max(
								Math.floor(
									($scrollParent[0].scrollTop) / $scope.elementHeight + $scope.excess/2
								) - $scope.excess,
								0
							);
							$scope.endIndex = Math.min(
								$scope.startIndex + Math.ceil(
									$scrollParent[0].clientHeight / $scope.elementHeight
								) + $scope.excess,
								originalLength
							);

							var digestRequired = $scope.startIndex !== _prevStartIndex || $scope.endIndex !== _prevEndIndex;

							if(digestRequired)
								$scope[collectionName] = originalCollection.slice($scope.startIndex, $scope.endIndex);

							_prevStartIndex = $scope.startIndex;
							_prevEndIndex = $scope.endIndex;

							return digestRequired;
						}
					}
				};
			}
		};
	}]);

	$('head').append([
		''
	].join(''));
})(window, window.angular);<|endoftext|>


<commit_before>// Generated on 2014-10-30 using generator-angular 0.9.8
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  // Time how long tasks take. Can help when optimizing build times
  require('time-grunt')(grunt);

  // Configurable paths for the application
  var appConfig = {
    app: require('./bower.json').appPath || 'app',
    dist: 'dist'
  };

  // Define the configuration for all the tasks
  grunt.initConfig({

    // Project settings
    yeoman: appConfig,

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      js: {
        files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
        tasks: ['newer:jshint:all'],
        options: {
          livereload: '<%= connect.options.livereload %>'
        }
      },
      jsTest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['newer:jshint:test', 'karma']
      },
      compass: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        tasks: ['compass:server', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },

    // The actual grunt server settings
    connect: {
      options: {
        port: 9000,
        // Change this to '0.0.0.0' to access the server from outside.
        hostname: 'localhost',
        livereload: 35729
      },
      proxies: [
        {
          context: '/api',
          host: 'localhost',
          port: '3000',
          https: false,
          changeOrigin: true,
          xforward: true
        }
      ],
      livereload: {
        options: {
          open: true,
          base: [
            '.tmp',
            '<%= yeoman.app %>'
          ],
          middleware: function (connect, options) {
            if (!Array.isArray(options.base)) {
              options.base = [options.base];
            }

            // Setup the proxy
            var middlewares = [require('grunt-connect-proxy/lib/utils').proxyRequest];

            // Serve static files.
            options.base.forEach(function(base) {
              middlewares.push(connect.static(base));
            });
            middlewares.push(connect().use(
              '/bower_components',
              connect.static('./bower_components')
            ));

            // Make directory browse-able.
            var directory = options.directory || options.base[options.base.length - 1];
            middlewares.push(connect.directory(directory));

            return middlewares;
          }
        }
      },
      test: {
        options: {
          port: 9001,
          middleware: function (connect) {
            return [
              connect.static('.tmp'),
              connect.static('test'),
              connect().use(
                '/bower_components',
                connect.static('./bower_components')
              ),
              connect.static(appConfig.app)
            ];
          }
        }
      },
      dist: {
        options: {
          open: true,
          base: '<%= yeoman.dist %>'
        }
      }
    },

    // Make sure code styles are up to par and there are no obvious mistakes
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: {
        src: [
          'Gruntfile.js',
          '<%= yeoman.app %>/scripts/{,*/}*.js'
        ]
      },
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/spec/{,*/}*.js']
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%= yeoman.dist %>/{,*/}*',
            '!<%= yeoman.dist %>/.git*'
          ]
        }]
      },
      server: '.tmp'
    },

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['last 3 version']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      }
    },

    // Automatically inject Bower components into the app
    wiredep: {
      app: {
        src: ['<%= yeoman.app %>/index.html'],
        ignorePath:  /\.\.\//
      },
      sass: {
        src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        ignorePath: /(\.\.\/){1,2}bower_components\//
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    compass: {
      options: {
        sassDir: '<%= yeoman.app %>/styles',
        cssDir: '.tmp/styles',
        generatedImagesDir: '.tmp/images/generated',
        imagesDir: '<%= yeoman.app %>/images',
        javascriptsDir: '<%= yeoman.app %>/scripts',
        fontsDir: '<%= yeoman.app %>/styles/fonts',
        importPath: './bower_components',
        httpImagesPath: '/images',
        httpGeneratedImagesPath: '/images/generated',
        httpFontsPath: '/styles/fonts',
        relativeAssets: false,
        assetCacheBuster: false,
        raw: 'Sass::Script::Number.precision = 10\n'
      },
      dist: {
        options: {
          generatedImagesDir: '<%= yeoman.dist %>/images/generated'
        }
      },
      server: {
        options: {
          debugInfo: true
        }
      }
    },

    // Renames files for browser caching purposes
    filerev: {
      dist: {
        src: [
          '<%= yeoman.dist %>/scripts/{,*/}*.js',
          '<%= yeoman.dist %>/styles/{,*/}*.css',
          '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
          '<%= yeoman.dist %>/styles/fonts/*'
        ]
      }
    },

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      html: '<%= yeoman.app %>/index.html',
      options: {
        dest: '<%= yeoman.dist %>',
        flow: {
          html: {
            steps: {
              js: ['concat', 'uglifyjs'],
              css: ['cssmin']
            },
            post: {}
          }
        }
      }
    },

    // Performs rewrites based on filerev and the useminPrepare configuration
    usemin: {
      html: ['<%= yeoman.dist %>/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
      options: {
        assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/images']
      }
    },

    // The following *-min tasks will produce minified files in the dist folder
    // By default, your `index.html`'s <!-- Usemin block --> will take care of
    // minification. These next options are pre-configured if you do not wish
    // to use the Usemin blocks.
    // cssmin: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/styles/main.css': [
    //         '.tmp/styles/{,*/}*.css'
    //       ]
    //     }
    //   }
    // },
    // uglify: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/scripts/scripts.js': [
    //         '<%= yeoman.dist %>/scripts/scripts.js'
    //       ]
    //     }
    //   }
    // },
    // concat: {
    //   dist: {}
    // },

    imagemin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.{png,jpg,jpeg,gif}',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.svg',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

    htmlmin: {
      dist: {
        options: {
          collapseWhitespace: true,
          conservativeCollapse: true,
          collapseBooleanAttributes: true,
          removeCommentsFromCDATA: true,
          removeOptionalTags: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: ['*.html', 'views/{,*/}*.html'],
          dest: '<%= yeoman.dist %>'
        }]
      }
    },

    // ng-annotate tries to make the code safe for minification automatically
    // by using the Angular long form for dependency injection.
    ngAnnotate: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat/scripts',
          src: ['*.js', '!oldieshim.js'],
          dest: '.tmp/concat/scripts'
        }]
      }
    },

    // Replace Google CDN references
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,png,txt}',
            '.htaccess',
            '*.html',
            'views/{,*/}*.html',
            'images/{,*/}*.{webp}',
            'fonts/*'
          ]
        }, {
          expand: true,
          cwd: '.tmp/images',
          dest: '<%= yeoman.dist %>/images',
          src: ['generated/*']
        }, {
          expand: true,
          cwd: '.',
          src: [
            'bower_components/bootstrap-sass-official/assets/fonts/bootstrap/*',
            'bower_components/font-awesome/fonts/*',
            'bower_components/plupload/js/Moxie.swf',
            'bower_components/plupload/js/Moxie.xap'
          ],
          dest: '<%= yeoman.dist %>'
        }]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },
    // Run some tasks in parallel to speed up the build process
    concurrent: {
      server: [
        'compass:server'
      ],
      test: [
        'compass'
      ],
      dist: [
        'compass:dist',
        'imagemin',
        'svgmin'
      ]
    },

    // Test settings
    karma: {
      unit: {
        configFile: 'test/karma.conf.js',
        singleRun: true
      }
    },

    // angular 정적/동적 변수 할당
    ngconstant: {
      options: {
        name: 'config',
        dest: '<%= yeoman.dist %>/scripts/config.js',
        constants: {
          'ENVIRONMENT': 'production',
          'CACHE_VERSION': '<%= ((new Date()).valueOf().toString()) + (Math.floor((Math.random()*1000000)+1).toString()) %>'
        }
      },
      build: {
      }
    }
  });

  grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'wiredep',
      'concurrent:server',
      'autoprefixer',
      'configureProxies:server',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve:' + target]);
  });

  grunt.registerTask('test', [
    'clean:server',
    'concurrent:test',
    'autoprefixer',
    'connect:test',
    'karma'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'wiredep',
    'useminPrepare',
    'concurrent:dist',
    'autoprefixer',
    'concat',
    'ngAnnotate',
    'copy:dist',
    'ngconstant:build',
    'cdnify',
    'cssmin',
    'uglify',
    'filerev',
    'usemin',
    'htmlmin'
  ]);

  grunt.registerTask('default', [
    'newer:jshint',
    'test',
    'build'
  ]);
};
<commit_msg>add status interval.<commit_after>// Generated on 2014-10-30 using generator-angular 0.9.8
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  // Time how long tasks take. Can help when optimizing build times
  require('time-grunt')(grunt);

  // Configurable paths for the application
  var appConfig = {
    app: require('./bower.json').appPath || 'app',
    dist: 'dist'
  };

  // Define the configuration for all the tasks
  grunt.initConfig({

    // Project settings
    yeoman: appConfig,

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      js: {
        files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
        tasks: ['newer:jshint:all'],
        options: {
          livereload: '<%= connect.options.livereload %>'
        }
      },
      jsTest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['newer:jshint:test', 'karma']
      },
      compass: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        tasks: ['compass:server', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },

    // The actual grunt server settings
    connect: {
      options: {
        port: 9000,
        // Change this to '0.0.0.0' to access the server from outside.
        hostname: 'localhost',
        livereload: 35729
      },
      proxies: [
        {
          context: '/api',
          host: 'localhost',
          port: '3000',
          https: false,
          changeOrigin: true,
          xforward: true
        }
      ],
      livereload: {
        options: {
          open: true,
          base: [
            '.tmp',
            '<%= yeoman.app %>'
          ],
          middleware: function (connect, options) {
            if (!Array.isArray(options.base)) {
              options.base = [options.base];
            }

            // Setup the proxy
            var middlewares = [require('grunt-connect-proxy/lib/utils').proxyRequest];

            // Serve static files.
            options.base.forEach(function(base) {
              middlewares.push(connect.static(base));
            });
            middlewares.push(connect().use(
              '/bower_components',
              connect.static('./bower_components')
            ));

            // Make directory browse-able.
            var directory = options.directory || options.base[options.base.length - 1];
            middlewares.push(connect.directory(directory));

            return middlewares;
          }
        }
      },
      test: {
        options: {
          port: 9001,
          middleware: function (connect) {
            return [
              connect.static('.tmp'),
              connect.static('test'),
              connect().use(
                '/bower_components',
                connect.static('./bower_components')
              ),
              connect.static(appConfig.app)
            ];
          }
        }
      },
      dist: {
        options: {
          open: true,
          base: '<%= yeoman.dist %>'
        }
      }
    },

    // Make sure code styles are up to par and there are no obvious mistakes
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: {
        src: [
          'Gruntfile.js',
          '<%= yeoman.app %>/scripts/{,*/}*.js'
        ]
      },
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/spec/{,*/}*.js']
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%= yeoman.dist %>/{,*/}*',
            '!<%= yeoman.dist %>/.git*'
          ]
        }]
      },
      server: '.tmp'
    },

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['last 3 version']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      }
    },

    // Automatically inject Bower components into the app
    wiredep: {
      app: {
        src: ['<%= yeoman.app %>/index.html'],
        ignorePath:  /\.\.\//
      },
      sass: {
        src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        ignorePath: /(\.\.\/){1,2}bower_components\//
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    compass: {
      options: {
        sassDir: '<%= yeoman.app %>/styles',
        cssDir: '.tmp/styles',
        generatedImagesDir: '.tmp/images/generated',
        imagesDir: '<%= yeoman.app %>/images',
        javascriptsDir: '<%= yeoman.app %>/scripts',
        fontsDir: '<%= yeoman.app %>/styles/fonts',
        importPath: './bower_components',
        httpImagesPath: '/images',
        httpGeneratedImagesPath: '/images/generated',
        httpFontsPath: '/styles/fonts',
        relativeAssets: false,
        assetCacheBuster: false,
        raw: 'Sass::Script::Number.precision = 10\n'
      },
      dist: {
        options: {
          generatedImagesDir: '<%= yeoman.dist %>/images/generated'
        }
      },
      server: {
        options: {
          debugInfo: true
        }
      }
    },

    // Renames files for browser caching purposes
    filerev: {
      dist: {
        src: [
          '<%= yeoman.dist %>/scripts/{,*/}*.js',
          '<%= yeoman.dist %>/styles/{,*/}*.css',
          '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
          '<%= yeoman.dist %>/styles/fonts/*'
        ]
      }
    },

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      html: '<%= yeoman.app %>/index.html',
      options: {
        dest: '<%= yeoman.dist %>',
        flow: {
          html: {
            steps: {
              js: ['concat', 'uglifyjs'],
              css: ['cssmin']
            },
            post: {}
          }
        }
      }
    },

    // Performs rewrites based on filerev and the useminPrepare configuration
    usemin: {
      html: ['<%= yeoman.dist %>/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
      options: {
        assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/images']
      }
    },

    // The following *-min tasks will produce minified files in the dist folder
    // By default, your `index.html`'s <!-- Usemin block --> will take care of
    // minification. These next options are pre-configured if you do not wish
    // to use the Usemin blocks.
    // cssmin: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/styles/main.css': [
    //         '.tmp/styles/{,*/}*.css'
    //       ]
    //     }
    //   }
    // },
    // uglify: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/scripts/scripts.js': [
    //         '<%= yeoman.dist %>/scripts/scripts.js'
    //       ]
    //     }
    //   }
    // },
    // concat: {
    //   dist: {}
    // },

    imagemin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.{png,jpg,jpeg,gif}',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.svg',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

    htmlmin: {
      dist: {
        options: {
          collapseWhitespace: true,
          conservativeCollapse: true,
          collapseBooleanAttributes: true,
          removeCommentsFromCDATA: true,
          removeOptionalTags: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: ['*.html', 'views/{,*/}*.html'],
          dest: '<%= yeoman.dist %>'
        }]
      }
    },

    // ng-annotate tries to make the code safe for minification automatically
    // by using the Angular long form for dependency injection.
    ngAnnotate: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat/scripts',
          src: ['*.js', '!oldieshim.js'],
          dest: '.tmp/concat/scripts'
        }]
      }
    },

    // Replace Google CDN references
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,png,txt}',
            '.htaccess',
            '*.html',
            'views/{,*/}*.html',
            'images/{,*/}*.{webp}',
            'fonts/*'
          ]
        }, {
          expand: true,
          cwd: '.tmp/images',
          dest: '<%= yeoman.dist %>/images',
          src: ['generated/*']
        }, {
          expand: true,
          cwd: '.',
          src: [
            'bower_components/bootstrap-sass-official/assets/fonts/bootstrap/*',
            'bower_components/font-awesome/fonts/*',
            'bower_components/plupload/js/Moxie.swf',
            'bower_components/plupload/js/Moxie.xap'
          ],
          dest: '<%= yeoman.dist %>'
        }]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },
    // Run some tasks in parallel to speed up the build process
    concurrent: {
      server: [
        'compass:server'
      ],
      test: [
        'compass'
      ],
      dist: [
        'compass:dist',
        'imagemin',
        'svgmin'
      ]
    },

    // Test settings
    karma: {
      unit: {
        configFile: 'test/karma.conf.js',
        singleRun: true
      }
    },

    // angular 정적/동적 변수 할당
    ngconstant: {
      options: {
        name: 'config',
        dest: '<%= yeoman.dist %>/scripts/config.js',
        constants: {
          'ENVIRONMENT': 'production',
          'CACHE_VERSION': '<%= ((new Date()).valueOf().toString()) + (Math.floor((Math.random()*1000000)+1).toString()) %>',
          'STATUS_INTERVAL': '60000'
        }
      },
      build: {
      }
    }
  });

  grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'wiredep',
      'concurrent:server',
      'autoprefixer',
      'configureProxies:server',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve:' + target]);
  });

  grunt.registerTask('test', [
    'clean:server',
    'concurrent:test',
    'autoprefixer',
    'connect:test',
    'karma'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'wiredep',
    'useminPrepare',
    'concurrent:dist',
    'autoprefixer',
    'concat',
    'ngAnnotate',
    'copy:dist',
    'ngconstant:build',
    'cdnify',
    'cssmin',
    'uglify',
    'filerev',
    'usemin',
    'htmlmin'
  ]);

  grunt.registerTask('default', [
    'newer:jshint',
    'test',
    'build'
  ]);
};
<|endoftext|>


<commit_before>$(function(){
	// search control
	$('.leaflet-control-geocoder').tooltip({placement:'right', delay:400, title: function(){ return "Search for an address"}});

	map.on('drawControlReady', function(){
		// delete points control
	 	$('.leaflet-right a.leaflet-draw-edit-remove').tooltip({placement:'left', delay: 400, title: function(){return 'Delete user points'}});
		// All left side controls
		$('.leaflet-left .leaflet-control a').tooltip({placement:'right', delay: 400});
	});
});
<commit_msg>Delete troublesome admin-only tooltip<commit_after>$(function(){
	// search control
	$('.leaflet-control-geocoder').tooltip({placement:'right', delay:400, title: function(){ return "Search for an address"}});

	map.on('drawControlReady', function(){
		// All left side controls
		$('.leaflet-left .leaflet-control a').tooltip({placement:'right', delay: 400});
	});
});
<|endoftext|>


<commit_before>/**
* XMLHttpRequest.js Copyright (C) 2011 Sergey Ilinsky (http://www.ilinsky.com)
*
* This work is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This work is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

(function () {

    // Save reference to earlier defined object implementation (if any)
    var oXMLHttpRequest = window.XMLHttpRequest;

    // Define on browser type
    var bGecko  = !!window.controllers;
    var bIE     = !!window.document.namespaces;
    var bIE7    = bIE && window.navigator.userAgent.match(/MSIE 7.0/);

    // Enables "XMLHttpRequest()" call next to "new XMLHttpRequest()"
    function fXMLHttpRequest() {
        if (!window.XMLHttpRequest || bIE7) {
            this._object = new window.ActiveXObject("Microsoft.XMLHTTP");
        } // only use initial XHR object internally if current reference to XHR is our normalized replacement
        else if (window.XMLHttpRequest.isNormalizedObject) {
            this._object = new oXMLHttpRequest();
        } // otherwise use whatever is currently referenced by XMLHttpRequest
        else {
            this._object = new window.XMLHttpRequest();
        }
        this._listeners = [];
    }

    // Constructor
    function cXMLHttpRequest() {
        return new fXMLHttpRequest();
    }
    cXMLHttpRequest.prototype = fXMLHttpRequest.prototype;

    // BUGFIX: Firefox with Firebug installed would break pages if not executed
    if (bGecko && oXMLHttpRequest.wrapped) {
        cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;
    }

    // Marker to be able to easily identify our object
    cXMLHttpRequest.isNormalizedObject = true;

    // Constants
    cXMLHttpRequest.UNSENT            = 0;
    cXMLHttpRequest.OPENED            = 1;
    cXMLHttpRequest.HEADERS_RECEIVED  = 2;
    cXMLHttpRequest.LOADING           = 3;
    cXMLHttpRequest.DONE              = 4;

    // Interface level constants
    cXMLHttpRequest.prototype.UNSENT            = cXMLHttpRequest.UNSENT;
    cXMLHttpRequest.prototype.OPENED            = cXMLHttpRequest.OPENED;
    cXMLHttpRequest.prototype.HEADERS_RECEIVED  = cXMLHttpRequest.HEADERS_RECEIVED;
    cXMLHttpRequest.prototype.LOADING           = cXMLHttpRequest.LOADING;
    cXMLHttpRequest.prototype.DONE              = cXMLHttpRequest.DONE;

    // Public Properties
    cXMLHttpRequest.prototype.readyState    = cXMLHttpRequest.UNSENT;
    cXMLHttpRequest.prototype.responseText  = '';
    cXMLHttpRequest.prototype.responseXML   = null;
    cXMLHttpRequest.prototype.status        = 0;
    cXMLHttpRequest.prototype.statusText    = '';

    // Priority proposal
    cXMLHttpRequest.prototype.priority    = "NORMAL";

    // Instance-level Events Handlers
    cXMLHttpRequest.prototype.onreadystatechange  = null;

    // Class-level Events Handlers
    cXMLHttpRequest.onreadystatechange  = null;
    cXMLHttpRequest.onopen              = null;
    cXMLHttpRequest.onsend              = null;
    cXMLHttpRequest.onabort             = null;

    // Public Methods
    cXMLHttpRequest.prototype.open  = function(sMethod, sUrl, bAsync, sUser, sPassword) {
        // http://www.w3.org/TR/XMLHttpRequest/#the-open-method
        var sLowerCaseMethod = sMethod.toLowerCase();
        if (sLowerCaseMethod == "connect" || sLowerCaseMethod == "trace" || sLowerCaseMethod == "track") {
            // Using a generic error and an int - not too sure all browsers support correctly
            // http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#securityerror, so, this is safer
            // XXX should do better than that, but this is OT to XHR.
            throw new Error(18);
        }

        // Delete headers, required when object is reused
        delete this._headers;

        // When bAsync parameter value is omitted, use true as default
        if (arguments.length < 3) {
            bAsync  = true;
        }

        // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
        this._async   = bAsync;

        // Set the onreadystatechange handler
        var oRequest  = this;
        var nState    = this.readyState;
        var fOnUnload = null;

        // BUGFIX: IE - memory leak on page unload (inter-page leak)
        if (bIE && bAsync) {
            fOnUnload = function() {
                if (nState != cXMLHttpRequest.DONE) {
                    fCleanTransport(oRequest);
                    // Safe to abort here since onreadystatechange handler removed
                    oRequest.abort();
                }
            };
            window.attachEvent("onunload", fOnUnload);
        }

        // Add method sniffer
        if (cXMLHttpRequest.onopen) {
            cXMLHttpRequest.onopen.apply(this, arguments);
        }

        if (arguments.length > 4) {
            this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
        } else if (arguments.length > 3) {
            this._object.open(sMethod, sUrl, bAsync, sUser);
        } else {
            this._object.open(sMethod, sUrl, bAsync);
        }

        this.readyState = cXMLHttpRequest.OPENED;
        fReadyStateChange(this);

        this._object.onreadystatechange = function() {
            if (bGecko && !bAsync) {
                return;
            }

            // Synchronize state
            oRequest.readyState   = oRequest._object.readyState;
            fSynchronizeValues(oRequest);

            // BUGFIX: Firefox fires unnecessary DONE when aborting
            if (oRequest._aborted) {
                // Reset readyState to UNSENT
                oRequest.readyState = cXMLHttpRequest.UNSENT;

                // Return now
                return;
            }

            if (oRequest.readyState == cXMLHttpRequest.DONE) {
                // Free up queue
                delete oRequest._data;

                // Uncomment these lines for bAsync
                /**
                 * if (bAsync) {
                 *  fQueue_remove(oRequest);
                 * }
                 */

                fCleanTransport(oRequest);

                // Uncomment this block if you need a fix for IE cache
                /**
                 * // BUGFIX: IE - cache issue
                 * if (!oRequest._object.getResponseHeader("Date")) {
                 *  // Save object to cache
                 *  oRequest._cached  = oRequest._object;
                 *
                 *  // Instantiate a new transport object
                 *  cXMLHttpRequest.call(oRequest);
                 *
                 *  // Re-send request
                 *  if (sUser) {
                 *      if (sPassword) {
                 *          oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
                 *      } else {
                 *          oRequest._object.open(sMethod, sUrl, bAsync);
                 *      }
                 *
                 *      oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
                 *      // Copy headers set
                 *      if (oRequest._headers) {
                 *          for (var sHeader in oRequest._headers) {
                 *              // Some frameworks prototype objects with functions
                 *              if (typeof oRequest._headers[sHeader] == "string") {
                 *                  oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
                 *              }
                 *          }
                 *      }
                 *      oRequest._object.onreadystatechange = function() {
                 *          // Synchronize state
                 *          oRequest.readyState   = oRequest._object.readyState;
                 *
                 *          if (oRequest._aborted) {
                 *              //
                 *              oRequest.readyState = cXMLHttpRequest.UNSENT;
                 *
                 *              // Return
                 *              return;
                 *          }
                 *
                 *          if (oRequest.readyState == cXMLHttpRequest.DONE) {
                 *              // Clean Object
                 *              fCleanTransport(oRequest);
                 *
                 *              // get cached request
                 *              if (oRequest.status == 304) {
                 *                  oRequest._object  = oRequest._cached;
                 *              }
                 *
                 *              //
                 *              delete oRequest._cached;
                 *
                 *              //
                 *              fSynchronizeValues(oRequest);
                 *
                 *              //
                 *              fReadyStateChange(oRequest);
                 *
                 *              // BUGFIX: IE - memory leak in interrupted
                 *              if (bIE && bAsync) {
                 *                  window.detachEvent("onunload", fOnUnload);
                 *              }
                 *
                 *          }
                 *      };
                 *      oRequest._object.send(null);
                 *
                 *      // Return now - wait until re-sent request is finished
                 *      return;
                 *  };
                 */

                // BUGFIX: IE - memory leak in interrupted
                if (bIE && bAsync) {
                    window.detachEvent("onunload", fOnUnload);
                }

                // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
                if (nState != oRequest.readyState) {
                    fReadyStateChange(oRequest);
                }

                nState  = oRequest.readyState;
            }
        };
    };

    cXMLHttpRequest.prototype.send = function(vData) {
        // Add method sniffer
        if (cXMLHttpRequest.onsend) {
            cXMLHttpRequest.onsend.apply(this, arguments);
        }

        if (!arguments.length) {
            vData = null;
        }

        // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
        // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
        // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
        if (vData && vData.nodeType) {
            vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
            if (!this._headers["Content-Type"]) {
                this._object.setRequestHeader("Content-Type", "application/xml");
            }
        }

        this._data = vData;

        /**
         * // Add to queue
         * if (this._async) {
         *  fQueue_add(this);
         * } else { */
        fXMLHttpRequest_send(this);
         /**
         * }
         */
    };

    cXMLHttpRequest.prototype.abort = function() {
        // Add method sniffer
        if (cXMLHttpRequest.onabort) {
            cXMLHttpRequest.onabort.apply(this, arguments);
        }

        // BUGFIX: Gecko - unnecessary DONE when aborting
        if (this.readyState > cXMLHttpRequest.UNSENT) {
            this._aborted = true;
        }

        this._object.abort();

        // BUGFIX: IE - memory leak
        fCleanTransport(this);

        this.readyState = cXMLHttpRequest.UNSENT;

        delete this._data;

        /* if (this._async) {
        *   fQueue_remove(this);
        * }
        */
    };

    cXMLHttpRequest.prototype.getAllResponseHeaders = function() {
        return this._object.getAllResponseHeaders();
    };

    cXMLHttpRequest.prototype.getResponseHeader = function(sName) {
        return this._object.getResponseHeader(sName);
    };

    cXMLHttpRequest.prototype.setRequestHeader  = function(sName, sValue) {
        // BUGFIX: IE - cache issue
        if (!this._headers) {
            this._headers = {};
        }

        this._headers[sName]  = sValue;

        return this._object.setRequestHeader(sName, sValue);
    };

    // EventTarget interface implementation
    cXMLHttpRequest.prototype.addEventListener  = function(sName, fHandler, bUseCapture) {
        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) {
            if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) {
                return;
            }
        }

        // Add listener
        this._listeners.push([sName, fHandler, bUseCapture]);
    };

    cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {
        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) {
            if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) {
                break;
            }
        }

        // Remove listener
        if (oListener) {
            this._listeners.splice(nIndex, 1);
        }
    };

    cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) {
        var oEventPseudo  = {
            'type':             oEvent.type,
            'target':           this,
            'currentTarget':    this,
            'eventPhase':       2,
            'bubbles':          oEvent.bubbles,
            'cancelable':       oEvent.cancelable,
            'timeStamp':        oEvent.timeStamp,
            'stopPropagation':  function() {},  // There is no flow
            'preventDefault':   function() {},  // There is no default action
            'initEvent':        function() {}   // Original event object should be initialized
        };

        // Execute onreadystatechange
        if (oEventPseudo.type == "readystatechange" && this.onreadystatechange) {
            (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);
        }

        // Execute listeners
        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) {
            if (oListener[0] == oEventPseudo.type && !oListener[2]) {
                (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);
            }
        }

    };

    //
    cXMLHttpRequest.prototype.toString  = function() {
        return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
    };

    cXMLHttpRequest.toString  = function() {
        return '[' + "XMLHttpRequest" + ']';
    };

    /**
     * // Queue manager
     * var oQueuePending = {"CRITICAL":[],"HIGH":[],"NORMAL":[],"LOW":[],"LOWEST":[]},
     * aQueueRunning = [];
     * function fQueue_add(oRequest) {
     *  oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : "NORMAL"].push(oRequest);
     *  //
     *  setTimeout(fQueue_process);
     * };
     *
     * function fQueue_remove(oRequest) {
     *  for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++)
     *  if (bFound) {
     *      aQueueRunning[nIndex - 1] = aQueueRunning[nIndex];
     *  } else {
     *      if (aQueueRunning[nIndex] == oRequest) {
     *          bFound  = true;
     *      }
     * }
     *
     *  if (bFound) {
     *      aQueueRunning.length--;
     *  }
     *
     *
     *  //
     *  setTimeout(fQueue_process);
     * };
     *
     * function fQueue_process() {
     * if (aQueueRunning.length < 6) {
     * for (var sPriority in oQueuePending) {
     * if (oQueuePending[sPriority].length) {
     * var oRequest  = oQueuePending[sPriority][0];
     * oQueuePending[sPriority]  = oQueuePending[sPriority].slice(1);
     * //
     * aQueueRunning.push(oRequest);
     * // Send request
     * fXMLHttpRequest_send(oRequest);
     * break;
     * }
     * }
     * }
     * };
     */

    // Helper function
    function fXMLHttpRequest_send(oRequest) {
        oRequest._object.send(oRequest._data);

        // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
        if (bGecko && !oRequest._async) {
            oRequest.readyState = cXMLHttpRequest.OPENED;

            // Synchronize state
            fSynchronizeValues(oRequest);

            // Simulate missing states
            while (oRequest.readyState < cXMLHttpRequest.DONE) {
                oRequest.readyState++;
                fReadyStateChange(oRequest);
                // Check if we are aborted
                if (oRequest._aborted) {
                    return;
                }
            }
        }
    }

    function fReadyStateChange(oRequest) {
        // Sniffing code
        if (cXMLHttpRequest.onreadystatechange){
            cXMLHttpRequest.onreadystatechange.apply(oRequest);
        }

        // Fake event
        oRequest.dispatchEvent({
            'type':       "readystatechange",
            'bubbles':    false,
            'cancelable': false,
            'timeStamp':  new Date().getTime()
        });
    }

    function fGetDocument(oRequest) {
        var oDocument = oRequest.responseXML;
        var sResponse = oRequest.responseText;
        // Try parsing responseText
        if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
            oDocument = new window.ActiveXObject("Microsoft.XMLDOM");
            oDocument.async       = false;
            oDocument.validateOnParse = false;
            oDocument.loadXML(sResponse);
        }

        // Check if there is no error in document
        if (oDocument){
            if ((bIE && oDocument.parseError !== 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror")) {
                return null;
            }
        }
        return oDocument;
    }

    function fSynchronizeValues(oRequest) {
        try { oRequest.responseText = oRequest._object.responseText;  } catch (e) {}
        try { oRequest.responseXML  = fGetDocument(oRequest._object); } catch (e) {}
        try { oRequest.status       = oRequest._object.status;        } catch (e) {}
        try { oRequest.statusText   = oRequest._object.statusText;    } catch (e) {}
    }

    function fCleanTransport(oRequest) {
        // BUGFIX: IE - memory leak (on-page leak)
        oRequest._object.onreadystatechange = new window.Function();
    }

    // Internet Explorer 5.0 (missing apply)
    if (!window.Function.prototype.apply) {
        window.Function.prototype.apply = function(oRequest, oArguments) {
            if (!oArguments) {
                oArguments  = [];
            }
            oRequest.__func = this;
            oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
            delete oRequest.__func;
        };
    }

    // Register new object with window
    window.XMLHttpRequest = cXMLHttpRequest;

})();
<commit_msg>Delete XMLHttpRequest.js<commit_after><|endoftext|>


<commit_before>var Opbeat = require('./opbeat')

var wrap = function (fn, before, after) {
  return function opbeatInstrumentationWrapper () {
    var args = Array.prototype.slice.call(arguments)

    before.apply(this, args)
    var result = fn.apply(this, args)
    after.apply(this, args)

    return result
  }
}

var instrumentMethod = function (module, fn, transaction, type, prefix) {
  var ref = module[fn]
  var name = prefix ? prefix + fn : fn
  ref.original = module[fn]

  return module[fn] = wrap(module[fn], function () {
    ref.trace = transaction.startTrace(name, type)

  }, function () {
    if (ref.trace) {
      ref.trace.end()
    }
  })
}

var uninstrumentMethod =  function(module, fn) {

  var ref = module[fn]
  if(ref.original) {
    module[fn] = ref.original
  }

}

var getScopeFunctions = function(scope) {

  return Object.keys(scope).map(function (property) {
    var ref = scope[property]
    if (typeof ref === 'function') {
      return {
        scope: scope,
        property: property,
        ref: ref
      }
    } else {
      return null;
    }
  }).filter(function(item) {
    return item !== null
  })

}

function ngOpbeatProvider () {
  this.config = function config (properties) {
    Opbeat.config(properties)
  }

  this.install = function install () {
    Opbeat.install()
  }

  this.$get = [function () {
    return {
      captureException: function captureException (exception, cause) {
        Opbeat.captureException(exception, cause)
      },

      setUserContext: function setUser (user) {
        Opbeat.setUserContext(user)
      },

      setExtraContext: function setExtraContext (data) {
        Opbeat.setExtraContext(data)
      }
    }
  }]
}

function $opbeatErrorProvider ($provide ) {
  $provide.decorator('$exceptionHandler', ['$delegate', '$opbeat', function $ExceptionHandlerDecorator ($delegate, $opbeat) {
    return function $ExceptionHandler (exception, cause) {
      $opbeat.captureException(exception)
      return $delegate(exception, cause)
    }
  }])
}

function $opbeatInstrumentationProvider ($provide ) {
  $provide.decorator('$http', function ($delegate, $rootScope, $location) {
    var wrapper = function () {
      return $delegate.apply($delegate, arguments)
    }

    Object.keys($delegate).filter(function (key) {
      return (typeof $delegate[key] === 'function')
    }).forEach(function (key) {
      wrapper[key] = function () {
        var transaction = $rootScope._opbeatTransactions && $rootScope._opbeatTransactions[$location.absUrl()]
        var fn = instrumentMethod($delegate, key, transaction, 'http', '$http.')
        return fn.apply($delegate, arguments)
      }
    })

    return wrapper
  })

  $provide.decorator('$controller', function ($delegate, $location, $rootScope) {
    $rootScope._opbeatTransactions = {}

    $rootScope.$on('$routeChangeStart', function (e, current, previous, rejection) {
      var routeControllerTarget = current.controller;
      var transaction = $rootScope._opbeatTransactions[$location.absUrl()]
      if (!transaction) {
        transaction = Opbeat.startTransaction('angular.controller.'+routeControllerTarget, 'ext.controller')
        transaction.metadata.controllerName = routeControllerTarget

        $rootScope._opbeatTransactions[$location.absUrl()] = transaction
      }
    })

    return function () {
      var transaction = $rootScope._opbeatTransactions[$location.absUrl()]

      var args = Array.prototype.slice.call(arguments)
      var controllerName
      var controllerScope

      if (typeof args[0] === 'string') {
        controllerName = args[0]
      } else if (typeof args[0] === 'function') {
        controllerName = args[0].name
      }

      if (typeof args[1] === 'object') {
        controllerScope = args[1].$scope
      }

      if (controllerName && transaction && transaction.metadata.controllerName === controllerName) {
        console.log('opbeat.angular.controller', controllerName, controllerScope)

        if (controllerScope) {

          // Instrument scope functions
          getScopeFunctions(controllerScope).forEach(function (funcScope) {
            instrumentMethod(funcScope.scope, funcScope.property, transaction, 'app.controller')
          })

          controllerScope.$on('$destroy', function () {
            console.log('opbeat.angular.controller.destroy')
          })

          controllerScope.$on('$viewContentLoaded', function (event) {
            console.log('opbeat.angular.controller.$viewContentLoaded')

            if (controllerScope._opbeatTransaction) {
            }
          })

        }
      }

      var result = $delegate.apply(this, args)

      if (controllerName && transaction && transaction.metadata.controllerName === controllerName) {

        // Transaction clean up
        transaction.end()
        $rootScope._opbeatTransactions[$location.absUrl()] = null

        if (controllerScope) {
          // Uninstrument scope functions
          getScopeFunctions(controllerScope).forEach(function (funcScope) {
            uninstrumentMethod(funcScope.scope, funcScope.property)
          })
        }

        console.log('opbeat.decorator.controller.end')
      }

      return result

    }
  })

}

angular.module('ngOpbeat', [])
  .provider('$opbeat', ngOpbeatProvider)
  .config(['$provide', $opbeatErrorProvider])
  .config(['$provide', $opbeatInstrumentationProvider])

angular.module('angular-opbeat', ['ngOpbeat'])
<commit_msg>Cleaning<commit_after>var Opbeat = require('./opbeat')

var wrap = function (fn, before, after) {
  return function opbeatInstrumentationWrapper () {
    var args = Array.prototype.slice.call(arguments)

    before.apply(this, args)
    var result = fn.apply(this, args)
    after.apply(this, args)

    return result
  }
}

var instrumentMethod = function (module, fn, transaction, type, prefix) {
  var ref = module[fn]
  var name = prefix ? prefix + fn : fn
  ref.original = module[fn]

  return module[fn] = wrap(module[fn], function () {
    ref.trace = transaction.startTrace(name, type)

  }, function () {
    if (ref.trace) {
      ref.trace.end()
    }
  })
}

var uninstrumentMethod =  function(module, fn) {

  var ref = module[fn]
  if(ref.original) {
    module[fn] = ref.original
  }

}

var getScopeFunctions = function(scope) {

  return Object.keys(scope).map(function (property) {
    var ref = scope[property]
    if (typeof ref === 'function') {
      return {
        scope: scope,
        property: property,
        ref: ref
      }
    } else {
      return null;
    }
  }).filter(function(item) {
    return item !== null
  })

}

function ngOpbeatProvider () {
  this.config = function config (properties) {
    Opbeat.config(properties)
  }

  this.install = function install () {
    Opbeat.install()
  }

  this.$get = [function () {
    return {
      captureException: function captureException (exception, cause) {
        Opbeat.captureException(exception, cause)
      },

      setUserContext: function setUser (user) {
        Opbeat.setUserContext(user)
      },

      setExtraContext: function setExtraContext (data) {
        Opbeat.setExtraContext(data)
      }
    }
  }]
}

function $opbeatErrorProvider ($provide ) {
  $provide.decorator('$exceptionHandler', ['$delegate', '$opbeat', function $ExceptionHandlerDecorator ($delegate, $opbeat) {
    return function $ExceptionHandler (exception, cause) {
      $opbeat.captureException(exception)
      return $delegate(exception, cause)
    }
  }])
}

function $opbeatInstrumentationProvider ($provide ) {
  $provide.decorator('$http', function ($delegate, $rootScope, $location) {
    var wrapper = function () {
      return $delegate.apply($delegate, arguments)
    }

    Object.keys($delegate).filter(function (key) {
      return (typeof $delegate[key] === 'function')
    }).forEach(function (key) {
      wrapper[key] = function () {
        var transaction = $rootScope._opbeatTransactions && $rootScope._opbeatTransactions[$location.absUrl()]
        var fn = instrumentMethod($delegate, key, transaction, 'http', '$http.')
        return fn.apply($delegate, arguments)
      }
    })

    return wrapper
  })

  $provide.decorator('$controller', function ($delegate, $location, $rootScope) {
    $rootScope._opbeatTransactions = {}

    $rootScope.$on('$routeChangeStart', function (e, current, previous, rejection) {
      var routeControllerTarget = current.controller;
      var transaction = $rootScope._opbeatTransactions[$location.absUrl()]
      if (!transaction) {
        transaction = Opbeat.startTransaction('angular.controller.'+routeControllerTarget, 'ext.controller')
        transaction.metadata.controllerName = routeControllerTarget

        $rootScope._opbeatTransactions[$location.absUrl()] = transaction
      }
    })

    return function () {
      var transaction = $rootScope._opbeatTransactions[$location.absUrl()]

      var args = Array.prototype.slice.call(arguments)
      var controllerName
      var controllerScope

      if (typeof args[0] === 'string') {
        controllerName = args[0]
      } else if (typeof args[0] === 'function') {
        controllerName = args[0].name
      }

      if (typeof args[1] === 'object') {
        controllerScope = args[1].$scope
      }

      if (controllerName && transaction && transaction.metadata.controllerName === controllerName) {
        console.log('opbeat.angular.controller', controllerName, controllerScope)

        if (controllerScope) {

          // Instrument scope functions
          getScopeFunctions(controllerScope).forEach(function (funcScope) {
            instrumentMethod(funcScope.scope, funcScope.property, transaction, 'app.controller')
          })

          controllerScope.$on('$destroy', function () {
            console.log('opbeat.angular.controller.destroy')
          })

          controllerScope.$on('$viewContentLoaded', function (event) {
            console.log('opbeat.angular.controller.$viewContentLoaded')
          })

        }
      }

      var result = $delegate.apply(this, args)

      if (controllerName && transaction && transaction.metadata.controllerName === controllerName) {

        // Transaction clean up
        transaction.end()
        $rootScope._opbeatTransactions[$location.absUrl()] = null

        if (controllerScope) {
          // Uninstrument scope functions
          getScopeFunctions(controllerScope).forEach(function (funcScope) {
            uninstrumentMethod(funcScope.scope, funcScope.property)
          })
        }

        console.log('opbeat.decorator.controller.end')
      }

      return result
    }
  })

}

angular.module('ngOpbeat', [])
  .provider('$opbeat', ngOpbeatProvider)
  .config(['$provide', $opbeatErrorProvider])
  .config(['$provide', $opbeatInstrumentationProvider])

angular.module('angular-opbeat', ['ngOpbeat'])
<|endoftext|>