cn=Directory Manager
All about Directory Server
All | Personal | Sun

20070826 Sunday August 26, 2007

OpenDS 1.0.0-build004 is now available

I have just uploaded OpenDS 1.0.0-build004, built from revision 2794 of our source tree, to our weekly builds folder. The direct link to download the core server is https://opends.dev.java.net/files/documents/4926/65720/OpenDS-1.0.0-build004.zip. The direct link to download the DSML gateway is https://opends.dev.java.net/files/documents/4926/65721/OpenDS-1.0.0-build004-DSML.war.

I have also updated the archive that may be used to install or upgrade OpenDS via Java Web Start. You may launch that using the URL http://builds.opends.org/install/QuickSetup.jnlp, or visit https://www.opends.org/wiki/page/OverviewOfTheQuickSetupTool for more information.

Detailed information about this build is available at http://builds.opends.org/weekly-builds/1.0.0-build004/. Some of the changes that have been incorporated since OpenDS 1.0.0-build003 include:
  • Revision 2567 -- Update the global ACI definitions to ensure that anyone will be allowed to use the password policy request control by default.

  • Revision 2569 (Issue #2061) -- Update the "Who Am I?" extended operation handler so that it works properly in conjunction with the proxied authorization control and alternate SASL authorization identities.

  • Revision 2570 (Issue #2059) -- Update graphical panels to eliminate cases in which some panels used a different background color than the underlying window. Fix a problem in which it was necessary to click a button twice in order to accept a certificate. Make sure to display a more appropriate representation of the certificate fingerprint.

  • Revision 2584 (Issue #752) -- Implement support for subordinate modify DN plugins, which can be used to receive notification whenever an entry is renamed because of of its superiors was targeted by a modify DN operation.

  • Revision 2586 (Issue #1894) -- Provide the ability to clean up replication information in other servers when uninstalling an instance with replication configured. Also, eliminate the statuspanel.jar file to try to keep the total number of JAR files to a minimum (for easier embedded use), and minimize the number of classes that go in quicksetup.jar to reduce the initial download time when launching QuickSetup.

  • Revision 2595 -- Update the global ACI definitions to ensure that anyone will be allowed to use the authorization identity request control by default.

  • Revision 2601 (Issue #2087) -- Implement support for an identity mapper that can use regular expressions to transform the provided ID string before searching for the appropriate matching user.

  • Revision 2611 (Issue #423) -- Implement support for nested static groups. If the member/uniqueMember attribute of a static group references the DN of another group, then the members of that child group will be considered members of the parent group.

  • Revision 2612 -- Provide a new org.opends.server.util.EmbeddedUtils class that can be used to simplify the process of running the server as an embedded application. It includes methods for starting, stopping, and restarting an embedded server, as well as a means of determining whether the server is currently running.

  • Revision 2613 -- Provide a new @PublicAPI annotation type that can be used to tag code to indicate whether we consider it part of our public API, and if so what the stability level is for that code (i.e., how likely the interface is to change in an incompatible manner in the future) and the ways in which it may be accessed by third-party developers.

  • Revision 2614 (Issue #2098) -- Update the DIGEST-MD5 processing code to properly degrade to initial authentication whenever a client attempts to use subsequent authentication.

  • Revision 2619 (Issue #588) -- Implement support for the "list" tag in MakeLDIF. Note that the syntax for this implementation is not the same as the syntax used for the version of MakeLDIF provided with SLAMD, but it is more internally consistent with other tags that are part of MakeLDIF.

  • Revision 2641 -- Migrate to a new framework for message handling within the server. This will provide a much better framework for future I18n support, and moves the default English-language messages to properties files rather than having them embedded in the code.

  • Revision 2648 -- Correct a number of spelling errors identified in the English-language messages.

  • Revision 2650 -- Apply the @PublicAPI annotation to packages and classes that are part of the OpenDS codebase to indicate their anticipated role in our public API.

  • Revision 2660 -- Add a new convenience constructor for the InternalClientConnection class that makes it possible to create a connection authenticated as a given user by providing only that user's DN.

  • Revision 2664 -- Provide a new EmbeddedUtils.initializeForClientUse() method that can be used to initialize the proper internal structures so that OpenDS code can be more easily used for client-side use.

  • Revision 2687 (Issues #788, 791) -- Update the replication mechanism so that it has the ability to automatically repair inconsistencies that may be detected.

  • Revision 2706 -- Add a new internal LDAP socket implementation that provides a mechanism for leveraging third-party LDAP SDKs to perform internal operations in OpenDS. This makes it easier for applications that already support communication with external LDAPv3 directory servers to also interact with an embedded OpenDS instance. This capability has been tested with both JNDI and the Mozilla LDAP SDK for Java.

  • Revision 2707 -- Merge the installation and upgrade utilities into a single application. Now, when you launch QuickSetup via Java Web Start, you will be asked whether you want to install a new server or upgrade an existing installation.

  • Revision 2721 -- Implement support for an attribute uniqueness plugin, which can be used to ensure that the values for a specified set of attributes are all unique throughout the server (e.g., that no two users are allowed to have the same uid or e-mail address).

  • Revision 2736 (Issue #1602) -- Fix a problem in the replication code in which the removal of the entry at the root of a replication domain could cause a large number of changes to be replayed.

  • Revision 2737 (Issue #1804) -- Update the replication code so that the server can generate an administrative alert whenever a replication conflict is detected.

  • Revision 2743 -- Update the import-ldif and export-ldif tools so that they can be used to launch tasks to perform the import and export operations in addition to operating directly on the backend.

  • Revision 2748 (Issue #2134) -- Fix a problem in the configuration of VLV indexes that prevented them from being managed through the dsconfig tool.

  • Revision 2750 (Issue #2097) -- Fix a problem in the replication total update code that could cause initialization to fail if the replication code received any messages that were not related to the total update.

  • Revision 2755 (Issue #2103) -- Fix an issue with log rotation that could cause it to behave incorrectly if the time interval was changed and the new value was shorter than the previous value.

  • Revision 2757 -- Update the backup and restore tools so that they can be used to launch tasks in addition to operating directly on the backend.

  • Revision 2772 (Issue #2135) -- Add a configuration option that can be used to store entries using a more compact encoding.

  • Revision 2780 -- Update the default server configuration to ensure that the uniqueMember attribute type is indexed for equality.

  • Revision 2781 -- Add a tool that can be used to base64 encode or decode data provided as a string, contained in a file, or piped in via standard input.

  • Revision 2783 -- Update the lock manager configuration to provide a property that can be used to indicate whether fairness should be guaranteed for contended locks.

  • Revision 2784 (Issue #526) -- Add a mechanism for generating an RC script that can be installed on UNIX systems to configure the server to automatically start when the system boots. Also, update the stop-ds script so that if the server is to be stopped using a kill but no PID file is present, then the stop script will generate an error rather than trying to stop the server using a task (which is guaranteed to fail, since no credentials will have been provided).

Posted by cn_equals_directory_manager ( Aug 26 2007, 02:24:42 PM CDT ) Permalink

20070824 Friday August 24, 2007

Where's the latest OpenDS build?

If you've been watching, you might have noticed that we didn't release a build last week. It was scheduled, and we generated the build and put it through its paces, but unfortunately a huge last-minute commit (which will help make the server easier to internationalize) caused a little more instability than we would have liked. Although most of the problems were found and fixed pretty quickly, we decided to delay the build for another week just to get in some more testing.

This week, we unfortunately encountered another round of problems in the server due to another last-minute commit (which made a change to the behavior the JVM used for contended read/write locks) just before the build was to be generated. This introduced some undesirable side effects in the replication subsystem. We think that we've got those problems worked out and have respun the build and will be kicking off the latest round of tests again. We'll hopefully have a new build available within the next couple of days.

When the build is released, I'll do a much more complete write-up on the changes that it includes, but some of the things that have been checked in since the last build include:
  • We've merged the QuickSetup install and upgrade utilities into a single tool
  • We've added support for nested static groups
  • We've added a basic attribute uniqueness plugin
  • We've added a new identity mapper that lets you use a regular expression to transform the provided identifier string.
  • We've annotated lots of our code to indicate what we intend to expose as part of our public API
  • We've added several utilities to help make it easier to use the server as an embedded application
  • We've added some basic capabilities to allow replication to automatically repair inconsistencies that may be detected
  • We've updated the replication code so that it's easier for administrators to determine if any conflicts have been detected
  • We've further compacted the way that we store information in the database so that entries are significantly smaller and faster to encode/decode
  • We've added command-line tools to help invoke import, export, backup, and restore operations through the tasks interface
  • We've added a command-line tool that can base64 encode and decode information
  • We've added a command-line tool that can generate an RC script to allow the server to automatically start at boot time on UNIX-based systems
Posted by cn_equals_directory_manager ( Aug 24 2007, 07:17:54 PM CDT ) Permalink

20070820 Monday August 20, 2007

Internal operations in OpenDS

If you're interested in writing an extension to OpenDS (like a plugin, password validator, identity mapper, virtual attribute provider, etc.), then there's a decent chance that you'll want to be able to search for or make changes to content in the directory as part of your processing. And if you intend on using OpenDS in an embedded manner, then it's almost certainly going to be a requirement for you. One option could be to simply establish a connection to the LDAP listener and issue a request, but that's inefficient and can also have undesirable side effects (e.g., if your plugin creates a new LDAP operation, then the server will try to invoke plugins on that operation, which can create a kind of infinite recursion loop). A better alternative, however, is to perform internal operations within the server. Performing an internal operation is more efficient than creating a new external operation, and internal operations can do things that aren't allowed for external operations (e.g., update attributes marked as NO-USER-MODIFICATION) and they are also marked as internal operations so that it's possible to do things like skip plugin processing for them.


The Internal Client Connection Object

For quite a while now, OpenDS has provided the org.opends.server.protocols.internal.InternalClientConnection class, which offers a relatively simple way to perform internal operations in the server. To use it, you first need to obtain an internal client connection, which you can do in one of the following ways:
  • If you don't need to worry about enforcing access control for the internal operation, you can use the InternalClientConnection.getRootConnection() method. This will give you a connection established as an internal user with root privileges (bypass-acl, modify-acl, config-read, config-write, ldif-import, ldif-export, backend-backup, backend-restore, server-shutdown, server-restart, disconnect-client, cancel-request, password-reset, privilege-change, and unindexed-search) that can do just about anything in the server.

  • If you do want access control enforced for the internal operation (e.g., only do this operation if the authenticated user has the right to do it), then you will want to get an internal client connection as that user. To do that, you can create a new internal client connection with either the InternalClientConnection(DN) or InternalClientConnection(AuthenticationInfo) constructor.

Once you have a handle to the internal client connection, then you can use it to perform internal operations in the server. For example, to perform a simple search, you can use something like:
InternalSearchOperation searchOperation =
     internalClientConnection.processSearch("dc=example,dc=com", SearchScope.WHOLE_SUBTREE,
                                            "(uid=john.doe)");
for (SearchResultEntry matchingEntry : searchOperation.getSearchEntries())
{
  // Do something with the entry.
}

We've added lots of convenience methods in the InternalClientConnection class to help make performing internal operations easy, and we hope to have official documentation on this in the near future. For now, however, you can look at the Javadoc from our latest daily build to see what's available.


The Internal LDAP Socket

The internal operations API referenced above should be easy to use, and should allow you to do pretty much anything that you need. I would expect that someone who has ever done any programming involving an existing LDAP SDK (e.g., JDNI or the Mozilla LDAP SDK for Java) should find it especially easy to pick up. However, last week I was talking with some people who were interested in embedding OpenDS and had a bit of a dilemma because they wanted to be able to embed OpenDS and communicate efficiently with it, but they also wanted to have the ability for their application to communicate with external directory servers, and they wanted to avoid having to write all of their client code twice (once using the OpenDS internal API, and another time using the Mozilla LDAP SDK for Java which is their API of choice for external LDAP communication). I gave this a little thought and came up with a solution that I think is a rather elegant approach to the problem: I created a custom socket implementation that is able to convert LDAP requests into internal operations, process the operation, and then convert the response back into LDAP.

This code is implemented in the org.opends.server.protocols.internal.InternalLDAPSocket class, which extends the java.net.Socket superclass. Going along with this socket (and doing all the real work behind the scenes) are the InternalLDAPInputStream and InternaLDAPOutputStream classes. As long as the LDAP SDK that you are using supports the use of a custom socket factory, you can use this custom socket implementation to allow you to use that LDAP SDK to perform internal operations. Both JNDI and the Mozilla LDAP SDK for Java support this, and I've tested my implementation with both of them.

For JNDI, if you want to use this custom socket implementation, the only thing that you have to do out of the ordinary is to make sure that your environment properties have the "java.naming.ldap.factory.socket" property set to "org.opends.server.protocols.internal.InternalLDAPSocketFactory". For example:
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
        "com.sun.jndi.ldap.LdapCtxFactory");
env.put("java.naming.ldap.factory.socket",
        "org.opends.server.protocols.internal.InternalLDAPSocketFactory");
env.put(Context.PROVIDER_URL, "ldap://doesntmatter:389/");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=Directory Manager");
env.put(Context.SECURITY_CREDENTIALS, "password");

DirContext context = new InitialDirContext(env);
// Do whatever you want with the connection here

For the Mozilla LDAP SDK for Java, there's just a tiny bit more that you have to do, because it uses its own socket factory implementation (netscape.ldap.LDAPSocketFactory) instead of the one provided by the JDK (javax.net.SocketFactory, although to be fair that class didn't exist when the Mozilla SDK was written). That interface requires a single makeSocket method, which you can implement as follows:
public Socket makeSocket(String host, int port)
{
  return new InternalLDAPSocket();
}

When you're creating a connection with the Mozilla LDAP SDK for Java, then all you need to do is to use the LDAPConnection(LDAPSocketFactory) constructor to have it use that socket factory for its communication. As an example, I have written a simple EmbeddedMozillaLDAPSDKTest program that can be used to start an embedded OpenDS instance, perform some internal operations using the Mozilla LDAP SDK for Java, and shut down the server. In order to create an appropriate environment for this test, all I needed to do was:
  1. Create an empty directory to use as the server root.
  2. Copy the config directory structure from an OpenDS installation into the new server root.
  3. Create a lib directory below the new server root and copy all of the lib/*.jar files from an OpenDS installation into it.
  4. Create empty db, logs, and locks directories below the new server root
Then, when I compiled and ran the program, it started the server, interacted with it using the Mozilla SDK, and shut it down again. Note that I could have trimmed things down even more if I wanted to put more effort into it (e.g., we don't need everything under the config directory, and if we disable loggers then we wouldn't have needed the logs directory, etc.), but I wanted to keep this example simple.


Limitations of the Internal LDAP Socket Implementation

In general, if you're using the internal LDAP socket implementation you can do pretty much anything that you could do if you were talking to OpenDS using actual LDAP network communication. However, there are a few important things to note about this implementation:
  • You can only use clear-text communication when interacting with the Directory Server. This implementation doesn't support the use of SSL or StartTLS to secure the communication, but that really shouldn't be a problem since there's no actual communication and the operations never leave the JVM.

  • This implementation does not support the use of SASL authentication, so only simple binds are allowed. Although technically it would have worked with some mechanisms (e.g., ANONYMOUS, CRAM-MD5, DIGEST-MD5, and PLAIN), others (in particular, EXTERNAL and GSSAPI) would not have worked. Again, given that all the communication is purely internal to the JVM, I really didn't see a need to use anything other than simple authentication, so that's all that is exposed.

  • Abandon operations don't do anything. OpenDS doesn't provide a mechanism for abandoning internal operations, so any abandon operation requested in this manner will simply be ignored. Although I haven't tested it, I would expect that attempts to use the LDAP cancel extended operation would probably be rejected with a "cannot cancel" result.

Posted by cn_equals_directory_manager ( Aug 20 2007, 03:29:58 PM CDT ) Permalink

20070817 Friday August 17, 2007

Tips on using OpenDS in an embedded manner

Later today, I'm going to be talking to a group that is interested in using OpenDS with their application. One of the key things that interests them is the fact that it can be used as a fast, scalable, replicated data store that they can embed as part of their application. Unfortunately, there is not a lot of documentation available about how to do this, and until recently there weren't a lot of facilities in the code to help out with that either, which means that even though it was possible you had to get pretty familiar with the code in order to figure out how to use OpenDS in an embedded manner.

Fortunately, things are starting to change in this area. Some of the things that we've done recently around this include:
  • We've created an org.opends.server.util.EmbeddedUtils class that can be used to start, stop, and restart the server in an embedded environment, as well as to check whether it's currently running and also to initialize server data structures if you just want to use the libraries for some reason without actually running the server.

  • We've started to identify which classes are part of our public API. We have created an @PublicAPI annotation type, which shows up in the Javadoc documentation and is available via reflection. We hope to be able to use this to write tools that can examine third-party code to see if they're using any private or unstable interfaces.

  • We've added a few convenience methods in our internal operations API that can be used to help make it easier to invoke operations in the server using method calls rather than protocol-level communication.

The slides that I'm going to be using to discuss using OpenDS in an embedded manner are available in this PDF. It's just an overview of the facilities that we have in place and what's coming, and hopefully we'll have even more improvements in this area in the weeks to come.

Posted by cn_equals_directory_manager ( Aug 17 2007, 12:08:56 PM CDT ) Permalink Comments [1]

20070803 Friday August 03, 2007

OpenDS 1.0.0-build003 is now available

I have just uploaded OpenDS 1.0.0-build003, built from revision 2550 of our source tree, to our weekly builds folder. The direct link to download the core server is https://opends.dev.java.net/files/documents/4926/63458/OpenDS-1.0.0-build003.zip. The direct link to download the DSML gateway is https://opends.dev.java.net/files/documents/4926/63459/OpenDS-1.0.0-build003-DSML.war.

I have also updated the archive that may be used to install OpenDS via Java Web Start. You may launch that using the URL http://builds.opends.org/install/QuickSetup.jnlp, or visit https://www.opends.org/wiki/page/OverviewOfTheQuickSetupTool for more information.

Detailed information about this build is available at http://builds.opends.org/weekly-builds/1.0.0-build003. Some of the changes that have been incorporated since OpenDS 1.0.0-build002 include:
  • Revision 2446 (Issue #1986) -- Update the graphical and command-line setup mechanisms to attempt to detect and prevent install paths into directories containing a percent sign, especially on Windows.

  • Revision 2447 (Issue #2006) -- Update QuickSetup to prevent users from choosing the same ports for different protocols (like LDAP and LDAPS).

  • Revision 2448 (Issue #221) -- Add a general framework that may be used to allow OpenDS to send e-mail messages. Also, add an SMTP alert handler that can be used to send e-mail messages in response to administrative alerts generated within the server.

  • Revision 2449 (Issue #452) -- Add a new "targetcontrol" facility to the access control framework that can be used to restrict which clients are allowed to use specified request controls.

  • Revision 2457 (Issue #1819) -- Provide the ability to define certain configuration options as "advanced". This will make it possible to hide these options in administrative interfaces like dsconfig unless the user explicitly requests to see advanced options.

  • Revision 2461 (Issue #1849) -- Fix a problem with the evaluation of the debugsearchindex operational attribute (used to provide information about index processing performed during a search) in which evaluation was not correct with double-negation (a "NOT" inside a "NOT").

  • Revision 2475 (Issue #1015) -- Update a number of the command-line tools provided with OpenDS so that they include improved debugging support. When used in "--verbose" mode, they can now trace the contents of incoming and outgoing LDAP messages and ASN.1 elements in many cases.

  • Revision 2479 (Issue #443) -- Add a new access control "extop" keyword that can be used to restrict which extended operations may be invoked for a given client.

  • Revision 2480 (Issue #1831) -- Provide initial support for an "--interactive" mode for the dsconfig tool. This provides a basic text-based, menu-driven interface for interacting with the server configuration, although there are a number of known issues that still need to be addressed with this capability.

  • Revision 2483 (Issue #1971) -- Allow partial non-append imports for a backend with multiple base DNs (i.e., allow content under one base DN to be imported without impacting content below other base DNs in the same backend).

  • Revision 2499 (Issue #38) -- Provide a mechanism for performing VLV indexing, which makes it possible to efficiently use virtual list view and server-side sorting for searches that might not otherwise be indexed and/or inefficient.

  • Revision 2500 -- Fix a problem in access control evaluation in which use of the targetattr keyword to match all attributes except a named list could incorrectly grant access to operational attributes.

  • Revision 2503 (Issue #429, 478, 2025) -- Add support for a new disconnect client task that can be used to allow an appropriately-privileged administrator (needing at least the "disconnect-client" privilege) to terminate a client connection if the need arises. Also, add a "Get Connection ID" extended operation that can be used to allow a client to get the connection ID associated with its connection.

  • Revision 2505 (Issue #2024) -- Implement support for restricting the set of tasks that can be invoked in the server. Only those tasks which are listed in the ds-cfg-allowed-task attribute in the cn=config entry may be invoked in the server.

  • Revision 2508 (Issue #1683) -- Provide a mechanism to disable privileges in the server if necessary. If a given privilege is disabled, then it will be assumed that all clients have that privilege.

  • Revision 2509 (Issue #1787) -- Provide a configuration option that makes it possible for an administrator to control whether responses to failed bind operations should be allowed to include an error message that explains the problem. By default, this message will not be included for security reasons, but administrators may configure the server to allow it to be sent to provide the client with information about the reason for the failure.

  • Revision 2512 (Issue #2027) -- Provide a way to configure each alert handler with an explicit set of alert types that will be allowed or ignored. This makes it possible to restrict the types of alerts that a given alert handler will be asked to process.

  • Revision 2514 (Issue #118) -- Update the server to provide support for an idle time limit configuration option for LDAP clients. That is, it is now possible to configure the server to automatically terminate a client connection if it has remained unused for too long. The idle time limit is a server-wide configuration option, but it can be overridden on a per-user basis.

  • Revision 2515 (Issue #2026) -- Ensure that processes launched by QuickSetup will use the same JVM as is used to run QuickSetup, even if an alternate JAVA_HOME is configured in the environment.

  • Revision 2521 -- Update the status panel utility so that it can communicate with the server over a secure communication channel. If the server certificate is not trusted, the user will be prompted about whether to accept it.

  • Revision 2529 (Issue #2033, 2034) -- Update the task backend to provide the ability to send an e-mail message whenever a task is complete. The set of recipients may be configured on a per-task basis, and it is possible to specify whether the message should always be sent or only if the task fails.

  • Revision 2533 (Issue #1991) -- Improve the "dsconfig list-properties" output and make its usage more consistent with other dsconfig subcommands.

  • Revision 2535 (Issue #2032) -- Update the password policy to ensure that the sum of the minimum password age and the password expiration warning interval should always be less than the maximum password age (if the corresponding options are configured). This will prevent undesirable configurations, like a minimum age that is greater than the maximum age, or sending expiration warning messages to the client during a time when the user is not allowed to change the password.

  • Revision 2539 -- Update the access control handler to provide the ability to control whether a smart referral (i.e., a named subordinate reference as per RFC 3296) should be returned to the client.

  • Revision 2542 -- Fix a problem with the way that the Netscape password expired control was being encoded to ensure that it always has an appropriate value.

Posted by cn_equals_directory_manager ( Aug 03 2007, 04:33:41 PM CDT ) Permalink

OpenDS switching to bi-weekly builds

For the last year we have generally made pre-packaged OpenDS builds available once a week. There have been a few exceptions, but in general we've had a weekly build schedule. Starting with this week's build (or actually, with last week's lack of a build) we are changing to a bi-weekly (i.e., fortnightly -- once every two weeks, not twice a week) process. The main reason for this is that our QA team has started looking more closely at what goes into these builds and has continued to improve their test coverage. Since at least some of this isn't automated and involves manual testing, reducing the frequency of these QA-tested builds gives them more time to get other stuff done (like writing new automated test cases) in between verifying builds that we want to make public.

So what, if anything, does this change? Not a whole lot. Of course, since they have two weeks of effort instead of one, there will be a larger number of changes from one build to another. But at least for now, where you get the builds (https://opends.dev.java.net/servlets/ProjectDocumentList?folderID=5700&expandFolder=5700&folderID=0) won't change and there will still be places that refer to them as "weekly" builds, although we'll probably clean up these references at some point.

If the arrival of the latest OpenDS build is the highlight of your week and you're not sure how you'll be able to handle waiting twice as long between builds, you can always look at our daily builds (http://builds.opends.org/daily-builds/), or you can check out and build the code for yourself whenever you want. But for this week, you should be able to get your fix in a few minutes when we post OpenDS 1.0.0-build003.

Posted by cn_equals_directory_manager ( Aug 03 2007, 04:23:12 PM CDT ) Permalink


Archives
Language
Links
Referrers