@Override
  public List<SchedulingTask> apply() {
    l = getAlgorithm().getWorkflow().instantiate(getInstance().getInstanceSize());
    setInstance(l);
    List<SchedulingTask> scheduledTasks = new ArrayList<SchedulingTask>(getScheduledTasks());

    getAlgorithm().schedulePathOnInstance(scheduledTasks, l, getUmodLocalTaskStarttimes());

    Set<SchedulingTask> modified = new HashSet<SchedulingTask>();
    for (SchedulingTask task : getPcp()) {
      repairDependencies(task, scheduledTasks, modified);
    }

    for (SchedulingTask t : modified) {
      t.setLatestEndTime(-1.);
    }

    for (SchedulingTask t : modified) {
      AbstractAlgorithm.calcLFT(t);
    }

    return scheduledTasks;
  }
  private void combineParallelLanesAnyPathesUsingJoinWhatever(
      SchedulingTask join, Comparator<Lane> throwerComparator) {

    Set<Lane> predecessors = AbstractAlgorithm.getParentLanesOfTaskSetReadOnly(join);

    List<Lane> throwerList = new ArrayList<Lane>(predecessors);
    List<Lane> catcherList = throwerList;
    Collections.sort(throwerList, throwerComparator);

    // shortest thrower first
    for (Lane thrower : throwerList) {
      if (!algorithm.getWorkflow().existsLane(thrower)) {
        continue;
      }

      SchedulingTaskList throwerLastPath = thrower.getUmodLastPath();
      if (throwerLastPath.size() == thrower.getTasksCount()) {
        continue;
      }

      // for (Lane catcher : catcherList) {
      for (int i = catcherList.size() - 1; i >= 0; --i) {
        Lane catcher = catcherList.get(i); // longest catcher first
        if (!algorithm.getWorkflow().existsLane(catcher) || catcher == thrower) {
          continue;
        }

        // thrower catcher combination
        tryMigrateWhatever(thrower, catcher);
        boolean throwerReleased = !algorithm.getWorkflow().existsLane(thrower);
        if (throwerReleased) {
          // next thrower
          break;
        }
      } // catcher for
    } // thrower for
  }