docs: function (transition) {
            var treeChanges = calcTreeChanges(transition);
            var currentInactives = stickySupport.getInactiveStates();
            var futureInactives, exitingTypes, enteringTypes;
            var keep = treeChanges.keep;
  
  
            /////////////////////////////////////////
            // helper functions
            function notIn(array) { return function (elem) { return array.indexOf(elem) === -1; }; }
            function flattenReduce(memo, list) { return memo.concat(list); }
            function uniqReduce(memo, orphan) { if (notIn(memo)(orphan)) memo.push(orphan); return memo; }
            function prop(attr) { return function(obj) { return obj[attr]; } }
            function typeIs(type) { return function(obj) { return obj.type === type; } }
            function isChildOf(state) { return function(other) { return other.parent === state; }; }
            var notEntering = notIn(treeChanges.entering);
            function notSticky(state) { return !state.sticky; }
            ////////////////////////////////////
  
  
            // Calculate the "exit" transition types for states being exited in fromPath
            // Exit types will be either "inactivate" or "exit"
            // Two things must be satisfied in order to inactivate the "exiting" states (instead of exit them):
            // - The first element of the exiting path must be sticky
            // - We must be entering any sibling state of the sticky (we can check this using entering.length)
            var shouldInactivate = treeChanges.exiting[0] && treeChanges.exiting[0].sticky && treeChanges.entering.length > 0;
            exitingTypes = treeChanges.exiting.map(function (state) {
                var stateRentering = treeChanges.entering.indexOf(state) !== -1;
                var type = shouldInactivate && !stateRentering ? "inactivate" : "exit";
                return { type: type, state: state };
            });
  
  
            // Calculate the "enter" transition types for states being entered in toPath
            // Enter types will be either "enter", "reactivate", or "reload" where:
            //   enter: full resolve, no special logic
            //   reactivate: use previous locals
            //   reload: like 'enter', except exit the inactive state before entering it.
            var reloaded = transition.options && !!transition.options.reload;
            enteringTypes = treeChanges.entering.map(function(state) {
              var type = getEnterTransition(state, transition.toParams, transition.reloadStateTree, reloaded);
              reloaded = reloaded || type === 'reload';
              return { type: type, state: state };
            });
  
            // Find all the "orphaned" states.  those states that are :
            //  - are siblings of the entering states
            //  - previously inactive
            //  - are not being reactivated (entered)
            //  - are not sticky
            // unioned with:
            //  - children of the toState
            //  - previously inactive
            //
            // Given:
            //   - states A (sticky: true), B, A.foo, A.bar
            //   - A.foo is currently inactive
            //   - B is currently active
            // Orphan case 1)
            //   - Transition to A.bar orphans the inactive state A.foo; it should be exited
            // Orphan case 2)
            //   - Transition directly to A orphans the inactive state A.foo; it should be exited
            //
            // Given:
            //   - states A (sticky: true), B, A.foo (sticky), A.bar
            //   - A.foo is currently inactive
            //   - B is currently active
            // Orphan case 3)
            //   - Transition directly to A orphans the inactive sticky state A.foo; it should be exited
            // Note: transition from B to A.bar does not orphan A.foo
            // Note 2: each orphaned state might be the parent of a larger inactive subtree.
            var orphanedRoots = treeChanges.entering
                // For each entering state in the path, find all sibling states which are currently inactive
                .map(function (entering) { return currentInactives.filter(isChildOf(entering.parent)); })
                // Flatten nested arrays. Now we have an array of inactive states that are children of the ones being entered.
                .reduce(flattenReduce, [])
                // Consider "orphaned": only those children that are themselves not currently being entered
                .filter(notEntering)
                // Consider "orphaned": only those children that are not themselves sticky states.
                .filter(notSticky)
                // Finally, union that set with any inactive children of the "to state"
                .concat(currentInactives.filter(isChildOf(transition.toState)));
  
            var currentInactivesByParent = mapInactivesByImmediateParent();
            var allOrphans = orphanedRoots
                .map(function(root) { return currentInactivesByParent[root.name] })
                .filter(angular.isDefined)
                .reduce(flattenReduce, [])
                .concat(orphanedRoots)
                // Sort by depth to exit orphans in proper order
                .sort(sortByStateDepth);
  
            // Add them to the list of states being exited.
            var exitOrOrphaned = exitingTypes
                .filter(typeIs("exit"))
                .map(prop("state"))
                .concat(allOrphans);
  
            // Now calculate the states that will be inactive if this transition succeeds.
            // We have already pushed the transitionType == "inactivate" states to 'inactives'.
            // Second, add all the existing inactive states
            futureInactives = currentInactives
                .filter(notIn(exitOrOrphaned))
                .filter(notIn(treeChanges.entering))
                .concat(exitingTypes.filter(typeIs("inactivate")).map(prop("state")))
                .sort(sortByStateDepth);
  
            return {
              keep: keep,
              enter: new Array(keep).concat(enteringTypes.map(prop("type"))),
              exit: new Array(keep).concat(exitingTypes.map(prop("type"))),
              inactives: futureInactives,
              reactivatingStates: enteringTypes.filter(typeIs("reactivate")).map(prop("state")),
              orphans: allOrphans
            };
          }