From a5bf51c829a0f7d63c923fd48260a0fd167bd4f9 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Wed, 24 Jul 2013 12:12:05 +0000
Subject: [PATCH] Extracted method getCannotBindErrorMessage() and checkCanUsePort(). Used interfaces instead of concrete classes.
---
opends/src/server/org/opends/server/tools/InstallDS.java | 143 ++++++-----------------
opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java | 173 ++++++++--------------------
2 files changed, 90 insertions(+), 226 deletions(-)
diff --git a/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java b/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
index 33e7804..e2b6fd2 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -27,6 +27,7 @@
*/
package org.opends.quicksetup.installer;
+import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
@@ -35,78 +36,35 @@
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
-import java.awt.event.WindowEvent;
-import javax.naming.NameAlreadyBoundException;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.NamingSecurityException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
+import javax.naming.*;
+import javax.naming.directory.*;
import javax.naming.ldap.InitialLdapContext;
+import javax.naming.ldap.Rdn;
+import javax.swing.JPanel;
-import org.opends.admin.ads.ADSContext;
-import org.opends.admin.ads.ADSContextException;
-import org.opends.admin.ads.ReplicaDescriptor;
-import org.opends.admin.ads.ServerDescriptor;
-import org.opends.admin.ads.SuffixDescriptor;
-import org.opends.admin.ads.TopologyCache;
-import org.opends.admin.ads.TopologyCacheException;
-import org.opends.admin.ads.TopologyCacheFilter;
+import org.opends.admin.ads.*;
import org.opends.admin.ads.util.ApplicationTrustManager;
import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.admin.ads.util.PreferredConnection;
-import org.opends.quicksetup.ApplicationException;
-import org.opends.quicksetup.ButtonName;
-import org.opends.quicksetup.Constants;
-import org.opends.quicksetup.Installation;
-import org.opends.quicksetup.JavaArguments;
-import org.opends.quicksetup.LicenseFile;
-import org.opends.quicksetup.ProgressStep;
-import org.opends.quicksetup.QuickSetupLog;
-import org.opends.quicksetup.ReturnCode;
-import org.opends.quicksetup.SecurityOptions;
-import org.opends.quicksetup.Step;
-import org.opends.quicksetup.UserData;
-import org.opends.quicksetup.UserDataCertificateException;
-import org.opends.quicksetup.UserDataConfirmationException;
-import org.opends.quicksetup.UserDataException;
-import org.opends.quicksetup.WizardStep;
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
+import org.opends.quicksetup.*;
+import org.opends.quicksetup.event.ButtonActionListener;
+import org.opends.quicksetup.event.ButtonEvent;
+import org.opends.quicksetup.installer.ui.*;
import org.opends.quicksetup.ui.*;
import org.opends.quicksetup.util.FileManager;
import org.opends.quicksetup.util.IncompatibleVersionException;
import org.opends.quicksetup.util.Utils;
-
-import static org.opends.quicksetup.util.Utils.*;
-import static org.opends.quicksetup.Step.*;
import org.opends.server.util.CertificateManager;
-import org.opends.quicksetup.event.ButtonActionListener;
-import org.opends.quicksetup.event.ButtonEvent;
-import org.opends.quicksetup.installer.ui.DataOptionsPanel;
-import org.opends.quicksetup.installer.ui.DataReplicationPanel;
-import org.opends.quicksetup.installer.ui.GlobalAdministratorPanel;
-import org.opends.quicksetup.installer.ui.InstallReviewPanel;
-import org.opends.quicksetup.installer.ui.InstallWelcomePanel;
-import org.opends.quicksetup.installer.ui.InstallLicensePanel;
-import org.opends.quicksetup.installer.ui.RemoteReplicationPortsPanel;
-import org.opends.quicksetup.installer.ui.RuntimeOptionsPanel;
-import org.opends.quicksetup.installer.ui.ServerSettingsPanel;
-import org.opends.quicksetup.installer.ui.SuffixesToReplicatePanel;
+import org.opends.server.util.DynamicConstants;
import org.opends.server.util.SetupUtils;
import org.opends.server.util.StaticUtils;
-import org.opends.messages.Message;
-import org.opends.messages.MessageBuilder;
+
import static org.opends.messages.QuickSetupMessages.*;
-
-import javax.naming.ldap.Rdn;
-import javax.swing.*;
-import org.opends.server.util.DynamicConstants;
-
+import static org.opends.quicksetup.Step.*;
+import static org.opends.quicksetup.util.Utils.*;
/**
* This is an abstract class that is in charge of actually performing the
@@ -158,12 +116,16 @@
private static final int MAX_NUMBER_ENTRIES = 10000000;
- // If the user decides to import more than this number of entries, the
- // import process of automatically generated data will be verbose.
+ /**
+ * If the user decides to import more than this number of entries, the import
+ * process of automatically generated data will be verbose.
+ */
private static final int THRESOLD_AUTOMATIC_DATA_VERBOSE = 20000;
- // If the user decides to import a number of entries higher than this
- // threshold, the start process will be verbose.
+ /**
+ * If the user decides to import a number of entries higher than this
+ * threshold, the start process will be verbose.
+ */
private static final int NENTRIES_THRESOLD_FOR_VERBOSE_START = 100000;
/** Set of progress steps that have been completed. */
@@ -903,7 +865,7 @@
checkAbort();
- ArrayList<String> argList = new ArrayList<String>();
+ List<String> argList = new ArrayList<String>();
argList.add("-C");
argList.add(getConfigurationClassName());
@@ -1292,21 +1254,16 @@
}
checkAbort();
- ArrayList<String> argList = new ArrayList<String>();
-
+ List<String> argList = new ArrayList<String>();
argList.add("-n");
argList.add(getBackendName());
-
for (File f : ldifFiles)
{
argList.add("-l");
argList.add(f.getAbsolutePath());
}
-
argList.add("-F");
-
argList.add("-Q");
-
argList.add("--noPropertiesFile");
final String[] args = new String[argList.size()];
@@ -1400,7 +1357,7 @@
pointAdder.start();
}
- ArrayList<String> argList = new ArrayList<String>();
+ List<String> argList = new ArrayList<String>();
argList.add("-n");
argList.add(getBackendName());
for (String ldifPath : ldifPaths)
@@ -1530,16 +1487,14 @@
{
setNotifyListeners(false);
}
- final ArrayList<String> argList = new ArrayList<String>();
+ final List<String> argList = new ArrayList<String>();
argList.add("-n");
argList.add(getBackendName());
argList.add("-A");
argList.add(templatePath.getAbsolutePath());
argList.add("-s"); // seed
argList.add("0");
-
argList.add("-F");
-
argList.add("--noPropertiesFile");
final String[] args = new String[argList.size()];
@@ -3071,7 +3026,7 @@
private void updateUserDataForServerSettingsPanel(QuickSetup qs)
throws UserDataException
{
- ArrayList<Message> errorMsgs = new ArrayList<Message>();
+ List<Message> errorMsgs = new ArrayList<Message>();
Message confirmationMsg = null;
if (isWebStart())
@@ -3194,16 +3149,8 @@
qs.displayFieldInvalid(FieldName.SERVER_PORT, true);
} else if (!canUseAsPort(port))
{
- if (isPriviledgedPort(port))
- {
- errorMsgs.add(INFO_CANNOT_BIND_PRIVILEDGED_PORT.get(
- String.valueOf(port)));
- } else
- {
- errorMsgs.add(INFO_CANNOT_BIND_PORT.get(String.valueOf(port)));
- }
+ errorMsgs.add(getCannotBindErrorMessage(port));
qs.displayFieldInvalid(FieldName.SERVER_PORT, true);
-
} else
{
getUserData().setServerPort(port);
@@ -3232,17 +3179,8 @@
qs.displayFieldInvalid(FieldName.ADMIN_CONNECTOR_PORT, true);
} else if (!canUseAsPort(adminConnectorPort))
{
- if (isPriviledgedPort(adminConnectorPort))
- {
- errorMsgs.add(INFO_CANNOT_BIND_PRIVILEDGED_PORT.get(
- String.valueOf(adminConnectorPort)));
- } else
- {
- errorMsgs.add(INFO_CANNOT_BIND_PORT.get(
- String.valueOf(adminConnectorPort)));
- }
+ errorMsgs.add(getCannotBindErrorMessage(adminConnectorPort));
qs.displayFieldInvalid(FieldName.ADMIN_CONNECTOR_PORT, true);
-
}
else if (adminConnectorPort == port)
{
@@ -3255,7 +3193,6 @@
getUserData().setAdminConnectorPort(adminConnectorPort);
qs.displayFieldInvalid(FieldName.ADMIN_CONNECTOR_PORT, false);
}
-
} catch (NumberFormatException nfe)
{
errorMsgs.add(INFO_INVALID_PORT_VALUE_RANGE.get(
@@ -3277,16 +3214,8 @@
qs.displayFieldInvalid(FieldName.SECURITY_OPTIONS, true);
} else if (!canUseAsPort(securePort))
{
- if (isPriviledgedPort(securePort))
- {
- errorMsgs.add(INFO_CANNOT_BIND_PRIVILEDGED_PORT.get(
- String.valueOf(securePort)));
- } else
- {
- errorMsgs.add(INFO_CANNOT_BIND_PORT.get(String.valueOf(securePort)));
- }
+ errorMsgs.add(getCannotBindErrorMessage(securePort));
qs.displayFieldInvalid(FieldName.SECURITY_OPTIONS, true);
-
}
else if (port == securePort)
{
@@ -3391,6 +3320,15 @@
}
}
+ private Message getCannotBindErrorMessage(int port)
+ {
+ if (isPriviledgedPort(port))
+ {
+ return INFO_CANNOT_BIND_PRIVILEDGED_PORT.get(String.valueOf(port));
+ }
+ return INFO_CANNOT_BIND_PORT.get(String.valueOf(port));
+ }
+
/**
* Validate the data provided by the user in the data options panel and update
* the userData object according to that content.
@@ -3405,7 +3343,7 @@
Integer replicationPort = -1;
boolean secureReplication = false;
Integer port = null;
- ArrayList<Message> errorMsgs = new ArrayList<Message>();
+ List<Message> errorMsgs = new ArrayList<Message>();
DataReplicationOptions.Type type = (DataReplicationOptions.Type)
qs.getFieldValue(FieldName.REPLICATION_OPTIONS);
@@ -3524,7 +3462,7 @@
}
}
- private int checkReplicationPort(QuickSetup qs, ArrayList<Message> errorMsgs)
+ private int checkReplicationPort(QuickSetup qs, List<Message> errorMsgs)
{
int replicationPort = -1;
String sPort = qs.getFieldStringValue(FieldName.REPLICATION_PORT);
@@ -3540,15 +3478,7 @@
qs.displayFieldInvalid(FieldName.SERVER_PORT, true);
} else if (!canUseAsPort(replicationPort))
{
- if (isPriviledgedPort(replicationPort))
- {
- errorMsgs.add(INFO_CANNOT_BIND_PRIVILEDGED_PORT.get(
- String.valueOf(replicationPort)));
- } else
- {
- errorMsgs.add(INFO_CANNOT_BIND_PORT.get(
- String.valueOf(replicationPort)));
- }
+ errorMsgs.add(getCannotBindErrorMessage(replicationPort));
qs.displayFieldInvalid(FieldName.REPLICATION_PORT, true);
} else
@@ -3579,7 +3509,7 @@
}
private void checkRemoteHostPortDnAndPwd(String host, String sPort, String dn,
- String pwd, QuickSetup qs, ArrayList<Message> errorMsgs)
+ String pwd, QuickSetup qs, List<Message> errorMsgs)
{
// Check host
if ((host == null) || (host.length() == 0))
@@ -3628,7 +3558,7 @@
}
private void updateUserDataWithADS(String host, int port, String dn,
- String pwd, QuickSetup qs, ArrayList<Message> errorMsgs,
+ String pwd, QuickSetup qs, List<Message> errorMsgs,
boolean[] hasGlobalAdministrators,
String[] effectiveDn) throws UserDataException
{
@@ -3831,7 +3761,7 @@
private void updateUserDataForCreateAdministratorPanel(QuickSetup qs)
throws UserDataException
{
- ArrayList<Message> errorMsgs = new ArrayList<Message>();
+ List<Message> errorMsgs = new ArrayList<Message>();
// Check the Global Administrator UID
String uid = qs.getFieldStringValue(FieldName.GLOBAL_ADMINISTRATOR_UID);
@@ -3903,7 +3833,7 @@
private void updateUserDataForSuffixesOptionsPanel(QuickSetup qs)
throws UserDataException
{
- ArrayList<Message> errorMsgs = new ArrayList<Message>();
+ List<Message> errorMsgs = new ArrayList<Message>();
if (qs.getFieldValue(FieldName.SUFFIXES_TO_REPLICATE_OPTIONS) ==
SuffixesToReplicateOptions.Type.REPLICATE_WITH_EXISTING_SUFFIXES)
{
@@ -3965,7 +3895,7 @@
private void updateUserDataForRemoteReplicationPorts(QuickSetup qs)
throws UserDataException
{
- ArrayList<Message> errorMsgs = new ArrayList<Message>();
+ List<Message> errorMsgs = new ArrayList<Message>();
Map<ServerDescriptor, AuthenticationData> servers =
getUserData().getRemoteWithNoReplicationPort();
Map<?, ?> hm =
@@ -4037,12 +3967,11 @@
*
* @throws UserDataException if the data provided by the user is not
* valid.
- *
*/
private void updateUserDataForNewSuffixOptionsPanel(QuickSetup qs)
throws UserDataException
{
- ArrayList<Message> errorMsgs = new ArrayList<Message>();
+ List<Message> errorMsgs = new ArrayList<Message>();
NewSuffixOptions dataOptions = null;
@@ -4182,7 +4111,6 @@
/**
* Update the userData object according to the content of the runtime options
* panel.
- *
*/
private void updateUserDataForRuntimeOptionsPanel(QuickSetup qs)
{
@@ -4195,7 +4123,6 @@
/**
* Update the userData object according to the content of the review
* panel.
- *
*/
private void updateUserDataForReviewPanel(QuickSetup qs)
{
diff --git a/opends/src/server/org/opends/server/tools/InstallDS.java b/opends/src/server/org/opends/server/tools/InstallDS.java
index f8ae616..59d1e45 100644
--- a/opends/src/server/org/opends/server/tools/InstallDS.java
+++ b/opends/src/server/org/opends/server/tools/InstallDS.java
@@ -26,7 +26,6 @@
* Portions Copyright 2011-2013 ForgeRock AS
* Portions Copyright 2011 profiq s.r.o.
*/
-
package org.opends.server.tools;
import static org.opends.messages.AdminToolMessages.*;
@@ -41,10 +40,7 @@
import java.io.OutputStream;
import java.io.PrintStream;
import java.security.KeyStoreException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
+import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -82,8 +78,6 @@
import org.opends.server.util.cli.MenuBuilder;
import org.opends.server.util.cli.MenuResult;
-
-
/**
* This class provides a very simple mechanism for installing the OpenDS
* Directory Service. It performs the following tasks:
@@ -113,7 +107,6 @@
/**
* The enumeration containing the different return codes that the command-line
* can have.
- *
*/
enum ErrorReturnCode
{
@@ -244,7 +237,7 @@
*/
static private final Logger LOG = Logger.getLogger(InstallDS.class.getName());
- // The argument parser
+ /** The argument parser. */
private InstallDSArgumentParser argParser;
/**
@@ -264,7 +257,6 @@
*
* @param args the command-line arguments provided to this program.
*/
-
public static void main(String[] args)
{
int retCode = mainCLI(args, System.out, System.err, System.in);
@@ -280,7 +272,6 @@
*
* @return The error code.
*/
-
public static int mainCLI(String[] args)
{
return mainCLI(args, System.out, System.err, System.in);
@@ -301,7 +292,6 @@
* @param inStream The input stream to use for standard input.
* @return The error code.
*/
-
public static int mainCLI(String[] args,
OutputStream outStream, OutputStream errStream, InputStream inStream)
{
@@ -696,7 +686,7 @@
private void initializeUserDataWithParser(UserData uData)
throws UserDataException
{
- LinkedList<Message> errorMessages = new LinkedList<Message>();
+ List<Message> errorMessages = new LinkedList<Message>();
uData.setQuiet(isQuiet());
uData.setVerbose(isVerbose());
uData.setConnectTimeout(getConnectTimeout());
@@ -751,59 +741,16 @@
if (!argParser.skipPortCheckArg.isPresent())
{
- // Check if the port can be used.
- if (!SetupUtils.canUseAsPort(ldapPort))
- {
- Message message;
- if (SetupUtils.isPriviledgedPort(ldapPort))
- {
- message = ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get(
- ldapPort);
- }
- else
- {
- message = ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(ldapPort);
- }
- errorMessages.add(message);
- }
-
-// Check if the port can be used.
- if (!SetupUtils.canUseAsPort(adminConnectorPort))
- {
- Message message;
- if (SetupUtils.isPriviledgedPort(adminConnectorPort))
- {
- message = ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get(
- adminConnectorPort);
- }
- else
- {
- message = ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(adminConnectorPort);
- }
- errorMessages.add(message);
- }
+ checkCanUsePort(ldapPort, errorMessages);
+ checkCanUsePort(adminConnectorPort, errorMessages);
}
if (argParser.jmxPortArg.isPresent())
{
int jmxPort = argParser.jmxPortArg.getIntValue();
uData.setServerJMXPort(jmxPort);
- // Check if the port can be used.
if (!argParser.skipPortCheckArg.isPresent())
{
- if (!SetupUtils.canUseAsPort(jmxPort))
- {
- Message message;
- if (SetupUtils.isPriviledgedPort(jmxPort))
- {
- message = ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get(
- jmxPort);
- }
- else
- {
- message = ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(jmxPort);
- }
- errorMessages.add(message);
- }
+ checkCanUsePort(jmxPort, errorMessages);
}
}
}
@@ -818,7 +765,7 @@
if (argParser.importLDIFArg.isPresent())
{
// Check that the files exist
- LinkedList<String> nonExistingFiles = new LinkedList<String>();
+ List<String> nonExistingFiles = new LinkedList<String>();
for (String file : argParser.importLDIFArg.getValues())
{
if (!Utils.fileExists(file))
@@ -883,23 +830,9 @@
{
errorMessages.add(ae.getMessageObject());
}
- if (enableSSL)
+ if (enableSSL && !argParser.skipPortCheckArg.isPresent())
{
- if (!argParser.skipPortCheckArg.isPresent())
- {
- if (!SetupUtils.canUseAsPort(ldapsPort))
- {
- if (SetupUtils.isPriviledgedPort(ldapsPort))
- {
- errorMessages.add(
- ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get(ldapsPort));
- }
- else
- {
- errorMessages.add(ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(ldapsPort));
- }
- }
- }
+ checkCanUsePort(ldapsPort, errorMessages);
}
SecurityOptions securityOptions;
LinkedList<String> keystoreAliases = new LinkedList<String>();
@@ -975,6 +908,23 @@
}
}
+ private void checkCanUsePort(int port, List<Message> errorMessages)
+ {
+ if (!SetupUtils.canUseAsPort(port))
+ {
+ errorMessages.add(getCannotBindErrorMessage(port));
+ }
+ }
+
+ private Message getCannotBindErrorMessage(int port)
+ {
+ if (SetupUtils.isPriviledgedPort(port))
+ {
+ return ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get(port);
+ }
+ return ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(port);
+ }
+
/**
* This method updates the contents of a UserData object with what the user
* specified in the command-line. If the user did not provide explicitly some
@@ -1105,7 +1055,7 @@
dns.addAll(arg.getValues());
usedProvided = true;
}
- LinkedList<String> toRemove = new LinkedList<String>();
+ List<String> toRemove = new LinkedList<String>();
for (String dn : dns)
{
try
@@ -1149,7 +1099,7 @@
String hostName = promptForHostNameIfRequired();
uData.setHostName(hostName);
- LinkedList<Integer> usedPorts = new LinkedList<Integer>();
+ List<Integer> usedPorts = new LinkedList<Integer>();
// Determine the LDAP port number.
int ldapPort = promptIfRequiredForPortData(argParser.ldapPortArg,
INFO_INSTALLDS_PROMPT_LDAPPORT.get(), usedPorts, true);
@@ -1234,32 +1184,19 @@
if (!argParser.skipPortCheckArg.isPresent())
{
- // Check if the port can be used.
if (!SetupUtils.canUseAsPort(portNumber))
{
- Message message;
- if (SetupUtils.isPriviledgedPort(portNumber))
+ Message message = getCannotBindErrorMessage(portNumber);
+ if (prompted || includeLineBreak)
{
- if (prompted || includeLineBreak)
- {
- println();
- }
- message = ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get(
- portNumber);
- println(message);
- portNumber = -1;
- }
- else
- {
- if (prompted || includeLineBreak)
- {
- println();
- }
- message = ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(portNumber);
- println(message);
println();
- portNumber = -1;
}
+ println(message);
+ if (!SetupUtils.isPriviledgedPort(portNumber))
+ {
+ println();
+ }
+ portNumber = -1;
}
}
if (portNumber != -1)
@@ -1331,7 +1268,7 @@
if (argParser.importLDIFArg.isPresent())
{
// Check that the files exist
- LinkedList<String> nonExistingFiles = new LinkedList<String>();
+ List<String> nonExistingFiles = new LinkedList<String>();
LinkedList<String> importLDIFFiles = new LinkedList<String>();
for (String file : argParser.importLDIFArg.getValues())
{
@@ -1634,7 +1571,7 @@
boolean enableStartTLS = false;
int ldapsPort = -1;
- LinkedList<Integer> usedPorts = new LinkedList<Integer>();
+ List<Integer> usedPorts = new LinkedList<Integer>();
usedPorts.add(uData.getServerPort());
if (uData.getServerJMXPort() != -1)
{
@@ -2136,7 +2073,7 @@
throw new IllegalStateException(
"Called promptIfRequiredCertificate with invalid type: "+type);
}
- LinkedList<Message> errorMessages = new LinkedList<Message>();
+ List<Message> errorMessages = new LinkedList<Message>();
LinkedList<String> keystoreAliases = new LinkedList<String>();
boolean firstTry = true;
int nPasswordPrompts = 0;
@@ -2432,7 +2369,7 @@
* @param nicknames the list of certificates the user must choose from.
* @return the chosen certificate nickname.
*/
- private String promptForCertificateNickname(LinkedList<String> nicknames)
+ private String promptForCertificateNickname(List<String> nicknames)
{
String nickname = null;
while (nickname == null)
--
Gitblit v1.10.0