whole_func_string: function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
                                     jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
                                     previousCompileContext) {
        previousCompileContext = previousCompileContext || {};
  
        var terminalPriority = -Number.MAX_VALUE,
            newScopeDirective,
            controllerDirectives = previousCompileContext.controllerDirectives,
            newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
            templateDirective = previousCompileContext.templateDirective,
            nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
            hasTranscludeDirective = false,
            hasTemplate = false,
            hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
            $compileNode = templateAttrs.$$element = jqLite(compileNode),
            directive,
            directiveName,
            $template,
            replaceDirective = originalReplaceDirective,
            childTranscludeFn = transcludeFn,
            linkFn,
            directiveValue;
  
        // executes all directives on the current element
        for(var i = 0, ii = directives.length; i < ii; i++) {
          directive = directives[i];
          var attrStart = directive.$$start;
          var attrEnd = directive.$$end;
  
          // collect multiblock sections
          if (attrStart) {
            $compileNode = groupScan(compileNode, attrStart, attrEnd);
          }
          $template = undefined;
  
          if (terminalPriority > directive.priority) {
            break; // prevent further processing of directives
          }
  
          if (directiveValue = directive.scope) {
  
            // skip the check for directives with async templates, we'll check the derived sync
            // directive when the template arrives
            if (!directive.templateUrl) {
              if (isObject(directiveValue)) {
                // This directive is trying to add an isolated scope.
                // Check that there is no scope of any kind already
                assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
                                  directive, $compileNode);
                newIsolateScopeDirective = directive;
              } else {
                // This directive is trying to add a child scope.
                // Check that there is no isolated scope already
                assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
                                  $compileNode);
              }
            }
  
            newScopeDirective = newScopeDirective || directive;
          }
  
          directiveName = directive.name;
  
          if (!directive.templateUrl && directive.controller) {
            directiveValue = directive.controller;
            controllerDirectives = controllerDirectives || {};
            assertNoDuplicate("'" + directiveName + "' controller",
                controllerDirectives[directiveName], directive, $compileNode);
            controllerDirectives[directiveName] = directive;
          }
  
          if (directiveValue = directive.transclude) {
            hasTranscludeDirective = true;
  
            // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
            // This option should only be used by directives that know how to safely handle element transclusion,
            // where the transcluded nodes are added or replaced after linking.
            if (!directive.$$tlb) {
              assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
              nonTlbTranscludeDirective = directive;
            }
  
            if (directiveValue == 'element') {
              hasElementTranscludeDirective = true;
              terminalPriority = directive.priority;
              $template = $compileNode;
              $compileNode = templateAttrs.$$element =
                  jqLite(document.createComment(' ' + directiveName + ': ' +
                                                templateAttrs[directiveName] + ' '));
              compileNode = $compileNode[0];
              replaceWith(jqCollection, sliceArgs($template), compileNode);
  
              childTranscludeFn = compile($template, transcludeFn, terminalPriority,
                                          replaceDirective && replaceDirective.name, {
                                            // Don't pass in:
                                            // - controllerDirectives - otherwise we'll create duplicates controllers
                                            // - newIsolateScopeDirective or templateDirective - combining templates with
                                            //   element transclusion doesn't make sense.
                                            //
                                            // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
                                            // on the same element more than once.
                                            nonTlbTranscludeDirective: nonTlbTranscludeDirective
                                          });
            } else {
              $template = jqLite(jqLiteClone(compileNode)).contents();
              $compileNode.empty(); // clear contents
              childTranscludeFn = compile($template, transcludeFn);
            }
          }
  
          if (directive.template) {
            hasTemplate = true;
            assertNoDuplicate('template', templateDirective, directive, $compileNode);
            templateDirective = directive;
  
            directiveValue = (isFunction(directive.template))
                ? directive.template($compileNode, templateAttrs)
                : directive.template;
  
            directiveValue = denormalizeTemplate(directiveValue);
  
            if (directive.replace) {
              replaceDirective = directive;
              if (jqLiteIsTextNode(directiveValue)) {
                $template = [];
              } else {
                $template = jqLite(wrapTemplate(directive.type, trim(directiveValue)));
              }
              compileNode = $template[0];
  
              if ($template.length != 1 || compileNode.nodeType !== 1) {
                throw $compileMinErr('tplrt',
                    "Template for directive '{0}' must have exactly one root element. {1}",
                    directiveName, '');
              }
  
              replaceWith(jqCollection, $compileNode, compileNode);
  
              var newTemplateAttrs = {$attr: {}};
  
              // combine directives from the original node and from the template:
              // - take the array of directives for this element
              // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
              // - collect directives from the template and sort them by priority
              // - combine directives as: processed + template + unprocessed
              var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
              var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
  
              if (newIsolateScopeDirective) {
                markDirectivesAsIsolate(templateDirectives);
              }
              directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
              mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
  
              ii = directives.length;
            } else {
              $compileNode.html(directiveValue);
            }
          }
  
          if (directive.templateUrl) {
            hasTemplate = true;
            assertNoDuplicate('template', templateDirective, directive, $compileNode);
            templateDirective = directive;
  
            if (directive.replace) {
              replaceDirective = directive;
            }
  
            nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
                templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
                  controllerDirectives: controllerDirectives,
                  newIsolateScopeDirective: newIsolateScopeDirective,
                  templateDirective: templateDirective,
                  nonTlbTranscludeDirective: nonTlbTranscludeDirective
                });
            ii = directives.length;
          } else if (directive.compile) {
            try {
              linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
              if (isFunction(linkFn)) {
                addLinkFns(null, linkFn, attrStart, attrEnd);
              } else if (linkFn) {
                addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
              }
            } catch (e) {
              $exceptionHandler(e, startingTag($compileNode));
            }
          }
  
          if (directive.terminal) {
            nodeLinkFn.terminal = true;
            terminalPriority = Math.max(terminalPriority, directive.priority);
          }
  
        }
  
        nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
        nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
        nodeLinkFn.templateOnThisElement = hasTemplate;
        nodeLinkFn.transclude = childTranscludeFn;
  
        previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
  
        // might be normal or delayed nodeLinkFn depending on if templateUrl is present
        return nodeLinkFn;
  
        ////////////////////
  
        function addLinkFns(pre, post, attrStart, attrEnd) {
          if (pre) {
            if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
            pre.require = directive.require;
            pre.directiveName = directiveName;
            if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
              pre = cloneAndAnnotateFn(pre, {isolateScope: true});
            }
            preLinkFns.push(pre);
          }
          if (post) {
            if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
            post.require = directive.require;
            post.directiveName = directiveName;
            if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
              post = cloneAndAnnotateFn(post, {isolateScope: true});
            }
            postLinkFns.push(post);
          }
        }
  
  
        function getControllers(directiveName, require, $element, elementControllers) {
          var value, retrievalMethod = 'data', optional = false;
          if (isString(require)) {
            while((value = require.charAt(0)) == '^' || value == '?') {
              require = require.substr(1);
              if (value == '^') {
                retrievalMethod = 'inheritedData';
              }
              optional = optional || value == '?';
            }
            value = null;
  
            if (elementControllers && retrievalMethod === 'data') {
              value = elementControllers[require];
            }
            value = value || $element[retrievalMethod]('$' + require + 'Controller');
  
            if (!value && !optional) {
              throw $compileMinErr('ctreq',
                  "Controller '{0}', required by directive '{1}', can't be found!",
                  require, directiveName);
            }
            return value;
          } else if (isArray(require)) {
            value = [];
            forEach(require, function(require) {
              value.push(getControllers(directiveName, require, $element, elementControllers));
            });
          }
          return value;
        }
  
  
        function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
          var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
  
          attrs = (compileNode === linkNode)
            ? templateAttrs
            : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
          $element = attrs.$$element;
  
          if (newIsolateScopeDirective) {
            var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
  
            isolateScope = scope.$new(true);
  
            if (templateDirective && (templateDirective === newIsolateScopeDirective ||
                templateDirective === newIsolateScopeDirective.$$originalDirective)) {
              $element.data('$isolateScope', isolateScope);
            } else {
              $element.data('$isolateScopeNoTemplate', isolateScope);
            }
  
  
  
            safeAddClass($element, 'ng-isolate-scope');
  
            forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
              var match = definition.match(LOCAL_REGEXP) || [],
                  attrName = match[3] || scopeName,
                  optional = (match[2] == '?'),
                  mode = match[1], // @, =, or &
                  lastValue,
                  parentGet, parentSet, compare;
  
              isolateScope.$$isolateBindings[scopeName] = mode + attrName;
  
              switch (mode) {
  
                case '@':
                  attrs.$observe(attrName, function(value) {
                    isolateScope[scopeName] = value;
                  });
                  attrs.$$observers[attrName].$$scope = scope;
                  if( attrs[attrName] ) {
                    // If the attribute has been provided then we trigger an interpolation to ensure
                    // the value is there for use in the link fn
                    isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
                  }
                  break;
  
                case '=':
                  if (optional && !attrs[attrName]) {
                    return;
                  }
                  parentGet = $parse(attrs[attrName]);
                  if (parentGet.literal) {
                    compare = equals;
                  } else {
                    compare = function(a,b) { return a === b; };
                  }
                  parentSet = parentGet.assign || function() {
                    // reset the change, or we will throw this exception on every $digest
                    lastValue = isolateScope[scopeName] = parentGet(scope);
                    throw $compileMinErr('nonassign',
                        "Expression '{0}' used with directive '{1}' is non-assignable!",
                        attrs[attrName], newIsolateScopeDirective.name);
                  };
                  lastValue = isolateScope[scopeName] = parentGet(scope);
                  var unwatch = scope.$watch($parse(attrs[attrName], function parentValueWatch(parentValue) {
                    if (!compare(parentValue, isolateScope[scopeName])) {
                      // we are out of sync and need to copy
                      if (!compare(parentValue, lastValue)) {
                        // parent changed and it has precedence
                        isolateScope[scopeName] = parentValue;
                      } else {
                        // if the parent can be assigned then do so
                        parentSet(scope, parentValue = isolateScope[scopeName]);
                      }
                    }
                    return lastValue = parentValue;
                  }), null, parentGet.literal);
                  isolateScope.$on('$destroy', unwatch);
                  break;
  
                case '&':
                  parentGet = $parse(attrs[attrName]);
                  isolateScope[scopeName] = function(locals) {
                    return parentGet(scope, locals);
                  };
                  break;
  
                default:
                  throw $compileMinErr('iscp',
                      "Invalid isolate scope definition for directive '{0}'." +
                      " Definition: {... {1}: '{2}' ...}",
                      newIsolateScopeDirective.name, scopeName, definition);
              }
            });
          }
          transcludeFn = boundTranscludeFn && controllersBoundTransclude;
          if (controllerDirectives) {
            forEach(controllerDirectives, function(directive) {
              var locals = {
                $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
                $element: $element,
                $attrs: attrs,
                $transclude: transcludeFn
              }, controllerInstance;
  
              controller = directive.controller;
              if (controller == '@') {
                controller = attrs[directive.name];
              }
  
              controllerInstance = $controller(controller, locals);
              // For directives with element transclusion the element is a comment,
              // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
              // clean up (http://bugs.jquery.com/ticket/8335).
              // Instead, we save the controllers for the element in a local hash and attach to .data
              // later, once we have the actual element.
              elementControllers[directive.name] = controllerInstance;
              if (!hasElementTranscludeDirective) {
                $element.data('$' + directive.name + 'Controller', controllerInstance);
              }
  
              if (directive.controllerAs) {
                locals.$scope[directive.controllerAs] = controllerInstance;
              }
            });
          }
  
          // PRELINKING
          for(i = 0, ii = preLinkFns.length; i < ii; i++) {
            try {
              linkFn = preLinkFns[i];
              linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
                  linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
            } catch (e) {
              $exceptionHandler(e, startingTag($element));
            }
          }
  
          // RECURSION
          // We only pass the isolate scope, if the isolate directive has a template,
          // otherwise the child elements do not belong to the isolate directive.
          var scopeToChild = scope;
          if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
            scopeToChild = isolateScope;
          }
          childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
  
          // POSTLINKING
          for(i = postLinkFns.length - 1; i >= 0; i--) {
            try {
              linkFn = postLinkFns[i];
              linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
                  linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
            } catch (e) {
              $exceptionHandler(e, startingTag($element));
            }
          }
  
          // This is the function that is injected as `$transclude`.
          function controllersBoundTransclude(scope, cloneAttachFn) {
            var transcludeControllers;
  
            // no scope passed
            if (arguments.length < 2) {
              cloneAttachFn = scope;
              scope = undefined;
            }
  
            if (hasElementTranscludeDirective) {
              transcludeControllers = elementControllers;
            }
  
            return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
          }
        }
      }
