code: public List<Container> packList(List<BoxItem> boxes, int limit, BooleanSupplier interrupt) {
  		List<Container> containers = filterByVolumeAndWeight(toBoxes(boxes, true), Arrays.asList(this.containers), limit);
  		if (containers.isEmpty()) {
  			return null;
  		}
  
  		Adapter pack = adapter();
  		pack.initialize(boxes, containers);
  
  		List<Container> containerPackResults = new ArrayList<>();
  
  		// binary search: not as simple as in the single-container use-case; discarding containers would need some kind
  		// of criteria which could be trivially calculated, perhaps on volume.
  		do {
  			PackResult best = null;
  			for (int i = 0; i < containers.size(); i++) {
  
  				if (interrupt.getAsBoolean()) {
  					return null;
  				}
  
  				PackResult result = pack.attempt(i, interrupt);
  				if (result == null) {
  					return null; // timeout
  				}
  
  				if (!result.isEmpty()) {
  					if (best == null || result.packsMoreBoxesThan(best)) {
  						best = result;
  
  						if (!pack.hasMore(best)) { // will not match any better than this
  							break;
  						}
  					}
  				}
  			}
  
  			if (best == null) {
  				// negative result
  				return null;
  			}
  
  			boolean end = !pack.hasMore(best);
  
  			containerPackResults.add(pack.accepted(best));
  
  			if (end) {
  				// positive result
  				return containerPackResults;
  			}
  
  		} while (containerPackResults.size() < limit);
  
  		return null;
  	}
docs: Return a list of containers which holds all the boxes in the argument
  
  @param boxes     list of boxes to fit in a container
  @param limit     maximum number of containers
  @param interrupt When true, the computation is interrupted as soon as possible.
  @return index of container if match, -1 if not