text:
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* lib/krb5/keytab/kt_file.c */
/*
 * Copyright 1990,1991,1995,2007,2008 by the 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.
 */
/*
 * Copyright (c) Hewlett-Packard Company 1991
 * Released to the Massachusetts Institute of Technology for inclusion
 * in the Kerberos source code distribution.
 *
 * Copyright 1990,1991 by the 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 LEAN_CLIENT

#include "k5-int.h"
#include "../os/os-proto.h"
#include <stdio.h>

/*
 * Information needed by internal routines of the file-based ticket
 * cache implementation.
 */

/*
 * Constants
 */

#define KRB5_KT_VNO_1   0x0501  /* krb v5, keytab version 1 (DCE compat) */
#define KRB5_KT_VNO     0x0502  /* krb v5, keytab version 2 (standard)  */

#define KRB5_KT_DEFAULT_VNO KRB5_KT_VNO

/*
 * Types
 */
typedef struct _krb5_ktfile_data {
    char *name;                 /* Name of the file */
    FILE *openf;                /* open file, if any. */
    char iobuf[BUFSIZ];         /* so we can zap it later */
    int version;                /* Version number of keytab */
    unsigned int iter_count;    /* Number of active iterators */
    long start_offset;          /* Starting offset after version */
    k5_mutex_t lock;            /* Protect openf, version */
} krb5_ktfile_data;

/*
 * Some limitations:
 *
 * If the file OPENF is left open between calls, we have an iterator
 * active, and OPENF is opened in read-only mode.  So, no changes
 * can be made via that handle.
 *
 * An advisory file lock is used while the file is open.  Thus,
 * multiple handles on the same underlying file cannot be used without
 * disrupting the locking in effect.
 *
 * The start_offset field is only valid if the file is open.  It will
 * almost certainly always be the same constant.  It's used so that
 * if an iterator is active, and we start another one, we don't have
 * to seek back to the start and re-read the version number to set
 * the position for the iterator.
 */

/*
 * Macros
 */
#define KTPRIVATE(id) ((krb5_ktfile_data *)(id)->data)
#define KTFILENAME(id) (((krb5_ktfile_data *)(id)->data)->name)
#define KTFILEP(id) (((krb5_ktfile_data *)(id)->data)->openf)
#define KTFILEBUFP(id) (((krb5_ktfile_data *)(id)->data)->iobuf)
#define KTVERSION(id) (((krb5_ktfile_data *)(id)->data)->version)
#define KTITERS(id) (((krb5_ktfile_data *)(id)->data)->iter_count)
#define KTSTARTOFF(id) (((krb5_ktfile_data *)(id)->data)->start_offset)
#define KTLOCK(id) k5_mutex_lock(&((krb5_ktfile_data *)(id)->data)->lock)
#define KTUNLOCK(id) k5_mutex_unlock(&((krb5_ktfile_data *)(id)->data)->lock)
#define KTCHECKLOCK(id) k5_mutex_assert_locked(&((krb5_ktfile_data *)(id)->data)->lock)

extern const struct _krb5_kt_ops krb5_ktf_ops;
extern const struct _krb5_kt_ops krb5_ktf_writable_ops;

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_resolve(krb5_context, const char *, krb5_keytab *);

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_get_name(krb5_context, krb5_keytab, char *, unsigned int);

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_close(krb5_context, krb5_keytab);

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_get_entry(krb5_context, krb5_keytab, krb5_const_principal,
                      krb5_kvno, krb5_enctype, krb5_keytab_entry *);

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_start_seq_get(krb5_context, krb5_keytab, krb5_kt_cursor *);

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_get_next(krb5_context, krb5_keytab, krb5_keytab_entry *,
                     krb5_kt_cursor *);

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_end_get(krb5_context, krb5_keytab, krb5_kt_cursor *);

/* routines to be included on extended version (write routines) */
static krb5_error_code KRB5_CALLCONV
krb5_ktfile_add(krb5_context, krb5_keytab, krb5_keytab_entry *);

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_remove(krb5_context, krb5_keytab, krb5_keytab_entry *);

static krb5_error_code
krb5_ktfileint_openr(krb5_context, krb5_keytab);

static krb5_error_code
krb5_ktfileint_openw(krb5_context, krb5_keytab);

static krb5_error_code
krb5_ktfileint_close(krb5_context, krb5_keytab);

static krb5_error_code
krb5_ktfileint_read_entry(krb5_context, krb5_keytab, krb5_keytab_entry *);

static krb5_error_code
krb5_ktfileint_write_entry(krb5_context, krb5_keytab, krb5_keytab_entry *);

static krb5_error_code
krb5_ktfileint_delete_entry(krb5_context, krb5_keytab, krb5_int32);

static krb5_error_code
krb5_ktfileint_internal_read_entry(krb5_context, krb5_keytab,
                                   krb5_keytab_entry *, krb5_int32 *);

static krb5_error_code
krb5_ktfileint_size_entry(krb5_context, krb5_keytab_entry *, krb5_int32 *);

static krb5_error_code
krb5_ktfileint_find_slot(krb5_context, krb5_keytab, krb5_int32 *,
                         krb5_int32 *);

/*
 * This is an implementation specific resolver.  It returns a keytab id
 * initialized with file keytab routines.
 */

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_resolve(krb5_context context, const char *name,
                    krb5_keytab *id_out)
{
    krb5_ktfile_data *data = NULL;
    krb5_error_code err = ENOMEM;
    krb5_keytab id;

    *id_out = NULL;

    id = calloc(1, sizeof(*id));
    if (id == NULL)
        return ENOMEM;

    id->ops = &krb5_ktf_ops;
    data = calloc(1, sizeof(krb5_ktfile_data));
    if (data == NULL)
        goto cleanup;

    data->name = strdup(name);
    if (data->name == NULL)
        goto cleanup;

    err = k5_mutex_init(&data->lock);
    if (err)
        goto cleanup;

    data->openf = 0;
    data->version = 0;
    data->iter_count = 0;

    id->data = (krb5_pointer) data;
    id->magic = KV5M_KEYTAB;
    *id_out = id;
    return 0;
cleanup:
    if (data)
        free(data->name);
    free(data);
    free(id);
    return err;
}

/*
 * "Close" a file-based keytab and invalidate the id.  This means
 * free memory hidden in the structures.
 */

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_close(krb5_context context, krb5_keytab id)
/*
 * This routine is responsible for freeing all memory allocated
 * for this keytab.  There are no system resources that need
 * to be freed nor are there any open files.
 *
 * This routine should undo anything done by krb5_ktfile_resolve().
 */
{
    free(KTFILENAME(id));
    zap(KTFILEBUFP(id), BUFSIZ);
    k5_mutex_destroy(&((krb5_ktfile_data *)id->data)->lock);
    free(id->data);
    id->ops = 0;
    free(id);
    return (0);
}

/* Return true if k1 is more recent than k2, applying wraparound heuristics. */
static krb5_boolean
more_recent(const krb5_keytab_entry *k1, const krb5_keytab_entry *k2)
{
    /*
     * If a small kvno was written at the same time or later than a large kvno,
     * the kvno probably wrapped at some boundary, so consider the small kvno
     * more recent.  Wraparound can happen due to pre-1.14 keytab file format
     * limitations (8-bit kvno storage), pre-1.14 kadmin protocol limitations
     * (8-bit kvno marshalling), or KDB limitations (16-bit kvno storage).
     */
    if (!ts_after(k2->timestamp, k1->timestamp) &&
        k1->vno < 128 && k2->vno > 240)
        return TRUE;
    if (!ts_after(k1->timestamp, k2->timestamp) &&
        k1->vno > 240 && k2->vno < 128)
        return FALSE;

    /* Otherwise do a simple version comparison. */
    return k1->vno > k2->vno;
}

/*
 * This is the get_entry routine for the file based keytab implementation.
 * It opens the keytab file, and either retrieves the entry or returns
 * an error.
 */

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_get_entry(krb5_context context, krb5_keytab id,
                      krb5_const_principal principal, krb5_kvno kvno,
                      krb5_enctype enctype, krb5_keytab_entry *entry)
{
    krb5_keytab_entry cur_entry, new_entry;
    krb5_error_code kerror = 0;
    int found_wrong_kvno = 0;
    krb5_boolean similar;
    int was_open;
    char *princname;

    KTLOCK(id);

    if (KTFILEP(id) != NULL) {
        was_open = 1;

        if (fseek(KTFILEP(id), KTSTARTOFF(id), SEEK_SET) == -1) {
            KTUNLOCK(id);
            return errno;
        }
    } else {
        was_open = 0;

        /* Open the keyfile for reading */
        if ((kerror = krb5_ktfileint_openr(context, id))) {
            KTUNLOCK(id);
            return(kerror);
        }
    }

    /*
     * For efficiency and simplicity, we'll use a while true that
     * is exited with a break statement.
     */
    cur_entry.principal = 0;
    cur_entry.vno = 0;
    cur_entry.key.contents = 0;

    while (TRUE) {
        if ((kerror = krb5_ktfileint_read_entry(context, id, &new_entry)))
            break;

        /* by the time this loop exits, it must either free cur_entry,
           and copy new_entry there, or free new_entry.  Otherwise, it
           leaks. */

        /* if the principal isn't the one requested, free new_entry
           and continue to the next. */

        if (!krb5_principal_compare(context, principal, new_entry.principal)) {
            krb5_kt_free_entry(context, &new_entry);
            continue;
        }

        /* if the enctype is not ignored and doesn't match, free new_entry
           and continue to the next */

        if (enctype != IGNORE_ENCTYPE) {
            if ((kerror = krb5_c_enctype_compare(context, enctype,
                                                 new_entry.key.enctype,
                                                 &similar))) {
                krb5_kt_free_entry(context, &new_entry);
                break;
            }

            if (!similar) {
                krb5_kt_free_entry(context, &new_entry);
                continue;
            }
            /*
             * Coerce the enctype of the output keyblock in case we
             * got an inexact match on the enctype.
             */
            new_entry.key.enctype = enctype;

        }

        if (kvno == IGNORE_VNO || new_entry.vno == IGNORE_VNO) {
            /* If this entry is more recent (or the first match), free the
             * current and keep the new.  Otherwise, free the new. */
            if (cur_entry.principal == NULL ||
                more_recent(&new_entry, &cur_entry)) {
                krb5_kt_free_entry(context, &cur_entry);
                cur_entry = new_entry;
            } else {
                krb5_kt_free_entry(context, &new_entry);
            }
        } else {
            /*
             * If this kvno matches exactly, free the current, keep the new,
             * and break out.  If it matches the low 8 bits of the desired
             * kvno, remember the first match (because the recorded kvno may
             * have been truncated due to pre-1.14 keytab format or kadmin
             * protocol limitations) but keep looking for an exact match.
             * Otherwise, remember that we were here so we can return the right
             * error, and free the new.
             */
            if (new_entry.vno == kvno) {
                krb5_kt_free_entry(context, &cur_entry);
                cur_entry = new_entry;
                if (new_entry.vno == kvno)
                    break;
            } else if (new_entry.vno == (kvno & 0xff) &&
                       cur_entry.principal == NULL) {
                cur_entry = new_entry;
            } else {
                found_wrong_kvno++;
                krb5_kt_free_entry(context, &new_entry);
            }
        }
    }

    if (kerror == KRB5_KT_END) {
        if (cur_entry.principal)
            kerror = 0;
        else if (found_wrong_kvno)
            kerror = KRB5_KT_KVNONOTFOUND;
        else {
            kerror = KRB5_KT_NOTFOUND;
            if (krb5_unparse_name(context, principal, &princname) == 0) {
                k5_setmsg(context, kerror,
                          _("No key table entry found for %s"), princname);
                free(princname);
            }
        }
    }
    if (kerror) {
        if (was_open == 0)
            (void) krb5_ktfileint_close(context, id);
        KTUNLOCK(id);
        krb5_kt_free_entry(context, &cur_entry);
        return kerror;
    }
    if (was_open == 0 && (kerror = krb5_ktfileint_close(context, id)) != 0) {
        KTUNLOCK(id);
        krb5_kt_free_entry(context, &cur_entry);
        return kerror;
    }
    KTUNLOCK(id);
    *entry = cur_entry;
    return 0;
}

