public PathSpecSet copyAndRemovePrefix(PathSpec prefix)
  {
    if (isAllInclusive() || isEmpty())
    {
      // allInclusive or empty projections stay the same
      return this;
    }

    // if we contain the exact prefix or any sub prefix, it should be an all inclusive set
    PathSpec partialPrefix = prefix;
    do
    {
      if (getPathSpecs().contains(partialPrefix))
      {
        return allInclusive();
      }
      partialPrefix = partialPrefix.getParent();
    } while (!partialPrefix.isEmptyPath());

    List<String> prefixPathComponents = prefix.getPathComponents();
    int prefixPathLength = prefixPathComponents.size();

    return PathSpecSet.of(
        getPathSpecs().stream()
            .filter(pathSpec -> {
              List<String> pathComponents = pathSpec.getPathComponents();
              return pathComponents.size() > prefixPathLength && prefixPathComponents.equals(pathComponents.subList(0, prefixPathLength));
            })
            .map(pathSpec -> new PathSpec(pathSpec.getPathComponents().subList(prefixPathLength, pathSpec.getPathComponents().size()).toArray(new String[0])))
            .collect(Collectors.toSet()));
  }
@Test(dataProvider = "copyAndRemovePrefixProvider")
  public void testCopyAndRemovePrefix(PathSpecSet input, PathSpec prefix, PathSpecSet expected) {
    Assert.assertEquals(input.copyAndRemovePrefix(prefix), expected);
  }