@Override
  @NotNull
  public Collection<Group> group(@NotNull AbstractTreeNode<?> parent, @NotNull Collection<TreeElement> children) {
    List<Key> keys = new ArrayList<>();

    String parentPrefix;
    int parentPrefixLength;
    if (parent.getValue() instanceof PropertiesPrefixGroup) {
      parentPrefix = ((PropertiesPrefixGroup)parent.getValue()).getPrefix();
      parentPrefixLength = StringUtil.split(parentPrefix, mySeparator).size();
    }
    else {
      parentPrefix = "";
      parentPrefixLength = 0;
    }
    for (TreeElement element : children) {
      final String text = getPropertyUnescapedKey(element);
      if (text == null) continue;
      boolean expected = text.startsWith(parentPrefix) || text.startsWith(mySeparator);
      if (!expected) LOG.error("unexpected text: " + text + "; parentPrefix=" + parentPrefix + "; mySeparator=" + mySeparator);
      List<String> words = StringUtil.split(text, mySeparator);
      keys.add(new Key(words, element));
    }

    if (keys.isEmpty()) return ContainerUtil.emptyList();

    keys.sort((k1, k2) -> {
      List<String> o1 = k1.words;
      List<String> o2 = k2.words;
      for (int i = 0; i < Math.max(o1.size(), o2.size()); i++) {
        if (i == o1.size()) return 1;
        if (i == o2.size()) return -1;
        String s1 = o1.get(i);
        String s2 = o2.get(i);
        int res = s1.compareTo(s2);
        if (res != 0) return res;
      }
      return 0;
    });
    List<Group> groups = new ArrayList<>();
    int groupStart = 0;
    for (int i = 0; i <= keys.size(); i++) {
      if (!isEndOfGroup(i, keys, parentPrefixLength)) {
        continue;
      }
      // find longest group prefix
      List<String> firstKey = groupStart == keys.size() ? Collections.emptyList() : keys.get(groupStart).words;
      List<TreeElement> groupChildren = new SmartList<>();
      groupChildren.add(keys.get(groupStart).node);
      int prefixLen = firstKey.size();
      for (int j = groupStart+1; j < i; j++) {
        List<String> prevKey = keys.get(j-1).words;
        List<String> nextKey = keys.get(j).words;
        for (int k = parentPrefixLength; k < prefixLen; k++) {
          String word = k < nextKey.size() ? nextKey.get(k) : null;
          String wordInPrevKey = k < prevKey.size() ? prevKey.get(k) : null;
          if (!Comparing.strEqual(word, wordInPrevKey)) {
            prefixLen = k;
            break;
          }
        }
        groupChildren.add(keys.get(j).node);
      }
      String[] strings = firstKey.subList(0,prefixLen).toArray(new String[prefixLen]);
      String prefix = StringUtil.join(strings, mySeparator);
      String presentableName = prefix.substring(parentPrefix.length());
      presentableName = StringUtil.trimStart(presentableName, mySeparator);
      if (i - groupStart > 1) {
        groups.add(new PropertiesPrefixGroup(groupChildren, prefix, presentableName, mySeparator));
      }
      else if (groupStart != keys.size()) {
        TreeElement node = keys.get(groupStart).node;
        ((PropertyStructureViewElement)node).setPresentableName(presentableName);
      }
      groupStart = i;
    }
    return groups;
  }
@Override
  @NotNull
  public Collection<Group> group(@NotNull AbstractTreeNode<?> parent, @NotNull Collection<TreeElement> children)