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)
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;
  }