aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandra Ellwood <lxs@mit.edu>2008-05-07 19:30:12 +0000
committerAlexandra Ellwood <lxs@mit.edu>2008-05-07 19:30:12 +0000
commit5434b4b675b53ed41436bccc9ef70d76d199a081 (patch)
tree34bb81c9a68d59648a71bf8312bbef44bc868511
parentc59402909451704c36f862fb2968f6c8e717df4c (diff)
downloadkrb5-5434b4b675b53ed41436bccc9ef70d76d199a081.zip
krb5-5434b4b675b53ed41436bccc9ef70d76d199a081.tar.gz
krb5-5434b4b675b53ed41436bccc9ef70d76d199a081.tar.bz2
Move KIM implementation to the krb5 repository
Moved sources and headers. ticket: new status: open git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20314 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/include/kim/kim.h176
-rw-r--r--src/include/kim/kim_ccache.h554
-rw-r--r--src/include/kim/kim_credential.h519
-rw-r--r--src/include/kim/kim_error.h120
-rw-r--r--src/include/kim/kim_identity.h307
-rw-r--r--src/include/kim/kim_options.h637
-rw-r--r--src/include/kim/kim_preferences.h485
-rw-r--r--src/include/kim/kim_selection_hints.h537
-rw-r--r--src/include/kim/kim_string.h84
-rw-r--r--src/include/kim/kim_types.h162
-rw-r--r--src/kim/agent/mac/KerberosAgent-Info.plist26
-rw-r--r--src/kim/agent/mac/KerberosAgentPrefix.pch20
-rw-r--r--src/kim/agent/mac/main.m6
-rw-r--r--src/kim/agent/mac/resources/Add.tiffbin0 -> 728 bytes
-rw-r--r--src/kim/agent/mac/resources/Add_Pressed.tiffbin0 -> 688 bytes
-rw-r--r--src/kim/agent/mac/resources/English.lproj/Authentication.xib3698
-rw-r--r--src/kim/agent/mac/resources/English.lproj/MainMenu.xib3882
-rw-r--r--src/kim/agent/mac/resources/Gear.tiffbin0 -> 22360 bytes
-rw-r--r--src/kim/agent/mac/resources/KerberosAgent.icnsbin0 -> 40494 bytes
-rw-r--r--src/kim/agent/mac/resources/Remove.tiffbin0 -> 694 bytes
-rw-r--r--src/kim/agent/mac/resources/Remove_Pressed.tiffbin0 -> 656 bytes
-rw-r--r--src/kim/lib/kim.exports149
-rw-r--r--src/kim/lib/kim_ccache.c1051
-rw-r--r--src/kim/lib/kim_ccache_private.h39
-rw-r--r--src/kim/lib/kim_credential.c908
-rw-r--r--src/kim/lib/kim_error.c244
-rw-r--r--src/kim/lib/kim_error_code.et72
-rw-r--r--src/kim/lib/kim_error_private.h55
-rw-r--r--src/kim/lib/kim_identity.c544
-rw-r--r--src/kim/lib/kim_identity_private.h38
-rw-r--r--src/kim/lib/kim_library.c214
-rw-r--r--src/kim/lib/kim_library_private.h54
-rw-r--r--src/kim/lib/kim_options.c694
-rw-r--r--src/kim/lib/kim_options_private.h41
-rw-r--r--src/kim/lib/kim_preferences.c1120
-rw-r--r--src/kim/lib/kim_preferences_private.h102
-rw-r--r--src/kim/lib/kim_private.h45
-rw-r--r--src/kim/lib/kim_selection_hints.c702
-rw-r--r--src/kim/lib/kim_selection_hints_private.h55
-rw-r--r--src/kim/lib/kim_string.c181
-rw-r--r--src/kim/lib/kim_string_private.h60
-rw-r--r--src/kim/lib/mac/kim_os_identity.c50
-rw-r--r--src/kim/lib/mac/kim_os_library.c56
-rw-r--r--src/kim/lib/mac/kim_os_preferences.c552
-rw-r--r--src/kim/lib/mac/kim_os_private.h54
-rw-r--r--src/kim/lib/mac/kim_os_selection_hints.c538
-rw-r--r--src/kim/lib/mac/kim_os_string.c266
-rw-r--r--src/kim/test/main.c82
-rw-r--r--src/kim/test/test_kim_common.c159
-rw-r--r--src/kim/test/test_kim_common.h78
-rw-r--r--src/kim/test/test_kim_identity.c559
-rw-r--r--src/kim/test/test_kim_identity.h50
-rw-r--r--src/kim/test/test_kim_preferences.c298
-rw-r--r--src/kim/test/test_kim_preferences.h42
-rw-r--r--src/kim/test/test_kim_selection_hints.c469
-rw-r--r--src/kim/test/test_kim_selection_hints.h46
56 files changed, 20880 insertions, 0 deletions
diff --git a/src/include/kim/kim.h b/src/include/kim/kim.h
new file mode 100644
index 0000000..893891d
--- /dev/null
+++ b/src/include/kim/kim.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_H
+#define KIM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kim/kim_types.h>
+#include <kim/kim_string.h>
+#include <kim/kim_error.h>
+#include <kim/kim_identity.h>
+#include <kim/kim_options.h>
+#include <kim/kim_selection_hints.h>
+#include <kim/kim_preferences.h>
+#include <kim/kim_credential.h>
+#include <kim/kim_ccache.h>
+
+/*!
+ * \mainpage Kerberos Identity Management (KIM) API Documentation
+ *
+ * \section introduction Introduction
+ *
+ * The Kerberos Identity Management API is a high level API for managing the selection
+ * and management of Kerberos credentials. It is intended for use by applications,
+ * credential management applications (eg: kinit, kpasswd, etc) and internally by the
+ * Kerberos libraries. Under some circumstances client applications may also benefit
+ * from the Kerberos Identity Management API.
+ *
+ *
+ * \section conventions API Conventions
+ *
+ * Although KIM currently only provides a C API, it attempts to make that API as
+ * object-oriented as possible. KIM functions are grouped by object and all of the
+ * object types are opaque, including errors. The reason for this is two-fold. First,
+ * the KIM API is rather large. Grouping functions by object allows the API to be
+ * broken up into smaller, more manageable chunks. Second, providing an object-like C
+ * API will make it easier to port to object oriented languages.
+ *
+ * Because C lacks classes and other object oriented syntax, KIM functions adhere to
+ * the following naming conventions to make functions easier to identify:
+ *
+ * \li Functions beginning with \b kim_object_create are constructors for an object of
+ * type kim_object. On success these functions return a newly allocated object which
+ * must later be freed by the caller.
+ *
+ * \li Functions of the form \b kim_object_copy are copy constructors. They instantiate
+ * a new object of kim_object from an object of the same type.
+ *
+ * \li Functions of the form \b kim_object_free are destructors for objects of type
+ * kim_object.
+ *
+ * \li Functions beginning with \b kim_object_get and \b kim_object_set
+ * examine and modify properties of objects of type kim_object.
+ *
+ * \li All KIM APIs except destructors and error management APIs return a
+ * KIM Error object (kim_error_t).
+ *
+ *
+ * \section terminology Terminology
+ *
+ * Kerberos organizes its authentication tokens by client identity (the name of the user)
+ * and service identity (the name of a service). The following terms are used throughout
+ * this documentation:
+ *
+ * \li <b>credential</b> - A token which authenticates a client identity to a
+ * service identity.
+ *
+ * \li <b>ccache</b> - Short for "credentials cache". A set of credentials for a single
+ * client identity.
+ *
+ * \li <b>cache collection</b> - The set of all credential caches.
+ *
+ * \li <b>default ccache</b> - A credentials cache that the Kerberos libraries will use
+ * if no ccache is specified by the caller. Use of the default
+ * ccache is now discouraged. Instead applications should use
+ * selection hints to choose an appropriate client identity.
+ *
+ * \section selection_api Client Identity Selection APIs
+ *
+ * KIM provides high level APIs for applications to select which client identity to
+ * use. Use of these APIs is intended to replace the traditional "default ccache"
+ * mechanism previously used by Kerberos.
+ *
+ * <B>KIM Selection Hints (kim_selection_hints_t)</B> controls options for selecting
+ * a client identity:
+ * - \subpage kim_selection_hints_overview
+ * - \subpage kim_selection_hints_reference
+ *
+ * <B>KIM Identity (kim_identity_t)</B> provides an immutable Kerberos identity object
+ * - \subpage kim_identity_overview
+ * - \subpage kim_identity_reference
+ *
+ *
+ * \section management_api Credential Management APIs
+ *
+ * KIM also provides APIs for acquiring new credentials over the network
+ * by contacting a KDC and for viewing and modifying the existing credentials
+ * in the cache collection
+ *
+ * Whether or not you use the credential or ccache APIs depends on
+ * whether you want KIM to store any newly acquired credentials in the
+ * cache collection. KIM ccache APIs always create a ccache in the cache
+ * collection containing newly acquired credentials whereas the KIM
+ * credential APIs just return a credential object. In general most
+ * callers want to store newly acquired credentials and should use the
+ * KIM ccache APIs when acquiring credentials.
+ *
+ * <B>KIM CCache (kim_ccache_t)</B> manipulates credential caches in the cache collection:
+ * - \subpage kim_ccache_overview
+ * - \subpage kim_ccache_reference
+ *
+ * <B>KIM Credential (kim_credential_t)</B> manipulates credentials:
+ * - \subpage kim_credential_overview
+ * - \subpage kim_credential_reference
+ *
+ * <B>KIM Options (kim_options_t)</B> control options for credential acquisition:
+ * - \subpage kim_options_overview
+ * - \subpage kim_options_reference
+ *
+ * <B>KIM Realms List (kim_favorite_identities_t)</B> views and edits the current user's favorite realms list:
+ * - \subpage kim_favorite_identities_overview
+ * - \subpage kim_favorite_identities_reference
+ *
+ * <B>KIM Preferences (kim_preferences_t)</B> views and edits the current user's preferences:
+ * - \subpage kim_preferences_overview
+ * - \subpage kim_preferences_reference
+ *
+ *
+ * \section utility_apis Miscellaneous APIs
+ *
+ * The high and low level APIs depend on the following basic utility classes
+ * to manage generic types.
+ *
+ * <B>KIM String (kim_string_t)</B> provides memory management for an immutable string:
+ * - \subpage kim_string_overview
+ * - \subpage kim_string_reference
+ *
+ * <B>KIM Error (kim_error_t)</B> provides a machine and user-readable error message:
+ * - \subpage kim_error_overview
+ * - \subpage kim_error_reference
+ *
+ *
+ * \section types Types and Constants
+ *
+ * \li \subpage kim_types_reference
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_H */
diff --git a/src/include/kim/kim_ccache.h b/src/include/kim/kim_ccache.h
new file mode 100644
index 0000000..ad3ee16
--- /dev/null
+++ b/src/include/kim/kim_ccache.h
@@ -0,0 +1,554 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_CCACHE_H
+#define KIM_CCACHE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kim/kim_types.h>
+
+/*!
+ * \page kim_ccache_overview KIM CCache Overview
+ *
+ * \section kim_ccache_introduction Introduction
+ *
+ * Kerberos credentials are stored in "ccaches" (short for "credentials caches").
+ * The set of all ccaches which the KIM can use is called the "cache collection".
+ * Each ccache has a name and type which uniquely identify it in the cache
+ * collection and a client identity. The ccache's client identity is the
+ * identity whose credentials are stored in the ccache. This allows for easy
+ * lookup of all the credentials for a given identity.
+ *
+ * KIM attempts to preserve a one-to-one relationship between client identities
+ * and ccaches. If the KIM is used to manipulate the cache collection, there
+ * will be one ccache per identity. However, because low-level APIs allow callers
+ * to create multiple ccaches for the same client identity or a single ccache
+ * containing credentials for different client identities, KIM handles those
+ * situations. In general when searching KIM will find the first ccache matching
+ * the requested client identity. It will not find credentials for the requested
+ * client identity if they are in a ccache with a different client identity.
+ *
+ * The kim_ccache_t object is a reference to a ccache in the cache collection.
+ * If other applications make changes to the the ccache pointed to by a KIM ccache
+ * object, the object will immediately show those changes. KIM performs locking
+ * on the cache collection to prevent deadlocks and maintain a consistent behavior
+ * when multiple applications attempt to modify the cache collection.
+ *
+ * \note KIM ccache APIs are intended for applications and system
+ * tools which manage credentials for the user. They are not a substitute for
+ * krb5 and GSSAPI functions which obtain service credentials for the purpose
+ * of authenticating a client to an application server.
+ *
+ * \section kim_credential_cache_collection Acquiring a CCache from the Cache Collection
+ *
+ * KIM provides a simple iterator API for iterating over the ccaches
+ * in the cache collection. First, call #kim_ccache_iterator_create() to obtain
+ * an iterator for the cache collection. Then loop calling
+ * #kim_ccache_iterator_next() until either you find the ccache you are looking
+ * for or the API returns a NULL ccache, indicating that there are no more
+ * ccaches in the cache collection. When you are done with the iterator, call
+ * #kim_ccache_iterator_free().
+ *
+ * \note #kim_ccache_iterator_next() returns ccache objects which
+ * must be freed with #kim_ccache_free() to avoid leaking memory.
+ *
+ * KIM also provides a convenient API #kim_ccache_create_from_client_identity()
+ * which returns the ccache for a specific client identity, if any exists.
+ * Typically callers of this API obtain the client identity using
+ * #kim_selection_hints_get_identity().
+ *
+ *
+ * \section kim_ccache_acquire_default Acquiring Credentials from the Default CCache
+ *
+ * #kim_ccache_create_from_default() returns the default ccache.
+ * The default ccache is a legacy concept which was replaced by selection
+ * hints. Prior to the existence of selection hints, applications always
+ * looked at the default ccache for credentials. By setting the system default
+ * ccache, users could manually control which credentials each application used.
+ * As the number of ccaches and applications has grown, this mechanism has become
+ * unusable. You should avoid using this API whenever possible.
+ *
+ *
+ * \section kim_ccache_acquire_new Acquiring New Credentials in a CCache
+ *
+ * KIM provides the #kim_ccache_create_new() API for acquiring new
+ * credentials and storing them in a ccache. Credentials can either be
+ * obtained for a specific client identity or by specifying
+ * #KIM_IDENTITY_ANY to allow the user to choose. Typically
+ * callers of this API obtain the client identity using
+ * #kim_selection_hints_get_identity(). Depending on the kim_options
+ * specified, #kim_ccache_create_new() may present a GUI or command line
+ * prompt to obtain information from the user.
+ *
+ * #kim_ccache_create_new_if_needed()
+ * searches the cache collection for a ccache for the client identity
+ * and if no appropriate ccache is available, attempts to acquire
+ * new credentials and store them in a new ccache. Depending on the
+ * kim_options specified, #kim_ccache_create_new_if_needed() may
+ * present a GUI or command line prompt to obtain information from the
+ * user. This function exists for convenience and to avoid code duplication.
+ * It can be trivially implemented using
+ * #kim_ccache_create_from_client_identity() and #kim_ccache_create_new().
+ *
+ * KIM provides the #kim_ccache_create_from_keytab() to create credentials
+ * using a keytab and store them in the cache collection. A keytab is an
+ * on-disk copy of a client identity's secret key. Typically sites use
+ * keytabs for client identities that identify a machine or service and
+ * protect the keytab with disk permissions. Because a keytab is
+ * sufficient to obtain credentials, keytabs will normally only be readable
+ * by root, Administrator or some other privileged account.
+ * Typically applications use credentials obtained from keytabs to obtain
+ * credentials for batch processes. These keytabs and credentials are usually
+ * for a special identity used for the batch process rather than a user
+ * identity.
+ *
+ *
+ * \section kim_ccache_validate Validating Credentials in a CCache
+ *
+ * A credential with a start time in the future (ie: after the issue date)
+ * is called a post-dated credential. Because the KDC administrator may
+ * wish to disable a identity, once the start time is reached, all post-dated
+ * credentials must be validated before they can be used. Otherwise an
+ * attacker using a compromised account could acquire lots of post-dated
+ * credentials to circumvent the acccount being disabled.
+ *
+ * KIM provides the #kim_ccache_validate() API to validate the TGT
+ * credential in a ccache. Note that this API replaces any existing
+ * credentials with the validated credential.
+ *
+ *
+ * \section kim_ccache_renew Renewing Credentials in a CCache
+ *
+ * A renewable credential can be used to obtain a new identical credential
+ * without resending secret information (such as a password) to the KDC.
+ * A credential may only be renewed during its renewal lifetime and while
+ * valid.
+ *
+ * KIM provides the #kim_ccache_renew() API to renew the TGT credential
+ * in a ccache. Note that this API replaces any existing credentials with the
+ * renewed credential.
+ *
+ *
+ * \section kim_ccache_verify Verifying Credentials in a CCache
+ *
+ * When a program acquires TGT credentials for the purpose of authenticating
+ * itself to the machine it is running on, it is insufficient for the machine
+ * to assume that the caller is authorized just because it got credentials.
+ * Instead, the credentials must be verified using a key the local machine.
+ * The reason this is necessary is because an attacker can trick the
+ * machine into obtaining credentials from any KDC, including malicious ones
+ * with the same realm name as the local machine's realm. This exploit is
+ * called the Zanarotti attack.
+ *
+ * In order to avoid the Zanarotti attack, the local machine must authenticate
+ * the process in the same way an application server would authenticate a client.
+ * Like an application server, the local machine must have its own identity in
+ * its realm and a keytab for that identity on its local disk. However,
+ * rather than forcing system daemons to use the network-oriented calls in the
+ * krb5 and GSS APIs, KIM provides the #kim_ccache_verify() API to
+ * verify credentials directly.
+ *
+ * The most common reason for using #kim_ccache_verify() is user login.
+ * If the local machine wants to use Kerberos to verify the username and password
+ * provided by the user, it must call #kim_ccache_verify() on the credentials
+ * it obtains to make sure they are really from a KDC it trusts. Another common
+ * case is a server which is only using Kerberos internally. For example an
+ * LDAP or web server might use a username and password obtained over the network
+ * to get Kerberos credentials. In order to make sure they aren't being tricked
+ * into talking to the wrong KDC, these servers must also call
+ * #kim_ccache_verify().
+ *
+ * The Zanarotti attack is only a concern if the act of accessing the machine
+ * gives the process special access. Thus a managed cluster machine with
+ * Kerberos-authenticated networked home directories does not need to call
+ * #kim_ccache_verify(). Even though an attacker can log in as any user on
+ * the cluster machine, the attacker can't actually access any of the user's data
+ * or use any of their privileges because those are all authenticated via
+ * Kerberized application servers (and thus require actually having credentials
+ * for the real local realm).
+ *
+ * #kim_ccache_verify() provides an option to
+ * return success even if the machine's host key is not present. This option
+ * exists for sites which have a mix of different machines, some of which are
+ * vulnerable to the Zanarotti attack and some are not. If this option is used,
+ * it is the responsiblity of the machine's maintainer to obtain a keytab
+ * for their machine if it needs one.
+ *
+ *
+ * \section kim_ccache_properties Examining CCache Properties
+ *
+ * \li #kim_ccache_get_type() returns the type of the ccache. Types include
+ * "API" for CCAPI ccaches, "FILE" for file-based ccaches and "MEMORY" for
+ * single-process in-memory ccaches.
+ *
+ * \li #kim_ccache_get_name() returns the name of the ccache. A ccache's name
+ * identifies the ccache uniquely among ccaches of the same type. Note that
+ * two ccaches with different types may have the same name.
+ *
+ * \li #kim_ccache_get_display_name() returns a display string which uniquely
+ * identifies a ccache. A ccache display name is of the form "<type>:<name>"
+ * and can be displayed to the user or used as an argument to certain krb5
+ * APIs, such as krb5_cc_resolve().
+ *
+ * \li #kim_ccache_get_client_identity()
+ * returns the ccache's client identity.
+ *
+ * \li #kim_ccache_get_valid_credential()
+ * returns the first valid TGT in the ccache for its client identity.
+ * If there are no TGTs in the ccache, it returns the first
+ * valid non-TGT credential for the ccache's client identity.
+ * TGT credentials (ie: "ticket-granting tickets") are credentials for
+ * the krbtgt service: a service identity of the form "krbtgt/<REALM>@<REALM>".
+ * These credentials allow the entity named by the client identity to obtain
+ * additional credentials without resending shared secrets (such as a password)
+ * to the KDC. Kerberos uses TGTs to provide single sign-on authentication.
+ *
+ * \li #kim_ccache_get_start_time()
+ * returns when the credential's in a ccache will become valid.
+ * Credentials may be "post-dated" which means that their lifetime starts sometime
+ * in the future. Note that when a post-dated credential's start time is reached,
+ * the credential must be validated. See \ref kim_credential_validate for more information.
+ *
+ * \li #kim_ccache_get_expiration_time()
+ * returns when the credential's in a ccache will expire.
+ * Credentials are time limited by the lifetime of the credential. While you can
+ * request a credential of any lifetime, the KDC limits the credential lifetime
+ * to a administrator-defined maximum. Typically credential lifetime range from 10
+ * to 21 hours.
+ *
+ * \li #kim_ccache_get_renewal_expiration_time()
+ * returns when the credential's in a ccache will no longer be renewable.
+ * Valid credentials may be renewed up until their renewal expiration time.
+ * Renewing credentials acquires a fresh set of credentials with a full lifetime
+ * without resending secrets to the KDC (such as a password). If credentials are
+ * not renewable, this function will return an error.
+ *
+ * See \ref kim_ccache_reference and \ref kim_ccache_iterator_reference for
+ * information on specific APIs.
+ */
+
+
+/*!
+ * \defgroup kim_ccache_iterator_reference KIM CCache Iterator Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_ccache_iterator on exit, a ccache iterator object for the cache collection.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get a ccache iterator to enumerate ccaches in the cache collection.
+ */
+kim_error_t kim_ccache_iterator_create (kim_ccache_iterator_t *out_ccache_iterator);
+
+/*!
+ * \param in_ccache_iterator a ccache iterator object.
+ * \param out_ccache on exit, the next ccache in the cache collection. If there are
+ * no more ccaches in the cache collection this argument will be
+ * set to NULL.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the next ccache in the cache collection.
+ */
+kim_error_t kim_ccache_iterator_next (kim_ccache_iterator_t in_ccache_iterator,
+ kim_ccache_t *out_ccache);
+
+/*!
+ * \param io_ccache_iterator a ccache iterator object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with a ccache iterator.
+ */
+void kim_ccache_iterator_free (kim_ccache_iterator_t *io_ccache_iterator);
+
+/*!@}*/
+
+/*!
+ * \defgroup kim_ccache_reference KIM CCache Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_ccache on exit, a new cache object for a ccache containing a newly acquired
+ * initial credential. Must be freed with kim_ccache_free().
+ * \param in_client_identity a client identity to obtain a credential for. Specify KIM_IDENTITY_ANY to
+ * allow the user to choose.
+ * \param in_options options to control credential acquisition.
+ * \note Depending on the kim_options specified, #kim_ccache_create_new() may
+ * present a GUI or command line prompt to obtain information from the user.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Acquire a new initial credential and store it in a ccache.
+ */
+kim_error_t kim_ccache_create_new (kim_ccache_t *out_ccache,
+ kim_identity_t in_client_identity,
+ kim_options_t in_options);
+
+/*!
+ * \param out_ccache on exit, a ccache object for a ccache containing a newly acquired
+ * initial credential. Must be freed with kim_ccache_free().
+ * \param in_client_identity a client identity to obtain a credential for.
+ * \param in_options options to control credential acquisition (if a credential is acquired).
+ * \note Depending on the kim_options specified, #kim_ccache_create_new_if_needed() may
+ * present a GUI or command line prompt to obtain information from the user.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Find a ccache containing a valid initial credential in the cache collection, or if
+ * unavailable, acquire and store a new initial credential.
+ */
+kim_error_t kim_ccache_create_new_if_needed (kim_ccache_t *out_ccache,
+ kim_identity_t in_client_identity,
+ kim_options_t in_options);
+
+/*!
+ * \param out_ccache on exit, a ccache object for a ccache containing a TGT
+ * credential. Must be freed with kim_ccache_free().
+ * \param in_client_identity a client identity to obtain a credential for.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Find a ccache for a client identity in the cache collection.
+ */
+kim_error_t kim_ccache_create_from_client_identity (kim_ccache_t *out_ccache,
+ kim_identity_t in_client_identity);
+
+/*!
+ * \param out_ccache on exit, a new ccache object containing an initial credential
+ * for the client identity \a in_identity obtained using in_keytab.
+ * Must be freed with kim_ccache_free().
+ * \param in_identity a client identity to obtain a credential for. Specify NULL for
+ * the first client identity in the keytab.
+ * \param in_options options to control credential acquisition.
+ * \param in_keytab a path to a keytab. Specify NULL for the default keytab location.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Acquire a new initial credential from a keytab and store it in a ccache.
+ */
+kim_error_t kim_ccache_create_from_keytab (kim_ccache_t *out_ccache,
+ kim_identity_t in_identity,
+ kim_options_t in_options,
+ kim_string_t in_keytab);
+
+/*!
+ * \param out_ccache on exit, a ccache object for the default ccache.
+ * Must be freed with kim_ccache_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the default ccache.
+ */
+kim_error_t kim_ccache_create_from_default (kim_ccache_t *out_ccache);
+
+/*!
+ * \param out_ccache on exit, a ccache object for the ccache identified by
+ * \a in_type and \a in_name. Must be freed with kim_ccache_free().
+ * \param in_type a ccache type string.
+ * \param in_name a ccache name string.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \note This API is provided for backwards compatibilty with applications which are not
+ * KIM-aware and should be avoided whenever possible.
+ * \brief Get a ccache for a ccache type and name.
+ */
+kim_error_t kim_ccache_create_from_type_and_name (kim_ccache_t *out_ccache,
+ kim_string_t in_type,
+ kim_string_t in_name);
+
+/*!
+ * \param out_ccache on exit, a new ccache object which is a copy of in_krb5_ccache.
+ * Must be freed with kim_ccache_free().
+ * \param in_krb5_context the krb5 context used to create \a in_krb5_ccache.
+ * \param in_krb5_ccache a krb5 ccache object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get a ccache for a krb5 ccache.
+ */
+kim_error_t kim_ccache_create_from_krb5_ccache (kim_ccache_t *out_ccache,
+ krb5_context in_krb5_context,
+ krb5_ccache in_krb5_ccache);
+
+/*!
+ * \param out_ccache on exit, the new ccache object which is a copy of in_ccache.
+ * Must be freed with kim_ccache_free().
+ * \param in_ccache a ccache object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy a ccache.
+ */
+kim_error_t kim_ccache_copy (kim_ccache_t *out_ccache,
+ kim_ccache_t in_ccache);
+
+/*!
+ * \param in_ccache a ccache object.
+ * \param in_krb5_context a krb5 context which will be used to create out_krb5_ccache.
+ * \param out_krb5_ccache on exit, a new krb5 ccache object which is a copy of in_ccache.
+ * Must be freed with krb5_cc_close() or krb5_cc_destroy().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get a krb5 ccache for a ccache.
+ */
+kim_error_t kim_ccache_get_krb5_ccache (kim_ccache_t in_ccache,
+ krb5_context in_krb5_context,
+ krb5_ccache *out_krb5_ccache);
+
+/*!
+ * \param in_ccache a ccache object.
+ * \param out_name on exit, the name string of \a in_ccache.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the name of a ccache.
+ */
+kim_error_t kim_ccache_get_name (kim_ccache_t in_ccache,
+ kim_string_t *out_name);
+
+/*!
+ * \param in_ccache a ccache object.
+ * \param out_type on exit, the type string of \a in_ccache.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the type of a ccache.
+ */
+kim_error_t kim_ccache_get_type (kim_ccache_t in_ccache,
+ kim_string_t *out_type);
+
+/*!
+ * \param in_ccache a ccache object.
+ * \param out_display_name on exit, the type and name of \a in_ccache in a format appropriate for
+ * display to the user in command line programs. (ie: "<type>:<name>")
+ * Must be freed with kim_string_free().
+ * Note: this string can also be passed to krb5_cc_resolve().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the type and name for a ccache in display format.
+ */
+kim_error_t kim_ccache_get_display_name (kim_ccache_t in_ccache,
+ kim_string_t *out_display_name);
+
+/*!
+ * \param in_ccache a ccache object.
+ * \param out_client_identity on exit, an identity object containing the client identity of
+ * \a in_ccache. Must be freed with kim_identity_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the client identity for a ccache.
+ */
+kim_error_t kim_ccache_get_client_identity (kim_ccache_t in_ccache,
+ kim_identity_t *out_client_identity);
+
+/*!
+ * \param in_ccache a ccache object.
+ * \param out_credential on exit, the first valid credential in \a in_ccache.
+ * Must be freed with kim_credential_free(). Set to NULL
+ * if you only want return value, not the actual credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the first valid credential in a ccache.
+ * \note This function prefers TGT credentials. If there are any non-valid TGTs
+ * in the ccache, it will always return an error. However, if there are no
+ * TGTs at all, it will return the first valid non-TGT credential. If you only want
+ * TGTs, use kim_credential_is_tgt() to verify that \a out_credential is a tgt.
+ */
+kim_error_t kim_ccache_get_valid_credential (kim_ccache_t in_ccache,
+ kim_credential_t *out_credential);
+
+/*!
+ * \param in_ccache a ccache object.
+ * \param out_start_time on exit, the time when the credentials in \a in_ccache
+ * become valid. May be in the past or future.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the time when the credentials in the ccache become valid.
+ */
+kim_error_t kim_ccache_get_start_time (kim_ccache_t in_ccache,
+ kim_time_t *out_start_time);
+
+/*!
+ * \param in_ccache a ccache object.
+ * \param out_expiration_time on exit, the time when the credentials in
+ * \a in_ccache will expire. May be in the past or future.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the time when the credentials in the ccache will expire.
+ */
+kim_error_t kim_ccache_get_expiration_time (kim_ccache_t in_ccache,
+ kim_time_t *out_expiration_time);
+
+/*!
+ * \param in_ccache a ccache object.
+ * \param out_renewal_expiration_time on exit, the time when the credentials in \a in_ccache
+ * will no longer be renewable. May be in the past or future.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the time when the credentials in the ccache will no longer be renewable.
+ */
+kim_error_t kim_ccache_get_renewal_expiration_time (kim_ccache_t in_ccache,
+ kim_time_t *out_renewal_expiration_time);
+
+/*!
+ * \param io_ccache a ccache object which will be set to the default ccache.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \note This API is provided for backwards compatibilty with applications which are not
+ * KIM-aware and should be avoided whenever possible.
+ * \brief Set a ccache to the default ccache.
+ */
+kim_error_t kim_ccache_set_default (kim_ccache_t io_ccache);
+
+/*!
+ * \param in_ccache a ccache object containing the TGT credential to be verified.
+ * \param in_service_identity a service identity to look for in the keytab. Specify
+ * KIM_IDENTITY_ANY to use the default service identity
+ * (usually host/<host's FQDN>@<host's local realm>).
+ * \param in_keytab a path to a keytab. Specify NULL for the default keytab location.
+ * \param in_fail_if_no_service_key whether or not the absence of a key for \a in_service_identity
+ * in the host's keytab will cause a failure.
+ * \note specifying FALSE for \a in_fail_if_no_service_key may expose the calling program to
+ * the Zanarotti attack if the host has no keytab installed.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Verify the TGT in a ccache.
+ */
+kim_error_t kim_ccache_verify (kim_ccache_t in_ccache,
+ kim_identity_t in_service_identity,
+ kim_string_t in_keytab,
+ kim_boolean_t in_fail_if_no_service_key);
+
+/*!
+ * \param in_ccache a ccache object containing a TGT to be renewed.
+ * \param in_options initial credential options to be used if a new credential is obtained.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Renew the TGT in a ccache.
+ */
+kim_error_t kim_ccache_renew (kim_ccache_t in_ccache,
+ kim_options_t in_options);
+
+/*!
+ * \param in_ccache a ccache object containing a TGT to be validated.
+ * \param in_options initial credential options.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Validate the TGT in a ccache.
+ */
+kim_error_t kim_ccache_validate (kim_ccache_t in_ccache,
+ kim_options_t in_options);
+
+/*!
+ * \param io_ccache a ccache object to be destroyed. Set to NULL on exit.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Remove a ccache from the cache collection.
+ * \note Frees memory associated with the ccache. Do not call kim_ccache_free()
+ * after calling this function.
+ */
+kim_error_t kim_ccache_destroy (kim_ccache_t *io_ccache);
+
+/*!
+ * \param io_ccache a ccache object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with a ccache.
+ */
+void kim_ccache_free (kim_ccache_t *io_ccache);
+
+/*!@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_CCACHE_H */
diff --git a/src/include/kim/kim_credential.h b/src/include/kim/kim_credential.h
new file mode 100644
index 0000000..03fe50c
--- /dev/null
+++ b/src/include/kim/kim_credential.h
@@ -0,0 +1,519 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_CREDENTIAL_H
+#define KIM_CREDENTIAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kim/kim_types.h>
+#include <krb5.h>
+
+/*!
+ * \addtogroup kim_types_reference
+ * @{
+ */
+
+/*!
+ * Possible credential states. Credentials may be:
+ * \li valid - The credential can be used.
+ * \li expired - The credential's lifetime has been exceeded.
+ * \li not_yet_valid - The credential is post dated and the time when
+ * it becomes valid has not yet been reached.
+ * \li needs_validation - The credential is post-dated and although
+ * the time when it becomes valid has been reached
+ * it has not yet been validated.
+ * \li address_mismatch - The credential contains IP address(es) which do
+ * not match the host's local address(es).
+ */
+enum kim_credential_state_enum {
+ kim_credentials_state_valid = 0,
+ kim_credentials_state_expired = 1,
+ kim_credentials_state_not_yet_valid = 2,
+ kim_credentials_state_needs_validation = 3,
+ kim_credentials_state_address_mismatch = 4
+};
+
+/*!
+ * The state of a credential. See #kim_credential_state_enum for
+ * possible values.
+ */
+typedef int kim_credential_state_t;
+
+/*! @} */
+
+/*!
+ * \page kim_credential_overview KIM Credential Overview
+ *
+ * \section kim_credential_introduction Introduction
+ *
+ * A Kerberos credential (also called a "Kerberos ticket") is a time-limited
+ * token issued by a KDC which authenticates the entity named by the credential's
+ * client identity to the service named by the credential's service identity.
+ *
+ * The kim_credential_t object contains a single Kerberos credential. KIM credentials
+ * objects are always copies of credentials, not references to credentials
+ * stored in the cache collection. Modifying credential objects in the ccache
+ * collection will not change any existing KIM credential objects.
+ *
+ * KIM credential APIs are intended for applications and system
+ * tools which manage credentials for the user. They are not a substitute for
+ * krb5 and GSSAPI functions which obtain service credentials for the purpose
+ * of authenticating a client to an application server.
+ *
+ * \note Many of the APIs listed below have equivalent functions which
+ * operate on ccaches. In most cases applications will want to use the
+ * ccache versions of these APIs since they automatically store any
+ * newly created credentials. See \ref kim_ccache_overview for more
+ * information.
+ *
+ *
+ * \section kim_credential_acquire_new Acquiring New Credentials
+ *
+ * KIM provides the #kim_credential_create_new() API for acquiring new
+ * credentials. Credentials can either be obtained for a specific
+ * client identity or by specifying #KIM_IDENTITY_ANY to allow
+ * the user to choose. Typically callers of this API obtain the client
+ * identity using #kim_selection_hints_get_identity(). Depending on the
+ * kim_options specified, #kim_credential_create_new() may present a
+ * GUI or command line prompt to obtain information from the user.
+ *
+ * KIM provides the #kim_credential_create_from_keytab() to create credentials
+ * using a keytab. A keytab is an on-disk copy of a client identity's secret
+ * key. Typically sites use keytabs for client identities that identify a
+ * machine or service and protect the keytab with disk permissions. Because
+ * a keytab is sufficient to obtain credentials, keytabs will normally only
+ * be readable by root, Administrator or some other privileged account.
+ * Typically applications use credentials obtained from keytabs to obtain
+ * credentials for batch processes. These keytabs and credentials are usually
+ * for a special identity used for the batch process rather than a user
+ * identity.
+ *
+ *
+ * \section kim_credential_validate Validating Credentials
+ *
+ * A credential with a start time in the future (ie: after the issue date)
+ * is called a post-dated credential. Because the KDC administrator may
+ * wish to disable a identity, once the start time is reached, all post-dated
+ * credentials must be validated before they can be used. Otherwise an
+ * attacker using a compromised account could acquire lots of post-dated
+ * credentials to circumvent the acccount being disabled.
+ *
+ * KIM provides the #kim_credential_validate() API to validate a credential.
+ * Note that this API replaces the credential object with a new validated
+ * credential object. If you wish to store the new credential in the
+ * ccache collection you must either call #kim_credential_store() on the
+ * validated credential or use #kim_ccache_validate() instead.
+ *
+ *
+ * \section kim_credential_renew Renewing Credentials
+ *
+ * A renewable credential can be used to obtain a new identical credential
+ * without resending secret information (such as a password) to the KDC.
+ * A credential may only be renewed during its renewal lifetime and while
+ * valid.
+ *
+ * KIM provides the #kim_credential_renew() API to renew a credential.
+ * Note that this API replaces the credential object with a new renewed
+ * credential object. If you wish to store the new credential in the
+ * ccache collection you must either call #kim_credential_store() on the
+ * renewed credential or use #kim_ccache_renew() instead.
+ *
+ *
+ * \section kim_credential_storing Storing Credentials in the Cache Collection
+ *
+ * KIM credential objects may be stored in the ccache collection using
+ * #kim_credential_store(). This function runs any KIM authentication
+ * plugins on the credential and if the plugins return successfully, creates a
+ * new ccache for the credential's client identity in the cache collection
+ * and stores the credential in that ccache. Any existing ccaches and credentials
+ * for that client identity will be overwritten. #kim_credential_store() may
+ * optionally return a kim_ccache_t object for the new ccache if you need to perform
+ * further operations on the new ccache.
+ *
+ * Most of the time if you plan to store the credentials you are manipulating, you
+ * should use one of KIM ccache APIs. These functions perform the same operations
+ * except that they also call #kim_credential_store() any time the credential object
+ * changes. See \ref kim_ccache_overview for more information.
+ *
+ *
+ * \section kim_credential_iterator_t Iterating over the Credentials in a CCache
+ *
+ * KIM provides a simple iterator API for iterating over the credentials
+ * in a ccache. First, call #kim_credential_iterator_create() to obtain
+ * an iterator for a ccache. Then loop calling #kim_credential_iterator_next()
+ * until either you find the credential you are looking for or the API
+ * returns a NULL credential, indicating that there are no more
+ * credentials in the ccache. When you are done with the iterator, call
+ * #kim_credential_iterator_free().
+ *
+ * \note #kim_credential_iterator_next() returns credential objects which
+ * must be freed with #kim_credential_free() to avoid leaking memory.
+ *
+ *
+ * \section kim_credential_verify Verifying Credentials
+ *
+ * When a program acquires TGT credentials for the purpose of authenticating
+ * itself to the machine it is running on, it is insufficient for the machine
+ * to assume that the caller is authorized just because it got credentials.
+ * Instead, the credentials must be verified using a key the local machine.
+ * The reason this is necessary is because an attacker can trick the
+ * machine into obtaining credentials from any KDC, including malicious ones
+ * with the same realm name as the local machine's realm. This exploit is
+ * called the Zanarotti attack.
+ *
+ * In order to avoid the Zanarotti attack, the local machine must authenticate
+ * the process in the same way an application server would authenticate a client.
+ * Like an application server, the local machine must have its own identity in
+ * its realm and a keytab for that identity on its local disk. However,
+ * rather than forcing system daemons to use the network-oriented calls in the
+ * krb5 and GSS APIs, KIM provides the #kim_credential_verify() API to
+ * verify credentials directly.
+ *
+ * The most common reason for using #kim_credential_verify() is user login.
+ * If the local machine wants to use Kerberos to verify the username and password
+ * provided by the user, it must call #kim_credential_verify() on the credentials
+ * it obtains to make sure they are really from a KDC it trusts. Another common
+ * case is a server which is only using Kerberos internally. For example an
+ * LDAP or web server might use a username and password obtained over the network
+ * to get Kerberos credentials. In order to make sure they aren't being tricked
+ * into talking to the wrong KDC, these servers must also call
+ * #kim_credential_verify().
+ *
+ * The Zanarotti attack is only a concern if the act of accessing the machine
+ * gives the process special access. Thus a managed cluster machine with
+ * Kerberos-authenticated networked home directories does not need to call
+ * #kim_credential_verify(). Even though an attacker can log in as any user on
+ * the cluster machine, the attacker can't actually access any of the user's data
+ * or use any of their privileges because those are all authenticated via
+ * Kerberized application servers (and thus require actually having credentials
+ * for the real local realm).
+ *
+ * #kim_credential_verify() provides an option to
+ * return success even if the machine's host key is not present. This option
+ * exists for sites which have a mix of different machines, some of which are
+ * vulnerable to the Zanarotti attack and some are not. If this option is used,
+ * it is the responsiblity of the machine's maintainer to obtain a keytab
+ * for their machine if it needs one.
+ *
+ *
+ * \section kim_credential_properties Examining Credential Properties
+ *
+ * \li #kim_credential_get_client_identity()
+ * returns the credential's client identity.
+ *
+ * \li #kim_credential_get_service_identity()
+ * returns the credential's service identity.
+ *
+ * \li #kim_credential_is_tgt()
+ * returns whether the credential is a TGT (ie: "ticket-granting ticket"). TGTs are
+ * credentials for the krbtgt service: a service identity of the form "krbtgt/<REALM>@<REALM>".
+ * These credentials allow the entity named by the client identity to obtain
+ * additional service credentials without resending shared secrets (such as a password)
+ * to the KDC. Kerberos uses TGTs to provide single sign-on authentication.
+ *
+ * \li #kim_credential_is_valid()
+ * returns whether the credential is valid and if not why the credential is not valid.
+ *
+ * \li #kim_credential_get_start_time()
+ * returns when the credential will become valid.
+ * Credentials may be "post-dated" which means that their lifetime starts sometime
+ * in the future. Note that when a post-dated credential's start time is reached,
+ * the credential must be validated. See \ref kim_credential_validate for more information.
+ *
+ * \li #kim_credential_get_expiration_time()
+ * returns when the credential will expire.
+ * Credentials are time limited by the lifetime of the credential. While you can
+ * request a credential of any lifetime, the KDC limits the credential lifetime
+ * to a administrator-defined maximum. Typically credential lifetime range from 10
+ * to 21 hours.
+ *
+ * \li #kim_credential_get_renewal_expiration_time()
+ * returns when the credential will no longer be renewable.
+ * Valid credentials may be renewed up until their renewal expiration time.
+ * Renewing credentials acquires a fresh set of credentials with a full lifetime
+ * without resending secrets to the KDC (such as a password). If credentials are
+ * not renewable, this function will return an error.
+ *
+ *
+ * See \ref kim_credential_reference and \ref kim_credential_iterator_reference for
+ * information on specific APIs.
+ */
+
+/*!
+ * \defgroup kim_credential_iterator_reference KIM Credential Iterator Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_credential_iterator on exit, a credential iterator object for \a in_ccache.
+ * Must be freed with kim_credential_iterator_free().
+ * \param in_ccache a ccache object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get a credential iterator to enumerate credentials in a ccache.
+ */
+
+kim_error_t kim_credential_iterator_create (kim_credential_iterator_t *out_credential_iterator,
+ kim_ccache_t in_ccache);
+
+/*!
+ * \param in_credential_iterator a credential iterator object.
+ * \param out_credential on exit, the next credential in the ccache iterated by
+ * \a in_credential_iterator. Must be freed with
+ * kim_credential_free(). If there are no more credentials
+ * this argument will be set to NULL.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the next credential in a ccache.
+ */
+
+kim_error_t kim_credential_iterator_next (kim_credential_iterator_t in_credential_iterator,
+ kim_credential_t *out_credential);
+
+/*!
+ * \param io_credential_iterator a credential iterator object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with a credential iterator.
+ */
+void kim_credential_iterator_free (kim_credential_iterator_t *io_credential_iterator);
+
+/*!@}*/
+
+/*!
+ * \defgroup kim_credential_reference KIM Credential Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_credential on exit, a new credential object containing a newly acquired
+ * initial credential. Must be freed with kim_credential_free().
+ * \param in_client_identity a client identity to obtain a credential for. Specify NULL to
+ * allow the user to choose the identity
+ * \param in_options options to control credential acquisition.
+ * \note Depending on the kim_options specified, #kim_credential_create_new() may
+ * present a GUI or command line prompt to obtain information from the user.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Acquire a new initial credential.
+ * \sa kim_ccache_create_new
+ */
+kim_error_t kim_credential_create_new (kim_credential_t *out_credential,
+ kim_identity_t in_client_identity,
+ kim_options_t in_options);
+
+/*!
+ * \param out_credential on exit, a new credential object containing an initial credential
+ * for \a in_identity obtained using \a in_keytab.
+ * Must be freed with kim_credential_free().
+ * \param in_identity a client identity to obtain a credential for. Specify NULL for
+ * the first identity in the keytab.
+ * \param in_options options to control credential acquisition.
+ * \param in_keytab a path to a keytab. Specify NULL for the default keytab location.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Acquire a new initial credential from a keytab.
+ * \sa kim_ccache_create_from_keytab
+ */
+kim_error_t kim_credential_create_from_keytab (kim_credential_t *out_credential,
+ kim_identity_t in_identity,
+ kim_options_t in_options,
+ kim_string_t in_keytab);
+
+/*!
+ * \param out_credential on exit, a new credential object which is a copy of \a in_krb5_creds.
+ * Must be freed with kim_credential_free().
+ * \param in_krb5_context the krb5 context used to create \a in_krb5_creds.
+ * \param in_krb5_creds a krb5 credential object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy a credential from a krb5 credential object.
+ */
+kim_error_t kim_credential_create_from_krb5_creds (kim_credential_t *out_credential,
+ krb5_context in_krb5_context,
+ krb5_creds *in_krb5_creds);
+
+/*!
+ * \param out_credential on exit, a new credential object which is a copy of \a in_credential.
+ * Must be freed with kim_credential_free().
+ * \param in_credential a credential object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy a credential object.
+ */
+kim_error_t kim_credential_copy (kim_credential_t *out_credential,
+ kim_credential_t in_credential);
+
+/*!
+ * \param in_credential a credential object.
+ * \param in_krb5_context a krb5 context which will be used to create \a out_krb5_creds.
+ * \param out_krb5_creds on exit, a new krb5 creds object which is a copy of \a in_credential.
+ * Must be freed with krb5_free_creds().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get a krb5 credentials object for a credential object.
+ */
+kim_error_t kim_credential_get_krb5_creds (kim_credential_t in_credential,
+ krb5_context in_krb5_context,
+ krb5_creds **out_krb5_creds);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_client_identity on exit, an identity object containing the client identity of
+ * \a in_credential. Must be freed with kim_identity_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the client identity of a credential object.
+ */
+kim_error_t kim_credential_get_client_identity (kim_credential_t in_credential,
+ kim_identity_t *out_client_identity);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_service_identity on exit, an identity object containing the service identity of
+ * \a in_credential. Must be freed with kim_identity_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the service identity of a credential object.
+ */
+kim_error_t kim_credential_get_service_identity (kim_credential_t in_credential,
+ kim_identity_t *out_service_identity);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_is_tgt on exit, whether or not the credential is a TGT.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Check if a credential is a ticket granting ticket.
+ */
+kim_error_t kim_credential_is_tgt (kim_credential_t in_credential,
+ kim_boolean_t *out_is_tgt);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_state on exit, the state of the credential. See #kim_credential_state_enum
+ * for the possible values of \a out_state.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Check the state of a credential (valid, expired, postdated, etc).
+ */
+kim_error_t kim_credential_get_state (kim_credential_t in_credential,
+ kim_credential_state_t *out_state);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_start_time on exit, the time when \a in_credential becomes valid.
+ * May be in the past or future.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the time when the credentials become valid.
+ * \sa kim_ccache_get_start_time
+ */
+kim_error_t kim_credential_get_start_time (kim_credential_t in_credential,
+ kim_time_t *out_start_time);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_expiration_time on exit, the time when \a in_credential will expire.
+ * May be in the past or future.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the time when the credentials will expire.
+ * \sa kim_ccache_get_expiration_time
+ */
+kim_error_t kim_credential_get_expiration_time (kim_credential_t in_credential,
+ kim_time_t *out_expiration_time);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_renewal_expiration_time on exit, the time when \a in_credential will no longer
+ * be renewable. May be in the past or future.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the time when the credentials will no longer be renewable.
+ * \sa kim_ccache_get_renewal_expiration_time
+ */
+kim_error_t kim_credential_get_renewal_expiration_time (kim_credential_t in_credential,
+ kim_time_t *out_renewal_expiration_time);
+
+
+/*!
+ * \param in_credential a credential object.
+ * \param in_client_identity a client identity.
+ * \param out_ccache on exit, a ccache object containing \a in_credential with the client
+ * identity \a in_client_identity. Must be freed with kim_ccache_free().
+ * Specify NULL if you don't want this return value.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Store a credential in a ccache in the cache collection.
+ */
+kim_error_t kim_credential_store (kim_credential_t in_credential,
+ kim_identity_t in_client_identity,
+ kim_ccache_t *out_ccache);
+
+/*!
+ * \param in_credential a TGT credential to be verified.
+ * \param in_service_identity a service identity to look for in the keytab. Specify
+ * KIM_IDENTITY_ANY to use the default service identity
+ * (usually host/<host's FQDN>@<host's local realm>).
+ * \param in_keytab a path to a keytab. Specify NULL for the default keytab location.
+ * \param in_fail_if_no_service_key whether or not the absence of a key for \a in_service_identity
+ * in the host's keytab will cause a failure.
+ * \note specifying FALSE for \a in_fail_if_no_service_key may expose the calling program to
+ * the Zanarotti attack if the host has no keytab installed.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Verify a TGT credential.
+ * \sa kim_ccache_verify
+ */
+kim_error_t kim_credential_verify (kim_credential_t in_credential,
+ kim_identity_t in_service_identity,
+ kim_string_t in_keytab,
+ kim_boolean_t in_fail_if_no_service_key);
+
+/*!
+ * \param io_credential a TGT credential to be renewed. On exit, the old credential
+ * object will be freed and \a io_credential will be replaced
+ * with a new renewed credential. The new credential must be freed
+ * with kim_credential_free().
+ * \param in_options initial credential options.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Renew a TGT credential.
+ * \sa kim_ccache_renew
+ */
+kim_error_t kim_credential_renew (kim_credential_t *io_credential,
+ kim_options_t in_options);
+
+/*!
+ * \param io_credential a credential object to be validated. On exit, the old credential
+ * object will be freed and \a io_credential will be replaced
+ * with a new validated credential. The new credential must be freed
+ * with kim_credential_free().
+ * \param in_options initial credential options.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Validate a TGT credential.
+ * \sa kim_ccache_validate
+ */
+kim_error_t kim_credential_validate (kim_credential_t *io_credential,
+ kim_options_t in_options);
+
+/*!
+ * \param io_credential the credential object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with a credential object.
+ */
+void kim_credential_free (kim_credential_t *io_credential);
+
+/*!@}*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_CREDENTIAL_H */
diff --git a/src/include/kim/kim_error.h b/src/include/kim/kim_error.h
new file mode 100644
index 0000000..8a6a4d5
--- /dev/null
+++ b/src/include/kim/kim_error.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_ERROR_H
+#define KIM_ERROR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kim/kim_types.h>
+#include <kim/kim_error_code.h>
+
+/*!
+ * \ingroup kim_types_reference
+ * The kim_error_t returned when no error occurred.
+ * Does not need to be freed with kim_error_free().
+ */
+#define KIM_NO_ERROR ((kim_error_t) NULL)
+
+/*!
+ * \ingroup kim_types_reference
+ * The kim_error_code_t for KIM_NO_ERROR.
+ */
+#define KIM_NO_ERROR_ECODE ((kim_error_code_t) 0)
+
+/*!
+ * \page kim_error_overview KIM Error Overview
+ *
+ * An error object. Error objects consist of a machine readable error code for
+ * for programmatic error handling and a string describing the error. All KIM APIs
+ * return kim_errors with the exception of memory deallocation functions and the
+ * kim_error_t APIs which return pieces of a kim_error_t object.
+ *
+ * Functions which return successfully will return #KIM_NO_ERROR (NULL). Because
+ * #KIM_NO_ERROR does not need to be freed, you may use if-ladders or goto-style
+ * error handling when calling the KIM APIs. In addition, kim_error_free() may
+ * be called on #KIM_NO_ERROR.
+ *
+ * \note Certain kim_error_t objects are preallocated by the libraries avoid
+ * exacerbating existing problems while trying to report an error. For example,
+ * the out of memory error object is preallocated. It is safe to call
+ * #kim_error_free() on these errors, although the function may not actually free
+ * the object.
+ *
+ * By providing an error object rather than a numeric code, the KIM APIs can
+ * tailor error strings to the circumstances of the error. So rather than returning
+ * error strings like "Client not found in Kerberos database", we can report
+ * "'user@REALM' not found in Kerberos database" while still providing the machine
+ * readable error KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
+ *
+ * See \ref kim_error_reference for information on specific APIs.
+ */
+
+/*!
+ * \defgroup kim_error_reference KIM Error Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_error on exit, a new error object which is a copy of \a in_error.
+ * Must be freed with kim_error_free().
+ * \param in_error the error to copy.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy an error.
+ */
+kim_error_t kim_error_copy (kim_error_t *out_error,
+ kim_error_t in_error);
+
+/*!
+ * \param in_error an error object.
+ * \return On success, a machine-readable error code describing the error represented
+ * by \a in_error. On failure, #KIM_PARAMETER_ECODE.
+ * \brief Get a numerical error code for an error.
+ */
+kim_error_code_t kim_error_get_code (kim_error_t in_error);
+
+/*!
+ * \param in_error an error object.
+ * \return On success, a human-readable error string describing the error represented
+ * by \a in_error. On failure, NULL, indicating that the kim_error_t object was
+ * invalid.
+ * \brief Get a text description of an error.
+ */
+kim_string_t kim_error_get_display_string (kim_error_t in_error);
+
+/*!
+ * \param io_error the error object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with an error.
+ */
+void kim_error_free (kim_error_t *io_error);
+
+/*!@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_ERROR_H */
diff --git a/src/include/kim/kim_identity.h b/src/include/kim/kim_identity.h
new file mode 100644
index 0000000..9ee7fc0
--- /dev/null
+++ b/src/include/kim/kim_identity.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_IDENTITY_H
+#define KIM_IDENTITY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kim/kim_types.h>
+#include <krb5.h>
+#include <gssapi/gssapi.h>
+
+/*!
+ * \ingroup kim_types_reference
+ * Constant to specify any Kerberos identity is acceptable.
+ */
+#define KIM_IDENTITY_ANY ((kim_identity_t) NULL)
+
+/*!
+ * \page kim_identity_overview KIM Identity Overview
+ *
+ * \section kim_identity_introduction Introduction
+ *
+ * Identities in Kerberos are named by "principals". These identies may be people (users)
+ * or services (a server running on a host). When Kerberos issues credentials which
+ * authenticate one identity to another, the identity being authenticated is called
+ * the "client identity" and the identity being authenticated to is called the
+ * "service identity".
+ *
+ * Kerberos identities are made up of one or more components, as well as the Kerberos realm
+ * the entity belongs to. For client identities the first component is usually the client
+ * username (eg: "jdoe"). For service identities the first component is the name of the
+ * service (eg: "imap").
+ *
+ * Kerberos identities have both a binary (opaque) representation and also a string
+ * representation. The string representation consists of the components separated by '/'
+ * followed by an '@' and then the realm. For example, the identity "jdoe/admin@EXAMPLE.COM"
+ * represents John Doe's administrator identity at the realm EXAMPLE.COM. Note that
+ * identity components may contain both '/' and '@' characters. When building a
+ * identity from its string representation these syntactic characters must be escaped
+ * with '\'.
+ *
+ *
+ * \section kim_identity_create_display Creating and Displaying Identities
+ *
+ * KIM Identities can be generated from components, their escaped string representation
+ * or from a krb5_principal. Once you have a KIM identity object, you can also get
+ * the component, string or krb5_principal representations back out:
+ *
+ * \li #kim_identity_create_from_components() creates an identity object from a list of components.
+ * \li #kim_identity_get_number_of_components() returns the number of components in an identity object.
+ * \li #kim_identity_get_component_at_index() return a component of an identity object.
+ * \li #kim_identity_get_realm() returns the identity's realm.
+ *
+ * \li #kim_identity_create_from_string() generates an identity object from an escaped string representation.
+ * \li #kim_identity_get_string() returns the identity's escaped string representation.
+ * \li #kim_identity_get_display_string() returns a non-escaped string for display to the user.
+ * This string cannot be passed into #kim_identity_create_from_string().
+ *
+ * \li #kim_identity_create_from_krb5_principal() generates an identity object from a krb5_principal object.
+ * \li #kim_identity_get_krb5_principal() returns a krb5_principal object for an identity object.
+ *
+ * \li #kim_identity_get_gss_name() returns a gss_name_t object for use with gss_acquire_cred().
+ *
+ * \note If you need to know if two identity objects refer to the same entity, use #kim_identity_compare().
+ *
+ *
+ * \section kim_identity_selection Choosing a Client Identity
+ *
+ * Unfortunately most of the time applications don't know what client identity to use.
+ * Users may have identities for multiple Kerberos realms, as well as multiple identities
+ * in a single realm (such as a user and administrator identity).
+ *
+ * To solve this problem, #kim_selection_hints_get_identity() takes information
+ * from the application in the form of a selection hints object and returns the best
+ * matching client identity, if one is available. See \ref kim_selection_hints_overview
+ * for more information.
+ *
+ *
+ * \section kim_identity_password Changing a Identity's Password
+ *
+ * Many Kerberos sites use passwords for user accounts. Because passwords may be
+ * stolen or compromised, they must be frequently changed. KIM provides APIs to
+ * change the identity's password directly, and also handles changing the identity's
+ * password when it has expired.
+ *
+ * #kim_identity_change_password() presents a user interface to obtain the old and
+ * new passwords from the user. #kim_identity_change_password_with_passwords() takes
+ * the old and new passwords as input, but may still present a user interface if it
+ * needs to obtain additional information to authenticate.
+ *
+ * \note Not all identities have a password. Some sites use certificates (pkinit)
+ * and in the future there may be other authentication mechanisms (eg: smart cards).
+ *
+ * See \ref kim_identity_reference for information on specific APIs.
+ */
+
+/*!
+ * \defgroup kim_identity_reference KIM Identity Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_identity on exit, a new identity object. Must be freed with kim_identity_free().
+ * \param in_string a string representation of a Kerberos identity.
+ * Special characters such as '/' and '@' must be escaped with '\'.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Create a identity from a string.
+ */
+kim_error_t kim_identity_create_from_string (kim_identity_t *out_identity,
+ kim_string_t in_string);
+
+/*!
+ * \param out_identity on exit, a new identity object. Must be freed with kim_identity_free().
+ * \param in_realm a string representation of a Kerberos realm.
+ * \param in_1st_component a string representing the first component of the identity.
+ * \param ... zero or more strings of type kim_string_t representing additional components
+ * of the identity followed by a terminating NULL. Components will be assembled in
+ * order (ie: the 4th argument to kim_identity_create_from_components() will be
+ * the 2nd component of the identity).
+ * \note The last argument must be a NULL or kim_identity_create_from_components() may crash.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Create a identity from a realm and component strings.
+ */
+kim_error_t kim_identity_create_from_components (kim_identity_t *out_identity,
+ kim_string_t in_realm,
+ kim_string_t in_1st_component,
+ ...);
+
+/*!
+ * \param out_identity on exit, a new identity object which is a copy of \a in_krb5_principal.
+ * Must be freed with kim_identity_free().
+ * \param in_krb5_context the krb5 context used to create \a in_krb5_principal.
+ * \param in_krb5_principal a krb5 principal object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Create an identity object from a krb5_principal.
+ */
+kim_error_t kim_identity_create_from_krb5_principal (kim_identity_t *out_identity,
+ krb5_context in_krb5_context,
+ krb5_principal in_krb5_principal);
+
+/*!
+ * \param out_identity on exit, a new identity object which is a copy of \a in_identity.
+ * Must be freed with kim_identity_free().
+ * \param in_identity an identity object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy an identity object.
+ */
+kim_error_t kim_identity_copy (kim_identity_t *out_identity,
+ kim_identity_t in_identity);
+
+
+/*!
+ * \param in_identity an identity object.
+ * \param in_compare_to_identity an identity object.
+ * \param out_comparison on exit, a comparison of \a in_identity and
+ * \a in_compare_to_identity which determines whether
+ * or not the two identities are equivalent and their
+ * sort order (for display to the user) if they are not.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Compare identity objects for equivalency.
+ */
+kim_error_t kim_identity_compare (kim_identity_t in_identity,
+ kim_identity_t in_compare_to_identity,
+ kim_comparison_t *out_comparison);
+/*!
+ * \param in_identity an identity object.
+ * \param out_string on exit, a string representation of \a in_identity.
+ * Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the string representation of a identity.
+ * \note Special characters such as '@' and '/' will be escaped with '\'.
+ */
+kim_error_t kim_identity_get_string (kim_identity_t in_identity,
+ kim_string_t *out_string);
+
+
+/*!
+ * \param in_identity an identity object.
+ * \param out_display_string on exit, a string representation of \a in_identity appropriate for
+ * display to the user. Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get a human-readable string representation of an identity.
+ * \note Special characters such as '/' and '@' are \em not escaped with '\'. As a result the
+ * string returned from this function cannot be used with kim_identity_create_from_string()
+ * because it does not uniquely specify a principal.
+ * The result of this function should \em only be used to display to the user.
+ */
+kim_error_t kim_identity_get_display_string (kim_identity_t in_identity,
+ kim_string_t *out_display_string);
+
+/*!
+ * \param in_identity an identity object.
+ * \param out_realm_string on exit, a string representation of \a in_identity's realm.
+ * Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the realm string of an identity.
+ */
+kim_error_t kim_identity_get_realm (kim_identity_t in_identity,
+ kim_string_t *out_realm_string);
+
+/*!
+ * \param in_identity an identity object.
+ * \param out_number_of_components on exit the number of components in \a in_identity.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the number of components of an identity.
+ */
+kim_error_t kim_identity_get_number_of_components (kim_identity_t in_identity,
+ kim_count_t *out_number_of_components);
+
+/*!
+ * \param in_identity an identity object.
+ * \param in_index the index of the desired component. Component indexes start at 0.
+ * \param out_component_string on exit, a string representation of the component in \a in_identity
+ * specified by \a in_index. Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the Nth component of an identity.
+ */
+kim_error_t kim_identity_get_component_at_index (kim_identity_t in_identity,
+ kim_count_t in_index,
+ kim_string_t *out_component_string);
+
+/*!
+ * \param in_identity an identity object.
+ * \param in_krb5_context a krb5 context object.
+ * \param out_krb5_principal on exit, a krb5_principal representation of \a in_identity
+ * allocated with \a in_krb5_context. Must be freed with
+ * krb5_free_principal() using \a in_krb5_context.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the krb5_principal representation of an identity.
+ */
+kim_error_t kim_identity_get_krb5_principal (kim_identity_t in_identity,
+ krb5_context in_krb5_context,
+ krb5_principal *out_krb5_principal);
+
+/*!
+ * \param in_identity an identity object.
+ * \param out_gss_name on exit, a gss_name_t representation of \a in_identity.
+ * Must be freed with gss_release_name().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the gss_name_t representation of an identity.
+ */
+kim_error_t kim_identity_get_gss_name (kim_identity_t in_identity,
+ gss_name_t *out_gss_name);
+
+/*!
+ * \param in_identity an identity object whose password will be changed.
+ * \param in_options initial credential options to be used if a new credential is obtained.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Change the password for an identity.
+ * \note kim_identity_change_password() will acquire a temporary credential to change
+ * the password. It uses the \a in_options structure to obtain information about the desired
+ * prompter and current password.
+ */
+kim_error_t kim_identity_change_password (kim_identity_t in_identity,
+ kim_options_t in_options);
+
+/*!
+ * \param in_identity an identity object whose password will be changed.
+ * \param in_options initial credential options to be used if a new credential is obtained.
+ * \param in_new_password a string representation of the identity's new password.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Change the password for an identity to a caller-provided new password.
+ * \note kim_identity_change_password_with_passwords() will acquire a temporary credential
+ * to change the password. It uses the \a in_options structure to obtain information about
+ * the desired prompter and current password.
+ */
+kim_error_t kim_identity_change_password_to_password (kim_identity_t in_identity,
+ kim_options_t in_options,
+ kim_string_t in_new_password);
+
+/*!
+ * \param io_identity the identity object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with an identity.
+ */
+void kim_identity_free (kim_identity_t *io_identity);
+
+/*!@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_IDENTITY_H */
diff --git a/src/include/kim/kim_options.h b/src/include/kim/kim_options.h
new file mode 100644
index 0000000..ebdb791
--- /dev/null
+++ b/src/include/kim/kim_options.h
@@ -0,0 +1,637 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_OPTIONS_H
+#define KIM_OPTIONS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kim/kim_types.h>
+
+/*!
+ * \addtogroup kim_types_reference
+ * @{
+ */
+
+/*!
+ * Specifies the user's default options.
+ */
+#define KIM_OPTIONS_DEFAULT ((kim_options_t) NULL)
+
+/*!
+ * Specifies that credentials should be valid immediately.
+ */
+#define KIM_OPTIONS_START_IMMEDIATELY ((kim_time_t) 0)
+
+/*!
+ * The type of prompt which needs to be displayed.
+ * This value determines what type of user interface is displayed.
+ * See \ref kim_options_custom_prompt_callback for more information.
+ */
+typedef uint32_t kim_prompt_type_t;
+
+enum kim_prompt_type_enum {
+ kim_prompt_type_password = 0,
+ kim_prompt_type_challenge = 1
+};
+
+/*!
+ * The prompt callback used to display a prompt to the user.
+ * See \ref kim_options_custom_prompt_callback for more information.
+ */
+typedef kim_error_code_t (*kim_prompt_callback_t) (kim_options_t *io_options,
+ kim_prompt_type_t in_type,
+ kim_string_t in_title,
+ kim_string_t in_message,
+ kim_string_t in_description,
+ void **out_reply);
+
+/*!
+ * The default prompt callback.
+ * See \ref kim_options_custom_prompt_callback for more information.
+ */
+kim_error_code_t kim_prompt_callback_default (kim_options_t *io_options,
+ kim_prompt_type_t in_type,
+ kim_string_t in_title,
+ kim_string_t in_message,
+ kim_string_t in_description,
+ void **out_reply);
+
+/*!
+ * The graphical prompt callback.
+ * See \ref kim_options_custom_prompt_callback for more information.
+ */
+kim_error_code_t kim_prompt_callback_gui (kim_options_t *io_options,
+ kim_prompt_type_t in_type,
+ kim_string_t in_title,
+ kim_string_t in_message,
+ kim_string_t in_description,
+ void **out_reply);
+
+/*!
+ * The command line prompt callback.
+ * See \ref kim_options_custom_prompt_callback for more information.
+ */
+kim_error_code_t kim_prompt_callback_cli (kim_options_t *io_options,
+ kim_prompt_type_t in_type,
+ kim_string_t in_title,
+ kim_string_t in_message,
+ kim_string_t in_description,
+ void **out_reply);
+
+/*!
+ * The prompt callback which always returns an error.
+ * Use to turn off prompting entirely.
+ * \note Using this callback may prevent the user from authenicating.
+ * See \ref kim_options_custom_prompt_callback for more information.
+ */
+kim_error_code_t kim_prompt_callback_none (kim_options_t *io_options,
+ kim_prompt_type_t in_type,
+ kim_string_t in_title,
+ kim_string_t in_message,
+ kim_string_t in_description,
+ void **out_reply);
+
+/*! @} */
+
+/*!
+ * \page kim_options_overview KIM Options Overview
+ *
+ * \section kim_options_introduction Introduction
+ *
+ * Kerberos Identity Management Options (kim_options_t) allows you to control how
+ * the Kerberos library obtains credentials. When the options structure is initialized with
+ * #kim_options_create(), each option is filled in with a default value which can then be modified
+ * with the kim_options_set_*() APIs. If you only want to use the default values, you may pass
+ * #KIM_OPTIONS_DEFAULT into any KIM function that takes a kim_options_t.
+ *
+ * KIM options fall into two major categories: options for controlling how credentials are
+ * acquired and options for controlling what properties the newly acquired credentials will have:
+ *
+ * \section kim_options_credential_acquisition Options for Controlling Credential Acquisition
+ *
+ * In order to acquire credentials, Kerberos needs to obtain one or more secrets from the user.
+ * These secrets may be a certificate, password, SecurID pin, or information from a smart card.
+ * If obtaining the secret requires interaction with the user, the Kerberos libraries call a
+ * "prompter callback" to display a dialog or command line prompt to request information from
+ * the user. If you want to provide your own custom dialogs or command line prompts,
+ * the KIM APIs provide a mechanism for replacing the default prompt callbacks with your own.
+ *
+ * \subsection kim_options_custom_prompt_callback Providing a Custom Prompt Callback
+ *
+ * All secrets are obtained from the user through a #kim_prompt_callback_t. By default,
+ * options use #kim_prompt_callback_default, which presents an expanding dialog to request
+ * information from the user, or if no graphical access is available, a command line prompt.
+ *
+ * KIM also provides three other callbacks: #kim_prompt_callback_gui only presents
+ * a dialog and returns an error if there is no graphical access. #kim_prompt_callback_cli
+ * only presents a command line interface and returns an error if there is no controlling
+ * terminal available. #kim_prompt_callback_none always returns an error.
+ *
+ * Using #kim_options_set_prompt_callback(), you can change the prompt callback to one of
+ * the above callbacks or a callback you have defined yourself. Callbacks are called in a
+ * loop, one for each prompt. Because network traffic may occur between calls to the prompt
+ * callback, your prompt interface should support time passing between calls to the prompter.
+ * If you are defining a callback yourself, you should also set your own options data with
+ * #kim_options_set_data() for storing state between calls. Options data is a caller
+ * defined pointer value -- the Kerberos libaries make no use of it.
+ *
+ * \subsection kim_options_preset_prompts Prefetching Prompt Responses
+ *
+ * Sometimes you may have already collected some of the information needed to acquire
+ * Kerberos credentials. Rather than creating a prompt callback, you may also prefetch
+ * responses to the options directly with #kim_options_set_prompt_response(). Once you
+ * have associated your response with a given prompt type, the Kerberos libraries will
+ * use this response for the first prompt of that type rather than calling the prompt
+ * callback to obtain it.
+ *
+ * Note that even if you prefetch responses, the prompt callback may still be called if
+ * you did not provide all the information required for the identity. You may specify
+ * the #kim_prompt_callback_none prompt callback to prevent prompting from occuring entirely,
+ * however, doing so will tie your application to a particular Kerberos configuration.
+ * For example, if your application assumes that all identities only require a password,
+ * it will not be able to acquire credentials at sites using SecurID pins.
+ *
+ *
+ * \section kim_options_credential_properties Options for Controlling Credential Properties
+ *
+ * Kerberos credentials have a number of different properties which can be requested
+ * when credentials are acquired. These properties control when and for how long the
+ * credentials are valid and what you can do with them.
+
+ * Note that setting these properties in the KIM options only changes what the Kerberos
+ * libraries \em request from the KDC. The KDC itself may choose not to honor your
+ * requested properties if they violate the site security policy. For example, most sites
+ * place an upper bound on how long credentials may be valid. If you request a credential
+ * lifetime longer than this upper bound, the KDC may return credentials with a shorter
+ * lifetime than you requested.
+ *
+ * \subsection kim_options_lifetimes Credential Lifetime
+ *
+ * Kerberos credentials have start time and a lifetime during which they are valid.
+ * Once the lifetime has passed, credentials "expire" and can no longer be used.
+ *
+ * The requested credential start time can be set with #kim_options_set_start_time()
+ * and examined with #kim_options_get_start_time(). The requested credential
+ * lifetime can be set with #kim_options_set_lifetime() and examined with
+ * #kim_options_get_lifetime().
+ *
+ * \subsection kim_options_renewable Renewable Credentials
+ *
+ * Credentials with very long lifetimes are more convenient since the user does not
+ * have authenticate as often. Unfortunately they are also a higher security
+ * risk: if credentials are stolen they can be used until they expire.
+ * Credential renewal exists to compromise between these two conflicting goals.
+ *
+ * Renewable credentials are TGT credentials which can be used to obtain new
+ * TGT credentials without reauthenticating. By regularly renewing credentials
+ * the KDC has an opportunity to check to see if the client's credentials have been
+ * reported stolen and refuse to renew them. Renewable credentials have a "renewal
+ * lifetime" during which credentials can be renewed. This lifetime is relative
+ * to the original credential start time. If credentials are renewed shortly before
+ * the end of the renewal lifetime, their lifetime will be capped to the end of the
+ * renewal lifetime.
+ *
+ * Note that credentials must be valid to be renewed and therefore may not be
+ * an appropriate solution for all use cases. Sites which use renewable
+ * credentials often create helper processes running as the user which will
+ * automatically renew the user's credentials when they get close to expiration.
+ *
+ * Use #kim_options_set_renewable() to change whether or not the Kerberos libraries
+ * request renewable credentials and #kim_options_get_renewable() to find out the
+ * current setting. Use #kim_options_set_renewal_lifetime() to change the requested
+ * renewal lifetime and #kim_options_get_renewal_lifetime() to find out the current
+ * value.
+ *
+ * \subsection kim_options_addressless Addressless Credentials
+ *
+ * Traditionally Kerberos used the host's IP address as a mechanism to restrict
+ * the user's credentials to a specific host, thus making it harder to use stolen
+ * credentials. When authenticating to a remote service with credentials containing
+ * addresses, the remote service verifies that the client's IP address is one of the
+ * addresses listed in the credential. Unfortunately, modern network technologies
+ * such as NAT rewrite the IP address in transit, making it difficult to use
+ * credentials with addresses in them. As a result, most Kerberos sites now obtain
+ * addressless credentials.
+ *
+ * Use #kim_options_set_addressless() to change whether or not the Kerberos libraries
+ * request addressless credentials. Use #kim_options_get_addressless() to find out the
+ * current setting.
+ *
+ * \subsection kim_options_forwardable Forwardable Credentials
+ *
+ * Forwardable credentials are TGT credentials which can be forwarded to a service
+ * you have authenticated to. If the credentials contain IP addresses, the addresses
+ * are changed to reflect the service's IP address. Credential forwarding is most
+ * commonly used for Kerberos-authenticated remote login services. By forwarding
+ * TGT credentials through the remote login service, the user's credentials will
+ * appear on the remote host when the user logs in.
+ *
+ * The forwardable flag only applies to TGT credentials.
+ *
+ * Use #kim_options_set_forwardable() to change whether or not the Kerberos libraries
+ * request forwardable credentials. Use #kim_options_get_forwardable() to find out the
+ * current setting.
+ *
+ * \subsection kim_options_proxiable Proxiable Credentials
+ *
+ * Proxiable credentials are similar to forwardable credentials except that instead of
+ * forwarding the a TGT credential itself, a service credential is forwarded
+ * instead. Using proxiable credentials, a user can permit a service to perform
+ * a specific task as the user using one of the user's service credentials.
+ *
+ * Like forwardability, the proxiable flag only applies to TGT credentials. Unlike
+ * forwarded credentials, the IP address of proxiable credentials are not modified for
+ * the service when being proxied. This can be solved by also requesting addressless
+ * credentials.
+ *
+ * Use #kim_options_set_proxiable() to change whether or not the Kerberos libraries
+ * request proxiable credentials. Use #kim_options_get_proxiable() to find out the
+ * current setting.
+ *
+ * \subsection kim_options_service_name Service Name
+ *
+ * Normally users acquire TGT credentials (ie "ticket granting tickets") and then
+ * use those credentials to acquire service credentials. This allows Kerberos to
+ * provide single sign-on while still providing mutual authentication to services.
+ * However, sometimes you just want an initial credential for a service. KIM
+ * options allows you to set the service name with
+ * #kim_options_set_service_name() and query it with
+ * #kim_options_get_service_name().
+ *
+ * See \ref kim_options_reference for information on specific APIs.
+ */
+
+/*!
+ * \defgroup kim_options_reference KIM Options Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_options on exit, a new options object. Must be freed with kim_options_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Create new options with default values.
+ */
+kim_error_t kim_options_create (kim_options_t *out_options);
+
+/*!
+ * \param out_options on exit, a new options object which is a copy of \a in_options.
+ * Must be freed with kim_options_free().
+ * \param in_options a options object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy options.
+ */
+kim_error_t kim_options_copy (kim_options_t *out_options,
+ kim_options_t in_options);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_prompt_callback a prompt callback function.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the prompt callback for obtaining information from the user.
+ * \par Default value
+ * #kim_prompt_callback_default
+ * \sa kim_options_get_prompt_callback()
+ */
+kim_error_t kim_options_set_prompt_callback (kim_options_t io_options,
+ kim_prompt_callback_t in_prompt_callback);
+
+/*!
+ * \param in_options an options object.
+ * \param out_prompt_callback on exit, the prompt callback specified by in_options.
+ * Does not need to be freed but may become invalid when
+ * \a in_options is freed.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the prompt callback for obtaining information from the user.
+ * \par Default value
+ * #kim_prompt_callback_default
+ * \sa kim_options_set_prompt_callback()
+ */
+kim_error_t kim_options_get_prompt_callback (kim_options_t in_options,
+ kim_prompt_callback_t *out_prompt_callback);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_data a pointer to caller-specific data.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set caller-specific data for use in library callbacks.
+ * \note This option can be used by the caller to store a pointer to data needed when handling a
+ * callback. The KIM library does not use this options data in any way.
+ * \par Default value
+ * NULL (no data is set by default)
+ * \sa kim_options_get_data()
+ */
+kim_error_t kim_options_set_data (kim_options_t io_options,
+ const void *in_data);
+
+/*!
+ * \param in_options an options object.
+ * \param out_data on exit, the pointer to caller specific data specified by in_options.
+ * Does not need to be freed but may become invalid when \a in_options is freed.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get caller-specific data for use in library callbacks.
+ * \note This option can be used by the caller to store a pointer to data needed when handling a
+ * callback. The KIM library does not use this options data in any way.
+ * \par Default value
+ * NULL (no data is set by default)
+ * \sa kim_options_set_data()
+ */
+kim_error_t kim_options_get_data (kim_options_t in_options,
+ const void **out_data);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_prompt_type a type of prompt.
+ * \param in_response a response to prompts of \a in_prompt_type.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set a response for a prompt for use when acquiring credentials.
+ * \note Each response only overrides the first prompt of a given prompt type. If multiple
+ * prompts of the same type are required, or if a prompt of a different type is requested,
+ * the prompt callback will be called to obtain user input. If you want to turn off prompting
+ * entirely, call #kim_options_set_prompt_callback() with #kim_prompt_callback_none.
+ * \par Default value
+ * NULL (no response is set by default)
+ * \sa kim_options_get_prompt_response()
+ */
+kim_error_t kim_options_set_prompt_response (kim_options_t io_options,
+ kim_prompt_type_t in_prompt_type,
+ void *in_response);
+
+/*!
+ * \param in_options an options object.
+ * \param in_prompt_type a type of prompt.
+ * \param out_response on exit, the response to prompts of type \a in_prompt_type specified
+ * by \a in_options. Does not need to be freed but may become invalid
+ * when \a in_options is freed.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the response for a prompt for use when acquiring credentials.
+ * \note Each response only overrides the first prompt of a given prompt type. If multiple
+ * prompts of the same type are required, or if a prompt of a different type is requested,
+ * the prompt callback will be called to obtain user input. If you want to turn off prompting
+ * entirely, call #kim_options_set_prompt_callback() with #kim_prompt_callback_none.
+ * \par Default value
+ * NULL (no response is set by default)
+ * \sa kim_options_set_prompt_response()
+ */
+kim_error_t kim_options_get_prompt_response (kim_options_t in_options,
+ kim_prompt_type_t in_prompt_type,
+ void **out_response);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_start_time a start date (in seconds since January 1, 1970). Set to
+ * #KIM_OPTIONS_START_IMMEDIATELY for the acquired credential to be valid
+ * immediately.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the date when a credential should become valid.
+ * \note When using a start time in the future, once the start time has been reached the credential
+ * must be validated before it can be used.
+ * \par Default value
+ * 0, indicating "now". The credential will be valid immediately.
+ * \sa kim_options_get_start_time(), kim_credential_validate(), kim_ccache_validate(), kim_identity_validate()
+ */
+kim_error_t kim_options_set_start_time (kim_options_t io_options,
+ kim_time_t in_start_time);
+
+/*!
+ * \param in_options an options object.
+ * \param out_start_time on exit, the start date (in seconds since January 1, 1970) specified by
+ * \a in_options. #KIM_OPTIONS_START_IMMEDIATELY indicates the credential
+ * will be valid immediately.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the date when a credential should become valid.
+ * \note When using a start time in the future, once the start time has been reached the credential
+ * must be validated before it can be used.
+ * \par Default value
+ * 0, indicating "now". The credential will be valid immediately.
+ * \sa kim_options_set_start_time(), kim_credential_validate(), kim_ccache_validate(), kim_identity_validate()
+ */
+kim_error_t kim_options_get_start_time (kim_options_t in_options,
+ kim_time_t *out_start_time);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_lifetime a lifetime duration (in seconds).
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the duration during which a credential should be valid.
+ * \note KDCs have a maximum allowed lifetime per identity (usually 10 to 21 hours).
+ * As a result the credential will actually have a lifetime which is the minimum of
+ * \a in_lifetime and the KDC's maximum allowed lifetime.
+ * \sa kim_options_get_lifetime()
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. 10 hours if unspecified.
+ */
+kim_error_t kim_options_set_lifetime (kim_options_t io_options,
+ kim_lifetime_t in_lifetime);
+
+/*!
+ * \param in_options an options object.
+ * \param out_lifetime on exit, the lifetime duration (in seconds) specified in \a in_options.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the duration during which an acquired credential should be valid.
+ * \note KDCs have a maximum allowed lifetime per identity (usually 10 to 21 hours).
+ * As a result the credential will actually have a lifetime which is the minimum of
+ * \a in_lifetime and the KDC's maximum allowed lifetime.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. 10 hours if unspecified.
+ * \sa kim_options_set_lifetime()
+ */
+kim_error_t kim_options_get_lifetime (kim_options_t in_options,
+ kim_lifetime_t *out_lifetime);
+
+/*!
+* \param io_options an options object to modify.
+ * \param in_renewable a boolean value indicating whether or not to request a renewable
+ * credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set whether or not to request a renewable credential.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. TRUE if unspecified.
+ * \sa kim_options_get_renewable()
+ */
+kim_error_t kim_options_set_renewable (kim_options_t io_options,
+ kim_boolean_t in_renewable);
+
+/*!
+* \param in_options an options object.
+ * \param out_renewable on exit, a boolean value indicating whether or \a in_options will
+ * request a renewable credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get whether or not to request a renewable credential.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. TRUE if unspecified.
+ * \sa kim_options_set_renewable()
+ */
+kim_error_t kim_options_get_renewable (kim_options_t in_options,
+ kim_boolean_t *out_renewable);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_renewal_lifetime a renewal lifetime duration (in seconds).
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the duration during which a valid credential should be renewable.
+ * \note KDCs have a maximum allowed renewal lifetime per identity (usually 10 to 21 hours).
+ * As a result the credential will actually have a lifetime which is the minimum of
+ * \a in_lifetime and the KDC's maximum allowed lifetime.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. 7 days if unspecified.
+ * \sa kim_options_get_renewal_lifetime(), kim_identity_renew(), kim_credential_renew(), kim_ccache_renew()
+ */
+kim_error_t kim_options_set_renewal_lifetime (kim_options_t io_options,
+ kim_lifetime_t in_renewal_lifetime);
+
+/*!
+ * \param in_options an options object.
+ * \param out_renewal_lifetime on exit, the renewal lifetime duration (in seconds) specified
+ * in \a in_options.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the duration during which a valid credential should be renewable.
+ * \note KDCs have a maximum allowed lifetime per identity (usually 10 to 21 hours).
+ * As a result the credential will actually have a lifetime which is the minimum of
+ * \a in_lifetime and the KDC's maximum allowed lifetime.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. 7 days if unspecified.
+ * \sa kim_options_set_renewal_lifetime(), kim_identity_renew(), kim_credential_renew(), kim_ccache_renew()
+ */
+kim_error_t kim_options_get_renewal_lifetime (kim_options_t in_options,
+ kim_lifetime_t *out_renewal_lifetime);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_forwardable a boolean value indicating whether or not to request a forwardable
+ * credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set whether or not to request a forwardable credential.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. TRUE if unspecified.
+ * \sa kim_options_get_forwardable()
+ */
+kim_error_t kim_options_set_forwardable (kim_options_t io_options,
+ kim_boolean_t in_forwardable);
+
+/*!
+ * \param in_options an options object.
+ * \param out_forwardable on exit, a boolean value indicating whether or \a in_options will
+ * request a forwardable credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get whether or not to request a forwardable credential.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. TRUE if unspecified.
+ * \sa kim_options_set_forwardable()
+ */
+kim_error_t kim_options_get_forwardable (kim_options_t in_options,
+ kim_boolean_t *out_forwardable);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_proxiable a boolean value indicating whether or not to request a proxiable
+ * credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set whether or not to request a proxiable credential.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. TRUE if unspecified.
+ * \sa kim_options_get_proxiable()
+ */
+kim_error_t kim_options_set_proxiable (kim_options_t io_options,
+ kim_boolean_t in_proxiable);
+
+/*!
+ * \param in_options an options object.
+ * \param out_proxiable on exit, a boolean value indicating whether or \a in_options will
+ * request a proxiable credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get whether or not to request a proxiable credential.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. TRUE if unspecified.
+ * \sa kim_options_set_proxiable()
+ */
+kim_error_t kim_options_get_proxiable (kim_options_t in_options,
+ kim_boolean_t *out_proxiable);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_addressless a boolean value indicating whether or not to request an addressless
+ * credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set whether or not to request an addressless credential.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. TRUE if unspecified.
+ * \sa kim_options_get_addressless()
+ */
+kim_error_t kim_options_set_addressless (kim_options_t io_options,
+ kim_boolean_t in_addressless);
+
+/*!
+ * \param in_options an options object.
+ * \param out_addressless on exit, a boolean value indicating whether or \a in_options will
+ * request an addressless credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get whether or not to request an addressless credential.
+ * \par Default value
+ * Read from the user's preferences and the Kerberos configuration. TRUE if unspecified.
+ * \sa kim_options_set_addressless()
+ */
+kim_error_t kim_options_get_addressless (kim_options_t in_options,
+ kim_boolean_t *out_addressless);
+
+/*!
+ * \param io_options an options object to modify.
+ * \param in_service_name a service name.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the service name to request a credential for.
+ * \par Default value
+ * NULL, indicating "krbtgt@<REALM>", the ticket granting ticket (TGT) service.
+ * \sa kim_options_get_service_name()
+ */
+kim_error_t kim_options_set_service_name (kim_options_t io_options,
+ kim_string_t in_service_name);
+
+/*!
+ * \param in_options an options object.
+ * \param out_service_name on exit, the service name specified in \a in_options.
+ * Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the service name to request a credential for.
+ * \par Default value
+ * NULL, indicating "krbtgt@<REALM>", the ticket granting ticket (TGT) service.
+ * \sa kim_options_set_service_name()
+ */
+kim_error_t kim_options_get_service_name (kim_options_t in_options,
+ kim_string_t *out_service_name);
+
+/*!
+ * \param io_options the options object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with an options object.
+ */
+void kim_options_free (kim_options_t *io_options);
+
+/*!@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_OPTIONS_H */
diff --git a/src/include/kim/kim_preferences.h b/src/include/kim/kim_preferences.h
new file mode 100644
index 0000000..17ca351
--- /dev/null
+++ b/src/include/kim/kim_preferences.h
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_PREFERENCES_H
+#define KIM_PREFERENCES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kim/kim_types.h>
+
+/*!
+ * \page kim_favorite_identities_overview KIM Favorite Identities Overview
+ *
+ * \section kim_favorite_identities_introduction Introduction
+ *
+ * As Kerberos becomes more widespread, the number of possible Kerberos
+ * identities and realms a user might want to use will become very large.
+ * Sites may list hundreds of realms in their Kerberos configuration files.
+ * In addition, sites may wish to use DNS SRV records to avoid having to list
+ * all the realms they use in their Kerberos configuration. As a result, the
+ * list of realms in the Kerberos configuration may be exceedingly large and/or
+ * incomplete. Users may also use multiple identities from the same realm.
+ *
+ * On platforms which use a GUI to acquire credentials, the KIM would like
+ * to to display a list of identities for the user to select from. Depending on
+ * what is appropriate for the platform, identities may be displayed in a popup
+ * menu or other list.
+ *
+ * To solve this problem, the KIM maintains a list of favorite identities
+ * specifically for identity selection. This list is a set of unique identities
+ * in alphabetical order (as appropriate for the user's language localization).
+ *
+ * On most platforms the list of favorite identities has both an administrator
+ * preference and a user preference which overrides it. The administrator
+ * preference exists only to initialize the favorite identities for new user
+ * accounts. Once the user modifies the list their favorite identities may
+ * diverge from the site favorite identities preference.
+ *
+ * \note The location of user preferences and the semantics of
+ * preference synchronization is platform-specific. Where possible KIM will use
+ * platform-specific preference mechanisms.
+ *
+ * Most callers will not need to use the favorite identities APIs. However if you
+ * are implementing your own graphical prompt callback or a credential management
+ * application, you may to view and/or edit the user's favorite identities.
+ *
+ * \section kim_favorite_identities_edit Viewing and Editing the Favorite Identities
+ *
+ * First, you need to acquire the Favorite Identities stored in the user's
+ * preferences using #kim_preferences_create() and
+ * #kim_preferences_get_favorite_identities(). Or you can use
+ * #kim_favorite_identities_create() to get an empty identities list if you want to
+ * overwrite the user's identities list entirely. See \ref kim_preferences_overview
+ * for more information on modifying the user's preferences.
+ *
+ * Then use #kim_favorite_identities_get_number_of_identities() and
+ * #kim_favorite_identities_get_identity_at_index() to display the identities list.
+ * Use #kim_favorite_identities_add_identity() and #kim_favorite_identities_remove_identity()
+ * to change which identities are in the identities list. Identities are always stored in
+ * alphabetical order and duplicate identities are not permitted, so when you add or remove a
+ * identity you should redisplay the entire list.
+ *
+ * Once you are done editing the identities list, store changes in the user's preference file
+ * using #kim_preferences_set_favorite_identities() and #kim_preferences_synchronize().
+ *
+ * See \ref kim_favorite_identities_reference for information on specific APIs.
+ */
+
+/*!
+ * \defgroup kim_favorite_identities_reference KIM Favorite Identities Documentation
+ * @{
+ */
+
+/*!
+ * \param out_favorite_identities on exit, a new favorite identities object.
+ * Must be freed with kim_favorite_identities_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Create a new favorite identities list.
+ */
+kim_error_t kim_favorite_identities_create (kim_favorite_identities_t *out_favorite_identities);
+
+/*!
+ * \param out_favorite_identities on exit, a new favorite identities object which is
+ * a copy of in_favorite_identities.
+ * Must be freed with kim_favorite_identities_free().
+ * \param in_favorite_identities a favorite identities object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy a favorite identities list.
+ */
+kim_error_t kim_favorite_identities_copy (kim_favorite_identities_t *out_favorite_identities,
+ kim_favorite_identities_t in_favorite_identities);
+
+/*!
+ * \param in_favorite_identities a favorite identities object.
+ * \param out_number_of_identities on exit, the number of identities in \a in_favorite_identities.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the number of identities in a favorite identities list.
+ */
+kim_error_t kim_favorite_identities_get_number_of_identities (kim_favorite_identities_t in_favorite_identities,
+ kim_count_t *out_number_of_identities);
+
+/*!
+ * \param in_favorite_identities a favorite identities object.
+ * \param in_index a index into the identities list (starting at 0).
+ * \param out_realm on exit, the identity at \a in_index in \a in_favorite_identities.
+ * Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the Nth identity in a favorite identities list.
+ */
+kim_error_t kim_favorite_identities_get_identity_at_index (kim_favorite_identities_t in_favorite_identities,
+ kim_count_t in_index,
+ kim_identity_t *out_identity);
+/*!
+ * \param io_favorite_identities a favorite identities object.
+ * \param in_identity an identity string to add to \a in_favorite_identities.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Add an identity to a favorite identities list.
+ */
+kim_error_t kim_favorite_identities_add_identity (kim_favorite_identities_t io_favorite_identities,
+ kim_identity_t in_identity);
+
+/*!
+ * \param io_favorite_identities a favorite identities object.
+ * \param in_identity an identity to remove from \a in_favorite_identities.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Remove an identity from a identities list.
+ */
+kim_error_t kim_favorite_identities_remove_identity (kim_favorite_identities_t io_favorite_identities,
+ kim_identity_t in_identity);
+
+/*!
+ * \param io_favorite_identities a favorite identities object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Empty a favorite identities list.
+ */
+kim_error_t kim_favorite_identities_remove_all_identities (kim_favorite_identities_t io_favorite_identities);
+
+/*!
+ * \param io_favorite_identities the favorite identities object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with an identities list.
+ */
+
+void kim_favorite_identities_free (kim_favorite_identities_t *io_favorite_identities);
+
+/*!@}*/
+
+/*!
+ * \page kim_preferences_overview KIM Preferences Overview
+ *
+ * \section kim_preferences_introduction Introduction
+ *
+ * In addition to the site preferences stored in the Kerberos configuration, users may also
+ * want to have their own personal preferences for controlling credential acquisition.
+ * As a result, KIM provides user preferences for initial credential options and
+ * user interface behavior such as the default client identity and the favorite identities list.
+ *
+ * \section kim_preferences_edit Viewing and Editing the Preferences
+ *
+ * In order to view and edit the user's preferences, call #kim_preferences_create() to acquire a
+ * preferences object containing the user's preferences. You can examine preferences
+ * with the functions starting with "kim_preferences_get_" and change preferences with
+ * the functions starting with "kim_preferences_set_". Once you are done making changes,
+ * you can write changes back out to the user's preferences with #kim_preferences_synchronize().
+ *
+ * \note The location of user preferences and the semantics of
+ * preference synchronization is platform-specific. Where possible KIM will use
+ * platform-specific preference mechanisms.
+ *
+ * \section kim_preferences_options Initial Credential Options Preferences
+ *
+ * KIM provides user preferences for initial credential options. These
+ * are the options #kim_options_create() will use when creating a new KIM
+ * options object. They are also the options specified by KIM_OPTIONS_DEFAULT.
+ * You can view and edit the initial credential options using
+ * #kim_preferences_get_options() and #kim_preferences_set_options().
+ *
+ * \note Not all credential options in the kim_options_t object have corresponding
+ * user preferences. For example, the prompt callback function is not stored
+ * in the user preferences since it has no meaning outside of the current
+ * application. Some options which are not currently stored in the
+ * preferences may be stored there in the future.
+ *
+ * If you are implementing a user interface for credentials acquisition,
+ * you should be aware that KIM has a user preference to manage the initial
+ * credential options preferences. If the user successfully acquires credentials
+ * with non-default options and #kim_preferences_get_remember_options() is set
+ * to TRUE, you should store the options used to get credentials with
+ * #kim_preferences_set_options().
+ *
+ * \section kim_preferences_client_identity Client Identity Preferences
+ *
+ * KIM also provides user preferences for the default client identity.
+ * This identity is used whenever KIM needs to display a graphical dialog for
+ * credential acquisition but does not know what client identity to use.
+ * You can view and edit the default client identity using
+ * #kim_preferences_get_client_identity() and
+ * #kim_preferences_set_client_identity().
+ *
+ * If you are implementing a user interface for credentials acquisition,
+ * you should be aware that KIM has a user preference to manage
+ * the client identity preferences. If the user successfully acquires credentials
+ * with non-default options and #kim_preferences_get_remember_client_identity() is
+ * set to TRUE, you should store the client identity for which credentials were
+ * acquired using #kim_preferences_set_client_identity().
+ *
+ * \section kim_preferences_favorite_identities Favorite Identities Preferences
+ *
+ * When presenting a graphical interface for credential acquisition, KIM
+ * may need to display a list of identities for the user to select from.
+ * This list is generated by the user's favorite identities preference.
+ * You can view and edit the favorite identities preference using
+ * #kim_preferences_get_favorite_identities() and
+ * #kim_preferences_set_favorite_identities(). Please see the
+ * \ref kim_favorite_identities_overview for more information.
+ *
+ * See \ref kim_preferences_reference for information on specific APIs.
+ */
+
+/*!
+ * \defgroup kim_preferences_reference KIM Preferences Documentation
+ * @{
+ */
+
+/*!
+ * \param out_preferences on exit, a new preferences object.
+ * Must be freed with kim_preferences_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Create a new preferences object from the current user's preferences.
+ */
+kim_error_t kim_preferences_create (kim_preferences_t *out_preferences);
+
+/*!
+ * \param out_preferences on exit, a new preferences object which is a copy of in_preferences.
+ * Must be freed with kim_preferences_free().
+ * \param in_preferences a preferences object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy a preferences object.
+ */
+kim_error_t kim_preferences_copy (kim_preferences_t *out_preferences,
+ kim_preferences_t in_preferences);
+
+/*!
+ * \param io_preferences a preferences object to modify.
+ * \param in_options an options object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the user's preferred options.
+ * \sa kim_preferences_get_options()
+ */
+kim_error_t kim_preferences_set_options (kim_preferences_t io_preferences,
+ kim_options_t in_options);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \param out_options on exit, the options specified in \a in_preferences.
+ * Must be freed with kim_options_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the user's preferred options.
+ * \sa kim_preferences_set_options()
+ */
+kim_error_t kim_preferences_get_options (kim_preferences_t in_preferences,
+ kim_options_t *out_options);
+
+/*!
+ * \param io_preferences a preferences object to modify.
+ * \param in_remember_options a boolean value indicating whether or not to remember the last
+ * options used to acquire a credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set whether or not to remember the last options the user used to acquire a credential.
+ * \sa kim_preferences_get_remember_options()
+ */
+kim_error_t kim_preferences_set_remember_options (kim_preferences_t io_preferences,
+ kim_boolean_t in_remember_options);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \param out_remember_options on exit, a boolean value indicating whether or \a in_preferences will
+ * remember the last options used to acquire a credential.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get whether or not to remember the last options the user used to acquire a credential.
+ * \sa kim_preferences_set_remember_options()
+ */
+kim_error_t kim_preferences_get_remember_options (kim_preferences_t in_preferences,
+ kim_boolean_t *out_remember_options);
+
+/*!
+ * \param io_preferences a preferences object to modify.
+ * \param in_client_identity a client identity object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the user's preferred client identity.
+ * \sa kim_preferences_get_client_identity()
+ */
+kim_error_t kim_preferences_set_client_identity (kim_preferences_t io_preferences,
+ kim_identity_t in_client_identity);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \param out_client_identity on exit, the client identity specified in \a in_preferences.
+ * Must be freed with kim_identity_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the user's preferred client identity.
+ * \sa kim_preferences_set_client_identity()
+ */
+kim_error_t kim_preferences_get_client_identity (kim_preferences_t in_preferences,
+ kim_identity_t *out_client_identity);
+
+/*!
+ * \param io_preferences a preferences object to modify.
+ * \param in_remember_client_identity a boolean value indicating whether or not to remember the last
+ * client identity for which a credential was acquired.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set whether or not to remember the last client identity the user acquired a credential for.
+ * \sa kim_preferences_get_remember_client_identity()
+ */
+kim_error_t kim_preferences_set_remember_client_identity (kim_preferences_t io_preferences,
+ kim_boolean_t in_remember_client_identity);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \param out_remember_client_identity on exit, a boolean value indicating whether or \a in_preferences will
+ * remember the last client identity for which a credential was acquired.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get whether or not to remember the last client identity the user acquired a credential for.
+ * \sa kim_preferences_set_remember_client_identity()
+ */
+kim_error_t kim_preferences_get_remember_client_identity (kim_preferences_t in_preferences,
+ kim_boolean_t *out_remember_client_identity);
+
+/*!
+ * \param io_preferences a preferences object to modify.
+ * \param in_minimum_lifetime a minimum lifetime indicating how small a lifetime the
+ * GUI tools should allow the user to specify for credentials.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the minimum credential lifetime for GUI credential lifetime controls.
+ * \sa kim_preferences_get_minimum_lifetime()
+ */
+kim_error_t kim_preferences_set_minimum_lifetime (kim_preferences_t io_preferences,
+ kim_lifetime_t in_minimum_lifetime);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \param out_minimum_lifetime on exit, the minimum lifetime that GUI tools will
+ * allow the user to specify for credentials.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the minimum credential lifetime for GUI credential lifetime controls.
+ * \sa kim_preferences_set_minimum_lifetime()
+ */
+kim_error_t kim_preferences_get_minimum_lifetime (kim_preferences_t in_preferences,
+ kim_lifetime_t *out_minimum_lifetime);
+
+/*!
+ * \param io_preferences a preferences object to modify.
+ * \param in_maximum_lifetime a maximum lifetime indicating how large a lifetime the
+ * GUI tools should allow the user to specify for credentials.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the maximum credential lifetime for GUI credential lifetime controls.
+ * \sa kim_preferences_get_maximum_lifetime()
+ */
+kim_error_t kim_preferences_set_maximum_lifetime (kim_preferences_t io_preferences,
+ kim_lifetime_t in_maximum_lifetime);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \param out_maximum_lifetime on exit, the maximum lifetime that GUI tools will
+ * allow the user to specify for credentials.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the maximum credential lifetime for GUI credential lifetime controls.
+ * \sa kim_preferences_set_maximum_lifetime()
+ */
+kim_error_t kim_preferences_get_maximum_lifetime (kim_preferences_t in_preferences,
+ kim_lifetime_t *out_maximum_lifetime);
+
+/*!
+ * \param io_preferences a preferences object to modify.
+ * \param in_minimum_renewal_lifetime a minimum lifetime indicating how small a lifetime the
+ * GUI tools should allow the user to specify for
+ * credential renewal.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the minimum credential renewal lifetime for GUI credential lifetime controls.
+ * \sa kim_preferences_get_minimum_renewal_lifetime()
+ */
+kim_error_t kim_preferences_set_minimum_renewal_lifetime (kim_preferences_t io_preferences,
+ kim_lifetime_t in_minimum_renewal_lifetime);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \param out_minimum_renewal_lifetime on exit, the minimum lifetime that GUI tools will
+ * allow the user to specify for credential renewal.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the minimum credential renewal lifetime for GUI credential lifetime controls.
+ * \sa kim_preferences_set_minimum_renewal_lifetime()
+ */
+kim_error_t kim_preferences_get_minimum_renewal_lifetime (kim_preferences_t in_preferences,
+ kim_lifetime_t *out_minimum_renewal_lifetime);
+
+/*!
+ * \param io_preferences a preferences object to modify.
+ * \param in_maximum_renewal_lifetime a maximum lifetime indicating how large a lifetime the
+ * GUI tools should allow the user to specify for
+ * credential renewal.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the maximum credential renewal lifetime for GUI credential lifetime controls.
+ * \sa kim_preferences_get_minimum_renewal_lifetime()
+ */
+kim_error_t kim_preferences_set_maximum_renewal_lifetime (kim_preferences_t io_preferences,
+ kim_lifetime_t in_maximum_renewal_lifetime);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \param out_maximum_renewal_lifetime on exit, the maximum lifetime that GUI tools will
+ * allow the user to specify for credential renewal.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the maximum credential renewal lifetime for GUI credential lifetime controls.
+ * \sa kim_preferences_set_minimum_renewal_lifetime()
+ */
+kim_error_t kim_preferences_get_maximum_renewal_lifetime (kim_preferences_t in_preferences,
+ kim_lifetime_t *out_maximum_renewal_lifetime);
+
+/*!
+ * \param io_preferences a preferences object to modify.
+ * \param in_favorite_identities a favorite identities object.
+ * See \ref kim_favorite_identities_overview for more information on KIM
+ * Favorite Identities.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the user's preferred list of identities.
+ * \sa kim_preferences_get_favorite_identities()
+ */
+kim_error_t kim_preferences_set_favorite_identities (kim_preferences_t io_preferences,
+ kim_favorite_identities_t in_favorite_identities);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \param out_favorite_identities on exit, a copy of the favorite identities specified in \a in_preferences.
+ * See \ref kim_favorite_identities_overview for more information on KIM
+ * Favorite Identities. Must be freed with kim_favorite_identities_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the user's preferred list of identities.
+ * \sa kim_preferences_set_favorite_identities()
+ */
+kim_error_t kim_preferences_get_favorite_identities (kim_preferences_t in_preferences,
+ kim_favorite_identities_t *out_favorite_identities);
+
+/*!
+ * \param in_preferences a preferences object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Synchronize a preferences object with the user's preferences, writing pending changes
+ * and reading any changes applied by other processes.
+ */
+kim_error_t kim_preferences_synchronize (kim_preferences_t in_preferences);
+
+/*!
+ * \param io_preferences the preferences object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with a preferences object.
+ */
+void kim_preferences_free (kim_preferences_t *io_preferences);
+
+/*!@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_PREFERENCES_H */
diff --git a/src/include/kim/kim_selection_hints.h b/src/include/kim/kim_selection_hints.h
new file mode 100644
index 0000000..42ec1f0
--- /dev/null
+++ b/src/include/kim/kim_selection_hints.h
@@ -0,0 +1,537 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_SELECTION_HINTS_H
+#define KIM_SELECTION_HINTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kim/kim_types.h>
+
+/*!
+ * \page kim_selection_hints_overview KIM Selection Hints Overview
+ *
+ * \section kim_selection_hints_introduction Introduction
+ *
+ * Most users belong to multiple organizations and thus need
+ * to authenticate to multiple Kerberos realms. Traditionally Kerberos sites
+ * solved this problem by setting up a cross-realm relationship, which allowed
+ * the user to use TGT credentials for their client identity in one realm
+ * to obtain credentials in another realm via cross-realm authentication. As a
+ * result users could acquire credentials for a single client identity and use
+ * them everywhere.
+ *
+ * Setting up cross-realm requires that realms share a secret, so sites must
+ * coordinate with one another to set up a cross-realm relationship. In
+ * addition, sites must set up authorization policies for users from other
+ * realms. As Kerberos becomes increasingly wide-spread, many realms will
+ * not have cross-realm relationships, and users will need to
+ * manually obtain credentials for their client identity at each realm
+ * (eg: "user@BANK.COM", "user@UNIVERSITY.EDU", etc). As a result, users
+ * will often have multiple credentials caches, one for each client identity.
+ *
+ * Unfortunately this presents a problem for applications which need to obtain
+ * service credentials. Which client identity should they use?
+ * Rather than having each application to manually search the cache collection,
+ * KIM provides a selection hints API for choosing the best client identity.
+ * This API is intended to simplify the process of choosing credentials
+ * and provide consistent behavior across all applications.
+ *
+ * Searching the cache collection for credentials may be expensive if there
+ * are a large number of caches. If credentials for the client identity
+ * are expired or not present, KIM may also wish to prompt the user for
+ * new credentials for the appropriate client identity. As a result,
+ * applications might want to remember which client identity worked in
+ * the past and always request credentials using that identity.
+ *
+ *
+ * \section kim_selection_hints_creating Creating KIM Selection Hints
+ *
+ * A KIM selection hints object consists of an application identifier and one or
+ * more pieces of information about the service the client application will be
+ * contacting. The application identifier is used by user preferences
+ * to control how applications share cache entries. It is important to be
+ * consistent about what application identifier you provide. Java-style
+ * identifiers are recommended to avoid collisions.
+ *
+ * \section kim_selection_hints_searching Selection Hint Search Behavior
+ *
+ * When using selection hints to search for an appropriate client identity,
+ * KIM uses a consistent hint search order. This allows applications to specify
+ * potentially contradictory information without preventing KIM from locating a
+ * single ccache. In addition the selection hint search order may change,
+ * especially if more hints are added.
+ *
+ * As a result, callers are encouraged to provide all relevant search hints,
+ * even if only a subset of those search hints are necessary to get reasonable
+ * behavior in the current implementation. Doing so will provide the most
+ * user-friendly selection experience.
+ *
+ * Currently the search order looks like this:
+ *
+ * \li <B>Service Identity</B> The client identity which has obtained a service credential for this service identity.
+ * \li <B>Server</B> A client identity which has obtained a service credential for this server.
+ * \li <B>Service Realm</B> A client identity which has obtained a service credential for this realm.
+ * \li <B>Service</B> A client identity which has obtained a service credential for this service.
+ * \li <B>Client Realm</B> A client identity in this realm.
+ * \li <B>User</B> A client identity whose first component is this user string.
+ *
+ * For example, if you specify a service identity and a credential for
+ * that identity already exists in the ccache collection, KIM may use that
+ * ccache, even if your user and client realm entries in the selection hints would
+ * lead it to choose a different ccache. If no credentials for the service identity
+ * exist then KIM will fall back on the user and realm hints.
+ *
+ * \note Due to performance and information exposure concerns, currently all
+ * searching is done by examining the cache collection. In the future the KIM
+ * may also make network requests as part of its search algorithm. For example
+ * it might check to see if the TGT credentials in each ccache can obtain
+ * credentials for the service identity specified by the selection hints.
+ *
+ * \section kim_selection_hints_selecting Selecting an Identity Using Selection Hints
+ *
+ * Once you have provided search criteria for selecting an identity, use
+ * #kim_selection_hints_get_identity() to obtain an identity object.
+ * You can then use #kim_identity_get_gss_name() to obtain a gss_name_t
+ * for use in gss_acquire_cred() or use
+ * #kim_ccache_create_from_client_identity() to obtain a ccache containing
+ * credentials for the identity.
+ *
+ * \note #kim_selection_hints_get_identity() obtains an identity based on
+ * the current state of the selection hints object. If you change the
+ * selection hints object you must call #kim_selection_hints_get_identity()
+ * again.
+ *
+ * \section kim_selection_hints_caching Selection Hint Caching Behavior
+ *
+ * In addition to using selection hints to search for an appropriate client
+ * identity, KIM can also use them to remember which client identity worked.
+ * KIM maintains a per-user cache mapping selection hints to identities so
+ * that applications do not have to maintain their own caches or present
+ * user interface for selecting which cache to use.
+ *
+ * When #kim_selection_hints_get_identity() is called KIM looks up in the
+ * cache and returns the identity which the selection hints map to. If
+ * there is not a preexisting cache entry for the selection hints then
+ * #kim_selection_hints_get_identity() will search for an identity and
+ * prompt the user if it cannot find an appropriate one.
+ *
+ * If the client identity returned by KIM authenticates and passes
+ * authorization checks, you should tell KIM to cache the identity by calling
+ * #kim_selection_hints_remember_identity(). This will create a cache entry
+ * for the mapping between your selection hints and the identity so that
+ * subsequent calls to #kim_selection_hints_get_identity() do not need to
+ * prompt the user.
+ *
+ * If the client identity returned by KIM fails to authenticate or fails
+ * authorization checks, you must call #kim_selection_hints_forget_identity()
+ * to remove any mapping that already exists. After this function is called,
+ * future calls to #kim_selection_hints_get_identity() will search for an
+ * identity again. You may also wish to call this function if the user
+ * changes your application preferences such that the identity might be
+ * invalidated.
+ *
+ * \note It is very important that you call #kim_selection_hints_forget_identity()
+ * if your application fails to successfully establish a connection with the
+ * server. Otherwise the user can get "stuck" using the same non-working
+ * identity if they chose the wrong one accidentally or if their identity
+ * information changes. Because only your application understands the
+ * authorization checksof the protocol it uses, KIM cannot tell whether or not
+ * the identity worked.
+ *
+ * If you wish to search and prompt for an identity without using
+ * the cached mappings, you can turn off the cached mapping lookups using
+ * #kim_selection_hints_set_remember_identity(). This is not recommended
+ * for most applications since it will result in a lot of unnecessary
+ * searching and prompting for identities.
+ *
+ * \note Because cache entries key off of selection hints, it is important
+ * to always specify the same hints when contacting a particular
+ * service. Otherwise KIM will not always find the cache entries.
+ *
+ * \section kim_selection_hints_prompt Selection Hint Prompting Behavior
+ *
+ * If valid credentials for identity in the selection hints cache are
+ * unavailable or if no identity could be found using searching or caching
+ * when #kim_selection_hints_get_identity() is called, KIM may present a
+ * GUI to ask the user to select an identity or acquire credentials for
+ * an identity.
+ *
+ * \note Because of the caching behavior described above the user will
+ * only be prompted to choose an identity when setting up the application
+ * or when their identity stops working.
+ *
+ * In order to let the user know why Kerberos needs their assistance, KIM
+ * displays the name of the application which requested the identity
+ * selection. Unfortunately, some platforms do not provide a runtime
+ * mechanism for determining the name of the calling process. If your
+ * application runs on one of these platforms (or is cross-platform)
+ * you should provide a localized version of its name with
+ * #kim_selection_hints_set_application_name(). You can check what name
+ * will be used with #kim_selection_hints_get_application_name().
+ *
+ * In many cases a single application may select different identities for
+ * different purposes. For example an email application might use different
+ * identities to check mail for different accounts. If your application
+ * has this property you may need to provide the user with a localized
+ * string describing how the identity will be used. You can specify
+ * this string with #kim_selection_hints_get_explanation(). You can find
+ * out what string will be used with kim_selection_hints_set_explanation().
+ *
+ * Since the user may choose to acquire credentials when selection an
+ * identity, KIM also provides #kim_selection_hints_set_options() to
+ * set what credential acquisition options are used.
+ * #kim_selection_hints_get_options() returns the options which will be used.
+ *
+ * If you need to disable user interaction, use
+ * #kim_selection_hints_set_allow_user_interaction(). Use
+ * #kim_selection_hints_get_allow_user_interaction() to find out whether or
+ * not user interaction is enabled. User interaction is enabled by default.
+ *
+ * See \ref kim_selection_hints_reference for information on specific APIs.
+ */
+
+/*!
+ * \defgroup kim_selection_hints_reference KIM Selection Hints Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_selection_hints on exit, a new selection hints object.
+ * Must be freed with kim_selection_hints_free().
+ * \param in_application_identifier an application identifier string. Java-style identifiers are recommended
+ * to avoid cache entry collisions (eg: "com.example.MyApplication")
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Create a new selection hints object.
+ */
+kim_error_t kim_selection_hints_create (kim_selection_hints_t *out_selection_hints,
+ kim_string_t in_application_identifier);
+
+/*!
+ * \param out_selection_hints on exit, a new selection hints object which is a copy of in_selection_hints.
+ * Must be freed with kim_selection_hints_free().
+ * \param in_selection_hints a selection hints object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy a selection hints object.
+ */
+kim_error_t kim_selection_hints_copy (kim_selection_hints_t *out_selection_hints,
+ kim_selection_hints_t in_selection_hints);
+
+/*!
+ * \param io_selection_hints a selection hints object to modify.
+ * \param in_service_identity a service identity.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the preferred service identity.
+ * \sa kim_selection_hints_get_service_identity_hint()
+ */
+kim_error_t kim_selection_hints_set_service_identity_hint (kim_selection_hints_t io_selection_hints,
+ kim_identity_t in_service_identity);
+
+/*!
+ * \param in_selection_hints a selection hints object.
+ * \param out_service_identity on exit, the service identity specified in \a in_selection_hints.
+ * Must be freed with kim_identity_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the preferred service identity.
+ * \sa kim_selection_hints_set_service_identity_hint()
+ */
+kim_error_t kim_selection_hints_get_service_identity_hint (kim_selection_hints_t in_selection_hints,
+ kim_identity_t *out_service_identity);
+
+/*!
+ * \param io_selection_hints a selection hints object to modify.
+ * \param in_client_realm a client realm string.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the preferred client realm.
+ * \sa kim_selection_hints_get_client_realm_hint()
+ */
+kim_error_t kim_selection_hints_set_client_realm_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_client_realm);
+
+/*!
+ * \param in_selection_hints a selection hints object.
+ * \param out_client_realm on exit, the client realm string specified in \a in_selection_hints.
+ * Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the preferred client realm.
+ * \sa kim_selection_hints_set_client_realm_hint()
+ */
+kim_error_t kim_selection_hints_get_client_realm_hint (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_client_realm);
+
+/*!
+ * \param io_selection_hints a selection hints object to modify.
+ * \param in_user a user name string.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the preferred user name.
+ * \sa kim_selection_hints_get_user_hint()
+ */
+kim_error_t kim_selection_hints_set_user_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_user);
+
+/*!
+ * \param in_selection_hints a selection hints object.
+ * \param out_user on exit, the user name string specified in \a in_selection_hints.
+ * Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the preferred user name.
+ * \sa kim_selection_hints_set_user_hint()
+ */
+kim_error_t kim_selection_hints_get_user_hint (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_user);
+
+
+/*!
+ * \param io_selection_hints a selection hints object to modify.
+ * \param in_service_realm a service realm string.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the preferred service realm.
+ * \sa kim_selection_hints_get_service_realm_hint()
+ */
+kim_error_t kim_selection_hints_set_service_realm_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_service_realm);
+
+/*!
+ * \param io_selection_hints a selection hints object.
+ * \param out_service_realm on exit, the service realm string specified in \a in_selection_hints.
+ * Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the preferred service realm.
+ * \sa kim_selection_hints_set_service_realm_hint()
+ */
+kim_error_t kim_selection_hints_get_service_realm_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t *out_service_realm);
+
+/*!
+ * \param io_selection_hints a selection hints object to modify.
+ * \param in_service a service name string.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the preferred service name.
+ * \sa kim_selection_hints_get_service_hint()
+ */
+kim_error_t kim_selection_hints_set_service_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_service);
+
+/*!
+ * \param in_selection_hints a selection hints object.
+ * \param out_service on exit, the service name string specified in \a in_selection_hints.
+ * Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the preferred service name.
+ * \sa kim_selection_hints_set_service_hint()
+ */
+kim_error_t kim_selection_hints_get_service_hint (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_service);
+
+/*!
+ * \param io_selection_hints a selection hints object to modify.
+ * \param in_server a server host name string.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the preferred server host name.
+ * \sa kim_selection_hints_get_server_hint()
+ */
+kim_error_t kim_selection_hints_set_server_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_server);
+
+/*!
+ * \param in_selection_hints a selection hints object.
+ * \param out_server on exit, the server host name string specified in \a in_selection_hints.
+ * Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the preferred server host name.
+ * \sa kim_selection_hints_set_server_hint()
+ */
+kim_error_t kim_selection_hints_get_server_hint (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_server);
+
+/*!
+ * \param io_selection_hints a selection hints object to modify.
+ * \param in_application_name a localized string containing the full name of the application.
+ * \note If you do not call this function KIM will attempt to determine the application
+ * name at runtime. If that fails (the functionality is only available on some platforms)
+ * then KIM will use the application identity string.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the application name for use in user interaction.
+ * \sa kim_selection_hints_get_application_name()
+ */
+kim_error_t kim_selection_hints_set_application_name (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_application_name);
+
+/*!
+ * \param in_selection_hints a selection hints object.
+ * \param out_application_name on exit, the localized full name of the application specified
+ * in \a in_selection_hints. Must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the application name for use in user interaction.
+ * \sa kim_selection_hints_set_application_name()
+ */
+kim_error_t kim_selection_hints_get_application_name (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_application_name);
+
+/*!
+ * \param io_selection_hints a selection hints object to modify.
+ * \param in_explanation a localized string describing why the caller needs the identity.
+ * \note If the application only does one thing (the reason it needs an identity is obvious)
+ * then you may not need to call this function. You may still need to call
+ * #kim_selection_hints_set_application_name()
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the strings used to prompt the user to select the identity.
+ * \sa kim_selection_hints_get_explanation()
+ */
+kim_error_t kim_selection_hints_set_explanation (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_explanation);
+
+/*!
+ * \param in_selection_hints a selection hints object.
+ * \param out_explanation on exit, the localized string specified in \a in_selection_hints
+ * which describes why the caller needs the identity. May be NULL.
+ * If non-NULL, must be freed with kim_string_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the strings used to prompt the user to select the identity.
+ * \sa kim_selection_hints_set_explanation()
+ */
+kim_error_t kim_selection_hints_get_explanation (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_explanation);
+
+
+/*!
+ * \param io_selection_hints a selection hints object to modify.
+ * \param in_options options to control credential acquisition.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Set the options which will be used if credentials need to be acquired.
+ * \sa kim_selection_hints_get_options()
+ */
+kim_error_t kim_selection_hints_set_options (kim_selection_hints_t io_selection_hints,
+ kim_options_t in_options);
+
+/*!
+ * \param in_selection_hints a selection hints object.
+ * \param out_options on exit, the options to control credential acquisition
+ * specified in \a in_selection_hints. May be KIM_OPTIONS_DEFAULT.
+ * If not, must be freed with kim_options_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Get the options which will be used if credentials need to be acquired.
+ * \sa kim_selection_hints_set_options()
+ */
+kim_error_t kim_selection_hints_get_options (kim_selection_hints_t in_selection_hints,
+ kim_options_t *out_options);
+
+/*!
+ * \param in_selection_hints a selection hints object to modify
+ * \param in_allow_user_interaction a boolean value specifying whether or not KIM should ask
+ * the user to select an identity for \a in_selection_hints.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \note This setting defaults to TRUE.
+ * \brief Set whether or not KIM may interact with the user to select an identity.
+ * \sa kim_selection_hints_get_allow_user_interaction
+ */
+kim_error_t kim_selection_hints_set_allow_user_interaction (kim_selection_hints_t in_selection_hints,
+ kim_boolean_t in_allow_user_interaction);
+
+/*!
+ * \param in_selection_hints a selection hints object to modify
+ * \param out_allow_user_interaction on exit, a boolean value specifying whether or not KIM
+ * should ask the user to select an identity for
+ * \a in_selection_hints.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \note This setting defaults to TRUE.
+ * \brief Get whether or not KIM may interact with the user to select an identity.
+ * \sa kim_selection_hints_set_allow_user_interaction
+ */
+kim_error_t kim_selection_hints_get_allow_user_interaction (kim_selection_hints_t in_selection_hints,
+ kim_boolean_t *out_allow_user_interaction);
+
+/*!
+ * \param in_selection_hints a selection hints object to modify
+ * \param in_remember_identity a boolean value specifying whether or not KIM should use a cached
+ * mapping between \a in_selection_hints and a Kerberos identity.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \note This setting defaults to TRUE.
+ * \brief Set whether or not KIM will use cached mappings for this selection hints object.
+ * \sa kim_selection_hints_get_remember_identity
+ */
+kim_error_t kim_selection_hints_set_remember_identity (kim_selection_hints_t in_selection_hints,
+ kim_boolean_t in_remember_identity);
+
+/*!
+ * \param in_selection_hints a selection hints object to modify
+ * \param out_remember_identity on exit, a boolean value specifying whether or not KIM will use a
+ * cached mapping between \a in_selection_hints and a Kerberos identity.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \note This setting defaults to TRUE.
+ * \brief Get whether or not KIM will use cache mappings for this selection hints object.
+ * \sa kim_selection_hints_set_remember_identity
+ */
+kim_error_t kim_selection_hints_get_remember_identity (kim_selection_hints_t in_selection_hints,
+ kim_boolean_t *out_remember_identity);
+
+/*!
+ * \param in_selection_hints the selection hints to add to the cache.
+ * \param out_identity the Kerberos identity \a in_selection_hints maps to.
+ * Must be freed with kim_identity_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \note \a out_identity is the identity mapped to by the current state of \a in_selection_hints.
+ * This function may prompt the user via a GUI to choose that identity.
+ * Subsequent modifications to \a in_selection_hints will not change \a out_identity.
+ * \brief Choose a client identity based on selection hints.
+ */
+
+kim_error_t kim_selection_hints_get_identity (kim_selection_hints_t in_selection_hints,
+ kim_identity_t *out_identity);
+
+/*!
+ * \param in_selection_hints the selection hints to add to the cache.
+ * \param in_identity the Kerberos identity \a in_selection_hints maps to.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Add an entry for the selection hints to the selection hints cache,
+ * replacing any existing entry.
+ */
+
+kim_error_t kim_selection_hints_remember_identity (kim_selection_hints_t in_selection_hints,
+ kim_identity_t in_identity);
+
+/*!
+ * \param in_selection_hints the selection hints to remove from the cache.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Remove an entry for the selection hints from the selection hints cache.
+ */
+
+kim_error_t kim_selection_hints_forget_identity (kim_selection_hints_t in_selection_hints);
+
+/*!
+ * \param io_selection_hints the selection hints object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with a selection hints object.
+ */
+
+void kim_selection_hints_free (kim_selection_hints_t *io_selection_hints);
+
+/*!@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_SELECTION_HINTS_H */
diff --git a/src/include/kim/kim_string.h b/src/include/kim/kim_string.h
new file mode 100644
index 0000000..eb5277e
--- /dev/null
+++ b/src/include/kim/kim_string.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_STRING_H
+#define KIM_STRING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <kim/kim_types.h>
+
+/*!
+ * \page kim_string_overview KIM String Overview
+ *
+ * A UTF8 string.
+ *
+ * Memory management routines are provided for runtime consistency on
+ * operating systems with shared libraries and multiple runtimes.
+ *
+ * See \ref kim_string_reference for information on specific APIs.
+ */
+
+/*!
+ * \defgroup kim_string_reference KIM String Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_string on exit, a new string object which is a copy of \a in_string.
+ Must be freed with kim_string_free().
+ * \param in_string the string to copy.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Copy a string.
+ */
+kim_error_t kim_string_copy (kim_string_t *out_string,
+ const kim_string_t in_string);
+
+/*!
+ * \param in_string a string.
+ * \param in_compare_to_string a string to be compared to \a in_string.
+ * \param out_comparison on exit, a comparison result indicating whether \a in_string
+ * is greater than, less than or equal to \a in_compare_to_string.
+ * \return On success, #KIM_NO_ERROR. On failure, an error object representing the failure.
+ * \brief Compare two strings.
+ */
+kim_error_t kim_string_compare (kim_string_t in_string,
+ kim_string_t in_compare_to_string,
+ kim_comparison_t *out_comparison);
+
+/*!
+ * \param io_string a string to be freed. Set to NULL on exit.
+ * \brief Free memory associated with a string.
+ */
+void kim_string_free (kim_string_t *io_string);
+
+/*!@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_STRING_H */
diff --git a/src/include/kim/kim_types.h b/src/include/kim/kim_types.h
new file mode 100644
index 0000000..7898e62
--- /dev/null
+++ b/src/include/kim/kim_types.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_TYPES_H
+#define KIM_TYPES_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ * \defgroup kim_types_reference KIM Types and Constants
+ * @{
+ */
+
+/*!
+ * The KIM String type. See \ref kim_string_overview for more information.
+ */
+typedef int32_t kim_error_code_t;
+
+/*!
+ * A time value represented in seconds since January 1, 1970.
+ */
+typedef int64_t kim_time_t;
+
+/*!
+ * A duration represented in seconds.
+ */
+typedef int64_t kim_lifetime_t;
+
+/*!
+ * An quantity, usually used to return the number of elements in an array.
+ */
+typedef uint64_t kim_count_t;
+
+/*!
+ * A boolean value. 0 means false, all other values mean true.
+ */
+typedef int kim_boolean_t;
+
+/*!
+ * A comparison between two sortable objects.
+ * \li Less than 0 means the first object is less than the second.
+ * \li 0 means the two objects are identical.
+ * \li Greater than 0 means the first object is greater than the second.
+ * \note Convenience macros are provided for interpreting kim_comparison_ts
+ * to improve code readability.
+ * See #kim_comparison_is_less_than(), #kim_comparison_is_equal() and
+ * #kim_comparison_is_greater_than()
+ */
+typedef int kim_comparison_t;
+
+/*!
+ * Convenience macro for interpreting #kim_comparison_t.
+ */
+#define kim_comparison_is_less_than(c) (c < 0)
+
+/*!
+ * Convenience macro for interpreting #kim_comparison_t.
+ */
+#define kim_comparison_is_equal_to(c) (c == 0)
+
+/*!
+ * Convenience macro for interpreting #kim_comparison_t.
+ */
+#define kim_comparison_is_greater_than(c) (c > 0)
+
+/*!
+ * The KIM String type. See \ref kim_string_overview for more information.
+ */
+typedef const char *kim_string_t;
+
+struct kim_error_opaque;
+/*!
+ * A KIM Error object. See \ref kim_error_overview for more information.
+ */
+typedef struct kim_error_opaque *kim_error_t;
+
+struct kim_identity_opaque;
+/*!
+ * A KIM Principal object. See \ref kim_identity_overview for more information.
+ */
+typedef struct kim_identity_opaque *kim_identity_t;
+
+struct kim_options_opaque;
+/*!
+ * A KIM Options object. See \ref kim_options_overview for more information.
+ */
+typedef struct kim_options_opaque *kim_options_t;
+
+struct kim_selection_hints_opaque;
+/*!
+ * A KIM Selection Hints object. See \ref kim_selection_hints_overview for more information.
+ */
+typedef struct kim_selection_hints_opaque *kim_selection_hints_t;
+
+struct kim_favorite_identities_opaque;
+/*!
+ * A KIM Favorite Realms object. See \ref kim_favorite_identities_overview for more information.
+ */
+typedef struct kim_favorite_identities_opaque *kim_favorite_identities_t;
+
+struct kim_preferences_opaque;
+/*!
+ * A KIM Preferences object. See \ref kim_preferences_overview for more information.
+ */
+typedef struct kim_preferences_opaque *kim_preferences_t;
+
+struct kim_ccache_iterator_opaque;
+/*!
+ * A KIM CCache Iterator object. See \ref kim_credential_cache_collection for more information.
+ */
+typedef struct kim_ccache_iterator_opaque *kim_ccache_iterator_t;
+
+struct kim_ccache_opaque;
+/*!
+ * A KIM CCache object. See \ref kim_ccache_overview for more information.
+ */
+typedef struct kim_ccache_opaque *kim_ccache_t;
+
+struct kim_credential_iterator_opaque;
+/*!
+ * A KIM Credential Iterator object. See \ref kim_credential_iterator_t for more information.
+ */
+typedef struct kim_credential_iterator_opaque *kim_credential_iterator_t;
+
+struct kim_credential_opaque;
+/*!
+ * A KIM Credential object. See \ref kim_credential_overview for more information.
+ */
+typedef struct kim_credential_opaque *kim_credential_t;
+
+/*!@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KIM_TYPES_H */
diff --git a/src/kim/agent/mac/KerberosAgent-Info.plist b/src/kim/agent/mac/KerberosAgent-Info.plist
new file mode 100644
index 0000000..2a00a31
--- /dev/null
+++ b/src/kim/agent/mac/KerberosAgent-Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>KerberosAgent</string>
+ <key>CFBundleIdentifier</key>
+ <string>edu.mit.KerberosAgent</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>KrbA</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/src/kim/agent/mac/KerberosAgentPrefix.pch b/src/kim/agent/mac/KerberosAgentPrefix.pch
new file mode 100644
index 0000000..88c32a8
--- /dev/null
+++ b/src/kim/agent/mac/KerberosAgentPrefix.pch
@@ -0,0 +1,20 @@
+#ifdef __OBJC__
+#import <Cocoa/Cocoa.h>
+
+#define CacheCollectionDidChangeNotification @"CacheCollectionDidChange"
+#endif
+
+#define BIND_8_COMPAT
+
+#include <Kerberos/Kerberos.h>
+#include <Kerberos/KerberosLoginPrivate.h>
+#include <Kerberos/KerberosDebug.h>
+#include <nameser.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
diff --git a/src/kim/agent/mac/main.m b/src/kim/agent/mac/main.m
new file mode 100644
index 0000000..fb0b9df
--- /dev/null
+++ b/src/kim/agent/mac/main.m
@@ -0,0 +1,6 @@
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, char *argv[])
+{
+ return NSApplicationMain(argc, (const char **) argv);
+}
diff --git a/src/kim/agent/mac/resources/Add.tiff b/src/kim/agent/mac/resources/Add.tiff
new file mode 100644
index 0000000..b78b0c2
--- /dev/null
+++ b/src/kim/agent/mac/resources/Add.tiff
Binary files differ
diff --git a/src/kim/agent/mac/resources/Add_Pressed.tiff b/src/kim/agent/mac/resources/Add_Pressed.tiff
new file mode 100644
index 0000000..b842e20
--- /dev/null
+++ b/src/kim/agent/mac/resources/Add_Pressed.tiff
Binary files differ
diff --git a/src/kim/agent/mac/resources/English.lproj/Authentication.xib b/src/kim/agent/mac/resources/English.lproj/Authentication.xib
new file mode 100644
index 0000000..1060d73
--- /dev/null
+++ b/src/kim/agent/mac/resources/English.lproj/Authentication.xib
@@ -0,0 +1,3698 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.01">
+ <data>
+ <int key="IBDocument.SystemTarget">1050</int>
+ <string key="IBDocument.SystemVersion">9A581</string>
+ <string key="IBDocument.InterfaceBuilderVersion">629</string>
+ <string key="IBDocument.AppKitVersion">949</string>
+ <string key="IBDocument.HIToolboxVersion">343.00</string>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="300045"/>
+ <integer value="19"/>
+ <integer value="5"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string id="147422244">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000842439">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="262677138">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSCustomObject" id="553445653">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="714830734">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSWindowTemplate" id="224590347">
+ <int key="NSWindowStyleMask">15</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{279, 363}, {419, 465}}</string>
+ <int key="NSWTFlags">1886912512</int>
+ <string key="NSWindowTitle">Select a Kerberos Identity</string>
+ <object class="NSMutableString" key="NSWindowClass">
+ <characters key="NS.bytes">NSWindow</characters>
+ </object>
+ <object class="NSMutableString" key="NSViewClass">
+ <characters key="NS.bytes">View</characters>
+ </object>
+ <object class="NSView" key="NSWindowView" id="928852707">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSImageView" id="856695188">
+ <reference key="NSNextResponder" ref="928852707"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string id="901666209">Apple PDF pasteboard type</string>
+ <string id="655846867">Apple PICT pasteboard type</string>
+ <string id="634841833">Apple PNG pasteboard type</string>
+ <string id="578115750">NSFilenamesPboardType</string>
+ <string id="976484999">NeXT Encapsulated PostScript v1.2 pasteboard type</string>
+ <string id="549194653">NeXT TIFF v4.0 pasteboard type</string>
+ </object>
+ </object>
+ <string key="NSFrame">{{17, 386}, {62, 62}}</string>
+ <reference key="NSSuperview" ref="928852707"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="320974445">
+ <int key="NSCellFlags">537001472</int>
+ <int key="NSCellFlags2">33554432</int>
+ <object class="NSCustomResource" key="NSContents" id="995022583">
+ <string key="NSClassName" id="18406880">NSImage</string>
+ <string key="NSResourceName">KerberosAgent</string>
+ </object>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ <object class="NSTextField" id="499468804">
+ <reference key="NSNextResponder" ref="928852707"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{84, 386}, {318, 40}}</string>
+ <reference key="NSSuperview" ref="928852707"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="82820472">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Please select a Kerberos Identity</string>
+ <object class="NSFont" key="NSSupport" id="604532625">
+ <string key="NSName" id="103036106">LucidaGrande</string>
+ <double key="NSSize">1.300000e+01</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="499468804"/>
+ <object class="NSColor" key="NSBackgroundColor" id="876444531">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName" id="908056328">System</string>
+ <string key="NSColorName">controlColor</string>
+ <object class="NSColor" key="NSColor" id="31892828">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2OQA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="883746258">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="908056328"/>
+ <string key="NSColorName">controlTextColor</string>
+ <object class="NSColor" key="NSColor" id="18538584">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSScrollView" id="147207906">
+ <reference key="NSNextResponder" ref="928852707"/>
+ <int key="NSvFlags">274</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSClipView" id="750193364">
+ <reference key="NSNextResponder" ref="147207906"/>
+ <int key="NSvFlags">2304</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTableView" id="988096643">
+ <reference key="NSNextResponder" ref="750193364"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{380, 300}</string>
+ <reference key="NSSuperview" ref="750193364"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTableHeaderView" key="NSHeaderView" id="401017936">
+ <reference key="NSNextResponder" ref="320641129"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{380, 17}</string>
+ <reference key="NSSuperview" ref="320641129"/>
+ <reference key="NSWindow"/>
+ <reference key="NSTableView" ref="988096643"/>
+ </object>
+ <object class="_NSCornerView" key="NSCornerView" id="907434254">
+ <reference key="NSNextResponder" ref="147207906"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{-26, 0}, {16, 17}}</string>
+ <reference key="NSSuperview" ref="147207906"/>
+ <reference key="NSWindow"/>
+ </object>
+ <object class="NSMutableArray" key="NSTableColumns">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTableColumn" id="697375404">
+ <double key="NSWidth">2.739741e+02</double>
+ <double key="NSMinWidth">1.499741e+02</double>
+ <double key="NSMaxWidth">1.000000e+03</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">75628032</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">Identity</string>
+ <object class="NSFont" key="NSSupport" id="26">
+ <reference key="NSName" ref="103036106"/>
+ <double key="NSSize">1.100000e+01</double>
+ <int key="NSfFlags">3100</int>
+ </object>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="223105710">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="908056328"/>
+ <string key="NSColorName">headerTextColor</string>
+ <reference key="NSColor" ref="18538584"/>
+ </object>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell" id="325541546">
+ <int key="NSCellFlags">1411513920</int>
+ <int key="NSCellFlags2">272761856</int>
+ <string key="NSContents" id="989132158">Text Cell</string>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="988096643"/>
+ <reference key="NSBackgroundColor" ref="876444531"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <bool key="NSIsEditable">YES</bool>
+ <reference key="NSTableView" ref="988096643"/>
+ </object>
+ <object class="NSTableColumn" id="1004662124">
+ <double key="NSWidth">1.003135e+02</double>
+ <double key="NSMinWidth">1.000000e+02</double>
+ <double key="NSMaxWidth">1.500000e+02</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">67108864</int>
+ <string key="NSContents">Time Remaining</string>
+ <reference key="NSSupport" ref="26"/>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="908056328"/>
+ <string key="NSColorName">headerColor</string>
+ <object class="NSColor" key="NSColor" id="591379363">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ </object>
+ <reference key="NSTextColor" ref="223105710"/>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell" id="618557697">
+ <int key="NSCellFlags">1140981312</int>
+ <int key="NSCellFlags2">71435264</int>
+ <reference key="NSContents" ref="989132158"/>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="988096643"/>
+ <reference key="NSBackgroundColor" ref="876444531"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <bool key="NSIsEditable">YES</bool>
+ <reference key="NSTableView" ref="988096643"/>
+ </object>
+ </object>
+ <double key="NSIntercellSpacingWidth">3.000000e+00</double>
+ <double key="NSIntercellSpacingHeight">2.000000e+00</double>
+ <reference key="NSBackgroundColor" ref="591379363"/>
+ <object class="NSColor" key="NSGridColor" id="733934977">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="908056328"/>
+ <string key="NSColorName">gridColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC41AA</bytes>
+ </object>
+ </object>
+ <double key="NSRowHeight">1.700000e+01</double>
+ <int key="NSTvFlags">1119879168</int>
+ <int key="NSColumnAutoresizingStyle">5</int>
+ <int key="NSDraggingSourceMaskForLocal">15</int>
+ <int key="NSDraggingSourceMaskForNonLocal">0</int>
+ <bool key="NSAllowsTypeSelect">YES</bool>
+ </object>
+ </object>
+ <string key="NSFrame">{{1, 17}, {380, 300}}</string>
+ <reference key="NSSuperview" ref="147207906"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="988096643"/>
+ <reference key="NSDocView" ref="988096643"/>
+ <object class="NSColor" key="NSBGColor" id="1015612366">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="908056328"/>
+ <string key="NSColorName">controlBackgroundColor</string>
+ <reference key="NSColor" ref="31892828"/>
+ </object>
+ <int key="NScvFlags">4</int>
+ </object>
+ <object class="NSScroller" id="80966883">
+ <reference key="NSNextResponder" ref="147207906"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{-30, 17}, {15, 285}}</string>
+ <reference key="NSSuperview" ref="147207906"/>
+ <reference key="NSWindow"/>
+ <reference key="NSTarget" ref="147207906"/>
+ <string key="NSAction" id="299467350">_doScroller:</string>
+ <double key="NSPercent">9.684210e-01</double>
+ </object>
+ <object class="NSScroller" id="564144656">
+ <reference key="NSNextResponder" ref="147207906"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{1, -30}, {362, 15}}</string>
+ <reference key="NSSuperview" ref="147207906"/>
+ <reference key="NSWindow"/>
+ <int key="NSsFlags">1</int>
+ <reference key="NSTarget" ref="147207906"/>
+ <reference key="NSAction" ref="299467350"/>
+ <double key="NSPercent">9.040768e-01</double>
+ </object>
+ <object class="NSClipView" id="320641129">
+ <reference key="NSNextResponder" ref="147207906"/>
+ <int key="NSvFlags">2304</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="401017936"/>
+ </object>
+ <string key="NSFrame">{{1, 0}, {380, 17}}</string>
+ <reference key="NSSuperview" ref="147207906"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="401017936"/>
+ <reference key="NSDocView" ref="401017936"/>
+ <reference key="NSBGColor" ref="1015612366"/>
+ <int key="NScvFlags">4</int>
+ </object>
+ <reference ref="907434254"/>
+ </object>
+ <string key="NSFrame">{{17, 60}, {382, 318}}</string>
+ <reference key="NSSuperview" ref="928852707"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="750193364"/>
+ <int key="NSsFlags">562</int>
+ <reference key="NSVScroller" ref="80966883"/>
+ <reference key="NSHScroller" ref="564144656"/>
+ <reference key="NSContentView" ref="750193364"/>
+ <reference key="NSHeaderClipView" ref="320641129"/>
+ <reference key="NSCornerView" ref="907434254"/>
+ <bytes key="NSScrollAmts">QSAAAEEgAABBmAAAQZgAAA</bytes>
+ </object>
+ <object class="NSButton" id="426244837">
+ <reference key="NSNextResponder" ref="928852707"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{320, 12}, {87, 32}}</string>
+ <reference key="NSSuperview" ref="928852707"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="686991406">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Select</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="426244837"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="604532625"/>
+ <string key="NSAlternateContents" id="802704698"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="505388869">
+ <reference key="NSNextResponder" ref="928852707"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{156, 12}, {82, 32}}</string>
+ <reference key="NSSuperview" ref="928852707"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="720384657">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Cancel</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="505388869"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="604532625"/>
+ <reference key="NSAlternateContents" ref="802704698"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="616352993">
+ <reference key="NSNextResponder" ref="928852707"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{238, 12}, {82, 32}}</string>
+ <reference key="NSSuperview" ref="928852707"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="923350128">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string type="base64-UTF8" key="NSContents">TmV34oCmA</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="616352993"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="604532625"/>
+ <reference key="NSAlternateContents" ref="802704698"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{419, 465}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
+ <string key="NSMinSize">{213, 129}</string>
+ <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ </object>
+ <object class="NSWindowTemplate" id="236877202">
+ <int key="NSWindowStyleMask">13</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{378, 247}, {484, 199}}</string>
+ <int key="NSWTFlags">1886912512</int>
+ <string key="NSWindowTitle">Authenticate to Kerberos</string>
+ <object class="NSMutableString" key="NSWindowClass">
+ <characters key="NS.bytes">NSWindow</characters>
+ </object>
+ <object class="NSMutableString" key="NSViewClass">
+ <characters key="NS.bytes">View</characters>
+ </object>
+ <object class="NSView" key="NSWindowView" id="632526042">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTabView" id="402198404">
+ <reference key="NSNextResponder" ref="632526042"/>
+ <int key="NSvFlags">274</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSView" id="821532364">
+ <reference key="NSNextResponder" ref="402198404"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSButton" id="487636925">
+ <reference key="NSNextResponder" ref="821532364"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{392, 12}, {82, 32}}</string>
+ <reference key="NSSuperview" ref="821532364"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="402198404"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="1002938556">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Done</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="487636925"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="604532625"/>
+ <reference key="NSAlternateContents" ref="802704698"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSImageView" id="144384471">
+ <reference key="NSNextResponder" ref="821532364"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="901666209"/>
+ <reference ref="655846867"/>
+ <reference ref="634841833"/>
+ <reference ref="578115750"/>
+ <reference ref="976484999"/>
+ <reference ref="549194653"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{17, 122}, {62, 62}}</string>
+ <reference key="NSSuperview" ref="821532364"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="681150857"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="140668900">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">33554432</int>
+ <reference key="NSContents" ref="995022583"/>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ <object class="NSTextField" id="681150857">
+ <reference key="NSNextResponder" ref="821532364"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{84, 167}, {387, 17}}</string>
+ <reference key="NSSuperview" ref="821532364"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="351897359"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="987061439">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Conclusion</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="681150857"/>
+ <reference key="NSBackgroundColor" ref="876444531"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="351897359">
+ <reference key="NSNextResponder" ref="821532364"/>
+ <int key="NSvFlags">274</int>
+ <string key="NSFrame">{{84, 60}, {387, 99}}</string>
+ <reference key="NSSuperview" ref="821532364"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="491153292"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="30067995">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272760832</int>
+ <string key="NSContents">Congratulations! You have acquired Kerberos tickets for lxs@ATHENA.MIT.EDU.</string>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="351897359"/>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MSAwLjk3MDAwMDAzAA</bytes>
+ </object>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ </object>
+ <object class="NSButton" id="491153292">
+ <reference key="NSNextResponder" ref="821532364"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{305, 12}, {91, 32}}</string>
+ <reference key="NSSuperview" ref="821532364"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="487636925"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="403345038">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents" id="460300317">Go Back</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="491153292"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="604532625"/>
+ <reference key="NSAlternateContents" ref="802704698"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{488, 201}</string>
+ <reference key="NSSuperview" ref="402198404"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="144384471"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{-4, 0}, {488, 201}}</string>
+ <reference key="NSSuperview" ref="632526042"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="821532364"/>
+ <object class="NSMutableArray" key="NSTabViewItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTabViewItem" id="433865568">
+ <string key="NSIdentifier">1</string>
+ <object class="NSView" key="NSView" id="267285695">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSImageView" id="54265178">
+ <reference key="NSNextResponder" ref="267285695"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="901666209"/>
+ <reference ref="655846867"/>
+ <reference ref="634841833"/>
+ <reference ref="578115750"/>
+ <reference ref="976484999"/>
+ <reference ref="549194653"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{20, 119}, {62, 62}}</string>
+ <reference key="NSSuperview" ref="267285695"/>
+ <reference key="NSNextKeyView" ref="8788833"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="683080457">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">33554432</int>
+ <reference key="NSContents" ref="995022583"/>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ <object class="NSTextField" id="8788833">
+ <reference key="NSNextResponder" ref="267285695"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{87, 119}, {387, 51}}</string>
+ <reference key="NSSuperview" ref="267285695"/>
+ <reference key="NSNextKeyView" ref="176276299"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="230651394">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Please enter your Kerberos identity</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="8788833"/>
+ <reference key="NSBackgroundColor" ref="876444531"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="409805769">
+ <reference key="NSNextResponder" ref="267285695"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{90, 89}, {378, 22}}</string>
+ <reference key="NSSuperview" ref="267285695"/>
+ <reference key="NSNextKeyView" ref="566752045"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="111694776">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <reference key="NSContents" ref="802704698"/>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="409805769"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <object class="NSColor" key="NSBackgroundColor" id="490771653">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="908056328"/>
+ <string key="NSColorName">textBackgroundColor</string>
+ <reference key="NSColor" ref="591379363"/>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="955928389">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="908056328"/>
+ <string key="NSColorName">textColor</string>
+ <reference key="NSColor" ref="18538584"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextField" id="176276299">
+ <reference key="NSNextResponder" ref="267285695"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{17, 94}, {68, 17}}</string>
+ <reference key="NSSuperview" ref="267285695"/>
+ <reference key="NSNextKeyView" ref="409805769"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="169436004">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">71303168</int>
+ <string key="NSContents">Name:</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="176276299"/>
+ <reference key="NSBackgroundColor" ref="876444531"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ </object>
+ <object class="NSComboBox" id="400442477">
+ <reference key="NSNextResponder" ref="267285695"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{90, 57}, {381, 26}}</string>
+ <reference key="NSSuperview" ref="267285695"/>
+ <reference key="NSNextKeyView"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSComboBoxCell" key="NSCell" id="459624661">
+ <int key="NSCellFlags">343014976</int>
+ <int key="NSCellFlags2">272630784</int>
+ <object class="NSMutableString" key="NSContents" id="917015490">
+ <characters key="NS.bytes"/>
+ </object>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="400442477"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="490771653"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ <int key="NSVisibleItemCount">5</int>
+ <bool key="NSHasVerticalScroller">YES</bool>
+ <reference key="NSDelegate" ref="400442477"/>
+ <object class="NSComboTableView" key="NSTableView" id="113933544">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">274</int>
+ <string key="NSFrameSize">{15, 0}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSMutableArray" key="NSTableColumns">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTableColumn">
+ <integer value="0" key="NSIdentifier"/>
+ <double key="NSWidth">1.200000e+01</double>
+ <double key="NSMinWidth">1.000000e+01</double>
+ <double key="NSMaxWidth">1.000000e+03</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">75628032</int>
+ <int key="NSCellFlags2">0</int>
+ <reference key="NSContents" ref="917015490"/>
+ <object class="NSFont" key="NSSupport">
+ <reference key="NSName" ref="103036106"/>
+ <double key="NSSize">1.200000e+01</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes>
+ </object>
+ <reference key="NSTextColor" ref="591379363"/>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell">
+ <int key="NSCellFlags">338820672</int>
+ <int key="NSCellFlags2">1024</int>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="113933544"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="1015612366"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <reference key="NSTableView" ref="113933544"/>
+ </object>
+ </object>
+ <double key="NSIntercellSpacingWidth">3.000000e+00</double>
+ <double key="NSIntercellSpacingHeight">2.000000e+00</double>
+ <reference key="NSBackgroundColor" ref="1015612366"/>
+ <reference key="NSGridColor" ref="733934977"/>
+ <double key="NSRowHeight">1.900000e+01</double>
+ <string key="NSAction">tableViewAction:</string>
+ <int key="NSTvFlags">-767524864</int>
+ <reference key="NSDelegate" ref="459624661"/>
+ <reference key="NSDataSource" ref="459624661"/>
+ <reference key="NSTarget" ref="459624661"/>
+ <int key="NSColumnAutoresizingStyle">1</int>
+ <int key="NSDraggingSourceMaskForLocal">15</int>
+ <int key="NSDraggingSourceMaskForNonLocal">0</int>
+ <bool key="NSAllowsTypeSelect">YES</bool>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextField" id="566752045">
+ <reference key="NSNextResponder" ref="267285695"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{17, 61}, {68, 17}}</string>
+ <reference key="NSSuperview" ref="267285695"/>
+ <reference key="NSNextKeyView" ref="400442477"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="462123130">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">71303168</int>
+ <string key="NSContents">Realm:</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="566752045"/>
+ <reference key="NSBackgroundColor" ref="876444531"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ </object>
+ <object class="NSButton" id="725810597">
+ <reference key="NSNextResponder" ref="267285695"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{376, 12}, {98, 32}}</string>
+ <reference key="NSSuperview" ref="267285695"/>
+ <reference key="NSNextKeyView" ref="402198404"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="670473243">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents" id="239294574">Continue</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="725810597"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="604532625"/>
+ <reference key="NSAlternateContents" ref="802704698"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="909400991">
+ <reference key="NSNextResponder" ref="267285695"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrame">{{18, 15}, {51, 27}}</string>
+ <reference key="NSSuperview" ref="267285695"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="384105704">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="802704698"/>
+ <object class="NSFont" key="NSSupport" id="24">
+ <reference key="NSName" ref="103036106"/>
+ <double key="NSSize">1.000000e+01</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <reference key="NSControlView" ref="909400991"/>
+ <int key="NSButtonFlags">-2033434369</int>
+ <int key="NSButtonFlags2">2</int>
+ <object class="NSCustomResource" key="NSNormalImage" id="968230828">
+ <reference key="NSClassName" ref="18406880"/>
+ <string key="NSResourceName">Gear</string>
+ </object>
+ <reference key="NSAlternateContents" ref="802704698"/>
+ <reference key="NSKeyEquivalent" ref="802704698"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{488, 201}</string>
+ <reference key="NSNextKeyView" ref="54265178"/>
+ </object>
+ <string key="NSLabel">Select Identity</string>
+ <reference key="NSColor" ref="876444531"/>
+ <reference key="NSTabView" ref="402198404"/>
+ </object>
+ <object class="NSTabViewItem" id="328078317">
+ <string key="NSIdentifier">2</string>
+ <object class="NSView" key="NSView" id="657191530">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSImageView" id="92949448">
+ <reference key="NSNextResponder" ref="657191530"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="901666209"/>
+ <reference ref="655846867"/>
+ <reference ref="634841833"/>
+ <reference ref="578115750"/>
+ <reference ref="976484999"/>
+ <reference ref="549194653"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{17, 122}, {62, 62}}</string>
+ <reference key="NSSuperview" ref="657191530"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="193754575">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">33554432</int>
+ <reference key="NSContents" ref="995022583"/>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ <object class="NSTextField" id="506042805">
+ <reference key="NSNextResponder" ref="657191530"/>
+ <int key="NSvFlags">290</int>
+ <string key="NSFrame">{{87, 60}, {381, 22}}</string>
+ <reference key="NSSuperview" ref="657191530"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="664764666">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <reference key="NSContents" ref="802704698"/>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="506042805"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="490771653"/>
+ <reference key="NSTextColor" ref="955928389"/>
+ </object>
+ </object>
+ <object class="NSButton" id="67140815">
+ <reference key="NSNextResponder" ref="657191530"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{376, 12}, {98, 32}}</string>
+ <reference key="NSSuperview" ref="657191530"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="646394101">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="239294574"/>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="67140815"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="604532625"/>
+ <reference key="NSAlternateContents" ref="802704698"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="142035750">
+ <reference key="NSNextResponder" ref="657191530"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{283, 12}, {93, 32}}</string>
+ <reference key="NSSuperview" ref="657191530"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="1009827779">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="460300317"/>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="142035750"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="604532625"/>
+ <reference key="NSAlternateContents" ref="802704698"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="616334468">
+ <reference key="NSNextResponder" ref="657191530"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{84, 167}, {387, 17}}</string>
+ <reference key="NSSuperview" ref="657191530"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="377963764">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Please enter your Kerberos password</string>
+ <reference key="NSSupport" ref="604532625"/>
+ <reference key="NSControlView" ref="616334468"/>
+ <reference key="NSBackgroundColor" ref="876444531"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="67707351">
+ <reference key="NSNextResponder" ref="657191530"/>
+ <int key="NSvFlags">274</int>
+ <string key="NSFrame">{{84, 90}, {387, 69}}</string>
+ <reference key="NSSuperview" ref="657191530"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="841876216">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Mail wants to connect to the account lxs@mit.edu</string>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="67707351"/>
+ <reference key="NSBackgroundColor" ref="876444531"/>
+ <reference key="NSTextColor" ref="883746258"/>
+ </object>
+ </object>
+ <object class="NSButton" id="63314511">
+ <reference key="NSNextResponder" ref="657191530"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrame">{{18, 16}, {51, 26}}</string>
+ <reference key="NSSuperview" ref="657191530"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="955946369">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="802704698"/>
+ <reference key="NSSupport" ref="24"/>
+ <reference key="NSControlView" ref="63314511"/>
+ <int key="NSButtonFlags">-2033958657</int>
+ <int key="NSButtonFlags2">2</int>
+ <reference key="NSNormalImage" ref="968230828"/>
+ <reference key="NSAlternateContents" ref="802704698"/>
+ <reference key="NSKeyEquivalent" ref="802704698"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{488, 201}</string>
+ </object>
+ <string key="NSLabel">Authentication Information</string>
+ <reference key="NSColor" ref="876444531"/>
+ <reference key="NSTabView" ref="402198404"/>
+ </object>
+ <object class="NSTabViewItem" id="558859643">
+ <string key="NSIdentifier">3</string>
+ <reference key="NSView" ref="821532364"/>
+ <string key="NSLabel">Result</string>
+ <reference key="NSColor" ref="876444531"/>
+ <reference key="NSTabView" ref="402198404"/>
+ </object>
+ </object>
+ <reference key="NSSelectedTabViewItem" ref="558859643"/>
+ <reference key="NSFont" ref="604532625"/>
+ <int key="NSTvFlags">6</int>
+ <bool key="NSAllowTruncatedLabels">YES</bool>
+ <bool key="NSDrawsBackground">YES</bool>
+ </object>
+ </object>
+ <string key="NSFrameSize">{484, 199}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
+ <string key="NSMinSize">{239.32, 129}</string>
+ <string key="NSMaxSize">{3.40282e+38, 131}</string>
+ <reference key="NSFrameAutosaveName" ref="802704698"/>
+ </object>
+ <object class="NSArrayController" id="297584252">
+ <object class="NSMutableArray" key="NSDeclaredKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>servicePrincipalString</string>
+ <string>shortTimeRemainingString</string>
+ </object>
+ <string key="NSObjectClassName">KerberosCredential</string>
+ <bool key="NSEditable">YES</bool>
+ <object class="_NSManagedProxy" key="_NSManagedProxy"/>
+ <bool key="NSAvoidsEmptySelection">YES</bool>
+ <bool key="NSPreservesSelection">YES</bool>
+ <bool key="NSSelectsInsertedObjects">YES</bool>
+ <bool key="NSFilterRestrictsInsertion">YES</bool>
+ <bool key="NSClearsFilterPredicateOnInsertion">YES</bool>
+ </object>
+ <object class="NSArrayController" id="950399944">
+ <object class="NSMutableArray" key="NSDeclaredKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>credentialsArray</string>
+ <string>principalString</string>
+ <string>shortTimeRemainingString</string>
+ </object>
+ <string key="NSObjectClassName">KerberosCache</string>
+ <object class="_NSManagedProxy" key="_NSManagedProxy"/>
+ <bool key="NSAvoidsEmptySelection">YES</bool>
+ <bool key="NSPreservesSelection">YES</bool>
+ <bool key="NSSelectsInsertedObjects">YES</bool>
+ <bool key="NSFilterRestrictsInsertion">YES</bool>
+ <bool key="NSClearsFilterPredicateOnInsertion">YES</bool>
+ </object>
+ <object class="NSCustomObject" id="692063328">
+ <string key="NSClassName" id="1030909434">KerberosCacheCollection</string>
+ </object>
+ <object class="NSObjectController" id="597809582">
+ <object class="NSMutableArray" key="NSDeclaredKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>cachesArray</string>
+ </object>
+ <string key="NSObjectClassName">KerberosCacheCollection</string>
+ <object class="_NSManagedProxy" key="_NSManagedProxy"/>
+ </object>
+ <object class="NSMenu" id="161772700">
+ <string key="NSTitle">Menu</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="1064438280">
+ <reference key="NSMenu" ref="161772700"/>
+ <string type="base64-UTF8" key="NSTitle">VGlja2V0IE9wdGlvbnPigKY</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <object class="NSCustomResource" key="NSOnImage" id="567647476">
+ <reference key="NSClassName" ref="18406880"/>
+ <string key="NSResourceName">NSMenuCheckmark</string>
+ </object>
+ <object class="NSCustomResource" key="NSMixedImage" id="383973281">
+ <reference key="NSClassName" ref="18406880"/>
+ <string key="NSResourceName">NSMenuMixedState</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="466925177">
+ <reference key="NSMenu" ref="161772700"/>
+ <string type="base64-UTF8" key="NSTitle">Q2hhbmdlIFBhc3N3b3Jk4oCmA</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="278140056">
+ <reference key="NSMenu" ref="161772700"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="802704698"/>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="738897734">
+ <reference key="NSMenu" ref="161772700"/>
+ <string key="NSTitle">About Kerberos...</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ </object>
+ <reference key="NSName" ref="802704698"/>
+ </object>
+ <object class="NSMenu" id="728521747">
+ <string key="NSTitle">Authentication</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="914044585">
+ <reference key="NSMenu" ref="728521747"/>
+ <string key="NSTitle" id="977452246">KerberosAgent</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="502115125">
+ <reference key="NSTitle" ref="977452246"/>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="1042628752">
+ <reference key="NSMenu" ref="502115125"/>
+ <string key="NSTitle">About KerberosAgent</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="274166331">
+ <reference key="NSMenu" ref="502115125"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="802704698"/>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="538085610">
+ <reference key="NSMenu" ref="502115125"/>
+ <string type="base64-UTF8" key="NSTitle">UHJlZmVyZW5jZXPigKY</string>
+ <string key="NSKeyEquiv">,</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="938929997">
+ <reference key="NSMenu" ref="502115125"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="802704698"/>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="799169684">
+ <reference key="NSMenu" ref="502115125"/>
+ <string key="NSTitle">Services</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="243149938">
+ <object class="NSMutableString" key="NSTitle">
+ <characters key="NS.bytes">Services</characters>
+ </object>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <string key="NSName">_NSServicesMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="602001654">
+ <reference key="NSMenu" ref="502115125"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="802704698"/>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="584259263">
+ <reference key="NSMenu" ref="502115125"/>
+ <string key="NSTitle">Hide KerberosAgent</string>
+ <string key="NSKeyEquiv" id="55220401">h</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="929814071">
+ <reference key="NSMenu" ref="502115125"/>
+ <string key="NSTitle">Hide Others</string>
+ <reference key="NSKeyEquiv" ref="55220401"/>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="939420081">
+ <reference key="NSMenu" ref="502115125"/>
+ <string key="NSTitle">Show All</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="152776582">
+ <reference key="NSMenu" ref="502115125"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="802704698"/>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="230900097">
+ <reference key="NSMenu" ref="502115125"/>
+ <string key="NSTitle">Quit KerberosAgent</string>
+ <string key="NSKeyEquiv">q</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ </object>
+ <string key="NSName">_NSAppleMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="896694755">
+ <reference key="NSMenu" ref="728521747"/>
+ <string key="NSTitle" id="394480076">Edit</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="110659800">
+ <reference key="NSTitle" ref="394480076"/>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="926431453">
+ <reference key="NSMenu" ref="110659800"/>
+ <string key="NSTitle">Undo</string>
+ <string key="NSKeyEquiv">z</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="343562382">
+ <reference key="NSMenu" ref="110659800"/>
+ <string key="NSTitle">Redo</string>
+ <string key="NSKeyEquiv">Z</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="567302077">
+ <reference key="NSMenu" ref="110659800"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="802704698"/>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="560099369">
+ <reference key="NSMenu" ref="110659800"/>
+ <string key="NSTitle">Cut</string>
+ <string key="NSKeyEquiv">x</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="231472735">
+ <reference key="NSMenu" ref="110659800"/>
+ <string key="NSTitle">Copy</string>
+ <string key="NSKeyEquiv">c</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="558779467">
+ <reference key="NSMenu" ref="110659800"/>
+ <string key="NSTitle">Paste</string>
+ <string key="NSKeyEquiv">v</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="833503552">
+ <reference key="NSMenu" ref="110659800"/>
+ <string key="NSTitle">Paste and Match Style</string>
+ <string key="NSKeyEquiv">V</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="752289593">
+ <reference key="NSMenu" ref="110659800"/>
+ <string key="NSTitle">Delete</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="316589196">
+ <reference key="NSMenu" ref="110659800"/>
+ <string key="NSTitle">Select All</string>
+ <string key="NSKeyEquiv">a</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="59830132">
+ <reference key="NSMenu" ref="728521747"/>
+ <string key="NSTitle" id="1054504489">Window</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="1060193503">
+ <object class="NSMutableString" key="NSTitle">
+ <characters key="NS.bytes">Window</characters>
+ </object>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="816076202">
+ <reference key="NSMenu" ref="1060193503"/>
+ <string key="NSTitle">Close</string>
+ <string key="NSKeyEquiv">w</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="786942921">
+ <reference key="NSMenu" ref="1060193503"/>
+ <string key="NSTitle">Minimize</string>
+ <string key="NSKeyEquiv">m</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="195483115">
+ <reference key="NSMenu" ref="1060193503"/>
+ <string key="NSTitle">Zoom</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="408248079">
+ <reference key="NSMenu" ref="1060193503"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="802704698"/>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ <object class="NSMenuItem" id="746994503">
+ <reference key="NSMenu" ref="1060193503"/>
+ <string key="NSTitle">Bring All to Front</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ </object>
+ <string key="NSName">_NSWindowsMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="80172760">
+ <reference key="NSMenu" ref="728521747"/>
+ <string key="NSTitle">Help</string>
+ <reference key="NSKeyEquiv" ref="802704698"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="237751743">
+ <object class="NSMutableString" key="NSTitle">
+ <characters key="NS.bytes">Help</characters>
+ </object>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="100873261">
+ <reference key="NSMenu" ref="237751743"/>
+ <string key="NSTitle">KerberosAgent Help</string>
+ <string key="NSKeyEquiv">?</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="567647476"/>
+ <reference key="NSMixedImage" ref="383973281"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ <string key="NSName">_NSMainMenu</string>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">selectNextTabViewItem:</string>
+ <reference key="source" ref="402198404"/>
+ <reference key="destination" ref="725810597"/>
+ </object>
+ <int key="connectionID">35</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">selectNextTabViewItem:</string>
+ <reference key="source" ref="402198404"/>
+ <reference key="destination" ref="67140815"/>
+ </object>
+ <int key="connectionID">65</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">selectPreviousTabViewItem:</string>
+ <reference key="source" ref="402198404"/>
+ <reference key="destination" ref="142035750"/>
+ </object>
+ <int key="connectionID">66</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">selectPreviousTabViewItem:</string>
+ <reference key="source" ref="402198404"/>
+ <reference key="destination" ref="491153292"/>
+ </object>
+ <int key="connectionID">68</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performClose:</string>
+ <reference key="source" ref="224590347"/>
+ <reference key="destination" ref="720384657"/>
+ </object>
+ <int key="connectionID">300013</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label" id="556043823">value: arrangedObjects.principalString</string>
+ <reference key="source" ref="697375404"/>
+ <reference key="destination" ref="950399944"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="697375404"/>
+ <reference key="NSDestination" ref="950399944"/>
+ <reference key="NSLabel" ref="556043823"/>
+ <string key="NSBinding" id="148080267">value</string>
+ <string key="NSKeyPath">arrangedObjects.principalString</string>
+ <object class="NSDictionary" key="NSOptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string id="886848689">NSAllowsEditingMultipleValuesSelection</string>
+ <string id="378783107">NSAlwaysPresentsApplicationModalAlerts</string>
+ <string id="215220083">NSConditionallySetsEditable</string>
+ <string id="273405183">NSConditionallySetsEnabled</string>
+ <string id="520817857">NSContinuouslyUpdatesValue</string>
+ <string id="831553551">NSCreatesSortDescriptor</string>
+ <string id="341111534">NSMultipleValuesPlaceholder</string>
+ <string id="584131368">NSNoSelectionPlaceholder</string>
+ <string id="726040556">NSNotApplicablePlaceholder</string>
+ <string id="899970177">NSNullPlaceholder</string>
+ <string id="791828350">NSRaisesForNotApplicableKeys</string>
+ <string id="887810258">NSValidatesImmediately</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="0" id="6"/>
+ <reference ref="6"/>
+ <integer value="1" id="5"/>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <reference ref="5"/>
+ <string id="715781285"/>
+ <reference ref="715781285"/>
+ <reference ref="715781285"/>
+ <reference ref="715781285"/>
+ <reference ref="5"/>
+ <reference ref="6"/>
+ </object>
+ </object>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">300026</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label" id="139491530">value: arrangedObjects.shortTimeRemainingString</string>
+ <reference key="source" ref="1004662124"/>
+ <reference key="destination" ref="950399944"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="1004662124"/>
+ <reference key="NSDestination" ref="950399944"/>
+ <reference key="NSLabel" ref="139491530"/>
+ <reference key="NSBinding" ref="148080267"/>
+ <string key="NSKeyPath">arrangedObjects.shortTimeRemainingString</string>
+ <object class="NSDictionary" key="NSOptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="886848689"/>
+ <reference ref="378783107"/>
+ <reference ref="215220083"/>
+ <reference ref="273405183"/>
+ <reference ref="520817857"/>
+ <reference ref="831553551"/>
+ <reference ref="341111534"/>
+ <reference ref="584131368"/>
+ <reference ref="726040556"/>
+ <reference ref="899970177"/>
+ <reference ref="791828350"/>
+ <reference ref="887810258"/>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <reference ref="5"/>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <reference ref="715781285"/>
+ <reference ref="715781285"/>
+ <reference ref="715781285"/>
+ <reference ref="715781285"/>
+ <reference ref="5"/>
+ <reference ref="6"/>
+ </object>
+ </object>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">300027</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label" id="542590181">menu</string>
+ <reference key="source" ref="909400991"/>
+ <reference key="destination" ref="161772700"/>
+ </object>
+ <int key="connectionID">300036</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label" id="102057808">popupMenu</string>
+ <reference key="source" ref="909400991"/>
+ <reference key="destination" ref="161772700"/>
+ </object>
+ <int key="connectionID">300037</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label" id="393875829">nextKeyView</string>
+ <reference key="source" ref="409805769"/>
+ <reference key="destination" ref="400442477"/>
+ </object>
+ <int key="connectionID">300038</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <reference key="label" ref="393875829"/>
+ <reference key="source" ref="400442477"/>
+ <reference key="destination" ref="409805769"/>
+ </object>
+ <int key="connectionID">300039</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <reference key="label" ref="102057808"/>
+ <reference key="source" ref="63314511"/>
+ <reference key="destination" ref="161772700"/>
+ </object>
+ <int key="connectionID">300040</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <reference key="label" ref="542590181"/>
+ <reference key="source" ref="63314511"/>
+ <reference key="destination" ref="161772700"/>
+ </object>
+ <int key="connectionID">300041</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label" id="604171933">content</string>
+ <reference key="source" ref="297584252"/>
+ <reference key="destination" ref="950399944"/>
+ </object>
+ <int key="connectionID">300042</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <reference key="label" ref="604171933"/>
+ <reference key="source" ref="597809582"/>
+ <reference key="destination" ref="692063328"/>
+ </object>
+ <int key="connectionID">300043</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <reference key="label" ref="604171933"/>
+ <reference key="source" ref="950399944"/>
+ <reference key="destination" ref="597809582"/>
+ </object>
+ <int key="connectionID">300044</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hide:</string>
+ <reference key="source" ref="714830734"/>
+ <reference key="destination" ref="584259263"/>
+ </object>
+ <int key="connectionID">300099</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hideOtherApplications:</string>
+ <reference key="source" ref="714830734"/>
+ <reference key="destination" ref="929814071"/>
+ </object>
+ <int key="connectionID">300100</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">unhide:</string>
+ <reference key="source" ref="714830734"/>
+ <reference key="destination" ref="939420081"/>
+ </object>
+ <int key="connectionID">300101</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">terminate:</string>
+ <reference key="source" ref="714830734"/>
+ <reference key="destination" ref="230900097"/>
+ </object>
+ <int key="connectionID">300102</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performClose:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="816076202"/>
+ </object>
+ <int key="connectionID">300104</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performMiniaturize:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="786942921"/>
+ </object>
+ <int key="connectionID">300105</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performZoom:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="195483115"/>
+ </object>
+ <int key="connectionID">300106</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">arrangeInFront:</string>
+ <reference key="source" ref="714830734"/>
+ <reference key="destination" ref="746994503"/>
+ </object>
+ <int key="connectionID">300107</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">undo:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="926431453"/>
+ </object>
+ <int key="connectionID">300108</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">redo:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="343562382"/>
+ </object>
+ <int key="connectionID">300109</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">cut:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="560099369"/>
+ </object>
+ <int key="connectionID">300110</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">copy:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="231472735"/>
+ </object>
+ <int key="connectionID">300111</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">paste:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="558779467"/>
+ </object>
+ <int key="connectionID">300112</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">pasteAsPlainText:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="833503552"/>
+ </object>
+ <int key="connectionID">300113</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">delete:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="752289593"/>
+ </object>
+ <int key="connectionID">300114</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">selectAll:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="316589196"/>
+ </object>
+ <int key="connectionID">300115</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showHelp:</string>
+ <reference key="source" ref="553445653"/>
+ <reference key="destination" ref="100873261"/>
+ </object>
+ <int key="connectionID">300116</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontStandardAboutPanel:</string>
+ <reference key="source" ref="262677138"/>
+ <reference key="destination" ref="1042628752"/>
+ </object>
+ <int key="connectionID">300117</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="1000842439"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="262677138"/>
+ <reference key="parent" ref="0"/>
+ <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="553445653"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="224590347"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="928852707"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <reference key="objectName" ref="1054504489"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">6</int>
+ <reference key="object" ref="928852707"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="856695188"/>
+ <reference ref="499468804"/>
+ <reference ref="147207906"/>
+ <reference ref="426244837"/>
+ <reference ref="505388869"/>
+ <reference ref="616352993"/>
+ </object>
+ <reference key="parent" ref="224590347"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">7</int>
+ <reference key="object" ref="856695188"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="320974445"/>
+ </object>
+ <reference key="parent" ref="928852707"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">8</int>
+ <reference key="object" ref="499468804"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="82820472"/>
+ </object>
+ <reference key="parent" ref="928852707"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">9</int>
+ <reference key="object" ref="147207906"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="988096643"/>
+ <reference ref="80966883"/>
+ <reference ref="564144656"/>
+ <reference ref="401017936"/>
+ </object>
+ <reference key="parent" ref="928852707"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">10</int>
+ <reference key="object" ref="988096643"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="697375404"/>
+ <reference ref="1004662124"/>
+ </object>
+ <reference key="parent" ref="147207906"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">11</int>
+ <reference key="object" ref="697375404"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="325541546"/>
+ </object>
+ <reference key="parent" ref="988096643"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">18</int>
+ <reference key="object" ref="1004662124"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="618557697"/>
+ </object>
+ <reference key="parent" ref="988096643"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">15</int>
+ <reference key="object" ref="426244837"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="686991406"/>
+ </object>
+ <reference key="parent" ref="928852707"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">16</int>
+ <reference key="object" ref="505388869"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="720384657"/>
+ </object>
+ <reference key="parent" ref="928852707"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">17</int>
+ <reference key="object" ref="616352993"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="923350128"/>
+ </object>
+ <reference key="parent" ref="928852707"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">19</int>
+ <reference key="object" ref="236877202"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="632526042"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Window1</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">20</int>
+ <reference key="object" ref="632526042"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="402198404"/>
+ </object>
+ <reference key="parent" ref="236877202"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">21</int>
+ <reference key="object" ref="402198404"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="328078317"/>
+ <reference ref="433865568"/>
+ <reference ref="558859643"/>
+ </object>
+ <reference key="parent" ref="632526042"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">22</int>
+ <reference key="object" ref="328078317"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="657191530"/>
+ </object>
+ <reference key="parent" ref="402198404"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">23</int>
+ <reference key="object" ref="657191530"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="92949448"/>
+ <reference ref="506042805"/>
+ <reference ref="67140815"/>
+ <reference ref="142035750"/>
+ <reference ref="616334468"/>
+ <reference ref="67707351"/>
+ <reference ref="63314511"/>
+ </object>
+ <reference key="parent" ref="328078317"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">43</int>
+ <reference key="object" ref="92949448"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="193754575"/>
+ </object>
+ <reference key="parent" ref="657191530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">45</int>
+ <reference key="object" ref="506042805"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="664764666"/>
+ </object>
+ <reference key="parent" ref="657191530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">47</int>
+ <reference key="object" ref="67140815"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="646394101"/>
+ </object>
+ <reference key="parent" ref="657191530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">48</int>
+ <reference key="object" ref="142035750"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1009827779"/>
+ </object>
+ <reference key="parent" ref="657191530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">49</int>
+ <reference key="object" ref="616334468"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="377963764"/>
+ </object>
+ <reference key="parent" ref="657191530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">50</int>
+ <reference key="object" ref="67707351"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="841876216"/>
+ </object>
+ <reference key="parent" ref="657191530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">24</int>
+ <reference key="object" ref="433865568"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="267285695"/>
+ </object>
+ <reference key="parent" ref="402198404"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">25</int>
+ <reference key="object" ref="267285695"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="54265178"/>
+ <reference ref="8788833"/>
+ <reference ref="409805769"/>
+ <reference ref="176276299"/>
+ <reference ref="400442477"/>
+ <reference ref="566752045"/>
+ <reference ref="725810597"/>
+ <reference ref="909400991"/>
+ </object>
+ <reference key="parent" ref="433865568"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">26</int>
+ <reference key="object" ref="54265178"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="683080457"/>
+ </object>
+ <reference key="parent" ref="267285695"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">27</int>
+ <reference key="object" ref="8788833"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="230651394"/>
+ </object>
+ <reference key="parent" ref="267285695"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">28</int>
+ <reference key="object" ref="409805769"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="111694776"/>
+ </object>
+ <reference key="parent" ref="267285695"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">29</int>
+ <reference key="object" ref="176276299"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="169436004"/>
+ </object>
+ <reference key="parent" ref="267285695"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">31</int>
+ <reference key="object" ref="400442477"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="459624661"/>
+ </object>
+ <reference key="parent" ref="267285695"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">32</int>
+ <reference key="object" ref="566752045"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="462123130"/>
+ </object>
+ <reference key="parent" ref="267285695"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">33</int>
+ <reference key="object" ref="725810597"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="670473243"/>
+ </object>
+ <reference key="parent" ref="267285695"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">59</int>
+ <reference key="object" ref="558859643"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="821532364"/>
+ </object>
+ <reference key="parent" ref="402198404"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">60</int>
+ <reference key="object" ref="821532364"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="487636925"/>
+ <reference ref="144384471"/>
+ <reference ref="681150857"/>
+ <reference ref="351897359"/>
+ <reference ref="491153292"/>
+ </object>
+ <reference key="parent" ref="558859643"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">61</int>
+ <reference key="object" ref="487636925"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1002938556"/>
+ </object>
+ <reference key="parent" ref="821532364"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">62</int>
+ <reference key="object" ref="144384471"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="140668900"/>
+ </object>
+ <reference key="parent" ref="821532364"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">63</int>
+ <reference key="object" ref="681150857"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="987061439"/>
+ </object>
+ <reference key="parent" ref="821532364"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">64</int>
+ <reference key="object" ref="351897359"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="30067995"/>
+ </object>
+ <reference key="parent" ref="821532364"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">67</int>
+ <reference key="object" ref="491153292"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="403345038"/>
+ </object>
+ <reference key="parent" ref="821532364"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100007</int>
+ <reference key="object" ref="320974445"/>
+ <reference key="parent" ref="856695188"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100008</int>
+ <reference key="object" ref="82820472"/>
+ <reference key="parent" ref="499468804"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100015</int>
+ <reference key="object" ref="686991406"/>
+ <reference key="parent" ref="426244837"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100016</int>
+ <reference key="object" ref="720384657"/>
+ <reference key="parent" ref="505388869"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100017</int>
+ <reference key="object" ref="923350128"/>
+ <reference key="parent" ref="616352993"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100043</int>
+ <reference key="object" ref="193754575"/>
+ <reference key="parent" ref="92949448"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100045</int>
+ <reference key="object" ref="664764666"/>
+ <reference key="parent" ref="506042805"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100047</int>
+ <reference key="object" ref="646394101"/>
+ <reference key="parent" ref="67140815"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100048</int>
+ <reference key="object" ref="1009827779"/>
+ <reference key="parent" ref="142035750"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100049</int>
+ <reference key="object" ref="377963764"/>
+ <reference key="parent" ref="616334468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100050</int>
+ <reference key="object" ref="841876216"/>
+ <reference key="parent" ref="67707351"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100026</int>
+ <reference key="object" ref="683080457"/>
+ <reference key="parent" ref="54265178"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100027</int>
+ <reference key="object" ref="230651394"/>
+ <reference key="parent" ref="8788833"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100028</int>
+ <reference key="object" ref="111694776"/>
+ <reference key="parent" ref="409805769"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100029</int>
+ <reference key="object" ref="169436004"/>
+ <reference key="parent" ref="176276299"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100031</int>
+ <reference key="object" ref="459624661"/>
+ <reference key="parent" ref="400442477"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100032</int>
+ <reference key="object" ref="462123130"/>
+ <reference key="parent" ref="566752045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100033</int>
+ <reference key="object" ref="670473243"/>
+ <reference key="parent" ref="725810597"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100061</int>
+ <reference key="object" ref="1002938556"/>
+ <reference key="parent" ref="487636925"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100062</int>
+ <reference key="object" ref="140668900"/>
+ <reference key="parent" ref="144384471"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100063</int>
+ <reference key="object" ref="987061439"/>
+ <reference key="parent" ref="681150857"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100064</int>
+ <reference key="object" ref="30067995"/>
+ <reference key="parent" ref="351897359"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100067</int>
+ <reference key="object" ref="403345038"/>
+ <reference key="parent" ref="491153292"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100009</int>
+ <reference key="object" ref="80966883"/>
+ <reference key="parent" ref="147207906"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">200009</int>
+ <reference key="object" ref="564144656"/>
+ <reference key="parent" ref="147207906"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300009</int>
+ <reference key="object" ref="401017936"/>
+ <reference key="parent" ref="147207906"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="714830734"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300010</int>
+ <reference key="object" ref="63314511"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="955946369"/>
+ </object>
+ <reference key="parent" ref="657191530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300011</int>
+ <reference key="object" ref="955946369"/>
+ <reference key="parent" ref="63314511"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300018</int>
+ <reference key="object" ref="325541546"/>
+ <reference key="parent" ref="697375404"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300019</int>
+ <reference key="object" ref="618557697"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="1004662124"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300021</int>
+ <reference key="object" ref="297584252"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">CredentialsController</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300022</int>
+ <reference key="object" ref="950399944"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">CachesController</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300023</int>
+ <reference key="object" ref="692063328"/>
+ <reference key="parent" ref="0"/>
+ <reference key="objectName" ref="1030909434"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300024</int>
+ <reference key="object" ref="597809582"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">CacheCollectionController</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300028</int>
+ <reference key="object" ref="909400991"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="384105704"/>
+ </object>
+ <reference key="parent" ref="267285695"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300029</int>
+ <reference key="object" ref="384105704"/>
+ <reference key="parent" ref="909400991"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300030</int>
+ <reference key="object" ref="161772700"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="738897734"/>
+ <reference ref="278140056"/>
+ <reference ref="466925177"/>
+ <reference ref="1064438280"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">GearMenu</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300031</int>
+ <reference key="object" ref="738897734"/>
+ <reference key="parent" ref="161772700"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300032</int>
+ <reference key="object" ref="278140056"/>
+ <reference key="parent" ref="161772700"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300033</int>
+ <reference key="object" ref="466925177"/>
+ <reference key="parent" ref="161772700"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300034</int>
+ <reference key="object" ref="1064438280"/>
+ <reference key="parent" ref="161772700"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300045</int>
+ <reference key="object" ref="728521747"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="896694755"/>
+ <reference ref="80172760"/>
+ <reference ref="914044585"/>
+ <reference ref="59830132"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">MainMenu</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300047</int>
+ <reference key="object" ref="896694755"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="110659800"/>
+ </object>
+ <reference key="parent" ref="728521747"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300048</int>
+ <reference key="object" ref="80172760"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="237751743"/>
+ </object>
+ <reference key="parent" ref="728521747"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300049</int>
+ <reference key="object" ref="914044585"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="502115125"/>
+ </object>
+ <reference key="parent" ref="728521747"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300050</int>
+ <reference key="object" ref="59830132"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1060193503"/>
+ </object>
+ <reference key="parent" ref="728521747"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300051</int>
+ <reference key="object" ref="1060193503"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="786942921"/>
+ <reference ref="408248079"/>
+ <reference ref="195483115"/>
+ <reference ref="816076202"/>
+ <reference ref="746994503"/>
+ </object>
+ <reference key="parent" ref="59830132"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300052</int>
+ <reference key="object" ref="786942921"/>
+ <reference key="parent" ref="1060193503"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300053</int>
+ <reference key="object" ref="408248079"/>
+ <reference key="parent" ref="1060193503"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300055</int>
+ <reference key="object" ref="195483115"/>
+ <reference key="parent" ref="1060193503"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300057</int>
+ <reference key="object" ref="816076202"/>
+ <reference key="parent" ref="1060193503"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300058</int>
+ <reference key="object" ref="746994503"/>
+ <reference key="parent" ref="1060193503"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300059</int>
+ <reference key="object" ref="502115125"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="274166331"/>
+ <reference ref="939420081"/>
+ <reference ref="152776582"/>
+ <reference ref="929814071"/>
+ <reference ref="602001654"/>
+ <reference ref="938929997"/>
+ <reference ref="230900097"/>
+ <reference ref="584259263"/>
+ <reference ref="799169684"/>
+ <reference ref="538085610"/>
+ <reference ref="1042628752"/>
+ </object>
+ <reference key="parent" ref="914044585"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300060</int>
+ <reference key="object" ref="274166331"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300061</int>
+ <reference key="object" ref="939420081"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300062</int>
+ <reference key="object" ref="152776582"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300063</int>
+ <reference key="object" ref="929814071"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300064</int>
+ <reference key="object" ref="602001654"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300065</int>
+ <reference key="object" ref="938929997"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300066</int>
+ <reference key="object" ref="230900097"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300067</int>
+ <reference key="object" ref="584259263"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300068</int>
+ <reference key="object" ref="799169684"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="243149938"/>
+ </object>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300069</int>
+ <reference key="object" ref="538085610"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300070</int>
+ <reference key="object" ref="1042628752"/>
+ <reference key="parent" ref="502115125"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300071</int>
+ <reference key="object" ref="243149938"/>
+ <reference key="parent" ref="799169684"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300072</int>
+ <reference key="object" ref="237751743"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="100873261"/>
+ </object>
+ <reference key="parent" ref="80172760"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300073</int>
+ <reference key="object" ref="100873261"/>
+ <reference key="parent" ref="237751743"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300074</int>
+ <reference key="object" ref="110659800"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="833503552"/>
+ <reference ref="343562382"/>
+ <reference ref="316589196"/>
+ <reference ref="558779467"/>
+ <reference ref="752289593"/>
+ <reference ref="560099369"/>
+ <reference ref="926431453"/>
+ <reference ref="231472735"/>
+ <reference ref="567302077"/>
+ </object>
+ <reference key="parent" ref="896694755"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300076</int>
+ <reference key="object" ref="833503552"/>
+ <reference key="parent" ref="110659800"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300078</int>
+ <reference key="object" ref="343562382"/>
+ <reference key="parent" ref="110659800"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300079</int>
+ <reference key="object" ref="316589196"/>
+ <reference key="parent" ref="110659800"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300080</int>
+ <reference key="object" ref="558779467"/>
+ <reference key="parent" ref="110659800"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300081</int>
+ <reference key="object" ref="752289593"/>
+ <reference key="parent" ref="110659800"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300082</int>
+ <reference key="object" ref="560099369"/>
+ <reference key="parent" ref="110659800"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300083</int>
+ <reference key="object" ref="926431453"/>
+ <reference key="parent" ref="110659800"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300084</int>
+ <reference key="object" ref="231472735"/>
+ <reference key="parent" ref="110659800"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300085</int>
+ <reference key="object" ref="567302077"/>
+ <reference key="parent" ref="110659800"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.IBPluginDependency</string>
+ <string>-2.IBPluginDependency</string>
+ <string>10.IBPluginDependency</string>
+ <string>10.ImportedFromIB2</string>
+ <string>100009.IBShouldRemoveOnLegacySave</string>
+ <string>11.IBPluginDependency</string>
+ <string>11.ImportedFromIB2</string>
+ <string>15.IBPluginDependency</string>
+ <string>15.ImportedFromIB2</string>
+ <string>16.IBPluginDependency</string>
+ <string>16.ImportedFromIB2</string>
+ <string>17.IBPluginDependency</string>
+ <string>17.ImportedFromIB2</string>
+ <string>18.IBPluginDependency</string>
+ <string>18.ImportedFromIB2</string>
+ <string>19.IBPluginDependency</string>
+ <string>19.IBWindowTemplateEditedContentRect</string>
+ <string>19.ImportedFromIB2</string>
+ <string>19.NSWindowTemplate.visibleAtLaunch</string>
+ <string>19.editorWindowContentRectSynchronizationRect</string>
+ <string>19.windowTemplate.hasMaxSize</string>
+ <string>19.windowTemplate.hasMinSize</string>
+ <string>19.windowTemplate.maxSize</string>
+ <string>19.windowTemplate.minSize</string>
+ <string>20.IBPluginDependency</string>
+ <string>20.ImportedFromIB2</string>
+ <string>200009.IBShouldRemoveOnLegacySave</string>
+ <string>21.IBPluginDependency</string>
+ <string>21.ImportedFromIB2</string>
+ <string>22.IBPluginDependency</string>
+ <string>22.ImportedFromIB2</string>
+ <string>23.IBPluginDependency</string>
+ <string>23.ImportedFromIB2</string>
+ <string>24.IBPluginDependency</string>
+ <string>24.ImportedFromIB2</string>
+ <string>25.IBPluginDependency</string>
+ <string>25.ImportedFromIB2</string>
+ <string>26.IBPluginDependency</string>
+ <string>26.ImportedFromIB2</string>
+ <string>27.IBPluginDependency</string>
+ <string>27.ImportedFromIB2</string>
+ <string>28.IBPluginDependency</string>
+ <string>28.ImportedFromIB2</string>
+ <string>29.IBPluginDependency</string>
+ <string>29.ImportedFromIB2</string>
+ <string>300009.IBShouldRemoveOnLegacySave</string>
+ <string>300010.CustomClassName</string>
+ <string>300010.IBPluginDependency</string>
+ <string>300010.ImportedFromIB2</string>
+ <string>300018.IBPluginDependency</string>
+ <string>300019.IBPluginDependency</string>
+ <string>300021.IBPluginDependency</string>
+ <string>300021.ImportedFromIB2</string>
+ <string>300022.IBPluginDependency</string>
+ <string>300022.ImportedFromIB2</string>
+ <string>300023.IBPluginDependency</string>
+ <string>300023.ImportedFromIB2</string>
+ <string>300024.IBPluginDependency</string>
+ <string>300024.ImportedFromIB2</string>
+ <string>300028.CustomClassName</string>
+ <string>300028.IBPluginDependency</string>
+ <string>300028.ImportedFromIB2</string>
+ <string>300030.IBPluginDependency</string>
+ <string>300030.ImportedFromIB2</string>
+ <string>300031.IBPluginDependency</string>
+ <string>300031.ImportedFromIB2</string>
+ <string>300032.IBPluginDependency</string>
+ <string>300032.ImportedFromIB2</string>
+ <string>300033.IBPluginDependency</string>
+ <string>300033.ImportedFromIB2</string>
+ <string>300034.IBPluginDependency</string>
+ <string>300034.ImportedFromIB2</string>
+ <string>300045.IBPluginDependency</string>
+ <string>300045.ImportedFromIB2</string>
+ <string>300045.editorWindowContentRectSynchronizationRect</string>
+ <string>300047.IBPluginDependency</string>
+ <string>300047.ImportedFromIB2</string>
+ <string>300048.IBPluginDependency</string>
+ <string>300048.ImportedFromIB2</string>
+ <string>300049.IBPluginDependency</string>
+ <string>300049.ImportedFromIB2</string>
+ <string>300050.IBPluginDependency</string>
+ <string>300050.ImportedFromIB2</string>
+ <string>300051.IBPluginDependency</string>
+ <string>300051.ImportedFromIB2</string>
+ <string>300051.editorWindowContentRectSynchronizationRect</string>
+ <string>300052.IBPluginDependency</string>
+ <string>300052.ImportedFromIB2</string>
+ <string>300053.IBPluginDependency</string>
+ <string>300053.ImportedFromIB2</string>
+ <string>300055.IBPluginDependency</string>
+ <string>300055.ImportedFromIB2</string>
+ <string>300057.IBPluginDependency</string>
+ <string>300057.ImportedFromIB2</string>
+ <string>300058.IBPluginDependency</string>
+ <string>300058.ImportedFromIB2</string>
+ <string>300059.IBPluginDependency</string>
+ <string>300059.ImportedFromIB2</string>
+ <string>300059.editorWindowContentRectSynchronizationRect</string>
+ <string>300060.IBPluginDependency</string>
+ <string>300060.ImportedFromIB2</string>
+ <string>300061.IBPluginDependency</string>
+ <string>300061.ImportedFromIB2</string>
+ <string>300062.IBPluginDependency</string>
+ <string>300062.ImportedFromIB2</string>
+ <string>300063.IBPluginDependency</string>
+ <string>300063.ImportedFromIB2</string>
+ <string>300064.IBPluginDependency</string>
+ <string>300064.ImportedFromIB2</string>
+ <string>300065.IBPluginDependency</string>
+ <string>300065.ImportedFromIB2</string>
+ <string>300066.IBPluginDependency</string>
+ <string>300066.ImportedFromIB2</string>
+ <string>300067.IBPluginDependency</string>
+ <string>300067.ImportedFromIB2</string>
+ <string>300068.IBPluginDependency</string>
+ <string>300068.ImportedFromIB2</string>
+ <string>300069.IBPluginDependency</string>
+ <string>300069.ImportedFromIB2</string>
+ <string>300070.IBPluginDependency</string>
+ <string>300070.ImportedFromIB2</string>
+ <string>300071.IBPluginDependency</string>
+ <string>300071.ImportedFromIB2</string>
+ <string>300071.editorWindowContentRectSynchronizationRect</string>
+ <string>300072.IBPluginDependency</string>
+ <string>300072.ImportedFromIB2</string>
+ <string>300072.editorWindowContentRectSynchronizationRect</string>
+ <string>300073.IBPluginDependency</string>
+ <string>300073.ImportedFromIB2</string>
+ <string>300074.IBPluginDependency</string>
+ <string>300074.ImportedFromIB2</string>
+ <string>300074.editorWindowContentRectSynchronizationRect</string>
+ <string>300076.IBPluginDependency</string>
+ <string>300076.ImportedFromIB2</string>
+ <string>300078.IBPluginDependency</string>
+ <string>300078.ImportedFromIB2</string>
+ <string>300079.IBPluginDependency</string>
+ <string>300079.ImportedFromIB2</string>
+ <string>300080.IBPluginDependency</string>
+ <string>300080.ImportedFromIB2</string>
+ <string>300081.IBPluginDependency</string>
+ <string>300081.ImportedFromIB2</string>
+ <string>300082.IBPluginDependency</string>
+ <string>300082.ImportedFromIB2</string>
+ <string>300083.IBPluginDependency</string>
+ <string>300083.ImportedFromIB2</string>
+ <string>300084.IBPluginDependency</string>
+ <string>300084.ImportedFromIB2</string>
+ <string>300085.IBPluginDependency</string>
+ <string>300085.ImportedFromIB2</string>
+ <string>31.IBPluginDependency</string>
+ <string>31.ImportedFromIB2</string>
+ <string>32.IBPluginDependency</string>
+ <string>32.ImportedFromIB2</string>
+ <string>33.IBPluginDependency</string>
+ <string>33.ImportedFromIB2</string>
+ <string>43.IBPluginDependency</string>
+ <string>43.ImportedFromIB2</string>
+ <string>45.CustomClassName</string>
+ <string>45.IBPluginDependency</string>
+ <string>45.ImportedFromIB2</string>
+ <string>47.IBPluginDependency</string>
+ <string>47.ImportedFromIB2</string>
+ <string>48.IBPluginDependency</string>
+ <string>48.ImportedFromIB2</string>
+ <string>49.IBPluginDependency</string>
+ <string>49.ImportedFromIB2</string>
+ <string>5.IBPluginDependency</string>
+ <string>5.IBWindowTemplateEditedContentRect</string>
+ <string>5.ImportedFromIB2</string>
+ <string>5.NSWindowTemplate.visibleAtLaunch</string>
+ <string>5.editorWindowContentRectSynchronizationRect</string>
+ <string>5.windowTemplate.hasMaxSize</string>
+ <string>5.windowTemplate.hasMinSize</string>
+ <string>5.windowTemplate.maxSize</string>
+ <string>5.windowTemplate.minSize</string>
+ <string>50.IBPluginDependency</string>
+ <string>50.ImportedFromIB2</string>
+ <string>59.IBPluginDependency</string>
+ <string>59.ImportedFromIB2</string>
+ <string>6.IBPluginDependency</string>
+ <string>6.ImportedFromIB2</string>
+ <string>60.IBPluginDependency</string>
+ <string>60.ImportedFromIB2</string>
+ <string>61.IBPluginDependency</string>
+ <string>61.ImportedFromIB2</string>
+ <string>62.IBPluginDependency</string>
+ <string>62.ImportedFromIB2</string>
+ <string>63.IBPluginDependency</string>
+ <string>63.ImportedFromIB2</string>
+ <string>64.IBPluginDependency</string>
+ <string>64.ImportedFromIB2</string>
+ <string>67.IBPluginDependency</string>
+ <string>67.ImportedFromIB2</string>
+ <string>7.IBPluginDependency</string>
+ <string>7.ImportedFromIB2</string>
+ <string>8.IBPluginDependency</string>
+ <string>8.ImportedFromIB2</string>
+ <string>9.IBPluginDependency</string>
+ <string>9.ImportedFromIB2</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="147422244"/>
+ <reference ref="147422244"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <string>{{932, 664}, {484, 199}}</string>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>{{932, 664}, {484, 199}}</string>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>{3.40282e+38, 109}</string>
+ <string>{239.32, 107}</string>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>PopupButton</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string>PopupButton</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string id="473800332">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <reference ref="473800332"/>
+ <reference ref="5"/>
+ <reference ref="473800332"/>
+ <reference ref="5"/>
+ <reference ref="473800332"/>
+ <reference ref="5"/>
+ <reference ref="473800332"/>
+ <reference ref="5"/>
+ <string id="678993855">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string>{{21, 1069}, {314, 20}}</string>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <string>{{203, 976}, {197, 93}}</string>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <string>{{33, 886}, {240, 183}}</string>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <string>{{273, 1003}, {64, 6}}</string>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <string>{{274, 1046}, {211, 23}}</string>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <string>{{159, 896}, {253, 173}}</string>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="678993855"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <string>NSSecureTextField</string>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <string>{{503, 256}, {419, 465}}</string>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>{{503, 256}, {419, 465}}</string>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>{3.40282e+38, 3.40282e+38}</string>
+ <string>{213, 107}</string>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ <reference ref="147422244"/>
+ <reference ref="5"/>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">300117</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">PopupButton</string>
+ <string key="superclassName">NSButton</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <reference key="NS.key.0" ref="102057808"/>
+ <string key="NS.object.0">NSMenu</string>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <reference key="minorKey" ref="802704698"/>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">KerberosCacheCollection</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">../../../Common/Headers/KerberosCacheCollection.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">FirstResponder</string>
+ <nil key="superclassName"/>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.LastKnownRelativeProjectPath">../../../Projects/KerberosIdentityManagement.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ <object class="NSMutableData" key="IBDocument.RunnableNib">
+ <bytes key="NS.bytes">YnBsaXN0MDDUAAEAAgADAAQABQAGAAkAClgkdmVyc2lvblQkdG9wWSRhcmNoaXZlclgkb2JqZWN0cxIA
+AYag0QAHAAhdSUIub2JqZWN0ZGF0YYABXxAPTlNLZXllZEFyY2hpdmVyrxEDBAALAAwAMQA1ADYAPAA9
+AEMAWwBcAF0AYQBlAGgACwB1AH4AjgCXAJgAmQCaAJsAnACdAKEAogCwALUAtgC3ALoAvQDDAMwAzQDa
+ANsA4wDkAOcA8QDyAPMA+AD6AP8BAAEDAQcBCgEiASoBOQE9AVoBWwFjAW0BbgFxAXgBeQF8AYEBkwGa
+AZsBoAGjAagBqQGsAbUBtgG5AcMBygHLAdAB0QHUAd0B4QHmAecB6gHsAe0B8gHzAfYCAgIDAgQCBwIR
+AhICFgIXAhgCGwIkAiUCOAI5AjoCPAI/AkICSgJLAlMCVAJWAl4CXwJnAmgCagALAmsCbQJuAm8CcAJz
+AoACgQKCAoQChgALAo0CkQKiAqYCrgK2Ar8CwALIAskCywLWAt8C4ALpAu4C7wL4Av8DAAMBAwoDEgMT
+AxYDFwMfAyADIgMjAyQDKgM0AzUDOwNGA1ADWQNaA2IDZgNnA28DdgN3A38DgAOIA5IDlwOYA50DngOf
+A6cDqAOwAAsDsQPAA8IACwPUAAsD1QPZAKwD4gPoA+wD7gP3A/gD+wP+BAEEAgQJBAoEEgQTBBsEHAQe
+BCkCQQQqBCsENwQ6BD4EPwMiBEIEQwRGBE0ETgRTBF0EZgLfBG8EcwR9AQkEfgR/BIcEEgSOBJYEmASf
+BKAEqASqAu4EsQS4BLkEwATBBMgEyQQpBNIE0wMiBNwE3QTkBOUE5gToAAsCbQTpBOoE6wUQBRcFGAUc
+BSEFIgUmBTYFPAU9BT4FQgVDBUcFSAVLBUwFUQVWBVcFXgVlBWYFbQVuBXkFgAWBBYMFhAWHBYwFkwWY
+BZkFmgWeBaUFqQWqBasFrAWwBbcFuAW5BboFvwXABcQFywXMBc0F0QXYBdkF2gXbBd8F5gXqBesF7AXt
+BfIF+gX7BfwANQX/BgAGBAYLBgwGDQYOBhIGGQYaBhsGHwYmBicGKAYpBRcGLgYyBjkGOgY7BjwFIQZB
+BbkGRgZLBlAGYwZoBmkGagZrBm0GbwZ0Bn4GhAaFBmkGhgaHBokGigaPBpAGlAabBpwGnQaeBqMGqAat
+BrIGtga3BrgGuga8BsEGyAbJBsoGzwbWBtcG2AbZBt4G5QbmBucG7AbzBvQG9Qb6BrcG/QcBBwgHCQcK
+BwsHFwcYBxkHGgc3BzgHOQc6BzsHPAc9Bz4HPwdAB0EHQgCvAIcCOQdFB0gHSwdTB1QHVQdxB+gH7Qfu
+B/UAtgf/CAAIDggXCB4IHwggCCkIMgf/CDMIOAg6CD0IPghHCFAIUQhaB/8IWwhnCHAIeQf/CHoIfAiE
+CI0IjgiXB/8ImAiaCJ4InwihCRgJkAoICgkKCgoLCgwKDQoOCg8KEAoRChIKEwoUChUKFgoXChgKGQoa
+ChsKHAodCh4KHwogCiEKIgojCiQKJQomCicKKAopCioKKwosCi0KLgovCjAKMQoyCjMKNAo1CjYKNwo4
+CjkKOgo7CjwKPQBnCj4KPwpACkEKQgpDCkQKRQpGCkcKSApJCkoKSwpMCk0KTgpPClAKUQpSClMKVApV
+ClYKVwpYClkKWgpbClwKXQpeCl8KYAphCmIKYwpkCmUKZgpnCmgKaQpqCmsKbAptCm4KbwpwCnEKcgpz
+CnQKdQp2CncKeAp5CnoKgAqGCyALugu7C7wLvQu+C78LwAvBC8ILwwvEC8ULxgvHC8gLyQvKC8sA7gvM
+C80LzgvPC9AL0QvSC9ML1AvVC9YL1wvYC9kL2gvbAVEL3AvdC94L3wvgC+EL4gvjC+QL5QvmC+cL6Avp
+C+oL6wvsC+0L7gvvC/AL8QvyC/ML9Av1C/YAWAv3C/gL+Qv6C/sL/Av9C/4L/wwADAEMAgwDDAQMBQIM
+DAYMBwwIDAkMCgwLDAwMDQwODA8MEAwRDBIMEwwUDBUMFgwXAi8MGAwZDBoMGwwcDB0MHgwfDCAMIQwi
+DCMMJAPrDCUMJgwnDCgMKQwqDCsMLAwtDC4MLwwwDDEMMgwzDDQMNQw2DDcMOAw5DDoMOww8DD0MPgw/
+DEAMQQxCDEMMRAxFDEYMRwxIDEkMSgxLDE4MUQxUVSRudWxs3xASAA0ADgAPABAAEQASABMAFAAVABYA
+FwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwVk5TUm9vdFYk
+Y2xhc3NdTlNPYmplY3RzS2V5c18QD05TQ2xhc3Nlc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eU9pZHNW
+YWx1ZXNdTlNDb25uZWN0aW9uc1tOU05hbWVzS2V5c1tOU0ZyYW1ld29ya11OU0NsYXNzZXNLZXlzWk5T
+T2lkc0tleXNdTlNOYW1lc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eUNvbm5lY3RvcnNdTlNGb250TWFu
+YWdlcl8QEE5TVmlzaWJsZVdpbmRvd3NfEA9OU09iamVjdHNWYWx1ZXNfEBdOU0FjY2Vzc2liaWxpdHlP
+aWRzS2V5c1lOU05leHRPaWRcTlNPaWRzVmFsdWVzgAKBAwOBAcWBAmaBAwKBARCBAfCABYECZYECZ4EB
+8YEDAIAAgAaBAe+BAwESAASUVoECaNIADgAyADMANFtOU0NsYXNzTmFtZYAEgANdTlNBcHBsaWNhdGlv
+btIANwA4ADkAOlgkY2xhc3Nlc1okY2xhc3NuYW1logA6ADteTlNDdXN0b21PYmplY3RYTlNPYmplY3Rf
+EBBJQkNvY29hRnJhbWV3b3Jr0gAOAD4APwBAWk5TLm9iamVjdHOAGKIAQQBCgAeAftwARAAOAEUARgBH
+AEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFpcTlNXaW5kb3dWaWV3XE5TU2NyZWVu
+UmVjdF1OU1dpbmRvd1RpdGxlWU5TV1RGbGFnc11OU1dpbmRvd0NsYXNzXE5TV2luZG93UmVjdFlOU01h
+eFNpemVfEA9OU1dpbmRvd0JhY2tpbmdfEBFOU1dpbmRvd1N0eWxlTWFza1lOU01pblNpemVbTlNWaWV3
+Q2xhc3OADYB9gHqACRJweAAAgAqACIB8EAIQD4B7gAxfEBh7ezI3OSwgMzYzfSwgezQxOSwgNDY1fX1f
+EBpTZWxlY3QgYSBLZXJiZXJvcyBJZGVudGl0edIADgBeAF8AYFlOUy5zdHJpbmeAC1hOU1dpbmRvd9IA
+NwA4AGIAY6MAYwBkADtfEA9OU011dGFibGVTdHJpbmdYTlNTdHJpbmfSAA4AXgBfAGeAC1RWaWV31wBp
+AA4AagBrAGwAYABtAG4AbwBwAHEAcgBuAHRfEA9OU05leHRSZXNwb25kZXJaTlNTdWJ2aWV3c1hOU3ZG
+bGFnc1tOU0ZyYW1lU2l6ZVtOU1N1cGVydmlld4AOgHmADxEBAIB3gA6AeNIADgA+AHYAd4BSpgB4AHkA
+egB7AHwAfYAQgCGAMoBlgG2ActoAaQAOAH8AgACBAIIAawCDAGAAbQBPAIUAhgCHAIgAiQCKAIcAbgBP
+V05TRnJhbWVaTlNFZGl0YWJsZVZOU0NlbGxbTlNEcmFnVHlwZXNZTlNFbmFibGVkgA2AIIAZCYAagBER
+AQwJgA6ADdIADgA+AD8AkIAYpgCRAJIAkwCUAJUAloASgBOAFIAVgBaAF18QGUFwcGxlIFBERiBwYXN0
+ZWJvYXJkIHR5cGVfEBlBcHBsZSBQTkcgcGFzdGVib2FyZCB0eXBlXxAxTmVYVCBFbmNhcHN1bGF0ZWQg
+UG9zdFNjcmlwdCB2MS4yIHBhc3RlYm9hcmQgdHlwZV8QFU5TRmlsZW5hbWVzUGJvYXJkVHlwZV8QHk5l
+WFQgVElGRiB2NC4wIHBhc3RlYm9hcmQgdHlwZV8QGkFwcGxlIFBJQ1QgcGFzdGVib2FyZCB0eXBl0gA3
+ADgAngCfowCfAKAAO1xOU011dGFibGVTZXRVTlNTZXRfEBV7ezE3LCAzODZ9LCB7NjIsIDYyfX3YAKMA
+DgCkAKUApgCnAKgAqQCqAKsArACtAKwArACuAK9bTlNDZWxsRmxhZ3NXTlNTdHlsZVpOU0NvbnRlbnRz
+V05TQWxpZ25XTlNTY2FsZVxOU0NlbGxGbGFnczJaTlNBbmltYXRlcxIgAf4AgB8QAIAbEgIAAAAI0wAO
+ADIAsQCyALMAtF5OU1Jlc291cmNlTmFtZYAegByAHVdOU0ltYWdlXUtlcmJlcm9zQWdlbnTSADcAOAC4
+ALmiALkAO18QEE5TQ3VzdG9tUmVzb3VyY2XSADcAOAC7ALyjALwAgQA7W05TSW1hZ2VDZWxs0gA3ADgA
+vgC/pQC/AMAAwQDCADtbTlNJbWFnZVZpZXdZTlNDb250cm9sVk5TVmlld1tOU1Jlc3BvbmRlctgAaQAO
+AH8AgQBrAIMAYABtAE8AxQDGAMcAyACHAG4AT4ANgDGAIoAjEQEKCYAOgA1fEBZ7ezg0LCAzODZ9LCB7
+MzE4LCA0MH192ACjAA4AzgClAM8A0ACoANEA0gDTANQA1QDWAHkA2ADZXxARTlNCYWNrZ3JvdW5kQ29s
+b3JZTlNTdXBwb3J0XU5TQ29udHJvbFZpZXdbTlNUZXh0Q29sb3ISBAH+AIAwgCiAJIAlgCESEEAAAIAt
+XxAhUGxlYXNlIHNlbGVjdCBhIEtlcmJlcm9zIElkZW50aXR51AAOANwA3QDeAN8A4ADhAOJWTlNTaXpl
+Vk5TTmFtZVhOU2ZGbGFnc4AnI0AqAAAAAAAAgCYRBBRcTHVjaWRhR3JhbmRl0gA3ADgA5QDmogDmADtW
+TlNGb2501QAOAOgA6QDqAOsA7ADtAO4A7wDwV05TQ29sb3JcTlNDb2xvclNwYWNlW05TQ29sb3JOYW1l
+XU5TQ2F0YWxvZ05hbWWALIArEAaAKoApVlN5c3RlbVxjb250cm9sQ29sb3LTAA4A6QD0AOwA9gD3V05T
+V2hpdGWALBADSzAuNjY2NjY2NjkA0gA3ADgA+QDoogDoADvVAA4A6ADpAOoA6wDsAPwA7gD9APCALIAv
+gC6AKV8QEGNvbnRyb2xUZXh0Q29sb3LTAA4A6QD0AOwA9gECgCxCMADSADcAOAEEAQWkAQUBBgCBADtf
+EA9OU1RleHRGaWVsZENlbGxcTlNBY3Rpb25DZWxs0gA3ADgBCAEJpQEJAMAAwQDCADtbTlNUZXh0Rmll
+bGTfEA8AaQELAA4AfwEMAQ0BDgBqAQ8AawBgAG0BEAERARIATwEUARUBFgEXARgBGQEaARsBHABuAE8B
+HwEgASBbTlNIU2Nyb2xsZXJYTlNzRmxhZ3NcTlNDb3JuZXJWaWV3XxAQTlNIZWFkZXJDbGlwVmlld1xO
+U1Njcm9sbEFtdHNbTlNWU2Nyb2xsZXJdTlNOZXh0S2V5Vmlld11OU0NvbnRlbnRWaWV3gA2AX4BkgGMR
+AjKAPIA5gDNPEBBBIAAAQSAAAEGYAABBmAAAEQESgA6ADYBbgDSANNIADgA+AHYBJIBSpQEgAR8BFAEZ
+ARiANIBbgF+AOYA82wBpAA4AfwErAGoAawEsAGABLQBtAREAegEvATABMQEyATMBNABuATYAegE0WU5T
+Y3ZGbGFnc1lOU0RvY1ZpZXdZTlNCR0NvbG9ygDKAWoBXEASANREJAIA2gA6AWIAygDbSAA4APgB2ATuA
+UqEBNIA23xAUAGkBPgAOAT8BQADOAUEBDQFCAUMBRABrAGwAgwBgAUUBRgBtAUcBSAEgAKwBSgFLAUwB
+TQCHARgBUAFRAVIAcQFTAIcAbgFWAFgBIAFYAVlfEB9OU0RyYWdnaW5nU291cmNlTWFza0Zvck5vbkxv
+Y2FsWU5TVHZGbGFnc1xOU0hlYWRlclZpZXdfEBJOU0FsbG93c1R5cGVTZWxlY3RfEBdOU0ludGVyY2Vs
+bFNwYWNpbmdXaWR0aF8QGU5TQ29sdW1uQXV0b3Jlc2l6aW5nU3R5bGVfEBhOU0ludGVyY2VsbFNwYWNp
+bmdIZWlnaHRbTlNHcmlkQ29sb3JfEBxOU0RyYWdnaW5nU291cmNlTWFza0ZvckxvY2FsXk5TVGFibGVD
+b2x1bW5zW05TUm93SGVpZ2h0gDSAVhJCwAAAgDiAUAmAPCNACAAAAAAAABAFI0AAAAAAAAAAgDcJgA6A
+U4A0gD8jQDEAAAAAAABaezM4MCwgMzAwfdcAaQAOAGsAbABgAG0BXAEZAV4AcQFfAG4BGQE0W05TVGFi
+bGVWaWV3gDmAO4A6gA6AOYA22wBpAA4AfwErAGoAawEsAGABLQBtAREAegEvAWYBMQFnATMBTABuATYA
+egFMgDKAWoBigGGAOIAOgFiAMoA4WXszODAsIDE3fdIANwA4AW8BcKQBcADBAMIAO18QEU5TVGFibGVI
+ZWFkZXJWaWV31gBpAA4AfwBrAGAAbQB6AXMBdAF1AG4AeoAygD6APRP/////gAABAIAOgDJfEBR7ey0y
+NiwgMH0sIHsxNiwgMTd9fdIANwA4AXoBe6QBewDBAMIAO11fTlNDb3JuZXJWaWV30gAOAD4AdgF+gFKi
+AX8BgIBAgEvaAYIADgGDAYQBhQGGAYcBiAGJAVwAhwGLAYwBjQGOAPYBjwGQAIcBNF5OU0lzUmVzaXpl
+YWJsZVxOU0hlYWRlckNlbGxXTlNXaWR0aFpOU0RhdGFDZWxsXk5TUmVzaXppbmdNYXNrWk5TTWluV2lk
+dGhaTlNNYXhXaWR0aFxOU0lzRWRpdGFibGUJgEqAQSNAcR+WAAAAAIBII0BivywAAAAAI0CPQAAAAAAA
+CYA21wCjAA4AzgClAM8AqADRAZQBlQGWAZcBmACsAZkSBIH+AIBHgESAQoBDgEVYSWRlbnRpdHnUAA4A
+3ADdAN4A3wGdAOEBn4AnI0AmAAAAAAAAgCYRDBzTAA4A6QD0AOwA9gGigCxLMC4zMzMzMzI5OQDVAA4A
+6ADpAOoA6wDsAPwA7gGmAPCALIAvgEaAKV8QD2hlYWRlclRleHRDb2xvctIANwA4AaoBq6UBqwEFAQYA
+gQA7XxARTlNUYWJsZUhlYWRlckNlbGzYAKMADgDOAKUAzwDQAKgA0QGtANMA1AGwAZgBNAGzANkSVCH+
+QIAwgCiASYBDgDYSEEIEAIAtWVRleHQgQ2VsbNIANwA4AbcBuKIBuAA7XU5TVGFibGVDb2x1bW7aAYIA
+DgGDAYQBhQGGAYcBiAGJAVwAhwGLAbwBvQG+APYBvwHAAIcBNAmASoBMI0BZFBAAAAAAgFEjQFkAAAAA
+AAAjQGLAAAAAAAAJgDbXAKMADgDOAKUAzwCoANEA0gGVAcUBxgGYAcgBmYBHgE6ATYBDEgQAAACARV5U
+aW1lIFJlbWFpbmluZ9UADgDoAOkA6gDrAOwBTQDuAc4A8IAsgFCAT4ApW2hlYWRlckNvbG9y0wAOAOkA
+9ADsAPYB04AsQjEA2ACjAA4AzgClAM8A0ACoANEB1QDTANQBsAGYATQB2wDZEkQB/kCAMIAogEmAQ4A2
+EgRCBACALdIANwA4Ad4B36MB3wHgADteTlNNdXRhYmxlQXJyYXlXTlNBcnJhedUADgDoAOkA6gDrAOwB
+4wDuAeQA8IAsgFWAVIApWWdyaWRDb2xvctMADgDpAPQA7AD2AemALEQwLjUA0gA3ADgB6wFcpQFcAMAA
+wQDCADtfEBV7ezEsIDE3fSwgezM4MCwgMzAwfX3VAA4A6ADpAOoA6wDsAO0A7gHwAPCALIArgFmAKV8Q
+FmNvbnRyb2xCYWNrZ3JvdW5kQ29sb3LSADcAOAH0AfWkAfUAwQDCADtaTlNDbGlwVmlld9kAaQH3AA4A
+fwBrAGAB+ABtAfkAegB6AfwB/QF1AG4B/wB6AgFYTlNUYXJnZXRYTlNBY3Rpb25ZTlNQZXJjZW50gDKA
+MoBegFyADoBdgDIjP+79TiAAAABfEBZ7ey0zMCwgMTd9LCB7MTUsIDI4NX19XF9kb1Njcm9sbGVyOtIA
+NwA4AgUCBqUCBgDAAMEAwgA7Wk5TU2Nyb2xsZXLaAGkB9wAOAH8BDABrAGAB+ABtAfkAegB6AfwCCwIM
+AXUAbgH/AHoCEIAygDKAXoBgEAGADoBdgDIjP+zuMmAAAABfEBV7ezEsIC0zMH0sIHszNjIsIDE1fX3S
+AA4APgB2AhSAUqEBTIA4XxATe3sxLCAwfSwgezM4MCwgMTd9fV8QFnt7MTcsIDYwfSwgezM4MiwgMzE4
+fX3SADcAOAIZAhqkAhoAwQDCADtcTlNTY3JvbGxWaWV32ABpAA4AfwCBAGsAgwBgAG0ATwIdAh4CHwIg
+AIcAbgBPgA2AbIBmgGcRASEJgA6ADV8QFXt7MzIwLCAxMn0sIHs4NywgMzJ9fd0AowAOAiYCJwIoAikC
+KgClAM8A0AIrAKgCLADSAi0CLgIvAgwA1gIxAjIA1gB7AjUCNgI3XxATTlNBbHRlcm5hdGVDb250ZW50
+c18QEk5TUGVyaW9kaWNJbnRlcnZhbF5OU0J1dHRvbkZsYWdzMl8QEE5TQWx0ZXJuYXRlSW1hZ2VfEA9O
+U0tleUVxdWl2YWxlbnRfEA9OU1BlcmlvZGljRGVsYXldTlNCdXR0b25GbGFnc4BrgGkQGYAlgGqAaIAl
+gGUQyBIIAAAAE/////+GgkD/VlNlbGVjdFDSAA4AXgBfAjmAC9IANwA4Aj0CPqQCPgEGAIEAO1xOU0J1
+dHRvbkNlbGzSADcAOAJAAkGlAkEAwADBAMIAO1hOU0J1dHRvbtgAaQAOAH8AgQBrAIMAYABtAE8CHQJF
+AkYCIACHAG4AT4ANgGyAboBvCYAOgA1fEBV7ezE1NiwgMTJ9LCB7ODIsIDMyfX3dAKMADgImAicCKAIp
+AioApQDPANACKwCoAiwA0gItAi4CLwIMANYCTwJQANYAfAI1AjYCN4BrgGmAJYBxgHCAJYBtVkNhbmNl
+bNIADgBeAF8COYAL2ABpAA4AfwCBAGsAgwBgAG0ATwIdAlkCWgIgAIcAbgBPgA2AbIBzgHQJgA6ADV8Q
+FXt7MjM4LCAxMn0sIHs4MiwgMzJ9fd0AowAOAiYCJwIoAikCKgClAM8A0AIrAKgCLADSAi0CLgIvAgwA
+1gJjAmQA1gB9AjUCNgI3gGuAaYAlgHaAdYAlgHJkAE4AZQB3ICbSAA4AXgBfAjmAC1p7NDE5LCA0NjV9
+0gA3ADgCbADBowDBAMIAO18QFnt7MCwgMH0sIHsxOTIwLCAxMTc4fX1aezIxMywgMTI5fV8QGnszLjQw
+MjgyZSszOCwgMy40MDI4MmUrMzh90gA3ADgCcQJyogJyADtfEBBOU1dpbmRvd1RlbXBsYXRl3QBEAA4A
+RQJ0AEYARwBIAEkASgBLAEwATQBOAnUAUAJ3Ai4CeQBTAnoCewJ8AFcCfQJ+An9fEBNOU0ZyYW1lQXV0
+b3NhdmVOYW1lgIOAfYEBDYBpgICAgYB/gQEPEA2BAQ6Agl8QGHt7Mzc4LCAyNDd9LCB7NDg0LCAxOTl9
+fV8QGEF1dGhlbnRpY2F0ZSB0byBLZXJiZXJvc9IADgBeAF8AYIAL0gAOAF4AXwBngAvXAGkADgBqAGsA
+bABgAG0ChwBvAokAcQKKAocCjICEgHmAhYEBC4CEgQEM0gAOAD4AdgKPgFKhApCAht4AaQAOApIBPwB/
+AOYAagBrAGACkwBtApQBEQKVAnUClwKYAO4CmQDWApsBHAKHAIcCdQCHAqACoV5OU1RhYlZpZXdJdGVt
+c18QEU5TRHJhd3NCYWNrZ3JvdW5kXxAWTlNBbGxvd1RydW5jYXRlZExhYmVsc18QFU5TU2VsZWN0ZWRU
+YWJWaWV3SXRlbYCDgQEKgKOAooAlgIeAhAmAgwmAiIEBB9IADgA+AHYCpIBSoQKggIjYAGkADgBqAGsA
+bABgAG0BEQKQAG8CqQBxAqoChwKQAq2AhoB5gImAoYCEgIaAj9IADgA+AHYCsIBSpQKxAq0CswK0ArWA
+ioCPgJKAlYCZ2QBpAA4AfwCBAGsAgwBgAG0BEQKgAh0CuQK6AiAAhwKHAqACkICIgGyAi4CMCYCEgIiA
+hl8QFXt7MzkyLCAxMn0sIHs4MiwgMzJ9fd0AowAOAiYCJwIoAikCKgClAM8A0AIrAKgCLADSAi0CLgIv
+AgwA1gLEAsUA1gKxAjUCNgI3gGuAaYAlgI6AjYAlgIpURG9uZdIADgBeAF8COYAL2wBpAA4AfwCAAIEA
+ggBrAIMAYABtARECoACFAs4AhwLQAtEAigCHAocCoAKzgIiAIICRCYCTgJAJgISAiICS0gAOAD4APwLY
+gBimAJEAkgCTAJQAlQCWgBKAE4AUgBWAFoAXXxAVe3sxNywgMTIyfSwgezYyLCA2Mn192QBpAA4AfwCB
+AGsAgwBgAG0BEQKgAMUC4wLkAMgAhwKHAqACtICIgDGAlICWCYCEgIiAldgAowAOAKQApQCmAKcAqACp
+AuoAqwCsAK0ArACsAK4ArxIAAf4AgB+AGwhfEBZ7ezg0LCAxNjd9LCB7Mzg3LCAxN3192QBpAA4AfwCB
+AGsAgwBgAG0BEQKgAMUC8gLzARwAhwKHAqACtYCIgDGAmICaCYCEgIiAmdgAowAOAM4ApQDPANAAqADR
+ANIA0wDUAvsA1gKzANgA2YAwgCiAl4AlgJKALVpDb25jbHVzaW9uXxAVe3s4NCwgNjB9LCB7Mzg3LCA5
+OX192QBpAA4AfwCBAGsAgwBgAG0BEQKgAh0DBAMFAiAAhwKHAqACsYCIgGyAnYCeCYCEgIiAitgAowAO
+AM4ApQDPANAAqADRANIA0wMMAw0BmAK0AxAA2YAwgJyAm4BDgJUSEEIAAIAtXxBLQ29uZ3JhdHVsYXRp
+b25zISBZb3UgaGF2ZSBhY3F1aXJlZCBLZXJiZXJvcyB0aWNrZXRzIGZvciBseHNAQVRIRU5BLk1JVC5F
+RFUu0wAOAOkA9ADsAPYDFYAsTTEgMC45NzAwMDAwMwBfEBV7ezMwNSwgMTJ9LCB7OTEsIDMyfX3dAKMA
+DgImAicCKAIpAioApQDPANACKwCoAiwA0gItAi4CLwIMANYDGwMcANYCtQI1AjYCN4BrgGmAJYCggJ+A
+JYCZV0dvIEJhY2vSAA4AXgBfAjmAC1p7NDg4LCAyMDF9XxAVe3stNCwgMH0sIHs0ODgsIDIwMX190gAO
+AD4AdgMmgFKjAycDKAKhgKSA5IEBB9YADgMrAMEDLADoAy0DLgMvAzACkADUAzNcTlNJZGVudGlmaWVy
+WU5TVGFiVmlld1dOU0xhYmVsgOOApYCmgIaAKIDiUTHWAGkADgBqAGsAbAERACsAbwM4AHEDOQM6gACA
+eYCngOGAqNIADgA+AHYDPYBSqAM6Az8DQANBA0IDQwNEA0WAqICrgLGAroC8gLOA04DY2gBpAA4AfwCA
+AIEAggBrAIMAbQERAzAAhQNJAIcDSwNMAIoAhwMwAz+ApoAggKoJgKyAqQmApoCr0gAOAD4APwNSgBim
+AJEAkgCTAJQAlQCWgBKAE4AUgBWAFoAXXxAVe3syMCwgMTE5fSwgezYyLCA2Mn192ABpAA4AfwCBAGsA
+gwBtAREDMADFA10DXgDIAIcDMANBgKaAMYCtgK8JgKaArtgAowAOAKQApQCmAKcAqACpAuoAqwCsAK0A
+rACsAK4Ar4AfgBsIXxAWe3s4NywgMTE5fSwgezM4NywgNTF9fdgAaQAOAH8AgQBrAIMAbQERAzAAxQNq
+A2sAigCHAzADQICmgDGAuYC6CYCmgLHYAKMADgDOAKUAzwDQAKgA0QDSANMA1ANyANYDPwDYANmAMIAo
+gLCAJYCrgC1fECNQbGVhc2UgZW50ZXIgeW91ciBLZXJiZXJvcyBpZGVudGl0edgAaQAOAH8AgQBrAIMA
+bQERAzAAxQN6A3sAyACHAzADQ4CmgDGAsoC0CYCmgLNfEBV7ezkwLCA4OX0sIHszNzgsIDIyfX3YAGkA
+DgB/AIEAawCDAG0BEQMwAMUDgwOEAIoAhwMwA0KApoAxgNCA0QmApoC82QCjAA4AzgClAM8A0ACoApMA
+0QOJANMDiwIuANYDQAOPAIcDkRP/////lHH+QYAwgLWAaYAlgLESEEAEAAmAt9UADgDoAOkA6gDrAOwB
+TQDuA5UA8IAsgFCAtoApXxATdGV4dEJhY2tncm91bmRDb2xvctUADgDoAOkA6gDrAOwA/ADuA5sA8IAs
+gC+AuIApWXRleHRDb2xvcl8QFHt7MTcsIDk0fSwgezY4LCAxN3192ACjAA4AzgClAM8A0ACoANEA0gDT
+ANQDogDWA0EDpQDZgDCAKIC7gCWArhIEQAAAgC1VTmFtZTrYAGkADgB/AIEAawCDAG0BEQMwA6oDqwOs
+AMgAhwMwA6+ApoDPgL2AvwmApoC+XxAVe3s5MCwgNTd9LCB7MzgxLCAyNn193QOyAKMADgDOAKUAzwDQ
+AKgCkwOzAVwDtADRA0IDtgO3A4sDuQDWA0IDjwCHAVEDvQCHANlaTlNEZWxlZ2F0ZV8QEk5TVmlzaWJs
+ZUl0ZW1Db3VudF8QFU5TSGFzVmVydGljYWxTY3JvbGxlcoC8EhRx/kCAzoC1gMCAJYC8CYDBCYAt0gAO
+AF4AXwI5gAvfEBYAaQOyAfcBPwE+AA4AzgFBAUIBQwFEA8MAawBsAIMAYAH4AUUBRgBtAUcBSAPEA6wD
+rAPHAKwDyAE2AIcBUAIMAVIDrAEcA8wAhwPOA88BVgBYA8QD0gPTXE5TRGF0YVNvdXJjZYDCgL+AvxP/
+////0kCAAIDNgFgJgL+AwwmAxIDMgFOAwoDFI0AzAAAAAAAAV3sxNSwgMH3SAA4APgB2A9eAUqED2IDG
+2gGCAA4BgwMrAYQBhQGGAYcBiAFcAIcBiwPcA90D3gPfAPYD4AGQA70JgEqAyIDHI0AoAAAAAAAAgMsj
+QCQAAAAAAACAwdcAowAOAM4ApQDPAKgA0QGUAZUD5AO5A+YArAFNgEeAyoDAgMmAUNQADgDcAN0A3gDf
+A94A4QPrgCeAJhAQ0wAOAOkA9ADsAPYBooAs2ACjAA4AzgDPANAAqAKTANED7wDTATYA1gO9A/QAhwDZ
+EhQx/kCAMIBYgCWAwREEAAmALV8QEHRhYmxlVmlld0FjdGlvbjrSADcAOAP5A/qmA/oBXADAAMEAwgA7
+XxAQTlNDb21ib1RhYmxlVmlld9IANwA4A/wD/aUD/QEFAQYAgQA7Xk5TQ29tYm9Cb3hDZWxs0gA3ADgD
+/wQApgQAAQkAwADBAMIAO1pOU0NvbWJvQm94XxAUe3sxNywgNjF9LCB7NjgsIDE3fX3YAKMADgDOAKUA
+zwDQAKgA0QDSANMA1AQFANYDQwOlANmAMIAogNKAJYCzgC1WUmVhbG062ABpAA4AfwCBAGsAgwBtARED
+MAIdBA0EDgIgAIcDMAKQgKaAbIDUgNUJgKaAhl8QFXt7Mzc2LCAxMn0sIHs5OCwgMzJ9fd0AowAOAiYC
+JwIoAikCKgClAM8A0AIrAKgCLADSAi0CLgIvAgwA1gQXBBgA1gNEAjUCNgI3gGuAaYAlgNeA1oAlgNNY
+Q29udGludWXSAA4AXgBfAjmAC9kAaQAOAH8EHwCBAGsAgwAyAG0DMAQhBCIEIwQkBCUAhwQnAzBfEBNO
+U09yaWdpbmFsQ2xhc3NOYW1lgKaA4IDbgNqA3BEBJAmA2YCmW1BvcHVwQnV0dG9uXxAUe3sxOCwgMTV9
+LCB7NTEsIDI3fX3dAKMADgImBCwCJwIoAioApQDPANACKwCoAiwA0gItAi4ELwQwAFcCLgIuBDMDRQQ1
+AjYENl1OU05vcm1hbEltYWdlgGuAaYDeEEuAaYBpgN2A2BEBkBP/////hsxA/9QADgDcAN0A3gDfA+AA
+4QPrgCeAJtMADgAyALEAsgCzBD2AHoAcgN9UR2VhctIANwA4BEAEQaIEQQA7Xk5TQ2xhc3NTd2FwcGVy
+XxAPU2VsZWN0IElkZW50aXR50gA3ADgERARFogRFADtdTlNUYWJWaWV3SXRlbdYADgMrAMEDLADoAy0D
+LgRIBEkCkADUBEyA44DlgOaAhoAogQEGUTLVAGkADgBqAGsAbAArAG8EUQBxBFKAAIB5gOeBAQXSAA4A
+PgB2BFWAUqcEVgRXBFgEWQRaBFsEXIDogOyA8YD1gPmA/YEBAdkAaQAOAH8AgACBAIIAawCDAG0ESQCF
+BGAAhwRiBGMAigCHBEmA5oAggOoJgOuA6QmA5tIADgA+AD8EaIAYpgCRAJIAkwCUAJUAloASgBOAFIAV
+gBaAF9gAowAOAKQApQCmAKcAqACpAuoAqwCsAK0ArACsAK4Ar4AfgBsI2QBpAA4AfwQfAIEAawCDADIA
+bQRJBCEEdgR3BHgEeQCHBHsESYDmgOCA74DugPARASIJgO2A5l8QEU5TU2VjdXJlVGV4dEZpZWxkXxAV
+e3s4NywgNjB9LCB7MzgxLCAyMn192QCjAA4AzgClAM8A0ACoApMA0QOJANMDiwIuANYEVwOPAIcDkYAw
+gLWAaYAlgOwJgLfXAGkADgB/AIEAawCDAG0ESQIdBIoEiwIgAIcESYDmgGyA8oDzCYDm3QCjAA4CJgIn
+AigCKQIqAKUAzwDQAisAqAIsANICLQIuAi8CDADWBJIEGADWBFgCNQI2AjeAa4BpgCWA9IDWgCWA8dIA
+DgBeAF8COYAL1wBpAA4AfwCBAGsAgwBtBEkCHQSbBJwCIACHBEmA5oBsgPaA9wmA5l8QFXt7MjgzLCAx
+Mn0sIHs5MywgMzJ9fd0AowAOAiYCJwIoAikCKgClAM8A0AIrAKgCLADSAi0CLgIvAgwA1gSkAxwA1gRZ
+AjUCNgI3gGuAaYAlgPiAn4AlgPXSAA4AXgBfAjmAC9cAaQAOAH8AgQBrAIMAbQRJAMUErQSuAMgAhwRJ
+gOaAMYD6gPsJgObYAKMADgDOAKUAzwDQAKgA0QDSANMA1AS0ANYEWgDYANmAMIAogPyAJYD5gC1fECNQ
+bGVhc2UgZW50ZXIgeW91ciBLZXJiZXJvcyBwYXNzd29yZNcAaQAOAH8AgQBrAIMAbQRJAMUEvAS9ARwA
+hwRJgOaAMYD+gP8JgOZfEBV7ezg0LCA5MH0sIHszODcsIDY5fX3YAKMADgDOAKUAzwDQAKgA0QDSANMA
+1ATEAZgEWwDYANmAMIAogQEAgEOA/YAtXxAwTWFpbCB3YW50cyB0byBjb25uZWN0IHRvIHRoZSBhY2Nv
+dW50IGx4c0BtaXQuZWR12QBpAA4AfwQfAIEAawCDADIAbQRJBCEEzAQjBM4EJQCHBNAESYDmgOCBAQOA
+2oEBBAmBAQKA5l8QFHt7MTgsIDE2fSwgezUxLCAyNn193QCjAA4CJgQsAicCKAIqAKUAzwDQAisAqAIs
+ANICLQIuBC8EMABXAi4CLgQzBFwENQI2BNuAa4BpgN6AaYBpgN2BAQET/////4bEQP9fEBpBdXRoZW50
+aWNhdGlvbiBJbmZvcm1hdGlvbtYADgMrAMEDLADoAy0DLgTfAqACkADUBOOA44EBCICIgIaAKIEBCVEz
+VlJlc3VsdNIANwA4BOcDLKQDLADBAMIAO1p7NDg0LCAxOTl9XXsyMzkuMzIsIDEyOX1fEBJ7My40MDI4
+MmUrMzgsIDEzMX3SAA4APgB2BO2AUq8QIgTuBO8E8ATxBPIE8wT0BPUE9gT3BPgE+QT6BPsE/AT9BP4E
+/wUABQEFAgUDBQQFBQUGBQcFCAUJBQoFCwUMBQ0FDgUPgQERgQEUgQEWgQEhgQEvgQE0gQE6gQE/gQFB
+gQFFgQFKgQFQgQFXgQFcgQFggQFlgQFngQFsgQFugQFwgQFxgQGCgQGEgQGJgQGKgQGLgQGSgQGWgQGb
+gQGfgQGjgQGmgQGrgQHB1AAOBREFEgMtBRMCkAK1BRZdTlNEZXN0aW5hdGlvblhOU1NvdXJjZYEBE4CG
+gJmBARJfEBpzZWxlY3RQcmV2aW91c1RhYlZpZXdJdGVtOtIANwA4BRkFGqMFGgUbADtfEBVOU05pYkNv
+bnRyb2xDb25uZWN0b3JeTlNOaWJDb25uZWN0b3LUAA4FEQUSAy0FEwKQA0QFIIEBE4CGgNOBARVfEBZz
+ZWxlY3ROZXh0VGFiVmlld0l0ZW060wAOBRIDLQUTBSQFJYEBE4EBF4EBINgADgUnBSgFKQUqBSsFLAUt
+BS4FLwUwBTEFMgUzBTQFNVdOU1RpdGxlXxARTlNLZXlFcXVpdk1vZE1hc2taTlNLZXlFcXVpdl1OU01u
+ZW1vbmljTG9jWU5TT25JbWFnZVxOU01peGVkSW1hZ2VWTlNNZW51gQEfgQEZEgAQAACBARoSf////4EB
+G4EBHYEBGNQADgUnAN0FNwU4BTkFOgU7W05TTWVudUl0ZW1zgQEsgQHkgQHngQHlWE1pbmltaXplUW3T
+AA4AMgCxALIAswVBgB6AHIEBHF8QD05TTWVudUNoZWNrbWFya9MADgAyALEAsgCzBUaAHoAcgQEeXxAQ
+TlNNZW51TWl4ZWRTdGF0ZdIANwA4BUkFSqIFSgA7Wk5TTWVudUl0ZW1fEBNwZXJmb3JtTWluaWF0dXJp
+emU61AAOBREFEgMtBU0FTgNFBVCBAS6BASKA2IEBLdQADgUnAN0FNwU4BVMCLgVVgQEsgQEjgGmBASRU
+TWVuddIADgA+AHYFWYBSpAVaBVsFXAVdgQElgQEngQEpgQEq2AAOBScFKAUpBSoFKwUsBS0FLgVgBTAC
+LgUyBTMFNAVOgQEfgQEmgGmBARuBAR2BASJvEA8AVABpAGMAawBlAHQAIABPAHAAdABpAG8AbgBzICbY
+AA4FJwUoBSkFKgUrBSwFLQUuBWgFMAIuBTIFMwU0BU6BAR+BASiAaYEBG4EBHYEBIm8QEABDAGgAYQBu
+AGcAZQAgAFAAYQBzAHMAdwBvAHIAZCAm2gAOBScFKAVvBSkFcAUqBSsFLAUtBS4CLgUwAIcCLgCHBTIF
+MwU0BU5dTlNJc1NlcGFyYXRvclxOU0lzRGlzYWJsZWSBAR+AaQmAaQmBARuBAR2BASLYAA4FJwUoBSkF
+KgUrBSwFLQUuBXsFMAIuBTIFMwU0BU6BAR+BASuAaYEBG4EBHYEBIl8QEUFib3V0IEtlcmJlcm9zLi4u
+0gA3ADgFggUtogUtADtUbWVuddIANwA4BYUFhqMFhgUbADtfEBROU05pYk91dGxldENvbm5lY3RvctQA
+DgURBRIDLQUTAB8FigWLgQETgAKBATCBATPXAA4FJwUpBSoFKwUsBS0FLgWOAi4FMgUzBTQFkoEBH4EB
+MoBpgQEbgQEdgQEx1AAOBScA3QU3BTgFlQWWBZeBASyBAcqBAduBAcxfEBNBYm91dCBLZXJiZXJvc0Fn
+ZW50XxAdb3JkZXJGcm9udFN0YW5kYXJkQWJvdXRQYW5lbDrTAA4FEgMtBRMFnAWdgQETgQE1gQE52AAO
+BScFKAUpBSoFKwUsBS0FLgWgBTAFoQUyBTMFNAWkgQEfgQE3gQE4gQEbgQEdgQE20wAOBScFNwU4BacF
+qIEBLIEB3YEB31RVbmRvUXpVdW5kbzrTAA4FEgMtBRMFrgWvgQETgQE7gQE+2AAOBScFKAUpBSoFKwUs
+BS0FLgWyBTAFswUyBTMFNAU1gQEfgQE8gQE9gQEbgQEdgQEYVUNsb3NlUXddcGVyZm9ybUNsb3NlOtQA
+DgURBRIDLQVNA0ADQgW+gQEugLGAvIEBQFtuZXh0S2V5Vmlld9MADgUSAy0FEwXCBcOBAROBAUKBAUTY
+AA4FJwUoBSkFKgUrBSwFLQUuBcYFMAIuBTIFMwU0BaSBAR+BAUOAaYEBG4EBHYEBNlZEZWxldGVXZGVs
+ZXRlOtMADgUSAy0FEwXPBdCBAROBAUaBAUnYAA4FJwUoBSkFKgUrBSwFLQUuBdMFMAXUBTIFMwU0BaSB
+AR+BAUeBAUiBARuBAR2BATZaU2VsZWN0IEFsbFFhWnNlbGVjdEFsbDrTAA4FEgMtBRMF3QXegQETgQFL
+gQFP2AAOBScFKAUpBSoFKwUsBS0FLgXhBTAF4gUyBTMFNAXlgQEfgQFNgQFOgQEbgQEdgQFM0wAOBScF
+NwU4BegF6YEBLIEB64EB7F8QEktlcmJlcm9zQWdlbnQgSGVscFE/WXNob3dIZWxwOtQADgURBRIDLQUT
+Be8F8AXxgQETgQFUgQFRgQFW2AAOBScFKAUpBSoFKwUsBS0FLgX0BfUF9gUyBTMFNAWSgQEfgQFSEgAY
+AACBAVOBARuBAR2BATFbSGlkZSBPdGhlcnNRaNIADgAyADMF/oAEgQFVXxAWaGlkZU90aGVyQXBwbGlj
+YXRpb25zOtMADgUSAy0FEwYCBgOBAROBAViBAVvYAA4FJwUoBSkFKgUrBSwFLQUuBgYFMAYHBTIFMwU0
+BaSBAR+BAVmBAVqBARuBAR2BATZUUmVkb1FaVXJlZG860wAOBRIDLQUTBhAGEYEBE4EBXYEBX9gADgUn
+BSgFKQUqBSsFLAUtBS4GFAUwAi4FMgUzBTQFNYEBH4EBXoBpgQEbgQEdgQEYVFpvb21ccGVyZm9ybVpv
+b2060wAOBRIDLQUTBh0GHoEBE4EBYYEBZNgADgUnBSgFKQUqBSsFLAUtBS4GIQUwBiIFMgUzBTQFpIEB
+H4EBYoEBY4EBG4EBHYEBNlVQYXN0ZVF2VnBhc3RlOtQADgURBRIDLQUTApAEWQYtgQETgIaA9YEBZtMA
+DgUSAy0FEwYwBjGBAROBAWiBAWvYAA4FJwUoBSkFKgUrBSwFLQUuBjQFMAY1BTIFMwU0BaSBAR+BAWmB
+AWqBARuBAR2BATZTQ3V0UXhUY3V0OtQADgURBRIDLQUTApAEWAZAgQETgIaA8YEBbdQADgURBRIDLQUT
+AEECRgZFgQETgAeAb4EBb9QADgURBRIDLQVNA0IDQAW+gQEugLyAsYEBQNQADgURBRIDLQVNBk0GTgZP
+gQEugQF6gQFygQGB2gZRAA4GUgZTAIAGVAZVBlYGVwZYAIcGWgCHBlwAhwZeBl8AhwCHAIdfEBpOU0Zp
+bHRlclJlc3RyaWN0c0luc2VydGlvbl8QFE5TUHJlc2VydmVzU2VsZWN0aW9uXxAPX05TTWFuYWdlZFBy
+b3h5XxARTlNPYmplY3RDbGFzc05hbWVeTlNEZWNsYXJlZEtleXNfECJOU0NsZWFyc0ZpbHRlclByZWRp
+Y2F0ZU9uSW5zZXJ0aW9uXxAYTlNTZWxlY3RzSW5zZXJ0ZWRPYmplY3RzXxAWTlNBdm9pZHNFbXB0eVNl
+bGVjdGlvbgmBAXkJgQF3CYEBdoEBcwkJCdIADgA+AHYGZYBSogZmBmeBAXSBAXVfEBZzZXJ2aWNlUHJp
+bmNpcGFsU3RyaW5nXxAYc2hvcnRUaW1lUmVtYWluaW5nU3RyaW5nXxASS2VyYmVyb3NDcmVkZW50aWFs
+0QAOBmyBAXjSADcAOAZuBlOiBlMAO9IANwA4BnAGcaQGcQZyBnMAO18QEU5TQXJyYXlDb250cm9sbGVy
+XxASTlNPYmplY3RDb250cm9sbGVyXE5TQ29udHJvbGxlctkGUQAOBlIGUwZUBlUGVgZXBlgAhwZaAIcG
+eAZ5BnoAhwCHAIcJgQF5CYEBgIEBf4EBewkJCdIADgA+AHYGgIBSowaBBoIGg4EBfIEBfYEBfl8QEGNy
+ZWRlbnRpYWxzQXJyYXlfEA9wcmluY2lwYWxTdHJpbmddS2VyYmVyb3NDYWNoZdEADgZsgQF4V2NvbnRl
+bnTUAA4FEQUSAy0FTQVOBFwGjoEBLoEBIoEBAYEBg1lwb3B1cE1lbnXTAA4FEgMtBRMGkgaTgQETgQGF
+gQGI2AAOBScFKAUpBSoFKwUsBS0FLgaWBfUGlwUyBTMFNAWkgQEfgQGGgQGHgQEbgQEdgQE2XxAVUGFz
+dGUgYW5kIE1hdGNoIFN0eWxlUVZfEBFwYXN0ZUFzUGxhaW5UZXh0OtQADgURBRIDLQVNBU4DRQaOgQEu
+gQEigNiBAYPUAA4FEQUSAy0FTQVOBFwFUIEBLoEBIoEBAYEBLdQADgURBRIDLQVNBqoGTQZPgQEugQGM
+gQF6gQGB1AAOBlMGVAZVBq4GrwawBrGBAZGBAZCBAY+BAY3SAA4APgB2BrSAUqEGtYEBjltjYWNoZXNB
+cnJheV8QF0tlcmJlcm9zQ2FjaGVDb2xsZWN0aW9u0QAOBmyBAXjSADcAOAa7BnKjBnIGcwA71AAOBREF
+EgMtBRMF7wa/BsCBAROBAVSBAZOBAZXYAA4FJwUoBSkFKgUrBSwFLQUuBsMFMAIuBTIFMwU0BTWBAR+B
+AZSAaYEBG4EBHYEBGF8QEkJyaW5nIEFsbCB0byBGcm9udF8QD2FycmFuZ2VJbkZyb250OtQADgURBRID
+LQUTBe8GzQbOgQETgQFUgQGXgQGa2AAOBScFKAUpBSoFKwUsBS0FLgbRBTAG0gUyBTMFNAWSgQEfgQGY
+gQGZgQEbgQEdgQExXxASUXVpdCBLZXJiZXJvc0FnZW50UXFadGVybWluYXRlOtQADgURBRIDLQUTBe8G
+3AbdgQETgQFUgQGcgQGe2AAOBScFKAUpBSoFKwUsBS0FLgbgBTAF9gUyBTMFNAWSgQEfgQGdgQFTgQEb
+gQEdgQExXxASSGlkZSBLZXJiZXJvc0FnZW50VWhpZGU61AAOBREFEgMtBRMF7wbqBuuBAROBAVSBAaCB
+AaLYAA4FJwUoBSkFKgUrBSwFLQUuBu4FMAIuBTIFMwU0BZKBAR+BAaGAaYEBG4EBHYEBMVhTaG93IEFs
+bFd1bmhpZGU61AAOBREFEgMtBU0G9waqBk+BAS6BAaSBAYyBAYHSAA4AMgAzBvyABIEBpdMADgUSAy0F
+Ewb/BwCBAROBAaeBAarYAA4FJwUoBSkFKgUrBSwFLQUuBwMFMAcEBTIFMwU0BaSBAR+BAaiBAamBARuB
+AR2BATZUQ29weVFjVWNvcHk62AAOBREHDAcNBRIDLQcOBw8HEAZNBxIHEwF/BxUHFgBXWU5TS2V5UGF0
+aFlOU0JpbmRpbmdZTlNPcHRpb25zXxAcTlNOaWJCaW5kaW5nQ29ubmVjdG9yVmVyc2lvboEBwIEBeoEB
+roEBrYBAgQGsgQGvXxAmdmFsdWU6IGFycmFuZ2VkT2JqZWN0cy5wcmluY2lwYWxTdHJpbmdVdmFsdWVf
+EB9hcnJhbmdlZE9iamVjdHMucHJpbmNpcGFsU3RyaW5n0wAOBxsAPgccBx0HKldOUy5rZXlzgQG/rAce
+Bx8HIAchByIHIwckByUHJgcnBygHKYEBsIEBsYEBsoEBs4EBtIEBtYEBtoEBt4EBuIEBuYEBuoEBu6wH
+KwcsBysHKwcvBy8HKwcsBy8HLwcrByyBAbyBAb2BAbyBAbyBAb6BAb6BAbyBAb2BAb6BAb6BAbyBAb1f
+EBpOU0NvbmRpdGlvbmFsbHlTZXRzRW5hYmxlZF8QHE5TUmFpc2VzRm9yTm90QXBwbGljYWJsZUtleXNf
+EBZOU1ZhbGlkYXRlc0ltbWVkaWF0ZWx5XxAmTlNBbHdheXNQcmVzZW50c0FwcGxpY2F0aW9uTW9kYWxB
+bGVydHNfEBtOU011bHRpcGxlVmFsdWVzUGxhY2Vob2xkZXJfEBFOU051bGxQbGFjZWhvbGRlcl8QGk5T
+Q29udGludW91c2x5VXBkYXRlc1ZhbHVlXxAXTlNDcmVhdGVzU29ydERlc2NyaXB0b3JfEBpOU05vdEFw
+cGxpY2FibGVQbGFjZWhvbGRlcl8QGE5TTm9TZWxlY3Rpb25QbGFjZWhvbGRlcl8QJk5TQWxsb3dzRWRp
+dGluZ011bHRpcGxlVmFsdWVzU2VsZWN0aW9uXxAbTlNDb25kaXRpb25hbGx5U2V0c0VkaXRhYmxlCAnS
+ADcAOAdGB0eiB0cAO1xOU0RpY3Rpb25hcnnSADcAOAdJB0qjB0oFGwA7XxAVTlNOaWJCaW5kaW5nQ29u
+bmVjdG9y2AAOBREHDAcNBRIDLQcOBw8HEAZNB04HEwGAB1EHUgBXgQHAgQF6gQHDgQGtgEuBAcKBAcRf
+EC92YWx1ZTogYXJyYW5nZWRPYmplY3RzLnNob3J0VGltZVJlbWFpbmluZ1N0cmluZ18QKGFycmFuZ2Vk
+T2JqZWN0cy5zaG9ydFRpbWVSZW1haW5pbmdTdHJpbmfTAA4HGwA+BxwHVwdkgQG/rAceBx8HIAchByIH
+IwckByUHJgcnBygHKYEBsIEBsYEBsoEBs4EBtIEBtYEBtoEBt4EBuIEBuYEBuoEBu6wHKwcsBysHKwcv
+By8HKwcrBy8HLwcrByyBAbyBAb2BAbyBAbyBAb6BAb6BAbyBAbyBAb6BAb6BAbyBAb3SAA4APgdyB3OB
+Ae6vEHQHdAE0AX8EDgJ1AHkGTQRYBVsCswMFB38BgABPBCQFnAWkAIgCtAUkA0AGkgRWBK4HjAYCARQA
+QQeQBhABjgTOAqEG3AM/BVoHmAa/BjAF5QNBBvcEXAbNA0QAeAeiAtAESQVOB6YAewXCBfAG6gerAqAE
+vQMoBGIHsAK1BFcDXgOsAh8Htge3BV0DSwRaA3sAQgWuAzAC8wRbAuQFNQZOA2sDQgXdA0MAfAKQAloA
+xwM6Bv8HzgG+BJwCsQXPAroFigaqA0UEWQVcAycH2gR4BIsH3QB9AUwBHwWSA4QAegXvAkYCrQYdgQHG
+gDaAQIDVgIOAIYEBeoDxgQEngJKAnoEBzYBLgA2A3IEBNYEBNoAagJWBAReAsYEBhYDogPuBAdyBAViA
+X4AHgQHJgQFdgEiBAQSBAQeBAZyAq4EBJYEBzoEBk4EBaIEBTICugQGkgQEBgQGXgNOAEIEB4YCTgOaB
+ASKBAeCAZYEBQoEBUYEBoIEB0oCIgP+A5IDrgQHVgJmA7ICvgL+AZ4EB6IEB2YEBKoCsgPmAtIB+gQE7
+gKaAmoD9gJaBARiBAXKAuoC8gQFLgLOAbYCGgHSAI4CogQGngQHagFGA94CKgQFGgIyBATCBAYyA2ID1
+gQEpgKSBAeaA8IDzgQHRgHKAOIBbgQExgNGAMoEBVIBvgI+BAWHUAA4FJwDdBTcFOAfqB+sH7IEBLIEB
+x4EB7YEByF5BdXRoZW50aWNhdGlvbtIADgA+AHYH8IBSpAeQB4wHoge2gQHJgQHcgQHhgQHo2gAOB/YF
+JwUoBSkFKgUrBSwFLQH4BS4FkgWVBTACLgUyBTMFNAd0B/5ZTlNTdWJtZW51gQEfgQExgQHKgGmBARuB
+AR2BAcaBActec3VibWVudUFjdGlvbjrSAA4APgB2CAKAUqsFigd/B5gH3QerB7cG3AXwBuoHzgbNgQEw
+gQHNgQHOgQHRgQHSgQHZgQGcgQFRgQGggQHagQGX2gAOBScFKAVvBSkFcAUqBSsFLAUtBS4CLgUwAIcC
+LgCHBTIFMwU0BZKBAR+AaQmAaQmBARuBAR2BATHYAA4FJwUoBSkFKgUrBSwFLQUuCBkFMAgaBTIFMwU0
+BZKBAR+BAc+BAdCBARuBAR2BATFsAFAAcgBlAGYAZQByAGUAbgBjAGUAcyAmUSzaAA4FJwUoBW8FKQVw
+BSoFKwUsBS0FLgIuBTAAhwIuAIcFMgUzBTQFkoEBH4BpCYBpCYEBG4EBHYEBMdoADgf2BScFKAUpBSoF
+KwUsBS0B+AUuB7AILAUwAi4FMgUzBTQFkggxgQEfgQHVgQHTgGmBARuBAR2BATGBAdRYU2VydmljZXPU
+AA4FJwDdBTcFOAg1CDYIN4EBLIEB1oEB2IEB19IADgBeAF8IMoAL0gAOAD4Adgg8gFKgXxAPX05TU2Vy
+dmljZXNNZW512gAOBScFKAVvBSkFcAUqBSsFLAUtBS4CLgUwAIcCLgCHBTIFMwU0BZKBAR+AaQmAaQmB
+ARuBAR2BATHaAA4FJwUoBW8FKQVwBSoFKwUsBS0FLgIuBTAAhwIuAIcFMgUzBTQFkoEBH4BpCYBpCYEB
+G4EBHYEBMVxfTlNBcHBsZU1lbnXaAA4H9gUnBSgFKQUqBSsFLAUtAfgFLgWkBacFMAIuBTIFMwU0B3QI
+WYEBH4EBNoEB3YBpgQEbgQEdgQHGgQHeVEVkaXTSAA4APgB2CF2AUqkFnAYCB6YGMAb/Bh0GkgXCBc+B
+ATWBAViBAeCBAWiBAaeBAWGBAYWBAUKBAUbaAA4FJwUoBW8FKQVwBSoFKwUsBS0FLgIuBTAAhwIuAIcF
+MgUzBTQFpIEBH4BpCYBpCYEBG4EBHYEBNtoADgf2BScFKAUpBSoFKwUsBS0B+AUuBTUIcwUwAi4FMgUz
+BTQHdAh4gQEfgQEYgQHigGmBARuBAR2BAcaBAeNWV2luZG930gAOAF4AXwh5gAvSAA4APgB2CH6AUqUF
+rgUkBhAH2ga/gQE7gQEXgQFdgQHmgQGT2gAOBScFKAVvBSkFcAUqBSsFLAUtBS4CLgUwAIcCLgCHBTIF
+MwU0BTWBAR+AaQmAaQmBARuBAR2BARheX05TV2luZG93c01lbnXaAA4H9gUnBSgFKQUqBSsFLAUtAfgF
+LgXlCJEFMAIuBTIFMwU0B3QIloEBH4EBTIEB6YBpgQEbgQEdgQHGgQHqVEhlbHDSAA4AXgBfCJeAC9IA
+DgA+AHYInIBSoQXdgQFLW19OU01haW5NZW510gA3ADgIoAHgogHgADvSAA4APgdyCKOBAe6vEHQAHwB6
+ATQDRABCAE8AHwRJBU4CoAK1BZIBNABBA0UFpAeMAHgCoAU1AzAFpARJBFoHdAWkAHoAHwd0BTUBfwRc
+ApAFkgMwBU4FkgU1BaQHtgMwAB8ESQWSAzAATwd0Aq0DKAAfBaQATwWkBZIFkgWSAqEEWwKQBFYHqwKg
+BEkDPwNCAHsHdAWSBU4DOgRJA0AAHwU1AycCtARJArMHogAfA0EDMAXlAzAATwJ1AH0AeQMwBaQFkgGA
+BFkCoAWkArEFkgAfAzAESQVOApAFNQRXBFgFkgBPAHoAegeQA0MATwAfAHwCoAWkgAKAMoA2gNOAfoAN
+gAKA5oEBIoCIgJmBATGANoAHgNiBATaBAdyAEICIgQEYgKaBATaA5oD5gQHGgQE2gDKAAoEBxoEBGIBA
+gQEBgIaBATGApoEBIoEBMYEBGIEBNoEB6ICmgAKA5oEBMYCmgA2BAcaAj4DkgAKBATaADYEBNoEBMYEB
+MYEBMYEBB4D9gIaA6IEB0oCIgOaAq4C8gGWBAcaBATGBASKAqIDmgLGAAoEBGICkgJWA5oCSgQHhgAKA
+roCmgQFMgKaADYCDgHKAIYCmgQE2gQExgEuA9YCIgQE2gIqBATGAAoCmgOaBASKAhoEBGIDsgPGBATGA
+DYAygDKBAcmAs4ANgAKAbYCIgQE20gAOAD4HcgkagQHurxB1B3QBNAF/BA4CdQB5Bk0EWAVbArMDBQd/
+AYAATwQkBZwFpACIArQFJAaSA0AEVgYCB4wErgEUAEEHkAYQAY4EzgKhBtwDPwVaB5gGvwYwBeUDQQb3
+Bs0HogRcAHgDRALQBU4ESQemBfAAewXCBuoHqwKgBL0DKARiB7ACtQRXAB8DXgOsAh8Htge3BV0DSwRa
+A3sAQgWuAzAC8wRbBTUC5AZOBd0DQgNrA0MAfAKQAloAxwM6Bv8HzgG+BJwCsQXPAroFigaqA0UFXARZ
+AycH2gR4BIsH3QB9AUwBHwWSA4QAegXvAq0CRgYdgQHGgDaAQIDVgIOAIYEBeoDxgQEngJKAnoEBzYBL
+gA2A3IEBNYEBNoAagJWBAReBAYWAsYDogQFYgQHcgPuAX4AHgQHJgQFdgEiBAQSBAQeBAZyAq4EBJYEB
+zoEBk4EBaIEBTICugQGkgQGXgQHhgQEBgBCA04CTgQEigOaBAeCBAVGAZYEBQoEBoIEB0oCIgP+A5IDr
+gQHVgJmA7IACgK+Av4BngQHogQHZgQEqgKyA+YC0gH6BATuApoCagP2BARiAloEBcoEBS4C8gLqAs4Bt
+gIaAdIAjgKiBAaeBAdqAUYD3gIqBAUaAjIEBMIEBjIDYgQEpgPWApIEB5oDwgPOBAdGAcoA4gFuBATGA
+0YAygQFUgI+Ab4EBYdIADgA+B3IJkoEB7q8QdQmTCZQJlQmWCZcJmAmZCZoJmwmcCZ0JngmfCaAJoQmi
+CaMJpAmlCaYJpwmoCakJqgmrCawJrQhzCa8JsAmxCbIJswm0CbUJtgm3CbgJuQm6CbsG/Am9Cb4JvwnA
+CcEJwgnDCcQJxQnGCccJyAnJCcoJywnMCc0JzgnPCdAJ0QnSCdMJ1AnVCdYJ1wnYCdkJ2gnbCdwJ3Qne
+Cd8J4AnhCeIJ4wnkCeUJ5gnnCegJ6QnqCesJ7AntCe4J7wnwCfEJ8gnzCfQJ9Qn2CfcJ+An5CfoJ+wn8
+Cf0J/gn/CgAKAQoCCgMKBAoFCgYKB4EB8oEB84EB9IEB9YEB9oEB94EB+IEB+YEB+oEB+4EB/IEB/YEB
+/oEB/4ECAIECAYECAoECA4ECBIECBYECBoECB4ECCIECCYECCoECC4ECDIEB4oECDYECDoECD4ECEIEC
+EYECEoECE4ECFIECFYECFoECF4ECGIECGYEBpYECGoECG4ECHIECHYECHoECH4ECIIECIYECIoECI4EC
+JIECJYECJoECJ4ECKIECKYECKoECK4ECLIECLYECLoECL4ECMIECMYECMoECM4ECNIECNYECNoECN4EC
+OIECOYECOoECO4ECPIECPYECPoECP4ECQIECQYECQoECQ4ECRIECRYECRoECR4ECSIECSYECSoECS4EC
+TIECTYECToECT4ECUIECUYECUoECU4ECVIECVYECVoECV4ECWIECWYECWoECW4ECXIECXYECXoECX4EC
+YIECYYECYoECY4ECZFhNYWluTWVudV8QJVRhYmxlIFZpZXcgKElkZW50aXR5LCBUaW1lIFJlbWFpbmlu
+ZylfEBdUYWJsZSBDb2x1bW4gKElkZW50aXR5KV8QGEJ1dHRvbiBDZWxsIChDb250aW51ZSktMV5Db250
+ZW50IFZpZXctMV8QL1N0YXRpYyBUZXh0IChQbGVhc2Ugc2VsZWN0IGEgS2VyYmVyb3MgSWRlbnRpdHkp
+XxAQQ2FjaGVzQ29udHJvbGxlcl8QFlB1c2ggQnV0dG9uIChDb250aW51ZSlvEBwATQBlAG4AdQAgAEkA
+dABlAG0AIAAoAEMAaABhAG4AZwBlACAAUABhAHMAcwB3AG8AcgBkICYAKV8QGFN0YXRpYyBUZXh0IChD
+b25jbHVzaW9uKV8QFUJ1dHRvbiBDZWxsIChHbyBCYWNrKVtTZXBhcmF0b3ItMl8QHVRhYmxlIENvbHVt
+biAoVGltZSBSZW1haW5pbmcpXENvbnRlbnQgVmlld18QFEJ1dHRvbiBDZWxsIChHZWFyKS0xXxAQTWVu
+dSBJdGVtIChVbmRvKVtNZW51IChFZGl0KV8QGkltYWdlIENlbGwgKEtlcmJlcm9zQWdlbnQpXxBZU3Rh
+dGljIFRleHQgKENvbmdyYXR1bGF0aW9ucyEgWW91IGhhdmUgYWNxdWlyZWQgS2VyYmVyb3MgdGlja2V0
+cyBmb3IgbHhzQEFUSEVOQS5NSVQuRURVLilfEBRNZW51IEl0ZW0gKE1pbmltaXplKV8QIU1lbnUgSXRl
+bSAoUGFzdGUgYW5kIE1hdGNoIFN0eWxlKVpUZXh0IEZpZWxkXxAcSW1hZ2UgVmlldyAoS2VyYmVyb3NB
+Z2VudCktMl8QEE1lbnUgSXRlbSAoUmVkbylfEBBNZW51IEl0ZW0gKEVkaXQpXxA1VGV4dCBGaWVsZCBD
+ZWxsIChQbGVhc2UgZW50ZXIgeW91ciBLZXJiZXJvcyBwYXNzd29yZClfEBNIb3Jpem9udGFsIFNjcm9s
+bGVyXxAZTWVudSBJdGVtIChLZXJiZXJvc0FnZW50KV8QEE1lbnUgSXRlbSAoWm9vbSlfEBtUZXh0IEZp
+ZWxkIENlbGwgKFRleHQgQ2VsbClfEBJCdXR0b24gQ2VsbCAoR2VhcilfEBZUYWIgVmlldyBJdGVtIChS
+ZXN1bHQpXxAeTWVudSBJdGVtIChIaWRlIEtlcmJlcm9zQWdlbnQpXxAxU3RhdGljIFRleHQgKFBsZWFz
+ZSBlbnRlciB5b3VyIEtlcmJlcm9zIGlkZW50aXR5KW8QGwBNAGUAbgB1ACAASQB0AGUAbQAgACgAVABp
+AGMAawBlAHQAIABPAHAAdABpAG8AbgBzICYAKW8QGABNAGUAbgB1ACAASQB0AGUAbQAgACgAUAByAGUA
+ZgBlAHIAZQBuAGMAZQBzICYAKV8QHk1lbnUgSXRlbSAoQnJpbmcgQWxsIHRvIEZyb250KV8QD01lbnUg
+SXRlbSAoQ3V0KVtNZW51IChIZWxwKV8QE1N0YXRpYyBUZXh0IChOYW1lOilfEB5NZW51IEl0ZW0gKFF1
+aXQgS2VyYmVyb3NBZ2VudClfEBJNZW51IEl0ZW0gKFdpbmRvdylfEBNQb3B1cCBCdXR0b24gKEdlYXIp
+XxAaSW1hZ2UgVmlldyAoS2VyYmVyb3NBZ2VudClfEBhQdXNoIEJ1dHRvbiAoQ29udGludWUpLTFfEBxJ
+bWFnZSBDZWxsIChLZXJiZXJvc0FnZW50KS0xWEdlYXJNZW51VlZpZXctMVtTZXBhcmF0b3ItMV8QF01l
+bnUgSXRlbSAoSGlkZSBPdGhlcnMpXxAUUHVzaCBCdXR0b24gKFNlbGVjdClfEBJNZW51IEl0ZW0gKERl
+bGV0ZSlfEBRNZW51IEl0ZW0gKFNob3cgQWxsKV8QFE1lbnUgSXRlbSAoU2VydmljZXMpXxBCVGV4dCBG
+aWVsZCBDZWxsIChNYWlsIHdhbnRzIHRvIGNvbm5lY3QgdG8gdGhlIGFjY291bnQgbHhzQG1pdC5lZHUp
+XxAqVGFiIFZpZXcgSXRlbSAoQXV0aGVudGljYXRpb24gSW5mb3JtYXRpb24pXxAcSW1hZ2UgQ2VsbCAo
+S2VyYmVyb3NBZ2VudCktMl8QD01lbnUgKFNlcnZpY2VzKV8QFVB1c2ggQnV0dG9uIChHbyBCYWNrKV8Q
+EVNlY3VyZSBUZXh0IEZpZWxkXEZpbGUncyBPd25lcl8QNVRleHQgRmllbGQgQ2VsbCAoUGxlYXNlIGVu
+dGVyIHlvdXIgS2VyYmVyb3MgaWRlbnRpdHkpXkNvbWJvIEJveCBDZWxsXxAUQnV0dG9uIENlbGwgKFNl
+bGVjdClfEBBNZW51IEl0ZW0gKEhlbHApW1NlcGFyYXRvci0zXxAdTWVudSBJdGVtIChBYm91dCBLZXJi
+ZXJvcy4uLilfEBxJbWFnZSBDZWxsIChLZXJiZXJvc0FnZW50KS0zXxAxU3RhdGljIFRleHQgKFBsZWFz
+ZSBlbnRlciB5b3VyIEtlcmJlcm9zIHBhc3N3b3JkKV8QEVRleHQgRmllbGQgQ2VsbC0xV1dpbmRvdzFf
+EBFNZW51IEl0ZW0gKENsb3NlKVZWaWV3LTJfEF1UZXh0IEZpZWxkIENlbGwgKENvbmdyYXR1bGF0aW9u
+cyEgWW91IGhhdmUgYWNxdWlyZWQgS2VyYmVyb3MgdGlja2V0cyBmb3IgbHhzQEFUSEVOQS5NSVQuRURV
+LilfED5TdGF0aWMgVGV4dCAoTWFpbCB3YW50cyB0byBjb25uZWN0IHRvIHRoZSBhY2NvdW50IGx4c0Bt
+aXQuZWR1KV1NZW51IChXaW5kb3cpXxAcVGV4dCBGaWVsZCBDZWxsIChDb25jbHVzaW9uKV8QFUNyZWRl
+bnRpYWxzQ29udHJvbGxlcl8QHk1lbnUgSXRlbSAoS2VyYmVyb3NBZ2VudCBIZWxwKVlDb21ibyBCb3hf
+EBdUZXh0IEZpZWxkIENlbGwgKE5hbWU6KV8QFFN0YXRpYyBUZXh0IChSZWFsbTopXxAUUHVzaCBCdXR0
+b24gKENhbmNlbClfEEhObyBTaGFkb3cgVGFiIFZpZXcgKFNlbGVjdCBJZGVudGl0eSwgQXV0aGVudGlj
+YXRpb24gSW5mb3JtYXRpb24sIFJlc3VsdClvEBIAQgB1AHQAdABvAG4AIABDAGUAbABsACAAKABOAGUA
+dyAmAClfEDNUZXh0IEZpZWxkIENlbGwgKFBsZWFzZSBzZWxlY3QgYSBLZXJiZXJvcyBJZGVudGl0eSlf
+EBxJbWFnZSBWaWV3IChLZXJiZXJvc0FnZW50KS0zXxAQTWVudSBJdGVtIChDb3B5KVtTZXBhcmF0b3It
+NF8QHVRleHQgRmllbGQgQ2VsbCAoVGV4dCBDZWxsKS0xXxAXQnV0dG9uIENlbGwgKEdvIEJhY2spLTFf
+EBJQdXNoIEJ1dHRvbiAoRG9uZSlfEBZNZW51IEl0ZW0gKFNlbGVjdCBBbGwpXxASQnV0dG9uIENlbGwg
+KERvbmUpXxAfTWVudSBJdGVtIChBYm91dCBLZXJiZXJvc0FnZW50KV8QGUNhY2hlQ29sbGVjdGlvbkNv
+bnRyb2xsZXJfEBVQb3B1cCBCdXR0b24gKEdlYXIpLTFZU2VwYXJhdG9yXxAXUHVzaCBCdXR0b24gKEdv
+IEJhY2spLTFfEB9UYWIgVmlldyBJdGVtIChTZWxlY3QgSWRlbnRpdHkpW1NlcGFyYXRvci02XxAPVGV4
+dCBGaWVsZCBDZWxsXxAWQnV0dG9uIENlbGwgKENvbnRpbnVlKVtTZXBhcmF0b3ItNW8QEgBQAHUAcwBo
+ACAAQgB1AHQAdABvAG4AIAAoAE4AZQB3ICYAKV8QEVRhYmxlIEhlYWRlciBWaWV3XxARVmVydGljYWwg
+U2Nyb2xsZXJfEBRNZW51IChLZXJiZXJvc0FnZW50KV8QGFRleHQgRmllbGQgQ2VsbCAoUmVhbG06KVtT
+Y3JvbGwgVmlld1tBcHBsaWNhdGlvbl8QHEltYWdlIFZpZXcgKEtlcmJlcm9zQWdlbnQpLTFfEBRCdXR0
+b24gQ2VsbCAoQ2FuY2VsKV8QEU1lbnUgSXRlbSAoUGFzdGUp0gAOAD4Hcgp8gQHuowRXBFwDRYDsgQEB
+gNjSAA4APgdyCoKBAe6jBHsE0AQngO2BAQKA2dIADgA+B3IKiIEB7q8Qlwd0ATQBfwT0BQAEDgJ1AHkE
+7gZNBFgFWwUIArMFCQMFB38BgABPBCQFnAWkBPwAiAK0BSQE/QUKA0AGkgRWBK4HjAYCARQAQQeQBQEG
+EAGOBM4FDAKhBtwDPwVaB5gGvwYwBeUDQQUDBvcEXAbNA0QAeAeiBQ8C0ARJBU4HpgB7BcIF8ATyBuoH
+qwKgBL0E+QMoBGIHsAK1BPEEVwT1AB8FDQNeBQUDrAIfBPMHtgT+B7cE+gVdA0sFBwRaBPgDewBCBa4D
+MALzBFsC5AU1Bk4E8ANrA0IF3QT2A0MFBAT3AHwFCwKQAloAxwM6BQYG/wfOAb4E+wScArEFzwK6BYoG
+qgNFBFkFXAMnB9oEeAT/BIsH3QB9AUwE7wUCAR8FDgWSA4QAegXvAkYCrQYdgQHGgDaAQIEBOoEBboDV
+gIOAIYEBEYEBeoDxgQEngQGSgJKBAZaAnoEBzYBLgA2A3IEBNYEBNoEBYIAagJWBAReBAWWBAZuAsYEB
+hYDogPuBAdyBAViAX4AHgQHJgQFwgQFdgEiBAQSBAaOBAQeBAZyAq4EBJYEBzoEBk4EBaIEBTICugQGC
+gQGkgQEBgQGXgNOAEIEB4YEBwYCTgOaBASKBAeCAZYEBQoEBUYEBL4EBoIEB0oCIgP+BAVCA5IDrgQHV
+gJmBASGA7IEBP4ACgQGmgK+BAYmAv4BngQE0gQHogQFngQHZgQFXgQEqgKyBAYuA+YEBSoC0gH6BATuA
+poCagP2AloEBGIEBcoEBFoC6gLyBAUuBAUGAs4EBhIEBRYBtgQGfgIaAdIAjgKiBAYqBAaeBAdqAUYEB
+XID3gIqBAUaAjIEBMIEBjIDYgPWBASmApIEB5oDwgQFsgPOBAdGAcoA4gQEUgQFxgFuBAauBATGA0YAy
+gQFUgG+Aj4EBYdIADgA+B3ILIoEB7q8QlwsjCyQLJQsmCycLKAspCyoLKwssCy0LLgsvCzALMQsyCzML
+NAs1CzYLNws4CzkLOgs7CzwLPQs+Cz8LQAtBC0ILQwtEC0ULRgtHC0gLSQtKC0sLTAtNC04LTwtQC1EL
+UgtTC1QLVQtWC1cLWAtZC1oLWwtcC10LXgtfC2ALYQtiC2MLZAtlC2YLZwtoC2kLagtrC2wLbQtuC28L
+cAtxC3ILcwt0C3ULdgt3C3gLeQt6C3sLfAt9C34LfwuAC4ELgguDC4QLhQuGC4cLiAuJC4oLiwuMC40L
+jguPC5ALkQuSC5MLlAuVC5YLlwuYC5kLmgubC5wLnQueC58LoAuhC6ILowukC6ULpgunC6gLqQuqC6sL
+rAutC64LrwuwC7ELsguzC7QLtQu2C7cLuAu5gQJpgQJqgQJrgQJsgQJtgQJugQJvgQJwgQJxgQJygQJz
+gQJ0gQJ1gQJ2gQJ3gQJ4gQJ5gQJ6gQJ7gQJ8gQJ9gQJ+gQJ/gQKAgQKBgQKCgQKDgQKEgQKFgQKGgQKH
+gQKIgQKJgQKKgQKLgQKMgQKNgQKOgQKPgQKQgQKRgQKSgQKTgQKUgQKVgQKWgQKXgQKYgQKZgQKagQKb
+gQKcgQKdgQKegQKfgQKggQKhgQKigQKjgQKkgQKlgQKmgQKngQKogQKpgQKqgQKrgQKsgQKtgQKugQKv
+gQKwgQKxgQKygQKzgQK0gQK1gQK2gQK3gQK4gQK5gQK6gQK7gQK8gQK9gQK+gQK/gQLAgQLBgQLCgQLD
+gQLEgQLFgQLGgQLHgQLIgQLJgQLKgQLLgQLMgQLNgQLOgQLPgQLQgQLRgQLSgQLTgQLUgQLVgQLWgQLX
+gQLYgQLZgQLagQLbgQLcgQLdgQLegQLfgQLggQLhgQLigQLjgQLkgQLlgQLmgQLngQLogQLpgQLqgQLr
+gQLsgQLtgQLugQLvgQLwgQLxgQLygQLzgQL0gQL1gQL2gQL3gQL4gQL5gQL6gQL7gQL8gQL9gQL+gQL/
+EgAElA0QChALEgAElEgSAAST7RIAAYbBEBQQCBBEEgAEk/YQLxIABJQBEgAElEsQPxIABJRGEgABhuMS
+AASUHBASEgAEk/0SAASUMxIABJQqEgAElFASAAGGpxBAEgAElBQQQhIABJRDEBwSAASULBArEgABhtES
+AASUDxIABJQuEgADDUkSAASUERIABJQGEgAElBcSAAST8hIABJPrEgAElAsQOxIABJQjEBsSAASUAhIA
+BJQlEgAElBoSAASUMhIABJQoEB0SAASUCBIABJP3EgAEk+oSAASUIhAhEAcSAASUEhIABJP7EgABht4Q
+FxIABJP+EgAElDUSAASUMRIABJQfEgAElFUSAASUHRIABJQkEDwSAAGG0hIABJREEBYSAAGGyxIABJQn
+EEMSAASUBBAtEgAElAcSAASUTxIAAYa7EgAElAUSAAGGvxIAAYavEgAElEwSAASUEBIABJROEgAElCAS
+AASUTRIABJP/EgABhroSAASUDBAxEgAElFQSAAGGvBATEgAElBkSAAGG4BAyEgABht8SAASUExIABJP1
+EgAElEkSAAGGvRAfEgAElCkSAASUUhAgEgAElFESAASUUxIABJRFEBUSAAGGsRIAAYaoEBoSAASUCRIA
+BJQ0EgAElB4SAAST8xIABJRKEgABhtAQPRIABJQvEgABht0SAASUJhIABJP4EgAEk/wQMBIABJQAEBgS
+AASUFRIAAYbNEEESAAGGzxIABJQhEBESAAST6RAjEgAElAoSAAGGqRIABJP6EgAElBsSAAGGwBAJE///
+///////9EgABhrAQPhIABJQw0gAOAD4AdgxNgFKg0gAOAD4HcgxQgQHuoNIADgA+B3IMU4EB7qDSADcA
+OAxVDFaiDFYAO15OU0lCT2JqZWN0RGF0YQAIABkAIgAnADEAOgA/AEQAUgBUAGYGcgZ4BsMGygbRBt8G
+8QcNBxsHJwczB0EHTAdaB3YHhAeXB6kHwwfNB9oH3AffB+IH5QfoB+sH7gfwB/MH9gf5B/wH/ggACAMI
+BggLCA4IFwgjCCUIJwg1CD4IRwhSCFcIZghvCIIIiwiWCJgInQifCKEI0gjfCOwI+gkECRIJHwkpCTsJ
+TwlZCWUJZwlpCWsJbQlyCXQJdgl4CXoJfAl+CYAJmwm4CcEJywnNCdYJ3wnmCfgKAQoKCgwKEQouCkAK
+SwpUCmAKbApuCnAKcgp1CncKeQp7CoQKhgqTCpUKlwqZCpsKnQqfCsgK0ArbCuIK7gr4CvoK/Ar+Cv8L
+AQsDCwYLBwsJCwsLFAsWCyMLJQsnCykLKwstCy8LSwtnC5sLswvUC/EL+gwBDA4MFAwsDE0MWQxhDGwM
+dAx8DIkMlAyZDJsMnQyfDKQMpQyyDMEMwwzFDMcMzwzdDOYM6wz+DQcNDg0aDSMNLg06DUQNSw1XDXgN
+eg18DX4NgA2DDYQNhg2IDaENwg3WDeAN7g36Df8OAQ4DDgUOBw4JDg4OEA40DkUOTA5TDlwOXg5nDmkO
+bA55DoIOhw6ODqMOqw64DsQO0g7UDtYO2A7aDtwO4w7wDv0PBQ8HDwkPFQ8eDyMPOA86DzwPPg9AD1MP
+YA9iD2UPbg93D4kPlg+fD6oPtg/1EAEQChAXECoQNxBDEFEQXxBhEGMQZRBnEGoQbBBuEHAQgxCGEIgQ
+ihCMEI4QkBCZEJsQphCoEKoQrBCuELAQ3RDnEPEQ+xD9EP8RAREDEQURCBEKEQwRDhEQERIRGxEdESAR
+IhF1EZcRoRGuEcMR3RH5EhQSIBI/Ek4SWhJcEl4SYxJlEmcSaBJqEnMSdRJ+EoASgRKDEoUShxKJEpIS
+nRK6EsYSyBLKEswSzhLQEtIS/xMBEwMTBRMHEwkTCxMNEw8TERMbEyQTLRNBE1oTXBNeE2ATaRNrE20T
+hBONE5YTpBOtE68TtBO2E7gT4RPwE/0UBRQQFB8UKhQ1FEIUQxRFFEcUUBRSFFsUZBRlFGcUhBSJFIsU
+jRSPFJEUkxScFK0UrxS4FLoUvRTKFMwU2BTtFO8U8RTzFPUVBxUQFRsVLxVQFVUVVxVZFVsVXRVfFWQV
+ZhVwFXkVfhWMFbUVthW4FboVwxXFFc4V1xXYFdoV9xX5FfsV/RX/FgQWBhYVFioWLBYuFjAWMhY+FksW
+TRZQFnEWdhZ4FnoWfBZ+FoAWhRaHFpAWlxamFq4WwxbFFscWyRbLFtUW4hbkFukW8hb9FxUXKhcsFy4X
+MBcyF0sXVBddF2gXjReWF58XqRerF60XrxexF7MXtRe3F8AX2RfmF+8X+hgFGC4YMBgyGDQYNhg4GDoY
+PBg+GEcYXxhoGGoYbRhvGIUYnhinGLAYvRjeGOAY4hjkGOYY6RjqGOwY7hkGGTsZURlmGXUZiBmaGawZ
+uhm8Gb4ZwBnCGcQZxhnIGcoZzBnRGdoZ4RniGesZ7Rn2Gf8aDBoVGiAaKRpKGkwaThpQGlIaUxpVGlca
+bxqkGqYaqBqqGqwarhqwGrIauRrCGsQa5RrnGuka6xrtGu4a8BryGwobPxtBG0MbRRtHG0kbSxtNG1Yb
+XxthG2wbdRt8G5UboBu9G8YbyxveHBMcKRwrHC0cMBwyHDQcNhw4HDscPRxAHEIcXRx4HIEcgxyMHI4c
+qxytHK8csRy0HLYcuRzCHMQcxxzJHQIdER0lHT4dVh1YHVsdXR1fHWEdYx1lHWYdaB1pHWsdbh13HXkd
+fB1+HZ8doR2jHaUdpx2pHasdrR22Hbgdwx3FHccdyR3LHc0d8h30HfYd+B36Hfsd/R3/HgEeGR5OHlAe
+Uh5UHlYeWB5aHlweYR5qHmwemR6bHp0enx6gHqIepB6lHqceqR6rHrQeth7DHsUexx7JHssezR7PHucf
+DB8OHxAfEh8UHxUfFx8ZHxsfPB9BH0MfRR9GH18fhB+GH4gfih+MH40fjx+RH5MftB+2H7gfuh+8H74f
+wB/LH+MgCCAKIAwgDiAQIBEgEyAVIBcgOCA6IDwgPiBAIEIgRyBJIJcgpCCmILQgzCEBIQMhBSEHIQkh
+CyENIQ8hFyEgISIhLSFFIU4hUCFXIVkhWyFeIXchhCGOIZYhmCGaIZwhniGgIaIhpCG9Ib8hwSHDIcUh
+xyHQIdIh4yHlIech6SHrIe0h7yHxIfMiHCIeIiAiIiIjIiUiJyIoIioiLCI1IjciRCJGIkgiSiJMIk4i
+UCJoIokiiyKNIo8ikSKSIpQiliK3IrkiuyK8ItUi9iL4Ivoi/CL+Iv8jASMDIyQjJiMoIyojLCMuIzAj
+ViN3I3kjeyN9I38jgCOCI4QjnCO9I78jwSPDI8UjxiPII8oj7yP4I/oj/CP+JAAkAiQHJAgkCiQfJCEk
+IyQlJCckPSRSJFQkViRYJFokZCR7JJwkniSgJKIkpCSmJKskrSSzJNQk1iTYJNok3CTdJN8k4ST5JS4l
+OSVOJWYlaCVtJW8lcSVzJXUldyV4JXoleyV9JYYliCXjJfAl8iX0JfYl/yYBJgMmBCYGJggmCSYLJg0m
+DyYRJhMmHCYkJi0mLyYyJjQmXSZeJmAmYiZkJm0mbyZ4JnomlyaZJpsmnSafJqEmsia0JrYmuCbFJscm
+6CbtJu8m8SbzJvUm+Cb5JvsnDicXJyQnNydAJ0snWidjJ3AneyeSJ7MntSe3J7knuye9J78nxifnJ+kn
+6yftJ+8n8CfyJ/QoDChBKEMoRShHKEkoSyhNKE8oWChhKGMoiCieKKAooiikKKYoqCirKKworiiwKLwo
+0ykIKRYpGCkaKRwpHikgKSIpJCkmKSkpMilDKUUpRylUKVYpWClaKV8paCltKXwpjimXKZwpqinDKcUp
+xynJKcspzSnQKdIp5ynpKesp7SnwKfkp+yoKKgwqDioQKhIqFCoWKhkqPipAKkIqRCpFKkcqSSpKKkwq
+VSpXKmQqZipoKmoqbCpuKnAqkSqTKpUqliq7Kr0qvyrBKsMqxSrIKskqyyrNKuEq+SseKyArIiskKyYr
+KCspKysrSCtKK0wrTitQK1ErUyuIK4orjCuOK5ArkiuUK5YrnyuhK74rwCvCK8QrxivHK8kr4SwWLBgs
+GiwcLB4sICwiLCQsLSwvLEwsTixQLFIsVCxVLFcseCx6LHwsfiyALIIshCyqLMcsySzLLM0szyzQLNIs
+6i0LLQ0tDy0SLRQtFi0YLUstcC1yLXQtdy15LXwtfS2ALYItmS3OLdAt0i3ULdYt2C3aLd0t5i4DLhwu
+Hi4hLiMuJS4nLiouLC4zLjwuRS5QLl4ucy58Ln4uxS7ILssuzi7RLtQu1y7aLt0u4C7jLuYu6S7sLu8u
+8i71Lvgu+y7+LwEvBC8HLwovDS8QLxMvFi8ZLxwvHy8iLyUvKC8rLzwvSi9TL1YvWC9aL10vei+DL4ov
+oi+xL8IvxS/HL8kvzC/lL/Iv9S/4L/swHDAkMDgwQzBRMFswaDBvMHIwdTB6MH0wgjCFMIgwizCcMKgw
+qzCuMLEwtDC9ML8wzDDOMNAw0zDlMPIw9DD2MPkxDDEVMRoxJTE7MUwxTzFSMVQxVzFoMWsxbjFwMXMx
+eDGBMYMxjDGPMZIxlTGYMbkxvDG/McExxDHHMcox6zIMMg8yEjIUMhcyGjIdMkAyaTJ3MoQyhzKJMooy
+jDKNMpAykzKWMrcyujK9Mr8ywjLFMsgy3DLlMuoy7zL4Mv8zFjMnMyozLDMvMzIzTzNSM1UzVzNaM10z
+YDNxM3QzdzN6M30zkzOzM8AzwzPGM8kz6jPtM/Az8zP2M/kz/DQJNAw0DzQSNBc0GTQfNCw0LzQyNDU0
+VjRZNFw0XzRiNGU0aDRuNHA0fjSPNJI0lDSWNJk0pTSyNLU0uDS7NNw03zTiNOQ05zTqNO009DT8NQk1
+DDUPNRI1MzU2NTk1PDU/NUI1RTVQNVI1XTVqNW01cDVzNZQ1lzWaNZ01oDWjNaY1szW2Nbk1vDXRNdM1
+3TXuNfE19DX3Nfo2GzYeNiE2JjYpNiw2LzYyNj42QDZJNks2TjZnNnQ2dzZ6Nn02njahNqQ2pzaqNq02
+sDa1Nrc2vTbKNs020DbTNvQ29zb6Nvw2/zcCNwU3CjcXNyQ3JzcqNy03TjdRN1Q3VzdaN103YDdmN2g3
+bzeAN4M3hTeHN4o3lzeaN503oDfBN8Q3xzfKN8030DfTN9c32TfeN+838jf0N/Y3+TgKOA04DzgROBQ4
+JTgoOCo4LDgvOEA4QzhGOEk4TDh1OJI4qTi7OM843jkDOR45Nzk4OTs5PDk/OUA5QzlGOUc5SDlJOVI5
+VDlZOVw5Xzl4OZM5qDmtObA5uTm+Occ50DnkOfk6BjorOiw6LzowOjM6Njo5Ojo6Ozo8OkU6RzpOOlE6
+VDpXOmo6fDqKOo86kjqaOqs6rjqxOrQ6tzrBOs460TrUOtc6+Dr7Ov47ATsEOwc7CjsiOyQ7ODtJO0w7
+TztRO1Q7ZTtoO2s7bjtxO4I7hTuIO4s7jjufO6I7pTuoO6s7tDu2O7k7vDvIO+I75zvqO/M7+jwLPA48
+ETwUPBc8ODw7PD48QDxDPEY8STxePHA8gTyEPIc8ijyNPK48sTy0PLc8ujy9PMA81TzXPOI88zz2PPk8
+/Dz/PSA9Iz0mPSk9LD0vPTI9Rz1NPV49YT1kPWc9aj2LPY49kT2TPZY9mT2cPaU9rT2+PcE9xD3HPco9
+0z3VPdg95T3oPes97j4PPhI+FT4YPhs+Hj4hPiY+KD4uPk8+WT5jPm0+jD6PPpI+lT6YPpo+nT6gPsk+
+zz7xPv4/Bj8JPyI/JT8oPys/Lj8xPzQ/Nz86Pz0/QD9DP0Y/Xz9iP2U/aD9rP24/cT90P3c/ej99P4A/
+gz+gP78/2EABQB9AM0BQQGpAh0CiQMtA6UDqQOtA9ED5QQZBD0EWQS5BT0FSQVVBWEFbQV1BYEFjQZVB
+wEHNQdBB6UHsQe9B8kH1QfhB+0H+QgFCBEIHQgpCDUImQilCLEIvQjJCNUI4QjtCPkJBQkRCR0JKQlNC
+VkNBQ0RDRkNIQ0pDTENOQ1FDU0NWQ1hDWkNdQ19DYUNjQ2ZDaUNrQ21DcENyQ3VDd0N5Q3xDf0OBQ4ND
+hkOJQ4tDjkORQ5RDlkOZQ5xDn0OiQ6VDp0OqQ61DsEOyQ7RDt0O5Q7tDvkPBQ8NDxkPJQ8xDz0PRQ9ND
+1UPXQ9pD3EPeQ+BD4kPkQ+dD6kPtQ+9D8UPzQ/VD+EP6Q/xD/kQARANEBkQIRApEDUQPRBFEE0QVRBdE
+GUQcRB9EIUQjRCVEKEQqRC1EMEQyRDREN0Q5RDxEPkRARENERURHRElETERORFBEU0RVRFdEWkRrRG5E
+cUR0RHdEhkSPRJFEmkSdRKBEo0SmRM9E2UTcRN9E4kTkROdE6kTtRPBE/0UIRQpFIUUkRSdFKkUtRTBF
+M0U2RTlFPEU/RUJFa0VuRXBFcUVzRXRFd0V6RX1FnkWhRaRFp0WqRa1FsEXJRctF9EX3RflF+kX8Rf1G
+AEYDRgZGL0YyRjVGOEY6Rj1GQEZDRkZGT0ZgRmNGZkZpRmxGdUZ3RoBGgkaDRpVGvkbBRsNGxEbGRsdG
+ykbNRtBG+Ub8Rv5G/0cBRwJHBUcIRwtHGEdBR0RHR0dKR0xHT0dSR1VHWEddR2ZHaEd7R35HgUeER4dH
+ikeNR5BHk0eWR79HwkfER8VHx0fIR8tHzkfRR/pH/UgASANIBUgISAtIDkgRSBhIIUgjSCxILkg5SDxI
+P0hCSEVISEhxSHRIdkh3SHlIekh9SIBIg0iSSLtIvkjBSMRIxkjJSMxIz0jSSNdI4EjiSOtI7UjwSPNI
+/0kISQ1JFkkZSgRKBkoISgpKDEoOShBKEkoUShdKGUobSh5KIEoiSiRKJ0oqSixKLkoxSjNKNko4SjpK
+PUpASkJKREpHSkpKTEpPSlFKVEpWSllKXEpfSmJKZUpnSmlKa0puSnBKckp1SndKeUp7Sn5KgEqDSoZK
+iUqMSo9KkUqTSpVKmEqaSpxKnkqgSqJKpUqoSqtKrUqvSrFKs0q2SrhKukq8Sr5KwUrDSsVKx0rKSsxK
+zkrQStJK1ErWStlK3EreSuBK4krlSudK6krsSu5K8ErzSvVK+Er6SvxK/0sBSwNLBUsISwpLDEsOSxBL
+EksVSx5LIUwOTBFME0wVTBdMGUwbTB5MIEwjTCVMJ0wqTCxMLkwwTDNMNkw4TDpMPUxATEJMRExHTEpM
+TExOTFBMU0xWTFhMW0xeTGFMY0xmTGlMbExvTHJMdEx3THpMfUyATIJMhEyGTIlMi0yOTJFMk0yWTJlM
+nEyeTKBMokykTKdMqUyrTK1Mr0yxTLNMtky5TLxMvkzATMJMxEzHTMlMy0zNTNBM0kzVTNhM2kzcTN5M
+4EziTORM5kzoTOtM7kzwTPJM9Ez3TPlM/Ez/TQFNBE0GTQhNC00NTQ9NEk0UTRZNGE0bTR1NH00iTSRN
+Jk0pTTJNNU4iTiVOKE4rTi5OMU40TjdOOk49TkBOQ05GTklOTE5PTlJOVU5YTltOXk5hTmROZ05qTm1O
+cE5zTnZOeU58Tn9Ogk6FTohOi06OTpFOlE6XTppOnU6gTqNOpk6pTqxOr06yTrVOuE67Tr5OwU7ETsdO
+yk7NTtBO007WTtlO3E7fTuJO5U7oTutO7k7xTvRO9076Tv1PAE8DTwZPCU8MTw9PEk8VTxhPG08eTyFP
+JE8nTypPLU8wTzNPNk85TzxPP09CT0VPSE9LT05PUU9UT1dPWk9dT2BPY09mT2lPbE9vT3JPdU94T3tP
+fk+BT4pPsk/MT+dP9lAoUDtQVFCPUKpQwlDOUO5Q+1ESUSVRMVFOUapRwVHlUfBSD1IiUjVSbVKDUp9S
+slLQUuVS/lMfU1NTjFO/U+BT8lP+VBRUNVRKVGBUfVSYVLdUwFTHVNNU7VUEVRlVMFVHVYxVuVXYVepW
+AlYWViNWW1ZqVoFWlFagVsBW31cTVydXL1dDV0pXqlfrV/lYGFgwWFFYW1h1WIxYo1juWRVZS1lqWX1Z
+iVmpWcNZ2FnxWgZaKFpEWlxaZlqAWqJarlrAWtla5VsMWyBbNFtLW2Zbclt+W51btFvIW9Fb1FvbW91b
+4FviW+tb7lv1W/db+lv8XAVcCF05XTxdPl1AXUNdRl1IXUpdTF1PXVJdVF1XXVpdXF1fXWFdZF1mXWhd
+al1tXXBdc111XXddel19XYBdgl2FXYddiV2MXY9dkV2TXZZdmV2cXZ5doV2kXaddql2sXa9dsl21Xbhd
+u129XcBdw13GXcldy13NXdBd013VXddd2l3dXd9d4l3lXehd613uXfBd8l31Xfdd+V38Xf5eAV4DXgZe
+CF4LXg1eEF4SXhReF14aXh1eIF4jXiZeKF4rXi1eMF4yXjReN145XjtePV4/XkJeRV5IXkpeTF5PXlJe
+VF5XXlpeXF5fXmFeY15lXmdeal5tXnBecl51XndeeV58Xn5egV6EXoZeiF6LXo1ekF6SXpVel16aXpxe
+nl6hXqRepl6pXqxerl6wXrNetV63Xrpew17GX/df+l/9YABgA2AGYAlgDGAPYBJgFWAYYBtgHmAhYCRg
+J2AqYC1gMGAzYDZgOWA8YD9gQmBFYEhgS2BOYFFgVGBXYFpgXWBgYGNgZmBpYGxgb2ByYHVgeGB7YH5g
+gWCEYIdgimCNYJBgk2CWYJlgnGCfYKJgpWCoYKtgrmCxYLRgt2C6YL1gwGDDYMZgyWDMYM9g0mDVYNhg
+22DeYOFg5GDnYOpg7WDwYPNg9mD5YPxg/2ECYQVhCGELYQ5hEWEUYRdhGmEdYSBhI2EmYSlhLGEvYTJh
+NWE4YTthPmFBYURhR2FKYU1hUGFTYVZhWWFcYV9hYmFlYWhha2FuYXFhdGF3YXphfWGAYYNhhmGJYYxh
+j2GSYZVhmGGbYZ5hoWGkYadhqmGtYbBhs2G2YblhvGHBYcNhxWHKYc9h1GHWYdhh2mHfYeFh5mHrYe1h
+8mH3Yfxh/mIDYghiDWISYhdiGWIeYiBiJWInYixiLmIzYjhiPWJCYkdiTGJRYlZiW2JgYmJiZ2JpYm5i
+c2J4Yn1igmKEYolijmKTYphimmKcYqFipmKrYq1ismK3YrxiwWLGYsti0GLSYtdi3GLeYuNi6GLqYu9i
+8WL2YvtjAGMFYwpjD2MUYxljHmMjYyhjLWMyYzdjOWM+Y0NjRWNKY09jUWNWY1tjYGNlY2pjbGNxY3Zj
+eGN9Y4Jjh2OJY45jk2OVY5pjn2OkY6ljrmOzY7VjumO/Y8RjyWPOY9Bj1WPXY9xj4WPjY+hj7WPvY/Rj
+9mP7ZABkBWQKZA9kEWQaZB9kIWQmZC9kMWQyZDtkPmQ/ZEhkS2RMZFVkWgAAAAAAAAICAAAAAAAADFcA
+AAAAAAAAAAAAAAAAAGRpA</bytes>
+ </object>
+ </data>
+</archive>
diff --git a/src/kim/agent/mac/resources/English.lproj/MainMenu.xib b/src/kim/agent/mac/resources/English.lproj/MainMenu.xib
new file mode 100644
index 0000000..12d33cb
--- /dev/null
+++ b/src/kim/agent/mac/resources/English.lproj/MainMenu.xib
@@ -0,0 +1,3882 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.01">
+ <data>
+ <int key="IBDocument.SystemTarget">1050</int>
+ <string key="IBDocument.SystemVersion">9A581</string>
+ <string key="IBDocument.InterfaceBuilderVersion">629</string>
+ <string key="IBDocument.AppKitVersion">949</string>
+ <string key="IBDocument.HIToolboxVersion">343.00</string>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="300378"/>
+ <integer value="300336"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string id="438620934">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="949938097">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="58791012">
+ <object class="NSMutableString" key="NSClassName">
+ <characters key="NS.bytes">NSApplication</characters>
+ </object>
+ </object>
+ <object class="NSCustomObject" id="506161835">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="364998124">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSMenu" id="576137369">
+ <string key="NSTitle" id="33876972">MainMenu</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="946093663">
+ <reference key="NSMenu" ref="576137369"/>
+ <string key="NSTitle" id="399535664">KerberosAgent</string>
+ <string key="NSKeyEquiv" id="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <object class="NSCustomResource" key="NSOnImage" id="42192827">
+ <string key="NSClassName" id="98235535">NSImage</string>
+ <string key="NSResourceName">NSMenuCheckmark</string>
+ </object>
+ <object class="NSCustomResource" key="NSMixedImage" id="573706172">
+ <reference key="NSClassName" ref="98235535"/>
+ <string key="NSResourceName">NSMenuMixedState</string>
+ </object>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="980333367">
+ <reference key="NSTitle" ref="399535664"/>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="104201360">
+ <reference key="NSMenu" ref="980333367"/>
+ <string key="NSTitle">About KerberosAgent</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="941049996">
+ <reference key="NSMenu" ref="980333367"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="1001321221"/>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="885473566">
+ <reference key="NSMenu" ref="980333367"/>
+ <string type="base64-UTF8" key="NSTitle">UHJlZmVyZW5jZXPigKY</string>
+ <string key="NSKeyEquiv">,</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="773057625">
+ <reference key="NSMenu" ref="980333367"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="1001321221"/>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="701559942">
+ <reference key="NSMenu" ref="980333367"/>
+ <string key="NSTitle">Services</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="297859549">
+ <object class="NSMutableString" key="NSTitle">
+ <characters key="NS.bytes">Services</characters>
+ </object>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <string key="NSName">_NSServicesMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="2694966">
+ <reference key="NSMenu" ref="980333367"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="1001321221"/>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="329699580">
+ <reference key="NSMenu" ref="980333367"/>
+ <string key="NSTitle">Hide KerberosAgent</string>
+ <string key="NSKeyEquiv" id="1034269235">h</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="844777333">
+ <reference key="NSMenu" ref="980333367"/>
+ <string key="NSTitle">Hide Others</string>
+ <reference key="NSKeyEquiv" ref="1034269235"/>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="110892548">
+ <reference key="NSMenu" ref="980333367"/>
+ <string key="NSTitle">Show All</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="354292100">
+ <reference key="NSMenu" ref="980333367"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="1001321221"/>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="10506244">
+ <reference key="NSMenu" ref="980333367"/>
+ <string key="NSTitle">Quit KerberosAgent</string>
+ <string key="NSKeyEquiv">q</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ </object>
+ <string key="NSName">_NSAppleMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="1071484604">
+ <reference key="NSMenu" ref="576137369"/>
+ <string key="NSTitle" id="759385032">Edit</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="694937866">
+ <reference key="NSTitle" ref="759385032"/>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="9292975">
+ <reference key="NSMenu" ref="694937866"/>
+ <string key="NSTitle">Undo</string>
+ <string key="NSKeyEquiv">z</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="970758993">
+ <reference key="NSMenu" ref="694937866"/>
+ <string key="NSTitle">Redo</string>
+ <string key="NSKeyEquiv">Z</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="851800591">
+ <reference key="NSMenu" ref="694937866"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="1001321221"/>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="644214546">
+ <reference key="NSMenu" ref="694937866"/>
+ <string key="NSTitle">Cut</string>
+ <string key="NSKeyEquiv">x</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="157511090">
+ <reference key="NSMenu" ref="694937866"/>
+ <string key="NSTitle">Copy</string>
+ <string key="NSKeyEquiv">c</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="76167146">
+ <reference key="NSMenu" ref="694937866"/>
+ <string key="NSTitle">Paste</string>
+ <string key="NSKeyEquiv">v</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="872606351">
+ <reference key="NSMenu" ref="694937866"/>
+ <string key="NSTitle">Paste and Match Style</string>
+ <string key="NSKeyEquiv">V</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="693913733">
+ <reference key="NSMenu" ref="694937866"/>
+ <string key="NSTitle">Delete</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="491366892">
+ <reference key="NSMenu" ref="694937866"/>
+ <string key="NSTitle">Select All</string>
+ <string key="NSKeyEquiv">a</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="132646693">
+ <reference key="NSMenu" ref="576137369"/>
+ <string key="NSTitle" id="703913682">Window</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="307678365">
+ <object class="NSMutableString" key="NSTitle">
+ <characters key="NS.bytes">Window</characters>
+ </object>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="499080229">
+ <reference key="NSMenu" ref="307678365"/>
+ <string key="NSTitle">Close</string>
+ <string key="NSKeyEquiv">w</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="308116730">
+ <reference key="NSMenu" ref="307678365"/>
+ <string key="NSTitle">Minimize</string>
+ <string key="NSKeyEquiv">m</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="695757627">
+ <reference key="NSMenu" ref="307678365"/>
+ <string key="NSTitle">Zoom</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="615570499">
+ <reference key="NSMenu" ref="307678365"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="1001321221"/>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="150140133">
+ <reference key="NSMenu" ref="307678365"/>
+ <string key="NSTitle">Bring All to Front</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ </object>
+ <string key="NSName">_NSWindowsMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="608222506">
+ <reference key="NSMenu" ref="576137369"/>
+ <string key="NSTitle">Help</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="566679562">
+ <object class="NSMutableString" key="NSTitle">
+ <characters key="NS.bytes">Help</characters>
+ </object>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="376978259">
+ <reference key="NSMenu" ref="566679562"/>
+ <string key="NSTitle">KerberosAgent Help</string>
+ <string key="NSKeyEquiv">?</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ <string key="NSName">_NSMainMenu</string>
+ </object>
+ <object class="NSObjectController" id="116785486">
+ <object class="NSMutableArray" key="NSDeclaredKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>cachesArray</string>
+ </object>
+ <string key="NSObjectClassName" id="1053976860">KerberosCacheCollection</string>
+ <object class="_NSManagedProxy" key="_NSManagedProxy"/>
+ </object>
+ <object class="NSCustomObject" id="171210350">
+ <reference key="NSClassName" ref="1053976860"/>
+ </object>
+ <object class="NSArrayController" id="21498042">
+ <object class="NSMutableArray" key="NSDeclaredKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>credentialsArray</string>
+ <string>principalString</string>
+ <string id="130005483">shortTimeRemainingString</string>
+ <string>timeRemainingString</string>
+ </object>
+ <string key="NSObjectClassName">KerberosCache</string>
+ <object class="_NSManagedProxy" key="_NSManagedProxy"/>
+ <bool key="NSAvoidsEmptySelection">YES</bool>
+ <bool key="NSPreservesSelection">YES</bool>
+ <bool key="NSSelectsInsertedObjects">YES</bool>
+ <bool key="NSFilterRestrictsInsertion">YES</bool>
+ <bool key="NSClearsFilterPredicateOnInsertion">YES</bool>
+ </object>
+ <object class="NSArrayController" id="220358512">
+ <object class="NSMutableArray" key="NSDeclaredKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>servicePrincipalString</string>
+ <reference ref="130005483"/>
+ </object>
+ <string key="NSObjectClassName">KerberosCredential</string>
+ <bool key="NSEditable">YES</bool>
+ <object class="_NSManagedProxy" key="_NSManagedProxy"/>
+ <bool key="NSAvoidsEmptySelection">YES</bool>
+ <bool key="NSPreservesSelection">YES</bool>
+ <bool key="NSSelectsInsertedObjects">YES</bool>
+ <bool key="NSFilterRestrictsInsertion">YES</bool>
+ <bool key="NSClearsFilterPredicateOnInsertion">YES</bool>
+ </object>
+ <object class="NSWindowTemplate" id="7348993">
+ <int key="NSWindowStyleMask">13</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{279, 363}, {419, 465}}</string>
+ <int key="NSWTFlags">1886912512</int>
+ <string key="NSWindowTitle">Choose a Kerberos Identity</string>
+ <object class="NSMutableString" key="NSWindowClass">
+ <characters key="NS.bytes">NSWindow</characters>
+ </object>
+ <object class="NSMutableString" key="NSViewClass">
+ <characters key="NS.bytes">View</characters>
+ </object>
+ <object class="NSView" key="NSWindowView" id="221966185">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSImageView" id="919779806">
+ <reference key="NSNextResponder" ref="221966185"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string id="248893621">Apple PDF pasteboard type</string>
+ <string id="792839034">Apple PICT pasteboard type</string>
+ <string id="139007242">Apple PNG pasteboard type</string>
+ <string id="513246449">NSFilenamesPboardType</string>
+ <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
+ <string id="676443656">NeXT TIFF v4.0 pasteboard type</string>
+ </object>
+ </object>
+ <string key="NSFrame">{{17, 386}, {62, 62}}</string>
+ <reference key="NSSuperview" ref="221966185"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="405384087">
+ <int key="NSCellFlags">537001472</int>
+ <int key="NSCellFlags2">33554432</int>
+ <object class="NSCustomResource" key="NSContents" id="14953420">
+ <reference key="NSClassName" ref="98235535"/>
+ <string key="NSResourceName">KerberosAgent</string>
+ </object>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ <object class="NSTextField" id="837237465">
+ <reference key="NSNextResponder" ref="221966185"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{84, 377}, {318, 29}}</string>
+ <reference key="NSSuperview" ref="221966185"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="1006984983">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">4325376</int>
+ <string key="NSContents">Checking mail for account lxs@mit.edu</string>
+ <object class="NSFont" key="NSSupport" id="26">
+ <string key="NSName" id="139607319">LucidaGrande</string>
+ <double key="NSSize">1.100000e+01</double>
+ <int key="NSfFlags">3100</int>
+ </object>
+ <reference key="NSControlView" ref="837237465"/>
+ <object class="NSColor" key="NSBackgroundColor" id="489363697">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName" id="602240259">System</string>
+ <string key="NSColorName">controlColor</string>
+ <object class="NSColor" key="NSColor" id="59293560">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2OQA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="616389791">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="602240259"/>
+ <string key="NSColorName">controlTextColor</string>
+ <object class="NSColor" key="NSColor" id="575450793">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSScrollView" id="536182542">
+ <reference key="NSNextResponder" ref="221966185"/>
+ <int key="NSvFlags">274</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSClipView" id="264355826">
+ <reference key="NSNextResponder" ref="536182542"/>
+ <int key="NSvFlags">2304</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTableView" id="636123923">
+ <reference key="NSNextResponder" ref="264355826"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{380, 291}</string>
+ <reference key="NSSuperview" ref="264355826"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTableHeaderView" key="NSHeaderView" id="159615320">
+ <reference key="NSNextResponder" ref="957348444"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{380, 17}</string>
+ <reference key="NSSuperview" ref="957348444"/>
+ <reference key="NSWindow"/>
+ <reference key="NSTableView" ref="636123923"/>
+ </object>
+ <object class="_NSCornerView" key="NSCornerView" id="279471085">
+ <reference key="NSNextResponder" ref="536182542"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{-26, 0}, {16, 17}}</string>
+ <reference key="NSSuperview" ref="536182542"/>
+ <reference key="NSWindow"/>
+ </object>
+ <object class="NSMutableArray" key="NSTableColumns">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTableColumn" id="726475981">
+ <double key="NSWidth">2.739741e+02</double>
+ <double key="NSMinWidth">1.499741e+02</double>
+ <double key="NSMaxWidth">1.000000e+03</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">75628032</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">Identity</string>
+ <reference key="NSSupport" ref="26"/>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="822687063">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="602240259"/>
+ <string key="NSColorName">headerTextColor</string>
+ <reference key="NSColor" ref="575450793"/>
+ </object>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell" id="393823551">
+ <int key="NSCellFlags">1411513920</int>
+ <int key="NSCellFlags2">1346372608</int>
+ <string key="NSContents" id="684068333">Text Cell</string>
+ <object class="NSFont" key="NSSupport" id="870487994">
+ <reference key="NSName" ref="139607319"/>
+ <double key="NSSize">1.300000e+01</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="636123923"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="489363697"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <bool key="NSIsEditable">YES</bool>
+ <reference key="NSTableView" ref="636123923"/>
+ </object>
+ <object class="NSTableColumn" id="497509491">
+ <double key="NSWidth">1.003135e+02</double>
+ <double key="NSMinWidth">1.000000e+02</double>
+ <double key="NSMaxWidth">1.500000e+02</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">67108864</int>
+ <string key="NSContents">Time Remaining</string>
+ <reference key="NSSupport" ref="26"/>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="602240259"/>
+ <string key="NSColorName">headerColor</string>
+ <object class="NSColor" key="NSColor" id="61380785">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ </object>
+ <reference key="NSTextColor" ref="822687063"/>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell" id="448257474">
+ <int key="NSCellFlags">1140981312</int>
+ <int key="NSCellFlags2">1145046016</int>
+ <reference key="NSContents" ref="684068333"/>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="636123923"/>
+ <reference key="NSBackgroundColor" ref="489363697"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <bool key="NSIsEditable">YES</bool>
+ <reference key="NSTableView" ref="636123923"/>
+ </object>
+ </object>
+ <double key="NSIntercellSpacingWidth">3.000000e+00</double>
+ <double key="NSIntercellSpacingHeight">2.000000e+00</double>
+ <reference key="NSBackgroundColor" ref="61380785"/>
+ <object class="NSColor" key="NSGridColor" id="785987320">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="602240259"/>
+ <string key="NSColorName">gridColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC41AA</bytes>
+ </object>
+ </object>
+ <double key="NSRowHeight">1.700000e+01</double>
+ <int key="NSTvFlags">1119879168</int>
+ <int key="NSColumnAutoresizingStyle">5</int>
+ <int key="NSDraggingSourceMaskForLocal">15</int>
+ <int key="NSDraggingSourceMaskForNonLocal">0</int>
+ <bool key="NSAllowsTypeSelect">YES</bool>
+ </object>
+ </object>
+ <string key="NSFrame">{{1, 17}, {380, 291}}</string>
+ <reference key="NSSuperview" ref="536182542"/>
+ <reference key="NSWindow"/>
+ <reference key="NSDocView" ref="636123923"/>
+ <object class="NSColor" key="NSBGColor" id="458828224">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="602240259"/>
+ <string key="NSColorName">controlBackgroundColor</string>
+ <reference key="NSColor" ref="59293560"/>
+ </object>
+ <int key="NScvFlags">4</int>
+ </object>
+ <object class="NSScroller" id="87192718">
+ <reference key="NSNextResponder" ref="536182542"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{-30, 17}, {15, 285}}</string>
+ <reference key="NSSuperview" ref="536182542"/>
+ <reference key="NSWindow"/>
+ <reference key="NSTarget" ref="536182542"/>
+ <string key="NSAction" id="372881541">_doScroller:</string>
+ <double key="NSPercent">9.684210e-01</double>
+ </object>
+ <object class="NSScroller" id="501018053">
+ <reference key="NSNextResponder" ref="536182542"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{1, -30}, {362, 15}}</string>
+ <reference key="NSSuperview" ref="536182542"/>
+ <reference key="NSWindow"/>
+ <int key="NSsFlags">1</int>
+ <reference key="NSTarget" ref="536182542"/>
+ <reference key="NSAction" ref="372881541"/>
+ <double key="NSPercent">9.040768e-01</double>
+ </object>
+ <object class="NSClipView" id="957348444">
+ <reference key="NSNextResponder" ref="536182542"/>
+ <int key="NSvFlags">2304</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="159615320"/>
+ </object>
+ <string key="NSFrame">{{1, 0}, {380, 17}}</string>
+ <reference key="NSSuperview" ref="536182542"/>
+ <reference key="NSWindow"/>
+ <reference key="NSDocView" ref="159615320"/>
+ <reference key="NSBGColor" ref="458828224"/>
+ <int key="NScvFlags">4</int>
+ </object>
+ <reference ref="279471085"/>
+ </object>
+ <string key="NSFrame">{{17, 60}, {382, 309}}</string>
+ <reference key="NSSuperview" ref="221966185"/>
+ <reference key="NSWindow"/>
+ <int key="NSsFlags">562</int>
+ <reference key="NSVScroller" ref="87192718"/>
+ <reference key="NSHScroller" ref="501018053"/>
+ <reference key="NSContentView" ref="264355826"/>
+ <reference key="NSHeaderClipView" ref="957348444"/>
+ <reference key="NSCornerView" ref="279471085"/>
+ <bytes key="NSScrollAmts">QSAAAEEgAABBmAAAQZgAAA</bytes>
+ </object>
+ <object class="NSButton" id="853176257">
+ <reference key="NSNextResponder" ref="221966185"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{320, 12}, {87, 32}}</string>
+ <reference key="NSSuperview" ref="221966185"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="938853223">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Choose</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="853176257"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="870487994"/>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="47718130">
+ <reference key="NSNextResponder" ref="221966185"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{238, 12}, {82, 32}}</string>
+ <reference key="NSSuperview" ref="221966185"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="887730787">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Cancel</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="47718130"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="870487994"/>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <string type="base64-UTF8" key="NSKeyEquivalent">Gw</string>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="186661261">
+ <reference key="NSNextResponder" ref="221966185"/>
+ <int key="NSvFlags">270</int>
+ <string key="NSFrame">{{84, 414}, {318, 21}}</string>
+ <reference key="NSSuperview" ref="221966185"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="927465653">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">4194304</int>
+ <string key="NSContents">Mail requires that you choose a Kerberos Identity</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="186661261"/>
+ <reference key="NSBackgroundColor" ref="489363697"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ </object>
+ <object class="NSButton" id="474370300">
+ <reference key="NSNextResponder" ref="221966185"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrame">{{17, 30}, {23, 22}}</string>
+ <reference key="NSSuperview" ref="221966185"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="226976488">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="1001321221"/>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="474370300"/>
+ <int key="NSButtonFlags">138690815</int>
+ <int key="NSButtonFlags2">6</int>
+ <object class="NSCustomResource" key="NSNormalImage">
+ <reference key="NSClassName" ref="98235535"/>
+ <string key="NSResourceName">Add</string>
+ </object>
+ <object class="NSCustomResource" key="NSAlternateImage">
+ <reference key="NSClassName" ref="98235535"/>
+ <string key="NSResourceName">Add_Pressed</string>
+ </object>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="355395495">
+ <reference key="NSNextResponder" ref="221966185"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrame">{{39, 30}, {23, 22}}</string>
+ <reference key="NSSuperview" ref="221966185"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="857531424">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="1001321221"/>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="355395495"/>
+ <int key="NSButtonFlags">138690815</int>
+ <int key="NSButtonFlags2">6</int>
+ <object class="NSCustomResource" key="NSNormalImage">
+ <reference key="NSClassName" ref="98235535"/>
+ <string key="NSResourceName">Remove</string>
+ </object>
+ <object class="NSCustomResource" key="NSAlternateImage">
+ <reference key="NSClassName" ref="98235535"/>
+ <string key="NSResourceName">Remove_Pressed</string>
+ </object>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{419, 465}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
+ <string key="NSMinSize">{213, 129}</string>
+ <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ <reference key="NSFrameAutosaveName" ref="1001321221"/>
+ </object>
+ <object class="NSWindowTemplate" id="584899104">
+ <int key="NSWindowStyleMask">13</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{378, 247}, {484, 199}}</string>
+ <int key="NSWTFlags">1886912512</int>
+ <string key="NSWindowTitle">Authenticate to Kerberos</string>
+ <object class="NSMutableString" key="NSWindowClass">
+ <characters key="NS.bytes">NSWindow</characters>
+ </object>
+ <object class="NSMutableString" key="NSViewClass">
+ <characters key="NS.bytes">View</characters>
+ </object>
+ <object class="NSView" key="NSWindowView" id="485397981">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTabView" id="190599775">
+ <reference key="NSNextResponder" ref="485397981"/>
+ <int key="NSvFlags">274</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSView" id="676568523">
+ <reference key="NSNextResponder" ref="190599775"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSImageView" id="820211389">
+ <reference key="NSNextResponder" ref="676568523"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="248893621"/>
+ <reference ref="792839034"/>
+ <reference ref="139007242"/>
+ <reference ref="513246449"/>
+ <string id="920896168">NeXT Encapsulated PostScript v1.2 pasteboard type</string>
+ <reference ref="676443656"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{20, 119}, {62, 62}}</string>
+ <reference key="NSSuperview" ref="676568523"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="775130166"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="755050138">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">33554432</int>
+ <reference key="NSContents" ref="14953420"/>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ <object class="NSTextField" id="775130166">
+ <reference key="NSNextResponder" ref="676568523"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{87, 119}, {387, 51}}</string>
+ <reference key="NSSuperview" ref="676568523"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="816049975"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="543696716">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Please enter your Kerberos identity</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="775130166"/>
+ <reference key="NSBackgroundColor" ref="489363697"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="631342211">
+ <reference key="NSNextResponder" ref="676568523"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{90, 89}, {378, 22}}</string>
+ <reference key="NSSuperview" ref="676568523"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="190752038"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="599743341">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <reference key="NSContents" ref="1001321221"/>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="631342211"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <object class="NSColor" key="NSBackgroundColor" id="874817374">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="602240259"/>
+ <string key="NSColorName">textBackgroundColor</string>
+ <reference key="NSColor" ref="61380785"/>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="260493922">
+ <int key="NSColorSpace">6</int>
+ <reference key="NSCatalogName" ref="602240259"/>
+ <string key="NSColorName">textColor</string>
+ <reference key="NSColor" ref="575450793"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextField" id="816049975">
+ <reference key="NSNextResponder" ref="676568523"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{17, 94}, {68, 17}}</string>
+ <reference key="NSSuperview" ref="676568523"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="631342211"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="1055736335">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">71303168</int>
+ <string key="NSContents">Name:</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="816049975"/>
+ <reference key="NSBackgroundColor" ref="489363697"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ </object>
+ <object class="NSComboBox" id="564993215">
+ <reference key="NSNextResponder" ref="676568523"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{90, 57}, {381, 26}}</string>
+ <reference key="NSSuperview" ref="676568523"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSComboBoxCell" key="NSCell" id="319194335">
+ <int key="NSCellFlags">343014976</int>
+ <int key="NSCellFlags2">272630784</int>
+ <object class="NSMutableString" key="NSContents" id="934109934">
+ <characters key="NS.bytes"/>
+ </object>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="564993215"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="874817374"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ <int key="NSVisibleItemCount">5</int>
+ <bool key="NSHasVerticalScroller">YES</bool>
+ <reference key="NSDelegate" ref="564993215"/>
+ <object class="NSComboTableView" key="NSTableView" id="800966924">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">274</int>
+ <string key="NSFrameSize">{15, 0}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSMutableArray" key="NSTableColumns">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTableColumn">
+ <integer value="0" key="NSIdentifier"/>
+ <double key="NSWidth">1.200000e+01</double>
+ <double key="NSMinWidth">1.000000e+01</double>
+ <double key="NSMaxWidth">1.000000e+03</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">75628032</int>
+ <int key="NSCellFlags2">0</int>
+ <reference key="NSContents" ref="934109934"/>
+ <object class="NSFont" key="NSSupport">
+ <reference key="NSName" ref="139607319"/>
+ <double key="NSSize">1.200000e+01</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes>
+ </object>
+ <reference key="NSTextColor" ref="61380785"/>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell">
+ <int key="NSCellFlags">338820672</int>
+ <int key="NSCellFlags2">1024</int>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="800966924"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="458828224"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <reference key="NSTableView" ref="800966924"/>
+ </object>
+ </object>
+ <double key="NSIntercellSpacingWidth">3.000000e+00</double>
+ <double key="NSIntercellSpacingHeight">2.000000e+00</double>
+ <reference key="NSBackgroundColor" ref="458828224"/>
+ <reference key="NSGridColor" ref="785987320"/>
+ <double key="NSRowHeight">1.900000e+01</double>
+ <string key="NSAction">tableViewAction:</string>
+ <int key="NSTvFlags">-767524864</int>
+ <reference key="NSDelegate" ref="319194335"/>
+ <reference key="NSDataSource" ref="319194335"/>
+ <reference key="NSTarget" ref="319194335"/>
+ <int key="NSColumnAutoresizingStyle">1</int>
+ <int key="NSDraggingSourceMaskForLocal">15</int>
+ <int key="NSDraggingSourceMaskForNonLocal">0</int>
+ <bool key="NSAllowsTypeSelect">YES</bool>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextField" id="190752038">
+ <reference key="NSNextResponder" ref="676568523"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{17, 61}, {68, 17}}</string>
+ <reference key="NSSuperview" ref="676568523"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="564993215"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="915880596">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">71303168</int>
+ <string key="NSContents">Realm:</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="190752038"/>
+ <reference key="NSBackgroundColor" ref="489363697"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ </object>
+ <object class="NSButton" id="6694186">
+ <reference key="NSNextResponder" ref="676568523"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{376, 12}, {98, 32}}</string>
+ <reference key="NSSuperview" ref="676568523"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="190599775"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="788013598">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents" id="202547841">Continue</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="6694186"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="870487994"/>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="873179038">
+ <reference key="NSNextResponder" ref="676568523"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrame">{{18, 15}, {51, 27}}</string>
+ <reference key="NSSuperview" ref="676568523"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="440166836">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="1001321221"/>
+ <object class="NSFont" key="NSSupport" id="24">
+ <reference key="NSName" ref="139607319"/>
+ <double key="NSSize">1.000000e+01</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <reference key="NSControlView" ref="873179038"/>
+ <int key="NSButtonFlags">-2033434369</int>
+ <int key="NSButtonFlags2">2</int>
+ <object class="NSCustomResource" key="NSNormalImage" id="936837443">
+ <reference key="NSClassName" ref="98235535"/>
+ <string key="NSResourceName">Gear</string>
+ </object>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <reference key="NSKeyEquivalent" ref="1001321221"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{488, 201}</string>
+ <reference key="NSSuperview" ref="190599775"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="820211389"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{-4, 0}, {488, 201}}</string>
+ <reference key="NSSuperview" ref="485397981"/>
+ <reference key="NSWindow"/>
+ <object class="NSMutableArray" key="NSTabViewItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTabViewItem" id="1014910444">
+ <string key="NSIdentifier">1</string>
+ <reference key="NSView" ref="676568523"/>
+ <string key="NSLabel">Select Identity</string>
+ <reference key="NSColor" ref="489363697"/>
+ <reference key="NSTabView" ref="190599775"/>
+ </object>
+ <object class="NSTabViewItem" id="653267471">
+ <string key="NSIdentifier">2</string>
+ <object class="NSView" key="NSView" id="859867445">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSImageView" id="1072529850">
+ <reference key="NSNextResponder" ref="859867445"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="248893621"/>
+ <reference ref="792839034"/>
+ <reference ref="139007242"/>
+ <reference ref="513246449"/>
+ <reference ref="920896168"/>
+ <reference ref="676443656"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{17, 122}, {62, 62}}</string>
+ <reference key="NSSuperview" ref="859867445"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="882004624">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">33554432</int>
+ <reference key="NSContents" ref="14953420"/>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ <object class="NSTextField" id="1006869652">
+ <reference key="NSNextResponder" ref="859867445"/>
+ <int key="NSvFlags">290</int>
+ <string key="NSFrame">{{87, 60}, {381, 22}}</string>
+ <reference key="NSSuperview" ref="859867445"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="790272817">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <reference key="NSContents" ref="1001321221"/>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="1006869652"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="874817374"/>
+ <reference key="NSTextColor" ref="260493922"/>
+ </object>
+ </object>
+ <object class="NSButton" id="686465652">
+ <reference key="NSNextResponder" ref="859867445"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{376, 12}, {98, 32}}</string>
+ <reference key="NSSuperview" ref="859867445"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="905688153">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="202547841"/>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="686465652"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="870487994"/>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="715096260">
+ <reference key="NSNextResponder" ref="859867445"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{283, 12}, {93, 32}}</string>
+ <reference key="NSSuperview" ref="859867445"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="1009654784">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents" id="158315544">Go Back</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="715096260"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="870487994"/>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="687944822">
+ <reference key="NSNextResponder" ref="859867445"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{84, 167}, {387, 17}}</string>
+ <reference key="NSSuperview" ref="859867445"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="657627124">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Please enter your Kerberos password</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="687944822"/>
+ <reference key="NSBackgroundColor" ref="489363697"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="877064427">
+ <reference key="NSNextResponder" ref="859867445"/>
+ <int key="NSvFlags">274</int>
+ <string key="NSFrame">{{84, 90}, {387, 69}}</string>
+ <reference key="NSSuperview" ref="859867445"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="1029493879">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Mail wants to connect to the account lxs@mit.edu</string>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="877064427"/>
+ <reference key="NSBackgroundColor" ref="489363697"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ </object>
+ <object class="NSButton" id="317922958">
+ <reference key="NSNextResponder" ref="859867445"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrame">{{18, 16}, {51, 26}}</string>
+ <reference key="NSSuperview" ref="859867445"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="283917634">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="1001321221"/>
+ <reference key="NSSupport" ref="24"/>
+ <reference key="NSControlView" ref="317922958"/>
+ <int key="NSButtonFlags">-2033958657</int>
+ <int key="NSButtonFlags2">2</int>
+ <reference key="NSNormalImage" ref="936837443"/>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <reference key="NSKeyEquivalent" ref="1001321221"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{488, 201}</string>
+ </object>
+ <string key="NSLabel">Authentication Information</string>
+ <reference key="NSColor" ref="489363697"/>
+ <reference key="NSTabView" ref="190599775"/>
+ </object>
+ <object class="NSTabViewItem" id="653420350">
+ <string key="NSIdentifier">3</string>
+ <object class="NSView" key="NSView" id="596161636">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSButton" id="456929201">
+ <reference key="NSNextResponder" ref="596161636"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{392, 12}, {82, 32}}</string>
+ <reference key="NSSuperview" ref="596161636"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="987351438">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Done</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="456929201"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="870487994"/>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSImageView" id="602437307">
+ <reference key="NSNextResponder" ref="596161636"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="248893621"/>
+ <reference ref="792839034"/>
+ <reference ref="139007242"/>
+ <reference ref="513246449"/>
+ <reference ref="920896168"/>
+ <reference ref="676443656"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{17, 122}, {62, 62}}</string>
+ <reference key="NSSuperview" ref="596161636"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="676046583">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">33554432</int>
+ <reference key="NSContents" ref="14953420"/>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ <object class="NSTextField" id="376340069">
+ <reference key="NSNextResponder" ref="596161636"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{84, 167}, {387, 17}}</string>
+ <reference key="NSSuperview" ref="596161636"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="900295856">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Conclusion</string>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="376340069"/>
+ <reference key="NSBackgroundColor" ref="489363697"/>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="198861469">
+ <reference key="NSNextResponder" ref="596161636"/>
+ <int key="NSvFlags">274</int>
+ <string key="NSFrame">{{84, 60}, {387, 99}}</string>
+ <reference key="NSSuperview" ref="596161636"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="622356311">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272760832</int>
+ <string key="NSContents">Congratulations! You have acquired Kerberos tickets for lxs@ATHENA.MIT.EDU.</string>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="198861469"/>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MSAwLjk3MDAwMDAzAA</bytes>
+ </object>
+ <reference key="NSTextColor" ref="616389791"/>
+ </object>
+ </object>
+ <object class="NSButton" id="391292489">
+ <reference key="NSNextResponder" ref="596161636"/>
+ <int key="NSvFlags">289</int>
+ <string key="NSFrame">{{305, 12}, {91, 32}}</string>
+ <reference key="NSSuperview" ref="596161636"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="897987816">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <reference key="NSContents" ref="158315544"/>
+ <reference key="NSSupport" ref="870487994"/>
+ <reference key="NSControlView" ref="391292489"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <reference key="NSAlternateImage" ref="870487994"/>
+ <reference key="NSAlternateContents" ref="1001321221"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{488, 201}</string>
+ </object>
+ <string key="NSLabel">Result</string>
+ <reference key="NSColor" ref="489363697"/>
+ <reference key="NSTabView" ref="190599775"/>
+ </object>
+ </object>
+ <reference key="NSSelectedTabViewItem" ref="1014910444"/>
+ <reference key="NSFont" ref="870487994"/>
+ <int key="NSTvFlags">6</int>
+ <bool key="NSAllowTruncatedLabels">YES</bool>
+ <bool key="NSDrawsBackground">YES</bool>
+ </object>
+ </object>
+ <string key="NSFrameSize">{484, 199}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
+ <string key="NSMinSize">{239.32, 129}</string>
+ <string key="NSMaxSize">{3.40282e+38, 131}</string>
+ <reference key="NSFrameAutosaveName" ref="1001321221"/>
+ </object>
+ <object class="NSMenu" id="1022633701">
+ <string key="NSTitle">Menu</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="530465715">
+ <reference key="NSMenu" ref="1022633701"/>
+ <string type="base64-UTF8" key="NSTitle">VGlja2V0IE9wdGlvbnPigKY</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="522082566">
+ <reference key="NSMenu" ref="1022633701"/>
+ <string type="base64-UTF8" key="NSTitle">Q2hhbmdlIFBhc3N3b3Jk4oCmA</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="852460838">
+ <reference key="NSMenu" ref="1022633701"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <reference key="NSTitle" ref="1001321221"/>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ <object class="NSMenuItem" id="463708873">
+ <reference key="NSMenu" ref="1022633701"/>
+ <string key="NSTitle">About Kerberos...</string>
+ <reference key="NSKeyEquiv" ref="1001321221"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="42192827"/>
+ <reference key="NSMixedImage" ref="573706172"/>
+ </object>
+ </object>
+ <reference key="NSName" ref="1001321221"/>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">arrangeInFront:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="150140133"/>
+ </object>
+ <int key="connectionID">39</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showHelp:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="376978259"/>
+ </object>
+ <int key="connectionID">122</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">terminate:</string>
+ <reference key="source" ref="58791012"/>
+ <reference key="destination" ref="10506244"/>
+ </object>
+ <int key="connectionID">139</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontStandardAboutPanel:</string>
+ <reference key="source" ref="58791012"/>
+ <reference key="destination" ref="104201360"/>
+ </object>
+ <int key="connectionID">142</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hideOtherApplications:</string>
+ <reference key="source" ref="58791012"/>
+ <reference key="destination" ref="844777333"/>
+ </object>
+ <int key="connectionID">146</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hide:</string>
+ <reference key="source" ref="58791012"/>
+ <reference key="destination" ref="329699580"/>
+ </object>
+ <int key="connectionID">152</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">unhideAllApplications:</string>
+ <reference key="source" ref="58791012"/>
+ <reference key="destination" ref="110892548"/>
+ </object>
+ <int key="connectionID">153</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">cut:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="644214546"/>
+ </object>
+ <int key="connectionID">175</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">paste:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="76167146"/>
+ </object>
+ <int key="connectionID">176</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">redo:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="970758993"/>
+ </object>
+ <int key="connectionID">178</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">selectAll:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="491366892"/>
+ </object>
+ <int key="connectionID">179</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">undo:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="9292975"/>
+ </object>
+ <int key="connectionID">180</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">copy:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="157511090"/>
+ </object>
+ <int key="connectionID">181</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">delete:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="693913733"/>
+ </object>
+ <int key="connectionID">201</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performZoom:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="695757627"/>
+ </object>
+ <int key="connectionID">204</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">pasteAsPlainText:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="872606351"/>
+ </object>
+ <int key="connectionID">211</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performMiniaturize:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="308116730"/>
+ </object>
+ <int key="connectionID">235</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performClose:</string>
+ <reference key="source" ref="506161835"/>
+ <reference key="destination" ref="499080229"/>
+ </object>
+ <int key="connectionID">246</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label" id="547549419">content</string>
+ <reference key="source" ref="116785486"/>
+ <reference key="destination" ref="171210350"/>
+ </object>
+ <int key="connectionID">280</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label" id="573711689">contentArray: selection.cachesArray</string>
+ <reference key="source" ref="21498042"/>
+ <reference key="destination" ref="116785486"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="21498042"/>
+ <reference key="NSDestination" ref="116785486"/>
+ <reference key="NSLabel" ref="573711689"/>
+ <string key="NSBinding" id="938840909">contentArray</string>
+ <string key="NSKeyPath">selection.cachesArray</string>
+ <object class="NSDictionary" key="NSOptions">
+ <string key="NS.key.0" id="161525133">NSConditionallySetsEditable</string>
+ <integer value="0" key="NS.object.0" id="6"/>
+ </object>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">321</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <reference key="label" ref="547549419"/>
+ <reference key="source" ref="220358512"/>
+ <reference key="destination" ref="21498042"/>
+ </object>
+ <int key="connectionID">323</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label" id="732026233">contentArray: selection.credentialsArray</string>
+ <reference key="source" ref="220358512"/>
+ <reference key="destination" ref="21498042"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="220358512"/>
+ <reference key="NSDestination" ref="21498042"/>
+ <reference key="NSLabel" ref="732026233"/>
+ <reference key="NSBinding" ref="938840909"/>
+ <string key="NSKeyPath">selection.credentialsArray</string>
+ <object class="NSDictionary" key="NSOptions">
+ <reference key="NS.key.0" ref="161525133"/>
+ <reference key="NS.object.0" ref="6"/>
+ </object>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">326</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performClose:</string>
+ <reference key="source" ref="7348993"/>
+ <reference key="destination" ref="887730787"/>
+ </object>
+ <int key="connectionID">300356</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label" id="667685968">nextKeyView</string>
+ <reference key="source" ref="564993215"/>
+ <reference key="destination" ref="631342211"/>
+ </object>
+ <int key="connectionID">300406</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label" id="190965223">selectPreviousTabViewItem:</string>
+ <reference key="source" ref="190599775"/>
+ <reference key="destination" ref="391292489"/>
+ </object>
+ <int key="connectionID">300407</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <reference key="label" ref="667685968"/>
+ <reference key="source" ref="631342211"/>
+ <reference key="destination" ref="564993215"/>
+ </object>
+ <int key="connectionID">300408</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label" id="157488126">selectNextTabViewItem:</string>
+ <reference key="source" ref="190599775"/>
+ <reference key="destination" ref="6694186"/>
+ </object>
+ <int key="connectionID">300409</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <reference key="label" ref="157488126"/>
+ <reference key="source" ref="190599775"/>
+ <reference key="destination" ref="686465652"/>
+ </object>
+ <int key="connectionID">300410</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <reference key="label" ref="190965223"/>
+ <reference key="source" ref="190599775"/>
+ <reference key="destination" ref="715096260"/>
+ </object>
+ <int key="connectionID">300411</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label" id="167993371">value: arrangedObjects.principalString</string>
+ <reference key="source" ref="726475981"/>
+ <reference key="destination" ref="21498042"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="726475981"/>
+ <reference key="NSDestination" ref="21498042"/>
+ <reference key="NSLabel" ref="167993371"/>
+ <string key="NSBinding" id="406057131">value</string>
+ <string key="NSKeyPath">arrangedObjects.principalString</string>
+ <object class="NSDictionary" key="NSOptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string id="67980214">NSAllowsEditingMultipleValuesSelection</string>
+ <string id="573856099">NSAlwaysPresentsApplicationModalAlerts</string>
+ <string id="303072301">NSConditionallySetsEditable</string>
+ <string id="559346106">NSConditionallySetsEnabled</string>
+ <string id="583148074">NSContinuouslyUpdatesValue</string>
+ <string id="460582391">NSCreatesSortDescriptor</string>
+ <string id="179518014">NSMultipleValuesPlaceholder</string>
+ <string id="205163876">NSNoSelectionPlaceholder</string>
+ <string id="259444919">NSNotApplicablePlaceholder</string>
+ <string id="487631746">NSNullPlaceholder</string>
+ <string id="704241107">NSRaisesForNotApplicableKeys</string>
+ <string id="376227408">NSValidatesImmediately</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <integer value="1" id="5"/>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <string id="295165583"/>
+ <reference ref="295165583"/>
+ <reference ref="295165583"/>
+ <reference ref="295165583"/>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ </object>
+ </object>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">300413</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label" id="497691951">value: arrangedObjects.shortTimeRemainingString</string>
+ <reference key="source" ref="497509491"/>
+ <reference key="destination" ref="21498042"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="497509491"/>
+ <reference key="NSDestination" ref="21498042"/>
+ <reference key="NSLabel" ref="497691951"/>
+ <reference key="NSBinding" ref="406057131"/>
+ <string key="NSKeyPath">arrangedObjects.shortTimeRemainingString</string>
+ <object class="NSDictionary" key="NSOptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="67980214"/>
+ <reference ref="573856099"/>
+ <reference ref="303072301"/>
+ <reference ref="559346106"/>
+ <reference ref="583148074"/>
+ <reference ref="460582391"/>
+ <reference ref="179518014"/>
+ <reference ref="205163876"/>
+ <reference ref="259444919"/>
+ <reference ref="487631746"/>
+ <reference ref="704241107"/>
+ <reference ref="376227408"/>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <reference ref="5"/>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ <reference ref="295165583"/>
+ <reference ref="295165583"/>
+ <reference ref="295165583"/>
+ <reference ref="295165583"/>
+ <reference ref="6"/>
+ <reference ref="6"/>
+ </object>
+ </object>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">300415</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label" id="658841096">popupMenu</string>
+ <reference key="source" ref="873179038"/>
+ <reference key="destination" ref="1022633701"/>
+ </object>
+ <int key="connectionID">300422</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <reference key="label" ref="658841096"/>
+ <reference key="source" ref="317922958"/>
+ <reference key="destination" ref="1022633701"/>
+ </object>
+ <int key="connectionID">300423</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label" id="725738149">menu</string>
+ <reference key="source" ref="317922958"/>
+ <reference key="destination" ref="1022633701"/>
+ </object>
+ <int key="connectionID">300424</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <reference key="label" ref="725738149"/>
+ <reference key="source" ref="873179038"/>
+ <reference key="destination" ref="1022633701"/>
+ </object>
+ <int key="connectionID">300425</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="949938097"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="58791012"/>
+ <reference key="parent" ref="0"/>
+ <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="506161835"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">29</int>
+ <reference key="object" ref="576137369"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="132646693"/>
+ <reference ref="946093663"/>
+ <reference ref="608222506"/>
+ <reference ref="1071484604"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <reference key="objectName" ref="33876972"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">19</int>
+ <reference key="object" ref="132646693"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="307678365"/>
+ </object>
+ <reference key="parent" ref="576137369"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">24</int>
+ <reference key="object" ref="307678365"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="150140133"/>
+ <reference ref="499080229"/>
+ <reference ref="695757627"/>
+ <reference ref="615570499"/>
+ <reference ref="308116730"/>
+ </object>
+ <reference key="parent" ref="132646693"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="150140133"/>
+ <reference key="parent" ref="307678365"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">23</int>
+ <reference key="object" ref="499080229"/>
+ <reference key="parent" ref="307678365"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">203</int>
+ <reference key="object" ref="695757627"/>
+ <reference key="parent" ref="307678365"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">233</int>
+ <reference key="object" ref="615570499"/>
+ <reference key="parent" ref="307678365"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">234</int>
+ <reference key="object" ref="308116730"/>
+ <reference key="parent" ref="307678365"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">56</int>
+ <reference key="object" ref="946093663"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="980333367"/>
+ </object>
+ <reference key="parent" ref="576137369"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">57</int>
+ <reference key="object" ref="980333367"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="104201360"/>
+ <reference ref="885473566"/>
+ <reference ref="701559942"/>
+ <reference ref="329699580"/>
+ <reference ref="10506244"/>
+ <reference ref="773057625"/>
+ <reference ref="2694966"/>
+ <reference ref="844777333"/>
+ <reference ref="354292100"/>
+ <reference ref="110892548"/>
+ <reference ref="941049996"/>
+ </object>
+ <reference key="parent" ref="946093663"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">58</int>
+ <reference key="object" ref="104201360"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">129</int>
+ <reference key="object" ref="885473566"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">131</int>
+ <reference key="object" ref="701559942"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="297859549"/>
+ </object>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">130</int>
+ <reference key="object" ref="297859549"/>
+ <reference key="parent" ref="701559942"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">134</int>
+ <reference key="object" ref="329699580"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">136</int>
+ <reference key="object" ref="10506244"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">143</int>
+ <reference key="object" ref="773057625"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">144</int>
+ <reference key="object" ref="2694966"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">145</int>
+ <reference key="object" ref="844777333"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">149</int>
+ <reference key="object" ref="354292100"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">150</int>
+ <reference key="object" ref="110892548"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">202</int>
+ <reference key="object" ref="941049996"/>
+ <reference key="parent" ref="980333367"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">103</int>
+ <reference key="object" ref="608222506"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="566679562"/>
+ </object>
+ <reference key="parent" ref="576137369"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">106</int>
+ <reference key="object" ref="566679562"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="376978259"/>
+ </object>
+ <reference key="parent" ref="608222506"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">111</int>
+ <reference key="object" ref="376978259"/>
+ <reference key="parent" ref="566679562"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">163</int>
+ <reference key="object" ref="1071484604"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="694937866"/>
+ </object>
+ <reference key="parent" ref="576137369"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">169</int>
+ <reference key="object" ref="694937866"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="851800591"/>
+ <reference ref="157511090"/>
+ <reference ref="9292975"/>
+ <reference ref="644214546"/>
+ <reference ref="693913733"/>
+ <reference ref="76167146"/>
+ <reference ref="491366892"/>
+ <reference ref="970758993"/>
+ <reference ref="872606351"/>
+ </object>
+ <reference key="parent" ref="1071484604"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">156</int>
+ <reference key="object" ref="851800591"/>
+ <reference key="parent" ref="694937866"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">157</int>
+ <reference key="object" ref="157511090"/>
+ <reference key="parent" ref="694937866"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">158</int>
+ <reference key="object" ref="9292975"/>
+ <reference key="parent" ref="694937866"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">160</int>
+ <reference key="object" ref="644214546"/>
+ <reference key="parent" ref="694937866"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">164</int>
+ <reference key="object" ref="693913733"/>
+ <reference key="parent" ref="694937866"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">171</int>
+ <reference key="object" ref="76167146"/>
+ <reference key="parent" ref="694937866"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">172</int>
+ <reference key="object" ref="491366892"/>
+ <reference key="parent" ref="694937866"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">173</int>
+ <reference key="object" ref="970758993"/>
+ <reference key="parent" ref="694937866"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">210</int>
+ <reference key="object" ref="872606351"/>
+ <reference key="parent" ref="694937866"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">262</int>
+ <reference key="object" ref="116785486"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">CacheCollectionController</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">279</int>
+ <reference key="object" ref="171210350"/>
+ <reference key="parent" ref="0"/>
+ <reference key="objectName" ref="1053976860"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">310</int>
+ <reference key="object" ref="21498042"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">CachesController</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">322</int>
+ <reference key="object" ref="220358512"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">CredentialsController</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="364998124"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300335</int>
+ <reference key="object" ref="7348993"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="221966185"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <reference key="objectName" ref="703913682"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300336</int>
+ <reference key="object" ref="221966185"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="47718130"/>
+ <reference ref="853176257"/>
+ <reference ref="536182542"/>
+ <reference ref="837237465"/>
+ <reference ref="919779806"/>
+ <reference ref="186661261"/>
+ <reference ref="474370300"/>
+ <reference ref="355395495"/>
+ </object>
+ <reference key="parent" ref="7348993"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300338</int>
+ <reference key="object" ref="47718130"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="887730787"/>
+ </object>
+ <reference key="parent" ref="221966185"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300339</int>
+ <reference key="object" ref="853176257"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="938853223"/>
+ </object>
+ <reference key="parent" ref="221966185"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300340</int>
+ <reference key="object" ref="536182542"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="159615320"/>
+ <reference ref="501018053"/>
+ <reference ref="87192718"/>
+ <reference ref="636123923"/>
+ </object>
+ <reference key="parent" ref="221966185"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300341</int>
+ <reference key="object" ref="837237465"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1006984983"/>
+ </object>
+ <reference key="parent" ref="221966185"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300342</int>
+ <reference key="object" ref="919779806"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="405384087"/>
+ </object>
+ <reference key="parent" ref="221966185"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300343</int>
+ <reference key="object" ref="405384087"/>
+ <reference key="parent" ref="919779806"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300344</int>
+ <reference key="object" ref="1006984983"/>
+ <reference key="parent" ref="837237465"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300345</int>
+ <reference key="object" ref="159615320"/>
+ <reference key="parent" ref="536182542"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300346</int>
+ <reference key="object" ref="501018053"/>
+ <reference key="parent" ref="536182542"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300347</int>
+ <reference key="object" ref="87192718"/>
+ <reference key="parent" ref="536182542"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300348</int>
+ <reference key="object" ref="636123923"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="497509491"/>
+ <reference ref="726475981"/>
+ </object>
+ <reference key="parent" ref="536182542"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300349</int>
+ <reference key="object" ref="497509491"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="448257474"/>
+ </object>
+ <reference key="parent" ref="636123923"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300350</int>
+ <reference key="object" ref="726475981"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="393823551"/>
+ </object>
+ <reference key="parent" ref="636123923"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300351</int>
+ <reference key="object" ref="393823551"/>
+ <reference key="parent" ref="726475981"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300352</int>
+ <reference key="object" ref="448257474"/>
+ <reference key="parent" ref="497509491"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300353</int>
+ <reference key="object" ref="938853223"/>
+ <reference key="parent" ref="853176257"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300354</int>
+ <reference key="object" ref="887730787"/>
+ <reference key="parent" ref="47718130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300357</int>
+ <reference key="object" ref="584899104"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="485397981"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Window1</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300358</int>
+ <reference key="object" ref="485397981"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="190599775"/>
+ </object>
+ <reference key="parent" ref="584899104"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300359</int>
+ <reference key="object" ref="190599775"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="653420350"/>
+ <reference ref="1014910444"/>
+ <reference ref="653267471"/>
+ </object>
+ <reference key="parent" ref="485397981"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300360</int>
+ <reference key="object" ref="653420350"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="596161636"/>
+ </object>
+ <reference key="parent" ref="190599775"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300361</int>
+ <reference key="object" ref="1014910444"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="676568523"/>
+ </object>
+ <reference key="parent" ref="190599775"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300362</int>
+ <reference key="object" ref="653267471"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="859867445"/>
+ </object>
+ <reference key="parent" ref="190599775"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300363</int>
+ <reference key="object" ref="859867445"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="317922958"/>
+ <reference ref="877064427"/>
+ <reference ref="687944822"/>
+ <reference ref="715096260"/>
+ <reference ref="686465652"/>
+ <reference ref="1006869652"/>
+ <reference ref="1072529850"/>
+ </object>
+ <reference key="parent" ref="653267471"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300364</int>
+ <reference key="object" ref="317922958"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="283917634"/>
+ </object>
+ <reference key="parent" ref="859867445"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300365</int>
+ <reference key="object" ref="877064427"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1029493879"/>
+ </object>
+ <reference key="parent" ref="859867445"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300366</int>
+ <reference key="object" ref="687944822"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="657627124"/>
+ </object>
+ <reference key="parent" ref="859867445"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300367</int>
+ <reference key="object" ref="715096260"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1009654784"/>
+ </object>
+ <reference key="parent" ref="859867445"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300368</int>
+ <reference key="object" ref="686465652"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="905688153"/>
+ </object>
+ <reference key="parent" ref="859867445"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300369</int>
+ <reference key="object" ref="1006869652"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="790272817"/>
+ </object>
+ <reference key="parent" ref="859867445"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300370</int>
+ <reference key="object" ref="1072529850"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="882004624"/>
+ </object>
+ <reference key="parent" ref="859867445"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300371</int>
+ <reference key="object" ref="882004624"/>
+ <reference key="parent" ref="1072529850"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300372</int>
+ <reference key="object" ref="790272817"/>
+ <reference key="parent" ref="1006869652"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300373</int>
+ <reference key="object" ref="905688153"/>
+ <reference key="parent" ref="686465652"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300374</int>
+ <reference key="object" ref="1009654784"/>
+ <reference key="parent" ref="715096260"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300375</int>
+ <reference key="object" ref="657627124"/>
+ <reference key="parent" ref="687944822"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300376</int>
+ <reference key="object" ref="1029493879"/>
+ <reference key="parent" ref="877064427"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300377</int>
+ <reference key="object" ref="283917634"/>
+ <reference key="parent" ref="317922958"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300378</int>
+ <reference key="object" ref="676568523"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="873179038"/>
+ <reference ref="6694186"/>
+ <reference ref="190752038"/>
+ <reference ref="564993215"/>
+ <reference ref="816049975"/>
+ <reference ref="631342211"/>
+ <reference ref="775130166"/>
+ <reference ref="820211389"/>
+ </object>
+ <reference key="parent" ref="1014910444"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300379</int>
+ <reference key="object" ref="873179038"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="440166836"/>
+ </object>
+ <reference key="parent" ref="676568523"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300380</int>
+ <reference key="object" ref="6694186"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="788013598"/>
+ </object>
+ <reference key="parent" ref="676568523"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300381</int>
+ <reference key="object" ref="190752038"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="915880596"/>
+ </object>
+ <reference key="parent" ref="676568523"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300382</int>
+ <reference key="object" ref="564993215"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="319194335"/>
+ </object>
+ <reference key="parent" ref="676568523"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300383</int>
+ <reference key="object" ref="816049975"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1055736335"/>
+ </object>
+ <reference key="parent" ref="676568523"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300384</int>
+ <reference key="object" ref="631342211"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="599743341"/>
+ </object>
+ <reference key="parent" ref="676568523"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300385</int>
+ <reference key="object" ref="775130166"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="543696716"/>
+ </object>
+ <reference key="parent" ref="676568523"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300386</int>
+ <reference key="object" ref="820211389"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="755050138"/>
+ </object>
+ <reference key="parent" ref="676568523"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300387</int>
+ <reference key="object" ref="755050138"/>
+ <reference key="parent" ref="820211389"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300388</int>
+ <reference key="object" ref="543696716"/>
+ <reference key="parent" ref="775130166"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300389</int>
+ <reference key="object" ref="599743341"/>
+ <reference key="parent" ref="631342211"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300390</int>
+ <reference key="object" ref="1055736335"/>
+ <reference key="parent" ref="816049975"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300391</int>
+ <reference key="object" ref="319194335"/>
+ <reference key="parent" ref="564993215"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300392</int>
+ <reference key="object" ref="915880596"/>
+ <reference key="parent" ref="190752038"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300393</int>
+ <reference key="object" ref="788013598"/>
+ <reference key="parent" ref="6694186"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300394</int>
+ <reference key="object" ref="440166836"/>
+ <reference key="parent" ref="873179038"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300395</int>
+ <reference key="object" ref="596161636"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="391292489"/>
+ <reference ref="198861469"/>
+ <reference ref="376340069"/>
+ <reference ref="602437307"/>
+ <reference ref="456929201"/>
+ </object>
+ <reference key="parent" ref="653420350"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300396</int>
+ <reference key="object" ref="391292489"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="897987816"/>
+ </object>
+ <reference key="parent" ref="596161636"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300397</int>
+ <reference key="object" ref="198861469"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="622356311"/>
+ </object>
+ <reference key="parent" ref="596161636"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300398</int>
+ <reference key="object" ref="376340069"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="900295856"/>
+ </object>
+ <reference key="parent" ref="596161636"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300399</int>
+ <reference key="object" ref="602437307"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="676046583"/>
+ </object>
+ <reference key="parent" ref="596161636"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300400</int>
+ <reference key="object" ref="456929201"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="987351438"/>
+ </object>
+ <reference key="parent" ref="596161636"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300401</int>
+ <reference key="object" ref="987351438"/>
+ <reference key="parent" ref="456929201"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300402</int>
+ <reference key="object" ref="676046583"/>
+ <reference key="parent" ref="602437307"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300403</int>
+ <reference key="object" ref="900295856"/>
+ <reference key="parent" ref="376340069"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300404</int>
+ <reference key="object" ref="622356311"/>
+ <reference key="parent" ref="198861469"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300405</int>
+ <reference key="object" ref="897987816"/>
+ <reference key="parent" ref="391292489"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300417</int>
+ <reference key="object" ref="1022633701"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="530465715"/>
+ <reference ref="522082566"/>
+ <reference ref="852460838"/>
+ <reference ref="463708873"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">GearMenu</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300418</int>
+ <reference key="object" ref="530465715"/>
+ <reference key="parent" ref="1022633701"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300419</int>
+ <reference key="object" ref="522082566"/>
+ <reference key="parent" ref="1022633701"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300420</int>
+ <reference key="object" ref="852460838"/>
+ <reference key="parent" ref="1022633701"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300421</int>
+ <reference key="object" ref="463708873"/>
+ <reference key="parent" ref="1022633701"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300437</int>
+ <reference key="object" ref="186661261"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="927465653"/>
+ </object>
+ <reference key="parent" ref="221966185"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300438</int>
+ <reference key="object" ref="927465653"/>
+ <reference key="parent" ref="186661261"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300443</int>
+ <reference key="object" ref="474370300"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="226976488"/>
+ </object>
+ <reference key="parent" ref="221966185"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300444</int>
+ <reference key="object" ref="226976488"/>
+ <reference key="parent" ref="474370300"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300445</int>
+ <reference key="object" ref="355395495"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="857531424"/>
+ </object>
+ <reference key="parent" ref="221966185"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">300446</int>
+ <reference key="object" ref="857531424"/>
+ <reference key="parent" ref="355395495"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.IBPluginDependency</string>
+ <string>-2.IBPluginDependency</string>
+ <string>103.IBPluginDependency</string>
+ <string>103.ImportedFromIB2</string>
+ <string>106.IBPluginDependency</string>
+ <string>106.ImportedFromIB2</string>
+ <string>106.editorWindowContentRectSynchronizationRect</string>
+ <string>111.IBPluginDependency</string>
+ <string>111.ImportedFromIB2</string>
+ <string>129.IBPluginDependency</string>
+ <string>129.ImportedFromIB2</string>
+ <string>130.IBPluginDependency</string>
+ <string>130.ImportedFromIB2</string>
+ <string>131.IBPluginDependency</string>
+ <string>131.ImportedFromIB2</string>
+ <string>134.IBPluginDependency</string>
+ <string>134.ImportedFromIB2</string>
+ <string>136.IBPluginDependency</string>
+ <string>136.ImportedFromIB2</string>
+ <string>143.IBPluginDependency</string>
+ <string>143.ImportedFromIB2</string>
+ <string>144.IBPluginDependency</string>
+ <string>144.ImportedFromIB2</string>
+ <string>145.IBPluginDependency</string>
+ <string>145.ImportedFromIB2</string>
+ <string>149.IBPluginDependency</string>
+ <string>149.ImportedFromIB2</string>
+ <string>150.IBPluginDependency</string>
+ <string>150.ImportedFromIB2</string>
+ <string>156.IBPluginDependency</string>
+ <string>156.ImportedFromIB2</string>
+ <string>157.IBPluginDependency</string>
+ <string>157.ImportedFromIB2</string>
+ <string>158.IBPluginDependency</string>
+ <string>158.ImportedFromIB2</string>
+ <string>160.IBPluginDependency</string>
+ <string>160.ImportedFromIB2</string>
+ <string>163.IBPluginDependency</string>
+ <string>163.ImportedFromIB2</string>
+ <string>164.IBPluginDependency</string>
+ <string>164.ImportedFromIB2</string>
+ <string>169.IBPluginDependency</string>
+ <string>169.ImportedFromIB2</string>
+ <string>169.editorWindowContentRectSynchronizationRect</string>
+ <string>171.IBPluginDependency</string>
+ <string>171.ImportedFromIB2</string>
+ <string>172.IBPluginDependency</string>
+ <string>172.ImportedFromIB2</string>
+ <string>173.IBPluginDependency</string>
+ <string>173.ImportedFromIB2</string>
+ <string>19.IBPluginDependency</string>
+ <string>19.ImportedFromIB2</string>
+ <string>202.IBPluginDependency</string>
+ <string>202.ImportedFromIB2</string>
+ <string>203.IBPluginDependency</string>
+ <string>203.ImportedFromIB2</string>
+ <string>210.IBPluginDependency</string>
+ <string>210.ImportedFromIB2</string>
+ <string>23.IBPluginDependency</string>
+ <string>23.ImportedFromIB2</string>
+ <string>233.IBPluginDependency</string>
+ <string>233.ImportedFromIB2</string>
+ <string>234.IBPluginDependency</string>
+ <string>234.ImportedFromIB2</string>
+ <string>24.IBPluginDependency</string>
+ <string>24.ImportedFromIB2</string>
+ <string>24.editorWindowContentRectSynchronizationRect</string>
+ <string>262.IBPluginDependency</string>
+ <string>262.ImportedFromIB2</string>
+ <string>279.IBPluginDependency</string>
+ <string>279.ImportedFromIB2</string>
+ <string>29.IBPluginDependency</string>
+ <string>29.ImportedFromIB2</string>
+ <string>29.editorWindowContentRectSynchronizationRect</string>
+ <string>300335.IBPluginDependency</string>
+ <string>300335.IBWindowTemplateEditedContentRect</string>
+ <string>300335.ImportedFromIB2</string>
+ <string>300335.NSWindowTemplate.visibleAtLaunch</string>
+ <string>300335.editorWindowContentRectSynchronizationRect</string>
+ <string>300335.windowTemplate.hasMaxSize</string>
+ <string>300335.windowTemplate.hasMinSize</string>
+ <string>300335.windowTemplate.maxSize</string>
+ <string>300335.windowTemplate.minSize</string>
+ <string>300336.IBPluginDependency</string>
+ <string>300336.ImportedFromIB2</string>
+ <string>300338.IBPluginDependency</string>
+ <string>300338.ImportedFromIB2</string>
+ <string>300339.IBPluginDependency</string>
+ <string>300339.ImportedFromIB2</string>
+ <string>300340.IBPluginDependency</string>
+ <string>300340.ImportedFromIB2</string>
+ <string>300341.IBPluginDependency</string>
+ <string>300341.ImportedFromIB2</string>
+ <string>300342.IBPluginDependency</string>
+ <string>300342.ImportedFromIB2</string>
+ <string>300345.IBShouldRemoveOnLegacySave</string>
+ <string>300346.IBShouldRemoveOnLegacySave</string>
+ <string>300347.IBShouldRemoveOnLegacySave</string>
+ <string>300348.IBPluginDependency</string>
+ <string>300348.ImportedFromIB2</string>
+ <string>300349.IBPluginDependency</string>
+ <string>300349.ImportedFromIB2</string>
+ <string>300350.IBPluginDependency</string>
+ <string>300350.ImportedFromIB2</string>
+ <string>300351.IBPluginDependency</string>
+ <string>300352.IBPluginDependency</string>
+ <string>300357.IBPluginDependency</string>
+ <string>300357.IBWindowTemplateEditedContentRect</string>
+ <string>300357.ImportedFromIB2</string>
+ <string>300357.NSWindowTemplate.visibleAtLaunch</string>
+ <string>300357.editorWindowContentRectSynchronizationRect</string>
+ <string>300357.windowTemplate.hasMaxSize</string>
+ <string>300357.windowTemplate.hasMinSize</string>
+ <string>300357.windowTemplate.maxSize</string>
+ <string>300357.windowTemplate.minSize</string>
+ <string>300358.IBPluginDependency</string>
+ <string>300358.ImportedFromIB2</string>
+ <string>300359.IBPluginDependency</string>
+ <string>300359.ImportedFromIB2</string>
+ <string>300360.IBPluginDependency</string>
+ <string>300360.ImportedFromIB2</string>
+ <string>300361.IBPluginDependency</string>
+ <string>300361.ImportedFromIB2</string>
+ <string>300362.IBPluginDependency</string>
+ <string>300362.ImportedFromIB2</string>
+ <string>300363.IBPluginDependency</string>
+ <string>300363.ImportedFromIB2</string>
+ <string>300364.CustomClassName</string>
+ <string>300364.IBPluginDependency</string>
+ <string>300364.ImportedFromIB2</string>
+ <string>300365.IBPluginDependency</string>
+ <string>300365.ImportedFromIB2</string>
+ <string>300366.IBPluginDependency</string>
+ <string>300366.ImportedFromIB2</string>
+ <string>300367.IBPluginDependency</string>
+ <string>300367.ImportedFromIB2</string>
+ <string>300368.IBPluginDependency</string>
+ <string>300368.ImportedFromIB2</string>
+ <string>300369.CustomClassName</string>
+ <string>300369.IBPluginDependency</string>
+ <string>300369.ImportedFromIB2</string>
+ <string>300370.IBPluginDependency</string>
+ <string>300370.ImportedFromIB2</string>
+ <string>300378.IBPluginDependency</string>
+ <string>300378.ImportedFromIB2</string>
+ <string>300379.CustomClassName</string>
+ <string>300379.IBPluginDependency</string>
+ <string>300379.ImportedFromIB2</string>
+ <string>300380.IBPluginDependency</string>
+ <string>300380.ImportedFromIB2</string>
+ <string>300381.IBPluginDependency</string>
+ <string>300381.ImportedFromIB2</string>
+ <string>300382.IBPluginDependency</string>
+ <string>300382.ImportedFromIB2</string>
+ <string>300383.IBPluginDependency</string>
+ <string>300383.ImportedFromIB2</string>
+ <string>300384.IBPluginDependency</string>
+ <string>300384.ImportedFromIB2</string>
+ <string>300385.IBPluginDependency</string>
+ <string>300385.ImportedFromIB2</string>
+ <string>300386.IBPluginDependency</string>
+ <string>300386.ImportedFromIB2</string>
+ <string>300395.IBPluginDependency</string>
+ <string>300395.ImportedFromIB2</string>
+ <string>300396.IBPluginDependency</string>
+ <string>300396.ImportedFromIB2</string>
+ <string>300397.IBPluginDependency</string>
+ <string>300397.ImportedFromIB2</string>
+ <string>300398.IBPluginDependency</string>
+ <string>300398.ImportedFromIB2</string>
+ <string>300399.IBPluginDependency</string>
+ <string>300399.ImportedFromIB2</string>
+ <string>300400.IBPluginDependency</string>
+ <string>300400.ImportedFromIB2</string>
+ <string>300417.IBPluginDependency</string>
+ <string>300417.ImportedFromIB2</string>
+ <string>300417.editorWindowContentRectSynchronizationRect</string>
+ <string>300418.IBPluginDependency</string>
+ <string>300418.ImportedFromIB2</string>
+ <string>300419.IBPluginDependency</string>
+ <string>300419.ImportedFromIB2</string>
+ <string>300420.IBPluginDependency</string>
+ <string>300420.ImportedFromIB2</string>
+ <string>300421.IBPluginDependency</string>
+ <string>300421.ImportedFromIB2</string>
+ <string>300437.IBPluginDependency</string>
+ <string>300438.IBPluginDependency</string>
+ <string>300443.IBAttributePlaceholdersKey</string>
+ <string>300443.IBPluginDependency</string>
+ <string>300443.ImportedFromIB2</string>
+ <string>300445.IBAttributePlaceholdersKey</string>
+ <string>300445.IBPluginDependency</string>
+ <string>300445.ImportedFromIB2</string>
+ <string>310.IBPluginDependency</string>
+ <string>310.ImportedFromIB2</string>
+ <string>322.IBPluginDependency</string>
+ <string>322.ImportedFromIB2</string>
+ <string>5.IBPluginDependency</string>
+ <string>5.ImportedFromIB2</string>
+ <string>56.IBPluginDependency</string>
+ <string>56.ImportedFromIB2</string>
+ <string>57.IBPluginDependency</string>
+ <string>57.ImportedFromIB2</string>
+ <string>57.editorWindowContentRectSynchronizationRect</string>
+ <string>58.IBPluginDependency</string>
+ <string>58.ImportedFromIB2</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="438620934"/>
+ <reference ref="438620934"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <string>{{1137, 580}, {211, 23}}</string>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <string>{{1022, 430}, {253, 173}}</string>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <string>{{1066, 510}, {197, 93}}</string>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <string>{{884, 603}, {314, 20}}</string>
+ <string id="880393840">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{719, 105}, {419, 465}}</string>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>{{719, 105}, {419, 465}}</string>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>{3.40282e+38, 3.40282e+38}</string>
+ <string>{213, 107}</string>
+ <reference ref="880393840"/>
+ <reference ref="5"/>
+ <reference ref="880393840"/>
+ <reference ref="5"/>
+ <reference ref="880393840"/>
+ <reference ref="5"/>
+ <reference ref="880393840"/>
+ <reference ref="5"/>
+ <reference ref="880393840"/>
+ <reference ref="5"/>
+ <reference ref="880393840"/>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <reference ref="880393840"/>
+ <reference ref="5"/>
+ <reference ref="880393840"/>
+ <reference ref="5"/>
+ <reference ref="880393840"/>
+ <reference ref="5"/>
+ <reference ref="880393840"/>
+ <reference ref="880393840"/>
+ <string id="437408960">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string id="437055072">{{932, 664}, {484, 199}}</string>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <reference ref="437055072"/>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>{3.40282e+38, 109}</string>
+ <string>{239.32, 107}</string>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <string id="90569650">PopupButton</string>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <string>NSSecureTextField</string>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="90569650"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <reference ref="437408960"/>
+ <reference ref="5"/>
+ <string id="392805128">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1" id="9"/>
+ <string>{{444, 717}, {203, 73}}</string>
+ <reference ref="392805128"/>
+ <reference ref="9"/>
+ <reference ref="392805128"/>
+ <reference ref="9"/>
+ <reference ref="392805128"/>
+ <reference ref="9"/>
+ <reference ref="392805128"/>
+ <reference ref="9"/>
+ <string id="21292261">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="21292261"/>
+ <object class="NSMutableDictionary">
+ <string key="NS.key.0" id="26480611">ToolTip</string>
+ <object class="IBToolTipAttribute" key="NS.object.0">
+ <reference key="name" ref="26480611"/>
+ <reference key="object" ref="474370300"/>
+ <string key="toolTip">Create an account</string>
+ </object>
+ </object>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="9"/>
+ <object class="NSMutableDictionary">
+ <string key="NS.key.0" id="224749459">ToolTip</string>
+ <object class="IBToolTipAttribute" key="NS.object.0">
+ <reference key="name" ref="224749459"/>
+ <reference key="object" ref="355395495"/>
+ <string key="toolTip">Remove an account</string>
+ </object>
+ </object>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="9"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ <string>{{896, 420}, {240, 183}}</string>
+ <reference ref="438620934"/>
+ <reference ref="5"/>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">300446</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">FirstResponder</string>
+ <nil key="superclassName"/>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey" id="811564078">IBUserSource</string>
+ <string key="minorKey" id="908484235"/>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">KerberosCacheCollection</string>
+ <string key="superclassName" id="664915295">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <reference key="majorKey" ref="811564078"/>
+ <reference key="minorKey" ref="908484235"/>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">KerberosCacheCollection</string>
+ <reference key="superclassName" ref="664915295"/>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">../../../Common/Headers/KerberosCacheCollection.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">PopupButton</string>
+ <string key="superclassName">NSButton</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <reference key="NS.key.0" ref="658841096"/>
+ <string key="NS.object.0">NSMenu</string>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <reference key="minorKey" ref="1001321221"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.LastKnownRelativeProjectPath">../../../Projects/KerberosIdentityManagement.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ <object class="NSMutableData" key="IBDocument.RunnableNib">
+ <bytes key="NS.bytes">YnBsaXN0MDDUAAEAAgADAAQABQAGAAkAClgkdmVyc2lvblQkdG9wWSRhcmNoaXZlclgkb2JqZWN0cxIA
+AYag0QAHAAhdSUIub2JqZWN0ZGF0YYABXxAPTlNLZXllZEFyY2hpdmVyrxEDKAALAAwAMQA1ADkAQABD
+AEQASgBkAGUAZgBpAGwACwB5AH0AkgCWAJ8AqgC6AMMAxADFAMYAxwDIAMkAzQDOANgA5gDrAOwA7QDw
+APMA+QD6AQMBEAERARkBGgEcASUBJgEnASwBLgEzATQBNwE7AT4BRwFIAVEBWwFcAWEBYgFlAWoBawFs
+AXQBdQF9AX4BjwGRAAsBsgALAbMBtwDiAckB0AHUAdcB2gHjAegB6QHsAfAB9QH2AfkB+gH9AgACAwIE
+AgsCDAIWAhcCKgIrAi0CMAIzAj8CMgJAAkECTQJQAlQCVQJYAlkCWwJcAmICawJsAm0CcAJ3AngCfQKH
+ApACmQKaAp4CqAE9AqkCqgKyAhYCuQLBAsMCygLLAtMC1ALWAt0C3gLlAuYC7QLuAvUC9gL7AwQDBQJY
+Aw4DDwMWAxcDHAMkAysDLAM0AzUDNwNAApkDSQNNAt0DVANbA1wDYwNkA2wDbQNwA3cDeAOAAlgDggOD
+A4UACwOGA4cDiAOJA4wDlwOYA5kDmwOdAAsDpAOvA7kAxQPCA8MDyAPQA9ED2QPaA+8D9wQFBAkEGQQa
+BCEEKgQrBC4ENQQ2BDkEPgRIBE4ETwRRBFYEVwRhBGIEbARzBHQEeQR6BIMEhQSGBIkEkwSUBJUEmASh
+BKIEpgSnBKgEqwSzBLQEvAS9BL4ExgTHBM8E0ATRBNoE2wTjBOQE7ATtBPcE+wT8BQAFAQUDBQsFDAUV
+BRkFGgUeBR8FIQALA4YFIgUjBSQFTAVTBVsFXwVgBWEFYwVlBWkFbAVtBXEFdgV9BX4FhQWUBZUFmQWa
+BZ4FnwWiBakFqgW1BbwFvQW/BcAFxAXLBdAF0QXSBdMF1gXaBeEF5QXmBecF6AXsBfMF9AX1BfoGAQYG
+BgcGCAYNBg4GEgYaBhsGHAYdBiIGMgY3BjgGOQY6BjwGPwZJBlAGUQZSBlMGVAZWBdIGWwZgBmQGawZv
+BnAGcQZyBncGeAZ9BoQGhQaGBocGjAaQBpcGmAaZBp4GnwakBqUGqQawBrEGsgazBrcGvga/BsAGwQbF
+BswGzQbOBtMG2gbbBtwG4AbnBugG6QbqBu8G9gb3BvgG/QcEBwUHBgcHBwsHEgcTBxQHFQcaBx4HJQcm
+BycHKActBzEHOAc5BzoHOwdAB0wHTQdOB08HVgDlB1gHWwdeB2YHZwdoB2kHhQeGB4cHiAeJB4oHiweM
+B40HjgePB1YBWwCOB5EHmQeaB5sHoQepB6oHqwfHB84HzwfQB9MH2AfZCFQIXghjCGQIZQhnAOwIawh5
+CIIIiQiKCIsIlAidCGQIngijCKUIqAipCLIIuwi8CL0IxAhkCM0I1ghkCNcI4wjsCPUIZAj2CPgJAAkJ
+CQoJCwA4CQ4JEAmLCgcKgwqECoUKhgqHCogKiQqKCosKjAqNCo4KjwqQCpEKkgqTCpQKlQqWCpcKmAqZ
+CpoKmwqcCp0KngqfCqAKoQqiCqMKpAqlCqYKpwqoCqkKqgqrCqwKrQquCq8KsAqxCrIAawqzCrQKtQq2
+CrcKuAq5CroKuwq8Cr0Kvgq/CsAKwQrCCsMKxArFCsYKxwrICskKygrLCswKzQrOCs8K0ArRCtIK0wrU
+CtUK1grXCtgK2QraCtsK3ArdCt4K3wrgCuEK4grjCuQK5QrmCucK6ArpCuoK6wrsCu0K7grvCvAK8Qry
+CvMK9Ar1CvYK9wr4Cv4LBAulDEYMRwxIDEkMSgxLDEwMTQxODE8MUAxRDFIMUwxUDFUMVgxXDFgMWQxa
+DFsMXAxdDF4MXwxgDGEMYgxjDGQMZQxmDGcMaAxpDGoMawxsDG0MbgGLDG8McAxxDHIMcwx0DHUMdgx3
+DHgMeQx6DHsMfAx9DH4MfwyADIEMggyDDIQMhQyGDIcMiAyJDIoMiwyMDI0MjgyPDJAMkQySDJMMlAyV
+DJYMlwyYDJkMmgybDJwMnQyeDJ8MoAyhDKIMowykDKUMpgynDKgMqQyqDKsMrAytDK4MrwywDLEMsgyz
+DLQMtQy2DLcMuAy5DLoMuwy8DL0Mvgy/DMAMwQzCDMMMxAzFDMYMxwzIDMkMygzLDMwBpgzNDM4MzwzQ
+DNEM0gzTDNQM1QzWDNcM2AzZDNoM2wzcDN0M3gzfDOAM4QziDOUM6AzrVSRudWxs3xASAA0ADgAPABAA
+EQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4A
+LwAwVk5TUm9vdFYkY2xhc3NdTlNPYmplY3RzS2V5c18QD05TQ2xhc3Nlc1ZhbHVlc18QGU5TQWNjZXNz
+aWJpbGl0eU9pZHNWYWx1ZXNdTlNDb25uZWN0aW9uc1tOU05hbWVzS2V5c1tOU0ZyYW1ld29ya11OU0Ns
+YXNzZXNLZXlzWk5TT2lkc0tleXNdTlNOYW1lc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eUNvbm5lY3Rv
+cnNdTlNGb250TWFuYWdlcl8QEE5TVmlzaWJsZVdpbmRvd3NfEA9OU09iamVjdHNWYWx1ZXNfEBdOU0Fj
+Y2Vzc2liaWxpdHlPaWRzS2V5c1lOU05leHRPaWRcTlNPaWRzVmFsdWVzgAKBAyeBAd2BAoOBAyaBAR6B
+AgqABoECgoEChIECC4EDJIAAgAeBAgmBAyUSAASVoYEChdIADgAyADMANFtOU0NsYXNzTmFtZYAFgAPS
+AA4ANgA3ADhZTlMuc3RyaW5ngARdTlNBcHBsaWNhdGlvbtIAOgA7ADwAPVgkY2xhc3Nlc1okY2xhc3Nu
+YW1lowA9AD4AP18QD05TTXV0YWJsZVN0cmluZ1hOU1N0cmluZ1hOU09iamVjdNIAOgA7AEEAQqIAQgA/
+Xk5TQ3VzdG9tT2JqZWN0XxAQSUJDb2NvYUZyYW1ld29ya9IADgBFAEYAR1pOUy5vYmplY3RzgByiAEgA
+SYAIgMHdAEsADgBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAY1xO
+U1dpbmRvd1ZpZXdcTlNTY3JlZW5SZWN0XxATTlNGcmFtZUF1dG9zYXZlTmFtZV1OU1dpbmRvd1RpdGxl
+WU5TV1RGbGFnc11OU1dpbmRvd0NsYXNzXE5TV2luZG93UmVjdFlOU01heFNpemVfEA9OU1dpbmRvd0Jh
+Y2tpbmdfEBFOU1dpbmRvd1N0eWxlTWFza1lOU01pblNpemVbTlNWaWV3Q2xhc3OADYDAgL2AO4AKEnB4
+AACAC4AJgL8QAhANgL6ADF8QGHt7Mzc4LCAyNDd9LCB7NDg0LCAxOTl9fV8QGEF1dGhlbnRpY2F0ZSB0
+byBLZXJiZXJvc9IADgA2ADcAaIAEWE5TV2luZG930gAOADYANwBrgARUVmlld9cAbQAOAG4AbwBwAGgA
+cQByAHMAdAB1AHYAcgB4XxAPTlNOZXh0UmVzcG9uZGVyWk5TU3Vidmlld3NYTlN2RmxhZ3NbTlNGcmFt
+ZVNpemVbTlNTdXBlcnZpZXeADoBzgA8RAQCAu4AOgLzSAA4ARQB6AHuAV6EAfIAQ3QBtAA4AfgB/AIAA
+gQBuAG8AaACCAHEAgwCEAFcAhgCHAIgAiQCKAIsAjAByAI4AVwCOAJFeTlNUYWJWaWV3SXRlbXNZTlNU
+dkZsYWdzV05TRnJhbWVWTlNGb250XxARTlNEcmF3c0JhY2tncm91bmRfEBZOU0FsbG93VHJ1bmNhdGVk
+TGFiZWxzXxAVTlNTZWxlY3RlZFRhYlZpZXdJdGVtgA2AuoB1EAaAdIAqgBERARKADgmADQmAdtIADgBF
+AHoAlIBXoQCVgBLYAG0ADgBuAG8AcABoAHEAlwB8AHMAmgB1AJsAcgB8AJ5dTlNOZXh0S2V5Vmlld4AQ
+gHOAE4BygA6AEIAU0gAOAEUAegChgFeoAJ4AowCkAKUApgCnAKgAqYAUgB6AN4AngESAOYBigGnbAG0A
+DgCAAKsArACtAG8ArgBoAHEAlwCVALAAsQCOALMAtAC1AI4AcgCVAKNaTlNFZGl0YWJsZVZOU0NlbGxb
+TlNEcmFnVHlwZXNZTlNFbmFibGVkgBKAJYAdCYAfgBURAQwJgA6AEoAe0gAOAEUARgC8gBymAL0AvgC/
+AMAAwQDCgBaAF4AYgBmAGoAbXxAZQXBwbGUgUERGIHBhc3RlYm9hcmQgdHlwZV8QGUFwcGxlIFBORyBw
+YXN0ZWJvYXJkIHR5cGVfEDFOZVhUIEVuY2Fwc3VsYXRlZCBQb3N0U2NyaXB0IHYxLjIgcGFzdGVib2Fy
+ZCB0eXBlXxAVTlNGaWxlbmFtZXNQYm9hcmRUeXBlXxAeTmVYVCBUSUZGIHY0LjAgcGFzdGVib2FyZCB0
+eXBlXxAaQXBwbGUgUElDVCBwYXN0ZWJvYXJkIHR5cGXSADoAOwDKAMujAMsAzAA/XE5TTXV0YWJsZVNl
+dFVOU1NldF8QFXt7MjAsIDExOX0sIHs2MiwgNjJ9fdkAbQAOAIAArABvAK4AaABxAJcAlQDQANEA0gDT
+AI4AcgCVAKWAEoA2gCaAKBEBCgmADoASgCfYANkADgDaANsA3ADdAN4A3wDgAOEA4gDjAOIA4gDkAOVb
+TlNDZWxsRmxhZ3NXTlNTdHlsZVpOU0NvbnRlbnRzV05TQWxpZ25XTlNTY2FsZVxOU0NlbGxGbGFnczJa
+TlNBbmltYXRlcxIAAf4AgCQQAIAgEgIAAAAI0wAOADIA5wDoAOkA6l5OU1Jlc291cmNlTmFtZYAjgCGA
+IldOU0ltYWdlXUtlcmJlcm9zQWdlbnTSADoAOwDuAO+iAO8AP18QEE5TQ3VzdG9tUmVzb3VyY2XSADoA
+OwDxAPKjAPIArAA/W05TSW1hZ2VDZWxs0gA6ADsA9AD1pQD1APYA9wD4AD9bTlNJbWFnZVZpZXdZTlND
+b250cm9sVk5TVmlld1tOU1Jlc3BvbmRlcl8QFnt7ODcsIDExOX0sIHszODcsIDUxfX3ZAG0ADgCAAKwA
+bwCuAGgAcQCXAJUA0AD9AP4AtQCOAHIAlQCkgBKANoBBgEIJgA6AEoA32ADZAA4BBADbAQUBBgDeAQcB
+CAEJAQoBCwCKAKMBDgEPXxARTlNCYWNrZ3JvdW5kQ29sb3JZTlNTdXBwb3J0XU5TQ29udHJvbFZpZXdb
+TlNUZXh0Q29sb3ISBAH+AIA1gC2AKYAqgB4SEEAAAIAyXxAjUGxlYXNlIGVudGVyIHlvdXIgS2VyYmVy
+b3MgaWRlbnRpdHnUAA4BEgETARQBFQEWARcBGFZOU1NpemVWTlNOYW1lWE5TZkZsYWdzgCwjQCoAAAAA
+AACAKxEEFFxMdWNpZGFHcmFuZGXSADoAOwEbAIGiAIEAP9UADgEdAR4BHwEgASEBIgCIASMBJFdOU0Nv
+bG9yXE5TQ29sb3JTcGFjZVtOU0NvbG9yTmFtZV1OU0NhdGFsb2dOYW1lgDGAMIAvgC5WU3lzdGVtXGNv
+bnRyb2xDb2xvctMADgEeASgBIQEqAStXTlNXaGl0ZYAxEANLMC42NjY2NjY2OQDSADoAOwEtAR2iAR0A
+P9UADgEdAR4BHwEgASEBMACIATEBJIAxgDSAM4AuXxAQY29udHJvbFRleHRDb2xvctMADgEeASgBIQEq
+ATaAMUIwANIAOgA7ATgBOaQBOQE6AKwAP18QD05TVGV4dEZpZWxkQ2VsbFxOU0FjdGlvbkNlbGzSADoA
+OwE8AT2lAT0A9gD3APgAP1tOU1RleHRGaWVsZNkAbQAOAIAArABvAK4AaABxAJcAlQDQAUEBQgDTAI4A
+cgCVAKeAEoA2gDiAOgmADoASgDlfEBV7ezkwLCA4OX0sIHszNzgsIDIyfX3ZAG0ADgCAAKwAbwCuAGgA
+cQCXAJUA0AFLAUwAtQCOAHIAlQCmgBKANoBfgGAJgA6AEoBE2QDZAA4BBADbAQUBBgDeAIIBBwFSAQkB
+VABaAIoApAFYAI4BWhP/////lHH+QYA1gDyAO4AqgDcSEEAEAAmAP1DVAA4BHQEeAR8BIAEhAV4AiAFf
+ASSAMYA+gD2ALl8QE3RleHRCYWNrZ3JvdW5kQ29sb3LTAA4BHgEoASEBKgFkgDFCMQDVAA4BHQEeAR8B
+IAEhATAAiAFoASSAMYA0gECALll0ZXh0Q29sb3JfEBR7ezE3LCA5NH0sIHs2OCwgMTd9fdgA2QAOAQQA
+2wEFAQYA3gEHAQgBCQEKAW8AigClAXIBD4A1gC2AQ4AqgCcSBEAAAIAyVU5hbWU62ABtAA4AgACsAG8A
+rgBoAHEAlQF3AXgBeQDTAI4AcgCVgBKAXoBFgEYJgA6AEl8QFXt7OTAsIDU3fSwgezM4MSwgMjZ9fd0B
+fwDZAA4BBADbAQUBBgDeAIIBgAGBAYIBBwCmAYQBhQFUAYcAigCmAVgAjgGLAYwAjgEPWk5TRGVsZWdh
+dGVfEBJOU1Zpc2libGVJdGVtQ291bnRbTlNUYWJsZVZpZXdfEBVOU0hhc1ZlcnRpY2FsU2Nyb2xsZXKA
+RBIUcf5AgF2APIBHgCqARAkQBYBICYAy0gAOADYANwFbgATfEBYAbQF/AZIAfwGTAA4BBAGUAZUBlgGX
+AZgAbwBwAK4AaAGZAZoBmwBxAZwBnQGeAXkBeQGhAOIBogGjAI4BpQGmAacBeQCMAakAjgGrAawBrQGu
+AZ4BsAGxWE5TVGFyZ2V0XxAfTlNEcmFnZ2luZ1NvdXJjZU1hc2tGb3JOb25Mb2NhbF8QEk5TQWxsb3dz
+VHlwZVNlbGVjdF8QF05TSW50ZXJjZWxsU3BhY2luZ1dpZHRoXxAZTlNDb2x1bW5BdXRvcmVzaXppbmdT
+dHlsZV8QGE5TSW50ZXJjZWxsU3BhY2luZ0hlaWdodFxOU0RhdGFTb3VyY2VYTlNBY3Rpb25bTlNHcmlk
+Q29sb3JfEBxOU0RyYWdnaW5nU291cmNlTWFza0ZvckxvY2FsXk5TVGFibGVDb2x1bW5zW05TUm93SGVp
+Z2h0gEmARoBGE//////SQIAAgFyAVAkjQAgAAAAAAAAQASNAAAAAAAAAAIBGgEoJgEuAW4BYEA+ASYBM
+I0AzAAAAAAAAV3sxNSwgMH3SAA4ARQB6AbWAV6EBtoBN2gG4AA4BuQG6AbsBvAG9Ab4BvwGBAI4BwQHC
+AcMBxAHFASoBxgHHAYxeTlNJc1Jlc2l6ZWFibGVcTlNIZWFkZXJDZWxsXE5TSWRlbnRpZmllcldOU1dp
+ZHRoWk5TRGF0YUNlbGxeTlNSZXNpemluZ01hc2taTlNNaW5XaWR0aFpOU01heFdpZHRoCYBWgE+ATiNA
+KAAAAAAAAIBTI0AkAAAAAAAAI0CPQAAAAAAAgEjXANkADgEEANsBBQDeAQcBygHLAcwBhwHOAOIBXhIE
+gf4AgFKAUYBHgFCAPtQADgESARMBFAEVAcQBFwHTgCyAKxAQ0wAOAR4BKAEhASoB1oAxSzAuMzMzMzMy
+OTkA0gA6ADsB2AHZpQHZATkBOgCsAD9fEBFOU1RhYmxlSGVhZGVyQ2VsbNgA2QAOAQQBBQEGAN4AggEH
+AdsBCQGjAIoBjAHgAI4BDxIUMf5AgDWAVIAqgEgRBAAJgDLVAA4BHQEeAR8BIAEhASIAiAHmASSAMYAw
+gFWALl8QFmNvbnRyb2xCYWNrZ3JvdW5kQ29sb3LSADoAOwHqAeuiAesAP11OU1RhYmxlQ29sdW1u0gA6
+ADsB7QHuowHuAe8AP15OU011dGFibGVBcnJheVdOU0FycmF51QAOAR0BHgEfASABIQHyAIgB8wEkgDGA
+WoBZgC5ZZ3JpZENvbG9y0wAOAR4BKAEhASoB+IAxRDAuNQBfEBB0YWJsZVZpZXdBY3Rpb2460gA6ADsB
++wH8pgH8AYEA9gD3APgAP18QEE5TQ29tYm9UYWJsZVZpZXfSADoAOwH+Af+lAf8BOQE6AKwAP15OU0Nv
+bWJvQm94Q2VsbNIAOgA7AgECAqYCAgE9APYA9wD4AD9aTlNDb21ib0JveF8QFHt7MTcsIDYxfSwgezY4
+LCAxN3192ADZAA4BBADbAQUBBgDeAQcBCAEJAQoCBwCKAKcBcgEPgDWALYBhgCqAOYAyVlJlYWxtOtkA
+bQAOAIAArABvAK4AaABxAJcAlQIOAg8CEAIRAI4AcgCVAHyAEoBogGOAZBEBIQmADoASgBBfEBV7ezM3
+NiwgMTJ9LCB7OTgsIDMyfX3dANkADgIYAhkCGgIbAhwA2wEFAQYCHQDeAh4BCAIfAFoCIQGmAIoCIwIk
+AIoAqAInAigCKV8QE05TQWx0ZXJuYXRlQ29udGVudHNfEBJOU1BlcmlvZGljSW50ZXJ2YWxeTlNCdXR0
+b25GbGFnczJfEBBOU0FsdGVybmF0ZUltYWdlXxAPTlNLZXlFcXVpdmFsZW50XxAPTlNQZXJpb2RpY0Rl
+bGF5XU5TQnV0dG9uRmxhZ3OAZ4A7EBmAKoBmgGWAKoBiEMgSCAAAABP/////hoJA/1hDb250aW51ZdIA
+DgA2ADcBW4AE0gA6ADsCLgIvpAIvAToArAA/XE5TQnV0dG9uQ2VsbNIAOgA7AjECMqUCMgD2APcA+AA/
+WE5TQnV0dG9u2gBtAA4AgAI0AKwAbwCuAGgAMgBxAJUCNgI3AjgCOQI6AI4AcgI9AJVfEBNOU09yaWdp
+bmFsQ2xhc3NOYW1lgBKAcYBsgGuAbREBJAmADoBqgBJbUG9wdXBCdXR0b25fEBR7ezE4LCAxNX0sIHs1
+MSwgMjd9fd0A2QAOAhgCQgIZAhoCHADbAQUBBgIdAN4CHgEIAh8AWgJFAkYAYABaAFoCSQCpAksCKAJM
+XU5TTm9ybWFsSW1hZ2WAZ4A7gG8QS4A7gDuAboBpEQGQE/////+GzED/1AAOARIBEwEUARUBxgEXAdOA
+LIAr0wAOADIA5wDoAOkCU4AjgCGAcFRHZWFy0gA6ADsCVgJXogJXAD9eTlNDbGFzc1N3YXBwZXJaezQ4
+OCwgMjAxfdIAOgA7AloA96MA9wD4AD9fEBV7ey00LCAwfSwgezQ4OCwgMjAxfX3SAA4ARQB6Al6AV6MA
+kQJgAmGAdoB6gJ7WAA4BugD3AmMBHQJkAmUCZgCVAHwBCgJqWU5TVGFiVmlld1dOU0xhYmVsgHmAd4AS
+gBCALYB4UTFfEA9TZWxlY3QgSWRlbnRpdHnSADoAOwJuAm+iAm8AP11OU1RhYlZpZXdJdGVt1gAOAboA
+9wJjAR0CZAJlAnICcwB8AQoCdoB5gHuAfIAQgC2AnVEy1QBtAA4AbgBvAHAAKwBzAnsAdQJ8gACAc4B9
+gJzSAA4ARQB6An+AV6cCgAKBAoICgwKEAoUChoB+gIKAh4CLgJCAlICZ2QBtAA4AgACrAKwArQBvAK4A
+cQJzALACigCOAowCjQC1AI4Cc4B8gCWAgAmAgYB/CYB80gAOAEUARgKSgBymAL0AvgC/AMAAwQDCgBaA
+F4AYgBmAGoAbXxAVe3sxNywgMTIyfSwgezYyLCA2Mn192ADZAA4A2gDbANwA3QDeAN8A4ADhAOIA4wDi
+AOIA5ADlgCSAIAjZAG0ADgCAAjQArABvAK4AMgBxAnMCNgKhAqICowKkAI4CpgJzgHyAcYCFgISAhhEB
+IgmAg4B8XxARTlNTZWN1cmVUZXh0RmllbGRfEBV7ezg3LCA2MH0sIHszODEsIDIyfX3ZANkADgEEANsB
+BQEGAN4AggEHAVIBCQFUAFoAigKBAVgAjgFagDWAPIA7gCqAggmAP9cAbQAOAIAArABvAK4AcQJzAg4C
+tQK2AhEAjgJzgHyAaICIgIkJgHzdANkADgIYAhkCGgIbAhwA2wEFAQYCHQDeAh4BCAIfAFoCIQGmAIoC
+vQIkAIoCggInAigCKYBngDuAKoCKgGWAKoCH0gAOADYANwFbgATXAG0ADgCAAKwAbwCuAHECcwIOAsYC
+xwIRAI4Cc4B8gGiAjICNCYB8XxAVe3syODMsIDEyfSwgezkzLCAzMn193QDZAA4CGAIZAhoCGwIcANsB
+BQEGAh0A3gIeAQgCHwBaAiEBpgCKAs8C0ACKAoMCJwIoAimAZ4A7gCqAj4COgCqAi1dHbyBCYWNr0gAO
+ADYANwFbgATXAG0ADgCAAKwAbwCuAHECcwDQAtkC2gDTAI4Cc4B8gDaAkYCSCYB8XxAWe3s4NCwgMTY3
+fSwgezM4NywgMTd9fdgA2QAOAQQA2wEFAQYA3gEHAQgBCQEKAuEAigKEAQ4BD4A1gC2Ak4AqgJCAMl8Q
+I1BsZWFzZSBlbnRlciB5b3VyIEtlcmJlcm9zIHBhc3N3b3Jk1wBtAA4AgACsAG8ArgBxAnMA0ALpAuoA
+jACOAnOAfIA2gJWAlgmAfF8QFXt7ODQsIDkwfSwgezM4NywgNjl9fdgA2QAOAQQA2wEFAQYA3gEHAQgB
+CQEKAvEC8gKFAQ4BD4A1gC2Al4CYgJSAMl8QME1haWwgd2FudHMgdG8gY29ubmVjdCB0byB0aGUgYWNj
+b3VudCBseHNAbWl0LmVkddQADgESARMBFAEVAvgBFwL6gCwjQCYAAAAAAACAKxEMHNkAbQAOAIACNACs
+AG8ArgAyAHECcwI2Av4COAMAAjoAjgI9AnOAfIBxgJqAa4CbCYBqgHxfEBR7ezE4LCAxNn0sIHs1MSwg
+MjZ9fd0A2QAOAhgCQgIZAhoCHADbAQUBBgIdAN4CHgEIAh8AWgJFAkYAYABaAFoCSQKGAksCKAMNgGeA
+O4BvgDuAO4BugJkT/////4bEQP9fEBpBdXRoZW50aWNhdGlvbiBJbmZvcm1hdGlvbtYADgG6APcCYwEd
+AmQCZQMRAxIAfAEKAxWAeYCfgKCAEIAtgLlRM9UAbQAOAG4AbwBwACsAcwMaAHUDG4AAgHOAoYC40gAO
+AEUAegMegFelAx8DIAMhAyIDI4CigKeAq4CvgLTXAG0ADgCAAKwAbwCuAHEDEgIOAycDKAIRAI4DEoCg
+gGiAo4CkCYCgXxAVe3szOTIsIDEyfSwgezgyLCAzMn193QDZAA4CGAIZAhoCGwIcANsBBQEGAh0A3gIe
+AQgCHwBaAiEBpgCKAzADMQCKAx8CJwIoAimAZ4A7gCqApoClgCqAolREb25l0gAOADYANwFbgATZAG0A
+DgCAAKsArACtAG8ArgBxAxIAsAM6AI4DPAM9ALUAjgMSgKCAJYCpCYCqgKgJgKDSAA4ARQBGA0KAHKYA
+vQC+AL8AwADBAMKAFoAXgBiAGYAagBvYANkADgDaANsA3ADdAN4A3wDgAOEA4gDjAOIA4gDkAOWAJIAg
+CNcAbQAOAIAArABvAK4AcQMSANADUANRANMAjgMSgKCANoCsgK0JgKDYANkADgEEANsBBQEGAN4BBwEI
+AQkBCgNXAIoDIQEOAQ+ANYAtgK6AKoCrgDJaQ29uY2x1c2lvbtcAbQAOAIAArABvAK4AcQMSANADXwNg
+AIwAjgMSgKCANoCwgLEJgKBfEBV7ezg0LCA2MH0sIHszODcsIDk5fX3YANkADgEEANsBBQEGAN4BBwEI
+AQkDZgNnAvIDIgNqAQ+ANYCzgLKAmICvEhBCAACAMl8QS0NvbmdyYXR1bGF0aW9ucyEgWW91IGhhdmUg
+YWNxdWlyZWQgS2VyYmVyb3MgdGlja2V0cyBmb3IgbHhzQEFUSEVOQS5NSVQuRURVLtMADgEeASgBIQEq
+A2+AMU0xIDAuOTcwMDAwMDMA1wBtAA4AgACsAG8ArgBxAxICDgNzA3QCEQCOAxKAoIBogLWAtgmAoF8Q
+FXt7MzA1LCAxMn0sIHs5MSwgMzJ9fd0A2QAOAhgCGQIaAhsCHADbAQUBBgIdAN4CHgEIAh8AWgIhAaYA
+igN8AtAAigMjAicCKAIpgGeAO4AqgLeAjoAqgLTSAA4ANgA3AVuABFZSZXN1bHTSADoAOwOEAmOkAmMA
+9wD4AD9aezQ4NCwgMTk5fV8QFnt7MCwgMH0sIHsxOTIwLCAxMTc4fX1dezIzOS4zMiwgMTI5fV8QEnsz
+LjQwMjgyZSszOCwgMTMxfdIAOgA7A4oDi6IDiwA/XxAQTlNXaW5kb3dUZW1wbGF0Zd0ASwAOAEwATQBO
+AE8AUABRAFIAUwBUAFUAVgONAFgDjwBaA5EAXAOSA5MDlABgAGEDlQOWgMaAwIEBG4A7gMOAxIDCgQEd
+gQEcgMVfEBh7ezI3OSwgMzYzfSwgezQxOSwgNDY1fX1fEBpDaG9vc2UgYSBLZXJiZXJvcyBJZGVudGl0
+edIADgA2ADcAaIAE0gAOADYANwBrgATXAG0ADgBuAG8AcABoAHEDngBzA6AAdQOhA54Do4DHgHOAyIEB
+GYDHgQEa0gAOAEUAegOmgFeoA6cDqAOpA6oDqwOsA60DroDJgM6A0oD7gQEAgQEFgQEJgQER2gBtAA4A
+gACrAKwArQBvAK4AaABxA40AsAOyAI4DtAO1ALUAjgOeA42AxoAlgMwJgM2AygmAx4DG0gAOAEUARgO7
+gBymAL0AvgO+AMAAwQDCgBaAF4DLgBmAGoAbXxAVe3sxNywgMzg2fSwgezYyLCA2Mn192ADZAA4A2gDb
+ANwA3QDeAN8DxADhAOIA4wDiAOIA5ADlEiAB/gCAJIAgCNgAbQAOAIAArABvAK4AaABxA40A0APLA8wA
+0wCOA54DjYDGgDaAz4DQCYDHgMZfEBZ7ezg0LCAzNzd9LCB7MzE4LCAyOX192ADZAA4BBADbAQUBBgDe
+AQcBCAEJAQoD1ALyA6gD1wEPgDWALYDRgJiAzhIAQgAAgDJfECVDaGVja2luZyBtYWlsIGZvciBhY2Nv
+dW50IGx4c0BtaXQuZWR13gBtA9sADgCAA9wD3QPeAG4D3wBvAGgAcQPgA+EDjQPjA+QD5QPmA+cD6APp
+A+oAjAOeA40D7QPuW05TSFNjcm9sbGVyWE5Tc0ZsYWdzXE5TQ29ybmVyVmlld18QEE5TSGVhZGVyQ2xp
+cFZpZXdcTlNTY3JvbGxBbXRzW05TVlNjcm9sbGVyXU5TQ29udGVudFZpZXeAxoD1gPqA+RECMoDcgNmA
+008QEEEgAABBIAAAQZgAAEGYAACAx4DGgPGA1NIADgBFAHoD8YBXpQPuA+0D4wPoA+eA1IDxgPWA2YDc
+2gBtAA4AgAP4AG4AbwP5AGgD+gBxA6kD/AP9A/4D/wQABAEDngGjA6lZTlNjdkZsYWdzWU5TRG9jVmll
+d1lOU0JHQ29sb3KA0oDwgO8QBIDVEQkAgNaAx4BUgNLSAA4ARQB6BAeAV6EEAYDW3xAUAG0BkwAOAH8E
+CgEEAZQD3QGVAZYBlwBvAHAArgBoAZoBmwBxAZwBnQPuAOIEDAQNBA4BXgCOA+cBpQGLAacAdQQSAI4D
+ngGtAa4D7gQXBBhcTlNIZWFkZXJWaWV3gNSA7hJCwAAAgNiAPgmA3IDXCYDHgFiA1IDfI0AxAAAAAAAA
+WnszODAsIDI5MX3XAG0ADgBvAHAAaABxAYED6AQcAHUEHQOeA+gEAYDZgNuA2oDHgNmA1toAbQAOAIAD
++ABuAG8D+QBoA/oAcQOpA/wEJAP+BCUEAAQOA54BowOpgNKA8ID4gPeA2IDHgFSA0ll7MzgwLCAxN33S
+ADoAOwQsBC2kBC0A9wD4AD9fEBFOU1RhYmxlSGVhZGVyVmlld9YAbQAOAIAAbwBoAHEDqQQwBDEEMgOe
+A6mA0oDegN0T/////4AAAQCAx4DSXxAUe3stMjYsIDB9LCB7MTYsIDE3fX3SADoAOwQ3BDikBDgA9wD4
+AD9dX05TQ29ybmVyVmlld9IADgBFAHoEO4BXogQ8BD2A4IDo2gG4AA4BuQG7AbwBvQG+Ab8EPwGBAI4B
+wQRCBEMERAEqBEUBxwCOBAFcTlNJc0VkaXRhYmxlCYBWgOEjQHEflgAAAACA5iNAYr8sAAAAAAmA1tcA
+2QAOAQQA2wEFAN4BBwHKAcsESgRLAvIA4gRNgFKA44DigJiA5FhJZGVudGl0edMADgEeASgBIQEqAdaA
+MdUADgEdAR4BHwEgASEBMACIBFQBJIAxgDSA5YAuXxAPaGVhZGVyVGV4dENvbG9y2QDZAA4BBADbAQUB
+BgDeAIIBBwRYAQkBCgRbAIoEAQReAI4BDxJUIf5AgDWALYDngCqA1hJQQAQACYAyWVRleHQgQ2VsbNoB
+uAAOAbkBuwG8Ab0BvgG/BD8BgQCOAcEEZQRmBGcBKgRoBGkAjgQBCYBWgOkjQFkUEAAAAACA7SNAWQAA
+AAAAACNAYsAAAAAAAAmA1tcA2QAOAQQA2wEFAN4BBwEIAcsEbgRvAvIEcQRNgFKA64DqgJgSBAAAAIDk
+XlRpbWUgUmVtYWluaW5n1QAOAR0BHgEfASABIQFeAIgEdwEkgDGAPoDsgC5baGVhZGVyQ29sb3LYANkA
+DgEEANsBBQEGAN4BBwR7AQkBCgRbAIoEAQSBAQ8SRAH+QIA1gC2A54AqgNYSREAEAIAy0gA6ADsEhAGB
+pQGBAPYA9wD4AD9fEBV7ezEsIDE3fSwgezM4MCwgMjkxfX3SADoAOwSHBIikBIgA9wD4AD9aTlNDbGlw
+Vmlld9kAbQGSAA4AgABvAGgBmQBxBIoDqQOpBI0EjgQyA54EkAOpBJJZTlNQZXJjZW50gNKA0oD0gPKA
+x4DzgNIjP+79TiAAAABfEBZ7ey0zMCwgMTd9LCB7MTUsIDI4NX19XF9kb1Njcm9sbGVyOtIAOgA7BJYE
+l6UElwD2APcA+AA/Wk5TU2Nyb2xsZXLaAG0BkgAOAIAD3ABvAGgBmQBxBIoDqQOpBI0EnAGmBDIDngSQ
+A6kEoIDSgNKA9ID2gMeA84DSIz/s7jJgAAAAXxAVe3sxLCAtMzB9LCB7MzYyLCAxNX190gAOAEUAegSk
+gFehBA6A2F8QE3t7MSwgMH0sIHszODAsIDE3fX1fEBZ7ezE3LCA2MH0sIHszODIsIDMwOX190gA6ADsE
+qQSqpASqAPcA+AA/XE5TU2Nyb2xsVmlld9gAbQAOAIAArABvAK4AaABxA40CDgSuBK8CEQCOA54DjYDG
+gGiA/ID9CYDHgMZfEBV7ezMyMCwgMTJ9LCB7ODcsIDMyfX3dANkADgIYAhkCGgIbAhwA2wEFAQYCHQDe
+Ah4BCAIfAFoCIQGmAIoEuAS5AIoDqgInAigCKYBngDuAKoD/gP6AKoD7VkNob29zZVEN2ABtAA4AgACs
+AG8ArgBoAHEDjQIOBMEEwgIRAI4DngONgMaAaIEBAYEBAgmAx4DGXxAVe3syMzgsIDEyfSwgezgyLCAz
+Mn193QDZAA4CGAIZAhoCGwIcANsBBQEGAh0A3gIeAQgCHwBaAiEBpgCKBMsEzACKA6sCJwIoAimAZ4A7
+gCqBAQSBAQOAKoEBAFZDYW5jZWxRG9gAbQAOAIAArABvAK4AaABxA40A0ATUBNUE1gCOA54DjYDGgDaB
+AQaBAQcRAQ4JgMeAxl8QFnt7ODQsIDQxNH0sIHszMTgsIDIxfX3YANkADgEEANsBBQEGAN4BBwEIAQkB
+CgTeAIoDrAThAQ+ANYAtgQEIgCqBAQUSAEAAAIAyXxAxTWFpbCByZXF1aXJlcyB0aGF0IHlvdSBjaG9v
+c2UgYSBLZXJiZXJvcyBJZGVudGl0edgAbQAOAIAArABvAK4AaABxA40CDgTnBOgCOgCOA54DjYDGgGiB
+AQqBAQsJgMeAxl8QFHt7MTcsIDMwfSwgezIzLCAyMn193gDZAA4CGAJCAhkCGgIbAhwA2wEFAQYCHQDe
+Ah4BCAIfAFoE8AIhAIgE8QTyAFoC8gOtAicCKAT2gGeAO4EBDIEBDoEBEIA7gJiBAQkSCERA/9MADgAy
+AOcA6ADpBPqAI4AhgQENU0FkZNMADgAyAOcA6ADpBP+AI4AhgQEPW0FkZF9QcmVzc2Vk0gAOADYANwFb
+gATYAG0ADgCAAKwAbwCuAGgAcQONAg4FBgUHAjoAjgOeA42AxoBogQESgQETCYDHgMZfEBR7ezM5LCAz
+MH0sIHsyMywgMjJ9fd4A2QAOAhgCQgIZAhoCGwIcANsBBQEGAh0A3gIeAQgCHwBaBQ8CIQCIBRAFEQBa
+AvIDrgInAigE9oBngDuBARSBARaBARiAO4CYgQER0wAOADIA5wDoAOkFGIAjgCGBARVWUmVtb3Zl0wAO
+ADIA5wDoAOkFHYAjgCGBARdeUmVtb3ZlX1ByZXNzZWTSAA4ANgA3AVuABFp7NDE5LCA0NjV9WnsyMTMs
+IDEyOX1fEBp7My40MDI4MmUrMzgsIDMuNDAyODJlKzM4fdIADgBFAHoFJoBXrxAlBScFKAUpBSoFKwUs
+BS0FLgUvBTAFMQUyBTMFNAU1BTYFNwU4BTkFOgU7BTwFPQU+BT8FQAVBBUIFQwVEBUUFRgVHBUgFSQVK
+BUuBAR+BASqBATyBAUOBAUmBAU2BAVKBAVSBAVmBAWiBAWqBAWuBAXGBAXOBAXiBAXmBAX2BAX+BAYGB
+AYaBAYuBAY+BAZOBAZiBAZyBAaGBAaaBAaeBAayBAa2BAbKBAbOBAbyBAc+BAdOBAdeBAdvUAA4FTQVO
+AmQFTwVQBVEFUl1OU0Rlc3RpbmF0aW9uWE5TU291cmNlgQEpgQEngQEggQEo1AAOBVQFVQVWBVcFWAVZ
+BVpfEA9fTlNNYW5hZ2VkUHJveHlfEBFOU09iamVjdENsYXNzTmFtZV5OU0RlY2xhcmVkS2V5c4EBJoEB
+JIEBI4EBIdIADgBFAHoFXYBXoQVegQEiW2NhY2hlc0FycmF5XxAXS2VyYmVyb3NDYWNoZUNvbGxlY3Rp
+b27RAA4FYoEBJdIAOgA7BWQFVKIFVAA/0gA6ADsFZgVnowVnBWgAP18QEk5TT2JqZWN0Q29udHJvbGxl
+clxOU0NvbnRyb2xsZXLSAA4AMgAzBVmABYEBI1djb250ZW500gA6ADsFbgVvowVvBXAAP18QFE5TTmli
+T3V0bGV0Q29ubmVjdG9yXk5TTmliQ29ubmVjdG9y1AAOBU0FTgJkBU8FcwKGBXWBASmBASuAmYEBO9QA
+DgV3ARMFeAV5BXoAWgV8V05TVGl0bGVbTlNNZW51SXRlbXOBATqBASyAO4EBLVRNZW510gAOAEUAegWA
+gFekBYEFggWDBYSBAS6BATWBATeBATjYAA4FdwWGBYcFiAWJBYoFiwWMBY0FjgBaBZAFkQWSBXNfEBFO
+U0tleUVxdWl2TW9kTWFza1pOU0tleUVxdWl2XU5TTW5lbW9uaWNMb2NZTlNPbkltYWdlXE5TTWl4ZWRJ
+bWFnZVZOU01lbnWBATSBAS8SABAAAIA7En////+BATCBATKBAStvEA8AVABpAGMAawBlAHQAIABPAHAA
+dABpAG8AbgBzICbTAA4AMgDnAOgA6QWYgCOAIYEBMV8QD05TTWVudUNoZWNrbWFya9MADgAyAOcA6ADp
+BZ2AI4AhgQEzXxAQTlNNZW51TWl4ZWRTdGF0ZdIAOgA7BaAFoaIFoQA/Wk5TTWVudUl0ZW3YAA4FdwWG
+BYcFiAWJBYoFiwWMBaQFjgBaBZAFkQWSBXOBATSBATaAO4EBMIEBMoEBK28QEABDAGgAYQBuAGcAZQAg
+AFAAYQBzAHMAdwBvAHIAZCAm2gAOBXcFhgWrBYcFrAWIBYkFigWLBYwAWgWOAI4AWgCOBZAFkQWSBXNd
+TlNJc1NlcGFyYXRvclxOU0lzRGlzYWJsZWSBATSAOwmAOwmBATCBATKBASvYAA4FdwWGBYcFiAWJBYoF
+iwWMBbcFjgBaBZAFkQWSBXOBATSBATmAO4EBMIEBMoEBK18QEUFib3V0IEtlcmJlcm9zLi4u0gA6ADsF
+vgWLogWLAD9UbWVuddMADgVOAmQFwQXCBcOBAUKBAT2BAUHYAA4FdwWGBYcFiAWJBYoFiwWMBcYFjgXH
+BZAFkQWSBcqBATSBAT+BAUCBATCBATKBAT7UAA4FdwETBXgFeQXNBc4Fz4EBOoECAYECBIECAlVDbG9z
+ZVF3XXBlcmZvcm1DbG9zZTrSADoAOwXUBdWjBdUFcAA/XxAVTlNOaWJDb250cm9sQ29ubmVjdG9y0wAO
+BU4CZAXBBdgF2YEBQoEBRIEBSNgADgV3BYYFhwWIBYkFigWLBYwF3AWOBd0FkAWRBZIF4IEBNIEBRoEB
+R4EBMIEBMoEBRdMADgV3BXgFeQXjBeSBATqBAfqBAfxaU2VsZWN0IEFsbFFhWnNlbGVjdEFsbDrTAA4F
+TgJkBcEF6gXrgQFCgQFKgQFM2AAOBXcFhgWHBYgFiQWKBYsFjAXuBY4AWgWQBZEFkgXKgQE0gQFLgDuB
+ATCBATKBAT5UWm9vbVxwZXJmb3JtWm9vbTrUAA4FTQVOAmQFwQAfBfgF+YEBQoACgQFOgQFR1wAOBXcF
+hwWIBYkFigWLBYwF/ABaBZAFkQWSBgCBATSBAVCAO4EBMIEBMoEBT9QADgV3ARMFeAV5BgMGBAYFgQE6
+gQHkgQH0gQHlXxATQWJvdXQgS2VyYmVyb3NBZ2VudF8QHW9yZGVyRnJvbnRTdGFuZGFyZEFib3V0UGFu
+ZWw61AAOBU0FTgJkBU8FcwCpBgyBASmBASuAaYEBU1lwb3B1cE1lbnXTAA4FTgJkBcEGEAYRgQFCgQFV
+gQFY2AAOBXcFhgWHBYgFiQWKBYsFjAYUBhUGFgWQBZEFkgXggQE0gQFWEgAYAACBAVeBATCBATKBAUVf
+EBVQYXN0ZSBhbmQgTWF0Y2ggU3R5bGVRVl8QEXBhc3RlQXNQbGFpblRleHQ61AAOBU0FTgJkBU8GHwYg
+BVKBASmBAWGBAVqBASjaBiMADgYkBVQAqwVVBVYGJQYmBicAjgYpAI4GKwCOBi0GLgCOAI4Ajl8QGk5T
+RmlsdGVyUmVzdHJpY3RzSW5zZXJ0aW9uXxAUTlNQcmVzZXJ2ZXNTZWxlY3Rpb25fECJOU0NsZWFyc0Zp
+bHRlclByZWRpY2F0ZU9uSW5zZXJ0aW9uXxAYTlNTZWxlY3RzSW5zZXJ0ZWRPYmplY3RzXxAWTlNBdm9p
+ZHNFbXB0eVNlbGVjdGlvbgmBAWAJgQFfCYEBXoEBWwkJCdIADgBFAHoGNIBXogY1BjaBAVyBAV1fEBZz
+ZXJ2aWNlUHJpbmNpcGFsU3RyaW5nXxAYc2hvcnRUaW1lUmVtYWluaW5nU3RyaW5nXxASS2VyYmVyb3ND
+cmVkZW50aWFs0QAOBWKBASXSADoAOwY9Bj6kBj4FZwVoAD9fEBFOU0FycmF5Q29udHJvbGxlctkGIwAO
+BiQFVAVVBVYGJQYmBicAjgYpAI4GQwZEBkUAjgCOAI4JgQFgCYEBZ4EBZoEBYgkJCdIADgBFAHoGS4BX
+pAZMBk0GNgZPgQFjgQFkgQFdgQFlXxAQY3JlZGVudGlhbHNBcnJheV8QD3ByaW5jaXBhbFN0cmluZ18Q
+E3RpbWVSZW1haW5pbmdTdHJpbmddS2VyYmVyb3NDYWNoZdEADgVigQEl1AAOBU0FTgJkBcEASQTCBlqB
+AUKAwYEBAoEBadQADgVNBU4CZAVPBXMAqQV1gQEpgQErgGmBATvTAA4FTgJkBcEGYgZjgQFCgQFsgQFw
+2AAOBXcFhgWHBYgFiQWKBYsFjAZmBY4GZwWQBZEFkgZqgQE0gQFugQFvgQEwgQEygQFt0wAOBXcFeAV5
+Bm0GboEBOoEB4oEB418QEktlcmJlcm9zQWdlbnQgSGVscFE/WXNob3dIZWxwOtQADgVNBU4CZAVPAKQA
+pgZ2gQEpgDeARIEBcltuZXh0S2V5Vmlld9QADgVNBU4CZAXBAB8GewZ8gQFCgAKBAXSBAXfYAA4FdwWG
+BYcFiAWJBYoFiwWMBn8GFQaABZAFkQWSBgCBATSBAXWBAXaBATCBATKBAU9bSGlkZSBPdGhlcnNRaF8Q
+FmhpZGVPdGhlckFwcGxpY2F0aW9uczrUAA4FTQVOAmQFTwCmAKQGdoEBKYBEgDeBAXLTAA4FTgJkBcEG
+jgaPgQFCgQF6gQF82AAOBXcFhgWHBYgFiQWKBYsFjAaSBY4AWgWQBZEFkgXKgQE0gQF7gDuBATCBATKB
+AT5fEBJCcmluZyBBbGwgdG8gRnJvbnRfEA9hcnJhbmdlSW5Gcm9udDrUAA4FTQVOAmQFwQB8AyMGnYEB
+QoAQgLSBAX5fEBpzZWxlY3RQcmV2aW91c1RhYlZpZXdJdGVtOtQADgVNBU4CZAXBAHwAqAajgQFCgBCA
+YoEBgF8QFnNlbGVjdE5leHRUYWJWaWV3SXRlbTrTAA4FTgJkBcEGpwaogQFCgQGCgQGF2AAOBXcFhgWH
+BYgFiQWKBYsFjAarBY4GrAWQBZEFkgXggQE0gQGDgQGEgQEwgQEygQFFVVBhc3RlUXZWcGFzdGU60wAO
+BU4CZAXBBrUGtoEBQoEBh4EBitgADgV3BYYFhwWIBYkFigWLBYwGuQWOBroFkAWRBZIF4IEBNIEBiIEB
+iYEBMIEBMoEBRVRDb3B5UWNVY29weTrTAA4FTgJkBcEGwwbEgQFCgQGMgQGO2AAOBXcFhgWHBYgFiQWK
+BYsFjAbHBY4AWgWQBZEFkgXggQE0gQGNgDuBATCBATKBAUVWRGVsZXRlV2RlbGV0ZTrUAA4FTQVOAmQF
+wQAfBtEG0oEBQoACgQGQgQGS2AAOBXcFhgWHBYgFiQWKBYsFjAbVBY4GgAWQBZEFkgYAgQE0gQGRgQF2
+gQEwgQEygQFPXxASSGlkZSBLZXJiZXJvc0FnZW50VWhpZGU60wAOBU4CZAXBBt4G34EBQoEBlIEBl9gA
+DgV3BYYFhwWIBYkFigWLBYwG4gWOBuMFkAWRBZIF4IEBNIEBlYEBloEBMIEBMoEBRVNDdXRReFRjdXQ6
+1AAOBU0FTgJkBcEAHwbtBu6BAUKAAoEBmYEBm9gADgV3BYYFhwWIBYkFigWLBYwG8QWOAFoFkAWRBZIG
+AIEBNIEBmoA7gQEwgQEygQFPWFNob3cgQWxsXxAWdW5oaWRlQWxsQXBwbGljYXRpb25zOtQADgVNBU4C
+ZAXBAB8G+wb8gQFCgAKBAZ2BAaDYAA4FdwWGBYcFiAWJBYoFiwWMBv8FjgcABZAFkQWSBgCBATSBAZ6B
+AZ+BATCBATKBAU9fEBJRdWl0IEtlcmJlcm9zQWdlbnRRcVp0ZXJtaW5hdGU60wAOBU4CZAXBBwkHCoEB
+QoEBooEBpdgADgV3BYYFhwWIBYkFigWLBYwHDQWOBw4FkAWRBZIF4IEBNIEBo4EBpIEBMIEBMoEBRVRV
+bmRvUXpVdW5kbzrUAA4FTQVOAmQFTwVzAoYGDIEBKYEBK4CZgQFT0wAOBU4CZAXBBxwHHYEBQoEBqIEB
+q9gADgV3BYYFhwWIBYkFigWLBYwHIAWOByEFkAWRBZIF4IEBNIEBqYEBqoEBMIEBMoEBRVRSZWRvUVpV
+cmVkbzrUAA4FTQVOAmQFwQB8AoIGo4EBQoAQgIeBAYDTAA4FTgJkBcEHLwcwgQFCgQGugQGx2AAOBXcF
+hgWHBYgFiQWKBYsFjAczBY4HNAWQBZEFkgXKgQE0gQGvgQGwgQEwgQEygQE+WE1pbmltaXplUW1fEBNw
+ZXJmb3JtTWluaWF0dXJpemU61AAOBU0FTgJkBcEAfAKDBp2BAUKAEICLgQF+2AAOBU0HQQdCBU4CZAdD
+B0QHRQVRB0cHSAYfB0oHSwBgWU5TS2V5UGF0aFlOU0JpbmRpbmdZTlNPcHRpb25zXxAcTlNOaWJCaW5k
+aW5nQ29ubmVjdG9yVmVyc2lvboEBu4EBIIEBtoEBtYEBYYEBtIEBt18QI2NvbnRlbnRBcnJheTogc2Vs
+ZWN0aW9uLmNhY2hlc0FycmF5XGNvbnRlbnRBcnJheV8QFXNlbGVjdGlvbi5jYWNoZXNBcnJhedMADgdQ
+AEUHUQdSB1RXTlMua2V5c4EBuqEHU4EBuKEHVYEBuV8QG05TQ29uZGl0aW9uYWxseVNldHNFZGl0YWJs
+ZQjSADoAOwdZB1qiB1oAP1xOU0RpY3Rpb25hcnnSADoAOwdcB12jB10FcAA/XxAVTlNOaWJCaW5kaW5n
+Q29ubmVjdG9y2AAOBU0HQQdCBU4CZAdDB0QHRQYfB2EHYgQ9B2QHZQBggQG7gQFhgQG/gQG+gOiBAb2B
+AcBfEC92YWx1ZTogYXJyYW5nZWRPYmplY3RzLnNob3J0VGltZVJlbWFpbmluZ1N0cmluZ1V2YWx1ZV8Q
+KGFycmFuZ2VkT2JqZWN0cy5zaG9ydFRpbWVSZW1haW5pbmdTdHJpbmfTAA4HUABFB1EHawd4gQG6rAds
+B20HbgdvB3AHcQdyB3MHdAd1B3YHd4EBwYEBwoEBw4EBxIEBxYEBxoEBx4EByIEByYEByoEBy4EBzKwH
+VQdVB1UHVQd9B30HVQdVB30HfQdVB4SBAbmBAbmBAbmBAbmBAc2BAc2BAbmBAbmBAc2BAc2BAbmBAc5f
+EBpOU0NvbmRpdGlvbmFsbHlTZXRzRW5hYmxlZF8QHE5TUmFpc2VzRm9yTm90QXBwbGljYWJsZUtleXNf
+EBZOU1ZhbGlkYXRlc0ltbWVkaWF0ZWx5XxAmTlNBbHdheXNQcmVzZW50c0FwcGxpY2F0aW9uTW9kYWxB
+bGVydHNfEBtOU011bHRpcGxlVmFsdWVzUGxhY2Vob2xkZXJfEBFOU051bGxQbGFjZWhvbGRlcl8QGk5T
+Q29udGludW91c2x5VXBkYXRlc1ZhbHVlXxAXTlNDcmVhdGVzU29ydERlc2NyaXB0b3JfEBpOU05vdEFw
+cGxpY2FibGVQbGFjZWhvbGRlcl8QGE5TTm9TZWxlY3Rpb25QbGFjZWhvbGRlcl8QJk5TQWxsb3dzRWRp
+dGluZ011bHRpcGxlVmFsdWVzU2VsZWN0aW9uCdgADgVNB0EHQgVOAmQHQwdEB0UGHweUB0gGIAeXB5gA
+YIEBu4EBYYEB0YEBtYEBWoEB0IEB0l8QKGNvbnRlbnRBcnJheTogc2VsZWN0aW9uLmNyZWRlbnRpYWxz
+QXJyYXlfEBpzZWxlY3Rpb24uY3JlZGVudGlhbHNBcnJhedMADgdQAEUHUQedB5+BAbqhB1OBAbihB1WB
+AbnYAA4FTQdBB0IFTgJkB0MHRAdFBh8HpAdiBDwHpweoAGCBAbuBAWGBAdWBAb6A4IEB1IEB1l8QJnZh
+bHVlOiBhcnJhbmdlZE9iamVjdHMucHJpbmNpcGFsU3RyaW5nXxAfYXJyYW5nZWRPYmplY3RzLnByaW5j
+aXBhbFN0cmluZ9MADgdQAEUHUQetB7qBAbqsB2wHbQduB28HcAdxB3IHcwd0B3UHdgd3gQHBgQHCgQHD
+gQHEgQHFgQHGgQHHgQHIgQHJgQHKgQHLgQHMrAdVB1UHVQdVB30HfQdVB1UHfQd9B1UHhIEBuYEBuYEB
+uYEBuYEBzYEBzYEBuYEBuYEBzYEBzYEBuYEBztQADgVNB8gHyQfKA60HzAfNWE5TTWFya2VyVk5TRmls
+ZYEB2oEBCYEB2YEB2F8QEE5TVG9vbFRpcEhlbHBLZXlfEBFDcmVhdGUgYW4gYWNjb3VudNIAOgA7B9EH
+0qIH0gA/XxARTlNJQkhlbHBDb25uZWN0b3LUAA4FTQfIB8kHygOuB9YHzYEB2oEBEYEB3IEB2F8QEVJl
+bW92ZSBhbiBhY2NvdW500gAOAEUH2gfbgQIIrxB4BYIE6AfeBfgGAAZqBtEEAQKCAuoF6gLHB+gH6QOp
+B+sAVwK2AJEChgQ8AoEGpwWDA2AGIAOuAUwDIAaOB/oHHAD+B/0GtQTCCAADrQbeAKkC2gREA6wDKAMh
+AKgAngYQCAwDIwCVBNUAswBJAUIIEwPtCBUF4AbtA6oFBwKFBXMDqAWBBVEFygNRBcICowXYAKMDdAbD
+BGcCjACnBwkDPAQOAXkApQKDAmAD4wgyBK8DEgONBh8G+wMiCDkDqwZ7AjkDzAg+AKYGYgcvBD0DHwIQ
+AnMASAKEA6cDtAB8CEsCYQVQAKQA0gKAAwAIUgWEgQE1gQELgQHegQFOgQFPgQFtgQGQgNaAh4CWgQFK
+gI2BAeuBAe6A0oEB34ANgImAdoCZgOCAgoEBgoEBN4CxgQFagQERgGCAp4EBeoECA4EBqIBCgQHzgQGH
+gQECgQHygQEJgQGUgGmAkoDmgQEFgKSAq4BigBSBAVWBAeaAtIASgQEHgB+AwYA6gQH5gPGBAfeBAUWB
+AZmA+4EBE4CUgQErgM6BAS6BASCBAT6ArYEBPYCGgQFEgB6AtoEBjIDtgIGAOYEBooCqgNiARoAngIuA
+eoD1gQH9gP2AoIDGgQFhgQGdgK+BAeqBAQCBAXSAbYDQgQHngESBAWyBAa6A6ICigGSAfIAIgJCAyYDN
+gBCBAf6AnoEBJ4A3gCiAfoCbgQIGgQE42gAOCFUFdwWGBYcFiAWJBYoFiwGZBYwGaghYBY4AWgWQBZEF
+kgfrCF1ZTlNTdWJtZW51gQE0gQFtgQHggDuBATCBATKBAd+BAeHUAA4FdwETBXgFeQhgCGEIYoEBOoEB
+9YECBYEB9lRIZWxwXnN1Ym1lbnVBY3Rpb2460gAOADYANwhjgATSAA4ARQB6CGmAV6EGYoEBbNIADgBF
+AHoIbYBXqwX4CAwIPgg5B+gIAAbRBnsG7Qf9BvuBAU6BAeaBAeeBAeqBAeuBAfKBAZCBAXSBAZmBAfOB
+AZ3aAA4FdwWGBasFhwWsBYgFiQWKBYsFjABaBY4AjgBaAI4FkAWRBZIGAIEBNIA7CYA7CYEBMIEBMoEB
+T9gADgV3BYYFhwWIBYkFigWLBYwIhAWOCIUFkAWRBZIGAIEBNIEB6IEB6YEBMIEBMoEBT2wAUAByAGUA
+ZgBlAHIAZQBuAGMAZQBzICZRLNoADgV3BYYFqwWHBawFiAWJBYoFiwWMAFoFjgCOAFoAjgWQBZEFkgYA
+gQE0gDsJgDsJgQEwgQEygQFP2gAOCFUFdwWGBYcFiAWJBYoFiwGZBYwH6QiXBY4AWgWQBZEFkgYACJyB
+ATSBAe6BAeyAO4EBMIEBMoEBT4EB7VhTZXJ2aWNlc9QADgV3ARMFeAV5CKAIoQiigQE6gQHvgQHxgQHw
+0gAOADYANwidgATSAA4ARQB6CKeAV6BfEA9fTlNTZXJ2aWNlc01lbnXaAA4FdwWGBasFhwWsBYgFiQWK
+BYsFjABaBY4AjgBaAI4FkAWRBZIGAIEBNIA7CYA7CYEBMIEBMoEBT9oADgV3BYYFqwWHBawFiAWJBYoF
+iwWMAFoFjgCOAFoAjgWQBZEFkgYAgQE0gDsJgDsJgQEwgQEygQFPXF9OU0FwcGxlTWVudVhNYWluTWVu
+ddIADgBFAHoIv4BXpAgVCBMISwfegQH3gQH5gQH+gQHe2gAOCFUFdwWGBYcFiAWJBYoFiwGZBYwGAAYD
+BY4AWgWQBZEFkgfrCMyBATSBAU+BAeSAO4EBMIEBMoEB34EB+NoADghVBXcFhgWHBYgFiQWKBYsBmQWM
+BeAF4wWOAFoFkAWRBZIH6wjVgQE0gQFFgQH6gDuBATCBATKBAd+BAftURWRpdNIADgBFAHoI2YBXqQcJ
+BxwIMgbeBrUGpwYQBsMF2IEBooEBqIEB/YEBlIEBh4EBgoEBVYEBjIEBRNoADgV3BYYFqwWHBawFiAWJ
+BYoFiwWMAFoFjgCOAFoAjgWQBZEFkgXggQE0gDsJgDsJgQEwgQEygQFF2gAOCFUFdwWGBYcFiAWJBYoF
+iwGZBYwFygjvBY4AWgWQBZEFkgfrCPSBATSBAT6BAf+AO4EBMIEBMoEB34ECAFZXaW5kb3fSAA4ANgA3
+CPWABNIADgBFAHoI+oBXpQXCBy8F6gf6Bo6BAT2BAa6BAUqBAgOBAXraAA4FdwWGBasFhwWsBYgFiQWK
+BYsFjABaBY4AjgBaAI4FkAWRBZIFyoEBNIA7CYA7CYEBMIEBMoEBPl5fTlNXaW5kb3dzTWVudVtfTlNN
+YWluTWVuddIADgAyADMJDYAFgQIH0gA6ADsJDwHvogHvAD/SAA4ARQfaCRKBAgivEHgFcwOtB+sGAAgV
+B94GAAOpAnMChQXKAoMGAAfoA40AHwBIAoIAfAJzBAECcwXgBXMDIgAfA40ApwMSBcoFygXgAKUGAAXg
+A6sGAAONBeAAlQKEBDwDjQMfAxIAlQCVBeAGAAMSAJEDrACeAB8ApAfrA6kH6wgTBgADjQOuAnMAHwON
+BXMAHwhLAyEFygKBBeAAlQMjBeAEPQKAAJUF4AMgA6kApgCVAnMAfAOpBeADqgJhAEkAHwYAAxIGAAON
+BgAAqQOoBgAAlQZqBcoEAQMSAKgCYAAfAnMDjQOnAFcH6wB8AB8AlQCjAnMChgAfBXOBASuBAQmBAd+B
+AU+BAfeBAd6BAU+A0oB8gJSBAT6Ai4EBT4EB64DGgAKACICHgBCAfIDWgHyBAUWBASuAr4ACgMaAOYCg
+gQE+gQE+gQFFgCeBAU+BAUWBAQCBAU+AxoEBRYASgJCA4IDGgKKAoIASgBKBAUWBAU+AoIB2gQEFgBSA
+AoA3gQHfgNKBAd+BAfmBAU+AxoEBEYB8gAKAxoEBK4ACgQH+gKuBAT6AgoEBRYASgLSBAUWA6IB+gBKB
+AUWAp4DSgESAEoB8gBCA0oEBRYD7gJ6AwYACgQFPgKCBAU+AxoEBT4BpgM6BAU+AEoEBbYEBPoDWgKCA
+YoB6gAKAfIDGgMmADYEB34AQgAKAEoAegHyAmYACgQEr0gAOAEUH2gmNgQIIrxB5BYIE6AfeBfgGagYA
+BtEEAQKCAuoF6gLHB+gH6QOpB+sAVwK2AJEChgQ8AoEGpwWDA2AGIAOuAUwDIAaOB/oHHAD+B/0GtQTC
+A60IAAbeAKkC2gOsBEQAqACeAyEDKAYQCAwAlQMjBNUAswBJA+0IEwFCCBUF4AbtA6oFBwKFBXMFgQOo
+BVEFygNRBcICowXYAKMDdAbDBGcCjACnBwkDPAQOAKUCgwF5AmAD4wgyBK8DEgYfA40G+wMiCDkDqwZ7
+AjkDzAg+AKYGYgcvAB8EPQJzAoQASAMfAhADpwB8A7QISwJhBVAApADSAoADAAhSBYSBATWBAQuBAd6B
+AU6BAW2BAU+BAZCA1oCHgJaBAUqAjYEB64EB7oDSgQHfgA2AiYB2gJmA4ICCgQGCgQE3gLGBAVqBARGA
+YICngQF6gQIDgQGogEKBAfOBAYeBAQKBAQmBAfKBAZSAaYCSgQEFgOaAYoAUgKuApIEBVYEB5oASgLSB
+AQeAH4DBgPGBAfmAOoEB94EBRYEBmYD7gQETgJSBASuBAS6AzoEBIIEBPoCtgQE9gIaBAUSAHoC2gQGM
+gO2AgYA5gQGigKqA2IAngIuARoB6gPWBAf2A/YCggQFhgMaBAZ2Ar4EB6oEBAIEBdIBtgNCBAeeARIEB
+bIEBroACgOiAfICQgAiAooBkgMmAEIDNgQH+gJ6BASeAN4AogH6Am4ECBoEBONIADgBFB9oKCYECCK8Q
+eQoKCgsKDAoNCg4KDwoQChEKEgoTChQKFQoWChcKGAhgChoKGwocCh0KHgofCiAKIQoiCiMKJAolCiYK
+JwooCikKKgorCiwKLQouCi8KMAoxCjIKMwo0CjUKNgo3CjgKOQo6CjsKPAo9Cj4I7wpACkEKQgpDCkQK
+RQpGCkcKSApJCkoKSwpMCk0KTgpPClAKUQpSClMKVApVClYKVwpYClkKWgpbClwKXQpeCl8KYAphCmIK
+YwpkCmUKZgpnCmgKaQpqCmsKbAptCm4KbwpwCnEKcgpzCnQKdQp2CncKeAp5CnoKewVZCn0Kfgp/CoAK
+gQqCgQIMgQINgQIOgQIPgQIQgQIRgQISgQITgQIUgQIVgQIWgQIXgQIYgQIZgQIagQH1gQIbgQIcgQId
+gQIegQIfgQIggQIhgQIigQIjgQIkgQIlgQImgQIngQIogQIpgQIqgQIrgQIsgQItgQIugQIvgQIwgQIx
+gQIygQIzgQI0gQI1gQI2gQI3gQI4gQI5gQI6gQI7gQI8gQI9gQI+gQI/gQH/gQJAgQJBgQJCgQJDgQJE
+gQJFgQJGgQJHgQJIgQJJgQJKgQJLgQJMgQJNgQJOgQJPgQJQgQJRgQJSgQJTgQJUgQJVgQJWgQJXgQJY
+gQJZgQJagQJbgQJcgQJdgQJegQJfgQJggQJhgQJigQJjgQJkgQJlgQJmgQJngQJogQJpgQJqgQJrgQJs
+gQJtgQJugQJvgQJwgQJxgQJygQJzgQJ0gQJ1gQJ2gQJ3gQJ4gQJ5gQJ6gQJ7gQEjgQJ8gQJ9gQJ+gQJ/
+gQKAgQKBbxAcAE0AZQBuAHUAIABJAHQAZQBtACAAKABDAGgAYQBuAGcAZQAgAFAAYQBzAHMAdwBvAHIA
+ZCAmAClfEBFCdXR0b24gQ2VsbCAoQWRkKV8QEE1lbnUgSXRlbSAoSGVscClfEB9NZW51IEl0ZW0gKEFi
+b3V0IEtlcmJlcm9zQWdlbnQpW01lbnUgKEhlbHApXxAUTWVudSAoS2VyYmVyb3NBZ2VudClfEB5NZW51
+IEl0ZW0gKEhpZGUgS2VyYmVyb3NBZ2VudClfECVUYWJsZSBWaWV3IChJZGVudGl0eSwgVGltZSBSZW1h
+aW5pbmcpXxAYUHVzaCBCdXR0b24gKENvbnRpbnVlKS0xXxBCVGV4dCBGaWVsZCBDZWxsIChNYWlsIHdh
+bnRzIHRvIGNvbm5lY3QgdG8gdGhlIGFjY291bnQgbHhzQG1pdC5lZHUpXxAQTWVudSBJdGVtIChab29t
+KV8QFUJ1dHRvbiBDZWxsIChHbyBCYWNrKV8QFE1lbnUgSXRlbSAoU2VydmljZXMpXxAPTWVudSAoU2Vy
+dmljZXMpW1Njcm9sbCBWaWV3XkNvbnRlbnQgVmlldy0xXxAYQnV0dG9uIENlbGwgKENvbnRpbnVlKS0x
+XxAfVGFiIFZpZXcgSXRlbSAoU2VsZWN0IElkZW50aXR5KV8QFVBvcHVwIEJ1dHRvbiAoR2VhciktMV8Q
+F1RhYmxlIENvbHVtbiAoSWRlbnRpdHkpXxARU2VjdXJlIFRleHQgRmllbGRfEBFNZW51IEl0ZW0gKFBh
+c3RlKVlTZXBhcmF0b3JfEF1UZXh0IEZpZWxkIENlbGwgKENvbmdyYXR1bGF0aW9ucyEgWW91IGhhdmUg
+YWNxdWlyZWQgS2VyYmVyb3MgdGlja2V0cyBmb3IgbHhzQEFUSEVOQS5NSVQuRURVLilfEBVDcmVkZW50
+aWFsc0NvbnRyb2xsZXJfEBZTcXVhcmUgQnV0dG9uIChSZW1vdmUpXxAYVGV4dCBGaWVsZCBDZWxsIChS
+ZWFsbTopXxAcSW1hZ2UgVmlldyAoS2VyYmVyb3NBZ2VudCktM18QHk1lbnUgSXRlbSAoQnJpbmcgQWxs
+IHRvIEZyb250KVtTZXBhcmF0b3ItNl8QEE1lbnUgSXRlbSAoUmVkbylfEBdUZXh0IEZpZWxkIENlbGwg
+KE5hbWU6KVtTZXBhcmF0b3ItMl8QEE1lbnUgSXRlbSAoQ29weSlfEBRCdXR0b24gQ2VsbCAoQ2FuY2Vs
+KV8QE1NxdWFyZSBCdXR0b24gKEFkZClbU2VwYXJhdG9yLTNfEA9NZW51IEl0ZW0gKEN1dClfEBNQb3B1
+cCBCdXR0b24gKEdlYXIpXxA1VGV4dCBGaWVsZCBDZWxsIChQbGVhc2UgZW50ZXIgeW91ciBLZXJiZXJv
+cyBwYXNzd29yZClfED9TdGF0aWMgVGV4dCAoTWFpbCByZXF1aXJlcyB0aGF0IHlvdSBjaG9vc2UgYSBL
+ZXJiZXJvcyBJZGVudGl0eSlfEBtUZXh0IEZpZWxkIENlbGwgKFRleHQgQ2VsbClfEBZQdXNoIEJ1dHRv
+biAoQ29udGludWUpXxAcSW1hZ2UgVmlldyAoS2VyYmVyb3NBZ2VudCktMV8QGFN0YXRpYyBUZXh0IChD
+b25jbHVzaW9uKV8QEkJ1dHRvbiBDZWxsIChEb25lKV8QIU1lbnUgSXRlbSAoUGFzdGUgYW5kIE1hdGNo
+IFN0eWxlKVtTZXBhcmF0b3ItNF8QF1B1c2ggQnV0dG9uIChHbyBCYWNrKS0xXxBDVGV4dCBGaWVsZCBD
+ZWxsIChNYWlsIHJlcXVpcmVzIHRoYXQgeW91IGNob29zZSBhIEtlcmJlcm9zIElkZW50aXR5KV8QHElt
+YWdlIENlbGwgKEtlcmJlcm9zQWdlbnQpLTFfEBFWZXJ0aWNhbCBTY3JvbGxlcl8QEE1lbnUgSXRlbSAo
+RWRpdClfEA9UZXh0IEZpZWxkIENlbGxfEBlNZW51IEl0ZW0gKEtlcmJlcm9zQWdlbnQpW01lbnUgKEVk
+aXQpXxAUTWVudSBJdGVtIChTaG93IEFsbClfEBRQdXNoIEJ1dHRvbiAoQ2hvb3NlKV8QFEJ1dHRvbiBD
+ZWxsIChSZW1vdmUpXxA+U3RhdGljIFRleHQgKE1haWwgd2FudHMgdG8gY29ubmVjdCB0byB0aGUgYWNj
+b3VudCBseHNAbWl0LmVkdSlYR2Vhck1lbnVvEBsATQBlAG4AdQAgAEkAdABlAG0AIAAoAFQAaQBjAGsA
+ZQB0ACAATwBwAHQAaQBvAG4AcyAmAClfEDNTdGF0aWMgVGV4dCAoQ2hlY2tpbmcgbWFpbCBmb3IgYWNj
+b3VudCBseHNAbWl0LmVkdSlfEBlDYWNoZUNvbGxlY3Rpb25Db250cm9sbGVyXU1lbnUgKFdpbmRvdylf
+EBxUZXh0IEZpZWxkIENlbGwgKENvbmNsdXNpb24pXxARTWVudSBJdGVtIChDbG9zZSlfEBFUZXh0IEZp
+ZWxkIENlbGwtMV8QFk1lbnUgSXRlbSAoU2VsZWN0IEFsbClfEDFTdGF0aWMgVGV4dCAoUGxlYXNlIGVu
+dGVyIHlvdXIgS2VyYmVyb3MgaWRlbnRpdHkpXxAXQnV0dG9uIENlbGwgKEdvIEJhY2spLTFfEBJNZW51
+IEl0ZW0gKERlbGV0ZSlfEB1UZXh0IEZpZWxkIENlbGwgKFRleHQgQ2VsbCktMV8QHEltYWdlIENlbGwg
+KEtlcmJlcm9zQWdlbnQpLTJfEBRTdGF0aWMgVGV4dCAoUmVhbG06KV8QEE1lbnUgSXRlbSAoVW5kbylf
+EBxJbWFnZSBDZWxsIChLZXJiZXJvc0FnZW50KS0zXxARVGFibGUgSGVhZGVyIFZpZXdfEBNTdGF0aWMg
+VGV4dCAoTmFtZTopXxAVUHVzaCBCdXR0b24gKEdvIEJhY2spXkNvbWJvIEJveCBDZWxsXxAqVGFiIFZp
+ZXcgSXRlbSAoQXV0aGVudGljYXRpb24gSW5mb3JtYXRpb24pXxATSG9yaXpvbnRhbCBTY3JvbGxlcltT
+ZXBhcmF0b3ItMV8QFEJ1dHRvbiBDZWxsIChDaG9vc2UpVlZpZXctMl8QEENhY2hlc0NvbnRyb2xsZXJc
+Q29udGVudCBWaWV3XxAeTWVudSBJdGVtIChRdWl0IEtlcmJlcm9zQWdlbnQpXxBZU3RhdGljIFRleHQg
+KENvbmdyYXR1bGF0aW9ucyEgWW91IGhhdmUgYWNxdWlyZWQgS2VyYmVyb3MgdGlja2V0cyBmb3IgbHhz
+QEFUSEVOQS5NSVQuRURVLilbU2VwYXJhdG9yLTVfEBRQdXNoIEJ1dHRvbiAoQ2FuY2VsKV8QF01lbnUg
+SXRlbSAoSGlkZSBPdGhlcnMpXxASQnV0dG9uIENlbGwgKEdlYXIpXxA3VGV4dCBGaWVsZCBDZWxsIChD
+aGVja2luZyBtYWlsIGZvciBhY2NvdW50IGx4c0BtaXQuZWR1KW8QGABNAGUAbgB1ACAASQB0AGUAbQAg
+ACgAUAByAGUAZgBlAHIAZQBuAGMAZQBzICYAKVlDb21ibyBCb3hfEB5NZW51IEl0ZW0gKEtlcmJlcm9z
+QWdlbnQgSGVscClfEBRNZW51IEl0ZW0gKE1pbmltaXplKVxGaWxlJ3MgT3duZXJfEB1UYWJsZSBDb2x1
+bW4gKFRpbWUgUmVtYWluaW5nKVZWaWV3LTFfEDFTdGF0aWMgVGV4dCAoUGxlYXNlIGVudGVyIHlvdXIg
+S2VyYmVyb3MgcGFzc3dvcmQpV1dpbmRvdzFfEBJQdXNoIEJ1dHRvbiAoRG9uZSlfEBZCdXR0b24gQ2Vs
+bCAoQ29udGludWUpXxAaSW1hZ2UgVmlldyAoS2VyYmVyb3NBZ2VudClfEEhObyBTaGFkb3cgVGFiIFZp
+ZXcgKFNlbGVjdCBJZGVudGl0eSwgQXV0aGVudGljYXRpb24gSW5mb3JtYXRpb24sIFJlc3VsdClfEBpJ
+bWFnZSBDZWxsIChLZXJiZXJvc0FnZW50KV8QEk1lbnUgSXRlbSAoV2luZG93KV8QFlRhYiBWaWV3IEl0
+ZW0gKFJlc3VsdClaVGV4dCBGaWVsZF8QNVRleHQgRmllbGQgQ2VsbCAoUGxlYXNlIGVudGVyIHlvdXIg
+S2VyYmVyb3MgaWRlbnRpdHkpXxAcSW1hZ2UgVmlldyAoS2VyYmVyb3NBZ2VudCktMl8QFEJ1dHRvbiBD
+ZWxsIChHZWFyKS0xW0FwcGxpY2F0aW9uXxAdTWVudSBJdGVtIChBYm91dCBLZXJiZXJvcy4uLinSAA4A
+RQfaCvqBAgijAoYCgQCpgJmAgoBp0gAOAEUH2gsAgQIIowI9AqYCPYBqgIOAatIADgBFB9oLBoECCK8Q
+ngWCBOgFPQfeBUUF+AYABmoG0QQBAoIC6gXqAscH6AVGB+kFLQVLBT8DqQfrBUoAVwK2BUAAkQKGBDwC
+gQUyBqcFgwNgBiADrgFMAyAFNwUuBTkGjgVDB/oHHAD+BTYH/Qa1BMIIAAOtBt4AqQLaBTEERAOsAygD
+IQCoAJ4FMAU8BUkFOwYQCAwDIwCVBNUFJwCzBTgASQFCCBMD7QgVBeAG7QOqBQcChQVzA6gFgQVRBcoD
+UQVEBcICowXYAKMDdAUrBsMFKQRnAowFMwU+AKcHCQM8BA4BeQClAoMCYAPjBSwIMgSvBS8DEgU0A40G
+Hwb7AyIIOQUqBUgDqwZ7AjkDzAg+AKYFQgVHBTUGYgcvAB8EPQMfAhAASAJzAoQFQQOnA7QAfAU6CEsC
+YQVQAKQA0gKAAwAIUgUoBYSBATWBAQuBAZOBAd6BAbKBAU6BAU+BAW2BAZCA1oCHgJaBAUqAjYEB64EB
+s4EB7oEBUoEB24EBnIDSgQHfgQHXgA2AiYEBoYB2gJmA4ICCgQFrgQGCgQE3gLGBAVqBARGAYICngQF9
+gQFUgQGBgQF6gQGsgQIDgQGogEKBAXmBAfOBAYeBAQKBAfKBAQmBAZSAaYCSgQFqgOaBAQWApICrgGKA
+FIEBaIEBj4EB04EBi4EBVYEB5oC0gBKBAQeBAR+AH4EBf4DBgDqBAfmA8YEB94EBRYEBmYD7gQETgJSB
+ASuAzoEBLoEBIIEBPoCtgQGtgQE9gIaBAUSAHoC2gQFJgQGMgQE8gO2AgYEBcYEBmIA5gQGigKqA2IBG
+gCeAi4B6gPWBAU2BAf2A/YEBWYCggQFzgMaBAWGBAZ2Ar4EB6oEBQ4EBz4EBAIEBdIBtgNCBAeeARIEB
+p4EBvIEBeIEBbIEBroACgOiAooBkgAiAfICQgQGmgMmAzYAQgQGGgQH+gJ6BASeAN4AogH6Am4ECBoEB
+KoEBONIADgBFB9oLp4ECCK8QnguoC6kLqgurC6wLrQuuC68LsAuxC7ILswu0C7ULtgu3C7gLuQu6C7sL
+vAu9C74LvwvAC8ELwgvDC8QLxQvGC8cLyAvJC8oLywvMC80LzgvPC9AL0QvSC9ML1AvVC9YL1wvYC9kL
+2gvbC9wL3QveC98L4AvhC+IL4wvkC+UL5gvnC+gL6QvqC+sL7AvtC+4L7wvwC/EL8gvzC/QL9Qv2C/cL
++Av5C/oL+wv8C/0L/gv/DAAMAQwCDAMMBAwFDAYMBwwIDAkMCgwLDAwMDQwODA8MEAwRDBIMEwwUDBUM
+FgwXDBgMGQwaDBsMHAwdDB4MHwwgDCEMIgwjDCQMJQwmDCcMKAwpDCoMKwwsDC0MLgwvDDAMMQwyDDMM
+NAw1DDYMNww4DDkMOgw7DDwMPQw+DD8MQAxBDEIMQwxEDEWBAoaBAoeBAoiBAomBAoqBAouBAoyBAo2B
+Ao6BAo+BApCBApGBApKBApOBApSBApWBApaBApeBApiBApmBApqBApuBApyBAp2BAp6BAp+BAqCBAqGB
+AqKBAqOBAqSBAqWBAqaBAqeBAqiBAqmBAqqBAquBAqyBAq2BAq6BAq+BArCBArGBArKBArOBArSBArWB
+AraBAreBAriBArmBArqBAruBAryBAr2BAr6BAr+BAsCBAsGBAsKBAsOBAsSBAsWBAsaBAseBAsiBAsmB
+AsqBAsuBAsyBAs2BAs6BAs+BAtCBAtGBAtKBAtOBAtSBAtWBAtaBAteBAtiBAtmBAtqBAtuBAtyBAt2B
+At6BAt+BAuCBAuGBAuKBAuOBAuSBAuWBAuaBAueBAuiBAumBAuqBAuuBAuyBAu2BAu6BAu+BAvCBAvGB
+AvKBAvOBAvSBAvWBAvaBAveBAviBAvmBAvqBAvuBAvyBAv2BAv6BAv+BAwCBAwGBAwKBAwOBAwSBAwWB
+AwaBAweBAwiBAwmBAwqBAwuBAwyBAw2BAw6BAw+BAxCBAxGBAxKBAxOBAxSBAxWBAxaBAxeBAxiBAxmB
+AxqBAxuBAxyBAx2BAx6BAx+BAyCBAyGBAyKBAyMSAASVgxIABJWcEK8QZxIABJV7EDoQORBqEIYSAASV
+PBIABJVQEgAElVgQyxIABJVWEIMRAUEQghIABJWGEgAElaAQixIABJU0EB0SAASVnxIABJVGEgAElVUQ
+tBIABJVJEgAElUwSAASVPhIABJVREHoQqxIABJWEEgAElXQRAUISAASVnRIABJVoEgAElW8SAASVdxDT
+ELASAASVehDpEK0SAASVZhAnEJUQnRIABJVCEJASAASVmxCgEgAElVsSAASVVxIABJWJEgAElT8SAASV
+lRIABJVxEgAElW4SAASVXBIABJViEgAElUQQmBIABJV9EMkQ0hDKEgAElWwSAASVWhIABJWWEQEYEgAE
+lWMSAASVeRIABJUvEgAElWUQoxIABJU7EDgQqRCWEgAElTMSAASVnhIABJVNEgAElYESAASVNRIABJWC
+EQEGEBgSAASVcxDrEBcSAASVVBCsEgAElWESAASVdRDMEKQQ9hIABJVAEgAElVMSAASVdhCZEgAElV0Q
+nhIABJVyEgAElTkSAASVZxIABJVfEgAElU8SAASVShIABJU6EI4QnBIABJVBEQFDEgAElWsQkhIABJUw
+EQE2EIgSAASVbRCPELMRAUYSAASVMhCREgAElWoSAASVOBCBEgAElV4QshIABJV/EgAElXgQbxDqEgAE
+lT0SAASVcBIABJVpEgAElUUSAASVSxIABJVOEgAElYcSAASVNhIABJU3EgAElUcQtRATEgAElUgRARcS
+AASVYBIABJVkEgAElVISAASVWRP//////////RIABJWIEgAElYXSAA4ARQB6DOSAV6DSAA4ARQfaDOeB
+Agig0gAOAEUH2gzqgQIIoNIAOgA7DOwM7aIM7QA/Xk5TSUJPYmplY3REYXRhAAgAGQAiACcAMQA6AD8A
+RABSAFQAZga6BsAHCwcSBxkHJwc5B1UHYwdvB3sHiQeUB6IHvgfMB98H8QgLCBUIIggkCCcIKggtCDAI
+Mwg2CDgIOwg+CEEIRAhGCEgISwhOCFMIVghfCGsIbQhvCHgIggiECJIImwikCK8ItgjICNEI2gjjCOgI
+9wkKCRMJHgkgCSUJJwkpCV4Jawl4CY4JnAmmCbQJwQnLCd0J8Qn7CgcKCQoLCg0KDwoRChYKGAoaChwK
+HgogCiIKJAo/CloKYwplCm4Kdwp5Cn4KmwqtCrgKwQrNCtkK2wrdCt8K4grkCuYK6ArxCvMK9gr4Cy0L
+PAtGC04LVQtpC4ILmgucC54LoAuiC6QLpguoC6sLrQuuC7ALsQuzC7wLvgvBC8ML5AvyC/QL9gv4C/oL
+/Av+DAAMCQwLDBwMHgwgDCIMJAwmDCgMKgwsDFkMZAxrDHcMgQyDDIUMhwyIDIoMjAyPDJAMkgyUDJYM
+nwyhDK4MsAyyDLQMtgy4DLoM1gzyDSYNPg1fDXwNhQ2MDZkNnw23DdwN3g3gDeIN5A3nDegN6g3sDe4O
+Dw4bDiMOLg42Dj4OSw5WDlsOXQ5fDmEOZg5nDnQOgw6FDocOiQ6RDp8OqA6tDsAOyQ7QDtwO5Q7wDvwP
+Bg8NDxkPMg9XD1kPWw9dD18PYA9iD2QPZg+HD5sPpQ+zD78PxA/GD8gPyg/MD84P0w/VD/sQDBATEBoQ
+IxAlEC4QMBAzEEAQSRBOEGMQaxB4EIQQkhCUEJYQmBCaEKEQrhC7EMMQxRDHENMQ3BDhEPYQ+BD6EPwQ
+/hERER4RIBEjESwRNRFHEVQRXRFoEXQRmRGbEZ0RnxGhEaIRpBGmEagRwBHlEecR6RHrEe0R7hHwEfIR
+9BIZEiISJBImEigSKhIsEjESMhI0EjUSShJMEk4SUBJSEmgSdRJ3EnoSjxKREpMSlRKXEqESuBLZEtsS
+3RLfEuES4xLoEuoS8BMRExMTFRMXExkTGhMcEx4TNhNrE3YTixOXE68TsRO2E7gTuhO8E74TwBPBE8MT
+xRPGE8gT0RPTFC4UNxRZFG4UiBSkFL8UzBTVFOEVABUPFRsVHRUfFSEVKhUsFS4VLxU4FToVQxVFFUcV
+SBVKFUwVThVQFVIVVBVdFWUVbhVwFXMVdRWeFa0VuhXHFc8V2hXpFfQV/xYAFgIWBBYGFg8WERYaFiMW
+JRZCFkcWSRZLFk0WTxZRFmIWZBZmFmgWdRZ3FoMWjBaXFqsWzBbRFtMW1RbXFtkW3BbdFt8W9Bb2FvgW
++hb8FxUXHhcjFzEXOhdBF1AXWBdtF28XcRdzF3UXfxeMF44XkxemF68XvBfPF9gX4xfyF/sYCBgTGCoY
+SxhNGE8YURhTGFUYVxheGIMYhRiHGIkYixiOGI8YkRiTGJUYrRjiGPgZDRkcGS8ZQRlTGWEZYxllGWcZ
+aRlrGW0ZbxlxGXMZeBmBGYoZkxmVGZ4Zpxm0Gb0ZyBnRGfoaEBoSGhQaFhoYGhoaHRoeGiAaIhokGjAa
+Rxp8GooajBqOGpAakhqUGpYamBqaGp0aphq3GrkauxrIGsoazBrOGtMa3BrhGvAa+xsEGwsbIxssGy4b
+NRs3GzkbOxtUG14bZhtoG2obbBtuG3Abcht0G4YbjxuUG6Ibuxu9G78bwRvDG8UbxxvJG94b4BviG+Qb
+5hvvG/EcABwCHAQcBhwIHAocDBwOHDMcNRw3HDkcOhw8HD4cPxxBHEocTBxZHFscXRxfHGEcYxxlHH0c
+nhygHKIcoxzIHMoczBzOHNAc0hzVHNYc2BzaHO4dBh0rHS0dLx0xHTMdNR02HTgdVR1XHVkdWx1dHV4d
+YB2VHZcdmR2bHZ0dnx2hHaMdrB2uHcsdzR3PHdEd0x3UHdYd7h4jHiUeJx4pHiseLR4vHjEeOR5CHkQe
+YR5jHmUeZx5pHmoebB6FHqYeqB6qHqwerh6wHrIe2B71Hvce+R77Hv0e/h8AHxgfOR87Hz0fPx9BH0Mf
+RR94H4kfix+UH5YfmR++H8Afwh/EH8YfyB/JH8sfzR/kIBkgGyAdIB8gISAjICUgJyAwIE0gZiBoIGog
+bCBuIHAgciB0IIkgiyCNII8gkSCaIJwgpyCpIKsgrSCvILEgziDQINIg1CDWINcg2SDxISYhKCEqISwh
+LiEwITIhNCE5IUIhRCFpIWshbSFvIXAhciF0IXUhdyGAIYIhjyGRIZMhlSGXIZkhmyG8Ib4hwCHBId4h
+4CHiIeQh5iHnIekiCiIMIg4iECISIhQiFiIhIj4iQCJCIkQiRiJHIkkiYSKCIoQihiKIIooijCKRIpMi
+4SLuIvAi/iMbIx0jHyMhIyMjJCMmIz4jcyN1I3cjeSN7I30jfyOBI4ojjCOTI5wjpSOwI8kj1yPsI/Uj
++iQNJEIkRCRGJEkkSyRNJE8kUSRUJFckWSR0JJEkmiScJKUkpyTEJMYkyCTKJM0kzyTSJNsk3STuJPAk
+8iT0JPYk+ST8JP8lAiUrJS0lLyUxJTIlNCU2JTclOSU7JUQlRiVTJVUlVyVZJVslXSVfJXclmCWdJZ8l
+oSWiJcMlxSXHJcklyyXMJc4l0CXpJgomDCYOJhAmEiYUJhkmGyZDJnwmiCaRJp4msSa+Jsom2CbaJtwm
+3ibgJuMm5SbnJukm/Cb+JwAnAicEJw0nDycaJxwnHicgJyInJCdNJ1cnYSdrJ20nbydxJ3MndSd4J3on
+fCd+J4AniSeLJ44nkCfjJ/An8if0J/kn+yf9J/4oACgCKAMoBSgHKAkoCygUKB8oPCg+KEAoQihEKEYo
+SChxKHModSh3KHkoeyh9KH8ogSiLKJQonSixKMoozCjOKNAo2SjbKN0o9Cj9KQYpFCkdKR8pJCkmKSgp
+USleKV8pYSljKWwpbil3KXgpeimXKZkpmymdKZ8poSmqKbcpuSnOKdAp0inUKdYp6CoNKhIqFCoWKhgq
+GiocKiEqIiokKi4qVypYKloqXCplKmcqcCp5KnoqfCqZKpsqnSqfKqEqpiqoKrcqzCrOKtAq0irUKuAr
+ASsGKwgrCisMKw4rECsVKxcrICsrK0MrTCtVK2ArhSuPK5ErkyuVK5crmSubK50rpiu/K8wr1SvgK+ss
+FCwWLBgsGiwcLB4sICwiLCssQyxMLE4sUSxTLGksgiyLLJQsoSzCLMQsxizILMosyyzNLM8s5y0cLR4t
+IC0iLSQtJi0oLSotMS0zLVQtVi1YLVstXi1fLWEtYy17LbAtsi20LbYtuS28Lb4twS3ILcot6y3tLe8t
+8i31Lfgt+S37Lf0uFi43LjkuOy4+LkAuQy5ILkoufi6fLqEuoy6mLqkuqi6sLq4uxS7+LwAvAi8FLwgv
+Cy8NLw8vEi8XLyQvJi8oLysvLy88Lz4vQC9DL08vWC9aL3svfS9/L4IvhS+GL4gvii+hL9ov3C/eL+Ev
+5C/nL+kv6y/uL/sv/S//MAIwCTAWMBgwGjAdMCwwNTA3MEIwTTBqMHMwdTDCMMUwyDDLMM4w0TDUMNcw
+2jDdMOAw4zDmMOkw7DDvMPIw9TD4MPsw/jEBMQQxBzEKMQ0xEDETMRYxGTEcMR8xIjElMSgxKzEuMTEx
+QjFQMVkxXDFfMWIxZTF2MYgxnDGrMa4xsTG0MbcxwDHCMcUxyDHUMe4x8zH2Mf8yBDINMhQyKTI2Mj8y
+QTJEMkwyVTJcMnMygjKTMpYymTKbMp4yrzK3MsMyxjLJMssyzjLTMtwy3jLnMuoy7TLwMvMzFDMoMzMz
+QTNLM1gzXzNiM2UzajNsM3EzdDN3M3ozmzOoM6ozrDOvM8EzzjPQM9Iz1TPoM/Ez9jQBNCI0JTQoNCo0
+LTQwNDM0VjR/NI00mjSdNJ80oDSiNKM0pjSpNKw0zTTQNNM01TTYNNs03jTyNPs1ADUFNRI1FTUYNRs1
+PDU/NUI1RTVINUs1TjVfNWI1ZTVoNWs1cTVzNYE1ijWRNak1tjW5Nbw1vzXgNeM15jXpNew17zXyNf82
+AjYFNgg2EzYVNiA2LTYwNjM2NjZXNlo2XTZfNmI2ZTZoNm02ejaLNo42kDaTNpY2sza2Nrk2uza+NsE2
+xDbVNtg22zbeNuE29zcXNyg3KzcuNzA3Mzc9N0o3TTdQN1M3dDd3N3o3fzeCN4U3iDeLN6M3pTe5N8o3
+zTfQN9M31jf/OBw4MzhYOHM4jDiNOJA4kTiUOJU4mDibOJw4nTieOKc4qTiuOLE4tDjNOOg4/TkCOQU5
+DjkXOSs5UDlROVQ5VTlYOVs5XjlfOWA5YTlqOWw5dTl4OXs5fjmBOZQ5pjm8Oco5zznSOeM55jnoOes5
+7jn/OgI6BToHOgo6FzoaOh06IDpBOkQ6RzpKOk06UDpTOmA6YzpmOmk6fjqAOoo6mzqeOqA6ojqlOrE6
+wjrFOsc6yjrNOu468Tr0Ovc6+jr9OwA7DDsOOyc7ODs7Oz07PztCO087UjtVO1g7eTt8O387gTuEO4c7
+ijufO7E7wjvFO8c7yTvMO+k7+jv9O/88ATwEPB08KjwtPDA8MzxUPFc8WjxdPGA8YzxmPGw8bjx1PII8
+hTyIPIs8rDyvPLI8tTy4PLs8vjzDPMU8yzzYPNs83jzhPQI9BT0IPQo9DT0QPRM9Gj0iPTM9Nj04PTs9
+Pj1fPWI9ZT1oPWs9bj1xPYY9jD2ZPZw9nz2iPcM9xj3JPcw9zz3SPdU92T3bPeA98T30PfY9+T38Ph0+
+ID4jPiU+KD4rPi4+Nz5QPmE+ZD5mPmk+bD6NPpA+kz6WPpk+nD6fPrQ+tj7BPs4+0T7UPtc++D77Pv4/
+AT8EPwc/Cj8PPxE/Fz8oPys/Lj8wPzM/QD9DP0Y/ST9qP20/cD9zP3Y/eT98P4E/gz+JP5o/nT+fP6E/
+pD+xP7Q/tz+6P9s/3j/hP+Q/5z/qP+0/9j/4QA5AH0AiQCRAJkApQEpAVEBeQGhAh0CKQI1AkECTQJZA
+mUCcQMJAz0DnQPRA/ED/QQJBBUEIQQtBKUEqQTNBOEFFQU5BVUFtQY5BkUGUQZdBmkGcQZ9BokHUQdpC
+BUISQhVCLkIxQjRCN0I6Qj1CQEJDQkZCSUJMQk9CUkJrQm5CcUJ0QndCekJ9QoBCg0KGQolCjEKPQqxC
+y0LkQw1DK0M/Q1xDdkOTQ65D10PYQ/lD/EP/RAJEBUQIRAtEDkQ5RFZEY0RmRGlEbERvRHJEk0SWRJlE
+nESfRKFEpESnRNBE8kT/RQJFG0UeRSFFJEUnRSpFLUUwRTNFNkU5RTxFP0VYRVtFXkVhRWRFZ0VqRW1F
+cEVzRXZFeUV8RY1FlkWdRaBFo0WmRalFvEXQRdlF3kXyRgNGBkYJRgxGD0YjRixGL0ciRyVHKEcrRy5H
+MUc0RzdHOUc7Rz1HQEdCR0VHSEdKR01HT0dRR1NHVUdXR1lHXEdfR2FHZEdnR2lHa0duR3FHdEd2R3lH
+fEd/R4JHhUeIR4pHjEeOR5FHk0eVR5dHmUecR59HoUejR6ZHqEeqR6xHr0exR7RHt0e6R7xHv0fBR8RH
+xkfJR8xHz0fRR9RH1kfZR9tH3UfgR+JH5EfmR+lH60ftR+9H8UfzR/VH90f6R/xH/kgASANIBkgISAtI
+DkgRSBNIFUgYSBpIHUggSCJIJEgmSChIKkgsSC5IMEgySDVIN0g6SDxIPkhASEJIRUhISHFIe0h+SIFI
+hEiGSIlIjEiPSJJIo0imSKlIrEivSLRIw0jMSM5I10jZSNxI30joSOpJAUkESQdJCkkNSRBJE0kWSRlJ
+HEkfSSJJS0lOSVBJUUlTSVRJV0laSV1JfkmBSYRJh0mKSY1JkEmpSatJ1EnXSdlJ2kncSd1J4EnjSeZK
+D0oSShVKGEoaSh1KIEojSiZKL0pASkNKRkpJSkxKVUpXSmBKYkpjSnVKnkqhSqNKpEqmSqdKqkqtSrBK
+2UrcSt5K30rhSuJK5UroSutK+EsBSwpLDEsVSxhLG0seSyFLSktNS1BLU0tVS1hLW0teS2FLikuNS5BL
+k0uVS5hLm0ueS6FLpkuvS7FLxEvHS8pLzUvQS9NL1kvZS9xL30wITAtMDUwOTBBMEUwUTBdMGkxDTEZM
+SUxMTE5MUUxUTFdMWkxhTGpMbEx1THdMgkyFTIhMi0yOTJFMuky9TL9MwEzCTMNMxkzJTMxM20znTPBM
+8kz1TP5NA00MTQ9OAk4FTghOC04OThFOFE4XThlOG04dTiBOIk4lTihOKk4sTi5OME4yTjRONk44TjtO
+Pk5ATkJORE5GTkhOS05OTlFOU05WTllOXE5fTmFOZE5mTmhOak5sTm5OcE5yTnROd056TnxOfk6BToNO
+hU6HTopOjE6PTpJOlU6XTppOnE6eTqBOo06lTqhOqk6tTq9Osk60TrZOuU67Tr1Ov07CTsROxk7ITspO
+zE7OTtBO007VTtdO2U7bTt5O4E7jTuVO6E7qTuxO707xTvRO9075TvtO/U7/TwFPA08FTwdPCU8MTw5P
+EE8STxRPFk8YTxpPHU8mTylQHlAhUCRQJ1AqUC1QMFAzUDVQN1A5UDxQPlBBUERQRlBJUEtQTVBPUFFQ
+U1BVUFhQW1BdUGBQY1BlUGdQalBtUHBQclB1UHhQe1B+UIFQhFCGUIhQi1CNUI9QkVCTUJVQmFCbUJ1Q
+n1CiUKRQplCoUKtQrVCwULNQtlC4ULtQvVDAUMNQxVDIUMtQzVDQUNJQ1VDXUNlQ3FDeUOBQ4lDlUOdQ
+6VDrUO1Q71DxUPNQ9lD4UPpQ/VD/UQJRBFEHUQpRDVEPURFRFFEWURlRHFEeUSBRIlEkUSZRKFEqUSxR
+LlEwUTNRNVE4UTpRPFE+UUBRQ1FGUU9RUlJHUkpSTVJQUlNSVlJZUlxSX1JiUmVSaFJrUm5ScVJ0UndS
+elJ9UoBSg1KGUolSjFKPUpJSlVKYUptSnlKhUqRSp1KqUq1SsFKzUrZSuVK8Ur9SwlLFUshSy1LOUtFS
+1FLXUtpS3VLgUuNS5lLpUuxS71LyUvVS+FL7Uv5TAVMEUwdTClMNUxBTE1MWUxlTHFMfUyJTJVMoUytT
+LlMxUzRTN1M6Uz1TQFNDU0ZTSVNMU09TUlNVU1hTW1NeU2FTZFNnU2pTbVNwU3NTdlN5U3xTf1OCU4VT
+iFOLU45TkVOUU5dTmlOdU6BTo1OmU6lTrFOvU7JT7VQBVBRUNlRCVFlUelSiVL1VAlUVVS1VRFVWVWJV
+cVWMVa5VxlXgVfRWCFYSVnJWilajVr5W3Vb+VwpXHVc3V0NXVldtV4NXj1ehV7dX71gxWE9YaFiHWKJY
+t1jbWOdZAVlHWWZZelmNWZ9Zu1nHWd5Z9VoMWk1aVlqPWsVa4VrvWw5bIls2W09bg1udW7Jb0lvxXAhc
+G1w6XE5cZFx8XItcuFzOXNpc8Vz4XQtdGF05XZVdoV24XdJd514hXlReXl5/XpZeo17DXspe/l8GXxtf
+NF9RX5xfuV/OX+df8mAqYElgYGBsYIxglWCYYJ9goWCjYKVgrmCxYLhgumC8YL5gx2DKYgliDGIPYhJi
+FWIYYhtiHmIhYiRiJmIoYipiLWIvYjJiNWI4YjtiPmJBYkNiRmJJYktiTWJQYlJiVGJWYlhiW2JeYmFi
+Y2JmYmlia2JtYnBic2J2YnlifGJ/YoJihGKHYopijWKQYpNilmKZYptinWKgYqJipWKnYqliq2KtYrBi
+s2K2YrlivGK/YsFiw2LGYsliy2LOYtBi0mLVYtdi2mLdYuBi4mLlYudi6mLsYu9i8mL1Yvdi+mL9Yv9j
+AmMEYwZjCWMMYw9jEWMTYxZjGWMbYx5jIGMiYyRjJmMoYypjLGMvYzJjNGM3YzljPGM+Y0FjRGNGY0lj
+TGNPY1JjVWNXY1ljXGNeY2FjZGNnY2pjbWNvY3Fjc2N1Y3djeWN7Y35jgGOCY4Rjh2OKY4xjj2ORY5Nj
+lWOXY5pjnWOgY6ljrGTrZO5k8WT0ZPdk+mT9ZQBlA2UGZQllDGUPZRJlFWUYZRtlHmUhZSRlJ2UqZS1l
+MGUzZTZlOWU8ZT9lQmVFZUhlS2VOZVFlVGVXZVplXWVgZWNlZmVpZWxlb2VyZXVleGV7ZX5lgWWEZYdl
+imWNZZBlk2WWZZllnGWfZaJlpWWoZatlrmWxZbRlt2W6Zb1lwGXDZcZlyWXMZc9l0mXVZdhl22XeZeFl
+5GXnZepl7WXwZfNl9mX5Zfxl/2YCZgVmCGYLZg5mEWYUZhdmGmYdZiBmI2YmZilmLGYvZjJmNWY4Zjtm
+PmZBZkRmR2ZKZk1mUGZTZlZmWWZcZl9mYmZlZmhma2ZuZnFmdGZ3ZnpmfWaAZoNmhmaJZoxmj2aSZpVm
+mGabZp5moWakZqdmqmatZrBms2a2ZrlmvGa/ZsJmxWbKZs9m0WbTZthm2mbcZt5m4GblZupm72bxZvZm
++Gb7Zv1nAmcHZwlnDmcQZxVnGmcfZyFnJmcrZzBnNWc3ZzlnPmdDZ0ZnS2dQZ1VnWmdcZ15nY2dlZ2dn
+bGduZ3Bncmd3Z3lnfmeAZ4VnimePZ5RnmWeeZ6NnqGetZ7JntGe5Z7tnvWe/Z8RnyWfOZ9Fn1mfbZ+Bn
+5WfnZ+xn7mfwZ/Jn92f8aAFoBmgLaBBoE2gVaBpoHGgeaCNoJWgqaC9oMWgzaDVoOmg/aERoRmhLaE1o
+UmhXaFxoYWhmaGtocGhyaHRoeWh8aIFog2iIaItojWiSaJRolmiZaJ5ooGilaKporGixaLNouGi9aL9o
+wWjGaMto0GjVaNpo32jkaOlo7mjzaPVo92j8aP9pBGkJaQ5pE2kcaSFpJmkvaTFpMmk7aT5pP2lIaUtp
+TGlVaVoAAAAAAAACAgAAAAAAAAzuAAAAAAAAAAAAAAAAAABpaQ</bytes>
+ </object>
+ </data>
+</archive>
diff --git a/src/kim/agent/mac/resources/Gear.tiff b/src/kim/agent/mac/resources/Gear.tiff
new file mode 100644
index 0000000..c138258
--- /dev/null
+++ b/src/kim/agent/mac/resources/Gear.tiff
Binary files differ
diff --git a/src/kim/agent/mac/resources/KerberosAgent.icns b/src/kim/agent/mac/resources/KerberosAgent.icns
new file mode 100644
index 0000000..c6a7252
--- /dev/null
+++ b/src/kim/agent/mac/resources/KerberosAgent.icns
Binary files differ
diff --git a/src/kim/agent/mac/resources/Remove.tiff b/src/kim/agent/mac/resources/Remove.tiff
new file mode 100644
index 0000000..dacc97c
--- /dev/null
+++ b/src/kim/agent/mac/resources/Remove.tiff
Binary files differ
diff --git a/src/kim/agent/mac/resources/Remove_Pressed.tiff b/src/kim/agent/mac/resources/Remove_Pressed.tiff
new file mode 100644
index 0000000..de3f877
--- /dev/null
+++ b/src/kim/agent/mac/resources/Remove_Pressed.tiff
Binary files differ
diff --git a/src/kim/lib/kim.exports b/src/kim/lib/kim.exports
new file mode 100644
index 0000000..eda7349
--- /dev/null
+++ b/src/kim/lib/kim.exports
@@ -0,0 +1,149 @@
+kim_error_copy
+kim_error_get_code
+kim_error_get_display_string
+kim_error_free
+
+kim_string_copy
+kim_string_compare
+kim_string_free
+
+kim_identity_create_from_string
+kim_identity_create_from_components
+kim_identity_create_from_krb5_principal
+kim_identity_copy
+kim_identity_compare
+kim_identity_get_string
+kim_identity_get_display_string
+kim_identity_get_realm
+kim_identity_get_number_of_components
+kim_identity_get_component_at_index
+kim_identity_get_krb5_principal
+kim_identity_get_gss_name
+kim_identity_change_password
+kim_identity_change_password_to_password
+kim_identity_free
+
+kim_prompt_callback_default
+kim_prompt_callback_gui
+kim_prompt_callback_cli
+kim_prompt_callback_none
+
+kim_options_create
+kim_options_copy
+kim_options_set_prompt_callback
+kim_options_get_prompt_callback
+kim_options_set_data
+kim_options_get_data
+kim_options_set_prompt_response
+kim_options_get_prompt_response
+kim_options_set_start_time
+kim_options_get_start_time
+kim_options_set_lifetime
+kim_options_get_lifetime
+kim_options_set_renewable
+kim_options_get_renewable
+kim_options_set_renewal_lifetime
+kim_options_get_renewal_lifetime
+kim_options_set_forwardable
+kim_options_get_forwardable
+kim_options_set_proxiable
+kim_options_get_proxiable
+kim_options_set_addressless
+kim_options_get_addressless
+kim_options_set_service_name
+kim_options_get_service_name
+kim_options_free
+
+kim_selection_hints_create
+kim_selection_hints_copy
+kim_selection_hints_set_service_identity_hint
+kim_selection_hints_get_service_identity_hint
+kim_selection_hints_set_client_realm_hint
+kim_selection_hints_get_client_realm_hint
+kim_selection_hints_set_user_hint
+kim_selection_hints_get_user_hint
+kim_selection_hints_set_service_realm_hint
+kim_selection_hints_get_service_realm_hint
+kim_selection_hints_set_service_hint
+kim_selection_hints_get_service_hint
+kim_selection_hints_set_server_hint
+kim_selection_hints_get_server_hint
+kim_selection_hints_set_application_name
+kim_selection_hints_get_application_name
+kim_selection_hints_set_explanation
+kim_selection_hints_get_explanation
+kim_selection_hints_set_options
+kim_selection_hints_get_options
+kim_selection_hints_set_allow_user_interaction
+kim_selection_hints_get_allow_user_interaction
+kim_selection_hints_set_remember_identity
+kim_selection_hints_get_remember_identity
+kim_selection_hints_get_identity
+kim_selection_hints_remember_identity
+kim_selection_hints_forget_identity
+kim_selection_hints_free
+
+kim_preferences_create
+kim_preferences_copy
+kim_preferences_set_options
+kim_preferences_get_options
+kim_preferences_set_remember_options
+kim_preferences_get_remember_options
+kim_preferences_set_client_identity
+kim_preferences_get_client_identity
+kim_preferences_set_remember_client_identity
+kim_preferences_get_remember_client_identity
+kim_preferences_set_favorite_identities
+kim_preferences_get_favorite_identities
+kim_preferences_synchronize
+kim_preferences_free
+
+kim_credential_iterator_create
+kim_credential_iterator_next
+kim_credential_iterator_free
+
+kim_credential_create_new
+kim_credential_create_from_keytab
+kim_credential_create_from_krb5_creds
+kim_credential_copy
+kim_credential_get_krb5_creds
+kim_credential_get_client_identity
+kim_credential_get_service_identity
+kim_credential_is_tgt
+kim_credential_get_state
+kim_credential_get_start_time
+kim_credential_get_expiration_time
+kim_credential_get_renewal_expiration_time
+kim_credential_store
+kim_credential_verify
+kim_credential_renew
+kim_credential_validate
+kim_credential_free
+
+kim_ccache_iterator_create
+kim_ccache_iterator_next
+kim_ccache_iterator_free
+
+kim_ccache_create_new
+kim_ccache_create_new_if_needed
+kim_ccache_create_from_client_identity
+kim_ccache_create_from_keytab
+kim_ccache_create_from_default
+kim_ccache_create_from_type_and_name
+kim_ccache_create_from_krb5_ccache
+kim_ccache_copy
+kim_ccache_get_krb5_ccache
+kim_ccache_get_name
+kim_ccache_get_type
+kim_ccache_get_display_name
+kim_ccache_get_client_identity
+kim_ccache_get_valid_credential
+kim_ccache_get_start_time
+kim_ccache_get_expiration_time
+kim_ccache_get_renewal_expiration_time
+kim_ccache_set_default
+kim_ccache_verify
+kim_ccache_renew
+kim_ccache_validate
+kim_ccache_destroy
+kim_ccache_free
diff --git a/src/kim/lib/kim_ccache.c b/src/kim/lib/kim_ccache.c
new file mode 100644
index 0000000..e01671b
--- /dev/null
+++ b/src/kim/lib/kim_ccache.c
@@ -0,0 +1,1051 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <krb5.h>
+#include <Kerberos/CredentialsCache.h>
+#include "kim_private.h"
+
+struct kim_ccache_iterator_opaque {
+ krb5_context context;
+ krb5_cccol_cursor cursor;
+};
+
+struct kim_ccache_iterator_opaque kim_ccache_iterator_initializer = { NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_iterator_create (kim_ccache_iterator_t *out_ccache_iterator)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_ccache_iterator_t ccache_iterator = NULL;
+
+ if (!err && !out_ccache_iterator) { err = param_error (1, "out_ccache_iterator", "NULL"); }
+
+ if (!err) {
+ ccache_iterator = malloc (sizeof (*ccache_iterator));
+ if (ccache_iterator) {
+ *ccache_iterator = kim_ccache_iterator_initializer;
+ } else {
+ err = os_error (errno);
+ }
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&ccache_iterator->context));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cccol_cursor_new (ccache_iterator->context,
+ &ccache_iterator->cursor));
+ }
+
+ if (!err) {
+ *out_ccache_iterator = ccache_iterator;
+ ccache_iterator = NULL;
+ }
+
+ kim_ccache_iterator_free (&ccache_iterator);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_iterator_next (kim_ccache_iterator_t in_ccache_iterator,
+ kim_ccache_t *out_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ krb5_ccache ccache = NULL;
+
+ if (!err && !in_ccache_iterator) { err = param_error (1, "in_ccache_iterator", "NULL"); }
+ if (!err && !out_ccache ) { err = param_error (2, "out_ccache", "NULL"); }
+
+ if (!err) {
+ krb5_error_code terr = krb5_cccol_cursor_next (in_ccache_iterator->context,
+ in_ccache_iterator->cursor,
+ &ccache);
+
+ if (!terr) {
+ err = kim_ccache_create_from_krb5_ccache (out_ccache,
+ in_ccache_iterator->context,
+ ccache);
+ } else if (terr == KRB5_CC_END) {
+ *out_ccache = NULL; /* no more ccaches */
+
+ } else {
+ err = krb5_error (terr);
+ }
+ }
+
+ if (ccache) { krb5_cc_close (in_ccache_iterator->context, ccache); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_ccache_iterator_free (kim_ccache_iterator_t *io_ccache_iterator)
+{
+ if (io_ccache_iterator && *io_ccache_iterator) {
+ if ((*io_ccache_iterator)->context) {
+ if ((*io_ccache_iterator)->cursor) {
+ krb5_cccol_cursor_free ((*io_ccache_iterator)->context,
+ &(*io_ccache_iterator)->cursor);
+ }
+ krb5_free_context ((*io_ccache_iterator)->context);
+ }
+ free (*io_ccache_iterator);
+ *io_ccache_iterator = NULL;
+ }
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+struct kim_ccache_opaque {
+ krb5_context context;
+ krb5_ccache ccache;
+};
+
+struct kim_ccache_opaque kim_ccache_initializer = { NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_ccache_create_resolve_name (kim_string_t *out_resolve_name,
+ kim_string_t in_name,
+ kim_string_t in_type)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !out_resolve_name) { err = param_error (1, "out_resolve_name", "NULL"); }
+ if (!err && !in_name ) { err = param_error (2, "in_name", "NULL"); }
+ if (!err && !in_type ) { err = param_error (2, "in_type", "NULL"); }
+
+ if (!err) {
+ err = kim_string_create_from_format (out_resolve_name, "%s:%s",
+ in_type, in_name);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static kim_boolean_t kim_ccache_k5ccaches_are_equal (krb5_context in_context,
+ krb5_ccache in_ccache,
+ krb5_context in_compare_to_context,
+ krb5_ccache io_compare_to_ccache)
+{
+ kim_boolean_t equal = FALSE;
+
+ if (in_context && in_ccache && in_compare_to_context && io_compare_to_ccache) {
+ const char *type = krb5_cc_get_type (in_context, in_ccache);
+ const char *compare_to_type = krb5_cc_get_type (in_compare_to_context,
+ io_compare_to_ccache);
+ const char *name = krb5_cc_get_name (in_context, in_ccache);
+ const char *compare_to_name = krb5_cc_get_name (in_compare_to_context,
+ io_compare_to_ccache);
+
+ equal = (!strcmp (type, compare_to_type) &&
+ !strcmp (name, compare_to_name));
+ }
+
+ return equal;
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_ccache_allocate (kim_ccache_t *out_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_ccache_t ccache = NULL;
+
+ if (!err && !out_ccache) { err = param_error (1, "out_ccache", "NULL"); }
+
+ if (!err) {
+ ccache = malloc (sizeof (*ccache));
+ if (!ccache) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ *ccache = kim_ccache_initializer;
+ *out_ccache = ccache;
+ ccache = NULL;
+ }
+
+ kim_ccache_free (&ccache);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_create_new (kim_ccache_t *out_ccache,
+ kim_identity_t in_client_identity,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+ kim_identity_t client_identity = NULL;
+
+ if (!err && !out_ccache) { err = param_error (1, "out_ccache", "NULL"); }
+
+ if (!err) {
+ err = kim_credential_create_new (&credential, in_client_identity, in_options);
+ }
+
+ if (!err) {
+ err = kim_credential_get_client_identity (credential, &client_identity);
+ }
+
+ if (!err) {
+ err = kim_credential_store (credential, client_identity, out_ccache);
+ }
+
+ kim_identity_free (&client_identity);
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_create_new_if_needed (kim_ccache_t *out_ccache,
+ kim_identity_t in_client_identity,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !out_ccache ) { err = param_error (1, "out_ccache", "NULL"); }
+ if (!err && !in_client_identity) { err = param_error (2, "in_client_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_create_from_client_identity (out_ccache, in_client_identity);
+
+ if (err) {
+ kim_error_free (&err); /* toss error since we don't care */
+ err = kim_ccache_create_new (out_ccache, in_client_identity, in_options);
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_create_from_client_identity (kim_ccache_t *out_ccache,
+ kim_identity_t in_client_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_ccache_iterator_t iterator = NULL;
+ kim_boolean_t found = FALSE;
+
+ if (!err && !out_ccache ) { err = param_error (1, "out_ccache", "NULL"); }
+ if (!err && !in_client_identity) { err = param_error (2, "in_client_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_iterator_create (&iterator);
+ }
+
+ while (!err && !found) {
+ kim_ccache_t ccache = NULL;
+ kim_identity_t identity = NULL;
+
+ err = kim_ccache_iterator_next (iterator, &ccache);
+
+ if (!err && !ccache) {
+ kim_string_t string = NULL;
+
+ err = kim_identity_get_display_string (in_client_identity, &string);
+
+ if (!err) {
+ err = kim_error_create_from_code (KIM_NO_SUCH_PRINCIPAL_ECODE,
+ string);
+ }
+
+ kim_string_free (&string);
+ }
+
+ if (!err) {
+ err = kim_ccache_get_client_identity (ccache, &identity);
+ }
+
+ if (!err) {
+ err = kim_identity_compare (in_client_identity, identity, &found);
+ }
+
+ if (!err && found) {
+ *out_ccache = ccache;
+ ccache = NULL;
+ }
+
+ kim_identity_free (&identity);
+ kim_ccache_free (&ccache);
+ }
+
+ kim_ccache_iterator_free (&iterator);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_create_from_keytab (kim_ccache_t *out_ccache,
+ kim_identity_t in_identity,
+ kim_options_t in_options,
+ kim_string_t in_keytab)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+ kim_identity_t client_identity = NULL;
+
+ if (!err && !out_ccache) { err = param_error (1, "out_ccache", "NULL"); }
+
+ if (!err) {
+ err = kim_credential_create_from_keytab (&credential, in_identity,
+ in_options, in_keytab);
+ }
+
+ if (!err) {
+ err = kim_credential_get_client_identity (credential, &client_identity);
+ }
+
+ if (!err) {
+ err = kim_credential_store (credential, client_identity, out_ccache);
+ }
+
+ kim_identity_free (&client_identity);
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_create_from_default (kim_ccache_t *out_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_ccache_t ccache = NULL;
+
+ if (!err && !out_ccache) { err = param_error (1, "out_ccache", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_allocate (&ccache);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&ccache->context));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_default (ccache->context, &ccache->ccache));
+ }
+
+ if (!err) {
+ *out_ccache = ccache;
+ ccache = NULL;
+ }
+
+ kim_ccache_free (&ccache);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_create_from_display_name (kim_ccache_t *out_ccache,
+ kim_string_t in_display_name)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_ccache_t ccache = NULL;
+
+ if (!err && !out_ccache ) { err = param_error (1, "out_ccache", "NULL"); }
+ if (!err && !in_display_name) { err = param_error (2, "in_display_name", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_allocate (&ccache);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&ccache->context));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_resolve (ccache->context, in_display_name,
+ &ccache->ccache));
+ }
+
+ if (!err) {
+ *out_ccache = ccache;
+ ccache = NULL;
+ }
+
+ kim_ccache_free (&ccache);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_create_from_type_and_name (kim_ccache_t *out_ccache,
+ kim_string_t in_type,
+ kim_string_t in_name)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t resolve_name = NULL;
+
+ if (!err && !out_ccache) { err = param_error (1, "out_ccache", "NULL"); }
+ if (!err && !in_name ) { err = param_error (2, "in_name", "NULL"); }
+ if (!err && !in_type ) { err = param_error (2, "in_type", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_create_resolve_name (&resolve_name, in_name, in_type);
+ }
+
+ if (!err) {
+ err = kim_ccache_create_from_display_name (out_ccache, resolve_name);
+ }
+
+ kim_string_free (&resolve_name);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_create_from_krb5_ccache (kim_ccache_t *out_ccache,
+ krb5_context in_krb5_context,
+ krb5_ccache in_krb5_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !out_ccache ) { err = param_error (1, "out_ccache", "NULL"); }
+ if (!err && !in_krb5_ccache ) { err = param_error (2, "in_krb5_ccache", "NULL"); }
+ if (!err && !in_krb5_context) { err = param_error (3, "in_krb5_context", "NULL"); }
+
+ if (!err) {
+ kim_string_t type = krb5_cc_get_type (in_krb5_context, in_krb5_ccache);
+ kim_string_t name = krb5_cc_get_name (in_krb5_context, in_krb5_ccache);
+
+ err = kim_ccache_create_from_type_and_name (out_ccache, type, name);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_copy (kim_ccache_t *out_ccache,
+ kim_ccache_t in_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t name = NULL;
+ kim_string_t type = NULL;
+
+ if (!err && !out_ccache) { err = param_error (1, "out_ccache", "NULL"); }
+ if (!err && !in_ccache ) { err = param_error (2, "in_ccache", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_get_name (in_ccache, &name);
+ }
+
+ if (!err) {
+ err = kim_ccache_get_type (in_ccache, &type);
+ }
+
+ if (!err) {
+ err = kim_ccache_create_from_type_and_name (out_ccache, type, name);
+ }
+
+ kim_string_free (&name);
+ kim_string_free (&type);
+
+ return check_error (err);
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_compare (kim_ccache_t in_ccache,
+ kim_ccache_t in_compare_to_ccache,
+ kim_boolean_t *out_equal)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_ccache ) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !in_compare_to_ccache) { err = param_error (2, "in_compare_to_ccache", "NULL"); }
+ if (!err && !out_equal ) { err = param_error (3, "out_equal", "NULL"); }
+
+ if (!err) {
+ *out_equal = kim_ccache_k5ccaches_are_equal (in_ccache->context,
+ in_ccache->ccache,
+ in_compare_to_ccache->context,
+ in_compare_to_ccache->ccache);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_get_krb5_ccache (kim_ccache_t in_ccache,
+ krb5_context in_krb5_context,
+ krb5_ccache *out_krb5_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t resolve_name = NULL;
+
+ if (!err && !in_ccache ) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !in_krb5_context) { err = param_error (2, "in_krb5_context", "NULL"); }
+ if (!err && !out_krb5_ccache) { err = param_error (2, "out_krb5_ccache", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_get_display_name (in_ccache, &resolve_name);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_resolve (in_krb5_context, resolve_name,
+ out_krb5_ccache));
+ }
+
+ kim_string_free (&resolve_name);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_get_type (kim_ccache_t in_ccache,
+ kim_string_t *out_type)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_ccache) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !out_type ) { err = param_error (2, "out_type", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (out_type, krb5_cc_get_type (in_ccache->context,
+ in_ccache->ccache));
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_get_name (kim_ccache_t in_ccache,
+ kim_string_t *out_name)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_ccache) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !out_name ) { err = param_error (2, "out_name", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (out_name, krb5_cc_get_name (in_ccache->context,
+ in_ccache->ccache));
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_get_display_name (kim_ccache_t in_ccache,
+ kim_string_t *out_display_name)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_ccache ) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !out_display_name) { err = param_error (2, "out_display_name", "NULL"); }
+
+ if (!err) {
+ kim_string_t type = krb5_cc_get_type (in_ccache->context,
+ in_ccache->ccache);
+ kim_string_t name = krb5_cc_get_name (in_ccache->context,
+ in_ccache->ccache);
+
+ err = kim_ccache_create_resolve_name (out_display_name, type, name);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_get_client_identity (kim_ccache_t in_ccache,
+ kim_identity_t *out_client_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ krb5_principal principal = NULL;
+
+ if (!err && !in_ccache ) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !out_client_identity) { err = param_error (2, "out_client_identity", "NULL"); }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_get_principal (in_ccache->context,
+ in_ccache->ccache,
+ &principal));
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_krb5_principal (out_client_identity,
+ in_ccache->context,
+ principal);
+ }
+
+ if (principal) { krb5_free_principal (in_ccache->context, principal); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_get_valid_credential (kim_ccache_t in_ccache,
+ kim_credential_t *out_credential)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_iterator_t iterator = NULL;
+ kim_boolean_t out_of_credentials = FALSE;
+ kim_boolean_t found_valid_tgt = FALSE;
+ kim_boolean_t found_invalid_tgt = FALSE;
+ kim_credential_state_t invalid_tgt_state = kim_credentials_state_valid;
+ kim_credential_t valid_credential = NULL;
+
+ if (!err && !in_ccache ) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !out_credential) { err = param_error (2, "out_credential", "NULL"); }
+
+ if (!err) {
+ err = kim_credential_iterator_create (&iterator, in_ccache);
+ }
+
+ while (!err && !found_valid_tgt && !out_of_credentials) {
+ kim_credential_t credential = NULL;
+
+ err = kim_credential_iterator_next (iterator, &credential);
+
+ if (!err && !credential) {
+ out_of_credentials = TRUE;
+
+ } else if (!err) {
+ kim_identity_t service_identity = NULL;
+ kim_credential_state_t state = kim_credentials_state_valid;
+ kim_boolean_t is_tgt = FALSE;
+
+ err = kim_credential_get_service_identity (credential,
+ &service_identity);
+
+ if (!err) {
+ err = kim_credential_get_state (credential, &state);
+ }
+
+ if (!err) {
+ err = kim_identity_is_tgt_service (service_identity, &is_tgt);
+ }
+
+ if (!err) {
+ if (state == kim_credentials_state_valid) {
+ kim_credential_free (&valid_credential);
+
+ valid_credential = credential;
+ credential = NULL;
+
+ if (is_tgt) {
+ found_valid_tgt = TRUE;
+ }
+ } else {
+ if (is_tgt && !found_invalid_tgt) {
+ found_invalid_tgt = TRUE;
+ invalid_tgt_state = state;
+ }
+ }
+ }
+
+ kim_identity_free (&service_identity);
+ }
+
+ kim_credential_free (&credential);
+ }
+
+ if (!err && (!valid_credential || found_invalid_tgt)) {
+ kim_identity_t identity = NULL;
+ kim_string_t identity_string = NULL;
+
+ err = kim_ccache_get_client_identity (in_ccache, &identity);
+
+ if (!err) {
+ err = kim_identity_get_display_string (identity,
+ &identity_string);
+ }
+
+ if (!err && found_invalid_tgt) {
+ switch (invalid_tgt_state) {
+ case kim_credentials_state_expired:
+ err = kim_error_create_from_code (KIM_CREDENTIALS_EXPIRED_ECODE,
+ identity_string);
+ break;
+ case kim_credentials_state_not_yet_valid:
+ case kim_credentials_state_needs_validation:
+ err = kim_error_create_from_code (KIM_NEEDS_VALIDATION_ECODE,
+ identity_string);
+ break;
+ case kim_credentials_state_address_mismatch:
+ err = kim_error_create_from_code (KIM_BAD_IP_ADDRESS_ECODE,
+ identity_string);
+ break;
+ }
+ }
+
+ if (!err && !valid_credential) {
+ err = kim_error_create_from_code (KIM_NO_CREDENTIALS_ECODE,
+ identity_string);
+ }
+
+ kim_string_free (&identity_string);
+ kim_identity_free (&identity);
+ }
+
+ if (!err) {
+ *out_credential = valid_credential;
+ valid_credential = NULL;
+ }
+
+ kim_credential_free (&valid_credential);
+ kim_credential_iterator_free (&iterator);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_get_start_time (kim_ccache_t in_ccache,
+ kim_time_t *out_start_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+
+ if (!err && !in_ccache ) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !out_start_time) { err = param_error (2, "out_start_time", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_get_valid_credential (in_ccache, &credential);
+ }
+
+ if (!err) {
+ err = kim_credential_get_start_time (credential, out_start_time);
+ }
+
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_get_expiration_time (kim_ccache_t in_ccache,
+ kim_time_t *out_expiration_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+
+ if (!err && !in_ccache ) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !out_expiration_time) { err = param_error (2, "out_expiration_time", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_get_valid_credential (in_ccache, &credential);
+ }
+
+ if (!err) {
+ err = kim_credential_get_expiration_time (credential,
+ out_expiration_time);
+ }
+
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_get_renewal_expiration_time (kim_ccache_t in_ccache,
+ kim_time_t *out_renewal_expiration_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+
+ if (!err && !in_ccache ) { err = param_error (1, "in_ccache", "NULL"); }
+ if (!err && !out_renewal_expiration_time) { err = param_error (2, "out_renewal_expiration_time", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_get_valid_credential (in_ccache, &credential);
+ }
+
+ if (!err) {
+ err = kim_credential_get_renewal_expiration_time (credential,
+ out_renewal_expiration_time);
+ }
+
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_set_default (kim_ccache_t io_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_ccache) { err = param_error (1, "io_ccache", "NULL"); }
+
+ if (!err) {
+ char *environment_ccache_name = getenv ("KRB5CCNAME");
+
+ if (environment_ccache_name) {
+ krb5_ccache environment_ccache = NULL;
+ krb5_principal client_principal = NULL;
+
+ err = krb5_error (krb5_cc_resolve (io_ccache->context,
+ environment_ccache_name,
+ &environment_ccache));
+
+ if (!err && !kim_ccache_k5ccaches_are_equal (io_ccache->context,
+ io_ccache->ccache,
+ io_ccache->context,
+ environment_ccache)) {
+ /* KRB5CCNAME is set and does not point to this ccache.
+ * Move the creds and make this kim_ccache_t object refer to that ccache. */
+
+ err = krb5_error (krb5_cc_get_principal (io_ccache->context,
+ io_ccache->ccache,
+ &client_principal));
+
+ if (!err) {
+ err = krb5_error (krb5_cc_initialize (io_ccache->context,
+ environment_ccache,
+ client_principal));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_copy_creds (io_ccache->context,
+ io_ccache->ccache,
+ environment_ccache));
+ }
+
+ if (!err) {
+ krb5_cc_destroy (io_ccache->context, io_ccache->ccache);
+ io_ccache->ccache = environment_ccache;
+ environment_ccache = NULL; /* take ownership */
+ }
+ }
+
+ if (environment_ccache) { krb5_cc_close (io_ccache->context,
+ environment_ccache); }
+
+ } else {
+ kim_string_t type = NULL;
+ kim_string_t name = NULL;
+ cc_context_t cc_context = NULL;
+ cc_ccache_t cc_ccache = NULL;
+
+ err = kim_ccache_get_type (io_ccache, &type);
+
+ if (!err && strcmp (type, "API")) {
+ kim_string_t display_name = NULL;
+ /* Not a CCAPI ccache; can't set to default */
+
+ err = kim_ccache_get_display_name (io_ccache, &display_name);
+
+ if (!err) {
+ err = kim_error_create_from_code (KIM_CANT_BECOME_DEFAULT_ECODE,
+ display_name);
+ }
+
+ kim_string_free (&display_name);
+ }
+
+ if (!err) {
+ err = kim_ccache_get_name (io_ccache, &name);
+ }
+
+ /* get a CCAPI ccache for this cache */
+ if (!err) {
+ err = ccapi_error (cc_initialize (&cc_context, ccapi_version_4,
+ NULL, NULL));
+ }
+
+ if (!err) {
+ err = ccapi_error (cc_context_open_ccache (cc_context, name,
+ &cc_ccache));
+ }
+
+ if (!err) {
+ err = ccapi_error (cc_ccache_set_default (cc_ccache));
+ }
+
+ if (cc_context) { cc_context_release (cc_context); }
+ if (cc_ccache ) { cc_ccache_release (cc_ccache); }
+ kim_string_free (&name);
+ kim_string_free (&type);
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_verify (kim_ccache_t in_ccache,
+ kim_identity_t in_service_identity,
+ kim_string_t in_keytab,
+ kim_boolean_t in_fail_if_no_service_key)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+
+ if (!err && !in_ccache) { err = param_error (1, "in_ccache", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_get_valid_credential (in_ccache, &credential);
+ }
+
+ if (!err) {
+ err = kim_credential_verify (credential, in_service_identity,
+ in_keytab, in_fail_if_no_service_key);
+ }
+
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_renew (kim_ccache_t in_ccache,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+ kim_identity_t client_identity = NULL;
+
+ if (!err && !in_ccache) { err = param_error (1, "in_ccache", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_get_valid_credential (in_ccache, &credential);
+ }
+
+ if (!err) {
+ err = kim_credential_renew (&credential, in_options);
+ }
+
+ if (!err) {
+ err = kim_ccache_get_client_identity (in_ccache, &client_identity);
+ }
+
+ if (!err) {
+ err = kim_credential_store (credential, client_identity, NULL);
+ }
+
+ kim_identity_free (&client_identity);
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_validate (kim_ccache_t in_ccache,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+ kim_identity_t client_identity = NULL;
+
+ if (!err && !in_ccache) { err = param_error (1, "in_ccache", "NULL"); }
+
+ if (!err) {
+ err = kim_ccache_get_valid_credential (in_ccache, &credential);
+ }
+
+ if (!err) {
+ err = kim_credential_validate (&credential, in_options);
+ }
+
+ if (!err) {
+ err = kim_ccache_get_client_identity (in_ccache, &client_identity);
+ }
+
+ if (!err) {
+ err = kim_credential_store (credential, client_identity, NULL);
+ }
+
+ kim_identity_free (&client_identity);
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_ccache_destroy (kim_ccache_t *io_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (io_ccache && *io_ccache) {
+ err = krb5_error (krb5_cc_destroy ((*io_ccache)->context,
+ (*io_ccache)->ccache));
+
+ if (!err) {
+ (*io_ccache)->ccache = NULL;
+ kim_ccache_free (io_ccache);
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_ccache_free (kim_ccache_t *io_ccache)
+{
+ if (io_ccache && *io_ccache) {
+ if ((*io_ccache)->context) {
+ if ((*io_ccache)->ccache) {
+ krb5_cc_close ((*io_ccache)->context, (*io_ccache)->ccache);
+ }
+ krb5_free_context ((*io_ccache)->context);
+ }
+ free (*io_ccache);
+ *io_ccache = NULL;
+ }
+}
+
diff --git a/src/kim/lib/kim_ccache_private.h b/src/kim/lib/kim_ccache_private.h
new file mode 100644
index 0000000..23af8b2
--- /dev/null
+++ b/src/kim/lib/kim_ccache_private.h
@@ -0,0 +1,39 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_CCACHE_PRIVATE_H
+#define KIM_CCACHE_PRIVATE_H
+
+#include <kim/kim.h>
+
+kim_error_t kim_ccache_create_from_display_name (kim_ccache_t *out_ccache,
+ kim_string_t in_display_name);
+
+kim_error_t kim_ccache_compare (kim_ccache_t in_ccache,
+ kim_ccache_t in_compare_to_ccache,
+ kim_boolean_t *out_equal);
+
+#endif /* KIM_CCACHE_PRIVATE_H */
diff --git a/src/kim/lib/kim_credential.c b/src/kim/lib/kim_credential.c
new file mode 100644
index 0000000..2ef618c
--- /dev/null
+++ b/src/kim/lib/kim_credential.c
@@ -0,0 +1,908 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <krb5.h>
+#include "kim_private.h"
+
+struct kim_credential_iterator_opaque {
+ krb5_context context;
+ krb5_ccache ccache;
+ krb5_cc_cursor cursor;
+};
+
+struct kim_credential_iterator_opaque kim_credential_iterator_initializer = { NULL, NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_iterator_create (kim_credential_iterator_t *out_credential_iterator,
+ kim_ccache_t in_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_iterator_t credential_iterator = NULL;
+
+ if (!err && !out_credential_iterator) { err = param_error (1, "out_credential_iterator", "NULL"); }
+ if (!err && !in_ccache ) { err = param_error (2, "in_ccache", "NULL"); }
+
+ if (!err) {
+ credential_iterator = malloc (sizeof (*credential_iterator));
+ if (credential_iterator) {
+ *credential_iterator = kim_credential_iterator_initializer;
+ } else {
+ err = os_error (errno);
+ }
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&credential_iterator->context));
+ }
+
+ if (!err) {
+ err = kim_ccache_get_krb5_ccache (in_ccache,
+ credential_iterator->context,
+ &credential_iterator->ccache);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_start_seq_get (credential_iterator->context,
+ credential_iterator->ccache,
+ &credential_iterator->cursor));
+ }
+
+ if (!err) {
+ *out_credential_iterator = credential_iterator;
+ credential_iterator = NULL;
+ }
+
+ kim_credential_iterator_free (&credential_iterator);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_iterator_next (kim_credential_iterator_t in_credential_iterator,
+ kim_credential_t *out_credential)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_credential_iterator) { err = param_error (1, "in_credential_iterator", "NULL"); }
+ if (!err && !out_credential ) { err = param_error (2, "out_credential", "NULL"); }
+
+ if (!err) {
+ krb5_creds creds;
+
+ krb5_error_code terr = krb5_cc_next_cred (in_credential_iterator->context,
+ in_credential_iterator->ccache,
+ &in_credential_iterator->cursor,
+ &creds);
+
+ if (!terr) {
+ err = kim_credential_create_from_krb5_creds (out_credential,
+ in_credential_iterator->context,
+ &creds);
+
+ krb5_free_cred_contents (in_credential_iterator->context, &creds);
+
+ } else if (terr == KRB5_CC_END) {
+ *out_credential = NULL; /* no more ccaches */
+
+ } else {
+ err = krb5_error (terr);
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_credential_iterator_free (kim_credential_iterator_t *io_credential_iterator)
+{
+ if (io_credential_iterator && *io_credential_iterator) {
+ if ((*io_credential_iterator)->context) {
+ if ((*io_credential_iterator)->ccache) {
+ if ((*io_credential_iterator)->cursor) {
+ krb5_cc_end_seq_get ((*io_credential_iterator)->context,
+ (*io_credential_iterator)->ccache,
+ &(*io_credential_iterator)->cursor);
+ }
+ krb5_cc_close ((*io_credential_iterator)->context,
+ (*io_credential_iterator)->ccache);
+ }
+ krb5_free_context ((*io_credential_iterator)->context);
+ }
+ free (*io_credential_iterator);
+ *io_credential_iterator = NULL;
+ }
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+struct kim_credential_opaque {
+ krb5_context context;
+ krb5_creds *creds;
+};
+
+struct kim_credential_opaque kim_credential_initializer = { NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_credential_allocate (kim_credential_t *out_credential)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+
+ if (!err && !out_credential) { err = param_error (1, "out_credential", "NULL"); }
+
+ if (!err) {
+ credential = malloc (sizeof (*credential));
+ if (!credential) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ *credential = kim_credential_initializer;
+ *out_credential = credential;
+ credential = NULL;
+ }
+
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_create_new (kim_credential_t *out_credential,
+ kim_identity_t in_client_identity,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+
+ if (!err && !out_credential) { err = param_error (1, "out_credential", "NULL"); }
+
+ if (!err) {
+ err = kim_credential_allocate (&credential);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&credential->context));
+ }
+
+ if (!err) {
+#warning Get tickets here
+ }
+
+ if (!err) {
+ *out_credential = credential;
+ credential = NULL;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_create_from_keytab (kim_credential_t *out_credential,
+ kim_identity_t in_identity,
+ kim_options_t in_options,
+ kim_string_t in_keytab)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_creds creds;
+ kim_boolean_t free_creds = FALSE;
+ krb5_principal principal = NULL;
+ kim_time_t start_time = 0;
+ kim_string_t service_name = NULL;
+ krb5_get_init_creds_opt *init_cred_options = NULL;
+
+ if (!err && !out_credential) { err = param_error (1, "out_credential", "NULL"); }
+
+ if (!err) {
+ err = kim_credential_allocate (&credential);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&credential->context));
+ }
+
+ if (!err) {
+ kim_options_t options = in_options;
+
+ if (!options) {
+ err = kim_options_create (&options);
+ }
+
+ if (!err) {
+ err = kim_options_get_start_time (options, &start_time);
+ }
+
+ if (!err) {
+ err = kim_options_get_service_name (options, &service_name);
+ }
+
+ if (!err) {
+ err = kim_options_get_init_cred_options (options, credential->context,
+ &init_cred_options);
+ }
+
+ if (options != in_options) { kim_options_free (&options); }
+ }
+
+ if (!err) {
+ if (in_keytab) {
+ err = krb5_error (krb5_kt_resolve (credential->context, in_keytab, &keytab));
+ } else {
+ err = krb5_error (krb5_kt_default (credential->context, &keytab));
+ }
+ }
+
+ if (!err) {
+ if (in_identity) {
+ err = kim_identity_get_krb5_principal (in_identity, credential->context, &principal);
+ } else {
+ krb5_kt_cursor cursor = NULL;
+ krb5_keytab_entry entry;
+ kim_boolean_t entry_allocated = FALSE;
+
+ err = krb5_error (krb5_kt_start_seq_get (credential->context, keytab, &cursor));
+
+ if (!err) {
+ err = krb5_error (krb5_kt_next_entry (credential->context, keytab, &entry, &cursor));
+ entry_allocated = (err == KIM_NO_ERROR); /* remember to free later */
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_principal (credential->context, entry.principal, &principal));
+ }
+
+ if (entry_allocated) { krb5_free_keytab_entry_contents (credential->context, &entry); }
+ if (cursor ) { krb5_kt_end_seq_get (credential->context, keytab, &cursor); }
+ }
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_get_init_creds_keytab (credential->context, &creds, principal, keytab,
+ start_time, (char *) service_name, init_cred_options));
+ if (!err) { free_creds = TRUE; }
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_creds (credential->context, &creds, &credential->creds));
+ }
+
+ if (!err) {
+ *out_credential = credential;
+ credential = NULL;
+ }
+
+ if (principal ) { krb5_free_principal (credential->context, principal); }
+ if (free_creds) { krb5_free_cred_contents (credential->context, &creds); }
+ kim_options_free_init_cred_options (credential->context, &init_cred_options);
+ kim_string_free (&service_name);
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_create_from_krb5_creds (kim_credential_t *out_credential,
+ krb5_context in_krb5_context,
+ krb5_creds *in_krb5_creds)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+
+ if (!err && !out_credential ) { err = param_error (1, "out_credential", "NULL"); }
+ if (!err && !in_krb5_creds ) { err = param_error (2, "in_krb5_creds", "NULL"); }
+ if (!err && !in_krb5_context) { err = param_error (3, "in_krb5_context", "NULL"); }
+
+ if (!err) {
+ err = kim_credential_allocate (&credential);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&credential->context));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_creds (credential->context, in_krb5_creds, &credential->creds));
+ }
+
+ if (!err) {
+ *out_credential = credential;
+ credential = NULL;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_copy (kim_credential_t *out_credential,
+ kim_credential_t in_credential)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_credential_t credential = NULL;
+
+ if (!err && !out_credential) { err = param_error (1, "out_credential", "NULL"); }
+ if (!err && !in_credential ) { err = param_error (2, "in_credential", "NULL"); }
+
+ if (!err) {
+ err = kim_credential_allocate (&credential);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&credential->context));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_creds (credential->context, in_credential->creds, &credential->creds));
+ }
+
+ if (!err) {
+ *out_credential = credential;
+ credential = NULL;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_get_krb5_creds (kim_credential_t in_credential,
+ krb5_context in_krb5_context,
+ krb5_creds **out_krb5_creds)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_credential ) { err = param_error (1, "in_credential", "NULL"); }
+ if (!err && !in_krb5_context) { err = param_error (2, "in_krb5_context", "NULL"); }
+ if (!err && !out_krb5_creds ) { err = param_error (3, "out_krb5_creds", "NULL"); }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_creds (in_krb5_context, in_credential->creds, out_krb5_creds));
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_get_client_identity (kim_credential_t in_credential,
+ kim_identity_t *out_client_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_credential ) { err = param_error (1, "in_credential", "NULL"); }
+ if (!err && !out_client_identity) { err = param_error (2, "out_client_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_identity_create_from_krb5_principal (out_client_identity,
+ in_credential->context,
+ in_credential->creds->client);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_get_service_identity (kim_credential_t in_credential,
+ kim_identity_t *out_service_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_credential ) { err = param_error (1, "in_credential", "NULL"); }
+ if (!err && !out_service_identity) { err = param_error (2, "out_service_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_identity_create_from_krb5_principal (out_service_identity,
+ in_credential->context,
+ in_credential->creds->server);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_is_tgt (kim_credential_t in_credential,
+ kim_boolean_t *out_is_tgt)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_identity_t service = NULL;
+
+ if (!err && !in_credential) { err = param_error (1, "in_credential", "NULL"); }
+ if (!err && !out_is_tgt ) { err = param_error (2, "out_is_tgt", "NULL"); }
+
+ if (!err) {
+ err = kim_credential_get_service_identity (in_credential, &service);
+ }
+
+ if (!err) {
+ err = kim_identity_is_tgt_service (service, out_is_tgt);
+ }
+
+ kim_identity_free (&service);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_get_state (kim_credential_t in_credential,
+ kim_credential_state_t *out_state)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_time_t expiration_time = 0;
+ kim_time_t start_time = 0;
+ krb5_timestamp now = 0;
+
+ if (!err && !in_credential) { err = param_error (1, "in_credential", "NULL"); }
+ if (!err && !out_state ) { err = param_error (2, "out_state", "NULL"); }
+
+ if (!err) {
+ err = kim_credential_get_expiration_time (in_credential, &expiration_time);
+ }
+
+ if (!err) {
+ err = kim_credential_get_start_time (in_credential, &start_time);
+ }
+
+ if (!err) {
+ krb5_int32 usec;
+
+ err = krb5_error (krb5_us_timeofday (in_credential->context, &now, &usec));
+ }
+
+ if (!err) {
+ *out_state = kim_credentials_state_valid;
+
+ if (expiration_time <= now) {
+ *out_state = kim_credentials_state_expired;
+
+ } else if ((in_credential->creds->ticket_flags & TKT_FLG_POSTDATED) &&
+ (in_credential->creds->ticket_flags & TKT_FLG_INVALID)) {
+ if (start_time > now) {
+ *out_state = kim_credentials_state_not_yet_valid;
+ } else {
+ *out_state = kim_credentials_state_needs_validation;
+ }
+
+ } else if (in_credential->creds->addresses) { /* ticket contains addresses */
+ krb5_address **laddresses = NULL;
+
+ krb5_error_code code = krb5_os_localaddr (in_credential->context, &laddresses);
+ if (!code) { laddresses = NULL; }
+
+ if (laddresses) { /* assume valid if the local host has no addresses */
+ kim_boolean_t found_match = FALSE;
+ kim_count_t i = 0;
+
+ for (i = 0; in_credential->creds->addresses[0]; i++) {
+ if (krb5_address_search (in_credential->context,
+ in_credential->creds->addresses[i], laddresses)) {
+ found_match = TRUE;
+ break;
+ }
+ }
+
+ if (!found_match) {
+ *out_state = kim_credentials_state_address_mismatch;
+ }
+ }
+
+ if (laddresses) { krb5_free_addresses (in_credential->context, laddresses); }
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_get_start_time (kim_credential_t in_credential,
+ kim_time_t *out_start_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_credential) { err = param_error (1, "in_credential", "NULL"); }
+
+ if (!err) {
+ *out_start_time = (in_credential->creds->times.starttime ?
+ in_credential->creds->times.starttime :
+ in_credential->creds->times.authtime);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_get_expiration_time (kim_credential_t in_credential,
+ kim_time_t *out_expiration_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_credential) { err = param_error (1, "in_credential", "NULL"); }
+
+ if (!err) {
+ *out_expiration_time = in_credential->creds->times.endtime;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_get_renewal_expiration_time (kim_credential_t in_credential,
+ kim_time_t *out_renewal_expiration_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_credential) { err = param_error (1, "in_credential", "NULL"); }
+
+ if (!err) {
+ *out_renewal_expiration_time = in_credential->creds->times.renew_till;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_store (kim_credential_t in_credential,
+ kim_identity_t in_client_identity,
+ kim_ccache_t *out_ccache)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ krb5_context context = NULL;
+ krb5_ccache k5ccache = NULL;
+ kim_string_t type = NULL;
+ krb5_principal client_principal = NULL;
+ kim_boolean_t destroy_ccache_on_error = FALSE;
+
+ if (!err && !in_credential ) { err = param_error (1, "in_credential", "NULL"); }
+ if (!err && !in_client_identity) { err = param_error (2, "in_client_identity", "NULL"); }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&context));
+ }
+
+ if (!err) {
+ err = kim_identity_get_krb5_principal (in_client_identity, context,
+ &client_principal);
+ }
+
+ if (!err) {
+ char *environment_ccache = getenv ("KRB5CCNAME");
+
+ if (environment_ccache) {
+ err = krb5_error (krb5_cc_resolve (context, environment_ccache, &k5ccache));
+
+ } else {
+ kim_ccache_t ccache = NULL;
+
+ err = kim_ccache_create_from_client_identity (&ccache, in_client_identity);
+
+ if (!err) {
+ err = kim_ccache_get_krb5_ccache (ccache, context, &k5ccache);
+
+ } else if (kim_error_get_code (err) == KIM_NO_SUCH_PRINCIPAL_ECODE) {
+ /* Nothing to replace, toss error and create a new ccache */
+ kim_error_free (&err);
+ err = krb5_error (krb5_cc_new_unique (context, "API", NULL, &k5ccache));
+ if (!err) { destroy_ccache_on_error = TRUE; }
+ }
+
+ kim_ccache_free (&ccache);
+ }
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_initialize (in_credential->context,
+ k5ccache, client_principal));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_store_cred (in_credential->context,
+ k5ccache, in_credential->creds));
+ }
+
+#warning Call plugins here
+
+ if (!err && out_ccache) {
+ err = kim_ccache_create_from_krb5_ccache (out_ccache, context, k5ccache);
+ }
+
+ if (k5ccache) {
+ if (err && destroy_ccache_on_error) {
+ krb5_cc_destroy (in_credential->context, k5ccache);
+ } else {
+ krb5_cc_close (in_credential->context, k5ccache);
+ }
+ }
+ if (client_principal) { krb5_free_principal (context, client_principal); }
+ if (context ) { krb5_free_context (context); }
+ kim_string_free (&type);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_verify (kim_credential_t in_credential,
+ kim_identity_t in_service_identity,
+ kim_string_t in_keytab,
+ kim_boolean_t in_fail_if_no_service_key)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ krb5_context scontext = NULL;
+ krb5_principal service_principal = NULL;
+ krb5_keytab keytab = NULL;
+
+ if (!err && !in_credential) { err = param_error (1, "in_credential", "NULL"); }
+
+ if (!err) {
+ err = krb5_error (krb5_init_secure_context (&scontext));
+ }
+
+ if (!err && in_service_identity) {
+ err = kim_identity_get_krb5_principal (in_service_identity, scontext, &service_principal);
+ }
+
+ if (in_keytab) {
+ err = krb5_error (krb5_kt_resolve (scontext, in_keytab, &keytab));
+ }
+
+ if (!err) {
+ krb5_verify_init_creds_opt options;
+
+ /* That's "no key == fail" not "no fail" >.< */
+ krb5_verify_init_creds_opt_init (&options);
+ krb5_verify_init_creds_opt_set_ap_req_nofail (&options, in_fail_if_no_service_key);
+
+ err = krb5_error (krb5_verify_init_creds (scontext, in_credential->creds,
+ service_principal,
+ keytab,
+ NULL /* don't store creds in ccache */,
+ &options));
+
+ if (err && !service_principal && in_fail_if_no_service_key) {
+ /* If the service principal wasn't specified but we are supposed to fail without a key
+ we should walk the keytab trying to find one that succeeds. */
+ krb5_error_code code = 0;
+ kim_boolean_t verified = 0;
+ krb5_kt_cursor cursor = NULL;
+ krb5_keytab_entry entry;
+
+
+ if (!keytab) {
+ code = krb5_kt_default (scontext, &keytab);
+ }
+
+ if (!err) {
+ code = krb5_kt_start_seq_get (scontext, keytab, &cursor);
+ }
+
+ while (!code && !verified) {
+ kim_boolean_t free_entry = 0;
+
+ code = krb5_kt_next_entry (scontext, keytab, &entry, &cursor);
+ free_entry = !code; /* remember to free */
+
+ if (!code) {
+ code = krb5_verify_init_creds (scontext, in_credential->creds,
+ entry.principal /* get principal for the 1st entry */,
+ keytab,
+ NULL /* don't store creds in ccache */,
+ &options);
+ }
+
+ if (!code) {
+ verified = 1;
+ }
+
+ if (free_entry) { krb5_free_keytab_entry_contents (scontext, &entry); }
+ }
+
+ if (!code && verified) {
+ /* We found a key that verified! */
+ kim_error_free (&err);
+ }
+
+ if (cursor) { krb5_kt_end_seq_get (scontext, keytab, &cursor); }
+ }
+ }
+
+ if (keytab ) { krb5_kt_close (scontext, keytab); }
+ if (service_principal) { krb5_free_principal (scontext, service_principal); }
+ if (scontext ) { krb5_free_context (scontext); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_renew (kim_credential_t *io_credential,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t service_name = NULL;
+ krb5_ccache ccache = NULL;
+
+ if (!err && !io_credential) { err = param_error (1, "io_credential", "NULL"); }
+
+ if (!err) {
+ kim_options_t options = in_options;
+
+ if (!options) {
+ err = kim_options_create (&options);
+ }
+
+ if (!err) {
+ err = kim_options_get_service_name (options, &service_name);
+ }
+
+ if (options != in_options) { kim_options_free (&options); }
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_new_unique ((*io_credential)->context,
+ "MEMORY", NULL,
+ &ccache));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_initialize ((*io_credential)->context, ccache,
+ (*io_credential)->creds->client));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_store_cred ((*io_credential)->context, ccache,
+ (*io_credential)->creds));
+ }
+
+ if (!err) {
+ krb5_creds creds;
+ krb5_creds *renewed_creds = NULL;
+ kim_boolean_t free_creds = 0;
+
+ err = krb5_error (krb5_get_renewed_creds ((*io_credential)->context,
+ &creds, (*io_credential)->creds->client,
+ ccache, (char *) service_name));
+ if (!err) { free_creds = 1; }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_creds ((*io_credential)->context, &creds, &renewed_creds));
+ }
+
+ if (!err) {
+ /* replace the credentials */
+ krb5_free_creds ((*io_credential)->context, (*io_credential)->creds);
+ (*io_credential)->creds = renewed_creds;
+ }
+
+ if (free_creds) { krb5_free_cred_contents ((*io_credential)->context, &creds); }
+ }
+
+ if (ccache) { krb5_cc_destroy ((*io_credential)->context, ccache); }
+ kim_string_free (&service_name);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_credential_validate (kim_credential_t *io_credential,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t service_name = NULL;
+ krb5_ccache ccache = NULL;
+
+ if (!err && !io_credential) { err = param_error (1, "io_credential", "NULL"); }
+
+ if (!err) {
+ kim_options_t options = in_options;
+
+ if (!options) {
+ err = kim_options_create (&options);
+ }
+
+ if (!err) {
+ err = kim_options_get_service_name (options, &service_name);
+ }
+
+ if (options != in_options) { kim_options_free (&options); }
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_new_unique ((*io_credential)->context,
+ "MEMORY", NULL,
+ &ccache));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_initialize ((*io_credential)->context, ccache,
+ (*io_credential)->creds->client));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_cc_store_cred ((*io_credential)->context, ccache,
+ (*io_credential)->creds));
+ }
+
+ if (!err) {
+ krb5_creds creds;
+ krb5_creds *validated_creds = NULL;
+ kim_boolean_t free_creds = 0;
+
+ err = krb5_error (krb5_get_validated_creds ((*io_credential)->context,
+ &creds, (*io_credential)->creds->client,
+ ccache, (char *) service_name));
+ if (!err) { free_creds = 1; }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_creds ((*io_credential)->context, &creds, &validated_creds));
+ }
+
+ if (!err) {
+ /* replace the credentials */
+ krb5_free_creds ((*io_credential)->context, (*io_credential)->creds);
+ (*io_credential)->creds = validated_creds;
+ }
+
+ if (free_creds) { krb5_free_cred_contents ((*io_credential)->context, &creds); }
+ }
+
+ if (ccache) { krb5_cc_destroy ((*io_credential)->context, ccache); }
+ kim_string_free (&service_name);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_credential_free (kim_credential_t *io_credential)
+{
+ if (io_credential && *io_credential) {
+ if ((*io_credential)->context) {
+ if ((*io_credential)->creds) {
+ krb5_free_creds ((*io_credential)->context, (*io_credential)->creds);
+ }
+ krb5_free_context ((*io_credential)->context);
+ }
+ free (*io_credential);
+ *io_credential = NULL;
+ }
+}
diff --git a/src/kim/lib/kim_error.c b/src/kim/lib/kim_error.c
new file mode 100644
index 0000000..090204f
--- /dev/null
+++ b/src/kim/lib/kim_error.c
@@ -0,0 +1,244 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "kim_private.h"
+#include <com_err.h>
+#include <CredentialsCache.h>
+
+struct kim_error_opaque {
+ kim_error_code_t code;
+ kim_string_t message;
+};
+
+struct kim_error_opaque kim_no_memory_error_struct = { KIM_OUT_OF_MEMORY_ECODE, NULL, };
+kim_error_t kim_no_memory_error = &kim_no_memory_error_struct;
+
+struct kim_error_opaque kim_error_initializer = { KIM_NO_ERROR_ECODE, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_error_allocate (kim_error_t *out_error)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_error_t error = NULL;
+
+ if (!err) {
+ error = malloc (sizeof (*error));
+ if (!error) {
+ err = kim_no_memory_error;
+ } else {
+ *error = kim_error_initializer;
+ }
+ }
+
+ if (!err) {
+ *out_error = error;
+ error = NULL;
+ }
+
+ kim_error_free (&error);
+
+ return check_error (err);
+}
+
+#pragma mark -- Helper Functions --
+
+/* These helper functions exist so we get type checking on the most common errors */
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t _kim_error_create_for_param (kim_string_t in_function,
+ unsigned int in_argument_position,
+ kim_string_t in_argument_name,
+ kim_string_t in_invalid_value)
+{
+ return kim_error_create_from_code (KIM_PARAMETER_ECODE,
+ in_function,
+ in_argument_position,
+ in_argument_name,
+ in_invalid_value);
+}
+
+#pragma mark -- Generic Functions --
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_error_create_from_code (kim_error_code_t in_code,
+ ...)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ va_list args;
+
+ va_start (args, in_code);
+ err = kim_error_create_from_code_va (in_code, args);
+ va_end (args);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_error_create_from_code_va (kim_error_code_t in_code,
+ va_list in_args)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_error_t error = KIM_NO_ERROR;
+ kim_string_t message = NULL;
+
+ /* short circuit out of memory errors so we don't loop */
+ switch (in_code) {
+ case 0:
+ return KIM_NO_ERROR;
+
+ case KIM_OUT_OF_MEMORY_ECODE:
+ case ENOMEM:
+ case KRB5_CC_NOMEM:
+ case ccErrNoMem:
+// case klMemFullErr:
+// case memFullErr:
+ err = kim_no_memory_error;
+ break;
+ }
+
+ if (!err) {
+ err = kim_string_create_from_format_va_retcode (&message, error_message (in_code), in_args);
+ }
+
+ if (!err) {
+ err = kim_error_allocate (&error);
+ }
+
+ if (!err) {
+ error->code = in_code;
+ error->message = message;
+ message = NULL; /* take ownership */
+
+ err = error;
+ error = NULL; /* take ownership */
+ }
+
+ kim_error_free (&error);
+ kim_string_free (&message);
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_error_copy (kim_error_t *out_error,
+ kim_error_t in_error)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_error_t error = KIM_NO_ERROR;
+
+ if (!err && !out_error) { err = param_error (1, "out_error", "NULL"); }
+ if (!err && !in_error ) { err = param_error (2, "in_error", "NULL"); }
+
+ if (!err) {
+ if (in_error == kim_no_memory_error) {
+ error = kim_no_memory_error;
+
+ } else {
+ err = kim_error_allocate (&error);
+
+ if (!err) {
+ error->code = in_error->code;
+ if (in_error->message) {
+ err = kim_string_copy (&error->message, in_error->message);
+ }
+ }
+ }
+ }
+
+ if (!err) {
+ *out_error = error;
+ error = KIM_NO_ERROR;
+ }
+
+ kim_error_free (&error);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_code_t kim_error_get_code (kim_error_t in_error)
+{
+ if (!in_error) { /* KIM_NO_ERROR */
+ return KIM_NO_ERROR_ECODE;
+ } else {
+ return in_error->code;
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_string_t kim_error_get_display_string (kim_error_t in_error)
+{
+ if (!in_error) { /* KIM_NO_ERROR */
+ return error_message (KIM_NO_ERROR_ECODE);
+
+ } else if (in_error->message) {
+ return in_error->message;
+
+ } else {
+ /* Note that kim_no_memory_error will get here because its string is NULL */
+ return error_message (in_error->code);
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_error_free (kim_error_t *io_error)
+{
+ if (io_error && *io_error) {
+ if (*io_error != kim_no_memory_error) {
+ kim_string_free (&(*io_error)->message);
+ free (*io_error);
+ *io_error = KIM_NO_ERROR;
+ }
+ }
+}
+
+#pragma mark -- Debugging Functions --
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t _check_error (kim_error_t in_err,
+ kim_string_t in_function,
+ kim_string_t in_file,
+ int in_line)
+{
+ if (in_err) {
+ kim_error_code_t code = kim_error_get_code (in_err);
+ kim_string_t message = kim_error_get_display_string (in_err);
+
+ kim_debug_printf ("%s(): got %d ('%s') at %s: %d",
+ in_function, code, message, in_file, in_line);
+ }
+
+ return in_err;
+}
diff --git a/src/kim/lib/kim_error_code.et b/src/kim/lib/kim_error_code.et
new file mode 100644
index 0000000..c9f0330
--- /dev/null
+++ b/src/kim/lib/kim_error_code.et
@@ -0,0 +1,72 @@
+# Copyright 2005-2006 by the Massachusetts Institute of Technology.
+#
+# Export of this software from the United States of America may
+# require a specific license from the United States Government.
+# It is the responsibility of any person or organization contemplating
+# export to obtain such a license before exporting.
+#
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission. Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose. It is provided "as is" without express
+# or implied warranty.
+
+error_table_manager "Kerberos Identity Management"
+error_table KIM
+
+# Configuration and System Errors
+error_code KIM_OUT_OF_MEMORY_ECODE, "Out of memory"
+error_code KIM_PARAMETER_ECODE, "%s(): argument %d (%s) may not be %s. Please consult the KIM API documentation"
+error_code KIM_KRB5_INIT_FAILED_ECODE, "Unable to initialize Kerberos v5"
+error_code KIM_NO_REALMS_ECODE, "There are no Kerberos realms configured"
+error_code KIM_NO_SUCH_REALM_ECODE, "The realm '%s' is not in your configuration file or does not exist"
+
+index 25
+# Principal Errors
+error_code KIM_BAD_PRINCIPAL_STRING_ECODE, "'%s' is not a valid Kerberos principal"
+error_code KIM_BAD_COMPONENT_INDEX_ECODE, "Principal does not have a component at index %d"
+error_code KIM_PASSWORD_MISMATCH_ECODE, "New and verify passwords do not match"
+error_code KIM_INSECURE_PASSWORD_ECODE, "Your new password for '%s' is insecure; please pick another one"
+error_code KIM_PASSWORD_CHANGE_FAILED_ECODE, "Unable to change password for %s"
+
+index 50
+# Options Errors
+error_code KIM_BAD_OPTIONS_ECODE, "Invalid options"
+error_code KIM_BAD_OPTIONS_VALUE_ECODE, "Invalid value for Kerberos default login option"
+
+index 75
+# User Interface Errors
+error_code KIM_CAPS_LOCK_ECODE, "Password Incorrect (check your Caps Lock)"
+error_code KIM_USER_CANCELED_ECODE, "The user cancelled the operation"
+error_code KIM_NO_SERVER_ECODE, "Unable to launch or contact %s"
+error_code KIM_NO_GUI_ECODE, "Unable to display a graphical user interface from this environment"
+error_code KIM_NO_CLI_ECODE, "Unable to display a command line user interface from this environment"
+
+index 100
+# Preferences Errors
+error_code KIM_PREFERENCES_READ_ECODE, "Unable to read user preferences. The file may be missing, inaccessible or corrupted"
+error_code KIM_PREFERENCES_WRITE_ECODE, "Unable to write user preferences. The file may be inaccessible"
+error_code KIM_IDENTITY_NOT_IN_IDENTITIES_LIST, "Identity %s is not in the favorite identities list"
+error_code KIM_IDENTITY_ALREADY_IN_IDENTITIES_LIST, "Identity %s is already in the favorite identities list"
+error_code KIM_BAD_IDENTITY_INDEX_ECODE, "No identity at index %d in the favorite identities list"
+
+index 125
+# Cache Collection Errors
+error_code KIM_NO_SUCH_PRINCIPAL_ECODE, "Principal '%s' does not exist in the cache collection"
+error_code KIM_CANT_BECOME_DEFAULT_ECODE, "The credentials cache '%s' cannot become the system default ccache."
+error_code KIM_CREDENTIALS_EXPIRED_ECODE, "The Kerberos credentials for '%s' have expired"
+error_code KIM_NO_CREDENTIALS_ECODE, "You do not have Kerberos credentials for principal '%s'"
+error_code KIM_BAD_IP_ADDRESS_ECODE, "The IP addresses in the Kerberos credentials for '%s' do not match any of your computer's IP addresses"
+error_code KIM_NO_SUCH_CCACHE_ECODE, "The credentials cache '%s' does not exist"
+error_code KIM_BAD_HOST_CONFIGURATION_ECODE, "Unable to get local hostname or address information"
+error_code KIM_NEEDS_VALIDATION_ECODE, "The Kerberos credentials for '%s' need to be validated"
+
+end
diff --git a/src/kim/lib/kim_error_private.h b/src/kim/lib/kim_error_private.h
new file mode 100644
index 0000000..73a67fc
--- /dev/null
+++ b/src/kim/lib/kim_error_private.h
@@ -0,0 +1,55 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_ERROR_PRIVATE_H
+#define KIM_ERROR_PRIVATE_H
+
+#include <kim/kim.h>
+
+kim_error_t _kim_error_create_for_param (kim_string_t in_function,
+ unsigned int in_argument_position,
+ kim_string_t in_argument_name,
+ kim_string_t in_invalid_value);
+#define param_error(pos, name, value) _kim_error_create_for_param(__FUNCTION__, \
+ pos, name, value)
+
+kim_error_t kim_error_create_from_code (kim_error_code_t in_code,
+ ...);
+kim_error_t kim_error_create_from_code_va (kim_error_code_t in_code,
+ va_list args);
+
+#define ccapi_error(code) kim_error_create_from_code(code)
+#define krb5_error(code) kim_error_create_from_code(code)
+#define gss_error(code) kim_error_create_from_code(code)
+#define os_error(code) kim_error_create_from_code(code)
+
+kim_error_t _check_error (kim_error_t in_err,
+ kim_string_t in_function,
+ kim_string_t in_file,
+ int in_line);
+#define check_error(err) _check_error(err, __FUNCTION__, __FILE__, __LINE__)
+
+#endif /* KIM_ERROR_PRIVATE_H */
diff --git a/src/kim/lib/kim_identity.c b/src/kim/lib/kim_identity.c
new file mode 100644
index 0000000..abb1b64
--- /dev/null
+++ b/src/kim/lib/kim_identity.c
@@ -0,0 +1,544 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <krb5.h>
+#include <gssapi/gssapi.h>
+#include "kim_private.h"
+
+/* ------------------------------------------------------------------------ */
+
+struct kim_identity_opaque {
+ krb5_context context;
+ krb5_principal principal;
+};
+
+struct kim_identity_opaque kim_identity_initializer = { NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_identity_allocate (kim_identity_t *out_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_identity_t identity = NULL;
+
+ if (!err && !out_identity) { err = param_error (1, "out_identity", "NULL"); }
+
+ if (!err) {
+ identity = malloc (sizeof (*identity));
+ if (!identity) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ *identity = kim_identity_initializer;
+ *out_identity = identity;
+ identity = NULL;
+ }
+
+ kim_identity_free (&identity);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_create_from_string (kim_identity_t *out_identity,
+ kim_string_t in_string)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_identity_t identity = NULL;
+
+ if (!err && !out_identity) { err = param_error (1, "out_identity", "NULL"); }
+ if (!err && !in_string ) { err = param_error (2, "in_string", "NULL"); }
+
+ if (!err) {
+ err = kim_identity_allocate (&identity);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&identity->context));
+ }
+
+ if (!err) {
+ krb5_error_code code = krb5_parse_name (identity->context, in_string, &identity->principal);
+ if (code == KRB5_PARSE_MALFORMED) {
+ err = kim_error_create_from_code (KIM_BAD_PRINCIPAL_STRING_ECODE, in_string);
+ } else if (code) {
+ err = krb5_error (code);
+ }
+ }
+
+ if (!err) {
+#warning Run translator here
+ }
+
+ if (!err) {
+ *out_identity = identity;
+ identity = NULL;
+ }
+
+ if (identity) { kim_identity_free (&identity); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_create_from_components (kim_identity_t *out_identity,
+ kim_string_t in_realm,
+ kim_string_t in_1st_component,
+ ...)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_identity_t identity = NULL;
+ krb5_principal_data principal_data; /* allocated by KIM so can't be returned */
+
+ if (!err && !out_identity ) { err = param_error (1, "out_identity", "NULL"); }
+ if (!err && !in_realm ) { err = param_error (2, "in_realm", "NULL"); }
+ if (!err && !in_1st_component) { err = param_error (3, "in_1st_component", "NULL"); }
+
+ if (!err) {
+ err = kim_identity_allocate (&identity);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&identity->context));
+ }
+
+ if (!err) {
+ va_list args;
+ kim_count_t component_count = 1;
+
+ va_start (args, in_1st_component);
+ while (va_arg (args, kim_string_t)) { component_count++; }
+ va_end (args);
+
+ principal_data.length = component_count;
+ principal_data.data = (krb5_data *) malloc (component_count * sizeof (krb5_data));
+ if (!principal_data.data) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ va_list args;
+ krb5_int32 i;
+
+ krb5_princ_set_realm_length (context, &principal_data, strlen (in_realm));
+ krb5_princ_set_realm_data (context, &principal_data, (char *) in_realm);
+
+ va_start (args, in_1st_component);
+ for (i = 0; !err && (i < principal_data.length); i++) {
+ kim_string_t component = NULL;
+ if (i == 0) {
+ err = kim_string_copy (&component, in_1st_component);
+ } else {
+ err = kim_string_copy (&component, va_arg (args, kim_string_t));
+ }
+
+ if (!err) {
+ principal_data.data[i].data = (char *) component;
+ principal_data.data[i].length = strlen (component);
+ }
+ }
+ va_end (args);
+ }
+
+ if (!err) {
+ /* make a copy that has actually been allocated by the krb5
+ * library so krb5_free_principal can be called on it */
+ err = krb5_error (krb5_copy_principal (identity->context, &principal_data, &identity->principal));
+ }
+
+ if (!err) {
+#warning Run translator here
+ }
+
+ if (!err) {
+ *out_identity = identity;
+ identity = NULL;
+ }
+
+ if (principal_data.data) {
+ krb5_int32 i;
+
+ for (i = 0; i < principal_data.length; i++) {
+ kim_string_t component = principal_data.data[i].data;
+ kim_string_free (&component);
+ }
+ free (principal_data.data);
+ }
+ kim_identity_free (&identity);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_create_from_krb5_principal (kim_identity_t *out_identity,
+ krb5_context in_krb5_context,
+ krb5_principal in_krb5_principal)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_identity_t identity = NULL;
+
+ if (!err && !out_identity ) { err = param_error (1, "out_identity", "NULL"); }
+ if (!err && !in_krb5_principal) { err = param_error (2, "in_krb5_principal", "NULL"); }
+ if (!err && !in_krb5_context ) { err = param_error (3, "in_krb5_context", "NULL"); }
+
+ if (!err) {
+ err = kim_identity_allocate (&identity);
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&identity->context));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_principal (identity->context, in_krb5_principal,
+ &identity->principal));
+ }
+
+ if (!err) {
+#warning Run translator here
+ }
+
+ if (!err) {
+ *out_identity = identity;
+ identity = NULL;
+ }
+
+ kim_identity_free (&identity);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_copy (kim_identity_t *out_identity,
+ kim_identity_t in_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_identity_t identity = KIM_IDENTITY_ANY;
+
+ if (!err && !out_identity) { err = param_error (1, "out_identity", "NULL"); }
+
+ if (!err && in_identity != KIM_IDENTITY_ANY) {
+ err = kim_identity_allocate (&identity);
+
+ if (!err) {
+ err = krb5_error (krb5_init_context (&identity->context));
+ }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_principal (identity->context, in_identity->principal,
+ &identity->principal));
+ }
+ }
+
+ if (!err) {
+ *out_identity = identity;
+ identity = NULL;
+ }
+
+ kim_identity_free (&identity);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_compare (kim_identity_t in_identity,
+ kim_identity_t in_compare_to_identity,
+ kim_comparison_t *out_comparison)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_identity ) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !in_compare_to_identity) { err = param_error (2, "in_compare_to_identity", "NULL"); }
+ if (!err && !out_comparison ) { err = param_error (3, "out_comparison", "NULL"); }
+
+ if (!err) {
+ if (krb5_principal_compare (in_identity->context,
+ in_identity->principal,
+ in_compare_to_identity->principal)) {
+ *out_comparison = 0;
+ } else {
+ kim_string_t string = NULL;
+ kim_string_t compare_to_string = NULL;
+
+ err = kim_identity_get_string (in_identity, &string);
+
+ if (!err) {
+ err = kim_identity_get_string (in_compare_to_identity, &compare_to_string);
+ }
+
+ if (!err) {
+ err = kim_string_compare (string, compare_to_string, out_comparison);
+ }
+
+ kim_string_free (&string);
+ kim_string_free (&compare_to_string);
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_get_string (kim_identity_t in_identity,
+ kim_string_t *out_string)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ char *unparsed_name = NULL;
+
+ if (!err && !in_identity) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !out_string ) { err = param_error (2, "out_string", "NULL"); }
+
+ if (!err) {
+ err = krb5_error (krb5_unparse_name (in_identity->context,
+ in_identity->principal,
+ &unparsed_name));
+ }
+
+ if (!err) {
+ err = kim_string_copy (out_string, unparsed_name);
+ }
+
+ if (unparsed_name) { krb5_free_unparsed_name (in_identity->context, unparsed_name); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_get_display_string (kim_identity_t in_identity,
+ kim_string_t *out_display_string)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t string = NULL;
+
+ if (!err && !in_identity ) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !out_display_string) { err = param_error (2, "out_display_string", "NULL"); }
+
+ if (!err) {
+ err = kim_identity_get_string (in_identity, &string);
+ }
+
+ if (!err) {
+ kim_count_t i, j;
+ kim_count_t length = strlen (string) + 1; /* Copy the '\0' */
+ char *display_string = (char *) string; /* so we can modify it */
+
+ /* In place copy, skipping escaped separators.
+ * Note that we do not want to remove other escaped characters
+ * (tab, break, newline, NULL) because they are less readable
+ * when unescaped (and NULL isn't a valid string character). */
+ for (i = 0, j = 0; i < length; i++) {
+ if (string[i] == '\\') {
+ switch (string[i + 1]) {
+ case '/': /* component separator */
+ case '@': /* realm separator */
+ continue; /* skip the '\' */
+ }
+ }
+
+ display_string[j++] = string[i]; /* Copy this char */
+ }
+
+ *out_display_string = string;
+ string = NULL;
+ }
+
+ if (string) { kim_string_free (&string); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_get_realm (kim_identity_t in_identity,
+ kim_string_t *out_realm_string)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_identity ) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !out_realm_string) { err = param_error (2, "out_realm_string", "NULL"); }
+
+ if (!err) {
+ krb5_data *realm = krb5_princ_realm (in_identity->context, in_identity->principal);
+
+ err = kim_string_create_from_buffer (out_realm_string, realm->data, realm->length);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_get_number_of_components (kim_identity_t in_identity,
+ kim_count_t *out_number_of_components)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_identity ) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !out_number_of_components) { err = param_error (2, "out_number_of_components", "NULL"); }
+
+ if (!err) {
+ *out_number_of_components = krb5_princ_size (in_identity->context, in_identity->principal);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_get_component_at_index (kim_identity_t in_identity,
+ kim_count_t in_index,
+ kim_string_t *out_component_string)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ krb5_data *component = NULL;
+
+ if (!err && !in_identity ) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !out_component_string) { err = param_error (3, "out_component_string", "NULL"); }
+
+ if (!err) {
+ krb5_int32 i = in_index;
+ component = krb5_princ_component (in_identity->context, in_identity->principal, i);
+ if (!component) { err = kim_error_create_from_code (KIM_BAD_COMPONENT_INDEX_ECODE, i); }
+ }
+
+ if (!err) {
+ err = kim_string_create_from_buffer (out_component_string, component->data, component->length);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_get_krb5_principal (kim_identity_t in_identity,
+ krb5_context in_krb5_context,
+ krb5_principal *out_krb5_principal)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_identity ) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !in_krb5_context ) { err = param_error (2, "in_krb5_context", "NULL"); }
+ if (!err && !out_krb5_principal) { err = param_error (3, "out_krb5_principal", "NULL"); }
+
+ if (!err) {
+ err = krb5_error (krb5_copy_principal (in_identity->context,
+ in_identity->principal,
+ out_krb5_principal));
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_get_gss_name (kim_identity_t in_identity,
+ gss_name_t *out_gss_name)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_identity ) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !out_gss_name) { err = param_error (2, "out_gss_name", "NULL"); }
+
+ if (!err) {
+#warning kim_identity_get_gss_name not implemented
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_is_tgt_service (kim_identity_t in_identity,
+ kim_boolean_t *out_is_tgt_service)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_identity ) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !out_is_tgt_service) { err = param_error (2, "out_is_tgt_service", "NULL"); }
+
+ if (!err) {
+ kim_count_t count = krb5_princ_size (in_identity->context, in_identity->principal);
+ krb5_data *name = krb5_princ_name (in_identity->context, in_identity->principal);
+
+ /* krbtgt/<REALM1>@<REALM2> (usually REALM1 == REALM2, but not always) */
+ *out_is_tgt_service = ((count == 2) &&
+ (strlen (KRB5_TGS_NAME) == name->length) &&
+ (strncmp (name->data, KRB5_TGS_NAME, name->length) == 0));
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_change_password (kim_identity_t in_identity,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_identity) { err = param_error (1, "in_identity", "NULL"); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_identity_change_password_to_password (kim_identity_t in_identity,
+ kim_options_t in_options,
+ kim_string_t in_new_password)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_identity ) { err = param_error (1, "in_identity", "NULL"); }
+ if (!err && !in_new_password) { err = param_error (3, "in_new_password", "NULL"); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_identity_free (kim_identity_t *io_identity)
+{
+ if (io_identity && *io_identity) {
+ kim_identity_t identity = *io_identity;
+
+ if (identity->context) {
+ if (identity->principal) {
+ krb5_free_principal (identity->context, identity->principal);
+ }
+ krb5_free_context (identity->context);
+ }
+
+ free (identity);
+ *io_identity = NULL;
+ }
+}
diff --git a/src/kim/lib/kim_identity_private.h b/src/kim/lib/kim_identity_private.h
new file mode 100644
index 0000000..f638707
--- /dev/null
+++ b/src/kim/lib/kim_identity_private.h
@@ -0,0 +1,38 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_IDENTITY_PRIVATE_H
+#define KIM_IDENTITY_PRIVATE_H
+
+#include <kim/kim.h>
+#include "kim_library_private.h"
+
+kim_error_t kim_os_identity_create_for_username (kim_identity_t *out_identity);
+
+kim_error_t kim_identity_is_tgt_service (kim_identity_t in_identity,
+ kim_boolean_t *out_is_tgt_service);
+
+#endif /* KIM_IDENTITY_PRIVATE_H */
diff --git a/src/kim/lib/kim_library.c b/src/kim/lib/kim_library.c
new file mode 100644
index 0000000..7024861
--- /dev/null
+++ b/src/kim/lib/kim_library.c
@@ -0,0 +1,214 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#define KRB5_PRIVATE 1
+
+#include <pthread.h>
+#include <stdarg.h>
+#include <krb5/krb5.h>
+#include <profile.h>
+
+#include "kim_private.h"
+#include "kim_os_private.h"
+
+/* ------------------------------------------------------------------------ */
+
+void __kim_library_debug_printf (kim_string_t in_function,
+ kim_string_t in_format,
+ ...)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t format = NULL;
+ kim_string_t string = NULL;
+
+ if (!err && !in_function) { err = param_error (1, "in_function", "NULL"); }
+ if (!err && !in_format ) { err = param_error (2, "in_format", "NULL"); }
+
+ if (!err) {
+ err = kim_string_create_from_format (&format, "%s(): %s", in_function, in_format);
+ }
+
+ if (!err) {
+ va_list args;
+ va_start (args, in_format);
+ err = kim_string_create_from_format_va (&string, format, args);
+ va_end (args);
+ }
+
+ if (!err) {
+ kim_os_library_debug_print (string);
+ }
+
+ kim_string_free (&format);
+ kim_string_free (&string);
+ kim_error_free (&err);
+}
+
+#pragma mark -- Allow Home Directory Access --
+
+static pthread_mutex_t g_allow_home_directory_access_mutex = PTHREAD_MUTEX_INITIALIZER;
+kim_boolean_t g_allow_home_directory_access = TRUE;
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_library_set_allow_home_directory_access (kim_boolean_t in_allow_access)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ int mutex_err = pthread_mutex_lock (&g_allow_home_directory_access_mutex);
+ if (mutex_err) { err = os_error (mutex_err); }
+
+ if (!err) {
+ g_allow_home_directory_access = in_allow_access;
+ }
+
+ if (!mutex_err) { pthread_mutex_unlock (&g_allow_home_directory_access_mutex); }
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_library_get_allow_home_directory_access (kim_boolean_t *out_allow_access)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ int mutex_err = 0;
+
+ if (!err && !out_allow_access) { err = param_error (3, "out_allow_access", "NULL"); }
+
+ if (!err) {
+ mutex_err = pthread_mutex_lock (&g_allow_home_directory_access_mutex);;
+ if (mutex_err) { err = os_error (mutex_err); }
+ }
+
+ if (!err) {
+ *out_allow_access = g_allow_home_directory_access;
+ }
+
+ if (!mutex_err) { pthread_mutex_unlock (&g_allow_home_directory_access_mutex); }
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_boolean_t kim_library_allow_home_directory_access (void)
+{
+ kim_boolean_t allow_access = FALSE;
+ kim_error_t err = kim_library_get_allow_home_directory_access (&allow_access);
+
+ kim_error_free (&err);
+
+ return allow_access;
+}
+
+
+#pragma mark -- Allow Automatic Prompting --
+
+static pthread_mutex_t g_allow_automatic_prompting_mutex = PTHREAD_MUTEX_INITIALIZER;
+kim_boolean_t g_allow_automatic_prompting = TRUE;
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_library_set_allow_automatic_prompting (kim_boolean_t in_allow_automatic_prompting)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ int mutex_err = pthread_mutex_lock (&g_allow_automatic_prompting_mutex);
+ if (mutex_err) { err = os_error (mutex_err); }
+
+ if (!err) {
+ g_allow_automatic_prompting = in_allow_automatic_prompting;
+ }
+
+ if (!mutex_err) { pthread_mutex_unlock (&g_allow_automatic_prompting_mutex); }
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_library_get_allow_automatic_prompting (kim_boolean_t *out_allow_automatic_prompting)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ int mutex_err = 0;
+
+ if (!err && !out_allow_automatic_prompting) { err = param_error (3, "out_allow_automatic_prompting", "NULL"); }
+
+ if (!err) {
+ mutex_err = pthread_mutex_lock (&g_allow_automatic_prompting_mutex);;
+ if (mutex_err) { err = os_error (mutex_err); }
+ }
+
+ if (!err) {
+ *out_allow_automatic_prompting = g_allow_automatic_prompting;
+ }
+
+ if (!mutex_err) { pthread_mutex_unlock (&g_allow_automatic_prompting_mutex); }
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_boolean_t kim_library_allow_automatic_prompting (void)
+{
+ kim_boolean_t allow_automatic_prompting = TRUE;
+ kim_error_t err = kim_library_get_allow_automatic_prompting (&allow_automatic_prompting);
+
+ if (allow_automatic_prompting && getenv ("KERBEROSLOGIN_NEVER_PROMPT")) {
+ kim_debug_printf ("KERBEROSLOGIN_NEVER_PROMPT is set.");
+ allow_automatic_prompting = FALSE;
+ }
+
+ if (allow_automatic_prompting && getenv ("KIM_NEVER_PROMPT")) {
+ kim_debug_printf ("KIM_NEVER_PROMPT is set.");
+ allow_automatic_prompting = FALSE;
+ }
+
+ if (allow_automatic_prompting) {
+ /* Make sure there is at least 1 config file. We don't support DNS
+ * domain-realm lookup, so if there is no config, Kerberos won't work. */
+
+ kim_boolean_t kerberos_config_exists = FALSE;
+ char **files = NULL;
+ profile_t profile = NULL;
+
+ if (krb5_get_default_config_files (&files) == 0) {
+ if (profile_init ((const_profile_filespec_t *) files, &profile) == 0) {
+ kerberos_config_exists = TRUE;
+ }
+ }
+
+ if (!kerberos_config_exists) {
+ kim_debug_printf ("No valid config file.");
+ allow_automatic_prompting = FALSE;
+ }
+
+ if (profile) { profile_abandon (profile); }
+ if (files ) { krb5_free_config_files (files); }
+ }
+
+ kim_error_free (&err);
+
+ return allow_automatic_prompting;
+}
diff --git a/src/kim/lib/kim_library_private.h b/src/kim/lib/kim_library_private.h
new file mode 100644
index 0000000..afe24bc
--- /dev/null
+++ b/src/kim/lib/kim_library_private.h
@@ -0,0 +1,54 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_LIBRARY_PRIVATE_H
+#define KIM_LIBRARY_PRIVATE_H
+
+#include <kim/kim.h>
+
+
+#define kim_debug_printf(format, ...) __kim_library_debug_printf(__FUNCTION__, format, ## __VA_ARGS__)
+void __kim_library_debug_printf (kim_string_t in_function,
+ kim_string_t in_format,
+ ...);
+
+kim_error_t kim_library_set_allow_home_directory_access (kim_boolean_t in_allow_access);
+
+kim_error_t kim_library_get_allow_home_directory_access (kim_boolean_t *out_allow_access);
+
+kim_boolean_t kim_library_allow_home_directory_access (void);
+
+kim_error_t kim_library_set_allow_automatic_prompting (kim_boolean_t in_allow_automatic_prompting);
+
+kim_error_t kim_library_get_allow_automatic_prompting (kim_boolean_t *out_allow_automatic_prompting);
+
+kim_boolean_t kim_library_allow_automatic_prompting (void);
+
+void kim_os_library_debug_print (kim_string_t in_string);
+
+kim_boolean_t kim_os_library_caller_is_server (void);
+
+#endif /* KIM_LIBRARY_PRIVATE_H */
diff --git a/src/kim/lib/kim_options.c b/src/kim/lib/kim_options.c
new file mode 100644
index 0000000..c68d4a5
--- /dev/null
+++ b/src/kim/lib/kim_options.c
@@ -0,0 +1,694 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "kim_private.h"
+
+/* ------------------------------------------------------------------------ */
+
+struct kim_options_opaque {
+ kim_prompt_callback_t prompt_callback;
+ const void *prompt_callback_data;
+#warning add prompt responses here
+ kim_time_t start_time;
+ kim_lifetime_t lifetime;
+ kim_boolean_t renewable;
+ kim_lifetime_t renewal_lifetime;
+ kim_boolean_t forwardable;
+ kim_boolean_t proxiable;
+ kim_boolean_t addressless;
+ kim_string_t service_name;
+};
+
+struct kim_options_opaque kim_options_initializer = {
+ NULL, NULL,
+ 0,
+ kim_default_lifetime,
+ kim_default_renewable,
+ kim_default_renewal_lifetime,
+ kim_default_forwardable,
+ kim_default_proxiable,
+ kim_default_addressless,
+ NULL };
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_options_allocate (kim_options_t *out_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_options_t options = NULL;
+
+ if (!err && !out_options) { err = param_error (1, "out_options", "NULL"); }
+
+ if (!err) {
+ options = malloc (sizeof (*options));
+ if (!options) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ *options = kim_options_initializer;
+ *out_options = options;
+ options = NULL;
+ }
+
+ kim_options_free (&options);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_create_from_defaults (kim_options_t *out_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_options_t options = NULL;
+
+ if (!err && !out_options) { err = param_error (1, "out_options", "NULL"); }
+
+ if (!err) {
+ err = kim_options_allocate (&options);
+ }
+
+ if (!err) {
+ *out_options = options;
+ options = NULL;
+ }
+
+ kim_options_free (&options);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_create (kim_options_t *out_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_preferences_t preferences = NULL;
+
+ if (!err && !out_options) { err = param_error (1, "out_options", "NULL"); }
+
+ if (!err) {
+ err = kim_preferences_create (&preferences);
+ }
+
+ if (!err) {
+ err = kim_preferences_get_options (preferences, out_options);
+ }
+
+ kim_preferences_free (&preferences);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_copy (kim_options_t *out_options,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_options_t options = NULL;
+
+ if (!err && !out_options) { err = param_error (1, "out_options", "NULL"); }
+ if (!err && !in_options ) { err = param_error (2, "in_options", "NULL"); }
+
+ if (!err) {
+ err = kim_options_allocate (&options);
+ }
+
+ if (!err) {
+ options->prompt_callback = in_options->prompt_callback;
+ options->prompt_callback_data = in_options->prompt_callback_data;
+#warning copy prompt responses here
+ }
+
+ if (!err) {
+ options->start_time = in_options->start_time;
+ options->lifetime = in_options->lifetime;
+ options->renewable = in_options->renewable;
+ options->renewal_lifetime = in_options->renewal_lifetime;
+ options->forwardable = in_options->forwardable;
+ options->proxiable = in_options->proxiable;
+ options->addressless = in_options->addressless;
+
+ if (in_options->service_name) {
+ err = kim_string_copy (&options->service_name, in_options->service_name);
+ }
+ }
+
+ if (!err) {
+ *out_options = options;
+ options = NULL;
+ }
+
+ kim_options_free (&options);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_prompt_callback (kim_options_t io_options,
+ kim_prompt_callback_t in_prompt_callback)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+
+ if (!err) {
+ io_options->prompt_callback = in_prompt_callback;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_prompt_callback (kim_options_t in_options,
+ kim_prompt_callback_t *out_prompt_callback)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_prompt_callback) { err = param_error (2, "out_prompt_callback", "NULL"); }
+
+ if (!err) {
+ *out_prompt_callback = in_options->prompt_callback;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_data (kim_options_t io_options,
+ const void *in_data)
+
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+
+ if (!err) {
+ io_options->prompt_callback_data = in_data;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_data (kim_options_t in_options,
+ const void **out_data)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_data ) { err = param_error (2, "out_data", "NULL"); }
+
+ if (!err) {
+ *out_data = in_options->prompt_callback_data;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_prompt_response (kim_options_t io_options,
+ kim_prompt_type_t in_prompt_type,
+ void *in_response)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options ) { err = param_error (1, "io_options", "NULL"); }
+ if (!err && !in_response) { err = param_error (2, "in_response", "NULL"); }
+
+ if (!err) {
+#warning kim_options_set_prompt_response unimplemented
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_prompt_response (kim_options_t in_options,
+ kim_prompt_type_t in_prompt_type,
+ void **out_response)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_response) { err = param_error (2, "out_response", "NULL"); }
+
+ if (!err) {
+#warning kim_options_get_prompt_response unimplemented
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_start_time (kim_options_t io_options,
+ kim_time_t in_start_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+
+ if (!err) {
+ io_options->start_time = in_start_time;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_start_time (kim_options_t in_options,
+ kim_time_t *out_start_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_start_time) { err = param_error (2, "out_start_time", "NULL"); }
+
+ if (!err) {
+ *out_start_time = in_options->start_time;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_lifetime (kim_options_t io_options,
+ kim_lifetime_t in_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+
+ if (!err) {
+ io_options->lifetime = in_lifetime;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_lifetime (kim_options_t in_options,
+ kim_lifetime_t *out_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_lifetime) { err = param_error (2, "out_lifetime", "NULL"); }
+
+ if (!err) {
+ *out_lifetime = in_options->lifetime;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_renewable (kim_options_t io_options,
+ kim_boolean_t in_renewable)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+
+ if (!err) {
+ io_options->renewable = in_renewable;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_renewable (kim_options_t in_options,
+ kim_boolean_t *out_renewable)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_renewable) { err = param_error (2, "out_renewable", "NULL"); }
+
+ if (!err) {
+ *out_renewable = in_options->renewable;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_renewal_lifetime (kim_options_t io_options,
+ kim_lifetime_t in_renewal_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+
+ if (!err) {
+ io_options->renewal_lifetime = in_renewal_lifetime;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_renewal_lifetime (kim_options_t in_options,
+ kim_lifetime_t *out_renewal_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_renewal_lifetime) { err = param_error (2, "out_renewal_lifetime", "NULL"); }
+
+ if (!err) {
+ *out_renewal_lifetime = in_options->renewal_lifetime;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_forwardable (kim_options_t io_options,
+ kim_boolean_t in_forwardable)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+
+ if (!err) {
+ io_options->forwardable = in_forwardable;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_forwardable (kim_options_t in_options,
+ kim_boolean_t *out_forwardable)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_forwardable) { err = param_error (2, "out_forwardable", "NULL"); }
+
+ if (!err) {
+ *out_forwardable = in_options->forwardable;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_proxiable (kim_options_t io_options,
+ kim_boolean_t in_proxiable)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+
+ if (!err) {
+ io_options->proxiable = in_proxiable;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_proxiable (kim_options_t in_options,
+ kim_boolean_t *out_proxiable)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_proxiable) { err = param_error (2, "out_proxiable", "NULL"); }
+
+ if (!err) {
+ *out_proxiable = in_options->proxiable;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_addressless (kim_options_t io_options,
+ kim_boolean_t in_addressless)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+
+ if (!err) {
+ io_options->addressless = in_addressless;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_addressless (kim_options_t in_options,
+ kim_boolean_t *out_addressless)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_addressless) { err = param_error (2, "out_addressless", "NULL"); }
+
+ if (!err) {
+ *out_addressless = in_options->addressless;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_set_service_name (kim_options_t io_options,
+ kim_string_t in_service_name)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t service_name = NULL;
+
+ if (!err && !io_options ) { err = param_error (1, "io_options", "NULL"); }
+ if (!err && !in_service_name) { err = param_error (2, "in_service_name", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (&service_name, in_service_name);
+ }
+
+ if (!err) {
+ kim_string_free (&io_options->service_name);
+ io_options->service_name = service_name;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_service_name (kim_options_t in_options,
+ kim_string_t *out_service_name)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !out_service_name) { err = param_error (2, "out_service_name", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (out_service_name, in_options->service_name);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_get_init_cred_options (kim_options_t in_options,
+ krb5_context in_context,
+ krb5_get_init_creds_opt **out_init_cred_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ krb5_get_init_creds_opt *init_cred_options;
+ krb5_address **addresses = NULL;
+
+ if (!err && !in_options ) { err = param_error (1, "in_options", "NULL"); }
+ if (!err && !in_context ) { err = param_error (2, "in_context", "NULL"); }
+ if (!err && !out_init_cred_options) { err = param_error (3, "out_init_cred_options", "NULL"); }
+
+ if (!err && !in_options->addressless) {
+ err = krb5_error (krb5_os_localaddr (in_context, &addresses));
+ }
+
+ if (!err) {
+ krb5_get_init_creds_opt_alloc (in_context, &init_cred_options);
+ krb5_get_init_creds_opt_set_tkt_life (init_cred_options, in_options->lifetime);
+ krb5_get_init_creds_opt_set_renew_life (init_cred_options, in_options->renewable ? in_options->renewal_lifetime : 0);
+ krb5_get_init_creds_opt_set_forwardable (init_cred_options, in_options->forwardable);
+ krb5_get_init_creds_opt_set_proxiable (init_cred_options, in_options->proxiable);
+ krb5_get_init_creds_opt_set_address_list (init_cred_options, addresses);
+
+ *out_init_cred_options = init_cred_options;
+ init_cred_options = NULL;
+ addresses = NULL;
+ }
+
+ if (init_cred_options) { krb5_get_init_creds_opt_free (in_context, init_cred_options); }
+ if (addresses ) { krb5_free_addresses (in_context, addresses); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_options_free_init_cred_options (krb5_context in_context,
+ krb5_get_init_creds_opt **io_init_cred_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_context) { err = param_error (1, "in_context", "NULL"); }
+
+ if (!err && io_init_cred_options && *io_init_cred_options) {
+ if ((*io_init_cred_options)->address_list) {
+ krb5_free_addresses (in_context, (*io_init_cred_options)->address_list);
+ }
+ krb5_get_init_creds_opt_free (in_context, *io_init_cred_options);
+ *io_init_cred_options = NULL;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_options_free (kim_options_t *io_options)
+{
+ if (io_options && *io_options) {
+ kim_string_free (&(*io_options)->service_name);
+ free (*io_options);
+ *io_options = NULL;
+ }
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_code_t kim_prompt_callback_default (kim_options_t *io_options,
+ kim_prompt_type_t in_type,
+ kim_string_t in_title,
+ kim_string_t in_message,
+ kim_string_t in_description,
+ void **out_reply)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_error_code_t code = KIM_NO_ERROR_ECODE;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+ if (!err && !out_reply ) { err = param_error (6, "out_reply", "NULL"); }
+
+ if (!err) {
+ }
+
+ code = kim_error_get_code (check_error (err));
+ kim_error_free (&err);
+ return code;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_code_t kim_prompt_callback_gui (kim_options_t *io_options,
+ kim_prompt_type_t in_type,
+ kim_string_t in_title,
+ kim_string_t in_message,
+ kim_string_t in_description,
+ void **out_reply)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_error_code_t code = KIM_NO_ERROR_ECODE;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+ if (!err && !out_reply ) { err = param_error (6, "out_reply", "NULL"); }
+
+ if (!err) {
+ }
+
+ code = kim_error_get_code (check_error (err));
+ kim_error_free (&err);
+ return code;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_code_t kim_prompt_callback_cli (kim_options_t *io_options,
+ kim_prompt_type_t in_type,
+ kim_string_t in_title,
+ kim_string_t in_message,
+ kim_string_t in_description,
+ void **out_reply)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_error_code_t code = KIM_NO_ERROR_ECODE;
+
+ if (!err && !io_options) { err = param_error (1, "io_options", "NULL"); }
+ if (!err && !out_reply ) { err = param_error (6, "out_reply", "NULL"); }
+
+ if (!err) {
+ }
+
+ code = kim_error_get_code (check_error (err));
+ kim_error_free (&err);
+ return code;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_code_t kim_prompt_callback_none (kim_options_t *io_options,
+ kim_prompt_type_t in_type,
+ kim_string_t in_title,
+ kim_string_t in_message,
+ kim_string_t in_description,
+ void **out_reply)
+{
+ return KIM_USER_CANCELED_ECODE;
+}
diff --git a/src/kim/lib/kim_options_private.h b/src/kim/lib/kim_options_private.h
new file mode 100644
index 0000000..ce75e48
--- /dev/null
+++ b/src/kim/lib/kim_options_private.h
@@ -0,0 +1,41 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_OPTIONS_PRIVATE_H
+#define KIM_OPTIONS_PRIVATE_H
+
+#include <kim/kim.h>
+
+kim_error_t kim_options_create_from_defaults (kim_options_t *out_options);
+
+kim_error_t kim_options_get_init_cred_options (kim_options_t in_options,
+ krb5_context in_context,
+ krb5_get_init_creds_opt **out_init_cred_options);
+
+kim_error_t kim_options_free_init_cred_options (krb5_context in_context,
+ krb5_get_init_creds_opt **io_init_cred_options);
+
+#endif /* KIM_OPTIONS_PRIVATE_H */
diff --git a/src/kim/lib/kim_preferences.c b/src/kim/lib/kim_preferences.c
new file mode 100644
index 0000000..cf2ad8f
--- /dev/null
+++ b/src/kim/lib/kim_preferences.c
@@ -0,0 +1,1120 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "kim_private.h"
+
+#pragma mark -- KIM Favorite Realms --
+
+struct kim_favorite_identities_opaque {
+ kim_count_t count;
+ kim_identity_t *identities;
+};
+
+struct kim_favorite_identities_opaque kim_favorite_identities_initializer = { 0, NULL };
+struct kim_favorite_identities_opaque kim_empty_favorite_identities_struct = { 0, NULL };
+const kim_favorite_identities_t kim_empty_favorite_identities = &kim_empty_favorite_identities_struct;
+
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_favorite_identities_allocate (kim_favorite_identities_t *out_favorite_identities)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_favorite_identities_t favorite_identities = NULL;
+
+ if (!err && !out_favorite_identities) { err = param_error (1, "out_favorite_identities", "NULL"); }
+
+ if (!err) {
+ favorite_identities = malloc (sizeof (*favorite_identities));
+ if (!favorite_identities) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ *favorite_identities = kim_favorite_identities_initializer;
+ *out_favorite_identities = favorite_identities;
+ favorite_identities = NULL;
+ }
+
+ kim_favorite_identities_free (&favorite_identities);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_favorite_identities_resize (kim_favorite_identities_t io_favorite_identities,
+ kim_count_t in_new_count)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_favorite_identities) { err = param_error (1, "io_favorite_identities", "NULL"); }
+
+ if (!err && io_favorite_identities->count != in_new_count) {
+ kim_identity_t *identities = NULL;
+
+ if (in_new_count == 0) {
+ if (io_favorite_identities->identities) {
+ free (io_favorite_identities->identities);
+ }
+ } else {
+ if (!io_favorite_identities->identities) {
+ identities = malloc (sizeof (*identities) * in_new_count);
+ } else {
+ identities = realloc (io_favorite_identities->identities,
+ sizeof (*identities) * in_new_count);
+ }
+ if (!identities) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ io_favorite_identities->count = in_new_count;
+ io_favorite_identities->identities = identities;
+ identities = NULL;
+ }
+
+ if (identities) { free (identities); }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_favorite_identities_create (kim_favorite_identities_t *out_favorite_identities)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_favorite_identities_t favorite_identities = NULL;
+
+ if (!err && !out_favorite_identities) { err = param_error (1, "out_favorite_identities", "NULL"); }
+
+ if (!err) {
+ err = kim_favorite_identities_allocate (&favorite_identities);
+ }
+
+ if (!err) {
+ *out_favorite_identities = favorite_identities;
+ favorite_identities = NULL;
+ }
+
+ kim_favorite_identities_free (&favorite_identities);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_favorite_identities_copy (kim_favorite_identities_t *out_favorite_identities,
+ kim_favorite_identities_t in_favorite_identities)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_favorite_identities_t favorite_identities = NULL;
+
+ if (!err && !out_favorite_identities) { err = param_error (1, "out_favorite_identities", "NULL"); }
+ if (!err && !in_favorite_identities ) { err = param_error (2, "in_favorite_identities", "NULL"); }
+
+ if (!err) {
+ err = kim_favorite_identities_allocate (&favorite_identities);
+ }
+
+ if (!err) {
+ err = kim_favorite_identities_resize (favorite_identities, in_favorite_identities->count);
+ }
+
+ if (!err) {
+ kim_count_t i;
+
+ for (i = 0; !err && i < favorite_identities->count; i++) {
+ err = kim_identity_copy (&favorite_identities->identities[i],
+ in_favorite_identities->identities[i]);
+ }
+ }
+
+ if (!err) {
+ *out_favorite_identities = favorite_identities;
+ favorite_identities = NULL;
+ }
+
+ kim_favorite_identities_free (&favorite_identities);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_favorite_identities_get_number_of_identities (kim_favorite_identities_t in_favorite_identities,
+ kim_count_t *out_number_of_identities)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_favorite_identities ) { err = param_error (1, "in_favorite_identities", "NULL"); }
+ if (!err && !out_number_of_identities) { err = param_error (2, "out_number_of_identities", "NULL"); }
+
+ if (!err) {
+ *out_number_of_identities = in_favorite_identities->count;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_favorite_identities_get_identity_at_index (kim_favorite_identities_t in_favorite_identities,
+ kim_count_t in_index,
+ kim_identity_t *out_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_favorite_identities) { err = param_error (1, "in_favorite_identities", "NULL"); }
+ if (!err && !out_identity ) { err = param_error (3, "out_identity", "NULL"); }
+
+ if (!err) {
+ if (in_index >= in_favorite_identities->count) {
+ err = kim_error_create_from_code (KIM_BAD_IDENTITY_INDEX_ECODE, in_index);
+ }
+ }
+
+ if (!err) {
+ err = kim_identity_copy (out_identity, in_favorite_identities->identities[in_index]);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_favorite_identities_add_identity (kim_favorite_identities_t io_favorite_identities,
+ kim_identity_t in_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_identity_t identity = NULL;
+ kim_count_t insert_at = 0;
+
+ if (!err && !io_favorite_identities) { err = param_error (1, "io_favorite_identities", "NULL"); }
+ if (!err && !in_identity ) { err = param_error (2, "in_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_identity_copy (&identity, in_identity);
+ }
+
+ if (!err) {
+ kim_count_t i;
+
+ for (i = 0; !err && i < io_favorite_identities->count; i++) {
+ kim_comparison_t identity_comparison = 0;
+
+ err = kim_identity_compare (in_identity, io_favorite_identities->identities[i], &identity_comparison);
+
+ if (!err) {
+ if (kim_comparison_is_greater_than (identity_comparison)) {
+ break; /* found the first greater one so insert here */
+
+ } else if (kim_comparison_is_equal_to (identity_comparison)) {
+ /* already in list */
+ kim_string_t display_string = NULL;
+
+ err = kim_identity_get_display_string (in_identity, &display_string);
+
+ if (!err) {
+ err = kim_error_create_from_code (KIM_IDENTITY_ALREADY_IN_IDENTITIES_LIST,
+ display_string);
+ }
+
+ kim_string_free (&display_string);
+ }
+ }
+ }
+
+ insert_at = i; /* Remember where we are going to insert */
+ }
+
+ if (!err) {
+ err = kim_favorite_identities_resize (io_favorite_identities, io_favorite_identities->count + 1);
+ }
+
+ if (!err) {
+ kim_count_t move_count = io_favorite_identities->count - 1 - insert_at;
+
+ memmove (&io_favorite_identities->identities[insert_at + 1],
+ &io_favorite_identities->identities[insert_at],
+ move_count * sizeof (*io_favorite_identities->identities));
+ io_favorite_identities->identities[insert_at] = identity;
+ identity = NULL;
+ }
+
+ kim_identity_free (&identity);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_favorite_identities_remove_identity (kim_favorite_identities_t io_favorite_identities,
+ kim_identity_t in_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_boolean_t found = FALSE;
+ kim_count_t i;
+
+ if (!err && !io_favorite_identities) { err = param_error (1, "io_favorite_identities", "NULL"); }
+ if (!err && !in_identity ) { err = param_error (2, "in_identity", "NULL"); }
+
+ if (!err) {
+ for (i = 0; !err && !found && i < io_favorite_identities->count; i++) {
+ kim_identity_t identity = io_favorite_identities->identities[i];
+
+ err = kim_identity_compare (in_identity, identity, &found);
+
+ if (!err && found) {
+ kim_count_t new_count = io_favorite_identities->count - 1;
+ memmove (&io_favorite_identities->identities[i],
+ &io_favorite_identities->identities[i + 1],
+ (new_count - i) * sizeof (*io_favorite_identities->identities));
+
+ kim_error_t terr = kim_favorite_identities_resize (io_favorite_identities, new_count);
+ if (terr) {
+ kim_debug_printf ("failed to resize list to %d. Continuing.", new_count);
+ kim_error_free (&terr);
+ }
+
+ kim_identity_free (&identity);
+ }
+ }
+ }
+
+ if (!err && !found) {
+ kim_string_t display_string = NULL;
+
+ err = kim_identity_get_display_string (in_identity, &display_string);
+
+ if (!err) {
+ err = kim_error_create_from_code (KIM_IDENTITY_NOT_IN_IDENTITIES_LIST, display_string);
+ }
+
+ kim_string_free (&display_string);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_favorite_identities_remove_all_identities (kim_favorite_identities_t io_favorite_identities)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_favorite_identities) { err = param_error (1, "io_favorite_identities", "NULL"); }
+
+ if (!err) {
+ kim_count_t i;
+
+ for (i = 0; i < io_favorite_identities->count; i++) {
+ kim_identity_free (&io_favorite_identities->identities[i]);
+ }
+ free (io_favorite_identities->identities);
+ io_favorite_identities->count = 0;
+ io_favorite_identities->identities = NULL;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_favorite_identities_free (kim_favorite_identities_t *io_favorite_identities)
+{
+ if (io_favorite_identities && *io_favorite_identities &&
+ *io_favorite_identities != kim_default_favorite_identities) {
+ kim_count_t i;
+
+ for (i = 0; i < (*io_favorite_identities)->count; i++) {
+ kim_identity_free (&(*io_favorite_identities)->identities[i]);
+ }
+ free ((*io_favorite_identities)->identities);
+ free (*io_favorite_identities);
+ *io_favorite_identities = NULL;
+ }
+}
+
+#pragma mark -- KIM Preferences --
+
+struct kim_preferences_opaque {
+ kim_options_t options;
+ kim_boolean_t options_changed;
+ kim_boolean_t remember_options;
+ kim_boolean_t remember_options_changed;
+ kim_identity_t client_identity;
+ kim_boolean_t client_identity_changed;
+ kim_boolean_t remember_client_identity;
+ kim_boolean_t remember_client_identity_changed;
+ kim_lifetime_t minimum_lifetime;
+ kim_lifetime_t maximum_lifetime;
+ kim_boolean_t lifetime_range_changed;
+ kim_lifetime_t minimum_renewal_lifetime;
+ kim_lifetime_t maximum_renewal_lifetime;
+ kim_boolean_t renewal_lifetime_range_changed;
+ kim_favorite_identities_t favorite_identities;
+ kim_boolean_t favorite_identities_changed;
+};
+
+struct kim_preferences_opaque kim_preferences_initializer = {
+ NULL,
+ FALSE,
+ kim_default_remember_options,
+ FALSE,
+ kim_default_client_identity,
+ FALSE,
+ kim_default_remember_client_identity,
+ FALSE,
+ kim_default_minimum_lifetime,
+ kim_default_maximum_lifetime,
+ FALSE,
+ kim_default_minimum_renewal_lifetime,
+ kim_default_maximum_renewal_lifetime,
+ FALSE,
+ NULL,
+ FALSE
+};
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_preferences_read (kim_preferences_t in_preferences)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences) { err = param_error (1, "in_preferences", "NULL"); }
+
+ if (!err) {
+ kim_lifetime_t lifetime = kim_default_lifetime;
+
+ err = kim_os_preferences_get_lifetime_for_key (kim_preference_key_lifetime,
+ kim_default_lifetime,
+ &lifetime);
+
+ if (!err) {
+ err = kim_options_set_lifetime (in_preferences->options, lifetime);
+ }
+ }
+
+ if (!err) {
+ kim_boolean_t renewable = kim_default_renewable;
+
+ err = kim_os_preferences_get_boolean_for_key (kim_preference_key_renewable,
+ kim_default_renewable,
+ &renewable);
+
+ if (!err) {
+ err = kim_options_set_renewable (in_preferences->options, renewable);
+ }
+ }
+
+ if (!err) {
+ kim_lifetime_t renewal_lifetime = kim_default_renewal_lifetime;
+
+ err = kim_os_preferences_get_lifetime_for_key (kim_preference_key_renewal_lifetime,
+ kim_default_renewal_lifetime,
+ &renewal_lifetime);
+
+ if (!err) {
+ err = kim_options_set_renewal_lifetime (in_preferences->options, renewal_lifetime);
+ }
+ }
+
+ if (!err) {
+ kim_boolean_t forwardable = kim_default_forwardable;
+
+ err = kim_os_preferences_get_boolean_for_key (kim_preference_key_forwardable,
+ kim_default_forwardable,
+ &forwardable);
+
+ if (!err) {
+ err = kim_options_set_forwardable (in_preferences->options, forwardable);
+ }
+ }
+
+ if (!err) {
+ kim_boolean_t proxiable = kim_default_proxiable;
+
+ err = kim_os_preferences_get_boolean_for_key (kim_preference_key_proxiable,
+ kim_default_proxiable,
+ &proxiable);
+
+ if (!err) {
+ err = kim_options_set_proxiable (in_preferences->options, proxiable);
+ }
+ }
+
+ if (!err) {
+ kim_boolean_t addressless = kim_default_addressless;
+
+ err = kim_os_preferences_get_boolean_for_key (kim_preference_key_addressless,
+ kim_default_addressless,
+ &addressless);
+
+ if (!err) {
+ err = kim_options_set_addressless (in_preferences->options, addressless);
+ }
+ }
+
+ if (!err) {
+ err = kim_os_preferences_get_boolean_for_key (kim_preference_key_remember_options,
+ kim_default_remember_options,
+ &in_preferences->remember_options);
+ }
+
+ if (!err) {
+ kim_identity_t default_identity = kim_default_client_identity;
+
+ err = kim_os_identity_create_for_username (&default_identity);
+
+ if (!err) {
+ err = kim_os_preferences_get_identity_for_key (kim_preference_key_client_identity,
+ default_identity,
+ &in_preferences->client_identity);
+ }
+
+ kim_identity_free (&default_identity);
+ }
+
+ if (!err) {
+ err = kim_os_preferences_get_boolean_for_key (kim_preference_key_remember_client_identity,
+ kim_default_remember_client_identity,
+ &in_preferences->remember_client_identity);
+ }
+
+ if (!err) {
+ err = kim_os_preferences_get_favorite_identities_for_key (kim_preference_key_favorite_identities,
+ kim_default_favorite_identities,
+ &in_preferences->favorite_identities);
+ }
+
+ if (!err) {
+ err = kim_os_preferences_get_lifetime_for_key (kim_preference_key_minimum_lifetime,
+ kim_default_minimum_lifetime,
+ &in_preferences->minimum_lifetime);
+ }
+
+ if (!err) {
+ err = kim_os_preferences_get_lifetime_for_key (kim_preference_key_maximum_lifetime,
+ kim_default_maximum_lifetime,
+ &in_preferences->maximum_lifetime);
+ }
+
+ if (!err) {
+ err = kim_os_preferences_get_lifetime_for_key (kim_preference_key_minimum_renewal_lifetime,
+ kim_default_minimum_renewal_lifetime,
+ &in_preferences->minimum_renewal_lifetime);
+ }
+
+ if (!err) {
+ err = kim_os_preferences_get_lifetime_for_key (kim_preference_key_maximum_renewal_lifetime,
+ kim_default_maximum_renewal_lifetime,
+ &in_preferences->maximum_renewal_lifetime);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_preferences_write (kim_preferences_t in_preferences)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences) { err = param_error (1, "in_preferences", "NULL"); }
+
+ if (!err && in_preferences->remember_options && in_preferences->options_changed) {
+ kim_lifetime_t lifetime = kim_default_lifetime;
+
+ err = kim_options_get_lifetime (in_preferences->options, &lifetime);
+
+ if (!err) {
+ err = kim_os_preferences_set_lifetime_for_key (kim_preference_key_lifetime,
+ lifetime);
+ }
+
+ if (!err) {
+ kim_boolean_t renewable = kim_default_renewable;
+
+ err = kim_options_get_renewable (in_preferences->options, &renewable);
+
+ if (!err) {
+ err = kim_os_preferences_set_boolean_for_key (kim_preference_key_renewable,
+ renewable);
+ }
+ }
+
+ if (!err) {
+ kim_lifetime_t renewal_lifetime = kim_default_renewal_lifetime;
+
+ err = kim_options_get_renewal_lifetime (in_preferences->options, &renewal_lifetime);
+
+ if (!err) {
+ err = kim_os_preferences_set_lifetime_for_key (kim_preference_key_renewal_lifetime,
+ renewal_lifetime);
+ }
+ }
+
+ if (!err) {
+ kim_boolean_t forwardable = kim_default_forwardable;
+
+ err = kim_options_get_forwardable (in_preferences->options, &forwardable);
+
+ if (!err) {
+ err = kim_os_preferences_set_boolean_for_key (kim_preference_key_forwardable,
+ forwardable);
+ }
+ }
+
+ if (!err) {
+ kim_boolean_t proxiable = kim_default_proxiable;
+
+ err = kim_options_get_proxiable (in_preferences->options, &proxiable);
+
+ if (!err) {
+ err = kim_os_preferences_set_boolean_for_key (kim_preference_key_proxiable,
+ proxiable);
+ }
+ }
+
+ if (!err) {
+ kim_boolean_t addressless = kim_default_addressless;
+
+ err = kim_options_get_addressless (in_preferences->options, &addressless);
+
+ if (!err) {
+ err = kim_os_preferences_set_boolean_for_key (kim_preference_key_addressless,
+ addressless);
+ }
+ }
+ }
+
+ if (!err && in_preferences->remember_options_changed) {
+ err = kim_os_preferences_set_boolean_for_key (kim_preference_key_remember_options,
+ in_preferences->remember_options);
+ }
+
+ if (!err && in_preferences->remember_client_identity && in_preferences->client_identity_changed) {
+ kim_identity_t default_identity = kim_default_client_identity;
+
+ err = kim_os_identity_create_for_username (&default_identity);
+
+ if (!err) {
+ err = kim_os_preferences_set_identity_for_key (kim_preference_key_client_identity,
+ in_preferences->client_identity);
+ }
+
+ kim_identity_free (&default_identity);
+ }
+
+ if (!err && in_preferences->remember_client_identity_changed) {
+ err = kim_os_preferences_set_boolean_for_key (kim_preference_key_remember_client_identity,
+ in_preferences->remember_client_identity);
+ }
+
+ if (!err && in_preferences->favorite_identities_changed) {
+ err = kim_os_preferences_set_favorite_identities_for_key (kim_preference_key_favorite_identities,
+ in_preferences->favorite_identities);
+ }
+
+ if (!err && in_preferences->lifetime_range_changed) {
+ err = kim_os_preferences_set_lifetime_for_key (kim_preference_key_minimum_lifetime,
+ in_preferences->minimum_lifetime);
+ if (!err) {
+ err = kim_os_preferences_set_lifetime_for_key (kim_preference_key_maximum_lifetime,
+ in_preferences->maximum_lifetime);
+ }
+ }
+
+ if (!err && in_preferences->renewal_lifetime_range_changed) {
+ err = kim_os_preferences_set_lifetime_for_key (kim_preference_key_minimum_renewal_lifetime,
+ in_preferences->minimum_renewal_lifetime);
+ if (!err) {
+ err = kim_os_preferences_set_lifetime_for_key (kim_preference_key_maximum_renewal_lifetime,
+ in_preferences->maximum_renewal_lifetime);
+ }
+ }
+
+ return check_error (err);
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_preferences_allocate (kim_preferences_t *out_preferences)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_preferences_t preferences = NULL;
+
+ if (!err && !out_preferences) { err = param_error (1, "out_preferences", "NULL"); }
+
+ if (!err) {
+ preferences = malloc (sizeof (*preferences));
+ if (!preferences) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ *preferences = kim_preferences_initializer;
+ *out_preferences = preferences;
+ preferences = NULL;
+ }
+
+ kim_preferences_free (&preferences);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_create (kim_preferences_t *out_preferences)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_preferences_t preferences = NULL;
+
+ if (!err && !out_preferences) { err = param_error (1, "out_preferences", "NULL"); }
+
+ if (!err) {
+ err = kim_preferences_allocate (&preferences);
+ }
+
+ if (!err) {
+ err = kim_options_create_from_defaults (&preferences->options);
+ }
+
+ if (!err) {
+ err = kim_preferences_read (preferences);
+ }
+
+ if (!err) {
+ *out_preferences = preferences;
+ preferences = NULL;
+ }
+
+ kim_preferences_free (&preferences);
+
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_copy (kim_preferences_t *out_preferences,
+ kim_preferences_t in_preferences)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_preferences_t preferences = NULL;
+
+ if (!err && !out_preferences) { err = param_error (1, "out_preferences", "NULL"); }
+ if (!err && !in_preferences ) { err = param_error (2, "in_preferences", "NULL"); }
+
+ if (!err) {
+ err = kim_preferences_allocate (&preferences);
+ }
+
+ if (!err) {
+ preferences->remember_options = in_preferences->remember_options;
+ err = kim_options_copy (&preferences->options, in_preferences->options);
+ }
+
+ if (!err) {
+ preferences->remember_client_identity = in_preferences->remember_client_identity;
+ err = kim_identity_copy (&preferences->client_identity, in_preferences->client_identity);
+ }
+
+ if (!err) {
+ err = kim_favorite_identities_copy (&preferences->favorite_identities, in_preferences->favorite_identities);
+ }
+
+ if (!err) {
+ *out_preferences = preferences;
+ preferences = NULL;
+ }
+
+ kim_preferences_free (&preferences);
+
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_set_options (kim_preferences_t io_preferences,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_options_t options = NULL;
+
+ if (!err && !io_preferences) { err = param_error (1, "io_preferences", "NULL"); }
+ if (!err && !in_options ) { err = param_error (2, "in_options", "NULL"); }
+
+ if (!err) {
+ err = kim_options_copy (&options, in_options);
+ }
+
+ if (!err) {
+ kim_options_free (&io_preferences->options);
+ io_preferences->options = options;
+ io_preferences->options_changed = TRUE;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_get_options (kim_preferences_t in_preferences,
+ kim_options_t *out_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences) { err = param_error (1, "in_preferences", "NULL"); }
+ if (!err && !out_options ) { err = param_error (2, "out_options", "NULL"); }
+
+ if (!err) {
+ err = kim_options_copy (out_options, in_preferences->options);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_set_remember_options (kim_preferences_t io_preferences,
+ kim_boolean_t in_remember_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_preferences) { err = param_error (1, "io_preferences", "NULL"); }
+
+ if (!err) {
+ io_preferences->remember_options = in_remember_options;
+ io_preferences->remember_options_changed = TRUE;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_get_remember_options (kim_preferences_t in_preferences,
+ kim_boolean_t *out_remember_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences ) { err = param_error (1, "in_preferences", "NULL"); }
+ if (!err && !out_remember_options) { err = param_error (2, "out_remember_options", "NULL"); }
+
+ if (!err) {
+ *out_remember_options = in_preferences->remember_options;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_set_client_identity (kim_preferences_t io_preferences,
+ kim_identity_t in_client_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_identity_t identity = KIM_IDENTITY_ANY;
+
+ if (!err && !io_preferences ) { err = param_error (1, "io_preferences", "NULL"); }
+ /* in_client_identity may be KIM_IDENTITY_ANY */
+
+ if (!err && in_client_identity) {
+ err = kim_identity_copy (&identity, in_client_identity);
+ }
+
+ if (!err) {
+ kim_identity_free (&io_preferences->client_identity);
+ io_preferences->client_identity = identity;
+ io_preferences->client_identity_changed = TRUE;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_get_client_identity (kim_preferences_t in_preferences,
+ kim_identity_t *out_client_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences ) { err = param_error (1, "in_preferences", "NULL"); }
+ if (!err && !out_client_identity) { err = param_error (2, "out_client_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_identity_copy (out_client_identity, in_preferences->client_identity);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_set_remember_client_identity (kim_preferences_t io_preferences,
+ kim_boolean_t in_remember_client_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_preferences) { err = param_error (1, "io_preferences", "NULL"); }
+
+ if (!err) {
+ io_preferences->remember_client_identity = in_remember_client_identity;
+ io_preferences->remember_client_identity_changed = TRUE;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_get_remember_client_identity (kim_preferences_t in_preferences,
+ kim_boolean_t *out_remember_client_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences ) { err = param_error (1, "in_preferences", "NULL"); }
+ if (!err && !out_remember_client_identity) { err = param_error (2, "out_remember_client_identity", "NULL"); }
+
+ if (!err) {
+ *out_remember_client_identity = in_preferences->remember_client_identity;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_set_minimum_lifetime (kim_preferences_t io_preferences,
+ kim_lifetime_t in_minimum_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_preferences) { err = param_error (1, "io_preferences", "NULL"); }
+
+ if (!err) {
+ io_preferences->minimum_lifetime = in_minimum_lifetime;
+ io_preferences->lifetime_range_changed = TRUE;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_get_minimum_lifetime (kim_preferences_t in_preferences,
+ kim_lifetime_t *out_minimum_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences ) { err = param_error (1, "in_preferences", "NULL"); }
+ if (!err && !out_minimum_lifetime) { err = param_error (2, "out_minimum_lifetime", "NULL"); }
+
+ if (!err) {
+ *out_minimum_lifetime = in_preferences->minimum_lifetime;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_set_maximum_lifetime (kim_preferences_t io_preferences,
+ kim_lifetime_t in_maximum_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_preferences) { err = param_error (1, "io_preferences", "NULL"); }
+
+ if (!err) {
+ io_preferences->maximum_lifetime = in_maximum_lifetime;
+ io_preferences->lifetime_range_changed = TRUE;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_get_maximum_lifetime (kim_preferences_t in_preferences,
+ kim_lifetime_t *out_maximum_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences ) { err = param_error (1, "in_preferences", "NULL"); }
+ if (!err && !out_maximum_lifetime) { err = param_error (2, "out_maximum_lifetime", "NULL"); }
+
+ if (!err) {
+ *out_maximum_lifetime = in_preferences->maximum_lifetime;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_set_minimum_renewal_lifetime (kim_preferences_t io_preferences,
+ kim_lifetime_t in_minimum_renewal_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_preferences) { err = param_error (1, "io_preferences", "NULL"); }
+
+ if (!err) {
+ io_preferences->minimum_renewal_lifetime = in_minimum_renewal_lifetime;
+ io_preferences->renewal_lifetime_range_changed = TRUE;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_get_minimum_renewal_lifetime (kim_preferences_t in_preferences,
+ kim_lifetime_t *out_minimum_renewal_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences ) { err = param_error (1, "in_preferences", "NULL"); }
+ if (!err && !out_minimum_renewal_lifetime) { err = param_error (2, "out_minimum_renewal_lifetime", "NULL"); }
+
+ if (!err) {
+ *out_minimum_renewal_lifetime = in_preferences->minimum_renewal_lifetime;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_set_maximum_renewal_lifetime (kim_preferences_t io_preferences,
+ kim_lifetime_t in_maximum_renewal_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_preferences) { err = param_error (1, "io_preferences", "NULL"); }
+
+ if (!err) {
+ io_preferences->maximum_renewal_lifetime = in_maximum_renewal_lifetime;
+ io_preferences->renewal_lifetime_range_changed = TRUE;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_get_maximum_renewal_lifetime (kim_preferences_t in_preferences,
+ kim_lifetime_t *out_maximum_renewal_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences ) { err = param_error (1, "in_preferences", "NULL"); }
+ if (!err && !out_maximum_renewal_lifetime) { err = param_error (2, "out_maximum_renewal_lifetime", "NULL"); }
+
+ if (!err) {
+ *out_maximum_renewal_lifetime = in_preferences->maximum_renewal_lifetime;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_set_favorite_identities (kim_preferences_t io_preferences,
+ kim_favorite_identities_t in_favorite_identities)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_favorite_identities_t favorite_identities = NULL;
+
+ if (!err && !io_preferences ) { err = param_error (1, "io_preferences", "NULL"); }
+ if (!err && !in_favorite_identities) { err = param_error (2, "in_favorite_identities", "NULL"); }
+
+ if (!err) {
+ err = kim_favorite_identities_copy (&favorite_identities, in_favorite_identities);
+ }
+
+ if (!err) {
+ kim_favorite_identities_free (&io_preferences->favorite_identities);
+ io_preferences->favorite_identities = favorite_identities;
+ io_preferences->favorite_identities_changed = TRUE;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_get_favorite_identities (kim_preferences_t in_preferences,
+ kim_favorite_identities_t *out_favorite_identities)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences ) { err = param_error (1, "in_preferences", "NULL"); }
+ if (!err && !out_favorite_identities) { err = param_error (2, "out_favorite_identities", "NULL"); }
+
+ if (!err) {
+ err = kim_favorite_identities_copy (out_favorite_identities, in_preferences->favorite_identities);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_preferences_synchronize (kim_preferences_t in_preferences)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_preferences) { err = param_error (1, "in_preferences", "NULL"); }
+
+ if (!err) {
+ err = kim_preferences_write (in_preferences);
+ }
+
+ if (!err) {
+ err = kim_preferences_read (in_preferences);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_preferences_free (kim_preferences_t *io_preferences)
+{
+ if (io_preferences && *io_preferences) {
+ kim_options_free (&(*io_preferences)->options);
+ kim_identity_free (&(*io_preferences)->client_identity);
+ kim_favorite_identities_free (&(*io_preferences)->favorite_identities);
+ free (*io_preferences);
+ *io_preferences = NULL;
+ }
+}
+
diff --git a/src/kim/lib/kim_preferences_private.h b/src/kim/lib/kim_preferences_private.h
new file mode 100644
index 0000000..a629fbb
--- /dev/null
+++ b/src/kim/lib/kim_preferences_private.h
@@ -0,0 +1,102 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_PREFERENCES_PRIVATE_H
+#define KIM_PREFERENCES_PRIVATE_H
+
+#include <kim/kim.h>
+
+extern const kim_favorite_identities_t kim_empty_favorite_identities;
+
+typedef enum kim_preference_key_enum {
+ kim_preference_key_lifetime,
+ kim_preference_key_renewable,
+ kim_preference_key_renewal_lifetime,
+ kim_preference_key_forwardable,
+ kim_preference_key_proxiable,
+ kim_preference_key_addressless,
+ kim_preference_key_remember_options,
+ kim_preference_key_client_identity,
+ kim_preference_key_remember_client_identity,
+ kim_preference_key_favorite_identities,
+ kim_preference_key_minimum_lifetime,
+ kim_preference_key_maximum_lifetime,
+ kim_preference_key_minimum_renewal_lifetime,
+ kim_preference_key_maximum_renewal_lifetime
+} kim_preference_key_t;
+
+#define kim_default_lifetime 10*60*60
+#define kim_default_renewable TRUE
+#define kim_default_renewal_lifetime 7*24*60*60
+#define kim_default_forwardable TRUE
+#define kim_default_proxiable TRUE
+#define kim_default_addressless TRUE
+#define kim_default_remember_options TRUE
+#define kim_default_client_identity KIM_IDENTITY_ANY
+#define kim_default_remember_client_identity TRUE
+#define kim_default_favorite_identities kim_empty_favorite_identities
+#define kim_default_minimum_lifetime 10*60
+#define kim_default_maximum_lifetime 10*60*60
+#define kim_default_minimum_renewal_lifetime 10*60
+#define kim_default_maximum_renewal_lifetime 7*24*60*60
+
+
+kim_error_t kim_os_preferences_get_identity_for_key (kim_preference_key_t in_key,
+ kim_identity_t in_hardcoded_default,
+ kim_identity_t *out_identity);
+
+kim_error_t kim_os_preferences_set_identity_for_key (kim_preference_key_t in_key,
+ kim_identity_t in_identity);
+
+kim_error_t kim_os_preferences_get_favorite_identities_for_key (kim_preference_key_t in_key,
+ kim_favorite_identities_t in_hardcoded_default,
+ kim_favorite_identities_t *out_favorite_identities);
+
+kim_error_t kim_os_preferences_set_favorite_identities_for_key (kim_preference_key_t in_key,
+ kim_favorite_identities_t in_favorite_identities);
+
+kim_error_t kim_os_preferences_get_time_for_key (kim_preference_key_t in_key,
+ kim_time_t in_hardcoded_default,
+ kim_time_t *out_time);
+
+kim_error_t kim_os_preferences_set_time_for_key (kim_preference_key_t in_key,
+ kim_time_t in_time);
+
+kim_error_t kim_os_preferences_get_lifetime_for_key (kim_preference_key_t in_key,
+ kim_lifetime_t in_hardcoded_default,
+ kim_lifetime_t *out_lifetime);
+
+kim_error_t kim_os_preferences_set_lifetime_for_key (kim_preference_key_t in_key,
+ kim_lifetime_t in_lifetime);
+
+kim_error_t kim_os_preferences_get_boolean_for_key (kim_preference_key_t in_key,
+ kim_boolean_t in_hardcoded_default,
+ kim_boolean_t *out_boolean);
+
+kim_error_t kim_os_preferences_set_boolean_for_key (kim_preference_key_t in_key,
+ kim_boolean_t in_boolean);
+
+#endif /* KIM_PREFERENCES_PRIVATE_H */
diff --git a/src/kim/lib/kim_private.h b/src/kim/lib/kim_private.h
new file mode 100644
index 0000000..cf9ed81
--- /dev/null
+++ b/src/kim/lib/kim_private.h
@@ -0,0 +1,45 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_PRIVATE_H
+#define KIM_PRIVATE_H
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <kim/kim.h>
+
+#include "kim_error_private.h"
+#include "kim_identity_private.h"
+#include "kim_ccache_private.h"
+#include "kim_library_private.h"
+#include "kim_options_private.h"
+#include "kim_preferences_private.h"
+#include "kim_selection_hints_private.h"
+#include "kim_string_private.h"
+
+#endif /* KIM_PRIVATE_H */
diff --git a/src/kim/lib/kim_selection_hints.c b/src/kim/lib/kim_selection_hints.c
new file mode 100644
index 0000000..4ed3fba
--- /dev/null
+++ b/src/kim/lib/kim_selection_hints.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright 2005-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "kim_private.h"
+
+/* ------------------------------------------------------------------------ */
+
+struct kim_selection_hints_opaque {
+ kim_string_t application_identifier;
+ kim_string_t application_name;
+ kim_string_t explanation;
+ kim_options_t options;
+ kim_boolean_t allow_user_interaction;
+ kim_boolean_t use_cached_results;
+ kim_string_t service_identity;
+ kim_string_t client_realm;
+ kim_string_t user;
+ kim_string_t service_realm;
+ kim_string_t service;
+ kim_string_t server;
+};
+
+struct kim_selection_hints_opaque kim_selection_hints_initializer = {
+ NULL,
+ NULL,
+ NULL,
+ KIM_OPTIONS_DEFAULT,
+ TRUE,
+ TRUE,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_selection_hints_allocate (kim_selection_hints_t *out_selection_hints)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_selection_hints_t selection_hints = NULL;
+
+ if (!err && !out_selection_hints) { err = param_error (1, "out_selection_hints", "NULL"); }
+
+ if (!err) {
+ selection_hints = malloc (sizeof (*selection_hints));
+ if (!selection_hints) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ *selection_hints = kim_selection_hints_initializer;
+ *out_selection_hints = selection_hints;
+ selection_hints = NULL;
+ }
+
+ kim_selection_hints_free (&selection_hints);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_create (kim_selection_hints_t *out_selection_hints,
+ kim_string_t in_application_identifier)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_selection_hints_t selection_hints = NULL;
+
+ if (!err && !out_selection_hints ) { err = param_error (1, "out_selection_hints", "NULL"); }
+ if (!err && !in_application_identifier) { err = param_error (1, "in_application_identifier", "NULL"); }
+
+ if (!err) {
+ err = kim_selection_hints_allocate (&selection_hints);
+ }
+
+ if (!err) {
+ err = kim_string_copy (&selection_hints->application_identifier,
+ in_application_identifier);
+ }
+
+ if (!err) {
+ *out_selection_hints = selection_hints;
+ selection_hints = NULL;
+ }
+
+ kim_selection_hints_free (&selection_hints);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_copy (kim_selection_hints_t *out_selection_hints,
+ kim_selection_hints_t in_selection_hints)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_selection_hints_t selection_hints = NULL;
+
+ if (!err && !out_selection_hints) { err = param_error (1, "out_selection_hints", "NULL"); }
+ if (!err && !in_selection_hints ) { err = param_error (1, "in_selection_hints", "NULL"); }
+
+ if (!err) {
+ err = kim_selection_hints_allocate (&selection_hints);
+ }
+
+ if (!err) {
+ err = kim_string_copy (&selection_hints->application_identifier,
+ in_selection_hints->application_identifier);
+ }
+
+ if (!err && in_selection_hints->application_name) {
+ err = kim_string_copy (&selection_hints->application_name,
+ in_selection_hints->application_name);
+ }
+
+ if (!err && in_selection_hints->explanation) {
+ err = kim_string_copy (&selection_hints->explanation,
+ in_selection_hints->explanation);
+ }
+
+ if (!err && in_selection_hints->options) {
+ err = kim_options_copy (&selection_hints->options,
+ in_selection_hints->options);
+ }
+
+ if (!err && in_selection_hints->service_identity) {
+ err = kim_string_copy (&selection_hints->service_identity,
+ in_selection_hints->service_identity);
+ }
+
+ if (!err && in_selection_hints->client_realm) {
+ err = kim_string_copy (&selection_hints->client_realm,
+ in_selection_hints->client_realm);
+ }
+
+ if (!err && in_selection_hints->user) {
+ err = kim_string_copy (&selection_hints->user,
+ in_selection_hints->user);
+ }
+
+ if (!err && in_selection_hints->service_realm) {
+ err = kim_string_copy (&selection_hints->service_realm,
+ in_selection_hints->service_realm);
+ }
+
+ if (!err && in_selection_hints->service) {
+ err = kim_string_copy (&selection_hints->service,
+ in_selection_hints->service);
+ }
+
+ if (!err && in_selection_hints->server) {
+ err = kim_string_copy (&selection_hints->server,
+ in_selection_hints->server);
+ }
+
+ if (!err) {
+ selection_hints->allow_user_interaction = in_selection_hints->allow_user_interaction;
+ selection_hints->use_cached_results = in_selection_hints->use_cached_results;
+
+ *out_selection_hints = selection_hints;
+ selection_hints = NULL;
+ }
+
+ kim_selection_hints_free (&selection_hints);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_service_identity_hint (kim_selection_hints_t io_selection_hints,
+ kim_identity_t in_service_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints ) { err = param_error (1, "io_selection_hints", "NULL"); }
+ if (!err && !in_service_identity) { err = param_error (2, "in_service_identity", "KIM_IDENTITY_ANY"); }
+
+ if (!err) {
+ err = kim_identity_get_string (in_service_identity, &io_selection_hints->service_identity);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_service_identity_hint (kim_selection_hints_t in_selection_hints,
+ kim_identity_t *out_service_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints ) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_service_identity) { err = param_error (2, "out_service_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_identity_create_from_string (out_service_identity, in_selection_hints->service_identity);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_client_realm_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_client_realm)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints) { err = param_error (1, "io_selection_hints", "NULL"); }
+ if (!err && !in_client_realm ) { err = param_error (2, "in_client_realm", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (&io_selection_hints->client_realm, in_client_realm);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_client_realm_hint (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_client_realm)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_client_realm ) { err = param_error (2, "out_client_realm", "NULL"); }
+
+ if (!err) {
+ if (in_selection_hints->client_realm) {
+ err = kim_string_copy (out_client_realm, in_selection_hints->client_realm);
+ } else {
+ *out_client_realm = NULL;
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_user_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_user)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints) { err = param_error (1, "io_selection_hints", "NULL"); }
+ if (!err && !in_user ) { err = param_error (2, "in_user", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (&io_selection_hints->user, in_user);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_user_hint (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_user)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_user ) { err = param_error (2, "out_user", "NULL"); }
+
+ if (!err) {
+ if (in_selection_hints->user) {
+ err = kim_string_copy (out_user, in_selection_hints->user);
+ } else {
+ *out_user = NULL;
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_service_realm_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_service_realm)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints) { err = param_error (1, "io_selection_hints", "NULL"); }
+ if (!err && !in_service_realm ) { err = param_error (2, "in_service_realm", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (&io_selection_hints->service_realm, in_service_realm);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_service_realm_hint (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_service_realm)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_service_realm ) { err = param_error (2, "out_service_realm", "NULL"); }
+
+ if (!err) {
+ if (in_selection_hints->service_realm) {
+ err = kim_string_copy (out_service_realm, in_selection_hints->service_realm);
+ } else {
+ *out_service_realm = NULL;
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_service_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_service)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints) { err = param_error (1, "io_selection_hints", "NULL"); }
+ if (!err && !in_service ) { err = param_error (2, "in_service", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (&io_selection_hints->service, in_service);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_service_hint (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_service)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_service ) { err = param_error (2, "out_service", "NULL"); }
+
+ if (!err) {
+ if (in_selection_hints->service) {
+ err = kim_string_copy (out_service, in_selection_hints->service);
+ } else {
+ *out_service = NULL;
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_server_hint (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_server_hostname)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints) { err = param_error (1, "io_selection_hints", "NULL"); }
+ if (!err && !in_server_hostname) { err = param_error (2, "in_server_hostname", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (&io_selection_hints->server, in_server_hostname);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_server_hint (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_server_hostname)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints ) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_server_hostname) { err = param_error (2, "out_server_hostname", "NULL"); }
+
+ if (!err) {
+ if (in_selection_hints->server) {
+ err = kim_string_copy (out_server_hostname, in_selection_hints->server);
+ } else {
+ *out_server_hostname = NULL;
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_application_name (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_application_name)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints ) { err = param_error (1, "io_selection_hints", "NULL"); }
+ if (!err && !in_application_name) { err = param_error (2, "in_application_name", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (&io_selection_hints->application_name, in_application_name);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_application_name (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_application_name)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints ) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_application_name) { err = param_error (2, "out_application_name", "NULL"); }
+
+ if (!err) {
+ if (in_selection_hints->application_name) {
+ err = kim_string_copy (out_application_name, in_selection_hints->application_name);
+ } else {
+ *out_application_name = NULL;
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_explanation (kim_selection_hints_t io_selection_hints,
+ kim_string_t in_explanation)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints) { err = param_error (1, "io_selection_hints", "NULL"); }
+ if (!err && !in_explanation ) { err = param_error (2, "in_explanation", "NULL"); }
+
+ if (!err) {
+ err = kim_string_copy (&io_selection_hints->explanation, in_explanation);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_explanation (kim_selection_hints_t in_selection_hints,
+ kim_string_t *out_explanation)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_explanation ) { err = param_error (2, "out_explanation", "NULL"); }
+
+ if (!err) {
+ if (in_selection_hints->explanation) {
+ err = kim_string_copy (out_explanation, in_selection_hints->explanation);
+ } else {
+ *out_explanation = NULL;
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_options (kim_selection_hints_t io_selection_hints,
+ kim_options_t in_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints) { err = param_error (1, "io_selection_hints", "NULL"); }
+ if (!err && !in_options ) { err = param_error (2, "in_options", "NULL"); }
+
+ if (!err) {
+ err = kim_options_copy (&io_selection_hints->options, in_options);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_options (kim_selection_hints_t in_selection_hints,
+ kim_options_t *out_options)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_options ) { err = param_error (2, "out_options", "NULL"); }
+
+ if (!err) {
+ if (in_selection_hints->options) {
+ err = kim_options_copy (out_options, in_selection_hints->options);
+ } else {
+ *out_options = KIM_OPTIONS_DEFAULT;
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_allow_user_interaction (kim_selection_hints_t io_selection_hints,
+ kim_boolean_t in_allow_user_interaction)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints ) { err = param_error (1, "io_selection_hints", "NULL"); }
+
+ if (!err) {
+ io_selection_hints->allow_user_interaction = in_allow_user_interaction;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_allow_user_interaction (kim_selection_hints_t in_selection_hints,
+ kim_boolean_t *out_allow_user_interaction)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints ) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_allow_user_interaction) { err = param_error (2, "out_allow_user_interaction", "NULL"); }
+
+ if (!err) {
+ *out_allow_user_interaction = in_selection_hints->allow_user_interaction;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_set_remember_identity (kim_selection_hints_t io_selection_hints,
+ kim_boolean_t in_use_cached_results)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !io_selection_hints ) { err = param_error (1, "io_selection_hints", "NULL"); }
+
+ if (!err) {
+ io_selection_hints->use_cached_results = in_use_cached_results;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_remember_identity (kim_selection_hints_t in_selection_hints,
+ kim_boolean_t *out_use_cached_results)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints ) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_use_cached_results) { err = param_error (2, "out_use_cached_results", "NULL"); }
+
+ if (!err) {
+ *out_use_cached_results = in_selection_hints->use_cached_results;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_identity (kim_selection_hints_t in_selection_hints,
+ kim_identity_t *out_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_identity_t identity = NULL;
+ kim_ccache_t ccache = NULL;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_identity ) { err = param_error (2, "out_identity", "NULL"); }
+
+ if (!err && in_selection_hints->use_cached_results) {
+ err = kim_os_selection_hints_lookup_identity (in_selection_hints, &identity);
+ }
+
+ if (!err && !identity && in_selection_hints->allow_user_interaction) {
+#warning GUI to let user pick identity here
+ }
+
+ if (!err) {
+ *out_identity = identity;
+ identity = NULL;
+ }
+
+ kim_identity_free (&identity);
+ kim_ccache_free (&ccache);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_remember_identity (kim_selection_hints_t in_selection_hints,
+ kim_identity_t in_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !in_identity ) { err = param_error (2, "in_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_os_selection_hints_remember_identity (in_selection_hints,
+ in_identity);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_forget_identity (kim_selection_hints_t in_selection_hints)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+
+ if (!err) {
+ err = kim_os_selection_hints_forget_identity (in_selection_hints);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_selection_hints_get_preference_strings (kim_selection_hints_t in_selection_hints,
+ kim_selection_hints_preference_strings *io_preference_strings)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints ) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !io_preference_strings) { err = param_error (2, "io_preference_strings", "NULL"); }
+
+ if (!err) {
+ io_preference_strings->application_identifier = in_selection_hints->application_identifier;
+ io_preference_strings->service_identity = in_selection_hints->service_identity;
+ io_preference_strings->client_realm = in_selection_hints->client_realm;
+ io_preference_strings->user = in_selection_hints->user;
+ io_preference_strings->service_realm = in_selection_hints->service_realm;
+ io_preference_strings->service = in_selection_hints->service;
+ io_preference_strings->server = in_selection_hints->server;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_selection_hints_free (kim_selection_hints_t *io_selection_hints)
+{
+ if (io_selection_hints && *io_selection_hints) {
+ kim_string_free (&(*io_selection_hints)->application_identifier);
+ kim_string_free (&(*io_selection_hints)->application_name);
+ kim_string_free (&(*io_selection_hints)->explanation);
+ kim_options_free (&(*io_selection_hints)->options);
+ kim_string_free (&(*io_selection_hints)->service_identity);
+ kim_string_free (&(*io_selection_hints)->client_realm);
+ kim_string_free (&(*io_selection_hints)->user);
+ kim_string_free (&(*io_selection_hints)->service_realm);
+ kim_string_free (&(*io_selection_hints)->service);
+ kim_string_free (&(*io_selection_hints)->server);
+ free (*io_selection_hints);
+ *io_selection_hints = NULL;
+ }
+}
+
diff --git a/src/kim/lib/kim_selection_hints_private.h b/src/kim/lib/kim_selection_hints_private.h
new file mode 100644
index 0000000..a975ff9
--- /dev/null
+++ b/src/kim/lib/kim_selection_hints_private.h
@@ -0,0 +1,55 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_SELECTION_HINTS_PRIVATE_H
+#define KIM_SELECTION_HINTS_PRIVATE_H
+
+#include <kim/kim.h>
+
+typedef struct kim_selection_hints_preference_strings {
+ kim_string_t application_identifier;
+ kim_string_t service_identity;
+ kim_string_t client_realm;
+ kim_string_t user;
+ kim_string_t service_realm;
+ kim_string_t service;
+ kim_string_t server;
+} kim_selection_hints_preference_strings;
+
+
+kim_error_t kim_selection_hints_get_preference_strings (kim_selection_hints_t in_selection_hints,
+ kim_selection_hints_preference_strings *io_preference_strings);
+
+kim_error_t kim_os_selection_hints_lookup_identity (kim_selection_hints_t in_selection_hints,
+ kim_identity_t *out_identity);
+
+kim_error_t kim_os_selection_hints_remember_identity (kim_selection_hints_t in_selection_hints,
+ kim_identity_t in_identity);
+
+kim_error_t kim_os_selection_hints_forget_identity (kim_selection_hints_t in_selection_hints);
+
+
+#endif /* KIM_SELECTION_HINTS_PRIVATE_H */
diff --git a/src/kim/lib/kim_string.c b/src/kim/lib/kim_string.c
new file mode 100644
index 0000000..941467b
--- /dev/null
+++ b/src/kim/lib/kim_string.c
@@ -0,0 +1,181 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "kim_private.h"
+
+
+/* ------------------------------------------------------------------------ */
+
+static inline kim_error_t kim_string_allocate (kim_string_t *out_string,
+ kim_count_t in_length)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t string = NULL;
+
+ if (!err && !out_string) { err = param_error (1, "out_string", "NULL"); }
+
+ if (!err) {
+ string = calloc (in_length, sizeof (char *));
+ if (!string) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ *out_string = string;
+ string = NULL;
+ }
+
+ kim_string_free (&string);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_string_create_from_format (kim_string_t *out_string,
+ kim_string_t in_format,
+ ...)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ va_list args;
+
+ va_start (args, in_format);
+ err = kim_string_create_from_format_va (out_string, in_format, args);
+ va_end (args);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_string_create_from_format_va_retcode (kim_string_t *out_string,
+ kim_string_t in_format,
+ va_list in_args)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ int count = vasprintf ((char **) out_string, in_format, in_args);
+ if (count < 0) { err = os_error (ENOMEM); }
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_string_create_from_format_va (kim_string_t *out_string,
+ kim_string_t in_format,
+ va_list in_args)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t string = NULL;
+
+ if (!err && !out_string) { err = param_error (1, "out_string", "NULL"); }
+ if (!err && !in_format ) { err = param_error (2, "in_format", "NULL"); }
+
+ if (!err) {
+ err = kim_string_create_from_format_va_retcode (&string, in_format, in_args);
+ }
+
+ if (!err) {
+ *out_string = string;
+ string = NULL;
+ }
+
+ if (string) { kim_string_free (&string); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_string_create_from_buffer (kim_string_t *out_string,
+ const char *in_buffer,
+ kim_count_t in_length)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t string = NULL;
+
+ if (!err && !out_string) { err = param_error (1, "out_string", "NULL"); }
+ if (!err && !in_buffer ) { err = param_error (2, "in_buffer", "NULL"); }
+
+ if (!err) {
+ err = kim_string_allocate (&string, in_length + 1);
+ }
+
+ if (!err) {
+ memcpy ((char *) string, in_buffer, in_length * sizeof (char));
+ *out_string = string;
+ string = NULL;
+ }
+
+ kim_string_free (&string);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_string_copy (kim_string_t *out_string,
+ kim_string_t in_string)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t string = NULL;
+
+ if (!err && !out_string) { err = param_error (1, "out_string", "NULL"); }
+ if (!err && !in_string ) { err = param_error (2, "in_string", "NULL"); }
+
+ if (!err) {
+ err = kim_string_allocate (&string, strlen (in_string) + 1);
+ }
+
+ if (!err) {
+ strcpy ((char *) string, in_string);
+ *out_string = string;
+ string = NULL;
+ }
+
+ kim_string_free (&string);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_string_compare (kim_string_t in_string,
+ kim_string_t in_compare_to_string,
+ kim_comparison_t *out_comparison)
+{
+ return kim_os_string_compare (in_string, in_compare_to_string, out_comparison);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void kim_string_free (kim_string_t *io_string)
+{
+ if (io_string && *io_string) {
+ free ((char *) *io_string);
+ *io_string = NULL;
+ }
+}
diff --git a/src/kim/lib/kim_string_private.h b/src/kim/lib/kim_string_private.h
new file mode 100644
index 0000000..72204c2
--- /dev/null
+++ b/src/kim/lib/kim_string_private.h
@@ -0,0 +1,60 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_STRING_PRIVATE_H
+#define KIM_STRING_PRIVATE_H
+
+#include <kim/kim.h>
+
+
+kim_error_t kim_string_create_from_format (kim_string_t *out_string,
+ kim_string_t in_format,
+ ...);
+
+kim_error_t kim_string_create_from_format_va_retcode (kim_string_t *out_string,
+ kim_string_t in_format,
+ va_list in_args);
+
+kim_error_t kim_string_create_from_format_va (kim_string_t *out_string,
+ kim_string_t in_format,
+ va_list in_args);
+
+kim_error_t kim_string_create_from_buffer (kim_string_t *out_string,
+ const char *in_buffer,
+ kim_count_t in_length);
+
+kim_error_t kim_string_prepend (kim_string_t *io_string,
+ kim_string_t in_prefix);
+
+kim_error_t kim_string_append (kim_string_t *io_string,
+ kim_string_t in_suffix);
+
+/* OS-specific because it should use UTF8-safe sorting where possible */
+kim_error_t kim_os_string_compare (kim_string_t in_string,
+ kim_string_t in_compare_to_string,
+ kim_comparison_t *out_comparison);
+
+#endif /* KIM_STRING_PRIVATE_H */
diff --git a/src/kim/lib/mac/kim_os_identity.c b/src/kim/lib/mac/kim_os_identity.c
new file mode 100644
index 0000000..ed351a5
--- /dev/null
+++ b/src/kim/lib/mac/kim_os_identity.c
@@ -0,0 +1,50 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <pwd.h>
+#include <Kerberos/kipc_session.h>
+
+#include "kim_os_private.h"
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_identity_create_for_username (kim_identity_t *out_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !out_identity) { err = param_error (1, "out_identity", "NULL"); }
+
+ if (!err) {
+ struct passwd *pw = getpwuid (kipc_session_get_session_uid ());
+ if (pw) {
+ err = kim_identity_create_from_string (out_identity, pw->pw_name);
+ } else {
+ *out_identity = KIM_IDENTITY_ANY;
+ }
+ }
+
+ return check_error (err);
+}
diff --git a/src/kim/lib/mac/kim_os_library.c b/src/kim/lib/mac/kim_os_library.c
new file mode 100644
index 0000000..733f5c4
--- /dev/null
+++ b/src/kim/lib/mac/kim_os_library.c
@@ -0,0 +1,56 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <CoreServices/CoreServices.h>
+#include <Kerberos/KerberosDebug.h>
+
+#include "kim_os_private.h"
+
+/* ------------------------------------------------------------------------ */
+
+void kim_os_library_debug_print (kim_string_t in_string)
+{
+ dprintf (in_string);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_boolean_t kim_os_library_caller_is_server (void)
+{
+ CFBundleRef mainBundle = CFBundleGetMainBundle ();
+ if (mainBundle) {
+ CFStringRef mainBundleID = CFBundleGetIdentifier (mainBundle);
+ if (mainBundleID) {
+ CFComparisonResult result;
+ result = CFStringCompare (mainBundleID, CFSTR("edu.mit.Kerberos.KerberosAgent"), 0);
+ if (result == kCFCompareEqualTo) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
diff --git a/src/kim/lib/mac/kim_os_preferences.c b/src/kim/lib/mac/kim_os_preferences.c
new file mode 100644
index 0000000..3cd2ab8
--- /dev/null
+++ b/src/kim/lib/mac/kim_os_preferences.c
@@ -0,0 +1,552 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "kim_os_private.h"
+
+#define KIM_PREFERENCES_FILE CFSTR("edu.mit.Kerberos.IdentityManagement")
+#define KLL_PREFERENCES_FILE CFSTR("edu.mit.Kerberos.KerberosLogin")
+
+#define kim_os_preference_any_identity "KIM_IDENTITY_ANY"
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_os_preferences_cfstring_for_key (kim_preference_key_t in_key,
+ CFStringRef *out_kim_string_key,
+ CFStringRef *out_kll_string_key)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !out_kim_string_key) { err = param_error (2, "out_kim_string_key", "NULL"); }
+ if (!err && !out_kll_string_key) { err = param_error (3, "out_kll_string_key", "NULL"); }
+
+ if (!err) {
+ if (in_key == kim_preference_key_lifetime) {
+ *out_kim_string_key = CFSTR ("CredentialLifetime");
+ *out_kll_string_key = CFSTR ("KLDefaultTicketLifetime");
+
+ } else if (in_key == kim_preference_key_renewable) {
+ *out_kim_string_key = CFSTR ("RenewableCredentials");
+ *out_kll_string_key = CFSTR ("KLGetRenewableTickets");
+
+ } else if (in_key == kim_preference_key_renewal_lifetime) {
+ *out_kim_string_key = CFSTR ("CredentialRenewalLifetime");
+ *out_kll_string_key = CFSTR ("KLDefaultRenewableLifetime");
+
+ } else if (in_key == kim_preference_key_forwardable) {
+ *out_kim_string_key = CFSTR ("ForwardableCredentials");
+ *out_kll_string_key = CFSTR ("KLDefaultForwardableTicket");
+
+ } else if (in_key == kim_preference_key_proxiable) {
+ *out_kim_string_key = CFSTR ("ProxiableCredentials");
+ *out_kll_string_key = CFSTR ("KLGetProxiableTickets");
+
+ } else if (in_key == kim_preference_key_addressless) {
+ *out_kim_string_key = CFSTR ("AddresslessCredentials");
+ *out_kll_string_key = CFSTR ("KLGetAddresslessTickets");
+
+ } else if (in_key == kim_preference_key_remember_options) {
+ *out_kim_string_key = CFSTR ("RememberCredentialAttributes");
+ *out_kll_string_key = CFSTR ("KLRememberExtras");
+
+ } else if (in_key == kim_preference_key_client_identity) {
+ *out_kim_string_key = CFSTR ("ClientIdentity");
+ *out_kll_string_key = CFSTR ("KLName");
+
+ } else if (in_key == kim_preference_key_remember_client_identity) {
+ *out_kim_string_key = CFSTR ("RememberClientIdentity");
+ *out_kll_string_key = CFSTR ("KLRememberPrincipal");
+
+ } else if (in_key == kim_preference_key_favorite_identities) {
+ *out_kim_string_key = CFSTR ("FavoriteIdentities");
+ *out_kll_string_key = CFSTR ("KLFavoriteIdentities");
+
+ } else if (in_key == kim_preference_key_minimum_lifetime) {
+ *out_kim_string_key = CFSTR ("MinimumLifetime");
+ *out_kll_string_key = CFSTR ("KLMinimumTicketLifetime");
+
+ } else if (in_key == kim_preference_key_maximum_lifetime) {
+ *out_kim_string_key = CFSTR ("MaximumLifetime");
+ *out_kll_string_key = CFSTR ("KLMaximumTicketLifetime");
+
+ } else if (in_key == kim_preference_key_minimum_renewal_lifetime) {
+ *out_kim_string_key = CFSTR ("MinimumRenewalLifetime");
+ *out_kll_string_key = CFSTR ("KLMinimumRenewableLifetime");
+
+ } else if (in_key == kim_preference_key_maximum_renewal_lifetime) {
+ *out_kim_string_key = CFSTR ("MaximumRenewalLifetime");
+ *out_kll_string_key = CFSTR ("KLMaximumRenewableLifetime");
+
+ } else {
+ err = param_error (1, "in_key", "not in kim_preference_key_enum");
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_os_preferences_get_value (kim_preference_key_t in_key,
+ CFTypeID in_type,
+ CFPropertyListRef *out_value)
+{
+
+ kim_error_t err = KIM_NO_ERROR;
+ CFPropertyListRef value = NULL;
+ CFStringRef users[] = { kCFPreferencesCurrentUser, kCFPreferencesAnyUser, NULL };
+ CFStringRef files[] = { KIM_PREFERENCES_FILE, KLL_PREFERENCES_FILE, NULL };
+ CFStringRef hosts[] = { kCFPreferencesCurrentHost, kCFPreferencesAnyHost, NULL };
+ CFStringRef keys[] = { NULL, NULL, NULL };
+
+ if (!err && !out_value) { err = param_error (3, "out_value", "NULL"); }
+
+ if (!err) {
+ /* Index must correspond to the appropriate file */
+ err = kim_os_preferences_cfstring_for_key (in_key, &keys[0], &keys[1]);
+ }
+
+ if (!err) {
+ kim_count_t u, f, h;
+
+ if (!kim_library_allow_home_directory_access()) {
+ users[0] = kCFPreferencesAnyUser;
+ users[1] = NULL;
+ }
+
+ for (u = 0; !value && users[u]; u++) {
+ for (f = 0; !value && files[f]; f++) {
+ for (h = 0; !value && hosts[h]; h++) {
+ value = CFPreferencesCopyValue (keys[f], files[f], users[u], hosts[h]);
+ }
+ }
+ }
+
+ if (value && CFGetTypeID (value) != in_type) {
+ err = kim_error_create_from_code (KIM_PREFERENCES_READ_ECODE);
+ }
+ }
+
+
+ if (!err) {
+ *out_value = value;
+ value = NULL;
+ }
+
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_os_preferences_set_value (kim_preference_key_t in_key,
+ CFPropertyListRef in_value)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFStringRef kim_key = NULL;
+ CFStringRef kll_key = NULL;
+
+ if (!err && !in_value) { err = param_error (2, "in_value", "NULL"); }
+
+ if (!err) {
+ err = kim_os_preferences_cfstring_for_key (in_key, &kim_key, &kll_key);
+ }
+
+ if (!err) {
+ kim_boolean_t homedir_ok = kim_library_allow_home_directory_access();
+ CFStringRef user = homedir_ok ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser;
+ CFStringRef host = homedir_ok ? kCFPreferencesAnyHost : kCFPreferencesCurrentHost;
+
+ CFPreferencesSetValue (kim_key, in_value, KIM_PREFERENCES_FILE, user, host);
+ if (!CFPreferencesSynchronize (KIM_PREFERENCES_FILE, user, host)) {
+ err = kim_error_create_from_code (KIM_PREFERENCES_WRITE_ECODE);
+ }
+ }
+
+ return check_error (err);
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_get_identity_for_key (kim_preference_key_t in_key,
+ kim_identity_t in_hardcoded_default,
+ kim_identity_t *out_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t string = NULL;
+ CFStringRef value = NULL;
+
+ if (!err && !out_identity) { err = param_error (2, "out_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_os_preferences_get_value (in_key, CFStringGetTypeID (),
+ (CFPropertyListRef *) &value);
+ }
+
+ if (!err) {
+ if (value) {
+ err = kim_os_string_create_from_cfstring (&string, value);
+
+ if (!err) {
+ if (!strcmp (kim_os_preference_any_identity, string)) {
+ *out_identity = KIM_IDENTITY_ANY;
+
+ } else {
+ err = kim_identity_create_from_string (out_identity, string);
+ }
+ }
+ } else {
+ err = kim_identity_copy (out_identity, in_hardcoded_default);
+ }
+ }
+
+ kim_string_free (&string);
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_set_identity_for_key (kim_preference_key_t in_key,
+ kim_identity_t in_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFStringRef value = NULL;
+ kim_string_t string = NULL;
+
+ /* in_identity can be KIM_IDENTITY_ANY */
+
+ if (!err) {
+ if (in_identity) {
+ err = kim_identity_get_string (in_identity, &string);
+
+ } else {
+ err = kim_string_copy (&string, kim_os_preference_any_identity);
+ }
+ }
+
+ if (!err) {
+ err = kim_os_string_get_cfstring (string, &value);
+ }
+
+ if (!err) {
+ err = kim_os_preferences_set_value (in_key, value);
+ }
+
+ if (value) { CFRelease (value); }
+ kim_string_free (&string);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_get_favorite_identities_for_key (kim_preference_key_t in_key,
+ kim_favorite_identities_t in_hardcoded_default,
+ kim_favorite_identities_t *out_favorite_identities)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFArrayRef value = NULL;
+
+ if (!err && !out_favorite_identities) { err = param_error (2, "out_favorite_identities", "NULL"); }
+
+ if (!err) {
+ err = kim_os_preferences_get_value (in_key, CFArrayGetTypeID (),
+ (CFPropertyListRef *) &value);
+ }
+
+ if (!err) {
+ if (!value || CFArrayGetCount (value) < 1) {
+ err = kim_favorite_identities_copy (out_favorite_identities, in_hardcoded_default);
+
+ } else {
+ kim_favorite_identities_t favorite_identities = NULL;
+ CFIndex count = CFArrayGetCount (value);
+ CFIndex i;
+
+ err = kim_favorite_identities_create (&favorite_identities);
+
+ for (i = 0; !err && i < count; i++) {
+ CFStringRef cfstring = NULL;
+ kim_string_t string = NULL;
+ kim_identity_t identity = NULL;
+
+ cfstring = (CFStringRef) CFArrayGetValueAtIndex (value, i);
+ if (!cfstring || CFGetTypeID (cfstring) != CFStringGetTypeID ()) {
+ err = kim_error_create_from_code (KIM_PREFERENCES_READ_ECODE);
+ }
+
+ if (!err) {
+ err = kim_os_string_create_from_cfstring (&string, cfstring);
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, string);
+ }
+
+ if (!err) {
+ err = kim_favorite_identities_add_identity (favorite_identities, identity);
+ }
+
+ kim_identity_free (&identity);
+ kim_string_free (&string);
+ }
+
+ if (!err) {
+ *out_favorite_identities = favorite_identities;
+ favorite_identities = NULL;
+ }
+
+ kim_favorite_identities_free (&favorite_identities);
+ }
+ }
+
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_set_favorite_identities_for_key (kim_preference_key_t in_key,
+ kim_favorite_identities_t in_favorite_identities)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_count_t count = 0;
+ CFMutableArrayRef value = NULL;
+
+ if (!err && !in_favorite_identities) { err = param_error (2, "in_favorite_identities", "NULL"); }
+
+ if (!err) {
+ err = kim_favorite_identities_get_number_of_identities (in_favorite_identities, &count);
+ }
+
+ if (!err) {
+ value = CFArrayCreateMutable (kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
+ if (!value) { err = os_error (ENOMEM); }
+ }
+
+ if (!err) {
+ kim_count_t i;
+
+ for (i = 0; !err && i < count; i++) {
+ kim_identity_t identity = NULL;
+ kim_string_t string = NULL;
+ CFStringRef cfstring = NULL;
+
+ err = kim_favorite_identities_get_identity_at_index (in_favorite_identities, i, &identity);
+
+ if (!err) {
+ err = kim_identity_get_string (identity, &string);
+ }
+
+ if (!err) {
+ err = kim_os_string_get_cfstring (string, &cfstring);
+ }
+
+ if (!err) {
+ CFArrayAppendValue (value, cfstring);
+ }
+
+ if (cfstring) { CFRelease (cfstring); }
+ kim_string_free (&string);
+ kim_identity_free (&identity);
+ }
+ }
+
+ if (!err) {
+ err = kim_os_preferences_set_value (in_key, value);
+ }
+
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_get_time_for_key (kim_preference_key_t in_key,
+ kim_time_t in_hardcoded_default,
+ kim_time_t *out_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFNumberRef value = NULL;
+
+ if (!err && !out_time) { err = param_error (2, "out_time", "NULL"); }
+
+ if (!err) {
+ err = kim_os_preferences_get_value (in_key, CFNumberGetTypeID (),
+ (CFPropertyListRef *) &value);
+ }
+
+ if (!err) {
+ if (value) {
+ SInt32 number; // CFNumbers are signed so we need to cast
+ if (CFNumberGetValue (value, kCFNumberSInt32Type, &number) != TRUE) {
+ err = os_error (ENOMEM);
+ } else {
+ *out_time = number;
+ }
+ } else {
+ *out_time = in_hardcoded_default;
+ }
+ }
+
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_set_time_for_key (kim_preference_key_t in_key,
+ kim_time_t in_time)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFNumberRef value = NULL;
+ SInt32 number = (SInt32) in_time;
+
+ if (!err) {
+ value = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &number);
+ if (!value) { err = os_error (ENOMEM); }
+ }
+
+ if (!err) {
+ err = kim_os_preferences_set_value (in_key, value);
+ }
+
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_get_lifetime_for_key (kim_preference_key_t in_key,
+ kim_lifetime_t in_hardcoded_default,
+ kim_lifetime_t *out_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFNumberRef value = NULL;
+
+ if (!err && !out_lifetime) { err = param_error (2, "out_lifetime", "NULL"); }
+
+ if (!err) {
+ err = kim_os_preferences_get_value (in_key, CFNumberGetTypeID (),
+ (CFPropertyListRef *) &value);
+ }
+
+ if (!err) {
+ if (value) {
+ SInt32 number; // CFNumbers are signed so we need to cast
+ if (CFNumberGetValue (value, kCFNumberSInt32Type, &number) != TRUE) {
+ err = os_error (ENOMEM);
+ } else {
+ *out_lifetime = number;
+ }
+ } else {
+ *out_lifetime = in_hardcoded_default;
+ }
+ }
+
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_set_lifetime_for_key (kim_preference_key_t in_key,
+ kim_lifetime_t in_lifetime)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFNumberRef value = NULL;
+ SInt32 number = (SInt32) in_lifetime;
+
+ if (!err) {
+ value = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &number);
+ if (!value) { err = os_error (ENOMEM); }
+ }
+
+ if (!err) {
+ err = kim_os_preferences_set_value (in_key, value);
+ }
+
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_get_boolean_for_key (kim_preference_key_t in_key,
+ kim_boolean_t in_hardcoded_default,
+ kim_boolean_t *out_boolean)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFBooleanRef value = NULL;
+
+ if (!err && !out_boolean) { err = param_error (2, "out_boolean", "NULL"); }
+
+ if (!err) {
+ err = kim_os_preferences_get_value (in_key, CFBooleanGetTypeID (),
+ (CFPropertyListRef *) &value);
+ }
+
+ if (!err) {
+ if (value) {
+ *out_boolean = CFBooleanGetValue (value);
+ } else {
+ *out_boolean = in_hardcoded_default;
+ }
+ }
+
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_preferences_set_boolean_for_key (kim_preference_key_t in_key,
+ kim_boolean_t in_boolean)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFBooleanRef value = in_boolean ? kCFBooleanTrue : kCFBooleanFalse;
+
+ if (!err) {
+ err = kim_os_preferences_set_value (in_key, value);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
diff --git a/src/kim/lib/mac/kim_os_private.h b/src/kim/lib/mac/kim_os_private.h
new file mode 100644
index 0000000..bebf987
--- /dev/null
+++ b/src/kim/lib/mac/kim_os_private.h
@@ -0,0 +1,54 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KIM_OS_PRIVATE_H
+#define KIM_OS_PRIVATE_H
+
+#include <CoreFoundation/CoreFoundation.h>
+#include "kim_private.h"
+
+
+CFStringEncoding kim_os_string_get_encoding (void);
+
+CFStringRef kim_os_string_get_cfstring_for_key_and_dictionary (CFStringRef in_key,
+ CFBundleRef in_bundle);
+
+CFStringRef kim_os_string_get_cfstring_for_key (kim_string_t in_key_string);
+
+kim_error_t kim_os_string_create_from_cfstring (kim_string_t *out_string,
+ CFStringRef in_cfstring);
+
+kim_error_t kim_os_string_create_for_key (kim_string_t *out_string,
+ kim_string_t in_key_string);
+
+kim_error_t kim_os_string_get_cfstring (kim_string_t in_string,
+ CFStringRef *out_cfstring);
+
+kim_error_t kim_os_string_compare_to_cfstring (kim_string_t in_string,
+ CFStringRef in_compare_to_cfstring,
+ kim_comparison_t *out_comparison);
+
+#endif /* KIM_PRIVATE_H */
diff --git a/src/kim/lib/mac/kim_os_selection_hints.c b/src/kim/lib/mac/kim_os_selection_hints.c
new file mode 100644
index 0000000..e19ac77
--- /dev/null
+++ b/src/kim/lib/mac/kim_os_selection_hints.c
@@ -0,0 +1,538 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#define KIM_SELECTION_HINTS_FILE CFSTR("edu.mit.Kerberos.SelectionHints")
+
+#define KIM_SELECTION_HINTS_ARRAY CFSTR("Hints")
+
+#define KIM_SERVICE_IDENTITY_HINT CFSTR("KIMServiceIdentityHint")
+#define KIM_APPLICATION_ID_HINT CFSTR("KIMApplicationIDHint")
+#define KIM_USER_HINT CFSTR("KIMUserHint")
+#define KIM_CLIENT_REALM_HINT CFSTR("KIMClientRealmHint")
+#define KIM_SERVICE_HINT CFSTR("KIMServiceHint")
+#define KIM_SERVICE_REALM_HINT CFSTR("KIMServiceRealmHint")
+#define KIM_SERVER_HINT CFSTR("KIMServerHint")
+#define KIM_IDENTITY_HINT CFSTR("KIMIdentityHint")
+
+#define KIM_MAX_HINTS 8 /* the number of hint types above */
+
+#include "kim_os_private.h"
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_os_selection_hints_get_selection_hints_array (CFArrayRef *out_selection_hints_array)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFPropertyListRef value = NULL;
+ CFStringRef users[] = { kCFPreferencesCurrentUser, kCFPreferencesAnyUser, NULL };
+ CFStringRef hosts[] = { kCFPreferencesCurrentHost, kCFPreferencesAnyHost, NULL };
+
+ if (!err && !out_selection_hints_array) { err = param_error (1, "out_selection_hints_array", "NULL"); }
+
+ if (!err) {
+ kim_count_t u, h;
+
+ if (!kim_library_allow_home_directory_access()) {
+ users[0] = kCFPreferencesAnyUser;
+ users[1] = NULL;
+ }
+
+ for (u = 0; !value && users[u]; u++) {
+ for (h = 0; !value && hosts[h]; h++) {
+ value = CFPreferencesCopyValue (KIM_SELECTION_HINTS_ARRAY,
+ KIM_SELECTION_HINTS_FILE,
+ users[u], hosts[h]);
+ }
+ }
+
+ if (value && CFGetTypeID (value) != CFArrayGetTypeID ()) {
+ err = kim_error_create_from_code (KIM_PREFERENCES_READ_ECODE);
+ }
+ }
+
+ if (!err) {
+ *out_selection_hints_array = value;
+ value = NULL;
+ }
+
+ if (value) { CFRelease (value); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_os_selection_hints_set_selection_hints_array (CFArrayRef in_selection_hints_array)
+{
+ kim_error_t err = KIM_NO_ERROR;
+
+ if (!err && !in_selection_hints_array) { err = param_error (1, "in_selection_hints_array", "NULL"); }
+
+ if (!err) {
+ kim_boolean_t homedir_ok = kim_library_allow_home_directory_access();
+ CFStringRef user = homedir_ok ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser;
+ CFStringRef host = homedir_ok ? kCFPreferencesAnyHost : kCFPreferencesCurrentHost;
+
+ CFPreferencesSetValue (KIM_SELECTION_HINTS_ARRAY, in_selection_hints_array,
+ KIM_SELECTION_HINTS_FILE, user, host);
+ if (!CFPreferencesSynchronize (KIM_SELECTION_HINTS_FILE, user, host)) {
+ err = kim_error_create_from_code (KIM_PREFERENCES_WRITE_ECODE);
+ }
+ }
+
+ return check_error (err);
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_os_selection_hints_create_dictionary (kim_selection_hints_t in_selection_hints,
+ kim_identity_t in_identity,
+ CFDictionaryRef *out_hints_dictionary)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_selection_hints_preference_strings preference_strings = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ kim_string_t identity_string = NULL;
+ CFStringRef keys[KIM_MAX_HINTS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ CFStringRef values[KIM_MAX_HINTS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ CFIndex i = 0;
+
+ if (!err && !in_selection_hints ) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !in_identity ) { err = param_error (2, "in_selection_hints", "NULL"); }
+ if (!err && !out_hints_dictionary) { err = param_error (3, "out_hints_dictionary", "NULL"); }
+
+ if (!err) {
+ err = kim_selection_hints_get_preference_strings (in_selection_hints, &preference_strings);
+ }
+
+ if (!err) {
+ err = kim_identity_get_string (in_identity, &identity_string);
+ }
+
+ if (!err) {
+ keys[i] = KIM_APPLICATION_ID_HINT;
+ err = kim_os_string_get_cfstring (preference_strings.application_identifier, &values[i]);
+ }
+
+ if (!err) {
+ keys[++i] = KIM_IDENTITY_HINT;
+ err = kim_os_string_get_cfstring (identity_string, &values[i]);
+ }
+
+ if (!err && preference_strings.service_identity) {
+ keys[++i] = KIM_SERVICE_IDENTITY_HINT;
+ err = kim_os_string_get_cfstring (preference_strings.service_identity, &values[i]);
+ }
+
+ if (!err && preference_strings.user) {
+ keys[++i] = KIM_USER_HINT;
+ err = kim_os_string_get_cfstring (preference_strings.user, &values[i]);
+ }
+
+ if (!err && preference_strings.client_realm) {
+ keys[++i] = KIM_CLIENT_REALM_HINT;
+ err = kim_os_string_get_cfstring (preference_strings.client_realm, &values[i]);
+ }
+
+ if (!err && preference_strings.service) {
+ keys[++i] = KIM_SERVICE_HINT;
+ err = kim_os_string_get_cfstring (preference_strings.service, &values[i]);
+ }
+
+ if (!err && preference_strings.service_realm) {
+ keys[++i] = KIM_SERVICE_REALM_HINT;
+ err = kim_os_string_get_cfstring (preference_strings.service_realm, &values[i]);
+ }
+
+ if (!err && preference_strings.server) {
+ keys[++i] = KIM_SERVER_HINT;
+ err = kim_os_string_get_cfstring (preference_strings.server, &values[i]);
+ }
+
+ if (!err) {
+ *out_hints_dictionary = CFDictionaryCreate (kCFAllocatorDefault,
+ (const void **) keys,
+ (const void **) values,
+ i+1, /* number of hints */
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ for (i = 0; i < KIM_MAX_HINTS; i++) { if (values[i]) { CFRelease (values[i]); } }
+ kim_string_free (&identity_string);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static kim_boolean_t kim_os_selection_hints_compare_hint (kim_string_t in_string,
+ CFStringRef in_value)
+{
+ kim_boolean_t equal = 0;
+
+ if (!in_string && !in_value) {
+ equal = 1;
+
+ } else if (in_string && in_value) {
+ if (CFGetTypeID (in_value) == CFStringGetTypeID ()) {
+ kim_comparison_t comparison;
+
+ kim_error_t err = kim_os_string_compare_to_cfstring (in_string, in_value,
+ &comparison);
+
+ if (!err && kim_comparison_is_equal_to (comparison)) {
+ equal = 1;
+ }
+
+ kim_error_free (&err);
+ } else {
+ kim_debug_printf ("%s: Malformed string in hints dictionary.", __FUNCTION__);
+ }
+ }
+
+ return equal;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_os_selection_hints_compare_to_dictionary (kim_selection_hints_t in_selection_hints,
+ CFDictionaryRef in_hints_dictionary,
+ kim_boolean_t *out_hints_equal)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_selection_hints_preference_strings preference_strings = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ kim_boolean_t hints_equal = 1;
+
+ if (!err && !in_selection_hints ) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !in_hints_dictionary) { err = param_error (2, "in_hints_dictionary", "NULL"); }
+ if (!err && !out_hints_equal ) { err = param_error (3, "out_hints_equal", "NULL"); }
+
+ if (!err) {
+ err = kim_selection_hints_get_preference_strings (in_selection_hints, &preference_strings);
+ }
+
+ if (!err && hints_equal) {
+ hints_equal = kim_os_selection_hints_compare_hint (preference_strings.application_identifier,
+ CFDictionaryGetValue (in_hints_dictionary,
+ KIM_APPLICATION_ID_HINT));
+ }
+
+ if (!err && hints_equal) {
+ hints_equal = kim_os_selection_hints_compare_hint (preference_strings.service_identity,
+ CFDictionaryGetValue (in_hints_dictionary,
+ KIM_SERVICE_IDENTITY_HINT));
+ }
+
+ if (!err && hints_equal) {
+ hints_equal = kim_os_selection_hints_compare_hint (preference_strings.user,
+ CFDictionaryGetValue (in_hints_dictionary,
+ KIM_USER_HINT));
+ }
+
+ if (!err && hints_equal) {
+ hints_equal = kim_os_selection_hints_compare_hint (preference_strings.client_realm,
+ CFDictionaryGetValue (in_hints_dictionary,
+ KIM_CLIENT_REALM_HINT));
+ }
+
+ if (!err && hints_equal) {
+ hints_equal = kim_os_selection_hints_compare_hint (preference_strings.service,
+ CFDictionaryGetValue (in_hints_dictionary,
+ KIM_SERVICE_HINT));
+ }
+
+ if (!err && hints_equal) {
+ hints_equal = kim_os_selection_hints_compare_hint (preference_strings.service_realm,
+ CFDictionaryGetValue (in_hints_dictionary,
+ KIM_SERVICE_REALM_HINT));
+ }
+
+ if (!err && hints_equal) {
+ hints_equal = kim_os_selection_hints_compare_hint (preference_strings.server,
+ CFDictionaryGetValue (in_hints_dictionary,
+ KIM_SERVER_HINT));
+ }
+
+ if (!err) {
+ *out_hints_equal = hints_equal;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static kim_error_t kim_os_selection_hints_get_dictionary_identity (CFDictionaryRef in_dictionary,
+ kim_identity_t *out_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFStringRef identity_cfstr = NULL;
+ kim_string_t identity_string = NULL;
+
+ identity_cfstr = CFDictionaryGetValue (in_dictionary, KIM_IDENTITY_HINT);
+ if (!identity_cfstr || CFGetTypeID (identity_cfstr) != CFStringGetTypeID ()) {
+ kim_debug_printf ("%s: Malformed hints dictionary (invalid identity).", __FUNCTION__);
+ err = kim_error_create_from_code (KIM_PREFERENCES_READ_ECODE);
+ }
+
+ if (!err) {
+ err = kim_os_string_create_from_cfstring (&identity_string, identity_cfstr);
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_string (out_identity, identity_string);
+ }
+
+ kim_string_free (&identity_string);
+
+ return check_error (err);
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_selection_hints_lookup_identity (kim_selection_hints_t in_selection_hints,
+ kim_identity_t *out_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFArrayRef hints_array = NULL;
+ CFIndex i = 0;
+ CFIndex count = 0;
+ kim_boolean_t found = 0;
+ CFDictionaryRef found_dictionary = NULL;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !out_identity ) { err = param_error (2, "out_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_os_selection_hints_get_selection_hints_array (&hints_array);
+ }
+
+ if (!err) {
+ count = CFArrayGetCount (hints_array);
+ }
+
+ for (i = 0; !err && !found && i < count; i++) {
+ CFDictionaryRef dictionary = NULL;
+
+ dictionary = CFArrayGetValueAtIndex (hints_array, i);
+ if (!dictionary) { err = os_error (ENOMEM); }
+
+ if (!err && CFGetTypeID (dictionary) != CFDictionaryGetTypeID ()) {
+ kim_debug_printf ("%s: Malformed entry in hints array.", __FUNCTION__);
+ continue; /* skip entries which aren't dictionaries */
+ }
+
+ if (!err) {
+ err = kim_os_selection_hints_compare_to_dictionary (in_selection_hints,
+ dictionary,
+ &found);
+ }
+
+ if (!err && found) {
+ found_dictionary = dictionary;
+ }
+ }
+
+ if (!err && found) {
+ err = kim_os_selection_hints_get_dictionary_identity (found_dictionary,
+ out_identity);
+ }
+
+ if (hints_array) { CFRelease (hints_array); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_selection_hints_remember_identity (kim_selection_hints_t in_selection_hints,
+ kim_identity_t in_identity)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFArrayRef old_hints_array = NULL;
+ CFMutableArrayRef new_hints_array = NULL;
+ CFIndex count = 0;
+ CFIndex i = 0;
+ kim_boolean_t hint_already_exists = 0;
+ kim_boolean_t hints_array_changed = 0;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+ if (!err && !in_identity ) { err = param_error (2, "in_identity", "NULL"); }
+
+ if (!err) {
+ err = kim_os_selection_hints_get_selection_hints_array (&old_hints_array);
+ }
+
+ if (!err) {
+ if (old_hints_array) {
+ new_hints_array = CFArrayCreateMutableCopy (kCFAllocatorDefault, 0,
+ old_hints_array);
+ } else {
+ new_hints_array = CFArrayCreateMutable (kCFAllocatorDefault, 0,
+ &kCFTypeArrayCallBacks);
+ }
+ if (!new_hints_array) { err = os_error (ENOMEM); }
+ }
+
+ if (!err) {
+ count = CFArrayGetCount (new_hints_array);
+ }
+
+ for (i = 0; !err && i < count; i++) {
+ CFDictionaryRef dictionary = NULL;
+ kim_identity_t identity = NULL;
+ kim_boolean_t hints_equal = 0;
+
+ dictionary = CFArrayGetValueAtIndex (new_hints_array, i);
+ if (!dictionary) { err = os_error (ENOMEM); }
+
+ if (!err && CFGetTypeID (dictionary) != CFDictionaryGetTypeID ()) {
+ kim_debug_printf ("%s: Malformed entry in hints array.", __FUNCTION__);
+ continue; /* skip entries which aren't dictionaries */
+ }
+
+ if (!err) {
+ err = kim_os_selection_hints_compare_to_dictionary (in_selection_hints,
+ dictionary,
+ &hints_equal);
+ }
+
+ if (!err && hints_equal) {
+ kim_comparison_t comparison;
+
+ err = kim_os_selection_hints_get_dictionary_identity (dictionary,
+ &identity);
+
+ if (!err) {
+ err = kim_identity_compare (in_identity, identity, &comparison);
+ }
+
+ if (!err) {
+ if (kim_comparison_is_equal_to (comparison) && !hint_already_exists) {
+ hint_already_exists = 1;
+ } else {
+ CFArrayRemoveValueAtIndex (new_hints_array, i);
+ i--; /* back up one index so we don't skip */
+ count = CFArrayGetCount (new_hints_array); /* count changed */
+ hints_array_changed = 1;
+ }
+ }
+
+ kim_identity_free (&identity);
+ }
+ }
+
+ if (!err && !hint_already_exists) {
+ CFDictionaryRef new_hint_dictionary = NULL;
+
+ err = kim_os_selection_hints_create_dictionary (in_selection_hints,
+ in_identity,
+ &new_hint_dictionary);
+
+ if (!err) {
+ CFArrayInsertValueAtIndex (new_hints_array, 0, new_hint_dictionary);
+ hints_array_changed = 1;
+ }
+
+ if (new_hint_dictionary) { CFRelease (new_hint_dictionary); }
+ }
+
+ if (!err && hints_array_changed) {
+ err = kim_os_selection_hints_set_selection_hints_array (new_hints_array);
+ }
+
+ if (new_hints_array ) { CFRelease (new_hints_array); }
+ if (old_hints_array ) { CFRelease (old_hints_array); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_selection_hints_forget_identity (kim_selection_hints_t in_selection_hints)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFArrayRef old_hints_array = NULL;
+ CFMutableArrayRef new_hints_array = NULL;
+ CFIndex count = 0;
+ CFIndex i = 0;
+
+ if (!err && !in_selection_hints) { err = param_error (1, "in_selection_hints", "NULL"); }
+
+ if (!err) {
+ err = kim_os_selection_hints_get_selection_hints_array (&old_hints_array);
+ }
+
+ if (!err) {
+ new_hints_array = CFArrayCreateMutableCopy (kCFAllocatorDefault, 0,
+ old_hints_array);
+ if (!new_hints_array) { err = os_error (ENOMEM); }
+ }
+
+ if (!err) {
+ count = CFArrayGetCount (new_hints_array);
+ }
+
+ for (i = 0; !err && i < count; i++) {
+ CFDictionaryRef dictionary = NULL;
+ kim_boolean_t hints_equal = 0;
+
+ dictionary = CFArrayGetValueAtIndex (new_hints_array, i);
+ if (!dictionary) { err = os_error (ENOMEM); }
+
+ if (!err && CFGetTypeID (dictionary) != CFDictionaryGetTypeID ()) {
+ kim_debug_printf ("%s: Malformed entry in hints array.", __FUNCTION__);
+ continue; /* skip entries which aren't dictionaries */
+ }
+
+ if (!err) {
+ err = kim_os_selection_hints_compare_to_dictionary (in_selection_hints,
+ dictionary,
+ &hints_equal);
+ }
+
+ if (!err && hints_equal) {
+ CFArrayRemoveValueAtIndex (new_hints_array, i);
+ i--; /* back up one index so we don't skip */
+ count = CFArrayGetCount (new_hints_array); /* count changed */
+ }
+ }
+
+ if (!err) {
+ err = kim_os_selection_hints_set_selection_hints_array (new_hints_array);
+ }
+
+ if (new_hints_array) { CFRelease (new_hints_array); }
+
+ return check_error (err);
+}
+
diff --git a/src/kim/lib/mac/kim_os_string.c b/src/kim/lib/mac/kim_os_string.c
new file mode 100644
index 0000000..a4c5699
--- /dev/null
+++ b/src/kim/lib/mac/kim_os_string.c
@@ -0,0 +1,266 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <CoreServices/CoreServices.h>
+
+#include "kim_os_private.h"
+
+/* ------------------------------------------------------------------------ */
+/* WARNING: DO NOT CALL check_error() -- it is called by error_message()!! */
+
+CFStringEncoding kim_os_string_get_encoding (void)
+{
+ typedef TextEncoding (*GetApplicationTextEncodingProcPtr) (void);
+ GetApplicationTextEncodingProcPtr GetApplicationTextEncodingPtr = NULL;
+
+ if (kim_os_library_caller_is_server ()) {
+ return kCFStringEncodingUTF8; /* server only does UTF8 */
+ }
+
+ CFBundleRef carbonBundle = CFBundleGetBundleWithIdentifier (CFSTR ("com.apple.Carbon"));
+ if (carbonBundle != NULL && CFBundleIsExecutableLoaded (carbonBundle)) {
+ GetApplicationTextEncodingPtr = (GetApplicationTextEncodingProcPtr) CFBundleGetFunctionPointerForName (carbonBundle,
+ CFSTR ("GetApplicationTextEncoding"));
+ }
+
+ if (GetApplicationTextEncodingPtr) {
+ return (CFStringEncoding) (*GetApplicationTextEncodingPtr) ();
+ }
+
+ return CFStringGetSystemEncoding ();
+}
+
+/* ------------------------------------------------------------------------ */
+/* WARNING: DO NOT CALL check_error() -- it is called by error_message()!! */
+
+CFStringRef kim_os_string_get_cfstring_for_key_and_dictionary (CFStringRef in_key,
+ CFBundleRef in_bundle)
+{
+ CFDictionaryRef dictionary = NULL;
+ CFStringRef value = NULL;
+
+ if (kim_library_allow_home_directory_access ()) {
+ // Accesses user's homedir to get localization information
+ dictionary = CFBundleGetLocalInfoDictionary (in_bundle);
+ } else {
+ dictionary = CFBundleGetInfoDictionary (in_bundle);
+ }
+
+ if (dictionary) {
+ value = (CFTypeRef) CFDictionaryGetValue (dictionary, in_key);
+ }
+
+ if (value && (CFGetTypeID (value) != CFStringGetTypeID ())) {
+ value = NULL; // Only return CFStrings
+ }
+
+ return value;
+}
+
+/* ------------------------------------------------------------------------ */
+/* WARNING: DO NOT CALL check_error() -- it is called by error_message()!! */
+
+CFStringRef kim_os_string_get_cfstring_for_key (kim_string_t in_key_string)
+{
+ CFStringRef key = NULL;
+ CFStringRef value = NULL;
+
+ if (in_key_string) {
+ key = CFStringCreateWithCString (kCFAllocatorDefault, in_key_string, kCFStringEncodingASCII);
+
+ if (key) {
+ // Try to find the key, first searching in the framework, then in the main bundle
+ CFBundleRef frameworkBundle = CFBundleGetBundleWithIdentifier (CFSTR ("edu.mit.Kerberos"));
+ if (frameworkBundle) {
+ value = kim_os_string_get_cfstring_for_key_and_dictionary (key, frameworkBundle);
+ }
+
+ if (!value) {
+ CFBundleRef mainBundle = CFBundleGetMainBundle ();
+
+ if (mainBundle) {
+ value = kim_os_string_get_cfstring_for_key_and_dictionary (key, mainBundle);
+ }
+ }
+
+ if (value && (CFGetTypeID (value) != CFStringGetTypeID ())) {
+ value = NULL; // Only return CFStrings
+ }
+
+ CFRelease (key);
+ }
+ }
+
+ return value;
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_string_create_from_cfstring (kim_string_t *out_string,
+ CFStringRef in_cfstring)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ kim_string_t string = NULL;
+ CFStringEncoding encoding = kim_os_string_get_encoding ();
+ CFIndex length = 0;
+
+ if (!err && !out_string ) { err = param_error (1, "out_string", "NULL"); }
+ if (!err && !in_cfstring) { err = param_error (2, "in_cfstring", "NULL"); }
+
+ if (!err) {
+ length = CFStringGetMaximumSizeForEncoding (CFStringGetLength (in_cfstring), encoding) + 1;
+
+ string = (char *) calloc (length, sizeof (char));
+ if (!string) { err = os_error (errno); }
+ }
+
+ if (!err) {
+ if (!CFStringGetCString (in_cfstring, (char *) string, length, encoding)) {
+ err = os_error (ENOMEM);
+ }
+ }
+
+ if (!err) {
+ *out_string = string;
+ string = NULL;
+ }
+
+ kim_string_free (&string);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_string_create_for_key (kim_string_t *out_string,
+ kim_string_t in_key_string)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFStringRef value = NULL;
+
+ if (!err && !out_string ) { err = param_error (1, "out_string", "NULL"); }
+ if (!err && !in_key_string) { err = param_error (2, "in_key_string", "NULL"); }
+
+ if (!err) {
+ value = kim_os_string_get_cfstring_for_key (in_key_string);
+ if (value) {
+ err = kim_os_string_create_from_cfstring (out_string, value);
+ } else {
+ // We failed to look it up. Use the key so we return something.
+ err = kim_string_copy (out_string, in_key_string);
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_string_get_cfstring (kim_string_t in_string,
+ CFStringRef *out_cfstring)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFStringRef cfstring = NULL;
+
+ if (!err && !in_string ) { err = param_error (1, "in_string", "NULL"); }
+ if (!err && !out_cfstring) { err = param_error (2, "out_cfstring", "NULL"); }
+
+ if (!err) {
+ cfstring = CFStringCreateWithCString (kCFAllocatorDefault, in_string, kCFStringEncodingUTF8);
+ if (!cfstring) { err = os_error (ENOMEM); }
+ }
+
+ if (!err) {
+ *out_cfstring = cfstring;
+ cfstring = NULL;
+ }
+
+ if (cfstring) { CFRelease (cfstring); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_string_compare (kim_string_t in_string,
+ kim_string_t in_compare_to_string,
+ kim_comparison_t *out_comparison)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFStringRef cfstring = NULL;
+ CFStringRef compare_to_cfstring = NULL;
+
+ if (!err && !in_string ) { err = param_error (1, "in_string", "NULL"); }
+ if (!err && !in_compare_to_string) { err = param_error (2, "in_compare_to_string", "NULL"); }
+ if (!err && !out_comparison ) { err = param_error (3, "out_comparison", "NULL"); }
+
+ if (!err) {
+ err = kim_os_string_get_cfstring (in_string, &cfstring);
+ }
+
+ if (!err) {
+ err = kim_os_string_get_cfstring (in_compare_to_string, &compare_to_cfstring);
+ }
+
+ if (!err) {
+ /* Returned CFComparisonResult is compatible with kim_comparison_t */
+ *out_comparison = CFStringCompare (cfstring, compare_to_cfstring, 0);
+ }
+
+ if (cfstring ) { CFRelease (cfstring); }
+ if (compare_to_cfstring) { CFRelease (compare_to_cfstring); }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error_t kim_os_string_compare_to_cfstring (kim_string_t in_string,
+ CFStringRef in_compare_to_cfstring,
+ kim_comparison_t *out_comparison)
+{
+ kim_error_t err = KIM_NO_ERROR;
+ CFStringRef cfstring = NULL;
+
+ if (!err && !in_string ) { err = param_error (1, "in_string", "NULL"); }
+ if (!err && !in_compare_to_cfstring) { err = param_error (2, "in_compare_to_cfstring", "NULL"); }
+ if (!err && !out_comparison ) { err = param_error (3, "out_comparison", "NULL"); }
+
+ if (!err) {
+ err = kim_os_string_get_cfstring (in_string, &cfstring);
+ }
+
+ if (!err) {
+ /* Returned CFComparisonResult is compatible with kim_comparison_t */
+ *out_comparison = CFStringCompare (cfstring, in_compare_to_cfstring, 0);
+ }
+
+ if (cfstring) { CFRelease (cfstring); }
+
+ return check_error (err);
+}
diff --git a/src/kim/test/main.c b/src/kim/test/main.c
new file mode 100644
index 0000000..c1c5bd1
--- /dev/null
+++ b/src/kim/test/main.c
@@ -0,0 +1,82 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "test_kim_identity.h"
+#include "test_kim_preferences.h"
+#include "test_kim_selection_hints.h"
+
+int main (int argc, const char * argv[])
+{
+ kim_test_state_t state = NULL;
+
+ if (test_init (&state)) {
+ return 1;
+ }
+
+ test_kim_identity_create_from_krb5_principal (state);
+
+ test_kim_identity_create_from_string (state);
+
+ test_kim_identity_copy (state);
+
+ test_kim_identity_compare (state);
+
+ test_kim_identity_get_display_string (state);
+
+ test_kim_identity_get_realm (state);
+
+ test_kim_identity_get_number_of_components (state);
+
+ test_kim_identity_get_component_at_index (state);
+
+ test_kim_identity_get_krb5_principal (state);
+
+ test_kim_preferences_create (state);
+
+ test_kim_preferences_copy (state);
+
+ test_kim_preferences_set_options (state);
+
+ test_kim_preferences_set_remember_options (state);
+
+ test_kim_preferences_set_client_identity (state);
+
+ test_kim_selection_hints_set_service_identity_hint (state);
+
+ test_kim_selection_hints_set_client_realm_hint (state);
+
+ test_kim_selection_hints_set_user_hint (state);
+
+ test_kim_selection_hints_set_service_realm_hint (state);
+
+ test_kim_selection_hints_set_service_hint (state);
+
+ test_kim_selection_hints_set_server_hint (state);
+
+ test_kim_selection_hints_remember_identity (state);
+
+ return test_cleanup (state);
+}
diff --git a/src/kim/test/test_kim_common.c b/src/kim/test/test_kim_common.c
new file mode 100644
index 0000000..1e3b967
--- /dev/null
+++ b/src/kim/test/test_kim_common.c
@@ -0,0 +1,159 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <test_kim_common.h>
+
+const char *k_no_test_name = "No test name set";
+
+/* ------------------------------------------------------------------------ */
+
+int test_init (kim_test_state_t *out_state)
+{
+ kim_test_state_t state = NULL;
+
+ printf ("Initializing tests... ");
+
+ state = malloc (sizeof (*state));
+ if (!state) {
+ printf ("out of memory.\n\n");
+ return 1;
+ }
+
+ state->test_name = k_no_test_name;
+ state->global_fail_count = 0;
+ state->test_fail_count = 0;
+
+ *out_state = state;
+
+ printf ("done.\n\n");
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int test_cleanup (kim_test_state_t io_state)
+{
+ int global_fail_count = io_state->global_fail_count;
+
+ printf ("Exiting. %d total failures.", global_fail_count);
+ free (io_state);
+
+ return global_fail_count;
+}
+
+/* ------------------------------------------------------------------------ */
+
+void start_test (kim_test_state_t in_state,
+ const char *in_test_name)
+{
+ in_state->test_name = in_test_name;
+ in_state->test_fail_count = 0;
+
+ printf ("Testing %s...\n", in_state->test_name);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void end_test (kim_test_state_t in_state)
+{
+ printf ("Finished testing %s. %d failures.\n\n",
+ in_state->test_name, in_state->test_fail_count);
+
+ in_state->test_name = k_no_test_name;
+ in_state->global_fail_count += in_state->test_fail_count;
+ in_state->test_fail_count = 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+void fail_if_error (kim_test_state_t in_state,
+ const char *in_function,
+ kim_error_t in_err,
+ const char *in_format,
+ ...)
+{
+ if (in_err) {
+ va_list args;
+
+ printf ("\tFAILURE: ");
+ printf ("%s() got %d (%s) ",
+ in_function, kim_error_get_code (in_err),
+ kim_error_get_display_string (in_err));
+
+ va_start (args, in_format);
+ vprintf (in_format, args);
+ va_end (args);
+
+ printf ("\n");
+
+ in_state->test_fail_count++;
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+
+void fail_if_error_code (kim_test_state_t in_state,
+ const char *in_function,
+ kim_error_code_t in_code,
+ const char *in_format,
+ ...)
+{
+ if (in_code) {
+ va_list args;
+
+ printf ("\tFAILURE: ");
+ printf ("%s() got %d (%s) ",
+ in_function, in_code, error_message (in_code));
+
+ va_start (args, in_format);
+ vprintf (in_format, args);
+ va_end (args);
+
+ printf ("\n");
+
+ in_state->test_fail_count++;
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+
+void log_failure (kim_test_state_t in_state,
+ const char *in_format,
+ ...)
+{
+ va_list args;
+
+ printf ("\tFAILURE: ");
+
+ va_start (args, in_format);
+ vprintf (in_format, args);
+ va_end (args);
+
+ printf ("\n");
+
+ in_state->test_fail_count++;
+}
diff --git a/src/kim/test/test_kim_common.h b/src/kim/test/test_kim_common.h
new file mode 100644
index 0000000..1612242
--- /dev/null
+++ b/src/kim/test/test_kim_common.h
@@ -0,0 +1,78 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef TEST_KIM_COMMON_H
+#define TEST_KIM_COMMON_H
+
+#include <kim/kim.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct kim_test_state_d {
+ const char *test_name;
+ int global_fail_count;
+ int test_fail_count;
+} *kim_test_state_t;
+
+int test_init (kim_test_state_t *out_state);
+
+int test_cleanup (kim_test_state_t io_state);
+
+void start_test (kim_test_state_t in_state,
+ const char *in_test_name);
+
+void end_test (kim_test_state_t in_state);
+
+void fail_if_error (kim_test_state_t in_state,
+ const char *in_function,
+ kim_error_t in_err,
+ const char *in_format,
+ ...)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+__attribute__ ((__format__ (__printf__, 4, 5)))
+#endif
+;
+
+void fail_if_error_code (kim_test_state_t in_state,
+ const char *in_function,
+ kim_error_code_t in_code,
+ const char *in_format,
+ ...)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+__attribute__ ((__format__ (__printf__, 4, 5)))
+#endif
+;
+
+void log_failure (kim_test_state_t in_state,
+ const char *in_format,
+ ...)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif
+;
+
+#endif /* TEST_KIM_COMMON_H */
diff --git a/src/kim/test/test_kim_identity.c b/src/kim/test/test_kim_identity.c
new file mode 100644
index 0000000..be97726
--- /dev/null
+++ b/src/kim/test/test_kim_identity.c
@@ -0,0 +1,559 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "test_kim_identity.h"
+
+typedef struct test_identity_d {
+ const char *string;
+ const char *display_string;
+ kim_boolean_t is_tgt_service;
+ const char *realm;
+ kim_count_t component_count;
+ const char *components[5];
+} test_identity_t;
+
+
+test_identity_t test_identities[] = {
+ {"a@B", "a@B", 0, "B", 1, { "a", NULL, NULL, NULL, NULL } },
+ {"user@EXAMPLE.COM", "user@EXAMPLE.COM", 0, "EXAMPLE.COM", 1, { "user", NULL, NULL, NULL, NULL } },
+ {"krbtgt@EXAMPLE.COM", "krbtgt@EXAMPLE.COM", 0, "EXAMPLE.COM", 1, { "krbtgt", NULL, NULL, NULL, NULL } },
+ {"krbtgt/EXAMPLE.COM@EXAMPLE.COM", "krbtgt/EXAMPLE.COM@EXAMPLE.COM", 1, "EXAMPLE.COM", 2, { "krbtgt", "EXAMPLE.COM", NULL, NULL, NULL } },
+ {"krbtgt/OTHER.COM@EXAMPLE.COM", "krbtgt/OTHER.COM@EXAMPLE.COM", 1, "EXAMPLE.COM", 2, { "krbtgt", "OTHER.COM", NULL, NULL, NULL } },
+ {"a space@EXAMPLE.COM", "a space@EXAMPLE.COM", 0, "EXAMPLE.COM", 1, { "a space", NULL, NULL, NULL, NULL } },
+ {"üñîçödé@EXAMPLE.COM", "üñîçödé@EXAMPLE.COM", 0, "EXAMPLE.COM", 1, { "üñîçödé", NULL, NULL, NULL, NULL } },
+ {"user.name@EXAMPLE.COM", "user.name@EXAMPLE.COM", 0, "EXAMPLE.COM", 1, { "user.name", NULL, NULL, NULL, NULL } },
+ {"user\\/instance@EXAMPLE.COM", "user/instance@EXAMPLE.COM", 0, "EXAMPLE.COM", 1, { "user\/instance", NULL, NULL, NULL, NULL } },
+ {"user\\@instance@EXAMPLE.COM", "user@instance@EXAMPLE.COM", 0, "EXAMPLE.COM", 1, { "user\@instance", NULL, NULL, NULL, NULL } },
+ {"user/instance@EXAMPLE.COM", "user/instance@EXAMPLE.COM", 0, "EXAMPLE.COM", 2, { "user", "instance", NULL, NULL, NULL } },
+ {"user/i1/i2@EXAMPLE.COM", "user/i1/i2@EXAMPLE.COM", 0, "EXAMPLE.COM", 3, { "user", "i1", "i2", NULL, NULL } },
+ {"user/i1/i2/i3/i4@EXAMPLE.COM", "user/i1/i2/i3/i4@EXAMPLE.COM", 0, "EXAMPLE.COM", 5, { "user", "i1", "i2", "i3", "i4" } },
+ {"an insanely long principal for testing icky hex key principals/an insanely long instance for testing icky hex key principals@AN-INSANELY-LONG-REALM-NAME-FOR-TESTING-AUTOGENERATED-REALM-NAMES",
+ "an insanely long principal for testing icky hex key principals/an insanely long instance for testing icky hex key principals@AN-INSANELY-LONG-REALM-NAME-FOR-TESTING-AUTOGENERATED-REALM-NAMES",
+ 0, "AN-INSANELY-LONG-REALM-NAME-FOR-TESTING-AUTOGENERATED-REALM-NAMES",
+ 2, { "an insanely long principal for testing icky hex key principals", "an insanely long instance for testing icky hex key principals", NULL, NULL, NULL } },
+ { NULL, NULL, 0, NULL, 0, { NULL, NULL, NULL, NULL, NULL } },
+};
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_identity_create_from_krb5_principal (kim_test_state_t state)
+{
+ kim_count_t i = 0;
+
+ start_test (state, "kim_identity_create_from_krb5_principal");
+
+ for (i = 0; test_identities[i].string; i++) {
+ krb5_error_code code = 0;
+ kim_error_t err = NULL;
+ krb5_context context = NULL;
+ krb5_principal principal = NULL;
+ kim_identity_t identity = NULL;
+ kim_string_t string = NULL;
+
+ printf (".");
+
+ code = krb5_init_context (&context);
+ fail_if_error_code (state, "krb5_init_context", code,
+ "while initializing context");
+
+ if (!code) {
+ code = krb5_parse_name (context, test_identities[i].string, &principal);
+ fail_if_error_code (state, "krb5_parse_name", code,
+ "while creating krb5_principal for %s",
+ test_identities[i].string);
+ }
+
+ if (!code && !err) {
+ err = kim_identity_create_from_krb5_principal (&identity, context, principal);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+ }
+
+ if (!code && !err) {
+ err = kim_identity_get_string (identity, &string);
+ fail_if_error (state, "kim_identity_get_string", err,
+ "while getting the string for %s",
+ test_identities[i].string);
+ }
+
+ if (!code && !err && strcmp (string, test_identities[i].string)) {
+ log_failure (state, "Unexpected string (got '%s', expected '%s')",
+ string, test_identities[i].string);
+ }
+
+ kim_string_free (&string);
+ kim_identity_free (&identity);
+ if (principal) { krb5_free_principal (context, principal); }
+ if (context ) { krb5_free_context (context); }
+
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_identity_create_from_string (kim_test_state_t state)
+{
+ kim_count_t i = 0;
+
+ start_test (state, "kim_identity_create_from_string");
+
+ for (i = 0; test_identities[i].string; i++) {
+ kim_error_t err = NULL;
+ kim_identity_t identity = NULL;
+ kim_string_t string = NULL;
+
+ printf (".");
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, test_identities[i].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+ }
+
+ if (!err) {
+ err = kim_identity_get_string (identity, &string);
+ fail_if_error (state, "kim_identity_get_string", err,
+ "while getting the string for %s",
+ test_identities[i].string);
+ }
+
+ if (!err && strcmp (string, test_identities[i].string)) {
+ log_failure (state, "Unexpected string (got '%s', expected '%s')",
+ string, test_identities[i].string);
+ }
+
+ kim_string_free (&string);
+ kim_identity_free (&identity);
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_identity_copy (kim_test_state_t state)
+{
+ kim_count_t i = 0;
+
+ start_test (state, "kim_identity_copy");
+
+ for (i = 0; test_identities[i].string; i++) {
+ kim_error_t err = NULL;
+ kim_identity_t identity = NULL;
+ kim_identity_t identity_copy = NULL;
+ kim_string_t string = NULL;
+
+ printf (".");
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, test_identities[i].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+ }
+
+ if (!err) {
+ err = kim_identity_copy (&identity_copy, identity);
+ fail_if_error (state, "kim_identity_copy", err,
+ "while copying %s", test_identities[i].string);
+ }
+
+ if (!err) {
+ err = kim_identity_get_string (identity_copy, &string);
+ fail_if_error (state, "kim_identity_get_string", err,
+ "while getting the string for the copy of %s",
+ test_identities[i].string);
+ }
+
+ if (!err && strcmp (string, test_identities[i].string)) {
+ log_failure (state, "Unexpected string (got '%s', expected '%s')",
+ string, test_identities[i].string);
+ }
+
+ kim_string_free (&string);
+ kim_identity_free (&identity_copy);
+ kim_identity_free (&identity);
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_identity_compare (kim_test_state_t state)
+{
+ kim_count_t i, j = 0;
+
+ start_test (state, "kim_identity_create_from_string");
+
+ for (i = 0; test_identities[i].string; i++) {
+ kim_error_t err = NULL;
+ kim_identity_t identity = NULL;
+
+ printf (".");
+
+ err = kim_identity_create_from_string (&identity, test_identities[i].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+
+ for (j = 0; !err && test_identities[j].string; j++) {
+ kim_identity_t compare_to_identity = NULL;
+ kim_comparison_t comparison = 0;
+
+ err = kim_identity_create_from_string (&compare_to_identity, test_identities[j].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[j].string);
+
+ if (!err) {
+ err = kim_identity_compare (identity, compare_to_identity, &comparison);
+ fail_if_error (state, "kim_identity_compare", err,
+ "while comparing %s and %s",
+ test_identities[i].string, test_identities[j].string);
+ }
+
+ if (!err) {
+ if (i == j && !kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Expected %s and %s to be equal but kim_identity_compare returned %d",
+ test_identities[i].string, test_identities[j].string, comparison);
+
+ } else if (i != j && kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Expected %s and %s to be NOT equal but kim_identity_compare returned %d",
+ test_identities[i].string, test_identities[j].string, comparison);
+ }
+ }
+
+ kim_identity_free (&compare_to_identity);
+ }
+
+ kim_identity_free (&identity);
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_identity_get_display_string (kim_test_state_t state)
+{
+ kim_count_t i = 0;
+
+ start_test (state, "kim_identity_get_display_string");
+
+ for (i = 0; test_identities[i].string; i++) {
+ kim_error_t err = NULL;
+ kim_identity_t identity = NULL;
+ kim_string_t string = NULL;
+
+ printf (".");
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, test_identities[i].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+ }
+
+ if (!err) {
+ err = kim_identity_get_display_string (identity, &string);
+ fail_if_error (state, "kim_identity_get_display_string", err,
+ "while getting the display string for %s",
+ test_identities[i].string);
+ }
+
+ if (!err && strcmp (string, test_identities[i].display_string)) {
+ log_failure (state, "Unexpected display string for %s (got '%s', expected '%s')",
+ test_identities[i].string, string, test_identities[i].display_string);
+ }
+
+ kim_string_free (&string);
+ kim_identity_free (&identity);
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_identity_get_realm (kim_test_state_t state)
+{
+ kim_count_t i = 0;
+
+ start_test (state, "kim_identity_get_realm");
+
+ for (i = 0; test_identities[i].string; i++) {
+ kim_error_t err = NULL;
+ kim_identity_t identity = NULL;
+ kim_string_t realm = NULL;
+
+ printf (".");
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, test_identities[i].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+ }
+
+ if (!err) {
+ err = kim_identity_get_realm (identity, &realm);
+ fail_if_error (state, "kim_identity_get_realm", err,
+ "while getting the realm for %s", test_identities[i].string);
+ }
+
+ if (!err && strcmp (realm, test_identities[i].realm)) {
+ log_failure (state, "Unexpected realm string (got '%s', expected '%s')",
+ realm, test_identities[i].realm);
+ }
+
+ kim_string_free (&realm);
+ kim_identity_free (&identity);
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_identity_get_number_of_components (kim_test_state_t state)
+{
+ kim_count_t i = 0;
+
+ start_test (state, "kim_identity_get_number_of_components");
+
+ for (i = 0; test_identities[i].string; i++) {
+ kim_error_t err = NULL;
+ kim_identity_t identity = NULL;
+ kim_count_t count = 0;
+
+ printf (".");
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, test_identities[i].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+ }
+
+ if (!err) {
+ err = kim_identity_get_number_of_components (identity, &count);
+ fail_if_error (state, "kim_identity_get_number_of_components", err,
+ "while getting number of components of %s",
+ test_identities[i].string);
+ }
+
+ if (!err && (count != test_identities[i].component_count)) {
+ log_failure (state, "Unexpected component count of %s (got %d, expected %d)",
+ test_identities[i].string, (int) count, (int) test_identities[i].component_count);
+ }
+
+ kim_identity_free (&identity);
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_identity_get_component_at_index (kim_test_state_t state)
+{
+ kim_count_t i = 0;
+
+ start_test (state, "kim_identity_get_component_at_index");
+
+ for (i = 0; test_identities[i].string; i++) {
+ kim_error_t err = NULL;
+ kim_identity_t identity = NULL;
+ kim_count_t c = 0;
+
+ printf (".");
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, test_identities[i].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+ }
+
+ for (c = 0; !err && c < test_identities[i].component_count; c++) {
+ kim_string_t component = NULL;
+
+ err = kim_identity_get_component_at_index (identity, c, &component);
+ fail_if_error (state, "kim_identity_get_component_at_index", err,
+ "while getting component %d of %s", (int) c,
+ test_identities[i].string);
+
+ if (!err && strcmp (component, test_identities[i].components[c])) {
+ log_failure (state, "Unexpected component %d of %s (got '%s', expected '%s')",
+ (int) c, test_identities[i].string,
+ component, test_identities[i].components[c]);
+ }
+
+ kim_string_free (&component);
+ }
+
+ kim_identity_free (&identity);
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_identity_get_krb5_principal (kim_test_state_t state)
+{
+ kim_count_t i = 0;
+
+ start_test (state, "kim_identity_get_krb5_principal");
+
+ for (i = 0; test_identities[i].string; i++) {
+ krb5_error_code code = 0;
+ kim_error_t err = NULL;
+ krb5_context context = NULL;
+ krb5_principal principal = NULL;
+ krb5_principal identity_principal = NULL;
+ kim_identity_t identity = NULL;
+
+ printf (".");
+
+ code = krb5_init_context (&context);
+ fail_if_error_code (state, "krb5_init_context", code,
+ "while initializing context");
+
+ if (!code) {
+ code = krb5_parse_name (context, test_identities[i].string, &principal);
+ fail_if_error_code (state, "krb5_parse_name", code,
+ "while creating krb5_principal for %s",
+ test_identities[i].string);
+ }
+
+ if (!code && !err) {
+ err = kim_identity_create_from_string (&identity, test_identities[i].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+ }
+
+ if (!code && !err) {
+ err = kim_identity_get_krb5_principal (identity, context, &identity_principal);
+ fail_if_error (state, "kim_identity_get_krb5_principal", err,
+ "while getting the krb5_principal for %s",
+ test_identities[i].string);
+ }
+
+ if (!code && !err) {
+ if (!krb5_principal_compare (context, principal, identity_principal)) {
+ log_failure (state, "Principal and identity principal for %s do not match",
+ test_identities[i].string);
+ }
+ }
+
+ kim_identity_free (&identity);
+ if (identity_principal) { krb5_free_principal (context, identity_principal); }
+ if (principal ) { krb5_free_principal (context, principal); }
+ if (context ) { krb5_free_context (context); }
+
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+/*
+void test_kim_identity_is_tgt_service (kim_test_state_t state)
+{
+ kim_count_t i = 0;
+
+ start_test (state, "kim_identity_is_tgt_service");
+
+ for (i = 0; test_identities[i].string; i++) {
+ kim_error_t err = NULL;
+ kim_identity_t identity = NULL;
+ kim_boolean_t is_tgt_service = 0;
+
+ printf (".");
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, test_identities[i].string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s",
+ test_identities[i].string);
+ }
+
+ if (!err) {
+ err = kim_identity_is_tgt_service (identity, &is_tgt_service);
+ fail_if_error (state, "kim_identity_is_tgt_service", err,
+ "while determining if %s is a tgt service",
+ test_identities[i].string);
+ }
+
+ if (!err && (is_tgt_service != test_identities[i].is_tgt_service)) {
+ log_failure (state, "Unexpected result from kim_identity_is_tgt_service for %s (got %d, expected %d)",
+ test_identities[i].string, is_tgt_service, test_identities[i].is_tgt_service);
+ }
+
+ kim_identity_free (&identity);
+ kim_error_free (&err);
+ }
+
+ printf ("\n");
+
+ end_test (state);
+}
+*/
diff --git a/src/kim/test/test_kim_identity.h b/src/kim/test/test_kim_identity.h
new file mode 100644
index 0000000..a294c2c
--- /dev/null
+++ b/src/kim/test/test_kim_identity.h
@@ -0,0 +1,50 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef TEST_KIM_IDENTITY_H
+#define TEST_KIM_IDENTITY_H
+
+#include "test_kim_common.h"
+
+void test_kim_identity_create_from_krb5_principal (kim_test_state_t state);
+
+void test_kim_identity_create_from_string (kim_test_state_t state);
+
+void test_kim_identity_copy (kim_test_state_t state);
+
+void test_kim_identity_compare (kim_test_state_t state);
+
+void test_kim_identity_get_display_string (kim_test_state_t state);
+
+void test_kim_identity_get_realm (kim_test_state_t state);
+
+void test_kim_identity_get_number_of_components (kim_test_state_t state);
+
+void test_kim_identity_get_component_at_index (kim_test_state_t state);
+
+void test_kim_identity_get_krb5_principal (kim_test_state_t state);
+
+#endif /* TEST_KIM_IDENTITY_H */
diff --git a/src/kim/test/test_kim_preferences.c b/src/kim/test/test_kim_preferences.c
new file mode 100644
index 0000000..6cf0ba7
--- /dev/null
+++ b/src/kim/test/test_kim_preferences.c
@@ -0,0 +1,298 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "test_kim_preferences.h"
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_preferences_create (kim_test_state_t state)
+{
+
+ start_test (state, "kim_preferences_create");
+
+ {
+ kim_error_t err = NULL;
+ kim_preferences_t prefs = NULL;
+
+ err = kim_preferences_create (&prefs);
+ fail_if_error (state, "kim_preferences_create", err,
+ "while creating preferences");
+
+ kim_preferences_free (&prefs);
+ kim_error_free (&err);
+ }
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_preferences_copy (kim_test_state_t state)
+{
+
+ start_test (state, "test_kim_preferences_copy");
+
+ {
+ kim_error_t err = NULL;
+ kim_preferences_t prefs = NULL;
+ kim_preferences_t prefs_copy = NULL;
+
+ err = kim_preferences_create (&prefs);
+ fail_if_error (state, "kim_preferences_create", err,
+ "while creating preferences");
+
+ if (!err) {
+ err = kim_preferences_copy (&prefs_copy, prefs);
+ fail_if_error (state, "kim_preferences_copy", err,
+ "while copying preferences");
+ }
+
+ kim_preferences_free (&prefs_copy);
+ kim_preferences_free (&prefs);
+ kim_error_free (&err);
+ }
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_preferences_set_options (kim_test_state_t state)
+{
+
+ start_test (state, "kim_preferences_set_options");
+
+ {
+ kim_error_t err = NULL;
+ kim_preferences_t prefs = NULL;
+ kim_options_t old_options = NULL;
+ kim_options_t new_options = NULL;
+ kim_options_t verify_options = NULL;
+ const char *custom_data = "Some custom data";
+ const char *verify_custom_data = NULL;
+
+ err = kim_preferences_create (&prefs);
+ fail_if_error (state, "kim_preferences_create", err,
+ "while creating preferences");
+
+ if (!err) {
+ err = kim_preferences_get_options (prefs, &old_options);
+ fail_if_error (state, "kim_preferences_get_options", err,
+ "while getting old options");
+ }
+
+ if (!err) {
+ err = kim_options_create (&new_options);
+ fail_if_error (state, "kim_options_create", err,
+ "while creating options");
+ }
+
+ if (!err) {
+ err = kim_options_set_data (new_options, custom_data);
+ fail_if_error (state, "kim_options_set_data", err,
+ "while setting the custom data to %s", custom_data);
+ }
+
+ if (!err) {
+ err = kim_preferences_set_options (prefs, new_options);
+ fail_if_error (state, "kim_preferences_set_options", err,
+ "while setting the new options");
+ }
+
+ if (!err) {
+ err = kim_preferences_get_options (prefs, &verify_options);
+ fail_if_error (state, "kim_preferences_get_options", err,
+ "while getting options for verification");
+ }
+
+ if (!err) {
+ err = kim_options_get_data (verify_options, (const void **)&verify_custom_data);
+ fail_if_error (state, "kim_options_get_data", err,
+ "while getting the custom data of the verify options");
+ }
+
+ if (!err && custom_data != verify_custom_data) {
+ log_failure (state, "Unexpected custom data in options (got %p, expected %p)",
+ verify_custom_data, custom_data);
+ }
+
+ if (!err) {
+ err = kim_preferences_set_options (prefs, old_options);
+ fail_if_error (state, "kim_preferences_set_options", err,
+ "while restoring the options");
+ }
+
+ kim_options_free (&old_options);
+ kim_options_free (&new_options);
+ kim_options_free (&verify_options);
+ kim_preferences_free (&prefs);
+ kim_error_free (&err);
+ }
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_preferences_set_remember_options (kim_test_state_t state)
+{
+
+ start_test (state, "kim_preferences_set_remember_options");
+
+ {
+ kim_error_t err = NULL;
+ kim_preferences_t prefs = NULL;
+ kim_boolean_t remember_options = FALSE;
+
+ err = kim_preferences_create (&prefs);
+ fail_if_error (state, "kim_preferences_create", err,
+ "while creating preferences");
+
+ if (!err) {
+ err = kim_preferences_set_remember_options (prefs, TRUE);
+ fail_if_error (state, "kim_preferences_set_remember_options", err,
+ "while setting the preference to remember options");
+ }
+
+ if (!err) {
+ err = kim_preferences_get_remember_options (prefs, &remember_options);
+ fail_if_error (state, "kim_preferences_get_remember_options", err,
+ "while getting the preference to remember options");
+ }
+
+ if (!err && !remember_options) {
+ log_failure (state, "Unexpected remember options preference (got %d, expected TRUE)",
+ remember_options);
+ }
+
+ if (!err) {
+ err = kim_preferences_set_remember_options (prefs, FALSE);
+ fail_if_error (state, "kim_preferences_set_remember_options", err,
+ "while setting the preference to remember options");
+ }
+
+ if (!err) {
+ err = kim_preferences_get_remember_options (prefs, &remember_options);
+ fail_if_error (state, "kim_preferences_get_remember_options", err,
+ "while getting the preference to remember options");
+ }
+
+ if (!err && remember_options) {
+ log_failure (state, "Unexpected remember options preference (got %d, expected 0)",
+ remember_options);
+ }
+
+ kim_preferences_free (&prefs);
+ kim_error_free (&err);
+ }
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_preferences_set_client_identity (kim_test_state_t state)
+{
+
+ start_test (state, "kim_preferences_set_client_identity");
+
+ {
+ kim_error_t err = NULL;
+ kim_preferences_t prefs = NULL;
+ kim_string_t test_string = "user@EXAMPLE.COM";
+ kim_identity_t test_identity = KIM_IDENTITY_ANY;
+ kim_string_t string = NULL;
+ kim_identity_t identity = KIM_IDENTITY_ANY;
+ kim_comparison_t comparison = 0;
+
+ err = kim_preferences_create (&prefs);
+ fail_if_error (state, "kim_preferences_create", err,
+ "while creating preferences");
+
+ if (!err) {
+ err = kim_identity_create_from_string (&test_identity, test_string);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating the identity for %s", test_string);
+ }
+
+ if (!err) {
+ err = kim_preferences_set_client_identity (prefs, KIM_IDENTITY_ANY);
+ fail_if_error (state, "kim_preferences_set_client_identity", err,
+ "while setting the identity to KIM_IDENTITY_ANY");
+ }
+
+ if (!err) {
+ err = kim_preferences_get_client_identity (prefs, &identity);
+ fail_if_error (state, "kim_preferences_get_client_identity", err,
+ "while getting the client identity preference");
+ }
+
+ if (!err && identity != KIM_IDENTITY_ANY) {
+ log_failure (state, "Unexpected client identity preference (got %p, expected %p)",
+ identity, KIM_IDENTITY_ANY);
+ kim_identity_free (&identity);
+ }
+
+ if (!err) {
+ err = kim_preferences_set_client_identity (prefs, test_identity);
+ fail_if_error (state, "kim_preferences_set_client_identity", err,
+ "while setting the identity to %s", test_string);
+ }
+
+ if (!err) {
+ err = kim_preferences_get_client_identity (prefs, &identity);
+ fail_if_error (state, "kim_preferences_get_client_identity", err,
+ "while getting the client identity preference");
+ }
+
+ if (!err && identity) {
+ err = kim_identity_get_string (identity, &string);
+ fail_if_error (state, "kim_identity_get_string", err,
+ "while getting the string for client identity preference");
+ }
+
+ if (!err) {
+ err = kim_identity_compare (identity, test_identity, &comparison);
+ fail_if_error (state, "kim_identity_compare", err,
+ "while comparing %s to the identity preference %s",
+ test_string, string ? string : "NULL");
+ }
+
+ if (!err && !kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Unexpected client identity preference (got %s, expected %s)",
+ string ? string : "NULL", test_string);
+ kim_identity_free (&identity);
+ }
+
+ kim_string_free (&string);
+ kim_identity_free (&identity);
+ kim_identity_free (&test_identity);
+ kim_preferences_free (&prefs);
+ kim_error_free (&err);
+ }
+
+ end_test (state);
+}
diff --git a/src/kim/test/test_kim_preferences.h b/src/kim/test/test_kim_preferences.h
new file mode 100644
index 0000000..e86f11f
--- /dev/null
+++ b/src/kim/test/test_kim_preferences.h
@@ -0,0 +1,42 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef TEST_KIM_PREFERENCES_H
+#define TEST_KIM_PREFERENCES_H
+
+#include "test_kim_common.h"
+
+void test_kim_preferences_create (kim_test_state_t state);
+
+void test_kim_preferences_copy (kim_test_state_t state);
+
+void test_kim_preferences_set_options (kim_test_state_t state);
+
+void test_kim_preferences_set_remember_options (kim_test_state_t state);
+
+void test_kim_preferences_set_client_identity (kim_test_state_t state);
+
+#endif /* TEST_KIM_PREFERENCES_H */
diff --git a/src/kim/test/test_kim_selection_hints.c b/src/kim/test/test_kim_selection_hints.c
new file mode 100644
index 0000000..d2bc511
--- /dev/null
+++ b/src/kim/test/test_kim_selection_hints.c
@@ -0,0 +1,469 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "test_kim_selection_hints.h"
+
+#define KSH_TEST_ID "edu.mit.Kerberos.test_kim"
+#define KSH_SERVICE_IDENTITY "service/server.example.com@EXAMPLE.COM"
+#define KSH_SERVICE "service"
+#define KSH_SERVER "server.example.com"
+#define KSH_SERVICE_REALM "EXAMPLE.COM"
+#define KSH_USER "jdoe"
+#define KSH_CLIENT_REALM "USERS.EXAMPLE.COM"
+
+#define KSH_IDENTITY "jdoe@USERS.EXAMPLE.COM"
+
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_selection_hints_set_service_identity_hint (kim_test_state_t state)
+{
+ kim_error_t err = NULL;
+ kim_selection_hints_t hints = NULL;
+ kim_identity_t service_identity = NULL;
+ kim_identity_t identity = KIM_IDENTITY_ANY;
+ kim_string_t string = NULL;
+ kim_comparison_t comparison = 0;
+
+ start_test (state, "kim_selection_hints_set_service_identity_hint");
+
+ if (!err) {
+ err = kim_selection_hints_create (&hints, KSH_TEST_ID);
+ fail_if_error (state, "kim_selection_hints_create", err,
+ "while creating selection hints for %s", KSH_TEST_ID);
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_string (&service_identity,
+ KSH_SERVICE_IDENTITY);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating an identity for %s",
+ KSH_SERVICE_IDENTITY);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_service_identity_hint (hints, service_identity);
+ fail_if_error (state, "kim_selection_hints_set_service_identity_hint",
+ err, "while setting service identity to %s",
+ KSH_SERVICE_IDENTITY);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_get_service_identity_hint (hints, &identity);
+ fail_if_error (state, "kim_selection_hints_get_service_identity_hint",
+ err, "while getting service identity %s",
+ KSH_SERVICE_IDENTITY);
+ }
+
+ if (!err && identity) {
+ err = kim_identity_get_string (identity, &string);
+ fail_if_error (state, "kim_identity_get_string", err,
+ "while getting the string for the service identity hint");
+ }
+
+ if (!err) {
+ err = kim_identity_compare (service_identity, identity, &comparison);
+ fail_if_error (state, "kim_identity_compare", err,
+ "while comparing %s to the identity hint %s",
+ KSH_SERVICE_IDENTITY, string ? string : "NULL");
+ }
+
+ if (!err && !kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Unexpected service identity hint (got %s, expected %s)",
+ string ? string : "NULL", KSH_SERVICE_IDENTITY);
+ kim_identity_free (&identity);
+ }
+
+ kim_string_free (&string);
+ kim_identity_free (&service_identity);
+ kim_selection_hints_free (&hints);
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_selection_hints_set_client_realm_hint (kim_test_state_t state)
+{
+ kim_error_t err = NULL;
+ kim_selection_hints_t hints = NULL;
+ kim_string_t string = NULL;
+ kim_comparison_t comparison = 0;
+
+ start_test (state, "kim_selection_hints_set_client_realm_hint");
+
+ if (!err) {
+ err = kim_selection_hints_create (&hints, KSH_TEST_ID);
+ fail_if_error (state, "kim_selection_hints_create", err,
+ "while creating selection hints for %s", KSH_TEST_ID);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_client_realm_hint (hints, KSH_CLIENT_REALM);
+ fail_if_error (state, "kim_selection_hints_set_client_realm_hint",
+ err, "while setting client realm hint to %s",
+ KSH_CLIENT_REALM);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_get_client_realm_hint (hints, &string);
+ fail_if_error (state, "kim_selection_hints_get_client_realm_hint",
+ err, "while getting the client realm %s",
+ KSH_CLIENT_REALM);
+ }
+
+ if (!err) {
+ err = kim_string_compare (KSH_CLIENT_REALM, string, &comparison);
+ fail_if_error (state, "kim_identity_compare", err,
+ "while comparing %s to the client realm hint %s",
+ KSH_CLIENT_REALM, string ? string : "NULL");
+ }
+
+ if (!err && !kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Unexpected client realm hint (got %s, expected %s)",
+ string ? string : "NULL", KSH_CLIENT_REALM);
+ }
+
+ kim_string_free (&string);
+ kim_selection_hints_free (&hints);
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_selection_hints_set_user_hint (kim_test_state_t state)
+{
+ kim_error_t err = NULL;
+ kim_selection_hints_t hints = NULL;
+ kim_string_t string = NULL;
+ kim_comparison_t comparison = 0;
+
+ start_test (state, "kim_selection_hints_set_user_hint");
+
+ if (!err) {
+ err = kim_selection_hints_create (&hints, KSH_TEST_ID);
+ fail_if_error (state, "kim_selection_hints_create", err,
+ "while creating selection hints for %s", KSH_TEST_ID);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_user_hint (hints, KSH_USER);
+ fail_if_error (state, "kim_selection_hints_set_user_hint",
+ err, "while setting user hint to %s",
+ KSH_USER);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_get_user_hint (hints, &string);
+ fail_if_error (state, "kim_selection_hints_get_user_hint",
+ err, "while getting the user hint %s",
+ KSH_USER);
+ }
+
+ if (!err) {
+ err = kim_string_compare (KSH_USER, string, &comparison);
+ fail_if_error (state, "kim_identity_compare", err,
+ "while comparing %s to the user hint %s",
+ KSH_USER, string ? string : "NULL");
+ }
+
+ if (!err && !kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Unexpected user hint (got %s, expected %s)",
+ string ? string : "NULL", KSH_USER);
+ }
+
+ kim_string_free (&string);
+ kim_selection_hints_free (&hints);
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_selection_hints_set_service_realm_hint (kim_test_state_t state)
+{
+ kim_error_t err = NULL;
+ kim_selection_hints_t hints = NULL;
+ kim_string_t string = NULL;
+ kim_comparison_t comparison = 0;
+
+ start_test (state, "kim_selection_hints_set_service_realm_hint");
+
+ if (!err) {
+ err = kim_selection_hints_create (&hints, KSH_TEST_ID);
+ fail_if_error (state, "kim_selection_hints_create", err,
+ "while creating selection hints for %s", KSH_TEST_ID);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_service_realm_hint (hints, KSH_SERVICE_REALM);
+ fail_if_error (state, "kim_selection_hints_set_service_realm_hint",
+ err, "while setting service realm to %s",
+ KSH_SERVICE_REALM);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_get_service_realm_hint (hints, &string);
+ fail_if_error (state, "kim_selection_hints_get_service_realm_hint",
+ err, "while getting the service realm hint %s",
+ KSH_SERVICE_REALM);
+ }
+
+ if (!err) {
+ err = kim_string_compare (KSH_SERVICE_REALM, string, &comparison);
+ fail_if_error (state, "kim_identity_compare", err,
+ "while comparing %s to the service realm hint %s",
+ KSH_SERVICE_REALM, string ? string : "NULL");
+ }
+
+ if (!err && !kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Unexpected service realm hint (got %s, expected %s)",
+ string ? string : "NULL", KSH_SERVICE_REALM);
+ }
+
+ kim_string_free (&string);
+ kim_selection_hints_free (&hints);
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_selection_hints_set_service_hint (kim_test_state_t state)
+{
+ kim_error_t err = NULL;
+ kim_selection_hints_t hints = NULL;
+ kim_string_t string = NULL;
+ kim_comparison_t comparison = 0;
+
+ start_test (state, "kim_selection_hints_set_service_hint");
+
+ if (!err) {
+ err = kim_selection_hints_create (&hints, KSH_TEST_ID);
+ fail_if_error (state, "kim_selection_hints_create", err,
+ "while creating selection hints for %s", KSH_TEST_ID);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_service_hint (hints, KSH_SERVICE);
+ fail_if_error (state, "kim_selection_hints_set_service_hint",
+ err, "while setting service hint to %s",
+ KSH_SERVICE);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_get_service_hint (hints, &string);
+ fail_if_error (state, "kim_selection_hints_get_service_hint",
+ err, "while getting the service hint %s",
+ KSH_SERVICE);
+ }
+
+ if (!err) {
+ err = kim_string_compare (KSH_SERVICE, string, &comparison);
+ fail_if_error (state, "kim_identity_compare", err,
+ "while comparing %s to the service hint %s",
+ KSH_SERVICE, string ? string : "NULL");
+ }
+
+ if (!err && !kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Unexpected service hint (got %s, expected %s)",
+ string ? string : "NULL", KSH_SERVICE);
+ }
+
+ kim_string_free (&string);
+ kim_selection_hints_free (&hints);
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_selection_hints_set_server_hint (kim_test_state_t state)
+{
+ kim_error_t err = NULL;
+ kim_selection_hints_t hints = NULL;
+ kim_string_t string = NULL;
+ kim_comparison_t comparison = 0;
+
+ start_test (state, "kim_selection_hints_set_server_hint");
+
+ if (!err) {
+ err = kim_selection_hints_create (&hints, KSH_TEST_ID);
+ fail_if_error (state, "kim_selection_hints_create", err,
+ "while creating selection hints for %s", KSH_TEST_ID);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_server_hint (hints, KSH_SERVER);
+ fail_if_error (state, "kim_selection_hints_set_server_hint",
+ err, "while setting server hint to %s",
+ KSH_SERVER);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_get_server_hint (hints, &string);
+ fail_if_error (state, "kim_selection_hints_get_server_hint",
+ err, "while getting the server hint %s",
+ KSH_SERVER);
+ }
+
+ if (!err) {
+ err = kim_string_compare (KSH_SERVER, string, &comparison);
+ fail_if_error (state, "kim_identity_compare", err,
+ "while comparing %s to the server hint %s",
+ KSH_SERVER, string ? string : "NULL");
+ }
+
+ if (!err && !kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Unexpected server hint (got %s, expected %s)",
+ string ? string : "NULL", KSH_SERVER);
+ }
+
+ kim_string_free (&string);
+ kim_selection_hints_free (&hints);
+
+ end_test (state);
+}
+
+/* ------------------------------------------------------------------------ */
+
+void test_kim_selection_hints_remember_identity (kim_test_state_t state)
+{
+ kim_error_t err = NULL;
+ kim_selection_hints_t hints = NULL;
+ kim_identity_t service_identity = NULL;
+ kim_identity_t client_identity = NULL;
+ kim_string_t string = NULL;
+ kim_identity_t identity = KIM_IDENTITY_ANY;
+ kim_comparison_t comparison = 0;
+
+ start_test (state, "kim_selection_hints_remember_identity");
+
+ if (!err) {
+ err = kim_selection_hints_create (&hints, KSH_TEST_ID);
+ fail_if_error (state, "kim_selection_hints_create", err,
+ "while creating selection hints for %s", KSH_TEST_ID);
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_string (&service_identity,
+ KSH_SERVICE_IDENTITY);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating an identity for %s",
+ KSH_SERVICE_IDENTITY);
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_string (&client_identity,
+ KSH_IDENTITY);
+ fail_if_error (state, "kim_identity_create_from_string", err,
+ "while creating an identity for %s",
+ KSH_IDENTITY);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_service_identity_hint (hints, service_identity);
+ fail_if_error (state, "kim_selection_hints_set_service_identity_hint",
+ err, "while setting service identity to %s",
+ KSH_SERVICE_IDENTITY);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_client_realm_hint (hints, KSH_CLIENT_REALM);
+ fail_if_error (state, "kim_selection_hints_set_client_realm_hint",
+ err, "while setting client realm to %s",
+ KSH_CLIENT_REALM);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_user_hint (hints, KSH_USER);
+ fail_if_error (state, "kim_selection_hints_set_user_hint",
+ err, "while setting user to %s",
+ KSH_USER);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_service_realm_hint (hints, KSH_SERVICE_REALM);
+ fail_if_error (state, "kim_selection_hints_set_service_realm_hint",
+ err, "while setting service realm to %s",
+ KSH_SERVICE_REALM);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_service_hint (hints, KSH_SERVICE);
+ fail_if_error (state, "kim_selection_hints_set_service_hint",
+ err, "while setting service to %s",
+ KSH_SERVICE);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_server_hint (hints, KSH_SERVER);
+ fail_if_error (state, "kim_selection_hints_set_server_hint",
+ err, "while setting server to %s",
+ KSH_SERVER);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_remember_identity (hints, client_identity);
+ fail_if_error (state, "kim_selection_hints_remember_identity",
+ err, "while remembering identity %s",
+ KSH_IDENTITY);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_get_identity (hints, &identity);
+ fail_if_error (state, "kim_selection_hints_get_identity",
+ err, "while checking if identity is %s",
+ KSH_IDENTITY);
+ }
+
+ if (!err && identity) {
+ err = kim_identity_get_string (identity, &string);
+ fail_if_error (state, "kim_identity_get_string", err,
+ "while getting the string for the client identity hint");
+ }
+
+ if (!err) {
+ err = kim_identity_compare (client_identity, identity, &comparison);
+ fail_if_error (state, "kim_identity_compare", err,
+ "while comparing %s to the identity hint %s",
+ KSH_IDENTITY, string ? string : "NULL");
+ }
+
+ if (!err && !kim_comparison_is_equal_to (comparison)) {
+ log_failure (state, "Unexpected client identity hint (got %s, expected %s)",
+ string ? string : "NULL", KSH_IDENTITY);
+ }
+
+ kim_string_free (&string);
+ kim_identity_free (&identity);
+ kim_identity_free (&client_identity);
+ kim_identity_free (&service_identity);
+ kim_selection_hints_free (&hints);
+
+ end_test (state);
+}
diff --git a/src/kim/test/test_kim_selection_hints.h b/src/kim/test/test_kim_selection_hints.h
new file mode 100644
index 0000000..fac9a3d
--- /dev/null
+++ b/src/kim/test/test_kim_selection_hints.h
@@ -0,0 +1,46 @@
+/*
+ * $Header$
+ *
+ * Copyright 2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef TEST_KIM_SELECTION_HINTS_H
+#define TEST_KIM_SELECTION_HINTS_H
+
+#include "test_kim_common.h"
+
+void test_kim_selection_hints_set_service_identity_hint (kim_test_state_t state);
+
+void test_kim_selection_hints_set_client_realm_hint (kim_test_state_t state);
+
+void test_kim_selection_hints_set_user_hint (kim_test_state_t state);
+
+void test_kim_selection_hints_set_service_realm_hint (kim_test_state_t state);
+
+void test_kim_selection_hints_set_service_hint (kim_test_state_t state);
+
+void test_kim_selection_hints_set_server_hint (kim_test_state_t state);
+
+void test_kim_selection_hints_remember_identity (kim_test_state_t state);
+
+#endif /* TEST_KIM_SELECTION_HINTS_H */