/*
 * Get the name of the file containing a file-based keytab.
 */

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len)
/*
 * This routine returns the name of the name of the file associated with
 * this file-based keytab.  name is zeroed and the filename is truncated
 * to fit in name if necessary.  The name is prefixed with PREFIX:, so that
 * trt will happen if the name is passed back to resolve.
 */
{
    int result;

    memset(name, 0, len);
    result = snprintf(name, len, "%s:%s", id->ops->prefix, KTFILENAME(id));
    if (SNPRINTF_OVERFLOW(result, len))
        return(KRB5_KT_NAME_TOOLONG);
    return(0);
}

/*
 * krb5_ktfile_start_seq_get()
 */

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursorp)
{
    krb5_error_code retval;
    long *fileoff;

    KTLOCK(id);

    if (KTITERS(id) == 0) {
        if ((retval = krb5_ktfileint_openr(context, id))) {
            KTUNLOCK(id);
            return retval;
        }
    }

    if (!(fileoff = (long *)malloc(sizeof(*fileoff)))) {
        if (KTITERS(id) == 0)
            krb5_ktfileint_close(context, id);
        KTUNLOCK(id);
        return ENOMEM;
    }
    *fileoff = KTSTARTOFF(id);
    *cursorp = (krb5_kt_cursor)fileoff;
    KTITERS(id)++;
    if (KTITERS(id) == 0) {
        /* Wrapped?!  */
        KTITERS(id)--;
        KTUNLOCK(id);
        k5_setmsg(context, KRB5_KT_IOERR, "Too many keytab iterators active");
        return KRB5_KT_IOERR;   /* XXX */
    }
    KTUNLOCK(id);

    return 0;
}

/*
 * krb5_ktfile_get_next()
 */

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor)
{
    long *fileoff = (long *)*cursor;
    krb5_keytab_entry cur_entry;
    krb5_error_code kerror;

    KTLOCK(id);
    if (KTFILEP(id) == NULL) {
        KTUNLOCK(id);
        return KRB5_KT_IOERR;
    }
    if (fseek(KTFILEP(id), *fileoff, 0) == -1) {
        KTUNLOCK(id);
        return KRB5_KT_END;
    }
    if ((kerror = krb5_ktfileint_read_entry(context, id, &cur_entry))) {
        KTUNLOCK(id);
        return kerror;
    }
    *fileoff = ftell(KTFILEP(id));
    *entry = cur_entry;
    KTUNLOCK(id);
    return 0;
}

/*
 * krb5_ktfile_end_get()
 */

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor)
{
    krb5_error_code kerror;

    free(*cursor);
    KTLOCK(id);
    KTITERS(id)--;
    if (KTFILEP(id) != NULL && KTITERS(id) == 0)
        kerror = krb5_ktfileint_close(context, id);
    else
        kerror = 0;
    KTUNLOCK(id);
    return kerror;
}

/*
 * ser_ktf.c - Serialize keytab file context for subsequent reopen.
 */

static const char ktfile_def_name[] = ".";

/*
 * Routines to deal with externalizing krb5_keytab for [WR]FILE: variants.
 *      krb5_ktf_keytab_size();
 *      krb5_ktf_keytab_externalize();
 *      krb5_ktf_keytab_internalize();
 */
static krb5_error_code
krb5_ktf_keytab_size(krb5_context, krb5_pointer, size_t *);

static krb5_error_code
krb5_ktf_keytab_externalize(krb5_context, krb5_pointer, krb5_octet **,
                            size_t *);

static krb5_error_code
krb5_ktf_keytab_internalize(krb5_context,krb5_pointer *, krb5_octet **,
                            size_t *);

/*
 * Serialization entry for this type.
 */
const krb5_ser_entry krb5_ktfile_ser_entry = {
    KV5M_KEYTAB,                        /* Type                 */
    krb5_ktf_keytab_size,               /* Sizer routine        */
    krb5_ktf_keytab_externalize,        /* Externalize routine  */
    krb5_ktf_keytab_internalize         /* Internalize routine  */
};

/*
 * krb5_ktf_keytab_size()       - Determine the size required to externalize
 *                                this krb5_keytab variant.
 */
static krb5_error_code
krb5_ktf_keytab_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
{
    krb5_error_code     kret;
    krb5_keytab         keytab;
    size_t              required;
    krb5_ktfile_data    *ktdata;

    kret = EINVAL;
    if ((keytab = (krb5_keytab) arg)) {
        /*
         * Saving FILE: variants of krb5_keytab requires at minimum:
         *      krb5_int32      for KV5M_KEYTAB
         *      krb5_int32      for length of keytab name.
         *      krb5_int32      for file status.
         *      krb5_int32      for file position.
         *      krb5_int32      for file position.
         *      krb5_int32      for version.
         *      krb5_int32      for KV5M_KEYTAB
         */
        required = sizeof(krb5_int32) * 7;
        if (keytab->ops && keytab->ops->prefix)
            required += (strlen(keytab->ops->prefix)+1);

        /*
         * The keytab name is formed as follows:
         *      <prefix>:<name>
         * If there's no name, we use a default name so that we have something
         * to call krb5_keytab_resolve with.
         */
        ktdata = (krb5_ktfile_data *) keytab->data;
        required += strlen((ktdata && ktdata->name) ?
                           ktdata->name : ktfile_def_name);
        kret = 0;

        if (!kret)
            *sizep += required;
    }
    return(kret);
}

/*
 * krb5_ktf_keytab_externalize()        - Externalize the krb5_keytab.
 */
static krb5_error_code
krb5_ktf_keytab_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
{
    krb5_error_code     kret;
    krb5_keytab         keytab;
    size_t              required;
    krb5_octet          *bp;
    size_t              remain;
    krb5_ktfile_data    *ktdata;
    krb5_int32          file_is_open;
    int64_t             file_pos;
    char                *ktname;
    const char          *fnamep;

    required = 0;
    bp = *buffer;
    remain = *lenremain;
    kret = EINVAL;
    if ((keytab = (krb5_keytab) arg)) {
        kret = ENOMEM;
        if (!krb5_ktf_keytab_size(kcontext, arg, &required) &&
            (required <= remain)) {
            /* Our identifier */
            (void) krb5_ser_pack_int32(KV5M_KEYTAB, &bp, &remain);

            ktdata = (krb5_ktfile_data *) keytab->data;
            file_is_open = 0;
            file_pos = 0;

            /* Calculate the length of the name */
            if (ktdata && ktdata->name)
                fnamep = ktdata->name;
            else
                fnamep = ktfile_def_name;

            if (keytab->ops && keytab->ops->prefix) {
                if (asprintf(&ktname, "%s:%s", keytab->ops->prefix, fnamep) < 0)
                    ktname = NULL;
            } else
                ktname = strdup(fnamep);

            if (ktname) {
                /* Fill in the file-specific keytab information. */
                if (ktdata) {
                    if (ktdata->openf) {
                        long    fpos;
                        int     fflags = 0;

                        file_is_open = 1;
#if !defined(_WIN32)
                        fflags = fcntl(fileno(ktdata->openf), F_GETFL, 0);
                        if (fflags > 0)
                            file_is_open |= ((fflags & O_ACCMODE) << 1);
#else
                        file_is_open = 0;
#endif
                        fpos = ftell(ktdata->openf);
                        file_pos = fpos; /* XX range check? */
                    }
                }

                /* Put the length of the file name */
                (void) krb5_ser_pack_int32((krb5_int32) strlen(ktname),
                                           &bp, &remain);

                /* Put the name */
                (void) krb5_ser_pack_bytes((krb5_octet *) ktname,
                                           strlen(ktname),
                                           &bp, &remain);

                /* Put the file open flag */
                (void) krb5_ser_pack_int32(file_is_open, &bp, &remain);

                /* Put the file position */
                (void) krb5_ser_pack_int64(file_pos, &bp, &remain);

                /* Put the version */
                (void) krb5_ser_pack_int32((krb5_int32) ((ktdata) ?
                                                         ktdata->version : 0),
                                           &bp, &remain);

                /* Put the trailer */
                (void) krb5_ser_pack_int32(KV5M_KEYTAB, &bp, &remain);
                kret = 0;
                *buffer = bp;
                *lenremain = remain;
                free(ktname);
            }
        }
    }
    return(kret);
}

/*
 * krb5_ktf_keytab_internalize()        - Internalize the krb5_ktf_keytab.
 */
static krb5_error_code
krb5_ktf_keytab_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
{
    krb5_error_code     kret;
    krb5_keytab         keytab = NULL;
    krb5_int32          ibuf;
    krb5_octet          *bp;
    size_t              remain;
    char                *ktname = NULL;
    krb5_ktfile_data    *ktdata;
    krb5_int32          file_is_open;
    int64_t             foff;

    *argp = NULL;
    bp = *buffer;
    remain = *lenremain;

    /* Read our magic number */
    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain) || ibuf != KV5M_KEYTAB)
        return EINVAL;

    /* Read the keytab name */
    kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    if (kret)
        return kret;
    ktname = malloc(ibuf + 1);
    if (!ktname)
        return ENOMEM;
    kret = krb5_ser_unpack_bytes((krb5_octet *) ktname, (size_t) ibuf,
                                 &bp, &remain);
    if (kret)
        goto cleanup;
    ktname[ibuf] = '\0';

    /* Resolve the keytab. */
    kret = krb5_kt_resolve(kcontext, ktname, &keytab);
    if (kret)
        goto cleanup;

    if (keytab->ops != &krb5_ktf_ops) {
        kret = EINVAL;
        goto cleanup;
    }
    ktdata = (krb5_ktfile_data *) keytab->data;

    if (remain < (sizeof(krb5_int32)*5)) {
        kret = EINVAL;
        goto cleanup;
    }
    (void) krb5_ser_unpack_int32(&file_is_open, &bp, &remain);
    (void) krb5_ser_unpack_int64(&foff, &bp, &remain);
    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    ktdata->version = (int) ibuf;
    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    if (ibuf != KV5M_KEYTAB) {
        kret = EINVAL;
        goto cleanup;
    }

    if (file_is_open) {
        int     fmode;
        long    fpos;

#if !defined(_WIN32)
        fmode = (file_is_open >> 1) & O_ACCMODE;
#else
        fmode = 0;
#endif
        if (fmode)
            kret = krb5_ktfileint_openw(kcontext, keytab);
        else
            kret = krb5_ktfileint_openr(kcontext, keytab);
        if (kret)
            goto cleanup;
        fpos = foff; /* XX range check? */
        if (fseek(KTFILEP(keytab), fpos, SEEK_SET) == -1) {
            kret = errno;
            goto cleanup;
        }
    }

    *buffer = bp;
    *lenremain = remain;
    *argp = (krb5_pointer) keytab;
cleanup:
    if (kret != 0 && keytab)
        krb5_kt_close(kcontext, keytab);
    free(ktname);
    return kret;
}

