docs: public static  <T extends Item> AutoCompletionCandidates ofJobNames(final Class<T> type, final String value, ItemGroup container) {
          final AutoCompletionCandidates candidates = new AutoCompletionCandidates();
          class Visitor extends ItemVisitor {
              String prefix;
  
              Visitor(String prefix) {
                  this.prefix = prefix;
              }
  
              @Override
              public void onItem(Item i) {
                  String itemName = contextualNameOf(i);
                  
                  //Check user's setting on whether to do case sensitive comparison, configured in user -> configure
                  //This is the same setting that is used by the global search field, should be consistent throughout
                  //the whole application.
                  boolean caseInsensitive = UserSearchProperty.isCaseInsensitive();
  
                  if ((startsWithImpl(itemName, value, caseInsensitive) || startsWithImpl(value, itemName, caseInsensitive))
                      // 'foobar' is a valid candidate if the current value is 'foo'.
                      // Also, we need to visit 'foo' if the current value is 'foo/bar'
                   && (value.length()> itemName.length() || !itemName.substring(value.length()).contains("/"))
                      // but 'foobar/zot' isn't if the current value is 'foo'
                      // we'll first show 'foobar' and then wait for the user to type '/' to show the rest
                   && i.hasPermission(Item.READ)
                      // and read permission required
                  ) {
                      if (type.isInstance(i) && startsWithImpl(itemName, value, caseInsensitive))
                          candidates.add(itemName);
  
                      // recurse
                      String oldPrefix = prefix;
                      prefix = itemName;
                      super.onItem(i);
                      prefix = oldPrefix;
                  }
              }
  
              private String contextualNameOf(Item i) {
                  if (prefix.endsWith("/") || prefix.length()==0)
                      return prefix+i.getName();
                  else
                      return prefix+'/'+i.getName();
              }
          }
  
          if (container==null || container==Jenkins.getInstance()) {
              new Visitor("").onItemGroup(Jenkins.getInstance());
          } else {
              new Visitor("").onItemGroup(container);
              if (value.startsWith("/"))
                  new Visitor("/").onItemGroup(Jenkins.getInstance());
  
              for ( String p="../"; value.startsWith(p); p+="../") {
                  container = ((Item)container).getParent();
                  new Visitor(p).onItemGroup(container);
              }
          }
  
          return candidates;
      }