/** Create the plates node networks. */
    @Override
    public void buildPhase() throws PipelineException {
      StageInformation stageInfo = getStageInformation();

      /* stage prerequisites */
      {
        /* lock the latest version of all of the prerequisites */
        lockNodePrerequisites();

        /* lock the specific version of the source images node we are delivering */
        pClient.lock(
            getAuthor(), getView(), pSourceVersion.getName(), pSourceVersion.getVersionID());
      }

      /* the delivery network */
      {
        String readQtDeliverableImagesNodeName = pDeliverNamer.getReadQtDeliverableImagesNode();
        {
          NukeReadStage stage =
              new NukeReadStage(
                  stageInfo,
                  pContext,
                  pClient,
                  readQtDeliverableImagesNodeName,
                  pSourceVersion.getName());
          stage.addSingleParamValue("ReadName", "Images");
          addTaskAnnotation(stage, NodePurpose.Prepare);
          stage.build();
        }

        String qtDeliverSlateNukeNodeName = pDeliverNamer.getQtDeliverSlateNukeNode();
        {
          SlateSubstStage stage =
              new SlateSubstStage(
                  stageInfo,
                  pContext,
                  pClient,
                  qtDeliverSlateNukeNodeName,
                  pSlateNodeName,
                  pDeliveryType,
                  pDeliverable,
                  pClientVersion,
                  pClientShotName,
                  pLensInfo,
                  pTakeInfo,
                  pSourceVersion,
                  pNotes,
                  pSlateHold);
          addTaskAnnotation(stage, NodePurpose.Prepare);
          stage.build();
        }

        String qtDeliverSlatedImagesNodeName = pDeliverNamer.getQtDeliverSlatedImagesNode();
        {
          TreeMap<String, String> subst = new TreeMap<String, String>();
          subst.put(readQtDeliverableImagesNodeName, "Images");
          subst.put(pFormatNodeName, "FinalFormat");

          NukeSubstCompStage stage =
              new NukeSubstCompStage(
                  stageInfo,
                  pContext,
                  pClient,
                  qtDeliverSlatedImagesNodeName,
                  pFrameRange,
                  4,
                  "jpg",
                  "Append & Process",
                  qtDeliverSlateNukeNodeName,
                  subst);
          addTaskAnnotation(stage, NodePurpose.Prepare);
          stage.build();
        }

        String qtDeliverSlatedMovieNodeName = pDeliverNamer.getQtDeliverSlatedMovieNode();
        {
          DjvUnixQtStage stage =
              new DjvUnixQtStage(
                  stageInfo,
                  pContext,
                  pClient,
                  qtDeliverSlatedMovieNodeName,
                  qtDeliverSlatedImagesNodeName,
                  "24");
          addTaskAnnotation(stage, NodePurpose.Prepare);
          stage.build();
        }

        String qtDeliverableNodeName = pDeliverNamer.getQtDeliverableNode();
        {
          QtEncodeStage stage =
              new QtEncodeStage(
                  stageInfo,
                  pContext,
                  pClient,
                  qtDeliverableNodeName,
                  qtDeliverSlatedMovieNodeName,
                  pCodecNodeName);
          addTaskAnnotation(stage, NodePurpose.Deliver);
          stage.build();
          addToQueueList(qtDeliverableNodeName);
          addToCheckInList(qtDeliverableNodeName);
        }
      }
    }
    /**
     * Phase in which parameter values should be extracted from parameters and checked for
     * consistency and applicability.
     */
    @Override
    public void validatePhase() throws PipelineException {
      /* sets up the built-in parameters common to all builders */
      validateBuiltInParams();

      /* setup the StudioDefinitions version of the UtilContext */
      pStudioDefs.setContext(pContext);

      /* lookup the source images node */
      String sourceNodeName = null;
      VersionID sourceVersionID = null;
      {
        Path spath = (Path) getParamValue(aSourceNode);
        if (spath == null) throw new PipelineException("No " + aSourceNode + " was specified!");
        sourceNodeName = spath.toString();
        pSourcePrefix = spath.getName();

        String sversion = (String) getParamValue(aSourceVersion);
        if (sversion == null)
          throw new PipelineException("No " + aSourceVersion + " was specified!");

        try {
          sourceVersionID = new VersionID(sversion);
        } catch (Exception ex) {
          throw new PipelineException(
              "The value supplied for the "
                  + aSourceVersion
                  + " parameter "
                  + "("
                  + sversion
                  + ") is not a legal node revision number!\n\n"
                  + ex.getMessage());
        }

        try {
          pSourceVersion = pClient.getCheckedInVersion(sourceNodeName, sourceVersionID);
        } catch (PipelineException ex) {
          throw new PipelineException(
              "The source images node ("
                  + sourceNodeName
                  + " v"
                  + sourceVersionID
                  + ") "
                  + "does not exist!");
        }
      }

      /* set namer/builder parameters based on the annotations on the source images node */
      {
        boolean validated = false;
        String projName = null;
        String taskName = null;
        String taskType = null;
        TreeMap<String, BaseAnnotation> annotations = pClient.getAnnotations(sourceNodeName);
        TreeSet<String> otherPurposes = new TreeSet<String>();
        for (String aname : annotations.keySet()) {
          if (aname.equals("Task") || aname.startsWith("AltTask")) {
            BaseAnnotation annot = annotations.get(aname);
            String purpose = lookupPurpose(sourceNodeName, aname, annot);
            if (purpose == null) {
              otherPurposes.add("<UNKNWON>");
            } else if (purpose.equals(aFocus)
                || purpose.equals(aEdit)
                || purpose.equals(aProduct)) {
              projName = lookupProjectName(sourceNodeName, aname, annot);
              taskName = lookupTaskName(sourceNodeName, aname, annot);
              taskType = lookupTaskType(sourceNodeName, aname, annot);
              validated = true;
              break;
            } else {
              otherPurposes.add(purpose);
            }
          }
        }

        if (!validated) {
          StringBuilder buf = new StringBuilder();
          buf.append(
              "Unable to find an valid "
                  + aEdit
                  + ", "
                  + aFocus
                  + " or "
                  + aProduct
                  + " "
                  + "task annotation for the source images node ("
                  + sourceNodeName
                  + " v"
                  + sourceVersionID
                  + ")!");

          if (!otherPurposes.isEmpty()) {
            buf.append(
                "\n\nHowever, there were task annotations on the source images node for "
                    + "the following unsupported purposes:");
            for (String purpose : otherPurposes) buf.append(" " + purpose);
          }

          throw new PipelineException(buf.toString());
        }

        if (taskName.length() != 5)
          throw new PipelineException(
              "The "
                  + aTaskName
                  + " ("
                  + taskName
                  + ") of the source images "
                  + "node ("
                  + sourceNodeName
                  + " v"
                  + sourceVersionID
                  + ") did not conform to "
                  + "the 2-letter sequence name followed by 3-digit shot number format!");
        pProjectName = projName;
        pSeqName = taskName.substring(0, 2);
        pShotName = taskName.substring(2, 5);

        try {
          pTaskType = TaskType.valueOf(TaskType.class, taskType);
        } catch (IllegalArgumentException ex) {
          throw new PipelineException(
              "The "
                  + DeliverNamer.aTaskType
                  + " ("
                  + taskType
                  + ") of the source images "
                  + "node ("
                  + sourceNodeName
                  + " v"
                  + sourceVersionID
                  + ") was an unknown type "
                  + "by this builder!");
        }
      }

      /* generate a temporary working area where the approval process will take place
      and change the util context to use it instead for all future operations */
      {
        String tempView =
            ("QtDeliver" + "-" + pProjectName + "-" + pSeqName + pShotName + "-" + pSourcePrefix);
        tempView = tempView.replaceAll(" ", "_");

        setContext(new UtilContext(pContext.getAuthor(), tempView, pContext.getToolset()));
      }

      /* turn on the DoAnnotations flag for the StageInformation shared by all
      of the Stages created by this builder since we always want task annotations */
      getStageInformation().setDoAnnotations(true);

      /* initialize internal Project namer */
      {
        pProjectNamer.setParamValue(new ParamMapping(StudioDefinitions.aProjectName), pProjectName);
        pProjectNamer.generateNames();
      }
    }