From d9ef4462a53d5ae301f2e86c4299503b155f1118 Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Fri, 09 Oct 2015 11:17:56 +0000
Subject: [PATCH] OPENDJ-2295 Provide a method to get back human readable strings from normalized index keys

---
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UserPasswordExactEqualityMatchingRuleImpl.java             |    5 +
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberEqualityMatchingRuleImpl.java               |    5 +
 opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java                                                  |   11 +++
 opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRuleImpl.java    |    6 ++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java                  |    5 +
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java            |    5 +
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/OctetStringSubstringMatchingRuleImpl.java                  |    5 +
 opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/EqualityIndexer.java                                |    5 +
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java              |    5 +
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java                 |    5 +
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java                           |    6 ++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java |    5 +
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java                 |    5 +
 opendj-server-legacy/src/main/java/org/opends/server/schema/AbstractPasswordEqualityMatchingRuleImpl.java             |    6 ++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java             |    5 +
 opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java                                                  |   14 ++++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteString.java                                                   |    2 
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java                     |    5 +
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java                              |   10 +++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TimeBasedMatchingRulesImpl.java                            |    9 ++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java                     |   10 +++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java                    |    5 +
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UUIDEqualityMatchingRuleImpl.java                          |    5 +
 23 files changed, 139 insertions(+), 5 deletions(-)

diff --git a/opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java b/opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java
index 6e79431..29c8931 100644
--- a/opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java
+++ b/opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java
@@ -731,13 +731,23 @@
      *         representation.
      */
     public static char byteToASCII(final byte b) {
-        if (b >= 32 && b <= 126) {
+        if (isPrintable(b)) {
             return (char) b;
         }
-
         return ' ';
     }
 
+    /**
+     * Returns whether the byte is a printable ASCII character.
+     *
+     * @param b
+     *          The byte for which to determine whether it is printable ASCII
+     * @return true if the byte is a printable ASCII character
+     */
+    public static boolean isPrintable(final byte b) {
+        return 32 <= b && b <= 126;
+    }
+
     /** Prevent instantiation. */
     private StaticUtils() {
         // No implementation required.
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteString.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteString.java
index 03f4084..605cdd9 100755
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteString.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteString.java
@@ -793,7 +793,7 @@
 
     /**
      * Returns a string representation of the contents of this byte sequence
-     * using hexadecimal characters and a percent prefix (#) before each char.
+     * using hexadecimal characters and a percent prefix (%) before each char.
      *
      * @return A string representation of the contents of this byte sequence
      *         using percent + hexadecimal characters.
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
index dbf1dca..f001f92 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
@@ -38,6 +38,7 @@
 import org.forgerock.opendj.ldap.spi.Indexer;
 
 import static org.forgerock.opendj.ldap.Assertion.*;
+import static com.forgerock.opendj.util.StaticUtils.*;
 
 /**
  * This class implements a default equality or approximate matching rule that
@@ -84,11 +85,20 @@
         }
 
         @Override
+        public String keyToHumanReadableString(ByteSequence key) {
+            return AbstractMatchingRuleImpl.this.keyToHumanReadableString(key);
+        }
+
+        @Override
         public String getIndexID() {
             return indexID;
         }
     }
 
+    String keyToHumanReadableString(ByteSequence key) {
+        return key.toByteString().toHexString();
+    }
+
     @Override
     public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue)
             throws DecodeException {
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java
index 39d8769..bfa424d 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java
@@ -251,6 +251,11 @@
             }
         }
 
+        @Override
+        public String keyToHumanReadableString(ByteSequence key) {
+            return AbstractSubstringMatchingRuleImpl.this.keyToHumanReadableString(key);
+        }
+
         /** {@inheritDoc} */
         @Override
         public String getIndexID() {
@@ -270,6 +275,11 @@
         this.equalityIndexId = equalityIndexId;
     }
 
+    @Override
+    String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
+
     /** {@inheritDoc} */
     @Override
     public final Assertion getAssertion(final Schema schema, final ByteSequence assertionValue)
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java
index d3e48c7..c183846 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java
@@ -46,4 +46,9 @@
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
         return SchemaUtils.normalizeStringAttributeValue(value, TRIM, NO_CASE_FOLD);
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java
index eec5651..edce186 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java
@@ -48,4 +48,9 @@
             throws DecodeException {
         return SchemaUtils.normalizeIA5StringAttributeValue(value, TRIM, NO_CASE_FOLD);
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java
index 71602f4..271e483 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java
@@ -46,4 +46,9 @@
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
         return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD);
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java
index 03ee6a1..b6a4a1d 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java
@@ -48,4 +48,9 @@
             throws DecodeException {
         return SchemaUtils.normalizeIA5StringAttributeValue(value, TRIM, CASE_FOLD);
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java
index 3f1ac61..0473903 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java
@@ -91,4 +91,9 @@
         // Grab the substring between the start pos and the current pos
         return ByteString.valueOf(string);
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
index 861cf0e..b8fad5b 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
@@ -54,4 +54,9 @@
             throw DecodeException.error(e.getMessageObject());
         }
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java
index 7fc85cd..4425675 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java
@@ -944,4 +944,9 @@
             return false;
         }
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java
index 33d1c3d..dcc75fc 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java
@@ -45,4 +45,9 @@
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
         return SchemaUtils.normalizeNumericStringAttributeValue(value);
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java
index f54195d..f6a7e89 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java
@@ -78,4 +78,9 @@
         final String oid = readOID(reader, schema.getOption(ALLOW_MALFORMED_NAMES_AND_OPTIONS));
         return ByteString.valueOf(resolveNames(schema, oid));
     }