/*
 * krb5_ktfile_add()
 */

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_add(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
{
    krb5_error_code retval;

    KTLOCK(id);
    if (KTFILEP(id)) {
        /* Iterator(s) active -- no changes.  */
        KTUNLOCK(id);
        k5_setmsg(context, KRB5_KT_IOERR,
                  _("Cannot change keytab with keytab iterators active"));
        return KRB5_KT_IOERR;   /* XXX */
    }
    if ((retval = krb5_ktfileint_openw(context, id))) {
        KTUNLOCK(id);
        return retval;
    }
    if (fseek(KTFILEP(id), 0, 2) == -1) {
        KTUNLOCK(id);
        return KRB5_KT_END;
    }
    retval = krb5_ktfileint_write_entry(context, id, entry);
    krb5_ktfileint_close(context, id);
    KTUNLOCK(id);
    return retval;
}

/*
 * krb5_ktfile_remove()
 */

static krb5_error_code KRB5_CALLCONV
krb5_ktfile_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
{
    krb5_keytab_entry   cur_entry;
    krb5_error_code     kerror;
    krb5_int32          delete_point;

    KTLOCK(id);
    if (KTFILEP(id)) {
        /* Iterator(s) active -- no changes.  */
        KTUNLOCK(id);
        k5_setmsg(context, KRB5_KT_IOERR,
                  _("Cannot change keytab with keytab iterators active"));
        return KRB5_KT_IOERR;   /* XXX */
    }

    if ((kerror = krb5_ktfileint_openw(context, id))) {
        KTUNLOCK(id);
        return kerror;
    }

    /*
     * For efficiency and simplicity, we'll use a while true that
     * is exited with a break statement.
     */
    while (TRUE) {
        if ((kerror = krb5_ktfileint_internal_read_entry(context, id,
                                                         &cur_entry,
                                                         &delete_point)))
            break;

        if ((entry->vno == cur_entry.vno) &&
            (entry->key.enctype == cur_entry.key.enctype) &&
            krb5_principal_compare(context, entry->principal, cur_entry.principal)) {
            /* found a match */
            krb5_kt_free_entry(context, &cur_entry);
            break;
        }
        krb5_kt_free_entry(context, &cur_entry);
    }

    if (kerror == KRB5_KT_END)
        kerror = KRB5_KT_NOTFOUND;

    if (kerror) {
        (void) krb5_ktfileint_close(context, id);
        KTUNLOCK(id);
        return kerror;
    }

    kerror = krb5_ktfileint_delete_entry(context, id, delete_point);

    if (kerror) {
        (void) krb5_ktfileint_close(context, id);
    } else {
        kerror = krb5_ktfileint_close(context, id);
    }
    KTUNLOCK(id);
    return kerror;
}

/*
 * krb5_ktf_ops
 */

const struct _krb5_kt_ops krb5_ktf_ops = {
    0,
    "FILE",     /* Prefix -- this string should not appear anywhere else! */
    krb5_ktfile_resolve,
    krb5_ktfile_get_name,
    krb5_ktfile_close,
    krb5_ktfile_get_entry,
    krb5_ktfile_start_seq_get,
    krb5_ktfile_get_next,
    krb5_ktfile_end_get,
    krb5_ktfile_add,
    krb5_ktfile_remove,
    &krb5_ktfile_ser_entry
};

/*
 * krb5_ktf_writable_ops -- this is the same as krb5_ktf_ops except for the
 * prefix.  WRFILE should no longer be needed, but is effectively aliased to
 * FILE for compatibility.
 */

const struct _krb5_kt_ops krb5_ktf_writable_ops = {
    0,
    "WRFILE",   /* Prefix -- this string should not appear anywhere else! */
    krb5_ktfile_resolve,
    krb5_ktfile_get_name,
    krb5_ktfile_close,
    krb5_ktfile_get_entry,
    krb5_ktfile_start_seq_get,
    krb5_ktfile_get_next,
    krb5_ktfile_end_get,
    krb5_ktfile_add,
    krb5_ktfile_remove,
    &krb5_ktfile_ser_entry
};

/*
 * krb5_kt_dfl_ops
 */

const krb5_kt_ops krb5_kt_dfl_ops = {
    0,
    "FILE",     /* Prefix -- this string should not appear anywhere else! */
    krb5_ktfile_resolve,
    krb5_ktfile_get_name,
    krb5_ktfile_close,
    krb5_ktfile_get_entry,
    krb5_ktfile_start_seq_get,
    krb5_ktfile_get_next,
    krb5_ktfile_end_get,
    0,
    0,
    &krb5_ktfile_ser_entry
};

/* Formerly lib/krb5/keytab/file/ktf_util.c */

/*
 * This function contains utilities for the file based implementation of
 * the keytab.  There are no public functions in this file.
 *
 * This file is the only one that has knowledge of the format of a
 * keytab file.
 *
 * The format is as follows:
 *
 * <file format vno>
 * <record length>
 * principal timestamp vno key
 * <record length>
 * principal timestamp vno key
 * ....
 *
 * A length field (sizeof(krb5_int32)) exists between entries.  When this
 * length is positive it indicates an active entry, when negative a hole.
 * The length indicates the size of the block in the file (this may be
 * larger than the size of the next record, since we are using a first
 * fit algorithm for re-using holes and the first fit may be larger than
 * the entry we are writing).  Another (compatible) implementation could
 * break up holes when allocating them to smaller entries to minimize
 * wasted space.  (Such an implementation should also coalesce adjacent
 * holes to reduce fragmentation).  This implementation does neither.
 *
 * There are no separators between fields of an entry.
 * A principal is a length-encoded array of length-encoded strings.  The
 * length is a krb5_int16 in each case.  The specific format, then, is
 * multiple entries concatinated with no separators.  An entry has this
 * exact format:
 *
 * sizeof(krb5_int16) bytes for number of components in the principal;
 * then, each component listed in ordser.
 * For each component, sizeof(krb5_int16) bytes for the number of bytes
 * in the component, followed by the component.
 * sizeof(krb5_int32) for the principal type (for KEYTAB V2 and higher)
 * sizeof(krb5_int32) bytes for the timestamp
 * sizeof(krb5_octet) bytes for the key version number
 * sizeof(krb5_int16) bytes for the enctype
 * sizeof(krb5_int16) bytes for the key length, followed by the key
 */

#ifndef SEEK_SET
#define SEEK_SET 0
#define SEEK_CUR 1
#endif

typedef krb5_int16  krb5_kt_vno;

#define krb5_kt_default_vno ((krb5_kt_vno)KRB5_KT_DEFAULT_VNO)

static krb5_error_code
krb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode)
{
    krb5_error_code kerror;
    krb5_kt_vno kt_vno;
    int writevno = 0;

    KTCHECKLOCK(id);
    errno = 0;
    KTFILEP(id) = fopen(KTFILENAME(id),
                        (mode == KRB5_LOCKMODE_EXCLUSIVE) ? "rb+" : "rb");
    if (!KTFILEP(id)) {
        if ((mode == KRB5_LOCKMODE_EXCLUSIVE) && (errno == ENOENT)) {
            /* try making it first time around */
            k5_create_secure_file(context, KTFILENAME(id));
            errno = 0;
            KTFILEP(id) = fopen(KTFILENAME(id), "rb+");
            if (!KTFILEP(id))
                goto report_errno;
            writevno = 1;
        } else {
        report_errno:
            switch (errno) {
            case 0:
                /* XXX */
                return EMFILE;
            case ENOENT:
                k5_setmsg(context, ENOENT,
                          _("Key table file '%s' not found"), KTFILENAME(id));
                return ENOENT;
            default:
                return errno;
            }
        }
    }
    set_cloexec_file(KTFILEP(id));
    if ((kerror = krb5_lock_file(context, fileno(KTFILEP(id)), mode))) {
        (void) fclose(KTFILEP(id));
        KTFILEP(id) = 0;
        return kerror;
    }
    /* assume ANSI or BSD-style stdio */
    setbuf(KTFILEP(id), KTFILEBUFP(id));

    /* get the vno and verify it */
    if (writevno) {
        kt_vno = htons(krb5_kt_default_vno);
        KTVERSION(id) = krb5_kt_default_vno;
        if (!fwrite(&kt_vno, sizeof(kt_vno), 1, KTFILEP(id))) {
            kerror = errno;
            (void) krb5_unlock_file(context, fileno(KTFILEP(id)));
            (void) fclose(KTFILEP(id));
            KTFILEP(id) = 0;
            return kerror;
        }
    } else {
        /* gotta verify it instead... */
        if (!fread(&kt_vno, sizeof(kt_vno), 1, KTFILEP(id))) {
            if (feof(KTFILEP(id)))
                kerror = KRB5_KEYTAB_BADVNO;
            else
                kerror = errno;
            (void) krb5_unlock_file(context, fileno(KTFILEP(id)));
            (void) fclose(KTFILEP(id));
            KTFILEP(id) = 0;
            return kerror;
        }
        kt_vno = KTVERSION(id) = ntohs(kt_vno);
        if ((kt_vno != KRB5_KT_VNO) &&
            (kt_vno != KRB5_KT_VNO_1)) {
            (void) krb5_unlock_file(context, fileno(KTFILEP(id)));
            (void) fclose(KTFILEP(id));
            KTFILEP(id) = 0;
            return KRB5_KEYTAB_BADVNO;
        }
    }
    KTSTARTOFF(id) = ftell(KTFILEP(id));
    return 0;
}

static krb5_error_code
krb5_ktfileint_openr(krb5_context context, krb5_keytab id)
{
    return krb5_ktfileint_open(context, id, KRB5_LOCKMODE_SHARED);
}

static krb5_error_code
krb5_ktfileint_openw(krb5_context context, krb5_keytab id)
{
    return krb5_ktfileint_open(context, id, KRB5_LOCKMODE_EXCLUSIVE);
}

static krb5_error_code
krb5_ktfileint_close(krb5_context context, krb5_keytab id)
{
    krb5_error_code kerror;

    KTCHECKLOCK(id);
    if (!KTFILEP(id))
        return 0;
    kerror = krb5_unlock_file(context, fileno(KTFILEP(id)));
    (void) fclose(KTFILEP(id));
    KTFILEP(id) = 0;
    return kerror;
}

static krb5_error_code
krb5_ktfileint_delete_entry(krb5_context context, krb5_keytab id, krb5_int32 delete_point)
{
    krb5_int32  size;
    krb5_int32  len;
    char        iobuf[BUFSIZ];

    KTCHECKLOCK(id);
    if (fseek(KTFILEP(id), delete_point, SEEK_SET)) {
        return errno;
    }
    if (!fread(&size, sizeof(size), 1, KTFILEP(id))) {
        return KRB5_KT_END;
    }
    if (KTVERSION(id) != KRB5_KT_VNO_1)
        size = ntohl(size);

    if (size > 0) {
        krb5_int32 minus_size = -size;
        if (KTVERSION(id) != KRB5_KT_VNO_1)
            minus_size = htonl(minus_size);

        if (fseek(KTFILEP(id), delete_point, SEEK_SET)) {
            return errno;
        }

        if (!fwrite(&minus_size, sizeof(minus_size), 1, KTFILEP(id))) {
            return KRB5_KT_IOERR;
        }

        if (size < BUFSIZ) {
            len = size;
        } else {
            len = BUFSIZ;
        }

        memset(iobuf, 0, (size_t) len);
        while (size > 0) {
            if (!fwrite(iobuf, 1, (size_t) len, KTFILEP(id))) {
                return KRB5_KT_IOERR;
            }
            size -= len;
            if (size < len) {
                len = size;
            }
        }

        return k5_sync_disk_file(context, KTFILEP(id));
    }

    return 0;
}

