let run ~(run_with: Machine.t)     ~configuration     ~reference_build     ~vcfs     ~bam     ~predictor     ~alleles_file     ~output_folder   =   let open KEDSL in   let host = Machine.(as_host run_with) in   let vaxrank =     Machine.get_tool run_with Machine.Tool.Definition.(create "vaxrank")   in   let sorted_bam =     Samtools.sort_bam_if_necessary ~run_with ~by:`Coordinate bam in   let predictor_tool = Topiary.(predictor_to_tool ~run_with predictor) in   let (predictor_edges, predictor_init) =     match predictor_tool with     | Some (e, i) -> ([depends_on e;], i)     | None -> ([], Program.(sh "echo 'No external prediction tool required'"))   in   let vcfs_arg = List.concat_map vcfs ~f:(fun v -> ["--vcf"; v#product#path]) in   let bam_arg = ["--bam"; sorted_bam#product#path] in   let predictor_arg =     ["--mhc-predictor"; (Topiary.predictor_to_string predictor)] in   let allele_arg = ["--mhc-alleles-file"; alleles_file#product#path] in   let output_prefix = output_folder // "vaxrank-result" in   let output_of switch kind suffix  =     let path = output_prefix ^ "." ^ suffix in     let arg = if switch       then [sprintf "--output-%s-report" kind; path] else [] in     let prod = if switch       then Some (KEDSL.single_file ~host path) else None in     arg, prod   in   let ascii_arg, ascii_product =     output_of configuration.Configuration.ascii_report "ascii" "txt" in   let xlsx_arg, xlsx_product =     output_of configuration.Configuration.xlsx_report "xlsx" "xlsx" in   let pdf_arg, pdf_product =     output_of configuration.Configuration.pdf_report "pdf" "pdf" in   let () =     match ascii_product, xlsx_product, pdf_product with     | NoneNoneNone ->       failwith "Vaxrank requires one or more of pdf_report, xlsx_report, or ascii_report."     | _, _, _ -> () in   let arguments =     vcfs_arg @ bam_arg @ predictor_arg @ allele_arg (* input *)     @ xlsx_arg @ pdf_arg @ ascii_arg     @ Configuration.render configuration (* other config *)   in   let name = "Vaxrank run" in   let product =     let path_of f = Option.map f ~f:(fun f -> f#path) in     object       method is_done =         Some (`And                 (List.filter_map ~f:(fun f ->                      let open Option in                      f >>= fun f -> f#is_done)                    [ascii_product; xlsx_product; pdf_product]))       method ascii_report_path = path_of ascii_product       method xlsx_report_path = path_of xlsx_product       method pdf_report_path = path_of pdf_product       method output_folder_path = output_folder     end   in   workflow_node     product     ~name     ~edges:([         depends_on (Samtools.index_to_bai ~run_with sorted_bam);         depends_on Machine.Tool.(ensure vaxrank);         depends_on (Pyensembl.cache_genome ~run_with ~reference_build);         depends_on sorted_bam;         depends_on alleles_file;       ] @ (List.map ~f:depends_on vcfs)         @ predictor_edges)     ~make:(       Machine.run_program run_with ~name         Program.(           Machine.Tool.(init vaxrank)           && predictor_init           && Pyensembl.(set_cache_dir_command ~run_with)           && shf "mkdir -p %s" (Filename.quote output_folder)           && exec (["vaxrank"] @ arguments)         )     )