func_code_string: function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
                                     jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
                                     previousCompileContext) {
        previousCompileContext = previousCompileContext || {};
  
        var terminalPriority = -Number.MAX_VALUE,
            newScopeDirective,
            controllerDirectives = previousCompileContext.controllerDirectives,
            newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
            templateDirective = previousCompileContext.templateDirective,
            nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
            hasTranscludeDirective = false,
            hasTemplate = false,
            hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
            $compileNode = templateAttrs.$$element = jqLite(compileNode),
            directive,
            directiveName,
            $template,
            replaceDirective = originalReplaceDirective,
            childTranscludeFn = transcludeFn,
            linkFn,
            directiveValue;
  
        // executes all directives on the current element
        for(var i = 0, ii = directives.length; i < ii; i++) {
          directive = directives[i];
          var attrStart = directive.$$start;
          var attrEnd = directive.$$end;
  
          // collect multiblock sections
          if (attrStart) {
            $compileNode = groupScan(compileNode, attrStart, attrEnd);
          }
          $template = undefined;
  
          if (terminalPriority > directive.priority) {
            break; // prevent further processing of directives
          }
  
          if (directiveValue = directive.scope) {
  
            // skip the check for directives with async templates, we'll check the derived sync
            // directive when the template arrives
            if (!directive.templateUrl) {
              if (isObject(directiveValue)) {
                // This directive is trying to add an isolated scope.
                // Check that there is no scope of any kind already
                assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
                                  directive, $compileNode);
                newIsolateScopeDirective = directive;
              } else {
                // This directive is trying to add a child scope.
                // Check that there is no isolated scope already
                assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
                                  $compileNode);
              }
            }
  
            newScopeDirective = newScopeDirective || directive;
          }
  
          directiveName = directive.name;
  
          if (!directive.templateUrl && directive.controller) {
            directiveValue = directive.controller;
            controllerDirectives = controllerDirectives || {};
            assertNoDuplicate("'" + directiveName + "' controller",
                controllerDirectives[directiveName], directive, $compileNode);
            controllerDirectives[directiveName] = directive;
          }
  
          if (directiveValue = directive.transclude) {
            hasTranscludeDirective = true;
  
            // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
            // This option should only be used by directives that know how to safely handle element transclusion,
            // where the transcluded nodes are added or replaced after linking.
            if (!directive.$$tlb) {
              assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
              nonTlbTranscludeDirective = directive;
            }
  
            if (directiveValue == 'element') {
              hasElementTranscludeDirective = true;
              terminalPriority = directive.priority;
              $template = $compileNode;
              $compileNode = templateAttrs.$$element =
                  jqLite(document.createComment(' ' + directiveName + ': ' +
                                                templateAttrs[directiveName] + ' '));
              compileNode = $compileNode[0];
              replaceWith(jqCollection, sliceArgs($template), compileNode);
  
              childTranscludeFn = compile($template, transcludeFn, terminalPriority,
                                          replaceDirective && replaceDirective.name, {
                                            // Don't pass in:
                                            // - controllerDirectives - otherwise we'll create duplicates controllers
                                            // - newIsolateScopeDirective or templateDirective - combining templates with
                                            //   element transclusion doesn't make sense.
                                            //
                                            // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
                                            // on the same element more than once.
                                            nonTlbTranscludeDirective: nonTlbTranscludeDirective
                                          });
            } else {
              $template = jqLite(jqLiteClone(compileNode)).contents();
              $compileNode.empty(); // clear contents
              childTranscludeFn = compile($template, transcludeFn);
            }
          }
  
          if (directive.template) {
            hasTemplate = true;
            assertNoDuplicate('template', templateDirective, directive, $compileNode);
            templateDirective = directive;
  
            directiveValue = (isFunction(directive.template))
                ? directive.template($compileNode, templateAttrs)
                : directive.template;
  
            directiveValue = denormalizeTemplate(directiveValue);
  
            if (directive.replace) {
              replaceDirective = directive;
              if (jqLiteIsTextNode(directiveValue)) {
                $template = [];
              } else {
                $template = jqLite(wrapTemplate(directive.type, trim(directiveValue)));
              }
              compileNode = $template[0];
  
              if ($template.length != 1 || compileNode.nodeType !== 1) {
                throw $compileMinErr('tplrt',
                    "Template for directive '{0}' must have exactly one root element. {1}",
                    directiveName, '');
              }
  
              replaceWith(jqCollection, $compileNode, compileNode);
  
              var newTemplateAttrs = {$attr: {}};
  
              // combine directives from the original node and from the template:
              // - take the array of directives for this element
              // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
              // - collect directives from the template and sort them by priority
              // - combine directives as: processed + template + unprocessed
              var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
              var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
  
              if (newIsolateScopeDirective) {
                markDirectivesAsIsolate(templateDirectives);
              }
              directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
              mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
  
              ii = directives.length;
            } else {
              $compileNode.html(directiveValue);
            }
          }
  
          if (directive.templateUrl) {
            hasTemplate = true;
            assertNoDuplicate('template', templateDirective, directive, $compileNode);
            templateDirective = directive;
  
            if (directive.replace) {
              replaceDirective = directive;
            }
  
            nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
                templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
                  controllerDirectives: controllerDirectives,
                  newIsolateScopeDirective: newIsolateScopeDirective,
                  templateDirective: templateDirective,
                  nonTlbTranscludeDirective: nonTlbTranscludeDirective
                });
            ii = directives.length;
          } else if (directive.compile) {
            try {
              linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
              if (isFunction(linkFn)) {
                addLinkFns(null, linkFn, attrStart, attrEnd);
              } else if (linkFn) {
                addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
              }
            } catch (e) {
              $exceptionHandler(e, startingTag($compileNode));
            }
          }
  
          if (directive.terminal) {
            nodeLinkFn.terminal = true;
            terminalPriority = Math.max(terminalPriority, directive.priority);
          }
  
        }
  
        nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
        nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
        nodeLinkFn.templateOnThisElement = hasTemplate;
        nodeLinkFn.transclude = childTranscludeFn;
  
        previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
  
        // might be normal or delayed nodeLinkFn depending on if templateUrl is present
        return nodeLinkFn;
  
        ////////////////////
  
        function addLinkFns(pre, post, attrStart, attrEnd) {
          if (pre) {
            if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
            pre.require = directive.require;
            pre.directiveName = directiveName;
            if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
              pre = cloneAndAnnotateFn(pre, {isolateScope: true});
            }
            preLinkFns.push(pre);
          }
          if (post) {
            if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
            post.require = directive.require;
            post.directiveName = directiveName;
            if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
              post = cloneAndAnnotateFn(post, {isolateScope: true});
            }
            postLinkFns.push(post);
          }
        }
  
  
        function getControllers(directiveName, require, $element, elementControllers) {
          var value, retrievalMethod = 'data', optional = false;
          if (isString(require)) {
            while((value = require.charAt(0)) == '^' || value == '?') {
              require = require.substr(1);
              if (value == '^') {
                retrievalMethod = 'inheritedData';
              }
              optional = optional || value == '?';
            }
            value = null;
  
            if (elementControllers && retrievalMethod === 'data') {
              value = elementControllers[require];
            }
            value = value || $element[retrievalMethod]('$' + require + 'Controller');
  
            if (!value && !optional) {
              throw $compileMinErr('ctreq',
                  "Controller '{0}', required by directive '{1}', can't be found!",
                  require, directiveName);
            }
            return value;
          } else if (isArray(require)) {
            value = [];
            forEach(require, function(require) {
              value.push(getControllers(directiveName, require, $element, elementControllers));
            });
          }
          return value;
        }
  
  
        function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
          var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
  
          attrs = (compileNode === linkNode)
            ? templateAttrs
            : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
          $element = attrs.$$element;
  
          if (newIsolateScopeDirective) {
            var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
  
            isolateScope = scope.$new(true);
  
            if (templateDirective && (templateDirective === newIsolateScopeDirective ||
                templateDirective === newIsolateScopeDirective.$$originalDirective)) {
              $element.data('$isolateScope', isolateScope);
            } else {
              $element.data('$isolateScopeNoTemplate', isolateScope);
            }
  
  
  
            safeAddClass($element, 'ng-isolate-scope');
  
            forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
              var match = definition.match(LOCAL_REGEXP) || [],
                  attrName = match[3] || scopeName,
                  optional = (match[2] == '?'),
                  mode = match[1], // @, =, or &
                  lastValue,
                  parentGet, parentSet, compare;
  
              isolateScope.$$isolateBindings[scopeName] = mode + attrName;
  
              switch (mode) {
  
                case '@':
                  attrs.$observe(attrName, function(value) {
                    isolateScope[scopeName] = value;
                  });
                  attrs.$$observers[attrName].$$scope = scope;
                  if( attrs[attrName] ) {
                    // If the attribute has been provided then we trigger an interpolation to ensure
                    // the value is there for use in the link fn
                    isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
                  }
                  break;
  
                case '=':
                  if (optional && !attrs[attrName]) {
                    return;
                  }
                  parentGet = $parse(attrs[attrName]);
                  if (parentGet.literal) {
                    compare = equals;
                  } else {
                    compare = function(a,b) { return a === b; };
                  }
                  parentSet = parentGet.assign || function() {
                    // reset the change, or we will throw this exception on every $digest
                    lastValue = isolateScope[scopeName] = parentGet(scope);
                    throw $compileMinErr('nonassign',
                        "Expression '{0}' used with directive '{1}' is non-assignable!",
                        attrs[attrName], newIsolateScopeDirective.name);
                  };
                  lastValue = isolateScope[scopeName] = parentGet(scope);
                  var unwatch = scope.$watch($parse(attrs[attrName], function parentValueWatch(parentValue) {
                    if (!compare(parentValue, isolateScope[scopeName])) {
                      // we are out of sync and need to copy
                      if (!compare(parentValue, lastValue)) {
                        // parent changed and it has precedence
                        isolateScope[scopeName] = parentValue;
                      } else {
                        // if the parent can be assigned then do so
                        parentSet(scope, parentValue = isolateScope[scopeName]);
                      }
                    }
                    return lastValue = parentValue;
                  }), null, parentGet.literal);
                  isolateScope.$on('$destroy', unwatch);
                  break;
  
                case '&':
                  parentGet = $parse(attrs[attrName]);
                  isolateScope[scopeName] = function(locals) {
                    return parentGet(scope, locals);
                  };
                  break;
  
                default:
                  throw $compileMinErr('iscp',
                      "Invalid isolate scope definition for directive '{0}'." +
                      " Definition: {... {1}: '{2}' ...}",
                      newIsolateScopeDirective.name, scopeName, definition);
              }
            });
          }
          transcludeFn = boundTranscludeFn && controllersBoundTransclude;
          if (controllerDirectives) {
            forEach(controllerDirectives, function(directive) {
              var locals = {
                $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
                $element: $element,
                $attrs: attrs,
                $transclude: transcludeFn
              }, controllerInstance;
  
              controller = directive.controller;
              if (controller == '@') {
                controller = attrs[directive.name];
              }
  
              controllerInstance = $controller(controller, locals);
              // For directives with element transclusion the element is a comment,
              // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
              // clean up (http://bugs.jquery.com/ticket/8335).
              // Instead, we save the controllers for the element in a local hash and attach to .data
              // later, once we have the actual element.
              elementControllers[directive.name] = controllerInstance;
              if (!hasElementTranscludeDirective) {
                $element.data('$' + directive.name + 'Controller', controllerInstance);
              }
  
              if (directive.controllerAs) {
                locals.$scope[directive.controllerAs] = controllerInstance;
              }
            });
          }
  
          // PRELINKING
          for(i = 0, ii = preLinkFns.length; i < ii; i++) {
            try {
              linkFn = preLinkFns[i];
              linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
                  linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
            } catch (e) {
              $exceptionHandler(e, startingTag($element));
            }
          }
  
          // RECURSION
          // We only pass the isolate scope, if the isolate directive has a template,
          // otherwise the child elements do not belong to the isolate directive.
          var scopeToChild = scope;
          if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
            scopeToChild = isolateScope;
          }
          childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
  
          // POSTLINKING
          for(i = postLinkFns.length - 1; i >= 0; i--) {
            try {
              linkFn = postLinkFns[i];
              linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
                  linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
            } catch (e) {
              $exceptionHandler(e, startingTag($element));
            }
          }
  
          // This is the function that is injected as `$transclude`.
          function controllersBoundTransclude(scope, cloneAttachFn) {
            var transcludeControllers;
  
            // no scope passed
            if (arguments.length < 2) {
              cloneAttachFn = scope;
              scope = undefined;
            }
  
            if (hasElementTranscludeDirective) {
              transcludeControllers = elementControllers;
            }
  
            return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
          }
        }
      }
func_documentation_string: Once the directives have been collected, their compile functions are executed. This method
  is responsible for inlining directive templates as well as terminating the application
  of the directives if the terminal directive has been reached.
  
  @param {Array} directives Array of collected directives to execute their compile function.
  this needs to be pre-sorted by priority order.
  @param {Node} compileNode The raw DOM node to apply the compile functions to
  @param {Object} templateAttrs The shared attribute function
  @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
  scope argument is auto-generated to the new
  child of the transcluded parent scope.
  @param {JQLite} jqCollection If we are working on the root of the compile tree then this
  argument has the root jqLite array so that we can replace nodes
  on it.
  @param {Object=} originalReplaceDirective An optional directive that will be ignored when
  compiling the transclusion.
  @param {Array.<Function>} preLinkFns
  @param {Array.<Function>} postLinkFns
  @param {Object} previousCompileContext Context used for previous compilation of the current
  node
  @returns {Function} linkFn