static krb5_error_code
krb5_ktfileint_internal_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *ret_entry, krb5_int32 *delete_point)
{
    krb5_octet vno;
    krb5_int16 count;
    unsigned int u_count, u_princ_size;
    krb5_int16 enctype;
    krb5_int16 princ_size;
    register int i;
    krb5_int32 size;
    krb5_int32 start_pos, pos;
    krb5_error_code error;
    char        *tmpdata;
    krb5_data   *princ;
    uint32_t    vno32;

    KTCHECKLOCK(id);
    memset(ret_entry, 0, sizeof(krb5_keytab_entry));
    ret_entry->magic = KV5M_KEYTAB_ENTRY;

    /* fseek to synchronise buffered I/O on the key table. */

    if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
    {
        return errno;
    }

    do {
        *delete_point = ftell(KTFILEP(id));
        if (!fread(&size, sizeof(size), 1, KTFILEP(id))) {
            return KRB5_KT_END;
        }
        if (KTVERSION(id) != KRB5_KT_VNO_1)
            size = ntohl(size);

        if (size < 0) {
            if (fseek(KTFILEP(id), -size, SEEK_CUR)) {
                return errno;
            }
        }
    } while (size < 0);

    if (size == 0) {
        return KRB5_KT_END;
    }

    start_pos = ftell(KTFILEP(id));

    /* deal with guts of parsing... */

    /* first, int16 with #princ components */
    if (!fread(&count, sizeof(count), 1, KTFILEP(id)))
        return KRB5_KT_END;
    if (KTVERSION(id) == KRB5_KT_VNO_1) {
        count -= 1;         /* V1 includes the realm in the count */
    } else {
        count = ntohs(count);
    }
    if (!count || (count < 0))
        return KRB5_KT_END;
    ret_entry->principal = (krb5_principal)malloc(sizeof(krb5_principal_data));
    if (!ret_entry->principal)
        return ENOMEM;

    u_count = count;
    ret_entry->principal->magic = KV5M_PRINCIPAL;
    ret_entry->principal->length = u_count;
    ret_entry->principal->data = (krb5_data *)
        calloc(u_count, sizeof(krb5_data));
    if (!ret_entry->principal->data) {
        free(ret_entry->principal);
        ret_entry->principal = 0;
        return ENOMEM;
    }

    /* Now, get the realm data */
    if (!fread(&princ_size, sizeof(princ_size), 1, KTFILEP(id))) {
        error = KRB5_KT_END;
        goto fail;
    }
    if (KTVERSION(id) != KRB5_KT_VNO_1)
        princ_size = ntohs(princ_size);
    if (!princ_size || (princ_size < 0)) {
        error = KRB5_KT_END;
        goto fail;
    }
    u_princ_size = princ_size;

    ret_entry->principal->realm.length = u_princ_size;
    tmpdata = malloc(u_princ_size+1);
    if (!tmpdata) {
        error = ENOMEM;
        goto fail;
    }
    if (fread(tmpdata, 1, u_princ_size, KTFILEP(id)) != (size_t) princ_size) {
        free(tmpdata);
        error = KRB5_KT_END;
        goto fail;
    }
    tmpdata[princ_size] = 0;    /* Some things might be expecting null */
                                /* termination...  ``Be conservative in */
                                /* what you send out'' */
    ret_entry->principal->realm.data = tmpdata;

    for (i = 0; i < count; i++) {
        princ = &ret_entry->principal->data[i];
        if (!fread(&princ_size, sizeof(princ_size), 1, KTFILEP(id))) {
            error = KRB5_KT_END;
            goto fail;
        }
        if (KTVERSION(id) != KRB5_KT_VNO_1)
            princ_size = ntohs(princ_size);
        if (!princ_size || (princ_size < 0)) {
            error = KRB5_KT_END;
            goto fail;
        }

        u_princ_size = princ_size;
        princ->length = u_princ_size;
        princ->data = malloc(u_princ_size+1);
        if (!princ->data) {
            error = ENOMEM;
            goto fail;
        }
        if (!fread(princ->data, sizeof(char), u_princ_size, KTFILEP(id))) {
            error = KRB5_KT_END;
            goto fail;
        }
        princ->data[princ_size] = 0; /* Null terminate */
    }

    /* read in the principal type, if we can get it */
    if (KTVERSION(id) != KRB5_KT_VNO_1) {
        if (!fread(&ret_entry->principal->type,
                   sizeof(ret_entry->principal->type), 1, KTFILEP(id))) {
            error = KRB5_KT_END;
            goto fail;
        }
        ret_entry->principal->type = ntohl(ret_entry->principal->type);
    }

    /* read in the timestamp */
    if (!fread(&ret_entry->timestamp, sizeof(ret_entry->timestamp), 1, KTFILEP(id))) {
        error = KRB5_KT_END;
        goto fail;
    }
    if (KTVERSION(id) != KRB5_KT_VNO_1)
        ret_entry->timestamp = ntohl(ret_entry->timestamp);

    /* read in the version number */
    if (!fread(&vno, sizeof(vno), 1, KTFILEP(id))) {
        error = KRB5_KT_END;
        goto fail;
    }
    ret_entry->vno = (krb5_kvno)vno;

    /* key type */
    if (!fread(&enctype, sizeof(enctype), 1, KTFILEP(id))) {
        error = KRB5_KT_END;
        goto fail;
    }
    if (KTVERSION(id) != KRB5_KT_VNO_1)
        enctype = ntohs(enctype);
    ret_entry->key.enctype = (krb5_enctype)enctype;

    /* key contents */
    ret_entry->key.magic = KV5M_KEYBLOCK;

    if (!fread(&count, sizeof(count), 1, KTFILEP(id))) {
        error = KRB5_KT_END;
        goto fail;
    }
    if (KTVERSION(id) != KRB5_KT_VNO_1)
        count = ntohs(count);
    if (!count || (count < 0)) {
        error = KRB5_KT_END;
        goto fail;
    }

    u_count = count;
    ret_entry->key.length = u_count;

    ret_entry->key.contents = (krb5_octet *)malloc(u_count);
    if (!ret_entry->key.contents) {
        error = ENOMEM;
        goto fail;
    }
    if (!fread(ret_entry->key.contents, sizeof(krb5_octet), count,
               KTFILEP(id))) {
        error = KRB5_KT_END;
        goto fail;
    }

    /* Check for a 32-bit kvno extension if four or more bytes remain. */
    pos = ftell(KTFILEP(id));
    if (pos - start_pos + 4 <= size) {
        if (!fread(&vno32, sizeof(vno32), 1, KTFILEP(id))) {
            error = KRB5_KT_END;
            goto fail;
        }
        if (KTVERSION(id) != KRB5_KT_VNO_1)
            vno32 = ntohl(vno32);
        /* If the value is 0, the bytes are just zero-fill. */
        if (vno32)
            ret_entry->vno = vno32;
    }

    /*
     * Reposition file pointer to the next inter-record length field.
     */
    if (fseek(KTFILEP(id), start_pos + size, SEEK_SET) == -1) {
        error = errno;
        goto fail;
    }

    return 0;
fail:

    for (i = 0; i < ret_entry->principal->length; i++)
        free(ret_entry->principal->data[i].data);
    free(ret_entry->principal->data);
    ret_entry->principal->data = 0;
    free(ret_entry->principal);
    ret_entry->principal = 0;
    return error;
}

static krb5_error_code
krb5_ktfileint_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entryp)
{
    krb5_int32 delete_point;

    return krb5_ktfileint_internal_read_entry(context, id, entryp, &delete_point);
}

static krb5_error_code
krb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
{
    krb5_octet vno;
    krb5_data *princ;
    krb5_int16 count, size, enctype;
    krb5_error_code retval = 0;
    krb5_timestamp timestamp;
    krb5_int32  princ_type;
    krb5_int32  size_needed;
    krb5_int32  commit_point = -1;
    uint32_t    vno32;
    int         i;

    KTCHECKLOCK(id);
    retval = krb5_ktfileint_size_entry(context, entry, &size_needed);
    if (retval)
        return retval;
    retval = krb5_ktfileint_find_slot(context, id, &size_needed, &commit_point);
    if (retval)
        return retval;

    /* fseek to synchronise buffered I/O on the key table. */
    /* XXX Without the weird setbuf crock, can we get rid of this now?  */
    if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
    {
        return errno;
    }

    if (KTVERSION(id) == KRB5_KT_VNO_1) {
        count = (krb5_int16)entry->principal->length + 1;
    } else {
        count = htons((u_short)entry->principal->length);
    }

    if (!fwrite(&count, sizeof(count), 1, KTFILEP(id))) {
    abend:
        return KRB5_KT_IOERR;
    }
    size = entry->principal->realm.length;
    if (KTVERSION(id) != KRB5_KT_VNO_1)
        size = htons(size);
    if (!fwrite(&size, sizeof(size), 1, KTFILEP(id))) {
        goto abend;
    }
    if (!fwrite(entry->principal->realm.data, sizeof(char),
                entry->principal->realm.length, KTFILEP(id))) {
        goto abend;
    }

    count = (krb5_int16)entry->principal->length;
    for (i = 0; i < count; i++) {
        princ = &entry->principal->data[i];
        size = princ->length;
        if (KTVERSION(id) != KRB5_KT_VNO_1)
            size = htons(size);
        if (!fwrite(&size, sizeof(size), 1, KTFILEP(id))) {
            goto abend;
        }
        if (!fwrite(princ->data, sizeof(char), princ->length, KTFILEP(id))) {
            goto abend;
        }
    }

    /*
     * Write out the principal type
     */
    if (KTVERSION(id) != KRB5_KT_VNO_1) {
        princ_type = htonl(entry->principal->type);
        if (!fwrite(&princ_type, sizeof(princ_type), 1, KTFILEP(id))) {
            goto abend;
        }
    }

    /*
     * Fill in the time of day the entry was written to the keytab.
     */
    if (krb5_timeofday(context, &entry->timestamp)) {
        entry->timestamp = 0;
    }
    if (KTVERSION(id) == KRB5_KT_VNO_1)
        timestamp = entry->timestamp;
    else
        timestamp = htonl(entry->timestamp);
    if (!fwrite(&timestamp, sizeof(timestamp), 1, KTFILEP(id))) {
        goto abend;
    }

    /* key version number */
    vno = (krb5_octet)entry->vno;
    if (!fwrite(&vno, sizeof(vno), 1, KTFILEP(id))) {
        goto abend;
    }
    /* key type */
    if (KTVERSION(id) == KRB5_KT_VNO_1)
        enctype = entry->key.enctype;
    else
        enctype = htons(entry->key.enctype);
    if (!fwrite(&enctype, sizeof(enctype), 1, KTFILEP(id))) {
        goto abend;
    }
    /* key length */
    if (KTVERSION(id) == KRB5_KT_VNO_1)
        size = entry->key.length;
    else
        size = htons(entry->key.length);
    if (!fwrite(&size, sizeof(size), 1, KTFILEP(id))) {
        goto abend;
    }
    if (!fwrite(entry->key.contents, sizeof(krb5_octet),
                entry->key.length, KTFILEP(id))) {
        goto abend;
    }

    /* 32-bit key version number */
    vno32 = entry->vno;
    if (KTVERSION(id) != KRB5_KT_VNO_1)
        vno32 = htonl(vno32);
    if (!fwrite(&vno32, sizeof(vno32), 1, KTFILEP(id)))
        goto abend;

    if (fflush(KTFILEP(id)))
        goto abend;

    retval = k5_sync_disk_file(context, KTFILEP(id));

    if (retval) {
        return retval;
    }

    if (fseek(KTFILEP(id), commit_point, SEEK_SET)) {
        return errno;
    }
    if (KTVERSION(id) != KRB5_KT_VNO_1)
        size_needed = htonl(size_needed);
    if (!fwrite(&size_needed, sizeof(size_needed), 1, KTFILEP(id))) {
        goto abend;
    }
    if (fflush(KTFILEP(id)))
        goto abend;
    retval = k5_sync_disk_file(context, KTFILEP(id));

    return retval;
}

/*
 * Determine the size needed for a file entry for the given
 * keytab entry.
 */
static krb5_error_code
krb5_ktfileint_size_entry(krb5_context context, krb5_keytab_entry *entry, krb5_int32 *size_needed)
{
    krb5_int16 count;
    krb5_int32 total_size, i;
    krb5_error_code retval = 0;

    count = (krb5_int16)entry->principal->length;

    total_size = sizeof(count);
    total_size += entry->principal->realm.length + sizeof(krb5_int16);

    for (i = 0; i < count; i++)
        total_size += entry->principal->data[i].length + sizeof(krb5_int16);

    total_size += sizeof(entry->principal->type);
    total_size += sizeof(entry->timestamp);
    total_size += sizeof(krb5_octet);
    total_size += sizeof(krb5_int16);
    total_size += sizeof(krb5_int16) + entry->key.length;
    total_size += sizeof(uint32_t);

    *size_needed = total_size;
    return retval;
}

/*
 * Find and reserve a slot in the file for an entry of the needed size.
 * The commit point will be set to the position in the file where the
 * the length (sizeof(krb5_int32) bytes) of this node should be written
 * when commiting the write.  The file position left as a result of this
 * call is the position where the actual data should be written.
 *
 * The size_needed argument may be adjusted if we find a hole that is
 * larger than the size needed.  (Recall that size_needed will be used
 * to commit the write, but that this field must indicate the size of the
 * block in the file rather than the size of the actual entry)
 */
