class AbstractBaselineCommand implements ComputeCommand<BaselineTaskArg, BaselineTaskResult> {
    /** {@inheritDoc} */
    @Override public Class<BaselineTask> taskClass() {
        return BaselineTask.class;
    }

    /** {@inheritDoc} */
    @Override public Collection<GridClientNode> nodes(Collection<GridClientNode> nodes, BaselineTaskArg arg) {
        return coordinatorOrNull(nodes);
    }

    /** {@inheritDoc} */
    @Override public void printResult(
        BaselineTaskArg arg,
        BaselineTaskResult res,
        Consumer<String> printer
    ) {<FILL_FUNCTION_BODY>}
}

        printer.accept("Cluster state: " + res.clusterState());
        printer.accept("Current topology version: " + res.getTopologyVersion());
        BaselineAutoAdjustSettings autoAdjustSettings = res.getAutoAdjustSettings();

        if (autoAdjustSettings != null) {
            printer.accept("Baseline auto adjustment " + (TRUE.equals(autoAdjustSettings.getEnabled()) ? "enabled" : "disabled")
                + ": softTimeout=" + autoAdjustSettings.getSoftTimeout()
            );
        }

        if (autoAdjustSettings.enabled) {
            if (res.isBaselineAdjustInProgress())
                printer.accept("Baseline auto-adjust is in progress");
            else if (res.getRemainingTimeToBaselineAdjust() < 0)
                printer.accept("Baseline auto-adjust are not scheduled");
            else
                printer.accept("Baseline auto-adjust will happen in '" + res.getRemainingTimeToBaselineAdjust() + "' ms");
        }

        printer.accept("");

        Map<String, BaselineNode> baseline = res.getBaseline();

        Map<String, BaselineNode> srvs = res.getServers();

        // if task runs on a node with BaselineNode of old version (V1) we'll get order=null for all nodes.
        Function<BaselineNode, String> extractFormattedAddrs = node -> {
            Stream<String> sortedByIpHosts =
                Optional.ofNullable(node)
                    .map(addrs -> node.getAddrs())
                    .orElse(Collections.emptyList())
                    .stream()
                    .sorted(Comparator
                        .comparing(resolvedAddr -> new VisorTaskUtils.SortableAddress(resolvedAddr.address())))
                    .map(resolvedAddr -> {
                        if (!resolvedAddr.hostname().equals(resolvedAddr.address()))
                            return resolvedAddr.hostname() + "/" + resolvedAddr.address();
                        else
                            return resolvedAddr.address();
                    });
            if (arg.verbose()) {
                String hosts = String.join(",", sortedByIpHosts.collect(Collectors.toList()));

                if (!hosts.isEmpty())
                    return ", Addresses=" + hosts;
                else
                    return "";
            }
            else
                return sortedByIpHosts.findFirst().map(ip -> ", Address=" + ip).orElse("");
        };

        String crdStr = srvs.values().stream()
            // check for not null
            .filter(node -> node.getOrder() != null)
            .min(Comparator.comparing(BaselineNode::getOrder))
            // format
            .map(crd -> " (Coordinator: ConsistentId=" + crd.getConsistentId() + extractFormattedAddrs.apply(crd) +
                ", Order=" + crd.getOrder() + ")")
            .orElse("");

        printer.accept("Current topology version: " + res.getTopologyVersion() + crdStr);
        printer.accept("");

        if (F.isEmpty(baseline))
            printer.accept("Baseline nodes not found.");
        else {
            printer.accept("Baseline nodes:");

            for (BaselineNode node : baseline.values()) {
                BaselineNode srvNode = srvs.get(node.getConsistentId());

                String state = ", State=" + (srvNode != null ? "ONLINE" : "OFFLINE");

                String order = srvNode != null ? ", Order=" + srvNode.getOrder() : "";

                printer.accept(DOUBLE_INDENT + "ConsistentId=" + node.getConsistentId() +
                    extractFormattedAddrs.apply(srvNode) + state + order);
            }

            printer.accept(U.DELIM);
            printer.accept("Number of baseline nodes: " + baseline.size());

            printer.accept("");

            List<BaselineNode> others = new ArrayList<>();

            for (BaselineNode node : srvs.values()) {
                if (!baseline.containsKey(node.getConsistentId()))
                    others.add(node);
            }

            if (F.isEmpty(others))
                printer.accept("Other nodes not found.");
            else {
                printer.accept("Other nodes:");

                for (BaselineNode node : others)
                    printer.accept(DOUBLE_INDENT + "ConsistentId=" + node.getConsistentId() + ", Order=" + node.getOrder());

                printer.accept("Number of other nodes: " + others.size());
            }
        }
    
<no_super_class>