(function(scope) {

// imports

var Changeling = scope.Changeling;

var Projection = function(inNode) {
  // contract with host
  this.host = inNode;
  this.host.projection = this;
  // start empty
  this.clear();
};

Projection.prototype = {
  clear: function() {
    this.host.textContent = "";
    if (this.host.insertions) {
      this.host.insertions = [];
    }
  },
  add: function(inNode) {
    // if a Changeling, add the baby instead
    var n = inNode.baby || inNode;
    if (n.parentNode) {
      new Changeling(n).transplant(n);
    }
    appendExplodedChild(this.host, n);
  },
  addNodes: function(inNodes) {
    for (var i=0, n; (n=inNodes[i]); i++) {
      this.add(n);
    }
  }
};

Projection.flatten = function(inNode) {
  // 1. create insertion list if needed
  // 2. construct composed dom by walking insertion
  //    list, exploding insertion points and
  //    adding regular nodes
  if (!inNode.insertions) {
    createInsertions(inNode);
  }
  // compose into an empty subtree
  inNode.textContent = '';
  // use insertion list to compile composed DOM
  for (var i=0, n; (n=inNode.insertions[i]); i++) {
    // always deref
    n = n.baby || n;
    // if n is flattenable
    if (n.shouldFlatten) {
      n.shouldFlatten = false;
      // insert n's COMPOSED children
      var nodes = n.composedNodes || n.childNodes;
      for (var j=0, c; (c=nodes[j]); j++) {
        // make sure there is a placeholder for c in the insertion list
        if (!c.baby) {
          new Changeling(c).transplant(c);
        } else {
          c = c.baby;
        }
        // add the node to the flattened-composed dom
        appendFlattenedChild(inNode, c);
      }
    } else {
      // otherwise, add n itself to the flattened-composed dom
      appendFlattenedChild(inNode, n);
    }
  }
};

var createInsertions = function(inNode) {
  var i$ = inNode.insertions = [];
  for (var i=0, n; (n=inNode.childNodes[i]); i++) {
    i$.push(new Changeling(n));
  }
};

// add to the 'exploded composed' tree
var appendExplodedChild = function(inNode, inChild) {
  if (inNode.insertions) {
    inNode.insertions.push(inChild);
  } else {
    // equivalent to appendChild, but avoids any appendChild override
    inNode.insertBefore(inChild, null);
  }
};

// add to the 'flattened composed' tree
var appendFlattenedChild = function(inNode, inChild) {
  // equivalent to appendChild, but avoids any appendChild override
  inNode.insertBefore(inChild, null);
};

scope.Projection = Projection;

})(window.__exported_components_polyfill_scope__);

@@ -1963,24 +1963,279 @@
 ng(n));%0A  %7D%0A
+  // modify API so appendChild sends input directly into insertion list%0A  // *unless* this object also has LightDOM, then LightDOM wins%0A  if (!inNode.lightDOM) %7B%0A    inNode.appendChild = function(inChild) %7B%0A      this.insertions.push(inChild);%0A    %7D;%0A  %7D%0A
 %7D;%0A%0A// add t

add appendChild override to nodes with insertion lists (unless they also have LightDOM); this way user code can modify trees via appendChild without knowing about insertion lists