static krb5_error_code
krb5_ktfileint_find_slot(krb5_context context, krb5_keytab id, krb5_int32 *size_needed, krb5_int32 *commit_point_ptr)
{
    FILE *fp;
    krb5_int32 size, zero_point, commit_point;
    krb5_kt_vno kt_vno;

    KTCHECKLOCK(id);
    fp = KTFILEP(id);
    /* Skip over file version number. */
    if (fseek(fp, 0, SEEK_SET))
        return errno;
    if (!fread(&kt_vno, sizeof(kt_vno), 1, fp))
        return errno;

    for (;;) {
        commit_point = ftell(fp);
        if (commit_point == -1)
            return errno;
        if (!fread(&size, sizeof(size), 1, fp)) {
            /* Hit the end of file, reserve this slot. */
            /* Necessary to avoid a later fseek failing on Solaris 10. */
            if (fseek(fp, 0, SEEK_CUR))
                return errno;
            /* htonl(0) is 0, so no need to worry about byte order */
            size = 0;
            if (!fwrite(&size, sizeof(size), 1, fp))
                return errno;
            break;
        }

        if (KTVERSION(id) != KRB5_KT_VNO_1)
            size = ntohl(size);

        if (size > 0) {
            /* Non-empty record; seek past it. */
            if (fseek(fp, size, SEEK_CUR))
                return errno;
        } else if (size < 0) {
            /* Empty record; use if it's big enough, seek past otherwise. */
            size = -size;
            if (size >= *size_needed) {
                *size_needed = size;
                break;
            } else {
                if (fseek(fp, size, SEEK_CUR))
                    return errno;
            }
        } else {
            /* Empty record at end of file; use it. */
            /* Ensure the new record will be followed by another 0. */
            zero_point = ftell(fp);
            if (zero_point == -1)
                return errno;
            if (fseek(fp, *size_needed, SEEK_CUR))
                return errno;
            /* htonl(0) is 0, so no need to worry about byte order */
            if (!fwrite(&size, sizeof(size), 1, fp))
                return errno;
            if (fseek(fp, zero_point, SEEK_SET))
                return errno;
            break;
        }
    }

    *commit_point_ptr = commit_point;
    return 0;
}
#endif /* LEAN_CLIENT */


text:
require 'test_helper'

Geokit::Geocoders::provider_order = [:google, :us]

