code: private List<List<ResolvedLocation>> generateAllCombos(final List<List<ResolvedLocation>> allCandidates,
              final int index, final int depth) {
          // stopping condition
          if (index == allCandidates.size()) {
              // return a list with an empty list
              List<List<ResolvedLocation>> result = new ArrayList<List<ResolvedLocation>>();
              result.add(new ArrayList<ResolvedLocation>());
              return result;
          }
  
          // initialize return object
          List<List<ResolvedLocation>> result = new ArrayList<List<ResolvedLocation>>();
  
          // recursive call
          List<List<ResolvedLocation>> recursive = generateAllCombos(allCandidates, index+1, depth);
  
          // for each element of the first list of input, up to depth or list size
          for (int j = 0; j < Math.min(allCandidates.get(index).size(), depth); j++) {
              // add the element to all combinations obtained for the rest of the lists
              for (List<ResolvedLocation> recList : recursive) {
                  List<ResolvedLocation> newList = new ArrayList<ResolvedLocation>();
                  // add element of the first list
                  newList.add(allCandidates.get(index).get(j));
                  // copy a combination from recursive
                  for (ResolvedLocation listItem : recList) {
                      newList.add(listItem);
                  }
                  // add new combination to result
                  result.add(newList);
              }
          }
  
          return result;
      }
docs: Recursive helper function for
  {@link #pickBestCandidates}.
  
  Generates all combinations of candidate matches from each
  location, down to the specified depth through the lists.
  
  Adapted from:
  http://www.daniweb.com/software-development/java/threads/177956/generating-all-possible-combinations-from-list-of-sublists#post882553
  
  @param allCandidates list of lists of candidate matches for all location names
  @param index         keeps track of which location we're working on for recursive calls
  @param depth         max depth into list we're searching during this recursion
  @return              all combinations of candidate matches for each location, down to the specified depth