2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import java.net.URLDecoder;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.EnumSet;
29 import java.util.Enumeration;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Locale;
36 import jalview.util.Platform;
38 public class ArgParser
40 private static final String NEGATESTRING = "no";
42 private static final String DEFAULTLINKEDID = "";
44 private static enum Opt
46 BOOLEAN, STRING, UNARY, MULTI, LINKED, ORDERED, NODUPLICATEVALUES
52 NOCALCULATION, NOMENUBAR, NOSTATUS, SHOWOVERVIEW, ANNOTATIONS, COLOUR,
53 FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, NOANNOTATION, NOANNOTATION2,
54 NODISPLAY, NOGUI, NONEWS, NOQUESTIONNAIRE, NOSORTBYTREE, NOUSAGESTATS,
55 OPEN, OPEN2, PROPS, QUESTIONNAIRE, SETPROP, SORTBYTREE, TREE, VDOC,
58 HELP("h"), CALCULATION, MENUBAR, STATUS, SHOWOVERVIEW, ANNOTATIONS,
59 COLOUR, FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, ANNOTATION,
60 ANNOTATION2, DISPLAY, GUI, NEWS, NOQUESTIONNAIRE, SORTBYTREE,
61 USAGESTATS, OPEN, OPEN2, PROPS, QUESTIONNAIRE, SETPROP, TREE, VDOC,
62 VSESS, OUTPUT, OUTPUTTYPE, SSANNOTATION, NOTEMPFAC, TEMPFAC,
63 TEMPFAC_LABEL, TEMPFAC_DESC, TEMPFAC_SHADING, TITLE, PAEMATRIX, WRAP,
64 NOSTRUCTURE, STRUCTURE, IMAGE, QUIT, DEBUG("d");
68 HELP.setOptions(Opt.UNARY);
69 CALCULATION.setOptions(true, Opt.BOOLEAN); // default "true" implies only
70 // expecting "--nocalculation"
71 MENUBAR.setOptions(true, Opt.BOOLEAN);
72 STATUS.setOptions(true, Opt.BOOLEAN);
73 SHOWOVERVIEW.setOptions(Opt.UNARY, Opt.LINKED);
74 ANNOTATIONS.setOptions(Opt.STRING, Opt.LINKED);
75 COLOUR.setOptions(Opt.STRING, Opt.LINKED);
76 FEATURES.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
77 GROOVY.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
78 GROUPS.setOptions(Opt.STRING, Opt.LINKED);
79 HEADLESS.setOptions(Opt.UNARY);
80 JABAWS.setOptions(Opt.STRING);
81 ANNOTATION.setOptions(true, Opt.BOOLEAN);
82 ANNOTATION2.setOptions(true, Opt.BOOLEAN);
83 DISPLAY.setOptions(true, Opt.BOOLEAN);
84 GUI.setOptions(true, Opt.BOOLEAN);
85 NEWS.setOptions(true, Opt.BOOLEAN);
86 NOQUESTIONNAIRE.setOptions(Opt.UNARY); // unary as --questionnaire=val
87 // expects a string value
88 SORTBYTREE.setOptions(true, Opt.BOOLEAN);
89 USAGESTATS.setOptions(true, Opt.BOOLEAN);
90 OPEN.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
91 OPEN2.setOptions(Opt.STRING, Opt.LINKED);
92 PROPS.setOptions(Opt.STRING);
93 QUESTIONNAIRE.setOptions(Opt.STRING);
94 SETPROP.setOptions(Opt.STRING);
95 TREE.setOptions(Opt.STRING);
97 VDOC.setOptions(Opt.UNARY);
98 VSESS.setOptions(Opt.UNARY);
100 OUTPUT.setOptions(Opt.STRING, Opt.LINKED);
101 OUTPUTTYPE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
103 SSANNOTATION.setOptions(Opt.BOOLEAN, Opt.LINKED);
104 NOTEMPFAC.setOptions(Opt.UNARY, Opt.LINKED);
105 TEMPFAC.setOptions(Opt.STRING, Opt.LINKED);
106 TEMPFAC_LABEL.setOptions(Opt.STRING, Opt.LINKED);
107 TEMPFAC_DESC.setOptions(Opt.STRING, Opt.LINKED);
108 TEMPFAC_SHADING.setOptions(Opt.BOOLEAN, Opt.LINKED);
109 TITLE.setOptions(Opt.STRING, Opt.LINKED);
110 PAEMATRIX.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
111 NOSTRUCTURE.setOptions(Opt.UNARY, Opt.LINKED);
112 STRUCTURE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
113 WRAP.setOptions(Opt.BOOLEAN, Opt.LINKED);
114 IMAGE.setOptions(Opt.STRING, Opt.LINKED);
115 QUIT.setOptions(Opt.UNARY);
116 DEBUG.setOptions(Opt.BOOLEAN);
119 private final String[] argNames;
121 private Opt[] argOptions;
123 private boolean defaultBoolValue = false;
125 public String toLongString()
127 StringBuilder sb = new StringBuilder();
128 sb.append("Arg: ").append(this.name());
129 for (String name : getNames())
131 sb.append(", '").append(name).append("'");
133 sb.append("\nOptions: ");
134 boolean first = true;
135 for (Opt o : argOptions)
141 sb.append(o.toString());
145 return sb.toString();
153 private Arg(String... names)
155 int length = (names == null || names.length == 0
156 || (names.length == 1 && names[0] == null)) ? 1
158 this.argNames = new String[length];
159 this.argNames[0] = this.getName();
161 System.arraycopy(names, 0, this.argNames, 1, names.length);
164 public String[] getNames()
169 public String getName()
171 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
175 public final String toString()
180 public boolean hasOption(Opt o)
182 if (argOptions == null)
184 for (Opt option : argOptions)
192 protected void setOptions(Opt... options)
194 setOptions(false, options);
197 protected void setOptions(boolean defaultBoolValue, Opt... options)
199 this.defaultBoolValue = defaultBoolValue;
200 argOptions = options;
203 protected boolean getDefaultBoolValue()
205 return defaultBoolValue;
209 public static class ArgValues
211 private static final String ID = "id";
215 private int argCount = 0;
217 private boolean boolValue = false;
219 private boolean negated = false;
221 private int boolIndex = -1;
223 private List<Integer> argsIndexes;
225 private List<ArgValue> argValueList;
227 private Map<String, ArgValue> idMap = new HashMap<>();
229 protected ArgValues(Arg a)
232 this.argValueList = new ArrayList<ArgValue>();
233 this.boolValue = arg.getDefaultBoolValue();
241 protected int getCount()
246 protected void incrementCount()
251 protected void setNegated(boolean b)
256 protected boolean isNegated()
261 protected void setBoolean(boolean b, int i)
267 protected boolean getBoolean()
269 return this.boolValue;
273 public String toString()
275 if (argValueList == null)
277 StringBuilder sb = new StringBuilder();
278 sb.append(arg.toLongString());
279 if (arg.hasOption(Opt.BOOLEAN) || arg.hasOption(Opt.UNARY))
280 sb.append("Boolean: ").append(boolValue).append("; Default: ")
281 .append(arg.getDefaultBoolValue()).append("; Negated: ")
282 .append(negated).append("\n");
283 if (arg.hasOption(Opt.STRING))
285 sb.append("Values:");
286 boolean first = true;
287 for (ArgValue av : argValueList)
289 String v = av.getValue();
293 sb.append(v).append("'");
298 sb.append("Count: ").append(argCount).append("\n");
299 return sb.toString();
302 protected void addValue()
307 protected void addValue(String val, int argIndex)
309 addArgValue(new ArgValue(val, argIndex));
312 protected void addArgValue(ArgValue av)
314 if ((!arg.hasOption(Opt.MULTI) && argValueList.size() > 0)
315 || (arg.hasOption(Opt.NODUPLICATEVALUES)
316 && argValueList.contains(av.getValue())))
318 if (argValueList == null)
320 argValueList = new ArrayList<ArgValue>();
322 SubVals sv = ArgParser.getSubVals(av.getValue());
325 String id = sv.get(ID);
329 argValueList.add(av);
332 protected boolean hasValue(String val)
334 return argValueList.contains(val);
337 protected ArgValue getArgValue()
339 if (arg.hasOption(Opt.MULTI))
340 Console.warn("Requesting single value for multi value argument");
341 return argValueList.size() > 0 ? argValueList.get(0) : null;
344 protected List<ArgValue> getArgValueList()
349 protected boolean hasId(String id)
351 return idMap.containsKey(id);
354 protected ArgValue getId(String id)
356 return idMap.get(id);
361 private List<String> vargs = null;
363 private boolean isApplet;
365 // private AppletParams appletParams;
367 public boolean isApplet()
372 public String nextValue()
374 return vargs.remove(0);
382 public String getValue(String arg)
384 return getValue(arg, false);
387 public String getValue(String arg, boolean utf8decode)
389 int index = vargs.indexOf(arg);
394 ret = vargs.get(index + 1).toString();
397 if (utf8decode && ret != null)
401 dc = URLDecoder.decode(ret, "UTF-8");
403 } catch (Exception e)
405 // TODO: log failure to decode
413 public Object getAppletValue(String key, String def, boolean asString)
416 return (appletParams == null ? null
417 : (value = appletParams.get(key.toLowerCase())) == null ? def
418 : asString ? "" + value : value);
423 private static final Map<String, Arg> argMap;
425 private Map<String, ArgValuesMap> linkedArgs = new HashMap<>();
427 private List<String> linkedOrder = null;
429 private List<Arg> argList;
433 argMap = new HashMap<>();
434 for (Arg a : EnumSet.allOf(Arg.class))
436 ARGNAME: for (String argName : a.getNames())
438 if (argMap.containsKey(argName))
440 Console.warn("Trying to add argument name multiple times: '"
441 + argName + "'"); // RESTORE THIS WHEN MERGED
442 if (argMap.get(argName) != a)
445 "Trying to add argument name multiple times for different Args: '"
446 + argMap.get(argName).getName() + ":" + argName
447 + "' and '" + a.getName() + ":" + argName
452 argMap.put(argName, a);
457 public ArgParser(String[] args)
460 vargs = new ArrayList<>();
461 isApplet = (args.length > 0 && args[0].startsWith("<applet"));
464 // appletParams = AppletParams.getAppletParams(args, vargs);
473 // AppletParams.getAppletParams(Platform.getAppletInfoAsMap(), vargs);
475 for (int i = 0; i < args.length; i++)
477 String arg = args[i].trim();
478 if (arg.charAt(0) == '-')
480 arg = arg.substring(1);
487 Enumeration<String> argE = Collections.enumeration(Arrays.asList(args));
489 while (argE.hasMoreElements())
491 String arg = argE.nextElement();
492 String argName = null;
494 String linkedId = null;
495 if (arg.startsWith("--"))
497 int equalPos = arg.indexOf('=');
500 argName = arg.substring(2, equalPos);
501 val = arg.substring(equalPos + 1);
505 argName = arg.substring(2);
507 int idOpen = argName.indexOf('[');
508 int idClose = argName.indexOf(']');
510 if (idOpen > -1 && idClose == argName.length() - 1)
512 linkedId = argName.substring(idOpen + 1, idClose);
513 argName = argName.substring(0, idOpen);
516 Arg a = argMap.get(argName);
517 // check for boolean prepended by "no"
518 boolean negated = false;
519 if (a == null && argName.startsWith(NEGATESTRING) && argMap
520 .containsKey(argName.substring(NEGATESTRING.length())))
522 argName = argName.substring(NEGATESTRING.length());
523 a = argMap.get(argName);
527 // check for config errors
531 Console.error("Argument '" + arg + "' not recognised. Ignoring.");
534 if (!a.hasOption(Opt.BOOLEAN) && negated)
536 // used "no" with a non-boolean option
537 Console.error("Argument '--" + NEGATESTRING + argName
538 + "' not a boolean option. Ignoring.");
541 if (!a.hasOption(Opt.STRING) && equalPos > -1)
543 // set --argname=value when arg does not accept values
544 Console.error("Argument '--" + argName
545 + "' does not expect a value (given as '" + arg
549 if (!a.hasOption(Opt.LINKED) && linkedId != null)
551 // set --argname[linkedId] when arg does not use linkedIds
552 Console.error("Argument '--" + argName
553 + "' does not expect a linked id (given as '" + arg
558 if (a.hasOption(Opt.STRING) && equalPos == -1)
560 // take next arg as value if required, and '=' was not found
561 if (!argE.hasMoreElements())
563 // no value to take for arg, which wants a value
564 Console.error("Argument '" + a.getName()
565 + "' requires a value, none given. Ignoring.");
568 val = argE.nextElement();
571 // use default linkedId for linked arguments
572 if (a.hasOption(Opt.LINKED) && linkedId == null)
573 linkedId = DEFAULTLINKEDID;
575 if (!linkedArgs.containsKey(linkedId))
576 linkedArgs.put(linkedId, new ArgValuesMap());
578 ArgValuesMap avm = linkedArgs.get(linkedId);
580 if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val))
582 Console.error("Argument '--" + argName
583 + "' cannot contain a duplicate value ('" + val
584 + "'). Ignoring this and subsequent occurrences.");
588 // check for unique id
589 SubVals sv = ArgParser.getSubVals(val);
590 String id = sv.get(ArgValues.ID);
591 if (id != null && avm.hasId(a, id))
593 Console.error("Argument '--" + argName + "' has a duplicate id ('"
594 + id + "'). Ignoring.");
598 ArgValues avs = avm.getOrCreateArgValues(a);
601 avs = new ArgValues(a);
603 // store appropriate value
604 if (a.hasOption(Opt.STRING))
606 avs.addValue(val, argIndex);
608 else if (a.hasOption(Opt.BOOLEAN))
610 avs.setBoolean(!negated, argIndex);
611 avs.setNegated(negated);
613 else if (a.hasOption(Opt.UNARY))
615 avs.setBoolean(true, argIndex);
617 avs.incrementCount();
619 // store in appropriate place
620 if (a.hasOption(Opt.LINKED))
622 // allow a default linked id for single usage
623 if (linkedId == null)
624 linkedId = DEFAULTLINKEDID;
625 // store the order of linkedIds
626 if (linkedOrder == null)
627 linkedOrder = new ArrayList<>();
628 if (!linkedOrder.contains(linkedId))
629 linkedOrder.add(linkedId);
632 // store arg in the list of args used
634 argList = new ArrayList<>();
635 if (!argList.contains(a))
641 public boolean isSet(Arg a)
643 return a.hasOption(Opt.LINKED) ? isSet("", a) : isSet(null, a);
646 public boolean isSet(String linkedId, Arg a)
648 ArgValuesMap avm = linkedArgs.get(linkedId);
649 return avm == null ? false : avm.containsArg(a);
652 public boolean getBool(Arg a)
654 if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY))
656 Console.warn("Getting boolean from non boolean Arg '" + a.getName()
659 return a.hasOption(Opt.LINKED) ? getBool("", a) : getBool(null, a);
662 public boolean getBool(String linkedId, Arg a)
664 ArgValuesMap avm = linkedArgs.get(linkedId);
666 return a.getDefaultBoolValue();
667 ArgValues avs = avm.getArgValues(a);
668 return avs == null ? a.getDefaultBoolValue() : avs.getBoolean();
671 public List<String> linkedIds()
676 public ArgValuesMap linkedArgs(String id)
678 return linkedArgs.get(id);
682 public String toString()
684 StringBuilder sb = new StringBuilder();
685 sb.append("UNLINKED\n");
686 sb.append(argValuesMapToString(linkedArgs.get(null)));
687 if (linkedIds() != null)
689 sb.append("LINKED\n");
690 for (String id : linkedIds())
692 // already listed these as UNLINKED args
696 ArgValuesMap avm = linkedArgs(id);
697 sb.append("ID: '").append(id).append("'\n");
698 sb.append(argValuesMapToString(avm));
701 return sb.toString();
704 private static String argValuesMapToString(ArgValuesMap avm)
708 StringBuilder sb = new StringBuilder();
709 for (Arg a : avm.getArgKeys())
711 ArgValues v = avm.getArgValues(a);
712 sb.append(v.toString());
715 return sb.toString();
718 public static SubVals getSubVals(String item)
720 return new SubVals(item);
724 * A helper class to keep an index of argument position with argument values
726 public static class ArgValue
728 private int argIndex;
730 private String value;
734 protected ArgValue(String value, int argIndex)
737 this.argIndex = argIndex;
740 protected String getValue()
745 protected int getArgIndex()
750 protected void setId(String i)
755 protected String getId()
762 * A helper class to parse a string of the possible forms "content"
763 * "[index]content", "[keyName=keyValue]content" and return the integer index,
764 * the strings keyName and keyValue, and the content after the square brackets
765 * (if present). Values not set `will be -1 or null.
767 public static class SubVals
769 private static int NOTSET = -1;
771 private int index = NOTSET;
773 private Map<String, String> subVals = null;
775 private static char SEPARATOR = ';';
777 private String content = null;
779 public SubVals(String item)
781 this.parseVals(item);
784 public void parseVals(String item)
786 if (item.indexOf('[') == 0 && item.indexOf(']') > 1)
788 int openBracket = item.indexOf('[');
789 int closeBracket = item.indexOf(']');
790 String subvalsString = item.substring(openBracket + 1,
792 this.content = item.substring(closeBracket + 1);
793 boolean setIndex = false;
794 for (String subvalString : subvalsString
795 .split(Character.toString(SEPARATOR)))
797 int equals = subvalString.indexOf('=');
801 subVals = new HashMap<>();
802 subVals.put(subvalString.substring(0, equals),
803 subvalString.substring(equals + 1));
809 this.index = Integer.parseInt(subvalString);
811 } catch (NumberFormatException e)
813 Console.warn("Failed to obtain subvalue or index from '"
814 + item + "'. Setting index=0 and using content='"
828 public boolean notSet()
830 // notSet is true if content present but nonsensical
831 return index == NOTSET && subVals == null;
834 public String get(String key)
836 return subVals == null ? null : subVals.get(key);
839 public boolean has(String key)
841 return subVals == null ? false : subVals.containsKey(key);
844 public int getIndex()
849 public String getContent()
856 * Helper class to allow easy extraction of information about specific
857 * argument values (without having to check for null etc all the time)
859 protected static class ArgValuesMap
861 protected Map<Arg, ArgValues> m;
863 protected ArgValuesMap()
868 protected ArgValuesMap(Map<Arg, ArgValues> map)
873 private Map<Arg, ArgValues> getMap()
878 private void newMap()
880 m = new HashMap<Arg, ArgValues>();
883 private void newArg(Arg a)
888 m.put(a, new ArgValues(a));
891 protected void addArgValue(Arg a, ArgValue av)
893 if (getMap() == null)
894 m = new HashMap<Arg, ArgValues>();
896 if (!m.containsKey(a))
897 m.put(a, new ArgValues(a));
898 ArgValues avs = m.get(a);
902 protected ArgValues getArgValues(Arg a)
904 return m == null ? null : m.get(a);
907 protected ArgValues getOrCreateArgValues(Arg a)
909 ArgValues avs = m.get(a);
912 return getArgValues(a);
915 protected List<ArgValue> getArgValueList(Arg a)
917 ArgValues avs = getArgValues(a);
918 return avs == null ? new ArrayList<>() : avs.getArgValueList();
921 protected ArgValue getArgValue(Arg a)
923 List<ArgValue> vals = getArgValueList(a);
924 return (vals == null || vals.size() == 0) ? null : vals.get(0);
927 protected String getValue(Arg a)
929 ArgValue av = getArgValue(a);
930 return av == null ? null : av.getValue();
933 protected boolean containsArg(Arg a)
935 if (m == null || !m.containsKey(a))
937 return getArgValue(a) != null;
940 protected boolean hasValue(Arg a, String val)
942 if (m == null || !m.containsKey(a))
944 for (ArgValue av : getArgValueList(a))
946 String avVal = av.getValue();
947 if ((val == null && avVal == null)
948 || (val != null && val.equals(avVal)))
956 protected boolean getBoolean(Arg a)
958 ArgValues av = getArgValues(a);
959 return av == null ? false : av.getBoolean();
962 protected Set<Arg> getArgKeys()
967 protected ArgValue getClosestPreviousArgValueOfArg(ArgValue thisAv,
970 ArgValue closestAv = null;
971 int thisArgIndex = thisAv.getArgIndex();
972 ArgValues compareAvs = this.getArgValues(a);
973 int closestPreviousIndex = -1;
974 for (ArgValue av : compareAvs.getArgValueList())
976 int argIndex = av.getArgIndex();
977 if (argIndex < thisArgIndex && argIndex > closestPreviousIndex)
979 closestPreviousIndex = argIndex;
986 protected ArgValue getClosestNextArgValueOfArg(ArgValue thisAv, Arg a)
988 // this looks for the *next* arg that *might* be referring back to
989 // a thisAv. Such an arg would have no subValues (if it does it should
990 // specify an id in the subValues so wouldn't need to be guessed).
991 ArgValue closestAv = null;
992 int thisArgIndex = thisAv.getArgIndex();
993 ArgValues compareAvs = this.getArgValues(a);
994 int closestNextIndex = Integer.MAX_VALUE;
995 for (ArgValue av : compareAvs.getArgValueList())
997 int argIndex = av.getArgIndex();
998 if (argIndex > thisArgIndex && argIndex < closestNextIndex)
1000 closestNextIndex = argIndex;
1007 protected ArgValue[] getArgValuesReferringTo(String key, String value,
1010 // this looks for the *next* arg that *might* be referring back to
1011 // a thisAv. Such an arg would have no subValues (if it does it should
1012 // specify an id in the subValues so wouldn't need to be guessed).
1013 List<ArgValue> avList = new ArrayList<>();
1014 Arg[] args = a == null ? (Arg[]) this.getMap().keySet().toArray()
1017 for (Arg keyArg : args)
1019 for (ArgValue av : this.getArgValueList(keyArg))
1024 return (ArgValue[]) avList.toArray();
1027 protected boolean hasId(Arg a, String id)
1029 ArgValues avs = this.getArgValues(a);
1030 return avs == null ? false : avs.hasId(id);
1033 protected ArgValue getId(Arg a, String id)
1035 ArgValues avs = this.getArgValues(a);
1036 return avs == null ? null : avs.getId(id);
1040 private static final Collection<Arg> bootstrapArgs = new ArrayList(
1041 Arrays.asList(Arg.PROPS, Arg.DEBUG));
1043 public static Map<Arg, String> bootstrapArgs(String[] args)
1045 Map<Arg, String> bootstrapArgMap = new HashMap<>();
1047 return bootstrapArgMap;
1048 Enumeration<String> argE = Collections.enumeration(Arrays.asList(args));
1049 while (argE.hasMoreElements())
1051 String arg = argE.nextElement();
1052 String argName = null;
1054 if (arg.startsWith("--"))
1056 int equalPos = arg.indexOf('=');
1059 argName = arg.substring(2, equalPos);
1060 val = arg.substring(equalPos + 1);
1064 argName = arg.substring(2);
1066 Arg a = argMap.get(argName);
1067 if (a != null && bootstrapArgs.contains(a))
1068 bootstrapArgMap.put(a, val);
1071 return bootstrapArgMap;