+
+    @Override
+    String keyToHumanReadableString(ByteSequence key) {
+        return key.toByteString().toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/OctetStringSubstringMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/OctetStringSubstringMatchingRuleImpl.java
index 5778d06..12d9fee 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/OctetStringSubstringMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/OctetStringSubstringMatchingRuleImpl.java
@@ -45,4 +45,9 @@
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
         return value.toByteString();
     }
+
+    @Override
+    String keyToHumanReadableString(ByteSequence key) {
+        return key.toByteString().toHexString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberEqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberEqualityMatchingRuleImpl.java
index d3992dd..82e29d8 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberEqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberEqualityMatchingRuleImpl.java
@@ -61,4 +61,9 @@
 
         return ByteString.valueOf(buffer);
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TimeBasedMatchingRulesImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TimeBasedMatchingRulesImpl.java
index e273f0e..c452c2e 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TimeBasedMatchingRulesImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/TimeBasedMatchingRulesImpl.java
@@ -533,9 +533,9 @@
          * Decomposes an attribute value into a set of partial date and time
          * index keys.
          *
-         * @param attValue
+         * @param attributeValue
          *            The normalized attribute value
-         * @param set
+         * @param keys
          *            A set into which the keys will be inserted.
          */
         private void timeKeys(ByteSequence attributeValue, Collection<ByteString> keys) {
@@ -584,6 +584,11 @@
             matchingRule.timeKeys(value, keys);
         }
 
+        @Override
+        public String keyToHumanReadableString(ByteSequence key) {
+            return key.toByteString().toHexString();
+        }
+
         /** {@inheritDoc} */
         @Override
         public String getIndexID() {
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UUIDEqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UUIDEqualityMatchingRuleImpl.java
index 9bb56d7..26f4743 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UUIDEqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UUIDEqualityMatchingRuleImpl.java
@@ -124,4 +124,9 @@
 
         return ByteString.valueOf(builder);
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UserPasswordExactEqualityMatchingRuleImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UserPasswordExactEqualityMatchingRuleImpl.java
index 6753120..d03d9b4 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UserPasswordExactEqualityMatchingRuleImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/UserPasswordExactEqualityMatchingRuleImpl.java
@@ -69,4 +69,9 @@
             return value.toByteString();
         }
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key) {
+        return key.toString();
+    }
 }
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java
index ca401e1..6707d2d 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java
@@ -64,4 +64,15 @@
      */
     void createKeys(Schema schema, ByteSequence value, Collection<ByteString> keys) throws DecodeException;
 
+    /**
+     * Returns a human readable representation of the key.
+     * Does a best effort conversion from an index key to a string that can be printed, as
+     * used by the diagnostic tools, which are the only users of the method.
+     * It is not necessary for the resulting string to exactly match the value it was
+     * generated from.
+     *
+     * @param key the byte string for the index key.
+     * @return a human readable representation of the key
+     */
+    String keyToHumanReadableString(ByteSequence key);
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/EqualityIndexer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/EqualityIndexer.java
index b3033c3..0a06dfc 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/EqualityIndexer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/EqualityIndexer.java
@@ -72,4 +72,9 @@
     keys.add(equalityRule.normalizeAttributeValue(value));
   }
 
+  @Override
+  public String keyToHumanReadableString(ByteSequence key)
+  {
+    return key.toString();
+  }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
index ae57206..fb40abd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
@@ -203,6 +203,12 @@
     }
 
     @Override
+    public String keyToHumanReadableString(ByteSequence key)
+    {
+      return "PRESENCE";
+    }
+
+    @Override
     public String getIndexID()
     {
       return IndexType.PRESENCE.toString();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRuleImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRuleImpl.java
index 296cc91..71aebab 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRuleImpl.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRuleImpl.java
@@ -69,6 +69,12 @@
     {
       return ORDERING_ID;
     }
+
+    @Override
+    public String keyToHumanReadableString(ByteSequence key)
+    {
+      return key.toString();
+    }
   }
 
   /** {@inheritDoc} */
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/schema/AbstractPasswordEqualityMatchingRuleImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/schema/AbstractPasswordEqualityMatchingRuleImpl.java
index 32e87ce..3357319 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/schema/AbstractPasswordEqualityMatchingRuleImpl.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/schema/AbstractPasswordEqualityMatchingRuleImpl.java
@@ -61,6 +61,12 @@
     }
 
     @Override
+    public String keyToHumanReadableString(ByteSequence key)
+    {
+      return key.toString();
+    }
+
+    @Override
     public String getIndexID()
     {
       return EQUALITY_ID;

--
Gitblit v1.10.0