class ActsAsMappableTest < GeokitTestCase

  LOCATION_A_IP = "217.10.83.5"

  def setup
    @location_a = GeoKit::GeoLoc.new
    @location_a.lat = 32.918593
    @location_a.lng = -96.958444
    @location_a.city = "Irving"
    @location_a.state = "TX"
    @location_a.country_code = "US"
    @location_a.success = true

    @sw = GeoKit::LatLng.new(32.91663,-96.982841)
    @ne = GeoKit::LatLng.new(32.96302,-96.919495)
    @bounds_center=GeoKit::LatLng.new((@sw.lat+@ne.lat)/2,(@sw.lng+@ne.lng)/2)

    @starbucks = companies(:starbucks)
    @loc_a = locations(:a)
    @custom_loc_a = custom_locations(:a)
    @loc_e = locations(:e)
    @custom_loc_e = custom_locations(:e)

    @barnes_and_noble = mock_organizations(:barnes_and_noble)
    @address = mock_addresses(:address_barnes_and_noble)
  end

  def test_override_default_units_the_hard_way
    Location.default_units = :kms
    locations = Location.find(:all, :origin => @loc_a, :conditions => "distance < 3.97")
    assert_equal 5, locations.size
    locations = Location.count(:origin => @loc_a, :conditions => "distance < 3.97")
    assert_equal 5, locations
    Location.default_units = :miles
  end

  def test_include
    locations = Location.find(:all, :origin => @loc_a, :include => :company, :conditions => "company_id = 1")
    assert !locations.empty?
    assert_equal 1, locations[0].company.id
    assert_equal 'Starbucks', locations[0].company.name
  end

  def test_distance_between_geocoded
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("San Francisco, CA").returns(@location_a)
    assert_equal 0, Location.distance_between("Irving, TX", "San Francisco, CA")
  end

  def test_distance_to_geocoded
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
    assert_equal 0, @custom_loc_a.distance_to("Irving, TX")
  end

  def test_distance_to_geocoded_error
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(GeoKit::GeoLoc.new)
    assert_raise(GeoKit::Geocoders::GeocodeError) { @custom_loc_a.distance_to("Irving, TX")  }
  end

  def test_custom_attributes_distance_calculations
    assert_equal 0, @custom_loc_a.distance_to(@loc_a)
    assert_equal 0, CustomLocation.distance_between(@custom_loc_a, @loc_a)
  end

  def test_distance_column_in_select
    locations = Location.find(:all, :origin => @loc_a, :order => "distance ASC")
    assert_equal 6, locations.size
    assert_equal 0, @loc_a.distance_to(locations.first)
    assert_in_delta 3.97, @loc_a.distance_to(locations.last, :units => :miles, :formula => :sphere), 0.01
  end

  def test_find_with_distance_condition
    locations = Location.find(:all, :origin => @loc_a, :conditions => "distance < 3.97")
    assert_equal 5, locations.size
    locations = Location.count(:origin => @loc_a, :conditions => "distance < 3.97")
    assert_equal 5, locations
  end

  def test_find_with_distance_condition_with_units_override
    locations = Location.find(:all, :origin => @loc_a, :units => :kms, :conditions => "distance < 6.387")
    assert_equal 5, locations.size
    locations = Location.count(:origin => @loc_a, :units => :kms, :conditions => "distance < 6.387")
    assert_equal 5, locations
  end

  def test_find_with_distance_condition_with_formula_override
    locations = Location.find(:all, :origin => @loc_a, :formula => :flat, :conditions => "distance < 6.387")
    assert_equal 6, locations.size
    locations = Location.count(:origin => @loc_a, :formula => :flat, :conditions => "distance < 6.387")
    assert_equal 6, locations
  end

  def test_find_within
    locations = Location.find_within(3.97, :origin => @loc_a)
    assert_equal 5, locations.size
    locations = Location.count_within(3.97, :origin => @loc_a)
    assert_equal 5, locations
  end

  def test_find_within_with_token
    locations = Location.find(:all, :within => 3.97, :origin => @loc_a)
    assert_equal 5, locations.size
    locations = Location.count(:within => 3.97, :origin => @loc_a)
    assert_equal 5, locations
  end

  def test_find_within_with_coordinates
    locations = Location.find_within(3.97, :origin =>[@loc_a.lat,@loc_a.lng])
    assert_equal 5, locations.size
    locations = Location.count_within(3.97, :origin =>[@loc_a.lat,@loc_a.lng])
    assert_equal 5, locations
  end

  def test_find_with_compound_condition
    locations = Location.find(:all, :origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
    assert_equal 2, locations.size
    locations = Location.count(:origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
    assert_equal 2, locations
  end

  def test_find_with_secure_compound_condition
    locations = Location.find(:all, :origin => @loc_a, :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
    assert_equal 2, locations.size
    locations = Location.count(:origin => @loc_a, :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
    assert_equal 2, locations
  end

  def test_find_beyond
    locations = Location.find_beyond(3.95, :origin => @loc_a)
    assert_equal 1, locations.size
    locations = Location.count_beyond(3.95, :origin => @loc_a)
    assert_equal 1, locations
  end

  def test_find_beyond_with_token
    locations = Location.find(:all, :beyond => 3.95, :origin => @loc_a)
    assert_equal 1, locations.size
    locations = Location.count(:beyond => 3.95, :origin => @loc_a)
    assert_equal 1, locations
  end

  def test_find_beyond_with_coordinates
    locations = Location.find_beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
    assert_equal 1, locations.size
    locations = Location.count_beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
    assert_equal 1, locations
  end

  def test_find_range_with_token
    locations = Location.find(:all, :range => 0..10, :origin => @loc_a)
    assert_equal 6, locations.size
    locations = Location.count(:range => 0..10, :origin => @loc_a)
    assert_equal 6, locations
  end

  def test_find_range_with_token_with_conditions
    locations = Location.find(:all, :origin => @loc_a, :range => 0..10, :conditions => ["city = ?", 'Coppell'])
    assert_equal 2, locations.size
    locations = Location.count(:origin => @loc_a, :range => 0..10, :conditions => ["city = ?", 'Coppell'])
    assert_equal 2, locations
  end

  def test_find_range_with_token_with_hash_conditions
    locations = Location.find(:all, :origin => @loc_a, :range => 0..10, :conditions => {:city => 'Coppell'})
    assert_equal 2, locations.size
    locations = Location.count(:origin => @loc_a, :range => 0..10, :conditions => {:city => 'Coppell'})
    assert_equal 2, locations
  end

  def test_find_range_with_token_excluding_end
    locations = Location.find(:all, :range => 0...10, :origin => @loc_a)
    assert_equal 6, locations.size
    locations = Location.count(:range => 0...10, :origin => @loc_a)
    assert_equal 6, locations
  end

  def test_find_nearest
    assert_equal @loc_a, Location.find_nearest(:origin => @loc_a)
  end

  def test_find_nearest_through_find
     assert_equal @loc_a, Location.find(:nearest, :origin => @loc_a)
  end

  def test_find_nearest_with_coordinates
    assert_equal @loc_a, Location.find_nearest(:origin =>[@loc_a.lat, @loc_a.lng])
  end

  def test_find_farthest
    assert_equal @loc_e, Location.find_farthest(:origin => @loc_a)
  end

  def test_find_farthest_through_find
    assert_equal @loc_e, Location.find(:farthest, :origin => @loc_a)
  end

  def test_find_farthest_with_coordinates
    assert_equal @loc_e, Location.find_farthest(:origin =>[@loc_a.lat, @loc_a.lng])
  end

  def test_scoped_distance_column_in_select
    locations = @starbucks.locations.find(:all, :origin => @loc_a, :order => "distance ASC")
    assert_equal 5, locations.size
    assert_equal 0, @loc_a.distance_to(locations.first)
    assert_in_delta 3.97, @loc_a.distance_to(locations.last, :units => :miles, :formula => :sphere), 0.01
  end

  def test_scoped_find_with_distance_condition
    locations = @starbucks.locations.find(:all, :origin => @loc_a, :conditions => "distance < 3.97")
    assert_equal 4, locations.size
    locations = @starbucks.locations.count(:origin => @loc_a, :conditions => "distance < 3.97")
    assert_equal 4, locations
  end

  def test_scoped_find_within
    locations = @starbucks.locations.find_within(3.97, :origin => @loc_a)
    assert_equal 4, locations.size
    locations = @starbucks.locations.count_within(3.97, :origin => @loc_a)
    assert_equal 4, locations
  end

  def test_scoped_find_with_compound_condition
    locations = @starbucks.locations.find(:all, :origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
    assert_equal 2, locations.size
    locations = @starbucks.locations.count( :origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
    assert_equal 2, locations
  end

  def test_scoped_find_beyond
    locations = @starbucks.locations.find_beyond(3.95, :origin => @loc_a)
    assert_equal 1, locations.size
    locations = @starbucks.locations.count_beyond(3.95, :origin => @loc_a)
    assert_equal 1, locations
  end

  def test_scoped_find_nearest
    assert_equal @loc_a, @starbucks.locations.find_nearest(:origin => @loc_a)
  end

  def test_scoped_find_farthest
    assert_equal @loc_e, @starbucks.locations.find_farthest(:origin => @loc_a)
  end

  def test_ip_geocoded_distance_column_in_select
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.find(:all, :origin => LOCATION_A_IP, :order => "distance ASC")
    assert_equal 6, locations.size
    assert_equal 0, @loc_a.distance_to(locations.first)
    assert_in_delta 3.97, @loc_a.distance_to(locations.last, :units => :miles, :formula => :sphere), 0.01
  end

  def test_ip_geocoded_find_with_distance_condition
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.find(:all, :origin => LOCATION_A_IP, :conditions => "distance < 3.97")
    assert_equal 5, locations.size
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.count(:origin => LOCATION_A_IP, :conditions => "distance < 3.97")
    assert_equal 5, locations
  end

  def test_ip_geocoded_find_within
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.find_within(3.97, :origin => LOCATION_A_IP)
    assert_equal 5, locations.size
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.count_within(3.97, :origin => LOCATION_A_IP)
    assert_equal 5, locations
  end

  def test_ip_geocoded_find_with_compound_condition
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.find(:all, :origin => LOCATION_A_IP, :conditions => "distance < 5 and city = 'Coppell'")
    assert_equal 2, locations.size
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.count(:origin => LOCATION_A_IP, :conditions => "distance < 5 and city = 'Coppell'")
    assert_equal 2, locations
  end

  def test_ip_geocoded_find_with_secure_compound_condition
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.find(:all, :origin => LOCATION_A_IP, :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
    assert_equal 2, locations.size
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.count(:origin => LOCATION_A_IP, :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
    assert_equal 2, locations
  end

  def test_ip_geocoded_find_beyond
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.find_beyond(3.95, :origin => LOCATION_A_IP)
    assert_equal 1, locations.size
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    locations = Location.count_beyond(3.95, :origin => LOCATION_A_IP)
    assert_equal 1, locations
  end

  def test_ip_geocoded_find_nearest
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    assert_equal @loc_a, Location.find_nearest(:origin => LOCATION_A_IP)
  end

  def test_ip_geocoded_find_farthest
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
    assert_equal @loc_e, Location.find_farthest(:origin => LOCATION_A_IP)
  end

  def test_ip_geocoder_exception
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with('127.0.0.1').returns(GeoKit::GeoLoc.new)
    assert_raises GeoKit::Geocoders::GeocodeError do
      Location.find_farthest(:origin => '127.0.0.1')
    end
  end

  def test_address_geocode
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with('Irving, TX').returns(@location_a)
    locations = Location.find(:all, :origin => 'Irving, TX', :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
    assert_equal 2, locations.size
  end

  def test_find_with_custom_distance_condition
    locations = CustomLocation.find(:all, :origin => @loc_a, :conditions => "dist < 3.97")
    assert_equal 5, locations.size
    locations = CustomLocation.count(:origin => @loc_a, :conditions => "dist < 3.97")
    assert_equal 5, locations
  end

  def test_find_with_custom_distance_condition_using_custom_origin
    locations = CustomLocation.find(:all, :origin => @custom_loc_a, :conditions => "dist < 3.97")
    assert_equal 5, locations.size
    locations = CustomLocation.count(:origin => @custom_loc_a, :conditions => "dist < 3.97")
    assert_equal 5, locations
  end

  def test_find_within_with_custom
    locations = CustomLocation.find_within(3.97, :origin => @loc_a)
    assert_equal 5, locations.size
    locations = CustomLocation.count_within(3.97, :origin => @loc_a)
    assert_equal 5, locations
  end

  def test_find_within_with_coordinates_with_custom
    locations = CustomLocation.find_within(3.97, :origin =>[@loc_a.lat, @loc_a.lng])
    assert_equal 5, locations.size
    locations = CustomLocation.count_within(3.97, :origin =>[@loc_a.lat, @loc_a.lng])
    assert_equal 5, locations
  end

  def test_find_with_compound_condition_with_custom
    locations = CustomLocation.find(:all, :origin => @loc_a, :conditions => "dist < 5 and city = 'Coppell'")
    assert_equal 1, locations.size
    locations = CustomLocation.count(:origin => @loc_a, :conditions => "dist < 5 and city = 'Coppell'")
    assert_equal 1, locations
  end

  def test_find_with_secure_compound_condition_with_custom
    locations = CustomLocation.find(:all, :origin => @loc_a, :conditions => ["dist < ? and city = ?", 5, 'Coppell'])
    assert_equal 1, locations.size
    locations = CustomLocation.count(:origin => @loc_a, :conditions => ["dist < ? and city = ?", 5, 'Coppell'])
    assert_equal 1, locations
  end

  def test_find_beyond_with_custom
    locations = CustomLocation.find_beyond(3.95, :origin => @loc_a)
    assert_equal 1, locations.size
    locations = CustomLocation.count_beyond(3.95, :origin => @loc_a)
    assert_equal 1, locations
  end

  def test_find_beyond_with_coordinates_with_custom
    locations = CustomLocation.find_beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
    assert_equal 1, locations.size
    locations = CustomLocation.count_beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
    assert_equal 1, locations
  end

  def test_find_nearest_with_custom
    assert_equal @custom_loc_a, CustomLocation.find_nearest(:origin => @loc_a)
  end

  def test_find_nearest_with_coordinates_with_custom
    assert_equal @custom_loc_a, CustomLocation.find_nearest(:origin =>[@loc_a.lat, @loc_a.lng])
  end

  def test_find_farthest_with_custom
    assert_equal @custom_loc_e, CustomLocation.find_farthest(:origin => @loc_a)
  end

  def test_find_farthest_with_coordinates_with_custom
    assert_equal @custom_loc_e, CustomLocation.find_farthest(:origin =>[@loc_a.lat, @loc_a.lng])
  end

  def test_find_with_array_origin
    locations = Location.find(:all, :origin =>[@loc_a.lat,@loc_a.lng], :conditions => "distance < 3.97")
    assert_equal 5, locations.size
    locations = Location.count(:origin =>[@loc_a.lat,@loc_a.lng], :conditions => "distance < 3.97")
    assert_equal 5, locations
  end

  # Bounding box tests

  def test_find_within_bounds
    locations = Location.find_within_bounds([@sw,@ne])
    assert_equal 2, locations.size
    locations = Location.count_within_bounds([@sw,@ne])
    assert_equal 2, locations
  end

  def test_find_within_bounds_ordered_by_distance
    locations = Location.find_within_bounds([@sw,@ne], :origin=>@bounds_center, :order=>'distance asc')
    assert_equal locations[0], locations(:d)
    assert_equal locations[1], locations(:a)
  end

  def test_find_within_bounds_with_token
    locations = Location.find(:all, :bounds=>[@sw,@ne])
    assert_equal 2, locations.size
    locations = Location.count(:bounds=>[@sw,@ne])
    assert_equal 2, locations
  end

  def test_find_within_bounds_with_string_conditions
    locations = Location.find(:all, :bounds=>[@sw,@ne], :conditions=>"id !=#{locations(:a).id}")
    assert_equal 1, locations.size
  end

  def test_find_within_bounds_with_array_conditions
    locations = Location.find(:all, :bounds=>[@sw,@ne], :conditions=>["id != ?", locations(:a).id])
    assert_equal 1, locations.size
  end

  def test_find_within_bounds_with_hash_conditions
    locations = Location.find(:all, :bounds=>[@sw,@ne], :conditions=>{:id => locations(:a).id})
    assert_equal 1, locations.size
  end

  def test_auto_geocode
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
    store=Store.new(:address=>'Irving, TX')
    store.save
    assert_equal store.lat,@location_a.lat
    assert_equal store.lng,@location_a.lng
    assert_equal 0, store.errors.size
  end

  def test_auto_geocode_failure
    GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("BOGUS").returns(GeoKit::GeoLoc.new)
    store=Store.new(:address=>'BOGUS')
    store.save
    assert store.new_record?
    assert_equal 1, store.errors.size
  end

  # Test :through

  def test_find_with_through
    organizations = MockOrganization.find(:all, :origin => @location_a, :order => 'distance ASC')
    assert_equal 2, organizations.size
    organizations = MockOrganization.count(:origin => @location_a, :conditions => "distance < 3.97")
    assert_equal 1, organizations
  end

  def test_find_with_through_with_hash
    people = MockPerson.find(:all, :origin => @location_a, :order => 'distance ASC')
    assert_equal 2, people.size
    people = MockPerson.count(:origin => @location_a, :conditions => "distance < 3.97")
    assert_equal 2, people
  end
end

redpajama_set_name: RedPajamaGithub


text:
using UnityEngine;
using System.Collections;

public class Projectile : MonoBehaviour {

    protected float Speed { get; set; }
    protected Vector3 direction = Vector3.up;

    public int Damage;

    void Start() {
        Initialize();
    }

    public virtual void Initialize() {

    }

    public virtual void Move() {
        transform.position += Speed * Time.deltaTime * direction;
    }

    public virtual void DestroyWhenOffScreen() {
        if(!GetComponent<Renderer>().isVisible) {
            Destroy(gameObject);
        }
    }

	void Update(){
        Move();
        DestroyWhenOffScreen();
	}

    public virtual void HitShip() {
        Destroy(gameObject);
    }

    public virtual void HitShip(Transform t) {

    }
}


text:
package com.evolveum.midpoint.util.exception;

import com.evolveum.midpoint.util.LocalizableMessage;

/**
 * @author semancik
 *
 */
public class PolicyViolationException extends CommonException {
	private static final long serialVersionUID = 1L;

	public PolicyViolationException() {
	}

	public PolicyViolationException(String message) {
		super(message);
	}

	public PolicyViolationException(LocalizableMessage userFriendlyMessage) {
		super(userFriendlyMessage);
	}

	public PolicyViolationException(Throwable cause) {
		super(cause);
	}

	public PolicyViolationException(LocalizableMessage userFriendlyMessage, Throwable cause) {
		super(userFriendlyMessage, cause);
	}

	public PolicyViolationException(String message, Throwable cause) {
		super(message, cause);
	}

	@Override
	public String getErrorTypeMessage() {
		return "Policy violation";
	}

}


text:
package BasicStructure;
public class ProgressSaver
{
}


text:
<instance description="" template="upgrade">
	<group name="upgrade_bag">
		<bool name="enable_in_hold" value="True" />
		<float name="global_max_limit" value="0" />
		<bool name="has_speech_code" value="True" />
		<float name="local_max_limit" value="1" />
		<enum name="owner_type" value="self" />
		<group name="speech_code_2">
			<string name="code_1" value="" />
			<string name="code_2" value="" />
			<string name="code_3" value="" />
		</group>
		<group name="speech_code_3">
			<string name="code_1" value="cmo" />
			<string name="code_2" value="" />
			<string name="code_3" value="" />
		</group>
		<group name="time_cost">
			<group name="cost">
				<float name="action" value="0" />
				<float name="command" value="0" />
				<float name="fuel" value="0" />
				<float name="manpower" value="0" />
				<float name="munition" value="25" />
				<float name="popcap" value="0" />
			</group>
			<float name="time_seconds" value="30" />
		</group>
		<bool name="ui_event_cue" value="True" />
		<enum name="ui_group" value="unit_upgrade_panel" />
		<group name="ui_info">
			<locstring name="extra_text" value="0" />
			<locstring name="help_text" value="11025916" />
			<string name="hotkey_name" value="U" />
			<icon name="icon_name" value="Icons_abilities_ability_german_ambush_camo_on" />
			<bool name="reveal_for_decryption" value="False" />
			<locstring name="screen_name" value="11025915" />
			<locstring name="brief_text" value="0" />
			<locstring name="screen_name_short" value="0" />
			<enum name="ui_style" value="default" />
		</group>
		<bool name="validate_actions" value="False" />
		<list name="actions">
			<template_reference name="action" value="action\change_target_action">
				<list name="actions">
					<template_reference name="action" value="action\delay">
						<float name="delay" value="2" />
						<float name="delay_min" value="0" />
						<bool name="progress_bar" value="False" />
						<bool name="randomize" value="False" />
						<list name="delayed_actions">
							<template_reference name="action" value="action\apply_modifiers_action">
								<float name="duration" value="0" />
								<bool name="permanent" value="False" />
								<list name="modifiers">
									<template_reference name="modifier" value="modifiers\camouflage_enable">
										<enum name="application_type" value="apply_to_entity" />
										<bool name="exclusive" value="False" />
										<string name="modifier_id" value="" />
										<string name="target_type_name" value="" />
										<enum name="usage_type" value="enable" />
										<float name="value" value="1" />
										<instance_reference name="tooltip" value="modifier_tooltip\camouflage_enable" />
									</template_reference>
								</list>
								<uniqueid name="id" value="1073746175" />
							</template_reference>
						</list>
						<uniqueid name="id" value="1073746176" />
						<bool name="can_prevent_refund" value="True" />
					</template_reference>
				</list>
				<enum name="change_target_type" value="entities" />
				<uniqueid name="id" value="1073746177" />
			</template_reference>
		</list>
		<list name="requirements">
			<template_reference name="required" value="requirements\required_in_territory">
				<enum name="reason" value="usage" />
				<locstring name="ui_name" value="0" />
				<bool name="in_supply" value="True" />
				<bool name="is_secured" value="False" />
				<bool name="is_secured_by_checkpoint" value="False" />
				<bool name="not_in_transition" value="False" />
			</template_reference>
			<template_reference name="required" value="requirements\required_squad_veterancy">
				<enum name="reason" value="usage" />
				<locstring name="ui_name" value="444" mod="95f9ec3171c849d792717e865bd5e612" />
				<float name="veterancy_rank" value="4" />
			</template_reference>
		</list>
		<int name="ui_position" value="9" />
		<icon name="ui_kicker_icon_name" value="" />
		<locstring name="ui_squad_name_override" value="0" />
		<locstring name="ui_squad_help_text_override" value="0" />
		<locstring name="ui_squad_extra_text_override" value="0" />
	</group>
	<uniqueid name="pbgid" value="70" />
</instance>


text:
namespace switches {

// Media switches
extern const char kEnableCmaMediaPipeline[];
extern const char kHdmiSinkSupportedCodecs[];

// Content-implementation switches
extern const char kEnableLocalFileAccesses[];

// Metrics switches
extern const char kOverrideMetricsUploadUrl[];

// Network switches
extern const char kNoWifi[];

// App switches
extern const char kAllowHiddenMediaPlayback[];

// Switches to communicate app state information
extern const char kLastLaunchedApp[];
extern const char kPreviousApp[];

// ALSA-based CMA switches. (Only valid for audio products.)
extern const char kAlsaOutputBufferSize[];
extern const char kAlsaOutputPeriodSize[];
extern const char kAlsaOutputStartThreshold[];
extern const char kAlsaOutputAvailMin[];
extern const char kAlsaCheckCloseTimeout[];
extern const char kAlsaNumOutputChannels[];

}  // namespace switches

#endif  // CHROMECAST_BASE_CHROMECAST_SWITCHES_H_


text:
package com.korotyx.virtualentity;

public class VirtualEntityMain
{

}


text:
from setuptools import setup, find_packages, Extension
import numpy

numpy_include = str(numpy.get_include())
module = Extension('kreveik.network.boolfuncs.boolfuncs_c',
                   #extra_compile_args= ['-fopenmp'],
                   #extra_link_args=['-lgomp'],
                   sources = ['kreveik/network/boolfuncs/boolfuncs.c'],
                   include_dirs=[numpy_include])

setup(
    name = "Kreveik",
    version = "0.6.0",
    packages = find_packages(),
    install_requires = ['docutils>=0.3','numpy>=1.5','matplotlib>=1.0'],

    package_data = {
        # If any package contains *.md files, include them:
        '': ['*.md','README'],
    },

    # metadata for upload to PyPI
    author = "Mehmet Ali Anil",
    author_email = "mehmet.ali.anil@ieee.org",
    description = "Kreveik is a Python module for Boolean networks. With Kreveik, one can create, investigate dynamics of, form families of random Boolean networks.",
    license = "LICENSE.txt",
    keywords = "random boolean networks genetic algorithm",
    url = "http://github.com/mehmetalianil/Kreveik/",
    # project home page, if any

    classifiers=[
          'Development Status :: 4 - Beta',
          'Environment :: Console',
          'Intended Audience :: Science/Research',
          'License :: Other/Proprietary License',
          'Natural Language :: English',
          'Operating System :: POSIX',
          'Programming Language :: Python :: 2.7',
          'Programming Language :: C',
          'Topic :: Scientific/Engineering :: Bio-Informatics',
          'Topic :: Scientific/Engineering :: Information Analysis',
          'Topic :: Scientific/Engineering :: Physics'
          ],
      ext_modules = [module]

)


text:
iSpy.Models.iOSKeychain = Backbone.Model.extend({

    defaults: {
        "Identities": [],
        "Generic Passwords": [],
        "Certificates": [],
        "Internet Passwords": [],
        "Keys": [],
    },

    initialize: function() {
        console.log("[Models|iOSKeychain] initialize");
        iSpy.Events.on('sync:keyChainItems', this.set, this);
    },

    rpcRead: [
        {
            "messageType": "keyChainItems",
            "messageData": {}
        },
    ],

});


text:
SYNONYM

#### According to
Index Fungorum

#### Published in
null

#### Original name
Clitopilus omphaliiformis Joss., 1941

### Remarks
null


text:
package de.apoth.anderoids.logic.entities;

import de.apoth.anderoids.logic.GameLogic;
import de.apoth.anderoids.resource.Position;
import de.apoth.anderoids.resource.Time;
/**
 * This component allows for linear movement to be calculated on demand,
 * which reduces the amount of objects moved in each logic tick.
 *
 * One would think that the class to derive from is actually MovementComponent,
 * but since the getPosition Function must be changed its not so
 * @author apoth
 *
 */
public class ImplicitPositionComponent extends PositionComponent {

	private Position inertia = null;
	private Time creationTime;
	public void setInertia(Position p)
	{
		this.inertia = p;
	}
	public ImplicitPositionComponent(Position p) {
		super(p);
		this.inertia = new Position();
		this.creationTime = GameLogic.get().getCurrentTime();
	}

	@Override
	public Position getPosition()
	{
		Time time = GameLogic.get().getCurrentTime();
		time = Time.getDifference(time, this.creationTime);
		assert(time.t >= 0.0f); //prevent rounding errors
		Position retu = new Position(this.p);
		retu.addWithFactor(this.inertia, time.t);
		return retu;
	}

}


text:
using System;
using UnityEngine;
using LuaInterface;

public class AnimatorControllerParameterTypeWrap
{
	static LuaMethod[] enums = new LuaMethod[]
	{
		new LuaMethod("Float", GetFloat),
		new LuaMethod("Int", GetInt),
		new LuaMethod("Bool", GetBool),
		new LuaMethod("Trigger", GetTrigger),
		new LuaMethod("IntToEnum", IntToEnum),
	};

	public static void Register(IntPtr L)
	{
		LuaScriptMgr.RegisterLib(L, "UnityEngine.AnimatorControllerParameterType", typeof(UnityEngine.AnimatorControllerParameterType), enums);
	}

	[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
	static int GetFloat(IntPtr L)
	{
		LuaScriptMgr.Push(L, AnimatorControllerParameterType.Float);
		return 1;
	}

	[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
	static int GetInt(IntPtr L)
	{
		LuaScriptMgr.Push(L, AnimatorControllerParameterType.Int);
		return 1;
	}

	[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
	static int GetBool(IntPtr L)
	{
		LuaScriptMgr.Push(L, AnimatorControllerParameterType.Bool);
		return 1;
	}

	[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
	static int GetTrigger(IntPtr L)
	{
		LuaScriptMgr.Push(L, AnimatorControllerParameterType.Trigger);
		return 1;
	}

	[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
	static int IntToEnum(IntPtr L)
	{
		int arg0 = (int)LuaDLL.lua_tonumber(L, 1);
		AnimatorControllerParameterType o = (AnimatorControllerParameterType)arg0;
		LuaScriptMgr.Push(L, o);
		return 1;
	}
}


text:
![0 stars](../../images/ic_star_border_black_18dp_1x.png)![0 stars](../../images/ic_star_border_black_18dp_1x.png)![0 stars](../../images/ic_star_border_black_18dp_1x.png)![0 stars](../../images/ic_star_border_black_18dp_1x.png)![0 stars](../../images/ic_star_border_black_18dp_1x.png) 0

To use the NYC Running Events Fun Facts skill, try saying...

* *Alexa, open n. y. c. running*

* *Alexa, start n. y. c. running*

* *Alexa, ask n. y. c. running to give me a running fact*

This skill is intended for runners or non-runners interested in learning facts about New York City Long Distance Races.

***

### Skill Details

* **Invocation Name:** n. y. c. running
* **Category:** null
* **ID:** amzn1.ask.skill.5559ed36-2492-43d4-964a-bd1c6f9ce598
* **ASIN:** B01N1N8DK8
* **Author:** Instant Analytics
* **Release Date:** December 6, 2016 @ 01:36:19
* **In-App Purchasing:** No


text:
using namespace std;

void Disassembler::reverse() {
    string str;
    for(size_t i = 0; i < codes.size(); i++) {
        Instruction tmp(codes[i]);
        str = tmp.reverse();
        if ( tmp.need_label ) {
            unsigned int t = pc+tmp.offset+1;
            if (labels.count(t) == 0) {
                labels[t] = "Label"+to_string(labels.size());
            }
            str += "Label"+to_string(labels.size());
        } else if ( tmp.need_target ) {
            unsigned int t = tmp.target;
            if (labels.count(t) == 0) {
                labels[t] = "Label"+to_string(labels.size());
            }
            str += "Label"+to_string(labels.size());
        }
        instructions.push_back("\t" + str);
        pc++;
    }
    for(auto i = labels.rbegin(); i != labels.rend(); i++) {
        instructions.insert(instructions.begin() + i->first, i->second + ":");
    }
}

void Disassembler::print(ostream &out) {
    for(auto i = instructions.begin(); i != instructions.end(); i++) {
        out << *i << endl;
    }
}


text:
<?php
namespace PlaygroundSocial\Cron;

class Cron
{

    /*
    For use :

    $this->log('Hello World', CronController::ERROR);
    $this->log('Hello World', CronController::WARN);
    $this->log('Hello World', CronController::DEBUG);
    $this->log('Hello World', CronController::SUCCESS);

    public function log($message, $level)
    {
        CronController::log($message, $level);
    }

    */

    const ERROR = "error";
    const WARN = "warning";
    const DEBUG = "debug";
    const SUCCESS = "success";

    public static function log($message, $level)
    {
        $obj = new self();
        $obj->$level($message);
    }

    public function success($message)
    {
        // echo "\033[32m".$message."\033[37m"."\n";
    }

    public function debug($message)
    {
        // echo "\033[34m".$message."\033[37m"."\n";
    }

    public function warning($message)
    {
        // echo "\033[33m".$message."\033[37m"."\n";
    }

    public function error($message)
    {
        // echo "\033[31m".$message."\033[37m"."\n";
    }

}


text:
@class WZYGaraponTvProgram;

#define WZYGaraponLog(...) NSLog(__VA_ARGS__)
#if WZY_GARAPON_DEBUG
#define WZYGaraponLogD(...) NSLog(__VA_ARGS__)
#else
#define WZYGaraponLogD(...) ;
#endif

typedef void (^WZYGaraponAsyncBlock)(NSError *error);
typedef void (^WZYGaraponRequestAsyncBlock)(NSDictionary *response, NSError *error);
typedef void (^WZYGaraponTvProgramBlock)(WZYGaraponTvProgram *program);

#define WZY_GARAPON_AUTH_HOST @"garagw.garapon.info"

typedef enum : NSInteger {
    WZYGaraponUnknownApiCategory,
    WZYGaraponWebAuthApiCategory,
    WZYGaraponTvV3ApiCategory,
} WZYGaraponApiCategory;

typedef enum : NSInteger {
    WZYGaraponUnknownApi,
    WZYGaraponAuthApi,
    WZYGaraponAuthLoginApi,
    WZYGaraponAuthLogoutApi,
    WZYGaraponSearchApi,
    WZYGaraponFavoriteApi,
    WZYGaraponChannelApi,
} WZYGaraponApiType;

FOUNDATION_EXPORT NSString *WZYGaraponLocalizedString(NSString *key);


text:
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="box_bg">#ffffff</color>
    <color name="window_background">#cccccc</color>

    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <color name="background_blue">#FF007ACC</color>
    <color name="black">#FF000000</color>
    <color name="orange">#FFE65C00</color>
    <color name="shadow">#44000000</color>
    <color name="white">#FFFFFFFF</color>

</resources>


text:
#include "stack_instructions.h"
#include "registers.h"
#include "memory.h"

void instr_tsx(void) {
    reg_X.data = (signed char)reg_SP.data;
    /* set zero flag if appropriate */
    if (reg_X.data == 0x00) {
        reg_PSR.data.flags.Z = 1;
    }
    /* set negative flag if appropriate */
    if (reg_X.data & 0x10) {
        reg_PSR.data.flags.N = 1;
    }
}

void instr_txs(void) {
    reg_SP.data = (unsigned char)reg_X.data;
}

void instr_pha(void) {
    unsigned short stack_index = get_full_SP();
    MEMORY_BLOCK[stack_index] = reg_A.data;
    reg_SP.data--;
}

void instr_php(void) {
    unsigned short stack_index = get_full_SP();
    MEMORY_BLOCK[stack_index] = reg_PSR.data.reg;
    reg_SP.data--;
}

void instr_pla(void) {
    unsigned short stack_index;
    reg_SP.data++;
    stack_index = get_full_SP();
    reg_A.data = MEMORY_BLOCK[stack_index];
    /* set zero flag if appropriate */
    if (reg_A.data == 0x00) {
        reg_PSR.data.flags.Z = 1;
    }
    /* set negative flag if appropriate */
    if (reg_A.data & 0x10) {
        reg_PSR.data.flags.N = 1;
    }
}

void instr_plp(void) {
    unsigned short stack_index;
    reg_SP.data++;
    stack_index = get_full_SP();
    reg_PSR.data.reg = MEMORY_BLOCK[stack_index];
}


text:
: ${HADOOP_PREFIX:=/usr/local/hadoop}

$HADOOP_PREFIX/etc/hadoop/hadoop-env.sh

rm /tmp/*.pid

# installing libraries if any - (resource urls added comma separated to the ACP system variable)
cd $HADOOP_PREFIX/share/hadoop/common ; for cp in ${ACP//,/ }; do  echo == $cp; curl -LO $cp ; done; cd -

# altering the core-site configuration
sed s/HOSTNAME/$2/ /usr/local/hadoop/etc/hadoop/core-site.xml.template > /usr/local/hadoop/etc/hadoop/core-site.xml

# altering the yatrn-site configuration
sed s/HOSTNAME/$2/ /usr/local/hadoop/etc/hadoop/yarn-site.xml.template > /usr/local/hadoop/etc/hadoop/yarn-site.xml

service sshd start
#$HADOOP_PREFIX/sbin/start-dfs.sh
#$HADOOP_PREFIX/sbin/start-yarn.sh
#$HADOOP_PREFIX/sbin/mr-jobhistory-daemon.sh start historyserver

if [[ $1 == "-d" ]]; then
  while true; do sleep 1000; done
fi

if [[ $1 == "-bash" ]]; then
  /bin/bash
fi

if [[ $1 == "master" ]] ; then
  $HADOOP_PREFIX/bin/hdfs namenode -format
  $HADOOP_PREFIX/sbin/hadoop-daemon.sh --config $HADOOP_CONF_DIR --script hdfs start namenode
  $HADOOP_PREFIX/sbin/yarn-daemon.sh --config $HADOOP_CONF_DIR start resourcemanager
  $HADOOP_PREFIX/etc/hadoop/hadoop-env.sh && $HADOOP_PREFIX/bin/hdfs dfs -mkdir -p /user/root
  $HADOOP_PREFIX/etc/hadoop/hadoop-env.sh && $HADOOP_PREFIX/bin/hdfs dfs -put $HADOOP_PREFIX/etc/hadoop/ input
  while true; do sleep 1000; done
fi

if [[ $1 == "worker" ]]; then
  $HADOOP_PREFIX/sbin/hadoop-daemon.sh --config $HADOOP_CONF_DIR --script hdfs start datanode
  $HADOOP_PREFIX/sbin/yarn-daemon.sh --config $HADOOP_CONF_DIR start nodemanager
  while true; do sleep 1000; done
fi


text:
SeqDB is a *locking* sequential numbering database, which allows you to generate numbers sequentially without repetition and skips.

The database is built with Go using [BoltDB](https://github.com/boltdb/bolt). It follows a plain text protocol inspired by memcache and redis.

## Architecture

The database is divided into *buckets*. There can be any number of buckets in the database but there must be at least one. Buckets may be divided based on your users or there can be one global bucket.

Buckets are divided into *sequences*. Each sequence is named similar to a bucket, but there can't be two sequences in a bucket with the same name. The same sequence names in different buckets are allowed.

**Example**

You have a bucket named `First` and another bucket named `Second` . You can have a sequence named `default` in both the `First` and `Second` bucket, but there cannot be two of them in the `First` bucket.

## Locking

When working with a bucket, either reading or writing, the whole bucket is locked from concurrent access regardless of the sequence.

## Protocol

### SET bucket sequence value

Directly set the sequence in the bucket

Returns `OK` if command successful

### GET bucket sequence

Return the current sequence

### INC bucket sequence

Increments the sequence by one and return the new value

### QUIT

Closes connection to the server

Returns `OK` if command successful


text:
using Cirrious.CrossCore.Converters;
using System;

namespace WTM.Mobile.Core.Converters
{
    public class StringFormatValueConverter : MvxValueConverter
    {
        public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
                return null;

            if (parameter == null)
                return value;

            var format = "{0:" + parameter.ToString() + "}";

            return string.Format(format, value);
        }
    }
}


text:
package com.consol.citrus.generate;

/**
 * Unit testing framework can be either JUnit or TestNG. Test case generator
 * will create different Java classes according to the unit test framework.
 */
public enum UnitFramework {
    TESTNG,
    JUNIT4,
    JUNIT5;

    public static UnitFramework fromString(String value) {
        if (value.equalsIgnoreCase("testng")) {
            return TESTNG;
        } else if (value.equalsIgnoreCase("junit") || value.equalsIgnoreCase("junit4")) {
            return JUNIT4;
        } else if (value.equalsIgnoreCase("junit5")) {
            return JUNIT5;
        } else {
            throw new IllegalArgumentException("Found unsupported unit test framework '" + value + "'");
        }
    }
}


text:
using System;
using System.Collections.Generic;
using System.IO;
using MatterHackers.MatterControl.DataStorage;
using Newtonsoft.Json;

namespace MatterHackers.MatterControl
{
	internal class ManifestFile
	{
		private List<PrintItem> projectFiles;
		private string projectName = "Test Project";
		private string projectDateCreated;

		public ManifestFile()
		{
			DateTime now = DateTime.Now;
			projectDateCreated = now.ToString("s");
		}

		public List<PrintItem> ProjectFiles
		{
			get
			{
				return projectFiles;
			}
			set
			{
				projectFiles = value;
			}
		}

		public string ProjectName
		{
			get
			{
				return projectName;
			}
			set
			{
				projectName = value;
			}
		}

		public string ProjectDateCreated
		{
			get
			{
				return projectDateCreated;
			}
			set
			{
				projectDateCreated = value;
			}
		}
	}

	internal class ManifestFileHandler
	{
		private ManifestFile project;

		public ManifestFileHandler(List<PrintItem> projectFiles)
		{
			if (projectFiles != null)
			{
				project = new ManifestFile();
				project.ProjectFiles = projectFiles;
			}
		}

		private static string applicationDataPath = ApplicationDataStorage.ApplicationUserDataPath;
		private static string defaultPathAndFileName = Path.Combine(applicationDataPath , "data", "default.mcp");

		public void ExportToJson(string savedFileName = null)
		{
			if (savedFileName == null)
			{
				savedFileName = defaultPathAndFileName;
			}

			string jsonString = JsonConvert.SerializeObject(this.project, Newtonsoft.Json.Formatting.Indented);
            string pathToDataFolder = Path.Combine(applicationDataPath, "data");
            if (!Directory.Exists(pathToDataFolder))
			{
                Directory.CreateDirectory(pathToDataFolder);
			}

			File.WriteAllText(savedFileName, jsonString);
		}

		public List<PrintItem> ImportFromJson(string filePath = null)
		{
			if (filePath == null)
			{
				filePath = defaultPathAndFileName;
			}

			if (!System.IO.File.Exists(filePath))
			{
				return null;
			}

			string json = File.ReadAllText(filePath);

			ManifestFile newProject = JsonConvert.DeserializeObject<ManifestFile>(json);
			if (newProject == null)
			{
				return new List<PrintItem>();
			}

			return newProject.ProjectFiles;
		}

	}
}


text:
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace Rosie
{
	public class WebRequestHandler : IDeviceService
	{
		public WebRequestHandler ()
		{
		}

		public static string Identifier = "Web";

		public string ServiceIdentifier => Identifier;

		HttpClient client = new HttpClient ();

		public event EventHandler<DeviceState> CurrentStateUpdated;
		public event EventHandler<Device> DeviceAdded;

		public async Task<bool> HandleRequest (Device device, DeviceUpdate request)
		{
			try {
				if (request.DataType != DataTypes.Bool)
					return false;
				//TODO: Fixme
				//var url = device.ad
				//var resp = await client.GetAsync (request.BoolValue.Value ? device.OnUrl : device.OffUrl);
				//resp.EnsureSuccessStatusCode ();
			} catch (Exception ex) {
				Console.WriteLine (ex);
			}
			return false;
		}
	}
}


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Buddhism</title>
<link href="stylesheet.css" rel="stylesheet" type="text/css" />

Buddhism

According to Buddhism, there were countless Buddhas before Gautama Buddha and there will be many Buddhas after him. In short, he is not the first, nor will he be the last.

However, counting from the present kalpa (the beginning of our present universe) Buddha Gautama is considered the fourth Buddha. The first is Gakusandho Buddha, second Gonakamano Buddha and the third Gassapo Buddha. The last Buddha of this kalpa will be Mettaya Buddha. Then the universe will renew itself and from then begins a new kalpa.

Old stories say that Siddhārtha Gautama was born around the 6th century BC. He was the one who would become the first Buddha in written history. Some Buddhists believe that Siddhārtha Gautama was a perfect person.

He was born a prince and was unsure about if he wanted to become a religious man or a prince. At age 29 he noticed pain and suffering. he then wanted to learn the answer to the problem of human suffering, or pain. He gave up all his money and power, and became a monk without a home. He walked from place to place, trying to learn the answers to life.

<< Go to home


text:
package net.aung.moviemaniac.views.pods;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.TextView;

import net.aung.moviemaniac.R;
import net.aung.moviemaniac.data.vos.GenreVO;
import net.aung.moviemaniac.views.components.textview.SmallDashUnderlineTextView;

import java.util.List;

/**
 * Created by aung on 12/16/15.
 */
public class ViewPodGenreListDetail extends LinearLayout {

    public ViewPodGenreListDetail(Context context) {
        super(context);
    }

    public ViewPodGenreListDetail(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ViewPodGenreListDetail(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
    }

    public void setGenreList(List<GenreVO> genreList, int textColor) {
        if (genreList == null || genreList.size() == 0)
            return;

        if (getChildCount() == 0) {
            for (int position = 0; position < genreList.size(); position++) {
                //TextView tv = new SmallDashUnderlineTextView(getContext(), textColor);
                TextView tv = new TextView(getContext());
                tv.setBackgroundResource(R.drawable.genre_bg);
                tv.setTextColor(getContext().getResources().getColor(R.color.primary_text));

                int padding = (int) getContext().getResources().getDimension(R.dimen.margin_medium);
                tv.setPadding(padding, 0, padding, 0);

                GenreVO genre = genreList.get(position);
                if(genre != null) {
                    tv.setText(genre.getName());
                    addView(tv);

                    if (position < genreList.size() - 1) {
                        TextView tvSeparator = new TextView(getContext());
                        tvSeparator.setTextSize(14);
                        tvSeparator.setTextColor(textColor);
                        tvSeparator.setText(" | ");
                        addView(tvSeparator);
                    }
                }
            }
        }
    }
}