docs: function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) {
  		if (old === vnodes || old == null && vnodes == null) return
  		else if (old == null || old.length === 0) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns)
  		else if (vnodes == null || vnodes.length === 0) removeNodes(old, 0, old.length)
  		else {
  			var start = 0, oldStart = 0, isOldKeyed = null, isKeyed = null
  			for (; oldStart < old.length; oldStart++) {
  				if (old[oldStart] != null) {
  					isOldKeyed = old[oldStart].key != null
  					break
  				}
  			}
  			for (; start < vnodes.length; start++) {
  				if (vnodes[start] != null) {
  					isKeyed = vnodes[start].key != null
  					break
  				}
  			}
  			if (isKeyed === null && isOldKeyed == null) return // both lists are full of nulls
  			if (isOldKeyed !== isKeyed) {
  				removeNodes(old, oldStart, old.length)
  				createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns)
  			} else if (!isKeyed) {
  				// Don't index past the end of either list (causes deopts).
  				var commonLength = old.length < vnodes.length ? old.length : vnodes.length
  				// Rewind if necessary to the first non-null index on either side.
  				// We could alternatively either explicitly create or remove nodes when `start !== oldStart`
  				// but that would be optimizing for sparse lists which are more rare than dense ones.
  				start = start < oldStart ? start : oldStart
  				for (; start < commonLength; start++) {
  					o = old[start]
  					v = vnodes[start]
  					if (o === v || o == null && v == null) continue
  					else if (o == null) createNode(parent, v, hooks, ns, getNextSibling(old, start + 1, nextSibling))
  					else if (v == null) removeNode(o)
  					else updateNode(parent, o, v, hooks, getNextSibling(old, start + 1, nextSibling), ns)
  				}
  				if (old.length > commonLength) removeNodes(old, start, old.length)
  				if (vnodes.length > commonLength) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns)
  			} else {
  				// keyed diff
  				var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oe, ve, topSibling
  
  				// bottom-up
  				while (oldEnd >= oldStart && end >= start) {
  					oe = old[oldEnd]
  					ve = vnodes[end]
  					if (oe == null) oldEnd--
  					else if (ve == null) end--
  					else if (oe.key === ve.key) {
  						if (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns)
  						if (ve.dom != null) nextSibling = ve.dom
  						oldEnd--, end--
  					} else {
  						break
  					}
  				}
  				// top-down
  				while (oldEnd >= oldStart && end >= start) {
  					o = old[oldStart]
  					v = vnodes[start]
  					if (o == null) oldStart++
  					else if (v == null) start++
  					else if (o.key === v.key) {
  						oldStart++, start++
  						if (o !== v) updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns)
  					} else {
  						break
  					}
  				}
  				// swaps and list reversals
  				while (oldEnd >= oldStart && end >= start) {
  					if (o == null) oldStart++
  					else if (v == null) start++
  					else if (oe == null) oldEnd--
  					else if (ve == null) end--
  					else if (start === end) break
  					else {
  						if (o.key !== ve.key || oe.key !== v.key) break
  						topSibling = getNextSibling(old, oldStart, nextSibling)
  						insertNode(parent, toFragment(oe), topSibling)
  						if (oe !== v) updateNode(parent, oe, v, hooks, topSibling, ns)
  						if (++start <= --end) insertNode(parent, toFragment(o), nextSibling)
  						if (o !== ve) updateNode(parent, o, ve, hooks, nextSibling, ns)
  						if (ve.dom != null) nextSibling = ve.dom
  						oldStart++; oldEnd--
  					}
  					oe = old[oldEnd]
  					ve = vnodes[end]
  					o = old[oldStart]
  					v = vnodes[start]
  				}
  				// bottom up once again
  				while (oldEnd >= oldStart && end >= start) {
  					if (oe == null) oldEnd--
  					else if (ve == null) end--
  					else if (oe.key === ve.key) {
  						if (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns)
  						if (ve.dom != null) nextSibling = ve.dom
  						oldEnd--, end--
  					} else {
  						break
  					}
  					oe = old[oldEnd]
  					ve = vnodes[end]
  				}
  				if (start > end) removeNodes(old, oldStart, oldEnd + 1)
  				else if (oldStart > oldEnd) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)
  				else {
  					// inspired by ivi https://github.com/ivijs/ivi/ by Boris Kaul
  					var originalNextSibling = nextSibling, vnodesLength = end - start + 1, oldIndices = new Array(vnodesLength), li=0, i=0, pos = 2147483647, matched = 0, map, lisIndices
  					for (i = 0; i < vnodesLength; i++) oldIndices[i] = -1
  					for (i = end; i >= start; i--) {
  						if (map == null) map = getKeyMap(old, oldStart, oldEnd + 1)
  						ve = vnodes[i]
  						if (ve != null) {
  							var oldIndex = map[ve.key]
  							if (oldIndex != null) {
  								pos = (oldIndex < pos) ? oldIndex : -1 // becomes -1 if nodes were re-ordered
  								oldIndices[i-start] = oldIndex
  								oe = old[oldIndex]
  								old[oldIndex] = null
  								if (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns)
  								if (ve.dom != null) nextSibling = ve.dom
  								matched++
  							}
  						}
  					}
  					nextSibling = originalNextSibling
  					if (matched !== oldEnd - oldStart + 1) removeNodes(old, oldStart, oldEnd + 1)
  					if (matched === 0) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)
  					else {
  						if (pos === -1) {
  							// the indices of the indices of the items that are part of the
  							// longest increasing subsequence in the oldIndices list
  							lisIndices = makeLisIndices(oldIndices)
  							li = lisIndices.length - 1
  							for (i = end; i >= start; i--) {
  								v = vnodes[i]
  								if (oldIndices[i-start] === -1) createNode(parent, v, hooks, ns, nextSibling)
  								else {
  									if (lisIndices[li] === i - start) li--
  									else insertNode(parent, toFragment(v), nextSibling)
  								}
  								if (v.dom != null) nextSibling = vnodes[i].dom
  							}
  						} else {
  							for (i = end; i >= start; i--) {
  								v = vnodes[i]
  								if (oldIndices[i-start] === -1) createNode(parent, v, hooks, ns, nextSibling)
  								if (v.dom != null) nextSibling = vnodes[i].dom
  							}
  						}
  					}
  				}
  			}
  		}
  	}