whole_func_string: function ApplyPatchMultiChunk(script, diff_array, new_source, preview_only,
        change_log) {
  
      var old_source = script.source;
  
      // Gather compile information about old version of script.
      var old_compile_info = GatherCompileInfo(old_source, script);
  
      // Build tree structures for old and new versions of the script.
      var root_old_node = BuildCodeInfoTree(old_compile_info);
  
      var pos_translator = new PosTranslator(diff_array);
  
      // Analyze changes.
      MarkChangedFunctions(root_old_node, pos_translator.GetChunks());
  
      // Find all SharedFunctionInfo's that were compiled from this script.
      FindLiveSharedInfos(root_old_node, script);
  
      // Gather compile information about new version of script.
      var new_compile_info;
      try {
        new_compile_info = GatherCompileInfo(new_source, script);
      } catch (e) {
        var failure =
            new Failure("Failed to compile new version of script: " + e);
        if (e instanceof SyntaxError) {
          var details = {
            type: "liveedit_compile_error",
            syntaxErrorMessage: e.message
          };
          CopyErrorPositionToDetails(e, details);
          failure.details = details;
        }
        throw failure;
      }
      var root_new_node = BuildCodeInfoTree(new_compile_info);
  
      // Link recompiled script data with other data.
      FindCorrespondingFunctions(root_old_node, root_new_node);
  
      // Prepare to-do lists.
      var replace_code_list = new GlobalArray();
      var link_to_old_script_list = new GlobalArray();
      var link_to_original_script_list = new GlobalArray();
      var update_positions_list = new GlobalArray();
  
      function HarvestTodo(old_node) {
        function CollectDamaged(node) {
          link_to_old_script_list.push(node);
          for (var i = 0; i < node.children.length; i++) {
            CollectDamaged(node.children[i]);
          }
        }
  
        // Recursively collects all newly compiled functions that are going into
        // business and should have link to the actual script updated.
        function CollectNew(node_list) {
          for (var i = 0; i < node_list.length; i++) {
            link_to_original_script_list.push(node_list[i]);
            CollectNew(node_list[i].children);
          }
        }
  
        if (old_node.status == FunctionStatus.DAMAGED) {
          CollectDamaged(old_node);
          return;
        }
        if (old_node.status == FunctionStatus.UNCHANGED) {
          update_positions_list.push(old_node);
        } else if (old_node.status == FunctionStatus.SOURCE_CHANGED) {
          update_positions_list.push(old_node);
        } else if (old_node.status == FunctionStatus.CHANGED) {
          replace_code_list.push(old_node);
          CollectNew(old_node.unmatched_new_nodes);
        }
        for (var i = 0; i < old_node.children.length; i++) {
          HarvestTodo(old_node.children[i]);
        }
      }
  
      var preview_description = {
          change_tree: DescribeChangeTree(root_old_node),
          textual_diff: {
            old_len: old_source.length,
            new_len: new_source.length,
            chunks: diff_array
          },
          updated: false
      };
  
      if (preview_only) {
        return preview_description;
      }
  
      HarvestTodo(root_old_node);
  
      // Collect shared infos for functions whose code need to be patched.
      var replaced_function_old_infos = new GlobalArray();
      var replaced_function_new_infos = new GlobalArray();
      for (var i = 0; i < replace_code_list.length; i++) {
        var old_infos = replace_code_list[i].live_shared_function_infos;
        var new_info =
            replace_code_list[i].corresponding_node.info.shared_function_info;
  
        if (old_infos) {
          for (var j = 0; j < old_infos.length; j++) {
            replaced_function_old_infos.push(old_infos[j]);
            replaced_function_new_infos.push(new_info);
          }
        }
      }
  
      // We haven't changed anything before this line yet.
      // Committing all changes.
  
      // Check that function being patched is not currently on stack or drop them.
      var dropped_functions_number =
          CheckStackActivations(replaced_function_old_infos,
                                replaced_function_new_infos,
                                change_log);
  
      // Our current implementation requires client to manually issue "step in"
      // command for correct stack state if the stack was modified.
      preview_description.stack_modified = dropped_functions_number != 0;
  
      // Start with breakpoints. Convert their line/column positions and
      // temporary remove.
      var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log);
  
      var old_script;
  
      // Create an old script only if there are function that should be linked
      // to old version.
      if (link_to_old_script_list.length == 0) {
        %LiveEditReplaceScript(script, new_source, null);
        old_script = UNDEFINED;
      } else {
        var old_script_name = CreateNameForOldScript(script);
  
        // Update the script text and create a new script representing an old
        // version of the script.
        old_script = %LiveEditReplaceScript(script, new_source,
            old_script_name);
  
        var link_to_old_script_report = new GlobalArray();
        change_log.push( { linked_to_old_script: link_to_old_script_report } );
  
        // We need to link to old script all former nested functions.
        for (var i = 0; i < link_to_old_script_list.length; i++) {
          LinkToOldScript(link_to_old_script_list[i], old_script,
              link_to_old_script_report);
        }
  
        preview_description.created_script_name = old_script_name;
      }
  
      // Link to an actual script all the functions that we are going to use.
      for (var i = 0; i < link_to_original_script_list.length; i++) {
        %LiveEditFunctionSetScript(
            link_to_original_script_list[i].info.shared_function_info, script);
      }
  
      for (var i = 0; i < replace_code_list.length; i++) {
        PatchFunctionCode(replace_code_list[i], change_log);
      }
  
      var position_patch_report = new GlobalArray();
      change_log.push( {position_patched: position_patch_report} );
  
      for (var i = 0; i < update_positions_list.length; i++) {
        // TODO(LiveEdit): take into account whether it's source_changed or
        // unchanged and whether positions changed at all.
        PatchPositions(update_positions_list[i], diff_array,
            position_patch_report);
  
        if (update_positions_list[i].live_shared_function_infos) {
          update_positions_list[i].live_shared_function_infos.
              forEach(function (info) {
                  %LiveEditFunctionSourceUpdated(info.raw_array);
                });
        }
      }
  
      break_points_restorer(pos_translator, old_script);
  
      preview_description.updated = true;
      return preview_description;
    }
