1#![doc(html_logo_url = "https://images.squarespace-cdn.com/content/v1/60416644b68a5453a868e856/1628206791960-M61IU1QP850NRLI9CE07/Stanhope+Etching.jpg?format=2500w")]
2mod read_csv;
14mod read_xlsx;
15mod read_ebml;
16mod write_ebml;
17mod write_html;
18mod write_script;
19mod write_webmenu;
20
21use std::{
23 process::Command,
24 fs::{self},
27 io::{self, Error, ErrorKind, Result},
28 path::Path,
29};
30use chrono::prelude::*;
31use read_ebml::Process;
32
33use clap::Parser; use read_csv::read_csv; use read_xlsx::read_xlsx;
36use write_ebml::get_process_folder_name;
37use write_ebml::write_ebml;
38use read_ebml::read_ebml;
39use crate::read_ebml::SubStep;
40use write_html::generate_complete_html;
41use write_webmenu::generate_complete_webmenu;
42use glob::glob;
43
44#[derive(Parser, Debug)]
46#[command(version, about =
47"\n\n\x1b[1;30;47mStanope\x1b[0m\x1b[30;47m, the Easy Button process generation engine.\x1b[0m
48
49Arguments passed into the options should be surrounded by single or double quotes, e.g.
50% ./stanhope -p \"EB-WI-0010\" \x1b[36m<< double quotes are accepted\x1b[0m
51% ./stanhope -a 'EB-WI-*' \x1b[36m<< single quotes are accepted\x1b[0m",
52author = "Strativus Group <contact@strativusgroup.com>",
53long_about = None,
54after_help =
55"
56")]
57struct StanhopeArgs {
58 #[arg(short, long, value_name = "SPREADSHEET-FILE", default_value_t = String::from(""), verbatim_doc_comment)]
72 listgen: String,
73
74 #[arg(short, long, default_value_t = false, verbatim_doc_comment)]
78 webmenu: bool,
79
80 #[arg(short, long, default_value_t = false, verbatim_doc_comment)]
84 graphics_audit: bool,
85
86 #[arg(short, long, default_value_t = false, verbatim_doc_comment)]
90 filename_audit: bool,
91
92 #[arg(short, long, default_value_t = false, verbatim_doc_comment)]
99 marking_audit: bool,
100
101 #[arg(short, long, value_name = "DOCUMENT-NUMBER", default_value_t = String::from(""), verbatim_doc_comment)]
107 process_ebml: String,
108
109 #[arg(short, long, use_value_delimiter = true, value_delimiter = ' ', num_args = 3, value_names = ["DOCUMENT-NUMBER","SCRIPT-FORMAT","PAUSE-AFTER-EACH"], verbatim_doc_comment)]
119 scriptify_process: Vec<String>,
120
121 #[arg(short, long, value_name = "DOCUMENT-NUMBER", default_value_t = String::from(""), verbatim_doc_comment)]
129 archive_process: String,
130
131 #[arg(short, long, value_name = "DOCUMENT-NUMBER", default_value_t = String::from(""), verbatim_doc_comment)]
137 inspect_process: String,
138
139 #[arg(short, long, value_name = "DOCUMENT-NUMBER", default_value_t = String::from(""), verbatim_doc_comment)]
145 cleanup_previous: String,
146
147 #[arg(short, long, default_value_t = false,)]
149 verbose: bool,
150
151 #[arg(short, long, default_value_t = false,)]
153 ebml_help: bool,
154}
155
156fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
158 fs::create_dir_all(&dst)?;
159 for entry in fs::read_dir(src)? {
160 let entry = entry?;
161 let ty = entry.file_type()?;
162 if ty.is_dir() {
163 copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
164 } else {
165 fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
166 }
167 }
168 Ok(())
169}
170
171fn copy_files_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
173 fs::create_dir_all(&dst)?;
174 for entry in fs::read_dir(src)? {
175 let entry = entry?;
176 let ty = entry.file_type()?;
177 if ty.is_dir() {
178 ();
179 } else {
180 fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
181 }
182 }
183 Ok(())
184}
185
186fn archive_single_process(new_proc: Process, verbose: &bool) {
188 let previous_folder = get_process_folder_name(&new_proc).to_owned() + "/previous";
191 match Path::new(&previous_folder).exists() {
192 true => (),
193 false => { let _ = fs::create_dir(&previous_folder); },
194 };
195 let root_assets_folder = "./assets";
196 let previous_assets_folder = previous_folder.clone() + "/assets";
197 match Path::new(&previous_assets_folder).exists() {
198 true => (),
199 false => { let _ = fs::create_dir(&previous_assets_folder); },
200 };
201
202 let rev_string = new_proc.get_revision();
204 let right_now_string = Utc::now().format("UTC-%Y-%m-%d-T%H-%M-%S").to_string();
205 let timestamp_folder = previous_folder.clone() + "/Rev_" + new_proc.get_revision() + "_" + &right_now_string;
206 if *verbose {
207 println!("Revision: {}",&rev_string);
208 println!("SystemTime::now() ...ish: {}",right_now_string);
209 println!("Trying to create this folder: {:?}",timestamp_folder);
210 }
211 let _ = fs::create_dir(×tamp_folder);
212 let _ = copy_dir_all(root_assets_folder,previous_assets_folder);
214 let _ = copy_files_all(get_process_folder_name(&new_proc),timestamp_folder.clone());
216}
217
218fn list_directories_to_cleanup(prev:String) -> Vec<String> {
229
230 let mut all_revs:Vec<String> = vec![];
231 let mut directories_to_cleanup:Vec<String> = vec![];
232 let all_archives = glob(&(prev.clone() + "/Rev_*_UTC-*-*-*-T*-*-*")).expect("Failed to read glob pattern");
233
234 for entry in all_archives {
235 match entry {
236 Ok(path) => {
237 let archive = path.file_name().expect("huh?").to_str().expect("huh?");
238 let pos = archive.find("_UTC-").expect("rust is hard");
239 let rev = String::from(&archive[4..pos]);
240 all_revs.push(rev);
241 },
242 Err(e) => println!("{:?}",e),
243 }
244 }
245
246 all_revs.dedup();
247 println!("For this process, these are all the revisions: {:?}",&all_revs);
248
249 for rev in all_revs {
250 println!("\nHere are all of the archive folders for Rev {}:",rev);
251 let these = glob(&(prev.clone() + "/Rev_" + &rev + "_UTC-*-*-*-T*-*-*")).expect("Failed to read glob pattern");
252 let mut vec:Vec<String> = vec![];
253 for this in these {
254 match this {
255 Ok(path) => vec.push(path.file_name().expect("huh?").to_str().expect("huh?").to_string()),
256 Err(e) => println!("{:?}",e),
257 }
258 }
259 vec.sort_by(|a, b| a.to_lowercase().cmp(&b.to_lowercase()));
260 let keeper = vec.pop().expect("pop?");
261 for d in &vec {
262 println!(" {} \x1b[93mDELETE\x1b[0m",&d);
263 }
264 println!(" 💾 {} 💾 << only one to be saved...",&keeper);
265 directories_to_cleanup.append(&mut vec);
266 }
267 directories_to_cleanup
268}
269
270pub fn globify_document_number(input:&String) -> Vec<String> {
272 let all_results = match input.chars().last().unwrap() {
273 '*' => glob(&(input.to_owned())).expect("Failed to read glob pattern"),
274 _ => glob(&(input.to_owned()+"*")).expect("Failed to read glob pattern"),
275 };
276 let mut matching_process_folders:Vec<String> = vec![];
277
278 for entry in all_results {
279 match entry {
280 Ok(path) => {
281 let process_folder = path.file_name().expect("huh?").to_str().expect("huh?");
282 matching_process_folders.push(String::from(process_folder));
283 },
284 Err(e) => println!("{:?}",e),
285 }
286 }
287 matching_process_folders
288}
289
290fn attempt_fallbacks(fallbacks: Vec<Box<dyn Fn() -> Result<i32>>>) -> Result<i32> {
292 let mut last_error = None;
293
294 for fallback in fallbacks {
295 match fallback() {
296 Ok(value) => return Ok(value),
297 Err(e) => {
298 println!("Call failed, trying next... (Error: {})", e);
299 last_error = Some(e);
300 }
301 }
302 }
303
304 Err(last_error.unwrap_or_else(|| Error::new(ErrorKind::Other, "No fallbacks provided")))
305}
306
307fn print_graphics_audit_to_stdout(v:&bool) {
317 let list_of_process_folders = write_webmenu::find_all_process_folders(".");
318 print_title_block_to_stdout("Library Graphics Audit");
320 for folder in list_of_process_folders {
321 let folder_string = folder.file_name().expect("No bueno?").to_str().expect("Really bueno?").to_string();
322 let new_ebml_str = folder_string.clone() + "/" + &folder_string + ".ebml";
323 let new_process = read_ebml(&("./".to_owned()+&new_ebml_str));
324
325 if new_process.get_missing_image_count() == 0 {
326 println!(" [ No missing images! ] {}",&folder_string);
327 } else {
328 println!(" ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ {}",&folder_string);
329 }
330 if new_process.get_missing_image_count() > 0 {
331 println!(" ▒▒▒▒▒▒▒▒▒▒▒ -> Missing Images");
332 for image in new_process.get_missing_images() {
333 println!(" ▒▒▒▒▒▒▒▒ {}",image);
334 }
335 }
336 if *v {
337 if new_process.get_all_images().len() > 0 {
338 println!(" -> All Images");
339 for image in new_process.get_all_images() {
340 println!(" {}",image.0);
341 }
342 } else { println!(" -> No images at all, in fact..."); }
343 }
344 }
345}
346
347fn print_filename_audit_to_stdout(v:&bool) {
360 let list_of_process_folders = write_webmenu::find_all_process_folders(".");
361 print_title_block_to_stdout("Library Filename Audit");
362 for folder in list_of_process_folders {
363 let expected_folder_string = folder.file_name().expect("No bueno?").to_str().expect("Really bueno?").to_string();
364 let expected_ebml_str = expected_folder_string.clone() + "/" + &expected_folder_string + ".ebml";
365 println!("{}→ {}",if *v {"\n"}else{""},expected_folder_string);
366 match Path::new(&expected_ebml_str).exists() {
367 true => {
368 if *v { println!(" ↳ {}",expected_ebml_str); }
369 let new_proc = read_ebml(&("./".to_owned()+&expected_ebml_str));
370 if *v { println!(" ↳ EBML file exists as named above."); }
371 if *v { println!(" ↳ EBML Contents 'Number' : {}",new_proc.get_number()); }
372 if *v { println!(" ↳ EBML Contents 'Title' : {}",new_proc.get_title()); }
373 if expected_folder_string == (new_proc.get_number().to_owned() + " - " + new_proc.get_title()).to_string() {
374 if *v { println!(" ↳ CLEAN AUDIT: EBML CONTENTS MATCH FOLDER AND FILE NAMES"); }
375 } else {
376 println!(" ↳ \x1b[31mWARNING: SOMETHING IS MISMATCHED BETWEEN FOLDER NAME, FILE NAME, AND EBML CONTENTS\x1b[0m");
377 println!(" ↳ \x1b[33mSpecial characters in EBML title converted to '_' in folder/file names might be OK\x1b[0m");
378 }
379 },
380 false => {
381 println!(" ↳ \x1b[31m{}\x1b[0m",expected_ebml_str);
382 println!(" ↳ \x1b[31mWARNING: LIKELY FOLDER NAME MISMATCH WITH EBML NAME\x1b[0m");
383 },
384 };
385 }
386}
387
388fn print_marking_audit_to_stdout(v:&bool) {
394 let list_of_process_folders = write_webmenu::find_all_process_folders(".");
395 print_title_block_to_stdout("(Portion) Marking Audit");
396
397 println!("{} folders...",list_of_process_folders.len());
398
399 for folder in list_of_process_folders {
400 if *v {print!("\n================================================================================");}
401 let mut numer:u16 = 0;
402 let mut denom:u16 = 0;
403
404 let folder_string = folder.file_name().expect("No bueno?").to_str().expect("Really bueno?").to_string();
405
406 let new_ebml_str = folder_string.clone() + "/" + &folder_string + ".ebml";
407 let new_process = read_ebml(&("./".to_owned()+&new_ebml_str));
408
409 let classification_header = get_classification_header(new_process.get_all_templates());
410
411 print!("\n");
412 println!("{}",&folder_string);
413 println!("\x1b[1;37;44m{}\x1b[0m",classification_header);
414
415 (numer,denom) = tally_portion_marking_check(&folder_string,numer,denom,&true);
416
417 (numer,denom) = tally_portion_marking_check(new_process.get_title(),numer,denom,v);
419 (numer,denom) = tally_portion_marking_check(new_process.get_subject(),numer,denom,v);
420 (numer,denom) = tally_portion_marking_check(new_process.get_product(),numer,denom,v);
421 for rev in new_process.get_all_revisions() {
422 (numer,denom) = tally_portion_marking_check(&rev.1,numer,denom,v);
423 }
424 for sec in new_process.get_all_sections() {
425 (numer,denom) = tally_portion_marking_check(&sec.get_title(),numer,denom,v);
426 for stp in sec.get_all_steps() {
427 (numer,denom) = tally_portion_marking_check(&stp.get_text(),numer,denom,v);
428 for sub in stp.get_all_sub_steps() {
429 match sub {
430 SubStep::Objective(s) => (numer,denom) = tally_portion_marking_check(&s,numer,denom,v),
431 SubStep::OutOfScope(s) => (numer,denom) = tally_portion_marking_check(&s,numer,denom,v),
432 SubStep::ActionSequence(vec) => for a in vec {
433 (numer,denom) = tally_portion_marking_check(a.get_perform(),numer,denom,v);
434 (numer,denom) = tally_portion_marking_check(a.get_expect(),numer,denom,v);
435 },
436 SubStep::Command(_) => (),
437 SubStep::Image(_,s) => (numer,denom) = tally_portion_marking_check(&s,numer,denom,v),
438 SubStep::Warning(s) => (numer,denom) = tally_portion_marking_check(&s,numer,denom,v),
439 SubStep::Verification(r) => (numer,denom) = tally_portion_marking_check(r.get_text(),numer,denom,v),
440 SubStep::Resource(r) => (numer,denom) = tally_portion_marking_check(r.get_name(),numer,denom,v),
441 SubStep::Context(s) => (numer,denom) = tally_portion_marking_check(&s,numer,denom,v),
442 SubStep::Table(t) => (numer,denom) = tally_portion_marking_check(t.get_caption(),numer,denom,v),
443 };
444 }
445 }
446 }
447 println!("📗 Properly Portion-Marked: {:4}",numer);
448 println!("📕 Total lines checked: {:4}",denom);
449 println!("📚 Success percentage: {:4.0}%",(f32::from(numer)/f32::from(denom)*100.0));
450 }
451
452 fn get_classification_header(v:&Vec<String>) -> String {
459 let mut classy:String; let mut classification:String = String::from("UNKNOWN, OR NOT FOUND ANYWHERE..."); let mut success:bool;
462
463 (classy,success) = get_header_from_css_file("assets/stanhope.css");
465 if success { classification = classy; }
467
468 for template in v {
470 (classy,success) = get_header_from_css_file(&("assets/".to_owned()+template));
471 if success { classification = classy; }
472 }
473 return classification;
474 }
476
477
478 fn get_header_from_css_file(f:&str) -> (String,bool) {
479 use std::fs::File;
480 use std::io::{BufRead, BufReader};
481
482 let mut header:String = String::from("UNKNOWN, OR NOT FOUND ANYWHERE...");
483 let mut success:bool = false;
484
485 match Path::new(f).exists() {
488 true => {
489 let file = File::open(f).unwrap();
491 let reader = BufReader::new(file);
492 let mut flag:bool = false;
493
494 for line in reader.lines() {
495 let line = line.unwrap(); match flag {
498 true => {
499 if line.contains("content:") {
500 if line.contains("'") {
502 header = line.split("'").nth(1).expect("?").to_string();
503 success = true;
504 } else if line.contains('\"') {
505 header = line.split('\"').nth(1).expect("?").to_string();
506 success = true;
507 }
508 }
509 flag = false;
510 },
511 false => {
512 if line.contains(".classification p::before") {
513 flag = true;
514 if line.contains("content:") {
515 if line.contains("'") {
517 header = line.split("'").nth(1).expect("?").to_string();
518 success = true;
519 } else if line.contains('\"') {
520 header = line.split('\"').nth(1).expect("?").to_string();
521 success = true;
522 }
523 flag = false;
524 }
525 }
526 },
527 }
528 }
529
530 if !success {
531 }
533 },
534 false => (),};
536 return (header,success)
538 }
539
540 fn tally_portion_marking_check(s:&str,mut n:u16,mut d:u16,v:&bool) -> (u16,u16) {
541 d = d + 1;
542 if s.len() == 0 || probably_portion_marked(s) {
543 n = n + 1;
544 if *v {
545 println!("✅ {}",s.trim());
546 }
547 } else {
548 if *v {
549 println!("❌ {}",s.trim());
550 }
551 }
552 return (n,d);
553 }
554
555 fn probably_portion_marked(s:&str) -> bool {
556 s.trim().starts_with('(') && s.contains(')')
557 }
558
559 }
561
562fn print_title_block_to_stdout(s:&str) {
569 let to_print = s.trim();
570 print!("╭─"); print!("{:─<1$}", "", to_print.len()); print!("─╮\n");
571 print!("│ "); print!("{}",&to_print); print!(" │\n");
572 print!("╰─"); print!("{:─<1$}", "", to_print.len());print!("─╯\n");
573}
574
575fn main() {
587
588 let args = StanhopeArgs::parse();
589
590 if !(&args.listgen=="") {
593
594 let Some((_, last_part)) = &args.listgen.rsplit_once('.') else { todo!() };
595 let needed_processes_list = match *last_part {
596 "csv" => {
597 read_csv(&args.listgen,args.verbose.clone())
599
600 },
601 "xlsx" => {
602 read_xlsx(&args.listgen,args.verbose.clone())
604 },
605 _ => {
606 vec!(Process::new())
607 },
608 };
609
610 if args.verbose { println!("Stanhope found {} EBML files to create in the spreadsheet.",needed_processes_list.len()); }
611
612 for new_proc_to_create in needed_processes_list {
614 if args.verbose { new_proc_to_create.display_process_to_stdout() };
615 write_ebml(&new_proc_to_create,args.verbose.clone());
616 }
617
618 }
619
620 if !(args.scriptify_process.len()==0) {
623 let matching_processes = globify_document_number(&args.scriptify_process[0]);
625 if args.verbose { println!("{:?}",&matching_processes) };
626
627 if matching_processes.len() > 0 {
628
629 for process in matching_processes {
630
631
632 let file_to_read = "./".to_owned() + &process + "/" + &process + ".ebml";
633
634 if args.verbose {
635 println!("");
636 println!("=== Stanhope Scriptification =========================================================");
637 println!("===");
638 println!("=== >> Process: {}",&process);
639 println!("=== >> Script Format: {}",&args.scriptify_process[1]);
640 println!("=== >> Pause after each? {}",&args.scriptify_process[2]);
641 println!("===");
642 println!("======================================================================================");
643 println!("");
644 }
645
646 if args.verbose { print!("[A] Attempting to read EBML -> {} ...",&file_to_read); }
647 let new_proc = read_ebml(&file_to_read);
648 if args.verbose { print!("success!\n"); }
649
650 let all_commands = new_proc.get_all_command_lines();
651 if args.verbose { print!("[B] Stanhope found {} lines of type \"Command\" in the file.\n",all_commands.len()); }
652
653 if args.verbose { print!("[C] Processing script format \"{}\"\n",&args.scriptify_process[1]); }
654
655
656 let wait:bool = match args.scriptify_process[2].to_uppercase().as_str() {
657 "F" | "FALSE" | "N" | "NO" => false,
658 _ => true,
659 };
660 write_script::script_file_from_process(new_proc,write_script::learn(&args.scriptify_process[1]),wait)
661
662 } }; } if !(&args.process_ebml=="") {
669 let matching_processes = globify_document_number(&args.process_ebml);
671 if args.verbose { println!("{:?}",&matching_processes) };
672
673 if matching_processes.len() > 0 {
674
675 for process in matching_processes {
676
677 let file_to_read = "./".to_owned() + &process + "/" + &process + ".ebml";
678 if args.verbose { println!("Attempting to process this file: {}",&file_to_read) };
679
680 let new_proc = read_ebml(&file_to_read);
681 if args.verbose { new_proc.display_process_to_stdout() };
682
683 if args.verbose { println!("Attempting to delete old HTML file: {:?}",fs::remove_file(&file_to_read.replace(".ebml",".html"))); } else { let _ = fs::remove_file(&file_to_read.replace(".ebml",".html")); }
685
686 generate_complete_html(&String::from(&file_to_read.replace(".ebml",".html")),&new_proc);
687
688 let win_chrome_path = "& 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' --headless --no-pdf-header-footer --print-to-pdf=\"";
690 let win_process_library = "$PWD\\";
691 let win_chrome_string_to_throw = &(win_chrome_path.to_string() + win_process_library + &file_to_read.replace(".ebml",".pdf") + "\" \"" + win_process_library + &file_to_read.clone().replace(".ebml",".html\""));
692 let posix_chrome = "chrome --headless --print-to-pdf=\"".to_string() + &file_to_read.clone().replace(".ebml",".pdf") + "\" \"" + &file_to_read.clone().replace(".ebml",".html") + "\" --no-pdf-header-footer";
694 let posix_chromium = "chromium --headless --print-to-pdf=\"".to_string() + &file_to_read.clone().replace(".ebml",".pdf") + "\" \"" + &file_to_read.clone().replace(".ebml",".html") + "\" --no-pdf-header-footer";
696
697 let _output = if cfg!(target_os = "windows") {
698
699 let mut fallbacks: Vec<Box<dyn Fn() -> Result<i32>>> = Vec::new();
700 fallbacks.push(Box::new(move || {
701
702 if args.verbose { println!("Here's my command string to chrome:\n\n{}\n\n",win_chrome_string_to_throw); }
703 Command::new("powershell.exe")
704 .args(["-Command", win_chrome_string_to_throw])
705 .output()
706 .expect("failed to execute process");
707
708 Err(Error::new(ErrorKind::Other, "Chrome call to OS attempted."))
709 }));
710
711 } else {
712
713 let mut fallbacks: Vec<Box<dyn Fn() -> Result<i32>>> = Vec::new();
715 fallbacks.push(Box::new(move || {
716
717 Command::new("sh")
718 .arg("-c")
719 .arg(&(posix_chrome))
720 .output()
721 .expect("failed to execute process");
722
723 Err(Error::new(ErrorKind::Other, "Chrome call to OS attempted."))
724 }));
725 fallbacks.push(Box::new(move || {
726
727 Command::new("sh")
728 .arg("-c")
729 .arg(&(posix_chromium))
730 .output()
731 .expect("failed to execute process");
732
733 Err(Error::new(ErrorKind::Other, "Chromium call to OS attempted."))
734 }));
735 let _result = attempt_fallbacks(fallbacks);
736
737 };
738
739 archive_single_process(new_proc,&args.verbose);
740
741 } } } if !(&args.archive_process=="") {
748 let matching_processes = globify_document_number(&args.archive_process);
750 if args.verbose { println!("{:?}",&matching_processes) };
751
752 if matching_processes.len() > 0 {
753
754 for process in matching_processes {
755
756 let file_to_read = "./".to_owned() + &process + "/" + &process + ".ebml";
757
758 let new_proc = read_ebml(&file_to_read);
759 archive_single_process(new_proc,&args.verbose);
760 }
761 }
762 }
763
764 if !(&args.cleanup_previous=="") {
767 let matching_processes = globify_document_number(&args.cleanup_previous);
769 if args.verbose { println!("{:?}",&matching_processes) };
770
771 if matching_processes.len() > 0 {
772
773 for process in matching_processes {
774
775 let prevs = "./".to_owned() + &process + "/previous";
776
777 let delete_these = list_directories_to_cleanup(prevs);
778
779 for dir in delete_these {
780 println!("Attempting to delete {} ... ",&dir);
781 let delete_this = "./".to_owned() + &process + "/previous/" + &dir;
782 let _ = fs::remove_dir_all(delete_this);
783 }
784 }
785 }
786 }
787
788 if !(&args.inspect_process=="") {
791 let matching_processes = globify_document_number(&args.inspect_process);
793 if args.verbose { println!("{:?}",&matching_processes) };
794
795 if matching_processes.len() > 0 {
796
797 for process in matching_processes {
798
799 let file_to_read = "./".to_owned() + &process + "/" + &process + ".ebml";
800
801 let new_proc = read_ebml(&file_to_read);
802 new_proc.display_process_to_stdout();
803 }
804 }
805 }
806
807 if args.webmenu {
810 generate_complete_webmenu(&args.verbose);
811 }
812
813 if args.graphics_audit {
816 print_graphics_audit_to_stdout(&args.verbose);
817 }
818
819 if args.filename_audit {
822 print_filename_audit_to_stdout(&args.verbose);
823 }
824
825 if args.marking_audit {
828 print_marking_audit_to_stdout(&args.verbose);
829 }
830
831 if args.ebml_help {
834 println!("{}",format!("
835
836Note: Process files passed into --process-ebml are specifically-formatted EBML files (Easy Button Markup Language).
837
838\x1b[36m
839=================================================
840== Easy Button Markup Language Cheat Sheet ==
841== ==
842== Everything below this block is valid EBML ==
843=================================================
844\x1b[0m
845
846// <COMMENT>
847Template | <CSS FILENAME FOUND IN ASSETS FOLDER>
848
849Title | <PROCESS TITLE>
850Number | <PROCESS NUMBER>
851Author | <PROCESS AUTHOR>
852Reviewer | <PROCESS REVIEWER>
853Process Type | <CATEGORY>, e.g. Test Procedure
854
855Subject | <THING TO WHICH THE PROCESS APPLIES>
856Subject Image | <FILENAME OF IMAGE OF SUBJECT>
857Product | <THING PRODUCED BY THIS PROCESS> - optional
858Product Image | <FILENAME OF IMAGE OF PRODUCT> - optional
859
860Revision | <LATEST REV NUM> | <DESCRIPTION OF CHANGE>
861Revision | <INTERMEDIATE REV NUM> | <DESCRIPTION OF CHANGE>
862Revision | <FIRST REV NUM> | <INITIAL DESCTIPTION>
863
864Section | <TITLE OF SECTION>
865 Step | <TITLE OF STEP>
866
867 // These all must occur within a STEP
868
869 Context | <PLAIN TEXT STATEMENTS FOR CONTEXT>
870 Command | <VERBATIM COMPUTER CODE>
871 Warning | <BIG BOLD TEXT TO CAPTURE ATTENTION>
872 Image | <FILENAME> | <CAPTION TEXT>
873 Resource | <THING YOU NEED TO COMPLETE THIS STEP> | <CALIBRATED?>
874 Objective | <ACHIEVED PURPOSE OF THIS PROCESS>
875 Out of Scope | <NOTE ABOUT WHAT NOT TO DO HERE>
876
877 // Verification methods can be single letter: A, I, D, T, S
878 // They can also be full words: Analysis, Inspection, Demonstration, Test, Sampling
879 Verification | <REQUIREMENT ID> | <FULL TEXT OF REQUIREMENT> | <VERIFICATION METHOD>
880
881 // Action lines can be grouped together to form consecutive table rows
882 // To optionally include Two-Party Verification, <TPV> can be \"TPV\"
883 // To NOT make an action Two-Party Verified, stop at the <EXPECTED RESULT>
884 Action | <THING TO DO> | <EXPECTED RESULT> | <TPV?> - optional
885 Action | <THING TO DO> | <EXPECTED RESULT> | <TPV?> - optional
886
887// You can reference a different process's section and stanhope will fetch it for you
888Section Reference | <OTHER PROCESS> | <TITLE OF SECTION>
889
890
891// Alternate Aliases for EBML lines are below
892// Everything here continues to be valid EBML
893// Note: the EBML line designators (left of the first pipe) are NOT case sensitive
894// 'section' is the same as 'SECTION'
895// 'rev' is the same as 'REV'
896
897REV | C | 'Revision' has a new alias!
898rev | B | EBML line indicators are NOT case sensitive!
899ReV | A | I mean, you *could* do that...
900Rev | - | This is revision 'dash'
901
902SEC | Section Alias 'SEC' (or 'sec' etc.) works!
903 STP | Step Alias 'STP' (or 'stp' etc.) works!
904
905 // 'Context' has several new aliases
906 Comment | Context alias
907 TXT | Context alias
908 CMT | Context alias, perhaps short for 'comment'
909
910 // 'Command' has a new alias
911 CMD | Command alias
912 > | Command alias
913 % | Command alias
914 $ | Command alias
915 # | Command alias
916
917 // 'Image' has a new alias
918 IMG | image.ext | This caption appears under the image
919 PICTURE | image.ext | This caption appears under the image
920 PIC | image.ext | This caption appears under the image
921 Figure | image.ext | This caption appears under the image
922 FIG | image.ext | This caption appears under the image
923
924 // 'Action' has a new alias
925 // The Two-Party Verification flag has some aliases as well
926 DO | Do this action | Expect this result
927 DO | Do this action | Expect this result | TPV
928 DO | Do this action | Expect this result | T
929 DO | Do this action | Expect this result | TRUE
930 DO | Do this action | Expect this result | Y
931 DO | Do this action | Expect this result | YES
932 DO | Do this action | Expect this result | Two Party Verification
933 DO | Do this action | Expect this result | Two-Party Verification
934 // That makes an eight-row Action table, with TPVs for the last seven actions
935
936 // 'Warning' has new aliases
937 WARN | Warning text
938 WRN | Warning text
939 WAR | Warning text
940 Alert | Warning text
941 ! | Warning text
942
943 // 'Verification' has new aliases
944 VER | ReqID | Verification Text | Method
945 REQUIREMENT | ReqID | Verification Text | Method
946 REQ | ReqID | Verification Text | Method
947 // The methods of verification have a few aliases as well
948 REQ | ReqID | Verification Text | Demonstration
949 REQ | ReqID | Verification Text | Demo
950 REQ | ReqID | Verification Text | D
951 REQ | ReqID | Verification Text | Inspection
952 REQ | ReqID | Verification Text | I
953 REQ | ReqID | Verification Text | Analysis
954 REQ | ReqID | Verification Text | A
955 REQ | ReqID | Verification Text | Sampling
956 REQ | ReqID | Verification Text | Sample
957 REQ | ReqID | Verification Text | S
958 REQ | ReqID | Verification Text | Test
959 REQ | ReqID | Verification Text | T
960
961 // 'Resource' has a new alias
962 // There are several ways to indicate if a resource needs calibration, too!
963 RES | Name of resource
964 RES | Name of calibrated resource | C
965 RES | Name of calibrated resource | CAL
966 RES | Name of calibrated resource | CALIB
967 RES | Name of calibrated resource | CALIBRATE
968 RES | Name of calibrated resource | CALIBRATED
969 RES | Name of calibrated resource | CALIBRATION
970 RES | Name of calibrated resource | Y
971 RES | Name of calibrated resource | YES
972 RES | Name of calibrated resource | T
973 RES | Name of calibrated resource | TRUE
974
975 // 'Objective' has a new alias
976 OBJ | Objective achieved!
977
978 // 'Out of Scope' has a new alias
979 OOS | Description of what is not in this process scope
980
981// 'Section Reference' has a new alias
982SECREF | Process-Number | Title of Section to Fetch
983
984\x1b[36m
985=================================================
986== Everything above this block is valid EBML ==
987== ==
988== Easy Button Markup Language Cheat Sheet ==
989=================================================
990\x1b[0m
991
992For extensive examples of EBML in action, see https://stanhope.strativusgroup.com/latest/stylesheetviewer.html"));
993 }
994
995}