| var MutationObserver = window.MutationObserver | 
|   || window.WebKitMutationObserver | 
|   || window.MozMutationObserver; | 
|   | 
| /* | 
|  * Copyright 2012 The Polymer Authors. All rights reserved. | 
|  * Use of this source code is goverened by a BSD-style | 
|  * license that can be found in the LICENSE file. | 
|  */ | 
|   | 
| var WeakMap = window.WeakMap; | 
|   | 
| if (typeof WeakMap === 'undefined') { | 
|   var defineProperty = Object.defineProperty; | 
|   var counter = Date.now() % 1e9; | 
|   | 
|   WeakMap = function() { | 
|     this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__'); | 
|   }; | 
|   | 
|   WeakMap.prototype = { | 
|     set: function(key, value) { | 
|       var entry = key[this.name]; | 
|       if (entry && entry[0] === key) | 
|         entry[1] = value; | 
|       else | 
|         defineProperty(key, this.name, {value: [key, value], writable: true}); | 
|       return this; | 
|     }, | 
|     get: function(key) { | 
|       var entry; | 
|       return (entry = key[this.name]) && entry[0] === key ? | 
|           entry[1] : undefined; | 
|     }, | 
|     'delete': function(key) { | 
|       var entry = key[this.name]; | 
|       if (!entry) return false; | 
|       var hasValue = entry[0] === key; | 
|       entry[0] = entry[1] = undefined; | 
|       return hasValue; | 
|     }, | 
|     has: function(key) { | 
|       var entry = key[this.name]; | 
|       if (!entry) return false; | 
|       return entry[0] === key; | 
|     } | 
|   }; | 
| } | 
|   | 
| var registrationsTable = new WeakMap(); | 
|   | 
| // We use setImmediate or postMessage for our future callback. | 
| var setImmediate = window.msSetImmediate; | 
|   | 
| // Use post message to emulate setImmediate. | 
| if (!setImmediate) { | 
|   var setImmediateQueue = []; | 
|   var sentinel = String(Math.random()); | 
|   window.addEventListener('message', function(e) { | 
|     if (e.data === sentinel) { | 
|       var queue = setImmediateQueue; | 
|       setImmediateQueue = []; | 
|       queue.forEach(function(func) { | 
|         func(); | 
|       }); | 
|     } | 
|   }); | 
|   setImmediate = function(func) { | 
|     setImmediateQueue.push(func); | 
|     window.postMessage(sentinel, '*'); | 
|   }; | 
| } | 
|   | 
| // This is used to ensure that we never schedule 2 callas to setImmediate | 
| var isScheduled = false; | 
|   | 
| // Keep track of observers that needs to be notified next time. | 
| var scheduledObservers = []; | 
|   | 
| /** | 
|  * Schedules |dispatchCallback| to be called in the future. | 
|  * @param {MutationObserver} observer | 
|  */ | 
| function scheduleCallback(observer) { | 
|   scheduledObservers.push(observer); | 
|   if (!isScheduled) { | 
|     isScheduled = true; | 
|     setImmediate(dispatchCallbacks); | 
|   } | 
| } | 
|   | 
| function wrapIfNeeded(node) { | 
|   return window.ShadowDOMPolyfill && | 
|       window.ShadowDOMPolyfill.wrapIfNeeded(node) || | 
|       node; | 
| } | 
|   | 
| function dispatchCallbacks() { | 
|   // http://dom.spec.whatwg.org/#mutation-observers | 
|   | 
|   isScheduled = false; // Used to allow a new setImmediate call above. | 
|   | 
|   var observers = scheduledObservers; | 
|   scheduledObservers = []; | 
|   // Sort observers based on their creation UID (incremental). | 
|   observers.sort(function(o1, o2) { | 
|     return o1.uid_ - o2.uid_; | 
|   }); | 
|   | 
|   var anyNonEmpty = false; | 
|   observers.forEach(function(observer) { | 
|   | 
|     // 2.1, 2.2 | 
|     var queue = observer.takeRecords(); | 
|     // 2.3. Remove all transient registered observers whose observer is mo. | 
|     removeTransientObserversFor(observer); | 
|   | 
|     // 2.4 | 
|     if (queue.length) { | 
|       observer.callback_(queue, observer); | 
|       anyNonEmpty = true; | 
|     } | 
|   }); | 
|   | 
|   // 3. | 
|   if (anyNonEmpty) | 
|     dispatchCallbacks(); | 
| } | 
|   | 
| function removeTransientObserversFor(observer) { | 
|   observer.nodes_.forEach(function(node) { | 
|     var registrations = registrationsTable.get(node); | 
|     if (!registrations) | 
|       return; | 
|     registrations.forEach(function(registration) { | 
|       if (registration.observer === observer) | 
|         registration.removeTransientObservers(); | 
|     }); | 
|   }); | 
| } | 
|   | 
| /** | 
|  * This function is used for the "For each registered observer observer (with | 
|  * observer's options as options) in target's list of registered observers, | 
|  * run these substeps:" and the "For each ancestor ancestor of target, and for | 
|  * each registered observer observer (with options options) in ancestor's list | 
|  * of registered observers, run these substeps:" part of the algorithms. The | 
|  * |options.subtree| is checked to ensure that the callback is called | 
|  * correctly. | 
|  * | 
|  * @param {Node} target | 
|  * @param {function(MutationObserverInit):MutationRecord} callback | 
|  */ | 
| function forEachAncestorAndObserverEnqueueRecord(target, callback) { | 
|   for (var node = target; node; node = node.parentNode) { | 
|     var registrations = registrationsTable.get(node); | 
|   | 
|     if (registrations) { | 
|       for (var j = 0; j < registrations.length; j++) { | 
|         var registration = registrations[j]; | 
|         var options = registration.options; | 
|   | 
|         // Only target ignores subtree. | 
|         if (node !== target && !options.subtree) | 
|           continue; | 
|   | 
|         var record = callback(options); | 
|         if (record) | 
|           registration.enqueue(record); | 
|       } | 
|     } | 
|   } | 
| } | 
|   | 
| var uidCounter = 0; | 
|   | 
| /** | 
|  * The class that maps to the DOM MutationObserver interface. | 
|  * @param {Function} callback. | 
|  * @constructor | 
|  */ | 
| function JsMutationObserver(callback) { | 
|   this.callback_ = callback; | 
|   this.nodes_ = []; | 
|   this.records_ = []; | 
|   this.uid_ = ++uidCounter; | 
| } | 
|   | 
| JsMutationObserver.prototype = { | 
|   observe: function(target, options) { | 
|     target = wrapIfNeeded(target); | 
|   | 
|     // 1.1 | 
|     if (!options.childList && !options.attributes && !options.characterData || | 
|   | 
|         // 1.2 | 
|         options.attributeOldValue && !options.attributes || | 
|   | 
|         // 1.3 | 
|         options.attributeFilter && options.attributeFilter.length && | 
|             !options.attributes || | 
|   | 
|         // 1.4 | 
|         options.characterDataOldValue && !options.characterData) { | 
|   | 
|       throw new SyntaxError(); | 
|     } | 
|   | 
|     var registrations = registrationsTable.get(target); | 
|     if (!registrations) | 
|       registrationsTable.set(target, registrations = []); | 
|   | 
|     // 2 | 
|     // If target's list of registered observers already includes a registered | 
|     // observer associated with the context object, replace that registered | 
|     // observer's options with options. | 
|     var registration; | 
|     for (var i = 0; i < registrations.length; i++) { | 
|       if (registrations[i].observer === this) { | 
|         registration = registrations[i]; | 
|         registration.removeListeners(); | 
|         registration.options = options; | 
|         break; | 
|       } | 
|     } | 
|   | 
|     // 3. | 
|     // Otherwise, add a new registered observer to target's list of registered | 
|     // observers with the context object as the observer and options as the | 
|     // options, and add target to context object's list of nodes on which it | 
|     // is registered. | 
|     if (!registration) { | 
|       registration = new Registration(this, target, options); | 
|       registrations.push(registration); | 
|       this.nodes_.push(target); | 
|     } | 
|   | 
|     registration.addListeners(); | 
|   }, | 
|   | 
|   disconnect: function() { | 
|     this.nodes_.forEach(function(node) { | 
|       var registrations = registrationsTable.get(node); | 
|       for (var i = 0; i < registrations.length; i++) { | 
|         var registration = registrations[i]; | 
|         if (registration.observer === this) { | 
|           registration.removeListeners(); | 
|           registrations.splice(i, 1); | 
|           // Each node can only have one registered observer associated with | 
|           // this observer. | 
|           break; | 
|         } | 
|       } | 
|     }, this); | 
|     this.records_ = []; | 
|   }, | 
|   | 
|   takeRecords: function() { | 
|     var copyOfRecords = this.records_; | 
|     this.records_ = []; | 
|     return copyOfRecords; | 
|   } | 
| }; | 
|   | 
| /** | 
|  * @param {string} type | 
|  * @param {Node} target | 
|  * @constructor | 
|  */ | 
| function MutationRecord(type, target) { | 
|   this.type = type; | 
|   this.target = target; | 
|   this.addedNodes = []; | 
|   this.removedNodes = []; | 
|   this.previousSibling = null; | 
|   this.nextSibling = null; | 
|   this.attributeName = null; | 
|   this.attributeNamespace = null; | 
|   this.oldValue = null; | 
| } | 
|   | 
| function copyMutationRecord(original) { | 
|   var record = new MutationRecord(original.type, original.target); | 
|   record.addedNodes = original.addedNodes.slice(); | 
|   record.removedNodes = original.removedNodes.slice(); | 
|   record.previousSibling = original.previousSibling; | 
|   record.nextSibling = original.nextSibling; | 
|   record.attributeName = original.attributeName; | 
|   record.attributeNamespace = original.attributeNamespace; | 
|   record.oldValue = original.oldValue; | 
|   return record; | 
| }; | 
|   | 
| // We keep track of the two (possibly one) records used in a single mutation. | 
| var currentRecord, recordWithOldValue; | 
|   | 
| /** | 
|  * Creates a record without |oldValue| and caches it as |currentRecord| for | 
|  * later use. | 
|  * @param {string} oldValue | 
|  * @return {MutationRecord} | 
|  */ | 
| function getRecord(type, target) { | 
|   return currentRecord = new MutationRecord(type, target); | 
| } | 
|   | 
| /** | 
|  * Gets or creates a record with |oldValue| based in the |currentRecord| | 
|  * @param {string} oldValue | 
|  * @return {MutationRecord} | 
|  */ | 
| function getRecordWithOldValue(oldValue) { | 
|   if (recordWithOldValue) | 
|     return recordWithOldValue; | 
|   recordWithOldValue = copyMutationRecord(currentRecord); | 
|   recordWithOldValue.oldValue = oldValue; | 
|   return recordWithOldValue; | 
| } | 
|   | 
| function clearRecords() { | 
|   currentRecord = recordWithOldValue = undefined; | 
| } | 
|   | 
| /** | 
|  * @param {MutationRecord} record | 
|  * @return {boolean} Whether the record represents a record from the current | 
|  * mutation event. | 
|  */ | 
| function recordRepresentsCurrentMutation(record) { | 
|   return record === recordWithOldValue || record === currentRecord; | 
| } | 
|   | 
| /** | 
|  * Selects which record, if any, to replace the last record in the queue. | 
|  * This returns |null| if no record should be replaced. | 
|  * | 
|  * @param {MutationRecord} lastRecord | 
|  * @param {MutationRecord} newRecord | 
|  * @param {MutationRecord} | 
|  */ | 
| function selectRecord(lastRecord, newRecord) { | 
|   if (lastRecord === newRecord) | 
|     return lastRecord; | 
|   | 
|   // Check if the the record we are adding represents the same record. If | 
|   // so, we keep the one with the oldValue in it. | 
|   if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) | 
|     return recordWithOldValue; | 
|   | 
|   return null; | 
| } | 
|   | 
| /** | 
|  * Class used to represent a registered observer. | 
|  * @param {MutationObserver} observer | 
|  * @param {Node} target | 
|  * @param {MutationObserverInit} options | 
|  * @constructor | 
|  */ | 
| function Registration(observer, target, options) { | 
|   this.observer = observer; | 
|   this.target = target; | 
|   this.options = options; | 
|   this.transientObservedNodes = []; | 
| } | 
|   | 
| Registration.prototype = { | 
|   enqueue: function(record) { | 
|     var records = this.observer.records_; | 
|     var length = records.length; | 
|   | 
|     // There are cases where we replace the last record with the new record. | 
|     // For example if the record represents the same mutation we need to use | 
|     // the one with the oldValue. If we get same record (this can happen as we | 
|     // walk up the tree) we ignore the new record. | 
|     if (records.length > 0) { | 
|       var lastRecord = records[length - 1]; | 
|       var recordToReplaceLast = selectRecord(lastRecord, record); | 
|       if (recordToReplaceLast) { | 
|         records[length - 1] = recordToReplaceLast; | 
|         return; | 
|       } | 
|     } else { | 
|       scheduleCallback(this.observer); | 
|     } | 
|   | 
|     records[length] = record; | 
|   }, | 
|   | 
|   addListeners: function() { | 
|     this.addListeners_(this.target); | 
|   }, | 
|   | 
|   addListeners_: function(node) { | 
|     var options = this.options; | 
|     if (options.attributes) | 
|       node.addEventListener('DOMAttrModified', this, true); | 
|   | 
|     if (options.characterData) | 
|       node.addEventListener('DOMCharacterDataModified', this, true); | 
|   | 
|     if (options.childList) | 
|       node.addEventListener('DOMNodeInserted', this, true); | 
|   | 
|     if (options.childList || options.subtree) | 
|       node.addEventListener('DOMNodeRemoved', this, true); | 
|   }, | 
|   | 
|   removeListeners: function() { | 
|     this.removeListeners_(this.target); | 
|   }, | 
|   | 
|   removeListeners_: function(node) { | 
|     var options = this.options; | 
|     if (options.attributes) | 
|       node.removeEventListener('DOMAttrModified', this, true); | 
|   | 
|     if (options.characterData) | 
|       node.removeEventListener('DOMCharacterDataModified', this, true); | 
|   | 
|     if (options.childList) | 
|       node.removeEventListener('DOMNodeInserted', this, true); | 
|   | 
|     if (options.childList || options.subtree) | 
|       node.removeEventListener('DOMNodeRemoved', this, true); | 
|   }, | 
|   | 
|   /** | 
|    * Adds a transient observer on node. The transient observer gets removed | 
|    * next time we deliver the change records. | 
|    * @param {Node} node | 
|    */ | 
|   addTransientObserver: function(node) { | 
|     // Don't add transient observers on the target itself. We already have all | 
|     // the required listeners set up on the target. | 
|     if (node === this.target) | 
|       return; | 
|   | 
|     this.addListeners_(node); | 
|     this.transientObservedNodes.push(node); | 
|     var registrations = registrationsTable.get(node); | 
|     if (!registrations) | 
|       registrationsTable.set(node, registrations = []); | 
|   | 
|     // We know that registrations does not contain this because we already | 
|     // checked if node === this.target. | 
|     registrations.push(this); | 
|   }, | 
|   | 
|   removeTransientObservers: function() { | 
|     var transientObservedNodes = this.transientObservedNodes; | 
|     this.transientObservedNodes = []; | 
|   | 
|     transientObservedNodes.forEach(function(node) { | 
|       // Transient observers are never added to the target. | 
|       this.removeListeners_(node); | 
|   | 
|       var registrations = registrationsTable.get(node); | 
|       for (var i = 0; i < registrations.length; i++) { | 
|         if (registrations[i] === this) { | 
|           registrations.splice(i, 1); | 
|           // Each node can only have one registered observer associated with | 
|           // this observer. | 
|           break; | 
|         } | 
|       } | 
|     }, this); | 
|   }, | 
|   | 
|   handleEvent: function(e) { | 
|     // Stop propagation since we are managing the propagation manually. | 
|     // This means that other mutation events on the page will not work | 
|     // correctly but that is by design. | 
|     e.stopImmediatePropagation(); | 
|   | 
|     switch (e.type) { | 
|       case 'DOMAttrModified': | 
|         // http://dom.spec.whatwg.org/#concept-mo-queue-attributes | 
|   | 
|         var name = e.attrName; | 
|         var namespace = e.relatedNode.namespaceURI; | 
|         var target = e.target; | 
|   | 
|         // 1. | 
|         var record = new getRecord('attributes', target); | 
|         record.attributeName = name; | 
|         record.attributeNamespace = namespace; | 
|   | 
|         // 2. | 
|         var oldValue = null; | 
|         if (!(typeof MutationEvent !== 'undefined' && e.attrChange === MutationEvent.ADDITION)) | 
|           oldValue = e.prevValue; | 
|   | 
|         forEachAncestorAndObserverEnqueueRecord(target, function(options) { | 
|           // 3.1, 4.2 | 
|           if (!options.attributes) | 
|             return; | 
|   | 
|           // 3.2, 4.3 | 
|           if (options.attributeFilter && options.attributeFilter.length && | 
|               options.attributeFilter.indexOf(name) === -1 && | 
|               options.attributeFilter.indexOf(namespace) === -1) { | 
|             return; | 
|           } | 
|           // 3.3, 4.4 | 
|           if (options.attributeOldValue) | 
|             return getRecordWithOldValue(oldValue); | 
|   | 
|           // 3.4, 4.5 | 
|           return record; | 
|         }); | 
|   | 
|         break; | 
|   | 
|       case 'DOMCharacterDataModified': | 
|         // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata | 
|         var target = e.target; | 
|   | 
|         // 1. | 
|         var record = getRecord('characterData', target); | 
|   | 
|         // 2. | 
|         var oldValue = e.prevValue; | 
|   | 
|   | 
|         forEachAncestorAndObserverEnqueueRecord(target, function(options) { | 
|           // 3.1, 4.2 | 
|           if (!options.characterData) | 
|             return; | 
|   | 
|           // 3.2, 4.3 | 
|           if (options.characterDataOldValue) | 
|             return getRecordWithOldValue(oldValue); | 
|   | 
|           // 3.3, 4.4 | 
|           return record; | 
|         }); | 
|   | 
|         break; | 
|   | 
|       case 'DOMNodeRemoved': | 
|         this.addTransientObserver(e.target); | 
|         // Fall through. | 
|       case 'DOMNodeInserted': | 
|         // http://dom.spec.whatwg.org/#concept-mo-queue-childlist | 
|         var target = e.relatedNode; | 
|         var changedNode = e.target; | 
|         var addedNodes, removedNodes; | 
|         if (e.type === 'DOMNodeInserted') { | 
|           addedNodes = [changedNode]; | 
|           removedNodes = []; | 
|         } else { | 
|   | 
|           addedNodes = []; | 
|           removedNodes = [changedNode]; | 
|         } | 
|         var previousSibling = changedNode.previousSibling; | 
|         var nextSibling = changedNode.nextSibling; | 
|   | 
|         // 1. | 
|         var record = getRecord('childList', target); | 
|         record.addedNodes = addedNodes; | 
|         record.removedNodes = removedNodes; | 
|         record.previousSibling = previousSibling; | 
|         record.nextSibling = nextSibling; | 
|   | 
|         forEachAncestorAndObserverEnqueueRecord(target, function(options) { | 
|           // 2.1, 3.2 | 
|           if (!options.childList) | 
|             return; | 
|   | 
|           // 2.2, 3.3 | 
|           return record; | 
|         }); | 
|   | 
|     } | 
|   | 
|     clearRecords(); | 
|   } | 
| }; | 
|   | 
| if (!MutationObserver) { | 
|   MutationObserver = JsMutationObserver; | 
| } | 
|   | 
| module.exports = MutationObserver; |