func_code_string: function ApplyPatchMultiChunk(script, diff_array, new_source, preview_only,
        change_log) {
  
      var old_source = script.source;
  
      // Gather compile information about old version of script.
      var old_compile_info = GatherCompileInfo(old_source, script);
  
      // Build tree structures for old and new versions of the script.
      var root_old_node = BuildCodeInfoTree(old_compile_info);
  
      var pos_translator = new PosTranslator(diff_array);
  
      // Analyze changes.
      MarkChangedFunctions(root_old_node, pos_translator.GetChunks());
  
      // Find all SharedFunctionInfo's that were compiled from this script.
      FindLiveSharedInfos(root_old_node, script);
  
      // Gather compile information about new version of script.
      var new_compile_info;
      try {
        new_compile_info = GatherCompileInfo(new_source, script);
      } catch (e) {
        var failure =
            new Failure("Failed to compile new version of script: " + e);
        if (e instanceof SyntaxError) {
          var details = {
            type: "liveedit_compile_error",
            syntaxErrorMessage: e.message
          };
          CopyErrorPositionToDetails(e, details);
          failure.details = details;
        }
        throw failure;
      }
      var root_new_node = BuildCodeInfoTree(new_compile_info);
  
      // Link recompiled script data with other data.
      FindCorrespondingFunctions(root_old_node, root_new_node);
  
      // Prepare to-do lists.
      var replace_code_list = new GlobalArray();
      var link_to_old_script_list = new GlobalArray();
      var link_to_original_script_list = new GlobalArray();
      var update_positions_list = new GlobalArray();
  
      function HarvestTodo(old_node) {
        function CollectDamaged(node) {
          link_to_old_script_list.push(node);
          for (var i = 0; i < node.children.length; i++) {
            CollectDamaged(node.children[i]);
          }
        }
  
        // Recursively collects all newly compiled functions that are going into
        // business and should have link to the actual script updated.
        function CollectNew(node_list) {
          for (var i = 0; i < node_list.length; i++) {
            link_to_original_script_list.push(node_list[i]);
            CollectNew(node_list[i].children);
          }
        }
  
        if (old_node.status == FunctionStatus.DAMAGED) {
          CollectDamaged(old_node);
          return;
        }
        if (old_node.status == FunctionStatus.UNCHANGED) {
          update_positions_list.push(old_node);
        } else if (old_node.status == FunctionStatus.SOURCE_CHANGED) {
          update_positions_list.push(old_node);
        } else if (old_node.status == FunctionStatus.CHANGED) {
          replace_code_list.push(old_node);
          CollectNew(old_node.unmatched_new_nodes);
        }
        for (var i = 0; i < old_node.children.length; i++) {
          HarvestTodo(old_node.children[i]);
        }
      }
  
      var preview_description = {
          change_tree: DescribeChangeTree(root_old_node),
          textual_diff: {
            old_len: old_source.length,
            new_len: new_source.length,
            chunks: diff_array
          },
          updated: false
      };
  
      if (preview_only) {
        return preview_description;
      }
  
      HarvestTodo(root_old_node);
  
      // Collect shared infos for functions whose code need to be patched.
      var replaced_function_old_infos = new GlobalArray();
      var replaced_function_new_infos = new GlobalArray();
      for (var i = 0; i < replace_code_list.length; i++) {
        var old_infos = replace_code_list[i].live_shared_function_infos;
        var new_info =
            replace_code_list[i].corresponding_node.info.shared_function_info;
  
        if (old_infos) {
          for (var j = 0; j < old_infos.length; j++) {
            replaced_function_old_infos.push(old_infos[j]);
            replaced_function_new_infos.push(new_info);
          }
        }
      }
  
      // We haven't changed anything before this line yet.
      // Committing all changes.
  
      // Check that function being patched is not currently on stack or drop them.
      var dropped_functions_number =
          CheckStackActivations(replaced_function_old_infos,
                                replaced_function_new_infos,
                                change_log);
  
      // Our current implementation requires client to manually issue "step in"
      // command for correct stack state if the stack was modified.
      preview_description.stack_modified = dropped_functions_number != 0;
  
      // Start with breakpoints. Convert their line/column positions and
      // temporary remove.
      var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log);
  
      var old_script;
  
      // Create an old script only if there are function that should be linked
      // to old version.
      if (link_to_old_script_list.length == 0) {
        %LiveEditReplaceScript(script, new_source, null);
        old_script = UNDEFINED;
      } else {
        var old_script_name = CreateNameForOldScript(script);
  
        // Update the script text and create a new script representing an old
        // version of the script.
        old_script = %LiveEditReplaceScript(script, new_source,
            old_script_name);
  
        var link_to_old_script_report = new GlobalArray();
        change_log.push( { linked_to_old_script: link_to_old_script_report } );
  
        // We need to link to old script all former nested functions.
        for (var i = 0; i < link_to_old_script_list.length; i++) {
          LinkToOldScript(link_to_old_script_list[i], old_script,
              link_to_old_script_report);
        }
  
        preview_description.created_script_name = old_script_name;
      }
  
      // Link to an actual script all the functions that we are going to use.
      for (var i = 0; i < link_to_original_script_list.length; i++) {
        %LiveEditFunctionSetScript(
            link_to_original_script_list[i].info.shared_function_info, script);
      }
  
      for (var i = 0; i < replace_code_list.length; i++) {
        PatchFunctionCode(replace_code_list[i], change_log);
      }
  
      var position_patch_report = new GlobalArray();
      change_log.push( {position_patched: position_patch_report} );
  
      for (var i = 0; i < update_positions_list.length; i++) {
        // TODO(LiveEdit): take into account whether it's source_changed or
        // unchanged and whether positions changed at all.
        PatchPositions(update_positions_list[i], diff_array,
            position_patch_report);
  
        if (update_positions_list[i].live_shared_function_infos) {
          update_positions_list[i].live_shared_function_infos.
              forEach(function (info) {
                  %LiveEditFunctionSourceUpdated(info.raw_array);
                });
        }
      }
  
      break_points_restorer(pos_translator, old_script);
  
      preview_description.updated = true;
      return preview_description;
    }
func_documentation_string: Applies the change to the script. The change is in form of list of chunks encoded in a single array as a series of triplets (pos1_start, pos1_end, pos2_end)